Skip to content

Commit

Permalink
Add NT_SIGINFO NOTE to ELF dumps (#82449)
Browse files Browse the repository at this point in the history
* Add NT_SIGINFO NOTE to ELF dumps

Linux Watson needs this to better triage ELF dumps.

Add CreateDumpOptions helper struct to pass all the command options around. Add the
"--code", "--errno", "--address" command line options used to fill the NT_SIGINFO
NOTE. The runtime passes to createdump on a crash.

Added "ExceptionType" field to "Parameters" section of the Linux crash report json.

* Add NT_SIGINFO define

* Code review feedback
  • Loading branch information
mikem8361 authored Mar 5, 2023
1 parent 3b63eb1 commit 615de00
Show file tree
Hide file tree
Showing 14 changed files with 241 additions and 111 deletions.
15 changes: 10 additions & 5 deletions src/coreclr/debug/createdump/crashinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ CrashInfo* g_crashInfo;

static bool ModuleInfoCompare(const ModuleInfo* lhs, const ModuleInfo* rhs) { return lhs->BaseAddress() < rhs->BaseAddress(); }

CrashInfo::CrashInfo(pid_t pid, bool gatherFrames, pid_t crashThread, uint32_t signal) :
CrashInfo::CrashInfo(const CreateDumpOptions& options) :
m_ref(1),
m_pid(pid),
m_pid(options.Pid),
m_ppid(-1),
m_hdac(nullptr),
m_pClrDataEnumRegions(nullptr),
m_pClrDataProcess(nullptr),
m_gatherFrames(gatherFrames),
m_crashThread(crashThread),
m_signal(signal),
m_gatherFrames(options.CrashReport),
m_crashThread(options.CrashThread),
m_signal(options.Signal),
m_moduleInfos(&ModuleInfoCompare),
m_mainModule(nullptr),
m_cbModuleMappings(0),
Expand All @@ -30,6 +30,11 @@ CrashInfo::CrashInfo(pid_t pid, bool gatherFrames, pid_t crashThread, uint32_t s
#else
m_auxvValues.fill(0);
m_fdMem = -1;
memset(&m_siginfo, 0, sizeof(m_siginfo));
m_siginfo.si_signo = options.Signal;
m_siginfo.si_code = options.SignalCode;
m_siginfo.si_errno = options.SignalErrno;
m_siginfo.si_addr = options.SignalAddress;
#endif
}

Expand Down
4 changes: 3 additions & 1 deletion src/coreclr/debug/createdump/crashinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class CrashInfo : public ICLRDataEnumMemoryRegionsCallback, public ICLRDataLoggi
#ifdef __APPLE__
vm_map_t m_task; // the mach task for the process
#else
siginfo_t m_siginfo; // signal info (if any)
bool m_canUseProcVmReadSyscall;
int m_fdMem; // /proc/<pid>/mem handle
int m_fdPagemap; // /proc/<pid>/pagemap handle
Expand All @@ -83,7 +84,7 @@ class CrashInfo : public ICLRDataEnumMemoryRegionsCallback, public ICLRDataLoggi
void operator=(const CrashInfo&) = delete;

public:
CrashInfo(pid_t pid, bool gatherFrames, pid_t crashThread, uint32_t signal);
CrashInfo(const CreateDumpOptions& options);
virtual ~CrashInfo();

// Memory usage stats
Expand Down Expand Up @@ -127,6 +128,7 @@ class CrashInfo : public ICLRDataEnumMemoryRegionsCallback, public ICLRDataLoggi
#ifndef __APPLE__
inline const std::vector<elf_aux_entry>& AuxvEntries() const { return m_auxvEntries; }
inline size_t GetAuxvSize() const { return m_auxvEntries.size() * sizeof(elf_aux_entry); }
inline const siginfo_t* SigInfo() const { return &m_siginfo; }
#endif

// IUnknown
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/debug/createdump/crashreportwriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,17 +175,17 @@ CrashReportWriter::WriteCrashReport()
}
CloseArray(); // threads
CloseObject(); // payload
#ifdef __APPLE__
OpenObject("parameters");
if (exceptionType != nullptr)
{
WriteValue("ExceptionType", exceptionType);
}
#ifdef __APPLE__
WriteSysctl("kern.osproductversion", "OSVersion");
WriteSysctl("hw.model", "SystemModel");
WriteValue("SystemManufacturer", "apple");
CloseObject(); // parameters
#endif // __APPLE__
CloseObject(); // parameters
}

