Added some debugging and fixed some bugs.
diff --git a/src/bloaty.cc b/src/bloaty.cc
index 73c47d0..58fb7af 100644
--- a/src/bloaty.cc
+++ b/src/bloaty.cc
@@ -258,6 +258,7 @@
return std::string(symbol);
}
} else {
+ printf("Unexpected source: %d\n", (int)source);
BLOATY_UNREACHABLE();
}
}
@@ -867,12 +868,12 @@
outputs_.push_back(std::make_pair(map, munger));
}
-void RangeSink::AddFileRange(string_view name, uint64_t fileoff,
- uint64_t filesize) {
+void RangeSink::AddFileRange(const char* analyzer, string_view name,
+ uint64_t fileoff, uint64_t filesize) {
if (verbose_level > 2) {
- fprintf(stdout, "[%s] AddFileRange(%.*s, %" PRIx64 ", %" PRIx64 ")\n",
- GetDataSourceLabel(data_source_), (int)name.size(), name.data(),
- fileoff, filesize);
+ fprintf(stdout, "[%s, %s] AddFileRange(%.*s, %" PRIx64 ", %" PRIx64 ")\n",
+ GetDataSourceLabel(data_source_), analyzer, (int)name.size(),
+ name.data(), fileoff, filesize);
}
for (auto& pair : outputs_) {
const std::string label = pair.second->Munge(name);
@@ -885,14 +886,16 @@
}
}
-void RangeSink::AddFileRangeFor(uint64_t label_from_vmaddr,
+void RangeSink::AddFileRangeFor(const char* analyzer,
+ uint64_t label_from_vmaddr,
string_view file_range) {
uint64_t file_offset = file_range.data() - file_->data().data();
if (verbose_level > 2) {
fprintf(stdout,
- "[%s] AddFileRangeFor(%" PRIx64 ", [%" PRIx64 ", %" PRIx64 "])\n",
- GetDataSourceLabel(data_source_), label_from_vmaddr, file_offset,
- file_range.size());
+ "[%s, %s] AddFileRangeFor(%" PRIx64 ", [%" PRIx64 ", %" PRIx64
+ "])\n",
+ GetDataSourceLabel(data_source_), analyzer, label_from_vmaddr,
+ file_offset, file_range.size());
}
assert(translator_);
for (auto& pair : outputs_) {
@@ -908,14 +911,13 @@
}
}
-void RangeSink::AddVMRangeFor(uint64_t label_from_vmaddr, uint64_t addr,
- uint64_t size) {
+void RangeSink::AddVMRangeFor(const char* analyzer, uint64_t label_from_vmaddr,
+ uint64_t addr, uint64_t size) {
if (verbose_level > 2) {
fprintf(stdout,
- "[%s] AddVMRangeFor(%" PRIx64 ", [%" PRIx64 ", %" PRIx64 "])\n",
- GetDataSourceLabel(data_source_), label_from_vmaddr, addr, size);
- fprintf(stdout, "Translation map:\n%s",
- translator_->file_map.DebugString().c_str());
+ "[%s, %s] AddVMRangeFor(%" PRIx64 ", [%" PRIx64 ", %" PRIx64 "])\n",
+ GetDataSourceLabel(data_source_), analyzer, label_from_vmaddr, addr,
+ size);
}
assert(translator_);
for (auto& pair : outputs_) {
@@ -930,12 +932,12 @@
}
}
-void RangeSink::AddVMRange(uint64_t vmaddr, uint64_t vmsize,
- const std::string& name) {
+void RangeSink::AddVMRange(const char* analyzer, uint64_t vmaddr,
+ uint64_t vmsize, const std::string& name) {
if (verbose_level > 2) {
- fprintf(stdout, "[%s] AddVMRange(%.*s, %" PRIx64 ", %" PRIx64 ")\n",
- GetDataSourceLabel(data_source_), (int)name.size(), name.data(),
- vmaddr, vmsize);
+ fprintf(stdout, "[%s, %s] AddVMRange(%.*s, %" PRIx64 ", %" PRIx64 ")\n",
+ GetDataSourceLabel(data_source_), analyzer, (int)name.size(),
+ name.data(), vmaddr, vmsize);
}
assert(translator_);
for (auto& pair : outputs_) {
@@ -945,26 +947,29 @@
}
}
-void RangeSink::AddVMRangeAllowAlias(uint64_t vmaddr, uint64_t size,
- const std::string& name) {
+void RangeSink::AddVMRangeAllowAlias(const char* analyzer, uint64_t vmaddr,
+ uint64_t size, const std::string& name) {
// TODO: maybe track alias (but what would we use it for?)
// TODO: verify that it is in fact an alias.
- AddVMRange(vmaddr, size, name);
+ AddVMRange(analyzer, vmaddr, size, name);
}
-void RangeSink::AddVMRangeIgnoreDuplicate(uint64_t vmaddr, uint64_t vmsize,
+void RangeSink::AddVMRangeIgnoreDuplicate(const char* analyzer, uint64_t vmaddr,
+ uint64_t vmsize,
const std::string& name) {
// TODO suppress warning that AddVMRange alone might trigger.
- AddVMRange(vmaddr, vmsize, name);
+ AddVMRange(analyzer, vmaddr, vmsize, name);
}
-void RangeSink::AddRange(string_view name, uint64_t vmaddr, uint64_t vmsize,
- uint64_t fileoff, uint64_t filesize) {
+void RangeSink::AddRange(const char* analyzer, string_view name,
+ uint64_t vmaddr, uint64_t vmsize, uint64_t fileoff,
+ uint64_t filesize) {
if (verbose_level > 2) {
- fprintf(stdout, "[%s] AddRange(%.*s, %" PRIx64 ", %" PRIx64 ", %" PRIx64
+ fprintf(stdout,
+ "[%s, %s] AddRange(%.*s, %" PRIx64 ", %" PRIx64 ", %" PRIx64
", %" PRIx64 ")\n",
- GetDataSourceLabel(data_source_), (int)name.size(), name.data(),
- vmaddr, vmsize, fileoff, filesize);
+ GetDataSourceLabel(data_source_), analyzer, (int)name.size(),
+ name.data(), vmaddr, vmsize, fileoff, filesize);
}
for (auto& pair : outputs_) {
const std::string label = pair.second->Munge(name);
@@ -1106,6 +1111,7 @@
}
void ScanAndRollupFiles(const std::vector<std::unique_ptr<ObjectFile>>& files,
+ std::vector<std::string>* build_ids,
Rollup* rollup) const;
void ScanAndRollupFile(ObjectFile* file, Rollup* rollup,
std::string* out_build_id) const;
@@ -1333,11 +1339,13 @@
for (auto sink : filename_sink_ptrs) {
maps.base_map()->vm_map.ForEachRange(
[sink](uint64_t start, uint64_t length) {
- sink->AddVMRange(start, length, sink->input_file().filename());
+ sink->AddVMRange("inputfile_vmcopier", start, length,
+ sink->input_file().filename());
});
maps.base_map()->file_map.ForEachRange(
[sink](uint64_t start, uint64_t length) {
- sink->AddFileRange(sink->input_file().filename(), start, length);
+ sink->AddFileRange("inputfile_filecopier",
+ sink->input_file().filename(), start, length);
});
}
@@ -1349,13 +1357,14 @@
RangeSink* from = sinks[i - 1].get();
from->MapAtIndex(0).vm_map.ForEachRange([ranges_sink](uint64_t start,
uint64_t length) {
- ranges_sink->AddVMRange(start, length,
+ ranges_sink->AddVMRange("rawrange_vmcopier", start, length,
absl::StrCat("vm: [", absl::Hex(start), ", ",
absl::Hex(start + length), "]"));
});
from->MapAtIndex(0).file_map.ForEachRange(
[ranges_sink](uint64_t start, uint64_t length) {
ranges_sink->AddFileRange(
+ "rawrange_filecopier",
absl::StrCat("file: [", absl::Hex(start), ", ",
absl::Hex(start + length), "]"),
start, length);
@@ -1380,7 +1389,8 @@
void Bloaty::ScanAndRollupFiles(
const std::vector<std::unique_ptr<ObjectFile>>& files,
- Rollup* rollup) const {
+ std::vector<std::string>* build_ids,
+ Rollup * rollup) const {
int num_cpus = std::thread::hardware_concurrency();
int num_threads = std::min(num_cpus, static_cast<int>(files.size()));
@@ -1406,14 +1416,6 @@
}, &thread_data[i]);
}
- // Create a copy of the debug_files_ member, so we can determine which (if
- // any) debug files weren't used. We copy it because we are in a const method
- // so can't mutate debug_files_ directly.
- std::map<std::string, const ObjectFile*> debug_files;
- for (const auto& pair : debug_files_) {
- debug_files[pair.first] = pair.second.get();
- }
-
for (int i = 0; i < num_threads; i++) {
threads[i].join();
PerThreadData* data = &thread_data[i];
@@ -1424,7 +1426,7 @@
}
if (!data->build_id.empty()) {
- debug_files.erase(data->build_id);
+ build_ids->push_back(data->build_id);
}
}
@@ -1432,26 +1434,6 @@
if (index.TryGetError(&error)) {
THROW(error.c_str());
}
-
- if (!debug_files.empty()) {
- std::string unused_debug;
- for (const auto& pair : debug_files) {
- unused_debug += absl::Substitute(
- "$0 $1\n",
- absl::BytesToHexString(pair.second->GetBuildId()).c_str(),
- pair.second->file_data().filename().c_str());
- }
-
- std::string input_files;
- for (const auto& file : files) {
- input_files += absl::Substitute(
- "$0 $1\n", absl::BytesToHexString(file->GetBuildId()).c_str(),
- file->file_data().filename().c_str());
- }
- THROWF(
- "Debug file(s) did not match any input file:\n$0\nInput Files:\n$1",
- unused_debug.c_str(), input_files.c_str());
- }
}
void Bloaty::ScanAndRollup(const Options& options, RollupOutput* output) {
@@ -1464,16 +1446,47 @@
}
Rollup rollup;
- ScanAndRollupFiles(input_files_, &rollup);
+ std::vector<std::string> build_ids;
+ ScanAndRollupFiles(input_files_, &build_ids, &rollup);
if (!base_files_.empty()) {
Rollup base;
- ScanAndRollupFiles(base_files_, &base);
+ ScanAndRollupFiles(base_files_, &build_ids, &base);
rollup.Subtract(base);
rollup.CreateDiffModeRollupOutput(&base, options, output);
} else {
rollup.CreateRollupOutput(options, output);
}
+
+ for (const auto& build_id : build_ids) {
+ debug_files_.erase(build_id);
+ }
+
+ // Error out if some --debug-files were not used.
+ if (!debug_files_.empty()) {
+ std::string input_files;
+ std::string unused_debug;
+ for (const auto& pair : debug_files_) {
+ unused_debug += absl::Substitute(
+ "$0 $1\n",
+ absl::BytesToHexString(pair.second->GetBuildId()).c_str(),
+ pair.second->file_data().filename().c_str());
+ }
+
+ for (const auto& file : input_files_) {
+ input_files += absl::Substitute(
+ "$0 $1\n", absl::BytesToHexString(file->GetBuildId()).c_str(),
+ file->file_data().filename().c_str());
+ }
+ for (const auto& file : base_files_) {
+ input_files += absl::Substitute(
+ "$0 $1\n", absl::BytesToHexString(file->GetBuildId()).c_str(),
+ file->file_data().filename().c_str());
+ }
+ THROWF(
+ "Debug file(s) did not match any input file:\n$0\nInput Files:\n$1",
+ unused_debug.c_str(), input_files.c_str());
+ }
}
void Bloaty::DisassembleFunction(string_view function, const Options& options,
diff --git a/src/bloaty.h b/src/bloaty.h
index 78fc557..8e36592 100644
--- a/src/bloaty.h
+++ b/src/bloaty.h
@@ -146,26 +146,28 @@
// If vmsize or filesize is zero, this mapping is presumed not to exist in
// that domain. For example, .bss mappings don't exist in the file, and
// .debug_* mappings don't exist in memory.
- void AddRange(absl::string_view name, uint64_t vmaddr, uint64_t vmsize,
- uint64_t fileoff, uint64_t filesize);
+ void AddRange(const char* analyzer, absl::string_view name, uint64_t vmaddr,
+ uint64_t vmsize, uint64_t fileoff, uint64_t filesize);
- void AddRange(absl::string_view name, uint64_t vmaddr, uint64_t vmsize,
- absl::string_view file_range) {
- AddRange(name, vmaddr, vmsize, file_range.data() - file_->data().data(),
- file_range.size());
+ void AddRange(const char* analyzer, absl::string_view name, uint64_t vmaddr,
+ uint64_t vmsize, absl::string_view file_range) {
+ AddRange(analyzer, name, vmaddr, vmsize,
+ file_range.data() - file_->data().data(), file_range.size());
}
- void AddFileRange(absl::string_view name,
+ void AddFileRange(const char* analyzer, absl::string_view name,
uint64_t fileoff, uint64_t filesize);
// Like AddFileRange(), but the label is whatever label was previously
// assigned to VM address |label_from_vmaddr|. If no existing label is
// assigned to |label_from_vmaddr|, this function does nothing.
- void AddFileRangeFor(uint64_t label_from_vmaddr,
+ void AddFileRangeFor(const char* analyzer, uint64_t label_from_vmaddr,
absl::string_view file_range);
- void AddVMRangeFor(uint64_t label_from_vmaddr, uint64_t addr, uint64_t size);
+ void AddVMRangeFor(const char* analyzer, uint64_t label_from_vmaddr,
+ uint64_t addr, uint64_t size);
- void AddFileRange(absl::string_view name, absl::string_view file_range) {
+ void AddFileRange(const char* analyzer, absl::string_view name,
+ absl::string_view file_range) {
// When separate debug files are being used, the DWARF analyzer will try to
// add sections of the debug file. We want to prevent this because we only
// want to profile the main file (not the debug file), so we filter these
@@ -173,7 +175,7 @@
// useless work being done. We may want to avoid doing this useless work in
// the first place.
if (FileContainsPointer(file_range.data())) {
- AddFileRange(name, file_range.data() - file_->data().data(),
+ AddFileRange(analyzer, name, file_range.data() - file_->data().data(),
file_range.size());
}
}
@@ -182,7 +184,8 @@
// Adds a region to the memory map. It should not overlap any previous
// region added with Add(), but it should overlap the base memory map.
- void AddVMRange(uint64_t vmaddr, uint64_t vmsize, const std::string& name);
+ void AddVMRange(const char* analyzer, uint64_t vmaddr, uint64_t vmsize,
+ const std::string& name);
// Like Add(), but allows that this addr/size might have previously been added
// already under a different name. If so, this name becomes an alias of the
@@ -190,8 +193,8 @@
//
// This is for things like symbol tables that sometimes map multiple names to
// the same physical function.
- void AddVMRangeAllowAlias(uint64_t vmaddr, uint64_t size,
- const std::string& name);
+ void AddVMRangeAllowAlias(const char* analyzer, uint64_t vmaddr,
+ uint64_t size, const std::string& name);
// Like Add(), but allows that this addr/size might have previously been added
// already under a different name. If so, this add is simply ignored.
@@ -200,8 +203,8 @@
// come from multiple source files. But if it does, we don't want to alias
// the entire source file to another, because it's probably only part of the
// source file that overlaps.
- void AddVMRangeIgnoreDuplicate(uint64_t vmaddr, uint64_t size,
- const std::string& name);
+ void AddVMRangeIgnoreDuplicate(const char* analyzer, uint64_t vmaddr,
+ uint64_t size, const std::string& name);
const DualMap& MapAtIndex(size_t index) const {
return *outputs_[index].first;
diff --git a/src/disassemble.cc b/src/disassemble.cc
index 4b65876..f0a0365 100644
--- a/src/disassemble.cc
+++ b/src/disassemble.cc
@@ -80,7 +80,8 @@
op->mem.index == X86_REG_INVALID) {
uint64_t to_address = in->address + in->size + op->mem.disp;
if (to_address) {
- sink->AddVMRangeFor(in->address, to_address, RangeSink::kUnknownSize);
+ sink->AddVMRangeFor("x86_disassemble", in->address, to_address,
+ RangeSink::kUnknownSize);
}
}
}
diff --git a/src/dwarf.cc b/src/dwarf.cc
index 7e89a60..541277e 100644
--- a/src/dwarf.cc
+++ b/src/dwarf.cc
@@ -592,7 +592,7 @@
void AddIndirectString(string_view range) const {
if (strp_sink_) {
- strp_sink_->AddFileRange(unit_name_, range);
+ strp_sink_->AddFileRange("dwarf_strp", unit_name_, range);
}
}
@@ -1851,8 +1851,8 @@
std::string filename = map.GetFilename(ranges.debug_info_offset());
while (ranges.NextRange()) {
- sink->AddVMRangeIgnoreDuplicate(ranges.address(), ranges.length(),
- filename);
+ sink->AddVMRangeIgnoreDuplicate("dwarf_aranges", ranges.address(),
+ ranges.length(), filename);
}
}
@@ -1876,7 +1876,7 @@
if (high_pc > low_pc) {
high_pc -= low_pc;
}
- sink->AddVMRangeIgnoreDuplicate(low_pc, high_pc, name);
+ sink->AddVMRangeIgnoreDuplicate("dwarf_pcpair", low_pc, high_pc, name);
}
// Sometimes a DIE has a linkage_name, which we can look up in the symbol
@@ -1884,8 +1884,8 @@
if (attr.HasAttribute<1>()) {
auto it = symtab.find(attr.GetAttribute<1>());
if (it != symtab.end()) {
- sink->AddVMRangeIgnoreDuplicate(it->second.first, it->second.second,
- name);
+ sink->AddVMRangeIgnoreDuplicate("dwarf_linkagename", it->second.first,
+ it->second.second, name);
}
}
@@ -1910,7 +1910,7 @@
// up in the symbol map.
uint64_t size;
if (symbol_map.vm_map.TryGetSize(addr, &size)) {
- sink->AddVMRangeIgnoreDuplicate(addr, size, name);
+ sink->AddVMRangeIgnoreDuplicate("dwarf_location", addr, size, name);
} else {
if (verbose_level > 0) {
fprintf(stderr,
@@ -1925,7 +1925,7 @@
if (attr.HasAttribute<5>()) {
absl::string_view loc_range = file.debug_loc.substr(attr.GetAttribute<5>());
loc_range = GetLocationListRange(sizes, loc_range);
- sink->AddFileRange(name, loc_range);
+ sink->AddFileRange("dwarf_locrange", name, loc_range);
}
uint64_t ranges_offset = UINT64_MAX;
@@ -1939,7 +1939,7 @@
if (ranges_offset != UINT64_MAX) {
absl::string_view ranges_range = file.debug_ranges.substr(ranges_offset);
ranges_range = GetRangeListRange(sizes, ranges_range);
- sink->AddFileRange(name, ranges_range);
+ sink->AddFileRange("dwarf_debugrange", name, ranges_range);
}
}
@@ -1965,7 +1965,7 @@
attr_reader.ReadAttributes(&die_reader);
std::string compileunit_name = std::string(attr_reader.GetAttribute<0>());
if (!compileunit_name.empty()) {
- sink->AddFileRange(compileunit_name, full_unit);
+ sink->AddFileRange("dwarf_pubnames", compileunit_name, full_unit);
}
}
}
@@ -2078,6 +2078,7 @@
uint8_t fde_encoding = 0;
uint8_t lsda_encoding = 0;
bool is_signal_handler = false;
+ bool has_augmentation_length = false;
uint64_t personality_function = 0;
uint32_t return_address_reg = 0;
};
@@ -2115,6 +2116,7 @@
switch (aug_string[0]) {
case 'z':
// Length until the end of augmentation data.
+ cie_info.has_augmentation_length = true;
dwarf::ReadLEB128<uint32_t>(&entry);
break;
case 'L':
@@ -2148,9 +2150,23 @@
nullptr, sink);
// TODO(haberman); Technically the FDE addresses could span a
// function/compilation unit? They can certainly span inlines.
- // uint64_t length =
- // ReadEncodedPointer(cie_info.fde_encoding & 0xf, true, &entry, sink);
- sink->AddFileRangeFor(address, full_entry);
+ /*
+ uint64_t length =
+ ReadEncodedPointer(cie_info.fde_encoding & 0xf, true, &entry, sink);
+ (void)length;
+
+ if (cie_info.has_augmentation_length) {
+ uint32_t augmentation_length = dwarf::ReadLEB128<uint32_t>(&entry);
+ (void)augmentation_length;
+ }
+
+ uint64_t lsda =
+ ReadEncodedPointer(cie_info.lsda_encoding, true, &entry, sink);
+ if (lsda) {
+ }
+ */
+
+ sink->AddFileRangeFor("dwarf_fde", address, full_entry);
}
}
}
@@ -2181,7 +2197,7 @@
ReadEncodedPointer(table_enc, true, &data, base, sink);
uint64_t fde_addr = ReadEncodedPointer(table_enc, true, &data, base, sink);
entry_data.remove_suffix(data.size());
- sink->AddFileRangeFor(initial_location, entry_data);
+ sink->AddFileRangeFor("dwarf_fde_table", initial_location, entry_data);
// We could add fde_addr with an unknown length if we wanted to skip reading
// eh_frame. We can't count on this table being available though, so we
@@ -2199,7 +2215,7 @@
data = sizes.ReadInitialLength(&data);
data = data_with_length.substr(
0, data.size() + (data.data() - data_with_length.data()));
- sink->AddFileRange(unit_name, data);
+ sink->AddFileRange("dwarf_stmtlistrange", unit_name, data);
}
// The DWARF debug info can help us get compileunits info. DIEs for compilation
@@ -2243,7 +2259,8 @@
}
die_reader.set_compileunit_name(compileunit_name);
- sink->AddFileRange(compileunit_name, die_reader.unit_range());
+ sink->AddFileRange("dwarf_debuginfo", compileunit_name,
+ die_reader.unit_range());
AddDIE(file, compileunit_name, attr_reader, symtab, symbol_map,
die_reader.unit_sizes(), sink);
@@ -2256,7 +2273,7 @@
dwarf::SkipBytes(die_reader.debug_abbrev_offset(), &abbrev_data);
dwarf::AbbrevTable unit_abbrev;
abbrev_data = unit_abbrev.ReadAbbrevs(abbrev_data);
- sink->AddFileRange(compileunit_name, abbrev_data);
+ sink->AddFileRange("dwarf_abbrev", compileunit_name, abbrev_data);
while (die_reader.NextDIE()) {
attr_reader.ReadAttributes(&die_reader);
@@ -2313,7 +2330,8 @@
span_startaddr = addr;
} else if (line_info.end_sequence ||
(!last_source.empty() && name != last_source)) {
- sink->AddVMRange(span_startaddr, addr - span_startaddr, last_source);
+ sink->AddVMRange("dwarf_stmtlist", span_startaddr, addr - span_startaddr,
+ last_source);
if (line_info.end_sequence) {
span_startaddr = 0;
} else {
diff --git a/src/elf.cc b/src/elf.cc
index 13075df..6c502da 100644
--- a/src/elf.cc
+++ b/src/elf.cc
@@ -720,9 +720,10 @@
return true;
}
-void MaybeAddFileRange(RangeSink* sink, string_view label, string_view range) {
+void MaybeAddFileRange(const char* analyzer, RangeSink* sink, string_view label,
+ string_view range) {
if (sink) {
- sink->AddFileRange(label, range);
+ sink->AddFileRange(analyzer, label, range);
}
}
@@ -737,10 +738,10 @@
ArFile::MemberFile member;
ArFile::MemberReader reader(ar_file);
- MaybeAddFileRange(sink, "[AR Headers]", ar_file.magic());
+ MaybeAddFileRange("ar_archive", sink, "[AR Headers]", ar_file.magic());
while (reader.ReadMember(&member)) {
- MaybeAddFileRange(sink, "[AR Headers]", member.header);
+ MaybeAddFileRange("ar_archive", sink, "[AR Headers]", member.header);
switch (member.file_type) {
case ArFile::MemberFile::kNormal: {
ElfFile elf(member.contents);
@@ -748,16 +749,18 @@
func(elf, member.filename, index_base);
index_base += elf.section_count();
} else {
- MaybeAddFileRange(sink, "[AR Non-ELF Member File]",
+ MaybeAddFileRange("ar_archive", sink, "[AR Non-ELF Member File]",
member.contents);
}
break;
}
case ArFile::MemberFile::kSymbolTable:
- MaybeAddFileRange(sink, "[AR Symbol Table]", member.contents);
+ MaybeAddFileRange("ar_archive", sink, "[AR Symbol Table]",
+ member.contents);
break;
case ArFile::MemberFile::kLongFilenameTable:
- MaybeAddFileRange(sink, "[AR Headers]", member.contents);
+ MaybeAddFileRange("ar_archive", sink, "[AR Headers]",
+ member.contents);
break;
}
}
@@ -803,9 +806,64 @@
}
}
+static void ElfMachineToCapstone(Elf64_Half e_machine, cs_arch* arch,
+ cs_mode* mode) {
+ switch (e_machine) {
+ case EM_386:
+ *arch = CS_ARCH_X86;
+ *mode = CS_MODE_32;
+ break;
+ case EM_X86_64:
+ *arch = CS_ARCH_X86;
+ *mode = CS_MODE_64;
+ break;
+
+ // These aren't tested, but we include them on the off-chance
+ // that it will work.
+ case EM_ARM:
+ *arch = CS_ARCH_ARM;
+ *mode = CS_MODE_LITTLE_ENDIAN;
+ break;
+ case EM_MIPS:
+ *arch = CS_ARCH_MIPS;
+ break;
+ case EM_PPC:
+ *arch = CS_ARCH_PPC;
+ *mode = CS_MODE_32;
+ break;
+ case EM_PPC64:
+ *arch = CS_ARCH_PPC;
+ *mode = CS_MODE_64;
+ break;
+ case EM_SPARC:
+ *arch = CS_ARCH_SPARC;
+ *mode = CS_MODE_BIG_ENDIAN;
+ break;
+ case EM_SPARCV9:
+ *arch = CS_ARCH_SPARC;
+ *mode = CS_MODE_V9;
+ break;
+ default:
+ THROWF("Unknown ELF machine value: $0'", e_machine);
+ }
+}
+
+static void ReadElfArchMode(const InputFile& file, cs_arch* arch, cs_mode* mode) {
+ ForEachElf(file, nullptr,
+ [=](const ElfFile& elf, string_view /*filename*/,
+ uint32_t /*index_base*/) {
+ // Last .o file wins? (For .a files)? It's kind of arbitrary,
+ // but a single .a file shouldn't have multiple archs in it.
+ ElfMachineToCapstone(elf.header().e_machine, arch, mode);
+ });
+}
+
static void ReadELFSymbols(const InputFile& file, RangeSink* sink,
- SymbolTable* table) {
+ SymbolTable* table, bool disassemble) {
bool is_object = IsObjectFile(file.data());
+ DisassemblyInfo info;
+ DisassemblyInfo* infop = &info;
+ ReadElfArchMode(file, &info.arch, &info.mode);
ForEachElf(
file, sink,
@@ -849,15 +907,23 @@
string_view name = strtab_section.ReadString(sym.st_name);
uint64_t full_addr =
ToVMAddr(sym.st_value, index_base + sym.st_shndx, is_object);
- if (sink) {
+ if (sink && !disassemble) {
sink->AddVMRangeAllowAlias(
- full_addr, sym.st_size,
+ "elf_symbols", full_addr, sym.st_size,
ItaniumDemangle(name, sink->data_source()));
}
if (table) {
table->insert(
std::make_pair(name, std::make_pair(full_addr, sym.st_size)));
}
+ if (disassemble && ELF64_ST_TYPE(sym.st_info) == STT_FUNC) {
+ if (verbose_level > 1) {
+ printf("Disassembling function: %s\n", name.data());
+ }
+ infop->text = sink->TranslateVMToFile(full_addr).substr(0, sym.st_size);
+ infop->start_address = full_addr;
+ DisassembleFindReferences(*infop, sink);
+ }
}
}
});
@@ -893,8 +959,8 @@
ToVMAddr(sym.st_value, index_base + sym.st_shndx, is_object);
// Capture the trailing NULL.
name = string_view(name.data(), name.size() + 1);
- sink->AddFileRangeFor(full_addr, name);
- sink->AddFileRangeFor(full_addr, sym_range);
+ sink->AddFileRangeFor("elf_symtab_name", full_addr, name);
+ sink->AddFileRangeFor("elf_symtab_sym", full_addr, sym_range);
}
}
@@ -909,7 +975,7 @@
// TODO(haberman): fix this for object files.
uint64_t full_addr = ToVMAddr(rela.r_offset, index_base, is_object);
full_addr = rela.r_offset;
- sink->AddFileRangeFor(full_addr, rela_range);
+ sink->AddFileRangeFor("elf_rela", full_addr, rela_range);
}
}
@@ -925,38 +991,7 @@
// Disassemble first, because sometimes other tables will refer to things we
// discovered through disassembling.
- ForEachElf(
- file, sink,
- [&file, info, sink, is_object](const ElfFile& elf,
- string_view /*filename*/,
- uint32_t /*index_base*/) {
- for (Elf64_Xword i = 1; i < elf.section_count(); i++) {
- ElfFile::Section section;
- elf.ReadSection(i, §ion);
-
- if (section.header().sh_flags & SHF_EXECINSTR) {
- // Use symbols to find functions in this executable section.
- // Unfortunately we can't just disassemble the entire section
- // because sometimes the padding between functions contains garbage
- // (invalid instructions).
- string_view filedata = file.data();
- uint64_t offset = section.contents().data() - file.data().data();
- uint64_t limit = offset + section.contents().size();
- uint64_t vmbase = section.header().sh_addr - offset;
- info->symbol_map.file_map.ForEachRangeWithStart(
- offset, [limit, vmbase, filedata, info, sink](uint64_t start,
- uint64_t length) {
- if (start >= limit) {
- return false;
- }
- info->text = StrictSubstr(filedata, start, length);
- info->start_address = vmbase + start;
- DisassembleFindReferences(*info, sink);
- return true;
- });
- }
- }
- });
+ ReadELFSymbols(file, sink, nullptr, true);
// Now scan other tables.
ForEachElf(
@@ -1042,20 +1077,23 @@
}
name_from_flags += ']';
- sink->AddRange(name_from_flags, full_addr, vmsize, contents);
+ sink->AddRange("elf_section", name_from_flags, full_addr, vmsize,
+ contents);
} else if (report_by == kReportBySectionName) {
- sink->AddRange(name, full_addr, vmsize, contents);
+ sink->AddRange("elf_section", name, full_addr, vmsize, contents);
} else if (report_by == kReportByEscapedSectionName) {
- sink->AddRange(std::string("[section ") + std::string(name) + "]",
+ sink->AddRange("elf_section",
+ std::string("[section ") + std::string(name) + "]",
full_addr, vmsize, contents);
} else if (report_by == kReportByArchiveMember) {
- sink->AddRange(filename, full_addr, vmsize, contents);
+ sink->AddRange("elf_section", filename, full_addr, vmsize,
+ contents);
}
}
if (report_by == kReportByArchiveMember) {
// Cover unmapped parts of the file.
- sink->AddFileRange(filename, elf.entire_file());
+ sink->AddFileRange("unmapped_armember", filename, elf.entire_file());
}
});
}
@@ -1098,8 +1136,8 @@
name = absl::StrCat("[", name, "]");
}
- sink->AddRange(name, header.p_vaddr, header.p_memsz,
- segment.contents());
+ sink->AddRange("elf_segment", name, header.p_vaddr,
+ header.p_memsz, segment.contents());
}
});
}
@@ -1154,73 +1192,23 @@
}
}
-static void ElfMachineToCapstone(Elf64_Half e_machine, cs_arch* arch,
- cs_mode* mode) {
- switch (e_machine) {
- case EM_386:
- *arch = CS_ARCH_X86;
- *mode = CS_MODE_32;
- break;
- case EM_X86_64:
- *arch = CS_ARCH_X86;
- *mode = CS_MODE_64;
- break;
-
- // These aren't tested, but we include them on the off-chance
- // that it will work.
- case EM_ARM:
- *arch = CS_ARCH_ARM;
- *mode = CS_MODE_LITTLE_ENDIAN;
- break;
- case EM_MIPS:
- *arch = CS_ARCH_MIPS;
- break;
- case EM_PPC:
- *arch = CS_ARCH_PPC;
- *mode = CS_MODE_32;
- break;
- case EM_PPC64:
- *arch = CS_ARCH_PPC;
- *mode = CS_MODE_64;
- break;
- case EM_SPARC:
- *arch = CS_ARCH_SPARC;
- *mode = CS_MODE_BIG_ENDIAN;
- break;
- case EM_SPARCV9:
- *arch = CS_ARCH_SPARC;
- *mode = CS_MODE_V9;
- break;
- default:
- THROWF("Unknown ELF machine value: $0'", e_machine);
- }
-}
-
-static void ReadElfArchMode(const InputFile& file, cs_arch* arch, cs_mode* mode) {
- ForEachElf(file, nullptr,
- [=](const ElfFile& elf, string_view /*filename*/,
- uint32_t /*index_base*/) {
- // Last .o file wins? (For .a files)? It's kind of arbitrary,
- // but a single .a file shouldn't have multiple archs in it.
- ElfMachineToCapstone(elf.header().e_machine, arch, mode);
- });
-}
-
void AddCatchAll(RangeSink* sink) {
ForEachElf(sink->input_file(), sink,
[sink](const ElfFile& elf, string_view /*filename*/,
uint32_t /*index_base*/) {
- sink->AddFileRange("[ELF Headers]", elf.header_region());
- sink->AddFileRange("[ELF Headers]", elf.section_headers());
- sink->AddFileRange("[ELF Headers]", elf.segment_headers());
-
+ sink->AddFileRange("elf_catchall", "[ELF Headers]",
+ elf.header_region());
+ sink->AddFileRange("elf_catchall", "[ELF Headers]",
+ elf.section_headers());
+ sink->AddFileRange("elf_catchall", "[ELF Headers]",
+ elf.segment_headers());
});
// The last-line fallback to make sure we cover the entire VM space.
DoReadELFSegments(sink, kReportByEscapedSegmentName);
// The last-line fallback to make sure we cover the entire file.
- sink->AddFileRange("[Unmapped]", sink->input_file().data());
+ sink->AddFileRange("elf_catchall", "[Unmapped]", sink->input_file().data());
}
} // namespace
@@ -1268,7 +1256,7 @@
case DataSource::kRawSymbols:
case DataSource::kShortSymbols:
case DataSource::kFullSymbols:
- ReadELFSymbols(debug_file().file_data(), sink, nullptr);
+ ReadELFSymbols(debug_file().file_data(), sink, nullptr, false);
break;
case DataSource::kArchiveMembers:
DoReadELFSections(sink, kReportByArchiveMember);
@@ -1282,7 +1270,8 @@
DataSource::kRawSymbols,
&sinks[0]->MapAtIndex(0));
symbol_sink.AddOutput(&symbol_map, &empty_munger);
- ReadELFSymbols(debug_file().file_data(), &symbol_sink, &symtab);
+ ReadELFSymbols(debug_file().file_data(), &symbol_sink, &symtab,
+ false);
dwarf::File dwarf;
ReadDWARFSections(debug_file().file_data(), &dwarf);
ReadDWARFCompileUnits(dwarf, symtab, symbol_map, sink);
@@ -1347,7 +1336,8 @@
SymbolTable symbol_table;
RangeSink symbol_sink(&file_data(), symbol_source, &base_map);
symbol_sink.AddOutput(&info->symbol_map, &empty_munger);
- ReadELFSymbols(debug_file().file_data(), &symbol_sink, &symbol_table);
+ ReadELFSymbols(debug_file().file_data(), &symbol_sink, &symbol_table,
+ false);
if (symbol) {
auto entry = symbol_table.find(*symbol);
diff --git a/src/macho.cc b/src/macho.cc
index 8c380c4..79c9758 100644
--- a/src/macho.cc
+++ b/src/macho.cc
@@ -106,7 +106,7 @@
if (sink->data_source() == DataSource::kSegments) {
sink->AddRange(
- segname, segment->vmaddr, segment->vmsize,
+ "macho_segment", segname, segment->vmaddr, segment->vmsize,
StrictSubstr(file_data, segment->fileoff, segment->filesize));
} else if (sink->data_source() == DataSource::kSections) {
uint32_t nsects = segment->nsects;
@@ -127,7 +127,7 @@
std::string label = absl::StrJoin(
std::make_tuple(segname, ArrayToStr(section->sectname, 16)), ",");
- sink->AddRange(label, section->addr, section->size,
+ sink->AddRange("macho_section", label, section->addr, section->size,
StrictSubstr(file_data, section->offset, filesize));
}
} else {
@@ -139,18 +139,20 @@
RangeSink* sink) {
auto info = GetStructPointer<dyld_info_command>(command_data);
- sink->AddFileRange("Rebase Info", StrictSubstr(file_data, info->rebase_off,
- info->rebase_size));
- sink->AddFileRange("Binding Info",
+ sink->AddFileRange(
+ "macho_dyld", "Rebase Info",
+ StrictSubstr(file_data, info->rebase_off, info->rebase_size));
+ sink->AddFileRange("macho_dyld", "Binding Info",
StrictSubstr(file_data, info->bind_off, info->bind_size));
sink->AddFileRange(
- "Weak Binding Info",
+ "macho_dyld", "Weak Binding Info",
StrictSubstr(file_data, info->weak_bind_off, info->weak_bind_size));
sink->AddFileRange(
- "Lazy Binding Info",
+ "macho_dyld", "Lazy Binding Info",
StrictSubstr(file_data, info->lazy_bind_off, info->lazy_bind_size));
- sink->AddFileRange("Export Info", StrictSubstr(file_data, info->export_off,
- info->export_size));
+ sink->AddFileRange(
+ "macho_dyld", "Export Info",
+ StrictSubstr(file_data, info->export_off, info->export_size));
}
static void ParseSymbolTable(string_view command_data, string_view file_data,
@@ -158,10 +160,10 @@
auto symtab = GetStructPointer<symtab_command>(command_data);
// TODO(haberman): use 32-bit symbol size where appropriate.
- sink->AddFileRange("Symbol Table",
+ sink->AddFileRange("macho_symtab", "Symbol Table",
StrictSubstr(file_data, symtab->symoff,
symtab->nsyms * sizeof(nlist_64)));
- sink->AddFileRange("String Table",
+ sink->AddFileRange("macho_symtab", "String Table",
StrictSubstr(file_data, symtab->stroff, symtab->strsize));
}
@@ -170,24 +172,24 @@
auto dysymtab = GetStructPointer<dysymtab_command>(command_data);
sink->AddFileRange(
- "Table of Contents",
+ "macho_dynsymtab", "Table of Contents",
StrictSubstr(file_data, dysymtab->tocoff,
dysymtab->ntoc * sizeof(dylib_table_of_contents)));
- sink->AddFileRange("Module Table",
+ sink->AddFileRange("macho_dynsymtab", "Module Table",
StrictSubstr(file_data, dysymtab->modtaboff,
dysymtab->nmodtab * sizeof(dylib_module_64)));
sink->AddFileRange(
- "Referenced Symbol Table",
+ "macho_dynsymtab", "Referenced Symbol Table",
StrictSubstr(file_data, dysymtab->extrefsymoff,
dysymtab->nextrefsyms * sizeof(dylib_reference)));
- sink->AddFileRange("Indirect Symbol Table",
+ sink->AddFileRange("macho_dynsymtab", "Indirect Symbol Table",
StrictSubstr(file_data, dysymtab->indirectsymoff,
dysymtab->nindirectsyms * sizeof(uint32_t)));
- sink->AddFileRange("External Relocation Entries",
+ sink->AddFileRange("macho_dynsymtab", "External Relocation Entries",
StrictSubstr(file_data, dysymtab->extreloff,
dysymtab->nextrel * sizeof(relocation_info)));
sink->AddFileRange(
- "Local Relocation Entries",
+ "macho_dynsymtab", "Local Relocation Entries",
StrictSubstr(file_data, dysymtab->locreloff,
dysymtab->nlocrel * sizeof(struct relocation_info)));
}
@@ -196,7 +198,8 @@
string_view file_data, RangeSink* sink) {
auto linkedit = GetStructPointer<linkedit_data_command>(command_data);
sink->AddFileRange(
- label, StrictSubstr(file_data, linkedit->dataoff, linkedit->datasize));
+ "macho_linkedit", label,
+ StrictSubstr(file_data, linkedit->dataoff, linkedit->datasize));
}
void ParseMachOLoadCommand(uint32_t cmd, string_view command_data,
@@ -275,7 +278,8 @@
continue;
}
- sink->AddVMRange(addr, size, ItaniumDemangle(name, sink->data_source()));
+ sink->AddVMRange("macho_syms", addr, size,
+ ItaniumDemangle(name, sink->data_source()));
}
}
}
@@ -378,7 +382,7 @@
}
static void AddMachOFallback(RangeSink* sink) {
- sink->AddFileRange("[Unmapped]", sink->input_file().data());
+ sink->AddFileRange("macho_fallback", "[Unmapped]", sink->input_file().data());
}
class MachOObjectFile : public ObjectFile {
diff --git a/src/range_map.h b/src/range_map.h
index 9c0058f..424a1ed 100644
--- a/src/range_map.h
+++ b/src/range_map.h
@@ -119,7 +119,8 @@
template <class Func>
void ForEachRangeWithStart(uint64_t start, Func func) const {
for (auto iter = FindContaining(start); iter != mappings_.end(); ++iter) {
- if (!func(iter->first, RangeEnd(iter) - iter->first)) {
+ if (!func(iter->second.label, iter->first,
+ RangeEnd(iter) - iter->first)) {
return;
}
}
diff --git a/tests/range_map_test.cc b/tests/range_map_test.cc
index 732acaf..c88a6c8 100644
--- a/tests/range_map_test.cc
+++ b/tests/range_map_test.cc
@@ -344,6 +344,13 @@
AssertMapEquals(map3_, {
{125, UINT64_MAX, kNoTranslation, "translate me"}
});
+
+ map2_.AddRange(20, 10, "fallback");
+
+ AssertRollupEquals({&map_, &map2_}, {
+ {{"foo", "fallback"}, 20, 25},
+ {{"foo", "translate me"}, 25, 30},
+ });
}
} // namespace bloaty