summaryrefslogtreecommitdiffstats
path: root/llvm/tools/llvm-readobj
diff options
context:
space:
mode:
authorDavide Italiano <davide@freebsd.org>2015-10-16 23:19:01 +0000
committerDavide Italiano <davide@freebsd.org>2015-10-16 23:19:01 +0000
commit4f05f32bb7f1c9a640d959fac9a0f8dd7edd4776 (patch)
tree3ea0539b3096ed52d0549b18a2b9a410ad839d8d /llvm/tools/llvm-readobj
parent91c7321ea9d5ce8248dbe75fe2b32830eb99e061 (diff)
downloadbcm5719-llvm-4f05f32bb7f1c9a640d959fac9a0f8dd7edd4776.tar.gz
bcm5719-llvm-4f05f32bb7f1c9a640d959fac9a0f8dd7edd4776.zip
[llvm-readobj] Teach ELFDumper about symbol versioning.
Differential Revision: http://reviews.llvm.org/D13824 llvm-svn: 250575
Diffstat (limited to 'llvm/tools/llvm-readobj')
-rw-r--r--llvm/tools/llvm-readobj/ELFDumper.cpp103
-rw-r--r--llvm/tools/llvm-readobj/ObjDumper.h1
-rw-r--r--llvm/tools/llvm-readobj/llvm-readobj.cpp8
3 files changed, 106 insertions, 6 deletions
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 5b4a78cf52f..fa4bf36925a 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -58,6 +58,7 @@ public:
void printHashTable() override;
void printGnuHashTable() override;
void printLoadName() override;
+ void printVersionInfo() override;
void printAttributes() override;
void printMipsPLTGOT() override;
@@ -76,6 +77,7 @@ private:
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;
@@ -85,6 +87,7 @@ private:
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 {
@@ -119,12 +122,6 @@ private:
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();
@@ -171,6 +168,12 @@ private:
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; }
@@ -302,6 +305,94 @@ template <class ELFT> void ELFDumper<ELFT>::LoadVersionMap() {
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();
+ uint8_t *P = (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;
+ }
+ uint8_t *SecStartAddress = (uint8_t *)Obj->base() + Sec->sh_offset;
+ uint8_t *SecEndAddress = SecStartAddress + Sec->sh_size;
+ 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((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,
diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h
index 79c25828304..2ca1300439e 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/llvm/tools/llvm-readobj/ObjDumper.h
@@ -41,6 +41,7 @@ public:
virtual void printHashTable() { }
virtual void printGnuHashTable() { }
virtual void printLoadName() {}
+ virtual void printVersionInfo() {}
// Only implemented for ARM ELF at this time.
virtual void printAttributes() { }
diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp
index 3b40d5335ca..cb0c9c6418e 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -221,6 +221,12 @@ namespace opts {
PrintStackMap("stackmap",
cl::desc("Display contents of stackmap section"));
+ // -version-info
+ cl::opt<bool>
+ VersionInfo("version-info",
+ cl::desc("Display ELF version sections (if present)"));
+ cl::alias VersionInfoShort("V", cl::desc("Alias for -version-info"),
+ cl::aliasopt(VersionInfo));
} // namespace opts
namespace llvm {
@@ -328,6 +334,8 @@ static void dumpObject(const ObjectFile *Obj) {
Dumper->printHashTable();
if (opts::GnuHashTable)
Dumper->printGnuHashTable();
+ if (opts::VersionInfo)
+ Dumper->printVersionInfo();
if (Obj->getArch() == llvm::Triple::arm && Obj->isELF())
if (opts::ARMAttributes)
Dumper->printAttributes();
OpenPOWER on IntegriCloud