diff options
author | Robert Sesek <rsesek@chromium.org> | 2014-08-27 12:12:44 -0400 |
---|---|---|
committer | Robert Sesek <rsesek@chromium.org> | 2014-08-27 16:14:41 +0000 |
commit | abcd8100a58d4e5ba55f4ec2e5f394e0aa6a3f33 (patch) | |
tree | f502825654e85f9c009a222384cd07a154e2a1e8 /components/breakpad/app | |
parent | 6a35b2b82305427017f42a971dc022d154eb127d (diff) | |
download | chromium_src-abcd8100a58d4e5ba55f4ec2e5f394e0aa6a3f33.zip chromium_src-abcd8100a58d4e5ba55f4ec2e5f394e0aa6a3f33.tar.gz chromium_src-abcd8100a58d4e5ba55f4ec2e5f394e0aa6a3f33.tar.bz2 |
Rename components/breakpad to components/crash.
In the near future, Crashpad (the new Mac crash reporter) will be integrated,
and it should be integrated/exposed transparently to the users of this
component.
BUG=406410
R=blundell@chromium.org
TBR=darin@chromium.org
Review URL: https://codereview.chromium.org/485893007
Cr-Commit-Position: refs/heads/master@{#292162}
Diffstat (limited to 'components/breakpad/app')
-rw-r--r-- | components/breakpad/app/BUILD.gn | 69 | ||||
-rw-r--r-- | components/breakpad/app/DEPS | 7 | ||||
-rw-r--r-- | components/breakpad/app/breakpad_client.cc | 127 | ||||
-rw-r--r-- | components/breakpad/app/breakpad_client.h | 143 | ||||
-rw-r--r-- | components/breakpad/app/breakpad_linux.cc | 1615 | ||||
-rw-r--r-- | components/breakpad/app/breakpad_linux.h | 32 | ||||
-rw-r--r-- | components/breakpad/app/breakpad_linux_impl.h | 65 | ||||
-rw-r--r-- | components/breakpad/app/breakpad_mac.h | 27 | ||||
-rw-r--r-- | components/breakpad/app/breakpad_mac.mm | 279 | ||||
-rw-r--r-- | components/breakpad/app/breakpad_mac_stubs.mm | 24 | ||||
-rw-r--r-- | components/breakpad/app/breakpad_win.cc | 609 | ||||
-rw-r--r-- | components/breakpad/app/breakpad_win.h | 22 | ||||
-rw-r--r-- | components/breakpad/app/crash_keys_win.cc | 194 | ||||
-rw-r--r-- | components/breakpad/app/crash_keys_win.h | 75 | ||||
-rw-r--r-- | components/breakpad/app/crash_keys_win_unittest.cc | 145 | ||||
-rw-r--r-- | components/breakpad/app/hard_error_handler_win.cc | 118 | ||||
-rw-r--r-- | components/breakpad/app/hard_error_handler_win.h | 34 |
17 files changed, 0 insertions, 3585 deletions
diff --git a/components/breakpad/app/BUILD.gn b/components/breakpad/app/BUILD.gn deleted file mode 100644 index b8bd9aa..0000000 --- a/components/breakpad/app/BUILD.gn +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2014 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. - -if (is_android) { - import("//build/config/android/config.gni") -} - -source_set("lib") { - sources = [ - "breakpad_client.cc", - "breakpad_client.h", - "crash_keys_win.cc", - "crash_keys_win.h", - ] - - include_dirs = [ - "../../../breakpad/src", - ] -} - -# Note: if you depend on this target, you need to either link in -# content.gyp:content_common, or add content/public/common/content_switches.cc -# to your sources. -# -# GYP version: components/breakpad.gyp:breakpad_component -source_set("app") { - sources = [ - "breakpad_linux_impl.h", - "breakpad_mac.h", - "breakpad_mac.mm", - "breakpad_win.cc", - "breakpad_win.h", - "hard_error_handler_win.cc", - "hard_error_handler_win.h", - ] - if (is_android || is_linux) { - # Want these files on both Linux and Android. - set_sources_assignment_filter([]) - sources += [ - "breakpad_linux.cc", - "breakpad_linux.h", - ] - } - - defines = [ "BREAKPAD_IMPLEMENTATION" ] - - deps = [ - "//base", - ":lib", - ] - - if (is_mac) { - deps += [ "//breakpad" ] - } else if (is_win) { - deps += [ - "//sandbox", - "//breakpad:breakpad_handler", - #'../breakpad/breakpad.gyp:breakpad_sender', TODO(GYP) - ] - } else if (is_posix && !is_ios && - (!is_android || !is_android_webview_build)) { - deps += [ "//breakpad:client" ] - } -} - -source_set("test_support") { - deps = [ ":lib" ] -} diff --git a/components/breakpad/app/DEPS b/components/breakpad/app/DEPS deleted file mode 100644 index 4080651..0000000 --- a/components/breakpad/app/DEPS +++ /dev/null @@ -1,7 +0,0 @@ -include_rules = [ - "+sandbox", - - "+content/public/common/content_descriptors.h", - "+content/public/common/result_codes.h", - "+third_party/lss/linux_syscall_support.h", -] diff --git a/components/breakpad/app/breakpad_client.cc b/components/breakpad/app/breakpad_client.cc deleted file mode 100644 index 5c763ca..0000000 --- a/components/breakpad/app/breakpad_client.cc +++ /dev/null @@ -1,127 +0,0 @@ -// 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. - -#include "components/breakpad/app/breakpad_client.h" - -#include "base/files/file_path.h" -#include "base/logging.h" - -namespace breakpad { - -namespace { - -BreakpadClient* g_client = NULL; - -} // namespace - -void SetBreakpadClient(BreakpadClient* client) { - g_client = client; -} - -BreakpadClient* GetBreakpadClient() { - DCHECK(g_client); - return g_client; -} - -BreakpadClient::BreakpadClient() {} -BreakpadClient::~BreakpadClient() {} - -void BreakpadClient::SetBreakpadClientIdFromGUID( - const std::string& client_guid) { -} - -#if defined(OS_WIN) -bool BreakpadClient::GetAlternativeCrashDumpLocation( - base::FilePath* crash_dir) { - return false; -} - -void BreakpadClient::GetProductNameAndVersion(const base::FilePath& exe_path, - base::string16* product_name, - base::string16* version, - base::string16* special_build, - base::string16* channel_name) { -} - -bool BreakpadClient::ShouldShowRestartDialog(base::string16* title, - base::string16* message, - bool* is_rtl_locale) { - return false; -} - -bool BreakpadClient::AboutToRestart() { - return false; -} - -bool BreakpadClient::GetDeferredUploadsSupported(bool is_per_usr_install) { - return false; -} - -bool BreakpadClient::GetIsPerUserInstall(const base::FilePath& exe_path) { - return true; -} - -bool BreakpadClient::GetShouldDumpLargerDumps(bool is_per_user_install) { - return false; -} - -int BreakpadClient::GetResultCodeRespawnFailed() { - return 0; -} - -void BreakpadClient::InitBrowserCrashDumpsRegKey() { -} - -void BreakpadClient::RecordCrashDumpAttempt(bool is_real_crash) { -} -#endif - -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS) -void BreakpadClient::GetProductNameAndVersion(std::string* product_name, - std::string* version) { -} - -base::FilePath BreakpadClient::GetReporterLogFilename() { - return base::FilePath(); -} -#endif - -bool BreakpadClient::GetCrashDumpLocation(base::FilePath* crash_dir) { - return false; -} - -size_t BreakpadClient::RegisterCrashKeys() { - return 0; -} - -bool BreakpadClient::IsRunningUnattended() { - return true; -} - -bool BreakpadClient::GetCollectStatsConsent() { - return false; -} - -#if defined(OS_WIN) || defined(OS_MACOSX) -bool BreakpadClient::ReportingIsEnforcedByPolicy(bool* breakpad_enabled) { - return false; -} -#endif - -#if defined(OS_ANDROID) -int BreakpadClient::GetAndroidMinidumpDescriptor() { - return 0; -} -#endif - -#if defined(OS_MACOSX) -void BreakpadClient::InstallAdditionalFilters(BreakpadRef breakpad) { -} -#endif - -bool BreakpadClient::EnableBreakpadForProcess(const std::string& process_type) { - return false; -} - -} // namespace breakpad diff --git a/components/breakpad/app/breakpad_client.h b/components/breakpad/app/breakpad_client.h deleted file mode 100644 index 7ade184c..0000000 --- a/components/breakpad/app/breakpad_client.h +++ /dev/null @@ -1,143 +0,0 @@ -// 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. - -#ifndef COMPONENTS_BREAKPAD_APP_BREAKPAD_CLIENT_H_ -#define COMPONENTS_BREAKPAD_APP_BREAKPAD_CLIENT_H_ - -#include <string> - -#include "base/strings/string16.h" -#include "build/build_config.h" - -namespace base { -class FilePath; -} - -#if defined(OS_MACOSX) -// We don't want to directly include -// breakpad/src/client/mac/Framework/Breakpad.h here, so we repeat the -// definition of BreakpadRef. -// -// On Mac, when compiling without breakpad support, a stub implementation is -// compiled in. Not having any includes of the breakpad library allows for -// reusing this header for the stub. -typedef void* BreakpadRef; -#endif - -namespace breakpad { - -class BreakpadClient; - -// Setter and getter for the client. The client should be set early, before any -// breakpad code is called, and should stay alive throughout the entire runtime. -void SetBreakpadClient(BreakpadClient* client); - -#if defined(BREAKPAD_IMPLEMENTATION) -// Breakpad's embedder API should only be used by breakpad. -BreakpadClient* GetBreakpadClient(); -#endif - -// Interface that the embedder implements. -class BreakpadClient { - public: - BreakpadClient(); - virtual ~BreakpadClient(); - - // Sets the Breakpad client ID, which is a unique identifier for the client - // that is sending crash reports. After it is set, it should not be changed. - // |client_guid| may either be a full GUID or a GUID that was already stripped - // from its dashes. - virtual void SetBreakpadClientIdFromGUID(const std::string& client_guid); - -#if defined(OS_WIN) - // Returns true if an alternative location to store the minidump files was - // specified. Returns true if |crash_dir| was set. - virtual bool GetAlternativeCrashDumpLocation(base::FilePath* crash_dir); - - // Returns a textual description of the product type and version to include - // in the crash report. - virtual void GetProductNameAndVersion(const base::FilePath& exe_path, - base::string16* product_name, - base::string16* version, - base::string16* special_build, - base::string16* channel_name); - - // Returns true if a restart dialog should be displayed. In that case, - // |message| and |title| are set to a message to display in a dialog box with - // the given title before restarting, and |is_rtl_locale| indicates whether - // to display the text as RTL. - virtual bool ShouldShowRestartDialog(base::string16* title, - base::string16* message, - bool* is_rtl_locale); - - // Returns true if it is ok to restart the application. Invoked right before - // restarting after a crash. - virtual bool AboutToRestart(); - - // Returns true if the crash report uploader supports deferred uploads. - virtual bool GetDeferredUploadsSupported(bool is_per_user_install); - - // Returns true if the running binary is a per-user installation. - virtual bool GetIsPerUserInstall(const base::FilePath& exe_path); - - // Returns true if larger crash dumps should be dumped. - virtual bool GetShouldDumpLargerDumps(bool is_per_user_install); - - // Returns the result code to return when breakpad failed to respawn a - // crashed process. - virtual int GetResultCodeRespawnFailed(); - - // Invoked when initializing breakpad in the browser process. - virtual void InitBrowserCrashDumpsRegKey(); - - // Invoked before attempting to write a minidump. - virtual void RecordCrashDumpAttempt(bool is_real_crash); -#endif - -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS) - // Returns a textual description of the product type and version to include - // in the crash report. - virtual void GetProductNameAndVersion(std::string* product_name, - std::string* version); - - virtual base::FilePath GetReporterLogFilename(); -#endif - - // The location where minidump files should be written. Returns true if - // |crash_dir| was set. - virtual bool GetCrashDumpLocation(base::FilePath* crash_dir); - - // Register all of the potential crash keys that can be sent to the crash - // reporting server. Returns the size of the union of all keys. - virtual size_t RegisterCrashKeys(); - - // Returns true if running in unattended mode (for automated testing). - virtual bool IsRunningUnattended(); - - // Returns true if the user has given consent to collect stats. - virtual bool GetCollectStatsConsent(); - -#if defined(OS_WIN) || defined(OS_MACOSX) - // Returns true if breakpad is enforced via management policies. In that - // case, |breakpad_enabled| is set to the value enforced by policies. - virtual bool ReportingIsEnforcedByPolicy(bool* breakpad_enabled); -#endif - -#if defined(OS_ANDROID) - // Returns the descriptor key of the android minidump global descriptor. - virtual int GetAndroidMinidumpDescriptor(); -#endif - -#if defined(OS_MACOSX) - // Install additional breakpad filter callbacks. - virtual void InstallAdditionalFilters(BreakpadRef breakpad); -#endif - - // Returns true if breakpad should run in the given process type. - virtual bool EnableBreakpadForProcess(const std::string& process_type); -}; - -} // namespace breakpad - -#endif // COMPONENTS_BREAKPAD_APP_BREAKPAD_CLIENT_H_ diff --git a/components/breakpad/app/breakpad_linux.cc b/components/breakpad/app/breakpad_linux.cc deleted file mode 100644 index df9d588..0000000 --- a/components/breakpad/app/breakpad_linux.cc +++ /dev/null @@ -1,1615 +0,0 @@ -// 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. - -// For linux_syscall_support.h. This makes it safe to call embedded system -// calls when in seccomp mode. - -#include "components/breakpad/app/breakpad_linux.h" - -#include <fcntl.h> -#include <poll.h> -#include <signal.h> -#include <stdlib.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/uio.h> -#include <sys/wait.h> -#include <time.h> -#include <unistd.h> - -#include <algorithm> -#include <string> - -#include "base/base_switches.h" -#include "base/command_line.h" -#include "base/debug/crash_logging.h" -#include "base/debug/dump_without_crashing.h" -#include "base/files/file_path.h" -#include "base/linux_util.h" -#include "base/path_service.h" -#include "base/posix/eintr_wrapper.h" -#include "base/posix/global_descriptors.h" -#include "base/process/memory.h" -#include "base/strings/string_util.h" -#include "breakpad/src/client/linux/crash_generation/crash_generation_client.h" -#include "breakpad/src/client/linux/handler/exception_handler.h" -#include "breakpad/src/client/linux/minidump_writer/directory_reader.h" -#include "breakpad/src/common/linux/linux_libc_support.h" -#include "breakpad/src/common/memory.h" -#include "components/breakpad/app/breakpad_client.h" -#include "components/breakpad/app/breakpad_linux_impl.h" -#include "content/public/common/content_descriptors.h" - -#if defined(OS_ANDROID) -#include <android/log.h> -#include <sys/stat.h> - -#include "base/android/build_info.h" -#include "base/android/path_utils.h" -#endif -#include "third_party/lss/linux_syscall_support.h" - -#if defined(ADDRESS_SANITIZER) -#include <ucontext.h> // for getcontext(). -#endif - -#if defined(OS_ANDROID) -#define STAT_STRUCT struct stat -#define FSTAT_FUNC fstat -#else -#define STAT_STRUCT struct kernel_stat -#define FSTAT_FUNC sys_fstat -#endif - -// Some versions of gcc are prone to warn about unused return values. In cases -// where we either a) know the call cannot fail, or b) there is nothing we -// can do when a call fails, we mark the return code as ignored. This avoids -// spurious compiler warnings. -#define IGNORE_RET(x) do { if (x); } while (0) - -using google_breakpad::ExceptionHandler; -using google_breakpad::MinidumpDescriptor; - -namespace breakpad { - -namespace { - -#if !defined(OS_CHROMEOS) -const char kUploadURL[] = "https://clients2.google.com/cr/report"; -#endif - -bool g_is_crash_reporter_enabled = false; -uint64_t g_process_start_time = 0; -pid_t g_pid = 0; -char* g_crash_log_path = NULL; -ExceptionHandler* g_breakpad = NULL; - -#if defined(ADDRESS_SANITIZER) -const char* g_asan_report_str = NULL; -#endif -#if defined(OS_ANDROID) -char* g_process_type = NULL; -#endif - -CrashKeyStorage* g_crash_keys = NULL; - -// Writes the value |v| as 16 hex characters to the memory pointed at by -// |output|. -void write_uint64_hex(char* output, uint64_t v) { - static const char hextable[] = "0123456789abcdef"; - - for (int i = 15; i >= 0; --i) { - output[i] = hextable[v & 15]; - v >>= 4; - } -} - -// The following helper functions are for calculating uptime. - -// Converts a struct timeval to milliseconds. -uint64_t timeval_to_ms(struct timeval *tv) { - uint64_t ret = tv->tv_sec; // Avoid overflow by explicitly using a uint64_t. - ret *= 1000; - ret += tv->tv_usec / 1000; - return ret; -} - -// Converts a struct timeval to milliseconds. -uint64_t kernel_timeval_to_ms(struct kernel_timeval *tv) { - uint64_t ret = tv->tv_sec; // Avoid overflow by explicitly using a uint64_t. - ret *= 1000; - ret += tv->tv_usec / 1000; - return ret; -} - -// String buffer size to use to convert a uint64_t to string. -const size_t kUint64StringSize = 21; - -void SetProcessStartTime() { - // Set the base process start time value. - struct timeval tv; - if (!gettimeofday(&tv, NULL)) - g_process_start_time = timeval_to_ms(&tv); - else - g_process_start_time = 0; -} - -// uint64_t version of my_int_len() from -// breakpad/src/common/linux/linux_libc_support.h. Return the length of the -// given, non-negative integer when expressed in base 10. -unsigned my_uint64_len(uint64_t i) { - if (!i) - return 1; - - unsigned len = 0; - while (i) { - len++; - i /= 10; - } - - return len; -} - -// uint64_t version of my_uitos() from -// breakpad/src/common/linux/linux_libc_support.h. Convert a non-negative -// integer to a string (not null-terminated). -void my_uint64tos(char* output, uint64_t i, unsigned i_len) { - for (unsigned index = i_len; index; --index, i /= 10) - output[index - 1] = '0' + (i % 10); -} - -#if defined(OS_ANDROID) -char* my_strncpy(char* dst, const char* src, size_t len) { - int i = len; - char* p = dst; - if (!dst || !src) - return dst; - while (i != 0 && *src != '\0') { - *p++ = *src++; - i--; - } - while (i != 0) { - *p++ = '\0'; - i--; - } - return dst; -} - -char* my_strncat(char *dest, const char* src, size_t len) { - char* ret = dest; - while (*dest) - dest++; - while (len--) - if (!(*dest++ = *src++)) - return ret; - *dest = 0; - return ret; -} -#endif - -#if !defined(OS_CHROMEOS) -bool my_isxdigit(char c) { - return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); -} -#endif - -size_t LengthWithoutTrailingSpaces(const char* str, size_t len) { - while (len > 0 && str[len - 1] == ' ') { - len--; - } - return len; -} - -void SetClientIdFromCommandLine(const CommandLine& command_line) { - // Get the guid from the command line switch. - std::string switch_value = - command_line.GetSwitchValueASCII(switches::kEnableCrashReporter); - GetBreakpadClient()->SetBreakpadClientIdFromGUID(switch_value); -} - -// MIME substrings. -#if defined(OS_CHROMEOS) -const char g_sep[] = ":"; -#endif -const char g_rn[] = "\r\n"; -const char g_form_data_msg[] = "Content-Disposition: form-data; name=\""; -const char g_quote_msg[] = "\""; -const char g_dashdash_msg[] = "--"; -const char g_dump_msg[] = "upload_file_minidump\"; filename=\"dump\""; -#if defined(ADDRESS_SANITIZER) -const char g_log_msg[] = "upload_file_log\"; filename=\"log\""; -#endif -const char g_content_type_msg[] = "Content-Type: application/octet-stream"; - -// MimeWriter manages an iovec for writing MIMEs to a file. -class MimeWriter { - public: - static const int kIovCapacity = 30; - static const size_t kMaxCrashChunkSize = 64; - - MimeWriter(int fd, const char* const mime_boundary); - ~MimeWriter(); - - // Append boundary. - virtual void AddBoundary(); - - // Append end of file boundary. - virtual void AddEnd(); - - // Append key/value pair with specified sizes. - virtual void AddPairData(const char* msg_type, - size_t msg_type_size, - const char* msg_data, - size_t msg_data_size); - - // Append key/value pair. - void AddPairString(const char* msg_type, - const char* msg_data) { - AddPairData(msg_type, my_strlen(msg_type), msg_data, my_strlen(msg_data)); - } - - // Append key/value pair, splitting value into chunks no larger than - // |chunk_size|. |chunk_size| cannot be greater than |kMaxCrashChunkSize|. - // The msg_type string will have a counter suffix to distinguish each chunk. - virtual void AddPairDataInChunks(const char* msg_type, - size_t msg_type_size, - const char* msg_data, - size_t msg_data_size, - size_t chunk_size, - bool strip_trailing_spaces); - - // Add binary file contents to be uploaded with the specified filename. - virtual void AddFileContents(const char* filename_msg, - uint8_t* file_data, - size_t file_size); - - // Flush any pending iovecs to the output file. - void Flush() { - IGNORE_RET(sys_writev(fd_, iov_, iov_index_)); - iov_index_ = 0; - } - - protected: - void AddItem(const void* base, size_t size); - // Minor performance trade-off for easier-to-maintain code. - void AddString(const char* str) { - AddItem(str, my_strlen(str)); - } - void AddItemWithoutTrailingSpaces(const void* base, size_t size); - - struct kernel_iovec iov_[kIovCapacity]; - int iov_index_; - - // Output file descriptor. - int fd_; - - const char* const mime_boundary_; - - private: - DISALLOW_COPY_AND_ASSIGN(MimeWriter); -}; - -MimeWriter::MimeWriter(int fd, const char* const mime_boundary) - : iov_index_(0), - fd_(fd), - mime_boundary_(mime_boundary) { -} - -MimeWriter::~MimeWriter() { -} - -void MimeWriter::AddBoundary() { - AddString(mime_boundary_); - AddString(g_rn); -} - -void MimeWriter::AddEnd() { - AddString(mime_boundary_); - AddString(g_dashdash_msg); - AddString(g_rn); -} - -void MimeWriter::AddPairData(const char* msg_type, - size_t msg_type_size, - const char* msg_data, - size_t msg_data_size) { - AddString(g_form_data_msg); - AddItem(msg_type, msg_type_size); - AddString(g_quote_msg); - AddString(g_rn); - AddString(g_rn); - AddItem(msg_data, msg_data_size); - AddString(g_rn); -} - -void MimeWriter::AddPairDataInChunks(const char* msg_type, - size_t msg_type_size, - const char* msg_data, - size_t msg_data_size, - size_t chunk_size, - bool strip_trailing_spaces) { - if (chunk_size > kMaxCrashChunkSize) - return; - - unsigned i = 0; - size_t done = 0, msg_length = msg_data_size; - - while (msg_length) { - char num[kUint64StringSize]; - const unsigned num_len = my_uint_len(++i); - my_uitos(num, i, num_len); - - size_t chunk_len = std::min(chunk_size, msg_length); - - AddString(g_form_data_msg); - AddItem(msg_type, msg_type_size); - AddItem(num, num_len); - AddString(g_quote_msg); - AddString(g_rn); - AddString(g_rn); - if (strip_trailing_spaces) { - AddItemWithoutTrailingSpaces(msg_data + done, chunk_len); - } else { - AddItem(msg_data + done, chunk_len); - } - AddString(g_rn); - AddBoundary(); - Flush(); - - done += chunk_len; - msg_length -= chunk_len; - } -} - -void MimeWriter::AddFileContents(const char* filename_msg, uint8_t* file_data, - size_t file_size) { - AddString(g_form_data_msg); - AddString(filename_msg); - AddString(g_rn); - AddString(g_content_type_msg); - AddString(g_rn); - AddString(g_rn); - AddItem(file_data, file_size); - AddString(g_rn); -} - -void MimeWriter::AddItem(const void* base, size_t size) { - // Check if the iovec is full and needs to be flushed to output file. - if (iov_index_ == kIovCapacity) { - Flush(); - } - iov_[iov_index_].iov_base = const_cast<void*>(base); - iov_[iov_index_].iov_len = size; - ++iov_index_; -} - -void MimeWriter::AddItemWithoutTrailingSpaces(const void* base, size_t size) { - AddItem(base, LengthWithoutTrailingSpaces(static_cast<const char*>(base), - size)); -} - -#if defined(OS_CHROMEOS) -// This subclass is used on Chromium OS to report crashes in a format easy for -// the central crash reporting facility to understand. -// Format is <name>:<data length in decimal>:<data> -class CrashReporterWriter : public MimeWriter { - public: - explicit CrashReporterWriter(int fd); - - virtual void AddBoundary() OVERRIDE; - - virtual void AddEnd() OVERRIDE; - - virtual void AddPairData(const char* msg_type, - size_t msg_type_size, - const char* msg_data, - size_t msg_data_size) OVERRIDE; - - virtual void AddPairDataInChunks(const char* msg_type, - size_t msg_type_size, - const char* msg_data, - size_t msg_data_size, - size_t chunk_size, - bool strip_trailing_spaces) OVERRIDE; - - virtual void AddFileContents(const char* filename_msg, - uint8_t* file_data, - size_t file_size) OVERRIDE; - - private: - DISALLOW_COPY_AND_ASSIGN(CrashReporterWriter); -}; - - -CrashReporterWriter::CrashReporterWriter(int fd) : MimeWriter(fd, "") {} - -// No-ops. -void CrashReporterWriter::AddBoundary() {} -void CrashReporterWriter::AddEnd() {} - -void CrashReporterWriter::AddPairData(const char* msg_type, - size_t msg_type_size, - const char* msg_data, - size_t msg_data_size) { - char data[kUint64StringSize]; - const unsigned data_len = my_uint_len(msg_data_size); - my_uitos(data, msg_data_size, data_len); - - AddItem(msg_type, msg_type_size); - AddString(g_sep); - AddItem(data, data_len); - AddString(g_sep); - AddItem(msg_data, msg_data_size); - Flush(); -} - -void CrashReporterWriter::AddPairDataInChunks(const char* msg_type, - size_t msg_type_size, - const char* msg_data, - size_t msg_data_size, - size_t chunk_size, - bool strip_trailing_spaces) { - if (chunk_size > kMaxCrashChunkSize) - return; - - unsigned i = 0; - size_t done = 0; - size_t msg_length = msg_data_size; - - while (msg_length) { - char num[kUint64StringSize]; - const unsigned num_len = my_uint_len(++i); - my_uitos(num, i, num_len); - - size_t chunk_len = std::min(chunk_size, msg_length); - - size_t write_len = chunk_len; - if (strip_trailing_spaces) { - // Take care of this here because we need to know the exact length of - // what is going to be written. - write_len = LengthWithoutTrailingSpaces(msg_data + done, write_len); - } - - char data[kUint64StringSize]; - const unsigned data_len = my_uint_len(write_len); - my_uitos(data, write_len, data_len); - - AddItem(msg_type, msg_type_size); - AddItem(num, num_len); - AddString(g_sep); - AddItem(data, data_len); - AddString(g_sep); - AddItem(msg_data + done, write_len); - Flush(); - - done += chunk_len; - msg_length -= chunk_len; - } -} - -void CrashReporterWriter::AddFileContents(const char* filename_msg, - uint8_t* file_data, - size_t file_size) { - char data[kUint64StringSize]; - const unsigned data_len = my_uint_len(file_size); - my_uitos(data, file_size, data_len); - - AddString(filename_msg); - AddString(g_sep); - AddItem(data, data_len); - AddString(g_sep); - AddItem(file_data, file_size); - Flush(); -} -#endif // defined(OS_CHROMEOS) - -void DumpProcess() { - if (g_breakpad) - g_breakpad->WriteMinidump(); -} - -#if defined(OS_ANDROID) -const char kGoogleBreakpad[] = "google-breakpad"; -#endif - -size_t WriteLog(const char* buf, size_t nbytes) { -#if defined(OS_ANDROID) - return __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, buf); -#else - return sys_write(2, buf, nbytes); -#endif -} - -size_t WriteNewline() { - return WriteLog("\n", 1); -} - -#if defined(OS_ANDROID) -// Android's native crash handler outputs a diagnostic tombstone to the device -// log. By returning false from the HandlerCallbacks, breakpad will reinstall -// the previous (i.e. native) signal handlers before returning from its own -// handler. A Chrome build fingerprint is written to the log, so that the -// specific build of Chrome and the location of the archived Chrome symbols can -// be determined directly from it. -bool FinalizeCrashDoneAndroid() { - base::android::BuildInfo* android_build_info = - base::android::BuildInfo::GetInstance(); - - __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, - "### ### ### ### ### ### ### ### ### ### ### ### ###"); - __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, - "Chrome build fingerprint:"); - __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, - android_build_info->package_version_name()); - __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, - android_build_info->package_version_code()); - __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, - CHROME_BUILD_ID); - __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, - "### ### ### ### ### ### ### ### ### ### ### ### ###"); - return false; -} -#endif - -bool CrashDone(const MinidumpDescriptor& minidump, - const bool upload, - const bool succeeded) { - // WARNING: this code runs in a compromised context. It may not call into - // libc nor allocate memory normally. - if (!succeeded) { - const char msg[] = "Failed to generate minidump."; - WriteLog(msg, sizeof(msg) - 1); - return false; - } - - DCHECK(!minidump.IsFD()); - - BreakpadInfo info = {0}; - info.filename = minidump.path(); - info.fd = minidump.fd(); -#if defined(ADDRESS_SANITIZER) - google_breakpad::PageAllocator allocator; - const size_t log_path_len = my_strlen(minidump.path()); - char* log_path = reinterpret_cast<char*>(allocator.Alloc(log_path_len + 1)); - my_memcpy(log_path, minidump.path(), log_path_len); - my_memcpy(log_path + log_path_len - 4, ".log", 4); - log_path[log_path_len] = '\0'; - info.log_filename = log_path; -#endif - info.process_type = "browser"; - info.process_type_length = 7; - info.distro = base::g_linux_distro; - info.distro_length = my_strlen(base::g_linux_distro); - info.upload = upload; - info.process_start_time = g_process_start_time; - info.oom_size = base::g_oom_size; - info.pid = g_pid; - info.crash_keys = g_crash_keys; - HandleCrashDump(info); -#if defined(OS_ANDROID) - return FinalizeCrashDoneAndroid(); -#else - return true; -#endif -} - -// Wrapper function, do not add more code here. -bool CrashDoneNoUpload(const MinidumpDescriptor& minidump, - void* context, - bool succeeded) { - return CrashDone(minidump, false, succeeded); -} - -#if !defined(OS_ANDROID) -// Wrapper function, do not add more code here. -bool CrashDoneUpload(const MinidumpDescriptor& minidump, - void* context, - bool succeeded) { - return CrashDone(minidump, true, succeeded); -} -#endif - -#if defined(ADDRESS_SANITIZER) -extern "C" -void __asan_set_error_report_callback(void (*cb)(const char*)); - -extern "C" -void AsanLinuxBreakpadCallback(const char* report) { - g_asan_report_str = report; - // Send minidump here. - g_breakpad->SimulateSignalDelivery(SIGKILL); -} -#endif - -void EnableCrashDumping(bool unattended) { - g_is_crash_reporter_enabled = true; - - base::FilePath tmp_path("/tmp"); - PathService::Get(base::DIR_TEMP, &tmp_path); - - base::FilePath dumps_path(tmp_path); - if (GetBreakpadClient()->GetCrashDumpLocation(&dumps_path)) { - base::FilePath logfile = - dumps_path.Append(GetBreakpadClient()->GetReporterLogFilename()); - std::string logfile_str = logfile.value(); - const size_t crash_log_path_len = logfile_str.size() + 1; - g_crash_log_path = new char[crash_log_path_len]; - strncpy(g_crash_log_path, logfile_str.c_str(), crash_log_path_len); - } - DCHECK(!g_breakpad); - MinidumpDescriptor minidump_descriptor(dumps_path.value()); - minidump_descriptor.set_size_limit(kMaxMinidumpFileSize); -#if defined(OS_ANDROID) - unattended = true; // Android never uploads directly. -#endif - if (unattended) { - g_breakpad = new ExceptionHandler( - minidump_descriptor, - NULL, - CrashDoneNoUpload, - NULL, - true, // Install handlers. - -1); // Server file descriptor. -1 for in-process. - return; - } - -#if !defined(OS_ANDROID) - // Attended mode - g_breakpad = new ExceptionHandler( - minidump_descriptor, - NULL, - CrashDoneUpload, - NULL, - true, // Install handlers. - -1); // Server file descriptor. -1 for in-process. -#endif -} - -#if defined(OS_ANDROID) -bool CrashDoneInProcessNoUpload( - const google_breakpad::MinidumpDescriptor& descriptor, - void* context, - const bool succeeded) { - // WARNING: this code runs in a compromised context. It may not call into - // libc nor allocate memory normally. - if (!succeeded) { - static const char msg[] = "Crash dump generation failed.\n"; - WriteLog(msg, sizeof(msg) - 1); - return false; - } - - // Start constructing the message to send to the browser. - BreakpadInfo info = {0}; - info.filename = NULL; - info.fd = descriptor.fd(); - info.process_type = g_process_type; - info.process_type_length = my_strlen(g_process_type); - info.distro = NULL; - info.distro_length = 0; - info.upload = false; - info.process_start_time = g_process_start_time; - info.pid = g_pid; - info.crash_keys = g_crash_keys; - HandleCrashDump(info); - bool finalize_result = FinalizeCrashDoneAndroid(); - base::android::BuildInfo* android_build_info = - base::android::BuildInfo::GetInstance(); - if (android_build_info->sdk_int() >= 18 && - my_strcmp(android_build_info->build_type(), "eng") != 0 && - my_strcmp(android_build_info->build_type(), "userdebug") != 0) { - // On JB MR2 and later, the system crash handler displays a dialog. For - // renderer crashes, this is a bad user experience and so this is disabled - // for user builds of Android. - // TODO(cjhopman): There should be some way to recover the crash stack from - // non-uploading user clients. See http://crbug.com/273706. - __android_log_write(ANDROID_LOG_WARN, - kGoogleBreakpad, - "Tombstones are disabled on JB MR2+ user builds."); - __android_log_write(ANDROID_LOG_WARN, - kGoogleBreakpad, - "### ### ### ### ### ### ### ### ### ### ### ### ###"); - return true; - } else { - return finalize_result; - } -} - -void EnableNonBrowserCrashDumping(const std::string& process_type, - int minidump_fd) { - // This will guarantee that the BuildInfo has been initialized and subsequent - // calls will not require memory allocation. - base::android::BuildInfo::GetInstance(); - SetClientIdFromCommandLine(*CommandLine::ForCurrentProcess()); - - // On Android, the current sandboxing uses process isolation, in which the - // child process runs with a different UID. That breaks the normal crash - // reporting where the browser process generates the minidump by inspecting - // the child process. This is because the browser process now does not have - // the permission to access the states of the child process (as it has a - // different UID). - // TODO(jcivelli): http://b/issue?id=6776356 we should use a watchdog - // process forked from the renderer process that generates the minidump. - if (minidump_fd == -1) { - LOG(ERROR) << "Minidump file descriptor not found, crash reporting will " - " not work."; - return; - } - SetProcessStartTime(); - g_pid = getpid(); - - g_is_crash_reporter_enabled = true; - // Save the process type (it is leaked). - const size_t process_type_len = process_type.size() + 1; - g_process_type = new char[process_type_len]; - strncpy(g_process_type, process_type.c_str(), process_type_len); - new google_breakpad::ExceptionHandler(MinidumpDescriptor(minidump_fd), - NULL, CrashDoneInProcessNoUpload, NULL, true, -1); -} -#else -// Non-Browser = Extension, Gpu, Plugins, Ppapi and Renderer -class NonBrowserCrashHandler : public google_breakpad::CrashGenerationClient { - public: - NonBrowserCrashHandler() - : server_fd_(base::GlobalDescriptors::GetInstance()->Get( - kCrashDumpSignal)) { - } - - virtual ~NonBrowserCrashHandler() {} - - virtual bool RequestDump(const void* crash_context, - size_t crash_context_size) OVERRIDE { - int fds[2] = { -1, -1 }; - if (sys_socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { - static const char msg[] = "Failed to create socket for crash dumping.\n"; - WriteLog(msg, sizeof(msg) - 1); - return false; - } - - // Start constructing the message to send to the browser. - char b; // Dummy variable for sys_read below. - const char* b_addr = &b; // Get the address of |b| so we can create the - // expected /proc/[pid]/syscall content in the - // browser to convert namespace tids. - - // The length of the control message: - static const unsigned kControlMsgSize = sizeof(int); - static const unsigned kControlMsgSpaceSize = CMSG_SPACE(kControlMsgSize); - static const unsigned kControlMsgLenSize = CMSG_LEN(kControlMsgSize); - - struct kernel_msghdr msg; - my_memset(&msg, 0, sizeof(struct kernel_msghdr)); - struct kernel_iovec iov[kCrashIovSize]; - iov[0].iov_base = const_cast<void*>(crash_context); - iov[0].iov_len = crash_context_size; - iov[1].iov_base = &b_addr; - iov[1].iov_len = sizeof(b_addr); - iov[2].iov_base = &fds[0]; - iov[2].iov_len = sizeof(fds[0]); - iov[3].iov_base = &g_process_start_time; - iov[3].iov_len = sizeof(g_process_start_time); - iov[4].iov_base = &base::g_oom_size; - iov[4].iov_len = sizeof(base::g_oom_size); - google_breakpad::SerializedNonAllocatingMap* serialized_map; - iov[5].iov_len = g_crash_keys->Serialize( - const_cast<const google_breakpad::SerializedNonAllocatingMap**>( - &serialized_map)); - iov[5].iov_base = serialized_map; -#if !defined(ADDRESS_SANITIZER) - COMPILE_ASSERT(5 == kCrashIovSize - 1, Incorrect_Number_Of_Iovec_Members); -#else - iov[6].iov_base = const_cast<char*>(g_asan_report_str); - iov[6].iov_len = kMaxAsanReportSize + 1; - COMPILE_ASSERT(6 == kCrashIovSize - 1, Incorrect_Number_Of_Iovec_Members); -#endif - - msg.msg_iov = iov; - msg.msg_iovlen = kCrashIovSize; - char cmsg[kControlMsgSpaceSize]; - my_memset(cmsg, 0, kControlMsgSpaceSize); - msg.msg_control = cmsg; - msg.msg_controllen = sizeof(cmsg); - - struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); - hdr->cmsg_level = SOL_SOCKET; - hdr->cmsg_type = SCM_RIGHTS; - hdr->cmsg_len = kControlMsgLenSize; - ((int*)CMSG_DATA(hdr))[0] = fds[1]; - - if (HANDLE_EINTR(sys_sendmsg(server_fd_, &msg, 0)) < 0) { - static const char errmsg[] = "Failed to tell parent about crash.\n"; - WriteLog(errmsg, sizeof(errmsg) - 1); - IGNORE_RET(sys_close(fds[0])); - IGNORE_RET(sys_close(fds[1])); - return false; - } - IGNORE_RET(sys_close(fds[1])); - - if (HANDLE_EINTR(sys_read(fds[0], &b, 1)) != 1) { - static const char errmsg[] = "Parent failed to complete crash dump.\n"; - WriteLog(errmsg, sizeof(errmsg) - 1); - } - IGNORE_RET(sys_close(fds[0])); - - return true; - } - - private: - // The pipe FD to the browser process, which will handle the crash dumping. - const int server_fd_; - - DISALLOW_COPY_AND_ASSIGN(NonBrowserCrashHandler); -}; - -void EnableNonBrowserCrashDumping() { - g_is_crash_reporter_enabled = true; - // We deliberately leak this object. - DCHECK(!g_breakpad); - - g_breakpad = new ExceptionHandler( - MinidumpDescriptor("/tmp"), // Unused but needed or Breakpad will assert. - NULL, - NULL, - NULL, - true, - -1); - g_breakpad->set_crash_generation_client(new NonBrowserCrashHandler()); -} -#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()); -} - -// GetBreakpadClient() cannot call any Set methods until after InitCrashKeys(). -void InitCrashKeys() { - g_crash_keys = new CrashKeyStorage; - GetBreakpadClient()->RegisterCrashKeys(); - base::debug::SetCrashKeyReportingFunctions(&SetCrashKeyValue, &ClearCrashKey); -} - -// Miscellaneous initialization functions to call after Breakpad has been -// enabled. -void PostEnableBreakpadInitialization() { - SetProcessStartTime(); - g_pid = getpid(); - - base::debug::SetDumpWithoutCrashingFunction(&DumpProcess); -#if defined(ADDRESS_SANITIZER) - // Register the callback for AddressSanitizer error reporting. - __asan_set_error_report_callback(AsanLinuxBreakpadCallback); -#endif -} - -} // namespace - -void LoadDataFromFD(google_breakpad::PageAllocator& allocator, - int fd, bool close_fd, uint8_t** file_data, size_t* size) { - STAT_STRUCT st; - if (FSTAT_FUNC(fd, &st) != 0) { - static const char msg[] = "Cannot upload crash dump: stat failed\n"; - WriteLog(msg, sizeof(msg) - 1); - if (close_fd) - IGNORE_RET(sys_close(fd)); - return; - } - - *file_data = reinterpret_cast<uint8_t*>(allocator.Alloc(st.st_size)); - if (!(*file_data)) { - static const char msg[] = "Cannot upload crash dump: cannot alloc\n"; - WriteLog(msg, sizeof(msg) - 1); - if (close_fd) - IGNORE_RET(sys_close(fd)); - return; - } - my_memset(*file_data, 0xf, st.st_size); - - *size = st.st_size; - int byte_read = sys_read(fd, *file_data, *size); - if (byte_read == -1) { - static const char msg[] = "Cannot upload crash dump: read failed\n"; - WriteLog(msg, sizeof(msg) - 1); - if (close_fd) - IGNORE_RET(sys_close(fd)); - return; - } - - if (close_fd) - IGNORE_RET(sys_close(fd)); -} - -void LoadDataFromFile(google_breakpad::PageAllocator& allocator, - const char* filename, - int* fd, uint8_t** file_data, size_t* size) { - // WARNING: this code runs in a compromised context. It may not call into - // libc nor allocate memory normally. - *fd = sys_open(filename, O_RDONLY, 0); - *size = 0; - - if (*fd < 0) { - static const char msg[] = "Cannot upload crash dump: failed to open\n"; - WriteLog(msg, sizeof(msg) - 1); - return; - } - - LoadDataFromFD(allocator, *fd, true, file_data, size); -} - -// Spawn the appropriate upload process for the current OS: -// - generic Linux invokes wget. -// - ChromeOS invokes crash_reporter. -// |dumpfile| is the path to the dump data file. -// |mime_boundary| is only used on Linux. -// |exe_buf| is only used on CrOS and is the crashing process' name. -void ExecUploadProcessOrTerminate(const BreakpadInfo& info, - const char* dumpfile, - const char* mime_boundary, - const char* exe_buf, - google_breakpad::PageAllocator* allocator) { -#if defined(OS_CHROMEOS) - // CrOS uses crash_reporter instead of wget to report crashes, - // it needs to know where the crash dump lives and the pid and uid of the - // crashing process. - static const char kCrashReporterBinary[] = "/sbin/crash_reporter"; - - char pid_buf[kUint64StringSize]; - uint64_t pid_str_length = my_uint64_len(info.pid); - my_uint64tos(pid_buf, info.pid, pid_str_length); - pid_buf[pid_str_length] = '\0'; - - char uid_buf[kUint64StringSize]; - uid_t uid = geteuid(); - uint64_t uid_str_length = my_uint64_len(uid); - my_uint64tos(uid_buf, uid, uid_str_length); - uid_buf[uid_str_length] = '\0'; - const char* args[] = { - kCrashReporterBinary, - "--chrome", - dumpfile, - "--pid", - pid_buf, - "--uid", - uid_buf, - "--exe", - exe_buf, - NULL, - }; - static const char msg[] = "Cannot upload crash dump: cannot exec " - "/sbin/crash_reporter\n"; -#else - // The --header argument to wget looks like: - // --header=Content-Type: multipart/form-data; boundary=XYZ - // where the boundary has two fewer leading '-' chars - static const char header_msg[] = - "--header=Content-Type: multipart/form-data; boundary="; - char* const header = reinterpret_cast<char*>(allocator->Alloc( - sizeof(header_msg) - 1 + strlen(mime_boundary) - 2 + 1)); - memcpy(header, header_msg, sizeof(header_msg) - 1); - memcpy(header + sizeof(header_msg) - 1, mime_boundary + 2, - strlen(mime_boundary) - 2); - // We grab the NUL byte from the end of |mime_boundary|. - - // The --post-file argument to wget looks like: - // --post-file=/tmp/... - static const char post_file_msg[] = "--post-file="; - char* const post_file = reinterpret_cast<char*>(allocator->Alloc( - sizeof(post_file_msg) - 1 + strlen(dumpfile) + 1)); - memcpy(post_file, post_file_msg, sizeof(post_file_msg) - 1); - memcpy(post_file + sizeof(post_file_msg) - 1, dumpfile, strlen(dumpfile)); - - static const char kWgetBinary[] = "/usr/bin/wget"; - const char* args[] = { - kWgetBinary, - header, - post_file, - kUploadURL, - "--timeout=10", // Set a timeout so we don't hang forever. - "--tries=1", // Don't retry if the upload fails. - "-O", // output reply to fd 3 - "/dev/fd/3", - NULL, - }; - static const char msg[] = "Cannot upload crash dump: cannot exec " - "/usr/bin/wget\n"; -#endif - execve(args[0], const_cast<char**>(args), environ); - WriteLog(msg, sizeof(msg) - 1); - sys__exit(1); -} - -// Runs in the helper process to wait for the upload process running -// ExecUploadProcessOrTerminate() to finish. Returns the number of bytes written -// to |fd| and save the written contents to |buf|. -// |buf| needs to be big enough to hold |bytes_to_read| + 1 characters. -size_t WaitForCrashReportUploadProcess(int fd, size_t bytes_to_read, - char* buf) { - size_t bytes_read = 0; - - // Upload should finish in about 10 seconds. Add a few more 500 ms - // internals to account for process startup time. - for (size_t wait_count = 0; wait_count < 24; ++wait_count) { - struct kernel_pollfd poll_fd; - poll_fd.fd = fd; - poll_fd.events = POLLIN | POLLPRI | POLLERR; - int ret = sys_poll(&poll_fd, 1, 500); - if (ret < 0) { - // Error - break; - } else if (ret > 0) { - // There is data to read. - ssize_t len = HANDLE_EINTR( - sys_read(fd, buf + bytes_read, bytes_to_read - bytes_read)); - if (len < 0) - break; - bytes_read += len; - if (bytes_read == bytes_to_read) - break; - } - // |ret| == 0 -> timed out, continue waiting. - // or |bytes_read| < |bytes_to_read| still, keep reading. - } - buf[bytes_to_read] = 0; // Always NUL terminate the buffer. - return bytes_read; -} - -// |buf| should be |expected_len| + 1 characters in size and NULL terminated. -bool IsValidCrashReportId(const char* buf, size_t bytes_read, - size_t expected_len) { - if (bytes_read != expected_len) - return false; -#if defined(OS_CHROMEOS) - return my_strcmp(buf, "_sys_cr_finished") == 0; -#else - for (size_t i = 0; i < bytes_read; ++i) { - if (!my_isxdigit(buf[i])) - return false; - } - return true; -#endif -} - -// |buf| should be |expected_len| + 1 characters in size and NULL terminated. -void HandleCrashReportId(const char* buf, size_t bytes_read, - size_t expected_len) { - WriteNewline(); - if (!IsValidCrashReportId(buf, bytes_read, expected_len)) { -#if defined(OS_CHROMEOS) - static const char msg[] = "Crash_reporter failed to process crash report"; -#else - static const char msg[] = "Failed to get crash dump id."; -#endif - WriteLog(msg, sizeof(msg) - 1); - WriteNewline(); - return; - } - -#if defined(OS_CHROMEOS) - static const char msg[] = "Crash dump received by crash_reporter\n"; - WriteLog(msg, sizeof(msg) - 1); -#else - // Write crash dump id to stderr. - static const char msg[] = "Crash dump id: "; - WriteLog(msg, sizeof(msg) - 1); - WriteLog(buf, my_strlen(buf)); - WriteNewline(); - - // Write crash dump id to crash log as: seconds_since_epoch,crash_id - struct kernel_timeval tv; - if (g_crash_log_path && !sys_gettimeofday(&tv, NULL)) { - uint64_t time = kernel_timeval_to_ms(&tv) / 1000; - char time_str[kUint64StringSize]; - const unsigned time_len = my_uint64_len(time); - my_uint64tos(time_str, time, time_len); - - const int kLogOpenFlags = O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC; - int log_fd = sys_open(g_crash_log_path, kLogOpenFlags, 0600); - if (log_fd > 0) { - sys_write(log_fd, time_str, time_len); - sys_write(log_fd, ",", 1); - sys_write(log_fd, buf, my_strlen(buf)); - sys_write(log_fd, "\n", 1); - IGNORE_RET(sys_close(log_fd)); - } - } -#endif -} - -#if defined(OS_CHROMEOS) -const char* GetCrashingProcessName(const BreakpadInfo& info, - google_breakpad::PageAllocator* allocator) { - // Symlink to process binary is at /proc/###/exe. - char linkpath[kUint64StringSize + sizeof("/proc/") + sizeof("/exe")] = - "/proc/"; - uint64_t pid_value_len = my_uint64_len(info.pid); - my_uint64tos(linkpath + sizeof("/proc/") - 1, info.pid, pid_value_len); - linkpath[sizeof("/proc/") - 1 + pid_value_len] = '\0'; - my_strlcat(linkpath, "/exe", sizeof(linkpath)); - - const int kMaxSize = 4096; - char* link = reinterpret_cast<char*>(allocator->Alloc(kMaxSize)); - if (link) { - ssize_t size = readlink(linkpath, link, kMaxSize); - if (size < kMaxSize && size > 0) { - // readlink(2) doesn't add a terminating NUL, so do it now. - link[size] = '\0'; - - const char* name = my_strrchr(link, '/'); - if (name) - return name + 1; - return link; - } - } - // Either way too long, or a read error. - return "chrome-crash-unknown-process"; -} -#endif - -void HandleCrashDump(const BreakpadInfo& info) { - int dumpfd; - bool keep_fd = false; - size_t dump_size; - uint8_t* dump_data; - google_breakpad::PageAllocator allocator; - const char* exe_buf = NULL; - -#if defined(OS_CHROMEOS) - // Grab the crashing process' name now, when it should still be available. - // If we try to do this later in our grandchild the crashing process has - // already terminated. - exe_buf = GetCrashingProcessName(info, &allocator); -#endif - - if (info.fd != -1) { - // Dump is provided with an open FD. - keep_fd = true; - dumpfd = info.fd; - - // The FD is pointing to the end of the file. - // Rewind, we'll read the data next. - if (lseek(dumpfd, 0, SEEK_SET) == -1) { - static const char msg[] = "Cannot upload crash dump: failed to " - "reposition minidump FD\n"; - WriteLog(msg, sizeof(msg) - 1); - IGNORE_RET(sys_close(dumpfd)); - return; - } - LoadDataFromFD(allocator, info.fd, false, &dump_data, &dump_size); - } else { - // Dump is provided with a path. - keep_fd = false; - LoadDataFromFile(allocator, info.filename, &dumpfd, &dump_data, &dump_size); - } - - // TODO(jcivelli): make log work when using FDs. -#if defined(ADDRESS_SANITIZER) - int logfd; - size_t log_size; - uint8_t* log_data; - // Load the AddressSanitizer log into log_data. - LoadDataFromFile(allocator, info.log_filename, &logfd, &log_data, &log_size); -#endif - - // We need to build a MIME block for uploading to the server. Since we are - // going to fork and run wget, it needs to be written to a temp file. - const int ufd = sys_open("/dev/urandom", O_RDONLY, 0); - if (ufd < 0) { - static const char msg[] = "Cannot upload crash dump because /dev/urandom" - " is missing\n"; - WriteLog(msg, sizeof(msg) - 1); - return; - } - - static const char temp_file_template[] = - "/tmp/chromium-upload-XXXXXXXXXXXXXXXX"; - char temp_file[sizeof(temp_file_template)]; - int temp_file_fd = -1; - if (keep_fd) { - temp_file_fd = dumpfd; - // Rewind the destination, we are going to overwrite it. - if (lseek(dumpfd, 0, SEEK_SET) == -1) { - static const char msg[] = "Cannot upload crash dump: failed to " - "reposition minidump FD (2)\n"; - WriteLog(msg, sizeof(msg) - 1); - IGNORE_RET(sys_close(dumpfd)); - return; - } - } else { - if (info.upload) { - memcpy(temp_file, temp_file_template, sizeof(temp_file_template)); - - for (unsigned i = 0; i < 10; ++i) { - uint64_t t; - sys_read(ufd, &t, sizeof(t)); - write_uint64_hex(temp_file + sizeof(temp_file) - (16 + 1), t); - - temp_file_fd = sys_open(temp_file, O_WRONLY | O_CREAT | O_EXCL, 0600); - if (temp_file_fd >= 0) - break; - } - - if (temp_file_fd < 0) { - static const char msg[] = "Failed to create temporary file in /tmp: " - "cannot upload crash dump\n"; - WriteLog(msg, sizeof(msg) - 1); - IGNORE_RET(sys_close(ufd)); - return; - } - } else { - temp_file_fd = sys_open(info.filename, O_WRONLY, 0600); - if (temp_file_fd < 0) { - static const char msg[] = "Failed to save crash dump: failed to open\n"; - WriteLog(msg, sizeof(msg) - 1); - IGNORE_RET(sys_close(ufd)); - return; - } - } - } - - // The MIME boundary is 28 hyphens, followed by a 64-bit nonce and a NUL. - char mime_boundary[28 + 16 + 1]; - my_memset(mime_boundary, '-', 28); - uint64_t boundary_rand; - sys_read(ufd, &boundary_rand, sizeof(boundary_rand)); - write_uint64_hex(mime_boundary + 28, boundary_rand); - mime_boundary[28 + 16] = 0; - IGNORE_RET(sys_close(ufd)); - - // The MIME block looks like this: - // BOUNDARY \r\n - // Content-Disposition: form-data; name="prod" \r\n \r\n - // Chrome_Linux \r\n - // BOUNDARY \r\n - // Content-Disposition: form-data; name="ver" \r\n \r\n - // 1.2.3.4 \r\n - // BOUNDARY \r\n - // - // zero or one: - // Content-Disposition: form-data; name="ptime" \r\n \r\n - // abcdef \r\n - // BOUNDARY \r\n - // - // zero or one: - // Content-Disposition: form-data; name="ptype" \r\n \r\n - // abcdef \r\n - // BOUNDARY \r\n - // - // zero or one: - // Content-Disposition: form-data; name="lsb-release" \r\n \r\n - // abcdef \r\n - // BOUNDARY \r\n - // - // zero or one: - // Content-Disposition: form-data; name="oom-size" \r\n \r\n - // 1234567890 \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-Type: application/octet-stream \r\n \r\n - // <dump contents> - // \r\n BOUNDARY -- \r\n - -#if defined(OS_CHROMEOS) - CrashReporterWriter writer(temp_file_fd); -#else - MimeWriter writer(temp_file_fd, mime_boundary); -#endif - { - // TODO(thestig) Do not use this inside a compromised context. - std::string product_name; - std::string version; - - GetBreakpadClient()->GetProductNameAndVersion(&product_name, &version); - - writer.AddBoundary(); - writer.AddPairString("prod", product_name.c_str()); - writer.AddBoundary(); - writer.AddPairString("ver", version.c_str()); - writer.AddBoundary(); - if (info.pid > 0) { - char pid_value_buf[kUint64StringSize]; - uint64_t pid_value_len = my_uint64_len(info.pid); - my_uint64tos(pid_value_buf, info.pid, pid_value_len); - static const char pid_key_name[] = "pid"; - writer.AddPairData(pid_key_name, sizeof(pid_key_name) - 1, - pid_value_buf, pid_value_len); - writer.AddBoundary(); - } -#if defined(OS_ANDROID) - // Addtional MIME blocks are added for logging on Android devices. - static const char android_build_id[] = "android_build_id"; - static const char android_build_fp[] = "android_build_fp"; - static const char device[] = "device"; - static const char model[] = "model"; - static const char brand[] = "brand"; - static const char exception_info[] = "exception_info"; - - base::android::BuildInfo* android_build_info = - base::android::BuildInfo::GetInstance(); - writer.AddPairString( - android_build_id, android_build_info->android_build_id()); - writer.AddBoundary(); - writer.AddPairString( - android_build_fp, android_build_info->android_build_fp()); - writer.AddBoundary(); - writer.AddPairString(device, android_build_info->device()); - writer.AddBoundary(); - writer.AddPairString(model, android_build_info->model()); - writer.AddBoundary(); - writer.AddPairString(brand, android_build_info->brand()); - writer.AddBoundary(); - if (android_build_info->java_exception_info() != NULL) { - writer.AddPairString(exception_info, - android_build_info->java_exception_info()); - writer.AddBoundary(); - } -#endif - writer.Flush(); - } - - if (info.process_start_time > 0) { - struct kernel_timeval tv; - if (!sys_gettimeofday(&tv, NULL)) { - uint64_t time = kernel_timeval_to_ms(&tv); - if (time > info.process_start_time) { - time -= info.process_start_time; - char time_str[kUint64StringSize]; - const unsigned time_len = my_uint64_len(time); - my_uint64tos(time_str, time, time_len); - - static const char process_time_msg[] = "ptime"; - writer.AddPairData(process_time_msg, sizeof(process_time_msg) - 1, - time_str, time_len); - writer.AddBoundary(); - writer.Flush(); - } - } - } - - if (info.process_type_length) { - writer.AddPairString("ptype", info.process_type); - writer.AddBoundary(); - writer.Flush(); - } - - if (info.distro_length) { - static const char distro_msg[] = "lsb-release"; - writer.AddPairString(distro_msg, info.distro); - writer.AddBoundary(); - writer.Flush(); - } - - if (info.oom_size) { - char oom_size_str[kUint64StringSize]; - const unsigned oom_size_len = my_uint64_len(info.oom_size); - my_uint64tos(oom_size_str, info.oom_size, oom_size_len); - static const char oom_size_msg[] = "oom-size"; - writer.AddPairData(oom_size_msg, sizeof(oom_size_msg) - 1, - oom_size_str, oom_size_len); - writer.AddBoundary(); - 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); -#if defined(ADDRESS_SANITIZER) - // Append a multipart boundary and the contents of the AddressSanitizer log. - writer.AddBoundary(); - writer.AddFileContents(g_log_msg, log_data, log_size); -#endif - writer.AddEnd(); - writer.Flush(); - - IGNORE_RET(sys_close(temp_file_fd)); - -#if defined(OS_ANDROID) - if (info.filename) { - int filename_length = my_strlen(info.filename); - - // If this was a file, we need to copy it to the right place and use the - // right file name so it gets uploaded by the browser. - const char msg[] = "Output crash dump file:"; - WriteLog(msg, sizeof(msg) - 1); - WriteLog(info.filename, filename_length - 1); - - char pid_buf[kUint64StringSize]; - uint64_t pid_str_length = my_uint64_len(info.pid); - my_uint64tos(pid_buf, info.pid, pid_str_length); - - // -1 because we won't need the null terminator on the original filename. - unsigned done_filename_len = filename_length - 1 + pid_str_length; - char* done_filename = reinterpret_cast<char*>( - allocator.Alloc(done_filename_len)); - // Rename the file such that the pid is the suffix in order signal to other - // processes that the minidump is complete. The advantage of using the pid - // as the suffix is that it is trivial to associate the minidump with the - // crashed process. - // Finally, note strncpy prevents null terminators from - // being copied. Pad the rest with 0's. - my_strncpy(done_filename, info.filename, done_filename_len); - // Append the suffix a null terminator should be added. - my_strncat(done_filename, pid_buf, pid_str_length); - // Rename the minidump file to signal that it is complete. - if (rename(info.filename, done_filename)) { - const char failed_msg[] = "Failed to rename:"; - WriteLog(failed_msg, sizeof(failed_msg) - 1); - WriteLog(info.filename, filename_length - 1); - const char to_msg[] = "to"; - WriteLog(to_msg, sizeof(to_msg) - 1); - WriteLog(done_filename, done_filename_len - 1); - } - } -#endif - - if (!info.upload) - return; - - const pid_t child = sys_fork(); - if (!child) { - // Spawned helper process. - // - // This code is called both when a browser is crashing (in which case, - // nothing really matters any more) and when a renderer/plugin crashes, in - // which case we need to continue. - // - // Since we are a multithreaded app, if we were just to fork(), we might - // grab file descriptors which have just been created in another thread and - // hold them open for too long. - // - // Thus, we have to loop and try and close everything. - const int fd = sys_open("/proc/self/fd", O_DIRECTORY | O_RDONLY, 0); - if (fd < 0) { - for (unsigned i = 3; i < 8192; ++i) - IGNORE_RET(sys_close(i)); - } else { - google_breakpad::DirectoryReader reader(fd); - const char* name; - while (reader.GetNextEntry(&name)) { - int i; - if (my_strtoui(&i, name) && i > 2 && i != fd) - IGNORE_RET(sys_close(i)); - reader.PopEntry(); - } - - IGNORE_RET(sys_close(fd)); - } - - IGNORE_RET(sys_setsid()); - - // Leave one end of a pipe in the upload process and watch for it getting - // closed by the upload process exiting. - int fds[2]; - if (sys_pipe(fds) >= 0) { - const pid_t upload_child = sys_fork(); - if (!upload_child) { - // Upload process. - IGNORE_RET(sys_close(fds[0])); - IGNORE_RET(sys_dup2(fds[1], 3)); - ExecUploadProcessOrTerminate(info, temp_file, mime_boundary, exe_buf, - &allocator); - } - - // Helper process. - if (upload_child > 0) { - IGNORE_RET(sys_close(fds[1])); - - const size_t kCrashIdLength = 16; - char id_buf[kCrashIdLength + 1]; - size_t bytes_read = - WaitForCrashReportUploadProcess(fds[0], kCrashIdLength, id_buf); - HandleCrashReportId(id_buf, bytes_read, kCrashIdLength); - - if (sys_waitpid(upload_child, NULL, WNOHANG) == 0) { - // Upload process is still around, kill it. - sys_kill(upload_child, SIGKILL); - } - } - } - - // Helper process. - IGNORE_RET(sys_unlink(info.filename)); -#if defined(ADDRESS_SANITIZER) - IGNORE_RET(sys_unlink(info.log_filename)); -#endif - IGNORE_RET(sys_unlink(temp_file)); - sys__exit(0); - } - - // Main browser process. - if (child <= 0) - return; - (void) HANDLE_EINTR(sys_waitpid(child, NULL, 0)); -} - -void InitCrashReporter(const std::string& process_type) { -#if defined(OS_ANDROID) - // This will guarantee that the BuildInfo has been initialized and subsequent - // calls will not require memory allocation. - base::android::BuildInfo::GetInstance(); -#endif - // Determine the process type and take appropriate action. - const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); - if (parsed_command_line.HasSwitch(switches::kDisableBreakpad)) - return; - - if (process_type.empty()) { - bool enable_breakpad = GetBreakpadClient()->GetCollectStatsConsent() || - GetBreakpadClient()->IsRunningUnattended(); - enable_breakpad &= - !parsed_command_line.HasSwitch(switches::kDisableBreakpad); - if (!enable_breakpad) { - enable_breakpad = parsed_command_line.HasSwitch( - switches::kEnableCrashReporterForTesting); - } - if (!enable_breakpad) { - VLOG(1) << "Breakpad disabled"; - return; - } - - InitCrashKeys(); - EnableCrashDumping(GetBreakpadClient()->IsRunningUnattended()); - } else if (GetBreakpadClient()->EnableBreakpadForProcess(process_type)) { -#if defined(OS_ANDROID) - NOTREACHED() << "Breakpad initialized with InitCrashReporter() instead of " - "InitNonBrowserCrashReporter in " << process_type << " process."; - return; -#else - // We might be chrooted in a zygote or renderer process so we cannot call - // GetCollectStatsConsent because that needs access the the user's home - // dir. Instead, we set a command line flag for these processes. - // Even though plugins are not chrooted, we share the same code path for - // simplicity. - if (!parsed_command_line.HasSwitch(switches::kEnableCrashReporter)) - return; - InitCrashKeys(); - SetClientIdFromCommandLine(parsed_command_line); - EnableNonBrowserCrashDumping(); - VLOG(1) << "Non Browser crash dumping enabled for: " << process_type; -#endif // #if defined(OS_ANDROID) - } - - PostEnableBreakpadInitialization(); -} - -#if defined(OS_ANDROID) -void InitNonBrowserCrashReporterForAndroid(const std::string& process_type) { - const CommandLine* command_line = CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kEnableCrashReporter)) { - // On Android we need to provide a FD to the file where the minidump is - // generated as the renderer and browser run with different UIDs - // (preventing the browser from inspecting the renderer process). - int minidump_fd = base::GlobalDescriptors::GetInstance()->MaybeGet( - GetBreakpadClient()->GetAndroidMinidumpDescriptor()); - if (minidump_fd < 0) { - NOTREACHED() << "Could not find minidump FD, crash reporting disabled."; - } else { - EnableNonBrowserCrashDumping(process_type, minidump_fd); - } - } -} -#endif // OS_ANDROID - -bool IsCrashReporterEnabled() { - return g_is_crash_reporter_enabled; -} - -} // namespace breakpad diff --git a/components/breakpad/app/breakpad_linux.h b/components/breakpad/app/breakpad_linux.h deleted file mode 100644 index b507c92..0000000 --- a/components/breakpad/app/breakpad_linux.h +++ /dev/null @@ -1,32 +0,0 @@ -// 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. - -// Public interface for enabling Breakpad on Linux systems. - -#ifndef COMPONENTS_BREAKPAD_APP_BREAKPAD_LINUX_H_ -#define COMPONENTS_BREAKPAD_APP_BREAKPAD_LINUX_H_ - -#include <string> - -#include "build/build_config.h" - -namespace breakpad { - -// Turns on the crash reporter in any process. -extern void InitCrashReporter(const std::string& process_type); - -// Enables the crash reporter in child processes. -#if defined(OS_ANDROID) -extern void InitNonBrowserCrashReporterForAndroid( - const std::string& process_type); -#endif - -// Checks if crash reporting is enabled. Note that this is not the same as -// being opted into metrics reporting (and crash reporting), which controls -// whether InitCrashReporter() is called. -bool IsCrashReporterEnabled(); - -} // namespace breakpad - -#endif // COMPONENTS_BREAKPAD_APP_BREAKPAD_LINUX_H_ diff --git a/components/breakpad/app/breakpad_linux_impl.h b/components/breakpad/app/breakpad_linux_impl.h deleted file mode 100644 index f662236..0000000 --- a/components/breakpad/app/breakpad_linux_impl.h +++ /dev/null @@ -1,65 +0,0 @@ -// 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 COMPONENTS_BREAKPAD_APP_BREAKPAD_LINUX_IMPL_H_ -#define COMPONENTS_BREAKPAD_APP_BREAKPAD_LINUX_IMPL_H_ - -#include <sys/types.h> - -#include "base/basictypes.h" -#include "breakpad/src/common/simple_string_dictionary.h" -#include "components/breakpad/app/breakpad_linux.h" - -namespace breakpad { - -typedef google_breakpad::NonAllocatingMap<256, 256, 64> CrashKeyStorage; - -#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 = 6; -#else -// Additional field to pass the AddressSanitizer log to the crash handler. -const size_t kCrashIovSize = 7; -#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* 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); - -} // namespace breakpad - -#endif // COMPONENTS_BREAKPAD_APP_BREAKPAD_LINUX_IMPL_H_ diff --git a/components/breakpad/app/breakpad_mac.h b/components/breakpad/app/breakpad_mac.h deleted file mode 100644 index 1db6d75..0000000 --- a/components/breakpad/app/breakpad_mac.h +++ /dev/null @@ -1,27 +0,0 @@ -// 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. - -#ifndef COMPONENTS_BREAKPAD_APP_BREAKPAD_MAC_H_ -#define COMPONENTS_BREAKPAD_APP_BREAKPAD_MAC_H_ - -#include <string> - -// This header defines the entry points for Breakpad integration. - -namespace breakpad { - -// Initializes Breakpad. -void InitCrashReporter(const std::string& process_type); - -// Give Breakpad a chance to store information about the current process. -// Extra information requires a parsed command line, so call this after -// CommandLine::Init has been called. -void InitCrashProcessInfo(const std::string& process_type_switch); - -// Is Breakpad enabled? -bool IsCrashReporterEnabled(); - -} // namespace breakpad - -#endif // COMPONENTS_BREAKPAD_APP_BREAKPAD_MAC_H_ diff --git a/components/breakpad/app/breakpad_mac.mm b/components/breakpad/app/breakpad_mac.mm deleted file mode 100644 index 6cb5504..0000000 --- a/components/breakpad/app/breakpad_mac.mm +++ /dev/null @@ -1,279 +0,0 @@ -// 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. - -#import "components/breakpad/app/breakpad_mac.h" - -#include <CoreFoundation/CoreFoundation.h> -#import <Foundation/Foundation.h> - -#include "base/auto_reset.h" -#include "base/base_switches.h" -#import "base/basictypes.h" -#include "base/command_line.h" -#include "base/debug/crash_logging.h" -#include "base/debug/dump_without_crashing.h" -#include "base/file_util.h" -#include "base/files/file_path.h" -#import "base/logging.h" -#include "base/mac/bundle_locations.h" -#include "base/mac/mac_util.h" -#include "base/mac/scoped_cftyperef.h" -#import "base/mac/scoped_nsautorelease_pool.h" -#include "base/strings/sys_string_conversions.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread_restrictions.h" -#import "breakpad/src/client/mac/Framework/Breakpad.h" -#include "components/breakpad/app/breakpad_client.h" - -namespace breakpad { - -namespace { - -BreakpadRef gBreakpadRef = NULL; - -void SetCrashKeyValue(NSString* key, NSString* value) { - // Comment repeated from header to prevent confusion: - // IMPORTANT: On OS X, the key/value pairs are sent to the crash server - // out of bounds and not recorded on disk in the minidump, this means - // that if you look at the minidump file locally you won't see them! - if (gBreakpadRef == NULL) { - return; - } - - BreakpadAddUploadParameter(gBreakpadRef, key, value); -} - -void ClearCrashKeyValue(NSString* key) { - if (gBreakpadRef == NULL) { - return; - } - - BreakpadRemoveUploadParameter(gBreakpadRef, key); -} - -void SetCrashKeyValueImpl(const base::StringPiece& key, - const base::StringPiece& value) { - SetCrashKeyValue(base::SysUTF8ToNSString(key.as_string()), - base::SysUTF8ToNSString(value.as_string())); -} - -void ClearCrashKeyValueImpl(const base::StringPiece& key) { - ClearCrashKeyValue(base::SysUTF8ToNSString(key.as_string())); -} - -bool FatalMessageHandler(int severity, const char* file, int line, - size_t message_start, const std::string& str) { - // Do not handle non-FATAL. - if (severity != logging::LOG_FATAL) - return false; - - // In case of OOM condition, this code could be reentered when - // constructing and storing the key. Using a static is not - // thread-safe, but if multiple threads are in the process of a - // fatal crash at the same time, this should work. - static bool guarded = false; - if (guarded) - return false; - - base::AutoReset<bool> guard(&guarded, true); - - // Only log last path component. This matches logging.cc. - if (file) { - const char* slash = strrchr(file, '/'); - if (slash) - file = slash + 1; - } - - NSString* fatal_key = @"LOG_FATAL"; - NSString* fatal_value = - [NSString stringWithFormat:@"%s:%d: %s", - file, line, str.c_str() + message_start]; - SetCrashKeyValue(fatal_key, fatal_value); - - // Rather than including the code to force the crash here, allow the - // caller to do it. - return false; -} - -// BreakpadGenerateAndSendReport() does not report the current -// thread. This class can be used to spin up a thread to run it. -class DumpHelper : public base::PlatformThread::Delegate { - public: - static void DumpWithoutCrashing() { - DumpHelper dumper; - base::PlatformThreadHandle handle; - if (base::PlatformThread::Create(0, &dumper, &handle)) { - // The entire point of this is to block so that the correct - // stack is logged. - base::ThreadRestrictions::ScopedAllowIO allow_io; - base::PlatformThread::Join(handle); - } - } - - private: - DumpHelper() {} - - virtual void ThreadMain() OVERRIDE { - base::PlatformThread::SetName("CrDumpHelper"); - BreakpadGenerateAndSendReport(gBreakpadRef); - } - - DISALLOW_COPY_AND_ASSIGN(DumpHelper); -}; - -void SIGABRTHandler(int signal) { - // The OSX abort() (link below) masks all signals for the process, - // and all except SIGABRT for the thread. SIGABRT will be masked - // when the SIGABRT is sent, which means at this point only SIGKILL - // and SIGSTOP can be delivered. Unmask others so that the code - // below crashes as desired. - // - // http://www.opensource.apple.com/source/Libc/Libc-825.26/stdlib/FreeBSD/abort.c - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, signal); - pthread_sigmask(SIG_SETMASK, &mask, NULL); - - // Most interesting operations are not safe in a signal handler, just crash. - char* volatile death_ptr = NULL; - *death_ptr = '!'; -} - -} // namespace - -bool IsCrashReporterEnabled() { - return gBreakpadRef != NULL; -} - -// Only called for a branded build of Chrome.app. -void InitCrashReporter(const std::string& process_type) { - DCHECK(!gBreakpadRef); - base::mac::ScopedNSAutoreleasePool autorelease_pool; - - // Check whether crash reporting should be enabled. If enterprise - // configuration management controls crash reporting, it takes precedence. - // Otherwise, check whether the user has consented to stats and crash - // reporting. The browser process can make this determination directly. - // Helper processes may not have access to the disk or to the same data as - // the browser process, so the browser passes the decision to them on the - // command line. - NSBundle* main_bundle = base::mac::FrameworkBundle(); - bool is_browser = !base::mac::IsBackgroundOnlyProcess(); - bool enable_breakpad = false; - CommandLine* command_line = CommandLine::ForCurrentProcess(); - - if (is_browser) { - // Since the configuration management infrastructure is possibly not - // initialized when this code runs, read the policy preference directly. - if (!GetBreakpadClient()->ReportingIsEnforcedByPolicy(&enable_breakpad)) { - // Controlled by the user. The crash reporter may be enabled by - // preference or through an environment variable, but the kDisableBreakpad - // switch overrides both. - enable_breakpad = GetBreakpadClient()->GetCollectStatsConsent() || - GetBreakpadClient()->IsRunningUnattended(); - enable_breakpad &= !command_line->HasSwitch(switches::kDisableBreakpad); - } - } else { - // This is a helper process, check the command line switch. - enable_breakpad = command_line->HasSwitch(switches::kEnableCrashReporter); - } - - if (!enable_breakpad) { - VLOG_IF(1, is_browser) << "Breakpad disabled"; - return; - } - - // Tell Breakpad where crash_inspector and crash_report_sender are. - NSString* resource_path = [main_bundle resourcePath]; - NSString *inspector_location = - [resource_path stringByAppendingPathComponent:@"crash_inspector"]; - NSString *reporter_bundle_location = - [resource_path stringByAppendingPathComponent:@"crash_report_sender.app"]; - NSString *reporter_location = - [[NSBundle bundleWithPath:reporter_bundle_location] executablePath]; - - if (!inspector_location || !reporter_location) { - VLOG_IF(1, is_browser && base::mac::AmIBundled()) << "Breakpad disabled"; - return; - } - - NSDictionary* info_dictionary = [main_bundle infoDictionary]; - NSMutableDictionary *breakpad_config = - [[info_dictionary mutableCopy] autorelease]; - [breakpad_config setObject:inspector_location - forKey:@BREAKPAD_INSPECTOR_LOCATION]; - [breakpad_config setObject:reporter_location - forKey:@BREAKPAD_REPORTER_EXE_LOCATION]; - - // In the main application (the browser process), crashes can be passed to - // the system's Crash Reporter. This allows the system to notify the user - // when the application crashes, and provide the user with the option to - // restart it. - if (is_browser) - [breakpad_config setObject:@"NO" forKey:@BREAKPAD_SEND_AND_EXIT]; - - base::FilePath dir_crash_dumps; - GetBreakpadClient()->GetCrashDumpLocation(&dir_crash_dumps); - [breakpad_config setObject:base::SysUTF8ToNSString(dir_crash_dumps.value()) - forKey:@BREAKPAD_DUMP_DIRECTORY]; - - // Initialize Breakpad. - gBreakpadRef = BreakpadCreate(breakpad_config); - if (!gBreakpadRef) { - LOG_IF(ERROR, base::mac::AmIBundled()) << "Breakpad initializaiton failed"; - return; - } - - // Initialize the scoped crash key system. - base::debug::SetCrashKeyReportingFunctions(&SetCrashKeyValueImpl, - &ClearCrashKeyValueImpl); - GetBreakpadClient()->RegisterCrashKeys(); - - // Set Breakpad metadata values. These values are added to Info.plist during - // the branded Google Chrome.app build. - SetCrashKeyValue(@"ver", [info_dictionary objectForKey:@BREAKPAD_VERSION]); - SetCrashKeyValue(@"prod", [info_dictionary objectForKey:@BREAKPAD_PRODUCT]); - SetCrashKeyValue(@"plat", @"OS X"); - - if (!is_browser) { - // Get the guid from the command line switch. - std::string client_guid = - command_line->GetSwitchValueASCII(switches::kEnableCrashReporter); - GetBreakpadClient()->SetBreakpadClientIdFromGUID(client_guid); - } - - logging::SetLogMessageHandler(&FatalMessageHandler); - base::debug::SetDumpWithoutCrashingFunction(&DumpHelper::DumpWithoutCrashing); - - // abort() sends SIGABRT, which breakpad does not intercept. - // Register a signal handler to crash in a way breakpad will - // intercept. - struct sigaction sigact; - memset(&sigact, 0, sizeof(sigact)); - sigact.sa_handler = SIGABRTHandler; - CHECK(0 == sigaction(SIGABRT, &sigact, NULL)); -} - -void InitCrashProcessInfo(const std::string& process_type_switch) { - if (gBreakpadRef == NULL) { - return; - } - - // Determine the process type. - NSString* process_type = @"browser"; - if (!process_type_switch.empty()) { - process_type = base::SysUTF8ToNSString(process_type_switch); - } - - GetBreakpadClient()->InstallAdditionalFilters(gBreakpadRef); - - // Store process type in crash dump. - SetCrashKeyValue(@"ptype", process_type); - - NSString* pid_value = - [NSString stringWithFormat:@"%d", static_cast<unsigned int>(getpid())]; - SetCrashKeyValue(@"pid", pid_value); -} - -} // namespace breakpad diff --git a/components/breakpad/app/breakpad_mac_stubs.mm b/components/breakpad/app/breakpad_mac_stubs.mm deleted file mode 100644 index a05e150..0000000 --- a/components/breakpad/app/breakpad_mac_stubs.mm +++ /dev/null @@ -1,24 +0,0 @@ -// 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. - -#import "components/breakpad/app/breakpad_mac.h" - -#import <Foundation/Foundation.h> - -// Stubbed out versions of breakpad integration functions so we can compile -// without linking in Breakpad. - -namespace breakpad { - -bool IsCrashReporterEnabled() { - return false; -} - -void InitCrashProcessInfo(const std::string& process_type_switch) { -} - -void InitCrashReporter(const std::string& process_type) { -} - -} // namespace breakpad diff --git a/components/breakpad/app/breakpad_win.cc b/components/breakpad/app/breakpad_win.cc deleted file mode 100644 index 5fdf9c2..0000000 --- a/components/breakpad/app/breakpad_win.cc +++ /dev/null @@ -1,609 +0,0 @@ -// 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. - -#include "components/breakpad/app/breakpad_win.h" - -#include <windows.h> -#include <shellapi.h> -#include <tchar.h> -#include <userenv.h> -#include <winnt.h> - -#include <algorithm> -#include <map> -#include <vector> - -#include "base/base_switches.h" -#include "base/basictypes.h" -#include "base/command_line.h" -#include "base/debug/crash_logging.h" -#include "base/debug/dump_without_crashing.h" -#include "base/environment.h" -#include "base/memory/scoped_ptr.h" -#include "base/strings/string16.h" -#include "base/strings/string_split.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "base/synchronization/lock.h" -#include "base/win/metro.h" -#include "base/win/pe_image.h" -#include "base/win/registry.h" -#include "base/win/win_util.h" -#include "breakpad/src/client/windows/handler/exception_handler.h" -#include "components/breakpad/app/breakpad_client.h" -#include "components/breakpad/app/crash_keys_win.h" -#include "components/breakpad/app/hard_error_handler_win.h" -#include "content/public/common/result_codes.h" -#include "sandbox/win/src/nt_internals.h" -#include "sandbox/win/src/sidestep/preamble_patcher.h" - -// userenv.dll is required for GetProfileType(). -#pragma comment(lib, "userenv.lib") - -#pragma intrinsic(_AddressOfReturnAddress) -#pragma intrinsic(_ReturnAddress) - -namespace breakpad { - -namespace { - -// Minidump with stacks, PEB, TEB, and unloaded module list. -const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>( - MiniDumpWithProcessThreadData | // Get PEB and TEB. - MiniDumpWithUnloadedModules); // Get unloaded modules when available. - -// Minidump with all of the above, plus memory referenced from stack. -const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>( - MiniDumpWithProcessThreadData | // Get PEB and TEB. - MiniDumpWithUnloadedModules | // Get unloaded modules when available. - MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack. - -// Large dump with all process memory. -const MINIDUMP_TYPE kFullDumpType = static_cast<MINIDUMP_TYPE>( - MiniDumpWithFullMemory | // Full memory from process. - MiniDumpWithProcessThreadData | // Get PEB and TEB. - MiniDumpWithHandleData | // Get all handle information. - MiniDumpWithUnloadedModules); // Get unloaded modules when available. - -const char kPipeNameVar[] = "CHROME_BREAKPAD_PIPE_NAME"; - -const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\"; -const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices"; - -// This is the well known SID for the system principal. -const wchar_t kSystemPrincipalSid[] =L"S-1-5-18"; - -google_breakpad::ExceptionHandler* g_breakpad = NULL; -google_breakpad::ExceptionHandler* g_dumphandler_no_crash = NULL; - -EXCEPTION_POINTERS g_surrogate_exception_pointers = {0}; -EXCEPTION_RECORD g_surrogate_exception_record = {0}; -CONTEXT g_surrogate_context = {0}; - -typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle, - NTSTATUS ExitStatus); -char* g_real_terminate_process_stub = NULL; - -} // namespace - -// Dumps the current process memory. -extern "C" void __declspec(dllexport) __cdecl DumpProcess() { - if (g_breakpad) { - g_breakpad->WriteMinidump(); - } -} - -// Used for dumping a process state when there is no crash. -extern "C" void __declspec(dllexport) __cdecl DumpProcessWithoutCrash() { - if (g_dumphandler_no_crash) { - g_dumphandler_no_crash->WriteMinidump(); - } -} - -namespace { - -// We need to prevent ICF from folding DumpForHangDebuggingThread() and -// DumpProcessWithoutCrashThread() together, since that makes them -// indistinguishable in crash dumps. We do this by making the function -// bodies unique, and prevent optimization from shuffling things around. -MSVC_DISABLE_OPTIMIZE() -MSVC_PUSH_DISABLE_WARNING(4748) - -DWORD WINAPI DumpProcessWithoutCrashThread(void*) { - DumpProcessWithoutCrash(); - return 0; -} - -// The following two functions do exactly the same thing as the two above. But -// we want the signatures to be different so that we can easily track them in -// crash reports. -// TODO(yzshen): Remove when enough information is collected and the hang rate -// of pepper/renderer processes is reduced. -DWORD WINAPI DumpForHangDebuggingThread(void*) { - DumpProcessWithoutCrash(); - VLOG(1) << "dumped for hang debugging"; - return 0; -} - -MSVC_POP_WARNING() -MSVC_ENABLE_OPTIMIZE() - -} // namespace - -// Injects a thread into a remote process to dump state when there is no crash. -extern "C" HANDLE __declspec(dllexport) __cdecl -InjectDumpProcessWithoutCrash(HANDLE process) { - return CreateRemoteThread(process, NULL, 0, DumpProcessWithoutCrashThread, - 0, 0, NULL); -} - -extern "C" HANDLE __declspec(dllexport) __cdecl -InjectDumpForHangDebugging(HANDLE process) { - return CreateRemoteThread(process, NULL, 0, DumpForHangDebuggingThread, - 0, 0, NULL); -} - -// Returns a string containing a list of all modifiers for the loaded profile. -std::wstring GetProfileType() { - std::wstring profile_type; - DWORD profile_bits = 0; - if (::GetProfileType(&profile_bits)) { - static const struct { - DWORD bit; - const wchar_t* name; - } kBitNames[] = { - { PT_MANDATORY, L"mandatory" }, - { PT_ROAMING, L"roaming" }, - { PT_TEMPORARY, L"temporary" }, - }; - for (size_t i = 0; i < arraysize(kBitNames); ++i) { - const DWORD this_bit = kBitNames[i].bit; - if ((profile_bits & this_bit) != 0) { - profile_type.append(kBitNames[i].name); - profile_bits &= ~this_bit; - if (profile_bits != 0) - profile_type.append(L", "); - } - } - } else { - DWORD last_error = ::GetLastError(); - base::SStringPrintf(&profile_type, L"error %u", last_error); - } - return profile_type; -} - -namespace { - -// This callback is used when we want to get a dump without crashing the -// process. -bool DumpDoneCallbackWhenNoCrash(const wchar_t*, const wchar_t*, void*, - EXCEPTION_POINTERS* ex_info, - MDRawAssertionInfo*, bool) { - return true; -} - -// This callback is executed when the browser process has crashed, after -// the crash dump has been created. We need to minimize the amount of work -// done here since we have potentially corrupted process. Our job is to -// spawn another instance of chrome which will show a 'chrome has crashed' -// dialog. This code needs to live in the exe and thus has no access to -// facilities such as the i18n helpers. -bool DumpDoneCallback(const wchar_t*, const wchar_t*, void*, - EXCEPTION_POINTERS* ex_info, - MDRawAssertionInfo*, bool) { - // Check if the exception is one of the kind which would not be solved - // by simply restarting chrome. In this case we show a message box with - // and exit silently. Remember that chrome is in a crashed state so we - // can't show our own UI from this process. - if (HardErrorHandler(ex_info)) - return true; - - if (!GetBreakpadClient()->AboutToRestart()) - return true; - - // Now we just start chrome browser with the same command line. - STARTUPINFOW si = {sizeof(si)}; - PROCESS_INFORMATION pi; - if (::CreateProcessW(NULL, ::GetCommandLineW(), NULL, NULL, FALSE, - CREATE_UNICODE_ENVIRONMENT, NULL, NULL, &si, &pi)) { - ::CloseHandle(pi.hProcess); - ::CloseHandle(pi.hThread); - } - // After this return we will be terminated. The actual return value is - // not used at all. - return true; -} - -// flag to indicate that we are already handling an exception. -volatile LONG handling_exception = 0; - -// This callback is used when there is no crash. Note: Unlike the -// |FilterCallback| below this does not do dupe detection. It is upto the caller -// to implement it. -bool FilterCallbackWhenNoCrash( - void*, EXCEPTION_POINTERS*, MDRawAssertionInfo*) { - GetBreakpadClient()->RecordCrashDumpAttempt(false); - return true; -} - -// This callback is executed when the Chrome process has crashed and *before* -// the crash dump is created. To prevent duplicate crash reports we -// make every thread calling this method, except the very first one, -// go to sleep. -bool FilterCallback(void*, EXCEPTION_POINTERS*, MDRawAssertionInfo*) { - // Capture every thread except the first one in the sleep. We don't - // want multiple threads to concurrently report exceptions. - if (::InterlockedCompareExchange(&handling_exception, 1, 0) == 1) { - ::Sleep(INFINITE); - } - GetBreakpadClient()->RecordCrashDumpAttempt(true); - return true; -} - -// Previous unhandled filter. Will be called if not null when we -// intercept a crash. -LPTOP_LEVEL_EXCEPTION_FILTER previous_filter = NULL; - -// Exception filter used when breakpad is not enabled. We just display -// the "Do you want to restart" message and then we call the previous filter. -long WINAPI ChromeExceptionFilter(EXCEPTION_POINTERS* info) { - DumpDoneCallback(NULL, NULL, NULL, info, NULL, false); - - if (previous_filter) - return previous_filter(info); - - return EXCEPTION_EXECUTE_HANDLER; -} - -// Exception filter for the service process used when breakpad is not enabled. -// We just display the "Do you want to restart" message and then die -// (without calling the previous filter). -long WINAPI ServiceExceptionFilter(EXCEPTION_POINTERS* info) { - DumpDoneCallback(NULL, NULL, NULL, info, NULL, false); - return EXCEPTION_EXECUTE_HANDLER; -} - -} // namespace - -// NOTE: This function is used by SyzyASAN to annotate crash reports. If you -// change the name or signature of this function you will break SyzyASAN -// instrumented releases of Chrome. Please contact syzygy-team@chromium.org -// before doing so! -extern "C" void __declspec(dllexport) __cdecl SetCrashKeyValueImpl( - const wchar_t* key, const wchar_t* value) { - CrashKeysWin* keeper = CrashKeysWin::keeper(); - if (!keeper) - return; - - // TODO(siggi): This doesn't look quite right - there's NULL deref potential - // here, and an implicit std::wstring conversion. Fixme. - keeper->SetCrashKeyValue(key, value); -} - -extern "C" void __declspec(dllexport) __cdecl ClearCrashKeyValueImpl( - const wchar_t* key) { - CrashKeysWin* keeper = CrashKeysWin::keeper(); - if (!keeper) - return; - - // TODO(siggi): This doesn't look quite right - there's NULL deref potential - // here, and an implicit std::wstring conversion. Fixme. - keeper->ClearCrashKeyValue(key); -} - -static bool WrapMessageBoxWithSEH(const wchar_t* text, const wchar_t* caption, - UINT flags, bool* exit_now) { - // We wrap the call to MessageBoxW with a SEH handler because it some - // machines with CursorXP, PeaDict or with FontExplorer installed it crashes - // uncontrollably here. Being this a best effort deal we better go away. - __try { - *exit_now = (IDOK != ::MessageBoxW(NULL, text, caption, flags)); - } __except(EXCEPTION_EXECUTE_HANDLER) { - // Its not safe to continue executing, exit silently here. - ::TerminateProcess(::GetCurrentProcess(), - GetBreakpadClient()->GetResultCodeRespawnFailed()); - } - - return true; -} - -// This function is executed by the child process that DumpDoneCallback() -// spawned and basically just shows the 'chrome has crashed' dialog if -// the CHROME_CRASHED environment variable is present. -bool ShowRestartDialogIfCrashed(bool* exit_now) { - // If we are being launched in metro mode don't try to show the dialog. - if (base::win::IsMetroProcess()) - return false; - - base::string16 message; - base::string16 title; - bool is_rtl_locale; - if (!GetBreakpadClient()->ShouldShowRestartDialog( - &title, &message, &is_rtl_locale)) { - return false; - } - - // If the UI layout is right-to-left, we need to pass the appropriate MB_XXX - // flags so that an RTL message box is displayed. - UINT flags = MB_OKCANCEL | MB_ICONWARNING; - if (is_rtl_locale) - flags |= MB_RIGHT | MB_RTLREADING; - - return WrapMessageBoxWithSEH(message.c_str(), title.c_str(), flags, exit_now); -} - -// Crashes the process after generating a dump for the provided exception. Note -// that the crash reporter should be initialized before calling this function -// for it to do anything. -// NOTE: This function is used by SyzyASAN to invoke a crash. If you change the -// the name or signature of this function you will break SyzyASAN instrumented -// releases of Chrome. Please contact syzygy-team@chromium.org before doing so! -extern "C" int __declspec(dllexport) CrashForException( - EXCEPTION_POINTERS* info) { - if (g_breakpad) { - g_breakpad->WriteMinidumpForException(info); - // Patched stub exists based on conditions (See InitCrashReporter). - // As a side note this function also gets called from - // WindowProcExceptionFilter. - if (g_real_terminate_process_stub == NULL) { - ::TerminateProcess(::GetCurrentProcess(), content::RESULT_CODE_KILLED); - } else { - NtTerminateProcessPtr real_terminate_proc = - reinterpret_cast<NtTerminateProcessPtr>( - static_cast<char*>(g_real_terminate_process_stub)); - real_terminate_proc(::GetCurrentProcess(), content::RESULT_CODE_KILLED); - } - } - return EXCEPTION_CONTINUE_SEARCH; -} - -static NTSTATUS WINAPI HookNtTerminateProcess(HANDLE ProcessHandle, - NTSTATUS ExitStatus) { - if (g_breakpad && - (ProcessHandle == ::GetCurrentProcess() || ProcessHandle == NULL)) { - NT_TIB* tib = reinterpret_cast<NT_TIB*>(NtCurrentTeb()); - void* address_on_stack = _AddressOfReturnAddress(); - if (address_on_stack < tib->StackLimit || - address_on_stack > tib->StackBase) { - g_surrogate_exception_record.ExceptionAddress = _ReturnAddress(); - g_surrogate_exception_record.ExceptionCode = DBG_TERMINATE_PROCESS; - g_surrogate_exception_record.ExceptionFlags = EXCEPTION_NONCONTINUABLE; - CrashForException(&g_surrogate_exception_pointers); - } - } - - NtTerminateProcessPtr real_proc = - reinterpret_cast<NtTerminateProcessPtr>( - static_cast<char*>(g_real_terminate_process_stub)); - return real_proc(ProcessHandle, ExitStatus); -} - -static void InitTerminateProcessHooks() { - NtTerminateProcessPtr terminate_process_func_address = - reinterpret_cast<NtTerminateProcessPtr>(::GetProcAddress( - ::GetModuleHandle(L"ntdll.dll"), "NtTerminateProcess")); - if (terminate_process_func_address == NULL) - return; - - DWORD old_protect = 0; - if (!::VirtualProtect(terminate_process_func_address, 5, - PAGE_EXECUTE_READWRITE, &old_protect)) - return; - - g_real_terminate_process_stub = reinterpret_cast<char*>(VirtualAllocEx( - ::GetCurrentProcess(), NULL, sidestep::kMaxPreambleStubSize, - MEM_COMMIT, PAGE_EXECUTE_READWRITE)); - if (g_real_terminate_process_stub == NULL) - return; - - g_surrogate_exception_pointers.ContextRecord = &g_surrogate_context; - g_surrogate_exception_pointers.ExceptionRecord = - &g_surrogate_exception_record; - - sidestep::SideStepError patch_result = - sidestep::PreamblePatcher::Patch( - terminate_process_func_address, HookNtTerminateProcess, - g_real_terminate_process_stub, sidestep::kMaxPreambleStubSize); - if (patch_result != sidestep::SIDESTEP_SUCCESS) { - CHECK(::VirtualFreeEx(::GetCurrentProcess(), g_real_terminate_process_stub, - 0, MEM_RELEASE)); - CHECK(::VirtualProtect(terminate_process_func_address, 5, old_protect, - &old_protect)); - return; - } - - DWORD dummy = 0; - CHECK(::VirtualProtect(terminate_process_func_address, - 5, - old_protect, - &dummy)); - CHECK(::VirtualProtect(g_real_terminate_process_stub, - sidestep::kMaxPreambleStubSize, - old_protect, - &old_protect)); -} - -static void InitPipeNameEnvVar(bool is_per_user_install) { - scoped_ptr<base::Environment> env(base::Environment::Create()); - if (env->HasVar(kPipeNameVar)) { - // The Breakpad pipe name is already configured: nothing to do. - return; - } - - // Check whether configuration management controls crash reporting. - bool crash_reporting_enabled = true; - bool controlled_by_policy = GetBreakpadClient()->ReportingIsEnforcedByPolicy( - &crash_reporting_enabled); - - const CommandLine& command = *CommandLine::ForCurrentProcess(); - bool use_crash_service = - !controlled_by_policy && (command.HasSwitch(switches::kNoErrorDialogs) || - GetBreakpadClient()->IsRunningUnattended()); - - std::wstring pipe_name; - if (use_crash_service) { - // Crash reporting is done by crash_service.exe. - pipe_name = kChromePipeName; - } else { - // We want to use the Google Update crash reporting. We need to check if the - // user allows it first (in case the administrator didn't already decide - // via policy). - if (!controlled_by_policy) - crash_reporting_enabled = GetBreakpadClient()->GetCollectStatsConsent(); - - if (!crash_reporting_enabled) { - // Crash reporting is disabled, don't set the environment variable. - return; - } - - // Build the pipe name. It can be either: - // System-wide install: "NamedPipe\GoogleCrashServices\S-1-5-18" - // Per-user install: "NamedPipe\GoogleCrashServices\<user SID>" - std::wstring user_sid; - if (is_per_user_install) { - if (!base::win::GetUserSidString(&user_sid)) { - return; - } - } else { - user_sid = kSystemPrincipalSid; - } - - pipe_name = kGoogleUpdatePipeName; - pipe_name += user_sid; - } - env->SetVar(kPipeNameVar, base::UTF16ToASCII(pipe_name)); -} - -void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter) { - previous_filter = SetUnhandledExceptionFilter(filter); -} - -void InitCrashReporter(const std::string& process_type_switch) { - const CommandLine& command = *CommandLine::ForCurrentProcess(); - if (command.HasSwitch(switches::kDisableBreakpad)) - return; - - // Disable the message box for assertions. - _CrtSetReportMode(_CRT_ASSERT, 0); - - std::wstring process_type = base::ASCIIToWide(process_type_switch); - if (process_type.empty()) - process_type = L"browser"; - - wchar_t exe_path[MAX_PATH]; - exe_path[0] = 0; - GetModuleFileNameW(NULL, exe_path, MAX_PATH); - - bool is_per_user_install = - GetBreakpadClient()->GetIsPerUserInstall(base::FilePath(exe_path)); - - // This is intentionally leaked. - CrashKeysWin* keeper = new CrashKeysWin(); - - google_breakpad::CustomClientInfo* custom_info = - keeper->GetCustomInfo(exe_path, process_type, - GetProfileType(), CommandLine::ForCurrentProcess(), - GetBreakpadClient()); - - google_breakpad::ExceptionHandler::MinidumpCallback callback = NULL; - LPTOP_LEVEL_EXCEPTION_FILTER default_filter = NULL; - // We install the post-dump callback only for the browser and service - // processes. It spawns a new browser/service process. - if (process_type == L"browser") { - callback = &DumpDoneCallback; - default_filter = &ChromeExceptionFilter; - } else if (process_type == L"service") { - callback = &DumpDoneCallback; - default_filter = &ServiceExceptionFilter; - } - - if (process_type == L"browser") { - InitPipeNameEnvVar(is_per_user_install); - GetBreakpadClient()->InitBrowserCrashDumpsRegKey(); - } - - scoped_ptr<base::Environment> env(base::Environment::Create()); - std::string pipe_name_ascii; - if (!env->GetVar(kPipeNameVar, &pipe_name_ascii)) { - // Breakpad is not enabled. Configuration is managed or the user - // did not allow Google Update to send crashes. We need to use - // our default crash handler instead, but only for the - // browser/service processes. - if (default_filter) - InitDefaultCrashCallback(default_filter); - return; - } - std::wstring pipe_name = base::ASCIIToWide(pipe_name_ascii); - -#ifdef _WIN64 - // The protocol for connecting to the out-of-process Breakpad crash - // reporter is different for x86-32 and x86-64: the message sizes - // are different because the message struct contains a pointer. As - // a result, there are two different named pipes to connect to. The - // 64-bit one is distinguished with an "-x64" suffix. - pipe_name += L"-x64"; -#endif - - // Get the alternate dump directory. We use the temp path. - wchar_t temp_dir[MAX_PATH] = {0}; - ::GetTempPathW(MAX_PATH, temp_dir); - - MINIDUMP_TYPE dump_type = kSmallDumpType; - // Capture full memory if explicitly instructed to. - if (command.HasSwitch(switches::kFullMemoryCrashReport)) - dump_type = kFullDumpType; - else if (GetBreakpadClient()->GetShouldDumpLargerDumps(is_per_user_install)) - dump_type = kLargerDumpType; - - g_breakpad = new google_breakpad::ExceptionHandler(temp_dir, &FilterCallback, - callback, NULL, - google_breakpad::ExceptionHandler::HANDLER_ALL, - dump_type, pipe_name.c_str(), custom_info); - - // Now initialize the non crash dump handler. - g_dumphandler_no_crash = new google_breakpad::ExceptionHandler(temp_dir, - &FilterCallbackWhenNoCrash, - &DumpDoneCallbackWhenNoCrash, - NULL, - // Set the handler to none so this handler would not be added to - // |handler_stack_| in |ExceptionHandler| which is a list of exception - // handlers. - google_breakpad::ExceptionHandler::HANDLER_NONE, - dump_type, pipe_name.c_str(), custom_info); - - // Set the DumpWithoutCrashingFunction for this instance of base.lib. Other - // executable images linked with base should set this again for - // DumpWithoutCrashing to function correctly. - // See chrome_main.cc for example. - base::debug::SetDumpWithoutCrashingFunction(&DumpProcessWithoutCrash); - - if (g_breakpad->IsOutOfProcess()) { - // Tells breakpad to handle breakpoint and single step exceptions. - // This might break JIT debuggers, but at least it will always - // generate a crashdump for these exceptions. - g_breakpad->set_handle_debug_exceptions(true); - -#ifndef _WIN64 - if (process_type != L"browser" && - !GetBreakpadClient()->IsRunningUnattended()) { - // Initialize the hook TerminateProcess to catch unexpected exits. - InitTerminateProcessHooks(); - } -#endif - } -} - -// If the user has disabled crash reporting uploads and restarted Chrome, the -// restarted instance will still contain the pipe environment variable, which -// will allow the restarted process to still upload crash reports. This function -// clears the environment variable, so that the restarted Chrome, which inherits -// its environment from the current Chrome, will no longer contain the variable. -extern "C" void __declspec(dllexport) __cdecl - ClearBreakpadPipeEnvironmentVariable() { - scoped_ptr<base::Environment> env(base::Environment::Create()); - env->UnSetVar(kPipeNameVar); -} - -} // namespace breakpad diff --git a/components/breakpad/app/breakpad_win.h b/components/breakpad/app/breakpad_win.h deleted file mode 100644 index 926192d..0000000 --- a/components/breakpad/app/breakpad_win.h +++ /dev/null @@ -1,22 +0,0 @@ -// 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. - -#ifndef COMPONENTS_BREAKPAD_APP_BREAKPAD_WIN_H_ -#define COMPONENTS_BREAKPAD_APP_BREAKPAD_WIN_H_ - -#include <windows.h> -#include <string> -#include <vector> - -namespace breakpad { - -void InitCrashReporter(const std::string& process_type_switch); - -// If chrome has been restarted because it crashed, this function will display -// a dialog asking for permission to continue execution or to exit now. -bool ShowRestartDialogIfCrashed(bool* exit_now); - -} // namespace breakpad - -#endif // COMPONENTS_BREAKPAD_APP_BREAKPAD_WIN_H_ diff --git a/components/breakpad/app/crash_keys_win.cc b/components/breakpad/app/crash_keys_win.cc deleted file mode 100644 index 68bbd389d..0000000 --- a/components/breakpad/app/crash_keys_win.cc +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2014 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. - -#include "components/breakpad/app/crash_keys_win.h" - -#include <algorithm> - -#include "base/base_switches.h" -#include "base/command_line.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "components/breakpad/app/breakpad_client.h" - - -namespace breakpad { - -namespace { - -const size_t kMaxPluginPathLength = 256; -const size_t kMaxDynamicEntries = 256; - -} // namespace - -CrashKeysWin* CrashKeysWin::keeper_; - -CrashKeysWin::CrashKeysWin() : dynamic_keys_offset_(0) { - DCHECK_EQ(static_cast<CrashKeysWin*>(NULL), keeper_); - keeper_ = this; -} - -CrashKeysWin::~CrashKeysWin() { - DCHECK_EQ(this, keeper_); - keeper_ = NULL; -} - -// Appends the plugin path to |g_custom_entries|. -void CrashKeysWin::SetPluginPath(const std::wstring& path) { - if (path.size() > kMaxPluginPathLength) { - // If the path is too long, truncate from the start rather than the end, - // since we want to be able to recover the DLL name. - SetPluginPath(path.substr(path.size() - kMaxPluginPathLength)); - return; - } - - // The chunk size without terminator. - const size_t kChunkSize = static_cast<size_t>( - google_breakpad::CustomInfoEntry::kValueMaxLength - 1); - - int chunk_index = 0; - size_t chunk_start = 0; // Current position inside |path| - - for (chunk_start = 0; chunk_start < path.size(); chunk_index++) { - size_t chunk_length = std::min(kChunkSize, path.size() - chunk_start); - - custom_entries_.push_back(google_breakpad::CustomInfoEntry( - base::StringPrintf(L"plugin-path-chunk-%i", chunk_index + 1).c_str(), - path.substr(chunk_start, chunk_length).c_str())); - - chunk_start += chunk_length; - } -} - -// Appends the breakpad dump path to |g_custom_entries|. -void CrashKeysWin::SetBreakpadDumpPath(BreakpadClient* breakpad_client) { - - base::FilePath crash_dumps_dir_path; - if (breakpad_client->GetAlternativeCrashDumpLocation( - &crash_dumps_dir_path)) { - custom_entries_.push_back(google_breakpad::CustomInfoEntry( - L"breakpad-dump-location", crash_dumps_dir_path.value().c_str())); - } -} - -// Returns the custom info structure based on the dll in parameter and the -// process type. -google_breakpad::CustomClientInfo* -CrashKeysWin::GetCustomInfo(const std::wstring& exe_path, - const std::wstring& type, - const std::wstring& profile_type, - base::CommandLine* cmd_line, - BreakpadClient* breakpad_client) { - base::string16 version, product; - base::string16 special_build; - base::string16 channel_name; - - breakpad_client->GetProductNameAndVersion( - base::FilePath(exe_path), - &product, - &version, - &special_build, - &channel_name); - - // We only expect this method to be called once per process. - // Common enties - custom_entries_.push_back( - google_breakpad::CustomInfoEntry(L"ver", - base::UTF16ToWide(version).c_str())); - custom_entries_.push_back( - google_breakpad::CustomInfoEntry(L"prod", - base::UTF16ToWide(product).c_str())); - custom_entries_.push_back( - google_breakpad::CustomInfoEntry(L"plat", L"Win32")); - custom_entries_.push_back( - google_breakpad::CustomInfoEntry(L"ptype", type.c_str())); - custom_entries_.push_back(google_breakpad::CustomInfoEntry( - L"pid", base::StringPrintf(L"%d", ::GetCurrentProcessId()).c_str())); - custom_entries_.push_back(google_breakpad::CustomInfoEntry( - L"channel", base::UTF16ToWide(channel_name).c_str())); - custom_entries_.push_back(google_breakpad::CustomInfoEntry( - L"profile-type", profile_type.c_str())); - - if (!special_build.empty()) - custom_entries_.push_back(google_breakpad::CustomInfoEntry( - L"special", base::UTF16ToWide(special_build).c_str())); - - if (type == L"plugin" || type == L"ppapi") { - std::wstring plugin_path = cmd_line->GetSwitchValueNative("plugin-path"); - if (!plugin_path.empty()) - SetPluginPath(plugin_path); - } - - - // Check whether configuration management controls crash reporting. - bool crash_reporting_enabled = true; - bool controlled_by_policy = breakpad_client->ReportingIsEnforcedByPolicy( - &crash_reporting_enabled); - bool use_crash_service = !controlled_by_policy && - (cmd_line->HasSwitch(switches::kNoErrorDialogs) || - breakpad_client->IsRunningUnattended()); - if (use_crash_service) - SetBreakpadDumpPath(breakpad_client); - - // Create space for dynamic ad-hoc keys. The names and values are set using - // the API defined in base/debug/crash_logging.h. - dynamic_keys_offset_ = custom_entries_.size(); - for (size_t i = 0; i < kMaxDynamicEntries; ++i) { - // The names will be mutated as they are set. Un-numbered since these are - // merely placeholders. The name cannot be empty because Breakpad's - // HTTPUpload will interpret that as an invalid parameter. - custom_entries_.push_back( - google_breakpad::CustomInfoEntry(L"unspecified-crash-key", L"")); - } - - static google_breakpad::CustomClientInfo custom_client_info; - custom_client_info.entries = &custom_entries_.front(); - custom_client_info.count = custom_entries_.size(); - - return &custom_client_info; -} - -void CrashKeysWin::SetCrashKeyValue( - const std::wstring& key, const std::wstring& value) { - // CustomInfoEntry limits the length of key and value. If they exceed - // their maximum length the underlying string handling functions raise - // an exception and prematurely trigger a crash. Truncate here. - std::wstring safe_key(std::wstring(key).substr( - 0, google_breakpad::CustomInfoEntry::kNameMaxLength - 1)); - std::wstring safe_value(std::wstring(value).substr( - 0, google_breakpad::CustomInfoEntry::kValueMaxLength - 1)); - - // If we already have a value for this key, update it; otherwise, insert - // the new value if we have not exhausted the pre-allocated slots for dynamic - // entries. - base::AutoLock lock(lock_); - - DynamicEntriesMap::iterator it = dynamic_entries_.find(safe_key); - google_breakpad::CustomInfoEntry* entry = NULL; - if (it == dynamic_entries_.end()) { - if (dynamic_entries_.size() >= kMaxDynamicEntries) - return; - entry = &custom_entries_[dynamic_keys_offset_++]; - dynamic_entries_.insert(std::make_pair(safe_key, entry)); - } else { - entry = it->second; - } - - entry->set(safe_key.data(), safe_value.data()); -} - -void CrashKeysWin::ClearCrashKeyValue(const std::wstring& key) { - base::AutoLock lock(lock_); - - std::wstring key_string(key); - DynamicEntriesMap::iterator it = dynamic_entries_.find(key_string); - if (it == dynamic_entries_.end()) - return; - - it->second->set_value(NULL); -} - -} // namespace breakpad diff --git a/components/breakpad/app/crash_keys_win.h b/components/breakpad/app/crash_keys_win.h deleted file mode 100644 index 135a31c..0000000 --- a/components/breakpad/app/crash_keys_win.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2014 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. - -#include <map> -#include <string> -#include <vector> - -#include "base/macros.h" -#include "base/synchronization/lock.h" -#include "breakpad/src/client/windows/common/ipc_protocol.h" -#include "breakpad/src/client/windows/handler/exception_handler.h" - - -namespace base { -class CommandLine; -} // namespace base - -namespace breakpad { - -class BreakpadClient; - -// Manages the breakpad key/value pair stash, there may only be one instance -// of this class per process at one time. -class CrashKeysWin { - public: - CrashKeysWin(); - ~CrashKeysWin(); - - // May only be called once. - // |exe_path| is the path to the executable running, which may be used - // to figure out whether this is a user or system install. - // |type| is the process type, or mode this process is running in e.g. - // something like "browser" or "renderer". - // |profile_type| is a string describing the kind of the user's Windows - // profile, e.g. "mandatory", or "roaming" or similar. - // |cmd_line| is the current process' command line consulted for explicit - // crash reporting flags. - // |breakpad_client| is consulted for crash reporting settings. - google_breakpad::CustomClientInfo* GetCustomInfo( - const std::wstring& exe_path, - const std::wstring& type, - const std::wstring& profile_type, - base::CommandLine* cmd_line, - BreakpadClient* breakpad_client); - - void SetCrashKeyValue(const std::wstring& key, const std::wstring& value); - void ClearCrashKeyValue(const std::wstring& key); - - static CrashKeysWin* keeper() { return keeper_; } - - private: - // One-time initialization of private key/value pairs. - void SetPluginPath(const std::wstring& path); - void SetBreakpadDumpPath(BreakpadClient* breakpad_client); - - // Must not be resized after GetCustomInfo is invoked. - std::vector<google_breakpad::CustomInfoEntry> custom_entries_; - - typedef std::map<std::wstring, google_breakpad::CustomInfoEntry*> - DynamicEntriesMap; - base::Lock lock_; - // Keeps track of the next index for a new dynamic entry. - size_t dynamic_keys_offset_; // Under lock_. - // Maintains key->entry information for dynamic key/value entries - // in custom_entries_. - DynamicEntriesMap dynamic_entries_; // Under lock_. - - // Stores the sole instance of this class allowed per process. - static CrashKeysWin* keeper_; - - DISALLOW_COPY_AND_ASSIGN(CrashKeysWin); -}; - -} // namespace breakpad diff --git a/components/breakpad/app/crash_keys_win_unittest.cc b/components/breakpad/app/crash_keys_win_unittest.cc deleted file mode 100644 index 6574e50..0000000 --- a/components/breakpad/app/crash_keys_win_unittest.cc +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2014 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. - -#include "components/breakpad/app/crash_keys_win.h" - -#include "base/command_line.h" -#include "base/files/file_path.h" -#include "base/strings/stringprintf.h" -#include "components/breakpad/app/breakpad_client.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace breakpad { - -using testing::_; -using testing::DoAll; -using testing::Return; -using testing::SetArgPointee; - -class MockBreakpadClient : public BreakpadClient { - public: - MOCK_METHOD1(GetAlternativeCrashDumpLocation, - bool(base::FilePath* crash_dir)); - MOCK_METHOD5(GetProductNameAndVersion, void(const base::FilePath& exe_path, - base::string16* product_name, - base::string16* version, - base::string16* special_build, - base::string16* channel_name)); - MOCK_METHOD3(ShouldShowRestartDialog, bool(base::string16* title, - base::string16* message, - bool* is_rtl_locale)); - MOCK_METHOD0(AboutToRestart, bool()); - MOCK_METHOD1(GetDeferredUploadsSupported, bool(bool is_per_user_install)); - MOCK_METHOD1(GetIsPerUserInstall, bool(const base::FilePath& exe_path)); - MOCK_METHOD1(GetShouldDumpLargerDumps, bool(bool is_per_user_install)); - MOCK_METHOD0(GetResultCodeRespawnFailed, int()); - MOCK_METHOD0(InitBrowserCrashDumpsRegKey, void()); - MOCK_METHOD1(RecordCrashDumpAttempt, void(bool is_real_crash)); - - MOCK_METHOD2(GetProductNameAndVersion, void(std::string* product_name, - std::string* version)); - MOCK_METHOD0(GetReporterLogFilename, base::FilePath()); - MOCK_METHOD1(GetCrashDumpLocation, bool(base::FilePath* crash_dir)); - MOCK_METHOD0(RegisterCrashKeys, size_t()); - MOCK_METHOD0(IsRunningUnattended, bool()); - MOCK_METHOD0(GetCollectStatsConsent, bool()); - MOCK_METHOD1(ReportingIsEnforcedByPolicy, bool(bool* breakpad_enabled)); - MOCK_METHOD0(GetAndroidMinidumpDescriptor, int()); -#if defined(OS_MACOSX) - MOCK_METHOD1(InstallAdditionalFilters, void(BreakpadRef breakpad)); -#endif - MOCK_METHOD1(EnableBreakpadForProcess, bool(const std::string& process_type)); -}; - -class CrashKeysWinTest : public testing::Test { - public: - - size_t CountKeyValueOccurences( - const google_breakpad::CustomClientInfo* client_info, - const wchar_t* key, const wchar_t* value); - - protected: - testing::StrictMock<MockBreakpadClient> breakpad_client_; -}; - -size_t CrashKeysWinTest::CountKeyValueOccurences( - const google_breakpad::CustomClientInfo* client_info, - const wchar_t* key, const wchar_t* value) { - size_t occurrences = 0; - for (size_t i = 0; i < client_info->count; ++i) { - if (wcscmp(client_info->entries[i].name, key) == 0 && - wcscmp(client_info->entries[i].value, value) == 0) { - ++occurrences; - } - } - - return occurrences; -} - -TEST_F(CrashKeysWinTest, RecordsSelf) { - ASSERT_EQ(static_cast<CrashKeysWin*>(NULL), CrashKeysWin::keeper()); - - { - CrashKeysWin crash_keys; - - ASSERT_EQ(&crash_keys, CrashKeysWin::keeper()); - } - - ASSERT_EQ(static_cast<CrashKeysWin*>(NULL), CrashKeysWin::keeper()); -} - -// Tests the crash keys set up for the most common official build consumer -// scenario. No policy controls, not running unattended and no explicit -// switches. -TEST_F(CrashKeysWinTest, OfficialLikeKeys) { - CrashKeysWin crash_keys; - - const base::FilePath kExePath(L"C:\\temp\\exe_path.exe"); - // The exe path ought to get passed through to the breakpad client. - EXPECT_CALL(breakpad_client_, GetProductNameAndVersion(kExePath, _, _, _, _)) - .WillRepeatedly(DoAll( - SetArgPointee<1>(L"SomeProdName"), - SetArgPointee<2>(L"1.2.3.4"), - SetArgPointee<3>(L""), - SetArgPointee<4>(L"-devm"))); - - EXPECT_CALL(breakpad_client_, GetAlternativeCrashDumpLocation(_)) - .WillRepeatedly(DoAll( - SetArgPointee<0>(base::FilePath(L"C:\\temp")), - Return(false))); - - EXPECT_CALL(breakpad_client_, ReportingIsEnforcedByPolicy(_)) - .WillRepeatedly(Return(false)); - - EXPECT_CALL(breakpad_client_, IsRunningUnattended()) - .WillRepeatedly(Return(false)); - - // Provide an empty command line. - base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM); - google_breakpad::CustomClientInfo* info = - crash_keys.GetCustomInfo(kExePath.value(), - L"made_up_type", - L"temporary", - &cmd_line, - &breakpad_client_); - - ASSERT_TRUE(info != NULL); - ASSERT_TRUE(info->entries != NULL); - - // We expect 7 fixed keys and a "freeboard" of 256 keys for dynamic entries. - EXPECT_EQ(256U + 7U, info->count); - - EXPECT_EQ(1, CountKeyValueOccurences(info, L"ver", L"1.2.3.4")); - EXPECT_EQ(1, CountKeyValueOccurences(info, L"prod", L"SomeProdName")); - EXPECT_EQ(1, CountKeyValueOccurences(info, L"plat", L"Win32")); - EXPECT_EQ(1, CountKeyValueOccurences(info, L"ptype", L"made_up_type")); - std::wstring pid_str(base::StringPrintf(L"%d", ::GetCurrentProcessId())); - EXPECT_EQ(1, CountKeyValueOccurences(info, L"pid", pid_str.c_str())); - EXPECT_EQ(1, CountKeyValueOccurences(info, L"channel", L"-devm")); - EXPECT_EQ(1, CountKeyValueOccurences(info, L"profile-type", L"temporary")); - EXPECT_EQ(256, CountKeyValueOccurences(info, L"unspecified-crash-key", L"")); -} - -} // namespace breakpad diff --git a/components/breakpad/app/hard_error_handler_win.cc b/components/breakpad/app/hard_error_handler_win.cc deleted file mode 100644 index cf93adc..0000000 --- a/components/breakpad/app/hard_error_handler_win.cc +++ /dev/null @@ -1,118 +0,0 @@ -// 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. - -#include "components/breakpad/app/hard_error_handler_win.h" - -#if defined(_WIN32_WINNT_WIN8) && _MSC_VER < 1700 -// The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h, and in -// delayimp.h previous to VS2012. -#undef FACILITY_VISUALCPP -#endif -#include <DelayIMP.h> -#include <winternl.h> - -#include "base/basictypes.h" -#include "base/strings/string_util.h" -#include "components/breakpad/app/breakpad_client.h" - -namespace breakpad { - -namespace { -const DWORD kExceptionModuleNotFound = VcppException(ERROR_SEVERITY_ERROR, - ERROR_MOD_NOT_FOUND); -const DWORD kExceptionEntryPtNotFound = VcppException(ERROR_SEVERITY_ERROR, - ERROR_PROC_NOT_FOUND); -// This is defined in <ntstatus.h> but we can't include this file here. -const DWORD FACILITY_GRAPHICS_KERNEL = 0x1E; -const DWORD NT_STATUS_ENTRYPOINT_NOT_FOUND = 0xC0000139; -const DWORD NT_STATUS_DLL_NOT_FOUND = 0xC0000135; - -// We assume that exception codes are NT_STATUS codes. -DWORD FacilityFromException(DWORD exception_code) { - return (exception_code >> 16) & 0x0FFF; -} - -// This is not a generic function. It only works with some |nt_status| values. -// Check the strings here http://msdn.microsoft.com/en-us/library/cc704588.aspx -// before attempting to use this function. -void RaiseHardErrorMsg(long nt_status, const std::string& p1, - const std::string& p2) { - // If headless just exit silently. - if (GetBreakpadClient()->IsRunningUnattended()) - return; - - HMODULE ntdll = ::GetModuleHandleA("NTDLL.DLL"); - wchar_t* msg_template = NULL; - size_t count = ::FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_FROM_HMODULE, - ntdll, - nt_status, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - reinterpret_cast<wchar_t*>(&msg_template), - 0, - NULL); - - if (!count) - return; - count += p1.size() + p2.size() + 1; - base::string16 message; - ::wsprintf(WriteInto(&message, count), msg_template, p1.c_str(), p2.c_str()); - // The MB_SERVICE_NOTIFICATION causes this message to be displayed by - // csrss. This means that we are not creating windows or pumping WM messages - // in this process. - ::MessageBox(NULL, message.c_str(), - L"chrome.exe", - MB_OK | MB_SERVICE_NOTIFICATION); - ::LocalFree(msg_template); -} - -void ModuleNotFoundHardError(const EXCEPTION_RECORD* ex_record) { - DelayLoadInfo* dli = reinterpret_cast<DelayLoadInfo*>( - ex_record->ExceptionInformation[0]); - if (!dli->szDll) - return; - RaiseHardErrorMsg(NT_STATUS_DLL_NOT_FOUND, dli->szDll, std::string()); -} - -void EntryPointNotFoundHardError(const EXCEPTION_RECORD* ex_record) { - DelayLoadInfo* dli = reinterpret_cast<DelayLoadInfo*>( - ex_record->ExceptionInformation[0]); - if (!dli->dlp.fImportByName) - return; - if (!dli->dlp.szProcName) - return; - if (!dli->szDll) - return; - RaiseHardErrorMsg(NT_STATUS_ENTRYPOINT_NOT_FOUND, - dli->dlp.szProcName, dli->szDll); -} - -} // namespace - -bool HardErrorHandler(EXCEPTION_POINTERS* ex_info) { - if (!ex_info) - return false; - if (!ex_info->ExceptionRecord) - return false; - - long exception = ex_info->ExceptionRecord->ExceptionCode; - if (exception == kExceptionModuleNotFound) { - ModuleNotFoundHardError(ex_info->ExceptionRecord); - return true; - } else if (exception == kExceptionEntryPtNotFound) { - EntryPointNotFoundHardError(ex_info->ExceptionRecord); - return true; - } else if (FacilityFromException(exception) == FACILITY_GRAPHICS_KERNEL) { -#if defined(USE_AURA) - RaiseHardErrorMsg(exception, std::string(), std::string()); - return true; -#else - return false; -#endif - } - return false; -} - -} // namespace breakpad diff --git a/components/breakpad/app/hard_error_handler_win.h b/components/breakpad/app/hard_error_handler_win.h deleted file mode 100644 index daf0482..0000000 --- a/components/breakpad/app/hard_error_handler_win.h +++ /dev/null @@ -1,34 +0,0 @@ -// 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. - -#ifndef COMPONENTS_BREAKPAD_APP_HARD_ERROR_HANDLER_WIN_H_ -#define COMPONENTS_BREAKPAD_APP_HARD_ERROR_HANDLER_WIN_H_ - -#include <windows.h> - -namespace breakpad { - -// This function is in charge of displaying a dialog box that informs the -// user of a fatal condition in chrome. It is meant to be called from -// breakpad's unhandled exception handler after the crash dump has been -// created. The return value will be true if we are to retry launching -// chrome (and show the 'chrome has crashed' dialog) or to silently exit. -// -// This function only handles a few known exceptions, currently: -// - Failure to load a delayload dll. -// - Failure to bind to a delayloaded import. -// - Fatal Graphics card failure (aura build only). -// -// If any of these conditions are encountered, a message box shown by -// the operating system CSRSS process via NtRaiseHardError is invoked. -// The wording and localization is up to the operating system. -// -// Do not call this function for memory related errors like heap corruption -// or stack exahustion. This function assumes that memory allocations are -// possible. -bool HardErrorHandler(EXCEPTION_POINTERS* ex_info); - -} // namespace breakpad - -#endif // COMPONENTS_BREAKPAD_APP_HARD_ERROR_HANDLER_WIN_H_ |