diff options
Diffstat (limited to 'src/client/linux/microdump_writer')
3 files changed, 104 insertions, 41 deletions
diff --git a/src/client/linux/microdump_writer/microdump_writer.cc b/src/client/linux/microdump_writer/microdump_writer.cc index e14f9754..f45925fe 100644 --- a/src/client/linux/microdump_writer/microdump_writer.cc +++ b/src/client/linux/microdump_writer/microdump_writer.cc @@ -60,6 +60,8 @@ class MicrodumpWriter { public: MicrodumpWriter(const ExceptionHandler::CrashContext* context, const MappingList& mappings, + const char* build_fingerprint, + const char* product_info, LinuxDumper* dumper) : ucontext_(context ? &context->context : NULL), #if !defined(__ARM_EABI__) && !defined(__mips__) @@ -67,6 +69,8 @@ class MicrodumpWriter { #endif dumper_(dumper), mapping_list_(mappings), + build_fingerprint_(build_fingerprint), + product_info_(product_info), log_line_(NULL) { log_line_ = reinterpret_cast<char*>(Alloc(kLineBufferSize)); if (log_line_) @@ -88,9 +92,9 @@ class MicrodumpWriter { bool Dump() { bool success; LogLine("-----BEGIN BREAKPAD MICRODUMP-----"); - success = DumpOSInformation(); - if (success) - success = DumpCrashingThread(); + DumpProductInformation(); + DumpOSInformation(); + success = DumpCrashingThread(); if (success) success = DumpMappings(); LogLine("-----END BREAKPAD MICRODUMP-----"); @@ -143,10 +147,17 @@ class MicrodumpWriter { my_strlcpy(log_line_, "", kLineBufferSize); } - bool DumpOSInformation() { - struct utsname uts; - if (uname(&uts)) - return false; + void DumpProductInformation() { + LogAppend("V "); + if (product_info_) { + LogAppend(product_info_); + } else { + LogAppend("UNKNOWN:0.0.0.0"); + } + LogCommitLine(); + } + + void DumpOSInformation() { const uint8_t n_cpus = static_cast<uint8_t>(sysconf(_SC_NPROCESSORS_CONF)); #if defined(__ANDROID__) @@ -178,13 +189,23 @@ class MicrodumpWriter { LogAppend(" "); LogAppend(n_cpus); LogAppend(" "); - LogAppend(uts.machine); - LogAppend(" "); - LogAppend(uts.release); - LogAppend(" "); - LogAppend(uts.version); + // If the client has attached a build fingerprint to the MinidumpDescriptor + // use that one. Otherwise try to get some basic info from uname(). + if (build_fingerprint_) { + LogAppend(build_fingerprint_); + } else { + struct utsname uts; + if (uname(&uts) == 0) { + LogAppend(uts.machine); + LogAppend(" "); + LogAppend(uts.release); + LogAppend(" "); + LogAppend(uts.version); + } else { + LogAppend("no build fingerprint available"); + } + } LogCommitLine(); - return true; } bool DumpThreadStack(uint32_t thread_id, @@ -367,6 +388,8 @@ class MicrodumpWriter { #endif LinuxDumper* dumper_; const MappingList& mapping_list_; + const char* const build_fingerprint_; + const char* const product_info_; char* log_line_; }; } // namespace @@ -376,7 +399,9 @@ namespace google_breakpad { bool WriteMicrodump(pid_t crashing_process, const void* blob, size_t blob_size, - const MappingList& mappings) { + const MappingList& mappings, + const char* build_fingerprint, + const char* product_info) { LinuxPtraceDumper dumper(crashing_process); const ExceptionHandler::CrashContext* context = NULL; if (blob) { @@ -388,7 +413,8 @@ bool WriteMicrodump(pid_t crashing_process, dumper.set_crash_signal(context->siginfo.si_signo); dumper.set_crash_thread(context->tid); } - MicrodumpWriter writer(context, mappings, &dumper); + MicrodumpWriter writer(context, mappings, build_fingerprint, product_info, + &dumper); if (!writer.Init()) return false; return writer.Dump(); diff --git a/src/client/linux/microdump_writer/microdump_writer.h b/src/client/linux/microdump_writer/microdump_writer.h index 3c19f3d0..e2185583 100644 --- a/src/client/linux/microdump_writer/microdump_writer.h +++ b/src/client/linux/microdump_writer/microdump_writer.h @@ -46,12 +46,18 @@ namespace google_breakpad { // blob: a blob of data from the crashing process. See exception_handler.h // blob_size: the length of |blob| in bytes. // mappings: a list of additional mappings provided by the application. +// build_fingerprint: a (optional) C string which determines the OS +// build fingerprint (e.g., aosp/occam/mako:5.1.1/LMY47W/1234:eng/dev-keys). +// product_info: a (optional) C string which determines the product name and +// version (e.g., WebView:42.0.2311.136). // // Returns true iff successful. bool WriteMicrodump(pid_t crashing_process, const void* blob, size_t blob_size, - const MappingList& mappings); + const MappingList& mappings, + const char* build_fingerprint, + const char* product_info); } // namespace google_breakpad diff --git a/src/client/linux/microdump_writer/microdump_writer_unittest.cc b/src/client/linux/microdump_writer/microdump_writer_unittest.cc index 52b1d9a9..1fa6f1ff 100644 --- a/src/client/linux/microdump_writer/microdump_writer_unittest.cc +++ b/src/client/linux/microdump_writer/microdump_writer_unittest.cc @@ -48,7 +48,11 @@ namespace { typedef testing::Test MicrodumpWriterTest; -TEST(MicrodumpWriterTest, Setup) { +void CrashAndGetMicrodump( + const MappingList& mappings, + const char* build_fingerprint, + const char* product_info, + scoped_array<char>* buf) { int fds[2]; ASSERT_NE(-1, pipe(fds)); @@ -73,6 +77,36 @@ TEST(MicrodumpWriterTest, Setup) { // Set a non-zero tid to avoid tripping asserts. context.tid = child; + // Redirect temporarily stderr to the stderr.log file. + int save_err = dup(STDERR_FILENO); + ASSERT_NE(-1, save_err); + ASSERT_NE(-1, dup2(err_fd, STDERR_FILENO)); + + ASSERT_TRUE(WriteMicrodump(child, &context, sizeof(context), mappings, + build_fingerprint, product_info)); + + // Revert stderr back to the console. + dup2(save_err, STDERR_FILENO); + close(save_err); + + // Read back the stderr file and check for the microdump marker. + fsync(err_fd); + lseek(err_fd, 0, SEEK_SET); + const size_t kBufSize = 64 * 1024; + buf->reset(new char[kBufSize]); + ASSERT_GT(read(err_fd, buf->get(), kBufSize), 0); + + close(err_fd); + close(fds[1]); + + ASSERT_NE(static_cast<char*>(0), strstr( + buf->get(), "-----BEGIN BREAKPAD MICRODUMP-----")); + ASSERT_NE(static_cast<char*>(0), strstr( + buf->get(), "-----END BREAKPAD MICRODUMP-----")); + +} + +TEST(MicrodumpWriterTest, BasicWithMappings) { // Push some extra mapping to check the MappingList logic. const uint32_t memory_size = sysconf(_SC_PAGESIZE); const char* kMemoryName = "libfoo.so"; @@ -93,28 +127,8 @@ TEST(MicrodumpWriterTest, Setup) { memcpy(mapping.second, kModuleGUID, sizeof(MDGUID)); mappings.push_back(mapping); - // Redirect temporarily stderr to the stderr.log file. - int save_err = dup(STDERR_FILENO); - ASSERT_NE(-1, save_err); - ASSERT_NE(-1, dup2(err_fd, STDERR_FILENO)); - - ASSERT_TRUE(WriteMicrodump(child, &context, sizeof(context), mappings)); - - // Revert stderr back to the console. - dup2(save_err, STDERR_FILENO); - close(save_err); - - // Read back the stderr file and check for the microdump marker. - fsync(err_fd); - lseek(err_fd, 0, SEEK_SET); - const size_t kBufSize = 64 * 1024; - scoped_array<char> buf(new char[kBufSize]); - ASSERT_GT(read(err_fd, buf.get(), kBufSize), 0); - - ASSERT_NE(static_cast<char*>(0), strstr( - buf.get(), "-----BEGIN BREAKPAD MICRODUMP-----")); - ASSERT_NE(static_cast<char*>(0), strstr( - buf.get(), "-----END BREAKPAD MICRODUMP-----")); + scoped_array<char> buf; + CrashAndGetMicrodump(mappings, NULL, NULL, &buf); #ifdef __LP64__ ASSERT_NE(static_cast<char*>(0), strstr( @@ -126,8 +140,25 @@ TEST(MicrodumpWriterTest, Setup) { "33221100554477668899AABBCCDDEEFF0 libfoo.so")); #endif - close(err_fd); - close(fds[1]); + // In absence of a product info in the minidump, the writer should just write + // an unknown marker. + ASSERT_NE(static_cast<char*>(0), strstr( + buf.get(), "V UNKNOWN:0.0.0.0")); +} + +// Ensure that the product info and build fingerprint metadata show up in the +// final microdump if present. +TEST(MicrodumpWriterTest, BuildFingerprintAndProductInfo) { + const char kProductInfo[] = "MockProduct:42.0.2311.99"; + const char kBuildFingerprint[] = + "aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys"; + scoped_array<char> buf; + MappingList no_mappings; + + CrashAndGetMicrodump(no_mappings, kBuildFingerprint, kProductInfo, &buf); + + ASSERT_NE(static_cast<char*>(0), strstr(buf.get(), kBuildFingerprint)); + ASSERT_NE(static_cast<char*>(0), strstr(buf.get(), kProductInfo)); } } // namespace |