Index: llvm/test/tools/llvm-readobj/ELF/hash-symbols.test =================================================================== --- llvm/test/tools/llvm-readobj/ELF/hash-symbols.test +++ llvm/test/tools/llvm-readobj/ELF/hash-symbols.test @@ -509,3 +509,96 @@ Sections: - Section: .gnu.hash - Section: .dynamic + +## Check the behavior when the dynamic symbol table is empty. + +## Case A: Check we report a warning when the dynamic symbol table is empty and we attempt to print hash symbols +## from the .hash table. The number of symbols in the dynamic symbol table can be calculated from its size +## or derived from the Chain vector of the .hash table. Make both ways to produce a zero to do the check. +# RUN: yaml2obj --docnum=9 %s -o %t9.1.so +# RUN: llvm-readelf --hash-symbols %t9.1.so 2>&1 | FileCheck %s -DFILE=%t9.1.so --check-prefix=DYNSYM-EMPTY-HASH + +# DYNSYM-EMPTY-HASH: Symbol table of .hash for image: +# DYNSYM-EMPTY-HASH-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name +# DYNSYM-EMPTY-HASH-NEXT: warning: '[[FILE]]': unable to print symbols for the .hash table: the dynamic symbol table is empty +# DYNSYM-EMPTY-HASH-NOT: {{.}} + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_386 +Sections: + - Name: .hash + Type: SHT_HASH + Flags: [ SHF_ALLOC ] + Bucket: [ 0 ] + Chain: [ ] + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_ALLOC ] + Entries: + - Tag: DT_HASH + Value: 0x0 + - Tag: DT_NULL + Value: 0x0 + - Name: .dynsym + Type: SHT_DYNSYM + Flags: [ SHF_ALLOC ] + Size: 0 + - Name: .dynstr + Type: SHT_STRTAB +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_R, PF_X ] + Sections: + - Section: .hash + - Section: .dynamic + +## Case B: Check we report a warning when the dynamic symbol table is empty and we attempt to print +## hash symbols from the .gnu.hash table. +# RUN: yaml2obj --docnum=10 %s -o %t10.so +# RUN: llvm-readelf --hash-symbols %t10.so 2>&1 | FileCheck %s -DFILE=%t10.so --check-prefix=DYNSYM-EMPTY-GNUHASH + +# DYNSYM-EMPTY-GNUHASH: Symbol table of .gnu.hash for image: +# DYNSYM-EMPTY-GNUHASH-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name +# DYNSYM-EMPTY-GNUHASH-NEXT: warning: '[[FILE]]': unable to print symbols for the .gnu.hash table: the dynamic symbol table is empty +# DYNSYM-EMPTY-GNUHASH-NOT: {{.}} + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_386 +Sections: + - Name: .gnu.hash + Type: SHT_GNU_HASH + Flags: [ SHF_ALLOC ] + Header: + SymNdx: 0x0 + Shift2: 0x0 + BloomFilter: [ 0x0 ] + HashBuckets: [ 0x1 ] + HashValues: [ 0x0 ] + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_ALLOC ] + Entries: + - Tag: DT_GNU_HASH + Value: 0x0 + - Tag: DT_NULL + Value: 0x0 + - Name: .dynsym + Type: SHT_DYNSYM + Flags: [ SHF_ALLOC ] + Size: 0 + - Name: .dynstr + Type: SHT_STRTAB +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_R, PF_X ] + Sections: + - Section: .gnu.hash + - Section: .dynamic Index: llvm/tools/llvm-readobj/ELFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/ELFDumper.cpp +++ llvm/tools/llvm-readobj/ELFDumper.cpp @@ -4035,7 +4035,7 @@ if (this->dumper()->getDynamicStringTable().empty()) return; auto StringTable = this->dumper()->getDynamicStringTable(); - auto DynSyms = this->dumper()->dynamic_symbols(); + Elf_Sym_Range DynSyms = this->dumper()->dynamic_symbols(); auto PrintHashTable = [&](const Elf_Hash *SysVHash) { if (ELFT::Is64Bits) @@ -4044,6 +4044,14 @@ OS << " Num Buc: Value Size Type Bind Vis Ndx Name"; OS << "\n"; + const Elf_Sym *FirstSym = DynSyms.empty() ? nullptr : &DynSyms[0]; + if (!FirstSym) { + this->reportUniqueWarning( + createError("unable to print symbols for the .hash table: the " + "dynamic symbol table is empty")); + return; + } + auto Buckets = SysVHash->buckets(); auto Chains = SysVHash->chains(); for (uint32_t Buc = 0; Buc < SysVHash->nbucket; Buc++) { @@ -4062,7 +4070,7 @@ break; } - printHashedSymbol(Obj, &DynSyms[0], Ch, StringTable, Buc); + printHashedSymbol(Obj, FirstSym, Ch, StringTable, Buc); Visited[Ch] = true; } } @@ -4093,6 +4101,14 @@ return; } + const Elf_Sym *FirstSym = DynSyms.empty() ? nullptr : &DynSyms[0]; + if (!FirstSym) { + this->reportUniqueWarning( + createError("unable to print symbols for the .gnu.hash table: the " + "dynamic symbol table is empty")); + return; + } + auto Buckets = GnuHash->buckets(); for (uint32_t Buc = 0; Buc < GnuHash->nbuckets; Buc++) { if (Buckets[Buc] == ELF::STN_UNDEF) @@ -4101,7 +4117,7 @@ uint32_t GnuHashable = Index - GnuHash->symndx; // Print whole chain while (true) { - printHashedSymbol(Obj, &DynSyms[0], Index++, StringTable, Buc); + printHashedSymbol(Obj, FirstSym, Index++, StringTable, Buc); // Chain ends at symbol with stopper bit if ((GnuHash->values(DynSyms.size())[GnuHashable++] & 1) == 1) break;