/** * Capture a stack backtrace and optionally use the passed in exception pointers. * * @param BackTrace [out] Pointer to array to take backtrace * @param MaxDepth Entries in BackTrace array * @param Context Optional thread context information */ void FWindowsPlatformStackWalk::CaptureStackBackTrace( uint64* BackTrace, uint32 MaxDepth, void* Context ) { // Make sure we have place to store the information before we go through the process of raising // an exception and handling it. if (BackTrace == NULL || MaxDepth == 0) { return; } if (Context) { CaptureStackTraceHelper(BackTrace, MaxDepth, (CONTEXT*)Context); } else { #if USE_FAST_STACKTRACE if (!GMaxCallstackDepthInitialized) { DetermineMaxCallstackDepth(); } PVOID WinBackTrace[MAX_CALLSTACK_DEPTH]; uint16 NumFrames = RtlCaptureStackBackTrace(0, FMath::Min<ULONG>(GMaxCallstackDepth, MaxDepth), WinBackTrace, NULL); for (uint16 FrameIndex = 0; FrameIndex < NumFrames; ++FrameIndex) { BackTrace[FrameIndex] = (uint64)WinBackTrace[FrameIndex]; } while (NumFrames < MaxDepth) { BackTrace[NumFrames++] = 0; } #elif USE_SLOW_STACKTRACE // NOTE: Make sure to enable Stack Frame pointers: bOmitFramePointers = false, or /Oy- // If GStackWalkingInitialized is true, traces will work anyway but will be much slower. if (!GStackWalkingInitialized) { InitStackWalking(); } CONTEXT HelperContext; RtlCaptureContext(&HelperContext); // Capture the back trace. CaptureStackTraceHelper(BackTrace, MaxDepth, &HelperContext); #elif PLATFORM_64BITS // Raise an exception so CaptureStackBackTraceHelper has access to context record. __try { RaiseException(0, // Application-defined exception code. 0, // Zero indicates continuable exception. 0, // Number of arguments in args array (ignored if args is NULL) NULL); // Array of arguments } // Capture the back trace. __except (CaptureStackTraceHelper(BackTrace, MaxDepth, (GetExceptionInformation())->ContextRecord)) { } #else // Use a bit of inline assembly to capture the information relevant to stack walking which is // basically EIP and EBP. CONTEXT HelperContext; memset(&HelperContext, 0, sizeof(CONTEXT)); HelperContext.ContextFlags = CONTEXT_FULL; // Use a fake function call to pop the return address and retrieve EIP. __asm { call FakeFunctionCall FakeFunctionCall : pop eax mov HelperContext.Eip, eax mov HelperContext.Ebp, ebp mov HelperContext.Esp, esp } // Capture the back trace. CaptureStackTraceHelper(BackTrace, MaxDepth, &HelperContext); #endif } }
void PlatformStack::CaptureStackBackTrace(uint64* backTrace, uint32 maxDepth, void* context) { if (backTrace == NULL || maxDepth == 0) { return; } if (context) { CaptureStackTraceHelper(backTrace, maxDepth, (CONTEXT*)context); } else { #if USE_FAST_STACKTRACE //if (!GMaxCallstackDepthInitialized) //{ // DetermineMaxCallstackDepth(); //} PVOID winBackTrace[MAX_CALLSTACK_DEPTH]; uint16 numFrames = RtlCaptureStackBackTrace(0, maxDepth, winBackTrace, NULL); for (uint16 frameIndex = 0; frameIndex < numFrames; ++frameIndex) { backTrace[frameIndex] = (uint64)winBackTrace[frameIndex]; } while (numFrames < maxDepth) { backTrace[numFrames++] = 0; } #elif USE_SLOW_STACKTRACE InitSysStack(); CONTEXT helperContext; RtlCaptureContext(&helperContext); CaptureStackTraceHelper(backTrace, maxDepth, &helperContext); #elif _WIN64 // Raise an exception so CaptureStackBackTraceHelper has access to context record. __try { RaiseException(0, // Application-defined exception code. 0, // Zero indicates continuable exception. 0, // Number of arguments in args array (ignored if args is NULL) NULL); // Array of arguments } // Capture the back trace. __except (CaptureStackTraceHelper(backTrace, maxDepth, (GetExceptionInformation())->ContextRecord)) { } #else // Use a bit of inline assembly to capture the information relevant to stack walking which is // basically EIP and EBP. CONTEXT HelperContext; memset(&HelperContext, 0, sizeof(CONTEXT)); HelperContext.ContextFlags = CONTEXT_FULL; // Use a fake function call to pop the return address and retrieve EIP. __asm { call FakeFunctionCall FakeFunctionCall : pop eax mov HelperContext.Eip, eax mov HelperContext.Ebp, ebp mov HelperContext.Esp, esp } // Capture the back trace. CaptureStackTraceHelper(backTrace, maxDepth, &HelperContext); #endif } }