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