2023-08-23 15:23:47 -04:00
|
|
|
/*
|
|
|
|
* Created by Brett on 23/08/23.
|
|
|
|
* Licensed under GNU General Public License V3.0
|
|
|
|
* See LICENSE file for license detail
|
|
|
|
*/
|
|
|
|
#include <blt/std/assert.h>
|
2023-12-07 15:59:26 -05:00
|
|
|
#include <blt/std/utility.h>
|
2023-08-23 15:23:47 -04:00
|
|
|
#include <blt/std/logging.h>
|
|
|
|
#include <blt/std/string.h>
|
|
|
|
#include <iostream>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <sstream>
|
2024-08-02 23:46:51 -04:00
|
|
|
#include <exception>
|
2024-08-09 23:38:25 -04:00
|
|
|
#include <cstring>
|
2024-08-02 23:46:51 -04:00
|
|
|
|
2024-10-31 22:28:43 -04:00
|
|
|
struct abort_exception final : public std::exception
|
2024-08-02 23:46:51 -04:00
|
|
|
{
|
|
|
|
public:
|
2024-08-09 23:38:25 -04:00
|
|
|
explicit abort_exception(const char* what)
|
|
|
|
{
|
|
|
|
auto len = std::strlen(what) + 1;
|
|
|
|
error = static_cast<char*>(std::malloc(len));
|
|
|
|
std::memcpy(static_cast<char*>(error), what, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
abort_exception(const abort_exception& copy) = delete;
|
|
|
|
abort_exception& operator=(const abort_exception& copy) = delete;
|
2024-08-02 23:46:51 -04:00
|
|
|
|
|
|
|
[[nodiscard]] const char* what() const noexcept override
|
|
|
|
{
|
|
|
|
if (error == nullptr)
|
|
|
|
return "Abort called";
|
|
|
|
return error;
|
|
|
|
}
|
2024-08-09 23:38:25 -04:00
|
|
|
|
|
|
|
~abort_exception() override
|
|
|
|
{
|
|
|
|
std::free(static_cast<void*>(error));
|
|
|
|
}
|
2024-08-02 23:46:51 -04:00
|
|
|
|
|
|
|
private:
|
2024-08-09 23:38:25 -04:00
|
|
|
char* error{nullptr};
|
2024-08-02 23:46:51 -04:00
|
|
|
};
|
2023-08-23 15:23:47 -04:00
|
|
|
|
2024-10-31 22:28:43 -04:00
|
|
|
#if defined(__GNUC__) && !defined(__EMSCRIPTEN__) && !defined(WIN32)
|
|
|
|
#define IS_GNU_BACKTRACE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef IS_GNU_BACKTRACE
|
2023-09-07 00:23:13 -04:00
|
|
|
|
|
|
|
#include <execinfo.h>
|
|
|
|
#include <cstdlib>
|
2024-08-09 23:38:25 -04:00
|
|
|
|
2023-09-07 00:23:13 -04:00
|
|
|
#endif
|
|
|
|
|
2024-10-31 22:28:43 -04:00
|
|
|
#if IS_GNU_BACKTRACE
|
2023-09-07 00:23:13 -04:00
|
|
|
#define BLT_STACK_TRACE(number) void* ptrs[number]; \
|
|
|
|
int size = backtrace(ptrs, number); \
|
|
|
|
char** messages = backtrace_symbols(ptrs, size);
|
|
|
|
|
|
|
|
#define BLT_FREE_STACK_TRACE() free(messages);
|
2023-12-07 15:59:26 -05:00
|
|
|
|
2023-09-07 00:23:13 -04:00
|
|
|
#else
|
2023-12-16 02:42:38 -05:00
|
|
|
#define BLT_STACK_TRACE(number) void();
|
2023-09-07 00:23:13 -04:00
|
|
|
#define BLT_FREE_STACK_TRACE() void();
|
|
|
|
#endif
|
|
|
|
|
2024-08-09 23:38:25 -04:00
|
|
|
namespace blt
|
|
|
|
{
|
2024-02-21 20:36:22 -05:00
|
|
|
|
2024-10-31 22:28:43 -04:00
|
|
|
#if IS_GNU_BACKTRACE
|
2024-08-09 23:38:25 -04:00
|
|
|
|
|
|
|
static inline std::string _macro_filename(const std::string& path)
|
|
|
|
{
|
2023-08-23 15:23:47 -04:00
|
|
|
auto paths = blt::string::split(path, "/");
|
2024-08-09 23:38:25 -04:00
|
|
|
auto final = paths[paths.size() - 1];
|
2023-08-23 15:23:47 -04:00
|
|
|
if (final == "/")
|
2024-08-09 23:38:25 -04:00
|
|
|
return paths[paths.size() - 2];
|
2023-08-23 15:23:47 -04:00
|
|
|
return final;
|
|
|
|
}
|
2024-08-09 23:38:25 -04:00
|
|
|
|
2024-02-21 20:36:22 -05:00
|
|
|
#endif
|
2023-08-23 15:23:47 -04:00
|
|
|
|
|
|
|
void b_throw(const char* what, const char* path, int line)
|
|
|
|
{
|
2024-10-31 22:28:43 -04:00
|
|
|
#if IS_GNU_BACKTRACE
|
2023-08-23 15:23:47 -04:00
|
|
|
BLT_STACK_TRACE(50);
|
|
|
|
|
|
|
|
BLT_ERROR("An exception '%s' has occurred in file '%s:%d'", what, path, line);
|
|
|
|
BLT_ERROR("Stack Trace:");
|
|
|
|
printStacktrace(messages, size, path, line);
|
|
|
|
|
|
|
|
BLT_FREE_STACK_TRACE();
|
2024-02-21 20:36:22 -05:00
|
|
|
#else
|
|
|
|
(void) what;
|
|
|
|
(void) path;
|
|
|
|
(void) line;
|
2023-08-23 15:23:47 -04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2024-01-31 17:24:46 -05:00
|
|
|
void b_assert_failed(const char* expression, const char* msg, const char* path, int line)
|
2023-08-23 15:23:47 -04:00
|
|
|
{
|
2024-10-31 22:28:43 -04:00
|
|
|
#if IS_GNU_BACKTRACE
|
2023-08-23 15:23:47 -04:00
|
|
|
BLT_STACK_TRACE(50);
|
|
|
|
|
|
|
|
BLT_ERROR("The assertion '%s' has failed in file '%s:%d'", expression, path, line);
|
2024-01-31 17:24:46 -05:00
|
|
|
if (msg != nullptr)
|
|
|
|
BLT_ERROR(msg);
|
2023-08-23 15:23:47 -04:00
|
|
|
BLT_ERROR("Stack Trace:");
|
|
|
|
|
|
|
|
printStacktrace(messages, size, path, line);
|
|
|
|
|
|
|
|
BLT_FREE_STACK_TRACE();
|
2024-08-03 19:50:26 -04:00
|
|
|
#else
|
2024-02-21 20:36:22 -05:00
|
|
|
(void) expression;
|
|
|
|
(void) msg;
|
|
|
|
(void) path;
|
|
|
|
(void) line;
|
2024-08-03 19:50:26 -04:00
|
|
|
#endif
|
|
|
|
if (msg != nullptr)
|
|
|
|
throw abort_exception(msg);
|
|
|
|
throw abort_exception(expression);
|
2023-08-23 15:23:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void printStacktrace(char** messages, int size, const char* path, int line)
|
|
|
|
{
|
2023-12-07 15:59:26 -05:00
|
|
|
if (messages == nullptr)
|
|
|
|
return;
|
2024-10-31 22:28:43 -04:00
|
|
|
#if IS_GNU_BACKTRACE
|
2024-08-09 23:38:25 -04:00
|
|
|
for (int i = 1; i < size; i++)
|
|
|
|
{
|
2023-08-23 15:23:47 -04:00
|
|
|
int tabs = i - 1;
|
|
|
|
std::string buffer;
|
|
|
|
for (int j = 0; j < tabs; j++)
|
|
|
|
buffer += '\t';
|
|
|
|
if (i != 1)
|
|
|
|
buffer += "⮡";
|
|
|
|
|
|
|
|
std::string message(messages[i]);
|
|
|
|
|
|
|
|
auto f = message.find('(');
|
|
|
|
|
|
|
|
auto mes = message.substr(f + 1, message.size());
|
|
|
|
std::string loc;
|
|
|
|
|
|
|
|
buffer += message.substr(0, f);
|
|
|
|
if (i == 1)
|
|
|
|
{
|
|
|
|
loc = '\'';
|
|
|
|
loc += _macro_filename(path);
|
|
|
|
loc += ':';
|
|
|
|
loc += std::to_string(line);
|
|
|
|
loc += '\'';
|
|
|
|
} else
|
2023-12-07 15:59:26 -05:00
|
|
|
loc = demangle(mes.substr(0, mes.find('+')));
|
2023-08-23 15:23:47 -04:00
|
|
|
|
|
|
|
if (!loc.empty())
|
|
|
|
buffer += " in ";
|
|
|
|
buffer += loc;
|
|
|
|
|
2024-08-09 23:38:25 -04:00
|
|
|
|
2023-08-23 15:23:47 -04:00
|
|
|
BLT_ERROR(buffer);
|
|
|
|
}
|
2024-02-21 20:36:22 -05:00
|
|
|
#else
|
|
|
|
(void) size;
|
|
|
|
(void) path;
|
|
|
|
(void) line;
|
2023-08-23 15:23:47 -04:00
|
|
|
#endif
|
2024-02-21 20:36:22 -05:00
|
|
|
|
2023-08-23 15:23:47 -04:00
|
|
|
}
|
|
|
|
|
2024-06-24 01:05:44 -04:00
|
|
|
void b_abort(const char* what, const char* path, int line)
|
|
|
|
{
|
2024-10-31 22:28:43 -04:00
|
|
|
#if IS_GNU_BACKTRACE
|
2024-06-24 01:05:44 -04:00
|
|
|
BLT_STACK_TRACE(50);
|
|
|
|
#endif
|
2024-08-02 23:46:51 -04:00
|
|
|
BLT_FATAL("----{BLT ABORT}----");
|
2024-07-11 02:30:54 -04:00
|
|
|
BLT_FATAL("\tWhat: %s", what);
|
2024-10-31 22:28:43 -04:00
|
|
|
BLT_FATAL("\tCalled from %s:%d", path, line);
|
|
|
|
#if IS_GNU_BACKTRACE
|
2024-06-24 01:05:44 -04:00
|
|
|
printStacktrace(messages, size, path, line);
|
|
|
|
|
|
|
|
BLT_FREE_STACK_TRACE();
|
|
|
|
#endif
|
2024-08-02 23:46:51 -04:00
|
|
|
throw abort_exception(what);
|
2024-06-24 01:05:44 -04:00
|
|
|
}
|
|
|
|
|
2023-08-23 15:23:47 -04:00
|
|
|
|
|
|
|
}
|