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