diff options
Diffstat (limited to 'src/debug/createdump/datatarget.cpp')
-rw-r--r-- | src/debug/createdump/datatarget.cpp | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/src/debug/createdump/datatarget.cpp b/src/debug/createdump/datatarget.cpp new file mode 100644 index 0000000000..38505e2d45 --- /dev/null +++ b/src/debug/createdump/datatarget.cpp @@ -0,0 +1,263 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "createdump.h" + +#define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8) + +DumpDataTarget::DumpDataTarget(pid_t pid) : + m_ref(1), + m_pid(pid), + m_fd(-1), + m_crashInfo(nullptr) +{ +} + +DumpDataTarget::~DumpDataTarget() +{ + if (m_fd != -1) + { + close(m_fd); + m_fd = -1; + } +} + +bool +DumpDataTarget::Initialize(CrashInfo * crashInfo) +{ + char memPath[128]; + _snprintf_s(memPath, sizeof(memPath), sizeof(memPath), "/proc/%lu/mem", m_pid); + + m_fd = open(memPath, O_RDONLY); + if (m_fd == -1) + { + fprintf(stderr, "open(%s) FAILED %d (%s)\n", memPath, errno, strerror(errno)); + return false; + } + m_crashInfo = crashInfo; + return true; +} + +STDMETHODIMP +DumpDataTarget::QueryInterface( + ___in REFIID InterfaceId, + ___out PVOID* Interface + ) +{ + if (InterfaceId == IID_IUnknown || + InterfaceId == IID_ICLRDataTarget) + { + *Interface = (ICLRDataTarget*)this; + AddRef(); + return S_OK; + } + else if (InterfaceId == IID_ICorDebugDataTarget4) + { + *Interface = (ICorDebugDataTarget4*)this; + AddRef(); + return S_OK; + } + else + { + *Interface = NULL; + return E_NOINTERFACE; + } +} + +STDMETHODIMP_(ULONG) +DumpDataTarget::AddRef() +{ + LONG ref = InterlockedIncrement(&m_ref); + return ref; +} + +STDMETHODIMP_(ULONG) +DumpDataTarget::Release() +{ + LONG ref = InterlockedDecrement(&m_ref); + if (ref == 0) + { + delete this; + } + return ref; +} + +HRESULT STDMETHODCALLTYPE +DumpDataTarget::GetMachineType( + /* [out] */ ULONG32 *machine) +{ +#ifdef _AMD64_ + *machine = IMAGE_FILE_MACHINE_AMD64; +#elif _ARM_ + *machine = IMAGE_FILE_MACHINE_ARMNT; +#elif _ARM64_ + *machine = IMAGE_FILE_MACHINE_ARM64; +#elif _X86_ + *machine = IMAGE_FILE_MACHINE_I386; +#else +#error Unsupported architecture +#endif + return S_OK; +} + +HRESULT STDMETHODCALLTYPE +DumpDataTarget::GetPointerSize( + /* [out] */ ULONG32 *size) +{ +#if defined(_AMD64_) || defined(_ARM64_) + *size = 8; +#elif defined(_ARM_) || defined(_X86_) + *size = 4; +#else +#error Unsupported architecture +#endif + return S_OK; +} + +HRESULT STDMETHODCALLTYPE +DumpDataTarget::GetImageBase( + /* [string][in] */ LPCWSTR moduleName, + /* [out] */ CLRDATA_ADDRESS *baseAddress) +{ + assert(m_crashInfo != nullptr); + *baseAddress = 0; + + char tempModuleName[MAX_PATH]; + int length = WideCharToMultiByte(CP_ACP, 0, moduleName, -1, tempModuleName, sizeof(tempModuleName), NULL, NULL); + if (length > 0) + { + for (const MemoryRegion& image : m_crashInfo->ModuleMappings()) + { + const char *name = strrchr(image.FileName(), '/'); + if (name != nullptr) + { + name++; + } + else + { + name = image.FileName(); + } + if (strcmp(name, tempModuleName) == 0) + { + *baseAddress = image.StartAddress(); + return S_OK; + } + } + } + return E_FAIL; +} + +HRESULT STDMETHODCALLTYPE +DumpDataTarget::ReadVirtual( + /* [in] */ CLRDATA_ADDRESS address, + /* [length_is][size_is][out] */ PBYTE buffer, + /* [in] */ ULONG32 size, + /* [optional][out] */ ULONG32 *done) +{ + assert(m_fd != -1); + size_t read = pread64(m_fd, buffer, size, (off64_t)address); + if (read == -1) + { + fprintf(stderr, "ReadVirtual FAILED %016lx %08x\n", address, size); + *done = 0; + return E_FAIL; + } + *done = read; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE +DumpDataTarget::WriteVirtual( + /* [in] */ CLRDATA_ADDRESS address, + /* [size_is][in] */ PBYTE buffer, + /* [in] */ ULONG32 size, + /* [optional][out] */ ULONG32 *done) +{ + assert(false); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE +DumpDataTarget::GetTLSValue( + /* [in] */ ULONG32 threadID, + /* [in] */ ULONG32 index, + /* [out] */ CLRDATA_ADDRESS* value) +{ + assert(false); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE +DumpDataTarget::SetTLSValue( + /* [in] */ ULONG32 threadID, + /* [in] */ ULONG32 index, + /* [in] */ CLRDATA_ADDRESS value) +{ + assert(false); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE +DumpDataTarget::GetCurrentThreadID( + /* [out] */ ULONG32* threadID) +{ + assert(false); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE +DumpDataTarget::GetThreadContext( + /* [in] */ ULONG32 threadID, + /* [in] */ ULONG32 contextFlags, + /* [in] */ ULONG32 contextSize, + /* [out, size_is(contextSize)] */ PBYTE context) +{ + assert(m_crashInfo != nullptr); + if (contextSize < sizeof(CONTEXT)) + { + assert(false); + return E_INVALIDARG; + } + memset(context, 0, contextSize); + for (const ThreadInfo* thread : m_crashInfo->Threads()) + { + if (thread->Tid() == threadID) + { + thread->GetThreadContext(contextFlags, reinterpret_cast<CONTEXT*>(context)); + return S_OK; + } + } + return E_FAIL; +} + +HRESULT STDMETHODCALLTYPE +DumpDataTarget::SetThreadContext( + /* [in] */ ULONG32 threadID, + /* [in] */ ULONG32 contextSize, + /* [out, size_is(contextSize)] */ PBYTE context) +{ + assert(false); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE +DumpDataTarget::Request( + /* [in] */ ULONG32 reqCode, + /* [in] */ ULONG32 inBufferSize, + /* [size_is][in] */ BYTE *inBuffer, + /* [in] */ ULONG32 outBufferSize, + /* [size_is][out] */ BYTE *outBuffer) +{ + 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; +} |