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 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 using google_breakpad::SeccompUnwinder; | 53 using google_breakpad::SeccompUnwinder; |
54 using google_breakpad::ThreadInfo; | 54 using google_breakpad::ThreadInfo; |
55 using google_breakpad::UContextReader; | 55 using google_breakpad::UContextReader; |
56 | 56 |
57 const size_t kLineBufferSize = 2048; | 57 const size_t kLineBufferSize = 2048; |
58 | 58 |
59 class MicrodumpWriter { | 59 class MicrodumpWriter { |
60 public: | 60 public: |
61 MicrodumpWriter(const ExceptionHandler::CrashContext* context, | 61 MicrodumpWriter(const ExceptionHandler::CrashContext* context, |
62 const MappingList& mappings, | 62 const MappingList& mappings, |
| 63 const char* build_fingerprint, |
| 64 const char* product_info, |
63 LinuxDumper* dumper) | 65 LinuxDumper* dumper) |
64 : ucontext_(context ? &context->context : NULL), | 66 : ucontext_(context ? &context->context : NULL), |
65 #if !defined(__ARM_EABI__) && !defined(__mips__) | 67 #if !defined(__ARM_EABI__) && !defined(__mips__) |
66 float_state_(context ? &context->float_state : NULL), | 68 float_state_(context ? &context->float_state : NULL), |
67 #endif | 69 #endif |
68 dumper_(dumper), | 70 dumper_(dumper), |
69 mapping_list_(mappings), | 71 mapping_list_(mappings), |
| 72 build_fingerprint_(build_fingerprint), |
| 73 product_info_(product_info), |
70 log_line_(NULL) { | 74 log_line_(NULL) { |
71 log_line_ = reinterpret_cast<char*>(Alloc(kLineBufferSize)); | 75 log_line_ = reinterpret_cast<char*>(Alloc(kLineBufferSize)); |
72 if (log_line_) | 76 if (log_line_) |
73 log_line_[0] = '\0'; // Clear out the log line buffer. | 77 log_line_[0] = '\0'; // Clear out the log line buffer. |
74 } | 78 } |
75 | 79 |
76 ~MicrodumpWriter() { dumper_->ThreadsResume(); } | 80 ~MicrodumpWriter() { dumper_->ThreadsResume(); } |
77 | 81 |
78 bool Init() { | 82 bool Init() { |
79 // In the exceptional case where the system was out of memory and there | 83 // In the exceptional case where the system was out of memory and there |
80 // wasn't even room to allocate the line buffer, bail out. There is nothing | 84 // wasn't even room to allocate the line buffer, bail out. There is nothing |
81 // useful we can possibly achieve without the ability to Log. At least let's | 85 // useful we can possibly achieve without the ability to Log. At least let's |
82 // try to not crash. | 86 // try to not crash. |
83 if (!dumper_->Init() || !log_line_) | 87 if (!dumper_->Init() || !log_line_) |
84 return false; | 88 return false; |
85 return dumper_->ThreadsSuspend(); | 89 return dumper_->ThreadsSuspend(); |
86 } | 90 } |
87 | 91 |
88 bool Dump() { | 92 bool Dump() { |
89 bool success; | 93 bool success; |
90 LogLine("-----BEGIN BREAKPAD MICRODUMP-----"); | 94 LogLine("-----BEGIN BREAKPAD MICRODUMP-----"); |
91 success = DumpOSInformation(); | 95 DumpProductInformation(); |
92 if (success) | 96 DumpOSInformation(); |
93 success = DumpCrashingThread(); | 97 success = DumpCrashingThread(); |
94 if (success) | 98 if (success) |
95 success = DumpMappings(); | 99 success = DumpMappings(); |
96 LogLine("-----END BREAKPAD MICRODUMP-----"); | 100 LogLine("-----END BREAKPAD MICRODUMP-----"); |
97 dumper_->ThreadsResume(); | 101 dumper_->ThreadsResume(); |
98 return success; | 102 return success; |
99 } | 103 } |
100 | 104 |
101 private: | 105 private: |
102 // Writes one line to the system log. | 106 // Writes one line to the system log. |
103 void LogLine(const char* msg) { | 107 void LogLine(const char* msg) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 for (size_t i = 0; i < length; ++i, ++ptr) | 140 for (size_t i = 0; i < length; ++i, ++ptr) |
137 LogAppend(*ptr); | 141 LogAppend(*ptr); |
138 } | 142 } |
139 | 143 |
140 // Writes out the current line buffer on the system log. | 144 // Writes out the current line buffer on the system log. |
141 void LogCommitLine() { | 145 void LogCommitLine() { |
142 LogLine(log_line_); | 146 LogLine(log_line_); |
143 my_strlcpy(log_line_, "", kLineBufferSize); | 147 my_strlcpy(log_line_, "", kLineBufferSize); |
144 } | 148 } |
145 | 149 |
146 bool DumpOSInformation() { | 150 void DumpProductInformation() { |
147 struct utsname uts; | 151 LogAppend("V "); |
148 if (uname(&uts)) | 152 if (product_info_) { |
149 return false; | 153 LogAppend(product_info_); |
| 154 } else { |
| 155 LogAppend("UNKNOWN:0.0.0.0"); |
| 156 } |
| 157 LogCommitLine(); |
| 158 } |
| 159 |
| 160 void DumpOSInformation() { |
150 const uint8_t n_cpus = static_cast<uint8_t>(sysconf(_SC_NPROCESSORS_CONF)); | 161 const uint8_t n_cpus = static_cast<uint8_t>(sysconf(_SC_NPROCESSORS_CONF)); |
151 | 162 |
152 #if defined(__ANDROID__) | 163 #if defined(__ANDROID__) |
153 const char kOSId[] = "A"; | 164 const char kOSId[] = "A"; |
154 #else | 165 #else |
155 const char kOSId[] = "L"; | 166 const char kOSId[] = "L"; |
156 #endif | 167 #endif |
157 | 168 |
158 // We cannot depend on uts.machine. On multiarch devices it always returns the | 169 // We cannot depend on uts.machine. On multiarch devices it always returns the |
159 // primary arch, not the one that match the executable being run. | 170 // primary arch, not the one that match the executable being run. |
(...skipping 11 matching lines...) Expand all Loading... |
171 #error "This code has not been ported to your platform yet" | 182 #error "This code has not been ported to your platform yet" |
172 #endif | 183 #endif |
173 | 184 |
174 LogAppend("O "); | 185 LogAppend("O "); |
175 LogAppend(kOSId); | 186 LogAppend(kOSId); |
176 LogAppend(" "); | 187 LogAppend(" "); |
177 LogAppend(kArch); | 188 LogAppend(kArch); |
178 LogAppend(" "); | 189 LogAppend(" "); |
179 LogAppend(n_cpus); | 190 LogAppend(n_cpus); |
180 LogAppend(" "); | 191 LogAppend(" "); |
181 LogAppend(uts.machine); | 192 // If the client has attached a build fingerprint to the MinidumpDescriptor |
182 LogAppend(" "); | 193 // use that one. Otherwise try to get some basic info from uname(). |
183 LogAppend(uts.release); | 194 if (build_fingerprint_) { |
184 LogAppend(" "); | 195 LogAppend(build_fingerprint_); |
185 LogAppend(uts.version); | 196 } else { |
| 197 struct utsname uts; |
| 198 if (uname(&uts) == 0) { |
| 199 LogAppend(uts.machine); |
| 200 LogAppend(" "); |
| 201 LogAppend(uts.release); |
| 202 LogAppend(" "); |
| 203 LogAppend(uts.version); |
| 204 } else { |
| 205 LogAppend("no build fingerprint available"); |
| 206 } |
| 207 } |
186 LogCommitLine(); | 208 LogCommitLine(); |
187 return true; | |
188 } | 209 } |
189 | 210 |
190 bool DumpThreadStack(uint32_t thread_id, | 211 bool DumpThreadStack(uint32_t thread_id, |
191 uintptr_t stack_pointer, | 212 uintptr_t stack_pointer, |
192 int max_stack_len, | 213 int max_stack_len, |
193 uint8_t** stack_copy) { | 214 uint8_t** stack_copy) { |
194 *stack_copy = NULL; | 215 *stack_copy = NULL; |
195 const void* stack; | 216 const void* stack; |
196 size_t stack_len; | 217 size_t stack_len; |
197 | 218 |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
360 } | 381 } |
361 | 382 |
362 void* Alloc(unsigned bytes) { return dumper_->allocator()->Alloc(bytes); } | 383 void* Alloc(unsigned bytes) { return dumper_->allocator()->Alloc(bytes); } |
363 | 384 |
364 const struct ucontext* const ucontext_; | 385 const struct ucontext* const ucontext_; |
365 #if !defined(__ARM_EABI__) && !defined(__mips__) | 386 #if !defined(__ARM_EABI__) && !defined(__mips__) |
366 const google_breakpad::fpstate_t* const float_state_; | 387 const google_breakpad::fpstate_t* const float_state_; |
367 #endif | 388 #endif |
368 LinuxDumper* dumper_; | 389 LinuxDumper* dumper_; |
369 const MappingList& mapping_list_; | 390 const MappingList& mapping_list_; |
| 391 const char* const build_fingerprint_; |
| 392 const char* const product_info_; |
370 char* log_line_; | 393 char* log_line_; |
371 }; | 394 }; |
372 } // namespace | 395 } // namespace |
373 | 396 |
374 namespace google_breakpad { | 397 namespace google_breakpad { |
375 | 398 |
376 bool WriteMicrodump(pid_t crashing_process, | 399 bool WriteMicrodump(pid_t crashing_process, |
377 const void* blob, | 400 const void* blob, |
378 size_t blob_size, | 401 size_t blob_size, |
379 const MappingList& mappings) { | 402 const MappingList& mappings, |
| 403 const char* build_fingerprint, |
| 404 const char* product_info) { |
380 LinuxPtraceDumper dumper(crashing_process); | 405 LinuxPtraceDumper dumper(crashing_process); |
381 const ExceptionHandler::CrashContext* context = NULL; | 406 const ExceptionHandler::CrashContext* context = NULL; |
382 if (blob) { | 407 if (blob) { |
383 if (blob_size != sizeof(ExceptionHandler::CrashContext)) | 408 if (blob_size != sizeof(ExceptionHandler::CrashContext)) |
384 return false; | 409 return false; |
385 context = reinterpret_cast<const ExceptionHandler::CrashContext*>(blob); | 410 context = reinterpret_cast<const ExceptionHandler::CrashContext*>(blob); |
386 dumper.set_crash_address( | 411 dumper.set_crash_address( |
387 reinterpret_cast<uintptr_t>(context->siginfo.si_addr)); | 412 reinterpret_cast<uintptr_t>(context->siginfo.si_addr)); |
388 dumper.set_crash_signal(context->siginfo.si_signo); | 413 dumper.set_crash_signal(context->siginfo.si_signo); |
389 dumper.set_crash_thread(context->tid); | 414 dumper.set_crash_thread(context->tid); |
390 } | 415 } |
391 MicrodumpWriter writer(context, mappings, &dumper); | 416 MicrodumpWriter writer(context, mappings, build_fingerprint, product_info, |
| 417 &dumper); |
392 if (!writer.Init()) | 418 if (!writer.Init()) |
393 return false; | 419 return false; |
394 return writer.Dump(); | 420 return writer.Dump(); |
395 } | 421 } |
396 | 422 |
397 } // namespace google_breakpad | 423 } // namespace google_breakpad |
OLD | NEW |