[llvm-branch-commits] [llvm] dd5c982 - [llvm-nm][ELF] - Make -D display symbol versions.
Georgii Rymar via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Jan 21 00:28:50 PST 2021
Author: Georgii Rymar
Date: 2021-01-21T11:23:45+03:00
New Revision: dd5c98280473a7f74c5e5a715839e4938b46a69c
URL: https://github.com/llvm/llvm-project/commit/dd5c98280473a7f74c5e5a715839e4938b46a69c
DIFF: https://github.com/llvm/llvm-project/commit/dd5c98280473a7f74c5e5a715839e4938b46a69c.diff
LOG: [llvm-nm][ELF] - Make -D display symbol versions.
This fixes https://bugs.llvm.org/show_bug.cgi?id=48670.
Since binutils 2.35, nm -D displays symbol versions by default.
This patch teaches llvm-nm to do the same.
Differential revision: https://reviews.llvm.org/D94907
Added:
Modified:
llvm/test/tools/llvm-nm/dynamic.test
llvm/tools/llvm-nm/llvm-nm.cpp
Removed:
################################################################################
diff --git a/llvm/test/tools/llvm-nm/dynamic.test b/llvm/test/tools/llvm-nm/dynamic.test
index 7c7ec8241ec7..9d91aacb5717 100644
--- a/llvm/test/tools/llvm-nm/dynamic.test
+++ b/llvm/test/tools/llvm-nm/dynamic.test
@@ -60,3 +60,106 @@ Sections:
- Name: .dynsym
Type: SHT_DYNSYM
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 at v2
+# VERSIONED-SYMS-NEXT: U version3sym at v3hidden
+# VERSIONED-SYMS-NEXT: U version4sym at v4
+# VERSIONED-SYMS-NEXT: U version5sym at v5hidden
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_DYN
+Sections:
+ - Name: .gnu.version
+ Type: SHT_GNU_versym
+ Flags: [ SHF_ALLOC ]
+## 0x8000 is a special VERSYM_HIDDEN bit.
+ Entries: [ 0, 0, 1, [[VERSYMENTRY=2]], 0x8003, 4, 0x8005 ]
+ ShSize: [[VERSYMSIZE=<none>]]
+ - Name: .gnu.version_d
+ Type: SHT_GNU_verdef
+ Flags: [ SHF_ALLOC ]
+ Link: .dynstr
+ AddressAlign: 0x4
+ Info: 0x2
+ ShOffset: [[VERDEFOFFSET=<none>]]
+ Entries:
+ - VersionNdx: 2
+ Names:
+ - v2
+ - VersionNdx: 3
+ Names:
+ - v3hidden
+ - Name: .gnu.version_r
+ Type: SHT_GNU_verneed
+ Flags: [ SHF_ALLOC ]
+ Link: .dynstr
+ Info: 0x2
+ Dependencies:
+ - Version: 1
+ File: file1.so
+ Entries:
+ - Name: v4
+ Hash: 0
+ Flags: 0
+ Other: 4
+ - Version: 1
+ File: file2.0
+ Entries:
+ - Name: v5hidden
+ Hash: 0
+ Flags: 0
+ Other: 5
+DynamicSymbols:
+ - Name: localversym
+ - Name: globalversym
+ - Name: version2sym
+ - Name: version3sym
+ - Name: version4sym
+ - Name: version5sym
+
+## In the following cases we check we report warnings when unable to read symbol version.
+## Check that we still print unversioned symbol names.
+
+## Case 1: check we report a warning when unable to read symbol versions
+## from a broken SHT_GNU_verdef section. In this case its sh_offset
+## field has a too large value that goes past the EOF.
+
+# 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
+
+# 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)
+# VERSION-ERR3: warning: unable to read symbol versions: unable to get a version for entry 3 of SHT_GNU_versym section with index 1: SHT_GNU_versym section refers to a version index 255 which is missing
+
+# VERSION-ERR-NEXT: U globalversym{{$}}
+# VERSION-ERR-NEXT: U localversym{{$}}
+# VERSION-ERR-NEXT: U version2sym{{$}}
+# VERSION-ERR-NEXT: U version3sym{{$}}
+# VERSION-ERR-NEXT: U version4sym{{$}}
+# VERSION-ERR-NEXT: U version5sym{{$}}
+
+## Case 2: check we report a warning when we are unable to read a SHT_GNU_versym section entry.
+## In this case, the section has a size that is not a multiple of its sh_entsize.
+
+# 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
+
+## Case 3: check we report a warning when we are unable to get a vesrion 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
diff --git a/llvm/tools/llvm-nm/llvm-nm.cpp b/llvm/tools/llvm-nm/llvm-nm.cpp
index ccb54c3576fe..117538a08ed2 100644
--- a/llvm/tools/llvm-nm/llvm-nm.cpp
+++ b/llvm/tools/llvm-nm/llvm-nm.cpp
@@ -1686,10 +1686,77 @@ static void dumpSymbolsFromDLInfoMachO(MachOObjectFile &MachO) {
}
}
+template <class ELFT>
+static Expected<std::vector<std::string>>
+readSymbolVersionsELF(const ELFFile<ELFT> &Obj, StringRef FileName,
+ ELFObjectFileBase::elf_symbol_iterator_range Symbols) {
+ using Elf_Shdr = typename ELFT::Shdr;
+
+ // We called sections() earlier, so can't fail here.
+ typename ELFT::ShdrRange SectionsOrErr = cantFail(Obj.sections());
+ const Elf_Shdr *SymVerSec = nullptr;
+ const Elf_Shdr *SymVerNeedSec = nullptr;
+ const Elf_Shdr *SymVerDefSec = nullptr;
+ for (const Elf_Shdr &Sec : SectionsOrErr) {
+ if (Sec.sh_type == ELF::SHT_GNU_versym)
+ SymVerSec = &Sec;
+ else if (Sec.sh_type == ELF::SHT_GNU_verdef)
+ SymVerDefSec = &Sec;
+ else if (Sec.sh_type == ELF::SHT_GNU_verneed)
+ SymVerNeedSec = &Sec;
+ }
+
+ if (!SymVerSec)
+ return std::vector<std::string>{};
+
+ Expected<SmallVector<Optional<VersionEntry>, 0>> MapOrErr =
+ Obj.loadVersionMap(SymVerNeedSec, SymVerDefSec);
+ if (!MapOrErr)
+ return MapOrErr.takeError();
+
+ std::vector<std::string> Ret;
+ size_t I = 0;
+ for (auto It = Symbols.begin(), E = Symbols.end(); It != E; ++It) {
+ ++I;
+ Expected<const typename ELFT::Versym *> VerEntryOrErr =
+ Obj.template getEntry<typename ELFT::Versym>(*SymVerSec, I);
+ if (!VerEntryOrErr)
+ return createError("unable to read an entry with index " + Twine(I) +
+ " from " + describe(Obj, *SymVerSec) + ": " +
+ toString(VerEntryOrErr.takeError()));
+
+ bool IsDefault;
+ Expected<StringRef> VerOrErr = Obj.getSymbolVersionByIndex(
+ (*VerEntryOrErr)->vs_index, IsDefault, *MapOrErr);
+ 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());
+ }
+
+ return Ret;
+}
+
+static Expected<std::vector<std::string>>
+readSymbolVersionsELF(const ELFObjectFileBase &Obj,
+ ELFObjectFileBase::elf_symbol_iterator_range Symbols) {
+ if (const auto *ELF = dyn_cast<ELF32LEObjectFile>(&Obj))
+ return readSymbolVersionsELF(ELF->getELFFile(), Obj.getFileName(), Symbols);
+ else if (const auto *ELF = dyn_cast<ELF32BEObjectFile>(&Obj))
+ return readSymbolVersionsELF(ELF->getELFFile(), Obj.getFileName(), Symbols);
+ else if (const auto *ELF = dyn_cast<ELF64LEObjectFile>(&Obj))
+ return readSymbolVersionsELF(ELF->getELFFile(), Obj.getFileName(), Symbols);
+ return readSymbolVersionsELF(cast<ELF64BEObjectFile>(&Obj)->getELFFile(),
+ Obj.getFileName(), Symbols);
+}
+
static void dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
StringRef ArchiveName = {},
StringRef ArchitectureName = {}) {
auto Symbols = Obj.symbols();
+ std::vector<std::string> SymbolVersions;
if (DynamicSyms) {
const auto *E = dyn_cast<ELFObjectFileBase>(&Obj);
if (!E) {
@@ -1697,6 +1764,14 @@ static void dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
return;
}
Symbols = E->getDynamicSymbolIterators();
+
+ if (Expected<std::vector<std::string>> VersionsOrErr =
+ readSymbolVersionsELF(*E, Symbols))
+ SymbolVersions = std::move(*VersionsOrErr);
+ else
+ WithColor::warning(errs(), ToolName)
+ << "unable to read symbol versions: "
+ << toString(VersionsOrErr.takeError()) << "\n";
}
// If a "-s segname sectname" option was specified and this is a Mach-O
@@ -1710,7 +1785,9 @@ static void dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
return;
}
if (!(MachO && DyldInfoOnly)) {
+ size_t I = -1;
for (BasicSymbolRef Sym : Symbols) {
+ ++I;
Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
if (!SymFlagsOrErr) {
error(SymFlagsOrErr.takeError(), Obj.getFileName());
@@ -1750,6 +1827,9 @@ static void dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
} else
error(std::move(E), Obj.getFileName());
}
+ if (!SymbolVersions.empty() && !SymbolVersions[I].empty())
+ S.Name += "@" + SymbolVersions[I];
+
S.Sym = Sym;
SymbolList.push_back(S);
}
More information about the llvm-branch-commits
mailing list