aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael J. Spencer <bigcheesegs@gmail.com>2013-02-20 02:37:12 +0000
committerMichael J. Spencer <bigcheesegs@gmail.com>2013-02-20 02:37:12 +0000
commitd326d05fb9c794e93fc7fc0601028f196600f7e2 (patch)
treecf029adfcba0f251aac254aae9fc6510852a7560
parent7cc098d805b3c294e842f8ceea3e5e55652f33f9 (diff)
[llvm-readobj] Add ELF .dynamic table dumping.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@175592 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/Object/ELF.h49
-rw-r--r--test/Object/readobj-shared-object.test13
-rw-r--r--tools/llvm-readobj/CMakeLists.txt1
-rw-r--r--tools/llvm-readobj/ELF.cpp196
-rw-r--r--tools/llvm-readobj/llvm-readobj.cpp9
-rw-r--r--tools/llvm-readobj/llvm-readobj.h22
6 files changed, 281 insertions, 9 deletions
diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h
index bd3bbe1e4f..36e35f5748 100644
--- a/include/llvm/Object/ELF.h
+++ b/include/llvm/Object/ELF.h
@@ -471,9 +471,9 @@ public:
template<class EntT>
class ELFEntityIterator {
public:
- typedef void difference_type;
+ typedef ptrdiff_t difference_type;
typedef EntT value_type;
- typedef std::forward_iterator_tag iterator_category;
+ typedef std::random_access_iterator_tag iterator_category;
typedef value_type &reference;
typedef value_type *pointer;
@@ -513,10 +513,22 @@ public:
return Tmp;
}
+ ELFEntityIterator &operator =(const ELFEntityIterator &Other) {
+ EntitySize = Other.EntitySize;
+ Current = Other.Current;
+ return *this;
+ }
+
+ difference_type operator -(const ELFEntityIterator &Other) const {
+ assert(EntitySize == Other.EntitySize &&
+ "Subtracting iterators of different EntitiySize!");
+ return (Current - Other.Current) / EntitySize;
+ }
+
const char *get() const { return Current; }
private:
- const uint64_t EntitySize;
+ uint64_t EntitySize;
const char *Current;
};
@@ -605,6 +617,7 @@ private:
return getSection(Rel.w.b);
}
+public:
bool isRelocationHasAddend(DataRefImpl Rel) const;
template<typename T>
const T *getEntry(uint16_t Section, uint32_t Entry) const;
@@ -706,8 +719,14 @@ public:
return SymbolTableSections[0];
}
+ const Elf_Shdr *getDynamicStringTableSectionHeader() const {
+ return dot_dynstr_sec;
+ }
+
Elf_Dyn_iterator begin_dynamic_table() const;
- Elf_Dyn_iterator end_dynamic_table() const;
+ /// \param NULLEnd use one past the first DT_NULL entry as the end instead of
+ /// the section size.
+ Elf_Dyn_iterator end_dynamic_table(bool NULLEnd = false) const;
Elf_Sym_iterator begin_elf_dynamic_symbols() const {
const Elf_Shdr *DynSymtab = SymbolTableSections[0];
@@ -2276,11 +2295,23 @@ ELFObjectFile<ELFT>::begin_dynamic_table() const {
template<class ELFT>
typename ELFObjectFile<ELFT>::Elf_Dyn_iterator
-ELFObjectFile<ELFT>::end_dynamic_table() const {
- if (dot_dynamic_sec)
- return Elf_Dyn_iterator(dot_dynamic_sec->sh_entsize,
- (const char *)base() + dot_dynamic_sec->sh_offset +
- dot_dynamic_sec->sh_size);
+ELFObjectFile<ELFT>::end_dynamic_table(bool NULLEnd) const {
+ if (dot_dynamic_sec) {
+ Elf_Dyn_iterator Ret(dot_dynamic_sec->sh_entsize,
+ (const char *)base() + dot_dynamic_sec->sh_offset +
+ dot_dynamic_sec->sh_size);
+
+ if (NULLEnd) {
+ Elf_Dyn_iterator Start = begin_dynamic_table();
+ for (; Start != Ret && Start->getTag() != ELF::DT_NULL; ++Start)
+ ;
+ // Include the DT_NULL.
+ if (Start != Ret)
+ ++Start;
+ Ret = Start;
+ }
+ return Ret;
+ }
return Elf_Dyn_iterator(0, 0);
}
diff --git a/test/Object/readobj-shared-object.test b/test/Object/readobj-shared-object.test
index 3065c6f636..2c0b54dca4 100644
--- a/test/Object/readobj-shared-object.test
+++ b/test/Object/readobj-shared-object.test
@@ -71,6 +71,19 @@ ELF: .symtab {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} r
ELF: .strtab {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} rodata
ELF: Total: 14
+ELF:Dynamic section contains 9 entries
+ELF: Tag Type Name/Value
+ELF: 00000001 (NEEDED) Shared library: [libc.so.6]
+ELF: 00000001 (NEEDED) Shared library: [libm.so.6]
+ELF: 0000000e (SONAME) Library soname: [libfoo.so]
+ELF: 00000004 (HASH) {{[0-9a-f]+}}
+ELF: 00000005 (STRTAB) {{[0-9a-f]+}}
+ELF: 00000006 (SYMTAB) {{[0-9a-f]+}}
+ELF: 0000000a (STRSZ) {{[0-9]+}} (bytes)
+ELF: 0000000b (SYMENT) {{[0-9]+}} (bytes)
+ELF: 00000000 (NULL) 0x0
+ELF: Total: 9
+
ELF:Libraries needed:
ELF: libc.so.6
ELF: libm.so.6
diff --git a/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt
index be80469f28..676c23d7ae 100644
--- a/tools/llvm-readobj/CMakeLists.txt
+++ b/tools/llvm-readobj/CMakeLists.txt
@@ -1,5 +1,6 @@
set(LLVM_LINK_COMPONENTS archive bitreader object)
add_llvm_tool(llvm-readobj
+ ELF.cpp
llvm-readobj.cpp
)
diff --git a/tools/llvm-readobj/ELF.cpp b/tools/llvm-readobj/ELF.cpp
new file mode 100644
index 0000000000..07f15b3a6d
--- /dev/null
+++ b/tools/llvm-readobj/ELF.cpp
@@ -0,0 +1,196 @@
+//===- llvm-readobj/ELF.cpp - ELF Specific Dumper -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-readobj.h"
+
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Format.h"
+
+namespace llvm {
+using namespace object;
+using namespace ELF;
+
+const char *getTypeString(uint64_t Type) {
+ switch (Type) {
+ case DT_BIND_NOW:
+ return "(BIND_NOW)";
+ case DT_DEBUG:
+ return "(DEBUG)";
+ case DT_FINI:
+ return "(FINI)";
+ case DT_FINI_ARRAY:
+ return "(FINI_ARRAY)";
+ case DT_FINI_ARRAYSZ:
+ return "(FINI_ARRAYSZ)";
+ case DT_FLAGS:
+ return "(FLAGS)";
+ case DT_HASH:
+ return "(HASH)";
+ case DT_INIT:
+ return "(INIT)";
+ case DT_INIT_ARRAY:
+ return "(INIT_ARRAY)";
+ case DT_INIT_ARRAYSZ:
+ return "(INIT_ARRAYSZ)";
+ case DT_PREINIT_ARRAY:
+ return "(PREINIT_ARRAY)";
+ case DT_PREINIT_ARRAYSZ:
+ return "(PREINIT_ARRAYSZ)";
+ case DT_JMPREL:
+ return "(JMPREL)";
+ case DT_NEEDED:
+ return "(NEEDED)";
+ case DT_NULL:
+ return "(NULL)";
+ case DT_PLTGOT:
+ return "(PLTGOT)";
+ case DT_PLTREL:
+ return "(PLTREL)";
+ case DT_PLTRELSZ:
+ return "(PLTRELSZ)";
+ case DT_REL:
+ return "(REL)";
+ case DT_RELA:
+ return "(RELA)";
+ case DT_RELENT:
+ return "(RELENT)";
+ case DT_RELSZ:
+ return "(RELSZ)";
+ case DT_RELAENT:
+ return "(RELAENT)";
+ case DT_RELASZ:
+ return "(RELASZ)";
+ case DT_RPATH:
+ return "(RPATH)";
+ case DT_RUNPATH:
+ return "(RUNPATH)";
+ case DT_SONAME:
+ return "(SONAME)";
+ case DT_STRSZ:
+ return "(STRSZ)";
+ case DT_STRTAB:
+ return "(STRTAB)";
+ case DT_SYMBOLIC:
+ return "(SYMBOLIC)";
+ case DT_SYMENT:
+ return "(SYMENT)";
+ case DT_SYMTAB:
+ return "(SYMTAB)";
+ case DT_TEXTREL:
+ return "(TEXTREL)";
+ default:
+ return "unknown";
+ }
+}
+
+template <class ELFT>
+void printValue(const ELFObjectFile<ELFT> *O, uint64_t Type, uint64_t Value,
+ bool Is64, raw_ostream &OS) {
+ switch (Type) {
+ case DT_PLTREL:
+ if (Value == DT_REL) {
+ OS << "REL";
+ break;
+ } else if (Value == DT_RELA) {
+ OS << "RELA";
+ break;
+ }
+ // Fallthrough.
+ case DT_PLTGOT:
+ case DT_HASH:
+ case DT_STRTAB:
+ case DT_SYMTAB:
+ case DT_RELA:
+ case DT_INIT:
+ case DT_FINI:
+ case DT_REL:
+ case DT_JMPREL:
+ case DT_INIT_ARRAY:
+ case DT_FINI_ARRAY:
+ case DT_PREINIT_ARRAY:
+ case DT_DEBUG:
+ case DT_NULL:
+ OS << format("0x%" PRIx64, Value);
+ break;
+ case DT_PLTRELSZ:
+ case DT_RELASZ:
+ case DT_RELAENT:
+ case DT_STRSZ:
+ case DT_SYMENT:
+ case DT_RELSZ:
+ case DT_RELENT:
+ case DT_INIT_ARRAYSZ:
+ case DT_FINI_ARRAYSZ:
+ case DT_PREINIT_ARRAYSZ:
+ OS << Value << " (bytes)";
+ break;
+ case DT_NEEDED:
+ OS << "Shared library: ["
+ << O->getString(O->getDynamicStringTableSectionHeader(), Value) << "]";
+ break;
+ case DT_SONAME:
+ OS << "Library soname: ["
+ << O->getString(O->getDynamicStringTableSectionHeader(), Value) << "]";
+ break;
+ }
+}
+
+template <class ELFT>
+ErrorOr<void> dumpDynamicTable(const ELFObjectFile<ELFT> *O, raw_ostream &OS) {
+ typedef ELFObjectFile<ELFT> ELFO;
+ typedef typename ELFO::Elf_Dyn_iterator EDI;
+ EDI Start = O->begin_dynamic_table(),
+ End = O->end_dynamic_table(true);
+
+ if (Start == End)
+ return error_code::success();
+
+ ptrdiff_t Total = std::distance(Start, End);
+ OS << "Dynamic section contains " << Total << " entries\n";
+
+ bool Is64 = O->getBytesInAddress() == 8;
+
+ OS << " Tag" << (Is64 ? " " : " ") << "Type"
+ << " " << "Name/Value\n";
+ for (; Start != End; ++Start) {
+ OS << " "
+ << format(Is64 ? "0x%016" PRIx64 : "0x%08" PRIx64, Start->getTag())
+ << " " << format("%-21s", getTypeString(Start->getTag()));
+ printValue(O, Start->getTag(), Start->getVal(), Is64, OS);
+ OS << "\n";
+ }
+
+ OS << " Total: " << Total << "\n\n";
+ return error_code::success();
+}
+
+ErrorOr<void> dumpELFDynamicTable(ObjectFile *O, raw_ostream &OS) {
+ // Little-endian 32-bit
+ if (const ELFObjectFile<ELFType<support::little, 4, false> > *ELFObj =
+ dyn_cast<ELFObjectFile<ELFType<support::little, 4, false> > >(O))
+ return dumpDynamicTable(ELFObj, OS);
+
+ // Big-endian 32-bit
+ if (const ELFObjectFile<ELFType<support::big, 4, false> > *ELFObj =
+ dyn_cast<ELFObjectFile<ELFType<support::big, 4, false> > >(O))
+ return dumpDynamicTable(ELFObj, OS);
+
+ // Little-endian 64-bit
+ if (const ELFObjectFile<ELFType<support::little, 8, true> > *ELFObj =
+ dyn_cast<ELFObjectFile<ELFType<support::little, 8, true> > >(O))
+ return dumpDynamicTable(ELFObj, OS);
+
+ // Big-endian 64-bit
+ if (const ELFObjectFile<ELFType<support::big, 8, true> > *ELFObj =
+ dyn_cast<ELFObjectFile<ELFType<support::big, 8, true> > >(O))
+ return dumpDynamicTable(ELFObj, OS);
+ return error_code(object_error::invalid_file_type);
+}
+} // end namespace llvm
diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp
index 0a43775ef2..8f0917fc91 100644
--- a/tools/llvm-readobj/llvm-readobj.cpp
+++ b/tools/llvm-readobj/llvm-readobj.cpp
@@ -19,6 +19,8 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm-readobj.h"
+
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Object/ELF.h"
@@ -263,6 +265,13 @@ int main(int argc, char** argv) {
dump(obj, &dumpSection, obj->begin_sections(), obj->end_sections(),
"Section iteration failed");
+ if (obj->isELF()) {
+ if (ErrorOr<void> e = dumpELFDynamicTable(obj, outs()))
+ ;
+ else
+ errs() << "InputFilename" << ": " << error_code(e).message() << "\n";
+ }
+
outs() << "Libraries needed:\n";
dump(obj, &dumpLibrary, obj->begin_libraries_needed(),
obj->end_libraries_needed(), "Needed libraries iteration failed");
diff --git a/tools/llvm-readobj/llvm-readobj.h b/tools/llvm-readobj/llvm-readobj.h
new file mode 100644
index 0000000000..cf492b2a8d
--- /dev/null
+++ b/tools/llvm-readobj/llvm-readobj.h
@@ -0,0 +1,22 @@
+//===- llvm-readobj.h - Dump contents of an Object File -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_READ_OBJ_H
+#define LLVM_TOOLS_READ_OBJ_H
+
+#include "llvm/Support/ErrorOr.h"
+
+namespace llvm {
+namespace object { class ObjectFile; }
+class raw_ostream;
+
+ErrorOr<void> dumpELFDynamicTable(object::ObjectFile *O, raw_ostream &OS);
+} // end namespace llvm
+
+#endif