Merge pull request #6441 from pollend/feature/5886-add-unhandled-exception-support

feature: add Exception Handler support for unix
This commit is contained in:
Chris Galvan
2022-01-20 12:25:02 -06:00
committed by GitHub
7 changed files with 99 additions and 99 deletions
@@ -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
-42
View File
@@ -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(&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"
@@ -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