From f57b6e7308e9db32e63488aa5e8f938934f54cf0 Mon Sep 17 00:00:00 2001 From: Mike McLaughlin Date: Mon, 12 Jul 2021 08:55:14 -0700 Subject: [PATCH] Add crash report to createdump for Linux Watson (#55438) Add crash report to createdump for Linux Watson For Linux Watson the crash report will contains the .NET Core version, the faulting process name (the module/assembly containing Main) and the managed exception info (including the exception HRESULT) and thread stack trace of the thread the caused the crash. Add the CLRDATA_MODULE_IS_MAIN_MODULE flag to the DAC's IXCLRDataModule::GetFlags API. Add code to get the managed method name and write it out as "method_name" (even on MacOS). Add native frame symbolization (unmanaged_name) using dladdr. Only get the image info once and save in a global Demangle the stack frame symbols Only write PH_HDR_CANARY section if neccessary --- src/coreclr/debug/createdump/CMakeLists.txt | 1 + src/coreclr/debug/createdump/crashinfo.cpp | 87 ++++++++--- src/coreclr/debug/createdump/crashinfo.h | 11 +- src/coreclr/debug/createdump/crashinfomac.cpp | 36 +++++ .../debug/createdump/crashinfounix.cpp | 10 ++ .../debug/createdump/crashreportwriter.cpp | 146 +++++++++++------- .../debug/createdump/crashreportwriter.h | 6 +- src/coreclr/debug/createdump/createdump.h | 2 + src/coreclr/debug/createdump/datatarget.h | 4 + .../debug/createdump/dumpwriterelf.cpp | 35 +++-- src/coreclr/debug/createdump/dumpwriterelf.h | 4 + .../debug/createdump/dumpwritermacho.h | 4 + src/coreclr/debug/createdump/moduleinfo.h | 49 +++--- src/coreclr/debug/createdump/stackframe.h | 42 ++++- src/coreclr/debug/createdump/threadinfo.cpp | 18 ++- src/coreclr/debug/createdump/threadinfo.h | 25 ++- .../debug/createdump/threadinfomac.cpp | 1 + .../debug/createdump/threadinfounix.cpp | 3 +- src/coreclr/debug/daccess/task.cpp | 11 +- src/coreclr/inc/xclrdata.idl | 1 + src/coreclr/pal/prebuilt/inc/xclrdata.h | 3 +- 21 files changed, 364 insertions(+), 135 deletions(-) diff --git a/src/coreclr/debug/createdump/CMakeLists.txt b/src/coreclr/debug/createdump/CMakeLists.txt index 5d766d53da185a..f0093b7cb66601 100644 --- a/src/coreclr/debug/createdump/CMakeLists.txt +++ b/src/coreclr/debug/createdump/CMakeLists.txt @@ -86,6 +86,7 @@ endif(CLR_CMAKE_HOST_OSX) dbgutil # share the PAL in the dac module mscordaccore + dl ) add_dependencies(createdump mscordaccore) diff --git a/src/coreclr/debug/createdump/crashinfo.cpp b/src/coreclr/debug/createdump/crashinfo.cpp index bc444815415cf0..807036fd200822 100644 --- a/src/coreclr/debug/createdump/crashinfo.cpp +++ b/src/coreclr/debug/createdump/crashinfo.cpp @@ -6,13 +6,17 @@ // This is for the PAL_VirtualUnwindOutOfProc read memory adapter. 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) : m_ref(1), m_pid(pid), m_ppid(-1), + m_hdac(nullptr), m_gatherFrames(gatherFrames), m_crashThread(crashThread), - m_signal(signal) + m_signal(signal), + m_moduleInfos(&ModuleInfoCompare) { g_crashInfo = this; #ifdef __APPLE__ @@ -31,6 +35,20 @@ CrashInfo::~CrashInfo() delete thread; } m_threads.clear(); + + // Clean up the modules + for (ModuleInfo* module : m_moduleInfos) + { + delete module; + } + m_moduleInfos.clear(); + + // Unload DAC module + if (m_hdac != nullptr) + { + FreeLibrary(m_hdac); + m_hdac = nullptr; + } #ifdef __APPLE__ if (m_task != 0) { @@ -191,7 +209,6 @@ CrashInfo::EnumerateMemoryRegionsWithDAC(MINIDUMP_TYPE minidumpType) PFN_CLRDataCreateInstance pfnCLRDataCreateInstance = nullptr; ICLRDataEnumMemoryRegions* pClrDataEnumRegions = nullptr; IXCLRDataProcess* pClrDataProcess = nullptr; - HMODULE hdac = nullptr; HRESULT hr = S_OK; bool result = false; @@ -205,13 +222,13 @@ CrashInfo::EnumerateMemoryRegionsWithDAC(MINIDUMP_TYPE minidumpType) dacPath.append(MAKEDLLNAME_A("mscordaccore")); // Load and initialize the DAC - hdac = LoadLibraryA(dacPath.c_str()); - if (hdac == nullptr) + m_hdac = LoadLibraryA(dacPath.c_str()); + if (m_hdac == nullptr) { fprintf(stderr, "LoadLibraryA(%s) FAILED %d\n", dacPath.c_str(), GetLastError()); goto exit; } - pfnCLRDataCreateInstance = (PFN_CLRDataCreateInstance)GetProcAddress(hdac, "CLRDataCreateInstance"); + pfnCLRDataCreateInstance = (PFN_CLRDataCreateInstance)GetProcAddress(m_hdac, "CLRDataCreateInstance"); if (pfnCLRDataCreateInstance == nullptr) { fprintf(stderr, "GetProcAddress(CLRDataCreateInstance) FAILED %d\n", GetLastError()); @@ -262,10 +279,6 @@ CrashInfo::EnumerateMemoryRegionsWithDAC(MINIDUMP_TYPE minidumpType) { pClrDataProcess->Release(); } - if (hdac != nullptr) - { - FreeLibrary(hdac); - } return result; } @@ -347,10 +360,13 @@ CrashInfo::EnumerateManagedModules(IXCLRDataProcess* pClrDataProcess) bool CrashInfo::UnwindAllThreads(IXCLRDataProcess* pClrDataProcess) { + ReleaseHolder pSos = nullptr; + pClrDataProcess->QueryInterface(__uuidof(ISOSDacInterface), (void**)&pSos); + // For each native and managed thread for (ThreadInfo* thread : m_threads) { - if (!thread->UnwindThread(pClrDataProcess)) { + if (!thread->UnwindThread(pClrDataProcess, pSos)) { return false; } } @@ -426,9 +442,9 @@ CrashInfo::GetBaseAddressFromAddress(uint64_t address) uint64_t CrashInfo::GetBaseAddressFromName(const char* moduleName) { - for (const ModuleInfo& moduleInfo : m_moduleInfos) + for (const ModuleInfo* moduleInfo : m_moduleInfos) { - std::string name = GetFileName(moduleInfo.ModuleName()); + std::string name = GetFileName(moduleInfo->ModuleName()); #ifdef __APPLE__ // Module names are case insenstive on MacOS if (strcasecmp(name.c_str(), moduleName) == 0) @@ -436,7 +452,7 @@ CrashInfo::GetBaseAddressFromName(const char* moduleName) if (name.compare(moduleName) == 0) #endif { - return moduleInfo.BaseAddress(); + return moduleInfo->BaseAddress(); } } return 0; @@ -445,14 +461,14 @@ CrashInfo::GetBaseAddressFromName(const char* moduleName) // // Return the module info for the base address // -const ModuleInfo* +ModuleInfo* CrashInfo::GetModuleInfoFromBaseAddress(uint64_t baseAddress) { ModuleInfo search(baseAddress); - const auto& found = m_moduleInfos.find(search); + const auto& found = m_moduleInfos.find(&search); if (found != m_moduleInfos.end()) { - return &*found; + return *found; } return nullptr; } @@ -475,11 +491,12 @@ void CrashInfo::AddModuleInfo(bool isManaged, uint64_t baseAddress, IXCLRDataModule* pClrDataModule, const std::string& moduleName) { ModuleInfo moduleInfo(baseAddress); - const auto& found = m_moduleInfos.find(moduleInfo); + const auto& found = m_moduleInfos.find(&moduleInfo); if (found == m_moduleInfos.end()) { uint32_t timeStamp = 0; uint32_t imageSize = 0; + bool isMainModule = false; GUID mvid; if (isManaged) { @@ -511,11 +528,18 @@ CrashInfo::AddModuleInfo(bool isManaged, uint64_t baseAddress, IXCLRDataModule* } if (pClrDataModule != nullptr) { + ULONG32 flags = 0; + pClrDataModule->GetFlags(&flags); + isMainModule = (flags & CLRDATA_MODULE_IS_MAIN_MODULE) != 0; pClrDataModule->GetVersionId(&mvid); } - TRACE("MODULE: timestamp %08x size %08x %s %s\n", timeStamp, imageSize, FormatGuid(&mvid).c_str(), moduleName.c_str()); + TRACE("MODULE: timestamp %08x size %08x %s %s%s\n", timeStamp, imageSize, FormatGuid(&mvid).c_str(), isMainModule ? "*" : "", moduleName.c_str()); + } + ModuleInfo* moduleInfo = new ModuleInfo(isManaged, baseAddress, timeStamp, imageSize, &mvid, moduleName); + if (isMainModule) { + m_mainModule = moduleInfo; } - m_moduleInfos.insert(ModuleInfo(isManaged, baseAddress, timeStamp, imageSize, &mvid, moduleName)); + m_moduleInfos.insert(moduleInfo); } } @@ -737,6 +761,31 @@ CrashInfo::TraceVerbose(const char* format, ...) } } +// +// Lookup a symbol in a module. The caller needs to call "free()" on symbol returned. +// +const char* +ModuleInfo::GetSymbolName(uint64_t address) +{ + LoadModule(); + + if (m_localBaseAddress != 0) + { + uint64_t localAddress = m_localBaseAddress + (address - m_baseAddress); + Dl_info info; + if (dladdr((void*)localAddress, &info) != 0) + { + if (info.dli_sname != nullptr) + { + int status = -1; + char *demangled = abi::__cxa_demangle(info.dli_sname, nullptr, 0, &status); + return status == 0 ? demangled : strdup(info.dli_sname); + } + } + } + return nullptr; +} + // // Returns just the file name portion of a file path // diff --git a/src/coreclr/debug/createdump/crashinfo.h b/src/coreclr/debug/createdump/crashinfo.h index f315b98dd2877d..199144e17540ec 100644 --- a/src/coreclr/debug/createdump/crashinfo.h +++ b/src/coreclr/debug/createdump/crashinfo.h @@ -46,6 +46,7 @@ class CrashInfo : public ICLRDataEnumMemoryRegionsCallback, pid_t m_pid; // pid pid_t m_ppid; // parent pid pid_t m_tgid; // process group + HMODULE m_hdac; // dac module handle when loaded bool m_gatherFrames; // if true, add the native and managed stack frames to the thread info pid_t m_crashThread; // crashing thread id or 0 if none uint32_t m_signal; // crash signal code or 0 if none @@ -68,7 +69,12 @@ class CrashInfo : public ICLRDataEnumMemoryRegionsCallback, std::set m_otherMappings; // other memory mappings std::set m_memoryRegions; // memory regions from DAC, etc. std::set m_moduleAddresses; // memory region to module base address - std::set m_moduleInfos; // module infos (base address and module name) + std::set m_moduleInfos; // module infos (base address and module name) + ModuleInfo* m_mainModule; // the module containing "Main" + + // no public copy constructor + CrashInfo(const CrashInfo&) = delete; + void operator=(const CrashInfo&) = delete; public: CrashInfo(pid_t pid, bool gatherFrames, pid_t crashThread, uint32_t signal); @@ -82,7 +88,7 @@ class CrashInfo : public ICLRDataEnumMemoryRegionsCallback, bool ReadProcessMemory(void* address, void* buffer, size_t size, size_t* read); // read raw memory uint64_t GetBaseAddressFromAddress(uint64_t address); uint64_t GetBaseAddressFromName(const char* moduleName); - const ModuleInfo* GetModuleInfoFromBaseAddress(uint64_t baseAddress); + ModuleInfo* GetModuleInfoFromBaseAddress(uint64_t baseAddress); void AddModuleAddressRange(uint64_t startAddress, uint64_t endAddress, uint64_t baseAddress); void AddModuleInfo(bool isManaged, uint64_t baseAddress, IXCLRDataModule* pClrDataModule, const std::string& moduleName); void InsertMemoryRegion(uint64_t address, size_t size); @@ -98,6 +104,7 @@ class CrashInfo : public ICLRDataEnumMemoryRegionsCallback, inline const pid_t CrashThread() const { return m_crashThread; } inline const uint32_t Signal() const { return m_signal; } inline const std::string& Name() const { return m_name; } + inline const ModuleInfo* MainModule() const { return m_mainModule; } inline const std::vector Threads() const { return m_threads; } inline const std::set ModuleMappings() const { return m_moduleMappings; } diff --git a/src/coreclr/debug/createdump/crashinfomac.cpp b/src/coreclr/debug/createdump/crashinfomac.cpp index 4461d2a8c96a55..ad9c247e37dfdc 100644 --- a/src/coreclr/debug/createdump/crashinfomac.cpp +++ b/src/coreclr/debug/createdump/crashinfomac.cpp @@ -380,3 +380,39 @@ CrashInfo::ReadProcessMemory(void* address, void* buffer, size_t size, size_t* r *read = numberOfBytesRead; return size == 0 || numberOfBytesRead > 0; } + +const struct dyld_all_image_infos* g_image_infos = nullptr; + +void +ModuleInfo::LoadModule() +{ + if (m_module == nullptr) + { + m_module = dlopen(m_moduleName.c_str(), RTLD_LAZY); + if (m_module != nullptr) + { + if (g_image_infos == nullptr) + { + struct task_dyld_info dyld_info; + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; + kern_return_t result = task_info(mach_task_self_, TASK_DYLD_INFO, (task_info_t)&dyld_info, &count); + if (result == KERN_SUCCESS) + { + g_image_infos = (const struct dyld_all_image_infos*)dyld_info.all_image_info_addr; + } + } + if (g_image_infos != nullptr) + { + for (int i = 0; i < g_image_infos->infoArrayCount; ++i) + { + const struct dyld_image_info* image = g_image_infos->infoArray + i; + if (strcasecmp(image->imageFilePath, m_moduleName.c_str()) == 0) + { + m_localBaseAddress = (uint64_t)image->imageLoadAddress; + break; + } + } + } + } + } +} diff --git a/src/coreclr/debug/createdump/crashinfounix.cpp b/src/coreclr/debug/createdump/crashinfounix.cpp index 2cc1eb6c688fb6..2f9605554ad1f3 100644 --- a/src/coreclr/debug/createdump/crashinfounix.cpp +++ b/src/coreclr/debug/createdump/crashinfounix.cpp @@ -414,3 +414,13 @@ GetStatus(pid_t pid, pid_t* ppid, pid_t* tgid, std::string* name) fclose(statusFile); return true; } + +void +ModuleInfo::LoadModule() +{ + if (m_module == nullptr) + { + m_module = dlopen(m_moduleName.c_str(), RTLD_LAZY); + m_localBaseAddress = ((struct link_map*)m_module)->l_addr; + } +} diff --git a/src/coreclr/debug/createdump/crashreportwriter.cpp b/src/coreclr/debug/createdump/crashreportwriter.cpp index 9cac899968f881..40d8dbdba767a5 100644 --- a/src/coreclr/debug/createdump/crashreportwriter.cpp +++ b/src/coreclr/debug/createdump/crashreportwriter.cpp @@ -51,20 +51,19 @@ CrashReportWriter::WriteCrashReport(const std::string& dumpFileName) } } -#ifdef __APPLE__ - void CrashReportWriter::WriteCrashReport() { - const char* exceptionType = nullptr; OpenObject("payload"); - WriteValue("protocol_version", "0.0.7"); + WriteValue("protocol_version", "1.0.0"); OpenObject("configuration"); #if defined(__x86_64__) WriteValue("architecture", "amd64"); #elif defined(__aarch64__) WriteValue("architecture", "arm64"); +#elif defined(__arm__) + WriteValue("architecture", "arm"); #endif std::string version; assert(strncmp(sccsid, "@(#)Version ", 12) == 0); @@ -73,6 +72,13 @@ CrashReportWriter::WriteCrashReport() WriteValue("version", version.c_str()); CloseObject(); // configuration + // The main module was saved away in the crash info + if (m_crashInfo.MainModule()->BaseAddress() != 0) + { + WriteValue("process_name", GetFileName(m_crashInfo.MainModule()->ModuleName()).c_str()); + } + + const char* exceptionType = nullptr; OpenArray("threads"); for (const ThreadInfo* thread : m_crashInfo.Threads()) { @@ -131,6 +137,10 @@ CrashReportWriter::WriteCrashReport() { WriteValue("managed_exception_type", thread->ManagedExceptionType().c_str()); } + if (thread->ManagedExceptionHResult() != 0) + { + WriteValue32("managed_exception_hresult", thread->ManagedExceptionHResult()); + } WriteValue64("native_thread_id", thread->Tid()); OpenObject("ctx"); WriteValue64("IP", thread->GetInstructionPointer()); @@ -148,7 +158,7 @@ CrashReportWriter::WriteCrashReport() } CloseArray(); // threads CloseObject(); // payload - +#ifdef __APPLE__ OpenObject("parameters"); if (exceptionType != nullptr) { @@ -158,8 +168,35 @@ CrashReportWriter::WriteCrashReport() WriteSysctl("hw.model", "SystemModel"); WriteValue("SystemManufacturer", "apple"); CloseObject(); // parameters +#endif // __APPLE__ } +#ifdef __APPLE__ + +void +CrashReportWriter::WriteSysctl(const char* sysctlname, const char* valueName) +{ + size_t size = 0; + if (sysctlbyname(sysctlname, nullptr, &size, NULL, 0) >= 0) + { + ArrayHolder buffer = new char[size]; + if (sysctlbyname(sysctlname, buffer, &size, NULL, 0) >= 0) + { + WriteValue(valueName, buffer); + } + else + { + TRACE("sysctlbyname(%s) 1 FAILED %s\n", sysctlname, strerror(errno)); + } + } + else + { + TRACE("sysctlbyname(%s) 2 FAILED %s\n", sysctlname, strerror(errno)); + } +} + +#endif // __APPLE__ + void CrashReportWriter::WriteStackFrame(const StackFrame& frame) { @@ -167,16 +204,26 @@ CrashReportWriter::WriteStackFrame(const StackFrame& frame) WriteValueBool("is_managed", frame.IsManaged()); WriteValue64("module_address", frame.ModuleAddress()); WriteValue64("stack_pointer", frame.StackPointer()); - WriteValue64("native_address", frame.ReturnAddress()); + WriteValue64("native_address", frame.InstructionPointer()); WriteValue64("native_offset", frame.NativeOffset()); if (frame.IsManaged()) { WriteValue32("token", frame.Token()); WriteValue32("il_offset", frame.ILOffset()); } + IXCLRDataMethodInstance* pMethod = frame.GetMethod(); + if (pMethod != nullptr) + { + ArrayHolder wszUnicodeName = new WCHAR[MAX_LONGPATH + 1]; + if (SUCCEEDED(pMethod->GetName(0, MAX_LONGPATH, nullptr, wszUnicodeName))) + { + std::string methodName = FormatString("%S", wszUnicodeName.GetPtr()); + WriteValue("method_name", methodName.c_str()); + } + } if (frame.ModuleAddress() != 0) { - const ModuleInfo* moduleInfo = m_crashInfo.GetModuleInfoFromBaseAddress(frame.ModuleAddress()); + ModuleInfo* moduleInfo = m_crashInfo.GetModuleInfoFromBaseAddress(frame.ModuleAddress()); if (moduleInfo != nullptr) { std::string moduleName = GetFileName(moduleInfo->ModuleName()); @@ -189,6 +236,12 @@ CrashReportWriter::WriteStackFrame(const StackFrame& frame) } else { + const char* symbol = moduleInfo->GetSymbolName(frame.InstructionPointer()); + if (symbol != nullptr) + { + WriteValue("unmanaged_name", symbol); + free((void*)symbol); + } WriteValue("native_module", moduleName.c_str()); } } @@ -196,38 +249,8 @@ CrashReportWriter::WriteStackFrame(const StackFrame& frame) CloseObject(); } -void -CrashReportWriter::WriteSysctl(const char* sysctlname, const char* valueName) -{ - size_t size = 0; - if (sysctlbyname(sysctlname, nullptr, &size, NULL, 0) >= 0) - { - ArrayHolder buffer = new char[size]; - if (sysctlbyname(sysctlname, buffer, &size, NULL, 0) >= 0) - { - WriteValue(valueName, buffer); - } - else - { - TRACE("sysctlbyname(%s) 1 FAILED %s\n", sysctlname, strerror(errno)); - } - } - else - { - TRACE("sysctlbyname(%s) 2 FAILED %s\n", sysctlname, strerror(errno)); - } -} - -#else // __APPLE__ - -void -CrashReportWriter::WriteCrashReport() -{ -} - -#endif // __APPLE__ - -bool CrashReportWriter::OpenWriter(const char* fileName) +bool +CrashReportWriter::OpenWriter(const char* fileName) { m_fd = open(fileName, O_WRONLY|O_CREAT|O_TRUNC, 0664); if (m_fd == -1) @@ -239,13 +262,15 @@ bool CrashReportWriter::OpenWriter(const char* fileName) return true; } -void CrashReportWriter::CloseWriter() +void +CrashReportWriter::CloseWriter() { assert(m_indent == JSON_INDENT_VALUE); Write("\n}\n"); } -void CrashReportWriter::Write(const std::string& text) +void +CrashReportWriter::Write(const std::string& text) { if (!DumpWriter::WriteData(m_fd, (void*)text.c_str(), text.length())) { @@ -253,19 +278,22 @@ void CrashReportWriter::Write(const std::string& text) } } -void CrashReportWriter::Write(const char* buffer) +void +CrashReportWriter::Write(const char* buffer) { std::string text(buffer); Write(text); } -void CrashReportWriter::Indent(std::string& text) +void +CrashReportWriter::Indent(std::string& text) { assert(m_indent >= 0); text.append(m_indent, ' '); } -void CrashReportWriter::WriteSeperator(std::string& text) +void +CrashReportWriter::WriteSeperator(std::string& text) { if (m_comma) { @@ -275,7 +303,8 @@ void CrashReportWriter::WriteSeperator(std::string& text) Indent(text); } -void CrashReportWriter::OpenValue(const char* key, char marker) +void +CrashReportWriter::OpenValue(const char* key, char marker) { std::string text; WriteSeperator(text); @@ -292,7 +321,8 @@ void CrashReportWriter::OpenValue(const char* key, char marker) Write(text); } -void CrashReportWriter::CloseValue(char marker) +void +CrashReportWriter::CloseValue(char marker) { std::string text; text.append(1, '\n'); @@ -304,7 +334,8 @@ void CrashReportWriter::CloseValue(char marker) Write(text); } -void CrashReportWriter::WriteValue(const char* key, const char* value) +void +CrashReportWriter::WriteValue(const char* key, const char* value) { std::string text; WriteSeperator(text); @@ -317,41 +348,48 @@ void CrashReportWriter::WriteValue(const char* key, const char* value) Write(text); } -void CrashReportWriter::WriteValueBool(const char* key, bool value) +void +CrashReportWriter::WriteValueBool(const char* key, bool value) { WriteValue(key, value ? "true" : "false"); } -void CrashReportWriter::WriteValue32(const char* key, uint32_t value) +void +CrashReportWriter::WriteValue32(const char* key, uint32_t value) { char buffer[16]; snprintf(buffer, sizeof(buffer), "0x%x", value); WriteValue(key, buffer); } -void CrashReportWriter::WriteValue64(const char* key, uint64_t value) +void +CrashReportWriter::WriteValue64(const char* key, uint64_t value) { char buffer[32]; snprintf(buffer, sizeof(buffer), "0x%" PRIx64, value); WriteValue(key, buffer); } -void CrashReportWriter::OpenObject(const char* key) +void +CrashReportWriter::OpenObject(const char* key) { OpenValue(key, '{'); } -void CrashReportWriter::CloseObject() +void +CrashReportWriter::CloseObject() { CloseValue('}'); } -void CrashReportWriter::OpenArray(const char* key) +void +CrashReportWriter::OpenArray(const char* key) { OpenValue(key, '['); } -void CrashReportWriter::CloseArray() +void +CrashReportWriter::CloseArray() { CloseValue(']'); } diff --git a/src/coreclr/debug/createdump/crashreportwriter.h b/src/coreclr/debug/createdump/crashreportwriter.h index ef77bfcac55927..e5f0f618d944f9 100644 --- a/src/coreclr/debug/createdump/crashreportwriter.h +++ b/src/coreclr/debug/createdump/crashreportwriter.h @@ -13,6 +13,10 @@ class CrashReportWriter bool m_comma; CrashInfo& m_crashInfo; + // no public copy constructor + CrashReportWriter(const CrashReportWriter&) = delete; + void operator=(const CrashReportWriter&) = delete; + public: CrashReportWriter(CrashInfo& crashInfo); virtual ~CrashReportWriter(); @@ -21,9 +25,9 @@ class CrashReportWriter private: void WriteCrashReport(); #ifdef __APPLE__ - void WriteStackFrame(const StackFrame& frame); void WriteSysctl(const char* sysctlname, const char* valueName); #endif + void WriteStackFrame(const StackFrame& frame); void Write(const std::string& text); void Write(const char* buffer); void Indent(std::string& text); diff --git a/src/coreclr/debug/createdump/createdump.h b/src/coreclr/debug/createdump/createdump.h index 95f63f460e4af5..f588867c7926f8 100644 --- a/src/coreclr/debug/createdump/createdump.h +++ b/src/coreclr/debug/createdump/createdump.h @@ -71,6 +71,8 @@ typedef int T_CONTEXT; #endif #include #include +#include +#include #ifdef __APPLE__ #include #else diff --git a/src/coreclr/debug/createdump/datatarget.h b/src/coreclr/debug/createdump/datatarget.h index 954ff5328b4e71..792947bafe2172 100644 --- a/src/coreclr/debug/createdump/datatarget.h +++ b/src/coreclr/debug/createdump/datatarget.h @@ -9,6 +9,10 @@ class DumpDataTarget : public ICLRDataTarget LONG m_ref; // reference count CrashInfo& m_crashInfo; + // no public copy constructor + DumpDataTarget(const DumpDataTarget&) = delete; + void operator=(const DumpDataTarget&) = delete; + public: DumpDataTarget(CrashInfo& crashInfo); virtual ~DumpDataTarget(); diff --git a/src/coreclr/debug/createdump/dumpwriterelf.cpp b/src/coreclr/debug/createdump/dumpwriterelf.cpp index 57249d83f7e6c7..afd403212b2473 100644 --- a/src/coreclr/debug/createdump/dumpwriterelf.cpp +++ b/src/coreclr/debug/createdump/dumpwriterelf.cpp @@ -32,12 +32,10 @@ DumpWriter::WriteDump() ehdr.e_type = ET_CORE; ehdr.e_machine = ELF_ARCH; ehdr.e_version = EV_CURRENT; - ehdr.e_shoff = sizeof(Ehdr); - ehdr.e_phoff = sizeof(Ehdr) + sizeof(Shdr); + ehdr.e_phoff = sizeof(Ehdr); ehdr.e_ehsize = sizeof(Ehdr); ehdr.e_phentsize = sizeof(Phdr); - ehdr.e_shentsize = sizeof(Shdr); // The ELF header only allows UINT16 for the number of program // headers. In a core dump this equates to PT_NODE and PT_LOAD. @@ -60,26 +58,33 @@ DumpWriter::WriteDump() } else { ehdr.e_phnum = PH_HDR_CANARY; + ehdr.e_phoff = sizeof(Ehdr) + sizeof(Shdr); + ehdr.e_shnum = 1; + ehdr.e_shoff = sizeof(Ehdr); + ehdr.e_shentsize = sizeof(Shdr); } if (!WriteData(&ehdr, sizeof(Ehdr))) { return false; } - size_t offset = sizeof(Ehdr) + sizeof(Shdr) + (phnum * sizeof(Phdr)); + size_t offset = sizeof(Ehdr) + (phnum * sizeof(Phdr)); size_t filesz = GetProcessInfoSize() + GetAuxvInfoSize() + GetThreadInfoSize() + GetNTFileInfoSize(); - // Add single section containing the actual count - // of the program headers to be written. - Shdr shdr; - memset(&shdr, 0, sizeof(shdr)); - shdr.sh_info = phnum; - // When section header offset is present but ehdr section num = 0 - // then is is expected that the sh_size indicates the size of the - // section array or 1 in our case. - shdr.sh_size = 1; - if (!WriteData(&shdr, sizeof(shdr))) { - return false; + if (ehdr.e_phnum == PH_HDR_CANARY) + { + // Add single section containing the actual count of the program headers to be written. + Shdr shdr; + memset(&shdr, 0, sizeof(shdr)); + shdr.sh_info = phnum; + shdr.sh_size = 1; + offset += sizeof(Shdr); + + // When section header offset is present but ehdr section num = 0 then is is expected that + // the sh_size indicates the size of the section array or 1 in our case. + if (!WriteData(&shdr, sizeof(shdr))) { + return false; + } } // PT_NOTE header diff --git a/src/coreclr/debug/createdump/dumpwriterelf.h b/src/coreclr/debug/createdump/dumpwriterelf.h index ac4dc10fd2f139..6da55da2f13750 100644 --- a/src/coreclr/debug/createdump/dumpwriterelf.h +++ b/src/coreclr/debug/createdump/dumpwriterelf.h @@ -36,6 +36,10 @@ class DumpWriter CrashInfo& m_crashInfo; BYTE m_tempBuffer[0x4000]; + // no public copy constructor + DumpWriter(const DumpWriter&) = delete; + void operator=(const DumpWriter&) = delete; + public: DumpWriter(CrashInfo& crashInfo); virtual ~DumpWriter(); diff --git a/src/coreclr/debug/createdump/dumpwritermacho.h b/src/coreclr/debug/createdump/dumpwritermacho.h index 6be2aa7742b602..704ea084882140 100644 --- a/src/coreclr/debug/createdump/dumpwritermacho.h +++ b/src/coreclr/debug/createdump/dumpwritermacho.h @@ -30,6 +30,10 @@ class DumpWriter std::vector m_threadLoadCommands; BYTE m_tempBuffer[0x4000]; + // no public copy constructor + DumpWriter(const DumpWriter&) = delete; + void operator=(const DumpWriter&) = delete; + public: DumpWriter(CrashInfo& crashInfo); virtual ~DumpWriter(); diff --git a/src/coreclr/debug/createdump/moduleinfo.h b/src/coreclr/debug/createdump/moduleinfo.h index f07e50d592f08a..2876562fba2dd4 100644 --- a/src/coreclr/debug/createdump/moduleinfo.h +++ b/src/coreclr/debug/createdump/moduleinfo.h @@ -10,10 +10,27 @@ struct ModuleInfo GUID m_mvid; std::string m_moduleName; bool m_isManaged; + void* m_module; + uint64_t m_localBaseAddress; + + // no public copy constructor + ModuleInfo(const ModuleInfo&) = delete; + void operator=(const ModuleInfo&) = delete; + + void LoadModule(); public: + ModuleInfo() : + m_baseAddress(0), + m_module(nullptr), + m_localBaseAddress(0) + { + } + ModuleInfo(uint64_t baseAddress) : - m_baseAddress(baseAddress) + m_baseAddress(baseAddress), + m_module(nullptr), + m_localBaseAddress(0) { } @@ -23,23 +40,19 @@ struct ModuleInfo m_imageSize(imageSize), m_mvid(*mvid), m_moduleName(moduleName), - m_isManaged(isManaged) - { - } - - // copy constructor - ModuleInfo(const ModuleInfo& moduleInfo) : - m_baseAddress(moduleInfo.m_baseAddress), - m_timeStamp(moduleInfo.m_timeStamp), - m_imageSize(moduleInfo.m_imageSize), - m_mvid(moduleInfo.m_mvid), - m_moduleName(moduleInfo.m_moduleName), - m_isManaged(moduleInfo.m_isManaged) + m_isManaged(isManaged), + m_module(nullptr), + m_localBaseAddress(0) { } ~ModuleInfo() { + if (m_module != nullptr) + { + dlclose(m_module); + m_module = nullptr; + } } inline bool IsManaged() const { return m_isManaged; } @@ -49,13 +62,5 @@ struct ModuleInfo inline const GUID* Mvid() const { return &m_mvid; } inline const std::string& ModuleName() const { return m_moduleName; } - bool operator<(const ModuleInfo& rhs) const - { - return m_baseAddress < rhs.m_baseAddress; - } - - void Trace() const - { - TRACE("%" PRIA PRIx64 " %s\n", m_baseAddress, m_moduleName.c_str()); - } + const char* GetSymbolName(uint64_t address); }; diff --git a/src/coreclr/debug/createdump/stackframe.h b/src/coreclr/debug/createdump/stackframe.h index 90db2697b812bf..75e20d93120c0c 100644 --- a/src/coreclr/debug/createdump/stackframe.h +++ b/src/coreclr/debug/createdump/stackframe.h @@ -5,45 +5,75 @@ struct StackFrame { private: uint64_t m_moduleAddress; - uint64_t m_returnAddress; + uint64_t m_instructionPointer; uint64_t m_stackPointer; uint32_t m_nativeOffset; uint32_t m_token; uint32_t m_ilOffset; + IXCLRDataMethodInstance* m_pMethod; bool m_isManaged; public: // Create native stack frame - StackFrame(uint64_t moduleAddress, uint64_t returnAddress, uint64_t stackPointer, uint32_t nativeOffset) : + StackFrame(uint64_t moduleAddress, uint64_t instructionPointer, uint64_t stackPointer, uint32_t nativeOffset) : m_moduleAddress(moduleAddress), - m_returnAddress(returnAddress), + m_instructionPointer(instructionPointer), m_stackPointer(stackPointer), m_nativeOffset(nativeOffset), m_token(0), m_ilOffset(0), + m_pMethod(nullptr), m_isManaged(false) { } // Create managed stack frame - StackFrame(uint64_t moduleAddress, uint64_t returnAddress, uint64_t stackPointer, uint32_t nativeOffset, uint64_t token, uint32_t ilOffset) : + StackFrame(uint64_t moduleAddress, uint64_t instructionPointer, uint64_t stackPointer, IXCLRDataMethodInstance* pMethod, uint32_t nativeOffset, uint64_t token, uint32_t ilOffset) : m_moduleAddress(moduleAddress), - m_returnAddress(returnAddress), + m_instructionPointer(instructionPointer), m_stackPointer(stackPointer), m_nativeOffset(nativeOffset), m_token(token), m_ilOffset(ilOffset), + m_pMethod(pMethod), m_isManaged(true) { } + // copy constructor + StackFrame(const StackFrame& frame) : + m_moduleAddress(frame.m_moduleAddress), + m_instructionPointer(frame.m_instructionPointer), + m_stackPointer(frame.m_stackPointer), + m_nativeOffset(frame.m_nativeOffset), + m_token(frame.m_token), + m_ilOffset(frame.m_ilOffset), + m_pMethod(frame.m_pMethod), + m_isManaged(frame.m_isManaged) + { + if (m_pMethod != nullptr) + { + m_pMethod->AddRef(); + } + } + + ~StackFrame() + { + if (m_pMethod != nullptr) + { + m_pMethod->Release(); + m_pMethod = nullptr; + } + } + inline uint64_t ModuleAddress() const { return m_moduleAddress; } - inline uint64_t ReturnAddress() const { return m_returnAddress; } + inline uint64_t InstructionPointer() const { return m_instructionPointer; } inline uint64_t StackPointer() const { return m_stackPointer; } inline uint32_t NativeOffset() const { return m_nativeOffset; } inline uint32_t Token() const { return m_token; } inline uint32_t ILOffset() const { return m_ilOffset; } inline bool IsManaged() const { return m_isManaged; } + inline IXCLRDataMethodInstance* GetMethod() const { return m_pMethod; } bool operator<(const StackFrame& rhs) const { diff --git a/src/coreclr/debug/createdump/threadinfo.cpp b/src/coreclr/debug/createdump/threadinfo.cpp index 99284ed040247c..2107c6c1bafb73 100644 --- a/src/coreclr/debug/createdump/threadinfo.cpp +++ b/src/coreclr/debug/createdump/threadinfo.cpp @@ -107,7 +107,7 @@ ThreadInfo::UnwindNativeFrames(CONTEXT* pContext) } bool -ThreadInfo::UnwindThread(IXCLRDataProcess* pClrDataProcess) +ThreadInfo::UnwindThread(IXCLRDataProcess* pClrDataProcess, ISOSDacInterface* pSos) { TRACE("Unwind: thread %04x\n", Tid()); @@ -152,7 +152,15 @@ ThreadInfo::UnwindThread(IXCLRDataProcess* pClrDataProcess) if (SUCCEEDED(pExceptionValue->GetAddress(&exceptionObject))) { m_exceptionObject = exceptionObject; - TRACE("Unwind: exception object %p\n", (void*)exceptionObject); + if (pSos != nullptr) + { + DacpExceptionObjectData exceptionData; + if (SUCCEEDED(exceptionData.Request(pSos, exceptionObject))) + { + m_exceptionHResult = exceptionData.HResult; + } + } + TRACE("Unwind: exception object %p exception hresult %08x\n", (void*)m_exceptionObject, m_exceptionHResult); } ReleaseHolder pExceptionType; if (SUCCEEDED(pExceptionValue->GetType(&pExceptionType))) @@ -202,6 +210,7 @@ ThreadInfo::GatherStackFrames(CONTEXT* pContext, IXCLRDataStackWalk* pStackwalk) mdMethodDef token = 0; uint32_t nativeOffset = 0; uint32_t ilOffset = 0; + ReleaseHolder pMethod; ReleaseHolder pFrame; if (SUCCEEDED(pStackwalk->GetFrame(&pFrame))) @@ -212,7 +221,6 @@ ThreadInfo::GatherStackFrames(CONTEXT* pContext, IXCLRDataStackWalk* pStackwalk) if ((simpleType & (CLRDATA_SIMPFRAME_MANAGED_METHOD | CLRDATA_SIMPFRAME_RUNTIME_MANAGED_CODE)) != 0) { - ReleaseHolder pMethod; if (SUCCEEDED(pFrame->GetMethodInstance(&pMethod))) { ReleaseHolder pModule; @@ -258,7 +266,7 @@ ThreadInfo::GatherStackFrames(CONTEXT* pContext, IXCLRDataStackWalk* pStackwalk) } // Add managed stack frame for the crash info notes - StackFrame frame(moduleAddress, ip, sp, nativeOffset, token, ilOffset); + StackFrame frame(moduleAddress, ip, sp, pMethod.Detach(), nativeOffset, token, ilOffset); AddStackFrame(frame); } @@ -270,7 +278,7 @@ ThreadInfo::AddStackFrame(const StackFrame& frame) { TRACE("Unwind: sp %p ip %p off %08x mod %p%c\n", (void*)frame.StackPointer(), - (void*)frame.ReturnAddress(), + (void*)frame.InstructionPointer(), frame.NativeOffset(), (void*)frame.ModuleAddress(), frame.IsManaged() ? '*' : ' '); diff --git a/src/coreclr/debug/createdump/threadinfo.h b/src/coreclr/debug/createdump/threadinfo.h index 1a690157908c37..7ce0df5f1ec18c 100644 --- a/src/coreclr/debug/createdump/threadinfo.h +++ b/src/coreclr/debug/createdump/threadinfo.h @@ -42,7 +42,8 @@ class ThreadInfo pid_t m_tgid; // thread group bool m_managed; // if true, thread has managed code running uint64_t m_exceptionObject; // exception object address - std::string m_exceptionType; // exception type + std::string m_exceptionType; // exception type + int32_t m_exceptionHResult; // exception HRESULT std::set m_frames; // stack frames #ifdef __APPLE__ @@ -64,6 +65,10 @@ class ThreadInfo #endif #endif // __APPLE__ + // no public copy constructor + ThreadInfo(const ThreadInfo&) = delete; + void operator=(const ThreadInfo&) = delete; + public: #ifdef __APPLE__ ThreadInfo(CrashInfo& crashInfo, pid_t tid, mach_port_t port); @@ -73,7 +78,7 @@ class ThreadInfo #endif ~ThreadInfo(); bool Initialize(); - bool UnwindThread(IXCLRDataProcess* pClrDataProcess); + bool UnwindThread(IXCLRDataProcess* pClrDataProcess, ISOSDacInterface* pSos); void GetThreadStack(); void GetThreadContext(uint32_t flags, CONTEXT* context) const; @@ -83,6 +88,7 @@ class ThreadInfo inline bool IsManaged() const { return m_managed; } inline uint64_t ManagedExceptionObject() const { return m_exceptionObject; } + inline int32_t ManagedExceptionHResult() const { return m_exceptionHResult; } inline std::string ManagedExceptionType() const { return m_exceptionType; } inline const std::set StackFrames() const { return m_frames; } @@ -108,16 +114,19 @@ class ThreadInfo #elif defined(__arm__) && defined(__VFP_FP__) && !defined(__SOFTFP__) inline const user_vfpregs_struct* VFPRegisters() const { return &m_vfpRegisters; } #endif - inline const uint64_t GetStackPointer() const - { #if defined(__x86_64__) - return m_gpRegisters.rsp; + inline const uint64_t GetInstructionPointer() const { return m_gpRegisters.rip; } + inline const uint64_t GetStackPointer() const { return m_gpRegisters.rsp; } + inline const uint64_t GetFramePointer() const { return m_gpRegisters.rbp; } #elif defined(__aarch64__) - return MCREG_Sp(m_gpRegisters); + inline const uint64_t GetInstructionPointer() const { return MCREG_Pc(m_gpRegisters); } + inline const uint64_t GetStackPointer() const { return MCREG_Sp(m_gpRegisters); } + inline const uint64_t GetFramePointer() const { return MCREG_Fp(m_gpRegisters); } #elif defined(__arm__) - return m_gpRegisters.ARM_sp; + inline const uint64_t GetInstructionPointer() const { return m_gpRegisters.ARM_pc; } + inline const uint64_t GetStackPointer() const { return m_gpRegisters.ARM_sp; } + inline const uint64_t GetFramePointer() const { return m_gpRegisters.ARM_fp; } #endif - } #endif // __APPLE__ private: diff --git a/src/coreclr/debug/createdump/threadinfomac.cpp b/src/coreclr/debug/createdump/threadinfomac.cpp index 3ea9151a6494f8..92b9339088fcab 100644 --- a/src/coreclr/debug/createdump/threadinfomac.cpp +++ b/src/coreclr/debug/createdump/threadinfomac.cpp @@ -8,6 +8,7 @@ ThreadInfo::ThreadInfo(CrashInfo& crashInfo, pid_t tid, mach_port_t port) : m_tid(tid), m_managed(false), m_exceptionObject(0), + m_exceptionHResult(0), m_port(port) { } diff --git a/src/coreclr/debug/createdump/threadinfounix.cpp b/src/coreclr/debug/createdump/threadinfounix.cpp index c1e5ca1154cca3..90a4c8ab9ffe50 100644 --- a/src/coreclr/debug/createdump/threadinfounix.cpp +++ b/src/coreclr/debug/createdump/threadinfounix.cpp @@ -26,7 +26,8 @@ ThreadInfo::ThreadInfo(CrashInfo& crashInfo, pid_t tid) : m_crashInfo(crashInfo), m_tid(tid), m_managed(false), - m_exceptionObject(0) + m_exceptionObject(0), + m_exceptionHResult(0) { } diff --git a/src/coreclr/debug/daccess/task.cpp b/src/coreclr/debug/daccess/task.cpp index b16f85d8773ef1..c3143bf243b710 100644 --- a/src/coreclr/debug/daccess/task.cpp +++ b/src/coreclr/debug/daccess/task.cpp @@ -2503,7 +2503,16 @@ ClrDataModule::GetFlags( { (*flags) |= CLRDATA_MODULE_IS_MEMORY_STREAM; } - + PTR_Assembly pAssembly = m_module->GetAssembly(); + PTR_BaseDomain pBaseDomain = pAssembly->GetDomain(); + if (pBaseDomain->IsAppDomain()) + { + AppDomain* pAppDomain = pBaseDomain->AsAppDomain(); + if (pAssembly == pAppDomain->GetRootAssembly()) + { + (*flags) |= CLRDATA_MODULE_IS_MAIN_MODULE; + } + } status = S_OK; } EX_CATCH diff --git a/src/coreclr/inc/xclrdata.idl b/src/coreclr/inc/xclrdata.idl index 818915a29ccec7..aeddf9529bee4f 100644 --- a/src/coreclr/inc/xclrdata.idl +++ b/src/coreclr/inc/xclrdata.idl @@ -1014,6 +1014,7 @@ typedef enum CLRDATA_MODULE_DEFAULT = 0x00000000, CLRDATA_MODULE_IS_DYNAMIC = 0x00000001, CLRDATA_MODULE_IS_MEMORY_STREAM = 0x00000002, + CLRDATA_MODULE_IS_MAIN_MODULE = 0x00000004, } CLRDataModuleFlag; typedef enum diff --git a/src/coreclr/pal/prebuilt/inc/xclrdata.h b/src/coreclr/pal/prebuilt/inc/xclrdata.h index dbee62b9b12254..b28463dc86c780 100644 --- a/src/coreclr/pal/prebuilt/inc/xclrdata.h +++ b/src/coreclr/pal/prebuilt/inc/xclrdata.h @@ -3300,7 +3300,8 @@ enum __MIDL___MIDL_itf_xclrdata_0000_0008_0001 { CLRDATA_MODULE_DEFAULT = 0, CLRDATA_MODULE_IS_DYNAMIC = 0x1, - CLRDATA_MODULE_IS_MEMORY_STREAM = 0x2 + CLRDATA_MODULE_IS_MEMORY_STREAM = 0x2, + CLRDATA_MODULE_IS_MAIN_MODULE = 0x4 } CLRDataModuleFlag; typedef /* [public][public][public] */