From 0d53bdd43d36d9ff64715b9caa01d49b4649da77 Mon Sep 17 00:00:00 2001 From: Primiano Tucci Date: Mon, 28 Sep 2015 13:52:54 +0100 Subject: Add GPU fingerprint information to breakpad microdumps. Although strictly the GPU fingerprint is defined by the build fingerprint, there is not currently a straightforward mapping from build fingerprint to useful GPU / GL driver information. In order to aid debugging of WebView crashes that occur in GL drivers, and to better understand the range of drivers and versions for feature blacklisting purposes, it is useful to have GPU fingerprints in breakpad microdumps. Landing this patch on behalf of Tobias Sargeant BUG=chromium:536769 R=primiano@chromium.org, thestig@chromium.org Review URL: https://codereview.chromium.org/1334473003 . --- .../linux/microdump_writer/microdump_writer.cc | 36 ++++++---- .../linux/microdump_writer/microdump_writer.h | 5 +- .../microdump_writer/microdump_writer_unittest.cc | 80 ++++++++++++++++++---- 3 files changed, 91 insertions(+), 30 deletions(-) (limited to 'src/client/linux/microdump_writer') diff --git a/src/client/linux/microdump_writer/microdump_writer.cc b/src/client/linux/microdump_writer/microdump_writer.cc index d2eaa6ee..aa9f9413 100644 --- a/src/client/linux/microdump_writer/microdump_writer.cc +++ b/src/client/linux/microdump_writer/microdump_writer.cc @@ -37,6 +37,7 @@ #include "client/linux/dump_writer_common/thread_info.h" #include "client/linux/dump_writer_common/ucontext_reader.h" #include "client/linux/handler/exception_handler.h" +#include "client/linux/handler/microdump_extra_info.h" #include "client/linux/log/log.h" #include "client/linux/minidump_writer/linux_ptrace_dumper.h" #include "common/linux/linux_libc_support.h" @@ -48,6 +49,7 @@ using google_breakpad::LinuxDumper; using google_breakpad::LinuxPtraceDumper; using google_breakpad::MappingInfo; using google_breakpad::MappingList; +using google_breakpad::MicrodumpExtraInfo; using google_breakpad::RawContextCPU; using google_breakpad::ThreadInfo; using google_breakpad::UContextReader; @@ -58,8 +60,7 @@ class MicrodumpWriter { public: MicrodumpWriter(const ExceptionHandler::CrashContext* context, const MappingList& mappings, - const char* build_fingerprint, - const char* product_info, + const MicrodumpExtraInfo& microdump_extra_info, LinuxDumper* dumper) : ucontext_(context ? &context->context : NULL), #if !defined(__ARM_EABI__) && !defined(__mips__) @@ -67,8 +68,7 @@ class MicrodumpWriter { #endif dumper_(dumper), mapping_list_(mappings), - build_fingerprint_(build_fingerprint), - product_info_(product_info), + microdump_extra_info_(microdump_extra_info), log_line_(NULL) { log_line_ = reinterpret_cast(Alloc(kLineBufferSize)); if (log_line_) @@ -92,6 +92,7 @@ class MicrodumpWriter { LogLine("-----BEGIN BREAKPAD MICRODUMP-----"); DumpProductInformation(); DumpOSInformation(); + DumpGPUInformation(); success = DumpCrashingThread(); if (success) success = DumpMappings(); @@ -149,8 +150,8 @@ class MicrodumpWriter { void DumpProductInformation() { LogAppend("V "); - if (product_info_) { - LogAppend(product_info_); + if (microdump_extra_info_.product_info) { + LogAppend(microdump_extra_info_.product_info); } else { LogAppend("UNKNOWN:0.0.0.0"); } @@ -200,8 +201,8 @@ class MicrodumpWriter { // 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_); + if (microdump_extra_info_.build_fingerprint) { + LogAppend(microdump_extra_info_.build_fingerprint); } else if (has_uts_info) { LogAppend(uts.release); LogAppend(" "); @@ -212,6 +213,16 @@ class MicrodumpWriter { LogCommitLine(); } + void DumpGPUInformation() { + LogAppend("G "); + if (microdump_extra_info_.gpu_fingerprint) { + LogAppend(microdump_extra_info_.gpu_fingerprint); + } else { + LogAppend("UNKNOWN"); + } + LogCommitLine(); + } + bool DumpThreadStack(uint32_t thread_id, uintptr_t stack_pointer, int max_stack_len, @@ -390,8 +401,7 @@ class MicrodumpWriter { #endif LinuxDumper* dumper_; const MappingList& mapping_list_; - const char* const build_fingerprint_; - const char* const product_info_; + const MicrodumpExtraInfo microdump_extra_info_; char* log_line_; }; } // namespace @@ -402,8 +412,7 @@ bool WriteMicrodump(pid_t crashing_process, const void* blob, size_t blob_size, const MappingList& mappings, - const char* build_fingerprint, - const char* product_info) { + const MicrodumpExtraInfo& microdump_extra_info) { LinuxPtraceDumper dumper(crashing_process); const ExceptionHandler::CrashContext* context = NULL; if (blob) { @@ -415,8 +424,7 @@ bool WriteMicrodump(pid_t crashing_process, dumper.set_crash_signal(context->siginfo.si_signo); dumper.set_crash_thread(context->tid); } - MicrodumpWriter writer(context, mappings, build_fingerprint, product_info, - &dumper); + MicrodumpWriter writer(context, mappings, microdump_extra_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 e2185583..7c742761 100644 --- a/src/client/linux/microdump_writer/microdump_writer.h +++ b/src/client/linux/microdump_writer/microdump_writer.h @@ -37,6 +37,8 @@ namespace google_breakpad { +struct MicrodumpExtraInfo; + // Writes a microdump (a reduced dump containing only the state of the crashing // thread) on the console (logcat on Android). These functions do not malloc nor // use libc functions which may. Thus, it can be used in contexts where the @@ -56,8 +58,7 @@ bool WriteMicrodump(pid_t crashing_process, const void* blob, size_t blob_size, const MappingList& mappings, - const char* build_fingerprint, - const char* product_info); + const MicrodumpExtraInfo& microdump_extra_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 035e73c1..58a73118 100644 --- a/src/client/linux/microdump_writer/microdump_writer_unittest.cc +++ b/src/client/linux/microdump_writer/microdump_writer_unittest.cc @@ -37,6 +37,7 @@ #include "breakpad_googletest_includes.h" #include "client/linux/handler/exception_handler.h" +#include "client/linux/handler/microdump_extra_info.h" #include "client/linux/microdump_writer/microdump_writer.h" #include "common/linux/eintr_wrapper.h" #include "common/linux/ignore_ret.h" @@ -50,10 +51,20 @@ namespace { typedef testing::Test MicrodumpWriterTest; -void CrashAndGetMicrodump( - const MappingList& mappings, +MicrodumpExtraInfo MakeMicrodumpExtraInfo( const char* build_fingerprint, const char* product_info, + const char* gpu_fingerprint) { + MicrodumpExtraInfo info; + info.build_fingerprint = build_fingerprint; + info.product_info = product_info; + info.gpu_fingerprint = gpu_fingerprint; + return info; +} + +void CrashAndGetMicrodump( + const MappingList& mappings, + const MicrodumpExtraInfo& microdump_extra_info, scoped_array* buf) { int fds[2]; ASSERT_NE(-1, pipe(fds)); @@ -85,7 +96,7 @@ void CrashAndGetMicrodump( ASSERT_NE(-1, dup2(err_fd, STDERR_FILENO)); ASSERT_TRUE(WriteMicrodump(child, &context, sizeof(context), mappings, - build_fingerprint, product_info)); + microdump_extra_info)); // Revert stderr back to the console. dup2(save_err, STDERR_FILENO); @@ -107,12 +118,12 @@ void CrashAndGetMicrodump( buf->get(), "-----END BREAKPAD MICRODUMP-----")); } -void CheckMicrodumpContents(const string µdum_content, - const string &expected_fingerprint, - const string &expected_product_info) { - std::istringstream iss(microdum_content); +void CheckMicrodumpContents(const string& microdump_content, + const MicrodumpExtraInfo& expected_info) { + std::istringstream iss(microdump_content); bool did_find_os_info = false; bool did_find_product_info = false; + bool did_find_gpu_info = false; for (string line; std::getline(iss, line);) { if (line.find("O ") == 0) { std::istringstream os_info_tokens(line); @@ -130,15 +141,33 @@ void CheckMicrodumpContents(const string µdum_content, // Check that the build fingerprint is in the right place. os_info_tokens >> token; - ASSERT_EQ(expected_fingerprint, token); + if (expected_info.build_fingerprint) + ASSERT_EQ(expected_info.build_fingerprint, token); did_find_os_info = true; } else if (line.find("V ") == 0) { - ASSERT_EQ("V " + expected_product_info, line); + if (expected_info.product_info) + ASSERT_EQ(string("V ") + expected_info.product_info, line); did_find_product_info = true; + } else if (line.find("G ") == 0) { + if (expected_info.gpu_fingerprint) + ASSERT_EQ(string("G ") + expected_info.gpu_fingerprint, line); + did_find_gpu_info = true; } } ASSERT_TRUE(did_find_os_info); ASSERT_TRUE(did_find_product_info); + ASSERT_TRUE(did_find_gpu_info); +} + +void CheckMicrodumpContents(const string& microdump_content, + const string& expected_fingerprint, + const string& expected_product_info, + const string& expected_gpu_fingerprint) { + CheckMicrodumpContents( + microdump_content, + MakeMicrodumpExtraInfo(expected_fingerprint.c_str(), + expected_product_info.c_str(), + expected_gpu_fingerprint.c_str())); } TEST(MicrodumpWriterTest, BasicWithMappings) { @@ -163,7 +192,7 @@ TEST(MicrodumpWriterTest, BasicWithMappings) { mappings.push_back(mapping); scoped_array buf; - CrashAndGetMicrodump(mappings, NULL, NULL, &buf); + CrashAndGetMicrodump(mappings, MicrodumpExtraInfo(), &buf); #ifdef __LP64__ ASSERT_NE(static_cast(0), strstr( @@ -187,19 +216,42 @@ 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"; + const char kGPUFingerprint[] = + "Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)"; + const MicrodumpExtraInfo kMicrodumpExtraInfo( + MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint)); scoped_array buf; MappingList no_mappings; - CrashAndGetMicrodump(no_mappings, kBuildFingerprint, kProductInfo, &buf); - CheckMicrodumpContents(string(buf.get()), kBuildFingerprint, kProductInfo); + CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf); + CheckMicrodumpContents(string(buf.get()), kMicrodumpExtraInfo); } TEST(MicrodumpWriterTest, NoProductInfo) { const char kBuildFingerprint[] = "foobar"; + const char kGPUFingerprint[] = "bazqux"; scoped_array buf; MappingList no_mappings; - CrashAndGetMicrodump(no_mappings, kBuildFingerprint, NULL, &buf); - CheckMicrodumpContents(string(buf.get()), kBuildFingerprint, "UNKNOWN:0.0.0.0"); + const MicrodumpExtraInfo kMicrodumpExtraInfoNoProductInfo( + MakeMicrodumpExtraInfo(kBuildFingerprint, NULL, kGPUFingerprint)); + + CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoProductInfo, &buf); + CheckMicrodumpContents(string(buf.get()), kBuildFingerprint, + "UNKNOWN:0.0.0.0", kGPUFingerprint); +} + +TEST(MicrodumpWriterTest, NoGPUInfo) { + const char kProductInfo[] = "bazqux"; + const char kBuildFingerprint[] = "foobar"; + scoped_array buf; + MappingList no_mappings; + + const MicrodumpExtraInfo kMicrodumpExtraInfoNoGPUInfo( + MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, NULL)); + + CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoGPUInfo, &buf); + CheckMicrodumpContents(string(buf.get()), kBuildFingerprint, + kProductInfo, "UNKNOWN"); } } // namespace -- cgit v1.2.1