555 lines
14 KiB
C++
555 lines
14 KiB
C++
//----------------------------------------------------------------------------
|
|
//
|
|
// ARM machine implementation.
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 2001-2002.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "ntsdp.hpp"
|
|
|
|
char g_ArmSp[] = "sp";
|
|
char g_ArmLr[] = "lr";
|
|
char g_ArmPc[] = "pc";
|
|
char g_ArmPsr[] = "psr";
|
|
char g_ArmPsrN[] = "nf";
|
|
char g_ArmPsrZ[] = "zf";
|
|
char g_ArmPsrC[] = "cf";
|
|
char g_ArmPsrV[] = "vf";
|
|
char g_ArmPsrQ[] = "qf";
|
|
char g_ArmPsrI[] = "if";
|
|
char g_ArmPsrF[] = "ff";
|
|
char g_ArmPsrT[] = "tf";
|
|
char g_ArmPsrMode[] = "mode";
|
|
|
|
REGDEF g_ArmRegs[] =
|
|
{
|
|
g_R0, ARM_R0, g_R1, ARM_R1, g_R2, ARM_R2, g_R3, ARM_R3,
|
|
g_R4, ARM_R4, g_R5, ARM_R5, g_R6, ARM_R6,
|
|
g_R7, ARM_R7, g_R8, ARM_R8, g_R9, ARM_R9, g_R10, ARM_R10,
|
|
g_R11, ARM_R11, g_R12, ARM_R12,
|
|
|
|
g_ArmSp, ARM_SP, g_ArmLr, ARM_LR, g_ArmPc, ARM_PC, g_ArmPsr, ARM_PSR,
|
|
|
|
g_ArmPsrN, ARM_PSR_N, g_ArmPsrZ, ARM_PSR_Z, g_ArmPsrC, ARM_PSR_C,
|
|
g_ArmPsrV, ARM_PSR_V, g_ArmPsrQ, ARM_PSR_Q, g_ArmPsrI, ARM_PSR_I,
|
|
g_ArmPsrF, ARM_PSR_F, g_ArmPsrT, ARM_PSR_T,
|
|
g_ArmPsrMode, ARM_PSR_MODE,
|
|
|
|
NULL, 0,
|
|
};
|
|
|
|
REGSUBDEF g_ArmSubRegs[] =
|
|
{
|
|
{ ARM_PSR_N, ARM_PSR, 31, 1 },
|
|
{ ARM_PSR_Z, ARM_PSR, 30, 1 },
|
|
{ ARM_PSR_C, ARM_PSR, 29, 1 },
|
|
{ ARM_PSR_V, ARM_PSR, 28, 1 },
|
|
{ ARM_PSR_Q, ARM_PSR, 27, 1 },
|
|
{ ARM_PSR_I, ARM_PSR, 7, 1 },
|
|
{ ARM_PSR_F, ARM_PSR, 6, 1 },
|
|
{ ARM_PSR_T, ARM_PSR, 5, 1 },
|
|
{ ARM_PSR_MODE, ARM_PSR, 0, 5 },
|
|
{ REG_ERROR, REG_ERROR, 0, 0 },
|
|
};
|
|
|
|
RegisterGroup g_ArmGroup =
|
|
{
|
|
0, g_ArmRegs, g_ArmSubRegs, NULL
|
|
};
|
|
|
|
// First ExecTypes entry must be the actual processor type.
|
|
ULONG g_ArmExecTypes[] =
|
|
{
|
|
IMAGE_FILE_MACHINE_ARM
|
|
};
|
|
|
|
// This array must be sorted by CV reg value.
|
|
CvRegMap g_ArmCvRegMap[] =
|
|
{
|
|
{CV_ARM_R0, ARM_R0},
|
|
{CV_ARM_R1, ARM_R1},
|
|
{CV_ARM_R2, ARM_R2},
|
|
{CV_ARM_R3, ARM_R3},
|
|
{CV_ARM_R4, ARM_R4},
|
|
{CV_ARM_R5, ARM_R5},
|
|
{CV_ARM_R6, ARM_R6},
|
|
{CV_ARM_R7, ARM_R7},
|
|
{CV_ARM_R8, ARM_R8},
|
|
{CV_ARM_R9, ARM_R9},
|
|
{CV_ARM_R10, ARM_R10},
|
|
{CV_ARM_R11, ARM_R11},
|
|
{CV_ARM_R12, ARM_R12},
|
|
{CV_ARM_SP, ARM_SP},
|
|
{CV_ARM_LR, ARM_LR},
|
|
{CV_ARM_PC, ARM_PC},
|
|
{CV_ARM_CPSR, ARM_PSR},
|
|
};
|
|
|
|
ArmMachineInfo::ArmMachineInfo(TargetInfo* Target)
|
|
: MachineInfo(Target)
|
|
{
|
|
m_FullName = "ARM 32-bit";
|
|
m_AbbrevName = "arm";
|
|
m_PageSize = ARM_PAGE_SIZE;
|
|
m_PageShift = ARM_PAGE_SHIFT;
|
|
m_NumExecTypes = 1;
|
|
m_ExecTypes = g_ArmExecTypes;
|
|
m_Ptr64 = FALSE;
|
|
m_RetRegIndex = ARM_R0;
|
|
|
|
m_MaxDataBreakpoints = 0;
|
|
m_SymPrefix = NULL;
|
|
|
|
m_AllMask = REGALL_INT32;
|
|
|
|
m_SizeCanonicalContext = sizeof(ARM_CONTEXT);
|
|
m_SverCanonicalContext = NT_SVER_NT4;
|
|
|
|
m_CvRegMapSize = DIMA(g_ArmCvRegMap);
|
|
m_CvRegMap = g_ArmCvRegMap;
|
|
}
|
|
|
|
HRESULT
|
|
ArmMachineInfo::Initialize(void)
|
|
{
|
|
m_NumGroups = 1;
|
|
m_Groups[0] = &g_ArmGroup;
|
|
|
|
return MachineInfo::Initialize();
|
|
}
|
|
|
|
void
|
|
ArmMachineInfo::
|
|
InitializeContext(ULONG64 Pc,
|
|
PDBGKD_ANY_CONTROL_REPORT ControlReport)
|
|
{
|
|
// No ARM KD support.
|
|
}
|
|
|
|
void
|
|
ArmMachineInfo::GetSystemTypeInfo(PSYSTEM_TYPE_INFO Info)
|
|
{
|
|
Info->SizeTargetContext = sizeof(ARM_CONTEXT);
|
|
Info->OffsetTargetContextFlags =
|
|
FIELD_OFFSET(ARM_CONTEXT, ContextFlags);
|
|
|
|
// NT doesn't run on the ARM so these NT-related
|
|
// data structure constants are not meaningful.
|
|
Info->SizeControlReport = 0;
|
|
Info->OffsetSpecialRegisters = 0;
|
|
Info->SizeKspecialRegisters = 0;
|
|
Info->TriagePrcbOffset = 0;
|
|
Info->SizePageFrameNumber = sizeof(ULONG);
|
|
Info->SizePte = sizeof(ULONG);
|
|
Info->SharedUserDataOffset = 0;
|
|
Info->UmSharedUserDataOffset = 0;
|
|
Info->UmSharedSysCallOffset = 0;
|
|
Info->UmSharedSysCallSize = 0;
|
|
Info->SizeDynamicFunctionTable = 0;
|
|
Info->SizeRuntimeFunction = 0;
|
|
}
|
|
|
|
void
|
|
ArmMachineInfo::GetDefaultKdData(PKDDEBUGGER_DATA64 KdData)
|
|
{
|
|
// No KD data to fill in.
|
|
}
|
|
|
|
HRESULT
|
|
ArmMachineInfo::KdGetContextState(ULONG State)
|
|
{
|
|
// MCTX_CONTEXT and MCTX_FULL are the same for Arm.
|
|
if (State >= MCTX_CONTEXT && m_ContextState < MCTX_FULL)
|
|
{
|
|
HRESULT Status;
|
|
|
|
Status = m_Target->GetContext(m_Target->m_RegContextThread->m_Handle,
|
|
&m_Context);
|
|
if (Status != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
m_ContextState = MCTX_FULL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
ArmMachineInfo::KdSetContext(void)
|
|
{
|
|
return m_Target->SetContext(m_Target->m_RegContextThread->m_Handle,
|
|
&m_Context);
|
|
}
|
|
|
|
HRESULT
|
|
ArmMachineInfo::ConvertContextFrom(PCROSS_PLATFORM_CONTEXT Context,
|
|
ULONG FromSver,
|
|
ULONG FromSize, PVOID From)
|
|
{
|
|
if (FromSize < sizeof(ARM_CONTEXT))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
memcpy(Context, From, sizeof(ARM_CONTEXT));
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
ArmMachineInfo::ConvertContextTo(PCROSS_PLATFORM_CONTEXT Context,
|
|
ULONG ToSver, ULONG ToSize, PVOID To)
|
|
{
|
|
if (ToSize < sizeof(ARM_CONTEXT))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
memcpy(To, Context, sizeof(ARM_CONTEXT));
|
|
return S_OK;
|
|
}
|
|
|
|
void
|
|
ArmMachineInfo::InitializeContextFlags(PCROSS_PLATFORM_CONTEXT Context,
|
|
ULONG Version)
|
|
{
|
|
Context->ArmContext.ContextFlags = ARM_CONTEXT_FULL;
|
|
}
|
|
|
|
HRESULT
|
|
ArmMachineInfo::GetContextFromThreadStack(ULONG64 ThreadBase,
|
|
PCROSS_PLATFORM_CONTEXT Context,
|
|
ULONG64 Stack)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT
|
|
ArmMachineInfo::GetContextFromFiber(ProcessInfo* Process,
|
|
ULONG64 FiberBase,
|
|
PCROSS_PLATFORM_CONTEXT Context,
|
|
BOOL Verbose)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT
|
|
ArmMachineInfo::GetContextFromTrapFrame(ULONG64 TrapBase,
|
|
PCROSS_PLATFORM_CONTEXT Context,
|
|
BOOL Verbose)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
void
|
|
ArmMachineInfo::GetScopeFrameFromContext(PCROSS_PLATFORM_CONTEXT Context,
|
|
PDEBUG_STACK_FRAME ScopeFrame)
|
|
{
|
|
ZeroMemory(ScopeFrame, sizeof(*ScopeFrame));
|
|
ScopeFrame->InstructionOffset = Context->ArmContext.Pc;
|
|
ScopeFrame->FrameOffset = Context->ArmContext.R11;
|
|
ScopeFrame->StackOffset = Context->ArmContext.Sp;
|
|
}
|
|
|
|
HRESULT
|
|
ArmMachineInfo::GetScopeFrameRegister(ULONG Reg,
|
|
PDEBUG_STACK_FRAME ScopeFrame,
|
|
PULONG64 Value)
|
|
{
|
|
HRESULT Status;
|
|
REGVAL RegVal;
|
|
|
|
switch(Reg)
|
|
{
|
|
case ARM_SP:
|
|
*Value = ScopeFrame->StackOffset;
|
|
return S_OK;
|
|
case ARM_R11:
|
|
*Value = ScopeFrame->FrameOffset;
|
|
return S_OK;
|
|
default:
|
|
RegVal.I64 = 0;
|
|
if ((Status = FullGetVal(Reg, &RegVal)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
*Value = RegVal.I64;
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
ArmMachineInfo::SetScopeFrameRegister(ULONG Reg,
|
|
PDEBUG_STACK_FRAME ScopeFrame,
|
|
ULONG64 Value)
|
|
{
|
|
REGVAL RegVal;
|
|
|
|
switch(Reg)
|
|
{
|
|
case ARM_SP:
|
|
ScopeFrame->StackOffset = Value;
|
|
return S_OK;
|
|
case ARM_R11:
|
|
ScopeFrame->FrameOffset = Value;
|
|
return S_OK;
|
|
default:
|
|
RegVal.Type = GetType(Reg);
|
|
RegVal.I64 = Value;
|
|
return FullSetVal(Reg, &RegVal);
|
|
}
|
|
}
|
|
|
|
int
|
|
ArmMachineInfo::GetType(ULONG Reg)
|
|
{
|
|
if (Reg < ARM_INT_FIRST || Reg > ARM_INT_LAST)
|
|
{
|
|
return REGVAL_SUB32;
|
|
}
|
|
else
|
|
{
|
|
return REGVAL_INT32;
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
ArmMachineInfo::GetVal(ULONG Reg, REGVAL *Val)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if (Reg < ARM_INT_FIRST || Reg > ARM_INT_LAST)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ((Status = GetContextState(MCTX_FULL)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
Val->Type = GetType(Reg);
|
|
Val->I64 = *(&m_Context.ArmContext.R0 + (Reg - ARM_INT_FIRST));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
ArmMachineInfo::SetVal(ULONG Reg, REGVAL *Val)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if (m_ContextIsReadOnly)
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_WRITE_FAULT);
|
|
}
|
|
|
|
if (Reg < ARM_INT_FIRST || Reg > ARM_INT_LAST)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// Optimize away some common cases where registers are
|
|
// set to their current value.
|
|
if (m_ContextState >= MCTX_PC && Reg == ARM_PC &&
|
|
Val->I64 == m_Context.ArmContext.Pc)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
if ((Status = GetContextState(MCTX_DIRTY)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
*(&m_Context.ArmContext.R0 + (Reg - ARM_INT_FIRST)) = Val->I32;
|
|
|
|
NotifyChangeDebuggeeState(DEBUG_CDS_REGISTERS,
|
|
RegCountFromIndex(Reg));
|
|
return S_OK;
|
|
}
|
|
|
|
void
|
|
ArmMachineInfo::GetPC(PADDR Address)
|
|
{
|
|
ADDRFLAT(Address, EXTEND64(GetReg32(ARM_PC)));
|
|
}
|
|
|
|
void
|
|
ArmMachineInfo::SetPC(PADDR Address)
|
|
{
|
|
SetReg32(ARM_PC, (ULONG)Flat(*Address));
|
|
}
|
|
|
|
void
|
|
ArmMachineInfo::GetFP(PADDR Address)
|
|
{
|
|
ADDRFLAT(Address, EXTEND64(GetReg32(ARM_R11)));
|
|
}
|
|
|
|
void
|
|
ArmMachineInfo::GetSP(PADDR Address)
|
|
{
|
|
ADDRFLAT(Address, EXTEND64(GetReg32(ARM_SP)));
|
|
}
|
|
|
|
ULONG64
|
|
ArmMachineInfo::GetArgReg(void)
|
|
{
|
|
return EXTEND64(GetReg32(ARM_R0));
|
|
}
|
|
|
|
ULONG64
|
|
ArmMachineInfo::GetRetReg(void)
|
|
{
|
|
return EXTEND64(GetReg32(ARM_R0));
|
|
}
|
|
|
|
void
|
|
ArmMachineInfo::OutputAll(ULONG Mask, ULONG OutMask)
|
|
{
|
|
if (GetContextState(MCTX_FULL) != S_OK)
|
|
{
|
|
ErrOut("Unable to retrieve register information\n");
|
|
return;
|
|
}
|
|
|
|
if (Mask & (REGALL_INT32 | REGALL_INT64))
|
|
{
|
|
MaskOut(OutMask, " r0=%08x r1=%08x r2=%08x "
|
|
"r3=%08x r4=%08x r5=%08x\n",
|
|
m_Context.ArmContext.R0, m_Context.ArmContext.R1,
|
|
m_Context.ArmContext.R2, m_Context.ArmContext.R3,
|
|
m_Context.ArmContext.R4, m_Context.ArmContext.R5);
|
|
MaskOut(OutMask, " r6=%08x r7=%08x r8=%08x "
|
|
"r9=%08x r10=%08x r11=%08x\n",
|
|
m_Context.ArmContext.R6, m_Context.ArmContext.R7,
|
|
m_Context.ArmContext.R8, m_Context.ArmContext.R9,
|
|
m_Context.ArmContext.R10, m_Context.ArmContext.R11);
|
|
MaskOut(OutMask, "r12=%08x sp=%08x lr=%08x "
|
|
"pc=%08x psr=%08x %s%s%s%s%s %s\n",
|
|
m_Context.ArmContext.R12, m_Context.ArmContext.Sp,
|
|
m_Context.ArmContext.Lr, m_Context.ArmContext.Pc,
|
|
m_Context.ArmContext.Psr,
|
|
(m_Context.ArmContext.Psr & ARM_FLAG_N) ? "N" : "-",
|
|
(m_Context.ArmContext.Psr & ARM_FLAG_Z) ? "Z" : "-",
|
|
(m_Context.ArmContext.Psr & ARM_FLAG_C) ? "C" : "-",
|
|
(m_Context.ArmContext.Psr & ARM_FLAG_V) ? "V" : "-",
|
|
(m_Context.ArmContext.Psr & ARM_FLAG_Q) ? "Q" : "-",
|
|
(m_Context.ArmContext.Psr & ARM_FLAG_T) ? "Thumb" : "ARM");
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
ArmMachineInfo::SetAndOutputTrapFrame(ULONG64 TrapBase,
|
|
PCROSS_PLATFORM_CONTEXT Context)
|
|
{
|
|
return SetAndOutputContext(Context, TRUE, REGALL_INT32);
|
|
}
|
|
|
|
TRACEMODE
|
|
ArmMachineInfo::GetTraceMode(void)
|
|
{
|
|
return TRACE_NONE;
|
|
}
|
|
|
|
void
|
|
ArmMachineInfo::SetTraceMode(TRACEMODE Mode)
|
|
{
|
|
// No explicit trace mode needed.
|
|
}
|
|
|
|
BOOL
|
|
ArmMachineInfo::IsStepStatusSupported(ULONG Status)
|
|
{
|
|
switch (Status)
|
|
{
|
|
case DEBUG_STATUS_STEP_INTO:
|
|
case DEBUG_STATUS_STEP_OVER:
|
|
return TRUE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
ULONG
|
|
ArmMachineInfo::ExecutingMachine(void)
|
|
{
|
|
return m_ExecTypes[0];
|
|
}
|
|
|
|
HRESULT
|
|
ArmMachineInfo::SetPageDirectory(ThreadInfo* Thread,
|
|
ULONG Idx, ULONG64 PageDir,
|
|
PULONG NextIdx)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT
|
|
ArmMachineInfo::GetVirtualTranslationPhysicalOffsets(ThreadInfo* Thread,
|
|
ULONG64 Virt,
|
|
PULONG64 Offsets,
|
|
ULONG OffsetsSize,
|
|
PULONG Levels,
|
|
PULONG PfIndex,
|
|
PULONG64 LastVal)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT
|
|
ArmMachineInfo::GetBaseTranslationVirtualOffset(PULONG64 Offset)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
void
|
|
ArmMachineInfo::DecodePte(ULONG64 Pte, PULONG64 PageFrameNumber,
|
|
PULONG Flags)
|
|
{
|
|
// XXX
|
|
*PageFrameNumber = 0;
|
|
*Flags = 0;
|
|
}
|
|
|
|
void
|
|
ArmMachineInfo::OutputFunctionEntry(PVOID RawEntry)
|
|
{
|
|
ErrOut("ARM function entries not implemented\n");
|
|
}
|
|
|
|
HRESULT
|
|
ArmMachineInfo::ReadDynamicFunctionTable(ProcessInfo* Process,
|
|
ULONG64 Table,
|
|
PULONG64 NextTable,
|
|
PULONG64 MinAddress,
|
|
PULONG64 MaxAddress,
|
|
PULONG64 BaseAddress,
|
|
PULONG64 TableData,
|
|
PULONG TableSize,
|
|
PWSTR OutOfProcessDll,
|
|
PCROSS_PLATFORM_DYNAMIC_FUNCTION_TABLE RawTable)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
PVOID
|
|
ArmMachineInfo::FindDynamicFunctionEntry(PCROSS_PLATFORM_DYNAMIC_FUNCTION_TABLE Table,
|
|
ULONG64 Address,
|
|
PVOID TableData,
|
|
ULONG TableSize)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
HRESULT
|
|
ArmMachineInfo::ReadKernelProcessorId
|
|
(ULONG Processor, PDEBUG_PROCESSOR_IDENTIFICATION_ALL Id)
|
|
{
|
|
// No ARM KD support.
|
|
return E_NOTIMPL;
|
|
}
|