intial commit
This commit is contained in:
146
source/mijin/debug/assert.hpp
Normal file
146
source/mijin/debug/assert.hpp
Normal file
@@ -0,0 +1,146 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(MIJIN_DEBUG_ASSERT_HPP_INCLUDED)
|
||||
#define MIJIN_DEBUG_ASSERT_HPP_INCLUDED 1
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace mijin
|
||||
{
|
||||
|
||||
//
|
||||
// public defines
|
||||
//
|
||||
|
||||
#if MIJIN_DEBUG
|
||||
#ifdef _WIN32
|
||||
#pragma comment(lib, "kernel32")
|
||||
extern "C" __declspec(dllimport) void __stdcall DebugBreak();
|
||||
#define MIJIN_TRAP() DebugBreak()
|
||||
#define MIJIN_FUNC() __FUNCSIG__
|
||||
#else // _WIN32
|
||||
#include <signal.h>
|
||||
#define MIJIN_TRAP() raise(SIGTRAP)
|
||||
#define MIJIN_FUNC() "" // TODO: __PRETTY_FUNCTION__ is not working for some reason -.-
|
||||
#endif // !_WIN32
|
||||
|
||||
#define MIJIN_DO_RAISE_ERROR(msg, func, file, line) \
|
||||
switch (mijin::handleError(msg, func, file, line)) \
|
||||
{ \
|
||||
case mijin::ErrorHandling::CONTINUE: \
|
||||
break; \
|
||||
case mijin::ErrorHandling::TRAP: \
|
||||
MIJIN_TRAP(); \
|
||||
[[fallthrough]]; \
|
||||
default: /* ABORT */ \
|
||||
std::abort(); \
|
||||
}
|
||||
|
||||
#define MIJIN_RAISE_ERROR(msg, func, file, line) MIJIN_DO_RAISE_ERROR(msg, func, file, line)
|
||||
|
||||
#define MIJIN_ERROR(msg) \
|
||||
MIJIN_RAISE_ERROR(msg, MIJIN_FUNC(), __FILE__, __LINE__)
|
||||
|
||||
#define MIJIN_FATAL(msg) \
|
||||
MIJIN_ERROR(msg) \
|
||||
std::abort()
|
||||
|
||||
// TODO: make ignoreAll work (static variables cannot be used in constexpr functions)
|
||||
#define MIJIN_ASSERT(condition, msg) \
|
||||
if (!static_cast<bool>(condition)) \
|
||||
{ \
|
||||
/* static bool ignoreAll = false; */ \
|
||||
if (true) /*!ignoreAll */ \
|
||||
{ \
|
||||
mijin::AssertionResult assertion_result__ = mijin::handleAssert(#condition,\
|
||||
msg, MIJIN_FUNC(), __FILE__, __LINE__); \
|
||||
switch (assertion_result__) \
|
||||
{ \
|
||||
case mijin::AssertionResult::ABORT: \
|
||||
std::abort(); \
|
||||
break; \
|
||||
case mijin::AssertionResult::IGNORE: \
|
||||
break; \
|
||||
case mijin::AssertionResult::IGNORE_ALL: \
|
||||
/* ignoreAll = true; */ \
|
||||
break; \
|
||||
default: /* ERROR */ \
|
||||
MIJIN_ERROR("Debug assertion failed: " #condition "\nMessage: " msg); \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MIJIN_ASSERT_FATAL(condition, msg) \
|
||||
if (!static_cast<bool>(condition)) \
|
||||
{ \
|
||||
MIJIN_ERROR("Debug assertion failed: " #condition "\nMessage: " msg); \
|
||||
}
|
||||
#else // MIJIN_DEBUG
|
||||
#define MIJIN_ERROR(...)
|
||||
#define MIJIN_FATAL(...) std::abort()
|
||||
#define MIJIN_ASSERT(...)
|
||||
#define MIJIN_ASSERT_FATAL(...)
|
||||
#endif // !MIJIN_DEBUG
|
||||
|
||||
//
|
||||
// public constants
|
||||
//
|
||||
|
||||
//
|
||||
// public types
|
||||
//
|
||||
|
||||
enum class AssertionResult
|
||||
{
|
||||
ABORT = -1, // call std::abort()
|
||||
ERROR = 0, // raise an error using MIJIN_ERROR() handling
|
||||
IGNORE = 1, // do nothing
|
||||
IGNORE_ALL = 2 // do nothing and nevery halt again (not implemented yet)
|
||||
};
|
||||
|
||||
enum class ErrorHandling
|
||||
{
|
||||
TRAP = 0,
|
||||
CONTINUE = 1,
|
||||
ABORT = 2
|
||||
};
|
||||
|
||||
//
|
||||
// public functions
|
||||
//
|
||||
|
||||
#ifdef MIJIN_USE_CUSTOM_ASSERTION_HANDLER
|
||||
AssertionResult handleAssert(const char* condition,
|
||||
const char* message, const char* function,
|
||||
const char* file, int line) noexcept;
|
||||
#else
|
||||
constexpr AssertionResult handleAssert(const char* /* condition */,
|
||||
const char* /* message */, const char* /* function */,
|
||||
const char* /* file */, int /* line */)
|
||||
{
|
||||
return AssertionResult::ERROR;
|
||||
}
|
||||
#endif // MIJIN_USE_CUSTOM_ASSERTION_HANDLER
|
||||
|
||||
#ifdef MIJIN_USE_CUSTOM_ERROR_HANDLER
|
||||
ErrorHandling handleError(const char* message, const char* function,
|
||||
const char* file, int line) noexcept;
|
||||
#else
|
||||
inline ErrorHandling handleError(const char* message, const char* function,
|
||||
const char* file, int line) noexcept
|
||||
{
|
||||
std::puts(message);
|
||||
std::printf("Function: %s\n", function);
|
||||
std::printf("File: %s\n", file);
|
||||
std::printf("Line: %d\n", line);
|
||||
(void) std::fflush(stdout);
|
||||
return ErrorHandling::TRAP;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace mijin
|
||||
|
||||
#endif // !defined(MIJIN_DEBUG_ASSERT_HPP_INCLUDED)
|
||||
87
source/mijin/debug/symbol_info.cpp
Normal file
87
source/mijin/debug/symbol_info.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
|
||||
#include "symbol_info.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
#include "../detect.hpp"
|
||||
|
||||
#if MIJIN_TARGET_OS == MIJIN_OS_LINUX
|
||||
#if !defined(_GNU_SOURCE)
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#if MIJIN_COMPILER == MIJIN_COMPILER_GCC
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
namespace mijin
|
||||
{
|
||||
|
||||
//
|
||||
// internal defines
|
||||
//
|
||||
|
||||
//
|
||||
// internal constants
|
||||
//
|
||||
|
||||
//
|
||||
// internal types
|
||||
//
|
||||
|
||||
//
|
||||
// internal variables
|
||||
//
|
||||
|
||||
static thread_local std::unordered_map<const void*, std::string> g_functionNameCache;
|
||||
|
||||
//
|
||||
// internal functions
|
||||
//
|
||||
|
||||
//
|
||||
// public functions
|
||||
//
|
||||
|
||||
const char* lookupFunctionName(const void* function)
|
||||
{
|
||||
auto it = g_functionNameCache.find(function);
|
||||
if (it != g_functionNameCache.end()) {
|
||||
return it->second.c_str();
|
||||
}
|
||||
|
||||
#if MIJIN_TARGET_OS == MIJIN_OS_LINUX
|
||||
Dl_info info;
|
||||
dladdr(function, &info);
|
||||
|
||||
std::string name = demangleCPPIdentifier(info.dli_sname);
|
||||
if (name.empty()) {
|
||||
name = info.dli_sname;
|
||||
}
|
||||
#else
|
||||
std::string name = "<unknown>";
|
||||
#endif
|
||||
return g_functionNameCache.insert({function, std::move(name)}).first->second.c_str();
|
||||
}
|
||||
|
||||
#if MIJIN_COMPILER == MIJIN_COMPILER_GCC
|
||||
std::string demangleCPPIdentifier(const char* identifier)
|
||||
{
|
||||
char* demangled = abi::__cxa_demangle(identifier, /* output_buffer = */ nullptr, /* length = */ nullptr, /* status = */ nullptr);
|
||||
if (demangled != nullptr)
|
||||
{
|
||||
std::string name = demangled;
|
||||
std::free(demangled); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
|
||||
return name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
#else
|
||||
std::string demangleCPPIdentifier(const char* /* identifier */)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace mijin
|
||||
33
source/mijin/debug/symbol_info.hpp
Normal file
33
source/mijin/debug/symbol_info.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(MIJIN_DEBUG_SYMBOL_INFO_HPP_INCLUDED)
|
||||
#define MIJIN_DEBUG_SYMBOL_INFO_HPP_INCLUDED 1
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace mijin
|
||||
{
|
||||
|
||||
//
|
||||
// public defines
|
||||
//
|
||||
|
||||
//
|
||||
// public constants
|
||||
//
|
||||
|
||||
//
|
||||
// public types
|
||||
//
|
||||
|
||||
//
|
||||
// public functions
|
||||
//
|
||||
|
||||
[[nodiscard]] const char* lookupFunctionName(const void* function);
|
||||
[[nodiscard]] std::string demangleCPPIdentifier(const char* identifier);
|
||||
|
||||
} // namespace mijin
|
||||
|
||||
#endif // !defined(MIJIN_DEBUG_SYMBOL_INFO_HPP_INCLUDED)
|
||||
Reference in New Issue
Block a user