From ada7c41a34031b3d50807d7f86b0bc50cce66b83 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 15 Dec 2021 19:18:24 -0800 Subject: [PATCH 1/5] feature: add Exception Handler support for unix REF: https://github.com/o3de/o3de/issues/5886 Signed-off-by: Michael Pollind --- .../UnixLike/AzCore/Debug/Trace_UnixLike.cpp | 155 ++++++++++++------ Code/Legacy/CrySystem/SystemInit.cpp | 42 ----- 2 files changed, 105 insertions(+), 92 deletions(-) diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp index 92a80b0d9a..b0ee4ea1e3 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp @@ -6,74 +6,129 @@ * */ +#include #include #include #include +#include #include #include -namespace AZ::Debug::Platform +namespace AZ::Debug { #if defined(AZ_ENABLE_DEBUG_TOOLS) - bool performDebuggerDetection() + void ExceptionHandler(int signal); +#endif + + constexpr int MaxMessageLength = 4096; + constexpr int MaxStackLines = 100; + + namespace Platform { - AZ::IO::SystemFile processStatusFile; - if (!processStatusFile.Open("/proc/self/status", AZ::IO::SystemFile::SF_OPEN_READ_ONLY)) +#if defined(AZ_ENABLE_DEBUG_TOOLS) + bool performDebuggerDetection() { - return false; - } - - char buffer[4096]; - AZ::IO::SystemFile::SizeType numRead = processStatusFile.Read(sizeof(buffer), buffer); - - const AZStd::string_view processStatusView(buffer, buffer + numRead); - constexpr AZStd::string_view tracerPidString = "TracerPid:"; - const size_t tracerPidOffset = processStatusView.find(tracerPidString); - if (tracerPidOffset == AZStd::string_view::npos) - { - return false; - } - for (size_t i = tracerPidOffset + tracerPidString.length(); i < numRead; ++i) - { - if (!::isspace(processStatusView[i])) + AZ::IO::SystemFile processStatusFile; + if (!processStatusFile.Open("/proc/self/status", AZ::IO::SystemFile::SF_OPEN_READ_ONLY)) { - return processStatusView[i] != '0'; + return false; + } + + char buffer[4096]; + AZ::IO::SystemFile::SizeType numRead = processStatusFile.Read(sizeof(buffer), buffer); + + const AZStd::string_view processStatusView(buffer, buffer + numRead); + constexpr AZStd::string_view tracerPidString = "TracerPid:"; + const size_t tracerPidOffset = processStatusView.find(tracerPidString); + if (tracerPidOffset == AZStd::string_view::npos) + { + return false; + } + for (size_t i = tracerPidOffset + tracerPidString.length(); i < numRead; ++i) + { + if (!::isspace(processStatusView[i])) + { + return processStatusView[i] != '0'; + } + } + return false; + } + + bool IsDebuggerPresent() + { + static bool s_detectionPerformed = false; + static bool s_debuggerDetected = false; + if (!s_detectionPerformed) + { + s_debuggerDetected = performDebuggerDetection(); + s_detectionPerformed = true; + } + return s_debuggerDetected; + } + + bool AttachDebugger() + { + // Not supported yet + AZ_Assert(false, "AttachDebugger() is not supported for Unix platform yet"); + return false; + } + + void SignalHandler(int handler) + { + } + + void HandleExceptions(bool isEnabled) + { + if (isEnabled) + { + signal(SIGSEGV, ExceptionHandler); + signal(SIGTRAP, ExceptionHandler); + signal(SIGILL, ExceptionHandler); + } + else + { + signal(SIGSEGV, SIG_DFL); + signal(SIGTRAP, SIG_DFL); + signal(SIGILL, SIG_DFL); } } - return false; - } - bool IsDebuggerPresent() - { - static bool s_detectionPerformed = false; - static bool s_debuggerDetected = false; - if (!s_detectionPerformed) + void DebugBreak() { - s_debuggerDetected = performDebuggerDetection(); - s_detectionPerformed = true; + raise(SIGINT); } - return s_debuggerDetected; - } - - bool AttachDebugger() - { - // Not supported yet - AZ_Assert(false, "AttachDebugger() is not supported for Unix platform yet"); - return false; - } - - void HandleExceptions(bool) - {} - - void DebugBreak() - { - raise(SIGINT); - } #endif // AZ_ENABLE_DEBUG_TOOLS - void Terminate(int exitCode) + void Terminate(int exitCode) + { + _exit(exitCode); + } + } // namespace Platform + +#if defined(AZ_ENABLE_DEBUG_TOOLS) + void ExceptionHandler(int signal) { - _exit(exitCode); + char message[MaxMessageLength]; + Debug::Trace::Instance().Output(nullptr, "==================================================================\n"); + azsnprintf(message, MaxMessageLength, "Error: signal %s: \n", strsignal(signal)); + Debug::Trace::Instance().Output(nullptr, message); + + void* buffers[MaxStackLines]; + int numberBacktraceStrings = backtrace(buffers, MaxStackLines); + char** backtraceResults = backtrace_symbols(buffers, numberBacktraceStrings); + if (backtraceResults == nullptr) + { + Debug::Trace::Instance().Output(nullptr, "==================================================================\n"); + return; + } + for (int j = 0; j < numberBacktraceStrings; j++) + { + Debug::Trace::Instance().Output(nullptr, backtraceResults[j]); + } + + Debug::Trace::Instance().Output(nullptr, "==================================================================\n"); } -} // namespace AZ::Debug::Platform +#endif + +} // namespace AZ::Debug diff --git a/Code/Legacy/CrySystem/SystemInit.cpp b/Code/Legacy/CrySystem/SystemInit.cpp index 09bbc3773a..f3f9442322 100644 --- a/Code/Legacy/CrySystem/SystemInit.cpp +++ b/Code/Legacy/CrySystem/SystemInit.cpp @@ -115,43 +115,6 @@ extern LONG WINAPI CryEngineExceptionFilterWER(struct _EXCEPTION_POINTERS* pExce #include AZ_RESTRICTED_FILE(SystemInit_cpp) #endif -#if AZ_TRAIT_USE_CRY_SIGNAL_HANDLER - -#include -#include -void CryEngineSignalHandler(int signal) -{ - char resolvedPath[_MAX_PATH]; - - // it is assumed that @log@ points at the appropriate place (so for apple, to the user profile dir) - if (AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath("@log@/crash.log", resolvedPath, _MAX_PATH)) - { - fprintf(stderr, "Crash Signal Handler - logged to %s\n", resolvedPath); - FILE* file = fopen(resolvedPath, "a"); - if (file) - { - char sTime[128]; - time_t ltime; - time(<ime); - struct tm* today = localtime(<ime); - strftime(sTime, 40, "<%Y-%m-%d %H:%M:%S> ", today); - fprintf(file, "%s: Error: signal %s:\n", sTime, strsignal(signal)); - fflush(file); - void* array[100]; - int s = backtrace(array, 100); - backtrace_symbols_fd(array, s, fileno(file)); - fclose(file); - CryLogAlways("Successfully recorded crash file: '%s'", resolvedPath); - abort(); - } - } - - CryLogAlways("Could not record crash file..."); - abort(); -} - -#endif // AZ_TRAIT_USE_CRY_SIGNAL_HANDLER - ////////////////////////////////////////////////////////////////////////// #define DEFAULT_LOG_FILENAME "@log@/Log.txt" @@ -697,11 +660,6 @@ public: ///////////////////////////////////////////////////////////////////////////////// bool CSystem::Init(const SSystemInitParams& startupParams) { -#if AZ_TRAIT_USE_CRY_SIGNAL_HANDLER - signal(SIGSEGV, CryEngineSignalHandler); - signal(SIGTRAP, CryEngineSignalHandler); - signal(SIGILL, CryEngineSignalHandler); -#endif // AZ_TRAIT_USE_CRY_SIGNAL_HANDLER // Temporary Fix for an issue accessing gEnv from this object instance. The gEnv is not resolving to the // global gEnv, instead its resolving an some uninitialized gEnv elsewhere (NULL). Since gEnv is From 833598d68fc737c82982b85608be387ad9922886 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 16 Dec 2021 20:30:56 -0800 Subject: [PATCH 2/5] chore: remove signal handler Signed-off-by: Michael Pollind --- .../AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h | 1 - .../Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h | 1 - Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h | 1 - .../AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h | 1 - Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h | 1 - 5 files changed, 5 deletions(-) diff --git a/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h b/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h index e8efce1133..e99f29e051 100644 --- a/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h +++ b/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h @@ -98,7 +98,6 @@ #define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE static_cast(sysconf(_SC_NPROCESSORS_ONLN)); #define AZ_TRAIT_UNITTEST_NON_PREALLOCATED_HPHA_TEST 0 #define AZ_TRAIT_UNITTEST_USE_TEST_RUNNER_ENVIRONMENT 1 -#define AZ_TRAIT_USE_CRY_SIGNAL_HANDLER 0 #define AZ_TRAIT_USE_POSIX_STRERROR_R 1 #define AZ_TRAIT_USE_SECURE_CRT_FUNCTIONS 0 #define AZ_TRAIT_USE_WINDOWS_FILE_API 0 diff --git a/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h b/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h index 59d5f3c5ed..e5e52995a1 100644 --- a/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h +++ b/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h @@ -98,7 +98,6 @@ #define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE static_cast(sysconf(_SC_NPROCESSORS_ONLN)); #define AZ_TRAIT_UNITTEST_NON_PREALLOCATED_HPHA_TEST 0 #define AZ_TRAIT_UNITTEST_USE_TEST_RUNNER_ENVIRONMENT 0 -#define AZ_TRAIT_USE_CRY_SIGNAL_HANDLER 1 #define AZ_TRAIT_USE_POSIX_STRERROR_R 1 #define AZ_TRAIT_USE_SECURE_CRT_FUNCTIONS 0 #define AZ_TRAIT_USE_WINDOWS_FILE_API 0 diff --git a/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h b/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h index 1a3d0663e1..9a6c76fe2d 100644 --- a/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h +++ b/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h @@ -98,7 +98,6 @@ #define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE static_cast(sysconf(_SC_NPROCESSORS_ONLN)); #define AZ_TRAIT_UNITTEST_NON_PREALLOCATED_HPHA_TEST 0 #define AZ_TRAIT_UNITTEST_USE_TEST_RUNNER_ENVIRONMENT 0 -#define AZ_TRAIT_USE_CRY_SIGNAL_HANDLER 1 #define AZ_TRAIT_USE_POSIX_STRERROR_R 1 #define AZ_TRAIT_USE_SECURE_CRT_FUNCTIONS 0 #define AZ_TRAIT_USE_WINDOWS_FILE_API 0 diff --git a/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h b/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h index 1a83aba267..71d6b395c5 100644 --- a/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h +++ b/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h @@ -98,7 +98,6 @@ #define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE INVALID_RETURN_VALUE #define AZ_TRAIT_UNITTEST_NON_PREALLOCATED_HPHA_TEST 1 #define AZ_TRAIT_UNITTEST_USE_TEST_RUNNER_ENVIRONMENT 0 -#define AZ_TRAIT_USE_CRY_SIGNAL_HANDLER 0 #define AZ_TRAIT_USE_POSIX_STRERROR_R 0 #define AZ_TRAIT_USE_SECURE_CRT_FUNCTIONS 1 #define AZ_TRAIT_USE_WINDOWS_FILE_API 1 diff --git a/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h b/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h index 7a75af71fb..11a0ba84e0 100644 --- a/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h +++ b/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h @@ -99,7 +99,6 @@ #define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE static_cast(sysconf(_SC_NPROCESSORS_ONLN)); #define AZ_TRAIT_UNITTEST_NON_PREALLOCATED_HPHA_TEST 0 #define AZ_TRAIT_UNITTEST_USE_TEST_RUNNER_ENVIRONMENT 0 -#define AZ_TRAIT_USE_CRY_SIGNAL_HANDLER 1 #define AZ_TRAIT_USE_POSIX_STRERROR_R 1 #define AZ_TRAIT_USE_SECURE_CRT_FUNCTIONS 0 #define AZ_TRAIT_USE_WINDOWS_FILE_API 0 From 21850aa73ea90c6846f2b47903d5ac1b6b916b05 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 23 Dec 2021 15:09:29 -0800 Subject: [PATCH 3/5] chore: replace stack trace logic with StackRecorder Signed-off-by: Michael Pollind --- .../UnixLike/AzCore/Debug/Trace_UnixLike.cpp | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp index b0ee4ea1e3..67de4a3219 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp @@ -9,11 +9,9 @@ #include #include #include +#include -#include -#include #include -#include namespace AZ::Debug { @@ -114,19 +112,15 @@ namespace AZ::Debug azsnprintf(message, MaxMessageLength, "Error: signal %s: \n", strsignal(signal)); Debug::Trace::Instance().Output(nullptr, message); - void* buffers[MaxStackLines]; - int numberBacktraceStrings = backtrace(buffers, MaxStackLines); - char** backtraceResults = backtrace_symbols(buffers, numberBacktraceStrings); - if (backtraceResults == nullptr) - { - Debug::Trace::Instance().Output(nullptr, "==================================================================\n"); - return; + StackFrame frames[MaxStackLines]; + SymbolStorage::StackLine stackLines[MaxStackLines]; + SymbolStorage decoder; + const unsigned int numberOfFrames = StackRecorder::Record(frames, MaxStackLines); + decoder.DecodeFrames(frames, numberOfFrames, stackLines); + for(int i = 0; i < numberOfFrames; ++i) { + azsnprintf(message, MaxMessageLength, "%s \n", stackLines[i]); + Debug::Trace::Instance().Output(nullptr, message); } - for (int j = 0; j < numberBacktraceStrings; j++) - { - Debug::Trace::Instance().Output(nullptr, backtraceResults[j]); - } - Debug::Trace::Instance().Output(nullptr, "==================================================================\n"); } #endif From 39c09ba6f70fade423993b8d120b3fa66527ff60 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 4 Jan 2022 21:10:56 -0800 Subject: [PATCH 4/5] chore: correct formatting and address comments Signed-off-by: Michael Pollind --- .../UnixLike/AzCore/Debug/Trace_UnixLike.cpp | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp index 67de4a3219..e1f1a0f801 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp @@ -6,10 +6,10 @@ * */ +#include #include #include #include -#include #include @@ -33,7 +33,7 @@ namespace AZ::Debug return false; } - char buffer[4096]; + char buffer[MaxMessageLength]; AZ::IO::SystemFile::SizeType numRead = processStatusFile.Read(sizeof(buffer), buffer); const AZStd::string_view processStatusView(buffer, buffer + numRead); @@ -72,10 +72,6 @@ namespace AZ::Debug return false; } - void SignalHandler(int handler) - { - } - void HandleExceptions(bool isEnabled) { if (isEnabled) @@ -108,20 +104,22 @@ namespace AZ::Debug void ExceptionHandler(int signal) { char message[MaxMessageLength]; - Debug::Trace::Instance().Output(nullptr, "==================================================================\n"); + // Trace::RawOutput + Debug::Trace::Instance().RawOutput(nullptr, "==================================================================\n"); azsnprintf(message, MaxMessageLength, "Error: signal %s: \n", strsignal(signal)); - Debug::Trace::Instance().Output(nullptr, message); + Debug::Trace::Instance().RawOutput(nullptr, message); StackFrame frames[MaxStackLines]; SymbolStorage::StackLine stackLines[MaxStackLines]; SymbolStorage decoder; const unsigned int numberOfFrames = StackRecorder::Record(frames, MaxStackLines); - decoder.DecodeFrames(frames, numberOfFrames, stackLines); - for(int i = 0; i < numberOfFrames; ++i) { + decoder.DecodeFrames(frames, numberOfFrames, stackLines); + for (int i = 0; i < numberOfFrames; ++i) + { azsnprintf(message, MaxMessageLength, "%s \n", stackLines[i]); - Debug::Trace::Instance().Output(nullptr, message); + Debug::Trace::Instance().RawOutput(nullptr, message); } - Debug::Trace::Instance().Output(nullptr, "==================================================================\n"); + Debug::Trace::Instance().RawOutput(nullptr, "==================================================================\n"); } #endif From c95845d45b3523092ac61fc4eab5c9199749af0d Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 19 Jan 2022 20:02:50 -0800 Subject: [PATCH 5/5] chore: replace isspace Signed-off-by: Michael Pollind --- .../Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp index e1f1a0f801..e89c46bce7 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp @@ -45,7 +45,7 @@ namespace AZ::Debug } for (size_t i = tracerPidOffset + tracerPidString.length(); i < numRead; ++i) { - if (!::isspace(processStatusView[i])) + if (processStatusView[i] != ' ') { return processStatusView[i] != '0'; }