diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h --- a/llvm/include/llvm/Object/ELFObjectFile.h +++ b/llvm/include/llvm/Object/ELFObjectFile.h @@ -1019,8 +1019,12 @@ template elf_symbol_iterator ELFObjectFile::dynamic_symbol_begin() const { - DataRefImpl Sym = toDRI(DotDynSymSec, 0); - return symbol_iterator(SymbolRef(Sym, this)); + if (!DotDynSymSec || DotDynSymSec->sh_size < sizeof(Elf_Sym)) + // Ignore errors here where the dynsym is empty or sh_size less than the + // size of one symbol. These should be handled elsewhere. + return symbol_iterator(SymbolRef(toDRI(DotDynSymSec, 0), this)); + // Skip 0-index NULL symbol. + return symbol_iterator(SymbolRef(toDRI(DotDynSymSec, 1), this)); } template diff --git a/llvm/test/tools/llvm-nm/dynamic.test b/llvm/test/tools/llvm-nm/dynamic.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-nm/dynamic.test @@ -0,0 +1,90 @@ +## This is a test for --dynamic/-D option. + +## Test llvm-nm dumping ELF file with valid .dynsym section. +# RUN: yaml2obj --docnum=1 %s -o %t1.o +# RUN: llvm-nm --dynamic %t1.o | \ +# RUN: FileCheck %s --match-full-lines --strict-whitespace --check-prefix DYNSYM +# RUN: llvm-nm -D %t1.o | \ +# RUN: FileCheck %s --match-full-lines --strict-whitespace --check-prefix DYNSYM + +# DYNSYM: U globalsym +# DYNSYM-NEXT: U localsym1 +# DYNSYM-NEXT:0000000000000000 n localsym2 +# DYNSYM-EMPTY: + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: section + Type: SHT_PROGBITS +DynamicSymbols: + - Name: localsym1 + Type: STT_OBJECT + - Name: localsym2 + Section: section + - Name: globalsym + Type: STT_OBJECT + Binding: STB_GLOBAL + +## Test llvm-nm dumping ELF file without .dynsym section. +# RUN: yaml2obj --docnum=2 %s -o %t2.o +# RUN: llvm-nm --dynamic %t2.o 2>&1 | \ +# RUN: FileCheck %s --match-full-lines --strict-whitespace -DFILE=%t2.o --check-prefix NO-SYMS + +# NO-SYMS:[[FILE]]: no symbols +# NO-SYMS-EMPTY: + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 + +## Test llvm-nm dumping ELF file with empty .dynsym section. +# RUN: yaml2obj --docnum=3 %s -o %t3.o +# RUN: llvm-nm --dynamic %t3.o 2>&1 | \ +# RUN: FileCheck %s --match-full-lines --strict-whitespace -DFILE=%t3.o --check-prefix NO-SYMS + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .dynsym + Type: SHT_DYNSYM + Size: 0 + +## Test llvm-nm dumping ELF file with malformed .dynsym section header +## whose sh_size doesn't match dynamic symbol entries (sh_size % sizeof(Elf_Sym) != 0). +## gnu-nm will dump as much symbol as (sh_size / sizeof(Elf_Sym) indicates. We are imitating this behavior. +# RU: yaml2obj --docnum=4 -DBITS=32 -DSIZE=33 %s -o %t4-32.o +# RU: llvm-nm --dynamic %t4-32.o 2>&1 | \ +# RU: FileCheck %s --match-full-lines --strict-whitespace -DFILE=%t4-32.o --check-prefix MALFORMED + +# RUN: yaml2obj --docnum=4 -DBITS=64 -DSIZE=49 %s -o %t4-64.o +# RUN: llvm-nm --dynamic %t4-64.o 2>&1 | \ +# RUN: FileCheck %s --match-full-lines --strict-whitespace -DFILE=%t4-64.o --check-prefix MALFORMED + +# MALFORMED: U a +# MALFORMED-EMPTY: + +--- !ELF +FileHeader: + Class: ELFCLASS[[BITS]] + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_386 +Sections: + - Name: .dynstr + Type: SHT_STRTAB + Content: "6100" # "a\0" + - Name: .dynsym + Type: SHT_DYNSYM + Size: [[SIZE]] # 33 for 32-bit, 49 for 64-bit (sizeof(Elf32_Sym) = 16, sizeof(Elf64_Sym) = 24).