Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / components / crash / content / app / breakpad_win.cc
blob5b53ff791830104f4664e21e25f675b668768576
1 // Copyright 2013 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 "components/crash/content/app/breakpad_win.h"
7 #include <windows.h>
8 #include <shellapi.h>
9 #include <tchar.h>
10 #include <userenv.h>
11 #include <winnt.h>
13 #include <algorithm>
14 #include <map>
15 #include <vector>
17 #include "base/base_switches.h"
18 #include "base/basictypes.h"
19 #include "base/command_line.h"
20 #include "base/debug/crash_logging.h"
21 #include "base/debug/dump_without_crashing.h"
22 #include "base/environment.h"
23 #include "base/memory/scoped_ptr.h"
24 #include "base/numerics/safe_conversions.h"
25 #include "base/strings/string16.h"
26 #include "base/strings/string_split.h"
27 #include "base/strings/string_util.h"
28 #include "base/strings/stringprintf.h"
29 #include "base/strings/utf_string_conversions.h"
30 #include "base/synchronization/lock.h"
31 #include "base/win/metro.h"
32 #include "base/win/pe_image.h"
33 #include "base/win/registry.h"
34 #include "base/win/win_util.h"
35 #include "breakpad/src/client/windows/handler/exception_handler.h"
36 #include "components/crash/content/app/crash_keys_win.h"
37 #include "components/crash/content/app/crash_reporter_client.h"
38 #include "components/crash/content/app/hard_error_handler_win.h"
39 #include "content/public/common/result_codes.h"
40 #include "sandbox/win/src/nt_internals.h"
41 #include "sandbox/win/src/sidestep/preamble_patcher.h"
43 // userenv.dll is required for GetProfileType().
44 #pragma comment(lib, "userenv.lib")
46 #pragma intrinsic(_AddressOfReturnAddress)
47 #pragma intrinsic(_ReturnAddress)
49 #ifdef _WIN64
50 // See http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
51 typedef struct _UNWIND_INFO {
52 unsigned char Version : 3;
53 unsigned char Flags : 5;
54 unsigned char SizeOfProlog;
55 unsigned char CountOfCodes;
56 unsigned char FrameRegister : 4;
57 unsigned char FrameOffset : 4;
58 ULONG ExceptionHandler;
59 } UNWIND_INFO, *PUNWIND_INFO;
60 #endif
62 namespace breakpad {
64 using crash_reporter::GetCrashReporterClient;
66 namespace {
68 // Minidump with stacks, PEB, TEB, and unloaded module list.
69 const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
70 MiniDumpWithProcessThreadData | // Get PEB and TEB.
71 MiniDumpWithUnloadedModules); // Get unloaded modules when available.
73 // Minidump with all of the above, plus memory referenced from stack.
74 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>(
75 MiniDumpWithProcessThreadData | // Get PEB and TEB.
76 MiniDumpWithUnloadedModules | // Get unloaded modules when available.
77 MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack.
79 // Large dump with all process memory.
80 const MINIDUMP_TYPE kFullDumpType = static_cast<MINIDUMP_TYPE>(
81 MiniDumpWithFullMemory | // Full memory from process.
82 MiniDumpWithProcessThreadData | // Get PEB and TEB.
83 MiniDumpWithHandleData | // Get all handle information.
84 MiniDumpWithUnloadedModules); // Get unloaded modules when available.
86 const char kPipeNameVar[] = "CHROME_BREAKPAD_PIPE_NAME";
88 const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\";
89 const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices";
91 // This is the well known SID for the system principal.
92 const wchar_t kSystemPrincipalSid[] =L"S-1-5-18";
94 google_breakpad::ExceptionHandler* g_breakpad = NULL;
95 google_breakpad::ExceptionHandler* g_dumphandler_no_crash = NULL;
97 #if !defined(_WIN64)
98 EXCEPTION_POINTERS g_surrogate_exception_pointers = {0};
99 EXCEPTION_RECORD g_surrogate_exception_record = {0};
100 CONTEXT g_surrogate_context = {0};
101 #endif // !defined(_WIN64)
103 typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle,
104 NTSTATUS ExitStatus);
105 char* g_real_terminate_process_stub = NULL;
107 } // namespace
109 // Dumps the current process memory.
110 extern "C" void __declspec(dllexport) __cdecl DumpProcess() {
111 if (g_breakpad) {
112 g_breakpad->WriteMinidump();
116 // Used for dumping a process state when there is no crash.
117 extern "C" void __declspec(dllexport) __cdecl DumpProcessWithoutCrash() {
118 if (g_dumphandler_no_crash) {
119 g_dumphandler_no_crash->WriteMinidump();
123 namespace {
125 // We need to prevent ICF from folding DumpForHangDebuggingThread() and
126 // DumpProcessWithoutCrashThread() together, since that makes them
127 // indistinguishable in crash dumps. We do this by making the function
128 // bodies unique, and prevent optimization from shuffling things around.
129 MSVC_DISABLE_OPTIMIZE()
130 MSVC_PUSH_DISABLE_WARNING(4748)
132 DWORD WINAPI DumpProcessWithoutCrashThread(void*) {
133 DumpProcessWithoutCrash();
134 return 0;
137 // The following two functions do exactly the same thing as the two above. But
138 // we want the signatures to be different so that we can easily track them in
139 // crash reports.
140 // TODO(yzshen): Remove when enough information is collected and the hang rate
141 // of pepper/renderer processes is reduced.
142 DWORD WINAPI DumpForHangDebuggingThread(void*) {
143 DumpProcessWithoutCrash();
144 VLOG(1) << "dumped for hang debugging";
145 return 0;
148 MSVC_POP_WARNING()
149 MSVC_ENABLE_OPTIMIZE()
151 } // namespace
153 // Injects a thread into a remote process to dump state when there is no crash.
154 extern "C" HANDLE __declspec(dllexport) __cdecl
155 InjectDumpProcessWithoutCrash(HANDLE process) {
156 return CreateRemoteThread(process, NULL, 0, DumpProcessWithoutCrashThread,
157 0, 0, NULL);
160 extern "C" HANDLE __declspec(dllexport) __cdecl
161 InjectDumpForHangDebugging(HANDLE process) {
162 return CreateRemoteThread(process, NULL, 0, DumpForHangDebuggingThread,
163 0, 0, NULL);
166 // Returns a string containing a list of all modifiers for the loaded profile.
167 std::wstring GetProfileType() {
168 std::wstring profile_type;
169 DWORD profile_bits = 0;
170 if (::GetProfileType(&profile_bits)) {
171 static const struct {
172 DWORD bit;
173 const wchar_t* name;
174 } kBitNames[] = {
175 { PT_MANDATORY, L"mandatory" },
176 { PT_ROAMING, L"roaming" },
177 { PT_TEMPORARY, L"temporary" },
179 for (size_t i = 0; i < arraysize(kBitNames); ++i) {
180 const DWORD this_bit = kBitNames[i].bit;
181 if ((profile_bits & this_bit) != 0) {
182 profile_type.append(kBitNames[i].name);
183 profile_bits &= ~this_bit;
184 if (profile_bits != 0)
185 profile_type.append(L", ");
188 } else {
189 DWORD last_error = ::GetLastError();
190 base::SStringPrintf(&profile_type, L"error %u", last_error);
192 return profile_type;
195 namespace {
197 // This callback is used when we want to get a dump without crashing the
198 // process.
199 bool DumpDoneCallbackWhenNoCrash(const wchar_t*, const wchar_t*, void*,
200 EXCEPTION_POINTERS* ex_info,
201 MDRawAssertionInfo*, bool succeeded) {
202 GetCrashReporterClient()->RecordCrashDumpAttemptResult(
203 false /* is_real_crash */, succeeded);
204 return true;
207 // This callback is executed when the browser process has crashed, after
208 // the crash dump has been created. We need to minimize the amount of work
209 // done here since we have potentially corrupted process. Our job is to
210 // spawn another instance of chrome which will show a 'chrome has crashed'
211 // dialog. This code needs to live in the exe and thus has no access to
212 // facilities such as the i18n helpers.
213 bool DumpDoneCallback(const wchar_t*, const wchar_t*, void*,
214 EXCEPTION_POINTERS* ex_info,
215 MDRawAssertionInfo*, bool succeeded) {
216 GetCrashReporterClient()->RecordCrashDumpAttemptResult(
217 true /* is_real_crash */, succeeded);
218 // Check if the exception is one of the kind which would not be solved
219 // by simply restarting chrome. In this case we show a message box with
220 // and exit silently. Remember that chrome is in a crashed state so we
221 // can't show our own UI from this process.
222 if (HardErrorHandler(ex_info))
223 return true;
225 if (!GetCrashReporterClient()->AboutToRestart())
226 return true;
228 // Now we just start chrome browser with the same command line.
229 STARTUPINFOW si = {sizeof(si)};
230 PROCESS_INFORMATION pi;
231 if (::CreateProcessW(NULL, ::GetCommandLineW(), NULL, NULL, FALSE,
232 CREATE_UNICODE_ENVIRONMENT, NULL, NULL, &si, &pi)) {
233 ::CloseHandle(pi.hProcess);
234 ::CloseHandle(pi.hThread);
236 // After this return we will be terminated. The actual return value is
237 // not used at all.
238 return true;
241 // flag to indicate that we are already handling an exception.
242 volatile LONG handling_exception = 0;
244 // This callback is used when there is no crash. Note: Unlike the
245 // |FilterCallback| below this does not do dupe detection. It is upto the caller
246 // to implement it.
247 bool FilterCallbackWhenNoCrash(
248 void*, EXCEPTION_POINTERS*, MDRawAssertionInfo*) {
249 GetCrashReporterClient()->RecordCrashDumpAttempt(false);
250 return true;
253 // This callback is executed when the Chrome process has crashed and *before*
254 // the crash dump is created. To prevent duplicate crash reports we
255 // make every thread calling this method, except the very first one,
256 // go to sleep.
257 bool FilterCallback(void*, EXCEPTION_POINTERS*, MDRawAssertionInfo*) {
258 // Capture every thread except the first one in the sleep. We don't
259 // want multiple threads to concurrently report exceptions.
260 if (::InterlockedCompareExchange(&handling_exception, 1, 0) == 1) {
261 ::Sleep(INFINITE);
263 GetCrashReporterClient()->RecordCrashDumpAttempt(true);
264 return true;
267 // Previous unhandled filter. Will be called if not null when we
268 // intercept a crash.
269 LPTOP_LEVEL_EXCEPTION_FILTER previous_filter = NULL;
271 // Exception filter used when breakpad is not enabled. We just display
272 // the "Do you want to restart" message and then we call the previous filter.
273 long WINAPI ChromeExceptionFilter(EXCEPTION_POINTERS* info) {
274 DumpDoneCallback(NULL, NULL, NULL, info, NULL, false);
276 if (previous_filter)
277 return previous_filter(info);
279 return EXCEPTION_EXECUTE_HANDLER;
282 // Exception filter for the service process used when breakpad is not enabled.
283 // We just display the "Do you want to restart" message and then die
284 // (without calling the previous filter).
285 long WINAPI ServiceExceptionFilter(EXCEPTION_POINTERS* info) {
286 DumpDoneCallback(NULL, NULL, NULL, info, NULL, false);
287 return EXCEPTION_EXECUTE_HANDLER;
290 #if !defined(COMPONENT_BUILD)
291 // Installed via base::debug::SetCrashKeyReportingFunctions.
292 void SetCrashKeyValueForBaseDebug(const base::StringPiece& key,
293 const base::StringPiece& value) {
294 DCHECK(CrashKeysWin::keeper());
295 CrashKeysWin::keeper()->SetCrashKeyValue(base::UTF8ToUTF16(key),
296 base::UTF8ToUTF16(value));
299 // Installed via base::debug::SetCrashKeyReportingFunctions.
300 void ClearCrashKeyForBaseDebug(const base::StringPiece& key) {
301 DCHECK(CrashKeysWin::keeper());
302 CrashKeysWin::keeper()->ClearCrashKeyValue(base::UTF8ToUTF16(key));
304 #endif // !defined(COMPONENT_BUILD)
306 } // namespace
308 // NOTE: This function is used by SyzyASAN to annotate crash reports. If you
309 // change the name or signature of this function you will break SyzyASAN
310 // instrumented releases of Chrome. Please contact syzygy-team@chromium.org
311 // before doing so!
312 extern "C" void __declspec(dllexport) __cdecl SetCrashKeyValueImpl(
313 const wchar_t* key, const wchar_t* value) {
314 CrashKeysWin* keeper = CrashKeysWin::keeper();
315 if (!keeper)
316 return;
318 // TODO(siggi): This doesn't look quite right - there's NULL deref potential
319 // here, and an implicit std::wstring conversion. Fixme.
320 keeper->SetCrashKeyValue(key, value);
323 extern "C" void __declspec(dllexport) __cdecl ClearCrashKeyValueImpl(
324 const wchar_t* key) {
325 CrashKeysWin* keeper = CrashKeysWin::keeper();
326 if (!keeper)
327 return;
329 // TODO(siggi): This doesn't look quite right - there's NULL deref potential
330 // here, and an implicit std::wstring conversion. Fixme.
331 keeper->ClearCrashKeyValue(key);
334 static bool WrapMessageBoxWithSEH(const wchar_t* text, const wchar_t* caption,
335 UINT flags, bool* exit_now) {
336 // We wrap the call to MessageBoxW with a SEH handler because it some
337 // machines with CursorXP, PeaDict or with FontExplorer installed it crashes
338 // uncontrollably here. Being this a best effort deal we better go away.
339 __try {
340 *exit_now = (IDOK != ::MessageBoxW(NULL, text, caption, flags));
341 } __except(EXCEPTION_EXECUTE_HANDLER) {
342 // Its not safe to continue executing, exit silently here.
343 ::TerminateProcess(::GetCurrentProcess(),
344 GetCrashReporterClient()->GetResultCodeRespawnFailed());
347 return true;
350 // This function is executed by the child process that DumpDoneCallback()
351 // spawned and basically just shows the 'chrome has crashed' dialog if
352 // the CHROME_CRASHED environment variable is present.
353 bool ShowRestartDialogIfCrashed(bool* exit_now) {
354 // If we are being launched in metro mode don't try to show the dialog.
355 if (base::win::IsMetroProcess())
356 return false;
358 base::string16 message;
359 base::string16 title;
360 bool is_rtl_locale;
361 if (!GetCrashReporterClient()->ShouldShowRestartDialog(
362 &title, &message, &is_rtl_locale)) {
363 return false;
366 // If the UI layout is right-to-left, we need to pass the appropriate MB_XXX
367 // flags so that an RTL message box is displayed.
368 UINT flags = MB_OKCANCEL | MB_ICONWARNING;
369 if (is_rtl_locale)
370 flags |= MB_RIGHT | MB_RTLREADING;
372 return WrapMessageBoxWithSEH(message.c_str(), title.c_str(), flags, exit_now);
375 extern "C" void __declspec(dllexport) TerminateProcessWithoutDump() {
376 // Patched stub exists based on conditions (See InitCrashReporter).
377 // As a side note this function also gets called from
378 // WindowProcExceptionFilter.
379 if (g_real_terminate_process_stub == NULL) {
380 ::TerminateProcess(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
381 } else {
382 NtTerminateProcessPtr real_terminate_proc =
383 reinterpret_cast<NtTerminateProcessPtr>(
384 static_cast<char*>(g_real_terminate_process_stub));
385 real_terminate_proc(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
389 // Crashes the process after generating a dump for the provided exception. Note
390 // that the crash reporter should be initialized before calling this function
391 // for it to do anything.
392 // NOTE: This function is used by SyzyASAN to invoke a crash. If you change the
393 // the name or signature of this function you will break SyzyASAN instrumented
394 // releases of Chrome. Please contact syzygy-team@chromium.org before doing so!
395 extern "C" int __declspec(dllexport) CrashForException(
396 EXCEPTION_POINTERS* info) {
397 if (g_breakpad) {
398 g_breakpad->WriteMinidumpForException(info);
399 TerminateProcessWithoutDump();
401 return EXCEPTION_CONTINUE_SEARCH;
404 #ifndef _WIN64
405 static NTSTATUS WINAPI HookNtTerminateProcess(HANDLE ProcessHandle,
406 NTSTATUS ExitStatus) {
407 if (g_breakpad &&
408 (ProcessHandle == ::GetCurrentProcess() || ProcessHandle == NULL)) {
409 NT_TIB* tib = reinterpret_cast<NT_TIB*>(NtCurrentTeb());
410 void* address_on_stack = _AddressOfReturnAddress();
411 if (address_on_stack < tib->StackLimit ||
412 address_on_stack > tib->StackBase) {
413 g_surrogate_exception_record.ExceptionAddress = _ReturnAddress();
414 g_surrogate_exception_record.ExceptionCode = DBG_TERMINATE_PROCESS;
415 g_surrogate_exception_record.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
416 CrashForException(&g_surrogate_exception_pointers);
420 NtTerminateProcessPtr real_proc =
421 reinterpret_cast<NtTerminateProcessPtr>(
422 static_cast<char*>(g_real_terminate_process_stub));
423 return real_proc(ProcessHandle, ExitStatus);
426 static void InitTerminateProcessHooks() {
427 NtTerminateProcessPtr terminate_process_func_address =
428 reinterpret_cast<NtTerminateProcessPtr>(::GetProcAddress(
429 ::GetModuleHandle(L"ntdll.dll"), "NtTerminateProcess"));
430 if (terminate_process_func_address == NULL)
431 return;
433 DWORD old_protect = 0;
434 if (!::VirtualProtect(terminate_process_func_address, 5,
435 PAGE_EXECUTE_READWRITE, &old_protect))
436 return;
438 g_real_terminate_process_stub = reinterpret_cast<char*>(VirtualAllocEx(
439 ::GetCurrentProcess(), NULL, sidestep::kMaxPreambleStubSize,
440 MEM_COMMIT, PAGE_EXECUTE_READWRITE));
441 if (g_real_terminate_process_stub == NULL)
442 return;
444 g_surrogate_exception_pointers.ContextRecord = &g_surrogate_context;
445 g_surrogate_exception_pointers.ExceptionRecord =
446 &g_surrogate_exception_record;
448 sidestep::SideStepError patch_result =
449 sidestep::PreamblePatcher::Patch(
450 terminate_process_func_address, HookNtTerminateProcess,
451 g_real_terminate_process_stub, sidestep::kMaxPreambleStubSize);
452 if (patch_result != sidestep::SIDESTEP_SUCCESS) {
453 CHECK(::VirtualFreeEx(::GetCurrentProcess(), g_real_terminate_process_stub,
454 0, MEM_RELEASE));
455 CHECK(::VirtualProtect(terminate_process_func_address, 5, old_protect,
456 &old_protect));
457 return;
460 DWORD dummy = 0;
461 CHECK(::VirtualProtect(terminate_process_func_address,
463 old_protect,
464 &dummy));
465 CHECK(::VirtualProtect(g_real_terminate_process_stub,
466 sidestep::kMaxPreambleStubSize,
467 old_protect,
468 &old_protect));
470 #endif
472 static void InitPipeNameEnvVar(bool is_per_user_install) {
473 scoped_ptr<base::Environment> env(base::Environment::Create());
474 if (env->HasVar(kPipeNameVar)) {
475 // The Breakpad pipe name is already configured: nothing to do.
476 return;
479 // Check whether configuration management controls crash reporting.
480 bool crash_reporting_enabled = true;
481 bool controlled_by_policy =
482 GetCrashReporterClient()->ReportingIsEnforcedByPolicy(
483 &crash_reporting_enabled);
485 const base::CommandLine& command = *base::CommandLine::ForCurrentProcess();
486 bool use_crash_service = !controlled_by_policy &&
487 (command.HasSwitch(switches::kNoErrorDialogs) ||
488 GetCrashReporterClient()->IsRunningUnattended());
490 std::wstring pipe_name;
491 if (use_crash_service) {
492 // Crash reporting is done by crash_service.exe.
493 pipe_name = kChromePipeName;
494 } else {
495 // We want to use the Google Update crash reporting. We need to check if the
496 // user allows it first (in case the administrator didn't already decide
497 // via policy).
498 if (!controlled_by_policy)
499 crash_reporting_enabled =
500 GetCrashReporterClient()->GetCollectStatsConsent();
502 if (!crash_reporting_enabled) {
503 // Crash reporting is disabled, don't set the environment variable.
504 return;
507 // Build the pipe name. It can be either:
508 // System-wide install: "NamedPipe\GoogleCrashServices\S-1-5-18"
509 // Per-user install: "NamedPipe\GoogleCrashServices\<user SID>"
510 std::wstring user_sid;
511 if (is_per_user_install) {
512 if (!base::win::GetUserSidString(&user_sid)) {
513 return;
515 } else {
516 user_sid = kSystemPrincipalSid;
519 pipe_name = kGoogleUpdatePipeName;
520 pipe_name += user_sid;
522 env->SetVar(kPipeNameVar, base::UTF16ToASCII(pipe_name));
525 void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter) {
526 previous_filter = SetUnhandledExceptionFilter(filter);
529 void InitCrashReporter(const std::string& process_type_switch) {
530 const base::CommandLine& command = *base::CommandLine::ForCurrentProcess();
531 if (command.HasSwitch(switches::kDisableBreakpad))
532 return;
534 // Disable the message box for assertions.
535 _CrtSetReportMode(_CRT_ASSERT, 0);
537 base::string16 process_type = base::ASCIIToUTF16(process_type_switch);
538 if (process_type.empty())
539 process_type = L"browser";
541 wchar_t exe_path[MAX_PATH];
542 exe_path[0] = 0;
543 GetModuleFileNameW(NULL, exe_path, MAX_PATH);
545 bool is_per_user_install =
546 GetCrashReporterClient()->GetIsPerUserInstall(base::FilePath(exe_path));
548 // This is intentionally leaked.
549 CrashKeysWin* keeper = new CrashKeysWin();
551 google_breakpad::CustomClientInfo* custom_info =
552 keeper->GetCustomInfo(exe_path, process_type, GetProfileType(),
553 base::CommandLine::ForCurrentProcess(),
554 GetCrashReporterClient());
556 #if !defined(COMPONENT_BUILD)
557 // chrome/common/child_process_logging_win.cc registers crash keys for
558 // chrome.dll. In a component build, that is sufficient as chrome.dll and
559 // chrome.exe share a copy of base (in base.dll).
560 // In a static build, the EXE must separately initialize the crash keys
561 // configuration as it has its own statically linked copy of base.
562 base::debug::SetCrashKeyReportingFunctions(&SetCrashKeyValueForBaseDebug,
563 &ClearCrashKeyForBaseDebug);
564 GetCrashReporterClient()->RegisterCrashKeys();
565 #endif
567 google_breakpad::ExceptionHandler::MinidumpCallback callback = NULL;
568 LPTOP_LEVEL_EXCEPTION_FILTER default_filter = NULL;
569 // We install the post-dump callback only for the browser and service
570 // processes. It spawns a new browser/service process.
571 if (process_type == L"browser") {
572 callback = &DumpDoneCallback;
573 default_filter = &ChromeExceptionFilter;
574 } else if (process_type == L"service") {
575 callback = &DumpDoneCallback;
576 default_filter = &ServiceExceptionFilter;
579 if (process_type == L"browser") {
580 InitPipeNameEnvVar(is_per_user_install);
581 GetCrashReporterClient()->InitBrowserCrashDumpsRegKey();
584 scoped_ptr<base::Environment> env(base::Environment::Create());
585 std::string pipe_name_ascii;
586 if (!env->GetVar(kPipeNameVar, &pipe_name_ascii)) {
587 // Breakpad is not enabled. Configuration is managed or the user
588 // did not allow Google Update to send crashes. We need to use
589 // our default crash handler instead, but only for the
590 // browser/service processes.
591 if (default_filter)
592 InitDefaultCrashCallback(default_filter);
593 return;
595 base::string16 pipe_name = base::ASCIIToUTF16(pipe_name_ascii);
597 #ifdef _WIN64
598 // The protocol for connecting to the out-of-process Breakpad crash
599 // reporter is different for x86-32 and x86-64: the message sizes
600 // are different because the message struct contains a pointer. As
601 // a result, there are two different named pipes to connect to. The
602 // 64-bit one is distinguished with an "-x64" suffix.
603 pipe_name += L"-x64";
604 #endif
606 // Get the alternate dump directory. We use the temp path.
607 wchar_t temp_dir[MAX_PATH] = {0};
608 ::GetTempPathW(MAX_PATH, temp_dir);
610 MINIDUMP_TYPE dump_type = kSmallDumpType;
611 // Capture full memory if explicitly instructed to.
612 if (command.HasSwitch(switches::kFullMemoryCrashReport))
613 dump_type = kFullDumpType;
614 else if (GetCrashReporterClient()->GetShouldDumpLargerDumps(
615 is_per_user_install))
616 dump_type = kLargerDumpType;
618 g_breakpad = new google_breakpad::ExceptionHandler(temp_dir, &FilterCallback,
619 callback, NULL,
620 google_breakpad::ExceptionHandler::HANDLER_ALL,
621 dump_type, pipe_name.c_str(), custom_info);
623 // Now initialize the non crash dump handler.
624 g_dumphandler_no_crash = new google_breakpad::ExceptionHandler(temp_dir,
625 &FilterCallbackWhenNoCrash,
626 &DumpDoneCallbackWhenNoCrash,
627 NULL,
628 // Set the handler to none so this handler would not be added to
629 // |handler_stack_| in |ExceptionHandler| which is a list of exception
630 // handlers.
631 google_breakpad::ExceptionHandler::HANDLER_NONE,
632 dump_type, pipe_name.c_str(), custom_info);
634 // Set the DumpWithoutCrashingFunction for this instance of base.lib. Other
635 // executable images linked with base should set this again for
636 // DumpWithoutCrashing to function correctly.
637 // See chrome_main.cc for example.
638 base::debug::SetDumpWithoutCrashingFunction(&DumpProcessWithoutCrash);
640 if (g_breakpad->IsOutOfProcess()) {
641 // Tells breakpad to handle breakpoint and single step exceptions.
642 // This might break JIT debuggers, but at least it will always
643 // generate a crashdump for these exceptions.
644 g_breakpad->set_handle_debug_exceptions(true);
646 #ifndef _WIN64
647 if (process_type != L"browser" &&
648 !GetCrashReporterClient()->IsRunningUnattended()) {
649 // Initialize the hook TerminateProcess to catch unexpected exits.
650 InitTerminateProcessHooks();
652 #endif
656 void ConsumeInvalidHandleExceptions() {
657 if (g_breakpad) {
658 g_breakpad->set_consume_invalid_handle_exceptions(true);
660 if (g_dumphandler_no_crash) {
661 g_dumphandler_no_crash->set_consume_invalid_handle_exceptions(true);
665 // If the user has disabled crash reporting uploads and restarted Chrome, the
666 // restarted instance will still contain the pipe environment variable, which
667 // will allow the restarted process to still upload crash reports. This function
668 // clears the environment variable, so that the restarted Chrome, which inherits
669 // its environment from the current Chrome, will no longer contain the variable.
670 extern "C" void __declspec(dllexport) __cdecl
671 ClearBreakpadPipeEnvironmentVariable() {
672 scoped_ptr<base::Environment> env(base::Environment::Create());
673 env->UnSetVar(kPipeNameVar);
676 #ifdef _WIN64
677 int CrashForExceptionInNonABICompliantCodeRange(
678 PEXCEPTION_RECORD ExceptionRecord,
679 ULONG64 EstablisherFrame,
680 PCONTEXT ContextRecord,
681 PDISPATCHER_CONTEXT DispatcherContext) {
682 EXCEPTION_POINTERS info = { ExceptionRecord, ContextRecord };
683 return CrashForException(&info);
686 struct ExceptionHandlerRecord {
687 RUNTIME_FUNCTION runtime_function;
688 UNWIND_INFO unwind_info;
689 unsigned char thunk[12];
692 extern "C" void __declspec(dllexport) __cdecl
693 RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) {
694 ExceptionHandlerRecord* record =
695 reinterpret_cast<ExceptionHandlerRecord*>(start);
697 // We assume that the first page of the code range is executable and
698 // committed and reserved for breakpad. What could possibly go wrong?
700 // All addresses are 32bit relative offsets to start.
701 record->runtime_function.BeginAddress = 0;
702 record->runtime_function.EndAddress =
703 base::checked_cast<DWORD>(size_in_bytes);
704 record->runtime_function.UnwindData =
705 offsetof(ExceptionHandlerRecord, unwind_info);
707 // Create unwind info that only specifies an exception handler.
708 record->unwind_info.Version = 1;
709 record->unwind_info.Flags = UNW_FLAG_EHANDLER;
710 record->unwind_info.SizeOfProlog = 0;
711 record->unwind_info.CountOfCodes = 0;
712 record->unwind_info.FrameRegister = 0;
713 record->unwind_info.FrameOffset = 0;
714 record->unwind_info.ExceptionHandler =
715 offsetof(ExceptionHandlerRecord, thunk);
717 // Hardcoded thunk.
718 // mov imm64, rax
719 record->thunk[0] = 0x48;
720 record->thunk[1] = 0xb8;
721 void* handler = &CrashForExceptionInNonABICompliantCodeRange;
722 memcpy(&record->thunk[2], &handler, 8);
724 // jmp rax
725 record->thunk[10] = 0xff;
726 record->thunk[11] = 0xe0;
728 // Protect reserved page against modifications.
729 DWORD old_protect;
730 CHECK(VirtualProtect(
731 start, sizeof(ExceptionHandlerRecord), PAGE_EXECUTE_READ, &old_protect));
732 CHECK(RtlAddFunctionTable(
733 &record->runtime_function, 1, reinterpret_cast<DWORD64>(start)));
736 extern "C" void __declspec(dllexport) __cdecl
737 UnregisterNonABICompliantCodeRange(void* start) {
738 ExceptionHandlerRecord* record =
739 reinterpret_cast<ExceptionHandlerRecord*>(start);
741 CHECK(RtlDeleteFunctionTable(&record->runtime_function));
743 #endif
745 } // namespace breakpad