[all] improve backtrace and debugging support

This commit is contained in:
Geoffrey McRae 2021-01-25 18:36:51 +11:00
parent 2973319bff
commit 6f1c19b3b0
4 changed files with 56 additions and 19 deletions

View File

@ -2299,6 +2299,7 @@ int main(int argc, char * argv[])
lg_shutdown(); lg_shutdown();
config_free(); config_free();
return ret;
cleanupCrashHandler();
return ret;
} }

View File

@ -19,4 +19,5 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include <stdbool.h> #include <stdbool.h>
bool installCrashHandler(const char * exe); bool installCrashHandler(const char * exe);
void cleanupCrashHandler(void);

View File

@ -21,10 +21,17 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#define __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS
#endif #endif
#include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <inttypes.h> #include <inttypes.h>
#include "time.h" #include "time.h"
#ifdef ENABLE_BACKTRACE
void printBacktrace(void);
#else
#define printBacktrace
#endif
#if defined(_WIN32) && !defined(__GNUC__) #if defined(_WIN32) && !defined(__GNUC__)
#define DIRECTORY_SEPARATOR '\\' #define DIRECTORY_SEPARATOR '\\'
#else #else
@ -53,13 +60,22 @@ Place, Suite 330, Boston, MA 02111-1307 USA
sizeof(s) > 20 && (s)[sizeof(s)-21] == DIRECTORY_SEPARATOR ? (s) + sizeof(s) - 20 : \ sizeof(s) > 20 && (s)[sizeof(s)-21] == DIRECTORY_SEPARATOR ? (s) + sizeof(s) - 20 : \
sizeof(s) > 21 && (s)[sizeof(s)-22] == DIRECTORY_SEPARATOR ? (s) + sizeof(s) - 21 : (s)) sizeof(s) > 21 && (s)[sizeof(s)-22] == DIRECTORY_SEPARATOR ? (s) + sizeof(s) - 21 : (s))
#define DEBUG_PRINT(type, fmt, ...) do {fprintf(stderr, "%12" PRId64 " " type " %20s:%-4u | %-30s | " fmt "\n", microtime(), STRIPPATH(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__);} while (0) #define DEBUG_PRINT(type, fmt, ...) do { \
fprintf(stderr, "%12" PRId64 " " type " %20s:%-4u | %-30s | " fmt "\n", \
microtime(), STRIPPATH(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__);\
} while (0)
#define DEBUG_BREAK() DEBUG_PRINT("[ ]", "%s", "================================================================================") #define DEBUG_BREAK() DEBUG_PRINT("[ ]", "================================================================================")
#define DEBUG_INFO(fmt, ...) DEBUG_PRINT("[I]", fmt, ##__VA_ARGS__) #define DEBUG_INFO(fmt, ...) DEBUG_PRINT("[I]", fmt, ##__VA_ARGS__)
#define DEBUG_WARN(fmt, ...) DEBUG_PRINT("[W]", fmt, ##__VA_ARGS__) #define DEBUG_WARN(fmt, ...) DEBUG_PRINT("[W]", fmt, ##__VA_ARGS__)
#define DEBUG_ERROR(fmt, ...) DEBUG_PRINT("[E]", fmt, ##__VA_ARGS__) #define DEBUG_ERROR(fmt, ...) DEBUG_PRINT("[E]", fmt, ##__VA_ARGS__)
#define DEBUG_FIXME(fmt, ...) DEBUG_PRINT("[F]", fmt, ##__VA_ARGS__) #define DEBUG_FIXME(fmt, ...) DEBUG_PRINT("[F]", fmt, ##__VA_ARGS__)
#define DEBUG_FATAL(fmt, ...) do { \
DEBUG_BREAK(); \
DEBUG_PRINT("[!]", fmt, ##__VA_ARGS__); \
printBacktrace(); \
abort(); \
} while(0)
#if defined(DEBUG_SPICE) | defined(DEBUG_IVSHMEM) #if defined(DEBUG_SPICE) | defined(DEBUG_IVSHMEM)
#define DEBUG_PROTO(fmt, args...) DEBUG_PRINT("[P]", fmt, ##args) #define DEBUG_PROTO(fmt, args...) DEBUG_PRINT("[P]", fmt, ##args)

View File

