handler_main.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  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. #include "handler/handler_main.h"
  15. #include <errno.h>
  16. #include <getopt.h>
  17. #include <stdint.h>
  18. #include <stdlib.h>
  19. #include <sys/types.h>
  20. #include <algorithm>
  21. #include <map>
  22. #include <memory>
  23. #include <string>
  24. #include <utility>
  25. #include <vector>
  26. #include "base/auto_reset.h"
  27. #include "base/compiler_specific.h"
  28. #include "base/files/file_path.h"
  29. #include "base/files/scoped_file.h"
  30. #include "base/logging.h"
  31. #include "base/metrics/persistent_histogram_allocator.h"
  32. #include "base/scoped_generic.h"
  33. #include "base/strings/stringprintf.h"
  34. #include "base/strings/utf_string_conversions.h"
  35. #include "build/build_config.h"
  36. #include "client/crash_report_database.h"
  37. #include "client/crashpad_client.h"
  38. #include "client/crashpad_info.h"
  39. #include "client/prune_crash_reports.h"
  40. #include "client/simple_string_dictionary.h"
  41. #include "handler/crash_report_upload_thread.h"
  42. #include "handler/prune_crash_reports_thread.h"
  43. #include "tools/tool_support.h"
  44. #include "util/file/file_io.h"
  45. #include "util/misc/metrics.h"
  46. #include "util/misc/paths.h"
  47. #include "util/numeric/in_range_cast.h"
  48. #include "util/stdlib/map_insert.h"
  49. #include "util/stdlib/string_number_conversion.h"
  50. #include "util/string/split_string.h"
  51. #include "util/synchronization/semaphore.h"
  52. #if defined(OS_MACOSX)
  53. #include <libgen.h>
  54. #include <signal.h>
  55. #include "base/mac/scoped_mach_port.h"
  56. #include "handler/mac/crash_report_exception_handler.h"
  57. #include "handler/mac/exception_handler_server.h"
  58. #include "handler/mac/file_limit_annotation.h"
  59. #include "util/mach/child_port_handshake.h"
  60. #include "util/mach/mach_extensions.h"
  61. #include "util/posix/close_stdio.h"
  62. #include "util/posix/signals.h"
  63. #elif defined(OS_WIN)
  64. #include <windows.h>
  65. #include "handler/win/crash_report_exception_handler.h"
  66. #include "util/win/exception_handler_server.h"
  67. #include "util/win/handle.h"
  68. #include "util/win/initial_client_data.h"
  69. #include "util/win/session_end_watcher.h"
  70. #endif // OS_MACOSX
  71. namespace crashpad {
  72. namespace {
  73. void Usage(const base::FilePath& me) {
  74. fprintf(stderr,
  75. "Usage: %" PRFilePath " [OPTION]...\n"
  76. "Crashpad's exception handler server.\n"
  77. "\n"
  78. " --annotation=KEY=VALUE set a process annotation in each crash report\n"
  79. " --database=PATH store the crash report database at PATH\n"
  80. #if defined(OS_MACOSX)
  81. " --handshake-fd=FD establish communication with the client over FD\n"
  82. #endif // OS_MACOSX
  83. #if defined(OS_WIN)
  84. " --initial-client-data=HANDLE_request_crash_dump,\n"
  85. " HANDLE_request_non_crash_dump,\n"
  86. " HANDLE_non_crash_dump_completed,\n"
  87. " HANDLE_pipe,\n"
  88. " HANDLE_client_process,\n"
  89. " Address_crash_exception_information,\n"
  90. " Address_non_crash_exception_information,\n"
  91. " Address_debug_critical_section\n"
  92. " use precreated data to register initial client\n"
  93. #endif // OS_WIN
  94. #if defined(OS_MACOSX)
  95. " --mach-service=SERVICE register SERVICE with the bootstrap server\n"
  96. #endif // OS_MACOSX
  97. " --metrics-dir=DIR store metrics files in DIR (only in Chromium)\n"
  98. " --monitor-self run a second handler to catch crashes in the first\n"
  99. " --monitor-self-annotation=KEY=VALUE\n"
  100. " set a module annotation in the handler\n"
  101. " --monitor-self-argument=ARGUMENT\n"
  102. " provide additional arguments to the second handler\n"
  103. " --no-identify-client-via-url\n"
  104. " when uploading crash report, don't add\n"
  105. " client-identifying arguments to URL\n"
  106. " --no-periodic-tasks don't scan for new reports or prune the database\n"
  107. " --no-rate-limit don't rate limit crash uploads\n"
  108. " --no-upload-gzip don't use gzip compression when uploading\n"
  109. #if defined(OS_WIN)
  110. " --pipe-name=PIPE communicate with the client over PIPE\n"
  111. #endif // OS_WIN
  112. #if defined(OS_MACOSX)
  113. " --reset-own-crash-exception-port-to-system-default\n"
  114. " reset the server's exception handler to default\n"
  115. #endif // OS_MACOSX
  116. " --url=URL send crash reports to this Breakpad server URL,\n"
  117. " only if uploads are enabled for the database\n"
  118. " --help display this help and exit\n"
  119. " --version output version information and exit\n",
  120. me.value().c_str());
  121. ToolSupport::UsageTail(me);
  122. }
  123. struct Options {
  124. std::map<std::string, std::string> annotations;
  125. std::map<std::string, std::string> monitor_self_annotations;
  126. std::string url;
  127. base::FilePath database;
  128. base::FilePath metrics_dir;
  129. std::vector<std::string> monitor_self_arguments;
  130. #if defined(OS_MACOSX)
  131. std::string mach_service;
  132. int handshake_fd;
  133. bool reset_own_crash_exception_port_to_system_default;
  134. #elif defined(OS_WIN)
  135. std::string pipe_name;
  136. InitialClientData initial_client_data;
  137. #endif // OS_MACOSX
  138. bool identify_client_via_url;
  139. bool monitor_self;
  140. bool periodic_tasks;
  141. bool rate_limit;
  142. bool upload_gzip;
  143. };
  144. // Splits |key_value| on '=' and inserts the resulting key and value into |map|.
  145. // If |key_value| has the wrong format, logs an error and returns false. If the
  146. // key is already in the map, logs a warning, replaces the existing value, and
  147. // returns true. If the key and value were inserted into the map, returns true.
  148. // |argument| is used to give context to logged messages.
  149. bool AddKeyValueToMap(std::map<std::string, std::string>* map,
  150. const std::string& key_value,
  151. const char* argument) {
  152. std::string key;
  153. std::string value;
  154. if (!SplitStringFirst(key_value, '=', &key, &value)) {
  155. LOG(ERROR) << argument << " requires KEY=VALUE";
  156. return false;
  157. }
  158. std::string old_value;
  159. if (!MapInsertOrReplace(map, key, value, &old_value)) {
  160. LOG(WARNING) << argument << " has duplicate key " << key
  161. << ", discarding value " << old_value;
  162. }
  163. return true;
  164. }
  165. // Calls Metrics::HandlerLifetimeMilestone, but only on the first call. This is
  166. // to prevent multiple exit events from inadvertently being recorded, which
  167. // might happen if a crash occurs during destruction in what would otherwise be
  168. // a normal exit, or if a CallMetricsRecordNormalExit object is destroyed after
  169. // something else logs an exit event.
  170. void MetricsRecordExit(Metrics::LifetimeMilestone milestone) {
  171. static bool once = [](Metrics::LifetimeMilestone milestone) {
  172. Metrics::HandlerLifetimeMilestone(milestone);
  173. return true;
  174. }(milestone);
  175. ALLOW_UNUSED_LOCAL(once);
  176. }
  177. // Calls MetricsRecordExit() to record a failure, and returns EXIT_FAILURE for
  178. // the convenience of callers in main() which can simply write “return
  179. // ExitFailure();”.
  180. int ExitFailure() {
  181. MetricsRecordExit(Metrics::LifetimeMilestone::kFailed);
  182. return EXIT_FAILURE;
  183. }
  184. class CallMetricsRecordNormalExit {
  185. public:
  186. CallMetricsRecordNormalExit() {}
  187. ~CallMetricsRecordNormalExit() {
  188. MetricsRecordExit(Metrics::LifetimeMilestone::kExitedNormally);
  189. }
  190. private:
  191. DISALLOW_COPY_AND_ASSIGN(CallMetricsRecordNormalExit);
  192. };
  193. #if defined(OS_MACOSX)
  194. void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) {
  195. MetricsRecordExit(Metrics::LifetimeMilestone::kCrashed);
  196. // Is siginfo->si_code useful? The only interesting values on macOS are 0 (not
  197. // useful, signals generated asynchronously such as by kill() or raise()) and
  198. // small positive numbers (useful, signal generated via a hardware fault). The
  199. // standard specifies these other constants, and while xnu never uses them,
  200. // they are intended to denote signals generated asynchronously and are
  201. // included here. Additionally, existing practice on other systems
  202. // (acknowledged by the standard) is for negative numbers to indicate that a
  203. // signal was generated asynchronously. Although xnu does not do this, allow
  204. // for the possibility for completeness.
  205. bool si_code_valid = !(siginfo->si_code <= 0 ||
  206. siginfo->si_code == SI_USER ||
  207. siginfo->si_code == SI_QUEUE ||
  208. siginfo->si_code == SI_TIMER ||
  209. siginfo->si_code == SI_ASYNCIO ||
  210. siginfo->si_code == SI_MESGQ);
  211. // 0x5343 = 'SC', signifying “signal and code”, disambiguates from the schema
  212. // used by ExceptionCodeForMetrics(). That system primarily uses Mach
  213. // exception types and codes, which are not available to a POSIX signal
  214. // handler. It does provide a way to encode only signal numbers, but does so
  215. // with the understanding that certain “raw” signals would not be encountered
  216. // without a Mach exception. Furthermore, it does not allow siginfo->si_code
  217. // to be encoded, because that’s not available to Mach exception handlers. It
  218. // would be a shame to lose that information available to a POSIX signal
  219. // handler.
  220. int metrics_code = 0x53430000 | (InRangeCast<uint8_t>(sig, 0xff) << 8);
  221. if (si_code_valid) {
  222. metrics_code |= InRangeCast<uint8_t>(siginfo->si_code, 0xff);
  223. }
  224. Metrics::HandlerCrashed(metrics_code);
  225. Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, nullptr);
  226. }
  227. void HandleTerminateSignal(int sig, siginfo_t* siginfo, void* context) {
  228. MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated);
  229. Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, nullptr);
  230. }
  231. void ReinstallCrashHandler() {
  232. // This is used to re-enable the metrics-recording crash handler after
  233. // MonitorSelf() sets up a Crashpad exception handler. On macOS, the
  234. // metrics-recording handler uses signals and the Crashpad handler uses Mach
  235. // exceptions, so there’s nothing to re-enable.
  236. }
  237. void InstallCrashHandler() {
  238. Signals::InstallCrashHandlers(HandleCrashSignal, 0, nullptr);
  239. // Not a crash handler, but close enough.
  240. Signals::InstallTerminateHandlers(HandleTerminateSignal, 0, nullptr);
  241. }
  242. struct ResetSIGTERMTraits {
  243. static struct sigaction* InvalidValue() {
  244. return nullptr;
  245. }
  246. static void Free(struct sigaction* sa) {
  247. int rv = sigaction(SIGTERM, sa, nullptr);
  248. PLOG_IF(ERROR, rv != 0) << "sigaction";
  249. }
  250. };
  251. using ScopedResetSIGTERM =
  252. base::ScopedGeneric<struct sigaction*, ResetSIGTERMTraits>;
  253. ExceptionHandlerServer* g_exception_handler_server;
  254. // This signal handler is only operative when being run from launchd.
  255. void HandleSIGTERM(int sig, siginfo_t* siginfo, void* context) {
  256. // Don’t call MetricsRecordExit(). This is part of the normal exit path when
  257. // running from launchd.
  258. DCHECK(g_exception_handler_server);
  259. g_exception_handler_server->Stop();
  260. }
  261. #elif defined(OS_WIN)
  262. LONG(WINAPI* g_original_exception_filter)(EXCEPTION_POINTERS*) = nullptr;
  263. LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) {
  264. MetricsRecordExit(Metrics::LifetimeMilestone::kCrashed);
  265. Metrics::HandlerCrashed(exception_pointers->ExceptionRecord->ExceptionCode);
  266. if (g_original_exception_filter)
  267. return g_original_exception_filter(exception_pointers);
  268. else
  269. return EXCEPTION_CONTINUE_SEARCH;
  270. }
  271. // Handles events like Control-C and Control-Break on a console.
  272. BOOL WINAPI ConsoleHandler(DWORD console_event) {
  273. MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated);
  274. return false;
  275. }
  276. // Handles a WM_ENDSESSION message sent when the user session is ending.
  277. class TerminateHandler final : public SessionEndWatcher {
  278. public:
  279. TerminateHandler() : SessionEndWatcher() {}
  280. ~TerminateHandler() override {}
  281. private:
  282. // SessionEndWatcher:
  283. void SessionEnding() override {
  284. MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated);
  285. }
  286. DISALLOW_COPY_AND_ASSIGN(TerminateHandler);
  287. };
  288. void ReinstallCrashHandler() {
  289. // This is used to re-enable the metrics-recording crash handler after
  290. // MonitorSelf() sets up a Crashpad exception handler. The Crashpad handler
  291. // takes over the UnhandledExceptionFilter, so reinstall the metrics-recording
  292. // one.
  293. g_original_exception_filter =
  294. SetUnhandledExceptionFilter(&UnhandledExceptionHandler);
  295. }
  296. void InstallCrashHandler() {
  297. ReinstallCrashHandler();
  298. // These are termination handlers, not crash handlers, but that’s close
  299. // enough. Note that destroying the TerminateHandler would wait for its thread
  300. // to exit, which isn’t necessary or desirable.
  301. SetConsoleCtrlHandler(ConsoleHandler, true);
  302. static TerminateHandler* terminate_handler = new TerminateHandler();
  303. ALLOW_UNUSED_LOCAL(terminate_handler);
  304. }
  305. #endif // OS_MACOSX
  306. void MonitorSelf(const Options& options) {
  307. base::FilePath executable_path;
  308. if (!Paths::Executable(&executable_path)) {
  309. return;
  310. }
  311. if (std::find(options.monitor_self_arguments.begin(),
  312. options.monitor_self_arguments.end(),
  313. "--monitor-self") != options.monitor_self_arguments.end()) {
  314. LOG(WARNING) << "--monitor-self-argument=--monitor-self is not supported";
  315. return;
  316. }
  317. std::vector<std::string> extra_arguments(options.monitor_self_arguments);
  318. if (!options.identify_client_via_url) {
  319. extra_arguments.push_back("--no-identify-client-via-url");
  320. }
  321. extra_arguments.push_back("--no-periodic-tasks");
  322. if (!options.rate_limit) {
  323. extra_arguments.push_back("--no-rate-limit");
  324. }
  325. if (!options.upload_gzip) {
  326. extra_arguments.push_back("--no-upload-gzip");
  327. }
  328. for (const auto& iterator : options.monitor_self_annotations) {
  329. extra_arguments.push_back(
  330. base::StringPrintf("--monitor-self-annotation=%s=%s",
  331. iterator.first.c_str(),
  332. iterator.second.c_str()));
  333. }
  334. // Don’t use options.metrics_dir. The current implementation only allows one
  335. // instance of crashpad_handler to be writing metrics at a time, and it should
  336. // be the primary instance.
  337. CrashpadClient crashpad_client;
  338. if (!crashpad_client.StartHandler(executable_path,
  339. options.database,
  340. base::FilePath(),
  341. options.url,
  342. options.annotations,
  343. extra_arguments,
  344. true,
  345. false)) {
  346. return;
  347. }
  348. // Make sure that appropriate metrics will be recorded on crash before this
  349. // process is terminated.
  350. ReinstallCrashHandler();
  351. }
  352. } // namespace
  353. int HandlerMain(int argc,
  354. char* argv[],
  355. const UserStreamDataSources* user_stream_sources) {
  356. InstallCrashHandler();
  357. CallMetricsRecordNormalExit metrics_record_normal_exit;
  358. const base::FilePath argv0(
  359. ToolSupport::CommandLineArgumentToFilePathStringType(argv[0]));
  360. const base::FilePath me(argv0.BaseName());
  361. enum OptionFlags {
  362. // Long options without short equivalents.
  363. kOptionLastChar = 255,
  364. kOptionAnnotation,
  365. kOptionDatabase,
  366. #if defined(OS_MACOSX)
  367. kOptionHandshakeFD,
  368. #endif // OS_MACOSX
  369. #if defined(OS_WIN)
  370. kOptionInitialClientData,
  371. #endif // OS_WIN
  372. #if defined(OS_MACOSX)
  373. kOptionMachService,
  374. #endif // OS_MACOSX
  375. kOptionMetrics,
  376. kOptionMonitorSelf,
  377. kOptionMonitorSelfAnnotation,
  378. kOptionMonitorSelfArgument,
  379. kOptionNoIdentifyClientViaUrl,
  380. kOptionNoPeriodicTasks,
  381. kOptionNoRateLimit,
  382. kOptionNoUploadGzip,
  383. #if defined(OS_WIN)
  384. kOptionPipeName,
  385. #endif // OS_WIN
  386. #if defined(OS_MACOSX)
  387. kOptionResetOwnCrashExceptionPortToSystemDefault,
  388. #endif // OS_MACOSX
  389. kOptionURL,
  390. // Standard options.
  391. kOptionHelp = -2,
  392. kOptionVersion = -3,
  393. };
  394. static constexpr option long_options[] = {
  395. {"annotation", required_argument, nullptr, kOptionAnnotation},
  396. {"database", required_argument, nullptr, kOptionDatabase},
  397. #if defined(OS_MACOSX)
  398. {"handshake-fd", required_argument, nullptr, kOptionHandshakeFD},
  399. #endif // OS_MACOSX
  400. #if defined(OS_WIN)
  401. {"initial-client-data",
  402. required_argument,
  403. nullptr,
  404. kOptionInitialClientData},
  405. #endif // OS_MACOSX
  406. #if defined(OS_MACOSX)
  407. {"mach-service", required_argument, nullptr, kOptionMachService},
  408. #endif // OS_MACOSX
  409. {"metrics-dir", required_argument, nullptr, kOptionMetrics},
  410. {"monitor-self", no_argument, nullptr, kOptionMonitorSelf},
  411. {"monitor-self-annotation",
  412. required_argument,
  413. nullptr,
  414. kOptionMonitorSelfAnnotation},
  415. {"monitor-self-argument",
  416. required_argument,
  417. nullptr,
  418. kOptionMonitorSelfArgument},
  419. {"no-identify-client-via-url",
  420. no_argument,
  421. nullptr,
  422. kOptionNoIdentifyClientViaUrl},
  423. {"no-periodic-tasks", no_argument, nullptr, kOptionNoPeriodicTasks},
  424. {"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit},
  425. {"no-upload-gzip", no_argument, nullptr, kOptionNoUploadGzip},
  426. #if defined(OS_WIN)
  427. {"pipe-name", required_argument, nullptr, kOptionPipeName},
  428. #endif // OS_WIN
  429. #if defined(OS_MACOSX)
  430. {"reset-own-crash-exception-port-to-system-default",
  431. no_argument,
  432. nullptr,
  433. kOptionResetOwnCrashExceptionPortToSystemDefault},
  434. #endif // OS_MACOSX
  435. {"url", required_argument, nullptr, kOptionURL},
  436. {"help", no_argument, nullptr, kOptionHelp},
  437. {"version", no_argument, nullptr, kOptionVersion},
  438. {nullptr, 0, nullptr, 0},
  439. };
  440. Options options = {};
  441. #if defined(OS_MACOSX)
  442. options.handshake_fd = -1;
  443. #endif
  444. options.identify_client_via_url = true;
  445. options.periodic_tasks = true;
  446. options.rate_limit = true;
  447. options.upload_gzip = true;
  448. int opt;
  449. while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) {
  450. switch (opt) {
  451. case kOptionAnnotation: {
  452. if (!AddKeyValueToMap(&options.annotations, optarg, "--annotation")) {
  453. return ExitFailure();
  454. }
  455. break;
  456. }
  457. case kOptionDatabase: {
  458. options.database = base::FilePath(
  459. ToolSupport::CommandLineArgumentToFilePathStringType(optarg));
  460. break;
  461. }
  462. #if defined(OS_MACOSX)
  463. case kOptionHandshakeFD: {
  464. if (!StringToNumber(optarg, &options.handshake_fd) ||
  465. options.handshake_fd < 0) {
  466. ToolSupport::UsageHint(me,
  467. "--handshake-fd requires a file descriptor");
  468. return ExitFailure();
  469. }
  470. break;
  471. }
  472. case kOptionMachService: {
  473. options.mach_service = optarg;
  474. break;
  475. }
  476. #endif // OS_MACOSX
  477. #if defined(OS_WIN)
  478. case kOptionInitialClientData: {
  479. if (!options.initial_client_data.InitializeFromString(optarg)) {
  480. ToolSupport::UsageHint(
  481. me, "failed to parse --initial-client-data");
  482. return ExitFailure();
  483. }
  484. break;
  485. }
  486. #endif // OS_WIN
  487. case kOptionMetrics: {
  488. options.metrics_dir = base::FilePath(
  489. ToolSupport::CommandLineArgumentToFilePathStringType(optarg));
  490. break;
  491. }
  492. case kOptionMonitorSelf: {
  493. options.monitor_self = true;
  494. break;
  495. }
  496. case kOptionMonitorSelfAnnotation: {
  497. if (!AddKeyValueToMap(&options.monitor_self_annotations,
  498. optarg,
  499. "--monitor-self-annotation")) {
  500. return ExitFailure();
  501. }
  502. break;
  503. }
  504. case kOptionMonitorSelfArgument: {
  505. options.monitor_self_arguments.push_back(optarg);
  506. break;
  507. }
  508. case kOptionNoIdentifyClientViaUrl: {
  509. options.identify_client_via_url = false;
  510. break;
  511. }
  512. case kOptionNoPeriodicTasks: {
  513. options.periodic_tasks = false;
  514. break;
  515. }
  516. case kOptionNoRateLimit: {
  517. options.rate_limit = false;
  518. break;
  519. }
  520. case kOptionNoUploadGzip: {
  521. options.upload_gzip = false;
  522. break;
  523. }
  524. #if defined(OS_WIN)
  525. case kOptionPipeName: {
  526. options.pipe_name = optarg;
  527. break;
  528. }
  529. #endif // OS_WIN
  530. #if defined(OS_MACOSX)
  531. case kOptionResetOwnCrashExceptionPortToSystemDefault: {
  532. options.reset_own_crash_exception_port_to_system_default = true;
  533. break;
  534. }
  535. #endif // OS_MACOSX
  536. case kOptionURL: {
  537. options.url = optarg;
  538. break;
  539. }
  540. case kOptionHelp: {
  541. Usage(me);
  542. MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly);
  543. return EXIT_SUCCESS;
  544. }
  545. case kOptionVersion: {
  546. ToolSupport::Version(me);
  547. MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly);
  548. return EXIT_SUCCESS;
  549. }
  550. default: {
  551. ToolSupport::UsageHint(me, nullptr);
  552. return ExitFailure();
  553. }
  554. }
  555. }
  556. argc -= optind;
  557. argv += optind;
  558. #if defined(OS_MACOSX)
  559. if (options.handshake_fd < 0 && options.mach_service.empty()) {
  560. ToolSupport::UsageHint(me, "--handshake-fd or --mach-service is required");
  561. return ExitFailure();
  562. }
  563. if (options.handshake_fd >= 0 && !options.mach_service.empty()) {
  564. ToolSupport::UsageHint(
  565. me, "--handshake-fd and --mach-service are incompatible");
  566. return ExitFailure();
  567. }
  568. #elif defined(OS_WIN)
  569. if (!options.initial_client_data.IsValid() && options.pipe_name.empty()) {
  570. ToolSupport::UsageHint(me,
  571. "--initial-client-data or --pipe-name is required");
  572. return ExitFailure();
  573. }
  574. if (options.initial_client_data.IsValid() && !options.pipe_name.empty()) {
  575. ToolSupport::UsageHint(
  576. me, "--initial-client-data and --pipe-name are incompatible");
  577. return ExitFailure();
  578. }
  579. #endif // OS_MACOSX
  580. if (options.database.empty()) {
  581. ToolSupport::UsageHint(me, "--database is required");
  582. return ExitFailure();
  583. }
  584. if (argc) {
  585. ToolSupport::UsageHint(me, nullptr);
  586. return ExitFailure();
  587. }
  588. #if defined(OS_MACOSX)
  589. if (options.reset_own_crash_exception_port_to_system_default) {
  590. CrashpadClient::UseSystemDefaultHandler();
  591. }
  592. #endif // OS_MACOSX
  593. if (options.monitor_self) {
  594. MonitorSelf(options);
  595. }
  596. if (!options.monitor_self_annotations.empty()) {
  597. // Establish these annotations even if --monitor-self is not present, in
  598. // case something such as generate_dump wants to try to access them later.
  599. //
  600. // If the handler is part of a multi-purpose executable, simple annotations
  601. // may already be present for this module. If they are, use them.
  602. CrashpadInfo* crashpad_info = CrashpadInfo::GetCrashpadInfo();
  603. SimpleStringDictionary* module_annotations =
  604. crashpad_info->simple_annotations();
  605. if (!module_annotations) {
  606. module_annotations = new SimpleStringDictionary();
  607. crashpad_info->set_simple_annotations(module_annotations);
  608. }
  609. for (const auto& iterator : options.monitor_self_annotations) {
  610. module_annotations->SetKeyValue(iterator.first.c_str(),
  611. iterator.second.c_str());
  612. }
  613. }
  614. #if defined(OS_MACOSX)
  615. if (options.mach_service.empty()) {
  616. // Don’t do this when being run by launchd. See launchd.plist(5).
  617. CloseStdinAndStdout();
  618. }
  619. base::mac::ScopedMachReceiveRight receive_right;
  620. if (options.handshake_fd >= 0) {
  621. receive_right.reset(
  622. ChildPortHandshake::RunServerForFD(
  623. base::ScopedFD(options.handshake_fd),
  624. ChildPortHandshake::PortRightType::kReceiveRight));
  625. } else if (!options.mach_service.empty()) {
  626. receive_right = BootstrapCheckIn(options.mach_service);
  627. }
  628. if (!receive_right.is_valid()) {
  629. return ExitFailure();
  630. }
  631. ExceptionHandlerServer exception_handler_server(
  632. std::move(receive_right), !options.mach_service.empty());
  633. base::AutoReset<ExceptionHandlerServer*> reset_g_exception_handler_server(
  634. &g_exception_handler_server, &exception_handler_server);
  635. struct sigaction old_sigterm_action;
  636. ScopedResetSIGTERM reset_sigterm;
  637. if (!options.mach_service.empty()) {
  638. // When running from launchd, no no-senders notification could ever be
  639. // triggered, because launchd maintains a send right to the service. When
  640. // launchd wants the job to exit, it will send a SIGTERM. See
  641. // launchd.plist(5).
  642. //
  643. // Set up a SIGTERM handler that will call exception_handler_server.Stop().
  644. // This replaces the HandleTerminateSignal handler for SIGTERM.
  645. if (Signals::InstallHandler(
  646. SIGTERM, HandleSIGTERM, 0, &old_sigterm_action)) {
  647. reset_sigterm.reset(&old_sigterm_action);
  648. }
  649. }
  650. RecordFileLimitAnnotation();
  651. #elif defined(OS_WIN)
  652. // Shut down as late as possible relative to programs we're watching.
  653. if (!SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY))
  654. PLOG(ERROR) << "SetProcessShutdownParameters";
  655. ExceptionHandlerServer exception_handler_server(!options.pipe_name.empty());
  656. if (!options.pipe_name.empty()) {
  657. exception_handler_server.SetPipeName(base::UTF8ToUTF16(options.pipe_name));
  658. }
  659. #endif // OS_MACOSX
  660. base::GlobalHistogramAllocator* histogram_allocator = nullptr;
  661. if (!options.metrics_dir.empty()) {
  662. static constexpr char kMetricsName[] = "CrashpadMetrics";
  663. constexpr size_t kMetricsFileSize = 1 << 20;
  664. if (base::GlobalHistogramAllocator::CreateWithActiveFileInDir(
  665. options.metrics_dir, kMetricsFileSize, 0, kMetricsName)) {
  666. histogram_allocator = base::GlobalHistogramAllocator::Get();
  667. histogram_allocator->CreateTrackingHistograms(kMetricsName);
  668. }
  669. }
  670. Metrics::HandlerLifetimeMilestone(Metrics::LifetimeMilestone::kStarted);
  671. std::unique_ptr<CrashReportDatabase> database(
  672. CrashReportDatabase::Initialize(options.database));
  673. if (!database) {
  674. return ExitFailure();
  675. }
  676. // TODO(scottmg): options.rate_limit should be removed when we have a
  677. // configurable database setting to control upload limiting.
  678. // See https://crashpad.chromium.org/bug/23.
  679. CrashReportUploadThread::Options upload_thread_options;
  680. upload_thread_options.identify_client_via_url =
  681. options.identify_client_via_url;
  682. upload_thread_options.rate_limit = options.rate_limit;
  683. upload_thread_options.upload_gzip = options.upload_gzip;
  684. upload_thread_options.watch_pending_reports = options.periodic_tasks;
  685. CrashReportUploadThread upload_thread(database.get(),
  686. options.url,
  687. upload_thread_options);
  688. upload_thread.Start();
  689. std::unique_ptr<PruneCrashReportThread> prune_thread;
  690. if (options.periodic_tasks) {
  691. prune_thread.reset(new PruneCrashReportThread(
  692. database.get(), PruneCondition::GetDefault()));
  693. prune_thread->Start();
  694. }
  695. CrashReportExceptionHandler exception_handler(database.get(),
  696. &upload_thread,
  697. &options.annotations,
  698. user_stream_sources);
  699. #if defined(OS_WIN)
  700. if (options.initial_client_data.IsValid()) {
  701. exception_handler_server.InitializeWithInheritedDataForInitialClient(
  702. options.initial_client_data, &exception_handler);
  703. }
  704. #endif // OS_WIN
  705. exception_handler_server.Run(&exception_handler);
  706. upload_thread.Stop();
  707. if (prune_thread) {
  708. prune_thread->Stop();
  709. }
  710. return EXIT_SUCCESS;
  711. }
  712. } // namespace crashpad