mirror of
https://github.com/Detanup01/gbe_fork.git
synced 2024-11-23 11:15:34 +08:00
linux crash printer
This commit is contained in:
parent
d15441a30e
commit
57e7dbebde
15
crash_printer/crash_printer/linux.hpp
Normal file
15
crash_printer/crash_printer/linux.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef _CRASH_PRINTER_LINUX
|
||||
#define _CRASH_PRINTER_LINUX
|
||||
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace crash_printer {
|
||||
|
||||
bool init(const std::string &log_file);
|
||||
|
||||
void deinit();
|
||||
|
||||
}
|
||||
|
||||
#endif // _CRASH_PRINTER_LINUX
|
169
crash_printer/linux.cpp
Normal file
169
crash_printer/linux.cpp
Normal file
@ -0,0 +1,169 @@
|
||||
// https://stackoverflow.com/a/1925461
|
||||
|
||||
#include "crash_printer/common.hpp"
|
||||
#include "crash_printer/linux.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
|
||||
#include <ucontext.h>
|
||||
#include <signal.h> // SIGBUS + SA_SIGINFO ...
|
||||
#include <string.h> // strsignal
|
||||
#include <execinfo.h> // backtrace + backtrace_symbols
|
||||
|
||||
constexpr static const int max_stack_frames = 50;
|
||||
|
||||
static bool old_SIGILL = false;
|
||||
static struct sigaction oldact_SIGILL{};
|
||||
|
||||
static bool old_SIGSEGV = false;
|
||||
static struct sigaction oldact_SIGSEGV{};
|
||||
|
||||
static bool old_SIGBUS = false;
|
||||
static struct sigaction oldact_SIGBUS{};
|
||||
|
||||
static std::string logs_filepath{};
|
||||
|
||||
static void restore_handlers()
|
||||
{
|
||||
if (old_SIGILL) {
|
||||
old_SIGILL = false;
|
||||
sigaction(SIGILL, &oldact_SIGILL, nullptr);
|
||||
}
|
||||
|
||||
if (old_SIGSEGV) {
|
||||
old_SIGSEGV = false;
|
||||
sigaction(SIGSEGV, &oldact_SIGSEGV, nullptr);
|
||||
}
|
||||
|
||||
if (old_SIGBUS) {
|
||||
old_SIGBUS = false;
|
||||
sigaction(SIGBUS, &oldact_SIGBUS, nullptr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void exception_handler(int signal, siginfo_t *info, void *context, struct sigaction *oldact)
|
||||
{
|
||||
if (!crash_printer::create_dir(logs_filepath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::ofstream file(logs_filepath, std::ios::app);
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto t_now = std::chrono::system_clock::to_time_t(now);
|
||||
auto gm_time = std::gmtime(&t_now);
|
||||
auto time = std::string(std::asctime(gm_time));
|
||||
time.pop_back(); // remove the trailing '\n' added by asctime
|
||||
crash_printer::write(file, "[" + time + "]");
|
||||
{
|
||||
std::stringstream ss{};
|
||||
ss << "Unhandled exception:" << std::endl
|
||||
<< " code: " << std::dec << signal << " (" << strsignal(signal) << ")" << std::endl;
|
||||
crash_printer::write(file, ss.str());
|
||||
}
|
||||
void* stack_frames[max_stack_frames];
|
||||
int stack_size = backtrace(stack_frames, max_stack_frames);
|
||||
char** stack_symbols = backtrace_symbols(stack_frames, stack_size);
|
||||
|
||||
if (stack_symbols != nullptr) {
|
||||
// fprintf(stderr, "Stack trace:\n");
|
||||
crash_printer::write(file, "*********** Stack trace ***********");
|
||||
for (int i = 1; i < stack_size; ++i) {
|
||||
char *symbol = stack_symbols[i];
|
||||
std::stringstream ss{};
|
||||
ss << "[frame " << std::dec << (stack_size - i - 1) << "]: "
|
||||
<< std::hex << stack_frames[i] << " | "
|
||||
<< symbol;
|
||||
crash_printer::write(file, ss.str());
|
||||
}
|
||||
|
||||
free(stack_symbols);
|
||||
}
|
||||
|
||||
crash_printer::write(file, "**********************************\n");
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
// Register the signal handler for illegal instruction (SIGILL)
|
||||
static void exception_handler_SIGILL(int signal, siginfo_t *info, void *context) {
|
||||
exception_handler(signal, info, context, &oldact_SIGILL);
|
||||
sigaction(SIGILL, &oldact_SIGILL, nullptr);
|
||||
}
|
||||
|
||||
static void exception_handler_SIGSEGV(int signal, siginfo_t *info, void *context) {
|
||||
exception_handler(signal, info, context, &oldact_SIGSEGV);
|
||||
sigaction(SIGSEGV, &oldact_SIGSEGV, nullptr);
|
||||
}
|
||||
|
||||
static void exception_handler_SIGBUS(int signal, siginfo_t *info, void *context) {
|
||||
exception_handler(signal, info, context, &oldact_SIGBUS);
|
||||
sigaction(SIGBUS, &oldact_SIGBUS, nullptr);
|
||||
}
|
||||
|
||||
|
||||
bool crash_printer::init(const std::string &log_file)
|
||||
{
|
||||
logs_filepath = log_file;
|
||||
|
||||
// save old handlers
|
||||
// https://linux.die.net/man/2/sigaction
|
||||
if (
|
||||
sigaction(SIGILL, nullptr, &oldact_SIGILL) != 0 ||
|
||||
sigaction(SIGSEGV, nullptr, &oldact_SIGSEGV) != 0 ||
|
||||
sigaction(SIGBUS, nullptr, &oldact_SIGBUS) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr int sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK | SA_RESETHAND | SA_NOCLDSTOP;
|
||||
|
||||
// https://linux.die.net/man/2/sigaction
|
||||
// register handler for illegal instruction (SIGILL)
|
||||
struct sigaction sa_SIGILL{};
|
||||
sa_SIGILL.sa_sigaction = exception_handler_SIGILL;
|
||||
sa_SIGILL.sa_flags = sa_flags;
|
||||
sigemptyset(&sa_SIGILL.sa_mask); // all signals unblocked
|
||||
if (sigaction(SIGILL, &sa_SIGILL, nullptr) != 0) {
|
||||
restore_handlers();
|
||||
return false;
|
||||
}
|
||||
old_SIGILL = true;
|
||||
|
||||
// register handler for segmentation fault (SIGSEGV)
|
||||
struct sigaction sa_SIGSEGV{};
|
||||
sa_SIGSEGV.sa_sigaction = exception_handler_SIGSEGV;
|
||||
sa_SIGSEGV.sa_flags = sa_flags;
|
||||
sigemptyset(&sa_SIGSEGV.sa_mask); // all signals unblocked
|
||||
if (sigaction(SIGSEGV, &sa_SIGSEGV, nullptr) != 0) {
|
||||
restore_handlers();
|
||||
return false;
|
||||
}
|
||||
old_SIGSEGV = true;
|
||||
|
||||
// register handler for bus error (SIGBUS)
|
||||
struct sigaction sa_SIGBUS{};
|
||||
sa_SIGBUS.sa_sigaction = exception_handler_SIGBUS;
|
||||
sa_SIGBUS.sa_flags = sa_flags;
|
||||
sigemptyset(&sa_SIGBUS.sa_mask); // all signals unblocked
|
||||
if (sigaction(SIGBUS, &sa_SIGBUS, nullptr) != 0) {
|
||||
restore_handlers();
|
||||
return false;
|
||||
}
|
||||
old_SIGBUS = true;
|
||||
|
||||
// // register handler for floating-point exception (SIGFPE)
|
||||
// if (sigaction(SIGFPE, &sa, nullptr) != 0) {
|
||||
// perror("Error setting up signal handler");
|
||||
// return EXIT_FAILURE;
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void crash_printer::deinit()
|
||||
{
|
||||
restore_handlers();
|
||||
}
|
Loading…
Reference in New Issue
Block a user