crash: Compress crash report with gzip on Linux
[chromium-blink-merge.git] / components / crash / app / breakpad_linux.cc
blobd33d2328cf56f4388d0700f6fb9aea5b190eba07
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // For linux_syscall_support.h. This makes it safe to call embedded system
6 // calls when in seccomp mode.
8 #include "components/crash/app/breakpad_linux.h"
10 #include <fcntl.h>
11 #include <poll.h>
12 #include <signal.h>
13 #include <stdlib.h>
14 #include <sys/socket.h>
15 #include <sys/time.h>
16 #include <sys/types.h>
17 #include <sys/uio.h>
18 #include <sys/wait.h>
19 #include <time.h>
20 #include <unistd.h>
22 #include <algorithm>
23 #include <string>
25 #include "base/base_switches.h"
26 #include "base/command_line.h"
27 #include "base/debug/crash_logging.h"
28 #include "base/debug/dump_without_crashing.h"
29 #include "base/files/file_path.h"
30 #include "base/linux_util.h"
31 #include "base/path_service.h"
32 #include "base/posix/eintr_wrapper.h"
33 #include "base/posix/global_descriptors.h"
34 #include "base/process/memory.h"
35 #include "base/strings/string_util.h"
36 #include "breakpad/src/client/linux/crash_generation/crash_generation_client.h"
37 #include "breakpad/src/client/linux/handler/exception_handler.h"
38 #include "breakpad/src/client/linux/minidump_writer/directory_reader.h"
39 #include "breakpad/src/common/linux/linux_libc_support.h"
40 #include "breakpad/src/common/memory.h"
41 #include "build/build_config.h"
42 #include "components/crash/app/breakpad_linux_impl.h"
43 #include "components/crash/app/crash_reporter_client.h"
44 #include "content/public/common/content_descriptors.h"
46 #if defined(OS_ANDROID)
47 #include <android/log.h>
48 #include <sys/stat.h>
50 #include "base/android/build_info.h"
51 #include "base/android/path_utils.h"
52 #include "base/debug/leak_annotations.h"
53 #endif
54 #include "third_party/lss/linux_syscall_support.h"
56 #if defined(ADDRESS_SANITIZER)
57 #include <ucontext.h> // for getcontext().
58 #endif
60 #if defined(OS_ANDROID)
61 #define STAT_STRUCT struct stat
62 #define FSTAT_FUNC fstat
63 #else
64 #define STAT_STRUCT struct kernel_stat
65 #define FSTAT_FUNC sys_fstat
66 #endif
68 // Some versions of gcc are prone to warn about unused return values. In cases
69 // where we either a) know the call cannot fail, or b) there is nothing we
70 // can do when a call fails, we mark the return code as ignored. This avoids
71 // spurious compiler warnings.
72 #define IGNORE_RET(x) do { if (x); } while (0)
74 using crash_reporter::GetCrashReporterClient;
75 using google_breakpad::ExceptionHandler;
76 using google_breakpad::MinidumpDescriptor;
78 namespace breakpad {
80 namespace {
82 #if !defined(OS_CHROMEOS)
83 const char kUploadURL[] = "https://clients2.google.com/cr/report";
84 #endif
86 bool g_is_crash_reporter_enabled = false;
87 uint64_t g_process_start_time = 0;
88 pid_t g_pid = 0;
89 char* g_crash_log_path = nullptr;
90 ExceptionHandler* g_breakpad = nullptr;
92 #if defined(ADDRESS_SANITIZER)
93 const char* g_asan_report_str = nullptr;
94 #endif
95 #if defined(OS_ANDROID)
96 char* g_process_type = nullptr;
97 ExceptionHandler* g_microdump = nullptr;
98 const char* g_microdump_build_fingerprint = nullptr;
99 const char* g_microdump_product_info = nullptr;
100 #endif
102 CrashKeyStorage* g_crash_keys = nullptr;
104 // Writes the value |v| as 16 hex characters to the memory pointed at by
105 // |output|.
106 void write_uint64_hex(char* output, uint64_t v) {
107 static const char hextable[] = "0123456789abcdef";
109 for (int i = 15; i >= 0; --i) {
110 output[i] = hextable[v & 15];
111 v >>= 4;
115 // The following helper functions are for calculating uptime.
117 // Converts a struct timeval to milliseconds.
118 uint64_t timeval_to_ms(struct timeval *tv) {
119 uint64_t ret = tv->tv_sec; // Avoid overflow by explicitly using a uint64_t.
120 ret *= 1000;
121 ret += tv->tv_usec / 1000;
122 return ret;
125 // Converts a struct timeval to milliseconds.
126 uint64_t kernel_timeval_to_ms(struct kernel_timeval *tv) {
127 uint64_t ret = tv->tv_sec; // Avoid overflow by explicitly using a uint64_t.
128 ret *= 1000;
129 ret += tv->tv_usec / 1000;
130 return ret;
133 // String buffer size to use to convert a uint64_t to string.
134 const size_t kUint64StringSize = 21;
136 void SetProcessStartTime() {
137 // Set the base process start time value.
138 struct timeval tv;
139 if (!gettimeofday(&tv, nullptr))
140 g_process_start_time = timeval_to_ms(&tv);
141 else
142 g_process_start_time = 0;
145 // uint64_t version of my_int_len() from
146 // breakpad/src/common/linux/linux_libc_support.h. Return the length of the
147 // given, non-negative integer when expressed in base 10.
148 unsigned my_uint64_len(uint64_t i) {
149 if (!i)
150 return 1;
152 unsigned len = 0;
153 while (i) {
154 len++;
155 i /= 10;
158 return len;
161 // uint64_t version of my_uitos() from
162 // breakpad/src/common/linux/linux_libc_support.h. Convert a non-negative
163 // integer to a string (not null-terminated).
164 void my_uint64tos(char* output, uint64_t i, unsigned i_len) {
165 for (unsigned index = i_len; index; --index, i /= 10)
166 output[index - 1] = '0' + (i % 10);
169 #if defined(OS_ANDROID)
170 char* my_strncpy(char* dst, const char* src, size_t len) {
171 int i = len;
172 char* p = dst;
173 if (!dst || !src)
174 return dst;
175 while (i != 0 && *src != '\0') {
176 *p++ = *src++;
177 i--;
179 while (i != 0) {
180 *p++ = '\0';
181 i--;
183 return dst;
186 char* my_strncat(char *dest, const char* src, size_t len) {
187 char* ret = dest;
188 while (*dest)
189 dest++;
190 while (len--)
191 if (!(*dest++ = *src++))
192 return ret;
193 *dest = 0;
194 return ret;
196 #endif
198 #if !defined(OS_CHROMEOS)
199 bool my_isxdigit(char c) {
200 return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f');
202 #endif
204 size_t LengthWithoutTrailingSpaces(const char* str, size_t len) {
205 while (len > 0 && str[len - 1] == ' ') {
206 len--;
208 return len;
211 void SetClientIdFromCommandLine(const base::CommandLine& command_line) {
212 // Get the guid from the command line switch.
213 std::string switch_value =
214 command_line.GetSwitchValueASCII(switches::kEnableCrashReporter);
215 GetCrashReporterClient()->SetCrashReporterClientIdFromGUID(switch_value);
218 // MIME substrings.
219 #if defined(OS_CHROMEOS)
220 const char g_sep[] = ":";
221 #endif
222 const char g_rn[] = "\r\n";
223 const char g_form_data_msg[] = "Content-Disposition: form-data; name=\"";
224 const char g_quote_msg[] = "\"";
225 const char g_dashdash_msg[] = "--";
226 const char g_dump_msg[] = "upload_file_minidump\"; filename=\"dump\"";
227 #if defined(ADDRESS_SANITIZER)
228 const char g_log_msg[] = "upload_file_log\"; filename=\"log\"";
229 #endif
230 const char g_content_type_msg[] = "Content-Type: application/octet-stream";
232 // MimeWriter manages an iovec for writing MIMEs to a file.
233 class MimeWriter {
234 public:
235 static const int kIovCapacity = 30;
236 static const size_t kMaxCrashChunkSize = 64;
238 MimeWriter(int fd, const char* const mime_boundary);
239 ~MimeWriter();
241 // Append boundary.
242 virtual void AddBoundary();
244 // Append end of file boundary.
245 virtual void AddEnd();
247 // Append key/value pair with specified sizes.
248 virtual void AddPairData(const char* msg_type,
249 size_t msg_type_size,
250 const char* msg_data,
251 size_t msg_data_size);
253 // Append key/value pair.
254 void AddPairString(const char* msg_type,
255 const char* msg_data) {
256 AddPairData(msg_type, my_strlen(msg_type), msg_data, my_strlen(msg_data));
259 // Append key/value pair, splitting value into chunks no larger than
260 // |chunk_size|. |chunk_size| cannot be greater than |kMaxCrashChunkSize|.
261 // The msg_type string will have a counter suffix to distinguish each chunk.
262 virtual void AddPairDataInChunks(const char* msg_type,
263 size_t msg_type_size,
264 const char* msg_data,
265 size_t msg_data_size,
266 size_t chunk_size,
267 bool strip_trailing_spaces);
269 // Add binary file contents to be uploaded with the specified filename.
270 virtual void AddFileContents(const char* filename_msg,
271 uint8_t* file_data,
272 size_t file_size);
274 // Flush any pending iovecs to the output file.
275 void Flush() {
276 IGNORE_RET(sys_writev(fd_, iov_, iov_index_));
277 iov_index_ = 0;
280 protected:
281 void AddItem(const void* base, size_t size);
282 // Minor performance trade-off for easier-to-maintain code.
283 void AddString(const char* str) {
284 AddItem(str, my_strlen(str));
286 void AddItemWithoutTrailingSpaces(const void* base, size_t size);
288 struct kernel_iovec iov_[kIovCapacity];
289 int iov_index_;
291 // Output file descriptor.
292 int fd_;
294 const char* const mime_boundary_;
296 private:
297 DISALLOW_COPY_AND_ASSIGN(MimeWriter);
300 MimeWriter::MimeWriter(int fd, const char* const mime_boundary)
301 : iov_index_(0),
302 fd_(fd),
303 mime_boundary_(mime_boundary) {
306 MimeWriter::~MimeWriter() {
309 void MimeWriter::AddBoundary() {
310 AddString(mime_boundary_);
311 AddString(g_rn);
314 void MimeWriter::AddEnd() {
315 AddString(mime_boundary_);
316 AddString(g_dashdash_msg);
317 AddString(g_rn);
320 void MimeWriter::AddPairData(const char* msg_type,
321 size_t msg_type_size,
322 const char* msg_data,
323 size_t msg_data_size) {
324 AddString(g_form_data_msg);
325 AddItem(msg_type, msg_type_size);
326 AddString(g_quote_msg);
327 AddString(g_rn);
328 AddString(g_rn);
329 AddItem(msg_data, msg_data_size);
330 AddString(g_rn);
333 void MimeWriter::AddPairDataInChunks(const char* msg_type,
334 size_t msg_type_size,
335 const char* msg_data,
336 size_t msg_data_size,
337 size_t chunk_size,
338 bool strip_trailing_spaces) {
339 if (chunk_size > kMaxCrashChunkSize)
340 return;
342 unsigned i = 0;
343 size_t done = 0, msg_length = msg_data_size;
345 while (msg_length) {
346 char num[kUint64StringSize];
347 const unsigned num_len = my_uint_len(++i);
348 my_uitos(num, i, num_len);
350 size_t chunk_len = std::min(chunk_size, msg_length);
352 AddString(g_form_data_msg);
353 AddItem(msg_type, msg_type_size);
354 AddItem(num, num_len);
355 AddString(g_quote_msg);
356 AddString(g_rn);
357 AddString(g_rn);
358 if (strip_trailing_spaces) {
359 AddItemWithoutTrailingSpaces(msg_data + done, chunk_len);
360 } else {
361 AddItem(msg_data + done, chunk_len);
363 AddString(g_rn);
364 AddBoundary();
365 Flush();
367 done += chunk_len;
368 msg_length -= chunk_len;
372 void MimeWriter::AddFileContents(const char* filename_msg, uint8_t* file_data,
373 size_t file_size) {
374 AddString(g_form_data_msg);
375 AddString(filename_msg);
376 AddString(g_rn);
377 AddString(g_content_type_msg);
378 AddString(g_rn);
379 AddString(g_rn);
380 AddItem(file_data, file_size);
381 AddString(g_rn);
384 void MimeWriter::AddItem(const void* base, size_t size) {
385 // Check if the iovec is full and needs to be flushed to output file.
386 if (iov_index_ == kIovCapacity) {
387 Flush();
389 iov_[iov_index_].iov_base = const_cast<void*>(base);
390 iov_[iov_index_].iov_len = size;
391 ++iov_index_;
394 void MimeWriter::AddItemWithoutTrailingSpaces(const void* base, size_t size) {
395 AddItem(base, LengthWithoutTrailingSpaces(static_cast<const char*>(base),
396 size));
399 #if defined(OS_CHROMEOS)
400 // This subclass is used on Chromium OS to report crashes in a format easy for
401 // the central crash reporting facility to understand.
402 // Format is <name>:<data length in decimal>:<data>
403 class CrashReporterWriter : public MimeWriter {
404 public:
405 explicit CrashReporterWriter(int fd);
407 void AddBoundary() override;
409 void AddEnd() override;
411 void AddPairData(const char* msg_type,
412 size_t msg_type_size,
413 const char* msg_data,
414 size_t msg_data_size) override;
416 void AddPairDataInChunks(const char* msg_type,
417 size_t msg_type_size,
418 const char* msg_data,
419 size_t msg_data_size,
420 size_t chunk_size,
421 bool strip_trailing_spaces) override;
423 void AddFileContents(const char* filename_msg,
424 uint8_t* file_data,
425 size_t file_size) override;
427 private:
428 DISALLOW_COPY_AND_ASSIGN(CrashReporterWriter);
432 CrashReporterWriter::CrashReporterWriter(int fd) : MimeWriter(fd, "") {}
434 // No-ops.
435 void CrashReporterWriter::AddBoundary() {}
436 void CrashReporterWriter::AddEnd() {}
438 void CrashReporterWriter::AddPairData(const char* msg_type,
439 size_t msg_type_size,
440 const char* msg_data,
441 size_t msg_data_size) {
442 char data[kUint64StringSize];
443 const unsigned data_len = my_uint_len(msg_data_size);
444 my_uitos(data, msg_data_size, data_len);
446 AddItem(msg_type, msg_type_size);
447 AddString(g_sep);
448 AddItem(data, data_len);
449 AddString(g_sep);
450 AddItem(msg_data, msg_data_size);
451 Flush();
454 void CrashReporterWriter::AddPairDataInChunks(const char* msg_type,
455 size_t msg_type_size,
456 const char* msg_data,
457 size_t msg_data_size,
458 size_t chunk_size,
459 bool strip_trailing_spaces) {
460 if (chunk_size > kMaxCrashChunkSize)
461 return;
463 unsigned i = 0;
464 size_t done = 0;
465 size_t msg_length = msg_data_size;
467 while (msg_length) {
468 char num[kUint64StringSize];
469 const unsigned num_len = my_uint_len(++i);
470 my_uitos(num, i, num_len);
472 size_t chunk_len = std::min(chunk_size, msg_length);
474 size_t write_len = chunk_len;
475 if (strip_trailing_spaces) {
476 // Take care of this here because we need to know the exact length of
477 // what is going to be written.
478 write_len = LengthWithoutTrailingSpaces(msg_data + done, write_len);
481 char data[kUint64StringSize];
482 const unsigned data_len = my_uint_len(write_len);
483 my_uitos(data, write_len, data_len);
485 AddItem(msg_type, msg_type_size);
486 AddItem(num, num_len);
487 AddString(g_sep);
488 AddItem(data, data_len);
489 AddString(g_sep);
490 AddItem(msg_data + done, write_len);
491 Flush();
493 done += chunk_len;
494 msg_length -= chunk_len;
498 void CrashReporterWriter::AddFileContents(const char* filename_msg,
499 uint8_t* file_data,
500 size_t file_size) {
501 char data[kUint64StringSize];
502 const unsigned data_len = my_uint_len(file_size);
503 my_uitos(data, file_size, data_len);
505 AddString(filename_msg);
506 AddString(g_sep);
507 AddItem(data, data_len);
508 AddString(g_sep);
509 AddItem(file_data, file_size);
510 Flush();
512 #endif // defined(OS_CHROMEOS)
514 void DumpProcess() {
515 if (g_breakpad)
516 g_breakpad->WriteMinidump();
518 #if defined(OS_ANDROID)
519 // If microdumps are enabled write also a microdump on the system log.
520 if (g_microdump)
521 g_microdump->WriteMinidump();
522 #endif
525 #if defined(OS_ANDROID)
526 const char kGoogleBreakpad[] = "google-breakpad";
527 #endif
529 size_t WriteLog(const char* buf, size_t nbytes) {
530 #if defined(OS_ANDROID)
531 return __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, buf);
532 #else
533 return sys_write(2, buf, nbytes);
534 #endif
537 size_t WriteNewline() {
538 return WriteLog("\n", 1);
541 #if defined(OS_ANDROID)
542 void AndroidLogWriteHorizontalRule() {
543 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
544 "### ### ### ### ### ### ### ### ### ### ### ### ###");
547 // Android's native crash handler outputs a diagnostic tombstone to the device
548 // log. By returning false from the HandlerCallbacks, breakpad will reinstall
549 // the previous (i.e. native) signal handlers before returning from its own
550 // handler. A Chrome build fingerprint is written to the log, so that the
551 // specific build of Chrome and the location of the archived Chrome symbols can
552 // be determined directly from it.
553 bool FinalizeCrashDoneAndroid(bool is_browser_process) {
554 base::android::BuildInfo* android_build_info =
555 base::android::BuildInfo::GetInstance();
557 AndroidLogWriteHorizontalRule();
558 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
559 "Chrome build fingerprint:");
560 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
561 android_build_info->package_version_name());
562 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
563 android_build_info->package_version_code());
564 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
565 CHROME_BUILD_ID);
566 AndroidLogWriteHorizontalRule();
568 if (!is_browser_process &&
569 android_build_info->sdk_int() >= 18 &&
570 my_strcmp(android_build_info->build_type(), "eng") != 0 &&
571 my_strcmp(android_build_info->build_type(), "userdebug") != 0) {
572 // On JB MR2 and later, the system crash handler displays a dialog. For
573 // renderer crashes, this is a bad user experience and so this is disabled
574 // for user builds of Android.
575 // TODO(cjhopman): There should be some way to recover the crash stack from
576 // non-uploading user clients. See http://crbug.com/273706.
577 __android_log_write(ANDROID_LOG_WARN,
578 kGoogleBreakpad,
579 "Tombstones are disabled on JB MR2+ user builds.");
580 AndroidLogWriteHorizontalRule();
581 return true;
583 return false;
585 #endif
587 bool CrashDone(const MinidumpDescriptor& minidump,
588 const bool upload,
589 const bool succeeded) {
590 // WARNING: this code runs in a compromised context. It may not call into
591 // libc nor allocate memory normally.
592 if (!succeeded) {
593 const char msg[] = "Failed to generate minidump.";
594 WriteLog(msg, sizeof(msg) - 1);
595 return false;
598 DCHECK(!minidump.IsFD());
600 BreakpadInfo info = {0};
601 info.filename = minidump.path();
602 info.fd = minidump.fd();
603 #if defined(ADDRESS_SANITIZER)
604 google_breakpad::PageAllocator allocator;
605 const size_t log_path_len = my_strlen(minidump.path());
606 char* log_path = reinterpret_cast<char*>(allocator.Alloc(log_path_len + 1));
607 my_memcpy(log_path, minidump.path(), log_path_len);
608 my_memcpy(log_path + log_path_len - 4, ".log", 4);
609 log_path[log_path_len] = '\0';
610 info.log_filename = log_path;
611 #endif
612 info.process_type = "browser";
613 info.process_type_length = 7;
614 info.distro = base::g_linux_distro;
615 info.distro_length = my_strlen(base::g_linux_distro);
616 info.upload = upload;
617 info.process_start_time = g_process_start_time;
618 info.oom_size = base::g_oom_size;
619 info.pid = g_pid;
620 info.crash_keys = g_crash_keys;
621 HandleCrashDump(info);
622 #if defined(OS_ANDROID)
623 return FinalizeCrashDoneAndroid(true /* is_browser_process */);
624 #else
625 return true;
626 #endif
629 // Wrapper function, do not add more code here.
630 bool CrashDoneNoUpload(const MinidumpDescriptor& minidump,
631 void* context,
632 bool succeeded) {
633 return CrashDone(minidump, false, succeeded);
636 #if !defined(OS_ANDROID)
637 // Wrapper function, do not add more code here.
638 bool CrashDoneUpload(const MinidumpDescriptor& minidump,
639 void* context,
640 bool succeeded) {
641 return CrashDone(minidump, true, succeeded);
643 #endif
645 #if defined(ADDRESS_SANITIZER)
646 extern "C"
647 void __asan_set_error_report_callback(void (*cb)(const char*));
649 extern "C"
650 void AsanLinuxBreakpadCallback(const char* report) {
651 g_asan_report_str = report;
652 // Send minidump here.
653 g_breakpad->SimulateSignalDelivery(SIGKILL);
655 #endif
657 void EnableCrashDumping(bool unattended) {
658 g_is_crash_reporter_enabled = true;
660 base::FilePath tmp_path("/tmp");
661 PathService::Get(base::DIR_TEMP, &tmp_path);
663 base::FilePath dumps_path(tmp_path);
664 if (GetCrashReporterClient()->GetCrashDumpLocation(&dumps_path)) {
665 base::FilePath logfile =
666 dumps_path.Append(GetCrashReporterClient()->GetReporterLogFilename());
667 std::string logfile_str = logfile.value();
668 const size_t crash_log_path_len = logfile_str.size() + 1;
669 g_crash_log_path = new char[crash_log_path_len];
670 strncpy(g_crash_log_path, logfile_str.c_str(), crash_log_path_len);
672 DCHECK(!g_breakpad);
673 MinidumpDescriptor minidump_descriptor(dumps_path.value());
674 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
675 switches::kFullMemoryCrashReport)) {
676 minidump_descriptor.set_size_limit(-1); // unlimited.
677 } else {
678 minidump_descriptor.set_size_limit(kMaxMinidumpFileSize);
680 #if defined(OS_ANDROID)
681 unattended = true; // Android never uploads directly.
682 #endif
683 if (unattended) {
684 g_breakpad = new ExceptionHandler(
685 minidump_descriptor,
686 nullptr,
687 CrashDoneNoUpload,
688 nullptr,
689 true, // Install handlers.
690 -1); // Server file descriptor. -1 for in-process.
691 return;
694 #if !defined(OS_ANDROID)
695 // Attended mode
696 g_breakpad = new ExceptionHandler(
697 minidump_descriptor,
698 nullptr,
699 CrashDoneUpload,
700 nullptr,
701 true, // Install handlers.
702 -1); // Server file descriptor. -1 for in-process.
703 #endif
706 #if defined(OS_ANDROID)
707 bool MicrodumpCrashDone(const MinidumpDescriptor& minidump,
708 void* context,
709 bool succeeded) {
710 // WARNING: this code runs in a compromised context. It may not call into
711 // libc nor allocate memory normally.
712 if (!succeeded) {
713 static const char msg[] = "Microdump crash handler failed.\n";
714 WriteLog(msg, sizeof(msg) - 1);
715 return false;
718 const bool is_browser_process = (context != nullptr);
719 return FinalizeCrashDoneAndroid(is_browser_process);
722 // The microdump handler does NOT upload anything. It just dumps out on the
723 // system console (logcat) a restricted and serialized variant of a minidump.
724 // See crbug.com/410294 for more details.
725 void InitMicrodumpCrashHandlerIfNecessary(const std::string& process_type) {
726 #if (!defined(ARCH_CPU_ARMEL) && !defined(ARCH_CPU_ARM64))
727 // TODO(primiano): For the moment microdumps are enabled only on arm (32/64).
728 // Extend support to other architectures (requires some breakpad changes).
729 return;
730 #endif
732 if (!GetCrashReporterClient()->ShouldEnableBreakpadMicrodumps())
733 return;
735 VLOG(1) << "Enabling microdumps crash handler (process_type:"
736 << process_type << ")";
738 // The exception handler runs in a compromised context and cannot use c_str()
739 // as that would require the heap. Therefore, we have to guarantee that the
740 // build fingerprint and product info pointers are always valid.
741 const char* product_name = nullptr;
742 const char* product_version = nullptr;
743 GetCrashReporterClient()->GetProductNameAndVersion(&product_name,
744 &product_version);
746 MinidumpDescriptor descriptor(MinidumpDescriptor::kMicrodumpOnConsole);
748 if (product_name && product_version) {
749 g_microdump_product_info = strdup(
750 (product_name + std::string(":") + product_version).c_str());
751 ANNOTATE_LEAKING_OBJECT_PTR(g_microdump_product_info);
752 descriptor.SetMicrodumpProductInfo(g_microdump_product_info);
755 const char* android_build_fp =
756 base::android::BuildInfo::GetInstance()->android_build_fp();
757 if (android_build_fp) {
758 g_microdump_build_fingerprint = strdup(android_build_fp);
759 ANNOTATE_LEAKING_OBJECT_PTR(g_microdump_build_fingerprint);
760 descriptor.SetMicrodumpBuildFingerprint(g_microdump_build_fingerprint);
763 DCHECK(!g_microdump);
764 bool is_browser_process = process_type.empty() || process_type == "webview";
765 g_microdump = new ExceptionHandler(
766 descriptor,
767 nullptr,
768 MicrodumpCrashDone,
769 reinterpret_cast<void*>(is_browser_process),
770 true, // Install handlers.
771 -1); // Server file descriptor. -1 for in-process.
772 return;
775 bool CrashDoneInProcessNoUpload(
776 const google_breakpad::MinidumpDescriptor& descriptor,
777 void* context,
778 const bool succeeded) {
779 // WARNING: this code runs in a compromised context. It may not call into
780 // libc nor allocate memory normally.
781 if (!succeeded) {
782 static const char msg[] = "Crash dump generation failed.\n";
783 WriteLog(msg, sizeof(msg) - 1);
784 return false;
787 // Start constructing the message to send to the browser.
788 BreakpadInfo info = {0};
789 info.filename = nullptr;
790 info.fd = descriptor.fd();
791 info.process_type = g_process_type;
792 info.process_type_length = my_strlen(g_process_type);
793 info.distro = nullptr;
794 info.distro_length = 0;
795 info.upload = false;
796 info.process_start_time = g_process_start_time;
797 info.pid = g_pid;
798 info.crash_keys = g_crash_keys;
799 HandleCrashDump(info);
800 return FinalizeCrashDoneAndroid(false /* is_browser_process */);
803 void EnableNonBrowserCrashDumping(const std::string& process_type,
804 int minidump_fd) {
805 // This will guarantee that the BuildInfo has been initialized and subsequent
806 // calls will not require memory allocation.
807 base::android::BuildInfo::GetInstance();
808 SetClientIdFromCommandLine(*base::CommandLine::ForCurrentProcess());
810 // On Android, the current sandboxing uses process isolation, in which the
811 // child process runs with a different UID. That breaks the normal crash
812 // reporting where the browser process generates the minidump by inspecting
813 // the child process. This is because the browser process now does not have
814 // the permission to access the states of the child process (as it has a
815 // different UID).
816 // TODO(jcivelli): http://b/issue?id=6776356 we should use a watchdog
817 // process forked from the renderer process that generates the minidump.
818 if (minidump_fd == -1) {
819 LOG(ERROR) << "Minidump file descriptor not found, crash reporting will "
820 " not work.";
821 return;
823 SetProcessStartTime();
824 g_pid = getpid();
826 g_is_crash_reporter_enabled = true;
827 // Save the process type (it is leaked).
828 const size_t process_type_len = process_type.size() + 1;
829 g_process_type = new char[process_type_len];
830 strncpy(g_process_type, process_type.c_str(), process_type_len);
831 new google_breakpad::ExceptionHandler(MinidumpDescriptor(minidump_fd),
832 nullptr, CrashDoneInProcessNoUpload, nullptr, true, -1);
834 #else
835 // Non-Browser = Extension, Gpu, Plugins, Ppapi and Renderer
836 class NonBrowserCrashHandler : public google_breakpad::CrashGenerationClient {
837 public:
838 NonBrowserCrashHandler()
839 : server_fd_(base::GlobalDescriptors::GetInstance()->Get(
840 kCrashDumpSignal)) {
843 ~NonBrowserCrashHandler() override {}
845 bool RequestDump(const void* crash_context,
846 size_t crash_context_size) override {
847 int fds[2] = { -1, -1 };
848 if (sys_socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
849 static const char msg[] = "Failed to create socket for crash dumping.\n";
850 WriteLog(msg, sizeof(msg) - 1);
851 return false;
854 // Start constructing the message to send to the browser.
855 char b; // Dummy variable for sys_read below.
856 const char* b_addr = &b; // Get the address of |b| so we can create the
857 // expected /proc/[pid]/syscall content in the
858 // browser to convert namespace tids.
860 // The length of the control message:
861 static const unsigned kControlMsgSize = sizeof(int);
862 static const unsigned kControlMsgSpaceSize = CMSG_SPACE(kControlMsgSize);
863 static const unsigned kControlMsgLenSize = CMSG_LEN(kControlMsgSize);
865 struct kernel_msghdr msg;
866 my_memset(&msg, 0, sizeof(struct kernel_msghdr));
867 struct kernel_iovec iov[kCrashIovSize];
868 iov[0].iov_base = const_cast<void*>(crash_context);
869 iov[0].iov_len = crash_context_size;
870 iov[1].iov_base = &b_addr;
871 iov[1].iov_len = sizeof(b_addr);
872 iov[2].iov_base = &fds[0];
873 iov[2].iov_len = sizeof(fds[0]);
874 iov[3].iov_base = &g_process_start_time;
875 iov[3].iov_len = sizeof(g_process_start_time);
876 iov[4].iov_base = &base::g_oom_size;
877 iov[4].iov_len = sizeof(base::g_oom_size);
878 google_breakpad::SerializedNonAllocatingMap* serialized_map;
879 iov[5].iov_len = g_crash_keys->Serialize(
880 const_cast<const google_breakpad::SerializedNonAllocatingMap**>(
881 &serialized_map));
882 iov[5].iov_base = serialized_map;
883 #if !defined(ADDRESS_SANITIZER)
884 static_assert(5 == kCrashIovSize - 1, "kCrashIovSize should equal 6");
885 #else
886 iov[6].iov_base = const_cast<char*>(g_asan_report_str);
887 iov[6].iov_len = kMaxAsanReportSize + 1;
888 static_assert(6 == kCrashIovSize - 1, "kCrashIovSize should equal 7");
889 #endif
891 msg.msg_iov = iov;
892 msg.msg_iovlen = kCrashIovSize;
893 char cmsg[kControlMsgSpaceSize];
894 my_memset(cmsg, 0, kControlMsgSpaceSize);
895 msg.msg_control = cmsg;
896 msg.msg_controllen = sizeof(cmsg);
898 struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
899 hdr->cmsg_level = SOL_SOCKET;
900 hdr->cmsg_type = SCM_RIGHTS;
901 hdr->cmsg_len = kControlMsgLenSize;
902 ((int*)CMSG_DATA(hdr))[0] = fds[1];
904 if (HANDLE_EINTR(sys_sendmsg(server_fd_, &msg, 0)) < 0) {
905 static const char errmsg[] = "Failed to tell parent about crash.\n";
906 WriteLog(errmsg, sizeof(errmsg) - 1);
907 IGNORE_RET(sys_close(fds[0]));
908 IGNORE_RET(sys_close(fds[1]));
909 return false;
911 IGNORE_RET(sys_close(fds[1]));
913 if (HANDLE_EINTR(sys_read(fds[0], &b, 1)) != 1) {
914 static const char errmsg[] = "Parent failed to complete crash dump.\n";
915 WriteLog(errmsg, sizeof(errmsg) - 1);
917 IGNORE_RET(sys_close(fds[0]));
919 return true;
922 private:
923 // The pipe FD to the browser process, which will handle the crash dumping.
924 const int server_fd_;
926 DISALLOW_COPY_AND_ASSIGN(NonBrowserCrashHandler);
929 void EnableNonBrowserCrashDumping() {
930 g_is_crash_reporter_enabled = true;
931 // We deliberately leak this object.
932 DCHECK(!g_breakpad);
934 g_breakpad = new ExceptionHandler(
935 MinidumpDescriptor("/tmp"), // Unused but needed or Breakpad will assert.
936 nullptr,
937 nullptr,
938 nullptr,
939 true,
940 -1);
941 g_breakpad->set_crash_generation_client(new NonBrowserCrashHandler());
943 #endif // defined(OS_ANDROID)
945 void SetCrashKeyValue(const base::StringPiece& key,
946 const base::StringPiece& value) {
947 g_crash_keys->SetKeyValue(key.data(), value.data());
950 void ClearCrashKey(const base::StringPiece& key) {
951 g_crash_keys->RemoveKey(key.data());
954 // GetCrashReporterClient() cannot call any Set methods until after
955 // InitCrashKeys().
956 void InitCrashKeys() {
957 g_crash_keys = new CrashKeyStorage;
958 GetCrashReporterClient()->RegisterCrashKeys();
959 base::debug::SetCrashKeyReportingFunctions(&SetCrashKeyValue, &ClearCrashKey);
962 // Miscellaneous initialization functions to call after Breakpad has been
963 // enabled.
964 void PostEnableBreakpadInitialization() {
965 SetProcessStartTime();
966 g_pid = getpid();
968 base::debug::SetDumpWithoutCrashingFunction(&DumpProcess);
969 #if defined(ADDRESS_SANITIZER)
970 // Register the callback for AddressSanitizer error reporting.
971 __asan_set_error_report_callback(AsanLinuxBreakpadCallback);
972 #endif
975 } // namespace
977 void LoadDataFromFD(google_breakpad::PageAllocator& allocator,
978 int fd, bool close_fd, uint8_t** file_data, size_t* size) {
979 STAT_STRUCT st;
980 if (FSTAT_FUNC(fd, &st) != 0) {
981 static const char msg[] = "Cannot upload crash dump: stat failed\n";
982 WriteLog(msg, sizeof(msg) - 1);
983 if (close_fd)
984 IGNORE_RET(sys_close(fd));
985 return;
988 *file_data = reinterpret_cast<uint8_t*>(allocator.Alloc(st.st_size));
989 if (!(*file_data)) {
990 static const char msg[] = "Cannot upload crash dump: cannot alloc\n";
991 WriteLog(msg, sizeof(msg) - 1);
992 if (close_fd)
993 IGNORE_RET(sys_close(fd));
994 return;
996 my_memset(*file_data, 0xf, st.st_size);
998 *size = st.st_size;
999 int byte_read = sys_read(fd, *file_data, *size);
1000 if (byte_read == -1) {
1001 static const char msg[] = "Cannot upload crash dump: read failed\n";
1002 WriteLog(msg, sizeof(msg) - 1);
1003 if (close_fd)
1004 IGNORE_RET(sys_close(fd));
1005 return;
1008 if (close_fd)
1009 IGNORE_RET(sys_close(fd));
1012 void LoadDataFromFile(google_breakpad::PageAllocator& allocator,
1013 const char* filename,
1014 int* fd, uint8_t** file_data, size_t* size) {
1015 // WARNING: this code runs in a compromised context. It may not call into
1016 // libc nor allocate memory normally.
1017 *fd = sys_open(filename, O_RDONLY, 0);
1018 *size = 0;
1020 if (*fd < 0) {
1021 static const char msg[] = "Cannot upload crash dump: failed to open\n";
1022 WriteLog(msg, sizeof(msg) - 1);
1023 return;
1026 LoadDataFromFD(allocator, *fd, true, file_data, size);
1029 // Spawn the appropriate upload process for the current OS:
1030 // - generic Linux invokes wget.
1031 // - ChromeOS invokes crash_reporter.
1032 // |dumpfile| is the path to the dump data file.
1033 // |mime_boundary| is only used on Linux.
1034 // |exe_buf| is only used on CrOS and is the crashing process' name.
1035 void ExecUploadProcessOrTerminate(const BreakpadInfo& info,
1036 const char* dumpfile,
1037 const char* mime_boundary,
1038 const char* exe_buf,
1039 google_breakpad::PageAllocator* allocator) {
1040 #if defined(OS_CHROMEOS)
1041 // CrOS uses crash_reporter instead of wget to report crashes,
1042 // it needs to know where the crash dump lives and the pid and uid of the
1043 // crashing process.
1044 static const char kCrashReporterBinary[] = "/sbin/crash_reporter";
1046 char pid_buf[kUint64StringSize];
1047 uint64_t pid_str_length = my_uint64_len(info.pid);
1048 my_uint64tos(pid_buf, info.pid, pid_str_length);
1049 pid_buf[pid_str_length] = '\0';
1051 char uid_buf[kUint64StringSize];
1052 uid_t uid = geteuid();
1053 uint64_t uid_str_length = my_uint64_len(uid);
1054 my_uint64tos(uid_buf, uid, uid_str_length);
1055 uid_buf[uid_str_length] = '\0';
1057 const char kChromeFlag[] = "--chrome=";
1058 size_t buf_len = my_strlen(dumpfile) + sizeof(kChromeFlag);
1059 char* chrome_flag = reinterpret_cast<char*>(allocator->Alloc(buf_len));
1060 chrome_flag[0] = '\0';
1061 my_strlcat(chrome_flag, kChromeFlag, buf_len);
1062 my_strlcat(chrome_flag, dumpfile, buf_len);
1064 const char kPidFlag[] = "--pid=";
1065 buf_len = my_strlen(pid_buf) + sizeof(kPidFlag);
1066 char* pid_flag = reinterpret_cast<char*>(allocator->Alloc(buf_len));
1067 pid_flag[0] = '\0';
1068 my_strlcat(pid_flag, kPidFlag, buf_len);
1069 my_strlcat(pid_flag, pid_buf, buf_len);
1071 const char kUidFlag[] = "--uid=";
1072 buf_len = my_strlen(uid_buf) + sizeof(kUidFlag);
1073 char* uid_flag = reinterpret_cast<char*>(allocator->Alloc(buf_len));
1074 uid_flag[0] = '\0';
1075 my_strlcat(uid_flag, kUidFlag, buf_len);
1076 my_strlcat(uid_flag, uid_buf, buf_len);
1078 const char kExeBuf[] = "--exe=";
1079 buf_len = my_strlen(exe_buf) + sizeof(kExeBuf);
1080 char* exe_flag = reinterpret_cast<char*>(allocator->Alloc(buf_len));
1081 exe_flag[0] = '\0';
1082 my_strlcat(exe_flag, kExeBuf, buf_len);
1083 my_strlcat(exe_flag, exe_buf, buf_len);
1085 const char* args[] = {
1086 kCrashReporterBinary,
1087 chrome_flag,
1088 pid_flag,
1089 uid_flag,
1090 exe_flag,
1091 nullptr,
1093 static const char msg[] = "Cannot upload crash dump: cannot exec "
1094 "/sbin/crash_reporter\n";
1095 #else
1096 // Compress |dumpfile| with gzip.
1097 const pid_t gzip_child = sys_fork();
1098 if (gzip_child < 0) {
1099 static const char msg[] = "sys_fork() for gzip process failed.\n";
1100 WriteLog(msg, sizeof(msg) - 1);
1101 sys__exit(1);
1103 if (!gzip_child) {
1104 // gzip process.
1105 const char* args[] = {
1106 "/bin/gzip",
1107 "-f", // Do not prompt to verify before overwriting.
1108 dumpfile,
1109 nullptr,
1111 execve(args[0], const_cast<char**>(args), environ);
1112 static const char msg[] = "Cannot exec gzip.\n";
1113 WriteLog(msg, sizeof(msg) - 1);
1114 sys__exit(1);
1116 // Wait for gzip process.
1117 int status = 0;
1118 if (sys_waitpid(gzip_child, &status, 0) != gzip_child ||
1119 !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
1120 static const char msg[] = "sys_waitpid() for gzip process failed.\n";
1121 WriteLog(msg, sizeof(msg) - 1);
1122 sys_kill(gzip_child, SIGKILL);
1123 sys__exit(1);
1126 static const char kGzipExtension[] = ".gz";
1127 const size_t gzip_file_size = my_strlen(dumpfile) + sizeof(kGzipExtension);
1128 char* const gzip_file = reinterpret_cast<char*>(allocator->Alloc(
1129 gzip_file_size));
1130 my_strlcpy(gzip_file, dumpfile, gzip_file_size);
1131 my_strlcat(gzip_file, kGzipExtension, gzip_file_size);
1133 // Rename |gzip_file| to |dumpfile| (the original file was deleted by gzip).
1134 if (rename(gzip_file, dumpfile)) {
1135 static const char msg[] = "Failed to rename gzipped file.\n";
1136 WriteLog(msg, sizeof(msg) - 1);
1137 sys__exit(1);
1140 // The --header argument to wget looks like:
1141 // --header=Content-Encoding: gzip
1142 // --header=Content-Type: multipart/form-data; boundary=XYZ
1143 // where the boundary has two fewer leading '-' chars
1144 static const char header_content_encoding[] =
1145 "--header=Content-Encoding: gzip";
1146 static const char header_msg[] =
1147 "--header=Content-Type: multipart/form-data; boundary=";
1148 const size_t header_content_type_size =
1149 sizeof(header_msg) - 1 + my_strlen(mime_boundary) - 2 + 1;
1150 char* const header_content_type = reinterpret_cast<char*>(allocator->Alloc(
1151 header_content_type_size));
1152 my_strlcpy(header_content_type, header_msg, header_content_type_size);
1153 my_strlcat(header_content_type, mime_boundary + 2, header_content_type_size);
1155 // The --post-file argument to wget looks like:
1156 // --post-file=/tmp/...
1157 static const char post_file_msg[] = "--post-file=";
1158 const size_t post_file_size =
1159 sizeof(post_file_msg) - 1 + my_strlen(dumpfile) + 1;
1160 char* const post_file = reinterpret_cast<char*>(allocator->Alloc(
1161 post_file_size));
1162 my_strlcpy(post_file, post_file_msg, post_file_size);
1163 my_strlcat(post_file, dumpfile, post_file_size);
1165 static const char kWgetBinary[] = "/usr/bin/wget";
1166 const char* args[] = {
1167 kWgetBinary,
1168 header_content_encoding,
1169 header_content_type,
1170 post_file,
1171 kUploadURL,
1172 "--timeout=10", // Set a timeout so we don't hang forever.
1173 "--tries=1", // Don't retry if the upload fails.
1174 "-O", // output reply to fd 3
1175 "/dev/fd/3",
1176 nullptr,
1178 static const char msg[] = "Cannot upload crash dump: cannot exec "
1179 "/usr/bin/wget\n";
1180 #endif
1181 execve(args[0], const_cast<char**>(args), environ);
1182 WriteLog(msg, sizeof(msg) - 1);
1183 sys__exit(1);
1186 // Runs in the helper process to wait for the upload process running
1187 // ExecUploadProcessOrTerminate() to finish. Returns the number of bytes written
1188 // to |fd| and save the written contents to |buf|.
1189 // |buf| needs to be big enough to hold |bytes_to_read| + 1 characters.
1190 size_t WaitForCrashReportUploadProcess(int fd, size_t bytes_to_read,
1191 char* buf) {
1192 size_t bytes_read = 0;
1194 // Upload should finish in about 10 seconds. Add a few more 500 ms
1195 // internals to account for process startup time.
1196 for (size_t wait_count = 0; wait_count < 24; ++wait_count) {
1197 struct kernel_pollfd poll_fd;
1198 poll_fd.fd = fd;
1199 poll_fd.events = POLLIN | POLLPRI | POLLERR;
1200 int ret = sys_poll(&poll_fd, 1, 500);
1201 if (ret < 0) {
1202 // Error
1203 break;
1204 } else if (ret > 0) {
1205 // There is data to read.
1206 ssize_t len = HANDLE_EINTR(
1207 sys_read(fd, buf + bytes_read, bytes_to_read - bytes_read));
1208 if (len < 0)
1209 break;
1210 bytes_read += len;
1211 if (bytes_read == bytes_to_read)
1212 break;
1214 // |ret| == 0 -> timed out, continue waiting.
1215 // or |bytes_read| < |bytes_to_read| still, keep reading.
1217 buf[bytes_to_read] = 0; // Always NUL terminate the buffer.
1218 return bytes_read;
1221 // |buf| should be |expected_len| + 1 characters in size and nullptr terminated.
1222 bool IsValidCrashReportId(const char* buf, size_t bytes_read,
1223 size_t expected_len) {
1224 if (bytes_read != expected_len)
1225 return false;
1226 #if defined(OS_CHROMEOS)
1227 return my_strcmp(buf, "_sys_cr_finished") == 0;
1228 #else
1229 for (size_t i = 0; i < bytes_read; ++i) {
1230 if (!my_isxdigit(buf[i]))
1231 return false;
1233 return true;
1234 #endif
1237 // |buf| should be |expected_len| + 1 characters in size and nullptr terminated.
1238 void HandleCrashReportId(const char* buf, size_t bytes_read,
1239 size_t expected_len) {
1240 WriteNewline();
1241 if (!IsValidCrashReportId(buf, bytes_read, expected_len)) {
1242 #if defined(OS_CHROMEOS)
1243 static const char msg[] =
1244 "System crash-reporter failed to process crash report.";
1245 #else
1246 static const char msg[] = "Failed to get crash dump id.";
1247 #endif
1248 WriteLog(msg, sizeof(msg) - 1);
1249 WriteNewline();
1251 static const char id_msg[] = "Report Id: ";
1252 WriteLog(id_msg, sizeof(id_msg) - 1);
1253 WriteLog(buf, bytes_read);
1254 WriteNewline();
1255 return;
1258 #if defined(OS_CHROMEOS)
1259 static const char msg[] = "Crash dump received by crash_reporter\n";
1260 WriteLog(msg, sizeof(msg) - 1);
1261 #else
1262 // Write crash dump id to stderr.
1263 static const char msg[] = "Crash dump id: ";
1264 WriteLog(msg, sizeof(msg) - 1);
1265 WriteLog(buf, my_strlen(buf));
1266 WriteNewline();
1268 // Write crash dump id to crash log as: seconds_since_epoch,crash_id
1269 struct kernel_timeval tv;
1270 if (g_crash_log_path && !sys_gettimeofday(&tv, nullptr)) {
1271 uint64_t time = kernel_timeval_to_ms(&tv) / 1000;
1272 char time_str[kUint64StringSize];
1273 const unsigned time_len = my_uint64_len(time);
1274 my_uint64tos(time_str, time, time_len);
1276 const int kLogOpenFlags = O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC;
1277 int log_fd = sys_open(g_crash_log_path, kLogOpenFlags, 0600);
1278 if (log_fd > 0) {
1279 sys_write(log_fd, time_str, time_len);
1280 sys_write(log_fd, ",", 1);
1281 sys_write(log_fd, buf, my_strlen(buf));
1282 sys_write(log_fd, "\n", 1);
1283 IGNORE_RET(sys_close(log_fd));
1286 #endif
1289 #if defined(OS_CHROMEOS)
1290 const char* GetCrashingProcessName(const BreakpadInfo& info,
1291 google_breakpad::PageAllocator* allocator) {
1292 // Symlink to process binary is at /proc/###/exe.
1293 char linkpath[kUint64StringSize + sizeof("/proc/") + sizeof("/exe")] =
1294 "/proc/";
1295 uint64_t pid_value_len = my_uint64_len(info.pid);
1296 my_uint64tos(linkpath + sizeof("/proc/") - 1, info.pid, pid_value_len);
1297 linkpath[sizeof("/proc/") - 1 + pid_value_len] = '\0';
1298 my_strlcat(linkpath, "/exe", sizeof(linkpath));
1300 const int kMaxSize = 4096;
1301 char* link = reinterpret_cast<char*>(allocator->Alloc(kMaxSize));
1302 if (link) {
1303 ssize_t size = readlink(linkpath, link, kMaxSize);
1304 if (size < kMaxSize && size > 0) {
1305 // readlink(2) doesn't add a terminating NUL, so do it now.
1306 link[size] = '\0';
1308 const char* name = my_strrchr(link, '/');
1309 if (name)
1310 return name + 1;
1311 return link;
1314 // Either way too long, or a read error.
1315 return "chrome-crash-unknown-process";
1317 #endif
1319 void HandleCrashDump(const BreakpadInfo& info) {
1320 int dumpfd;
1321 bool keep_fd = false;
1322 size_t dump_size;
1323 uint8_t* dump_data;
1324 google_breakpad::PageAllocator allocator;
1325 const char* exe_buf = nullptr;
1327 if (GetCrashReporterClient()->HandleCrashDump(info.filename)) {
1328 return;
1331 #if defined(OS_CHROMEOS)
1332 // Grab the crashing process' name now, when it should still be available.
1333 // If we try to do this later in our grandchild the crashing process has
1334 // already terminated.
1335 exe_buf = GetCrashingProcessName(info, &allocator);
1336 #endif
1338 if (info.fd != -1) {
1339 // Dump is provided with an open FD.
1340 keep_fd = true;
1341 dumpfd = info.fd;
1343 // The FD is pointing to the end of the file.
1344 // Rewind, we'll read the data next.
1345 if (lseek(dumpfd, 0, SEEK_SET) == -1) {
1346 static const char msg[] = "Cannot upload crash dump: failed to "
1347 "reposition minidump FD\n";
1348 WriteLog(msg, sizeof(msg) - 1);
1349 IGNORE_RET(sys_close(dumpfd));
1350 return;
1352 LoadDataFromFD(allocator, info.fd, false, &dump_data, &dump_size);
1353 } else {
1354 // Dump is provided with a path.
1355 keep_fd = false;
1356 LoadDataFromFile(allocator, info.filename, &dumpfd, &dump_data, &dump_size);
1359 // TODO(jcivelli): make log work when using FDs.
1360 #if defined(ADDRESS_SANITIZER)
1361 int logfd;
1362 size_t log_size;
1363 uint8_t* log_data;
1364 // Load the AddressSanitizer log into log_data.
1365 LoadDataFromFile(allocator, info.log_filename, &logfd, &log_data, &log_size);
1366 #endif
1368 // We need to build a MIME block for uploading to the server. Since we are
1369 // going to fork and run wget, it needs to be written to a temp file.
1370 const int ufd = sys_open("/dev/urandom", O_RDONLY, 0);
1371 if (ufd < 0) {
1372 static const char msg[] = "Cannot upload crash dump because /dev/urandom"
1373 " is missing\n";
1374 WriteLog(msg, sizeof(msg) - 1);
1375 return;
1378 static const char temp_file_template[] =
1379 "/tmp/chromium-upload-XXXXXXXXXXXXXXXX";
1380 char temp_file[sizeof(temp_file_template)];
1381 int temp_file_fd = -1;
1382 if (keep_fd) {
1383 temp_file_fd = dumpfd;
1384 // Rewind the destination, we are going to overwrite it.
1385 if (lseek(dumpfd, 0, SEEK_SET) == -1) {
1386 static const char msg[] = "Cannot upload crash dump: failed to "
1387 "reposition minidump FD (2)\n";
1388 WriteLog(msg, sizeof(msg) - 1);
1389 IGNORE_RET(sys_close(dumpfd));
1390 return;
1392 } else {
1393 if (info.upload) {
1394 my_memcpy(temp_file, temp_file_template, sizeof(temp_file_template));
1396 for (unsigned i = 0; i < 10; ++i) {
1397 uint64_t t;
1398 sys_read(ufd, &t, sizeof(t));
1399 write_uint64_hex(temp_file + sizeof(temp_file) - (16 + 1), t);
1401 temp_file_fd = sys_open(temp_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
1402 if (temp_file_fd >= 0)
1403 break;
1406 if (temp_file_fd < 0) {
1407 static const char msg[] = "Failed to create temporary file in /tmp: "
1408 "cannot upload crash dump\n";
1409 WriteLog(msg, sizeof(msg) - 1);
1410 IGNORE_RET(sys_close(ufd));
1411 return;
1413 } else {
1414 temp_file_fd = sys_open(info.filename, O_WRONLY, 0600);
1415 if (temp_file_fd < 0) {
1416 static const char msg[] = "Failed to save crash dump: failed to open\n";
1417 WriteLog(msg, sizeof(msg) - 1);
1418 IGNORE_RET(sys_close(ufd));
1419 return;
1424 // The MIME boundary is 28 hyphens, followed by a 64-bit nonce and a NUL.
1425 char mime_boundary[28 + 16 + 1];
1426 my_memset(mime_boundary, '-', 28);
1427 uint64_t boundary_rand;
1428 sys_read(ufd, &boundary_rand, sizeof(boundary_rand));
1429 write_uint64_hex(mime_boundary + 28, boundary_rand);
1430 mime_boundary[28 + 16] = 0;
1431 IGNORE_RET(sys_close(ufd));
1433 // The MIME block looks like this:
1434 // BOUNDARY \r\n
1435 // Content-Disposition: form-data; name="prod" \r\n \r\n
1436 // Chrome_Linux \r\n
1437 // BOUNDARY \r\n
1438 // Content-Disposition: form-data; name="ver" \r\n \r\n
1439 // 1.2.3.4 \r\n
1440 // BOUNDARY \r\n
1442 // zero or one:
1443 // Content-Disposition: form-data; name="ptime" \r\n \r\n
1444 // abcdef \r\n
1445 // BOUNDARY \r\n
1447 // zero or one:
1448 // Content-Disposition: form-data; name="ptype" \r\n \r\n
1449 // abcdef \r\n
1450 // BOUNDARY \r\n
1452 // zero or one:
1453 // Content-Disposition: form-data; name="lsb-release" \r\n \r\n
1454 // abcdef \r\n
1455 // BOUNDARY \r\n
1457 // zero or one:
1458 // Content-Disposition: form-data; name="oom-size" \r\n \r\n
1459 // 1234567890 \r\n
1460 // BOUNDARY \r\n
1462 // zero or more (up to CrashKeyStorage::num_entries = 64):
1463 // Content-Disposition: form-data; name=crash-key-name \r\n
1464 // crash-key-value \r\n
1465 // BOUNDARY \r\n
1467 // Content-Disposition: form-data; name="dump"; filename="dump" \r\n
1468 // Content-Type: application/octet-stream \r\n \r\n
1469 // <dump contents>
1470 // \r\n BOUNDARY -- \r\n
1472 #if defined(OS_CHROMEOS)
1473 CrashReporterWriter writer(temp_file_fd);
1474 #else
1475 MimeWriter writer(temp_file_fd, mime_boundary);
1476 #endif
1478 const char* product_name = "";
1479 const char* version = "";
1481 GetCrashReporterClient()->GetProductNameAndVersion(&product_name, &version);
1483 writer.AddBoundary();
1484 writer.AddPairString("prod", product_name);
1485 writer.AddBoundary();
1486 writer.AddPairString("ver", version);
1487 writer.AddBoundary();
1488 if (info.pid > 0) {
1489 char pid_value_buf[kUint64StringSize];
1490 uint64_t pid_value_len = my_uint64_len(info.pid);
1491 my_uint64tos(pid_value_buf, info.pid, pid_value_len);
1492 static const char pid_key_name[] = "pid";
1493 writer.AddPairData(pid_key_name, sizeof(pid_key_name) - 1,
1494 pid_value_buf, pid_value_len);
1495 writer.AddBoundary();
1497 #if defined(OS_ANDROID)
1498 // Addtional MIME blocks are added for logging on Android devices.
1499 static const char android_build_id[] = "android_build_id";
1500 static const char android_build_fp[] = "android_build_fp";
1501 static const char device[] = "device";
1502 static const char model[] = "model";
1503 static const char brand[] = "brand";
1504 static const char exception_info[] = "exception_info";
1506 base::android::BuildInfo* android_build_info =
1507 base::android::BuildInfo::GetInstance();
1508 writer.AddPairString(
1509 android_build_id, android_build_info->android_build_id());
1510 writer.AddBoundary();
1511 writer.AddPairString(
1512 android_build_fp, android_build_info->android_build_fp());
1513 writer.AddBoundary();
1514 writer.AddPairString(device, android_build_info->device());
1515 writer.AddBoundary();
1516 writer.AddPairString(model, android_build_info->model());
1517 writer.AddBoundary();
1518 writer.AddPairString(brand, android_build_info->brand());
1519 writer.AddBoundary();
1520 if (android_build_info->java_exception_info() != nullptr) {
1521 writer.AddPairString(exception_info,
1522 android_build_info->java_exception_info());
1523 writer.AddBoundary();
1525 #endif
1526 writer.Flush();
1529 if (info.process_start_time > 0) {
1530 struct kernel_timeval tv;
1531 if (!sys_gettimeofday(&tv, nullptr)) {
1532 uint64_t time = kernel_timeval_to_ms(&tv);
1533 if (time > info.process_start_time) {
1534 time -= info.process_start_time;
1535 char time_str[kUint64StringSize];
1536 const unsigned time_len = my_uint64_len(time);
1537 my_uint64tos(time_str, time, time_len);
1539 static const char process_time_msg[] = "ptime";
1540 writer.AddPairData(process_time_msg, sizeof(process_time_msg) - 1,
1541 time_str, time_len);
1542 writer.AddBoundary();
1543 writer.Flush();
1548 if (info.process_type_length) {
1549 writer.AddPairString("ptype", info.process_type);
1550 writer.AddBoundary();
1551 writer.Flush();
1554 if (info.distro_length) {
1555 static const char distro_msg[] = "lsb-release";
1556 writer.AddPairString(distro_msg, info.distro);
1557 writer.AddBoundary();
1558 writer.Flush();
1561 if (info.oom_size) {
1562 char oom_size_str[kUint64StringSize];
1563 const unsigned oom_size_len = my_uint64_len(info.oom_size);
1564 my_uint64tos(oom_size_str, info.oom_size, oom_size_len);
1565 static const char oom_size_msg[] = "oom-size";
1566 writer.AddPairData(oom_size_msg, sizeof(oom_size_msg) - 1,
1567 oom_size_str, oom_size_len);
1568 writer.AddBoundary();
1569 writer.Flush();
1572 if (info.crash_keys) {
1573 CrashKeyStorage::Iterator crash_key_iterator(*info.crash_keys);
1574 const CrashKeyStorage::Entry* entry;
1575 while ((entry = crash_key_iterator.Next())) {
1576 writer.AddPairString(entry->key, entry->value);
1577 writer.AddBoundary();
1578 writer.Flush();
1582 writer.AddFileContents(g_dump_msg, dump_data, dump_size);
1583 #if defined(ADDRESS_SANITIZER)
1584 // Append a multipart boundary and the contents of the AddressSanitizer log.
1585 writer.AddBoundary();
1586 writer.AddFileContents(g_log_msg, log_data, log_size);
1587 #endif
1588 writer.AddEnd();
1589 writer.Flush();
1591 IGNORE_RET(sys_close(temp_file_fd));
1593 #if defined(OS_ANDROID)
1594 if (info.filename) {
1595 int filename_length = my_strlen(info.filename);
1597 // If this was a file, we need to copy it to the right place and use the
1598 // right file name so it gets uploaded by the browser.
1599 const char msg[] = "Output crash dump file:";
1600 WriteLog(msg, sizeof(msg) - 1);
1601 WriteLog(info.filename, filename_length - 1);
1603 char pid_buf[kUint64StringSize];
1604 uint64_t pid_str_length = my_uint64_len(info.pid);
1605 my_uint64tos(pid_buf, info.pid, pid_str_length);
1607 // -1 because we won't need the null terminator on the original filename.
1608 unsigned done_filename_len = filename_length - 1 + pid_str_length;
1609 char* done_filename = reinterpret_cast<char*>(
1610 allocator.Alloc(done_filename_len));
1611 // Rename the file such that the pid is the suffix in order signal to other
1612 // processes that the minidump is complete. The advantage of using the pid
1613 // as the suffix is that it is trivial to associate the minidump with the
1614 // crashed process.
1615 // Finally, note strncpy prevents null terminators from
1616 // being copied. Pad the rest with 0's.
1617 my_strncpy(done_filename, info.filename, done_filename_len);
1618 // Append the suffix a null terminator should be added.
1619 my_strncat(done_filename, pid_buf, pid_str_length);
1620 // Rename the minidump file to signal that it is complete.
1621 if (rename(info.filename, done_filename)) {
1622 const char failed_msg[] = "Failed to rename:";
1623 WriteLog(failed_msg, sizeof(failed_msg) - 1);
1624 WriteLog(info.filename, filename_length - 1);
1625 const char to_msg[] = "to";
1626 WriteLog(to_msg, sizeof(to_msg) - 1);
1627 WriteLog(done_filename, done_filename_len - 1);
1630 #endif
1632 if (!info.upload)
1633 return;
1635 const pid_t child = sys_fork();
1636 if (!child) {
1637 // Spawned helper process.
1639 // This code is called both when a browser is crashing (in which case,
1640 // nothing really matters any more) and when a renderer/plugin crashes, in
1641 // which case we need to continue.
1643 // Since we are a multithreaded app, if we were just to fork(), we might
1644 // grab file descriptors which have just been created in another thread and
1645 // hold them open for too long.
1647 // Thus, we have to loop and try and close everything.
1648 const int fd = sys_open("/proc/self/fd", O_DIRECTORY | O_RDONLY, 0);
1649 if (fd < 0) {
1650 for (unsigned i = 3; i < 8192; ++i)
1651 IGNORE_RET(sys_close(i));
1652 } else {
1653 google_breakpad::DirectoryReader reader(fd);
1654 const char* name;
1655 while (reader.GetNextEntry(&name)) {
1656 int i;
1657 if (my_strtoui(&i, name) && i > 2 && i != fd)
1658 IGNORE_RET(sys_close(i));
1659 reader.PopEntry();
1662 IGNORE_RET(sys_close(fd));
1665 IGNORE_RET(sys_setsid());
1667 // Leave one end of a pipe in the upload process and watch for it getting
1668 // closed by the upload process exiting.
1669 int fds[2];
1670 if (sys_pipe(fds) >= 0) {
1671 const pid_t upload_child = sys_fork();
1672 if (!upload_child) {
1673 // Upload process.
1674 IGNORE_RET(sys_close(fds[0]));
1675 IGNORE_RET(sys_dup2(fds[1], 3));
1676 ExecUploadProcessOrTerminate(info, temp_file, mime_boundary, exe_buf,
1677 &allocator);
1680 // Helper process.
1681 if (upload_child > 0) {
1682 IGNORE_RET(sys_close(fds[1]));
1684 const size_t kCrashIdLength = 16;
1685 char id_buf[kCrashIdLength + 1];
1686 size_t bytes_read =
1687 WaitForCrashReportUploadProcess(fds[0], kCrashIdLength, id_buf);
1688 HandleCrashReportId(id_buf, bytes_read, kCrashIdLength);
1690 if (sys_waitpid(upload_child, nullptr, WNOHANG) == 0) {
1691 // Upload process is still around, kill it.
1692 sys_kill(upload_child, SIGKILL);
1697 // Helper process.
1698 IGNORE_RET(sys_unlink(info.filename));
1699 #if defined(ADDRESS_SANITIZER)
1700 IGNORE_RET(sys_unlink(info.log_filename));
1701 #endif
1702 IGNORE_RET(sys_unlink(temp_file));
1703 sys__exit(0);
1706 // Main browser process.
1707 if (child <= 0)
1708 return;
1709 (void) HANDLE_EINTR(sys_waitpid(child, nullptr, 0));
1712 void InitCrashReporter(const std::string& process_type) {
1713 #if defined(OS_ANDROID)
1714 // This will guarantee that the BuildInfo has been initialized and subsequent
1715 // calls will not require memory allocation.
1716 base::android::BuildInfo::GetInstance();
1718 // Handler registration is LIFO. Install the microdump handler first, such
1719 // that if conventional minidump crash reporting is enabled below, it takes
1720 // precedence (i.e. its handler is run first) over the microdump handler.
1721 InitMicrodumpCrashHandlerIfNecessary(process_type);
1722 #endif
1723 // Determine the process type and take appropriate action.
1724 const base::CommandLine& parsed_command_line =
1725 *base::CommandLine::ForCurrentProcess();
1726 if (parsed_command_line.HasSwitch(switches::kDisableBreakpad))
1727 return;
1729 if (process_type.empty()) {
1730 bool enable_breakpad = GetCrashReporterClient()->GetCollectStatsConsent() ||
1731 GetCrashReporterClient()->IsRunningUnattended();
1732 enable_breakpad &=
1733 !parsed_command_line.HasSwitch(switches::kDisableBreakpad);
1734 if (!enable_breakpad) {
1735 enable_breakpad = parsed_command_line.HasSwitch(
1736 switches::kEnableCrashReporterForTesting);
1738 if (!enable_breakpad) {
1739 VLOG(1) << "Breakpad disabled";
1740 return;
1743 InitCrashKeys();
1744 EnableCrashDumping(GetCrashReporterClient()->IsRunningUnattended());
1745 } else if (GetCrashReporterClient()->EnableBreakpadForProcess(process_type)) {
1746 #if defined(OS_ANDROID)
1747 NOTREACHED() << "Breakpad initialized with InitCrashReporter() instead of "
1748 "InitNonBrowserCrashReporter in " << process_type << " process.";
1749 return;
1750 #else
1751 // We might be chrooted in a zygote or renderer process so we cannot call
1752 // GetCollectStatsConsent because that needs access the the user's home
1753 // dir. Instead, we set a command line flag for these processes.
1754 // Even though plugins are not chrooted, we share the same code path for
1755 // simplicity.
1756 if (!parsed_command_line.HasSwitch(switches::kEnableCrashReporter))
1757 return;
1758 InitCrashKeys();
1759 SetClientIdFromCommandLine(parsed_command_line);
1760 EnableNonBrowserCrashDumping();
1761 VLOG(1) << "Non Browser crash dumping enabled for: " << process_type;
1762 #endif // #if defined(OS_ANDROID)
1765 PostEnableBreakpadInitialization();
1768 #if defined(OS_ANDROID)
1769 void InitNonBrowserCrashReporterForAndroid(const std::string& process_type) {
1770 const base::CommandLine* command_line =
1771 base::CommandLine::ForCurrentProcess();
1773 // Handler registration is LIFO. Install the microdump handler first, such
1774 // that if conventional minidump crash reporting is enabled below, it takes
1775 // precedence (i.e. its handler is run first) over the microdump handler.
1776 InitMicrodumpCrashHandlerIfNecessary(process_type);
1778 if (command_line->HasSwitch(switches::kEnableCrashReporter)) {
1779 // On Android we need to provide a FD to the file where the minidump is
1780 // generated as the renderer and browser run with different UIDs
1781 // (preventing the browser from inspecting the renderer process).
1782 int minidump_fd = base::GlobalDescriptors::GetInstance()->MaybeGet(
1783 GetCrashReporterClient()->GetAndroidMinidumpDescriptor());
1784 if (minidump_fd < 0) {
1785 NOTREACHED() << "Could not find minidump FD, crash reporting disabled.";
1786 } else {
1787 InitCrashKeys();
1788 EnableNonBrowserCrashDumping(process_type, minidump_fd);
1792 #endif // OS_ANDROID
1794 bool IsCrashReporterEnabled() {
1795 return g_is_crash_reporter_enabled;
1798 } // namespace breakpad