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; _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits