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