[yaml2obj][obj2yaml] - Support SHT_GNU_verdef (.gnu.version_d) section.

This patch adds support for parsing/dumping the .gnu.version section.

Description of the section is: https://refspecs.linuxfoundation.org/LSB_1.3.0/gLSB/gLSB/symverdefs.html

Differential revision: https://reviews.llvm.org/D58437

llvm-svn: 354574
This commit is contained in:
George Rimar 2019-02-21 12:21:43 +00:00
parent a13d56908a
commit b6a05e83ac
6 changed files with 308 additions and 9 deletions

View File

@ -121,6 +121,7 @@ struct Section {
RawContent,
Relocation,
NoBits,
Verdef,
Verneed,
Symver,
MipsABIFlags
@ -203,6 +204,25 @@ struct SymverSection : Section {
}
};
struct VerdefEntry {
uint16_t Version;
uint16_t Flags;
uint16_t VersionNdx;
uint32_t Hash;
std::vector<StringRef> VerNames;
};
struct VerdefSection : Section {
std::vector<VerdefEntry> Entries;
llvm::yaml::Hex64 Info;
VerdefSection() : Section(SectionKind::Verdef) {}
static bool classof(const Section *S) {
return S->Kind == SectionKind::Verdef;
}
};
struct Group : Section {
// Members of a group contain a flag and a list of section indices
// that are part of the group.
@ -274,6 +294,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::DynamicEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::ProgramHeader)
LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::ELFYAML::Section>)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Symbol)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VerdefEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VernauxEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VerneedEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Relocation)
@ -419,6 +440,10 @@ template <> struct MappingTraits<ELFYAML::DynamicEntry> {
static void mapping(IO &IO, ELFYAML::DynamicEntry &Rel);
};
template <> struct MappingTraits<ELFYAML::VerdefEntry> {
static void mapping(IO &IO, ELFYAML::VerdefEntry &E);
};
template <> struct MappingTraits<ELFYAML::VerneedEntry> {
static void mapping(IO &IO, ELFYAML::VerneedEntry &E);
};

View File

