[llvm] b9ce772 - [Object, llvm-readelf] - Move the API for retrieving symbol versions to ELF.h
Georgii Rymar via llvm-commits
llvm-commits at lists.llvm.org
Mon Jan 18 01:50:45 PST 2021
Author: Georgii Rymar
Date: 2021-01-18T12:50:29+03:00
New Revision: b9ce772b8fb5d02afd026c9b029f5d53d1ea9591
URL: https://github.com/llvm/llvm-project/commit/b9ce772b8fb5d02afd026c9b029f5d53d1ea9591
DIFF: https://github.com/llvm/llvm-project/commit/b9ce772b8fb5d02afd026c9b029f5d53d1ea9591.diff
LOG: [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
Added:
Modified:
llvm/include/llvm/Object/ELF.h
llvm/test/tools/llvm-readobj/ELF/verdef-invalid.test
llvm/test/tools/llvm-readobj/ELF/verneed-invalid.test
llvm/tools/llvm-readobj/ELFDumper.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h
index 86359ff44d562..7ed124012a05d 100644
--- a/llvm/include/llvm/Object/ELF.h
+++ b/llvm/include/llvm/Object/ELF.h
@@ -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 @@ class ELFFile {
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 @@ class ELFFile {
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,
diff --git a/llvm/test/tools/llvm-readobj/ELF/verdef-invalid.test b/llvm/test/tools/llvm-readobj/ELF/verdef-invalid.test
index e7c93efed1a59..17e0fb1dda63b 100644
--- a/llvm/test/tools/llvm-readobj/ELF/verdef-invalid.test
+++ b/llvm/test/tools/llvm-readobj/ELF/verdef-invalid.test
@@ -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
diff --git a/llvm/test/tools/llvm-readobj/ELF/verneed-invalid.test b/llvm/test/tools/llvm-readobj/ELF/verneed-invalid.test
index 712bdc4c24346..2d4e32a8b1638 100644
--- a/llvm/test/tools/llvm-readobj/ELF/verneed-invalid.test
+++ b/llvm/test/tools/llvm-readobj/ELF/verneed-invalid.test
@@ -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 [
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 5a99359a9cc6b..f04dec998673b 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -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 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
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 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
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 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
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();
-
- // Has the VersionMap already been loaded?
- if (!VersionMap.empty())
- return Error::success();
-
- // 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);
- }
+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;
+
+ Expected<SmallVector<Optional<VersionEntry>, 0>> MapOrErr =
+ Obj.loadVersionMap(SymbolVersionNeedSection, SymbolVersionDefSection);
+ if (MapOrErr)
+ VersionMap = *MapOrErr;
+ else
+ return MapOrErr.takeError();
- 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;
More information about the llvm-commits
mailing list