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 static 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 25 matching lines...) Expand all Loading... | |
459 | 499 |
460 #if !defined(OS_ANDROID) | 500 #if !defined(OS_ANDROID) |
461 // Wrapper function, do not add more code here. | 501 // Wrapper function, do not add more code here. |
462 bool CrashDoneUpload(const MinidumpDescriptor& minidump, | 502 bool CrashDoneUpload(const MinidumpDescriptor& minidump, |
463 void* context, | 503 void* context, |
464 bool succeeded) { | 504 bool succeeded) { |
465 return CrashDone(minidump, true, succeeded); | 505 return CrashDone(minidump, true, succeeded); |
466 } | 506 } |
467 #endif | 507 #endif |
468 | 508 |
509 #if defined(OS_ANDROID) | |
510 bool CrashDoneInProcessNoUpload( | |
511 const google_breakpad::MinidumpDescriptor& descriptor, | |
512 void* context, | |
513 const bool succeeded) { | |
514 // WARNING: this code runs in a compromised context. It may not call into | |
515 // libc nor allocate memory normally. | |
516 if (!succeeded) { | |
517 static const char msg[] = "Crash dump generation failed.\n"; | |
518 WriteLog(msg, sizeof(msg)); | |
519 return false; | |
520 } | |
521 | |
522 // Start constructing the message to send to the browser. | |
523 char guid[kGuidSize + 1] = {0}; | |
524 char crash_url[kMaxActiveURLSize + 1] = {0}; | |
525 char distro[kDistroSize + 1] = {0}; | |
526 size_t guid_length = 0; | |
527 size_t crash_url_length = 0; | |
528 size_t distro_length = 0; | |
529 PopulateGUIDAndURLAndDistro(guid, &guid_length, crash_url, &crash_url_length, | |
530 distro, &distro_length); | |
531 BreakpadInfo info = {0}; | |
532 info.filename = NULL; | |
533 info.fd = descriptor.fd(); | |
534 info.process_type = g_process_type; | |
535 info.process_type_length = my_strlen(g_process_type); | |
536 info.crash_url = crash_url; | |
537 info.crash_url_length = crash_url_length; | |
538 info.guid = guid; | |
539 info.guid_length = guid_length; | |
540 info.distro = distro; | |
541 info.distro_length = distro_length; | |
542 info.upload = false; | |
543 info.process_start_time = g_process_start_time; | |
544 HandleCrashDump(info); | |
545 return true; | |
546 } | |
547 #endif | |
548 | |
469 #if defined(ADDRESS_SANITIZER) | 549 #if defined(ADDRESS_SANITIZER) |
470 extern "C" | 550 extern "C" |
471 void __asan_set_error_report_callback(void (*cb)(const char*)); | 551 void __asan_set_error_report_callback(void (*cb)(const char*)); |
472 | 552 |
473 extern "C" | 553 extern "C" |
474 void AsanLinuxBreakpadCallback(const char* report) { | 554 void AsanLinuxBreakpadCallback(const char* report) { |
475 g_asan_report_str = report; | 555 g_asan_report_str = report; |
476 // Send minidump here. | 556 // Send minidump here. |
477 g_breakpad->SimulateSignalDelivery(SIGKILL); | 557 g_breakpad->SimulateSignalDelivery(SIGKILL); |
478 } | 558 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
513 g_breakpad = new ExceptionHandler( | 593 g_breakpad = new ExceptionHandler( |
514 MinidumpDescriptor(dumps_path.value()), | 594 MinidumpDescriptor(dumps_path.value()), |
515 NULL, | 595 NULL, |
516 CrashDoneUpload, | 596 CrashDoneUpload, |
517 NULL, | 597 NULL, |
518 true, // Install handlers. | 598 true, // Install handlers. |
519 -1); // Server file descriptor. -1 for in-process. | 599 -1); // Server file descriptor. -1 for in-process. |
520 #endif | 600 #endif |
521 } | 601 } |
522 | 602 |
603 #if !defined(OS_ANDROID) | |
523 // Non-Browser = Extension, Gpu, Plugins, Ppapi and Renderer | 604 // Non-Browser = Extension, Gpu, Plugins, Ppapi and Renderer |
524 bool NonBrowserCrashHandler(const void* crash_context, | 605 bool NonBrowserCrashHandler(const void* crash_context, |
525 size_t crash_context_size, | 606 size_t crash_context_size, |
526 void* context) { | 607 void* context) { |
527 const int fd = reinterpret_cast<intptr_t>(context); | 608 const int fd = reinterpret_cast<intptr_t>(context); |
528 int fds[2] = { -1, -1 }; | 609 int fds[2] = { -1, -1 }; |
529 if (sys_socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { | 610 if (sys_socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { |
530 static const char msg[] = "Failed to create socket for crash dumping.\n"; | 611 static const char msg[] = "Failed to create socket for crash dumping.\n"; |
531 WriteLog(msg, sizeof(msg)-1); | 612 WriteLog(msg, sizeof(msg)-1); |
532 return false; | 613 return false; |
533 } | 614 } |
534 | 615 |
535 // Start constructing the message to send to the browser. | 616 // Start constructing the message to send to the browser. |
536 char guid[kGuidSize + 1] = {0}; | 617 char guid[kGuidSize + 1] = {0}; |
537 char crash_url[kMaxActiveURLSize + 1] = {0}; | 618 char crash_url[kMaxActiveURLSize + 1] = {0}; |
538 char distro[kDistroSize + 1] = {0}; | 619 char distro[kDistroSize + 1] = {0}; |
539 const size_t guid_len = | 620 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 | 621 |
550 char b; // Dummy variable for sys_read below. | 622 char b; // Dummy variable for sys_read below. |
551 const char* b_addr = &b; // Get the address of |b| so we can create the | 623 const char* b_addr = &b; // Get the address of |b| so we can create the |
552 // expected /proc/[pid]/syscall content in the | 624 // expected /proc/[pid]/syscall content in the |
553 // browser to convert namespace tids. | 625 // browser to convert namespace tids. |
554 | 626 |
555 // The length of the control message: | 627 // The length of the control message: |
556 static const unsigned kControlMsgSize = sizeof(fds); | 628 static const unsigned kControlMsgSize = sizeof(fds); |
557 static const unsigned kControlMsgSpaceSize = CMSG_SPACE(kControlMsgSize); | 629 static const unsigned kControlMsgSpaceSize = CMSG_SPACE(kControlMsgSize); |
558 static const unsigned kControlMsgLenSize = CMSG_LEN(kControlMsgSize); | 630 static const unsigned kControlMsgLenSize = CMSG_LEN(kControlMsgSize); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
616 | 688 |
617 #if defined(OS_ANDROID) | 689 #if defined(OS_ANDROID) |
618 // When false is returned, breakpad will continue to its minidump generator | 690 // When false is returned, breakpad will continue to its minidump generator |
619 // and then to the HandlerCallback, which, in this case, is | 691 // and then to the HandlerCallback, which, in this case, is |
620 // CrashDoneNonBrowserAndroid(). | 692 // CrashDoneNonBrowserAndroid(). |
621 return false; | 693 return false; |
622 #else | 694 #else |
623 return true; | 695 return true; |
624 #endif | 696 #endif |
625 } | 697 } |
698 #endif | |
626 | 699 |
700 #if defined(OS_ANDROID) | |
701 void EnableNonBrowserCrashDumping(int minidump_fd) { | |
702 // This will guarantee that the BuildInfo has been initialized and subsequent | |
703 // calls will not require memory allocation. | |
704 base::android::BuildInfo::GetInstance(); | |
705 child_process_logging::SetClientId("Android"); | |
706 | |
707 // On Android, the current sandboxing uses process isolation, in which the | |
708 // child process runs with a different UID. That breaks the normal crash | |
709 // reporting where the browser process generates the minidump by inspecting | |
710 // the child process. This is because the browser process now does not have | |
711 // the permission to access the states of the child process (as it has a | |
712 // different UID). | |
713 // TODO(jcivelli): http://b/issue?id=6776356 we should use a watchdog | |
714 // process forked from the renderer process that generates the minidump. | |
715 if (minidump_fd == -1) { | |
716 LOG(ERROR) << "Minidump file descriptor not found, crash reporting will " | |
717 " not work."; | |
718 return; | |
719 } | |
720 SetProcessStartTime(); | |
721 | |
722 g_is_crash_reporter_enabled = true; | |
723 // Save the process type (it is leaked). | |
724 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | |
725 const std::string process_type = | |
726 parsed_command_line.GetSwitchValueASCII(switches::kProcessType); | |
727 const size_t process_type_len = process_type.size() + 1; | |
728 g_process_type = new char[process_type_len]; | |
729 strncpy(g_process_type, process_type.c_str(), process_type_len); | |
730 new google_breakpad::ExceptionHandler(MinidumpDescriptor(minidump_fd), | |
731 NULL, CrashDoneInProcessNoUpload, NULL, true, -1); | |
732 } | |
733 #else | |
627 void EnableNonBrowserCrashDumping() { | 734 void EnableNonBrowserCrashDumping() { |
628 const int fd = base::GlobalDescriptors::GetInstance()->Get(kCrashDumpSignal); | 735 const int fd = base::GlobalDescriptors::GetInstance()->Get(kCrashDumpSignal); |
629 g_is_crash_reporter_enabled = true; | 736 g_is_crash_reporter_enabled = true; |
630 // We deliberately leak this object. | 737 // We deliberately leak this object. |
631 DCHECK(!g_breakpad); | 738 DCHECK(!g_breakpad); |
632 | 739 |
633 ExceptionHandler::MinidumpCallback crash_done_callback = NULL; | 740 ExceptionHandler::MinidumpCallback crash_done_callback = NULL; |
634 #if defined(OS_ANDROID) | 741 #if defined(OS_ANDROID) |
635 crash_done_callback = CrashDoneNonBrowserAndroid; | 742 crash_done_callback = CrashDoneNonBrowserAndroid; |
636 #endif | 743 #endif |
637 | 744 |
638 g_breakpad = new ExceptionHandler( | 745 g_breakpad = new ExceptionHandler( |
639 MinidumpDescriptor("/tmp"), // Unused but needed or Breakpad will assert. | 746 MinidumpDescriptor("/tmp"), // Unused but needed or Breakpad will assert. |
640 NULL, | 747 NULL, |
641 crash_done_callback, | 748 crash_done_callback, |
642 reinterpret_cast<void*>(fd), // Param passed to the crash handler. | 749 reinterpret_cast<void*>(fd), // Param passed to the crash handler. |
643 true, | 750 true, |
644 -1); | 751 -1); |
645 g_breakpad->set_crash_handler(NonBrowserCrashHandler); | 752 g_breakpad->set_crash_handler(NonBrowserCrashHandler); |
646 } | 753 } |
754 #endif | |
647 | 755 |
648 } // namespace | 756 } // namespace |
649 | 757 |
758 void LoadDataFromFD(google_breakpad::PageAllocator& allocator, | |
759 int fd, bool close_fd, uint8_t** file_data, size_t* size) { | |
760 STAT_STRUCT st; | |
761 if (FSTAT_FUNC(fd, &st) != 0) { | |
762 static const char msg[] = "Cannot upload crash dump: stat failed\n"; | |
763 WriteLog(msg, sizeof(msg) - 1); | |
764 if (close_fd) | |
765 IGNORE_RET(sys_close(fd)); | |
766 return; | |
767 } | |
768 | |
769 *file_data = reinterpret_cast<uint8_t*>(allocator.Alloc(st.st_size)); | |
770 if (!(*file_data)) { | |
771 static const char msg[] = "Cannot upload crash dump: cannot alloc\n"; | |
772 WriteLog(msg, sizeof(msg) - 1); | |
773 if (close_fd) | |
774 IGNORE_RET(sys_close(fd)); | |
775 return; | |
776 } | |
777 my_memset(*file_data, 0xf, st.st_size); | |
778 | |
779 *size = st.st_size; | |
780 int byte_read = sys_read(fd, *file_data, *size); | |
781 if (byte_read == -1) { | |
782 static const char msg[] = "Cannot upload crash dump: read failed\n"; | |
783 WriteLog(msg, sizeof(msg) - 1); | |
784 if (close_fd) | |
785 IGNORE_RET(sys_close(fd)); | |
786 return; | |
787 } | |
788 | |
789 if (close_fd) | |
790 IGNORE_RET(sys_close(fd)); | |
791 } | |
792 | |
650 void LoadDataFromFile(google_breakpad::PageAllocator& allocator, | 793 void LoadDataFromFile(google_breakpad::PageAllocator& allocator, |
651 const BreakpadInfo& info, const char* filename, | 794 const char* filename, |
652 int* fd, uint8_t** file_data, size_t* size) { | 795 int* fd, uint8_t** file_data, size_t* size) { |
653 // WARNING: this code runs in a compromised context. It may not call into | 796 // WARNING: this code runs in a compromised context. It may not call into |
654 // libc nor allocate memory normally. | 797 // libc nor allocate memory normally. |
655 *fd = sys_open(filename, O_RDONLY, 0); | 798 *fd = sys_open(filename, O_RDONLY, 0); |
656 *size = 0; | 799 *size = 0; |
657 | 800 |
658 if (*fd < 0) { | 801 if (*fd < 0) { |
659 static const char msg[] = "Cannot upload crash dump: failed to open\n"; | 802 static const char msg[] = "Cannot upload crash dump: failed to open\n"; |
660 WriteLog(msg, sizeof(msg)); | 803 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; | 804 return; |
669 } | 805 } |
670 | 806 |
671 *file_data = reinterpret_cast<uint8_t*>(allocator.Alloc(st.st_size)); | 807 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 } | 808 } |
684 | 809 |
685 void HandleCrashDump(const BreakpadInfo& info) { | 810 void HandleCrashDump(const BreakpadInfo& info) { |
686 int dumpfd; | 811 int dumpfd; |
812 bool keep_fd = false; | |
687 size_t dump_size; | 813 size_t dump_size; |
688 uint8_t* dump_data; | 814 uint8_t* dump_data; |
689 google_breakpad::PageAllocator allocator; | 815 google_breakpad::PageAllocator allocator; |
690 LoadDataFromFile(allocator, info, info.filename, | 816 |
691 &dumpfd, &dump_data, &dump_size); | 817 if (info.fd != -1) { |
818 // Dump is provided with an open FD. | |
819 keep_fd = true; | |
820 dumpfd = info.fd; | |
821 | |
822 // The FD is pointing to the end of the file. | |
823 // Rewind, we'll read the data next. | |
824 if (lseek(dumpfd, 0, SEEK_SET) == -1) { | |
825 static const char msg[] = "Cannot upload crash dump: failed to " | |
826 "reposition minidump FD\n"; | |
827 WriteLog(msg, sizeof(msg) - 1); | |
828 IGNORE_RET(sys_close(dumpfd)); | |
829 return; | |
830 } | |
831 LoadDataFromFD(allocator, info.fd, false, &dump_data, &dump_size); | |
832 } else { | |
833 // Dump is provided with a path. | |
834 keep_fd = false; | |
835 LoadDataFromFile(allocator, info.filename, &dumpfd, &dump_data, &dump_size); | |
836 } | |
837 | |
838 // TODO(jcivelli): make log work when using FDs. | |
692 #if defined(ADDRESS_SANITIZER) | 839 #if defined(ADDRESS_SANITIZER) |
693 int logfd; | 840 int logfd; |
694 size_t log_size; | 841 size_t log_size; |
695 uint8_t* log_data; | 842 uint8_t* log_data; |
696 // Load the AddressSanitizer log into log_data. | 843 // Load the AddressSanitizer log into log_data. |
697 LoadDataFromFile(allocator, info, info.log_filename, | 844 LoadDataFromFile(allocator, info, info.log_filename, |
698 &logfd, &log_data, &log_size); | 845 &logfd, &log_data, &log_size); |
699 #endif | 846 #endif |
700 | 847 |
701 // We need to build a MIME block for uploading to the server. Since we are | 848 // 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. | 849 // 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); | 850 const int ufd = sys_open("/dev/urandom", O_RDONLY, 0); |
704 if (ufd < 0) { | 851 if (ufd < 0) { |
705 static const char msg[] = "Cannot upload crash dump because /dev/urandom" | 852 static const char msg[] = "Cannot upload crash dump because /dev/urandom" |
706 " is missing\n"; | 853 " is missing\n"; |
707 WriteLog(msg, sizeof(msg) - 1); | 854 WriteLog(msg, sizeof(msg) - 1); |
708 return; | 855 return; |
709 } | 856 } |
710 | 857 |
711 static const char temp_file_template[] = | 858 static const char temp_file_template[] = |
712 "/tmp/chromium-upload-XXXXXXXXXXXXXXXX"; | 859 "/tmp/chromium-upload-XXXXXXXXXXXXXXXX"; |
713 char temp_file[sizeof(temp_file_template)]; | 860 char temp_file[sizeof(temp_file_template)]; |
714 int temp_file_fd = -1; | 861 int temp_file_fd = -1; |
715 if (info.upload) { | 862 if (keep_fd) { |
716 memcpy(temp_file, temp_file_template, sizeof(temp_file_template)); | 863 temp_file_fd = dumpfd; |
717 | 864 // Rewind the destination, we are going to overwrite it. |
718 for (unsigned i = 0; i < 10; ++i) { | 865 if (lseek(dumpfd, 0, SEEK_SET) == -1) { |
719 uint64_t t; | 866 static const char msg[] = "Cannot upload crash dump: failed to " |
720 sys_read(ufd, &t, sizeof(t)); | 867 "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); | 868 WriteLog(msg, sizeof(msg) - 1); |
732 IGNORE_RET(sys_close(ufd)); | 869 IGNORE_RET(sys_close(dumpfd)); |
733 return; | 870 return; |
734 } | 871 } |
735 } else { | 872 } else { |
736 temp_file_fd = sys_open(info.filename, O_WRONLY, 0600); | 873 if (info.upload) { |
737 if (temp_file_fd < 0) { | 874 memcpy(temp_file, temp_file_template, sizeof(temp_file_template)); |
738 static const char msg[] = "Failed to save crash dump: failed to open\n"; | 875 |
739 WriteLog(msg, sizeof(msg) - 1); | 876 for (unsigned i = 0; i < 10; ++i) { |
740 IGNORE_RET(sys_close(ufd)); | 877 uint64_t t; |
741 return; | 878 sys_read(ufd, &t, sizeof(t)); |
879 write_uint64_hex(temp_file + sizeof(temp_file) - (16 + 1), t); | |
880 | |
881 temp_file_fd = sys_open(temp_file, O_WRONLY | O_CREAT | O_EXCL, 0600); | |
882 if (temp_file_fd >= 0) | |
883 break; | |
884 } | |
885 | |
886 if (temp_file_fd < 0) { | |
887 static const char msg[] = "Failed to create temporary file in /tmp: " | |
888 "cannot upload crash dump\n"; | |
889 WriteLog(msg, sizeof(msg) - 1); | |
890 IGNORE_RET(sys_close(ufd)); | |
891 return; | |
892 } | |
893 } else { | |
894 temp_file_fd = sys_open(info.filename, O_WRONLY, 0600); | |
895 if (temp_file_fd < 0) { | |
896 static const char msg[] = "Failed to save crash dump: failed to open\n"; | |
897 WriteLog(msg, sizeof(msg) - 1); | |
898 IGNORE_RET(sys_close(ufd)); | |
899 return; | |
900 } | |
742 } | 901 } |
743 } | 902 } |
744 | 903 |
745 // The MIME boundary is 28 hyphens, followed by a 64-bit nonce and a NUL. | 904 // The MIME boundary is 28 hyphens, followed by a 64-bit nonce and a NUL. |
746 char mime_boundary[28 + 16 + 1]; | 905 char mime_boundary[28 + 16 + 1]; |
747 my_memset(mime_boundary, '-', 28); | 906 my_memset(mime_boundary, '-', 28); |
748 uint64_t boundary_rand; | 907 uint64_t boundary_rand; |
749 sys_read(ufd, &boundary_rand, sizeof(boundary_rand)); | 908 sys_read(ufd, &boundary_rand, sizeof(boundary_rand)); |
750 write_uint64_hex(mime_boundary + 28, boundary_rand); | 909 write_uint64_hex(mime_boundary + 28, boundary_rand); |
751 mime_boundary[28 + 16] = 0; | 910 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. | 1220 // Append a multipart boundary and the contents of the AddressSanitizer log. |
1062 writer.AddBoundary(); | 1221 writer.AddBoundary(); |
1063 writer.AddFileContents(g_log_msg, log_data, log_size); | 1222 writer.AddFileContents(g_log_msg, log_data, log_size); |
1064 #endif | 1223 #endif |
1065 writer.AddEnd(); | 1224 writer.AddEnd(); |
1066 writer.Flush(); | 1225 writer.Flush(); |
1067 | 1226 |
1068 IGNORE_RET(sys_close(temp_file_fd)); | 1227 IGNORE_RET(sys_close(temp_file_fd)); |
1069 | 1228 |
1070 #if defined(OS_ANDROID) | 1229 #if defined(OS_ANDROID) |
1071 __android_log_write(ANDROID_LOG_WARN, | 1230 if (info.filename) { |
1072 kGoogleBreakpad, | 1231 int filename_length = my_strlen(info.filename); |
1073 "Output crash dump file:"); | |
1074 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, info.filename); | |
1075 | 1232 |
1076 char pid_buf[kUint64StringSize]; | 1233 // 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); | 1234 // right file name so it gets uploaded by the browser. |
1078 my_uint64tos(pid_buf, info.pid, pid_str_len); | 1235 const char* msg = "Output crash dump file:"; |
1236 WriteLog(msg, sizeof(msg) - 1); | |
1237 WriteLog(info.filename, filename_length - 1); | |
1079 | 1238 |
1080 // -1 because we won't need the null terminator on the original filename. | 1239 char pid_buf[kUint64StringSize]; |
1081 size_t done_filename_len = my_strlen(info.filename) + pid_str_len - 1; | 1240 uint64_t pid_str_length = my_uint64_len(info.pid); |
1082 char* done_filename = reinterpret_cast<char*>( | 1241 my_uint64tos(pid_buf, info.pid, pid_str_length); |
1083 allocator.Alloc(done_filename_len)); | 1242 |
1084 // Rename the file such that the pid is the suffix in order to signal other | 1243 // -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 | 1244 unsigned done_filename_len = filename_length -1 + pid_str_length; |
1086 // the suffix is that it is trivial to associate the minidump with the | 1245 char* done_filename = reinterpret_cast<char*>( |
1087 // crashed process. | 1246 allocator.Alloc(done_filename_len)); |
1088 // Finally, note strncpy prevents null terminators from | 1247 // Rename the file such that the pid is the suffix in order signal to other |
1089 // being copied. Pad the rest with 0's. | 1248 // processes that the minidump is complete. The advantage of using the pid |
1090 my_strncpy(done_filename, info.filename, done_filename_len); | 1249 // as the suffix is that it is trivial to associate the minidump with the |
1091 // Append the suffix a null terminator should be added. | 1250 // crashed process. |
1092 my_strncat(done_filename, pid_buf, pid_str_len); | 1251 // Finally, note strncpy prevents null terminators from |
1093 // Rename the minidump file to signal that it is complete. | 1252 // being copied. Pad the rest with 0's. |
1094 if (rename(info.filename, done_filename)) { | 1253 my_strncpy(done_filename, info.filename, done_filename_len); |
1095 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, "Failed to rename:"); | 1254 // Append the suffix a null terminator should be added. |
1096 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, info.filename); | 1255 my_strncat(done_filename, pid_buf, pid_str_length); |
1097 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, "to"); | 1256 // Rename the minidump file to signal that it is complete. |
1098 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, done_filename); | 1257 if (rename(info.filename, done_filename)) { |
1258 const char* failed_msg = "Failed to rename:"; | |
Lei Zhang
2012/10/23 02:57:34
There's a few instances of this. It's wrong. sizeo
Jay Civelli
2012/10/23 20:39:55
Good point, changed the char* to char[] in all the
| |
1259 WriteLog(failed_msg, sizeof(failed_msg) - 1); | |
1260 WriteLog(info.filename, filename_length - 1); | |
1261 const char* to_msg = "to"; | |
1262 WriteLog(to_msg, sizeof(to_msg) - 1); | |
1263 WriteLog(done_filename, done_filename_len - 1); | |
1264 } | |
1099 } | 1265 } |
1100 #endif | 1266 #endif |
1101 | 1267 |
1102 if (!info.upload) | 1268 if (!info.upload) |
1103 return; | 1269 return; |
1104 | 1270 |
1105 // The --header argument to wget looks like: | 1271 // The --header argument to wget looks like: |
1106 // --header=Content-Type: multipart/form-data; boundary=XYZ | 1272 // --header=Content-Type: multipart/form-data; boundary=XYZ |
1107 // where the boundary has two fewer leading '-' chars | 1273 // where the boundary has two fewer leading '-' chars |
1108 static const char header_msg[] = | 1274 static const char header_msg[] = |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1269 const std::string process_type = | 1435 const std::string process_type = |
1270 parsed_command_line.GetSwitchValueASCII(switches::kProcessType); | 1436 parsed_command_line.GetSwitchValueASCII(switches::kProcessType); |
1271 if (process_type.empty()) { | 1437 if (process_type.empty()) { |
1272 EnableCrashDumping(getenv(env_vars::kHeadless) != NULL); | 1438 EnableCrashDumping(getenv(env_vars::kHeadless) != NULL); |
1273 } else if (process_type == switches::kRendererProcess || | 1439 } else if (process_type == switches::kRendererProcess || |
1274 process_type == switches::kPluginProcess || | 1440 process_type == switches::kPluginProcess || |
1275 process_type == switches::kPpapiPluginProcess || | 1441 process_type == switches::kPpapiPluginProcess || |
1276 process_type == switches::kZygoteProcess || | 1442 process_type == switches::kZygoteProcess || |
1277 process_type == switches::kGpuProcess) { | 1443 process_type == switches::kGpuProcess) { |
1278 #if defined(OS_ANDROID) | 1444 #if defined(OS_ANDROID) |
1279 child_process_logging::SetClientId("Android"); | 1445 NOTREACHED() << "Breakpad initialized with InitCrashReporter() instead of " |
1446 "InitNonBrowserCrashReporter in non browser process."; | |
1447 #else | |
1448 InitNonBrowserCrashReporter(); | |
1280 #endif | 1449 #endif |
1281 // We might be chrooted in a zygote or renderer process so we cannot call | 1450 LOG(INFO) << "Non Browser crash dumping enabled for: " << process_type; |
Lei Zhang
2012/10/23 02:57:34
I don't think this block should be removed for non
Jay Civelli
2012/10/23 20:39:55
Oops, it's now back.
| |
1282 // GetCollectStatsConsent because that needs access the the user's home | |
1283 // 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 | |
1285 // simplicity. | |
1286 if (!parsed_command_line.HasSwitch(switches::kEnableCrashReporter)) | |
1287 return; | |
1288 // Get the guid and linux distro from the command line switch. | |
1289 std::string switch_value = | |
1290 parsed_command_line.GetSwitchValueASCII(switches::kEnableCrashReporter); | |
1291 size_t separator = switch_value.find(","); | |
1292 if (separator != std::string::npos) { | |
1293 child_process_logging::SetClientId(switch_value.substr(0, separator)); | |
1294 base::SetLinuxDistro(switch_value.substr(separator + 1)); | |
1295 } else { | |
1296 child_process_logging::SetClientId(switch_value); | |
1297 } | |
1298 EnableNonBrowserCrashDumping(); | |
1299 } | 1451 } |
1300 | 1452 SetProcessStartTime(); |
1301 // Set the base process start time value. | |
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 | 1453 |
1308 logging::SetDumpWithoutCrashingFunction(&DumpProcess); | 1454 logging::SetDumpWithoutCrashingFunction(&DumpProcess); |
1309 #if defined(ADDRESS_SANITIZER) | 1455 #if defined(ADDRESS_SANITIZER) |
1310 // Register the callback for AddressSanitizer error reporting. | 1456 // Register the callback for AddressSanitizer error reporting. |
1311 __asan_set_error_report_callback(AsanLinuxBreakpadCallback); | 1457 __asan_set_error_report_callback(AsanLinuxBreakpadCallback); |
1312 #endif | 1458 #endif |
1313 } | 1459 } |
1314 | 1460 |
1461 #if defined(OS_ANDROID) | |
1462 void InitNonBrowserCrashReporterForAndroid(int minidump_fd) { | |
1463 // We might be chrooted in a zygote or renderer process so we cannot call | |
1464 // GetCollectStatsConsent because that needs access the the user's home | |
1465 // dir. Instead, we set a command line flag for these processes. | |
1466 // Even though plugins are not chrooted, we share the same code path for | |
1467 // simplicity. | |
1468 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | |
1469 if (!parsed_command_line.HasSwitch(switches::kEnableCrashReporter)) | |
1470 return; | |
1471 | |
1472 // Get the guid and linux distro from the command line switch. | |
1473 std::string switch_value = | |
1474 parsed_command_line.GetSwitchValueASCII(switches::kEnableCrashReporter); | |
1475 size_t separator = switch_value.find(","); | |
1476 if (separator != std::string::npos) { | |
1477 child_process_logging::SetClientId(switch_value.substr(0, separator)); | |
1478 // The notion of a distro doesn't make sense in Android. | |
1479 base::SetLinuxDistro(switch_value.substr(separator + 1)); | |
Lei Zhang
2012/10/23 02:57:34
This seems silly. What does Android pass as the va
Jay Civelli
2012/10/23 20:39:55
You are right, this is silly, we know it's Android
| |
1480 } else { | |
1481 child_process_logging::SetClientId(switch_value); | |
1482 } | |
1483 EnableNonBrowserCrashDumping(minidump_fd); | |
1484 } | |
1485 #endif // OS_ANDROID | |
1486 | |
1315 bool IsCrashReporterEnabled() { | 1487 bool IsCrashReporterEnabled() { |
1316 return g_is_crash_reporter_enabled; | 1488 return g_is_crash_reporter_enabled; |
1317 } | 1489 } |
OLD | NEW |