llvm/llvm/test/tools/llvm-readobj/ELF/dyn-symbols-size-from-hash-table.test

## This test shows how llvm-readobj uses the hash table section to derive the
## size of a dynamic symbol table. This allows dumping of the dynamic symbol
## table in the event of an object without section headers.

## Case 1a) Table size is derived from hash table, with DT_SYMTAB before DT_HASH.
# RUN: yaml2obj --docnum=1 %s -o %t1a-64 -DBITS=64 \
# RUN:          -DTAG1=DT_SYMTAB -DTAG2=DT_HASH -DVAL1=0x400 -DVAL2=0x600
# RUN: llvm-strip --strip-sections %t1a-64
# RUN: llvm-readobj --dyn-symbols %t1a-64 2>&1 | \
# RUN:   FileCheck %s --check-prefixes=LLVM1,STRIP --implicit-check-not=warning:
# RUN: llvm-readelf --dyn-symbols %t1a-64 2>&1 | \
# RUN:   FileCheck %s --check-prefixes=GNU1,GNU1-STRIP --implicit-check-not=warning:
# RUN: yaml2obj --docnum=1 %s -o %t1a-32 -DBITS=32 \
# RUN:          -DTAG1=DT_SYMTAB -DTAG2=DT_HASH -DVAL1=0x400 -DVAL2=0x600
# RUN: llvm-strip --strip-sections %t1a-32
# RUN: llvm-readobj --dyn-symbols %t1a-32 2>&1 | \
# RUN:   FileCheck %s --check-prefixes=LLVM1,STRIP --implicit-check-not=warning:
# RUN: llvm-readelf --dyn-symbols %t1a-32 2>&1 | \
# RUN:   FileCheck %s --check-prefixes=GNU1,GNU1-STRIP --implicit-check-not=warning:

## 1b) Table size is derived from hash table, with DT_HASH before DT_SYMTAB.
## We don't bother testing 32 and 64-bit here. The above cases show that reading
## the nchain value is correct for all formats, and other tests show the basic
## printing behaviour.
# RUN: yaml2obj --docnum=1 %s -o %t1b-64 -DBITS=64 \
# RUN:          -DTAG1=DT_HASH -DTAG2=DT_SYMTAB -DVAL1=0x600 -DVAL2=0x400
# RUN: llvm-strip --strip-sections %t1b-64
# RUN: llvm-readobj --dyn-symbols %t1b-64 2>&1 | \
# RUN:   FileCheck %s --check-prefixes=LLVM1,STRIP --implicit-check-not=warning:
# RUN: llvm-readelf --dyn-symbols %t1b-64 2>&1 | \
# RUN:   FileCheck %s --check-prefixes=GNU1,GNU1-STRIP --implicit-check-not=warning:

# LLVM1:      DynamicSymbols [
# LLVM1-NEXT:   Symbol {
# LLVM1-NEXT:     Name:  (0)
# LLVM1-NEXT:     Value: 0x0
# LLVM1-NEXT:     Size: 0
# LLVM1-NEXT:     Binding: Local (0x0)
# LLVM1-NEXT:     Type: None (0x0)
# LLVM1-NEXT:     Other: 0
# LLVM1-NEXT:     Section: Undefined (0x0)
# LLVM1-NEXT:   }
# LLVM1-NEXT:   Symbol {
# LLVM1-NEXT:     Name: foo (5)
# LLVM1-NEXT:     Value: 0x100
# LLVM1-NEXT:     Size: 0
# LLVM1-NEXT:     Binding: Local (0x0)
# LLVM1-NEXT:     Type: Function (0x2)
# LLVM1-NEXT:     Other: 0
# STRIP-NEXT:     Section: <?> (0x1)
# NOSTRIP-NEXT:   Section: .text (0x1)
# LLVM1-NEXT:   }
# LLVM1-NEXT:   Symbol {
# LLVM1-NEXT:     Name: bar (1)
# LLVM1-NEXT:     Value: 0x200
# LLVM1-NEXT:     Size: 0
# LLVM1-NEXT:     Binding: Local (0x0)
# LLVM1-NEXT:     Type: Object (0x1)
# LLVM1-NEXT:     Other: 0
# STRIP-NEXT:     Section: <?> (0x2)
# NOSTRIP-NEXT:   Section: .data (0x2)
# LLVM1-NEXT:   }
# LLVM1-NEXT: ]

