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