Skip to content

Commit

Permalink
Move CrashKeysWin to a separate file and add first tests.
Browse files Browse the repository at this point in the history
R=rsesek@chromium.org
BUG=378916

Review URL: https://codereview.chromium.org/327853002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@276854 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
siggi@chromium.org committed Jun 12, 2014
1 parent 5b081a2 commit caebd1b
Show file tree
Hide file tree
Showing 6 changed files with 491 additions and 239 deletions.
98 changes: 68 additions & 30 deletions components/breakpad.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,54 @@
# found in the LICENSE file.

{
'target_defaults': {
'variables': {
'breakpad_component_target': 0,
},
'target_conditions': [
['breakpad_component_target==1', {
'defines': ['BREAKPAD_IMPLEMENTATION'],
'sources': [
'breakpad/app/breakpad_client.cc',
'breakpad/app/breakpad_client.h',
'breakpad/app/breakpad_linux.cc',
'breakpad/app/breakpad_linux.h',
'breakpad/app/breakpad_linux_impl.h',
'breakpad/app/breakpad_mac.h',
'breakpad/app/breakpad_mac.mm',
'breakpad/app/breakpad_win.cc',
'breakpad/app/breakpad_win.h',
'breakpad/app/hard_error_handler_win.cc',
'breakpad/app/hard_error_handler_win.h',
],
}],
],
},
'targets': [
{
'target_name': 'breakpad_component_lib',
'type': 'static_library',
'sources': [
'breakpad/app/breakpad_client.cc',
'breakpad/app/breakpad_client.h',
'breakpad/app/crash_keys_win.cc',
'breakpad/app/crash_keys_win.h',
],
'include_dirs': [
'..',
'../breakpad/src',
],
},
{
'variables': {
'conditions': [
['OS == "ios" ', {
# On IOS there are no files compiled into the library, and we
# can't have libraries with zero objects.
'breakpad_component_target_type%': 'none',
}, {
'breakpad_component_target_type%': 'static_library',
}],
],
},
# 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.
'target_name': 'breakpad_component',
'type': 'static_library',
'variables': {
'breakpad_component_target': 1,
},
'type': '<(breakpad_component_target_type)',
'sources': [
'breakpad/app/breakpad_linux.cc',
'breakpad/app/breakpad_linux.h',
'breakpad/app/breakpad_linux_impl.h',
'breakpad/app/breakpad_mac.h',
'breakpad/app/breakpad_mac.mm',
'breakpad/app/breakpad_win.cc',
'breakpad/app/breakpad_win.h',
'breakpad/app/hard_error_handler_win.cc',
'breakpad/app/hard_error_handler_win.h',
],
'dependencies': [
'breakpad_component_lib',
'../base/base.gyp:base',
],
'defines': ['BREAKPAD_IMPLEMENTATION'],
'conditions': [
['OS=="mac"', {
'dependencies': [
Expand Down Expand Up @@ -71,6 +83,18 @@
}],
],
},
{
'target_name': 'breakpad_test_support',
'type': 'none',
'dependencies': [
'breakpad_component_lib',
],
'direct_dependent_settings': {
'include_dirs' : [
'../breakpad/src',
],
}
},
],
'conditions': [
['OS=="win"', {
Expand Down Expand Up @@ -98,11 +122,25 @@
# content/public/common/content_switches.cc to your sources.
'target_name': 'breakpad_win64',
'type': 'static_library',
'variables': {
'breakpad_component_target': 1,
},
'sources': [
'breakpad/app/breakpad_client.cc',
'breakpad/app/breakpad_client.h',
'breakpad/app/breakpad_linux.cc',
'breakpad/app/breakpad_linux.h',
'breakpad/app/breakpad_linux_impl.h',
'breakpad/app/breakpad_mac.h',
'breakpad/app/breakpad_mac.mm',
'breakpad/app/breakpad_win.cc',
'breakpad/app/breakpad_win.h',
# TODO(siggi): test the x64 version too.
'breakpad/app/crash_keys_win.cc',
'breakpad/app/crash_keys_win.h',
'breakpad/app/hard_error_handler_win.cc',
'breakpad/app/hard_error_handler_win.h',
],
'defines': [
'COMPILE_CONTENT_STATICALLY',
'BREAKPAD_IMPLEMENTATION',
],
'dependencies': [
'../base/base.gyp:base_win64',
Expand Down
212 changes: 4 additions & 208 deletions components/breakpad/app/breakpad_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#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"
Expand All @@ -46,55 +47,6 @@

namespace breakpad {

// 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.
google_breakpad::CustomClientInfo*
GetCustomInfo(const std::wstring& exe_path, const std::wstring& type);

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();

// 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_;
};

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;
}

namespace {

// Minidump with stacks, PEB, TEB, and unloaded module list.
Expand Down Expand Up @@ -134,14 +86,6 @@ typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle,
NTSTATUS ExitStatus);
char* g_real_terminate_process_stub = NULL;


// Allow for 256 dynamic entries in addition to the fixed set of entries
// set up in this file.
const size_t kMaxDynamicEntries = 256;

// Maximum length for plugin path to include in plugin crash reports.
const size_t kMaxPluginPathLength = 256;

} // namespace

// Dumps the current process memory.
Expand Down Expand Up @@ -201,43 +145,6 @@ InjectDumpForHangDebugging(HANDLE process) {
0, 0, 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() {
base::FilePath crash_dumps_dir_path;
if (GetBreakpadClient()->GetAlternativeCrashDumpLocation(
&crash_dumps_dir_path)) {
custom_entries_.push_back(google_breakpad::CustomInfoEntry(
L"breakpad-dump-location", crash_dumps_dir_path.value().c_str()));
}
}

// Returns a string containing a list of all modifiers for the loaded profile.
std::wstring GetProfileType() {
std::wstring profile_type;
Expand Down Expand Up @@ -267,79 +174,6 @@ std::wstring GetProfileType() {
return profile_type;
}

// 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) {
base::string16 version, product;
base::string16 special_build;
base::string16 channel_name;
GetBreakpadClient()->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", version.c_str()));
custom_entries_.push_back(
google_breakpad::CustomInfoEntry(L"prod", 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", channel_name.c_str()));
custom_entries_.push_back(google_breakpad::CustomInfoEntry(
L"profile-type", GetProfileType().c_str()));

if (!special_build.empty()) {
custom_entries_.push_back(google_breakpad::CustomInfoEntry(
L"special", special_build.c_str()));
}

if (type == L"plugin" || type == L"ppapi") {
std::wstring plugin_path =
CommandLine::ForCurrentProcess()->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 = GetBreakpadClient()->ReportingIsEnforcedByPolicy(
&crash_reporting_enabled);
const CommandLine& command = *CommandLine::ForCurrentProcess();
bool use_crash_service =
!controlled_by_policy && (command.HasSwitch(switches::kNoErrorDialogs) ||
GetBreakpadClient()->IsRunningUnattended());
if (use_crash_service)
SetBreakpadDumpPath();

// 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;
}

namespace {

// This callback is used when we want to get a dump without crashing the
Expand Down Expand Up @@ -433,35 +267,6 @@ long WINAPI ServiceExceptionFilter(EXCEPTION_POINTERS* info) {

} // namespace

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());
}

// 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
Expand All @@ -477,17 +282,6 @@ extern "C" void __declspec(dllexport) __cdecl SetCrashKeyValueImpl(
keeper->SetCrashKeyValue(key, value);
}

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);
}

extern "C" void __declspec(dllexport) __cdecl ClearCrashKeyValueImpl(
const wchar_t* key) {
CrashKeysWin* keeper = CrashKeysWin::keeper();
Expand Down Expand Up @@ -709,7 +503,9 @@ void InitCrashReporter(const std::string& process_type_switch) {
CrashKeysWin* keeper = new CrashKeysWin();

google_breakpad::CustomClientInfo* custom_info =
keeper->GetCustomInfo(exe_path, process_type);
keeper->GetCustomInfo(exe_path, process_type,
GetProfileType(), CommandLine::ForCurrentProcess(),
GetBreakpadClient());

google_breakpad::ExceptionHandler::MinidumpCallback callback = NULL;
LPTOP_LEVEL_EXCEPTION_FILTER default_filter = NULL;
Expand Down
Loading

0 comments on commit caebd1b

Please sign in to comment.