| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/crash/content/app/fallback_crash_handling_win.h" |
| |
| #include <memory> |
| |
| #include "base/base_switches.h" |
| #include "base/command_line.h" |
| #include "base/logging.h" |
| #include "components/crash/content/app/crash_switches.h" |
| #include "components/crash/content/app/fallback_crash_handler_launcher_win.h" |
| #include "components/crash/content/app/fallback_crash_handler_win.h" |
| |
| namespace crash_reporter { |
| |
| namespace switches { |
| const char kFallbackCrashHandler[] = "fallback-handler"; |
| const char kPrefetchArgument[] = "/prefetch:7"; |
| } |
| |
| const uint32_t kFallbackCrashTerminationCode = 0xFFFF8001; |
| |
| namespace { |
| |
| std::unique_ptr<FallbackCrashHandlerLauncher> g_fallback_crash_handler_launcher; |
| |
| LONG WINAPI FallbackUnhandledExceptionFilter(EXCEPTION_POINTERS* exc_ptrs) { |
| if (!g_fallback_crash_handler_launcher) |
| return EXCEPTION_CONTINUE_SEARCH; |
| |
| return g_fallback_crash_handler_launcher->LaunchAndWaitForHandler(exc_ptrs); |
| } |
| |
| } // namespace |
| |
| bool SetupFallbackCrashHandling(const base::CommandLine& command_line) { |
| DCHECK(!g_fallback_crash_handler_launcher); |
| |
| // Run the same program. |
| base::CommandLine base_command_line(command_line.GetProgram()); |
| base_command_line.AppendSwitchASCII("type", switches::kFallbackCrashHandler); |
| |
| // This is to support testing under gtest. |
| if (command_line.HasSwitch(::switches::kTestChildProcess)) { |
| base_command_line.AppendSwitchASCII( |
| ::switches::kTestChildProcess, |
| command_line.GetSwitchValueASCII(::switches::kTestChildProcess)); |
| } |
| |
| // All Chrome processes need a prefetch argument. |
| base_command_line.AppendArg(switches::kPrefetchArgument); |
| |
| // Get the database path. |
| base::FilePath database_path = command_line.GetSwitchValuePath("database"); |
| if (database_path.empty()) { |
| NOTREACHED(); |
| return false; |
| } |
| |
| std::unique_ptr<FallbackCrashHandlerLauncher> fallback_launcher( |
| new FallbackCrashHandlerLauncher()); |
| |
| if (!fallback_launcher->Initialize(base_command_line, database_path)) { |
| NOTREACHED(); |
| return false; |
| } |
| |
| // This is necessary because chrome_elf stubs out the |
| // SetUnhandledExceptionFilter in the IAT of chrome.exe. |
| typedef PTOP_LEVEL_EXCEPTION_FILTER(WINAPI * |
| SetUnhandledExceptionFilterFunction)( |
| PTOP_LEVEL_EXCEPTION_FILTER filter); |
| HMODULE kernel32 = GetModuleHandle(L"kernel32.dll"); |
| if (!kernel32) |
| return false; |
| |
| SetUnhandledExceptionFilterFunction set_unhandled_exception_filter = |
| reinterpret_cast<SetUnhandledExceptionFilterFunction>( |
| GetProcAddress(kernel32, "SetUnhandledExceptionFilter")); |
| if (!set_unhandled_exception_filter) |
| return false; |
| |
| // Success, pass ownership to the global. |
| g_fallback_crash_handler_launcher = std::move(fallback_launcher); |
| |
| set_unhandled_exception_filter(&FallbackUnhandledExceptionFilter); |
| |
| return true; |
| } |
| |
| int RunAsFallbackCrashHandler(const base::CommandLine& command_line, |
| std::string product_name, |
| std::string version, |
| std::string channel_name) { |
| FallbackCrashHandler fallback_handler; |
| |
| if (!fallback_handler.ParseCommandLine(command_line)) { |
| // TODO(siggi): Figure out how to UMA from this process, if need be. |
| return 1; |
| } |
| |
| if (!fallback_handler.GenerateCrashDump( |
| product_name, version, channel_name, |
| crash_reporter::switches::kCrashpadHandler)) { |
| // TODO(siggi): Figure out how to UMA from this process, if need be. |
| return 2; |
| } |
| |
| if (!fallback_handler.process().Terminate(kFallbackCrashTerminationCode, |
| false)) { |
| return 3; |
| } |
| |
| return 0; |
| } |
| |
| } // namespace crash_reporter |