# GNU1-STRIP:   Symbol table for image contains 3 entries:
# GNU1-NOSTRIP: Symbol table '.dynsym' contains 3 entries:
# GNU1-NEXT:      Num:    Value        Size Type    Bind   Vis       Ndx Name
# GNU1-NEXT:        0: {{0*}}00000000     0 NOTYPE  LOCAL  DEFAULT   UND
# GNU1-NEXT:        1: {{0*}}00000100     0 FUNC    LOCAL  DEFAULT     1 foo
# GNU1-NEXT:        2: {{0*}}00000200     0 OBJECT  LOCAL  DEFAULT     2 bar
# GNU1-EMPTY:

--- !ELF
FileHeader:
  Class: ELFCLASS[[BITS]]
  Data:  ELFDATA2LSB
  Type:  ET_DYN
Sections:
  - Name:         .text
    Type:         SHT_PROGBITS
  - Name:         .data
    Type:         SHT_PROGBITS
  - Name:         .dynsym
    Type:         SHT_DYNSYM
    Flags:        [ SHF_ALLOC ]
    Address:      0x400
    AddressAlign: 0x400
  - Name:         .hash
    Type:         SHT_HASH
    Flags:        [ SHF_ALLOC ]
    Address:      0x600
    AddressAlign: 0x200
    Bucket:       [ 1 ]
    Chain:        [ 1, 2, 3 ]
  - Name:         .dynstr
    Type:         SHT_STRTAB
    Flags:        [ SHF_ALLOC ]
    Address:      0x800
    AddressAlign: 0x200
  - Name:         .dynamic
    Type:         SHT_DYNAMIC
    Flags:        [ SHF_ALLOC ]
    Address:      0xA00
    AddressAlign: 0x200
    Entries:
      - Tag:   DT_STRTAB
        Value: 0x800
      - Tag:   DT_STRSZ
        Value: 9
      - Tag:   [[TAG1]]
        Value: [[VAL1]]
      - Tag:   [[TAG2]]
        Value: [[VAL2]]
      - Tag:   DT_NULL
        Value: 0
DynamicSymbols:
  - Name:    foo
    Type:    STT_FUNC
    Section: .text
    Value:   0x100
  - Name:    bar
    Type:    STT_OBJECT
    Section: .data
    Value:   0x200
ProgramHeaders:
  - Type:     PT_LOAD
    VAddr:    0
    FirstSec: .text
    LastSec:  .data
  - Type:     PT_LOAD
    VAddr:    0x400
    FirstSec: .dynsym
    LastSec:  .dynamic
  - Type:     PT_DYNAMIC
    VAddr:    0xA00
    FirstSec: .dynamic
    LastSec:  .dynamic

## Case 2: Table size from DT_HASH does not match size from section header.
# RUN: yaml2obj --docnum=2 %s -o %t2-smaller -DCHAIN="[1, 2]"
# RUN: llvm-readobj --dyn-symbols %t2-smaller 2>&1 | \
# RUN:   FileCheck %s --check-prefixes=LLVM2,WARN \
# RUN:              --implicit-check-not=warning: -DNCHAIN=2
# RUN: llvm-readelf --dyn-symbols %t2-smaller 2>&1 | \
# RUN:   FileCheck %s --check-prefixes=GNU2,WARN \
# RUN:                --implicit-check-not=warning: -DNCHAIN=2

# RUN: yaml2obj --docnum=2 %s -o %t2-larger -DCHAIN="[1, 2, 3, 4]"
# RUN: llvm-readobj --dyn-symbols %t2-larger 2>&1 | \
# RUN:   FileCheck %s --check-prefixes=LLVM2,LLVM2-MORE,LLVM2-ALL,WARN \
# RUN:                --implicit-check-not=warning: -DNCHAIN=4
# RUN: llvm-readelf --dyn-symbols %t2-larger 2>&1 | \
# RUN:   FileCheck %s --check-prefixes=GNU2,GNU2-MORE,GNU2-ALL,WARN \
# RUN:                --implicit-check-not=warning: -DNCHAIN=4

# WARN: warning: '{{.*}}2-{{.*}}': hash table nchain ([[NCHAIN]]) differs from symbol count derived from SHT_DYNSYM section header (3)

