1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
|
From 3521be8b8599ae2cc12361c8f600fc58a473de91 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
Date: Sat, 7 Feb 2015 13:32:56 +0000
Subject: [PATCH 14/29] print backtrace in assert logging with libunwind
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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
---
NEWS | 1 +
configure.ac | 11 +++++++++
src/CMakeLists.txt | 11 +++++++++
src/Makefile.am | 5 ++--
src/buffer.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/buffer.h | 2 ++
src/config.h.cmake | 3 +++
7 files changed, 102 insertions(+), 2 deletions(-)
diff --git a/NEWS b/NEWS
index 9c579de..fd537e8 100644
--- a/NEWS
+++ b/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
diff --git a/configure.ac b/configure.ac
index e804030..63261ca 100644
--- a/configure.ac
+++ b/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,
diff --git a/src/Makefile.am b/src/Makefile.am
index 4afdcc6..a5471ff 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -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
diff --git a/src/buffer.c b/src/buffer.c
index 1199164..b4bd415 100644
--- a/src/buffer.c
+++ b/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();
}
diff --git a/src/buffer.h b/src/buffer.h
index 20635e2..d2f5985 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -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");
--
2.4.5
|