/*** 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;
}