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