1## Here we test the --elf-hash-histogram command line option. 2 3## This test case checks how we built histograms for hash sections. 4 5# RUN: yaml2obj --docnum=1 -D BITS=32 %s -o %t1-32.o 6# RUN: llvm-readelf --elf-hash-histogram %t1-32.o | FileCheck %s --check-prefix=HIST 7 8## Test --histogram and -I aliases. 9# RUN: llvm-readelf --histogram %t1-32.o | FileCheck %s --check-prefix=HIST 10# RUN: llvm-readelf -I %t1-32.o | FileCheck %s --check-prefix=HIST 11 12# RUN: yaml2obj --docnum=1 -D BITS=64 %s -o %t1-64.o 13# RUN: llvm-readelf --elf-hash-histogram %t1-64.o | FileCheck %s --check-prefix=HIST 14 15## Check that LLVM output has the expected format. 16# RUN: llvm-readobj --elf-hash-histogram %t1-32.o | FileCheck %s --check-prefix=LLVM-HIST 17# RUN: llvm-readobj --elf-hash-histogram %t1-64.o | FileCheck %s --check-prefix=LLVM-HIST 18 19# HIST: Histogram for bucket list length (total of 3 buckets) 20# HIST-NEXT: Length Number % of total Coverage 21# HIST-NEXT: 0 2 ( 66.7%) 0.0% 22# HIST-NEXT: 1 0 ( 0.0%) 0.0% 23# HIST-NEXT: 2 0 ( 0.0%) 0.0% 24# HIST-NEXT: 3 1 ( 33.3%) 100.0% 25# HIST-NEXT: Histogram for `.gnu.hash' bucket list length (total of 3 buckets) 26# HIST-NEXT: Length Number % of total Coverage 27# HIST-NEXT: 0 1 ( 33.3%) 0.0% 28# HIST-NEXT: 1 1 ( 33.3%) 25.0% 29# HIST-NEXT: 2 0 ( 0.0%) 25.0% 30# HIST-NEXT: 3 1 ( 33.3%) 100.0% 31# HIST-NOT: {{.}} 32 33# LLVM-HIST: HashHistogram { 34# LLVM-HIST-NEXT: TotalBuckets: 3 35# LLVM-HIST-NEXT: Chains [ 36# LLVM-HIST-NEXT: Chain { 37# LLVM-HIST-NEXT: Length: 0 38# LLVM-HIST-NEXT: Count: 2 39# LLVM-HIST-NEXT: Percentage: 66.7 40# LLVM-HIST-NEXT: Coverage: 0.0 41# LLVM-HIST-NEXT: } 42# LLVM-HIST-NEXT: Chain { 43# LLVM-HIST-NEXT: Length: 1 44# LLVM-HIST-NEXT: Count: 0 45# LLVM-HIST-NEXT: Percentage: 0.0 46# LLVM-HIST-NEXT: Coverage: 0.0 47# LLVM-HIST-NEXT: } 48# LLVM-HIST-NEXT: Chain { 49# LLVM-HIST-NEXT: Length: 2 50# LLVM-HIST-NEXT: Count: 0 51# LLVM-HIST-NEXT: Percentage: 0.0 52# LLVM-HIST-NEXT: Coverage: 0.0 53# LLVM-HIST-NEXT: } 54# LLVM-HIST-NEXT: Chain { 55# LLVM-HIST-NEXT: Length: 3 56# LLVM-HIST-NEXT: Count: 1 57# LLVM-HIST-NEXT: Percentage: 33.3 58# LLVM-HIST-NEXT: Coverage: 100.0 59# LLVM-HIST-NEXT: } 60# LLVM-HIST-NEXT: ] 61# LLVM-HIST-NEXT: } 62# LLVM-HIST-NEXT: GnuHashHistogram { 63# LLVM-HIST-NEXT: TotalBuckets: 3 64# LLVM-HIST-NEXT: Buckets [ 65# LLVM-HIST-NEXT: Bucket { 66# LLVM-HIST-NEXT: Length: 0 67# LLVM-HIST-NEXT: Count: 1 68# LLVM-HIST-NEXT: Percentage: 33.3 69# LLVM-HIST-NEXT: Coverage: 0.0 70# LLVM-HIST-NEXT: } 71# LLVM-HIST-NEXT: Bucket { 72# LLVM-HIST-NEXT: Length: 1 73# LLVM-HIST-NEXT: Count: 1 74# LLVM-HIST-NEXT: Percentage: 33.3 75# LLVM-HIST-NEXT: Coverage: 25.0 76# LLVM-HIST-NEXT: } 77# LLVM-HIST-NEXT: Bucket { 78# LLVM-HIST-NEXT: Length: 2 79# LLVM-HIST-NEXT: Count: 0 80# LLVM-HIST-NEXT: Percentage: 0.0 81# LLVM-HIST-NEXT: Coverage: 25.0 82# LLVM-HIST-NEXT: } 83# LLVM-HIST-NEXT: Bucket { 84# LLVM-HIST-NEXT: Length: 3 85# LLVM-HIST-NEXT: Count: 1 86# LLVM-HIST-NEXT: Percentage: 33.3 87# LLVM-HIST-NEXT: Coverage: 100.0 88# LLVM-HIST-NEXT: } 89# LLVM-HIST-NEXT: ] 90# LLVM-HIST-NEXT: } 91 92--- !ELF 93FileHeader: 94 Class: ELFCLASS[[BITS]] 95 Data: ELFDATA2LSB 96 Type: ET_DYN 97Sections: 98 - Name: .hash 99 Type: SHT_HASH 100 Flags: [ SHF_ALLOC ] 101 Bucket: [ 6, 4, 5 ] 102 Chain: [ 0, 0, 1, 0, 2 ] 103 - Name: .gnu.hash 104 Type: SHT_GNU_HASH 105 Flags: [ SHF_ALLOC ] 106 Header: 107 SymNdx: 0x1 108 Shift2: 0x0 109 BloomFilter: [ 0x0 ] 110 HashBuckets: [ 0x00000001, 0x00000004, 0x00000000 ] 111 HashValues: [ 0x0B887388, 0xECD54542, 0x7C92E3BB, 0x1C5871D9 ] 112 - Name: .dynamic 113 Type: SHT_DYNAMIC 114 Flags: [ SHF_WRITE, SHF_ALLOC ] 115 Entries: 116 - Tag: DT_HASH 117 Value: 0x0 118 - Tag: DT_GNU_HASH 119## sizeof(.hash) == 0x28. 120 Value: 0x28 121 - Tag: DT_NULL 122 Value: 0x0 123DynamicSymbols: 124 - Name: a 125 - Name: b 126 - Name: c 127 - Name: d 128ProgramHeaders: 129 - Type: PT_LOAD 130 FirstSec: .hash 131 LastSec: .dynamic 132 133## Show that we report a warning for a hash table which contains an entry of 134## the bucket array pointing to a cycle. 135 136# RUN: yaml2obj --docnum=2 %s -o %t2.o 137# RUN: llvm-readelf --elf-hash-histogram 2>&1 %t2.o | \ 138# RUN: FileCheck -DFILE=%t2.o %s --check-prefix=BROKEN --implicit-check-not=warning: 139 140# BROKEN: warning: '[[FILE]]': .hash section is invalid: bucket 1: a cycle was detected in the linked chain 141# BROKEN: Histogram for bucket list length (total of 2 buckets) 142# BROKEN-NEXT: Length Number % of total Coverage 143# BROKEN-NEXT: 0 0 ( 0.0%) 0.0% 144# BROKEN-NEXT: 1 2 (100.0%) 100.0% 145 146--- !ELF 147FileHeader: 148 Class: ELFCLASS32 149 Data: ELFDATA2LSB 150 Type: ET_REL 151Sections: 152 - Name: .hash 153 Type: SHT_HASH 154 Link: .dynsym 155 Bucket: [ 1, 1 ] 156 Chain: [ 0, 1 ] 157 - Name: .dynamic 158 Type: SHT_DYNAMIC 159 Flags: [ SHF_ALLOC ] 160 Entries: 161## llvm-readelf will read the hash table from the file offset 162## p_offset + (p_vaddr - DT_HASH) = p_offset + (0 - 0) = p_offset, 163## which is the start of PT_LOAD, i.e. the file offset of .hash. 164 - Tag: DT_HASH 165 Value: 0x0 166 - Tag: DT_NULL 167 Value: 0 168DynamicSymbols: 169 - Name: foo 170ProgramHeaders: 171 - Type: PT_LOAD 172 FirstSec: .hash 173 LastSec: .dynamic 174 175## Each SHT_HASH section starts with two 32-bit fields: nbucket and nchain. 176## Check we report an error when a DT_HASH value points to data that has size less than 8 bytes. 177 178# RUN: yaml2obj --docnum=3 %s -o %t3.o 179# RUN: llvm-readelf --elf-hash-histogram %t3.o 2>&1 | FileCheck %s --check-prefix=ERR1 -DFILE=%t3.o 180 181# ERR1: warning: '[[FILE]]': the hash table at offset 0x2b1 goes past the end of the file (0x2b8){{$}} 182 183--- !ELF 184FileHeader: 185 Class: ELFCLASS64 186 Data: ELFDATA2LSB 187 Type: ET_DYN 188Sections: 189 - Name: .hash 190 Type: SHT_HASH 191 Flags: [ SHF_ALLOC ] 192 Bucket: [ 0 ] 193 Chain: [ 0 ] 194 - Name: .dynamic 195 Type: SHT_DYNAMIC 196 Flags: [ SHF_WRITE, SHF_ALLOC ] 197 Entries: 198 - Tag: DT_HASH 199 Value: 0x239 200 - Tag: DT_NULL 201 Value: 0x0 202DynamicSymbols: [] 203ProgramHeaders: 204 - Type: PT_LOAD 205 FileSize: 0x23a 206 FirstSec: .hash 207 LastSec: .dynamic 208 209## Check we report a warning when the hash table goes past the end of the file. 210 211## Case A.1: the hash table ends right before the EOF. We have a broken nbucket 212## field that has a value larger than the number of buckets. 213# RUN: yaml2obj --docnum=4 %s -o %t4.1.o -DNBUCKET=0x5d -DNCHAIN=0x1 214# RUN: llvm-readelf --elf-hash-histogram %t4.1.o 2>&1 | \ 215# RUN: FileCheck %s --implicit-check-not={{.}} --allow-empty 216 217## Case A.2: the hash table ends 1 byte past the EOF. We have a broken nbucket 218## field that has a value larger than the number of buckets. 219# RUN: yaml2obj --docnum=4 %s -o %t4.2.o -DNBUCKET=0x5e -DNCHAIN=0x1 220# RUN: llvm-readelf --elf-hash-histogram %t4.2.o 2>&1 | \ 221# RUN: FileCheck %s --check-prefix=ERR2 -DFILE=%t4.2.o --implicit-check-not="warning:" 222# ERR2: warning: '[[FILE]]': the hash table at offset 0x54 goes past the end of the file (0x1d4), nbucket = 94, nchain = 1{{$}} 223 224## Case B.1: the hash table ends right before the EOF. We have a broken nchain 225## field that has a value larger than the number of chains. 226# RUN: yaml2obj --docnum=4 %s -o %t4.3.o -DNBUCKET=0x1 -DNCHAIN=0x5d 227# RUN: llvm-readelf --elf-hash-histogram %t4.3.o 2>&1 | \ 228# RUN: FileCheck %s --check-prefix=ERR3 -DFILE=%t4.3.o --implicit-check-not="warning:" 229# ERR3: warning: '[[FILE]]': hash table nchain (93) differs from symbol count derived from SHT_DYNSYM section header (1){{$}} 230# ERR3: 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 231 232## Case B.2: the hash table ends 1 byte past the EOF. We have a broken nchain 233## field that has a value larger than the number of chains. 234# RUN: yaml2obj --docnum=4 %s -o %t4.4.o -DNBUCKET=0x1 -DNCHAIN=0x5e 235# RUN: llvm-readelf --elf-hash-histogram %t4.4.o 2>&1 | \ 236# RUN: FileCheck %s --check-prefix=ERR4 -DFILE=%t4.4.o --implicit-check-not="warning:" 237# ERR4: warning: '[[FILE]]': hash table nchain (94) differs from symbol count derived from SHT_DYNSYM section header (1){{$}} 238# ERR4: 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 239# ERR4: warning: '[[FILE]]': the hash table at offset 0x54 goes past the end of the file (0x1d4), nbucket = 1, nchain = 94{{$}} 240 241--- !ELF 242FileHeader: 243 Class: ELFCLASS32 244 Data: ELFDATA2LSB 245 Type: ET_DYN 246Sections: 247 - Name: .hash 248 Type: SHT_HASH 249 Flags: [ SHF_ALLOC ] 250 Bucket: [ 0 ] 251 NBucket: [[NBUCKET]] 252 Chain: [ 0 ] 253 NChain: [[NCHAIN]] 254 - Name: .dynamic 255 Type: SHT_DYNAMIC 256 Flags: [ SHF_WRITE, SHF_ALLOC ] 257 Entries: 258 - Tag: DT_HASH 259 Value: 0x0 260 - Tag: DT_NULL 261 Value: 0x0 262DynamicSymbols: [] 263ProgramHeaders: 264 - Type: PT_LOAD 265 FirstSec: .hash 266 LastSec: .dynamic 267 268## Check we dump a histogram for the .gnu.hash table even when the .hash table is skipped. 269 270## Case A: the .hash table has no data to build histogram and it is skipped. 271# RUN: yaml2obj --docnum=5 %s -o %t5.o 272# RUN: llvm-readelf --elf-hash-histogram %t5.o 2>&1 | \ 273# RUN: FileCheck %s --check-prefix=GNU-HASH --implicit-check-not="Histogram" 274 275## Case B: the .hash table has a broken nbucket field. We report a warning 276## and skip dumping of the .hash table. 277# RUN: yaml2obj --docnum=5 -DNBUCKET=0xffffffff %s -o %t6.o 278# RUN: llvm-readelf --elf-hash-histogram %t6.o 2>&1 | \ 279# RUN: FileCheck %s -DFILE=%t6.o --check-prefixes=WARN,GNU-HASH 280 281# WARN: warning: '[[FILE]]': the hash table at offset 0x78 goes past the end of the file (0x358), nbucket = 4294967295, nchain = 2 282# GNU-HASH: Histogram for `.gnu.hash' bucket list length (total of 3 buckets) 283 284--- !ELF 285FileHeader: 286 Class: ELFCLASS64 287 Data: ELFDATA2LSB 288 Type: ET_DYN 289Sections: 290 - Name: .hash 291 Type: SHT_HASH 292 Flags: [ SHF_ALLOC ] 293 Bucket: [ 0 ] 294## 0x2 is a no-op: it does not change the number of buckets described by the "Bucket" key 295 NBucket: [[NBUCKET=0x2]] 296 Chain: [ 0, 0 ] 297 - Name: .gnu.hash 298 Type: SHT_GNU_HASH 299 Flags: [ SHF_ALLOC ] 300 Header: 301 SymNdx: 0x1 302 Shift2: 0x0 303 BloomFilter: [ 0x0 ] 304 HashBuckets: [ 0x00000001, 0x00000004, 0x00000000 ] 305 HashValues: [ 0x0B887388 ] 306 - Name: .dynamic 307 Type: SHT_DYNAMIC 308 Flags: [ SHF_WRITE, SHF_ALLOC ] 309 Entries: 310 - Tag: DT_HASH 311 Value: 0x0 312 - Tag: DT_GNU_HASH 313## sizeof(.hash) == 0x14. 314 Value: 0x14 315 - Tag: DT_NULL 316 Value: 0x0 317DynamicSymbols: 318 - Name: foo 319ProgramHeaders: 320 - Type: PT_LOAD 321 FirstSec: .hash 322 LastSec: .dynamic 323 324## Check we report a proper warning when the GNU hash table goes past the end of the file. 325 326## Case A: the 'maskwords' field is set so that the GNU hash table goes past the end of the file. 327# RUN: yaml2obj --docnum=6 -D MASKWORDS=0x80000000 %s -o %t7 328# RUN: llvm-readelf --elf-hash-histogram %t7 2>&1 | \ 329# RUN: FileCheck %s -DFILE=%t7 --check-prefix=ERR5 --implicit-check-not="Histogram" 330 331# ERR5: warning: '[[FILE]]': unable to dump the SHT_GNU_HASH section at 0x78: it goes past the end of the file 332 333## Case B: the 'nbuckets' field is set so that the GNU hash table goes past the end of the file. 334# RUN: yaml2obj --docnum=6 -D NBUCKETS=0x80000000 %s -o %t8 335# RUN: llvm-readelf --elf-hash-histogram %t8 2>&1 | \ 336# RUN: FileCheck %s -DFILE=%t8 --check-prefix=ERR5 --implicit-check-not="Histogram" 337 338--- !ELF 339FileHeader: 340 Class: ELFCLASS64 341 Data: ELFDATA2LSB 342 Type: ET_DYN 343Sections: 344 - Name: .gnu.hash 345 Type: SHT_GNU_HASH 346 Flags: [ SHF_ALLOC ] 347 Header: 348 SymNdx: 0x0 349 Shift2: 0x0 350## The number of words in the Bloom filter. The value of 1 is no-op. 351 MaskWords: [[MASKWORDS=1]] 352## The number of hash buckets. The value of 1 is no-op. 353 NBuckets: [[NBUCKETS=1]] 354 BloomFilter: [ 0x0 ] 355 HashBuckets: [ 0x0 ] 356 HashValues: [ 0x0 ] 357 - Name: .dynamic 358 Type: SHT_DYNAMIC 359 Flags: [ SHF_ALLOC ] 360 Link: .dynstr 361 Entries: 362 - Tag: DT_GNU_HASH 363 Value: 0x0 364 - Tag: DT_NULL 365 Value: 0x0 366DynamicSymbols: [] 367ProgramHeaders: 368 - Type: PT_LOAD 369 FirstSec: .gnu.hash 370 LastSec: .dynamic 371 372## Linkers might produce an empty no-op SHT_GNU_HASH section when 373## there are no dynamic symbols or when all dynamic symbols are undefined. 374## Such sections normally have a single zero entry in the bloom 375## filter, a single zero entry in the hash bucket and no values. 376## 377## The index of the first symbol in the dynamic symbol table 378## included in the hash table can be set to the number of dynamic symbols, 379## which is one larger than the index of the last dynamic symbol. 380## For empty tables however, this value is unimportant and can be ignored. 381 382## Check the case when a 'symndx' index of the first symbol in the dynamic symbol 383## table is larger than the number of dynamic symbols. 384 385## Case A: when the buckets array is not empty and has a non-zero value we report a warning. 386# RUN: yaml2obj --docnum=7 -DVAL=0x1 %s -o %t9 387# RUN: llvm-readelf --elf-hash-histogram %t9 2>&1 | \ 388# RUN: FileCheck %s -DFILE=%t9 --check-prefix=ERR6 389 390# ERR6: warning: '[[FILE]]': unable to print the GNU hash table histogram: the first hashed symbol index (16) is greater than or equal to the number of dynamic symbols (1) 391 392## Case B: we do not report a warning when the buckets array contains only zero values. 393# RUN: yaml2obj --docnum=7 -DVAL=0x0 %s -o %t10 394# RUN: llvm-readelf --elf-hash-histogram %t10 2>&1 | \ 395# RUN: FileCheck %s --allow-empty --implicit-check-not="Histogram" 396 397## Case C: we do not report a warning when the buckets array is empty. 398# RUN: yaml2obj --docnum=7 -DVAL="" %s -o %t11 399# RUN: llvm-readelf --elf-hash-histogram %t11 2>&1 | \ 400# RUN: FileCheck %s --allow-empty --implicit-check-not="Histogram" 401 402--- !ELF 403FileHeader: 404 Class: ELFCLASS64 405 Data: ELFDATA2LSB 406 Type: ET_DYN 407Sections: 408 - Name: .gnu.hash 409 Type: SHT_GNU_HASH 410 Flags: [ SHF_ALLOC ] 411 Header: 412 SymNdx: 0x10 413 Shift2: 0x0 414 BloomFilter: [ 0x0 ] 415 HashBuckets: [ [[VAL]] ] 416 HashValues: [ 0x0 ] 417 - Name: .dynamic 418 Type: SHT_DYNAMIC 419 Flags: [ SHF_ALLOC ] 420 Link: .dynstr 421 Entries: 422 - Tag: DT_GNU_HASH 423 Value: 0x0 424 - Tag: DT_NULL 425 Value: 0x0 426DynamicSymbols: [] 427ProgramHeaders: 428 - Type: PT_LOAD 429 FirstSec: .gnu.hash 430 LastSec: .dynamic 431 432## Check we report warnings when the dynamic symbol table is absent or empty. 433 434## The code locates the dynamic symbol table by the section type. Use SHT_PROGBITS to hide it. 435# RUN: yaml2obj --docnum=8 -DTYPE=SHT_PROGBITS %s -o %t12 436# RUN: llvm-readelf --elf-hash-histogram %t12 2>&1 | \ 437# RUN: FileCheck %s -DFILE=%t12 --check-prefix=ERR7 438 439# ERR7: warning: '[[FILE]]': unable to print the GNU hash table histogram: no dynamic symbol table found 440 441# RUN: yaml2obj --docnum=8 -DTYPE=SHT_DYNSYM %s -o %t13 442# RUN: llvm-readelf --elf-hash-histogram %t13 2>&1 | \ 443# RUN: FileCheck %s -DFILE=%t13 --check-prefix=ERR8 444 445# ERR8: warning: '[[FILE]]': unable to print the GNU hash table histogram: the dynamic symbol table is empty 446 447--- !ELF 448FileHeader: 449 Class: ELFCLASS64 450 Data: ELFDATA2LSB 451 Type: ET_DYN 452Sections: 453 - Name: .gnu.hash 454 Type: SHT_GNU_HASH 455 Flags: [ SHF_ALLOC ] 456 Header: 457 SymNdx: 0x0 458 Shift2: 0x0 459 BloomFilter: [ 0x0 ] 460 HashBuckets: [ 0x0 ] 461 HashValues: [ 0x0 ] 462 - Name: .dynamic 463 Type: SHT_DYNAMIC 464 Flags: [ SHF_ALLOC ] 465 Entries: 466 - Tag: DT_GNU_HASH 467 Value: 0x0 468 - Tag: DT_NULL 469 Value: 0x0 470 - Name: .dynsym 471 Type: [[TYPE]] 472 Size: 0 473ProgramHeaders: 474 - Type: PT_LOAD 475 FirstSec: .gnu.hash 476 LastSec: .gnu.hash 477