Updating trunk VERSION from 722.0 to 723.0
[chromium-blink-merge.git] / chrome / app / breakpad_win.cc
blobb7aa15caf296fb2c6e91ffa0e5d8b9ec9605186b
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/app/breakpad_win.h"
7 #include <windows.h>
8 #include <shellapi.h>
9 #include <tchar.h>
11 #include <algorithm>
12 #include <vector>
14 #include "base/base_switches.h"
15 #include "base/command_line.h"
16 #include "base/environment.h"
17 #include "base/file_util.h"
18 #include "base/file_version_info.h"
19 #include "base/memory/scoped_ptr.h"
20 #include "base/string_split.h"
21 #include "base/string_util.h"
22 #include "base/utf_string_conversions.h"
23 #include "base/win/registry.h"
24 #include "base/win/win_util.h"
25 #include "breakpad/src/client/windows/handler/exception_handler.h"
26 #include "chrome/app/hard_error_handler_win.h"
27 #include "chrome/common/child_process_logging.h"
28 #include "chrome/common/chrome_switches.h"
29 #include "chrome/common/env_vars.h"
30 #include "chrome/installer/util/google_chrome_sxs_distribution.h"
31 #include "chrome/installer/util/google_update_settings.h"
32 #include "chrome/installer/util/install_util.h"
33 #include "content/common/result_codes.h"
34 #include "policy/policy_constants.h"
36 namespace {
38 // Minidump with stacks, PEB, TEB, and unloaded module list.
39 const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
40 MiniDumpWithProcessThreadData | // Get PEB and TEB.
41 MiniDumpWithUnloadedModules); // Get unloaded modules when available.
43 // Minidump with all of the above, plus memory referenced from stack.
44 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>(
45 MiniDumpWithProcessThreadData | // Get PEB and TEB.
46 MiniDumpWithUnloadedModules | // Get unloaded modules when available.
47 MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack.
49 // Large dump with all process memory.
50 const MINIDUMP_TYPE kFullDumpType = static_cast<MINIDUMP_TYPE>(
51 MiniDumpWithFullMemory | // Full memory from process.
52 MiniDumpWithProcessThreadData | // Get PEB and TEB.
53 MiniDumpWithHandleData | // Get all handle information.
54 MiniDumpWithUnloadedModules); // Get unloaded modules when available.
56 const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\";
57 const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices";
59 // This is the well known SID for the system principal.
60 const wchar_t kSystemPrincipalSid[] =L"S-1-5-18";
62 google_breakpad::ExceptionHandler* g_breakpad = NULL;
64 // A pointer to the custom entries that we send in the event of a crash. We need
65 // this pointer, along with the offsets into it below, so that we can keep the
66 // data updated as the state of the browser changes.
67 static std::vector<google_breakpad::CustomInfoEntry>* g_custom_entries = NULL;
68 static size_t g_url_chunks_offset;
69 static size_t g_num_of_extensions_offset;
70 static size_t g_extension_ids_offset;
71 static size_t g_client_id_offset;
72 static size_t g_gpu_info_offset;
73 static size_t g_num_of_views_offset;
75 // Dumps the current process memory.
76 extern "C" void __declspec(dllexport) __cdecl DumpProcess() {
77 if (g_breakpad)
78 g_breakpad->WriteMinidump();
81 // Reduces the size of the string |str| to a max of 64 chars. Required because
82 // breakpad's CustomInfoEntry raises an invalid_parameter error if the string
83 // we want to set is longer.
84 std::wstring TrimToBreakpadMax(const std::wstring& str) {
85 std::wstring shorter(str);
86 return shorter.substr(0,
87 google_breakpad::CustomInfoEntry::kValueMaxLength - 1);
90 // Returns the custom info structure based on the dll in parameter and the
91 // process type.
92 google_breakpad::CustomClientInfo* GetCustomInfo(const std::wstring& dll_path,
93 const std::wstring& type) {
94 scoped_ptr<FileVersionInfo>
95 version_info(FileVersionInfo::CreateFileVersionInfo(FilePath(dll_path)));
97 std::wstring version, product;
98 if (version_info.get()) {
99 // Get the information from the file.
100 version = version_info->product_version();
101 if (!version_info->is_official_build())
102 version.append(L"-devel");
104 const CommandLine& command = *CommandLine::ForCurrentProcess();
105 if (command.HasSwitch(switches::kChromeFrame)) {
106 product = L"ChromeFrame";
107 } else {
108 product = version_info->product_short_name();
110 } else {
111 // No version info found. Make up the values.
112 product = L"Chrome";
113 version = L"0.0.0.0-devel";
116 // We only expect this method to be called once per process.
117 DCHECK(!g_custom_entries);
118 g_custom_entries = new std::vector<google_breakpad::CustomInfoEntry>;
120 // Common g_custom_entries.
121 g_custom_entries->push_back(
122 google_breakpad::CustomInfoEntry(L"ver", version.c_str()));
123 g_custom_entries->push_back(
124 google_breakpad::CustomInfoEntry(L"prod", product.c_str()));
125 g_custom_entries->push_back(
126 google_breakpad::CustomInfoEntry(L"plat", L"Win32"));
127 g_custom_entries->push_back(
128 google_breakpad::CustomInfoEntry(L"ptype", type.c_str()));
130 g_num_of_extensions_offset = g_custom_entries->size();
131 g_custom_entries->push_back(
132 google_breakpad::CustomInfoEntry(L"num-extensions", L"N/A"));
134 g_extension_ids_offset = g_custom_entries->size();
135 for (int i = 0; i < kMaxReportedActiveExtensions; ++i) {
136 g_custom_entries->push_back(google_breakpad::CustomInfoEntry(
137 StringPrintf(L"extension-%i", i + 1).c_str(), L""));
140 // Add empty values for the gpu_info. We'll put the actual values
141 // when we collect them at this location.
142 g_gpu_info_offset = g_custom_entries->size();
143 g_custom_entries->push_back(
144 google_breakpad::CustomInfoEntry(L"gpu-venid", L""));
145 g_custom_entries->push_back(
146 google_breakpad::CustomInfoEntry(L"gpu-devid", L""));
147 g_custom_entries->push_back(
148 google_breakpad::CustomInfoEntry(L"gpu-driver", L""));
149 g_custom_entries->push_back(
150 google_breakpad::CustomInfoEntry(L"gpu-psver", L""));
151 g_custom_entries->push_back(
152 google_breakpad::CustomInfoEntry(L"gpu-vsver", L""));
154 // Read the id from registry. If reporting has never been enabled
155 // the result will be empty string. Its OK since when user enables reporting
156 // we will insert the new value at this location.
157 std::wstring guid;
158 GoogleUpdateSettings::GetMetricsId(&guid);
159 g_client_id_offset = g_custom_entries->size();
160 g_custom_entries->push_back(
161 google_breakpad::CustomInfoEntry(L"guid", guid.c_str()));
163 if (type == L"renderer" || type == L"plugin" || type == L"gpu-process") {
164 g_num_of_views_offset = g_custom_entries->size();
165 g_custom_entries->push_back(
166 google_breakpad::CustomInfoEntry(L"num-views", L""));
167 // Create entries for the URL. Currently we only allow each chunk to be 64
168 // characters, which isn't enough for a URL. As a hack we create 8 entries
169 // and split the URL across the g_custom_entries.
170 g_url_chunks_offset = g_custom_entries->size();
171 for (int i = 0; i < kMaxUrlChunks; ++i) {
172 g_custom_entries->push_back(google_breakpad::CustomInfoEntry(
173 StringPrintf(L"url-chunk-%i", i + 1).c_str(), L""));
175 } else {
176 g_custom_entries->push_back(
177 google_breakpad::CustomInfoEntry(L"num-views", L"N/A"));
179 // Browser-specific g_custom_entries.
180 google_breakpad::CustomInfoEntry switch1(L"switch-1", L"");
181 google_breakpad::CustomInfoEntry switch2(L"switch-2", L"");
183 // Get the first two command line switches if they exist. The CommandLine
184 // class does not allow to enumerate the switches so we do it by hand.
185 int num_args = 0;
186 wchar_t** args = ::CommandLineToArgvW(::GetCommandLineW(), &num_args);
187 if (args) {
188 if (num_args > 1)
189 switch1.set_value(TrimToBreakpadMax(args[1]).c_str());
190 if (num_args > 2)
191 switch2.set_value(TrimToBreakpadMax(args[2]).c_str());
192 // The caller must free the memory allocated for |args|.
193 ::LocalFree(args);
196 g_custom_entries->push_back(switch1);
197 g_custom_entries->push_back(switch2);
200 static google_breakpad::CustomClientInfo custom_client_info;
201 custom_client_info.entries = &g_custom_entries->front();
202 custom_client_info.count = g_custom_entries->size();
204 return &custom_client_info;
207 // Contains the information needed by the worker thread.
208 struct CrashReporterInfo {
209 google_breakpad::CustomClientInfo* custom_info;
210 std::wstring dll_path;
211 std::wstring process_type;
214 // This callback is executed when the browser process has crashed, after
215 // the crash dump has been created. We need to minimize the amount of work
216 // done here since we have potentially corrupted process. Our job is to
217 // spawn another instance of chrome which will show a 'chrome has crashed'
218 // dialog. This code needs to live in the exe and thus has no access to
219 // facilities such as the i18n helpers.
220 bool DumpDoneCallback(const wchar_t*, const wchar_t*, void*,
221 EXCEPTION_POINTERS* ex_info,
222 MDRawAssertionInfo*, bool) {
223 // If the exception is because there was a problem loading a delay-loaded
224 // module, then show the user a dialog explaining the problem and then exit.
225 if (DelayLoadFailureExceptionMessageBox(ex_info))
226 return true;
228 // We set CHROME_CRASHED env var. If the CHROME_RESTART is present.
229 // This signals the child process to show the 'chrome has crashed' dialog.
230 scoped_ptr<base::Environment> env(base::Environment::Create());
231 if (!env->HasVar(env_vars::kRestartInfo)) {
232 return true;
234 env->SetVar(env_vars::kShowRestart, "1");
235 // Now we just start chrome browser with the same command line.
236 STARTUPINFOW si = {sizeof(si)};
237 PROCESS_INFORMATION pi;
238 if (::CreateProcessW(NULL, ::GetCommandLineW(), NULL, NULL, FALSE,
239 CREATE_UNICODE_ENVIRONMENT, NULL, NULL, &si, &pi)) {
240 ::CloseHandle(pi.hProcess);
241 ::CloseHandle(pi.hThread);
243 // After this return we will be terminated. The actual return value is
244 // not used at all.
245 return true;
248 // flag to indicate that we are already handling an exception.
249 volatile LONG handling_exception = 0;
251 // This callback is executed when the Chrome process has crashed and *before*
252 // the crash dump is created. To prevent duplicate crash reports we
253 // make every thread calling this method, except the very first one,
254 // go to sleep.
255 bool FilterCallback(void*, EXCEPTION_POINTERS*, MDRawAssertionInfo*) {
256 // Capture every thread except the first one in the sleep. We don't
257 // want multiple threads to concurrently report exceptions.
258 if (::InterlockedCompareExchange(&handling_exception, 1, 0) == 1) {
259 ::Sleep(INFINITE);
261 return true;
264 // Previous unhandled filter. Will be called if not null when we
265 // intercept a crash.
266 LPTOP_LEVEL_EXCEPTION_FILTER previous_filter = NULL;
268 // Exception filter used when breakpad is not enabled. We just display
269 // the "Do you want to restart" message and then we call the previous filter.
270 long WINAPI ChromeExceptionFilter(EXCEPTION_POINTERS* info) {
271 DumpDoneCallback(NULL, NULL, NULL, info, NULL, false);
273 if (previous_filter)
274 return previous_filter(info);
276 return EXCEPTION_EXECUTE_HANDLER;
279 // Exception filter for the service process used when breakpad is not enabled.
280 // We just display the "Do you want to restart" message and then die
281 // (without calling the previous filter).
282 long WINAPI ServiceExceptionFilter(EXCEPTION_POINTERS* info) {
283 DumpDoneCallback(NULL, NULL, NULL, info, NULL, false);
284 return EXCEPTION_EXECUTE_HANDLER;
287 extern "C" void __declspec(dllexport) __cdecl SetActiveURL(
288 const wchar_t* url_cstring) {
289 DCHECK(url_cstring);
291 if (!g_custom_entries)
292 return;
294 std::wstring url(url_cstring);
295 size_t chunk_index = 0;
296 size_t url_size = url.size();
298 // Split the url across all the chunks.
299 for (size_t url_offset = 0;
300 chunk_index < kMaxUrlChunks && url_offset < url_size; ++chunk_index) {
301 size_t current_chunk_size = std::min(url_size - url_offset,
302 static_cast<size_t>(
303 google_breakpad::CustomInfoEntry::kValueMaxLength - 1));
305 wchar_t* entry_value =
306 (*g_custom_entries)[g_url_chunks_offset + chunk_index].value;
307 url._Copy_s(entry_value,
308 google_breakpad::CustomInfoEntry::kValueMaxLength,
309 current_chunk_size, url_offset);
310 entry_value[current_chunk_size] = L'\0';
311 url_offset += current_chunk_size;
314 // And null terminate any unneeded chunks.
315 for (; chunk_index < kMaxUrlChunks; ++chunk_index)
316 (*g_custom_entries)[g_url_chunks_offset + chunk_index].value[0] = L'\0';
319 extern "C" void __declspec(dllexport) __cdecl SetClientId(
320 const wchar_t* client_id) {
321 if (client_id == NULL)
322 return;
324 if (!g_custom_entries)
325 return;
327 wcscpy_s((*g_custom_entries)[g_client_id_offset].value,
328 google_breakpad::CustomInfoEntry::kValueMaxLength,
329 client_id);
332 static void SetIntegerValue(size_t offset, int value) {
333 if (!g_custom_entries)
334 return;
336 wcscpy_s((*g_custom_entries)[offset].value,
337 google_breakpad::CustomInfoEntry::kValueMaxLength,
338 StringPrintf(L"%d", value).c_str());
341 extern "C" void __declspec(dllexport) __cdecl SetNumberOfExtensions(
342 int number_of_extensions) {
343 SetIntegerValue(g_num_of_extensions_offset, number_of_extensions);
346 extern "C" void __declspec(dllexport) __cdecl SetExtensionID(
347 int index, const wchar_t* id) {
348 DCHECK(id);
349 DCHECK(index < kMaxReportedActiveExtensions);
351 if (!g_custom_entries)
352 return;
354 wcscpy_s((*g_custom_entries)[g_extension_ids_offset + index].value,
355 google_breakpad::CustomInfoEntry::kValueMaxLength,
356 id);
359 extern "C" void __declspec(dllexport) __cdecl SetGpuInfo(
360 const wchar_t* vendor_id, const wchar_t* device_id,
361 const wchar_t* driver_version, const wchar_t* pixel_shader_version,
362 const wchar_t* vertex_shader_version) {
363 if (!g_custom_entries)
364 return;
366 wcscpy_s((*g_custom_entries)[g_gpu_info_offset].value,
367 google_breakpad::CustomInfoEntry::kValueMaxLength,
368 vendor_id);
369 wcscpy_s((*g_custom_entries)[g_gpu_info_offset+1].value,
370 google_breakpad::CustomInfoEntry::kValueMaxLength,
371 device_id);
372 wcscpy_s((*g_custom_entries)[g_gpu_info_offset+2].value,
373 google_breakpad::CustomInfoEntry::kValueMaxLength,
374 driver_version);
375 wcscpy_s((*g_custom_entries)[g_gpu_info_offset+3].value,
376 google_breakpad::CustomInfoEntry::kValueMaxLength,
377 pixel_shader_version);
378 wcscpy_s((*g_custom_entries)[g_gpu_info_offset+4].value,
379 google_breakpad::CustomInfoEntry::kValueMaxLength,
380 vertex_shader_version);
383 extern "C" void __declspec(dllexport) __cdecl SetNumberOfViews(
384 int number_of_views) {
385 SetIntegerValue(g_num_of_views_offset, number_of_views);
388 } // namespace
390 bool WrapMessageBoxWithSEH(const wchar_t* text, const wchar_t* caption,
391 UINT flags, bool* exit_now) {
392 // We wrap the call to MessageBoxW with a SEH handler because it some
393 // machines with CursorXP, PeaDict or with FontExplorer installed it crashes
394 // uncontrollably here. Being this a best effort deal we better go away.
395 __try {
396 *exit_now = (IDOK != ::MessageBoxW(NULL, text, caption, flags));
397 } __except(EXCEPTION_EXECUTE_HANDLER) {
398 // Its not safe to continue executing, exit silently here.
399 ::ExitProcess(ResultCodes::RESPAWN_FAILED);
402 return true;
405 // This function is executed by the child process that DumpDoneCallback()
406 // spawned and basically just shows the 'chrome has crashed' dialog if
407 // the CHROME_CRASHED environment variable is present.
408 bool ShowRestartDialogIfCrashed(bool* exit_now) {
409 if (!::GetEnvironmentVariableW(ASCIIToWide(env_vars::kShowRestart).c_str(),
410 NULL, 0)) {
411 return false;
414 DWORD len = ::GetEnvironmentVariableW(
415 ASCIIToWide(env_vars::kRestartInfo).c_str(), NULL, 0);
416 if (!len)
417 return true;
419 wchar_t* restart_data = new wchar_t[len + 1];
420 ::GetEnvironmentVariableW(ASCIIToWide(env_vars::kRestartInfo).c_str(),
421 restart_data, len);
422 restart_data[len] = 0;
423 // The CHROME_RESTART var contains the dialog strings separated by '|'.
424 // See PrepareRestartOnCrashEnviroment() function for details.
425 std::vector<std::wstring> dlg_strings;
426 base::SplitString(restart_data, L'|', &dlg_strings);
427 delete[] restart_data;
428 if (dlg_strings.size() < 3)
429 return true;
431 // If the UI layout is right-to-left, we need to pass the appropriate MB_XXX
432 // flags so that an RTL message box is displayed.
433 UINT flags = MB_OKCANCEL | MB_ICONWARNING;
434 if (dlg_strings[2] == ASCIIToWide(env_vars::kRtlLocale))
435 flags |= MB_RIGHT | MB_RTLREADING;
437 return WrapMessageBoxWithSEH(dlg_strings[1].c_str(), dlg_strings[0].c_str(),
438 flags, exit_now);
441 // Crashes the process after generating a dump for the provided exception. Note
442 // that the crash reporter should be initialized before calling this function
443 // for it to do anything.
444 extern "C" int __declspec(dllexport) CrashForException(
445 EXCEPTION_POINTERS* info) {
446 if (g_breakpad) {
447 g_breakpad->WriteMinidumpForException(info);
448 ::ExitProcess(ResultCodes::KILLED);
450 return EXCEPTION_CONTINUE_SEARCH;
453 // Determine whether configuration management allows loading the crash reporter.
454 // Since the configuration management infrastructure is not initialized at this
455 // point, we read the corresponding registry key directly. The return status
456 // indicates whether policy data was successfully read. If it is true, |result|
457 // contains the value set by policy.
458 static bool MetricsReportingControlledByPolicy(bool* result) {
459 std::wstring key_name = UTF8ToWide(policy::key::kMetricsReportingEnabled);
460 DWORD value = 0;
461 // TODO(joshia): why hkcu_policy_key opens HKEY_LOCAL_MACHINE?
462 base::win::RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE,
463 policy::kRegistrySubKey, KEY_READ);
464 if (hkcu_policy_key.ReadValueDW(key_name.c_str(), &value) == ERROR_SUCCESS) {
465 *result = value != 0;
466 return true;
469 base::win::RegKey hklm_policy_key(HKEY_CURRENT_USER,
470 policy::kRegistrySubKey, KEY_READ);
471 if (hklm_policy_key.ReadValueDW(key_name.c_str(), &value) == ERROR_SUCCESS) {
472 *result = value != 0;
473 return true;
476 return false;
479 static DWORD __stdcall InitCrashReporterThread(void* param) {
480 scoped_ptr<CrashReporterInfo> info(
481 reinterpret_cast<CrashReporterInfo*>(param));
483 // GetCustomInfo can take a few milliseconds to get the file information, so
484 // we do it here so it can run in a separate thread.
485 info->custom_info = GetCustomInfo(info->dll_path, info->process_type);
487 google_breakpad::ExceptionHandler::MinidumpCallback callback = NULL;
488 LPTOP_LEVEL_EXCEPTION_FILTER default_filter = NULL;
489 // We install the post-dump callback only for the browser and service
490 // processes. It spawns a new browser/service process.
491 if (info->process_type == L"browser") {
492 callback = &DumpDoneCallback;
493 default_filter = &ChromeExceptionFilter;
494 } else if (info->process_type == L"service") {
495 callback = &DumpDoneCallback;
496 default_filter = &ServiceExceptionFilter;
499 // Check whether configuration management controls crash reporting.
500 bool crash_reporting_enabled = true;
501 bool controlled_by_policy =
502 MetricsReportingControlledByPolicy(&crash_reporting_enabled);
504 const CommandLine& command = *CommandLine::ForCurrentProcess();
505 bool use_crash_service = !controlled_by_policy &&
506 ((command.HasSwitch(switches::kNoErrorDialogs) ||
507 GetEnvironmentVariable(
508 ASCIIToWide(env_vars::kHeadless).c_str(), NULL, 0)));
509 bool is_per_user_install =
510 InstallUtil::IsPerUserInstall(info->dll_path.c_str());
512 std::wstring pipe_name;
513 if (use_crash_service) {
514 // Crash reporting is done by crash_service.exe.
515 pipe_name = kChromePipeName;
516 } else {
517 // We want to use the Google Update crash reporting. We need to check if the
518 // user allows it first (in case the administrator didn't already decide
519 // via policy).
520 if (!controlled_by_policy)
521 crash_reporting_enabled = GoogleUpdateSettings::GetCollectStatsConsent();
523 if (!crash_reporting_enabled) {
524 // Configuration managed or the user did not allow Google Update to send
525 // crashes, we need to use our default crash handler instead, but only
526 // for the browser/service processes.
527 if (default_filter)
528 InitDefaultCrashCallback(default_filter);
529 return 0;
532 // Build the pipe name. It can be either:
533 // System-wide install: "NamedPipe\GoogleCrashServices\S-1-5-18"
534 // Per-user install: "NamedPipe\GoogleCrashServices\<user SID>"
535 std::wstring user_sid;
536 if (is_per_user_install) {
537 if (!base::win::GetUserSidString(&user_sid)) {
538 if (default_filter)
539 InitDefaultCrashCallback(default_filter);
540 return -1;
542 } else {
543 user_sid = kSystemPrincipalSid;
546 pipe_name = kGoogleUpdatePipeName;
547 pipe_name += user_sid;
550 // Get the alternate dump directory. We use the temp path.
551 wchar_t temp_dir[MAX_PATH] = {0};
552 ::GetTempPathW(MAX_PATH, temp_dir);
554 MINIDUMP_TYPE dump_type = kSmallDumpType;
555 // Capture full memory if explicitly instructed to.
556 if (command.HasSwitch(switches::kFullMemoryCrashReport)) {
557 dump_type = kFullDumpType;
558 } else {
559 // Capture more detail in crash dumps for beta and dev channel builds.
560 string16 channel_string;
561 GoogleUpdateSettings::GetChromeChannel(!is_per_user_install,
562 &channel_string);
563 if (channel_string == L"dev" || channel_string == L"beta" ||
564 channel_string == GoogleChromeSxSDistribution::ChannelName())
565 dump_type = kLargerDumpType;
568 g_breakpad = new google_breakpad::ExceptionHandler(temp_dir, &FilterCallback,
569 callback, NULL,
570 google_breakpad::ExceptionHandler::HANDLER_ALL,
571 dump_type, pipe_name.c_str(), info->custom_info);
573 if (!g_breakpad->IsOutOfProcess()) {
574 // The out-of-process handler is unavailable.
575 scoped_ptr<base::Environment> env(base::Environment::Create());
576 env->SetVar(env_vars::kNoOOBreakpad, WideToUTF8(info->process_type));
577 } else {
578 // Tells breakpad to handle breakpoint and single step exceptions.
579 // This might break JIT debuggers, but at least it will always
580 // generate a crashdump for these exceptions.
581 g_breakpad->set_handle_debug_exceptions(true);
584 return 0;
587 void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter) {
588 previous_filter = SetUnhandledExceptionFilter(filter);
591 void InitCrashReporterWithDllPath(const std::wstring& dll_path) {
592 const CommandLine& command = *CommandLine::ForCurrentProcess();
593 if (!command.HasSwitch(switches::kDisableBreakpad)) {
594 // Disable the message box for assertions.
595 _CrtSetReportMode(_CRT_ASSERT, 0);
597 // Query the custom_info now because if we do it in the thread it's going to
598 // fail in the sandbox. The thread will delete this object.
599 CrashReporterInfo* info(new CrashReporterInfo);
600 info->process_type = command.GetSwitchValueNative(switches::kProcessType);
601 if (info->process_type.empty())
602 info->process_type = L"browser";
604 info->dll_path = dll_path;
606 // If this is not the browser, we can't be sure that we will be able to
607 // initialize the crash_handler in another thread, so we run it right away.
608 // This is important to keep the thread for the browser process because
609 // it may take some times to initialize the crash_service process. We use
610 // the Windows worker pool to make better reuse of the thread.
611 if (info->process_type != L"browser") {
612 InitCrashReporterThread(info);
613 } else {
614 if (QueueUserWorkItem(
615 &InitCrashReporterThread,
616 info,
617 WT_EXECUTELONGFUNCTION) == 0) {
618 // We failed to queue to the worker pool, initialize in this thread.
619 InitCrashReporterThread(info);