//===------ 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/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; ArrayRef Sections; ArrayRef SymTable; DenseMap UsedSectionNames; std::vector SectionNames; DenseMap UsedSymbolNames; std::vector SymbolNames; Expected getUniquedSectionName(const Elf_Shdr *Sec); Expected getUniquedSymbolName(const Elf_Sym *Sym, StringRef StrTable, const Elf_Shdr *SymTab); 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 dumpDynamicSection(const Elf_Shdr *Shdr); Expected dumpRelocSection(const Elf_Shdr *Shdr); Expected dumpContentSection(const Elf_Shdr *Shdr); Expected dumpSymtabShndxSection(const Elf_Shdr *Shdr); Expected dumpNoBitsSection(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); 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 = 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] = 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 != 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) if (Error E = dumpSymbols(SymTab, Y->Symbols)) return std::move(E); if (DynSymTab) 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->Sections.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->Sections.emplace_back(*SecOrErr); break; } case ELF::SHT_REL: case ELF::SHT_RELA: { Expected SecOrErr = dumpRelocSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Sections.emplace_back(*SecOrErr); break; } case ELF::SHT_GROUP: { Expected GroupOrErr = dumpGroup(&Sec); if (!GroupOrErr) return GroupOrErr.takeError(); Y->Sections.emplace_back(*GroupOrErr); break; } case ELF::SHT_MIPS_ABIFLAGS: { Expected SecOrErr = dumpMipsABIFlags(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Sections.emplace_back(*SecOrErr); break; } case ELF::SHT_NOBITS: { Expected SecOrErr = dumpNoBitsSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Sections.emplace_back(*SecOrErr); break; } case ELF::SHT_GNU_verdef: { Expected SecOrErr = dumpVerdefSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Sections.emplace_back(*SecOrErr); break; } case ELF::SHT_GNU_versym: { Expected SecOrErr = dumpSymverSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Sections.emplace_back(*SecOrErr); break; } case ELF::SHT_GNU_verneed: { Expected SecOrErr = dumpVerneedSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Sections.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: { Expected SecOrErr = dumpContentSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); Y->Sections.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(); const Elf_Sym *Sym = *SymOrErr; auto StrTabSec = Obj.getSection(SymTab->sh_link); if (!StrTabSec) return StrTabSec.takeError(); auto StrTabOrErr = Obj.getStringTable(*StrTabSec); if (!StrTabOrErr) return StrTabOrErr.takeError(); StringRef StrTab = *StrTabOrErr; if (Sym) { Expected NameOrErr = getUniquedSymbolName(Sym, StrTab, SymTab); if (!NameOrErr) return NameOrErr.takeError(); R.Symbol = NameOrErr.get(); } else { // We have some edge cases of relocations without a symbol associated, // e.g. an object containing the invalid (according to the System V // ABI) R_X86_64_NONE reloc. Create a symbol with an empty name instead // of crashing. R.Symbol = ""; } 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 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::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::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::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(); 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(); 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::dumpGroup(const Elf_Shdr *Shdr) { auto S = std::make_unique(); if (Error E = dumpCommonSection(Shdr, *S)) return std::move(E); auto SymtabOrErr = Obj.getSection(Shdr->sh_link); if (!SymtabOrErr) return SymtabOrErr.takeError(); // Get symbol with index sh_info which name is the signature of the group. const Elf_Shdr *Symtab = *SymtabOrErr; auto SymOrErr = Obj.getSymbol(Symtab, Shdr->sh_info); if (!SymOrErr) return SymOrErr.takeError(); auto StrTabOrErr = Obj.getStringTableForSymtab(*Symtab); if (!StrTabOrErr) return StrTabOrErr.takeError(); Expected SymbolName = getUniquedSymbolName(*SymOrErr, *StrTabOrErr, Symtab); 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"); }