diff options
author | primiano@chromium.org <primiano@chromium.org> | 2015-05-15 08:43:01 +0000 |
---|---|---|
committer | primiano@chromium.org <primiano@chromium.org> | 2015-05-15 08:43:01 +0000 |
commit | 90cbb27528a69b9fb19d9f8a01f8fabc16e4a687 (patch) | |
tree | cde355f082391d9ba0b76d3cb89e2beb9c782576 /src/client/linux/microdump_writer | |
parent | Switch code review server to codereview.chromium.org. (diff) | |
download | breakpad-90cbb27528a69b9fb19d9f8a01f8fabc16e4a687.tar.xz |
[microdump] Add build fingerprint and product info metadata.
This is to add build fingerprint and product name/version to
microdumps. Conversely to what happens in the case of minidumps
with MIME fields, due to the nature of minidumps, extra metadata
cannot be reliably injected after the dump is completed.
This CL adds the plumbing to inject two optional fields plus the
corresponding tests.
BUG=chromium:410294
R=thestig@chromium.org
Review URL: https://codereview.chromium.org/1125153008
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1456 4c0a9323-5329-0410-9bdc-e9ce6186880e
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 |