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

Side by Side Diff: src/client/linux/microdump_writer/microdump_writer.cc

Issue 1796803003: Add statistics about free space to microdump format. (Closed) Base URL: https://chromium.googlesource.com/breakpad/breakpad.git@master
Patch Set: Address PS7 comments Created 4 years, 7 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 (c) 2014, Google Inc. 1 // Copyright (c) 2014, Google Inc.
2 // All rights reserved. 2 // All rights reserved.
3 // 3 //
4 // Redistribution and use in source and binary forms, with or without 4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are 5 // modification, are permitted provided that the following conditions are
6 // met: 6 // met:
7 // 7 //
8 // * Redistributions of source code must retain the above copyright 8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer. 9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above 10 // * Redistributions in binary form must reproduce the above
(...skipping 14 matching lines...) Expand all
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 29
30 // This translation unit generates microdumps into the console (logcat on 30 // This translation unit generates microdumps into the console (logcat on
31 // Android). See crbug.com/410294 for more info and design docs. 31 // Android). See crbug.com/410294 for more info and design docs.
32 32
33 #include "client/linux/microdump_writer/microdump_writer.h" 33 #include "client/linux/microdump_writer/microdump_writer.h"
34 34
35 #include <limits>
36
35 #include <sys/utsname.h> 37 #include <sys/utsname.h>
36 38
37 #include <algorithm>
38
39 #include "client/linux/dump_writer_common/thread_info.h" 39 #include "client/linux/dump_writer_common/thread_info.h"
40 #include "client/linux/dump_writer_common/ucontext_reader.h" 40 #include "client/linux/dump_writer_common/ucontext_reader.h"
41 #include "client/linux/handler/exception_handler.h" 41 #include "client/linux/handler/exception_handler.h"
42 #include "client/linux/handler/microdump_extra_info.h" 42 #include "client/linux/handler/microdump_extra_info.h"
43 #include "client/linux/log/log.h" 43 #include "client/linux/log/log.h"
44 #include "client/linux/minidump_writer/linux_ptrace_dumper.h" 44 #include "client/linux/minidump_writer/linux_ptrace_dumper.h"
45 #include "common/linux/file_id.h" 45 #include "common/linux/file_id.h"
46 #include "common/linux/linux_libc_support.h" 46 #include "common/linux/linux_libc_support.h"
47 #include "common/memory.h"
47 48
48 namespace { 49 namespace {
49 50
50 using google_breakpad::auto_wasteful_vector; 51 using google_breakpad::auto_wasteful_vector;
51 using google_breakpad::ExceptionHandler; 52 using google_breakpad::ExceptionHandler;
52 using google_breakpad::kDefaultBuildIdSize; 53 using google_breakpad::kDefaultBuildIdSize;
53 using google_breakpad::LinuxDumper; 54 using google_breakpad::LinuxDumper;
54 using google_breakpad::LinuxPtraceDumper; 55 using google_breakpad::LinuxPtraceDumper;
55 using google_breakpad::MappingInfo; 56 using google_breakpad::MappingInfo;
56 using google_breakpad::MappingList; 57 using google_breakpad::MappingList;
57 using google_breakpad::MicrodumpExtraInfo; 58 using google_breakpad::MicrodumpExtraInfo;
58 using google_breakpad::RawContextCPU; 59 using google_breakpad::RawContextCPU;
59 using google_breakpad::ThreadInfo; 60 using google_breakpad::ThreadInfo;
60 using google_breakpad::UContextReader; 61 using google_breakpad::UContextReader;
61 62
62 const size_t kLineBufferSize = 2048; 63 const size_t kLineBufferSize = 2048;
63 64
65 template <typename Dst, typename Src>
66 Dst saturated_cast(Src src) {
67 if (src >= std::numeric_limits<Dst>::max())
68 return std::numeric_limits<Dst>::max();
69 if (src <= std::numeric_limits<Dst>::min())
70 return std::numeric_limits<Dst>::min();
71 return static_cast<Dst>(src);
72 }
73
74 int Log2Floor(uint64_t n) {
75 // Copied from chromium src/base/bits.h
76 if (n == 0)
77 return -1;
78 int log = 0;
79 uint64_t value = n;
80 for (int i = 5; i >= 0; --i) {
81 int shift = (1 << i);
82 uint64_t x = value >> shift;
83 if (x != 0) {
84 value = x;
85 log += shift;
86 }
87 }
88 assert(value == 1u);
89 return log;
90 }
91
92 bool MappingsAreAdjacent(const MappingInfo& a, const MappingInfo& b) {
93 // Because of load biasing, we can end up with a situation where two
94 // mappings actually overlap. So we will define adjacency to also include a
95 // b start address that lies within a's address range (including starting
96 // immediately after a).
97 // Because load biasing only ever moves the start address backwards, the end
98 // address should still increase.
99 return a.start_addr <= b.start_addr && a.start_addr + a.size >= b.start_addr;
100 }
101
102 bool MappingLessThan(const MappingInfo* a, const MappingInfo* b) {
103 // Return true if mapping a is before mapping b.
104 // For the same reason (load biasing) we compare end addresses, which - unlike
105 // start addresses - will not have been modified.
106 return a->start_addr + a->size < b->start_addr + b->size;
107 }
108
109 size_t NextOrderedMapping(
110 const google_breakpad::wasteful_vector<MappingInfo*>& mappings,
111 size_t curr) {
112 // Find the mapping that directly follows mappings[curr].
113 // If no such mapping exists, return |invalid| to indicate this.
114 const size_t invalid = std::numeric_limits<size_t>::max();
115 size_t best = invalid;
116 for (size_t next = 0; next < mappings.size(); ++next) {
117 if (MappingLessThan(mappings[curr], mappings[next]) &&
118 (best == invalid || MappingLessThan(mappings[next], mappings[best]))) {
119 best = next;
120 }
121 }
122 return best;
123 }
124
64 class MicrodumpWriter { 125 class MicrodumpWriter {
65 public: 126 public:
66 MicrodumpWriter(const ExceptionHandler::CrashContext* context, 127 MicrodumpWriter(const ExceptionHandler::CrashContext* context,
67 const MappingList& mappings, 128 const MappingList& mappings,
68 const MicrodumpExtraInfo& microdump_extra_info, 129 const MicrodumpExtraInfo& microdump_extra_info,
69 LinuxDumper* dumper) 130 LinuxDumper* dumper)
70 : ucontext_(context ? &context->context : NULL), 131 : ucontext_(context ? &context->context : NULL),
71 #if !defined(__ARM_EABI__) && !defined(__mips__) 132 #if !defined(__ARM_EABI__) && !defined(__mips__)
72 float_state_(context ? &context->float_state : NULL), 133 float_state_(context ? &context->float_state : NULL),
73 #endif 134 #endif
(...skipping 17 matching lines...) Expand all
91 return false; 152 return false;
92 return dumper_->ThreadsSuspend() && dumper_->LateInit(); 153 return dumper_->ThreadsSuspend() && dumper_->LateInit();
93 } 154 }
94 155
95 bool Dump() { 156 bool Dump() {
96 bool success; 157 bool success;
97 LogLine("-----BEGIN BREAKPAD MICRODUMP-----"); 158 LogLine("-----BEGIN BREAKPAD MICRODUMP-----");
98 DumpProductInformation(); 159 DumpProductInformation();
99 DumpOSInformation(); 160 DumpOSInformation();
100 DumpGPUInformation(); 161 DumpGPUInformation();
162 #if !defined(__LP64__)
163 DumpFreeSpace();
164 #endif
101 success = DumpCrashingThread(); 165 success = DumpCrashingThread();
102 if (success) 166 if (success)
103 success = DumpMappings(); 167 success = DumpMappings();
104 LogLine("-----END BREAKPAD MICRODUMP-----"); 168 LogLine("-----END BREAKPAD MICRODUMP-----");
105 dumper_->ThreadsResume(); 169 dumper_->ThreadsResume();
106 return success; 170 return success;
107 } 171 }
108 172
109 private: 173 private:
110 // Writes one line to the system log. 174 // Writes one line to the system log.
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after
384 LogAppend(module_identifier.data4[3]); 448 LogAppend(module_identifier.data4[3]);
385 LogAppend(module_identifier.data4[4]); 449 LogAppend(module_identifier.data4[4]);
386 LogAppend(module_identifier.data4[5]); 450 LogAppend(module_identifier.data4[5]);
387 LogAppend(module_identifier.data4[6]); 451 LogAppend(module_identifier.data4[6]);
388 LogAppend(module_identifier.data4[7]); 452 LogAppend(module_identifier.data4[7]);
389 LogAppend("0 "); // Age is always 0 on Linux. 453 LogAppend("0 "); // Age is always 0 on Linux.
390 LogAppend(file_name); 454 LogAppend(file_name);
391 LogCommitLine(); 455 LogCommitLine();
392 } 456 }
393 457
458 #if !defined(__LP64__)
459 void DumpFreeSpace() {
460 const google_breakpad::wasteful_vector<MappingInfo*>& mappings =
461 dumper_->mappings();
462 if (mappings.size() == 0) return;
463
464 // This is complicated by the fact that mappings is not in order. It should
465 // be mostly in order, however the mapping that contains the entry point for
466 // the process is always at the front of the vector.
467
468 static const int HBITS = sizeof(size_t) * 8;
469 size_t hole_histogram[HBITS];
470 my_memset(hole_histogram, 0, sizeof(hole_histogram));
471
472 // Find the lowest address mapping.
473 size_t curr = 0;
474 for (size_t i = 1; i < mappings.size(); ++i) {
475 if (mappings[i]->start_addr < mappings[curr]->start_addr) curr = i;
476 }
477
478 uintptr_t lo_addr = mappings[curr]->start_addr;
479
480 size_t hole_cnt = 0;
481 size_t hole_max = 0;
482 size_t hole_sum = 0;
483
484 while (true) {
485 // Skip to the end of an adjacent run of mappings. This is an optimization
486 // for the fact that mappings is mostly sorted.
487 while (curr != mappings.size() - 1 &&
488 MappingsAreAdjacent(*mappings[curr], *mappings[curr + 1])) {
489 ++curr;
490 }
491
492 size_t next = NextOrderedMapping(mappings, curr);
493 if (next == std::numeric_limits<size_t>::max())
494 break;
495
496 uintptr_t hole_lo = mappings[curr]->start_addr + mappings[curr]->size;
497 uintptr_t hole_hi = mappings[next]->start_addr;
498
499 if (hole_hi > hole_lo) {
500 size_t hole_sz = hole_hi - hole_lo;
501 int log2_hole_sz = Log2Floor(hole_sz);
Primiano Tucci (use gerrit) 2016/05/24 13:23:12 Somebody just reported that this variable is unuse
502 hole_sum += hole_sz;
503 hole_max = std::max(hole_sz, hole_max);
504 ++hole_cnt;
505 ++hole_histogram[Log2Floor(hole_sz)];
506 }
507 curr = next;
508 }
509
510 uintptr_t hi_addr = mappings[curr]->start_addr + mappings[curr]->size;
511
512 LogAppend("H ");
513 LogAppend(lo_addr);
514 LogAppend(" ");
515 LogAppend(hi_addr);
516 LogAppend(" ");
517 LogAppend(saturated_cast<uint16_t>(hole_cnt));
518 LogAppend(" ");
519 LogAppend(hole_max);
520 LogAppend(" ");
521 LogAppend(hole_sum);
522 for (unsigned int i = 0; i < HBITS; ++i) {
523 if (!hole_histogram[i]) continue;
524 LogAppend(" ");
525 LogAppend(saturated_cast<uint8_t>(i));
526 LogAppend(":");
527 LogAppend(saturated_cast<uint8_t>(hole_histogram[i]));
Tobias Sargeant 2016/05/23 10:51:59 And added a saturated cast here too, to simplify t
Primiano Tucci (use gerrit) 2016/05/23 14:15:45 makes sense. thanks.
528 }
529 LogCommitLine();
530 }
531 #endif
532
394 // Write information about the mappings in effect. 533 // Write information about the mappings in effect.
395 bool DumpMappings() { 534 bool DumpMappings() {
396 // First write all the mappings from the dumper 535 // First write all the mappings from the dumper
397 for (unsigned i = 0; i < dumper_->mappings().size(); ++i) { 536 for (unsigned i = 0; i < dumper_->mappings().size(); ++i) {
398 const MappingInfo& mapping = *dumper_->mappings()[i]; 537 const MappingInfo& mapping = *dumper_->mappings()[i];
399 if (mapping.name[0] == 0 || // only want modules with filenames. 538 if (mapping.name[0] == 0 || // only want modules with filenames.
400 !mapping.exec || // only want executable mappings. 539 !mapping.exec || // only want executable mappings.
401 mapping.size < 4096 || // too small to get a signature for. 540 mapping.size < 4096 || // too small to get a signature for.
402 HaveMappingInfo(mapping)) { 541 HaveMappingInfo(mapping)) {
403 continue; 542 continue;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
445 dumper.set_crash_signal(context->siginfo.si_signo); 584 dumper.set_crash_signal(context->siginfo.si_signo);
446 dumper.set_crash_thread(context->tid); 585 dumper.set_crash_thread(context->tid);
447 } 586 }
448 MicrodumpWriter writer(context, mappings, microdump_extra_info, &dumper); 587 MicrodumpWriter writer(context, mappings, microdump_extra_info, &dumper);
449 if (!writer.Init()) 588 if (!writer.Init())
450 return false; 589 return false;
451 return writer.Dump(); 590 return writer.Dump();
452 } 591 }
453 592
454 } // namespace google_breakpad 593 } // namespace google_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