/**
 * 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
	}	
}
Esempio n. 2
0
	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
		}
	}