Windows2000/private/sdktools/imagehlp/walki64.c
2020-09-30 17:12:32 +02:00

440 lines
15 KiB
C

/*++
Copyright (c) 1996 Intel Corporation
Copyright (c) 1993 Microsoft Corporation
Module Name:
walki64.c
Abstract:
This file implements the IA64 stack walking api.
Environment:
User Mode
--*/
#define _IMAGEHLP_SOURCE_
#define _IA64REG_
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include "private.h"
#define NOEXTAPI
#include "wdbgexts.h"
#include "ntdbg.h"
#include "symbols.h"
#include <stdlib.h>
BOOL
WalkIa64Init(
HANDLE hProcess,
LPSTACKFRAME64 StackFrame,
PIA64_CONTEXT Context,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
PGET_MODULE_BASE_ROUTINE64 GetModuleBase
);
BOOL
WalkIa64Next(
HANDLE hProcess,
LPSTACKFRAME64 StackFrame,
PIA64_CONTEXT Context,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
PGET_MODULE_BASE_ROUTINE64 GetModuleBase
);
BOOL
GetStackFrameIa64(
HANDLE hProcess,
PULONG64 ReturnAddress,
PULONG64 FramePointer,
PULONG64 BStorePointer,
PIA64_CONTEXT Context,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
PGET_MODULE_BASE_ROUTINE64 GetModuleBase
);
#define CALLBACK_STACK(f) (f->KdHelp.ThCallbackStack)
#define CALLBACK_BSTORE(f) (f->KdHelp.ThCallbackBStore)
#define CALLBACK_NEXT(f) (f->KdHelp.NextCallback)
#define CALLBACK_FUNC(f) (f->KdHelp.KiCallUserMode)
#define CALLBACK_THREAD(f) (f->KdHelp.Thread)
ULONGLONG GetImageBase (HANDLE hProcess, ULONG64 ControlPc)
{
PPROCESS_ENTRY ProcessEntry;
PMODULE_ENTRY mi;
__try {
ProcessEntry = FindProcessEntry( hProcess );
if (!ProcessEntry) {
SetLastError( ERROR_INVALID_HANDLE );
return (ULONGLONG) NULL;
}
mi = GetModuleForPC( ProcessEntry, ControlPc, FALSE );
if (mi == NULL) {
SetLastError( ERROR_MOD_NOT_FOUND );
return (ULONGLONG) NULL;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
return (ULONGLONG) NULL;
}
return (mi->BaseOfDll);
}
WalkIa64(
HANDLE hProcess,
LPSTACKFRAME64 StackFrame,
PIA64_CONTEXT Context,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
PGET_MODULE_BASE_ROUTINE64 GetModuleBase
)
{
BOOL rval;
if (StackFrame->Virtual) {
rval = WalkIa64Next( hProcess, StackFrame, Context, ReadMemory, FunctionTableAccess, GetModuleBase);
} else {
rval = WalkIa64Init( hProcess, StackFrame, Context, ReadMemory, FunctionTableAccess, GetModuleBase);
}
return rval;
}
ULONGLONG
VirtualUnwindIa64 (
HANDLE hProcess,
ULONGLONG ImageBase,
DWORD64 ControlPc,
PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY FunctionEntry,
PIA64_CONTEXT ContextRecord,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory
);
BOOL
GetStackFrameIa64(
HANDLE hProcess,
PULONG64 ReturnAddress,
PULONG64 FramePointer,
PULONG64 BStorePointer,
PIA64_CONTEXT Context,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
PGET_MODULE_BASE_ROUTINE64 GetModuleBase
)
{
ULONGLONG ImageBase;
PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY rf;
ULONG64 dwRa = (ULONG64)Context->BrRp;
BOOL rval = TRUE;
rf = (PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY) FunctionTableAccess( hProcess, *ReturnAddress );
if (rf) {
// The Rp value coming out of mainCRTStartup is set by some run-time
// routine to be 0; this serves to cause an error if someone actually
// does a return from the mainCRTStartup frame.
ImageBase = GetModuleBase (hProcess, *ReturnAddress);
dwRa = (ULONG64)VirtualUnwindIa64( hProcess, ImageBase, *ReturnAddress, rf, Context, ReadMemory );
if (!dwRa) {
rval = FALSE;
}
if ((dwRa == *ReturnAddress) && (*FramePointer == Context->IntSp) && (*(FramePointer+1) == Context->RsBSP)) {
rval = FALSE;
}
*ReturnAddress = dwRa;
*FramePointer = Context->IntSp;
*BStorePointer = Context->RsBSP;
} else {
SHORT BsFrameSize;
SHORT TempFrameSize;
if ((dwRa == *ReturnAddress) && (*FramePointer == Context->IntSp) && (*(FramePointer+1) == Context->RsBSP)) {
rval = FALSE;
}
*ReturnAddress = Context->BrRp;
*FramePointer = Context->IntSp;
*BStorePointer = Context->RsBSP;
Context->StIFS = Context->RsPFS;
BsFrameSize = (SHORT)(Context->StIFS >> IA64_PFS_SIZE_SHIFT) & IA64_PFS_SIZE_MASK;
TempFrameSize = BsFrameSize - (SHORT)((Context->RsBSP >> 3) & IA64_NAT_BITS_PER_RNAT_REG);
while (TempFrameSize > 0) {
BsFrameSize++;
TempFrameSize -= IA64_NAT_BITS_PER_RNAT_REG;
}
Context->RsBSPSTORE = Context->RsBSP -= BsFrameSize * sizeof(ULONGLONG);
}
return rval;
}
BOOL
WalkIa64Init(
HANDLE hProcess,
LPSTACKFRAME64 StackFrame,
PIA64_CONTEXT Context,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
PGET_MODULE_BASE_ROUTINE64 GetModuleBase
)
{
IA64_KSWITCH_FRAME SwitchFrame;
IA64_CONTEXT ContextSave;
DWORD64 PcOffset;
DWORD64 FrameOffset;
DWORD64 BStoreOffset;
DWORD cb;
ULONG Index;
BOOL Result;
if (StackFrame->AddrFrame.Offset) {
if (ReadMemory( hProcess,
StackFrame->AddrFrame.Offset+IA64_STACK_SCRATCH_AREA,
&SwitchFrame,
sizeof(IA64_KSWITCH_FRAME),
&cb )) {
SHORT BsFrameSize;
SHORT TempFrameSize;
// successfully read a switch frame from the stack
Context->IntSp = StackFrame->AddrFrame.Offset;
Context->Preds = SwitchFrame.SwitchPredicates;
Context->StIIP = SwitchFrame.SwitchRp;
Context->StFPSR = SwitchFrame.SwitchFPSR;
Context->BrRp = SwitchFrame.SwitchRp;
Context->RsPFS = SwitchFrame.SwitchPFS;
Context->StIFS = SwitchFrame.SwitchPFS;
BsFrameSize = (SHORT)(SwitchFrame.SwitchPFS >> IA64_PFS_SIZE_SHIFT) & IA64_PFS_SIZE_MASK;
TempFrameSize = BsFrameSize - (SHORT)((SwitchFrame.SwitchBsp >> 3) & IA64_NAT_BITS_PER_RNAT_REG);
while (TempFrameSize > 0) {
BsFrameSize++;
TempFrameSize -= IA64_NAT_BITS_PER_RNAT_REG;
}
Context->RsBSP = SwitchFrame.SwitchBsp - BsFrameSize * sizeof(ULONGLONG);
Context->FltS0 = SwitchFrame.SwitchExceptionFrame.FltS0;
Context->FltS1 = SwitchFrame.SwitchExceptionFrame.FltS1;
Context->FltS2 = SwitchFrame.SwitchExceptionFrame.FltS2;
Context->FltS3 = SwitchFrame.SwitchExceptionFrame.FltS3;
Context->FltS4 = SwitchFrame.SwitchExceptionFrame.FltS4;
Context->FltS5 = SwitchFrame.SwitchExceptionFrame.FltS5;
Context->FltS6 = SwitchFrame.SwitchExceptionFrame.FltS6;
Context->FltS7 = SwitchFrame.SwitchExceptionFrame.FltS7;
Context->FltS8 = SwitchFrame.SwitchExceptionFrame.FltS8;
Context->FltS9 = SwitchFrame.SwitchExceptionFrame.FltS9;
Context->FltS10 = SwitchFrame.SwitchExceptionFrame.FltS10;
Context->FltS11 = SwitchFrame.SwitchExceptionFrame.FltS11;
Context->FltS12 = SwitchFrame.SwitchExceptionFrame.FltS12;
Context->FltS13 = SwitchFrame.SwitchExceptionFrame.FltS13;
Context->FltS14 = SwitchFrame.SwitchExceptionFrame.FltS14;
Context->FltS15 = SwitchFrame.SwitchExceptionFrame.FltS15;
Context->FltS16 = SwitchFrame.SwitchExceptionFrame.FltS16;
Context->FltS17 = SwitchFrame.SwitchExceptionFrame.FltS17;
Context->FltS18 = SwitchFrame.SwitchExceptionFrame.FltS18;
Context->FltS19 = SwitchFrame.SwitchExceptionFrame.FltS19;
Context->IntS0 = SwitchFrame.SwitchExceptionFrame.IntS0;
Context->IntS1 = SwitchFrame.SwitchExceptionFrame.IntS1;
Context->IntS2 = SwitchFrame.SwitchExceptionFrame.IntS2;
Context->IntS3 = SwitchFrame.SwitchExceptionFrame.IntS3;
Context->IntNats = SwitchFrame.SwitchExceptionFrame.IntNats;
Context->BrS0 = SwitchFrame.SwitchExceptionFrame.BrS0;
Context->BrS1 = SwitchFrame.SwitchExceptionFrame.BrS1;
Context->BrS2 = SwitchFrame.SwitchExceptionFrame.BrS2;
Context->BrS3 = SwitchFrame.SwitchExceptionFrame.BrS3;
Context->BrS4 = SwitchFrame.SwitchExceptionFrame.BrS4;
Context->ApEC = SwitchFrame.SwitchExceptionFrame.ApEC;
Context->ApLC = SwitchFrame.SwitchExceptionFrame.ApLC;
} else {
return FALSE;
}
}
ZeroMemory( StackFrame, sizeof(*StackFrame) );
StackFrame->Virtual = TRUE;
StackFrame->AddrPC.Offset = Context->StIIP;
StackFrame->AddrPC.Mode = AddrModeFlat;
StackFrame->AddrFrame.Offset = Context->IntSp;
StackFrame->AddrFrame.Mode = AddrModeFlat;
StackFrame->AddrBStore.Offset = Context->RsBSP;
StackFrame->AddrBStore.Mode = AddrModeFlat;
ContextSave = *Context;
PcOffset = StackFrame->AddrPC.Offset;
FrameOffset = StackFrame->AddrFrame.Offset;
BStoreOffset = StackFrame->AddrBStore.Offset;
if (!GetStackFrameIa64( hProcess,
&PcOffset,
&FrameOffset,
&BStoreOffset,
&ContextSave,
ReadMemory,
FunctionTableAccess,
GetModuleBase) ) {
StackFrame->AddrReturn.Offset = Context->BrRp;
} else {
StackFrame->AddrReturn.Offset = PcOffset;
}
StackFrame->AddrReturn.Mode = AddrModeFlat;
// get the arguments to the function
Index = (ULONG)(ContextSave.RsBSP & 0x1F8) >> 3;
if (Index > 59) {
DWORD i, j;
DWORD64 Params[5];
Result = ReadMemory (hProcess, ContextSave.RsBSP, Params, 40, &cb);
if (Result) {
j = 0;
for (i = 0; i < 5; i++, Index++) {
if (Index != 63) {
StackFrame->Params[j++] = Params[i];
}
}
}
} else {
Result = ReadMemory (hProcess, ContextSave.RsBSP, StackFrame->Params, 32, &cb);
}
if (!Result) {
StackFrame->Params[0] =
StackFrame->Params[1] =
StackFrame->Params[2] =
StackFrame->Params[3] = 0;
}
return TRUE;
}
BOOL
WalkIa64Next(
HANDLE hProcess,
LPSTACKFRAME64 StackFrame,
PIA64_CONTEXT Context,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccess,
PGET_MODULE_BASE_ROUTINE64 GetModuleBase
)
{
DWORD cb;
IA64_CONTEXT ContextSave;
BOOL rval = TRUE;
BOOL Result;
DWORD64 StackAddress;
DWORD64 BStoreAddress;
PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY rf;
DWORD64 qw;
ULONG Index;
if (!GetStackFrameIa64( hProcess,
&StackFrame->AddrPC.Offset,
&StackFrame->AddrFrame.Offset,
&StackFrame->AddrBStore.Offset,
Context,
ReadMemory,
FunctionTableAccess,
GetModuleBase) ) {
rval = FALSE;
// If the frame could not be unwound or is terminal, see if
// there is a callback frame:
if (AppVersion.Revision >= 4 && CALLBACK_STACK(StackFrame)) {
if (CALLBACK_STACK(StackFrame) & 0x80000000) {
// it is the pointer to the stack frame that we want
StackAddress = CALLBACK_STACK(StackFrame);
} else {
// if it is a positive integer, it is the offset to
// the address in the thread.
// Look up the pointer:
rval = ReadMemory(hProcess,
(CALLBACK_THREAD(StackFrame) + CALLBACK_STACK(StackFrame)),
&StackAddress,
sizeof(DWORD64),
&cb);
if (!rval || StackAddress == 0) {
StackAddress = (DWORD64)-1;
CALLBACK_STACK(StackFrame) = (DWORD)-1;
}
}
if ( (StackAddress == (DWORD64)-1) ||
!(rf = (PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY)FunctionTableAccess(hProcess, CALLBACK_FUNC(StackFrame))) ) {
rval = FALSE;
} else {
ReadMemory(hProcess,
(StackAddress + CALLBACK_NEXT(StackFrame)),
&CALLBACK_STACK(StackFrame),
sizeof(DWORD64),
&cb);
StackFrame->AddrPC.Offset = rf->BeginAddress; // ?????
StackFrame->AddrFrame.Offset = StackAddress;
Context->IntSp = StackAddress;
rval = TRUE;
}
}
}
// get the return address
ContextSave = *Context;
StackFrame->AddrReturn.Offset = StackFrame->AddrPC.Offset;
if (!GetStackFrameIa64( hProcess,
&StackFrame->AddrReturn.Offset,
&qw,
&qw,
&ContextSave,
ReadMemory,
FunctionTableAccess,
GetModuleBase) ) {
StackFrame->AddrReturn.Offset = 0;
}
// get the arguments to the function
Index = (ULONG)(ContextSave.RsBSP & 0x1F8) >> 3;
if (Index > 59) {
DWORD i, j;
DWORD64 Params[5];
Result = ReadMemory (hProcess, ContextSave.RsBSP, Params, 40, &cb);
if (Result) {
j = 0;
for (i = 0; i < 5; i++, Index++) {
if (Index != 63) {
StackFrame->Params[j++] = Params[i];
}
}
}
} else {
Result = ReadMemory (hProcess, ContextSave.RsBSP, StackFrame->Params, 32, &cb);
}
if (!Result) {
StackFrame->Params[0] =
StackFrame->Params[1] =
StackFrame->Params[2] =
StackFrame->Params[3] = 0;
}
return rval;
}