forked from OSchip/llvm-project
[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:
parent
f446fc5acf
commit
b9ce772b8f
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 [
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue