windows-nt/Source/XPSP1/NT/sdktools/debuggers/imagehlp/walk.c
2020-09-26 16:20:57 +08:00

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