| 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 |