515 lines
14 KiB
C
515 lines
14 KiB
C
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
walk.c
|
|
|
|
Abstract:
|
|
|
|
This function implements the stack walking api.
|
|
|
|
Author:
|
|
|
|
Wesley Witt (wesw) 1-Oct-1993
|
|
|
|
Environment:
|
|
|
|
User Mode
|
|
|
|
--*/
|
|
|
|
#include <private.h>
|
|
#include "globals.h"
|
|
|
|
#ifndef PAGE_SIZE
|
|
#if defined(_X86_) || defined(_AMD64_)
|
|
#define PAGE_SIZE 0x1000
|
|
#elif defined(_ALPHA_) || defined(_IA64_)
|
|
#define PAGE_SIZE 0x2000
|
|
#else
|
|
#error Unknown processor architecture
|
|
#endif
|
|
#endif
|
|
|
|
BOOL
|
|
ReadMemoryRoutineLocal(
|
|
HANDLE hProcess,
|
|
DWORD64 qwBaseAddress,
|
|
LPVOID lpBuffer,
|
|
DWORD nSize,
|
|
LPDWORD lpNumberOfBytesRead
|
|
);
|
|
|
|
LPVOID
|
|
FunctionTableAccessRoutineLocal(
|
|
HANDLE hProcess,
|
|
DWORD64 AddrBase
|
|
);
|
|
|
|
DWORD64
|
|
GetModuleBaseRoutineLocal(
|
|
HANDLE hProcess,
|
|
DWORD64 ReturnAddress
|
|
);
|
|
|
|
DWORD64
|
|
TranslateAddressRoutineLocal(
|
|
HANDLE hProcess,
|
|
HANDLE hThread,
|
|
LPADDRESS64 lpaddr
|
|
);
|
|
|
|
BOOL
|
|
ImagepReadMemoryThunk(
|
|
HANDLE hProcess,
|
|
DWORD64 qwBaseAddress,
|
|
LPVOID lpBuffer,
|
|
DWORD nSize,
|
|
LPDWORD lpNumberOfBytesRead
|
|
)
|
|
{
|
|
PREAD_PROCESS_MEMORY_ROUTINE fnImagepUserReadMemory32;
|
|
|
|
fnImagepUserReadMemory32 = tlsvar(ImagepUserReadMemory32);
|
|
return fnImagepUserReadMemory32(
|
|
hProcess,
|
|
(DWORD)qwBaseAddress,
|
|
lpBuffer,
|
|
nSize,
|
|
lpNumberOfBytesRead
|
|
);
|
|
}
|
|
|
|
LPVOID
|
|
ImagepFunctionTableAccessThunk(
|
|
HANDLE hProcess,
|
|
DWORD64 AddrBase
|
|
)
|
|
{
|
|
PFUNCTION_TABLE_ACCESS_ROUTINE fnImagepUserFunctionTableAccess32;
|
|
|
|
fnImagepUserFunctionTableAccess32 = tlsvar(ImagepUserFunctionTableAccess32);
|
|
return fnImagepUserFunctionTableAccess32(
|
|
hProcess,
|
|
(DWORD)AddrBase
|
|
);
|
|
}
|
|
|
|
PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY
|
|
AlphaFunctionTableAccessThunk(
|
|
HANDLE hProcess,
|
|
DWORD64 AddrBase
|
|
)
|
|
{
|
|
PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY FunctionEntry32;
|
|
PFUNCTION_TABLE_ACCESS_ROUTINE fnImagepUserFunctionTableAccess32;
|
|
|
|
fnImagepUserFunctionTableAccess32 = tlsvar(ImagepUserFunctionTableAccess32);
|
|
FunctionEntry32 = (PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY)
|
|
fnImagepUserFunctionTableAccess32(
|
|
hProcess,
|
|
(DWORD)AddrBase
|
|
);
|
|
|
|
if (FunctionEntry32) {
|
|
ConvertAlphaRf32To64( FunctionEntry32, &tlsvar(Axp64FunctionEntry) );
|
|
|
|
return &tlsvar(Axp64FunctionEntry);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
DWORD64
|
|
ImagepGetModuleBaseThunk(
|
|
HANDLE hProcess,
|
|
DWORD64 ReturnAddress
|
|
)
|
|
{
|
|
PGET_MODULE_BASE_ROUTINE fnImagepUserGetModuleBase32;
|
|
|
|
fnImagepUserGetModuleBase32 = tlsvar(ImagepUserGetModuleBase32);
|
|
return (ULONG64)(LONG64)(LONG)fnImagepUserGetModuleBase32(
|
|
hProcess,
|
|
(DWORD)ReturnAddress
|
|
);
|
|
}
|
|
|
|
DWORD64
|
|
ImagepTranslateAddressThunk(
|
|
HANDLE hProcess,
|
|
HANDLE hThread,
|
|
LPADDRESS64 lpaddr
|
|
)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
StackFrame32To64(
|
|
LPSTACKFRAME StackFrame32,
|
|
LPSTACKFRAME64 StackFrame64
|
|
)
|
|
{
|
|
Address32To64(&StackFrame32->AddrPC, &StackFrame64->AddrPC );
|
|
Address32To64(&StackFrame32->AddrReturn, &StackFrame64->AddrReturn );
|
|
Address32To64(&StackFrame32->AddrFrame, &StackFrame64->AddrFrame );
|
|
Address32To64(&StackFrame32->AddrStack, &StackFrame64->AddrStack );
|
|
StackFrame64->FuncTableEntry = StackFrame32->FuncTableEntry;
|
|
StackFrame64->Far = StackFrame32->Far;
|
|
StackFrame64->Virtual = StackFrame32->Virtual;
|
|
StackFrame64->Params[0] = StackFrame32->Params[0];
|
|
StackFrame64->Params[1] = StackFrame32->Params[1];
|
|
StackFrame64->Params[2] = StackFrame32->Params[2];
|
|
StackFrame64->Params[3] = StackFrame32->Params[3];
|
|
StackFrame64->Reserved[0] = StackFrame32->Reserved[0];
|
|
StackFrame64->Reserved[1] = StackFrame32->Reserved[1];
|
|
StackFrame64->Reserved[2] = StackFrame32->Reserved[2];
|
|
KdHelp32To64(&StackFrame32->KdHelp, &StackFrame64->KdHelp);
|
|
}
|
|
|
|
void
|
|
StackFrame64To32(
|
|
LPSTACKFRAME64 StackFrame64,
|
|
LPSTACKFRAME StackFrame32
|
|
)
|
|
{
|
|
Address64To32(&StackFrame64->AddrPC, &StackFrame32->AddrPC );
|
|
Address64To32(&StackFrame64->AddrReturn, &StackFrame32->AddrReturn );
|
|
Address64To32(&StackFrame64->AddrFrame, &StackFrame32->AddrFrame );
|
|
Address64To32(&StackFrame64->AddrStack, &StackFrame32->AddrStack );
|
|
StackFrame32->FuncTableEntry = StackFrame64->FuncTableEntry;
|
|
StackFrame32->Far = StackFrame64->Far;
|
|
StackFrame32->Virtual = StackFrame64->Virtual;
|
|
StackFrame32->Params[0] = (ULONG)StackFrame64->Params[0];
|
|
StackFrame32->Params[1] = (ULONG)StackFrame64->Params[1];
|
|
StackFrame32->Params[2] = (ULONG)StackFrame64->Params[2];
|
|
StackFrame32->Params[3] = (ULONG)StackFrame64->Params[3];
|
|
StackFrame32->Reserved[0] = (ULONG)StackFrame64->Reserved[0];
|
|
StackFrame32->Reserved[1] = (ULONG)StackFrame64->Reserved[1];
|
|
StackFrame32->Reserved[2] = (ULONG)StackFrame64->Reserved[2];
|
|
}
|
|
|
|
BOOL
|
|
StackWalk(
|
|
DWORD MachineType,
|
|
HANDLE hProcess,
|
|
HANDLE hThread,
|
|
LPSTACKFRAME StackFrame32,
|
|
LPVOID ContextRecord,
|
|
PREAD_PROCESS_MEMORY_ROUTINE ReadMemory32,
|
|
PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccess32,
|
|
PGET_MODULE_BASE_ROUTINE GetModuleBase32,
|
|
PTRANSLATE_ADDRESS_ROUTINE TranslateAddress32
|
|
)
|
|
{
|
|
BOOL rval;
|
|
BOOL UseSym = FALSE;
|
|
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory;
|
|
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess;
|
|
PGET_MODULE_BASE_ROUTINE64 GetModuleBase;
|
|
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress;
|
|
STACKFRAME64 StackFrame;
|
|
|
|
// Alpha stack walking no longer requires the FunctionTableAccess callback
|
|
// except for backward compatability with debuggers that didn't specify
|
|
// a GetModuleBase callback. If the GetModuleBase routine is provided
|
|
// then set FunctionTableAccess to NULL to prevent a mixture of the
|
|
// callback and read-from-image methods of accessing function table entries.
|
|
|
|
if (MachineType == IMAGE_FILE_MACHINE_ALPHA) {
|
|
if (GetModuleBase32 == NULL && FunctionTableAccess32) {
|
|
FunctionTableAccess = (PFUNCTION_TABLE_ACCESS_ROUTINE64)AlphaFunctionTableAccessThunk;
|
|
tlsvar(ImagepUserFunctionTableAccess32) = FunctionTableAccess32;
|
|
} else {
|
|
FunctionTableAccess = NULL;
|
|
}
|
|
} else {
|
|
if (FunctionTableAccess32) {
|
|
tlsvar(ImagepUserFunctionTableAccess32) = FunctionTableAccess32;
|
|
FunctionTableAccess = ImagepFunctionTableAccessThunk;
|
|
} else {
|
|
FunctionTableAccess = FunctionTableAccessRoutineLocal;
|
|
UseSym = TRUE;
|
|
}
|
|
}
|
|
|
|
if (GetModuleBase32) {
|
|
tlsvar(ImagepUserGetModuleBase32) = GetModuleBase32;
|
|
GetModuleBase = ImagepGetModuleBaseThunk;
|
|
} else {
|
|
GetModuleBase = GetModuleBaseRoutineLocal;
|
|
UseSym = TRUE;
|
|
}
|
|
|
|
if (ReadMemory32) {
|
|
tlsvar(ImagepUserReadMemory32) = ReadMemory32;
|
|
ReadMemory = ImagepReadMemoryThunk;
|
|
} else {
|
|
ReadMemory = ReadMemoryRoutineLocal;
|
|
}
|
|
|
|
if (TranslateAddress32) {
|
|
tlsvar(ImagepUserTranslateAddress32) = TranslateAddress32;
|
|
TranslateAddress = ImagepTranslateAddressThunk;
|
|
} else {
|
|
TranslateAddress = TranslateAddressRoutineLocal;
|
|
}
|
|
|
|
if (UseSym) {
|
|
//
|
|
// We are using the code in symbols.c
|
|
// hProcess better be a real valid process handle
|
|
//
|
|
|
|
//
|
|
// Always call syminitialize. It's a nop if process
|
|
// is already loaded.
|
|
//
|
|
if (!SymInitialize( hProcess, NULL, FALSE )) {
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
StackFrame32To64(StackFrame32, &StackFrame);
|
|
|
|
switch (MachineType) {
|
|
case IMAGE_FILE_MACHINE_I386:
|
|
rval = WalkX86( hProcess,
|
|
hThread,
|
|
&StackFrame,
|
|
ContextRecord,
|
|
ReadMemory,
|
|
FunctionTableAccess,
|
|
GetModuleBase,
|
|
TranslateAddress,
|
|
0
|
|
);
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_ALPHA:
|
|
rval = WalkAlpha( hProcess,
|
|
&StackFrame,
|
|
ContextRecord,
|
|
ReadMemory,
|
|
GetModuleBase,
|
|
FunctionTableAccess,
|
|
FALSE
|
|
);
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_IA64:
|
|
case IMAGE_FILE_MACHINE_ALPHA64:
|
|
case IMAGE_FILE_MACHINE_AMD64:
|
|
default:
|
|
rval = FALSE;
|
|
break;
|
|
}
|
|
if (rval) {
|
|
StackFrame64To32(&StackFrame, StackFrame32);
|
|
}
|
|
|
|
return rval;
|
|
}
|
|
|
|
|
|
BOOL
|
|
StackWalk64(
|
|
DWORD MachineType,
|
|
HANDLE hProcess,
|
|
HANDLE hThread,
|
|
LPSTACKFRAME64 StackFrame,
|
|
LPVOID ContextRecord,
|
|
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
|
|
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
|
|
PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
|
|
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
|
|
)
|
|
{
|
|
BOOL rval;
|
|
BOOL UseSym = FALSE;
|
|
|
|
g.MachineType = MachineType;
|
|
if (!FunctionTableAccess) {
|
|
FunctionTableAccess = FunctionTableAccessRoutineLocal;
|
|
UseSym = TRUE;
|
|
}
|
|
|
|
if (!GetModuleBase) {
|
|
GetModuleBase = GetModuleBaseRoutineLocal;
|
|
UseSym = TRUE;
|
|
}
|
|
|
|
if (!ReadMemory) {
|
|
ReadMemory = ReadMemoryRoutineLocal;
|
|
}
|
|
|
|
if (!TranslateAddress) {
|
|
TranslateAddress = TranslateAddressRoutineLocal;
|
|
}
|
|
|
|
if (UseSym) {
|
|
//
|
|
// We are using the code in symbols.c
|
|
// hProcess better be a real valid process handle
|
|
//
|
|
|
|
//
|
|
// Always call syminitialize. It's a nop if process
|
|
// is already loaded.
|
|
//
|
|
if (!SymInitialize( hProcess, NULL, FALSE )) {
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
switch (MachineType) {
|
|
case IMAGE_FILE_MACHINE_I386:
|
|
rval = WalkX86( hProcess,
|
|
hThread,
|
|
StackFrame,
|
|
ContextRecord,
|
|
ReadMemory,
|
|
FunctionTableAccess,
|
|
GetModuleBase,
|
|
TranslateAddress,
|
|
WALK_FIX_FPO_EBP
|
|
);
|
|
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_IA64:
|
|
rval = WalkIa64( hProcess,
|
|
StackFrame,
|
|
ContextRecord,
|
|
ReadMemory,
|
|
FunctionTableAccess,
|
|
GetModuleBase
|
|
);
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_ALPHA:
|
|
rval = WalkAlpha( hProcess,
|
|
StackFrame,
|
|
ContextRecord,
|
|
ReadMemory,
|
|
GetModuleBase,
|
|
FunctionTableAccess,
|
|
FALSE
|
|
);
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_ALPHA64:
|
|
rval = WalkAlpha( hProcess,
|
|
StackFrame,
|
|
ContextRecord,
|
|
ReadMemory,
|
|
GetModuleBase,
|
|
FunctionTableAccess,
|
|
TRUE
|
|
);
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_AMD64:
|
|
rval = WalkAmd64( hProcess,
|
|
StackFrame,
|
|
ContextRecord,
|
|
ReadMemory,
|
|
FunctionTableAccess,
|
|
GetModuleBase
|
|
);
|
|
break;
|
|
|
|
default:
|
|
rval = FALSE;
|
|
break;
|
|
}
|
|
|
|
return rval;
|
|
}
|
|
|
|
BOOL
|
|
ReadMemoryRoutineLocal(
|
|
HANDLE hProcess,
|
|
DWORD64 qwBaseAddress,
|
|
LPVOID lpBuffer,
|
|
DWORD nSize,
|
|
LPDWORD lpNumberOfBytesRead
|
|
)
|
|
{
|
|
// ReadProcessMemory will fail if any part of the
|
|
// region to read does not have read access. This
|
|
// routine attempts to read the largest valid prefix
|
|
// so it has to break up reads on page boundaries.
|
|
|
|
BOOL Status = TRUE;
|
|
SIZE_T TotalBytesRead = 0;
|
|
SIZE_T Read;
|
|
ULONG ReadSize;
|
|
|
|
while (nSize > 0) {
|
|
|
|
// Calculate bytes to read and don't let read cross
|
|
// a page boundary.
|
|
ReadSize = PAGE_SIZE - (ULONG)(qwBaseAddress & (PAGE_SIZE - 1));
|
|
ReadSize = min(nSize, ReadSize);
|
|
|
|
if (!ReadProcessMemory(hProcess, (PVOID)(ULONG_PTR)qwBaseAddress,
|
|
lpBuffer, ReadSize, &Read)) {
|
|
if (TotalBytesRead == 0) {
|
|
// If we haven't read anything indicate failure.
|
|
Status = FALSE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
TotalBytesRead += Read;
|
|
qwBaseAddress += Read;
|
|
lpBuffer = (PVOID)((PUCHAR)lpBuffer + Read);
|
|
nSize -= (DWORD)Read;
|
|
}
|
|
|
|
*lpNumberOfBytesRead = (DWORD)TotalBytesRead;
|
|
return Status;
|
|
}
|
|
|
|
LPVOID
|
|
FunctionTableAccessRoutineLocal(
|
|
HANDLE hProcess,
|
|
DWORD64 AddrBase
|
|
)
|
|
{
|
|
return SymFunctionTableAccess64(hProcess, AddrBase);
|
|
}
|
|
|
|
DWORD64
|
|
GetModuleBaseRoutineLocal(
|
|
HANDLE hProcess,
|
|
DWORD64 ReturnAddress
|
|
)
|
|
{
|
|
IMAGEHLP_MODULE64 ModuleInfo = {0};
|
|
ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
|
|
|
|
if (SymGetModuleInfo64(hProcess, ReturnAddress, &ModuleInfo)) {
|
|
return ModuleInfo.BaseOfImage;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
DWORD64
|
|
TranslateAddressRoutineLocal(
|
|
HANDLE hProcess,
|
|
HANDLE hThread,
|
|
LPADDRESS64 paddr
|
|
)
|
|
{
|
|
return 0;
|
|
}
|