// Gather all the necessary crash dump info.
//
bool
-CrashInfo::GatherCrashInfo(const char* programPath, MINIDUMP_TYPE minidumpType)
+CrashInfo::GatherCrashInfo(MINIDUMP_TYPE minidumpType)
{
// Get the process info
if (!GetStatus(m_pid, &m_ppid, &m_tgid, &m_name))
}
}
// Gather all the useful memory regions from the DAC
- if (!EnumerateMemoryRegionsWithDAC(programPath, minidumpType))
+ if (!EnumerateMemoryRegionsWithDAC(minidumpType))
{
return false;
}
}
MemoryRegion memoryRegion(regionFlags, start, end, offset, moduleName);
- if (moduleName != nullptr && *moduleName == '/') {
+ if (moduleName != nullptr && *moduleName == '/')
+ {
+ if (m_coreclrPath.empty())
+ {
+ std::string coreclrPath;
+ coreclrPath.append(moduleName);
+ size_t last = coreclrPath.rfind(MAKEDLLNAME_A("coreclr"));
+ if (last != -1) {
+ m_coreclrPath = coreclrPath.substr(0, last);
+ }
+ }
m_moduleMappings.insert(memoryRegion);
}
- else {
+ else
+ {
m_otherMappings.insert(memoryRegion);
}
if (linuxGateAddress != nullptr && reinterpret_cast<void*>(start) == linuxGateAddress)
return false;
}
uint64_t baseAddress = (uint64_t)phdrAddr - sizeof(Ehdr);
- TRACE("DSO: base %" PRIA PRIx64 " phdr %p phnum %d\n", baseAddress, phdrAddr, phnum);
-
- // Search for the program PT_DYNAMIC header
ElfW(Dyn)* dynamicAddr = nullptr;
- for (int i = 0; i < phnum; i++, phdrAddr++)
- {
- Phdr ph;
- if (!ReadMemory(phdrAddr, &ph, sizeof(ph))) {
- fprintf(stderr, "ReadMemory(%p, %" PRIx ") phdr FAILED\n", phdrAddr, sizeof(ph));
- return false;
- }
- TRACE("DSO: phdr %p type %d (%x) vaddr %" PRIxA " memsz %" PRIxA " offset %" PRIxA "\n",
- phdrAddr, ph.p_type, ph.p_type, ph.p_vaddr, ph.p_memsz, ph.p_offset);
- switch (ph.p_type)
- {
- case PT_DYNAMIC:
- dynamicAddr = reinterpret_cast<ElfW(Dyn)*>(ph.p_vaddr);
- break;
-
- case PT_NOTE:
- case PT_GNU_EH_FRAME:
- if (ph.p_vaddr != 0 && ph.p_memsz != 0) {
- InsertMemoryRegion(ph.p_vaddr, ph.p_memsz);
- }
- break;
+ TRACE("DSO: base %" PRIA PRIx64 " phdr %p phnum %d\n", baseAddress, phdrAddr, phnum);
- case PT_LOAD:
- MemoryRegion region(0, ph.p_vaddr, ph.p_vaddr + ph.p_memsz, baseAddress);
- m_moduleAddresses.insert(region);
- break;
- }
+ // Enumerate program headers searching for the PT_DYNAMIC header, etc.
+ if (!EnumerateProgramHeaders(phdrAddr, phnum, baseAddress, &dynamicAddr))
+ {
+ return false;
}
-
if (dynamicAddr == nullptr) {
return false;
}
{
Phdr* phdrAddr = reinterpret_cast<Phdr*>(baseAddress + ehdr.e_phoff);
- // Add the program headers and search for the module's note and unwind info segments
- for (int i = 0; i < phnum; i++, phdrAddr++)
+ if (!EnumerateProgramHeaders(phdrAddr, phnum, baseAddress, nullptr))
{
- Phdr ph;
- if (!ReadMemory(phdrAddr, &ph, sizeof(ph))) {
- fprintf(stderr, "ReadMemory(%p, %" PRIx ") phdr FAILED\n", phdrAddr, sizeof(ph));
- return false;
- }
- TRACE("ELF: phdr %p type %d (%x) vaddr %" PRIxA " memsz %" PRIxA " paddr %" PRIxA " filesz %" PRIxA " offset %" PRIxA " align %" PRIxA "\n",
- phdrAddr, ph.p_type, ph.p_type, ph.p_vaddr, ph.p_memsz, ph.p_paddr, ph.p_filesz, ph.p_offset, ph.p_align);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+//
+// Enumerate the program headers adding the build id note, unwind frame
+// region and module addresses to the crash info.
+//
+bool
+CrashInfo::EnumerateProgramHeaders(Phdr* phdrAddr, int phnum, uint64_t baseAddress, ElfW(Dyn)** pdynamicAddr)
+{
+ uint64_t loadbias = baseAddress;
- switch (ph.p_type)
+ for (int i = 0; i < phnum; i++)
+ {
+ Phdr ph;
+ if (!ReadMemory(phdrAddr + i, &ph, sizeof(ph))) {
+ fprintf(stderr, "ReadMemory(%p, %" PRIx ") phdr FAILED\n", phdrAddr + i, sizeof(ph));
+ return false;
+ }
+ if (ph.p_type == PT_LOAD && ph.p_offset == 0)
+ {
+ loadbias -= ph.p_vaddr;
+ TRACE("PHDR: loadbias %" PRIA PRIx64 "\n", loadbias);
+ break;
+ }
+ }
+
+ for (int i = 0; i < phnum; i++)
+ {
+ Phdr ph;
+ if (!ReadMemory(phdrAddr + i, &ph, sizeof(ph))) {
+ fprintf(stderr, "ReadMemory(%p, %" PRIx ") phdr FAILED\n", phdrAddr + i, sizeof(ph));
+ return false;
+ }
+ TRACE("PHDR: %p type %d (%x) vaddr %" PRIxA " memsz %" PRIxA " paddr %" PRIxA " filesz %" PRIxA " offset %" PRIxA " align %" PRIxA "\n",
+ phdrAddr + i, ph.p_type, ph.p_type, ph.p_vaddr, ph.p_memsz, ph.p_paddr, ph.p_filesz, ph.p_offset, ph.p_align);
+
+ switch (ph.p_type)
+ {
+ case PT_DYNAMIC:
+ if (pdynamicAddr != nullptr)
{
- case PT_DYNAMIC:
- case PT_NOTE:
- case PT_GNU_EH_FRAME:
- if (ph.p_vaddr != 0 && ph.p_memsz != 0) {
- InsertMemoryRegion(baseAddress + ph.p_vaddr, ph.p_memsz);
- }
+ *pdynamicAddr = reinterpret_cast<ElfW(Dyn)*>(loadbias + ph.p_vaddr);
break;
+ }
+ // fall into InsertMemoryRegion
- case PT_LOAD:
- MemoryRegion region(0, baseAddress + ph.p_vaddr, baseAddress + ph.p_vaddr + ph.p_memsz, baseAddress);
- m_moduleAddresses.insert(region);
- break;
+ case PT_NOTE:
+ case PT_GNU_EH_FRAME:
+ if (ph.p_vaddr != 0 && ph.p_memsz != 0) {
+ InsertMemoryRegion(loadbias + ph.p_vaddr, ph.p_memsz);
}
+ break;
+
+ case PT_LOAD:
+ MemoryRegion region(0, loadbias + ph.p_vaddr, loadbias + ph.p_vaddr + ph.p_memsz, baseAddress);
+ m_moduleAddresses.insert(region);
+ break;
}
}
// Enumerate all the memory regions using the DAC memory region support given a minidump type
//
bool
-CrashInfo::EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE minidumpType)
+CrashInfo::EnumerateMemoryRegionsWithDAC(MINIDUMP_TYPE minidumpType)
{
PFN_CLRDataCreateInstance pfnCLRDataCreateInstance = nullptr;
ICLRDataEnumMemoryRegions* pClrDataEnumRegions = nullptr;
HRESULT hr = S_OK;
bool result = false;
- // We assume that the DAC is in the same location as this createdump exe
- std::string dacPath;
- dacPath.append(programPath);
- dacPath.append("/");
- dacPath.append(MAKEDLLNAME_A("mscordaccore"));
-
- // Load and initialize the DAC
- hdac = LoadLibraryA(dacPath.c_str());
- if (hdac == nullptr)
- {
- fprintf(stderr, "LoadLibraryA(%s) FAILED %d\n", dacPath.c_str(), GetLastError());
- goto exit;
- }
- pfnCLRDataCreateInstance = (PFN_CLRDataCreateInstance)GetProcAddress(hdac, "CLRDataCreateInstance");
- if (pfnCLRDataCreateInstance == nullptr)
- {
- fprintf(stderr, "GetProcAddress(CLRDataCreateInstance) FAILED %d\n", GetLastError());
- goto exit;
- }
- if ((minidumpType & MiniDumpWithFullMemory) == 0)
+ if (!m_coreclrPath.empty())
{
- hr = pfnCLRDataCreateInstance(__uuidof(ICLRDataEnumMemoryRegions), m_dataTarget, (void**)&pClrDataEnumRegions);
- if (FAILED(hr))
+ // We assume that the DAC is in the same location as the libcoreclr.so module
+ std::string dacPath;
+ dacPath.append(m_coreclrPath);
+ dacPath.append(MAKEDLLNAME_A("mscordaccore"));
+
+ // Load and initialize the DAC
+ hdac = LoadLibraryA(dacPath.c_str());
+ if (hdac == nullptr)
+ {
+ fprintf(stderr, "LoadLibraryA(%s) FAILED %d\n", dacPath.c_str(), GetLastError());
+ goto exit;
+ }
+ pfnCLRDataCreateInstance = (PFN_CLRDataCreateInstance)GetProcAddress(hdac, "CLRDataCreateInstance");
+ if (pfnCLRDataCreateInstance == nullptr)
{
- fprintf(stderr, "CLRDataCreateInstance(ICLRDataEnumMemoryRegions) FAILED %08x\n", hr);
+ fprintf(stderr, "GetProcAddress(CLRDataCreateInstance) FAILED %d\n", GetLastError());
goto exit;
}
- // Calls CrashInfo::EnumMemoryRegion for each memory region found by the DAC
- hr = pClrDataEnumRegions->EnumMemoryRegions(this, minidumpType, CLRDATA_ENUM_MEM_DEFAULT);
+ if ((minidumpType & MiniDumpWithFullMemory) == 0)
+ {
+ hr = pfnCLRDataCreateInstance(__uuidof(ICLRDataEnumMemoryRegions), m_dataTarget, (void**)&pClrDataEnumRegions);
+ if (FAILED(hr))
+ {
+ fprintf(stderr, "CLRDataCreateInstance(ICLRDataEnumMemoryRegions) FAILED %08x\n", hr);
+ goto exit;
+ }
+ // Calls CrashInfo::EnumMemoryRegion for each memory region found by the DAC
+ hr = pClrDataEnumRegions->EnumMemoryRegions(this, minidumpType, CLRDATA_ENUM_MEM_DEFAULT);
+ if (FAILED(hr))
+ {
+ fprintf(stderr, "EnumMemoryRegions FAILED %08x\n", hr);
+ goto exit;
+ }
+ }
+ hr = pfnCLRDataCreateInstance(__uuidof(IXCLRDataProcess), m_dataTarget, (void**)&pClrDataProcess);
if (FAILED(hr))
{
- fprintf(stderr, "EnumMemoryRegions FAILED %08x\n", hr);
+ fprintf(stderr, "CLRDataCreateInstance(IXCLRDataProcess) FAILED %08x\n", hr);
+ goto exit;
+ }
+ if (!EnumerateManagedModules(pClrDataProcess))
+ {
goto exit;
}
}
- hr = pfnCLRDataCreateInstance(__uuidof(IXCLRDataProcess), m_dataTarget, (void**)&pClrDataProcess);
- if (FAILED(hr))
- {
- fprintf(stderr, "CLRDataCreateInstance(IXCLRDataProcess) FAILED %08x\n", hr);
- goto exit;
- }
- if (!EnumerateManagedModules(pClrDataProcess))
- {
- goto exit;
+ else {
+ TRACE("EnumerateMemoryRegionsWithDAC: coreclr not found; not using DAC\n");
}
if (!UnwindAllThreads(pClrDataProcess))
{
bool
ThreadInfo::UnwindThread(CrashInfo& crashInfo, IXCLRDataProcess* pClrDataProcess)
{
- ReleaseHolder<IXCLRDataTask> pTask;
- ReleaseHolder<IXCLRDataStackWalk> pStackwalk;
-
TRACE("Unwind: thread %04x\n", Tid());
// Get starting native context for the thread
// Unwind the native frames at the top of the stack
UnwindNativeFrames(crashInfo, &context);
- // Get the managed stack walker for this thread
- if (SUCCEEDED(pClrDataProcess->GetTaskByOSThreadID(Tid(), &pTask)))
+ if (pClrDataProcess != nullptr)
{
- pTask->CreateStackWalk(
- CLRDATA_SIMPFRAME_UNRECOGNIZED |
- CLRDATA_SIMPFRAME_MANAGED_METHOD |
- CLRDATA_SIMPFRAME_RUNTIME_MANAGED_CODE |
- CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE,
- &pStackwalk);
- }
+ ReleaseHolder<IXCLRDataTask> pTask;
+ ReleaseHolder<IXCLRDataStackWalk> pStackwalk;
- // For each managed frame (if any)
- if (pStackwalk != nullptr)
- {
- TRACE("Unwind: managed frames\n");
- do
+ // Get the managed stack walker for this thread
+ if (SUCCEEDED(pClrDataProcess->GetTaskByOSThreadID(Tid(), &pTask)))
{
- // Get the managed stack frame context
- if (pStackwalk->GetContext(CONTEXT_ALL, sizeof(context), nullptr, (BYTE *)&context) != S_OK) {
- TRACE("Unwind: stack walker GetContext FAILED\n");
- break;
- }
-
- // Unwind all the native frames after the managed frame
- UnwindNativeFrames(crashInfo, &context);
+ pTask->CreateStackWalk(
+ CLRDATA_SIMPFRAME_UNRECOGNIZED |
+ CLRDATA_SIMPFRAME_MANAGED_METHOD |
+ CLRDATA_SIMPFRAME_RUNTIME_MANAGED_CODE |
+ CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE,
+ &pStackwalk);
+ }
- } while (pStackwalk->Next() == S_OK);
+ // For each managed frame (if any)
+ if (pStackwalk != nullptr)
+ {
+ TRACE("Unwind: managed frames\n");
+ do
+ {
+ // Get the managed stack frame context
+ if (pStackwalk->GetContext(CONTEXT_ALL, sizeof(context), nullptr, (BYTE *)&context) != S_OK) {
+ TRACE("Unwind: stack walker GetContext FAILED\n");
+ break;
+ }
+
+ // Unwind all the native frames after the managed frame
+ UnwindNativeFrames(crashInfo, &context);
+
+ } while (pStackwalk->Next() == S_OK);
+ }
}
return true;