Chromium Code Reviews| 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> |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 107 public: | 107 public: |
| 108 virtual void HandleOutput(const char* output) = 0; | 108 virtual void HandleOutput(const char* output) = 0; |
| 109 | 109 |
| 110 protected: | 110 protected: |
| 111 virtual ~BacktraceOutputHandler() {} | 111 virtual ~BacktraceOutputHandler() {} |
| 112 }; | 112 }; |
| 113 | 113 |
| 114 void OutputPointer(void* pointer, BacktraceOutputHandler* handler) { | 114 void OutputPointer(void* pointer, BacktraceOutputHandler* handler) { |
| 115 char buf[1024] = { '\0' }; | 115 char buf[1024] = { '\0' }; |
| 116 handler->HandleOutput(" [0x"); | 116 handler->HandleOutput(" [0x"); |
| 117 internal::itoa_r(reinterpret_cast<intptr_t>(pointer), buf, sizeof(buf), 16); | 117 internal::itoa_r(reinterpret_cast<intptr_t>(pointer), |
| 118 buf, sizeof(buf), 16, 12); | |
| 118 handler->HandleOutput(buf); | 119 handler->HandleOutput(buf); |
| 119 handler->HandleOutput("]"); | 120 handler->HandleOutput("]"); |
| 120 } | 121 } |
| 121 | 122 |
| 122 void ProcessBacktrace(void *const *trace, | 123 void ProcessBacktrace(void *const *trace, |
| 123 int size, | 124 int size, |
| 124 BacktraceOutputHandler* handler) { | 125 BacktraceOutputHandler* handler) { |
| 125 // NOTE: This code MUST be async-signal safe (it's used by in-process | 126 // 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. | 127 // stack dumping signal handler). NO malloc or stdio is allowed here. |
| 127 | 128 |
| 128 #if defined(USE_SYMBOLIZE) | 129 #if defined(USE_SYMBOLIZE) |
| 129 for (int i = 0; i < size; ++i) { | 130 for (int i = 0; i < size; ++i) { |
| 130 handler->HandleOutput("\t"); | 131 OutputPointer(trace[i], handler); |
|
jar (doing other things)
2013/01/09 19:04:25
Why did you change the order of this in the output
Paweł Hajdan Jr.
2013/01/09 19:08:25
I'm not aware of anyone parsing this output, it's
| |
| 132 handler->HandleOutput(" "); | |
| 131 | 133 |
| 132 char buf[1024] = { '\0' }; | 134 char buf[1024] = { '\0' }; |
| 133 | 135 |
| 134 // Subtract by one as return address of function may be in the next | 136 // Subtract by one as return address of function may be in the next |
| 135 // function when a function is annotated as noreturn. | 137 // function when a function is annotated as noreturn. |
| 136 void* address = static_cast<char*>(trace[i]) - 1; | 138 void* address = static_cast<char*>(trace[i]) - 1; |
| 137 if (google::Symbolize(address, buf, sizeof(buf))) | 139 if (google::Symbolize(address, buf, sizeof(buf))) |
| 138 handler->HandleOutput(buf); | 140 handler->HandleOutput(buf); |
| 139 else | 141 else |
| 140 handler->HandleOutput("<unknown>"); | 142 handler->HandleOutput("<unknown>"); |
| 141 | 143 |
| 142 OutputPointer(trace[i], handler); | |
| 143 handler->HandleOutput("\n"); | 144 handler->HandleOutput("\n"); |
| 144 } | 145 } |
| 145 #else | 146 #else |
| 146 bool printed = false; | 147 bool printed = false; |
| 147 | 148 |
| 148 // Below part is async-signal unsafe (uses malloc), so execute it only | 149 // Below part is async-signal unsafe (uses malloc), so execute it only |
| 149 // when we are not executing the signal handler. | 150 // when we are not executing the signal handler. |
| 150 if (in_signal_handler == 0) { | 151 if (in_signal_handler == 0) { |
| 151 scoped_ptr_malloc<char*> trace_symbols(backtrace_symbols(trace, size)); | 152 scoped_ptr_malloc<char*> trace_symbols(backtrace_symbols(trace, size)); |
| 152 if (trace_symbols.get()) { | 153 if (trace_symbols.get()) { |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 176 | 177 |
| 177 // Record the fact that we are in the signal handler now, so that the rest | 178 // 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 // of StackTrace can behave in an async-signal-safe manner. |
| 179 in_signal_handler = 1; | 180 in_signal_handler = 1; |
| 180 | 181 |
| 181 if (BeingDebugged()) | 182 if (BeingDebugged()) |
| 182 BreakDebugger(); | 183 BreakDebugger(); |
| 183 | 184 |
| 184 char buf[1024] = "Received signal "; | 185 char buf[1024] = "Received signal "; |
| 185 size_t buf_len = strlen(buf); | 186 size_t buf_len = strlen(buf); |
| 186 internal::itoa_r(signal, buf + buf_len, sizeof(buf) - buf_len, 10); | 187 internal::itoa_r(signal, buf + buf_len, sizeof(buf) - buf_len, 10, 0); |
| 187 RAW_LOG(ERROR, buf); | 188 RAW_LOG(ERROR, buf); |
| 188 | 189 |
| 189 debug::StackTrace().PrintBacktrace(); | 190 debug::StackTrace().PrintBacktrace(); |
| 190 | 191 |
| 191 // TODO(shess): Port to Linux. | 192 #if defined(OS_LINUX) |
| 192 #if defined(OS_MACOSX) | 193 // TODO(phajdan.jr): Port to 32-bit. |
| 194 #if ARCH_CPU_X86_FAMILY && ARCH_CPU_64_BITS | |
| 195 const struct { | |
| 196 const char* label; | |
| 197 greg_t value; | |
| 198 } registers[] = { | |
| 199 { " r8: ", context->uc_mcontext.gregs[REG_R8] }, | |
|
jar (doing other things)
2013/01/04 20:57:36
Question: Are all these registers held intact duri
Paweł Hajdan Jr.
2013/01/04 21:53:23
See http://pubs.opengroup.org/onlinepubs/007904975
| |
| 200 { " r9: ", context->uc_mcontext.gregs[REG_R9] }, | |
| 201 { " r10: ", context->uc_mcontext.gregs[REG_R10] }, | |
| 202 { " r11: ", context->uc_mcontext.gregs[REG_R11] }, | |
| 203 { " r12: ", context->uc_mcontext.gregs[REG_R12] }, | |
| 204 { " r13: ", context->uc_mcontext.gregs[REG_R13] }, | |
| 205 { " r14: ", context->uc_mcontext.gregs[REG_R14] }, | |
| 206 { " r15: ", context->uc_mcontext.gregs[REG_R15] }, | |
| 207 { " di: ", context->uc_mcontext.gregs[REG_RDI] }, | |
| 208 { " si: ", context->uc_mcontext.gregs[REG_RSI] }, | |
| 209 { " bp: ", context->uc_mcontext.gregs[REG_RBP] }, | |
| 210 { " bx: ", context->uc_mcontext.gregs[REG_RBX] }, | |
| 211 { " dx: ", context->uc_mcontext.gregs[REG_RDX] }, | |
| 212 { " ax: ", context->uc_mcontext.gregs[REG_RAX] }, | |
| 213 { " cx: ", context->uc_mcontext.gregs[REG_RCX] }, | |
| 214 { " sp: ", context->uc_mcontext.gregs[REG_RSP] }, | |
| 215 { " ip: ", context->uc_mcontext.gregs[REG_RIP] }, | |
| 216 { " efl: ", context->uc_mcontext.gregs[REG_EFL] }, | |
| 217 { " cgf: ", context->uc_mcontext.gregs[REG_CSGSFS] }, | |
| 218 { " erf: ", context->uc_mcontext.gregs[REG_ERR] }, | |
| 219 { " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] }, | |
| 220 { " msk: ", context->uc_mcontext.gregs[REG_OLDMASK] }, | |
| 221 { " cr2: ", context->uc_mcontext.gregs[REG_CR2] }, | |
| 222 }; | |
| 223 | |
| 224 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(registers); i++) { | |
| 225 HANDLE_EINTR(write(STDERR_FILENO, | |
| 226 registers[i].label, | |
| 227 strlen(registers[i].label))); | |
| 228 internal::itoa_r(registers[i].value, buf, sizeof(buf), 16, 16); | |
| 229 HANDLE_EINTR(write(STDERR_FILENO, buf, strlen(buf))); | |
| 230 | |
| 231 if ((i + 1) % 4 == 0) { | |
| 232 HANDLE_EINTR(write(STDERR_FILENO, "\n", 1)); | |
| 233 } | |
| 234 } | |
| 235 HANDLE_EINTR(write(STDERR_FILENO, "\n", 1)); | |
| 236 #endif | |
| 237 #elif defined(OS_MACOSX) | |
| 193 // TODO(shess): Port to 64-bit. | 238 // TODO(shess): Port to 64-bit. |
| 194 #if ARCH_CPU_X86_FAMILY && ARCH_CPU_32_BITS | 239 #if ARCH_CPU_X86_FAMILY && ARCH_CPU_32_BITS |
| 195 size_t len; | 240 size_t len; |
| 196 | 241 |
| 197 // NOTE: Even |snprintf()| is not on the approved list for signal | 242 // NOTE: Even |snprintf()| is not on the approved list for signal |
| 198 // handlers, but buffered I/O is definitely not on the list due to | 243 // handlers, but buffered I/O is definitely not on the list due to |
| 199 // potential for |malloc()|. | 244 // potential for |malloc()|. |
| 200 len = static_cast<size_t>( | 245 len = static_cast<size_t>( |
| 201 snprintf(buf, sizeof(buf), | 246 snprintf(buf, sizeof(buf), |
| 202 "ax: %x, bx: %x, cx: %x, dx: %x\n", | 247 "ax: %x, bx: %x, cx: %x, dx: %x\n", |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 340 } | 385 } |
| 341 | 386 |
| 342 void StackTrace::OutputToStream(std::ostream* os) const { | 387 void StackTrace::OutputToStream(std::ostream* os) const { |
| 343 StreamBacktraceOutputHandler handler(os); | 388 StreamBacktraceOutputHandler handler(os); |
| 344 ProcessBacktrace(trace_, count_, &handler); | 389 ProcessBacktrace(trace_, count_, &handler); |
| 345 } | 390 } |
| 346 | 391 |
| 347 namespace internal { | 392 namespace internal { |
| 348 | 393 |
| 349 // NOTE: code from sandbox/linux/seccomp-bpf/demo.cc. | 394 // NOTE: code from sandbox/linux/seccomp-bpf/demo.cc. |
| 350 char *itoa_r(intptr_t i, char *buf, size_t sz, int base) { | 395 char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) { |
| 351 // Make sure we can write at least one NUL byte. | 396 // Make sure we can write at least one NUL byte. |
| 352 size_t n = 1; | 397 size_t n = 1; |
| 353 if (n > sz) | 398 if (n > sz) |
| 354 return NULL; | 399 return NULL; |
| 355 | 400 |
| 356 if (base < 2 || base > 16) { | 401 if (base < 2 || base > 16) { |
| 357 buf[0] = '\000'; | 402 buf[0] = '\000'; |
| 358 return NULL; | 403 return NULL; |
| 359 } | 404 } |
| 360 | 405 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 380 do { | 425 do { |
| 381 // Make sure there is still enough space left in our output buffer. | 426 // Make sure there is still enough space left in our output buffer. |
| 382 if (++n > sz) { | 427 if (++n > sz) { |
| 383 buf[0] = '\000'; | 428 buf[0] = '\000'; |
| 384 return NULL; | 429 return NULL; |
| 385 } | 430 } |
| 386 | 431 |
| 387 // Output the next digit. | 432 // Output the next digit. |
| 388 *ptr++ = "0123456789abcdef"[j % base]; | 433 *ptr++ = "0123456789abcdef"[j % base]; |
| 389 j /= base; | 434 j /= base; |
| 390 } while (j); | 435 |
| 436 if (padding > 0) | |
| 437 padding--; | |
| 438 } while (j > 0 || padding > 0); | |
| 391 | 439 |
| 392 // Terminate the output with a NUL character. | 440 // Terminate the output with a NUL character. |
| 393 *ptr = '\000'; | 441 *ptr = '\000'; |
| 394 | 442 |
| 395 // Conversion to ASCII actually resulted in the digits being in reverse | 443 // 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 | 444 // 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. | 445 // the number of characters needed until we are done converting. |
| 398 // So, now, we reverse the string (except for the possible "-" sign). | 446 // So, now, we reverse the string (except for the possible "-" sign). |
| 399 while (--ptr > start) { | 447 while (--ptr > start) { |
| 400 char ch = *ptr; | 448 char ch = *ptr; |
| 401 *ptr = *start; | 449 *ptr = *start; |
| 402 *start++ = ch; | 450 *start++ = ch; |
| 403 } | 451 } |
| 404 return buf; | 452 return buf; |
| 405 } | 453 } |
| 406 | 454 |
| 407 } // namespace internal | 455 } // namespace internal |
| 408 | 456 |
| 409 } // namespace debug | 457 } // namespace debug |
| 410 } // namespace base | 458 } // namespace base |
| OLD | NEW |