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

Side by Side Diff: components/breakpad/app/breakpad_linux.cc

Issue 248653002: Linux Breakpad: Keep reading from the crash upload progress until a complete crash id has been rece… (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: O_CLOEXEC Created 6 years, 8 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 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 7
8 #include "components/breakpad/app/breakpad_linux.h" 8 #include "components/breakpad/app/breakpad_linux.h"
9 9
10 #include <fcntl.h> 10 #include <fcntl.h>
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
182 while (*dest) 182 while (*dest)
183 dest++; 183 dest++;
184 while (len--) 184 while (len--)
185 if (!(*dest++ = *src++)) 185 if (!(*dest++ = *src++))
186 return ret; 186 return ret;
187 *dest = 0; 187 *dest = 0;
188 return ret; 188 return ret;
189 } 189 }
190 #endif 190 #endif
191 191
192 #if !defined(OS_CHROMEOS)
193 bool my_isxdigit(char c) {
194 return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f');
195 }
196 #endif
197
192 size_t LengthWithoutTrailingSpaces(const char* str, size_t len) { 198 size_t LengthWithoutTrailingSpaces(const char* str, size_t len) {
193 while (len > 0 && str[len - 1] == ' ') { 199 while (len > 0 && str[len - 1] == ' ') {
194 len--; 200 len--;
195 } 201 }
196 return len; 202 return len;
197 } 203 }
198 204
199 // Populates the passed in allocated string and its size with the distro of 205 // Populates the passed in allocated string and its size with the distro of
200 // the crashing process. 206 // the crashing process.
201 // The passed string is expected to be at least kDistroSize bytes long. 207 // The passed string is expected to be at least kDistroSize bytes long.
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
290 void AddItemWithoutTrailingSpaces(const void* base, size_t size); 296 void AddItemWithoutTrailingSpaces(const void* base, size_t size);
291 297
292 struct kernel_iovec iov_[kIovCapacity]; 298 struct kernel_iovec iov_[kIovCapacity];
293 int iov_index_; 299 int iov_index_;
294 300
295 // Output file descriptor. 301 // Output file descriptor.
296 int fd_; 302 int fd_;
297 303
298 const char* const mime_boundary_; 304 const char* const mime_boundary_;
299 305
306 private:
300 DISALLOW_COPY_AND_ASSIGN(MimeWriter); 307 DISALLOW_COPY_AND_ASSIGN(MimeWriter);
301 }; 308 };
302 309
303 MimeWriter::MimeWriter(int fd, const char* const mime_boundary) 310 MimeWriter::MimeWriter(int fd, const char* const mime_boundary)
304 : iov_index_(0), 311 : iov_index_(0),
305 fd_(fd), 312 fd_(fd),
306 mime_boundary_(mime_boundary) { 313 mime_boundary_(mime_boundary) {
307 } 314 }
308 315
309 MimeWriter::~MimeWriter() { 316 MimeWriter::~MimeWriter() {
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
396 403
397 void MimeWriter::AddItemWithoutTrailingSpaces(const void* base, size_t size) { 404 void MimeWriter::AddItemWithoutTrailingSpaces(const void* base, size_t size) {
398 AddItem(base, LengthWithoutTrailingSpaces(static_cast<const char*>(base), 405 AddItem(base, LengthWithoutTrailingSpaces(static_cast<const char*>(base),
399 size)); 406 size));
400 } 407 }
401 408
402 #if defined(OS_CHROMEOS) 409 #if defined(OS_CHROMEOS)
403 // This subclass is used on Chromium OS to report crashes in a format easy for 410 // This subclass is used on Chromium OS to report crashes in a format easy for
404 // the central crash reporting facility to understand. 411 // the central crash reporting facility to understand.
405 // Format is <name>:<data length in decimal>:<data> 412 // Format is <name>:<data length in decimal>:<data>
406 class CrashReporterWriter : public MimeWriter 413 class CrashReporterWriter : public MimeWriter {
407 {
408 public: 414 public:
409 explicit CrashReporterWriter(int fd); 415 explicit CrashReporterWriter(int fd);
410 416
411 virtual void AddBoundary() OVERRIDE; 417 virtual void AddBoundary() OVERRIDE;
412 418
413 virtual void AddEnd() OVERRIDE; 419 virtual void AddEnd() OVERRIDE;
414 420
415 virtual void AddPairData(const char* msg_type, 421 virtual void AddPairData(const char* msg_type,
416 size_t msg_type_size, 422 size_t msg_type_size,
417 const char* msg_data, 423 const char* msg_data,
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
525 #endif 531 #endif
526 532
527 size_t WriteLog(const char* buf, size_t nbytes) { 533 size_t WriteLog(const char* buf, size_t nbytes) {
528 #if defined(OS_ANDROID) 534 #if defined(OS_ANDROID)
529 return __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, buf); 535 return __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, buf);
530 #else 536 #else
531 return sys_write(2, buf, nbytes); 537 return sys_write(2, buf, nbytes);
532 #endif 538 #endif
533 } 539 }
534 540
541 size_t WriteNewline() {
542 return WriteLog("\n", 1);
543 }
544
535 #if defined(OS_ANDROID) 545 #if defined(OS_ANDROID)
536 // Android's native crash handler outputs a diagnostic tombstone to the device 546 // Android's native crash handler outputs a diagnostic tombstone to the device
537 // log. By returning false from the HandlerCallbacks, breakpad will reinstall 547 // log. By returning false from the HandlerCallbacks, breakpad will reinstall
538 // the previous (i.e. native) signal handlers before returning from its own 548 // the previous (i.e. native) signal handlers before returning from its own
539 // handler. A Chrome build fingerprint is written to the log, so that the 549 // handler. A Chrome build fingerprint is written to the log, so that the
540 // specific build of Chrome and the location of the archived Chrome symbols can 550 // specific build of Chrome and the location of the archived Chrome symbols can
541 // be determined directly from it. 551 // be determined directly from it.
542 bool FinalizeCrashDoneAndroid() { 552 bool FinalizeCrashDoneAndroid() {
543 base::android::BuildInfo* android_build_info = 553 base::android::BuildInfo* android_build_info =
544 base::android::BuildInfo::GetInstance(); 554 base::android::BuildInfo::GetInstance();
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
699 info.distro_length = distro_length; 709 info.distro_length = distro_length;
700 info.upload = false; 710 info.upload = false;
701 info.process_start_time = g_process_start_time; 711 info.process_start_time = g_process_start_time;
702 info.pid = g_pid; 712 info.pid = g_pid;
703 info.crash_keys = g_crash_keys; 713 info.crash_keys = g_crash_keys;
704 HandleCrashDump(info); 714 HandleCrashDump(info);
705 bool finalize_result = FinalizeCrashDoneAndroid(); 715 bool finalize_result = FinalizeCrashDoneAndroid();
706 base::android::BuildInfo* android_build_info = 716 base::android::BuildInfo* android_build_info =
707 base::android::BuildInfo::GetInstance(); 717 base::android::BuildInfo::GetInstance();
708 if (android_build_info->sdk_int() >= 18 && 718 if (android_build_info->sdk_int() >= 18 &&
709 strcmp(android_build_info->build_type(), "eng") != 0 && 719 my_strcmp(android_build_info->build_type(), "eng") != 0 &&
710 strcmp(android_build_info->build_type(), "userdebug") != 0) { 720 my_strcmp(android_build_info->build_type(), "userdebug") != 0) {
711 // On JB MR2 and later, the system crash handler displays a dialog. For 721 // On JB MR2 and later, the system crash handler displays a dialog. For
712 // renderer crashes, this is a bad user experience and so this is disabled 722 // renderer crashes, this is a bad user experience and so this is disabled
713 // for user builds of Android. 723 // for user builds of Android.
714 // TODO(cjhopman): There should be some way to recover the crash stack from 724 // TODO(cjhopman): There should be some way to recover the crash stack from
715 // non-uploading user clients. See http://crbug.com/273706. 725 // non-uploading user clients. See http://crbug.com/273706.
716 __android_log_write(ANDROID_LOG_WARN, 726 __android_log_write(ANDROID_LOG_WARN,
717 kGoogleBreakpad, 727 kGoogleBreakpad,
718 "Tombstones are disabled on JB MR2+ user builds."); 728 "Tombstones are disabled on JB MR2+ user builds.");
719 __android_log_write(ANDROID_LOG_WARN, 729 __android_log_write(ANDROID_LOG_WARN,
720 kGoogleBreakpad, 730 kGoogleBreakpad,
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after
1013 NULL, 1023 NULL,
1014 }; 1024 };
1015 static const char msg[] = "Cannot upload crash dump: cannot exec " 1025 static const char msg[] = "Cannot upload crash dump: cannot exec "
1016 "/usr/bin/wget\n"; 1026 "/usr/bin/wget\n";
1017 #endif 1027 #endif
1018 execve(args[0], const_cast<char**>(args), environ); 1028 execve(args[0], const_cast<char**>(args), environ);
1019 WriteLog(msg, sizeof(msg) - 1); 1029 WriteLog(msg, sizeof(msg) - 1);
1020 sys__exit(1); 1030 sys__exit(1);
1021 } 1031 }
1022 1032
1033 // Runs in the helper process to wait for the upload process running
1034 // ExecUploadProcessOrTerminate() to finish. Returns the number of bytes written
1035 // to |fd| and save the written contents to |buf|.
1036 // |buf| needs to be big enough to hold |bytes_to_read| + 1 characters.
1037 size_t WaitForCrashReportUploadProcess(int fd, size_t bytes_to_read,
1038 char* buf) {
1039 size_t bytes_read = 0;
1040
1041 // Upload should finish in about 10 seconds. Add a few more 500 ms
1042 // internals to account for process startup time.
1043 for (size_t wait_count = 0; wait_count < 24; ++wait_count) {
1044 struct kernel_pollfd poll_fd;
1045 poll_fd.fd = fd;
1046 poll_fd.events = POLLIN | POLLPRI | POLLERR;
1047 int ret = sys_poll(&poll_fd, 1, 500);
1048 if (ret < 0) {
1049 // Error
1050 break;
1051 } else if (ret > 0) {
1052 // There is data to read.
1053 ssize_t len = HANDLE_EINTR(
1054 sys_read(fd, buf + bytes_read, bytes_to_read - bytes_read));
1055 if (len < 0)
1056 break;
1057 bytes_read += len;
1058 if (bytes_read == bytes_to_read)
1059 break;
1060 }
1061 // |ret| == 0 -> timed out, continue waiting.
1062 // or |bytes_read| < |bytes_to_read| still, keep reading.
1063 }
1064 buf[bytes_to_read] = 0; // Always NUL terminate the buffer.
1065 return bytes_read;
1066 }
1067
1068 // |buf| should be |expected_len| + 1 characters in size and NULL terminated.
1069 bool IsValidCrashReportId(const char* buf, size_t bytes_read,
1070 size_t expected_len) {
1071 if (bytes_read != expected_len)
1072 return false;
1073 #if defined(OS_CHROMEOS)
1074 return my_strcmp(buf, "_sys_cr_finished") == 0;
1075 #else
1076 for (size_t i = 0; i <= bytes_read; ++i) {
1077 if (!my_isxdigit(buf[i]))
1078 return false;
1079 }
1080 return true;
1081 #endif
1082 }
1083
1084 // |buf| should be |expected_len| + 1 characters in size and NULL terminated.
1085 void HandleCrashReportId(const char* buf, size_t bytes_read,
1086 size_t expected_len) {
1087 WriteNewline();
1088 if (!IsValidCrashReportId(buf, bytes_read, expected_len)) {
1089 #if defined(OS_CHROMEOS)
1090 static const char msg[] = "Crash_reporter failed to process crash report";
1091 #else
1092 static const char msg[] = "Failed to get crash dump id.";
1093 #endif
1094 WriteLog(msg, sizeof(msg) - 1);
1095 WriteNewline();
1096 return;
1097 }
1098
1099 #if defined(OS_CHROMEOS)
1100 static const char msg[] = "Crash dump received by crash_reporter\n";
1101 WriteLog(msg, sizeof(msg) - 1);
1102 #else
1103 // Write crash dump id to stderr.
1104 static const char msg[] = "Crash dump id: ";
1105 WriteLog(msg, sizeof(msg) - 1);
1106 WriteLog(buf, my_strlen(buf));
1107 WriteNewline();
1108
1109 // Write crash dump id to crash log as: seconds_since_epoch,crash_id
1110 struct kernel_timeval tv;
1111 if (g_crash_log_path && !sys_gettimeofday(&tv, NULL)) {
1112 uint64_t time = kernel_timeval_to_ms(&tv) / 1000;
1113 char time_str[kUint64StringSize];
1114 const unsigned time_len = my_uint64_len(time);
1115 my_uint64tos(time_str, time, time_len);
1116
1117 const int kLogOpenFlags = O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC;
1118 int log_fd = sys_open(g_crash_log_path, kLogOpenFlags, 0600);
1119 if (log_fd > 0) {
1120 sys_write(log_fd, time_str, time_len);
1121 sys_write(log_fd, ",", 1);
1122 sys_write(log_fd, buf, my_strlen(buf));
1123 sys_write(log_fd, "\n", 1);
1124 IGNORE_RET(sys_close(log_fd));
1125 }
1126 }
1127 #endif
1128 }
1129
1023 #if defined(OS_CHROMEOS) 1130 #if defined(OS_CHROMEOS)
1024 const char* GetCrashingProcessName(const BreakpadInfo& info, 1131 const char* GetCrashingProcessName(const BreakpadInfo& info,
1025 google_breakpad::PageAllocator* allocator) { 1132 google_breakpad::PageAllocator* allocator) {
1026 // Symlink to process binary is at /proc/###/exe. 1133 // Symlink to process binary is at /proc/###/exe.
1027 char linkpath[kUint64StringSize + sizeof("/proc/") + sizeof("/exe")] = 1134 char linkpath[kUint64StringSize + sizeof("/proc/") + sizeof("/exe")] =
1028 "/proc/"; 1135 "/proc/";
1029 uint64_t pid_value_len = my_uint64_len(info.pid); 1136 uint64_t pid_value_len = my_uint64_len(info.pid);
1030 my_uint64tos(linkpath + sizeof("/proc/") - 1, info.pid, pid_value_len); 1137 my_uint64tos(linkpath + sizeof("/proc/") - 1, info.pid, pid_value_len);
1031 linkpath[sizeof("/proc/") - 1 + pid_value_len] = '\0'; 1138 linkpath[sizeof("/proc/") - 1 + pid_value_len] = '\0';
1032 my_strlcat(linkpath, "/exe", sizeof(linkpath)); 1139 my_strlcat(linkpath, "/exe", sizeof(linkpath));
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
1198 // Content-Type: application/octet-stream \r\n \r\n 1305 // Content-Type: application/octet-stream \r\n \r\n
1199 // <dump contents> 1306 // <dump contents>
1200 // \r\n BOUNDARY -- \r\n 1307 // \r\n BOUNDARY -- \r\n
1201 1308
1202 #if defined(OS_CHROMEOS) 1309 #if defined(OS_CHROMEOS)
1203 CrashReporterWriter writer(temp_file_fd); 1310 CrashReporterWriter writer(temp_file_fd);
1204 #else 1311 #else
1205 MimeWriter writer(temp_file_fd, mime_boundary); 1312 MimeWriter writer(temp_file_fd, mime_boundary);
1206 #endif 1313 #endif
1207 { 1314 {
1315 // TODO(thestig) Do not use this inside a compromised context.
1208 std::string product_name; 1316 std::string product_name;
1209 std::string version; 1317 std::string version;
1210 1318
1211 GetBreakpadClient()->GetProductNameAndVersion(&product_name, &version); 1319 GetBreakpadClient()->GetProductNameAndVersion(&product_name, &version);
1212 1320
1213 writer.AddBoundary(); 1321 writer.AddBoundary();
1214 writer.AddPairString("prod", product_name.c_str()); 1322 writer.AddPairString("prod", product_name.c_str());
1215 writer.AddBoundary(); 1323 writer.AddBoundary();
1216 writer.AddPairString("ver", version.c_str()); 1324 writer.AddPairString("ver", version.c_str());
1217 writer.AddBoundary(); 1325 writer.AddBoundary();
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
1403 // Upload process. 1511 // Upload process.
1404 IGNORE_RET(sys_close(fds[0])); 1512 IGNORE_RET(sys_close(fds[0]));
1405 IGNORE_RET(sys_dup2(fds[1], 3)); 1513 IGNORE_RET(sys_dup2(fds[1], 3));
1406 ExecUploadProcessOrTerminate(info, temp_file, mime_boundary, exe_buf, 1514 ExecUploadProcessOrTerminate(info, temp_file, mime_boundary, exe_buf,
1407 &allocator); 1515 &allocator);
1408 } 1516 }
1409 1517
1410 // Helper process. 1518 // Helper process.
1411 if (upload_child > 0) { 1519 if (upload_child > 0) {
1412 IGNORE_RET(sys_close(fds[1])); 1520 IGNORE_RET(sys_close(fds[1]));
1413 char id_buf[17]; // Crash report IDs are expected to be 16 chars.
1414 ssize_t len = -1;
1415 // Upload should finish in about 10 seconds. Add a few more 500 ms
1416 // internals to account for process startup time.
1417 for (size_t wait_count = 0; wait_count < 24; ++wait_count) {
1418 struct kernel_pollfd poll_fd;
1419 poll_fd.fd = fds[0];
1420 poll_fd.events = POLLIN | POLLPRI | POLLERR;
1421 int ret = sys_poll(&poll_fd, 1, 500);
1422 if (ret < 0) {
1423 // Error
1424 break;
1425 } else if (ret > 0) {
1426 // There is data to read.
1427 len = HANDLE_EINTR(sys_read(fds[0], id_buf, sizeof(id_buf) - 1));
1428 break;
1429 }
1430 // ret == 0 -> timed out, continue waiting.
1431 }
1432 if (len > 0) {
1433 // Write crash dump id to stderr.
1434 id_buf[len] = 0;
1435 static const char msg[] = "\nCrash dump id: ";
1436 WriteLog(msg, sizeof(msg) - 1);
1437 WriteLog(id_buf, my_strlen(id_buf));
1438 WriteLog("\n", 1);
1439 1521
1440 // Write crash dump id to crash log as: seconds_since_epoch,crash_id 1522 const size_t kCrashIdLength = 16;
1441 struct kernel_timeval tv; 1523 char id_buf[kCrashIdLength + 1];
1442 if (g_crash_log_path && !sys_gettimeofday(&tv, NULL)) { 1524 size_t bytes_read =
1443 uint64_t time = kernel_timeval_to_ms(&tv) / 1000; 1525 WaitForCrashReportUploadProcess(fds[0], kCrashIdLength, id_buf);
1444 char time_str[kUint64StringSize]; 1526 HandleCrashReportId(id_buf, bytes_read, kCrashIdLength);
1445 const unsigned time_len = my_uint64_len(time);
1446 my_uint64tos(time_str, time, time_len);
1447 1527
1448 int log_fd = sys_open(g_crash_log_path,
1449 O_CREAT | O_WRONLY | O_APPEND,
1450 0600);
1451 if (log_fd > 0) {
1452 sys_write(log_fd, time_str, time_len);
1453 sys_write(log_fd, ",", 1);
1454 sys_write(log_fd, id_buf, my_strlen(id_buf));
1455 sys_write(log_fd, "\n", 1);
1456 IGNORE_RET(sys_close(log_fd));
1457 }
1458 }
1459 }
1460 if (sys_waitpid(upload_child, NULL, WNOHANG) == 0) { 1528 if (sys_waitpid(upload_child, NULL, WNOHANG) == 0) {
1461 // Upload process is still around, kill it. 1529 // Upload process is still around, kill it.
1462 sys_kill(upload_child, SIGKILL); 1530 sys_kill(upload_child, SIGKILL);
1463 } 1531 }
1464 } 1532 }
1465 } 1533 }
1466 1534
1467 // Helper process. 1535 // Helper process.
1468 IGNORE_RET(sys_unlink(info.filename)); 1536 IGNORE_RET(sys_unlink(info.filename));
1469 #if defined(ADDRESS_SANITIZER) 1537 #if defined(ADDRESS_SANITIZER)
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
1545 } 1613 }
1546 } 1614 }
1547 } 1615 }
1548 #endif // OS_ANDROID 1616 #endif // OS_ANDROID
1549 1617
1550 bool IsCrashReporterEnabled() { 1618 bool IsCrashReporterEnabled() {
1551 return g_is_crash_reporter_enabled; 1619 return g_is_crash_reporter_enabled;
1552 } 1620 }
1553 1621
1554 } // namespace breakpad 1622 } // namespace breakpad
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698