## Show we report a warning when the sh_entsize of the SHT_DYNSYM section is zero and therefore we are unable
## to derive the number of dynamic symbols from SHT_DYNSYM section header.
# RUN: yaml2obj --docnum=2 %s -o %t2-zero-entsize -DCHAIN="[1, 2, 3, 4]" -DENTSIZE=0
# RUN: llvm-readobj --dyn-symbols %t2-zero-entsize 2>&1 | \
# RUN:   FileCheck %s -DFILE=%t2-zero-entsize --check-prefixes=LLVM2,LLVM2-MORE,LLVM2-ALL,WARN-ENTSIZE \
# RUN:                --implicit-check-not=warning:
# RUN: llvm-readelf --dyn-symbols %t2-zero-entsize 2>&1 | \
# RUN:   FileCheck %s -DFILE=%t2-zero-entsize --check-prefixes=GNU2,GNU2-MORE,GNU2-ALL,WARN-ENTSIZE \
# RUN:                --implicit-check-not=warning: -DNCHAIN=4

## WARN-ENTSIZE: warning: '[[FILE]]': SHT_DYNSYM section has sh_entsize == 0

## Show there's no warning if the sizes match
# RUN: yaml2obj --docnum=2 %s -o %t2-same -DCHAIN="[1, 2, 3]"
# RUN: llvm-readobj --dyn-symbols %t2-same 2>&1 | \
# RUN:   FileCheck %s --check-prefixes=LLVM2,LLVM2-MORE --implicit-check-not=warning:
# RUN: llvm-readelf --dyn-symbols %t2-same 2>&1 | \
# RUN:   FileCheck %s --check-prefixes=GNU2,GNU2-MORE \
# RUN:                --implicit-check-not=warning: -DNCHAIN=3

# LLVM2:           DynamicSymbols [
# LLVM2-NEXT:        Symbol {
# LLVM2-NEXT:          Name:  (0)
# LLVM2-NEXT:          Value: 0x0
# LLVM2-NEXT:          Size: 0
# LLVM2-NEXT:          Binding: Local (0x0)
# LLVM2-NEXT:          Type: None (0x0)
# LLVM2-NEXT:          Other: 0
# LLVM2-NEXT:          Section: Undefined (0x0)
# LLVM2-NEXT:        }
# LLVM2-NEXT:        Symbol {
# LLVM2-NEXT:          Name: foo (9)
# LLVM2-NEXT:          Value: 0x100
# LLVM2-NEXT:          Size: 0
# LLVM2-NEXT:          Binding: Local (0x0)
# LLVM2-NEXT:          Type: Function (0x2)
# LLVM2-NEXT:          Other: 0
# LLVM2-NEXT:          Section: .text (0x1)
# LLVM2-NEXT:        }
# LLVM2-MORE-NEXT:   Symbol {
# LLVM2-MORE-NEXT:     Name: bar (5)
# LLVM2-MORE-NEXT:     Value: 0x200
# LLVM2-MORE-NEXT:     Size: 0
# LLVM2-MORE-NEXT:     Binding: Local (0x0)
# LLVM2-MORE-NEXT:     Type: Object (0x1)
# LLVM2-MORE-NEXT:     Other: 0
# LLVM2-MORE-NEXT:     Section: .data (0x2)
# LLVM2-MORE-NEXT:   }
# LLVM2-ALL-NEXT:    Symbol {
# LLVM2-ALL-NEXT:      Name: baz (1)
# LLVM2-ALL-NEXT:      Value: 0x300
# LLVM2-ALL-NEXT:      Size: 0
# LLVM2-ALL-NEXT:      Binding: Local (0x0)
# LLVM2-ALL-NEXT:      Type: Object (0x1)
# LLVM2-ALL-NEXT:      Other: 0
# LLVM2-ALL-NEXT:      Section: .data (0x2)
# LLVM2-ALL-NEXT:    }
# LLVM2-NEXT:      ]

# GNU2:           Symbol table '.dynsym' contains [[NCHAIN]] entries:
# GNU2-NEXT:        Num:    Value        Size Type    Bind   Vis       Ndx Name
# GNU2-NEXT:          0: {{0*}}00000000     0 NOTYPE  LOCAL  DEFAULT   UND
# GNU2-NEXT:          1: {{0*}}00000100     0 FUNC    LOCAL  DEFAULT     1 foo
# GNU2-MORE-NEXT:     2: {{0*}}00000200     0 OBJECT  LOCAL  DEFAULT     2 bar
# GNU2-ALL-NEXT:      3: {{0*}}00000300     0 OBJECT  LOCAL  DEFAULT     2 baz
# GNU2-EMPTY:

## In this YAML, we define 4 dynamic symbols (including the null symbol), but
## constrain the .dynsym section header to say there are only 3. This means that
## when a size of 4 is derived from the hash table, we still have a valid symbol
## to dump.
--- !ELF
FileHeader:
  Class: ELFCLASS64
  Data:  ELFDATA2LSB
  Type:  ET_DYN
