Index: src/client/linux/microdump_writer/microdump_writer.cc |
diff --git a/src/client/linux/microdump_writer/microdump_writer.cc b/src/client/linux/microdump_writer/microdump_writer.cc |
index 91697ed840f930635c494764cac29ca6dd55b09a..138a2b0d86463b0ab0262253beda5e2c5d336123 100644 |
--- a/src/client/linux/microdump_writer/microdump_writer.cc |
+++ b/src/client/linux/microdump_writer/microdump_writer.cc |
@@ -32,6 +32,7 @@ |
#include "client/linux/microdump_writer/microdump_writer.h" |
Primiano Tucci (use gerrit)
2016/04/07 18:07:39
in general in breakpad client we don't allow anyth
Tobias Sargeant
2016/05/03 13:43:19
Acknowledged.
|
+#include <algorithm> |
#include <sys/utsname.h> |
#include "client/linux/dump_writer_common/thread_info.h" |
@@ -41,6 +42,7 @@ |
#include "client/linux/log/log.h" |
#include "client/linux/minidump_writer/linux_ptrace_dumper.h" |
#include "common/linux/linux_libc_support.h" |
+#include "common/memory.h" |
namespace { |
@@ -93,6 +95,7 @@ class MicrodumpWriter { |
DumpProductInformation(); |
DumpOSInformation(); |
DumpGPUInformation(); |
+ DumpFreeSpace(); |
success = DumpCrashingThread(); |
if (success) |
success = DumpMappings(); |
@@ -376,6 +379,107 @@ class MicrodumpWriter { |
LogCommitLine(); |
} |
+ static bool MappingsAreAdjacent(const MappingInfo *a, const MappingInfo *b) { |
Primiano Tucci (use gerrit)
2016/04/07 18:07:39
should these static functions just be anonymous na
Primiano Tucci (use gerrit)
2016/04/07 18:07:39
nit: * should be close to the type, i.e. MappingIn
|
+ // Because of load biasing, we can end up with a situation where two |
+ // mappings actually overlap. So we will define adjacency to also include a |
+ // b start address that lies within a's address range (including starting |
+ // immediately after a). |
+ // Because load biasing only ever moves the start address backwards, the end |
+ // address should still increase. |
+ return a->start_addr <= b->start_addr && |
+ a->start_addr + a->size >= b->start_addr; |
+ } |
+ |
+ static bool StartAddrLessThan(const MappingInfo *a, const MappingInfo *b) { |
+ return a->start_addr < b->start_addr; |
+ } |
+ |
+ static size_t NextOrderedMapping( |
+ const google_breakpad::wasteful_vector<MappingInfo*>& mappings, |
+ size_t curr) { |
+ size_t best = mappings.size(); |
+ for (size_t next = 0; next < mappings.size(); ++next) { |
+ if (StartAddrLessThan(mappings[curr], mappings[next])) { |
+ if (best == mappings.size() || |
+ StartAddrLessThan(mappings[next], mappings[best])) |
+ best = next; |
+ } |
+ } |
+ return best; |
+ } |
+ |
+ bool DumpFreeSpace() { |
+ const google_breakpad::wasteful_vector<MappingInfo*>& mappings = |
+ dumper_->mappings(); |
+ if (mappings.size() == 0) return false; |
+ |
+ // This is complicated by the fact that mappings is not in order. It should |
+ // be mostly in order, however the mapping that contains the entry point for |
+ // the process is always at the front of the vector. |
+ |
+ static const int HBITS = sizeof(size_t)*8; |
Primiano Tucci (use gerrit)
2016/04/07 18:07:39
nit: space between ) * 8
Tobias Sargeant
2016/05/03 13:43:19
Done.
|
+ int hole_hist[HBITS]; |
+ std::fill(hole_hist, hole_hist + HBITS, 0); |
Primiano Tucci (use gerrit)
2016/04/07 18:07:39
nope, in breakpad we cannot rely on any std lib fu
Tobias Sargeant
2016/05/03 13:43:19
Done.
|
+ |
+ // Find the lowest address mapping. |
+ size_t curr = |
+ std::min_element(mappings.begin(), mappings.end(), StartAddrLessThan) - |
+ mappings.begin(); |
+ |
+ uintptr_t lo_addr = mappings[curr]->start_addr; |
+ |
+ int hole_cnt = 0; |
+ size_t hole_max = 0; |
+ size_t hole_tot = 0; |
+ |
+ while (true) { |
+ // Skip to the end of an adjacent run of mappings. This is an optimization |
+ // for the fact that mappings is mostly sorted. |
+ while (curr != mappings.size() - 1 && |
+ MappingsAreAdjacent(mappings[curr], mappings[curr + 1])) |
+ ++curr; |
+ |
+ size_t next = NextOrderedMapping(mappings, curr); |
+ if (next == mappings.size()) |
+ break; |
+ |
+ uintptr_t hole_lo = mappings[curr]->start_addr + mappings[curr]->size; |
+ uintptr_t hole_hi = mappings[next]->start_addr; |
+ |
+ if (hole_hi > hole_lo) { |
+ size_t hole_sz = hole_hi - hole_lo; |
+ hole_tot += hole_sz; |
+ hole_max = std::max(hole_sz, hole_max); |
+ ++hole_cnt; |
+ size_t h = 0; |
+ while (hole_sz) { |
+ ++h; |
+ hole_sz >>= 1; |
+ } |
+ ++hole_hist[h]; |
+ } |
+ curr = next; |
+ } |
+ |
+ uintptr_t hi_addr = mappings[curr]->start_addr + mappings[curr]->size; |
+ |
+ LogAppend("H "); |
+ LogAppend(lo_addr); |
+ LogAppend(" "); |
+ LogAppend(hi_addr); |
+ |
+ char buf[32]; |
+ snprintf(buf, 32, " %d %0zX %0zX", hole_cnt, hole_max, hole_tot); |
Primiano Tucci (use gerrit)
2016/04/07 18:07:39
no snprintf for same reason. Please use the LogApp
Tobias Sargeant
2016/05/03 13:43:19
Done.
|
+ LogAppend(buf); |
+ for (int i = 0; i < HBITS; ++i) { |
+ if (!hole_hist[i]) continue; |
+ snprintf(buf, 32, " %d:%d", i, hole_hist[i]); |
+ LogAppend(buf); |
+ } |
+ LogCommitLine(); |
+ return true; |
+ } |
+ |
// Write information about the mappings in effect. |
bool DumpMappings() { |
// First write all the mappings from the dumper |