Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 57 additions & 46 deletions src/bloaty.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1107,12 +1107,13 @@ std::unique_ptr<InputFile> MmapInputFileFactory::OpenFile(

RangeSink::RangeSink(const InputFile* file, const Options& options,
DataSource data_source, const DualMap* translator,
google::protobuf::Arena* arena)
google::protobuf::Arena* arena, int segment_id)
: file_(file),
options_(options),
data_source_(data_source),
translator_(translator),
arena_(arena) {}
arena_(arena),
segment_id_(segment_id) {}

RangeSink::~RangeSink() {}

Expand Down Expand Up @@ -1148,11 +1149,11 @@ bool RangeSink::IsVerboseForVMRange(uint64_t vmaddr, uint64_t vmsize) {
RangeMap vm_map;
RangeMap file_map;
bool contains = false;
vm_map.AddRangeWithTranslation(vmaddr, vmsize, "", translator_->vm_map,
vm_map.AddRangeWithTranslation(VMAddr(segment_id_, vmaddr), vmsize, "", translator_->vm_map,
false, &file_map);
file_map.ForEachRange(
[this, &contains](uint64_t fileoff, uint64_t filesize) {
if (ContainsVerboseFileOffset(fileoff, filesize)) {
[this, &contains](VMAddr fileoff, uint64_t filesize) {
if (ContainsVerboseFileOffset(fileoff.address, filesize)) {
contains = true;
}
});
Expand Down Expand Up @@ -1180,10 +1181,10 @@ bool RangeSink::IsVerboseForFileRange(uint64_t fileoff, uint64_t filesize) {
RangeMap vm_map;
RangeMap file_map;
bool contains = false;
file_map.AddRangeWithTranslation(fileoff, filesize, "",
file_map.AddRangeWithTranslation(VMAddr(fileoff), filesize, "",
translator_->file_map, false, &vm_map);
vm_map.ForEachRange([this, &contains](uint64_t vmaddr, uint64_t vmsize) {
if (ContainsVerboseVMAddr(vmaddr, vmsize)) {
vm_map.ForEachRange([this, &contains](VMAddr vmaddr, uint64_t vmsize) {
if (ContainsVerboseVMAddr(vmaddr.address, vmsize)) {
contains = true;
}
});
Expand All @@ -1209,14 +1210,14 @@ void RangeSink::AddFileRange(const char* analyzer, string_view name,
const std::string label = pair.second->Munge(name);
if (translator_) {
bool ok = pair.first->file_map.AddRangeWithTranslation(
fileoff, filesize, label, translator_->file_map, verbose,
VMAddr(fileoff), filesize, label, translator_->file_map, verbose,
&pair.first->vm_map);
if (!ok) {
WARN("File range ($0, $1) for label $2 extends beyond base map",
fileoff, filesize, name);
}
} else {
pair.first->file_map.AddRange(fileoff, filesize, label);
pair.first->file_map.AddRange(VMAddr(fileoff), filesize, label);
}
}
}
Expand All @@ -1234,9 +1235,9 @@ void RangeSink::AddFileRangeForVMAddr(const char* analyzer,
assert(translator_);
for (auto& pair : outputs_) {
std::string label;
if (pair.first->vm_map.TryGetLabel(label_from_vmaddr, &label)) {
if (pair.first->vm_map.TryGetLabel(VMAddr(segment_id_, label_from_vmaddr), &label)) {
bool ok = pair.first->file_map.AddRangeWithTranslation(
file_offset, file_range.size(), label, translator_->file_map, verbose,
VMAddr(file_offset), file_range.size(), label, translator_->file_map, verbose,
&pair.first->vm_map);
if (!ok) {
WARN("File range ($0, $1) for label $2 extends beyond base map",
Expand Down Expand Up @@ -1264,9 +1265,9 @@ void RangeSink::AddFileRangeForFileRange(const char* analyzer,
for (auto& pair : outputs_) {
std::string label;
if (pair.first->file_map.TryGetLabelForRange(
from_file_offset, from_file_range.size(), &label)) {
VMAddr(from_file_offset), from_file_range.size(), &label)) {
bool ok = pair.first->file_map.AddRangeWithTranslation(
file_offset, file_range.size(), label, translator_->file_map, verbose,
VMAddr(file_offset), file_range.size(), label, translator_->file_map, verbose,
&pair.first->vm_map);
if (!ok) {
WARN("File range ($0, $1) for label $2 extends beyond base map",
Expand All @@ -1284,17 +1285,17 @@ void RangeSink::AddVMRangeForVMAddr(const char* analyzer,
uint64_t size) {
bool verbose = IsVerboseForVMRange(addr, size);
if (verbose) {
printf("[%s, %s] AddVMRangeForVMAddr(%" PRIx64 ", [%" PRIx64 ", %" PRIx64
"])\n",
GetDataSourceLabel(data_source_), analyzer, label_from_vmaddr, addr,
size);
printf("[%s, %s] AddVMRangeForVMAddr(seg=%d label_from=%" PRIx64 ", seg=%d addr=%" PRIx64 ", %" PRIx64
")\n",
GetDataSourceLabel(data_source_), analyzer, segment_id_, label_from_vmaddr,
segment_id_, addr, size);
}
assert(translator_);
for (auto& pair : outputs_) {
std::string label;
if (pair.first->vm_map.TryGetLabel(label_from_vmaddr, &label)) {
if (pair.first->vm_map.TryGetLabel(VMAddr(segment_id_, label_from_vmaddr), &label)) {
bool ok = pair.first->vm_map.AddRangeWithTranslation(
addr, size, label, translator_->vm_map, verbose,
VMAddr(segment_id_, addr), size, label, translator_->vm_map, verbose,
&pair.first->file_map);
if (!ok && verbose_level > 1) {
WARN("VM range ($0, $1) for label $2 extends beyond base map", addr,
Expand All @@ -1310,15 +1311,15 @@ void RangeSink::AddVMRange(const char* analyzer, uint64_t vmaddr,
uint64_t vmsize, const std::string& name) {
bool verbose = IsVerboseForVMRange(vmaddr, vmsize);
if (verbose) {
printf("[%s, %s] AddVMRange(%.*s, %" PRIx64 ", %" PRIx64 ")\n",
printf("[%s, %s] AddVMRange(%.*s, seg=%d vmaddr=%" PRIx64 ", %" PRIx64 ")\n",
GetDataSourceLabel(data_source_), analyzer, (int)name.size(),
name.data(), vmaddr, vmsize);
name.data(), segment_id_, vmaddr, vmsize);
}
assert(translator_);
for (auto& pair : outputs_) {
const std::string label = pair.second->Munge(name);
bool ok = pair.first->vm_map.AddRangeWithTranslation(
vmaddr, vmsize, label, translator_->vm_map, verbose,
VMAddr(segment_id_, vmaddr), vmsize, label, translator_->vm_map, verbose,
&pair.first->file_map);
if (!ok) {
WARN("VM range ($0, $1) for label $2 extends beyond base map", vmaddr,
Expand Down Expand Up @@ -1353,15 +1354,15 @@ void RangeSink::AddRange(const char* analyzer, string_view name,

if (IsVerboseForVMRange(vmaddr, vmsize) ||
IsVerboseForFileRange(fileoff, filesize)) {
printf("[%s, %s] AddRange(%.*s, %" PRIx64 ", %" PRIx64 ", %" PRIx64
printf("[%s, %s] AddRange(%.*s, seg=%d vmaddr=%" PRIx64 ", %" PRIx64 ", %" PRIx64
", %" PRIx64 ")\n",
GetDataSourceLabel(data_source_), analyzer, (int)name.size(),
name.data(), vmaddr, vmsize, fileoff, filesize);
name.data(), segment_id_, vmaddr, vmsize, fileoff, filesize);
}

if (translator_) {
if (!translator_->vm_map.CoversRange(vmaddr, vmsize) ||
!translator_->file_map.CoversRange(fileoff, filesize)) {
if (!translator_->vm_map.CoversRange(VMAddr(segment_id_, vmaddr), vmsize) ||
!translator_->file_map.CoversRange(VMAddr(fileoff), filesize)) {
WARN("AddRange($0, $1, $2, $3, $4) will be ignored, because it is not "
"covered by base map.",
name.data(), vmaddr, vmsize, fileoff, filesize);
Expand All @@ -1373,11 +1374,11 @@ void RangeSink::AddRange(const char* analyzer, string_view name,
const std::string label = pair.second->Munge(name);
uint64_t common = std::min(vmsize, filesize);

pair.first->vm_map.AddDualRange(vmaddr, common, fileoff, label);
pair.first->file_map.AddDualRange(fileoff, common, vmaddr, label);
pair.first->vm_map.AddDualRange(VMAddr(segment_id_, vmaddr), common, VMAddr(fileoff), label);
pair.first->file_map.AddDualRange(VMAddr(fileoff), common, VMAddr(segment_id_, vmaddr), label);

pair.first->vm_map.AddRange(vmaddr + common, vmsize - common, label);
pair.first->file_map.AddRange(fileoff + common, filesize - common, label);
pair.first->vm_map.AddRange(VMAddr(segment_id_, vmaddr + common), vmsize - common, label);
pair.first->file_map.AddRange(VMAddr(fileoff + common), filesize - common, label);
}
}

Expand All @@ -1386,7 +1387,7 @@ uint64_t RangeSink::TranslateFileToVM(const char* ptr) {
uint64_t offset = ptr - file_->data().data();
uint64_t translated;
if (!FileContainsPointer(ptr) ||
!translator_->file_map.Translate(offset, &translated)) {
!translator_->file_map.Translate(VMAddr(0, offset), &translated)) {
THROWF("Can't translate file offset ($0) to VM, contains: $1, map:\n$2",
offset, FileContainsPointer(ptr),
translator_->file_map.DebugString().c_str());
Expand All @@ -1397,7 +1398,7 @@ uint64_t RangeSink::TranslateFileToVM(const char* ptr) {
std::string_view RangeSink::TranslateVMToFile(uint64_t address) {
assert(translator_);
uint64_t translated;
if (!translator_->vm_map.Translate(address, &translated) ||
if (!translator_->vm_map.Translate(VMAddr(segment_id_, address), &translated) ||
translated > file_->data().size()) {
THROWF("Can't translate VM pointer ($0) to file", address);

Expand Down Expand Up @@ -1868,26 +1869,36 @@ struct DualMaps {
map->file_map.Compress();
}
RangeMap::ComputeRollup(VmMaps(), [=](const std::vector<std::string>& keys,
uint64_t addr, uint64_t end) {
VMAddr addr, VMAddr end) {
return rollup->AddSizes(keys, end - addr, true);
});
RangeMap::ComputeRollup(
FileMaps(),
[=](const std::vector<std::string>& keys, uint64_t addr, uint64_t end) {
[=](const std::vector<std::string>& keys, VMAddr addr, VMAddr end) {
return rollup->AddSizes(keys, end - addr, false);
});
}

void PrintMaps(const std::vector<const RangeMap*> maps) {
uint64_t last = 0;
uint64_t max = maps[0]->GetMaxAddress();
int hex_digits = max > 0 ? std::ceil(std::log2(max) / 4) : 0;
VMAddr last(0, 0);
int last_segment = -1;
VMAddr max = maps[0]->GetMaxAddress();
int hex_digits = max.address > 0 ? std::ceil(std::log2(max.address) / 4) : 0;
RangeMap::ComputeRollup(maps, [&](const std::vector<std::string>& keys,
uint64_t addr, uint64_t end) {
if (addr > last) {
PrintMapRow("[-- Nothing mapped --]", last, addr, hex_digits);
VMAddr addr, VMAddr end) {
if (addr.segment != last_segment) {
if (last_segment != -1) {
printf("\n");
}
printf("SEGMENT %d:\n", addr.segment);
last = VMAddr(addr.segment, 0);
last_segment = addr.segment;
}

if (addr.address > last.address) {
PrintMapRow("[-- Nothing mapped --]", last.address, addr.address, hex_digits);
}
PrintMapRow(KeysToString(keys), addr, end, hex_digits);
PrintMapRow(KeysToString(keys), addr.address, end.address, hex_digits);
last = end;
});
printf("\n");
Expand Down Expand Up @@ -2004,14 +2015,14 @@ void Bloaty::ScanAndRollupFile(const std::string& filename, Rollup* rollup,
// kInputFile source: Copy the base map to the filename sink(s).
for (auto sink : filename_sink_ptrs) {
maps.base_map()->vm_map.ForEachRange(
[sink](uint64_t start, uint64_t length) {
sink->AddVMRange("inputfile_vmcopier", start, length,
[sink](VMAddr start, uint64_t length) {
sink->AddVMRange("inputfile_vmcopier", start.address, length,
sink->input_file().filename());
});
maps.base_map()->file_map.ForEachRange(
[sink](uint64_t start, uint64_t length) {
[sink](VMAddr start, uint64_t length) {
sink->AddFileRange("inputfile_filecopier",
sink->input_file().filename(), start, length);
sink->input_file().filename(), start.address, length);
});
}

Expand Down
5 changes: 4 additions & 1 deletion src/bloaty.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class RangeSink {
public:
RangeSink(const InputFile *file, const Options &options,
DataSource data_source, const DualMap *translator,
google::protobuf::Arena *arena);
google::protobuf::Arena *arena, int segment_id = 0);
RangeSink(const RangeSink &) = delete;
RangeSink &operator=(const RangeSink &) = delete;
~RangeSink();
Expand All @@ -126,6 +126,8 @@ class RangeSink {
DataSource data_source() const { return data_source_; }
const InputFile &input_file() const { return *file_; }
bool IsBaseMap() const { return translator_ == nullptr; }
int segment_id() const { return segment_id_; }
void set_segment_id(int segment_id) { segment_id_ = segment_id; }

// 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
Expand Down Expand Up @@ -238,6 +240,7 @@ class RangeSink {
const DualMap* translator_;
std::vector<std::pair<DualMap*, const NameMunger*>> outputs_;
google::protobuf::Arena *arena_;
int segment_id_;
};

// NameMunger //////////////////////////////////////////////////////////////////
Expand Down
2 changes: 1 addition & 1 deletion src/disassemble.cc
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ std::string DisassembleFunction(const DisassemblyInfo& info) {
} else {
op_str = "<" + std::to_string(iter->second);
}
} else if (info.symbol_map.vm_map.TryGetLabel(target, &label)) {
} else if (info.symbol_map.vm_map.TryGetLabel(VMAddr(target), &label)) {
op_str = label;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/dwarf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ void AddDIE(const dwarf::CU& cu, const GeneralDIE& die,
// Unfortunately the location doesn't include a size, so we look that part
// up in the symbol map.
uint64_t size;
if (symbol_map.vm_map.TryGetSize(addr, &size)) {
if (symbol_map.vm_map.TryGetSize(VMAddr(addr), &size)) {
sink->AddVMRangeIgnoreDuplicate("dwarf_location", addr, size,
cu.unit_name());
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/elf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -950,7 +950,7 @@ static void ReadELFSymbols(const InputFile& file, RangeSink* sink,
}
// TODO(brandonvu) Continue if VM pointer cannot be translated. Issue #315
uint64_t unused;
if (!sink->Translator()->vm_map.Translate(full_addr, &unused)) {
if (!sink->Translator()->vm_map.Translate(VMAddr(full_addr), &unused)) {
WARN("Can't translate VM pointer ($0) to file", full_addr);
continue;
}
Expand Down Expand Up @@ -1462,7 +1462,7 @@ class ElfObjectFile : public ObjectFile {
// symbolized.

uint64_t fileoff;
if (!base_map.vm_map.Translate(vmaddr, &fileoff)) {
if (!base_map.vm_map.Translate(VMAddr(vmaddr), &fileoff)) {
THROWF("Couldn't translate VM address for function $0", symbol);
}

Expand Down
21 changes: 14 additions & 7 deletions src/macho.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ struct LoadCommand {
uint32_t cmd;
string_view command_data;
string_view file_data;
int segment_id; // Architecture index for universal binaries
};

template <class Struct>
Expand All @@ -84,7 +85,7 @@ bool Is64Bit<mach_header_64>() { return true; }

template <class Struct, class Func>
void ParseMachOHeaderImpl(string_view macho_data, RangeSink* overhead_sink,
Func&& loadcmd_func) {
int segment_id, Func&& loadcmd_func) {
string_view header_data = macho_data;
auto header = GetStructPointerAndAdvance<Struct>(&header_data);
MaybeAddOverhead(overhead_sink,
Expand All @@ -107,6 +108,7 @@ void ParseMachOHeaderImpl(string_view macho_data, RangeSink* overhead_sink,
data.cmd = command->cmd;
data.command_data = StrictSubstr(header_data, 0, command->cmdsize);
data.file_data = macho_data;
data.segment_id = segment_id;
std::forward<Func>(loadcmd_func)(data);

MaybeAddOverhead(overhead_sink, "[Mach-O Headers]", data.command_data);
Expand All @@ -116,7 +118,7 @@ void ParseMachOHeaderImpl(string_view macho_data, RangeSink* overhead_sink,

template <class Func>
void ParseMachOHeader(string_view macho_file, RangeSink* overhead_sink,
Func&& loadcmd_func) {
int segment_id, Func&& loadcmd_func) {
uint32_t magic = ReadMagic(macho_file);
switch (magic) {
case MH_MAGIC:
Expand All @@ -127,12 +129,12 @@ void ParseMachOHeader(string_view macho_file, RangeSink* overhead_sink,
// Still, you can build 32-bit binaries as of this writing, and
// there are existing 32-bit binaries floating around, so we might
// as well support them.
ParseMachOHeaderImpl<mach_header>(macho_file, overhead_sink,
ParseMachOHeaderImpl<mach_header>(macho_file, overhead_sink, segment_id,
std::forward<Func>(loadcmd_func));
break;
case MH_MAGIC_64:
ParseMachOHeaderImpl<mach_header_64>(
macho_file, overhead_sink, std::forward<Func>(loadcmd_func));
macho_file, overhead_sink, segment_id, std::forward<Func>(loadcmd_func));
break;
case MH_CIGAM:
case MH_CIGAM_64:
Expand Down Expand Up @@ -167,7 +169,8 @@ void ParseFatHeader(string_view fat_file, RangeSink* overhead_sink,
auto arch = GetStructPointerAndAdvance<fat_arch>(&header_data);
string_view macho_data = StrictSubstr(
fat_file, ByteSwap(arch->offset), ByteSwap(arch->size));
ParseMachOHeader(macho_data, overhead_sink,
// Pass architecture index as segment_id for multi-arch binaries
ParseMachOHeader(macho_data, overhead_sink, i,
std::forward<Func>(loadcmd_func));
}
}
Expand All @@ -181,7 +184,8 @@ void ForEachLoadCommand(string_view maybe_fat_file, RangeSink* overhead_sink,
case MH_MAGIC_64:
case MH_CIGAM:
case MH_CIGAM_64:
ParseMachOHeader(maybe_fat_file, overhead_sink,
// Single-architecture binary uses segment_id = 0
ParseMachOHeader(maybe_fat_file, overhead_sink, 0,
std::forward<Func>(loadcmd_func));
break;
case FAT_CIGAM:
Expand Down Expand Up @@ -417,7 +421,10 @@ void ParseLoadCommand(const LoadCommand& cmd, RangeSink* sink) {
void ParseLoadCommands(RangeSink* sink) {
ForEachLoadCommand(
sink->input_file().data(), sink,
[sink](const LoadCommand& cmd) { ParseLoadCommand(cmd, sink); });
[sink](const LoadCommand& cmd) {
sink->set_segment_id(cmd.segment_id);
ParseLoadCommand(cmd, sink);
});
}

template <class NList>
Expand Down
Loading