forked from OSchip/llvm-project
[llvm-readobj/llvm-readelf] - Implement GNU style dumper of the SHT_GNU_verneed section.
It was not implemented yet, we had only LLVM style dumper implemented. Section description is here: https://refspecs.linuxfoundation.org/LSB_2.0.1/LSB-Core/LSB-Core/symverrqmts.html Differential revision: https://reviews.llvm.org/D62516 llvm-svn: 362080
This commit is contained in:
parent
3a34bccd20
commit
e3406c42a4
|
@ -0,0 +1,107 @@
|
||||||
|
## Check how llvm-readobj/llvm-readelf tools dump the flags of SHT_GNU_verneed
|
||||||
|
## section entries.
|
||||||
|
|
||||||
|
# RUN: yaml2obj %s -o %t
|
||||||
|
# RUN: llvm-readobj -V %t | FileCheck %s --check-prefix=LLVM-VERDEF
|
||||||
|
# RUN: llvm-readelf -V %t | FileCheck %s --check-prefix=GNU-VERDEF
|
||||||
|
|
||||||
|
# LLVM-VERDEF: SHT_GNU_verneed {
|
||||||
|
# LLVM-VERDEF-NEXT: Dependency {
|
||||||
|
# LLVM-VERDEF-NEXT: Version: 1
|
||||||
|
# LLVM-VERDEF-NEXT: Count: 6
|
||||||
|
# LLVM-VERDEF-NEXT: FileName: dso.so.0
|
||||||
|
# LLVM-VERDEF-NEXT: Entries [
|
||||||
|
# LLVM-VERDEF-NEXT: Entry {
|
||||||
|
# LLVM-VERDEF-NEXT: Hash: 0
|
||||||
|
# LLVM-VERDEF-NEXT: Flags: Base (0x1)
|
||||||
|
# LLVM-VERDEF-NEXT: Index: 0
|
||||||
|
# LLVM-VERDEF-NEXT: Name: base
|
||||||
|
# LLVM-VERDEF-NEXT: }
|
||||||
|
# LLVM-VERDEF-NEXT: Entry {
|
||||||
|
# LLVM-VERDEF-NEXT: Hash: 0
|
||||||
|
# LLVM-VERDEF-NEXT: Flags: Weak (0x2)
|
||||||
|
# LLVM-VERDEF-NEXT: Index: 0
|
||||||
|
# LLVM-VERDEF-NEXT: Name: weak
|
||||||
|
# LLVM-VERDEF-NEXT: }
|
||||||
|
# LLVM-VERDEF-NEXT: Entry {
|
||||||
|
# LLVM-VERDEF-NEXT: Hash: 0
|
||||||
|
# LLVM-VERDEF-NEXT: Flags: Info (0x4)
|
||||||
|
# LLVM-VERDEF-NEXT: Index: 0
|
||||||
|
# LLVM-VERDEF-NEXT: Name: info
|
||||||
|
# LLVM-VERDEF-NEXT: }
|
||||||
|
# LLVM-VERDEF-NEXT: Entry {
|
||||||
|
# LLVM-VERDEF-NEXT: Hash: 0
|
||||||
|
# LLVM-VERDEF-NEXT: Flags: 0x7
|
||||||
|
# LLVM-VERDEF-NEXT: Index: 0
|
||||||
|
# LLVM-VERDEF-NEXT: Name: all
|
||||||
|
# LLVM-VERDEF-NEXT: }
|
||||||
|
# LLVM-VERDEF-NEXT: Entry {
|
||||||
|
# LLVM-VERDEF-NEXT: Hash: 0
|
||||||
|
# LLVM-VERDEF-NEXT: Flags: 0x8
|
||||||
|
# LLVM-VERDEF-NEXT: Index: 0
|
||||||
|
# LLVM-VERDEF-NEXT: Name: unknown
|
||||||
|
# LLVM-VERDEF-NEXT: }
|
||||||
|
# LLVM-VERDEF-NEXT: Entry {
|
||||||
|
# LLVM-VERDEF-NEXT: Hash: 0
|
||||||
|
# LLVM-VERDEF-NEXT: Flags: 0xF
|
||||||
|
# LLVM-VERDEF-NEXT: Index: 0
|
||||||
|
# LLVM-VERDEF-NEXT: Name: all_and_unknown
|
||||||
|
# LLVM-VERDEF-NEXT: }
|
||||||
|
# LLVM-VERDEF-NEXT: ]
|
||||||
|
# LLVM-VERDEF-NEXT: }
|
||||||
|
# LLVM-VERDEF-NEXT: }
|
||||||
|
|
||||||
|
# GNU-VERDEF: Version needs section '.gnu.version_r' contains 1 entries:
|
||||||
|
# GNU-VERDEF-NEXT: Addr: 0000000000000000 Offset: 0x000200 Link: 6 (.dynstr)
|
||||||
|
# GNU-VERDEF-NEXT: 0x0000: Version: 1 File: dso.so.0 Cnt: 6
|
||||||
|
# GNU-VERDEF-NEXT: 0x0010: Name: base Flags: BASE Version: 0
|
||||||
|
# GNU-VERDEF-NEXT: 0x0020: Name: weak Flags: WEAK Version: 0
|
||||||
|
# GNU-VERDEF-NEXT: 0x0030: Name: info Flags: INFO Version: 0
|
||||||
|
# GNU-VERDEF-NEXT: 0x0040: Name: all Flags: BASE | WEAK | INFO Version: 0
|
||||||
|
# GNU-VERDEF-NEXT: 0x0050: Name: unknown Flags: <unknown> Version: 0
|
||||||
|
# GNU-VERDEF-NEXT: 0x0060: Name: all_and_unknown Flags: BASE | WEAK | INFO | <unknown> Version: 0
|
||||||
|
|
||||||
|
--- !ELF
|
||||||
|
FileHeader:
|
||||||
|
Class: ELFCLASS64
|
||||||
|
Data: ELFDATA2LSB
|
||||||
|
Type: ET_EXEC
|
||||||
|
Machine: EM_X86_64
|
||||||
|
Entry: 0x0000000000201000
|
||||||
|
Sections:
|
||||||
|
- Name: .gnu.version_r
|
||||||
|
Type: SHT_GNU_verneed
|
||||||
|
Link: .dynstr
|
||||||
|
Info: 0x0000000000000001
|
||||||
|
Dependencies:
|
||||||
|
- Version: 1
|
||||||
|
File: dso.so.0
|
||||||
|
Entries:
|
||||||
|
- Name: base
|
||||||
|
Hash: 0
|
||||||
|
Flags: 0x1
|
||||||
|
Other: 0
|
||||||
|
- Name: weak
|
||||||
|
Hash: 0
|
||||||
|
Flags: 0x2
|
||||||
|
Other: 0
|
||||||
|
- Name: info
|
||||||
|
Hash: 0
|
||||||
|
Flags: 0x4
|
||||||
|
Other: 0
|
||||||
|
- Name: all
|
||||||
|
Hash: 0
|
||||||
|
Flags: 0x7
|
||||||
|
Other: 0
|
||||||
|
- Name: unknown
|
||||||
|
Hash: 0
|
||||||
|
Flags: 0x8
|
||||||
|
Other: 0
|
||||||
|
- Name: all_and_unknown
|
||||||
|
Hash: 0
|
||||||
|
Flags: 0xf
|
||||||
|
Other: 0
|
||||||
|
## Needed to trigger .dynstr creation, which is required by .gnu.version_r
|
||||||
|
DynamicSymbols:
|
||||||
|
- Name: f1
|
||||||
|
Binding: STB_GLOBAL
|
|
@ -173,6 +173,13 @@ DynamicSymbols:
|
||||||
# GNU-NEXT: Addr: 0000000000000000 Offset: 0x000280 Link: 7 (.dynsym)
|
# GNU-NEXT: Addr: 0000000000000000 Offset: 0x000280 Link: 7 (.dynsym)
|
||||||
# GNU-NEXT: 000: 0 (*local*) 2 (VERSION1) 3 (VERSION2) 4 (v1)
|
# GNU-NEXT: 000: 0 (*local*) 2 (VERSION1) 3 (VERSION2) 4 (v1)
|
||||||
# GNU-NEXT: 004: 5 (v2) 6 (v3)
|
# GNU-NEXT: 004: 5 (v2) 6 (v3)
|
||||||
|
# GNU-EMPTY:
|
||||||
# GNU: Dumper for .gnu.version_d is not implemented
|
# GNU-NEXT: Dumper for .gnu.version_d is not implemented
|
||||||
# GNU: Dumper for .gnu.version_r is not implemented
|
# GNU-EMPTY:
|
||||||
|
# GNU-NEXT: Version needs section '.gnu.version_r' contains 2 entries:
|
||||||
|
# GNU-NEXT: Addr: 0000000000000000 Offset: 0x0002cc Link: 8 (.dynstr)
|
||||||
|
# GNU-NEXT: 0x0000: Version: 1 File: verneed1.so.0 Cnt: 2
|
||||||
|
# GNU-NEXT: 0x0010: Name: v1 Flags: none Version: 4
|
||||||
|
# GNU-NEXT: 0x0020: Name: v2 Flags: none Version: 5
|
||||||
|
# GNU-NEXT: 0x0030: Version: 1 File: verneed2.so.0 Cnt: 1
|
||||||
|
# GNU-NEXT: 0x0040: Name: v3 Flags: none Version: 6
|
||||||
|
|
|
@ -3423,23 +3423,31 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class ELFT>
|
||||||
|
static void printGNUVersionSectionProlog(formatted_raw_ostream &OS,
|
||||||
|
const Twine &Name, unsigned EntriesNum,
|
||||||
|
const ELFFile<ELFT> *Obj,
|
||||||
|
const typename ELFT::Shdr *Sec) {
|
||||||
|
StringRef SecName = unwrapOrError(Obj->getSectionName(Sec));
|
||||||
|
OS << Name << " section '" << SecName << "' "
|
||||||
|
<< "contains " << EntriesNum << " entries:\n";
|
||||||
|
|
||||||
|
const typename ELFT::Shdr *SymTab =
|
||||||
|
unwrapOrError(Obj->getSection(Sec->sh_link));
|
||||||
|
StringRef SymTabName = unwrapOrError(Obj->getSectionName(SymTab));
|
||||||
|
OS << " Addr: " << format_hex_no_prefix(Sec->sh_addr, 16)
|
||||||
|
<< " Offset: " << format_hex(Sec->sh_offset, 8)
|
||||||
|
<< " Link: " << Sec->sh_link << " (" << SymTabName << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
void GNUStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj,
|
void GNUStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj,
|
||||||
const Elf_Shdr *Sec) {
|
const Elf_Shdr *Sec) {
|
||||||
if (!Sec)
|
if (!Sec)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
StringRef SecName = unwrapOrError(Obj->getSectionName(Sec));
|
unsigned Entries = Sec->sh_size / sizeof(Elf_Versym);
|
||||||
uint64_t Entries = Sec->sh_size / sizeof(Elf_Versym);
|
printGNUVersionSectionProlog(OS, "Version symbols", Entries, Obj, Sec);
|
||||||
|
|
||||||
OS << "Version symbols section '" << SecName << "' "
|
|
||||||
<< "contains " << Entries << " entries:\n";
|
|
||||||
|
|
||||||
const Elf_Shdr *SymTab = unwrapOrError(Obj->getSection(Sec->sh_link));
|
|
||||||
StringRef SymTabName = unwrapOrError(Obj->getSectionName(SymTab));
|
|
||||||
OS << " Addr: " << format_hex_no_prefix(Sec->sh_addr, 16)
|
|
||||||
<< " Offset: " << format_hex(Sec->sh_offset, 8)
|
|
||||||
<< " Link: " << Sec->sh_link << " (" << SymTabName << ")\n";
|
|
||||||
|
|
||||||
const uint8_t *VersymBuf =
|
const uint8_t *VersymBuf =
|
||||||
reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset);
|
reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset);
|
||||||
|
@ -3491,6 +3499,28 @@ void GNUStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj,
|
||||||
|
|
||||||
StringRef SecName = unwrapOrError(Obj->getSectionName(Sec));
|
StringRef SecName = unwrapOrError(Obj->getSectionName(Sec));
|
||||||
OS << "Dumper for " << SecName << " is not implemented\n";
|
OS << "Dumper for " << SecName << " is not implemented\n";
|
||||||
|
OS << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string verNeedFlagToString(unsigned Flags) {
|
||||||
|
if (Flags == 0)
|
||||||
|
return "none";
|
||||||
|
|
||||||
|
std::string Ret;
|
||||||
|
auto AddFlag = [&Ret, &Flags](unsigned Flag, StringRef Name) {
|
||||||
|
if (!(Flags & Flag))
|
||||||
|
return;
|
||||||
|
if (!Ret.empty())
|
||||||
|
Ret += " | ";
|
||||||
|
Ret += Name;
|
||||||
|
Flags &= ~Flag;
|
||||||
|
};
|
||||||
|
|
||||||
|
AddFlag(VER_FLG_BASE, "BASE");
|
||||||
|
AddFlag(VER_FLG_WEAK, "WEAK");
|
||||||
|
AddFlag(VER_FLG_INFO, "INFO");
|
||||||
|
AddFlag(~0, "<unknown>");
|
||||||
|
return Ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
|
@ -3499,8 +3529,42 @@ void GNUStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,
|
||||||
if (!Sec)
|
if (!Sec)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
StringRef SecName = unwrapOrError(Obj->getSectionName(Sec));
|
unsigned VerneedNum = Sec->sh_info;
|
||||||
OS << "Dumper for " << SecName << " is not implemented\n";
|
printGNUVersionSectionProlog(OS, "Version needs", VerneedNum, Obj, Sec);
|
||||||
|
|
||||||
|
ArrayRef<uint8_t> SecData = unwrapOrError(Obj->getSectionContents(Sec));
|
||||||
|
|
||||||
|
const Elf_Shdr *StrTabSec = unwrapOrError(Obj->getSection(Sec->sh_link));
|
||||||
|
StringRef StringTable = {
|
||||||
|
reinterpret_cast<const char *>(Obj->base() + StrTabSec->sh_offset),
|
||||||
|
StrTabSec->sh_size};
|
||||||
|
|
||||||
|
const uint8_t *VerneedBuf = SecData.data();
|
||||||
|
for (unsigned I = 0; I < VerneedNum; ++I) {
|
||||||
|
const Elf_Verneed *Verneed =
|
||||||
|
reinterpret_cast<const Elf_Verneed *>(VerneedBuf);
|
||||||
|
|
||||||
|
OS << format(" 0x%04x: Version: %u File: %s Cnt: %u\n",
|
||||||
|
reinterpret_cast<const uint8_t *>(Verneed) - SecData.begin(),
|
||||||
|
(unsigned)Verneed->vn_version,
|
||||||
|
StringTable.drop_front(Verneed->vn_file).data(),
|
||||||
|
(unsigned)Verneed->vn_cnt);
|
||||||
|
|
||||||
|
const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux;
|
||||||
|
for (unsigned J = 0; J < Verneed->vn_cnt; ++J) {
|
||||||
|
const Elf_Vernaux *Vernaux =
|
||||||
|
reinterpret_cast<const Elf_Vernaux *>(VernauxBuf);
|
||||||
|
|
||||||
|
OS << format(" 0x%04x: Name: %s Flags: %s Version: %u\n",
|
||||||
|
reinterpret_cast<const uint8_t *>(Vernaux) - SecData.begin(),
|
||||||
|
StringTable.drop_front(Vernaux->vna_name).data(),
|
||||||
|
verNeedFlagToString(Vernaux->vna_flags).c_str(),
|
||||||
|
(unsigned)Vernaux->vna_other);
|
||||||
|
VernauxBuf += Vernaux->vna_next;
|
||||||
|
}
|
||||||
|
VerneedBuf += Verneed->vn_next;
|
||||||
|
}
|
||||||
|
OS << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash histogram shows statistics of how efficient the hash was for the
|
// Hash histogram shows statistics of how efficient the hash was for the
|
||||||
|
|
Loading…
Reference in New Issue