Commit d8d59137 authored by rsesek@chromium.org's avatar rsesek@chromium.org

[Linux] Implement the crash key logging mechanism.

BUG=77656

Review URL: https://chromiumcodereview.appspot.com/16019015

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@203006 0039d316-1c4b-4281-b951-d872f2087c98
parent 7dfb9e28
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <string> #include <string>
#include "base/command_line.h" #include "base/command_line.h"
#include "base/debug/crash_logging.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/linux_util.h" #include "base/linux_util.h"
#include "base/path_service.h" #include "base/path_service.h"
...@@ -35,11 +36,13 @@ ...@@ -35,11 +36,13 @@
#include "breakpad/src/client/linux/minidump_writer/directory_reader.h" #include "breakpad/src/client/linux/minidump_writer/directory_reader.h"
#include "breakpad/src/common/linux/linux_libc_support.h" #include "breakpad/src/common/linux/linux_libc_support.h"
#include "breakpad/src/common/memory.h" #include "breakpad/src/common/memory.h"
#include "chrome/app/breakpad_linux_impl.h"
#include "chrome/browser/crash_upload_list.h" #include "chrome/browser/crash_upload_list.h"
#include "chrome/common/child_process_logging.h" #include "chrome/common/child_process_logging.h"
#include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info_posix.h" #include "chrome/common/chrome_version_info_posix.h"
#include "chrome/common/crash_keys.h"
#include "chrome/common/dump_without_crashing.h" #include "chrome/common/dump_without_crashing.h"
#include "chrome/common/env_vars.h" #include "chrome/common/env_vars.h"
#include "chrome/common/logging_chrome.h" #include "chrome/common/logging_chrome.h"
...@@ -84,6 +87,7 @@ bool g_is_crash_reporter_enabled = false; ...@@ -84,6 +87,7 @@ bool g_is_crash_reporter_enabled = false;
uint64_t g_process_start_time = 0; uint64_t g_process_start_time = 0;
char* g_crash_log_path = NULL; char* g_crash_log_path = NULL;
ExceptionHandler* g_breakpad = NULL; ExceptionHandler* g_breakpad = NULL;
#if defined(ADDRESS_SANITIZER) #if defined(ADDRESS_SANITIZER)
const char* g_asan_report_str = NULL; const char* g_asan_report_str = NULL;
#endif #endif
...@@ -91,6 +95,8 @@ const char* g_asan_report_str = NULL; ...@@ -91,6 +95,8 @@ const char* g_asan_report_str = NULL;
char* g_process_type = NULL; char* g_process_type = NULL;
#endif #endif
CrashKeyStorage* g_crash_keys = NULL;
// Writes the value |v| as 16 hex characters to the memory pointed at by // Writes the value |v| as 16 hex characters to the memory pointed at by
// |output|. // |output|.
void write_uint64_hex(char* output, uint64_t v) { void write_uint64_hex(char* output, uint64_t v) {
...@@ -483,6 +489,7 @@ bool CrashDone(const MinidumpDescriptor& minidump, ...@@ -483,6 +489,7 @@ bool CrashDone(const MinidumpDescriptor& minidump,
info.process_start_time = g_process_start_time; info.process_start_time = g_process_start_time;
info.oom_size = base::g_oom_size; info.oom_size = base::g_oom_size;
info.pid = 0; info.pid = 0;
info.crash_keys = g_crash_keys;
HandleCrashDump(info); HandleCrashDump(info);
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
return FinalizeCrashDoneAndroid(); return FinalizeCrashDoneAndroid();
...@@ -663,15 +670,9 @@ bool NonBrowserCrashHandler(const void* crash_context, ...@@ -663,15 +670,9 @@ bool NonBrowserCrashHandler(const void* crash_context,
static const unsigned kControlMsgSpaceSize = CMSG_SPACE(kControlMsgSize); static const unsigned kControlMsgSpaceSize = CMSG_SPACE(kControlMsgSize);
static const unsigned kControlMsgLenSize = CMSG_LEN(kControlMsgSize); static const unsigned kControlMsgLenSize = CMSG_LEN(kControlMsgSize);
#if !defined(ADDRESS_SANITIZER)
const size_t kIovSize = 8;
#else
// Additional field to pass the AddressSanitizer log to the crash handler.
const size_t kIovSize = 9;
#endif
struct kernel_msghdr msg; struct kernel_msghdr msg;
my_memset(&msg, 0, sizeof(struct kernel_msghdr)); my_memset(&msg, 0, sizeof(struct kernel_msghdr));
struct kernel_iovec iov[kIovSize]; struct kernel_iovec iov[kCrashIovSize];
iov[0].iov_base = const_cast<void*>(crash_context); iov[0].iov_base = const_cast<void*>(crash_context);
iov[0].iov_len = crash_context_size; iov[0].iov_len = crash_context_size;
iov[1].iov_base = guid; iov[1].iov_base = guid;
...@@ -688,13 +689,18 @@ bool NonBrowserCrashHandler(const void* crash_context, ...@@ -688,13 +689,18 @@ bool NonBrowserCrashHandler(const void* crash_context,
iov[6].iov_len = sizeof(g_process_start_time); iov[6].iov_len = sizeof(g_process_start_time);
iov[7].iov_base = &base::g_oom_size; iov[7].iov_base = &base::g_oom_size;
iov[7].iov_len = sizeof(base::g_oom_size); iov[7].iov_len = sizeof(base::g_oom_size);
google_breakpad::SerializedNonAllocatingMap* serialized_map;
iov[8].iov_len = g_crash_keys->Serialize(
const_cast<const google_breakpad::SerializedNonAllocatingMap**>(
&serialized_map));
iov[8].iov_base = serialized_map;
#if defined(ADDRESS_SANITIZER) #if defined(ADDRESS_SANITIZER)
iov[8].iov_base = const_cast<char*>(g_asan_report_str); iov[9].iov_base = const_cast<char*>(g_asan_report_str);
iov[8].iov_len = kMaxAsanReportSize + 1; iov[9].iov_len = kMaxAsanReportSize + 1;
#endif #endif
msg.msg_iov = iov; msg.msg_iov = iov;
msg.msg_iovlen = kIovSize; msg.msg_iovlen = kCrashIovSize;
char cmsg[kControlMsgSpaceSize]; char cmsg[kControlMsgSpaceSize];
my_memset(cmsg, 0, kControlMsgSpaceSize); my_memset(cmsg, 0, kControlMsgSpaceSize);
msg.msg_control = cmsg; msg.msg_control = cmsg;
...@@ -740,6 +746,15 @@ void EnableNonBrowserCrashDumping() { ...@@ -740,6 +746,15 @@ void EnableNonBrowserCrashDumping() {
} }
#endif // defined(OS_ANDROID) #endif // defined(OS_ANDROID)
void SetCrashKeyValue(const base::StringPiece& key,
const base::StringPiece& value) {
g_crash_keys->SetKeyValue(key.data(), value.data());
}
void ClearCrashKey(const base::StringPiece& key) {
g_crash_keys->RemoveKey(key.data());
}
} // namespace } // namespace
void LoadDataFromFD(google_breakpad::PageAllocator& allocator, void LoadDataFromFD(google_breakpad::PageAllocator& allocator,
...@@ -973,6 +988,11 @@ void HandleCrashDump(const BreakpadInfo& info) { ...@@ -973,6 +988,11 @@ void HandleCrashDump(const BreakpadInfo& info) {
// 1234567890 \r\n // 1234567890 \r\n
// BOUNDARY \r\n // BOUNDARY \r\n
// //
// zero or more (up to CrashKeyStorage::num_entries = 64):
// Content-Disposition: form-data; name=crash-key-name \r\n
// crash-key-value \r\n
// BOUNDARY \r\n
//
// Content-Disposition: form-data; name="dump"; filename="dump" \r\n // Content-Disposition: form-data; name="dump"; filename="dump" \r\n
// Content-Type: application/octet-stream \r\n \r\n // Content-Type: application/octet-stream \r\n \r\n
// <dump contents> // <dump contents>
...@@ -1211,6 +1231,16 @@ void HandleCrashDump(const BreakpadInfo& info) { ...@@ -1211,6 +1231,16 @@ void HandleCrashDump(const BreakpadInfo& info) {
writer.Flush(); writer.Flush();
} }
if (info.crash_keys) {
CrashKeyStorage::Iterator crash_key_iterator(*info.crash_keys);
const CrashKeyStorage::Entry* entry;
while ((entry = crash_key_iterator.Next())) {
writer.AddPairString(entry->key, entry->value);
writer.AddBoundary();
writer.Flush();
}
}
writer.AddFileContents(g_dump_msg, dump_data, dump_size); writer.AddFileContents(g_dump_msg, dump_data, dump_size);
#if defined(ADDRESS_SANITIZER) #if defined(ADDRESS_SANITIZER)
// Append a multipart boundary and the contents of the AddressSanitizer log. // Append a multipart boundary and the contents of the AddressSanitizer log.
...@@ -1473,6 +1503,11 @@ void InitCrashReporter() { ...@@ -1473,6 +1503,11 @@ void InitCrashReporter() {
// Register the callback for AddressSanitizer error reporting. // Register the callback for AddressSanitizer error reporting.
__asan_set_error_report_callback(AsanLinuxBreakpadCallback); __asan_set_error_report_callback(AsanLinuxBreakpadCallback);
#endif #endif
g_crash_keys = new CrashKeyStorage;
crash_keys::RegisterChromeCrashKeys();
base::debug::SetCrashKeyReportingFunctions(
&SetCrashKeyValue, &ClearCrashKey);
} }
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
......
...@@ -2,55 +2,25 @@ ...@@ -2,55 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Public interface for enabling Breakpad on Linux systems. This can be
// included in files that are not built with linux_breakpad=1.
#ifndef CHROME_APP_BREAKPAD_LINUX_H_ #ifndef CHROME_APP_BREAKPAD_LINUX_H_
#define CHROME_APP_BREAKPAD_LINUX_H_ #define CHROME_APP_BREAKPAD_LINUX_H_
#include <sys/types.h> #include "build/build_config.h"
#include "base/basictypes.h"
// Turns on the crash reporter in any process.
extern void InitCrashReporter(); extern void InitCrashReporter();
// Enables the crash reporter in child processes.
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
extern void InitNonBrowserCrashReporterForAndroid(); extern void InitNonBrowserCrashReporterForAndroid();
#endif #endif
bool IsCrashReporterEnabled();
static const size_t kMaxActiveURLSize = 1024; // Checks if crash reporting is enabled. Note that this is not the same as
static const size_t kGuidSize = 32; // 128 bits = 32 chars in hex. // being opted into metrics reporting (and crash reporting), which controls
static const size_t kDistroSize = 128; // whether InitCrashReporter() is called.
#if defined(ADDRESS_SANITIZER) bool IsCrashReporterEnabled();
static const size_t kMaxAsanReportSize = 1 << 16;
#endif
// Define a preferred limit on minidump sizes, because Crash Server currently
// throws away any larger than 1.2MB (1.2 * 1024 * 1024). A value of -1 means
// no limit.
static const off_t kMaxMinidumpFileSize = 1258291;
// BreakpadInfo describes a crash report.
// The minidump information can either be contained in a file descriptor (fd) or
// in a file (whose path is in filename).
struct BreakpadInfo {
int fd; // File descriptor to the Breakpad dump data.
const char* filename; // Path to the Breakpad dump data.
#if defined(ADDRESS_SANITIZER)
const char* log_filename; // Path to the ASan log file.
const char* asan_report_str; // ASan report.
unsigned asan_report_length; // Length of |asan_report_length|.
#endif
const char* process_type; // Process type, e.g. "renderer".
unsigned process_type_length; // Length of |process_type|.
const char* crash_url; // Active URL in the crashing process.
unsigned crash_url_length; // Length of |crash_url|.
const char* guid; // Client ID.
unsigned guid_length; // Length of |guid|.
const char* distro; // Linux distro string.
unsigned distro_length; // Length of |distro|.
bool upload; // Whether to upload or save crash dump.
uint64_t process_start_time; // Uptime of the crashing process.
size_t oom_size; // Amount of memory requested if OOM.
uint64_t pid; // PID where applicable.
};
extern void HandleCrashDump(const BreakpadInfo& info);
#endif // CHROME_APP_BREAKPAD_LINUX_H_ #endif // CHROME_APP_BREAKPAD_LINUX_H_
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Internal header file for the Linux breakpad implementation. This file is
// shared between crash_handler_host_linux.cc and breakpad_linux.cc. It should
// only be used in files compiled with linux_breakpad=1.
#ifndef CHROME_APP_BREAKPAD_LINUX_IMPL_H_
#define CHROME_APP_BREAKPAD_LINUX_IMPL_H_
#include <sys/types.h>
#include "base/basictypes.h"
#include "breakpad/src/common/simple_string_dictionary.h"
#include "chrome/app/breakpad_linux.h"
typedef google_breakpad::NonAllocatingMap<256, 256, 64> CrashKeyStorage;
static const size_t kMaxActiveURLSize = 1024;
static const size_t kGuidSize = 32; // 128 bits = 32 chars in hex.
static const size_t kDistroSize = 128;
#if defined(ADDRESS_SANITIZER)
static const size_t kMaxAsanReportSize = 1 << 16;
#endif
// Define a preferred limit on minidump sizes, because Crash Server currently
// throws away any larger than 1.2MB (1.2 * 1024 * 1024). A value of -1 means
// no limit.
static const off_t kMaxMinidumpFileSize = 1258291;
// The size of the iovec used to transfer crash data from a child back to the
// browser.
#if !defined(ADDRESS_SANITIZER)
const size_t kCrashIovSize = 9;
#else
// Additional field to pass the AddressSanitizer log to the crash handler.
const size_t kCrashIovSize = 10;
#endif
// BreakpadInfo describes a crash report.
// The minidump information can either be contained in a file descriptor (fd) or
// in a file (whose path is in filename).
struct BreakpadInfo {
int fd; // File descriptor to the Breakpad dump data.
const char* filename; // Path to the Breakpad dump data.
#if defined(ADDRESS_SANITIZER)
const char* log_filename; // Path to the ASan log file.
const char* asan_report_str; // ASan report.
unsigned asan_report_length; // Length of |asan_report_length|.
#endif
const char* process_type; // Process type, e.g. "renderer".
unsigned process_type_length; // Length of |process_type|.
const char* crash_url; // Active URL in the crashing process.
unsigned crash_url_length; // Length of |crash_url|.
const char* guid; // Client ID.
unsigned guid_length; // Length of |guid|.
const char* distro; // Linux distro string.
unsigned distro_length; // Length of |distro|.
bool upload; // Whether to upload or save crash dump.
uint64_t process_start_time; // Uptime of the crashing process.
size_t oom_size; // Amount of memory requested if OOM.
uint64_t pid; // PID where applicable.
CrashKeyStorage* crash_keys;
};
extern void HandleCrashDump(const BreakpadInfo& info);
#endif // CHROME_APP_BREAKPAD_LINUX_IMPL_H_
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include "breakpad/src/client/linux/handler/exception_handler.h" #include "breakpad/src/client/linux/handler/exception_handler.h"
#include "breakpad/src/client/linux/minidump_writer/linux_dumper.h" #include "breakpad/src/client/linux/minidump_writer/linux_dumper.h"
#include "breakpad/src/client/linux/minidump_writer/minidump_writer.h" #include "breakpad/src/client/linux/minidump_writer/minidump_writer.h"
#include "chrome/app/breakpad_linux.h" #include "chrome/app/breakpad_linux_impl.h"
#include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_paths.h"
#include "chrome/common/env_vars.h" #include "chrome/common/env_vars.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
...@@ -60,6 +60,7 @@ void CrashDumpTask(CrashHandlerHostLinux* handler, BreakpadInfo* info) { ...@@ -60,6 +60,7 @@ void CrashDumpTask(CrashHandlerHostLinux* handler, BreakpadInfo* info) {
delete[] info->crash_url; delete[] info->crash_url;
delete[] info->guid; delete[] info->guid;
delete[] info->distro; delete[] info->distro;
delete info->crash_keys;
delete info; delete info;
} }
...@@ -128,14 +129,8 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) { ...@@ -128,14 +129,8 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
// //
// The message sender is in chrome/app/breakpad_linux.cc. // The message sender is in chrome/app/breakpad_linux.cc.
#if !defined(ADDRESS_SANITIZER)
const size_t kIovSize = 8;
#else
const size_t kIovSize = 9;
#endif
struct msghdr msg = {0}; struct msghdr msg = {0};
struct iovec iov[kIovSize]; struct iovec iov[kCrashIovSize];
// Freed in WriteDumpFile(); // Freed in WriteDumpFile();
char* crash_context = new char[kCrashContextSize]; char* crash_context = new char[kCrashContextSize];
...@@ -147,6 +142,13 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) { ...@@ -147,6 +142,13 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
asan_report_str_ = new char[kMaxAsanReportSize + 1]; asan_report_str_ = new char[kMaxAsanReportSize + 1];
#endif #endif
// Freed in CrashDumpTask().
CrashKeyStorage* crash_keys = new CrashKeyStorage;
google_breakpad::SerializedNonAllocatingMap* serialized_crash_keys;
size_t crash_keys_size = crash_keys->Serialize(
const_cast<const google_breakpad::SerializedNonAllocatingMap**>(
&serialized_crash_keys));
char* tid_buf_addr = NULL; char* tid_buf_addr = NULL;
int tid_fd = -1; int tid_fd = -1;
uint64_t uptime; uint64_t uptime;
...@@ -162,7 +164,8 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) { ...@@ -162,7 +164,8 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
#if defined(ADDRESS_SANITIZER) #if defined(ADDRESS_SANITIZER)
kMaxAsanReportSize + 1 + kMaxAsanReportSize + 1 +
#endif #endif
sizeof(oom_size); sizeof(oom_size) +
crash_keys_size;
iov[0].iov_base = crash_context; iov[0].iov_base = crash_context;
iov[0].iov_len = kCrashContextSize; iov[0].iov_len = kCrashContextSize;
iov[1].iov_base = guid; iov[1].iov_base = guid;
...@@ -179,12 +182,14 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) { ...@@ -179,12 +182,14 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
iov[6].iov_len = sizeof(uptime); iov[6].iov_len = sizeof(uptime);
iov[7].iov_base = &oom_size; iov[7].iov_base = &oom_size;
iov[7].iov_len = sizeof(oom_size); iov[7].iov_len = sizeof(oom_size);
iov[8].iov_base = serialized_crash_keys;
iov[8].iov_len = crash_keys_size;
#if defined(ADDRESS_SANITIZER) #if defined(ADDRESS_SANITIZER)
iov[8].iov_base = asan_report_str_; iov[9].iov_base = asan_report_str_;
iov[8].iov_len = kMaxAsanReportSize + 1; iov[9].iov_len = kMaxAsanReportSize + 1;
#endif #endif
msg.msg_iov = iov; msg.msg_iov = iov;
msg.msg_iovlen = kIovSize; msg.msg_iovlen = kCrashIovSize;
msg.msg_control = control; msg.msg_control = control;
msg.msg_controllen = kControlMsgSize; msg.msg_controllen = kControlMsgSize;
...@@ -346,6 +351,8 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) { ...@@ -346,6 +351,8 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
info->upload = (getenv(env_vars::kHeadless) == NULL); info->upload = (getenv(env_vars::kHeadless) == NULL);
#endif #endif
info->crash_keys = crash_keys;
#if defined(ADDRESS_SANITIZER) #if defined(ADDRESS_SANITIZER)
info->asan_report_str = asan_report_str_; info->asan_report_str = asan_report_str_;
info->asan_report_length = strlen(asan_report_str_); info->asan_report_length = strlen(asan_report_str_);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment