summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorHaru <haru@dotalux.com>2020-04-05 19:36:23 +0200
committerGitHub <noreply@github.com>2020-04-05 19:36:23 +0200
commit0c7baa39ae58eaf7f823f04a57247e1cc7ab604f (patch)
tree8def48313a6f33bbc4c5e44431bd4c5a0462de01 /src/common
parentdd7f653b00239299cdecb7ca826c21e5957863da (diff)
parentc0e51f774c8c3c0ee763e166fd4534624966edcf (diff)
downloadhercules-0c7baa39ae58eaf7f823f04a57247e1cc7ab604f.tar.gz
hercules-0c7baa39ae58eaf7f823f04a57247e1cc7ab604f.tar.bz2
hercules-0c7baa39ae58eaf7f823f04a57247e1cc7ab604f.tar.xz
hercules-0c7baa39ae58eaf7f823f04a57247e1cc7ab604f.zip
Merge pull request #2581 from 4144/backtrace
Add proper backtrace logging even if functions is hidden.
Diffstat (limited to 'src/common')
-rw-r--r--src/common/Makefile.in27
-rw-r--r--src/common/core.c2
-rw-r--r--src/common/nullpo.c133
-rw-r--r--src/common/nullpo.h7
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