@ -868,6 +868,12 @@ static void sectionMapping(IO &IO, ELFYAML::NoBitsSection &Section) {
IO.mapOptional("Size", Section.Size, Hex64(0));
}
static void sectionMapping(IO &IO, ELFYAML::VerdefSection &Section) {
commonSectionMapping(IO, Section);
IO.mapRequired("Info", Section.Info);
IO.mapRequired("Entries", Section.Entries);
}
static void sectionMapping(IO &IO, ELFYAML::SymverSection &Section) {
commonSectionMapping(IO, Section);
IO.mapRequired("Entries", Section.Entries);
@ -956,6 +962,11 @@ void MappingTraits<std::unique_ptr<ELFYAML::Section>>::mapping(
Section.reset(new ELFYAML::MipsABIFlags());
sectionMapping(IO, *cast<ELFYAML::MipsABIFlags>(Section.get()));
break;
case ELF::SHT_GNU_verdef:
if (!IO.outputting())
Section.reset(new ELFYAML::VerdefSection());
sectionMapping(IO, *cast<ELFYAML::VerdefSection>(Section.get()));
break;
case ELF::SHT_GNU_versym:
if (!IO.outputting())
Section.reset(new ELFYAML::SymverSection());
@ -1014,6 +1025,17 @@ void MappingTraits<ELFYAML::DynamicEntry>::mapping(IO &IO,
IO.mapRequired("Value", Rel.Val);
}
void MappingTraits<ELFYAML::VerdefEntry>::mapping(IO &IO,
ELFYAML::VerdefEntry &E) {
assert(IO.getContext() && "The IO context is not initialized");
IO.mapRequired("Version", E.Version);
IO.mapRequired("Flags", E.Flags);
IO.mapRequired("VersionNdx", E.VersionNdx);
IO.mapRequired("Hash", E.Hash);
IO.mapRequired("Names", E.VerNames);
}
void MappingTraits<ELFYAML::VerneedEntry>::mapping(IO &IO,
ELFYAML::VerneedEntry &E) {
assert(IO.getContext() && "The IO context is not initialized");

View File

@ -0,0 +1,72 @@
# RUN: yaml2obj %s -o %t
# RUN: obj2yaml %t | FileCheck %s
## Check we are able to yamalize SHT_GNU_verdef section.
# CHECK: - Name: .gnu.version_d
# CHECK-NEXT: Type: SHT_GNU_verdef
# CHECK-NEXT: Flags: [ SHF_ALLOC ]
# CHECK-NEXT: Address: 0x0000000000000230
# CHECK-NEXT: Link: .dynstr
# CHECK-NEXT: AddressAlign: 0x0000000000000004
# CHECK-NEXT: Info: 0x0000000000000004
# CHECK-NEXT: Entries:
# CHECK-NEXT: - Version: 1
# CHECK-NEXT: Flags: 1
# CHECK-NEXT: VersionNdx: 1
# CHECK-NEXT: Hash: 170240160
# CHECK-NEXT: Names:
# CHECK-NEXT: - dso.so.0
# CHECK-NEXT: - Version: 1
# CHECK-NEXT: Flags: 2
# CHECK-NEXT: VersionNdx: 2
# CHECK-NEXT: Hash: 108387921
# CHECK-NEXT: Names:
# CHECK-NEXT: - VERSION_1
# CHECK-NEXT: - Version: 1
# CHECK-NEXT: Flags: 3
# CHECK-NEXT: VersionNdx: 3
# CHECK-NEXT: Hash: 108387922
# CHECK-NEXT: Names:
# CHECK-NEXT: - VERSION_2
# CHECK-NEXT: - VERSION_3
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_DYN
Machine: EM_X86_64
Entry: 0x0000000000001000
Sections:
- Name: .gnu.version_d
Type: SHT_GNU_verdef
Flags: [ SHF_ALLOC ]
Address: 0x0000000000000230
Link: .dynstr
AddressAlign: 0x0000000000000004
Info: 0x0000000000000004
Entries:
- Version: 1
Flags: 1
VersionNdx: 1
Hash: 170240160
Names:
- dso.so.0
- Version: 1
Flags: 2
VersionNdx: 2
Hash: 108387921
Names:
- VERSION_1
- Version: 1
Flags: 3
VersionNdx: 3
Hash: 108387922
Names:
- VERSION_2
- VERSION_3
DynamicSymbols:
Global:
- Name: foo
...

View File

@ -0,0 +1,69 @@
# RUN: yaml2obj %s -o %t
# RUN: llvm-readelf -V %t | FileCheck %s
# Check we are able to handle the SHT_GNU_verdef sections.
# CHECK: SHT_GNU_verdef {
# CHECK-NEXT: Definition {
# CHECK-NEXT: Version: 1
# CHECK-NEXT: Flags: Base
# CHECK-NEXT: Index: 1
# CHECK-NEXT: Hash: 170240160
# CHECK-NEXT: Name: dso.so.0
# CHECK-NEXT: }
# CHECK-NEXT: Definition {
# CHECK-NEXT: Version: 1
# CHECK-NEXT: Flags: Weak
# CHECK-NEXT: Index: 2
# CHECK-NEXT: Hash: 108387921
# CHECK-NEXT: Name: VERSION_1
# CHECK-NEXT: }
# CHECK-NEXT: Definition {
# CHECK-NEXT: Version: 1
# CHECK-NEXT: Flags: 0x3
# CHECK-NEXT: Index: 3
# CHECK-NEXT: Hash: 108387922
# CHECK-NEXT: Name: VERSION_2
# CHECK-NEXT: Predecessor: VERSION_3
# CHECK-NEXT: }
# CHECK-NEXT: }
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_DYN
Machine: EM_X86_64
Entry: 0x0000000000001000
Sections:
- Name: .gnu.version_d
Type: SHT_GNU_verdef
Flags: [ SHF_ALLOC ]
Address: 0x0000000000000230
Link: .dynstr
AddressAlign: 0x0000000000000004
Info: 0x0000000000000003
Entries:
- Version: 1
Flags: 1
VersionNdx: 1
Hash: 170240160
Names:
- dso.so.0
- Version: 1
Flags: 2
VersionNdx: 2
Hash: 108387921
Names:
- VERSION_1
- Version: 1
Flags: 3
VersionNdx: 3
Hash: 108387922
Names:
- VERSION_2
- VERSION_3
DynamicSymbols:
Global:
- Name: foo
...

View File

@ -57,6 +57,7 @@ class ELFDumper {
ErrorOr<ELFYAML::RawContentSection *>
dumpContentSection(const Elf_Shdr *Shdr);
ErrorOr<ELFYAML::NoBitsSection *> dumpNoBitsSection(const Elf_Shdr *Shdr);
ErrorOr<ELFYAML::VerdefSection *> dumpVerdefSection(const Elf_Shdr *Shdr);
ErrorOr<ELFYAML::SymverSection *> dumpSymverSection(const Elf_Shdr *Shdr);
ErrorOr<ELFYAML::VerneedSection *> dumpVerneedSection(const Elf_Shdr *Shdr);
ErrorOr<ELFYAML::Group *> dumpGroup(const Elf_Shdr *Shdr);
@ -186,6 +187,13 @@ template <class ELFT> ErrorOr<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
Y->Sections.push_back(std::unique_ptr<ELFYAML::Section>(S.get()));
break;
}
case ELF::SHT_GNU_verdef: {
ErrorOr<ELFYAML::VerdefSection *> S = dumpVerdefSection(&Sec);
if (std::error_code EC = S.getError())
return EC;
Y->Sections.push_back(std::unique_ptr<ELFYAML::Section>(S.get()));
break;
}
case ELF::SHT_GNU_versym: {
ErrorOr<ELFYAML::SymverSection *> S = dumpSymverSection(&Sec);
if (std::error_code EC = S.getError())
@ -459,6 +467,56 @@ ELFDumper<ELFT>::dumpNoBitsSection(const Elf_Shdr *Shdr) {
return S.release();
}
template <class ELFT>
ErrorOr<ELFYAML::VerdefSection *>
ELFDumper<ELFT>::dumpVerdefSection(const Elf_Shdr *Shdr) {
typedef typename ELFT::Verdef Elf_Verdef;
typedef typename ELFT::Verdaux Elf_Verdaux;
auto S = make_unique<ELFYAML::VerdefSection>();
if (std::error_code EC = dumpCommonSection(Shdr, *S))
return EC;
S->Info = Shdr->sh_info;
auto StringTableShdrOrErr = Obj.getSection(Shdr->sh_link);
if (!StringTableShdrOrErr)
return errorToErrorCode(StringTableShdrOrErr.takeError());
auto StringTableOrErr = Obj.getStringTable(*StringTableShdrOrErr);
if (!StringTableOrErr)
return errorToErrorCode(StringTableOrErr.takeError());
auto Contents = Obj.getSectionContents(Shdr);
if (!Contents)
return errorToErrorCode(Contents.takeError());
llvm::ArrayRef<uint8_t> Data = *Contents;
const uint8_t *Buf = Data.data();
while (Buf) {
const Elf_Verdef *Verdef = reinterpret_cast<const Elf_Verdef *>(Buf);
ELFYAML::VerdefEntry Entry;
Entry.Version = Verdef->vd_version;
Entry.Flags = Verdef->vd_flags;
Entry.VersionNdx = Verdef->vd_ndx;
Entry.Hash = Verdef->vd_hash;
const uint8_t *BufAux = Buf + Verdef->vd_aux;
while (BufAux) {
const Elf_Verdaux *Verdaux =
reinterpret_cast<const Elf_Verdaux *>(BufAux);
Entry.VerNames.push_back(
StringTableOrErr->drop_front(Verdaux->vda_name).data());
BufAux = Verdaux->vda_next ? BufAux + Verdaux->vda_next : nullptr;
}
S->Entries.push_back(Entry);
Buf = Verdef->vd_next ? Buf + Verdef->vd_next : nullptr;
}
return S.release();
}
template <class ELFT>
ErrorOr<ELFYAML::SymverSection *>
ELFDumper<ELFT>::dumpSymverSection(const Elf_Shdr *Shdr) {

View File

@ -163,6 +163,9 @@ class ELFState {
bool writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::VerneedSection &Section,
ContiguousBlobAccumulator &CBA);
bool writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::VerdefSection &Section,
ContiguousBlobAccumulator &CBA);
bool writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::MipsABIFlags &Section,
ContiguousBlobAccumulator &CBA);
@ -311,6 +314,8 @@ bool ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
writeSectionContent(SHeader, *S, CBA);
} else if (auto S = dyn_cast<ELFYAML::VerneedSection>(Sec.get())) {
writeSectionContent(SHeader, *S, CBA);
} else if (auto S = dyn_cast<ELFYAML::VerdefSection>(Sec.get())) {
writeSectionContent(SHeader, *S, CBA);
} else
llvm_unreachable("Unknown section type");
@ -585,6 +590,51 @@ bool ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
return true;
}
template <class ELFT>
bool ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::VerdefSection &Section,
ContiguousBlobAccumulator &CBA) {
typedef typename ELFT::Verdef Elf_Verdef;
typedef typename ELFT::Verdaux Elf_Verdaux;
raw_ostream &OS =
CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
uint64_t AuxCnt = 0;
for (size_t I = 0; I < Section.Entries.size(); ++I) {
const ELFYAML::VerdefEntry &E = Section.Entries[I];
Elf_Verdef VerDef;
VerDef.vd_version = E.Version;
VerDef.vd_flags = E.Flags;
VerDef.vd_ndx = E.VersionNdx;
VerDef.vd_hash = E.Hash;
VerDef.vd_aux = sizeof(Elf_Verdef);
VerDef.vd_cnt = E.VerNames.size();
if (I == Section.Entries.size() - 1)
VerDef.vd_next = 0;
else
VerDef.vd_next =
sizeof(Elf_Verdef) + E.VerNames.size() * sizeof(Elf_Verdaux);
OS.write((const char *)&VerDef, sizeof(Elf_Verdef));
for (size_t J = 0; J < E.VerNames.size(); ++J, ++AuxCnt) {
Elf_Verdaux VernAux;
VernAux.vda_name = DotDynstr.getOffset(E.VerNames[J]);
if (J == E.VerNames.size() - 1)
VernAux.vda_next = 0;
else
VernAux.vda_next = sizeof(Elf_Verdaux);
OS.write((const char *)&VernAux, sizeof(Elf_Verdaux));
}
}
SHeader.sh_size = Section.Entries.size() * sizeof(Elf_Verdef) +
AuxCnt * sizeof(Elf_Verdaux);
SHeader.sh_info = Section.Info;
return true;
}
template <class ELFT>
bool ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::VerneedSection &Section,
@ -746,16 +796,19 @@ template <class ELFT> void ELFState<ELFT>::finalizeStrings() {
// Add the dynamic symbol names to .dynstr section.
AddSymbols(DotDynstr, Doc.DynamicSymbols);
// SHT_GNU_verneed section also adds strings to .dynstr section.
// SHT_GNU_verdef and SHT_GNU_verneed sections might also
// add strings to .dynstr section.
for (const std::unique_ptr<ELFYAML::Section> &Sec : Doc.Sections) {
auto VerNeed = dyn_cast<ELFYAML::VerneedSection>(Sec.get());
if (!VerNeed)
continue;
for (const ELFYAML::VerneedEntry &VE : VerNeed->VerneedV) {
DotDynstr.add(VE.File);
for (const ELFYAML::VernauxEntry &Aux : VE.AuxV)
DotDynstr.add(Aux.Name);
if (auto VerNeed = dyn_cast<ELFYAML::VerneedSection>(Sec.get())) {
for (const ELFYAML::VerneedEntry &VE : VerNeed->VerneedV) {
DotDynstr.add(VE.File);
for (const ELFYAML::VernauxEntry &Aux : VE.AuxV)
DotDynstr.add(Aux.Name);
}
} else if (auto VerDef = dyn_cast<ELFYAML::VerdefSection>(Sec.get())) {
for (const ELFYAML::VerdefEntry &E : VerDef->Entries)
for (StringRef Name : E.VerNames)
DotDynstr.add(Name);
}
}