From 615de00422f4f8d80e0009da1a117cc06dbb57e0 Mon Sep 17 00:00:00 2001 From: Mike McLaughlin Date: Sun, 5 Mar 2023 09:50:49 -0800 Subject: [PATCH] Add NT_SIGINFO NOTE to ELF dumps (#82449) * 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 --- src/coreclr/debug/createdump/crashinfo.cpp | 15 +- src/coreclr/debug/createdump/crashinfo.h | 4 +- .../debug/createdump/crashreportwriter.cpp | 4 +- src/coreclr/debug/createdump/createdump.h | 26 +++- .../debug/createdump/createdumpunix.cpp | 26 ++-- .../debug/createdump/createdumpwindows.cpp | 14 +- .../debug/createdump/dumpwriterelf.cpp | 33 ++++- src/coreclr/debug/createdump/dumpwriterelf.h | 17 ++- src/coreclr/debug/createdump/main.cpp | 130 ++++++++++-------- src/coreclr/debug/createdump/threadinfo.cpp | 6 + src/coreclr/debug/createdump/threadinfo.h | 1 + src/coreclr/pal/src/exception/signal.cpp | 12 +- src/coreclr/pal/src/include/pal/process.h | 5 +- src/coreclr/pal/src/thread/process.cpp | 59 +++++++- 14 files changed, 241 insertions(+), 111 deletions(-) diff --git a/src/coreclr/debug/createdump/crashinfo.cpp b/src/coreclr/debug/createdump/crashinfo.cpp index a3bc75a95cc4c..5addb7903ccc9 100644 --- a/src/coreclr/debug/createdump/crashinfo.cpp +++ b/src/coreclr/debug/createdump/crashinfo.cpp @@ -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), @@ -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 } diff --git a/src/coreclr/debug/createdump/crashinfo.h b/src/coreclr/debug/createdump/crashinfo.h index 11e7276273306..de00dee4bbac3 100644 --- a/src/coreclr/debug/createdump/crashinfo.h +++ b/src/coreclr/debug/createdump/crashinfo.h @@ -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//mem handle int m_fdPagemap; // /proc//pagemap handle @@ -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 @@ -127,6 +128,7 @@ class CrashInfo : public ICLRDataEnumMemoryRegionsCallback, public ICLRDataLoggi #ifndef __APPLE__ inline const std::vector& 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 diff --git a/src/coreclr/debug/createdump/crashreportwriter.cpp b/src/coreclr/debug/createdump/crashreportwriter.cpp index 049c2a7a22037..a092e93b42428 100644 --- a/src/coreclr/debug/createdump/crashreportwriter.cpp +++ b/src/coreclr/debug/createdump/crashreportwriter.cpp @@ -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__ diff --git a/src/coreclr/debug/createdump/createdump.h b/src/coreclr/debug/createdump/createdump.h index 15648c897957a..a89fdc3793be6 100644 --- a/src/coreclr/debug/createdump/createdump.h +++ b/src/coreclr/debug/createdump/createdump.h @@ -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 @@ -87,6 +90,24 @@ typedef int T_CONTEXT; #include #include #include + +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 @@ -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" diff --git a/src/coreclr/debug/createdump/createdumpunix.cpp b/src/coreclr/debug/createdump/createdumpunix.cpp index f86a283546a35..b5db55688e43a 100644 --- a/src/coreclr/debug/createdump/createdumpunix.cpp +++ b/src/coreclr/debug/createdump/createdumpunix.cpp @@ -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 = new CrashInfo(pid, crashReport, crashThread, signal); + ReleaseHolder crashInfo = new CrashInfo(options); DumpWriter dumpWriter(*crashInfo); std::string dumpPath; bool result = false; @@ -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 @@ -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())) @@ -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"); } @@ -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(); diff --git a/src/coreclr/debug/createdump/createdumpwindows.cpp b/src/coreclr/debug/createdump/createdumpwindows.cpp index 52cf16e2d0b99..4e8429255a343 100644 --- a/src/coreclr/debug/createdump/createdumpwindows.cpp +++ b/src/coreclr/debug/createdump/createdumpwindows.cpp @@ -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 pszName = new char[MAX_LONGPATH + 1]; std::string dumpPath; @@ -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) @@ -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) @@ -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; diff --git a/src/coreclr/debug/createdump/dumpwriterelf.cpp b/src/coreclr/debug/createdump/dumpwriterelf.cpp index 0cdc0feb6a4f1..be3072d347bbd 100644 --- a/src/coreclr/debug/createdump/dumpwriterelf.cpp +++ b/src/coreclr/debug/createdump/dumpwriterelf.cpp @@ -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; } } @@ -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(); @@ -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)) || @@ -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)) || @@ -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; } diff --git a/src/coreclr/debug/createdump/dumpwriterelf.h b/src/coreclr/debug/createdump/dumpwriterelf.h index cb8731871de21..425d0b9214c3e 100644 --- a/src/coreclr/debug/createdump/dumpwriterelf.h +++ b/src/coreclr/debug/createdump/dumpwriterelf.h @@ -31,6 +31,10 @@ #define NT_FILE 0x46494c45 #endif +#ifndef NT_SIGINFO +#define NT_SIGINFO 0x53494749 +#endif + class DumpWriter { private: @@ -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 - ); + )); } }; diff --git a/src/coreclr/debug/createdump/main.cpp b/src/coreclr/debug/createdump/main.cpp index 96dc36343879e..b54cab825025e 100644 --- a/src/coreclr/debug/createdump/main.cpp +++ b/src/coreclr/debug/createdump/main.cpp @@ -55,22 +55,28 @@ bool g_checkForSingleFile = false; // int __cdecl main(const int argc, const char* argv[]) { - MINIDUMP_TYPE minidumpType = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory | - MiniDumpWithDataSegs | - MiniDumpWithHandleData | - MiniDumpWithUnloadedModules | - MiniDumpWithFullMemoryInfo | - MiniDumpWithThreadInfo | - MiniDumpWithTokenInformation); - const char* dumpType = "minidump with heap"; - const char* dumpPathTemplate = nullptr; - bool crashReport = false; - bool createDump = true; + CreateDumpOptions options; + options.MinidumpType = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory | + MiniDumpWithDataSegs | + MiniDumpWithHandleData | + MiniDumpWithUnloadedModules | + MiniDumpWithFullMemoryInfo | + MiniDumpWithThreadInfo | + MiniDumpWithTokenInformation); + options.DumpType = "minidump with heap"; + options.DumpPathTemplate = nullptr; + options.CrashReport = false; + options.CreateDump = true; + options.Signal = 0; + options.CrashThread = 0; + options.Pid = 0; +#if defined(HOST_UNIX) && !defined(HOST_OSX) + options.SignalCode = 0; + options.SignalErrno = 0; + options.SignalAddress = nullptr; +#endif bool help = false; - int signal = 0; - int crashThread = 0; int exitCode = 0; - int pid = 0; #ifdef HOST_UNIX exitCode = PAL_InitializeDLL(); @@ -89,72 +95,86 @@ int __cdecl main(const int argc, const char* argv[]) { if ((strcmp(*argv, "-f") == 0) || (strcmp(*argv, "--name") == 0)) { - dumpPathTemplate = *++argv; + options.DumpPathTemplate = *++argv; } else if ((strcmp(*argv, "-n") == 0) || (strcmp(*argv, "--normal") == 0)) { - dumpType = "minidump"; - minidumpType = (MINIDUMP_TYPE)(MiniDumpNormal | - MiniDumpWithDataSegs | - MiniDumpWithHandleData | - MiniDumpWithThreadInfo); + options.DumpType = "minidump"; + options.MinidumpType = (MINIDUMP_TYPE)(MiniDumpNormal | + MiniDumpWithDataSegs | + MiniDumpWithHandleData | + MiniDumpWithThreadInfo); } else if ((strcmp(*argv, "-h") == 0) || (strcmp(*argv, "--withheap") == 0)) { - dumpType = "minidump with heap"; - minidumpType = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory | - MiniDumpWithDataSegs | - MiniDumpWithHandleData | - MiniDumpWithUnloadedModules | - MiniDumpWithFullMemoryInfo | - MiniDumpWithThreadInfo | - MiniDumpWithTokenInformation); + options.DumpType = "minidump with heap"; + options.MinidumpType = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory | + MiniDumpWithDataSegs | + MiniDumpWithHandleData | + MiniDumpWithUnloadedModules | + MiniDumpWithFullMemoryInfo | + MiniDumpWithThreadInfo | + MiniDumpWithTokenInformation); } else if ((strcmp(*argv, "-t") == 0) || (strcmp(*argv, "--triage") == 0)) { - dumpType = "triage minidump"; - minidumpType = (MINIDUMP_TYPE)(MiniDumpFilterTriage | - MiniDumpIgnoreInaccessibleMemory | - MiniDumpWithoutOptionalData | - MiniDumpWithProcessThreadData | - MiniDumpFilterModulePaths | - MiniDumpWithUnloadedModules | - MiniDumpFilterMemory | - MiniDumpWithHandleData); + options.DumpType = "triage minidump"; + options.MinidumpType = (MINIDUMP_TYPE)(MiniDumpFilterTriage | + MiniDumpIgnoreInaccessibleMemory | + MiniDumpWithoutOptionalData | + MiniDumpWithProcessThreadData | + MiniDumpFilterModulePaths | + MiniDumpWithUnloadedModules | + MiniDumpFilterMemory | + MiniDumpWithHandleData); } else if ((strcmp(*argv, "-u") == 0) || (strcmp(*argv, "--full") == 0)) { - dumpType = "full dump"; - minidumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | - MiniDumpWithDataSegs | - MiniDumpWithHandleData | - MiniDumpWithUnloadedModules | - MiniDumpWithFullMemoryInfo | - MiniDumpWithThreadInfo | - MiniDumpWithTokenInformation); + options.DumpType = "full dump"; + options.MinidumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | + MiniDumpWithDataSegs | + MiniDumpWithHandleData | + MiniDumpWithUnloadedModules | + MiniDumpWithFullMemoryInfo | + MiniDumpWithThreadInfo | + MiniDumpWithTokenInformation); } #ifdef HOST_UNIX else if (strcmp(*argv, "--crashreport") == 0) { - crashReport = true; + options.CrashReport = true; } else if (strcmp(*argv, "--crashreportonly") == 0) { - crashReport = true; - createDump = false; + options.CrashReport = true; + options.CreateDump = false; } else if (strcmp(*argv, "--crashthread") == 0) { - crashThread = atoi(*++argv); + options.CrashThread = atoi(*++argv); } else if (strcmp(*argv, "--signal") == 0) { - signal = atoi(*++argv); + options.Signal = atoi(*++argv); } else if (strcmp(*argv, "--singlefile") == 0) { g_checkForSingleFile = true; } +#ifndef HOST_OSX + else if (strcmp(*argv, "--code") == 0) + { + options.SignalCode = atoi(*++argv); + } + else if (strcmp(*argv, "--errno") == 0) + { + options.SignalErrno = atoi(*++argv); + } + else if (strcmp(*argv, "--address") == 0) + { + options.SignalAddress = (void*)atoll(*++argv); + } +#endif #endif else if ((strcmp(*argv, "-d") == 0) || (strcmp(*argv, "--diag") == 0)) { @@ -183,7 +203,7 @@ int __cdecl main(const int argc, const char* argv[]) else { #ifdef HOST_UNIX - pid = atoi(*argv); + options.Pid = atoi(*argv); #else printf_error("The pid argument is no longer supported\n"); return -1; @@ -194,7 +214,7 @@ int __cdecl main(const int argc, const char* argv[]) } #ifdef HOST_UNIX - if (pid == 0) + if (options.Pid == 0) { help = true; } @@ -212,7 +232,7 @@ int __cdecl main(const int argc, const char* argv[]) TRACE("TickFrequency: %d ticks per ms\n", g_ticksPerMS); ArrayHolder tmpPath = new char[MAX_LONGPATH]; - if (dumpPathTemplate == nullptr) + if (options.DumpPathTemplate == nullptr) { if (::GetTempPathA(MAX_LONGPATH, tmpPath) == 0) { @@ -225,10 +245,10 @@ int __cdecl main(const int argc, const char* argv[]) printf_error("strcat_s failed (%d)", exitCode); return exitCode; } - dumpPathTemplate = tmpPath; + options.DumpPathTemplate = tmpPath; } - if (CreateDump(dumpPathTemplate, pid, dumpType, minidumpType, createDump, crashReport, crashThread, signal)) + if (CreateDump(options)) { printf_status("Dump successfully written in %llums\n", GetTimeStamp() - g_startTime); } diff --git a/src/coreclr/debug/createdump/threadinfo.cpp b/src/coreclr/debug/createdump/threadinfo.cpp index 8742e457b0158..bd13736846ddc 100644 --- a/src/coreclr/debug/createdump/threadinfo.cpp +++ b/src/coreclr/debug/createdump/threadinfo.cpp @@ -387,3 +387,9 @@ ThreadInfo::GetThreadStack() TRACE("Thread %04x null stack pointer\n", m_tid); } } + +bool +ThreadInfo::IsCrashThread() const +{ + return m_tid == m_crashInfo.CrashThread(); +} diff --git a/src/coreclr/debug/createdump/threadinfo.h b/src/coreclr/debug/createdump/threadinfo.h index ed82c1ec51a65..4600dccb50911 100644 --- a/src/coreclr/debug/createdump/threadinfo.h +++ b/src/coreclr/debug/createdump/threadinfo.h @@ -156,6 +156,7 @@ class ThreadInfo inline const uint64_t GetFramePointer() const { return m_gpRegisters.ARM_fp; } #endif #endif // __APPLE__ + bool IsCrashThread() const; private: void UnwindNativeFrames(CONTEXT* pContext); diff --git a/src/coreclr/pal/src/exception/signal.cpp b/src/coreclr/pal/src/exception/signal.cpp index 7d299212db641..c3bdcc793eb95 100644 --- a/src/coreclr/pal/src/exception/signal.cpp +++ b/src/coreclr/pal/src/exception/signal.cpp @@ -380,7 +380,7 @@ static void invoke_previous_action(struct sigaction* action, int code, siginfo_t if (signalRestarts) { // This signal mustn't be ignored because it will be restarted. - PROCAbort(code); + PROCAbort(code, siginfo); } return; } @@ -395,7 +395,7 @@ static void invoke_previous_action(struct sigaction* action, int code, siginfo_t { // We can't invoke the original handler because returning from the // handler doesn't restart the exception. - PROCAbort(code); + PROCAbort(code, siginfo); } } else if (IsSaSigInfo(action)) @@ -413,7 +413,7 @@ static void invoke_previous_action(struct sigaction* action, int code, siginfo_t PROCNotifyProcessShutdown(IsRunningOnAlternateStack(context)); - PROCCreateCrashDumpIfEnabled(code); + PROCCreateCrashDumpIfEnabled(code, siginfo); } /*++ @@ -585,13 +585,13 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context) if (SwitchStackAndExecuteHandler(code | StackOverflowFlag, siginfo, context, (size_t)handlerStackTop)) { - PROCAbort(SIGSEGV); + PROCAbort(SIGSEGV, siginfo); } } else { (void)!write(STDERR_FILENO, StackOverflowMessage, sizeof(StackOverflowMessage) - 1); - PROCAbort(SIGSEGV); + PROCAbort(SIGSEGV, siginfo); } } @@ -746,7 +746,7 @@ static void sigterm_handler(int code, siginfo_t *siginfo, void *context) DWORD val = 0; if (enableDumpOnSigTerm.IsSet() && enableDumpOnSigTerm.TryAsInteger(10, val) && val == 1) { - PROCCreateCrashDumpIfEnabled(code); + PROCCreateCrashDumpIfEnabled(code, siginfo); } // g_pSynchronizationManager shouldn't be null if PAL is initialized. _ASSERTE(g_pSynchronizationManager != nullptr); diff --git a/src/coreclr/pal/src/include/pal/process.h b/src/coreclr/pal/src/include/pal/process.h index b1de472ad427f..71788cb2d0086 100644 --- a/src/coreclr/pal/src/include/pal/process.h +++ b/src/coreclr/pal/src/include/pal/process.h @@ -151,11 +151,12 @@ BOOL PROCAbortInitialize(); Parameters: signal - POSIX signal number + siginfo - POSIX signal info Does not return --*/ PAL_NORETURN -VOID PROCAbort(int signal = SIGABRT); +VOID PROCAbort(int signal = SIGABRT, siginfo_t* siginfo = nullptr); /*++ Function: @@ -180,7 +181,7 @@ VOID PROCNotifyProcessShutdown(bool isExecutingOnAltStack = false); (no return value) --*/ -VOID PROCCreateCrashDumpIfEnabled(int signal); +VOID PROCCreateCrashDumpIfEnabled(int signal, siginfo_t* siginfo); /*++ Function: diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp index 3f4402214959f..32da7beef37e6 100644 --- a/src/coreclr/pal/src/thread/process.cpp +++ b/src/coreclr/pal/src/thread/process.cpp @@ -2009,6 +2009,28 @@ PROCFormatInt(ULONG32 value) return buffer; } +/*++ +Function: + PROCFormatInt64 + + Helper function to format an ULONG64 as a string. + +--*/ +char* +PROCFormatInt64(ULONG64 value) +{ + char* buffer = (char*)InternalMalloc(128); + if (buffer != nullptr) + { + if (sprintf_s(buffer, 128, "%lld", value) == -1) + { + free(buffer); + buffer = nullptr; + } + } + return buffer; +} + static const INT UndefinedDumpType = 0; /*++ @@ -2376,7 +2398,7 @@ PAL_GenerateCoreDump( (no return value) --*/ VOID -PROCCreateCrashDumpIfEnabled(int signal) +PROCCreateCrashDumpIfEnabled(int signal, siginfo_t* siginfo) { // If enabled, launch the create minidump utility and wait until it completes if (!g_argvCreateDump.empty()) @@ -2384,13 +2406,16 @@ PROCCreateCrashDumpIfEnabled(int signal) std::vector argv(g_argvCreateDump); char* signalArg = nullptr; char* crashThreadArg = nullptr; + char* signalCodeArg = nullptr; + char* signalErrnoArg = nullptr; + char* signalAddressArg = nullptr; if (signal != 0) { // Remove the terminating nullptr argv.pop_back(); - // Add the Windows exception code to the command line + // Add the signal number to the command line signalArg = PROCFormatInt(signal); if (signalArg != nullptr) { @@ -2405,6 +2430,29 @@ PROCCreateCrashDumpIfEnabled(int signal) argv.push_back("--crashthread"); argv.push_back(crashThreadArg); } + + if (siginfo != nullptr) + { + signalCodeArg = PROCFormatInt(siginfo->si_code); + if (signalCodeArg != nullptr) + { + argv.push_back("--code"); + argv.push_back(signalCodeArg); + } + signalErrnoArg = PROCFormatInt(siginfo->si_errno); + if (signalErrnoArg != nullptr) + { + argv.push_back("--errno"); + argv.push_back(signalErrnoArg); + } + signalAddressArg = PROCFormatInt64((ULONG64)siginfo->si_addr); + if (signalAddressArg != nullptr) + { + argv.push_back("--address"); + argv.push_back(signalAddressArg); + } + } + argv.push_back(nullptr); } @@ -2412,6 +2460,9 @@ PROCCreateCrashDumpIfEnabled(int signal) free(signalArg); free(crashThreadArg); + free(signalCodeArg); + free(signalErrnoArg); + free(signalAddressArg); } } @@ -2429,12 +2480,12 @@ PROCCreateCrashDumpIfEnabled(int signal) --*/ PAL_NORETURN VOID -PROCAbort(int signal) +PROCAbort(int signal, siginfo_t* siginfo) { // Do any shutdown cleanup before aborting or creating a core dump PROCNotifyProcessShutdown(); - PROCCreateCrashDumpIfEnabled(signal); + PROCCreateCrashDumpIfEnabled(signal, siginfo); // Restore all signals; the SIGABORT handler to prevent recursion and // the others to prevent multiple core dumps from being generated.