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,94 @@ 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; virtual ~DumpStyle() { } + DumpStyle(ELFDumper *Dumper) : Dumper(Dumper) {} + virtual void printRelocations(const ELFFile *Obj) = 0; + virtual void printSections(const ELFFile *Obj) = 0; + virtual void printSymbols(const ELFFile *Obj) = 0; + virtual void printDynamicSymbols(const ELFFile *Obj) = 0; + virtual void printDynamicRelocations(const ELFFile *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) {} + }; + 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 +406,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 +515,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 +564,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 +951,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 +1148,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 +1253,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"; + ELFDumperStyle->printDynamicRelocations(Obj); } -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; - } -} - -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 +2168,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 +2221,288 @@ } 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 Offset, Info, Addend = "", 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; + } + // First two fields are bit width dependent. The rest of them are after are + // fixed width. + 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) + Addend = " - "; + else + Addend = " + "; + } + + uint64_t RelOffset = R.r_offset; + Offset = to_string(format(FmtCharHex, RelOffset)); + uint64_t RelInfo = R.r_info; + Info = to_string(format(FmtCharHex, RelInfo)); + int64_t RelAddend = R.r_addend; + if (IsRela) + Addend += RelAddend == 0 ? std::string("0") + : to_hexString(std::abs(RelAddend), false); + uint64_t ReValue; + if (Sym) { + ReValue = Sym->getValue(); + Value = to_string(format(FmtCharHex, ReValue)); + } + + Fields[0].Str = Offset; + Fields[1].Str = Info; + Fields[2].Str = RelocName; + Fields[3].Str = Value; + Fields[4].Str = TargetName; + for (auto &field : Fields) + printField(field); + if (IsRela) + OS << 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 " << 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].Str = Number; + Fields[1].Str = unwrapOrError(Obj->getSectionName(&Sec)); + Type = getSectionTypeString(Obj->getHeader()->e_machine, Sec.sh_type); + Fields[2].Str = Type; + uint64_t ShAddr = Sec.sh_addr; + Address = to_string(format(FmtChar, ShAddr)); + Fields[3].Str = Address; + uint64_t ShOffset = Sec.sh_offset; + Offset = to_string(format("%6.6x", ShOffset)); + Fields[4].Str = Offset; + uint64_t ShSize = Sec.sh_size; + Size = to_string(format("%6.6x", ShSize)); + Fields[5].Str = Size; + uint64_t ShEntSize = Sec.sh_entsize; + EntrySize = to_string(format("%2.2x", ShEntSize)); + Fields[6].Str = EntrySize; + Flags = getGNUFlags(Sec.sh_flags); + Fields[7].Str = Flags; + Link = to_string(Sec.sh_link); + Fields[8].Str = Link; + Info = to_string(Sec.sh_info); + Fields[9].Str = Info; + Alignment = to_string(Sec.sh_addralign); + Fields[10].Str = 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 +2545,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 @@ -61,6 +61,7 @@ raw_ostream &operator<<(raw_ostream &OS, const HexNumber& Value); const std::string to_hexString(uint64_t Value, bool UpperCase = true); const std::string to_string(uint64_t Value); +const std::string to_string(const format_object_base &Obj); class StreamWriter { public: 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_string(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)