OLD | NEW |
1 // Copyright 2014 The Crashpad Authors. All rights reserved. | 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
52 #include "handler/mac/exception_handler_server.h" | 52 #include "handler/mac/exception_handler_server.h" |
53 #include "util/mach/child_port_handshake.h" | 53 #include "util/mach/child_port_handshake.h" |
54 #include "util/mach/mach_extensions.h" | 54 #include "util/mach/mach_extensions.h" |
55 #include "util/posix/close_stdio.h" | 55 #include "util/posix/close_stdio.h" |
56 #elif defined(OS_WIN) | 56 #elif defined(OS_WIN) |
57 #include <windows.h> | 57 #include <windows.h> |
58 | 58 |
59 #include "handler/win/crash_report_exception_handler.h" | 59 #include "handler/win/crash_report_exception_handler.h" |
60 #include "util/win/exception_handler_server.h" | 60 #include "util/win/exception_handler_server.h" |
61 #include "util/win/handle.h" | 61 #include "util/win/handle.h" |
| 62 #include "util/win/initial_client_data.h" |
62 #endif // OS_MACOSX | 63 #endif // OS_MACOSX |
63 | 64 |
64 namespace crashpad { | 65 namespace crashpad { |
65 | 66 |
66 namespace { | 67 namespace { |
67 | 68 |
68 void Usage(const base::FilePath& me) { | 69 void Usage(const base::FilePath& me) { |
69 fprintf(stderr, | 70 fprintf(stderr, |
70 "Usage: %" PRFilePath " [OPTION]...\n" | 71 "Usage: %" PRFilePath " [OPTION]...\n" |
71 "Crashpad's exception handler server.\n" | 72 "Crashpad's exception handler server.\n" |
72 "\n" | 73 "\n" |
73 " --annotation=KEY=VALUE set a process annotation in each crash report\n" | 74 " --annotation=KEY=VALUE set a process annotation in each crash report\n" |
74 " --database=PATH store the crash report database at PATH\n" | 75 " --database=PATH store the crash report database at PATH\n" |
75 #if defined(OS_MACOSX) | 76 #if defined(OS_MACOSX) |
76 " --handshake-fd=FD establish communication with the client over FD\n
" | 77 " --handshake-fd=FD establish communication with the client over FD\n
" |
77 " --mach-service=SERVICE register SERVICE with the bootstrap server\n" | 78 " --mach-service=SERVICE register SERVICE with the bootstrap server\n" |
78 #elif defined(OS_WIN) | 79 #elif defined(OS_WIN) |
79 " --handshake-handle=HANDLE\n" | 80 " --initial-client-data=HANDLE_request_crash_dump,\n" |
80 " create a new pipe and send its name via HANDLE\n" | 81 " HANDLE_request_non_crash_dump,\n" |
| 82 " HANDLE_non_crash_dump_completed,\n" |
| 83 " HANDLE_pipe,\n" |
| 84 " HANDLE_client_process,\n" |
| 85 " Address_crash_exception_information,\n" |
| 86 " Address_non_crash_exception_information,\n" |
| 87 " Address_debug_critical_section\n" |
| 88 " use precreated data to register initial client\n" |
81 #endif // OS_MACOSX | 89 #endif // OS_MACOSX |
82 " --metrics-dir=DIR store metrics files in DIR (only in Chromium)\n" | 90 " --metrics-dir=DIR store metrics files in DIR (only in Chromium)\n" |
83 " --no-rate-limit don't rate limit crash uploads\n" | 91 " --no-rate-limit don't rate limit crash uploads\n" |
84 #if defined(OS_MACOSX) | 92 #if defined(OS_MACOSX) |
85 " --reset-own-crash-exception-port-to-system-default\n" | 93 " --reset-own-crash-exception-port-to-system-default\n" |
86 " reset the server's exception handler to default\n
" | 94 " reset the server's exception handler to default\n
" |
87 #elif defined(OS_WIN) | 95 #elif defined(OS_WIN) |
88 " --pipe-name=PIPE communicate with the client over PIPE\n" | 96 " --pipe-name=PIPE communicate with the client over PIPE\n" |
89 #endif // OS_MACOSX | 97 #endif // OS_MACOSX |
90 " --url=URL send crash reports to this Breakpad server URL,\n
" | 98 " --url=URL send crash reports to this Breakpad server URL,\n
" |
(...skipping 27 matching lines...) Expand all Loading... |
118 g_exception_handler_server->Stop(); | 126 g_exception_handler_server->Stop(); |
119 } | 127 } |
120 | 128 |
121 #endif // OS_MACOSX | 129 #endif // OS_MACOSX |
122 | 130 |
123 #if defined(OS_WIN) | 131 #if defined(OS_WIN) |
124 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { | 132 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { |
125 Metrics::HandlerCrashed(exception_pointers->ExceptionRecord->ExceptionCode); | 133 Metrics::HandlerCrashed(exception_pointers->ExceptionRecord->ExceptionCode); |
126 return EXCEPTION_CONTINUE_SEARCH; | 134 return EXCEPTION_CONTINUE_SEARCH; |
127 } | 135 } |
128 #endif | 136 #endif // OS_WIN |
129 | 137 |
130 } // namespace | 138 } // namespace |
131 | 139 |
132 int HandlerMain(int argc, char* argv[]) { | 140 int HandlerMain(int argc, char* argv[]) { |
133 #if defined(OS_WIN) | 141 #if defined(OS_WIN) |
134 SetUnhandledExceptionFilter(&UnhandledExceptionHandler); | 142 SetUnhandledExceptionFilter(&UnhandledExceptionHandler); |
135 #endif | 143 #endif |
136 | 144 |
137 const base::FilePath argv0( | 145 const base::FilePath argv0( |
138 ToolSupport::CommandLineArgumentToFilePathStringType(argv[0])); | 146 ToolSupport::CommandLineArgumentToFilePathStringType(argv[0])); |
139 const base::FilePath me(argv0.BaseName()); | 147 const base::FilePath me(argv0.BaseName()); |
140 | 148 |
141 enum OptionFlags { | 149 enum OptionFlags { |
142 // Long options without short equivalents. | 150 // Long options without short equivalents. |
143 kOptionLastChar = 255, | 151 kOptionLastChar = 255, |
144 kOptionAnnotation, | 152 kOptionAnnotation, |
145 kOptionDatabase, | 153 kOptionDatabase, |
146 #if defined(OS_MACOSX) | 154 #if defined(OS_MACOSX) |
147 kOptionHandshakeFD, | 155 kOptionHandshakeFD, |
| 156 #endif // OS_MACOSX |
| 157 #if defined(OS_WIN) |
| 158 kOptionInitialClientData, |
| 159 #endif // OS_WIN |
| 160 #if defined(OS_MACOSX) |
148 kOptionMachService, | 161 kOptionMachService, |
149 #elif defined(OS_WIN) | |
150 kOptionHandshakeHandle, | |
151 #endif // OS_MACOSX | 162 #endif // OS_MACOSX |
152 kOptionMetrics, | 163 kOptionMetrics, |
153 kOptionNoRateLimit, | 164 kOptionNoRateLimit, |
154 #if defined(OS_MACOSX) | 165 #if defined(OS_MACOSX) |
155 kOptionResetOwnCrashExceptionPortToSystemDefault, | 166 kOptionResetOwnCrashExceptionPortToSystemDefault, |
156 #elif defined(OS_WIN) | 167 #elif defined(OS_WIN) |
157 kOptionPipeName, | 168 kOptionPipeName, |
158 #endif // OS_MACOSX | 169 #endif // OS_MACOSX |
159 kOptionURL, | 170 kOptionURL, |
160 | 171 |
161 // Standard options. | 172 // Standard options. |
162 kOptionHelp = -2, | 173 kOptionHelp = -2, |
163 kOptionVersion = -3, | 174 kOptionVersion = -3, |
164 }; | 175 }; |
165 | 176 |
166 struct { | 177 struct { |
167 std::map<std::string, std::string> annotations; | 178 std::map<std::string, std::string> annotations; |
168 std::string url; | 179 std::string url; |
169 const char* database; | 180 const char* database; |
170 const char* metrics; | 181 const char* metrics; |
171 #if defined(OS_MACOSX) | 182 #if defined(OS_MACOSX) |
172 int handshake_fd; | 183 int handshake_fd; |
173 std::string mach_service; | 184 std::string mach_service; |
174 bool reset_own_crash_exception_port_to_system_default; | 185 bool reset_own_crash_exception_port_to_system_default; |
175 #elif defined(OS_WIN) | 186 #elif defined(OS_WIN) |
176 HANDLE handshake_handle; | |
177 std::string pipe_name; | 187 std::string pipe_name; |
| 188 InitialClientData initial_client_data; |
178 #endif // OS_MACOSX | 189 #endif // OS_MACOSX |
179 bool rate_limit; | 190 bool rate_limit; |
180 } options = {}; | 191 } options = {}; |
181 #if defined(OS_MACOSX) | 192 #if defined(OS_MACOSX) |
182 options.handshake_fd = -1; | 193 options.handshake_fd = -1; |
183 #elif defined(OS_WIN) | |
184 options.handshake_handle = INVALID_HANDLE_VALUE; | |
185 #endif | 194 #endif |
186 options.rate_limit = true; | 195 options.rate_limit = true; |
187 | 196 |
188 const option long_options[] = { | 197 const option long_options[] = { |
189 {"annotation", required_argument, nullptr, kOptionAnnotation}, | 198 {"annotation", required_argument, nullptr, kOptionAnnotation}, |
190 {"database", required_argument, nullptr, kOptionDatabase}, | 199 {"database", required_argument, nullptr, kOptionDatabase}, |
191 #if defined(OS_MACOSX) | 200 #if defined(OS_MACOSX) |
192 {"handshake-fd", required_argument, nullptr, kOptionHandshakeFD}, | 201 {"handshake-fd", required_argument, nullptr, kOptionHandshakeFD}, |
193 {"mach-service", required_argument, nullptr, kOptionMachService}, | 202 #endif // OS_MACOSX |
| 203 #if defined(OS_WIN) |
| 204 {"initial-client-data", |
| 205 required_argument, |
| 206 nullptr, |
| 207 kOptionInitialClientData}, |
| 208 #endif // OS_MACOSX |
| 209 #if defined(OS_MACOSX) |
| 210 {"mach-service", required_argument, nullptr, kOptionMachService}, |
| 211 #endif // OS_MACOSX |
| 212 {"metrics-dir", required_argument, nullptr, kOptionMetrics}, |
| 213 {"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit}, |
| 214 #if defined(OS_MACOSX) |
| 215 {"reset-own-crash-exception-port-to-system-default", |
| 216 no_argument, |
| 217 nullptr, |
| 218 kOptionResetOwnCrashExceptionPortToSystemDefault}, |
194 #elif defined(OS_WIN) | 219 #elif defined(OS_WIN) |
195 {"handshake-handle", required_argument, nullptr, kOptionHandshakeHandle}, | 220 {"pipe-name", required_argument, nullptr, kOptionPipeName}, |
196 #endif // OS_MACOSX | 221 #endif // OS_MACOSX |
197 {"metrics-dir", required_argument, nullptr, kOptionMetrics}, | 222 {"url", required_argument, nullptr, kOptionURL}, |
198 {"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit}, | 223 {"help", no_argument, nullptr, kOptionHelp}, |
199 #if defined(OS_MACOSX) | 224 {"version", no_argument, nullptr, kOptionVersion}, |
200 {"reset-own-crash-exception-port-to-system-default", | 225 {nullptr, 0, nullptr, 0}, |
201 no_argument, | |
202 nullptr, | |
203 kOptionResetOwnCrashExceptionPortToSystemDefault}, | |
204 #elif defined(OS_WIN) | |
205 {"pipe-name", required_argument, nullptr, kOptionPipeName}, | |
206 #endif // OS_MACOSX | |
207 {"url", required_argument, nullptr, kOptionURL}, | |
208 {"help", no_argument, nullptr, kOptionHelp}, | |
209 {"version", no_argument, nullptr, kOptionVersion}, | |
210 {nullptr, 0, nullptr, 0}, | |
211 }; | 226 }; |
212 | 227 |
213 int opt; | 228 int opt; |
214 while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) { | 229 while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) { |
215 switch (opt) { | 230 switch (opt) { |
216 case kOptionAnnotation: { | 231 case kOptionAnnotation: { |
217 std::string key; | 232 std::string key; |
218 std::string value; | 233 std::string value; |
219 if (!SplitString(optarg, '=', &key, &value)) { | 234 if (!SplitStringFirst(optarg, '=', &key, &value)) { |
220 ToolSupport::UsageHint(me, "--annotation requires KEY=VALUE"); | 235 ToolSupport::UsageHint(me, "--annotation requires KEY=VALUE"); |
221 return EXIT_FAILURE; | 236 return EXIT_FAILURE; |
222 } | 237 } |
223 std::string old_value; | 238 std::string old_value; |
224 if (!MapInsertOrReplace(&options.annotations, key, value, &old_value)) { | 239 if (!MapInsertOrReplace(&options.annotations, key, value, &old_value)) { |
225 LOG(WARNING) << "duplicate key " << key << ", discarding value " | 240 LOG(WARNING) << "duplicate key " << key << ", discarding value " |
226 << old_value; | 241 << old_value; |
227 } | 242 } |
228 break; | 243 break; |
229 } | 244 } |
230 case kOptionDatabase: { | 245 case kOptionDatabase: { |
231 options.database = optarg; | 246 options.database = optarg; |
232 break; | 247 break; |
233 } | 248 } |
234 #if defined(OS_MACOSX) | 249 #if defined(OS_MACOSX) |
235 case kOptionHandshakeFD: { | 250 case kOptionHandshakeFD: { |
236 if (!StringToNumber(optarg, &options.handshake_fd) || | 251 if (!StringToNumber(optarg, &options.handshake_fd) || |
237 options.handshake_fd < 0) { | 252 options.handshake_fd < 0) { |
238 ToolSupport::UsageHint(me, | 253 ToolSupport::UsageHint(me, |
239 "--handshake-fd requires a file descriptor"); | 254 "--handshake-fd requires a file descriptor"); |
240 return EXIT_FAILURE; | 255 return EXIT_FAILURE; |
241 } | 256 } |
242 break; | 257 break; |
243 } | 258 } |
244 case kOptionMachService: { | 259 case kOptionMachService: { |
245 options.mach_service = optarg; | 260 options.mach_service = optarg; |
246 break; | 261 break; |
247 } | 262 } |
248 #elif defined(OS_WIN) | 263 #elif defined(OS_WIN) |
249 case kOptionHandshakeHandle: { | 264 case kOptionInitialClientData: { |
250 // Use unsigned int, because the handle was presented by the client in | 265 if (!options.initial_client_data.InitializeFromString(optarg)) { |
251 // 0x%x format. | 266 ToolSupport::UsageHint( |
252 unsigned int handle_uint; | 267 me, "failed to parse --initial-client-data"); |
253 if (!StringToNumber(optarg, &handle_uint) || | |
254 (options.handshake_handle = IntToHandle(handle_uint)) == | |
255 INVALID_HANDLE_VALUE) { | |
256 ToolSupport::UsageHint(me, "--handshake-handle requires a HANDLE"); | |
257 return EXIT_FAILURE; | 268 return EXIT_FAILURE; |
258 } | 269 } |
259 break; | 270 break; |
260 } | 271 } |
261 #endif // OS_MACOSX | 272 #endif // OS_MACOSX |
262 case kOptionMetrics: { | 273 case kOptionMetrics: { |
263 options.metrics = optarg; | 274 options.metrics = optarg; |
264 break; | 275 break; |
265 } | 276 } |
266 case kOptionNoRateLimit: { | 277 case kOptionNoRateLimit: { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
303 if (options.handshake_fd < 0 && options.mach_service.empty()) { | 314 if (options.handshake_fd < 0 && options.mach_service.empty()) { |
304 ToolSupport::UsageHint(me, "--handshake-fd or --mach-service is required"); | 315 ToolSupport::UsageHint(me, "--handshake-fd or --mach-service is required"); |
305 return EXIT_FAILURE; | 316 return EXIT_FAILURE; |
306 } | 317 } |
307 if (options.handshake_fd >= 0 && !options.mach_service.empty()) { | 318 if (options.handshake_fd >= 0 && !options.mach_service.empty()) { |
308 ToolSupport::UsageHint( | 319 ToolSupport::UsageHint( |
309 me, "--handshake-fd and --mach-service are incompatible"); | 320 me, "--handshake-fd and --mach-service are incompatible"); |
310 return EXIT_FAILURE; | 321 return EXIT_FAILURE; |
311 } | 322 } |
312 #elif defined(OS_WIN) | 323 #elif defined(OS_WIN) |
313 if (options.handshake_handle == INVALID_HANDLE_VALUE && | 324 if (!options.initial_client_data.IsValid() && options.pipe_name.empty()) { |
314 options.pipe_name.empty()) { | 325 ToolSupport::UsageHint(me, |
315 ToolSupport::UsageHint(me, "--handshake-handle or --pipe-name is required"); | 326 "--initial-client-data or --pipe-name is required"); |
316 return EXIT_FAILURE; | 327 return EXIT_FAILURE; |
317 } | 328 } |
318 if (options.handshake_handle != INVALID_HANDLE_VALUE && | 329 if (options.initial_client_data.IsValid() && !options.pipe_name.empty()) { |
319 !options.pipe_name.empty()) { | |
320 ToolSupport::UsageHint( | 330 ToolSupport::UsageHint( |
321 me, "--handshake-handle and --pipe-name are incompatible"); | 331 me, "--initial-client-data and --pipe-name are incompatible"); |
322 return EXIT_FAILURE; | 332 return EXIT_FAILURE; |
323 } | 333 } |
324 #endif // OS_MACOSX | 334 #endif // OS_MACOSX |
325 | 335 |
326 if (!options.database) { | 336 if (!options.database) { |
327 ToolSupport::UsageHint(me, "--database is required"); | 337 ToolSupport::UsageHint(me, "--database is required"); |
328 return EXIT_FAILURE; | 338 return EXIT_FAILURE; |
329 } | 339 } |
330 | 340 |
331 if (argc) { | 341 if (argc) { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
382 } | 392 } |
383 #elif defined(OS_WIN) | 393 #elif defined(OS_WIN) |
384 // Shut down as late as possible relative to programs we're watching. | 394 // Shut down as late as possible relative to programs we're watching. |
385 if (!SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY)) | 395 if (!SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY)) |
386 PLOG(ERROR) << "SetProcessShutdownParameters"; | 396 PLOG(ERROR) << "SetProcessShutdownParameters"; |
387 | 397 |
388 ExceptionHandlerServer exception_handler_server(!options.pipe_name.empty()); | 398 ExceptionHandlerServer exception_handler_server(!options.pipe_name.empty()); |
389 | 399 |
390 if (!options.pipe_name.empty()) { | 400 if (!options.pipe_name.empty()) { |
391 exception_handler_server.SetPipeName(base::UTF8ToUTF16(options.pipe_name)); | 401 exception_handler_server.SetPipeName(base::UTF8ToUTF16(options.pipe_name)); |
392 } else if (options.handshake_handle != INVALID_HANDLE_VALUE) { | |
393 std::wstring pipe_name = exception_handler_server.CreatePipe(); | |
394 | |
395 uint32_t pipe_name_length = static_cast<uint32_t>(pipe_name.size()); | |
396 if (!LoggingWriteFile(options.handshake_handle, | |
397 &pipe_name_length, | |
398 sizeof(pipe_name_length))) { | |
399 return EXIT_FAILURE; | |
400 } | |
401 if (!LoggingWriteFile(options.handshake_handle, | |
402 pipe_name.c_str(), | |
403 pipe_name.size() * sizeof(pipe_name[0]))) { | |
404 return EXIT_FAILURE; | |
405 } | |
406 } | 402 } |
407 #endif // OS_MACOSX | 403 #endif // OS_MACOSX |
408 | 404 |
409 base::GlobalHistogramAllocator* histogram_allocator = nullptr; | 405 base::GlobalHistogramAllocator* histogram_allocator = nullptr; |
410 if (options.metrics) { | 406 if (options.metrics) { |
411 const base::FilePath metrics_dir( | 407 const base::FilePath metrics_dir( |
412 ToolSupport::CommandLineArgumentToFilePathStringType(options.metrics)); | 408 ToolSupport::CommandLineArgumentToFilePathStringType(options.metrics)); |
413 static const char kMetricsName[] = "CrashpadMetrics"; | 409 static const char kMetricsName[] = "CrashpadMetrics"; |
414 const size_t kMetricsFileSize = 1 << 20; | 410 const size_t kMetricsFileSize = 1 << 20; |
415 if (base::GlobalHistogramAllocator::CreateWithActiveFileInDir( | 411 if (base::GlobalHistogramAllocator::CreateWithActiveFileInDir( |
(...skipping 17 matching lines...) Expand all Loading... |
433 database.get(), options.url, options.rate_limit); | 429 database.get(), options.url, options.rate_limit); |
434 upload_thread.Start(); | 430 upload_thread.Start(); |
435 | 431 |
436 PruneCrashReportThread prune_thread(database.get(), | 432 PruneCrashReportThread prune_thread(database.get(), |
437 PruneCondition::GetDefault()); | 433 PruneCondition::GetDefault()); |
438 prune_thread.Start(); | 434 prune_thread.Start(); |
439 | 435 |
440 CrashReportExceptionHandler exception_handler( | 436 CrashReportExceptionHandler exception_handler( |
441 database.get(), &upload_thread, &options.annotations); | 437 database.get(), &upload_thread, &options.annotations); |
442 | 438 |
| 439 #if defined(OS_WIN) |
| 440 if (options.initial_client_data.IsValid()) { |
| 441 exception_handler_server.InitializeWithInheritedDataForInitialClient( |
| 442 options.initial_client_data, &exception_handler); |
| 443 } |
| 444 #endif // OS_WIN |
| 445 |
443 exception_handler_server.Run(&exception_handler); | 446 exception_handler_server.Run(&exception_handler); |
444 | 447 |
445 upload_thread.Stop(); | 448 upload_thread.Stop(); |
446 prune_thread.Stop(); | 449 prune_thread.Stop(); |
447 | 450 |
448 if (histogram_allocator) | 451 if (histogram_allocator) |
449 histogram_allocator->DeletePersistentLocation(); | 452 histogram_allocator->DeletePersistentLocation(); |
450 | 453 |
451 return EXIT_SUCCESS; | 454 return EXIT_SUCCESS; |
452 } | 455 } |
453 | 456 |
454 } // namespace crashpad | 457 } // namespace crashpad |
OLD | NEW |