stack_trace_posix.cc revision 23730a6e56a168d1879203e4b3819bb36e3d8f1f
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.
4
5#include "base/debug/stack_trace.h"
6
7#include <errno.h>
8#include <execinfo.h>
9#include <fcntl.h>
10#include <signal.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <sys/param.h>
14#include <sys/stat.h>
15#include <sys/types.h>
16#include <unistd.h>
17
18#include <ostream>
19
20#if defined(__GLIBCXX__)
21#include <cxxabi.h>
22#endif
23
24#if defined(OS_MACOSX)
25#include <AvailabilityMacros.h>
26#endif
27
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/numerics/safe_conversions.h"
33#include "base/posix/eintr_wrapper.h"
34#include "base/strings/string_number_conversions.h"
35
36#if defined(USE_SYMBOLIZE)
37#include "base/third_party/symbolize/symbolize.h"
38#endif
39
40namespace base {
41namespace debug {
42
43namespace {
44
45volatile sig_atomic_t in_signal_handler = 0;
46
47#if !defined(USE_SYMBOLIZE) && defined(__GLIBCXX__)
48// The prefix used for mangled symbols, per the Itanium C++ ABI:
49// http://www.codesourcery.com/cxx-abi/abi.html#mangling
50const char kMangledSymbolPrefix[] = "_Z";
51
52// Characters that can be used for symbols, generated by Ruby:
53// (('a'..'z').to_a+('A'..'Z').to_a+('0'..'9').to_a + ['_']).join
54const char kSymbolCharacters[] =
55    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
56#endif  // !defined(USE_SYMBOLIZE) && defined(__GLIBCXX__)
57
58#if !defined(USE_SYMBOLIZE)
59// Demangles C++ symbols in the given text. Example:
60//
61// "out/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]"
62// =>
63// "out/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x817778c]"
64void DemangleSymbols(std::string* text) {
65  // Note: code in this function is NOT async-signal safe (std::string uses
66  // malloc internally).
67
68#if defined(__GLIBCXX__)
69
70  std::string::size_type search_from = 0;
71  while (search_from < text->size()) {
72    // Look for the start of a mangled symbol, from search_from.
73    std::string::size_type mangled_start =
74        text->find(kMangledSymbolPrefix, search_from);
75    if (mangled_start == std::string::npos) {
76      break;  // Mangled symbol not found.
77    }
78
79    // Look for the end of the mangled symbol.
80    std::string::size_type mangled_end =
81        text->find_first_not_of(kSymbolCharacters, mangled_start);
82    if (mangled_end == std::string::npos) {
83      mangled_end = text->size();
84    }
85    std::string mangled_symbol =
86        text->substr(mangled_start, mangled_end - mangled_start);
87
88    // Try to demangle the mangled symbol candidate.
89    int status = 0;
90    scoped_ptr<char, base::FreeDeleter> demangled_symbol(
91        abi::__cxa_demangle(mangled_symbol.c_str(), NULL, 0, &status));
92    if (status == 0) {  // Demangling is successful.
93      // Remove the mangled symbol.
94      text->erase(mangled_start, mangled_end - mangled_start);
95      // Insert the demangled symbol.
96      text->insert(mangled_start, demangled_symbol.get());
97      // Next time, we'll start right after the demangled symbol we inserted.
98      search_from = mangled_start + strlen(demangled_symbol.get());
99    } else {
100      // Failed to demangle.  Retry after the "_Z" we just found.
101      search_from = mangled_start + 2;
102    }
103  }
104
105#endif  // defined(__GLIBCXX__)
106}
107#endif  // !defined(USE_SYMBOLIZE)
108
109class BacktraceOutputHandler {
110 public:
111  virtual void HandleOutput(const char* output) = 0;
112
113 protected:
114  virtual ~BacktraceOutputHandler() {}
115};
116
117void OutputPointer(void* pointer, BacktraceOutputHandler* handler) {
118  char buf[1024] = { '\0' };
119  handler->HandleOutput(" [0x");
120  internal::itoa_r(reinterpret_cast<intptr_t>(pointer),
121                   buf, sizeof(buf), 16, 12);
122  handler->HandleOutput(buf);
123  handler->HandleOutput("]");
124}
125
126void ProcessBacktrace(void *const *trace,
127                      size_t size,
128                      BacktraceOutputHandler* handler) {
129  // NOTE: This code MUST be async-signal safe (it's used by in-process
130  // stack dumping signal handler). NO malloc or stdio is allowed here.
131
132#if defined(USE_SYMBOLIZE)
133  for (size_t i = 0; i < size; ++i) {
134    OutputPointer(trace[i], handler);
135    handler->HandleOutput(" ");
136
137    char buf[1024] = { '\0' };
138
139    // Subtract by one as return address of function may be in the next
140    // function when a function is annotated as noreturn.
141    void* address = static_cast<char*>(trace[i]) - 1;
142    if (google::Symbolize(address, buf, sizeof(buf)))
143      handler->HandleOutput(buf);
144    else
145      handler->HandleOutput("<unknown>");
146
147    handler->HandleOutput("\n");
148  }
149#else
150  bool printed = false;
151
152  // Below part is async-signal unsafe (uses malloc), so execute it only
153  // when we are not executing the signal handler.
154  if (in_signal_handler == 0) {
155    scoped_ptr<char*, FreeDeleter>
156        trace_symbols(backtrace_symbols(trace, size));
157    if (trace_symbols.get()) {
158      for (size_t i = 0; i < size; ++i) {
159        std::string trace_symbol = trace_symbols.get()[i];
160        DemangleSymbols(&trace_symbol);
161        handler->HandleOutput(trace_symbol.c_str());
162        handler->HandleOutput("\n");
163      }
164
165      printed = true;
166    }
167  }
168
169  if (!printed) {
170    for (size_t i = 0; i < size; ++i) {
171      OutputPointer(trace[i], handler);
172      handler->HandleOutput("\n");
173    }
174  }
175#endif  // defined(USE_SYMBOLIZE)
176}
177
178void PrintToStderr(const char* output) {
179  // NOTE: This code MUST be async-signal safe (it's used by in-process
180  // stack dumping signal handler). NO malloc or stdio is allowed here.
181  ignore_result(HANDLE_EINTR(write(STDERR_FILENO, output, strlen(output))));
182}
183
184void StackDumpSignalHandler(int signal, siginfo_t* info, void* void_context) {
185  // NOTE: This code MUST be async-signal safe.
186  // NO malloc or stdio is allowed here.
187
188  // Record the fact that we are in the signal handler now, so that the rest
189  // of StackTrace can behave in an async-signal-safe manner.
190  in_signal_handler = 1;
191
192  if (BeingDebugged())
193    BreakDebugger();
194
195  PrintToStderr("Received signal ");
196  char buf[1024] = { 0 };
197  internal::itoa_r(signal, buf, sizeof(buf), 10, 0);
198  PrintToStderr(buf);
199  if (signal == SIGBUS) {
200    if (info->si_code == BUS_ADRALN)
201      PrintToStderr(" BUS_ADRALN ");
202    else if (info->si_code == BUS_ADRERR)
203      PrintToStderr(" BUS_ADRERR ");
204    else if (info->si_code == BUS_OBJERR)
205      PrintToStderr(" BUS_OBJERR ");
206    else
207      PrintToStderr(" <unknown> ");
208  } else if (signal == SIGFPE) {
209    if (info->si_code == FPE_FLTDIV)
210      PrintToStderr(" FPE_FLTDIV ");
211    else if (info->si_code == FPE_FLTINV)
212      PrintToStderr(" FPE_FLTINV ");
213    else if (info->si_code == FPE_FLTOVF)
214      PrintToStderr(" FPE_FLTOVF ");
215    else if (info->si_code == FPE_FLTRES)
216      PrintToStderr(" FPE_FLTRES ");
217    else if (info->si_code == FPE_FLTSUB)
218      PrintToStderr(" FPE_FLTSUB ");
219    else if (info->si_code == FPE_FLTUND)
220      PrintToStderr(" FPE_FLTUND ");
221    else if (info->si_code == FPE_INTDIV)
222      PrintToStderr(" FPE_INTDIV ");
223    else if (info->si_code == FPE_INTOVF)
224      PrintToStderr(" FPE_INTOVF ");
225    else
226      PrintToStderr(" <unknown> ");
227  } else if (signal == SIGILL) {
228    if (info->si_code == ILL_BADSTK)
229      PrintToStderr(" ILL_BADSTK ");
230    else if (info->si_code == ILL_COPROC)
231      PrintToStderr(" ILL_COPROC ");
232    else if (info->si_code == ILL_ILLOPN)
233      PrintToStderr(" ILL_ILLOPN ");
234    else if (info->si_code == ILL_ILLADR)
235      PrintToStderr(" ILL_ILLADR ");
236    else if (info->si_code == ILL_ILLTRP)
237      PrintToStderr(" ILL_ILLTRP ");
238    else if (info->si_code == ILL_PRVOPC)
239      PrintToStderr(" ILL_PRVOPC ");
240    else if (info->si_code == ILL_PRVREG)
241      PrintToStderr(" ILL_PRVREG ");
242    else
243      PrintToStderr(" <unknown> ");
244  } else if (signal == SIGSEGV) {
245    if (info->si_code == SEGV_MAPERR)
246      PrintToStderr(" SEGV_MAPERR ");
247    else if (info->si_code == SEGV_ACCERR)
248      PrintToStderr(" SEGV_ACCERR ");
249    else
250      PrintToStderr(" <unknown> ");
251  }
252  if (signal == SIGBUS || signal == SIGFPE ||
253      signal == SIGILL || signal == SIGSEGV) {
254    internal::itoa_r(reinterpret_cast<intptr_t>(info->si_addr),
255                     buf, sizeof(buf), 16, 12);
256    PrintToStderr(buf);
257  }
258  PrintToStderr("\n");
259
260  debug::StackTrace().Print();
261
262#if defined(OS_LINUX)
263#if ARCH_CPU_X86_FAMILY
264  ucontext_t* context = reinterpret_cast<ucontext_t*>(void_context);
265  const struct {
266    const char* label;
267    greg_t value;
268  } registers[] = {
269#if ARCH_CPU_32_BITS
270    { "  gs: ", context->uc_mcontext.gregs[REG_GS] },
271    { "  fs: ", context->uc_mcontext.gregs[REG_FS] },
272    { "  es: ", context->uc_mcontext.gregs[REG_ES] },
273    { "  ds: ", context->uc_mcontext.gregs[REG_DS] },
274    { " edi: ", context->uc_mcontext.gregs[REG_EDI] },
275    { " esi: ", context->uc_mcontext.gregs[REG_ESI] },
276    { " ebp: ", context->uc_mcontext.gregs[REG_EBP] },
277    { " esp: ", context->uc_mcontext.gregs[REG_ESP] },
278    { " ebx: ", context->uc_mcontext.gregs[REG_EBX] },
279    { " edx: ", context->uc_mcontext.gregs[REG_EDX] },
280    { " ecx: ", context->uc_mcontext.gregs[REG_ECX] },
281    { " eax: ", context->uc_mcontext.gregs[REG_EAX] },
282    { " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] },
283    { " err: ", context->uc_mcontext.gregs[REG_ERR] },
284    { "  ip: ", context->uc_mcontext.gregs[REG_EIP] },
285    { "  cs: ", context->uc_mcontext.gregs[REG_CS] },
286    { " efl: ", context->uc_mcontext.gregs[REG_EFL] },
287    { " usp: ", context->uc_mcontext.gregs[REG_UESP] },
288    { "  ss: ", context->uc_mcontext.gregs[REG_SS] },
289#elif ARCH_CPU_64_BITS
290    { "  r8: ", context->uc_mcontext.gregs[REG_R8] },
291    { "  r9: ", context->uc_mcontext.gregs[REG_R9] },
292    { " r10: ", context->uc_mcontext.gregs[REG_R10] },
293    { " r11: ", context->uc_mcontext.gregs[REG_R11] },
294    { " r12: ", context->uc_mcontext.gregs[REG_R12] },
295    { " r13: ", context->uc_mcontext.gregs[REG_R13] },
296    { " r14: ", context->uc_mcontext.gregs[REG_R14] },
297    { " r15: ", context->uc_mcontext.gregs[REG_R15] },
298    { "  di: ", context->uc_mcontext.gregs[REG_RDI] },
299    { "  si: ", context->uc_mcontext.gregs[REG_RSI] },
300    { "  bp: ", context->uc_mcontext.gregs[REG_RBP] },
301    { "  bx: ", context->uc_mcontext.gregs[REG_RBX] },
302    { "  dx: ", context->uc_mcontext.gregs[REG_RDX] },
303    { "  ax: ", context->uc_mcontext.gregs[REG_RAX] },
304    { "  cx: ", context->uc_mcontext.gregs[REG_RCX] },
305    { "  sp: ", context->uc_mcontext.gregs[REG_RSP] },
306    { "  ip: ", context->uc_mcontext.gregs[REG_RIP] },
307    { " efl: ", context->uc_mcontext.gregs[REG_EFL] },
308    { " cgf: ", context->uc_mcontext.gregs[REG_CSGSFS] },
309    { " erf: ", context->uc_mcontext.gregs[REG_ERR] },
310    { " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] },
311    { " msk: ", context->uc_mcontext.gregs[REG_OLDMASK] },
312    { " cr2: ", context->uc_mcontext.gregs[REG_CR2] },
313#endif
314  };
315
316#if ARCH_CPU_32_BITS
317  const int kRegisterPadding = 8;
318#elif ARCH_CPU_64_BITS
319  const int kRegisterPadding = 16;
320#endif
321
322  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(registers); i++) {
323    PrintToStderr(registers[i].label);
324    internal::itoa_r(registers[i].value, buf, sizeof(buf),
325                     16, kRegisterPadding);
326    PrintToStderr(buf);
327
328    if ((i + 1) % 4 == 0)
329      PrintToStderr("\n");
330  }
331  PrintToStderr("\n");
332#endif
333#elif defined(OS_MACOSX)
334  // TODO(shess): Port to 64-bit, and ARM architecture (32 and 64-bit).
335#if ARCH_CPU_X86_FAMILY && ARCH_CPU_32_BITS
336  ucontext_t* context = reinterpret_cast<ucontext_t*>(void_context);
337  size_t len;
338
339  // NOTE: Even |snprintf()| is not on the approved list for signal
340  // handlers, but buffered I/O is definitely not on the list due to
341  // potential for |malloc()|.
342  len = static_cast<size_t>(
343      snprintf(buf, sizeof(buf),
344               "ax: %x, bx: %x, cx: %x, dx: %x\n",
345               context->uc_mcontext->__ss.__eax,
346               context->uc_mcontext->__ss.__ebx,
347               context->uc_mcontext->__ss.__ecx,
348               context->uc_mcontext->__ss.__edx));
349  write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
350
351  len = static_cast<size_t>(
352      snprintf(buf, sizeof(buf),
353               "di: %x, si: %x, bp: %x, sp: %x, ss: %x, flags: %x\n",
354               context->uc_mcontext->__ss.__edi,
355               context->uc_mcontext->__ss.__esi,
356               context->uc_mcontext->__ss.__ebp,
357               context->uc_mcontext->__ss.__esp,
358               context->uc_mcontext->__ss.__ss,
359               context->uc_mcontext->__ss.__eflags));
360  write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
361
362  len = static_cast<size_t>(
363      snprintf(buf, sizeof(buf),
364               "ip: %x, cs: %x, ds: %x, es: %x, fs: %x, gs: %x\n",
365               context->uc_mcontext->__ss.__eip,
366               context->uc_mcontext->__ss.__cs,
367               context->uc_mcontext->__ss.__ds,
368               context->uc_mcontext->__ss.__es,
369               context->uc_mcontext->__ss.__fs,
370               context->uc_mcontext->__ss.__gs));
371  write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
372#endif  // ARCH_CPU_32_BITS
373#endif  // defined(OS_MACOSX)
374  _exit(1);
375}
376
377class PrintBacktraceOutputHandler : public BacktraceOutputHandler {
378 public:
379  PrintBacktraceOutputHandler() {}
380
381  virtual void HandleOutput(const char* output) OVERRIDE {
382    // NOTE: This code MUST be async-signal safe (it's used by in-process
383    // stack dumping signal handler). NO malloc or stdio is allowed here.
384    PrintToStderr(output);
385  }
386
387 private:
388  DISALLOW_COPY_AND_ASSIGN(PrintBacktraceOutputHandler);
389};
390
391class StreamBacktraceOutputHandler : public BacktraceOutputHandler {
392 public:
393  explicit StreamBacktraceOutputHandler(std::ostream* os) : os_(os) {
394  }
395
396  virtual void HandleOutput(const char* output) OVERRIDE {
397    (*os_) << output;
398  }
399
400 private:
401  std::ostream* os_;
402
403  DISALLOW_COPY_AND_ASSIGN(StreamBacktraceOutputHandler);
404};
405
406void WarmUpBacktrace() {
407  // Warm up stack trace infrastructure. It turns out that on the first
408  // call glibc initializes some internal data structures using pthread_once,
409  // and even backtrace() can call malloc(), leading to hangs.
410  //
411  // Example stack trace snippet (with tcmalloc):
412  //
413  // #8  0x0000000000a173b5 in tc_malloc
414  //             at ./third_party/tcmalloc/chromium/src/debugallocation.cc:1161
415  // #9  0x00007ffff7de7900 in _dl_map_object_deps at dl-deps.c:517
416  // #10 0x00007ffff7ded8a9 in dl_open_worker at dl-open.c:262
417  // #11 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178
418  // #12 0x00007ffff7ded31a in _dl_open (file=0x7ffff625e298 "libgcc_s.so.1")
419  //             at dl-open.c:639
420  // #13 0x00007ffff6215602 in do_dlopen at dl-libc.c:89
421  // #14 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178
422  // #15 0x00007ffff62156c4 in dlerror_run at dl-libc.c:48
423  // #16 __GI___libc_dlopen_mode at dl-libc.c:165
424  // #17 0x00007ffff61ef8f5 in init
425  //             at ../sysdeps/x86_64/../ia64/backtrace.c:53
426  // #18 0x00007ffff6aad400 in pthread_once
427  //             at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S:104
428  // #19 0x00007ffff61efa14 in __GI___backtrace
429  //             at ../sysdeps/x86_64/../ia64/backtrace.c:104
430  // #20 0x0000000000752a54 in base::debug::StackTrace::StackTrace
431  //             at base/debug/stack_trace_posix.cc:175
432  // #21 0x00000000007a4ae5 in
433  //             base::(anonymous namespace)::StackDumpSignalHandler
434  //             at base/process_util_posix.cc:172
435  // #22 <signal handler called>
436  StackTrace stack_trace;
437}
438
439}  // namespace
440
441bool EnableInProcessStackDumping() {
442  // When running in an application, our code typically expects SIGPIPE
443  // to be ignored.  Therefore, when testing that same code, it should run
444  // with SIGPIPE ignored as well.
445  struct sigaction sigpipe_action;
446  memset(&sigpipe_action, 0, sizeof(sigpipe_action));
447  sigpipe_action.sa_handler = SIG_IGN;
448  sigemptyset(&sigpipe_action.sa_mask);
449  bool success = (sigaction(SIGPIPE, &sigpipe_action, NULL) == 0);
450
451  // Avoid hangs during backtrace initialization, see above.
452  WarmUpBacktrace();
453
454  struct sigaction action;
455  memset(&action, 0, sizeof(action));
456  action.sa_flags = SA_RESETHAND | SA_SIGINFO;
457  action.sa_sigaction = &StackDumpSignalHandler;
458  sigemptyset(&action.sa_mask);
459
460  success &= (sigaction(SIGILL, &action, NULL) == 0);
461  success &= (sigaction(SIGABRT, &action, NULL) == 0);
462  success &= (sigaction(SIGFPE, &action, NULL) == 0);
463  success &= (sigaction(SIGBUS, &action, NULL) == 0);
464  success &= (sigaction(SIGSEGV, &action, NULL) == 0);
465  success &= (sigaction(SIGSYS, &action, NULL) == 0);
466
467  return success;
468}
469
470StackTrace::StackTrace() {
471  // NOTE: This code MUST be async-signal safe (it's used by in-process
472  // stack dumping signal handler). NO malloc or stdio is allowed here.
473
474  // Though the backtrace API man page does not list any possible negative
475  // return values, we take no chance.
476  count_ = base::saturated_cast<size_t>(backtrace(trace_, arraysize(trace_)));
477}
478
479void StackTrace::Print() const {
480  // NOTE: This code MUST be async-signal safe (it's used by in-process
481  // stack dumping signal handler). NO malloc or stdio is allowed here.
482
483  PrintBacktraceOutputHandler handler;
484  ProcessBacktrace(trace_, count_, &handler);
485}
486
487void StackTrace::OutputToStream(std::ostream* os) const {
488  StreamBacktraceOutputHandler handler(os);
489  ProcessBacktrace(trace_, count_, &handler);
490}
491
492namespace internal {
493
494// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
495char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
496  // Make sure we can write at least one NUL byte.
497  size_t n = 1;
498  if (n > sz)
499    return NULL;
500
501  if (base < 2 || base > 16) {
502    buf[0] = '\000';
503    return NULL;
504  }
505
506  char *start = buf;
507
508  uintptr_t j = i;
509
510  // Handle negative numbers (only for base 10).
511  if (i < 0 && base == 10) {
512    j = -i;
513
514    // Make sure we can write the '-' character.
515    if (++n > sz) {
516      buf[0] = '\000';
517      return NULL;
518    }
519    *start++ = '-';
520  }
521
522  // Loop until we have converted the entire number. Output at least one
523  // character (i.e. '0').
524  char *ptr = start;
525  do {
526    // Make sure there is still enough space left in our output buffer.
527    if (++n > sz) {
528      buf[0] = '\000';
529      return NULL;
530    }
531
532    // Output the next digit.
533    *ptr++ = "0123456789abcdef"[j % base];
534    j /= base;
535
536    if (padding > 0)
537      padding--;
538  } while (j > 0 || padding > 0);
539
540  // Terminate the output with a NUL character.
541  *ptr = '\000';
542
543  // Conversion to ASCII actually resulted in the digits being in reverse
544  // order. We can't easily generate them in forward order, as we can't tell
545  // the number of characters needed until we are done converting.
546  // So, now, we reverse the string (except for the possible "-" sign).
547  while (--ptr > start) {
548    char ch = *ptr;
549    *ptr = *start;
550    *start++ = ch;
551  }
552  return buf;
553}
554
555}  // namespace internal
556
557}  // namespace debug
558}  // namespace base
559