llvm/llvm/test/tools/llvm-readobj/ELF/hash-table.test

## Check how the SHT_HASH section is dumped with --hash-table.

# RUN: yaml2obj --docnum=1 -DBITS=64 -DMACHINE=EM_X86_64 %s -o %t.x64
# RUN: yaml2obj --docnum=1 -DBITS=32 -DMACHINE=EM_386 %s -o %t.x32

# RUN: llvm-readobj --hash-table %t.x64 | FileCheck %s --check-prefix=HASH
# RUN: llvm-readelf --hash-table %t.x64 | FileCheck %s --check-prefix=HASH

# RUN: llvm-readobj --hash-table %t.x32 | FileCheck %s --check-prefix=HASH
# RUN: llvm-readelf --hash-table %t.x32 | FileCheck %s --check-prefix=HASH

# HASH:      HashTable {
# HASH-NEXT:   Num Buckets: 2
# HASH-NEXT:   Num Chains: 3
# HASH-NEXT:   Buckets: [1, 2]
# HASH-NEXT:   Chains: [3, 4, 5]
# HASH-NEXT: }

--- !ELF
FileHeader:
  Class:   ELFCLASS[[BITS=64]]
  Data:    ELFDATA2LSB
  Type:    ET_DYN
  Machine: [[MACHINE]]
Sections:
  - Name:    .hash
    Type:    SHT_HASH
    Flags:   [ SHF_ALLOC ]
    Bucket:  [ 1, 2 ]
    Chain:   [ 3, 4, 5 ]
    EntSize: [[ENTSIZE=4]]
  - Name:  .dynamic
    Type:  SHT_DYNAMIC
    Flags: [ SHF_ALLOC ]
    Entries:
      - Tag:   DT_HASH
        Value: 0x0
      - Tag:   DT_NULL
        Value: 0x0
ProgramHeaders:
  - Type:     PT_LOAD
    FirstSec: .hash
    LastSec:  .dynamic

## Document that we ignore the sh_entsize value when dumping the hash section.
## Implementation assumes that the size of entries is 4, matching the ELF specification.

# RUN: yaml2obj --docnum=1 -DENTSIZE=8 -DBITS=64 -DMACHINE=EM_X86_64 %s -o %t.x64.ent8
# RUN: yaml2obj --docnum=1 -DENTSIZE=8 -DBITS=32 -DMACHINE=EM_386 %s -o %t.x32.ent8

# RUN: llvm-readobj --hash-table %t.x64.ent8 | FileCheck %s --check-prefix=HASH
# RUN: llvm-readelf --hash-table %t.x64.ent8 | FileCheck %s --check-prefix=HASH
# RUN: llvm-readobj --hash-table %t.x32.ent8 | FileCheck %s --check-prefix=HASH
# RUN: llvm-readelf --hash-table %t.x32.ent8 | FileCheck %s --check-prefix=HASH

## We don't support dumping hash tables on EM_S390 and EM_ALPHA platforms and report a warning.
## On these platforms the size of entries is 8, which violates the ELF specification, which says that the size
## of hash entries in the hash table must be 4.

# RUN: yaml2obj --docnum=1 -DMACHINE=EM_S390 %s -o %t.s390
# RUN: llvm-readobj --hash-table %t.s390 2>&1 | FileCheck %s -DFILE=%t.s390 --check-prefixes=WARN-HASH -DNAME="IBM S/390"
# RUN: llvm-readelf --hash-table %t.s390 2>&1 | FileCheck %s -DFILE=%t.s390 --check-prefixes=WARN-HASH -DNAME="IBM S/390"

# WARN-HASH:      HashTable {
# WARN-HASH-NEXT: warning: '[[FILE]]': the hash table at 0x78 is not supported: it contains non-standard 8 byte entries on [[NAME]] platform
# WARN-HASH-NEXT: }

# RUN: yaml2obj --docnum=1 -DMACHINE=EM_ALPHA %s -o %t.alpha
# RUN: llvm-readobj --hash-table %t.alpha 2>&1 | FileCheck %s -DFILE=%t.alpha --check-prefixes=WARN-HASH -DNAME="EM_ALPHA"
# RUN: llvm-readelf --hash-table %t.alpha 2>&1 | FileCheck %s -DFILE=%t.alpha --check-prefixes=WARN-HASH -DNAME="EM_ALPHA"

