| OLD | NEW | 
|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "base/debug/stack_trace.h" | 5 #include "base/debug/stack_trace.h" | 
| 6 | 6 | 
| 7 #include <errno.h> | 7 #include <errno.h> | 
| 8 #include <execinfo.h> | 8 #include <execinfo.h> | 
| 9 #include <fcntl.h> | 9 #include <fcntl.h> | 
| 10 #include <signal.h> | 10 #include <signal.h> | 
| 11 #include <stdio.h> | 11 #include <stdio.h> | 
| 12 #include <stdlib.h> | 12 #include <stdlib.h> | 
| 13 #include <sys/param.h> | 13 #include <sys/param.h> | 
| 14 #include <sys/stat.h> | 14 #include <sys/stat.h> | 
| 15 #include <sys/types.h> | 15 #include <sys/types.h> | 
| 16 #include <unistd.h> | 16 #include <unistd.h> | 
| 17 | 17 | 
| 18 #include <string> | 18 #include <ostream> | 
| 19 #include <vector> |  | 
| 20 | 19 | 
| 21 #if defined(__GLIBCXX__) | 20 #if defined(__GLIBCXX__) | 
| 22 #include <cxxabi.h> | 21 #include <cxxabi.h> | 
| 23 #endif | 22 #endif | 
| 24 | 23 | 
| 25 #if defined(OS_MACOSX) | 24 #if defined(OS_MACOSX) | 
| 26 #include <AvailabilityMacros.h> | 25 #include <AvailabilityMacros.h> | 
| 27 #endif | 26 #endif | 
| 28 | 27 | 
| 29 #include "base/basictypes.h" | 28 #include "base/basictypes.h" | 
|  | 29 #include "base/debug/debugger.h" | 
| 30 #include "base/eintr_wrapper.h" | 30 #include "base/eintr_wrapper.h" | 
| 31 #include "base/logging.h" | 31 #include "base/logging.h" | 
| 32 #include "base/memory/scoped_ptr.h" | 32 #include "base/memory/scoped_ptr.h" | 
| 33 #include "base/safe_strerror_posix.h" | 33 #include "base/string_number_conversions.h" | 
| 34 #include "base/string_piece.h" |  | 
| 35 #include "base/stringprintf.h" |  | 
| 36 | 34 | 
| 37 #if defined(USE_SYMBOLIZE) | 35 #if defined(USE_SYMBOLIZE) | 
| 38 #include "base/third_party/symbolize/symbolize.h" | 36 #include "base/third_party/symbolize/symbolize.h" | 
| 39 #endif | 37 #endif | 
| 40 | 38 | 
| 41 namespace base { | 39 namespace base { | 
| 42 namespace debug { | 40 namespace debug { | 
| 43 | 41 | 
| 44 namespace { | 42 namespace { | 
| 45 | 43 | 
|  | 44 volatile sig_atomic_t in_signal_handler = 0; | 
|  | 45 | 
| 46 // The prefix used for mangled symbols, per the Itanium C++ ABI: | 46 // The prefix used for mangled symbols, per the Itanium C++ ABI: | 
| 47 // http://www.codesourcery.com/cxx-abi/abi.html#mangling | 47 // http://www.codesourcery.com/cxx-abi/abi.html#mangling | 
| 48 const char kMangledSymbolPrefix[] = "_Z"; | 48 const char kMangledSymbolPrefix[] = "_Z"; | 
| 49 | 49 | 
| 50 // Characters that can be used for symbols, generated by Ruby: | 50 // Characters that can be used for symbols, generated by Ruby: | 
| 51 // (('a'..'z').to_a+('A'..'Z').to_a+('0'..'9').to_a + ['_']).join | 51 // (('a'..'z').to_a+('A'..'Z').to_a+('0'..'9').to_a + ['_']).join | 
| 52 const char kSymbolCharacters[] = | 52 const char kSymbolCharacters[] = | 
| 53     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; | 53     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; | 
| 54 | 54 | 
| 55 #if !defined(USE_SYMBOLIZE) | 55 #if !defined(USE_SYMBOLIZE) | 
| 56 // Demangles C++ symbols in the given text. Example: | 56 // Demangles C++ symbols in the given text. Example: | 
| 57 // | 57 // | 
| 58 // "out/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]" | 58 // "out/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]" | 
| 59 // => | 59 // => | 
| 60 // "out/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x817778c]" | 60 // "out/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x817778c]" | 
| 61 void DemangleSymbols(std::string* text) { | 61 void DemangleSymbols(std::string* text) { | 
|  | 62   // Note: code in this function is NOT async-signal safe (std::string uses | 
|  | 63   // malloc internally). | 
|  | 64 | 
| 62 #if defined(__GLIBCXX__) | 65 #if defined(__GLIBCXX__) | 
| 63 | 66 | 
| 64   std::string::size_type search_from = 0; | 67   std::string::size_type search_from = 0; | 
| 65   while (search_from < text->size()) { | 68   while (search_from < text->size()) { | 
| 66     // Look for the start of a mangled symbol, from search_from. | 69     // Look for the start of a mangled symbol, from search_from. | 
| 67     std::string::size_type mangled_start = | 70     std::string::size_type mangled_start = | 
| 68         text->find(kMangledSymbolPrefix, search_from); | 71         text->find(kMangledSymbolPrefix, search_from); | 
| 69     if (mangled_start == std::string::npos) { | 72     if (mangled_start == std::string::npos) { | 
| 70       break;  // Mangled symbol not found. | 73       break;  // Mangled symbol not found. | 
| 71     } | 74     } | 
| (...skipping 21 matching lines...) Expand all  Loading... | 
| 93     } else { | 96     } else { | 
| 94       // Failed to demangle.  Retry after the "_Z" we just found. | 97       // Failed to demangle.  Retry after the "_Z" we just found. | 
| 95       search_from = mangled_start + 2; | 98       search_from = mangled_start + 2; | 
| 96     } | 99     } | 
| 97   } | 100   } | 
| 98 | 101 | 
| 99 #endif  // defined(__GLIBCXX__) | 102 #endif  // defined(__GLIBCXX__) | 
| 100 } | 103 } | 
| 101 #endif  // !defined(USE_SYMBOLIZE) | 104 #endif  // !defined(USE_SYMBOLIZE) | 
| 102 | 105 | 
| 103 // Gets the backtrace as a vector of strings. If possible, resolve symbol | 106 class BacktraceOutputHandler { | 
| 104 // names and attach these. Otherwise just use raw addresses. Returns true | 107  public: | 
| 105 // if any symbol name is resolved.  Returns false on error and *may* fill | 108   virtual void HandleOutput(const char* output) = 0; | 
| 106 // in |error_message| if an error message is available. | 109 | 
| 107 bool GetBacktraceStrings(void *const *trace, int size, | 110  protected: | 
| 108                          std::vector<std::string>* trace_strings, | 111   virtual ~BacktraceOutputHandler() {} | 
| 109                          std::string* error_message) { | 112 }; | 
| 110   bool symbolized = false; | 113 | 
|  | 114 void OutputPointer(void* pointer, BacktraceOutputHandler* handler) { | 
|  | 115   char buf[1024] = { '\0' }; | 
|  | 116   handler->HandleOutput(" [0x"); | 
|  | 117   internal::itoa_r(reinterpret_cast<intptr_t>(pointer), buf, sizeof(buf), 16); | 
|  | 118   handler->HandleOutput(buf); | 
|  | 119   handler->HandleOutput("]"); | 
|  | 120 } | 
|  | 121 | 
|  | 122 void ProcessBacktrace(void *const *trace, | 
|  | 123                       int size, | 
|  | 124                       BacktraceOutputHandler* handler) { | 
|  | 125   // NOTE: This code MUST be async-signal safe (it's used by in-process | 
|  | 126   // stack dumping signal handler). NO malloc or stdio is allowed here. | 
| 111 | 127 | 
| 112 #if defined(USE_SYMBOLIZE) | 128 #if defined(USE_SYMBOLIZE) | 
| 113   for (int i = 0; i < size; ++i) { | 129   for (int i = 0; i < size; ++i) { | 
| 114     char symbol[1024]; | 130     handler->HandleOutput("\t"); | 
|  | 131 | 
|  | 132     char buf[1024] = { '\0' }; | 
|  | 133 | 
| 115     // Subtract by one as return address of function may be in the next | 134     // Subtract by one as return address of function may be in the next | 
| 116     // function when a function is annotated as noreturn. | 135     // function when a function is annotated as noreturn. | 
| 117     if (google::Symbolize(static_cast<char *>(trace[i]) - 1, | 136     void* address = static_cast<char*>(trace[i]) - 1; | 
| 118                           symbol, sizeof(symbol))) { | 137     if (google::Symbolize(address, buf, sizeof(buf))) | 
| 119       // Don't call DemangleSymbols() here as the symbol is demangled by | 138       handler->HandleOutput(buf); | 
| 120       // google::Symbolize(). | 139     else | 
| 121       trace_strings->push_back( | 140       handler->HandleOutput("<unknown>"); | 
| 122           base::StringPrintf("%s [%p]", symbol, trace[i])); | 141 | 
| 123       symbolized = true; | 142     OutputPointer(trace[i], handler); | 
| 124     } else { | 143     handler->HandleOutput("\n"); | 
| 125       trace_strings->push_back(base::StringPrintf("%p", trace[i])); | 144   } | 
|  | 145 #else | 
|  | 146   bool printed = false; | 
|  | 147 | 
|  | 148   // Below part is async-signal unsafe (uses malloc), so execute it only | 
|  | 149   // when we are not executing the signal handler. | 
|  | 150   if (in_signal_handler == 0) { | 
|  | 151     scoped_ptr_malloc<char*> trace_symbols(backtrace_symbols(trace, size)); | 
|  | 152     if (trace_symbols.get()) { | 
|  | 153       for (int i = 0; i < size; ++i) { | 
|  | 154         std::string trace_symbol = trace_symbols.get()[i]; | 
|  | 155         DemangleSymbols(&trace_symbol); | 
|  | 156         handler->HandleOutput(trace_symbol.c_str()); | 
|  | 157         handler->HandleOutput("\n"); | 
|  | 158       } | 
|  | 159 | 
|  | 160       printed = true; | 
| 126     } | 161     } | 
| 127   } | 162   } | 
| 128 #else | 163 | 
| 129   scoped_ptr_malloc<char*> trace_symbols(backtrace_symbols(trace, size)); | 164   if (!printed) { | 
| 130   if (trace_symbols.get()) { |  | 
| 131     for (int i = 0; i < size; ++i) { | 165     for (int i = 0; i < size; ++i) { | 
| 132       std::string trace_symbol = trace_symbols.get()[i]; | 166       OutputPointer(trace[i], handler); | 
| 133       DemangleSymbols(&trace_symbol); | 167       handler->HandleOutput("\n"); | 
| 134       trace_strings->push_back(trace_symbol); |  | 
| 135     } |  | 
| 136     symbolized = true; |  | 
| 137   } else { |  | 
| 138     if (error_message) |  | 
| 139       *error_message = safe_strerror(errno); |  | 
| 140     for (int i = 0; i < size; ++i) { |  | 
| 141       trace_strings->push_back(base::StringPrintf("%p", trace[i])); |  | 
| 142     } | 168     } | 
| 143   } | 169   } | 
| 144 #endif  // defined(USE_SYMBOLIZE) | 170 #endif  // defined(USE_SYMBOLIZE) | 
| 145 |  | 
| 146   return symbolized; |  | 
| 147 } | 171 } | 
| 148 | 172 | 
| 149 void StackDumpSignalHandler(int signal, siginfo_t* info, ucontext_t* context) { | 173 void StackDumpSignalHandler(int signal, siginfo_t* info, ucontext_t* context) { | 
|  | 174   // NOTE: This code MUST be async-signal safe. | 
|  | 175   // NO malloc or stdio is allowed here. | 
|  | 176 | 
|  | 177   // Record the fact that we are in the signal handler now, so that the rest | 
|  | 178   // of StackTrace can behave in an async-signal-safe manner. | 
|  | 179   in_signal_handler = 1; | 
|  | 180 | 
| 150   if (BeingDebugged()) | 181   if (BeingDebugged()) | 
| 151     BreakDebugger(); | 182     BreakDebugger(); | 
| 152 | 183 | 
| 153 #if defined(OS_MACOSX) | 184   char buf[1024] = "Received signal "; | 
| 154   // TODO(phajdan.jr): Fix async-signal non-safety (http://crbug.com/101155). | 185   size_t buf_len = strlen(buf); | 
| 155   DLOG(ERROR) << "Received signal " << signal; | 186   internal::itoa_r(signal, buf + buf_len, sizeof(buf) - buf_len, 10); | 
| 156   StackTrace().PrintBacktrace(); | 187   RAW_LOG(ERROR, buf); | 
| 157 #endif | 188 | 
|  | 189   debug::StackTrace().PrintBacktrace(); | 
| 158 | 190 | 
| 159   // TODO(shess): Port to Linux. | 191   // TODO(shess): Port to Linux. | 
| 160 #if defined(OS_MACOSX) | 192 #if defined(OS_MACOSX) | 
| 161   // TODO(shess): Port to 64-bit. | 193   // TODO(shess): Port to 64-bit. | 
| 162 #if ARCH_CPU_X86_FAMILY && ARCH_CPU_32_BITS | 194 #if ARCH_CPU_X86_FAMILY && ARCH_CPU_32_BITS | 
| 163   char buf[1024]; |  | 
| 164   size_t len; | 195   size_t len; | 
| 165 | 196 | 
| 166   // NOTE: Even |snprintf()| is not on the approved list for signal | 197   // NOTE: Even |snprintf()| is not on the approved list for signal | 
| 167   // handlers, but buffered I/O is definitely not on the list due to | 198   // handlers, but buffered I/O is definitely not on the list due to | 
| 168   // potential for |malloc()|. | 199   // potential for |malloc()|. | 
| 169   len = static_cast<size_t>( | 200   len = static_cast<size_t>( | 
| 170       snprintf(buf, sizeof(buf), | 201       snprintf(buf, sizeof(buf), | 
| 171                "ax: %x, bx: %x, cx: %x, dx: %x\n", | 202                "ax: %x, bx: %x, cx: %x, dx: %x\n", | 
| 172                context->uc_mcontext->__ss.__eax, | 203                context->uc_mcontext->__ss.__eax, | 
| 173                context->uc_mcontext->__ss.__ebx, | 204                context->uc_mcontext->__ss.__ebx, | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
| 194                context->uc_mcontext->__ss.__ds, | 225                context->uc_mcontext->__ss.__ds, | 
| 195                context->uc_mcontext->__ss.__es, | 226                context->uc_mcontext->__ss.__es, | 
| 196                context->uc_mcontext->__ss.__fs, | 227                context->uc_mcontext->__ss.__fs, | 
| 197                context->uc_mcontext->__ss.__gs)); | 228                context->uc_mcontext->__ss.__gs)); | 
| 198   write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1)); | 229   write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1)); | 
| 199 #endif  // ARCH_CPU_32_BITS | 230 #endif  // ARCH_CPU_32_BITS | 
| 200 #endif  // defined(OS_MACOSX) | 231 #endif  // defined(OS_MACOSX) | 
| 201   _exit(1); | 232   _exit(1); | 
| 202 } | 233 } | 
| 203 | 234 | 
|  | 235 class PrintBacktraceOutputHandler : public BacktraceOutputHandler { | 
|  | 236  public: | 
|  | 237   PrintBacktraceOutputHandler() {} | 
|  | 238 | 
|  | 239   virtual void HandleOutput(const char* output) { | 
|  | 240     // NOTE: This code MUST be async-signal safe (it's used by in-process | 
|  | 241     // stack dumping signal handler). NO malloc or stdio is allowed here. | 
|  | 242     ignore_result(HANDLE_EINTR(write(STDERR_FILENO, output, strlen(output)))); | 
|  | 243   } | 
|  | 244 | 
|  | 245  private: | 
|  | 246   DISALLOW_COPY_AND_ASSIGN(PrintBacktraceOutputHandler); | 
|  | 247 }; | 
|  | 248 | 
|  | 249 class StreamBacktraceOutputHandler : public BacktraceOutputHandler { | 
|  | 250  public: | 
|  | 251   StreamBacktraceOutputHandler(std::ostream* os) : os_(os) { | 
|  | 252   } | 
|  | 253 | 
|  | 254   virtual void HandleOutput(const char* output) { | 
|  | 255     (*os_) << output; | 
|  | 256   } | 
|  | 257 | 
|  | 258  private: | 
|  | 259   std::ostream* os_; | 
|  | 260 | 
|  | 261   DISALLOW_COPY_AND_ASSIGN(StreamBacktraceOutputHandler); | 
|  | 262 }; | 
|  | 263 | 
|  | 264 void WarmUpBacktrace() { | 
|  | 265   // Warm up stack trace infrastructure. It turns out that on the first | 
|  | 266   // call glibc initializes some internal data structures using pthread_once, | 
|  | 267   // and even backtrace() can call malloc(), leading to hangs. | 
|  | 268   // | 
|  | 269   // Example stack trace snippet (with tcmalloc): | 
|  | 270   // | 
|  | 271   // #8  0x0000000000a173b5 in tc_malloc | 
|  | 272   //             at ./third_party/tcmalloc/chromium/src/debugallocation.cc:1161 | 
|  | 273   // #9  0x00007ffff7de7900 in _dl_map_object_deps at dl-deps.c:517 | 
|  | 274   // #10 0x00007ffff7ded8a9 in dl_open_worker at dl-open.c:262 | 
|  | 275   // #11 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178 | 
|  | 276   // #12 0x00007ffff7ded31a in _dl_open (file=0x7ffff625e298 "libgcc_s.so.1") | 
|  | 277   //             at dl-open.c:639 | 
|  | 278   // #13 0x00007ffff6215602 in do_dlopen at dl-libc.c:89 | 
|  | 279   // #14 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178 | 
|  | 280   // #15 0x00007ffff62156c4 in dlerror_run at dl-libc.c:48 | 
|  | 281   // #16 __GI___libc_dlopen_mode at dl-libc.c:165 | 
|  | 282   // #17 0x00007ffff61ef8f5 in init | 
|  | 283   //             at ../sysdeps/x86_64/../ia64/backtrace.c:53 | 
|  | 284   // #18 0x00007ffff6aad400 in pthread_once | 
|  | 285   //             at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S:104 | 
|  | 286   // #19 0x00007ffff61efa14 in __GI___backtrace | 
|  | 287   //             at ../sysdeps/x86_64/../ia64/backtrace.c:104 | 
|  | 288   // #20 0x0000000000752a54 in base::debug::StackTrace::StackTrace | 
|  | 289   //             at base/debug/stack_trace_posix.cc:175 | 
|  | 290   // #21 0x00000000007a4ae5 in | 
|  | 291   //             base::(anonymous namespace)::StackDumpSignalHandler | 
|  | 292   //             at base/process_util_posix.cc:172 | 
|  | 293   // #22 <signal handler called> | 
|  | 294   StackTrace stack_trace; | 
|  | 295 } | 
|  | 296 | 
| 204 }  // namespace | 297 }  // namespace | 
| 205 | 298 | 
| 206 #if !defined(OS_IOS) | 299 #if !defined(OS_IOS) | 
| 207 bool EnableInProcessStackDumping() { | 300 bool EnableInProcessStackDumping() { | 
| 208   // When running in an application, our code typically expects SIGPIPE | 301   // When running in an application, our code typically expects SIGPIPE | 
| 209   // to be ignored.  Therefore, when testing that same code, it should run | 302   // to be ignored.  Therefore, when testing that same code, it should run | 
| 210   // with SIGPIPE ignored as well. | 303   // with SIGPIPE ignored as well. | 
| 211   struct sigaction action; | 304   struct sigaction action; | 
| 212   memset(&action, 0, sizeof(action)); | 305   memset(&action, 0, sizeof(action)); | 
| 213   action.sa_handler = SIG_IGN; | 306   action.sa_handler = SIG_IGN; | 
| 214   sigemptyset(&action.sa_mask); | 307   sigemptyset(&action.sa_mask); | 
| 215   bool success = (sigaction(SIGPIPE, &action, NULL) == 0); | 308   bool success = (sigaction(SIGPIPE, &action, NULL) == 0); | 
| 216 | 309 | 
|  | 310   // Avoid hangs during backtrace initialization, see above. | 
|  | 311   WarmUpBacktrace(); | 
|  | 312 | 
| 217   sig_t handler = reinterpret_cast<sig_t>(&StackDumpSignalHandler); | 313   sig_t handler = reinterpret_cast<sig_t>(&StackDumpSignalHandler); | 
| 218   success &= (signal(SIGILL, handler) != SIG_ERR); | 314   success &= (signal(SIGILL, handler) != SIG_ERR); | 
| 219   success &= (signal(SIGABRT, handler) != SIG_ERR); | 315   success &= (signal(SIGABRT, handler) != SIG_ERR); | 
| 220   success &= (signal(SIGFPE, handler) != SIG_ERR); | 316   success &= (signal(SIGFPE, handler) != SIG_ERR); | 
| 221   success &= (signal(SIGBUS, handler) != SIG_ERR); | 317   success &= (signal(SIGBUS, handler) != SIG_ERR); | 
| 222   success &= (signal(SIGSEGV, handler) != SIG_ERR); | 318   success &= (signal(SIGSEGV, handler) != SIG_ERR); | 
| 223   success &= (signal(SIGSYS, handler) != SIG_ERR); | 319   success &= (signal(SIGSYS, handler) != SIG_ERR); | 
| 224 | 320 | 
| 225   return success; | 321   return success; | 
| 226 } | 322 } | 
| 227 #endif  // !defined(OS_IOS) | 323 #endif  // !defined(OS_IOS) | 
| 228 | 324 | 
| 229 StackTrace::StackTrace() { | 325 StackTrace::StackTrace() { | 
|  | 326   // NOTE: This code MUST be async-signal safe (it's used by in-process | 
|  | 327   // stack dumping signal handler). NO malloc or stdio is allowed here. | 
|  | 328 | 
| 230   // Though the backtrace API man page does not list any possible negative | 329   // Though the backtrace API man page does not list any possible negative | 
| 231   // return values, we take no chance. | 330   // return values, we take no chance. | 
| 232   count_ = std::max(backtrace(trace_, arraysize(trace_)), 0); | 331   count_ = std::max(backtrace(trace_, arraysize(trace_)), 0); | 
| 233 } | 332 } | 
| 234 | 333 | 
| 235 void StackTrace::PrintBacktrace() const { | 334 void StackTrace::PrintBacktrace() const { | 
| 236   fflush(stderr); | 335   // NOTE: This code MUST be async-signal safe (it's used by in-process | 
| 237   std::vector<std::string> trace_strings; | 336   // stack dumping signal handler). NO malloc or stdio is allowed here. | 
| 238   GetBacktraceStrings(trace_, count_, &trace_strings, NULL); | 337 | 
| 239   for (size_t i = 0; i < trace_strings.size(); ++i) { | 338   PrintBacktraceOutputHandler handler; | 
| 240     fprintf(stderr, "\t%s\n", trace_strings[i].c_str()); | 339   ProcessBacktrace(trace_, count_, &handler); | 
| 241   } |  | 
| 242 } | 340 } | 
| 243 | 341 | 
| 244 void StackTrace::OutputToStream(std::ostream* os) const { | 342 void StackTrace::OutputToStream(std::ostream* os) const { | 
| 245   std::vector<std::string> trace_strings; | 343   StreamBacktraceOutputHandler handler(os); | 
| 246   std::string error_message; | 344   ProcessBacktrace(trace_, count_, &handler); | 
| 247   if (GetBacktraceStrings(trace_, count_, &trace_strings, &error_message)) { | 345 } | 
| 248     (*os) << "Backtrace:\n"; | 346 | 
| 249   } else { | 347 namespace internal { | 
| 250     if (!error_message.empty()) | 348 | 
| 251       error_message = " (" + error_message + ")"; | 349 // NOTE: code from sandbox/linux/seccomp-bpf/demo.cc. | 
| 252     (*os) << "Unable to get symbols for backtrace" << error_message << ". " | 350 char *itoa_r(intptr_t i, char *buf, size_t sz, int base) { | 
| 253           << "Dumping raw addresses in trace:\n"; | 351   // Make sure we can write at least one NUL byte. | 
|  | 352   size_t n = 1; | 
|  | 353   if (n > sz) | 
|  | 354     return NULL; | 
|  | 355 | 
|  | 356   if (base < 2 || base > 16) { | 
|  | 357     buf[0] = '\000'; | 
|  | 358     return NULL; | 
| 254   } | 359   } | 
| 255 | 360 | 
| 256   for (size_t i = 0; i < trace_strings.size(); ++i) { | 361   char *start = buf; | 
| 257     (*os) << "\t" << trace_strings[i] << "\n"; | 362 | 
|  | 363   uintptr_t j = i; | 
|  | 364 | 
|  | 365   // Handle negative numbers (only for base 10). | 
|  | 366   if (i < 0 && base == 10) { | 
|  | 367     j = -i; | 
|  | 368 | 
|  | 369     // Make sure we can write the '-' character. | 
|  | 370     if (++n > sz) { | 
|  | 371       buf[0] = '\000'; | 
|  | 372       return NULL; | 
|  | 373     } | 
|  | 374     *start++ = '-'; | 
| 258   } | 375   } | 
|  | 376 | 
|  | 377   // Loop until we have converted the entire number. Output at least one | 
|  | 378   // character (i.e. '0'). | 
|  | 379   char *ptr = start; | 
|  | 380   do { | 
|  | 381     // Make sure there is still enough space left in our output buffer. | 
|  | 382     if (++n > sz) { | 
|  | 383       buf[0] = '\000'; | 
|  | 384       return NULL; | 
|  | 385     } | 
|  | 386 | 
|  | 387     // Output the next digit. | 
|  | 388     *ptr++ = "0123456789abcdef"[j % base]; | 
|  | 389     j /= base; | 
|  | 390   } while (j); | 
|  | 391 | 
|  | 392   // Terminate the output with a NUL character. | 
|  | 393   *ptr = '\000'; | 
|  | 394 | 
|  | 395   // Conversion to ASCII actually resulted in the digits being in reverse | 
|  | 396   // order. We can't easily generate them in forward order, as we can't tell | 
|  | 397   // the number of characters needed until we are done converting. | 
|  | 398   // So, now, we reverse the string (except for the possible "-" sign). | 
|  | 399   while (--ptr > start) { | 
|  | 400     char ch = *ptr; | 
|  | 401     *ptr = *start; | 
|  | 402     *start++ = ch; | 
|  | 403   } | 
|  | 404   return buf; | 
| 259 } | 405 } | 
| 260 | 406 | 
|  | 407 }  // namespace internal | 
|  | 408 | 
| 261 }  // namespace debug | 409 }  // namespace debug | 
| 262 }  // namespace base | 410 }  // namespace base | 
| OLD | NEW | 
|---|