From 94a67752ace5236cb6228c4cbc6e6c2976895f2a Mon Sep 17 00:00:00 2001 From: Mike McLaughlin Date: Wed, 23 Aug 2017 21:13:36 -0700 Subject: [PATCH] Add unwind info to core dumps. (#13547) The createdump utility now enumerates all the native stack frames (with some help from the managed stack walker) for all the threads adding all the ELF unwind info needed. On a different machine and without any of the native modules loaded when the crashdump was generated all the thread stacks can still be unwound with lldb/gdb. Change the PAL_VirtualUnwindOutOfProc read memory adapter in DAC to add the memory to instances manager. Some misc. cleanup. --- src/debug/createdump/crashinfo.cpp | 159 ++++++++++++++++++++++++------------ src/debug/createdump/crashinfo.h | 35 ++++---- src/debug/createdump/datatarget.cpp | 9 -- src/debug/createdump/datatarget.h | 10 +-- src/debug/createdump/memoryregion.h | 12 +++ src/debug/createdump/threadinfo.cpp | 149 +++++++++++++++++++++++++++------ src/debug/createdump/threadinfo.h | 21 ++--- src/debug/daccess/dacfn.cpp | 25 +++++- src/debug/daccess/dacimpl.h | 1 + 9 files changed, 301 insertions(+), 120 deletions(-) diff --git a/src/debug/createdump/crashinfo.cpp b/src/debug/createdump/crashinfo.cpp index 803e2bd..b8f9294 100644 --- a/src/debug/createdump/crashinfo.cpp +++ b/src/debug/createdump/crashinfo.cpp @@ -4,6 +4,9 @@ #include "createdump.h" +// This is for the PAL_VirtualUnwindOutOfProc read memory adapter. +CrashInfo* g_crashInfo; + CrashInfo::CrashInfo(pid_t pid, ICLRDataTarget* dataTarget, bool sos) : m_ref(1), m_pid(pid), @@ -12,6 +15,7 @@ CrashInfo::CrashInfo(pid_t pid, ICLRDataTarget* dataTarget, bool sos) : m_sos(sos), m_dataTarget(dataTarget) { + g_crashInfo = this; dataTarget->AddRef(); m_auxvValues.fill(0); } @@ -57,7 +61,7 @@ CrashInfo::QueryInterface( } else { - *Interface = NULL; + *Interface = nullptr; return E_NOINTERFACE; } } @@ -172,6 +176,12 @@ CrashInfo::GatherCrashInfo(const char* programPath, MINIDUMP_TYPE minidumpType) { return false; } + + for (const MemoryRegion& region : m_moduleAddresses) + { + region.Trace(); + } + // If full memory dump, include everything regardless of permissions if (minidumpType & MiniDumpWithFullMemory) { @@ -205,15 +215,8 @@ CrashInfo::GatherCrashInfo(const char* programPath, MINIDUMP_TYPE minidumpType) // Add the thread's stack and some code memory to core for (ThreadInfo* thread : m_threads) { - uint64_t start; - size_t size; - - // Add the thread's stack and some of the code - thread->GetThreadStack(*this, &start, &size); - InsertMemoryRegion(start, size); - - thread->GetThreadCode(&start, &size); - InsertMemoryRegion(start, size); + // Add the thread's stack + thread->GetThreadStack(*this); } // All the regions added so far has been backed by memory. Now add the rest of // mappings so the debuggers like lldb see that an address is code (PF_X) even @@ -302,7 +305,7 @@ CrashInfo::EnumerateModuleMappings() // 35b1dac000-35b1fac000 ---p 001ac000 08:02 135870 /usr/lib64/libc-2.15.so // 35b1fac000-35b1fb0000 r--p 001ac000 08:02 135870 /usr/lib64/libc-2.15.so // 35b1fb0000-35b1fb2000 rw-p 001b0000 08:02 135870 /usr/lib64/libc-2.15.so - char* line = NULL; + char* line = nullptr; size_t lineLen = 0; int count = 0; ssize_t read; @@ -313,7 +316,7 @@ CrashInfo::EnumerateModuleMappings() assert(chars > 0 && chars <= sizeof(mapPath)); FILE* mapsFile = fopen(mapPath, "r"); - if (mapsFile == NULL) + if (mapsFile == nullptr) { fprintf(stderr, "fopen(%s) FAILED %s\n", mapPath, strerror(errno)); return false; @@ -408,7 +411,8 @@ CrashInfo::GetDSOInfo() if (phnum <= 0 || phdrAddr == nullptr) { return false; } - TRACE("DSO: phdr %p phnum %d\n", phdrAddr, phnum); + 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; @@ -422,16 +426,23 @@ CrashInfo::GetDSOInfo() 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); - if (ph.p_type == PT_DYNAMIC) + switch (ph.p_type) { + case PT_DYNAMIC: dynamicAddr = reinterpret_cast(ph.p_vaddr); - } - else if (ph.p_type == PT_NOTE || ph.p_type == PT_GNU_EH_FRAME) - { - if (ph.p_vaddr != 0 && ph.p_memsz != 0) - { + 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; + + case PT_LOAD: + MemoryRegion region(0, ph.p_vaddr, ph.p_vaddr + ph.p_memsz, baseAddress); + m_moduleAddresses.insert(region); + break; } } @@ -542,12 +553,20 @@ CrashInfo::GetELFInfo(uint64_t baseAddress) 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); - if (ph.p_type == PT_DYNAMIC || ph.p_type == PT_NOTE || ph.p_type == PT_GNU_EH_FRAME) + switch (ph.p_type) { - if (ph.p_vaddr != 0 && ph.p_memsz != 0) - { + 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); } + break; + + case PT_LOAD: + MemoryRegion region(0, baseAddress + ph.p_vaddr, baseAddress + ph.p_vaddr + ph.p_memsz, baseAddress); + m_moduleAddresses.insert(region); + break; } } } @@ -562,8 +581,8 @@ bool CrashInfo::EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE minidumpType) { PFN_CLRDataCreateInstance pfnCLRDataCreateInstance = nullptr; - ICLRDataEnumMemoryRegions* clrDataEnumRegions = nullptr; - IXCLRDataProcess* clrDataProcess = nullptr; + ICLRDataEnumMemoryRegions* pClrDataEnumRegions = nullptr; + IXCLRDataProcess* pClrDataProcess = nullptr; HMODULE hdac = nullptr; HRESULT hr = S_OK; bool result = false; @@ -589,39 +608,43 @@ CrashInfo::EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE } if ((minidumpType & MiniDumpWithFullMemory) == 0) { - hr = pfnCLRDataCreateInstance(__uuidof(ICLRDataEnumMemoryRegions), m_dataTarget, (void**)&clrDataEnumRegions); + 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 = clrDataEnumRegions->EnumMemoryRegions(this, minidumpType, CLRDATA_ENUM_MEM_DEFAULT); + 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**)&clrDataProcess); + hr = pfnCLRDataCreateInstance(__uuidof(IXCLRDataProcess), m_dataTarget, (void**)&pClrDataProcess); if (FAILED(hr)) { fprintf(stderr, "CLRDataCreateInstance(IXCLRDataProcess) FAILED %08x\n", hr); goto exit; } - if (!EnumerateManagedModules(clrDataProcess)) + if (!EnumerateManagedModules(pClrDataProcess)) + { + goto exit; + } + if (!UnwindAllThreads(pClrDataProcess)) { goto exit; } result = true; exit: - if (clrDataEnumRegions != nullptr) + if (pClrDataEnumRegions != nullptr) { - clrDataEnumRegions->Release(); + pClrDataEnumRegions->Release(); } - if (clrDataProcess != nullptr) + if (pClrDataProcess != nullptr) { - clrDataProcess->Release(); + pClrDataProcess->Release(); } if (hdac != nullptr) { @@ -631,24 +654,29 @@ exit: } // -// Enumerate all the managed modules and replace the module -// mapping with the module name found. +// Enumerate all the managed modules and replace the module mapping with the module name found. // bool -CrashInfo::EnumerateManagedModules(IXCLRDataProcess* clrDataProcess) +CrashInfo::EnumerateManagedModules(IXCLRDataProcess* pClrDataProcess) { - IXCLRDataModule* clrDataModule = nullptr; CLRDATA_ENUM enumModules = 0; + bool result = true; HRESULT hr = S_OK; - if (FAILED(hr = clrDataProcess->StartEnumModules(&enumModules))) { + if (FAILED(hr = pClrDataProcess->StartEnumModules(&enumModules))) { fprintf(stderr, "StartEnumModules FAILED %08x\n", hr); return false; } - while ((hr = clrDataProcess->EnumModule(&enumModules, &clrDataModule)) == S_OK) + + while (true) { + ReleaseHolder pClrDataModule; + if ((hr = pClrDataProcess->EnumModule(&enumModules, &pClrDataModule)) != S_OK) { + break; + } + DacpGetModuleData moduleData; - if (SUCCEEDED(hr = moduleData.Request(clrDataModule))) + if (SUCCEEDED(hr = moduleData.Request(pClrDataModule.GetPtr()))) { TRACE("MODULE: %" PRIA PRIx64 " dyn %d inmem %d file %d pe %" PRIA PRIx64 " pdb %" PRIA PRIx64, moduleData.LoadedPEAddress, moduleData.IsDynamic, moduleData.IsInMemory, moduleData.IsFileLayout, moduleData.PEFile, moduleData.InMemoryPdbAddress); @@ -656,12 +684,13 @@ CrashInfo::EnumerateManagedModules(IXCLRDataProcess* clrDataProcess) if (!moduleData.IsDynamic && moduleData.LoadedPEAddress != 0) { ArrayHolder wszUnicodeName = new WCHAR[MAX_LONGPATH + 1]; - if (SUCCEEDED(hr = clrDataModule->GetFileName(MAX_LONGPATH, NULL, wszUnicodeName))) + if (SUCCEEDED(hr = pClrDataModule->GetFileName(MAX_LONGPATH, nullptr, wszUnicodeName))) { char* pszName = (char*)malloc(MAX_LONGPATH + 1); if (pszName == nullptr) { fprintf(stderr, "Allocating module name FAILED\n"); - return false; + result = false; + break; } sprintf_s(pszName, MAX_LONGPATH, "%S", (WCHAR*)wszUnicodeName); TRACE(" %s\n", pszName); @@ -680,12 +709,27 @@ CrashInfo::EnumerateManagedModules(IXCLRDataProcess* clrDataProcess) else { TRACE("moduleData.Request FAILED %08x\n", hr); } - if (clrDataModule != nullptr) { - clrDataModule->Release(); - } } + if (enumModules != 0) { - clrDataProcess->EndEnumModules(enumModules); + pClrDataProcess->EndEnumModules(enumModules); + } + + return result; +} + +// +// Unwind all the native threads to ensure that the dwarf unwind info is added to the core dump. +// +bool +CrashInfo::UnwindAllThreads(IXCLRDataProcess* pClrDataProcess) +{ + // For each native and managed thread + for (ThreadInfo* thread : m_threads) + { + if (!thread->UnwindThread(*this, pClrDataProcess)) { + return false; + } } return true; } @@ -729,6 +773,20 @@ CrashInfo::ReplaceModuleMapping(CLRDATA_ADDRESS baseAddress, const char* pszName } // +// Returns the module base address for the IP or 0. +// +uint64_t CrashInfo::GetBaseAddress(uint64_t ip) +{ + MemoryRegion search(0, ip, ip, 0); + const MemoryRegion* found = SearchMemoryRegions(m_moduleAddresses, search); + if (found == nullptr) { + return 0; + } + // The memory region Offset() is the base address of the module + return found->Offset(); +} + +// // ReadMemory from target and add to memory regions list // bool @@ -828,11 +886,12 @@ CrashInfo::InsertMemoryRegion(const MemoryRegion& region) uint32_t CrashInfo::GetMemoryRegionFlags(uint64_t start) { - const MemoryRegion* region = SearchMemoryRegions(m_moduleMappings, start); + MemoryRegion search(0, start, start + PAGE_SIZE); + const MemoryRegion* region = SearchMemoryRegions(m_moduleMappings, search); if (region != nullptr) { return region->Flags(); } - region = SearchMemoryRegions(m_otherMappings, start); + region = SearchMemoryRegions(m_otherMappings, search); if (region != nullptr) { return region->Flags(); } @@ -922,12 +981,12 @@ CrashInfo::CombineMemoryRegions() // Searches for a memory region given an address. // const MemoryRegion* -CrashInfo::SearchMemoryRegions(const std::set& regions, uint64_t start) +CrashInfo::SearchMemoryRegions(const std::set& regions, const MemoryRegion& search) { - std::set::iterator found = regions.find(MemoryRegion(0, start, start + PAGE_SIZE)); + std::set::iterator found = regions.find(search); for (; found != regions.end(); found++) { - if (start >= found->StartAddress() && start < found->EndAddress()) + if (search.StartAddress() >= found->StartAddress() && search.StartAddress() < found->EndAddress()) { return &*found; } diff --git a/src/debug/createdump/crashinfo.h b/src/debug/createdump/crashinfo.h index 65f1d18..d7c3f03 100644 --- a/src/debug/createdump/crashinfo.h +++ b/src/debug/createdump/crashinfo.h @@ -10,7 +10,7 @@ typedef Elf32_auxv_t elf_aux_entry; #define PRId PRId32 #define PRIA "08" #define PRIxA PRIA PRIx -#elif defined(__x86_64) || defined(__aarch64__) +#elif defined(__x86_64__) || defined(__aarch64__) typedef Elf64_auxv_t elf_aux_entry; #define PRIx PRIx64 #define PRIu PRIu64 @@ -40,6 +40,7 @@ private: std::set m_moduleMappings; // module memory mappings 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 public: CrashInfo(pid_t pid, ICLRDataTarget* dataTarget, bool sos); @@ -47,21 +48,24 @@ public: bool EnumerateAndSuspendThreads(); bool GatherCrashInfo(const char* programPath, MINIDUMP_TYPE minidumpType); void ResumeThreads(); + bool ReadMemory(void* address, void* buffer, size_t size); + uint64_t GetBaseAddress(uint64_t ip); + void InsertMemoryRegion(uint64_t address, size_t size); static bool GetStatus(pid_t pid, pid_t* ppid, pid_t* tgid, char** name); - static const MemoryRegion* SearchMemoryRegions(const std::set& regions, uint64_t start); + static const MemoryRegion* SearchMemoryRegions(const std::set& regions, const MemoryRegion& search); - const pid_t Pid() const { return m_pid; } - const pid_t Ppid() const { return m_ppid; } - const pid_t Tgid() const { return m_tgid; } - const char* Name() const { return m_name; } - ICLRDataTarget* DataTarget() const { return m_dataTarget; } + inline const pid_t Pid() const { return m_pid; } + inline const pid_t Ppid() const { return m_ppid; } + inline const pid_t Tgid() const { return m_tgid; } + inline const char* Name() const { return m_name; } + inline ICLRDataTarget* DataTarget() const { return m_dataTarget; } - const std::vector Threads() const { return m_threads; } - const std::set ModuleMappings() const { return m_moduleMappings; } - const std::set OtherMappings() const { return m_otherMappings; } - const std::set MemoryRegions() const { return m_memoryRegions; } - const std::vector AuxvEntries() const { return m_auxvEntries; } - const size_t GetAuxvSize() const { return m_auxvEntries.size() * sizeof(elf_aux_entry); } + inline const std::vector Threads() const { return m_threads; } + inline const std::set ModuleMappings() const { return m_moduleMappings; } + inline const std::set OtherMappings() const { return m_otherMappings; } + inline const std::set MemoryRegions() const { return m_memoryRegions; } + inline const std::vector AuxvEntries() const { return m_auxvEntries; } + inline const size_t GetAuxvSize() const { return m_auxvEntries.size() * sizeof(elf_aux_entry); } // IUnknown STDMETHOD(QueryInterface)(___in REFIID InterfaceId, ___out PVOID* Interface); @@ -77,11 +81,10 @@ private: bool GetDSOInfo(); bool GetELFInfo(uint64_t baseAddress); bool EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE minidumpType); - bool EnumerateManagedModules(IXCLRDataProcess* clrDataProcess); + bool EnumerateManagedModules(IXCLRDataProcess* pClrDataProcess); + bool UnwindAllThreads(IXCLRDataProcess* pClrDataProcess); void ReplaceModuleMapping(CLRDATA_ADDRESS baseAddress, const char* pszName); - bool ReadMemory(void* address, void* buffer, size_t size); void InsertMemoryBackedRegion(const MemoryRegion& region); - void InsertMemoryRegion(uint64_t address, size_t size); void InsertMemoryRegion(const MemoryRegion& region); uint32_t GetMemoryRegionFlags(uint64_t start); bool ValidRegion(const MemoryRegion& region); diff --git a/src/debug/createdump/datatarget.cpp b/src/debug/createdump/datatarget.cpp index dec52c7..9bbfcc7 100644 --- a/src/debug/createdump/datatarget.cpp +++ b/src/debug/createdump/datatarget.cpp @@ -251,12 +251,3 @@ DumpDataTarget::Request( assert(false); return E_NOTIMPL; } - -HRESULT STDMETHODCALLTYPE -DumpDataTarget::VirtualUnwind( - /* [in] */ DWORD threadId, - /* [in] */ ULONG32 contextSize, - /* [in, out, size_is(contextSize)] */ PBYTE context) -{ - return E_NOTIMPL; -} diff --git a/src/debug/createdump/datatarget.h b/src/debug/createdump/datatarget.h index 8ff6773..f169818 100644 --- a/src/debug/createdump/datatarget.h +++ b/src/debug/createdump/datatarget.h @@ -4,7 +4,7 @@ class CrashInfo; -class DumpDataTarget : public ICLRDataTarget, ICorDebugDataTarget4 +class DumpDataTarget : public ICLRDataTarget { private: LONG m_ref; // reference count @@ -79,12 +79,4 @@ public: /* [size_is][in] */ BYTE *inBuffer, /* [in] */ ULONG32 outBufferSize, /* [size_is][out] */ BYTE *outBuffer); - - // - // ICorDebugDataTarget4 - // - virtual HRESULT STDMETHODCALLTYPE VirtualUnwind( - /* [in] */ DWORD threadId, - /* [in] */ ULONG32 contextSize, - /* [in, out, size_is(contextSize)] */ PBYTE context); }; diff --git a/src/debug/createdump/memoryregion.h b/src/debug/createdump/memoryregion.h index e8e49aa..fbdd9d0 100644 --- a/src/debug/createdump/memoryregion.h +++ b/src/debug/createdump/memoryregion.h @@ -58,6 +58,18 @@ public: assert((end & ~PAGE_MASK) == 0); } + // This is a special constructor for the module base address + // set where the start/end are not page aligned and "offset" + // is reused as the module base address. + MemoryRegion(uint32_t flags, uint64_t start, uint64_t end, uint64_t baseAddress) : + m_flags(flags), + m_startAddress(start), + m_endAddress(end), + m_offset(baseAddress), + m_fileName(nullptr) + { + } + // copy with new file name constructor MemoryRegion(const MemoryRegion& region, const char* fileName) : m_flags(region.m_flags), diff --git a/src/debug/createdump/threadinfo.cpp b/src/debug/createdump/threadinfo.cpp index 6a91ed7..3e5a5cc 100644 --- a/src/debug/createdump/threadinfo.cpp +++ b/src/debug/createdump/threadinfo.cpp @@ -5,6 +5,10 @@ #include "createdump.h" #include +#ifndef THUMB_CODE +#define THUMB_CODE 1 +#endif + #ifndef __GLIBC__ typedef int __ptrace_request; #endif @@ -14,6 +18,8 @@ typedef int __ptrace_request; #define FPREG_DataOffset(fpregs) *(DWORD*)&((fpregs).rdp) #define FPREG_DataSelector(fpregs) *(((WORD*)&((fpregs).rdp)) + 2) +extern CrashInfo* g_crashInfo; + ThreadInfo::ThreadInfo(pid_t tid) : m_tid(tid) { @@ -24,15 +30,15 @@ ThreadInfo::~ThreadInfo() } bool -ThreadInfo::Initialize(ICLRDataTarget* dataTarget) +ThreadInfo::Initialize(ICLRDataTarget* pDataTarget) { if (!CrashInfo::GetStatus(m_tid, &m_ppid, &m_tgid, nullptr)) { return false; } - if (dataTarget != nullptr) + if (pDataTarget != nullptr) { - if (!GetRegistersWithDataTarget(dataTarget)) + if (!GetRegistersWithDataTarget(pDataTarget)) { return false; } @@ -62,6 +68,108 @@ ThreadInfo::ResumeThread() } } +// Helper for UnwindNativeFrames +static void +GetFrameLocation(CONTEXT* pContext, uint64_t* ip, uint64_t* sp) +{ +#if defined(__x86_64__) + *ip = pContext->Rip; + *sp = pContext->Rsp; +#elif defined(__i386__) + *ip = pContext->Eip; + *sp = pContext->Esp; +#elif defined(__arm__) + *ip = pContext->Pc & ~THUMB_CODE; + *sp = pContext->Sp; +#endif +} + +// Helper for UnwindNativeFrames +static BOOL +ReadMemoryAdapter(PVOID address, PVOID buffer, SIZE_T size) +{ + return g_crashInfo->ReadMemory(address, buffer, size); +} + +void +ThreadInfo::UnwindNativeFrames(CrashInfo& crashInfo, CONTEXT* pContext) +{ + // For each native frame + while (true) + { + uint64_t ip = 0, sp = 0; + GetFrameLocation(pContext, &ip, &sp); + + TRACE("Unwind: sp %" PRIA PRIx64 " ip %" PRIA PRIx64 "\n", sp, ip); + if (ip == 0) { + break; + } + // Add two pages around the instruction pointer to the core dump + crashInfo.InsertMemoryRegion(ip - PAGE_SIZE, PAGE_SIZE * 2); + + // Look up the ip address to get the module base address + uint64_t baseAddress = crashInfo.GetBaseAddress(ip); + if (baseAddress == 0) { + TRACE("Unwind: module base not found ip %" PRIA PRIx64 "\n", ip); + break; + } + + // Unwind the native frame adding all the memory accessed to the + // core dump via the read memory adapter. + if (!PAL_VirtualUnwindOutOfProc(pContext, nullptr, baseAddress, ReadMemoryAdapter)) { + TRACE("Unwind: PAL_VirtualUnwindOutOfProc returned false\n"); + break; + } + } +} + +bool +ThreadInfo::UnwindThread(CrashInfo& crashInfo, IXCLRDataProcess* pClrDataProcess) +{ + ReleaseHolder pTask; + ReleaseHolder pStackwalk; + + TRACE("Unwind: thread %04x\n", Tid()); + + // Get starting native context for the thread + CONTEXT context; + GetThreadContext(CONTEXT_ALL, &context); + + // 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))) + { + pTask->CreateStackWalk( + CLRDATA_SIMPFRAME_UNRECOGNIZED | + CLRDATA_SIMPFRAME_MANAGED_METHOD | + CLRDATA_SIMPFRAME_RUNTIME_MANAGED_CODE | + CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE, + &pStackwalk); + } + + // 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; +} + bool ThreadInfo::GetRegistersWithPTrace() { @@ -97,11 +205,11 @@ ThreadInfo::GetRegistersWithPTrace() } bool -ThreadInfo::GetRegistersWithDataTarget(ICLRDataTarget* dataTarget) +ThreadInfo::GetRegistersWithDataTarget(ICLRDataTarget* pDataTarget) { CONTEXT context; context.ContextFlags = CONTEXT_ALL; - if (dataTarget->GetThreadContext(m_tid, context.ContextFlags, sizeof(context), reinterpret_cast(&context)) != S_OK) + if (pDataTarget->GetThreadContext(m_tid, context.ContextFlags, sizeof(context), reinterpret_cast(&context)) != S_OK) { return false; } @@ -188,39 +296,32 @@ ThreadInfo::GetRegistersWithDataTarget(ICLRDataTarget* dataTarget) } void -ThreadInfo::GetThreadStack(const CrashInfo& crashInfo, uint64_t* startAddress, size_t* size) const +ThreadInfo::GetThreadStack(CrashInfo& crashInfo) { + uint64_t startAddress; + size_t size; + #if defined(__arm__) - *startAddress = m_gpRegisters.ARM_sp & PAGE_MASK; + startAddress = m_gpRegisters.ARM_sp & PAGE_MASK; #else - *startAddress = m_gpRegisters.rsp & PAGE_MASK; + startAddress = m_gpRegisters.rsp & PAGE_MASK; #endif - *size = 4 * PAGE_SIZE; + size = 4 * PAGE_SIZE; - const MemoryRegion* region = CrashInfo::SearchMemoryRegions(crashInfo.OtherMappings(), *startAddress); + MemoryRegion search(0, startAddress, startAddress + PAGE_SIZE); + const MemoryRegion* region = CrashInfo::SearchMemoryRegions(crashInfo.OtherMappings(), search); if (region != nullptr) { // Use the mapping found for the size of the thread's stack - *size = region->EndAddress() - *startAddress; + size = region->EndAddress() - startAddress; if (g_diagnostics) { - TRACE("Thread %04x stack found in other mapping (size %08zx): ", m_tid, *size); + TRACE("Thread %04x stack found in other mapping (size %08zx): ", m_tid, size); region->Trace(); } } - -} - -void -ThreadInfo::GetThreadCode(uint64_t* startAddress, size_t* size) const -{ -#if defined(__arm__) - *startAddress = m_gpRegisters.ARM_pc & PAGE_MASK; -#elif defined(__x86_64__) - *startAddress = m_gpRegisters.rip & PAGE_MASK; -#endif - *size = PAGE_SIZE; + crashInfo.InsertMemoryRegion(startAddress, size); } void diff --git a/src/debug/createdump/threadinfo.h b/src/debug/createdump/threadinfo.h index 3756669..8851877 100644 --- a/src/debug/createdump/threadinfo.h +++ b/src/debug/createdump/threadinfo.h @@ -35,25 +35,26 @@ private: public: ThreadInfo(pid_t tid); ~ThreadInfo(); - bool Initialize(ICLRDataTarget* dataTarget); + bool Initialize(ICLRDataTarget* pDataTarget); void ResumeThread(); - void GetThreadStack(const CrashInfo& crashInfo, uint64_t* startAddress, size_t* size) const; - void GetThreadCode(uint64_t* startAddress, size_t* size) const; + bool UnwindThread(CrashInfo& crashInfo, IXCLRDataProcess* pClrDataProcess); + void GetThreadStack(CrashInfo& crashInfo); void GetThreadContext(uint32_t flags, CONTEXT* context) const; - const pid_t Tid() const { return m_tid; } - const pid_t Ppid() const { return m_ppid; } - const pid_t Tgid() const { return m_tgid; } + inline const pid_t Tid() const { return m_tid; } + inline const pid_t Ppid() const { return m_ppid; } + inline const pid_t Tgid() const { return m_tgid; } - const user_regs_struct* GPRegisters() const { return &m_gpRegisters; } - const user_fpregs_struct* FPRegisters() const { return &m_fpRegisters; } + inline const user_regs_struct* GPRegisters() const { return &m_gpRegisters; } + inline const user_fpregs_struct* FPRegisters() const { return &m_fpRegisters; } #if defined(__i386__) - const user_fpxregs_struct* FPXRegisters() const { return &m_fpxRegisters; } + inline const user_fpxregs_struct* FPXRegisters() const { return &m_fpxRegisters; } #elif defined(__arm__) && defined(__VFP_FP__) && !defined(__SOFTFP__) - const user_vfpregs_struct* VFPRegisters() const { return &m_vfpRegisters; } + inline const user_vfpregs_struct* VFPRegisters() const { return &m_vfpRegisters; } #endif private: + void UnwindNativeFrames(CrashInfo& crashInfo, CONTEXT* pContext); bool GetRegistersWithPTrace(); bool GetRegistersWithDataTarget(ICLRDataTarget* dataTarget); }; diff --git a/src/debug/daccess/dacfn.cpp b/src/debug/daccess/dacfn.cpp index 78a7b9f..d6e0a89 100644 --- a/src/debug/daccess/dacfn.cpp +++ b/src/debug/daccess/dacfn.cpp @@ -220,8 +220,29 @@ DacWriteAll(TADDR addr, PVOID buffer, ULONG32 size, bool throwEx) static BOOL DacReadAllAdapter(PVOID address, PVOID buffer, SIZE_T size) { - HRESULT hr = DacReadAll((TADDR)address, (PVOID)buffer, size, false); - return SUCCEEDED(hr); + DAC_INSTANCE* inst = g_dacImpl->m_instances.Find((TADDR)address); + if (inst == nullptr || inst->size < size) + { + inst = g_dacImpl->m_instances.Alloc((TADDR)address, size, DAC_PAL); + if (inst == nullptr) + { + return FALSE; + } + inst->noReport = 0; + HRESULT hr = DacReadAll((TADDR)address, inst + 1, size, false); + if (FAILED(hr)) + { + g_dacImpl->m_instances.ReturnAlloc(inst); + return FALSE; + } + if (!g_dacImpl->m_instances.Add(inst)) + { + g_dacImpl->m_instances.ReturnAlloc(inst); + return FALSE; + } + } + memcpy(buffer, inst + 1, size); + return TRUE; } HRESULT diff --git a/src/debug/daccess/dacimpl.h b/src/debug/daccess/dacimpl.h index c37face..b858230 100644 --- a/src/debug/daccess/dacimpl.h +++ b/src/debug/daccess/dacimpl.h @@ -125,6 +125,7 @@ enum DAC_USAGE_TYPE DAC_VPTR, DAC_STRA, DAC_STRW, + DAC_PAL, }; // mscordacwks's module handle -- 2.7.4