windows-nt/Source/XPSP1/NT/sdktools/debuggers/ntsd64/stkwalk.cpp
2020-09-26 16:20:57 +08:00

1081 lines
30 KiB
C++

//----------------------------------------------------------------------------
//
// Stack walking support.
//
// Copyright (C) Microsoft Corporation, 1997-2001.
//
//----------------------------------------------------------------------------
#include "ntsdp.hpp"
IMAGE_IA64_RUNTIME_FUNCTION_ENTRY g_EpcRfeBuffer;
PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY g_EpcRfe;
PFPO_DATA
SynthesizeKnownFpo(PSTR Symbol, ULONG64 OffStart, ULONG64 Disp)
{
static ULONG64 s_Nr2, s_Lu2, s_Eh3, s_Kuit;
if (!s_Nr2 || !s_Lu2 || !s_Eh3 || !s_Kuit)
{
GetOffsetFromSym("nt!_NLG_Return2", &s_Nr2, NULL);
GetOffsetFromSym("nt!_local_unwind2", &s_Lu2, NULL);
GetOffsetFromSym("nt!_except_handler3", &s_Eh3, NULL);
GetOffsetFromSym("nt!KiUnexpectedInterruptTail", &s_Kuit, NULL);
}
if (OffStart == s_Nr2 || OffStart == s_Lu2)
{
static FPO_DATA s_Lu2Fpo;
s_Lu2Fpo.ulOffStart = (ULONG)OffStart;
s_Lu2Fpo.cbProcSize = 0x68;
s_Lu2Fpo.cdwLocals = 4;
s_Lu2Fpo.cdwParams = 0;
s_Lu2Fpo.cbProlog = 0;
s_Lu2Fpo.cbRegs = 3;
s_Lu2Fpo.fHasSEH = 0;
s_Lu2Fpo.fUseBP = 0;
s_Lu2Fpo.reserved = 0;
s_Lu2Fpo.cbFrame = FRAME_FPO;
return &s_Lu2Fpo;
}
else if (OffStart == s_Eh3)
{
static FPO_DATA s_Eh3Fpo;
s_Eh3Fpo.ulOffStart = (ULONG)OffStart;
s_Eh3Fpo.cbProcSize = 0xbd;
s_Eh3Fpo.cdwLocals = 2;
s_Eh3Fpo.cdwParams = 4;
s_Eh3Fpo.cbProlog = 3;
s_Eh3Fpo.cbRegs = 4;
s_Eh3Fpo.fHasSEH = 0;
s_Eh3Fpo.fUseBP = 0;
s_Eh3Fpo.reserved = 0;
s_Eh3Fpo.cbFrame = FRAME_NONFPO;
return &s_Eh3Fpo;
}
else if (OffStart == s_Kuit)
{
//
// KiUnexpectedInterruptTail has three special stubs
// following it for CommonDispatchException[0-2]Args.
// These stubs set up for the appropriate number of
// arguments and then call CommonDispatchException.
// They do not have symbols or FPO data so fake some
// up if we're in the region immediately after KUIT.
//
PFPO_DATA KuitData = (PFPO_DATA)
SymFunctionTableAccess(g_CurrentProcess->Handle, OffStart);
if (KuitData != NULL &&
Disp >= (ULONG64)KuitData->cbProcSize &&
Disp < (ULONG64)KuitData->cbProcSize + 0x20)
{
static FPO_DATA s_CdeStubFpo;
s_CdeStubFpo.ulOffStart = (ULONG)OffStart;
s_CdeStubFpo.cbProcSize = 0x10;
s_CdeStubFpo.cdwLocals = 0;
s_CdeStubFpo.cdwParams = 0;
s_CdeStubFpo.cbProlog = 0;
s_CdeStubFpo.cbRegs = 0;
s_CdeStubFpo.fHasSEH = 0;
s_CdeStubFpo.fUseBP = 0;
s_CdeStubFpo.reserved = 0;
s_CdeStubFpo.cbFrame = FRAME_TRAP;
return &s_CdeStubFpo;
}
}
return NULL;
}
PFPO_DATA
SynthesizeFpoDataForModule(DWORD64 PCAddr)
{
DWORD64 Offset;
USHORT StdCallArgs;
CHAR symbuf[MAX_SYMBOL_LEN];
GetSymbolStdCall( PCAddr,
symbuf,
sizeof(symbuf),
&Offset,
&StdCallArgs);
if (Offset == PCAddr)
{
// No symbol.
return NULL;
}
PFPO_DATA KnownFpo =
SynthesizeKnownFpo(symbuf, PCAddr - Offset, Offset);
if (KnownFpo != NULL)
{
return KnownFpo;
}
if (StdCallArgs == 0xffff)
{
return NULL;
}
static FPO_DATA s_SynthFpo;
s_SynthFpo.ulOffStart = (ULONG)(PCAddr - Offset);
s_SynthFpo.cbProcSize = (ULONG)(Offset + 10);
s_SynthFpo.cdwLocals = 0;
s_SynthFpo.cdwParams = StdCallArgs;
s_SynthFpo.cbProlog = 0;
s_SynthFpo.cbRegs = 0;
s_SynthFpo.fHasSEH = 0;
s_SynthFpo.fUseBP = 0;
s_SynthFpo.reserved = 0;
s_SynthFpo.cbFrame = FRAME_NONFPO;
return &s_SynthFpo;
}
PFPO_DATA
SynthesizeFpoDataForFastSyscall(ULONG64 Offset)
{
static FPO_DATA s_FastFpo;
// XXX drewb - Temporary until the fake user-shared
// module is worked out.
s_FastFpo.ulOffStart = (ULONG)Offset;
s_FastFpo.cbProcSize = X86_SHARED_SYSCALL_SIZE;
s_FastFpo.cdwLocals = 0;
s_FastFpo.cdwParams = 0;
s_FastFpo.cbProlog = 0;
s_FastFpo.cbRegs = 0;
s_FastFpo.fHasSEH = 0;
s_FastFpo.fUseBP = 0;
s_FastFpo.reserved = 0;
s_FastFpo.cbFrame = FRAME_FPO;
return &s_FastFpo;
}
PFPO_DATA
ModifyFpoRecord(PDEBUG_IMAGE_INFO Image, PFPO_DATA FpoData)
{
if (FpoData->cdwLocals == 80)
{
static ULONG64 s_CommonDispatchException;
// Some versions of CommonDispatchException have
// the wrong locals size, which screws up stack
// traces. Detect and fix up these problems.
if (s_CommonDispatchException == 0)
{
GetOffsetFromSym("nt!CommonDispatchException",
&s_CommonDispatchException,
NULL);
}
if (Image->BaseOfImage + FpoData->ulOffStart ==
s_CommonDispatchException)
{
static FPO_DATA s_CdeFpo;
s_CdeFpo = *FpoData;
s_CdeFpo.cdwLocals = 20;
FpoData = &s_CdeFpo;
}
}
else if (FpoData->cdwLocals == 0 && FpoData->cdwParams == 0 &&
FpoData->cbRegs == 3)
{
static ULONG64 s_KiSwapThread;
// KiSwapThread has shrink-wrapping so that three registers
// are pushed in only a portion of the code. Unfortunately,
// the most important place in the code -- the call to
// KiSwapContext -- is outside of this region and therefore
// the register count is wrong much more often than it's
// correct. Switch the register count to two to make it
// correct more often than wrong.
if (s_KiSwapThread == 0)
{
GetOffsetFromSym("nt!KiSwapThread", &s_KiSwapThread, NULL);
}
if (Image->BaseOfImage + FpoData->ulOffStart ==
s_KiSwapThread)
{
static FPO_DATA s_KstFpo;
s_KstFpo = *FpoData;
s_KstFpo.cbRegs = 2;
FpoData = &s_KstFpo;
}
}
else if (FpoData->fHasSEH)
{
static FPO_DATA s_SehFpo;
s_SehFpo = *FpoData;
s_SehFpo.cbFrame = FRAME_NONFPO;
FpoData = &s_SehFpo;
}
return FpoData;
}
PFPO_DATA
FindFpoDataForModule(DWORD64 PCAddr)
/*++
Routine Description:
Locates the fpo data structure in the process's linked list for the
requested module.
Arguments:
PCAddr - address contained in the program counter
Return Value:
null - could not locate the entry
valid address - found the entry at the adress retured
--*/
{
PPROCESS_INFO Process;
PDEBUG_IMAGE_INFO Image;
PFPO_DATA FpoData;
Process = g_CurrentProcess;
Image = Process->ImageHead;
FpoData = 0;
while (Image)
{
if ((PCAddr >= Image->BaseOfImage) &&
(PCAddr < Image->BaseOfImage + Image->SizeOfImage))
{
FpoData = (PFPO_DATA)
SymFunctionTableAccess(g_CurrentProcess->Handle, PCAddr);
if (!FpoData)
{
FpoData = SynthesizeFpoDataForModule(PCAddr);
}
else
{
FpoData = ModifyFpoRecord(Image, FpoData);
}
return FpoData;
}
Image = Image->Next;
}
ULONG64 FscBase;
switch(IsInFastSyscall(PCAddr, &FscBase))
{
case FSC_FOUND:
return SynthesizeFpoDataForFastSyscall(FscBase);
}
// the function is not part of any known loaded image
return NULL;
}
LPVOID
SwFunctionTableAccess(
HANDLE hProcess,
ULONG64 AddrBase
)
{
static IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY s_Axp32;
static IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY s_Axp64;
static IMAGE_IA64_RUNTIME_FUNCTION_ENTRY s_Ia64;
static _IMAGE_RUNTIME_FUNCTION_ENTRY s_Amd64;
PVOID pife;
if (g_EffMachine == IMAGE_FILE_MACHINE_I386)
{
return (LPVOID)FindFpoDataForModule( AddrBase );
}
pife = SymFunctionTableAccess64(hProcess, AddrBase);
switch (g_EffMachine)
{
case IMAGE_FILE_MACHINE_AXP64:
if (!pife)
{
return NULL;
}
s_Axp64.BeginAddress =
((PIMAGE_FUNCTION_ENTRY64)pife)->StartingAddress;
s_Axp64.EndAddress =
((PIMAGE_FUNCTION_ENTRY64)pife)->EndingAddress;
s_Axp64.ExceptionHandler = 0;
s_Axp64.HandlerData = 0;
s_Axp64.PrologEndAddress =
((PIMAGE_FUNCTION_ENTRY64)pife)->EndOfPrologue;
return &s_Axp64;
case IMAGE_FILE_MACHINE_ALPHA:
if (!pife)
{
return NULL;
}
s_Axp32.BeginAddress =
((PIMAGE_FUNCTION_ENTRY)pife)->StartingAddress;
s_Axp32.EndAddress =
((PIMAGE_FUNCTION_ENTRY)pife)->EndingAddress;
s_Axp32.ExceptionHandler = 0;
s_Axp32.HandlerData = 0;
s_Axp32.PrologEndAddress =
((PIMAGE_FUNCTION_ENTRY)pife)->EndOfPrologue;
return &s_Axp32;
case IMAGE_FILE_MACHINE_IA64:
if (pife)
{
s_Ia64 = *(PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY)pife;
return &s_Ia64;
}
else
{
if (IS_KERNEL_TARGET() &&
(AddrBase >= IA64_MM_EPC_VA) &&
(AddrBase < (IA64_MM_EPC_VA + IA64_PAGE_SIZE)))
{
return g_EpcRfe;
}
else
{
return NULL;
}
}
break;
case IMAGE_FILE_MACHINE_AMD64:
if (pife)
{
s_Amd64 = *(_PIMAGE_RUNTIME_FUNCTION_ENTRY)pife;
return &s_Amd64;
}
break;
}
return NULL;
}
DWORD64
SwTranslateAddress(
HANDLE hProcess,
HANDLE hThread,
LPADDRESS64 lpaddress
)
{
//
// don't support 16bit stacks
//
return 0;
}
BOOL
SwReadMemory32(
HANDLE hProcess,
ULONG dwBaseAddress,
LPVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesRead
)
{
return SwReadMemory(hProcess,
EXTEND64(dwBaseAddress),
lpBuffer,
nSize,
lpNumberOfBytesRead);
}
BOOL
SwReadMemory(
HANDLE hProcess,
ULONG64 BaseAddress,
LPVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesRead
)
{
DBG_ASSERT(hProcess == g_CurrentProcess->Handle);
if (IS_KERNEL_TARGET())
{
DWORD BytesRead;
HRESULT Status;
if ((LONG_PTR)lpNumberOfBytesRead == -1)
{
if (g_TargetMachineType == IMAGE_FILE_MACHINE_I386)
{
BaseAddress += g_TargetMachine->m_SizeTargetContext;
}
Status = g_Target->ReadControl(CURRENT_PROC,
(ULONG)BaseAddress,
lpBuffer,
nSize,
&BytesRead);
return Status == S_OK;
}
}
if (g_Target->ReadVirtual(BaseAddress, lpBuffer, nSize,
lpNumberOfBytesRead) != S_OK)
{
// Make sure bytes read is zero.
if (lpNumberOfBytesRead != NULL)
{
*lpNumberOfBytesRead = 0;
}
return FALSE;
}
else
{
return TRUE;
}
}
DWORD64
SwGetModuleBase(
HANDLE hProcess,
ULONG64 Address
)
{
PDEBUG_IMAGE_INFO Image = g_CurrentProcess->ImageHead;
if (g_EffMachine == IMAGE_FILE_MACHINE_IA64 &&
IS_KERNEL_TARGET() &&
(Address >= IA64_MM_EPC_VA) &&
(Address < (IA64_MM_EPC_VA + IA64_PAGE_SIZE)))
{
Address -= (IA64_MM_EPC_VA - g_SystemCallVirtualAddress);
}
while (Image)
{
if ((Address >= Image->BaseOfImage) &&
(Address < (Image->BaseOfImage + Image->SizeOfImage)))
{
return Image->BaseOfImage;
}
Image = Image->Next;
}
// If no regular module was found we need to look in
// the dynamic function tables to see if an entry
// there matches.
ULONG64 DynBase = g_Target->
GetDynamicFunctionTableBase(g_Machine, Address);
if (DynBase)
{
return DynBase;
}
if (IS_KERNEL_TARGET())
{
// If no modules have been loaded there's still a possibility
// of getting a kernel stack trace (without symbols) by going
// after the module base directly. This also makes it possible
// to get a stack trace when there are no symbols available.
if (g_CurrentProcess->ImageHead == NULL)
{
return GetKernelModuleBase( Address );
}
}
return 0;
}
DWORD
SwGetModuleBase32(
HANDLE hProcess,
DWORD Address
)
{
return (DWORD)SwGetModuleBase(hProcess, Address);
}
void
PrintStackTraceHeaderLine(
ULONG Flags
)
{
if ( (Flags & DEBUG_STACK_COLUMN_NAMES) == 0 )
{
return;
}
StartOutLine(DEBUG_OUTPUT_NORMAL, OUT_LINE_NO_TIMESTAMP);
if (Flags & DEBUG_STACK_FRAME_NUMBERS)
{
dprintf(" # ");
}
if (Flags & DEBUG_STACK_FRAME_ADDRESSES)
{
g_Machine->PrintStackFrameAddressesTitle(Flags);
}
if (Flags & DEBUG_STACK_ARGUMENTS)
{
g_Machine->PrintStackArgumentsTitle(Flags);
}
g_Machine->PrintStackCallSiteTitle(Flags);
dprintf("\n");
}
VOID
PrintStackFrame(
PDEBUG_STACK_FRAME StackFrame,
ULONG Flags
)
{
DWORD64 displacement;
CHAR symbuf[MAX_SYMBOL_LEN];
USHORT StdCallArgs;
ULONG64 InstructionOffset = StackFrame->InstructionOffset;
if (g_EffMachine == IMAGE_FILE_MACHINE_IA64 &&
IS_KERNEL_TARGET() &&
(InstructionOffset >= IA64_MM_EPC_VA) &&
(InstructionOffset < (IA64_MM_EPC_VA + IA64_PAGE_SIZE)))
{
InstructionOffset = InstructionOffset -
(IA64_MM_EPC_VA - g_SystemCallVirtualAddress);
}
GetSymbolStdCall(InstructionOffset,
symbuf,
sizeof(symbuf),
&displacement,
&StdCallArgs);
StartOutLine(DEBUG_OUTPUT_NORMAL, OUT_LINE_NO_TIMESTAMP);
if (Flags & DEBUG_STACK_FRAME_NUMBERS)
{
dprintf("%02lx ", StackFrame->FrameNumber);
}
if (Flags & DEBUG_STACK_FRAME_ADDRESSES)
{
g_Machine->PrintStackFrameAddresses(Flags, StackFrame);
}
if (Flags & DEBUG_STACK_ARGUMENTS)
{
g_Machine->PrintStackArguments(Flags, StackFrame);
}
g_Machine->PrintStackCallSite(Flags, StackFrame,
symbuf, displacement,
StdCallArgs);
if (Flags & DEBUG_STACK_SOURCE_LINE)
{
OutputLineAddr(InstructionOffset, " [%s @ %d]");
}
dprintf( "\n" );
}
VOID
PrintStackTrace(
ULONG NumFrames,
PDEBUG_STACK_FRAME StackFrames,
ULONG Flags
)
{
ULONG i;
PrintStackTraceHeaderLine(Flags);
for (i = 0; i < NumFrames; i++)
{
PrintStackFrame(StackFrames + i, Flags);
}
}
void
GetStkTraceArgsForCurrentScope(
PULONG64 FramePointer,
PULONG64 StackPointer,
PULONG64 InstructionPointer,
PCROSS_PLATFORM_CONTEXT ContextCopyPointer
)
{
PCROSS_PLATFORM_CONTEXT ScopeContext = GetCurrentScopeContext();
if (ScopeContext != NULL)
{
g_Machine->PushContext(ScopeContext);
switch (g_EffMachine)
{
case IMAGE_FILE_MACHINE_I386:
if (*InstructionPointer == 0)
{
*InstructionPointer = g_Machine->GetReg64(X86_EIP);
}
if (*StackPointer == 0)
{
*StackPointer = g_Machine->GetReg64(X86_ESP);
}
if (*FramePointer == 0)
{
*FramePointer = g_Machine->GetReg64(X86_EBP);
}
break;
case IMAGE_FILE_MACHINE_IA64:
*InstructionPointer = g_Machine->GetReg64(STIIP);
*StackPointer = g_Machine->GetReg64(INTSP);
*FramePointer = g_Machine->GetReg64(RSBSP);
break;
case IMAGE_FILE_MACHINE_AXP64:
case IMAGE_FILE_MACHINE_ALPHA:
*InstructionPointer = g_Machine->GetReg64(ALPHA_FIR);
*StackPointer = g_Machine->GetReg64(SP_REG);
*FramePointer = g_Machine->GetReg64(FP_REG);
break;
case IMAGE_FILE_MACHINE_AMD64:
*InstructionPointer = g_Machine->GetReg64(AMD64_RIP);
*StackPointer = g_Machine->GetReg64(AMD64_RSP);
*FramePointer = g_Machine->GetReg64(AMD64_RBP);
break;
default:
break;
}
if (ContextCopyPointer)
{
*ContextCopyPointer = g_Machine->m_Context;
}
g_Machine->PopContext();
}
else
{
if (ContextCopyPointer)
{
*ContextCopyPointer = g_Machine->m_Context;
}
}
}
DWORD
StackTrace(
ULONG64 FramePointer,
ULONG64 StackPointer,
ULONG64 InstructionPointer,
PDEBUG_STACK_FRAME StackFrames,
ULONG NumFrames,
ULONG64 ExtThread,
ULONG Flags,
BOOL EstablishingScope
)
{
STACKFRAME64 VirtualFrame;
DWORD i;
CROSS_PLATFORM_CONTEXT Context;
PVOID FunctionEntry;
ULONG64 Value;
ULONG result;
BOOL SymWarning = FALSE;
ULONG X86Ebp;
if (!EstablishingScope)
{
RequireCurrentScope();
}
//
// let's start clean
//
ZeroMemory( StackFrames, sizeof(StackFrames[0]) * NumFrames );
ZeroMemory( &VirtualFrame, sizeof(VirtualFrame) );
if (g_Machine->GetContextState(MCTX_FULL) != S_OK)
{
return 0;
}
ULONG Seg;
if ((!FramePointer && !InstructionPointer && !StackPointer) ||
(g_EffMachine == IMAGE_FILE_MACHINE_I386))
{
// Do the default stack trace for current debug context
// For x86, set these if any of them is 0
GetStkTraceArgsForCurrentScope(&FramePointer, &StackPointer,
&InstructionPointer, &Context);
}
if (IS_KERNEL_TARGET())
{
//
// if debugger was initialized at boot, usermode addresses needed for
// stack traces on IA64 were not available. Try it now:
//
if (g_EffMachine == IMAGE_FILE_MACHINE_IA64 &&
!KdDebuggerData.KeUserCallbackDispatcher)
{
VerifyKernelBase (FALSE);
}
ULONG64 ThreadData;
// If no explicit thread is given then we use the
// current thread. However, the current thread is only
// valid if the current thread is the event thread since
// tracing back into user mode requires that the appropriate
// user-mode memory state be active.
if (ExtThread != 0)
{
ThreadData = ExtThread;
}
else if (g_CurrentProcess->CurrentThread != g_EventThread ||
g_CurrentProcess != g_EventProcess ||
GetImplicitThreadData(&ThreadData) != S_OK)
{
ThreadData = 0;
}
VirtualFrame.KdHelp.Thread = ThreadData;
VirtualFrame.KdHelp.ThCallbackStack = ThreadData ?
KdDebuggerData.ThCallbackStack : 0;
VirtualFrame.KdHelp.KiCallUserMode = KdDebuggerData.KiCallUserMode;
VirtualFrame.KdHelp.NextCallback = KdDebuggerData.NextCallback;
VirtualFrame.KdHelp.KeUserCallbackDispatcher =
KdDebuggerData.KeUserCallbackDispatcher;
VirtualFrame.KdHelp.FramePointer = KdDebuggerData.FramePointer;
VirtualFrame.KdHelp.SystemRangeStart = g_SystemRangeStart;
}
//
// setup the program counter
//
if (!InstructionPointer)
{
if (g_EffMachine == IMAGE_FILE_MACHINE_I386)
{
ADDR Addr;
VirtualFrame.AddrPC.Mode = AddrModeFlat;
g_Machine->GetPC(&Addr);
VirtualFrame.AddrPC.Segment = Addr.seg;
VirtualFrame.AddrPC.Offset = Flat(Addr);
}
}
else
{
VirtualFrame.AddrPC.Mode = AddrModeFlat;
Seg = g_Machine->GetSegRegNum(SEGREG_CODE);
VirtualFrame.AddrPC.Segment =
Seg ? (WORD)GetRegVal32(Seg) : 0;
VirtualFrame.AddrPC.Offset = InstructionPointer;
}
//
// setup the frame pointer
//
if (!FramePointer)
{
if (g_EffMachine == IMAGE_FILE_MACHINE_I386)
{
ADDR Addr;
VirtualFrame.AddrFrame.Mode = AddrModeFlat;
g_Machine->GetFP(&Addr);
VirtualFrame.AddrFrame.Segment = Addr.seg;
VirtualFrame.AddrFrame.Offset = Flat(Addr);
}
}
else
{
VirtualFrame.AddrFrame.Mode = AddrModeFlat;
Seg = g_Machine->GetSegRegNum(SEGREG_STACK);
VirtualFrame.AddrFrame.Segment =
Seg ? (WORD)GetRegVal32(Seg) : 0;
VirtualFrame.AddrFrame.Offset = FramePointer;
}
VirtualFrame.AddrBStore = VirtualFrame.AddrFrame;
if (g_EffMachine == IMAGE_FILE_MACHINE_I386)
{
X86Ebp = (ULONG) VirtualFrame.AddrFrame.Offset;
}
//
// setup the stack pointer
//
if (!StackPointer)
{
if (g_EffMachine == IMAGE_FILE_MACHINE_I386)
{
ADDR Addr;
VirtualFrame.AddrStack.Mode = AddrModeFlat;
g_Machine->GetSP(&Addr);
VirtualFrame.AddrStack.Segment = Addr.seg;
VirtualFrame.AddrStack.Offset = Flat(Addr);
}
}
else
{
VirtualFrame.AddrStack.Mode = AddrModeFlat;
Seg = g_Machine->GetSegRegNum(SEGREG_STACK);
VirtualFrame.AddrStack.Segment =
Seg ? (WORD)GetRegVal32(Seg) : 0;
VirtualFrame.AddrStack.Offset = StackPointer;
}
if (g_EffMachine == IMAGE_FILE_MACHINE_IA64 &&
IS_KERNEL_TARGET() &&
g_SystemCallVirtualAddress)
{
PVOID functionEntry;
ULONG numberOfBytesRead;
functionEntry = SwFunctionTableAccess (g_CurrentProcess->Handle,
g_SystemCallVirtualAddress);
if (functionEntry != NULL)
{
RtlCopyMemory(&g_EpcRfeBuffer, functionEntry,
sizeof(IMAGE_IA64_RUNTIME_FUNCTION_ENTRY));
g_EpcRfe = &g_EpcRfeBuffer;
}
else
{
g_EpcRfe = NULL;
}
}
for (i = 0; i < NumFrames; i++)
{
// SwReadMemory doesn't currently use the thread handle
// but send in something reasonable in case of future changes.
if (!StackWalk64(g_EffMachine,
g_CurrentProcess->Handle,
OS_HANDLE(g_CurrentProcess->CurrentThread->Handle),
&VirtualFrame,
&Context,
SwReadMemory,
SwFunctionTableAccess,
SwGetModuleBase,
SwTranslateAddress))
{
break;
}
StackFrames[i].InstructionOffset = VirtualFrame.AddrPC.Offset;
StackFrames[i].ReturnOffset = VirtualFrame.AddrReturn.Offset;
StackFrames[i].FrameOffset = VirtualFrame.AddrFrame.Offset;
StackFrames[i].StackOffset = VirtualFrame.AddrStack.Offset;
StackFrames[i].FuncTableEntry = (ULONG64)VirtualFrame.FuncTableEntry;
StackFrames[i].Virtual = VirtualFrame.Virtual;
StackFrames[i].FrameNumber = i;
// NOTE - we have more reserved space in the DEBUG_STACK_FRAME
memcpy(StackFrames[i].Reserved, VirtualFrame.Reserved,
sizeof(VirtualFrame.Reserved));
memcpy(StackFrames[i].Params, VirtualFrame.Params,
sizeof(VirtualFrame.Params));
if (g_EffMachine == IMAGE_FILE_MACHINE_IA64 &&
IS_KERNEL_TARGET())
{
if ((VirtualFrame.AddrPC.Offset >= IA64_MM_EPC_VA) &&
(VirtualFrame.AddrPC.Offset <
(IA64_MM_EPC_VA + IA64_PAGE_SIZE)))
{
VirtualFrame.AddrPC.Offset -=
(IA64_MM_EPC_VA - g_SystemCallVirtualAddress);
}
if ((i != 0) &&
(StackFrames[i - 1].InstructionOffset >= IA64_MM_EPC_VA) &&
(VirtualFrame.AddrPC.Offset <
(IA64_MM_EPC_VA + IA64_PAGE_SIZE)))
{
StackFrames[i - 1].ReturnOffset =
VirtualFrame.AddrPC.Offset;
}
} else if (g_EffMachine == IMAGE_FILE_MACHINE_I386)
{
if (StackFrames[i].FuncTableEntry)
{
PFPO_DATA FpoData = (PFPO_DATA)StackFrames[i].FuncTableEntry;
if (FpoData->cbFrame == FRAME_FPO &&
!FpoData->fUseBP)
{
SAVE_EBP(&StackFrames[i]) = (ULONG64) (LONG64) (LONG) X86Ebp;
}
}
X86Ebp = Context.X86Context.Ebp;
}
if (Flags && i == 0)
{
PrintStackTraceHeaderLine(Flags);
}
IMAGEHLP_MODULE64 Mod;
// If the current frame's PC is in a loaded module and
// that module does not have symbols it's very possible
// that the stack trace will be incorrect since the
// debugger has to guess about how to unwind the stack.
// Non-x86 architectures have unwind info in the images
// themselves so restrict this check to x86.
Mod.SizeOfStruct = sizeof(Mod);
if (!SymWarning &&
NumFrames > 1 &&
g_EffMachine == IMAGE_FILE_MACHINE_I386 &&
StackFrames[i].InstructionOffset != -1 &&
SymGetModuleInfo64(g_CurrentProcess->Handle,
StackFrames[i].InstructionOffset, &Mod) &&
(Mod.SymType == SymNone || Mod.SymType == SymExport ||
Mod.SymType == SymDeferred))
{
WarnOut("WARNING: Stack unwind information not available. "
"Following frames may be wrong.\n");
// Only show one warning per trace.
SymWarning = TRUE;
}
if (Flags)
{
PrintStackFrame(StackFrames + i, Flags);
if (Flags & DEBUG_STACK_NONVOLATILE_REGISTERS)
{
g_Machine->PrintStackNonvolatileRegisters(Flags,
StackFrames + i,
&Context, i);
}
}
}
return i;
}
#define BASIC_STACK \
(DEBUG_STACK_COLUMN_NAMES | DEBUG_STACK_FRAME_ADDRESSES | \
DEBUG_STACK_SOURCE_LINE)
ULONG g_StackTraceTypeFlags[STACK_TRACE_TYPE_MAX] =
{
BASIC_STACK, // Default
BASIC_STACK | DEBUG_STACK_ARGUMENTS, // kb
BASIC_STACK | DEBUG_STACK_ARGUMENTS | DEBUG_STACK_FUNCTION_INFO |
DEBUG_STACK_NONVOLATILE_REGISTERS, // kv
0, // kd
BASIC_STACK | DEBUG_STACK_PARAMETERS, // kp
BASIC_STACK | DEBUG_STACK_FRAME_NUMBERS, // kn
BASIC_STACK | DEBUG_STACK_ARGUMENTS | DEBUG_STACK_FRAME_NUMBERS, // kbn
BASIC_STACK | DEBUG_STACK_ARGUMENTS | DEBUG_STACK_FUNCTION_INFO |
DEBUG_STACK_NONVOLATILE_REGISTERS | DEBUG_STACK_FRAME_NUMBERS,// kvn
DEBUG_STACK_FRAME_NUMBERS, // kdn
BASIC_STACK | DEBUG_STACK_PARAMETERS | DEBUG_STACK_FRAME_NUMBERS // kpn
};
VOID
DoStackTrace(
ULONG64 FramePointer,
ULONG64 StackPointer,
ULONG64 InstructionPointer,
ULONG NumFrames,
STACK_TRACE_TYPE TraceType
)
{
PDEBUG_STACK_FRAME StackFrames;
ULONG NumFramesToRead;
DWORD FrameCount;
if (NumFrames == 0)
{
NumFrames = g_DefaultStackTraceDepth;
}
if (TraceType == STACK_TRACE_TYPE_KD)
{
NumFramesToRead = 1;
}
else
{
NumFramesToRead = NumFrames;
}
StackFrames = (PDEBUG_STACK_FRAME)
malloc( sizeof(StackFrames[0]) * NumFramesToRead );
if (!StackFrames)
{
ErrOut( "could not allocate memory for stack trace\n" );
return;
}
ULONG Flags = g_StackTraceTypeFlags[TraceType];
if ((TraceType == STACK_TRACE_TYPE_KB) && g_Machine->m_Ptr64)
{
Flags |= DEBUG_STACK_FRAME_ADDRESSES_RA_ONLY;
}
FrameCount = StackTrace( FramePointer,
StackPointer,
InstructionPointer,
StackFrames,
NumFramesToRead,
0,
Flags,
FALSE
);
if (FrameCount == 0)
{
ErrOut( "could not fetch any stack frames\n" );
free(StackFrames);
return;
}
if (TraceType == STACK_TRACE_TYPE_KD)
{
// Starting with the stack pointer, dump NumFrames DWORD's
// and the symbol if possible.
ADDR startAddr;
ADDRFLAT(&startAddr, StackFrames[0].FrameOffset);
fnDumpDwordMemory(&startAddr, NumFrames, TRUE);
}
free( StackFrames );
}