| 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
 | 
| 
 |