Skip to content

Commit a6ee9fd

Browse files
author
Hemant Kulkarni
committedNov 23, 2016
llvm-readobj: Use hash tables to print dynamic symbols.
-symbols prints both .symtab and .dynsym symbols for GNU style in ELF. -dyn-symbols prints symbols looking up through hash tables. This helps validate hash tables. llvm-svn: 287786
1 parent ff8f2b8 commit a6ee9fd

File tree

2 files changed

+136
-1
lines changed

2 files changed

+136
-1
lines changed
 

‎llvm/test/tools/llvm-readobj/gnu-symbols.test

+28
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ RUN: llvm-readobj -symbols %p/Inputs/relocs.obj.elf-x86_64 --elf-output-style=GN
44
RUN: | FileCheck %s -check-prefix ELF64
55
RUN: llvm-readobj -symbols %p/Inputs/gnuhash.so.elf-x86_64 --elf-output-style=GNU \
66
RUN: | FileCheck %s -check-prefix DYN
7+
RUN: llvm-readobj -dyn-symbols %p/Inputs/dynamic-table-exe.x86 --elf-output-style=GNU \
8+
RUN: | FileCheck %s -check-prefix HASH
79

810
ELF32: Symbol table '.symtab' contains 5 entries:
911
ELF32-NEXT: Num: Value Size Type Bind Vis Ndx Name
@@ -44,3 +46,29 @@ DYN-NEXT: 8: 0000000000200268 0 NOTYPE GLOBAL DEFAULT 5 __bss_start
4446
DYN-NEXT: 9: 00000000000001b8 0 NOTYPE GLOBAL DEFAULT 4 foo
4547
DYN-NEXT: 10: 0000000000200268 0 NOTYPE GLOBAL DEFAULT 5 _edata
4648
DYN-NEXT: 11: 0000000000200268 0 NOTYPE GLOBAL DEFAULT 5 _end
49+
50+
HASH: Symbol table of .hash for image:
51+
HASH-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name
52+
HASH-NEXT: 9 0: 00000000 0 FUNC GLOBAL DEFAULT UND __gxx_personality_v0@CXXABI_1.3
53+
HASH-NEXT: 13 0: 00001b64 0 NOTYPE GLOBAL DEFAULT ABS _edata@
54+
HASH-NEXT: 7 0: 00000000 0 FUNC GLOBAL DEFAULT UND _ZNSt14basic_ifstreamIcSt11char_traitsIcEEC1EPKcSt13_Ios_Openmode@GLIBCXX_3.4
55+
HASH-NEXT: 2 0: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses@
56+
HASH-NEXT: 1 0: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__@
57+
HASH-NEXT: 16 1: 00000850 81 FUNC GLOBAL DEFAULT 14 main@
58+
HASH-NEXT: 10 1: 00000000 0 FUNC GLOBAL DEFAULT UND _Unwind_Resume@GCC_3.0
59+
HASH-NEXT: 8 1: 00000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.0
60+
HASH-NEXT: 12 1: 00001b68 0 NOTYPE GLOBAL DEFAULT ABS _end@
61+
HASH-NEXT: 6 1: 00000000 0 FUNC GLOBAL DEFAULT UND _ZNSt14basic_ifstreamIcSt11char_traitsIcEED1Ev@GLIBCXX_3.4
62+
HASH-NEXT: 5 1: 00000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable@
63+
HASH-NEXT: 4 1: 00000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable@
64+
HASH-NEXT: 3 1: 00000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.0
65+
HASH-NEXT: 11 2: 00000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.1.3
66+
HASH-NEXT: 15 2: 00001b64 0 NOTYPE GLOBAL DEFAULT ABS __bss_start@
67+
HASH-NEXT: 14 2: 0000093c 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used@
68+
HASH: Symbol table of .gnu.hash for image:
69+
HASH-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name
70+
HASH-NEXT: 12 0: 00001b68 0 NOTYPE GLOBAL DEFAULT ABS _end@
71+
HASH-NEXT: 13 0: 00001b64 0 NOTYPE GLOBAL DEFAULT ABS _edata@
72+
HASH-NEXT: 14 1: 0000093c 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used@
73+
HASH-NEXT: 15 1: 00001b64 0 NOTYPE GLOBAL DEFAULT ABS __bss_start@
74+
HASH-NEXT: 16 1: 00000850 81 FUNC GLOBAL DEFAULT 14 main@

‎llvm/tools/llvm-readobj/ELFDumper.cpp

