OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // For linux_syscall_support.h. This makes it safe to call embedded system | 5 // For linux_syscall_support.h. This makes it safe to call embedded system |
6 // calls when in seccomp mode. | 6 // calls when in seccomp mode. |
7 #define SYS_SYSCALL_ENTRYPOINT "playground$syscallEntryPoint" | 7 #define SYS_SYSCALL_ENTRYPOINT "playground$syscallEntryPoint" |
8 | 8 |
9 #include "chrome/app/breakpad_linux.h" | 9 #include "chrome/app/breakpad_linux.h" |
10 | 10 |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 const char kUploadURL[] = "https://clients2.google.com/cr/staging_report"; | 86 const char kUploadURL[] = "https://clients2.google.com/cr/staging_report"; |
87 #endif | 87 #endif |
88 | 88 |
89 bool g_is_crash_reporter_enabled = false; | 89 bool g_is_crash_reporter_enabled = false; |
90 uint64_t g_process_start_time = 0; | 90 uint64_t g_process_start_time = 0; |
91 char* g_crash_log_path = NULL; | 91 char* g_crash_log_path = NULL; |
92 ExceptionHandler* g_breakpad = NULL; | 92 ExceptionHandler* g_breakpad = NULL; |
93 #if defined(ADDRESS_SANITIZER) | 93 #if defined(ADDRESS_SANITIZER) |
94 const char* g_asan_report_str = NULL; | 94 const char* g_asan_report_str = NULL; |
95 #endif | 95 #endif |
| 96 #if defined(OS_ANDROID) |
| 97 char* g_process_type = NULL; |
| 98 #endif |
96 | 99 |
97 // Writes the value |v| as 16 hex characters to the memory pointed at by | 100 // Writes the value |v| as 16 hex characters to the memory pointed at by |
98 // |output|. | 101 // |output|. |
99 void write_uint64_hex(char* output, uint64_t v) { | 102 void write_uint64_hex(char* output, uint64_t v) { |
100 static const char hextable[] = "0123456789abcdef"; | 103 static const char hextable[] = "0123456789abcdef"; |
101 | 104 |
102 for (int i = 15; i >= 0; --i) { | 105 for (int i = 15; i >= 0; --i) { |
103 output[i] = hextable[v & 15]; | 106 output[i] = hextable[v & 15]; |
104 v >>= 4; | 107 v >>= 4; |
105 } | 108 } |
(...skipping 13 matching lines...) Expand all Loading... |
119 uint64_t kernel_timeval_to_ms(struct kernel_timeval *tv) { | 122 uint64_t kernel_timeval_to_ms(struct kernel_timeval *tv) { |
120 uint64_t ret = tv->tv_sec; // Avoid overflow by explicitly using a uint64_t. | 123 uint64_t ret = tv->tv_sec; // Avoid overflow by explicitly using a uint64_t. |
121 ret *= 1000; | 124 ret *= 1000; |
122 ret += tv->tv_usec / 1000; | 125 ret += tv->tv_usec / 1000; |
123 return ret; | 126 return ret; |
124 } | 127 } |
125 | 128 |
126 // String buffer size to use to convert a uint64_t to string. | 129 // String buffer size to use to convert a uint64_t to string. |
127 size_t kUint64StringSize = 21; | 130 size_t kUint64StringSize = 21; |
128 | 131 |
| 132 void SetProcessStartTime() { |
| 133 // Set the base process start time value. |
| 134 struct timeval tv; |
| 135 if (!gettimeofday(&tv, NULL)) |
| 136 g_process_start_time = timeval_to_ms(&tv); |
| 137 else |
| 138 g_process_start_time = 0; |
| 139 } |
| 140 |
129 // uint64_t version of my_int_len() from | 141 // uint64_t version of my_int_len() from |
130 // breakpad/src/common/linux/linux_libc_support.h. Return the length of the | 142 // breakpad/src/common/linux/linux_libc_support.h. Return the length of the |
131 // given, non-negative integer when expressed in base 10. | 143 // given, non-negative integer when expressed in base 10. |
132 unsigned my_uint64_len(uint64_t i) { | 144 unsigned my_uint64_len(uint64_t i) { |
133 if (!i) | 145 if (!i) |
134 return 1; | 146 return 1; |
135 | 147 |
136 unsigned len = 0; | 148 unsigned len = 0; |
137 while (i) { | 149 while (i) { |
138 len++; | 150 len++; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 while (*dest) | 184 while (*dest) |
173 dest++; | 185 dest++; |
174 while (len--) | 186 while (len--) |
175 if (!(*dest++ = *src++)) | 187 if (!(*dest++ = *src++)) |
176 return ret; | 188 return ret; |
177 *dest = 0; | 189 *dest = 0; |
178 return ret; | 190 return ret; |
179 } | 191 } |
180 #endif | 192 #endif |
181 | 193 |
| 194 // Populates the passed in allocated strings and their sizes with the GUID, |
| 195 // crash url and distro of the crashing process. |
| 196 // The passed strings are expected to be at least kGuidSize, kMaxActiveURLSize |
| 197 // and kDistroSize bytes long respectively. |
| 198 void PopulateGUIDAndURLAndDistro(char* guid, size_t* guid_len_param, |
| 199 char* crash_url, size_t* crash_url_len_param, |
| 200 char* distro, size_t* distro_len_param) { |
| 201 size_t guid_len = std::min(my_strlen(child_process_logging::g_client_id), |
| 202 kGuidSize); |
| 203 size_t crash_url_len = |
| 204 std::min(my_strlen(child_process_logging::g_active_url), |
| 205 kMaxActiveURLSize); |
| 206 size_t distro_len = std::min(my_strlen(base::g_linux_distro), kDistroSize); |
| 207 memcpy(guid, child_process_logging::g_client_id, guid_len); |
| 208 memcpy(crash_url, child_process_logging::g_active_url, crash_url_len); |
| 209 memcpy(distro, base::g_linux_distro, distro_len); |
| 210 if (guid_len_param) |
| 211 *guid_len_param = guid_len; |
| 212 if (crash_url_len_param) |
| 213 *crash_url_len_param = crash_url_len; |
| 214 if (distro_len_param) |
| 215 *distro_len_param = distro_len; |
| 216 } |
| 217 |
182 // MIME substrings. | 218 // MIME substrings. |
183 const char g_rn[] = "\r\n"; | 219 const char g_rn[] = "\r\n"; |
184 const char g_form_data_msg[] = "Content-Disposition: form-data; name=\""; | 220 const char g_form_data_msg[] = "Content-Disposition: form-data; name=\""; |
185 const char g_quote_msg[] = "\""; | 221 const char g_quote_msg[] = "\""; |
186 const char g_dashdash_msg[] = "--"; | 222 const char g_dashdash_msg[] = "--"; |
187 const char g_dump_msg[] = "upload_file_minidump\"; filename=\"dump\""; | 223 const char g_dump_msg[] = "upload_file_minidump\"; filename=\"dump\""; |
188 #if defined(ADDRESS_SANITIZER) | 224 #if defined(ADDRESS_SANITIZER) |
189 const char g_log_msg[] = "upload_file_log\"; filename=\"log\""; | 225 const char g_log_msg[] = "upload_file_log\"; filename=\"log\""; |
190 #endif | 226 #endif |
191 const char g_content_type_msg[] = "Content-Type: application/octet-stream"; | 227 const char g_content_type_msg[] = "Content-Type: application/octet-stream"; |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
407 bool succeeded) { | 443 bool succeeded) { |
408 return FinalizeCrashDoneAndroid(); | 444 return FinalizeCrashDoneAndroid(); |
409 } | 445 } |
410 #endif | 446 #endif |
411 | 447 |
412 bool CrashDone(const MinidumpDescriptor& minidump, | 448 bool CrashDone(const MinidumpDescriptor& minidump, |
413 const bool upload, | 449 const bool upload, |
414 const bool succeeded) { | 450 const bool succeeded) { |
415 // WARNING: this code runs in a compromised context. It may not call into | 451 // WARNING: this code runs in a compromised context. It may not call into |
416 // libc nor allocate memory normally. | 452 // libc nor allocate memory normally. |
417 if (!succeeded) | 453 if (!succeeded) { |
| 454 const char msg[] = "Failed to generate minidump."; |
| 455 WriteLog(msg, sizeof(msg) - 1); |
418 return false; | 456 return false; |
| 457 } |
419 | 458 |
420 DCHECK(!minidump.IsFD()); | 459 DCHECK(!minidump.IsFD()); |
421 | 460 |
422 BreakpadInfo info; | 461 BreakpadInfo info = {0}; |
423 info.filename = minidump.path(); | 462 info.filename = minidump.path(); |
| 463 info.fd = minidump.fd(); |
424 #if defined(ADDRESS_SANITIZER) | 464 #if defined(ADDRESS_SANITIZER) |
425 google_breakpad::PageAllocator allocator; | 465 google_breakpad::PageAllocator allocator; |
426 const size_t log_path_len = my_strlen(minidump.path()); | 466 const size_t log_path_len = my_strlen(minidump.path()); |
427 char* log_path = reinterpret_cast<char*>(allocator.Alloc(log_path_len + 1)); | 467 char* log_path = reinterpret_cast<char*>(allocator.Alloc(log_path_len + 1)); |
428 my_memcpy(log_path, minidump.path(), log_path_len); | 468 my_memcpy(log_path, minidump.path(), log_path_len); |
429 my_memcpy(log_path + log_path_len - 4, ".log", 4); | 469 my_memcpy(log_path + log_path_len - 4, ".log", 4); |
430 log_path[log_path_len] = '\0'; | 470 log_path[log_path_len] = '\0'; |
431 info.log_filename = log_path; | 471 info.log_filename = log_path; |
432 #endif | 472 #endif |
433 info.process_type = "browser"; | 473 info.process_type = "browser"; |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
513 g_breakpad = new ExceptionHandler( | 553 g_breakpad = new ExceptionHandler( |
514 MinidumpDescriptor(dumps_path.value()), | 554 MinidumpDescriptor(dumps_path.value()), |
515 NULL, | 555 NULL, |
516 CrashDoneUpload, | 556 CrashDoneUpload, |
517 NULL, | 557 NULL, |
518 true, // Install handlers. | 558 true, // Install handlers. |
519 -1); // Server file descriptor. -1 for in-process. | 559 -1); // Server file descriptor. -1 for in-process. |
520 #endif | 560 #endif |
521 } | 561 } |
522 | 562 |
| 563 #if defined(OS_ANDROID) |
| 564 bool CrashDoneInProcessNoUpload( |
| 565 const google_breakpad::MinidumpDescriptor& descriptor, |
| 566 void* context, |
| 567 const bool succeeded) { |
| 568 // WARNING: this code runs in a compromised context. It may not call into |
| 569 // libc nor allocate memory normally. |
| 570 if (!succeeded) { |
| 571 static const char msg[] = "Crash dump generation failed.\n"; |
| 572 WriteLog(msg, sizeof(msg) - 1); |
| 573 return false; |
| 574 } |
| 575 |
| 576 // Start constructing the message to send to the browser. |
| 577 char guid[kGuidSize + 1] = {0}; |
| 578 char crash_url[kMaxActiveURLSize + 1] = {0}; |
| 579 char distro[kDistroSize + 1] = {0}; |
| 580 size_t guid_length = 0; |
| 581 size_t crash_url_length = 0; |
| 582 size_t distro_length = 0; |
| 583 PopulateGUIDAndURLAndDistro(guid, &guid_length, crash_url, &crash_url_length, |
| 584 distro, &distro_length); |
| 585 BreakpadInfo info = {0}; |
| 586 info.filename = NULL; |
| 587 info.fd = descriptor.fd(); |
| 588 info.process_type = g_process_type; |
| 589 info.process_type_length = my_strlen(g_process_type); |
| 590 info.crash_url = crash_url; |
| 591 info.crash_url_length = crash_url_length; |
| 592 info.guid = guid; |
| 593 info.guid_length = guid_length; |
| 594 info.distro = distro; |
| 595 info.distro_length = distro_length; |
| 596 info.upload = false; |
| 597 info.process_start_time = g_process_start_time; |
| 598 HandleCrashDump(info); |
| 599 return true; |
| 600 } |
| 601 |
| 602 void EnableNonBrowserCrashDumping(int minidump_fd) { |
| 603 // This will guarantee that the BuildInfo has been initialized and subsequent |
| 604 // calls will not require memory allocation. |
| 605 base::android::BuildInfo::GetInstance(); |
| 606 child_process_logging::SetClientId("Android"); |
| 607 |
| 608 // On Android, the current sandboxing uses process isolation, in which the |
| 609 // child process runs with a different UID. That breaks the normal crash |
| 610 // reporting where the browser process generates the minidump by inspecting |
| 611 // the child process. This is because the browser process now does not have |
| 612 // the permission to access the states of the child process (as it has a |
| 613 // different UID). |
| 614 // TODO(jcivelli): http://b/issue?id=6776356 we should use a watchdog |
| 615 // process forked from the renderer process that generates the minidump. |
| 616 if (minidump_fd == -1) { |
| 617 LOG(ERROR) << "Minidump file descriptor not found, crash reporting will " |
| 618 " not work."; |
| 619 return; |
| 620 } |
| 621 SetProcessStartTime(); |
| 622 |
| 623 g_is_crash_reporter_enabled = true; |
| 624 // Save the process type (it is leaked). |
| 625 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); |
| 626 const std::string process_type = |
| 627 parsed_command_line.GetSwitchValueASCII(switches::kProcessType); |
| 628 const size_t process_type_len = process_type.size() + 1; |
| 629 g_process_type = new char[process_type_len]; |
| 630 strncpy(g_process_type, process_type.c_str(), process_type_len); |
| 631 new google_breakpad::ExceptionHandler(MinidumpDescriptor(minidump_fd), |
| 632 NULL, CrashDoneInProcessNoUpload, NULL, true, -1); |
| 633 } |
| 634 #else |
523 // Non-Browser = Extension, Gpu, Plugins, Ppapi and Renderer | 635 // Non-Browser = Extension, Gpu, Plugins, Ppapi and Renderer |
524 bool NonBrowserCrashHandler(const void* crash_context, | 636 bool NonBrowserCrashHandler(const void* crash_context, |
525 size_t crash_context_size, | 637 size_t crash_context_size, |
526 void* context) { | 638 void* context) { |
527 const int fd = reinterpret_cast<intptr_t>(context); | 639 const int fd = reinterpret_cast<intptr_t>(context); |
528 int fds[2] = { -1, -1 }; | 640 int fds[2] = { -1, -1 }; |
529 if (sys_socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { | 641 if (sys_socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { |
530 static const char msg[] = "Failed to create socket for crash dumping.\n"; | 642 static const char msg[] = "Failed to create socket for crash dumping.\n"; |
531 WriteLog(msg, sizeof(msg)-1); | 643 WriteLog(msg, sizeof(msg) - 1); |
532 return false; | 644 return false; |
533 } | 645 } |
534 | 646 |
535 // Start constructing the message to send to the browser. | 647 // Start constructing the message to send to the browser. |
536 char guid[kGuidSize + 1] = {0}; | 648 char guid[kGuidSize + 1] = {0}; |
537 char crash_url[kMaxActiveURLSize + 1] = {0}; | 649 char crash_url[kMaxActiveURLSize + 1] = {0}; |
538 char distro[kDistroSize + 1] = {0}; | 650 char distro[kDistroSize + 1] = {0}; |
539 const size_t guid_len = | 651 PopulateGUIDAndURLAndDistro(guid, NULL, crash_url, NULL, distro, NULL); |
540 std::min(my_strlen(child_process_logging::g_client_id), kGuidSize); | |
541 const size_t crash_url_len = | |
542 std::min(my_strlen(child_process_logging::g_active_url), | |
543 kMaxActiveURLSize); | |
544 const size_t distro_len = | |
545 std::min(my_strlen(base::g_linux_distro), kDistroSize); | |
546 memcpy(guid, child_process_logging::g_client_id, guid_len); | |
547 memcpy(crash_url, child_process_logging::g_active_url, crash_url_len); | |
548 memcpy(distro, base::g_linux_distro, distro_len); | |
549 | 652 |
550 char b; // Dummy variable for sys_read below. | 653 char b; // Dummy variable for sys_read below. |
551 const char* b_addr = &b; // Get the address of |b| so we can create the | 654 const char* b_addr = &b; // Get the address of |b| so we can create the |
552 // expected /proc/[pid]/syscall content in the | 655 // expected /proc/[pid]/syscall content in the |
553 // browser to convert namespace tids. | 656 // browser to convert namespace tids. |
554 | 657 |
555 // The length of the control message: | 658 // The length of the control message: |
556 static const unsigned kControlMsgSize = sizeof(fds); | 659 static const unsigned kControlMsgSize = sizeof(fds); |
557 static const unsigned kControlMsgSpaceSize = CMSG_SPACE(kControlMsgSize); | 660 static const unsigned kControlMsgSpaceSize = CMSG_SPACE(kControlMsgSize); |
558 static const unsigned kControlMsgLenSize = CMSG_LEN(kControlMsgSize); | 661 static const unsigned kControlMsgLenSize = CMSG_LEN(kControlMsgSize); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
596 | 699 |
597 struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); | 700 struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); |
598 hdr->cmsg_level = SOL_SOCKET; | 701 hdr->cmsg_level = SOL_SOCKET; |
599 hdr->cmsg_type = SCM_RIGHTS; | 702 hdr->cmsg_type = SCM_RIGHTS; |
600 hdr->cmsg_len = kControlMsgLenSize; | 703 hdr->cmsg_len = kControlMsgLenSize; |
601 ((int*) CMSG_DATA(hdr))[0] = fds[0]; | 704 ((int*) CMSG_DATA(hdr))[0] = fds[0]; |
602 ((int*) CMSG_DATA(hdr))[1] = fds[1]; | 705 ((int*) CMSG_DATA(hdr))[1] = fds[1]; |
603 | 706 |
604 if (HANDLE_EINTR(sys_sendmsg(fd, &msg, 0)) < 0) { | 707 if (HANDLE_EINTR(sys_sendmsg(fd, &msg, 0)) < 0) { |
605 static const char errmsg[] = "Failed to tell parent about crash.\n"; | 708 static const char errmsg[] = "Failed to tell parent about crash.\n"; |
606 WriteLog(errmsg, sizeof(errmsg)-1); | 709 WriteLog(errmsg, sizeof(errmsg) - 1); |
607 IGNORE_RET(sys_close(fds[1])); | 710 IGNORE_RET(sys_close(fds[1])); |
608 return false; | 711 return false; |
609 } | 712 } |
610 IGNORE_RET(sys_close(fds[1])); | 713 IGNORE_RET(sys_close(fds[1])); |
611 | 714 |
612 if (HANDLE_EINTR(sys_read(fds[0], &b, 1)) != 1) { | 715 if (HANDLE_EINTR(sys_read(fds[0], &b, 1)) != 1) { |
613 static const char errmsg[] = "Parent failed to complete crash dump.\n"; | 716 static const char errmsg[] = "Parent failed to complete crash dump.\n"; |
614 WriteLog(errmsg, sizeof(errmsg)-1); | 717 WriteLog(errmsg, sizeof(errmsg) - 1); |
615 } | 718 } |
616 | 719 |
617 #if defined(OS_ANDROID) | |
618 // When false is returned, breakpad will continue to its minidump generator | |
619 // and then to the HandlerCallback, which, in this case, is | |
620 // CrashDoneNonBrowserAndroid(). | |
621 return false; | |
622 #else | |
623 return true; | 720 return true; |
624 #endif | |
625 } | 721 } |
626 | 722 |
627 void EnableNonBrowserCrashDumping() { | 723 void EnableNonBrowserCrashDumping() { |
628 const int fd = base::GlobalDescriptors::GetInstance()->Get(kCrashDumpSignal); | 724 const int fd = base::GlobalDescriptors::GetInstance()->Get(kCrashDumpSignal); |
629 g_is_crash_reporter_enabled = true; | 725 g_is_crash_reporter_enabled = true; |
630 // We deliberately leak this object. | 726 // We deliberately leak this object. |
631 DCHECK(!g_breakpad); | 727 DCHECK(!g_breakpad); |
632 | 728 |
633 ExceptionHandler::MinidumpCallback crash_done_callback = NULL; | |
634 #if defined(OS_ANDROID) | |
635 crash_done_callback = CrashDoneNonBrowserAndroid; | |
636 #endif | |
637 | |
638 g_breakpad = new ExceptionHandler( | 729 g_breakpad = new ExceptionHandler( |
639 MinidumpDescriptor("/tmp"), // Unused but needed or Breakpad will assert. | 730 MinidumpDescriptor("/tmp"), // Unused but needed or Breakpad will assert. |
640 NULL, | 731 NULL, |
641 crash_done_callback, | 732 NULL, |
642 reinterpret_cast<void*>(fd), // Param passed to the crash handler. | 733 reinterpret_cast<void*>(fd), // Param passed to the crash handler. |
643 true, | 734 true, |
644 -1); | 735 -1); |
645 g_breakpad->set_crash_handler(NonBrowserCrashHandler); | 736 g_breakpad->set_crash_handler(NonBrowserCrashHandler); |
646 } | 737 } |
| 738 #endif // defined(OS_ANDROID) |
647 | 739 |
648 } // namespace | 740 } // namespace |
649 | 741 |
| 742 void LoadDataFromFD(google_breakpad::PageAllocator& allocator, |
| 743 int fd, bool close_fd, uint8_t** file_data, size_t* size) { |
| 744 STAT_STRUCT st; |
| 745 if (FSTAT_FUNC(fd, &st) != 0) { |
| 746 static const char msg[] = "Cannot upload crash dump: stat failed\n"; |
| 747 WriteLog(msg, sizeof(msg) - 1); |
| 748 if (close_fd) |
| 749 IGNORE_RET(sys_close(fd)); |
| 750 return; |
| 751 } |
| 752 |
| 753 *file_data = reinterpret_cast<uint8_t*>(allocator.Alloc(st.st_size)); |
| 754 if (!(*file_data)) { |
| 755 static const char msg[] = "Cannot upload crash dump: cannot alloc\n"; |
| 756 WriteLog(msg, sizeof(msg) - 1); |
| 757 if (close_fd) |
| 758 IGNORE_RET(sys_close(fd)); |
| 759 return; |
| 760 } |
| 761 my_memset(*file_data, 0xf, st.st_size); |
| 762 |
| 763 *size = st.st_size; |
| 764 int byte_read = sys_read(fd, *file_data, *size); |
| 765 if (byte_read == -1) { |
| 766 static const char msg[] = "Cannot upload crash dump: read failed\n"; |
| 767 WriteLog(msg, sizeof(msg) - 1); |
| 768 if (close_fd) |
| 769 IGNORE_RET(sys_close(fd)); |
| 770 return; |
| 771 } |
| 772 |
| 773 if (close_fd) |
| 774 IGNORE_RET(sys_close(fd)); |
| 775 } |
| 776 |
650 void LoadDataFromFile(google_breakpad::PageAllocator& allocator, | 777 void LoadDataFromFile(google_breakpad::PageAllocator& allocator, |
651 const BreakpadInfo& info, const char* filename, | 778 const char* filename, |
652 int* fd, uint8_t** file_data, size_t* size) { | 779 int* fd, uint8_t** file_data, size_t* size) { |
653 // WARNING: this code runs in a compromised context. It may not call into | 780 // WARNING: this code runs in a compromised context. It may not call into |
654 // libc nor allocate memory normally. | 781 // libc nor allocate memory normally. |
655 *fd = sys_open(filename, O_RDONLY, 0); | 782 *fd = sys_open(filename, O_RDONLY, 0); |
656 *size = 0; | 783 *size = 0; |
657 | 784 |
658 if (*fd < 0) { | 785 if (*fd < 0) { |
659 static const char msg[] = "Cannot upload crash dump: failed to open\n"; | 786 static const char msg[] = "Cannot upload crash dump: failed to open\n"; |
660 WriteLog(msg, sizeof(msg)); | 787 WriteLog(msg, sizeof(msg) - 1); |
661 return; | |
662 } | |
663 STAT_STRUCT st; | |
664 if (FSTAT_FUNC(*fd, &st) != 0) { | |
665 static const char msg[] = "Cannot upload crash dump: stat failed\n"; | |
666 WriteLog(msg, sizeof(msg)); | |
667 IGNORE_RET(sys_close(*fd)); | |
668 return; | 788 return; |
669 } | 789 } |
670 | 790 |
671 *file_data = reinterpret_cast<uint8_t*>(allocator.Alloc(st.st_size)); | 791 LoadDataFromFD(allocator, *fd, true, file_data, size); |
672 if (!(*file_data)) { | |
673 static const char msg[] = "Cannot upload crash dump: cannot alloc\n"; | |
674 WriteLog(msg, sizeof(msg)); | |
675 IGNORE_RET(sys_close(*fd)); | |
676 return; | |
677 } | |
678 my_memset(*file_data, 0xf, st.st_size); | |
679 | |
680 *size = st.st_size; | |
681 sys_read(*fd, *file_data, *size); | |
682 IGNORE_RET(sys_close(*fd)); | |
683 } | 792 } |
684 | 793 |
685 void HandleCrashDump(const BreakpadInfo& info) { | 794 void HandleCrashDump(const BreakpadInfo& info) { |
686 int dumpfd; | 795 int dumpfd; |
| 796 bool keep_fd = false; |
687 size_t dump_size; | 797 size_t dump_size; |
688 uint8_t* dump_data; | 798 uint8_t* dump_data; |
689 google_breakpad::PageAllocator allocator; | 799 google_breakpad::PageAllocator allocator; |
690 LoadDataFromFile(allocator, info, info.filename, | 800 |
691 &dumpfd, &dump_data, &dump_size); | 801 if (info.fd != -1) { |
| 802 // Dump is provided with an open FD. |
| 803 keep_fd = true; |
| 804 dumpfd = info.fd; |
| 805 |
| 806 // The FD is pointing to the end of the file. |
| 807 // Rewind, we'll read the data next. |
| 808 if (lseek(dumpfd, 0, SEEK_SET) == -1) { |
| 809 static const char msg[] = "Cannot upload crash dump: failed to " |
| 810 "reposition minidump FD\n"; |
| 811 WriteLog(msg, sizeof(msg) - 1); |
| 812 IGNORE_RET(sys_close(dumpfd)); |
| 813 return; |
| 814 } |
| 815 LoadDataFromFD(allocator, info.fd, false, &dump_data, &dump_size); |
| 816 } else { |
| 817 // Dump is provided with a path. |
| 818 keep_fd = false; |
| 819 LoadDataFromFile(allocator, info.filename, &dumpfd, &dump_data, &dump_size); |
| 820 } |
| 821 |
| 822 // TODO(jcivelli): make log work when using FDs. |
692 #if defined(ADDRESS_SANITIZER) | 823 #if defined(ADDRESS_SANITIZER) |
693 int logfd; | 824 int logfd; |
694 size_t log_size; | 825 size_t log_size; |
695 uint8_t* log_data; | 826 uint8_t* log_data; |
696 // Load the AddressSanitizer log into log_data. | 827 // Load the AddressSanitizer log into log_data. |
697 LoadDataFromFile(allocator, info, info.log_filename, | 828 LoadDataFromFile(allocator, info, info.log_filename, |
698 &logfd, &log_data, &log_size); | 829 &logfd, &log_data, &log_size); |
699 #endif | 830 #endif |
700 | 831 |
701 // We need to build a MIME block for uploading to the server. Since we are | 832 // We need to build a MIME block for uploading to the server. Since we are |
702 // going to fork and run wget, it needs to be written to a temp file. | 833 // going to fork and run wget, it needs to be written to a temp file. |
703 const int ufd = sys_open("/dev/urandom", O_RDONLY, 0); | 834 const int ufd = sys_open("/dev/urandom", O_RDONLY, 0); |
704 if (ufd < 0) { | 835 if (ufd < 0) { |
705 static const char msg[] = "Cannot upload crash dump because /dev/urandom" | 836 static const char msg[] = "Cannot upload crash dump because /dev/urandom" |
706 " is missing\n"; | 837 " is missing\n"; |
707 WriteLog(msg, sizeof(msg) - 1); | 838 WriteLog(msg, sizeof(msg) - 1); |
708 return; | 839 return; |
709 } | 840 } |
710 | 841 |
711 static const char temp_file_template[] = | 842 static const char temp_file_template[] = |
712 "/tmp/chromium-upload-XXXXXXXXXXXXXXXX"; | 843 "/tmp/chromium-upload-XXXXXXXXXXXXXXXX"; |
713 char temp_file[sizeof(temp_file_template)]; | 844 char temp_file[sizeof(temp_file_template)]; |
714 int temp_file_fd = -1; | 845 int temp_file_fd = -1; |
715 if (info.upload) { | 846 if (keep_fd) { |
716 memcpy(temp_file, temp_file_template, sizeof(temp_file_template)); | 847 temp_file_fd = dumpfd; |
717 | 848 // Rewind the destination, we are going to overwrite it. |
718 for (unsigned i = 0; i < 10; ++i) { | 849 if (lseek(dumpfd, 0, SEEK_SET) == -1) { |
719 uint64_t t; | 850 static const char msg[] = "Cannot upload crash dump: failed to " |
720 sys_read(ufd, &t, sizeof(t)); | 851 "reposition minidump FD (2)\n"; |
721 write_uint64_hex(temp_file + sizeof(temp_file) - (16 + 1), t); | |
722 | |
723 temp_file_fd = sys_open(temp_file, O_WRONLY | O_CREAT | O_EXCL, 0600); | |
724 if (temp_file_fd >= 0) | |
725 break; | |
726 } | |
727 | |
728 if (temp_file_fd < 0) { | |
729 static const char msg[] = "Failed to create temporary file in /tmp: " | |
730 "cannot upload crash dump\n"; | |
731 WriteLog(msg, sizeof(msg) - 1); | 852 WriteLog(msg, sizeof(msg) - 1); |
732 IGNORE_RET(sys_close(ufd)); | 853 IGNORE_RET(sys_close(dumpfd)); |
733 return; | 854 return; |
734 } | 855 } |
735 } else { | 856 } else { |
736 temp_file_fd = sys_open(info.filename, O_WRONLY, 0600); | 857 if (info.upload) { |
737 if (temp_file_fd < 0) { | 858 memcpy(temp_file, temp_file_template, sizeof(temp_file_template)); |
738 static const char msg[] = "Failed to save crash dump: failed to open\n"; | 859 |
739 WriteLog(msg, sizeof(msg) - 1); | 860 for (unsigned i = 0; i < 10; ++i) { |
740 IGNORE_RET(sys_close(ufd)); | 861 uint64_t t; |
741 return; | 862 sys_read(ufd, &t, sizeof(t)); |
| 863 write_uint64_hex(temp_file + sizeof(temp_file) - (16 + 1), t); |
| 864 |
| 865 temp_file_fd = sys_open(temp_file, O_WRONLY | O_CREAT | O_EXCL, 0600); |
| 866 if (temp_file_fd >= 0) |
| 867 break; |
| 868 } |
| 869 |
| 870 if (temp_file_fd < 0) { |
| 871 static const char msg[] = "Failed to create temporary file in /tmp: " |
| 872 "cannot upload crash dump\n"; |
| 873 WriteLog(msg, sizeof(msg) - 1); |
| 874 IGNORE_RET(sys_close(ufd)); |
| 875 return; |
| 876 } |
| 877 } else { |
| 878 temp_file_fd = sys_open(info.filename, O_WRONLY, 0600); |
| 879 if (temp_file_fd < 0) { |
| 880 static const char msg[] = "Failed to save crash dump: failed to open\n"; |
| 881 WriteLog(msg, sizeof(msg) - 1); |
| 882 IGNORE_RET(sys_close(ufd)); |
| 883 return; |
| 884 } |
742 } | 885 } |
743 } | 886 } |
744 | 887 |
745 // The MIME boundary is 28 hyphens, followed by a 64-bit nonce and a NUL. | 888 // The MIME boundary is 28 hyphens, followed by a 64-bit nonce and a NUL. |
746 char mime_boundary[28 + 16 + 1]; | 889 char mime_boundary[28 + 16 + 1]; |
747 my_memset(mime_boundary, '-', 28); | 890 my_memset(mime_boundary, '-', 28); |
748 uint64_t boundary_rand; | 891 uint64_t boundary_rand; |
749 sys_read(ufd, &boundary_rand, sizeof(boundary_rand)); | 892 sys_read(ufd, &boundary_rand, sizeof(boundary_rand)); |
750 write_uint64_hex(mime_boundary + 28, boundary_rand); | 893 write_uint64_hex(mime_boundary + 28, boundary_rand); |
751 mime_boundary[28 + 16] = 0; | 894 mime_boundary[28 + 16] = 0; |
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1061 // Append a multipart boundary and the contents of the AddressSanitizer log. | 1204 // Append a multipart boundary and the contents of the AddressSanitizer log. |
1062 writer.AddBoundary(); | 1205 writer.AddBoundary(); |
1063 writer.AddFileContents(g_log_msg, log_data, log_size); | 1206 writer.AddFileContents(g_log_msg, log_data, log_size); |
1064 #endif | 1207 #endif |
1065 writer.AddEnd(); | 1208 writer.AddEnd(); |
1066 writer.Flush(); | 1209 writer.Flush(); |
1067 | 1210 |
1068 IGNORE_RET(sys_close(temp_file_fd)); | 1211 IGNORE_RET(sys_close(temp_file_fd)); |
1069 | 1212 |
1070 #if defined(OS_ANDROID) | 1213 #if defined(OS_ANDROID) |
1071 __android_log_write(ANDROID_LOG_WARN, | 1214 if (info.filename) { |
1072 kGoogleBreakpad, | 1215 int filename_length = my_strlen(info.filename); |
1073 "Output crash dump file:"); | |
1074 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, info.filename); | |
1075 | 1216 |
1076 char pid_buf[kUint64StringSize]; | 1217 // If this was a file, we need to copy it to the right place and use the |
1077 uint64_t pid_str_len = my_uint64_len(info.pid); | 1218 // right file name so it gets uploaded by the browser. |
1078 my_uint64tos(pid_buf, info.pid, pid_str_len); | 1219 const char msg[] = "Output crash dump file:"; |
| 1220 WriteLog(msg, sizeof(msg) - 1); |
| 1221 WriteLog(info.filename, filename_length - 1); |
1079 | 1222 |
1080 // -1 because we won't need the null terminator on the original filename. | 1223 char pid_buf[kUint64StringSize]; |
1081 size_t done_filename_len = my_strlen(info.filename) + pid_str_len - 1; | 1224 uint64_t pid_str_length = my_uint64_len(info.pid); |
1082 char* done_filename = reinterpret_cast<char*>( | 1225 my_uint64tos(pid_buf, info.pid, pid_str_length); |
1083 allocator.Alloc(done_filename_len)); | 1226 |
1084 // Rename the file such that the pid is the suffix in order to signal other | 1227 // -1 because we won't need the null terminator on the original filename. |
1085 // processes that the minidump is complete. The advantage of using the pid as | 1228 unsigned done_filename_len = filename_length - 1 + pid_str_length; |
1086 // the suffix is that it is trivial to associate the minidump with the | 1229 char* done_filename = reinterpret_cast<char*>( |
1087 // crashed process. | 1230 allocator.Alloc(done_filename_len)); |
1088 // Finally, note strncpy prevents null terminators from | 1231 // Rename the file such that the pid is the suffix in order signal to other |
1089 // being copied. Pad the rest with 0's. | 1232 // processes that the minidump is complete. The advantage of using the pid |
1090 my_strncpy(done_filename, info.filename, done_filename_len); | 1233 // as the suffix is that it is trivial to associate the minidump with the |
1091 // Append the suffix a null terminator should be added. | 1234 // crashed process. |
1092 my_strncat(done_filename, pid_buf, pid_str_len); | 1235 // Finally, note strncpy prevents null terminators from |
1093 // Rename the minidump file to signal that it is complete. | 1236 // being copied. Pad the rest with 0's. |
1094 if (rename(info.filename, done_filename)) { | 1237 my_strncpy(done_filename, info.filename, done_filename_len); |
1095 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, "Failed to rename:"); | 1238 // Append the suffix a null terminator should be added. |
1096 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, info.filename); | 1239 my_strncat(done_filename, pid_buf, pid_str_length); |
1097 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, "to"); | 1240 // Rename the minidump file to signal that it is complete. |
1098 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, done_filename); | 1241 if (rename(info.filename, done_filename)) { |
| 1242 const char failed_msg[] = "Failed to rename:"; |
| 1243 WriteLog(failed_msg, sizeof(failed_msg) - 1); |
| 1244 WriteLog(info.filename, filename_length - 1); |
| 1245 const char to_msg[] = "to"; |
| 1246 WriteLog(to_msg, sizeof(to_msg) - 1); |
| 1247 WriteLog(done_filename, done_filename_len - 1); |
| 1248 } |
1099 } | 1249 } |
1100 #endif | 1250 #endif |
1101 | 1251 |
1102 if (!info.upload) | 1252 if (!info.upload) |
1103 return; | 1253 return; |
1104 | 1254 |
1105 // The --header argument to wget looks like: | 1255 // The --header argument to wget looks like: |
1106 // --header=Content-Type: multipart/form-data; boundary=XYZ | 1256 // --header=Content-Type: multipart/form-data; boundary=XYZ |
1107 // where the boundary has two fewer leading '-' chars | 1257 // where the boundary has two fewer leading '-' chars |
1108 static const char header_msg[] = | 1258 static const char header_msg[] = |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1269 const std::string process_type = | 1419 const std::string process_type = |
1270 parsed_command_line.GetSwitchValueASCII(switches::kProcessType); | 1420 parsed_command_line.GetSwitchValueASCII(switches::kProcessType); |
1271 if (process_type.empty()) { | 1421 if (process_type.empty()) { |
1272 EnableCrashDumping(getenv(env_vars::kHeadless) != NULL); | 1422 EnableCrashDumping(getenv(env_vars::kHeadless) != NULL); |
1273 } else if (process_type == switches::kRendererProcess || | 1423 } else if (process_type == switches::kRendererProcess || |
1274 process_type == switches::kPluginProcess || | 1424 process_type == switches::kPluginProcess || |
1275 process_type == switches::kPpapiPluginProcess || | 1425 process_type == switches::kPpapiPluginProcess || |
1276 process_type == switches::kZygoteProcess || | 1426 process_type == switches::kZygoteProcess || |
1277 process_type == switches::kGpuProcess) { | 1427 process_type == switches::kGpuProcess) { |
1278 #if defined(OS_ANDROID) | 1428 #if defined(OS_ANDROID) |
1279 child_process_logging::SetClientId("Android"); | 1429 NOTREACHED() << "Breakpad initialized with InitCrashReporter() instead of " |
1280 #endif | 1430 "InitNonBrowserCrashReporter in " << process_type << " process."; |
| 1431 return; |
| 1432 #else |
1281 // We might be chrooted in a zygote or renderer process so we cannot call | 1433 // We might be chrooted in a zygote or renderer process so we cannot call |
1282 // GetCollectStatsConsent because that needs access the the user's home | 1434 // GetCollectStatsConsent because that needs access the the user's home |
1283 // dir. Instead, we set a command line flag for these processes. | 1435 // dir. Instead, we set a command line flag for these processes. |
1284 // Even though plugins are not chrooted, we share the same code path for | 1436 // Even though plugins are not chrooted, we share the same code path for |
1285 // simplicity. | 1437 // simplicity. |
1286 if (!parsed_command_line.HasSwitch(switches::kEnableCrashReporter)) | 1438 if (!parsed_command_line.HasSwitch(switches::kEnableCrashReporter)) |
1287 return; | 1439 return; |
1288 // Get the guid and linux distro from the command line switch. | 1440 // Get the guid and linux distro from the command line switch. |
1289 std::string switch_value = | 1441 std::string switch_value = |
1290 parsed_command_line.GetSwitchValueASCII(switches::kEnableCrashReporter); | 1442 parsed_command_line.GetSwitchValueASCII(switches::kEnableCrashReporter); |
1291 size_t separator = switch_value.find(","); | 1443 size_t separator = switch_value.find(","); |
1292 if (separator != std::string::npos) { | 1444 if (separator != std::string::npos) { |
1293 child_process_logging::SetClientId(switch_value.substr(0, separator)); | 1445 child_process_logging::SetClientId(switch_value.substr(0, separator)); |
1294 base::SetLinuxDistro(switch_value.substr(separator + 1)); | 1446 base::SetLinuxDistro(switch_value.substr(separator + 1)); |
1295 } else { | 1447 } else { |
1296 child_process_logging::SetClientId(switch_value); | 1448 child_process_logging::SetClientId(switch_value); |
1297 } | 1449 } |
1298 EnableNonBrowserCrashDumping(); | 1450 EnableNonBrowserCrashDumping(); |
| 1451 VLOG(1) << "Non Browser crash dumping enabled for: " << process_type; |
| 1452 #endif // #if defined(OS_ANDROID) |
1299 } | 1453 } |
1300 | 1454 |
1301 // Set the base process start time value. | 1455 SetProcessStartTime(); |
1302 struct timeval tv; | |
1303 if (!gettimeofday(&tv, NULL)) | |
1304 g_process_start_time = timeval_to_ms(&tv); | |
1305 else | |
1306 g_process_start_time = 0; | |
1307 | 1456 |
1308 logging::SetDumpWithoutCrashingFunction(&DumpProcess); | 1457 logging::SetDumpWithoutCrashingFunction(&DumpProcess); |
1309 #if defined(ADDRESS_SANITIZER) | 1458 #if defined(ADDRESS_SANITIZER) |
1310 // Register the callback for AddressSanitizer error reporting. | 1459 // Register the callback for AddressSanitizer error reporting. |
1311 __asan_set_error_report_callback(AsanLinuxBreakpadCallback); | 1460 __asan_set_error_report_callback(AsanLinuxBreakpadCallback); |
1312 #endif | 1461 #endif |
1313 } | 1462 } |
1314 | 1463 |
| 1464 #if defined(OS_ANDROID) |
| 1465 void InitNonBrowserCrashReporterForAndroid(int minidump_fd) { |
| 1466 const CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 1467 if (command_line->HasSwitch(switches::kEnableCrashReporter)) |
| 1468 EnableNonBrowserCrashDumping(minidump_fd); |
| 1469 } |
| 1470 #endif // OS_ANDROID |
| 1471 |
1315 bool IsCrashReporterEnabled() { | 1472 bool IsCrashReporterEnabled() { |
1316 return g_is_crash_reporter_enabled; | 1473 return g_is_crash_reporter_enabled; |
1317 } | 1474 } |
OLD | NEW |