void printNeededLibraries() override;
void printProgramHeaders() override;
void printHashTable() override;
+ void printGnuHashTable() override;
void printLoadName() override;
+ void printVersionInfo() override;
void printAttributes() override;
void printMipsPLTGOT() override;
typedef typename ELFO::Elf_Rela Elf_Rela;
typedef typename ELFO::Elf_Rela_Range Elf_Rela_Range;
typedef typename ELFO::Elf_Phdr Elf_Phdr;
+ typedef typename ELFO::Elf_Half Elf_Half;
typedef typename ELFO::Elf_Hash Elf_Hash;
+ typedef typename ELFO::Elf_GnuHash Elf_GnuHash;
typedef typename ELFO::Elf_Ehdr Elf_Ehdr;
typedef typename ELFO::Elf_Word Elf_Word;
typedef typename ELFO::uintX_t uintX_t;
typedef typename ELFO::Elf_Verneed Elf_Verneed;
typedef typename ELFO::Elf_Vernaux Elf_Vernaux;
typedef typename ELFO::Elf_Verdef Elf_Verdef;
+ typedef typename ELFO::Elf_Verdaux Elf_Verdaux;
/// \brief Represents a region described by entries in the .dynamic table.
struct DynRegionInfo {
error(Ret.getError());
return *Ret;
}
- Elf_Dyn_Range dynamic_table() const {
- ErrorOr<Elf_Dyn_Range> Ret = Obj->dynamic_table(DynamicProgHeader);
- error(Ret.getError());
- return *Ret;
- }
-
StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb,
bool &IsDefault);
void LoadVersionMap();
const Elf_Sym *DynSymStart = nullptr;
StringRef SOName;
const Elf_Hash *HashTable = nullptr;
+ const Elf_GnuHash *GnuHashTable = nullptr;
const Elf_Shdr *DotDynSymSec = nullptr;
const Elf_Shdr *DotSymtabSec = nullptr;
ArrayRef<Elf_Word> ShndxTable;
mutable SmallVector<VersionMapEntry, 16> VersionMap;
public:
+ Elf_Dyn_Range dynamic_table() const {
+ ErrorOr<Elf_Dyn_Range> Ret = Obj->dynamic_table(DynamicProgHeader);
+ error(Ret.getError());
+ return *Ret;
+ }
+
std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable,
bool IsDynamic);
const Elf_Shdr *getDotDynSymSec() const { return DotDynSymSec; }
LoadVersionNeeds(dot_gnu_version_r_sec);
}
+
+template <typename ELFO, class ELFT>
+static void printVersionSymbolSection(ELFDumper<ELFT> *Dumper,
+ const ELFO *Obj,
+ const typename ELFO::Elf_Shdr *Sec,
+ StreamWriter &W) {
+ DictScope SS(W, "Version symbols");
+ if (!Sec)
+ return;
+ StringRef Name = errorOrDefault(Obj->getSectionName(Sec));
+ W.printNumber("Section Name", Name, Sec->sh_name);
+ W.printHex("Address", Sec->sh_addr);
+ W.printHex("Offset", Sec->sh_offset);
+ W.printNumber("Link", Sec->sh_link);
+
+ const typename ELFO::Elf_Shdr *DynSymSec = Dumper->getDotDynSymSec();
+ const uint8_t *P = (const uint8_t *)Obj->base() + Sec->sh_offset;
+ ErrorOr<StringRef> StrTableOrErr =
+ Obj->getStringTableForSymtab(*DynSymSec);
+ error(StrTableOrErr.getError());
+
+ // Same number of entries in the dynamic symbol table (DT_SYMTAB).
+ ListScope Syms(W, "Symbols");
+ for (const typename ELFO::Elf_Sym &Sym : Obj->symbols(DynSymSec)) {
+ DictScope S(W, "Symbol");
+ std::string FullSymbolName =
+ Dumper->getFullSymbolName(&Sym, *StrTableOrErr, true /* IsDynamic */);
+ W.printNumber("Version", *P);
+ W.printString("Name", FullSymbolName);
+ P += sizeof(typename ELFO::Elf_Half);
+ }
+}
+
+template <typename ELFO, class ELFT>
+static void printVersionDefinitionSection(ELFDumper<ELFT> *Dumper,
+ const ELFO *Obj,
+ const typename ELFO::Elf_Shdr *Sec,
+ StreamWriter &W) {
+ DictScope SD(W, "Version definition");
+ if (!Sec)
+ return;
+ StringRef Name = errorOrDefault(Obj->getSectionName(Sec));
+ W.printNumber("Section Name", Name, Sec->sh_name);
+ W.printHex("Address", Sec->sh_addr);
+ W.printHex("Offset", Sec->sh_offset);
+ W.printNumber("Link", Sec->sh_link);
+
+ unsigned verdef_entries = 0;
+ // The number of entries in the section SHT_GNU_verdef
+ // is determined by DT_VERDEFNUM tag.
+ for (const typename ELFO::Elf_Dyn &Dyn : Dumper->dynamic_table()) {
+ if (Dyn.d_tag == DT_VERDEFNUM)
+ verdef_entries = Dyn.d_un.d_val;
+ }
+ const uint8_t *SecStartAddress =
+ (const uint8_t *)Obj->base() + Sec->sh_offset;
+ const uint8_t *SecEndAddress = SecStartAddress + Sec->sh_size;
+ const uint8_t *P = SecStartAddress;
+ ErrorOr<const typename ELFO::Elf_Shdr *> StrTabOrErr =
+ Obj->getSection(Sec->sh_link);
+ error(StrTabOrErr.getError());
+
+ ListScope Entries(W, "Entries");
+ for (unsigned i = 0; i < verdef_entries; ++i) {
+ if (P + sizeof(typename ELFO::Elf_Verdef) > SecEndAddress)
+ report_fatal_error("invalid offset in the section");
+ auto *VD = reinterpret_cast<const typename ELFO::Elf_Verdef *>(P);
+ DictScope Entry(W, "Entry");
+ W.printHex("Offset", (uintptr_t)P - (uintptr_t)SecStartAddress);
+ W.printNumber("Rev", VD->vd_version);
+ // FIXME: print something more readable.
+ W.printNumber("Flags", VD->vd_flags);
+ W.printNumber("Index", VD->vd_ndx);
+ W.printNumber("Cnt", VD->vd_cnt);
+ W.printString("Name", StringRef((const char *)(Obj->base() +
+ (*StrTabOrErr)->sh_offset +
+ VD->getAux()->vda_name)));
+ P += VD->vd_next;
+ }
+}
+
+template <typename ELFT> void ELFDumper<ELFT>::printVersionInfo() {
+ // Dump version symbol section.
+ printVersionSymbolSection(this, Obj, dot_gnu_version_sec, W);
+
+ // Dump version definition section.
+ printVersionDefinitionSection(this, Obj, dot_gnu_version_d_sec, W);
+}
+
template <typename ELFT>
StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab,
const Elf_Sym *symb,
if (entry.isVerdef()) {
// The first Verdaux entry holds the name.
name_offset = entry.getVerdef()->getAux()->vda_name;
- } else {
- name_offset = entry.getVernaux()->vna_name;
- }
-
- // Set IsDefault
- if (entry.isVerdef()) {
IsDefault = !(vs->vs_index & ELF::VERSYM_HIDDEN);
} else {
+ name_offset = entry.getVernaux()->vna_name;
IsDefault = false;
}
-
if (name_offset >= StrTab.size())
reportError("Invalid string offset");
return StringRef(StrTab.data() + name_offset);
HashTable =
reinterpret_cast<const Elf_Hash *>(toMappedAddr(Dyn.getPtr()));
break;
+ case ELF::DT_GNU_HASH:
+ GnuHashTable =
+ reinterpret_cast<const Elf_GnuHash *>(toMappedAddr(Dyn.getPtr()));
+ break;
case ELF::DT_RELA:
DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr());
break;
template<class ELFT>
void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) {
const Elf_Shdr *Symtab = (IsDynamic) ? DotDynSymSec : DotSymtabSec;
+ if (!Symtab)
+ return;
ErrorOr<StringRef> StrTableOrErr = Obj->getStringTableForSymtab(*Symtab);
error(StrTableOrErr.getError());
StringRef StrTable = *StrTableOrErr;
LLVM_READOBJ_TYPE_CASE(SYMENT);
LLVM_READOBJ_TYPE_CASE(SYMTAB);
LLVM_READOBJ_TYPE_CASE(TEXTREL);
+ LLVM_READOBJ_TYPE_CASE(VERDEF);
+ LLVM_READOBJ_TYPE_CASE(VERDEFNUM);
LLVM_READOBJ_TYPE_CASE(VERNEED);
LLVM_READOBJ_TYPE_CASE(VERNEEDNUM);
LLVM_READOBJ_TYPE_CASE(VERSYM);
case DT_FINI_ARRAY:
case DT_PREINIT_ARRAY:
case DT_DEBUG:
+ case DT_VERDEF:
case DT_VERNEED:
case DT_VERSYM:
case DT_GNU_HASH:
OS << format("0x%" PRIX64, Value);
break;
case DT_RELCOUNT:
+ case DT_VERDEFNUM:
case DT_VERNEEDNUM:
case DT_MIPS_RLD_VERSION:
case DT_MIPS_LOCAL_GOTNO:
<< " " << "Name/Value\n";
while (I != E) {
const Elf_Dyn &Entry = *I;
+ uintX_t Tag = Entry.getTag();
++I;
- W.startLine()
- << " "
- << format(Is64 ? "0x%016" PRIX64 : "0x%08" PRIX64, Entry.getTag())
- << " " << format("%-21s", getTypeString(Entry.getTag()));
- printValue(Entry.getTag(), Entry.getVal());
+ W.startLine() << " " << format_hex(Tag, Is64 ? 18 : 10, true) << " "
+ << format("%-21s", getTypeString(Tag));
+ printValue(Tag, Entry.getVal());
OS << "\n";
}
W.printList("Chains", HashTable->chains());
}
+template <typename ELFT>
+void ELFDumper<ELFT>::printGnuHashTable() {
+ DictScope D(W, "GnuHashTable");
+ if (!GnuHashTable)
+ return;
+ W.printNumber("Num Buckets", GnuHashTable->nbuckets);
+ W.printNumber("First Hashed Symbol Index", GnuHashTable->symndx);
+ W.printNumber("Num Mask Words", GnuHashTable->maskwords);
+ W.printNumber("Shift Count", GnuHashTable->shift2);
+ W.printHexList("Bloom Filter", GnuHashTable->filter());
+ W.printList("Buckets", GnuHashTable->buckets());
+ if (!DotDynSymSec)
+ reportError("No dynamic symbol section");
+ W.printHexList("Values",
+ GnuHashTable->values(DotDynSymSec->getEntityCount()));
+}
+
template <typename ELFT> void ELFDumper<ELFT>::printLoadName() {
outs() << "LoadName: " << SOName << '\n';
}