NT4/private/sdktools/imagehlp/walkppc.c
2020-09-30 17:12:29 +02:00

384 lines
12 KiB
C

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
walkppc.c
Abstract:
This file implements the PPC stack walking api.
Author:
Wesley Witt (wesw) 1-Oct-1993
Environment:
User Mode
Revision History:
Tom Wood (twood) 19-Aug-1994
Update to use VirtualUnwind even when there isn't a function table entry.
Add stack limit parameters to RtlVirtualUnwind.
--*/
#define TARGET_PPC
#define _IMAGEHLP_SOURCE_
#define ARG_AREA_OFFSET 24 // bytes for glue link area etc.
#define _CROSS_PLATFORM_
//
// The following defines are used to acquire the initial context for
// for a thread when stack tracing a thread other than the current thread.
// It is based on the fact that the thread relinquished control in
// ContextSwap (..\ntos\ke\ppc\ctxswap.s)
#define STK_MIN_FRAME 14*sizeof(ULONG)
#include "walk.h"
#include "private.h"
#include <stdlib.h>
BOOL
WalkPpcInit(
HANDLE hProcess,
LPSTACKFRAME StackFrame,
PCONTEXT Context,
PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine,
PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine
);
BOOL
WalkPpcNext(
HANDLE hProcess,
LPSTACKFRAME StackFrame,
PCONTEXT Context,
PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine,
PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine
);
BOOL
WalkPpcGetStackFrame(
HANDLE hProcess,
LPDWORD ReturnAddress,
LPDWORD FramePointer,
PCONTEXT Context,
PREAD_PROCESS_MEMORY_ROUTINE ReadMemory,
PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccess
);
#define CALLBACK_STACK(f) (f->KdHelp.ThCallbackStack)
#define CALLBACK_NEXT(f) (f->KdHelp.NextCallback)
#define CALLBACK_FUNC(f) (f->KdHelp.KiCallUserMode)
#define CALLBACK_THREAD(f) (f->KdHelp.Thread)
BOOL
WalkPpc(
HANDLE hProcess,
LPSTACKFRAME StackFrame,
PCONTEXT Context,
PREAD_PROCESS_MEMORY_ROUTINE ReadMemory,
PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccess
)
{
BOOL rval;
if (StackFrame->Virtual) {
rval = WalkPpcNext( hProcess,
StackFrame,
Context,
ReadMemory,
FunctionTableAccess
);
} else {
rval = WalkPpcInit( hProcess,
StackFrame,
Context,
ReadMemory,
FunctionTableAccess
);
}
return rval;
}
#define RtlVirtualUnwind VirtualUnwind
#define PRUNTIME_FUNCTION PIMAGE_RUNTIME_FUNCTION_ENTRY
#define RUNTIME_FUNCTION IMAGE_RUNTIME_FUNCTION_ENTRY
#define RtlLookupFunctionEntry(pc) FunctionTableAccess(hProcess,pc)
#define READ_ULONG(pc,dest) \
if (ReadMemory(hProcess, (LPVOID)(pc), &(dest), 4L, &ImagehlpCb) == 0) { \
(dest) = 0; \
}
#define READ_DOUBLE(pc,dest) \
if (ReadMemory(hProcess, (LPVOID)(pc), &(dest), 8L, &ImagehlpCb) == 0) { \
(dest) = 0; \
}
#include "ppc\vunwind.c"
BOOL
WalkPpcGetStackFrame(
HANDLE hProcess,
LPDWORD ReturnAddress,
LPDWORD FramePointer,
PCONTEXT Context,
PREAD_PROCESS_MEMORY_ROUTINE ReadMemory,
PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccess
)
{
DWORD NextPc;
NextPc = VirtualUnwind(hProcess,
*ReturnAddress,
(PIMAGE_RUNTIME_FUNCTION_ENTRY) FunctionTableAccess(hProcess, *ReturnAddress),
Context,
ReadMemory,
FunctionTableAccess);
if (NextPc == 0 ||
NextPc == 1 ||
(NextPc == *ReturnAddress && *FramePointer == Context->Gpr1))
return FALSE;
*ReturnAddress = NextPc;
*FramePointer = Context->Gpr1;
return TRUE;
}
BOOL
WalkPpcInit(
HANDLE hProcess,
LPSTACKFRAME StackFrame,
PCONTEXT Context,
PREAD_PROCESS_MEMORY_ROUTINE ReadMemory,
PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccess
)
{
KSWAP_FRAME ContextSwapFrame;
CONTEXT ContextSave;
DWORD PcOffset;
DWORD FrameOffset;
DWORD cb;
if (StackFrame->AddrFrame.Offset) {
if (ReadMemory( hProcess,
(LPVOID)((ULONG)StackFrame->AddrFrame.Offset + STK_MIN_FRAME),
&ContextSwapFrame,
sizeof(KSWAP_FRAME),
&cb )) {
//
// successfully read an swap frame from the stack
//
Context->Gpr1 = StackFrame->AddrFrame.Offset;
Context->Gpr15 = ContextSwapFrame.ExceptionFrame.Gpr15;
Context->Gpr16 = ContextSwapFrame.ExceptionFrame.Gpr16;
Context->Gpr17 = ContextSwapFrame.ExceptionFrame.Gpr17;
Context->Gpr18 = ContextSwapFrame.ExceptionFrame.Gpr18;
Context->Gpr19 = ContextSwapFrame.ExceptionFrame.Gpr19;
Context->Gpr20 = ContextSwapFrame.ExceptionFrame.Gpr20;
Context->Gpr21 = ContextSwapFrame.ExceptionFrame.Gpr21;
Context->Gpr22 = ContextSwapFrame.ExceptionFrame.Gpr22;
Context->Gpr23 = ContextSwapFrame.ExceptionFrame.Gpr23;
Context->Gpr24 = ContextSwapFrame.ExceptionFrame.Gpr24;
Context->Gpr25 = ContextSwapFrame.ExceptionFrame.Gpr25;
Context->Fpr14 = ContextSwapFrame.ExceptionFrame.Fpr14;
Context->Fpr15 = ContextSwapFrame.ExceptionFrame.Fpr15;
Context->Fpr16 = ContextSwapFrame.ExceptionFrame.Fpr16;
Context->Fpr17 = ContextSwapFrame.ExceptionFrame.Fpr17;
Context->Fpr18 = ContextSwapFrame.ExceptionFrame.Fpr18;
Context->Fpr19 = ContextSwapFrame.ExceptionFrame.Fpr19;
Context->Fpr20 = ContextSwapFrame.ExceptionFrame.Fpr20;
Context->Fpr21 = ContextSwapFrame.ExceptionFrame.Fpr21;
Context->Fpr22 = ContextSwapFrame.ExceptionFrame.Fpr22;
Context->Fpr23 = ContextSwapFrame.ExceptionFrame.Fpr23;
Context->Fpr24 = ContextSwapFrame.ExceptionFrame.Fpr24;
Context->Fpr25 = ContextSwapFrame.ExceptionFrame.Fpr25;
Context->Fpr26 = ContextSwapFrame.ExceptionFrame.Fpr26;
Context->Fpr27 = ContextSwapFrame.ExceptionFrame.Fpr27;
Context->Fpr28 = ContextSwapFrame.ExceptionFrame.Fpr28;
Context->Fpr29 = ContextSwapFrame.ExceptionFrame.Fpr29;
Context->Fpr30 = ContextSwapFrame.ExceptionFrame.Fpr30;
Context->Fpr31 = ContextSwapFrame.ExceptionFrame.Fpr31;
Context->Iar = ContextSwapFrame.SwapReturn;
Context->Cr = ContextSwapFrame.ConditionRegister;
} else {
return FALSE;
}
}
ZeroMemory( StackFrame, sizeof(*StackFrame) );
StackFrame->Virtual = TRUE;
StackFrame->AddrPC.Offset = Context->Iar;
StackFrame->AddrPC.Mode = AddrModeFlat;
StackFrame->AddrFrame.Offset = Context->Gpr1;
StackFrame->AddrFrame.Mode = AddrModeFlat;
ContextSave = *Context;
PcOffset = StackFrame->AddrPC.Offset;
FrameOffset = StackFrame->AddrFrame.Offset;
if (!WalkPpcGetStackFrame( hProcess,
&PcOffset,
&FrameOffset,
&ContextSave,
ReadMemory,
FunctionTableAccess ) ) {
StackFrame->AddrReturn.Offset = Context->Lr;
} else {
StackFrame->AddrReturn.Offset = PcOffset;
}
StackFrame->AddrReturn.Mode = AddrModeFlat;
//
// get the arguments to the function
//
if (!ReadMemory( hProcess, (LPVOID)(ContextSave.Gpr1 + ARG_AREA_OFFSET),
StackFrame->Params, 16, &cb )) {
StackFrame->Params[0] =
StackFrame->Params[1] =
StackFrame->Params[2] =
StackFrame->Params[3] = 0;
}
return TRUE;
}
BOOL
WalkPpcNext(
HANDLE hProcess,
LPSTACKFRAME StackFrame,
PCONTEXT Context,
PREAD_PROCESS_MEMORY_ROUTINE ReadMemory,
PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccess
)
{
DWORD cb;
CONTEXT ContextSave;
BOOL rval = TRUE;
DWORD Address;
PIMAGE_RUNTIME_FUNCTION_ENTRY rf;
if (!WalkPpcGetStackFrame( hProcess,
&StackFrame->AddrPC.Offset,
&StackFrame->AddrFrame.Offset,
Context,
ReadMemory,
FunctionTableAccess ) ) {
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,
// or -1.
Address = 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,
(PVOID)(CALLBACK_THREAD(StackFrame) +
CALLBACK_STACK(StackFrame)),
&Address,
sizeof(DWORD),
&cb);
if (!rval || Address == 0) {
Address = 0xffffffff;
CALLBACK_STACK(StackFrame) = 0xffffffff;
}
}
if ((Address == 0xffffffff) ||
!(rf = (PIMAGE_RUNTIME_FUNCTION_ENTRY)
FunctionTableAccess(hProcess, CALLBACK_FUNC(StackFrame))) ) {
rval = FALSE;
} else {
ReadMemory(hProcess,
(PVOID)(Address + CALLBACK_NEXT(StackFrame)),
&CALLBACK_STACK(StackFrame),
sizeof(DWORD),
&cb);
StackFrame->AddrPC.Offset = rf->PrologEndAddress;
StackFrame->AddrFrame.Offset = Address;
Context->Gpr1 = Address;
rval = TRUE;
}
}
}
//
// get the return address
//
ContextSave = *Context;
StackFrame->AddrReturn.Offset = StackFrame->AddrPC.Offset;
if (!WalkPpcGetStackFrame( hProcess,
&StackFrame->AddrReturn.Offset,
&cb,
&ContextSave,
ReadMemory,
FunctionTableAccess ) ) {
StackFrame->AddrReturn.Offset = 0;
}
//
// get the arguments to the function
//
if (!ReadMemory( hProcess, (LPVOID)(ContextSave.Gpr1+ ARG_AREA_OFFSET),
StackFrame->Params, 16, &cb )) {
StackFrame->Params[0] =
StackFrame->Params[1] =
StackFrame->Params[2] =
StackFrame->Params[3] = 0;
}
return rval;
}