## We don't report warnings about the unsupported hash table on EM_S390 and EM_ALPHA platforms
## when --hash-table is not requested.

# RUN: llvm-readobj %t.s390 2>&1 | FileCheck %s -DFILE=%t.s390 --allow-empty --implicit-check-not="warning:"
# RUN: llvm-readelf %t.s390 2>&1 | FileCheck %s -DFILE=%t.s390 --allow-empty --implicit-check-not="warning:"
# RUN: llvm-readobj %t.alpha 2>&1 | FileCheck %s -DFILE=%t.alpha --allow-empty --implicit-check-not="warning:"
# RUN: llvm-readelf %t.alpha 2>&1 | FileCheck %s -DFILE=%t.alpha --allow-empty --implicit-check-not="warning:"

## Check we can dump the SHT_HASH section even when an object
## does not have the section header table.

# RUN: yaml2obj --docnum=2 -DNOHEADERS=true %s -o %t.noshdr
# RUN: llvm-readobj --hash-table %t.noshdr 2>&1 | \
# RUN:   FileCheck %s -DFILE=%t.noshdr --check-prefix=NOSHDR --implicit-check-not=warning:
# RUN: llvm-readelf --hash-table %t.noshdr 2>&1 | \
# RUN:   FileCheck %s -DFILE=%t.noshdr --check-prefix=NOSHDR --implicit-check-not=warning:

# NOSHDR:      HashTable {
# NOSHDR-NEXT:   Num Buckets: 1
# NOSHDR-NEXT:   Num Chains: 1
# NOSHDR-NEXT:   Buckets: [0]
# NOSHDR-NEXT:   Chains: [1]
# NOSHDR-NEXT: }

--- !ELF
FileHeader:
  Class: ELFCLASS64
  Data:  ELFDATA2LSB
  Type:  ET_DYN
Sections:
  - Name:   .hash
    Type:   SHT_HASH
    Flags:  [ SHF_ALLOC ]
    Bucket: [ 0 ]
    Chain:  [ 1 ]
    EntSize: [[ENTSIZE=4]]
  - Name:  .dynamic
    Type:  SHT_DYNAMIC
    Flags: [ SHF_ALLOC ]
    Entries:
      - Tag:   [[DYNTAG=DT_HASH]]
        Value: 0x0
      - Tag:   DT_NULL
        Value: 0x0
  - Type: SectionHeaderTable
    NoHeaders: [[NOHEADERS=false]]
ProgramHeaders:
  - Type:     PT_LOAD
    FirstSec: .hash
    LastSec:  .dynamic
  - Type:     PT_DYNAMIC
    VAddr:    0x10
    FirstSec: .dynamic
    LastSec:  .dynamic

## Document we don't report a warning when the value of the sh_entsize field of the SHT_HASH section is not 4.

# RUN: yaml2obj --docnum=2 -DENTSIZE=0xff %s -o %t.ent.size
# RUN: llvm-readobj --hash-table %t.ent.size 2>&1 | \
# RUN:   FileCheck %s -DFILE=%t.ent.size --check-prefix=NOSHDR --implicit-check-not=warning:
# RUN: llvm-readelf --hash-table %t.ent.size 2>&1 | \
# RUN:   FileCheck %s -DFILE=%t.ent.size --check-prefix=NOSHDR --implicit-check-not=warning:

## Document we need the DT_HASH dynamic tag to locate the hash table.

# RUN: yaml2obj --docnum=2 -DDYNTAG=DT_NULL %s -o %t.no.dyntag
# RUN: llvm-readobj --hash-table %t.no.dyntag 2>&1 | \
# RUN:   FileCheck %s -DFILE=%t.no.dyntag --check-prefix=NODYNTAG --implicit-check-not=warning:
# RUN: llvm-readelf --hash-table %t.no.dyntag 2>&1 | \
# RUN:   FileCheck %s -DFILE=%t.no.dyntag --check-prefix=NODYNTAG --implicit-check-not=warning:

