18 #include "absl/numeric/int128.h"
19 #include "absl/strings/escaping.h"
20 #include "absl/strings/string_view.h"
21 #include "absl/strings/substitute.h"
45 T operator()(
T val) {
return val; }
51 THROWF(
"couldn't convert string '$0' to integer.",
str);
71 bool IsOpen() {
return ok_; }
127 const ElfFile& elf()
const {
return *
elf_; }
130 friend class ElfFile;
139 NoteIter(
const Section&
section)
165 bool is_64bit()
const {
return is_64bit_; }
168 template <
class T32,
class T64,
class Munger>
175 friend class Section;
190 template <
class T32,
class T64,
class Munger>
193 if (
elf_.is_64bit() &&
elf_.is_native_endian()) {
204 template <
class T32,
class T64,
class Munger>
243 template <
class From,
class Func>
263 template <
class From,
class Func>
279 template <
class From,
class Func>
293 template <
class From,
class Func>
305 template <
class From,
class Func>
313 template <
class From,
class Func>
322 template <
class From,
class Func>
331 template <
class From,
class Func>
339 template <
class T32,
class T64,
class Munger>
344 if (
elf_.is_64bit()) {
345 assert(!
elf_.is_native_endian());
347 Munger()(*
out,
out, ByteSwapFunc());
351 if (
elf_.is_native_endian()) {
352 Munger()(data32,
out, NullFunc());
354 Munger()(data32,
out, ByteSwapFunc());
363 return elf_->section_name_table_.ReadString(
header_.sh_name);
370 THROWF(
"can't read index $0 from strtab, total size is $1",
index,
376 const char* null_pos =
377 static_cast<const char*
>(memchr(
ret.data(),
'\0',
ret.size()));
379 if (null_pos == NULL) {
380 THROW(
"no NULL terminator found");
383 size_t len = null_pos -
ret.data();
388 Elf64_Word ElfFile::Section::GetEntryCount()
const {
390 THROW(
"sh_entsize is zero");
452 if (memcmp(ident,
"\177ELF", 4) != 0) {
480 ReadStruct<Elf32_Ehdr>(entire_file(), 0, EhdrMunger(), &
range, &
header_);
483 bool has_section0 = 0;
491 ReadSection(0, §ion0);
515 THROW(
"section string index pointed to non-strtab");
524 THROWF(
"segment $0 doesn't exist, only $1 segments",
index,
529 ReadStruct<Elf32_Phdr>(
532 PhdrMunger(), &segment->range_,
header);
533 segment->contents_ = GetRegion(
header->p_offset,
header->p_filesz);
538 THROWF(
"tried to read section $0, but there are only $1",
index,
543 ReadStruct<Elf32_Shdr>(
602 MemberReader(
const ArFile& ar) :
remaining_(ar.contents()) {}
603 bool ReadMember(MemberFile*
file);
608 n = (
n % 2 == 0 ?
n :
n + 1);
610 THROW(
"premature end of file");
625 static constexpr
const char*
kMagic =
"!<arch>\n";
629 bool ArFile::MemberReader::ReadMember(MemberFile*
file) {
632 char modified_timestamp[12];
643 THROW(
"Premature EOF in AR data");
651 file->
size = StringViewToSize(size_str);
653 file->file_type = MemberFile::kNormal;
655 if (file_id[0] ==
'/') {
657 if (file_id[1] ==
' ') {
658 file->file_type = MemberFile::kSymbolTable;
659 }
else if (file_id[1] ==
'/') {
660 file->file_type = MemberFile::kLongFilenameTable;
662 }
else if (isdigit(file_id[1])) {
663 size_t offset = StringViewToSize(file_id.substr(1));
666 if (
end == std::string::npos) {
667 THROW(
"Unterminated long filename");
672 THROW(
"Unexpected special filename in AR archive");
676 size_t slash = file_id.find(
'/');
678 if (slash == std::string::npos) {
679 THROW(
"BSD-style AR not yet implemented");
682 file->filename = file_id.substr(0, slash);
697 template <
class Func>
699 ArFile ar_file(
file.data());
702 if (ar_file.IsOpen()) {
703 ArFile::MemberFile
member;
704 ArFile::MemberReader
reader(ar_file);
706 MaybeAddFileRange(
"ar_archive",
sink,
"[AR Headers]", ar_file.magic());
709 MaybeAddFileRange(
"ar_archive",
sink,
"[AR Headers]",
member.header);
710 switch (
member.file_type) {
711 case ArFile::MemberFile::kNormal: {
712 ElfFile elf(
member.contents);
715 index_base += elf.section_count();
717 MaybeAddFileRange(
"ar_archive",
sink,
"[AR Non-ELF Member File]",
722 case ArFile::MemberFile::kSymbolTable:
723 MaybeAddFileRange(
"ar_archive",
sink,
"[AR Symbol Table]",
726 case ArFile::MemberFile::kLongFilenameTable:
727 MaybeAddFileRange(
"ar_archive",
sink,
"[AR Headers]",
733 ElfFile elf(
file.data());
735 THROWF(
"Not an ELF or Archive file: $0",
file.filename());
738 func(elf,
file.filename(), index_base);
749 if (ndx >= 1 << 24) {
750 THROW(
"ndx overflow: too many sections");
753 THROW(
"address overflow: section too big");
755 return (ndx << 40) |
addr;
768 return IsArchiveFile(
data) || (elf.IsOpen() && elf.header().e_type ==
ET_REL);
771 static void CheckNotObject(
const char* source, RangeSink*
sink) {
772 if (IsObjectFile(
sink->input_file().data())) {
774 "can't use data source '$0' on object files (only binaries and shared "
825 "Unable to map to capstone target, disassembly will be "
833 bool capstone_available =
true;
834 ForEachElf(
file,
nullptr,
835 [&capstone_available,
arch,
mode](
const ElfFile& elf,
840 capstone_available &=
841 ElfMachineToCapstone(elf.header().e_machine,
arch,
mode);
843 return capstone_available;
846 static void ReadELFSymbols(
const InputFile&
file, RangeSink*
sink,
848 bool is_object = IsObjectFile(
file.data());
849 DisassemblyInfo info;
850 DisassemblyInfo* infop = &info;
851 bool capstone_available = ReadElfArchMode(
file, &info.arch, &info.mode);
868 ElfFile::Section strtab_section;
869 elf.ReadSection(
section.header().sh_link, &strtab_section);
871 THROW(
"symtab section pointed to non-strtab section");
877 section.ReadSymbol(i, &sym,
nullptr);
895 if (
sink && !(capstone_available && disassemble)) {
896 sink->AddVMRangeAllowAlias(
897 "elf_symbols", full_addr, sym.
st_size,
902 std::make_pair(
name, std::make_pair(full_addr, sym.
st_size)));
904 if (capstone_available && disassemble &&
906 if (verbose_level > 1) {
907 printf(
"Disassembling function: %s\n", name.data());
909 infop->text =
sink->TranslateVMToFile(full_addr).substr(0, sym.
st_size);
910 infop->start_address = full_addr;
918 static void ReadELFSymbolTableEntries(
const ElfFile& elf,
919 const ElfFile::Section&
section,
920 uint64_t index_base,
bool is_object,
926 ElfFile::Section strtab_section;
927 elf.ReadSection(
section.header().sh_link, &strtab_section);
928 if (strtab_section.header().sh_type !=
SHT_STRTAB) {
929 THROW(
"symtab section pointed to non-strtab section");
935 section.ReadSymbol(i, &sym, &sym_range);
948 sink->AddFileRangeForVMAddr(
"elf_symtab_name", full_addr,
name);
949 sink->AddFileRangeForVMAddr(
"elf_symtab_sym", full_addr, sym_range);
953 static void ReadELFRelaEntries(
const ElfFile::Section&
section,
954 uint64_t index_base,
bool is_object,
961 section.ReadRelocationWithAddend(i, &rela, &rela_range);
963 ToVMAddr(rela.
r_offset, index_base + sh_info, is_object);
964 sink->AddFileRangeForVMAddr(
"elf_rela", full_addr, rela_range);
974 static void ReadELFTables(
const InputFile&
file, RangeSink*
sink) {
975 bool is_object = IsObjectFile(
file.data());
979 ReadELFSymbols(
file,
sink,
nullptr,
true);
989 switch (
section.header().sh_type) {
992 ReadELFSymbolTableEntries(elf, section, index_base,
996 ReadELFRelaEntries(section, index_base, is_object, sink);
1006 ReadEhFrame(section.contents(), sink);
1007 }
else if (
section.GetName() ==
".eh_frame_hdr") {
1008 ReadEhFrameHdr(section.contents(), sink);
1014 enum ReportSectionsBy {
1015 kReportBySectionName,
1016 kReportByEscapedSectionName,
1018 kReportByArchiveMember,
1021 static void DoReadELFSections(RangeSink*
sink,
enum ReportSectionsBy report_by) {
1022 bool is_object = IsObjectFile(
sink->input_file().data());
1026 std::string name_from_flags;
1027 for (Elf64_Xword i = 1; i < elf.section_count(); i++) {
1028 ElfFile::Section section;
1029 elf.ReadSection(i, §ion);
1030 string_view name = section.GetName();
1032 if (name.size() == 0) {
1036 const auto& header = section.header();
1037 auto addr = header.sh_addr;
1038 auto size = header.sh_size;
1039 auto filesize = (header.sh_type == SHT_NOBITS) ? 0 : size;
1040 auto vmsize = (header.sh_flags & SHF_ALLOC) ? size : 0;
1042 string_view contents = StrictSubstr(section.contents(), 0, filesize);
1044 uint64_t full_addr = ToVMAddr(addr, index_base + i, is_object);
1046 if (report_by == kReportByFlags) {
1047 name_from_flags = std::string(name);
1049 name_from_flags =
"Section [";
1051 if (header.sh_flags & SHF_ALLOC) {
1052 name_from_flags +=
'A';
1055 if (header.sh_flags & SHF_WRITE) {
1056 name_from_flags +=
'W';
1059 if (header.sh_flags & SHF_EXECINSTR) {
1060 name_from_flags +=
'X';
1063 name_from_flags +=
']';
1064 sink->AddRange(
"elf_section", name_from_flags, full_addr, vmsize,
1066 } else if (report_by == kReportBySectionName) {
1067 sink->AddRange(
"elf_section", name, full_addr, vmsize, contents);
1068 } else if (report_by == kReportByEscapedSectionName) {
1069 sink->AddRange(
"elf_section",
1070 std::string(
"[section ") + std::string(name) +
"]",
1071 full_addr, vmsize, contents);
1072 } else if (report_by == kReportByArchiveMember) {
1073 sink->AddRange(
"elf_section", filename, full_addr, vmsize,
1078 if (report_by == kReportByArchiveMember) {
1080 sink->AddFileRange(
"unmapped_armember",
filename, elf.entire_file());
1085 enum ReportSegmentsBy {
1086 kReportBySegmentName,
1087 kReportByEscapedSegmentName,
1091 ReportSegmentsBy report_by) {
1092 const auto&
header = segment.header();
1123 if (report_by == kReportByEscapedSegmentName) {
1130 static void DoReadELFSegments(RangeSink*
sink, ReportSegmentsBy report_by) {
1131 ForEachElf(
sink->input_file(),
sink,
1134 for (Elf64_Xword i = 0; i < elf.header().e_phnum; i++) {
1135 ElfFile::Segment segment;
1136 elf.ReadSegment(i, &segment);
1137 std::string name = GetSegmentName(segment, i, report_by);
1139 if (segment.header().p_type != PT_LOAD) {
1143 sink->AddRange(
"elf_segment", name, segment.header().p_vaddr,
1144 segment.header().p_memsz, segment.contents());
1148 ForEachElf(
sink->input_file(),
sink,
1151 for (Elf64_Xword i = 0; i < elf.header().e_phnum; i++) {
1152 ElfFile::Segment segment;
1153 elf.ReadSegment(i, &segment);
1154 const auto& header = segment.header();
1155 if (header.p_type != PT_TLS) continue;
1156 std::string name =
"TLS";
1157 sink->AddRange(
"elf_segment",
"TLS", header.p_vaddr,
1158 header.p_memsz, segment.contents());
1163 static void ReadELFSegments(RangeSink*
sink) {
1164 if (IsObjectFile(
sink->input_file().data())) {
1171 DoReadELFSections(
sink, kReportByFlags);
1173 DoReadELFSegments(
sink, kReportBySegmentName);
1181 static void ReadDWARFSections(
const InputFile &
file, dwarf::File *dwarf,
1183 ElfFile elf(
file.data());
1184 assert(elf.IsOpen());
1202 uncompressed_size = chdr.
ch_size;
1206 if (
name.find(
".debug_") == 0) {
1208 }
else if (
name.find(
".zdebug_") == 0) {
1215 uncompressed_size = ReadBigEndian<uint64_t>(&
contents);
1219 if (uncompressed_size) {
1230 if (
sink->IsBaseMap() ||
sink->data_source() != DataSource::kSegments) {
1231 if (!
sink->IsBaseMap()) {
1232 DoReadELFSections(
sink, kReportByEscapedSectionName);
1234 ForEachElf(
sink->input_file(),
sink,
1237 sink->AddFileRange(
"elf_catchall",
"[ELF Header]",
1238 elf.header_region());
1239 sink->AddFileRange(
"elf_catchall",
"[ELF Section Headers]",
1240 elf.section_headers());
1241 sink->AddFileRange(
"elf_catchall",
"[ELF Program Headers]",
1242 elf.segment_headers());
1245 DoReadELFSegments(
sink, kReportByEscapedSegmentName);
1249 sink->AddFileRange(
"elf_catchall",
"[Unmapped]",
sink->input_file().data());
1252 class ElfObjectFile :
public ObjectFile {
1254 ElfObjectFile(std::unique_ptr<InputFile>
file)
1264 assert(elf.IsOpen());
1272 for (ElfFile::NoteIter notes(
section); !notes.IsDone(); notes.Next()) {
1283 void ProcessFile(
const std::vector<RangeSink*>& sinks)
const override {
1284 for (
auto sink : sinks) {
1286 printf(
"Scanning source %d\n", (
int)
sink->data_source());
1288 switch (
sink->data_source()) {
1289 case DataSource::kSegments:
1290 ReadELFSegments(
sink);
1292 case DataSource::kSections:
1293 DoReadELFSections(
sink, kReportBySectionName);
1295 case DataSource::kRawSymbols:
1296 case DataSource::kShortSymbols:
1297 case DataSource::kFullSymbols:
1298 ReadELFSymbols(debug_file().
file_data(),
sink,
nullptr,
false);
1300 case DataSource::kArchiveMembers:
1301 DoReadELFSections(
sink, kReportByArchiveMember);
1303 case DataSource::kCompileUnits: {
1304 CheckNotObject(
"compileunits",
sink);
1307 NameMunger empty_munger;
1308 RangeSink symbol_sink(&debug_file().
file_data(),
1310 DataSource::kRawSymbols,
1311 &sinks[0]->MapAtIndex(0),
nullptr);
1312 symbol_sink.AddOutput(&symbol_map, &empty_munger);
1320 case DataSource::kInlines: {
1321 CheckNotObject(
"lineinfo",
sink);
1325 DoReadELFSections(
sink, kReportByEscapedSectionName);
1329 THROW(
"unknown data source");
1332 switch (
sink->data_source()) {
1333 case DataSource::kSegments:
1334 case DataSource::kSections:
1335 case DataSource::kArchiveMembers:
1339 ReadELFTables(
sink->input_file(),
sink);
1349 DisassemblyInfo* info)
const override {
1350 return DoGetDisassemblyInfo(&symbol, symbol_source, info);
1355 DisassemblyInfo* info)
const {
1359 NameMunger empty_munger;
1360 RangeSink base_sink(&
file_data(), bloaty::Options(), DataSource::kSegments,
1362 base_sink.AddOutput(&base_map, &empty_munger);
1363 std::vector<RangeSink*> sink_ptrs{&base_sink};
1368 RangeSink symbol_sink(&
file_data(), bloaty::Options(), symbol_source,
1369 &base_map,
nullptr);
1370 symbol_sink.AddOutput(&info->symbol_map, &empty_munger);
1371 ReadELFSymbols(debug_file().
file_data(), &symbol_sink, &symbol_table,
1375 auto entry = symbol_table.find(*symbol);
1376 if (entry == symbol_table.end()) {
1378 if (entry == symbol_table.end()) {
1382 uint64_t vmaddr = entry->second.first;
1389 if (!base_map.vm_map.Translate(vmaddr, &fileoff)) {
1390 THROWF(
"Couldn't translate VM address for function $0", symbol);
1394 info->start_address = vmaddr;
1397 return ReadElfArchMode(
file_data(), &info->arch, &info->mode);
1404 ElfFile elf(
file->data());
1405 ArFile ar(
file->data());
1406 if (elf.IsOpen() || ar.IsOpen()) {
1407 return std::unique_ptr<ObjectFile>(
new ElfObjectFile(
std::move(
file)));
1413 (void)&ElfFile::FindSectionByName;
1414 (void)&ElfFile::Section::ReadRelocation;