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

Side by Side Diff: chrome/app/breakpad_linux.cc

Issue 11189068: Changing minidump process generation to be in-process on Android. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed comments. Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698