Home | History | Annotate | Download | only in debug
      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 <fcntl.h>
      9 #include <signal.h>
     10 #include <stddef.h>
     11 #include <stdint.h>
     12 #include <stdio.h>
     13 #include <stdlib.h>
     14 #include <sys/param.h>
     15 #include <sys/stat.h>
     16 #include <sys/types.h>
     17 #include <unistd.h>
     18 
     19 #include <map>
     20 #include <ostream>
     21 #include <string>
     22 #include <vector>
     23 
     24 #if defined(__GLIBCXX__)
     25 #include <cxxabi.h>
     26 #endif
     27 #if !defined(__UCLIBC__)
     28 #include <execinfo.h>
     29 #endif
     30 
     31 #if defined(OS_MACOSX)
     32 #include <AvailabilityMacros.h>
     33 #endif
     34 
     35 #include "base/debug/debugger.h"
     36 #include "base/debug/proc_maps_linux.h"
     37 #include "base/logging.h"
     38 #include "base/macros.h"
     39 #include "base/memory/scoped_ptr.h"
     40 #include "base/memory/singleton.h"
     41 #include "base/numerics/safe_conversions.h"
     42 #include "base/posix/eintr_wrapper.h"
     43 #include "base/strings/string_number_conversions.h"
     44 #include "build/build_config.h"
     45 
     46 #if defined(USE_SYMBOLIZE)
     47 #error "symbolize support was removed from libchrome"
     48 #endif
     49 
     50 namespace base {
     51 namespace debug {
     52 
     53 namespace {
     54 
     55 volatile sig_atomic_t in_signal_handler = 0;
     56 
     57 #if !defined(USE_SYMBOLIZE) && defined(__GLIBCXX__)
     58 // The prefix used for mangled symbols, per the Itanium C++ ABI:
     59 // http://www.codesourcery.com/cxx-abi/abi.html#mangling
     60 const char kMangledSymbolPrefix[] = "_Z";
     61 
     62 // Characters that can be used for symbols, generated by Ruby:
     63 // (('a'..'z').to_a+('A'..'Z').to_a+('0'..'9').to_a + ['_']).join
     64 const char kSymbolCharacters[] =
     65     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
     66 #endif  // !defined(USE_SYMBOLIZE) && defined(__GLIBCXX__)
     67 
     68 #if !defined(USE_SYMBOLIZE)
     69 // Demangles C++ symbols in the given text. Example:
     70 //
     71 // "out/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]"
     72 // =>
     73 // "out/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x817778c]"
     74 #if defined(__GLIBCXX__) && !defined(__UCLIBC__)
     75 void DemangleSymbols(std::string* text) {
     76   // Note: code in this function is NOT async-signal safe (std::string uses
     77   // malloc internally).
     78   std::string::size_type search_from = 0;
     79   while (search_from < text->size()) {
     80     // Look for the start of a mangled symbol, from search_from.
     81     std::string::size_type mangled_start =
     82         text->find(kMangledSymbolPrefix, search_from);
     83     if (mangled_start == std::string::npos) {
     84       break;  // Mangled symbol not found.
     85     }
     86 
     87     // Look for the end of the mangled symbol.
     88     std::string::size_type mangled_end =
     89         text->find_first_not_of(kSymbolCharacters, mangled_start);
     90     if (mangled_end == std::string::npos) {
     91       mangled_end = text->size();
     92     }
     93     std::string mangled_symbol =
     94         text->substr(mangled_start, mangled_end - mangled_start);
     95 
     96     // Try to demangle the mangled symbol candidate.
     97     int status = 0;
     98     scoped_ptr<char, base::FreeDeleter> demangled_symbol(
     99         abi::__cxa_demangle(mangled_symbol.c_str(), NULL, 0, &status));
    100     if (status == 0) {  // Demangling is successful.
    101       // Remove the mangled symbol.
    102       text->erase(mangled_start, mangled_end - mangled_start);
    103       // Insert the demangled symbol.
    104       text->insert(mangled_start, demangled_symbol.get());
    105       // Next time, we'll start right after the demangled symbol we inserted.
    106       search_from = mangled_start + strlen(demangled_symbol.get());
    107     } else {
    108       // Failed to demangle.  Retry after the "_Z" we just found.
    109       search_from = mangled_start + 2;
    110     }
    111   }
    112 }
    113 #elif !defined(__UCLIBC__)
    114 void DemangleSymbols(std::string* /* text */) {}
    115 #endif  // defined(__GLIBCXX__) && !defined(__UCLIBC__)
    116 
    117 #endif  // !defined(USE_SYMBOLIZE)
    118 
    119 class BacktraceOutputHandler {
    120  public:
    121   virtual void HandleOutput(const char* output) = 0;
    122 
    123  protected:
    124   virtual ~BacktraceOutputHandler() {}
    125 };
    126 
    127 #if defined(USE_SYMBOLIZE) || !defined(__UCLIBC__)
    128 void OutputPointer(void* pointer, BacktraceOutputHandler* handler) {
    129   // This should be more than enough to store a 64-bit number in hex:
    130   // 16 hex digits + 1 for null-terminator.
    131   char buf[17] = { '\0' };
    132   handler->HandleOutput("0x");
    133   internal::itoa_r(reinterpret_cast<intptr_t>(pointer),
    134                    buf, sizeof(buf), 16, 12);
    135   handler->HandleOutput(buf);
    136 }
    137 #endif  // defined(USE_SYMBOLIZE) ||  !defined(__UCLIBC__)
    138 
    139 #if defined(USE_SYMBOLIZE)
    140 void OutputFrameId(intptr_t frame_id, BacktraceOutputHandler* handler) {
    141   // Max unsigned 64-bit number in decimal has 20 digits (18446744073709551615).
    142   // Hence, 30 digits should be more than enough to represent it in decimal
    143   // (including the null-terminator).
    144   char buf[30] = { '\0' };
    145   handler->HandleOutput("#");
    146   internal::itoa_r(frame_id, buf, sizeof(buf), 10, 1);
    147   handler->HandleOutput(buf);
    148 }
    149 #endif  // defined(USE_SYMBOLIZE)
    150 
    151 #if !defined(__UCLIBC__)
    152 void ProcessBacktrace(void *const * trace,
    153                       size_t size,
    154                       BacktraceOutputHandler* handler) {
    155   (void)trace;  // unused based on build context below.
    156   (void)size;  // unusud based on build context below.
    157   (void)handler;  // unused based on build context below.
    158   // NOTE: This code MUST be async-signal safe (it's used by in-process
    159   // stack dumping signal handler). NO malloc or stdio is allowed here.
    160 
    161 #if defined(USE_SYMBOLIZE)
    162   for (size_t i = 0; i < size; ++i) {
    163     OutputFrameId(i, handler);
    164     handler->HandleOutput(" ");
    165     OutputPointer(trace[i], handler);
    166     handler->HandleOutput(" ");
    167 
    168     char buf[1024] = { '\0' };
    169 
    170     // Subtract by one as return address of function may be in the next
    171     // function when a function is annotated as noreturn.
    172     void* address = static_cast<char*>(trace[i]) - 1;
    173     if (google::Symbolize(address, buf, sizeof(buf)))
    174       handler->HandleOutput(buf);
    175     else
    176       handler->HandleOutput("<unknown>");
    177 
    178     handler->HandleOutput("\n");
    179   }
    180 #elif !defined(__UCLIBC__)
    181   bool printed = false;
    182 
    183   // Below part is async-signal unsafe (uses malloc), so execute it only
    184   // when we are not executing the signal handler.
    185   if (in_signal_handler == 0) {
    186     scoped_ptr<char*, FreeDeleter>
    187         trace_symbols(backtrace_symbols(trace, size));
    188     if (trace_symbols.get()) {
    189       for (size_t i = 0; i < size; ++i) {
    190         std::string trace_symbol = trace_symbols.get()[i];
    191         DemangleSymbols(&trace_symbol);
    192         handler->HandleOutput(trace_symbol.c_str());
    193         handler->HandleOutput("\n");
    194       }
    195 
    196       printed = true;
    197     }
    198   }
    199 
    200   if (!printed) {
    201     for (size_t i = 0; i < size; ++i) {
    202       handler->HandleOutput(" [");
    203       OutputPointer(trace[i], handler);
    204       handler->HandleOutput("]\n");
    205     }
    206   }
    207 #endif  // defined(USE_SYMBOLIZE)
    208 }
    209 #endif  // !defined(__UCLIBC__)
    210 
    211 void PrintToStderr(const char* output) {
    212   // NOTE: This code MUST be async-signal safe (it's used by in-process
    213   // stack dumping signal handler). NO malloc or stdio is allowed here.
    214   ignore_result(HANDLE_EINTR(write(STDERR_FILENO, output, strlen(output))));
    215 }
    216 
    217 void StackDumpSignalHandler(int signal,
    218                             siginfo_t* info,
    219                             void* void_context) {
    220   (void)void_context;  // unused depending on build context
    221   // NOTE: This code MUST be async-signal safe.
    222   // NO malloc or stdio is allowed here.
    223 
    224   // Record the fact that we are in the signal handler now, so that the rest
    225   // of StackTrace can behave in an async-signal-safe manner.
    226   in_signal_handler = 1;
    227 
    228   if (BeingDebugged())
    229     BreakDebugger();
    230 
    231   PrintToStderr("Received signal ");
    232   char buf[1024] = { 0 };
    233   internal::itoa_r(signal, buf, sizeof(buf), 10, 0);
    234   PrintToStderr(buf);
    235   if (signal == SIGBUS) {
    236     if (info->si_code == BUS_ADRALN)
    237       PrintToStderr(" BUS_ADRALN ");
    238     else if (info->si_code == BUS_ADRERR)
    239       PrintToStderr(" BUS_ADRERR ");
    240     else if (info->si_code == BUS_OBJERR)
    241       PrintToStderr(" BUS_OBJERR ");
    242     else
    243       PrintToStderr(" <unknown> ");
    244   } else if (signal == SIGFPE) {
    245     if (info->si_code == FPE_FLTDIV)
    246       PrintToStderr(" FPE_FLTDIV ");
    247     else if (info->si_code == FPE_FLTINV)
    248       PrintToStderr(" FPE_FLTINV ");
    249     else if (info->si_code == FPE_FLTOVF)
    250       PrintToStderr(" FPE_FLTOVF ");
    251     else if (info->si_code == FPE_FLTRES)
    252       PrintToStderr(" FPE_FLTRES ");
    253     else if (info->si_code == FPE_FLTSUB)
    254       PrintToStderr(" FPE_FLTSUB ");
    255     else if (info->si_code == FPE_FLTUND)
    256       PrintToStderr(" FPE_FLTUND ");
    257     else if (info->si_code == FPE_INTDIV)
    258       PrintToStderr(" FPE_INTDIV ");
    259     else if (info->si_code == FPE_INTOVF)
    260       PrintToStderr(" FPE_INTOVF ");
    261     else
    262       PrintToStderr(" <unknown> ");
    263   } else if (signal == SIGILL) {
    264     if (info->si_code == ILL_BADSTK)
    265       PrintToStderr(" ILL_BADSTK ");
    266     else if (info->si_code == ILL_COPROC)
    267       PrintToStderr(" ILL_COPROC ");
    268     else if (info->si_code == ILL_ILLOPN)
    269       PrintToStderr(" ILL_ILLOPN ");
    270     else if (info->si_code == ILL_ILLADR)
    271       PrintToStderr(" ILL_ILLADR ");
    272     else if (info->si_code == ILL_ILLTRP)
    273       PrintToStderr(" ILL_ILLTRP ");
    274     else if (info->si_code == ILL_PRVOPC)
    275       PrintToStderr(" ILL_PRVOPC ");
    276     else if (info->si_code == ILL_PRVREG)
    277       PrintToStderr(" ILL_PRVREG ");
    278     else
    279       PrintToStderr(" <unknown> ");
    280   } else if (signal == SIGSEGV) {
    281     if (info->si_code == SEGV_MAPERR)
    282       PrintToStderr(" SEGV_MAPERR ");
    283     else if (info->si_code == SEGV_ACCERR)
    284       PrintToStderr(" SEGV_ACCERR ");
    285     else
    286       PrintToStderr(" <unknown> ");
    287   }
    288   if (signal == SIGBUS || signal == SIGFPE ||
    289       signal == SIGILL || signal == SIGSEGV) {
    290     internal::itoa_r(reinterpret_cast<intptr_t>(info->si_addr),
    291                      buf, sizeof(buf), 16, 12);
    292     PrintToStderr(buf);
    293   }
    294   PrintToStderr("\n");
    295 
    296 #if defined(CFI_ENFORCEMENT)
    297   if (signal == SIGILL && info->si_code == ILL_ILLOPN) {
    298     PrintToStderr(
    299         "CFI: Most likely a control flow integrity violation; for more "
    300         "information see:\n");
    301     PrintToStderr(
    302         "https://www.chromium.org/developers/testing/control-flow-integrity\n");
    303   }
    304 #endif
    305 
    306   debug::StackTrace().Print();
    307 
    308 #if defined(OS_LINUX)
    309 #if ARCH_CPU_X86_FAMILY
    310   ucontext_t* context = reinterpret_cast<ucontext_t*>(void_context);
    311   const struct {
    312     const char* label;
    313     greg_t value;
    314   } registers[] = {
    315 #if ARCH_CPU_32_BITS
    316     { "  gs: ", context->uc_mcontext.gregs[REG_GS] },
    317     { "  fs: ", context->uc_mcontext.gregs[REG_FS] },
    318     { "  es: ", context->uc_mcontext.gregs[REG_ES] },
    319     { "  ds: ", context->uc_mcontext.gregs[REG_DS] },
    320     { " edi: ", context->uc_mcontext.gregs[REG_EDI] },
    321     { " esi: ", context->uc_mcontext.gregs[REG_ESI] },
    322     { " ebp: ", context->uc_mcontext.gregs[REG_EBP] },
    323     { " esp: ", context->uc_mcontext.gregs[REG_ESP] },
    324     { " ebx: ", context->uc_mcontext.gregs[REG_EBX] },
    325     { " edx: ", context->uc_mcontext.gregs[REG_EDX] },
    326     { " ecx: ", context->uc_mcontext.gregs[REG_ECX] },
    327     { " eax: ", context->uc_mcontext.gregs[REG_EAX] },
    328     { " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] },
    329     { " err: ", context->uc_mcontext.gregs[REG_ERR] },
    330     { "  ip: ", context->uc_mcontext.gregs[REG_EIP] },
    331     { "  cs: ", context->uc_mcontext.gregs[REG_CS] },
    332     { " efl: ", context->uc_mcontext.gregs[REG_EFL] },
    333     { " usp: ", context->uc_mcontext.gregs[REG_UESP] },
    334     { "  ss: ", context->uc_mcontext.gregs[REG_SS] },
    335 #elif ARCH_CPU_64_BITS
    336     { "  r8: ", context->uc_mcontext.gregs[REG_R8] },
    337     { "  r9: ", context->uc_mcontext.gregs[REG_R9] },
    338     { " r10: ", context->uc_mcontext.gregs[REG_R10] },
    339     { " r11: ", context->uc_mcontext.gregs[REG_R11] },
    340     { " r12: ", context->uc_mcontext.gregs[REG_R12] },
    341     { " r13: ", context->uc_mcontext.gregs[REG_R13] },
    342     { " r14: ", context->uc_mcontext.gregs[REG_R14] },
    343     { " r15: ", context->uc_mcontext.gregs[REG_R15] },
    344     { "  di: ", context->uc_mcontext.gregs[REG_RDI] },
    345     { "  si: ", context->uc_mcontext.gregs[REG_RSI] },
    346     { "  bp: ", context->uc_mcontext.gregs[REG_RBP] },
    347     { "  bx: ", context->uc_mcontext.gregs[REG_RBX] },
    348     { "  dx: ", context->uc_mcontext.gregs[REG_RDX] },
    349     { "  ax: ", context->uc_mcontext.gregs[REG_RAX] },
    350     { "  cx: ", context->uc_mcontext.gregs[REG_RCX] },
    351     { "  sp: ", context->uc_mcontext.gregs[REG_RSP] },
    352     { "  ip: ", context->uc_mcontext.gregs[REG_RIP] },
    353     { " efl: ", context->uc_mcontext.gregs[REG_EFL] },
    354     { " cgf: ", context->uc_mcontext.gregs[REG_CSGSFS] },
    355     { " erf: ", context->uc_mcontext.gregs[REG_ERR] },
    356     { " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] },
    357     { " msk: ", context->uc_mcontext.gregs[REG_OLDMASK] },
    358     { " cr2: ", context->uc_mcontext.gregs[REG_CR2] },
    359 #endif  // ARCH_CPU_32_BITS
    360   };
    361 
    362 #if ARCH_CPU_32_BITS
    363   const int kRegisterPadding = 8;
    364 #elif ARCH_CPU_64_BITS
    365   const int kRegisterPadding = 16;
    366 #endif
    367 
    368   for (size_t i = 0; i < arraysize(registers); i++) {
    369     PrintToStderr(registers[i].label);
    370     internal::itoa_r(registers[i].value, buf, sizeof(buf),
    371                      16, kRegisterPadding);
    372     PrintToStderr(buf);
    373 
    374     if ((i + 1) % 4 == 0)
    375       PrintToStderr("\n");
    376   }
    377   PrintToStderr("\n");
    378 #endif  // ARCH_CPU_X86_FAMILY
    379 #endif  // defined(OS_LINUX)
    380 
    381   PrintToStderr("[end of stack trace]\n");
    382 
    383 #if defined(OS_MACOSX) && !defined(OS_IOS)
    384   if (::signal(signal, SIG_DFL) == SIG_ERR)
    385     _exit(1);
    386 #else
    387   // Non-Mac OSes should probably reraise the signal as well, but the Linux
    388   // sandbox tests break on CrOS devices.
    389   // https://code.google.com/p/chromium/issues/detail?id=551681
    390   _exit(1);
    391 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
    392 }
    393 
    394 class PrintBacktraceOutputHandler : public BacktraceOutputHandler {
    395  public:
    396   PrintBacktraceOutputHandler() {}
    397 
    398   void HandleOutput(const char* output) override {
    399     // NOTE: This code MUST be async-signal safe (it's used by in-process
    400     // stack dumping signal handler). NO malloc or stdio is allowed here.
    401     PrintToStderr(output);
    402   }
    403 
    404  private:
    405   DISALLOW_COPY_AND_ASSIGN(PrintBacktraceOutputHandler);
    406 };
    407 
    408 class StreamBacktraceOutputHandler : public BacktraceOutputHandler {
    409  public:
    410   explicit StreamBacktraceOutputHandler(std::ostream* os) : os_(os) {
    411   }
    412 
    413   void HandleOutput(const char* output) override { (*os_) << output; }
    414 
    415  private:
    416   std::ostream* os_;
    417 
    418   DISALLOW_COPY_AND_ASSIGN(StreamBacktraceOutputHandler);
    419 };
    420 
    421 void WarmUpBacktrace() {
    422   // Warm up stack trace infrastructure. It turns out that on the first
    423   // call glibc initializes some internal data structures using pthread_once,
    424   // and even backtrace() can call malloc(), leading to hangs.
    425   //
    426   // Example stack trace snippet (with tcmalloc):
    427   //
    428   // #8  0x0000000000a173b5 in tc_malloc
    429   //             at ./third_party/tcmalloc/chromium/src/debugallocation.cc:1161
    430   // #9  0x00007ffff7de7900 in _dl_map_object_deps at dl-deps.c:517
    431   // #10 0x00007ffff7ded8a9 in dl_open_worker at dl-open.c:262
    432   // #11 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178
    433   // #12 0x00007ffff7ded31a in _dl_open (file=0x7ffff625e298 "libgcc_s.so.1")
    434   //             at dl-open.c:639
    435   // #13 0x00007ffff6215602 in do_dlopen at dl-libc.c:89
    436   // #14 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178
    437   // #15 0x00007ffff62156c4 in dlerror_run at dl-libc.c:48
    438   // #16 __GI___libc_dlopen_mode at dl-libc.c:165
    439   // #17 0x00007ffff61ef8f5 in init
    440   //             at ../sysdeps/x86_64/../ia64/backtrace.c:53
    441   // #18 0x00007ffff6aad400 in pthread_once
    442   //             at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S:104
    443   // #19 0x00007ffff61efa14 in __GI___backtrace
    444   //             at ../sysdeps/x86_64/../ia64/backtrace.c:104
    445   // #20 0x0000000000752a54 in base::debug::StackTrace::StackTrace
    446   //             at base/debug/stack_trace_posix.cc:175
    447   // #21 0x00000000007a4ae5 in
    448   //             base::(anonymous namespace)::StackDumpSignalHandler
    449   //             at base/process_util_posix.cc:172
    450   // #22 <signal handler called>
    451   StackTrace stack_trace;
    452 }
    453 
    454 }  // namespace
    455 
    456 #if defined(USE_SYMBOLIZE)
    457 
    458 // class SandboxSymbolizeHelper.
    459 //
    460 // The purpose of this class is to prepare and install a "file open" callback
    461 // needed by the stack trace symbolization code
    462 // (base/third_party/symbolize/symbolize.h) so that it can function properly
    463 // in a sandboxed process.  The caveat is that this class must be instantiated
    464 // before the sandboxing is enabled so that it can get the chance to open all
    465 // the object files that are loaded in the virtual address space of the current
    466 // process.
    467 class SandboxSymbolizeHelper {
    468  public:
    469   // Returns the singleton instance.
    470   static SandboxSymbolizeHelper* GetInstance() {
    471     return Singleton<SandboxSymbolizeHelper>::get();
    472   }
    473 
    474  private:
    475   friend struct DefaultSingletonTraits<SandboxSymbolizeHelper>;
    476 
    477   SandboxSymbolizeHelper()
    478       : is_initialized_(false) {
    479     Init();
    480   }
    481 
    482   ~SandboxSymbolizeHelper() {
    483     UnregisterCallback();
    484     CloseObjectFiles();
    485   }
    486 
    487   // Returns a O_RDONLY file descriptor for |file_path| if it was opened
    488   // successfully during the initialization.  The file is repositioned at
    489   // offset 0.
    490   // IMPORTANT: This function must be async-signal-safe because it can be
    491   // called from a signal handler (symbolizing stack frames for a crash).
    492   int GetFileDescriptor(const char* file_path) {
    493     int fd = -1;
    494 
    495 #if !defined(OFFICIAL_BUILD)
    496     if (file_path) {
    497       // The assumption here is that iterating over std::map<std::string, int>
    498       // using a const_iterator does not allocate dynamic memory, hense it is
    499       // async-signal-safe.
    500       std::map<std::string, int>::const_iterator it;
    501       for (it = modules_.begin(); it != modules_.end(); ++it) {
    502         if (strcmp((it->first).c_str(), file_path) == 0) {
    503           // POSIX.1-2004 requires an implementation to guarantee that dup()
    504           // is async-signal-safe.
    505           fd = dup(it->second);
    506           break;
    507         }
    508       }
    509       // POSIX.1-2004 requires an implementation to guarantee that lseek()
    510       // is async-signal-safe.
    511       if (fd >= 0 && lseek(fd, 0, SEEK_SET) < 0) {
    512         // Failed to seek.
    513         fd = -1;
    514       }
    515     }
    516 #endif  // !defined(OFFICIAL_BUILD)
    517 
    518     return fd;
    519   }
    520 
    521   // Searches for the object file (from /proc/self/maps) that contains
    522   // the specified pc.  If found, sets |start_address| to the start address
    523   // of where this object file is mapped in memory, sets the module base
    524   // address into |base_address|, copies the object file name into
    525   // |out_file_name|, and attempts to open the object file.  If the object
    526   // file is opened successfully, returns the file descriptor.  Otherwise,
    527   // returns -1.  |out_file_name_size| is the size of the file name buffer
    528   // (including the null terminator).
    529   // IMPORTANT: This function must be async-signal-safe because it can be
    530   // called from a signal handler (symbolizing stack frames for a crash).
    531   static int OpenObjectFileContainingPc(uint64_t pc, uint64_t& start_address,
    532                                         uint64_t& base_address, char* file_path,
    533                                         int file_path_size) {
    534     // This method can only be called after the singleton is instantiated.
    535     // This is ensured by the following facts:
    536     // * This is the only static method in this class, it is private, and
    537     //   the class has no friends (except for the DefaultSingletonTraits).
    538     //   The compiler guarantees that it can only be called after the
    539     //   singleton is instantiated.
    540     // * This method is used as a callback for the stack tracing code and
    541     //   the callback registration is done in the constructor, so logically
    542     //   it cannot be called before the singleton is created.
    543     SandboxSymbolizeHelper* instance = GetInstance();
    544 
    545     // The assumption here is that iterating over
    546     // std::vector<MappedMemoryRegion> using a const_iterator does not allocate
    547     // dynamic memory, hence it is async-signal-safe.
    548     std::vector<MappedMemoryRegion>::const_iterator it;
    549     bool is_first = true;
    550     for (it = instance->regions_.begin(); it != instance->regions_.end();
    551          ++it, is_first = false) {
    552       const MappedMemoryRegion& region = *it;
    553       if (region.start <= pc && pc < region.end) {
    554         start_address = region.start;
    555         // Don't subtract 'start_address' from the first entry:
    556         // * If a binary is compiled w/o -pie, then the first entry in
    557         //   process maps is likely the binary itself (all dynamic libs
    558         //   are mapped higher in address space). For such a binary,
    559         //   instruction offset in binary coincides with the actual
    560         //   instruction address in virtual memory (as code section
    561         //   is mapped to a fixed memory range).
    562         // * If a binary is compiled with -pie, all the modules are
    563         //   mapped high at address space (in particular, higher than
    564         //   shadow memory of the tool), so the module can't be the
    565         //   first entry.
    566         base_address = (is_first ? 0U : start_address) - region.offset;
    567         if (file_path && file_path_size > 0) {
    568           strncpy(file_path, region.path.c_str(), file_path_size);
    569           // Ensure null termination.
    570           file_path[file_path_size - 1] = '\0';
    571         }
    572         return instance->GetFileDescriptor(region.path.c_str());
    573       }
    574     }
    575     return -1;
    576   }
    577 
    578   // Parses /proc/self/maps in order to compile a list of all object file names
    579   // for the modules that are loaded in the current process.
    580   // Returns true on success.
    581   bool CacheMemoryRegions() {
    582     // Reads /proc/self/maps.
    583     std::string contents;
    584     if (!ReadProcMaps(&contents)) {
    585       LOG(ERROR) << "Failed to read /proc/self/maps";
    586       return false;
    587     }
    588 
    589     // Parses /proc/self/maps.
    590     if (!ParseProcMaps(contents, &regions_)) {
    591       LOG(ERROR) << "Failed to parse the contents of /proc/self/maps";
    592       return false;
    593     }
    594 
    595     is_initialized_ = true;
    596     return true;
    597   }
    598 
    599   // Opens all object files and caches their file descriptors.
    600   void OpenSymbolFiles() {
    601     // Pre-opening and caching the file descriptors of all loaded modules is
    602     // not safe for production builds.  Hence it is only done in non-official
    603     // builds.  For more details, take a look at: http://crbug.com/341966.
    604 #if !defined(OFFICIAL_BUILD)
    605     // Open the object files for all read-only executable regions and cache
    606     // their file descriptors.
    607     std::vector<MappedMemoryRegion>::const_iterator it;
    608     for (it = regions_.begin(); it != regions_.end(); ++it) {
    609       const MappedMemoryRegion& region = *it;
    610       // Only interesed in read-only executable regions.
    611       if ((region.permissions & MappedMemoryRegion::READ) ==
    612               MappedMemoryRegion::READ &&
    613           (region.permissions & MappedMemoryRegion::WRITE) == 0 &&
    614           (region.permissions & MappedMemoryRegion::EXECUTE) ==
    615               MappedMemoryRegion::EXECUTE) {
    616         if (region.path.empty()) {
    617           // Skip regions with empty file names.
    618           continue;
    619         }
    620         if (region.path[0] == '[') {
    621           // Skip pseudo-paths, like [stack], [vdso], [heap], etc ...
    622           continue;
    623         }
    624         // Avoid duplicates.
    625         if (modules_.find(region.path) == modules_.end()) {
    626           int fd = open(region.path.c_str(), O_RDONLY | O_CLOEXEC);
    627           if (fd >= 0) {
    628             modules_.insert(std::make_pair(region.path, fd));
    629           } else {
    630             LOG(WARNING) << "Failed to open file: " << region.path
    631                          << "\n  Error: " << strerror(errno);
    632           }
    633         }
    634       }
    635     }
    636 #endif  // !defined(OFFICIAL_BUILD)
    637   }
    638 
    639   // Initializes and installs the symbolization callback.
    640   void Init() {
    641     if (CacheMemoryRegions()) {
    642       OpenSymbolFiles();
    643       google::InstallSymbolizeOpenObjectFileCallback(
    644           &OpenObjectFileContainingPc);
    645     }
    646   }
    647 
    648   // Unregister symbolization callback.
    649   void UnregisterCallback() {
    650     if (is_initialized_) {
    651       google::InstallSymbolizeOpenObjectFileCallback(NULL);
    652       is_initialized_ = false;
    653     }
    654   }
    655 
    656   // Closes all file descriptors owned by this instance.
    657   void CloseObjectFiles() {
    658 #if !defined(OFFICIAL_BUILD)
    659     std::map<std::string, int>::iterator it;
    660     for (it = modules_.begin(); it != modules_.end(); ++it) {
    661       int ret = IGNORE_EINTR(close(it->second));
    662       DCHECK(!ret);
    663       it->second = -1;
    664     }
    665     modules_.clear();
    666 #endif  // !defined(OFFICIAL_BUILD)
    667   }
    668 
    669   // Set to true upon successful initialization.
    670   bool is_initialized_;
    671 
    672 #if !defined(OFFICIAL_BUILD)
    673   // Mapping from file name to file descriptor.  Includes file descriptors
    674   // for all successfully opened object files and the file descriptor for
    675   // /proc/self/maps.  This code is not safe for production builds.
    676   std::map<std::string, int> modules_;
    677 #endif  // !defined(OFFICIAL_BUILD)
    678 
    679   // Cache for the process memory regions.  Produced by parsing the contents
    680   // of /proc/self/maps cache.
    681   std::vector<MappedMemoryRegion> regions_;
    682 
    683   DISALLOW_COPY_AND_ASSIGN(SandboxSymbolizeHelper);
    684 };
    685 #endif  // USE_SYMBOLIZE
    686 
    687 bool EnableInProcessStackDumping() {
    688 #if defined(USE_SYMBOLIZE)
    689   SandboxSymbolizeHelper::GetInstance();
    690 #endif  // USE_SYMBOLIZE
    691 
    692   // When running in an application, our code typically expects SIGPIPE
    693   // to be ignored.  Therefore, when testing that same code, it should run
    694   // with SIGPIPE ignored as well.
    695   struct sigaction sigpipe_action;
    696   memset(&sigpipe_action, 0, sizeof(sigpipe_action));
    697   sigpipe_action.sa_handler = SIG_IGN;
    698   sigemptyset(&sigpipe_action.sa_mask);
    699   bool success = (sigaction(SIGPIPE, &sigpipe_action, NULL) == 0);
    700 
    701   // Avoid hangs during backtrace initialization, see above.
    702   WarmUpBacktrace();
    703 
    704   struct sigaction action;
    705   memset(&action, 0, sizeof(action));
    706   action.sa_flags = SA_RESETHAND | SA_SIGINFO;
    707   action.sa_sigaction = &StackDumpSignalHandler;
    708   sigemptyset(&action.sa_mask);
    709 
    710   success &= (sigaction(SIGILL, &action, NULL) == 0);
    711   success &= (sigaction(SIGABRT, &action, NULL) == 0);
    712   success &= (sigaction(SIGFPE, &action, NULL) == 0);
    713   success &= (sigaction(SIGBUS, &action, NULL) == 0);
    714   success &= (sigaction(SIGSEGV, &action, NULL) == 0);
    715 // On Linux, SIGSYS is reserved by the kernel for seccomp-bpf sandboxing.
    716 #if !defined(OS_LINUX)
    717   success &= (sigaction(SIGSYS, &action, NULL) == 0);
    718 #endif  // !defined(OS_LINUX)
    719 
    720   return success;
    721 }
    722 
    723 StackTrace::StackTrace() {
    724   // NOTE: This code MUST be async-signal safe (it's used by in-process
    725   // stack dumping signal handler). NO malloc or stdio is allowed here.
    726 
    727 #if !defined(__UCLIBC__)
    728   // Though the backtrace API man page does not list any possible negative
    729   // return values, we take no chance.
    730   count_ = base::saturated_cast<size_t>(backtrace(trace_, arraysize(trace_)));
    731 #else
    732   count_ = 0;
    733 #endif
    734 }
    735 
    736 void StackTrace::Print() const {
    737   // NOTE: This code MUST be async-signal safe (it's used by in-process
    738   // stack dumping signal handler). NO malloc or stdio is allowed here.
    739 
    740 #if !defined(__UCLIBC__)
    741   PrintBacktraceOutputHandler handler;
    742   ProcessBacktrace(trace_, count_, &handler);
    743 #endif
    744 }
    745 
    746 #if !defined(__UCLIBC__)
    747 void StackTrace::OutputToStream(std::ostream* os) const {
    748   StreamBacktraceOutputHandler handler(os);
    749   ProcessBacktrace(trace_, count_, &handler);
    750 }
    751 #endif
    752 
    753 namespace internal {
    754 
    755 // NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
    756 char* itoa_r(intptr_t i, char* buf, size_t sz, int base, size_t padding) {
    757   // Make sure we can write at least one NUL byte.
    758   size_t n = 1;
    759   if (n > sz)
    760     return NULL;
    761 
    762   if (base < 2 || base > 16) {
    763     buf[0] = '\000';
    764     return NULL;
    765   }
    766 
    767   char* start = buf;
    768 
    769   uintptr_t j = i;
    770 
    771   // Handle negative numbers (only for base 10).
    772   if (i < 0 && base == 10) {
    773     // This does "j = -i" while avoiding integer overflow.
    774     j = static_cast<uintptr_t>(-(i + 1)) + 1;
    775 
    776     // Make sure we can write the '-' character.
    777     if (++n > sz) {
    778       buf[0] = '\000';
    779       return NULL;
    780     }
    781     *start++ = '-';
    782   }
    783 
    784   // Loop until we have converted the entire number. Output at least one
    785   // character (i.e. '0').
    786   char* ptr = start;
    787   do {
    788     // Make sure there is still enough space left in our output buffer.
    789     if (++n > sz) {
    790       buf[0] = '\000';
    791       return NULL;
    792     }
    793 
    794     // Output the next digit.
    795     *ptr++ = "0123456789abcdef"[j % base];
    796     j /= base;
    797 
    798     if (padding > 0)
    799       padding--;
    800   } while (j > 0 || padding > 0);
    801 
    802   // Terminate the output with a NUL character.
    803   *ptr = '\000';
    804 
    805   // Conversion to ASCII actually resulted in the digits being in reverse
    806   // order. We can't easily generate them in forward order, as we can't tell
    807   // the number of characters needed until we are done converting.
    808   // So, now, we reverse the string (except for the possible "-" sign).
    809   while (--ptr > start) {
    810     char ch = *ptr;
    811     *ptr = *start;
    812     *start++ = ch;
    813   }
    814   return buf;
    815 }
    816 
    817 }  // namespace internal
    818 
    819 }  // namespace debug
    820 }  // namespace base
    821