From b8236e532a9bc5e0c6684a0b51f808d4754272bd Mon Sep 17 00:00:00 2001 From: Simon Atanasyan Date: Wed, 14 May 2014 05:07:47 +0000 Subject: [obj2yaml] Support ELF input format in the obj2yaml tool. The ELF header e_flags field in the MIPS related test cases handled incorrectly. The obj2yaml prints too many flags. I will fix that in the next patches. The patch reviewed by Michael Spencer and Sean Silva. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208752 91177308-0d34-0410-b5e6-96231b3b80d8 --- tools/obj2yaml/CMakeLists.txt | 2 +- tools/obj2yaml/elf2yaml.cpp | 289 ++++++++++++++++++++++++++++++++++++++++++ tools/obj2yaml/obj2yaml.cpp | 2 + tools/obj2yaml/obj2yaml.h | 2 + 4 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 tools/obj2yaml/elf2yaml.cpp (limited to 'tools/obj2yaml') diff --git a/tools/obj2yaml/CMakeLists.txt b/tools/obj2yaml/CMakeLists.txt index 02f7e36515..f167ed5f6e 100644 --- a/tools/obj2yaml/CMakeLists.txt +++ b/tools/obj2yaml/CMakeLists.txt @@ -4,5 +4,5 @@ set(LLVM_LINK_COMPONENTS ) add_llvm_utility(obj2yaml - obj2yaml.cpp coff2yaml.cpp Error.cpp + obj2yaml.cpp coff2yaml.cpp elf2yaml.cpp Error.cpp ) diff --git a/tools/obj2yaml/elf2yaml.cpp b/tools/obj2yaml/elf2yaml.cpp new file mode 100644 index 0000000000..38afa138d9 --- /dev/null +++ b/tools/obj2yaml/elf2yaml.cpp @@ -0,0 +1,289 @@ +//===------ utils/elf2yaml.cpp - obj2yaml conversion tool -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "obj2yaml.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/ELFYAML.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/YAMLTraits.h" + +using namespace llvm; + +namespace { + +template +class ELFDumper { + typedef typename object::ELFFile::Elf_Shdr Elf_Shdr; + typedef typename object::ELFFile::Elf_Sym_Iter Elf_Sym_Iter; + + const object::ELFFile &Obj; + + error_code dumpSymbol(Elf_Sym_Iter Sym, ELFYAML::Symbol &S); + error_code dumpCommonSection(const Elf_Shdr *Shdr, ELFYAML::Section &S); + template + error_code dumpRelocation(const Elf_Shdr *Shdr, const RelT *Rel, + ELFYAML::Relocation &R); + + ErrorOr dumpRelSection(const Elf_Shdr *Shdr); + ErrorOr dumpRelaSection(const Elf_Shdr *Shdr); + ErrorOr + dumpContentSection(const Elf_Shdr *Shdr); + +public: + ELFDumper(const object::ELFFile &O); + ErrorOr dump(); +}; + +} + +template +ELFDumper::ELFDumper(const object::ELFFile &O) + : Obj(O) {} + +template +ErrorOr ELFDumper::dump() { + auto Y = make_unique(); + + // Dump header + 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.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 + for (const Elf_Shdr &Sec : Obj.sections()) { + switch (Sec.sh_type) { + case ELF::SHT_NULL: + case ELF::SHT_SYMTAB: + case ELF::SHT_DYNSYM: + case ELF::SHT_STRTAB: + // Do not dump these sections. + break; + case ELF::SHT_RELA: { + ErrorOr S = dumpRelaSection(&Sec); + if (error_code EC = S.getError()) + return EC; + Y->Sections.push_back(std::unique_ptr(S.get())); + break; + } + case ELF::SHT_REL: { + ErrorOr S = dumpRelSection(&Sec); + if (error_code EC = S.getError()) + return EC; + Y->Sections.push_back(std::unique_ptr(S.get())); + break; + } + default: { + ErrorOr S = dumpContentSection(&Sec); + if (error_code EC = S.getError()) + return EC; + Y->Sections.push_back(std::unique_ptr(S.get())); + } + } + } + + // Dump symbols + bool IsFirstSym = true; + for (auto SI = Obj.begin_symbols(), SE = Obj.end_symbols(); SI != SE; ++SI) { + if (IsFirstSym) { + IsFirstSym = false; + continue; + } + + ELFYAML::Symbol S; + if (error_code EC = ELFDumper::dumpSymbol(SI, S)) + return EC; + + switch (SI->getBinding()) + { + case ELF::STB_LOCAL: + Y->Symbols.Local.push_back(S); + break; + case ELF::STB_GLOBAL: + Y->Symbols.Global.push_back(S); + break; + case ELF::STB_WEAK: + Y->Symbols.Weak.push_back(S); + break; + default: + llvm_unreachable("Unknown ELF symbol binding"); + } + } + + return Y.release(); +} + +template +error_code ELFDumper::dumpSymbol(Elf_Sym_Iter Sym, ELFYAML::Symbol &S) { + S.Type = Sym->getType(); + S.Value = Sym->st_value; + S.Size = Sym->st_size; + + ErrorOr NameOrErr = Obj.getSymbolName(Sym); + if (error_code EC = NameOrErr.getError()) + return EC; + S.Name = NameOrErr.get(); + + const Elf_Shdr *Shdr = Obj.getSection(&*Sym); + if (!Shdr) + return obj2yaml_error::success; + + NameOrErr = Obj.getSectionName(Shdr); + if (error_code EC = NameOrErr.getError()) + return EC; + S.Section = NameOrErr.get(); + + return obj2yaml_error::success; +} + +template +template +error_code ELFDumper::dumpRelocation(const Elf_Shdr *Shdr, + const RelT *Rel, + ELFYAML::Relocation &R) { + R.Type = Rel->getType(Obj.isMips64EL()); + R.Offset = Rel->r_offset; + R.Addend = 0; + + auto NamePair = Obj.getRelocationSymbol(Shdr, Rel); + if (!NamePair.first) + return obj2yaml_error::success; + + ErrorOr NameOrErr = + Obj.getSymbolName(NamePair.first, NamePair.second); + if (error_code EC = NameOrErr.getError()) + return EC; + R.Symbol = NameOrErr.get(); + + return obj2yaml_error::success; +} + +template +error_code ELFDumper::dumpCommonSection(const Elf_Shdr *Shdr, + ELFYAML::Section &S) { + S.Type = Shdr->sh_type; + S.Flags = Shdr->sh_flags; + S.Address = Shdr->sh_addr; + S.AddressAlign = Shdr->sh_addralign; + + ErrorOr NameOrErr = Obj.getSectionName(Shdr); + if (error_code EC = NameOrErr.getError()) + return EC; + S.Name = NameOrErr.get(); + + if (Shdr->sh_link != ELF::SHN_UNDEF) { + if (const Elf_Shdr *LinkSection = Obj.getSection(Shdr->sh_link)) { + NameOrErr = Obj.getSectionName(LinkSection); + if (error_code EC = NameOrErr.getError()) + return EC; + S.Link = NameOrErr.get(); + } + } + if (Shdr->sh_info != ELF::SHN_UNDEF) { + if (const Elf_Shdr *InfoSection = Obj.getSection(Shdr->sh_info)) { + NameOrErr = Obj.getSectionName(InfoSection); + if (error_code EC = NameOrErr.getError()) + return EC; + S.Info = NameOrErr.get(); + } + } + return obj2yaml_error::success; +} + +template +ErrorOr +ELFDumper::dumpRelSection(const Elf_Shdr *Shdr) { + assert(Shdr->sh_type == ELF::SHT_REL && "Section type is not SHT_REL"); + auto S = make_unique(); + + if (error_code EC = dumpCommonSection(Shdr, *S)) + return EC; + + for (auto RI = Obj.begin_rel(Shdr), RE = Obj.end_rel(Shdr); RI != RE; + ++RI) { + ELFYAML::Relocation R; + if (error_code EC = dumpRelocation(Shdr, &*RI, R)) + return EC; + S->Relocations.push_back(R); + } + + return S.release(); +} + +template +ErrorOr +ELFDumper::dumpRelaSection(const Elf_Shdr *Shdr) { + assert(Shdr->sh_type == ELF::SHT_RELA && "Section type is not SHT_RELA"); + auto S = make_unique(); + + if (error_code EC = dumpCommonSection(Shdr, *S)) + return EC; + + for (auto RI = Obj.begin_rela(Shdr), RE = Obj.end_rela(Shdr); RI != RE; + ++RI) { + ELFYAML::Relocation R; + if (error_code EC = dumpRelocation(Shdr, &*RI, R)) + return EC; + R.Addend = RI->r_addend; + S->Relocations.push_back(R); + } + + return S.release(); +} + +template +ErrorOr +ELFDumper::dumpContentSection(const Elf_Shdr *Shdr) { + auto S = make_unique(); + + if (error_code EC = dumpCommonSection(Shdr, *S)) + return EC; + + ErrorOr> ContentOrErr = Obj.getSectionContents(Shdr); + if (error_code EC = ContentOrErr.getError()) + return EC; + S->Content = object::yaml::BinaryRef(ContentOrErr.get()); + + return S.release(); +} + +template +static error_code elf2yaml(raw_ostream &Out, const object::ELFFile &Obj) { + ELFDumper Dumper(Obj); + ErrorOr YAMLOrErr = Dumper.dump(); + if (error_code EC = YAMLOrErr.getError()) + return EC; + + std::unique_ptr YAML(YAMLOrErr.get()); + yaml::Output Yout(Out); + Yout << *YAML; + + return object::object_error::success; +} + +error_code 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()); + + return obj2yaml_error::unsupported_obj_file_format; +} diff --git a/tools/obj2yaml/obj2yaml.cpp b/tools/obj2yaml/obj2yaml.cpp index 493a0ce301..7fe034d5b4 100644 --- a/tools/obj2yaml/obj2yaml.cpp +++ b/tools/obj2yaml/obj2yaml.cpp @@ -22,6 +22,8 @@ using namespace llvm::object; static error_code dumpObject(const ObjectFile &Obj) { if (Obj.isCOFF()) return coff2yaml(outs(), cast(Obj)); + if (Obj.isELF()) + return elf2yaml(outs(), Obj); return obj2yaml_error::unsupported_obj_file_format; } diff --git a/tools/obj2yaml/obj2yaml.h b/tools/obj2yaml/obj2yaml.h index 80b30f2640..73c58fa958 100644 --- a/tools/obj2yaml/obj2yaml.h +++ b/tools/obj2yaml/obj2yaml.h @@ -19,5 +19,7 @@ llvm::error_code coff2yaml(llvm::raw_ostream &Out, const llvm::object::COFFObjectFile &Obj); +llvm::error_code elf2yaml(llvm::raw_ostream &Out, + const llvm::object::ObjectFile &Obj); #endif -- cgit v1.2.3