Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 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. | |
| 4 | |
| 5 #include "components/crash/content/app/crashpad.h" | |
| 6 | |
| 7 #include "base/environment.h" | |
| 8 #include "base/lazy_instance.h" | |
| 9 #include "base/memory/scoped_ptr.h" | |
| 10 #include "base/numerics/safe_conversions.h" | |
| 11 #include "base/path_service.h" | |
| 12 #include "base/strings/string16.h" | |
| 13 #include "base/strings/utf_string_conversions.h" | |
| 14 #include "components/crash/content/app/crash_reporter_client.h" | |
| 15 #include "third_party/crashpad/crashpad/client/crashpad_client.h" | |
| 16 | |
| 17 namespace crash_reporter { | |
| 18 namespace internal { | |
| 19 | |
| 20 base::LazyInstance<crashpad::CrashpadClient>::Leaky g_crashpad_client = | |
| 21 LAZY_INSTANCE_INITIALIZER; | |
| 22 | |
| 23 base::FilePath PlatformCrashpadInitialization(bool initial_client, | |
| 24 bool browser_process) { | |
| 25 base::FilePath database_path; // Only valid in the browser process. | |
| 26 bool result; | |
| 27 | |
| 28 static const char kPipeNameVar[] = "CHROME_CRASHPAD_PIPE_NAME"; | |
| 29 scoped_ptr<base::Environment> env(base::Environment::Create()); | |
| 30 | |
| 31 DCHECK_EQ(initial_client, browser_process); | |
| 32 | |
| 33 if (initial_client) { | |
| 34 CrashReporterClient* crash_reporter_client = GetCrashReporterClient(); | |
| 35 crash_reporter_client->GetCrashDumpLocation(&database_path); | |
| 36 | |
| 37 base::FilePath exe_file; | |
| 38 CHECK(PathService::Get(base::FILE_EXE, &exe_file)); | |
| 39 base::string16 product_name, version, special_build, channel_name; | |
| 40 crash_reporter_client->GetProductNameAndVersion( | |
| 41 exe_file, &product_name, &version, &special_build, &channel_name); | |
| 42 std::map<std::string, std::string> process_annotations; | |
| 43 process_annotations["prod"] = base::UTF16ToUTF8(product_name); | |
| 44 process_annotations["ver"] = base::UTF16ToUTF8(version); | |
| 45 #if defined(ARCH_CPU_X86) | |
| 46 process_annotations["plat"] = std::string("Win32"); | |
| 47 #else | |
| 48 process_annotations["plat"] = std::string("Win64"); | |
| 49 #endif | |
| 50 std::string url = "https://clients2.google.com/cr/report"; | |
| 51 | |
| 52 std::vector<std::string> arguments; | |
| 53 arguments.push_back("--crashpad_handler"); | |
| 54 | |
| 55 result = g_crashpad_client.Get().StartHandler( | |
| 56 exe_file, database_path, url, process_annotations, arguments, true); | |
| 57 | |
| 58 // If we're the browser, push the pipe name into the environment so child | |
| 59 // processes can connect to it. | |
| 60 DCHECK(!env->HasVar(kPipeNameVar)); | |
| 61 env->SetVar(kPipeNameVar, | |
| 62 base::UTF16ToUTF8(g_crashpad_client.Get().GetHandlerIPCPipe())); | |
| 63 } else { | |
| 64 std::string pipe_name_utf8; | |
| 65 result = env->GetVar(kPipeNameVar, &pipe_name_utf8); | |
| 66 if (result) { | |
| 67 result = g_crashpad_client.Get().SetHandlerIPCPipe( | |
| 68 base::UTF8ToUTF16(pipe_name_utf8)); | |
| 69 } | |
| 70 } | |
| 71 | |
| 72 if (result) { | |
| 73 result = g_crashpad_client.Get().UseHandler(); | |
| 74 CHECK(result); | |
| 75 } | |
| 76 | |
| 77 return database_path; | |
| 78 } | |
| 79 | |
| 80 // Crashes the process after generating a dump for the provided exception. Note | |
| 81 // that the crash reporter should be initialized before calling this function | |
| 82 // for it to do anything. | |
| 83 // NOTE: This function is used by SyzyASAN to invoke a crash. If you change the | |
| 84 // the name or signature of this function you will break SyzyASAN instrumented | |
| 85 // releases of Chrome. Please contact syzygy-team@chromium.org before doing so! | |
| 86 extern "C" int __declspec(dllexport) CrashForException( | |
| 87 EXCEPTION_POINTERS* info) { | |
| 88 g_crashpad_client.Get().DumpAndCrash(info); | |
| 89 return EXCEPTION_CONTINUE_SEARCH; | |
| 90 } | |
| 91 | |
| 92 #ifdef _WIN64 | |
| 93 int CrashForExceptionInNonABICompliantCodeRange( | |
| 94 PEXCEPTION_RECORD ExceptionRecord, | |
| 95 ULONG64 EstablisherFrame, | |
| 96 PCONTEXT ContextRecord, | |
| 97 PDISPATCHER_CONTEXT DispatcherContext) { | |
| 98 EXCEPTION_POINTERS info = { ExceptionRecord, ContextRecord }; | |
| 99 return CrashForException(&info); | |
| 100 } | |
| 101 | |
| 102 // See http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx | |
| 103 typedef struct _UNWIND_INFO { | |
| 104 unsigned char Version : 3; | |
| 105 unsigned char Flags : 5; | |
| 106 unsigned char SizeOfProlog; | |
| 107 unsigned char CountOfCodes; | |
| 108 unsigned char FrameRegister : 4; | |
| 109 unsigned char FrameOffset : 4; | |
| 110 ULONG ExceptionHandler; | |
| 111 } UNWIND_INFO, *PUNWIND_INFO; | |
| 112 | |
| 113 struct ExceptionHandlerRecord { | |
| 114 RUNTIME_FUNCTION runtime_function; | |
| 115 UNWIND_INFO unwind_info; | |
| 116 unsigned char thunk[12]; | |
| 117 }; | |
| 118 | |
| 119 // These are GetProcAddress()d from V8 binding code. | |
| 120 extern "C" void __declspec(dllexport) __cdecl | |
| 121 RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) { | |
| 122 ExceptionHandlerRecord* record = | |
| 123 reinterpret_cast<ExceptionHandlerRecord*>(start); | |
| 124 | |
| 125 // We assume that the first page of the code range is executable and | |
| 126 // committed and reserved for breakpad. What could possibly go wrong? | |
|
cpu_(ooo_6.6-7.5)
2015/11/07 01:53:18
love it.
| |
| 127 | |
| 128 // All addresses are 32bit relative offsets to start. | |
| 129 record->runtime_function.BeginAddress = 0; | |
| 130 record->runtime_function.EndAddress = | |
| 131 base::checked_cast<DWORD>(size_in_bytes); | |
| 132 record->runtime_function.UnwindData = | |
| 133 offsetof(ExceptionHandlerRecord, unwind_info); | |
| 134 | |
| 135 // Create unwind info that only specifies an exception handler. | |
| 136 record->unwind_info.Version = 1; | |
| 137 record->unwind_info.Flags = UNW_FLAG_EHANDLER; | |
| 138 record->unwind_info.SizeOfProlog = 0; | |
| 139 record->unwind_info.CountOfCodes = 0; | |
| 140 record->unwind_info.FrameRegister = 0; | |
| 141 record->unwind_info.FrameOffset = 0; | |
| 142 record->unwind_info.ExceptionHandler = | |
| 143 offsetof(ExceptionHandlerRecord, thunk); | |
| 144 | |
| 145 // Hardcoded thunk. | |
| 146 // mov imm64, rax | |
| 147 record->thunk[0] = 0x48; | |
| 148 record->thunk[1] = 0xb8; | |
| 149 void* handler = &CrashForExceptionInNonABICompliantCodeRange; | |
| 150 memcpy(&record->thunk[2], &handler, 8); | |
| 151 | |
| 152 // jmp rax | |
| 153 record->thunk[10] = 0xff; | |
| 154 record->thunk[11] = 0xe0; | |
| 155 | |
| 156 // Protect reserved page against modifications. | |
| 157 DWORD old_protect; | |
| 158 CHECK(VirtualProtect( | |
| 159 start, sizeof(ExceptionHandlerRecord), PAGE_EXECUTE_READ, &old_protect)); | |
| 160 CHECK(RtlAddFunctionTable( | |
| 161 &record->runtime_function, 1, reinterpret_cast<DWORD64>(start))); | |
| 162 } | |
| 163 | |
| 164 extern "C" void __declspec(dllexport) __cdecl | |
| 165 UnregisterNonABICompliantCodeRange(void* start) { | |
| 166 ExceptionHandlerRecord* record = | |
| 167 reinterpret_cast<ExceptionHandlerRecord*>(start); | |
| 168 | |
| 169 CHECK(RtlDeleteFunctionTable(&record->runtime_function)); | |
| 170 } | |
| 171 #endif | |
| 172 | |
| 173 } // namespace internal | |
| 174 } // namespace crash_reporter | |
| OLD | NEW |