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 |