# NODYNTAG:      HashTable {
# NODYNTAG-NEXT: }

## Each SHT_HASH section starts with two 32-bit fields: nbucket and nchain.
## Check we report an error when a DT_HASH value points to data that has size less than 8 bytes.

# RUN: yaml2obj --docnum=3 %s -o %t4.o
# RUN: llvm-readelf --hash-table %t4.o 2>&1 | FileCheck %s --check-prefix=ERR1 -DFILE=%t4.o
# RUN: llvm-readobj --hash-table %t4.o 2>&1 | FileCheck %s --check-prefix=ERR1 -DFILE=%t4.o

# ERR1:      HashTable {
# ERR1-NEXT:  warning: '[[FILE]]': the hash table at offset 0x2b1 goes past the end of the file (0x2b8){{$}}
# ERR1-NEXT: }

--- !ELF
FileHeader:
  Class: ELFCLASS64
  Data:  ELFDATA2LSB
  Type:  ET_DYN
Sections:
  - Name:   .hash
    Type:   SHT_HASH
    Flags:  [ SHF_ALLOC ]
    Bucket: [ 0 ]
    Chain:  [ 0 ]
  - Name:  .dynamic
    Type:  SHT_DYNAMIC
    Flags: [ SHF_WRITE, SHF_ALLOC ]
    Entries:
      - Tag:   DT_HASH
        Value: 0x239
      - Tag:   DT_NULL
        Value: 0x0
DynamicSymbols: []
ProgramHeaders:
  - Type:     PT_LOAD
    FileSize: 0x23a
    FirstSec: .hash
    LastSec:  .dynamic

## Check we report a warning when the hash table goes past the end of the file.

## Case A.1: the hash table ends right before the EOF. We have a broken nbucket
##           field that has a value larger than the number of buckets.
# RUN: yaml2obj --docnum=4 %s -o %t5.1.o -DNBUCKET=0x5d -DNCHAIN=0x1
# RUN: llvm-readelf --hash-table %t5.1.o 2>&1 | \
# RUN:   FileCheck %s --check-prefix=NOERR1 --implicit-check-not="warning:"
# RUN: llvm-readobj --hash-table %t5.1.o 2>&1 | \
# RUN:   FileCheck %s --check-prefix=NOERR1 --implicit-check-not="warning:"

# NOERR1:      HashTable {
# NOERR1-NEXT:  Num Buckets: 93
# NOERR1-NEXT:  Num Chains: 1
## Here we would dump the rest of the file as buckets array because we have a broken nbucket field.
## No need to check what we dump, we only want to test that we have no unexpected warnings/crashes.
# NOERR1-NEXT:  Buckets:
# NOERR1-NEXT:  Chains: [0]
# NOERR1-NEXT: }

## Case A.2: the hash table ends 1 byte past the EOF. We have a broken nbucket
##           field that has a value larger than the number of buckets.
# RUN: yaml2obj --docnum=4 %s -o %t5.2.o -DNBUCKET=0x5e -DNCHAIN=0x1
# RUN: llvm-readelf --hash-table %t5.2.o 2>&1 | \
# RUN:   FileCheck %s --check-prefix=ERR2 -DFILE=%t5.2.o --implicit-check-not="warning:"
# RUN: llvm-readobj --hash-table %t5.2.o 2>&1 | \
# RUN:   FileCheck %s --check-prefix=ERR2 -DFILE=%t5.2.o --implicit-check-not="warning:"

# ERR2:      HashTable {
# ERR2:       Num Buckets: 94
# ERR2:       Num Chains: 1
# ERR2-NEXT:  warning: '[[FILE]]': the hash table at offset 0x54 goes past the end of the file (0x1d4), nbucket = 94, nchain = 1{{$}}
# ERR2-NEXT: }

## Case B.1: the hash table ends right before the EOF. We have a broken nchain
##           field that has a value larger than the number of chains.
# RUN: yaml2obj --docnum=4 %s -o %t5.3.o -DNBUCKET=0x1 -DNCHAIN=0x5d
# RUN: llvm-readelf --hash-table %t5.3.o 2>&1 | \
# RUN:   FileCheck %s --check-prefix=NOERR2 -DFILE=%t5.3.o --implicit-check-not="warning:"
# RUN: llvm-readobj --hash-table %t5.3.o 2>&1 | \
# RUN:   FileCheck %s --check-prefix=NOERR2 -DFILE=%t5.3.o --implicit-check-not="warning:"

