tlx
backtrace.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 * tlx/backtrace.cpp
3 *
4 * Part of tlx - http://panthema.net/tlx
5 *
6 * Copyright (C) 2008-2017 Timo Bingmann <tb@panthema.net>
7 *
8 * All rights reserved. Published under the Boost Software License, Version 1.0
9 ******************************************************************************/
10
11#include <tlx/backtrace.hpp>
12
13#include <tlx/unused.hpp>
14
15#include <cstdarg>
16#include <cstdio>
17#include <cstdlib>
18
19#if __linux__
20
21#include <cxxabi.h>
22#include <execinfo.h>
23#include <signal.h>
24#include <unistd.h>
25
26#endif
27
28namespace tlx {
29
30void print_raw_backtrace(FILE* out, unsigned int max_frames,
31 const char* fmt, ...) {
32 char buffer[1024];
33 size_t p = 0;
34
35 va_list args;
36 va_start(args, fmt);
37
38 p += vsnprintf(buffer + p, sizeof(buffer) - p - 1, fmt, args);
39
40#if __linux__
41
42 // storage array for stack trace address data
43 void** addrlist = reinterpret_cast<void**>(
44 alloca(sizeof(void*) * max_frames));
45
46 // retrieve current stack addresses
47 int addrlen = backtrace(addrlist, max_frames);
48
49 for (int i = 1; i < addrlen; ++i) {
50 if (addrlist[i] == nullptr)
51 break;
52
53 p += snprintf(buffer + p, sizeof(buffer) - p - 1, " %p", addrlist[i]);
54 }
55
56 buffer[p + 1] = 0;
57 fprintf(out, "%s\n", buffer);
58
59#else
60
61 fprintf(out, "(backtrace not supported on this platform)\n");
62 tlx::unused(max_frames);
63
64#endif
65
66 va_end(args);
67}
68
69void print_raw_backtrace(FILE* out, unsigned int max_frames) {
70 return print_raw_backtrace(out, max_frames, "backtrace:");
71}
72
73void print_cxx_backtrace(FILE* out, unsigned int max_frames) {
74 fprintf(out, "backtrace:\n");
75
76#if __linux__
77
78 // storage array for stack trace address data
79 void** addrlist = reinterpret_cast<void**>(
80 alloca(sizeof(void*) * max_frames));
81
82 // retrieve current stack addresses
83 int addrlen = backtrace(addrlist, max_frames);
84
85 if (addrlen == 0) {
86 fprintf(out, " <empty, possibly corrupt>\n");
87 return;
88 }
89
90 // resolve addresses into strings containing "filename(function+address)",
91 // this array must be free()-ed
92 char** symbollist = backtrace_symbols(addrlist, addrlen);
93
94 // allocate string which will be filled with the demangled function name
95 size_t funcnamesize = 256;
96 char* funcname = reinterpret_cast<char*>(alloca(funcnamesize));
97
98 // iterate over the returned symbol lines. skip the first, it is the
99 // address of this function.
100 for (int i = 1; i < addrlen; i++)
101 {
102 char* begin_name = 0, * begin_offset = 0, * end_offset = 0;
103
104 // find parentheses and +address offset surrounding the mangled name:
105 // ./module(function+0x15c) [0x8048a6d]
106 for (char* p = symbollist[i]; *p; ++p)
107 {
108 if (*p == '(')
109 begin_name = p;
110 else if (*p == '+')
111 begin_offset = p;
112 else if (*p == ')' && begin_offset) {
113 end_offset = p;
114 break;
115 }
116 }
117
118 if (begin_name && begin_offset && end_offset
119 && begin_name < begin_offset)
120 {
121 *begin_name++ = '\0';
122 *begin_offset++ = '\0';
123 *end_offset = '\0';
124
125 // mangled name is now in [begin_name, begin_offset) and caller
126 // offset in [begin_offset, end_offset). now apply
127 // __cxa_demangle():
128
129 int status;
130 char* ret = abi::__cxa_demangle(begin_name,
131 funcname, &funcnamesize, &status);
132 if (status == 0) {
133 funcname = ret; // use possibly realloc()-ed string
134 fprintf(out, " %s : %s+%s\n",
135 symbollist[i], funcname, begin_offset);
136 }
137 else {
138 // demangling failed. Output function name as a C function with
139 // no arguments.
140 fprintf(out, " %s : %s()+%s\n",
141 symbollist[i], begin_name, begin_offset);
142 }
143 }
144 else
145 {
146 // couldn't parse the line? print the whole line.
147 fprintf(out, " %s\n", symbollist[i]);
148 }
149 }
150
151 free(symbollist);
152
153#else
154
155 fprintf(out, " (not supported on this platform)\n");
156 tlx::unused(max_frames);
157
158#endif
159}
160
161#if __linux__
162
163static void segv_backtrace_handler(int sig) {
164 tlx::unused(sig);
165
166 void* addr[16];
167 size_t size;
168
169 size = backtrace(addr, 16);
170
171 fprintf(stderr, "Caught SIGSEGV (segmentation fault). Backtrace:\n");
172 backtrace_symbols_fd(addr + 1, size - 1, STDERR_FILENO);
173 exit(1);
174}
175
176#endif
177
179#if __linux__
180 signal(SIGSEGV, segv_backtrace_handler);
181#else
182 printf("enable_segv_backtrace(): not supported on this platform.\n");
183#endif
184}
185
186} // namespace tlx
187
188/******************************************************************************/
void enable_segv_backtrace()
Install SIGSEGV signal handler and output backtrace on segmentation fault.
Definition: backtrace.cpp:178
void print_raw_backtrace(FILE *out, unsigned int max_frames, const char *fmt,...)
Print a plain hex stack backtrace of the called function to FILE* out, prefixed with the given printf...
Definition: backtrace.cpp:30
void unused(Types &&...)
Definition: unused.hpp:20
void print_cxx_backtrace(FILE *out, unsigned int max_frames)
Print a demangled stack backtrace of the caller function to FILE* out.
Definition: backtrace.cpp:73