@ -50,18 +50,19 @@ struct crash
asection * section; asection * section;
asymbol ** syms; asymbol ** syms;
long symCount; long symCount;
bool loaded;
}; };
static struct crash crash = {0}; static struct crash crash = {0};
static void load_symbols(void) static bool load_symbols(void)
{ {
bfd_init(); bfd_init();
crash.fd = bfd_openr(crash.exe, NULL); crash.fd = bfd_openr(crash.exe, NULL);
if (!crash.fd) if (!crash.fd)
{ {
DEBUG_ERROR("failed to open '%s'", crash.exe); DEBUG_ERROR("failed to open '%s'", crash.exe);
return; return false;
} }
crash.fd->flags |= BFD_DECOMPRESS; crash.fd->flags |= BFD_DECOMPRESS;
@ -70,20 +71,20 @@ static void load_symbols(void)
if (!bfd_check_format_matches(crash.fd, bfd_object, &matching)) if (!bfd_check_format_matches(crash.fd, bfd_object, &matching))
{ {
DEBUG_ERROR("executable is not a bfd_object"); DEBUG_ERROR("executable is not a bfd_object");
return; return false;
} }
crash.section = bfd_get_section_by_name(crash.fd, ".text"); crash.section = bfd_get_section_by_name(crash.fd, ".text");
if (!crash.section) if (!crash.section)
{ {
DEBUG_ERROR("failed to find .text section"); DEBUG_ERROR("failed to find .text section");
return; return false;
} }
if ((bfd_get_file_flags(crash.fd) & HAS_SYMS) == 0) if ((bfd_get_file_flags(crash.fd) & HAS_SYMS) == 0)
{ {
DEBUG_ERROR("executable '%s' has no symbols", crash.exe); DEBUG_ERROR("executable '%s' has no symbols", crash.exe);
return; return false;
} }
long storage = bfd_get_symtab_upper_bound(crash.fd); long storage = bfd_get_symtab_upper_bound(crash.fd);
@ -92,8 +93,10 @@ static void load_symbols(void)
if (crash.symCount < 0) if (crash.symCount < 0)
{ {
DEBUG_ERROR("failed to get the symbol count"); DEBUG_ERROR("failed to get the symbol count");
return; return false;
} }
return true;
} }
static bool lookup_address(bfd_vma pc, const char ** filename, const char ** function, unsigned int * line, unsigned int * discriminator) static bool lookup_address(bfd_vma pc, const char ** filename, const char ** function, unsigned int * line, unsigned int * discriminator)
@ -131,7 +134,7 @@ static bool lookup_address(bfd_vma pc, const char ** filename, const char ** fun
return true; return true;
} }
static void cleanup(void) void cleanupCrashHandler(void)
{ {
if (crash.syms) if (crash.syms)
free(crash.syms); free(crash.syms);
@ -168,18 +171,12 @@ static int dl_iterate_phdr_callback(struct dl_phdr_info * info, size_t size, voi
return 0; return 0;
} }
static void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext) void printBacktrace(void)
{ {
void * array[50]; void * array[50];
char ** messages; char ** messages;
int size, i; int size, i;
dl_iterate_phdr(dl_iterate_phdr_callback, NULL);
load_symbols();
DEBUG_ERROR("==== FATAL CRASH (%s) ====", BUILD_VERSION);
DEBUG_ERROR("signal %d (%s), address is %p", sig_num, strsignal(sig_num), info->si_addr);
size = backtrace(array, 50); size = backtrace(array, 50);
messages = backtrace_symbols(array, size); messages = backtrace_symbols(array, size);
@ -210,7 +207,14 @@ static void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext)
} }
free(messages); free(messages);
cleanup(); }
static void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext)
{
DEBUG_ERROR("==== FATAL CRASH (%s) ====", BUILD_VERSION);
DEBUG_ERROR("signal %d (%s), address is %p", sig_num, strsignal(sig_num), info->si_addr);
printBacktrace();
cleanupCrashHandler();
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -219,6 +223,13 @@ bool installCrashHandler(const char * exe)
struct sigaction sigact = { 0 }; struct sigaction sigact = { 0 };
crash.exe = realpath(exe, NULL); crash.exe = realpath(exe, NULL);
if (!load_symbols())
{
DEBUG_WARN("Unable to load the binary symbols, not installing crash handler");
return true;
}
dl_iterate_phdr(dl_iterate_phdr_callback, NULL);
sigact.sa_sigaction = crit_err_hdlr; sigact.sa_sigaction = crit_err_hdlr;
sigact.sa_flags = SA_RESTART | SA_SIGINFO; sigact.sa_flags = SA_RESTART | SA_SIGINFO;
@ -238,4 +249,12 @@ bool installCrashHandler(const char * exe)
return true; return true;
} }
void cleanupCrashHandler(void)
{
}
void printBacktrace(void)
{
}
#endif #endif