summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsiggi@chromium.org <siggi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-01 21:33:28 +0000
committersiggi@chromium.org <siggi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-01 21:33:28 +0000
commit9e95fd3e871e0bb43c08329e113965ea6d140837 (patch)
treeacdc4eab0476fc20a0b633b63a539601928dd1ce
parent7d0d57e4f016f17a951102ab8fc04273b9f15a7c (diff)
downloadchromium_src-9e95fd3e871e0bb43c08329e113965ea6d140837.zip
chromium_src-9e95fd3e871e0bb43c08329e113965ea6d140837.tar.gz
chromium_src-9e95fd3e871e0bb43c08329e113965ea6d140837.tar.bz2
Tweak minidump flags to include a little more detail.
In release channel this adds PEB/TEB and the unloaded module list to crash dumps. In dev/beta channel builds this additionally adds stack-referenced memory to crash dumps. For full memory dumps, this adds capture of the PEB/TEB, unloaded module list and all handle information. These minidump flags have been verified safe against the DbgHelp.dll version shipping with XP SP2 and later. Move some code from platform_util to install_util to allow reusing it in the chrome exe project. Add a test for the additional install_util code. BUG=32441 TEST=Unittests in this change. Review URL: http://codereview.chromium.org/659001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@40300 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/breakpad_win.cc35
-rw-r--r--chrome/common/platform_util_win.cc64
-rw-r--r--chrome/installer/installer.gyp1
-rw-r--r--chrome/installer/util/google_update_settings.cc25
-rw-r--r--chrome/installer/util/google_update_settings.h5
-rw-r--r--chrome/installer/util/google_update_settings_unittest.cc153
6 files changed, 220 insertions, 63 deletions
diff --git a/chrome/app/breakpad_win.cc b/chrome/app/breakpad_win.cc
index 9668038..a0ed497 100644
--- a/chrome/app/breakpad_win.cc
+++ b/chrome/app/breakpad_win.cc
@@ -25,6 +25,24 @@
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 wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\";
const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices";
@@ -326,6 +344,8 @@ static DWORD __stdcall InitCrashReporterThread(void* param) {
const CommandLine& command = *CommandLine::ForCurrentProcess();
bool use_crash_service = command.HasSwitch(switches::kNoErrorDialogs) ||
GetEnvironmentVariable(L"CHROME_HEADLESS", NULL, 0);
+ bool is_per_user_install =
+ InstallUtil::IsPerUserInstall(info->dll_path.c_str());
std::wstring pipe_name;
if (use_crash_service) {
@@ -346,7 +366,7 @@ static DWORD __stdcall InitCrashReporterThread(void* param) {
// System-wide install: "NamedPipe\GoogleCrashServices\S-1-5-18"
// Per-user install: "NamedPipe\GoogleCrashServices\<user SID>"
std::wstring user_sid;
- if (InstallUtil::IsPerUserInstall(info->dll_path.c_str())) {
+ if (is_per_user_install) {
if (!win_util::GetUserSidString(&user_sid)) {
if (callback)
InitDefaultCrashCallback();
@@ -364,8 +384,17 @@ static DWORD __stdcall InitCrashReporterThread(void* param) {
wchar_t temp_dir[MAX_PATH] = {0};
::GetTempPathW(MAX_PATH, temp_dir);
- bool full_dump = command.HasSwitch(switches::kFullMemoryCrashReport);
- MINIDUMP_TYPE dump_type = full_dump ? MiniDumpWithFullMemory : MiniDumpNormal;
+ MINIDUMP_TYPE dump_type = kSmallDumpType;
+ // Capture full memory if explicitly instructed to.
+ if (command.HasSwitch(switches::kFullMemoryCrashReport)) {
+ dump_type = kFullDumpType;
+ } else {
+ // Capture more detail in crash dumps for beta and dev channel builds.
+ string16 channel_string;
+ GoogleUpdateSettings::GetChromeChannel(&channel_string);
+ if (channel_string == L"dev" || channel_string == L"beta")
+ dump_type = kLargerDumpType;
+ }
g_breakpad = new google_breakpad::ExceptionHandler(temp_dir, &FilterCallback,
callback, NULL,
diff --git a/chrome/common/platform_util_win.cc b/chrome/common/platform_util_win.cc
index 5553c81..9313a51 100644
--- a/chrome/common/platform_util_win.cc
+++ b/chrome/common/platform_util_win.cc
@@ -17,6 +17,7 @@
#include "base/registry.h"
#include "base/scoped_comptr_win.h"
#include "base/string_util.h"
+#include "chrome/installer/util/google_update_settings.h"
#include "chrome/installer/util/google_update_constants.h"
#include "googleurl/src/gurl.h"
@@ -151,68 +152,11 @@ void SimpleErrorBox(gfx::NativeWindow parent,
win_util::MessageBox(parent, message, title, MB_OK | MB_SETFOREGROUND);
}
-
-namespace {
-
-std::wstring CurrentChromeChannel() {
- // Start by seeing if we can find the Clients key on the HKLM branch.
- // For each search, require confirmation by looking for "name"
- // inside it. We've noticed problems cleaning up the registry on
- // uninstall or upgrade (http://crbug.com/33532,
- // http://crbug.com/33534), and have other reports of inconsistency
- // (http://crbug.com/32479).
- HKEY registry_hive = HKEY_LOCAL_MACHINE;
- std::wstring key = google_update::kRegPathClients + std::wstring(L"\\") +
- google_update::kChromeUpgradeCode;
- RegKey google_update_hklm(registry_hive, key.c_str(), KEY_READ);
-
- if (!google_update_hklm.Valid() ||
- !google_update_hklm.ValueExists(google_update::kRegNameField)) {
- // HKLM failed us, try the same for the HKCU branch.
- registry_hive = HKEY_CURRENT_USER;
- RegKey google_update_hkcu(registry_hive, key.c_str(), KEY_READ);
- if (!google_update_hkcu.Valid() ||
- !google_update_hkcu.ValueExists(google_update::kRegNameField)) {
- // Unknown.
- registry_hive = 0;
- }
- }
-
- std::wstring update_branch(L"unknown"); // the default.
- if (registry_hive != 0) {
- // Now that we know which hive to use, read the 'ap' key from it.
- std::wstring key = google_update::kRegPathClientState +
- std::wstring(L"\\") + google_update::kChromeUpgradeCode;
- RegKey client_state(registry_hive, key.c_str(), KEY_READ);
- client_state.ReadValue(google_update::kRegApField, &update_branch);
- // If the parent folder exists (we have a valid install) but the
- // 'ap' key is empty, we necessarily are the stable channel.
- // So we print nothing.
- if (update_branch.empty() && client_state.Valid()) {
- update_branch = L"";
- }
- }
-
- // Map to something pithy for human consumption. There are no rules as to
- // what the ap string can contain, but generally it will contain a number
- // followed by a dash followed by the branch name (and then some random
- // suffix). We fall back on empty string in case we fail to parse.
- // Only ever return "", "unknown", "dev" or "beta".
- if (update_branch.find(L"-beta") != std::wstring::npos)
- update_branch = L"beta";
- else if (update_branch.find(L"-dev") != std::wstring::npos)
- update_branch = L"dev";
- else if (!update_branch.empty())
- update_branch = L"unknown";
-
- return update_branch;
-}
-
-} // namespace
-
string16 GetVersionStringModifier() {
#if defined(GOOGLE_CHROME_BUILD)
- return CurrentChromeChannel();
+ string16 channel;
+ GoogleUpdateSettings::GetChromeChannel(&channel);
+ return channel;
#else
return string16();
#endif
diff --git a/chrome/installer/installer.gyp b/chrome/installer/installer.gyp
index 818817d..6d4a832 100644
--- a/chrome/installer/installer.gyp
+++ b/chrome/installer/installer.gyp
@@ -86,6 +86,7 @@
'util/delete_reg_value_work_item_unittest.cc',
'util/delete_tree_work_item_unittest.cc',
'util/google_chrome_distribution_unittest.cc',
+ 'util/google_update_settings_unittest.cc',
'util/helper_unittest.cc',
'util/installer_util_unittests.rc',
'util/installer_util_unittests_resource.h',
diff --git a/chrome/installer/util/google_update_settings.cc b/chrome/installer/util/google_update_settings.cc
index a5298e5..2dabe50 100644
--- a/chrome/installer/util/google_update_settings.cc
+++ b/chrome/installer/util/google_update_settings.cc
@@ -143,3 +143,28 @@ bool GoogleUpdateSettings::ClearReferral() {
return ClearGoogleUpdateStrKey(google_update::kRegReferralField);
}
+bool GoogleUpdateSettings::GetChromeChannel(std::wstring* channel) {
+ std::wstring update_branch;
+ if (!ReadGoogleUpdateStrKey(google_update::kRegApField, &update_branch)) {
+ *channel = L"unknown";
+ return false;
+ }
+
+ // Map to something pithy for human consumption. There are no rules as to
+ // what the ap string can contain, but generally it will contain a number
+ // followed by a dash followed by the branch name (and then some random
+ // suffix). We fall back on empty string in case we fail to parse.
+ // Only ever return "", "unknown", "dev" or "beta".
+ if (update_branch.find(L"-beta") != std::wstring::npos)
+ *channel = L"beta";
+ else if (update_branch.find(L"-dev") != std::wstring::npos)
+ *channel = L"dev";
+ else if (update_branch.empty())
+ *channel = L"";
+ else
+ *channel = L"unknown";
+
+ return true;
+}
+
+
diff --git a/chrome/installer/util/google_update_settings.h b/chrome/installer/util/google_update_settings.h
index 06adb44..3edfedf 100644
--- a/chrome/installer/util/google_update_settings.h
+++ b/chrome/installer/util/google_update_settings.h
@@ -78,6 +78,11 @@ class GoogleUpdateSettings {
// true if this operation succeeded.
static bool ClearReferral();
+ // Return a human readable modifier for the version string, e.g.
+ // the channel (dev, beta, stable). Returns true if this operation succeeded,
+ // on success, channel contains one of "", "unknown", "dev" or "beta".
+ static bool GetChromeChannel(std::wstring* channel);
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(GoogleUpdateSettings);
};
diff --git a/chrome/installer/util/google_update_settings_unittest.cc b/chrome/installer/util/google_update_settings_unittest.cc
new file mode 100644
index 0000000..bb2e46c
--- /dev/null
+++ b/chrome/installer/util/google_update_settings_unittest.cc
@@ -0,0 +1,153 @@
+// Copyright (c) 2010 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 <windows.h>
+
+#include "base/registry.h"
+#include "chrome/installer/util/browser_distribution.h"
+#include "chrome/installer/util/google_update_settings.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+const wchar_t* kHKCUReplacement =
+ L"Software\\Google\\InstallUtilUnittest\\HKCU";
+const wchar_t* kHKLMReplacement =
+ L"Software\\Google\\InstallUtilUnittest\\HKLM";
+
+// This test fixture redirects the HKLM and HKCU registry hives for
+// the duration of the test to make it independent of the machine
+// and user settings.
+class GoogleUpdateSettingsTest: public testing::Test {
+ protected:
+ virtual void SetUp() {
+ // Wipe the keys we redirect to.
+ // This gives us a stable run, even in the presence of previous
+ // crashes or failures.
+ LSTATUS err = SHDeleteKey(HKEY_CURRENT_USER, kHKCUReplacement);
+ EXPECT_TRUE(err == ERROR_SUCCESS || err == ERROR_FILE_NOT_FOUND);
+ err = SHDeleteKey(HKEY_CURRENT_USER, kHKLMReplacement);
+ EXPECT_TRUE(err == ERROR_SUCCESS || err == ERROR_FILE_NOT_FOUND);
+
+ // Create the keys we're redirecting HKCU and HKLM to.
+ ASSERT_TRUE(hkcu_.Create(HKEY_CURRENT_USER, kHKCUReplacement));
+ ASSERT_TRUE(hklm_.Create(HKEY_CURRENT_USER, kHKLMReplacement));
+
+ // And do the switcharoo.
+ ASSERT_EQ(ERROR_SUCCESS,
+ ::RegOverridePredefKey(HKEY_CURRENT_USER, hkcu_.Handle()));
+ ASSERT_EQ(ERROR_SUCCESS,
+ ::RegOverridePredefKey(HKEY_LOCAL_MACHINE, hklm_.Handle()));
+ }
+
+ virtual void TearDown() {
+ // Undo the redirection.
+ EXPECT_EQ(ERROR_SUCCESS, ::RegOverridePredefKey(HKEY_CURRENT_USER, NULL));
+ EXPECT_EQ(ERROR_SUCCESS, ::RegOverridePredefKey(HKEY_LOCAL_MACHINE, NULL));
+
+ // Close our handles and delete the temp keys we redirected to.
+ hkcu_.Close();
+ hklm_.Close();
+ EXPECT_EQ(ERROR_SUCCESS, SHDeleteKey(HKEY_CURRENT_USER, kHKCUReplacement));
+ EXPECT_EQ(ERROR_SUCCESS, SHDeleteKey(HKEY_CURRENT_USER, kHKLMReplacement));
+ }
+
+ enum SystemUserInstall {
+ SYSTEM_INSTALL,
+ USER_INSTALL,
+ };
+
+ void SetApField(SystemUserInstall is_system, const wchar_t* value) {
+ HKEY root = is_system == SYSTEM_INSTALL ?
+ HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+
+ RegKey update_key;
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ std::wstring path = dist->GetStateKey();
+ ASSERT_TRUE(update_key.Create(root, path.c_str(), KEY_WRITE));
+ ASSERT_TRUE(update_key.WriteValue(L"ap", value));
+ }
+
+ // Tests setting the ap= value to various combinations of values with
+ // prefixes and suffixes, while asserting on the correct channel value.
+ // Note that any non-empty ap= value that doesn't match ".*-{dev|beta}.*"
+ // will return the "unknown" channel.
+ void TestCurrentChromeChannelWithVariousApValues(SystemUserInstall install) {
+ static struct Expectations {
+ const wchar_t* ap_value;
+ const wchar_t* channel;
+ } expectations[] = {
+ { L"dev", L"unknown" },
+ { L"-dev", L"dev" },
+ { L"-developer", L"dev" },
+ { L"beta", L"unknown" },
+ { L"-beta", L"beta" },
+ { L"-betamax", L"beta" },
+ };
+ bool is_system = install == SYSTEM_INSTALL;
+ const wchar_t* prefixes[] = {
+ L"",
+ L"prefix",
+ L"prefix-with-dash",
+ };
+ const wchar_t* suffixes[] = {
+ L"",
+ L"suffix",
+ L"suffix-with-dash",
+ };
+
+ for (size_t i = 0; i < arraysize(prefixes); ++i) {
+ for (size_t j = 0; j < arraysize(expectations); ++j) {
+ for (size_t k = 0; k < arraysize(suffixes); ++k) {
+ std::wstring ap = prefixes[i];
+ ap += expectations[j].ap_value;
+ ap += suffixes[k];
+ const wchar_t* channel = expectations[j].channel;
+
+ SetApField(install, ap.c_str());
+ std::wstring ret_channel;
+
+ EXPECT_TRUE(GoogleUpdateSettings::GetChromeChannel(&ret_channel));
+ EXPECT_STREQ(channel, ret_channel.c_str())
+ << "Expecting channel \"" << channel
+ << "\" for ap=\"" << ap << "\"";
+ }
+ }
+ }
+ }
+
+ RegKey hkcu_;
+ RegKey hklm_;
+};
+
+} // namespace
+
+// Verify that we return failure on no registration.
+TEST_F(GoogleUpdateSettingsTest, CurrentChromeChannelAbsent) {
+ std::wstring channel;
+ EXPECT_FALSE(GoogleUpdateSettings::GetChromeChannel(&channel));
+ EXPECT_STREQ(L"unknown", channel.c_str());
+}
+
+// Test an empty Ap key for system and user.
+TEST_F(GoogleUpdateSettingsTest, CurrentChromeChannelEmptySystem) {
+ SetApField(SYSTEM_INSTALL, L"");
+ std::wstring channel;
+ EXPECT_TRUE(GoogleUpdateSettings::GetChromeChannel(&channel));
+ EXPECT_STREQ(L"", channel.c_str());
+}
+
+TEST_F(GoogleUpdateSettingsTest, CurrentChromeChannelEmptyUser) {
+ SetApField(USER_INSTALL, L"");
+ std::wstring channel;
+ EXPECT_TRUE(GoogleUpdateSettings::GetChromeChannel(&channel));
+ EXPECT_STREQ(L"", channel.c_str());
+}
+
+TEST_F(GoogleUpdateSettingsTest, CurrentChromeChannelVariousApValuesSystem) {
+ TestCurrentChromeChannelWithVariousApValues(SYSTEM_INSTALL);
+}
+
+TEST_F(GoogleUpdateSettingsTest, CurrentChromeChannelVariousApValuesUser) {
+ TestCurrentChromeChannelWithVariousApValues(USER_INSTALL);
+}