|
|
|
|
@ -6,74 +6,129 @@
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <AzCore/Debug/TraceMessageBus.h>
|
|
|
|
|
#include <AzCore/IO/SystemFile.h>
|
|
|
|
|
#include <AzCore/std/string/string_view.h>
|
|
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <execinfo.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()
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
|