summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike McLaughlin <mikem@microsoft.com>2017-08-23 21:13:36 -0700
committerGitHub <noreply@github.com>2017-08-23 21:13:36 -0700
commit94a67752ace5236cb6228c4cbc6e6c2976895f2a (patch)
treef6844b51dedef5356d243f6c97613aeaac457043
parenta3e884a062607ac296fc3943796627e2209a95ea (diff)
downloadcoreclr-94a67752ace5236cb6228c4cbc6e6c2976895f2a.tar.gz
coreclr-94a67752ace5236cb6228c4cbc6e6c2976895f2a.tar.bz2
coreclr-94a67752ace5236cb6228c4cbc6e6c2976895f2a.zip
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.
-rw-r--r--src/debug/createdump/crashinfo.cpp159
-rw-r--r--src/debug/createdump/crashinfo.h35
-rw-r--r--src/debug/createdump/datatarget.cpp9
-rw-r--r--src/debug/createdump/datatarget.h10
-rw-r--r--src/debug/createdump/memoryregion.h12
-rw-r--r--src/debug/createdump/threadinfo.cpp149
-rw-r--r--src/debug/createdump/threadinfo.h21
-rw-r--r--src/debug/daccess/dacfn.cpp25
-rw-r--r--src/debug/daccess/dacimpl.h1
9 files changed, 301 insertions, 120 deletions
diff --git a/src/debug/createdump/crashinfo.cpp b/src/debug/createdump/crashinfo.cpp
index 803e2bdac1..b8f92943e2 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<ElfW(Dyn)*>(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<IXCLRDataModule> 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<WCHAR> 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<MemoryRegion>& regions, uint64_t start)
+CrashInfo::SearchMemoryRegions(const std::set<MemoryRegion>& regions, const MemoryRegion& search)
{
- std::set<MemoryRegion>::iterator found = regions.find(MemoryRegion(0, start, start + PAGE_SIZE));
+ std::set<MemoryRegion>::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 65f1d18730..d7c3f037c2 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<MemoryRegion> m_moduleMappings; // module memory mappings
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
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<MemoryRegion>& regions, uint64_t start);
+ static const MemoryRegion* SearchMemoryRegions(const std::set<MemoryRegion>& 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<ThreadInfo*> Threads() const { return m_threads; }
- const std::set<MemoryRegion> ModuleMappings() const { return m_moduleMappings; }
- const std::set<MemoryRegion> OtherMappings() const { return m_otherMappings; }
- const std::set<MemoryRegion> MemoryRegions() const { return m_memoryRegions; }
- const std::vector<elf_aux_entry> AuxvEntries() const { return m_auxvEntries; }
- const size_t GetAuxvSize() const { return m_auxvEntries.size() * sizeof(elf_aux_entry); }
+ inline const std::vector<ThreadInfo*> Threads() const { return m_threads; }
+ inline const std::set<MemoryRegion> ModuleMappings() const { return m_moduleMappings; }
+ inline const std::set<MemoryRegion> OtherMappings() const { return m_otherMappings; }
+ inline const std::set<MemoryRegion> MemoryRegions() const { return m_memoryRegions; }
+ inline const std::vector<elf_aux_entry> 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 dec52c707f..9bbfcc7ec9 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 8ff6773fa3..f1698186ea 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 e8e49aa149..fbdd9d0442 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 6a91ed741b..3e5a5ccc17 100644
--- a/src/debug/createdump/threadinfo.cpp
+++ b/src/debug/createdump/threadinfo.cpp
@@ -5,6 +5,10 @@
#include "createdump.h"
#include <asm/ptrace.h>
+#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<IXCLRDataTask> pTask;
+ ReleaseHolder<IXCLRDataStackWalk> 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<PBYTE>(&context)) != S_OK)
+ if (pDataTarget->GetThreadContext(m_tid, context.ContextFlags, sizeof(context), reinterpret_cast<PBYTE>(&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 3756669ac3..8851877cd0 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 78a7b9f2f5..d6e0a89267 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 c37face4e6..b8582304ab 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