print backtrace in assert logging with libunwind
From: Stefan Bühler <stbuehler@web.de> git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2974 152afb58-edef-0310-8abb-c4023f1b3aa9
This commit is contained in:
parent
d00e1e79b9
commit
3521be8b85
1
NEWS
1
NEWS
|
@ -14,6 +14,7 @@ NEWS
|
|||
* fixed typo in example config found by openSUSE user (boo# 907709)
|
||||
* [network] fix compile break in calculation of sockaddr_un size if SUN_LEN is not defined (fixes #2609)
|
||||
* [connections] fix bug in connection state handling
|
||||
* print backtrace in assert logging with libunwind
|
||||
|
||||
- 1.4.35 - 2014-03-12
|
||||
* [network/ssl] fix build error if TLSEXT is disabled
|
||||
|
|
11
configure.ac
11
configure.ac
|
@ -285,6 +285,17 @@ if test "$WITH_VALGRIND" != "no"; then
|
|||
AC_CHECK_HEADERS([valgrind/valgrind.h])
|
||||
fi
|
||||
|
||||
dnl Checking for libunwind
|
||||
AC_MSG_CHECKING(for libunwind)
|
||||
AC_ARG_WITH(libunwind,
|
||||
AC_HELP_STRING([--with-libunwind],[Include libunwind support for backtraces on assert failures]),
|
||||
[WITH_LIBUNWIND=$withval],[WITH_LIBUNWIND=no])
|
||||
|
||||
if test "$WITH_LIBUNWIND" != "no"; then
|
||||
PKG_CHECK_MODULES(LIBUNWIND, libunwind)
|
||||
AC_DEFINE(HAVE_LIBUNWIND, 1, [Have libunwind support])
|
||||
fi
|
||||
|
||||
dnl Check for openssl
|
||||
AC_MSG_CHECKING(for OpenSSL)
|
||||
AC_ARG_WITH(openssl,
|
||||
|
|
|
@ -29,6 +29,7 @@ OPTION(WITH_FAM "fam/gamin for reducing number of stat() calls [default: off]")
|
|||
OPTION(WITH_GDBM "gdbm storage for mod_trigger_b4_dl [default: off]")
|
||||
OPTION(WITH_MEMCACHE "memcached storage for mod_trigger_b4_dl [default: off]")
|
||||
OPTION(WITH_LIBEV "libev support for fdevent handlers [default: off]")
|
||||
OPTION(WITH_LIBUNWIND "with libunwind to print backtraces in asserts [default: off]")
|
||||
|
||||
IF(CMAKE_COMPILER_IS_GNUCC)
|
||||
OPTION(BUILD_EXTRA_WARNINGS "extra warnings")
|
||||
|
@ -54,6 +55,11 @@ IF(WITH_LIBEV)
|
|||
SET(HAVE_LIBEV 1 FORCE)
|
||||
ENDIF(WITH_LIBEV)
|
||||
|
||||
IF(WITH_LIBUNWIND)
|
||||
pkg_check_modules(LIBUNWIND REQUIRED libunwind)
|
||||
SET(HAVE_LIBUNWIND 1 FORCE)
|
||||
ENDIF()
|
||||
|
||||
IF(WITH_WEBDAV_PROPS)
|
||||
SET(WITH_XML 1)
|
||||
SET(WITH_SQLITE3 1)
|
||||
|
@ -610,6 +616,11 @@ IF(WITH_LIBEV)
|
|||
ADD_TARGET_PROPERTIES(lighttpd COMPILE_FLAGS ${LIBEV_CFLAGS})
|
||||
ENDIF(WITH_LIBEV)
|
||||
|
||||
IF(WITH_LIBUNWIND)
|
||||
TARGET_LINK_LIBRARIES(lighttpd ${LIBUNWIND_LDFLAGS})
|
||||
ADD_TARGET_PROPERTIES(lighttpd COMPILE_FLAGS ${LIBUNWIND_CFLAGS})
|
||||
ENDIF()
|
||||
|
||||
IF(NOT WIN32)
|
||||
INSTALL(TARGETS ${L_INSTALL_TARGETS}
|
||||
RUNTIME DESTINATION ${SBINDIR}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
AM_CFLAGS = $(FAM_CFLAGS)
|
||||
AM_CFLAGS = $(FAM_CFLAGS) $(LIBUNWIND_CFLAGS)
|
||||
|
||||
noinst_PROGRAMS=proc_open lemon # simple-fcgi #graphic evalo bench ajp ssl error_test adserver gen-license
|
||||
sbin_PROGRAMS=lighttpd lighttpd-angel
|
||||
|
@ -284,11 +284,12 @@ hdr = server.h buffer.h network.h log.h keyvalue.h \
|
|||
DEFS= @DEFS@ -DHAVE_VERSION_H -DLIBRARY_DIR="\"$(libdir)\"" -DSBIN_DIR="\"$(sbindir)\""
|
||||
|
||||
lighttpd_SOURCES = $(src)
|
||||
lighttpd_LDADD = $(PCRE_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) $(common_libadd) $(SSL_LIB) $(FAM_LIBS) $(LIBEV_LIBS)
|
||||
lighttpd_LDADD = $(PCRE_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) $(common_libadd) $(SSL_LIB) $(FAM_LIBS) $(LIBEV_LIBS) $(LIBUNWIND_LIBS)
|
||||
lighttpd_LDFLAGS = -export-dynamic
|
||||
lighttpd_CCPFLAGS = $(FAM_CFLAGS) $(LIBEV_CFLAGS)
|
||||
|
||||
proc_open_SOURCES = proc_open.c buffer.c
|
||||
proc_open_LDADD = $(LIBUNWIND_LIBS)
|
||||
proc_open_CPPFLAGS= -DDEBUG_PROC_OPEN
|
||||
|
||||
#gen_license_SOURCES = license.c md5.c buffer.c gen_license.c
|
||||
|
|
71
src/buffer.c
71
src/buffer.c
|
@ -1059,9 +1059,80 @@ int buffer_to_upper(buffer *b) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBUNWIND
|
||||
# define UNW_LOCAL_ONLY
|
||||
# include <libunwind.h>
|
||||
|
||||
void print_backtrace(FILE *file) {
|
||||
unw_cursor_t cursor;
|
||||
unw_context_t context;
|
||||
int ret;
|
||||
unsigned int frame = 0;
|
||||
|
||||
if (0 != (ret = unw_getcontext(&context))) goto error;
|
||||
if (0 != (ret = unw_init_local(&cursor, &context))) goto error;
|
||||
|
||||
fprintf(file, "Backtrace:\n");
|
||||
|
||||
while (0 < (ret = unw_step(&cursor))) {
|
||||
unw_word_t proc_ip = 0;
|
||||
unw_proc_info_t procinfo;
|
||||
char procname[256];
|
||||
unw_word_t proc_offset = 0;
|
||||
|
||||
if (0 != (ret = unw_get_reg(&cursor, UNW_REG_IP, &proc_ip))) goto error;
|
||||
|
||||
if (0 == proc_ip) {
|
||||
/* without an IP the other functions are useless; unw_get_proc_name would return UNW_EUNSPEC */
|
||||
++frame;
|
||||
fprintf(file, "%u: (nil)\n", frame);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (0 != (ret = unw_get_proc_info(&cursor, &procinfo))) goto error;
|
||||
|
||||
if (0 != (ret = unw_get_proc_name(&cursor, procname, sizeof(procname), &proc_offset))) {
|
||||
switch (-ret) {
|
||||
case UNW_ENOMEM:
|
||||
memset(procname + sizeof(procname) - 4, '.', 3);
|
||||
procname[sizeof(procname) - 1] = '\0';
|
||||
break;
|
||||
case UNW_ENOINFO:
|
||||
procname[0] = '?';
|
||||
procname[1] = '\0';
|
||||
proc_offset = 0;
|
||||
break;
|
||||
default:
|
||||
snprintf(procname, sizeof(procname), "?? (unw_get_proc_name error %d)", -ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
++frame;
|
||||
fprintf(file, "%u: %s (+0x%x) [%p]\n",
|
||||
frame,
|
||||
procname,
|
||||
(unsigned int) proc_offset,
|
||||
(void*)(uintptr_t)proc_ip);
|
||||
}
|
||||
|
||||
if (0 != ret) goto error;
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
fprintf(file, "Error while generating backtrace: unwind error %i\n", (int) -ret);
|
||||
}
|
||||
#else
|
||||
void print_backtrace(FILE *file) {
|
||||
UNUSED(file);
|
||||
}
|
||||
#endif
|
||||
|
||||
void log_failed_assert(const char *filename, unsigned int line, const char *msg) {
|
||||
/* can't use buffer here; could lead to recursive assertions */
|
||||
fprintf(stderr, "%s.%d: %s\n", filename, line, msg);
|
||||
print_backtrace(stderr);
|
||||
fflush(stderr);
|
||||
abort();
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct {
|
||||
char *ptr;
|
||||
|
@ -128,6 +129,7 @@ int light_isalnum(int c);
|
|||
|
||||
#define UNUSED(x) ( (void)(x) )
|
||||
|
||||
void print_backtrace(FILE *file);
|
||||
void log_failed_assert(const char *filename, unsigned int line, const char *msg) LI_NORETURN;
|
||||
#define force_assert(x) do { if (!(x)) log_failed_assert(__FILE__, __LINE__, "assertion failed: " #x); } while(0)
|
||||
#define SEGFAULT() log_failed_assert(__FILE__, __LINE__, "aborted");
|
||||
|
|
|
@ -158,4 +158,7 @@
|
|||
/* libev */
|
||||
#cmakedefine HAVE_LIBEV
|
||||
|
||||
/* libunwind */
|
||||
#cmakedefine HAVE_LIBUNWIND
|
||||
|
||||
#cmakedefine LIGHTTPD_STATIC
|
||||
|
|
Loading…
Reference in New Issue