Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(60)

Side by Side Diff: chrome/app/breakpad_win.cc

Issue 9432033: Add experiments info to crash dumps. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | chrome/app/breakpad_win_unittest.cc » ('j') | chrome/app/breakpad_win_unittest.cc » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/app/breakpad_win.h" 5 #include "chrome/app/breakpad_win.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 #include <shellapi.h> 8 #include <shellapi.h>
9 #include <tchar.h> 9 #include <tchar.h>
10 10
11 #include <algorithm> 11 #include <algorithm>
12 #include <vector> 12 #include <vector>
13 13
14 #include "base/base_switches.h" 14 #include "base/base_switches.h"
15 #include "base/command_line.h" 15 #include "base/command_line.h"
16 #include "base/environment.h" 16 #include "base/environment.h"
17 #include "base/file_util.h" 17 #include "base/file_util.h"
18 #include "base/file_version_info.h" 18 #include "base/file_version_info.h"
19 #include "base/memory/scoped_ptr.h" 19 #include "base/memory/scoped_ptr.h"
20 #include "base/string_split.h" 20 #include "base/string_split.h"
21 #include "base/string_util.h" 21 #include "base/string_util.h"
22 #include "base/string16.h"
22 #include "base/stringprintf.h" 23 #include "base/stringprintf.h"
23 #include "base/utf_string_conversions.h" 24 #include "base/utf_string_conversions.h"
24 #include "base/win/registry.h" 25 #include "base/win/registry.h"
25 #include "base/win/win_util.h" 26 #include "base/win/win_util.h"
26 #include "breakpad/src/client/windows/handler/exception_handler.h" 27 #include "breakpad/src/client/windows/handler/exception_handler.h"
27 #include "chrome/app/hard_error_handler_win.h" 28 #include "chrome/app/hard_error_handler_win.h"
28 #include "chrome/common/child_process_logging.h" 29 #include "chrome/common/child_process_logging.h"
29 #include "chrome/common/chrome_result_codes.h" 30 #include "chrome/common/chrome_result_codes.h"
30 #include "chrome/common/chrome_switches.h" 31 #include "chrome/common/chrome_switches.h"
31 #include "chrome/common/env_vars.h" 32 #include "chrome/common/env_vars.h"
32 #include "chrome/installer/util/google_chrome_sxs_distribution.h" 33 #include "chrome/installer/util/google_chrome_sxs_distribution.h"
33 #include "chrome/installer/util/google_update_settings.h" 34 #include "chrome/installer/util/google_update_settings.h"
34 #include "chrome/installer/util/install_util.h" 35 #include "chrome/installer/util/install_util.h"
35 #include "policy/policy_constants.h" 36 #include "policy/policy_constants.h"
36 37
38 // NACL_WIN64 build doesn't include field trials.
39 #if !defined(NACL_WIN64)
40 #include "base/metrics/field_trial.h"
41 #endif
42
37 namespace { 43 namespace {
38 44
39 // Minidump with stacks, PEB, TEB, and unloaded module list. 45 // Minidump with stacks, PEB, TEB, and unloaded module list.
40 const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>( 46 const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
41 MiniDumpWithProcessThreadData | // Get PEB and TEB. 47 MiniDumpWithProcessThreadData | // Get PEB and TEB.
42 MiniDumpWithUnloadedModules); // Get unloaded modules when available. 48 MiniDumpWithUnloadedModules); // Get unloaded modules when available.
43 49
44 // Minidump with all of the above, plus memory referenced from stack. 50 // Minidump with all of the above, plus memory referenced from stack.
45 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>( 51 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>(
46 MiniDumpWithProcessThreadData | // Get PEB and TEB. 52 MiniDumpWithProcessThreadData | // Get PEB and TEB.
(...skipping 23 matching lines...) Expand all
70 // data updated as the state of the browser changes. 76 // data updated as the state of the browser changes.
71 static std::vector<google_breakpad::CustomInfoEntry>* g_custom_entries = NULL; 77 static std::vector<google_breakpad::CustomInfoEntry>* g_custom_entries = NULL;
72 static size_t g_url_chunks_offset; 78 static size_t g_url_chunks_offset;
73 static size_t g_num_of_extensions_offset; 79 static size_t g_num_of_extensions_offset;
74 static size_t g_extension_ids_offset; 80 static size_t g_extension_ids_offset;
75 static size_t g_client_id_offset; 81 static size_t g_client_id_offset;
76 static size_t g_gpu_info_offset; 82 static size_t g_gpu_info_offset;
77 static size_t g_num_of_views_offset; 83 static size_t g_num_of_views_offset;
78 static size_t g_num_switches_offset; 84 static size_t g_num_switches_offset;
79 static size_t g_switches_offset; 85 static size_t g_switches_offset;
86 static size_t g_num_of_experiments_offset;
87 static size_t g_experiment_chunks_offset;
robertshield 2012/03/14 13:51:48 For clarity I'd prefer these to be initialized exp
MAD 2012/03/15 22:37:36 I don't understand... I just did the same thing as
robertshield 2012/03/20 19:24:31 Yes, this wasn't a criticism of your code :-)
80 88
81 // Maximum length for plugin path to include in plugin crash reports. 89 // Maximum length for plugin path to include in plugin crash reports.
82 const size_t kMaxPluginPathLength = 256; 90 const size_t kMaxPluginPathLength = 256;
83 91
84 // Dumps the current process memory. 92 // Dumps the current process memory.
85 extern "C" void __declspec(dllexport) __cdecl DumpProcess() { 93 extern "C" void __declspec(dllexport) __cdecl DumpProcess() {
86 if (g_breakpad) 94 if (g_breakpad)
87 g_breakpad->WriteMinidump(); 95 g_breakpad->WriteMinidump();
88 } 96 }
89 97
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 argv[argv_i].c_str(), 169 argv[argv_i].c_str(),
162 google_breakpad::CustomInfoEntry::kValueMaxLength); 170 google_breakpad::CustomInfoEntry::kValueMaxLength);
163 num_added++; 171 num_added++;
164 } 172 }
165 173
166 // Make note of the total number of switches. This is useful in case we have 174 // Make note of the total number of switches. This is useful in case we have
167 // truncated at kMaxSwitches, to see how many were unaccounted for. 175 // truncated at kMaxSwitches, to see how many were unaccounted for.
168 SetIntegerValue(g_num_switches_offset, static_cast<int>(argv.size()) - 1); 176 SetIntegerValue(g_num_switches_offset, static_cast<int>(argv.size()) - 1);
169 } 177 }
170 178
179 #if !defined(NACL_WIN64)
robertshield 2012/03/14 13:51:48 Would you consider moving this code to a new file
MAD 2012/03/15 22:37:36 It's doable, I guess I could call the function imp
robertshield 2012/03/20 19:24:31 Yes, that's what I meant. It would be a first step
180 void UpdateExperiments() {
181 std::vector<base::FieldTrial::NameGroupId> name_group_ids;
182 base::FieldTrialList::GetFieldTrialNameGroupIds(&name_group_ids);
183
184 std::vector<string16> experiment_strings(name_group_ids.size());
185 for (size_t i = 0; i < name_group_ids.size(); ++i) {
186 experiment_strings[i] = base::StringPrintf(
187 L"%x-%x", name_group_ids[i].name, name_group_ids[i].group);
188 }
189
190 size_t num_chunks = 0;
191 size_t current_experiment = 0;
192 string16 current_chunk;
193 // Preallocate the string...
194 current_chunk.resize(google_breakpad::CustomInfoEntry::kValueMaxLength);
195 current_chunk.erase(); // But start empty... This won't force a realloc.
196 while (current_experiment < experiment_strings.size() &&
197 num_chunks < kMaxReportedExperimentChunks) {
198 // Check if we have enough room to add another experiment to the current
199 // chunk string. If not, we commit the current chunk string and start over.
200 if (current_chunk.size() + experiment_strings[current_experiment].size() >
201 google_breakpad::CustomInfoEntry::kValueMaxLength) {
202 base::wcslcpy(
203 (*g_custom_entries)[g_experiment_chunks_offset + num_chunks].value,
robertshield 2012/03/14 13:51:48 Not 100% sure, but I believe this will do the wron
MAD 2012/03/15 22:37:36 You're right, I'll add a DCHECK...
robertshield 2012/03/20 19:24:31 Sounds good. I suggest also handling this case in
204 current_chunk.c_str(),
205 current_chunk.size() + 1); // This must include the NULL termination.
206 ++num_chunks;
207 current_chunk = experiment_strings[current_experiment];
208 } else {
209 if (!current_chunk.empty())
210 current_chunk += L",";
211 current_chunk += experiment_strings[current_experiment];
212 }
213 ++current_experiment;
214 }
215
216 // Commit the last chunk that didn't get big enough yet.
217 if (!current_chunk.empty() && num_chunks < kMaxReportedExperimentChunks) {
218 base::wcslcpy(
219 (*g_custom_entries)[g_experiment_chunks_offset + num_chunks].value,
220 current_chunk.c_str(),
221 current_chunk.size() + 1); // This must include the NULL termination.
222 }
223
224 // Make note of the total number of experiments,
225 // even if it's > kMaxReportedExperimentChunks. This is useful when
226 // correlating stability with the number of experiments running
227 // simultaneously.
228 SetIntegerValue(g_num_of_experiments_offset,
229 static_cast<int>(name_group_ids.size()));
230 }
231
232 extern "C" void __declspec(dllexport) __cdecl InitExperimentList() {
233 UpdateExperiments();
234 }
235
236 extern "C" void __declspec(dllexport) __cdecl AddFieldTrialGroup(
237 const std::string& field_trial_name, const std::string& group_name) {
238 // The trial is already in the list, we only use this as a notification.
239 // TODO(mad): Find a way to just add the new info instead of starting over.
robertshield 2012/03/14 13:51:48 please clarify that "the new info" is the data sto
MAD 2012/03/15 22:37:36 Done.
robertshield 2012/03/20 19:24:31 Where?
240 UpdateExperiments();
241 }
242 #endif // NACL_WIN64
243
171 // Appends the plugin path to |g_custom_entries|. 244 // Appends the plugin path to |g_custom_entries|.
172 void SetPluginPath(const std::wstring& path) { 245 void SetPluginPath(const std::wstring& path) {
173 DCHECK(g_custom_entries); 246 DCHECK(g_custom_entries);
174 247
175 if (path.size() > kMaxPluginPathLength) { 248 if (path.size() > kMaxPluginPathLength) {
176 // If the path is too long, truncate from the start rather than the end, 249 // If the path is too long, truncate from the start rather than the end,
177 // since we want to be able to recover the DLL name. 250 // since we want to be able to recover the DLL name.
178 SetPluginPath(path.substr(path.size() - kMaxPluginPathLength)); 251 SetPluginPath(path.substr(path.size() - kMaxPluginPathLength));
179 return; 252 return;
180 } 253 }
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 std::wstring plugin_path = 387 std::wstring plugin_path =
315 CommandLine::ForCurrentProcess()->GetSwitchValueNative("plugin-path"); 388 CommandLine::ForCurrentProcess()->GetSwitchValueNative("plugin-path");
316 if (!plugin_path.empty()) 389 if (!plugin_path.empty())
317 SetPluginPath(plugin_path); 390 SetPluginPath(plugin_path);
318 } 391 }
319 } else { 392 } else {
320 g_custom_entries->push_back( 393 g_custom_entries->push_back(
321 google_breakpad::CustomInfoEntry(L"num-views", L"N/A")); 394 google_breakpad::CustomInfoEntry(L"num-views", L"N/A"));
322 } 395 }
323 396
397 g_num_of_experiments_offset = g_custom_entries->size();
398 g_custom_entries->push_back(
399 google_breakpad::CustomInfoEntry(L"num-experiments", L"N/A"));
400
401 g_experiment_chunks_offset = g_custom_entries->size();
402 for (int i = 0; i < kMaxReportedExperimentChunks; ++i) {
403 g_custom_entries->push_back(google_breakpad::CustomInfoEntry(
404 base::StringPrintf(L"experiment-chunk-%i", i + 1).c_str(), L""));
405 }
406
324 static google_breakpad::CustomClientInfo custom_client_info; 407 static google_breakpad::CustomClientInfo custom_client_info;
325 custom_client_info.entries = &g_custom_entries->front(); 408 custom_client_info.entries = &g_custom_entries->front();
326 custom_client_info.count = g_custom_entries->size(); 409 custom_client_info.count = g_custom_entries->size();
327 410
328 return &custom_client_info; 411 return &custom_client_info;
329 } 412 }
330 413
331 // This callback is used when we want to get a dump without crashing the 414 // This callback is used when we want to get a dump without crashing the
332 // process. 415 // process.
333 bool DumpDoneCallbackWhenNoCrash(const wchar_t*, const wchar_t*, void*, 416 bool DumpDoneCallbackWhenNoCrash(const wchar_t*, const wchar_t*, void*,
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
504 google_breakpad::CustomInfoEntry::kValueMaxLength); 587 google_breakpad::CustomInfoEntry::kValueMaxLength);
505 } 588 }
506 589
507 extern "C" void __declspec(dllexport) __cdecl SetNumberOfViews( 590 extern "C" void __declspec(dllexport) __cdecl SetNumberOfViews(
508 int number_of_views) { 591 int number_of_views) {
509 SetIntegerValue(g_num_of_views_offset, number_of_views); 592 SetIntegerValue(g_num_of_views_offset, number_of_views);
510 } 593 }
511 594
512 } // namespace 595 } // namespace
513 596
597 namespace testing {
598
599 // Access to namespace protected functions for test purposes.
600 google_breakpad::CustomClientInfo* TestGetCustomInfo() {
601 return GetCustomInfo(L"", L"", L"");
602 }
603
604 #if !defined(NACL_WIN64)
605 void TestUpdateExperiments() {
606 UpdateExperiments();
607 }
608 #endif // NACL_WIN64
609
610 } // namespace testing
611
514 bool WrapMessageBoxWithSEH(const wchar_t* text, const wchar_t* caption, 612 bool WrapMessageBoxWithSEH(const wchar_t* text, const wchar_t* caption,
515 UINT flags, bool* exit_now) { 613 UINT flags, bool* exit_now) {
516 // We wrap the call to MessageBoxW with a SEH handler because it some 614 // We wrap the call to MessageBoxW with a SEH handler because it some
517 // machines with CursorXP, PeaDict or with FontExplorer installed it crashes 615 // machines with CursorXP, PeaDict or with FontExplorer installed it crashes
518 // uncontrollably here. Being this a best effort deal we better go away. 616 // uncontrollably here. Being this a best effort deal we better go away.
519 __try { 617 __try {
520 *exit_now = (IDOK != ::MessageBoxW(NULL, text, caption, flags)); 618 *exit_now = (IDOK != ::MessageBoxW(NULL, text, caption, flags));
521 } __except(EXCEPTION_EXECUTE_HANDLER) { 619 } __except(EXCEPTION_EXECUTE_HANDLER) {
522 // Its not safe to continue executing, exit silently here. 620 // Its not safe to continue executing, exit silently here.
523 ::ExitProcess(chrome::RESULT_CODE_RESPAWN_FAILED); 621 ::ExitProcess(chrome::RESULT_CODE_RESPAWN_FAILED);
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after
753 // Tells breakpad to handle breakpoint and single step exceptions. 851 // Tells breakpad to handle breakpoint and single step exceptions.
754 // This might break JIT debuggers, but at least it will always 852 // This might break JIT debuggers, but at least it will always
755 // generate a crashdump for these exceptions. 853 // generate a crashdump for these exceptions.
756 g_breakpad->set_handle_debug_exceptions(true); 854 g_breakpad->set_handle_debug_exceptions(true);
757 } 855 }
758 } 856 }
759 857
760 void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter) { 858 void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter) {
761 previous_filter = SetUnhandledExceptionFilter(filter); 859 previous_filter = SetUnhandledExceptionFilter(filter);
762 } 860 }
OLDNEW
« no previous file with comments | « no previous file | chrome/app/breakpad_win_unittest.cc » ('j') | chrome/app/breakpad_win_unittest.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698