1657 lines
47 KiB
C++
1657 lines
47 KiB
C++
/*** alpha_reg.c - processor-specific register structures
|
|
*
|
|
* Copyright <C> 1990-2001, Microsoft Corporation
|
|
* Copyright <C> 1992, Digital Equipment Corporation
|
|
*
|
|
* Purpose:
|
|
* Structures used to parse and access register and flag
|
|
* fields.
|
|
*
|
|
* Revision History:
|
|
*
|
|
* [-] 08-Aug-1992 Miche Baker-Harvey Created for Alpha
|
|
* [-] 01-Jul-1990 Richk Created.
|
|
*
|
|
*************************************************************************/
|
|
|
|
#include "ntsdp.hpp"
|
|
|
|
#include "alpha_strings.h"
|
|
#include "alpha_optable.h"
|
|
|
|
// See Get/SetRegVal comments in machine.hpp.
|
|
#define RegValError Do_not_use_GetSetRegVal_in_machine_implementations
|
|
#define GetRegVal(index, val) RegValError
|
|
#define GetRegVal32(index) RegValError
|
|
#define GetRegVal64(index) RegValError
|
|
#define SetRegVal(index, val) RegValError
|
|
#define SetRegVal32(index, val) RegValError
|
|
#define SetRegVal64(index, val) RegValError
|
|
|
|
#define IS_FLOATING_SAVED(Register) ((SAVED_FLOATING_MASK >> Register) & 1L)
|
|
#define IS_INTEGER_SAVED(Register) ((SAVED_INTEGER_MASK >> Register) & 1L)
|
|
|
|
|
|
//
|
|
// Define saved register masks.
|
|
|
|
#define SAVED_FLOATING_MASK 0xfff00000 // saved floating registers
|
|
#define SAVED_INTEGER_MASK 0xf3ffff02 // saved integer registers
|
|
|
|
|
|
//
|
|
// Instruction opcode values are defined in alphaops.h
|
|
//
|
|
|
|
REGDEF AlphaRegs[] =
|
|
{
|
|
g_F0, ALPHA_F0, g_F1, ALPHA_F1, g_F2, ALPHA_F2, g_F3, ALPHA_F3,
|
|
g_F4, ALPHA_F4, g_F5, ALPHA_F5, g_F6, ALPHA_F6, g_F7, ALPHA_F7,
|
|
g_F8, ALPHA_F8, g_F9, ALPHA_F9, g_F10, ALPHA_F10, g_F11, ALPHA_F11,
|
|
g_F12, ALPHA_F12, g_F13, ALPHA_F13, g_F14, ALPHA_F14, g_F15, ALPHA_F15,
|
|
g_F16, ALPHA_F16, g_F17, ALPHA_F17, g_F18, ALPHA_F18, g_F19, ALPHA_F19,
|
|
g_F20, ALPHA_F20, g_F21, ALPHA_F21, g_F22, ALPHA_F22, g_F23, ALPHA_F23,
|
|
g_F24, ALPHA_F24, g_F25, ALPHA_F25, g_F26, ALPHA_F26, g_F27, ALPHA_F27,
|
|
g_F28, ALPHA_F28, g_F29, ALPHA_F29, g_F30, ALPHA_F30, g_F31, ALPHA_F31,
|
|
|
|
g_AlphaV0, ALPHA_V0, g_AlphaT0, ALPHA_T0, g_AlphaT1, ALPHA_T1, g_AlphaT2, ALPHA_T2,
|
|
g_AlphaT3, ALPHA_T3, g_AlphaT4, ALPHA_T4, g_AlphaT5, ALPHA_T5, g_AlphaT6, ALPHA_T6,
|
|
g_AlphaT7, ALPHA_T7, g_AlphaS0, ALPHA_S0, g_AlphaS1, ALPHA_S1, g_AlphaS2, ALPHA_S2,
|
|
g_AlphaS3, ALPHA_S3, g_AlphaS4, ALPHA_S4, g_AlphaS5, ALPHA_S5, g_AlphaFP, ALPHA_FP,
|
|
g_AlphaA0, ALPHA_A0, g_AlphaA1, ALPHA_A1, g_AlphaA2, ALPHA_A2, g_AlphaA3, ALPHA_A3,
|
|
g_AlphaA4, ALPHA_A4, g_AlphaA5, ALPHA_A5, g_AlphaT8, ALPHA_T8, g_AlphaT9, ALPHA_T9,
|
|
g_AlphaT10, ALPHA_T10, g_AlphaT11, ALPHA_T11, g_AlphaRA, ALPHA_RA,
|
|
g_AlphaT12, ALPHA_T12, g_AlphaAT, ALPHA_AT, g_AlphaGP, ALPHA_GP,
|
|
g_AlphaSP, ALPHA_SP, g_AlphaZero, ALPHA_ZERO,
|
|
|
|
szFpcr, ALPHA_FPCR, szSoftFpcr, ALPHA_SFTFPCR, szFir, ALPHA_FIR,
|
|
|
|
szPsr, ALPHA_PSR,
|
|
|
|
szFlagMode, ALPHA_MODE, szFlagIe, ALPHA_IE, szFlagIrql, ALPHA_IRQL,
|
|
|
|
NULL, 0,
|
|
};
|
|
|
|
//
|
|
// PSR & IE definitions are from ksalpha.h
|
|
// which is generated automatically.
|
|
// Steal from \\bbox2\alphado\nt\public\sdk\inc\ksalpha.h
|
|
// NB: our masks are already shifted:
|
|
//
|
|
REGSUBDEF AlphaSubRegs[] =
|
|
{
|
|
{ ALPHA_MODE, ALPHA_PSR, ALPHA_PSR_MODE, ALPHA_PSR_MODE_MASK },
|
|
{ ALPHA_IE, ALPHA_PSR, ALPHA_PSR_IE, ALPHA_PSR_IE_MASK },
|
|
{ ALPHA_IRQL, ALPHA_PSR, ALPHA_PSR_IRQL, ALPHA_PSR_IRQL_MASK },
|
|
{ REG_ERROR, REG_ERROR, 0, 0 },
|
|
};
|
|
|
|
RegisterGroup g_AlphaGroup =
|
|
{
|
|
NULL, 0, AlphaRegs, AlphaSubRegs, NULL
|
|
};
|
|
|
|
// First ExecTypes entry must be the actual processor type.
|
|
ULONG g_Axp32ExecTypes[] =
|
|
{
|
|
IMAGE_FILE_MACHINE_ALPHA
|
|
};
|
|
|
|
// First ExecTypes entry must be the actual processor type.
|
|
ULONG g_Axp64ExecTypes[] =
|
|
{
|
|
IMAGE_FILE_MACHINE_AXP64
|
|
};
|
|
|
|
Axp32MachineInfo g_Axp32Machine;
|
|
Axp64MachineInfo g_Axp64Machine;
|
|
|
|
HRESULT
|
|
AlphaMachineInfo::InitializeConstants(void)
|
|
{
|
|
HRESULT Status;
|
|
|
|
m_Groups = &g_AlphaGroup;
|
|
m_AllMask = REGALL_INT64;
|
|
m_MaxDataBreakpoints = 0;
|
|
m_SymPrefix = NULL;
|
|
|
|
// 32/64-bit values are set in the specific Initialize.
|
|
// Alpha-generic values are here.
|
|
|
|
C_ASSERT(sizeof(ALPHA_CONTEXT) == sizeof(ALPHA_NT5_CONTEXT));
|
|
|
|
m_SizeTargetContext = sizeof(ALPHA_NT5_CONTEXT);
|
|
m_OffsetTargetContextFlags = FIELD_OFFSET(ALPHA_NT5_CONTEXT, ContextFlags);
|
|
m_SizeCanonicalContext = sizeof(ALPHA_NT5_CONTEXT);
|
|
m_SverCanonicalContext = NT_SVER_NT4;
|
|
m_SizeControlReport = sizeof(ALPHA_DBGKD_CONTROL_REPORT);
|
|
m_OffsetSpecialRegisters = 0;
|
|
m_SizeKspecialRegisters = 0;
|
|
|
|
if ((Status = opTableInit()) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
return MachineInfo::InitializeConstants();
|
|
}
|
|
|
|
void
|
|
AlphaMachineInfo::
|
|
InitializeContext(ULONG64 Pc,
|
|
PDBGKD_ANY_CONTROL_REPORT ControlReport)
|
|
{
|
|
m_Context.AlphaNt5Context.Fir = Pc;
|
|
m_ContextState = Pc ? MCTX_PC : MCTX_NONE;
|
|
|
|
if (Pc && ControlReport != NULL)
|
|
{
|
|
CacheReportInstructions
|
|
(Pc, ControlReport->AlphaControlReport.InstructionCount,
|
|
ControlReport->AlphaControlReport.InstructionStream);
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
AlphaMachineInfo::KdGetContextState(ULONG State)
|
|
{
|
|
// MCTX_CONTEXT and MCTX_FULL are the same for Alpha.
|
|
if (State >= MCTX_CONTEXT && m_ContextState < MCTX_FULL)
|
|
{
|
|
HRESULT Status;
|
|
|
|
Status = g_Target->GetContext(g_RegContextThread->Handle, &m_Context);
|
|
if (Status != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
m_ContextState = MCTX_FULL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
AlphaMachineInfo::KdSetContext(void)
|
|
{
|
|
return g_Target->SetContext(g_RegContextThread->Handle, &m_Context);
|
|
}
|
|
|
|
HRESULT
|
|
AlphaMachineInfo::ConvertContextFrom(PCROSS_PLATFORM_CONTEXT Context,
|
|
ULONG FromSver,
|
|
ULONG FromSize, PVOID From)
|
|
{
|
|
if (FromSize < sizeof(ALPHA_NT5_CONTEXT))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
PALPHA_CONTEXT Ctx = (PALPHA_CONTEXT)From;
|
|
|
|
// ALPHA_CONTEXT has been floating around for a while
|
|
// for use by the debugger. The system hasn't used it
|
|
// so they shouldn't ever end up here but go ahead
|
|
// and try and detect them based on the flags.
|
|
if (Ctx->ContextFlags != ALPHA_CONTEXT_FULL)
|
|
{
|
|
// This doesn't look like an ALPHA_CONTEXT, check
|
|
// ALPHA_NT5_CONTEXT.
|
|
if (((PALPHA_NT5_CONTEXT)From)->ContextFlags !=
|
|
ALPHA_CONTEXT_FULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// It looks like an ALPHA_NT5_CONTEXT so don't convert.
|
|
memcpy(Context, From, sizeof(ALPHA_NT5_CONTEXT));
|
|
}
|
|
else
|
|
{
|
|
PULONG High;
|
|
PULONG Low;
|
|
PULONGLONG Full;
|
|
int Count;
|
|
|
|
Low = &Ctx->FltF0;
|
|
High = &Ctx->HighFltF0;
|
|
Full = &Context->AlphaNt5Context.FltF0;
|
|
for (Count = 0; Count < 32; Count++)
|
|
{
|
|
Full[Count] = Low[Count] + ((ULONGLONG)High[Count] << 32);
|
|
}
|
|
|
|
Low = &Ctx->IntV0;
|
|
High = &Ctx->HighIntV0;
|
|
Full = &Context->AlphaNt5Context.IntV0;
|
|
for (Count = 0; Count < 32; Count++)
|
|
{
|
|
Full[Count] = Low[Count] + ((ULONGLONG)High[Count] << 32);
|
|
}
|
|
|
|
Context->AlphaNt5Context.ContextFlags = Ctx->ContextFlags;
|
|
Context->AlphaNt5Context.Psr = Ctx->Psr;
|
|
Context->AlphaNt5Context.Fpcr =
|
|
Ctx->Fpcr + ((ULONGLONG)Ctx->HighFpcr << 32);
|
|
Context->AlphaNt5Context.SoftFpcr =
|
|
Ctx->SoftFpcr + ((ULONGLONG)Ctx->HighSoftFpcr << 32);
|
|
Context->AlphaNt5Context.Fir =
|
|
Ctx->Fir + ((ULONGLONG)Ctx->HighFir << 32);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
AlphaMachineInfo::ConvertContextTo(PCROSS_PLATFORM_CONTEXT Context,
|
|
ULONG ToSver, ULONG ToSize, PVOID To)
|
|
{
|
|
if (ToSize < sizeof(ALPHA_NT5_CONTEXT))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
memcpy(To, Context, sizeof(ALPHA_NT5_CONTEXT));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void
|
|
AlphaMachineInfo::InitializeContextFlags(PCROSS_PLATFORM_CONTEXT Context,
|
|
ULONG Version)
|
|
{
|
|
Context->AlphaNt5Context.ContextFlags = ALPHA_CONTEXT_FULL;
|
|
}
|
|
|
|
int
|
|
AlphaMachineInfo::GetType(ULONG index)
|
|
{
|
|
if (
|
|
#if ALPHA_FLT_BASE > 0
|
|
index >= ALPHA_FLT_BASE &&
|
|
#endif
|
|
index <= ALPHA_FLT_LAST)
|
|
{
|
|
return REGVAL_FLOAT8;
|
|
}
|
|
else if (index >= ALPHA_INT64_BASE && index <= ALPHA_INT64_LAST)
|
|
{
|
|
return REGVAL_INT64;
|
|
}
|
|
else if (index >= ALPHA_INT32_BASE && index <= ALPHA_INT32_LAST)
|
|
{
|
|
return REGVAL_INT32;
|
|
}
|
|
else
|
|
{
|
|
return REGVAL_SUB32;
|
|
}
|
|
}
|
|
|
|
/*** RegGetVal - get register value
|
|
*
|
|
* Purpose:
|
|
* Returns the value of the register from the processor
|
|
* context structure.
|
|
*
|
|
* Input:
|
|
* regnum - register specification
|
|
*
|
|
* Returns:
|
|
* value of the register from the context structure
|
|
*
|
|
*************************************************************************/
|
|
|
|
BOOL
|
|
AlphaMachineInfo::GetVal (
|
|
ULONG regnum,
|
|
REGVAL *val
|
|
)
|
|
{
|
|
if (GetContextState(MCTX_FULL) != S_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
val->type = GetType(regnum);
|
|
// All registers except PSR are 64 bits and PSR is followed by
|
|
// ContextFlags so it's safe to always just grab 64 bits for
|
|
// the value.
|
|
val->i64 = *(&m_Context.AlphaNt5Context.FltF0 + regnum);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*** RegSetVal - set register value
|
|
*
|
|
* Purpose:
|
|
* Set the value of the register in the processor context
|
|
* structure.
|
|
*
|
|
* Input:
|
|
* regnum - register specification
|
|
* regvalue - new value to set the register
|
|
*
|
|
* Output:
|
|
* None.
|
|
*
|
|
*************************************************************************/
|
|
|
|
BOOL
|
|
AlphaMachineInfo::SetVal (
|
|
ULONG regnum,
|
|
REGVAL *val
|
|
)
|
|
{
|
|
if (m_ContextIsReadOnly)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Optimize away some common cases where registers are
|
|
// set to their current value.
|
|
if (m_ContextState >= MCTX_PC && regnum == ALPHA_FIR &&
|
|
val->i64 == m_Context.AlphaNt5Context.Fir)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if (GetContextState(MCTX_DIRTY) != S_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (regnum == ALPHA_PSR)
|
|
{
|
|
// Be careful to only write 32 bits for PSR to preserve
|
|
// ContextFlags.
|
|
*(ULONG *)(&m_Context.AlphaNt5Context.FltF0 + regnum) = val->i32;
|
|
}
|
|
else
|
|
{
|
|
*(&m_Context.AlphaNt5Context.FltF0 + regnum) = val->i64;
|
|
}
|
|
|
|
NotifyChangeDebuggeeState(DEBUG_CDS_REGISTERS,
|
|
RegCountFromIndex(regnum));
|
|
return TRUE;
|
|
}
|
|
|
|
/*** RegOutputAll - output all registers and present instruction
|
|
*
|
|
* Purpose:
|
|
* Function of "r" command.
|
|
*
|
|
* To output the current register state of the processor.
|
|
* All integer registers are output as well as processor status
|
|
* registers. Important flag fields are also output separately.
|
|
* OutDisCurrent is called to output the current instruction(s).
|
|
*
|
|
* Input:
|
|
* None.
|
|
*
|
|
* Output:
|
|
* None.
|
|
*
|
|
*************************************************************************/
|
|
|
|
VOID
|
|
AlphaMachineInfo::OutputAll(ULONG Mask, ULONG OutMask)
|
|
{
|
|
int regindex;
|
|
int regnumber;
|
|
ULONGLONG regvalue;
|
|
|
|
if (GetContextState(MCTX_FULL) != S_OK)
|
|
{
|
|
ErrOut("Unable to retrieve register information\n");
|
|
return;
|
|
}
|
|
|
|
if (Mask & (REGALL_INT32 | REGALL_INT64))
|
|
{
|
|
for (regindex = 0; regindex < 34; regindex++)
|
|
{
|
|
regnumber = GetIntRegNumber(regindex);
|
|
regvalue = GetReg64(regnumber);
|
|
|
|
if ( (Mask & REGALL_INT64) || regindex == 32 || regindex == 33)
|
|
{
|
|
MaskOut(OutMask, "%4s=%08lx %08lx",
|
|
RegNameFromIndex(regnumber),
|
|
(ULONG)(regvalue >> 32),
|
|
(ULONG)(regvalue & 0xffffffff));
|
|
if (regindex % 3 == 2)
|
|
{
|
|
MaskOut(OutMask, "\n");
|
|
}
|
|
else
|
|
{
|
|
MaskOut(OutMask, " ");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MaskOut(OutMask, "%4s=%08lx%c",
|
|
RegNameFromIndex(regnumber),
|
|
(ULONG)(regvalue & 0xffffffff),
|
|
NeedUpper(regvalue) ? '*' : ' ' );
|
|
if (regindex % 5 == 4)
|
|
{
|
|
MaskOut(OutMask, "\n");
|
|
}
|
|
else
|
|
{
|
|
MaskOut(OutMask, " ");
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// print out the fpcr as 64 bits regardless,
|
|
// and the FIR and Fpcr's - assuming we know they follow
|
|
// the floating and integer registers.
|
|
//
|
|
|
|
if (m_Ptr64)
|
|
{
|
|
regnumber = ALPHA_FIR;
|
|
MaskOut(OutMask, "%4s=%s\n",
|
|
RegNameFromIndex(regnumber),
|
|
FormatAddr64(GetReg64(regnumber)));
|
|
}
|
|
else
|
|
{
|
|
regnumber = ALPHA_FIR;
|
|
MaskOut(OutMask, "%4s=%08lx\n",
|
|
RegNameFromIndex(regnumber),
|
|
GetReg32(regnumber));
|
|
}
|
|
|
|
regnumber = ALPHA_PSR;
|
|
MaskOut(OutMask, "%4s=%08lx\n",
|
|
RegNameFromIndex(regnumber), GetReg32(regnumber));
|
|
|
|
MaskOut(OutMask, "mode=%1lx ie=%1lx irql=%1lx \n",
|
|
GetSubReg32(ALPHA_MODE),
|
|
GetSubReg32(ALPHA_IE),
|
|
GetSubReg32(ALPHA_IRQL));
|
|
}
|
|
|
|
if (Mask & REGALL_FLOAT)
|
|
{
|
|
ULONG i;
|
|
REGVAL val;
|
|
|
|
//
|
|
// Print them all out
|
|
//
|
|
for (i = 0 ; i < 16; i ++)
|
|
{
|
|
GetVal(i + ALPHA_FLT_BASE, &val);
|
|
MaskOut(OutMask, "%4s = %16e\t",
|
|
RegNameFromIndex(i), val.f8);
|
|
|
|
GetVal(i + ALPHA_FLT_BASE + 16, &val);
|
|
MaskOut(OutMask, "%4s = %16e\n",
|
|
RegNameFromIndex(i+16), val.f8);
|
|
}
|
|
}
|
|
}
|
|
|
|
TRACEMODE
|
|
AlphaMachineInfo::GetTraceMode (void)
|
|
{
|
|
return TRACE_NONE;
|
|
}
|
|
|
|
void
|
|
AlphaMachineInfo::SetTraceMode (TRACEMODE Mode)
|
|
{
|
|
;
|
|
}
|
|
|
|
BOOL
|
|
AlphaMachineInfo::IsStepStatusSupported(ULONG Status)
|
|
{
|
|
switch (Status)
|
|
{
|
|
case DEBUG_STATUS_STEP_INTO:
|
|
case DEBUG_STATUS_STEP_OVER:
|
|
return TRUE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
ULONG
|
|
AlphaMachineInfo::ExecutingMachine(void)
|
|
{
|
|
return g_TargetMachineType;
|
|
}
|
|
|
|
void
|
|
AlphaMachineInfo::ValidateCxr(PCROSS_PLATFORM_CONTEXT Context)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
BOOL
|
|
AlphaMachineInfo::DisplayTrapFrame(ULONG64 FrameAddress,
|
|
OUT PCROSS_PLATFORM_CONTEXT Context)
|
|
{
|
|
#define HIGH(x) ((ULONG) ((x>>32) & 0xFFFFFFFF))
|
|
#define LOW(x) ((ULONG) (x & 0xFFFFFFFF))
|
|
|
|
#define HIGHANDLOW(x) HIGH(x), LOW(x)
|
|
|
|
ALPHA_KTRAP_FRAME TrapContents;
|
|
ULONG64 Address=FrameAddress;
|
|
ULONG result;
|
|
ULONG64 DisasmAddr;
|
|
ULONG64 Displacement;
|
|
CHAR Buffer[80];
|
|
ULONG64 IntSp, IntFp;
|
|
|
|
if (!FrameAddress ||
|
|
g_Target->ReadVirtual(Address, &TrapContents,
|
|
sizeof(ALPHA_KTRAP_FRAME), &result) != S_OK)
|
|
{
|
|
dprintf("USAGE: !trap base_of_trap_frame\n");
|
|
return FALSE;
|
|
}
|
|
|
|
dprintf("v0 = %08lx %08lx a0 = %08lx %08lx\n" ,
|
|
HIGHANDLOW(TrapContents.IntV0),HIGHANDLOW(TrapContents.IntA0));
|
|
dprintf("t0 = %08lx %08lx a1 = %08lx %08lx\n" ,
|
|
HIGHANDLOW(TrapContents.IntT0),HIGHANDLOW(TrapContents.IntA1));
|
|
dprintf("t1 = %08lx %08lx a2 = %08lx %08lx\n" ,
|
|
HIGHANDLOW(TrapContents.IntT1),HIGHANDLOW(TrapContents.IntA2));
|
|
dprintf("t2 = %08lx %08lx a3 = %08lx %08lx\n" ,
|
|
HIGHANDLOW(TrapContents.IntT2),HIGHANDLOW(TrapContents.IntA3));
|
|
dprintf("t3 = %08lx %08lx a4 = %08lx %08lx\n" ,
|
|
HIGHANDLOW(TrapContents.IntT3),HIGHANDLOW(TrapContents.IntA4));
|
|
dprintf("t4 = %08lx %08lx a5 = %08lx %08lx\n" ,
|
|
HIGHANDLOW(TrapContents.IntT4),HIGHANDLOW(TrapContents.IntA5));
|
|
dprintf("t5 = %08lx %08lx t8 = %08lx %08lx\n" ,
|
|
HIGHANDLOW(TrapContents.IntT5),HIGHANDLOW(TrapContents.IntT8));
|
|
dprintf("t6 = %08lx %08lx t9 = %08lx %08lx\n" ,
|
|
HIGHANDLOW(TrapContents.IntT6),HIGHANDLOW(TrapContents.IntT9));
|
|
dprintf("t7 = %08lx %08lx t10 = %08lx %08lx\n" ,
|
|
HIGHANDLOW(TrapContents.IntT7),HIGHANDLOW(TrapContents.IntT10));
|
|
dprintf(" t11 = %08lx %08lx\n" ,
|
|
HIGHANDLOW(TrapContents.IntT11));
|
|
dprintf(" ra = %08lx %08lx\n" ,
|
|
HIGHANDLOW(TrapContents.IntRa));
|
|
dprintf(" t12 = %08lx %08lx\n" ,
|
|
HIGHANDLOW(TrapContents.IntT12));
|
|
dprintf(" at = %08lx %08lx\n" ,
|
|
HIGHANDLOW(TrapContents.IntAt));
|
|
dprintf(" gp = %08lx %08lx\n" ,
|
|
HIGHANDLOW(TrapContents.IntGp));
|
|
dprintf("fp = %08lx %08lx sp = %08lx %08lx\n",
|
|
HIGHANDLOW(IntFp = TrapContents.IntFp),HIGHANDLOW(IntSp = TrapContents.IntSp));
|
|
dprintf("fir= %08lx %08lx\n",
|
|
HIGHANDLOW(TrapContents.Fir));
|
|
|
|
DisasmAddr = (TrapContents.Fir);
|
|
g_LastRegFrame.InstructionOffset = DisasmAddr;
|
|
g_LastRegFrame.StackOffset = IntSp;
|
|
g_LastRegFrame.FrameOffset = IntFp;
|
|
|
|
GetSymbolStdCall(DisasmAddr, Buffer, sizeof(Buffer), &Displacement, NULL);
|
|
dprintf("%s+0x%I64lx\n",Buffer,Displacement);
|
|
|
|
ADDR tempAddr;
|
|
Type(tempAddr) = ADDR_FLAT | FLAT_COMPUTED;
|
|
Off(tempAddr) = Flat(tempAddr) = DisasmAddr;
|
|
|
|
if (Disassemble(&tempAddr, Buffer, FALSE))
|
|
{
|
|
|
|
dprintf(Buffer);
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
dprintf("%08I64lx ???????????????\n", DisasmAddr);
|
|
|
|
}
|
|
|
|
if (Context)
|
|
{
|
|
// Fill up the context struct
|
|
if (g_EffMachine == IMAGE_FILE_MACHINE_ALPHA)
|
|
{
|
|
#define COPY(fld) Context->AlphaContext.fld = (ULONG) TrapContents.fld
|
|
COPY(IntSp); COPY(IntFp); COPY(Fir);
|
|
COPY(IntRa); COPY(IntAt); COPY(IntGp);
|
|
COPY(IntV0); COPY(IntA0); COPY(IntT0); COPY(IntA1); COPY(IntA2);
|
|
COPY(IntT1); COPY(IntT2); COPY(IntT3); COPY(IntT4); COPY(IntT5);
|
|
COPY(IntT6); COPY(IntT6); COPY(IntT7); COPY(IntT8); COPY(IntT9);
|
|
COPY(IntT10); COPY(IntT11); COPY(IntT12);
|
|
COPY(IntA3); COPY(IntA4); COPY(IntA5);
|
|
#undef COPY
|
|
}
|
|
else
|
|
{
|
|
}
|
|
|
|
}
|
|
return TRUE;
|
|
|
|
#undef HIGHANDLOW
|
|
#undef HIGH
|
|
#undef LOW
|
|
}
|
|
|
|
HRESULT
|
|
AlphaMachineInfo::ReadKernelProcessorId
|
|
(ULONG Processor, PDEBUG_PROCESSOR_IDENTIFICATION_ALL Id)
|
|
{
|
|
HRESULT Status;
|
|
ULONG64 Pcr;
|
|
ULONG Data[2];
|
|
|
|
if ((Status = g_Target->
|
|
GetProcessorSystemDataOffset(Processor, DEBUG_DATA_KPCR_OFFSET,
|
|
&Pcr)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
Pcr += m_Ptr64 ?
|
|
FIELD_OFFSET(AXP64_PARTIAL_KPCR, ProcessorType) :
|
|
FIELD_OFFSET(ALPHA_PARTIAL_KPCR, ProcessorType);
|
|
|
|
if ((Status = g_Target->
|
|
ReadAllVirtual(Pcr, Data, sizeof(Data))) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
Id->Alpha.Type = Data[0];
|
|
Id->Alpha.Revision = Data[1];
|
|
return S_OK;
|
|
}
|
|
|
|
#define MAXENTRYTYPE 2
|
|
const char *g_AlphaEntryTypeName[] =
|
|
{
|
|
"ALPHA_RF_NOT_CONTIGUOUS", // 0
|
|
"ALPHA_RF_ALT_ENT_PROLOG", // 1
|
|
"ALPHA_RF_NULL_CONTEXT", // 2
|
|
"***INVALID***"
|
|
};
|
|
|
|
#define ALPHA_RF_ALT_PROLOG64(RF) (((ULONG64)(RF)->ExceptionHandler) & (~3))
|
|
|
|
void
|
|
AlphaMachineInfo::OutputFunctionEntry64
|
|
(PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY Entry)
|
|
{
|
|
BOOL Secondary = FALSE;
|
|
BOOL FixedReturn = FALSE;
|
|
ULONG EntryType = 0;
|
|
ULONG NullCount = 0;
|
|
|
|
if ((ALPHA_RF_PROLOG_END_ADDRESS(Entry) < ALPHA_RF_BEGIN_ADDRESS(Entry)) ||
|
|
(ALPHA_RF_PROLOG_END_ADDRESS(Entry) > ALPHA_RF_END_ADDRESS(Entry)))
|
|
{
|
|
Secondary = TRUE;
|
|
EntryType = ALPHA_RF_ENTRY_TYPE(Entry);
|
|
if (EntryType > MAXENTRYTYPE)
|
|
{
|
|
EntryType = MAXENTRYTYPE;
|
|
}
|
|
}
|
|
else if (ALPHA_RF_IS_FIXED_RETURN(Entry))
|
|
{
|
|
FixedReturn = TRUE;
|
|
}
|
|
NullCount = ALPHA_RF_NULL_CONTEXT_COUNT(Entry);
|
|
|
|
dprintf("BeginAddress = %s\n", FormatAddr64(Entry->BeginAddress));
|
|
dprintf("EndAddress = %s", FormatAddr64(Entry->EndAddress));
|
|
if (NullCount)
|
|
{
|
|
dprintf(" %d null-context instructions", NullCount);
|
|
}
|
|
dprintf("\n");
|
|
dprintf("ExceptionHandler = %s",
|
|
FormatAddr64(Entry->ExceptionHandler));
|
|
if (Entry->ExceptionHandler != 0)
|
|
{
|
|
if (Secondary)
|
|
{
|
|
ULONG64 AlternateProlog = ALPHA_RF_ALT_PROLOG64(Entry);
|
|
|
|
switch(EntryType)
|
|
{
|
|
case ALPHA_RF_NOT_CONTIGUOUS:
|
|
case ALPHA_RF_ALT_ENT_PROLOG:
|
|
if ((AlternateProlog >=
|
|
ALPHA_RF_BEGIN_ADDRESS(Entry)) &&
|
|
(AlternateProlog <= Entry->EndAddress))
|
|
{
|
|
dprintf(" alternate PrologEndAddress");
|
|
}
|
|
break;
|
|
case ALPHA_RF_NULL_CONTEXT:
|
|
dprintf(" stack adjustment");
|
|
break;
|
|
}
|
|
}
|
|
else if (FixedReturn)
|
|
{
|
|
dprintf(" fixed return address");
|
|
}
|
|
}
|
|
dprintf("\n");
|
|
dprintf("HandlerData = %s", FormatAddr64(Entry->HandlerData));
|
|
if (Secondary)
|
|
{
|
|
dprintf(" type %d: %s", EntryType, g_AlphaEntryTypeName[EntryType]);
|
|
}
|
|
dprintf("\n");
|
|
dprintf("PrologEndAddress = %s\n",
|
|
FormatAddr64(Entry->PrologEndAddress));
|
|
}
|
|
|
|
HRESULT
|
|
Axp32MachineInfo::InitializeConstants(void)
|
|
{
|
|
m_FullName = "Alpha 32-bit";
|
|
m_AbbrevName = "alpha";
|
|
m_PageSize = ALPHA_PAGE_SIZE;
|
|
m_PageShift = ALPHA_PAGE_SHIFT;
|
|
m_NumExecTypes = 1;
|
|
m_ExecTypes = g_Axp32ExecTypes;
|
|
m_Ptr64 = FALSE;
|
|
|
|
return AlphaMachineInfo::InitializeConstants();
|
|
}
|
|
|
|
HRESULT
|
|
Axp32MachineInfo::InitializeForTarget(void)
|
|
{
|
|
m_OffsetPrcbProcessorState =
|
|
FIELD_OFFSET(ALPHA_PARTIAL_KPRCB, ProcessorState);
|
|
m_OffsetPrcbNumber =
|
|
FIELD_OFFSET(ALPHA_PARTIAL_KPRCB, Number);
|
|
m_TriagePrcbOffset = EXTEND64(ALPHA_TRIAGE_PRCB_ADDRESS);
|
|
m_SizePrcb = ALPHA_KPRCB_SIZE;
|
|
m_OffsetKThreadApcProcess =
|
|
FIELD_OFFSET(CROSS_PLATFORM_THREAD, AlphaThread.ApcState.Process);
|
|
m_OffsetKThreadTeb =
|
|
FIELD_OFFSET(CROSS_PLATFORM_THREAD, AlphaThread.Teb);
|
|
m_OffsetKThreadInitialStack =
|
|
FIELD_OFFSET(CROSS_PLATFORM_THREAD, AlphaThread.InitialStack);
|
|
m_OffsetEprocessPeb = g_SystemVersion > NT_SVER_W2K ?
|
|
ALPHA_NT51_PEB_IN_EPROCESS : ALPHA_NT5_PEB_IN_EPROCESS;
|
|
m_OffsetEprocessDirectoryTableBase =
|
|
ALPHA_DIRECTORY_TABLE_BASE_IN_EPROCESS;
|
|
m_SizeEThread = ALPHA_ETHREAD_SIZE;
|
|
m_SizeEProcess = g_SystemVersion > NT_SVER_W2K ?
|
|
ALPHA_NT51_EPROCESS_SIZE : ALPHA_NT5_EPROCESS_SIZE;
|
|
m_SizePartialKThread = sizeof(ALPHA_THREAD);
|
|
m_SharedUserDataOffset = IS_KERNEL_TARGET() ?
|
|
EXTEND64(ALPHA_KI_USER_SHARED_DATA) : MM_SHARED_USER_DATA_VA;
|
|
|
|
return MachineInfo::InitializeForTarget();
|
|
}
|
|
|
|
HRESULT
|
|
Axp32MachineInfo::GetContextFromThreadStack(ULONG64 ThreadBase,
|
|
PCROSS_PLATFORM_THREAD Thread,
|
|
PCROSS_PLATFORM_CONTEXT Context,
|
|
PDEBUG_STACK_FRAME Frame,
|
|
PULONG RunningOnProc)
|
|
{
|
|
if (Thread->AlphaThread.State == 2)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT Status;
|
|
ALPHA_KEXCEPTION_FRAME ExFrame;
|
|
|
|
if ((Status = g_Target->ReadAllVirtual(Thread->AlphaThread.KernelStack,
|
|
&ExFrame, sizeof(ExFrame))) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Successfully read an exception frame from the stack.
|
|
//
|
|
|
|
Context->AlphaNt5Context.IntSp =
|
|
Thread->AlphaThread.KernelStack;
|
|
Context->AlphaNt5Context.Fir = ExFrame.SwapReturn;
|
|
Context->AlphaNt5Context.IntRa = ExFrame.SwapReturn;
|
|
Context->AlphaNt5Context.IntS0 = ExFrame.IntS0;
|
|
Context->AlphaNt5Context.IntS1 = ExFrame.IntS1;
|
|
Context->AlphaNt5Context.IntS2 = ExFrame.IntS2;
|
|
Context->AlphaNt5Context.IntS3 = ExFrame.IntS3;
|
|
Context->AlphaNt5Context.IntS4 = ExFrame.IntS4;
|
|
Context->AlphaNt5Context.IntS5 = ExFrame.IntS5;
|
|
Context->AlphaNt5Context.Psr = ExFrame.Psr;
|
|
|
|
Frame->FrameOffset = Context->AlphaNt5Context.IntSp;
|
|
Frame->StackOffset = Context->AlphaNt5Context.IntSp;
|
|
Frame->InstructionOffset = ExFrame.SwapReturn;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
VOID
|
|
Axp32MachineInfo::GetPC (
|
|
PADDR Address
|
|
)
|
|
{
|
|
// sign extend the address!
|
|
ADDRFLAT(Address, EXTEND64(GetReg32(ALPHA_FIR)));
|
|
}
|
|
|
|
VOID
|
|
Axp32MachineInfo::SetPC (
|
|
PADDR paddr
|
|
)
|
|
{
|
|
// sign extend the address!
|
|
SetReg64(ALPHA_FIR, EXTEND64(Flat(*paddr)));
|
|
}
|
|
|
|
VOID
|
|
Axp32MachineInfo::GetFP (
|
|
PADDR Address
|
|
)
|
|
{
|
|
ADDRFLAT(Address, GetReg32(FP_REG));
|
|
}
|
|
|
|
void
|
|
Axp32MachineInfo::GetSP(PADDR Address)
|
|
{
|
|
ADDRFLAT(Address, GetReg32(SP_REG));
|
|
}
|
|
|
|
ULONG64
|
|
Axp32MachineInfo::GetArgReg(void)
|
|
{
|
|
return GetReg32(ALPHA_INT64_BASE + A0_REG);
|
|
}
|
|
|
|
HRESULT
|
|
Axp32MachineInfo::SetPageDirectory(ULONG Idx, ULONG64 PageDir,
|
|
PULONG NextIdx)
|
|
{
|
|
*NextIdx = PAGE_DIR_COUNT;
|
|
|
|
if (PageDir == 0)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = g_Target->ReadImplicitProcessInfoPointer
|
|
(m_OffsetEprocessDirectoryTableBase, &PageDir)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
// DirectoryTableBase values on Alpha are the raw PTE entries
|
|
// so turn it into a clean physical address.
|
|
PageDir = ((ULONG)PageDir >> ALPHA_VALID_PFN_SHIFT) <<
|
|
ALPHA_PAGE_SHIFT;
|
|
|
|
// There is only one page directory so update all the slots.
|
|
m_PageDirectories[PAGE_DIR_USER] = PageDir;
|
|
m_PageDirectories[PAGE_DIR_SESSION] = PageDir;
|
|
m_PageDirectories[PAGE_DIR_KERNEL] = PageDir;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
#define ALPHA_PAGE_FILE_INDEX(Entry) \
|
|
(((ULONG)(Entry) >> 8) & MAX_PAGING_FILE_MASK)
|
|
#define ALPHA_PAGE_FILE_OFFSET(Entry) \
|
|
((ULONG64)((Entry) >> 12) << ALPHA_PAGE_SHIFT)
|
|
|
|
HRESULT
|
|
Axp32MachineInfo::GetVirtualTranslationPhysicalOffsets(ULONG64 Virt,
|
|
PULONG64 Offsets,
|
|
ULONG OffsetsSize,
|
|
PULONG Levels,
|
|
PULONG PfIndex,
|
|
PULONG64 LastVal)
|
|
{
|
|
HRESULT Status;
|
|
|
|
*Levels = 0;
|
|
|
|
if (m_Translating)
|
|
{
|
|
return E_UNEXPECTED;
|
|
}
|
|
m_Translating = TRUE;
|
|
|
|
//
|
|
// Reset the page directory in case it was 0
|
|
//
|
|
if (m_PageDirectories[PAGE_DIR_SINGLE] == 0)
|
|
{
|
|
if ((Status = SetDefaultPageDirectories(1 << PAGE_DIR_SINGLE)) != S_OK)
|
|
{
|
|
m_Translating = FALSE;
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
KdOut("Axp32VtoP: Virt %s, pagedir %s\n",
|
|
FormatAddr64(Virt),
|
|
FormatAddr64(m_PageDirectories[PAGE_DIR_SINGLE]));
|
|
|
|
(*Levels)++;
|
|
if (Offsets != NULL && OffsetsSize > 0)
|
|
{
|
|
*Offsets++ = m_PageDirectories[PAGE_DIR_SINGLE];
|
|
OffsetsSize--;
|
|
}
|
|
|
|
//
|
|
// Certain ranges of the system are mapped directly.
|
|
//
|
|
|
|
if ((Virt >= EXTEND64(ALPHA_PHYSICAL_START)) &&
|
|
(Virt <= EXTEND64(ALPHA_PHYSICAL_END)))
|
|
{
|
|
*LastVal = Virt - EXTEND64(ALPHA_PHYSICAL_START);
|
|
|
|
KdOut("Axp32VtoP: Direct phys %s\n", FormatAddr64(*LastVal));
|
|
|
|
(*Levels)++;
|
|
if (Offsets != NULL && OffsetsSize > 0)
|
|
{
|
|
*Offsets++ = *LastVal;
|
|
OffsetsSize--;
|
|
}
|
|
|
|
m_Translating = FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
ULONG64 Addr;
|
|
ULONG Entry;
|
|
|
|
Addr = (((ULONG)Virt >> ALPHA_PDE_SHIFT) * sizeof(Entry)) +
|
|
m_PageDirectories[PAGE_DIR_SINGLE];
|
|
|
|
KdOut("Axp32VtoP: PDE %s\n", FormatAddr64(Addr));
|
|
|
|
(*Levels)++;
|
|
if (Offsets != NULL && OffsetsSize > 0)
|
|
{
|
|
*Offsets++ = Addr;
|
|
OffsetsSize--;
|
|
}
|
|
|
|
if ((Status = g_Target->
|
|
ReadAllPhysical(Addr, &Entry, sizeof(Entry))) != S_OK)
|
|
{
|
|
KdOut("Axp32VtoP: PDE read error 0x%X\n", Status);
|
|
m_Translating = FALSE;
|
|
return Status;
|
|
}
|
|
|
|
if (Entry == 0)
|
|
{
|
|
KdOut("Axp32VtoP: zero PDE\n");
|
|
m_Translating = FALSE;
|
|
return HR_PAGE_NOT_AVAILABLE;
|
|
}
|
|
else if (!(Entry & 1))
|
|
{
|
|
Addr = ((((ULONG)Virt >> ALPHA_PTE_SHIFT) & ALPHA_PTE_MASK) *
|
|
sizeof(Entry)) + ALPHA_PAGE_FILE_OFFSET(Entry);
|
|
|
|
KdOut("Axp32VtoP: pagefile PTE %d:%s\n",
|
|
ALPHA_PAGE_FILE_INDEX(Entry), FormatAddr64(Addr));
|
|
|
|
if ((Status = g_Target->
|
|
ReadPageFile(ALPHA_PAGE_FILE_INDEX(Entry), Addr,
|
|
&Entry, sizeof(Entry))) != S_OK)
|
|
{
|
|
KdOut("Axp32VtoP: PDE not present, 0x%X\n", Status);
|
|
m_Translating = FALSE;
|
|
return Status;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Addr = ((((ULONG)Virt >> ALPHA_PTE_SHIFT) & ALPHA_PTE_MASK) *
|
|
sizeof(Entry)) +
|
|
((Entry >> ALPHA_VALID_PFN_SHIFT) << ALPHA_PAGE_SHIFT);
|
|
|
|
KdOut("Axp32VtoP: PTE %s\n", FormatAddr64(Addr));
|
|
|
|
(*Levels)++;
|
|
if (Offsets != NULL && OffsetsSize > 0)
|
|
{
|
|
*Offsets++ = Addr;
|
|
OffsetsSize--;
|
|
}
|
|
|
|
if ((Status = g_Target->
|
|
ReadAllPhysical(Addr, &Entry, sizeof(Entry))) != S_OK)
|
|
{
|
|
KdOut("Axp32VtoP: PTE read error 0x%X\n", Status);
|
|
m_Translating = FALSE;
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
if (!(Entry & 0x1) &&
|
|
((Entry & ALPHA_MM_PTE_PROTOTYPE_MASK) ||
|
|
!(Entry & ALPHA_MM_PTE_TRANSITION_MASK)))
|
|
{
|
|
if (Entry == 0)
|
|
{
|
|
KdOut("Axp32VtoP: zero PTE\n");
|
|
Status = HR_PAGE_NOT_AVAILABLE;
|
|
}
|
|
else if (Entry & ALPHA_MM_PTE_PROTOTYPE_MASK)
|
|
{
|
|
KdOut("Axp32VtoP: prototype PTE\n");
|
|
Status = HR_PAGE_NOT_AVAILABLE;
|
|
}
|
|
else
|
|
{
|
|
*PfIndex = ALPHA_PAGE_FILE_INDEX(Entry);
|
|
*LastVal = (Virt & (ALPHA_PAGE_SIZE - 1)) +
|
|
ALPHA_PAGE_FILE_OFFSET(Entry);
|
|
KdOut("Axp32VtoP: PTE not present, pagefile %d:%s\n",
|
|
*PfIndex, FormatAddr64(*LastVal));
|
|
Status = HR_PAGE_IN_PAGE_FILE;
|
|
}
|
|
m_Translating = FALSE;
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// This is a page which is either present or in transition.
|
|
// Return the physical address for the request virtual address.
|
|
//
|
|
|
|
*LastVal = ((Entry >> ALPHA_VALID_PFN_SHIFT) << ALPHA_PAGE_SHIFT) |
|
|
(Virt & (ALPHA_PAGE_SIZE - 1));
|
|
|
|
KdOut("Axp32VtoP: Mapped phys %s\n", FormatAddr64(*LastVal));
|
|
|
|
(*Levels)++;
|
|
if (Offsets != NULL && OffsetsSize > 0)
|
|
{
|
|
*Offsets++ = *LastVal;
|
|
OffsetsSize--;
|
|
}
|
|
|
|
m_Translating = FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
Axp32MachineInfo::GetBaseTranslationVirtualOffset(PULONG64 Offset)
|
|
{
|
|
*Offset = EXTEND64(ALPHA_BASE_VIRT);
|
|
return S_OK;
|
|
}
|
|
|
|
void
|
|
Axp32MachineInfo::OutputFunctionEntry(PVOID RawEntry)
|
|
{
|
|
// Assume Alpha function entries are always kept as
|
|
// 64-bit entries. That's what imagehlp does right now.
|
|
OutputFunctionEntry64((PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY)RawEntry);
|
|
}
|
|
|
|
HRESULT
|
|
Axp32MachineInfo::ReadDynamicFunctionTable(ULONG64 Table,
|
|
PULONG64 NextTable,
|
|
PULONG64 MinAddress,
|
|
PULONG64 MaxAddress,
|
|
PULONG64 BaseAddress,
|
|
PULONG64 TableData,
|
|
PULONG TableSize,
|
|
PWSTR OutOfProcessDll,
|
|
PCROSS_PLATFORM_DYNAMIC_FUNCTION_TABLE RawTable)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = g_Target->
|
|
ReadAllVirtual(Table, &RawTable->AlphaTable,
|
|
sizeof(RawTable->AlphaTable))) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
*NextTable = EXTEND64(RawTable->AlphaTable.Links.Flink);
|
|
*MinAddress = EXTEND64(RawTable->AlphaTable.MinimumAddress);
|
|
*MaxAddress = EXTEND64(RawTable->AlphaTable.MaximumAddress);
|
|
*BaseAddress = EXTEND64(RawTable->AlphaTable.MinimumAddress);
|
|
*TableData = EXTEND64(RawTable->AlphaTable.FunctionTable);
|
|
*TableSize = RawTable->AlphaTable.EntryCount *
|
|
sizeof(IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY);
|
|
OutOfProcessDll[0] = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
PVOID
|
|
Axp32MachineInfo::FindDynamicFunctionEntry(PCROSS_PLATFORM_DYNAMIC_FUNCTION_TABLE Table,
|
|
ULONG64 Address,
|
|
PVOID TableData,
|
|
ULONG TableSize)
|
|
{
|
|
ULONG i;
|
|
PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY Func;
|
|
// Always return AXP64 function entries.
|
|
static IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY s_RetFunc;
|
|
|
|
Func = (PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY)TableData;
|
|
for (i = 0; i < TableSize / sizeof(IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY); i++)
|
|
{
|
|
if (Address >= ALPHA_RF_BEGIN_ADDRESS(Func) &&
|
|
Address < ALPHA_RF_END_ADDRESS(Func))
|
|
{
|
|
// The table data is temporary so copy the data into
|
|
// a static buffer for longer-term storage.
|
|
s_RetFunc.BeginAddress = EXTEND64(Func->BeginAddress);
|
|
s_RetFunc.EndAddress = EXTEND64(Func->EndAddress);
|
|
s_RetFunc.ExceptionHandler = EXTEND64(Func->ExceptionHandler);
|
|
s_RetFunc.HandlerData = EXTEND64(Func->HandlerData);
|
|
s_RetFunc.PrologEndAddress = EXTEND64(Func->PrologEndAddress);
|
|
return (PVOID)&s_RetFunc;
|
|
}
|
|
|
|
Func++;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
HRESULT
|
|
Axp64MachineInfo::InitializeConstants(void)
|
|
{
|
|
m_FullName = "Alpha 64-bit";
|
|
m_AbbrevName = "axp64";
|
|
m_PageSize = AXP64_PAGE_SIZE;
|
|
m_PageShift = AXP64_PAGE_SHIFT;
|
|
m_NumExecTypes = 1;
|
|
m_ExecTypes = g_Axp64ExecTypes;
|
|
m_Ptr64 = TRUE;
|
|
|
|
return AlphaMachineInfo::InitializeConstants();
|
|
}
|
|
|
|
HRESULT
|
|
Axp64MachineInfo::InitializeForTarget(void)
|
|
{
|
|
m_OffsetPrcbProcessorState =
|
|
FIELD_OFFSET(AXP64_PARTIAL_KPRCB, ProcessorState);
|
|
m_OffsetPrcbNumber =
|
|
FIELD_OFFSET(AXP64_PARTIAL_KPRCB, Number);
|
|
m_TriagePrcbOffset = AXP64_TRIAGE_PRCB_ADDRESS;
|
|
m_SizePrcb = AXP64_KPRCB_SIZE;
|
|
m_OffsetKThreadApcProcess =
|
|
FIELD_OFFSET(CROSS_PLATFORM_THREAD, Axp64Thread.ApcState.Process);
|
|
m_OffsetKThreadTeb =
|
|
FIELD_OFFSET(CROSS_PLATFORM_THREAD, Axp64Thread.Teb);
|
|
m_OffsetKThreadInitialStack =
|
|
FIELD_OFFSET(CROSS_PLATFORM_THREAD, Axp64Thread.InitialStack);
|
|
m_OffsetEprocessPeb = AXP64_PEB_IN_EPROCESS;
|
|
m_OffsetEprocessDirectoryTableBase =
|
|
AXP64_DIRECTORY_TABLE_BASE_IN_EPROCESS;
|
|
m_SizeEThread = AXP64_ETHREAD_SIZE;
|
|
m_SizeEProcess = AXP64_EPROCESS_SIZE;
|
|
m_SizePartialKThread = sizeof(AXP64_THREAD);
|
|
m_SharedUserDataOffset = IS_KERNEL_TARGET() ?
|
|
AXP64_KI_USER_SHARED_DATA : MM_SHARED_USER_DATA_VA;
|
|
|
|
return MachineInfo::InitializeForTarget();
|
|
}
|
|
|
|
HRESULT
|
|
Axp64MachineInfo::GetContextFromThreadStack(ULONG64 ThreadBase,
|
|
PCROSS_PLATFORM_THREAD Thread,
|
|
PCROSS_PLATFORM_CONTEXT Context,
|
|
PDEBUG_STACK_FRAME Frame,
|
|
PULONG RunningOnProc)
|
|
{
|
|
if (Thread->Axp64Thread.State == 2)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT Status;
|
|
ALPHA_KEXCEPTION_FRAME ExFrame;
|
|
|
|
if ((Status = g_Target->ReadAllVirtual(Thread->Axp64Thread.KernelStack,
|
|
&ExFrame, sizeof(ExFrame))) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Successfully read an exception frame from the stack.
|
|
//
|
|
|
|
Context->AlphaNt5Context.IntSp =
|
|
Thread->Axp64Thread.KernelStack;
|
|
Context->AlphaNt5Context.Fir = ExFrame.SwapReturn;
|
|
Context->AlphaNt5Context.IntRa = ExFrame.SwapReturn;
|
|
Context->AlphaNt5Context.IntS0 = ExFrame.IntS0;
|
|
Context->AlphaNt5Context.IntS1 = ExFrame.IntS1;
|
|
Context->AlphaNt5Context.IntS2 = ExFrame.IntS2;
|
|
Context->AlphaNt5Context.IntS3 = ExFrame.IntS3;
|
|
Context->AlphaNt5Context.IntS4 = ExFrame.IntS4;
|
|
Context->AlphaNt5Context.IntS5 = ExFrame.IntS5;
|
|
Context->AlphaNt5Context.Psr = ExFrame.Psr;
|
|
|
|
Frame->FrameOffset = Context->AlphaNt5Context.IntSp;
|
|
Frame->StackOffset = Context->AlphaNt5Context.IntSp;
|
|
Frame->InstructionOffset = ExFrame.SwapReturn;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
VOID
|
|
Axp64MachineInfo::GetPC (
|
|
PADDR Address
|
|
)
|
|
{
|
|
ADDRFLAT(Address, GetReg64(ALPHA_FIR));
|
|
}
|
|
|
|
VOID
|
|
Axp64MachineInfo::SetPC (
|
|
PADDR paddr
|
|
)
|
|
{
|
|
SetReg64(ALPHA_FIR, Flat(*paddr));
|
|
}
|
|
|
|
VOID
|
|
Axp64MachineInfo::GetFP (
|
|
PADDR Address
|
|
)
|
|
{
|
|
ADDRFLAT(Address, GetReg64(FP_REG));
|
|
}
|
|
|
|
void
|
|
Axp64MachineInfo::GetSP(PADDR Address)
|
|
{
|
|
ADDRFLAT(Address, GetReg64(SP_REG));
|
|
}
|
|
|
|
ULONG64
|
|
Axp64MachineInfo::GetArgReg(void)
|
|
{
|
|
return GetReg64(ALPHA_INT64_BASE + A0_REG);
|
|
}
|
|
|
|
HRESULT
|
|
Axp64MachineInfo::SetPageDirectory(ULONG Idx, ULONG64 PageDir,
|
|
PULONG NextIdx)
|
|
{
|
|
if (PageDir == 0)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = g_Target->ReadImplicitProcessInfoPointer
|
|
(m_OffsetEprocessDirectoryTableBase, &PageDir)) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
// DirectoryTableBase values on Alpha are the raw PTE entries
|
|
// so turn it into a clean physical address.
|
|
PageDir = (PageDir >> AXP64_VALID_PFN_SHIFT) <<
|
|
AXP64_PAGE_SHIFT;
|
|
|
|
// There is only one page directory so update all the slots.
|
|
m_PageDirectories[PAGE_DIR_USER] = PageDir;
|
|
m_PageDirectories[PAGE_DIR_SESSION] = PageDir;
|
|
m_PageDirectories[PAGE_DIR_KERNEL] = PageDir;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
#define AXP64_PAGE_FILE_INDEX(Entry) \
|
|
(((ULONG)(Entry) >> 28) & MAX_PAGING_FILE_MASK)
|
|
#define AXP64_PAGE_FILE_OFFSET(Entry) \
|
|
(((Entry) >> 32) << AXP64_PAGE_SHIFT)
|
|
|
|
HRESULT
|
|
Axp64MachineInfo::GetVirtualTranslationPhysicalOffsets(ULONG64 Virt,
|
|
PULONG64 Offsets,
|
|
ULONG OffsetsSize,
|
|
PULONG Levels,
|
|
PULONG PfIndex,
|
|
PULONG64 LastVal)
|
|
{
|
|
HRESULT Status;
|
|
|
|
*Levels = 0;
|
|
|
|
if (m_Translating)
|
|
{
|
|
return E_UNEXPECTED;
|
|
}
|
|
m_Translating = TRUE;
|
|
|
|
//
|
|
// Reset the page directory in case it was 0
|
|
//
|
|
if (m_PageDirectories[PAGE_DIR_SINGLE] == 0)
|
|
{
|
|
if ((Status = SetDefaultPageDirectories(1 << PAGE_DIR_SINGLE)) != S_OK)
|
|
{
|
|
m_Translating = FALSE;
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
KdOut("Axp64VtoP: Virt %s, pagedir %s\n",
|
|
FormatAddr64(Virt),
|
|
FormatAddr64(m_PageDirectories[PAGE_DIR_SINGLE]));
|
|
|
|
(*Levels)++;
|
|
if (Offsets != NULL && OffsetsSize > 0)
|
|
{
|
|
*Offsets++ = m_PageDirectories[PAGE_DIR_SINGLE];
|
|
OffsetsSize--;
|
|
}
|
|
|
|
//
|
|
// Certain ranges of the system are mapped directly.
|
|
//
|
|
|
|
if ((Virt >= AXP64_PHYSICAL1_START) && (Virt <= AXP64_PHYSICAL1_END))
|
|
{
|
|
*LastVal = Virt - AXP64_PHYSICAL1_START;
|
|
|
|
KdOut("Axp64VtoP: Direct phys 1 %s\n", FormatAddr64(*LastVal));
|
|
|
|
(*Levels)++;
|
|
if (Offsets != NULL && OffsetsSize > 0)
|
|
{
|
|
*Offsets++ = *LastVal;
|
|
OffsetsSize--;
|
|
}
|
|
|
|
m_Translating = FALSE;
|
|
return S_OK;
|
|
}
|
|
if ((Virt >= AXP64_PHYSICAL2_START) && (Virt <= AXP64_PHYSICAL2_END))
|
|
{
|
|
*LastVal = Virt - AXP64_PHYSICAL2_START;
|
|
|
|
KdOut("Axp64VtoP: Direct phys 2 %s\n", FormatAddr64(*LastVal));
|
|
|
|
(*Levels)++;
|
|
if (Offsets != NULL && OffsetsSize > 0)
|
|
{
|
|
*Offsets++ = *LastVal;
|
|
OffsetsSize--;
|
|
}
|
|
|
|
m_Translating = FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
ULONG64 Addr;
|
|
ULONG64 Entry;
|
|
|
|
Addr = (((Virt >> AXP64_PDE1_SHIFT) & AXP64_PDE_MASK) * sizeof(Entry)) +
|
|
m_PageDirectories[PAGE_DIR_SINGLE];
|
|
|
|
KdOut("Axp64VtoP: PDE1 %s\n", FormatAddr64(Addr));
|
|
|
|
(*Levels)++;
|
|
if (Offsets != NULL && OffsetsSize > 0)
|
|
{
|
|
*Offsets++ = Addr;
|
|
OffsetsSize--;
|
|
}
|
|
|
|
if ((Status = g_Target->
|
|
ReadAllPhysical(Addr, &Entry, sizeof(Entry))) != S_OK)
|
|
{
|
|
KdOut("Axp64VtoP: PDE1 read error 0x%X\n", Status);
|
|
m_Translating = FALSE;
|
|
return Status;
|
|
}
|
|
|
|
if (Entry == 0)
|
|
{
|
|
KdOut("Axp64VtoP: zero PDE1\n");
|
|
m_Translating = FALSE;
|
|
return HR_PAGE_NOT_AVAILABLE;
|
|
}
|
|
else if (!(Entry & 1))
|
|
{
|
|
Addr = (((Virt >> AXP64_PDE2_SHIFT) & AXP64_PDE_MASK) *
|
|
sizeof(Entry)) + AXP64_PAGE_FILE_OFFSET(Entry);
|
|
|
|
KdOut("Axp64VtoP: pagefile PDE2 %d:%s\n",
|
|
AXP64_PAGE_FILE_INDEX(Entry), FormatAddr64(Addr));
|
|
|
|
if ((Status = g_Target->
|
|
ReadPageFile(AXP64_PAGE_FILE_INDEX(Entry), Addr,
|
|
&Entry, sizeof(Entry))) != S_OK)
|
|
{
|
|
KdOut("Axp64VtoP: PDE1 not present, 0x%X\n", Status);
|
|
m_Translating = FALSE;
|
|
return Status;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Addr = (((Virt >> AXP64_PDE2_SHIFT) & AXP64_PDE_MASK) *
|
|
sizeof(Entry)) +
|
|
((Entry >> AXP64_VALID_PFN_SHIFT) << AXP64_PAGE_SHIFT);
|
|
|
|
KdOut("Axp64VtoP: PDE2 %s\n", FormatAddr64(Addr));
|
|
|
|
(*Levels)++;
|
|
if (Offsets != NULL && OffsetsSize > 0)
|
|
{
|
|
*Offsets++ = Addr;
|
|
OffsetsSize--;
|
|
}
|
|
|
|
if ((Status = g_Target->
|
|
ReadAllPhysical(Addr, &Entry, sizeof(Entry))) != S_OK)
|
|
{
|
|
KdOut("Axp64VtoP: PDE2 read error 0x%X\n", Status);
|
|
m_Translating = FALSE;
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
if (Entry == 0)
|
|
{
|
|
KdOut("Axp64VtoP: zero PDE2\n");
|
|
m_Translating = FALSE;
|
|
return HR_PAGE_NOT_AVAILABLE;
|
|
}
|
|
else if (!(Entry & 1))
|
|
{
|
|
Addr = (((Virt >> AXP64_PTE_SHIFT) & AXP64_PTE_MASK) *
|
|
sizeof(Entry)) + AXP64_PAGE_FILE_OFFSET(Entry);
|
|
|
|
KdOut("Axp64VtoP: pagefile PTE %d:%s\n",
|
|
AXP64_PAGE_FILE_INDEX(Entry), FormatAddr64(Addr));
|
|
|
|
if ((Status = g_Target->
|
|
ReadPageFile(AXP64_PAGE_FILE_INDEX(Entry), Addr,
|
|
&Entry, sizeof(Entry))) != S_OK)
|
|
{
|
|
KdOut("Axp64VtoP: PDE2 not present, 0x%X\n", Status);
|
|
m_Translating = FALSE;
|
|
return Status;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Addr = (((Virt >> AXP64_PTE_SHIFT) & AXP64_PTE_MASK) * sizeof(Entry)) +
|
|
((Entry >> AXP64_VALID_PFN_SHIFT) << AXP64_PAGE_SHIFT);
|
|
|
|
KdOut("Axp64VtoP: PTE %s\n", FormatAddr64(Addr));
|
|
|
|
(*Levels)++;
|
|
if (Offsets != NULL && OffsetsSize > 0)
|
|
{
|
|
*Offsets++ = Addr;
|
|
OffsetsSize--;
|
|
}
|
|
|
|
if ((Status = g_Target->
|
|
ReadAllPhysical(Addr, &Entry, sizeof(Entry))) != S_OK)
|
|
{
|
|
KdOut("Axp64VtoP: PTE read error 0x%X\n", Status);
|
|
m_Translating = FALSE;
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
if (!(Entry & 0x1) &&
|
|
((Entry & AXP64_MM_PTE_PROTOTYPE_MASK) ||
|
|
!(Entry & AXP64_MM_PTE_TRANSITION_MASK)))
|
|
{
|
|
if (Entry == 0)
|
|
{
|
|
KdOut("Axp64VtoP: zero PTE\n");
|
|
Status = HR_PAGE_NOT_AVAILABLE;
|
|
}
|
|
else if (Entry & AXP64_MM_PTE_PROTOTYPE_MASK)
|
|
{
|
|
KdOut("Axp64VtoP: prototype PTE\n");
|
|
Status = HR_PAGE_NOT_AVAILABLE;
|
|
}
|
|
else
|
|
{
|
|
*PfIndex = AXP64_PAGE_FILE_INDEX(Entry);
|
|
*LastVal = (Virt & (AXP64_PAGE_SIZE - 1)) +
|
|
AXP64_PAGE_FILE_OFFSET(Entry);
|
|
KdOut("Axp64VtoP: PTE not present, pagefile %d:%s\n",
|
|
*PfIndex, FormatAddr64(*LastVal));
|
|
Status = HR_PAGE_IN_PAGE_FILE;
|
|
}
|
|
m_Translating = FALSE;
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// This is a page which is either present or in transition.
|
|
// Return the physical address for the request virtual address.
|
|
//
|
|
|
|
*LastVal = ((Entry >> AXP64_VALID_PFN_SHIFT) << AXP64_PAGE_SHIFT) |
|
|
(Virt & (AXP64_PAGE_SIZE - 1));
|
|
|
|
KdOut("Axp64VtoP: Mapped phys %s\n", FormatAddr64(*LastVal));
|
|
|
|
(*Levels)++;
|
|
if (Offsets != NULL && OffsetsSize > 0)
|
|
{
|
|
*Offsets++ = *LastVal;
|
|
OffsetsSize--;
|
|
}
|
|
|
|
m_Translating = FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
Axp64MachineInfo::GetBaseTranslationVirtualOffset(PULONG64 Offset)
|
|
{
|
|
*Offset = AXP64_BASE_VIRT;
|
|
return S_OK;
|
|
}
|
|
|
|
void
|
|
Axp64MachineInfo::OutputFunctionEntry(PVOID RawEntry)
|
|
{
|
|
OutputFunctionEntry64((PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY)RawEntry);
|
|
}
|
|
|
|
HRESULT
|
|
Axp64MachineInfo::ReadDynamicFunctionTable(ULONG64 Table,
|
|
PULONG64 NextTable,
|
|
PULONG64 MinAddress,
|
|
PULONG64 MaxAddress,
|
|
PULONG64 BaseAddress,
|
|
PULONG64 TableData,
|
|
PULONG TableSize,
|
|
PWSTR OutOfProcessDll,
|
|
PCROSS_PLATFORM_DYNAMIC_FUNCTION_TABLE RawTable)
|
|
{
|
|
HRESULT Status;
|
|
|
|
if ((Status = g_Target->
|
|
ReadAllVirtual(Table, &RawTable->Axp64Table,
|
|
sizeof(RawTable->Axp64Table))) != S_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
*NextTable = RawTable->Axp64Table.Links.Flink;
|
|
*MinAddress = RawTable->Axp64Table.MinimumAddress;
|
|
*MaxAddress = RawTable->Axp64Table.MaximumAddress;
|
|
*BaseAddress = RawTable->Axp64Table.MinimumAddress;
|
|
*TableData = RawTable->Axp64Table.FunctionTable;
|
|
*TableSize = RawTable->Axp64Table.EntryCount *
|
|
sizeof(IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY);
|
|
OutOfProcessDll[0] = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
PVOID
|
|
Axp64MachineInfo::FindDynamicFunctionEntry(PCROSS_PLATFORM_DYNAMIC_FUNCTION_TABLE Table,
|
|
ULONG64 Address,
|
|
PVOID TableData,
|
|
ULONG TableSize)
|
|
{
|
|
ULONG i;
|
|
PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY Func;
|
|
static IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY s_RetFunc;
|
|
|
|
Func = (PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY)TableData;
|
|
for (i = 0; i < TableSize / sizeof(IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY); i++)
|
|
{
|
|
if (Address >= ALPHA_RF_BEGIN_ADDRESS(Func) &&
|
|
Address < ALPHA_RF_END_ADDRESS(Func))
|
|
{
|
|
// The table data is temporary so copy the data into
|
|
// a static buffer for longer-term storage.
|
|
s_RetFunc.BeginAddress = Func->BeginAddress;
|
|
s_RetFunc.EndAddress = Func->EndAddress;
|
|
s_RetFunc.ExceptionHandler = Func->ExceptionHandler;
|
|
s_RetFunc.HandlerData = Func->HandlerData;
|
|
s_RetFunc.PrologEndAddress = Func->PrologEndAddress;
|
|
return (PVOID)&s_RetFunc;
|
|
}
|
|
|
|
Func++;
|
|
}
|
|
|
|
return NULL;
|
|
}
|