diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/Makefile.in | 27 | ||||
-rw-r--r-- | src/common/core.c | 2 | ||||
-rw-r--r-- | src/common/nullpo.c | 133 | ||||
-rw-r--r-- | src/common/nullpo.h | 7 |
4 files changed, 151 insertions, 18 deletions
diff --git a/src/common/Makefile.in b/src/common/Makefile.in index 033b26ae3..22b974cfd 100644 --- a/src/common/Makefile.in +++ b/src/common/Makefile.in @@ -33,6 +33,19 @@ LIBCONFIG_OBJ = $(addprefix $(LIBCONFIG_D)/, libconfig.o grammar.o scanctx.o \ LIBCONFIG_H = $(addprefix $(LIBCONFIG_D)/, libconfig.h grammar.h parsectx.h \ scanctx.h scanner.h strbuf.h wincompat.h) +ifeq (@USE_LIBBACKTRACE@,yes) + LIBBACKTRACE_D = $(THIRDPARTY_D)/libbacktrace + LIBBACKTRACE_OBJ = $(addprefix $(LIBBACKTRACE_D)/, atomic.o backtrace.o \ + dwarf.o @LIBBACKTRACE_FORMAT_FILE@ fileline.o mmapio.o mmap.o posix.o print.o \ + simple.o sort.o state.o) + LIBBACKTRACE_H = $(addprefix $(LIBBACKTRACE_D)/, backtrace.h \ + backtrace-supported.h config.h filenames.h internal.h) +else + LIBBACKTRACE_D = + LIBBACKTRACE_OBJ = + LIBBACKTRACE_H = +endif + MT19937AR_D = $(THIRDPARTY_D)/mt19937ar MT19937AR_OBJ = $(MT19937AR_D)/mt19937ar.o MT19937AR_H = $(MT19937AR_D)/mt19937ar.h @@ -95,7 +108,7 @@ help: Makefile: Makefile.in @$(MAKE) -C ../.. src/common/Makefile -$(SYSINFO_INC): $(COMMON_C) $(COMMON_PH) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) +$(SYSINFO_INC): $(COMMON_C) $(COMMON_PH) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) $(LIBBACKTRACE_H) @echo " MAKE $@" @$(MAKE) -C ../.. sysinfo @@ -121,7 +134,7 @@ obj_sql/common_sql.a: $(COMMON_SQL_OBJ) Makefile @echo " AR $@" @@AR@ rcs obj_sql/common_sql.a $(COMMON_SQL_OBJ) -common: $(COMMON_OBJ) $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) obj_all/common.a Makefile +common: $(COMMON_OBJ) $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) $(LIBBACKTRACE_OBJ) obj_all/common.a Makefile common_sql: $(COMMON_SQL_OBJ) obj_sql/common_sql.a Makefile @@ -134,14 +147,18 @@ $(LIBCONFIG_OBJ): @echo " MAKE $@" @$(MAKE) -C $(LIBCONFIG_D) +$(LIBBACKTRACE_OBJ): + @echo " MAKE $@" + @$(MAKE) -C $(LIBBACKTRACE_D) + .SECONDEXPANSION: -obj_all/sysinfo.o: sysinfo.c $(filter sysinfo.p.h, $(COMMON_PH)) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) $(SYSINFO_INC) | obj_all +obj_all/sysinfo.o: sysinfo.c $(filter sysinfo.p.h, $(COMMON_PH)) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) $(LIBBACKTRACE_H) $(SYSINFO_INC) | obj_all -obj_all/%.o: %.c $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) | $(SYSINFO_INC) obj_all +obj_all/%.o: %.c $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) $(LIBBACKTRACE_H) | $(SYSINFO_INC) obj_all @echo " CC $<" @$(CC) @CFLAGS@ @DEFS@ $(COMMON_INCLUDE) $(THIRDPARTY_INCLUDE) @CPPFLAGS@ -c $(OUTPUT_OPTION) $< -obj_sql/%.o: %.c $$(filter %.p.h, $(COMMON_PH)) $(COMMON_H) $(COMMON_SQL_H) $(CONFIG_H) $(LIBCONFIG_H) | $(SYSINFO_INC) obj_sql +obj_sql/%.o: %.c $$(filter %.p.h, $(COMMON_PH)) $(COMMON_H) $(COMMON_SQL_H) $(CONFIG_H) $(LIBCONFIG_H) $(LIBBACKTRACE_H) | $(SYSINFO_INC) obj_sql @echo " CC $<" @$(CC) @CFLAGS@ @DEFS@ $(COMMON_INCLUDE) $(THIRDPARTY_INCLUDE) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< diff --git a/src/common/core.c b/src/common/core.c index 54358b85c..5be90a411 100644 --- a/src/common/core.c +++ b/src/common/core.c @@ -489,6 +489,7 @@ int main(int argc, char **argv) iMalloc->init();// needed for Show* in display_title() [FlavioJS] showmsg->init(); + nullpo->init(); cmdline->init(); @@ -552,6 +553,7 @@ int main(int argc, char **argv) cmdline->final(); //sysinfo->final(); Called by iMalloc->final() + nullpo->final(); iMalloc->final(); showmsg->final(); // Should be after iMalloc->final() diff --git a/src/common/nullpo.c b/src/common/nullpo.c index dfb938708..11741745c 100644 --- a/src/common/nullpo.c +++ b/src/common/nullpo.c @@ -23,18 +23,106 @@ #include "nullpo.h" #include "common/showmsg.h" +#include "common/strlib.h" #include <stdio.h> #include <stdarg.h> #include <stdlib.h> #include <string.h> -#ifdef HAVE_EXECINFO +#if defined(HAVE_LIBBACKTRACE) +#include "libbacktrace/backtrace.h" +#include "libbacktrace/backtrace-supported.h" +# if defined(WIN32) +# include <windows.h> +# elif defined(__sun) +# include <limits.h> +# elif defined(__linux) || defined(__linux__) +# include <unistd.h> +# include <limits.h> +# elif defined(__APPLE__) && defined(__MACH__) +# include <mach-o/dyld.h> +# elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) +# include <sys/types.h> +# include <sys/sysctl.h> +# endif +#elif defined(HAVE_EXECINFO) #include <execinfo.h> -#endif // HAVE_EXECINFO +#endif // HAVE_LIBBACKTRACE + static struct nullpo_interface nullpo_s; struct nullpo_interface *nullpo; +#ifdef HAVE_LIBBACKTRACE +static char executable_path[PATH_MAX]; + +static void nullpo_error_callback(void *data, const char *msg, int errnum) +{ + ShowError("Error: %s (%d)", msg, errnum); +} + +static int nullpo_print_callback(void *data, uintptr_t pc, const char *filename, int lineno, const char *function) +{ + ShowError("0x%lx %s\n", + (unsigned long) pc, + function == NULL ? "???" : function); + ShowError("\t%s:%d\n", + filename == NULL ? "???" : filename, + lineno); + return 0; +} + +static void nullpo_backtrace_print(struct backtrace_state *state) +{ + backtrace_full(state, 0, nullpo_print_callback, nullpo_error_callback, state); +} + +static bool nullpo_backtrace_get_executable_path(char *buf, size_t length) +{ +#if defined(WIN32) + char *exe_path = NULL; + if (_get_pgmptr(&exe_path) != 0) + return false; + safestrncpy(buf, exe_path, length); + return true; +#elif defined(__sun) + if (length < MAX_PATH) + return false; + if (realpath(getexecname(), buf) == NULL) + return false; + buf[length - 1] = '\0'; + return true; +#elif defined(__linux) || defined(__linux__) + ssize_t len = readlink("/proc/self/exe", buf, length); + if (len <= 0 || len == length) + return false; + buf[len] = '\0'; + return true; +#elif defined(__APPLE__) && defined(__MACH__) + uint32_t len = (uint32_t)length; + if (_NSGetExecutablePath(buf, &len) != 0) + return false; // buffer too small (!) + // resolve symlinks, ., .. if possible + char *canonical_path = realpath(buf, NULL); + if (canonical_path != NULL) { + safestrncpy(buf, canonical_path, length); + free(canonical_path); + } + return true; +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) + int mib[4]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + if (sysctl(mib, 4, buf, &length, NULL, 0) != 0) + return false; + return true; +#endif + return false; +} +#endif // HAVE_LIBBACKTRACE + /** * Reports failed assertions or NULL pointers * @@ -46,12 +134,6 @@ struct nullpo_interface *nullpo; */ static void assert_report(const char *file, int line, const char *func, const char *targetname, const char *title) { -#ifdef HAVE_EXECINFO - void *array[10]; - int size; - char **strings; - int i; -#endif // HAVE_EXECINFO if (file == NULL) file = "??"; @@ -60,21 +142,46 @@ static void assert_report(const char *file, int line, const char *func, const ch ShowError("--- %s --------------------------------------------\n", title); ShowError("%s:%d: '%s' in function `%s'\n", file, line, targetname, func); -#ifdef HAVE_EXECINFO - size = (int)backtrace(array, 10); - strings = backtrace_symbols(array, size); - for (i = 0; i < size; i++) +#ifdef HAVE_LIBBACKTRACE + if (nullpo->backtrace_state != NULL) + nullpo_backtrace_print(nullpo->backtrace_state); +#elif defined(HAVE_EXECINFO) + void *array[10]; + int size = (int)backtrace(array, 10); + char **strings = backtrace_symbols(array, size); + for (int i = 0; i < size; i++) ShowError("%s\n", strings[i]); free(strings); -#endif // HAVE_EXECINFO +#endif // HAVE_LIBBACKTRACE ShowError("--- end %s ----------------------------------------\n", title); } +static void nullpo_init(void) +{ +#ifdef HAVE_LIBBACKTRACE + if (!nullpo_backtrace_get_executable_path(executable_path, sizeof executable_path)) { + safestrncpy(executable_path, "hercules", sizeof executable_path); + } + nullpo->backtrace_state = backtrace_create_state(executable_path, BACKTRACE_SUPPORTS_THREADS, nullpo_error_callback, NULL); +#endif +} + +static void nullpo_final(void) +{ + // FIXME: libbacktrace doesn't provide a backtrace_free_state, and it's unsafe to pass the state to + // backtrace_free (the function itself uses the state internally). For the time being, we'll leave the state + // allocated until program termination as shown in their examples. +} + /** * **/ void nullpo_defaults(void) { nullpo = &nullpo_s; + nullpo->init = nullpo_init; + nullpo->final = nullpo_final; nullpo->assert_report = assert_report; + + nullpo->backtrace_state = NULL; } diff --git a/src/common/nullpo.h b/src/common/nullpo.h index fc5386243..3eb002834 100644 --- a/src/common/nullpo.h +++ b/src/common/nullpo.h @@ -28,6 +28,8 @@ // if need disable asserts checks this line can be commented #define ASSERT_CHECK +struct backtrace_state; + /** Assert */ #if defined(ASSERT_CHECK) @@ -148,7 +150,12 @@ struct nullpo_interface { + void (*init) (void); + void (*final) (void); + void (*assert_report) (const char *file, int line, const char *func, const char *targetname, const char *title); + + struct backtrace_state *backtrace_state; }; #ifdef HERCULES_CORE |