diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h --- 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 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 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 @@ return "[unknown index]"; } +template +static std::string describe(const ELFFile &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 std::string getPhdrIndexForError(const ELFFile &Obj, const typename ELFT::Phdr &Phdr) { @@ -148,12 +195,22 @@ template Expected getEntry(const Elf_Shdr &Section, uint32_t Entry) const; + Expected> + getVersionDefinitions(const Elf_Shdr &Sec) const; + Expected> getVersionDependencies( + const Elf_Shdr &Sec, + WarningHandler WarnHandler = &defaultWarningHandler) const; + Expected getSymbolVersionByIndex( + uint32_t SymbolVersionIndex, bool &IsDefault, + SmallVector, 0> &VersionMap) const; + Expected getStringTable(const Elf_Shdr &Section, WarningHandler WarnHandler = &defaultWarningHandler) const; Expected getStringTableForSymtab(const Elf_Shdr &Section) const; Expected getStringTableForSymtab(const Elf_Shdr &Section, Elf_Shdr_Range Sections) const; + Expected getLinkAsStrtab(const typename ELFT::Shdr &Sec) const; Expected> getSHNDXTable(const Elf_Shdr &Section) const; Expected> getSHNDXTable(const Elf_Shdr &Section, @@ -171,6 +228,9 @@ Expected getRelocationSymbol(const Elf_Rel &Rel, const Elf_Shdr *SymTab) const; + Expected, 0>> + loadVersionMap(const Elf_Shdr *VerNeedSec, const Elf_Shdr *VerDefSec) const; + static Expected create(StringRef Object); bool isLE() const { @@ -518,6 +578,43 @@ return getELFRelativeRelocationType(getHeader().e_machine); } +template +Expected, 0>> +ELFFile::loadVersionMap(const Elf_Shdr *VerNeedSec, + const Elf_Shdr *VerDefSec) const { + SmallVector, 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> 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> 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 Expected ELFFile::getRelocationSymbol(const Elf_Rel &Rel, @@ -641,6 +738,207 @@ return &Arr[Entry]; } +template +Expected ELFFile::getSymbolVersionByIndex( + uint32_t SymbolVersionIndex, bool &IsDefault, + SmallVector, 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 +Expected> +ELFFile::getVersionDefinitions(const Elf_Shdr &Sec) const { + Expected StrTabOrErr = getLinkAsStrtab(Sec); + if (!StrTabOrErr) + return StrTabOrErr.takeError(); + + Expected> 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 { + 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(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 = ("vda_name) + ">").str(); + return Aux; + }; + + std::vector 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(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(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(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(VerdauxBuf) % sizeof(uint32_t) != 0) + return createError("invalid " + describe(*this, Sec) + + ": found a misaligned auxiliary entry at offset 0x" + + Twine::utohexstr(VerdauxBuf - Start)); + + Expected 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 +Expected> +ELFFile::getVersionDependencies(const Elf_Shdr &Sec, + WarningHandler WarnHandler) const { + StringRef StrTab; + Expected StrTabOrErr = getLinkAsStrtab(Sec); + if (!StrTabOrErr) { + if (Error E = WarnHandler(toString(StrTabOrErr.takeError()))) + return std::move(E); + } else { + StrTab = *StrTabOrErr; + } + + Expected> 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 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(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(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(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 = ("vn_file) + ">").str(); + + const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux; + for (unsigned J = 0; J < Verneed->vn_cnt; ++J) { + if (reinterpret_cast(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(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 = ""; + else + Aux.Name = std::string(StrTab.drop_front(Vernaux->vna_name)); + + VernauxBuf += Vernaux->vna_next; + } + VerneedBuf += Verneed->vn_next; + } + return Ret; +} + template Expected ELFFile::getSection(uint32_t Index) const { @@ -738,6 +1036,23 @@ return getStringTable(**SectionOrErr); } +template +Expected +ELFFile::getLinkAsStrtab(const typename ELFT::Shdr &Sec) const { + Expected StrTabSecOrErr = + getSection(Sec.sh_link); + if (!StrTabSecOrErr) + return createError("invalid section linked to " + describe(*this, Sec) + + ": " + toString(StrTabSecOrErr.takeError())); + + Expected StrTabOrErr = getStringTable(**StrTabSecOrErr); + if (!StrTabOrErr) + return createError("invalid string table linked to " + + describe(*this, Sec) + ": " + + toString(StrTabOrErr.takeError())); + return *StrTabOrErr; +} + template Expected ELFFile::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 --- a/llvm/test/tools/llvm-readobj/ELF/verdef-invalid.test +++ b/llvm/test/tools/llvm-readobj/ELF/verdef-invalid.test @@ -265,7 +265,7 @@ # 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 @@ # 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 () --- !ELF diff --git a/llvm/test/tools/llvm-readobj/ELF/verneed-invalid.test b/llvm/test/tools/llvm-readobj/ELF/verneed-invalid.test --- a/llvm/test/tools/llvm-readobj/ELF/verneed-invalid.test +++ b/llvm/test/tools/llvm-readobj/ELF/verneed-invalid.test @@ -158,7 +158,7 @@ # 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 () # BROKEN-AUX-LLVM: VersionSymbols [ diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -173,37 +173,6 @@ }; 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 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 AuxV; -}; struct NoteType { uint32_t ID; @@ -366,7 +335,7 @@ Expected getSymbolVersion(const Elf_Sym &Sym, bool &IsDefault) const; - Error LoadVersionMap() const; + Expected, 0> *> getVersionMap() const; DynRegionInfo DynRelRegion; DynRegionInfo DynRelaRegion; @@ -389,12 +358,6 @@ 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, 16> VersionMap; - std::string getFullSymbolName(const Elf_Sym &Symbol, unsigned SymIndex, DataRegion ShndxTable, Optional StrTable, @@ -406,32 +369,18 @@ unsigned SectionIndex) const; std::string getStaticSymbolName(uint32_t Index) const; StringRef getDynamicString(uint64_t Value) const; - Expected getSymbolVersionByIndex(uint32_t VersionSymbolIndex, - bool &IsDefault) const; void printSymbolsHelper(bool IsDynamic) const; std::string getDynamicEntry(uint64_t Type, uint64_t Value) const; - Expected> - getVersionDefinitions(const Elf_Shdr &Sec) const; - Expected> - getVersionDependencies(const Elf_Shdr &Sec) const; - Expected> getRelocationTarget(const Relocation &R, const Elf_Shdr *SymTab) const; ArrayRef getShndxTable(const Elf_Shdr *Symtab) const; -}; -template -static std::string describe(const ELFFile &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, 0> VersionMap; +}; template std::string ELFDumper::describe(const Elf_Shdr &Sec) const { @@ -440,22 +389,6 @@ namespace { -template -Expected getLinkAsStrtab(const ELFFile &Obj, - const typename ELFT::Shdr &Sec) { - Expected StrTabSecOrErr = - Obj.getSection(Sec.sh_link); - if (!StrTabSecOrErr) - return createError("invalid section linked to " + describe(Obj, Sec) + - ": " + toString(StrTabSecOrErr.takeError())); - - Expected StrTabOrErr = Obj.getStringTable(**StrTabSecOrErr); - if (!StrTabOrErr) - return createError("invalid string table linked to " + describe(Obj, Sec) + - ": " + toString(StrTabOrErr.takeError())); - return *StrTabOrErr; -} - template struct SymtabLink { typename ELFT::SymRange Symbols; StringRef StringTable; @@ -482,7 +415,7 @@ object::getELFSectionTypeName(Obj.getHeader().e_machine, (*SymtabOrErr)->sh_type)); - Expected StrTabOrErr = getLinkAsStrtab(Obj, **SymtabOrErr); + Expected StrTabOrErr = Obj.getLinkAsStrtab(**SymtabOrErr); if (!StrTabOrErr) return createError( "can't get a string table for the symbol table linked to " + @@ -538,173 +471,6 @@ return *VersionsOrErr; } -template -Expected> -ELFDumper::getVersionDefinitions(const Elf_Shdr &Sec) const { - Expected StrTabOrErr = getLinkAsStrtab(Obj, Sec); - if (!StrTabOrErr) - return StrTabOrErr.takeError(); - - Expected> 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 { - 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(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 = "vda_name) + ">"; - return Aux; - }; - - std::vector 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(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(VerdefBuf); - if (Version != 1) - return createError("unable to dump " + describe(Sec) + ": version " + - Twine(Version) + " is not yet supported"); - - const Elf_Verdef *D = reinterpret_cast(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(VerdauxBuf) % sizeof(uint32_t) != 0) - return createError("invalid " + describe(Sec) + - ": found a misaligned auxiliary entry at offset 0x" + - Twine::utohexstr(VerdauxBuf - Start)); - - Expected 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 -Expected> -ELFDumper::getVersionDependencies(const Elf_Shdr &Sec) const { - StringRef StrTab; - Expected StrTabOrErr = getLinkAsStrtab(Obj, Sec); - if (!StrTabOrErr) - reportUniqueWarning(StrTabOrErr.takeError()); - else - StrTab = *StrTabOrErr; - - Expected> 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 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(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(VerneedBuf); - if (Version != 1) - return createError("unable to dump " + describe(Sec) + ": version " + - Twine(Version) + " is not yet supported"); - - const Elf_Verneed *Verneed = - reinterpret_cast(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 = "vn_file) + ">"; - - const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux; - for (unsigned J = 0; J < Verneed->vn_cnt; ++J) { - if (reinterpret_cast(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(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 = ""; - else - Aux.Name = std::string(StrTab.drop_front(Vernaux->vna_name)); - - VernauxBuf += Vernaux->vna_next; - } - VerneedBuf += Verneed->vn_next; - } - return Ret; -} - template void ELFDumper::printSymbolsHelper(bool IsDynamic) const { Optional StrTable; @@ -953,46 +719,22 @@ } // end namespace llvm -template Error ELFDumper::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> 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> 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 +Expected, 0> *> +ELFDumper::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, 0>> MapOrErr = + Obj.loadVersionMap(SymbolVersionNeedSection, SymbolVersionDefSection); + if (MapOrErr) + VersionMap = *MapOrErr; + else + return MapOrErr.takeError(); - return Error::success(); + return &VersionMap; } template @@ -1012,11 +754,22 @@ sizeof(Elf_Sym); // Get the corresponding version index entry. - if (Expected EntryOrErr = - Obj.template getEntry(*SymbolVersionSection, EntryIndex)) - return getSymbolVersionByIndex((*EntryOrErr)->vs_index, IsDefault); - else + Expected EntryOrErr = + Obj.template getEntry(*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, 0> *> MapOrErr = + getVersionMap(); + if (!MapOrErr) + return MapOrErr.takeError(); + return Obj.getSymbolVersionByIndex(Version, IsDefault, **MapOrErr); } template @@ -1086,33 +839,6 @@ return maybeDemangle(*NameOrErr); } -template -Expected -ELFDumper::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 std::string ELFDumper::getFullSymbolName(const Elf_Sym &Symbol, unsigned SymIndex, @@ -4636,6 +4362,13 @@ return; } + SmallVector, 0> *VersionMap = nullptr; + if (Expected, 0> *> MapOrErr = + this->getVersionMap()) + VersionMap = *MapOrErr; + else + this->reportUniqueWarning(MapOrErr.takeError()); + ArrayRef VerTable = *VerTableOrErr; std::vector Versions; for (size_t I = 0, E = VerTable.size(); I < E; ++I) { @@ -4645,9 +4378,14 @@ continue; } + if (!VersionMap) { + Versions.emplace_back(""); + continue; + } + bool IsDefault; Expected 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 @@ printGNUVersionSectionProlog(*Sec, "Version definition", Sec->sh_info); - Expected> V = this->getVersionDefinitions(*Sec); + Expected> V = this->Obj.getVersionDefinitions(*Sec); if (!V) { this->reportUniqueWarning(V.takeError()); return; @@ -4729,7 +4467,8 @@ unsigned VerneedNum = Sec->sh_info; printGNUVersionSectionProlog(*Sec, "Version needs", VerneedNum); - Expected> V = this->getVersionDependencies(*Sec); + Expected> V = + this->Obj.getVersionDependencies(*Sec, this->WarningHandler); if (!V) { this->reportUniqueWarning(V.takeError()); return; @@ -6613,7 +6352,7 @@ if (!Sec) return; - Expected> V = this->getVersionDefinitions(*Sec); + Expected> V = this->Obj.getVersionDefinitions(*Sec); if (!V) { this->reportUniqueWarning(V.takeError()); return; @@ -6638,7 +6377,8 @@ if (!Sec) return; - Expected> V = this->getVersionDependencies(*Sec); + Expected> V = + this->Obj.getVersionDependencies(*Sec, this->WarningHandler); if (!V) { this->reportUniqueWarning(V.takeError()); return;