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

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

Issue 31243002: Move Linux/Android breakpad implementation to breakpad component (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: updates Created 7 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
« no previous file with comments | « chrome/app/breakpad_linux.h ('k') | chrome/app/breakpad_linux_impl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 // For linux_syscall_support.h. This makes it safe to call embedded system
6 // calls when in seccomp mode.
7
8 #include "chrome/app/breakpad_linux.h"
9
10 #include <fcntl.h>
11 #include <poll.h>
12 #include <signal.h>
13 #include <stdlib.h>
14 #include <sys/socket.h>
15 #include <sys/time.h>
16 #include <sys/types.h>
17 #include <sys/uio.h>
18 #include <sys/wait.h>
19 #include <time.h>
20 #include <unistd.h>
21
22 #include <algorithm>
23 #include <string>
24
25 #include "base/base_switches.h"
26 #include "base/command_line.h"
27 #include "base/debug/crash_logging.h"
28 #include "base/files/file_path.h"
29 #include "base/linux_util.h"
30 #include "base/path_service.h"
31 #include "base/platform_file.h"
32 #include "base/posix/eintr_wrapper.h"
33 #include "base/posix/global_descriptors.h"
34 #include "base/process/memory.h"
35 #include "base/strings/string_util.h"
36 #include "breakpad/src/client/linux/handler/exception_handler.h"
37 #include "breakpad/src/client/linux/minidump_writer/directory_reader.h"
38 #include "breakpad/src/common/linux/linux_libc_support.h"
39 #include "breakpad/src/common/memory.h"
40 #include "chrome/app/breakpad_linux_impl.h"
41 #include "components/breakpad/breakpad_client.h"
42 #include "content/public/common/content_descriptors.h"
43 #include "content/public/common/content_switches.h"
44
45 #if defined(OS_ANDROID)
46 #include <android/log.h>
47 #include <sys/stat.h>
48
49 #include "base/android/build_info.h"
50 #include "base/android/path_utils.h"
51 #endif
52 #include "third_party/lss/linux_syscall_support.h"
53
54 #if defined(ADDRESS_SANITIZER)
55 #include <ucontext.h> // for getcontext().
56 #endif
57
58 #if defined(OS_ANDROID)
59 #define STAT_STRUCT struct stat
60 #define FSTAT_FUNC fstat
61 #else
62 #define STAT_STRUCT struct kernel_stat
63 #define FSTAT_FUNC sys_fstat
64 #endif
65
66 // Some versions of gcc are prone to warn about unused return values. In cases
67 // where we either a) know the call cannot fail, or b) there is nothing we
68 // can do when a call fails, we mark the return code as ignored. This avoids
69 // spurious compiler warnings.
70 #define IGNORE_RET(x) do { if (x); } while (0)
71
72 using google_breakpad::ExceptionHandler;
73 using google_breakpad::MinidumpDescriptor;
74
75 namespace {
76
77 #if !defined(OS_CHROMEOS)
78 const char kUploadURL[] = "https://clients2.google.com/cr/report";
79 #endif
80
81 bool g_is_crash_reporter_enabled = false;
82 uint64_t g_process_start_time = 0;
83 char* g_crash_log_path = NULL;
84 ExceptionHandler* g_breakpad = NULL;
85
86 #if defined(ADDRESS_SANITIZER)
87 const char* g_asan_report_str = NULL;
88 #endif
89 #if defined(OS_ANDROID)
90 char* g_process_type = NULL;
91 #endif
92
93 CrashKeyStorage* g_crash_keys = NULL;
94
95 // Writes the value |v| as 16 hex characters to the memory pointed at by
96 // |output|.
97 void write_uint64_hex(char* output, uint64_t v) {
98 static const char hextable[] = "0123456789abcdef";
99
100 for (int i = 15; i >= 0; --i) {
101 output[i] = hextable[v & 15];
102 v >>= 4;
103 }
104 }
105
106 // The following helper functions are for calculating uptime.
107
108 // Converts a struct timeval to milliseconds.
109 uint64_t timeval_to_ms(struct timeval *tv) {
110 uint64_t ret = tv->tv_sec; // Avoid overflow by explicitly using a uint64_t.
111 ret *= 1000;
112 ret += tv->tv_usec / 1000;
113 return ret;
114 }
115
116 // Converts a struct timeval to milliseconds.
117 uint64_t kernel_timeval_to_ms(struct kernel_timeval *tv) {
118 uint64_t ret = tv->tv_sec; // Avoid overflow by explicitly using a uint64_t.
119 ret *= 1000;
120 ret += tv->tv_usec / 1000;
121 return ret;
122 }
123
124 // String buffer size to use to convert a uint64_t to string.
125 const size_t kUint64StringSize = 21;
126
127 void SetProcessStartTime() {
128 // Set the base process start time value.
129 struct timeval tv;
130 if (!gettimeofday(&tv, NULL))
131 g_process_start_time = timeval_to_ms(&tv);
132 else
133 g_process_start_time = 0;
134 }
135
136 // uint64_t version of my_int_len() from
137 // breakpad/src/common/linux/linux_libc_support.h. Return the length of the
138 // given, non-negative integer when expressed in base 10.
139 unsigned my_uint64_len(uint64_t i) {
140 if (!i)
141 return 1;
142
143 unsigned len = 0;
144 while (i) {
145 len++;
146 i /= 10;
147 }
148
149 return len;
150 }
151
152 // uint64_t version of my_uitos() from
153 // breakpad/src/common/linux/linux_libc_support.h. Convert a non-negative
154 // integer to a string (not null-terminated).
155 void my_uint64tos(char* output, uint64_t i, unsigned i_len) {
156 for (unsigned index = i_len; index; --index, i /= 10)
157 output[index - 1] = '0' + (i % 10);
158 }
159
160 #if defined(OS_ANDROID)
161 char* my_strncpy(char* dst, const char* src, size_t len) {
162 int i = len;
163 char* p = dst;
164 if (!dst || !src)
165 return dst;
166 while (i != 0 && *src != '\0') {
167 *p++ = *src++;
168 i--;
169 }
170 while (i != 0) {
171 *p++ = '\0';
172 i--;
173 }
174 return dst;
175 }
176
177 char* my_strncat(char *dest, const char* src, size_t len) {
178 char* ret = dest;
179 while (*dest)
180 dest++;
181 while (len--)
182 if (!(*dest++ = *src++))
183 return ret;
184 *dest = 0;
185 return ret;
186 }
187 #endif
188
189 size_t LengthWithoutTrailingSpaces(const char* str, size_t len) {
190 while (len > 0 && str[len - 1] == ' ') {
191 len--;
192 }
193 return len;
194 }
195
196 // Populates the passed in allocated string and its size with the distro of
197 // the crashing process.
198 // The passed string is expected to be at least kDistroSize bytes long.
199 void PopulateDistro(char* distro, size_t* distro_len_param) {
200 size_t distro_len = std::min(my_strlen(base::g_linux_distro), kDistroSize);
201 memcpy(distro, base::g_linux_distro, distro_len);
202 if (distro_len_param)
203 *distro_len_param = distro_len;
204 }
205
206 void SetClientIdFromCommandLine(const CommandLine& command_line) {
207 // Get the guid and linux distro from the command line switch.
208 std::string switch_value =
209 command_line.GetSwitchValueASCII(switches::kEnableCrashReporter);
210 size_t separator = switch_value.find(",");
211 if (separator != std::string::npos) {
212 breakpad::GetBreakpadClient()->SetClientID(
213 switch_value.substr(0, separator));
214 base::SetLinuxDistro(switch_value.substr(separator + 1));
215 } else {
216 breakpad::GetBreakpadClient()->SetClientID(switch_value);
217 }
218 }
219
220 // MIME substrings.
221 #if defined(OS_CHROMEOS)
222 const char g_sep[] = ":";
223 #endif
224 const char g_rn[] = "\r\n";
225 const char g_form_data_msg[] = "Content-Disposition: form-data; name=\"";
226 const char g_quote_msg[] = "\"";
227 const char g_dashdash_msg[] = "--";
228 const char g_dump_msg[] = "upload_file_minidump\"; filename=\"dump\"";
229 #if defined(ADDRESS_SANITIZER)
230 const char g_log_msg[] = "upload_file_log\"; filename=\"log\"";
231 #endif
232 const char g_content_type_msg[] = "Content-Type: application/octet-stream";
233
234 // MimeWriter manages an iovec for writing MIMEs to a file.
235 class MimeWriter {
236 public:
237 static const int kIovCapacity = 30;
238 static const size_t kMaxCrashChunkSize = 64;
239
240 MimeWriter(int fd, const char* const mime_boundary);
241 ~MimeWriter();
242
243 // Append boundary.
244 virtual void AddBoundary();
245
246 // Append end of file boundary.
247 virtual void AddEnd();
248
249 // Append key/value pair with specified sizes.
250 virtual void AddPairData(const char* msg_type,
251 size_t msg_type_size,
252 const char* msg_data,
253 size_t msg_data_size);
254
255 // Append key/value pair.
256 void AddPairString(const char* msg_type,
257 const char* msg_data) {
258 AddPairData(msg_type, my_strlen(msg_type), msg_data, my_strlen(msg_data));
259 }
260
261 // Append key/value pair, splitting value into chunks no larger than
262 // |chunk_size|. |chunk_size| cannot be greater than |kMaxCrashChunkSize|.
263 // The msg_type string will have a counter suffix to distinguish each chunk.
264 virtual void AddPairDataInChunks(const char* msg_type,
265 size_t msg_type_size,
266 const char* msg_data,
267 size_t msg_data_size,
268 size_t chunk_size,
269 bool strip_trailing_spaces);
270
271 // Add binary file contents to be uploaded with the specified filename.
272 virtual void AddFileContents(const char* filename_msg,
273 uint8_t* file_data,
274 size_t file_size);
275
276 // Flush any pending iovecs to the output file.
277 void Flush() {
278 IGNORE_RET(sys_writev(fd_, iov_, iov_index_));
279 iov_index_ = 0;
280 }
281
282 protected:
283 void AddItem(const void* base, size_t size);
284 // Minor performance trade-off for easier-to-maintain code.
285 void AddString(const char* str) {
286 AddItem(str, my_strlen(str));
287 }
288 void AddItemWithoutTrailingSpaces(const void* base, size_t size);
289
290 struct kernel_iovec iov_[kIovCapacity];
291 int iov_index_;
292
293 // Output file descriptor.
294 int fd_;
295
296 const char* const mime_boundary_;
297
298 DISALLOW_COPY_AND_ASSIGN(MimeWriter);
299 };
300
301 MimeWriter::MimeWriter(int fd, const char* const mime_boundary)
302 : iov_index_(0),
303 fd_(fd),
304 mime_boundary_(mime_boundary) {
305 }
306
307 MimeWriter::~MimeWriter() {
308 }
309
310 void MimeWriter::AddBoundary() {
311 AddString(mime_boundary_);
312 AddString(g_rn);
313 }
314
315 void MimeWriter::AddEnd() {
316 AddString(mime_boundary_);
317 AddString(g_dashdash_msg);
318 AddString(g_rn);
319 }
320
321 void MimeWriter::AddPairData(const char* msg_type,
322 size_t msg_type_size,
323 const char* msg_data,
324 size_t msg_data_size) {
325 AddString(g_form_data_msg);
326 AddItem(msg_type, msg_type_size);
327 AddString(g_quote_msg);
328 AddString(g_rn);
329 AddString(g_rn);
330 AddItem(msg_data, msg_data_size);
331 AddString(g_rn);
332 }
333
334 void MimeWriter::AddPairDataInChunks(const char* msg_type,
335 size_t msg_type_size,
336 const char* msg_data,
337 size_t msg_data_size,
338 size_t chunk_size,
339 bool strip_trailing_spaces) {
340 if (chunk_size > kMaxCrashChunkSize)
341 return;
342
343 unsigned i = 0;
344 size_t done = 0, msg_length = msg_data_size;
345
346 while (msg_length) {
347 char num[kUint64StringSize];
348 const unsigned num_len = my_uint_len(++i);
349 my_uitos(num, i, num_len);
350
351 size_t chunk_len = std::min(chunk_size, msg_length);
352
353 AddString(g_form_data_msg);
354 AddItem(msg_type, msg_type_size);
355 AddItem(num, num_len);
356 AddString(g_quote_msg);
357 AddString(g_rn);
358 AddString(g_rn);
359 if (strip_trailing_spaces) {
360 AddItemWithoutTrailingSpaces(msg_data + done, chunk_len);
361 } else {
362 AddItem(msg_data + done, chunk_len);
363 }
364 AddString(g_rn);
365 AddBoundary();
366 Flush();
367
368 done += chunk_len;
369 msg_length -= chunk_len;
370 }
371 }
372
373 void MimeWriter::AddFileContents(const char* filename_msg, uint8_t* file_data,
374 size_t file_size) {
375 AddString(g_form_data_msg);
376 AddString(filename_msg);
377 AddString(g_rn);
378 AddString(g_content_type_msg);
379 AddString(g_rn);
380 AddString(g_rn);
381 AddItem(file_data, file_size);
382 AddString(g_rn);
383 }
384
385 void MimeWriter::AddItem(const void* base, size_t size) {
386 // Check if the iovec is full and needs to be flushed to output file.
387 if (iov_index_ == kIovCapacity) {
388 Flush();
389 }
390 iov_[iov_index_].iov_base = const_cast<void*>(base);
391 iov_[iov_index_].iov_len = size;
392 ++iov_index_;
393 }
394
395 void MimeWriter::AddItemWithoutTrailingSpaces(const void* base, size_t size) {
396 AddItem(base, LengthWithoutTrailingSpaces(static_cast<const char*>(base),
397 size));
398 }
399
400 #if defined(OS_CHROMEOS)
401 // This subclass is used on Chromium OS to report crashes in a format easy for
402 // the central crash reporting facility to understand.
403 // Format is <name>:<data length in decimal>:<data>
404 class CrashReporterWriter : public MimeWriter
405 {
406 public:
407 explicit CrashReporterWriter(int fd);
408
409 virtual void AddBoundary() OVERRIDE;
410
411 virtual void AddEnd() OVERRIDE;
412
413 virtual void AddPairData(const char* msg_type,
414 size_t msg_type_size,
415 const char* msg_data,
416 size_t msg_data_size) OVERRIDE;
417
418 virtual void AddPairDataInChunks(const char* msg_type,
419 size_t msg_type_size,
420 const char* msg_data,
421 size_t msg_data_size,
422 size_t chunk_size,
423 bool strip_trailing_spaces) OVERRIDE;
424
425 virtual void AddFileContents(const char* filename_msg,
426 uint8_t* file_data,
427 size_t file_size) OVERRIDE;
428
429 private:
430 DISALLOW_COPY_AND_ASSIGN(CrashReporterWriter);
431 };
432
433
434 CrashReporterWriter::CrashReporterWriter(int fd) : MimeWriter(fd, "") {}
435
436 // No-ops.
437 void CrashReporterWriter::AddBoundary() {}
438 void CrashReporterWriter::AddEnd() {}
439
440 void CrashReporterWriter::AddPairData(const char* msg_type,
441 size_t msg_type_size,
442 const char* msg_data,
443 size_t msg_data_size) {
444 char data[kUint64StringSize];
445 const unsigned data_len = my_uint_len(msg_data_size);
446 my_uitos(data, msg_data_size, data_len);
447
448 AddItem(msg_type, msg_type_size);
449 AddString(g_sep);
450 AddItem(data, data_len);
451 AddString(g_sep);
452 AddItem(msg_data, msg_data_size);
453 Flush();
454 }
455
456 void CrashReporterWriter::AddPairDataInChunks(const char* msg_type,
457 size_t msg_type_size,
458 const char* msg_data,
459 size_t msg_data_size,
460 size_t chunk_size,
461 bool strip_trailing_spaces) {
462 if (chunk_size > kMaxCrashChunkSize)
463 return;
464
465 unsigned i = 0;
466 size_t done = 0;
467 size_t msg_length = msg_data_size;
468
469 while (msg_length) {
470 char num[kUint64StringSize];
471 const unsigned num_len = my_uint_len(++i);
472 my_uitos(num, i, num_len);
473
474 size_t chunk_len = std::min(chunk_size, msg_length);
475
476 size_t write_len = chunk_len;
477 if (strip_trailing_spaces) {
478 // Take care of this here because we need to know the exact length of
479 // what is going to be written.
480 write_len = LengthWithoutTrailingSpaces(msg_data + done, write_len);
481 }
482
483 char data[kUint64StringSize];
484 const unsigned data_len = my_uint_len(write_len);
485 my_uitos(data, write_len, data_len);
486
487 AddItem(msg_type, msg_type_size);
488 AddItem(num, num_len);
489 AddString(g_sep);
490 AddItem(data, data_len);
491 AddString(g_sep);
492 AddItem(msg_data + done, write_len);
493 Flush();
494
495 done += chunk_len;
496 msg_length -= chunk_len;
497 }
498 }
499
500 void CrashReporterWriter::AddFileContents(const char* filename_msg,
501 uint8_t* file_data,
502 size_t file_size) {
503 char data[kUint64StringSize];
504 const unsigned data_len = my_uint_len(file_size);
505 my_uitos(data, file_size, data_len);
506
507 AddString(filename_msg);
508 AddString(g_sep);
509 AddItem(data, data_len);
510 AddString(g_sep);
511 AddItem(file_data, file_size);
512 Flush();
513 }
514 #endif
515
516 void DumpProcess() {
517 if (g_breakpad)
518 g_breakpad->WriteMinidump();
519 }
520
521 #if defined(OS_ANDROID)
522 const char kGoogleBreakpad[] = "google-breakpad";
523 #endif
524
525 size_t WriteLog(const char* buf, size_t nbytes) {
526 #if defined(OS_ANDROID)
527 return __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, buf);
528 #else
529 return sys_write(2, buf, nbytes);
530 #endif
531 }
532
533 #if defined(OS_ANDROID)
534 // Android's native crash handler outputs a diagnostic tombstone to the device
535 // log. By returning false from the HandlerCallbacks, breakpad will reinstall
536 // the previous (i.e. native) signal handlers before returning from its own
537 // handler. A Chrome build fingerprint is written to the log, so that the
538 // specific build of Chrome and the location of the archived Chrome symbols can
539 // be determined directly from it.
540 bool FinalizeCrashDoneAndroid() {
541 base::android::BuildInfo* android_build_info =
542 base::android::BuildInfo::GetInstance();
543
544 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
545 "### ### ### ### ### ### ### ### ### ### ### ### ###");
546 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
547 "Chrome build fingerprint:");
548 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
549 android_build_info->package_version_name());
550 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
551 android_build_info->package_version_code());
552 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
553 CHROME_BUILD_ID);
554 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
555 "### ### ### ### ### ### ### ### ### ### ### ### ###");
556 return false;
557 }
558 #endif
559
560 bool CrashDone(const MinidumpDescriptor& minidump,
561 const bool upload,
562 const bool succeeded) {
563 // WARNING: this code runs in a compromised context. It may not call into
564 // libc nor allocate memory normally.
565 if (!succeeded) {
566 const char msg[] = "Failed to generate minidump.";
567 WriteLog(msg, sizeof(msg) - 1);
568 return false;
569 }
570
571 DCHECK(!minidump.IsFD());
572
573 BreakpadInfo info = {0};
574 info.filename = minidump.path();
575 info.fd = minidump.fd();
576 #if defined(ADDRESS_SANITIZER)
577 google_breakpad::PageAllocator allocator;
578 const size_t log_path_len = my_strlen(minidump.path());
579 char* log_path = reinterpret_cast<char*>(allocator.Alloc(log_path_len + 1));
580 my_memcpy(log_path, minidump.path(), log_path_len);
581 my_memcpy(log_path + log_path_len - 4, ".log", 4);
582 log_path[log_path_len] = '\0';
583 info.log_filename = log_path;
584 #endif
585 info.process_type = "browser";
586 info.process_type_length = 7;
587 info.distro = base::g_linux_distro;
588 info.distro_length = my_strlen(base::g_linux_distro);
589 info.upload = upload;
590 info.process_start_time = g_process_start_time;
591 info.oom_size = base::g_oom_size;
592 info.pid = 0;
593 info.crash_keys = g_crash_keys;
594 HandleCrashDump(info);
595 #if defined(OS_ANDROID)
596 return FinalizeCrashDoneAndroid();
597 #else
598 return true;
599 #endif
600 }
601
602 // Wrapper function, do not add more code here.
603 bool CrashDoneNoUpload(const MinidumpDescriptor& minidump,
604 void* context,
605 bool succeeded) {
606 return CrashDone(minidump, false, succeeded);
607 }
608
609 #if !defined(OS_ANDROID)
610 // Wrapper function, do not add more code here.
611 bool CrashDoneUpload(const MinidumpDescriptor& minidump,
612 void* context,
613 bool succeeded) {
614 return CrashDone(minidump, true, succeeded);
615 }
616 #endif
617
618 #if defined(ADDRESS_SANITIZER)
619 extern "C"
620 void __asan_set_error_report_callback(void (*cb)(const char*));
621
622 extern "C"
623 void AsanLinuxBreakpadCallback(const char* report) {
624 g_asan_report_str = report;
625 // Send minidump here.
626 g_breakpad->SimulateSignalDelivery(SIGKILL);
627 }
628 #endif
629
630 void EnableCrashDumping(bool unattended) {
631 g_is_crash_reporter_enabled = true;
632
633 base::FilePath tmp_path("/tmp");
634 PathService::Get(base::DIR_TEMP, &tmp_path);
635
636 base::FilePath dumps_path(tmp_path);
637 if (breakpad::GetBreakpadClient()->GetCrashDumpLocation(&dumps_path)) {
638 base::FilePath logfile = dumps_path.Append(
639 breakpad::GetBreakpadClient()->GetReporterLogFilename());
640 std::string logfile_str = logfile.value();
641 const size_t crash_log_path_len = logfile_str.size() + 1;
642 g_crash_log_path = new char[crash_log_path_len];
643 strncpy(g_crash_log_path, logfile_str.c_str(), crash_log_path_len);
644 }
645 DCHECK(!g_breakpad);
646 MinidumpDescriptor minidump_descriptor(dumps_path.value());
647 minidump_descriptor.set_size_limit(kMaxMinidumpFileSize);
648 #if defined(OS_ANDROID)
649 unattended = true; // Android never uploads directly.
650 #endif
651 if (unattended) {
652 g_breakpad = new ExceptionHandler(
653 minidump_descriptor,
654 NULL,
655 CrashDoneNoUpload,
656 NULL,
657 true, // Install handlers.
658 -1); // Server file descriptor. -1 for in-process.
659 return;
660 }
661
662 #if !defined(OS_ANDROID)
663 // Attended mode
664 g_breakpad = new ExceptionHandler(
665 minidump_descriptor,
666 NULL,
667 CrashDoneUpload,
668 NULL,
669 true, // Install handlers.
670 -1); // Server file descriptor. -1 for in-process.
671 #endif
672 }
673
674 #if defined(OS_ANDROID)
675 bool CrashDoneInProcessNoUpload(
676 const google_breakpad::MinidumpDescriptor& descriptor,
677 void* context,
678 const bool succeeded) {
679 // WARNING: this code runs in a compromised context. It may not call into
680 // libc nor allocate memory normally.
681 if (!succeeded) {
682 static const char msg[] = "Crash dump generation failed.\n";
683 WriteLog(msg, sizeof(msg) - 1);
684 return false;
685 }
686
687 // Start constructing the message to send to the browser.
688 char distro[kDistroSize + 1] = {0};
689 size_t distro_length = 0;
690 PopulateDistro(distro, &distro_length);
691 BreakpadInfo info = {0};
692 info.filename = NULL;
693 info.fd = descriptor.fd();
694 info.process_type = g_process_type;
695 info.process_type_length = my_strlen(g_process_type);
696 info.distro = distro;
697 info.distro_length = distro_length;
698 info.upload = false;
699 info.process_start_time = g_process_start_time;
700 info.crash_keys = g_crash_keys;
701 HandleCrashDump(info);
702 return FinalizeCrashDoneAndroid();
703 }
704
705 void EnableNonBrowserCrashDumping(int minidump_fd) {
706 // This will guarantee that the BuildInfo has been initialized and subsequent
707 // calls will not require memory allocation.
708 base::android::BuildInfo::GetInstance();
709 SetClientIdFromCommandLine(*CommandLine::ForCurrentProcess());
710
711 // On Android, the current sandboxing uses process isolation, in which the
712 // child process runs with a different UID. That breaks the normal crash
713 // reporting where the browser process generates the minidump by inspecting
714 // the child process. This is because the browser process now does not have
715 // the permission to access the states of the child process (as it has a
716 // different UID).
717 // TODO(jcivelli): http://b/issue?id=6776356 we should use a watchdog
718 // process forked from the renderer process that generates the minidump.
719 if (minidump_fd == -1) {
720 LOG(ERROR) << "Minidump file descriptor not found, crash reporting will "
721 " not work.";
722 return;
723 }
724 SetProcessStartTime();
725
726 g_is_crash_reporter_enabled = true;
727 // Save the process type (it is leaked).
728 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
729 const std::string process_type =
730 parsed_command_line.GetSwitchValueASCII(switches::kProcessType);
731 const size_t process_type_len = process_type.size() + 1;
732 g_process_type = new char[process_type_len];
733 strncpy(g_process_type, process_type.c_str(), process_type_len);
734 new google_breakpad::ExceptionHandler(MinidumpDescriptor(minidump_fd),
735 NULL, CrashDoneInProcessNoUpload, NULL, true, -1);
736 }
737 #else
738 // Non-Browser = Extension, Gpu, Plugins, Ppapi and Renderer
739 bool NonBrowserCrashHandler(const void* crash_context,
740 size_t crash_context_size,
741 void* context) {
742 const int fd = reinterpret_cast<intptr_t>(context);
743 int fds[2] = { -1, -1 };
744 if (sys_socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
745 static const char msg[] = "Failed to create socket for crash dumping.\n";
746 WriteLog(msg, sizeof(msg) - 1);
747 return false;
748 }
749
750 // Start constructing the message to send to the browser.
751 char distro[kDistroSize + 1] = {0};
752 PopulateDistro(distro, NULL);
753
754 char b; // Dummy variable for sys_read below.
755 const char* b_addr = &b; // Get the address of |b| so we can create the
756 // expected /proc/[pid]/syscall content in the
757 // browser to convert namespace tids.
758
759 // The length of the control message:
760 static const unsigned kControlMsgSize = sizeof(fds);
761 static const unsigned kControlMsgSpaceSize = CMSG_SPACE(kControlMsgSize);
762 static const unsigned kControlMsgLenSize = CMSG_LEN(kControlMsgSize);
763
764 struct kernel_msghdr msg;
765 my_memset(&msg, 0, sizeof(struct kernel_msghdr));
766 struct kernel_iovec iov[kCrashIovSize];
767 iov[0].iov_base = const_cast<void*>(crash_context);
768 iov[0].iov_len = crash_context_size;
769 iov[1].iov_base = distro;
770 iov[1].iov_len = kDistroSize + 1;
771 iov[2].iov_base = &b_addr;
772 iov[2].iov_len = sizeof(b_addr);
773 iov[3].iov_base = &fds[0];
774 iov[3].iov_len = sizeof(fds[0]);
775 iov[4].iov_base = &g_process_start_time;
776 iov[4].iov_len = sizeof(g_process_start_time);
777 iov[5].iov_base = &base::g_oom_size;
778 iov[5].iov_len = sizeof(base::g_oom_size);
779 google_breakpad::SerializedNonAllocatingMap* serialized_map;
780 iov[6].iov_len = g_crash_keys->Serialize(
781 const_cast<const google_breakpad::SerializedNonAllocatingMap**>(
782 &serialized_map));
783 iov[6].iov_base = serialized_map;
784 #if defined(ADDRESS_SANITIZER)
785 iov[7].iov_base = const_cast<char*>(g_asan_report_str);
786 iov[7].iov_len = kMaxAsanReportSize + 1;
787 #endif
788
789 msg.msg_iov = iov;
790 msg.msg_iovlen = kCrashIovSize;
791 char cmsg[kControlMsgSpaceSize];
792 my_memset(cmsg, 0, kControlMsgSpaceSize);
793 msg.msg_control = cmsg;
794 msg.msg_controllen = sizeof(cmsg);
795
796 struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
797 hdr->cmsg_level = SOL_SOCKET;
798 hdr->cmsg_type = SCM_RIGHTS;
799 hdr->cmsg_len = kControlMsgLenSize;
800 ((int*) CMSG_DATA(hdr))[0] = fds[0];
801 ((int*) CMSG_DATA(hdr))[1] = fds[1];
802
803 if (HANDLE_EINTR(sys_sendmsg(fd, &msg, 0)) < 0) {
804 static const char errmsg[] = "Failed to tell parent about crash.\n";
805 WriteLog(errmsg, sizeof(errmsg) - 1);
806 IGNORE_RET(sys_close(fds[1]));
807 return false;
808 }
809 IGNORE_RET(sys_close(fds[1]));
810
811 if (HANDLE_EINTR(sys_read(fds[0], &b, 1)) != 1) {
812 static const char errmsg[] = "Parent failed to complete crash dump.\n";
813 WriteLog(errmsg, sizeof(errmsg) - 1);
814 }
815
816 return true;
817 }
818
819 void EnableNonBrowserCrashDumping() {
820 const int fd = base::GlobalDescriptors::GetInstance()->Get(kCrashDumpSignal);
821 g_is_crash_reporter_enabled = true;
822 // We deliberately leak this object.
823 DCHECK(!g_breakpad);
824
825 g_breakpad = new ExceptionHandler(
826 MinidumpDescriptor("/tmp"), // Unused but needed or Breakpad will assert.
827 NULL,
828 NULL,
829 reinterpret_cast<void*>(fd), // Param passed to the crash handler.
830 true,
831 -1);
832 g_breakpad->set_crash_handler(NonBrowserCrashHandler);
833 }
834 #endif // defined(OS_ANDROID)
835
836 void SetCrashKeyValue(const base::StringPiece& key,
837 const base::StringPiece& value) {
838 g_crash_keys->SetKeyValue(key.data(), value.data());
839 }
840
841 void ClearCrashKey(const base::StringPiece& key) {
842 g_crash_keys->RemoveKey(key.data());
843 }
844
845 } // namespace
846
847 void LoadDataFromFD(google_breakpad::PageAllocator& allocator,
848 int fd, bool close_fd, uint8_t** file_data, size_t* size) {
849 STAT_STRUCT st;
850 if (FSTAT_FUNC(fd, &st) != 0) {
851 static const char msg[] = "Cannot upload crash dump: stat failed\n";
852 WriteLog(msg, sizeof(msg) - 1);
853 if (close_fd)
854 IGNORE_RET(sys_close(fd));
855 return;
856 }
857
858 *file_data = reinterpret_cast<uint8_t*>(allocator.Alloc(st.st_size));
859 if (!(*file_data)) {
860 static const char msg[] = "Cannot upload crash dump: cannot alloc\n";
861 WriteLog(msg, sizeof(msg) - 1);
862 if (close_fd)
863 IGNORE_RET(sys_close(fd));
864 return;
865 }
866 my_memset(*file_data, 0xf, st.st_size);
867
868 *size = st.st_size;
869 int byte_read = sys_read(fd, *file_data, *size);
870 if (byte_read == -1) {
871 static const char msg[] = "Cannot upload crash dump: read failed\n";
872 WriteLog(msg, sizeof(msg) - 1);
873 if (close_fd)
874 IGNORE_RET(sys_close(fd));
875 return;
876 }
877
878 if (close_fd)
879 IGNORE_RET(sys_close(fd));
880 }
881
882 void LoadDataFromFile(google_breakpad::PageAllocator& allocator,
883 const char* filename,
884 int* fd, uint8_t** file_data, size_t* size) {
885 // WARNING: this code runs in a compromised context. It may not call into
886 // libc nor allocate memory normally.
887 *fd = sys_open(filename, O_RDONLY, 0);
888 *size = 0;
889
890 if (*fd < 0) {
891 static const char msg[] = "Cannot upload crash dump: failed to open\n";
892 WriteLog(msg, sizeof(msg) - 1);
893 return;
894 }
895
896 LoadDataFromFD(allocator, *fd, true, file_data, size);
897 }
898
899 // Spawn the appropriate upload process for the current OS:
900 // - generic Linux invokes wget.
901 // - ChromeOS invokes crash_reporter.
902 // |dumpfile| is the path to the dump data file.
903 // |mime_boundary| is only used on Linux.
904 // |exe_buf| is only used on CrOS and is the crashing process' name.
905 void ExecUploadProcessOrTerminate(const BreakpadInfo& info,
906 const char* dumpfile,
907 const char* mime_boundary,
908 const char* exe_buf,
909 google_breakpad::PageAllocator* allocator) {
910 #if defined(OS_CHROMEOS)
911 // CrOS uses crash_reporter instead of wget to report crashes,
912 // it needs to know where the crash dump lives and the pid and uid of the
913 // crashing process.
914 static const char kCrashReporterBinary[] = "/sbin/crash_reporter";
915
916 char pid_buf[kUint64StringSize];
917 uint64_t pid_str_length = my_uint64_len(info.pid);
918 my_uint64tos(pid_buf, info.pid, pid_str_length);
919 pid_buf[pid_str_length] = '\0';
920
921 char uid_buf[kUint64StringSize];
922 uid_t uid = geteuid();
923 uint64_t uid_str_length = my_uint64_len(uid);
924 my_uint64tos(uid_buf, uid, uid_str_length);
925 uid_buf[uid_str_length] = '\0';
926 const char* args[] = {
927 kCrashReporterBinary,
928 "--chrome",
929 dumpfile,
930 "--pid",
931 pid_buf,
932 "--uid",
933 uid_buf,
934 "--exe",
935 exe_buf,
936 NULL,
937 };
938 static const char msg[] = "Cannot upload crash dump: cannot exec "
939 "/sbin/crash_reporter\n";
940 #else
941 // The --header argument to wget looks like:
942 // --header=Content-Type: multipart/form-data; boundary=XYZ
943 // where the boundary has two fewer leading '-' chars
944 static const char header_msg[] =
945 "--header=Content-Type: multipart/form-data; boundary=";
946 char* const header = reinterpret_cast<char*>(allocator->Alloc(
947 sizeof(header_msg) - 1 + strlen(mime_boundary) - 2 + 1));
948 memcpy(header, header_msg, sizeof(header_msg) - 1);
949 memcpy(header + sizeof(header_msg) - 1, mime_boundary + 2,
950 strlen(mime_boundary) - 2);
951 // We grab the NUL byte from the end of |mime_boundary|.
952
953 // The --post-file argument to wget looks like:
954 // --post-file=/tmp/...
955 static const char post_file_msg[] = "--post-file=";
956 char* const post_file = reinterpret_cast<char*>(allocator->Alloc(
957 sizeof(post_file_msg) - 1 + strlen(dumpfile) + 1));
958 memcpy(post_file, post_file_msg, sizeof(post_file_msg) - 1);
959 memcpy(post_file + sizeof(post_file_msg) - 1, dumpfile, strlen(dumpfile));
960
961 static const char kWgetBinary[] = "/usr/bin/wget";
962 const char* args[] = {
963 kWgetBinary,
964 header,
965 post_file,
966 kUploadURL,
967 "--timeout=10", // Set a timeout so we don't hang forever.
968 "--tries=1", // Don't retry if the upload fails.
969 "-O", // output reply to fd 3
970 "/dev/fd/3",
971 NULL,
972 };
973 static const char msg[] = "Cannot upload crash dump: cannot exec "
974 "/usr/bin/wget\n";
975 #endif
976 execve(args[0], const_cast<char**>(args), environ);
977 WriteLog(msg, sizeof(msg) - 1);
978 sys__exit(1);
979 }
980
981 #if defined(OS_CHROMEOS)
982 const char* GetCrashingProcessName(const BreakpadInfo& info,
983 google_breakpad::PageAllocator* allocator) {
984 // Symlink to process binary is at /proc/###/exe.
985 char linkpath[kUint64StringSize + sizeof("/proc/") + sizeof("/exe")] =
986 "/proc/";
987 uint64_t pid_value_len = my_uint64_len(info.pid);
988 my_uint64tos(linkpath + sizeof("/proc/") - 1, info.pid, pid_value_len);
989 linkpath[sizeof("/proc/") - 1 + pid_value_len] = '\0';
990 my_strlcat(linkpath, "/exe", sizeof(linkpath));
991
992 const int kMaxSize = 4096;
993 char* link = reinterpret_cast<char*>(allocator->Alloc(kMaxSize));
994 if (link) {
995 ssize_t size = readlink(linkpath, link, kMaxSize);
996 if (size < kMaxSize && size > 0) {
997 // readlink(2) doesn't add a terminating NUL, so do it now.
998 link[size] = '\0';
999
1000 const char* name = my_strrchr(link, '/');
1001 if (name)
1002 return name + 1;
1003 return link;
1004 }
1005 }
1006 // Either way too long, or a read error.
1007 return "chrome-crash-unknown-process";
1008 }
1009 #endif
1010
1011 void HandleCrashDump(const BreakpadInfo& info) {
1012 int dumpfd;
1013 bool keep_fd = false;
1014 size_t dump_size;
1015 uint8_t* dump_data;
1016 google_breakpad::PageAllocator allocator;
1017 const char* exe_buf = NULL;
1018
1019 #if defined(OS_CHROMEOS)
1020 // Grab the crashing process' name now, when it should still be available.
1021 // If we try to do this later in our grandchild the crashing process has
1022 // already terminated.
1023 exe_buf = GetCrashingProcessName(info, &allocator);
1024 #endif
1025
1026 if (info.fd != -1) {
1027 // Dump is provided with an open FD.
1028 keep_fd = true;
1029 dumpfd = info.fd;
1030
1031 // The FD is pointing to the end of the file.
1032 // Rewind, we'll read the data next.
1033 if (lseek(dumpfd, 0, SEEK_SET) == -1) {
1034 static const char msg[] = "Cannot upload crash dump: failed to "
1035 "reposition minidump FD\n";
1036 WriteLog(msg, sizeof(msg) - 1);
1037 IGNORE_RET(sys_close(dumpfd));
1038 return;
1039 }
1040 LoadDataFromFD(allocator, info.fd, false, &dump_data, &dump_size);
1041 } else {
1042 // Dump is provided with a path.
1043 keep_fd = false;
1044 LoadDataFromFile(allocator, info.filename, &dumpfd, &dump_data, &dump_size);
1045 }
1046
1047 // TODO(jcivelli): make log work when using FDs.
1048 #if defined(ADDRESS_SANITIZER)
1049 int logfd;
1050 size_t log_size;
1051 uint8_t* log_data;
1052 // Load the AddressSanitizer log into log_data.
1053 LoadDataFromFile(allocator, info.log_filename, &logfd, &log_data, &log_size);
1054 #endif
1055
1056 // We need to build a MIME block for uploading to the server. Since we are
1057 // going to fork and run wget, it needs to be written to a temp file.
1058 const int ufd = sys_open("/dev/urandom", O_RDONLY, 0);
1059 if (ufd < 0) {
1060 static const char msg[] = "Cannot upload crash dump because /dev/urandom"
1061 " is missing\n";
1062 WriteLog(msg, sizeof(msg) - 1);
1063 return;
1064 }
1065
1066 static const char temp_file_template[] =
1067 "/tmp/chromium-upload-XXXXXXXXXXXXXXXX";
1068 char temp_file[sizeof(temp_file_template)];
1069 int temp_file_fd = -1;
1070 if (keep_fd) {
1071 temp_file_fd = dumpfd;
1072 // Rewind the destination, we are going to overwrite it.
1073 if (lseek(dumpfd, 0, SEEK_SET) == -1) {
1074 static const char msg[] = "Cannot upload crash dump: failed to "
1075 "reposition minidump FD (2)\n";
1076 WriteLog(msg, sizeof(msg) - 1);
1077 IGNORE_RET(sys_close(dumpfd));
1078 return;
1079 }
1080 } else {
1081 if (info.upload) {
1082 memcpy(temp_file, temp_file_template, sizeof(temp_file_template));
1083
1084 for (unsigned i = 0; i < 10; ++i) {
1085 uint64_t t;
1086 sys_read(ufd, &t, sizeof(t));
1087 write_uint64_hex(temp_file + sizeof(temp_file) - (16 + 1), t);
1088
1089 temp_file_fd = sys_open(temp_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
1090 if (temp_file_fd >= 0)
1091 break;
1092 }
1093
1094 if (temp_file_fd < 0) {
1095 static const char msg[] = "Failed to create temporary file in /tmp: "
1096 "cannot upload crash dump\n";
1097 WriteLog(msg, sizeof(msg) - 1);
1098 IGNORE_RET(sys_close(ufd));
1099 return;
1100 }
1101 } else {
1102 temp_file_fd = sys_open(info.filename, O_WRONLY, 0600);
1103 if (temp_file_fd < 0) {
1104 static const char msg[] = "Failed to save crash dump: failed to open\n";
1105 WriteLog(msg, sizeof(msg) - 1);
1106 IGNORE_RET(sys_close(ufd));
1107 return;
1108 }
1109 }
1110 }
1111
1112 // The MIME boundary is 28 hyphens, followed by a 64-bit nonce and a NUL.
1113 char mime_boundary[28 + 16 + 1];
1114 my_memset(mime_boundary, '-', 28);
1115 uint64_t boundary_rand;
1116 sys_read(ufd, &boundary_rand, sizeof(boundary_rand));
1117 write_uint64_hex(mime_boundary + 28, boundary_rand);
1118 mime_boundary[28 + 16] = 0;
1119 IGNORE_RET(sys_close(ufd));
1120
1121 // The MIME block looks like this:
1122 // BOUNDARY \r\n
1123 // Content-Disposition: form-data; name="prod" \r\n \r\n
1124 // Chrome_Linux \r\n
1125 // BOUNDARY \r\n
1126 // Content-Disposition: form-data; name="ver" \r\n \r\n
1127 // 1.2.3.4 \r\n
1128 // BOUNDARY \r\n
1129 //
1130 // zero or one:
1131 // Content-Disposition: form-data; name="ptime" \r\n \r\n
1132 // abcdef \r\n
1133 // BOUNDARY \r\n
1134 //
1135 // zero or one:
1136 // Content-Disposition: form-data; name="ptype" \r\n \r\n
1137 // abcdef \r\n
1138 // BOUNDARY \r\n
1139 //
1140 // zero or one:
1141 // Content-Disposition: form-data; name="lsb-release" \r\n \r\n
1142 // abcdef \r\n
1143 // BOUNDARY \r\n
1144 //
1145 // zero or one:
1146 // Content-Disposition: form-data; name="oom-size" \r\n \r\n
1147 // 1234567890 \r\n
1148 // BOUNDARY \r\n
1149 //
1150 // zero or more (up to CrashKeyStorage::num_entries = 64):
1151 // Content-Disposition: form-data; name=crash-key-name \r\n
1152 // crash-key-value \r\n
1153 // BOUNDARY \r\n
1154 //
1155 // Content-Disposition: form-data; name="dump"; filename="dump" \r\n
1156 // Content-Type: application/octet-stream \r\n \r\n
1157 // <dump contents>
1158 // \r\n BOUNDARY -- \r\n
1159
1160 #if defined(OS_CHROMEOS)
1161 CrashReporterWriter writer(temp_file_fd);
1162 #else
1163 MimeWriter writer(temp_file_fd, mime_boundary);
1164 #endif
1165 {
1166 std::string product_name;
1167 std::string version;
1168
1169 breakpad::GetBreakpadClient()->GetProductNameAndVersion(&product_name,
1170 &version);
1171
1172 writer.AddBoundary();
1173 writer.AddPairString("prod", product_name.c_str());
1174 writer.AddBoundary();
1175 writer.AddPairString("ver", version.c_str());
1176 writer.AddBoundary();
1177 if (info.pid > 0) {
1178 char pid_value_buf[kUint64StringSize];
1179 uint64_t pid_value_len = my_uint64_len(info.pid);
1180 my_uint64tos(pid_value_buf, info.pid, pid_value_len);
1181 static const char pid_key_name[] = "pid";
1182 writer.AddPairData(pid_key_name, sizeof(pid_key_name) - 1,
1183 pid_value_buf, pid_value_len);
1184 writer.AddBoundary();
1185 }
1186 #if defined(OS_ANDROID)
1187 // Addtional MIME blocks are added for logging on Android devices.
1188 static const char android_build_id[] = "android_build_id";
1189 static const char android_build_fp[] = "android_build_fp";
1190 static const char device[] = "device";
1191 static const char model[] = "model";
1192 static const char brand[] = "brand";
1193 static const char exception_info[] = "exception_info";
1194
1195 base::android::BuildInfo* android_build_info =
1196 base::android::BuildInfo::GetInstance();
1197 writer.AddPairString(
1198 android_build_id, android_build_info->android_build_id());
1199 writer.AddBoundary();
1200 writer.AddPairString(
1201 android_build_fp, android_build_info->android_build_fp());
1202 writer.AddBoundary();
1203 writer.AddPairString(device, android_build_info->device());
1204 writer.AddBoundary();
1205 writer.AddPairString(model, android_build_info->model());
1206 writer.AddBoundary();
1207 writer.AddPairString(brand, android_build_info->brand());
1208 writer.AddBoundary();
1209 if (android_build_info->java_exception_info() != NULL) {
1210 writer.AddPairString(exception_info,
1211 android_build_info->java_exception_info());
1212 writer.AddBoundary();
1213 }
1214 #endif
1215 writer.Flush();
1216 }
1217
1218 if (info.process_start_time > 0) {
1219 struct kernel_timeval tv;
1220 if (!sys_gettimeofday(&tv, NULL)) {
1221 uint64_t time = kernel_timeval_to_ms(&tv);
1222 if (time > info.process_start_time) {
1223 time -= info.process_start_time;
1224 char time_str[kUint64StringSize];
1225 const unsigned time_len = my_uint64_len(time);
1226 my_uint64tos(time_str, time, time_len);
1227
1228 static const char process_time_msg[] = "ptime";
1229 writer.AddPairData(process_time_msg, sizeof(process_time_msg) - 1,
1230 time_str, time_len);
1231 writer.AddBoundary();
1232 writer.Flush();
1233 }
1234 }
1235 }
1236
1237 if (info.process_type_length) {
1238 writer.AddPairString("ptype", info.process_type);
1239 writer.AddBoundary();
1240 writer.Flush();
1241 }
1242
1243 if (info.distro_length) {
1244 static const char distro_msg[] = "lsb-release";
1245 writer.AddPairString(distro_msg, info.distro);
1246 writer.AddBoundary();
1247 writer.Flush();
1248 }
1249
1250 if (info.oom_size) {
1251 char oom_size_str[kUint64StringSize];
1252 const unsigned oom_size_len = my_uint64_len(info.oom_size);
1253 my_uint64tos(oom_size_str, info.oom_size, oom_size_len);
1254 static const char oom_size_msg[] = "oom-size";
1255 writer.AddPairData(oom_size_msg, sizeof(oom_size_msg) - 1,
1256 oom_size_str, oom_size_len);
1257 writer.AddBoundary();
1258 writer.Flush();
1259 }
1260
1261 if (info.crash_keys) {
1262 CrashKeyStorage::Iterator crash_key_iterator(*info.crash_keys);
1263 const CrashKeyStorage::Entry* entry;
1264 while ((entry = crash_key_iterator.Next())) {
1265 writer.AddPairString(entry->key, entry->value);
1266 writer.AddBoundary();
1267 writer.Flush();
1268 }
1269 }
1270
1271 writer.AddFileContents(g_dump_msg, dump_data, dump_size);
1272 #if defined(ADDRESS_SANITIZER)
1273 // Append a multipart boundary and the contents of the AddressSanitizer log.
1274 writer.AddBoundary();
1275 writer.AddFileContents(g_log_msg, log_data, log_size);
1276 #endif
1277 writer.AddEnd();
1278 writer.Flush();
1279
1280 IGNORE_RET(sys_close(temp_file_fd));
1281
1282 #if defined(OS_ANDROID)
1283 if (info.filename) {
1284 int filename_length = my_strlen(info.filename);
1285
1286 // If this was a file, we need to copy it to the right place and use the
1287 // right file name so it gets uploaded by the browser.
1288 const char msg[] = "Output crash dump file:";
1289 WriteLog(msg, sizeof(msg) - 1);
1290 WriteLog(info.filename, filename_length - 1);
1291
1292 char pid_buf[kUint64StringSize];
1293 uint64_t pid_str_length = my_uint64_len(info.pid);
1294 my_uint64tos(pid_buf, info.pid, pid_str_length);
1295
1296 // -1 because we won't need the null terminator on the original filename.
1297 unsigned done_filename_len = filename_length - 1 + pid_str_length;
1298 char* done_filename = reinterpret_cast<char*>(
1299 allocator.Alloc(done_filename_len));
1300 // Rename the file such that the pid is the suffix in order signal to other
1301 // processes that the minidump is complete. The advantage of using the pid
1302 // as the suffix is that it is trivial to associate the minidump with the
1303 // crashed process.
1304 // Finally, note strncpy prevents null terminators from
1305 // being copied. Pad the rest with 0's.
1306 my_strncpy(done_filename, info.filename, done_filename_len);
1307 // Append the suffix a null terminator should be added.
1308 my_strncat(done_filename, pid_buf, pid_str_length);
1309 // Rename the minidump file to signal that it is complete.
1310 if (rename(info.filename, done_filename)) {
1311 const char failed_msg[] = "Failed to rename:";
1312 WriteLog(failed_msg, sizeof(failed_msg) - 1);
1313 WriteLog(info.filename, filename_length - 1);
1314 const char to_msg[] = "to";
1315 WriteLog(to_msg, sizeof(to_msg) - 1);
1316 WriteLog(done_filename, done_filename_len - 1);
1317 }
1318 }
1319 #endif
1320
1321 if (!info.upload)
1322 return;
1323
1324 const pid_t child = sys_fork();
1325 if (!child) {
1326 // Spawned helper process.
1327 //
1328 // This code is called both when a browser is crashing (in which case,
1329 // nothing really matters any more) and when a renderer/plugin crashes, in
1330 // which case we need to continue.
1331 //
1332 // Since we are a multithreaded app, if we were just to fork(), we might
1333 // grab file descriptors which have just been created in another thread and
1334 // hold them open for too long.
1335 //
1336 // Thus, we have to loop and try and close everything.
1337 const int fd = sys_open("/proc/self/fd", O_DIRECTORY | O_RDONLY, 0);
1338 if (fd < 0) {
1339 for (unsigned i = 3; i < 8192; ++i)
1340 IGNORE_RET(sys_close(i));
1341 } else {
1342 google_breakpad::DirectoryReader reader(fd);
1343 const char* name;
1344 while (reader.GetNextEntry(&name)) {
1345 int i;
1346 if (my_strtoui(&i, name) && i > 2 && i != fd)
1347 IGNORE_RET(sys_close(i));
1348 reader.PopEntry();
1349 }
1350
1351 IGNORE_RET(sys_close(fd));
1352 }
1353
1354 IGNORE_RET(sys_setsid());
1355
1356 // Leave one end of a pipe in the upload process and watch for it getting
1357 // closed by the upload process exiting.
1358 int fds[2];
1359 if (sys_pipe(fds) >= 0) {
1360 const pid_t upload_child = sys_fork();
1361 if (!upload_child) {
1362 // Upload process.
1363 IGNORE_RET(sys_close(fds[0]));
1364 IGNORE_RET(sys_dup2(fds[1], 3));
1365 ExecUploadProcessOrTerminate(info, temp_file, mime_boundary, exe_buf,
1366 &allocator);
1367 }
1368
1369 // Helper process.
1370 if (upload_child > 0) {
1371 IGNORE_RET(sys_close(fds[1]));
1372 char id_buf[17]; // Crash report IDs are expected to be 16 chars.
1373 ssize_t len = -1;
1374 // Upload should finish in about 10 seconds. Add a few more 500 ms
1375 // internals to account for process startup time.
1376 for (size_t wait_count = 0; wait_count < 24; ++wait_count) {
1377 struct kernel_pollfd poll_fd;
1378 poll_fd.fd = fds[0];
1379 poll_fd.events = POLLIN | POLLPRI | POLLERR;
1380 int ret = sys_poll(&poll_fd, 1, 500);
1381 if (ret < 0) {
1382 // Error
1383 break;
1384 } else if (ret > 0) {
1385 // There is data to read.
1386 len = HANDLE_EINTR(sys_read(fds[0], id_buf, sizeof(id_buf) - 1));
1387 break;
1388 }
1389 // ret == 0 -> timed out, continue waiting.
1390 }
1391 if (len > 0) {
1392 // Write crash dump id to stderr.
1393 id_buf[len] = 0;
1394 static const char msg[] = "\nCrash dump id: ";
1395 WriteLog(msg, sizeof(msg) - 1);
1396 WriteLog(id_buf, my_strlen(id_buf));
1397 WriteLog("\n", 1);
1398
1399 // Write crash dump id to crash log as: seconds_since_epoch,crash_id
1400 struct kernel_timeval tv;
1401 if (g_crash_log_path && !sys_gettimeofday(&tv, NULL)) {
1402 uint64_t time = kernel_timeval_to_ms(&tv) / 1000;
1403 char time_str[kUint64StringSize];
1404 const unsigned time_len = my_uint64_len(time);
1405 my_uint64tos(time_str, time, time_len);
1406
1407 int log_fd = sys_open(g_crash_log_path,
1408 O_CREAT | O_WRONLY | O_APPEND,
1409 0600);
1410 if (log_fd > 0) {
1411 sys_write(log_fd, time_str, time_len);
1412 sys_write(log_fd, ",", 1);
1413 sys_write(log_fd, id_buf, my_strlen(id_buf));
1414 sys_write(log_fd, "\n", 1);
1415 IGNORE_RET(sys_close(log_fd));
1416 }
1417 }
1418 }
1419 if (sys_waitpid(upload_child, NULL, WNOHANG) == 0) {
1420 // Upload process is still around, kill it.
1421 sys_kill(upload_child, SIGKILL);
1422 }
1423 }
1424 }
1425
1426 // Helper process.
1427 IGNORE_RET(sys_unlink(info.filename));
1428 #if defined(ADDRESS_SANITIZER)
1429 IGNORE_RET(sys_unlink(info.log_filename));
1430 #endif
1431 IGNORE_RET(sys_unlink(temp_file));
1432 sys__exit(0);
1433 }
1434
1435 // Main browser process.
1436 if (child <= 0)
1437 return;
1438 (void) HANDLE_EINTR(sys_waitpid(child, NULL, 0));
1439 }
1440
1441 void InitCrashReporter() {
1442 #if defined(OS_ANDROID)
1443 // This will guarantee that the BuildInfo has been initialized and subsequent
1444 // calls will not require memory allocation.
1445 base::android::BuildInfo::GetInstance();
1446 #endif
1447 // Determine the process type and take appropriate action.
1448 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
1449 if (parsed_command_line.HasSwitch(switches::kDisableBreakpad))
1450 return;
1451
1452 const std::string process_type =
1453 parsed_command_line.GetSwitchValueASCII(switches::kProcessType);
1454 if (process_type.empty()) {
1455 EnableCrashDumping(breakpad::GetBreakpadClient()->IsRunningUnattended());
1456 } else if (process_type == switches::kRendererProcess ||
1457 process_type == switches::kPluginProcess ||
1458 process_type == switches::kPpapiPluginProcess ||
1459 process_type == switches::kZygoteProcess ||
1460 process_type == switches::kGpuProcess) {
1461 #if defined(OS_ANDROID)
1462 NOTREACHED() << "Breakpad initialized with InitCrashReporter() instead of "
1463 "InitNonBrowserCrashReporter in " << process_type << " process.";
1464 return;
1465 #else
1466 // We might be chrooted in a zygote or renderer process so we cannot call
1467 // GetCollectStatsConsent because that needs access the the user's home
1468 // dir. Instead, we set a command line flag for these processes.
1469 // Even though plugins are not chrooted, we share the same code path for
1470 // simplicity.
1471 if (!parsed_command_line.HasSwitch(switches::kEnableCrashReporter))
1472 return;
1473 SetClientIdFromCommandLine(parsed_command_line);
1474 EnableNonBrowserCrashDumping();
1475 VLOG(1) << "Non Browser crash dumping enabled for: " << process_type;
1476 #endif // #if defined(OS_ANDROID)
1477 }
1478
1479 SetProcessStartTime();
1480
1481 breakpad::GetBreakpadClient()->SetDumpWithoutCrashingFunction(&DumpProcess);
1482 #if defined(ADDRESS_SANITIZER)
1483 // Register the callback for AddressSanitizer error reporting.
1484 __asan_set_error_report_callback(AsanLinuxBreakpadCallback);
1485 #endif
1486
1487 g_crash_keys = new CrashKeyStorage;
1488 breakpad::GetBreakpadClient()->RegisterCrashKeys();
1489 base::debug::SetCrashKeyReportingFunctions(
1490 &SetCrashKeyValue, &ClearCrashKey);
1491 }
1492
1493 #if defined(OS_ANDROID)
1494 void InitNonBrowserCrashReporterForAndroid() {
1495 const CommandLine* command_line = CommandLine::ForCurrentProcess();
1496 if (command_line->HasSwitch(switches::kEnableCrashReporter)) {
1497 // On Android we need to provide a FD to the file where the minidump is
1498 // generated as the renderer and browser run with different UIDs
1499 // (preventing the browser from inspecting the renderer process).
1500 int minidump_fd = base::GlobalDescriptors::GetInstance()->
1501 MaybeGet(breakpad::GetBreakpadClient()->GetAndroidMinidumpDescriptor());
1502 if (minidump_fd == base::kInvalidPlatformFileValue) {
1503 NOTREACHED() << "Could not find minidump FD, crash reporting disabled.";
1504 } else {
1505 EnableNonBrowserCrashDumping(minidump_fd);
1506 }
1507 }
1508 }
1509 #endif // OS_ANDROID
1510
1511 bool IsCrashReporterEnabled() {
1512 return g_is_crash_reporter_enabled;
1513 }
OLDNEW
« no previous file with comments | « chrome/app/breakpad_linux.h ('k') | chrome/app/breakpad_linux_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698