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

Side by Side Diff: shell/crash/breakpad_linux.cc

Issue 1227333002: Add breakpad support to mojo shell apk. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Follow review Created 5 years, 4 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
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 // This file was forked from components/crash/app/breakpad_linux.cc and
6 // components/crash/app/breakpad_linux_impl.h in chromium.
7
8 // For linux_syscall_support.h. This makes it safe to call embedded system
9 // calls when in seccomp mode.
10
11 #include "shell/crash/breakpad_linux.h"
12
13 #include <fcntl.h>
14 #include <poll.h>
15 #include <signal.h>
16 #include <stdlib.h>
17 #include <sys/socket.h>
18 #include <sys/time.h>
19 #include <sys/types.h>
20 #include <sys/uio.h>
21 #include <sys/wait.h>
22 #include <time.h>
23 #include <unistd.h>
24
25 #include <algorithm>
26 #include <string>
27
28 #include "base/base_switches.h"
viettrungluu 2015/07/27 20:28:35 You shouldn't use switches from base_switches.*.
qsr 2015/07/28 08:46:22 Remove the switched for now. We can always add tho
29 #include "base/basictypes.h"
viettrungluu 2015/07/27 20:28:35 nit: Does it compile with including the non-deprec
qsr 2015/07/28 08:46:22 It does. I didn't know basictypes was deprecated.
30 #include "base/command_line.h"
31 #include "base/debug/crash_logging.h"
32 #include "base/debug/dump_without_crashing.h"
33 #include "base/files/file_path.h"
34 #include "base/files/file_util.h"
35 #include "base/linux_util.h"
36 #include "base/path_service.h"
37 #include "base/posix/eintr_wrapper.h"
38 #include "base/process/memory.h"
39 #include "base/strings/string_util.h"
40 #include "build/build_config.h"
41 #include "third_party/breakpad/src/client/linux/crash_generation/crash_generatio n_client.h"
42 #include "third_party/breakpad/src/client/linux/handler/exception_handler.h"
43 #include "third_party/breakpad/src/client/linux/minidump_writer/directory_reader .h"
44 #include "third_party/breakpad/src/common/linux/linux_libc_support.h"
45 #include "third_party/breakpad/src/common/memory.h"
46 #include "third_party/breakpad/src/common/simple_string_dictionary.h"
47
48 #if defined(OS_ANDROID)
49 #include <android/log.h>
50 #include <sys/stat.h>
51
52 #include "base/android/build_info.h"
53 #include "base/android/path_utils.h"
54 #endif
55 #include "third_party/lss/linux_syscall_support.h"
56
57 #if defined(OS_ANDROID)
58 #define STAT_STRUCT struct stat
59 #define FSTAT_FUNC fstat
60 #else
61 #define STAT_STRUCT struct kernel_stat
62 #define FSTAT_FUNC sys_fstat
63 #endif
64
65 // Some versions of gcc are prone to warn about unused return values. In cases
66 // where we either a) know the call cannot fail, or b) there is nothing we
67 // can do when a call fails, we mark the return code as ignored. This avoids
68 // spurious compiler warnings.
69 #define IGNORE_RET(x) \
70 do { \
71 if (x) \
72 ; \
73 } while (0)
74
75 using google_breakpad::ExceptionHandler;
76 using google_breakpad::MinidumpDescriptor;
77
78 namespace breakpad {
79
80 namespace {
81
82 using CrashKeyStorage = google_breakpad::NonAllocatingMap<256, 256, 64>;
83
84 // BreakpadInfo describes a crash report.
85 // The minidump information can either be contained in a file descriptor (fd) or
86 // in a file (whose path is in filename).
87 struct BreakpadInfo {
88 int fd; // File descriptor to the Breakpad dump data.
89 const char* filename; // Path to the Breakpad dump data.
90 const char* process_type; // Process type, e.g. "renderer".
91 unsigned process_type_length; // Length of |process_type|.
92 const char* distro; // Linux distro string.
93 unsigned distro_length; // Length of |distro|.
94 uint64_t process_start_time; // Uptime of the crashing process.
95 size_t oom_size; // Amount of memory requested if OOM.
96 uint64_t pid; // PID where applicable.
97 CrashKeyStorage* crash_keys;
98 };
99
100 // Define a preferred limit on minidump sizes, because Crash Server currently
101 // throws away any larger than 1.2MB (1.2 * 1024 * 1024). A value of -1 means
102 // no limit.
103 static const off_t kMaxMinidumpFileSize = 1258291;
104 bool g_is_crash_reporter_enabled = false;
105 uint64_t g_process_start_time = 0;
106 pid_t g_pid = 0;
107 ExceptionHandler* g_breakpad = nullptr;
108
109 CrashKeyStorage* g_crash_keys = nullptr;
110
111 #if defined(OS_ANDROID)
112 const char kProductName[] = "Mojo_Android";
113 #else
114 const char kProductName[] = "Mojo";
115 #endif
116 const char kVersion[] = "1.0.0";
117
118 // Writes the value |v| as 16 hex characters to the memory pointed at by
119 // |output|.
120 void write_uint64_hex(char* output, uint64_t v) {
121 static const char hextable[] = "0123456789abcdef";
122
123 for (int i = 15; i >= 0; --i) {
124 output[i] = hextable[v & 15];
125 v >>= 4;
126 }
127 }
128
129 // The following helper functions are for calculating uptime.
130
131 // Converts a struct timeval to milliseconds.
132 uint64_t timeval_to_ms(struct timeval* tv) {
133 uint64_t ret = tv->tv_sec; // Avoid overflow by explicitly using a uint64_t.
134 ret *= 1000;
135 ret += tv->tv_usec / 1000;
136 return ret;
137 }
138
139 // Converts a struct timeval to milliseconds.
140 uint64_t kernel_timeval_to_ms(struct kernel_timeval* tv) {
141 uint64_t ret = tv->tv_sec; // Avoid overflow by explicitly using a uint64_t.
142 ret *= 1000;
143 ret += tv->tv_usec / 1000;
144 return ret;
145 }
146
147 // String buffer size to use to convert a uint64_t to string.
148 const size_t kUint64StringSize = 21;
149
150 void SetProcessStartTime() {
151 // Set the base process start time value.
152 struct timeval tv;
153 if (!gettimeofday(&tv, nullptr))
154 g_process_start_time = timeval_to_ms(&tv);
155 else
156 g_process_start_time = 0;
157 }
158
159 // uint64_t version of my_int_len() from
160 // breakpad/src/common/linux/linux_libc_support.h. Return the length of the
161 // given, non-negative integer when expressed in base 10.
162 unsigned my_uint64_len(uint64_t i) {
163 if (!i)
164 return 1;
165
166 unsigned len = 0;
167 while (i) {
168 len++;
169 i /= 10;
170 }
171
172 return len;
173 }
174
175 // uint64_t version of my_uitos() from
176 // breakpad/src/common/linux/linux_libc_support.h. Convert a non-negative
177 // integer to a string (not null-terminated).
178 void my_uint64tos(char* output, uint64_t i, unsigned i_len) {
179 for (unsigned index = i_len; index; --index, i /= 10)
180 output[index - 1] = '0' + (i % 10);
181 }
182
183 size_t LengthWithoutTrailingSpaces(const char* str, size_t len) {
184 while (len > 0 && str[len - 1] == ' ') {
185 len--;
186 }
187 return len;
188 }
189
190 // MIME substrings.
191 const char g_rn[] = "\r\n";
192 const char g_form_data_msg[] = "Content-Disposition: form-data; name=\"";
193 const char g_quote_msg[] = "\"";
194 const char g_dashdash_msg[] = "--";
195 const char g_dump_msg[] = "upload_file_minidump\"; filename=\"dump\"";
196 const char g_content_type_msg[] = "Content-Type: application/octet-stream";
197
198 // MimeWriter manages an iovec for writing MIMEs to a file.
199 class MimeWriter {
200 public:
201 static const int kIovCapacity = 30;
202 static const size_t kMaxCrashChunkSize = 64;
203
204 MimeWriter(int fd, const char* const mime_boundary);
205 ~MimeWriter();
206
207 // Append boundary.
208 virtual void AddBoundary();
209
210 // Append end of file boundary.
211 virtual void AddEnd();
212
213 // Append key/value pair with specified sizes.
214 virtual void AddPairData(const char* msg_type,
215 size_t msg_type_size,
216 const char* msg_data,
217 size_t msg_data_size);
218
219 // Append key/value pair.
220 void AddPairString(const char* msg_type, const char* msg_data) {
221 AddPairData(msg_type, my_strlen(msg_type), msg_data, my_strlen(msg_data));
222 }
223
224 // Append key/value pair, splitting value into chunks no larger than
225 // |chunk_size|. |chunk_size| cannot be greater than |kMaxCrashChunkSize|.
226 // The msg_type string will have a counter suffix to distinguish each chunk.
227 virtual void AddPairDataInChunks(const char* msg_type,
228 size_t msg_type_size,
229 const char* msg_data,
230 size_t msg_data_size,
231 size_t chunk_size,
232 bool strip_trailing_spaces);
233
234 // Add binary file contents to be uploaded with the specified filename.
235 virtual void AddFileContents(const char* filename_msg,
236 uint8_t* file_data,
237 size_t file_size);
238
239 // Flush any pending iovecs to the output file.
240 void Flush() {
241 IGNORE_RET(sys_writev(fd_, iov_, iov_index_));
242 iov_index_ = 0;
243 }
244
245 protected:
246 void AddItem(const void* base, size_t size);
247 // Minor performance trade-off for easier-to-maintain code.
248 void AddString(const char* str) { AddItem(str, my_strlen(str)); }
249 void AddItemWithoutTrailingSpaces(const void* base, size_t size);
250
251 struct kernel_iovec iov_[kIovCapacity];
252 int iov_index_;
253
254 // Output file descriptor.
255 int fd_;
256
257 const char* const mime_boundary_;
258
259 private:
260 DISALLOW_COPY_AND_ASSIGN(MimeWriter);
261 };
262
263 MimeWriter::MimeWriter(int fd, const char* const mime_boundary)
264 : iov_index_(0), fd_(fd), mime_boundary_(mime_boundary) {
265 }
266
267 MimeWriter::~MimeWriter() {
268 }
269
270 void MimeWriter::AddBoundary() {
271 AddString(mime_boundary_);
272 AddString(g_rn);
273 }
274
275 void MimeWriter::AddEnd() {
276 AddString(mime_boundary_);
277 AddString(g_dashdash_msg);
278 AddString(g_rn);
279 }
280
281 void MimeWriter::AddPairData(const char* msg_type,
282 size_t msg_type_size,
283 const char* msg_data,
284 size_t msg_data_size) {
285 AddString(g_form_data_msg);
286 AddItem(msg_type, msg_type_size);
287 AddString(g_quote_msg);
288 AddString(g_rn);
289 AddString(g_rn);
290 AddItem(msg_data, msg_data_size);
291 AddString(g_rn);
292 }
293
294 void MimeWriter::AddPairDataInChunks(const char* msg_type,
295 size_t msg_type_size,
296 const char* msg_data,
297 size_t msg_data_size,
298 size_t chunk_size,
299 bool strip_trailing_spaces) {
300 if (chunk_size > kMaxCrashChunkSize)
301 return;
302
303 unsigned i = 0;
304 size_t done = 0, msg_length = msg_data_size;
305
306 while (msg_length) {
307 char num[kUint64StringSize];
308 const unsigned num_len = my_uint_len(++i);
309 my_uitos(num, i, num_len);
310
311 size_t chunk_len = std::min(chunk_size, msg_length);
312
313 AddString(g_form_data_msg);
314 AddItem(msg_type, msg_type_size);
315 AddItem(num, num_len);
316 AddString(g_quote_msg);
317 AddString(g_rn);
318 AddString(g_rn);
319 if (strip_trailing_spaces) {
320 AddItemWithoutTrailingSpaces(msg_data + done, chunk_len);
321 } else {
322 AddItem(msg_data + done, chunk_len);
323 }
324 AddString(g_rn);
325 AddBoundary();
326 Flush();
327
328 done += chunk_len;
329 msg_length -= chunk_len;
330 }
331 }
332
333 void MimeWriter::AddFileContents(const char* filename_msg,
334 uint8_t* file_data,
335 size_t file_size) {
336 AddString(g_form_data_msg);
337 AddString(filename_msg);
338 AddString(g_rn);
339 AddString(g_content_type_msg);
340 AddString(g_rn);
341 AddString(g_rn);
342 AddItem(file_data, file_size);
343 AddString(g_rn);
344 }
345
346 void MimeWriter::AddItem(const void* base, size_t size) {
347 // Check if the iovec is full and needs to be flushed to output file.
348 if (iov_index_ == kIovCapacity) {
349 Flush();
350 }
351 iov_[iov_index_].iov_base = const_cast<void*>(base);
352 iov_[iov_index_].iov_len = size;
353 ++iov_index_;
354 }
355
356 void MimeWriter::AddItemWithoutTrailingSpaces(const void* base, size_t size) {
357 AddItem(base,
358 LengthWithoutTrailingSpaces(static_cast<const char*>(base), size));
359 }
360
361 void DumpProcess() {
362 if (g_breakpad)
363 g_breakpad->WriteMinidump();
364 }
365
366 #if defined(OS_ANDROID)
367 const char kGoogleBreakpad[] = "google-breakpad";
368 #endif
369
370 size_t WriteLog(const char* buf, size_t nbytes) {
371 #if defined(OS_ANDROID)
372 return __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, buf);
373 #else
374 return sys_write(2, buf, nbytes);
375 #endif
376 }
377
378 #if defined(OS_ANDROID)
379 void AndroidLogWriteHorizontalRule() {
380 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
381 "### ### ### ### ### ### ### ### ### ### ### ### ###");
382 }
383
384 // Android's native crash handler outputs a diagnostic tombstone to the device
385 // log. By returning false from the HandlerCallbacks, breakpad will reinstall
386 // the previous (i.e. native) signal handlers before returning from its own
387 // handler. A Mojo shell build fingerprint is written to the log, so that the
388 // specific build of the shell and the location of the archived shell symbols
389 // can be determined directly from it.
390 bool FinalizeCrashDoneAndroid() {
391 base::android::BuildInfo* android_build_info =
392 base::android::BuildInfo::GetInstance();
393
394 AndroidLogWriteHorizontalRule();
395 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
396 "Mojo shell build fingerprint:");
397 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
398 android_build_info->package_version_name());
399 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
400 android_build_info->package_version_code());
401 AndroidLogWriteHorizontalRule();
402
403 return false;
404 }
405 #endif
406
407 void LoadDataFromFD(google_breakpad::PageAllocator& allocator,
408 int fd,
409 bool close_fd,
410 uint8_t** file_data,
411 size_t* size) {
412 STAT_STRUCT st;
413 if (FSTAT_FUNC(fd, &st) != 0) {
414 static const char msg[] = "Cannot upload crash dump: stat failed\n";
415 WriteLog(msg, sizeof(msg) - 1);
416 if (close_fd)
417 IGNORE_RET(sys_close(fd));
418 return;
419 }
420
421 *file_data = reinterpret_cast<uint8_t*>(allocator.Alloc(st.st_size));
422 if (!(*file_data)) {
423 static const char msg[] = "Cannot upload crash dump: cannot alloc\n";
424 WriteLog(msg, sizeof(msg) - 1);
425 if (close_fd)
426 IGNORE_RET(sys_close(fd));
427 return;
428 }
429 my_memset(*file_data, 0xf, st.st_size);
430
431 *size = st.st_size;
432 int byte_read = sys_read(fd, *file_data, *size);
433 if (byte_read == -1) {
434 static const char msg[] = "Cannot upload crash dump: read failed\n";
435 WriteLog(msg, sizeof(msg) - 1);
436 if (close_fd)
437 IGNORE_RET(sys_close(fd));
438 return;
439 }
440
441 if (close_fd)
442 IGNORE_RET(sys_close(fd));
443 }
444
445 void LoadDataFromFile(google_breakpad::PageAllocator& allocator,
446 const char* filename,
447 int* fd,
448 uint8_t** file_data,
449 size_t* size) {
450 // WARNING: this code runs in a compromised context. It may not call into
451 // libc nor allocate memory normally.
452 *fd = sys_open(filename, O_RDONLY, 0);
453 *size = 0;
454
455 if (*fd < 0) {
456 static const char msg[] = "Cannot upload crash dump: failed to open\n";
457 WriteLog(msg, sizeof(msg) - 1);
458 return;
459 }
460
461 LoadDataFromFD(allocator, *fd, true, file_data, size);
462 }
463
464 void HandleCrashDump(const BreakpadInfo& info) {
465 int dumpfd;
466 bool keep_fd = false;
467 size_t dump_size;
468 uint8_t* dump_data;
469 google_breakpad::PageAllocator allocator;
470
471 if (info.fd != -1) {
472 // Dump is provided with an open FD.
473 keep_fd = true;
474 dumpfd = info.fd;
475
476 // The FD is pointing to the end of the file.
477 // Rewind, we'll read the data next.
478 if (lseek(dumpfd, 0, SEEK_SET) == -1) {
479 static const char msg[] =
480 "Cannot upload crash dump: failed to "
481 "reposition minidump FD\n";
482 WriteLog(msg, sizeof(msg) - 1);
483 IGNORE_RET(sys_close(dumpfd));
484 return;
485 }
486 LoadDataFromFD(allocator, info.fd, false, &dump_data, &dump_size);
487 } else {
488 // Dump is provided with a path.
489 keep_fd = false;
490 LoadDataFromFile(allocator, info.filename, &dumpfd, &dump_data, &dump_size);
491 }
492
493 // We need to build a MIME block for uploading to the server. Since we are
494 // going to fork and run wget, it needs to be written to a temp file.
495 const int ufd = sys_open("/dev/urandom", O_RDONLY, 0);
496 if (ufd < 0) {
497 static const char msg[] =
498 "Cannot upload crash dump because /dev/urandom"
499 " is missing\n";
500 WriteLog(msg, sizeof(msg) - 1);
501 return;
502 }
503
504 int temp_file_fd = -1;
505 if (keep_fd) {
506 LOG(WARNING) << "Keeping fd...";
507 temp_file_fd = dumpfd;
508 // Rewind the destination, we are going to overwrite it.
509 if (lseek(dumpfd, 0, SEEK_SET) == -1) {
510 static const char msg[] =
511 "Cannot upload crash dump: failed to "
512 "reposition minidump FD (2)\n";
513 WriteLog(msg, sizeof(msg) - 1);
514 IGNORE_RET(sys_close(dumpfd));
515 return;
516 }
517 } else {
518 LOG(WARNING) << "Opening file: " << info.filename;
519 temp_file_fd = sys_open(info.filename, O_WRONLY, 0600);
520 if (temp_file_fd < 0) {
521 static const char msg[] = "Failed to save crash dump: failed to open\n";
522 WriteLog(msg, sizeof(msg) - 1);
523 IGNORE_RET(sys_close(ufd));
524 return;
525 }
526 }
527
528 // The MIME boundary is 28 hyphens, followed by a 64-bit nonce and a NUL.
529 char mime_boundary[28 + 16 + 1];
530 my_memset(mime_boundary, '-', 28);
531 uint64_t boundary_rand;
532 sys_read(ufd, &boundary_rand, sizeof(boundary_rand));
533 write_uint64_hex(mime_boundary + 28, boundary_rand);
534 mime_boundary[28 + 16] = 0;
535 IGNORE_RET(sys_close(ufd));
536
537 // The MIME block looks like this:
538 // BOUNDARY \r\n
539 // Content-Disposition: form-data; name="prod" \r\n \r\n
540 // MojoShell \r\n
541 // BOUNDARY \r\n
542 // Content-Disposition: form-data; name="ver" \r\n \r\n
543 // 1.2.3.4 \r\n
544 // BOUNDARY \r\n
545 //
546 // zero or one:
547 // Content-Disposition: form-data; name="ptime" \r\n \r\n
548 // abcdef \r\n
549 // BOUNDARY \r\n
550 //
551 // zero or one:
552 // Content-Disposition: form-data; name="ptype" \r\n \r\n
553 // abcdef \r\n
554 // BOUNDARY \r\n
555 //
556 // zero or one:
557 // Content-Disposition: form-data; name="lsb-release" \r\n \r\n
558 // abcdef \r\n
559 // BOUNDARY \r\n
560 //
561 // zero or one:
562 // Content-Disposition: form-data; name="oom-size" \r\n \r\n
563 // 1234567890 \r\n
564 // BOUNDARY \r\n
565 //
566 // zero or more (up to CrashKeyStorage::num_entries = 64):
567 // Content-Disposition: form-data; name=crash-key-name \r\n
568 // crash-key-value \r\n
569 // BOUNDARY \r\n
570 //
571 // Content-Disposition: form-data; name="dump"; filename="dump" \r\n
572 // Content-Type: application/octet-stream \r\n \r\n
573 // <dump contents>
574 // \r\n BOUNDARY -- \r\n
575
576 MimeWriter writer(temp_file_fd, mime_boundary);
577 {
578 writer.AddBoundary();
579 writer.AddPairString("prod", kProductName);
580 writer.AddBoundary();
581 writer.AddPairString("ver", kVersion);
582 writer.AddBoundary();
583 if (info.pid > 0) {
584 char pid_value_buf[kUint64StringSize];
585 uint64_t pid_value_len = my_uint64_len(info.pid);
586 my_uint64tos(pid_value_buf, info.pid, pid_value_len);
587 static const char pid_key_name[] = "pid";
588 writer.AddPairData(pid_key_name, sizeof(pid_key_name) - 1, pid_value_buf,
589 pid_value_len);
590 writer.AddBoundary();
591 }
592 #if defined(OS_ANDROID)
593 // Addtional MIME blocks are added for logging on Android devices.
594 static const char android_build_id[] = "android_build_id";
595 static const char android_build_fp[] = "android_build_fp";
596 static const char device[] = "device";
597 static const char model[] = "model";
598 static const char brand[] = "brand";
599 static const char exception_info[] = "exception_info";
600
601 base::android::BuildInfo* android_build_info =
602 base::android::BuildInfo::GetInstance();
603 writer.AddPairString(android_build_id,
604 android_build_info->android_build_id());
605 writer.AddBoundary();
606 writer.AddPairString(android_build_fp,
607 android_build_info->android_build_fp());
608 writer.AddBoundary();
609 writer.AddPairString(device, android_build_info->device());
610 writer.AddBoundary();
611 writer.AddPairString(model, android_build_info->model());
612 writer.AddBoundary();
613 writer.AddPairString(brand, android_build_info->brand());
614 writer.AddBoundary();
615 if (android_build_info->java_exception_info() != nullptr) {
616 writer.AddPairString(exception_info,
617 android_build_info->java_exception_info());
618 writer.AddBoundary();
619 }
620 #endif
621 writer.Flush();
622 }
623
624 if (info.process_start_time > 0) {
625 struct kernel_timeval tv;
626 if (!sys_gettimeofday(&tv, nullptr)) {
627 uint64_t time = kernel_timeval_to_ms(&tv);
628 if (time > info.process_start_time) {
629 time -= info.process_start_time;
630 char time_str[kUint64StringSize];
631 const unsigned time_len = my_uint64_len(time);
632 my_uint64tos(time_str, time, time_len);
633
634 static const char process_time_msg[] = "ptime";
635 writer.AddPairData(process_time_msg, sizeof(process_time_msg) - 1,
636 time_str, time_len);
637 writer.AddBoundary();
638 writer.Flush();
639 }
640 }
641 }
642
643 if (info.process_type_length) {
644 writer.AddPairString("ptype", info.process_type);
645 writer.AddBoundary();
646 writer.Flush();
647 }
648
649 if (info.distro_length) {
650 static const char distro_msg[] = "lsb-release";
651 writer.AddPairString(distro_msg, info.distro);
652 writer.AddBoundary();
653 writer.Flush();
654 }
655
656 if (info.oom_size) {
657 char oom_size_str[kUint64StringSize];
658 const unsigned oom_size_len = my_uint64_len(info.oom_size);
659 my_uint64tos(oom_size_str, info.oom_size, oom_size_len);
660 static const char oom_size_msg[] = "oom-size";
661 writer.AddPairData(oom_size_msg, sizeof(oom_size_msg) - 1, oom_size_str,
662 oom_size_len);
663 writer.AddBoundary();
664 writer.Flush();
665 }
666
667 if (info.crash_keys) {
668 CrashKeyStorage::Iterator crash_key_iterator(*info.crash_keys);
669 const CrashKeyStorage::Entry* entry;
670 while ((entry = crash_key_iterator.Next())) {
671 writer.AddPairString(entry->key, entry->value);
672 writer.AddBoundary();
673 writer.Flush();
674 }
675 }
676
677 writer.AddFileContents(g_dump_msg, dump_data, dump_size);
678 writer.AddEnd();
679 writer.Flush();
680
681 IGNORE_RET(sys_close(temp_file_fd));
682 }
683
684 bool CrashDone(const MinidumpDescriptor& minidump, const bool succeeded) {
685 // WARNING: this code runs in a compromised context. It may not call into
686 // libc nor allocate memory normally.
687 if (!succeeded) {
688 const char msg[] = "Failed to generate minidump.";
689 WriteLog(msg, sizeof(msg) - 1);
690 return false;
691 }
692
693 DCHECK(!minidump.IsFD());
694
695 BreakpadInfo info = {0};
696 info.filename = minidump.path();
697 info.fd = minidump.fd();
698 info.process_type = "shell";
699 info.process_type_length = 7;
700 info.distro = base::g_linux_distro;
701 info.distro_length = my_strlen(base::g_linux_distro);
702 info.process_start_time = g_process_start_time;
703 info.oom_size = base::g_oom_size;
704 info.pid = g_pid;
705 info.crash_keys = g_crash_keys;
706 HandleCrashDump(info);
707 #if defined(OS_ANDROID)
708 return FinalizeCrashDoneAndroid();
709 #else
710 return true;
711 #endif
712 }
713
714 // Wrapper function, do not add more code here.
715 bool CrashDoneNoUpload(const MinidumpDescriptor& minidump,
716 void* context,
717 bool succeeded) {
718 LOG(WARNING) << "CrashDoneNoUpload";
719 return CrashDone(minidump, succeeded);
720 }
721
722 void EnableCrashDumping(const base::FilePath& dumps_path) {
723 g_is_crash_reporter_enabled = true;
724
725 DCHECK(!g_breakpad);
726 DCHECK(base::CreateDirectoryAndGetError(dumps_path, nullptr));
727 MinidumpDescriptor minidump_descriptor(dumps_path.value());
728 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
729 switches::kFullMemoryCrashReport)) {
730 minidump_descriptor.set_size_limit(-1); // unlimited.
731 } else {
732 minidump_descriptor.set_size_limit(kMaxMinidumpFileSize);
733 }
734 g_breakpad = new ExceptionHandler(
735 minidump_descriptor, nullptr, CrashDoneNoUpload, nullptr,
736 true, // Install handlers.
737 -1); // Server file descriptor. -1 for in-process.
738 }
739
740 void SetCrashKeyValue(const base::StringPiece& key,
741 const base::StringPiece& value) {
742 g_crash_keys->SetKeyValue(key.data(), value.data());
743 }
744
745 void ClearCrashKey(const base::StringPiece& key) {
746 g_crash_keys->RemoveKey(key.data());
747 }
748
749 void RegisterCrashKeys() {
750 // TODO(qsr): Is there any key we want to put.
751 }
752
753 void InitCrashKeys() {
754 g_crash_keys = new CrashKeyStorage;
755 RegisterCrashKeys();
756 base::debug::SetCrashKeyReportingFunctions(&SetCrashKeyValue, &ClearCrashKey);
757 }
758
759 // Miscellaneous initialization functions to call after Breakpad has been
760 // enabled.
761 void PostEnableBreakpadInitialization() {
762 SetProcessStartTime();
763 g_pid = getpid();
764
765 base::debug::SetDumpWithoutCrashingFunction(&DumpProcess);
766 }
767
768 } // namespace
769
770 void InitCrashReporter(const base::FilePath& dumps_path) {
771 #if defined(OS_ANDROID)
772 // This will guarantee that the BuildInfo has been initialized and subsequent
773 // calls will not require memory allocation.
774 base::android::BuildInfo::GetInstance();
775 #endif
776 // Determine the process type and take appropriate action.
777 const base::CommandLine& parsed_command_line =
778 *base::CommandLine::ForCurrentProcess();
779 if (parsed_command_line.HasSwitch(switches::kDisableBreakpad))
780 return;
781
782 bool enable_breakpad =
783 !parsed_command_line.HasSwitch(switches::kDisableBreakpad);
784 if (!enable_breakpad) {
785 enable_breakpad =
786 parsed_command_line.HasSwitch(switches::kEnableCrashReporterForTesting);
787 }
788 if (!enable_breakpad) {
789 VLOG(1) << "Breakpad disabled";
790 return;
791 }
792
793 InitCrashKeys();
794 EnableCrashDumping(dumps_path);
795
796 PostEnableBreakpadInitialization();
797 }
798
799 bool IsCrashReporterEnabled() {
800 return g_is_crash_reporter_enabled;
801 }
802
803 } // namespace breakpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698