Files
UnrealEngine/Engine/Source/Runtime/AutoRTFM/Private/Utils.cpp
2025-05-18 13:04:45 +08:00

115 lines
3.3 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#if (defined(__AUTORTFM) && __AUTORTFM)
#include "Utils.h"
#include "ContextInlines.h"
#include "BuildMacros.h"
#include <utility>
#if AUTORTFM_PLATFORM_WINDOWS
#include "WindowsHeader.h"
#include <dbghelp.h>
#else
#include <execinfo.h>
#endif
namespace AutoRTFM
{
std::string GetFunctionDescription(void* FunctionPtr)
{
#if AUTORTFM_PLATFORM_WINDOWS
// This is gross, but it works. It's possible for someone to have SymInitialized before. But if they had, then this
// will just fail. Also, this function is called in cases where we're failing, so it's ok if we do dirty things.
SymInitialize(GetCurrentProcess(), nullptr, true);
DWORD64 Displacement = 0;
DWORD64 Address = reinterpret_cast<DWORD64>(FunctionPtr);
char Buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO Symbol = reinterpret_cast<PSYMBOL_INFO>(Buffer);
Symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
Symbol->MaxNameLen = MAX_SYM_NAME;
if (SymFromAddr(GetCurrentProcess(), Address, &Displacement, Symbol))
{
return Symbol->Name;
}
else
{
return "<error getting description>";
}
#else // AUTORTFM_PLATFORM_WINDOWS -> so !AUTORTFM_PLATFORM_WINDOWS
char** const symbols = backtrace_symbols(&FunctionPtr, 1);
std::string Name(*symbols);
free(symbols);
return Name;
#endif // AUTORTFM_PLATFORM_WINDOWS -> so !AUTORTFM_PLATFORM_WINDOWS
}
UE_AUTORTFM_API UE_AUTORTFM_FORCENOINLINE void ReportError(const char* File, int Line, void* ProgramCounter, const char* Format, ...)
{
if (ProgramCounter == nullptr)
{
ProgramCounter = __builtin_return_address(0);
}
const ForTheRuntime::EAutoRTFMInternalAbortActionState InternalAbortAction = ForTheRuntime::GetInternalAbortAction();
if (Format)
{
if (InternalAbortAction == ForTheRuntime::EAutoRTFMInternalAbortActionState::Crash)
{
va_list Args;
va_start(Args, Format);
::AutoRTFM::LogV(File, Line, ProgramCounter, autortfm_log_fatal, Format, Args);
va_end(Args);
}
else if (ForTheRuntime::GetEnsureOnInternalAbort())
{
va_list Args;
va_start(Args, Format);
[[maybe_unused]] static bool bCalled = [&]
{
::AutoRTFM::EnsureFailureV(File, Line, ProgramCounter, "!GetEnsureOnInternalAbort()", Format, Args);
return true;
}();
va_end(Args);
}
}
else
{
if (InternalAbortAction == ForTheRuntime::EAutoRTFMInternalAbortActionState::Crash)
{
::AutoRTFM::Log(File, Line, ProgramCounter, autortfm_log_fatal, "Transaction failing because of internal issue");
}
else if (ForTheRuntime::GetEnsureOnInternalAbort())
{
[[maybe_unused]] static bool bCalled = [&]
{
::AutoRTFM::EnsureFailure(File, Line, ProgramCounter, "!GetEnsureOnInternalAbort()", "Transaction failing because of internal issue");
return true;
}();
}
}
if (FContext* const Context = FContext::Get())
{
if (InternalAbortAction == ForTheRuntime::EAutoRTFMInternalAbortActionState::Abort)
{
Context->AbortByLanguageAndThrow();
}
else
{
TTask<void()> Task = [] { AUTORTFM_ENSURE(ForTheRuntime::SetAutoRTFMRuntime(ForTheRuntime::AutoRTFM_ForcedDisabled)); };
Context->AbortTransactionWithPostAbortCallback(EContextStatus::AbortedByCascadingRetry, std::move(Task));
}
}
}
} // namespace AutoRTFM
#endif // defined(__AUTORTFM) && __AUTORTFM