Index: test/tools/llvm-readobj/gnu-relocations.test =================================================================== --- /dev/null +++ test/tools/llvm-readobj/gnu-relocations.test @@ -0,0 +1,28 @@ +RUN: llvm-readobj -r %p/Inputs/relocs.obj.elf-i386 --elf-output-style=GNU \ +RUN: | FileCheck %s -check-prefix ELF32 +RUN: llvm-readobj -r %p/Inputs/relocs.obj.elf-x86_64 --elf-output-style=GNU \ +RUN: | FileCheck %s -check-prefix ELF64 + +ELF32: Relocation section '.rel.text' at offset 0x318 contains 41 entries: +ELF32-NEXT: Offset Info Type Sym. Value Symbol's Name +ELF32-NEXT: 00000002 00000500 R_386_NONE 00000000 sym +ELF32-NEXT: 00000008 00000501 R_386_32 00000000 sym +ELF32-NEXT: 0000000e 00000502 R_386_PC32 00000000 sym +ELF32-NEXT: 00000014 00000503 R_386_GOT32 00000000 sym +ELF32-NEXT: 0000001a 00000504 R_386_PLT32 00000000 sym +ELF32-NEXT: 00000020 00000505 R_386_COPY 00000000 sym +ELF32-NEXT: 00000026 00000506 R_386_GLOB_DAT 00000000 sym +ELF32-NEXT: 0000002c 00000507 R_386_JUMP_SLOT 00000000 sym +ELF32-NEXT: 00000032 00000508 R_386_RELATIVE 00000000 sym +ELF32-NEXT: 00000038 00000509 R_386_GOTOFF 00000000 sym + +ELF64: Relocation section '.rela.text' at offset 0x430 contains 38 entries: +ELF64-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +ELF64-NEXT: 0000000000000003 0000000500000000 R_X86_64_NONE 0000000000000000 sym - 4 +ELF64-NEXT: 000000000000000a 0000000500000001 R_X86_64_64 0000000000000000 sym - 4 +ELF64-NEXT: 0000000000000011 0000000500000002 R_X86_64_PC32 0000000000000000 sym - 4 +ELF64-NEXT: 0000000000000018 0000000500000003 R_X86_64_GOT32 0000000000000000 sym - 4 +ELF64-NEXT: 000000000000001f 0000000500000004 R_X86_64_PLT32 0000000000000000 sym - 4 +ELF64-NEXT: 0000000000000026 0000000500000005 R_X86_64_COPY 0000000000000000 sym - 4 +ELF64-NEXT: 000000000000002d 0000000500000006 R_X86_64_GLOB_DAT 0000000000000000 sym - 4 +ELF64-NEXT: 0000000000000034 0000000500000007 R_X86_64_JUMP_SLOT 0000000000000000 sym - 4 Index: test/tools/llvm-readobj/gnu-sections.test =================================================================== --- /dev/null +++ test/tools/llvm-readobj/gnu-sections.test @@ -0,0 +1,35 @@ +RUN: llvm-readobj -s %p/Inputs/relocs.obj.elf-i386 --elf-output-style=GNU \ +RUN: | FileCheck %s -check-prefix ELF32 +RUN: llvm-readobj -s %p/Inputs/relocs.obj.elf-x86_64 --elf-output-style=GNU \ +RUN: | FileCheck %s -check-prefix ELF64 + +ELF32: Section Headers: +ELF32-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +ELF32-NEXT: [ 0] NULL 00000000 000000 000000 00 0 0 0 +ELF32-NEXT: [ 1] .text PROGBITS 00000000 000034 0000f6 00 AX 0 0 4 +ELF32-NEXT: [ 2] .rel.text REL 00000000 000318 000148 08 6 1 4 +ELF32-NEXT: [ 3] .data PROGBITS 00000000 00012c 000000 00 WA 0 0 4 +ELF32-NEXT: [ 4] .bss NOBITS 00000000 00012c 000000 00 WA 0 0 4 +ELF32-NEXT: [ 5] .shstrtab STRTAB 00000000 00012c 000030 00 0 0 1 +ELF32-NEXT: [ 6] .symtab SYMTAB 00000000 00029c 000060 10 7 4 4 +ELF32-NEXT: [ 7] .strtab STRTAB 00000000 0002fc 00001b 00 0 0 1 +ELF32-NEXT: Key to Flags: +ELF32-NEXT: W (write), A (alloc), X (execute), M (merge), S (strings), l (large) +ELF32-NEXT: I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) +ELF32-NEXT: O (extra OS processing required) o (OS specific), p (processor specific) + +ELF64: There are 8 section headers, starting at offset 0x180: +ELF64: Section Headers: +ELF64-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +ELF64-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 +ELF64-NEXT: [ 1] .text PROGBITS 0000000000000000 000040 00010a 00 AX 0 0 4 +ELF64-NEXT: [ 2] .rela.text RELA 0000000000000000 000430 000390 18 6 1 8 +ELF64-NEXT: [ 3] .data PROGBITS 0000000000000000 00014c 000000 00 WA 0 0 4 +ELF64-NEXT: [ 4] .bss NOBITS 0000000000000000 00014c 000000 00 WA 0 0 4 +ELF64-NEXT: [ 5] .shstrtab STRTAB 0000000000000000 00014c 000031 00 0 0 1 +ELF64-NEXT: [ 6] .symtab SYMTAB 0000000000000000 000380 000090 18 7 4 8 +ELF64-NEXT: [ 7] .strtab STRTAB 0000000000000000 000410 00001b 00 0 0 1 +ELF64-NEXT: Key to Flags: +ELF64-NEXT: W (write), A (alloc), X (execute), M (merge), S (strings), l (large) +ELF64-NEXT: I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) +ELF64-NEXT: O (extra OS processing required) o (OS specific), p (processor specific) Index: tools/llvm-readobj/ELFDumper.cpp =================================================================== --- tools/llvm-readobj/ELFDumper.cpp +++ tools/llvm-readobj/ELFDumper.cpp @@ -44,6 +44,21 @@ #define ENUM_ENT_1(enum) \ { #enum, #enum, ELF::enum } +#define TYPEDEF_ELF_TYPES(ELFT) \ + typedef ELFFile ELFO; \ + typedef typename ELFO::Elf_Shdr Elf_Shdr; \ + typedef typename ELFO::Elf_Sym Elf_Sym; \ + typedef typename ELFO::Elf_Dyn Elf_Dyn; \ + typedef typename ELFO::Elf_Dyn_Range Elf_Dyn_Range; \ + typedef typename ELFO::Elf_Rel Elf_Rel; \ + typedef typename ELFO::Elf_Rela Elf_Rela; \ + typedef typename ELFO::Elf_Rela_Range Elf_Rela_Range; \ + typedef typename ELFO::Elf_Phdr Elf_Phdr; \ + typedef typename ELFO::Elf_Half Elf_Half; \ + typedef typename ELFO::Elf_Ehdr Elf_Ehdr; \ + typedef typename ELFO::Elf_Word Elf_Word; \ + typedef typename ELFO::uintX_t uintX_t; + namespace { template class DumpStyle; @@ -144,21 +159,15 @@ void parseDynamicTable(ArrayRef LoadSegments); - void printSymbolsHelper(bool IsDynamic); void printSymbol(const Elf_Sym *Symbol, const Elf_Sym *FirstSym, StringRef StrTable, bool IsDynamic); - void printDynamicRelocation(Elf_Rela Rel); - void printRelocations(const Elf_Shdr *Sec); - void printRelocation(Elf_Rela Rel, const Elf_Shdr *SymTab); void printValue(uint64_t Type, uint64_t Value); - Elf_Rel_Range dyn_rels() const; - Elf_Rela_Range dyn_relas() const; StringRef getDynamicString(uint64_t Offset) const; StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb, - bool &IsDefault); - void LoadVersionMap(); + bool &IsDefault) const; + void LoadVersionMap() const; void LoadVersionNeeds(const Elf_Shdr *ec) const; void LoadVersionDefs(const Elf_Shdr *sec) const; @@ -211,45 +220,99 @@ return DynSymRegion.getAsRange(); } + Elf_Rel_Range dyn_rels() const; + Elf_Rela_Range dyn_relas() const; std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable, - bool IsDynamic); + bool IsDynamic) const; const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; } - ArrayRef getShndxTable() { return ShndxTable; } + ArrayRef getShndxTable() const { return ShndxTable; } StringRef getDynamicStringTable() const { return DynamicStringTable; } + const DynRegionInfo &getDynRelRegion() const { return DynRelRegion; } + const DynRegionInfo &getDynRelaRegion()const { return DynRelaRegion; } + const DynRegionInfo &getDynPLTRelRegion()const { return DynPLTRelRegion; } }; template class DumpStyle { public: - virtual void printFileHeaders(const ELFFile *Obj) = 0; + TYPEDEF_ELF_TYPES(ELFT) + virtual void printFileHeaders(const ELFO *Obj) = 0; virtual ~DumpStyle() { } + DumpStyle(ELFDumper *Dumper) : Dumper(Dumper) {} + virtual void printRelocations(const ELFO *Obj) = 0; + virtual void printSections(const ELFO *Obj) = 0; + virtual void printSymbols(const ELFO *Obj) = 0; + virtual void printDynamicSymbols(const ELFO *Obj) = 0; + virtual void printDynamicRelocations(const ELFO *Obj) = 0; + const ELFDumper *dumper() const { return Dumper; } + +private: + const ELFDumper *Dumper; }; template class GNUStyle : public DumpStyle { formatted_raw_ostream OS; - public: - typedef typename ELFFile::Elf_Ehdr Elf_Ehdr; - GNUStyle(StreamWriter &W) : OS(W.getOStream()) {} - void printFileHeaders(const ELFFile *Obj) override; + TYPEDEF_ELF_TYPES(ELFT) + GNUStyle(StreamWriter &W, ELFDumper *Dumper) + : DumpStyle(Dumper), OS(W.getOStream()) {} + void printFileHeaders(const ELFO *Obj) override; + void printRelocations(const ELFO *Obj) override; + void printSections(const ELFO *Obj) override; + void printSymbols(const ELFO *Obj) override; + void printDynamicSymbols(const ELFO *Obj) override; + void printDynamicRelocations(const ELFO *Obj) override; private: + struct Field { + StringRef Str; + unsigned Column; + Field(StringRef S, unsigned Col) : Str(S), Column(Col) {} + Field(unsigned Col) : Str(""), Column(Col) {} + Field &operator=(StringRef S) { + Str = S; + return *this; + } + }; + template std::string printEnum(T Value, ArrayRef> EnumValues) { for (const auto &EnumItem : EnumValues) if (EnumItem.Value == Value) return EnumItem.AltName; - return to_hexString(Value); + return to_hexString(Value, false); } + formatted_raw_ostream &printField(struct Field F) { + if (F.Column != 0) + OS.PadToColumn(F.Column); + OS << F.Str; + OS.flush(); + return OS; + } + void printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab, + const Elf_Rela &R, bool IsRela); }; template class LLVMStyle : public DumpStyle { public: - typedef typename ELFFile::Elf_Ehdr Elf_Ehdr; - LLVMStyle(StreamWriter &W) : W(W) {} - - void printFileHeaders(const ELFFile *Obj) override; + TYPEDEF_ELF_TYPES(ELFT) + LLVMStyle(StreamWriter &W, ELFDumper *Dumper) + : DumpStyle(Dumper), W(W) {} + + void printFileHeaders(const ELFO *Obj) override; + void printRelocations(const ELFO *Obj) override; + void printRelocations(const Elf_Shdr *Sec, const ELFO *Obj); + void printSections(const ELFO *Obj) override; + void printSymbolsHelper(const ELFO *Obj, bool IsDynamic); + void printSymbols(const ELFO *Obj) override; + void printDynamicSymbols(const ELFO *Obj) override; + void printDynamicRelocations(const ELFO *Obj) override; private: + void printRelocation(const ELFO* Obj, Elf_Rela Rel, const Elf_Shdr *SymTab); + void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First, + StringRef StrTable, bool IsDynamic); + void printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel); + StreamWriter &W; }; @@ -348,7 +411,7 @@ } } -template void ELFDumper::LoadVersionMap() { +template void ELFDumper::LoadVersionMap() const { // If there is no dynamic symtab or version table, there is nothing to do. if (!DynSymRegion.Addr || !dot_gnu_version_sec) return; @@ -457,7 +520,7 @@ template StringRef ELFDumper::getSymbolVersion(StringRef StrTab, const Elf_Sym *symb, - bool &IsDefault) { + bool &IsDefault) const { // This is a dynamic symbol. Look in the GNU symbol version table. if (!dot_gnu_version_sec) { // No version table. @@ -506,7 +569,7 @@ template std::string ELFDumper::getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable, - bool IsDynamic) { + bool IsDynamic) const { StringRef SymbolName = unwrapOrError(Symbol->getName(StrTable)); if (!IsDynamic) return SymbolName; @@ -893,6 +956,56 @@ LLVM_READOBJ_ENUM_ENT(ELF, SHF_X86_64_LARGE) }; +static std::string getGNUFlags(uint64_t flags) { + std::string str; + for (auto entry : ElfSectionFlags) { + uint64_t flag = entry.Value & flags; + switch (flag) { + case ELF::SHF_WRITE: + str += "W"; + break; + case ELF::SHF_ALLOC: + str += "A"; + break; + case ELF::SHF_EXECINSTR: + str += "X"; + break; + case ELF::SHF_MERGE: + str += "M"; + break; + case ELF::SHF_STRINGS: + str += "S"; + break; + case ELF::SHF_INFO_LINK: + str += "I"; + break; + case ELF::SHF_LINK_ORDER: + str += "L"; + break; + case ELF::SHF_OS_NONCONFORMING: + str += "O"; + break; + case ELF::SHF_GROUP: + str += "G"; + break; + case ELF::SHF_TLS: + str += "T"; + break; + case ELF::SHF_EXCLUDE: + str += "E"; + break; + default: + if (flags & ELF::SHF_MASKOS) + str += "o"; + else if (flags & ELF::SHF_MASKPROC) + str += "p"; + else if (flag) + str += "x"; + } + } + return str; +} + static const char *getElfSegmentType(unsigned Arch, unsigned Type) { // Check potentially overlapped processor-specific // program header type. @@ -1040,9 +1153,9 @@ parseDynamicTable(LoadSegments); if (opts::Output == opts::GNU) - ELFDumperStyle.reset(new GNUStyle(Writer)); + ELFDumperStyle.reset(new GNUStyle(Writer, this)); else - ELFDumperStyle.reset(new LLVMStyle(Writer)); + ELFDumperStyle.reset(new LLVMStyle(Writer, this)); } template @@ -1145,261 +1258,29 @@ template void ELFDumper::printSections() { - ListScope SectionsD(W, "Sections"); - - int SectionIndex = -1; - for (const Elf_Shdr &Sec : Obj->sections()) { - ++SectionIndex; - - StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); - - DictScope SectionD(W, "Section"); - W.printNumber("Index", SectionIndex); - W.printNumber("Name", Name, Sec.sh_name); - W.printHex("Type", - getElfSectionType(Obj->getHeader()->e_machine, Sec.sh_type), - Sec.sh_type); - std::vector> SectionFlags(std::begin(ElfSectionFlags), - std::end(ElfSectionFlags)); - switch (Obj->getHeader()->e_machine) { - case EM_AMDGPU: - SectionFlags.insert(SectionFlags.end(), std::begin(ElfAMDGPUSectionFlags), - std::end(ElfAMDGPUSectionFlags)); - break; - case EM_HEXAGON: - SectionFlags.insert(SectionFlags.end(), - std::begin(ElfHexagonSectionFlags), - std::end(ElfHexagonSectionFlags)); - break; - case EM_MIPS: - SectionFlags.insert(SectionFlags.end(), std::begin(ElfMipsSectionFlags), - std::end(ElfMipsSectionFlags)); - break; - case EM_X86_64: - SectionFlags.insert(SectionFlags.end(), std::begin(ElfX86_64SectionFlags), - std::end(ElfX86_64SectionFlags)); - break; - default: - // Nothing to do. - break; - } - W.printFlags("Flags", Sec.sh_flags, makeArrayRef(SectionFlags)); - W.printHex("Address", Sec.sh_addr); - W.printHex("Offset", Sec.sh_offset); - W.printNumber("Size", Sec.sh_size); - W.printNumber("Link", Sec.sh_link); - W.printNumber("Info", Sec.sh_info); - W.printNumber("AddressAlignment", Sec.sh_addralign); - W.printNumber("EntrySize", Sec.sh_entsize); - - if (opts::SectionRelocations) { - ListScope D(W, "Relocations"); - printRelocations(&Sec); - } - - if (opts::SectionSymbols) { - ListScope D(W, "Symbols"); - const Elf_Shdr *Symtab = DotSymtabSec; - StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*Symtab)); - - for (const Elf_Sym &Sym : Obj->symbols(Symtab)) { - const Elf_Shdr *SymSec = - unwrapOrError(Obj->getSection(&Sym, Symtab, ShndxTable)); - if (SymSec == &Sec) - printSymbol(&Sym, Obj->symbol_begin(Symtab), StrTable, false); - } - } - - if (opts::SectionData && Sec.sh_type != ELF::SHT_NOBITS) { - ArrayRef Data = unwrapOrError(Obj->getSectionContents(&Sec)); - W.printBinaryBlock("SectionData", - StringRef((const char *)Data.data(), Data.size())); - } - } + ELFDumperStyle->printSections(Obj); } template void ELFDumper::printRelocations() { - ListScope D(W, "Relocations"); - - int SectionNumber = -1; - for (const Elf_Shdr &Sec : Obj->sections()) { - ++SectionNumber; - - if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA) - continue; - - StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); - - W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; - W.indent(); - - printRelocations(&Sec); - - W.unindent(); - W.startLine() << "}\n"; - } + ELFDumperStyle->printRelocations(Obj); } template void ELFDumper::printDynamicRelocations() { - if (DynRelRegion.Size && DynRelaRegion.Size) - report_fatal_error("There are both REL and RELA dynamic relocations"); - W.startLine() << "Dynamic Relocations {\n"; - W.indent(); - if (DynRelaRegion.Size > 0) - for (const Elf_Rela &Rela : dyn_relas()) - printDynamicRelocation(Rela); - else - for (const Elf_Rel &Rel : dyn_rels()) { - Elf_Rela Rela; - Rela.r_offset = Rel.r_offset; - Rela.r_info = Rel.r_info; - Rela.r_addend = 0; - printDynamicRelocation(Rela); - } - if (DynPLTRelRegion.EntSize == sizeof(Elf_Rela)) - for (const Elf_Rela &Rela : DynPLTRelRegion.getAsRange()) - printDynamicRelocation(Rela); - else - for (const Elf_Rel &Rel : DynPLTRelRegion.getAsRange()) { - Elf_Rela Rela; - Rela.r_offset = Rel.r_offset; - Rela.r_info = Rel.r_info; - Rela.r_addend = 0; - printDynamicRelocation(Rela); - } - W.unindent(); - W.startLine() << "}\n"; -} - -template -void ELFDumper::printRelocations(const Elf_Shdr *Sec) { - const Elf_Shdr *SymTab = unwrapOrError(Obj->getSection(Sec->sh_link)); - - switch (Sec->sh_type) { - case ELF::SHT_REL: - for (const Elf_Rel &R : Obj->rels(Sec)) { - Elf_Rela Rela; - Rela.r_offset = R.r_offset; - Rela.r_info = R.r_info; - Rela.r_addend = 0; - printRelocation(Rela, SymTab); - } - break; - case ELF::SHT_RELA: - for (const Elf_Rela &R : Obj->relas(Sec)) - printRelocation(R, SymTab); - break; - } + ELFDumperStyle->printDynamicRelocations(Obj); } -template -void ELFDumper::printRelocation(Elf_Rela Rel, const Elf_Shdr *SymTab) { - SmallString<32> RelocName; - Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); - StringRef TargetName; - const Elf_Sym *Sym = Obj->getRelocationSymbol(&Rel, SymTab); - if (Sym && Sym->getType() == ELF::STT_SECTION) { - const Elf_Shdr *Sec = - unwrapOrError(Obj->getSection(Sym, SymTab, ShndxTable)); - TargetName = unwrapOrError(Obj->getSectionName(Sec)); - } else if (Sym) { - StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab)); - TargetName = unwrapOrError(Sym->getName(StrTable)); - } - - if (opts::ExpandRelocs) { - DictScope Group(W, "Relocation"); - W.printHex("Offset", Rel.r_offset); - W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL())); - W.printNumber("Symbol", TargetName.size() > 0 ? TargetName : "-", - Rel.getSymbol(Obj->isMips64EL())); - W.printHex("Addend", Rel.r_addend); - } else { - raw_ostream& OS = W.startLine(); - OS << W.hex(Rel.r_offset) << " " << RelocName << " " - << (TargetName.size() > 0 ? TargetName : "-") << " " - << W.hex(Rel.r_addend) << "\n"; - } -} - -template -void ELFDumper::printDynamicRelocation(Elf_Rela Rel) { - SmallString<32> RelocName; - Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); - StringRef SymbolName; - uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL()); - const Elf_Sym *Sym = dynamic_symbols().begin() + SymIndex; - SymbolName = unwrapOrError(Sym->getName(DynamicStringTable)); - if (opts::ExpandRelocs) { - DictScope Group(W, "Relocation"); - W.printHex("Offset", Rel.r_offset); - W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL())); - W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-"); - W.printHex("Addend", Rel.r_addend); - } else { - raw_ostream &OS = W.startLine(); - OS << W.hex(Rel.r_offset) << " " << RelocName << " " - << (SymbolName.size() > 0 ? SymbolName : "-") << " " - << W.hex(Rel.r_addend) << "\n"; - } -} - -template -void ELFDumper::printSymbolsHelper(bool IsDynamic) { - StringRef StrTable; - Elf_Sym_Range Syms(nullptr, nullptr); - - if (IsDynamic) { - StrTable = DynamicStringTable; - Syms = dynamic_symbols(); - } else { - if (!DotSymtabSec) - return; - StrTable = unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec)); - Syms = Obj->symbols(DotSymtabSec); - } - for (const Elf_Sym &Sym : Syms) - printSymbol(&Sym, Syms.begin(), StrTable, IsDynamic); -} template void ELFDumper::printSymbols() { - ListScope Group(W, "Symbols"); - printSymbolsHelper(false); + ELFDumperStyle->printSymbols(Obj); } template void ELFDumper::printDynamicSymbols() { - ListScope Group(W, "DynamicSymbols"); - printSymbolsHelper(true); + ELFDumperStyle->printDynamicSymbols(Obj); } -template -void ELFDumper::printSymbol(const Elf_Sym *Symbol, - const Elf_Sym *FirstSym, StringRef StrTable, - bool IsDynamic) { - unsigned SectionIndex = 0; - StringRef SectionName; - getSectionNameIndex(*Obj, Symbol, FirstSym, ShndxTable, SectionName, - SectionIndex); - std::string FullSymbolName = getFullSymbolName(Symbol, StrTable, IsDynamic); - unsigned char SymbolType = Symbol->getType(); - - DictScope D(W, "Symbol"); - W.printNumber("Name", FullSymbolName, Symbol->st_name); - W.printHex ("Value", Symbol->st_value); - W.printNumber("Size", Symbol->st_size); - W.printEnum ("Binding", Symbol->getBinding(), - makeArrayRef(ElfSymbolBindings)); - if (Obj->getHeader()->e_machine == ELF::EM_AMDGPU && - SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS) - W.printEnum ("Type", SymbolType, makeArrayRef(AMDGPUSymbolTypes)); - else - W.printEnum ("Type", SymbolType, makeArrayRef(ElfSymbolTypes)); - W.printNumber("Other", Symbol->st_other); - W.printHex("Section", SectionName, SectionIndex); -} #define LLVM_READOBJ_TYPE_CASE(name) \ case DT_##name: return #name @@ -2292,8 +2173,7 @@ OS.flush(); } -template -void GNUStyle::printFileHeaders(const ELFFile *Obj) { +template void GNUStyle::printFileHeaders(const ELFO *Obj) { const Elf_Ehdr *e = Obj->getHeader(); OS << "ELF Header:\n"; OS << " Magic: "; @@ -2346,7 +2226,275 @@ } template -void LLVMStyle::printFileHeaders(const ELFFile *Obj) { +void GNUStyle::printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab, + const Elf_Rela &R, bool IsRela) { + std::string r_offset, r_info, r_addend = "", s_value; + SmallString<32> RelocName; + StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab)); + StringRef TargetName; + const Elf_Sym *Sym = nullptr; + unsigned bias; + const char *FmtCharHex; + if (ELFT::Is64Bits) { + bias = 8; + FmtCharHex = "%016" PRIx64; + } else { + bias = 0; + FmtCharHex = "%08" PRIx32; + } + Field fields[5] = {0, 10 + bias, 19 + 2 * bias, 42 + 2 * bias, 53 + 2 * bias}; + Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName); + Sym = Obj->getRelocationSymbol(&R, SymTab); + if (Sym && Sym->getType() == ELF::STT_SECTION) { + const Elf_Shdr *Sec = unwrapOrError( + Obj->getSection(Sym, SymTab, this->dumper()->getShndxTable())); + TargetName = unwrapOrError(Obj->getSectionName(Sec)); + } else if (Sym) { + TargetName = unwrapOrError(Sym->getName(StrTable)); + } + + if (Sym && IsRela) { + if (R.r_addend < 0) + r_addend = " - "; + else + r_addend = " + "; + } + r_offset = to_hexString(format(FmtCharHex, R.r_offset)); + r_info = to_hexString(format(FmtCharHex, R.r_info)); + if (IsRela) + r_addend += + R.r_addend == 0 ? std::string("0") : to_hexString(std::abs(R.r_addend), false); + if (Sym) + s_value = to_hexString(format(FmtCharHex, Sym->getValue())); + + fields[0] = r_offset; + fields[1] = r_info; + fields[2] = RelocName; + fields[3] = s_value; + fields[4] = TargetName; + for (auto &field : fields) + printField(field); + if (IsRela) + OS << r_addend; + OS << "\n"; +} + +template void GNUStyle::printRelocations(const ELFO *Obj) { + bool hasRelocSections = false; + for (const Elf_Shdr &Sec : Obj->sections()) { + if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA) + continue; + hasRelocSections = true; + StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); + unsigned entries = Sec.getEntityCount(); + uintX_t offset = Sec.sh_offset; + OS << "\nRelocation section '" << Name << "' at offset 0x" + << to_hexString(offset, false) << " contains " << to_string(entries) + << " entries:\n"; + if (ELFT::Is64Bits) + OS << " Offset Info Type" + << " Symbol's Value Symbol's Name"; + else + OS << " Offset Info Type Sym. Value " + << "Symbol's Name"; + OS << ((Sec.sh_type == ELF::SHT_RELA) ? " + Addend" : "") << "\n"; + + const Elf_Shdr *SymTab = unwrapOrError(Obj->getSection(Sec.sh_link)); + if (Sec.sh_type == ELF::SHT_REL) { + for (const auto &R : Obj->rels(&Sec)) { + Elf_Rela Rela; + Rela.r_offset = R.r_offset; + Rela.r_info = R.r_info; + Rela.r_addend = 0; + printRelocation(Obj, SymTab, Rela, false); + } + } else { + for (const auto &R : Obj->relas(&Sec)) + printRelocation(Obj, SymTab, R, true); + } + } + if (!hasRelocSections) + OS << "\nThere are no relocations in this file.\n"; +} + +std::string getSectiontypeString(unsigned arch, unsigned type) { + using namespace ELF; + switch (arch) { + case EM_ARM: + switch (type) { + case SHT_ARM_EXIDX: + return "ARM_EXIDX"; + case SHT_ARM_PREEMPTMAP: + return "ARM_PREEMPTMAP"; + case SHT_ARM_ATTRIBUTES: + return "ARM_ATTRIBUTES"; + case SHT_ARM_DEBUGOVERLAY: + return "ARM_DEBUGOVERLAY"; + case SHT_ARM_OVERLAYSECTION: + return "ARM_OVERLAYSECTION"; + } + case EM_X86_64: + switch (type) { + case SHT_X86_64_UNWIND: + return "X86_64_UNWIND"; + } + case EM_MIPS: + case EM_MIPS_RS3_LE: + switch (type) { + case SHT_MIPS_REGINFO: + return "MIPS_REGINFO"; + case SHT_MIPS_OPTIONS: + return "MIPS_OPTIONS"; + case SHT_MIPS_ABIFLAGS: + return "MIPS_ABIFLAGS"; + } + } + switch (type) { + case SHT_NULL: + return "NULL"; + case SHT_PROGBITS: + return "PROGBITS"; + case SHT_SYMTAB: + return "SYMTAB"; + case SHT_STRTAB: + return "STRTAB"; + case SHT_RELA: + return "RELA"; + case SHT_HASH: + return "HASH"; + case SHT_DYNAMIC: + return "DYNAMIC"; + case SHT_NOTE: + return "NOTE"; + case SHT_NOBITS: + return "NOBITS"; + case SHT_REL: + return "REL"; + case SHT_SHLIB: + return "SHLIB"; + case SHT_DYNSYM: + return "DYNSYM"; + case SHT_INIT_ARRAY: + return "INIT_ARRAY"; + case SHT_FINI_ARRAY: + return "FINI_ARRAY"; + case SHT_PREINIT_ARRAY: + return "PREINIT_ARRAY"; + case SHT_GROUP: + return "GROUP"; + case SHT_SYMTAB_SHNDX: + return "SYMTAB SECTION INDICES"; + // FIXME: Parse processor specific GNU attributes + case SHT_GNU_ATTRIBUTES: + return "ATTRIBUTES"; + case SHT_GNU_HASH: + return "GNU_HASH"; + case SHT_GNU_verdef: + return "VERDEF"; + case SHT_GNU_verneed: + return "VERNEED"; + case SHT_GNU_versym: + return "VERSYM"; + default: + return ""; + } + return ""; +} + +template void GNUStyle::printSections(const ELFO *Obj) { + size_t sectionIndex = 0; + std::string number, type, size, address, offset, flags, link, info, entrysize, + alignment; + unsigned bias; + const char *FmtChar; + + if (ELFT::Is64Bits) { + bias = 0; + FmtChar = "%016" PRIx64; + } else { + bias = 8; + FmtChar = "%08" PRIx32; + } + OS << "There are " << to_string(Obj->getHeader()->e_shnum) + << " section headers, starting at offset " + << "0x" << to_hexString(Obj->getHeader()->e_shoff, false) << ":\n\n"; + OS << "Section Headers:\n"; + Field fields[11] = {{"[Nr]", 2}, + {"Name", 7}, + {"Type", 25}, + {"Address", 41}, + {"Off", 58 - bias}, + {"Size", 65 - bias}, + {"ES", 72 - bias}, + {"Flg", 75 - bias}, + {"Lk", 79 - bias}, + {"Inf", 82 - bias}, + {"Al", 86 - bias}}; + for (auto &f : fields) + printField(f); + OS << "\n"; + + for (const Elf_Shdr &Sec : Obj->sections()) { + number = to_string(sectionIndex); + fields[0] = number; + fields[1] = unwrapOrError(Obj->getSectionName(&Sec)); + type = getSectiontypeString(Obj->getHeader()->e_machine, Sec.sh_type); + fields[2] = type; + address = to_hexString(format(FmtChar, Sec.sh_addr)); + fields[3] = address; + offset = to_hexString(format("%6.6x", Sec.sh_offset)); + fields[4] = offset; + size = to_hexString(format("%6.6x", Sec.sh_size)); + fields[5] = size; + entrysize = to_hexString(format("%2.2x", Sec.sh_entsize)); + fields[6] = entrysize; + flags = getGNUFlags(Sec.sh_flags); + fields[7] = flags; + link = to_string(Sec.sh_link); + fields[8] = link; + info = to_string(Sec.sh_info); + fields[9] = info; + alignment = to_string(Sec.sh_addralign); + fields[10] = alignment; + OS.PadToColumn(fields[0].Column); + OS << "[" << right_justify(fields[0].Str, 2) << "]"; + for (int i = 1; i < 7; i++) + printField(fields[i]); + OS.PadToColumn(fields[7].Column); + OS << right_justify(fields[7].Str, 3); + OS.PadToColumn(fields[8].Column); + OS << right_justify(fields[8].Str, 2); + OS.PadToColumn(fields[9].Column); + OS << right_justify(fields[9].Str, 3); + OS.PadToColumn(fields[10].Column); + OS << right_justify(fields[10].Str, 2); + OS << "\n"; + ++sectionIndex; + } + OS << "Key to Flags:\n" + << " W (write), A (alloc), X (execute), M (merge), S (strings), l " + "(large)\n" + << " I (info), L (link order), G (group), T (TLS), E (exclude),\ + x (unknown)\n" + << " O (extra OS processing required) o (OS specific),\ + p (processor specific)\n"; +} + +template void GNUStyle::printSymbols(const ELFO *Obj) { + OS << "GNU style symbols not implemented!\n"; +} + +template +void GNUStyle::printDynamicSymbols(const ELFO *Obj) { + OS << "GNU style dynamic symbols not implemented!\n"; +} + +template +void GNUStyle::printDynamicRelocations(const ELFO *Obj) { + OS << "GNU style dynamic relocations not implemented!\n"; +} + +template void LLVMStyle::printFileHeaders(const ELFO *Obj) { const Elf_Ehdr *e = Obj->getHeader(); { DictScope D(W, "ElfHeader"); @@ -2389,3 +2537,264 @@ W.printNumber("StringTableSectionIndex", e->e_shstrndx); } } + +template void LLVMStyle::printRelocations(const ELFO *Obj) { + ListScope D(W, "Relocations"); + + int SectionNumber = -1; + for (const Elf_Shdr &Sec : Obj->sections()) { + ++SectionNumber; + + if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA) + continue; + + StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); + + W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; + W.indent(); + + printRelocations(&Sec, Obj); + + W.unindent(); + W.startLine() << "}\n"; + } +} + +template +void LLVMStyle::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) { + const Elf_Shdr *SymTab = unwrapOrError(Obj->getSection(Sec->sh_link)); + + switch (Sec->sh_type) { + case ELF::SHT_REL: + for (const Elf_Rel &R : Obj->rels(Sec)) { + Elf_Rela Rela; + Rela.r_offset = R.r_offset; + Rela.r_info = R.r_info; + Rela.r_addend = 0; + printRelocation(Obj, Rela, SymTab); + } + break; + case ELF::SHT_RELA: + for (const Elf_Rela &R : Obj->relas(Sec)) + printRelocation(Obj, R, SymTab); + break; + } +} + +template +void LLVMStyle::printRelocation(const ELFO *Obj, Elf_Rela Rel, + const Elf_Shdr *SymTab) { + SmallString<32> RelocName; + Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); + StringRef TargetName; + const Elf_Sym *Sym = Obj->getRelocationSymbol(&Rel, SymTab); + if (Sym && Sym->getType() == ELF::STT_SECTION) { + const Elf_Shdr *Sec = unwrapOrError( + Obj->getSection(Sym, SymTab, this->dumper()->getShndxTable())); + TargetName = unwrapOrError(Obj->getSectionName(Sec)); + } else if (Sym) { + StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab)); + TargetName = unwrapOrError(Sym->getName(StrTable)); + } + + if (opts::ExpandRelocs) { + DictScope Group(W, "Relocation"); + W.printHex("Offset", Rel.r_offset); + W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL())); + W.printNumber("Symbol", TargetName.size() > 0 ? TargetName : "-", + Rel.getSymbol(Obj->isMips64EL())); + W.printHex("Addend", Rel.r_addend); + } else { + raw_ostream &OS = W.startLine(); + OS << W.hex(Rel.r_offset) << " " << RelocName << " " + << (TargetName.size() > 0 ? TargetName : "-") << " " + << W.hex(Rel.r_addend) << "\n"; + } +} + +template void LLVMStyle::printSections(const ELFO *Obj) { + ListScope SectionsD(W, "Sections"); + + int SectionIndex = -1; + for (const Elf_Shdr &Sec : Obj->sections()) { + ++SectionIndex; + + StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); + + DictScope SectionD(W, "Section"); + W.printNumber("Index", SectionIndex); + W.printNumber("Name", Name, Sec.sh_name); + W.printHex("Type", + getElfSectionType(Obj->getHeader()->e_machine, Sec.sh_type), + Sec.sh_type); + std::vector> SectionFlags(std::begin(ElfSectionFlags), + std::end(ElfSectionFlags)); + switch (Obj->getHeader()->e_machine) { + case EM_AMDGPU: + SectionFlags.insert(SectionFlags.end(), std::begin(ElfAMDGPUSectionFlags), + std::end(ElfAMDGPUSectionFlags)); + break; + case EM_HEXAGON: + SectionFlags.insert(SectionFlags.end(), + std::begin(ElfHexagonSectionFlags), + std::end(ElfHexagonSectionFlags)); + break; + case EM_MIPS: + SectionFlags.insert(SectionFlags.end(), std::begin(ElfMipsSectionFlags), + std::end(ElfMipsSectionFlags)); + break; + case EM_X86_64: + SectionFlags.insert(SectionFlags.end(), std::begin(ElfX86_64SectionFlags), + std::end(ElfX86_64SectionFlags)); + break; + default: + // Nothing to do. + break; + } + W.printFlags("Flags", Sec.sh_flags, makeArrayRef(SectionFlags)); + W.printHex("Address", Sec.sh_addr); + W.printHex("Offset", Sec.sh_offset); + W.printNumber("Size", Sec.sh_size); + W.printNumber("Link", Sec.sh_link); + W.printNumber("Info", Sec.sh_info); + W.printNumber("AddressAlignment", Sec.sh_addralign); + W.printNumber("EntrySize", Sec.sh_entsize); + + if (opts::SectionRelocations) { + ListScope D(W, "Relocations"); + printRelocations(&Sec, Obj); + } + + if (opts::SectionSymbols) { + ListScope D(W, "Symbols"); + const Elf_Shdr *Symtab = this->dumper()->getDotSymtabSec(); + StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*Symtab)); + + for (const Elf_Sym &Sym : Obj->symbols(Symtab)) { + const Elf_Shdr *SymSec = unwrapOrError( + Obj->getSection(&Sym, Symtab, this->dumper()->getShndxTable())); + if (SymSec == &Sec) + printSymbol(Obj, &Sym, Obj->symbol_begin(Symtab), StrTable, false); + } + } + + if (opts::SectionData && Sec.sh_type != ELF::SHT_NOBITS) { + ArrayRef Data = unwrapOrError(Obj->getSectionContents(&Sec)); + W.printBinaryBlock("SectionData", + StringRef((const char *)Data.data(), Data.size())); + } + } +} + +template +void LLVMStyle::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, + const Elf_Sym *First, StringRef StrTable, + bool IsDynamic) { + unsigned SectionIndex = 0; + StringRef SectionName; + getSectionNameIndex(*Obj, Symbol, First, this->dumper()->getShndxTable(), + SectionName, SectionIndex); + std::string FullSymbolName = + this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic); + unsigned char SymbolType = Symbol->getType(); + + DictScope D(W, "Symbol"); + W.printNumber("Name", FullSymbolName, Symbol->st_name); + W.printHex("Value", Symbol->st_value); + W.printNumber("Size", Symbol->st_size); + W.printEnum("Binding", Symbol->getBinding(), makeArrayRef(ElfSymbolBindings)); + if (Obj->getHeader()->e_machine == ELF::EM_AMDGPU && + SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS) + W.printEnum("Type", SymbolType, makeArrayRef(AMDGPUSymbolTypes)); + else + W.printEnum("Type", SymbolType, makeArrayRef(ElfSymbolTypes)); + W.printNumber("Other", Symbol->st_other); + W.printHex("Section", SectionName, SectionIndex); +} + +template +void LLVMStyle::printSymbolsHelper(const ELFO *Obj, bool IsDynamic) { + StringRef StrTable; + typename ELFO::Elf_Sym_Range Syms(nullptr, nullptr); + if (IsDynamic) { + StrTable = this->dumper()->getDynamicStringTable(); + Syms = this->dumper()->dynamic_symbols(); + } else { + if (!this->dumper()->getDotSymtabSec()) + return; + const auto DotSymtabSec = this->dumper()->getDotSymtabSec(); + StrTable = unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec)); + Syms = Obj->symbols(DotSymtabSec); + } + for (const Elf_Sym &Sym : Syms) + printSymbol(Obj, &Sym, Syms.begin(), StrTable, IsDynamic); +} + +template void LLVMStyle::printSymbols(const ELFO *Obj) { + ListScope Group(W, "Symbols"); + printSymbolsHelper(Obj, false); +} + +template +void LLVMStyle::printDynamicSymbols(const ELFO *Obj) { + ListScope Group(W, "DynamicSymbols"); + printSymbolsHelper(Obj, true); +} + +template +void LLVMStyle::printDynamicRelocations(const ELFO *Obj) { + const DynRegionInfo &DynRelRegion = this->dumper()->getDynRelRegion(); + const DynRegionInfo &DynRelaRegion = this->dumper()->getDynRelaRegion(); + const DynRegionInfo &DynPLTRelRegion = this->dumper()->getDynPLTRelRegion(); + if (DynRelRegion.Size && DynRelaRegion.Size) + report_fatal_error("There are both REL and RELA dynamic relocations"); + W.startLine() << "Dynamic Relocations {\n"; + W.indent(); + if (DynRelaRegion.Size > 0) + for (const Elf_Rela &Rela : this->dumper()->dyn_relas()) + printDynamicRelocation(Obj, Rela); + else + for (const Elf_Rel &Rel : this->dumper()->dyn_rels()) { + Elf_Rela Rela; + Rela.r_offset = Rel.r_offset; + Rela.r_info = Rel.r_info; + Rela.r_addend = 0; + printDynamicRelocation(Obj, Rela); + } + if (DynPLTRelRegion.EntSize == sizeof(Elf_Rela)) + for (const Elf_Rela &Rela : DynPLTRelRegion.getAsRange()) + printDynamicRelocation(Obj, Rela); + else + for (const Elf_Rel &Rel : DynPLTRelRegion.getAsRange()) { + Elf_Rela Rela; + Rela.r_offset = Rel.r_offset; + Rela.r_info = Rel.r_info; + Rela.r_addend = 0; + printDynamicRelocation(Obj, Rela); + } + W.unindent(); + W.startLine() << "}\n"; +} + +template +void LLVMStyle::printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel) { + SmallString<32> RelocName; + Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); + StringRef SymbolName; + uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL()); + const Elf_Sym *Sym = this->dumper()->dynamic_symbols().begin() + SymIndex; + SymbolName = + unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable())); + if (opts::ExpandRelocs) { + DictScope Group(W, "Relocation"); + W.printHex("Offset", Rel.r_offset); + W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL())); + W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-"); + W.printHex("Addend", Rel.r_addend); + } else { + raw_ostream &OS = W.startLine(); + OS << W.hex(Rel.r_offset) << " " << RelocName << " " + << (SymbolName.size() > 0 ? SymbolName : "-") << " " + << W.hex(Rel.r_addend) << "\n"; + } +} Index: tools/llvm-readobj/StreamWriter.h =================================================================== --- tools/llvm-readobj/StreamWriter.h +++ tools/llvm-readobj/StreamWriter.h @@ -62,6 +62,7 @@ const std::string to_hexString(uint64_t Value, bool UpperCase = true); const std::string to_string(uint64_t Value); +const std::string to_hexString(const format_object_base &obj); class StreamWriter { public: StreamWriter(raw_ostream &OS) Index: tools/llvm-readobj/StreamWriter.cpp =================================================================== --- tools/llvm-readobj/StreamWriter.cpp +++ tools/llvm-readobj/StreamWriter.cpp @@ -26,6 +26,12 @@ return stream.str(); } +const std::string to_hexString(const format_object_base &obj) { + char number[20] = {'0'}; + obj.print(number, 20); + return std::string(number); +} + void StreamWriter::printBinaryImpl(StringRef Label, StringRef Str, ArrayRef Data, bool Block) { if (Data.size() > 16)