Line data Source code
1 : /*
2 : * Copyright (c) 2007-2008 Aleksey Cheusov <vle@gmx.net>
3 : *
4 : * Permission is hereby granted, free of charge, to any person obtaining
5 : * a copy of this software and associated documentation files (the
6 : * "Software"), to deal in the Software without restriction, including
7 : * without limitation the rights to use, copy, modify, merge, publish,
8 : * distribute, sublicense, and/or sell copies of the Software, and to
9 : * permit persons to whom the Software is furnished to do so, subject to
10 : * the following conditions:
11 : *
12 : * The above copyright notice and this permission notice shall be
13 : * included in all copies or substantial portions of the Software.
14 : *
15 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 : * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 : * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 : * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 : * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 : */
23 :
24 : /*
25 : * Modifications by Marek Dopiera
26 : */
27 :
28 : #include <sstream>
29 : #include <vector>
30 :
31 : #include <dlfcn.h>
32 : #include <pthread.h>
33 :
34 : #include <config/cmake_config.h>
35 : #include <debug/stacktrace.h>
36 :
37 : namespace coherent {
38 : namespace debug {
39 :
40 : static pthread_mutex_t stacktrace_mutex = PTHREAD_MUTEX_INITIALIZER;
41 :
42 : #if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE)
43 : #include <execinfo.h>
44 :
45 : /* GNU libc ? */
46 0 : static int stacktrace_internal (void **buffer, int size)
47 : {
48 0 : return backtrace(buffer, size);
49 : }
50 :
51 : #else
52 : /* !HAVE_HEADER_EXECINFO_H (probably NetBSD/FreeBSD/Solaris etc.) */
53 :
54 : #include <string.h>
55 : #include <signal.h>
56 : #include <setjmp.h>
57 :
58 : static struct sigaction sigsegv_orig_handler;
59 : static struct sigaction sigbus_orig_handler;
60 :
61 : static jmp_buf jmpbuf;
62 :
63 : static void handler_sigfatal (int dummy)
64 : {
65 : longjmp (jmpbuf,1);
66 : }
67 :
68 : static void set_sigfatal_handlers (void)
69 : {
70 : struct sigaction sa;
71 :
72 : sa.sa_handler = handler_sigfatal;
73 : sigemptyset (&sa.sa_mask);
74 : sa.sa_flags = 0;
75 :
76 : sigaction (SIGSEGV, &sa, &sigsegv_orig_handler);
77 : sigaction (SIGBUS, &sa, &sigbus_orig_handler);
78 : }
79 :
80 : static void restore_sigfatal_handlers (void)
81 : {
82 : sigaction (SIGSEGV, &sigsegv_orig_handler, NULL);
83 : sigaction (SIGBUS, &sigbus_orig_handler, NULL);
84 : }
85 :
86 : #define one_return_address(x) \
87 : if (x >= size) break; \
88 : tb [x] = __builtin_return_address (x); \
89 : frame = __builtin_frame_address (x); \
90 : if (!tb [x] || !frame){\
91 : tb [x] = 0; \
92 : break;\
93 : }
94 :
95 : int stacktrace_internal (void **tb, int size)
96 : {
97 : int i = 0;
98 : void* frame = NULL;
99 :
100 : for (i=0; i < size; ++i){
101 : tb [i] = 0;
102 : }
103 :
104 : set_sigfatal_handlers ();
105 :
106 : if (!setjmp (jmpbuf)){
107 : while (1){
108 : one_return_address(0);
109 : one_return_address(1);
110 : one_return_address(2);
111 : one_return_address(3);
112 : one_return_address(4);
113 : one_return_address(5);
114 : one_return_address(6);
115 : one_return_address(7);
116 : one_return_address(8);
117 : one_return_address(9);
118 : one_return_address(10);
119 : one_return_address(11);
120 : one_return_address(12);
121 : one_return_address(13);
122 : one_return_address(14);
123 : one_return_address(15);
124 : one_return_address(16);
125 : one_return_address(17);
126 : one_return_address(18);
127 : one_return_address(19);
128 : one_return_address(20);
129 : one_return_address(21);
130 : one_return_address(22);
131 : one_return_address(23);
132 : one_return_address(24);
133 : one_return_address(25);
134 : one_return_address(26);
135 : one_return_address(27);
136 : one_return_address(28);
137 : one_return_address(29);
138 : one_return_address(30);
139 : one_return_address(31);
140 : one_return_address(32);
141 : one_return_address(33);
142 : one_return_address(34);
143 : one_return_address(35);
144 : one_return_address(36);
145 : one_return_address(37);
146 : one_return_address(38);
147 : one_return_address(39);
148 : }
149 :
150 : longjmp (jmpbuf, 2);
151 : }
152 :
153 : restore_sigfatal_handlers ();
154 :
155 : for (i=0; i < size; ++i){
156 : if (!tb [i])
157 : return i;
158 : }
159 : return size;
160 : }
161 :
162 : #endif /* HAVE_HEADER_EXECINFO_H */
163 :
164 : using namespace std;
165 :
166 0 : vector<string> stacktrace()
167 : {
168 0 : vector<string> res;
169 : void *syms[40];
170 0 : pthread_mutex_lock(&stacktrace_mutex);
171 0 : int const num_syms = stacktrace_internal(syms, 40);
172 0 : pthread_mutex_unlock(&stacktrace_mutex);
173 0 : for (int i = 0; i < num_syms; ++i) {
174 : Dl_info dlinfo;
175 0 : int ret = dladdr(syms[i], &dlinfo);
176 0 : if (ret) {
177 0 : stringstream ss;
178 0 : ss << dlinfo.dli_sname << " (" << syms[i] << ")";
179 0 : res.push_back(ss.str());
180 : } else {
181 0 : stringstream ss;
182 0 : ss << syms[i];
183 0 : res.push_back(ss.str());
184 : }
185 : }
186 0 : if (res.empty())
187 0 : res.push_back("(backtrace not available)");
188 : return res;
189 : }
190 :
191 0 : string stacktrace_as_string()
192 : {
193 0 : vector<string> const & elems = stacktrace();
194 0 : stringstream res;
195 0 : for (vector<string>::const_iterator it = elems.begin(); it != elems.end(); ++it) {
196 0 : if (it != elems.begin())
197 0 : res << endl;
198 0 : res << *it;
199 : }
200 0 : return res.str();
201 : }
202 :
203 : } // namespace debug
204 : } // namespace coherent
|