1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/debug/stack_trace.h"
13 #include <sys/param.h>
15 #include <sys/types.h>
20 #if defined(__GLIBCXX__)
24 #if defined(OS_MACOSX)
25 #include <AvailabilityMacros.h>
28 #include "base/basictypes.h"
29 #include "base/debug/debugger.h"
30 #include "base/logging.h"
31 #include "base/memory/scoped_ptr.h"
32 #include "base/posix/eintr_wrapper.h"
33 #include "base/process_util.h"
34 #include "base/string_number_conversions.h"
36 #if defined(USE_SYMBOLIZE)
37 #include "base/third_party/symbolize/symbolize.h"
45 volatile sig_atomic_t in_signal_handler
= 0;
47 // The prefix used for mangled symbols, per the Itanium C++ ABI:
48 // http://www.codesourcery.com/cxx-abi/abi.html#mangling
49 const char kMangledSymbolPrefix
[] = "_Z";
51 // Characters that can be used for symbols, generated by Ruby:
52 // (('a'..'z').to_a+('A'..'Z').to_a+('0'..'9').to_a + ['_']).join
53 const char kSymbolCharacters
[] =
54 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
56 #if !defined(USE_SYMBOLIZE)
57 // Demangles C++ symbols in the given text. Example:
59 // "out/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]"
61 // "out/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x817778c]"
62 void DemangleSymbols(std::string
* text
) {
63 // Note: code in this function is NOT async-signal safe (std::string uses
64 // malloc internally).
66 #if defined(__GLIBCXX__)
68 std::string::size_type search_from
= 0;
69 while (search_from
< text
->size()) {
70 // Look for the start of a mangled symbol, from search_from.
71 std::string::size_type mangled_start
=
72 text
->find(kMangledSymbolPrefix
, search_from
);
73 if (mangled_start
== std::string::npos
) {
74 break; // Mangled symbol not found.
77 // Look for the end of the mangled symbol.
78 std::string::size_type mangled_end
=
79 text
->find_first_not_of(kSymbolCharacters
, mangled_start
);
80 if (mangled_end
== std::string::npos
) {
81 mangled_end
= text
->size();
83 std::string mangled_symbol
=
84 text
->substr(mangled_start
, mangled_end
- mangled_start
);
86 // Try to demangle the mangled symbol candidate.
88 scoped_ptr_malloc
<char> demangled_symbol(
89 abi::__cxa_demangle(mangled_symbol
.c_str(), NULL
, 0, &status
));
90 if (status
== 0) { // Demangling is successful.
91 // Remove the mangled symbol.
92 text
->erase(mangled_start
, mangled_end
- mangled_start
);
93 // Insert the demangled symbol.
94 text
->insert(mangled_start
, demangled_symbol
.get());
95 // Next time, we'll start right after the demangled symbol we inserted.
96 search_from
= mangled_start
+ strlen(demangled_symbol
.get());
98 // Failed to demangle. Retry after the "_Z" we just found.
99 search_from
= mangled_start
+ 2;
103 #endif // defined(__GLIBCXX__)
105 #endif // !defined(USE_SYMBOLIZE)
107 class BacktraceOutputHandler
{
109 virtual void HandleOutput(const char* output
) = 0;
112 virtual ~BacktraceOutputHandler() {}
115 void OutputPointer(void* pointer
, BacktraceOutputHandler
* handler
) {
116 char buf
[1024] = { '\0' };
117 handler
->HandleOutput(" [0x");
118 internal::itoa_r(reinterpret_cast<intptr_t>(pointer
), buf
, sizeof(buf
), 16);
119 handler
->HandleOutput(buf
);
120 handler
->HandleOutput("]");
123 void ProcessBacktrace(void *const *trace
,
125 BacktraceOutputHandler
* handler
) {
126 // NOTE: This code MUST be async-signal safe (it's used by in-process
127 // stack dumping signal handler). NO malloc or stdio is allowed here.
129 #if defined(USE_SYMBOLIZE)
130 for (int i
= 0; i
< size
; ++i
) {
131 handler
->HandleOutput("\t");
133 char buf
[1024] = { '\0' };
135 // Subtract by one as return address of function may be in the next
136 // function when a function is annotated as noreturn.
137 void* address
= static_cast<char*>(trace
[i
]) - 1;
138 if (google::Symbolize(address
, buf
, sizeof(buf
)))
139 handler
->HandleOutput(buf
);
141 handler
->HandleOutput("<unknown>");
143 OutputPointer(trace
[i
], handler
);
144 handler
->HandleOutput("\n");
147 bool printed
= false;
149 // Below part is async-signal unsafe (uses malloc), so execute it only
150 // when we are not executing the signal handler.
151 if (in_signal_handler
== 0) {
152 scoped_ptr_malloc
<char*> trace_symbols(backtrace_symbols(trace
, size
));
153 if (trace_symbols
.get()) {
154 for (int i
= 0; i
< size
; ++i
) {
155 std::string trace_symbol
= trace_symbols
.get()[i
];
156 DemangleSymbols(&trace_symbol
);
157 handler
->HandleOutput(trace_symbol
.c_str());
158 handler
->HandleOutput("\n");
166 for (int i
= 0; i
< size
; ++i
) {
167 OutputPointer(trace
[i
], handler
);
168 handler
->HandleOutput("\n");
171 #endif // defined(USE_SYMBOLIZE)
174 void StackDumpSignalHandler(int signal
, siginfo_t
* info
, ucontext_t
* context
) {
175 // NOTE: This code MUST be async-signal safe.
176 // NO malloc or stdio is allowed here.
178 // Record the fact that we are in the signal handler now, so that the rest
179 // of StackTrace can behave in an async-signal-safe manner.
180 in_signal_handler
= 1;
185 char buf
[1024] = "Received signal ";
186 size_t buf_len
= strlen(buf
);
187 internal::itoa_r(signal
, buf
+ buf_len
, sizeof(buf
) - buf_len
, 10);
190 debug::StackTrace().PrintBacktrace();
192 // TODO(shess): Port to Linux.
193 #if defined(OS_MACOSX)
194 // TODO(shess): Port to 64-bit.
195 #if ARCH_CPU_X86_FAMILY && ARCH_CPU_32_BITS
198 // NOTE: Even |snprintf()| is not on the approved list for signal
199 // handlers, but buffered I/O is definitely not on the list due to
200 // potential for |malloc()|.
201 len
= static_cast<size_t>(
202 snprintf(buf
, sizeof(buf
),
203 "ax: %x, bx: %x, cx: %x, dx: %x\n",
204 context
->uc_mcontext
->__ss
.__eax
,
205 context
->uc_mcontext
->__ss
.__ebx
,
206 context
->uc_mcontext
->__ss
.__ecx
,
207 context
->uc_mcontext
->__ss
.__edx
));
208 write(STDERR_FILENO
, buf
, std::min(len
, sizeof(buf
) - 1));
210 len
= static_cast<size_t>(
211 snprintf(buf
, sizeof(buf
),
212 "di: %x, si: %x, bp: %x, sp: %x, ss: %x, flags: %x\n",
213 context
->uc_mcontext
->__ss
.__edi
,
214 context
->uc_mcontext
->__ss
.__esi
,
215 context
->uc_mcontext
->__ss
.__ebp
,
216 context
->uc_mcontext
->__ss
.__esp
,
217 context
->uc_mcontext
->__ss
.__ss
,
218 context
->uc_mcontext
->__ss
.__eflags
));
219 write(STDERR_FILENO
, buf
, std::min(len
, sizeof(buf
) - 1));
221 len
= static_cast<size_t>(
222 snprintf(buf
, sizeof(buf
),
223 "ip: %x, cs: %x, ds: %x, es: %x, fs: %x, gs: %x\n",
224 context
->uc_mcontext
->__ss
.__eip
,
225 context
->uc_mcontext
->__ss
.__cs
,
226 context
->uc_mcontext
->__ss
.__ds
,
227 context
->uc_mcontext
->__ss
.__es
,
228 context
->uc_mcontext
->__ss
.__fs
,
229 context
->uc_mcontext
->__ss
.__gs
));
230 write(STDERR_FILENO
, buf
, std::min(len
, sizeof(buf
) - 1));
231 #endif // ARCH_CPU_32_BITS
232 #endif // defined(OS_MACOSX)
236 class PrintBacktraceOutputHandler
: public BacktraceOutputHandler
{
238 PrintBacktraceOutputHandler() {}
240 virtual void HandleOutput(const char* output
) {
241 // NOTE: This code MUST be async-signal safe (it's used by in-process
242 // stack dumping signal handler). NO malloc or stdio is allowed here.
243 ignore_result(HANDLE_EINTR(write(STDERR_FILENO
, output
, strlen(output
))));
247 DISALLOW_COPY_AND_ASSIGN(PrintBacktraceOutputHandler
);
250 class StreamBacktraceOutputHandler
: public BacktraceOutputHandler
{
252 StreamBacktraceOutputHandler(std::ostream
* os
) : os_(os
) {
255 virtual void HandleOutput(const char* output
) {
262 DISALLOW_COPY_AND_ASSIGN(StreamBacktraceOutputHandler
);
265 void WarmUpBacktrace() {
266 // Warm up stack trace infrastructure. It turns out that on the first
267 // call glibc initializes some internal data structures using pthread_once,
268 // and even backtrace() can call malloc(), leading to hangs.
270 // Example stack trace snippet (with tcmalloc):
272 // #8 0x0000000000a173b5 in tc_malloc
273 // at ./third_party/tcmalloc/chromium/src/debugallocation.cc:1161
274 // #9 0x00007ffff7de7900 in _dl_map_object_deps at dl-deps.c:517
275 // #10 0x00007ffff7ded8a9 in dl_open_worker at dl-open.c:262
276 // #11 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178
277 // #12 0x00007ffff7ded31a in _dl_open (file=0x7ffff625e298 "libgcc_s.so.1")
279 // #13 0x00007ffff6215602 in do_dlopen at dl-libc.c:89
280 // #14 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178
281 // #15 0x00007ffff62156c4 in dlerror_run at dl-libc.c:48
282 // #16 __GI___libc_dlopen_mode at dl-libc.c:165
283 // #17 0x00007ffff61ef8f5 in init
284 // at ../sysdeps/x86_64/../ia64/backtrace.c:53
285 // #18 0x00007ffff6aad400 in pthread_once
286 // at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S:104
287 // #19 0x00007ffff61efa14 in __GI___backtrace
288 // at ../sysdeps/x86_64/../ia64/backtrace.c:104
289 // #20 0x0000000000752a54 in base::debug::StackTrace::StackTrace
290 // at base/debug/stack_trace_posix.cc:175
291 // #21 0x00000000007a4ae5 in
292 // base::(anonymous namespace)::StackDumpSignalHandler
293 // at base/process_util_posix.cc:172
294 // #22 <signal handler called>
295 StackTrace stack_trace
;
301 bool EnableInProcessStackDumping() {
302 // When running in an application, our code typically expects SIGPIPE
303 // to be ignored. Therefore, when testing that same code, it should run
304 // with SIGPIPE ignored as well.
305 bool success
= base::IgnoreSigPipe();
307 // Avoid hangs during backtrace initialization, see above.
310 sig_t handler
= reinterpret_cast<sig_t
>(&StackDumpSignalHandler
);
311 success
&= (signal(SIGILL
, handler
) != SIG_ERR
);
312 success
&= (signal(SIGABRT
, handler
) != SIG_ERR
);
313 success
&= (signal(SIGFPE
, handler
) != SIG_ERR
);
314 success
&= (signal(SIGBUS
, handler
) != SIG_ERR
);
315 success
&= (signal(SIGSEGV
, handler
) != SIG_ERR
);
316 success
&= (signal(SIGSYS
, handler
) != SIG_ERR
);
320 #endif // !defined(OS_IOS)
322 StackTrace::StackTrace() {
323 // NOTE: This code MUST be async-signal safe (it's used by in-process
324 // stack dumping signal handler). NO malloc or stdio is allowed here.
326 // Though the backtrace API man page does not list any possible negative
327 // return values, we take no chance.
328 count_
= std::max(backtrace(trace_
, arraysize(trace_
)), 0);
331 void StackTrace::PrintBacktrace() const {
332 // NOTE: This code MUST be async-signal safe (it's used by in-process
333 // stack dumping signal handler). NO malloc or stdio is allowed here.
335 PrintBacktraceOutputHandler handler
;
336 ProcessBacktrace(trace_
, count_
, &handler
);
339 void StackTrace::OutputToStream(std::ostream
* os
) const {
340 StreamBacktraceOutputHandler
handler(os
);
341 ProcessBacktrace(trace_
, count_
, &handler
);
346 // NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
347 char *itoa_r(intptr_t i
, char *buf
, size_t sz
, int base
) {
348 // Make sure we can write at least one NUL byte.
353 if (base
< 2 || base
> 16) {
362 // Handle negative numbers (only for base 10).
363 if (i
< 0 && base
== 10) {
366 // Make sure we can write the '-' character.
374 // Loop until we have converted the entire number. Output at least one
375 // character (i.e. '0').
378 // Make sure there is still enough space left in our output buffer.
384 // Output the next digit.
385 *ptr
++ = "0123456789abcdef"[j
% base
];
389 // Terminate the output with a NUL character.
392 // Conversion to ASCII actually resulted in the digits being in reverse
393 // order. We can't easily generate them in forward order, as we can't tell
394 // the number of characters needed until we are done converting.
395 // So, now, we reverse the string (except for the possible "-" sign).
396 while (--ptr
> start
) {
404 } // namespace internal