Merge pull request #6441 from pollend/feature/5886-add-unhandled-exception-support
feature: add Exception Handler support for unix
This commit is contained in:
@@ -98,7 +98,6 @@
|
||||
#define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE static_cast<unsigned int>(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
|
||||
|
||||
@@ -6,74 +6,121 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Debug/StackTracer.h>
|
||||
#include <AzCore/Debug/TraceMessageBus.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/std/string/string_view.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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[MaxMessageLength];
|
||||
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 (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 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];
|
||||
// Trace::RawOutput
|
||||
Debug::Trace::Instance().RawOutput(nullptr, "==================================================================\n");
|
||||
azsnprintf(message, MaxMessageLength, "Error: signal %s: \n", strsignal(signal));
|
||||
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)
|
||||
{
|
||||
azsnprintf(message, MaxMessageLength, "%s \n", stackLines[i]);
|
||||
Debug::Trace::Instance().RawOutput(nullptr, message);
|
||||
}
|
||||
Debug::Trace::Instance().RawOutput(nullptr, "==================================================================\n");
|
||||
}
|
||||
} // namespace AZ::Debug::Platform
|
||||
#endif
|
||||
|
||||
} // namespace AZ::Debug
|
||||
|
||||
@@ -98,7 +98,6 @@
|
||||
#define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE static_cast<unsigned int>(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
|
||||
|
||||
@@ -98,7 +98,6 @@
|
||||
#define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE static_cast<unsigned int>(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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -99,7 +99,6 @@
|
||||
#define AZ_TRAIT_THREAD_HARDWARE_CONCURRENCY_RETURN_VALUE static_cast<unsigned int>(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
|
||||
|
||||
@@ -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 <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(<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
|
||||
|
||||
Reference in New Issue
Block a user