diff --git a/src/Makefile b/src/Makefile index 37f7ba917..75dffb24e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -127,7 +127,7 @@ ifneq ($(uname_S),Darwin) endif # Linux ARM32 needs -latomic at linking time ifneq (,$(findstring armv,$(uname_M))) - FINAL_LIBS+=-latomic + FINAL_LIBS+=-latomic endif @@ -177,7 +177,7 @@ ifeq ($(uname_S),OpenBSD) FINAL_CXXFLAGS+= -DUSE_BACKTRACE -I/usr/local/include FINAL_LDFLAGS+= -L/usr/local/lib FINAL_LIBS+= -lexecinfo - endif + endif else ifeq ($(uname_S),NetBSD) @@ -187,7 +187,7 @@ ifeq ($(uname_S),NetBSD) FINAL_CFLAGS+= -DUSE_BACKTRACE -I/usr/pkg/include FINAL_LDFLAGS+= -L/usr/pkg/lib FINAL_LIBS+= -lexecinfo - endif + endif else ifeq ($(uname_S),FreeBSD) # FreeBSD @@ -316,6 +316,14 @@ else endef endif +# Alpine OS doesn't have support for the execinfo backtrace library we use for debug, so we provide an alternate implementation using libwunwind. +OS := $(shell cat /etc/os-release | grep ID= | head -n 1 | cut -d'=' -f2) +ifeq ($(OS),alpine) + FINAL_CXXFLAGS+=-DUNW_LOCAL_ONLY + FINAL_LIBS += -lunwind +endif + + REDIS_CC=$(QUIET_CC)$(CC) $(FINAL_CFLAGS) REDIS_CXX=$(QUIET_CC)$(CXX) $(FINAL_CXXFLAGS) KEYDB_AS=$(QUIET_CC) as --64 -g diff --git a/src/debug.cpp b/src/debug.cpp index 7b7fe29e1..a9614b61e 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -51,6 +51,12 @@ typedef ucontext_t sigcontext_t; #include #endif /* HAVE_BACKTRACE */ +//UNW_LOCAL_ONLY being set means we use libunwind for backtraces instead of execinfo +#ifdef UNW_LOCAL_ONLY +#include +#include +#endif + #ifdef __CYGWIN__ #ifndef SA_ONSTACK #define SA_ONSTACK 0x08000000 @@ -947,7 +953,7 @@ void _serverAssert(const char *estr, const char *file, int line) { serverLog(LL_WARNING,"==> %s:%d '%s' is not true",file,line,estr); if (g_pserver->crashlog_enabled) { -#ifdef HAVE_BACKTRACE +#if defined HAVE_BACKTRACE || defined UNW_LOCAL_ONLY logStackTrace(NULL, 1); #endif printCrashReport(); @@ -1044,7 +1050,7 @@ void _serverPanic(const char *file, int line, const char *msg, ...) { serverLog(LL_WARNING,"Guru Meditation: %s #%s:%d",fmtmsg,file,line); if (g_pserver->crashlog_enabled) { -#ifdef HAVE_BACKTRACE +#if defined HAVE_BACKTRACE || defined UNW_LOCAL_ONLY logStackTrace(NULL, 1); #endif printCrashReport(); @@ -1599,6 +1605,65 @@ void safe_write(int fd, const void *pv, ssize_t cb) } while (offset < cb); } +#ifdef UNW_LOCAL_ONLY + +/* Logs the stack trace using the libunwind call. + * The eip argument is unused as libunwind only gets local context. + * The uplevel argument indicates how many of the calling functions to skip. + */ +void logStackTrace(void * eip, int uplevel) { + (void)eip;//UNUSED + const char *msg; + int fd = openDirectLogFiledes(); + + if (fd == -1) return; /* If we can't log there is anything to do. */ + + msg = "\n------ STACK TRACE ------\n"; + if (write(fd,msg,strlen(msg)) == -1) {/* Avoid warning. */}; + unw_cursor_t cursor; + unw_context_t context; + + unw_getcontext(&context); + unw_init_local(&cursor, &context); + + /* Write symbols to log file */ + msg = "\nBacktrace:\n"; + if (write(fd,msg,strlen(msg)) == -1) {/* Avoid warning. */}; + + for (int i = 0; i < uplevel; i++) { + unw_step(&cursor); + } + + while ( unw_step(&cursor) ) { + unw_word_t ip, sp, off; + + unw_get_reg(&cursor, UNW_REG_IP, &ip); + unw_get_reg(&cursor, UNW_REG_SP, &sp); + + char symbol[256] = {""}; + char *name = symbol; + + if ( !unw_get_proc_name(&cursor, symbol, sizeof(symbol), &off) ) { + int status; + if ( (name = abi::__cxa_demangle(symbol, NULL, NULL, &status)) == 0 ) + name = symbol; + } + + dprintf(fd, "%s(+0x%" PRIxPTR ") [0x%016" PRIxPTR "] sp=0x%016" PRIxPTR "\n", + name, + static_cast(off), + static_cast(ip), + static_cast(sp)); + + if ( name != symbol ) + free(name); + } +} + +#endif /* UNW_LOCAL_ONLY */ + +#ifdef HAVE_BACKTRACE + void backtrace_symbols_demangle_fd(void **trace, size_t csym, int fd) { char **syms = backtrace_symbols(trace, csym); @@ -1642,8 +1707,6 @@ void backtrace_symbols_demangle_fd(void **trace, size_t csym, int fd) free(syms); } -#ifdef HAVE_BACKTRACE - /* Logs the stack trace using the backtrace() call. This function is designed * to be called from signal handlers safely. * The eip argument is optional (can take NULL). @@ -1934,6 +1997,9 @@ void sigsegvHandler(int sig, siginfo_t *info, void *secret) { logRegisters(uc); #endif +#ifdef UNW_LOCAL_ONLY + logStackTrace(NULL, 1); +#endif printCrashReport(); @@ -2028,6 +2094,8 @@ void watchdogSignalHandler(int sig, siginfo_t *info, void *secret) { serverLogFromHandler(LL_WARNING,"\n--- WATCHDOG TIMER EXPIRED ---"); #ifdef HAVE_BACKTRACE logStackTrace(getMcontextEip(uc), 1); +#elif defined UNW_LOCAL_ONLY + logStackTrace(NULL, 1); #else serverLogFromHandler(LL_WARNING,"Sorry: no support for backtrace()."); #endif