1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 10:42:39 +01:00

[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
This commit is contained in:
Georgii Rymar 2021-01-14 16:20:35 +03:00
parent 90681ff5c1
commit e9ef9e434c
2 changed files with 183 additions and 0 deletions

View File

@ -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@v2
# VERSIONED-SYMS-NEXT: U version3sym@v3hidden
# VERSIONED-SYMS-NEXT: U version4sym@v4
# VERSIONED-SYMS-NEXT: U version5sym@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

View File

@ -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);
}