OLD | NEW |
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" |
| 28 #include "chrome/app/breakpad_field_trial_win.h" |
27 #include "chrome/app/hard_error_handler_win.h" | 29 #include "chrome/app/hard_error_handler_win.h" |
28 #include "chrome/common/child_process_logging.h" | 30 #include "chrome/common/child_process_logging.h" |
29 #include "chrome/common/chrome_result_codes.h" | 31 #include "chrome/common/chrome_result_codes.h" |
30 #include "chrome/common/chrome_switches.h" | 32 #include "chrome/common/chrome_switches.h" |
31 #include "chrome/common/env_vars.h" | 33 #include "chrome/common/env_vars.h" |
32 #include "chrome/installer/util/google_chrome_sxs_distribution.h" | 34 #include "chrome/installer/util/google_chrome_sxs_distribution.h" |
33 #include "chrome/installer/util/google_update_settings.h" | 35 #include "chrome/installer/util/google_update_settings.h" |
34 #include "chrome/installer/util/install_util.h" | 36 #include "chrome/installer/util/install_util.h" |
35 #include "policy/policy_constants.h" | 37 #include "policy/policy_constants.h" |
36 | 38 |
| 39 namespace breakpad_win { |
| 40 |
| 41 std::vector<google_breakpad::CustomInfoEntry>* g_custom_entries = NULL; |
| 42 size_t g_num_of_experiments_offset = 0; |
| 43 size_t g_experiment_chunks_offset = 0; |
| 44 |
| 45 } // namespace breakpad_win |
| 46 |
| 47 using breakpad_win::g_custom_entries; |
| 48 using breakpad_win::g_experiment_chunks_offset; |
| 49 using breakpad_win::g_num_of_experiments_offset; |
| 50 |
37 namespace { | 51 namespace { |
38 | 52 |
39 // Minidump with stacks, PEB, TEB, and unloaded module list. | 53 // Minidump with stacks, PEB, TEB, and unloaded module list. |
40 const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>( | 54 const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>( |
41 MiniDumpWithProcessThreadData | // Get PEB and TEB. | 55 MiniDumpWithProcessThreadData | // Get PEB and TEB. |
42 MiniDumpWithUnloadedModules); // Get unloaded modules when available. | 56 MiniDumpWithUnloadedModules); // Get unloaded modules when available. |
43 | 57 |
44 // Minidump with all of the above, plus memory referenced from stack. | 58 // Minidump with all of the above, plus memory referenced from stack. |
45 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>( | 59 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>( |
46 MiniDumpWithProcessThreadData | // Get PEB and TEB. | 60 MiniDumpWithProcessThreadData | // Get PEB and TEB. |
(...skipping 11 matching lines...) Expand all Loading... |
58 | 72 |
59 const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\"; | 73 const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\"; |
60 const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices"; | 74 const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices"; |
61 | 75 |
62 // This is the well known SID for the system principal. | 76 // This is the well known SID for the system principal. |
63 const wchar_t kSystemPrincipalSid[] =L"S-1-5-18"; | 77 const wchar_t kSystemPrincipalSid[] =L"S-1-5-18"; |
64 | 78 |
65 google_breakpad::ExceptionHandler* g_breakpad = NULL; | 79 google_breakpad::ExceptionHandler* g_breakpad = NULL; |
66 google_breakpad::ExceptionHandler* g_dumphandler_no_crash = NULL; | 80 google_breakpad::ExceptionHandler* g_dumphandler_no_crash = NULL; |
67 | 81 |
68 // A pointer to the custom entries that we send in the event of a crash. We need | 82 static size_t g_url_chunks_offset = 0; |
69 // this pointer, along with the offsets into it below, so that we can keep the | 83 static size_t g_num_of_extensions_offset = 0; |
70 // data updated as the state of the browser changes. | 84 static size_t g_extension_ids_offset = 0; |
71 static std::vector<google_breakpad::CustomInfoEntry>* g_custom_entries = NULL; | 85 static size_t g_client_id_offset = 0; |
72 static size_t g_url_chunks_offset; | 86 static size_t g_gpu_info_offset = 0; |
73 static size_t g_num_of_extensions_offset; | 87 static size_t g_printer_info_offset = 0; |
74 static size_t g_extension_ids_offset; | 88 static size_t g_num_of_views_offset = 0; |
75 static size_t g_client_id_offset; | 89 static size_t g_num_switches_offset = 0; |
76 static size_t g_gpu_info_offset; | 90 static size_t g_switches_offset = 0; |
77 static size_t g_printer_info_offset; | |
78 static size_t g_num_of_views_offset; | |
79 static size_t g_num_switches_offset; | |
80 static size_t g_switches_offset; | |
81 | 91 |
82 // Maximum length for plugin path to include in plugin crash reports. | 92 // Maximum length for plugin path to include in plugin crash reports. |
83 const size_t kMaxPluginPathLength = 256; | 93 const size_t kMaxPluginPathLength = 256; |
84 | 94 |
85 // Dumps the current process memory. | 95 // Dumps the current process memory. |
86 extern "C" void __declspec(dllexport) __cdecl DumpProcess() { | 96 extern "C" void __declspec(dllexport) __cdecl DumpProcess() { |
87 if (g_breakpad) | 97 if (g_breakpad) |
88 g_breakpad->WriteMinidump(); | 98 g_breakpad->WriteMinidump(); |
89 } | 99 } |
90 | 100 |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
246 | 256 |
247 if (!special_build.empty()) | 257 if (!special_build.empty()) |
248 g_custom_entries->push_back( | 258 g_custom_entries->push_back( |
249 google_breakpad::CustomInfoEntry(L"special", special_build.c_str())); | 259 google_breakpad::CustomInfoEntry(L"special", special_build.c_str())); |
250 | 260 |
251 g_num_of_extensions_offset = g_custom_entries->size(); | 261 g_num_of_extensions_offset = g_custom_entries->size(); |
252 g_custom_entries->push_back( | 262 g_custom_entries->push_back( |
253 google_breakpad::CustomInfoEntry(L"num-extensions", L"N/A")); | 263 google_breakpad::CustomInfoEntry(L"num-extensions", L"N/A")); |
254 | 264 |
255 g_extension_ids_offset = g_custom_entries->size(); | 265 g_extension_ids_offset = g_custom_entries->size(); |
256 for (int i = 0; i < kMaxReportedActiveExtensions; ++i) { | 266 // one-based index for the name suffix. |
| 267 for (int i = 1; i <= kMaxReportedActiveExtensions; ++i) { |
257 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( | 268 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( |
258 base::StringPrintf(L"extension-%i", i + 1).c_str(), L"")); | 269 base::StringPrintf(L"extension-%i", i).c_str(), L"")); |
259 } | 270 } |
260 | 271 |
261 // Add empty values for the gpu_info. We'll put the actual values when we | 272 // Add empty values for the gpu_info. We'll put the actual values when we |
262 // collect them at this location. | 273 // collect them at this location. |
263 g_gpu_info_offset = g_custom_entries->size(); | 274 g_gpu_info_offset = g_custom_entries->size(); |
264 static const wchar_t* const kGpuEntries[] = { | 275 static const wchar_t* const kGpuEntries[] = { |
265 L"gpu-venid", | 276 L"gpu-venid", |
266 L"gpu-devid", | 277 L"gpu-devid", |
267 L"gpu-driver", | 278 L"gpu-driver", |
268 L"gpu-psver", | 279 L"gpu-psver", |
269 L"gpu-vsver", | 280 L"gpu-vsver", |
270 }; | 281 }; |
271 for (size_t i = 0; i < arraysize(kGpuEntries); ++i) { | 282 for (size_t i = 0; i < arraysize(kGpuEntries); ++i) { |
272 g_custom_entries->push_back( | 283 g_custom_entries->push_back( |
273 google_breakpad::CustomInfoEntry(kGpuEntries[i], L"")); | 284 google_breakpad::CustomInfoEntry(kGpuEntries[i], L"")); |
274 } | 285 } |
275 | 286 |
276 // Add empty values for the prn_info-*. We'll put the actual values when we | 287 // Add empty values for the prn_info-*. We'll put the actual values when we |
277 // collect them at this location. | 288 // collect them at this location. |
278 g_printer_info_offset = g_custom_entries->size(); | 289 g_printer_info_offset = g_custom_entries->size(); |
279 for (size_t i = 0; i < kMaxReportedPrinterRecords; ++i) { | 290 // one-based index for the name suffix. |
| 291 for (size_t i = 1; i <= kMaxReportedPrinterRecords; ++i) { |
280 g_custom_entries->push_back( | 292 g_custom_entries->push_back( |
281 google_breakpad::CustomInfoEntry( | 293 google_breakpad::CustomInfoEntry( |
282 base::StringPrintf(L"prn-info-%d", i + 1).c_str(), L"")); | 294 base::StringPrintf(L"prn-info-%d", i).c_str(), L"")); |
283 } | 295 } |
284 | 296 |
285 // Read the id from registry. If reporting has never been enabled | 297 // Read the id from registry. If reporting has never been enabled |
286 // the result will be empty string. Its OK since when user enables reporting | 298 // the result will be empty string. Its OK since when user enables reporting |
287 // we will insert the new value at this location. | 299 // we will insert the new value at this location. |
288 std::wstring guid; | 300 std::wstring guid; |
289 GoogleUpdateSettings::GetMetricsId(&guid); | 301 GoogleUpdateSettings::GetMetricsId(&guid); |
290 g_client_id_offset = g_custom_entries->size(); | 302 g_client_id_offset = g_custom_entries->size(); |
291 g_custom_entries->push_back( | 303 g_custom_entries->push_back( |
292 google_breakpad::CustomInfoEntry(L"guid", guid.c_str())); | 304 google_breakpad::CustomInfoEntry(L"guid", guid.c_str())); |
293 | 305 |
294 // Add empty values for the command line switches. We will fill them with | 306 // Add empty values for the command line switches. We will fill them with |
295 // actual values as part of SetCommandLine(). | 307 // actual values as part of SetCommandLine(). |
296 g_num_switches_offset = g_custom_entries->size(); | 308 g_num_switches_offset = g_custom_entries->size(); |
297 g_custom_entries->push_back( | 309 g_custom_entries->push_back( |
298 google_breakpad::CustomInfoEntry(L"num-switches", L"")); | 310 google_breakpad::CustomInfoEntry(L"num-switches", L"")); |
299 | 311 |
300 g_switches_offset = g_custom_entries->size(); | 312 g_switches_offset = g_custom_entries->size(); |
301 for (int i = 0; i < kMaxSwitches; ++i) { | 313 // one-based index for the name suffix. |
| 314 for (int i = 1; i <= kMaxSwitches; ++i) { |
302 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( | 315 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( |
303 base::StringPrintf(L"switch-%i", i + 1).c_str(), L"")); | 316 base::StringPrintf(L"switch-%i", i).c_str(), L"")); |
304 } | 317 } |
305 | 318 |
306 // Fill in the command line arguments using CommandLine::ForCurrentProcess(). | 319 // Fill in the command line arguments using CommandLine::ForCurrentProcess(). |
307 // The browser process may call SetCommandLine() again later on with a command | 320 // The browser process may call SetCommandLine() again later on with a command |
308 // line that has been augmented with the about:flags experiments. | 321 // line that has been augmented with the about:flags experiments. |
309 SetCommandLine(CommandLine::ForCurrentProcess()); | 322 SetCommandLine(CommandLine::ForCurrentProcess()); |
310 | 323 |
311 if (type == L"renderer" || type == L"plugin" || type == L"gpu-process") { | 324 if (type == L"renderer" || type == L"plugin" || type == L"gpu-process") { |
312 g_num_of_views_offset = g_custom_entries->size(); | 325 g_num_of_views_offset = g_custom_entries->size(); |
313 g_custom_entries->push_back( | 326 g_custom_entries->push_back( |
314 google_breakpad::CustomInfoEntry(L"num-views", L"")); | 327 google_breakpad::CustomInfoEntry(L"num-views", L"")); |
315 // Create entries for the URL. Currently we only allow each chunk to be 64 | 328 // Create entries for the URL. Currently we only allow each chunk to be 64 |
316 // characters, which isn't enough for a URL. As a hack we create 8 entries | 329 // characters, which isn't enough for a URL. As a hack we create 8 entries |
317 // and split the URL across the g_custom_entries. | 330 // and split the URL across the g_custom_entries. |
318 g_url_chunks_offset = g_custom_entries->size(); | 331 g_url_chunks_offset = g_custom_entries->size(); |
319 for (int i = 0; i < kMaxUrlChunks; ++i) { | 332 // one-based index for the name suffix. |
| 333 for (int i = 1; i <= kMaxUrlChunks; ++i) { |
320 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( | 334 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( |
321 base::StringPrintf(L"url-chunk-%i", i + 1).c_str(), L"")); | 335 base::StringPrintf(L"url-chunk-%i", i).c_str(), L"")); |
322 } | 336 } |
323 | 337 |
324 if (type == L"plugin") { | 338 if (type == L"plugin") { |
325 std::wstring plugin_path = | 339 std::wstring plugin_path = |
326 CommandLine::ForCurrentProcess()->GetSwitchValueNative("plugin-path"); | 340 CommandLine::ForCurrentProcess()->GetSwitchValueNative("plugin-path"); |
327 if (!plugin_path.empty()) | 341 if (!plugin_path.empty()) |
328 SetPluginPath(plugin_path); | 342 SetPluginPath(plugin_path); |
329 } | 343 } |
330 } else { | 344 } else { |
331 g_custom_entries->push_back( | 345 g_custom_entries->push_back( |
332 google_breakpad::CustomInfoEntry(L"num-views", L"N/A")); | 346 google_breakpad::CustomInfoEntry(L"num-views", L"N/A")); |
333 } | 347 } |
334 | 348 |
| 349 g_num_of_experiments_offset = g_custom_entries->size(); |
| 350 g_custom_entries->push_back( |
| 351 google_breakpad::CustomInfoEntry(L"num-experiments", L"N/A")); |
| 352 |
| 353 g_experiment_chunks_offset = g_custom_entries->size(); |
| 354 // We depend on this in UpdateExperiments... |
| 355 DCHECK_NE(0UL, g_experiment_chunks_offset); |
| 356 // And the test code depends on this. |
| 357 DCHECK_EQ(g_num_of_experiments_offset + 1, g_experiment_chunks_offset); |
| 358 // one-based index for the name suffix. |
| 359 for (int i = 1; i <= kMaxReportedExperimentChunks; ++i) { |
| 360 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( |
| 361 base::StringPrintf(L"experiment-chunk-%i", i).c_str(), L"")); |
| 362 } |
| 363 |
335 static google_breakpad::CustomClientInfo custom_client_info; | 364 static google_breakpad::CustomClientInfo custom_client_info; |
336 custom_client_info.entries = &g_custom_entries->front(); | 365 custom_client_info.entries = &g_custom_entries->front(); |
337 custom_client_info.count = g_custom_entries->size(); | 366 custom_client_info.count = g_custom_entries->size(); |
338 | 367 |
339 return &custom_client_info; | 368 return &custom_client_info; |
340 } | 369 } |
341 | 370 |
342 // This callback is used when we want to get a dump without crashing the | 371 // This callback is used when we want to get a dump without crashing the |
343 // process. | 372 // process. |
344 bool DumpDoneCallbackWhenNoCrash(const wchar_t*, const wchar_t*, void*, | 373 bool DumpDoneCallbackWhenNoCrash(const wchar_t*, const wchar_t*, void*, |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
528 } | 557 } |
529 } | 558 } |
530 | 559 |
531 extern "C" void __declspec(dllexport) __cdecl SetNumberOfViews( | 560 extern "C" void __declspec(dllexport) __cdecl SetNumberOfViews( |
532 int number_of_views) { | 561 int number_of_views) { |
533 SetIntegerValue(g_num_of_views_offset, number_of_views); | 562 SetIntegerValue(g_num_of_views_offset, number_of_views); |
534 } | 563 } |
535 | 564 |
536 } // namespace | 565 } // namespace |
537 | 566 |
| 567 namespace testing { |
| 568 |
| 569 // Access to namespace protected functions for testing purposes. |
| 570 void InitCustomInfoEntries() { |
| 571 GetCustomInfo(L"", L"", L""); |
| 572 } |
| 573 |
| 574 } // namespace testing |
| 575 |
538 bool WrapMessageBoxWithSEH(const wchar_t* text, const wchar_t* caption, | 576 bool WrapMessageBoxWithSEH(const wchar_t* text, const wchar_t* caption, |
539 UINT flags, bool* exit_now) { | 577 UINT flags, bool* exit_now) { |
540 // We wrap the call to MessageBoxW with a SEH handler because it some | 578 // We wrap the call to MessageBoxW with a SEH handler because it some |
541 // machines with CursorXP, PeaDict or with FontExplorer installed it crashes | 579 // machines with CursorXP, PeaDict or with FontExplorer installed it crashes |
542 // uncontrollably here. Being this a best effort deal we better go away. | 580 // uncontrollably here. Being this a best effort deal we better go away. |
543 __try { | 581 __try { |
544 *exit_now = (IDOK != ::MessageBoxW(NULL, text, caption, flags)); | 582 *exit_now = (IDOK != ::MessageBoxW(NULL, text, caption, flags)); |
545 } __except(EXCEPTION_EXECUTE_HANDLER) { | 583 } __except(EXCEPTION_EXECUTE_HANDLER) { |
546 // Its not safe to continue executing, exit silently here. | 584 // Its not safe to continue executing, exit silently here. |
547 ::TerminateProcess(::GetCurrentProcess(), | 585 ::TerminateProcess(::GetCurrentProcess(), |
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
778 // Tells breakpad to handle breakpoint and single step exceptions. | 816 // Tells breakpad to handle breakpoint and single step exceptions. |
779 // This might break JIT debuggers, but at least it will always | 817 // This might break JIT debuggers, but at least it will always |
780 // generate a crashdump for these exceptions. | 818 // generate a crashdump for these exceptions. |
781 g_breakpad->set_handle_debug_exceptions(true); | 819 g_breakpad->set_handle_debug_exceptions(true); |
782 } | 820 } |
783 } | 821 } |
784 | 822 |
785 void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter) { | 823 void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter) { |
786 previous_filter = SetUnhandledExceptionFilter(filter); | 824 previous_filter = SetUnhandledExceptionFilter(filter); |
787 } | 825 } |
OLD | NEW |