[Object, llvm-readelf] - Move the API for retrieving symbol versions to ELF.h

`ELFDumper.cpp` implements the functionality that allows to get symbol versions.
It is used for dumping versioned symbols.

This helps to implement https://bugs.llvm.org/show_bug.cgi?id=48670 ("make llvm-nm -D print version names"):
we can move out and reuse the code from `ELFDumper.cpp`.
This is what this patch do: it moves the related functionality to `ELFFile<ELFT>`.

Differential revision: https://reviews.llvm.org/D94771
This commit is contained in:
Georgii Rymar 2021-01-15 14:21:00 +03:00
parent f446fc5acf
commit b9ce772b8f
4 changed files with 371 additions and 316 deletions

View File

@ -30,6 +30,43 @@
namespace llvm {
namespace object {
struct VerdAux {
unsigned Offset;
std::string Name;
};
struct VerDef {
unsigned Offset;
unsigned Version;
unsigned Flags;
unsigned Ndx;
unsigned Cnt;
unsigned Hash;
std::string Name;
std::vector<VerdAux> AuxV;
};
struct VernAux {
unsigned Hash;
unsigned Flags;
unsigned Other;
unsigned Offset;
std::string Name;
};
struct VerNeed {
unsigned Version;
unsigned Cnt;
unsigned Offset;
std::string File;
std::vector<VernAux> AuxV;
};
struct VersionEntry {
std::string Name;
bool IsVerDef;
};
StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type);
uint32_t getELFRelativeRelocationType(uint32_t Machine);
StringRef getELFSectionTypeName(uint32_t Machine, uint32_t Type);
@ -101,6 +138,16 @@ std::string getSecIndexForError(const ELFFile<ELFT> &Obj,
return "[unknown index]";
}
template <class ELFT>
static std::string describe(const ELFFile<ELFT> &Obj,
const typename ELFT::Shdr &Sec) {
unsigned SecNdx = &Sec - &cantFail(Obj.sections()).front();
return (object::getELFSectionTypeName(Obj.getHeader().e_machine,
Sec.sh_type) +
" section with index " + Twine(SecNdx))
.str();
}
template <class ELFT>
std::string getPhdrIndexForError(const ELFFile<ELFT> &Obj,
const typename ELFT::Phdr &Phdr) {
@ -148,12 +195,22 @@ public:
template <typename T>
Expected<const T *> getEntry(const Elf_Shdr &Section, uint32_t Entry) const;
Expected<std::vector<VerDef>>
getVersionDefinitions(const Elf_Shdr &Sec) const;
Expected<std::vector<VerNeed>> getVersionDependencies(
const Elf_Shdr &Sec,
WarningHandler WarnHandler = &defaultWarningHandler) const;
Expected<StringRef> getSymbolVersionByIndex(
uint32_t SymbolVersionIndex, bool &IsDefault,
SmallVector<Optional<VersionEntry>, 0> &VersionMap) const;
Expected<StringRef>
getStringTable(const Elf_Shdr &Section,
WarningHandler WarnHandler = &defaultWarningHandler) const;
Expected<StringRef> getStringTableForSymtab(const Elf_Shdr &Section) const;
Expected<StringRef> getStringTableForSymtab(const Elf_Shdr &Section,
Elf_Shdr_Range Sections) const;
Expected<StringRef> getLinkAsStrtab(const typename ELFT::Shdr &Sec) const;
Expected<ArrayRef<Elf_Word>> getSHNDXTable(const Elf_Shdr &Section) const;
Expected<ArrayRef<Elf_Word>> getSHNDXTable(const Elf_Shdr &Section,
@ -171,6 +228,9 @@ public:
Expected<const Elf_Sym *> getRelocationSymbol(const Elf_Rel &Rel,
const Elf_Shdr *SymTab) const;
Expected<SmallVector<Optional<VersionEntry>, 0>>
loadVersionMap(const Elf_Shdr *VerNeedSec, const Elf_Shdr *VerDefSec) const;
static Expected<ELFFile> create(StringRef Object);
bool isLE() const {
@ -518,6 +578,43 @@ uint32_t ELFFile<ELFT>::getRelativeRelocationType() const {
return getELFRelativeRelocationType(getHeader().e_machine);
}
template <class ELFT>
Expected<SmallVector<Optional<VersionEntry>, 0>>
ELFFile<ELFT>::loadVersionMap(const Elf_Shdr *VerNeedSec,
const Elf_Shdr *VerDefSec) const {
SmallVector<Optional<VersionEntry>, 0> VersionMap;
// The first two version indexes are reserved.
// Index 0 is VER_NDX_LOCAL, index 1 is VER_NDX_GLOBAL.
VersionMap.push_back(VersionEntry());
VersionMap.push_back(VersionEntry());
auto InsertEntry = [&](unsigned N, StringRef Version, bool IsVerdef) {
if (N >= VersionMap.size())
VersionMap.resize(N + 1);
VersionMap[N] = {std::string(Version), IsVerdef};
};
if (VerDefSec) {
Expected<std::vector<VerDef>> Defs = getVersionDefinitions(*VerDefSec);
if (!Defs)
return Defs.takeError();
for (const VerDef &Def : *Defs)
InsertEntry(Def.Ndx & ELF::VERSYM_VERSION, Def.Name, true);
}
if (VerNeedSec) {
Expected<std::vector<VerNeed>> Deps = getVersionDependencies(*VerNeedSec);
if (!Deps)
return Deps.takeError();
for (const VerNeed &Dep : *Deps)
for (const VernAux &Aux : Dep.AuxV)
InsertEntry(Aux.Other & ELF::VERSYM_VERSION, Aux.Name, false);
}
return VersionMap;
}
template <class ELFT>
Expected<const typename ELFT::Sym *>
ELFFile<ELFT>::getRelocationSymbol(const Elf_Rel &Rel,
@ -641,6 +738,207 @@ Expected<const T *> ELFFile<ELFT>::getEntry(const Elf_Shdr &Section,
return &Arr[Entry];
}
template <typename ELFT>
Expected<StringRef> ELFFile<ELFT>::getSymbolVersionByIndex(
uint32_t SymbolVersionIndex, bool &IsDefault,
SmallVector<Optional<VersionEntry>, 0> &VersionMap) const {
size_t VersionIndex = SymbolVersionIndex & llvm::ELF::VERSYM_VERSION;
// Special markers for unversioned symbols.
if (VersionIndex == llvm::ELF::VER_NDX_LOCAL ||
VersionIndex == llvm::ELF::VER_NDX_GLOBAL) {
IsDefault = false;
return "";
}
// Lookup this symbol in the version table.
if (VersionIndex >= VersionMap.size() || !VersionMap[VersionIndex])
return createError("SHT_GNU_versym section refers to a version index " +
Twine(VersionIndex) + " which is missing");
const VersionEntry &Entry = *VersionMap[VersionIndex];
if (Entry.IsVerDef)
IsDefault = !(SymbolVersionIndex & llvm::ELF::VERSYM_HIDDEN);
else
IsDefault = false;
return Entry.Name.c_str();
}
template <class ELFT>
Expected<std::vector<VerDef>>
ELFFile<ELFT>::getVersionDefinitions(const Elf_Shdr &Sec) const {
Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Sec);
if (!StrTabOrErr)
return StrTabOrErr.takeError();
Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec);
if (!ContentsOrErr)
return createError("cannot read content of " + describe(*this, Sec) + ": " +
toString(ContentsOrErr.takeError()));
const uint8_t *Start = ContentsOrErr->data();
const uint8_t *End = Start + ContentsOrErr->size();
auto ExtractNextAux = [&](const uint8_t *&VerdauxBuf,
unsigned VerDefNdx) -> Expected<VerdAux> {
if (VerdauxBuf + sizeof(Elf_Verdaux) > End)
return createError("invalid " + describe(*this, Sec) +
": version definition " + Twine(VerDefNdx) +
" refers to an auxiliary entry that goes past the end "
"of the section");
auto *Verdaux = reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf);
VerdauxBuf += Verdaux->vda_next;
VerdAux Aux;
Aux.Offset = VerdauxBuf - Start;
if (Verdaux->vda_name <= StrTabOrErr->size())
Aux.Name = std::string(StrTabOrErr->drop_front(Verdaux->vda_name));
else
Aux.Name = ("<invalid vda_name: " + Twine(Verdaux->vda_name) + ">").str();
return Aux;
};
std::vector<VerDef> Ret;
const uint8_t *VerdefBuf = Start;
for (unsigned I = 1; I <= /*VerDefsNum=*/Sec.sh_info; ++I) {
if (VerdefBuf + sizeof(Elf_Verdef) > End)
return createError("invalid " + describe(*this, Sec) +
": version definition " + Twine(I) +
" goes past the end of the section");
if (reinterpret_cast<uintptr_t>(VerdefBuf) % sizeof(uint32_t) != 0)
return createError(
"invalid " + describe(*this, Sec) +
": found a misaligned version definition entry at offset 0x" +
Twine::utohexstr(VerdefBuf - Start));
unsigned Version = *reinterpret_cast<const Elf_Half *>(VerdefBuf);
if (Version != 1)
return createError("unable to dump " + describe(*this, Sec) +
": version " + Twine(Version) +
" is not yet supported");
const Elf_Verdef *D = reinterpret_cast<const Elf_Verdef *>(VerdefBuf);
VerDef &VD = *Ret.emplace(Ret.end());
VD.Offset = VerdefBuf - Start;
VD.Version = D->vd_version;
VD.Flags = D->vd_flags;
VD.Ndx = D->vd_ndx;
VD.Cnt = D->vd_cnt;
VD.Hash = D->vd_hash;
const uint8_t *VerdauxBuf = VerdefBuf + D->vd_aux;
for (unsigned J = 0; J < D->vd_cnt; ++J) {
if (reinterpret_cast<uintptr_t>(VerdauxBuf) % sizeof(uint32_t) != 0)
return createError("invalid " + describe(*this, Sec) +
": found a misaligned auxiliary entry at offset 0x" +
Twine::utohexstr(VerdauxBuf - Start));
Expected<VerdAux> AuxOrErr = ExtractNextAux(VerdauxBuf, I);
if (!AuxOrErr)
return AuxOrErr.takeError();
if (J == 0)
VD.Name = AuxOrErr->Name;
else
VD.AuxV.push_back(*AuxOrErr);
}
VerdefBuf += D->vd_next;
}
return Ret;
}
template <class ELFT>
Expected<std::vector<VerNeed>>
ELFFile<ELFT>::getVersionDependencies(const Elf_Shdr &Sec,
WarningHandler WarnHandler) const {
StringRef StrTab;
Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Sec);
if (!StrTabOrErr) {
if (Error E = WarnHandler(toString(StrTabOrErr.takeError())))
return std::move(E);
} else {
StrTab = *StrTabOrErr;
}
Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec);
if (!ContentsOrErr)
return createError("cannot read content of " + describe(*this, Sec) + ": " +
toString(ContentsOrErr.takeError()));
const uint8_t *Start = ContentsOrErr->data();
const uint8_t *End = Start + ContentsOrErr->size();
const uint8_t *VerneedBuf = Start;
std::vector<VerNeed> Ret;
for (unsigned I = 1; I <= /*VerneedNum=*/Sec.sh_info; ++I) {
if (VerneedBuf + sizeof(Elf_Verdef) > End)
return createError("invalid " + describe(*this, Sec) +
": version dependency " + Twine(I) +
" goes past the end of the section");
if (reinterpret_cast<uintptr_t>(VerneedBuf) % sizeof(uint32_t) != 0)
return createError(
"invalid " + describe(*this, Sec) +
": found a misaligned version dependency entry at offset 0x" +
Twine::utohexstr(VerneedBuf - Start));
unsigned Version = *reinterpret_cast<const Elf_Half *>(VerneedBuf);
if (Version != 1)
return createError("unable to dump " + describe(*this, Sec) +
": version " + Twine(Version) +
" is not yet supported");
const Elf_Verneed *Verneed =
reinterpret_cast<const Elf_Verneed *>(VerneedBuf);
VerNeed &VN = *Ret.emplace(Ret.end());
VN.Version = Verneed->vn_version;
VN.Cnt = Verneed->vn_cnt;
VN.Offset = VerneedBuf - Start;
if (Verneed->vn_file < StrTab.size())
VN.File = std::string(StrTab.drop_front(Verneed->vn_file));
else
VN.File = ("<corrupt vn_file: " + Twine(Verneed->vn_file) + ">").str();
const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux;
for (unsigned J = 0; J < Verneed->vn_cnt; ++J) {
if (reinterpret_cast<uintptr_t>(VernauxBuf) % sizeof(uint32_t) != 0)
return createError("invalid " + describe(*this, Sec) +
": found a misaligned auxiliary entry at offset 0x" +
Twine::utohexstr(VernauxBuf - Start));
if (VernauxBuf + sizeof(Elf_Vernaux) > End)
return createError(
"invalid " + describe(*this, Sec) + ": version dependency " +
Twine(I) +
" refers to an auxiliary entry that goes past the end "
"of the section");
const Elf_Vernaux *Vernaux =
reinterpret_cast<const Elf_Vernaux *>(VernauxBuf);
VernAux &Aux = *VN.AuxV.emplace(VN.AuxV.end());
Aux.Hash = Vernaux->vna_hash;
Aux.Flags = Vernaux->vna_flags;
Aux.Other = Vernaux->vna_other;
Aux.Offset = VernauxBuf - Start;
if (StrTab.size() <= Vernaux->vna_name)
Aux.Name = "<corrupt>";
else
Aux.Name = std::string(StrTab.drop_front(Vernaux->vna_name));
VernauxBuf += Vernaux->vna_next;
}
VerneedBuf += Verneed->vn_next;
}
return Ret;
}
template <class ELFT>
Expected<const typename ELFT::Shdr *>
ELFFile<ELFT>::getSection(uint32_t Index) const {
@ -738,6 +1036,23 @@ ELFFile<ELFT>::getStringTableForSymtab(const Elf_Shdr &Sec,
return getStringTable(**SectionOrErr);
}
template <class ELFT>
Expected<StringRef>
ELFFile<ELFT>::getLinkAsStrtab(const typename ELFT::Shdr &Sec) const {
Expected<const typename ELFT::Shdr *> StrTabSecOrErr =
getSection(Sec.sh_link);
if (!StrTabSecOrErr)
return createError("invalid section linked to " + describe(*this, Sec) +
": " + toString(StrTabSecOrErr.takeError()));
Expected<StringRef> StrTabOrErr = getStringTable(**StrTabSecOrErr);
if (!StrTabOrErr)
return createError("invalid string table linked to " +
describe(*this, Sec) + ": " +
toString(StrTabOrErr.takeError()));
return *StrTabOrErr;
}
template <class ELFT>
Expected<StringRef>
ELFFile<ELFT>::getSectionName(const Elf_Shdr &Section,

View File

@ -265,7 +265,7 @@ DynamicSymbols:
# INVALID-VERDEF-LLVM: VersionSymbols [
# INVALID-VERDEF-LLVM-NEXT: Symbol {
# INVALID-VERDEF-LLVM-NEXT: Version: 0
# INVALID-VERDEF-LLVM-NEXT: Name:
# INVALID-VERDEF-LLVM-NEXT: Name: {{$}}
# INVALID-VERDEF-LLVM-NEXT: }
# INVALID-VERDEF-LLVM-NEXT: Symbol {
# INVALID-VERDEF-LLVM-NEXT: Version: 2
@ -274,7 +274,7 @@ DynamicSymbols:
# INVALID-VERDEF-GNU: Version symbols section '.gnu.version' contains 2 entries:
# INVALID-VERDEF-GNU-NEXT: Addr: 0000000000000000 Offset: 0x000040 Link: 3 (.dynsym)
# INVALID-VERDEF-GNU-NEXT: warning: '[[FILE]]': unable to get a version for entry 1 of SHT_GNU_versym section with index 1: invalid SHT_GNU_verdef section with index 2: version definition 1 goes past the end of the section
# INVALID-VERDEF-GNU-NEXT: warning: '[[FILE]]': invalid SHT_GNU_verdef section with index 2: version definition 1 goes past the end of the section
# INVALID-VERDEF-GNU-NEXT: 000: 0 (*local*) 2 (<corrupt>)
--- !ELF

View File

@ -158,7 +158,7 @@ DynamicSymbols:
# BROKEN-AUX-GNU: Version symbols section '.gnu.version' contains 1 entries:
# BROKEN-AUX-GNU-NEXT: Addr: 0000000000000000 Offset: 0x000040 Link: 3 (.dynsym)
# BROKEN-AUX-GNU-NEXT: warning: '[[FILE]]': unable to get a version for entry 0 of SHT_GNU_versym section with index 1: invalid SHT_GNU_verneed section with index 2: found a misaligned auxiliary entry at offset 0x11
# BROKEN-AUX-GNU-NEXT: warning: '[[FILE]]': invalid SHT_GNU_verneed section with index 2: found a misaligned auxiliary entry at offset 0x11
# BROKEN-AUX-GNU-NEXT: 000: 2 (<corrupt>)
# BROKEN-AUX-LLVM: VersionSymbols [

View File

@ -173,37 +173,6 @@ struct GroupSection {
};
namespace {
struct VerdAux {
unsigned Offset;
std::string Name;
};
struct VerDef {
unsigned Offset;
unsigned Version;
unsigned Flags;
unsigned Ndx;
unsigned Cnt;
unsigned Hash;
std::string Name;
std::vector<VerdAux> AuxV;
};
struct VernAux {
unsigned Hash;
unsigned Flags;
unsigned Other;
unsigned Offset;
std::string Name;
};
struct VerNeed {
unsigned Version;
unsigned Cnt;
unsigned Offset;
std::string File;
std::vector<VernAux> AuxV;
};
struct NoteType {
uint32_t ID;
@ -366,7 +335,7 @@ protected:
Expected<StringRef> getSymbolVersion(const Elf_Sym &Sym,
bool &IsDefault) const;
Error LoadVersionMap() const;
Expected<SmallVector<Optional<VersionEntry>, 0> *> getVersionMap() const;
DynRegionInfo DynRelRegion;
DynRegionInfo DynRelaRegion;
@ -389,12 +358,6 @@ protected:
const Elf_Shdr *SymbolVersionNeedSection = nullptr; // .gnu.version_r
const Elf_Shdr *SymbolVersionDefSection = nullptr; // .gnu.version_d
struct VersionEntry {
std::string Name;
bool IsVerDef;
};
mutable SmallVector<Optional<VersionEntry>, 16> VersionMap;
std::string getFullSymbolName(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
Optional<StringRef> StrTable,
@ -406,32 +369,18 @@ protected:
unsigned SectionIndex) const;
std::string getStaticSymbolName(uint32_t Index) const;
StringRef getDynamicString(uint64_t Value) const;
Expected<StringRef> getSymbolVersionByIndex(uint32_t VersionSymbolIndex,
bool &IsDefault) const;
void printSymbolsHelper(bool IsDynamic) const;
std::string getDynamicEntry(uint64_t Type, uint64_t Value) const;
Expected<std::vector<VerDef>>
getVersionDefinitions(const Elf_Shdr &Sec) const;
Expected<std::vector<VerNeed>>
getVersionDependencies(const Elf_Shdr &Sec) const;
Expected<RelSymbol<ELFT>> getRelocationTarget(const Relocation<ELFT> &R,
const Elf_Shdr *SymTab) const;
ArrayRef<Elf_Word> getShndxTable(const Elf_Shdr *Symtab) const;
};
template <class ELFT>
static std::string describe(const ELFFile<ELFT> &Obj,
const typename ELFT::Shdr &Sec) {
unsigned SecNdx = &Sec - &cantFail(Obj.sections()).front();
return (object::getELFSectionTypeName(Obj.getHeader().e_machine,
Sec.sh_type) +
" section with index " + Twine(SecNdx))
.str();
}
private:
mutable SmallVector<Optional<VersionEntry>, 0> VersionMap;
};
template <class ELFT>
std::string ELFDumper<ELFT>::describe(const Elf_Shdr &Sec) const {
@ -440,22 +389,6 @@ std::string ELFDumper<ELFT>::describe(const Elf_Shdr &Sec) const {
namespace {
template <class ELFT>
Expected<StringRef> getLinkAsStrtab(const ELFFile<ELFT> &Obj,
const typename ELFT::Shdr &Sec) {
Expected<const typename ELFT::Shdr *> StrTabSecOrErr =
Obj.getSection(Sec.sh_link);
if (!StrTabSecOrErr)
return createError("invalid section linked to " + describe(Obj, Sec) +
": " + toString(StrTabSecOrErr.takeError()));
Expected<StringRef> StrTabOrErr = Obj.getStringTable(**StrTabSecOrErr);
if (!StrTabOrErr)
return createError("invalid string table linked to " + describe(Obj, Sec) +
": " + toString(StrTabOrErr.takeError()));
return *StrTabOrErr;
}
template <class ELFT> struct SymtabLink {
typename ELFT::SymRange Symbols;
StringRef StringTable;
@ -482,7 +415,7 @@ Expected<SymtabLink<ELFT>> getLinkAsSymtab(const ELFFile<ELFT> &Obj,
object::getELFSectionTypeName(Obj.getHeader().e_machine,
(*SymtabOrErr)->sh_type));
Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Obj, **SymtabOrErr);
Expected<StringRef> StrTabOrErr = Obj.getLinkAsStrtab(**SymtabOrErr);
if (!StrTabOrErr)
return createError(
"can't get a string table for the symbol table linked to " +
@ -538,173 +471,6 @@ ELFDumper<ELFT>::getVersionTable(const Elf_Shdr &Sec, ArrayRef<Elf_Sym> *SymTab,
return *VersionsOrErr;
}
template <class ELFT>
Expected<std::vector<VerDef>>
ELFDumper<ELFT>::getVersionDefinitions(const Elf_Shdr &Sec) const {
Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Obj, Sec);
if (!StrTabOrErr)
return StrTabOrErr.takeError();
Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj.getSectionContents(Sec);
if (!ContentsOrErr)
return createError("cannot read content of " + describe(Sec) + ": " +
toString(ContentsOrErr.takeError()));
const uint8_t *Start = ContentsOrErr->data();
const uint8_t *End = Start + ContentsOrErr->size();
auto ExtractNextAux = [&](const uint8_t *&VerdauxBuf,
unsigned VerDefNdx) -> Expected<VerdAux> {
if (VerdauxBuf + sizeof(Elf_Verdaux) > End)
return createError("invalid " + describe(Sec) + ": version definition " +
Twine(VerDefNdx) +
" refers to an auxiliary entry that goes past the end "
"of the section");
auto *Verdaux = reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf);
VerdauxBuf += Verdaux->vda_next;
VerdAux Aux;
Aux.Offset = VerdauxBuf - Start;
if (Verdaux->vda_name <= StrTabOrErr->size())
Aux.Name = std::string(StrTabOrErr->drop_front(Verdaux->vda_name));
else
Aux.Name = "<invalid vda_name: " + to_string(Verdaux->vda_name) + ">";
return Aux;
};
std::vector<VerDef> Ret;
const uint8_t *VerdefBuf = Start;
for (unsigned I = 1; I <= /*VerDefsNum=*/Sec.sh_info; ++I) {
if (VerdefBuf + sizeof(Elf_Verdef) > End)
return createError("invalid " + describe(Sec) + ": version definition " +
Twine(I) + " goes past the end of the section");
if (reinterpret_cast<uintptr_t>(VerdefBuf) % sizeof(uint32_t) != 0)
return createError(
"invalid " + describe(Sec) +
": found a misaligned version definition entry at offset 0x" +
Twine::utohexstr(VerdefBuf - Start));
unsigned Version = *reinterpret_cast<const Elf_Half *>(VerdefBuf);
if (Version != 1)
return createError("unable to dump " + describe(Sec) + ": version " +
Twine(Version) + " is not yet supported");
const Elf_Verdef *D = reinterpret_cast<const Elf_Verdef *>(VerdefBuf);
VerDef &VD = *Ret.emplace(Ret.end());
VD.Offset = VerdefBuf - Start;
VD.Version = D->vd_version;
VD.Flags = D->vd_flags;
VD.Ndx = D->vd_ndx;
VD.Cnt = D->vd_cnt;
VD.Hash = D->vd_hash;
const uint8_t *VerdauxBuf = VerdefBuf + D->vd_aux;
for (unsigned J = 0; J < D->vd_cnt; ++J) {
if (reinterpret_cast<uintptr_t>(VerdauxBuf) % sizeof(uint32_t) != 0)
return createError("invalid " + describe(Sec) +
": found a misaligned auxiliary entry at offset 0x" +
Twine::utohexstr(VerdauxBuf - Start));
Expected<VerdAux> AuxOrErr = ExtractNextAux(VerdauxBuf, I);
if (!AuxOrErr)
return AuxOrErr.takeError();
if (J == 0)
VD.Name = AuxOrErr->Name;
else
VD.AuxV.push_back(*AuxOrErr);
}
VerdefBuf += D->vd_next;
}
return Ret;
}
template <class ELFT>
Expected<std::vector<VerNeed>>
ELFDumper<ELFT>::getVersionDependencies(const Elf_Shdr &Sec) const {
StringRef StrTab;
Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Obj, Sec);
if (!StrTabOrErr)
reportUniqueWarning(StrTabOrErr.takeError());
else
StrTab = *StrTabOrErr;
Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj.getSectionContents(Sec);
if (!ContentsOrErr)
return createError("cannot read content of " + describe(Sec) + ": " +
toString(ContentsOrErr.takeError()));
const uint8_t *Start = ContentsOrErr->data();
const uint8_t *End = Start + ContentsOrErr->size();
const uint8_t *VerneedBuf = Start;
std::vector<VerNeed> Ret;
for (unsigned I = 1; I <= /*VerneedNum=*/Sec.sh_info; ++I) {
if (VerneedBuf + sizeof(Elf_Verdef) > End)
return createError("invalid " + describe(Sec) + ": version dependency " +
Twine(I) + " goes past the end of the section");
if (reinterpret_cast<uintptr_t>(VerneedBuf) % sizeof(uint32_t) != 0)
return createError(
"invalid " + describe(Sec) +
": found a misaligned version dependency entry at offset 0x" +
Twine::utohexstr(VerneedBuf - Start));
unsigned Version = *reinterpret_cast<const Elf_Half *>(VerneedBuf);
if (Version != 1)
return createError("unable to dump " + describe(Sec) + ": version " +
Twine(Version) + " is not yet supported");
const Elf_Verneed *Verneed =
reinterpret_cast<const Elf_Verneed *>(VerneedBuf);
VerNeed &VN = *Ret.emplace(Ret.end());
VN.Version = Verneed->vn_version;
VN.Cnt = Verneed->vn_cnt;
VN.Offset = VerneedBuf - Start;
if (Verneed->vn_file < StrTab.size())
VN.File = std::string(StrTab.drop_front(Verneed->vn_file));
else
VN.File = "<corrupt vn_file: " + to_string(Verneed->vn_file) + ">";
const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux;
for (unsigned J = 0; J < Verneed->vn_cnt; ++J) {
if (reinterpret_cast<uintptr_t>(VernauxBuf) % sizeof(uint32_t) != 0)
return createError("invalid " + describe(Sec) +
": found a misaligned auxiliary entry at offset 0x" +
Twine::utohexstr(VernauxBuf - Start));
if (VernauxBuf + sizeof(Elf_Vernaux) > End)
return createError(
"invalid " + describe(Sec) + ": version dependency " + Twine(I) +
" refers to an auxiliary entry that goes past the end "
"of the section");
const Elf_Vernaux *Vernaux =
reinterpret_cast<const Elf_Vernaux *>(VernauxBuf);
VernAux &Aux = *VN.AuxV.emplace(VN.AuxV.end());
Aux.Hash = Vernaux->vna_hash;
Aux.Flags = Vernaux->vna_flags;
Aux.Other = Vernaux->vna_other;
Aux.Offset = VernauxBuf - Start;
if (StrTab.size() <= Vernaux->vna_name)
Aux.Name = "<corrupt>";
else
Aux.Name = std::string(StrTab.drop_front(Vernaux->vna_name));
VernauxBuf += Vernaux->vna_next;
}
VerneedBuf += Verneed->vn_next;
}
return Ret;
}
template <class ELFT>
void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {
Optional<StringRef> StrTable;
@ -953,46 +719,22 @@ std::unique_ptr<ObjDumper> createELFDumper(const object::ELFObjectFileBase &Obj,
} // end namespace llvm
template <class ELFT> Error ELFDumper<ELFT>::LoadVersionMap() const {
// If there is no dynamic symtab or version table, there is nothing to do.
if (!DynSymRegion || !SymbolVersionSection)
return Error::success();
template <class ELFT>
Expected<SmallVector<Optional<VersionEntry>, 0> *>
ELFDumper<ELFT>::getVersionMap() const {
// If the VersionMap has already been loaded or if there is no dynamic symtab
// or version table, there is nothing to do.
if (!VersionMap.empty() || !DynSymRegion || !SymbolVersionSection)
return &VersionMap;
// Has the VersionMap already been loaded?
if (!VersionMap.empty())
return Error::success();
Expected<SmallVector<Optional<VersionEntry>, 0>> MapOrErr =
Obj.loadVersionMap(SymbolVersionNeedSection, SymbolVersionDefSection);
if (MapOrErr)
VersionMap = *MapOrErr;
else
return MapOrErr.takeError();
// The first two version indexes are reserved.
// Index 0 is LOCAL, index 1 is GLOBAL.
VersionMap.push_back(VersionEntry());
VersionMap.push_back(VersionEntry());
auto InsertEntry = [this](unsigned N, StringRef Version, bool IsVerdef) {
if (N >= VersionMap.size())
VersionMap.resize(N + 1);
VersionMap[N] = {std::string(Version), IsVerdef};
};
if (SymbolVersionDefSection) {
Expected<std::vector<VerDef>> Defs =
this->getVersionDefinitions(*SymbolVersionDefSection);
if (!Defs)
return Defs.takeError();
for (const VerDef &Def : *Defs)
InsertEntry(Def.Ndx & ELF::VERSYM_VERSION, Def.Name, true);
}
if (SymbolVersionNeedSection) {
Expected<std::vector<VerNeed>> Deps =
this->getVersionDependencies(*SymbolVersionNeedSection);
if (!Deps)
return Deps.takeError();
for (const VerNeed &Dep : *Deps)
for (const VernAux &Aux : Dep.AuxV)
InsertEntry(Aux.Other & ELF::VERSYM_VERSION, Aux.Name, false);
}
return Error::success();
return &VersionMap;
}
template <typename ELFT>
@ -1012,11 +754,22 @@ Expected<StringRef> ELFDumper<ELFT>::getSymbolVersion(const Elf_Sym &Sym,
sizeof(Elf_Sym);
// Get the corresponding version index entry.
if (Expected<const Elf_Versym *> EntryOrErr =
Obj.template getEntry<Elf_Versym>(*SymbolVersionSection, EntryIndex))
return getSymbolVersionByIndex((*EntryOrErr)->vs_index, IsDefault);
else
Expected<const Elf_Versym *> EntryOrErr =
Obj.template getEntry<Elf_Versym>(*SymbolVersionSection, EntryIndex);
if (!EntryOrErr)
return EntryOrErr.takeError();
unsigned Version = (*EntryOrErr)->vs_index;
if (Version == VER_NDX_LOCAL || Version == VER_NDX_GLOBAL) {
IsDefault = false;
return "";
}
Expected<SmallVector<Optional<VersionEntry>, 0> *> MapOrErr =
getVersionMap();
if (!MapOrErr)
return MapOrErr.takeError();
return Obj.getSymbolVersionByIndex(Version, IsDefault, **MapOrErr);
}
template <typename ELFT>
@ -1086,33 +839,6 @@ std::string ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const {
return maybeDemangle(*NameOrErr);
}
template <typename ELFT>
Expected<StringRef>
ELFDumper<ELFT>::getSymbolVersionByIndex(uint32_t SymbolVersionIndex,
bool &IsDefault) const {
size_t VersionIndex = SymbolVersionIndex & VERSYM_VERSION;
// Special markers for unversioned symbols.
if (VersionIndex == VER_NDX_LOCAL || VersionIndex == VER_NDX_GLOBAL) {
IsDefault = false;
return "";
}
// Lookup this symbol in the version table.
if (Error E = LoadVersionMap())
return std::move(E);
if (VersionIndex >= VersionMap.size() || !VersionMap[VersionIndex])
return createError("SHT_GNU_versym section refers to a version index " +
Twine(VersionIndex) + " which is missing");
const VersionEntry &Entry = *VersionMap[VersionIndex];
if (Entry.IsVerDef)
IsDefault = !(SymbolVersionIndex & VERSYM_HIDDEN);
else
IsDefault = false;
return Entry.Name.c_str();
}
template <typename ELFT>
std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym &Symbol,
unsigned SymIndex,
@ -4636,6 +4362,13 @@ void GNUELFDumper<ELFT>::printVersionSymbolSection(const Elf_Shdr *Sec) {
return;
}
SmallVector<Optional<VersionEntry>, 0> *VersionMap = nullptr;
if (Expected<SmallVector<Optional<VersionEntry>, 0> *> MapOrErr =
this->getVersionMap())
VersionMap = *MapOrErr;
else
this->reportUniqueWarning(MapOrErr.takeError());
ArrayRef<Elf_Versym> VerTable = *VerTableOrErr;
std::vector<StringRef> Versions;
for (size_t I = 0, E = VerTable.size(); I < E; ++I) {
@ -4645,9 +4378,14 @@ void GNUELFDumper<ELFT>::printVersionSymbolSection(const Elf_Shdr *Sec) {
continue;
}
if (!VersionMap) {
Versions.emplace_back("<corrupt>");
continue;
}
bool IsDefault;
Expected<StringRef> NameOrErr =
this->getSymbolVersionByIndex(Ndx, IsDefault);
this->Obj.getSymbolVersionByIndex(Ndx, IsDefault, *VersionMap);
if (!NameOrErr) {
this->reportUniqueWarning("unable to get a version for entry " +
Twine(I) + " of " + this->describe(*Sec) +
@ -4701,7 +4439,7 @@ void GNUELFDumper<ELFT>::printVersionDefinitionSection(const Elf_Shdr *Sec) {
printGNUVersionSectionProlog(*Sec, "Version definition", Sec->sh_info);
Expected<std::vector<VerDef>> V = this->getVersionDefinitions(*Sec);
Expected<std::vector<VerDef>> V = this->Obj.getVersionDefinitions(*Sec);
if (!V) {
this->reportUniqueWarning(V.takeError());
return;
@ -4729,7 +4467,8 @@ void GNUELFDumper<ELFT>::printVersionDependencySection(const Elf_Shdr *Sec) {
unsigned VerneedNum = Sec->sh_info;
printGNUVersionSectionProlog(*Sec, "Version needs", VerneedNum);
Expected<std::vector<VerNeed>> V = this->getVersionDependencies(*Sec);
Expected<std::vector<VerNeed>> V =
this->Obj.getVersionDependencies(*Sec, this->WarningHandler);
if (!V) {
this->reportUniqueWarning(V.takeError());
return;
@ -6613,7 +6352,7 @@ void LLVMELFDumper<ELFT>::printVersionDefinitionSection(const Elf_Shdr *Sec) {
if (!Sec)
return;
Expected<std::vector<VerDef>> V = this->getVersionDefinitions(*Sec);
Expected<std::vector<VerDef>> V = this->Obj.getVersionDefinitions(*Sec);
if (!V) {
this->reportUniqueWarning(V.takeError());
return;
@ -6638,7 +6377,8 @@ void LLVMELFDumper<ELFT>::printVersionDependencySection(const Elf_Shdr *Sec) {
if (!Sec)
return;
Expected<std::vector<VerNeed>> V = this->getVersionDependencies(*Sec);
Expected<std::vector<VerNeed>> V =
this->Obj.getVersionDependencies(*Sec, this->WarningHandler);
if (!V) {
this->reportUniqueWarning(V.takeError());
return;