Browse Source

feature: add Exception Handler support for unix

REF: https://github.com/o3de/o3de/issues/5886

Signed-off-by: Michael Pollind <[email protected]>
Michael Pollind 3 years ago
parent
commit
ada7c41a34

+ 95 - 40
Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp

@@ -6,74 +6,129 @@
  *
  *
  */
  */
 
 
+#include <AzCore/Debug/TraceMessageBus.h>
 #include <AzCore/IO/SystemFile.h>
 #include <AzCore/IO/SystemFile.h>
 #include <AzCore/std/string/string_view.h>
 #include <AzCore/std/string/string_view.h>
 
 
 #include <ctype.h>
 #include <ctype.h>
+#include <execinfo.h>
 #include <signal.h>
 #include <signal.h>
 #include <unistd.h>
 #include <unistd.h>
 
 
-namespace AZ::Debug::Platform
+namespace AZ::Debug
 {
 {
 #if defined(AZ_ENABLE_DEBUG_TOOLS)
 #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()
         {
         {
+            AZ::IO::SystemFile processStatusFile;
+            if (!processStatusFile.Open("/proc/self/status", AZ::IO::SystemFile::SF_OPEN_READ_ONLY))
+            {
+                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;
             return false;
         }
         }
 
 
-        char buffer[4096];
-        AZ::IO::SystemFile::SizeType numRead = processStatusFile.Read(sizeof(buffer), buffer);
+        bool IsDebuggerPresent()
+        {
+            static bool s_detectionPerformed = false;
+            static bool s_debuggerDetected = false;
+            if (!s_detectionPerformed)
+            {
+                s_debuggerDetected = performDebuggerDetection();
+                s_detectionPerformed = true;
+            }
+            return s_debuggerDetected;
+        }
 
 
-        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)
+        bool AttachDebugger()
         {
         {
+            // Not supported yet
+            AZ_Assert(false, "AttachDebugger() is not supported for Unix platform yet");
             return false;
             return false;
         }
         }
-        for (size_t i = tracerPidOffset + tracerPidString.length(); i < numRead; ++i)
+
+        void SignalHandler(int handler)
+        {
+        }
+
+        void HandleExceptions(bool isEnabled)
         {
         {
-            if (!::isspace(processStatusView[i]))
+            if (isEnabled)
             {
             {
-                return processStatusView[i] != '0';
+                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;
-    }
+#endif // AZ_ENABLE_DEBUG_TOOLS
 
 
-    bool AttachDebugger()
+        void Terminate(int exitCode)
+        {
+            _exit(exitCode);
+        }
+    } // namespace Platform
+
+#if defined(AZ_ENABLE_DEBUG_TOOLS)
+    void ExceptionHandler(int signal)
     {
     {
-        // Not supported yet
-        AZ_Assert(false, "AttachDebugger() is not supported for Unix platform yet");
-        return false;
-    }
+        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 HandleExceptions(bool)
-    {}
+        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]);
+        }
 
 
-    void DebugBreak()
-    {
-        raise(SIGINT);
+        Debug::Trace::Instance().Output(nullptr, "==================================================================\n");
     }
     }
-#endif // AZ_ENABLE_DEBUG_TOOLS
+#endif
 
 
-    void Terminate(int exitCode)
-    {
-        _exit(exitCode);
-    }
-} // namespace AZ::Debug::Platform
+} // namespace AZ::Debug

+ 0 - 42
Code/Legacy/CrySystem/SystemInit.cpp

@@ -115,43 +115,6 @@ extern LONG WINAPI CryEngineExceptionFilterWER(struct _EXCEPTION_POINTERS* pExce
 #include AZ_RESTRICTED_FILE(SystemInit_cpp)
 #include AZ_RESTRICTED_FILE(SystemInit_cpp)
 #endif
 #endif
 
 
-#if AZ_TRAIT_USE_CRY_SIGNAL_HANDLER
-
-#include <execinfo.h>
-#include <signal.h>
-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(&ltime);
-            struct tm* today = localtime(&ltime);
-            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"
 #define DEFAULT_LOG_FILENAME "@log@/Log.txt"
 
 
@@ -697,11 +660,6 @@ public:
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
 bool CSystem::Init(const SSystemInitParams& startupParams)
 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
     // 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
     // global gEnv, instead its resolving an some uninitialized gEnv elsewhere (NULL). Since gEnv is