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,14 +1019,19 @@ 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 || + DotDynSymSec->sh_size % sizeof(Elf_Sym) != 0) + // We are ignoring errors that sh_size doesn't match symbol entries. + return symbol_iterator(SymbolRef(toDRI(DotDynSymSec, 0), this)); + else + // Skip 0-index NULL symbol. + return symbol_iterator(SymbolRef(toDRI(DotDynSymSec, 1), this)); } template elf_symbol_iterator ELFObjectFile::dynamic_symbol_end() const { const Elf_Shdr *SymTab = DotDynSymSec; - if (!SymTab) + if (!SymTab || SymTab->sh_size % sizeof(Elf_Sym) != 0) return dynamic_symbol_begin(); DataRefImpl Sym = toDRI(SymTab, SymTab->sh_size / sizeof(Elf_Sym)); return basic_symbol_iterator(SymbolRef(Sym, this)); diff --git a/llvm/test/tools/llvm-nm/dynamic-symbols.test b/llvm/test/tools/llvm-nm/dynamic-symbols.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-nm/dynamic-symbols.test @@ -0,0 +1,91 @@ +## Test llvm-nm dumping good ELF file with .dynsym section. +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: llvm-nm --debug-syms --dynamic %t1 | \ +# RUN: FileCheck %s --match-full-lines --strict-whitespace --check-prefix DYNSYM +# RUN: llvm-nm --debug-syms -D %t1 | \ +# 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 + Binding: STB_LOCAL + - Name: globalsym + Type: STT_OBJECT + Binding: STB_GLOBAL + - Name: localsym2 + Section: section + +## Test llvm-nm dumping ELF file without .dynsym section. +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: llvm-nm --debug-syms --dynamic %t2 2>&1 | \ +# RUN: FileCheck %s --match-full-lines --strict-whitespace --check-prefix NODYNSYM +# RUN: llvm-nm --debug-syms -D %t2 2>&1 | \ +# RUN: FileCheck %s --match-full-lines --strict-whitespace --check-prefix NODYNSYM + +# NODYNSYM:{{.*}}: no symbols +# NODYNSYM-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 +# RUN: llvm-nm --debug-syms --dynamic %t3 2>&1 | \ +# RUN: FileCheck %s --match-full-lines --strict-whitespace --check-prefix EMPTY +# RUN: llvm-nm --debug-syms -D %t3 2>&1 | \ +# RUN: FileCheck %s --match-full-lines --strict-whitespace --check-prefix EMPTY + +# EMPTY:{{.*}}: no symbols +# EMPTY-EMPTY: + +--- !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). +# RUN: yaml2obj --docnum=4 %s -o %t4 +# RUN: llvm-nm --debug-syms --dynamic %t4 2>&1 | \ +# RUN: FileCheck %s --match-full-lines --strict-whitespace --check-prefix MALFORMED +# RUN: llvm-nm --debug-syms -D %t4 2>&1 | \ +# RUN: FileCheck %s --match-full-lines --strict-whitespace --check-prefix MALFORMED + +# MALFORMED:{{.*}}: no symbols +# MALFORMED-EMPTY: + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .dynsym + Type: SHT_DYNSYM + Size: 25 # sizeof(Elf64_Sym) = 24 + Content: "0123"