|
|
/*++
Copyright (c) 1995-1999 Microsoft Corporation
Module Name:
entrypt.c
Abstract: Debugger extensions that give an entry point from either an intel address or a native address Author:
02-Aug-1995 Ori Gershony (t-orig)
Revision History:
--*/
#define _WOW64CPUDBGAPI_
#define DECLARE_CPU_DEBUGGER_INTERFACE
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <imagehlp.h>
#include <ntsdexts.h>
#include "ntosdef.h"
#include "v86emul.h"
#include "ia64.h"
#include "wow64.h"
#include "wow64cpu.h"
#include "threadst.h"
#include "entrypt.h"
extern HANDLE Process; extern HANDLE Thread; extern PNTSD_OUTPUT_ROUTINE OutputRoutine; extern PNTSD_GET_SYMBOL GetSymbolRoutine; extern PNTSD_GET_EXPRESSION GetExpression; extern PWOW64GETCPUDATA CpuGetData; extern LPSTR ArgumentString;
#define DEBUGGERPRINT (*OutputRoutine)
#define GETSYMBOL (*GetSymbolRoutine)
#define GETEXPRESSION (*GetExpression)
#define CPUGETDATA (*CpuGetData)
extern THREADSTATE LocalCpuContext; extern BOOL ContextFetched; extern BOOL ContextDirty;
#define DECLARE_EXTAPI(name) \
VOID \ name( \ HANDLE hCurrentProcess, \ HANDLE hCurrentThread, \ DWORD64 dwCurrentPc, \ PNTSD_EXTENSION_APIS lpExtensionApis, \ LPSTR lpArgumentString \ )
#define INIT_EXTAPI \
Process = hCurrentProcess; \ Thread = hCurrentThread; \ OutputRoutine = lpExtensionApis->lpOutputRoutine; \ GetSymbolRoutine = lpExtensionApis->lpGetSymbolRoutine; \ GetExpression = lpExtensionApis->lpGetExpressionRoutine; \ ArgumentString = lpArgumentString;
#if _ALPHA_
#define EXCEPTIONDATA_SIGNATURE 0x01010101
#else
#define EXCEPTIONDATA_SIGNATURE 0x12341234
#endif
// Assume we can have at most 1/2 million entrypoints in a tree:
// With 4MB Translation Cache, we can have 1 million RISC instructions
// in the cache. Assume each Intel instruction requires 2 RISC instructions,
// and that each Intel instruction has its own Entrypoint. In that case,
// there can be at most 1/2 million entrypoints. Realistically, that number
// should be much smaller (like 50,000).
//
// Also, since the Entrypoint tree is balanced (a property of Red-Black trees),
// the required stack depth should be log2(500,000).
//
#define MAX_EPN_STACK_DEPTH 512*1024
ULONG_PTR EPN_Stack[MAX_EPN_STACK_DEPTH]; ULONG EPN_StackTop; ULONG EPN_MaxStackDepth;
#define EPN_STACK_RESET() EPN_StackTop=0; EPN_MaxStackDepth=0
#define EPN_PUSH(x) { \
if (EPN_StackTop == MAX_EPN_STACK_DEPTH-1) { \ DEBUGGERPRINT("Error: EPN stack overflow\n"); \ goto Error; \ } else { \ EPN_Stack[EPN_StackTop] = x; \ EPN_StackTop++; \ if (EPN_StackTop > EPN_MaxStackDepth) EPN_MaxStackDepth=EPN_StackTop; \ } \ }
#define EPN_POP(x) { \
if (EPN_StackTop == 0) { \ DEBUGGERPRINT("Error: EPN stack underflow\n"); \ goto Error; \ } else { \ EPN_StackTop--; \ x = EPN_Stack[EPN_StackTop]; \ } \ }
NTSTATUS TryGetExpr( PSTR Expression, PULONG_PTR pValue );
VOID findEPI( ULONG_PTR intelAddress, ULONG_PTR intelRoot ) /*++
Routine Description:
This routine finds an entry point which contains intelAddress if in the tree under intelRoot.
Arguments:
intelAddress -- The intel address to be contained in the entry point intelRoot -- The root of the tree to use for the search
Return Value:
return-value - none
--*/ { EPNODE entrypoint; NTSTATUS Status;
for (;;) { Status = NtReadVirtualMemory(Process, (PVOID)intelRoot, (PVOID) (&entrypoint), sizeof(EPNODE), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Error: cannot read value of entry point at location %x\n", intelRoot); return; }
if (intelRoot == (ULONG_PTR)entrypoint.intelLeft) { //
// At a NIL node.
//
break; }
if (intelAddress < (ULONG_PTR)entrypoint.ep.intelStart){ intelRoot = (ULONG_PTR)entrypoint.intelLeft; } else if (intelAddress > (ULONG_PTR)entrypoint.ep.intelEnd) { intelRoot = (ULONG_PTR)entrypoint.intelRight; } else { DEBUGGERPRINT ("Entry point for intel address %x is at %x\n", intelAddress, intelRoot); DEBUGGERPRINT ("intelStart = %x, intelEnd = %x\n", entrypoint.ep.intelStart, entrypoint.ep.intelEnd); DEBUGGERPRINT ("nativeStart = %x, nativeEnd = %x\n", entrypoint.ep.nativeStart, entrypoint.ep.nativeEnd); return; } }
DEBUGGERPRINT("Entry point corresponding to intel address %x is not in the tree.\n", intelAddress); }
DECLARE_EXTAPI(epi) /*++
Routine Description:
This routine dumps the entry point information for an intel address
Arguments:
Return Value:
return-value - none
--*/ { CHAR *pchCmd; ULONG_PTR intelAddress, pIntelRoot, intelRoot; NTSTATUS Status;
INIT_EXTAPI;
//
// fetch the CpuContext for the current thread
//
if (!CpuDbgGetRemoteContext(CPUGETDATA(Process, Thread))) { return; }
DEBUGGERPRINT ("Argument: %s\n", ArgumentString); //
// advance to first token
//
pchCmd = ArgumentString; while (*pchCmd && isspace(*pchCmd)) { pchCmd++; }
//
// if exists must be intel address
//
if (*pchCmd) { Status = TryGetExpr(pchCmd, &intelAddress); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Invalid Intel Address '%s' Status %x\n", pchCmd, Status); return; } } else { // Take the current eip value as the first argument
intelAddress = LocalCpuContext.eipReg.i4; }
Status = TryGetExpr("intelRoot", &pIntelRoot); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Error: cannot evaluate intelRoot\n"); return; }
Status = NtReadVirtualMemory(Process, (PVOID)pIntelRoot, (PVOID) (&intelRoot), sizeof(intelRoot), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Error: cannot read value of intelRoot\n"); return; }
findEPI(intelAddress, intelRoot); }
ULONG_PTR findEPN( ULONG_PTR nativeAddress, ULONG_PTR intelRoot ) /*++
Routine Description:
This routine finds an entry point which contains nativeAddress if in the tree under intelRoot.
Arguments:
nativeAddress -- The native address to be contained in the entry point intelRoot -- The root of the tree to use for the search
Return Value:
return-value - NULL - entrypoint not found non-NULL - ptr to ENTRYPOINT matching the native address
--*/ { EPNODE entrypoint; NTSTATUS Status; PVOID SubEP;
EPN_STACK_RESET();
EPN_PUSH(0);
while (intelRoot != 0) {
Status = NtReadVirtualMemory(Process, (PVOID)intelRoot, (PVOID) (&entrypoint), sizeof(EPNODE), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Error: cannot read value of entry point at location %x\n", intelRoot); return 0; }
if ((nativeAddress >= (ULONG_PTR)entrypoint.ep.nativeStart) && (nativeAddress <= (ULONG_PTR)entrypoint.ep.nativeEnd)) {
DEBUGGERPRINT ("Entry point for native address %x is at %x\n", nativeAddress, intelRoot); DEBUGGERPRINT ("intelStart = %x, intelEnd = %x\n", entrypoint.ep.intelStart, entrypoint.ep.intelEnd); DEBUGGERPRINT ("nativeStart = %x, nativeEnd = %x\n", entrypoint.ep.nativeStart, entrypoint.ep.nativeEnd); return intelRoot; }
// If there are sub-entrypoints, search them, too.
SubEP = (PVOID)entrypoint.ep.SubEP; while (SubEP) { ENTRYPOINT ep;
Status = NtReadVirtualMemory(Process, SubEP, (PVOID)(&ep), sizeof(ENTRYPOINT), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Error: cannot read value of sub-entry point at location %x\n", SubEP); return 0; }
if ((nativeAddress >= (ULONG_PTR)ep.nativeStart) && (nativeAddress <= (ULONG_PTR)ep.nativeEnd)) { DEBUGGERPRINT ("Entry point for native address %x is at %x\n", nativeAddress, intelRoot); DEBUGGERPRINT ("Sub-entrypoint actually containing the native address is %x\n", SubEP); DEBUGGERPRINT ("intelStart = %x, intelEnd = %x\n", ep.intelStart, ep.intelEnd); DEBUGGERPRINT ("nativeStart = %x, nativeEnd = %x\n", ep.nativeStart, ep.nativeEnd); return (ULONG_PTR)SubEP; }
SubEP = ep.SubEP; }
if ((ULONG_PTR)entrypoint.intelRight != intelRoot) { EPN_PUSH((ULONG_PTR)entrypoint.intelRight); } if ((ULONG_PTR)entrypoint.intelLeft != intelRoot) { EPN_PUSH((ULONG_PTR)entrypoint.intelLeft); }
EPN_POP(intelRoot); }
DEBUGGERPRINT("Entry point corresponding to native address %x is not in the tree.\n", nativeAddress); Error: return 0; }
VOID FindEipFromNativeAddress( ULONG_PTR nativeAddress, ULONG_PTR pEP ) { ENTRYPOINT EP; NTSTATUS Status; PVOID pUL; ULONG UL; ULONG RiscStart; ULONG RiscEnd; ULONG cEntryPoints;
Status = NtReadVirtualMemory(Process, (PVOID)pEP, (PVOID)(&EP), sizeof(ENTRYPOINT), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Error: cannot read value of entry point at location %x\n", pEP); return; }
//
// Search forward to the next EXCEPTIONDATA_SIGNATURE in the cache
//
pUL = (PVOID)(((ULONG_PTR)EP.nativeEnd+3) & ~3); do { Status = NtReadVirtualMemory(Process, pUL, &UL, sizeof(ULONG), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Error: error reading from TC at %x\n", pUL); return; }
pUL = (PVOID)( (PULONG)pUL + 1); } while (UL != EXCEPTIONDATA_SIGNATURE);
//
// Found the signature, get cEntryPoints
//
Status = NtReadVirtualMemory(Process, pUL, &cEntryPoints, sizeof(ULONG), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Error: error reading from TC at %x\n", pUL); return; } pUL = (PVOID)( (PULONG)pUL + 1); // skip cEntryPoints
while (1) { Status = NtReadVirtualMemory(Process, pUL, &UL, sizeof(ULONG), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Error: error reading from TC at %x\n", pUL); return; }
if (UL == (ULONG)pEP) { //
// Found the right ENTRYPOINT pointer
//
break; }
//
// Skip over the pairs of (x86, risc) offsets
//
do { pUL = (PVOID)( (PULONG)pUL + 1); Status = NtReadVirtualMemory(Process, pUL, &UL, sizeof(ULONG), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Error: error reading from TC at %x\n", pUL); return; } } while ((UL & 1) == 0);
cEntryPoints--; if (cEntryPoints == 0) { DEBUGGERPRINT("Error: cEntryPoints went to 0 at %x\n", pUL); return; }
pUL = (PVOID)( (PULONG)pUL + 1); }
//
// pUL points at the correct entrypoint pointer
//
nativeAddress -= (ULONG_PTR)EP.nativeStart; // Make relative to start of EP
RiscStart = 0; // Also relative to start of EP
while (1) { ULONG UL2;
pUL = (PVOID)( (PULONG)pUL + 1); Status = NtReadVirtualMemory(Process, pUL, &UL, sizeof(ULONG), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Error: error reading from TC at %x\n", pUL); return; } if (UL & 1) { break; }
Status = NtReadVirtualMemory(Process, (PVOID)((PULONG)pUL+1), &UL2, sizeof(ULONG), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Error: error reading from TC at %p\n", (ULONG_PTR)pUL+4); return; } RiscEnd = LOWORD(UL2) & 0xfffe; // RiscEnd = RiscStart of next instr
if ((RiscStart <= nativeAddress && nativeAddress < RiscEnd) || (UL & 1)) { DEBUGGERPRINT("Corresponding EIP=%p\n", (ULONG_PTR)EP.intelStart + HIWORD(UL)); return; } }
return;
}
DECLARE_EXTAPI(epn) /*++
Routine Description:
This routine dumps the entry point information for a native address
Arguments:
Return Value:
return-value - none
--*/ { CHAR *pchCmd; ULONG_PTR nativeAddress, pIntelRoot, intelRoot, EP; NTSTATUS Status;
INIT_EXTAPI;
//
// fetch the CpuContext for the current thread
//
if (!CpuDbgGetRemoteContext(CPUGETDATA(Process, Thread))) { return; }
//
// advance to first token
//
pchCmd = ArgumentString; while (*pchCmd && isspace(*pchCmd)) { pchCmd++; }
//
// if exists must be intel address
//
if (*pchCmd) { Status = TryGetExpr(pchCmd, &nativeAddress); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Invalid Native Address '%s' Status %x\n", pchCmd, Status); return; } } else { // Use the current pc as the host address
CONTEXT context; if (!GetThreadContext(Thread, &context)){ DEBUGGERPRINT("Error: cannot get thread context\n"); return; } #if defined (_MIPS_) || defined (_ALPHA_)
nativeAddress = (ULONG)context.Fir; #elif defined (_PPC_)
nativeAddress = context.Iar; #endif
}
Status = TryGetExpr("intelRoot", &pIntelRoot); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Error: cannot evaluate intelRoot\n"); return; }
Status = NtReadVirtualMemory(Process, (PVOID)pIntelRoot, (PVOID) (&intelRoot), sizeof(ULONG_PTR), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Error: cannot read value of intelRoot\n"); return; }
EP = findEPN(nativeAddress, intelRoot); if (EP) { FindEipFromNativeAddress(nativeAddress, EP); } }
DECLARE_EXTAPI(dumpep) /*++
Routine Description:
This routine dumps all entrypoints.
Arguments:
Return Value:
return-value - none
--*/ { ULONG_PTR pIntelRoot, intelRoot; NTSTATUS Status; EPNODE entrypoint;
INIT_EXTAPI;
//
// fetch the CpuContext for the current thread
//
if (!CpuDbgGetRemoteContext(CPUGETDATA(Process, Thread))) { return; }
Status = TryGetExpr("intelRoot", &pIntelRoot); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Error: cannot evaluate intelRoot\n"); return; }
Status = NtReadVirtualMemory(Process, (PVOID)pIntelRoot, (PVOID) (&intelRoot), sizeof(intelRoot), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Error: cannot read value of intelRoot\n"); return; }
EPN_STACK_RESET();
EPN_PUSH(0);
DEBUGGERPRINT("Entrypt: iStart: iEnd: rStart: rEnd: SubEP: iLeft: iRight:\n"); // xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
while (intelRoot != 0) { PENTRYPOINT ep;
Status = NtReadVirtualMemory(Process, (PVOID)intelRoot, (PVOID) (&entrypoint), sizeof(EPNODE), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Error: cannot read value of entry point at location %x\n", intelRoot); return; }
ep = &entrypoint.ep;
//
// Print all entrypoints except NIL.
//
if ((ULONG_PTR)entrypoint.intelLeft != intelRoot && (ULONG_PTR)entrypoint.intelRight != intelRoot) {
DEBUGGERPRINT("%8.8X %8.8X %8.8X %8.8X %8.8X %8.8X %8.8X %8.8X\n", intelRoot, ep->intelStart, ep->intelEnd, ep->nativeStart, ep->nativeEnd, ep->SubEP, entrypoint.intelLeft, entrypoint.intelRight );
while (ep->SubEP) { PVOID SubEP;
SubEP = (PVOID)ep->SubEP; Status = NtReadVirtualMemory(Process, SubEP, (PVOID)ep, sizeof(ENTRYPOINT), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Error: cannot read value of sub-entry point at location %x\n", SubEP); return; }
DEBUGGERPRINT("%8.8X %8.8X %8.8X %8.8X %8.8X %8.8X\n", SubEP, ep->intelStart, ep->intelEnd, ep->nativeStart, ep->nativeEnd, ep->SubEP );
} }
if ((ULONG_PTR)entrypoint.intelRight != intelRoot) { EPN_PUSH((ULONG_PTR)entrypoint.intelRight); } if ((ULONG_PTR)entrypoint.intelLeft != intelRoot) { EPN_PUSH((ULONG_PTR)entrypoint.intelLeft); }
EPN_POP(intelRoot); } DEBUGGERPRINT("---- End of Entrypoint Dump ----\n"); Error: return; }
|