diff --git a/test/tools/llvm-readobj/gnu-hash-symbols.test b/test/tools/llvm-readobj/gnu-hash-symbols.test new file mode 100644 index 00000000000..28ec34d4064 --- /dev/null +++ b/test/tools/llvm-readobj/gnu-hash-symbols.test @@ -0,0 +1,107 @@ +# RUN: llvm-readelf --hash-symbols %p/Inputs/dynamic-table-exe.x86 \ +# RUN: | FileCheck %s --check-prefix HASH + +# HASH: Symbol table of .hash for image: +# HASH-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name +# HASH-NEXT: 9 0: 00000000 0 FUNC GLOBAL DEFAULT UND __gxx_personality_v0@CXXABI_1.3 +# HASH-NEXT: 13 0: 00001b64 0 NOTYPE GLOBAL DEFAULT ABS _edata{{$}} +# HASH-NEXT: 7 0: 00000000 0 FUNC GLOBAL DEFAULT UND _ZNSt14basic_ifstreamIcSt11char_traitsIcEEC1EPKcSt13_Ios_Openmode@GLIBCXX_3.4 +# HASH-NEXT: 2 0: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses{{$}} +# HASH-NEXT: 1 0: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__{{$}} +# HASH-NEXT: 16 1: 00000850 81 FUNC GLOBAL DEFAULT 14 main{{$}} +# HASH-NEXT: 10 1: 00000000 0 FUNC GLOBAL DEFAULT UND _Unwind_Resume@GCC_3.0 +# HASH-NEXT: 8 1: 00000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.0 +# HASH-NEXT: 12 1: 00001b68 0 NOTYPE GLOBAL DEFAULT ABS _end{{$}} +# HASH-NEXT: 6 1: 00000000 0 FUNC GLOBAL DEFAULT UND _ZNSt14basic_ifstreamIcSt11char_traitsIcEED1Ev@GLIBCXX_3.4 +# HASH-NEXT: 5 1: 00000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable{{$}} +# HASH-NEXT: 4 1: 00000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable{{$}} +# HASH-NEXT: 3 1: 00000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.0 +# HASH-NEXT: 11 2: 00000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.1.3 +# HASH-NEXT: 15 2: 00001b64 0 NOTYPE GLOBAL DEFAULT ABS __bss_start{{$}} +# HASH-NEXT: 14 2: 0000093c 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used{{$}} +# HASH: Symbol table of .gnu.hash for image: +# HASH-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name +# HASH-NEXT: 12 0: 00001b68 0 NOTYPE GLOBAL DEFAULT ABS _end{{$}} +# HASH-NEXT: 13 0: 00001b64 0 NOTYPE GLOBAL DEFAULT ABS _edata{{$}} +# HASH-NEXT: 14 1: 0000093c 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used{{$}} +# HASH-NEXT: 15 1: 00001b64 0 NOTYPE GLOBAL DEFAULT ABS __bss_start{{$}} +# HASH-NEXT: 16 1: 00000850 81 FUNC GLOBAL DEFAULT 14 main{{$}} + +## Show that if there are no hash sections, we do not print anything. +# RUN: yaml2obj %s -o %t.o +# RUN: llvm-readelf --hash-symbols %t.o \ +# RUN: | FileCheck %s --check-prefix NO-HASH --allow-empty + +# NO-HASH-NOT: {{.}} + +## Sanity check that we can still find the dynamic symbols (i.e. the above test +## doesn't pass due to a mistake in the dynamic section). +# RUN: llvm-readelf --dyn-symbols %t.o | FileCheck %s --check-prefix DYNSYMS + +# DYNSYMS: Symbol table '.dynsym' contains 2 entries: + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + ## TODO: Replace the raw section contents with more meaningful dynamic + ## tags/symbols/etc, once yaml2obj supports it. + ## FIXME: yaml2obj does not currently allow custom addresses for .dynstr and + ## .dynsym if DynamicSymbols are specified. + ## See https://bugs.llvm.org/show_bug.cgi?id=40339 + - Name: .dynstr + Type: SHT_STRTAB + Flags: [ SHF_ALLOC ] + AddressAlign: 0x100 + EntSize: 0x1 + ## "\0_Z3fooi\0" + Content: "005f5a33666f6f6900" + - Name: .dynsym + Type: SHT_DYNSYM + Flags: [ SHF_ALLOC ] + Link: .dynstr + Info: 1 + Address: 0x100 + AddressAlign: 0x100 + EntSize: 0x18 + ## Null symbol; + ## st_name: 1; st_info: Global | Func; st_other: 0; + ## st_shndx: .text.foo; st_value: 0x2000; st_size: 0 + Content: "000000000000000000000000000000000000000000000000010000001200040000200000000000000000000000000000" + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_ALLOC ] + Link: .dynstr + Address: 0x1000 + AddressAlign: 0x1000 + ## DT_STRTAB - 0x0 + ## DT_STRSZ - 0x9 + ## DT_SYMTAB - 0x100 + ## DT_SYMENT - 0x18 + ## DT_NULL - 0x0 + Content: "050000000000000000000000000000000a000000000000000900000000000000060000000000000000010000000000000b00000000000000180000000000000000000000000000000000000000000000" + - Name: .text.foo + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ] + Size: 0x40 + Address: 0x2000 + AddressAlign: 0x2000 +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_R, PF_X ] + VAddr: 0x0 + PAddr: 0x0 + Sections: + - Section: .dynsym + - Section: .dynstr + - Section: .dynamic + - Section: .text.foo + - Type: PT_DYNAMIC + Flags: [ PF_R ] + VAddr: 0x1000 + PAddr: 0x1000 + Sections: + - Section: .dynamic diff --git a/test/tools/llvm-readobj/gnu-symbols.test b/test/tools/llvm-readobj/gnu-symbols.test index 7eb1123e859..77883717f5f 100644 --- a/test/tools/llvm-readobj/gnu-symbols.test +++ b/test/tools/llvm-readobj/gnu-symbols.test @@ -3,9 +3,9 @@ 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 -RUN: llvm-readobj -dyn-symbols %p/Inputs/dynamic-table-exe.x86 --elf-output-style=GNU \ -RUN: | FileCheck %s -check-prefix HASH +RUN: | FileCheck %s -check-prefixes=SYMTAB,DYN +RUN: llvm-readobj -dyn-symbols %p/Inputs/gnuhash.so.elf-x86_64 --elf-output-style=GNU \ +RUN: | FileCheck %s -check-prefixes=NO-SYMTAB,DYN ELF32: Symbol table '.symtab' contains 5 entries: ELF32-NEXT: Num: Value Size Type Bind Vis Ndx Name @@ -24,6 +24,8 @@ 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 +NO-SYMTAB-NOT: Symbol table '.symtab' + 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 @@ -32,43 +34,19 @@ 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 +NO-SYMTAB-NOT: Symbol table '.symtab' -HASH: Symbol table of .hash for image: -HASH-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name -HASH-NEXT: 9 0: 00000000 0 FUNC GLOBAL DEFAULT UND __gxx_personality_v0@CXXABI_1.3 -HASH-NEXT: 13 0: 00001b64 0 NOTYPE GLOBAL DEFAULT ABS _edata{{$}} -HASH-NEXT: 7 0: 00000000 0 FUNC GLOBAL DEFAULT UND _ZNSt14basic_ifstreamIcSt11char_traitsIcEEC1EPKcSt13_Ios_Openmode@GLIBCXX_3.4 -HASH-NEXT: 2 0: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses{{$}} -HASH-NEXT: 1 0: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__{{$}} -HASH-NEXT: 16 1: 00000850 81 FUNC GLOBAL DEFAULT 14 main{{$}} -HASH-NEXT: 10 1: 00000000 0 FUNC GLOBAL DEFAULT UND _Unwind_Resume@GCC_3.0 -HASH-NEXT: 8 1: 00000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.0 -HASH-NEXT: 12 1: 00001b68 0 NOTYPE GLOBAL DEFAULT ABS _end{{$}} -HASH-NEXT: 6 1: 00000000 0 FUNC GLOBAL DEFAULT UND _ZNSt14basic_ifstreamIcSt11char_traitsIcEED1Ev@GLIBCXX_3.4 -HASH-NEXT: 5 1: 00000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable{{$}} -HASH-NEXT: 4 1: 00000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable{{$}} -HASH-NEXT: 3 1: 00000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.0 -HASH-NEXT: 11 2: 00000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.1.3 -HASH-NEXT: 15 2: 00001b64 0 NOTYPE GLOBAL DEFAULT ABS __bss_start{{$}} -HASH-NEXT: 14 2: 0000093c 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used{{$}} -HASH: Symbol table of .gnu.hash for image: -HASH-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name -HASH-NEXT: 12 0: 00001b68 0 NOTYPE GLOBAL DEFAULT ABS _end{{$}} -HASH-NEXT: 13 0: 00001b64 0 NOTYPE GLOBAL DEFAULT ABS _edata{{$}} -HASH-NEXT: 14 1: 0000093c 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used{{$}} -HASH-NEXT: 15 1: 00001b64 0 NOTYPE GLOBAL DEFAULT ABS __bss_start{{$}} -HASH-NEXT: 16 1: 00000850 81 FUNC GLOBAL DEFAULT 14 main{{$}} +SYMTAB: Symbol table '.symtab' contains 12 entries: +SYMTAB-NEXT: Num: Value Size Type Bind Vis Ndx Name +SYMTAB-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND +SYMTAB-NEXT: 1: 00000000000000e8 0 SECTION LOCAL DEFAULT 1 +SYMTAB-NEXT: 2: 0000000000000120 0 SECTION LOCAL DEFAULT 2 +SYMTAB-NEXT: 3: 0000000000000198 0 SECTION LOCAL DEFAULT 3 +SYMTAB-NEXT: 4: 00000000000001b8 0 SECTION LOCAL DEFAULT 4 +SYMTAB-NEXT: 5: 00000000002001b8 0 SECTION LOCAL DEFAULT 5 +SYMTAB-NEXT: 6: 00000000002001b8 0 OBJECT LOCAL DEFAULT 5 _DYNAMIC +SYMTAB-NEXT: 7: 0000000000200268 0 OBJECT LOCAL DEFAULT 5 _GLOBAL_OFFSET_TABLE_ +SYMTAB-NEXT: 8: 0000000000200268 0 NOTYPE GLOBAL DEFAULT 5 __bss_start +SYMTAB-NEXT: 9: 00000000000001b8 0 NOTYPE GLOBAL DEFAULT 4 foo +SYMTAB-NEXT: 10: 0000000000200268 0 NOTYPE GLOBAL DEFAULT 5 _edata +SYMTAB-NEXT: 11: 0000000000200268 0 NOTYPE GLOBAL DEFAULT 5 _end diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index f7fef8d1617..b58128c44ae 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -149,6 +149,7 @@ public: void printDynamicRelocations() override; void printSymbols() override; void printDynamicSymbols() override; + void printHashSymbols() override; void printUnwindInfo() override; void printDynamicTable() override; @@ -330,8 +331,9 @@ public: virtual void printSectionHeaders(const ELFFile *Obj) = 0; virtual void printSymbols(const ELFFile *Obj) = 0; virtual void printDynamicSymbols(const ELFFile *Obj) = 0; + virtual void printHashSymbols(const ELFFile *Obj) {} virtual void printDynamicRelocations(const ELFFile *Obj) = 0; - virtual void printSymtabMessage(const ELFFile *obj, StringRef Name, + virtual void printSymtabMessage(const ELFFile *Obj, StringRef Name, size_t Offset) {} virtual void printSymbol(const ELFFile *Obj, const Elf_Sym *Symbol, const Elf_Sym *FirstSym, StringRef StrTable, @@ -365,6 +367,7 @@ public: void printSectionHeaders(const ELFO *Obj) override; void printSymbols(const ELFO *Obj) override; void printDynamicSymbols(const ELFO *Obj) override; + void printHashSymbols(const ELFO *Obj) override; void printDynamicRelocations(const ELFO *Obj) override; void printSymtabMessage(const ELFO *Obj, StringRef Name, size_t Offset) override; @@ -1629,6 +1632,11 @@ void ELFDumper::printDynamicSymbols() { ELFDumperStyle->printDynamicSymbols(ObjF->getELFFile()); } +template +void ELFDumper::printHashSymbols() { + ELFDumperStyle->printHashSymbols(ObjF->getELFFile()); +} + template void ELFDumper::printHashHistogram() { ELFDumperStyle->printHashHistogram(ObjF->getELFFile()); } @@ -3176,19 +3184,18 @@ template void GNUStyle::printSymbols(const ELFO *Obj) { template void GNUStyle::printDynamicSymbols(const ELFO *Obj) { + this->dumper()->printSymbolsHelper(true); +} + +template void GNUStyle::printHashSymbols(const ELFO *Obj) { if (this->dumper()->getDynamicStringTable().empty()) return; auto StringTable = this->dumper()->getDynamicStringTable(); auto DynSyms = this->dumper()->dynamic_symbols(); - auto GnuHash = this->dumper()->getGnuHashTable(); auto SysVHash = this->dumper()->getHashTable(); - // If no hash or .gnu.hash found, try using symbol table - if (GnuHash == nullptr && SysVHash == nullptr) - this->dumper()->printSymbolsHelper(true); - // Try printing .hash - if (this->dumper()->getHashTable()) { + if (SysVHash) { OS << "\n Symbol table of .hash for image:\n"; if (ELFT::Is64Bits) OS << " Num Buc: Value Size Type Bind Vis Ndx Name"; @@ -3212,6 +3219,7 @@ void GNUStyle::printDynamicSymbols(const ELFO *Obj) { } // Try printing .gnu.hash + auto GnuHash = this->dumper()->getGnuHashTable(); if (GnuHash) { OS << "\n Symbol table of .gnu.hash for image:\n"; if (ELFT::Is64Bits) diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h index b7fbf6f2962..fc50f7e277d 100644 --- a/tools/llvm-readobj/ObjDumper.h +++ b/tools/llvm-readobj/ObjDumper.h @@ -46,6 +46,7 @@ public: virtual void printSectionAsHex(StringRef SectionName) {} virtual void printHashTable() { } virtual void printGnuHashTable() { } + virtual void printHashSymbols() {} virtual void printLoadName() {} virtual void printVersionInfo() {} virtual void printGroupSections() {} diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index 2d195455be1..91526fe8380 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -136,6 +136,11 @@ namespace opts { cl::alias DynSymsGNU("dyn-syms", cl::desc("Alias for --dyn-symbols"), cl::aliasopt(DynamicSymbols)); + // -hash-symbols + cl::opt HashSymbols( + "hash-symbols", + cl::desc("Display the dynamic symbols derived from the hash section")); + // -unwind, -u cl::opt UnwindInfo("unwind", cl::desc("Display unwind information")); @@ -461,6 +466,8 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer) { Dumper->printSymbols(); if (opts::DynamicSymbols) Dumper->printDynamicSymbols(); + if (opts::HashSymbols) + Dumper->printHashSymbols(); if (opts::UnwindInfo) Dumper->printUnwindInfo(); if (opts::DynamicTable)