Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: base/debug/stack_trace_posix.cc

Issue 11745003: GTTF: dump registers on crash on 64-bit Linux (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/debug/stack_trace.h ('k') | base/debug/stack_trace_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « base/debug/stack_trace.h ('k') | base/debug/stack_trace_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698