Skip to content

Commit

Permalink
Add NT_SIGINFO NOTE to ELF dumps (#83059)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mikem8361 authored Mar 8, 2023
1 parent b524e93 commit dbb333c
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 @@ -9,16 +9,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 @@ -31,6 +31,11 @@ CrashInfo::CrashInfo(pid_t pid, bool gatherFrames, pid_t crashThread, uint32_t s
#else
m_auxvValues.fill(0);
m_fd = -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 @@ -57,6 +57,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_fd; // /proc/<pid>/mem handle
#endif
Expand All @@ -81,7 +82,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 @@ -125,6 +126,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 @@ -86,6 +89,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 @@ -106,12 +127,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 dbb333c

Please sign in to comment.