Skip to content

Instantly share code, notes, and snippets.

@Shviderskiy
Created February 2, 2020 20:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Shviderskiy/248e82bf73931a4b38e33e2da275312c to your computer and use it in GitHub Desktop.
Save Shviderskiy/248e82bf73931a4b38e33e2da275312c to your computer and use it in GitHub Desktop.
#include "crash.h"
#define _GNU_SOURCE
#include <stddef.h> // NULL
#include <stdlib.h> // EXIT_FAILURE
#include <string.h> // strsignal
#include <stdarg.h> // va_list
#include <stdio.h> // vsnprintf
#include <signal.h>
#include <dlfcn.h> // Dl_info, dladdr
#include <link.h> // dl_phdr_info, dl_iterate_phdr
#include <execinfo.h> // backtrace, backtrace_symbols
/* https://sourceforge.net/p/predef/wiki/Architectures/ */
#if defined(__amd64__) || \
defined(__amd64) || \
defined(__x86_64__) || \
defined(__x86_64)
#define GET_CURRENT_STACK_FRAME(POINTER_) \
__asm__ __volatile__("movq %%rbp, %0": "=r"(POINTER_))
#elif defined(i386) || defined(__i386) || defined(__i386__)
#define GET_CURRENT_STACK_FRAME(POINTER_) \
__asm__ __volatile__("mov %%ebp, %0": "=r"(POINTER_))
#else
#error "Processor architecture is not supported!"
#endif
typedef struct _stack_frame_t
{
struct _stack_frame_t * next;
void * ret_addr;
}
stack_frame_t;
static void(* __log)(char const * line_) = NULL;
static __sighandler_t __prev_signal_handler = NULL;
static void log(char const * format_, ...)
{
if (__log == NULL)
return;
va_list args;
va_start(args, format_);
static __thread char buffer[256];
vsnprintf(buffer, sizeof(buffer), format_, args);
va_end(args);
__log(buffer);
}
static int print_one_module(
struct dl_phdr_info * info_, size_t size_, void * data_)
{
(void)size_;
(void)data_;
log("%s [%p]", info_->dlpi_name, (void *)info_->dlpi_addr);
return 0;
}
static void print_modules()
{
log("========== MODULES ==========");
dl_iterate_phdr(print_one_module, NULL);
}
static void print_callstack()
{
log("========== CALLSTACK ==========");
stack_frame_t * stack_frame = NULL;
GET_CURRENT_STACK_FRAME(stack_frame);
for ( ; stack_frame != NULL; stack_frame = stack_frame->next)
{
Dl_info info;
if (dladdr(stack_frame->ret_addr, &info) == 0)
{
log("???: ??? [???:%p]", stack_frame->ret_addr);
}
else
{
log("%s: %s [%p:%p]",
info.dli_fname == NULL ? "???" : info.dli_fname,
info.dli_sname == NULL ? "???" : info.dli_sname,
info.dli_fbase, stack_frame->ret_addr);
}
}
}
static void print_callstack_default()
{
log("========== CALLSTACK ==========");
void * addresses[1024];
int addresses_count = backtrace(addresses, 1024);
if (addresses_count == 0)
{
log("no backtrace");
return;
}
char * * symbols = backtrace_symbols(addresses, addresses_count);
if (symbols == NULL)
{
log("no symbols");
return;
}
for (int i = 0; i < addresses_count; i++)
{
if (symbols[i] != NULL)
log("%s", symbols[i]);
else log("%p", addresses[i]);
}
free(symbols);
}
static void signal_handler(int signal_)
{
signal(signal_, __prev_signal_handler);
log("[%s] caught signal %d (%s)", __func__, signal_, strsignal(signal_));
print_modules();
print_callstack();
print_callstack_default();
}
void init_crash_handler(void(* log_)(char const * line_))
{
__log = log_;
log("[%s]", __func__);
__prev_signal_handler = signal(SIGSEGV, signal_handler);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment