[llvm-readobj] Impl GNU style symbols printing

Implements "readelf -sW and readelf -DsW"

Differential Revision: http://reviews.llvm.org/D18224

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@263952 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Hemant Kulkarni 2016-03-21 17:18:23 +00:00
parent 43f3f60fb4
commit 962167f0e2
3 changed files with 220 additions and 40 deletions

View File

@ -0,0 +1,46 @@
RUN: llvm-readobj -symbols %p/Inputs/symbols-proc-specific.elf-hexagon \
RUN: --elf-output-style=GNU | FileCheck %s -check-prefix ELF32
RUN: llvm-readobj -symbols %p/Inputs/relocs.obj.elf-x86_64 --elf-output-style=GNU \
RUN: | FileCheck %s -check-prefix ELF64
RUN: llvm-readobj -symbols %p/Inputs/gnuhash.so.elf-x86_64 --elf-output-style=GNU \
RUN: | FileCheck %s -check-prefix DYN
ELF32: Symbol table '.symtab' contains 5 entries:
ELF32-NEXT: Num: Value Size Type Bind Vis Ndx Name
ELF32-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
ELF32-NEXT: 1: 00000000 0 FILE LOCAL DEFAULT ABS a.c
ELF32-NEXT: 2: 00000000 20 FUNC GLOBAL DEFAULT 2 main
ELF32-NEXT: 3: 00000004 4 OBJECT GLOBAL DEFAULT PRC[0xff03] x
ELF32-NEXT: 4: 00000000 4 OBJECT GLOBAL DEFAULT 3 y
ELF64: Symbol table '.symtab' contains 6 entries:
ELF64-NEXT: Num: Value Size Type Bind Vis Ndx Name
ELF64-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
ELF64-NEXT: 1: 0000000000000000 0 SECTION LOCAL DEFAULT 1
ELF64-NEXT: 2: 0000000000000000 0 SECTION LOCAL DEFAULT 3
ELF64-NEXT: 3: 0000000000000000 0 SECTION LOCAL DEFAULT 4
ELF64-NEXT: 4: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _GLOBAL_OFFSET_TABLE_
ELF64-NEXT: 5: 0000000000000000 0 TLS GLOBAL DEFAULT UND sym
DYN:Symbol table '.dynsym' contains 5 entries:
DYN-NEXT: Num: Value Size Type Bind Vis Ndx Name
DYN-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
DYN-NEXT: 1: 00000000000001b8 0 NOTYPE GLOBAL DEFAULT 4 foo
DYN-NEXT: 2: 0000000000200268 0 NOTYPE GLOBAL DEFAULT 5 _edata
DYN-NEXT: 3: 0000000000200268 0 NOTYPE GLOBAL DEFAULT 5 _end
DYN-NEXT: 4: 0000000000200268 0 NOTYPE GLOBAL DEFAULT 5 __bss_start
DYN: Symbol table '.symtab' contains 12 entries:
DYN-NEXT: Num: Value Size Type Bind Vis Ndx Name
DYN-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
DYN-NEXT: 1: 00000000000000e8 0 SECTION LOCAL DEFAULT 1
DYN-NEXT: 2: 0000000000000120 0 SECTION LOCAL DEFAULT 2
DYN-NEXT: 3: 0000000000000198 0 SECTION LOCAL DEFAULT 3
DYN-NEXT: 4: 00000000000001b8 0 SECTION LOCAL DEFAULT 4
DYN-NEXT: 5: 00000000002001b8 0 SECTION LOCAL DEFAULT 5
DYN-NEXT: 6: 00000000002001b8 0 OBJECT LOCAL DEFAULT 5 _DYNAMIC
DYN-NEXT: 7: 0000000000200268 0 OBJECT LOCAL DEFAULT 5 _GLOBAL_OFFSET_TABLE_
DYN-NEXT: 8: 0000000000200268 0 NOTYPE GLOBAL DEFAULT 5 __bss_start
DYN-NEXT: 9: 00000000000001b8 0 NOTYPE GLOBAL DEFAULT 4 foo
DYN-NEXT: 10: 0000000000200268 0 NOTYPE GLOBAL DEFAULT 5 _edata
DYN-NEXT: 11: 0000000000200268 0 NOTYPE GLOBAL DEFAULT 5 _end

