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 <ostream> | 18 #include <ostream> |
19 | 19 |
20 #if defined(__GLIBCXX__) | 20 #if defined(__GLIBCXX__) |
21 #include <cxxabi.h> | 21 #include <cxxabi.h> |
22 #endif | 22 #endif |
23 | 23 |
24 #if defined(OS_MACOSX) | 24 #if defined(OS_MACOSX) |
25 #include <AvailabilityMacros.h> | 25 #include <AvailabilityMacros.h> |
26 #endif | 26 #endif |
27 | 27 |
28 #include "base/basictypes.h" | 28 #include "base/basictypes.h" |
29 #include "base/debug/debugger.h" | 29 #include "base/debug/debugger.h" |
| 30 #include "base/debug/format.h" |
30 #include "base/logging.h" | 31 #include "base/logging.h" |
31 #include "base/memory/scoped_ptr.h" | 32 #include "base/memory/scoped_ptr.h" |
32 #include "base/posix/eintr_wrapper.h" | 33 #include "base/posix/eintr_wrapper.h" |
33 #include "base/strings/string_number_conversions.h" | 34 #include "base/strings/string_number_conversions.h" |
34 | 35 |
35 #if defined(USE_SYMBOLIZE) | 36 #if defined(USE_SYMBOLIZE) |
36 #include "base/third_party/symbolize/symbolize.h" | 37 #include "base/third_party/symbolize/symbolize.h" |
37 #endif | 38 #endif |
38 | 39 |
39 namespace base { | 40 namespace base { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 | 106 |
106 class BacktraceOutputHandler { | 107 class BacktraceOutputHandler { |
107 public: | 108 public: |
108 virtual void HandleOutput(const char* output) = 0; | 109 virtual void HandleOutput(const char* output) = 0; |
109 | 110 |
110 protected: | 111 protected: |
111 virtual ~BacktraceOutputHandler() {} | 112 virtual ~BacktraceOutputHandler() {} |
112 }; | 113 }; |
113 | 114 |
114 void OutputPointer(void* pointer, BacktraceOutputHandler* handler) { | 115 void OutputPointer(void* pointer, BacktraceOutputHandler* handler) { |
115 char buf[1024] = { '\0' }; | 116 char buf[30]; |
116 handler->HandleOutput(" [0x"); | 117 Format(buf, " [0x%12x]", reinterpret_cast<intptr_t>(pointer)); |
117 internal::itoa_r(reinterpret_cast<intptr_t>(pointer), | |
118 buf, sizeof(buf), 16, 12); | |
119 handler->HandleOutput(buf); | 118 handler->HandleOutput(buf); |
120 handler->HandleOutput("]"); | |
121 } | 119 } |
122 | 120 |
123 void ProcessBacktrace(void *const *trace, | 121 void ProcessBacktrace(void *const *trace, |
124 int size, | 122 int size, |
125 BacktraceOutputHandler* handler) { | 123 BacktraceOutputHandler* handler) { |
126 // NOTE: This code MUST be async-signal safe (it's used by in-process | 124 // NOTE: This code MUST be async-signal safe (it's used by in-process |
127 // stack dumping signal handler). NO malloc or stdio is allowed here. | 125 // stack dumping signal handler). NO malloc or stdio is allowed here. |
128 | 126 |
129 #if defined(USE_SYMBOLIZE) | 127 #if defined(USE_SYMBOLIZE) |
130 for (int i = 0; i < size; ++i) { | 128 for (int i = 0; i < size; ++i) { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
181 // NOTE: This code MUST be async-signal safe. | 179 // NOTE: This code MUST be async-signal safe. |
182 // NO malloc or stdio is allowed here. | 180 // NO malloc or stdio is allowed here. |
183 | 181 |
184 // Record the fact that we are in the signal handler now, so that the rest | 182 // Record the fact that we are in the signal handler now, so that the rest |
185 // of StackTrace can behave in an async-signal-safe manner. | 183 // of StackTrace can behave in an async-signal-safe manner. |
186 in_signal_handler = 1; | 184 in_signal_handler = 1; |
187 | 185 |
188 if (BeingDebugged()) | 186 if (BeingDebugged()) |
189 BreakDebugger(); | 187 BreakDebugger(); |
190 | 188 |
191 PrintToStderr("Received signal "); | 189 char buf[80]; |
192 char buf[1024] = { 0 }; | 190 Format(buf, "Received signal %d ", signal); |
193 internal::itoa_r(signal, buf, sizeof(buf), 10, 0); | |
194 PrintToStderr(buf); | 191 PrintToStderr(buf); |
195 if (signal == SIGBUS) { | 192 if (signal == SIGBUS) { |
196 if (info->si_code == BUS_ADRALN) | 193 if (info->si_code == BUS_ADRALN) |
197 PrintToStderr(" BUS_ADRALN "); | 194 PrintToStderr("BUS_ADRALN "); |
198 else if (info->si_code == BUS_ADRERR) | 195 else if (info->si_code == BUS_ADRERR) |
199 PrintToStderr(" BUS_ADRERR "); | 196 PrintToStderr("BUS_ADRERR "); |
200 else if (info->si_code == BUS_OBJERR) | 197 else if (info->si_code == BUS_OBJERR) |
201 PrintToStderr(" BUS_OBJERR "); | 198 PrintToStderr("BUS_OBJERR "); |
202 else | 199 else |
203 PrintToStderr(" <unknown> "); | 200 PrintToStderr("<unknown> "); |
204 } else if (signal == SIGFPE) { | 201 } else if (signal == SIGFPE) { |
205 if (info->si_code == FPE_FLTDIV) | 202 if (info->si_code == FPE_FLTDIV) |
206 PrintToStderr(" FPE_FLTDIV "); | 203 PrintToStderr("FPE_FLTDIV "); |
207 else if (info->si_code == FPE_FLTINV) | 204 else if (info->si_code == FPE_FLTINV) |
208 PrintToStderr(" FPE_FLTINV "); | 205 PrintToStderr("FPE_FLTINV "); |
209 else if (info->si_code == FPE_FLTOVF) | 206 else if (info->si_code == FPE_FLTOVF) |
210 PrintToStderr(" FPE_FLTOVF "); | 207 PrintToStderr("FPE_FLTOVF "); |
211 else if (info->si_code == FPE_FLTRES) | 208 else if (info->si_code == FPE_FLTRES) |
212 PrintToStderr(" FPE_FLTRES "); | 209 PrintToStderr("FPE_FLTRES "); |
213 else if (info->si_code == FPE_FLTSUB) | 210 else if (info->si_code == FPE_FLTSUB) |
214 PrintToStderr(" FPE_FLTSUB "); | 211 PrintToStderr("FPE_FLTSUB "); |
215 else if (info->si_code == FPE_FLTUND) | 212 else if (info->si_code == FPE_FLTUND) |
216 PrintToStderr(" FPE_FLTUND "); | 213 PrintToStderr("FPE_FLTUND "); |
217 else if (info->si_code == FPE_INTDIV) | 214 else if (info->si_code == FPE_INTDIV) |
218 PrintToStderr(" FPE_INTDIV "); | 215 PrintToStderr("FPE_INTDIV "); |
219 else if (info->si_code == FPE_INTOVF) | 216 else if (info->si_code == FPE_INTOVF) |
220 PrintToStderr(" FPE_INTOVF "); | 217 PrintToStderr("FPE_INTOVF "); |
221 else | 218 else |
222 PrintToStderr(" <unknown> "); | 219 PrintToStderr("<unknown> "); |
223 } else if (signal == SIGILL) { | 220 } else if (signal == SIGILL) { |
224 if (info->si_code == ILL_BADSTK) | 221 if (info->si_code == ILL_BADSTK) |
225 PrintToStderr(" ILL_BADSTK "); | 222 PrintToStderr("ILL_BADSTK "); |
226 else if (info->si_code == ILL_COPROC) | 223 else if (info->si_code == ILL_COPROC) |
227 PrintToStderr(" ILL_COPROC "); | 224 PrintToStderr("ILL_COPROC "); |
228 else if (info->si_code == ILL_ILLOPN) | 225 else if (info->si_code == ILL_ILLOPN) |
229 PrintToStderr(" ILL_ILLOPN "); | 226 PrintToStderr("ILL_ILLOPN "); |
230 else if (info->si_code == ILL_ILLADR) | 227 else if (info->si_code == ILL_ILLADR) |
231 PrintToStderr(" ILL_ILLADR "); | 228 PrintToStderr("ILL_ILLADR "); |
232 else if (info->si_code == ILL_ILLTRP) | 229 else if (info->si_code == ILL_ILLTRP) |
233 PrintToStderr(" ILL_ILLTRP "); | 230 PrintToStderr("ILL_ILLTRP "); |
234 else if (info->si_code == ILL_PRVOPC) | 231 else if (info->si_code == ILL_PRVOPC) |
235 PrintToStderr(" ILL_PRVOPC "); | 232 PrintToStderr("ILL_PRVOPC "); |
236 else if (info->si_code == ILL_PRVREG) | 233 else if (info->si_code == ILL_PRVREG) |
237 PrintToStderr(" ILL_PRVREG "); | 234 PrintToStderr("ILL_PRVREG "); |
238 else | 235 else |
239 PrintToStderr(" <unknown> "); | 236 PrintToStderr("<unknown> "); |
240 } else if (signal == SIGSEGV) { | 237 } else if (signal == SIGSEGV) { |
241 if (info->si_code == SEGV_MAPERR) | 238 if (info->si_code == SEGV_MAPERR) |
242 PrintToStderr(" SEGV_MAPERR "); | 239 PrintToStderr("SEGV_MAPERR "); |
243 else if (info->si_code == SEGV_ACCERR) | 240 else if (info->si_code == SEGV_ACCERR) |
244 PrintToStderr(" SEGV_ACCERR "); | 241 PrintToStderr("SEGV_ACCERR "); |
245 else | 242 else |
246 PrintToStderr(" <unknown> "); | 243 PrintToStderr("<unknown> "); |
247 } | 244 } |
248 if (signal == SIGBUS || signal == SIGFPE || | 245 if (signal == SIGBUS || signal == SIGFPE || |
249 signal == SIGILL || signal == SIGSEGV) { | 246 signal == SIGILL || signal == SIGSEGV) { |
250 internal::itoa_r(reinterpret_cast<intptr_t>(info->si_addr), | 247 Format(buf, "%12x", reinterpret_cast<intptr_t>(info->si_addr)); |
251 buf, sizeof(buf), 16, 12); | |
252 PrintToStderr(buf); | 248 PrintToStderr(buf); |
253 } | 249 } |
254 PrintToStderr("\n"); | 250 PrintToStderr("\n"); |
255 | 251 |
256 debug::StackTrace().PrintBacktrace(); | 252 debug::StackTrace().PrintBacktrace(); |
257 | 253 |
258 #if defined(OS_LINUX) | 254 #if defined(OS_LINUX) |
259 #if ARCH_CPU_X86_FAMILY | 255 #if ARCH_CPU_X86_FAMILY |
260 ucontext_t* context = reinterpret_cast<ucontext_t*>(void_context); | 256 ucontext_t* context = reinterpret_cast<ucontext_t*>(void_context); |
261 const struct { | 257 const struct { |
262 const char* label; | 258 const char* label; |
263 greg_t value; | 259 greg_t value; |
264 } registers[] = { | 260 } registers[] = { |
265 #if ARCH_CPU_32_BITS | 261 #if ARCH_CPU_32_BITS |
266 { " gs: ", context->uc_mcontext.gregs[REG_GS] }, | 262 { "gs", context->uc_mcontext.gregs[REG_GS] }, |
267 { " fs: ", context->uc_mcontext.gregs[REG_FS] }, | 263 { "fs", context->uc_mcontext.gregs[REG_FS] }, |
268 { " es: ", context->uc_mcontext.gregs[REG_ES] }, | 264 { "es", context->uc_mcontext.gregs[REG_ES] }, |
269 { " ds: ", context->uc_mcontext.gregs[REG_DS] }, | 265 { "ds", context->uc_mcontext.gregs[REG_DS] }, |
270 { " edi: ", context->uc_mcontext.gregs[REG_EDI] }, | 266 { "edi", context->uc_mcontext.gregs[REG_EDI] }, |
271 { " esi: ", context->uc_mcontext.gregs[REG_ESI] }, | 267 { "esi", context->uc_mcontext.gregs[REG_ESI] }, |
272 { " ebp: ", context->uc_mcontext.gregs[REG_EBP] }, | 268 { "ebp", context->uc_mcontext.gregs[REG_EBP] }, |
273 { " esp: ", context->uc_mcontext.gregs[REG_ESP] }, | 269 { "esp", context->uc_mcontext.gregs[REG_ESP] }, |
274 { " ebx: ", context->uc_mcontext.gregs[REG_EBX] }, | 270 { "ebx", context->uc_mcontext.gregs[REG_EBX] }, |
275 { " edx: ", context->uc_mcontext.gregs[REG_EDX] }, | 271 { "edx", context->uc_mcontext.gregs[REG_EDX] }, |
276 { " ecx: ", context->uc_mcontext.gregs[REG_ECX] }, | 272 { "ecx", context->uc_mcontext.gregs[REG_ECX] }, |
277 { " eax: ", context->uc_mcontext.gregs[REG_EAX] }, | 273 { "eax", context->uc_mcontext.gregs[REG_EAX] }, |
278 { " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] }, | 274 { "trp", context->uc_mcontext.gregs[REG_TRAPNO] }, |
279 { " err: ", context->uc_mcontext.gregs[REG_ERR] }, | 275 { "err", context->uc_mcontext.gregs[REG_ERR] }, |
280 { " ip: ", context->uc_mcontext.gregs[REG_EIP] }, | 276 { "ip", context->uc_mcontext.gregs[REG_EIP] }, |
281 { " cs: ", context->uc_mcontext.gregs[REG_CS] }, | 277 { "cs", context->uc_mcontext.gregs[REG_CS] }, |
282 { " efl: ", context->uc_mcontext.gregs[REG_EFL] }, | 278 { "efl", context->uc_mcontext.gregs[REG_EFL] }, |
283 { " usp: ", context->uc_mcontext.gregs[REG_UESP] }, | 279 { "usp", context->uc_mcontext.gregs[REG_UESP] }, |
284 { " ss: ", context->uc_mcontext.gregs[REG_SS] }, | 280 { "ss", context->uc_mcontext.gregs[REG_SS] }, |
285 #elif ARCH_CPU_64_BITS | 281 #elif ARCH_CPU_64_BITS |
286 { " r8: ", context->uc_mcontext.gregs[REG_R8] }, | 282 { "r8", context->uc_mcontext.gregs[REG_R8] }, |
287 { " r9: ", context->uc_mcontext.gregs[REG_R9] }, | 283 { "r9", context->uc_mcontext.gregs[REG_R9] }, |
288 { " r10: ", context->uc_mcontext.gregs[REG_R10] }, | 284 { "r10", context->uc_mcontext.gregs[REG_R10] }, |
289 { " r11: ", context->uc_mcontext.gregs[REG_R11] }, | 285 { "r11", context->uc_mcontext.gregs[REG_R11] }, |
290 { " r12: ", context->uc_mcontext.gregs[REG_R12] }, | 286 { "r12", context->uc_mcontext.gregs[REG_R12] }, |
291 { " r13: ", context->uc_mcontext.gregs[REG_R13] }, | 287 { "r13", context->uc_mcontext.gregs[REG_R13] }, |
292 { " r14: ", context->uc_mcontext.gregs[REG_R14] }, | 288 { "r14", context->uc_mcontext.gregs[REG_R14] }, |
293 { " r15: ", context->uc_mcontext.gregs[REG_R15] }, | 289 { "r15", context->uc_mcontext.gregs[REG_R15] }, |
294 { " di: ", context->uc_mcontext.gregs[REG_RDI] }, | 290 { "di", context->uc_mcontext.gregs[REG_RDI] }, |
295 { " si: ", context->uc_mcontext.gregs[REG_RSI] }, | 291 { "si", context->uc_mcontext.gregs[REG_RSI] }, |
296 { " bp: ", context->uc_mcontext.gregs[REG_RBP] }, | 292 { "bp", context->uc_mcontext.gregs[REG_RBP] }, |
297 { " bx: ", context->uc_mcontext.gregs[REG_RBX] }, | 293 { "bx", context->uc_mcontext.gregs[REG_RBX] }, |
298 { " dx: ", context->uc_mcontext.gregs[REG_RDX] }, | 294 { "dx", context->uc_mcontext.gregs[REG_RDX] }, |
299 { " ax: ", context->uc_mcontext.gregs[REG_RAX] }, | 295 { "ax", context->uc_mcontext.gregs[REG_RAX] }, |
300 { " cx: ", context->uc_mcontext.gregs[REG_RCX] }, | 296 { "cx", context->uc_mcontext.gregs[REG_RCX] }, |
301 { " sp: ", context->uc_mcontext.gregs[REG_RSP] }, | 297 { "sp", context->uc_mcontext.gregs[REG_RSP] }, |
302 { " ip: ", context->uc_mcontext.gregs[REG_RIP] }, | 298 { "ip", context->uc_mcontext.gregs[REG_RIP] }, |
303 { " efl: ", context->uc_mcontext.gregs[REG_EFL] }, | 299 { "efl", context->uc_mcontext.gregs[REG_EFL] }, |
304 { " cgf: ", context->uc_mcontext.gregs[REG_CSGSFS] }, | 300 { "cgf", context->uc_mcontext.gregs[REG_CSGSFS] }, |
305 { " erf: ", context->uc_mcontext.gregs[REG_ERR] }, | 301 { "erf", context->uc_mcontext.gregs[REG_ERR] }, |
306 { " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] }, | 302 { "trp", context->uc_mcontext.gregs[REG_TRAPNO] }, |
307 { " msk: ", context->uc_mcontext.gregs[REG_OLDMASK] }, | 303 { "msk", context->uc_mcontext.gregs[REG_OLDMASK] }, |
308 { " cr2: ", context->uc_mcontext.gregs[REG_CR2] }, | 304 { "cr2", context->uc_mcontext.gregs[REG_CR2] }, |
309 #endif | 305 #endif |
310 }; | 306 }; |
311 | 307 |
312 #if ARCH_CPU_32_BITS | 308 #if ARCH_CPU_32_BITS |
313 const int kRegisterPadding = 8; | 309 #define K_REGISTER_PADDING "8" |
314 #elif ARCH_CPU_64_BITS | 310 #elif ARCH_CPU_64_BITS |
315 const int kRegisterPadding = 16; | 311 #define K_REGISTER_PADDING "16" |
316 #endif | 312 #endif |
317 | 313 |
318 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(registers); i++) { | 314 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(registers); i++) { |
319 PrintToStderr(registers[i].label); | 315 Format(buf, "%4s: %"K_REGISTER_PADDING"x%s", |
320 internal::itoa_r(registers[i].value, buf, sizeof(buf), | 316 registers[i].label, |
321 16, kRegisterPadding); | 317 registers[i].value, |
| 318 (i + 1) % 4 == 0 ? "\n" : ""); |
322 PrintToStderr(buf); | 319 PrintToStderr(buf); |
323 | |
324 if ((i + 1) % 4 == 0) | |
325 PrintToStderr("\n"); | |
326 } | 320 } |
327 PrintToStderr("\n"); | 321 PrintToStderr("\n"); |
328 #endif | 322 #endif |
329 #elif defined(OS_MACOSX) | 323 #elif defined(OS_MACOSX) |
330 // TODO(shess): Port to 64-bit. | 324 // TODO(shess): Port to 64-bit. |
331 #if ARCH_CPU_X86_FAMILY && ARCH_CPU_32_BITS | 325 #if ARCH_CPU_X86_FAMILY && ARCH_CPU_32_BITS |
332 ucontext_t* context = reinterpret_cast<ucontext_t*>(void_context); | 326 ucontext_t* context = reinterpret_cast<ucontext_t*>(void_context); |
333 size_t len; | 327 size_t len; |
334 | 328 |
335 // NOTE: Even |snprintf()| is not on the approved list for signal | 329 // NOTE: Even |snprintf()| is not on the approved list for signal |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
480 | 474 |
481 PrintBacktraceOutputHandler handler; | 475 PrintBacktraceOutputHandler handler; |
482 ProcessBacktrace(trace_, count_, &handler); | 476 ProcessBacktrace(trace_, count_, &handler); |
483 } | 477 } |
484 | 478 |
485 void StackTrace::OutputToStream(std::ostream* os) const { | 479 void StackTrace::OutputToStream(std::ostream* os) const { |
486 StreamBacktraceOutputHandler handler(os); | 480 StreamBacktraceOutputHandler handler(os); |
487 ProcessBacktrace(trace_, count_, &handler); | 481 ProcessBacktrace(trace_, count_, &handler); |
488 } | 482 } |
489 | 483 |
490 namespace internal { | |
491 | |
492 // NOTE: code from sandbox/linux/seccomp-bpf/demo.cc. | |
493 char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) { | |
494 // Make sure we can write at least one NUL byte. | |
495 size_t n = 1; | |
496 if (n > sz) | |
497 return NULL; | |
498 | |
499 if (base < 2 || base > 16) { | |
500 buf[0] = '\000'; | |
501 return NULL; | |
502 } | |
503 | |
504 char *start = buf; | |
505 | |
506 uintptr_t j = i; | |
507 | |
508 // Handle negative numbers (only for base 10). | |
509 if (i < 0 && base == 10) { | |
510 j = -i; | |
511 | |
512 // Make sure we can write the '-' character. | |
513 if (++n > sz) { | |
514 buf[0] = '\000'; | |
515 return NULL; | |
516 } | |
517 *start++ = '-'; | |
518 } | |
519 | |
520 // Loop until we have converted the entire number. Output at least one | |
521 // character (i.e. '0'). | |
522 char *ptr = start; | |
523 do { | |
524 // Make sure there is still enough space left in our output buffer. | |
525 if (++n > sz) { | |
526 buf[0] = '\000'; | |
527 return NULL; | |
528 } | |
529 | |
530 // Output the next digit. | |
531 *ptr++ = "0123456789abcdef"[j % base]; | |
532 j /= base; | |
533 | |
534 if (padding > 0) | |
535 padding--; | |
536 } while (j > 0 || padding > 0); | |
537 | |
538 // Terminate the output with a NUL character. | |
539 *ptr = '\000'; | |
540 | |
541 // Conversion to ASCII actually resulted in the digits being in reverse | |
542 // order. We can't easily generate them in forward order, as we can't tell | |
543 // the number of characters needed until we are done converting. | |
544 // So, now, we reverse the string (except for the possible "-" sign). | |
545 while (--ptr > start) { | |
546 char ch = *ptr; | |
547 *ptr = *start; | |
548 *start++ = ch; | |
549 } | |
550 return buf; | |
551 } | |
552 | |
553 } // namespace internal | |
554 | |
555 } // namespace debug | 484 } // namespace debug |
556 } // namespace base | 485 } // namespace base |
OLD | NEW |