Merge pull request #258 from haberman/better-tests
New testing infrastructure, and fixes for several ELF/DWARF bugs
diff --git a/src/bloaty.cc b/src/bloaty.cc
index 78147ea..62fcbb3 100644
--- a/src/bloaty.cc
+++ b/src/bloaty.cc
@@ -65,6 +65,7 @@
// otherwise. We would make this thread_local but that's not supported on OS X
// right now.
int verbose_level = 0;
+ShowDomain show = ShowDomain::kShowBoth;
struct DataSourceDefinition {
DataSource number;
@@ -1062,13 +1063,13 @@
uint64_t debug_fileoff = -1;
bool RangeSink::ContainsVerboseVMAddr(uint64_t vmaddr, uint64_t vmsize) {
- return options_.verbose_level() > 2 ||
+ return options_.verbose_level() > 1 ||
(options_.has_debug_vmaddr() && options_.debug_vmaddr() >= vmaddr &&
options_.debug_vmaddr() < (vmaddr + vmsize));
}
bool RangeSink::ContainsVerboseFileOffset(uint64_t fileoff, uint64_t filesize) {
- return options_.verbose_level() > 2 ||
+ return options_.verbose_level() > 1 ||
(options_.has_debug_fileoff() && options_.debug_fileoff() >= fileoff &&
options_.debug_fileoff() < (fileoff + filesize));
}
@@ -1184,7 +1185,7 @@
WARN("File range ($0, $1) for label $2 extends beyond base map",
file_offset, file_range.size(), label);
}
- } else if (verbose_level > 2) {
+ } else if (verbose_level > 1) {
printf("No label found for vmaddr %" PRIx64 "\n", label_from_vmaddr);
}
}
@@ -1214,7 +1215,7 @@
WARN("File range ($0, $1) for label $2 extends beyond base map",
file_offset, file_range.size(), label);
}
- } else if (verbose_level > 2) {
+ } else if (verbose_level > 1) {
printf("No label found for file range [%" PRIx64 ", %zx]\n",
from_file_offset, from_file_range.size());
}
@@ -1238,11 +1239,11 @@
bool ok = pair.first->vm_map.AddRangeWithTranslation(
addr, size, label, translator_->vm_map, verbose,
&pair.first->file_map);
- if (!ok && verbose_level > 0) {
+ if (!ok && verbose_level > 1) {
WARN("VM range ($0, $1) for label $2 extends beyond base map", addr,
size, label);
}
- } else if (verbose_level > 2) {
+ } else if (verbose_level > 1) {
printf("No label found for vmaddr %" PRIx64 "\n", label_from_vmaddr);
}
}
@@ -1765,11 +1766,16 @@
(void)filesize;
assert(filesize == file->file_data().data().size());
- if (verbose_level > 0) {
- printf("FILE MAP:\n");
- maps.PrintFileMaps();
- printf("VM MAP:\n");
- maps.PrintVMMaps();
+ if (verbose_level > 0 || options_.dump_raw_map()) {
+ printf("Maps for %s:\n\n", filename.c_str());
+ if (show != ShowDomain::kShowVM) {
+ printf("FILE MAP:\n");
+ maps.PrintFileMaps();
+ }
+ if (show != ShowDomain::kShowFile) {
+ printf("VM MAP:\n");
+ maps.PrintVMMaps();
+ }
}
}
@@ -2071,6 +2077,8 @@
output_options->output_format = OutputFormat::kCSV;
} else if (args.TryParseFlag("--tsv")) {
output_options->output_format = OutputFormat::kTSV;
+ } else if (args.TryParseFlag("--raw-map")) {
+ options->set_dump_raw_map(true);
} else if (args.TryParseOption("-c", &option)) {
std::ifstream input_file(std::string(option), std::ios::in);
if (!input_file.is_open()) {
@@ -2119,11 +2127,11 @@
} else if (args.TryParseOption("--domain", &option)) {
has_domain = true;
if (option == "vm") {
- output_options->show = ShowDomain::kShowVM;
+ show = output_options->show = ShowDomain::kShowVM;
} else if (option == "file") {
- output_options->show = ShowDomain::kShowFile;
+ show = output_options->show = ShowDomain::kShowFile;
} else if (option == "both") {
- output_options->show = ShowDomain::kShowBoth;
+ show = output_options->show = ShowDomain::kShowBoth;
} else {
THROWF("unknown value for --domain: $0", option);
}
diff --git a/src/bloaty.proto b/src/bloaty.proto
index 59db641..1679328 100644
--- a/src/bloaty.proto
+++ b/src/bloaty.proto
@@ -72,6 +72,9 @@
// Regex with which to filter names in the data sources.
optional string source_filter = 13;
+
+ // Dump raw memory map instead of printing normal output.
+ optional bool dump_raw_map = 14;
}
// A custom data source allows users to create their own label space by
diff --git a/src/dwarf.cc b/src/dwarf.cc
index b1d0bec..3fc8446 100644
--- a/src/dwarf.cc
+++ b/src/dwarf.cc
@@ -184,6 +184,16 @@
}
}
+ uint64_t GetMaxAddress() const {
+ if (address_size_ == 8) {
+ return UINT64_MAX;
+ } else if (address_size_ == 4) {
+ return UINT32_MAX;
+ } else {
+ BLOATY_UNREACHABLE();
+ }
+ }
+
// Reads an "initial length" as specified in many DWARF headers. This
// contains either a 32-bit or a 64-bit length, and signals whether we are
// using the 32-bit or 64-bit DWARF format (so it sets dwarf64 appropriately).
@@ -1081,16 +1091,20 @@
void ReadRangeList(const DIEReader& die_reader, uint64_t low_pc,
string_view name, RangeSink* sink, string_view* data) {
std::string name_str(name);
+ uint64_t max_address = die_reader.unit_sizes().GetMaxAddress();
while (true) {
uint64_t start, end;
start = die_reader.unit_sizes().ReadAddress(data);
end = die_reader.unit_sizes().ReadAddress(data);
if (start == 0 && end == 0) {
return;
+ } else if (start == max_address) {
+ low_pc = end;
+ } else {
+ uint64_t size = end - start;
+ sink->AddVMRangeIgnoreDuplicate("dwarf_rangelist", low_pc + start, size,
+ name_str);
}
- uint64_t size = end - start;
- sink->AddVMRangeIgnoreDuplicate("dwarf_rangelist", low_pc + start, size,
- name_str);
}
}
diff --git a/src/elf.cc b/src/elf.cc
index eb0e263..355210b 100644
--- a/src/elf.cc
+++ b/src/elf.cc
@@ -1065,6 +1065,7 @@
contents);
} else if (report_by == kReportBySectionName) {
sink->AddRange("elf_section", name, full_addr, vmsize, contents);
+ sink->AddFileRange("elf_section_header", name, section.range());
} else if (report_by == kReportByEscapedSectionName) {
if (!sink->IsBaseMap()) {
sink->AddFileRangeForFileRange("elf_section", contents,
@@ -1091,56 +1092,79 @@
kReportByEscapedSegmentName,
};
+std::string GetSegmentName(const ElfFile::Segment& segment, Elf64_Xword i,
+ ReportSegmentsBy report_by) {
+ const auto& header = segment.header();
+
+ // Include the segment index in the label, to support embedded.
+ //
+ // Including the index in the segment label differentiates
+ // segments with the same access control (e.g. RWX vs RW). In
+ // ELF files built for embedded microcontroller projects, a
+ // segment is used for each distinct type of memory. In simple
+ // cases, there is a segment for the flash (which will store
+ // code and read-only data) and a segment for RAM (which
+ // usually stores globals, stacks, and maybe a heap). In more
+ // involved projects, there may be special segments for faster
+ // RAM (e.g. core coupled RAM or CCRAM), or there may even be
+ // memory overlays to support manual paging of code from flash
+ // (which may be slow) into RAM.
+ std::string name(absl::StrCat("LOAD #", i, " ["));
+
+ if (header.p_flags & PF_R) {
+ name += 'R';
+ }
+
+ if (header.p_flags & PF_W) {
+ name += 'W';
+ }
+
+ if (header.p_flags & PF_X) {
+ name += 'X';
+ }
+
+ name += ']';
+
+ if (report_by == kReportByEscapedSegmentName) {
+ return absl::StrCat("[", name, "]");
+ } else {
+ return name;
+ }
+}
+
static void DoReadELFSegments(RangeSink* sink, ReportSegmentsBy report_by) {
+ if (!sink->IsBaseMap()) {
+ ForEachElf(sink->input_file(), sink,
+ [=](const ElfFile& elf, string_view /*filename*/,
+ uint32_t /*index_base*/) {
+ for (Elf64_Xword i = 0; i < elf.header().e_phnum; i++) {
+ ElfFile::Segment segment;
+ elf.ReadSegment(i, &segment);
+ std::string name = GetSegmentName(segment, i, report_by);
+
+ sink->AddFileRange("elf_segment_header", name,
+ segment.range());
+ }
+ });
+ }
+
ForEachElf(sink->input_file(), sink,
[=](const ElfFile& elf, string_view /*filename*/,
uint32_t /*index_base*/) {
for (Elf64_Xword i = 0; i < elf.header().e_phnum; i++) {
ElfFile::Segment segment;
elf.ReadSegment(i, &segment);
- const auto& header = segment.header();
+ std::string name = GetSegmentName(segment, i, report_by);
- if (header.p_type != PT_LOAD) {
+ if (segment.header().p_type != PT_LOAD) {
continue;
}
- // Include the segment index in the label, to support embedded.
- //
- // Including the index in the segment label differentiates
- // segments with the same access control (e.g. RWX vs RW). In
- // ELF files built for embedded microcontroller projects, a
- // segment is used for each distinct type of memory. In simple
- // cases, there is a segment for the flash (which will store
- // code and read-only data) and a segment for RAM (which
- // usually stores globals, stacks, and maybe a heap). In more
- // involved projects, there may be special segments for faster
- // RAM (e.g. core coupled RAM or CCRAM), or there may even be
- // memory overlays to support manual paging of code from flash
- // (which may be slow) into RAM.
- std::string name(absl::StrCat("LOAD #", i, " ["));
-
- if (header.p_flags & PF_R) {
- name += 'R';
- }
-
- if (header.p_flags & PF_W) {
- name += 'W';
- }
-
- if (header.p_flags & PF_X) {
- name += 'X';
- }
-
- name += ']';
-
- if (report_by == kReportByEscapedSegmentName) {
- name = absl::StrCat("[", name, "]");
- }
-
- sink->AddRange("elf_segment", name, header.p_vaddr,
- header.p_memsz, segment.contents());
+ sink->AddRange("elf_segment", name, segment.header().p_vaddr,
+ segment.header().p_memsz, segment.contents());
}
});
+
ForEachElf(sink->input_file(), sink,
[=](const ElfFile& elf, string_view /*filename*/,
uint32_t /*index_base*/) {
@@ -1148,10 +1172,10 @@
ElfFile::Segment segment;
elf.ReadSegment(i, &segment);
const auto& header = segment.header();
- if(header.p_type != PT_TLS) continue;
+ if (header.p_type != PT_TLS) continue;
std::string name = "TLS";
- sink->AddRange("elf_segment", "TLS", header.p_vaddr, header.p_memsz,
- segment.contents());
+ sink->AddRange("elf_segment", "TLS", header.p_vaddr,
+ header.p_memsz, segment.contents());
}
});
}
@@ -1276,6 +1300,9 @@
void ProcessFile(const std::vector<RangeSink*>& sinks) const override {
for (auto sink : sinks) {
+ if (verbose_level > 1) {
+ printf("Scanning source %d\n", (int)sink->data_source());
+ }
switch (sink->data_source()) {
case DataSource::kSegments:
ReadELFSegments(sink);
diff --git a/src/main.cc b/src/main.cc
index f2c5ec2..c6c04f8 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -40,6 +40,8 @@
return 1;
}
- output.Print(output_options, &std::cout);
+ if (!options.dump_raw_map()) {
+ output.Print(output_options, &std::cout);
+ }
return 0;
}
diff --git a/src/range_map.cc b/src/range_map.cc
index 08e1f18..71e4f0b 100644
--- a/src/range_map.cc
+++ b/src/range_map.cc
@@ -172,7 +172,7 @@
iter->second.size = new_size;
CheckConsistency(iter);
}
- } else if (verbose_level > 1) {
+ } else if (verbose_level > 2) {
printf(" skipping existing mapping (%s)\n",
EntryDebugString(iter).c_str());
}
diff --git a/tests/dwarf/range_lists/base-addr-selection.test b/tests/dwarf/range_lists/base-addr-selection.test
new file mode 100644
index 0000000..8efc530
--- /dev/null
+++ b/tests/dwarf/range_lists/base-addr-selection.test
@@ -0,0 +1,97 @@
+# Test for range list that contains a "base address selection" entry.
+# When the start address is the max address (eg. UINT64_MAX), it signals
+# a special kind of entry where the end address signifies the new base
+# address.
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_DYN
+ Machine: EM_X86_64
+ Entry: 0x1040
+ProgramHeaders:
+ - Type: PT_LOAD
+ Flags: [ PF_X, PF_R ]
+ FirstSec: .text
+ LastSec: .text
+ VAddr: 0x1000
+ Align: 0x1000
+Sections:
+ - Name: .note.gnu.build-id
+ Type: SHT_NOTE
+ Notes:
+ - Name: GNU
+ Desc: 6CF422D909772A0FB5400518A689D9F15F14BF57
+ Type: 0x3 # NT_GNU_BUILD_ID
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ Address: 0x1000
+ AddressAlign: 0x10
+ Content: 31ED4989D15E4889E24883E4F050544C8D053A010000488D0DD3000000488D3DC1000000FF15762F0000F40F1F440000488D3DB12F0000488D05AA2F00004839F87415488B054E2F00004885C07409FFE00F1F8000000000C30F1F8000000000488D3D812F0000488D357A2F00004829FE4889F048C1EE3F48C1F8034801C648D1FE7414488B05252F00004885C07408FFE0660F1F440000C30F1F8000000000803D412F000000752F5548833D062F0000004889E5740C488B3D222F0000E82DFFFFFFE868FFFFFFC605192F0000015DC30F1F8000000000C30F1F8000000000E97BFFFFFF554889E5B8010000005DC341574C8D3DDF2C000041564989D641554989F541544189FC55488D2DD02C0000534C29FD4883EC08E8A3FEFFFF48C1FD03741B31DB0F1F004C89F24C89EE4489E741FF14DF4883C3014839DD75EA4883C4085B5D415C415D415E415FC30F1F00C3
+...
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_DYN
+ Machine: EM_X86_64
+ Entry: 0x1040
+Sections:
+ - Name: .note.gnu.build-id
+ Type: SHT_NOTE
+ Notes:
+ - Name: GNU
+ Desc: 6CF422D909772A0FB5400518A689D9F15F14BF57
+ Type: 0x3 # NT_GNU_BUILD_ID
+DWARF:
+ debug_str:
+ - test.c
+ debug_abbrev:
+ - ID: 0
+ Table:
+ - Code: 0x1
+ Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Attribute: DW_AT_ranges
+ Form: DW_FORM_sec_offset
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ debug_ranges:
+ - Offset: 0x0
+ AddrSize: 0x8
+ Entries:
+ # This is the "base address selection" entry!
+ - LowOffset: 0xffffffffffffffff # UINT64_MAX
+ HighOffset: 0x1020
+ # Now these addresses are relative to 0x1020
+ - LowOffset: 0x22
+ HighOffset: 0x27
+ debug_info:
+ - Version: 4
+ AbbrevTableID: 0
+ AbbrOffset: 0x0
+ AddrSize: 8
+ Entries:
+ - AbbrCode: 0x1
+ Values:
+ - Value: 0x0
+ - Value: 0x0
+ - Value: 0x0
+ - AbbrCode: 0x0
+...
+
+$ bloaty 1 --debug-file=2 -d compileunits --raw-map --domain=vm
+Maps for 1:
+
+VM MAP:
+0000-1000 4096 [-- Nothing mapped --]
+1000-1042 66 [section .text]
+1042-1047 5 test.c
+1047-1151 266 [section .text]
+
diff --git a/tests/elf/sections/empty-bin-64.test b/tests/elf/sections/empty-bin-64.test
new file mode 100644
index 0000000..9df7eb3
--- /dev/null
+++ b/tests/elf/sections/empty-bin-64.test
@@ -0,0 +1,70 @@
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x1
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x1
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x1
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x1
+ EntSize: 0x1
+ Content: 004743433A202844656269616E2031302E322E312D362B6275696C6432292031302E322E3120323032313031313000
+ - Name: .note.GNU-stack
+ Type: SHT_PROGBITS
+ AddressAlign: 0x1
+Symbols:
+ - Name: 'null'
+ Type: STT_FILE
+ Index: SHN_ABS
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .note.GNU-stack
+ Type: STT_SECTION
+ Section: .note.GNU-stack
+ - Name: .comment
+ Type: STT_SECTION
+ Section: .comment
+...
+
+$ bloaty --raw-map 1
+Maps for 1:
+
+FILE MAP:
+000-040 64 [ELF Headers]
+040-070 48 .comment
+070-118 168 .symtab
+118-148 48 .strtab
+148-190 72 .shstrtab
+190-1d0 64 [ELF Headers]
+1d0-210 64 .text
+210-250 64 .data
+250-290 64 .bss
+290-2d0 64 .comment
+2d0-310 64 .note.GNU-stack
+310-350 64 .symtab
+350-390 64 .strtab
+390-3d0 64 .shstrtab
+
+VM MAP:
+
diff --git a/tests/elf/sections/empty-obj-64.test b/tests/elf/sections/empty-obj-64.test
new file mode 100644
index 0000000..fa94d1e
--- /dev/null
+++ b/tests/elf/sections/empty-obj-64.test
@@ -0,0 +1,70 @@
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x1
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x1
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x1
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x1
+ EntSize: 0x1
+ Content: 004743433A202844656269616E2031302E322E312D362B6275696C6432292031302E322E3120323032313031313000
+ - Name: .note.GNU-stack
+ Type: SHT_PROGBITS
+ AddressAlign: 0x1
+Symbols:
+ - Name: 'null'
+ Type: STT_FILE
+ Index: SHN_ABS
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .note.GNU-stack
+ Type: STT_SECTION
+ Section: .note.GNU-stack
+ - Name: .comment
+ Type: STT_SECTION
+ Section: .comment
+...
+
+$ bloaty --raw-map 1
+Maps for 1:
+
+FILE MAP:
+000-040 64 [ELF Headers]
+040-070 48 .comment
+070-118 168 .symtab
+118-148 48 .strtab
+148-190 72 .shstrtab
+190-1d0 64 [ELF Headers]
+1d0-210 64 .text
+210-250 64 .data
+250-290 64 .bss
+290-2d0 64 .comment
+2d0-310 64 .note.GNU-stack
+310-350 64 .symtab
+350-390 64 .strtab
+390-3d0 64 .shstrtab
+
+VM MAP:
+
diff --git a/tests/elf/sections/musl-static-bin.test b/tests/elf/sections/musl-static-bin.test
new file mode 100644
index 0000000..06c46ce
--- /dev/null
+++ b/tests/elf/sections/musl-static-bin.test
@@ -0,0 +1,591 @@
+# A fully statically-linked binary linked with musl.
+# Program text was:
+#
+# char x[123] = {0};
+# char y[456] = {1, 2, 3};
+# const char z[789] = {1, 2, 3};
+#
+# int main() {
+# volatile long addr = (long)&x;
+# addr = (long)&y;
+# addr = (long)&z;
+# return 5;
+# }
+#
+# This example uses musl because it can produce fully statically linked
+# binaries of reasonable size.
+#
+# This binary does not successfully run due to bugs in obj2yaml
+# (or possibly yaml2obj). The binary did not fully round-trip successfully.
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+ Entry: 0x000000000040105A
+ProgramHeaders:
+ - Type: PT_LOAD
+ Flags: [ PF_R ]
+ VAddr: 0x0000000000400000
+ Align: 0x0000000000001000
+ - Type: PT_LOAD
+ Flags: [ PF_X, PF_R ]
+ FirstSec: .init
+ LastSec: .fini
+ VAddr: 0x0000000000401000
+ Align: 0x0000000000001000
+ - Type: PT_LOAD
+ Flags: [ PF_R ]
+ FirstSec: .rodata
+ LastSec: .eh_frame
+ VAddr: 0x0000000000402000
+ Align: 0x0000000000001000
+ - Type: PT_LOAD
+ Flags: [ PF_W, PF_R ]
+ FirstSec: .init_array
+ LastSec: .bss
+ VAddr: 0x0000000000403FE8
+ FileSize: 0x228
+ MemSize: 0x510
+ Align: 0x0000000000001000
+ - Type: PT_GNU_STACK
+ Flags: [ PF_W, PF_R ]
+ Align: 0x0000000000000010
+ - Type: PT_GNU_RELRO
+ Flags: [ PF_R ]
+ FirstSec: .init_array
+ LastSec: .got
+ VAddr: 0x0000000000403FE8
+Sections:
+ - Name: .init
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ Address: 0x0000000000401000
+ AddressAlign: 0x0000000000000001
+ Content: 5058C3
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ Address: 0x0000000000401010
+ AddressAlign: 0x0000000000000010
+ Content: 5589FDE858040000E86304000031C0E84C04000089EFE8E50700000F1F440000488D050932000048894424F8488D05FD2F000048894424F8488D05B10F000048894424F8B805000000C34831ED4889E7488D3599EFBFFF4883E4F0E800000000488B37488D57084531C949C7C06918400048C7C10010400048C7C730104000E99C030000662E0F1F8400000000006690488D3D69310000488D05623100004839F8741548C7C0000000004885C07409FFE00F1F8000000000C30F1F8000000000488D3D39310000488D35323100004829FE4889F048C1EE3F48C1F8034801C648D1FE741448C7C0000000004885C07408FFE0660F1F440000C30F1F8000000000803D0931000000752F5548833DD62E0000004889E5740C488B3DF22E0000E8CDEEBFFFE868FFFFFFC605E1300000015DC30F1F8000000000C30F1F8000000000E97BFFFFFF662E0F1F84000000000090C3662E0F1F8400000000000F1F440000C3662E0F1F8400000000000F1F4400004881EC580100004889FA31C0B9260000004C8D44242048833A004C89C7F348AB48C7C0484340004889100F84D801000031C0660F1F4400004889C14883C00148833CC20075F2488D04CD100000004801D0488B104889050D3100004883C0084885D20F84B00100000F1F8400000000004883FA257708488B0848894CD420488B50084883C0104885D275E5488B8C24A0000000488B842420010000488B54245048890DB13000004885C074074889058D300000488915D63000004885F60F840D01000048C7C0C842400048C7C2D04240004889304889320FB60684C0741C4883C601660F1F4400003C2F75034889320FB6064883C60184C075EE4C89C7E83E030000488BBC24E8000000E8E1FEFFFF488B84248000000048394424780F847E000000660FEFC04889E7B80700000031D248C744241000000000BE030000000F110424C744241002000000C7442408010000000F0585C07901F44889FA4C8D44241841B902000000BE02800000488D3D22100000F6420620740B4C89C80F054885C07901F44883C2084939D075E6C605CE2F0000014881C458010000C30F1F4000488B84249000000048398424880000000F856CFFFFFF4883BC24D8000000000F855DFFFFFFEBCD660F1F840000000000488BB424180100004885F60F85E2FEFFFF48C7C2C8424000488D05AF0F000048890248C7C2D0424000488902E9F9FEFFFF0F1F8000000000B808000000E93CFEFFFF660F1F44000048C705352F000000000000E98BFEFFFF0F1F84000000000055534883EC08E845FCFFFF48C7C3E83F400048C7C5F03F40004839EB730D6690FF134883C3084839EB72F54883C4085B5DC3662E0F1F8400000000000F1F400041554863C641544C8D6CC2084989D4554889C5534889FB4883EC08E8A0FFFFFF89EF4C89EA4C89E6FFD389C7E8EFFBFFFF662E0F1F8400000000000F1F44000041554863C64989FD4154488D7CC2084989D455488B324889C5E832FDFFFF4C89E289EE4C89EF488D0593FFFFFF5D415C415DFFE0662E0F1F8400000000006690C3662E0F1F8400000000000F1F44000055534883EC0848C7C3F83F400048C7C5F03F40004839EB76140F1F80000000004883EB0831C0FF134839EB77F34883C40831C05B5DE9AF030000660F1F440000534889FB48893FE88D03000085C078547507C605072E000001C7433802000000B8DA000000488D3D043000000F05894330488D05202E0000488983A8000000488D838800000048898388000000488B05AC2D000048895B104889432031C048895B185BC3B8FFFFFFFF5BC30F1F44000041554989FD415455534883EC08488B05B42D00004C8B25B52D0000488B1D9E2D0000488D840738FFFFFF49F7DC4921C44885DB7436488D6F080F1F80000000004C89E0482B4328488B73084C89E748894500488B53104883C508482B7B28E894020000488B1B4885DB75D5488B05662D0000498945004C89E04D896C24084883C4085B5D415C415DC30F1F800000000055534883EC08488B4F284C8B5F184885C90F8411020000448B0D2E2C0000488B7F204C89D831DB31F64531C0BD00008000EB230F1F44000083FA020F84AF01000083FA070F856A0100004989C04801F84883E90174178B1083FA0675DB4C89DE482B70104801F84883E90175E984DB740744890DD42B00004D85C00F84A7010000498B402049037010488D0D102D0000498B50284889350D2D00004889050E2D0000498B403048C705972C000001000000488905082D000048890D712C00004801D6488D48FF48F7DE4821CE4801D6488D90DF000000488935DB2C0000488935E42C00004883F807771548C705CB2C000008000000BAE7000000B8080000004801D6488905372C0000488D3DD02C00004883E6F84889351D2C00004881FE50010000762141BA220000004531C9B80900000031FF49C7C0FFFFFFFFBA030000000F054889C7E826FEFFFF4889004889C74889C3E84101000085C00F88BC0000000F84AA000000C7433802000000B8DA000000488D3DB72D00000F05894330488D05D32B0000488983A8000000488D838800000048898388000000488B055F2B000048895B104889432048895B184883C4085B5DC381FA51E574640F858DFEFFFF488B50284589CA4C39D20F867DFEFFFF4881FA00008000BB01000000480F47D54989D1E965FEFFFF0F1F84000000000048C7C2000000004885D20F844DFEFFFF4889D6482B7010E941FEFFFF0F1F4000C605092B000001E94AFFFFFFF44883C4085B5DC30F1F4000488B15892B0000488B35722B0000488B05832B0000E97DFEFFFF662E0F1F8400000000000F1F40004863FFB8E70000000F05BA3C000000904889D00F05EBF94889F84883FA087214F7C707000000740CA448FFCAF7C70700000075F44889D148C1E903F348A583E2077405A4FFCA75FBC34889FEBF02100000B89E0000000F05C3
+ - Name: .fini
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ Address: 0x0000000000401869
+ AddressAlign: 0x0000000000000001
+ Content: 5058C3
+ - Name: .rodata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ Address: 0x0000000000402000
+ AddressAlign: 0x0000000000000020
+ Content: 0102030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002F6465762F6E756C6C00
+ - Name: .eh_frame
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ Address: 0x0000000000402320
+ AddressAlign: 0x0000000000000008
+ Content: 1400000000000000017A5200017810011B0C070890010000100000001C000000F0ECFFFF2A0000000000000000000000
+ - Name: .init_array
+ Type: SHT_INIT_ARRAY
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Address: 0x0000000000403FE8
+ AddressAlign: 0x0000000000000008
+ EntSize: 0x0000000000000008
+ Content: '5011400000000000'
+ - Name: .fini_array
+ Type: SHT_FINI_ARRAY
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Address: 0x0000000000403FF0
+ AddressAlign: 0x0000000000000008
+ EntSize: 0x0000000000000008
+ Content: '1011400000000000'
+ - Name: .got
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Address: 0x0000000000403FF8
+ AddressAlign: 0x0000000000000008
+ Content: '0000000000000000'
+ - Name: .got.plt
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Address: 0x0000000000404000
+ AddressAlign: 0x0000000000000008
+ EntSize: 0x0000000000000008
+ Content: '000000000000000000000000000000000000000000000000'
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Address: 0x0000000000404020
+ AddressAlign: 0x0000000000000020
+ Content: '20404000000000000000000000000000000000000000000000000000000000000102030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000200'
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Address: 0x0000000000404220
+ AddressAlign: 0x0000000000000020
+ Size: 0x00000000000002D8
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ EntSize: 0x0000000000000001
+ Content: 4743433A202844656269616E2031302E322E312D33292031302E322E31203230323031323234004743433A202844656269616E2031302E322E312D362B6275696C6432292031302E322E3120323032313031313000
+Symbols:
+ - Name: dummy
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000401470
+ Size: 0x0000000000000001
+ - Name: libc_exit_fini
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000401480
+ Size: 0x000000000000003A
+ - Name: deregister_tm_clones
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x00000000004010A0
+ - Name: register_tm_clones
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x00000000004010D0
+ - Name: __do_global_dtors_aux
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000401110
+ - Name: completed.0
+ Type: STT_OBJECT
+ Section: .bss
+ Value: 0x0000000000404220
+ Size: 0x0000000000000001
+ - Name: __do_global_dtors_aux_fini_array_entry
+ Type: STT_OBJECT
+ Section: .fini_array
+ Value: 0x0000000000403FF0
+ - Name: frame_dummy
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000401150
+ - Name: __frame_dummy_init_array_entry
+ Type: STT_OBJECT
+ Section: .init_array
+ Value: 0x0000000000403FE8
+ - Name: 'dummy (1)'
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000401160
+ Size: 0x0000000000000001
+ - Name: dummy1
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000401170
+ Size: 0x0000000000000001
+ - Name: libc_start_init
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x00000000004013B0
+ Size: 0x0000000000000032
+ - Name: libc_start_main_stage2
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x00000000004013F0
+ Size: 0x0000000000000031
+ - Name: static_init_tls
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x00000000004015C0
+ Size: 0x0000000000000242
+ - Name: main_tls
+ Type: STT_OBJECT
+ Section: .bss
+ Value: 0x0000000000404360
+ Size: 0x0000000000000030
+ - Name: builtin_tls
+ Type: STT_OBJECT
+ Section: .bss
+ Value: 0x00000000004043A0
+ Size: 0x0000000000000150
+ - Name: __FRAME_END__
+ Type: STT_OBJECT
+ Section: .eh_frame
+ Value: 0x000000000040234C
+ - Name: __fini_array_end
+ Section: .fini_array
+ Value: 0x0000000000403FF8
+ - Name: __fini_array_start
+ Section: .fini_array
+ Value: 0x0000000000403FF0
+ - Name: __init_array_end
+ Section: .init_array
+ Value: 0x0000000000403FF0
+ - Name: _GLOBAL_OFFSET_TABLE_
+ Type: STT_OBJECT
+ Section: .got.plt
+ Value: 0x0000000000404000
+ - Name: __init_array_start
+ Section: .init_array
+ Value: 0x0000000000403FE8
+ - Name: .init
+ Type: STT_SECTION
+ Section: .init
+ Value: 0x0000000000401000
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Value: 0x0000000000401010
+ - Name: .fini
+ Type: STT_SECTION
+ Section: .fini
+ Value: 0x0000000000401869
+ - Name: .rodata
+ Type: STT_SECTION
+ Section: .rodata
+ Value: 0x0000000000402000
+ - Name: .eh_frame
+ Type: STT_SECTION
+ Section: .eh_frame
+ Value: 0x0000000000402320
+ - Name: .init_array
+ Type: STT_SECTION
+ Section: .init_array
+ Value: 0x0000000000403FE8
+ - Name: .fini_array
+ Type: STT_SECTION
+ Section: .fini_array
+ Value: 0x0000000000403FF0
+ - Name: .got
+ Type: STT_SECTION
+ Section: .got
+ Value: 0x0000000000403FF8
+ - Name: .got.plt
+ Type: STT_SECTION
+ Section: .got.plt
+ Value: 0x0000000000404000
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ Value: 0x0000000000404020
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ Value: 0x0000000000404220
+ - Name: .comment
+ Type: STT_SECTION
+ Section: .comment
+ - Name: __thread_list_lock
+ Type: STT_OBJECT
+ Section: .bss
+ Binding: STB_GLOBAL
+ Value: 0x00000000004044F0
+ Size: 0x0000000000000004
+ Other: [ STV_HIDDEN ]
+ - Name: __init_libc
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_GLOBAL
+ Value: 0x0000000000401180
+ Size: 0x0000000000000228
+ Other: [ STV_HIDDEN ]
+ - Name: x
+ Type: STT_OBJECT
+ Section: .bss
+ Binding: STB_GLOBAL
+ Value: 0x0000000000404240
+ Size: 0x000000000000007B
+ - Name: __hwcap
+ Type: STT_OBJECT
+ Section: .bss
+ Binding: STB_GLOBAL
+ Value: 0x00000000004042D8
+ Size: 0x0000000000000008
+ Other: [ STV_HIDDEN ]
+ - Name: memcpy
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_GLOBAL
+ Value: 0x0000000000401827
+ - Name: __TMC_END__
+ Type: STT_OBJECT
+ Section: .data
+ Binding: STB_GLOBAL
+ Value: 0x0000000000404210
+ Other: [ STV_HIDDEN ]
+ - Name: __libc
+ Type: STT_OBJECT
+ Section: .bss
+ Binding: STB_GLOBAL
+ Value: 0x00000000004042E0
+ Size: 0x0000000000000068
+ Other: [ STV_HIDDEN ]
+ - Name: __dso_handle
+ Type: STT_OBJECT
+ Section: .data
+ Binding: STB_GLOBAL
+ Value: 0x0000000000404020
+ Other: [ STV_HIDDEN ]
+ - Name: __set_thread_area
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_GLOBAL
+ Value: 0x0000000000401859
+ Other: [ STV_HIDDEN ]
+ - Name: __copy_tls
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_GLOBAL
+ Value: 0x0000000000401530
+ Size: 0x0000000000000089
+ Other: [ STV_HIDDEN ]
+ - Name: _environ
+ Type: STT_OBJECT
+ Section: .bss
+ Binding: STB_WEAK
+ Value: 0x0000000000404348
+ Size: 0x0000000000000008
+ - Name: __environ
+ Type: STT_OBJECT
+ Section: .bss
+ Binding: STB_GLOBAL
+ Value: 0x0000000000404348
+ Size: 0x0000000000000008
+ - Name: _Exit
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_GLOBAL
+ Value: 0x0000000000401810
+ Size: 0x0000000000000017
+ - Name: __init_tls
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_WEAK
+ Value: 0x00000000004015C0
+ Size: 0x0000000000000242
+ Other: [ STV_HIDDEN ]
+ - Name: _init
+ Section: .init
+ Binding: STB_GLOBAL
+ Value: 0x0000000000401000
+ - Name: __funcs_on_exit
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_WEAK
+ Value: 0x0000000000401470
+ Size: 0x0000000000000001
+ Other: [ STV_HIDDEN ]
+ - Name: __memcpy_fwd
+ Section: .text
+ Binding: STB_GLOBAL
+ Value: 0x0000000000401827
+ Other: [ STV_HIDDEN ]
+ - Name: environ
+ Type: STT_OBJECT
+ Section: .bss
+ Binding: STB_WEAK
+ Value: 0x0000000000404348
+ Size: 0x0000000000000008
+ - Name: z
+ Type: STT_OBJECT
+ Section: .rodata
+ Binding: STB_GLOBAL
+ Value: 0x0000000000402000
+ Size: 0x0000000000000315
+ - Name: ___environ
+ Type: STT_OBJECT
+ Section: .bss
+ Binding: STB_WEAK
+ Value: 0x0000000000404348
+ Size: 0x0000000000000008
+ - Name: __progname
+ Type: STT_OBJECT
+ Section: .bss
+ Binding: STB_GLOBAL
+ Value: 0x00000000004042D0
+ Size: 0x0000000000000008
+ - Name: _start
+ Section: .text
+ Binding: STB_GLOBAL
+ Value: 0x000000000040105A
+ - Name: _start_c
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_GLOBAL
+ Value: 0x0000000000401070
+ Size: 0x0000000000000024
+ - Name: program_invocation_short_name
+ Type: STT_OBJECT
+ Section: .bss
+ Binding: STB_WEAK
+ Value: 0x00000000004042D0
+ Size: 0x0000000000000008
+ - Name: __libc_start_init
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_WEAK
+ Value: 0x00000000004013B0
+ Size: 0x0000000000000032
+ Other: [ STV_HIDDEN ]
+ - Name: __init_tp
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_GLOBAL
+ Value: 0x00000000004014C0
+ Size: 0x000000000000006B
+ Other: [ STV_HIDDEN ]
+ - Name: __init_ssp
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_WEAK
+ Value: 0x0000000000401170
+ Size: 0x0000000000000001
+ Other: [ STV_HIDDEN ]
+ - Name: __bss_start
+ Section: .bss
+ Binding: STB_GLOBAL
+ Value: 0x0000000000404210
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_GLOBAL
+ Value: 0x0000000000401030
+ Size: 0x000000000000002A
+ - Name: __stdio_exit
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_WEAK
+ Value: 0x0000000000401470
+ Size: 0x0000000000000001
+ - Name: y
+ Type: STT_OBJECT
+ Section: .data
+ Binding: STB_GLOBAL
+ Value: 0x0000000000404040
+ Size: 0x00000000000001C8
+ - Name: _fini
+ Section: .fini
+ Binding: STB_GLOBAL
+ Value: 0x0000000000401869
+ - Name: __libc_exit_fini
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_WEAK
+ Value: 0x0000000000401480
+ Size: 0x000000000000003A
+ Other: [ STV_HIDDEN ]
+ - Name: _edata
+ Section: .data
+ Binding: STB_GLOBAL
+ Value: 0x0000000000404210
+ - Name: _end
+ Section: .bss
+ Binding: STB_GLOBAL
+ Value: 0x00000000004044F8
+ - Name: exit
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_GLOBAL
+ Value: 0x0000000000401010
+ Size: 0x000000000000001B
+ - Name: __libc_start_main
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_GLOBAL
+ Value: 0x0000000000401430
+ Size: 0x0000000000000034
+ - Name: program_invocation_name
+ Type: STT_OBJECT
+ Section: .bss
+ Binding: STB_WEAK
+ Value: 0x00000000004042C8
+ Size: 0x0000000000000008
+ - Name: __default_stacksize
+ Type: STT_OBJECT
+ Section: .data
+ Binding: STB_GLOBAL
+ Value: 0x000000000040420C
+ Size: 0x0000000000000004
+ Other: [ STV_HIDDEN ]
+ - Name: __default_guardsize
+ Type: STT_OBJECT
+ Section: .data
+ Binding: STB_GLOBAL
+ Value: 0x0000000000404208
+ Size: 0x0000000000000004
+ Other: [ STV_HIDDEN ]
+ - Name: __sysinfo
+ Type: STT_OBJECT
+ Section: .bss
+ Binding: STB_GLOBAL
+ Value: 0x00000000004042C0
+ Size: 0x0000000000000008
+ Other: [ STV_HIDDEN ]
+ - Name: __progname_full
+ Type: STT_OBJECT
+ Section: .bss
+ Binding: STB_GLOBAL
+ Value: 0x00000000004042C8
+ Size: 0x0000000000000008
+...
+
+$ bloaty --raw-map 1
+Maps for 1:
+
+FILE MAP:
+0000-0040 64 [ELF Headers]
+0040-0078 56 [LOAD #0 [R]]
+0078-00b0 56 [LOAD #1 [RX]]
+00b0-00e8 56 [LOAD #2 [R]]
+00e8-0120 56 [LOAD #3 [RW]]
+0120-0158 56 [LOAD #4 [RW]]
+0158-0190 56 [LOAD #5 [R]]
+0190-01a0 16 .init
+01a0-09f9 2137 .text
+09f9-0a00 7 .fini
+0a00-0d20 800 .rodata
+0d20-0d50 48 .eh_frame
+0d50-0d58 8 .init_array
+0d58-0d60 8 .fini_array
+0d60-0d68 8 .got
+0d68-0d80 24 .got.plt
+0d80-0f78 504 .data
+0f78-0f80 8 .data
+0f80-0fd8 88 .comment
+0fd8-1710 1848 .symtab
+1710-1a43 819 .strtab
+1a43-1ac0 125 .shstrtab
+1ac0-1b00 64 [ELF Headers]
+1b00-1b40 64 .init
+1b40-1b80 64 .text
+1b80-1bc0 64 .fini
+1bc0-1c00 64 .rodata
+1c00-1c40 64 .eh_frame
+1c40-1c80 64 .init_array
+1c80-1cc0 64 .fini_array
+1cc0-1d00 64 .got
+1d00-1d40 64 .got.plt
+1d40-1d80 64 .data
+1d80-1dc0 64 .bss
+1dc0-1e00 64 .comment
+1e00-1e40 64 .symtab
+1e40-1e80 64 .strtab
+1e80-1ec0 64 .shstrtab
+
+VM MAP:
+000000-401000 4198400 [-- Nothing mapped --]
+401000-401010 16 .init
+401010-401869 2137 .text
+401869-40186c 3 .fini
+40186c-402000 1940 [-- Nothing mapped --]
+402000-402320 800 .rodata
+402320-402350 48 .eh_frame
+402350-403fe8 7320 [-- Nothing mapped --]
+403fe8-403ff0 8 .init_array
+403ff0-403ff8 8 .fini_array
+403ff8-404000 8 .got
+404000-404020 32 .got.plt
+404020-404220 512 .data
+404220-4044f8 728 .bss
+
diff --git a/tests/elf/sections/normal-obj.test b/tests/elf/sections/normal-obj.test
new file mode 100644
index 0000000..1473507
--- /dev/null
+++ b/tests/elf/sections/normal-obj.test
@@ -0,0 +1,125 @@
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 554889E5B8050000005DC3
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000010
+ Size: 0x000000000000007B
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000010
+ Content: '010203000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ - Name: .rodata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000010
+ Content: '010203000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ EntSize: 0x0000000000000001
+ Content: 0044656269616E20636C616E672076657273696F6E2031312E302E312D3200
+ - Name: .note.GNU-stack
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000001
+ - Name: .eh_frame
+ Type: SHT_X86_64_UNWIND
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000008
+ Content: 1400000000000000017A5200017810011B0C0708900100001C0000001C000000000000000B00000000410E108602430D06460C0708000000
+ - Name: .rela.eh_frame
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .eh_frame
+ Relocations:
+ - Offset: 0x0000000000000020
+ Symbol: .text
+ Type: R_X86_64_PC32
+ - Name: .llvm_addrsig
+ Type: SHT_LLVM_ADDRSIG
+ Flags: [ SHF_EXCLUDE ]
+ Link: .symtab
+ AddressAlign: 0x0000000000000001
+ Symbols: [ ]
+Symbols:
+ - Name: test.c
+ Type: STT_FILE
+ Index: SHN_ABS
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: foobar
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_GLOBAL
+ Size: 0x000000000000000B
+ - Name: x
+ Type: STT_OBJECT
+ Section: .bss
+ Binding: STB_GLOBAL
+ Size: 0x000000000000007B
+ - Name: y
+ Type: STT_OBJECT
+ Section: .data
+ Binding: STB_GLOBAL
+ Size: 0x00000000000001C8
+ - Name: z
+ Type: STT_OBJECT
+ Section: .rodata
+ Binding: STB_GLOBAL
+ Size: 0x0000000000000315
+...
+
+$ bloaty --raw-map 1
+Maps for 1:
+
+FILE MAP:
+000-040 64 [ELF Headers]
+040-050 16 .text
+050-220 464 .data
+220-535 789 .rodata
+535-558 35 .comment
+558-590 56 .eh_frame
+590-5a8 24 .rela.eh_frame
+5a8-650 168 .symtab
+650-66b 27 .strtab
+66b-6d8 109 .shstrtab
+6d8-718 64 [ELF Headers]
+718-758 64 .text
+758-798 64 .bss
+798-7d8 64 .data
+7d8-818 64 .rodata
+818-858 64 .comment
+858-898 64 .note.GNU-stack
+898-8d8 64 .eh_frame
+8d8-918 64 .rela.eh_frame
+918-958 64 .llvm_addrsig
+958-998 64 .symtab
+998-9d8 64 .strtab
+9d8-a18 64 .shstrtab
+
+VM MAP:
+00000000000-10000000000 1099511627776 [-- Nothing mapped --]
+10000000000-1000000000b 11 .text
+1000000000b-20000000000 1099511627765 [-- Nothing mapped --]
+20000000000-2000000007b 123 .bss
+2000000007b-30000000000 1099511627653 [-- Nothing mapped --]
+30000000000-300000001c8 456 .data
+300000001c8-40000000000 1099511627320 [-- Nothing mapped --]
+40000000000-40000000315 789 .rodata
+40000000315-70000000000 3298534882539 [-- Nothing mapped --]
+70000000000-70000000038 56 .eh_frame
+
diff --git a/tests/elf/sections/shn-xindex.test b/tests/elf/sections/shn-xindex.test
new file mode 100644
index 0000000..ed068f3
--- /dev/null
+++ b/tests/elf/sections/shn-xindex.test
@@ -0,0 +1,36 @@
+# Tests two special cases for the ELF format:
+# - If the section count in the ELF headers is 0, then, the true value
+# is read out of section 0.
+# - If the section string index in the ELF headers is SHN_XINDEX, the
+# true value is read out of section 0.
+#
+# These special cases are documented here:
+# https://docs.oracle.com/cd/E19683-01/817-3677/chapter6-94076/index.html
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+ EShNum: 0
+ EShStrNdx: 0xffff ## SHN_XINDEX
+Sections:
+ - Type: SHT_NULL
+ Link: .shstrtab
+ Size: 0x3
+...
+
+$ bloaty --raw-map 1
+Maps for 1:
+
+FILE MAP:
+000-040 64 [ELF Headers]
+040-041 1 .strtab
+041-058 23 .shstrtab
+058-098 64 [ELF Headers]
+098-0d8 64 .strtab
+0d8-118 64 .shstrtab
+
+VM MAP:
+
diff --git a/tests/tester.py b/tests/tester.py
new file mode 100755
index 0000000..556d579
--- /dev/null
+++ b/tests/tester.py
@@ -0,0 +1,72 @@
+#!/usr/bin/python3
+
+import os
+import glob
+import re
+import sys
+import subprocess
+import shutil
+import tempfile
+
+successes = 0
+failures = []
+
+def TestFile(filename):
+ cwd = os.getcwd()
+ abspath = os.path.abspath(filename)
+ global successes
+ global failures
+ with open(abspath) as f:
+ print(filename)
+ tmpdir = tempfile.mkdtemp(prefix="/tmp/bloaty-")
+ contents = f.read()
+ file_count = len(re.findall(r'^---', contents, flags=re.MULTILINE))
+ for i in range(1, file_count + 1):
+ subprocess.check_call('yaml2obj {0} --docnum={1} > {1}'.format(abspath, str(i)), shell=True, cwd=tmpdir)
+ lines = contents.splitlines()
+ while len(lines[0]) == 0 or lines[0][0] != '$':
+ lines.pop(0)
+ bloaty_invocation = os.path.join(cwd, lines[0][2:]) + ' > actual'
+ lines.pop(0)
+ expected_output = "\n".join(lines) + "\n"
+ failure = None
+ if subprocess.call(bloaty_invocation, shell=True, cwd=tmpdir) != 0:
+ failure = "CRASHED"
+ else:
+ with open(os.path.join(tmpdir, 'expected'), 'w') as expected:
+ expected.write(expected_output)
+ if subprocess.call('diff -u expected actual', shell=True, cwd=tmpdir) != 0:
+ failure = "FAILED"
+
+ if failure:
+ print("{}: {}".format(failure, filename))
+ print("{}: output in {}".format(failure, tmpdir))
+ failures.append((filename, tmpdir))
+ else:
+ successes += 1
+ shutil.rmtree(tmpdir)
+
+def TestArg(arg):
+ if os.path.isdir(arg):
+ files = sorted(glob.glob(os.path.join(arg, "**/*.test"), recursive=True))
+ for file in files:
+ TestFile(file)
+ else:
+ TestFile(arg)
+
+args = sys.argv[1:]
+
+if not args:
+ print("Usage: tester.py <FILE-OR-DIR> ...")
+ sys.exit(1)
+
+for arg in sys.argv[1:]:
+ TestArg(arg)
+
+if not failures:
+ print("SUCCESS: {} test(s) passed".format(successes))
+else:
+ print("\nFAILURE: {} tests passed, {} tests failed:".format(successes, len(failures)))
+ for failure in failures:
+ print(" - {} (output in {})".format(*failure))
+ sys.exit(1)