提交 ab5a4a03 编写于 作者: M Mike McLaughlin 提交者: GitHub

Add unwind info to core dumps. (dotnet/coreclr#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.

Commit migrated from https://github.com/dotnet/coreclr/commit/94a67752ace5236cb6228c4cbc6e6c2976895f2a
上级 415bfdd3
......@@ -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;
}
......@@ -728,6 +772,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
//
......@@ -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;
}
......
......@@ -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);
......
......@@ -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;
}
......@@ -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);
};
......@@ -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),
......
......@@ -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
......
......@@ -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);
};
......@@ -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
......
......@@ -125,6 +125,7 @@ enum DAC_USAGE_TYPE
DAC_VPTR,
DAC_STRA,
DAC_STRW,
DAC_PAL,
};
// mscordacwks's module handle
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册