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