1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (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
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "handler/handler_main.h"
16 
17 #include <errno.h>
18 #include <getopt.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <sys/types.h>
22 
23 #include <algorithm>
24 #include <map>
25 #include <memory>
26 #include <string>
27 #include <utility>
28 #include <vector>
29 
30 #include "base/auto_reset.h"
31 #include "base/compiler_specific.h"
32 #include "base/files/file_path.h"
33 #include "base/files/scoped_file.h"
34 #include "base/logging.h"
35 #include "base/metrics/persistent_histogram_allocator.h"
36 #include "base/scoped_generic.h"
37 #include "base/strings/string_number_conversions.h"
38 #include "base/strings/stringprintf.h"
39 #include "base/strings/utf_string_conversions.h"
40 #include "build/build_config.h"
41 #include "client/crash_report_database.h"
42 #include "client/crashpad_client.h"
43 #include "client/crashpad_info.h"
44 #include "client/prune_crash_reports.h"
45 #include "client/simple_string_dictionary.h"
46 #include "handler/crash_report_upload_thread.h"
47 #include "handler/prune_crash_reports_thread.h"
48 #include "tools/tool_support.h"
49 #include "util/file/file_io.h"
50 #include "util/misc/address_types.h"
51 #include "util/misc/metrics.h"
52 #include "util/misc/paths.h"
53 #include "util/numeric/in_range_cast.h"
54 #include "util/stdlib/map_insert.h"
55 #include "util/stdlib/string_number_conversion.h"
56 #include "util/string/split_string.h"
57 #include "util/synchronization/semaphore.h"
58 
59 #if defined(OS_CHROMEOS)
60 #include "handler/linux/cros_crash_report_exception_handler.h"
61 #endif
62 
63 #if defined(OS_LINUX) || defined(OS_ANDROID)
64 #include <unistd.h>
65 
66 #include "handler/linux/crash_report_exception_handler.h"
67 #include "handler/linux/exception_handler_server.h"
68 #include "util/posix/signals.h"
69 #elif defined(OS_MACOSX)
70 #include <libgen.h>
71 #include <signal.h>
72 
73 #include "base/mac/scoped_mach_port.h"
74 #include "handler/mac/crash_report_exception_handler.h"
75 #include "handler/mac/exception_handler_server.h"
76 #include "handler/mac/file_limit_annotation.h"
77 #include "util/mach/child_port_handshake.h"
78 #include "util/mach/mach_extensions.h"
79 #include "util/posix/close_stdio.h"
80 #include "util/posix/signals.h"
81 #elif defined(OS_WIN)
82 #include <windows.h>
83 
84 #include "handler/win/crash_report_exception_handler.h"
85 #include "util/win/exception_handler_server.h"
86 #include "util/win/handle.h"
87 #include "util/win/initial_client_data.h"
88 #include "util/win/session_end_watcher.h"
89 #elif defined(OS_FUCHSIA)
90 #include <zircon/process.h>
91 #include <zircon/processargs.h>
92 
93 #include <lib/zx/channel.h>
94 #include <lib/zx/job.h>
95 
96 #include "handler/fuchsia/crash_report_exception_handler.h"
97 #include "handler/fuchsia/exception_handler_server.h"
98 #elif defined(OS_LINUX)
99 #include "handler/linux/crash_report_exception_handler.h"
100 #include "handler/linux/exception_handler_server.h"
101 #endif  // OS_MACOSX
102 
103 namespace crashpad {
104 
105 namespace {
106 
Usage(const base::FilePath & me)107 void Usage(const base::FilePath& me) {
108   fprintf(stderr,
109 "Usage: %" PRFilePath " [OPTION]...\n"
110 "Crashpad's exception handler server.\n"
111 "\n"
112 "      --annotation=KEY=VALUE  set a process annotation in each crash report\n"
113 "      --database=PATH         store the crash report database at PATH\n"
114 #if defined(OS_MACOSX)
115 "      --handshake-fd=FD       establish communication with the client over FD\n"
116 #endif  // OS_MACOSX
117 #if defined(OS_WIN)
118 "      --initial-client-data=HANDLE_request_crash_dump,\n"
119 "                            HANDLE_request_non_crash_dump,\n"
120 "                            HANDLE_non_crash_dump_completed,\n"
121 "                            HANDLE_pipe,\n"
122 "                            HANDLE_client_process,\n"
123 "                            Address_crash_exception_information,\n"
124 "                            Address_non_crash_exception_information,\n"
125 "                            Address_debug_critical_section\n"
126 "                              use precreated data to register initial client\n"
127 #endif  // OS_WIN
128 #if defined(OS_ANDROID) || defined(OS_LINUX)
129 "      --initial-client-fd=FD  a socket connected to a client.\n"
130 #endif  // OS_ANDROID || OS_LINUX
131 #if defined(OS_MACOSX)
132 "      --mach-service=SERVICE  register SERVICE with the bootstrap server\n"
133 #endif  // OS_MACOSX
134 "      --metrics-dir=DIR       store metrics files in DIR (only in Chromium)\n"
135 "      --monitor-self          run a second handler to catch crashes in the first\n"
136 "      --monitor-self-annotation=KEY=VALUE\n"
137 "                              set a module annotation in the handler\n"
138 "      --monitor-self-argument=ARGUMENT\n"
139 "                              provide additional arguments to the second handler\n"
140 "      --no-identify-client-via-url\n"
141 "                              when uploading crash report, don't add\n"
142 "                              client-identifying arguments to URL\n"
143 "      --no-periodic-tasks     don't scan for new reports or prune the database\n"
144 "      --no-rate-limit         don't rate limit crash uploads\n"
145 "      --no-upload-gzip        don't use gzip compression when uploading\n"
146 #if defined(OS_ANDROID)
147 "      --no-write-minidump-to-database\n"
148 "                              don't write minidump to database\n"
149 #endif  // OS_ANDROID
150 #if defined(OS_WIN)
151 "      --pipe-name=PIPE        communicate with the client over PIPE\n"
152 #endif  // OS_WIN
153 #if defined(OS_MACOSX)
154 "      --reset-own-crash-exception-port-to-system-default\n"
155 "                              reset the server's exception handler to default\n"
156 #endif  // OS_MACOSX
157 #if defined(OS_LINUX) || defined(OS_ANDROID)
158 "      --sanitization-information=SANITIZATION_INFORMATION_ADDRESS\n"
159 "                              the address of a SanitizationInformation struct.\n"
160 "      --shared-client-connection the file descriptor provided by\n"
161 "                              --initial-client-fd is shared among multiple\n"
162 "                              clients\n"
163 "      --trace-parent-with-exception=EXCEPTION_INFORMATION_ADDRESS\n"
164 "                              request a dump for the handler's parent process\n"
165 #endif  // OS_LINUX || OS_ANDROID
166 "      --url=URL               send crash reports to this Breakpad server URL,\n"
167 "                              only if uploads are enabled for the database\n"
168 #if defined(OS_CHROMEOS)
169 "      --use-cros-crash-reporter\n"
170 "                              pass crash reports to /sbin/crash_reporter\n"
171 "                              instead of storing them in the database\n"
172 "      --minidump-dir-for-tests=TEST_MINIDUMP_DIR\n"
173 "                              causes /sbin/crash_reporter to leave dumps in\n"
174 "                              this directory instead of the normal location\n"
175 "      --always-allow-feedback\n"
176 "                              pass the --always_allow_feedback flag to\n"
177 "                              crash_reporter, thus skipping metrics consent\n"
178 "                              checks\n"
179 #endif  // OS_CHROMEOS
180 #if defined(OS_ANDROID)
181 "      --write-minidump-to-log write minidump to log\n"
182 #endif  // OS_ANDROID
183 "      --help                  display this help and exit\n"
184 "      --version               output version information and exit\n",
185           me.value().c_str());
186   ToolSupport::UsageTail(me);
187 }
188 
189 struct Options {
190   std::map<std::string, std::string> annotations;
191   std::map<std::string, std::string> monitor_self_annotations;
192   std::string url;
193   base::FilePath database;
194   base::FilePath metrics_dir;
195   std::vector<std::string> monitor_self_arguments;
196 #if defined(OS_MACOSX)
197   std::string mach_service;
198   int handshake_fd;
199   bool reset_own_crash_exception_port_to_system_default;
200 #elif defined(OS_LINUX) || defined(OS_ANDROID)
201   VMAddress exception_information_address;
202   VMAddress sanitization_information_address;
203   int initial_client_fd;
204   bool shared_client_connection;
205 #if defined(OS_ANDROID)
206   bool write_minidump_to_log;
207   bool write_minidump_to_database;
208 #endif  // OS_ANDROID
209 #elif defined(OS_WIN)
210   std::string pipe_name;
211   InitialClientData initial_client_data;
212 #endif  // OS_MACOSX
213   bool identify_client_via_url;
214   bool monitor_self;
215   bool periodic_tasks;
216   bool rate_limit;
217   bool upload_gzip;
218 #if defined(OS_CHROMEOS)
219   bool use_cros_crash_reporter = false;
220   base::FilePath minidump_dir_for_tests;
221   bool always_allow_feedback = false;
222 #endif  // OS_CHROMEOS
223 };
224 
225 // Splits |key_value| on '=' and inserts the resulting key and value into |map|.
226 // If |key_value| has the wrong format, logs an error and returns false. If the
227 // key is already in the map, logs a warning, replaces the existing value, and
228 // returns true. If the key and value were inserted into the map, returns true.
229 // |argument| is used to give context to logged messages.
AddKeyValueToMap(std::map<std::string,std::string> * map,const std::string & key_value,const char * argument)230 bool AddKeyValueToMap(std::map<std::string, std::string>* map,
231                       const std::string& key_value,
232                       const char* argument) {
233   std::string key;
234   std::string value;
235   if (!SplitStringFirst(key_value, '=', &key, &value)) {
236     LOG(ERROR) << argument << " requires KEY=VALUE";
237     return false;
238   }
239 
240   std::string old_value;
241   if (!MapInsertOrReplace(map, key, value, &old_value)) {
242     LOG(WARNING) << argument << " has duplicate key " << key
243                  << ", discarding value " << old_value;
244   }
245   return true;
246 }
247 
248 // Calls Metrics::HandlerLifetimeMilestone, but only on the first call. This is
249 // to prevent multiple exit events from inadvertently being recorded, which
250 // might happen if a crash occurs during destruction in what would otherwise be
251 // a normal exit, or if a CallMetricsRecordNormalExit object is destroyed after
252 // something else logs an exit event.
MetricsRecordExit(Metrics::LifetimeMilestone milestone)253 void MetricsRecordExit(Metrics::LifetimeMilestone milestone) {
254   static bool once = [](Metrics::LifetimeMilestone milestone) {
255     Metrics::HandlerLifetimeMilestone(milestone);
256     return true;
257   }(milestone);
258   ALLOW_UNUSED_LOCAL(once);
259 }
260 
261 // Calls MetricsRecordExit() to record a failure, and returns EXIT_FAILURE for
262 // the convenience of callers in main() which can simply write “return
263 // ExitFailure();”.
ExitFailure()264 int ExitFailure() {
265   MetricsRecordExit(Metrics::LifetimeMilestone::kFailed);
266   return EXIT_FAILURE;
267 }
268 
269 class CallMetricsRecordNormalExit {
270  public:
CallMetricsRecordNormalExit()271   CallMetricsRecordNormalExit() {}
~CallMetricsRecordNormalExit()272   ~CallMetricsRecordNormalExit() {
273     MetricsRecordExit(Metrics::LifetimeMilestone::kExitedNormally);
274   }
275 
276  private:
277   DISALLOW_COPY_AND_ASSIGN(CallMetricsRecordNormalExit);
278 };
279 
280 #if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_ANDROID)
281 
HandleCrashSignal(int sig,siginfo_t * siginfo,void * context)282 void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) {
283   MetricsRecordExit(Metrics::LifetimeMilestone::kCrashed);
284 
285   // Is siginfo->si_code useful? The only interesting values on macOS are 0 (not
286   // useful, signals generated asynchronously such as by kill() or raise()) and
287   // small positive numbers (useful, signal generated via a hardware fault). The
288   // standard specifies these other constants, and while xnu never uses them,
289   // they are intended to denote signals generated asynchronously and are
290   // included here. Additionally, existing practice on other systems
291   // (acknowledged by the standard) is for negative numbers to indicate that a
292   // signal was generated asynchronously. Although xnu does not do this, allow
293   // for the possibility for completeness.
294   bool si_code_valid = !(siginfo->si_code <= 0 ||
295                          siginfo->si_code == SI_USER ||
296                          siginfo->si_code == SI_QUEUE ||
297                          siginfo->si_code == SI_TIMER ||
298                          siginfo->si_code == SI_ASYNCIO ||
299                          siginfo->si_code == SI_MESGQ);
300 
301   // 0x5343 = 'SC', signifying “signal and code”, disambiguates from the schema
302   // used by ExceptionCodeForMetrics(). That system primarily uses Mach
303   // exception types and codes, which are not available to a POSIX signal
304   // handler. It does provide a way to encode only signal numbers, but does so
305   // with the understanding that certain “raw” signals would not be encountered
306   // without a Mach exception. Furthermore, it does not allow siginfo->si_code
307   // to be encoded, because that’s not available to Mach exception handlers. It
308   // would be a shame to lose that information available to a POSIX signal
309   // handler.
310   int metrics_code = 0x53430000 | (InRangeCast<uint8_t>(sig, 0xff) << 8);
311   if (si_code_valid) {
312     metrics_code |= InRangeCast<uint8_t>(siginfo->si_code, 0xff);
313   }
314   Metrics::HandlerCrashed(metrics_code);
315 
316   Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, nullptr);
317 }
318 
HandleTerminateSignal(int sig,siginfo_t * siginfo,void * context)319 void HandleTerminateSignal(int sig, siginfo_t* siginfo, void* context) {
320   MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated);
321   Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, nullptr);
322 }
323 
ReinstallCrashHandler()324 void ReinstallCrashHandler() {
325   // This is used to re-enable the metrics-recording crash handler after
326   // MonitorSelf() sets up a Crashpad exception handler. On macOS, the
327   // metrics-recording handler uses signals and the Crashpad handler uses Mach
328   // exceptions, so there’s nothing to re-enable.
329   // On Linux, the signal handler installed by StartHandler() restores the
330   // previously installed signal handler by default.
331 }
332 
InstallCrashHandler()333 void InstallCrashHandler() {
334   Signals::InstallCrashHandlers(HandleCrashSignal, 0, nullptr);
335 
336   // Not a crash handler, but close enough.
337   Signals::InstallTerminateHandlers(HandleTerminateSignal, 0, nullptr);
338 }
339 
340 #if defined(OS_MACOSX)
341 
342 struct ResetSIGTERMTraits {
InvalidValuecrashpad::__anon891c7b860111::ResetSIGTERMTraits343   static struct sigaction* InvalidValue() {
344     return nullptr;
345   }
346 
Freecrashpad::__anon891c7b860111::ResetSIGTERMTraits347   static void Free(struct sigaction* sa) {
348     int rv = sigaction(SIGTERM, sa, nullptr);
349     PLOG_IF(ERROR, rv != 0) << "sigaction";
350   }
351 };
352 using ScopedResetSIGTERM =
353     base::ScopedGeneric<struct sigaction*, ResetSIGTERMTraits>;
354 
355 ExceptionHandlerServer* g_exception_handler_server;
356 
357 // This signal handler is only operative when being run from launchd.
HandleSIGTERM(int sig,siginfo_t * siginfo,void * context)358 void HandleSIGTERM(int sig, siginfo_t* siginfo, void* context) {
359   // Don’t call MetricsRecordExit(). This is part of the normal exit path when
360   // running from launchd.
361 
362   DCHECK(g_exception_handler_server);
363   g_exception_handler_server->Stop();
364 }
365 
366 #endif  // OS_MACOSX
367 
368 #elif defined(OS_WIN)
369 
370 LONG(WINAPI* g_original_exception_filter)(EXCEPTION_POINTERS*) = nullptr;
371 
UnhandledExceptionHandler(EXCEPTION_POINTERS * exception_pointers)372 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) {
373   MetricsRecordExit(Metrics::LifetimeMilestone::kCrashed);
374   Metrics::HandlerCrashed(exception_pointers->ExceptionRecord->ExceptionCode);
375 
376   if (g_original_exception_filter)
377     return g_original_exception_filter(exception_pointers);
378   else
379     return EXCEPTION_CONTINUE_SEARCH;
380 }
381 
382 // Handles events like Control-C and Control-Break on a console.
ConsoleHandler(DWORD console_event)383 BOOL WINAPI ConsoleHandler(DWORD console_event) {
384   MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated);
385   return false;
386 }
387 
388 // Handles a WM_ENDSESSION message sent when the user session is ending.
389 class TerminateHandler final : public SessionEndWatcher {
390  public:
TerminateHandler()391   TerminateHandler() : SessionEndWatcher() {}
~TerminateHandler()392   ~TerminateHandler() override {}
393 
394  private:
395   // SessionEndWatcher:
SessionEnding()396   void SessionEnding() override {
397     MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated);
398   }
399 
400   DISALLOW_COPY_AND_ASSIGN(TerminateHandler);
401 };
402 
ReinstallCrashHandler()403 void ReinstallCrashHandler() {
404   // This is used to re-enable the metrics-recording crash handler after
405   // MonitorSelf() sets up a Crashpad exception handler. The Crashpad handler
406   // takes over the UnhandledExceptionFilter, so reinstall the metrics-recording
407   // one.
408   g_original_exception_filter =
409       SetUnhandledExceptionFilter(&UnhandledExceptionHandler);
410 }
411 
InstallCrashHandler()412 void InstallCrashHandler() {
413   ReinstallCrashHandler();
414 
415   // These are termination handlers, not crash handlers, but that’s close
416   // enough. Note that destroying the TerminateHandler would wait for its thread
417   // to exit, which isn’t necessary or desirable.
418   SetConsoleCtrlHandler(ConsoleHandler, true);
419   static TerminateHandler* terminate_handler = new TerminateHandler();
420   ALLOW_UNUSED_LOCAL(terminate_handler);
421 }
422 
423 #elif defined(OS_FUCHSIA)
424 
InstallCrashHandler()425 void InstallCrashHandler() {
426   // There's nothing to do here. Crashes in this process will already be caught
427   // here because this handler process is in the same job that has had its
428   // exception port bound.
429 
430   // TODO(scottmg): This should collect metrics on handler crashes, at a
431   // minimum. https://crashpad.chromium.org/bug/230.
432 }
433 
ReinstallCrashHandler()434 void ReinstallCrashHandler() {
435   // TODO(scottmg): Fuchsia: https://crashpad.chromium.org/bug/196
436   NOTREACHED();
437 }
438 
439 #endif  // OS_MACOSX
440 
MonitorSelf(const Options & options)441 void MonitorSelf(const Options& options) {
442   base::FilePath executable_path;
443   if (!Paths::Executable(&executable_path)) {
444     return;
445   }
446 
447   if (std::find(options.monitor_self_arguments.begin(),
448                 options.monitor_self_arguments.end(),
449                 "--monitor-self") != options.monitor_self_arguments.end()) {
450     LOG(WARNING) << "--monitor-self-argument=--monitor-self is not supported";
451     return;
452   }
453   std::vector<std::string> extra_arguments(options.monitor_self_arguments);
454   if (!options.identify_client_via_url) {
455     extra_arguments.push_back("--no-identify-client-via-url");
456   }
457   extra_arguments.push_back("--no-periodic-tasks");
458   if (!options.rate_limit) {
459     extra_arguments.push_back("--no-rate-limit");
460   }
461   if (!options.upload_gzip) {
462     extra_arguments.push_back("--no-upload-gzip");
463   }
464   for (const auto& iterator : options.monitor_self_annotations) {
465     extra_arguments.push_back(
466         base::StringPrintf("--monitor-self-annotation=%s=%s",
467                            iterator.first.c_str(),
468                            iterator.second.c_str()));
469   }
470 
471   // Don’t use options.metrics_dir. The current implementation only allows one
472   // instance of crashpad_handler to be writing metrics at a time, and it should
473   // be the primary instance.
474   CrashpadClient crashpad_client;
475 #if defined(OS_ANDROID)
476   if (!crashpad_client.StartHandlerAtCrash(executable_path,
477                                            options.database,
478                                            base::FilePath(),
479                                            options.url,
480                                            options.annotations,
481                                            extra_arguments)) {
482     return;
483   }
484 #else
485   if (!crashpad_client.StartHandler(executable_path,
486                                     options.database,
487                                     base::FilePath(),
488                                     options.url,
489                                     options.annotations,
490                                     extra_arguments,
491                                     true,
492                                     false)) {
493     return;
494   }
495 #endif
496 
497   // Make sure that appropriate metrics will be recorded on crash before this
498   // process is terminated.
499   ReinstallCrashHandler();
500 }
501 
502 class ScopedStoppable {
503  public:
504   ScopedStoppable() = default;
505 
~ScopedStoppable()506   ~ScopedStoppable() {
507     if (stoppable_) {
508       stoppable_->Stop();
509     }
510   }
511 
Reset(Stoppable * stoppable)512   void Reset(Stoppable* stoppable) { stoppable_.reset(stoppable); }
513 
Get()514   Stoppable* Get() { return stoppable_.get(); }
515 
516  private:
517   std::unique_ptr<Stoppable> stoppable_;
518 
519   DISALLOW_COPY_AND_ASSIGN(ScopedStoppable);
520 };
521 
522 }  // namespace
523 
HandlerMain(int argc,char * argv[],const UserStreamDataSources * user_stream_sources)524 int HandlerMain(int argc,
525                 char* argv[],
526                 const UserStreamDataSources* user_stream_sources) {
527 #if defined(OS_CHROMEOS)
528   if (freopen("/var/log/chrome/chrome", "a", stderr) == nullptr) {
529     PLOG(ERROR) << "Failed to redirect stderr to /var/log/chrome/chrome";
530   }
531 #endif
532 
533   InstallCrashHandler();
534   CallMetricsRecordNormalExit metrics_record_normal_exit;
535 
536   const base::FilePath argv0(
537       ToolSupport::CommandLineArgumentToFilePathStringType(argv[0]));
538   const base::FilePath me(argv0.BaseName());
539 
540   enum OptionFlags {
541     // Long options without short equivalents.
542     kOptionLastChar = 255,
543     kOptionAnnotation,
544     kOptionDatabase,
545 #if defined(OS_MACOSX)
546     kOptionHandshakeFD,
547 #endif  // OS_MACOSX
548 #if defined(OS_WIN)
549     kOptionInitialClientData,
550 #endif  // OS_WIN
551 #if defined(OS_ANDROID) || defined(OS_LINUX)
552     kOptionInitialClientFD,
553 #endif  // OS_ANDROID || OS_LINUX
554 #if defined(OS_MACOSX)
555     kOptionMachService,
556 #endif  // OS_MACOSX
557     kOptionMetrics,
558     kOptionMonitorSelf,
559     kOptionMonitorSelfAnnotation,
560     kOptionMonitorSelfArgument,
561     kOptionNoIdentifyClientViaUrl,
562     kOptionNoPeriodicTasks,
563     kOptionNoRateLimit,
564     kOptionNoUploadGzip,
565 #if defined(OS_ANDROID)
566     kOptionNoWriteMinidumpToDatabase,
567 #endif  // OS_ANDROID
568 #if defined(OS_WIN)
569     kOptionPipeName,
570 #endif  // OS_WIN
571 #if defined(OS_MACOSX)
572     kOptionResetOwnCrashExceptionPortToSystemDefault,
573 #endif  // OS_MACOSX
574 #if defined(OS_LINUX) || defined(OS_ANDROID)
575     kOptionSanitizationInformation,
576     kOptionSharedClientConnection,
577     kOptionTraceParentWithException,
578 #endif
579     kOptionURL,
580 #if defined(OS_CHROMEOS)
581     kOptionUseCrosCrashReporter,
582     kOptionMinidumpDirForTests,
583     kOptionAlwaysAllowFeedback,
584 #endif  // OS_CHROMEOS
585 #if defined(OS_ANDROID)
586     kOptionWriteMinidumpToLog,
587 #endif  // OS_ANDROID
588 
589     // Standard options.
590     kOptionHelp = -2,
591     kOptionVersion = -3,
592   };
593 
594   static constexpr option long_options[] = {
595     {"annotation", required_argument, nullptr, kOptionAnnotation},
596     {"database", required_argument, nullptr, kOptionDatabase},
597 #if defined(OS_MACOSX)
598     {"handshake-fd", required_argument, nullptr, kOptionHandshakeFD},
599 #endif  // OS_MACOSX
600 #if defined(OS_WIN)
601     {"initial-client-data",
602      required_argument,
603      nullptr,
604      kOptionInitialClientData},
605 #endif  // OS_MACOSX
606 #if defined(OS_ANDROID) || defined(OS_LINUX)
607     {"initial-client-fd", required_argument, nullptr, kOptionInitialClientFD},
608 #endif  // OS_ANDROID || OS_LINUX
609 #if defined(OS_MACOSX)
610     {"mach-service", required_argument, nullptr, kOptionMachService},
611 #endif  // OS_MACOSX
612     {"metrics-dir", required_argument, nullptr, kOptionMetrics},
613     {"monitor-self", no_argument, nullptr, kOptionMonitorSelf},
614     {"monitor-self-annotation",
615      required_argument,
616      nullptr,
617      kOptionMonitorSelfAnnotation},
618     {"monitor-self-argument",
619      required_argument,
620      nullptr,
621      kOptionMonitorSelfArgument},
622     {"no-identify-client-via-url",
623      no_argument,
624      nullptr,
625      kOptionNoIdentifyClientViaUrl},
626     {"no-periodic-tasks", no_argument, nullptr, kOptionNoPeriodicTasks},
627     {"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit},
628     {"no-upload-gzip", no_argument, nullptr, kOptionNoUploadGzip},
629 #if defined(OS_ANDROID)
630     {"no-write-minidump-to-database",
631      no_argument,
632      nullptr,
633      kOptionNoWriteMinidumpToDatabase},
634 #endif  // OS_ANDROID
635 #if defined(OS_WIN)
636     {"pipe-name", required_argument, nullptr, kOptionPipeName},
637 #endif  // OS_WIN
638 #if defined(OS_MACOSX)
639     {"reset-own-crash-exception-port-to-system-default",
640      no_argument,
641      nullptr,
642      kOptionResetOwnCrashExceptionPortToSystemDefault},
643 #endif  // OS_MACOSX
644 #if defined(OS_LINUX) || defined(OS_ANDROID)
645     {"sanitization-information",
646      required_argument,
647      nullptr,
648      kOptionSanitizationInformation},
649     {"shared-client-connection",
650      no_argument,
651      nullptr,
652      kOptionSharedClientConnection},
653     {"trace-parent-with-exception",
654      required_argument,
655      nullptr,
656      kOptionTraceParentWithException},
657 #endif  // OS_LINUX || OS_ANDROID
658     {"url", required_argument, nullptr, kOptionURL},
659 #if defined(OS_CHROMEOS)
660     {"use-cros-crash-reporter",
661       no_argument,
662       nullptr,
663       kOptionUseCrosCrashReporter},
664     {"minidump-dir-for-tests",
665       required_argument,
666       nullptr,
667       kOptionMinidumpDirForTests},
668     {"always-allow-feedback",
669       no_argument,
670       nullptr,
671       kOptionAlwaysAllowFeedback},
672 #endif  // OS_CHROMEOS
673 #if defined(OS_ANDROID)
674     {"write-minidump-to-log", no_argument, nullptr, kOptionWriteMinidumpToLog},
675 #endif  // OS_ANDROID
676     {"help", no_argument, nullptr, kOptionHelp},
677     {"version", no_argument, nullptr, kOptionVersion},
678     {nullptr, 0, nullptr, 0},
679   };
680 
681   Options options = {};
682 #if defined(OS_MACOSX)
683   options.handshake_fd = -1;
684 #endif
685   options.identify_client_via_url = true;
686 #if defined(OS_LINUX) || defined(OS_ANDROID)
687   options.initial_client_fd = kInvalidFileHandle;
688 #endif
689   options.periodic_tasks = true;
690   options.rate_limit = true;
691   options.upload_gzip = true;
692 #if defined(OS_ANDROID)
693   options.write_minidump_to_database = true;
694 #endif
695 
696   int opt;
697   while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) {
698     switch (opt) {
699       case kOptionAnnotation: {
700         if (!AddKeyValueToMap(&options.annotations, optarg, "--annotation")) {
701           return ExitFailure();
702         }
703         break;
704       }
705       case kOptionDatabase: {
706         options.database = base::FilePath(
707             ToolSupport::CommandLineArgumentToFilePathStringType(optarg));
708         break;
709       }
710 #if defined(OS_MACOSX)
711       case kOptionHandshakeFD: {
712         if (!StringToNumber(optarg, &options.handshake_fd) ||
713             options.handshake_fd < 0) {
714           ToolSupport::UsageHint(me,
715                                  "--handshake-fd requires a file descriptor");
716           return ExitFailure();
717         }
718         break;
719       }
720       case kOptionMachService: {
721         options.mach_service = optarg;
722         break;
723       }
724 #endif  // OS_MACOSX
725 #if defined(OS_WIN)
726       case kOptionInitialClientData: {
727         if (!options.initial_client_data.InitializeFromString(optarg)) {
728           ToolSupport::UsageHint(
729               me, "failed to parse --initial-client-data");
730           return ExitFailure();
731         }
732         break;
733       }
734 #endif  // OS_WIN
735 #if defined(OS_ANDROID) || defined(OS_LINUX)
736       case kOptionInitialClientFD: {
737         if (!base::StringToInt(optarg, &options.initial_client_fd)) {
738           ToolSupport::UsageHint(me, "failed to parse --initial-client-fd");
739           return ExitFailure();
740         }
741         break;
742       }
743 #endif  // OS_ANDROID || OS_LINUX
744       case kOptionMetrics: {
745         options.metrics_dir = base::FilePath(
746             ToolSupport::CommandLineArgumentToFilePathStringType(optarg));
747         break;
748       }
749       case kOptionMonitorSelf: {
750         options.monitor_self = true;
751         break;
752       }
753       case kOptionMonitorSelfAnnotation: {
754         if (!AddKeyValueToMap(&options.monitor_self_annotations,
755                               optarg,
756                               "--monitor-self-annotation")) {
757           return ExitFailure();
758         }
759         break;
760       }
761       case kOptionMonitorSelfArgument: {
762         options.monitor_self_arguments.push_back(optarg);
763         break;
764       }
765       case kOptionNoIdentifyClientViaUrl: {
766         options.identify_client_via_url = false;
767         break;
768       }
769       case kOptionNoPeriodicTasks: {
770         options.periodic_tasks = false;
771         break;
772       }
773       case kOptionNoRateLimit: {
774         options.rate_limit = false;
775         break;
776       }
777       case kOptionNoUploadGzip: {
778         options.upload_gzip = false;
779         break;
780       }
781 #if defined(OS_ANDROID)
782       case kOptionNoWriteMinidumpToDatabase: {
783         options.write_minidump_to_database = false;
784         break;
785       }
786 #endif  // OS_ANDROID
787 #if defined(OS_WIN)
788       case kOptionPipeName: {
789         options.pipe_name = optarg;
790         break;
791       }
792 #endif  // OS_WIN
793 #if defined(OS_MACOSX)
794       case kOptionResetOwnCrashExceptionPortToSystemDefault: {
795         options.reset_own_crash_exception_port_to_system_default = true;
796         break;
797       }
798 #endif  // OS_MACOSX
799 #if defined(OS_LINUX) || defined(OS_ANDROID)
800       case kOptionSanitizationInformation: {
801         if (!StringToNumber(optarg,
802                             &options.sanitization_information_address)) {
803           ToolSupport::UsageHint(me,
804                                  "failed to parse --sanitization-information");
805           return ExitFailure();
806         }
807         break;
808       }
809       case kOptionSharedClientConnection: {
810         options.shared_client_connection = true;
811         break;
812       }
813       case kOptionTraceParentWithException: {
814         if (!StringToNumber(optarg, &options.exception_information_address)) {
815           ToolSupport::UsageHint(
816               me, "failed to parse --trace-parent-with-exception");
817           return ExitFailure();
818         }
819         break;
820       }
821 #endif  // OS_LINUX || OS_ANDROID
822       case kOptionURL: {
823         options.url = optarg;
824         break;
825       }
826 #if defined(OS_CHROMEOS)
827       case kOptionUseCrosCrashReporter: {
828         options.use_cros_crash_reporter = true;
829         break;
830       }
831       case kOptionMinidumpDirForTests: {
832         options.minidump_dir_for_tests = base::FilePath(
833             ToolSupport::CommandLineArgumentToFilePathStringType(optarg));
834         break;
835       }
836       case kOptionAlwaysAllowFeedback: {
837         options.always_allow_feedback = true;
838         break;
839       }
840 #endif  // OS_CHROMEOS
841 #if defined(OS_ANDROID)
842       case kOptionWriteMinidumpToLog: {
843         options.write_minidump_to_log = true;
844         break;
845       }
846 #endif  // OS_ANDROID
847       case kOptionHelp: {
848         Usage(me);
849         MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly);
850         return EXIT_SUCCESS;
851       }
852       case kOptionVersion: {
853         ToolSupport::Version(me);
854         MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly);
855         return EXIT_SUCCESS;
856       }
857       default: {
858         ToolSupport::UsageHint(me, nullptr);
859         return ExitFailure();
860       }
861     }
862   }
863   argc -= optind;
864   argv += optind;
865 
866 #if defined(OS_MACOSX)
867   if (options.handshake_fd < 0 && options.mach_service.empty()) {
868     ToolSupport::UsageHint(me, "--handshake-fd or --mach-service is required");
869     return ExitFailure();
870   }
871   if (options.handshake_fd >= 0 && !options.mach_service.empty()) {
872     ToolSupport::UsageHint(
873         me, "--handshake-fd and --mach-service are incompatible");
874     return ExitFailure();
875   }
876 #elif defined(OS_WIN)
877   if (!options.initial_client_data.IsValid() && options.pipe_name.empty()) {
878     ToolSupport::UsageHint(me,
879                            "--initial-client-data or --pipe-name is required");
880     return ExitFailure();
881   }
882   if (options.initial_client_data.IsValid() && !options.pipe_name.empty()) {
883     ToolSupport::UsageHint(
884         me, "--initial-client-data and --pipe-name are incompatible");
885     return ExitFailure();
886   }
887 #elif defined(OS_LINUX) || defined(OS_ANDROID)
888   if (!options.exception_information_address &&
889       options.initial_client_fd == kInvalidFileHandle) {
890     ToolSupport::UsageHint(
891         me, "--trace-parent-with-exception or --initial-client-fd is required");
892     return ExitFailure();
893   }
894   if (options.sanitization_information_address &&
895       !options.exception_information_address) {
896     ToolSupport::UsageHint(
897         me,
898         "--sanitization_information requires --trace-parent-with-exception");
899     return ExitFailure();
900   }
901   if (options.shared_client_connection &&
902       options.initial_client_fd == kInvalidFileHandle) {
903     ToolSupport::UsageHint(
904         me, "--shared-client-connection requires --initial-client-fd");
905     return ExitFailure();
906   }
907 #if defined(OS_ANDROID)
908   if (!options.write_minidump_to_log && !options.write_minidump_to_database) {
909     ToolSupport::UsageHint(me,
910                            "--no_write_minidump_to_database is required to use "
911                            "with --write_minidump_to_log.");
912     ExitFailure();
913   }
914 #endif  // OS_ANDROID
915 #endif  // OS_MACOSX
916 
917   if (options.database.empty()) {
918     ToolSupport::UsageHint(me, "--database is required");
919     return ExitFailure();
920   }
921 
922   if (argc) {
923     ToolSupport::UsageHint(me, nullptr);
924     return ExitFailure();
925   }
926 
927 #if defined(OS_MACOSX)
928   if (options.reset_own_crash_exception_port_to_system_default) {
929     CrashpadClient::UseSystemDefaultHandler();
930   }
931 #endif  // OS_MACOSX
932 
933   if (options.monitor_self) {
934     MonitorSelf(options);
935   }
936 
937   if (!options.monitor_self_annotations.empty()) {
938     // Establish these annotations even if --monitor-self is not present, in
939     // case something such as generate_dump wants to try to access them later.
940     //
941     // If the handler is part of a multi-purpose executable, simple annotations
942     // may already be present for this module. If they are, use them.
943     CrashpadInfo* crashpad_info = CrashpadInfo::GetCrashpadInfo();
944     SimpleStringDictionary* module_annotations =
945         crashpad_info->simple_annotations();
946     if (!module_annotations) {
947       module_annotations = new SimpleStringDictionary();
948       crashpad_info->set_simple_annotations(module_annotations);
949     }
950 
951     for (const auto& iterator : options.monitor_self_annotations) {
952       module_annotations->SetKeyValue(iterator.first.c_str(),
953                                       iterator.second.c_str());
954     }
955   }
956 
957   std::unique_ptr<CrashReportDatabase> database(
958       CrashReportDatabase::Initialize(options.database));
959   if (!database) {
960     return ExitFailure();
961   }
962 
963   ScopedStoppable upload_thread;
964   if (!options.url.empty()) {
965     // TODO(scottmg): options.rate_limit should be removed when we have a
966     // configurable database setting to control upload limiting.
967     // See https://crashpad.chromium.org/bug/23.
968     CrashReportUploadThread::Options upload_thread_options;
969     upload_thread_options.identify_client_via_url =
970         options.identify_client_via_url;
971     upload_thread_options.rate_limit = options.rate_limit;
972     upload_thread_options.upload_gzip = options.upload_gzip;
973     upload_thread_options.watch_pending_reports = options.periodic_tasks;
974 
975     upload_thread.Reset(new CrashReportUploadThread(
976         database.get(), options.url, upload_thread_options));
977     upload_thread.Get()->Start();
978   }
979 
980 #if defined(OS_LINUX) || defined(OS_ANDROID)
981   std::unique_ptr<ExceptionHandlerServer::Delegate> exception_handler;
982 #else
983   std::unique_ptr<CrashReportExceptionHandler> exception_handler;
984 #endif
985 
986 #if defined(OS_CHROMEOS)
987   if (options.use_cros_crash_reporter) {
988     auto cros_handler = std::make_unique<CrosCrashReportExceptionHandler>(
989         database.get(),
990         &options.annotations,
991         user_stream_sources);
992 
993     if (!options.minidump_dir_for_tests.empty()) {
994       cros_handler->SetDumpDir(options.minidump_dir_for_tests);
995     }
996 
997     if (options.always_allow_feedback) {
998       cros_handler->SetAlwaysAllowFeedback();
999     }
1000 
1001     exception_handler = std::move(cros_handler);
1002   } else {
1003     exception_handler = std::make_unique<CrashReportExceptionHandler>(
1004         database.get(),
1005         static_cast<CrashReportUploadThread*>(upload_thread.Get()),
1006         &options.annotations,
1007         true,
1008         false,
1009         user_stream_sources);
1010   }
1011 #else
1012   exception_handler = std::make_unique<CrashReportExceptionHandler>(
1013       database.get(),
1014       static_cast<CrashReportUploadThread*>(upload_thread.Get()),
1015       &options.annotations,
1016 #if defined(OS_FUCHSIA)
1017       // TODO(scottmg): Process level file attachments, and for all platforms.
1018       nullptr,
1019 #endif
1020 #if defined(OS_ANDROID)
1021       options.write_minidump_to_database,
1022       options.write_minidump_to_log,
1023 #endif  // OS_ANDROID
1024 #if defined(OS_LINUX)
1025       true,
1026       false,
1027 #endif  // OS_LINUX
1028       user_stream_sources);
1029 #endif  // OS_CHROMEOS
1030 
1031 #if defined(OS_LINUX) || defined(OS_ANDROID)
1032   if (options.exception_information_address) {
1033     ExceptionHandlerProtocol::ClientInformation info;
1034     info.exception_information_address = options.exception_information_address;
1035     info.sanitization_information_address =
1036         options.sanitization_information_address;
1037     return exception_handler->HandleException(getppid(), geteuid(), info)
1038                ? EXIT_SUCCESS
1039                : ExitFailure();
1040   }
1041 #endif  // OS_LINUX || OS_ANDROID
1042 
1043   ScopedStoppable prune_thread;
1044   if (options.periodic_tasks) {
1045     prune_thread.Reset(new PruneCrashReportThread(
1046         database.get(), PruneCondition::GetDefault()));
1047     prune_thread.Get()->Start();
1048   }
1049 
1050 #if defined(OS_MACOSX)
1051   if (options.mach_service.empty()) {
1052     // Don’t do this when being run by launchd. See launchd.plist(5).
1053     CloseStdinAndStdout();
1054   }
1055 
1056   base::mac::ScopedMachReceiveRight receive_right;
1057 
1058   if (options.handshake_fd >= 0) {
1059     receive_right.reset(
1060         ChildPortHandshake::RunServerForFD(
1061             base::ScopedFD(options.handshake_fd),
1062             ChildPortHandshake::PortRightType::kReceiveRight));
1063   } else if (!options.mach_service.empty()) {
1064     receive_right = BootstrapCheckIn(options.mach_service);
1065   }
1066 
1067   if (!receive_right.is_valid()) {
1068     return ExitFailure();
1069   }
1070 
1071   ExceptionHandlerServer exception_handler_server(
1072       std::move(receive_right), !options.mach_service.empty());
1073   base::AutoReset<ExceptionHandlerServer*> reset_g_exception_handler_server(
1074       &g_exception_handler_server, &exception_handler_server);
1075 
1076   struct sigaction old_sigterm_action;
1077   ScopedResetSIGTERM reset_sigterm;
1078   if (!options.mach_service.empty()) {
1079     // When running from launchd, no no-senders notification could ever be
1080     // triggered, because launchd maintains a send right to the service. When
1081     // launchd wants the job to exit, it will send a SIGTERM. See
1082     // launchd.plist(5).
1083     //
1084     // Set up a SIGTERM handler that will call exception_handler_server.Stop().
1085     // This replaces the HandleTerminateSignal handler for SIGTERM.
1086     if (Signals::InstallHandler(
1087             SIGTERM, HandleSIGTERM, 0, &old_sigterm_action)) {
1088       reset_sigterm.reset(&old_sigterm_action);
1089     }
1090   }
1091 
1092   RecordFileLimitAnnotation();
1093 #elif defined(OS_WIN)
1094   // Shut down as late as possible relative to programs we're watching.
1095   if (!SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY))
1096     PLOG(ERROR) << "SetProcessShutdownParameters";
1097 
1098   ExceptionHandlerServer exception_handler_server(!options.pipe_name.empty());
1099 
1100   if (!options.pipe_name.empty()) {
1101     exception_handler_server.SetPipeName(base::UTF8ToUTF16(options.pipe_name));
1102   }
1103 #elif defined(OS_FUCHSIA)
1104   // These handles are logically "moved" into these variables when retrieved by
1105   // zx_take_startup_handle(). Both are given to ExceptionHandlerServer which
1106   // owns them in this process. There is currently no "connect-later" mode on
1107   // Fuchsia, all the binding must be done by the client before starting
1108   // crashpad_handler.
1109   zx::job root_job(zx_take_startup_handle(PA_HND(PA_USER0, 0)));
1110   if (!root_job.is_valid()) {
1111     LOG(ERROR) << "no job handle passed in startup handle 0";
1112     return EXIT_FAILURE;
1113   }
1114 
1115   zx::channel exception_channel(zx_take_startup_handle(PA_HND(PA_USER0, 1)));
1116   if (!exception_channel.is_valid()) {
1117     LOG(ERROR) << "no exception channel handle passed in startup handle 1";
1118     return EXIT_FAILURE;
1119   }
1120 
1121   ExceptionHandlerServer exception_handler_server(std::move(root_job),
1122                                                   std::move(exception_channel));
1123 #elif defined(OS_LINUX) || defined(OS_ANDROID)
1124   ExceptionHandlerServer exception_handler_server;
1125 #endif  // OS_MACOSX
1126 
1127   base::GlobalHistogramAllocator* histogram_allocator = nullptr;
1128   if (!options.metrics_dir.empty()) {
1129     static constexpr char kMetricsName[] = "CrashpadMetrics";
1130     constexpr size_t kMetricsFileSize = 1 << 20;
1131     if (base::GlobalHistogramAllocator::CreateWithActiveFileInDir(
1132             options.metrics_dir, kMetricsFileSize, 0, kMetricsName)) {
1133       histogram_allocator = base::GlobalHistogramAllocator::Get();
1134       histogram_allocator->CreateTrackingHistograms(kMetricsName);
1135     }
1136   }
1137 
1138   Metrics::HandlerLifetimeMilestone(Metrics::LifetimeMilestone::kStarted);
1139 
1140 #if defined(OS_WIN)
1141   if (options.initial_client_data.IsValid()) {
1142     exception_handler_server.InitializeWithInheritedDataForInitialClient(
1143         options.initial_client_data, exception_handler.get());
1144   }
1145 #elif defined(OS_LINUX) || defined(OS_ANDROID)
1146   if (options.initial_client_fd == kInvalidFileHandle ||
1147       !exception_handler_server.InitializeWithClient(
1148           ScopedFileHandle(options.initial_client_fd),
1149           options.shared_client_connection)) {
1150     return ExitFailure();
1151   }
1152 #endif  // OS_WIN
1153 
1154   exception_handler_server.Run(exception_handler.get());
1155 
1156   return EXIT_SUCCESS;
1157 }
1158 
1159 }  // namespace crashpad
1160