|
|
/*++
Copyright (c) 1999-2000 Microsoft Corporation
Module Name:
w64cpuex.c
Abstract:
Debugger extension DLL for debugging the CPU
Author:
27-Sept-1999 BarryBo
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"
#define MSCPU
#include "threadst.h"
#include "entrypt.h"
#include "config.h"
#include "instr.h"
#include "compiler.h"
#include "cpunotif.h"
#include "cpuregs.h"
/* Masks for bits 0 - 32. */ #define BIT0 0x1
#define BIT1 0x2
#define BIT2 0x4
#define BIT3 0x8
#define BIT4 0x10
#define BIT5 0x20
#define BIT6 0x40
#define BIT7 0x80
#define BIT8 0x100
#define BIT9 0x200
#define BIT10 0x400
#define BIT11 0x800
#define BIT12 0x1000
#define BIT13 0x2000
#define BIT14 0x4000
#define BIT15 0x8000
#define BIT16 0x10000
#define BIT17 0x20000
#define BIT18 0x40000
#define BIT19 0x80000
#define BIT20 0x100000
#define BIT21 0x200000
#define BIT22 0x400000
#define BIT23 0x800000
#define BIT24 0x1000000
#define BIT25 0x2000000
#define BIT26 0x4000000
#define BIT27 0x8000000
#define BIT28 0x10000000
#define BIT29 0x20000000
#define BIT30 0x40000000
#define BIT31 0x80000000
BOOL AutoFlushFlag = TRUE;
HANDLE Process; HANDLE Thread; PNTSD_OUTPUT_ROUTINE OutputRoutine; PNTSD_GET_SYMBOL GetSymbolRoutine; PNTSD_GET_EXPRESSION GetExpression; PWOW64GETCPUDATA CpuGetData; LPSTR ArgumentString;
#define DEBUGGERPRINT (*OutputRoutine)
#define GETSYMBOL (*GetSymbolRoutine)
#define GETEXPRESSION (*GetExpression)
#define CPUGETDATA (*CpuGetData)
// Local copy of the current process/thread's CPU state
PVOID RemoteCpuData; THREADSTATE LocalCpuContext; BOOL ContextFetched; BOOL ContextDirty;
// Cached addresses of interesting symbols within the CPU
HANDLE CachedProcess; ULONG_PTR pCompilerFlags; ULONG_PTR pTranslationCacheFlags; ULONG_PTR pDirtyMemoryAddr; ULONG_PTR pDirtyMemoryLength;
ULONG GetEfl(VOID); VOID SetEfl(ULONG);
//
// Table mapping a byte to a 0 or 1, corresponding to the parity bit for
// that byte.
//
CONST BYTE ParityBit[] = { 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 };
/*
* Does a plain old GetExpression under a try-except */ NTSTATUS TryGetExpr( PSTR Expression, PULONG_PTR pValue ) { NTSTATUS Status = STATUS_SUCCESS;
try { *pValue = GETEXPRESSION(Expression); } except(EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); }
return Status; }
VOID InvalidateSymbolsIfNeeded( VOID ) { if (CachedProcess == Process) { // The symbols match the current process
return; } // else the symbols were for another process. Invalidate the cache.
pCompilerFlags = 0; pTranslationCacheFlags = 0; pDirtyMemoryAddr = 0; pDirtyMemoryLength = 0; CachedProcess = Process; }
DWORD GetCompilerFlags(void) { NTSTATUS Status; DWORD CompilerFlags;
InvalidateSymbolsIfNeeded();
if (!pCompilerFlags) { Status = TryGetExpr("CompilerFlags", (ULONG_PTR *)&pCompilerFlags); if (!NT_SUCCESS(Status) || !pCompilerFlags) { DEBUGGERPRINT("Unable to get address of CompilerFlags Status %x\n", Status ); pCompilerFlags = 0; return 0xffffffff; } }
Status = NtReadVirtualMemory(Process, (PVOID)pCompilerFlags, &CompilerFlags, sizeof(DWORD), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Unable to read CompilerFlags Status %x\n", Status); return 0xffffffff; }
return CompilerFlags; }
void SetCompilerFlags(DWORD CompilerFlags) { NTSTATUS Status;
InvalidateSymbolsIfNeeded();
if (!pCompilerFlags) { Status = TryGetExpr("CompilerFlags", (ULONG_PTR *)&pCompilerFlags); if (!NT_SUCCESS(Status) || !pCompilerFlags) { DEBUGGERPRINT("Unable to get address of CompilerFlags Status %x\n", Status ); pCompilerFlags = 0; return; } }
Status = NtWriteVirtualMemory(Process, (PVOID)pCompilerFlags, &CompilerFlags, sizeof(DWORD), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Unable to writes CompilerFlags Status %x\n", Status); return; } }
NTSTATUS GetDirtyMemoryRange(PULONG DirtyMemoryAddr, PULONG DirtyMemoryLength) { NTSTATUS Status; ULONG DirtyMemoryEnd;
InvalidateSymbolsIfNeeded();
if (pDirtyMemoryLength == 0) { //
// First call to CpuFlushInstructionCache() - need to set up
// the global variables.
//
Status = TryGetExpr("DbgDirtyMemoryAddr", (ULONG_PTR *)&pDirtyMemoryAddr); if (!NT_SUCCESS(Status) || !pDirtyMemoryAddr) { DEBUGGERPRINT("Unable to get address of DbgDirtyMemoryAddr Status %x\n", Status ); return Status; }
Status = TryGetExpr("DbgDirtyMemoryLength", (ULONG_PTR *)&pDirtyMemoryLength); if (!NT_SUCCESS(Status) || !pDirtyMemoryLength) { DEBUGGERPRINT("Unable to get address of DbgDirtyMemoryLength Status %x\n", Status ); return Status; } }
Status = NtReadVirtualMemory(Process, (PVOID)pDirtyMemoryAddr, DirtyMemoryAddr, sizeof(ULONG), NULL ); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Unable to read pDirtyMemoryAddr %x Status %x\n", pDirtyMemoryAddr, Status ); return Status; }
Status = NtReadVirtualMemory(Process, (PVOID)pDirtyMemoryLength, DirtyMemoryLength, sizeof(ULONG), NULL ); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Unable to read pDirtyMemoryLength %x Status %x\n", pDirtyMemoryLength, Status ); pDirtyMemoryLength = 0; return Status; }
return Status; }
void RemindUserToFlushTheCache(void) { NTSTATUS Status; DWORD TranslationCacheFlags; DWORD CompilerFlags; BOOLEAN fCacheFlushPending;
//
// Read the value of TranslationCacheFlags
//
if (!pTranslationCacheFlags) { Status = TryGetExpr("TranslationCacheFlags", (ULONG_PTR *)&pTranslationCacheFlags); if (!NT_SUCCESS(Status) || !pTranslationCacheFlags) { DEBUGGERPRINT("Unable to get address of TranslationCacheFlags Status %x\n", Status ); return; } }
Status = NtReadVirtualMemory(Process, (PVOID)pTranslationCacheFlags, &TranslationCacheFlags, sizeof(TranslationCacheFlags), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("Unable to read TranslationCacheFlags Status %x\n", Status); return; }
//
// Read the value of CompilerFlags
//
CompilerFlags = GetCompilerFlags(); if (CompilerFlags == 0xffffffff) { //
// Got an error getting the CompilerFlags value.
//
return; }
//
// Determine if the Translation Cache is going to be flushed next time
// the CPU runs or not.
//
fCacheFlushPending = (LocalCpuContext.CpuNotify & CPUNOTIFY_MODECHANGE) ? TRUE : FALSE; if (!fCacheFlushPending && (LocalCpuContext.CpuNotify & CPUNOTIFY_DBGFLUSHTC)) { DWORD Addr, Length; Status = GetDirtyMemoryRange(&Addr, &Length); if (!NT_SUCCESS(Status)) { return; } if (Addr == 0 && Length == 0xffffffff) { //
// Cache flush is pending because user asked for !flush
//
fCacheFlushPending = TRUE; } }
//
// Give the user some worldly advice
//
if (LocalCpuContext.CpuNotify & (CPUNOTIFY_TRACEFLAG|CPUNOTIFY_SLOWMODE)) { //
// We need to be in slow mode to get logging to work.
//
if (CompilerFlags & COMPFL_FAST) { //
// Cpu is set to generate fast code. Remedy that.
//
if (AutoFlushFlag) { SetCompilerFlags(COMPFL_SLOW); } else { DEBUGGERPRINT("CPU in fast mode. Use '!wx86e.code SLOW' to switch to slow mode.\n"); } } if (!fCacheFlushPending && (TranslationCacheFlags & COMPFL_FAST)) { //
// Translation Cache contains fast code. Rememdy that.
//
if (AutoFlushFlag) { LocalCpuContext.CpuNotify |= CPUNOTIFY_MODECHANGE; ContextDirty = TRUE; } else { DEBUGGERPRINT("Translation Cache contains fast code. Use '!wx86e.flush' to flush,\n"); DEBUGGERPRINT("or the CPU will probably jump somewhere unexpected.\n"); } }
if (fCacheFlushPending && TranslationCacheFlags == COMPFL_SLOW) { //
// If there is a cache flush pending due to a switch in
// compilation modes, but the code in the cache is already
// correct, undo the cache flush
//
LocalCpuContext.CpuNotify &= ~(ULONG)CPUNOTIFY_MODECHANGE; ContextDirty = TRUE; } } else { //
// We can run in fast mode.
//
if (CompilerFlags & COMPFL_SLOW) { //
// Cpu is set to generate slow code. Remedy that.
//
if (AutoFlushFlag) { SetCompilerFlags(COMPFL_FAST); } else { DEBUGGERPRINT("CPU in slow mode. Use '!wx86e.code FAST' to switch to fast mode.\n"); } } if (!fCacheFlushPending && (TranslationCacheFlags & COMPFL_SLOW)) { //
// Translation Cache contains slow code. Remedy that.
//
if (AutoFlushFlag) { LocalCpuContext.CpuNotify |= CPUNOTIFY_MODECHANGE; ContextDirty = TRUE; } else { DEBUGGERPRINT("Translation Cache contains slow code. Use '!wx86e.flush' to flush.\n"); } }
if (fCacheFlushPending && TranslationCacheFlags == COMPFL_FAST) { //
// If there is a cache flush pending due to a switch in
// compilation modes, but the code in the cache is already
// correct, undo the cache flush
//
LocalCpuContext.CpuNotify &= ~(ULONG)CPUNOTIFY_MODECHANGE; ContextDirty = TRUE; } } }
WOW64CPUDBGAPI VOID CpuDbgInitExtapi( HANDLE hArgProcess, HANDLE hArgThread, DWORD64 ArgCurrentPC, PNTSD_EXTENSION_APIS lpExtensionApis, PWOW64GETCPUDATA lpGetData ) { Process = hArgProcess; Thread = hArgThread; OutputRoutine = lpExtensionApis->lpOutputRoutine; GetSymbolRoutine = lpExtensionApis->lpGetSymbolRoutine; GetExpression = lpExtensionApis->lpGetExpressionRoutine; CpuGetData = lpGetData;
InvalidateSymbolsIfNeeded(); ContextFetched = FALSE; ContextDirty = FALSE; }
WOW64CPUDBGAPI BOOL CpuDbgGetRemoteContext( PVOID CpuData ) { NTSTATUS Status;
Status = NtReadVirtualMemory(Process, CpuData, &LocalCpuContext, sizeof(LocalCpuContext), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("CpuDbgGetRemoteContext: Error %x reading CPU data from %x\n", Status, CpuData); return FALSE; }
ContextFetched = TRUE; RemoteCpuData = CpuData;
return TRUE; }
WOW64CPUDBGAPI BOOL CpuDbgSetRemoteContext( void ) { NTSTATUS Status;
if (!ContextDirty) { // Perf. optimization... don't update the remote context if
// nothing has changed.
return TRUE; }
if (!ContextFetched) { DEBUGGERPRINT("CpuDbgSetRemoteContext: Remote context was never fetched!\n"); return FALSE; }
Status = NtWriteVirtualMemory(Process, RemoteCpuData, &LocalCpuContext, sizeof(LocalCpuContext), NULL); if (!NT_SUCCESS(Status)) { DEBUGGERPRINT("CpuDbgSetRemoteContext: Error %x writing CPU data to %x\n", Status, RemoteCpuData); return FALSE; }
ContextDirty = FALSE;
return TRUE; }
WOW64CPUDBGAPI BOOL CpuDbgGetLocalContext( PCONTEXT32 Context ) { ULONG ContextFlags = Context->ContextFlags; PTHREADSTATE cpu = &LocalCpuContext;
if ((ContextFlags & CONTEXT_CONTROL_WX86) == CONTEXT_CONTROL_WX86) {
Context->EFlags = GetEfl(); Context->SegCs = CS; Context->Esp = esp; Context->SegSs = SS; Context->Ebp = ebp; Context->Eip = eip; //Context->Eip = cpu->eipReg.i4;
}
if ((ContextFlags & CONTEXT_SEGMENTS_WX86) == CONTEXT_SEGMENTS_WX86) { Context->SegGs = GS; Context->SegFs = FS; Context->SegEs = ES; Context->SegDs = DS; }
if ((ContextFlags & CONTEXT_INTEGER_WX86) == CONTEXT_INTEGER_WX86) { Context->Eax = eax; Context->Ebx = ebx; Context->Ecx = ecx; Context->Edx = edx; Context->Edi = edi; Context->Esi = esi; }
#if 0
if ((ContextFlags & CONTEXT_FLOATING_POINT_WX86) == CONTEXT_FLOATING_POINT_WX86) { }
if ((ContextFlags & CONTEXT_DEBUG_REGISTERS_WX86) == CONTEXT_DEBUG_REGISTERS_WX86) { }
if ((ContextFlags & CONTEXT_EXTENDED_REGISTERS_WX86) == CONTEXT_EXTENDED_REGISTERS_WX86) { } #endif
return TRUE; }
WOW64CPUDBGAPI BOOL CpuDbgSetLocalContext( PCONTEXT32 Context ) { ULONG ContextFlags = Context->ContextFlags; PTHREADSTATE cpu = &LocalCpuContext;
if ((ContextFlags & CONTEXT_CONTROL_WX86) == CONTEXT_CONTROL_WX86) { //
// i386 control registers are:
// ebp, eip, cs, eflag, esp and ss
//
LocalCpuContext.GpRegs[GP_EBP].i4 = Context->Ebp; LocalCpuContext.eipReg.i4 = Context->Eip; LocalCpuContext.GpRegs[REG_CS].i4= KGDT_R3_CODE|3; // Force Reality
SetEfl(Context->EFlags); LocalCpuContext.GpRegs[GP_ESP].i4 = Context->Esp; LocalCpuContext.GpRegs[REG_SS].i4 = KGDT_R3_DATA|3; // Force Reality
ContextDirty = TRUE; }
if ((ContextFlags & CONTEXT_INTEGER_WX86) == CONTEXT_INTEGER_WX86){ //
// i386 integer registers are:
// edi, esi, ebx, edx, ecx, eax
//
LocalCpuContext.GpRegs[GP_EDI].i4 = Context->Edi; LocalCpuContext.GpRegs[GP_ESI].i4 = Context->Esi; LocalCpuContext.GpRegs[GP_EBX].i4 = Context->Ebx; LocalCpuContext.GpRegs[GP_EDX].i4 = Context->Edx; LocalCpuContext.GpRegs[GP_ECX].i4 = Context->Ecx; LocalCpuContext.GpRegs[GP_EAX].i4 = Context->Eax; ContextDirty = TRUE; }
if ((ContextFlags & CONTEXT_SEGMENTS_WX86) == CONTEXT_SEGMENTS_WX86) { //
// i386 segment registers are:
// ds, es, fs, gs
// And since they are a constant, force them to be the right values
//
LocalCpuContext.GpRegs[REG_DS].i4 = KGDT_R3_DATA|3; LocalCpuContext.GpRegs[REG_ES].i4 = KGDT_R3_DATA|3; LocalCpuContext.GpRegs[REG_FS].i4 = KGDT_R3_TEB|3; LocalCpuContext.GpRegs[REG_GS].i4 = KGDT_R3_DATA|3; ContextDirty = TRUE; }
#if 0
if ((ContextFlags & CONTEXT_FLOATING_POINT_WX86) == CONTEXT_FLOATING_POINT_WX86) { }
if ((ContextFlags & CONTEXT_DEBUG_REGISTERS_WX86) == CONTEXT_DEBUG_REGISTERS_WX86) { }
if ((ContextFlags & CONTEXT_EXTENDED_REGISTERS_WX86) == CONTEXT_EXTENDED_REGISTERS_WX86) { } #endif
return TRUE; }
WOW64CPUDBGAPI VOID CpuDbgFlushInstructionCache( PVOID Addr, DWORD Length ) { NTSTATUS Status; ULONG DirtyMemoryEnd; ULONG DirtyMemoryAddr; ULONG DirtyMemoryLength;
Status = GetDirtyMemoryRange(&DirtyMemoryAddr, &DirtyMemoryLength); if (!NT_SUCCESS(Status)) { return; } if (DirtyMemoryAddr == 0xffffffff) { DirtyMemoryEnd = 0; } else { DirtyMemoryEnd = DirtyMemoryAddr + DirtyMemoryLength; }
if (PtrToUlong(Addr) < DirtyMemoryAddr) { //
// The new address is before the start of the dirty range
//
DirtyMemoryLength += DirtyMemoryAddr-PtrToUlong(Addr); DirtyMemoryAddr = PtrToUlong(Addr); }
if (PtrToUlong(Addr)+Length > DirtyMemoryEnd) { //
// The range is too small - grow it
//
DirtyMemoryEnd = PtrToUlong(Addr)+Length; DirtyMemoryLength = DirtyMemoryEnd - DirtyMemoryAddr; }
// Tell the CPU to call CpuFlushInstructionCache() next time it runs.
//
// The wow64 debugger extension guarantees that it will call
// DbgCpuGetRemoteContext before this call, and will call
// DbgCpuSetRemoteContext after this call, so we can flush out
// our context then.
//
NtWriteVirtualMemory(Process, (PVOID)pDirtyMemoryAddr, &DirtyMemoryAddr, sizeof(ULONG), NULL); NtWriteVirtualMemory(Process, (PVOID)pDirtyMemoryLength, &DirtyMemoryLength, sizeof(ULONG), NULL); LocalCpuContext.CpuNotify |= CPUNOTIFY_DBGFLUSHTC; ContextDirty = TRUE; }
VOID SetEax(ULONG ul) { LocalCpuContext.GpRegs[GP_EAX].i4 = ul; ContextDirty = TRUE; } VOID SetEbx(ULONG ul) { LocalCpuContext.GpRegs[GP_EBX].i4 = ul; ContextDirty = TRUE; } VOID SetEcx(ULONG ul) { LocalCpuContext.GpRegs[GP_ECX].i4 = ul; ContextDirty = TRUE; } VOID SetEdx(ULONG ul) { LocalCpuContext.GpRegs[GP_EDX].i4 = ul; ContextDirty = TRUE; } VOID SetEsi(ULONG ul) { LocalCpuContext.GpRegs[GP_ESI].i4 = ul; ContextDirty = TRUE; } VOID SetEdi(ULONG ul) { LocalCpuContext.GpRegs[GP_EDI].i4 = ul; ContextDirty = TRUE; } VOID SetEbp(ULONG ul) { LocalCpuContext.GpRegs[GP_EBP].i4 = ul; ContextDirty = TRUE; } VOID SetEsp(ULONG ul) { LocalCpuContext.GpRegs[GP_ESP].i4 = ul; ContextDirty = TRUE; } VOID SetEip(ULONG ul) { LocalCpuContext.eipReg.i4 = ul; ContextDirty = TRUE; } VOID SetEfl(ULONG ul) { LocalCpuContext.flag_cf = (ul & BIT0) ? 0x80000000 : 0; LocalCpuContext.flag_pf = (ul & BIT2) ? 0 : 1; LocalCpuContext.flag_aux= (ul & BIT4) ? 0x10 : 0; LocalCpuContext.flag_zf = (ul & BIT6) ? 0 : 1; LocalCpuContext.flag_sf = (ul & BIT7) ? 0x80000000 : 0; LocalCpuContext.flag_tf = (ul & BIT8) ? 1 : 0; LocalCpuContext.flag_df = (ul & BIT10) ? 1 : -1; LocalCpuContext.flag_of = (ul & BIT11) ? 0x80000000 : 0; // iopl, NT, RF, VM are ignored
LocalCpuContext.flag_ac = (ul & BIT18);
LocalCpuContext.CpuNotify &= ~CPUNOTIFY_TRACEFLAG; LocalCpuContext.CpuNotify |= LocalCpuContext.flag_tf; ContextDirty = TRUE;
// If the single-step flag is set and the CPU is in fast mode, this
// will flush the cache if autoflush is set, or else remind the user
// if autoflush is clear.
RemindUserToFlushTheCache(); }
ULONG GetEax(VOID) { return LocalCpuContext.GpRegs[GP_EAX].i4; } ULONG GetEbx(VOID) { return LocalCpuContext.GpRegs[GP_EBX].i4; } ULONG GetEcx(VOID) { return LocalCpuContext.GpRegs[GP_ECX].i4; } ULONG GetEdx(VOID) { return LocalCpuContext.GpRegs[GP_EDX].i4; } ULONG GetEsi(VOID) { return LocalCpuContext.GpRegs[GP_ESI].i4; } ULONG GetEdi(VOID) { return LocalCpuContext.GpRegs[GP_EDI].i4; } ULONG GetEsp(VOID) { return LocalCpuContext.GpRegs[GP_ESP].i4; } ULONG GetEbp(VOID) { return LocalCpuContext.GpRegs[GP_EBP].i4; } ULONG GetEip(VOID) { return LocalCpuContext.eipReg.i4; } ULONG GetEfl(VOID) { return (LocalCpuContext.flag_ac | // this is either 0 or 2^18
// VM, RF, NT are all 0
((LocalCpuContext.flag_of & 0x80000000) ? (1 << 11) : 0) | ((LocalCpuContext.flag_df == -1) ? 0 : (1 << 10)) | 1 << 9 | // IF
LocalCpuContext.flag_tf << 8 | ((LocalCpuContext.flag_sf & 0x80000000) ? (1 << 7) : 0) | ((LocalCpuContext.flag_zf) ? 0 : (1 << 6)) | ((LocalCpuContext.flag_aux & 0x10) ? (1 << 4) : 0) | ParityBit[LocalCpuContext.flag_pf & 0xff] << 2 | 0x2 | ((LocalCpuContext.flag_cf & 0x80000000) ? 1 : 0) ); }
CPUREGFUNCS CpuRegFuncs[] = { { "eax", SetEax, GetEax }, { "ebx", SetEbx, GetEbx }, { "ecx", SetEcx, GetEcx }, { "edx", SetEdx, GetEdx }, { "esi", SetEsi, GetEsi }, { "edi", SetEdi, GetEdi }, { "esp", SetEsp, GetEsp }, { "ebp", SetEbp, GetEbp }, { "eip", SetEip, GetEip }, { "efl", SetEfl, GetEfl }, { NULL, NULL, NULL} };
WOW64CPUDBGAPI PCPUREGFUNCS CpuDbgGetRegisterFuncs( void ) { return CpuRegFuncs; }
#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;
DECLARE_EXTAPI(help) { INIT_EXTAPI;
DEBUGGERPRINT("WOW64 MS CPU debugger extensions:\n\n"); DEBUGGERPRINT("epi [inteladdress] - dump an entrypt based on x86 address\n"); DEBUGGERPRINT("epn [nativeaddress] - dump an entrypt based on a native address\n"); DEBUGGERPRINT("dumpep - all entrypts\n"); DEBUGGERPRINT("code [fast|slow] - set the CPU's code-gen mode\n"); DEBUGGERPRINT("flush - flush the Translation Cache\n"); DEBUGGERPRINT("autoflush - the debugger extension may auto-flush the TC\n"); DEBUGGERPRINT("logeip - enable EIP logging\n"); DEBUGGERPRINT("last - dump the last EIP values\n"); DEBUGGERPRINT("callstack - dump the internal callstack cache\n"); }
DECLARE_EXTAPI(autoflush) { INIT_EXTAPI;
if (AutoFlushFlag) { AutoFlushFlag = FALSE; DEBUGGERPRINT("autoflush is OFF - use !flush to flush the cache when needed.\n"); } else { AutoFlushFlag = TRUE; DEBUGGERPRINT("autoflush is ON - The CPU Cache will be flushed automatically.\n"); } }
DECLARE_EXTAPI(code) { DWORD CompilerFlags;
INIT_EXTAPI;
CompilerFlags = GetCompilerFlags(); if (CompilerFlags == 0xffffffff) { //
// Got an error reading the CompilerFlags variable
//
return; }
if (!ArgumentString) { PrintCurrentValue: DEBUGGERPRINT("CPU Compiler is in %s mode.\n", (CompilerFlags & COMPFL_SLOW) ? "SLOW" : "FAST"); return; }
// Skip over whitespace
while (*ArgumentString && isspace(*ArgumentString)) { ArgumentString++; } if (!*ArgumentString) { goto PrintCurrentValue; }
if (_stricmp(ArgumentString, "fast") == 0) { SetCompilerFlags(COMPFL_FAST); } else if (_stricmp(ArgumentString, "slow") == 0) { SetCompilerFlags(COMPFL_SLOW); } else { DEBUGGERPRINT("usage: !code [fast|slow]\n"); }
RemindUserToFlushTheCache(); }
DECLARE_EXTAPI(flush) { INIT_EXTAPI;
if (!CpuDbgGetRemoteContext(CPUGETDATA(Process, Thread))) { return; } CpuDbgFlushInstructionCache(0, 0xffffffff); CpuDbgSetRemoteContext(); DEBUGGERPRINT("CPU Translation Cache will flush next time CpuSimulate loops.\n"); }
DECLARE_EXTAPI(logeip) { ULONG CpuNotify;
INIT_EXTAPI;
if (!CpuDbgGetRemoteContext(CPUGETDATA(Process, Thread))) { return; }
CpuNotify = LocalCpuContext.CpuNotify;
if (CpuNotify & CPUNOTIFY_SLOWMODE) { CpuNotify &= ~CPUNOTIFY_SLOWMODE; } else { CpuNotify |= CPUNOTIFY_SLOWMODE; }
LocalCpuContext.CpuNotify = CpuNotify; ContextDirty = TRUE;
if (CpuDbgSetRemoteContext()) { DEBUGGERPRINT("EIP logging "); if (CpuNotify & CPUNOTIFY_SLOWMODE) { DEBUGGERPRINT("ON - use !last to see the EIP log.\n"); } else { DEBUGGERPRINT("OFF.\n"); } } }
DECLARE_EXTAPI(last) { ULONG CpuNotify; DWORD64 n; char *pchCmd; DWORD64 EipOffset, i;
INIT_EXTAPI;
if (!CpuDbgGetRemoteContext(CPUGETDATA(Process, Thread))) { return; }
// Parse out the optional number of instructions. Default is all
// instructions in the log
n = 0xffffffff; pchCmd = ArgumentString; while (*pchCmd && isspace(*pchCmd)) { pchCmd++; }
if (*pchCmd) { NTSTATUS Status;
Status = TryGetExpr(pchCmd, &n); if (!NT_SUCCESS(Status) || !n) { DEBUGGERPRINT("Invalid Length: '%s' Status %x\n", pchCmd, Status ); return; } }
CpuNotify = LocalCpuContext.CpuNotify; if (!(CpuNotify & CPUNOTIFY_SLOWMODE)) { DEBUGGERPRINT("Warning: logeip is not enabled. Log may be out-of-date.\n"); }
EipOffset = LocalCpuContext.eipLogIndex; if (n >= EIPLOGSIZE) { n = EIPLOGSIZE; } else { EipOffset -= n; }
for (i = 0; i<n; ++i, ++EipOffset) { EipOffset %= EIPLOGSIZE; if (LocalCpuContext.eipLog[EipOffset] == 0) { break; } DEBUGGERPRINT("%x %x\n", i, LocalCpuContext.eipLog[EipOffset]); } }
DECLARE_EXTAPI(callstack) /*++
Routine Description:
This routine dumps out the callstack for the thread.
Arguments:
none Return Value:
None.
--*/ { ULONG i;
INIT_EXTAPI; //
// fetch the CpuContext for the current thread
//
if (!CpuDbgGetRemoteContext(CPUGETDATA(Process, Thread))) { return; }
//
// Dump out the call stack
//
DEBUGGERPRINT(" CallStackTimeStamp : %08lx\n", LocalCpuContext.CSTimestamp); DEBUGGERPRINT(" CallStackIndex : %08lx\n", LocalCpuContext.CSIndex); DEBUGGERPRINT(" -----------------------------\n"); DEBUGGERPRINT(" Intel : Native\n"); for (i = 0; i < CSSIZE; i++) { DEBUGGERPRINT( " %08lx : %08lx\n", LocalCpuContext.callStack[i].intelAddr, LocalCpuContext.callStack[i].nativeAddr ); } }
|