| Index: components/crash/content/app/crashpad_win.cc
|
| diff --git a/components/crash/content/app/crashpad_win.cc b/components/crash/content/app/crashpad_win.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..684366e88e5d81a0e363a9303cc76d9f60bf4921
|
| --- /dev/null
|
| +++ b/components/crash/content/app/crashpad_win.cc
|
| @@ -0,0 +1,202 @@
|
| +// Copyright 2015 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/crashpad.h"
|
| +
|
| +#include "base/environment.h"
|
| +#include "base/lazy_instance.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/numerics/safe_conversions.h"
|
| +#include "base/path_service.h"
|
| +#include "base/strings/string16.h"
|
| +#include "base/strings/string_number_conversions.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "build/build_config.h"
|
| +#include "components/crash/content/app/crash_reporter_client.h"
|
| +#include "third_party/crashpad/crashpad/client/crashpad_client.h"
|
| +#include "third_party/crashpad/crashpad/client/crashpad_info.h"
|
| +
|
| +namespace crash_reporter {
|
| +namespace internal {
|
| +
|
| +namespace {
|
| +
|
| +base::LazyInstance<crashpad::CrashpadClient>::Leaky g_crashpad_client =
|
| + LAZY_INSTANCE_INITIALIZER;
|
| +
|
| +} // namespace
|
| +
|
| +base::FilePath PlatformCrashpadInitialization(bool initial_client,
|
| + bool browser_process) {
|
| + base::FilePath database_path; // Only valid in the browser process.
|
| + bool result;
|
| +
|
| + const char kPipeNameVar[] = "CHROME_CRASHPAD_PIPE_NAME";
|
| + scoped_ptr<base::Environment> env(base::Environment::Create());
|
| +
|
| + DCHECK_EQ(initial_client, browser_process);
|
| +
|
| + if (initial_client) {
|
| + CrashReporterClient* crash_reporter_client = GetCrashReporterClient();
|
| + crash_reporter_client->GetCrashDumpLocation(&database_path);
|
| +
|
| + base::FilePath exe_file;
|
| + CHECK(PathService::Get(base::FILE_EXE, &exe_file));
|
| + base::string16 product_name, version, special_build, channel_name;
|
| + crash_reporter_client->GetProductNameAndVersion(
|
| + exe_file, &product_name, &version, &special_build, &channel_name);
|
| + std::map<std::string, std::string> process_annotations;
|
| + process_annotations["prod"] = base::UTF16ToUTF8(product_name);
|
| + process_annotations["ver"] = base::UTF16ToUTF8(version);
|
| + process_annotations["channel"] = base::UTF16ToUTF8(channel_name);
|
| + if (!special_build.empty())
|
| + process_annotations["special"] = base::UTF16ToUTF8(special_build);
|
| +#if defined(ARCH_CPU_X86)
|
| + process_annotations["plat"] = std::string("Win32");
|
| +#elif defined(ARCH_CPU_X86_64)
|
| + process_annotations["plat"] = std::string("Win64");
|
| +#endif
|
| +#if defined(GOOGLE_CHROME_BUILD)
|
| + std::string url = "https://clients2.google.com/cr/report";
|
| +#else
|
| + std::string url;
|
| +#endif
|
| +
|
| + std::vector<std::string> arguments;
|
| +
|
| + // In test binaries, use crashpad_handler directly. Otherwise, we launch
|
| + // chrome.exe with --type=crashpad-handler.
|
| + if (exe_file.BaseName().value() != FILE_PATH_LITERAL("chrome.exe")) {
|
| + base::FilePath exe_dir;
|
| + CHECK(PathService::Get(base::DIR_EXE, &exe_dir));
|
| + exe_file = exe_dir.Append(FILE_PATH_LITERAL("crashpad_handler.exe"));
|
| + } else {
|
| + arguments.push_back("--type=crashpad-handler");
|
| + }
|
| +
|
| + result = g_crashpad_client.Get().StartHandler(
|
| + exe_file, database_path, url, process_annotations, arguments, false);
|
| +
|
| + // If we're the browser, push the pipe name into the environment so child
|
| + // processes can connect to it. If we inherited another crashpad_handler's
|
| + // pipe name, we'll overwrite it here.
|
| + env->SetVar(kPipeNameVar,
|
| + base::UTF16ToUTF8(g_crashpad_client.Get().GetHandlerIPCPipe()));
|
| + } else {
|
| + std::string pipe_name_utf8;
|
| + result = env->GetVar(kPipeNameVar, &pipe_name_utf8);
|
| + if (result) {
|
| + result = g_crashpad_client.Get().SetHandlerIPCPipe(
|
| + base::UTF8ToUTF16(pipe_name_utf8));
|
| + }
|
| + }
|
| +
|
| + if (result) {
|
| + result = g_crashpad_client.Get().UseHandler();
|
| + }
|
| +
|
| + return database_path;
|
| +}
|
| +
|
| +extern "C" {
|
| +
|
| +// Crashes the process after generating a dump for the provided exception. Note
|
| +// that the crash reporter should be initialized before calling this function
|
| +// for it to do anything.
|
| +// NOTE: This function is used by SyzyASAN to invoke a crash. If you change the
|
| +// the name or signature of this function you will break SyzyASAN instrumented
|
| +// releases of Chrome. Please contact syzygy-team@chromium.org before doing so!
|
| +int __declspec(dllexport) CrashForException(
|
| + EXCEPTION_POINTERS* info) {
|
| + g_crashpad_client.Get().DumpAndCrash(info);
|
| + return EXCEPTION_CONTINUE_SEARCH;
|
| +}
|
| +
|
| +#if defined(ARCH_CPU_X86_64)
|
| +
|
| +static int CrashForExceptionInNonABICompliantCodeRange(
|
| + PEXCEPTION_RECORD ExceptionRecord,
|
| + ULONG64 EstablisherFrame,
|
| + PCONTEXT ContextRecord,
|
| + PDISPATCHER_CONTEXT DispatcherContext) {
|
| + EXCEPTION_POINTERS info = { ExceptionRecord, ContextRecord };
|
| + return CrashForException(&info);
|
| +}
|
| +
|
| +// See https://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
|
| +typedef struct _UNWIND_INFO {
|
| + unsigned char Version : 3;
|
| + unsigned char Flags : 5;
|
| + unsigned char SizeOfProlog;
|
| + unsigned char CountOfCodes;
|
| + unsigned char FrameRegister : 4;
|
| + unsigned char FrameOffset : 4;
|
| + ULONG ExceptionHandler;
|
| +} UNWIND_INFO, *PUNWIND_INFO;
|
| +
|
| +struct ExceptionHandlerRecord {
|
| + RUNTIME_FUNCTION runtime_function;
|
| + UNWIND_INFO unwind_info;
|
| + unsigned char thunk[12];
|
| +};
|
| +
|
| +// These are GetProcAddress()d from V8 binding code.
|
| +void __declspec(dllexport) __cdecl RegisterNonABICompliantCodeRange(
|
| + void* start,
|
| + size_t size_in_bytes) {
|
| + ExceptionHandlerRecord* record =
|
| + reinterpret_cast<ExceptionHandlerRecord*>(start);
|
| +
|
| + // We assume that the first page of the code range is executable and
|
| + // committed and reserved for breakpad. What could possibly go wrong?
|
| +
|
| + // All addresses are 32bit relative offsets to start.
|
| + record->runtime_function.BeginAddress = 0;
|
| + record->runtime_function.EndAddress =
|
| + base::checked_cast<DWORD>(size_in_bytes);
|
| + record->runtime_function.UnwindData =
|
| + offsetof(ExceptionHandlerRecord, unwind_info);
|
| +
|
| + // Create unwind info that only specifies an exception handler.
|
| + record->unwind_info.Version = 1;
|
| + record->unwind_info.Flags = UNW_FLAG_EHANDLER;
|
| + record->unwind_info.SizeOfProlog = 0;
|
| + record->unwind_info.CountOfCodes = 0;
|
| + record->unwind_info.FrameRegister = 0;
|
| + record->unwind_info.FrameOffset = 0;
|
| + record->unwind_info.ExceptionHandler =
|
| + offsetof(ExceptionHandlerRecord, thunk);
|
| +
|
| + // Hardcoded thunk.
|
| + // mov imm64, rax
|
| + record->thunk[0] = 0x48;
|
| + record->thunk[1] = 0xb8;
|
| + void* handler = &CrashForExceptionInNonABICompliantCodeRange;
|
| + memcpy(&record->thunk[2], &handler, 8);
|
| +
|
| + // jmp rax
|
| + record->thunk[10] = 0xff;
|
| + record->thunk[11] = 0xe0;
|
| +
|
| + // Protect reserved page against modifications.
|
| + DWORD old_protect;
|
| + CHECK(VirtualProtect(
|
| + start, sizeof(ExceptionHandlerRecord), PAGE_EXECUTE_READ, &old_protect));
|
| + CHECK(RtlAddFunctionTable(
|
| + &record->runtime_function, 1, reinterpret_cast<DWORD64>(start)));
|
| +}
|
| +
|
| +void __declspec(dllexport) __cdecl UnregisterNonABICompliantCodeRange(
|
| + void* start) {
|
| + ExceptionHandlerRecord* record =
|
| + reinterpret_cast<ExceptionHandlerRecord*>(start);
|
| +
|
| + CHECK(RtlDeleteFunctionTable(&record->runtime_function));
|
| +}
|
| +#endif // ARCH_CPU_X86_64
|
| +
|
| +} // extern "C"
|
| +
|
| +} // namespace internal
|
| +} // namespace crash_reporter
|
|
|