From 2a69789a246a80053996cc7bc083d68b64fa33dc Mon Sep 17 00:00:00 2001 From: Allanis <allanis@saracraft.net> Date: Tue, 26 Nov 2013 18:23:50 +0000 Subject: [PATCH] [Add] Automagically give backtraces in DEBUG mode. --- bin/Makefile | 38 +++++++++++++------- src/lephisto.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/lluadef.h | 6 ++-- src/log.h | 4 +-- 4 files changed, 125 insertions(+), 20 deletions(-) diff --git a/bin/Makefile b/bin/Makefile index 1a083a4..762b283 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -26,19 +26,6 @@ CXML = $(shell xml2-config --cflags) CTTF = $(shell freetype-config --cflags) CGL = CFLAGS = $(CLUA) $(CSDL) $(CXML) $(CTTF) $(CGL) $(VERSION) -D$(OS) -ifeq ($(OS),LINUX) - CFLAGS += -D_POSIX_SOURCE -endif -ifdef DEBUG -CFLAGS += -W -Wall -Wextra -Wunused -Wshadow -Wpointer-arith -Wmissing-prototypes \ - -Winline -Wcast-align -Wmissing-declarations -fstack-protector \ - -fstack-protector-all -g3 -DDEBUG -DLUA_USE_APICHECK -std=c99 -ifdef DEBUG_PARANOID - CFLAGS += -DDEBUG_PARANOID -endif -else -CFLAGS += -O2 -funroll-loops -pipe -std=c99 -endif # LDFLAGS. LDLUA = ../lib/lua/liblua.a @@ -49,6 +36,31 @@ LDGL = -lGL LDPNG = -lpng LDFLAGS = -lm $(LDLUA) $(LDSDL) $(LDXML) $(LDTTF) $(LDGL) $(LDPNG) +# OS Stuff. +ifeq ($(OS),LINUX) + CFLAGS += -D_POSIX_SOURCE +endif + +# Debug stuff. +ifdef DEBUG +CFLAGS += -W -Wall -Wextra -Wunused -Wshadow -Wpointer-arith -Wmissing-prototypes \ + -Winline -Wcast-align -Wmissing-declarations -fstack-protector \ + -fstack-protector-all -g3 -DDEBUG -DLUA_USE_APICHECK -std=c99 + +ifdef DEBUG_PARANOID + CFLAGS += -DDEBUG_PARANOID +endif + +# Handle OS Debug stuff here. +ifeq ($(OS), LINUX) + LDFLAGS += -rdynamic +endif # Linux. + +else # DEBUG +CFLAGS += -O2 -funroll-loops -pipe -std=c99 +endif + + # This is just for gstat to run some analysis on performance. ifdef DEBUG LDFLAGS += -pg diff --git a/src/lephisto.c b/src/lephisto.c index a58613a..0f988a8 100644 --- a/src/lephisto.c +++ b/src/lephisto.c @@ -10,8 +10,17 @@ */ #include <SDL/SDL.h> -#include <string.h> +/* Global. */ +#include <string.h> +#if defined(LINUX) && !defined(NODEBUG) +#include <signal.h> +#include <execinfo.h> +#include <stdlib.h> +#include <unistd.h> +#endif /* defined(LINUX) && !defined(NODEBUG) */ + +/* Local. */ #include "lephisto.h" #include "conf.h" #include "log.h" @@ -74,15 +83,17 @@ static void print_SDLversion(void); static void load_screen(void); static void load_all(void); static void unload_all(void); -void main_loop(void); static void display_fps(const double dt); static void window_caption(void); static void data_name(void); +static void debug_sigInit(void); /* Update. */ static void fps_control(void); static void update_all(void); static void update_routine(double dt); static void render_all(void); +/* Misc. */ +void main_loop(void); /* dialogue.c */ /** @@ -112,6 +123,9 @@ int main(int argc, char** argv) { /* Initialize SDL for possible warnings. */ SDL_Init(0); + /* Set up debug signal handlers. */ + debug_sigInit(); + /* Create the home directory if needed. */ if(lfile_dirMakeExist(".")) WARN("Unable to create lephisto directory '%s'", lfile_basePath()); @@ -591,3 +605,82 @@ static void print_SDLversion(void) { WARN("SDL is older than compiled version."); } +#if defined(LINUX) && !defined(NODEBUG) +/** + * @brief Get the string related to the signal code. + * @param sig Signal to which code belongs. + * @param sig_code Signal code to get string of. + * @return String of signal code. + */ +static const char* debug_sigCodeToStr(int sig, int sig_code) { + if(sig == SIGFPE) + switch(sig_code) { + case FPE_INTDIV: return "SIGFPE (integer divide by zero)"; + case FPE_INTOVF: return "SIGFPE (integer overflow)"; + case FPE_FLTDIV: return "SIGFPE (floating-point divide by zero)"; + case FPE_FLTOVF: return "SIGFPE (floating-point overflow)"; + case FPE_FLTUND: return "SIGFPE (floating-point underflow)"; + case FPE_FLTRES: return "SIGFPE (floating-point inexact result)"; + case FPE_FLTINV: return "SIGFPE (floating-point invalid operation)"; + case FPE_FLTSUB: return "SIGFPE (subscript out of range)"; + default: return "SIGFPE"; + } + else if(sig == SIGSEGV) + switch(sig_code) { + case SEGV_MAPERR: return "SIGEGV (address not mapped to object)"; + case SEGV_ACCERR: return "SIGEGV (invalid permissions for mapped object)"; + default: return "SIGSEGV"; + } + /* No suitable code found. */ + return strsignal(sig); +} + +/** + * @brief Backtrace signal handler for linux. + * @param sig Signal. + * @param info Signal information. + * @param unused Unused. + */ +static void debug_sigHandler(int sig, siginfo_t* info, void* unused) { + (void) sig; + (void) unused; + int i, num; + void* buf[64]; + char** symbols; + + num = backtrace(buf, 64); + symbols = backtrace_symbols(buf, num); + + DEBUG("LEPHISTO recieved %s!", + debug_sigCodeToStr(info->si_signo, info->si_code)); + for(i = 0; i < num; i++) + DEBUG(" %s", symbols[i]); + DEBUG("Report this to project maintainer with the backtrace."); + + exit(1); +} +#endif /* defined(LINUX) && !defined(DEBUG) */ + +/** + * @brief Set up the SignalHandler for Linux. + */ +static void debug_sigInit(void) { +#if defined(LINUX) && !defined(NODEBUG) + struct sigaction sa, so; + + /* Set up handler. */ + sa.sa_handler = NULL; + sa.sa_sigaction = debug_sigHandler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + + /* Attach signals. */ + sigaction(SIGSEGV, &sa, &so); + if(so.sa_handler == SIG_IGN) + DEBUG("Unable to set up SIGSEGV signal handler."); + sigaction(SIGFPE, &sa, &so); + if(so.sa_handler == SIG_IGN) + DEBUG("Unable to set up SIGFPE signal handler."); +#endif /* #if defined(LINUX) && !defined(NODEBUG) */ +} + diff --git a/src/lluadef.h b/src/lluadef.h index e2cb88d..b3d2639 100644 --- a/src/lluadef.h +++ b/src/lluadef.h @@ -5,7 +5,7 @@ #include "lualib.h" /* Debug stuff. */ -#ifdef DEBUG +#ifdef NODEBUG #define LLUA_DEBUG(str, args...) \ (fprintf(stdout, "Lua: "str"\n", ## args)) @@ -19,11 +19,11 @@ LLUA_DEBUG("[%s] Too few arguments (%s:%d)", __func__, __FILE__, __LINE__); \ return 0; \ } -#else /* DEBUG. */ +#else /* NODEBUG. */ #define LLUA_DEBUG(str, args...) do {;} while(0) #define LLUA_MIN_ARGS(n) do {;} while(0) #define LLUA_INVALID_PARAMETER() do {;} while(0) -#endif /* DEBUG. */ +#endif /* NODEBUG. */ /* Comfortability macros. */ #define luaL_dobuffer(L, b, n, s) \ diff --git a/src/log.h b/src/log.h index 2fc6801..6da5a36 100644 --- a/src/log.h +++ b/src/log.h @@ -9,9 +9,9 @@ #define LOG(str, args...)(fprintf(stdout, str"\n", ## args)) #ifdef DEBUG_PARANOID /* Will cause WARN's to blow up. */ -#define WARN(str, args...)(fprintf(stderr, "Warning: "str"\n", ## args), assert(0)) +#define WARN(str, args...)(fprintf(stderr, "Warning: [%s] "str"\n", __func__, ## args), assert(0)) #else -#define WARN(str, args...)(fprintf(stderr, "Warning: "str"\n", ## args)) +#define WARN(str, args...)(fprintf(stderr, "Warning: [%s] "str"\n", __func__, ## args)) #endif #define ERR(str, args...) (fprintf(stderr, "ERROR %s:%d: [%s] "str"\n", \