mirror of
https://github.com/bkaradzic/bx.git
synced 2026-02-17 12:42:34 +01:00
Added Linux/signal exception handling.
This commit is contained in:
@@ -115,12 +115,13 @@ namespace bx
|
|||||||
/// Assert handler function.
|
/// Assert handler function.
|
||||||
///
|
///
|
||||||
/// @param[in] _location Source code location where function is called.
|
/// @param[in] _location Source code location where function is called.
|
||||||
|
/// @param[in] _skip Skip top N stack frames.
|
||||||
/// @param[in] _format Printf style format.
|
/// @param[in] _format Printf style format.
|
||||||
/// @param[in] _argList Arguments for `_format` specification.
|
/// @param[in] _argList Arguments for `_format` specification.
|
||||||
///
|
///
|
||||||
/// @returns True if assert should stop code execution, otherwise returns false.
|
/// @returns True if assert should stop code execution, otherwise returns false.
|
||||||
///
|
///
|
||||||
typedef bool (*AssertHandlerFn)(const Location& _location, const char* _format, va_list _argList);
|
typedef bool (*AssertHandlerFn)(const Location& _location, uint32_t _skip, const char* _format, va_list _argList);
|
||||||
|
|
||||||
/// Set assert handler function.
|
/// Set assert handler function.
|
||||||
///
|
///
|
||||||
@@ -133,12 +134,13 @@ namespace bx
|
|||||||
/// Assert function calls AssertHandlerFn.
|
/// Assert function calls AssertHandlerFn.
|
||||||
///
|
///
|
||||||
/// @param[in] _location Source code location where function is called.
|
/// @param[in] _location Source code location where function is called.
|
||||||
|
/// @param[in] _skip Skip top N stack frames.
|
||||||
/// @param[in] _format Printf style format.
|
/// @param[in] _format Printf style format.
|
||||||
/// @param[in] ... Arguments for `_format` specification.
|
/// @param[in] ... Arguments for `_format` specification.
|
||||||
///
|
///
|
||||||
/// @returns True if assert should stop code execution, otherwise returns false.
|
/// @returns True if assert should stop code execution, otherwise returns false.
|
||||||
///
|
///
|
||||||
bool assertFunction(const Location& _location, const char* _format, ...);
|
bool assertFunction(const Location& _location, uint32_t _skip, const char* _format, ...);
|
||||||
|
|
||||||
/// Arithmetic type `Ty` limits.
|
/// Arithmetic type `Ty` limits.
|
||||||
template<typename Ty, bool SignT = isSigned<Ty>()>
|
template<typename Ty, bool SignT = isSigned<Ty>()>
|
||||||
|
|||||||
@@ -260,22 +260,22 @@ extern "C" void* __cdecl _alloca(size_t _size);
|
|||||||
bx::debugPrintf("%s(%d): BX " _format "\n", _location.filePath, _location.line, ##__VA_ARGS__); \
|
bx::debugPrintf("%s(%d): BX " _format "\n", _location.filePath, _location.line, ##__VA_ARGS__); \
|
||||||
BX_MACRO_BLOCK_END
|
BX_MACRO_BLOCK_END
|
||||||
|
|
||||||
#define _BX_ASSERT(_condition, _format, ...) \
|
#define _BX_ASSERT(_condition, _format, ...) \
|
||||||
BX_MACRO_BLOCK_BEGIN \
|
BX_MACRO_BLOCK_BEGIN \
|
||||||
if (!BX_IGNORE_C4127(_condition) \
|
if (!BX_IGNORE_C4127(_condition) \
|
||||||
&& bx::assertFunction(bx::Location::current(), "ASSERT %s -> " _format, #_condition, ##__VA_ARGS__) ) \
|
&& bx::assertFunction(bx::Location::current(), 0, "ASSERT %s -> " _format, #_condition, ##__VA_ARGS__) ) \
|
||||||
{ \
|
{ \
|
||||||
bx::debugBreak(); \
|
bx::debugBreak(); \
|
||||||
} \
|
} \
|
||||||
BX_MACRO_BLOCK_END
|
BX_MACRO_BLOCK_END
|
||||||
|
|
||||||
#define _BX_ASSERT_LOC(_location, _condition, _format, ...) \
|
#define _BX_ASSERT_LOC(_location, _condition, _format, ...) \
|
||||||
BX_MACRO_BLOCK_BEGIN \
|
BX_MACRO_BLOCK_BEGIN \
|
||||||
if (!BX_IGNORE_C4127(_condition) \
|
if (!BX_IGNORE_C4127(_condition) \
|
||||||
&& bx::assertFunction(_location, "ASSERT %s -> " _format, #_condition, ##__VA_ARGS__) ) \
|
&& bx::assertFunction(_location, 0, "ASSERT %s -> " _format, #_condition, ##__VA_ARGS__) ) \
|
||||||
{ \
|
{ \
|
||||||
bx::debugBreak(); \
|
bx::debugBreak(); \
|
||||||
} \
|
} \
|
||||||
BX_MACRO_BLOCK_END
|
BX_MACRO_BLOCK_END
|
||||||
|
|
||||||
#define _BX_WARN(_condition, _format, ...) \
|
#define _BX_WARN(_condition, _format, ...) \
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ namespace bx
|
|||||||
void* exec(const char* const* _argv);
|
void* exec(const char* const* _argv);
|
||||||
|
|
||||||
///
|
///
|
||||||
[[noreturn]] void exit(int32_t _exitCode);
|
[[noreturn]] void exit(int32_t _exitCode, bool _cleanup = true);
|
||||||
|
|
||||||
///
|
///
|
||||||
void* memoryMap(void* _address, size_t _size, Error* _err);
|
void* memoryMap(void* _address, size_t _size, Error* _err);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <bx/debug.h>
|
#include <bx/debug.h>
|
||||||
#include <bx/readerwriter.h>
|
#include <bx/readerwriter.h>
|
||||||
|
#include <bx/os.h>
|
||||||
|
|
||||||
#if !BX_CRT_NONE
|
#if !BX_CRT_NONE
|
||||||
# include <string.h> // memcpy, memmove, memset
|
# include <string.h> // memcpy, memmove, memset
|
||||||
@@ -22,7 +23,7 @@ namespace bx
|
|||||||
return LocationFull(_function, _filePath, _line);
|
return LocationFull(_function, _filePath, _line);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool defaultAssertHandler(const Location& _location, const char* _format, va_list _argList)
|
static bool defaultAssertHandler(const Location& _location, uint32_t _skip, const char* _format, va_list _argList)
|
||||||
{
|
{
|
||||||
char temp[8192];
|
char temp[8192];
|
||||||
int32_t total = 0;
|
int32_t total = 0;
|
||||||
@@ -41,7 +42,7 @@ namespace bx
|
|||||||
total += write(&smb, "\n\n", &err);
|
total += write(&smb, "\n\n", &err);
|
||||||
|
|
||||||
uintptr_t stack[32];
|
uintptr_t stack[32];
|
||||||
const uint32_t num = getCallStack(2 /* skip self */, BX_COUNTOF(stack), stack);
|
const uint32_t num = getCallStack(2 /* skip self */ + _skip, BX_COUNTOF(stack), stack);
|
||||||
total += writeCallstack(&smb, stack, num, &err);
|
total += writeCallstack(&smb, stack, num, &err);
|
||||||
|
|
||||||
total += write(&smb, &err,
|
total += write(&smb, &err,
|
||||||
@@ -80,11 +81,11 @@ namespace bx
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool assertFunction(const Location& _location, const char* _format, ...)
|
bool assertFunction(const Location& _location, uint32_t _skip, const char* _format, ...)
|
||||||
{
|
{
|
||||||
va_list argList;
|
va_list argList;
|
||||||
va_start(argList, _format);
|
va_start(argList, _format);
|
||||||
const bool result = s_assertHandler(_location, _format, argList);
|
const bool result = s_assertHandler(_location, _skip, _format, argList);
|
||||||
va_end(argList);
|
va_end(argList);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
102
src/debug.cpp
102
src/debug.cpp
@@ -22,6 +22,15 @@
|
|||||||
# include <cxxabi.h> // abi::__cxa_demangle
|
# include <cxxabi.h> // abi::__cxa_demangle
|
||||||
#endif // BX_CONFIG_CALLSTACK_*
|
#endif // BX_CONFIG_CALLSTACK_*
|
||||||
|
|
||||||
|
#ifndef BX_CONFIG_EXCEPTION_HANDLING_USE_SIGNALS
|
||||||
|
# define BX_CONFIG_EXCEPTION_HANDLING_USE_SIGNALS 0 \
|
||||||
|
| (BX_PLATFORM_LINUX && !BX_CRT_NONE)
|
||||||
|
#endif // BX_CONFIG_EXCEPTION_HANDLING_USE_SIGNALS
|
||||||
|
|
||||||
|
#if BX_CONFIG_EXCEPTION_HANDLING_USE_SIGNALS
|
||||||
|
# include <signal.h>
|
||||||
|
#endif // BX_CONFIG_EXCEPTION_HANDLING_USE_SIGNALS
|
||||||
|
|
||||||
#if BX_CRT_NONE
|
#if BX_CRT_NONE
|
||||||
# include <bx/crt0.h>
|
# include <bx/crt0.h>
|
||||||
#elif BX_PLATFORM_ANDROID
|
#elif BX_PLATFORM_ANDROID
|
||||||
@@ -283,6 +292,9 @@ namespace bx
|
|||||||
|
|
||||||
int32_t total = write(_writer, _err, "Callstack (%d):\n", _num);
|
int32_t total = write(_writer, _err, "Callstack (%d):\n", _num);
|
||||||
|
|
||||||
|
constexpr uint32_t kWidth = 40;
|
||||||
|
total += write(_writer, _err, "\t #: %-*s Line: PC --- Function ---\n", kWidth, "File ---");
|
||||||
|
|
||||||
CallbackData cbData;
|
CallbackData cbData;
|
||||||
|
|
||||||
for (uint32_t ii = 0; ii < _num && _err->isOk(); ++ii)
|
for (uint32_t ii = 0; ii < _num && _err->isOk(); ++ii)
|
||||||
@@ -311,13 +323,12 @@ namespace bx
|
|||||||
demangledName = "???";
|
demangledName = "???";
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr uint32_t width = 40;
|
const StringView fn = strTail(cbData.fileName, kWidth);
|
||||||
const StringView fn = strTail(cbData.fileName, width);
|
|
||||||
|
|
||||||
total += write(_writer, _err
|
total += write(_writer, _err
|
||||||
, "\t%2d: %-*S % 5d: %p %S\n"
|
, "\t%2d: %-*S % 5d: %p %S\n"
|
||||||
, ii
|
, ii
|
||||||
, width
|
, kWidth
|
||||||
, &fn
|
, &fn
|
||||||
, cbData.line
|
, cbData.line
|
||||||
, _stack[ii]
|
, _stack[ii]
|
||||||
@@ -363,4 +374,89 @@ namespace bx
|
|||||||
writeCallstack(getDebugOut(), stack, num, ErrorIgnore{});
|
writeCallstack(getDebugOut(), stack, num, ErrorIgnore{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if BX_CONFIG_EXCEPTION_HANDLING_USE_SIGNALS
|
||||||
|
struct Signal
|
||||||
|
{
|
||||||
|
int32_t signalId;
|
||||||
|
const char* name;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Signal s_signal[] =
|
||||||
|
{ // Linux
|
||||||
|
{ /* 4 */ SIGILL, "SIGILL - Illegal instruction signal." },
|
||||||
|
{ /* 6 */ SIGABRT, "SIGABRT - Abort signal." },
|
||||||
|
{ /* 8 */ SIGFPE, "SIGFPE - Floating point error signal." },
|
||||||
|
{ /* 11 */ SIGSEGV, "SIGSEGV - Segmentation violation signal." },
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExceptionHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExceptionHandler()
|
||||||
|
{
|
||||||
|
stack_t stack;
|
||||||
|
stack.ss_sp = s_stack;
|
||||||
|
stack.ss_size = sizeof(s_stack);
|
||||||
|
stack.ss_flags = 0;
|
||||||
|
sigaltstack(&stack, &m_oldStack);
|
||||||
|
|
||||||
|
struct sigaction sa;
|
||||||
|
sa.sa_handler = NULL;
|
||||||
|
sa.sa_sigaction = signalActionHandler;
|
||||||
|
sa.sa_mask = { 0 };
|
||||||
|
sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
|
||||||
|
sa.sa_restorer = NULL;
|
||||||
|
|
||||||
|
for (uint32_t ii = 0; ii < BX_COUNTOF(s_signal); ++ii)
|
||||||
|
{
|
||||||
|
sigaction(s_signal[ii].signalId, &sa, &m_oldSignalAction[ii]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~ExceptionHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void signalActionHandler(int32_t _signalId, siginfo_t* _info, void* _context)
|
||||||
|
{
|
||||||
|
BX_UNUSED(_context);
|
||||||
|
|
||||||
|
const char* name = "Unknown signal?";
|
||||||
|
|
||||||
|
for (uint32_t ii = 0; ii < BX_COUNTOF(s_signal); ++ii)
|
||||||
|
{
|
||||||
|
const Signal& signal = s_signal[ii];
|
||||||
|
|
||||||
|
if (signal.signalId == _signalId)
|
||||||
|
{
|
||||||
|
name = signal.name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assertFunction(Location("Exception Handler", -1), 2
|
||||||
|
, "%s SIGNAL %d, ERRNO %d, CODE %d"
|
||||||
|
, name
|
||||||
|
, _info->si_signo
|
||||||
|
, _info->si_errno
|
||||||
|
, _info->si_code
|
||||||
|
) )
|
||||||
|
{
|
||||||
|
exit(kExitFailure, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint32_t kExceptionStackSize = 64<<10;
|
||||||
|
|
||||||
|
static char s_stack[kExceptionStackSize];
|
||||||
|
|
||||||
|
stack_t m_oldStack;
|
||||||
|
struct sigaction m_oldSignalAction[BX_COUNTOF(s_signal)];
|
||||||
|
};
|
||||||
|
|
||||||
|
char ExceptionHandler::s_stack[kExceptionStackSize];
|
||||||
|
|
||||||
|
static ExceptionHandler s_exceptionHandler;
|
||||||
|
#endif // BX_PLATFORM_LINUX
|
||||||
|
|
||||||
} // namespace bx
|
} // namespace bx
|
||||||
|
|||||||
13
src/os.cpp
13
src/os.cpp
@@ -361,9 +361,18 @@ namespace bx
|
|||||||
#endif // BX_PLATFORM_LINUX
|
#endif // BX_PLATFORM_LINUX
|
||||||
}
|
}
|
||||||
|
|
||||||
void exit(int32_t _exitCode)
|
void exit(int32_t _exitCode, bool _cleanup)
|
||||||
{
|
{
|
||||||
::exit(_exitCode);
|
if (_cleanup)
|
||||||
|
{
|
||||||
|
::exit(_exitCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BX_PLATFORM_WINDOWS
|
||||||
|
TerminateProcess(GetCurrentProcess(), _exitCode);
|
||||||
|
#else
|
||||||
|
_Exit(_exitCode);
|
||||||
|
#endif // BX_PLATFORM_*
|
||||||
}
|
}
|
||||||
|
|
||||||
void* memoryMap(void* _address, size_t _size, Error* _err)
|
void* memoryMap(void* _address, size_t _size, Error* _err)
|
||||||
|
|||||||
@@ -31,7 +31,12 @@ BX_NO_INLINE void unusedFunction()
|
|||||||
|
|
||||||
void testAssert()
|
void testAssert()
|
||||||
{
|
{
|
||||||
|
BX_PRAGMA_DIAGNOSTIC_PUSH();
|
||||||
|
BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4804); // warning C4804: '%': unsafe use of type 'bool' in operation)
|
||||||
|
|
||||||
BX_ASSERT(false % 1, "Assert works!");
|
BX_ASSERT(false % 1, "Assert works!");
|
||||||
|
|
||||||
|
BX_PRAGMA_DIAGNOSTIC_POP();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Macros", "")
|
TEST_CASE("Macros", "")
|
||||||
|
|||||||
@@ -9,14 +9,17 @@
|
|||||||
#include <bx/file.h>
|
#include <bx/file.h>
|
||||||
#include <bx/simd_t.h>
|
#include <bx/simd_t.h>
|
||||||
|
|
||||||
bool testAssertHandler(const bx::Location& _location, const char* _format, va_list _argList)
|
BX_PRAGMA_DIAGNOSTIC_PUSH();
|
||||||
|
BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4702); // warning C4702: unreachable code
|
||||||
|
|
||||||
|
bool testAssertHandler(const bx::Location& _location, uint32_t _skip, const char* _format, va_list _argList)
|
||||||
{
|
{
|
||||||
bx::printf("%s(%d): ", _location.filePath, _location.line);
|
bx::printf("%s(%d): ", _location.filePath, _location.line);
|
||||||
bx::vprintf(_format, _argList);
|
bx::vprintf(_format, _argList);
|
||||||
bx::printf("\n");
|
bx::printf("\n");
|
||||||
|
|
||||||
uintptr_t stack[32];
|
uintptr_t stack[32];
|
||||||
const uint32_t num = bx::getCallStack(2 /* skip self */, BX_COUNTOF(stack), stack);
|
const uint32_t num = bx::getCallStack(2 /* skip self */ + _skip, BX_COUNTOF(stack), stack);
|
||||||
bx::writeCallstack(bx::getStdOut(), stack, num, bx::ErrorIgnore{});
|
bx::writeCallstack(bx::getStdOut(), stack, num, bx::ErrorIgnore{});
|
||||||
|
|
||||||
// Throwing exceptions is required for testing asserts being trigged.
|
// Throwing exceptions is required for testing asserts being trigged.
|
||||||
@@ -26,6 +29,8 @@ bool testAssertHandler(const bx::Location& _location, const char* _format, va_li
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BX_PRAGMA_DIAGNOSTIC_POP();
|
||||||
|
|
||||||
int runAllTests(int32_t _argc, const char* _argv[])
|
int runAllTests(int32_t _argc, const char* _argv[])
|
||||||
{
|
{
|
||||||
bx::setAssertHandler(testAssertHandler);
|
bx::setAssertHandler(testAssertHandler);
|
||||||
|
|||||||
Reference in New Issue
Block a user