diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h --- a/llvm/include/llvm/Object/ELF.h +++ b/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 than 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(); diff --git a/llvm/test/Object/invalid.test b/llvm/test/Object/invalid.test --- a/llvm/test/Object/invalid.test +++ b/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 diff --git a/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test b/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test --- a/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test +++ b/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: diff --git a/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test b/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test --- a/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test +++ b/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 diff --git a/llvm/test/tools/llvm-readobj/ELF/mips-got.test b/llvm/test/tools/llvm-readobj/ELF/mips-got.test --- a/llvm/test/tools/llvm-readobj/ELF/mips-got.test +++ b/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 diff --git a/llvm/test/tools/llvm-readobj/ELF/mips-plt.test b/llvm/test/tools/llvm-readobj/ELF/mips-plt.test --- a/llvm/test/tools/llvm-readobj/ELF/mips-plt.test +++ b/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 diff --git a/llvm/test/tools/llvm-readobj/ELF/section-symbols.test b/llvm/test/tools/llvm-readobj/ELF/section-symbols.test --- a/llvm/test/tools/llvm-readobj/ELF/section-symbols.test +++ b/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: diff --git a/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test b/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test --- a/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test +++ b/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: ] diff --git a/llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test b/llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test new file mode 100644 --- /dev/null +++ b/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 diff --git a/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml b/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml --- a/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml +++ b/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: diff --git a/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml b/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml --- a/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml +++ b/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: diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -314,6 +314,7 @@ virtual void printSymtabMessage(const Elf_Shdr *Symtab, size_t Offset, bool NonVisibilityBitsUsed) const {}; virtual void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable, Optional StrTable, bool IsDynamic, bool NonVisibilityBitsUsed) const = 0; @@ -321,9 +322,9 @@ virtual void printMipsGOT(const MipsGOTParser &Parser) = 0; virtual void printMipsPLT(const MipsGOTParser &Parser) = 0; - 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; StringRef getPrintableSectionName(const Elf_Shdr &Sec) const; std::vector getGroups(); @@ -372,6 +373,7 @@ DynRegionInfo DynRelrRegion; DynRegionInfo DynPLTRelRegion; Optional DynSymRegion; + DynRegionInfo DynSymTabShndxRegion; DynRegionInfo DynamicTable; StringRef DynamicStringTable; const Elf_Hash *HashTable = nullptr; @@ -380,7 +382,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 @@ -394,10 +396,12 @@ mutable SmallVector, 16> VersionMap; 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; @@ -415,6 +419,8 @@ Expected> getRelocationTarget(const Relocation &R, const Elf_Shdr *SymTab) const; + + ArrayRef getShndxTable(const Elf_Shdr *Symtab) const; }; template @@ -432,9 +438,11 @@ return ::describe(Obj, Sec); } +namespace { + template -static Expected getLinkAsStrtab(const ELFFile &Obj, - const typename ELFT::Shdr &Sec) { +Expected getLinkAsStrtab(const ELFFile &Obj, + const typename ELFT::Shdr &Sec) { Expected StrTabSecOrErr = Obj.getSection(Sec.sh_link); if (!StrTabSecOrErr) @@ -448,11 +456,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) @@ -478,14 +493,17 @@ 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) @@ -497,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; } @@ -720,9 +741,15 @@ bool NonVisibilityBitsUsed = llvm::any_of(Syms, [](const Elf_Sym &S) { return S.st_other & ~0x3; }); + DataRegion ShndxTable = + IsDynamic ? DataRegion( + (const Elf_Word *)this->DynSymTabShndxRegion.Addr, + this->getElfObject().getELFFile().end()) + : DataRegion(this->getShndxTable(SymtabSec)); + printSymtabMessage(SymtabSec, Entries, NonVisibilityBitsUsed); for (const Elf_Sym &Sym : Syms) - printSymbol(Sym, &Sym - Syms.begin(), StrTable, IsDynamic, + printSymbol(Sym, &Sym - Syms.begin(), ShndxTable, StrTable, IsDynamic, NonVisibilityBitsUsed); } @@ -819,18 +846,20 @@ return OS; } void printHashedSymbol(const Elf_Sym *Sym, unsigned SymIndex, - StringRef StrTable, uint32_t Bucket); + DataRegion ShndxTable, StringRef StrTable, + uint32_t Bucket); void printRelrReloc(const Elf_Relr &R) override; void printRelRelaReloc(const Relocation &R, const RelSymbol &RelSym) override; void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable, Optional StrTable, bool IsDynamic, bool NonVisibilityBitsUsed) const override; void printDynamicRelocHeader(unsigned Type, StringRef Name, const DynRegionInfo &Reg) override; - std::string getSymbolSectionNdx(const Elf_Sym &Symbol, - unsigned SymIndex) const; + std::string getSymbolSectionNdx(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable) const; void printProgramHeaders() override; void printSectionMapping() override; void printGNUVersionSectionProlog(const typename ELFT::Shdr &Sec, @@ -875,8 +904,10 @@ void printRelRelaReloc(const Relocation &R, const RelSymbol &RelSym) override; - void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex) const; + void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable) const; void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable, Optional StrTable, bool IsDynamic, bool /*NonVisibilityBitsUsed*/) const override; void printProgramHeaders() override; @@ -1011,11 +1042,23 @@ 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); } +template +ArrayRef +ELFDumper::getShndxTable(const Elf_Shdr *Symtab) const { + if (Symtab) { + auto It = ShndxTables.find(Symtab); + if (It != ShndxTables.end()) + return It->second; + } + return {}; +} + static std::string maybeDemangle(StringRef Name) { return opts::Demangle ? demangle(std::string(Name)) : Name.str(); } @@ -1073,6 +1116,7 @@ template std::string ELFDumper::getFullSymbolName(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable, Optional StrTable, bool IsDynamic) const { if (!StrTable) @@ -1087,7 +1131,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 ""; @@ -1119,8 +1164,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, @@ -1900,7 +1945,8 @@ : ObjDumper(Writer, O.getFileName()), ObjF(O), Obj(O.getELFFile()), FileName(O.getFileName()), 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 (!O.IsContentValid()) return; @@ -1934,12 +1980,29 @@ } } break; - case ELF::SHT_SYMTAB_SHNDX: - if (Expected> ShndxTableOrErr = Obj.getSHNDXTable(Sec)) - ShndxTable = *ShndxTableOrErr; - else - this->reportUniqueWarning(ShndxTableOrErr.takeError()); + 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 { + reportUniqueWarning(ShndxTableOrErr.takeError()); + } break; + } case ELF::SHT_GNU_versym: if (!SymbolVersionSection) SymbolVersionSection = &Sec; @@ -2081,6 +2144,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; } } @@ -3781,8 +3848,10 @@ } template -std::string GNUELFDumper::getSymbolSectionNdx(const Elf_Sym &Symbol, - unsigned SymIndex) const { +std::string +GNUELFDumper::getSymbolSectionNdx(const Elf_Sym &Symbol, + unsigned SymIndex, + DataRegion ShndxTable) const { unsigned SectionIndex = Symbol.st_shndx; switch (SectionIndex) { case ELF::SHN_UNDEF: @@ -3792,8 +3861,8 @@ case ELF::SHN_COMMON: return "COM"; case ELF::SHN_XINDEX: { - Expected IndexOrErr = object::getExtendedSymbolTableIndex( - Symbol, SymIndex, this->ShndxTable); + Expected IndexOrErr = + object::getExtendedSymbolTableIndex(Symbol, SymIndex, ShndxTable); if (!IndexOrErr) { assert(Symbol.st_shndx == SHN_XINDEX && "getExtendedSymbolTableIndex should only fail due to an invalid " @@ -3825,6 +3894,7 @@ template void GNUELFDumper::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable, Optional StrTable, bool IsDynamic, bool NonVisibilityBitsUsed) const { @@ -3865,10 +3935,10 @@ } Fields[6].Column += NonVisibilityBitsUsed ? 13 : 0; - Fields[6].Str = getSymbolSectionNdx(Symbol, SymIndex); + Fields[6].Str = getSymbolSectionNdx(Symbol, SymIndex, ShndxTable); - Fields[7].Str = - this->getFullSymbolName(Symbol, SymIndex, StrTable, IsDynamic); + Fields[7].Str = this->getFullSymbolName(Symbol, SymIndex, ShndxTable, + StrTable, IsDynamic); for (const Field &Entry : Fields) printField(Entry); OS << "\n"; @@ -3877,6 +3947,7 @@ template void GNUELFDumper::printHashedSymbol(const Elf_Sym *Symbol, unsigned SymIndex, + DataRegion ShndxTable, StringRef StrTable, uint32_t Bucket) { unsigned Bias = ELFT::Is64Bits ? 8 : 0; @@ -3900,8 +3971,9 @@ printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings)); Fields[6].Str = printEnum(Symbol->getVisibility(), makeArrayRef(ElfSymbolVisibilities)); - Fields[7].Str = getSymbolSectionNdx(*Symbol, SymIndex); - Fields[8].Str = this->getFullSymbolName(*Symbol, SymIndex, StrTable, true); + Fields[7].Str = getSymbolSectionNdx(*Symbol, SymIndex, ShndxTable); + Fields[8].Str = + this->getFullSymbolName(*Symbol, SymIndex, ShndxTable, StrTable, true); for (const Field &Entry : Fields) printField(Entry); @@ -3940,6 +4012,8 @@ return; } + DataRegion ShndxTable( + (const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end()); auto Buckets = SysVHash.buckets(); auto Chains = SysVHash.chains(); for (uint32_t Buc = 0; Buc < SysVHash.nbucket; Buc++) { @@ -3957,7 +4031,8 @@ break; } - printHashedSymbol(FirstSym + Ch, Ch, this->DynamicStringTable, Buc); + printHashedSymbol(FirstSym + Ch, Ch, ShndxTable, this->DynamicStringTable, + Buc); Visited[Ch] = true; } } @@ -4001,6 +4076,8 @@ else Values = *ValuesOrErr; + DataRegion ShndxTable( + (const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end()); ArrayRef Buckets = GnuHash.buckets(); for (uint32_t Buc = 0; Buc < GnuHash.nbuckets; Buc++) { if (Buckets[Buc] == ELF::STN_UNDEF) @@ -4010,7 +4087,8 @@ while (true) { uint32_t SymIndex = Index++; if (const Elf_Sym *Sym = GetSymbol(SymIndex, DynSyms.size())) - printHashedSymbol(Sym, SymIndex, this->DynamicStringTable, Buc); + printHashedSymbol(Sym, SymIndex, ShndxTable, this->DynamicStringTable, + Buc); else break; @@ -4549,7 +4627,7 @@ Sec->sh_size / sizeof(Elf_Versym)); Expected> VerTableOrErr = this->getVersionTable(*Sec, /*SymTab=*/nullptr, - /*StrTab=*/nullptr); + /*StrTab=*/nullptr, /*SymTabSec=*/nullptr); if (!VerTableOrErr) { this->reportUniqueWarning(VerTableOrErr.takeError()); return; @@ -5667,7 +5745,8 @@ // means "any section". if (FunctionSec) { if (Expected SecOrErr = - Obj.getSection(Sym, this->DotSymtabSec, this->ShndxTable)) { + Obj.getSection(Sym, this->DotSymtabSec, + this->getShndxTable(this->DotSymtabSec))) { if (*FunctionSec != *SecOrErr) continue; } else { @@ -5742,7 +5821,7 @@ uint64_t RelocSymValue = 0; if (Sym) { Expected SectionOrErr = - this->Obj.getSection(*Sym, SymTab, this->ShndxTable); + this->Obj.getSection(*Sym, SymTab, this->getShndxTable(SymTab)); if (!SectionOrErr) { reportUniqueWarning( "cannot identify the section for relocation symbol '" + @@ -5966,11 +6045,14 @@ << " Type Ndx Name\n"; else OS << " Address Access Initial Sym.Val. Type Ndx Name\n"; + + DataRegion ShndxTable( + (const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end()); for (auto &E : Parser.getGlobalEntries()) { const Elf_Sym &Sym = *Parser.getGotSym(&E); const Elf_Sym &FirstSym = this->dynamic_symbols()[0]; std::string SymName = this->getFullSymbolName( - Sym, &Sym - &FirstSym, this->DynamicStringTable, false); + Sym, &Sym - &FirstSym, ShndxTable, this->DynamicStringTable, false); OS.PadToColumn(2); OS << to_string(format_hex_no_prefix(Parser.getGotAddress(&E), 8 + Bias)); @@ -5983,7 +6065,8 @@ OS.PadToColumn(40 + 3 * Bias); OS << printEnum(Sym.getType(), makeArrayRef(ElfSymbolTypes)); OS.PadToColumn(48 + 3 * Bias); - OS << getSymbolSectionNdx(Sym, &Sym - this->dynamic_symbols().begin()); + OS << getSymbolSectionNdx(Sym, &Sym - this->dynamic_symbols().begin(), + ShndxTable); OS.PadToColumn(52 + 3 * Bias); OS << SymName << "\n"; } @@ -6018,12 +6101,14 @@ OS << "\n"; OS << " Entries:\n"; OS << " Address Initial Sym.Val. Type Ndx Name\n"; + DataRegion ShndxTable( + (const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.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->getFullSymbolName( - Sym, &Sym - &FirstSym, this->DynamicStringTable, false); + Sym, &Sym - &FirstSym, ShndxTable, this->DynamicStringTable, false); OS.PadToColumn(2); OS << to_string(format_hex_no_prefix(Parser.getPltAddress(&E), 8 + Bias)); @@ -6034,7 +6119,8 @@ OS.PadToColumn(29 + 3 * Bias); OS << printEnum(Sym.getType(), makeArrayRef(ElfSymbolTypes)); OS.PadToColumn(37 + 3 * Bias); - OS << getSymbolSectionNdx(Sym, &Sym - this->dynamic_symbols().begin()); + OS << getSymbolSectionNdx(Sym, &Sym - this->dynamic_symbols().begin(), + ShndxTable); OS.PadToColumn(41 + 3 * Bias); OS << SymName << "\n"; } @@ -6276,15 +6362,17 @@ StringRef StrTable = unwrapOrError( this->FileName, this->Obj.getStringTableForSymtab(*this->DotSymtabSec)); + ArrayRef ShndxTable = this->getShndxTable(this->DotSymtabSec); typename ELFT::SymRange Symbols = unwrapOrError( this->FileName, this->Obj.symbols(this->DotSymtabSec)); for (const Elf_Sym &Sym : Symbols) { const Elf_Shdr *SymSec = unwrapOrError( this->FileName, - this->Obj.getSection(Sym, this->DotSymtabSec, this->ShndxTable)); + this->Obj.getSection(Sym, this->DotSymtabSec, ShndxTable)); if (SymSec == &Sec) - printSymbol(Sym, &Sym - &Symbols[0], StrTable, false, false); + printSymbol(Sym, &Sym - &Symbols[0], ShndxTable, StrTable, false, + false); } } } @@ -6300,8 +6388,9 @@ } template -void LLVMELFDumper::printSymbolSection(const Elf_Sym &Symbol, - unsigned SymIndex) const { +void LLVMELFDumper::printSymbolSection( + const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable) const { auto GetSectionSpecialType = [&]() -> Optional { if (Symbol.isUndefined()) return StringRef("Undefined"); @@ -6324,7 +6413,7 @@ } Expected SectionIndex = - this->getSymbolSectionIndex(Symbol, SymIndex); + this->getSymbolSectionIndex(Symbol, SymIndex, ShndxTable); if (!SectionIndex) { assert(Symbol.st_shndx == SHN_XINDEX && "getSymbolSectionIndex should only fail due to an invalid " @@ -6351,11 +6440,12 @@ template void LLVMELFDumper::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable, Optional StrTable, bool IsDynamic, bool /*NonVisibilityBitsUsed*/) const { - std::string FullSymbolName = - this->getFullSymbolName(Symbol, SymIndex, StrTable, IsDynamic); + std::string FullSymbolName = this->getFullSymbolName( + Symbol, SymIndex, ShndxTable, StrTable, IsDynamic); unsigned char SymbolType = Symbol.getType(); DictScope D(W, "Symbol"); @@ -6394,7 +6484,7 @@ } W.printFlags("Other", Symbol.st_other, makeArrayRef(SymOtherFlags), 0x3u); } - printSymbolSection(Symbol, SymIndex); + printSymbolSection(Symbol, SymIndex, ShndxTable); } template @@ -6488,8 +6578,9 @@ StringRef StrTable; ArrayRef Syms; + const Elf_Shdr *SymTabSec; Expected> VerTableOrErr = - this->getVersionTable(*Sec, &Syms, &StrTable); + this->getVersionTable(*Sec, &Syms, &StrTable, &SymTabSec); if (!VerTableOrErr) { this->reportUniqueWarning(VerTableOrErr.takeError()); return; @@ -6498,11 +6589,13 @@ if (StrTable.empty() || Syms.empty() || Syms.size() != VerTableOrErr->size()) return; + ArrayRef ShNdxTable = this->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->getFullSymbolName(Syms[I], I, StrTable, - /*IsDynamic=*/true)); + W.printString("Name", + this->getFullSymbolName(Syms[I], I, ShNdxTable, StrTable, + /*IsDynamic=*/true)); } } @@ -6830,10 +6923,12 @@ W.printEnum("Type", Sym.getType(), makeArrayRef(ElfSymbolTypes)); const unsigned SymIndex = &Sym - this->dynamic_symbols().begin(); - printSymbolSection(Sym, SymIndex); + DataRegion ShndxTable( + (const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end()); + printSymbolSection(Sym, SymIndex, ShndxTable); std::string SymName = this->getFullSymbolName( - Sym, SymIndex, this->DynamicStringTable, true); + Sym, SymIndex, ShndxTable, this->DynamicStringTable, true); W.printNumber("Name", SymName, Sym.st_name); } } @@ -6867,6 +6962,8 @@ } { ListScope LS(W, "Entries"); + DataRegion ShndxTable( + (const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end()); for (auto &E : Parser.getPltEntries()) { DictScope D(W, "Entry"); PrintEntry(&E); @@ -6874,12 +6971,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->dynamic_symbols().begin()); + printSymbolSection(Sym, &Sym - this->dynamic_symbols().begin(), + ShndxTable); const Elf_Sym *FirstSym = cantFail( this->Obj.template getEntry(*Parser.getPltSymTable(), 0)); std::string SymName = this->getFullSymbolName( - Sym, &Sym - FirstSym, Parser.getPltStrTable(), true); + Sym, &Sym - FirstSym, ShndxTable, Parser.getPltStrTable(), true); W.printNumber("Name", SymName, Sym.st_name); } } diff --git a/llvm/unittests/Object/ELFTest.cpp b/llvm/unittests/Object/ELFTest.cpp --- a/llvm/unittests/Object/ELFTest.cpp +++ b/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,35 @@ 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) { + Expected ValOrErr = R[I]; + ASSERT_THAT_EXPECTED(ValOrErr, Succeeded()); + EXPECT_EQ(*ValOrErr, I); + } + }; + + // Check we can use the constructor that takes an ArrayRef. + DataRegion Region(Data); + + CheckOperator(Region); + const char *ErrMsg1 = + "the index is greater than 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)); +}