Chromium Code Reviews| 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..3e3c5611a54d39f1535513f27fc39476875abce9 |
| --- /dev/null |
| +++ b/components/crash/content/app/crashpad_win.cc |
| @@ -0,0 +1,147 @@ |
| +// 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/memory/scoped_ptr.h" |
| +#include "base/path_service.h" |
| +#include "base/strings/string16.h" |
| +#include "base/strings/utf_string_conversions.h" |
| +#include "components/crash/content/app/crash_reporter_client.h" |
| +#include "third_party/crashpad/crashpad/client/crashpad_client.h" |
| + |
| +namespace crash_reporter { |
| +namespace internal { |
| + |
| +base::FilePath PlatformCrashpadInitialization(bool initial_client, |
| + bool browser_process) { |
| + base::FilePath database_path; // Only valid in the browser process. |
| + crashpad::CrashpadClient crashpad_client; |
| + bool result; |
| + |
| + static 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); |
| +#if defined(ARCH_CPU_X86) |
| + process_annotations["plat"] = std::string("Win32"); |
| +#else |
| + process_annotations["plat"] = std::string("Win64"); |
| +#endif |
| + std::string url = "https://clients2.google.com/cr/report"; |
| + |
| + std::vector<std::string> arguments; |
| + arguments.push_back("--crashpad_handler"); |
| + |
| + result = crashpad_client.StartHandler(exe_file, database_path, url, |
| + process_annotations, arguments, true); |
| + |
| + // If we're the browser, push the pipe name into the environment so child |
| + // processes can connect to it. |
| + DCHECK(!env->HasVar(kPipeNameVar)); |
| + env->SetVar(kPipeNameVar, |
| + base::UTF16ToUTF8(crashpad_client.GetHandlerIPCPipe())); |
| + } else { |
| + std::string pipe_name_utf8; |
| + result = env->GetVar(kPipeNameVar, &pipe_name_utf8); |
| + if (result) { |
| + result = |
| + crashpad_client.SetHandlerIPCPipe(base::UTF8ToUTF16(pipe_name_utf8)); |
| + } |
| + } |
| + |
| + if (result) { |
| + result = crashpad_client.UseHandler(); |
| + CHECK(result); |
| + } |
| + |
| + return database_path; |
| +} |
| + |
| +#ifdef _WIN64 |
|
scottmg
2015/11/07 00:39:43
This is mostly unchanged from breakpad integration
|
| +int CrashForExceptionInNonABICompliantCodeRange( |
| + PEXCEPTION_RECORD ExceptionRecord, |
| + ULONG64 EstablisherFrame, |
| + PCONTEXT ContextRecord, |
| + PDISPATCHER_CONTEXT DispatcherContext) { |
| + EXCEPTION_POINTERS info = { ExceptionRecord, ContextRecord }; |
| + return CrashForException(&info); |
| +} |
| + |
| +struct ExceptionHandlerRecord { |
| + RUNTIME_FUNCTION runtime_function; |
| + UNWIND_INFO unwind_info; |
| + unsigned char thunk[12]; |
| +}; |
| + |
| +// These are GetProcAddress()d from V8 binding code. |
| +extern "C" 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))); |
| +} |
| + |
| +extern "C" void __declspec(dllexport) __cdecl |
| +UnregisterNonABICompliantCodeRange(void* start) { |
| + ExceptionHandlerRecord* record = |
| + reinterpret_cast<ExceptionHandlerRecord*>(start); |
| + |
| + CHECK(RtlDeleteFunctionTable(&record->runtime_function)); |
| +} |
| +#endif |
| + |
| +} // namespace internal |
| +} // namespace crash_reporter |