OLD | NEW |
1 // Copyright (c) 2014, Google Inc. | 1 // Copyright (c) 2014, Google Inc. |
2 // All rights reserved. | 2 // All rights reserved. |
3 // | 3 // |
4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
6 // met: | 6 // met: |
7 // | 7 // |
8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
(...skipping 19 matching lines...) Expand all Loading... |
30 // This translation unit generates microdumps into the console (logcat on | 30 // This translation unit generates microdumps into the console (logcat on |
31 // Android). See crbug.com/410294 for more info and design docs. | 31 // Android). See crbug.com/410294 for more info and design docs. |
32 | 32 |
33 #include "client/linux/microdump_writer/microdump_writer.h" | 33 #include "client/linux/microdump_writer/microdump_writer.h" |
34 | 34 |
35 #include <sys/utsname.h> | 35 #include <sys/utsname.h> |
36 | 36 |
37 #include "client/linux/dump_writer_common/thread_info.h" | 37 #include "client/linux/dump_writer_common/thread_info.h" |
38 #include "client/linux/dump_writer_common/ucontext_reader.h" | 38 #include "client/linux/dump_writer_common/ucontext_reader.h" |
39 #include "client/linux/handler/exception_handler.h" | 39 #include "client/linux/handler/exception_handler.h" |
| 40 #include "client/linux/handler/microdump_extra_info.h" |
40 #include "client/linux/log/log.h" | 41 #include "client/linux/log/log.h" |
41 #include "client/linux/minidump_writer/linux_ptrace_dumper.h" | 42 #include "client/linux/minidump_writer/linux_ptrace_dumper.h" |
42 #include "common/linux/linux_libc_support.h" | 43 #include "common/linux/linux_libc_support.h" |
43 | 44 |
44 namespace { | 45 namespace { |
45 | 46 |
46 using google_breakpad::ExceptionHandler; | 47 using google_breakpad::ExceptionHandler; |
47 using google_breakpad::LinuxDumper; | 48 using google_breakpad::LinuxDumper; |
48 using google_breakpad::LinuxPtraceDumper; | 49 using google_breakpad::LinuxPtraceDumper; |
49 using google_breakpad::MappingInfo; | 50 using google_breakpad::MappingInfo; |
50 using google_breakpad::MappingList; | 51 using google_breakpad::MappingList; |
| 52 using google_breakpad::MicrodumpExtraInfo; |
51 using google_breakpad::RawContextCPU; | 53 using google_breakpad::RawContextCPU; |
52 using google_breakpad::ThreadInfo; | 54 using google_breakpad::ThreadInfo; |
53 using google_breakpad::UContextReader; | 55 using google_breakpad::UContextReader; |
54 | 56 |
55 const size_t kLineBufferSize = 2048; | 57 const size_t kLineBufferSize = 2048; |
56 | 58 |
57 class MicrodumpWriter { | 59 class MicrodumpWriter { |
58 public: | 60 public: |
59 MicrodumpWriter(const ExceptionHandler::CrashContext* context, | 61 MicrodumpWriter(const ExceptionHandler::CrashContext* context, |
60 const MappingList& mappings, | 62 const MappingList& mappings, |
61 const char* build_fingerprint, | 63 const MicrodumpExtraInfo& microdump_extra_info, |
62 const char* product_info, | |
63 LinuxDumper* dumper) | 64 LinuxDumper* dumper) |
64 : ucontext_(context ? &context->context : NULL), | 65 : ucontext_(context ? &context->context : NULL), |
65 #if !defined(__ARM_EABI__) && !defined(__mips__) | 66 #if !defined(__ARM_EABI__) && !defined(__mips__) |
66 float_state_(context ? &context->float_state : NULL), | 67 float_state_(context ? &context->float_state : NULL), |
67 #endif | 68 #endif |
68 dumper_(dumper), | 69 dumper_(dumper), |
69 mapping_list_(mappings), | 70 mapping_list_(mappings), |
70 build_fingerprint_(build_fingerprint), | 71 microdump_extra_info_(microdump_extra_info), |
71 product_info_(product_info), | |
72 log_line_(NULL) { | 72 log_line_(NULL) { |
73 log_line_ = reinterpret_cast<char*>(Alloc(kLineBufferSize)); | 73 log_line_ = reinterpret_cast<char*>(Alloc(kLineBufferSize)); |
74 if (log_line_) | 74 if (log_line_) |
75 log_line_[0] = '\0'; // Clear out the log line buffer. | 75 log_line_[0] = '\0'; // Clear out the log line buffer. |
76 } | 76 } |
77 | 77 |
78 ~MicrodumpWriter() { dumper_->ThreadsResume(); } | 78 ~MicrodumpWriter() { dumper_->ThreadsResume(); } |
79 | 79 |
80 bool Init() { | 80 bool Init() { |
81 // In the exceptional case where the system was out of memory and there | 81 // In the exceptional case where the system was out of memory and there |
82 // wasn't even room to allocate the line buffer, bail out. There is nothing | 82 // wasn't even room to allocate the line buffer, bail out. There is nothing |
83 // useful we can possibly achieve without the ability to Log. At least let's | 83 // useful we can possibly achieve without the ability to Log. At least let's |
84 // try to not crash. | 84 // try to not crash. |
85 if (!dumper_->Init() || !log_line_) | 85 if (!dumper_->Init() || !log_line_) |
86 return false; | 86 return false; |
87 return dumper_->ThreadsSuspend() && dumper_->LateInit(); | 87 return dumper_->ThreadsSuspend() && dumper_->LateInit(); |
88 } | 88 } |
89 | 89 |
90 bool Dump() { | 90 bool Dump() { |
91 bool success; | 91 bool success; |
92 LogLine("-----BEGIN BREAKPAD MICRODUMP-----"); | 92 LogLine("-----BEGIN BREAKPAD MICRODUMP-----"); |
93 DumpProductInformation(); | 93 DumpProductInformation(); |
94 DumpOSInformation(); | 94 DumpOSInformation(); |
| 95 DumpGPUInformation(); |
95 success = DumpCrashingThread(); | 96 success = DumpCrashingThread(); |
96 if (success) | 97 if (success) |
97 success = DumpMappings(); | 98 success = DumpMappings(); |
98 LogLine("-----END BREAKPAD MICRODUMP-----"); | 99 LogLine("-----END BREAKPAD MICRODUMP-----"); |
99 dumper_->ThreadsResume(); | 100 dumper_->ThreadsResume(); |
100 return success; | 101 return success; |
101 } | 102 } |
102 | 103 |
103 private: | 104 private: |
104 // Writes one line to the system log. | 105 // Writes one line to the system log. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 } | 143 } |
143 | 144 |
144 // Writes out the current line buffer on the system log. | 145 // Writes out the current line buffer on the system log. |
145 void LogCommitLine() { | 146 void LogCommitLine() { |
146 LogLine(log_line_); | 147 LogLine(log_line_); |
147 my_strlcpy(log_line_, "", kLineBufferSize); | 148 my_strlcpy(log_line_, "", kLineBufferSize); |
148 } | 149 } |
149 | 150 |
150 void DumpProductInformation() { | 151 void DumpProductInformation() { |
151 LogAppend("V "); | 152 LogAppend("V "); |
152 if (product_info_) { | 153 if (microdump_extra_info_.product_info) { |
153 LogAppend(product_info_); | 154 LogAppend(microdump_extra_info_.product_info); |
154 } else { | 155 } else { |
155 LogAppend("UNKNOWN:0.0.0.0"); | 156 LogAppend("UNKNOWN:0.0.0.0"); |
156 } | 157 } |
157 LogCommitLine(); | 158 LogCommitLine(); |
158 } | 159 } |
159 | 160 |
160 void DumpOSInformation() { | 161 void DumpOSInformation() { |
161 const uint8_t n_cpus = static_cast<uint8_t>(sysconf(_SC_NPROCESSORS_CONF)); | 162 const uint8_t n_cpus = static_cast<uint8_t>(sysconf(_SC_NPROCESSORS_CONF)); |
162 | 163 |
163 #if defined(__ANDROID__) | 164 #if defined(__ANDROID__) |
(...skipping 29 matching lines...) Expand all Loading... |
193 | 194 |
194 // Dump the HW architecture (e.g., armv7l, aarch64). | 195 // Dump the HW architecture (e.g., armv7l, aarch64). |
195 struct utsname uts; | 196 struct utsname uts; |
196 const bool has_uts_info = (uname(&uts) == 0); | 197 const bool has_uts_info = (uname(&uts) == 0); |
197 const char* hwArch = has_uts_info ? uts.machine : "unknown_hw_arch"; | 198 const char* hwArch = has_uts_info ? uts.machine : "unknown_hw_arch"; |
198 LogAppend(hwArch); | 199 LogAppend(hwArch); |
199 LogAppend(" "); | 200 LogAppend(" "); |
200 | 201 |
201 // If the client has attached a build fingerprint to the MinidumpDescriptor | 202 // If the client has attached a build fingerprint to the MinidumpDescriptor |
202 // use that one. Otherwise try to get some basic info from uname(). | 203 // use that one. Otherwise try to get some basic info from uname(). |
203 if (build_fingerprint_) { | 204 if (microdump_extra_info_.build_fingerprint) { |
204 LogAppend(build_fingerprint_); | 205 LogAppend(microdump_extra_info_.build_fingerprint); |
205 } else if (has_uts_info) { | 206 } else if (has_uts_info) { |
206 LogAppend(uts.release); | 207 LogAppend(uts.release); |
207 LogAppend(" "); | 208 LogAppend(" "); |
208 LogAppend(uts.version); | 209 LogAppend(uts.version); |
209 } else { | 210 } else { |
210 LogAppend("no build fingerprint available"); | 211 LogAppend("no build fingerprint available"); |
211 } | 212 } |
212 LogCommitLine(); | 213 LogCommitLine(); |
213 } | 214 } |
214 | 215 |
| 216 void DumpGPUInformation() { |
| 217 LogAppend("G "); |
| 218 if (microdump_extra_info_.gpu_fingerprint) { |
| 219 LogAppend(microdump_extra_info_.gpu_fingerprint); |
| 220 } else { |
| 221 LogAppend("UNKNOWN"); |
| 222 } |
| 223 LogCommitLine(); |
| 224 } |
| 225 |
215 bool DumpThreadStack(uint32_t thread_id, | 226 bool DumpThreadStack(uint32_t thread_id, |
216 uintptr_t stack_pointer, | 227 uintptr_t stack_pointer, |
217 int max_stack_len, | 228 int max_stack_len, |
218 uint8_t** stack_copy) { | 229 uint8_t** stack_copy) { |
219 *stack_copy = NULL; | 230 *stack_copy = NULL; |
220 const void* stack; | 231 const void* stack; |
221 size_t stack_len; | 232 size_t stack_len; |
222 | 233 |
223 if (!dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) { | 234 if (!dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) { |
224 // The stack pointer might not be available. In this case we don't hard | 235 // The stack pointer might not be available. In this case we don't hard |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
383 } | 394 } |
384 | 395 |
385 void* Alloc(unsigned bytes) { return dumper_->allocator()->Alloc(bytes); } | 396 void* Alloc(unsigned bytes) { return dumper_->allocator()->Alloc(bytes); } |
386 | 397 |
387 const struct ucontext* const ucontext_; | 398 const struct ucontext* const ucontext_; |
388 #if !defined(__ARM_EABI__) && !defined(__mips__) | 399 #if !defined(__ARM_EABI__) && !defined(__mips__) |
389 const google_breakpad::fpstate_t* const float_state_; | 400 const google_breakpad::fpstate_t* const float_state_; |
390 #endif | 401 #endif |
391 LinuxDumper* dumper_; | 402 LinuxDumper* dumper_; |
392 const MappingList& mapping_list_; | 403 const MappingList& mapping_list_; |
393 const char* const build_fingerprint_; | 404 const MicrodumpExtraInfo microdump_extra_info_; |
394 const char* const product_info_; | |
395 char* log_line_; | 405 char* log_line_; |
396 }; | 406 }; |
397 } // namespace | 407 } // namespace |
398 | 408 |
399 namespace google_breakpad { | 409 namespace google_breakpad { |
400 | 410 |
401 bool WriteMicrodump(pid_t crashing_process, | 411 bool WriteMicrodump(pid_t crashing_process, |
402 const void* blob, | 412 const void* blob, |
403 size_t blob_size, | 413 size_t blob_size, |
404 const MappingList& mappings, | 414 const MappingList& mappings, |
405 const char* build_fingerprint, | 415 const MicrodumpExtraInfo& microdump_extra_info) { |
406 const char* product_info) { | |
407 LinuxPtraceDumper dumper(crashing_process); | 416 LinuxPtraceDumper dumper(crashing_process); |
408 const ExceptionHandler::CrashContext* context = NULL; | 417 const ExceptionHandler::CrashContext* context = NULL; |
409 if (blob) { | 418 if (blob) { |
410 if (blob_size != sizeof(ExceptionHandler::CrashContext)) | 419 if (blob_size != sizeof(ExceptionHandler::CrashContext)) |
411 return false; | 420 return false; |
412 context = reinterpret_cast<const ExceptionHandler::CrashContext*>(blob); | 421 context = reinterpret_cast<const ExceptionHandler::CrashContext*>(blob); |
413 dumper.set_crash_address( | 422 dumper.set_crash_address( |
414 reinterpret_cast<uintptr_t>(context->siginfo.si_addr)); | 423 reinterpret_cast<uintptr_t>(context->siginfo.si_addr)); |
415 dumper.set_crash_signal(context->siginfo.si_signo); | 424 dumper.set_crash_signal(context->siginfo.si_signo); |
416 dumper.set_crash_thread(context->tid); | 425 dumper.set_crash_thread(context->tid); |
417 } | 426 } |
418 MicrodumpWriter writer(context, mappings, build_fingerprint, product_info, | 427 MicrodumpWriter writer(context, mappings, microdump_extra_info, &dumper); |
419 &dumper); | |
420 if (!writer.Init()) | 428 if (!writer.Init()) |
421 return false; | 429 return false; |
422 return writer.Dump(); | 430 return writer.Dump(); |
423 } | 431 } |
424 | 432 |
425 } // namespace google_breakpad | 433 } // namespace google_breakpad |
OLD | NEW |