summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorEric Christopher <echristo@gmail.com>2013-04-03 18:31:38 +0000
committerEric Christopher <echristo@gmail.com>2013-04-03 18:31:38 +0000
commit76e70f340c09ba759ad96d8dfe416b64f24bc287 (patch)
treeac6cbe6235f9bf391026db87c52a0d617d35c9ba /tools
parent99ff2ba240979249b61514c1536bbe23be84ecc7 (diff)
downloadllvm-76e70f340c09ba759ad96d8dfe416b64f24bc287.tar.gz
llvm-76e70f340c09ba759ad96d8dfe416b64f24bc287.tar.bz2
llvm-76e70f340c09ba759ad96d8dfe416b64f24bc287.tar.xz
Implements low-level object file format specific output for COFF and
ELF with support for: - File headers - Section headers + data - Relocations - Symbols - Unwind data (only COFF/Win64) The output format follows a few rules: - Values are almost always output one per line (as elf-dump/coff-dump already do). - Many values are translated to something readable (like enum names), with the raw value in parentheses. - Hex numbers are output in uppercase, prefixed with "0x". - Flags are sorted alphabetically. - Lists and groups are always delimited. Example output: ---------- snip ---------- Sections [ Section { Index: 1 Name: .text (5) Type: SHT_PROGBITS (0x1) Flags [ (0x6) SHF_ALLOC (0x2) SHF_EXECINSTR (0x4) ] Address: 0x0 Offset: 0x40 Size: 33 Link: 0 Info: 0 AddressAlignment: 16 EntrySize: 0 Relocations [ 0x6 R_386_32 .rodata.str1.1 0x0 0xB R_386_PC32 puts 0x0 0x12 R_386_32 .rodata.str1.1 0x0 0x17 R_386_PC32 puts 0x0 ] SectionData ( 0000: 83EC04C7 04240000 0000E8FC FFFFFFC7 |.....$..........| 0010: 04240600 0000E8FC FFFFFF31 C083C404 |.$.........1....| 0020: C3 |.| ) } ] ---------- snip ---------- Relocations and symbols can be output standalone or together with the section header as displayed in the example. This feature set supports all tests in test/MC/COFF and test/MC/ELF (and I suspect all additional tests using elf-dump), making elf-dump and coff-dump deprecated. Patch by Nico Rieck! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@178679 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools')
-rw-r--r--tools/llvm-readobj/CMakeLists.txt13
-rw-r--r--tools/llvm-readobj/COFFDumper.cpp1014
-rw-r--r--tools/llvm-readobj/ELF.cpp196
-rw-r--r--tools/llvm-readobj/ELFDumper.cpp800
-rw-r--r--tools/llvm-readobj/Error.cpp62
-rw-r--r--tools/llvm-readobj/Error.h48
-rw-r--r--tools/llvm-readobj/LLVMBuild.txt2
-rw-r--r--tools/llvm-readobj/MachODumper.cpp438
-rw-r--r--tools/llvm-readobj/Makefile2
-rw-r--r--tools/llvm-readobj/ObjDumper.cpp33
-rw-r--r--tools/llvm-readobj/ObjDumper.h60
-rw-r--r--tools/llvm-readobj/StreamWriter.cpp79
-rw-r--r--tools/llvm-readobj/StreamWriter.h282
-rw-r--r--tools/llvm-readobj/llvm-readobj.cpp435
-rw-r--r--tools/llvm-readobj/llvm-readobj.h35
15 files changed, 3073 insertions, 426 deletions
diff --git a/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt
index 676c23d7ae..3d20def8f5 100644
--- a/tools/llvm-readobj/CMakeLists.txt
+++ b/tools/llvm-readobj/CMakeLists.txt
@@ -1,6 +1,15 @@
-set(LLVM_LINK_COMPONENTS archive bitreader object)
+set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ archive
+ bitreader
+ object)
add_llvm_tool(llvm-readobj
- ELF.cpp
llvm-readobj.cpp
+ ObjDumper.cpp
+ COFFDumper.cpp
+ ELFDumper.cpp
+ MachODumper.cpp
+ Error.cpp
+ StreamWriter.cpp
)
diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp
new file mode 100644
index 0000000000..be4e76cc63
--- /dev/null
+++ b/tools/llvm-readobj/COFFDumper.cpp
@@ -0,0 +1,1014 @@
+//===-- COFFDumper.cpp - COFF-specific dumper -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements the COFF-specific dumper for llvm-readobj.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm-readobj.h"
+#include "ObjDumper.h"
+
+#include "Error.h"
+#include "StreamWriter.h"
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/Win64EH.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+
+#include <algorithm>
+#include <cstring>
+#include <time.h>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::Win64EH;
+
+namespace {
+
+class COFFDumper : public ObjDumper {
+public:
+ COFFDumper(const llvm::object::COFFObjectFile *Obj, StreamWriter& Writer)
+ : ObjDumper(Writer)
+ , Obj(Obj) {
+ cacheRelocations();
+ }
+
+ virtual void printFileHeaders() LLVM_OVERRIDE;
+ virtual void printSections() LLVM_OVERRIDE;
+ virtual void printRelocations() LLVM_OVERRIDE;
+ virtual void printSymbols() LLVM_OVERRIDE;
+ virtual void printDynamicSymbols() LLVM_OVERRIDE;
+ virtual void printUnwindInfo() LLVM_OVERRIDE;
+
+private:
+ void printSymbol(symbol_iterator SymI);
+
+ void printRelocation(section_iterator SecI, relocation_iterator RelI);
+
+ void printX64UnwindInfo();
+
+ void printRuntimeFunction(
+ const RuntimeFunction& RTF,
+ uint64_t OffsetInSection,
+ const std::vector<RelocationRef> &Rels);
+
+ void printUnwindInfo(
+ const Win64EH::UnwindInfo& UI,
+ uint64_t OffsetInSection,
+ const std::vector<RelocationRef> &Rels);
+
+ void printUnwindCode(const Win64EH::UnwindInfo& UI, ArrayRef<UnwindCode> UCs);
+
+ void cacheRelocations();
+
+ error_code getSectionContents(
+ const std::vector<RelocationRef> &Rels,
+ uint64_t Offset,
+ ArrayRef<uint8_t> &Contents,
+ uint64_t &Addr);
+
+ error_code getSection(
+ const std::vector<RelocationRef> &Rels,
+ uint64_t Offset,
+ const coff_section **Section,
+ uint64_t *AddrPtr);
+
+ typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy;
+
+ const llvm::object::COFFObjectFile *Obj;
+ RelocMapTy RelocMap;
+ std::vector<RelocationRef> EmptyRelocs;
+};
+
+} // namespace
+
+
+namespace llvm {
+
+error_code createCOFFDumper(const object::ObjectFile *Obj,
+ StreamWriter& Writer,
+ OwningPtr<ObjDumper> &Result) {
+ const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(Obj);
+ if (!COFFObj)
+ return readobj_error::unsupported_obj_file_format;
+
+ Result.reset(new COFFDumper(COFFObj, Writer));
+ return readobj_error::success;
+}
+
+} // namespace llvm
+
+
+// Returns the name of the unwind code.
+static StringRef getUnwindCodeTypeName(uint8_t Code) {
+ switch(Code) {
+ default: llvm_unreachable("Invalid unwind code");
+ case UOP_PushNonVol: return "PUSH_NONVOL";
+ case UOP_AllocLarge: return "ALLOC_LARGE";
+ case UOP_AllocSmall: return "ALLOC_SMALL";
+ case UOP_SetFPReg: return "SET_FPREG";
+ case UOP_SaveNonVol: return "SAVE_NONVOL";
+ case UOP_SaveNonVolBig: return "SAVE_NONVOL_FAR";
+ case UOP_SaveXMM128: return "SAVE_XMM128";
+ case UOP_SaveXMM128Big: return "SAVE_XMM128_FAR";
+ case UOP_PushMachFrame: return "PUSH_MACHFRAME";
+ }
+}
+
+// Returns the name of a referenced register.
+static StringRef getUnwindRegisterName(uint8_t Reg) {
+ switch(Reg) {
+ default: llvm_unreachable("Invalid register");
+ case 0: return "RAX";
+ case 1: return "RCX";
+ case 2: return "RDX";
+ case 3: return "RBX";
+ case 4: return "RSP";
+ case 5: return "RBP";
+ case 6: return "RSI";
+ case 7: return "RDI";
+ case 8: return "R8";
+ case 9: return "R9";
+ case 10: return "R10";
+ case 11: return "R11";
+ case 12: return "R12";
+ case 13: return "R13";
+ case 14: return "R14";
+ case 15: return "R15";
+ }
+}
+
+// Calculates the number of array slots required for the unwind code.
+static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
+ switch (UnwindCode.getUnwindOp()) {
+ default: llvm_unreachable("Invalid unwind code");
+ case UOP_PushNonVol:
+ case UOP_AllocSmall:
+ case UOP_SetFPReg:
+ case UOP_PushMachFrame:
+ return 1;
+ case UOP_SaveNonVol:
+ case UOP_SaveXMM128:
+ return 2;
+ case UOP_SaveNonVolBig:
+ case UOP_SaveXMM128Big:
+ return 3;
+ case UOP_AllocLarge:
+ return (UnwindCode.getOpInfo() == 0) ? 2 : 3;
+ }
+}
+
+// Given a symbol sym this functions returns the address and section of it.
+static error_code resolveSectionAndAddress(const COFFObjectFile *Obj,
+ const SymbolRef &Sym,
+ const coff_section *&ResolvedSection,
+ uint64_t &ResolvedAddr) {
+ if (error_code EC = Sym.getAddress(ResolvedAddr))
+ return EC;
+
+ section_iterator iter(Obj->begin_sections());
+ if (error_code EC = Sym.getSection(iter))
+ return EC;
+
+ ResolvedSection = Obj->getCOFFSection(iter);
+ return object_error::success;
+}
+
+// Given a vector of relocations for a section and an offset into this section
+// the function returns the symbol used for the relocation at the offset.
+static error_code resolveSymbol(const std::vector<RelocationRef> &Rels,
+ uint64_t Offset, SymbolRef &Sym) {
+ for (std::vector<RelocationRef>::const_iterator RelI = Rels.begin(),
+ RelE = Rels.end();
+ RelI != RelE; ++RelI) {
+ uint64_t Ofs;
+ if (error_code EC = RelI->getOffset(Ofs))
+ return EC;
+
+ if (Ofs == Offset) {
+ if (error_code EC = RelI->getSymbol(Sym))
+ return EC;
+ return readobj_error::success;
+ }
+ }
+
+ return readobj_error::unknown_symbol;
+}
+
+// Given a vector of relocations for a section and an offset into this section
+// the function returns the name of the symbol used for the relocation at the
+// offset.
+static error_code resolveSymbolName(const std::vector<RelocationRef> &Rels,
+ uint64_t Offset, StringRef &Name) {
+ SymbolRef Sym;
+ if (error_code EC = resolveSymbol(Rels, Offset, Sym)) return EC;
+ if (error_code EC = Sym.getName(Name)) return EC;
+ return object_error::success;
+}
+
+static const EnumEntry<COFF::MachineTypes> ImageFileMachineType[] = {
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_UNKNOWN ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AM33 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AMD64 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARMV7 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_EBC ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_I386 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_IA64 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_M32R ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPS16 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU16),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPC ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPCFP),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_R4000 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3DSP ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH4 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH5 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_THUMB ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_WCEMIPSV2)
+};
+
+static const EnumEntry<COFF::Characteristics> ImageFileCharacteristics[] = {
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_RELOCS_STRIPPED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_EXECUTABLE_IMAGE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LINE_NUMS_STRIPPED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LOCAL_SYMS_STRIPPED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_AGGRESSIVE_WS_TRIM ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LARGE_ADDRESS_AWARE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_LO ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_32BIT_MACHINE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DEBUG_STRIPPED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_NET_RUN_FROM_SWAP ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_SYSTEM ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DLL ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_UP_SYSTEM_ONLY ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_HI )
+};
+
+static const EnumEntry<COFF::SectionCharacteristics>
+ImageSectionCharacteristics[] = {
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_UNINITIALIZED_DATA),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_OTHER ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_INFO ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_REMOVE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_COMDAT ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_GPREL ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PURGEABLE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_16BIT ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_LOCKED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PRELOAD ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_16BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_32BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_64BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_128BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_256BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_512BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1024BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2048BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4096BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8192BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_NRELOC_OVFL ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_DISCARDABLE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_CACHED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_PAGED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_SHARED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_EXECUTE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_READ ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_WRITE )
+};
+
+static const EnumEntry<COFF::SymbolBaseType> ImageSymType[] = {
+ { "Null" , COFF::IMAGE_SYM_TYPE_NULL },
+ { "Void" , COFF::IMAGE_SYM_TYPE_VOID },
+ { "Char" , COFF::IMAGE_SYM_TYPE_CHAR },
+ { "Short" , COFF::IMAGE_SYM_TYPE_SHORT },
+ { "Int" , COFF::IMAGE_SYM_TYPE_INT },
+ { "Long" , COFF::IMAGE_SYM_TYPE_LONG },
+ { "Float" , COFF::IMAGE_SYM_TYPE_FLOAT },
+ { "Double", COFF::IMAGE_SYM_TYPE_DOUBLE },
+ { "Struct", COFF::IMAGE_SYM_TYPE_STRUCT },
+ { "Union" , COFF::IMAGE_SYM_TYPE_UNION },
+ { "Enum" , COFF::IMAGE_SYM_TYPE_ENUM },
+ { "MOE" , COFF::IMAGE_SYM_TYPE_MOE },
+ { "Byte" , COFF::IMAGE_SYM_TYPE_BYTE },
+ { "Word" , COFF::IMAGE_SYM_TYPE_WORD },
+ { "UInt" , COFF::IMAGE_SYM_TYPE_UINT },
+ { "DWord" , COFF::IMAGE_SYM_TYPE_DWORD }
+};
+
+static const EnumEntry<COFF::SymbolComplexType> ImageSymDType[] = {
+ { "Null" , COFF::IMAGE_SYM_DTYPE_NULL },
+ { "Pointer" , COFF::IMAGE_SYM_DTYPE_POINTER },
+ { "Function", COFF::IMAGE_SYM_DTYPE_FUNCTION },
+ { "Array" , COFF::IMAGE_SYM_DTYPE_ARRAY }
+};
+
+static const EnumEntry<COFF::SymbolStorageClass> ImageSymClass[] = {
+ { "EndOfFunction" , COFF::IMAGE_SYM_CLASS_END_OF_FUNCTION },
+ { "Null" , COFF::IMAGE_SYM_CLASS_NULL },
+ { "Automatic" , COFF::IMAGE_SYM_CLASS_AUTOMATIC },
+ { "External" , COFF::IMAGE_SYM_CLASS_EXTERNAL },
+ { "Static" , COFF::IMAGE_SYM_CLASS_STATIC },
+ { "Register" , COFF::IMAGE_SYM_CLASS_REGISTER },
+ { "ExternalDef" , COFF::IMAGE_SYM_CLASS_EXTERNAL_DEF },
+ { "Label" , COFF::IMAGE_SYM_CLASS_LABEL },
+ { "UndefinedLabel" , COFF::IMAGE_SYM_CLASS_UNDEFINED_LABEL },
+ { "MemberOfStruct" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_STRUCT },
+ { "Argument" , COFF::IMAGE_SYM_CLASS_ARGUMENT },
+ { "StructTag" , COFF::IMAGE_SYM_CLASS_STRUCT_TAG },
+ { "MemberOfUnion" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_UNION },
+ { "UnionTag" , COFF::IMAGE_SYM_CLASS_UNION_TAG },
+ { "TypeDefinition" , COFF::IMAGE_SYM_CLASS_TYPE_DEFINITION },
+ { "UndefinedStatic", COFF::IMAGE_SYM_CLASS_UNDEFINED_STATIC },
+ { "EnumTag" , COFF::IMAGE_SYM_CLASS_ENUM_TAG },
+ { "MemberOfEnum" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_ENUM },
+ { "RegisterParam" , COFF::IMAGE_SYM_CLASS_REGISTER_PARAM },
+ { "BitField" , COFF::IMAGE_SYM_CLASS_BIT_FIELD },
+ { "Block" , COFF::IMAGE_SYM_CLASS_BLOCK },
+ { "Function" , COFF::IMAGE_SYM_CLASS_FUNCTION },
+ { "EndOfStruct" , COFF::IMAGE_SYM_CLASS_END_OF_STRUCT },
+ { "File" , COFF::IMAGE_SYM_CLASS_FILE },
+ { "Section" , COFF::IMAGE_SYM_CLASS_SECTION },
+ { "WeakExternal" , COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL },
+ { "CLRToken" , COFF::IMAGE_SYM_CLASS_CLR_TOKEN }
+};
+
+static const EnumEntry<COFF::COMDATType> ImageCOMDATSelect[] = {
+ { "NoDuplicates", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES },
+ { "Any" , COFF::IMAGE_COMDAT_SELECT_ANY },
+ { "SameSize" , COFF::IMAGE_COMDAT_SELECT_SAME_SIZE },
+ { "ExactMatch" , COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH },
+ { "Associative" , COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE },
+ { "Largest" , COFF::IMAGE_COMDAT_SELECT_LARGEST },
+ { "Newest" , COFF::IMAGE_COMDAT_SELECT_NEWEST }
+};
+
+static const EnumEntry<COFF::WeakExternalCharacteristics>
+WeakExternalCharacteristics[] = {
+ { "NoLibrary", COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY },
+ { "Library" , COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY },
+ { "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS }
+};
+
+static const EnumEntry<unsigned> UnwindFlags[] = {
+ { "ExceptionHandler", Win64EH::UNW_ExceptionHandler },
+ { "TerminateHandler", Win64EH::UNW_TerminateHandler },
+ { "ChainInfo" , Win64EH::UNW_ChainInfo }
+};
+
+static const EnumEntry<unsigned> UnwindOpInfo[] = {
+ { "RAX", 0 },
+ { "RCX", 1 },
+ { "RDX", 2 },
+ { "RBX", 3 },
+ { "RSP", 4 },
+ { "RBP", 5 },
+ { "RSI", 6 },
+ { "RDI", 7 },
+ { "R8", 8 },
+ { "R9", 9 },
+ { "R10", 10 },
+ { "R11", 11 },
+ { "R12", 12 },
+ { "R13", 13 },
+ { "R14", 14 },
+ { "R15", 15 }
+};
+
+// Some additional COFF structures not defined by llvm::object.
+namespace {
+ struct coff_aux_function_definition {
+ support::ulittle32_t TagIndex;
+ support::ulittle32_t TotalSize;
+ support::ulittle32_t PointerToLineNumber;
+ support::ulittle32_t PointerToNextFunction;
+ uint8_t Unused[2];
+ };
+
+ struct coff_aux_weak_external_definition {
+ support::ulittle32_t TagIndex;
+ support::ulittle32_t Characteristics;
+ uint8_t Unused[10];
+ };
+
+ struct coff_aux_file_record {
+ char FileName[18];
+ };
+
+ struct coff_aux_clr_token {
+ support::ulittle8_t AuxType;
+ support::ulittle8_t Reserved;
+ support::ulittle32_t SymbolTableIndex;
+ uint8_t Unused[12];
+ };
+} // namespace
+
+static uint64_t getOffsetOfLSDA(const Win64EH::UnwindInfo& UI) {
+ return static_cast<const char*>(UI.getLanguageSpecificData())
+ - reinterpret_cast<const char*>(&UI);
+}
+
+static uint32_t getLargeSlotValue(ArrayRef<UnwindCode> UCs) {
+ if (UCs.size() < 3)
+ return 0;
+
+ return UCs[1].FrameOffset + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16);
+}
+
+template<typename T>
+static error_code getSymbolAuxData(const COFFObjectFile *Obj,
+ const coff_symbol *Symbol, const T* &Aux) {
+ ArrayRef<uint8_t> AuxData = Obj->getSymbolAuxData(Symbol);
+ Aux = reinterpret_cast<const T*>(AuxData.data());
+ return readobj_error::success;
+}
+
+static std::string formatSymbol(const std::vector<RelocationRef> &Rels,
+ uint64_t Offset, uint32_t Disp) {
+ std::string Buffer;
+ raw_string_ostream Str(Buffer);
+
+ StringRef Sym;
+ if (resolveSymbolName(Rels, Offset, Sym)) {
+ Str << format(" (0x%X)", Offset);
+ return Str.str();
+ }
+
+ Str << Sym;
+ if (Disp > 0) {
+ Str << format(" +0x%X (0x%X)", Disp, Offset);
+ } else {
+ Str << format(" (0x%X)", Offset);
+ }
+
+ return Str.str();
+}
+
+// Given a vector of relocations for a section and an offset into this section
+// the function resolves the symbol used for the relocation at the offset and
+// returns the section content and the address inside the content pointed to
+// by the symbol.
+error_code COFFDumper::getSectionContents(
+ const std::vector<RelocationRef> &Rels, uint64_t Offset,
+ ArrayRef<uint8_t> &Contents, uint64_t &Addr) {
+
+ SymbolRef Sym;
+ const coff_section *Section;
+
+ if (error_code EC = resolveSymbol(Rels, Offset, Sym))
+ return EC;
+ if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr))
+ return EC;
+ if (error_code EC = Obj->getSectionContents(Section, Contents))
+ return EC;
+
+ return object_error::success;
+}
+
+error_code COFFDumper::getSection(
+ const std::vector<RelocationRef> &Rels, uint64_t Offset,
+ const coff_section **SectionPtr, uint64_t *AddrPtr) {
+
+ SymbolRef Sym;
+ if (error_code EC = resolveSymbol(Rels, Offset, Sym))
+ return EC;
+
+ const coff_section *Section;
+ uint64_t Addr;
+ if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr))
+ return EC;
+
+ if (SectionPtr)
+ *SectionPtr = Section;
+ if (AddrPtr)
+ *AddrPtr = Addr;
+
+ return object_error::success;
+}
+
+void COFFDumper::cacheRelocations() {
+ error_code EC;
+ for (section_iterator SecI = Obj->begin_sections(),
+ SecE = Obj->end_sections();
+ SecI != SecE; SecI.increment(EC)) {
+ if (error(EC))
+ break;
+
+ const coff_section *Section = Obj->getCOFFSection(SecI);
+
+ for (relocation_iterator RelI = SecI->begin_relocations(),
+ RelE = SecI->end_relocations();
+ RelI != RelE; RelI.increment(EC)) {
+ if (error(EC))
+ break;
+
+ RelocMap[Section].push_back(*RelI);
+ }
+
+ // Sort relocations by address.
+ std::sort(RelocMap[Section].begin(), RelocMap[Section].end(),
+ relocAddressLess);
+ }
+}
+
+void COFFDumper::printFileHeaders() {
+ const coff_file_header *Header = 0;
+ if (error(Obj->getHeader(Header)))
+ return;
+
+ time_t TDS = Header->TimeDateStamp;
+ char FormattedTime[20] = { };
+ strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
+
+ {
+ DictScope D(W, "ImageFileHeader");
+ W.printEnum ("Machine", Header->Machine,
+ makeArrayRef(ImageFileMachineType));
+ W.printNumber("SectionCount", Header->NumberOfSections);
+ W.printHex ("TimeDateStamp", FormattedTime, Header->TimeDateStamp);
+ W.printHex ("PointerToSymbolTable", Header->PointerToSymbolTable);
+ W.printNumber("SymbolCount", Header->NumberOfSymbols);
+ W.printNumber("OptionalHeaderSize", Header->SizeOfOptionalHeader);
+ W.printFlags ("Characteristics", Header->Characteristics,
+ makeArrayRef(ImageFileCharacteristics));
+ }
+}
+
+void COFFDumper::printSections() {
+ error_code EC;
+
+ ListScope SectionsD(W, "Sections");
+ int SectionNumber = 0;
+ for (section_iterator SecI = Obj->begin_sections(),
+ SecE = Obj->end_sections();
+ SecI != SecE; SecI.increment(EC)) {
+ if (error(EC))
+ break;
+
+ ++SectionNumber;
+ const coff_section *Section = Obj->getCOFFSection(SecI);
+
+ StringRef Name;
+ if (error(SecI->getName(Name)))
+ Name = "";
+
+ DictScope D(W, "Section");
+ W.printNumber("Number", SectionNumber);
+ W.printBinary("Name", Name, Section->Name);
+ W.printHex ("VirtualSize", Section->VirtualSize);
+ W.printHex ("VirtualAddress", Section->VirtualAddress);
+ W.printNumber("RawDataSize", Section->SizeOfRawData);
+ W.printHex ("PointerToRawData", Section->PointerToRawData);
+ W.printHex ("PointerToRelocations", Section->PointerToRelocations);
+ W.printHex ("PointerToLineNumbers", Section->PointerToLinenumbers);
+ W.printNumber("RelocationCount", Section->NumberOfRelocations);
+ W.printNumber("LineNumberCount", Section->NumberOfLinenumbers);
+ W.printFlags ("Characteristics", Section->Characteristics,
+ makeArrayRef(ImageSectionCharacteristics),
+ COFF::SectionCharacteristics(0x00F00000));
+
+ if (opts::SectionRelocations) {
+ ListScope D(W, "Relocations");
+ for (relocation_iterator RelI = SecI->begin_relocations(),
+ RelE = SecI->end_relocations();
+ RelI != RelE; RelI.increment(EC)) {
+ if (error(EC)) break;
+
+ printRelocation(SecI, RelI);
+ }
+ }
+
+ if (opts::SectionSymbols) {
+ ListScope D(W, "Symbols");
+ for (symbol_iterator SymI = Obj->begin_symbols(),
+ SymE = Obj->end_symbols();
+ SymI != SymE; SymI.increment(EC)) {
+ if (error(EC)) break;
+
+ bool Contained = false;
+ if (SecI->containsSymbol(*SymI, Contained) || !Contained)
+ continue;
+
+ printSymbol(SymI);
+ }
+ }
+
+ if (opts::SectionData) {
+ StringRef Data;
+ if (error(SecI->getContents(Data))) break;
+
+ W.printBinaryBlock("SectionData", Data);
+ }
+ }
+}
+
+void COFFDumper::printRelocations() {
+ ListScope D(W, "Relocations");
+
+ error_code EC;
+ int SectionNumber = 0;
+ for (section_iterator SecI = Obj->begin_sections(),
+ SecE = Obj->end_sections();
+ SecI != SecE; SecI.increment(EC)) {
+ ++SectionNumber;
+ if (error(EC))
+ break;
+
+ StringRef Name;
+ if (error(SecI->getName(Name)))
+ continue;
+
+ bool PrintedGroup = false;
+ for (relocation_iterator RelI = SecI->begin_relocations(),
+ RelE = SecI->end_relocations();
+ RelI != RelE; RelI.increment(EC)) {
+ if (error(EC)) break;
+
+ if (!PrintedGroup) {
+ W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n";
+ W.indent();
+ PrintedGroup = true;
+ }
+
+ printRelocation(SecI, RelI);
+ }
+
+ if (PrintedGroup) {
+ W.unindent();
+ W.startLine() << "}\n";
+ }
+ }
+}
+
+void COFFDumper::printRelocation(section_iterator SecI,
+ relocation_iterator RelI) {
+ uint64_t Offset;
+ uint64_t RelocType;
+ SmallString<32> RelocName;
+ SymbolRef Symbol;
+ StringRef SymbolName;
+ StringRef Contents;
+ if (error(RelI->getOffset(Offset))) return;
+ if (error(RelI->getType(RelocType))) return;
+ if (error(RelI->getTypeName(RelocName))) return;
+ if (error(RelI->getSymbol(Symbol))) return;
+ if (error(Symbol.getName(SymbolName))) return;
+ if (error(SecI->getContents(Contents))) return;
+
+ raw_ostream& OS = W.startLine();
+ OS << W.hex(Offset)
+ << " " << RelocName
+ << " " << (SymbolName.size() > 0 ? SymbolName : "-")
+ << "\n";
+}
+
+void COFFDumper::printSymbols() {
+ ListScope Group(W, "Symbols");
+
+ error_code EC;
+ for (symbol_iterator SymI = Obj->begin_symbols(),
+ SymE = Obj->end_symbols();
+ SymI != SymE; SymI.increment(EC)) {
+ if (error(EC)) break;
+
+ printSymbol(SymI);
+ }
+}
+
+void COFFDumper::printDynamicSymbols() {
+ ListScope Group(W, "DynamicSymbols");
+}
+
+void COFFDumper::printSymbol(symbol_iterator SymI) {
+ DictScope D(W, "Symbol");
+
+ const coff_symbol *Symbol = Obj->getCOFFSymbol(SymI);
+ const coff_section *Section;
+ if (error_code EC = Obj->getSection(Symbol->SectionNumber, Section)) {
+ W.startLine() << "Invalid section number: " << EC.message() << "\n";
+ W.flush();
+ return;
+ }
+
+ StringRef SymbolName;
+ if (Obj->getSymbolName(Symbol, SymbolName))
+ SymbolName = "";
+
+ StringRef SectionName;
+ if (Section && Obj->getSectionName(Section, SectionName))
+ SectionName = "";
+
+ W.printString("Name", SymbolName);
+ W.printNumber("Value", Symbol->Value);
+ W.printNumber("Section", SectionName, Symbol->SectionNumber);
+ W.printEnum ("BaseType", Symbol->getBaseType(), makeArrayRef(ImageSymType));
+ W.printEnum ("ComplexType", Symbol->getComplexType(),
+ makeArrayRef(ImageSymDType));
+ W.printEnum ("StorageClass", Symbol->StorageClass,
+ makeArrayRef(ImageSymClass));
+ W.printNumber("AuxSymbolCount", Symbol->NumberOfAuxSymbols);
+
+ for (unsigned I = 0; I < Symbol->NumberOfAuxSymbols; ++I) {
+ if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL &&
+ Symbol->getBaseType() == COFF::IMAGE_SYM_TYPE_NULL &&
+ Symbol->getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION &&
+ Symbol->SectionNumber > 0) {
+ const coff_aux_function_definition *Aux;
+ if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
+ break;
+
+ DictScope AS(W, "AuxFunctionDef");
+ W.printNumber("TagIndex", Aux->TagIndex);
+ W.printNumber("TotalSize", Aux->TotalSize);
+ W.printHex("PointerToLineNumber", Aux->PointerToLineNumber);
+ W.printHex("PointerToNextFunction", Aux->PointerToNextFunction);
+ W.printBinary("Unused", makeArrayRef(Aux->Unused));
+
+ } else if (
+ Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL ||
+ (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL &&
+ Symbol->SectionNumber == 0 &&
+ Symbol->Value == 0)) {
+ const coff_aux_weak_external_definition *Aux;
+ if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
+ break;
+
+ const coff_symbol *Linked;
+ StringRef LinkedName;
+ error_code EC;
+ if ((EC = Obj->getSymbol(Aux->TagIndex, Linked)) ||
+ (EC = Obj->getSymbolName(Linked, LinkedName))) {
+ LinkedName = "";
+ error(EC);
+ }
+
+ DictScope AS(W, "AuxWeakExternal");
+ W.printNumber("Linked", LinkedName, Aux->TagIndex);
+ W.printEnum ("Search", Aux->Characteristics,
+ makeArrayRef(WeakExternalCharacteristics));
+ W.printBinary("Unused", Aux->Unused);
+
+ } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_FILE) {
+ const coff_aux_file_record *Aux;
+ if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
+ break;
+
+ } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC) {
+ const coff_aux_section_definition *Aux;
+ if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
+ break;
+
+ DictScope AS(W, "AuxSectionDef");
+ W.printNumber("Length", Aux->Length);
+ W.printNumber("RelocationCount", Aux->NumberOfRelocations);
+ W.printNumber("LineNumberCount", Aux->NumberOfLinenumbers);
+ W.printHex("Checksum", Aux->CheckSum);
+ W.printNumber("Number", Aux->Number);
+ W.printEnum("Selection", Aux->Selection, makeArrayRef(ImageCOMDATSelect));
+ W.printBinary("Unused", makeArrayRef(Aux->Unused));
+
+ if (Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT
+ && Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
+ const coff_section *Assoc;
+ StringRef AssocName;
+ error_code EC;
+ if ((EC = Obj->getSection(Aux->Number, Assoc)) ||
+ (EC = Obj->getSectionName(Assoc, AssocName))) {
+ AssocName = "";
+ error(EC);
+ }
+
+ W.printNumber("AssocSection", AssocName, Aux->Number);
+ }
+ } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_CLR_TOKEN) {
+ const coff_aux_clr_token *Aux;
+ if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
+ break;
+
+ DictScope AS(W, "AuxCLRToken");
+ W.printNumber("AuxType", Aux->AuxType);
+ W.printNumber("Reserved", Aux->Reserved);
+ W.printNumber("SymbolTableIndex", Aux->SymbolTableIndex);
+ W.printBinary("Unused", Aux->Unused);
+
+ } else {
+ W.startLine() << "<unhandled auxiliary record>\n";
+ }
+ }
+}
+
+void COFFDumper::printUnwindInfo() {
+ const coff_file_header *Header;
+ if (error(Obj->getHeader(Header)))
+ return;
+
+ ListScope D(W, "UnwindInformation");
+ if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) {
+ W.startLine() << "Unsupported image machine type "
+ "(currently only AMD64 is supported).\n";
+ return;
+ }
+
+ printX64UnwindInfo();
+}
+
+void COFFDumper::printX64UnwindInfo() {
+ error_code EC;
+ for (section_iterator SecI = Obj->begin_sections(),
+ SecE = Obj->end_sections();
+ SecI != SecE; SecI.increment(EC)) {
+ if (error(EC)) break;
+
+ StringRef Name;
+ if (error(SecI->getName(Name)))
+ continue;
+ if (Name != ".pdata" && !Name.startswith(".pdata$"))
+ continue;
+
+ const coff_section *PData = Obj->getCOFFSection(SecI);
+
+ ArrayRef<uint8_t> Contents;
+ if (error(Obj->getSectionContents(PData, Contents)) ||
+ Contents.empty())
+ continue;
+
+ ArrayRef<RuntimeFunction> RFs(
+ reinterpret_cast<const RuntimeFunction *>(Contents.data()),
+ Contents.size() / sizeof(RuntimeFunction));
+
+ for (const RuntimeFunction *I = RFs.begin(), *E = RFs.end(); I < E; ++I) {
+ const uint64_t OffsetInSection = std::distance(RFs.begin(), I)
+ * sizeof(RuntimeFunction);
+
+ printRuntimeFunction(*I, OffsetInSection, RelocMap[PData]);
+ }
+ }
+}
+
+void COFFDumper::printRuntimeFunction(
+ const RuntimeFunction& RTF,
+ uint64_t OffsetInSection,
+ const std::vector<RelocationRef> &Rels) {
+
+ DictScope D(W, "RuntimeFunction");
+ W.printString("StartAddress",
+ formatSymbol(Rels, OffsetInSection + 0, RTF.StartAddress));
+ W.printString("EndAddress",
+ formatSymbol(Rels, OffsetInSection + 4, RTF.EndAddress));
+ W.printString("UnwindInfoAddress",
+ formatSymbol(Rels, OffsetInSection + 8, RTF.UnwindInfoOffset));
+
+ const coff_section* XData = 0;
+ uint64_t UnwindInfoOffset = 0;
+ if (error(getSection(Rels, OffsetInSection + 8, &XData, &UnwindInfoOffset)))
+ return;
+
+ ArrayRef<uint8_t> XContents;
+ if (error(Obj->getSectionContents(XData, XContents)) || XContents.empty())
+ return;
+
+ UnwindInfoOffset += RTF.UnwindInfoOffset;
+ if (UnwindInfoOffset > XContents.size())
+ return;
+
+ const Win64EH::UnwindInfo *UI =
+ reinterpret_cast<const Win64EH::UnwindInfo *>(
+ XContents.data() + UnwindInfoOffset);
+
+ printUnwindInfo(*UI, UnwindInfoOffset, RelocMap[XData]);
+}
+
+void COFFDumper::printUnwindInfo(
+ const Win64EH::UnwindInfo& UI,
+ uint64_t OffsetInSection,
+ const std::vector<RelocationRef> &Rels) {
+ DictScope D(W, "UnwindInfo");
+ W.printNumber("Version", UI.getVersion());
+ W.printFlags("Flags", UI.getFlags(), makeArrayRef(UnwindFlags));
+ W.printNumber("PrologSize", UI.PrologSize);
+ if (UI.getFrameRegister() != 0) {
+ W.printEnum("FrameRegister", UI.getFrameRegister(),
+ makeArrayRef(UnwindOpInfo));
+ W.printHex("FrameOffset", UI.getFrameOffset());
+ } else {
+ W.printString("FrameRegister", StringRef("-"));
+ W.printString("FrameOffset", StringRef("-"));
+ }
+
+ W.printNumber("UnwindCodeCount", UI.NumCodes);
+ {
+ ListScope CodesD(W, "UnwindCodes");
+ ArrayRef<UnwindCode> UCs(&UI.UnwindCodes[0], UI.NumCodes);
+ for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ++I) {
+ unsigned UsedSlots = getNumUsedSlots(*I);
+ if (UsedSlots > UCs.size()) {
+ errs() << "Corrupt unwind data";
+ return;
+ }
+ printUnwindCode(UI, ArrayRef<UnwindCode>(I, E));
+ I += UsedSlots - 1;
+ }
+ }
+
+ uint64_t LSDAOffset = OffsetInSection + getOffsetOfLSDA(UI);
+ if (UI.getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) {
+ W.printString("Handler", formatSymbol(Rels, LSDAOffset,
+ UI.getLanguageSpecificHandlerOffset()));
+ } else if (UI.getFlags() & UNW_ChainInfo) {
+ const RuntimeFunction *Chained = UI.getChainedFunctionEntry();
+ if (Chained) {
+ DictScope D(W, "Chained");
+ W.printString("StartAddress", formatSymbol(Rels, LSDAOffset + 0,
+ Chained->StartAddress));
+ W.printString("EndAddress", formatSymbol(Rels, LSDAOffset + 4,
+ Chained->EndAddress));
+ W.printString("UnwindInfoAddress", formatSymbol(Rels, LSDAOffset + 8,
+ Chained->UnwindInfoOffset));
+ }
+ }
+}
+
+// Prints one unwind code. Because an unwind code can occupy up to 3 slots in
+// the unwind codes array, this function requires that the correct number of
+// slots is provided.
+void COFFDumper::printUnwindCode(const Win64EH::UnwindInfo& UI,
+ ArrayRef<UnwindCode> UCs) {
+ assert(UCs.size() >= getNumUsedSlots(UCs[0]));
+
+ W.startLine() << format("0x%02X: ", unsigned(UCs[0].u.CodeOffset))
+ << getUnwindCodeTypeName(UCs[0].getUnwindOp());
+
+ uint32_t AllocSize = 0;
+
+ switch (UCs[0].getUnwindOp()) {
+ case UOP_PushNonVol:
+ outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo());
+ break;
+
+ case UOP_AllocLarge:
+ if (UCs[0].getOpInfo() == 0) {
+ AllocSize = UCs[1].FrameOffset * 8;
+ } else {
+ AllocSize = getLargeSlotValue(UCs);
+ }
+ outs() << " size=" << AllocSize;
+ break;
+ case UOP_AllocSmall:
+ outs() << " size=" << ((UCs[0].getOpInfo() + 1) * 8);
+ break;
+ case UOP_SetFPReg:
+ if (UI.getFrameRegister() == 0) {
+ outs() << " reg=<invalid>";
+ } else {
+ outs() << " reg=" << getUnwindRegisterName(UI.getFrameRegister())
+ << format(", offset=0x%X", UI.getFrameOffset() * 16);
+ }
+ break;
+ case UOP_SaveNonVol:
+ outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo())
+ << format(", offset=0x%X", UCs[1].FrameOffset * 8);
+ break;
+ case UOP_SaveNonVolBig:
+ outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo())
+ << format(", offset=0x%X", getLargeSlotValue(UCs));
+ break;
+ case UOP_SaveXMM128:
+ outs() << " reg=XMM" << static_cast<uint32_t>(UCs[0].getOpInfo())
+ << format(", offset=0x%X", UCs[1].FrameOffset * 16);
+ break;
+ case UOP_SaveXMM128Big:
+ outs() << " reg=XMM" << static_cast<uint32_t>(UCs[0].getOpInfo())
+ << format(", offset=0x%X", getLargeSlotValue(UCs));
+ break;
+ case UOP_PushMachFrame:
+ outs() << " errcode=" << (UCs[0].getOpInfo() == 0 ? "no" : "yes");
+ break;
+ }
+
+ outs() << "\n";
+}
diff --git a/tools/llvm-readobj/ELF.cpp b/tools/llvm-readobj/ELF.cpp
deleted file mode 100644
index 07f15b3a6d..0000000000
--- a/tools/llvm-readobj/ELF.cpp
+++ /dev/null
@@ -1,196 +0,0 @@
-//===- 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/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp
new file mode 100644
index 0000000000..9e111dd905
--- /dev/null
+++ b/tools/llvm-readobj/ELFDumper.cpp
@@ -0,0 +1,800 @@
+//===-- ELFDumper.cpp - ELF-specific dumper ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements the ELF-specific dumper for llvm-readobj.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm-readobj.h"
+#include "Error.h"
+#include "ObjDumper.h"
+#include "StreamWriter.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace ELF;
+
+
+#define LLVM_READOBJ_ENUM_CASE(ns, enum) \
+ case ns::enum: return #enum;
+
+namespace {
+
+template<typename ELFT>
+class ELFDumper : public ObjDumper {
+public:
+ ELFDumper(const ELFObjectFile<ELFT> *Obj, StreamWriter& Writer)
+ : ObjDumper(Writer)
+ , Obj(Obj) { }
+
+ virtual void printFileHeaders() LLVM_OVERRIDE;
+ virtual void printSections() LLVM_OVERRIDE;
+ virtual void printRelocations() LLVM_OVERRIDE;
+ virtual void printSymbols() LLVM_OVERRIDE;
+ virtual void printDynamicSymbols() LLVM_OVERRIDE;
+ virtual void printUnwindInfo() LLVM_OVERRIDE;
+
+ virtual void printDynamicTable() LLVM_OVERRIDE;
+ virtual void printNeededLibraries() LLVM_OVERRIDE;
+
+private:
+ typedef typename ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr;
+ typedef typename ELFObjectFile<ELFT>::Elf_Sym Elf_Sym;
+
+ void printSymbol(symbol_iterator SymI, bool IsDynamic = false);
+
+ void printRelocation(section_iterator SecI, relocation_iterator RelI);
+
+ const ELFObjectFile<ELFT> *Obj;
+};
+
+} // namespace
+
+
+namespace llvm {
+
+error_code createELFDumper(const object::ObjectFile *Obj,
+ StreamWriter& Writer,
+ OwningPtr<ObjDumper> &Result) {
+ typedef ELFType<support::little, 4, false> Little32ELF;
+ typedef ELFType<support::big, 4, false> Big32ELF;
+ typedef ELFType<support::little, 4, true > Little64ELF;
+ typedef ELFType<support::big, 8, true > Big64ELF;
+
+ typedef ELFObjectFile<Little32ELF> LittleELF32Obj;
+ typedef ELFObjectFile<Big32ELF > BigELF32Obj;
+ typedef ELFObjectFile<Little64ELF> LittleELF64Obj;
+ typedef ELFObjectFile<Big64ELF > BigELF64Obj;
+
+ // Little-endian 32-bit
+ if (const LittleELF32Obj *ELFObj = dyn_cast<LittleELF32Obj>(Obj)) {
+ Result.reset(new ELFDumper<Little32ELF>(ELFObj, Writer));
+ return readobj_error::success;
+ }
+
+ // Big-endian 32-bit
+ if (const BigELF32Obj *ELFObj = dyn_cast<BigELF32Obj>(Obj)) {
+ Result.reset(new ELFDumper<Big32ELF>(ELFObj, Writer));
+ return readobj_error::success;
+ }
+
+ // Little-endian 64-bit
+ if (const LittleELF64Obj *ELFObj = dyn_cast<LittleELF64Obj>(Obj)) {
+ Result.reset(new ELFDumper<Little64ELF>(ELFObj, Writer));
+ return readobj_error::success;
+ }
+
+ // Big-endian 64-bit
+ if (const BigELF64Obj *ELFObj = dyn_cast<BigELF64Obj>(Obj)) {
+ Result.reset(new ELFDumper<Big64ELF>(ELFObj, Writer));
+ return readobj_error::success;
+ }
+
+ return readobj_error::unsupported_obj_file_format;
+}
+
+} // namespace llvm
+
+
+static const EnumEntry<unsigned> ElfClass[] = {
+ { "None", ELF::ELFCLASSNONE },
+ { "32-bit", ELF::ELFCLASS32 },
+ { "64-bit", ELF::ELFCLASS64 },
+};
+
+static const EnumEntry<unsigned> ElfDataEncoding[] = {
+ { "None", ELF::ELFDATANONE },
+ { "LittleEndian", ELF::ELFDATA2LSB },
+ { "BigEndian", ELF::ELFDATA2MSB },
+};
+
+static const EnumEntry<unsigned> ElfObjectFileType[] = {
+ { "None", ELF::ET_NONE },
+ { "Relocatable", ELF::ET_REL },
+ { "Executable", ELF::ET_EXEC },
+ { "SharedObject", ELF::ET_DYN },
+ { "Core", ELF::ET_CORE },
+};
+
+static const EnumEntry<unsigned> ElfOSABI[] = {
+ { "SystemV", ELF::ELFOSABI_NONE },
+ { "HPUX", ELF::ELFOSABI_HPUX },
+ { "NetBSD", ELF::ELFOSABI_NETBSD },
+ { "GNU/Linux", ELF::ELFOSABI_LINUX },
+ { "GNU/Hurd", ELF::ELFOSABI_HURD },
+ { "Solaris", ELF::ELFOSABI_SOLARIS },
+ { "AIX", ELF::ELFOSABI_AIX },
+ { "IRIX", ELF::ELFOSABI_IRIX },
+ { "FreeBSD", ELF::ELFOSABI_FREEBSD },
+ { "TRU64", ELF::ELFOSABI_TRU64 },
+ { "Modesto", ELF::ELFOSABI_MODESTO },
+ { "OpenBSD", ELF::ELFOSABI_OPENBSD },
+ { "OpenVMS", ELF::ELFOSABI_OPENVMS },
+ { "NSK", ELF::ELFOSABI_NSK },
+ { "AROS", ELF::ELFOSABI_AROS },
+ { "FenixOS", ELF::ELFOSABI_FENIXOS },
+ { "C6000_ELFABI", ELF::ELFOSABI_C6000_ELFABI },
+ { "C6000_LINUX" , ELF::ELFOSABI_C6000_LINUX },
+ { "ARM", ELF::ELFOSABI_ARM },
+ { "Standalone" , ELF::ELFOSABI_STANDALONE }
+};
+
+static const EnumEntry<unsigned> ElfMachineType[] = {
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_NONE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_M32 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_386 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_68K ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_88K ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_486 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_860 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_S370 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS_RS3_LE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PARISC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_VPP500 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARC32PLUS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_960 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PPC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PPC64 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_S390 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SPU ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_V800 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_FR20 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_RH32 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_RCE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ARM ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ALPHA ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SH ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARCV9 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TRICORE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_300 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_300H ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_H8S ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_500 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_IA_64 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS_X ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_COLDFIRE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC12 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MMA ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PCP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_NCPU ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_NDR1 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_STARCORE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ME16 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ST100 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TINYJ ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_X86_64 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PDSP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PDP10 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PDP11 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_FX66 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ST9PLUS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ST7 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC16 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC11 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC08 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC05 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SVX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ST19 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_VAX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CRIS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_JAVELIN ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_FIREPATH ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ZSP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MMIX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_HUANY ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PRISM ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_AVR ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_FR30 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_D10V ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_D30V ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_V850 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_M32R ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MN10300 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MN10200 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PJ ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_OPENRISC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC_COMPACT ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_XTENSA ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TMM_GPP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_NS32K ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TPC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SNP1K ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ST200 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_IP2K ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MAX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CR ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_F2MC16 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MSP430 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_BLACKFIN ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SE_C33 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SEP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ARCA ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_UNICORE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_EXCESS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_DXP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ALTERA_NIOS2 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CRX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_XGATE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_C166 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_M16C ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_DSPIC30F ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_M32C ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TSK3000 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_RS08 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SHARC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG2 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SCORE7 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_DSP24 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE3 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_LATTICEMICO32),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SE_C17 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C6000 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C2000 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C5500 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MMDSP_PLUS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CYPRESS_M8C ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_R32C ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TRIMEDIA ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_HEXAGON ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_8051 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_STXP7X ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_NDS32 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG1 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG1X ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MAXQ30 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_XIMO16 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MANIK ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CRAYNV2 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_RX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_METAG ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MCST_ELBRUS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG16 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CR16 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ETPU ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SLE9X ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_L10M ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_K10M ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_AARCH64 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_AVR32 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_STM8 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TILE64 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TILEPRO ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MICROBLAZE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CUDA ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TILEGX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CLOUDSHIELD ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_COREA_1ST ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_COREA_2ND ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC_COMPACT2 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_OPEN8 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_RL78 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE5 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_78KOR ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_56800EX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MBLAZE )
+};
+
+static const EnumEntry<unsigned> ElfSymbolBindings[] = {
+ { "Local", ELF::STB_LOCAL },
+ { "Global", ELF::STB_GLOBAL },
+ { "Weak", ELF::STB_WEAK }
+};
+
+static const EnumEntry<unsigned> ElfSymbolTypes[] = {
+ { "None", ELF::STT_NOTYPE },
+ { "Object", ELF::STT_OBJECT },
+ { "Function", ELF::STT_FUNC },
+ { "Section", ELF::STT_SECTION },
+ { "File", ELF::STT_FILE },
+ { "Common", ELF::STT_COMMON },
+ { "TLS", ELF::STT_TLS },
+ { "GNU_IFunc", ELF::STT_GNU_IFUNC }
+};
+
+static const char *getElfSectionType(unsigned Arch, unsigned Type) {
+ switch (Arch) {
+ case Triple::arm:
+ switch (Type) {
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_EXIDX);
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_PREEMPTMAP);
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_ATTRIBUTES);
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_DEBUGOVERLAY);
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_OVERLAYSECTION);
+ }
+ case Triple::hexagon:
+ switch (Type) {
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_HEX_ORDERED);
+ }
+ case Triple::x86_64:
+ switch (Type) {
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_X86_64_UNWIND);
+ }
+ case Triple::mips:
+ case Triple::mipsel:
+ switch (Type) {
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_REGINFO);
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_OPTIONS);
+ }
+ }
+
+ switch (Type) {
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_NULL );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_PROGBITS );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_SYMTAB );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_STRTAB );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_RELA );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_HASH );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_DYNAMIC );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_NOTE );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_NOBITS );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_REL );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_SHLIB );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_DYNSYM );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_INIT_ARRAY );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_FINI_ARRAY );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_PREINIT_ARRAY );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_GROUP );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_SYMTAB_SHNDX );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_HASH );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_verdef );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_verneed );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_versym );
+ default: return "";
+ }
+}
+
+static const EnumEntry<unsigned> ElfSectionFlags[] = {
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_WRITE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_ALLOC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_EXECINSTR ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_MERGE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_STRINGS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_INFO_LINK ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_LINK_ORDER ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_OS_NONCONFORMING),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_GROUP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_TLS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_CP_SECTION),
+ LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_DP_SECTION),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NOSTRIP )
+};
+
+
+template<class ELFT>
+void ELFDumper<ELFT>::printFileHeaders() {
+ error_code EC;
+ typedef ELFObjectFile<ELFT> ELFO;
+
+ const typename ELFO::Elf_Ehdr *Header = Obj->getElfHeader();
+
+ {
+ DictScope D(W, "ElfHeader");
+ {
+ DictScope D(W, "Ident");
+ W.printBinary("Magic", makeArrayRef(Header->e_ident).slice(ELF::EI_MAG0,
+ 4));
+ W.printEnum ("Class", Header->e_ident[ELF::EI_CLASS],
+ makeArrayRef(ElfClass));
+ W.printEnum ("DataEncoding", Header->e_ident[ELF::EI_DATA],
+ makeArrayRef(ElfDataEncoding));
+ W.printNumber("FileVersion", Header->e_ident[ELF::EI_VERSION]);
+ W.printEnum ("OS/ABI", Header->e_ident[ELF::EI_OSABI],
+ makeArrayRef(ElfOSABI));
+ W.printNumber("ABIVersion", Header->e_ident[ELF::EI_ABIVERSION]);
+ W.printBinary("Unused", makeArrayRef(Header->e_ident).slice(ELF::EI_PAD));
+ }
+
+ W.printEnum ("Type", Header->e_type, makeArrayRef(ElfObjectFileType));
+ W.printEnum ("Machine", Header->e_machine, makeArrayRef(ElfMachineType));
+ W.printNumber("Version", Header->e_version);
+ W.printHex ("Entry", Header->e_entry);
+ W.printHex ("ProgramHeaderOffset", Header->e_phoff);
+ W.printHex ("SectionHeaderOffset", Header->e_shoff);
+ W.printFlags ("Flags", Header->e_flags);
+ W.printNumber("HeaderSize", Header->e_ehsize);
+ W.printNumber("ProgramHeaderEntrySize", Header->e_phentsize);
+ W.printNumber("ProgramHeaderCount", Header->e_phnum);
+ W.printNumber("SectionHeaderEntrySize", Header->e_shentsize);
+ W.printNumber("SectionHeaderCount", Header->e_shnum);
+ W.printNumber("StringTableSectionIndex", Header->e_shstrndx);
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printSections() {
+ ListScope SectionsD(W, "Sections");
+
+ int SectionIndex = -1;
+ error_code EC;
+ for (section_iterator SecI = Obj->begin_sections(),
+ SecE = Obj->end_sections();
+ SecI != SecE; SecI.increment(EC)) {
+ if (error(EC)) break;
+
+ ++SectionIndex;
+
+ const Elf_Shdr *Section = Obj->getElfSection(SecI);
+ StringRef Name;
+ if (error(SecI->getName(Name)))
+ Name = "";
+
+ DictScope SectionD(W, "Section");
+ W.printNumber("Index", SectionIndex);
+ W.printNumber("Name", Name, Section->sh_name);
+ W.printHex ("Type", getElfSectionType(Obj->getArch(), Section->sh_type),
+ Section->sh_type);
+ W.printFlags ("Flags", Section->sh_flags, makeArrayRef(ElfSectionFlags));
+ W.printHex ("Address", Section->sh_addr);
+ W.printHex ("Offset", Section->sh_offset);
+ W.printNumber("Size", Section->sh_size);
+ W.printNumber("Link", Section->sh_link);
+ W.printNumber("Info", Section->sh_info);
+ W.printNumber("AddressAlignment", Section->sh_addralign);
+ W.printNumber("EntrySize", Section->sh_entsize);
+
+ if (opts::SectionRelocations) {
+ ListScope D(W, "Relocations");
+ for (relocation_iterator RelI = SecI->begin_relocations(),
+ RelE = SecI->end_relocations();
+ RelI != RelE; RelI.increment(EC)) {
+ if (error(EC)) break;
+
+ printRelocation(SecI, RelI);
+ }
+ }
+
+ if (opts::SectionSymbols) {
+ ListScope D(W, "Symbols");
+ for (symbol_iterator SymI = Obj->begin_symbols(),
+ SymE = Obj->end_symbols();
+ SymI != SymE; SymI.increment(EC)) {
+ if (error(EC)) break;
+
+ bool Contained = false;
+ if (SecI->containsSymbol(*SymI, Contained) || !Contained)
+ continue;
+
+ printSymbol(SymI);
+ }
+ }
+
+ if (opts::SectionData) {
+ StringRef Data;
+ if (error(SecI->getContents(Data))) break;
+
+ W.printBinaryBlock("SectionData", Data);
+ }
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printRelocations() {
+ ListScope D(W, "Relocations");
+
+ error_code EC;
+ int SectionNumber = -1;
+ for (section_iterator SecI = Obj->begin_sections(),
+ SecE = Obj->end_sections();
+ SecI != SecE; SecI.increment(EC)) {
+ if (error(EC)) break;
+
+ ++SectionNumber;
+ StringRef Name;
+ if (error(SecI->getName(Name)))
+ continue;
+
+ bool PrintedGroup = false;
+ for (relocation_iterator RelI = SecI->begin_relocations(),
+ RelE = SecI->end_relocations();
+ RelI != RelE; RelI.increment(EC)) {
+ if (error(EC)) break;
+
+ if (!PrintedGroup) {
+ W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n";
+ W.indent();
+ PrintedGroup = true;
+ }
+
+ printRelocation(SecI, RelI);
+ }
+
+ if (PrintedGroup) {
+ W.unindent();
+ W.startLine() << "}\n";
+ }
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printRelocation(section_iterator Sec,
+ relocation_iterator RelI) {
+ uint64_t Offset;
+ SmallString<32> RelocName;
+ int64_t Info;
+ StringRef SymbolName;
+ SymbolRef Symbol;
+ if (error(RelI->getOffset(Offset))) return;
+ if (error(RelI->getTypeName(RelocName))) return;
+ if (error(RelI->getAdditionalInfo(Info))) return;
+ if (error(RelI->getSymbol(Symbol))) return;
+ if (error(Symbol.getName(SymbolName))) return;
+
+ raw_ostream& OS = W.startLine();
+ OS << W.hex(Offset)
+ << " " << RelocName
+ << " " << (SymbolName.size() > 0 ? SymbolName : "-")
+ << " " << W.hex(Info)
+ << "\n";
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printSymbols() {
+ ListScope Group(W, "Symbols");
+
+ error_code EC;
+ for (symbol_iterator SymI = Obj->begin_symbols(), SymE = Obj->end_symbols();
+ SymI != SymE; SymI.increment(EC)) {
+ if (error(EC)) break;
+
+ printSymbol(SymI);
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printDynamicSymbols() {
+ ListScope Group(W, "DynamicSymbols");
+
+ error_code EC;
+ for (symbol_iterator SymI = Obj->begin_dynamic_symbols(),
+ SymE = Obj->end_dynamic_symbols();
+ SymI != SymE; SymI.increment(EC)) {
+ if (error(EC)) break;
+
+ printSymbol(SymI, true);
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printSymbol(symbol_iterator SymI, bool IsDynamic) {
+ error_code EC;
+
+ const Elf_Sym *Symbol = Obj->getElfSymbol(SymI);
+ const Elf_Shdr *Section = Obj->getSection(Symbol);
+
+ StringRef SymbolName;
+ if (SymI->getName(SymbolName))
+ SymbolName = "";
+
+ StringRef SectionName;
+ if (Section && Obj->getSectionName(Section, SectionName))
+ SectionName = "";
+
+ std::string FullSymbolName(SymbolName);
+ if (IsDynamic) {
+ StringRef Version;
+ bool IsDefault;
+ if (error(Obj->getSymbolVersion(*SymI, Version, IsDefault)))
+ return;
+ if (!Version.empty()) {
+ FullSymbolName += (IsDefault ? "@@" : "@");
+ FullSymbolName += Version;
+ }
+ }
+
+ DictScope D(W, "Symbol");
+ W.printNumber("Name", FullSymbolName, Symbol->st_name);
+ W.printHex ("Value", Symbol->st_value);
+ W.printNumber("Size", Symbol->st_size);
+ W.printEnum ("Binding", Symbol->getBinding(),
+ makeArrayRef(ElfSymbolBindings));
+ W.printEnum ("Type", Symbol->getType(), makeArrayRef(ElfSymbolTypes));
+ W.printNumber("Other", Symbol->st_other);
+ W.printHex ("Section", SectionName, Symbol->st_shndx);
+}
+
+#define LLVM_READOBJ_TYPE_CASE(name) \
+ case DT_##name: return #name
+
+static const char *getTypeString(uint64_t Type) {
+ switch (Type) {
+ LLVM_READOBJ_TYPE_CASE(BIND_NOW);
+ LLVM_READOBJ_TYPE_CASE(DEBUG);
+ LLVM_READOBJ_TYPE_CASE(FINI);
+ LLVM_READOBJ_TYPE_CASE(FINI_ARRAY);
+ LLVM_READOBJ_TYPE_CASE(FINI_ARRAYSZ);
+ LLVM_READOBJ_TYPE_CASE(FLAGS);
+ LLVM_READOBJ_TYPE_CASE(HASH);
+ LLVM_READOBJ_TYPE_CASE(INIT);
+ LLVM_READOBJ_TYPE_CASE(INIT_ARRAY);
+ LLVM_READOBJ_TYPE_CASE(INIT_ARRAYSZ);
+ LLVM_READOBJ_TYPE_CASE(PREINIT_ARRAY);
+ LLVM_READOBJ_TYPE_CASE(PREINIT_ARRAYSZ);
+ LLVM_READOBJ_TYPE_CASE(JMPREL);
+ LLVM_READOBJ_TYPE_CASE(NEEDED);
+ LLVM_READOBJ_TYPE_CASE(NULL);
+ LLVM_READOBJ_TYPE_CASE(PLTGOT);
+ LLVM_READOBJ_TYPE_CASE(PLTREL);
+ LLVM_READOBJ_TYPE_CASE(PLTRELSZ);
+ LLVM_READOBJ_TYPE_CASE(REL);
+ LLVM_READOBJ_TYPE_CASE(RELA);
+ LLVM_READOBJ_TYPE_CASE(RELENT);
+ LLVM_READOBJ_TYPE_CASE(RELSZ);
+ LLVM_READOBJ_TYPE_CASE(RELAENT);
+ LLVM_READOBJ_TYPE_CASE(RELASZ);
+ LLVM_READOBJ_TYPE_CASE(RPATH);
+ LLVM_READOBJ_TYPE_CASE(RUNPATH);
+ LLVM_READOBJ_TYPE_CASE(SONAME);
+ LLVM_READOBJ_TYPE_CASE(STRSZ);
+ LLVM_READOBJ_TYPE_CASE(STRTAB);
+ LLVM_READOBJ_TYPE_CASE(SYMBOLIC);
+ LLVM_READOBJ_TYPE_CASE(SYMENT);
+ LLVM_READOBJ_TYPE_CASE(SYMTAB);
+ LLVM_READOBJ_TYPE_CASE(TEXTREL);
+ default: return "unknown";
+ }
+}
+
+#undef LLVM_READOBJ_TYPE_CASE
+
+template<class ELFT>
+static 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 << "SharedLibrary ("
+ << O->getString(O->getDynamicStringTableSectionHeader(), Value) << ")";
+ break;
+ case DT_SONAME:
+ OS << "LibrarySoname ("
+ << O->getString(O->getDynamicStringTableSectionHeader(), Value) << ")";
+ break;
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printUnwindInfo() {
+ W.startLine() << "UnwindInfo not implemented.\n";
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printDynamicTable() {
+ typedef ELFObjectFile<ELFT> ELFO;
+ typedef typename ELFO::Elf_Dyn_iterator EDI;
+ EDI Start = Obj->begin_dynamic_table(),
+ End = Obj->end_dynamic_table(true);
+
+ if (Start == End)
+ return;
+
+ ptrdiff_t Total = std::distance(Start, End);
+ raw_ostream &OS = W.getOStream();
+ W.startLine() << "DynamicSection [ (" << Total << " entries)\n";
+
+ bool Is64 = Obj->getBytesInAddress() == 8;
+
+ W.startLine()
+ << " Tag" << (Is64 ? " " : " ") << "Type"
+ << " " << "Name/Value\n";
+ for (; Start != End; ++Start) {
+ W.startLine()
+ << " "
+ << format(Is64 ? "0x%016" PRIX64 : "0x%08" PRIX64, Start->getTag())
+ << " " << format("%-21s", getTypeString(Start->getTag()));
+ printValue(Obj, Start->getTag(), Start->getVal(), Is64, OS);
+ OS << "\n";
+ }
+
+ W.startLine() << "]\n";
+}
+
+static bool compareLibraryName(const LibraryRef &L, const LibraryRef &R) {
+ StringRef LPath, RPath;
+ L.getPath(LPath);
+ R.getPath(RPath);
+ return LPath < RPath;
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printNeededLibraries() {
+ ListScope D(W, "NeededLibraries");
+
+ error_code EC;
+
+ typedef std::vector<LibraryRef> LibsTy;
+ LibsTy Libs;
+
+ for (library_iterator I = Obj->begin_libraries_needed(),
+ E = Obj->end_libraries_needed();
+ I != E; I.increment(EC)) {
+ if (EC)
+ report_fatal_error("Needed libraries iteration failed");
+
+ Libs.push_back(*I);
+ }
+
+ std::sort(Libs.begin(), Libs.end(), &compareLibraryName);
+
+ for (LibsTy::const_iterator I = Libs.begin(), E = Libs.end();
+ I != E; ++I) {
+ StringRef Path;
+ I->getPath(Path);
+ outs() << " " << Path << "\n";
+ }
+}
diff --git a/tools/llvm-readobj/Error.cpp b/tools/llvm-readobj/Error.cpp
new file mode 100644
index 0000000000..a6c61321c6
--- /dev/null
+++ b/tools/llvm-readobj/Error.cpp
@@ -0,0 +1,62 @@
+//===- Error.cpp - system_error extensions for llvm-readobj -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines a new error_category for the llvm-readobj tool.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+
+namespace {
+class _readobj_error_category : public _do_message {
+public:
+ virtual const char* name() const;
+ virtual std::string message(int ev) const;
+ virtual error_condition default_error_condition(int ev) const;
+};
+} // namespace
+
+const char *_readobj_error_category::name() const {
+ return "llvm.readobj";
+}
+
+std::string _readobj_error_category::message(int ev) const {
+ switch (ev) {
+ case readobj_error::success: return "Success";
+ case readobj_error::file_not_found:
+ return "No such file.";
+ case readobj_error::unsupported_file_format:
+ return "The file was not recognized as a valid object file.";
+ case readobj_error::unrecognized_file_format:
+ return "Unrecognized file type.";
+ case readobj_error::unsupported_obj_file_format:
+ return "Unsupported object file format.";
+ case readobj_error::unknown_symbol:
+ return "Unknown symbol.";
+ default:
+ llvm_unreachable("An enumerator of readobj_error does not have a message "
+ "defined.");
+ }
+}
+
+error_condition _readobj_error_category::default_error_condition(int ev) const {
+ if (ev == readobj_error::success)
+ return errc::success;
+ return errc::invalid_argument;
+}
+
+namespace llvm {
+const error_category &readobj_category() {
+ static _readobj_error_category o;
+ return o;
+}
+} // namespace llvm
diff --git a/tools/llvm-readobj/Error.h b/tools/llvm-readobj/Error.h
new file mode 100644
index 0000000000..cf68da89c1
--- /dev/null
+++ b/tools/llvm-readobj/Error.h
@@ -0,0 +1,48 @@
+//===- Error.h - system_error extensions for llvm-readobj -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This declares a new error_category for the llvm-readobj tool.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_READOBJ_ERROR_H
+#define LLVM_READOBJ_ERROR_H
+
+#include "llvm/Support/system_error.h"
+
+namespace llvm {
+
+const error_category &readobj_category();
+
+struct readobj_error {
+ enum _ {
+ success = 0,
+ file_not_found,
+ unsupported_file_format,
+ unrecognized_file_format,
+ unsupported_obj_file_format,
+ unknown_symbol
+ };
+ _ v_;
+
+ readobj_error(_ v) : v_(v) {}
+ explicit readobj_error(int v) : v_(_(v)) {}
+ operator int() const {return v_;}
+};
+
+inline error_code make_error_code(readobj_error e) {
+ return error_code(static_cast<int>(e), readobj_category());
+}
+
+template <> struct is_error_code_enum<readobj_error> : true_type { };
+template <> struct is_error_code_enum<readobj_error::_> : true_type { };
+
+} // namespace llvm
+
+#endif
diff --git a/tools/llvm-readobj/LLVMBuild.txt b/tools/llvm-readobj/LLVMBuild.txt
index c9f934f4b6..813c12b752 100644
--- a/tools/llvm-readobj/LLVMBuild.txt
+++ b/tools/llvm-readobj/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-readobj
parent = Tools
-required_libraries = Archive BitReader Object
+required_libraries = all-targets Archive BitReader Object
diff --git a/tools/llvm-readobj/MachODumper.cpp b/tools/llvm-readobj/MachODumper.cpp
new file mode 100644
index 0000000000..798c941772
--- /dev/null
+++ b/tools/llvm-readobj/MachODumper.cpp
@@ -0,0 +1,438 @@
+//===-- MachODump.cpp - Object file dumping utility for llvm --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the MachO-specific dumper for llvm-readobj.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-readobj.h"
+#include "Error.h"
+#include "ObjDumper.h"
+#include "StreamWriter.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Support/Casting.h"
+
+using namespace llvm;
+using namespace object;
+
+namespace {
+
+class MachODumper : public ObjDumper {
+public:
+ MachODumper(const llvm::object::MachOObjectFile *Obj, StreamWriter& Writer)
+ : ObjDumper(Writer)
+ , Obj(Obj) { }
+
+ virtual void printFileHeaders() LLVM_OVERRIDE;
+ virtual void printSections() LLVM_OVERRIDE;
+ virtual void printRelocations() LLVM_OVERRIDE;
+ virtual void printSymbols() LLVM_OVERRIDE;
+ virtual void printDynamicSymbols() LLVM_OVERRIDE;
+ virtual void printUnwindInfo() LLVM_OVERRIDE;
+
+private:
+ void printSymbol(symbol_iterator SymI);
+
+ void printRelocation(section_iterator SecI, relocation_iterator RelI);
+
+ const llvm::object::MachOObjectFile *Obj;
+};
+
+} // namespace
+
+
+namespace llvm {
+
+error_code createMachODumper(const object::ObjectFile *Obj,
+ StreamWriter& Writer,
+ OwningPtr<ObjDumper> &Result) {
+ const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj);
+ if (!MachOObj)
+ return readobj_error::unsupported_obj_file_format;
+
+ Result.reset(new MachODumper(MachOObj, Writer));
+ return readobj_error::success;
+}
+
+} // namespace llvm
+
+
+static const EnumEntry<unsigned> MachOSectionTypes[] = {
+ { "Regular" , 0x00 },
+ { "ZeroFill" , 0x01 },
+ { "CStringLiterals" , 0x02 },
+ { "4ByteLiterals" , 0x03 },
+ { "8ByteLiterals" , 0x04 },
+ { "LiteralPointers" , 0x05 },
+ { "NonLazySymbolPointers" , 0x06 },
+ { "LazySymbolPointers" , 0x07 },
+ { "SymbolStubs" , 0x08 },
+ { "ModInitFuncs" , 0x09 },
+ { "ModTermFuncs" , 0x0A },
+ { "Coalesced" , 0x0B },
+ { "GBZeroFill" , 0x0C },
+ { "Interposing" , 0x0D },
+ { "16ByteLiterals" , 0x0E },
+ { "DTraceDOF" , 0x0F },
+ { "LazyDylibSymbolPoints" , 0x10 },
+ { "ThreadLocalRegular" , 0x11 },
+ { "ThreadLocalZerofill" , 0x12 },
+ { "ThreadLocalVariables" , 0x13 },
+ { "ThreadLocalVariablePointers" , 0x14 },
+ { "ThreadLocalInitFunctionPointers", 0x15 }
+};
+
+static const EnumEntry<unsigned> MachOSectionAttributes[] = {
+ { "LocReloc" , 1 << 0 /*S_ATTR_LOC_RELOC */ },
+ { "ExtReloc" , 1 << 1 /*S_ATTR_EXT_RELOC */ },
+ { "SomeInstructions" , 1 << 2 /*S_ATTR_SOME_INSTRUCTIONS */ },
+ { "Debug" , 1 << 17 /*S_ATTR_DEBUG */ },
+ { "SelfModifyingCode", 1 << 18 /*S_ATTR_SELF_MODIFYING_CODE*/ },
+ { "LiveSupport" , 1 << 19 /*S_ATTR_LIVE_SUPPORT */ },
+ { "NoDeadStrip" , 1 << 20 /*S_ATTR_NO_DEAD_STRIP */ },
+ { "StripStaticSyms" , 1 << 21 /*S_ATTR_STRIP_STATIC_SYMS */ },
+ { "NoTOC" , 1 << 22 /*S_ATTR_NO_TOC */ },
+ { "PureInstructions" , 1 << 23 /*S_ATTR_PURE_INSTRUCTIONS */ },
+};
+
+static const EnumEntry<unsigned> MachOSymbolRefTypes[] = {
+ { "UndefinedNonLazy", 0 },
+ { "ReferenceFlagUndefinedLazy", 1 },
+ { "ReferenceFlagDefined", 2 },
+ { "ReferenceFlagPrivateDefined", 3 },
+ { "ReferenceFlagPrivateUndefinedNonLazy", 4 },
+ { "ReferenceFlagPrivateUndefinedLazy", 5 }
+};
+
+static const EnumEntry<unsigned> MachOSymbolFlags[] = {
+ { "ReferencedDynamically", 0x10 },
+ { "NoDeadStrip", 0x20 },
+ { "WeakRef", 0x40 },
+ { "WeakDef", 0x80 }
+};
+
+static const EnumEntry<unsigned> MachOSymbolTypes[] = {
+ { "Undef", 0x0 },
+ { "External", 0x1 },
+ { "Abs", 0x2 },
+ { "Indirect", 0xA },
+ { "PreboundUndef", 0xC },
+ { "Section", 0xE },
+ { "PrivateExternal", 0x10 }
+};
+
+namespace {
+ enum {
+ N_STAB = 0xE0
+ };
+
+ struct MachOSection {
+ ArrayRef<char> Name;
+ ArrayRef<char> SegmentName;
+ uint64_t Address;
+ uint64_t Size;
+ uint32_t Offset;
+ uint32_t Alignment;
+ uint32_t RelocationTableOffset;
+ uint32_t NumRelocationTableEntries;
+ uint32_t Flags;
+ uint32_t Reserved1;
+ uint32_t Reserved2;
+ };
+
+ struct MachOSymbol {
+ uint32_t StringIndex;
+ uint8_t Type;
+ uint8_t SectionIndex;
+ uint16_t Flags;
+ uint64_t Value;
+ };
+}
+
+static StringRef parseSegmentOrSectionName(ArrayRef<char> P) {
+ if (P[15] == 0)
+ // Null terminated.
+ return StringRef(P.data());
+ // Not null terminated, so this is a 16 char string.
+ return StringRef(P.data(), 16);
+}
+
+static bool is64BitLoadCommand(const MachOObject *MachOObj, DataRefImpl DRI) {
+ LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
+ if (LCI.Command.Type == macho::LCT_Segment64)
+ return true;
+ assert(LCI.Command.Type == macho::LCT_Segment && "Unexpected Type.");
+ return false;
+}
+
+static void getSection(const MachOObject *MachOObj,
+ DataRefImpl DRI,
+ MachOSection &Section) {
+ LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
+ if (is64BitLoadCommand(MachOObj, DRI)) {
+ InMemoryStruct<macho::Section64> Sect;
+ MachOObj->ReadSection64(LCI, DRI.d.b, Sect);
+
+ Section.Name = ArrayRef<char>(Sect->Name);
+ Section.SegmentName = ArrayRef<char>(Sect->SegmentName);
+ Section.Address = Sect->Address;
+ Section.Size = Sect->Size;
+ Section.Offset = Sect->Offset;
+ Section.Alignment = Sect->Align;
+ Section.RelocationTableOffset = Sect->RelocationTableOffset;
+ Section.NumRelocationTableEntries = Sect->NumRelocationTableEntries;
+ Section.Flags = Sect->Flags;
+ Section.Reserved1 = Sect->Reserved1;
+ Section.Reserved2 = Sect->Reserved2;
+ } else {
+ InMemoryStruct<macho::Section> Sect;
+ MachOObj->ReadSection(LCI, DRI.d.b, Sect);
+
+ Section.Name = Sect->Name;
+ Section.SegmentName = Sect->SegmentName;
+ Section.Address = Sect->Address;
+ Section.Size = Sect->Size;
+ Section.Offset = Sect->Offset;
+ Section.Alignment = Sect->Align;
+ Section.RelocationTableOffset = Sect->RelocationTableOffset;
+ Section.NumRelocationTableEntries = Sect->NumRelocationTableEntries;
+ Section.Flags = Sect->Flags;
+ Section.Reserved1 = Sect->Reserved1;
+ Section.Reserved2 = Sect->Reserved2;
+ }
+}
+
+static void getSymbolTableEntry(const MachOObject *MachO,
+ DataRefImpl DRI,
+ InMemoryStruct<macho::SymbolTableEntry> &Res) {
+ InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd;
+ LoadCommandInfo LCI = MachO->getLoadCommandInfo(DRI.d.a);
+ MachO->ReadSymtabLoadCommand(LCI, SymtabLoadCmd);
+ MachO->ReadSymbolTableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, Res);
+}
+
+static void getSymbol64TableEntry(const MachOObject *MachO,
+ DataRefImpl DRI,
+ InMemoryStruct<macho::Symbol64TableEntry> &Res) {
+ InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd;
+ LoadCommandInfo LCI = MachO->getLoadCommandInfo(DRI.d.a);
+ MachO->ReadSymtabLoadCommand(LCI, SymtabLoadCmd);
+ MachO->ReadSymbol64TableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, Res);
+}
+
+static void getSymbol(const MachOObject *MachOObj,
+ DataRefImpl DRI,
+ MachOSymbol &Symbol) {
+ if (MachOObj->is64Bit()) {
+ InMemoryStruct<macho::Symbol64TableEntry> Entry;
+ getSymbol64TableEntry(MachOObj, DRI, Entry);
+ Symbol.StringIndex = Entry->StringIndex;
+ Symbol.Type = Entry->Type;
+ Symbol.SectionIndex = Entry->SectionIndex;
+ Symbol.Flags = Entry->Flags;
+ Symbol.Value = Entry->Value;
+ } else {
+ InMemoryStruct<macho::SymbolTableEntry> Entry;
+ getSymbolTableEntry(MachOObj, DRI, Entry);
+ Symbol.StringIndex = Entry->StringIndex;
+ Symbol.Type = Entry->Type;
+ Symbol.SectionIndex = Entry->SectionIndex;
+ Symbol.Flags = Entry->Flags;
+ Symbol.Value = Entry->Value;
+ }
+}
+
+void MachODumper::printFileHeaders() {
+ W.startLine() << "FileHeaders not implemented.\n";
+}
+
+void MachODumper::printSections() {
+ ListScope Group(W, "Sections");
+
+ int SectionIndex = -1;
+ error_code EC;
+ for (section_iterator SecI = Obj->begin_sections(),
+ SecE = Obj->end_sections();
+ SecI != SecE; SecI.increment(EC)) {
+ if (error(EC)) break;
+
+ ++SectionIndex;
+
+ const MachOObject *MachO = const_cast<MachOObjectFile*>(Obj)->getObject();
+
+ MachOSection Section;
+ getSection(MachO, SecI->getRawDataRefImpl(), Section);
+ StringRef Name;
+ if (error(SecI->getName(Name)))
+ Name = "";
+
+ DictScope SectionD(W, "Section");
+ W.printNumber("Index", SectionIndex);
+ W.printBinary("Name", Name, Section.Name);
+ W.printBinary("Segment", parseSegmentOrSectionName(Section.SegmentName),
+ Section.SegmentName);
+ W.printHex ("Address", Section.Address);
+ W.printHex ("Size", Section.Size);
+ W.printNumber("Offset", Section.Offset);
+ W.printNumber("Alignment", Section.Alignment);
+ W.printHex ("RelocationOffset", Section.RelocationTableOffset);
+ W.printNumber("RelocationCount", Section.NumRelocationTableEntries);
+ W.printEnum ("Type", Section.Flags & 0xFF,
+ makeArrayRef(MachOSectionAttributes));
+ W.printFlags ("Attributes", Section.Flags >> 8,
+ makeArrayRef(MachOSectionAttributes));
+ W.printHex ("Reserved1", Section.Reserved1);
+ W.printHex ("Reserved2", Section.Reserved2);
+
+ if (opts::SectionRelocations) {
+ ListScope D(W, "Relocations");
+ for (relocation_iterator RelI = SecI->begin_relocations(),
+ RelE = SecI->end_relocations();
+ RelI != RelE; RelI.increment(EC)) {
+ if (error(EC)) break;
+
+ printRelocation(SecI, RelI);
+ }
+ }
+
+ if (opts::SectionSymbols) {
+ ListScope D(W, "Symbols");
+ for (symbol_iterator SymI = Obj->begin_symbols(),
+ SymE = Obj->end_symbols();
+ SymI != SymE; SymI.increment(EC)) {
+ if (error(EC)) break;
+
+ bool Contained = false;
+ if (SecI->containsSymbol(*SymI, Contained) || !Contained)
+ continue;
+
+ printSymbol(SymI);
+ }
+ }
+
+ if (opts::SectionData) {
+ StringRef Data;
+ if (error(SecI->getContents(Data))) break;
+
+ W.printBinaryBlock("SectionData", Data);
+ }
+ }
+}
+
+void MachODumper::printRelocations() {
+ ListScope D(W, "Relocations");
+
+ error_code EC;
+ for (section_iterator SecI = Obj->begin_sections(),
+ SecE = Obj->end_sections();
+ SecI != SecE; SecI.increment(EC)) {
+ if (error(EC)) break;
+
+ StringRef Name;
+ if (error(SecI->getName(Name)))
+ continue;
+
+ bool PrintedGroup = false;
+ for (relocation_iterator RelI = SecI->begin_relocations(),
+ RelE = SecI->end_relocations();
+ RelI != RelE; RelI.increment(EC)) {
+ if (error(EC)) break;
+
+ if (!PrintedGroup) {
+ W.startLine() << "Section " << Name << " {\n";
+ W.indent();
+ PrintedGroup = true;
+ }
+
+ printRelocation(SecI, RelI);
+ }
+
+ if (PrintedGroup) {
+ W.unindent();
+ W.startLine() << "}\n";
+ }
+ }
+}
+
+void MachODumper::printRelocation(section_iterator SecI,
+ relocation_iterator RelI) {
+ uint64_t Offset;
+ SmallString<32> RelocName;
+ int64_t Info;
+ StringRef SymbolName;
+ SymbolRef Symbol;
+ if (error(RelI->getOffset(Offset))) return;
+ if (error(RelI->getTypeName(RelocName))) return;
+ if (error(RelI->getAdditionalInfo(Info))) return;
+ if (error(RelI->getSymbol(Symbol))) return;
+ if (error(Symbol.getName(SymbolName))) return;
+
+ raw_ostream& OS = W.startLine();
+ OS << W.hex(Offset)
+ << " " << RelocName
+ << " " << (SymbolName.size() > 0 ? SymbolName : "-")
+ << " " << W.hex(Info)
+ << "\n";
+}
+
+void MachODumper::printSymbols() {
+ ListScope Group(W, "Symbols");
+
+ error_code EC;
+ for (symbol_iterator SymI = Obj->begin_symbols(),
+ SymE = Obj->end_symbols();
+ SymI != SymE; SymI.increment(EC)) {
+ if (error(EC)) break;
+
+ printSymbol(SymI);
+ }
+}
+
+void MachODumper::printDynamicSymbols() {
+ ListScope Group(W, "DynamicSymbols");
+}
+
+void MachODumper::printSymbol(symbol_iterator SymI) {
+ error_code EC;
+
+ StringRef SymbolName;
+ if (SymI->getName(SymbolName))
+ SymbolName = "";
+
+ const MachOObject *MachO = const_cast<MachOObjectFile*>(Obj)->getObject();
+
+ MachOSymbol Symbol;
+ getSymbol(MachO, SymI->getRawDataRefImpl(), Symbol);
+
+ StringRef SectionName;
+ section_iterator SecI(Obj->end_sections());
+ if (error(SymI->getSection(SecI)) ||
+ error(SecI->getName(SectionName)))
+ SectionName = "";
+
+ DictScope D(W, "Symbol");
+ W.printNumber("Name", SymbolName, Symbol.StringIndex);
+ if (Symbol.Type & N_STAB) {
+ W.printHex ("Type", "SymDebugTable", Symbol.Type);
+ } else {
+ W.printEnum("Type", Symbol.Type, makeArrayRef(MachOSymbolTypes));
+ }
+ W.printHex ("Section", SectionName, Symbol.SectionIndex);
+ W.printEnum ("RefType", static_cast<uint16_t>(Symbol.Flags & 0xF),
+ makeArrayRef(MachOSymbolRefTypes));
+ W.printFlags ("Flags", static_cast<uint16_t>(Symbol.Flags & ~0xF),
+ makeArrayRef(MachOSymbolFlags));
+ W.printHex ("Value", Symbol.Value);
+}
+
+void MachODumper::printUnwindInfo() {
+ W.startLine() << "UnwindInfo not implemented.\n";
+}
diff --git a/tools/llvm-readobj/Makefile b/tools/llvm-readobj/Makefile
index a7a7de3563..1bb72955f0 100644
--- a/tools/llvm-readobj/Makefile
+++ b/tools/llvm-readobj/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := llvm-readobj
-LINK_COMPONENTS := archive bitreader object
+LINK_COMPONENTS := archive bitreader object all-targets
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS := 1
diff --git a/tools/llvm-readobj/ObjDumper.cpp b/tools/llvm-readobj/ObjDumper.cpp
new file mode 100644
index 0000000000..61f511740a
--- /dev/null
+++ b/tools/llvm-readobj/ObjDumper.cpp
@@ -0,0 +1,33 @@
+//===-- ObjDumper.cpp - Base dumper class -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements ObjDumper.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ObjDumper.h"
+
+#include "Error.h"
+#include "StreamWriter.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+ObjDumper::ObjDumper(StreamWriter& Writer)
+ : W(Writer) {
+}
+
+ObjDumper::~ObjDumper() {
+}
+
+} // namespace llvm
diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h
new file mode 100644
index 0000000000..8d191cbe07
--- /dev/null
+++ b/tools/llvm-readobj/ObjDumper.h
@@ -0,0 +1,60 @@
+//===-- ObjDumper.h -------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_READOBJ_OBJDUMPER_H
+#define LLVM_READOBJ_OBJDUMPER_H
+
+namespace llvm {
+
+namespace object {
+ class ObjectFile;
+}
+
+class error_code;
+
+template<typename T>
+class OwningPtr;
+
+class StreamWriter;
+
+class ObjDumper {
+public:
+ ObjDumper(StreamWriter& Writer);
+ virtual ~ObjDumper();
+
+ virtual void printFileHeaders() = 0;
+ virtual void printSections() = 0;
+ virtual void printRelocations() = 0;
+ virtual void printSymbols() = 0;
+ virtual void printDynamicSymbols() = 0;
+ virtual void printUnwindInfo() = 0;
+
+ // Only implemented for ELF at this time.
+ virtual void printDynamicTable() { }
+ virtual void printNeededLibraries() { }
+
+protected:
+ StreamWriter& W;
+};
+
+error_code createCOFFDumper(const object::ObjectFile *Obj,
+ StreamWriter& Writer,
+ OwningPtr<ObjDumper> &Result);
+
+error_code createELFDumper(const object::ObjectFile *Obj,
+ StreamWriter& Writer,
+ OwningPtr<ObjDumper> &Result);
+
+error_code createMachODumper(const object::ObjectFile *Obj,
+ StreamWriter& Writer,
+ OwningPtr<ObjDumper> &Result);
+
+} // namespace llvm
+
+#endif
diff --git a/tools/llvm-readobj/StreamWriter.cpp b/tools/llvm-readobj/StreamWriter.cpp
new file mode 100644
index 0000000000..871811233a
--- /dev/null
+++ b/tools/llvm-readobj/StreamWriter.cpp
@@ -0,0 +1,79 @@
+#include "StreamWriter.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Format.h"
+#include <cctype>
+
+using namespace llvm::support;
+
+namespace llvm {
+
+raw_ostream &operator<<(raw_ostream &OS, const HexNumber& Value) {
+ uint64_t N = Value.Value;
+ // Zero is a special case.
+ if (N == 0)
+ return OS << "0x0";
+
+ char NumberBuffer[20];
+ char *EndPtr = NumberBuffer + sizeof(NumberBuffer);
+ char *CurPtr = EndPtr;
+
+ while (N) {
+ uintptr_t X = N % 16;
+ *--CurPtr = (X < 10 ? '0' + X : 'A' + X - 10);
+ N /= 16;
+ }
+
+ OS << "0x";
+ return OS.write(CurPtr, EndPtr - CurPtr);
+}
+
+void StreamWriter::printBinaryImpl(StringRef Label, StringRef Str,
+ ArrayRef<uint8_t> Data, bool Block) {
+ if (Data.size() > 16)
+ Block = true;
+
+ if (Block) {
+ startLine() << Label;
+ if (Str.size() > 0)
+ OS << ": " << Str;
+ OS << " (\n";
+ for (size_t addr = 0, end = Data.size(); addr < end; addr += 16) {
+ startLine() << format(" %04" PRIX64 ": ", uint64_t(addr));
+ // Dump line of hex.
+ for (size_t i = 0; i < 16; ++i) {
+ if (i != 0 && i % 4 == 0)
+ OS << ' ';
+ if (addr + i < end)
+ OS << hexdigit((Data[addr + i] >> 4) & 0xF, false)
+ << hexdigit(Data[addr + i] & 0xF, false);
+ else
+ OS << " ";
+ }
+ // Print ascii.
+ OS << " |";
+ for (std::size_t i = 0; i < 16 && addr + i < end; ++i) {
+ if (std::isprint(Data[addr + i] & 0xFF))
+ OS << Data[addr + i];
+ else
+ OS << ".";
+ }
+ OS << "|\n";
+ }
+
+ startLine() << ")\n";
+ } else {
+ startLine() << Label << ":";
+ if (Str.size() > 0)
+ OS << " " << Str;
+ OS << " (";
+ for (size_t i = 0; i < Data.size(); ++i) {
+ if (i > 0)
+ OS << " ";
+
+ OS << format("%02X", static_cast<int>(Data[i]));
+ }
+ OS << ")\n";
+ }
+}
+
+} // namespace llvm
diff --git a/tools/llvm-readobj/StreamWriter.h b/tools/llvm-readobj/StreamWriter.h
new file mode 100644
index 0000000000..129f6e7933
--- /dev/null
+++ b/tools/llvm-readobj/StreamWriter.h
@@ -0,0 +1,282 @@
+//===-- StreamWriter.h ----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_READOBJ_STREAMWRITER_H
+#define LLVM_READOBJ_STREAMWRITER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+using namespace llvm;
+using namespace llvm::support;
+
+namespace llvm {
+
+template<typename T>
+struct EnumEntry {
+ StringRef Name;
+ T Value;
+};
+
+struct HexNumber {
+ // To avoid sign-extension we have to explicitly cast to the appropriate
+ // unsigned type. The overloads are here so that every type that is implicitly
+ // convertible to an integer (including enums and endian helpers) can be used
+ // without requiring type traits or call-site changes.
+ HexNumber(int8_t Value) : Value(static_cast<uint8_t >(Value)) { }
+ HexNumber(int16_t Value) : Value(static_cast<uint16_t>(Value)) { }
+ HexNumber(int32_t Value) : Value(static_cast<uint32_t>(Value)) { }
+ HexNumber(int64_t Value) : Value(static_cast<uint64_t>(Value)) { }
+ HexNumber(uint8_t Value) : Value(Value) { }
+ HexNumber(uint16_t Value) : Value(Value) { }
+ HexNumber(uint32_t Value) : Value(Value) { }
+ HexNumber(uint64_t Value) : Value(Value) { }
+ uint64_t Value;
+};
+
+raw_ostream &operator<<(raw_ostream &OS, const HexNumber& Value);
+
+class StreamWriter {
+public:
+ StreamWriter(raw_ostream &OS)
+ : OS(OS)
+ , IndentLevel(0) {
+ }
+
+ void flush() {
+ OS.flush();
+ }
+
+ void indent(int Levels = 1) {
+ IndentLevel += Levels;
+ }
+
+ void unindent(int Levels = 1) {
+ IndentLevel = std::max(0, IndentLevel - Levels);
+ }
+
+ void printIndent() {
+ for (int i = 0; i < IndentLevel; ++i)
+ OS << " ";
+ }
+
+ template<typename T>
+ HexNumber hex(T Value) {
+ return HexNumber(Value);
+ }
+
+ template<typename T, typename TEnum>
+ void printEnum(StringRef Label, T Value,
+ ArrayRef<EnumEntry<TEnum> > EnumValues) {
+ StringRef Name;
+ bool Found = false;
+ for (size_t i = 0; i < EnumValues.size(); ++i) {
+ if (EnumValues[i].Value == Value) {
+ Name = EnumValues[i].Name;
+ Found = true;
+ break;
+ }
+ }
+
+ if (Found) {
+ startLine() << Label << ": " << Name << " (" << hex(Value) << ")\n";
+ } else {
+ startLine() << Label << ": " << hex(Value) << "\n";
+ }
+ }
+
+ template<typename T, typename TFlag>
+ void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag> > Flags,
+ TFlag EnumMask = TFlag(0)) {
+ typedef EnumEntry<TFlag> FlagEntry;
+ typedef SmallVector<FlagEntry, 10> FlagVector;
+ FlagVector SetFlags;
+
+ for (typename ArrayRef<FlagEntry>::const_iterator I = Flags.begin(),
+ E = Flags.end(); I != E; ++I) {
+ if (I->Value == 0)
+ continue;
+
+ bool IsEnum = (I->Value & EnumMask) != 0;
+ if ((!IsEnum && (Value & I->Value) == I->Value) ||
+ (IsEnum && (Value & EnumMask) == I->Value)) {
+ SetFlags.push_back(*I);
+ }
+ }
+
+ std::sort(SetFlags.begin(), SetFlags.end(), &flagName<TFlag>);
+
+ startLine() << Label << " [ (" << hex(Value) << ")\n";
+ for (typename FlagVector::const_iterator I = SetFlags.begin(),
+ E = SetFlags.end();
+ I != E; ++I) {
+ startLine() << " " << I->Name << " (" << hex(I->Value) << ")\n";
+ }
+ startLine() << "]\n";
+ }
+
+ template<typename T>
+ void printFlags(StringRef Label, T Value) {
+ startLine() << Label << " [ (" << hex(Value) << ")\n";
+ uint64_t Flag = 1;
+ uint64_t Curr = Value;
+ while (Curr > 0) {
+ if (Curr & 1)
+ startLine() << " " << hex(Flag) << "\n";
+ Curr >>= 1;
+ Flag <<= 1;
+ }
+ startLine() << "]\n";
+ }
+
+ void printNumber(StringRef Label, uint64_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printNumber(StringRef Label, uint32_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printNumber(StringRef Label, uint16_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printNumber(StringRef Label, uint8_t Value) {
+ startLine() << Label << ": " << unsigned(Value) << "\n";
+ }
+
+ void printNumber(StringRef Label, int64_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printNumber(StringRef Label, int32_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printNumber(StringRef Label, int16_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printNumber(StringRef Label, int8_t Value) {
+ startLine() << Label << ": " << int(Value) << "\n";
+ }
+
+ template<typename T>
+ void printHex(StringRef Label, T Value) {
+ startLine() << Label << ": " << hex(Value) << "\n";
+ }
+
+ template<typename T>
+ void printHex(StringRef Label, StringRef Str, T Value) {
+ startLine() << Label << ": " << Str << " (" << hex(Value) << ")\n";
+ }
+
+ void printString(StringRef Label, StringRef Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printString(StringRef Label, const std::string &Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ template<typename T>
+ void printNumber(StringRef Label, StringRef Str, T Value) {
+ startLine() << Label << ": " << Str << " (" << Value << ")\n";
+ }
+
+ void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) {
+ printBinaryImpl(Label, Str, Value, false);
+ }
+
+ void printBinary(StringRef Label, StringRef Str, ArrayRef<char> Value) {
+ ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()),
+ Value.size());
+ printBinaryImpl(Label, Str, V, false);
+ }
+
+ void printBinary(StringRef Label, ArrayRef<uint8_t> Value) {
+ printBinaryImpl(Label, StringRef(), Value, false);
+ }
+
+ void printBinary(StringRef Label, ArrayRef<char> Value) {
+ ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()),
+ Value.size());
+ printBinaryImpl(Label, StringRef(), V, false);
+ }
+
+ void printBinary(StringRef Label, StringRef Value) {
+ ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()),
+ Value.size());
+ printBinaryImpl(Label, StringRef(), V, false);
+ }
+
+ void printBinaryBlock(StringRef Label, StringRef Value) {
+ ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()),
+ Value.size());
+ printBinaryImpl(Label, StringRef(), V, true);
+ }
+
+ raw_ostream& startLine() {
+ printIndent();
+ return OS;
+ }
+
+ raw_ostream& getOStream() {
+ return OS;
+ }
+
+private:
+ template<typename T>
+ static bool flagName(const EnumEntry<T>& lhs, const EnumEntry<T>& rhs) {
+ return lhs.Name < rhs.Name;
+ }
+
+ void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value,
+ bool Block);
+
+ raw_ostream &OS;
+ int IndentLevel;
+};
+
+struct DictScope {
+ DictScope(StreamWriter& W, StringRef N) : W(W) {
+ W.startLine() << N << " {\n";
+ W.indent();
+ }
+
+ ~DictScope() {
+ W.unindent();
+ W.startLine() << "}\n";
+ }
+
+ StreamWriter& W;
+};
+
+struct ListScope {
+ ListScope(StreamWriter& W, StringRef N) : W(W) {
+ W.startLine() << N << " [\n";
+ W.indent();
+ }
+
+ ~ListScope() {
+ W.unindent();
+ W.startLine() << "]\n";
+ }
+
+ StreamWriter& W;
+};
+
+} // namespace llvm
+
+#endif
diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp
index ea37d105dc..67c9a98f40 100644
--- a/tools/llvm-readobj/llvm-readobj.cpp
+++ b/tools/llvm-readobj/llvm-readobj.cpp
@@ -21,268 +21,263 @@
#include "llvm-readobj.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/Analysis/Verifier.h"
-#include "llvm/Object/ELF.h"
+#include "Error.h"
+#include "ObjDumper.h"
+#include "StreamWriter.h"
+
+#include "llvm/Object/Archive.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Debug.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/system_error.h"
+
+#include <string>
+
using namespace llvm;
using namespace llvm::object;
-static cl::opt<std::string>
-InputFilename(cl::Positional, cl::desc("<input object>"), cl::init(""));
-
-static void dumpSymbolHeader() {
- outs() << format(" %-32s", (const char *)"Name")
- << format(" %-4s", (const char *)"Type")
- << format(" %-4s", (const char *)"Section")
- << format(" %-16s", (const char *)"Address")
- << format(" %-16s", (const char *)"Size")
- << format(" %-16s", (const char *)"FileOffset")
- << format(" %-26s", (const char *)"Flags") << "\n";
+namespace opts {
+ cl::list<std::string> InputFilenames(cl::Positional,
+ cl::desc("<input object files>"),
+ cl::ZeroOrMore);
+
+ // -file-headers, -h
+ cl::opt<bool> FileHeaders("file-headers",
+ cl::desc("Display file headers "));
+ cl::alias FileHeadersShort("h",
+ cl::desc("Alias for --file-headers"),
+ cl::aliasopt(FileHeaders));
+
+ // -sections, -s
+ cl::opt<bool> Sections("sections",
+ cl::desc("Display all sections."));
+ cl::alias SectionsShort("s",
+ cl::desc("Alias for --sections"),
+ cl::aliasopt(Sections));
+
+ // -section-relocations, -sr
+ cl::opt<bool> SectionRelocations("section-relocations",
+ cl::desc("Display relocations for each section shown."));
+ cl::alias SectionRelocationsShort("sr",
+ cl::desc("Alias for --section-relocations"),
+ cl::aliasopt(SectionRelocations));
+
+ // -section-symbols, -st
+ cl::opt<bool> SectionSymbols("section-symbols",
+ cl::desc("Display symbols for each section shown."));
+ cl::alias SectionSymbolsShort("st",
+ cl::desc("Alias for --section-symbols"),
+ cl::aliasopt(SectionSymbols));
+
+ // -section-data, -sd
+ cl::opt<bool> SectionData("section-data",
+ cl::desc("Display section data for each section shown."));
+ cl::alias SectionDataShort("sd",
+ cl::desc("Alias for --section-data"),
+ cl::aliasopt(SectionData));
+
+ // -relocations, -r
+ cl::opt<bool> Relocations("relocations",
+ cl::desc("Display the relocation entries in the file"));
+ cl::alias RelocationsShort("r",
+ cl::desc("Alias for --relocations"),
+ cl::aliasopt(Relocations));
+
+ // -symbols, -t
+ cl::opt<bool> Symbols("symbols",
+ cl::desc("Display the symbol table"));
+ cl::alias SymbolsShort("t",
+ cl::desc("Alias for --symbols"),
+ cl::aliasopt(Symbols));
+
+ // -dyn-symbols, -dt
+ cl::opt<bool> DynamicSymbols("dyn-symbols",
+ cl::desc("Display the dynamic symbol table"));
+ cl::alias DynamicSymbolsShort("dt",
+ cl::desc("Alias for --dyn-symbols"),
+ cl::aliasopt(DynamicSymbols));
+
+ // -unwind, -u
+ cl::opt<bool> UnwindInfo("unwind",
+ cl::desc("Display unwind information"));
+ cl::alias UnwindInfoShort("u",
+ cl::desc("Alias for --unwind"),
+ cl::aliasopt(UnwindInfo));
+
+ // -dynamic-table
+ cl::opt<bool> DynamicTable("dynamic-table",
+ cl::desc("Display the ELF .dynamic section table"));
+
+ // -needed-libs
+ cl::opt<bool> NeededLibraries("needed-libs",
+ cl::desc("Display the needed libraries"));
+} // namespace opts
+
+namespace llvm {
+
+bool error(error_code EC) {
+ if (!EC)
+ return false;
+
+ outs() << "\nError reading file: " << EC.message() << ".\n";
+ outs().flush();
+ return true;
}
-static void dumpSectionHeader() {
- outs() << format(" %-24s", (const char*)"Name")
- << format(" %-16s", (const char*)"Address")
- << format(" %-16s", (const char*)"Size")
- << format(" %-8s", (const char*)"Align")
- << format(" %-26s", (const char*)"Flags")
- << "\n";
+bool relocAddressLess(RelocationRef a, RelocationRef b) {
+ uint64_t a_addr, b_addr;
+ if (error(a.getAddress(a_addr))) return false;
+ if (error(b.getAddress(b_addr))) return false;
+ return a_addr < b_addr;
}
-static const char *getTypeStr(SymbolRef::Type Type) {
- switch (Type) {
- case SymbolRef::ST_Unknown: return "?";
- case SymbolRef::ST_Data: return "DATA";
- case SymbolRef::ST_Debug: return "DBG";
- case SymbolRef::ST_File: return "FILE";
- case SymbolRef::ST_Function: return "FUNC";
- case SymbolRef::ST_Other: return "-";
- }
- return "INV";
-}
-
-static std::string getSymbolFlagStr(uint32_t Flags) {
- std::string result;
- if (Flags & SymbolRef::SF_Undefined)
- result += "undef,";
- if (Flags & SymbolRef::SF_Global)
- result += "global,";
- if (Flags & SymbolRef::SF_Weak)
- result += "weak,";
- if (Flags & SymbolRef::SF_Absolute)
- result += "absolute,";
- if (Flags & SymbolRef::SF_ThreadLocal)
- result += "threadlocal,";
- if (Flags & SymbolRef::SF_Common)
- result += "common,";
- if (Flags & SymbolRef::SF_FormatSpecific)
- result += "formatspecific,";
-
- // Remove trailing comma
- if (result.size() > 0) {
- result.erase(result.size() - 1);
- }
- return result;
-}
+} // namespace llvm
-static void checkError(error_code ec, const char *msg) {
- if (ec)
- report_fatal_error(std::string(msg) + ": " + ec.message());
-}
-static std::string getSectionFlagStr(const SectionRef &Section) {
- const struct {
- error_code (SectionRef::*MemF)(bool &) const;
- const char *FlagStr, *ErrorStr;
- } Work[] =
- {{ &SectionRef::isText, "text,", "Section.isText() failed" },
- { &SectionRef::isData, "data,", "Section.isData() failed" },
- { &SectionRef::isBSS, "bss,", "Section.isBSS() failed" },
- { &SectionRef::isRequiredForExecution, "required,",
- "Section.isRequiredForExecution() failed" },
- { &SectionRef::isVirtual, "virtual,", "Section.isVirtual() failed" },
- { &SectionRef::isZeroInit, "zeroinit,", "Section.isZeroInit() failed" },
- { &SectionRef::isReadOnlyData, "rodata,",
- "Section.isReadOnlyData() failed" }};
-
- std::string result;
- for (uint32_t I = 0; I < sizeof(Work)/sizeof(*Work); ++I) {
- bool B;
- checkError((Section.*Work[I].MemF)(B), Work[I].ErrorStr);
- if (B)
- result += Work[I].FlagStr;
- }
+static void reportError(StringRef Input, error_code EC) {
+ if (Input == "-")
+ Input = "<stdin>";
- // Remove trailing comma
- if (result.size() > 0) {
- result.erase(result.size() - 1);
- }
- return result;
+ errs() << Input << ": " << EC.message() << "\n";
+ errs().flush();
}
-static void
-dumpSymbol(const SymbolRef &Sym, const ObjectFile *obj, bool IsDynamic) {
- StringRef Name;
- SymbolRef::Type Type;
- uint32_t Flags;
- uint64_t Address;
- uint64_t Size;
- uint64_t FileOffset;
- checkError(Sym.getName(Name), "SymbolRef.getName() failed");
- checkError(Sym.getAddress(Address), "SymbolRef.getAddress() failed");
- checkError(Sym.getSize(Size), "SymbolRef.getSize() failed");
- checkError(Sym.getFileOffset(FileOffset),
- "SymbolRef.getFileOffset() failed");
- checkError(Sym.getType(Type), "SymbolRef.getType() failed");
- checkError(Sym.getFlags(Flags), "SymbolRef.getFlags() failed");
- std::string FullName = Name;
-
- llvm::object::section_iterator symSection(obj->begin_sections());
- Sym.getSection(symSection);
- StringRef sectionName;
-
- if (symSection != obj->end_sections())
- checkError(symSection->getName(sectionName),
- "SectionRef::getName() failed");
-
- // If this is a dynamic symbol from an ELF object, append
- // the symbol's version to the name.
- if (IsDynamic && obj->isELF()) {
- StringRef Version;
- bool IsDefault;
- GetELFSymbolVersion(obj, Sym, Version, IsDefault);
- if (!Version.empty()) {
- FullName += (IsDefault ? "@@" : "@");
- FullName += Version;
- }
- }
+static void reportError(StringRef Input, StringRef Message) {
+ if (Input == "-")
+ Input = "<stdin>";
- // format() can't handle StringRefs
- outs() << format(" %-32s", FullName.c_str())
- << format(" %-4s", getTypeStr(Type))
- << format(" %-32s", std::string(sectionName).c_str())
- << format(" %16" PRIx64, Address) << format(" %16" PRIx64, Size)
- << format(" %16" PRIx64, FileOffset) << " "
- << getSymbolFlagStr(Flags) << "\n";
+ errs() << Input << ": " << Message << "\n";
}
-static void dumpStaticSymbol(const SymbolRef &Sym, const ObjectFile *obj) {
- return dumpSymbol(Sym, obj, false);
+/// @brief Creates an format-specific object file dumper.
+static error_code createDumper(const ObjectFile *Obj,
+ StreamWriter &Writer,
+ OwningPtr<ObjDumper> &Result) {
+ if (!Obj)
+ return readobj_error::unsupported_file_format;
+
+ if (Obj->isCOFF())
+ return createCOFFDumper(Obj, Writer, Result);
+ if (Obj->isELF())
+ return createELFDumper(Obj, Writer, Result);
+ if (Obj->isMachO())
+ return createMachODumper(Obj, Writer, Result);
+
+ return readobj_error::unsupported_obj_file_format;
}
-static void dumpDynamicSymbol(const SymbolRef &Sym, const ObjectFile *obj) {
- return dumpSymbol(Sym, obj, true);
-}
-
-static void dumpSection(const SectionRef &Section, const ObjectFile *obj) {
- StringRef Name;
- checkError(Section.getName(Name), "SectionRef::getName() failed");
- uint64_t Addr, Size, Align;
- checkError(Section.getAddress(Addr), "SectionRef::getAddress() failed");
- checkError(Section.getSize(Size), "SectionRef::getSize() failed");
- checkError(Section.getAlignment(Align), "SectionRef::getAlignment() failed");
- outs() << format(" %-24s", std::string(Name).c_str())
- << format(" %16" PRIx64, Addr)
- << format(" %16" PRIx64, Size)
- << format(" %8" PRIx64, Align)
- << " " << getSectionFlagStr(Section)
- << "\n";
-}
-static void dumpLibrary(const LibraryRef &lib, const ObjectFile *obj) {
- StringRef path;
- lib.getPath(path);
- outs() << " " << path << "\n";
-}
-
-template<typename Iterator, typename Func>
-static void dump(const ObjectFile *obj, Func f, Iterator begin, Iterator end,
- const char *errStr) {
- error_code ec;
- uint32_t count = 0;
- Iterator it = begin, ie = end;
- while (it != ie) {
- f(*it, obj);
- it.increment(ec);
- if (ec)
- report_fatal_error(errStr);
- ++count;
+/// @brief Dumps the specified object file.
+static void dumpObject(const ObjectFile *Obj) {
+ StreamWriter Writer(outs());
+ OwningPtr<ObjDumper> Dumper;
+ if (error_code EC = createDumper(Obj, Writer, Dumper)) {
+ reportError(Obj->getFileName(), EC);
+ return;
}
- outs() << " Total: " << count << "\n\n";
-}
-static void dumpHeaders(const ObjectFile *obj) {
- outs() << "File Format : " << obj->getFileFormatName() << "\n";
- outs() << "Arch : "
- << Triple::getArchTypeName((llvm::Triple::ArchType)obj->getArch())
+ outs() << '\n';
+ outs() << "File: " << Obj->getFileName() << "\n";
+ outs() << "Format: " << Obj->getFileFormatName() << "\n";
+ outs() << "Arch: "
+ << Triple::getArchTypeName((llvm::Triple::ArchType)Obj->getArch())
<< "\n";
- outs() << "Address Size: " << (8*obj->getBytesInAddress()) << " bits\n";
- outs() << "Load Name : " << obj->getLoadName() << "\n";
- outs() << "\n";
+ outs() << "AddressSize: " << (8*Obj->getBytesInAddress()) << "bit\n";
+ if (Obj->isELF())
+ outs() << "LoadName: " << Obj->getLoadName() << "\n";
+
+ if (opts::FileHeaders)
+ Dumper->printFileHeaders();
+ if (opts::Sections)
+ Dumper->printSections();
+ if (opts::Relocations)
+ Dumper->printRelocations();
+ if (opts::Symbols)
+ Dumper->printSymbols();
+ if (opts::DynamicSymbols)
+ Dumper->printDynamicSymbols();
+ if (opts::UnwindInfo)
+ Dumper->printUnwindInfo();
+ if (opts::DynamicTable)
+ Dumper->printDynamicTable();
+ if (opts::NeededLibraries)
+ Dumper->printNeededLibraries();
}
-int main(int argc, char** argv) {
- error_code ec;
- sys::PrintStackTraceOnErrorSignal();
- PrettyStackTraceProgram X(argc, argv);
- cl::ParseCommandLineOptions(argc, argv,
- "LLVM Object Reader\n");
+/// @brief Dumps each object file in \a Arc;
+static void dumpArchive(const Archive *Arc) {
+ for (Archive::child_iterator ArcI = Arc->begin_children(),
+ ArcE = Arc->end_children();
+ ArcI != ArcE; ++ArcI) {
+ OwningPtr<Binary> child;
+ if (error_code EC = ArcI->getAsBinary(child)) {
+ // Ignore non-object files.
+ if (EC != object_error::invalid_file_type)
+ reportError(Arc->getFileName(), EC.message());
+ continue;
+ }
- if (InputFilename.empty()) {
- errs() << "Please specify an input filename\n";
- return 1;
+ if (ObjectFile *Obj = dyn_cast<ObjectFile>(child.get()))
+ dumpObject(Obj);
+ else
+ reportError(Arc->getFileName(), readobj_error::unrecognized_file_format);
}
+}
+
- // Open the object file
- OwningPtr<MemoryBuffer> File;
- if (MemoryBuffer::getFile(InputFilename, File)) {
- errs() << InputFilename << ": Open failed\n";
- return 1;
+/// @brief Opens \a File and dumps it.
+static void dumpInput(StringRef File) {
+ // If file isn't stdin, check that it exists.
+ if (File != "-" && !sys::fs::exists(File)) {
+ reportError(File, readobj_error::file_not_found);
+ return;
}
- OwningPtr<ObjectFile> o(ObjectFile::createObjectFile(File.take()));
- ObjectFile *obj = o.get();
- if (!obj) {
- errs() << InputFilename << ": Object type not recognized\n";
+ // Attempt to open the binary.
+ OwningPtr<Binary> Binary;
+ if (error_code EC = createBinary(File, Binary)) {
+ reportError(File, EC);
+ return;
}
- dumpHeaders(obj);
+ if (Archive *Arc = dyn_cast<Archive>(Binary.get()))
+ dumpArchive(Arc);
+ else if (ObjectFile *Obj = dyn_cast<ObjectFile>(Binary.get()))
+ dumpObject(Obj);
+ else
+ reportError(File, readobj_error::unrecognized_file_format);
+}
- outs() << "Symbols:\n";
- dumpSymbolHeader();
- dump(obj, dumpStaticSymbol, obj->begin_symbols(), obj->end_symbols(),
- "Symbol iteration failed");
- outs() << "Dynamic Symbols:\n";
- dumpSymbolHeader();
- dump(obj, dumpDynamicSymbol, obj->begin_dynamic_symbols(),
- obj->end_dynamic_symbols(), "Symbol iteration failed");
+int main(int argc, const char *argv[]) {
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+ llvm_shutdown_obj Y;
- outs() << "Sections:\n";
- dumpSectionHeader();
- dump(obj, &dumpSection, obj->begin_sections(), obj->end_sections(),
- "Section iteration failed");
+ // Initialize targets.
+ llvm::InitializeAllTargetInfos();
- if (obj->isELF()) {
- if (ErrorOr<void> e = dumpELFDynamicTable(obj, outs()))
- ;
- else
- errs() << "InputFilename" << ": " << error_code(e).message() << "\n";
- }
+ // Register the target printer for --version.
+ cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
+
+ cl::ParseCommandLineOptions(argc, argv, "LLVM Object Reader\n");
- outs() << "Libraries needed:\n";
- dump(obj, &dumpLibrary, obj->begin_libraries_needed(),
- obj->end_libraries_needed(), "Needed libraries iteration failed");
+ // Default to stdin if no filename is specified.
+ if (opts::InputFilenames.size() == 0)
+ opts::InputFilenames.push_back("-");
+
+ std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(),
+ dumpInput);
return 0;
}
-
diff --git a/tools/llvm-readobj/llvm-readobj.h b/tools/llvm-readobj/llvm-readobj.h
index cf492b2a8d..be18268a7f 100644
--- a/tools/llvm-readobj/llvm-readobj.h
+++ b/tools/llvm-readobj/llvm-readobj.h
@@ -1,4 +1,4 @@
-//===- llvm-readobj.h - Dump contents of an Object File -------------------===//
+//===-- llvm-readobj.h ----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -10,13 +10,36 @@
#ifndef LLVM_TOOLS_READ_OBJ_H
#define LLVM_TOOLS_READ_OBJ_H
-#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/CommandLine.h"
+#include <string>
namespace llvm {
-namespace object { class ObjectFile; }
-class raw_ostream;
+ namespace object {
+ class RelocationRef;
+ }
-ErrorOr<void> dumpELFDynamicTable(object::ObjectFile *O, raw_ostream &OS);
-} // end namespace llvm
+ class error_code;
+
+ // Various helper functions.
+ bool error(error_code ec);
+ bool relocAddressLess(object::RelocationRef A,
+ object::RelocationRef B);
+} // namespace llvm
+
+namespace opts {
+ extern llvm::cl::list<std::string> InputFilenames;
+ extern llvm::cl::opt<bool> FileHeaders;
+ extern llvm::cl::opt<bool> Sections;
+ extern llvm::cl::opt<bool> SectionRelocations;
+ extern llvm::cl::opt<bool> SectionSymbols;
+ extern llvm::cl::opt<bool> SectionData;
+ extern llvm::cl::opt<bool> Relocations;
+ extern llvm::cl::opt<bool> Symbols;
+ extern llvm::cl::opt<bool> DynamicSymbols;
+ extern llvm::cl::opt<bool> UnwindInfo;
+} // namespace opts
+
+#define LLVM_READOBJ_ENUM_ENT(ns, enum) \
+ { #enum, ns::enum }
#endif