Commit 5c18bdf2 authored by Aleksey R.'s avatar Aleksey R.

add: ARM64 stack and CPU context support (for pykd/pykd#21)

parent a2b365c0
......@@ -16,33 +16,28 @@ namespace kdlib {
///////////////////////////////////////////////////////////////////////////////
static const struct DiaRegToRegRelativeAmd64 : DiaRegToRegRelativeBase
{
typedef std::map<ULONG, ULONG> Base;
DiaRegToRegRelativeAmd64();
} g_DiaRegToRegRelativeAmd64;
namespace {
DiaRegToRegRelativeAmd64::DiaRegToRegRelativeAmd64()
{
(*this)[CV_AMD64_RIP] = rriInstructionPointer;
(*this)[CV_AMD64_RBP] = rriStackFrame;
(*this)[CV_AMD64_RSP] = rriStackPointer;
}
const DiaRegToRegRelativeBase g_DiaRegToRegRelativeAmd64 {
{ CV_AMD64_RIP, rriInstructionPointer },
{ CV_AMD64_RBP, rriStackFrame },
{ CV_AMD64_RSP, rriStackPointer },
};
///////////////////////////////////////////////////////////////////////////////
const DiaRegToRegRelativeBase g_DiaRegToRegRelativeI386 {
{ CV_REG_EIP, rriInstructionPointer },
{ CV_REG_EBP, rriStackFrame },
{ CV_ALLREG_VFRAME, rriStackFrame },
{ CV_REG_ESP, rriStackPointer },
};
static const struct DiaRegToRegRelativeI386 : DiaRegToRegRelativeBase
{
typedef std::map<ULONG, ULONG> Base;
DiaRegToRegRelativeI386();
} g_DiaRegToRegRelativeI386;
const DiaRegToRegRelativeBase g_DiaRegToRegRelativeArm64 {
{ CV_ARM64_PC, rriInstructionPointer },
{ CV_ARM64_FP, rriStackFrame },
{ CV_ARM64_SP, rriStackPointer },
};
DiaRegToRegRelativeI386::DiaRegToRegRelativeI386()
{
(*this)[CV_REG_EIP] = rriInstructionPointer;
(*this)[CV_REG_EBP] = (*this)[CV_ALLREG_VFRAME] = rriStackFrame;
(*this)[CV_REG_ESP] = rriStackPointer;
}
} // end nameless namespace
///////////////////////////////////////////////////////////////////////////////
......@@ -431,6 +426,8 @@ ULONG DiaSymbol::getRegRealativeId()
return getRegRealativeIdImpl(g_DiaRegToRegRelativeAmd64);
case IMAGE_FILE_MACHINE_I386:
return getRegRealativeIdImpl(g_DiaRegToRegRelativeI386);
case IMAGE_FILE_MACHINE_ARM64:
return getRegRealativeIdImpl(g_DiaRegToRegRelativeArm64);
}
throw DiaException(L"Unsupported machine type");
}
......
This diff is collapsed.
......@@ -8,16 +8,14 @@
namespace kdlib {
///////////////////////////////////////////////////////////////////////////////
template <typename CONTEXT_TYPE>
class CPUContextImpl : public CPUContext
{
public:
CPUContextImpl();
protected:
using RawContextType = typename CONTEXT_TYPE;
virtual CPUType getCPUType() {
return m_cpuType;
......@@ -27,263 +25,192 @@ protected:
return m_cpuMode;
}
virtual NumVariant getRegisterByName( const std::wstring &name);
virtual void restore() {
auto hres = g_dbgMgr->advanced->SetThreadContext(&m_context, sizeof(m_context));
if (FAILED(hres))
throw DbgEngException(L"IDebugAdvanced::SetThreadContext", hres);
}
virtual void setRegisterByName( const std::wstring &name, const NumVariant& value) {
virtual NumVariant getRegisterByName(const std::wstring &name) {
NOT_IMPLEMENTED();
}
virtual NumVariant getRegisterByIndex( unsigned long index );
virtual void setRegisterByIndex( unsigned long index, const NumVariant& value) {
virtual void setRegisterByName(const std::wstring &name, const NumVariant& value) {
NOT_IMPLEMENTED();
}
virtual void setRegisterByIndex(unsigned long index, const NumVariant& value) {
NOT_IMPLEMENTED();
}
virtual std::wstring getRegisterName( unsigned long index );
virtual unsigned long getRegisterNumber() {
return static_cast<unsigned long>(m_indexedValues.size());
NOT_IMPLEMENTED();
}
virtual void restore();
virtual MEMOFFSET_64 getIP();
virtual void setIP(MEMOFFSET_64 ip);
virtual MEMOFFSET_64 getSP();
virtual void setSP(MEMOFFSET_64 sp);
virtual MEMOFFSET_64 getFP();
virtual void setFP(MEMOFFSET_64 fp);
virtual void setIP(MEMOFFSET_64 ip) {
NOT_IMPLEMENTED();
}
virtual void setSP(MEMOFFSET_64 sp) {
NOT_IMPLEMENTED();
}
virtual void setFP(MEMOFFSET_64 fp) {
NOT_IMPLEMENTED();
}
protected:
CPUContextImpl(CPUType cpuType, CPUType cpuMode, const CONTEXT_TYPE *context = nullptr)
: m_cpuType{ cpuType }, m_cpuMode{ cpuMode }
{
if (context)
{
static_assert(std::is_pod<CONTEXT_TYPE>::value, "std::is_pod<CONTEXT_TYPE>::value");
memcpy(&m_context, context, sizeof(CONTEXT_TYPE));
}
else
{
auto hres = g_dbgMgr->advanced->GetThreadContext(&m_context, sizeof(m_context));
if (FAILED(hres))
throw DbgEngException(L"IDebugAdvanced::GetThreadContext", hres);
}
}
CPUType m_cpuType;
CPUType m_cpuMode;
protected:
CONTEXT_TYPE m_context;
std::map<unsigned long, NumVariant> m_indexedValues;
std::map<std::wstring, unsigned long> m_indexedNames;
private:
const CPUType m_cpuType;
const CPUType m_cpuMode;
};
class CPUContextAmd64 : public CPUContext
///////////////////////////////////////////////////////////////////////////////
class CPUContextAmd64 : public CPUContextImpl<CONTEXT_X64>
{
typedef CPUContextImpl<CONTEXT_X64> Base;
public:
CPUContextAmd64();
CPUContextAmd64(const CONTEXT_X64& ctx) :
m_context(ctx)
{}
virtual CPUType getCPUType() {
return CPU_AMD64;
CPUContextAmd64() :
Base{ CPU_AMD64, CPU_AMD64 }
{
}
virtual CPUType getCPUMode() {
return CPU_AMD64;
}
virtual void restore();
virtual NumVariant getRegisterByName(const std::wstring &name) {
NOT_IMPLEMENTED();
}
virtual void setRegisterByName( const std::wstring &name, const NumVariant& value) {
NOT_IMPLEMENTED();
explicit CPUContextAmd64(const CONTEXT_X64 &context) :
Base{ CPU_AMD64, CPU_AMD64, &context }
{
}
virtual NumVariant getRegisterByIndex(unsigned long index);
virtual void setRegisterByIndex( unsigned long index, const NumVariant& value) {
NOT_IMPLEMENTED();
}
virtual std::wstring getRegisterName(unsigned long index);
virtual unsigned long getRegisterNumber() {
NOT_IMPLEMENTED();
}
virtual MEMOFFSET_64 getIP() {
return m_context.Rip;
}
virtual void setIP(MEMOFFSET_64 ip) {
NOT_IMPLEMENTED();
}
virtual MEMOFFSET_64 getSP() {
return m_context.Rsp;
}
virtual void setSP(MEMOFFSET_64 sp) {
NOT_IMPLEMENTED();
}
virtual MEMOFFSET_64 getFP() {
return m_context.Rbp;
}
virtual void setFP(MEMOFFSET_64 fp) {
NOT_IMPLEMENTED();
}
private:
CONTEXT_X64 m_context;
};
///////////////////////////////////////////////////////////////////////////////
class CPUContextI386: public CPUContext
class CPUContextI386 : public CPUContextImpl<CONTEXT_X86>
{
typedef CPUContextImpl<CONTEXT_X86> Base;
public:
CPUContextI386();
CPUContextI386(const CONTEXT_X86& ctx) :
m_context(ctx)
{}
virtual CPUType getCPUType() {
return CPU_I386;
}
virtual CPUType getCPUMode() {
return CPU_I386;
}
virtual void restore();
virtual NumVariant getRegisterByName(const std::wstring &name) {
NOT_IMPLEMENTED();
CPUContextI386() :
Base{ CPU_I386, CPU_I386 }
{
}
virtual void setRegisterByName( const std::wstring &name, const NumVariant& value) {
NOT_IMPLEMENTED();
CPUContextI386(const CONTEXT_X86 &context) :
Base{ CPU_I386, CPU_I386, &context }
{
}
virtual NumVariant getRegisterByIndex(unsigned long index);
virtual void setRegisterByIndex( unsigned long index, const NumVariant& value) {
NOT_IMPLEMENTED();
}
virtual std::wstring getRegisterName(unsigned long index);
virtual unsigned long getRegisterNumber() {
NOT_IMPLEMENTED();
}
virtual MEMOFFSET_64 getIP() {
return m_context.Eip;
}
virtual void setIP(MEMOFFSET_64 ip) {
NOT_IMPLEMENTED();
}
virtual MEMOFFSET_64 getSP() {
return m_context.Esp;
}
virtual void setSP(MEMOFFSET_64 sp) {
NOT_IMPLEMENTED();
}
virtual MEMOFFSET_64 getFP() {
return m_context.Ebp;
}
virtual void setFP(MEMOFFSET_64 fp) {
NOT_IMPLEMENTED();
}
private:
CONTEXT_X86 m_context;
};
///////////////////////////////////////////////////////////////////////////////
class CPUContextWOW64 : public CPUContext
class CPUContextWOW64 : public CPUContextImpl<WOW64_CONTEXT>
{
typedef CPUContextImpl<WOW64_CONTEXT> Base;
public:
CPUContextWOW64() :
Base{ CPU_AMD64, CPU_I386 }
{
}
CPUContextWOW64(const WOW64_CONTEXT& ctx) :
m_context(ctx)
{}
explicit CPUContextWOW64(const WOW64_CONTEXT &context) :
Base{ CPU_AMD64, CPU_I386, &context }
{
}
virtual NumVariant getRegisterByIndex(unsigned long index);
virtual std::wstring getRegisterName(unsigned long index);
virtual CPUType getCPUType() {
return CPU_AMD64;
virtual MEMOFFSET_64 getIP() {
return m_context.Eip;
}
virtual CPUType getCPUMode() {
return CPU_I386;
virtual MEMOFFSET_64 getSP() {
return m_context.Esp;
}
virtual void restore() {
NOT_IMPLEMENTED();
virtual MEMOFFSET_64 getFP() {
return m_context.Ebp;
}
};
///////////////////////////////////////////////////////////////////////////////
virtual NumVariant getRegisterByName(const std::wstring &name) {
NOT_IMPLEMENTED();
class CPUContextArm64 : public CPUContextImpl<CONTEXT_ARM64>
{
typedef CPUContextImpl<CONTEXT_ARM64> Base;
public:
CPUContextArm64() :
Base{ CPU_ARM64, CPU_ARM64 }
{
}
virtual void setRegisterByName( const std::wstring &name, const NumVariant& value) {
NOT_IMPLEMENTED();
explicit CPUContextArm64(const CONTEXT_ARM64 &context) :
Base{ CPU_ARM64, CPU_ARM64, &context }
{
}
virtual NumVariant getRegisterByIndex(unsigned long index);
virtual void setRegisterByIndex( unsigned long index, const NumVariant& value) {
NOT_IMPLEMENTED();
}
virtual std::wstring getRegisterName(unsigned long index);
virtual unsigned long getRegisterNumber() {
NOT_IMPLEMENTED();
}
virtual MEMOFFSET_64 getIP() {
return m_context.Eip;
}
virtual void setIP(MEMOFFSET_64 ip) {
NOT_IMPLEMENTED();
return m_context.Pc;
}
virtual MEMOFFSET_64 getSP() {
return m_context.Esp;
}
virtual void setSP(MEMOFFSET_64 sp) {
NOT_IMPLEMENTED();
return m_context.Sp;
}
virtual MEMOFFSET_64 getFP() {
return m_context.Ebp;
}
virtual void setFP(MEMOFFSET_64 fp) {
NOT_IMPLEMENTED();
return m_context.Fp;
}
private:
WOW64_CONTEXT m_context;
};
///////////////////////////////////////////////////////////////////////////////
}
} // namespace kdlib
......@@ -286,6 +286,100 @@ typedef struct WOW64_CONTEXT {
///////////////////////////////////////////////////////////////////////////////
#include "pshpack8.h"
#define ARM64_MAX_BREAKPOINTS 8
#define ARM64_MAX_WATCHPOINTS 2
typedef union _ARM64_NT_NEON128 {
struct {
ULONGLONG Low;
LONGLONG High;
} DUMMYSTRUCTNAME;
double D[2];
float S[4];
WORD H[8];
BYTE B[16];
} ARM64_NT_NEON128, *PARM64_NT_NEON128;
typedef struct DECLSPEC_ALIGN(16) _CONTEXT_ARM64 {
//
// Control flags.
//
/* +0x000 */ DWORD ContextFlags;
//
// Integer registers
//
/* +0x004 */ DWORD Cpsr; // NZVF + DAIF + CurrentEL + SPSel
/* +0x008 */ union {
struct {
DWORD64 X0;
DWORD64 X1;
DWORD64 X2;
DWORD64 X3;
DWORD64 X4;
DWORD64 X5;
DWORD64 X6;
DWORD64 X7;
DWORD64 X8;
DWORD64 X9;
DWORD64 X10;
DWORD64 X11;
DWORD64 X12;
DWORD64 X13;
DWORD64 X14;
DWORD64 X15;
DWORD64 X16;
DWORD64 X17;
DWORD64 X18;
DWORD64 X19;
DWORD64 X20;
DWORD64 X21;
DWORD64 X22;
DWORD64 X23;
DWORD64 X24;
DWORD64 X25;
DWORD64 X26;
DWORD64 X27;
DWORD64 X28;
/* +0x0f0 */ DWORD64 Fp;
/* +0x0f8 */ DWORD64 Lr;
} DUMMYSTRUCTNAME;
DWORD64 X[31];
} DUMMYUNIONNAME;
/* +0x100 */ DWORD64 Sp;
/* +0x108 */ DWORD64 Pc;
//
// Floating Point/NEON Registers
//
/* +0x110 */ ARM64_NT_NEON128 V[32];
/* +0x310 */ DWORD Fpcr;
/* +0x314 */ DWORD Fpsr;
//
// Debug registers
//
/* +0x318 */ DWORD Bcr[ARM64_MAX_BREAKPOINTS];
/* +0x338 */ DWORD64 Bvr[ARM64_MAX_BREAKPOINTS];
/* +0x378 */ DWORD Wcr[ARM64_MAX_WATCHPOINTS];
/* +0x380 */ DWORD64 Wvr[ARM64_MAX_WATCHPOINTS];
} CONTEXT_ARM64;
#include "poppack.h"
static_assert(FIELD_OFFSET(CONTEXT_ARM64, Fp) == 0x0f0, "FIELD_OFFSET(CONTEXT_ARM64, Fp) == 0x0f0");
static_assert(FIELD_OFFSET(CONTEXT_ARM64, Wvr) == 0x380, "FIELD_OFFSET(CONTEXT_ARM64, Wvr) == 0x380");
///////////////////////////////////////////////////////////////////////////////
union CONTEXT_STORAGE {
CONTEXT_X86 c1;
......
......@@ -5,8 +5,7 @@
#include "kdlib/typeinfo.h"
#include "kdlib/memaccess.h"
#include "kdlib/module.h"
#include <Windows.h>
#include "kdlib/stack.h"
using namespace kdlib;
......@@ -45,7 +44,7 @@ TEST_F(ARM64KernelMiniDump, Test)
// MS DIA
{
const std::wstring symName{ L"nt!KiUpdateThreadState" };
EXPECT_EQ(evaluate(symName).asULongLong(), getSymbolOffset(symName));
EXPECT_EQ( evaluate(symName).asULongLong(), getSymbolOffset(symName) );
}
// symexport
......@@ -57,4 +56,36 @@ TEST_F(ARM64KernelMiniDump, Test)
EXPECT_EQ( evaluate(L"clipsp!ClipSpInitialize").asULongLong(), clipsp->getSymbolVa(L"ClipSpInitialize") );
}
// stack & CPU context
{
const auto stack = getStack();
ASSERT_TRUE( stack.get() );
ASSERT_TRUE( stack->getFrameCount() >= 11 );
{
auto frame0 = stack->getFrame(0);
ASSERT_TRUE( frame0.get() );
EXPECT_EQ( std::wstring(L"KeBugCheck2"), findSymbol(frame0->getIP()) );
const auto currentContext = frame0->getCPUContext();
ASSERT_TRUE( currentContext.get() );
EXPECT_EQ( evaluate(L"@$ip").asULongLong(), currentContext->getIP() );
EXPECT_EQ( evaluate(L"@$csp").asULongLong(), currentContext->getSP() );
EXPECT_EQ( evaluate(L"@fp").asULongLong(), currentContext->getFP() );
}
{
auto frameWithVars = stack->getFrame(11);
ASSERT_TRUE( frameWithVars.get() );
EXPECT_EQ( std::wstring(L"FxRequest::CompleteInternal"), findSymbol(frameWithVars->getIP()) );
// sp-based variable
EXPECT_EQ( 0xffffc18eaa798940, frameWithVars->getLocalVar(L"irp")->getElement(L"m_Irp")->getValue() );
EXPECT_EQ( 0, frameWithVars->getTypedParam(L"Status")->getValue() );
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment