500 lines
12 KiB
C
500 lines
12 KiB
C
#include "ntsdp.h"
|
|
#if defined(TARGET_i386)
|
|
#include "86reg.h"
|
|
#endif
|
|
#include <string.h>
|
|
|
|
extern ULONG pageSize;
|
|
|
|
#ifdef KERNEL
|
|
extern PVOID NtsdCurrentEThread;
|
|
extern DBGKD_GET_VERSION vs;
|
|
#endif
|
|
|
|
#define SAVE_EBP(f) f.Reserved[0]
|
|
#define TRAP_TSS(f) f.Reserved[1]
|
|
#define TRAP_EDITED(f) f.Reserved[1]
|
|
#define SAVE_TRAP(f) f.Reserved[2]
|
|
|
|
#if defined(TARGET_i386) || defined(CHICAGO)
|
|
#define MachineType IMAGE_FILE_MACHINE_I386
|
|
#elif defined(TARGET_MIPS)
|
|
#define MachineType IMAGE_FILE_MACHINE_R4000
|
|
#elif defined(TARGET_ALPHA)
|
|
#define MachineType IMAGE_FILE_MACHINE_ALPHA
|
|
#elif defined(TARGET_PPC)
|
|
#define MachineType IMAGE_FILE_MACHINE_POWERPC
|
|
#else
|
|
#error( "unknown target machine" );
|
|
#endif
|
|
|
|
VOID
|
|
bangReload(
|
|
IN PUCHAR args
|
|
);
|
|
|
|
|
|
LPVOID
|
|
SwFunctionTableAccess(
|
|
HANDLE hProcess,
|
|
DWORD AddrBase
|
|
)
|
|
{
|
|
#if defined(TARGET_i386) || defined(CHICAGO)
|
|
return (LPVOID)FindFpoDataForModule( AddrBase );
|
|
#else
|
|
static IMAGE_RUNTIME_FUNCTION_ENTRY irfe;
|
|
PIMAGE_FUNCTION_ENTRY pife = SymFunctionTableAccess( hProcess, AddrBase );
|
|
if (pife) {
|
|
irfe.BeginAddress = pife->StartingAddress;
|
|
irfe.EndAddress = pife->EndingAddress;
|
|
irfe.ExceptionHandler = 0;
|
|
irfe.HandlerData = 0;
|
|
irfe.PrologEndAddress = pife->EndOfPrologue;
|
|
return &irfe;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
DWORD
|
|
SwTranslateAddress(
|
|
HANDLE hProcess,
|
|
HANDLE hThread,
|
|
LPADDRESS lpaddress
|
|
)
|
|
{
|
|
//
|
|
// don't support 16bit stacks
|
|
//
|
|
return 0;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SwReadMemory(
|
|
HANDLE hProcess,
|
|
LPCVOID lpBaseAddress,
|
|
LPVOID lpBuffer,
|
|
DWORD nSize,
|
|
LPDWORD lpNumberOfBytesRead
|
|
)
|
|
{
|
|
#ifdef KERNEL
|
|
BOOLEAN fSuccess;
|
|
DWORD BytesRead;
|
|
NTSTATUS Status;
|
|
|
|
if ((LONG)lpNumberOfBytesRead == -1) {
|
|
|
|
Status = DbgKdReadControlSpace(
|
|
NtsdCurrentProcessor,
|
|
(PVOID)lpBaseAddress,
|
|
lpBuffer,
|
|
nSize,
|
|
&BytesRead );
|
|
fSuccess = Status == STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
fSuccess = (BOOLEAN)NT_SUCCESS(DbgKdReadVirtualMemory(
|
|
(PVOID)lpBaseAddress,
|
|
lpBuffer,
|
|
nSize,
|
|
lpNumberOfBytesRead) );
|
|
|
|
}
|
|
|
|
return fSuccess;
|
|
|
|
#else
|
|
ULONG cTotalBytesRead = 0;
|
|
ULONG cBytesRead;
|
|
ULONG readcount;
|
|
PUCHAR pBufSource;
|
|
BOOLEAN fSuccess;
|
|
DWORD addr;
|
|
DWORD bias;
|
|
|
|
pBufSource = (PUCHAR)lpBaseAddress;
|
|
|
|
do {
|
|
//
|
|
// do not perform reads across page boundaries.
|
|
// calculate bytes to read in present page in readcount.
|
|
//
|
|
readcount = min(nSize - cTotalBytesRead,
|
|
pageSize - ((ULONG)pBufSource & (pageSize - 1)));
|
|
|
|
fSuccess = ReadProcessMemory(hProcess, pBufSource, lpBuffer, readcount, &cBytesRead);
|
|
|
|
// update total bytes read and new address for next read
|
|
|
|
if (fSuccess) {
|
|
cTotalBytesRead += cBytesRead;
|
|
pBufSource += cBytesRead;
|
|
(PUCHAR)lpBuffer += cBytesRead;
|
|
}
|
|
} while (fSuccess && cTotalBytesRead < nSize);
|
|
|
|
if (lpNumberOfBytesRead) {
|
|
*lpNumberOfBytesRead = cTotalBytesRead;
|
|
}
|
|
|
|
return TRUE;
|
|
#endif
|
|
}
|
|
|
|
|
|
DWORD
|
|
SwGetModuleBase(
|
|
HANDLE hProcess,
|
|
DWORD Address
|
|
)
|
|
{
|
|
PIMAGE_INFO pImage = pProcessCurrent->pImageHead;
|
|
|
|
while (pImage) {
|
|
if ((Address >= (DWORD)pImage->lpBaseOfImage) &&
|
|
(Address < (DWORD)((DWORD)pImage->lpBaseOfImage+pImage->dwSizeOfImage))) {
|
|
return (DWORD)pImage->lpBaseOfImage;
|
|
}
|
|
pImage = pImage->pImageNext;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef KERNEL
|
|
void
|
|
EnsureModLoadedForAddress(
|
|
DWORD Address
|
|
)
|
|
{
|
|
CHAR Buffer[11];
|
|
if (!SwGetModuleBase(0, Address)) {
|
|
sprintf(Buffer, "0x%08x", Address);
|
|
bangReload(Buffer);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
DWORD
|
|
StackTrace(
|
|
ULONG FramePointer,
|
|
ULONG StackPointer,
|
|
ULONG InstructionPointer,
|
|
LPSTACKFRAME StackFrames,
|
|
ULONG NumFrames,
|
|
ULONG ExtThread
|
|
)
|
|
{
|
|
CONTEXT Context;
|
|
PCONTEXT RegContext;
|
|
STACKFRAME VirtualFrame;
|
|
DWORD i;
|
|
|
|
#ifdef KERNEL
|
|
RegContext = GetRegContext();
|
|
#else
|
|
RegContext = &RegisterContext;
|
|
#endif
|
|
|
|
Context = *RegContext;
|
|
|
|
//
|
|
// lets start clean
|
|
//
|
|
ZeroMemory( StackFrames, sizeof(STACKFRAME)*NumFrames );
|
|
ZeroMemory( &VirtualFrame, sizeof(STACKFRAME) );
|
|
|
|
#ifdef KERNEL
|
|
|
|
if (vs.KeUserCallbackDispatcher == 0) {
|
|
//
|
|
// if debugger was initialized at boot, usermode addresses
|
|
// were not available. Try it now:
|
|
//
|
|
|
|
DbgKdGetVersion( &vs );
|
|
}
|
|
VirtualFrame.KdHelp.Thread = ExtThread ? ExtThread : (DWORD)NtsdCurrentEThread;
|
|
VirtualFrame.KdHelp.KiCallUserMode = vs.KiCallUserMode;
|
|
VirtualFrame.KdHelp.ThCallbackStack = vs.ThCallbackStack;
|
|
VirtualFrame.KdHelp.NextCallback = vs.NextCallback;
|
|
VirtualFrame.KdHelp.KeUserCallbackDispatcher = vs.KeUserCallbackDispatcher;
|
|
VirtualFrame.KdHelp.FramePointer = vs.FramePointer;
|
|
|
|
#endif
|
|
|
|
//
|
|
// setup the program counter
|
|
//
|
|
#if defined(TARGET_i386)
|
|
VirtualFrame.AddrPC.Mode = AddrModeFlat;
|
|
VirtualFrame.AddrPC.Segment = (WORD)X86GetRegValue(REGCS);
|
|
if (!InstructionPointer) {
|
|
VirtualFrame.AddrPC.Offset = (ULONG)X86GetRegValue(REGEIP);
|
|
} else {
|
|
VirtualFrame.AddrPC.Offset = InstructionPointer;
|
|
}
|
|
|
|
//
|
|
// setup the frame pointer
|
|
//
|
|
VirtualFrame.AddrFrame.Mode = AddrModeFlat;
|
|
VirtualFrame.AddrFrame.Segment = (WORD)X86GetRegValue(REGSS);
|
|
if (!FramePointer) {
|
|
VirtualFrame.AddrFrame.Offset = (ULONG)X86GetRegValue(REGEBP);
|
|
} else {
|
|
VirtualFrame.AddrFrame.Offset = FramePointer;
|
|
}
|
|
|
|
//
|
|
// setup the stack pointer
|
|
//
|
|
VirtualFrame.AddrStack.Mode = AddrModeFlat;
|
|
VirtualFrame.AddrStack.Segment = (WORD)X86GetRegValue(REGSS);
|
|
if (!StackPointer) {
|
|
VirtualFrame.AddrStack.Offset = (ULONG)X86GetRegValue(REGESP);
|
|
} else {
|
|
VirtualFrame.AddrStack.Offset = StackPointer;
|
|
}
|
|
#endif
|
|
|
|
#if defined (TARGET_MIPS) || defined(TARGET_ALPHA) || defined(TARGET_PPC)
|
|
|
|
if (InstructionPointer) {
|
|
VirtualFrame.AddrPC.Offset = InstructionPointer;
|
|
VirtualFrame.AddrPC.Mode = AddrModeFlat;
|
|
}
|
|
|
|
//
|
|
// setup the stack pointer
|
|
//
|
|
if (StackPointer) {
|
|
VirtualFrame.AddrStack.Offset = StackPointer;
|
|
VirtualFrame.AddrStack.Mode = AddrModeFlat;
|
|
}
|
|
|
|
if (FramePointer) {
|
|
VirtualFrame.AddrFrame.Offset = FramePointer;
|
|
VirtualFrame.AddrFrame.Mode = AddrModeFlat;
|
|
}
|
|
|
|
#endif
|
|
|
|
for (i=0; i<NumFrames; i++) {
|
|
if (!StackWalk( MachineType,
|
|
pProcessCurrent->hProcess,
|
|
#ifdef KERNEL
|
|
(HANDLE)DefaultProcessor,
|
|
#else
|
|
pProcessCurrent->pThreadCurrent->hThread,
|
|
#endif
|
|
&VirtualFrame,
|
|
&Context,
|
|
SwReadMemory,
|
|
SwFunctionTableAccess,
|
|
SwGetModuleBase,
|
|
SwTranslateAddress
|
|
)) {
|
|
break;
|
|
}
|
|
StackFrames[i] = VirtualFrame;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
VOID
|
|
DoStackTrace(
|
|
ULONG FramePointer,
|
|
ULONG StackPointer,
|
|
ULONG InstructionPointer,
|
|
ULONG NumFrames,
|
|
ULONG TraceType
|
|
)
|
|
{
|
|
LPSTACKFRAME StackFrames;
|
|
DWORD FrameCount;
|
|
DWORD i;
|
|
DWORD displacement;
|
|
CHAR symbuf[512];
|
|
USHORT StdCallArgs;
|
|
|
|
if (NumFrames == 0) {
|
|
NumFrames = 20;
|
|
}
|
|
|
|
StackFrames = malloc( sizeof(STACKFRAME) * NumFrames );
|
|
if (!StackFrames) {
|
|
dprintf( "could not allocate memory for stack trace\n" );
|
|
return;
|
|
}
|
|
|
|
FrameCount = StackTrace( FramePointer,
|
|
StackPointer,
|
|
InstructionPointer,
|
|
StackFrames,
|
|
NumFrames,
|
|
0
|
|
);
|
|
|
|
if (FrameCount == 0) {
|
|
dprintf( "could not fetch any stack frames\n" );
|
|
return;
|
|
}
|
|
|
|
#if defined(TARGET_i386)
|
|
dprintf( "ChildEBP RetAddr" );
|
|
if (TraceType) {
|
|
dprintf(" Args to Child");
|
|
}
|
|
dprintf("\n");
|
|
#else
|
|
if (TraceType==1) {
|
|
dprintf("\nCallee-SP Arguments to Callee Call Site\n\n");
|
|
} else {
|
|
dprintf("\nCallee-SP Return-RA Call Site\n\n");
|
|
}
|
|
#endif
|
|
|
|
for (i=0; i<FrameCount; i++) {
|
|
|
|
GetSymbolStdCall( StackFrames[i].AddrPC.Offset,
|
|
symbuf,
|
|
&displacement,
|
|
&StdCallArgs
|
|
);
|
|
|
|
#if defined(TARGET_i386)
|
|
dprintf( "%08x %08x ",
|
|
StackFrames[i].AddrFrame.Offset,
|
|
StackFrames[i].AddrReturn.Offset
|
|
);
|
|
|
|
if (TraceType > 0) {
|
|
dprintf( "%08x %08x %08x ",
|
|
StackFrames[i].Params[0],
|
|
StackFrames[i].Params[1],
|
|
StackFrames[i].Params[2]
|
|
);
|
|
}
|
|
|
|
if (*symbuf) {
|
|
dprintf( "%s", symbuf );
|
|
if (displacement) {
|
|
dprintf("+");
|
|
}
|
|
}
|
|
if (displacement) {
|
|
dprintf("0x%x", displacement);
|
|
}
|
|
|
|
if (TraceType == 2 && !StackFrames[i].FuncTableEntry) {
|
|
if (StdCallArgs != 0xffff) {
|
|
dprintf(" [Stdcall: %d]", StdCallArgs);
|
|
}
|
|
} else
|
|
if (TraceType == 2 && StackFrames[i].FuncTableEntry) {
|
|
PFPO_DATA pFpoData = (PFPO_DATA)StackFrames[i].FuncTableEntry;
|
|
switch (pFpoData->cbFrame) {
|
|
case FRAME_FPO:
|
|
if (pFpoData->fHasSEH) {
|
|
dprintf("(FPO: [SEH])");
|
|
} else {
|
|
dprintf(" (FPO:");
|
|
if (pFpoData->fUseBP) {
|
|
dprintf(" [EBP 0x%08x]", SAVE_EBP(StackFrames[i]));
|
|
}
|
|
dprintf(" [%d,%d,%d])", pFpoData->cdwParams,
|
|
pFpoData->cdwLocals,
|
|
pFpoData->cbRegs);
|
|
}
|
|
break;
|
|
|
|
case FRAME_NONFPO:
|
|
dprintf("(FPO: [Non-Fpo]" );
|
|
break;
|
|
|
|
#ifdef KERNEL
|
|
case FRAME_TRAP:
|
|
dprintf(" (FPO: [%d,%d] TrapFrame%s @ %08lx)",
|
|
pFpoData->cdwParams,
|
|
pFpoData->cdwLocals,
|
|
TRAP_EDITED(StackFrames[i]) ? "" : "-EDITED",
|
|
SAVE_TRAP(StackFrames[i]) );
|
|
break;
|
|
case FRAME_TSS:
|
|
dprintf(" (FPO: TaskGate %lx:0)", TRAP_TSS(StackFrames[i]));
|
|
break;
|
|
#endif
|
|
default:
|
|
dprintf("(UKNOWN FPO TYPE)");
|
|
break;
|
|
}
|
|
}
|
|
dprintf( "\n" );
|
|
#else
|
|
if (TraceType == 1) {
|
|
dprintf( " %08lx : ",
|
|
StackFrames[i].AddrFrame.Offset
|
|
);
|
|
} else {
|
|
dprintf( " %08lx %08lx : ",
|
|
StackFrames[i].AddrFrame.Offset,
|
|
StackFrames[i].AddrReturn.Offset
|
|
);
|
|
}
|
|
|
|
if (TraceType == 1) {
|
|
dprintf( "%08lx %08lx %08lx %08lx ",
|
|
StackFrames[i].Params[0],
|
|
StackFrames[i].Params[1],
|
|
StackFrames[i].Params[2],
|
|
StackFrames[i].Params[3]
|
|
);
|
|
}
|
|
|
|
dprintf( "%s", symbuf );
|
|
if (displacement) {
|
|
dprintf("+0x%lx ", displacement);
|
|
}
|
|
|
|
dprintf( "\n" );
|
|
#endif
|
|
}
|
|
|
|
free( StackFrames );
|
|
|
|
return;
|
|
}
|
|
|
|
#ifdef KERNEL
|
|
PVOID
|
|
GetCallbackStackHead(
|
|
PVOID Thread
|
|
)
|
|
{
|
|
KTHREAD Tcb;
|
|
DWORD dwRead;
|
|
NTSTATUS Status;
|
|
|
|
Status = DbgKdReadVirtualMemory(
|
|
Thread,
|
|
&Tcb,
|
|
sizeof(KTHREAD),
|
|
&dwRead);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
return Tcb.CallbackStack;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|