diff --git a/llvm/test/tools/llvm-nm/dynamic.test b/llvm/test/tools/llvm-nm/dynamic.test --- a/llvm/test/tools/llvm-nm/dynamic.test +++ b/llvm/test/tools/llvm-nm/dynamic.test @@ -62,17 +62,26 @@ Size: 0 ## Check we print symbol versions, when they are available. - -# RUN: yaml2obj --docnum=4 %s -o %t4.o -# RUN: llvm-nm --dynamic %t4.o 2>&1 | \ -# RUN: FileCheck %s -DFILE=%t4.o --check-prefix=VERSIONED-SYMS - -# VERSIONED-SYMS: U globalversym -# VERSIONED-SYMS-NEXT: U localversym -# VERSIONED-SYMS-NEXT: U version2sym@v2 -# VERSIONED-SYMS-NEXT: U version3sym@v3hidden -# VERSIONED-SYMS-NEXT: U version4sym@v4 -# VERSIONED-SYMS-NEXT: U version5sym@v5hidden +## A default version is one that is contained in the version table (SHT_GNU_versym) +## and only available for defined symbols. Check we use the "@@" prefix to print it. + +# RUN: yaml2obj --docnum=4 %s -o %t4-undef.o +# RUN: llvm-nm --dynamic %t4-undef.o 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t4-undef.o -DTYPE=U \ +# RUN: --check-prefixes=VERSIONED-SYMS,VERSIONED-UNDEF-SYMS + +# RUN: yaml2obj --docnum=4 -DINDEX=0x1 %s -o %t4-def.o +# RUN: llvm-nm --dynamic %t4-def.o 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t4-def.o -DTYPE=r \ +# RUN: --check-prefixes=VERSIONED-SYMS,VERSIONED-DEF-SYMS + +# VERSIONED-SYMS: [[TYPE]] globalversym +# VERSIONED-SYMS-NEXT: [[TYPE]] localversym +# VERSIONED-UNDEF-SYMS-NEXT: [[TYPE]] version2sym@v2 +# VERSIONED-DEF-SYMS-NEXT: [[TYPE]] version2sym@@v2 +# VERSIONED-SYMS-NEXT: [[TYPE]] version3sym@v3hidden +# VERSIONED-SYMS-NEXT: [[TYPE]] version4sym@v4 +# VERSIONED-SYMS-NEXT: [[TYPE]] version5sym@v5hidden --- !ELF FileHeader: @@ -120,13 +129,22 @@ Hash: 0 Flags: 0 Other: 5 + - Name: .dynsym + Type: SHT_DYNSYM + EntSize: [[ENTSIZE=]] DynamicSymbols: - - Name: localversym - - Name: globalversym - - Name: version2sym - - Name: version3sym - - Name: version4sym - - Name: version5sym + - Name: localversym + Index: [[INDEX=]] + - Name: globalversym + Index: [[INDEX=]] + - Name: version2sym + Index: [[INDEX=]] + - Name: version3sym + Index: [[INDEX=]] + - Name: version4sym + Index: [[INDEX=]] + - Name: version5sym + Index: [[INDEX=]] ## In the following cases we check we report warnings when unable to read symbol version. ## Check that we still print unversioned symbol names. @@ -137,7 +155,7 @@ # RUN: yaml2obj --docnum=4 -DVERDEFOFFSET=0xffffffff %s -o %t4-broken-verdef.o # RUN: llvm-nm --dynamic %t4-broken-verdef.o 2>&1 | \ -# RUN: FileCheck %s -DFILE=%t4-broken-verdef.o --check-prefixes=VERSION-ERR,VERSION-ERR1 +# RUN: FileCheck %s --check-prefixes=VERSION-ERR,VERSION-ERR1 # VERSION-ERR1: warning: unable to read symbol versions: cannot read content of SHT_GNU_verdef section with index 2: section [index 2] has a sh_offset (0xffffffff) + sh_size (0x38) that is greater than the file size (0x438) # VERSION-ERR2: warning: unable to read symbol versions: unable to read an entry with index 1 from SHT_GNU_versym section with index 1: section [index 1] has an invalid sh_size (255) which is not a multiple of its sh_entsize (2) @@ -155,11 +173,21 @@ # RUN: yaml2obj --docnum=4 -DVERSYMSIZE=0xff %s -o %t4-broken-versym.o # RUN: llvm-nm --dynamic %t4-broken-versym.o 2>&1 | \ -# RUN: FileCheck %s -DFILE=%t4-broken-versym.o --check-prefixes=VERSION-ERR,VERSION-ERR2 +# RUN: FileCheck %s --check-prefixes=VERSION-ERR,VERSION-ERR2 -## Case 3: check we report a warning when we are unable to get a vesrion for a SHT_GNU_versym section entry. +## Case 3: check we report a warning when we are unable to get a version for a SHT_GNU_versym section entry. ## In this case the SHT_GNU_versym section refers to a version index 255 which is missing. # RUN: yaml2obj --docnum=4 -DVERSYMENTRY=0xff %s -o %t4-broken-index.o # RUN: llvm-nm --dynamic %t4-broken-index.o 2>&1 | \ -# RUN: FileCheck %s -DFILE=%t4-broken-index.o --check-prefixes=VERSION-ERR,VERSION-ERR3 +# RUN: FileCheck %s --check-prefixes=VERSION-ERR,VERSION-ERR3 + +## Case 4: check we report a warning when we are unable to get symbol flags. +## In this case the dynamic symbol table has a wrong sh_entsize and we can't read a symbol. + +# RUN: yaml2obj --docnum=4 -DENTSIZE=0xff %s -o %t4-broken-dynsym.o +# RUN: not llvm-nm --dynamic %t4-broken-dynsym.o 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t4-broken-dynsym.o --check-prefix=VERSION-ERR4 + +# VERSION-ERR4: warning: unable to read symbol versions: unable to read flags for symbol with index 1: section [index 4] has invalid sh_entsize: expected 24, but got 255 +# VERSION-ERR4: error: [[FILE]] section [index 4] has invalid sh_entsize: expected 24, but got 255 diff --git a/llvm/tools/llvm-nm/llvm-nm.cpp b/llvm/tools/llvm-nm/llvm-nm.cpp --- a/llvm/tools/llvm-nm/llvm-nm.cpp +++ b/llvm/tools/llvm-nm/llvm-nm.cpp @@ -1686,8 +1686,15 @@ } } +namespace { +struct SymbolVersion { + std::string Name; + bool IsDefault; +}; +}; // namespace + template -static Expected> +static Expected> readSymbolVersionsELF(const ELFFile &Obj, StringRef FileName, ELFObjectFileBase::elf_symbol_iterator_range Symbols) { using Elf_Shdr = typename ELFT::Shdr; @@ -1707,14 +1714,14 @@ } if (!SymVerSec) - return std::vector{}; + return std::vector{}; Expected, 0>> MapOrErr = Obj.loadVersionMap(SymVerNeedSec, SymVerDefSec); if (!MapOrErr) return MapOrErr.takeError(); - std::vector Ret; + std::vector Ret; size_t I = 0; for (auto It = Symbols.begin(), E = Symbols.end(); It != E; ++It) { ++I; @@ -1725,21 +1732,27 @@ " from " + describe(Obj, *SymVerSec) + ": " + toString(VerEntryOrErr.takeError())); + Expected FlagsOrErr = It->getFlags(); + if (!FlagsOrErr) + return createError("unable to read flags for symbol with index " + + Twine(I) + ": " + toString(FlagsOrErr.takeError())); + bool IsDefault; Expected VerOrErr = Obj.getSymbolVersionByIndex( - (*VerEntryOrErr)->vs_index, IsDefault, *MapOrErr, /*IsSymHidden=*/None); + (*VerEntryOrErr)->vs_index, IsDefault, *MapOrErr, + (*FlagsOrErr) & SymbolRef::SF_Undefined); if (!VerOrErr) return createError("unable to get a version for entry " + Twine(I) + " of " + describe(Obj, *SymVerSec) + ": " + toString(VerOrErr.takeError())); - Ret.push_back((*VerOrErr).str()); + Ret.push_back({(*VerOrErr).str(), IsDefault}); } return Ret; } -static Expected> +static Expected> readSymbolVersionsELF(const ELFObjectFileBase &Obj, ELFObjectFileBase::elf_symbol_iterator_range Symbols) { if (const auto *ELF = dyn_cast(&Obj)) @@ -1756,7 +1769,7 @@ StringRef ArchiveName = {}, StringRef ArchitectureName = {}) { auto Symbols = Obj.symbols(); - std::vector SymbolVersions; + std::vector SymbolVersions; if (DynamicSyms) { const auto *E = dyn_cast(&Obj); if (!E) { @@ -1765,7 +1778,7 @@ } Symbols = E->getDynamicSymbolIterators(); - if (Expected> VersionsOrErr = + if (Expected> VersionsOrErr = readSymbolVersionsELF(*E, Symbols)) SymbolVersions = std::move(*VersionsOrErr); else @@ -1827,8 +1840,9 @@ } else error(std::move(E), Obj.getFileName()); } - if (!SymbolVersions.empty() && !SymbolVersions[I].empty()) - S.Name += "@" + SymbolVersions[I]; + if (!SymbolVersions.empty() && !SymbolVersions[I].Name.empty()) + S.Name += + (SymbolVersions[I].IsDefault ? "@@" : "@") + SymbolVersions[I].Name; S.Sym = Sym; SymbolList.push_back(S);