#ifdef __APPLE__
Expand Down
26 changes: 22 additions & 4 deletions src/coreclr/debug/createdump/createdump.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ extern void trace_verbose_printf(const char* format, ...);
#define TRACE_VERBOSE(args, ...)
#endif

// Keep in sync with the definitions in dbgutil.cpp and daccess.h
#define DACCESS_TABLE_SYMBOL "g_dacTable"

#ifdef HOST_64BIT
#define PRIA "016"
#else
Expand Down Expand Up @@ -87,6 +90,24 @@ typedef int T_CONTEXT;
#include <vector>
#include <array>
#include <string>

typedef struct
{
const char* DumpPathTemplate;
const char* DumpType;
MINIDUMP_TYPE MinidumpType;
bool CreateDump;
bool CrashReport;
int Pid;
int CrashThread;
int Signal;
#if defined(HOST_UNIX) && !defined(HOST_OSX)
int SignalCode;
int SignalErrno;
void* SignalAddress;
#endif
} CreateDumpOptions;

#ifdef HOST_UNIX
#ifdef __APPLE__
#include <mach/mach.h>
Expand All @@ -107,12 +128,9 @@ typedef int T_CONTEXT;
#define MAX_LONGPATH 1024
#endif

extern bool CreateDump(const CreateDumpOptions& options);
extern bool FormatDumpName(std::string& name, const char* pattern, const char* exename, int pid);
extern bool CreateDump(const char* dumpPathTemplate, int pid, const char* dumpType, MINIDUMP_TYPE minidumpType, bool createDump, bool crashReport, int crashThread, int signal);

extern std::string GetLastErrorString();
extern void printf_status(const char* format, ...);
extern void printf_error(const char* format, ...);

