Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(492)

Side by Side Diff: third_party/crashpad/crashpad/handler/handler_main.cc

Issue 2710663006: Update Crashpad to 4a2043ea65e2641ef1a921801c0aaa15ada02fc7 (Closed)
Patch Set: Update Crashpad to 4a2043ea65e2 Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and 12 // See the License for the specific language governing permissions and
13 // limitations under the License. 13 // limitations under the License.
14 14
15 #include "handler/handler_main.h" 15 #include "handler/handler_main.h"
16 16
17 #include <errno.h> 17 #include <errno.h>
18 #include <getopt.h> 18 #include <getopt.h>
19 #include <stdint.h> 19 #include <stdint.h>
20 #include <stdlib.h> 20 #include <stdlib.h>
21 #include <sys/types.h> 21 #include <sys/types.h>
22 22
23 #include <map> 23 #include <map>
24 #include <memory> 24 #include <memory>
25 #include <string> 25 #include <string>
26 #include <utility> 26 #include <utility>
27 #include <vector>
27 28
28 #include "base/auto_reset.h" 29 #include "base/auto_reset.h"
30 #include "base/compiler_specific.h"
29 #include "base/files/file_path.h" 31 #include "base/files/file_path.h"
30 #include "base/files/scoped_file.h" 32 #include "base/files/scoped_file.h"
31 #include "base/logging.h" 33 #include "base/logging.h"
32 #include "base/metrics/persistent_histogram_allocator.h" 34 #include "base/metrics/persistent_histogram_allocator.h"
33 #include "base/scoped_generic.h" 35 #include "base/scoped_generic.h"
34 #include "base/strings/utf_string_conversions.h" 36 #include "base/strings/utf_string_conversions.h"
35 #include "build/build_config.h" 37 #include "build/build_config.h"
36 #include "client/crash_report_database.h" 38 #include "client/crash_report_database.h"
37 #include "client/crashpad_client.h" 39 #include "client/crashpad_client.h"
38 #include "client/prune_crash_reports.h" 40 #include "client/prune_crash_reports.h"
(...skipping 18 matching lines...) Expand all
57 #include "util/mach/child_port_handshake.h" 59 #include "util/mach/child_port_handshake.h"
58 #include "util/mach/mach_extensions.h" 60 #include "util/mach/mach_extensions.h"
59 #include "util/posix/close_stdio.h" 61 #include "util/posix/close_stdio.h"
60 #elif defined(OS_WIN) 62 #elif defined(OS_WIN)
61 #include <windows.h> 63 #include <windows.h>
62 64
63 #include "handler/win/crash_report_exception_handler.h" 65 #include "handler/win/crash_report_exception_handler.h"
64 #include "util/win/exception_handler_server.h" 66 #include "util/win/exception_handler_server.h"
65 #include "util/win/handle.h" 67 #include "util/win/handle.h"
66 #include "util/win/initial_client_data.h" 68 #include "util/win/initial_client_data.h"
69 #include "util/win/session_end_watcher.h"
67 #endif // OS_MACOSX 70 #endif // OS_MACOSX
68 71
69 namespace crashpad { 72 namespace crashpad {
70 73
71 namespace { 74 namespace {
72 75
73 void Usage(const base::FilePath& me) { 76 void Usage(const base::FilePath& me) {
74 fprintf(stderr, 77 fprintf(stderr,
75 "Usage: %" PRFilePath " [OPTION]...\n" 78 "Usage: %" PRFilePath " [OPTION]...\n"
76 "Crashpad's exception handler server.\n" 79 "Crashpad's exception handler server.\n"
77 "\n" 80 "\n"
78 " --annotation=KEY=VALUE set a process annotation in each crash report\n" 81 " --annotation=KEY=VALUE set a process annotation in each crash report\n"
79 " --database=PATH store the crash report database at PATH\n" 82 " --database=PATH store the crash report database at PATH\n"
80 #if defined(OS_MACOSX) 83 #if defined(OS_MACOSX)
81 " --handshake-fd=FD establish communication with the client over FD\n " 84 " --handshake-fd=FD establish communication with the client over FD\n "
82 " --mach-service=SERVICE register SERVICE with the bootstrap server\n" 85 " --mach-service=SERVICE register SERVICE with the bootstrap server\n"
83 #elif defined(OS_WIN) 86 #elif defined(OS_WIN)
84 " --initial-client-data=HANDLE_request_crash_dump,\n" 87 " --initial-client-data=HANDLE_request_crash_dump,\n"
85 " HANDLE_request_non_crash_dump,\n" 88 " HANDLE_request_non_crash_dump,\n"
86 " HANDLE_non_crash_dump_completed,\n" 89 " HANDLE_non_crash_dump_completed,\n"
87 " HANDLE_pipe,\n" 90 " HANDLE_pipe,\n"
88 " HANDLE_client_process,\n" 91 " HANDLE_client_process,\n"
89 " Address_crash_exception_information,\n" 92 " Address_crash_exception_information,\n"
90 " Address_non_crash_exception_information,\n" 93 " Address_non_crash_exception_information,\n"
91 " Address_debug_critical_section\n" 94 " Address_debug_critical_section\n"
92 " use precreated data to register initial client\n" 95 " use precreated data to register initial client\n"
93 #endif // OS_MACOSX 96 #endif // OS_MACOSX
94 " --metrics-dir=DIR store metrics files in DIR (only in Chromium)\n" 97 " --metrics-dir=DIR store metrics files in DIR (only in Chromium)\n"
95 " --no-rate-limit don't rate limit crash uploads\n" 98 " --no-rate-limit don't rate limit crash uploads\n"
99 " --no-upload-gzip don't use gzip compression when uploading\n"
96 #if defined(OS_MACOSX) 100 #if defined(OS_MACOSX)
97 " --reset-own-crash-exception-port-to-system-default\n" 101 " --reset-own-crash-exception-port-to-system-default\n"
98 " reset the server's exception handler to default\n " 102 " reset the server's exception handler to default\n "
99 #elif defined(OS_WIN) 103 #elif defined(OS_WIN)
100 " --pipe-name=PIPE communicate with the client over PIPE\n" 104 " --pipe-name=PIPE communicate with the client over PIPE\n"
101 #endif // OS_MACOSX 105 #endif // OS_MACOSX
102 " --url=URL send crash reports to this Breakpad server URL,\n " 106 " --url=URL send crash reports to this Breakpad server URL,\n "
103 " only if uploads are enabled for the database\n" 107 " only if uploads are enabled for the database\n"
104 " --help display this help and exit\n" 108 " --help display this help and exit\n"
105 " --version output version information and exit\n", 109 " --version output version information and exit\n",
106 me.value().c_str()); 110 me.value().c_str());
107 ToolSupport::UsageTail(me); 111 ToolSupport::UsageTail(me);
108 } 112 }
109 113
114 // Calls Metrics::HandlerLifetimeMilestone, but only on the first call. This is
115 // to prevent multiple exit events from inadvertently being recorded, which
116 // might happen if a crash occurs during destruction in what would otherwise be
117 // a normal exit, or if a CallMetricsRecordNormalExit object is destroyed after
118 // something else logs an exit event.
119 void MetricsRecordExit(Metrics::LifetimeMilestone milestone) {
120 static bool once = [](Metrics::LifetimeMilestone milestone) {
121 Metrics::HandlerLifetimeMilestone(milestone);
122 return true;
123 }(milestone);
124 ALLOW_UNUSED_LOCAL(once);
125 }
126
127 // Calls MetricsRecordExit() to record a failure, and returns EXIT_FAILURE for
128 // the convenience of callers in main() which can simply write “return
129 // ExitFailure();”.
130 int ExitFailure() {
131 MetricsRecordExit(Metrics::LifetimeMilestone::kFailed);
132 return EXIT_FAILURE;
133 }
134
135 class CallMetricsRecordNormalExit {
136 public:
137 CallMetricsRecordNormalExit() {}
138 ~CallMetricsRecordNormalExit() {
139 MetricsRecordExit(Metrics::LifetimeMilestone::kExitedNormally);
140 }
141
142 private:
143 DISALLOW_COPY_AND_ASSIGN(CallMetricsRecordNormalExit);
144 };
145
110 #if defined(OS_MACOSX) 146 #if defined(OS_MACOSX)
111 147
112 struct sigaction g_original_crash_sigaction[NSIG]; 148 void InstallSignalHandler(const std::vector<int>& signals,
149 void (*handler)(int, siginfo_t*, void*)) {
150 struct sigaction sa = {};
151 sigemptyset(&sa.sa_mask);
152 sa.sa_flags = SA_SIGINFO;
153 sa.sa_sigaction = handler;
154
155 for (int sig : signals) {
156 int rv = sigaction(sig, &sa, nullptr);
157 PCHECK(rv == 0) << "sigaction " << sig;
158 }
159 }
160
161 void RestoreDefaultSignalHandler(int sig) {
162 struct sigaction sa = {};
163 sigemptyset(&sa.sa_mask);
164 sa.sa_flags = 0;
165 sa.sa_handler = SIG_DFL;
166 int rv = sigaction(sig, &sa, nullptr);
167 DPLOG_IF(ERROR, rv != 0) << "sigaction " << sig;
168 ALLOW_UNUSED_LOCAL(rv);
169 }
113 170
114 void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) { 171 void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) {
172 MetricsRecordExit(Metrics::LifetimeMilestone::kCrashed);
173
115 // Is siginfo->si_code useful? The only interesting values on macOS are 0 (not 174 // Is siginfo->si_code useful? The only interesting values on macOS are 0 (not
116 // useful, signals generated asynchronously such as by kill() or raise()) and 175 // useful, signals generated asynchronously such as by kill() or raise()) and
117 // small positive numbers (useful, signal generated via a hardware fault). The 176 // small positive numbers (useful, signal generated via a hardware fault). The
118 // standard specifies these other constants, and while xnu never uses them, 177 // standard specifies these other constants, and while xnu never uses them,
119 // they are intended to denote signals generated asynchronously and are 178 // they are intended to denote signals generated asynchronously and are
120 // included here. Additionally, existing practice on other systems 179 // included here. Additionally, existing practice on other systems
121 // (acknowledged by the standard) is for negative numbers to indicate that a 180 // (acknowledged by the standard) is for negative numbers to indicate that a
122 // signal was generated asynchronously. Although xnu does not do this, allow 181 // signal was generated asynchronously. Although xnu does not do this, allow
123 // for the possibility for completeness. 182 // for the possibility for completeness.
124 bool si_code_valid = !(siginfo->si_code <= 0 || 183 bool si_code_valid = !(siginfo->si_code <= 0 ||
(...skipping 11 matching lines...) Expand all
136 // without a Mach exception. Furthermore, it does not allow siginfo->si_code 195 // without a Mach exception. Furthermore, it does not allow siginfo->si_code
137 // to be encoded, because that’s not available to Mach exception handlers. It 196 // to be encoded, because that’s not available to Mach exception handlers. It
138 // would be a shame to lose that information available to a POSIX signal 197 // would be a shame to lose that information available to a POSIX signal
139 // handler. 198 // handler.
140 int metrics_code = 0x53430000 | (InRangeCast<uint8_t>(sig, 0xff) << 8); 199 int metrics_code = 0x53430000 | (InRangeCast<uint8_t>(sig, 0xff) << 8);
141 if (si_code_valid) { 200 if (si_code_valid) {
142 metrics_code |= InRangeCast<uint8_t>(siginfo->si_code, 0xff); 201 metrics_code |= InRangeCast<uint8_t>(siginfo->si_code, 0xff);
143 } 202 }
144 Metrics::HandlerCrashed(metrics_code); 203 Metrics::HandlerCrashed(metrics_code);
145 204
146 // Restore the previous signal handler. 205 RestoreDefaultSignalHandler(sig);
147 DCHECK_GT(sig, 0);
148 DCHECK_LT(static_cast<size_t>(sig), arraysize(g_original_crash_sigaction));
149 struct sigaction* osa = &g_original_crash_sigaction[sig];
150 int rv = sigaction(sig, osa, nullptr);
151 DPLOG_IF(ERROR, rv != 0) << "sigaction " << sig;
152 206
153 // If the signal was received synchronously resulting from a hardware fault, 207 // If the signal was received synchronously resulting from a hardware fault,
154 // returning from the signal handler will cause the kernel to re-raise it, 208 // returning from the signal handler will cause the kernel to re-raise it,
155 // because this handler hasn’t done anything to alleviate the condition that 209 // because this handler hasn’t done anything to alleviate the condition that
156 // caused the signal to be raised in the first place. With the old signal 210 // caused the signal to be raised in the first place. With the default signal
157 // handler in place (expected to be SIG_DFL), it will cause the same behavior 211 // handler in place, it will cause the same behavior to be taken as though
158 // to be taken as though this signal handler had never been installed at all 212 // this signal handler had never been installed at all (expected to be a
159 // (expected to be a crash). This is ideal, because the signal is re-raised 213 // crash). This is ideal, because the signal is re-raised with the same
160 // with the same properties and from the same context that initially triggered 214 // properties and from the same context that initially triggered it, providing
161 // it, providing the best debugging experience. 215 // the best debugging experience.
162 216
163 if ((sig != SIGILL && sig != SIGFPE && sig != SIGBUS && sig != SIGSEGV) || 217 if ((sig != SIGILL && sig != SIGFPE && sig != SIGBUS && sig != SIGSEGV) ||
164 !si_code_valid) { 218 !si_code_valid) {
165 // Signals received other than via hardware faults, such as those raised 219 // Signals received other than via hardware faults, such as those raised
166 // asynchronously via kill() and raise(), and those arising via hardware 220 // asynchronously via kill() and raise(), and those arising via hardware
167 // traps such as int3 (resulting in SIGTRAP but advancing the instruction 221 // traps such as int3 (resulting in SIGTRAP but advancing the instruction
168 // pointer), will not reoccur on their own when returning from the signal 222 // pointer), will not reoccur on their own when returning from the signal
169 // handler. Re-raise them or call to the previous signal handler as 223 // handler. Re-raise them.
170 // appropriate.
171 // 224 //
172 // Unfortunately, when SIGBUS is received asynchronously via kill(), 225 // Unfortunately, when SIGBUS is received asynchronously via kill(),
173 // siginfo->si_code makes it appear as though it was actually received via a 226 // siginfo->si_code makes it appear as though it was actually received via a
174 // hardware fault. See 10.12.3 xnu-3789.41.3/bsd/dev/i386/unix_signal.c 227 // hardware fault. See 10.12.3 xnu-3789.41.3/bsd/dev/i386/unix_signal.c
175 // sendsig(). An asynchronous SIGBUS will thus cause the handler-crashed 228 // sendsig(). An asynchronous SIGBUS will thus cause the handler-crashed
176 // metric to be logged but will not cause the process to terminate. This 229 // metric to be logged but will not cause the process to terminate. This
177 // isn’t ideal, but asynchronous SIGBUS is an unexpected condition. The 230 // isn’t ideal, but asynchronous SIGBUS is an unexpected condition. The
178 // alternative, to re-raise here on any SIGBUS, is a bad idea because it 231 // alternative, to re-raise here on any SIGBUS, is a bad idea because it
179 // would lose properties associated with the the original signal, which are 232 // would lose properties associated with the the original signal, which are
180 // very valuable for debugging and are visible to a Mach exception handler. 233 // very valuable for debugging and are visible to a Mach exception handler.
181 // Since SIGBUS is normally received synchronously in response to a hardware 234 // Since SIGBUS is normally received synchronously in response to a hardware
182 // fault, don’t sweat the unexpected asynchronous case. 235 // fault, don’t sweat the unexpected asynchronous case.
183 if (osa->sa_handler == SIG_DFL) { 236 //
184 // Because this signal handler executes with the signal blocked, this 237 // Because this signal handler executes with the signal blocked, this
185 // raise() cannot immediately deliver the signal. Delivery is deferred 238 // raise() cannot immediately deliver the signal. Delivery is deferred until
186 // until this signal handler returns and the signal becomes unblocked. The 239 // this signal handler returns and the signal becomes unblocked. The
187 // re-raised signal will appear with the same context as where it was 240 // re-raised signal will appear with the same context as where it was
188 // initially triggered. 241 // initially triggered.
189 rv = raise(sig); 242 int rv = raise(sig);
190 DPLOG_IF(ERROR, rv != 0) << "raise"; 243 DPLOG_IF(ERROR, rv != 0) << "raise";
191 } else if (osa->sa_handler != SIG_IGN) { 244 ALLOW_UNUSED_LOCAL(rv);
192 if (osa->sa_flags & SA_SIGINFO) {
193 osa->sa_sigaction(sig, siginfo, context);
194 } else {
195 osa->sa_handler(sig);
196 }
197 }
198 } 245 }
199 } 246 }
200 247
248 void HandleTerminateSignal(int sig, siginfo_t* siginfo, void* context) {
249 MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated);
250
251 RestoreDefaultSignalHandler(sig);
252
253 // Re-raise the signal. See the explanation in HandleCrashSignal(). Note that
254 // no checks for signals arising from synchronous hardware faults are made
255 // because termination signals never originate in that way.
256 int rv = raise(sig);
257 DPLOG_IF(ERROR, rv != 0) << "raise";
258 ALLOW_UNUSED_LOCAL(rv);
259 }
260
201 void InstallCrashHandler() { 261 void InstallCrashHandler() {
202 struct sigaction sa = {};
203 sigemptyset(&sa.sa_mask);
204 sa.sa_flags = SA_SIGINFO;
205 sa.sa_sigaction = HandleCrashSignal;
206
207 // These are the core-generating signals from 10.12.3 262 // These are the core-generating signals from 10.12.3
208 // xnu-3789.41.3/bsd/sys/signalvar.h sigprop: entries with SA_CORE are in the 263 // xnu-3789.41.3/bsd/sys/signalvar.h sigprop: entries with SA_CORE are in the
209 // set. 264 // set.
210 const int kSignals[] = {SIGQUIT, 265 const int kCrashSignals[] = {SIGQUIT,
211 SIGILL, 266 SIGILL,
212 SIGTRAP, 267 SIGTRAP,
213 SIGABRT, 268 SIGABRT,
214 SIGEMT, 269 SIGEMT,
215 SIGFPE, 270 SIGFPE,
216 SIGBUS, 271 SIGBUS,
217 SIGSEGV, 272 SIGSEGV,
218 SIGSYS}; 273 SIGSYS};
274 InstallSignalHandler(
275 std::vector<int>(&kCrashSignals[0],
276 &kCrashSignals[arraysize(kCrashSignals)]),
277 HandleCrashSignal);
219 278
220 for (int sig : kSignals) { 279 // Not a crash handler, but close enough. These are non-core-generating but
221 DCHECK_GT(sig, 0); 280 // terminating signals from 10.12.3 xnu-3789.41.3/bsd/sys/signalvar.h sigprop:
222 DCHECK_LT(static_cast<size_t>(sig), arraysize(g_original_crash_sigaction)); 281 // entries with SA_KILL but not SA_CORE are in the set. SIGKILL is excluded
223 int rv = sigaction(sig, &sa, &g_original_crash_sigaction[sig]); 282 // because it is uncatchable.
224 PCHECK(rv == 0) << "sigaction " << sig; 283 const int kTerminateSignals[] = {SIGHUP,
225 } 284 SIGINT,
285 SIGPIPE,
286 SIGALRM,
287 SIGTERM,
288 SIGXCPU,
289 SIGXFSZ,
290 SIGVTALRM,
291 SIGPROF,
292 SIGUSR1,
293 SIGUSR2};
294 InstallSignalHandler(
295 std::vector<int>(&kTerminateSignals[0],
296 &kTerminateSignals[arraysize(kTerminateSignals)]),
297 HandleTerminateSignal);
226 } 298 }
227 299
228 struct ResetSIGTERMTraits { 300 struct ResetSIGTERMTraits {
229 static struct sigaction* InvalidValue() { 301 static struct sigaction* InvalidValue() {
230 return nullptr; 302 return nullptr;
231 } 303 }
232 304
233 static void Free(struct sigaction* sa) { 305 static void Free(struct sigaction* sa) {
234 int rv = sigaction(SIGTERM, sa, nullptr); 306 int rv = sigaction(SIGTERM, sa, nullptr);
235 PLOG_IF(ERROR, rv != 0) << "sigaction"; 307 PLOG_IF(ERROR, rv != 0) << "sigaction";
236 } 308 }
237 }; 309 };
238 using ScopedResetSIGTERM = 310 using ScopedResetSIGTERM =
239 base::ScopedGeneric<struct sigaction*, ResetSIGTERMTraits>; 311 base::ScopedGeneric<struct sigaction*, ResetSIGTERMTraits>;
240 312
241 ExceptionHandlerServer* g_exception_handler_server; 313 ExceptionHandlerServer* g_exception_handler_server;
242 314
243 // This signal handler is only operative when being run from launchd. 315 // This signal handler is only operative when being run from launchd.
244 void HandleSIGTERM(int sig, siginfo_t* siginfo, void* context) { 316 void HandleSIGTERM(int sig, siginfo_t* siginfo, void* context) {
317 // Don’t call MetricsRecordExit(). This is part of the normal exit path when
318 // running from launchd.
319
245 DCHECK(g_exception_handler_server); 320 DCHECK(g_exception_handler_server);
246 g_exception_handler_server->Stop(); 321 g_exception_handler_server->Stop();
247 } 322 }
248 323
249 #elif defined(OS_WIN) 324 #elif defined(OS_WIN)
250 325
251 LONG(WINAPI* g_original_exception_filter)(EXCEPTION_POINTERS*) = nullptr; 326 LONG(WINAPI* g_original_exception_filter)(EXCEPTION_POINTERS*) = nullptr;
252 327
253 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { 328 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) {
329 MetricsRecordExit(Metrics::LifetimeMilestone::kCrashed);
254 Metrics::HandlerCrashed(exception_pointers->ExceptionRecord->ExceptionCode); 330 Metrics::HandlerCrashed(exception_pointers->ExceptionRecord->ExceptionCode);
255 331
256 if (g_original_exception_filter) 332 if (g_original_exception_filter)
257 return g_original_exception_filter(exception_pointers); 333 return g_original_exception_filter(exception_pointers);
258 else 334 else
259 return EXCEPTION_CONTINUE_SEARCH; 335 return EXCEPTION_CONTINUE_SEARCH;
260 } 336 }
261 337
338 // Handles events like Control-C and Control-Break on a console.
339 BOOL WINAPI ConsoleHandler(DWORD console_event) {
340 MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated);
341 return false;
342 }
343
344 // Handles a WM_ENDSESSION message sent when the user session is ending.
345 class TerminateHandler final : public SessionEndWatcher {
346 public:
347 TerminateHandler() : SessionEndWatcher() {}
348 ~TerminateHandler() override {}
349
350 private:
351 // SessionEndWatcher:
352 void SessionEnding() override {
353 MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated);
354 }
355
356 DISALLOW_COPY_AND_ASSIGN(TerminateHandler);
357 };
358
262 void InstallCrashHandler() { 359 void InstallCrashHandler() {
263 g_original_exception_filter = 360 g_original_exception_filter =
264 SetUnhandledExceptionFilter(&UnhandledExceptionHandler); 361 SetUnhandledExceptionFilter(&UnhandledExceptionHandler);
362
363 // These are termination handlers, not crash handlers, but that’s close
364 // enough. Note that destroying the TerminateHandler would wait for its thread
365 // to exit, which isn’t necessary or desirable.
366 SetConsoleCtrlHandler(ConsoleHandler, true);
367 static TerminateHandler* terminate_handler = new TerminateHandler();
368 ALLOW_UNUSED_LOCAL(terminate_handler);
265 } 369 }
266 370
267 #endif // OS_MACOSX 371 #endif // OS_MACOSX
268 372
269 } // namespace 373 } // namespace
270 374
271 int HandlerMain(int argc, char* argv[]) { 375 int HandlerMain(int argc, char* argv[]) {
272 InstallCrashHandler(); 376 InstallCrashHandler();
377 CallMetricsRecordNormalExit metrics_record_normal_exit;
273 378
274 const base::FilePath argv0( 379 const base::FilePath argv0(
275 ToolSupport::CommandLineArgumentToFilePathStringType(argv[0])); 380 ToolSupport::CommandLineArgumentToFilePathStringType(argv[0]));
276 const base::FilePath me(argv0.BaseName()); 381 const base::FilePath me(argv0.BaseName());
277 382
278 enum OptionFlags { 383 enum OptionFlags {
279 // Long options without short equivalents. 384 // Long options without short equivalents.
280 kOptionLastChar = 255, 385 kOptionLastChar = 255,
281 kOptionAnnotation, 386 kOptionAnnotation,
282 kOptionDatabase, 387 kOptionDatabase,
283 #if defined(OS_MACOSX) 388 #if defined(OS_MACOSX)
284 kOptionHandshakeFD, 389 kOptionHandshakeFD,
285 #endif // OS_MACOSX 390 #endif // OS_MACOSX
286 #if defined(OS_WIN) 391 #if defined(OS_WIN)
287 kOptionInitialClientData, 392 kOptionInitialClientData,
288 #endif // OS_WIN 393 #endif // OS_WIN
289 #if defined(OS_MACOSX) 394 #if defined(OS_MACOSX)
290 kOptionMachService, 395 kOptionMachService,
291 #endif // OS_MACOSX 396 #endif // OS_MACOSX
292 kOptionMetrics, 397 kOptionMetrics,
293 kOptionNoRateLimit, 398 kOptionNoRateLimit,
399 kOptionNoUploadGzip,
294 #if defined(OS_MACOSX) 400 #if defined(OS_MACOSX)
295 kOptionResetOwnCrashExceptionPortToSystemDefault, 401 kOptionResetOwnCrashExceptionPortToSystemDefault,
296 #elif defined(OS_WIN) 402 #elif defined(OS_WIN)
297 kOptionPipeName, 403 kOptionPipeName,
298 #endif // OS_MACOSX 404 #endif // OS_MACOSX
299 kOptionURL, 405 kOptionURL,
300 406
301 // Standard options. 407 // Standard options.
302 kOptionHelp = -2, 408 kOptionHelp = -2,
303 kOptionVersion = -3, 409 kOptionVersion = -3,
304 }; 410 };
305 411
306 struct { 412 struct {
307 std::map<std::string, std::string> annotations; 413 std::map<std::string, std::string> annotations;
308 std::string url; 414 std::string url;
309 const char* database; 415 const char* database;
310 const char* metrics; 416 const char* metrics;
311 #if defined(OS_MACOSX) 417 #if defined(OS_MACOSX)
312 int handshake_fd; 418 int handshake_fd;
313 std::string mach_service; 419 std::string mach_service;
314 bool reset_own_crash_exception_port_to_system_default; 420 bool reset_own_crash_exception_port_to_system_default;
315 #elif defined(OS_WIN) 421 #elif defined(OS_WIN)
316 std::string pipe_name; 422 std::string pipe_name;
317 InitialClientData initial_client_data; 423 InitialClientData initial_client_data;
318 #endif // OS_MACOSX 424 #endif // OS_MACOSX
319 bool rate_limit; 425 bool rate_limit;
426 bool upload_gzip;
320 } options = {}; 427 } options = {};
321 #if defined(OS_MACOSX) 428 #if defined(OS_MACOSX)
322 options.handshake_fd = -1; 429 options.handshake_fd = -1;
323 #endif 430 #endif
324 options.rate_limit = true; 431 options.rate_limit = true;
432 options.upload_gzip = true;
325 433
326 const option long_options[] = { 434 const option long_options[] = {
327 {"annotation", required_argument, nullptr, kOptionAnnotation}, 435 {"annotation", required_argument, nullptr, kOptionAnnotation},
328 {"database", required_argument, nullptr, kOptionDatabase}, 436 {"database", required_argument, nullptr, kOptionDatabase},
329 #if defined(OS_MACOSX) 437 #if defined(OS_MACOSX)
330 {"handshake-fd", required_argument, nullptr, kOptionHandshakeFD}, 438 {"handshake-fd", required_argument, nullptr, kOptionHandshakeFD},
331 #endif // OS_MACOSX 439 #endif // OS_MACOSX
332 #if defined(OS_WIN) 440 #if defined(OS_WIN)
333 {"initial-client-data", 441 {"initial-client-data",
334 required_argument, 442 required_argument,
335 nullptr, 443 nullptr,
336 kOptionInitialClientData}, 444 kOptionInitialClientData},
337 #endif // OS_MACOSX 445 #endif // OS_MACOSX
338 #if defined(OS_MACOSX) 446 #if defined(OS_MACOSX)
339 {"mach-service", required_argument, nullptr, kOptionMachService}, 447 {"mach-service", required_argument, nullptr, kOptionMachService},
340 #endif // OS_MACOSX 448 #endif // OS_MACOSX
341 {"metrics-dir", required_argument, nullptr, kOptionMetrics}, 449 {"metrics-dir", required_argument, nullptr, kOptionMetrics},
342 {"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit}, 450 {"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit},
451 {"no-upload-gzip", no_argument, nullptr, kOptionNoUploadGzip},
343 #if defined(OS_MACOSX) 452 #if defined(OS_MACOSX)
344 {"reset-own-crash-exception-port-to-system-default", 453 {"reset-own-crash-exception-port-to-system-default",
345 no_argument, 454 no_argument,
346 nullptr, 455 nullptr,
347 kOptionResetOwnCrashExceptionPortToSystemDefault}, 456 kOptionResetOwnCrashExceptionPortToSystemDefault},
348 #elif defined(OS_WIN) 457 #elif defined(OS_WIN)
349 {"pipe-name", required_argument, nullptr, kOptionPipeName}, 458 {"pipe-name", required_argument, nullptr, kOptionPipeName},
350 #endif // OS_MACOSX 459 #endif // OS_MACOSX
351 {"url", required_argument, nullptr, kOptionURL}, 460 {"url", required_argument, nullptr, kOptionURL},
352 {"help", no_argument, nullptr, kOptionHelp}, 461 {"help", no_argument, nullptr, kOptionHelp},
353 {"version", no_argument, nullptr, kOptionVersion}, 462 {"version", no_argument, nullptr, kOptionVersion},
354 {nullptr, 0, nullptr, 0}, 463 {nullptr, 0, nullptr, 0},
355 }; 464 };
356 465
357 int opt; 466 int opt;
358 while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) { 467 while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) {
359 switch (opt) { 468 switch (opt) {
360 case kOptionAnnotation: { 469 case kOptionAnnotation: {
361 std::string key; 470 std::string key;
362 std::string value; 471 std::string value;
363 if (!SplitStringFirst(optarg, '=', &key, &value)) { 472 if (!SplitStringFirst(optarg, '=', &key, &value)) {
364 ToolSupport::UsageHint(me, "--annotation requires KEY=VALUE"); 473 ToolSupport::UsageHint(me, "--annotation requires KEY=VALUE");
365 return EXIT_FAILURE; 474 return ExitFailure();
366 } 475 }
367 std::string old_value; 476 std::string old_value;
368 if (!MapInsertOrReplace(&options.annotations, key, value, &old_value)) { 477 if (!MapInsertOrReplace(&options.annotations, key, value, &old_value)) {
369 LOG(WARNING) << "duplicate key " << key << ", discarding value " 478 LOG(WARNING) << "duplicate key " << key << ", discarding value "
370 << old_value; 479 << old_value;
371 } 480 }
372 break; 481 break;
373 } 482 }
374 case kOptionDatabase: { 483 case kOptionDatabase: {
375 options.database = optarg; 484 options.database = optarg;
376 break; 485 break;
377 } 486 }
378 #if defined(OS_MACOSX) 487 #if defined(OS_MACOSX)
379 case kOptionHandshakeFD: { 488 case kOptionHandshakeFD: {
380 if (!StringToNumber(optarg, &options.handshake_fd) || 489 if (!StringToNumber(optarg, &options.handshake_fd) ||
381 options.handshake_fd < 0) { 490 options.handshake_fd < 0) {
382 ToolSupport::UsageHint(me, 491 ToolSupport::UsageHint(me,
383 "--handshake-fd requires a file descriptor"); 492 "--handshake-fd requires a file descriptor");
384 return EXIT_FAILURE; 493 return ExitFailure();
385 } 494 }
386 break; 495 break;
387 } 496 }
388 case kOptionMachService: { 497 case kOptionMachService: {
389 options.mach_service = optarg; 498 options.mach_service = optarg;
390 break; 499 break;
391 } 500 }
392 #elif defined(OS_WIN) 501 #elif defined(OS_WIN)
393 case kOptionInitialClientData: { 502 case kOptionInitialClientData: {
394 if (!options.initial_client_data.InitializeFromString(optarg)) { 503 if (!options.initial_client_data.InitializeFromString(optarg)) {
395 ToolSupport::UsageHint( 504 ToolSupport::UsageHint(
396 me, "failed to parse --initial-client-data"); 505 me, "failed to parse --initial-client-data");
397 return EXIT_FAILURE; 506 return ExitFailure();
398 } 507 }
399 break; 508 break;
400 } 509 }
401 #endif // OS_MACOSX 510 #endif // OS_MACOSX
402 case kOptionMetrics: { 511 case kOptionMetrics: {
403 options.metrics = optarg; 512 options.metrics = optarg;
404 break; 513 break;
405 } 514 }
406 case kOptionNoRateLimit: { 515 case kOptionNoRateLimit: {
407 options.rate_limit = false; 516 options.rate_limit = false;
408 break; 517 break;
409 } 518 }
519 case kOptionNoUploadGzip: {
520 options.upload_gzip = false;
521 break;
522 }
410 #if defined(OS_MACOSX) 523 #if defined(OS_MACOSX)
411 case kOptionResetOwnCrashExceptionPortToSystemDefault: { 524 case kOptionResetOwnCrashExceptionPortToSystemDefault: {
412 options.reset_own_crash_exception_port_to_system_default = true; 525 options.reset_own_crash_exception_port_to_system_default = true;
413 break; 526 break;
414 } 527 }
415 #elif defined(OS_WIN) 528 #elif defined(OS_WIN)
416 case kOptionPipeName: { 529 case kOptionPipeName: {
417 options.pipe_name = optarg; 530 options.pipe_name = optarg;
418 break; 531 break;
419 } 532 }
420 #endif // OS_MACOSX 533 #endif // OS_MACOSX
421 case kOptionURL: { 534 case kOptionURL: {
422 options.url = optarg; 535 options.url = optarg;
423 break; 536 break;
424 } 537 }
425 case kOptionHelp: { 538 case kOptionHelp: {
426 Usage(me); 539 Usage(me);
540 MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly);
427 return EXIT_SUCCESS; 541 return EXIT_SUCCESS;
428 } 542 }
429 case kOptionVersion: { 543 case kOptionVersion: {
430 ToolSupport::Version(me); 544 ToolSupport::Version(me);
545 MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly);
431 return EXIT_SUCCESS; 546 return EXIT_SUCCESS;
432 } 547 }
433 default: { 548 default: {
434 ToolSupport::UsageHint(me, nullptr); 549 ToolSupport::UsageHint(me, nullptr);
435 return EXIT_FAILURE; 550 return ExitFailure();
436 } 551 }
437 } 552 }
438 } 553 }
439 argc -= optind; 554 argc -= optind;
440 argv += optind; 555 argv += optind;
441 556
442 #if defined(OS_MACOSX) 557 #if defined(OS_MACOSX)
443 if (options.handshake_fd < 0 && options.mach_service.empty()) { 558 if (options.handshake_fd < 0 && options.mach_service.empty()) {
444 ToolSupport::UsageHint(me, "--handshake-fd or --mach-service is required"); 559 ToolSupport::UsageHint(me, "--handshake-fd or --mach-service is required");
445 return EXIT_FAILURE; 560 return ExitFailure();
446 } 561 }
447 if (options.handshake_fd >= 0 && !options.mach_service.empty()) { 562 if (options.handshake_fd >= 0 && !options.mach_service.empty()) {
448 ToolSupport::UsageHint( 563 ToolSupport::UsageHint(
449 me, "--handshake-fd and --mach-service are incompatible"); 564 me, "--handshake-fd and --mach-service are incompatible");
450 return EXIT_FAILURE; 565 return ExitFailure();
451 } 566 }
452 #elif defined(OS_WIN) 567 #elif defined(OS_WIN)
453 if (!options.initial_client_data.IsValid() && options.pipe_name.empty()) { 568 if (!options.initial_client_data.IsValid() && options.pipe_name.empty()) {
454 ToolSupport::UsageHint(me, 569 ToolSupport::UsageHint(me,
455 "--initial-client-data or --pipe-name is required"); 570 "--initial-client-data or --pipe-name is required");
456 return EXIT_FAILURE; 571 return ExitFailure();
457 } 572 }
458 if (options.initial_client_data.IsValid() && !options.pipe_name.empty()) { 573 if (options.initial_client_data.IsValid() && !options.pipe_name.empty()) {
459 ToolSupport::UsageHint( 574 ToolSupport::UsageHint(
460 me, "--initial-client-data and --pipe-name are incompatible"); 575 me, "--initial-client-data and --pipe-name are incompatible");
461 return EXIT_FAILURE; 576 return ExitFailure();
462 } 577 }
463 #endif // OS_MACOSX 578 #endif // OS_MACOSX
464 579
465 if (!options.database) { 580 if (!options.database) {
466 ToolSupport::UsageHint(me, "--database is required"); 581 ToolSupport::UsageHint(me, "--database is required");
467 return EXIT_FAILURE; 582 return ExitFailure();
468 } 583 }
469 584
470 if (argc) { 585 if (argc) {
471 ToolSupport::UsageHint(me, nullptr); 586 ToolSupport::UsageHint(me, nullptr);
472 return EXIT_FAILURE; 587 return ExitFailure();
473 } 588 }
474 589
475 #if defined(OS_MACOSX) 590 #if defined(OS_MACOSX)
476 if (options.mach_service.empty()) { 591 if (options.mach_service.empty()) {
477 // Don’t do this when being run by launchd. See launchd.plist(5). 592 // Don’t do this when being run by launchd. See launchd.plist(5).
478 CloseStdinAndStdout(); 593 CloseStdinAndStdout();
479 } 594 }
480 595
481 if (options.reset_own_crash_exception_port_to_system_default) { 596 if (options.reset_own_crash_exception_port_to_system_default) {
482 CrashpadClient::UseSystemDefaultHandler(); 597 CrashpadClient::UseSystemDefaultHandler();
483 } 598 }
484 599
485 base::mac::ScopedMachReceiveRight receive_right; 600 base::mac::ScopedMachReceiveRight receive_right;
486 601
487 if (options.handshake_fd >= 0) { 602 if (options.handshake_fd >= 0) {
488 receive_right.reset( 603 receive_right.reset(
489 ChildPortHandshake::RunServerForFD( 604 ChildPortHandshake::RunServerForFD(
490 base::ScopedFD(options.handshake_fd), 605 base::ScopedFD(options.handshake_fd),
491 ChildPortHandshake::PortRightType::kReceiveRight)); 606 ChildPortHandshake::PortRightType::kReceiveRight));
492 } else if (!options.mach_service.empty()) { 607 } else if (!options.mach_service.empty()) {
493 receive_right = BootstrapCheckIn(options.mach_service); 608 receive_right = BootstrapCheckIn(options.mach_service);
494 } 609 }
495 610
496 if (!receive_right.is_valid()) { 611 if (!receive_right.is_valid()) {
497 return EXIT_FAILURE; 612 return ExitFailure();
498 } 613 }
499 614
500 ExceptionHandlerServer exception_handler_server( 615 ExceptionHandlerServer exception_handler_server(
501 std::move(receive_right), !options.mach_service.empty()); 616 std::move(receive_right), !options.mach_service.empty());
502 base::AutoReset<ExceptionHandlerServer*> reset_g_exception_handler_server( 617 base::AutoReset<ExceptionHandlerServer*> reset_g_exception_handler_server(
503 &g_exception_handler_server, &exception_handler_server); 618 &g_exception_handler_server, &exception_handler_server);
504 619
505 struct sigaction old_sa; 620 struct sigaction old_sa;
506 ScopedResetSIGTERM reset_sigterm; 621 ScopedResetSIGTERM reset_sigterm;
507 if (!options.mach_service.empty()) { 622 if (!options.mach_service.empty()) {
508 // When running from launchd, no no-senders notification could ever be 623 // When running from launchd, no no-senders notification could ever be
509 // triggered, because launchd maintains a send right to the service. When 624 // triggered, because launchd maintains a send right to the service. When
510 // launchd wants the job to exit, it will send a SIGTERM. See 625 // launchd wants the job to exit, it will send a SIGTERM. See
511 // launchd.plist(5). 626 // launchd.plist(5).
512 // 627 //
513 // Set up a SIGTERM handler that will call exception_handler_server.Stop(). 628 // Set up a SIGTERM handler that will call exception_handler_server.Stop().
629 // This replaces the HandleTerminateSignal handler for SIGTERM.
514 struct sigaction sa = {}; 630 struct sigaction sa = {};
515 sigemptyset(&sa.sa_mask); 631 sigemptyset(&sa.sa_mask);
516 sa.sa_flags = SA_SIGINFO; 632 sa.sa_flags = SA_SIGINFO;
517 sa.sa_sigaction = HandleSIGTERM; 633 sa.sa_sigaction = HandleSIGTERM;
518 int rv = sigaction(SIGTERM, &sa, &old_sa); 634 int rv = sigaction(SIGTERM, &sa, &old_sa);
519 PCHECK(rv == 0) << "sigaction"; 635 PCHECK(rv == 0) << "sigaction";
520 reset_sigterm.reset(&old_sa); 636 reset_sigterm.reset(&old_sa);
521 } 637 }
522 #elif defined(OS_WIN) 638 #elif defined(OS_WIN)
523 // Shut down as late as possible relative to programs we're watching. 639 // Shut down as late as possible relative to programs we're watching.
(...skipping 13 matching lines...) Expand all
537 ToolSupport::CommandLineArgumentToFilePathStringType(options.metrics)); 653 ToolSupport::CommandLineArgumentToFilePathStringType(options.metrics));
538 static const char kMetricsName[] = "CrashpadMetrics"; 654 static const char kMetricsName[] = "CrashpadMetrics";
539 const size_t kMetricsFileSize = 1 << 20; 655 const size_t kMetricsFileSize = 1 << 20;
540 if (base::GlobalHistogramAllocator::CreateWithActiveFileInDir( 656 if (base::GlobalHistogramAllocator::CreateWithActiveFileInDir(
541 metrics_dir, kMetricsFileSize, 0, kMetricsName)) { 657 metrics_dir, kMetricsFileSize, 0, kMetricsName)) {
542 histogram_allocator = base::GlobalHistogramAllocator::Get(); 658 histogram_allocator = base::GlobalHistogramAllocator::Get();
543 histogram_allocator->CreateTrackingHistograms(kMetricsName); 659 histogram_allocator->CreateTrackingHistograms(kMetricsName);
544 } 660 }
545 } 661 }
546 662
663 Metrics::HandlerLifetimeMilestone(Metrics::LifetimeMilestone::kStarted);
664
547 std::unique_ptr<CrashReportDatabase> database(CrashReportDatabase::Initialize( 665 std::unique_ptr<CrashReportDatabase> database(CrashReportDatabase::Initialize(
548 base::FilePath(ToolSupport::CommandLineArgumentToFilePathStringType( 666 base::FilePath(ToolSupport::CommandLineArgumentToFilePathStringType(
549 options.database)))); 667 options.database))));
550 if (!database) { 668 if (!database) {
551 return EXIT_FAILURE; 669 return ExitFailure();
552 } 670 }
553 671
554 // TODO(scottmg): options.rate_limit should be removed when we have a 672 // TODO(scottmg): options.rate_limit should be removed when we have a
555 // configurable database setting to control upload limiting. 673 // configurable database setting to control upload limiting.
556 // See https://crashpad.chromium.org/bug/23. 674 // See https://crashpad.chromium.org/bug/23.
557 CrashReportUploadThread upload_thread( 675 CrashReportUploadThread upload_thread(
558 database.get(), options.url, options.rate_limit); 676 database.get(), options.url, options.rate_limit, options.upload_gzip);
559 upload_thread.Start(); 677 upload_thread.Start();
560 678
561 PruneCrashReportThread prune_thread(database.get(), 679 PruneCrashReportThread prune_thread(database.get(),
562 PruneCondition::GetDefault()); 680 PruneCondition::GetDefault());
563 prune_thread.Start(); 681 prune_thread.Start();
564 682
565 CrashReportExceptionHandler exception_handler( 683 CrashReportExceptionHandler exception_handler(
566 database.get(), &upload_thread, &options.annotations); 684 database.get(), &upload_thread, &options.annotations);
567 685
568 #if defined(OS_WIN) 686 #if defined(OS_WIN)
569 if (options.initial_client_data.IsValid()) { 687 if (options.initial_client_data.IsValid()) {
570 exception_handler_server.InitializeWithInheritedDataForInitialClient( 688 exception_handler_server.InitializeWithInheritedDataForInitialClient(
571 options.initial_client_data, &exception_handler); 689 options.initial_client_data, &exception_handler);
572 } 690 }
573 #endif // OS_WIN 691 #endif // OS_WIN
574 692
575 exception_handler_server.Run(&exception_handler); 693 exception_handler_server.Run(&exception_handler);
576 694
577 upload_thread.Stop(); 695 upload_thread.Stop();
578 prune_thread.Stop(); 696 prune_thread.Stop();
579 697
580 if (histogram_allocator) 698 if (histogram_allocator)
581 histogram_allocator->DeletePersistentLocation(); 699 histogram_allocator->DeletePersistentLocation();
582 700
583 return EXIT_SUCCESS; 701 return EXIT_SUCCESS;
584 } 702 }
585 703
586 } // namespace crashpad 704 } // namespace crashpad
OLDNEW
« no previous file with comments | « third_party/crashpad/crashpad/handler/handler.gyp ('k') | third_party/crashpad/crashpad/minidump/minidump_context.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698