|
|
/*++
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; }
|