Sections:
  - Name:         .text
    Type:         SHT_PROGBITS
  - Name:         .data
    Type:         SHT_PROGBITS
  - Name:         .dynsym
    Type:         SHT_DYNSYM
    Flags:        [ SHF_ALLOC ]
    ShSize:       0x48
    Address:      0x400
    AddressAlign: 0x400
## 0x18 is the standard entsize value.
    EntSize:      [[ENTSIZE=0x18]]
  - Name:         .hash
    Type:         SHT_HASH
    Flags:        [ SHF_ALLOC ]
    Address:      0x600
    AddressAlign: 0x200
    Bucket:       [ 1 ]
    Chain:        [[CHAIN]]
  - Name:         .dynstr
    Type:         SHT_STRTAB
    Flags:        [ SHF_ALLOC ]
    Address:      0x800
    AddressAlign: 0x200
  - Name:         .dynamic
    Type:         SHT_DYNAMIC
    Flags:        [ SHF_ALLOC ]
    Address:      0xA00
    AddressAlign: 0x200
    Entries:
      - Tag:   DT_SYMTAB
        Value: 0x400
      - Tag:   DT_HASH
        Value: 0x600
      - Tag:   DT_STRTAB
        Value: 0x800
      - Tag:   DT_STRSZ
        Value: 13
      - Tag:   DT_NULL
        Value: 0
DynamicSymbols:
  - Name:    foo
    Type:    STT_FUNC
    Section: .text
    Value:   0x100
  - Name:    bar
    Type:    STT_OBJECT
    Section: .data
    Value:   0x200
  - Name:    baz
    Type:    STT_OBJECT
    Section: .data
    Value:   0x300
ProgramHeaders:
  - Type:     PT_LOAD
    VAddr:    0
    FirstSec: .text
    LastSec:  .data
  - Type:     PT_LOAD
    VAddr:    0x400
    FirstSec: .dynsym
    LastSec:  .dynamic
  - Type:     PT_DYNAMIC
    VAddr:    0xA00
    FirstSec: .dynamic
    LastSec:  .dynamic

## Case 3: DT_HASH is missing.
## Show that no warning occurs if there are section headers.
# RUN: yaml2obj --docnum=1 %s -o %t3 -DTAG1=DT_SYMTAB -DVAL1=0x400 -DTAG2=DT_NULL -DVAL2=0 -DBITS=64
# RUN: llvm-readobj --dyn-symbols %t3 2>&1 | \
# RUN:   FileCheck %s --check-prefixes=LLVM1,NOSTRIP --implicit-check-not=warning:
# RUN: llvm-readelf --dyn-symbols %t3 2>&1 | \
# RUN:   FileCheck %s --check-prefixes=GNU1,GNU1-NOSTRIP --implicit-check-not=warning:

## Show that size is treated as zero, if no section headers are present.
# RUN: llvm-strip --strip-sections %t3
# RUN: llvm-readobj --dyn-symbols %t3 2>&1 | \
# RUN:   FileCheck %s --check-prefix=LLVM3 --implicit-check-not=warning:
# RUN: llvm-readelf --dyn-symbols %t3 2>&1 | \
# RUN:   FileCheck %s --implicit-check-not={{.}} --allow-empty

# LLVM3: DynamicSymbols [
# LLVM3: ]

## Case 4: The size of the dynamic symbol table, inferred from the hash table, is broken.
##         It is so large that symbol table goes past the end of the file. We have a dynamic
##         relocation which refers to a symbol with an index that is also too large to be
##         in the file. Check we report a warning when trying to dump this relocation.

# RUN: yaml2obj --docnum=3 %s -o %t4.1

## Remember the size of the output produced.
# RUN: wc -c %t4.1 > %t4.out.gnu.txt
# RUN: llvm-readelf --sections --dyn-relocations %t4.1 >> %t4.out.gnu.txt 2>&1
# RUN: FileCheck %s -DFILE=%t4.1 --input-file=%t4.out.gnu.txt --check-prefix=BROKEN-NCHAIN-GNU

# BROKEN-NCHAIN-GNU: [[#%u, FILESIZE:]]
# BROKEN-NCHAIN-GNU: warning: '[[FILE]]': the size (0x17ffffffe8) of the dynamic symbol table at 0x[[#%x, DYNSYMOFF:]], derived from the hash table, goes past the end of the file (0x[[#%x, FILESIZE]]) and will be ignored

