aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/linux/handler/exception_handler.cc3
-rw-r--r--src/client/linux/handler/microdump_extra_info.h48
-rw-r--r--src/client/linux/handler/minidump_descriptor.cc17
-rw-r--r--src/client/linux/handler/minidump_descriptor.h56
-rw-r--r--src/client/linux/microdump_writer/microdump_writer.cc36
-rw-r--r--src/client/linux/microdump_writer/microdump_writer.h5
-rw-r--r--src/client/linux/microdump_writer/microdump_writer_unittest.cc80
7 files changed, 164 insertions, 81 deletions
diff --git a/src/client/linux/handler/exception_handler.cc b/src/client/linux/handler/exception_handler.cc
index 5bd2d8cc..148d61f9 100644
--- a/src/client/linux/handler/exception_handler.cc
+++ b/src/client/linux/handler/exception_handler.cc
@@ -592,8 +592,7 @@ bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
context,
context_size,
mapping_list_,
- minidump_descriptor_.microdump_build_fingerprint(),
- minidump_descriptor_.microdump_product_info());
+ *minidump_descriptor_.microdump_extra_info());
}
if (minidump_descriptor_.IsFD()) {
return google_breakpad::WriteMinidump(minidump_descriptor_.fd(),
diff --git a/src/client/linux/handler/microdump_extra_info.h b/src/client/linux/handler/microdump_extra_info.h
new file mode 100644
index 00000000..b9c3d30d
--- /dev/null
+++ b/src/client/linux/handler/microdump_extra_info.h
@@ -0,0 +1,48 @@
+// Copyright 2015 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_LINUX_HANDLER_MICRODUMP_EXTRA_INFO_H_
+#define CLIENT_LINUX_HANDLER_MICRODUMP_EXTRA_INFO_H_
+
+namespace google_breakpad {
+
+struct MicrodumpExtraInfo {
+ // Strings pointed to by this struct are not copied, and are
+ // expected to remain valid for the lifetime of the process.
+ const char* build_fingerprint;
+ const char* product_info;
+ const char* gpu_fingerprint;
+
+ MicrodumpExtraInfo()
+ : build_fingerprint(NULL), product_info(NULL), gpu_fingerprint(NULL) {}
+};
+
+}
+
+#endif // CLIENT_LINUX_HANDLER_MICRODUMP_EXTRA_INFO_H_
diff --git a/src/client/linux/handler/minidump_descriptor.cc b/src/client/linux/handler/minidump_descriptor.cc
index c601d35f..ce09153d 100644
--- a/src/client/linux/handler/minidump_descriptor.cc
+++ b/src/client/linux/handler/minidump_descriptor.cc
@@ -45,8 +45,7 @@ MinidumpDescriptor::MinidumpDescriptor(const MinidumpDescriptor& descriptor)
directory_(descriptor.directory_),
c_path_(NULL),
size_limit_(descriptor.size_limit_),
- microdump_build_fingerprint_(descriptor.microdump_build_fingerprint_),
- microdump_product_info_(descriptor.microdump_product_info_) {
+ microdump_extra_info_(descriptor.microdump_extra_info_) {
// The copy constructor is not allowed to be called on a MinidumpDescriptor
// with a valid path_, as getting its c_path_ would require the heap which
// can cause problems in compromised environments.
@@ -67,8 +66,7 @@ MinidumpDescriptor& MinidumpDescriptor::operator=(
UpdatePath();
}
size_limit_ = descriptor.size_limit_;
- microdump_build_fingerprint_ = descriptor.microdump_build_fingerprint_;
- microdump_product_info_ = descriptor.microdump_product_info_;
+ microdump_extra_info_ = descriptor.microdump_extra_info_;
return *this;
}
@@ -86,15 +84,4 @@ void MinidumpDescriptor::UpdatePath() {
c_path_ = path_.c_str();
}
-void MinidumpDescriptor::SetMicrodumpBuildFingerprint(
- const char* build_fingerprint) {
- assert(mode_ == kWriteMicrodumpToConsole);
- microdump_build_fingerprint_ = build_fingerprint;
-}
-
-void MinidumpDescriptor::SetMicrodumpProductInfo(const char* product_info) {
- assert(mode_ == kWriteMicrodumpToConsole);
- microdump_product_info_ = product_info;
-}
-
} // namespace google_breakpad
diff --git a/src/client/linux/handler/minidump_descriptor.h b/src/client/linux/handler/minidump_descriptor.h
index 3584c692..782a60a4 100644
--- a/src/client/linux/handler/minidump_descriptor.h
+++ b/src/client/linux/handler/minidump_descriptor.h
@@ -35,6 +35,7 @@
#include <string>
+#include "client/linux/handler/microdump_extra_info.h"
#include "common/using_std_string.h"
// This class describes how a crash dump should be generated, either:
@@ -49,20 +50,17 @@ class MinidumpDescriptor {
struct MicrodumpOnConsole {};
static const MicrodumpOnConsole kMicrodumpOnConsole;
- MinidumpDescriptor() : mode_(kUninitialized),
- fd_(-1),
- size_limit_(-1),
- microdump_build_fingerprint_(NULL),
- microdump_product_info_(NULL) {}
+ MinidumpDescriptor()
+ : mode_(kUninitialized),
+ fd_(-1),
+ size_limit_(-1) {}
explicit MinidumpDescriptor(const string& directory)
: mode_(kWriteMinidumpToFile),
fd_(-1),
directory_(directory),
c_path_(NULL),
- size_limit_(-1),
- microdump_build_fingerprint_(NULL),
- microdump_product_info_(NULL) {
+ size_limit_(-1) {
assert(!directory.empty());
}
@@ -70,18 +68,14 @@ class MinidumpDescriptor {
: mode_(kWriteMinidumpToFd),
fd_(fd),
c_path_(NULL),
- size_limit_(-1),
- microdump_build_fingerprint_(NULL),
- microdump_product_info_(NULL) {
+ size_limit_(-1) {
assert(fd != -1);
}
explicit MinidumpDescriptor(const MicrodumpOnConsole&)
: mode_(kWriteMicrodumpToConsole),
fd_(-1),
- size_limit_(-1),
- microdump_build_fingerprint_(NULL),
- microdump_product_info_(NULL) {}
+ size_limit_(-1) {}
explicit MinidumpDescriptor(const MinidumpDescriptor& descriptor);
MinidumpDescriptor& operator=(const MinidumpDescriptor& descriptor);
@@ -107,17 +101,10 @@ class MinidumpDescriptor {
off_t size_limit() const { return size_limit_; }
void set_size_limit(off_t limit) { size_limit_ = limit; }
- // TODO(primiano): make this and product info (below) just part of the
- // microdump ctor once it is rolled stably into Chrome. ETA: June 2015.
- void SetMicrodumpBuildFingerprint(const char* build_fingerprint);
- const char* microdump_build_fingerprint() const {
- return microdump_build_fingerprint_;
- }
-
- void SetMicrodumpProductInfo(const char* product_info);
- const char* microdump_product_info() const {
- return microdump_product_info_;
- }
+ MicrodumpExtraInfo* microdump_extra_info() {
+ assert(IsMicrodumpOnConsole());
+ return &microdump_extra_info_;
+ };
private:
enum DumpMode {
@@ -145,15 +132,16 @@ class MinidumpDescriptor {
off_t size_limit_;
- // The product name/version and build fingerprint that should be appended to
- // the dump (microdump only). Microdumps don't have the ability of appending
- // extra metadata after the dump is generated (as opposite to minidumps
- // MIME fields), therefore the product details must be provided upfront.
- // The string pointers are supposed to be valid through all the lifetime of
- // the process (read: the caller has to guarantee that they are stored in
- // global static storage).
- const char* microdump_build_fingerprint_;
- const char* microdump_product_info_;
+ // The extra microdump data (e.g. product name/version, build
+ // fingerprint, gpu fingerprint) that should be appended to the dump
+ // (microdump only). Microdumps don't have the ability of appending
+ // extra metadata after the dump is generated (as opposite to
+ // minidumps MIME fields), therefore the extra data must be provided
+ // upfront. Any memory pointed to by members of the
+ // MicrodumpExtraInfo struct must be valid for the lifetime of the
+ // process (read: the caller has to guarantee that it is stored in
+ // global static storage.)
+ MicrodumpExtraInfo microdump_extra_info_;
};
} // namespace google_breakpad
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<char*>(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<char>* 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 &microdum_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 &microdum_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<char> buf;
- CrashAndGetMicrodump(mappings, NULL, NULL, &buf);
+ CrashAndGetMicrodump(mappings, MicrodumpExtraInfo(), &buf);
#ifdef __LP64__
ASSERT_NE(static_cast<char*>(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<char> 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<char> 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<char> buf;
+ MappingList no_mappings;
+
+ const MicrodumpExtraInfo kMicrodumpExtraInfoNoGPUInfo(
+ MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, NULL));
+
+ CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoGPUInfo, &buf);
+ CheckMicrodumpContents(string(buf.get()), kBuildFingerprint,
+ kProductInfo, "UNKNOWN");
}
} // namespace