diff options
author | Simon Atanasyan <simon@atanasyan.com> | 2014-05-14 05:07:47 +0000 |
---|---|---|
committer | Simon Atanasyan <simon@atanasyan.com> | 2014-05-14 05:07:47 +0000 |
commit | b8236e532a9bc5e0c6684a0b51f808d4754272bd (patch) | |
tree | 6b8bb07cc323e06c40b3fa126a36294478296c86 /tools/obj2yaml/elf2yaml.cpp | |
parent | 0fe443d8932b68ebbe281141ef79f81ee97e292d (diff) | |
download | llvm-b8236e532a9bc5e0c6684a0b51f808d4754272bd.tar.gz llvm-b8236e532a9bc5e0c6684a0b51f808d4754272bd.tar.bz2 llvm-b8236e532a9bc5e0c6684a0b51f808d4754272bd.tar.xz |
[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
Diffstat (limited to 'tools/obj2yaml/elf2yaml.cpp')
-rw-r--r-- | tools/obj2yaml/elf2yaml.cpp | 289 |
1 files changed, 289 insertions, 0 deletions
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 ELFT> +class ELFDumper { + typedef typename object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; + typedef typename object::ELFFile<ELFT>::Elf_Sym_Iter Elf_Sym_Iter; + + const object::ELFFile<ELFT> &Obj; + + error_code dumpSymbol(Elf_Sym_Iter Sym, ELFYAML::Symbol &S); + error_code dumpCommonSection(const Elf_Shdr *Shdr, ELFYAML::Section &S); + template <class RelT> + error_code dumpRelocation(const Elf_Shdr *Shdr, const RelT *Rel, + ELFYAML::Relocation &R); + + ErrorOr<ELFYAML::RelocationSection *> dumpRelSection(const Elf_Shdr *Shdr); + ErrorOr<ELFYAML::RelocationSection *> dumpRelaSection(const Elf_Shdr *Shdr); + ErrorOr<ELFYAML::RawContentSection *> + dumpContentSection(const Elf_Shdr *Shdr); + +public: + ELFDumper(const object::ELFFile<ELFT> &O); + ErrorOr<ELFYAML::Object *> dump(); +}; + +} + +template <class ELFT> +ELFDumper<ELFT>::ELFDumper(const object::ELFFile<ELFT> &O) + : Obj(O) {} + +template <class ELFT> +ErrorOr<ELFYAML::Object *> ELFDumper<ELFT>::dump() { + auto Y = make_unique<ELFYAML::Object>(); + + // 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<ELFYAML::RelocationSection *> S = dumpRelaSection(&Sec); + if (error_code EC = S.getError()) + return EC; + Y->Sections.push_back(std::unique_ptr<ELFYAML::Section>(S.get())); + break; + } + case ELF::SHT_REL: { + ErrorOr<ELFYAML::RelocationSection *> S = dumpRelSection(&Sec); + if (error_code EC = S.getError()) + return EC; + Y->Sections.push_back(std::unique_ptr<ELFYAML::Section>(S.get())); + break; + } + default: { + ErrorOr<ELFYAML::RawContentSection *> S = dumpContentSection(&Sec); + if (error_code EC = S.getError()) + return EC; + Y->Sections.push_back(std::unique_ptr<ELFYAML::Section>(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<ELFT>::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 <class ELFT> +error_code ELFDumper<ELFT>::dumpSymbol(Elf_Sym_Iter Sym, ELFYAML::Symbol &S) { + S.Type = Sym->getType(); + S.Value = Sym->st_value; + S.Size = Sym->st_size; + + ErrorOr<StringRef> 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 <class ELFT> +template <class RelT> +error_code ELFDumper<ELFT>::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<StringRef> NameOrErr = + Obj.getSymbolName(NamePair.first, NamePair.second); + if (error_code EC = NameOrErr.getError()) + return EC; + R.Symbol = NameOrErr.get(); + + return obj2yaml_error::success; +} + +template <class ELFT> +error_code ELFDumper<ELFT>::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<StringRef> 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 <class ELFT> +ErrorOr<ELFYAML::RelocationSection *> +ELFDumper<ELFT>::dumpRelSection(const Elf_Shdr *Shdr) { + assert(Shdr->sh_type == ELF::SHT_REL && "Section type is not SHT_REL"); + auto S = make_unique<ELFYAML::RelocationSection>(); + + 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 <class ELFT> +ErrorOr<ELFYAML::RelocationSection *> +ELFDumper<ELFT>::dumpRelaSection(const Elf_Shdr *Shdr) { + assert(Shdr->sh_type == ELF::SHT_RELA && "Section type is not SHT_RELA"); + auto S = make_unique<ELFYAML::RelocationSection>(); + + 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 <class ELFT> +ErrorOr<ELFYAML::RawContentSection *> +ELFDumper<ELFT>::dumpContentSection(const Elf_Shdr *Shdr) { + auto S = make_unique<ELFYAML::RawContentSection>(); + + if (error_code EC = dumpCommonSection(Shdr, *S)) + return EC; + + ErrorOr<ArrayRef<uint8_t>> ContentOrErr = Obj.getSectionContents(Shdr); + if (error_code EC = ContentOrErr.getError()) + return EC; + S->Content = object::yaml::BinaryRef(ContentOrErr.get()); + + return S.release(); +} + +template <class ELFT> +static error_code elf2yaml(raw_ostream &Out, const object::ELFFile<ELFT> &Obj) { + ELFDumper<ELFT> Dumper(Obj); + ErrorOr<ELFYAML::Object *> YAMLOrErr = Dumper.dump(); + if (error_code EC = YAMLOrErr.getError()) + return EC; + + std::unique_ptr<ELFYAML::Object> 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<object::ELF32LEObjectFile>(&Obj)) + return elf2yaml(Out, *ELFObj->getELFFile()); + + if (const auto *ELFObj = dyn_cast<object::ELF32BEObjectFile>(&Obj)) + return elf2yaml(Out, *ELFObj->getELFFile()); + + if (const auto *ELFObj = dyn_cast<object::ELF64LEObjectFile>(&Obj)) + return elf2yaml(Out, *ELFObj->getELFFile()); + + if (const auto *ELFObj = dyn_cast<object::ELF64BEObjectFile>(&Obj)) + return elf2yaml(Out, *ELFObj->getELFFile()); + + return obj2yaml_error::unsupported_obj_file_format; +} |