# BROKEN-NCHAIN-GNU: [Nr] Name      Type   Address          Off
# BROKEN-NCHAIN-GNU: [ 1] .rela.plt RELA   0000000000001000 0000[[#%x, RELAOFF:]]
# BROKEN-NCHAIN-GNU: [ 4] .dynsym   DYNSYM 0000000000001078 0000[[#%x, DYNSYMOFF]]

# BROKEN-NCHAIN-GNU:      'PLT' relocation section at offset 0x[[#%x, RELAOFF]] contains 24 bytes:
# BROKEN-NCHAIN-GNU-NEXT: Offset            Info             Type              Symbol's Value  Symbol's Name + Addend
# BROKEN-NCHAIN-GNU-NEXT: warning: '[[FILE]]': unable to get name of the dynamic symbol with index 4292739037: index is greater than or equal to the number of dynamic symbols (1)
# BROKEN-NCHAIN-GNU-NEXT: 0000000000000000  ffddffdd00000000 R_X86_64_NONE                     <corrupt> + 0

# RUN: wc -c %t4.1 > %t4.out.llvm.txt
# RUN: llvm-readobj --sections --dyn-relocations %t4.1 2>&1 >> %t4.out.llvm.txt 2>&1
# RUN: FileCheck %s -DFILE=%t4.1 --input-file=%t4.out.llvm.txt --check-prefix=BROKEN-NCHAIN-LLVM

# BROKEN-NCHAIN-LLVM: [[#%u, FILESIZE:]]
# BROKEN-NCHAIN-LLVM: warning: '[[FILE]]': the size (0x17ffffffe8) of the dynamic symbol table at 0x[[#%x, DYNSYMOFF:]], derived from the hash table, goes past the end of the file (0x[[#%x, FILESIZE]]) and will be ignored

# BROKEN-NCHAIN-LLVM:      Name: .dynsym
# BROKEN-NCHAIN-LLVM-NEXT: Type: SHT_DYNSYM
# BROKEN-NCHAIN-LLVM-NEXT: Flags [
# BROKEN-NCHAIN-LLVM-NEXT:   SHF_ALLOC
# BROKEN-NCHAIN-LLVM-NEXT: ]
# BROKEN-NCHAIN-LLVM-NEXT: Address: 0x1078
# BROKEN-NCHAIN-LLVM-NEXT: Offset: 0x[[#%X, DYNSYMOFF]]

# BROKEN-NCHAIN-LLVM:      Dynamic Relocations {
# BROKEN-NCHAIN-LLVM-NEXT: warning: '[[FILE]]': unable to get name of the dynamic symbol with index 4292739037: index is greater than or equal to the number of dynamic symbols (1)
# BROKEN-NCHAIN-LLVM-NEXT:   0x0 R_X86_64_NONE <corrupt> 0x0
# BROKEN-NCHAIN-LLVM-NEXT: }

--- !ELF
FileHeader:
  Class:   ELFCLASS64
  Data:    ELFDATA2LSB
  Type:    ET_EXEC
  Machine: EM_X86_64
Sections:
  - Name:    .rela.plt
    Type:    SHT_RELA
    Flags:   [ SHF_ALLOC ]
    Address: 0x1000
    Relocations:
      - Type:   R_X86_64_NONE
        Symbol: 0xFFDDFFDD
  - Name:  .dynamic
    Type:  SHT_DYNAMIC
    Flags: [ SHF_ALLOC ]
    Entries:
      - Tag:   DT_PLTRELSZ
        Value: 0x18
      - Tag:   DT_JMPREL
## 0x1000 - PT_LOAD's p_vaddr (0x1000) == 0x0.
## 0x0 + PT_LOAD's p_offset (0x78) == .rela.plt section offset (0x78).
        Value: 0x1000
      - Tag:   DT_PLTREL
        Value: 0x7 ## 7 == DT_RELA
      - Tag:   DT_HASH
## 0x1068 - PT_LOAD's p_vaddr (0x1000) == 0x68.
## 0x68 + PT_LOAD's p_offset (0x78) == .hash section offset (0xE0).
        Value: 0x1068
      - Tag:   DT_NULL
        Value: 0x0
  - Name:   .hash
    Type:   SHT_HASH
    Flags:  [ SHF_ALLOC ]
    Bucket: [ 0 ]
    Chain:  [ 0 ]
    NChain: 0xFFFFFFFF
DynamicSymbols: []
ProgramHeaders:
  - Type:     PT_LOAD
    FirstSec: .rela.plt
    LastSec:  .hash
    VAddr: 0x1000