From a45b71617d794b8f295276f26c64192f13bb3050 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 26 Feb 2021 13:58:02 +0100 Subject: [PATCH] Add separate `Platform::GetStackTrace` and `Platform::GetStackFrames` --- Source/Engine/Platform/Base/PlatformBase.cpp | 36 +++++++++++++++---- Source/Engine/Platform/Base/PlatformBase.h | 11 +++++- .../Platform/Windows/WindowsPlatform.cpp | 2 +- .../Engine/Platform/Windows/WindowsPlatform.h | 2 +- 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/Source/Engine/Platform/Base/PlatformBase.cpp b/Source/Engine/Platform/Base/PlatformBase.cpp index ba2d6d5f6..5ffb85a9a 100644 --- a/Source/Engine/Platform/Base/PlatformBase.cpp +++ b/Source/Engine/Platform/Base/PlatformBase.cpp @@ -202,11 +202,11 @@ void PlatformBase::Fatal(const Char* msg, void* context) LOG(Error, ""); // Log stack trace - const auto stackTrace = Platform::GetStackTrace(context ? 0 : 1, 60, context); - if (stackTrace.HasItems()) + const auto stackFrames = Platform::GetStackFrames(context ? 0 : 1, 60, context); + if (stackFrames.HasItems()) { LOG(Error, "Stack trace:"); - for (const auto& frame : stackTrace) + for (const auto& frame : stackFrames) { char chr = 0; int32 num = StringUtils::Length(frame.ModuleName); @@ -217,11 +217,11 @@ void PlatformBase::Fatal(const Char* msg, void* context) if (StringUtils::Length(frame.FileName) != 0) { StringAsUTF16 fileName(frame.FileName); - LOG(Error, " at {0}!{1} in {2}:line {3}", moduleName.Get(), functionName.Get(), fileName.Get(), frame.LineNumber); + LOG(Error, " at {0}!{1}() in {2}:line {3}", moduleName.Get(), functionName.Get(), fileName.Get(), frame.LineNumber); } else if (StringUtils::Length(frame.FunctionName) != 0) { - LOG(Error, " at {0}::{1}", moduleName.Get(), functionName.Get()); + LOG(Error, " at {0}!{1}()", moduleName.Get(), functionName.Get()); } else if (StringUtils::Length(frame.ModuleName) != 0) { @@ -483,11 +483,35 @@ int32 PlatformBase::RunProcess(const StringView& cmdLine, const StringView& work return -1; } -Array PlatformBase::GetStackTrace(int32 skipCount, int32 maxDepth, void* context) +Array PlatformBase::GetStackFrames(int32 skipCount, int32 maxDepth, void* context) { return Array(); } +String PlatformBase::GetStackTrace(int32 skipCount, int32 maxDepth, void* context) +{ + StringBuilder result; + Array stackFrames = Platform::GetStackFrames(skipCount, maxDepth, context); + for (const auto& frame : stackFrames) + { + StringAsUTF16 functionName(frame.FunctionName); + if (StringUtils::Length(frame.FileName) != 0) + { + StringAsUTF16 fileName(frame.FileName); + result.AppendFormat(TEXT(" at {0}() in {1}:line {2}\n"), functionName.Get(), fileName.Get(), frame.LineNumber); + } + else if (StringUtils::Length(frame.FunctionName) != 0) + { + result.AppendFormat(TEXT(" at {0}()\n"), functionName.Get()); + } + else + { + result.AppendFormat(TEXT(" at 0x{0:x}\n"), (uint64)frame.ProgramCounter); + } + } + return result.ToString(); +} + void PlatformBase::CollectCrashData(const String& crashDataFolder, void* context) { } diff --git a/Source/Engine/Platform/Base/PlatformBase.h b/Source/Engine/Platform/Base/PlatformBase.h index e97ce2b34..188bad122 100644 --- a/Source/Engine/Platform/Base/PlatformBase.h +++ b/Source/Engine/Platform/Base/PlatformBase.h @@ -804,7 +804,16 @@ public: /// The maximum depth of the stack to collect. Can be used to prevent too long stack traces in case of stack overflow exception. /// The platform-dependent context for the stack trace collecting (eg. platform exception info). /// The collected stack trace frames. Empty if not supported (eg. platform not implements this feature or not supported in the distributed build). - static Array GetStackTrace(int32 skipCount = 0, int32 maxDepth = 60, void* context = nullptr); + static Array GetStackFrames(int32 skipCount = 0, int32 maxDepth = 60, void* context = nullptr); + + /// + /// Gets current native stack trace information as string. + /// + /// The amount of stack frames to skip from the beginning. Can be used to skip the callee function from the trace (eg. in crash handler). + /// The maximum depth of the stack to collect. Can be used to prevent too long stack traces in case of stack overflow exception. + /// The platform-dependent context for the stack trace collecting (eg. platform exception info). + /// The collected stack trace printed into string. Empty if not supported (eg. platform not implements this feature or not supported in the distributed build). + static String GetStackTrace(int32 skipCount = 0, int32 maxDepth = 60, void* context = nullptr); // Crash dump data handling static void CollectCrashData(const String& crashDataFolder, void* context = nullptr); diff --git a/Source/Engine/Platform/Windows/WindowsPlatform.cpp b/Source/Engine/Platform/Windows/WindowsPlatform.cpp index e01ef7a44..83fafdf3e 100644 --- a/Source/Engine/Platform/Windows/WindowsPlatform.cpp +++ b/Source/Engine/Platform/Windows/WindowsPlatform.cpp @@ -1107,7 +1107,7 @@ void* WindowsPlatform::LoadLibrary(const Char* filename) return handle; } -Array WindowsPlatform::GetStackTrace(int32 skipCount, int32 maxDepth, void* context) +Array WindowsPlatform::GetStackFrames(int32 skipCount, int32 maxDepth, void* context) { Array result; #if CRASH_LOG_ENABLE diff --git a/Source/Engine/Platform/Windows/WindowsPlatform.h b/Source/Engine/Platform/Windows/WindowsPlatform.h index f437b819c..94bab3f50 100644 --- a/Source/Engine/Platform/Windows/WindowsPlatform.h +++ b/Source/Engine/Platform/Windows/WindowsPlatform.h @@ -82,7 +82,7 @@ public: static int32 RunProcess(const StringView& cmdLine, const StringView& workingDir, const Dictionary& environment, bool hiddenWindow = true); static Window* CreateWindow(const CreateWindowSettings& settings); static void* LoadLibrary(const Char* filename); - static Array GetStackTrace(int32 skipCount = 0, int32 maxDepth = 60, void* context = nullptr); + static Array GetStackFrames(int32 skipCount = 0, int32 maxDepth = 60, void* context = nullptr); #if CRASH_LOG_ENABLE static void CollectCrashData(const String& crashDataFolder, void* context = nullptr); #endif