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

Side by Side Diff: components/crash/content/app/breakpad_linux.cc

Issue 2676023003: breakpad: Fix crash_reporter upload success handling on Chrome OS (Closed)
Patch Set: fix unused var Created 3 years, 10 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
« 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/crash/content/app/breakpad_linux.h" 8 #include "components/crash/content/app/breakpad_linux.h"
9 9
10 #include <fcntl.h> 10 #include <fcntl.h>
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 93
94 bool g_is_crash_reporter_enabled = false; 94 bool g_is_crash_reporter_enabled = false;
95 uint64_t g_process_start_time = 0; 95 uint64_t g_process_start_time = 0;
96 pid_t g_pid = 0; 96 pid_t g_pid = 0;
97 char* g_crash_log_path = nullptr; 97 char* g_crash_log_path = nullptr;
98 ExceptionHandler* g_breakpad = nullptr; 98 ExceptionHandler* g_breakpad = nullptr;
99 99
100 #if defined(ADDRESS_SANITIZER) 100 #if defined(ADDRESS_SANITIZER)
101 const char* g_asan_report_str = nullptr; 101 const char* g_asan_report_str = nullptr;
102 #endif 102 #endif
103
103 #if defined(OS_ANDROID) 104 #if defined(OS_ANDROID)
104 #define G_DUMPS_SUPPRESSED_MAGIC 0x5AFECEDE 105 #define G_DUMPS_SUPPRESSED_MAGIC 0x5AFECEDE
105 uint32_t g_dumps_suppressed = 0; 106 uint32_t g_dumps_suppressed = 0;
106 char* g_process_type = nullptr; 107 char* g_process_type = nullptr;
107 ExceptionHandler* g_microdump = nullptr; 108 ExceptionHandler* g_microdump = nullptr;
108 int g_signal_code_pipe_fd = -1; 109 int g_signal_code_pipe_fd = -1;
109 110
110 class MicrodumpInfo { 111 class MicrodumpInfo {
111 public: 112 public:
112 MicrodumpInfo() 113 MicrodumpInfo()
(...skipping 1037 matching lines...) Expand 10 before | Expand all | Expand 10 after
1150 1151
1151 if (*fd < 0) { 1152 if (*fd < 0) {
1152 static const char msg[] = "Cannot upload crash dump: failed to open\n"; 1153 static const char msg[] = "Cannot upload crash dump: failed to open\n";
1153 WriteLog(msg, sizeof(msg) - 1); 1154 WriteLog(msg, sizeof(msg) - 1);
1154 return; 1155 return;
1155 } 1156 }
1156 1157
1157 LoadDataFromFD(allocator, *fd, true, file_data, size); 1158 LoadDataFromFD(allocator, *fd, true, file_data, size);
1158 } 1159 }
1159 1160
1160 // Spawn the appropriate upload process for the current OS: 1161 #if defined(OS_CHROMEOS)
1161 // - generic Linux invokes wget. 1162
1162 // - ChromeOS invokes crash_reporter. 1163 // Invoke crash_reporter to notify it of the crash. The actual upload is handled
1164 // by crash_uploader, which runs on a schedule.
1163 // |dumpfile| is the path to the dump data file. 1165 // |dumpfile| is the path to the dump data file.
1164 // |mime_boundary| is only used on Linux. 1166 // |exe_buf| is is the crashing process' name.
1165 // |exe_buf| is only used on CrOS and is the crashing process' name. 1167 // |status_pipe_fd| is the file descriptor of a pipe that will receive the magic
1166 void ExecUploadProcessOrTerminate(const BreakpadInfo& info, 1168 // crash complete string.
1169 void UploadWithCrashReporterOrExit(const BreakpadInfo& info,
1167 const char* dumpfile, 1170 const char* dumpfile,
1168 const char* mime_boundary,
1169 const char* exe_buf, 1171 const char* exe_buf,
1172 int uploader_status_fd,
1170 google_breakpad::PageAllocator* allocator) { 1173 google_breakpad::PageAllocator* allocator) {
1171 #if defined(OS_CHROMEOS)
1172 // CrOS uses crash_reporter instead of wget to report crashes, 1174 // CrOS uses crash_reporter instead of wget to report crashes,
1173 // it needs to know where the crash dump lives and the pid and uid of the 1175 // it needs to know where the crash dump lives and the pid and uid of the
1174 // crashing process. 1176 // crashing process.
1175 static const char kCrashReporterBinary[] = "/sbin/crash_reporter"; 1177 static const char kCrashReporterBinary[] = "/sbin/crash_reporter";
1176 1178
1179 // crash_reporter writes output to stdout. Connect it to the status pipe fd.
1180 if (sys_dup2(uploader_status_fd, STDOUT_FILENO) == -1) {
1181 const char err[] = "dup2 failed";
1182 WriteLog(err, sizeof(err) - 1);
1183 // Continue anyway, as crash_report may succeed even if we can't read its
1184 // status.
1185 }
1186
1177 char pid_buf[kUint64StringSize]; 1187 char pid_buf[kUint64StringSize];
1178 uint64_t pid_str_length = my_uint64_len(info.pid); 1188 uint64_t pid_str_length = my_uint64_len(info.pid);
1179 my_uint64tos(pid_buf, info.pid, pid_str_length); 1189 my_uint64tos(pid_buf, info.pid, pid_str_length);
1180 pid_buf[pid_str_length] = '\0'; 1190 pid_buf[pid_str_length] = '\0';
1181 1191
1182 char uid_buf[kUint64StringSize]; 1192 char uid_buf[kUint64StringSize];
1183 uid_t uid = geteuid(); 1193 uid_t uid = geteuid();
1184 uint64_t uid_str_length = my_uint64_len(uid); 1194 uint64_t uid_str_length = my_uint64_len(uid);
1185 my_uint64tos(uid_buf, uid, uid_str_length); 1195 my_uint64tos(uid_buf, uid, uid_str_length);
1186 uid_buf[uid_str_length] = '\0'; 1196 uid_buf[uid_str_length] = '\0';
(...skipping 29 matching lines...) Expand all
1216 const char* args[] = { 1226 const char* args[] = {
1217 kCrashReporterBinary, 1227 kCrashReporterBinary,
1218 chrome_flag, 1228 chrome_flag,
1219 pid_flag, 1229 pid_flag,
1220 uid_flag, 1230 uid_flag,
1221 exe_flag, 1231 exe_flag,
1222 nullptr, 1232 nullptr,
1223 }; 1233 };
1224 static const char msg[] = "Cannot upload crash dump: cannot exec " 1234 static const char msg[] = "Cannot upload crash dump: cannot exec "
1225 "/sbin/crash_reporter\n"; 1235 "/sbin/crash_reporter\n";
1226 #else 1236 execve(args[0], const_cast<char**>(args), environ);
1237 WriteLog(msg, sizeof(msg) - 1);
1238 sys__exit(1);
1239 }
1240
1241 #else // defined(OS_CHROMEOS)
1242
1243 // Invoke wget to upload the crash dump.
1244 // |dumpfile| is the path to the dump data file.
1245 // |uploader_status_fd| is the file descriptor to which to write the crash id.
1246 void UploadWithWgetOrExit(const BreakpadInfo& info,
1247 const char* dumpfile,
vapier 2017/02/06 17:17:44 indent is off here
James Cook 2017/02/06 22:09:05 Deleted this block.
1248 const char* mime_boundary,
1249 int uploader_status_fd,
1250 google_breakpad::PageAllocator* allocator) {
1251 // Configure wget to write to file descriptor 3. Do this before other work
vapier 2017/02/06 17:17:44 does it really need to dup ? can't it write to /d
James Cook 2017/02/06 22:09:05 Changed to write to /dev/fd/<foo> directly. I extr
1252 // that might allocate a file descriptor.
1253 const int kWgetOutputFd = 3;
1254 const char kWgetOutputFdPath[] = "/dev/fd/3";
1255 if (sys_dup2(uploader_status_fd, kWgetOutputFd) == -1) {
1256 const char err[] = "dup2 failed";
1257 WriteLog(err, sizeof(err) - 1);
1258 // Continue anyway since wget may succeed even if we can't read its status.
1259 }
1260
1227 // Compress |dumpfile| with gzip. 1261 // Compress |dumpfile| with gzip.
1228 const pid_t gzip_child = sys_fork(); 1262 const pid_t gzip_child = sys_fork();
1229 if (gzip_child < 0) { 1263 if (gzip_child < 0) {
1230 static const char msg[] = "sys_fork() for gzip process failed.\n"; 1264 static const char msg[] = "sys_fork() for gzip process failed.\n";
1231 WriteLog(msg, sizeof(msg) - 1); 1265 WriteLog(msg, sizeof(msg) - 1);
1232 sys__exit(1); 1266 sys__exit(1);
1233 } 1267 }
1234 if (!gzip_child) { 1268 if (!gzip_child) {
1235 // gzip process. 1269 // gzip process.
1236 const char* args[] = { 1270 const char* args[] = {
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
1296 static const char kWgetBinary[] = "/usr/bin/wget"; 1330 static const char kWgetBinary[] = "/usr/bin/wget";
1297 const char* args[] = { 1331 const char* args[] = {
1298 kWgetBinary, 1332 kWgetBinary,
1299 header_content_encoding, 1333 header_content_encoding,
1300 header_content_type, 1334 header_content_type,
1301 post_file, 1335 post_file,
1302 kUploadURL, 1336 kUploadURL,
1303 "--timeout=10", // Set a timeout so we don't hang forever. 1337 "--timeout=10", // Set a timeout so we don't hang forever.
1304 "--tries=1", // Don't retry if the upload fails. 1338 "--tries=1", // Don't retry if the upload fails.
1305 "-O", // output reply to fd 3 1339 "-O", // output reply to fd 3
1306 "/dev/fd/3", 1340 kWgetOutputFdPath,
1307 nullptr, 1341 nullptr,
1308 }; 1342 };
1309 static const char msg[] = "Cannot upload crash dump: cannot exec " 1343 static const char msg[] = "Cannot upload crash dump: cannot exec "
1310 "/usr/bin/wget\n"; 1344 "/usr/bin/wget\n";
1311 #endif
1312 execve(args[0], const_cast<char**>(args), environ); 1345 execve(args[0], const_cast<char**>(args), environ);
1313 WriteLog(msg, sizeof(msg) - 1); 1346 WriteLog(msg, sizeof(msg) - 1);
1314 sys__exit(1); 1347 sys__exit(1);
1315 } 1348 }
1316 1349
1350 #endif // defined(OS_CHROMEOS)
1351
1317 // Runs in the helper process to wait for the upload process running 1352 // Runs in the helper process to wait for the upload process running
1318 // ExecUploadProcessOrTerminate() to finish. Returns the number of bytes written 1353 // ExecUploadProcessOrTerminate() to finish. Returns the number of bytes written
1319 // to |fd| and save the written contents to |buf|. 1354 // to |fd| and save the written contents to |buf|.
1320 // |buf| needs to be big enough to hold |bytes_to_read| + 1 characters. 1355 // |buf| needs to be big enough to hold |bytes_to_read| + 1 characters.
1321 size_t WaitForCrashReportUploadProcess(int fd, size_t bytes_to_read, 1356 size_t WaitForCrashReportUploadProcess(int fd, size_t bytes_to_read,
1322 char* buf) { 1357 char* buf) {
1323 size_t bytes_read = 0; 1358 size_t bytes_read = 0;
1324 1359
1325 // Upload should finish in about 10 seconds. Add a few more 500 ms 1360 // Upload should finish in about 10 seconds. Add a few more 500 ms
1326 // internals to account for process startup time. 1361 // internals to account for process startup time.
(...skipping 18 matching lines...) Expand all
1345 // |ret| == 0 -> timed out, continue waiting. 1380 // |ret| == 0 -> timed out, continue waiting.
1346 // or |bytes_read| < |bytes_to_read| still, keep reading. 1381 // or |bytes_read| < |bytes_to_read| still, keep reading.
1347 } 1382 }
1348 buf[bytes_to_read] = 0; // Always NUL terminate the buffer. 1383 buf[bytes_to_read] = 0; // Always NUL terminate the buffer.
1349 return bytes_read; 1384 return bytes_read;
1350 } 1385 }
1351 1386
1352 // |buf| should be |expected_len| + 1 characters in size and nullptr terminated. 1387 // |buf| should be |expected_len| + 1 characters in size and nullptr terminated.
1353 bool IsValidCrashReportId(const char* buf, size_t bytes_read, 1388 bool IsValidCrashReportId(const char* buf, size_t bytes_read,
1354 size_t expected_len) { 1389 size_t expected_len) {
1355 if (bytes_read != expected_len) 1390 if (bytes_read != expected_len) {
1391 static const char msg[] = "Unexpected crash report id length\n";
1392 WriteLog(msg, sizeof(msg) - 1);
1356 return false; 1393 return false;
1394 }
1357 #if defined(OS_CHROMEOS) 1395 #if defined(OS_CHROMEOS)
1396 // See kSuccessMagic in platform2/crash-reporter/chrome_collector.cc.
1358 return my_strcmp(buf, "_sys_cr_finished") == 0; 1397 return my_strcmp(buf, "_sys_cr_finished") == 0;
1359 #else 1398 #else
1360 for (size_t i = 0; i < bytes_read; ++i) { 1399 for (size_t i = 0; i < bytes_read; ++i) {
1361 if (!my_isxdigit(buf[i])) 1400 if (!my_isxdigit(buf[i]))
1362 return false; 1401 return false;
1363 } 1402 }
1364 return true; 1403 return true;
1365 #endif 1404 #endif
1366 } 1405 }
1367 1406
1368 // |buf| should be |expected_len| + 1 characters in size and nullptr terminated. 1407 // |buf| should be |expected_len| + 1 characters in size and nullptr terminated.
1369 void HandleCrashReportId(const char* buf, size_t bytes_read, 1408 void HandleCrashReportId(const char* buf, size_t bytes_read,
1370 size_t expected_len) { 1409 size_t expected_len) {
1371 WriteNewline(); 1410 WriteNewline();
1372 if (!IsValidCrashReportId(buf, bytes_read, expected_len)) { 1411 if (!IsValidCrashReportId(buf, bytes_read, expected_len)) {
1373 #if defined(OS_CHROMEOS) 1412 #if defined(OS_CHROMEOS)
1374 static const char msg[] = 1413 static const char msg[] =
1375 "System crash-reporter failed to process crash report."; 1414 "System crash_reporter failed to process crash report.";
1376 #else 1415 #else
1377 static const char msg[] = "Failed to get crash dump id."; 1416 static const char msg[] = "Failed to get crash dump id.";
1378 #endif 1417 #endif
1379 WriteLog(msg, sizeof(msg) - 1); 1418 WriteLog(msg, sizeof(msg) - 1);
1380 WriteNewline(); 1419 WriteNewline();
1381 1420
1382 static const char id_msg[] = "Report Id: "; 1421 static const char id_msg[] = "Report Id: ";
1383 WriteLog(id_msg, sizeof(id_msg) - 1); 1422 WriteLog(id_msg, sizeof(id_msg) - 1);
1384 WriteLog(buf, bytes_read); 1423 WriteLog(buf, bytes_read);
1385 WriteNewline(); 1424 WriteNewline();
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1440 if (name) 1479 if (name)
1441 return name + 1; 1480 return name + 1;
1442 return link; 1481 return link;
1443 } 1482 }
1444 } 1483 }
1445 // Either way too long, or a read error. 1484 // Either way too long, or a read error.
1446 return "chrome-crash-unknown-process"; 1485 return "chrome-crash-unknown-process";
1447 } 1486 }
1448 #endif 1487 #endif
1449 1488
1489 // Attempts to close all open file descriptors other than stdin, stdout and
vapier 2017/02/06 17:17:44 this move doesn't seem related ?
James Cook 2017/02/06 22:09:05 No, but HandleCrashDump() is 400 lines long, so I'
1490 // stderr (0, 1, and 2).
1491 void CloseAllFileDescriptors() {
1492 const int fd = sys_open("/proc/self/fd", O_DIRECTORY | O_RDONLY, 0);
1493 if (fd < 0) {
1494 for (unsigned i = 3; i < 8192; ++i)
1495 IGNORE_RET(sys_close(i));
1496 } else {
1497 google_breakpad::DirectoryReader reader(fd);
1498 const char* name;
1499 while (reader.GetNextEntry(&name)) {
1500 int i;
1501 if (my_strtoui(&i, name) && i > 2 && i != fd)
1502 IGNORE_RET(sys_close(i));
1503 reader.PopEntry();
1504 }
1505
1506 IGNORE_RET(sys_close(fd));
1507 }
1508 }
1509
1450 void HandleCrashDump(const BreakpadInfo& info) { 1510 void HandleCrashDump(const BreakpadInfo& info) {
1451 int dumpfd; 1511 int dumpfd;
1452 bool keep_fd = false; 1512 bool keep_fd = false;
1453 size_t dump_size; 1513 size_t dump_size;
1454 uint8_t* dump_data; 1514 uint8_t* dump_data;
1455 google_breakpad::PageAllocator allocator; 1515 google_breakpad::PageAllocator allocator;
1456 const char* exe_buf = nullptr;
1457 1516
1458 if (GetCrashReporterClient()->HandleCrashDump(info.filename)) { 1517 if (GetCrashReporterClient()->HandleCrashDump(info.filename)) {
1459 return; 1518 return;
1460 } 1519 }
1461 1520
1462 #if defined(OS_CHROMEOS) 1521 #if defined(OS_CHROMEOS)
1463 // Grab the crashing process' name now, when it should still be available. 1522 // Grab the crashing process' name now, when it should still be available.
1464 // If we try to do this later in our grandchild the crashing process has 1523 // If we try to do this later in our grandchild the crashing process has
1465 // already terminated. 1524 // already terminated.
1466 exe_buf = GetCrashingProcessName(info, &allocator); 1525 const char* exe_buf = GetCrashingProcessName(info, &allocator);
1467 #endif 1526 #endif
1468 1527
1469 if (info.fd != -1) { 1528 if (info.fd != -1) {
1470 // Dump is provided with an open FD. 1529 // Dump is provided with an open FD.
1471 keep_fd = true; 1530 keep_fd = true;
1472 dumpfd = info.fd; 1531 dumpfd = info.fd;
1473 1532
1474 // The FD is pointing to the end of the file. 1533 // The FD is pointing to the end of the file.
1475 // Rewind, we'll read the data next. 1534 // Rewind, we'll read the data next.
1476 if (lseek(dumpfd, 0, SEEK_SET) == -1) { 1535 if (lseek(dumpfd, 0, SEEK_SET) == -1) {
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
1772 // 1831 //
1773 // This code is called both when a browser is crashing (in which case, 1832 // This code is called both when a browser is crashing (in which case,
1774 // nothing really matters any more) and when a renderer/plugin crashes, in 1833 // nothing really matters any more) and when a renderer/plugin crashes, in
1775 // which case we need to continue. 1834 // which case we need to continue.
1776 // 1835 //
1777 // Since we are a multithreaded app, if we were just to fork(), we might 1836 // Since we are a multithreaded app, if we were just to fork(), we might
1778 // grab file descriptors which have just been created in another thread and 1837 // grab file descriptors which have just been created in another thread and
1779 // hold them open for too long. 1838 // hold them open for too long.
1780 // 1839 //
1781 // Thus, we have to loop and try and close everything. 1840 // Thus, we have to loop and try and close everything.
1782 const int fd = sys_open("/proc/self/fd", O_DIRECTORY | O_RDONLY, 0); 1841 CloseAllFileDescriptors();
1783 if (fd < 0) {
1784 for (unsigned i = 3; i < 8192; ++i)
1785 IGNORE_RET(sys_close(i));
1786 } else {
1787 google_breakpad::DirectoryReader reader(fd);
1788 const char* name;
1789 while (reader.GetNextEntry(&name)) {
1790 int i;
1791 if (my_strtoui(&i, name) && i > 2 && i != fd)
1792 IGNORE_RET(sys_close(i));
1793 reader.PopEntry();
1794 }
1795
1796 IGNORE_RET(sys_close(fd));
1797 }
1798 1842
1799 IGNORE_RET(sys_setsid()); 1843 IGNORE_RET(sys_setsid());
1800 1844
1801 // Leave one end of a pipe in the upload process and watch for it getting 1845 // Leave one end of a pipe in the upload process and watch for it getting
1802 // closed by the upload process exiting. 1846 // closed by the upload process exiting.
1803 int fds[2]; 1847 int fds[2];
1804 if (sys_pipe(fds) >= 0) { 1848 if (sys_pipe(fds) >= 0) {
1805 const pid_t upload_child = sys_fork(); 1849 const pid_t upload_child = sys_fork();
1806 if (!upload_child) { 1850 if (!upload_child) {
1807 // Upload process. 1851 // Upload process.
1808 IGNORE_RET(sys_close(fds[0])); 1852 IGNORE_RET(sys_close(fds[0])); // Close read end of pipe.
1809 IGNORE_RET(sys_dup2(fds[1], 3)); 1853 const int pipe_write_fd = fds[1];
1810 ExecUploadProcessOrTerminate(info, temp_file, mime_boundary, exe_buf, 1854 #if defined(OS_CHROMEOS)
1811 &allocator); 1855 UploadWithCrashReporterOrExit(info, temp_file, exe_buf, pipe_write_fd,
1856 &allocator);
1857 #else
1858 UploadWithWgetOrExit(info, temp_file, mime_boundary, pipe_write_fd,
1859 &allocator);
1860 #endif
1812 } 1861 }
1813 1862
1814 // Helper process. 1863 // Helper process.
1815 if (upload_child > 0) { 1864 if (upload_child > 0) {
1816 IGNORE_RET(sys_close(fds[1])); 1865 IGNORE_RET(sys_close(fds[1])); // Close write end of pipe.
1817 1866
1818 const size_t kCrashIdLength = 16; 1867 const size_t kCrashIdLength = 16;
1819 char id_buf[kCrashIdLength + 1]; 1868 char id_buf[kCrashIdLength + 1];
1820 size_t bytes_read = 1869 size_t bytes_read =
1821 WaitForCrashReportUploadProcess(fds[0], kCrashIdLength, id_buf); 1870 WaitForCrashReportUploadProcess(fds[0], kCrashIdLength, id_buf);
1822 HandleCrashReportId(id_buf, bytes_read, kCrashIdLength); 1871 HandleCrashReportId(id_buf, bytes_read, kCrashIdLength);
1823 1872
1824 if (sys_waitpid(upload_child, nullptr, WNOHANG) == 0) { 1873 if (sys_waitpid(upload_child, nullptr, WNOHANG) == 0) {
1825 // Upload process is still around, kill it. 1874 // Upload process is still around, kill it.
1826 sys_kill(upload_child, SIGKILL); 1875 sys_kill(upload_child, SIGKILL);
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
1974 void SuppressDumpGeneration() { 2023 void SuppressDumpGeneration() {
1975 g_dumps_suppressed = G_DUMPS_SUPPRESSED_MAGIC; 2024 g_dumps_suppressed = G_DUMPS_SUPPRESSED_MAGIC;
1976 } 2025 }
1977 #endif // OS_ANDROID 2026 #endif // OS_ANDROID
1978 2027
1979 bool IsCrashReporterEnabled() { 2028 bool IsCrashReporterEnabled() {
1980 return g_is_crash_reporter_enabled; 2029 return g_is_crash_reporter_enabled;
1981 } 2030 }
1982 2031
1983 } // namespace breakpad 2032 } // 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