Skip to content

Commit

Permalink
Add crash report to createdump for Linux Watson (dotnet#55438)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mikem8361 authored Jul 12, 2021
1 parent f28318b commit f57b6e7
Show file tree
Hide file tree
Showing 21 changed files with 364 additions and 135 deletions.
1 change: 1 addition & 0 deletions src/coreclr/debug/createdump/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ endif(CLR_CMAKE_HOST_OSX)
dbgutil
# share the PAL in the dac module
mscordaccore
dl
)

add_dependencies(createdump mscordaccore)
Expand Down
87 changes: 68 additions & 19 deletions src/coreclr/debug/createdump/crashinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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__
Expand All @@ -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)
{
Expand Down Expand Up @@ -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;

Expand All @@ -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());
Expand Down Expand Up @@ -262,10 +279,6 @@ CrashInfo::EnumerateMemoryRegionsWithDAC(MINIDUMP_TYPE minidumpType)
{
pClrDataProcess->Release();
}
if (hdac != nullptr)
{
FreeLibrary(hdac);
}
return result;
}

Expand Down Expand Up @@ -347,10 +360,13 @@ CrashInfo::EnumerateManagedModules(IXCLRDataProcess* pClrDataProcess)
bool
CrashInfo::UnwindAllThreads(IXCLRDataProcess* pClrDataProcess)
{
ReleaseHolder<ISOSDacInterface> 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;
}
}
Expand Down Expand Up @@ -426,17 +442,17 @@ 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)
#else
if (name.compare(moduleName) == 0)
#endif
{
return moduleInfo.BaseAddress();
return moduleInfo->BaseAddress();
}
}
return 0;
Expand All @@ -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;
}
Expand All @@ -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)
{
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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
//
Expand Down
11 changes: 9 additions & 2 deletions src/coreclr/debug/createdump/crashinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -68,7 +69,12 @@ class CrashInfo : public ICLRDataEnumMemoryRegionsCallback,
std::set<MemoryRegion> m_otherMappings; // other memory mappings
std::set<MemoryRegion> m_memoryRegions; // memory regions from DAC, etc.
std::set<MemoryRegion> m_moduleAddresses; // memory region to module base address
std::set<ModuleInfo> m_moduleInfos; // module infos (base address and module name)
std::set<ModuleInfo*, bool (*)(const ModuleInfo* lhs, const ModuleInfo* rhs)> 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);
Expand All @@ -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);
Expand All @@ -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<ThreadInfo*> Threads() const { return m_threads; }
inline const std::set<MemoryRegion> ModuleMappings() const { return m_moduleMappings; }
Expand Down
36 changes: 36 additions & 0 deletions src/coreclr/debug/createdump/crashinfomac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
}
}
}
10 changes: 10 additions & 0 deletions src/coreclr/debug/createdump/crashinfounix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Loading

0 comments on commit f57b6e7

Please sign in to comment.