// Keep in sync with the definitions in dbgutil.cpp and daccess.h
#define DACCESS_TABLE_SYMBOL "g_dacTable"
26 changes: 13 additions & 13 deletions src/coreclr/debug/createdump/createdumpunix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ long g_pageSize = 0;
// The Linux/MacOS create dump code
//
bool
CreateDump(const char* dumpPathTemplate, int pid, const char* dumpType, MINIDUMP_TYPE minidumpType, bool createDump, bool crashReport, int crashThread, int signal)
CreateDump(const CreateDumpOptions& options)
{
ReleaseHolder<CrashInfo> crashInfo = new CrashInfo(pid, crashReport, crashThread, signal);
ReleaseHolder<CrashInfo> crashInfo = new CrashInfo(options);
DumpWriter dumpWriter(*crashInfo);
std::string dumpPath;
bool result = false;
Expand All @@ -29,11 +29,11 @@ CreateDump(const char* dumpPathTemplate, int pid, const char* dumpType, MINIDUMP
{
goto exit;
}
printf_status("Gathering state for process %d %s\n", pid, crashInfo->Name().c_str());
printf_status("Gathering state for process %d %s\n", options.Pid, crashInfo->Name().c_str());

if (signal != 0 || crashThread != 0)
if (options.Signal != 0 || options.CrashThread != 0)
{
printf_status("Crashing thread %08x signal %08x\n", crashThread, signal);
printf_status("Crashing thread %04x signal %d (%04x)\n", options.CrashThread, options.Signal, options.Signal);
}

// Suspend all the threads in the target process and build the list of threads
Expand All @@ -42,32 +42,32 @@ CreateDump(const char* dumpPathTemplate, int pid, const char* dumpType, MINIDUMP
goto exit;
}
// Gather all the info about the process, threads (registers, etc.) and memory regions
if (!crashInfo->GatherCrashInfo(minidumpType))
if (!crashInfo->GatherCrashInfo(options.MinidumpType))
{
goto exit;
}
// Format the dump pattern template now that the process name on MacOS has been obtained
if (!FormatDumpName(dumpPath, dumpPathTemplate, crashInfo->Name().c_str(), pid))
if (!FormatDumpName(dumpPath, options.DumpPathTemplate, crashInfo->Name().c_str(), options.Pid))
{
goto exit;
}
// Write the crash report json file if enabled
if (crashReport)
if (options.CrashReport)
{
CrashReportWriter crashReportWriter(*crashInfo);
crashReportWriter.WriteCrashReport(dumpPath);
}
if (createDump)
if (options.CreateDump)
{
// Gather all the useful memory regions from the DAC
if (!crashInfo->EnumerateMemoryRegionsWithDAC(minidumpType))
if (!crashInfo->EnumerateMemoryRegionsWithDAC(options.MinidumpType))
{
goto exit;
}
// Join all adjacent memory regions
crashInfo->CombineMemoryRegions();

printf_status("Writing %s to file %s\n", dumpType, dumpPath.c_str());
printf_status("Writing %s to file %s\n", options.DumpType, dumpPath.c_str());

// Write the actual dump file
if (!dumpWriter.OpenDump(dumpPath.c_str()))
Expand All @@ -85,7 +85,7 @@ CreateDump(const char* dumpPathTemplate, int pid, const char* dumpType, MINIDUMP
}
result = true;
exit:
if (kill(pid, 0) == 0)
if (kill(options.Pid, 0) == 0)
{
printf_status("Target process is alive\n");
}
Expand All @@ -98,7 +98,7 @@ CreateDump(const char* dumpPathTemplate, int pid, const char* dumpType, MINIDUMP
}
else
{
printf_error("kill(%d, 0) FAILED %s (%d)\n", pid, strerror(err), err);
printf_error("kill(%d, 0) FAILED %s (%d)\n", options.Pid, strerror(err), err);
}
}
crashInfo->CleanupAndResumeProcess();
Expand Down
14 changes: 7 additions & 7 deletions src/coreclr/debug/createdump/createdumpwindows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ typedef struct _PROCESS_BASIC_INFORMATION_ {
// The Windows create dump code
//
bool
CreateDump(const char* dumpPathTemplate, int pid, const char* dumpType, MINIDUMP_TYPE minidumpType, bool createDump, bool crashReport, int crashThread, int signal)
CreateDump(const CreateDumpOptions& options)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
HANDLE hProcess = NULL;
bool result = false;

_ASSERTE(createDump);
_ASSERTE(!crashReport);
_ASSERTE(options.CreateDump);
_ASSERTE(!options.CrashReport);

ArrayHolder<char> pszName = new char[MAX_LONGPATH + 1];
std::string dumpPath;
Expand All @@ -38,7 +38,7 @@ CreateDump(const char* dumpPathTemplate, int pid, const char* dumpType, MINIDUMP
printf_error("Failed to get parent process id status %d\n", status);
goto exit;
}
pid = (int)processInformation.InheritedFromUniqueProcessId;
int pid = (int)processInformation.InheritedFromUniqueProcessId;

hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess == NULL)
Expand All @@ -51,11 +51,11 @@ CreateDump(const char* dumpPathTemplate, int pid, const char* dumpType, MINIDUMP
printf_error("Get process name FAILED - %s\n", GetLastErrorString().c_str());
goto exit;
}
if (!FormatDumpName(dumpPath, dumpPathTemplate, pszName, pid))
if (!FormatDumpName(dumpPath, options.DumpPathTemplate, pszName, pid))
{
goto exit;
}
printf_status("Writing %s for process %d to file %s\n", dumpType, pid, dumpPath.c_str());
printf_status("Writing %s for process %d to file %s\n", options.DumpType, pid, dumpPath.c_str());

hFile = CreateFileA(dumpPath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
Expand All @@ -67,7 +67,7 @@ CreateDump(const char* dumpPathTemplate, int pid, const char* dumpType, MINIDUMP
// Retry the write dump on ERROR_PARTIAL_COPY
for (int i = 0; i < 5; i++)
{
if (MiniDumpWriteDump(hProcess, pid, hFile, minidumpType, NULL, NULL, NULL))
if (MiniDumpWriteDump(hProcess, pid, hFile, options.MinidumpType, NULL, NULL, NULL))
{
result = true;
break;
Expand Down
33 changes: 27 additions & 6 deletions src/coreclr/debug/createdump/dumpwriterelf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ DumpWriter::WriteDump()
// Write all the thread's state and registers
for (const ThreadInfo* thread : m_crashInfo.Threads())
{
if (!WriteThread(*thread, SIGABRT)) {
if (!WriteThread(*thread)) {
return false;
}
}
Expand Down Expand Up @@ -358,13 +358,20 @@ DumpWriter::WriteNTFileInfo()
}

bool
DumpWriter::WriteThread(const ThreadInfo& thread, int fatal_signal)
DumpWriter::WriteThread(const ThreadInfo& thread)
{
prstatus_t pr;
memset(&pr, 0, sizeof(pr));
const siginfo_t* siginfo = nullptr;

pr.pr_info.si_signo = fatal_signal;
pr.pr_cursig = fatal_signal;
if (m_crashInfo.Signal() != 0 && thread.IsCrashThread())
{
siginfo = m_crashInfo.SigInfo();
pr.pr_info.si_signo = siginfo->si_signo;
pr.pr_info.si_code = siginfo->si_code;
pr.pr_info.si_errno = siginfo->si_errno;
pr.pr_cursig = siginfo->si_signo;
}
pr.pr_pid = thread.Tid();
pr.pr_ppid = thread.Ppid();
pr.pr_pgrp = thread.Tgid();
Expand Down Expand Up @@ -395,9 +402,8 @@ DumpWriter::WriteThread(const ThreadInfo& thread, int fatal_signal)
return false;
}

nhdr.n_namesz = 6;

#if defined(__i386__)
nhdr.n_namesz = 6;
nhdr.n_descsz = sizeof(user_fpxregs_struct);
nhdr.n_type = NT_PRXFPREG;
if (!WriteData(&nhdr, sizeof(nhdr)) ||
Expand All @@ -408,6 +414,7 @@ DumpWriter::WriteThread(const ThreadInfo& thread, int fatal_signal)
#endif

#if defined(__arm__) && defined(__VFP_FP__) && !defined(__SOFTFP__)
nhdr.n_namesz = 6;
nhdr.n_descsz = sizeof(user_vfpregs_struct);
nhdr.n_type = NT_ARM_VFP;
if (!WriteData(&nhdr, sizeof(nhdr)) ||
Expand All @@ -417,5 +424,19 @@ DumpWriter::WriteThread(const ThreadInfo& thread, int fatal_signal)
}
#endif

if (siginfo != nullptr)
{
TRACE("Writing NT_SIGINFO tid %04x signo %d (%04x) code %04x errno %04x addr %p\n",
thread.Tid(), siginfo->si_signo, siginfo->si_signo, siginfo->si_code, siginfo->si_errno, siginfo->si_addr);

nhdr.n_namesz = 5;
nhdr.n_descsz = sizeof(siginfo_t);
nhdr.n_type = NT_SIGINFO;
if (!WriteData(&nhdr, sizeof(nhdr)) ||
!WriteData("CORE\0SIG", 8) ||
!WriteData(siginfo, sizeof(siginfo_t))) {
return false;
}
}
return true;
}
17 changes: 11 additions & 6 deletions src/coreclr/debug/createdump/dumpwriterelf.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
#define NT_FILE 0x46494c45
#endif

#ifndef NT_SIGINFO
#define NT_SIGINFO 0x53494749
#endif

class DumpWriter
{
private:
Expand All @@ -54,21 +58,22 @@ class DumpWriter
bool WriteAuxv();
size_t GetNTFileInfoSize(size_t* alignmentBytes = nullptr);
bool WriteNTFileInfo();
bool WriteThread(const ThreadInfo& thread, int fatal_signal);
bool WriteThread(const ThreadInfo& thread);
bool WriteData(const void* buffer, size_t length) { return WriteData(m_fd, buffer, length); }

size_t GetProcessInfoSize() const { return sizeof(Nhdr) + 8 + sizeof(prpsinfo_t); }
size_t GetAuxvInfoSize() const { return sizeof(Nhdr) + 8 + m_crashInfo.GetAuxvSize(); }
size_t GetThreadInfoSize() const
{
return m_crashInfo.Threads().size() * ((sizeof(Nhdr) + 8 + sizeof(prstatus_t))
+ sizeof(Nhdr) + 8 + sizeof(user_fpregs_struct)
return (m_crashInfo.Signal() != 0 ? (sizeof(Nhdr) + 8 + sizeof(siginfo_t)) : 0)
+ (m_crashInfo.Threads().size() * ((sizeof(Nhdr) + 8 + sizeof(prstatus_t))
+ (sizeof(Nhdr) + 8 + sizeof(user_fpregs_struct))
#if defined(__i386__)
+ sizeof(Nhdr) + 8 + sizeof(user_fpxregs_struct)
+ (sizeof(Nhdr) + 8 + sizeof(user_fpxregs_struct))
#endif
#if defined(__arm__) && defined(__VFP_FP__) && !defined(__SOFTFP__)
+ sizeof(Nhdr) + 8 + sizeof(user_vfpregs_struct)
+ (sizeof(Nhdr) + 8 + sizeof(user_vfpregs_struct))
#endif
);
));
}
};
Loading

0 comments on commit 615de00

Please sign in to comment.