View File

@ -159,9 +159,6 @@ private:
void parseDynamicTable(ArrayRef<const Elf_Phdr *> LoadSegments);
void printSymbol(const Elf_Sym *Symbol, const Elf_Sym *FirstSym,
StringRef StrTable, bool IsDynamic);
void printValue(uint64_t Type, uint64_t Value);
StringRef getDynamicString(uint64_t Offset) const;
@ -182,6 +179,7 @@ private:
const Elf_Hash *HashTable = nullptr;
const Elf_GnuHash *GnuHashTable = nullptr;
const Elf_Shdr *DotSymtabSec = nullptr;
StringRef DynSymtabName;
ArrayRef<Elf_Word> ShndxTable;
const Elf_Shdr *dot_gnu_version_sec = nullptr; // .gnu.version
@ -224,6 +222,8 @@ public:
Elf_Rela_Range dyn_relas() const;
std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable,
bool IsDynamic) const;
void printSymbolsHelper(bool IsDynamic) const;
const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; }
ArrayRef<Elf_Word> getShndxTable() const { return ShndxTable; }
StringRef getDynamicStringTable() const { return DynamicStringTable; }
@ -232,19 +232,54 @@ public:
const DynRegionInfo &getDynPLTRelRegion() const { return DynPLTRelRegion; }
};
template <class ELFT>
void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {
StringRef StrTable, SymtabName;
size_t Entries = 0;
Elf_Sym_Range Syms(nullptr, nullptr);
if (IsDynamic) {
StrTable = DynamicStringTable;
Syms = dynamic_symbols();
SymtabName = DynSymtabName;
if (DynSymRegion.Addr)
Entries = DynSymRegion.Size / DynSymRegion.EntSize;
} else {
if (!DotSymtabSec)
return;
StrTable = unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec));
Syms = Obj->symbols(DotSymtabSec);
SymtabName = unwrapOrError(Obj->getSectionName(DotSymtabSec));
Entries = DotSymtabSec->getEntityCount();
}
if (Syms.begin() == Syms.end())
return;
ELFDumperStyle->printSymtabMessage(Obj, SymtabName, Entries);
for (const auto &Sym : Syms)
ELFDumperStyle->printSymbol(Obj, &Sym, Syms.begin(), StrTable, IsDynamic);
}
template <typename ELFT> class DumpStyle {
public:
virtual void printFileHeaders(const ELFFile<ELFT> *Obj) = 0;
virtual ~DumpStyle() { }
using Elf_Shdr = typename ELFFile<ELFT>::Elf_Shdr;
using Elf_Sym = typename ELFFile<ELFT>::Elf_Sym;
DumpStyle(ELFDumper<ELFT> *Dumper) : Dumper(Dumper) {}
virtual ~DumpStyle() {}
virtual void printFileHeaders(const ELFFile<ELFT> *Obj) = 0;
virtual void printGroupSections(const ELFFile<ELFT> *Obj) = 0;
virtual void printRelocations(const ELFFile<ELFT> *Obj) = 0;
virtual void printSections(const ELFFile<ELFT> *Obj) = 0;
virtual void printSymbols(const ELFFile<ELFT> *Obj) = 0;
virtual void printDynamicSymbols(const ELFFile<ELFT> *Obj) = 0;
virtual void printDynamicRelocations(const ELFFile<ELFT> *Obj) = 0;
virtual void printSymtabMessage(const ELFFile<ELFT> *obj, StringRef Name,
size_t Offset) {
return;
}
virtual void printSymbol(const ELFFile<ELFT> *Obj, const Elf_Sym *Symbol,
const Elf_Sym *FirstSym, StringRef StrTable,
bool IsDynamic) = 0;
const ELFDumper<ELFT> *dumper() const { return Dumper; }
private:
const ELFDumper<ELFT> *Dumper;
};
@ -262,6 +297,8 @@ public:
void printSymbols(const ELFO *Obj) override;
void printDynamicSymbols(const ELFO *Obj) override;
void printDynamicRelocations(const ELFO *Obj) override;
virtual void printSymtabMessage(const ELFO *Obj, StringRef Name,
size_t Offset) override;
private:
struct Field {
@ -278,6 +315,7 @@ private:
return EnumItem.AltName;
return to_hexString(Value, false);
}
formatted_raw_ostream &printField(struct Field F) {
if (F.Column != 0)
OS.PadToColumn(F.Column);
@ -287,6 +325,10 @@ private:
}
void printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab,
const Elf_Rela &R, bool IsRela);
void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
StringRef StrTable, bool IsDynamic) override;
std::string getSymbolSectionNdx(const ELFO *Obj, const Elf_Sym *Symbol,
const Elf_Sym *FirstSym);
};
template <typename ELFT> class LLVMStyle : public DumpStyle<ELFT> {
@ -300,17 +342,15 @@ public:
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);
void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
StringRef StrTable, bool IsDynamic) override;
StreamWriter &W;
};
@ -840,15 +880,21 @@ static const EnumEntry<unsigned> ElfSymbolBindings[] = {
{"Weak", "WEAK", ELF::STB_WEAK},
{"Unique", "UNIQUE", ELF::STB_GNU_UNIQUE}};
static const EnumEntry<unsigned> ElfSymbolVisibilities[] = {
{"DEFAULT", "DEFAULT", ELF::STV_DEFAULT},
{"INTERNAL", "INTERNAL", ELF::STV_INTERNAL},
{"HIDDEN", "HIDDEN", ELF::STV_HIDDEN},
{"PROTECTED", "PROTECTED", ELF::STV_PROTECTED}};
static const EnumEntry<unsigned> ElfSymbolTypes[] = {
{"None", "NOTYPE", ELF::STT_NOTYPE},
{"Object", "OBJECT", ELF::STT_OBJECT},
{"Function", "FUNCTION", ELF::STT_FUNC},
{"Section", "SECTION", ELF::STT_SECTION},
{"File", "FILE", ELF::STT_FILE},
{"Common", "COMMON", ELF::STT_COMMON},
{"TLS", "TLS", ELF::STT_TLS},
{"GNU_IFunc", "IFUNC", ELF::STT_GNU_IFUNC}};
{"None", "NOTYPE", ELF::STT_NOTYPE},
{"Object", "OBJECT", ELF::STT_OBJECT},
{"Function", "FUNC", ELF::STT_FUNC},
{"Section", "SECTION", ELF::STT_SECTION},
{"File", "FILE", ELF::STT_FILE},
{"Common", "COMMON", ELF::STT_COMMON},
{"TLS", "TLS", ELF::STT_TLS},
{"GNU_IFunc", "IFUNC", ELF::STT_GNU_IFUNC}};
static const EnumEntry<unsigned> AMDGPUSymbolTypes[] = {
{ "AMDGPU_HSA_KERNEL", ELF::STT_AMDGPU_HSA_KERNEL },
@ -1108,6 +1154,8 @@ ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer)
if (DynSymRegion.Size)
reportError("Multilpe SHT_DYNSYM");
DynSymRegion = createDRIFrom(&Sec);
// This is only used (if Elf_Shdr present)for naming section in GNU style
DynSymtabName = unwrapOrError(Obj->getSectionName(&Sec));
break;
case ELF::SHT_SYMTAB_SHNDX:
ShndxTable = unwrapOrError(Obj->getSHNDXTable(Sec));
@ -2468,13 +2516,117 @@ template <class ELFT> void GNUStyle<ELFT>::printSections(const ELFO *Obj) {
p (processor specific)\n";
}
template <class ELFT>
void GNUStyle<ELFT>::printSymtabMessage(const ELFO *Obj, StringRef Name,
size_t Entries) {
if (Name.size())
OS << "\nSymbol table '" << Name << "' contains " << Entries
<< " entries:\n";
else
OS << "\n Symbol table for image:\n";
if (ELFT::Is64Bits)
OS << " Num: Value Size Type Bind Vis Ndx Name\n";
else
OS << " Num: Value Size Type Bind Vis Ndx Name\n";
}
template <class ELFT>
std::string GNUStyle<ELFT>::getSymbolSectionNdx(const ELFO *Obj,
const Elf_Sym *Symbol,
const Elf_Sym *FirstSym) {
unsigned SectionIndex = Symbol->st_shndx;
switch (SectionIndex) {
case ELF::SHN_UNDEF:
return "UND";
case ELF::SHN_ABS:
return "ABS";
case ELF::SHN_COMMON:
return "COM";
case ELF::SHN_XINDEX:
SectionIndex = Obj->getExtendedSymbolTableIndex(
Symbol, FirstSym, this->dumper()->getShndxTable());
default:
// Find if:
// Processor specific
if (SectionIndex >= ELF::SHN_LOPROC && SectionIndex <= ELF::SHN_HIPROC)
return std::string("PRC[0x") +
to_string(format_hex_no_prefix(SectionIndex, 4)) + "]";
// OS specific
if (SectionIndex >= ELF::SHN_LOOS && SectionIndex <= ELF::SHN_HIOS)
return std::string("OS[0x") +
to_string(format_hex_no_prefix(SectionIndex, 4)) + "]";
// Architecture reserved:
if (SectionIndex >= ELF::SHN_LORESERVE &&
SectionIndex <= ELF::SHN_HIRESERVE)
return std::string("RSV[0x") +
to_string(format_hex_no_prefix(SectionIndex, 4)) + "]";
// A normal section with an index
return to_string(format_decimal(SectionIndex, 3));
}
}
template <class ELFT>
void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,
const Elf_Sym *FirstSym, StringRef StrTable,
bool IsDynamic) {
static int Idx = 0;
static bool Dynamic = true;
size_t Width;
// If this function was called with a different value from IsDynamic
// from last call, happens when we move from dynamic to static symbol
// table, "Num" field should be reset.
if (!Dynamic != !IsDynamic) {
Idx = 0;
Dynamic = false;
}
std::string Num, Name, Value, Size, Binding, Type, Visibility, Section;
unsigned Bias = 0;
if (ELFT::Is64Bits) {
Bias = 8;
Width = 16;
} else {
Bias = 0;
Width = 8;
}
Field Fields[8] = {0, 8, 17 + Bias, 23 + Bias,
31 + Bias, 38 + Bias, 47 + Bias, 51 + Bias};
Num = to_string(format_decimal(Idx++, 6)) + ":";
Value = to_string(format_hex_no_prefix(Symbol->st_value, Width));
Size = to_string(format_decimal(Symbol->st_size, 5));
unsigned char SymbolType = Symbol->getType();
if (Obj->getHeader()->e_machine == ELF::EM_AMDGPU &&
SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS)
Type = printEnum(SymbolType, makeArrayRef(AMDGPUSymbolTypes));
else
Type = printEnum(SymbolType, makeArrayRef(ElfSymbolTypes));
unsigned Vis = Symbol->getVisibility();
Binding = printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings));
Visibility = printEnum(Vis, makeArrayRef(ElfSymbolVisibilities));
Section = getSymbolSectionNdx(Obj, Symbol, FirstSym);
Name = this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic);
Fields[0].Str = Num;
Fields[1].Str = Value;
Fields[2].Str = Size;
Fields[3].Str = Type;
Fields[4].Str = Binding;
Fields[5].Str = Visibility;
Fields[6].Str = Section;
Fields[7].Str = Name;
for (auto &Entry : Fields)
printField(Entry);
OS << "\n";
}
template <class ELFT> void GNUStyle<ELFT>::printSymbols(const ELFO *Obj) {
OS << "GNU style symbols not implemented!\n";
this->dumper()->printSymbolsHelper(true);
this->dumper()->printSymbolsHelper(false);
}
template <class ELFT>
void GNUStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) {
OS << "GNU style dynamic symbols not implemented!\n";
this->dumper()->printSymbolsHelper(true);
}
template <class ELFT>
@ -2735,33 +2887,15 @@ void LLVMStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,
W.printHex("Section", SectionName, SectionIndex);
}
template <class ELFT>
void LLVMStyle<ELFT>::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 <class ELFT> void LLVMStyle<ELFT>::printSymbols(const ELFO *Obj) {
ListScope Group(W, "Symbols");
printSymbolsHelper(Obj, false);
this->dumper()->printSymbolsHelper(false);
}
template <class ELFT>
void LLVMStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) {
ListScope Group(W, "DynamicSymbols");
printSymbolsHelper(Obj, true);
this->dumper()->printSymbolsHelper(true);
}
template <class ELFT>