//===------ utils/elf2yaml.cpp - obj2yaml conversion tool -------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "Error.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/ObjectYAML/ELFYAML.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/YAMLTraits.h" using namespace llvm; namespace { template class ELFDumper { typedef object::Elf_Sym_Impl Elf_Sym; typedef typename ELFT::Dyn Elf_Dyn; typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Word Elf_Word; typedef typename ELFT::Rel Elf_Rel; typedef typename ELFT::Rela Elf_Rela; using Elf_Relr = typename ELFT::Relr; using Elf_Nhdr = typename ELFT::Nhdr; using Elf_Note = typename ELFT::Note; ArrayRef Sections; ArrayRef SymTable; DenseMap UsedSectionNames; std::vector SectionNames; DenseMap UsedSymbolNames; std::vector SymbolNames; BumpPtrAllocator StringAllocator; Expected getUniquedSectionName(const Elf_Shdr *Sec); Expected getUniquedSymbolName(const Elf_Sym *Sym, StringRef StrTable, const Elf_Shdr *SymTab); Expected getSymbolName(uint32_t SymtabNdx, uint32_t SymbolNdx); const object::ELFFile &Obj; ArrayRef ShndxTable; Error dumpSymbols(const Elf_Shdr *Symtab, std::vector &Symbols); Error dumpSymbol(const Elf_Sym *Sym, const Elf_Shdr *SymTab, StringRef StrTable, ELFYAML::Symbol &S); Error dumpCommonSection(const Elf_Shdr *Shdr, ELFYAML::Section &S); Error dumpCommonRelocationSection(const Elf_Shdr *Shdr, ELFYAML::RelocationSection &S); template Error dumpRelocation(const RelT *Rel, const Elf_Shdr *SymTab, ELFYAML::Relocation &R); Expected dumpAddrsigSection(const Elf_Shdr *Shdr); Expected dumpLinkerOptionsSection(const Elf_Shdr *Shdr); Expected dumpDependentLibrariesSection(const Elf_Shdr *Shdr); Expected dumpCallGraphProfileSection(const Elf_Shdr *Shdr); Expected dumpDynamicSection(const Elf_Shdr *Shdr); Expected dumpRelocSection(const Elf_Shdr *Shdr); Expected dumpRelrSection(const Elf_Shdr *Shdr); Expected dumpContentSection(const Elf_Shdr *Shdr); Expected dumpSymtabShndxSection(const Elf_Shdr *Shdr); Expected dumpNoBitsSection(const Elf_Shdr *Shdr); Expected dumpHashSection(const Elf_Shdr *Shdr); Expected dumpNoteSection(const Elf_Shdr *Shdr); Expected dumpGnuHashSection(const Elf_Shdr *Shdr); Expected dumpVerdefSection(const Elf_Shdr *Shdr); Expected dumpSymverSection(const Elf_Shdr *Shdr); Expected dumpVerneedSection(const Elf_Shdr *Shdr); Expected dumpGroup(const Elf_Shdr *Shdr); Expected dumpMipsABIFlags(const Elf_Shdr *Shdr); Expected dumpStackSizesSection(const Elf_Shdr *Shdr); Expected dumpSpecialSection(const Elf_Shdr *Shdr); public: ELFDumper(const object::ELFFile &O); Expected dump(); }; } template ELFDumper::ELFDumper(const object::ELFFile &O) : Obj(O) {} template Expected ELFDumper::getUniquedSectionName(const Elf_Shdr *Sec) { unsigned SecIndex = Sec - &Sections[0]; assert(&Sections[SecIndex] == Sec); if (!SectionNames[SecIndex].empty()) return SectionNames[SecIndex]; auto NameOrErr = Obj.getSectionName(Sec); if (!NameOrErr) return NameOrErr; StringRef Name = *NameOrErr; std::string &Ret = SectionNames[SecIndex]; auto It = UsedSectionNames.insert({Name, 0}); if (!It.second) Ret = (Name + " [" + Twine(++It.first->second) + "]").str(); else Ret = std::string(Name); return Ret; } template Expected ELFDumper::getUniquedSymbolName(const Elf_Sym *Sym, StringRef StrTable, const Elf_Shdr *SymTab) { Expected SymbolNameOrErr = Sym->getName(StrTable); if (!SymbolNameOrErr) return SymbolNameOrErr; StringRef Name = *SymbolNameOrErr; if (Name.empty() && Sym->getType() == ELF::STT_SECTION) { auto ShdrOrErr = Obj.getSection(Sym, SymTab, ShndxTable); if (!ShdrOrErr) return ShdrOrErr.takeError(); return getUniquedSectionName(*ShdrOrErr); } // Symbols in .symtab can have duplicate names. For example, it is a common // situation for local symbols in a relocatable object. Here we assign unique // suffixes for such symbols so that we can differentiate them. if (SymTab->sh_type == ELF::SHT_SYMTAB) { unsigned Index = Sym - SymTable.data(); if (!SymbolNames[Index].empty()) return SymbolNames[Index]; auto It = UsedSymbolNames.insert({Name, 0}); if (!It.second) SymbolNames[Index] = (Name + " [" + Twine(++It.first->second) + "]").str(); else SymbolNames[Index] = std::string(Name); return SymbolNames[Index]; } return Name; } template Expected ELFDumper::dump() { auto Y = std::make_unique(); // Dump header. We do not dump SHEntSize, SHOff, SHNum and SHStrNdx fields. // When not explicitly set, the values are set by yaml2obj automatically // and there is no need to dump them here. Y->Header.Class = ELFYAML::ELF_ELFCLASS(Obj.getHeader()->getFileClass()); Y->Header.Data = ELFYAML::ELF_ELFDATA(Obj.getHeader()->getDataEncoding()); Y->Header.OSABI = Obj.getHeader()->e_ident[ELF::EI_OSABI]; Y->Header.ABIVersion = Obj.getHeader()->e_ident[ELF::EI_ABIVERSION]; Y->Header.Type = Obj.getHeader()->e_type; Y->Header.Machine = Obj.getHeader()->e_machine; Y->Header.Flags = Obj.getHeader()->e_flags; Y->Header.Entry = Obj.getHeader()->e_entry; // Dump sections auto SectionsOrErr = Obj.sections(); if (!SectionsOrErr) return SectionsOrErr.takeError(); Sections = *SectionsOrErr; SectionNames.resize(Sections.size()); // Dump symbols. We need to do this early because other sections might want // to access the deduplicated symbol names that we also create here. const Elf_Shdr *SymTab = nullptr; const Elf_Shdr *SymTabShndx = nullptr; const Elf_Shdr *DynSymTab = nullptr; for (const Elf_Shdr &Sec : Sections) { if (Sec.sh_type == ELF::SHT_SYMTAB) { SymTab = &Sec; } else if (Sec.sh_type == ELF::SHT_DYNSYM) { DynSymTab = &Sec; } else if (Sec.sh_type == ELF::SHT_SYMTAB_SHNDX) { // ABI allows us to have one SHT_SYMTAB_SHNDX for each symbol table. // We only support having the SHT_SYMTAB_SHNDX for SHT_SYMTAB now. if (SymTabShndx) return createStringError(obj2yaml_error::not_implemented, "multiple SHT_SYMTAB_SHNDX sections are not supported"); SymTabShndx = &Sec; } } // We need to locate the SHT_SYMTAB_SHNDX section early, because it might be // needed for dumping symbols. if (SymTabShndx) { if (!SymTab || SymTabShndx->sh_link != (unsigned)(SymTab - Sections.begin())) return createStringError( obj2yaml_error::not_implemented, "only SHT_SYMTAB_SHNDX associated with SHT_SYMTAB are supported"); auto TableOrErr = Obj.getSHNDXTable(*SymTabShndx); if (!TableOrErr) return TableOrErr.takeError(); ShndxTable = *TableOrErr; } if (SymTab) { Y->Symbols.emplace(); if (Error E = dumpSymbols(SymTab, *Y->Symbols)) return std::move(E); } if (DynSymTab) { Y->DynamicSymbols.emplace(); if (Error E = dumpSymbols(DynSymTab, *Y->DynamicSymbols)) return std::move(E); } for (const Elf_Shdr &Sec : Sections) { switch (Sec.sh_type) { case ELF::SHT_DYNAMIC: { Expected SecOrErr = dumpDynamicSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_STRTAB: case ELF::SHT_SYMTAB: case ELF::SHT_DYNSYM: // Do not dump these sections. break; case ELF::SHT_SYMTAB_SHNDX: { Expected SecOrErr = dumpSymtabShndxSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_REL: case ELF::SHT_RELA: { Expected SecOrErr = dumpRelocSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_RELR: { Expected SecOrErr = dumpRelrSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_GROUP: { Expected GroupOrErr = dumpGroup(&Sec); if (!GroupOrErr) return GroupOrErr.takeError(); Y->Chunks.emplace_back(*GroupOrErr); break; } case ELF::SHT_MIPS_ABIFLAGS: { Expected SecOrErr = dumpMipsABIFlags(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_NOBITS: { Expected SecOrErr = dumpNoBitsSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_NOTE: { Expected SecOrErr = dumpNoteSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_HASH: { Expected SecOrErr = dumpHashSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_GNU_HASH: { Expected SecOrErr = dumpGnuHashSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_GNU_verdef: { Expected SecOrErr = dumpVerdefSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_GNU_versym: { Expected SecOrErr = dumpSymverSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_GNU_verneed: { Expected SecOrErr = dumpVerneedSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_LLVM_ADDRSIG: { Expected SecOrErr = dumpAddrsigSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_LLVM_LINKER_OPTIONS: { Expected SecOrErr = dumpLinkerOptionsSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_LLVM_DEPENDENT_LIBRARIES: { Expected SecOrErr = dumpDependentLibrariesSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_LLVM_CALL_GRAPH_PROFILE: { Expected SecOrErr = dumpCallGraphProfileSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_NULL: { // We only dump the SHT_NULL section at index 0 when it // has at least one non-null field, because yaml2obj // normally creates the zero section at index 0 implicitly. if (&Sec == &Sections[0]) { const uint8_t *Begin = reinterpret_cast(&Sec); const uint8_t *End = Begin + sizeof(Elf_Shdr); if (std::find_if(Begin, End, [](uint8_t V) { return V != 0; }) == End) break; } LLVM_FALLTHROUGH; } default: { // Recognize some special SHT_PROGBITS sections by name. if (Sec.sh_type == ELF::SHT_PROGBITS) { Expected SpecialSecOrErr = dumpSpecialSection(&Sec); if (!SpecialSecOrErr) return SpecialSecOrErr.takeError(); if (*SpecialSecOrErr) { Y->Chunks.emplace_back(*SpecialSecOrErr); break; } } Expected SecOrErr = dumpContentSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Chunks.emplace_back(*SecOrErr); } } } return Y.release(); } template Error ELFDumper::dumpSymbols(const Elf_Shdr *Symtab, std::vector &Symbols) { if (!Symtab) return Error::success(); auto StrTableOrErr = Obj.getStringTableForSymtab(*Symtab); if (!StrTableOrErr) return StrTableOrErr.takeError(); StringRef StrTable = *StrTableOrErr; auto SymtabOrErr = Obj.symbols(Symtab); if (!SymtabOrErr) return SymtabOrErr.takeError(); if (Symtab->sh_type == ELF::SHT_SYMTAB) { SymTable = *SymtabOrErr; SymbolNames.resize(SymTable.size()); } for (const auto &Sym : (*SymtabOrErr).drop_front()) { ELFYAML::Symbol S; if (auto EC = dumpSymbol(&Sym, Symtab, StrTable, S)) return EC; Symbols.push_back(S); } return Error::success(); } template Error ELFDumper::dumpSymbol(const Elf_Sym *Sym, const Elf_Shdr *SymTab, StringRef StrTable, ELFYAML::Symbol &S) { S.Type = Sym->getType(); S.Value = Sym->st_value; S.Size = Sym->st_size; S.Other = Sym->st_other; S.Binding = Sym->getBinding(); Expected SymbolNameOrErr = getUniquedSymbolName(Sym, StrTable, SymTab); if (!SymbolNameOrErr) return SymbolNameOrErr.takeError(); S.Name = SymbolNameOrErr.get(); if (Sym->st_shndx >= ELF::SHN_LORESERVE) { S.Index = (ELFYAML::ELF_SHN)Sym->st_shndx; return Error::success(); } auto ShdrOrErr = Obj.getSection(Sym, SymTab, ShndxTable); if (!ShdrOrErr) return ShdrOrErr.takeError(); const Elf_Shdr *Shdr = *ShdrOrErr; if (!Shdr) return Error::success(); auto NameOrErr = getUniquedSectionName(Shdr); if (!NameOrErr) return NameOrErr.takeError(); S.Section = NameOrErr.get(); return Error::success(); } template template Error ELFDumper::dumpRelocation(const RelT *Rel, const Elf_Shdr *SymTab, ELFYAML::Relocation &R) { R.Type = Rel->getType(Obj.isMips64EL()); R.Offset = Rel->r_offset; R.Addend = 0; auto SymOrErr = Obj.getRelocationSymbol(Rel, SymTab); if (!SymOrErr) return SymOrErr.takeError(); // We have might have a relocation with symbol index 0, // e.g. R_X86_64_NONE or R_X86_64_GOTPC32. const Elf_Sym *Sym = *SymOrErr; if (!Sym) return Error::success(); auto StrTabSec = Obj.getSection(SymTab->sh_link); if (!StrTabSec) return StrTabSec.takeError(); auto StrTabOrErr = Obj.getStringTable(*StrTabSec); if (!StrTabOrErr) return StrTabOrErr.takeError(); Expected NameOrErr = getUniquedSymbolName(Sym, *StrTabOrErr, SymTab); if (!NameOrErr) return NameOrErr.takeError(); R.Symbol = NameOrErr.get(); return Error::success(); } template Error ELFDumper::dumpCommonSection(const Elf_Shdr *Shdr, ELFYAML::Section &S) { // Dump fields. We do not dump the ShOffset field. When not explicitly // set, the value is set by yaml2obj automatically. S.Type = Shdr->sh_type; if (Shdr->sh_flags) S.Flags = static_cast(Shdr->sh_flags); S.Address = Shdr->sh_addr; S.AddressAlign = Shdr->sh_addralign; if (Shdr->sh_entsize) S.EntSize = static_cast(Shdr->sh_entsize); auto NameOrErr = getUniquedSectionName(Shdr); if (!NameOrErr) return NameOrErr.takeError(); S.Name = NameOrErr.get(); if (Shdr->sh_link != ELF::SHN_UNDEF) { auto LinkSection = Obj.getSection(Shdr->sh_link); if (!LinkSection) return make_error( "unable to resolve sh_link reference in section '" + S.Name + "': " + toString(LinkSection.takeError()), inconvertibleErrorCode()); NameOrErr = getUniquedSectionName(*LinkSection); if (!NameOrErr) return NameOrErr.takeError(); S.Link = NameOrErr.get(); } return Error::success(); } template Expected ELFDumper::dumpSpecialSection(const Elf_Shdr *Shdr) { auto NameOrErr = getUniquedSectionName(Shdr); if (!NameOrErr) return NameOrErr.takeError(); if (ELFYAML::StackSizesSection::nameMatches(*NameOrErr)) return dumpStackSizesSection(Shdr); return nullptr; } template Error ELFDumper::dumpCommonRelocationSection( const Elf_Shdr *Shdr, ELFYAML::RelocationSection &S) { if (Error E = dumpCommonSection(Shdr, S)) return E; auto InfoSection = Obj.getSection(Shdr->sh_info); if (!InfoSection) return InfoSection.takeError(); auto NameOrErr = getUniquedSectionName(*InfoSection); if (!NameOrErr) return NameOrErr.takeError(); S.RelocatableSec = NameOrErr.get(); return Error::success(); } template Expected ELFDumper::dumpStackSizesSection(const Elf_Shdr *Shdr) { auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); auto ContentOrErr = Obj.getSectionContents(Shdr); if (!ContentOrErr) return ContentOrErr.takeError(); ArrayRef Content = *ContentOrErr; DataExtractor Data(Content, Obj.isLE(), ELFT::Is64Bits ? 8 : 4); std::vector Entries; DataExtractor::Cursor Cur(0); while (Cur && Cur.tell() < Content.size()) { uint64_t Address = Data.getAddress(Cur); uint64_t Size = Data.getULEB128(Cur); Entries.push_back({Address, Size}); } if (Content.empty() || !Cur) { // If .stack_sizes cannot be decoded, we dump it as an array of bytes. consumeError(Cur.takeError()); S->Content = yaml::BinaryRef(Content); } else { S->Entries = std::move(Entries); } return S.release(); } template Expected ELFDumper::dumpAddrsigSection(const Elf_Shdr *Shdr) { auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); auto ContentOrErr = Obj.getSectionContents(Shdr); if (!ContentOrErr) return ContentOrErr.takeError(); ArrayRef Content = *ContentOrErr; DataExtractor::Cursor Cur(0); DataExtractor Data(Content, Obj.isLE(), /*AddressSize=*/0); std::vector Symbols; while (Cur && Cur.tell() < Content.size()) { uint64_t SymNdx = Data.getULEB128(Cur); if (!Cur) break; Expected SymbolName = getSymbolName(Shdr->sh_link, SymNdx); if (!SymbolName || SymbolName->empty()) { consumeError(SymbolName.takeError()); Symbols.emplace_back( StringRef(std::to_string(SymNdx)).copy(StringAllocator)); continue; } Symbols.emplace_back(*SymbolName); } if (Cur) { S->Symbols = std::move(Symbols); return S.release(); } consumeError(Cur.takeError()); S->Content = yaml::BinaryRef(Content); return S.release(); } template Expected ELFDumper::dumpLinkerOptionsSection(const Elf_Shdr *Shdr) { auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); auto ContentOrErr = Obj.getSectionContents(Shdr); if (!ContentOrErr) return ContentOrErr.takeError(); ArrayRef Content = *ContentOrErr; if (Content.empty() || Content.back() != 0) { S->Content = Content; return S.release(); } SmallVector Strings; toStringRef(Content.drop_back()).split(Strings, '\0'); if (Strings.size() % 2 != 0) { S->Content = Content; return S.release(); } S->Options.emplace(); for (size_t I = 0, E = Strings.size(); I != E; I += 2) S->Options->push_back({Strings[I], Strings[I + 1]}); return S.release(); } template Expected ELFDumper::dumpDependentLibrariesSection(const Elf_Shdr *Shdr) { auto DL = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *DL)) return std::move(E); Expected> ContentOrErr = Obj.getSectionContents(Shdr); if (!ContentOrErr) return ContentOrErr.takeError(); ArrayRef Content = *ContentOrErr; if (!Content.empty() && Content.back() != 0) { DL->Content = Content; return DL.release(); } DL->Libs.emplace(); for (const uint8_t *I = Content.begin(), *E = Content.end(); I < E;) { StringRef Lib((const char *)I); DL->Libs->emplace_back(Lib); I += Lib.size() + 1; } return DL.release(); } template Expected ELFDumper::dumpCallGraphProfileSection(const Elf_Shdr *Shdr) { auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); Expected> ContentOrErr = Obj.getSectionContents(Shdr); if (!ContentOrErr) return ContentOrErr.takeError(); ArrayRef Content = *ContentOrErr; // Dump the section by using the Content key when it is truncated. // There is no need to create either "Content" or "Entries" fields when the // section is empty. if (Content.empty() || Content.size() % 16 != 0) { if (!Content.empty()) S->Content = yaml::BinaryRef(Content); return S.release(); } std::vector Entries(Content.size() / 16); DataExtractor Data(Content, Obj.isLE(), /*AddressSize=*/0); DataExtractor::Cursor Cur(0); auto ReadEntry = [&](ELFYAML::CallGraphEntry &E) { uint32_t FromSymIndex = Data.getU32(Cur); uint32_t ToSymIndex = Data.getU32(Cur); E.Weight = Data.getU64(Cur); if (!Cur) { consumeError(Cur.takeError()); return false; } Expected From = getSymbolName(Shdr->sh_link, FromSymIndex); Expected To = getSymbolName(Shdr->sh_link, ToSymIndex); if (From && To) { E.From = *From; E.To = *To; return true; } consumeError(From.takeError()); consumeError(To.takeError()); return false; }; for (ELFYAML::CallGraphEntry &E : Entries) { if (ReadEntry(E)) continue; S->Content = yaml::BinaryRef(Content); return S.release(); } S->Entries = std::move(Entries); return S.release(); } template Expected ELFDumper::dumpDynamicSection(const Elf_Shdr *Shdr) { auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); auto DynTagsOrErr = Obj.template getSectionContentsAsArray(Shdr); if (!DynTagsOrErr) return DynTagsOrErr.takeError(); for (const Elf_Dyn &Dyn : *DynTagsOrErr) S->Entries.push_back({(ELFYAML::ELF_DYNTAG)Dyn.getTag(), Dyn.getVal()}); return S.release(); } template Expected ELFDumper::dumpRelocSection(const Elf_Shdr *Shdr) { auto S = std::make_unique(); if (auto E = dumpCommonRelocationSection(Shdr, *S)) return std::move(E); auto SymTabOrErr = Obj.getSection(Shdr->sh_link); if (!SymTabOrErr) return SymTabOrErr.takeError(); const Elf_Shdr *SymTab = *SymTabOrErr; if (Shdr->sh_type == ELF::SHT_REL) { auto Rels = Obj.rels(Shdr); if (!Rels) return Rels.takeError(); for (const Elf_Rel &Rel : *Rels) { ELFYAML::Relocation R; if (Error E = dumpRelocation(&Rel, SymTab, R)) return std::move(E); S->Relocations.push_back(R); } } else { auto Rels = Obj.relas(Shdr); if (!Rels) return Rels.takeError(); for (const Elf_Rela &Rel : *Rels) { ELFYAML::Relocation R; if (Error E = dumpRelocation(&Rel, SymTab, R)) return std::move(E); R.Addend = Rel.r_addend; S->Relocations.push_back(R); } } return S.release(); } template Expected ELFDumper::dumpRelrSection(const Elf_Shdr *Shdr) { auto S = std::make_unique(); if (auto E = dumpCommonSection(Shdr, *S)) return std::move(E); if (Expected> Relrs = Obj.relrs(Shdr)) { S->Entries.emplace(); for (Elf_Relr Rel : *Relrs) S->Entries->emplace_back(Rel); return S.release(); } else { // Ignore. We are going to dump the data as raw content below. consumeError(Relrs.takeError()); } Expected> ContentOrErr = Obj.getSectionContents(Shdr); if (!ContentOrErr) return ContentOrErr.takeError(); S->Content = *ContentOrErr; return S.release(); } template Expected ELFDumper::dumpContentSection(const Elf_Shdr *Shdr) { auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); unsigned SecIndex = Shdr - &Sections[0]; if (SecIndex != 0 || Shdr->sh_type != ELF::SHT_NULL) { auto ContentOrErr = Obj.getSectionContents(Shdr); if (!ContentOrErr) return ContentOrErr.takeError(); ArrayRef Content = *ContentOrErr; if (!Content.empty()) S->Content = yaml::BinaryRef(Content); } else { S->Size = static_cast(Shdr->sh_size); } if (Shdr->sh_info) S->Info = static_cast(Shdr->sh_info); return S.release(); } template Expected ELFDumper::dumpSymtabShndxSection(const Elf_Shdr *Shdr) { auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); auto EntriesOrErr = Obj.template getSectionContentsAsArray(Shdr); if (!EntriesOrErr) return EntriesOrErr.takeError(); for (const Elf_Word &E : *EntriesOrErr) S->Entries.push_back(E); return S.release(); } template Expected ELFDumper::dumpNoBitsSection(const Elf_Shdr *Shdr) { auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); S->Size = Shdr->sh_size; return S.release(); } template Expected ELFDumper::dumpNoteSection(const Elf_Shdr *Shdr) { auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); auto ContentOrErr = Obj.getSectionContents(Shdr); if (!ContentOrErr) return ContentOrErr.takeError(); std::vector Entries; ArrayRef Content = *ContentOrErr; while (!Content.empty()) { if (Content.size() < sizeof(Elf_Nhdr)) { S->Content = yaml::BinaryRef(*ContentOrErr); return S.release(); } const Elf_Nhdr *Header = reinterpret_cast(Content.data()); if (Content.size() < Header->getSize()) { S->Content = yaml::BinaryRef(*ContentOrErr); return S.release(); } Elf_Note Note(*Header); Entries.push_back( {Note.getName(), Note.getDesc(), (llvm::yaml::Hex32)Note.getType()}); Content = Content.drop_front(Header->getSize()); } S->Notes = std::move(Entries); return S.release(); } template Expected ELFDumper::dumpHashSection(const Elf_Shdr *Shdr) { auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); auto ContentOrErr = Obj.getSectionContents(Shdr); if (!ContentOrErr) return ContentOrErr.takeError(); ArrayRef Content = *ContentOrErr; if (Content.size() % 4 != 0 || Content.size() < 8) { S->Content = yaml::BinaryRef(Content); return S.release(); } DataExtractor::Cursor Cur(0); DataExtractor Data(Content, Obj.isLE(), /*AddressSize=*/0); uint32_t NBucket = Data.getU32(Cur); uint32_t NChain = Data.getU32(Cur); if (Content.size() != (2 + NBucket + NChain) * 4) { S->Content = yaml::BinaryRef(Content); if (Cur) return S.release(); llvm_unreachable("entries were not read correctly"); } S->Bucket.emplace(NBucket); for (uint32_t &V : *S->Bucket) V = Data.getU32(Cur); S->Chain.emplace(NChain); for (uint32_t &V : *S->Chain) V = Data.getU32(Cur); if (Cur) return S.release(); llvm_unreachable("entries were not read correctly"); } template Expected ELFDumper::dumpGnuHashSection(const Elf_Shdr *Shdr) { auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); auto ContentOrErr = Obj.getSectionContents(Shdr); if (!ContentOrErr) return ContentOrErr.takeError(); unsigned AddrSize = ELFT::Is64Bits ? 8 : 4; ArrayRef Content = *ContentOrErr; DataExtractor Data(Content, Obj.isLE(), AddrSize); ELFYAML::GnuHashHeader Header; DataExtractor::Cursor Cur(0); uint32_t NBuckets = Data.getU32(Cur); Header.SymNdx = Data.getU32(Cur); uint32_t MaskWords = Data.getU32(Cur); Header.Shift2 = Data.getU32(Cur); // Set just the raw binary content if we were unable to read the header // or when the section data is truncated or malformed. uint64_t Size = Data.getData().size() - Cur.tell(); if (!Cur || (Size < MaskWords * AddrSize + NBuckets * 4) || (Size % 4 != 0)) { consumeError(Cur.takeError()); S->Content = yaml::BinaryRef(Content); return S.release(); } S->Header = Header; S->BloomFilter.emplace(MaskWords); for (llvm::yaml::Hex64 &Val : *S->BloomFilter) Val = Data.getAddress(Cur); S->HashBuckets.emplace(NBuckets); for (llvm::yaml::Hex32 &Val : *S->HashBuckets) Val = Data.getU32(Cur); S->HashValues.emplace((Data.getData().size() - Cur.tell()) / 4); for (llvm::yaml::Hex32 &Val : *S->HashValues) Val = Data.getU32(Cur); if (Cur) return S.release(); llvm_unreachable("GnuHashSection was not read correctly"); } template Expected ELFDumper::dumpVerdefSection(const Elf_Shdr *Shdr) { typedef typename ELFT::Verdef Elf_Verdef; typedef typename ELFT::Verdaux Elf_Verdaux; auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); S->Info = Shdr->sh_info; auto StringTableShdrOrErr = Obj.getSection(Shdr->sh_link); if (!StringTableShdrOrErr) return StringTableShdrOrErr.takeError(); auto StringTableOrErr = Obj.getStringTable(*StringTableShdrOrErr); if (!StringTableOrErr) return StringTableOrErr.takeError(); auto Contents = Obj.getSectionContents(Shdr); if (!Contents) return Contents.takeError(); S->Entries.emplace(); llvm::ArrayRef Data = *Contents; const uint8_t *Buf = Data.data(); while (Buf) { const Elf_Verdef *Verdef = reinterpret_cast(Buf); ELFYAML::VerdefEntry Entry; Entry.Version = Verdef->vd_version; Entry.Flags = Verdef->vd_flags; Entry.VersionNdx = Verdef->vd_ndx; Entry.Hash = Verdef->vd_hash; const uint8_t *BufAux = Buf + Verdef->vd_aux; while (BufAux) { const Elf_Verdaux *Verdaux = reinterpret_cast(BufAux); Entry.VerNames.push_back( StringTableOrErr->drop_front(Verdaux->vda_name).data()); BufAux = Verdaux->vda_next ? BufAux + Verdaux->vda_next : nullptr; } S->Entries->push_back(Entry); Buf = Verdef->vd_next ? Buf + Verdef->vd_next : nullptr; } return S.release(); } template Expected ELFDumper::dumpSymverSection(const Elf_Shdr *Shdr) { typedef typename ELFT::Half Elf_Half; auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); auto VersionsOrErr = Obj.template getSectionContentsAsArray(Shdr); if (!VersionsOrErr) return VersionsOrErr.takeError(); for (const Elf_Half &E : *VersionsOrErr) S->Entries.push_back(E); return S.release(); } template Expected ELFDumper::dumpVerneedSection(const Elf_Shdr *Shdr) { typedef typename ELFT::Verneed Elf_Verneed; typedef typename ELFT::Vernaux Elf_Vernaux; auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); S->Info = Shdr->sh_info; auto Contents = Obj.getSectionContents(Shdr); if (!Contents) return Contents.takeError(); auto StringTableShdrOrErr = Obj.getSection(Shdr->sh_link); if (!StringTableShdrOrErr) return StringTableShdrOrErr.takeError(); auto StringTableOrErr = Obj.getStringTable(*StringTableShdrOrErr); if (!StringTableOrErr) return StringTableOrErr.takeError(); S->VerneedV.emplace(); llvm::ArrayRef Data = *Contents; const uint8_t *Buf = Data.data(); while (Buf) { const Elf_Verneed *Verneed = reinterpret_cast(Buf); ELFYAML::VerneedEntry Entry; Entry.Version = Verneed->vn_version; Entry.File = StringRef(StringTableOrErr->drop_front(Verneed->vn_file).data()); const uint8_t *BufAux = Buf + Verneed->vn_aux; while (BufAux) { const Elf_Vernaux *Vernaux = reinterpret_cast(BufAux); ELFYAML::VernauxEntry Aux; Aux.Hash = Vernaux->vna_hash; Aux.Flags = Vernaux->vna_flags; Aux.Other = Vernaux->vna_other; Aux.Name = StringRef(StringTableOrErr->drop_front(Vernaux->vna_name).data()); Entry.AuxV.push_back(Aux); BufAux = Vernaux->vna_next ? BufAux + Vernaux->vna_next : nullptr; } S->VerneedV->push_back(Entry); Buf = Verneed->vn_next ? Buf + Verneed->vn_next : nullptr; } return S.release(); } template Expected ELFDumper::getSymbolName(uint32_t SymtabNdx, uint32_t SymbolNdx) { auto SymtabOrErr = Obj.getSection(SymtabNdx); if (!SymtabOrErr) return SymtabOrErr.takeError(); const Elf_Shdr *Symtab = *SymtabOrErr; auto SymOrErr = Obj.getSymbol(Symtab, SymbolNdx); if (!SymOrErr) return SymOrErr.takeError(); auto StrTabOrErr = Obj.getStringTableForSymtab(*Symtab); if (!StrTabOrErr) return StrTabOrErr.takeError(); return getUniquedSymbolName(*SymOrErr, *StrTabOrErr, Symtab); } template Expected ELFDumper::dumpGroup(const Elf_Shdr *Shdr) { auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); // Get symbol with index sh_info. This symbol's name is the signature of the group. Expected SymbolName = getSymbolName(Shdr->sh_link, Shdr->sh_info); if (!SymbolName) return SymbolName.takeError(); S->Signature = *SymbolName; auto MembersOrErr = Obj.template getSectionContentsAsArray(Shdr); if (!MembersOrErr) return MembersOrErr.takeError(); for (Elf_Word Member : *MembersOrErr) { if (Member == llvm::ELF::GRP_COMDAT) { S->Members.push_back({"GRP_COMDAT"}); continue; } auto SHdrOrErr = Obj.getSection(Member); if (!SHdrOrErr) return SHdrOrErr.takeError(); auto NameOrErr = getUniquedSectionName(*SHdrOrErr); if (!NameOrErr) return NameOrErr.takeError(); S->Members.push_back({*NameOrErr}); } return S.release(); } template Expected ELFDumper::dumpMipsABIFlags(const Elf_Shdr *Shdr) { assert(Shdr->sh_type == ELF::SHT_MIPS_ABIFLAGS && "Section type is not SHT_MIPS_ABIFLAGS"); auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); auto ContentOrErr = Obj.getSectionContents(Shdr); if (!ContentOrErr) return ContentOrErr.takeError(); auto *Flags = reinterpret_cast *>( ContentOrErr.get().data()); S->Version = Flags->version; S->ISALevel = Flags->isa_level; S->ISARevision = Flags->isa_rev; S->GPRSize = Flags->gpr_size; S->CPR1Size = Flags->cpr1_size; S->CPR2Size = Flags->cpr2_size; S->FpABI = Flags->fp_abi; S->ISAExtension = Flags->isa_ext; S->ASEs = Flags->ases; S->Flags1 = Flags->flags1; S->Flags2 = Flags->flags2; return S.release(); } template static Error elf2yaml(raw_ostream &Out, const object::ELFFile &Obj) { ELFDumper Dumper(Obj); Expected YAMLOrErr = Dumper.dump(); if (!YAMLOrErr) return YAMLOrErr.takeError(); std::unique_ptr YAML(YAMLOrErr.get()); yaml::Output Yout(Out); Yout << *YAML; return Error::success(); } Error elf2yaml(raw_ostream &Out, const object::ObjectFile &Obj) { if (const auto *ELFObj = dyn_cast(&Obj)) return elf2yaml(Out, *ELFObj->getELFFile()); if (const auto *ELFObj = dyn_cast(&Obj)) return elf2yaml(Out, *ELFObj->getELFFile()); if (const auto *ELFObj = dyn_cast(&Obj)) return elf2yaml(Out, *ELFObj->getELFFile()); if (const auto *ELFObj = dyn_cast(&Obj)) return elf2yaml(Out, *ELFObj->getELFFile()); llvm_unreachable("unknown ELF file format"); }