Index: llvm/include/llvm/Object/ELF.h =================================================================== --- llvm/include/llvm/Object/ELF.h +++ llvm/include/llvm/Object/ELF.h @@ -57,6 +57,36 @@ template class ELFFile; +template struct DataRegion { + // This constructor is used when we know the start and the size of a data + // region. We assume that Arr does not go past the end of the file. + DataRegion(ArrayRef Arr) : First(Arr.data()), Size(Arr.size()) {} + + // Sometimes we only know the start of a data region. We still don't want to + // read past the end of the file, so we provide the end of a buffer. + DataRegion(const T *Data, const uint8_t *BufferEnd) + : First(Data), BufEnd(BufferEnd) {} + + Expected operator[](uint64_t N) { + assert(Size || BufEnd); + if (Size) { + if (N >= *Size) + return createError( + "the index is greater or equal to the number of entries (" + + Twine(*Size) + ")"); + } else { + const uint8_t *EntryStart = (const uint8_t *)First + N * sizeof(T); + if (EntryStart + sizeof(T) > BufEnd) + return createError("can't read past the end of the file"); + } + return *(First + N); + } + + const T *First; + Optional Size = None; + const uint8_t *BufEnd = nullptr; +}; + template std::string getSecIndexForError(const ELFFile &Obj, const typename ELFT::Shdr &Sec) { @@ -99,6 +129,7 @@ using WarningHandler = llvm::function_ref; const uint8_t *base() const { return Buf.bytes_begin(); } + const uint8_t *end() const { return base() + getBufSize(); } size_t getBufSize() const { return Buf.size(); } @@ -274,13 +305,13 @@ Elf_Shdr_Range Sections, WarningHandler WarnHandler = &defaultWarningHandler) const; Expected getSectionIndex(const Elf_Sym &Sym, Elf_Sym_Range Syms, - ArrayRef ShndxTable) const; + DataRegion ShndxTable) const; Expected getSection(const Elf_Sym &Sym, const Elf_Shdr *SymTab, - ArrayRef ShndxTable) const; + DataRegion ShndxTable) const; Expected getSection(const Elf_Sym &Sym, Elf_Sym_Range Symtab, - ArrayRef ShndxTable) const; + DataRegion ShndxTable) const; Expected getSection(uint32_t Index) const; Expected getSymbol(const Elf_Shdr *Sec, @@ -313,22 +344,25 @@ template inline Expected getExtendedSymbolTableIndex(const typename ELFT::Sym &Sym, unsigned SymIndex, - ArrayRef ShndxTable) { + DataRegion ShndxTable) { assert(Sym.st_shndx == ELF::SHN_XINDEX); - if (SymIndex >= ShndxTable.size()) + if (!ShndxTable.First) return createError( - "extended symbol index (" + Twine(SymIndex) + - ") is past the end of the SHT_SYMTAB_SHNDX section of size " + - Twine(ShndxTable.size())); + "found an extended symbol index (" + Twine(SymIndex) + + "), but unable to locate the extended symbol index table"); - // The size of the table was checked in getSHNDXTable. - return ShndxTable[SymIndex]; + Expected TableOrErr = ShndxTable[SymIndex]; + if (!TableOrErr) + return createError("unable to read an extended symbol table at index " + + Twine(SymIndex) + ": " + + toString(TableOrErr.takeError())); + return *TableOrErr; } template Expected ELFFile::getSectionIndex(const Elf_Sym &Sym, Elf_Sym_Range Syms, - ArrayRef ShndxTable) const { + DataRegion ShndxTable) const { uint32_t Index = Sym.st_shndx; if (Index == ELF::SHN_XINDEX) { Expected ErrorOrIndex = @@ -345,7 +379,7 @@ template Expected ELFFile::getSection(const Elf_Sym &Sym, const Elf_Shdr *SymTab, - ArrayRef ShndxTable) const { + DataRegion ShndxTable) const { auto SymsOrErr = symbols(SymTab); if (!SymsOrErr) return SymsOrErr.takeError(); @@ -355,7 +389,7 @@ template Expected ELFFile::getSection(const Elf_Sym &Sym, Elf_Sym_Range Symbols, - ArrayRef ShndxTable) const { + DataRegion ShndxTable) const { auto IndexOrErr = getSectionIndex(Sym, Symbols, ShndxTable); if (!IndexOrErr) return IndexOrErr.takeError(); Index: llvm/test/Object/invalid.test =================================================================== --- llvm/test/Object/invalid.test +++ llvm/test/Object/invalid.test @@ -244,7 +244,7 @@ # RUN: llvm-readobj --symbols %p/Inputs/invalid-ext-symtab-index.elf-x86-64 2>&1 | \ # RUN: FileCheck -DFILE=%p/Inputs/invalid-ext-symtab-index.elf-x86-64 --check-prefix=INVALID-EXT-SYMTAB-INDEX %s -# INVALID-EXT-SYMTAB-INDEX: warning: '[[FILE]]': extended symbol index (0) is past the end of the SHT_SYMTAB_SHNDX section of size 0 +# INVALID-EXT-SYMTAB-INDEX: warning: '[[FILE]]': found an extended symbol index (0), but unable to locate the extended symbol index table # INVALID-EXT-SYMTAB-INDEX: Section: Reserved (0xFFFF) ## Check that llvm-readobj reports an error if a relocation section Index: llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test =================================================================== --- llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test +++ llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test @@ -364,14 +364,14 @@ # VERSIONED-SEC-SYM-XINDEX-LLVM: Name: (0) # VERSIONED-SEC-SYM-XINDEX-LLVM: Name: foo (12) -# VERSIONED-SEC-SYM-XINDEX-LLVM: warning: '[[FILE]]': extended symbol index (2) is past the end of the SHT_SYMTAB_SHNDX section of size 0 +# VERSIONED-SEC-SYM-XINDEX-LLVM: warning: '[[FILE]]': found an extended symbol index (2), but unable to locate the extended symbol index table # VERSIONED-SEC-SYM-XINDEX-LLVM-NEXT: Symbol { # VERSIONED-SEC-SYM-XINDEX-LLVM-NEXT: Name: (0) # VERSIONED-SEC-SYM-XINDEX-LLVM: Name: (0) # VERSIONED-SEC-SYM-XINDEX-GNU: Symbol table '.dynsym' contains 4 entries: # VERSIONED-SEC-SYM-XINDEX-GNU: Num: {{.*}} Ndx Name -# VERSIONED-SEC-SYM-XINDEX-GNU: warning: '[[FILE]]': extended symbol index (2) is past the end of the SHT_SYMTAB_SHNDX section of size 0 +# VERSIONED-SEC-SYM-XINDEX-GNU: warning: '[[FILE]]': found an extended symbol index (2), but unable to locate the extended symbol index table # VERSIONED-SEC-SYM-XINDEX-GNU-NEXT: 2: {{.*}} RSV[0xffff] ## Case 8: Check what we print when: Index: llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test =================================================================== --- llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test +++ llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test @@ -487,6 +487,7 @@ # PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': DT_SYMENT value of 0x987 is not the size of a symbol (0x18) # PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_REL: invalid e_phentsize: 1 # PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_JMPREL: invalid e_phentsize: 1 +# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_SYMTAB_SHNDX: invalid e_phentsize: 1 # PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_RELR: invalid e_phentsize: 1 # PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_ANDROID_RELR: invalid e_phentsize: 1 # PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_GNU_HASH: invalid e_phentsize: 1 Index: llvm/test/tools/llvm-readobj/ELF/mips-got.test =================================================================== --- llvm/test/tools/llvm-readobj/ELF/mips-got.test +++ llvm/test/tools/llvm-readobj/ELF/mips-got.test @@ -558,7 +558,7 @@ # SEC-SYMS-LLVM-NEXT: } # SEC-SYMS-LLVM-NEXT: Entry { # SEC-SYMS-LLVM: Type: Section (0x3) -# SEC-SYMS-LLVM-NEXT: warning: '[[FILE]]': extended symbol index (4) is past the end of the SHT_SYMTAB_SHNDX section of size 0 +# SEC-SYMS-LLVM-NEXT: warning: '[[FILE]]': found an extended symbol index (4), but unable to locate the extended symbol index table # SEC-SYMS-LLVM-NEXT: Section: Reserved (0xFFFF) # SEC-SYMS-LLVM-NEXT: Name: (0) # SEC-SYMS-LLVM-NEXT: } @@ -571,7 +571,7 @@ # SEC-SYMS-GNU-NEXT: {{.*}} 1 .got # SEC-SYMS-GNU-NEXT: warning: '[[FILE]]': unable to get section index for symbol with st_shndx = 0xfff2 (SHN_COMMON) # SEC-SYMS-GNU-NEXT: {{.*}} COM -# SEC-SYMS-GNU-NEXT: warning: '[[FILE]]': extended symbol index (4) is past the end of the SHT_SYMTAB_SHNDX section of size 0 +# SEC-SYMS-GNU-NEXT: warning: '[[FILE]]': found an extended symbol index (4), but unable to locate the extended symbol index table # SEC-SYMS-GNU-NEXT: {{.*}} RSV[0xffff] --- !ELF Index: llvm/test/tools/llvm-readobj/ELF/mips-plt.test =================================================================== --- llvm/test/tools/llvm-readobj/ELF/mips-plt.test +++ llvm/test/tools/llvm-readobj/ELF/mips-plt.test @@ -189,7 +189,7 @@ # SEC-SYMS-LLVM-NEXT: } # SEC-SYMS-LLVM-NEXT: Entry { # SEC-SYMS-LLVM: Type: Section (0x3) -# SEC-SYMS-LLVM-NEXT: warning: '[[FILE]]': extended symbol index (4) is past the end of the SHT_SYMTAB_SHNDX section of size 0 +# SEC-SYMS-LLVM-NEXT: warning: '[[FILE]]': found an extended symbol index (4), but unable to locate the extended symbol index table # SEC-SYMS-LLVM-NEXT: Section: Reserved (0xFFFF) # SEC-SYMS-LLVM-NEXT: Name: (0) # SEC-SYMS-LLVM-NEXT: } @@ -204,7 +204,7 @@ # SEC-SYMS-GNU-NEXT: 0000000000002018 {{.*}} 2 .got.plt # SEC-SYMS-GNU-NEXT: warning: '[[FILE]]': unable to get section index for symbol with st_shndx = 0xfff2 (SHN_COMMON) # SEC-SYMS-GNU-NEXT: 0000000000002020 {{.*}} COM -# SEC-SYMS-GNU-NEXT: warning: '[[FILE]]': extended symbol index (4) is past the end of the SHT_SYMTAB_SHNDX section of size 0 +# SEC-SYMS-GNU-NEXT: warning: '[[FILE]]': found an extended symbol index (4), but unable to locate the extended symbol index table # SEC-SYMS-GNU-NEXT: 0000000000002028 {{.*}} RSV[0xffff] --- !ELF Index: llvm/test/tools/llvm-readobj/ELF/section-symbols.test =================================================================== --- llvm/test/tools/llvm-readobj/ELF/section-symbols.test +++ llvm/test/tools/llvm-readobj/ELF/section-symbols.test @@ -150,7 +150,7 @@ # GNU2-NEXT: 0: {{.*}} NOTYPE {{.*}} UND {{$}} # GNU2-NEXT: 1: {{.*}} SECTION {{.*}} RSV[0xffff] -# WARN2: warning: '{{.*}}.tmp2': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0 +# WARN2: warning: '{{.*}}.tmp2': found an extended symbol index (1), but unable to locate the extended symbol index table --- !ELF FileHeader: Index: llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test =================================================================== --- llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test +++ llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test @@ -241,8 +241,8 @@ # GNU3-NEXT: 1: {{.*}} RSV[0xffff] no_shndx # GNU3-NEXT: 2: {{.*}} RSV[0xffff] no_shndx2 -# NO-SYMTAB-SHNDX: warning: '{{.*}}tmp3': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0 -# NO-SYMTAB-SHNDX: warning: '{{.*}}tmp3': extended symbol index (2) is past the end of the SHT_SYMTAB_SHNDX section of size 0 +# NO-SYMTAB-SHNDX: warning: '{{.*}}tmp3': found an extended symbol index (1), but unable to locate the extended symbol index table +# NO-SYMTAB-SHNDX: warning: '{{.*}}tmp3': found an extended symbol index (2), but unable to locate the extended symbol index table --- !ELF FileHeader: @@ -267,7 +267,7 @@ # SHNDX-ERR-GNU-NEXT: Symbol table '.symtab' contains 2 entries: # SHNDX-ERR-GNU-NEXT: Num: Value Size Type Bind Vis Ndx Name # SHNDX-ERR-GNU-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND -# SHNDX-ERR-GNU-NEXT: warning: '[[FILE]]': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0 +# SHNDX-ERR-GNU-NEXT: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table # SHNDX-ERR-GNU-NEXT: 1: 0000000000000000 0 NOTYPE LOCAL DEFAULT RSV[0xffff] # SHNDX-ERR-GNU-EMPTY: # SHNDX-ERR-GNU-NOT:{{.}} @@ -294,7 +294,7 @@ # SHNDX-ERR-LLVM-NEXT: Binding: Local (0x0) # SHNDX-ERR-LLVM-NEXT: Type: None (0x0) # SHNDX-ERR-LLVM-NEXT: Other: 0 -# SHNDX-ERR-LLVM-NEXT: warning: '[[FILE]]': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0 +# SHNDX-ERR-LLVM-NEXT: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table # SHNDX-ERR-LLVM-NEXT: Section: Reserved (0xFFFF) # SHNDX-ERR-LLVM-NEXT: } # SHNDX-ERR-LLVM-NEXT: ] Index: llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test @@ -0,0 +1,331 @@ +## In this file we have tests for the SHT_SYMTAB_SHNDX section +## and the DT_SYMTAB_SHNDX dynamic tag. + +## Check that different SHT_SYMTAB_SHNDX sections can be used with different symbol tables. +## In this test we check that we print different section indexes for regular and dynamic +## symbol tables that are linked to different SHT_SYMTAB_SHNDX sections. + +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: llvm-readelf --symbols --dyn-syms %t1 2>&1 | FileCheck %s --check-prefix=GNU +# RUN: llvm-readobj --symbols --dyn-syms %t1 2>&1 | FileCheck %s --check-prefix=LLVM + +# GNU: Symbol table '.dynsym' contains 3 entries: +# GNU-NEXT: Num: Value Size Type Bind Vis Ndx Name +# GNU-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND +# GNU-NEXT: 1: 00000000 0 NOTYPE LOCAL DEFAULT 3 dynsym1 +# GNU-NEXT: 2: 00000000 0 NOTYPE LOCAL DEFAULT 2 dynsym2 +# GNU: Symbol table '.symtab' contains 3 entries: +# GNU-NEXT: Num: Value Size Type Bind Vis Ndx Name +# GNU-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND +# GNU-NEXT: 1: 00000000 0 NOTYPE LOCAL DEFAULT 2 sym1 +# GNU-NEXT: 2: 00000000 0 NOTYPE LOCAL DEFAULT 1 sym2 + +# LLVM: Symbols [ +# LLVM-NEXT: Symbol { +# LLVM-NEXT: Name: (0) +# LLVM: Section: Undefined (0x0) +# LLVM-NEXT: } +# LLVM-NEXT: Symbol { +# LLVM-NEXT: Name: sym1 (6) +# LLVM: Section: .section2 (0x2) +# LLVM-NEXT: } +# LLVM-NEXT: Symbol { +# LLVM-NEXT: Name: sym2 (1) +# LLVM: Section: .section1 (0x1) +# LLVM-NEXT: } +# LLVM-NEXT: ] +# LLVM: DynamicSymbols [ +# LLVM-NEXT: Symbol { +# LLVM-NEXT: Name: (0) +# LLVM: Section: Undefined (0x0) +# LLVM-NEXT: } +# LLVM-NEXT: Symbol { +# LLVM-NEXT: Name: dynsym1 (9) +# LLVM: Section: .section3 (0x3) +# LLVM-NEXT: } +# LLVM-NEXT: Symbol { +# LLVM-NEXT: Name: dynsym2 (1) +# LLVM: Section: .section2 (0x2) +# LLVM-NEXT: } +# LLVM-NEXT: ] + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL +Sections: + - Name: .section1 + Type: SHT_PROGBITS + - Name: .section2 + Type: SHT_PROGBITS + - Name: .section3 + Type: SHT_PROGBITS + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_ALLOC ] + Address: 0x1000 + Offset: 0x1000 + Entries: + - Tag: [[TAGNAME=DT_SYMTAB_SHNDX]] + Value: [[SYMTABSHNDX=0x2100]] ## Address of .bar section. + - Tag: DT_NULL + Value: 0 +## By naming the SHT_SYMTAB_SHNDX sections to .foo and .bar we verify that we +## don't use their names to locate them. + - Name: .foo + Type: SHT_SYMTAB_SHNDX + Flags: [ SHF_ALLOC ] + Link: [[SHNDXLINK=.symtab]] + Entries: [ 0, 2, 1 ] + Offset: 0x2000 + Address: 0x2000 + - Name: .bar + Type: SHT_SYMTAB_SHNDX + Flags: [ SHF_ALLOC ] + Link: .dynsym + Entries: [ 0, 3, 2 ] + Offset: 0x2100 + Address: 0x2100 +Symbols: + - Name: sym1 + Index: SHN_XINDEX + - Name: sym2 + Index: SHN_XINDEX +DynamicSymbols: + - Name: dynsym1 + Index: SHN_XINDEX + - Name: dynsym2 + Index: SHN_XINDEX +ProgramHeaders: + - Type: PT_LOAD + VAddr: 0x1000 + FirstSec: .dynamic + LastSec: .bar + - Type: PT_DYNAMIC + VAddr: 0x1000 + FirstSec: .dynamic + LastSec: .dynamic + +## Check that we locate the SHT_SYMTAB_SHNDX section using the DT_SYMTAB_SHNDX +## dynamic tag when dumping dynamic symbols. In this case we make the value of +## DT_SYMTAB_SHNDX point to the SHT_SYMTAB_SHNDX section that is +## linked with the static symbol table and check that we use it. + +# RUN: yaml2obj --docnum=1 -DSYMTABSHNDX=0x2000 %s -o %t2 +# RUN: llvm-readelf --dyn-syms %t2 2>&1 | FileCheck %s --check-prefix=DYNTAG-GNU +# RUN: llvm-readobj --dyn-syms %t2 2>&1 | FileCheck %s --check-prefix=DYNTAG-LLVM + +# DYNTAG-GNU: Symbol table '.dynsym' contains 3 entries: +# DYNTAG-GNU-NEXT: Num: Value Size Type Bind Vis Ndx Name +# DYNTAG-GNU-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND +# DYNTAG-GNU-NEXT: 1: 00000000 0 NOTYPE LOCAL DEFAULT 2 dynsym1 +# DYNTAG-GNU-NEXT: 2: 00000000 0 NOTYPE LOCAL DEFAULT 1 dynsym2 + +# DYNTAG-LLVM: Name: dynsym1 (9) +# DYNTAG-LLVM: Section: .section2 (0x2) +# DYNTAG-LLVM-NEXT: } +# DYNTAG-LLVM-NEXT: Symbol { +# DYNTAG-LLVM-NEXT: Name: dynsym2 (1) +# DYNTAG-LLVM: Section: .section1 (0x1) +# DYNTAG-LLVM-NEXT: } +# DYNTAG-LLVM-NEXT: ] + +## Check that we report a warning when we dump a dynamic symbol table that +## contains symbols with extended indices, but we don't have a DT_SYMTAB_SHNDX tag to locate +## the corresponding extended indexes table. + +# RUN: yaml2obj --docnum=1 -DTAGNAME=0x0 -DSYMTABSHNDX=0x0 %s -o %t3 +# RUN: llvm-readelf --symbols --dyn-syms %t3 2>&1 | FileCheck %s -DFILE=%t3 --check-prefix=NOTAG-GNU +# RUN: llvm-readobj --symbols --dyn-syms %t3 2>&1 | FileCheck %s -DFILE=%t3 --check-prefix=NOTAG-LLVM + +# NOTAG-GNU: Symbol table '.dynsym' contains 3 entries: +# NOTAG-GNU-NEXT: Num: Value Size Type Bind Vis Ndx Name +# NOTAG-GNU-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND +# NOTAG-GNU-NEXT: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table +# NOTAG-GNU-NEXT: 1: 00000000 0 NOTYPE LOCAL DEFAULT RSV[0xffff] dynsym1 +# NOTAG-GNU-NEXT: warning: '[[FILE]]': found an extended symbol index (2), but unable to locate the extended symbol index table +# NOTAG-GNU-NEXT: 2: 00000000 0 NOTYPE LOCAL DEFAULT RSV[0xffff] dynsym2 + +# NOTAG-LLVM: Symbol { +# NOTAG-LLVM: Name: dynsym1 (9) +# NOTAG-LLVM-NEXT: Value: 0x0 +# NOTAG-LLVM-NEXT: Size: 0 +# NOTAG-LLVM-NEXT: Binding: Local (0x0) +# NOTAG-LLVM-NEXT: Type: None (0x0) +# NOTAG-LLVM-NEXT: Other: 0 +# NOTAG-LLVM-NEXT: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table +# NOTAG-LLVM-NEXT: Section: Reserved (0xFFFF) +# NOTAG-LLVM-NEXT: } +# NOTAG-LLVM-NEXT: Symbol { +# NOTAG-LLVM-NEXT: Name: dynsym2 (1) +# NOTAG-LLVM-NEXT: Value: 0x0 +# NOTAG-LLVM-NEXT: Size: 0 +# NOTAG-LLVM-NEXT: Binding: Local (0x0) +# NOTAG-LLVM-NEXT: Type: None (0x0) +# NOTAG-LLVM-NEXT: Other: 0 +# NOTAG-LLVM-NEXT: warning: '[[FILE]]': found an extended symbol index (2), but unable to locate the extended symbol index table +# NOTAG-LLVM-NEXT: Section: Reserved (0xFFFF) +# NOTAG-LLVM-NEXT: } + +## In this case we have a SHT_SYMTAB_SHNDX section with a sh_link field that has a +## value that is larger than the number of sections. Check we report a warning. + +# RUN: yaml2obj --docnum=1 -DSHNDXLINK=0xFF %s -o %t4 +# RUN: llvm-readelf --symbols --dyn-syms %t4 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t4 --check-prefixes=BROKENLINK,BROKENLINK-GNU --implicit-check-not=warning: +# RUN: llvm-readobj --symbols --dyn-syms %t4 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t4 --check-prefixes=BROKENLINK,BROKENLINK-LLVM --implicit-check-not=warning: + +# BROKENLINK: warning: '[[FILE]]': unable to get the associated symbol table for SHT_SYMTAB_SHNDX section with index 5: sh_link (255) is greater than or equal to the total number of sections (12) + +# BROKENLINK-GNU: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table +# BROKENLINK-GNU-NEXT: 1: 00000000 0 NOTYPE LOCAL DEFAULT RSV[0xffff] sym1 +# BROKENLINK-GNU-NEXT: warning: '[[FILE]]': found an extended symbol index (2), but unable to locate the extended symbol index table +# BROKENLINK-GNU-NEXT: 2: 00000000 0 NOTYPE LOCAL DEFAULT RSV[0xffff] sym2 + +# BROKENLINK-LLVM: Symbol { +# BROKENLINK-LLVM: Name: sym1 (6) +# BROKENLINK-LLVM: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table +# BROKENLINK-LLVM-NEXT: Section: Reserved (0xFFFF) +# BROKENLINK-LLVM-NEXT: } +# BROKENLINK-LLVM-NEXT: Symbol { +# BROKENLINK-LLVM-NEXT: Name: sym2 (1) +# BROKENLINK-LLVM: warning: '[[FILE]]': found an extended symbol index (2), but unable to locate the extended symbol index table +# BROKENLINK-LLVM-NEXT: Section: Reserved (0xFFFF) +# BROKENLINK-LLVM-NEXT: } + +## Check we report a warning when multiple SHT_SYMTAB_SHNDX sections are linked to a symbol table. +## In this case 2, sections are linked to the dynamic symbol table. Check it doesn't affect +## anything, because the SHT_SYMTAB_SHNDX section specified by the DT_SYMTAB_SHNDX tag is still used. + +# RUN: yaml2obj --docnum=1 -DSHNDXLINK=.dynsym %s -o %t.multiple +# RUN: llvm-readelf --symbols --dyn-syms %t.multiple 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t.multiple --check-prefix=MULTIPLE-GNU +# RUN: llvm-readobj --symbols --dyn-syms %t.multiple 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t.multiple --check-prefix=MULTIPLE-LLVM + +# MULTIPLE-GNU: warning: '[[FILE]]': multiple SHT_SYMTAB_SHNDX sections are linked to SHT_SYMTAB_SHNDX section with index 6 +# MULTIPLE-GNU: Symbol table '.dynsym' contains 3 entries: +# MULTIPLE-GNU-NEXT: Num: Value Size Type Bind Vis Ndx Name +# MULTIPLE-GNU-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND +# MULTIPLE-GNU-NEXT: 1: 00000000 0 NOTYPE LOCAL DEFAULT 3 dynsym1 +# MULTIPLE-GNU-NEXT: 2: 00000000 0 NOTYPE LOCAL DEFAULT 2 dynsym2 + +# MULTIPLE-LLVM: Symbol { +# MULTIPLE-LLVM: Name: dynsym1 (9) +# MULTIPLE-LLVM-NEXT: Value: 0x0 +# MULTIPLE-LLVM-NEXT: Size: 0 +# MULTIPLE-LLVM-NEXT: Binding: Local (0x0) +# MULTIPLE-LLVM-NEXT: Type: None (0x0) +# MULTIPLE-LLVM-NEXT: Other: 0 +# MULTIPLE-LLVM-NEXT: Section: .section3 (0x3) +# MULTIPLE-LLVM-NEXT: } +# MULTIPLE-LLVM-NEXT: Symbol { +# MULTIPLE-LLVM-NEXT: Name: dynsym2 (1) +# MULTIPLE-LLVM-NEXT: Value: 0x0 +# MULTIPLE-LLVM-NEXT: Size: 0 +# MULTIPLE-LLVM-NEXT: Binding: Local (0x0) +# MULTIPLE-LLVM-NEXT: Type: None (0x0) +# MULTIPLE-LLVM-NEXT: Other: 0 +# MULTIPLE-LLVM-NEXT: Section: .section2 (0x2) +# MULTIPLE-LLVM-NEXT: } + +## In this case we have a SHT_SYMTAB_SHNDX section placed right before +## the end of the file. This table is broken: it contains fewer entries than +## the number of dynamic symbols. +## Check we report a warning when trying to read an extended symbol index past +## the end of the file. + +# RUN: yaml2obj --docnum=2 %s -o %t.pastend +# RUN: llvm-readelf --dyn-syms %t.pastend 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t.pastend --check-prefix=PASTEND-GNU --implicit-check-not=warning: +# RUN: llvm-readobj --dyn-syms %t.pastend 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t.pastend --check-prefix=PASTEND-LLVM --implicit-check-not=warning: + +# PASTEND-GNU: 1: 00000000 0 NOTYPE LOCAL DEFAULT 1 dynsym1 +# PASTEND-GNU-NEXT: warning: '[[FILE]]': unable to read an extended symbol table at index 2: can't read past the end of the file +# PASTEND-GNU-NEXT: 2: 00000000 0 NOTYPE LOCAL DEFAULT RSV[0xffff] dynsym2 + +# PASTEND-LLVM: Symbol { +# PASTEND-LLVM: Name: dynsym2 (1) +# PASTEND-LLVM-NEXT: Value: 0x0 +# PASTEND-LLVM-NEXT: Size: 0 +# PASTEND-LLVM-NEXT: Binding: Local (0x0) +# PASTEND-LLVM-NEXT: Type: None (0x0) +# PASTEND-LLVM-NEXT: Other: 0 +# PASTEND-LLVM-NEXT: warning: '[[FILE]]': unable to read an extended symbol table at index 2: can't read past the end of the file +# PASTEND-LLVM-NEXT: Section: Reserved (0xFFFF) +# PASTEND-LLVM-NEXT: } + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL +Sections: + - Name: .section1 + Type: SHT_PROGBITS + - Name: .section2 + Type: SHT_PROGBITS + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_ALLOC ] + Address: 0x1000 + Offset: 0x1000 + Entries: + - Tag: DT_SYMTAB + Value: 0x1500 + - Tag: DT_HASH + Value: 0x1600 + - Tag: DT_STRTAB + Value: 0x1700 + - Tag: DT_STRSZ + Value: 17 ## ".dynsym1.dynsym2." + - Tag: DT_SYMTAB_SHNDX + Value: 0x2000 + - Tag: DT_NULL + Value: 0 + - Name: .dynsym + Type: SHT_DYNSYM + Flags: [ SHF_ALLOC ] + Offset: 0x1500 + Address: 0x1500 +## We need the .hash table to infer the number +## of dynamic symbols. + - Name: .hash + Type: SHT_HASH + Flags: [ SHF_ALLOC ] + Offset: 0x1600 + Address: 0x1600 + Bucket: [ 1 ] + Chain: [ 1, 2, 3 ] + - Name: .dynstr + Type: SHT_STRTAB + Flags: [ SHF_ALLOC ] + Offset: 0x1700 + Address: 0x1700 + - Name: .strtab + Type: SHT_STRTAB + - Name: .symtab_shndx + Type: SHT_SYMTAB_SHNDX + Flags: [ SHF_ALLOC ] + Entries: [ 0, 1 ] + Offset: 0x2000 + Address: 0x2000 +DynamicSymbols: + - Name: dynsym1 + Index: SHN_XINDEX + - Name: dynsym2 + Index: SHN_XINDEX +ProgramHeaders: + - Type: PT_LOAD + VAddr: 0x1000 + FirstSec: .dynamic + LastSec: .symtab_shndx + - Type: PT_DYNAMIC + VAddr: 0x1000 + FirstSec: .dynamic + LastSec: .dynamic +SectionHeaderTable: + NoHeaders: true Index: llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml =================================================================== --- llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml +++ llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml @@ -51,7 +51,7 @@ # RUN: yaml2obj --docnum=2 %s -o %t2 # RUN: not obj2yaml %t2 2>&1 | FileCheck %s -DFILE=%t2 --check-prefix=CASE2 -# CASE2: Error reading file: [[FILE]]: extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0 +# CASE2: Error reading file: [[FILE]]: found an extended symbol index (1), but unable to locate the extended symbol index table --- !ELF FileHeader: Index: llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml =================================================================== --- llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml +++ llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml @@ -5,7 +5,7 @@ # RUN: yaml2obj --docnum=1 %s -o %t1 # RUN: llvm-readobj --symbols 2>&1 %t1 | FileCheck -DFILE=%t1 %s --check-prefix=CASE1 -# CASE1: warning: '[[FILE]]': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0 +# CASE1: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table --- !ELF FileHeader: Index: llvm/tools/llvm-readobj/ELFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/ELFDumper.cpp +++ llvm/tools/llvm-readobj/ELFDumper.cpp @@ -306,6 +306,7 @@ DynRegionInfo DynRelrRegion; DynRegionInfo DynPLTRelRegion; Optional DynSymRegion; + DynRegionInfo DynSymTabShndxRegion; DynRegionInfo DynamicTable; StringRef DynamicStringTable; const Elf_Hash *HashTable = nullptr; @@ -314,7 +315,7 @@ const Elf_Shdr *DotDynsymSec = nullptr; const Elf_Shdr *DotCGProfileSec = nullptr; const Elf_Shdr *DotAddrsigSec = nullptr; - ArrayRef ShndxTable; + DenseMap> ShndxTables; Optional SONameOffset; const Elf_Shdr *SymbolVersionSection = nullptr; // .gnu.version @@ -362,14 +363,20 @@ return DynSymRegion->getAsArrayRef(); } + DynRegionInfo getDynSymTabShndxRegion() const { + return DynSymTabShndxRegion; + } + Elf_Rel_Range dyn_rels() const; Elf_Rela_Range dyn_relas() const; Elf_Relr_Range dyn_relrs() const; std::string getFullSymbolName(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable, Optional StrTable, bool IsDynamic) const; - Expected getSymbolSectionIndex(const Elf_Sym &Symbol, - unsigned SymIndex) const; + Expected + getSymbolSectionIndex(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable) const; Expected getSymbolSectionName(const Elf_Sym &Symbol, unsigned SectionIndex) const; std::string getStaticSymbolName(uint32_t Index) const; @@ -385,7 +392,7 @@ const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; } const Elf_Shdr *getDotCGProfileSec() const { return DotCGProfileSec; } const Elf_Shdr *getDotAddrsigSec() const { return DotAddrsigSec; } - ArrayRef getShndxTable() const { return ShndxTable; } + ArrayRef getShndxTable(const Elf_Shdr *Symtab) const; StringRef getDynamicStringTable() const { return DynamicStringTable; } const DynRegionInfo &getDynRelRegion() const { return DynRelRegion; } const DynRegionInfo &getDynRelaRegion() const { return DynRelaRegion; } @@ -395,9 +402,9 @@ const Elf_Hash *getHashTable() const { return HashTable; } const Elf_GnuHash *getGnuHashTable() const { return GnuHashTable; } - Expected> getVersionTable(const Elf_Shdr &Sec, - ArrayRef *SymTab, - StringRef *StrTab) const; + Expected> + getVersionTable(const Elf_Shdr &Sec, ArrayRef *SymTab, + StringRef *StrTab, const Elf_Shdr **SymTabSec) const; Expected> getVersionDefinitions(const Elf_Shdr &Sec) const; Expected> @@ -423,8 +430,21 @@ } template -static Expected getLinkAsStrtab(const ELFFile &Obj, - const typename ELFT::Shdr &Sec) { +ArrayRef +ELFDumper::getShndxTable(const Elf_Shdr *Symtab) const { + if (Symtab) { + auto It = ShndxTables.find(Symtab); + if (It != ShndxTables.end()) + return It->second; + } + return {}; +} + +namespace { + +template +Expected getLinkAsStrtab(const ELFFile &Obj, + const typename ELFT::Shdr &Sec) { Expected StrTabSecOrErr = Obj.getSection(Sec.sh_link); if (!StrTabSecOrErr) @@ -438,11 +458,18 @@ return *StrTabOrErr; } -// Returns the linked symbol table and associated string table for a given section. +template struct SymtabLink { + typename ELFT::SymRange Symbols; + StringRef StringTable; + const typename ELFT::Shdr *SymTab; +}; + +// Returns the linked symbol table, symbols and associated string table for a +// given section. template -static Expected> -getLinkAsSymtab(const ELFFile &Obj, const typename ELFT::Shdr &Sec, - unsigned ExpectedType) { +Expected> getLinkAsSymtab(const ELFFile &Obj, + const typename ELFT::Shdr &Sec, + unsigned ExpectedType) { Expected SymtabOrErr = Obj.getSection(Sec.sh_link); if (!SymtabOrErr) @@ -467,15 +494,16 @@ if (!SymsOrErr) return createError("unable to read symbols from the " + describe(Obj, Sec) + ": " + toString(SymsOrErr.takeError())); - - return std::make_pair(*SymsOrErr, *StrTabOrErr); + return SymtabLink{*SymsOrErr, *StrTabOrErr, *SymtabOrErr}; } +} // namespace template Expected> ELFDumper::getVersionTable(const Elf_Shdr &Sec, ArrayRef *SymTab, - StringRef *StrTab) const { - assert((!SymTab && !StrTab) || (SymTab && StrTab)); + StringRef *StrTab, + const Elf_Shdr **SymTabSec) const { + assert((!SymTab && !StrTab && !SymTabSec) || (SymTab && StrTab && SymTabSec)); if (reinterpret_cast(Obj.base() + Sec.sh_offset) % sizeof(uint16_t) != 0) @@ -487,23 +515,26 @@ return createError("cannot read content of " + describe(Sec) + ": " + toString(VersionsOrErr.takeError())); - Expected, StringRef>> SymTabOrErr = + Expected> SymTabOrErr = getLinkAsSymtab(Obj, Sec, SHT_DYNSYM); if (!SymTabOrErr) { reportUniqueWarning(SymTabOrErr.takeError()); return *VersionsOrErr; } - if (SymTabOrErr->first.size() != VersionsOrErr->size()) + if (SymTabOrErr->Symbols.size() != VersionsOrErr->size()) reportUniqueWarning(describe(Sec) + ": the number of entries (" + Twine(VersionsOrErr->size()) + ") does not match the number of symbols (" + - Twine(SymTabOrErr->first.size()) + + Twine(SymTabOrErr->Symbols.size()) + ") in the symbol table with index " + Twine(Sec.sh_link)); - if (SymTab) - std::tie(*SymTab, *StrTab) = *SymTabOrErr; + if (SymTab) { + *SymTab = SymTabOrErr->Symbols; + *StrTab = SymTabOrErr->StringTable; + *SymTabSec = SymTabOrErr->SymTab; + } return *VersionsOrErr; } @@ -710,10 +741,16 @@ bool NonVisibilityBitsUsed = llvm::any_of(Syms, [](const Elf_Sym &S) { return S.st_other & ~0x3; }); + DataRegion ShndxTable = + IsDynamic ? DataRegion( + (const Elf_Word *)this->getDynSymTabShndxRegion().Addr, + this->getElfObject().getELFFile().end()) + : DataRegion(this->getShndxTable(SymtabSec)); + ELFDumperStyle->printSymtabMessage(SymtabSec, Entries, NonVisibilityBitsUsed); for (const Elf_Sym &Sym : Syms) - ELFDumperStyle->printSymbol(Sym, &Sym - Syms.begin(), StrTable, IsDynamic, - NonVisibilityBitsUsed); + ELFDumperStyle->printSymbol(Sym, &Sym - Syms.begin(), ShndxTable, StrTable, + IsDynamic, NonVisibilityBitsUsed); } template class MipsGOTParser; @@ -743,6 +780,7 @@ virtual void printSymtabMessage(const Elf_Shdr *Symtab, size_t Offset, bool NonVisibilityBitsUsed) {} virtual void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable, Optional StrTable, bool IsDynamic, bool NonVisibilityBitsUsed) = 0; virtual void printProgramHeaders(bool PrintProgramHeaders, @@ -904,7 +942,8 @@ return OS; } void printHashedSymbol(const Elf_Sym *Sym, unsigned SymIndex, - StringRef StrTable, uint32_t Bucket); + DataRegion ShndxTable, StringRef StrTable, + uint32_t Bucket); void printReloc(const Relocation &R, unsigned RelIndex, const Elf_Shdr &Sec, const Elf_Shdr *SymTab) override; void printRelrReloc(const Elf_Relr &R) override; @@ -912,13 +951,15 @@ void printRelRelaReloc(const Relocation &R, const RelSymbol &RelSym); void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable, Optional StrTable, bool IsDynamic, bool NonVisibilityBitsUsed) override; void printDynamicRelocHeader(unsigned Type, StringRef Name, const DynRegionInfo &Reg) override; void printDynamicReloc(const Relocation &R) override; - std::string getSymbolSectionNdx(const Elf_Sym &Symbol, unsigned SymIndex); + std::string getSymbolSectionNdx(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable); void printProgramHeaders(); void printSectionMapping(); void printGNUVersionSectionProlog(const typename ELFT::Shdr &Sec, @@ -975,8 +1016,10 @@ void printRelRelaReloc(const Relocation &R, StringRef SymbolName); void printSymbols(); void printDynamicSymbols(); - void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex); + void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable); void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable, Optional StrTable, bool IsDynamic, bool /*NonVisibilityBitsUsed*/) override; void printProgramHeaders(); @@ -1104,8 +1147,9 @@ const Elf_Sym *FirstSym = cantFail(Obj.template getEntry(*SymTab, 0)); - std::string SymbolName = getFullSymbolName( - *Sym, Sym - FirstSym, *StrTableOrErr, SymTab->sh_type == SHT_DYNSYM); + std::string SymbolName = + getFullSymbolName(*Sym, Sym - FirstSym, getShndxTable(SymTab), + *StrTableOrErr, SymTab->sh_type == SHT_DYNSYM); return RelSymbol(Sym, SymbolName); } @@ -1166,6 +1210,7 @@ template std::string ELFDumper::getFullSymbolName(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable, Optional StrTable, bool IsDynamic) const { if (!StrTable) @@ -1180,7 +1225,8 @@ } if (SymbolName.empty() && Symbol.getType() == ELF::STT_SECTION) { - Expected SectionIndex = getSymbolSectionIndex(Symbol, SymIndex); + Expected SectionIndex = + getSymbolSectionIndex(Symbol, SymIndex, ShndxTable); if (!SectionIndex) { reportUniqueWarning(SectionIndex.takeError()); return ""; @@ -1212,8 +1258,8 @@ template Expected -ELFDumper::getSymbolSectionIndex(const Elf_Sym &Symbol, - unsigned SymIndex) const { +ELFDumper::getSymbolSectionIndex(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable) const { unsigned Ndx = Symbol.st_shndx; if (Ndx == SHN_XINDEX) return object::getExtendedSymbolTableIndex(Symbol, SymIndex, @@ -1992,7 +2038,8 @@ ScopedPrinter &Writer) : ObjDumper(Writer, O.getFileName()), ObjF(O), Obj(O.getELFFile()), DynRelRegion(O, *this), DynRelaRegion(O, *this), DynRelrRegion(O, *this), - DynPLTRelRegion(O, *this), DynamicTable(O, *this) { + DynPLTRelRegion(O, *this), DynSymTabShndxRegion(O, *this), + DynamicTable(O, *this) { if (opts::Output == opts::GNU) ELFDumperStyle.reset(new GNUStyle(Writer, *this)); else @@ -2031,12 +2078,29 @@ } } break; - case ELF::SHT_SYMTAB_SHNDX: - if (Expected> ShndxTableOrErr = Obj.getSHNDXTable(Sec)) - ShndxTable = *ShndxTableOrErr; - else + case ELF::SHT_SYMTAB_SHNDX: { + uint32_t SymtabNdx = Sec.sh_link; + if (SymtabNdx >= Sections.size()) { + reportUniqueWarning( + "unable to get the associated symbol table for " + describe(Sec) + + ": sh_link (" + Twine(SymtabNdx) + + ") is greater than or equal to the total number of sections (" + + Twine(Sections.size()) + ")"); + continue; + } + + if (Expected> ShndxTableOrErr = + Obj.getSHNDXTable(Sec)) { + if (!ShndxTables.insert({&Sections[SymtabNdx], *ShndxTableOrErr}) + .second) + reportUniqueWarning( + "multiple SHT_SYMTAB_SHNDX sections are linked to " + + describe(Sec)); + } else { this->reportUniqueWarning(ShndxTableOrErr.takeError()); + } break; + } case ELF::SHT_GNU_versym: if (!SymbolVersionSection) SymbolVersionSection = &Sec; @@ -2178,6 +2242,10 @@ DynPLTRelRegion.Size = Dyn.getVal(); DynPLTRelRegion.SizePrintName = "DT_PLTRELSZ value"; break; + case ELF::DT_SYMTAB_SHNDX: + DynSymTabShndxRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); + DynSymTabShndxRegion.EntSize = sizeof(Elf_Word); + break; } } @@ -3970,8 +4038,9 @@ } template -std::string GNUStyle::getSymbolSectionNdx(const Elf_Sym &Symbol, - unsigned SymIndex) { +std::string +GNUStyle::getSymbolSectionNdx(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable) { unsigned SectionIndex = Symbol.st_shndx; switch (SectionIndex) { case ELF::SHN_UNDEF: @@ -3981,8 +4050,8 @@ case ELF::SHN_COMMON: return "COM"; case ELF::SHN_XINDEX: { - Expected IndexOrErr = object::getExtendedSymbolTableIndex( - Symbol, SymIndex, this->dumper().getShndxTable()); + Expected IndexOrErr = + object::getExtendedSymbolTableIndex(Symbol, SymIndex, ShndxTable); if (!IndexOrErr) { assert(Symbol.st_shndx == SHN_XINDEX && "getExtendedSymbolTableIndex should only fail due to an invalid " @@ -4014,6 +4083,7 @@ template void GNUStyle::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable, Optional StrTable, bool IsDynamic, bool NonVisibilityBitsUsed) { unsigned Bias = ELFT::Is64Bits ? 8 : 0; @@ -4053,10 +4123,9 @@ } Fields[6].Column += NonVisibilityBitsUsed ? 13 : 0; - Fields[6].Str = getSymbolSectionNdx(Symbol, SymIndex); - - Fields[7].Str = - this->dumper().getFullSymbolName(Symbol, SymIndex, StrTable, IsDynamic); + Fields[6].Str = getSymbolSectionNdx(Symbol, SymIndex, ShndxTable); + Fields[7].Str = this->dumper().getFullSymbolName(Symbol, SymIndex, ShndxTable, + StrTable, IsDynamic); for (const Field &Entry : Fields) printField(Entry); OS << "\n"; @@ -4064,6 +4133,7 @@ template void GNUStyle::printHashedSymbol(const Elf_Sym *Symbol, unsigned SymIndex, + DataRegion ShndxTable, StringRef StrTable, uint32_t Bucket) { unsigned Bias = ELFT::Is64Bits ? 8 : 0; Field Fields[9] = {0, 6, 11, 20 + Bias, 25 + Bias, @@ -4086,9 +4156,9 @@ printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings)); Fields[6].Str = printEnum(Symbol->getVisibility(), makeArrayRef(ElfSymbolVisibilities)); - Fields[7].Str = getSymbolSectionNdx(*Symbol, SymIndex); - Fields[8].Str = - this->dumper().getFullSymbolName(*Symbol, SymIndex, StrTable, true); + Fields[7].Str = getSymbolSectionNdx(*Symbol, SymIndex, ShndxTable); + Fields[8].Str = this->dumper().getFullSymbolName(*Symbol, SymIndex, + ShndxTable, StrTable, true); for (const Field &Entry : Fields) printField(Entry); @@ -4128,6 +4198,10 @@ return; } + const ELFFile &EF = this->dumper().getElfObject().getELFFile(); + DataRegion ShndxTable( + (const Elf_Word *)this->dumper().getDynSymTabShndxRegion().Addr, + EF.end()); auto Buckets = SysVHash.buckets(); auto Chains = SysVHash.chains(); for (uint32_t Buc = 0; Buc < SysVHash.nbucket; Buc++) { @@ -4145,7 +4219,7 @@ break; } - printHashedSymbol(FirstSym + Ch, Ch, StringTable, Buc); + printHashedSymbol(FirstSym + Ch, Ch, ShndxTable, StringTable, Buc); Visited[Ch] = true; } } @@ -4191,6 +4265,10 @@ else Values = *ValuesOrErr; + const ELFFile &EF = this->dumper().getElfObject().getELFFile(); + DataRegion ShndxTable( + (const Elf_Word *)this->dumper().getDynSymTabShndxRegion().Addr, + EF.end()); ArrayRef Buckets = GnuHash.buckets(); for (uint32_t Buc = 0; Buc < GnuHash.nbuckets; Buc++) { if (Buckets[Buc] == ELF::STN_UNDEF) @@ -4200,7 +4278,7 @@ while (true) { uint32_t SymIndex = Index++; if (const Elf_Sym *Sym = GetSymbol(SymIndex, DynSyms.size())) - printHashedSymbol(Sym, SymIndex, StringTable, Buc); + printHashedSymbol(Sym, SymIndex, ShndxTable, StringTable, Buc); else break; @@ -4739,7 +4817,7 @@ Sec->sh_size / sizeof(Elf_Versym)); Expected> VerTableOrErr = this->dumper().getVersionTable(*Sec, /*SymTab=*/nullptr, - /*StrTab=*/nullptr); + /*StrTab=*/nullptr, /*SymTabSec=*/nullptr); if (!VerTableOrErr) { this->reportUniqueWarning(VerTableOrErr.takeError()); return; @@ -5858,8 +5936,10 @@ // Check if the symbol is in the right section. FunctionSec == None // means "any section". if (FunctionSec) { + ArrayRef ShndxTable = + this->dumper().getShndxTable(SymTab); if (Expected SecOrErr = - Obj.getSection(Sym, SymTab, this->dumper().getShndxTable())) { + Obj.getSection(Sym, SymTab, ShndxTable)) { if (*FunctionSec != *SecOrErr) continue; } else { @@ -5933,8 +6013,8 @@ uint64_t RelocSymValue = 0; if (Sym) { - Expected SectionOrErr = - this->Obj.getSection(*Sym, SymTab, this->dumper().getShndxTable()); + Expected SectionOrErr = this->Obj.getSection( + *Sym, SymTab, this->dumper().getShndxTable(SymTab)); if (!SectionOrErr) { reportUniqueWarning( "cannot identify the section for relocation symbol '" + @@ -6159,11 +6239,17 @@ << " Type Ndx Name\n"; else OS << " Address Access Initial Sym.Val. Type Ndx Name\n"; + const ELFFile &EF = this->dumper().getElfObject().getELFFile(); + DataRegion ShndxTable( + (const Elf_Word *)this->dumper().getDynSymTabShndxRegion().Addr, + EF.end()); + for (auto &E : Parser.getGlobalEntries()) { const Elf_Sym &Sym = *Parser.getGotSym(&E); const Elf_Sym &FirstSym = this->dumper().dynamic_symbols()[0]; std::string SymName = this->dumper().getFullSymbolName( - Sym, &Sym - &FirstSym, this->dumper().getDynamicStringTable(), false); + Sym, &Sym - &FirstSym, ShndxTable, + this->dumper().getDynamicStringTable(), false); OS.PadToColumn(2); OS << to_string(format_hex_no_prefix(Parser.getGotAddress(&E), 8 + Bias)); @@ -6176,8 +6262,9 @@ OS.PadToColumn(40 + 3 * Bias); OS << printEnum(Sym.getType(), makeArrayRef(ElfSymbolTypes)); OS.PadToColumn(48 + 3 * Bias); + OS << getSymbolSectionNdx( - Sym, &Sym - this->dumper().dynamic_symbols().begin()); + Sym, &Sym - this->dumper().dynamic_symbols().begin(), ShndxTable); OS.PadToColumn(52 + 3 * Bias); OS << SymName << "\n"; } @@ -6212,12 +6299,18 @@ OS << "\n"; OS << " Entries:\n"; OS << " Address Initial Sym.Val. Type Ndx Name\n"; + const ELFFile &EF = this->dumper().getElfObject().getELFFile(); + DataRegion ShndxTable( + (const Elf_Word *)this->dumper().getDynSymTabShndxRegion().Addr, + EF.end()); + for (auto &E : Parser.getPltEntries()) { const Elf_Sym &Sym = *Parser.getPltSym(&E); const Elf_Sym &FirstSym = *cantFail( this->Obj.template getEntry(*Parser.getPltSymTable(), 0)); std::string SymName = this->dumper().getFullSymbolName( - Sym, &Sym - &FirstSym, this->dumper().getDynamicStringTable(), false); + Sym, &Sym - &FirstSym, ShndxTable, + this->dumper().getDynamicStringTable(), false); OS.PadToColumn(2); OS << to_string(format_hex_no_prefix(Parser.getPltAddress(&E), 8 + Bias)); @@ -6228,8 +6321,9 @@ OS.PadToColumn(29 + 3 * Bias); OS << printEnum(Sym.getType(), makeArrayRef(ElfSymbolTypes)); OS.PadToColumn(37 + 3 * Bias); + OS << getSymbolSectionNdx( - Sym, &Sym - this->dumper().dynamic_symbols().begin()); + Sym, &Sym - this->dumper().dynamic_symbols().begin(), ShndxTable); OS.PadToColumn(41 + 3 * Bias); OS << SymName << "\n"; } @@ -6483,15 +6577,15 @@ if (const Elf_Shdr *Symtab = this->dumper().getDotSymtabSec()) { StringRef StrTable = unwrapOrError( this->FileName, this->Obj.getStringTableForSymtab(*Symtab)); - + ArrayRef ShndxTable = this->dumper().getShndxTable(Symtab); typename ELFT::SymRange Symbols = unwrapOrError(this->FileName, this->Obj.symbols(Symtab)); for (const Elf_Sym &Sym : Symbols) { const Elf_Shdr *SymSec = unwrapOrError( - this->FileName, this->Obj.getSection( - Sym, Symtab, this->dumper().getShndxTable())); + this->FileName, this->Obj.getSection(Sym, Symtab, ShndxTable)); if (SymSec == &Sec) - printSymbol(Sym, &Sym - &Symbols[0], StrTable, false, false); + printSymbol(Sym, &Sym - &Symbols[0], ShndxTable, StrTable, false, + false); } } } @@ -6508,7 +6602,8 @@ template void LLVMStyle::printSymbolSection(const Elf_Sym &Symbol, - unsigned SymIndex) { + unsigned SymIndex, + DataRegion ShndxTable) { auto GetSectionSpecialType = [&]() -> Optional { if (Symbol.isUndefined()) return StringRef("Undefined"); @@ -6531,7 +6626,7 @@ } Expected SectionIndex = - this->dumper().getSymbolSectionIndex(Symbol, SymIndex); + this->dumper().getSymbolSectionIndex(Symbol, SymIndex, ShndxTable); if (!SectionIndex) { assert(Symbol.st_shndx == SHN_XINDEX && "getSymbolSectionIndex should only fail due to an invalid " @@ -6558,10 +6653,11 @@ template void LLVMStyle::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable, Optional StrTable, bool IsDynamic, bool /*NonVisibilityBitsUsed*/) { - std::string FullSymbolName = - this->dumper().getFullSymbolName(Symbol, SymIndex, StrTable, IsDynamic); + std::string FullSymbolName = this->dumper().getFullSymbolName( + Symbol, SymIndex, ShndxTable, StrTable, IsDynamic); unsigned char SymbolType = Symbol.getType(); DictScope D(W, "Symbol"); @@ -6600,7 +6696,7 @@ } W.printFlags("Other", Symbol.st_other, makeArrayRef(SymOtherFlags), 0x3u); } - printSymbolSection(Symbol, SymIndex); + printSymbolSection(Symbol, SymIndex, ShndxTable); } template @@ -6706,8 +6802,9 @@ StringRef StrTable; ArrayRef Syms; + const Elf_Shdr *SymTabSec; Expected> VerTableOrErr = - this->dumper().getVersionTable(*Sec, &Syms, &StrTable); + this->dumper().getVersionTable(*Sec, &Syms, &StrTable, &SymTabSec); if (!VerTableOrErr) { this->reportUniqueWarning(VerTableOrErr.takeError()); return; @@ -6716,10 +6813,12 @@ if (StrTable.empty() || Syms.empty() || Syms.size() != VerTableOrErr->size()) return; + ArrayRef ShNdxTable = this->dumper().getShndxTable(SymTabSec); for (size_t I = 0, E = Syms.size(); I < E; ++I) { DictScope S(W, "Symbol"); W.printNumber("Version", (*VerTableOrErr)[I].vs_index & VERSYM_VERSION); - W.printString("Name", this->dumper().getFullSymbolName(Syms[I], I, StrTable, + W.printString("Name", this->dumper().getFullSymbolName(Syms[I], I, + ShNdxTable, StrTable, /*IsDynamic=*/true)); } } @@ -7050,10 +7149,15 @@ W.printEnum("Type", Sym.getType(), makeArrayRef(ElfSymbolTypes)); const unsigned SymIndex = &Sym - this->dumper().dynamic_symbols().begin(); - printSymbolSection(Sym, SymIndex); + const ELFFile &EF = this->dumper().getElfObject().getELFFile(); + DataRegion ShndxTable( + (const Elf_Word *)this->dumper().getDynSymTabShndxRegion().Addr, + EF.end()); + printSymbolSection(Sym, SymIndex, ShndxTable); std::string SymName = this->dumper().getFullSymbolName( - Sym, SymIndex, this->dumper().getDynamicStringTable(), true); + Sym, SymIndex, ShndxTable, this->dumper().getDynamicStringTable(), + true); W.printNumber("Name", SymName, Sym.st_name); } } @@ -7087,6 +7191,10 @@ } { ListScope LS(W, "Entries"); + const ELFFile &EF = this->dumper().getElfObject().getELFFile(); + DataRegion ShndxTable( + (const Elf_Word *)this->dumper().getDynSymTabShndxRegion().Addr, + EF.end()); for (auto &E : Parser.getPltEntries()) { DictScope D(W, "Entry"); PrintEntry(&E); @@ -7094,12 +7202,13 @@ const Elf_Sym &Sym = *Parser.getPltSym(&E); W.printHex("Value", Sym.st_value); W.printEnum("Type", Sym.getType(), makeArrayRef(ElfSymbolTypes)); - printSymbolSection(Sym, &Sym - this->dumper().dynamic_symbols().begin()); + printSymbolSection(Sym, &Sym - this->dumper().dynamic_symbols().begin(), + ShndxTable); const Elf_Sym *FirstSym = cantFail( this->Obj.template getEntry(*Parser.getPltSymTable(), 0)); std::string SymName = this->dumper().getFullSymbolName( - Sym, &Sym - FirstSym, Parser.getPltStrTable(), true); + Sym, &Sym - FirstSym, ShndxTable, Parser.getPltStrTable(), true); W.printNumber("Name", SymName, Sym.st_name); } } Index: llvm/unittests/Object/ELFTest.cpp =================================================================== --- llvm/unittests/Object/ELFTest.cpp +++ llvm/unittests/Object/ELFTest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Object/ELF.h" +#include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" using namespace llvm; @@ -54,3 +55,36 @@ TEST(ELFTest, getELFRelativeRelocationType) { EXPECT_EQ(0U, getELFRelativeRelocationType(EM_VE)); } + +// This is a test for the DataRegion helper struct, defined in ELF.h header. +TEST(ELFTest, DataRegionTest) { + std::vector Data = {0, 1, 2}; + + // Used to check that the operator[] works properly. + auto CheckOperator = [&](DataRegion &R) { + for (size_t I = 0, E = Data.size(); I != E; ++I) { + if (Expected ValOrErr = R[I]) + EXPECT_EQ(*ValOrErr, I); + else + ADD_FAILURE() << toString(ValOrErr.takeError()); + } + }; + + // Check we can use the constructor that takes an ArrayRef. + DataRegion Region(Data); + + CheckOperator(Region); + const char *ErrMsg1 = + "the index is greater or equal to the number of entries (3)"; + EXPECT_THAT_ERROR(Region[3].takeError(), FailedWithMessage(ErrMsg1)); + EXPECT_THAT_ERROR(Region[4].takeError(), FailedWithMessage(ErrMsg1)); + + // Check we can use the constructor that takes the data begin and the + // data end pointers. + Region = {Data.data(), Data.data() + Data.size()}; + + CheckOperator(Region); + const char *ErrMsg2 = "can't read past the end of the file"; + EXPECT_THAT_ERROR(Region[3].takeError(), FailedWithMessage(ErrMsg2)); + EXPECT_THAT_ERROR(Region[4].takeError(), FailedWithMessage(ErrMsg2)); +}