# NOERR2:      warning: '[[FILE]]': hash table nchain (93) differs from symbol count derived from SHT_DYNSYM section header (1)
# NOERR2:      warning: '[[FILE]]': the size (0x5d0) of the dynamic symbol table at 0x78, derived from the hash table, goes past the end of the file (0x1d4) and will be ignored
# NOERR2:      HashTable {
# NOERR2-NEXT:   Num Buckets: 1
# NOERR2-NEXT:   Num Chains: 93
# NOERR2-NEXT:   Buckets: [0]
## Here we would dump the rest of the file as chain array because we have a broken nchain field.
## No need to check what we dump, we only want to test that we have no unexpected warnings/crashes.
# NOERR2-NEXT:   Chains:
# NOERR2-NEXT: }

## Case B.2: the hash table ends 1 byte past the EOF. We have a broken nchain
##           field that has a value larger than the number of chains.
# RUN: yaml2obj --docnum=4 %s -o %t5.4.o -DNBUCKET=0x1 -DNCHAIN=0x5e
# RUN: llvm-readelf --hash-table %t5.4.o 2>&1 | \
# RUN:   FileCheck %s --check-prefix=ERR3 -DFILE=%t5.4.o --implicit-check-not="warning:"
# RUN: llvm-readobj --hash-table %t5.4.o 2>&1 | \
# RUN:   FileCheck %s --check-prefix=ERR3 -DFILE=%t5.4.o --implicit-check-not="warning:"

# ERR3:      warning: '[[FILE]]': hash table nchain (94) differs from symbol count derived from SHT_DYNSYM section header (1)
# ERR3:      warning: '[[FILE]]': the size (0x5e0) of the dynamic symbol table at 0x78, derived from the hash table, goes past the end of the file (0x1d4) and will be ignored
# ERR3:      HashTable {
# ERR3-NEXT:  Num Buckets: 1
# ERR3-NEXT:  Num Chains: 94
# ERR3-NEXT:  warning: '[[FILE]]': the hash table at offset 0x54 goes past the end of the file (0x1d4), nbucket = 1, nchain = 94{{$}}
# ERR3-NEXT: }

--- !ELF
FileHeader:
  Class: ELFCLASS32
  Data:  ELFDATA2LSB
  Type:  ET_DYN
Sections:
  - Name:    .hash
    Type:    SHT_HASH
    Flags:   [ SHF_ALLOC ]
    Bucket:  [ 0 ]
    NBucket: [[NBUCKET]]
    Chain:   [ 0 ]
    NChain:  [[NCHAIN]]
  - Name:  .dynamic
    Type:  SHT_DYNAMIC
    Flags: [ SHF_WRITE, SHF_ALLOC ]
    Entries:
      - Tag:   DT_HASH
        Value: 0x0
      - Tag:   DT_NULL
        Value: 0x0
DynamicSymbols: []
ProgramHeaders:
  - Type:     PT_LOAD
    FirstSec: .hash
    LastSec: .dynamic

## Show we do not duplicate warnings when printing both the hash table and the hash histogram.
## Note that --elf-hash-histogram is only implemented for llvm-readelf currently.
# RUN: yaml2obj --docnum=3 %s -o %t4.o
# RUN: llvm-readelf --hash-table --elf-hash-histogram %t4.o 2>&1 \
# RUN:   | FileCheck %s --check-prefix=SINGLE-WARN -DFILE=%t4.o --implicit-check-not="warning:"

# SINGLE-WARN:      warning: '[[FILE]]': hash table nchain (0) differs from symbol count derived from SHT_DYNSYM section header (1)
# SINGLE-WARN-NEXT: HashTable {
# SINGLE-WARN-NEXT: warning: '[[FILE]]': the hash table at offset 0x2b1 goes past the end of the file (0x2b8)
# SINGLE-WARN-NEXT: }