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

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, 1 month 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
« no previous file with comments | « chrome/app/breakpad_linux.h ('k') | chrome/app/chrome_main_delegate.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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() {
Lei Zhang 2012/10/24 05:20:47 nit: doesn't need to be static inside of an anonym
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 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
Lei Zhang 2012/10/24 05:20:47 nit: #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
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;
Lei Zhang 2012/10/24 05:20:47 nit: -1 -> - 1
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
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 }
OLDNEW
« no previous file with comments | « chrome/app/breakpad_linux.h ('k') | chrome/app/chrome_main_delegate.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698