//===------ 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 "obj2yaml.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/ObjectYAML/DWARFYAML.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 { LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) 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; std::unique_ptr DWARFCtx; DenseMap> ShndxTables; Expected> dumpProgramHeaders(ArrayRef> Sections); Optional dumpDWARFSections(std::vector> &Sections); Error dumpSymbols(const Elf_Shdr *Symtab, Optional> &Symbols); Error dumpSymbol(const Elf_Sym *Sym, const Elf_Shdr *SymTab, StringRef StrTable, ELFYAML::Symbol &S); Expected>> dumpSections(); 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 dumpGroupSection(const Elf_Shdr *Shdr); Expected dumpARMIndexTableSection(const Elf_Shdr *Shdr); Expected dumpMipsABIFlags(const Elf_Shdr *Shdr); Expected dumpStackSizesSection(const Elf_Shdr *Shdr); Expected dumpBBAddrMapSection(const Elf_Shdr *Shdr); Expected dumpPlaceholderSection(const Elf_Shdr *Shdr); bool shouldPrintSection(const ELFYAML::Section &S, const Elf_Shdr &SHdr, Optional DWARF); public: ELFDumper(const object::ELFFile &O, std::unique_ptr DCtx); Expected dump(); }; } template ELFDumper::ELFDumper(const object::ELFFile &O, std::unique_ptr DCtx) : Obj(O), DWARFCtx(std::move(DCtx)) {} template Expected ELFDumper::getUniquedSectionName(const Elf_Shdr &Sec) { unsigned SecIndex = &Sec - &Sections[0]; if (!SectionNames[SecIndex].empty()) return SectionNames[SecIndex]; auto NameOrErr = Obj.getSectionName(Sec); if (!NameOrErr) return NameOrErr; StringRef Name = *NameOrErr; // In some specific cases we might have more than one section without a // name (sh_name == 0). It normally doesn't happen, but when we have this case // it doesn't make sense to uniquify their names and add noise to the output. if (Name.empty()) return ""; std::string &Ret = SectionNames[SecIndex]; auto It = UsedSectionNames.insert({Name, 0}); if (!It.second) Ret = ELFYAML::appendUniqueSuffix(Name, Twine(++It.first->second)); 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) { Expected ShdrOrErr = Obj.getSection(*Sym, SymTab, ShndxTables.lookup(SymTab)); if (!ShdrOrErr) return ShdrOrErr.takeError(); // The null section has no name. return (*ShdrOrErr == nullptr) ? "" : 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] = ELFYAML::appendUniqueSuffix(Name, Twine(++It.first->second)); else SymbolNames[Index] = std::string(Name); return SymbolNames[Index]; } return Name; } template bool ELFDumper::shouldPrintSection(const ELFYAML::Section &S, const Elf_Shdr &SHdr, Optional DWARF) { // We only print 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 (S.Type == ELF::SHT_NULL && (&SHdr == &Sections[0])) { const uint8_t *Begin = reinterpret_cast(&SHdr); const uint8_t *End = Begin + sizeof(Elf_Shdr); return std::any_of(Begin, End, [](uint8_t V) { return V != 0; }); } // Normally we use "DWARF:" to describe contents of DWARF sections. Sometimes // the content of DWARF sections can be successfully parsed into the "DWARF:" // entry but their section headers may have special flags, entry size, address // alignment, etc. We will preserve the header for them under such // circumstances. StringRef SecName = S.Name.substr(1); if (DWARF && DWARF->getNonEmptySectionNames().count(SecName)) { if (const ELFYAML::RawContentSection *RawSec = dyn_cast(&S)) { if (RawSec->Type != ELF::SHT_PROGBITS || RawSec->Link || RawSec->Info || RawSec->AddressAlign != 1 || RawSec->Address || RawSec->EntSize) return true; ELFYAML::ELF_SHF ShFlags = RawSec->Flags.getValueOr(ELFYAML::ELF_SHF(0)); if (SecName == "debug_str") return ShFlags != ELFYAML::ELF_SHF(ELF::SHF_MERGE | ELF::SHF_STRINGS); return ShFlags != 0; } } // Normally we use "Symbols:" and "DynamicSymbols:" to describe contents of // symbol tables. We also build and emit corresponding string tables // implicitly. But sometimes it is important to preserve positions and virtual // addresses of allocatable sections, e.g. for creating program headers. // Generally we are trying to reduce noise in the YAML output. Because // of that we do not print non-allocatable versions of such sections and // assume they are placed at the end. // We also dump symbol tables when the Size field is set. It happens when they // are empty, which should not normally happen. if (S.Type == ELF::SHT_STRTAB || S.Type == ELF::SHT_SYMTAB || S.Type == ELF::SHT_DYNSYM) { return S.Size || S.Flags.getValueOr(ELFYAML::ELF_SHF(0)) & ELF::SHF_ALLOC; } return true; } template static void dumpSectionOffsets(const typename ELFT::Ehdr &Header, ArrayRef Phdrs, std::vector> &V, ArrayRef S) { if (V.empty()) return; uint64_t ExpectedOffset; if (Header.e_phoff > 0) ExpectedOffset = Header.e_phoff + Header.e_phentsize * Header.e_phnum; else ExpectedOffset = sizeof(typename ELFT::Ehdr); for (const std::unique_ptr &C : makeArrayRef(V).drop_front()) { ELFYAML::Section &Sec = *cast(C.get()); const typename ELFT::Shdr &SecHdr = S[Sec.OriginalSecNdx]; ExpectedOffset = alignTo(ExpectedOffset, SecHdr.sh_addralign ? SecHdr.sh_addralign : 1uLL); // We only set the "Offset" field when it can't be naturally derived // from the offset and size of the previous section. This reduces // the noise in the YAML output. if (SecHdr.sh_offset != ExpectedOffset) Sec.Offset = (yaml::Hex64)SecHdr.sh_offset; if (Sec.Type == ELF::SHT_NOBITS && !ELFYAML::shouldAllocateFileSpace(Phdrs, *cast(&Sec))) ExpectedOffset = SecHdr.sh_offset; else ExpectedOffset = SecHdr.sh_offset + SecHdr.sh_size; } } template Expected ELFDumper::dump() { auto Y = std::make_unique(); // Dump header. We do not dump EPh* and ESh* 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; if (Obj.getHeader().e_machine != 0) Y->Header.Machine = ELFYAML::ELF_EM(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()); // Normally an object that does not have sections has e_shnum == 0. // Also, e_shnum might be 0, when the the number of entries in the section // header table is larger than or equal to SHN_LORESERVE (0xff00). In this // case the real number of entries is held in the sh_size member of the // initial entry. We have a section header table when `e_shoff` is not 0. if (Obj.getHeader().e_shoff != 0 && Obj.getHeader().e_shnum == 0) Y->Header.EShNum = 0; // 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 *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) { // We need to locate SHT_SYMTAB_SHNDX sections early, because they // might be needed for dumping symbols. if (Expected> TableOrErr = Obj.getSHNDXTable(Sec)) { // The `getSHNDXTable` calls the `getSection` internally when validates // the symbol table section linked to the SHT_SYMTAB_SHNDX section. const Elf_Shdr *LinkedSymTab = cantFail(Obj.getSection(Sec.sh_link)); if (!ShndxTables.insert({LinkedSymTab, *TableOrErr}).second) return createStringError( errc::invalid_argument, "multiple SHT_SYMTAB_SHNDX sections are " "linked to the same symbol table with index " + Twine(Sec.sh_link)); } else { return createStringError(errc::invalid_argument, "unable to read extended section indexes: " + toString(TableOrErr.takeError())); } } } if (SymTab) if (Error E = dumpSymbols(SymTab, Y->Symbols)) return std::move(E); if (DynSymTab) if (Error E = dumpSymbols(DynSymTab, Y->DynamicSymbols)) return std::move(E); // We dump all sections first. It is simple and allows us to verify that all // sections are valid and also to generalize the code. But we are not going to // keep all of them in the final output (see comments for // 'shouldPrintSection()'). Undesired chunks will be removed later. Expected>> ChunksOrErr = dumpSections(); if (!ChunksOrErr) return ChunksOrErr.takeError(); std::vector> Chunks = std::move(*ChunksOrErr); std::vector OriginalOrder; if (!Chunks.empty()) for (const std::unique_ptr &C : makeArrayRef(Chunks).drop_front()) OriginalOrder.push_back(cast(C.get())); // Sometimes the order of sections in the section header table does not match // their actual order. Here we sort sections by the file offset. llvm::stable_sort(Chunks, [&](const std::unique_ptr &A, const std::unique_ptr &B) { return Sections[cast(A.get())->OriginalSecNdx].sh_offset < Sections[cast(B.get())->OriginalSecNdx].sh_offset; }); // Dump program headers. Expected> PhdrsOrErr = dumpProgramHeaders(Chunks); if (!PhdrsOrErr) return PhdrsOrErr.takeError(); Y->ProgramHeaders = std::move(*PhdrsOrErr); dumpSectionOffsets(Obj.getHeader(), Y->ProgramHeaders, Chunks, Sections); // Dump DWARF sections. Y->DWARF = dumpDWARFSections(Chunks); // We emit the "SectionHeaderTable" key when the order of sections in the // sections header table doesn't match the file order. const bool SectionsSorted = llvm::is_sorted(Chunks, [&](const std::unique_ptr &A, const std::unique_ptr &B) { return cast(A.get())->OriginalSecNdx < cast(B.get())->OriginalSecNdx; }); if (!SectionsSorted) { std::unique_ptr SHT = std::make_unique(/*IsImplicit=*/false); SHT->Sections.emplace(); for (ELFYAML::Section *S : OriginalOrder) SHT->Sections->push_back({S->Name}); Chunks.push_back(std::move(SHT)); } llvm::erase_if(Chunks, [this, &Y](const std::unique_ptr &C) { if (isa(*C.get())) return false; const ELFYAML::Section &S = cast(*C.get()); return !shouldPrintSection(S, Sections[S.OriginalSecNdx], Y->DWARF); }); Y->Chunks = std::move(Chunks); return Y.release(); } template static bool isInSegment(const ELFYAML::Section &Sec, const typename ELFT::Shdr &SHdr, const typename ELFT::Phdr &Phdr) { if (Sec.Type == ELF::SHT_NULL) return false; // A section is within a segment when its location in a file is within the // [p_offset, p_offset + p_filesz] region. bool FileOffsetsMatch = SHdr.sh_offset >= Phdr.p_offset && (SHdr.sh_offset + SHdr.sh_size <= Phdr.p_offset + Phdr.p_filesz); bool VirtualAddressesMatch = SHdr.sh_addr >= Phdr.p_vaddr && SHdr.sh_addr <= Phdr.p_vaddr + Phdr.p_memsz; if (FileOffsetsMatch) { // An empty section on the edges of a program header can be outside of the // virtual address space of the segment. This means it is not included in // the segment and we should ignore it. if (SHdr.sh_size == 0 && (SHdr.sh_offset == Phdr.p_offset || SHdr.sh_offset == Phdr.p_offset + Phdr.p_filesz)) return VirtualAddressesMatch; return true; } // SHT_NOBITS sections usually occupy no physical space in a file. Such // sections belong to a segment when they reside in the segment's virtual // address space. if (Sec.Type != ELF::SHT_NOBITS) return false; return VirtualAddressesMatch; } template Expected> ELFDumper::dumpProgramHeaders( ArrayRef> Chunks) { std::vector Ret; Expected PhdrsOrErr = Obj.program_headers(); if (!PhdrsOrErr) return PhdrsOrErr.takeError(); for (const typename ELFT::Phdr &Phdr : *PhdrsOrErr) { ELFYAML::ProgramHeader PH; PH.Type = Phdr.p_type; PH.Flags = Phdr.p_flags; PH.VAddr = Phdr.p_vaddr; PH.PAddr = Phdr.p_paddr; // yaml2obj sets the alignment of a segment to 1 by default. // We do not print the default alignment to reduce noise in the output. if (Phdr.p_align != 1) PH.Align = static_cast(Phdr.p_align); // Here we match sections with segments. // It is not possible to have a non-Section chunk, because // obj2yaml does not create Fill chunks. for (const std::unique_ptr &C : Chunks) { ELFYAML::Section &S = cast(*C.get()); if (isInSegment(S, Sections[S.OriginalSecNdx], Phdr)) { if (!PH.FirstSec) PH.FirstSec = S.Name; PH.LastSec = S.Name; PH.Chunks.push_back(C.get()); } } Ret.push_back(PH); } return Ret; } template Optional ELFDumper::dumpDWARFSections( std::vector> &Sections) { DWARFYAML::Data DWARF; for (std::unique_ptr &C : Sections) { if (!C->Name.startswith(".debug_")) continue; if (ELFYAML::RawContentSection *RawSec = dyn_cast(C.get())) { Error Err = Error::success(); cantFail(std::move(Err)); if (RawSec->Name == ".debug_aranges") Err = dumpDebugARanges(*DWARFCtx.get(), DWARF); else if (RawSec->Name == ".debug_str") Err = dumpDebugStrings(*DWARFCtx.get(), DWARF); else if (RawSec->Name == ".debug_ranges") Err = dumpDebugRanges(*DWARFCtx.get(), DWARF); else if (RawSec->Name == ".debug_addr") Err = dumpDebugAddr(*DWARFCtx.get(), DWARF); else continue; // If the DWARF section cannot be successfully parsed, emit raw content // instead of an entry in the DWARF section of the YAML. if (Err) consumeError(std::move(Err)); else RawSec->Content.reset(); } } if (DWARF.getNonEmptySectionNames().empty()) return None; return DWARF; } template Expected ELFDumper::dumpPlaceholderSection(const Elf_Shdr *Shdr) { auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S.get())) return std::move(E); // Normally symbol tables should not be empty. We dump the "Size" // key when they are. if ((Shdr->sh_type == ELF::SHT_SYMTAB || Shdr->sh_type == ELF::SHT_DYNSYM) && !Shdr->sh_size) S->Size.emplace(); return S.release(); } template Expected>> ELFDumper::dumpSections() { std::vector> Ret; auto Add = [&](Expected SecOrErr) -> Error { if (!SecOrErr) return SecOrErr.takeError(); Ret.emplace_back(*SecOrErr); return Error::success(); }; auto GetDumper = [this](unsigned Type) -> std::function(const Elf_Shdr *)> { if (Obj.getHeader().e_machine == ELF::EM_ARM && Type == ELF::SHT_ARM_EXIDX) return [this](const Elf_Shdr *S) { return dumpARMIndexTableSection(S); }; if (Obj.getHeader().e_machine == ELF::EM_MIPS && Type == ELF::SHT_MIPS_ABIFLAGS) return [this](const Elf_Shdr *S) { return dumpMipsABIFlags(S); }; switch (Type) { case ELF::SHT_DYNAMIC: return [this](const Elf_Shdr *S) { return dumpDynamicSection(S); }; case ELF::SHT_SYMTAB_SHNDX: return [this](const Elf_Shdr *S) { return dumpSymtabShndxSection(S); }; case ELF::SHT_REL: case ELF::SHT_RELA: return [this](const Elf_Shdr *S) { return dumpRelocSection(S); }; case ELF::SHT_RELR: return [this](const Elf_Shdr *S) { return dumpRelrSection(S); }; case ELF::SHT_GROUP: return [this](const Elf_Shdr *S) { return dumpGroupSection(S); }; case ELF::SHT_NOBITS: return [this](const Elf_Shdr *S) { return dumpNoBitsSection(S); }; case ELF::SHT_NOTE: return [this](const Elf_Shdr *S) { return dumpNoteSection(S); }; case ELF::SHT_HASH: return [this](const Elf_Shdr *S) { return dumpHashSection(S); }; case ELF::SHT_GNU_HASH: return [this](const Elf_Shdr *S) { return dumpGnuHashSection(S); }; case ELF::SHT_GNU_verdef: return [this](const Elf_Shdr *S) { return dumpVerdefSection(S); }; case ELF::SHT_GNU_versym: return [this](const Elf_Shdr *S) { return dumpSymverSection(S); }; case ELF::SHT_GNU_verneed: return [this](const Elf_Shdr *S) { return dumpVerneedSection(S); }; case ELF::SHT_LLVM_ADDRSIG: return [this](const Elf_Shdr *S) { return dumpAddrsigSection(S); }; case ELF::SHT_LLVM_LINKER_OPTIONS: return [this](const Elf_Shdr *S) { return dumpLinkerOptionsSection(S); }; case ELF::SHT_LLVM_DEPENDENT_LIBRARIES: return [this](const Elf_Shdr *S) { return dumpDependentLibrariesSection(S); }; case ELF::SHT_LLVM_CALL_GRAPH_PROFILE: return [this](const Elf_Shdr *S) { return dumpCallGraphProfileSection(S); }; case ELF::SHT_LLVM_BB_ADDR_MAP: return [this](const Elf_Shdr *S) { return dumpBBAddrMapSection(S); }; case ELF::SHT_STRTAB: case ELF::SHT_SYMTAB: case ELF::SHT_DYNSYM: // The contents of these sections are described by other parts of the YAML // file. But we still want to dump them, because their properties can be // important. See comments for 'shouldPrintSection()' for more details. return [this](const Elf_Shdr *S) { return dumpPlaceholderSection(S); }; default: return nullptr; } }; for (const Elf_Shdr &Sec : Sections) { // We have dedicated dumping functions for most of the section types. // Try to use one of them first. if (std::function(const Elf_Shdr *)> DumpFn = GetDumper(Sec.sh_type)) { if (Error E = Add(DumpFn(&Sec))) return std::move(E); continue; } // Recognize some special SHT_PROGBITS sections by name. if (Sec.sh_type == ELF::SHT_PROGBITS) { auto NameOrErr = Obj.getSectionName(Sec); if (!NameOrErr) return NameOrErr.takeError(); if (ELFYAML::StackSizesSection::nameMatches(*NameOrErr)) { if (Error E = Add(dumpStackSizesSection(&Sec))) return std::move(E); continue; } } if (Error E = Add(dumpContentSection(&Sec))) return std::move(E); } return std::move(Ret); } template Error ELFDumper::dumpSymbols( const Elf_Shdr *Symtab, Optional> &Symbols) { if (!Symtab) return Error::success(); auto SymtabOrErr = Obj.symbols(Symtab); if (!SymtabOrErr) return SymtabOrErr.takeError(); if (SymtabOrErr->empty()) return Error::success(); auto StrTableOrErr = Obj.getStringTableForSymtab(*Symtab); if (!StrTableOrErr) return StrTableOrErr.takeError(); if (Symtab->sh_type == ELF::SHT_SYMTAB) { SymTable = *SymtabOrErr; SymbolNames.resize(SymTable.size()); } Symbols.emplace(); for (const auto &Sym : (*SymtabOrErr).drop_front()) { ELFYAML::Symbol S; if (auto EC = dumpSymbol(&Sym, Symtab, *StrTableOrErr, 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(); if (Sym->st_value) S.Value = (yaml::Hex64)Sym->st_value; if (Sym->st_size) S.Size = (yaml::Hex64)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, ShndxTables.lookup(SymTab)); 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); if (Shdr->sh_addr) S.Address = static_cast(Shdr->sh_addr); S.AddressAlign = Shdr->sh_addralign; S.OriginalSecNdx = Shdr - &Sections[0]; Expected NameOrErr = getUniquedSectionName(*Shdr); if (!NameOrErr) return NameOrErr.takeError(); S.Name = NameOrErr.get(); if (Shdr->sh_entsize != ELFYAML::getDefaultShEntSize( Obj.getHeader().e_machine, S.Type, S.Name)) S.EntSize = static_cast(Shdr->sh_entsize); if (Shdr->sh_link != ELF::SHN_UNDEF) { Expected 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 Error ELFDumper::dumpCommonRelocationSection( const Elf_Shdr *Shdr, ELFYAML::RelocationSection &S) { if (Error E = dumpCommonSection(Shdr, S)) return E; // Having a zero sh_info field is normal: .rela.dyn is a dynamic // relocation section that normally has no value in this field. if (!Shdr->sh_info) return Error::success(); auto InfoSection = Obj.getSection(Shdr->sh_info); if (!InfoSection) return InfoSection.takeError(); Expected 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::dumpBBAddrMapSection(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()) return S.release(); 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); uint32_t NumBlocks = Data.getULEB128(Cur); std::vector BBEntries; // Read the specified number of BB entries, or until decoding fails. for (uint32_t BlockID = 0; Cur && BlockID < NumBlocks; ++BlockID) { uint32_t Offset = Data.getULEB128(Cur); uint32_t Size = Data.getULEB128(Cur); uint32_t Metadata = Data.getULEB128(Cur); BBEntries.push_back({Offset, Size, Metadata}); } Entries.push_back({Address, BBEntries}); } if (!Cur) { // If the section 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(); S->Entries.emplace(); 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(); if (Shdr->sh_size != 0) S->Relocations.emplace(); 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, *SymTabOrErr, 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, *SymTabOrErr, 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(); S->Entries.emplace(); 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); if (Shdr->sh_size) S->Size = static_cast(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); uint64_t NBucket = Data.getU32(Cur); uint64_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); uint64_t NBuckets = Data.getU32(Cur); Header.SymNdx = Data.getU32(Cur); uint64_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) { auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); 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; if (Verdef->vd_version != 1) return createStringError(errc::invalid_argument, "invalid SHT_GNU_verdef section version: " + Twine(Verdef->vd_version)); if (Verdef->vd_flags != 0) Entry.Flags = Verdef->vd_flags; if (Verdef->vd_ndx != 0) Entry.VersionNdx = Verdef->vd_ndx; if (Verdef->vd_hash != 0) 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; } if (Shdr->sh_info != S->Entries->size()) S->Info = (llvm::yaml::Hex64)Shdr->sh_info; return S.release(); } template Expected ELFDumper::dumpSymverSection(const Elf_Shdr *Shdr) { 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(); S->Entries.emplace(); for (const Elf_Half &E : *VersionsOrErr) S->Entries->push_back(E); return S.release(); } template Expected ELFDumper::dumpVerneedSection(const Elf_Shdr *Shdr) { auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); 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; } if (Shdr->sh_info != S->VerneedV->size()) S->Info = (llvm::yaml::Hex64)Shdr->sh_info; 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::dumpGroupSection(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(); S->Members.emplace(); for (Elf_Word Member : *MembersOrErr) { if (Member == llvm::ELF::GRP_COMDAT) { S->Members->push_back({"GRP_COMDAT"}); continue; } Expected SHdrOrErr = Obj.getSection(Member); if (!SHdrOrErr) return SHdrOrErr.takeError(); Expected NameOrErr = getUniquedSectionName(**SHdrOrErr); if (!NameOrErr) return NameOrErr.takeError(); S->Members->push_back({*NameOrErr}); } return S.release(); } template Expected ELFDumper::dumpARMIndexTableSection(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(); if (ContentOrErr->size() % (sizeof(Elf_Word) * 2) != 0) { S->Content = yaml::BinaryRef(*ContentOrErr); return S.release(); } ArrayRef Words( reinterpret_cast(ContentOrErr->data()), ContentOrErr->size() / sizeof(Elf_Word)); S->Entries.emplace(); for (size_t I = 0, E = Words.size(); I != E; I += 2) S->Entries->push_back({(yaml::Hex32)Words[I], (yaml::Hex32)Words[I + 1]}); 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, std::unique_ptr DWARFCtx) { ELFDumper Dumper(Obj, std::move(DWARFCtx)); 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) { std::unique_ptr DWARFCtx = DWARFContext::create(Obj); if (const auto *ELFObj = dyn_cast(&Obj)) return elf2yaml(Out, ELFObj->getELFFile(), std::move(DWARFCtx)); if (const auto *ELFObj = dyn_cast(&Obj)) return elf2yaml(Out, ELFObj->getELFFile(), std::move(DWARFCtx)); if (const auto *ELFObj = dyn_cast(&Obj)) return elf2yaml(Out, ELFObj->getELFFile(), std::move(DWARFCtx)); if (const auto *ELFObj = dyn_cast(&Obj)) return elf2yaml(Out, ELFObj->getELFFile(), std::move(DWARFCtx)); llvm_unreachable("unknown ELF file format"); }