static int jl_unw_step(bt_cursor_t *cursor, uintptr_t *ip, uintptr_t *sp) { // Might be called from unmanaged thread. #ifndef _CPU_X86_64_ *ip = (uintptr_t)cursor->stackframe.AddrPC.Offset; *sp = (uintptr_t)cursor->stackframe.AddrStack.Offset; if (*ip == 0 || *ip == ((uintptr_t)0)-1) { if (!readable_pointer((LPCVOID)*sp)) return 0; cursor->stackframe.AddrPC.Offset = *(DWORD32*)*sp; // POP EIP (aka RET) cursor->stackframe.AddrStack.Offset += sizeof(void*); return cursor->stackframe.AddrPC.Offset != 0; } BOOL result = StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), hMainThread, &cursor->stackframe, &cursor->context, NULL, JuliaFunctionTableAccess64, JuliaGetModuleBase64, NULL); return result; #else *ip = (uintptr_t)cursor->Rip; *sp = (uintptr_t)cursor->Rsp; if (*ip == 0 || *ip == ((uintptr_t)0)-1) { if (!readable_pointer((LPCVOID)*sp)) return 0; cursor->Rip = *(DWORD64*)*sp; // POP RIP (aka RET) cursor->Rsp += sizeof(void*); return cursor->Rip != 0; } DWORD64 ImageBase = JuliaGetModuleBase64(GetCurrentProcess(), cursor->Rip); if (!ImageBase) return 0; PRUNTIME_FUNCTION FunctionEntry = (PRUNTIME_FUNCTION)JuliaFunctionTableAccess64(GetCurrentProcess(), cursor->Rip); if (!FunctionEntry) { // assume this is a NO_FPO RBP-based function cursor->Rsp = cursor->Rbp; // MOV RSP, RBP if (!readable_pointer((LPCVOID)cursor->Rsp)) return 0; cursor->Rbp = *(DWORD64*)cursor->Rsp; // POP RBP cursor->Rsp += sizeof(void*); cursor->Rip = *(DWORD64*)cursor->Rsp; // POP RIP (aka RET) cursor->Rsp += sizeof(void*); } else { PVOID HandlerData; DWORD64 EstablisherFrame; (void)RtlVirtualUnwind( 0 /*UNW_FLAG_NHANDLER*/, ImageBase, cursor->Rip, FunctionEntry, cursor, &HandlerData, &EstablisherFrame, NULL); } return cursor->Rip != 0; #endif }
static void __cdecl capture_current_context(CONTEXT* pContextRecord) { ULONG64 ControlPc; ULONG64 EstablisherFrame; ULONG64 ImageBase; PRUNTIME_FUNCTION FunctionEntry; PVOID HandlerData; RtlCaptureContext(pContextRecord); ControlPc = pContextRecord->Rip; FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL); if (FunctionEntry != NULL) { RtlVirtualUnwind( UNW_FLAG_NHANDLER, ImageBase, ControlPc, FunctionEntry, pContextRecord, &HandlerData, &EstablisherFrame, NULL); } }
static unsigned int our_stackwalk(ULONG_PTR retaddr, ULONG_PTR sp, PVOID *backtrace, unsigned int count) { /* derived from http://www.nynaeve.net/Code/StackWalk64.cpp */ CONTEXT ctx; DWORD64 imgbase; PRUNTIME_FUNCTION runfunc; KNONVOLATILE_CONTEXT_POINTERS nvctx; PVOID handlerdata; ULONG_PTR establisherframe; unsigned int frame; RtlCaptureContext(&ctx); for (frame = 0; frame < count; frame++) { backtrace[frame] = (PVOID)ctx.Rip; runfunc = RtlLookupFunctionEntry(ctx.Rip, &imgbase, NULL); memset(&nvctx, 0, sizeof(nvctx)); if (runfunc == NULL) { ctx.Rip = (ULONG_PTR)(*(ULONG_PTR *)ctx.Rsp); ctx.Rsp += 8; } else { RtlVirtualUnwind(UNW_FLAG_NHANDLER, imgbase, ctx.Rip, runfunc, &ctx, &handlerdata, &establisherframe, &nvctx); } if (!ctx.Rip) break; } return frame + 1; }
static void nextExcInfo // MOVE AHEAD TO NEXT RTN. IN CALL CHAIN ( __EXC_INFO* info ) // - exception info { info->dctx.pc = RtlVirtualUnwind( info->dctx.pc , info->dctx.pdata , &info->ctx , &info->in_func , info->est_frame , 0 ); setPdata( info ); }
static int jl_unw_step(bt_cursor_t *cursor, uintptr_t *ip, uintptr_t *sp) { // Might be called from unmanaged thread. #ifndef _CPU_X86_64_ *ip = (uintptr_t)cursor->stackframe.AddrPC.Offset; *sp = (uintptr_t)cursor->stackframe.AddrStack.Offset; BOOL result = StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), hMainThread, &cursor->stackframe, &cursor->context, NULL, JuliaFunctionTableAccess64, JuliaGetModuleBase64, NULL); return result; #else *ip = (uintptr_t)cursor->Rip; *sp = (uintptr_t)cursor->Rsp; DWORD64 ImageBase = JuliaGetModuleBase64(GetCurrentProcess(), cursor->Rip); if (!ImageBase) return 0; PRUNTIME_FUNCTION FunctionEntry = (PRUNTIME_FUNCTION)JuliaFunctionTableAccess64(GetCurrentProcess(), cursor->Rip); if (!FunctionEntry) { // assume this is a NO_FPO RBP-based function MEMORY_BASIC_INFORMATION mInfo; cursor->Rsp = cursor->Rbp; // MOV RSP, RBP // Check whether the pointer is valid and executable before dereferencing // to avoid segfault while recording. See #10638. if (VirtualQuery((LPCVOID)cursor->Rsp, &mInfo, sizeof(MEMORY_BASIC_INFORMATION)) == 0) return 0; DWORD X = mInfo.AllocationProtect; if (!((X&PAGE_READONLY) || (X&PAGE_READWRITE) || (X&PAGE_WRITECOPY) || (X&PAGE_EXECUTE_READ)) || (X&PAGE_GUARD) || (X&PAGE_NOACCESS)) return 0; cursor->Rbp = *(DWORD64*)cursor->Rsp; // POP RBP cursor->Rsp = cursor->Rsp + sizeof(void*); cursor->Rip = *(DWORD64*)cursor->Rsp; // POP RIP (aka RET) cursor->Rsp = cursor->Rsp + sizeof(void*); } else { PVOID HandlerData; DWORD64 EstablisherFrame; (void)RtlVirtualUnwind( 0 /*UNW_FLAG_NHANDLER*/, ImageBase, cursor->Rip, FunctionEntry, cursor, &HandlerData, &EstablisherFrame, NULL); } return cursor->Rip != 0; #endif }
__declspec(noreturn) void __cdecl __report_gsfailure (ULONG_PTR StackCookie) { volatile UINT_PTR cookie[2] __MINGW_ATTRIB_UNUSED; #if defined(_WIN64) && !defined(__aarch64__) ULONG64 controlPC, imgBase, establisherFrame; PRUNTIME_FUNCTION fctEntry; PVOID hndData; RtlCaptureContext (&GS_ContextRecord); controlPC = GS_ContextRecord.Rip; fctEntry = RtlLookupFunctionEntry (controlPC, &imgBase, NULL); if (fctEntry != NULL) { RtlVirtualUnwind (UNW_FLAG_NHANDLER, imgBase, controlPC, fctEntry, &GS_ContextRecord, &hndData, &establisherFrame, NULL); } else #endif /* _WIN64 */ { #if defined(__x86_64__) || defined(_AMD64_) GS_ContextRecord.Rip = (ULONGLONG) _ReturnAddress(); GS_ContextRecord.Rsp = (ULONGLONG) _AddressOfReturnAddress() + 8; #elif defined(__i386__) || defined(_X86_) GS_ContextRecord.Eip = (DWORD) _ReturnAddress(); GS_ContextRecord.Esp = (DWORD) _AddressOfReturnAddress() + 4; #elif defined(__arm__) || defined(_ARM_) GS_ContextRecord.Pc = (DWORD) _ReturnAddress(); GS_ContextRecord.Sp = (DWORD) _AddressOfReturnAddress() + 4; #endif /* _WIN64 */ } #if defined(__x86_64__) || defined(_AMD64_) GS_ExceptionRecord.ExceptionAddress = (PVOID) GS_ContextRecord.Rip; GS_ContextRecord.Rcx = StackCookie; #elif defined(__i386__) || defined(_X86_) GS_ExceptionRecord.ExceptionAddress = (PVOID) GS_ContextRecord.Eip; GS_ContextRecord.Ecx = StackCookie; #elif defined(__arm__) || defined(_ARM_) GS_ExceptionRecord.ExceptionAddress = (PVOID) GS_ContextRecord.Pc; UNUSED_PARAM(StackCookie); #endif /* _WIN64 */ GS_ExceptionRecord.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN; GS_ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE; cookie[0] = __security_cookie; cookie[1] = __security_cookie_complement; SetUnhandledExceptionFilter (NULL); UnhandledExceptionFilter ((EXCEPTION_POINTERS *) &GS_ExceptionPointers); TerminateProcess (GetCurrentProcess (), STATUS_STACK_BUFFER_OVERRUN); abort(); }
static void __cdecl capture_previous_context(CONTEXT* pContextRecord) { ULONG64 ControlPc; ULONG64 EstablisherFrame; ULONG64 ImageBase; PRUNTIME_FUNCTION FunctionEntry; PVOID HandlerData; INT frames; RtlCaptureContext(pContextRecord); ControlPc = pContextRecord->Rip; // Unwind "twice" to get the context of the caller to the "previous" caller: for (frames = 0; frames < 2; ++frames) { FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL); if (FunctionEntry != NULL) { RtlVirtualUnwind( UNW_FLAG_NHANDLER, ImageBase, ControlPc, FunctionEntry, pContextRecord, &HandlerData, &EstablisherFrame, NULL); } else { break; } } }
void StackDump( LPVOID pMem, SIZE_T dwBytes) { CONTEXT Context; //KNONVOLATILE_CONTEXT_POINTERS NvContext; //UNWIND_HISTORY_TABLE UnwindHistoryTable; PRUNTIME_FUNCTION RuntimeFunction; PVOID HandlerData; ULONG64 EstablisherFrame; ULONG64 ImageBase; //OutputDebugString(L"StackTrace64: Executing stack trace...\n"); // // First, we'll get the caller's context. // RtlCaptureContext(&Context); // // Initialize the (optional) unwind history table. // /*RtlZeroMemory( &UnwindHistoryTable, sizeof(UNWIND_HISTORY_TABLE));*/ //BYTE SymBol[ sizeof(SYMBOL_INFO) + STACKWALK_MAX_NAMELEN ] = {0}; //SYMBOL_INFO* pSymbol = (SYMBOL_INFO*)SymBol; //DWORD64 dwDisplacement; HANDLE hProcess = GetCurrentProcess(); MEM_INFO stInfo; //stInfo.parCallStack = new STACK_ARRAY; //void * p = AllocMem(sizeof(STACK_ARRAY)); //stInfo.parCallStack = new( (void*)p ) STACK_ARRAY; stInfo.nMemSize = dwBytes; for( int i =0; i < g_StackDepth ; i++ )// only retrieve 40 functions { // // Try to look up unwind metadata for the current function. // RuntimeFunction = RtlLookupFunctionEntry( Context.Rip, &ImageBase, NULL ); /*RtlZeroMemory( &NvContext, sizeof(KNONVOLATILE_CONTEXT_POINTERS));*/ if (!RuntimeFunction) { // // If we don't have a RUNTIME_FUNCTION, then we've encountered // a leaf function. Adjust the stack approprately. // Context.Rip = (ULONG64)(*(PULONG64)Context.Rsp); Context.Rsp += 8; } else { // // Otherwise, call upon RtlVirtualUnwind to execute the unwind for // us. // RtlVirtualUnwind( 0, //UNW_FLAG_NHANDLER, ImageBase, Context.Rip, RuntimeFunction, &Context, &HandlerData, &EstablisherFrame, NULL ); } // // If we reach an RIP of zero, this means that we've walked off the end // of the call stack and are done. // if (!Context.Rip) break; ////////////////////////////////////////////////////////////////////////// //if( SymFromAddr( hProcess, Context.Rip, &dwDisplacement, pSymbol )) //{ // CString cs = "Ordinal823"; // if( cs == pSymbol->Name) // { // break; // } // //} ////////////////////////////////////////////////////////////////////////// if( i <= 1 )// ignore the functions on the top of stack which is our own. { continue; } stInfo.parCallStack.push_back( Context.Rip ); } g_Config::m_MemMap[pMem] = stInfo; }
VOID KeDumpMachineState ( IN PKPROCESSOR_STATE ProcessorState, IN PCHAR Buffer, IN PULONG BugCheckParameters, IN ULONG NumberOfParameters, IN PKE_BUGCHECK_UNICODE_TO_ANSI UnicodeToAnsiRoutine ) /*++ Routine Description: This function formats and displays the machine state at the time of the to bug check. Arguments: ProcessorState - Supplies a pointer to a processor state record. Buffer - Supplies a pointer to a buffer to be used to output machine state information. BugCheckParameters - Supplies a pointer to an array of additional bug check information. NumberOfParameters - Suppiles the size of the bug check parameters array. UnicodeToAnsiRoutine - Supplies a pointer to a routine to convert Unicode strings to Ansi strings without touching paged translation tables. Return Value: None. --*/ { PCONTEXT ContextRecord; ULONG ControlPc; PLDR_DATA_TABLE_ENTRY DataTableEntry; ULONG DisplayColumn; ULONG DisplayHeight; ULONG DisplayRow; ULONG DisplayWidth; UNICODE_STRING DllName; ULONG EstablisherFrame; PRUNTIME_FUNCTION FunctionEntry; PVOID ImageBase; ULONG Index; BOOLEAN InFunction; ULONG LastStack; PLIST_ENTRY ModuleListHead; PLIST_ENTRY NextEntry; ULONG NextPc; ULONG StackLimit; UCHAR AnsiBuffer[ 32 ]; ULONG DateStamp; // // Call the HAL to force all external interrupts to be disabled // at the interrupt controller. PowerPC optimization does not // do this when raising to high level. // for (Index = 0; Index < MAXIMUM_VECTOR; Index++) { HalDisableSystemInterrupt(Index, HIGH_LEVEL); } // // Query display parameters. // HalQueryDisplayParameters(&DisplayWidth, &DisplayHeight, &DisplayColumn, &DisplayRow); // // Display any addresses that fall within the range of any module in // the loaded module list. // for (Index = 0; Index < NumberOfParameters; Index += 1) { ImageBase = KiPcToFileHeader((PVOID)*BugCheckParameters, &ImageBase, &DataTableEntry); if (ImageBase != NULL) { sprintf(Buffer, "*** %08lX has base at %08lX - %s\n", *BugCheckParameters, ImageBase, (*UnicodeToAnsiRoutine)( &DataTableEntry->BaseDllName, AnsiBuffer, sizeof( AnsiBuffer ))); HalDisplayString(Buffer); } BugCheckParameters += 1; } // // Virtually unwind to the caller of bug check. // ContextRecord = &ProcessorState->ContextFrame; LastStack = ContextRecord->Gpr1; ControlPc = ContextRecord->Lr - 4; NextPc = ControlPc; FunctionEntry = KiLookupFunctionEntry(ControlPc); if (FunctionEntry != NULL) { NextPc = RtlVirtualUnwind(ControlPc, FunctionEntry, ContextRecord, &InFunction, &EstablisherFrame, NULL, 0, 0xffffffff); } // // At this point the context record contains the machine state at the // call to bug check. // // Put out the machine state at the time of the bugcheck. // sprintf(Buffer, "\n Machine State at Call to Bug Check IAR:%08lX MSR:%08lX\n", ContextRecord->Lr, ContextRecord->Msr); HalDisplayString(Buffer); // // Format and output the integer registers. // sprintf(Buffer, " R0:%8lX R1:%8lX R2:%8lX R3:%8lX R4:%8lX R5:%8lX\n", ContextRecord->Gpr0, ContextRecord->Gpr1, ContextRecord->Gpr2, ContextRecord->Gpr3, ContextRecord->Gpr4, ContextRecord->Gpr5); HalDisplayString(Buffer); sprintf(Buffer, " R6:%8lX R7:%8lX R8:%8lX R9:%8lX R10:%8lX R11:%8lX\n", ContextRecord->Gpr6, ContextRecord->Gpr7, ContextRecord->Gpr8, ContextRecord->Gpr9, ContextRecord->Gpr10, ContextRecord->Gpr11); HalDisplayString(Buffer); sprintf(Buffer, "R12:%8lX R13:%8lX R14:%8lX R15:%8lX R16:%8lX R17:%8lX\n", ContextRecord->Gpr12, ContextRecord->Gpr13, ContextRecord->Gpr14, ContextRecord->Gpr15, ContextRecord->Gpr16, ContextRecord->Gpr17); HalDisplayString(Buffer); sprintf(Buffer, "R18:%8lX R19:%8lX R20:%8lX R21:%8lX R22:%8lX R23:%8lX\n", ContextRecord->Gpr18, ContextRecord->Gpr19, ContextRecord->Gpr20, ContextRecord->Gpr21, ContextRecord->Gpr22, ContextRecord->Gpr23); HalDisplayString(Buffer); sprintf(Buffer, "R24:%8lX R25:%8lX R26:%8lX R27:%8lX R28:%8lX R29:%8lX\n", ContextRecord->Gpr24, ContextRecord->Gpr25, ContextRecord->Gpr26, ContextRecord->Gpr27, ContextRecord->Gpr28, ContextRecord->Gpr29); HalDisplayString(Buffer); sprintf(Buffer, "R30:%8lX R31:%8lX CR:%8lX CTR:%8lX XER:%8lX\n", ContextRecord->Gpr30, ContextRecord->Gpr31, ContextRecord->Cr, ContextRecord->Ctr, ContextRecord->Xer); HalDisplayString(Buffer); #if 0 // // I'd much rather see a longer stack trace and skip the floating // point stuff when the system crashes. plj // // // Format and output the floating registers. // DumpFloat = (PULONG)(&ContextRecord->Fpr0); sprintf(Buffer, " F0- F3:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n", *(DumpFloat+1), *DumpFloat, *(DumpFloat+3), *(DumpFloat+2), *(DumpFloat+5), *(DumpFloat+4), *(DumpFloat+7), *(DumpFloat+6)); HalDisplayString(Buffer); DumpFloat = (PULONG)(&ContextRecord->Fpr4); sprintf(Buffer, " F4- F7:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n", *(DumpFloat+1), *DumpFloat, *(DumpFloat+3), *(DumpFloat+2), *(DumpFloat+5), *(DumpFloat+4), *(DumpFloat+7), *(DumpFloat+6)); HalDisplayString(Buffer); DumpFloat = (PULONG)(&ContextRecord->Fpr8); sprintf(Buffer, " F8-F11:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n", *(DumpFloat+1), *DumpFloat, *(DumpFloat+3), *(DumpFloat+2), *(DumpFloat+5), *(DumpFloat+4), *(DumpFloat+7), *(DumpFloat+6)); HalDisplayString(Buffer); DumpFloat = (PULONG)(&ContextRecord->Fpr12); sprintf(Buffer, "F12-F15:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n", *(DumpFloat+1), *DumpFloat, *(DumpFloat+3), *(DumpFloat+2), *(DumpFloat+5), *(DumpFloat+4), *(DumpFloat+7), *(DumpFloat+6)); HalDisplayString(Buffer); DumpFloat = (PULONG)(&ContextRecord->Fpr16); sprintf(Buffer, "F16-F19:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n", *(DumpFloat+1), *DumpFloat, *(DumpFloat+3), *(DumpFloat+2), *(DumpFloat+5), *(DumpFloat+4), *(DumpFloat+7), *(DumpFloat+6)); HalDisplayString(Buffer); DumpFloat = (PULONG)(&ContextRecord->Fpr20); sprintf(Buffer, "F20-F23:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n", *(DumpFloat+1), *DumpFloat, *(DumpFloat+3), *(DumpFloat+2), *(DumpFloat+5), *(DumpFloat+4), *(DumpFloat+7), *(DumpFloat+6)); HalDisplayString(Buffer); DumpFloat = (PULONG)(&ContextRecord->Fpr24); sprintf(Buffer, "F24-F27:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n", *(DumpFloat+1), *DumpFloat, *(DumpFloat+3), *(DumpFloat+2), *(DumpFloat+5), *(DumpFloat+4), *(DumpFloat+7), *(DumpFloat+6)); HalDisplayString(Buffer); DumpFloat = (PULONG)(&ContextRecord->Fpr28); sprintf(Buffer, "F28-F31:%08lX%08lX %08lX%08lX %08lX%08lX %08lX%08lX\n", *(DumpFloat+1), *DumpFloat, *(DumpFloat+3), *(DumpFloat+2), *(DumpFloat+5), *(DumpFloat+4), *(DumpFloat+7), *(DumpFloat+6)); HalDisplayString(Buffer); DumpFloat = (PULONG)(&ContextRecord->Fpscr); sprintf(Buffer, " FPSCR:%08lX%08lX\n", *(DumpFloat+1), *DumpFloat); HalDisplayString(Buffer); #define STAKWALK 4 #else #define STAKWALK 8 #endif // // Output short stack back trace with base address. // DllName.Length = 0; DllName.Buffer = L""; if (FunctionEntry != NULL) { StackLimit = (ULONG)KeGetCurrentThread()->KernelStack; HalDisplayString("Callee-Sp Return-Ra Dll Base - Name\n"); for (Index = 0; Index < STAKWALK; Index += 1) { ImageBase = KiPcToFileHeader((PVOID)ControlPc, &ImageBase, &DataTableEntry); sprintf(Buffer, " %08lX %08lX : %08lX - %s\n", ContextRecord->Gpr1, NextPc + 4, ImageBase, (*UnicodeToAnsiRoutine)( (ImageBase != NULL) ? &DataTableEntry->BaseDllName : &DllName, AnsiBuffer, sizeof( AnsiBuffer ))); HalDisplayString(Buffer); if ((NextPc != ControlPc) || (ContextRecord->Gpr1 != LastStack)) { ControlPc = NextPc; LastStack = ContextRecord->Gpr1; FunctionEntry = KiLookupFunctionEntry(ControlPc); if ((FunctionEntry != NULL) && (LastStack < StackLimit)) { NextPc = RtlVirtualUnwind(ControlPc, FunctionEntry, ContextRecord, &InFunction, &EstablisherFrame, NULL, 0, 0xffffffff); } else { NextPc = ContextRecord->Lr; } } else { break; } } } // // Output the build number and other useful information. // sprintf(Buffer, "\nIRQL : %d, DPC Active : %s, SYSVER 0x%08x\n", KeGetCurrentIrql(), KeIsExecutingDpc() ? "TRUE" : "FALSE", NtBuildNumber); HalDisplayString(Buffer); // // Output the processor id and the primary cache sizes. // sprintf(Buffer, "Processor Id: %d.%d, Icache: %d, Dcache: %d", PCR->ProcessorVersion, PCR->ProcessorRevision, PCR->FirstLevelIcacheSize, PCR->FirstLevelDcacheSize); HalDisplayString(Buffer); // // If the display width is greater than 80 + 24 (the size of a DLL // name and base address), then display all the modules loaded in // the system. // HalQueryDisplayParameters(&DisplayWidth, &DisplayHeight, &DisplayColumn, &DisplayRow); if (DisplayWidth > (80 + 24)) { HalDisplayString("\n"); if (KeLoaderBlock != NULL) { ModuleListHead = &KeLoaderBlock->LoadOrderListHead; } else { ModuleListHead = &PsLoadedModuleList; } // // Output display headers. // Index = 1; KiDisplayString(80, Index, "Dll Base DateStmp - Name"); NextEntry = ModuleListHead->Flink; if (NextEntry != NULL) { // // Scan the list of loaded modules and display their base // address and name. // while (NextEntry != ModuleListHead) { Index += 1; DataTableEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); if (MmDbgReadCheck(DataTableEntry->DllBase) != NULL) { PIMAGE_NT_HEADERS NtHeaders; NtHeaders = RtlImageNtHeader(DataTableEntry->DllBase); DateStamp = NtHeaders->FileHeader.TimeDateStamp; } else { DateStamp = 0; } sprintf(Buffer, "%08lX %08lx - %s", DataTableEntry->DllBase, DateStamp, (*UnicodeToAnsiRoutine)( &DataTableEntry->BaseDllName, AnsiBuffer, sizeof( AnsiBuffer ))); KiDisplayString(80, Index, Buffer); NextEntry = NextEntry->Flink; if (Index > DisplayHeight) { break; } } } } // // Reset the current display position. // HalSetDisplayParameters(DisplayColumn, DisplayRow); // // The system has crashed, if we are running without the Kernel // debugger attached, attach it now. // KdInitSystem(NULL, FALSE); return; }
VOID RtlGetCallersAddress ( OUT PVOID *CallersPc, OUT PVOID *CallersCallersPc ) /*++ Routine Description: This routine returns the address of the routine that called the routine that called this routine, and the routine that called the routine that called this routine. For example, if A called B called C which called this routine, the return addresses in A and B would be returned. Arguments: CallersPc - Supplies a pointer to a variable that receives the address of the caller of the caller of this routine (B). CallersCallersPc - Supplies a pointer to a variable that receives the address of the caller of the caller of the caller of this routine (A). Return Value: None. Note: If either of the calling stack frames exceeds the limits of the stack, they are set to NULL. --*/ { CONTEXT ContextRecord; ULONG EstablisherFrame; PRUNTIME_FUNCTION FunctionEntry; BOOLEAN InFunction; ULONG NextPc; ULONG HighLimit, LowLimit; // // Assume the function table entries for the various routines cannot be // found or there are not four procedure activation records on the stack. // *CallersPc = NULL; *CallersCallersPc = NULL; // // Capture the current context. // RtlCaptureContext(&ContextRecord); NextPc = (ULONG)ContextRecord.XIntRa; // // Get the high and low limits of the current thread's stack. // RtlpGetStackLimits(&LowLimit, &HighLimit); // // Attempt to unwind to the caller of this routine (C). // FunctionEntry = RtlLookupFunctionEntry(NextPc); if (FunctionEntry != NULL) { // // A function entry was found for this routine. Virtually unwind // to the caller of this routine (C). // NextPc = RtlVirtualUnwind(NextPc | 1, FunctionEntry, &ContextRecord, &InFunction, &EstablisherFrame, NULL); // // Attempt to unwind to the caller of the caller of this routine (B). // FunctionEntry = RtlLookupFunctionEntry(NextPc); if ((FunctionEntry != NULL) && ((ULONG)ContextRecord.XIntSp < HighLimit)) { // // A function table entry was found for the caller of the caller // of this routine (B). Virtually unwind to the caller of the // caller of this routine (B). // NextPc = RtlVirtualUnwind(NextPc | 1, FunctionEntry, &ContextRecord, &InFunction, &EstablisherFrame, NULL); *CallersPc = (PVOID)NextPc; // // Attempt to unwind to the caller of the caller of the caller // of the caller of this routine (A). // FunctionEntry = RtlLookupFunctionEntry(NextPc); if ((FunctionEntry != NULL) && ((ULONG)ContextRecord.XIntSp < HighLimit)) { // // A function table entry was found for the caller of the // caller of the caller of this routine (A). Virtually unwind // to the caller of the caller of the caller of this routine // (A). // NextPc = RtlVirtualUnwind(NextPc | 1, FunctionEntry, &ContextRecord, &InFunction, &EstablisherFrame, NULL); *CallersCallersPc = (PVOID)NextPc; } } } return; }
int __gnat_backtrace (void **array, int size, void *exclude_min, void *exclude_max, int skip_frames) { CONTEXT context; UNWIND_HISTORY_TABLE history; int i; /* Get the context. */ RtlCaptureContext (&context); /* Setup unwind history table (a cached to speed-up unwinding). */ memset (&history, 0, sizeof (history)); i = 0; while (1) { PRUNTIME_FUNCTION RuntimeFunction; KNONVOLATILE_CONTEXT_POINTERS NvContext; ULONG64 ImageBase; VOID *HandlerData; ULONG64 EstablisherFrame; /* Get function metadata. */ RuntimeFunction = RtlLookupFunctionEntry (context.Rip, &ImageBase, &history); if (!RuntimeFunction) { /* In case of failure, assume this is a leaf function. */ context.Rip = *(ULONG64 *) context.Rsp; context.Rsp += 8; } else { /* Unwind. */ memset (&NvContext, 0, sizeof (KNONVOLATILE_CONTEXT_POINTERS)); RtlVirtualUnwind (0, ImageBase, context.Rip, RuntimeFunction, &context, &HandlerData, &EstablisherFrame, &NvContext); } /* 0 means bottom of the stack. */ if (context.Rip == 0) break; /* Skip frames. */ if (skip_frames > 1) { skip_frames--; continue; } /* Excluded frames. */ if ((void *)context.Rip >= exclude_min && (void *)context.Rip <= exclude_max) continue; array[i++] = (void *)(context.Rip - 2); if (i >= size) break; } return i; }
_WCRTLINK void _NextExcInfo( _EXCINFO *info ) { info->ControlPC = RtlVirtualUnwind( info->ControlPC, info->FunctionEntry, &info->ContextRecord, &info->InFunction, info->EstablisherFrame, NULL ); _SetPData( info ); }
void RtlUnwindActions2 ( IN PVOID TargetFrame OPTIONAL, IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL, IN PCONTEXT ContextRecord ) /*++ Routine Description: This function initiates an unwind of procedure call frames. The machine state at the time of the call to unwind is captured in a context record and the unwinding flag is set in the exception flags of the exception record. If the TargetFrame parameter is not specified, then the exit unwind flag is also set in the exception flags of the exception record. A backward scan through the procedure call frames is then performed to find the target of the unwind operation. As each frame is encounter, the PC where control left the corresponding function is determined and used to lookup exception handler information in the runtime function table built by the linker. If the respective routine has an exception handler, then the handler is called. N.B. This routine is provided for backward compatibility with release 1. Arguments: TargetFrame - Supplies an optional pointer to the call frame that is the target of the unwind. If this parameter is not specified, then an exit unwind is performed. TargetIp - Supplies an optional instruction address that specifies the continuation address of the unwind. This address is ignored if the target frame parameter is not specified. ExceptionRecord - Supplies an optional pointer to an exception record. ReturnValue - Supplies a value that is to be placed in the integer function return register just before continuing execution. Return Value: None. --*/ { // These were originally parameters but are not // not needed in this unwinding variant because // no context switch to TargetIp will be performed. PVOID TargetIp = NULL; PVOID ReturnValue = NULL; ULONG ControlPc; #if EH_DBG ULONG ControlPcHistory[PC_HISTORY_DEPTH]; ULONG ControlPcHistoryIndex = 0; #endif DISPATCHER_CONTEXT DispatcherContext; EXCEPTION_DISPOSITION Disposition; FRAME_POINTERS EstablisherFrame; ULONG ExceptionFlags; EXCEPTION_RECORD ExceptionRecord1; #if EH_DBG LONG FrameDepth = 0; #endif PRUNTIME_FUNCTION FunctionEntry; ULONG HighLimit; BOOLEAN InFunction; ULONG LowLimit; ULONG NextPc; #if EH_DBG if (EHRtlDebugFlags & RTL_DBG_UNWIND) { DbgPrint("\nRtlUnwindActions2(TargetFrame = %lx, TargetIp = %lx,, ReturnValue = %lx)\n", TargetFrame, TargetIp, ReturnValue); } #endif // // Get current stack limits, capture the current context, virtually // unwind to the caller of this routine, get the initial PC value, and // set the unwind target address. // __CxxGetStackLimits(&LowLimit, &HighLimit); RtlCaptureContext(ContextRecord); ControlPc = (ULONG)ContextRecord->IntRa - 4; FunctionEntry = RtlLookupFunctionEntry(ControlPc); NextPc = RtlVirtualUnwind(ControlPc, FunctionEntry, ContextRecord, &InFunction, &EstablisherFrame, NULL); ControlPc = NextPc; ContextRecord->Fir = (ULONGLONG)(LONG)TargetIp; // // If an exception record is not specified, then build a local exception // record for use in calling exception handlers during the unwind operation. // if (ARGUMENT_PRESENT(ExceptionRecord) == FALSE) { ExceptionRecord = &ExceptionRecord1; ExceptionRecord1.ExceptionCode = STATUS_UNWIND; ExceptionRecord1.ExceptionRecord = NULL; ExceptionRecord1.ExceptionAddress = (PVOID)ControlPc; ExceptionRecord1.NumberParameters = 0; } // // If the target frame of the unwind is specified, then a normal unwind // is being performed. Otherwise, an exit unwind is being performed. // ExceptionFlags = EXCEPTION_UNWINDING; if (ARGUMENT_PRESENT(TargetFrame) == FALSE) { ExceptionRecord->ExceptionFlags |= EXCEPTION_EXIT_UNWIND; } // // Scan backward through the call frame hierarchy and call exception // handlers until the target frame of the unwind is reached. // do { #if EH_DBG if (EHRtlDebugFlags & RTL_DBG_UNWIND_DETAIL) { DbgPrint("RtlUnwindActions2: Loop: FrameDepth = %d, sp = %lx, ControlPc = %lx\n", FrameDepth, ContextRecord->IntSp, ControlPc); FrameDepth -= 1; } #endif // // Lookup the function table entry using the point at which control // left the procedure. // FunctionEntry = RtlLookupFunctionEntry(ControlPc); // // If there is a function table entry for the routine, then virtually // unwind to the caller of the routine to obtain the virtual frame // pointer of the establisher, but don't update the context record. // if (FunctionEntry != NULL) { { CONTEXT LocalContext; RtlMoveMemory((PVOID)&LocalContext, ContextRecord, sizeof(CONTEXT)); NextPc = RtlVirtualUnwind(ControlPc, FunctionEntry, &LocalContext, &InFunction, &EstablisherFrame, NULL); } // // If the virtual frame pointer is not within the specified stack // limits, the virtual frame pointer is unaligned, or the target // frame is below the virtual frame and an exit unwind is not being // performed, then raise the exception STATUS_BAD_STACK. Otherwise, // check to determine if the current routine has an exception // handler. // if ((EstablisherFrame.Virtual < LowLimit) || (EstablisherFrame.Virtual > HighLimit) || ((ARGUMENT_PRESENT(TargetFrame) != FALSE) && ((ULONG)TargetFrame < EstablisherFrame.Virtual)) || ((EstablisherFrame.Virtual & 0xF) != 0)) { #if EH_DBG DbgPrint("\n****** Warning - bad stack or target frame (unwind).\n"); DbgPrint(" EstablisherFrame Virtual = %08lx, Real = %08lx\n", EstablisherFrame.Virtual, EstablisherFrame.Real); DbgPrint(" TargetFrame = %08lx\n", TargetFrame); if ((ARGUMENT_PRESENT(TargetFrame) != FALSE) && ((ULONG)TargetFrame < EstablisherFrame.Virtual)) { DbgPrint(" TargetFrame is below EstablisherFrame!\n"); } DbgPrint(" Previous EstablisherFrame (sp) = %08lx\n", (ULONG)ContextRecord->IntSp); DbgPrint(" LowLimit = %08lx, HighLimit = %08lx\n", LowLimit, HighLimit); DbgPrint(" NextPc = %08lx, ControlPc = %08lx\n", NextPc, ControlPc); DbgPrint(" Now raising STATUS_BAD_STACK exception.\n"); #endif _write(2, "C++ EH run-time failure 2 - aborting\n", 37); abort(); } else if ((FunctionEntry->ExceptionHandler != NULL) && InFunction) { #if EH_DBG if (EHRtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION_DETAIL) { DbgPrint("RtlUnwindActions2: ExceptionHandler = %lx, HandlerData = %lx\n", FunctionEntry->ExceptionHandler, FunctionEntry->HandlerData); } #endif // // The frame has an exception handler. // // The control PC, establisher frame pointer, the address // of the function table entry, and the address of the // context record are all stored in the dispatcher context. // This information is used by the unwind linkage routine // and can be used by the exception handler itself. // // A linkage routine written in assembler is used to actually // call the actual exception handler. This is required by the // exception handler that is associated with the linkage // routine so it can have access to two sets of dispatcher // context when it is called. // DispatcherContext.ControlPc = ControlPc; DispatcherContext.FunctionEntry = FunctionEntry; DispatcherContext.EstablisherFrame = EstablisherFrame.Virtual; DispatcherContext.ContextRecord = ContextRecord; // // Call the exception handler. // do { // // If the establisher frame is the target of the unwind // operation, then set the target unwind flag. // if ((ULONG)TargetFrame == EstablisherFrame.Virtual) { ExceptionFlags |= EXCEPTION_TARGET_UNWIND; } ExceptionRecord->ExceptionFlags = ExceptionFlags; // // Set the specified return value in case the exception // handler directly continues execution. // ContextRecord->IntV0 = (ULONGLONG)(LONG)ReturnValue; #if EH_DBG if (EHRtlDebugFlags & RTL_DBG_UNWIND_DETAIL) { DbgPrint("RtlUnwindActions2: calling __CxxExecuteHandlerForUnwind, ControlPc = %lx\n", ControlPc); } #endif Disposition = __CxxExecuteHandlerForUnwind(ExceptionRecord, (PVOID)EstablisherFrame.Virtual, ContextRecord, &DispatcherContext, FunctionEntry->ExceptionHandler); #if EH_DBG if (EHRtlDebugFlags & RTL_DBG_UNWIND_DETAIL) { DbgPrint("RtlUnwindActions2: __CxxExecuteHandlerForUnwind returned Disposition = %lx\n", Disposition); } #endif // // Clear target unwind and collided unwind flags. // ExceptionFlags &= ~(EXCEPTION_COLLIDED_UNWIND | EXCEPTION_TARGET_UNWIND); // // Case on the handler disposition. // switch (Disposition) { // // The disposition is to continue the search. // // If the target frame has not been reached, then // virtually unwind to the caller of the current // routine, update the context record, and continue // the search for a handler. // case ExceptionContinueSearch : if (EstablisherFrame.Virtual != (ULONG)TargetFrame) { NextPc = RtlVirtualUnwind(ControlPc, FunctionEntry, ContextRecord, &InFunction, &EstablisherFrame, NULL); } break; // // The disposition is collided unwind. // // Set the target of the current unwind to the context // record of the previous unwind, and reexecute the // exception handler from the collided frame with the // collided unwind flag set in the exception record. // case ExceptionCollidedUnwind : ControlPc = DispatcherContext.ControlPc; FunctionEntry = DispatcherContext.FunctionEntry; ContextRecord = DispatcherContext.ContextRecord; ContextRecord->Fir = (ULONGLONG)(LONG)TargetIp; ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND; EstablisherFrame.Virtual = DispatcherContext.EstablisherFrame; break; // // All other disposition values are invalid. // // Raise invalid disposition exception. // default : _write(2, "C++ EH run-time failure 3 - aborting\n", 37); abort(); } } while ((ExceptionFlags & EXCEPTION_COLLIDED_UNWIND) != 0); } else { // // Virtually unwind to the caller of the current routine and // update the context record. // if (EstablisherFrame.Virtual != (ULONG)TargetFrame) { NextPc = RtlVirtualUnwind(ControlPc, FunctionEntry, ContextRecord, &InFunction, &EstablisherFrame, NULL); } } } else { // // Set point at which control left the previous routine. // NextPc = (ULONG)ContextRecord->IntRa - 4; // // If the next control PC is the same as the old control PC, then // the function table is not correctly formed. // if (NextPc == ControlPc) { #if EH_DBG ULONG Count; DbgPrint("\n****** Warning - malformed function table (unwind).\n"); DbgPrint("ControlPc = %08lx, %08lx", NextPc, ControlPc); for (Count = 0; Count < PC_HISTORY_DEPTH; Count += 1) { if (ControlPcHistoryIndex > 0) { ControlPcHistoryIndex -= 1; ControlPc = ControlPcHistory[ControlPcHistoryIndex % PC_HISTORY_DEPTH]; DbgPrint(", %08lx", ControlPc); } } DbgPrint(ControlPcHistoryIndex == 0 ? ".\n" : ", ...\n"); DbgPrint(" Now raising STATUS_BAD_FUNCTION_TABLE exception.\n"); #endif _write(2, "C++ EH run-time failure 4 - aborting\n", 37); abort(); } } // // Set point at which control left the previous routine. // #if EH_DBG ControlPcHistory[ControlPcHistoryIndex % PC_HISTORY_DEPTH] = ControlPc; ControlPcHistoryIndex += 1; #endif ControlPc = NextPc; } while ((EstablisherFrame.Virtual < HighLimit) && (EstablisherFrame.Virtual != (ULONG)TargetFrame)); // // If the establisher stack pointer is equal to the target frame // pointer, then continue execution. // Otherwise, something truely horrible has happend. // if (EstablisherFrame.Virtual == (ULONG)TargetFrame) { ContextRecord->IntV0 = (ULONGLONG)(LONG)ReturnValue; #if EH_DBG if (EHRtlDebugFlags & RTL_DBG_UNWIND) { DbgPrint("RtlUnwindActions2: finished unwinding, and calling RtlpRestoreContext(%lx)\n",ContextRecord); } #endif // Do not restore the context here. // For C++ we need to "logicaly" unwind // the stack, perform several actions, // and then finally "physically" unwind // the stack. // RtlpRestoreContext(ContextRecord); return; } else { _write(2, "C++ EH run-time failure 1 - aborting\n", 37); abort(); } }
int setjmp ( IN jmp_buf JumpBuffer ) /*++ Routine Description: This function performs a set jump operation by capturing the current context, virtualy unwinding to the caller of set jump, and returns zero to the caller. Arguments: JumpBuffer - Supplies the address of a jump buffer to store the virtual frame pointer and target address of the caller. N.B. This is an array of double to force quadword alignment. Return Value: A value of zero is returned. --*/ { CONTEXT ContextRecord; ULONG EstablisherFrame; PRUNTIME_FUNCTION FunctionEntry; BOOLEAN InFunction; PULONG JumpArray; ULONG NextPc; // // Capture the current context, virtually unwind to the caller of set // jump, and return zero to the caller. // JumpArray = (PULONG)&JumpBuffer[0]; RtlCaptureContext(&ContextRecord); NextPc = ContextRecord.Lr - 4; FunctionEntry = RtlLookupFunctionEntry(NextPc); NextPc = RtlVirtualUnwind(NextPc, FunctionEntry, &ContextRecord, &InFunction, &EstablisherFrame, NULL, 0, 0xffffffff); JumpArray[1] = NextPc + 4; FunctionEntry = RtlLookupFunctionEntry(NextPc); NextPc = RtlVirtualUnwind(NextPc, FunctionEntry, &ContextRecord, &InFunction, &EstablisherFrame, NULL, 0, 0xffffffff); JumpArray[0] = EstablisherFrame; return 0; }
VOID ExpRaiseException ( IN PEXCEPTION_RECORD ExceptionRecord ) /*++ Routine Description: This function raises a software exception by building a context record and calling the exception dispatcher directly. Arguments: ExceptionRecord - Supplies a pointer to an exception record. Return Value: None. --*/ { ULONG ControlPc; CONTEXT ContextRecord; ULONG EstablisherFrame; PRUNTIME_FUNCTION FunctionEntry; BOOLEAN InFunction; ULONG NextPc; NTSTATUS Status; // // Capture the current context, virtually unwind to the caller of this // routine, set the fault instruction address to that of the caller, and // call the exception dispatcher. // RtlCaptureContext(&ContextRecord); ControlPc = ContextRecord.Lr - 4; FunctionEntry = RtlLookupFunctionEntry(ControlPc); NextPc = RtlVirtualUnwind(ControlPc, FunctionEntry, &ContextRecord, &InFunction, &EstablisherFrame, NULL, 0, 0xffffffff); ContextRecord.Iar = NextPc + 4; ExceptionRecord->ExceptionAddress = (PVOID)ContextRecord.Iar; // // If the exception is successfully dispatched, then continue execution. // Otherwise, give the kernel debugger a chance to handle the exception. // if (RtlDispatchException(ExceptionRecord, &ContextRecord)) { Status = ZwContinue(&ContextRecord, FALSE); } else { Status = ZwRaiseException(ExceptionRecord, &ContextRecord, FALSE); } // // Either the attempt to continue execution or the attempt to give // the kernel debugger a chance to handle the exception failed. Raise // a noncontinuable exception. // ExRaiseStatus(Status); }
VOID ExpRaiseStatus ( IN NTSTATUS ExceptionCode ) /*++ Routine Description: This function raises an exception with the specified status value by building an exception record, building a context record, and calling the exception dispatcher directly. The exception is marked as noncontinuable with no parameters. There is no return from this function. Arguments: ExceptionCode - Supplies the status value to be used as the exception code for the exception that is to be raised. Return Value: None. --*/ { ULONG ControlPc; CONTEXT ContextRecord; ULONG EstablisherFrame; EXCEPTION_RECORD ExceptionRecord; PRUNTIME_FUNCTION FunctionEntry; BOOLEAN InFunction; ULONG NextPc; NTSTATUS Status; // // Construct an exception record. // ExceptionRecord.ExceptionCode = ExceptionCode; ExceptionRecord.ExceptionRecord = (PEXCEPTION_RECORD)NULL; ExceptionRecord.NumberParameters = 0; ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE; // // Capture the current context, virtually unwind to the caller of this // routine, set the fault instruction address to that of the caller, and // call the exception dispatcher. // RtlCaptureContext(&ContextRecord); ControlPc = ContextRecord.Lr - 4; FunctionEntry = RtlLookupFunctionEntry(ControlPc); NextPc = RtlVirtualUnwind(ControlPc, FunctionEntry, &ContextRecord, &InFunction, &EstablisherFrame, NULL, 0, 0xffffffff); ContextRecord.Iar = NextPc + 4; ExceptionRecord.ExceptionAddress = (PVOID)ContextRecord.Iar; RtlDispatchException(&ExceptionRecord, &ContextRecord); // // An unwind was not initiated during the dispatching of a noncontinuable // exception. Give the kernel debugger a chance to handle the exception. // Status = ZwRaiseException(&ExceptionRecord, &ContextRecord, FALSE); // // The attempt to give the kernel debugger a chance to handle the exception // failed. Raise another noncontinuable exception. // ExRaiseStatus(Status); }