+108-1
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,8 @@ template <typename ELFT> class GNUStyle : public DumpStyle<ELFT> {
328328
OS.flush();
329329
return OS;
330330
}
331+
void printHashedSymbol(const ELFO *Obj, const Elf_Sym *FirstSym, uint32_t Sym,
332+
StringRef StrTable, uint32_t Bucket);
331333
void printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab,
332334
const Elf_Rela &R, bool IsRela);
333335
void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
@@ -2812,15 +2814,120 @@ void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,
28122814
printField(Entry);
28132815
OS << "\n";
28142816
}
2817+
template <class ELFT>
2818+
void GNUStyle<ELFT>::printHashedSymbol(const ELFO *Obj, const Elf_Sym *FirstSym,
2819+
uint32_t Sym, StringRef StrTable,
2820+
uint32_t Bucket) {
2821+
std::string Num, Buc, Name, Value, Size, Binding, Type, Visibility, Section;
2822+
unsigned Width, Bias = 0;
2823+
if (ELFT::Is64Bits) {
2824+
Bias = 8;
2825+
Width = 16;
2826+
} else {
2827+
Bias = 0;
2828+
Width = 8;
2829+
}
2830+
Field Fields[9] = {0, 6, 11, 20 + Bias, 25 + Bias,
2831+
34 + Bias, 41 + Bias, 49 + Bias, 53 + Bias};
2832+
Num = to_string(format_decimal(Sym, 5));
2833+
Buc = to_string(format_decimal(Bucket, 3)) + ":";
2834+
2835+
const auto Symbol = FirstSym + Sym;
2836+
Value = to_string(format_hex_no_prefix(Symbol->st_value, Width));
2837+
Size = to_string(format_decimal(Symbol->st_size, 5));
2838+
unsigned char SymbolType = Symbol->getType();
2839+
if (Obj->getHeader()->e_machine == ELF::EM_AMDGPU &&
2840+
SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS)
2841+
Type = printEnum(SymbolType, makeArrayRef(AMDGPUSymbolTypes));
2842+
else
2843+
Type = printEnum(SymbolType, makeArrayRef(ElfSymbolTypes));
2844+
unsigned Vis = Symbol->getVisibility();
2845+
Binding = printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings));
2846+
Visibility = printEnum(Vis, makeArrayRef(ElfSymbolVisibilities));
2847+
Section = getSymbolSectionNdx(Obj, Symbol, FirstSym);
2848+
Name = this->dumper()->getFullSymbolName(Symbol, StrTable, true);
2849+
Fields[0].Str = Num;
2850+
Fields[1].Str = Buc;
2851+
Fields[2].Str = Value;
2852+
Fields[3].Str = Size;
2853+
Fields[4].Str = Type;
2854+
Fields[5].Str = Binding;
2855+
Fields[6].Str = Visibility;
2856+
Fields[7].Str = Section;
2857+
Fields[8].Str = Name;
2858+
for (auto &Entry : Fields)
2859+
printField(Entry);
2860+
OS << "\n";
2861+
}
28152862

28162863
template <class ELFT> void GNUStyle<ELFT>::printSymbols(const ELFO *Obj) {
2864+
if (opts::DynamicSymbols)
2865+
return;
28172866
this->dumper()->printSymbolsHelper(true);
28182867
this->dumper()->printSymbolsHelper(false);
28192868
}
28202869

28212870
template <class ELFT>
28222871
void GNUStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) {
2823-
this->dumper()->printSymbolsHelper(true);
2872+
if (this->dumper()->getDynamicStringTable().size() == 0)
2873+
return;
2874+
auto StringTable = this->dumper()->getDynamicStringTable();
2875+
auto DynSyms = this->dumper()->dynamic_symbols();
2876+
auto GnuHash = this->dumper()->getGnuHashTable();
2877+
auto SysVHash = this->dumper()->getHashTable();
2878+
2879+
// If no hash or .gnu.hash found, try using symbol table
2880+
if (GnuHash == nullptr && SysVHash == nullptr)
2881+
this->dumper()->printSymbolsHelper(true);
2882+
2883+
// Try printing .hash
2884+
if (this->dumper()->getHashTable()) {
2885+
OS << "\n Symbol table of .hash for image:\n";
2886+
if (ELFT::Is64Bits)
2887+
OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
2888+
else
2889+
OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
2890+
OS << "\n";
2891+
2892+
uint32_t NBuckets = SysVHash->nbucket;
2893+
uint32_t NChains = SysVHash->nchain;
2894+
auto Buckets = SysVHash->buckets();
2895+
auto Chains = SysVHash->chains();
2896+
for (uint32_t Buc = 0; Buc < NBuckets; Buc++) {
2897+
if (Buckets[Buc] == ELF::STN_UNDEF)
2898+
continue;
2899+
for (uint32_t Ch = Buckets[Buc]; Ch < NChains; Ch = Chains[Ch]) {
2900+
if (Ch == ELF::STN_UNDEF)
2901+
break;
2902+
printHashedSymbol(Obj, &DynSyms[0], Ch, StringTable, Buc);
2903+
}
2904+
}
2905+
}
2906+
2907+
// Try printing .gnu.hash
2908+
if (GnuHash) {
2909+
OS << "\n Symbol table of .gnu.hash for image:\n";
2910+
if (ELFT::Is64Bits)
2911+
OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
2912+
else
2913+
OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
2914+
OS << "\n";
2915+
uint32_t NBuckets = GnuHash->nbuckets;
2916+
auto Buckets = GnuHash->buckets();
2917+
for (uint32_t Buc = 0; Buc < NBuckets; Buc++) {
2918+
if (Buckets[Buc] == ELF::STN_UNDEF)
2919+
continue;
2920+
uint32_t Index = Buckets[Buc];
2921+
uint32_t GnuHashable = Index - GnuHash->symndx;
2922+
// Print whole chain
2923+
while (true) {
2924+
printHashedSymbol(Obj, &DynSyms[0], Index++, StringTable, Buc);
2925+
// Chain ends at symbol with stopper bit
2926+
if ((GnuHash->values(DynSyms.size())[GnuHashable++] & 1) == 1)
2927+
break;
2928+
}
2929+
}
2930+
}
28242931
}
28252932

28262933
static inline std::string printPhdrFlags(unsigned Flag) {

0 commit comments

Comments
 (0)
Please sign in to comment.