Implements low-level object file format specific output for COFF and
authorEric Christopher <echristo@gmail.com>
Wed, 3 Apr 2013 18:31:38 +0000 (18:31 +0000)
committerEric Christopher <echristo@gmail.com>
Wed, 3 Apr 2013 18:31:38 +0000 (18:31 +0000)
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

34 files changed:
include/llvm/Object/ELF.h
include/llvm/Support/COFF.h
include/llvm/Support/Win64EH.h
test/MC/ELF/many-sections-2.s
test/Object/readobj-elf-versioning.test
test/Object/readobj-shared-object.test
test/tools/llvm-readobj/Inputs/trivial.ll [new file with mode: 0644]
test/tools/llvm-readobj/Inputs/trivial.obj.coff-i386 [new file with mode: 0644]
test/tools/llvm-readobj/Inputs/trivial.obj.coff-x86-64 [new file with mode: 0644]
test/tools/llvm-readobj/Inputs/trivial.obj.elf-i386 [new file with mode: 0644]
test/tools/llvm-readobj/Inputs/trivial.obj.elf-x86-64 [new file with mode: 0644]
test/tools/llvm-readobj/Inputs/trivial.obj.macho-i386 [new file with mode: 0644]
test/tools/llvm-readobj/Inputs/trivial.obj.macho-x86-64 [new file with mode: 0644]
test/tools/llvm-readobj/file-headers.test [new file with mode: 0644]
test/tools/llvm-readobj/lit.local.cfg [new file with mode: 0644]
test/tools/llvm-readobj/relocations.test [new file with mode: 0644]
test/tools/llvm-readobj/sections-ext.test [new file with mode: 0644]
test/tools/llvm-readobj/sections.test [new file with mode: 0644]
test/tools/llvm-readobj/symbols.test [new file with mode: 0644]
tools/llvm-readobj/CMakeLists.txt
tools/llvm-readobj/COFFDumper.cpp [new file with mode: 0644]
tools/llvm-readobj/ELF.cpp [deleted file]
tools/llvm-readobj/ELFDumper.cpp [new file with mode: 0644]
tools/llvm-readobj/Error.cpp [new file with mode: 0644]
tools/llvm-readobj/Error.h [new file with mode: 0644]
tools/llvm-readobj/LLVMBuild.txt
tools/llvm-readobj/MachODumper.cpp [new file with mode: 0644]
tools/llvm-readobj/Makefile
tools/llvm-readobj/ObjDumper.cpp [new file with mode: 0644]
tools/llvm-readobj/ObjDumper.h [new file with mode: 0644]
tools/llvm-readobj/StreamWriter.cpp [new file with mode: 0644]
tools/llvm-readobj/StreamWriter.h [new file with mode: 0644]
tools/llvm-readobj/llvm-readobj.cpp
tools/llvm-readobj/llvm-readobj.h

index 719bc08915d9b3f883aba909d44068af4c5bcc67..ac6f386032e45b5fa2cb77d265f463f63bd45840 100644 (file)
@@ -790,6 +790,7 @@ public:
   uint64_t getNumSections() const;
   uint64_t getStringTableIndex() const;
   ELF::Elf64_Word getSymbolTableIndex(const Elf_Sym *symb) const;
+  const Elf_Ehdr *getElfHeader() const;
   const Elf_Shdr *getSection(const Elf_Sym *symb) const;
   const Elf_Shdr *getElfSection(section_iterator &It) const;
   const Elf_Sym *getElfSymbol(symbol_iterator &It) const;
@@ -968,6 +969,12 @@ ELFObjectFile<ELFT>::getSection(const Elf_Sym *symb) const {
   return getSection(symb->st_shndx);
 }
 
+template<class ELFT>
+const typename ELFObjectFile<ELFT>::Elf_Ehdr *
+ELFObjectFile<ELFT>::getElfHeader() const {
+  return Header;
+}
+
 template<class ELFT>
 const typename ELFObjectFile<ELFT>::Elf_Shdr *
 ELFObjectFile<ELFT>::getElfSection(section_iterator &It) const {
index 02c44cdfad26b37631cfa22ef080ca4b16790b1d..823b43ad938adea3f47177af086d70846260254c 100644 (file)
@@ -321,7 +321,8 @@ namespace COFF {
     IMAGE_COMDAT_SELECT_SAME_SIZE,
     IMAGE_COMDAT_SELECT_EXACT_MATCH,
     IMAGE_COMDAT_SELECT_ASSOCIATIVE,
-    IMAGE_COMDAT_SELECT_LARGEST
+    IMAGE_COMDAT_SELECT_LARGEST,
+    IMAGE_COMDAT_SELECT_NEWEST
   };
 
   // Auxiliary Symbol Formats
index 164aca16bf3a435b57147c36f8fe7b7b5ac0a334..ecce713680412d4b9c577a6f969f5159233ded32 100644 (file)
@@ -106,12 +106,17 @@ struct UnwindInfo {
     return reinterpret_cast<void *>(&UnwindCodes[(NumCodes+1) & ~1]);
   }
 
-  /// \brief Return image-relativ offset of language-specific exception handler.
-  uint32_t getLanguageSpecificHandlerOffset() {
-    return *reinterpret_cast<uint32_t *>(getLanguageSpecificData());
+  /// \brief Return pointer to language specific data part of UnwindInfo.
+  const void *getLanguageSpecificData() const {
+    return reinterpret_cast<const void *>(&UnwindCodes[(NumCodes+1) & ~1]);
+  }
+
+  /// \brief Return image-relative offset of language-specific exception handler.
+  uint32_t getLanguageSpecificHandlerOffset() const {
+    return *reinterpret_cast<const uint32_t *>(getLanguageSpecificData());
   }
 
-  /// \brief Set image-relativ offset of language-specific exception handler.
+  /// \brief Set image-relative offset of language-specific exception handler.
   void setLanguageSpecificHandlerOffset(uint32_t offset) {
     *reinterpret_cast<uint32_t *>(getLanguageSpecificData()) = offset;
   }
@@ -126,6 +131,11 @@ struct UnwindInfo {
   RuntimeFunction *getChainedFunctionEntry() {
     return reinterpret_cast<RuntimeFunction *>(getLanguageSpecificData());
   }
+
+  /// \brief Return pointer to chained unwind info.
+  const RuntimeFunction *getChainedFunctionEntry() const {
+    return reinterpret_cast<const RuntimeFunction *>(getLanguageSpecificData());
+  }
 };
 
 
index f5a1a0e437628adc78fd6d294a775c8b5d19253d..789ebf378d8ee6f7cbbf179e439d32e8d61fa0f4 100644 (file)
@@ -1,5 +1,5 @@
 // RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t
-// RUN: llvm-readobj %t | FileCheck %s
+// RUN: llvm-readobj -s %t | FileCheck %s
 
 // CHECK: symtab_shndx
 
index be1a39d9c48cf0d41f3485cf4e376fe5bb224e66..1f09ef32a11aecc7f3005899332afe2d5160a494 100644 (file)
@@ -1,15 +1,46 @@
-RUN: llvm-readobj %p/Inputs/elf-versioning-test.i386 \
+RUN: llvm-readobj -dt %p/Inputs/elf-versioning-test.i386 \
 RUN:         | FileCheck %s -check-prefix ELF
-RUN: llvm-readobj %p/Inputs/elf-versioning-test.i386 \
+RUN: llvm-readobj -dt %p/Inputs/elf-versioning-test.i386 \
 RUN:         | FileCheck %s -check-prefix ELF32
-RUN: llvm-readobj %p/Inputs/elf-versioning-test.x86_64 \
+RUN: llvm-readobj -dt %p/Inputs/elf-versioning-test.x86_64 \
 RUN:         | FileCheck %s -check-prefix ELF
-RUN: llvm-readobj %p/Inputs/elf-versioning-test.x86_64 \
+RUN: llvm-readobj -dt %p/Inputs/elf-versioning-test.x86_64 \
 RUN:         | FileCheck %s -check-prefix ELF64
 
-ELF: foo@@VER2          FUNC  .text {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} global
-ELF: foo@VER1           FUNC  .text {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} global
-ELF: unversioned_define FUNC  .text {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} global
+ELF: DynamicSymbols [
+ELF:   Symbol {
+ELF:     Name: foo@@VER2
+ELF:     Binding: Global
+ELF:     Type: Function
+ELF:     Section: .text
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: foo@VER1
+ELF:     Binding: Global
+ELF:     Type: Function
+ELF:     Section: .text
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: unversioned_define
+ELF:     Binding: Global
+ELF:     Type: Function
+ELF:     Section: .text
+ELF:   }
+ELF: ]
 
-ELF32: puts@GLIBC_2.0   FUNC {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} undef,global
-ELF64: puts@GLIBC_2.2.5 FUNC {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} undef,global
+ELF32: DynamicSymbols [
+ELF32:   Symbol {
+ELF32:     Name: puts@GLIBC_2.0
+ELF32:     Binding: Global
+ELF32:     Type: Function
+ELF32:     Section:  (0x0)
+ELF32:   }
+ELF32: ]
+ELF64: DynamicSymbols [
+ELF64:   Symbol {
+ELF64:     Name: puts@GLIBC_2.2.5
+ELF64:     Binding: Global
+ELF64:     Type: Function
+ELF64:     Section:  (0x0)
+ELF64:   }
+ELF64: ]
index 548bd3801e0b802dfb3f954dcaf21f6224412d9f..72dbd32ea9d5fe1872142f4305f99b494350b044 100644 (file)
-RUN: llvm-readobj %p/Inputs/shared-object-test.elf-i386 \
+RUN: llvm-readobj -s -t -dt -dynamic-table -needed-libs \
+RUN:              %p/Inputs/shared-object-test.elf-i386 \
 RUN:         | FileCheck %s -check-prefix ELF
-RUN: llvm-readobj %p/Inputs/shared-object-test.elf-i386 \
+RUN: llvm-readobj -s -t -dt -dynamic-table -needed-libs \
+RUN:              %p/Inputs/shared-object-test.elf-i386 \
 RUN:         | FileCheck %s -check-prefix ELF32
 
-RUN: llvm-readobj %p/Inputs/shared-object-test.elf-x86-64 \
+RUN: llvm-readobj -s -t -dt -dynamic-table -needed-libs \
+RUN:            %p/Inputs/shared-object-test.elf-x86-64 \
 RUN:         | FileCheck %s -check-prefix ELF
-RUN: llvm-readobj %p/Inputs/shared-object-test.elf-x86-64 \
+RUN: llvm-readobj -s -t -dt -dynamic-table -needed-libs \
+RUN:            %p/Inputs/shared-object-test.elf-x86-64 \
 RUN:         | FileCheck %s -check-prefix ELF64
 
-ELF64:File Format : ELF64-x86-64
-ELF64:Arch        : x86_64
-ELF64:Address Size: 64 bits
-ELF64:Load Name   : libfoo.so
+ELF64: Format:      ELF64-x86-64
+ELF64: Arch:        x86_64
+ELF64: AddressSize: 64bit
+ELF64: LoadName:    libfoo.so
 
-ELF32:File Format : ELF32-i386
-ELF32:Arch        : i386
-ELF32:Address Size: 32 bits
-ELF32:Load Name   : libfoo.so
+ELF32: Format:      ELF32-i386
+ELF32: Arch:        i386
+ELF32: AddressSize: 32bit
+ELF32: LoadName:    libfoo.so
 
-ELF:Symbols:
-ELF:  Name                   Type    Section          Address        Size           FileOffset     Flags
-ELF:  .dynsym                DBG     .dynsym          {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  formatspecific
-ELF:  .dynstr                DBG     .dynstr          {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  formatspecific
-ELF:  .text                  DBG     .text            {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  formatspecific
-ELF:  .eh_frame              DBG     .eh_frame        {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  formatspecific
-ELF:  .tdata                 DBG     .tdata           {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  formatspecific
-ELF:  .dynamic               DBG     .dynamic         {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  formatspecific
-ELF:  .got.plt               DBG     .got.plt         {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  formatspecific
-ELF:  .data                  DBG     .data            {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  formatspecific
-ELF:  .bss                   DBG     .bss             {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  formatspecific
-ELF:  shared.ll              FILE                     {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  absolute,formatspecific
-ELF:  local_func             FUNC    .text            {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}
-ELF:  _GLOBAL_OFFSET_TABLE_  DATA                     {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  absolute
-ELF:  _DYNAMIC               DATA                     {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  absolute
-ELF:  common_sym             DATA    .bss             {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  global
-ELF:  tls_sym                DATA    .tdata           {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  global,threadlocal
-ELF:  defined_sym            DATA    .data            {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  global
-ELF:  __bss_start            ?                        {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  global,absolute
-ELF:  _end                   ?                        {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  global,absolute
-ELF:  global_func            FUNC    .text            {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  global
-ELF:  _edata                 ?                        {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  global,absolute
-ELF:  Total: 21
+ELF: Sections [
+ELF:   Section {
+ELF:     Name:  (0)
+ELF:     Type: SHT_NULL
+ELF:     Flags [ (0x0)
+ELF:     ]
+ELF:   }
+ELF:   Section {
+ELF:     Name: .hash
+ELF:     Type: SHT_HASH
+ELF:     Flags [ (0x2)
+ELF:       SHF_ALLOC
+ELF:     ]
+ELF:   }
+ELF:   Section {
+ELF:     Name: .dynsym
+ELF:     Type: SHT_DYNSYM
+ELF:     Flags [ (0x2)
+ELF:       SHF_ALLOC
+ELF:     ]
+ELF:   }
+ELF:   Section {
+ELF:     Name: .dynstr
+ELF:     Type: SHT_STRTAB
+ELF:     Flags [ (0x2)
+ELF:       SHF_ALLOC
+ELF:     ]
+ELF:   }
+ELF:   Section {
+ELF:     Name: .text
+ELF:     Type: SHT_PROGBITS
+ELF:     Flags [ (0x6)
+ELF:       SHF_ALLOC
+ELF:       SHF_EXECINSTR
+ELF:     ]
+ELF:   }
+ELF:   Section {
+ELF:     Name: .eh_frame
+ELF:     Type: SHT_PROGBITS
+ELF:     Flags [ (0x2)
+ELF:       SHF_ALLOC
+ELF:     ]
+ELF:   }
+ELF:   Section {
+ELF:     Name: .tdata
+ELF:     Type: SHT_PROGBITS
+ELF:     Flags [ (0x403)
+ELF:       SHF_ALLOC
+ELF:       SHF_TLS
+ELF:       SHF_WRITE
+ELF:     ]
+ELF:   }
+ELF:   Section {
+ELF:     Name: .dynamic
+ELF:     Type: SHT_DYNAMIC
+ELF:     Flags [ (0x3)
+ELF:       SHF_ALLOC
+ELF:       SHF_WRITE
+ELF:     ]
+ELF:   }
+ELF:   Section {
+ELF:     Name: .got.plt
+ELF:     Type: SHT_PROGBITS
+ELF:     Flags [ (0x3)
+ELF:       SHF_ALLOC
+ELF:       SHF_WRITE
+ELF:     ]
+ELF:   }
+ELF:   Section {
+ELF:     Name: .data
+ELF:     Type: SHT_PROGBITS
+ELF:     Flags [ (0x3)
+ELF:       SHF_ALLOC
+ELF:       SHF_WRITE
+ELF:     ]
+ELF:   }
+ELF:   Section {
+ELF:     Name: .bss
+ELF:     Type: SHT_NOBITS
+ELF:     Flags [ (0x3)
+ELF:       SHF_ALLOC
+ELF:       SHF_WRITE
+ELF:     ]
+ELF:   }
+ELF:   Section {
+ELF:     Name: .shstrtab
+ELF:     Type: SHT_STRTAB
+ELF:     Flags [ (0x0)
+ELF:     ]
+ELF:   }
+ELF:   Section {
+ELF:     Name: .symtab
+ELF:     Type: SHT_SYMTAB
+ELF:     Flags [ (0x0)
+ELF:     ]
+ELF:   }
+ELF:   Section {
+ELF:     Name: .strtab
+ELF:     Type: SHT_STRTAB
+ELF:     Flags [ (0x0)
+ELF:     ]
+ELF:   }
+ELF: ]
 
-ELF:Dynamic Symbols:
-ELF:  Name                   Type   Section  Address        Size           FileOffset     Flags
-ELF:  common_sym             DATA   .bss     {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  global
-ELF:  tls_sym                DATA   .tdata   {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  global,threadlocal
-ELF:  defined_sym            DATA   .data    {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  global
-ELF:  __bss_start            ?               {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  global,absolute
-ELF:  _end                   ?               {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  global,absolute
-ELF:  global_func            FUNC   .text    {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  global
-ELF:  _edata                 ?               {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  global,absolute
-ELF:  Total: {{[0-9a-f]+}}
+ELF: Symbols [
+ELF:   Symbol {
+ELF:     Name: .hash
+ELF:     Binding: Local
+ELF:     Type: Section
+ELF:     Section: .hash
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: .dynsym
+ELF:     Binding: Local
+ELF:     Type: Section
+ELF:     Section: .dynsym
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: .dynstr
+ELF:     Binding: Local
+ELF:     Type: Section
+ELF:     Section: .dynstr
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: .text
+ELF:     Binding: Local
+ELF:     Type: Section
+ELF:     Section: .text
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: .eh_frame
+ELF:     Binding: Local
+ELF:     Type: Section
+ELF:     Section: .eh_frame
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: .tdata
+ELF:     Binding: Local
+ELF:     Type: Section
+ELF:     Section: .tdata
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: .dynamic
+ELF:     Binding: Local
+ELF:     Type: Section
+ELF:     Section: .dynamic
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: .got.plt
+ELF:     Binding: Local
+ELF:     Type: Section
+ELF:     Section: .got.plt
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: .data
+ELF:     Binding: Local
+ELF:     Type: Section
+ELF:     Section: .data
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: .bss
+ELF:     Binding: Local
+ELF:     Type: Section
+ELF:     Section: .bss
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: shared.ll
+ELF:     Binding: Local
+ELF:     Type: File
+ELF:     Section: (0xFFF1)
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: local_func
+ELF:     Binding: Local
+ELF:     Type: Function
+ELF:     Section: .text
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: _GLOBAL_OFFSET_TABLE_
+ELF:     Binding: Local
+ELF:     Type: Object
+ELF:     Section: (0xFFF1)
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: _DYNAMIC
+ELF:     Binding: Local
+ELF:     Type: Object
+ELF:     Section: (0xFFF1)
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: common_sym
+ELF:     Binding: Global
+ELF:     Type: Object
+ELF:     Section: .bss
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: tls_sym
+ELF:     Binding: Global
+ELF:     Type: TLS
+ELF:     Section: .tdata
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: defined_sym
+ELF:     Binding: Global
+ELF:     Type: Object
+ELF:     Section: .data
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: __bss_start
+ELF:     Binding: Global
+ELF:     Type: None
+ELF:     Section: (0xFFF1)
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: _end
+ELF:     Binding: Global
+ELF:     Type: None
+ELF:     Section: (0xFFF1)
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: global_func
+ELF:     Binding: Global
+ELF:     Type: Function
+ELF:     Section: .text
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: _edata
+ELF:     Binding: Global
+ELF:     Type: None
+ELF:     Section: (0xFFF1)
+ELF:   }
+ELF: ]
 
-ELF:Sections:
-ELF:  Name                        Address        Size           Align          Flags
-ELF:                              {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  rodata
-ELF:  .hash                       {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  required,rodata
-ELF:  .dynsym                     {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  required,rodata
-ELF:  .dynstr                     {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  required,rodata
-ELF:  .text                       {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  text,{{(data,)?}}required
-ELF:  .eh_frame                   {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  data,required,rodata
-ELF:  .tdata                      {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  data,required
-ELF:  .dynamic                    {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  required
-ELF:  .got.plt                    {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  data,required
-ELF:  .data                       {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  data,required
-ELF:  .bss                        {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  bss,required,virtual,zeroinit
-ELF:  .shstrtab                   {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  rodata
-ELF:  .symtab                     {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  rodata
-ELF:  .strtab                     {{[0-9a-f]+}}  {{[0-9a-f]+}}  {{[0-9a-f]+}}  rodata
-ELF:  Total: 14
-
-ELF:Dynamic section contains 9 entries
-ELF:  Tag        Type                 Name/Value
-ELF: 00000001 (NEEDED)             Shared library: [libc.so.6]
-ELF: 00000001 (NEEDED)             Shared library: [libm.so.6]
-ELF: 0000000e (SONAME)             Library soname: [libfoo.so]
-ELF: 00000004 (HASH)               {{[0-9a-f]+}}
-ELF: 00000005 (STRTAB)             {{[0-9a-f]+}}
-ELF: 00000006 (SYMTAB)             {{[0-9a-f]+}}
-ELF: 0000000a (STRSZ)              {{[0-9]+}} (bytes)
-ELF: 0000000b (SYMENT)             {{[0-9]+}} (bytes)
-ELF: 00000000 (NULL)               0x0
-ELF:  Total: 9
-
-ELF:Libraries needed:
-ELF:  libc.so.6
-ELF:  libm.so.6
-ELF:  Total: 2
+ELF: DynamicSymbols [
+ELF:   Symbol {
+ELF:     Name: common_sym
+ELF:     Binding: Global
+ELF:     Type: Object
+ELF:     Section: .bss
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: tls_sym
+ELF:     Binding: Global
+ELF:     Type: TLS
+ELF:     Section: .tdata
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: defined_sym
+ELF:     Binding: Global
+ELF:     Type: Object
+ELF:     Section: .data
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: __bss_start
+ELF:     Binding: Global
+ELF:     Type: None
+ELF:     Section: (0xFFF1)
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: _end
+ELF:     Binding: Global
+ELF:     Type: None
+ELF:     Section: (0xFFF1)
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: global_func
+ELF:     Binding: Global
+ELF:     Type: Function
+ELF:     Section: .text
+ELF:   }
+ELF:   Symbol {
+ELF:     Name: _edata
+ELF:     Binding: Global
+ELF:     Type: None
+ELF:     Section: (0xFFF1)
+ELF:   }
+ELF: ]
 
+ELF: DynamicSection [ (9 entries)
+ELF:   Tag        Type                 Name/Value
+ELF:   00000001 NEEDED               SharedLibrary (libc.so.6)
+ELF:   00000001 NEEDED               SharedLibrary (libm.so.6)
+ELF:   0000000E SONAME               LibrarySoname (libfoo.so)
+ELF:   00000004 HASH                 {{[0-9a-f]+}}
+ELF:   00000005 STRTAB               {{[0-9a-f]+}}
+ELF:   00000006 SYMTAB               {{[0-9a-f]+}}
+ELF:   0000000A STRSZ                {{[0-9]+}} (bytes)
+ELF:   0000000B SYMENT               {{[0-9]+}} (bytes)
+ELF:   00000000 NULL                 0x0
+ELF: ]
 
+ELF:      NeededLibraries [
+ELF-NEXT:  libc.so.6
+ELF-NEXT:  libm.so.6
+ELF-NEXT: ]
diff --git a/test/tools/llvm-readobj/Inputs/trivial.ll b/test/tools/llvm-readobj/Inputs/trivial.ll
new file mode 100644 (file)
index 0000000..2cd7ec8
--- /dev/null
@@ -0,0 +1,19 @@
+; llc -mtriple=i386-pc-win32 trivial.ll -filetype=obj -o trivial-object-test.coff-i386
+; llc -mtriple=x86_64-pc-win32 trivial.ll -filetype=obj -o trivial-object-test.coff-x86-64
+; llc -mtriple=i386-linux-gnu trivial.ll -filetype=obj -o trivial-object-test.elf-i386 -relocation-model=pic
+; llc -mtriple=x86_64-linux-gnu trivial.ll -filetype=obj -o trivial-object-test.elf-x86-64 -relocation-model=pic
+; llc -mtriple=i386-apple-darwin10 trivial.ll -filetype=obj -o trivial-object-test.macho-i386 -relocation-model=pic
+; llc -mtriple=x86_64-apple-darwin10 trivial.ll -filetype=obj -o trivial-object-test.macho-x86-64 -relocation-model=pic
+
+@.str = private unnamed_addr constant [13 x i8] c"Hello World\0A\00", align 1
+
+define i32 @main() nounwind {
+entry:
+  %call = tail call i32 @puts(i8* getelementptr inbounds ([13 x i8]* @.str, i32 0, i32 0)) nounwind
+  tail call void bitcast (void (...)* @SomeOtherFunction to void ()*)() nounwind
+  ret i32 0
+}
+
+declare i32 @puts(i8* nocapture) nounwind
+
+declare void @SomeOtherFunction(...)
diff --git a/test/tools/llvm-readobj/Inputs/trivial.obj.coff-i386 b/test/tools/llvm-readobj/Inputs/trivial.obj.coff-i386
new file mode 100644 (file)
index 0000000..282e569
Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/trivial.obj.coff-i386 differ
diff --git a/test/tools/llvm-readobj/Inputs/trivial.obj.coff-x86-64 b/test/tools/llvm-readobj/Inputs/trivial.obj.coff-x86-64
new file mode 100644 (file)
index 0000000..8a7060e
Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/trivial.obj.coff-x86-64 differ
diff --git a/test/tools/llvm-readobj/Inputs/trivial.obj.elf-i386 b/test/tools/llvm-readobj/Inputs/trivial.obj.elf-i386
new file mode 100644 (file)
index 0000000..f85e40d
Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/trivial.obj.elf-i386 differ
diff --git a/test/tools/llvm-readobj/Inputs/trivial.obj.elf-x86-64 b/test/tools/llvm-readobj/Inputs/trivial.obj.elf-x86-64
new file mode 100644 (file)
index 0000000..95285c1
Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/trivial.obj.elf-x86-64 differ
diff --git a/test/tools/llvm-readobj/Inputs/trivial.obj.macho-i386 b/test/tools/llvm-readobj/Inputs/trivial.obj.macho-i386
new file mode 100644 (file)
index 0000000..5048171
Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/trivial.obj.macho-i386 differ
diff --git a/test/tools/llvm-readobj/Inputs/trivial.obj.macho-x86-64 b/test/tools/llvm-readobj/Inputs/trivial.obj.macho-x86-64
new file mode 100644 (file)
index 0000000..bcdfc8a
Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/trivial.obj.macho-x86-64 differ
diff --git a/test/tools/llvm-readobj/file-headers.test b/test/tools/llvm-readobj/file-headers.test
new file mode 100644 (file)
index 0000000..226eb93
--- /dev/null
@@ -0,0 +1,100 @@
+RUN: llvm-readobj -h %p/Inputs/trivial.obj.coff-i386 \
+RUN:   | FileCheck %s -check-prefix COFF32
+RUN: llvm-readobj -h %p/Inputs/trivial.obj.coff-x86-64 \
+RUN:   | FileCheck %s -check-prefix COFF64
+RUN: llvm-readobj -h %p/Inputs/trivial.obj.elf-i386 \
+RUN:   | FileCheck %s -check-prefix ELF32
+RUN: llvm-readobj -h %p/Inputs/trivial.obj.elf-x86-64 \
+RUN:   | FileCheck %s -check-prefix ELF64
+
+COFF32:      File: {{(.*[/\\])?}}trivial.obj.coff-i386
+COFF32-NEXT: Format: COFF-i386
+COFF32-NEXT: Arch: i386
+COFF32-NEXT: AddressSize: 32bit
+COFF32-NEXT: ImageFileHeader {
+COFF32-NEXT:   Machine: IMAGE_FILE_MACHINE_I386 (0x14C)
+COFF32-NEXT:   SectionCount: 2
+COFF32-NEXT:   TimeDateStamp: 2013-03-20 17:56:46 (0x5149F85E)
+COFF32-NEXT:   PointerToSymbolTable: 0xA5
+COFF32-NEXT:   SymbolCount: 7
+COFF32-NEXT:   OptionalHeaderSize: 0
+COFF32-NEXT:   Characteristics [ (0x0)
+COFF32-NEXT:   ]
+COFF32-NEXT: }
+
+COFF64:      File: {{(.*[/\\])?}}trivial.obj.coff-x86-64
+COFF64-NEXT: Format: COFF-x86-64
+COFF64-NEXT: Arch: x86_64
+COFF64-NEXT: AddressSize: 64bit
+COFF64-NEXT: ImageFileHeader {
+COFF64-NEXT:   Machine: IMAGE_FILE_MACHINE_AMD64 (0x8664)
+COFF64-NEXT:   SectionCount: 2
+COFF64-NEXT:   TimeDateStamp: 2013-03-20 17:56:46 (0x5149F85E)
+COFF64-NEXT:   PointerToSymbolTable: 0xAB
+COFF64-NEXT:   SymbolCount: 7
+COFF64-NEXT:   OptionalHeaderSize: 0
+COFF64-NEXT:   Characteristics [ (0x0)
+COFF64-NEXT:   ]
+COFF64-NEXT: }
+
+ELF32:      File: {{(.*[/\\])?}}trivial.obj.elf-i386
+ELF32-NEXT: Format: ELF32-i386
+ELF32-NEXT: Arch: i386
+ELF32-NEXT: AddressSize: 32bit
+ELF32-NEXT: LoadName:
+ELF32-NEXT: ElfHeader {
+ELF32-NEXT:   Ident {
+ELF32-NEXT:     Magic: (7F 45 4C 46)
+ELF32-NEXT:     Class: 32-bit (0x1)
+ELF32-NEXT:     DataEncoding: LittleEndian (0x1)
+ELF32-NEXT:     FileVersion: 1
+ELF32-NEXT:     OS/ABI: GNU/Linux (0x3)
+ELF32-NEXT:     ABIVersion: 0
+ELF32-NEXT:     Unused: (00 00 00 00 00 00 00)
+ELF32-NEXT:   }
+ELF32-NEXT:   Type: Relocatable (0x1)
+ELF32-NEXT:   Machine: EM_386 (0x3)
+ELF32-NEXT:   Version: 1
+ELF32-NEXT:   Entry: 0x0
+ELF32-NEXT:   ProgramHeaderOffset: 0x0
+ELF32-NEXT:   SectionHeaderOffset: 0xC8
+ELF32-NEXT:   Flags [ (0x0)
+ELF32-NEXT:   ]
+ELF32-NEXT:   HeaderSize: 52
+ELF32-NEXT:   ProgramHeaderEntrySize: 0
+ELF32-NEXT:   ProgramHeaderCount: 0
+ELF32-NEXT:   SectionHeaderEntrySize: 40
+ELF32-NEXT:   SectionHeaderCount: 10
+ELF32-NEXT:   StringTableSectionIndex: 7
+ELF32-NEXT: }
+
+ELF64:      File: {{(.*[/\\])?}}trivial.obj.elf-x86-64
+ELF64-NEXT: Format: ELF64-x86-64
+ELF64-NEXT: Arch: x86_64
+ELF64-NEXT: AddressSize: 64bit
+ELF64-NEXT: LoadName:
+ELF64-NEXT: ElfHeader {
+ELF64-NEXT:   Ident {
+ELF64-NEXT:     Magic: (7F 45 4C 46)
+ELF64-NEXT:     Class: 64-bit (0x2)
+ELF64-NEXT:     DataEncoding: LittleEndian (0x1)
+ELF64-NEXT:     FileVersion: 1
+ELF64-NEXT:     OS/ABI: GNU/Linux (0x3)
+ELF64-NEXT:     ABIVersion: 0
+ELF64-NEXT:     Unused: (00 00 00 00 00 00 00)
+ELF64-NEXT:   }
+ELF64-NEXT:   Type: Relocatable (0x1)
+ELF64-NEXT:   Machine: EM_X86_64 (0x3E)
+ELF64-NEXT:   Version: 1
+ELF64-NEXT:   Entry: 0x0
+ELF64-NEXT:   ProgramHeaderOffset: 0x0
+ELF64-NEXT:   SectionHeaderOffset: 0xB8
+ELF64-NEXT:   Flags [ (0x0)
+ELF64-NEXT:   ]
+ELF64-NEXT:   HeaderSize: 64
+ELF64-NEXT:   ProgramHeaderEntrySize: 0
+ELF64-NEXT:   ProgramHeaderCount: 0
+ELF64-NEXT:   SectionHeaderEntrySize: 64
+ELF64-NEXT:   SectionHeaderCount: 10
+ELF64-NEXT:   StringTableSectionIndex: 7
+ELF64-NEXT: }
diff --git a/test/tools/llvm-readobj/lit.local.cfg b/test/tools/llvm-readobj/lit.local.cfg
new file mode 100644 (file)
index 0000000..df9b335
--- /dev/null
@@ -0,0 +1 @@
+config.suffixes = ['.test']
diff --git a/test/tools/llvm-readobj/relocations.test b/test/tools/llvm-readobj/relocations.test
new file mode 100644 (file)
index 0000000..0608565
--- /dev/null
@@ -0,0 +1,32 @@
+RUN: llvm-readobj -r %p/Inputs/trivial.obj.coff-i386 \
+RUN:   | FileCheck %s -check-prefix COFF
+RUN: llvm-readobj -r %p/Inputs/trivial.obj.elf-i386 \
+RUN:   | FileCheck %s -check-prefix ELF
+RUN: llvm-readobj -r %p/Inputs/trivial.obj.macho-i386 \
+RUN:   | FileCheck %s -check-prefix MACHO
+
+COFF:      Relocations [
+COFF-NEXT:   Section (1) .text {
+COFF-NEXT:     0x4 IMAGE_REL_I386_DIR32 .data
+COFF-NEXT:     0x9 IMAGE_REL_I386_REL32 _puts
+COFF-NEXT:     0xE IMAGE_REL_I386_REL32 _SomeOtherFunction
+COFF-NEXT:   }
+COFF-NEXT: ]
+
+ELF:      Relocations [
+ELF-NEXT:   Section (1) .text {
+ELF-NEXT:     0xC R_386_GOTPC _GLOBAL_OFFSET_TABLE_ 0x0
+ELF-NEXT:     0x12 R_386_GOTOFF .L.str 0x0
+ELF-NEXT:     0x1A R_386_PLT32 puts 0x0
+ELF-NEXT:     0x1F R_386_PLT32 SomeOtherFunction 0x0
+ELF-NEXT:   }
+ELF-NEXT: ]
+
+MACHO:      Relocations [
+MACHO-NEXT:   Section __text {
+MACHO-NEXT:     0x18 GENERIC_RELOC_VANILLA _SomeOtherFunction 0x0
+MACHO-NEXT:     0x13 GENERIC_RELOC_VANILLA _puts 0x0
+MACHO-NEXT:     0xB GENERIC_RELOC_LOCAL_SECTDIFF _main 0x{{[0-9A-F]+}}
+MACHO-NEXT:     0x0 GENERIC_RELOC_PAIR _main 0x{{[0-9A-F]+}}
+MACHO-NEXT:   }
+MACHO-NEXT: ]
diff --git a/test/tools/llvm-readobj/sections-ext.test b/test/tools/llvm-readobj/sections-ext.test
new file mode 100644 (file)
index 0000000..a972c9a
--- /dev/null
@@ -0,0 +1,175 @@
+RUN: llvm-readobj -s -st -sr -sd %p/Inputs/trivial.obj.coff-i386 \
+RUN:   | FileCheck %s -check-prefix COFF
+RUN: llvm-readobj -s -st -sr -sd %p/Inputs/trivial.obj.elf-i386 \
+RUN:   | FileCheck %s -check-prefix ELF
+RUN: llvm-readobj -s -st -sr -sd %p/Inputs/trivial.obj.macho-i386 \
+RUN:   | FileCheck %s -check-prefix MACHO
+
+COFF:      Sections [
+COFF-NEXT:   Section {
+COFF-NEXT:     Number: 1
+COFF-NEXT:     Name: .text (2E 74 65 78 74 00 00 00)
+COFF-NEXT:     VirtualSize: 0x0
+COFF-NEXT:     VirtualAddress: 0x0
+COFF-NEXT:     RawDataSize: 22
+COFF-NEXT:     PointerToRawData: 0x64
+COFF-NEXT:     PointerToRelocations: 0x7A
+COFF-NEXT:     PointerToLineNumbers: 0x0
+COFF-NEXT:     RelocationCount: 3
+COFF-NEXT:     LineNumberCount: 0
+COFF-NEXT:     Characteristics [ (0x60500020)
+COFF-NEXT:       IMAGE_SCN_ALIGN_16BYTES (0x500000)
+COFF-NEXT:       IMAGE_SCN_CNT_CODE (0x20)
+COFF-NEXT:       IMAGE_SCN_MEM_EXECUTE (0x20000000)
+COFF-NEXT:       IMAGE_SCN_MEM_READ (0x40000000)
+COFF-NEXT:     ]
+COFF-NEXT:     Relocations [
+COFF-NEXT:       0x4 IMAGE_REL_I386_DIR32 .data
+COFF-NEXT:       0x9 IMAGE_REL_I386_REL32 _puts
+COFF-NEXT:       0xE IMAGE_REL_I386_REL32 _SomeOtherFunction
+COFF-NEXT:     ]
+COFF-NEXT:     Symbols [
+COFF-NEXT:       Symbol {
+COFF-NEXT:         Name: .text
+COFF-NEXT:         Value: 0
+COFF-NEXT:         Section: .text (1)
+COFF-NEXT:         BaseType: Null (0x0)
+COFF-NEXT:         ComplexType: Null (0x0)
+COFF-NEXT:         StorageClass: Static (0x3)
+COFF-NEXT:         AuxSymbolCount: 1
+COFF-NEXT:         AuxSectionDef {
+COFF-NEXT:           Length: 22
+COFF-NEXT:           RelocationCount: 3
+COFF-NEXT:           LineNumberCount: 0
+COFF-NEXT:           Checksum: 0x0
+COFF-NEXT:           Number: 1
+COFF-NEXT:           Selection: 0x0
+COFF-NEXT:           Unused: (00 00 00)
+COFF-NEXT:         }
+COFF-NEXT:       }
+COFF-NEXT:       Symbol {
+COFF-NEXT:         Name: _main
+COFF-NEXT:         Value: 0
+COFF-NEXT:         Section: .text (1)
+COFF-NEXT:         BaseType: Null (0x0)
+COFF-NEXT:         ComplexType: Function (0x2)
+COFF-NEXT:         StorageClass: External (0x2)
+COFF-NEXT:         AuxSymbolCount: 0
+COFF-NEXT:       }
+COFF-NEXT:     ]
+COFF-NEXT:     SectionData (
+COFF-NEXT:       0000: 50C70424 00000000 E8000000 00E80000  |P..$............|
+COFF-NEXT:       0010: 000031C0 5AC3                        |..1.Z.|
+COFF-NEXT:     )
+COFF-NEXT:   }
+
+ELF:      Sections [
+ELF-NEXT:   Section {
+ELF-NEXT:     Index: 0
+ELF-NEXT:     Name:  (0)
+ELF-NEXT:     Type: SHT_NULL (0x0)
+ELF-NEXT:     Flags [ (0x0)
+ELF-NEXT:     ]
+ELF-NEXT:     Address: 0x0
+ELF-NEXT:     Offset: 0x0
+ELF-NEXT:     Size: 0
+ELF-NEXT:     Link: 0
+ELF-NEXT:     Info: 0
+ELF-NEXT:     AddressAlignment: 0
+ELF-NEXT:     EntrySize: 0
+ELF-NEXT:     Relocations [
+ELF-NEXT:     ]
+ELF-NEXT:     Symbols [
+ELF-NEXT:     ]
+ELF-NEXT:     SectionData (
+ELF-NEXT:     )
+ELF-NEXT:   }
+ELF-NEXT:   Section {
+ELF-NEXT:     Index: 1
+ELF-NEXT:     Name: .text (5)
+ELF-NEXT:     Type: SHT_PROGBITS (0x1)
+ELF-NEXT:     Flags [ (0x6)
+ELF-NEXT:       SHF_ALLOC (0x2)
+ELF-NEXT:       SHF_EXECINSTR (0x4)
+ELF-NEXT:     ]
+ELF-NEXT:     Address: 0x0
+ELF-NEXT:     Offset: 0x40
+ELF-NEXT:     Size: 42
+ELF-NEXT:     Link: 0
+ELF-NEXT:     Info: 0
+ELF-NEXT:     AddressAlignment: 16
+ELF-NEXT:     EntrySize: 0
+ELF-NEXT:     Relocations [
+ELF-NEXT:       0xC R_386_GOTPC _GLOBAL_OFFSET_TABLE_ 0x0
+ELF-NEXT:       0x12 R_386_GOTOFF .L.str 0x0
+ELF-NEXT:       0x1A R_386_PLT32 puts 0x0
+ELF-NEXT:       0x1F R_386_PLT32 SomeOtherFunction 0x0
+ELF-NEXT:     ]
+ELF-NEXT:     Symbols [
+ELF-NEXT:       Symbol {
+ELF-NEXT:         Name: .text (0)
+ELF-NEXT:         Value: 0x0
+ELF-NEXT:         Size: 0
+ELF-NEXT:         Binding: Local (0x0)
+ELF-NEXT:         Type: Section (0x3)
+ELF-NEXT:         Other: 0
+ELF-NEXT:         Section: .text (0x1)
+ELF-NEXT:       }
+ELF-NEXT:       Symbol {
+ELF-NEXT:         Name: main (12)
+ELF-NEXT:         Value: 0x0
+ELF-NEXT:         Size: 42
+ELF-NEXT:         Binding: Global (0x1)
+ELF-NEXT:         Type: Function (0x2)
+ELF-NEXT:         Other: 0
+ELF-NEXT:         Section: .text (0x1)
+ELF-NEXT:       }
+ELF-NEXT:     ]
+ELF-NEXT:     SectionData (
+ELF-NEXT:       0000: 5383EC08 E8000000 005B81C3 03000000  |S........[......|
+ELF-NEXT:       0010: 8D830000 00008904 24E8FCFF FFFFE8FC  |........$.......|
+ELF-NEXT:       0020: FFFFFF31 C083C408 5BC3               |...1....[.|
+ELF-NEXT:     )
+ELF-NEXT:   }
+
+MACHO:      Sections [
+MACHO-NEXT:   Section {
+MACHO-NEXT:     Index: 0
+MACHO-NEXT:     Name: __text (5F 5F 74 65 78 74 00 00 00 00 00 00 00 00 00 00)
+MACHO-NEXT:     Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00)
+MACHO-NEXT:     Address: 0x0
+MACHO-NEXT:     Size: 0x22
+MACHO-NEXT:     Offset: 324
+MACHO-NEXT:     Alignment: 4
+MACHO-NEXT:     RelocationOffset: 0x174
+MACHO-NEXT:     RelocationCount: 4
+MACHO-NEXT:     Type: 0x0
+MACHO-NEXT:     Attributes [ (0x800004)
+MACHO-NEXT:       PureInstructions (0x800000)
+MACHO-NEXT:       SomeInstructions (0x4)
+MACHO-NEXT:     ]
+MACHO-NEXT:     Reserved1: 0x0
+MACHO-NEXT:     Reserved2: 0x0
+MACHO-NEXT:     Relocations [
+MACHO-NEXT:       0x18 GENERIC_RELOC_VANILLA _SomeOtherFunction 0x0
+MACHO-NEXT:       0x13 GENERIC_RELOC_VANILLA _puts 0x0
+MACHO-NEXT:       0xB GENERIC_RELOC_LOCAL_SECTDIFF _main 0x{{[0-9A-F]+}}
+MACHO-NEXT:       0x0 GENERIC_RELOC_PAIR _main 0x{{[0-9A-F]+}}
+MACHO-NEXT:     ]
+MACHO-NEXT:     Symbols [
+MACHO-NEXT:       Symbol {
+MACHO-NEXT:         Name: _main (1)
+MACHO-NEXT:         Type: 0xF
+MACHO-NEXT:         Section: __text (0x1)
+MACHO-NEXT:         RefType: UndefinedNonLazy (0x0)
+MACHO-NEXT:         Flags [ (0x0)
+MACHO-NEXT:         ]
+MACHO-NEXT:         Value: 0x0
+MACHO-NEXT:       }
+MACHO-NEXT:     ]
+MACHO-NEXT:     SectionData (
+MACHO-NEXT:       0000: 83EC0CE8 00000000 588D801A 00000089  |........X.......|
+MACHO-NEXT:       0010: 0424E8E9 FFFFFFE8 E4FFFFFF 31C083C4  |.$..........1...|
+MACHO-NEXT:       0020: 0CC3                                 |..|
+MACHO-NEXT:     )
+MACHO-NEXT:   }
diff --git a/test/tools/llvm-readobj/sections.test b/test/tools/llvm-readobj/sections.test
new file mode 100644 (file)
index 0000000..84154d7
--- /dev/null
@@ -0,0 +1,113 @@
+RUN: llvm-readobj -s %p/Inputs/trivial.obj.coff-i386 \
+RUN:   | FileCheck %s -check-prefix COFF
+RUN: llvm-readobj -s %p/Inputs/trivial.obj.elf-i386 \
+RUN:   | FileCheck %s -check-prefix ELF
+RUN: llvm-readobj -s %p/Inputs/trivial.obj.macho-i386 \
+RUN:   | FileCheck %s -check-prefix MACHO
+
+COFF:      Sections [
+COFF-NEXT:   Section {
+COFF-NEXT:     Number: 1
+COFF-NEXT:     Name: .text (2E 74 65 78 74 00 00 00)
+COFF-NEXT:     VirtualSize: 0x0
+COFF-NEXT:     VirtualAddress: 0x0
+COFF-NEXT:     RawDataSize: 22
+COFF-NEXT:     PointerToRawData: 0x64
+COFF-NEXT:     PointerToRelocations: 0x7A
+COFF-NEXT:     PointerToLineNumbers: 0x0
+COFF-NEXT:     RelocationCount: 3
+COFF-NEXT:     LineNumberCount: 0
+COFF-NEXT:     Characteristics [ (0x60500020)
+COFF-NEXT:       IMAGE_SCN_ALIGN_16BYTES (0x500000)
+COFF-NEXT:       IMAGE_SCN_CNT_CODE (0x20)
+COFF-NEXT:       IMAGE_SCN_MEM_EXECUTE (0x20000000)
+COFF-NEXT:       IMAGE_SCN_MEM_READ (0x40000000)
+COFF-NEXT:     ]
+COFF-NEXT:   }
+COFF-NEXT:   Section {
+COFF-NEXT:     Number: 2
+COFF-NEXT:     Name: .data (2E 64 61 74 61 00 00 00)
+COFF-NEXT:     VirtualSize: 0x0
+COFF-NEXT:     VirtualAddress: 0x0
+COFF-NEXT:     RawDataSize: 13
+COFF-NEXT:     PointerToRawData: 0x98
+COFF-NEXT:     PointerToRelocations: 0x0
+COFF-NEXT:     PointerToLineNumbers: 0x0
+COFF-NEXT:     RelocationCount: 0
+COFF-NEXT:     LineNumberCount: 0
+COFF-NEXT:     Characteristics [ (0xC0300040)
+COFF-NEXT:       IMAGE_SCN_ALIGN_4BYTES (0x300000)
+COFF-NEXT:       IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
+COFF-NEXT:       IMAGE_SCN_MEM_READ (0x40000000)
+COFF-NEXT:       IMAGE_SCN_MEM_WRITE (0x80000000)
+COFF-NEXT:     ]
+COFF-NEXT:   }
+COFF-NEXT: ]
+
+ELF:      Sections [
+ELF-NEXT:   Section {
+ELF-NEXT:     Index: 0
+ELF-NEXT:     Name:  (0)
+ELF-NEXT:     Type: SHT_NULL (0x0)
+ELF-NEXT:     Flags [ (0x0)
+ELF-NEXT:     ]
+ELF-NEXT:     Address: 0x0
+ELF-NEXT:     Offset: 0x0
+ELF-NEXT:     Size: 0
+ELF-NEXT:     Link: 0
+ELF-NEXT:     Info: 0
+ELF-NEXT:     AddressAlignment: 0
+ELF-NEXT:     EntrySize: 0
+ELF-NEXT:   }
+ELF-NEXT:   Section {
+ELF-NEXT:     Index: 1
+ELF-NEXT:     Name: .text (5)
+ELF-NEXT:     Type: SHT_PROGBITS (0x1)
+ELF-NEXT:     Flags [ (0x6)
+ELF-NEXT:       SHF_ALLOC (0x2)
+ELF-NEXT:       SHF_EXECINSTR (0x4)
+ELF-NEXT:     ]
+ELF-NEXT:     Address: 0x0
+ELF-NEXT:     Offset: 0x40
+ELF-NEXT:     Size: 42
+ELF-NEXT:     Link: 0
+ELF-NEXT:     Info: 0
+ELF-NEXT:     AddressAlignment: 16
+ELF-NEXT:     EntrySize: 0
+ELF-NEXT:   }
+
+MACHO:      Sections [
+MACHO-NEXT:   Section {
+MACHO-NEXT:     Index: 0
+MACHO-NEXT:     Name: __text (5F 5F 74 65 78 74 00 00 00 00 00 00 00 00 00 00)
+MACHO-NEXT:     Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00)
+MACHO-NEXT:     Address: 0x0
+MACHO-NEXT:     Size: 0x22
+MACHO-NEXT:     Offset: 324
+MACHO-NEXT:     Alignment: 4
+MACHO-NEXT:     RelocationOffset: 0x174
+MACHO-NEXT:     RelocationCount: 4
+MACHO-NEXT:     Type: 0x0
+MACHO-NEXT:     Attributes [ (0x800004)
+MACHO-NEXT:       PureInstructions (0x800000)
+MACHO-NEXT:       SomeInstructions (0x4)
+MACHO-NEXT:     ]
+MACHO-NEXT:     Reserved1: 0x0
+MACHO-NEXT:     Reserved2: 0x0
+MACHO-NEXT:   }
+MACHO-NEXT:   Section {
+MACHO-NEXT:     Index: 1
+MACHO-NEXT:     Name: __cstring (5F 5F 63 73 74 72 69 6E 67 00 00 00 00 00 00 00)
+MACHO-NEXT:     Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00)
+MACHO-NEXT:     Address: 0x22
+MACHO-NEXT:     Size: 0xD
+MACHO-NEXT:     Offset: 358
+MACHO-NEXT:     Alignment: 0
+MACHO-NEXT:     RelocationOffset: 0x0
+MACHO-NEXT:     RelocationCount: 0
+MACHO-NEXT:     Type: ExtReloc (0x2)
+MACHO-NEXT:     Attributes [ (0x0)
+MACHO-NEXT:     ]
+MACHO-NEXT:     Reserved1: 0x0
+MACHO-NEXT:     Reserved2: 0x0
+MACHO-NEXT:   }
diff --git a/test/tools/llvm-readobj/symbols.test b/test/tools/llvm-readobj/symbols.test
new file mode 100644 (file)
index 0000000..d33bd8e
--- /dev/null
@@ -0,0 +1,44 @@
+RUN: llvm-readobj -t %p/Inputs/trivial.obj.coff-i386 \
+RUN:   | FileCheck %s -check-prefix COFF
+RUN: llvm-readobj -t %p/Inputs/trivial.obj.elf-i386 \
+RUN:   | FileCheck %s -check-prefix ELF
+
+COFF:      Symbols [
+COFF-NEXT:   Symbol {
+COFF-NEXT:     Name: .text
+COFF-NEXT:     Value: 0
+COFF-NEXT:     Section: .text (1)
+COFF-NEXT:     BaseType: Null (0x0)
+COFF-NEXT:     ComplexType: Null (0x0)
+COFF-NEXT:     StorageClass: Static (0x3)
+COFF-NEXT:     AuxSymbolCount: 1
+COFF-NEXT:     AuxSectionDef {
+COFF-NEXT:       Length: 22
+COFF-NEXT:       RelocationCount: 3
+COFF-NEXT:       LineNumberCount: 0
+COFF-NEXT:       Checksum: 0x0
+COFF-NEXT:       Number: 1
+COFF-NEXT:       Selection: 0x0
+COFF-NEXT:       Unused: (00 00 00)
+COFF-NEXT:     }
+COFF-NEXT:   }
+
+ELF:      Symbols [
+ELF-NEXT:   Symbol {
+ELF-NEXT:     Name: trivial.ll (1)
+ELF-NEXT:     Value: 0x0
+ELF-NEXT:     Size: 0
+ELF-NEXT:     Binding: Local (0x0)
+ELF-NEXT:     Type: File (0x4)
+ELF-NEXT:     Other: 0
+ELF-NEXT:     Section:  (0xFFF1)
+ELF-NEXT:   }
+ELF-NEXT:   Symbol {
+ELF-NEXT:     Name: .L.str (39)
+ELF-NEXT:     Value: 0x0
+ELF-NEXT:     Size: 13
+ELF-NEXT:     Binding: Local (0x0)
+ELF-NEXT:     Type: Object (0x1)
+ELF-NEXT:     Other: 0
+ELF-NEXT:     Section: .rodata.str1.1 (0x5)
+ELF-NEXT:   }
index 676c23d7ae691df4255984a1dd4a451f47b3bcf2..3d20def8f51c181344ef9092e7ed591acf5dd4f2 100644 (file)
@@ -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 (file)
index 0000000..be4e76c
--- /dev/null
@@ -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 (file)
index 07f15b3..0000000
+++ /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 (file)
index 0000000..9e111dd
--- /dev/null
@@ -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 (file)
index 0000000..a6c6132
--- /dev/null
@@ -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 (file)
index 0000000..cf68da8
--- /dev/null
@@ -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
index c9f934f4b6fac55ff818ea0cebe1185892a17473..813c12b752bcd4e4e4495e0761c5f9e50dbcb7e8 100644 (file)
@@ -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 (file)
index 0000000..798c941
--- /dev/null
@@ -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";
+}
index a7a7de356303dd2709db82d0186c59dc1928b556..1bb72955f08f753922d3536a7ca6fcc4320f2702 100644 (file)
@@ -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 (file)
index 0000000..61f5117
--- /dev/null
@@ -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 (file)
index 0000000..8d191cb
--- /dev/null
@@ -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 (file)
index 0000000..8718112
--- /dev/null
@@ -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 (file)
index 0000000..129f6e7
--- /dev/null
@@ -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
index ea37d105dc6ea11c02ea00bb9b8fb078e225ef4d..67c9a98f40f3ae5c1ecb14047c8d8fce1dd80562 100644 (file)
 
 #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;
 }
-
index cf492b2a8da503ff76b927e7b0bba976fbfc296d..be18268a7f64b887210f844d7b24bcaec41eea9a 100644 (file)
@@ -1,4 +1,4 @@
-//===- llvm-readobj.h - Dump contents of an Object File -------------------===//
+//===-- llvm-readobj.h ----------------------------------------------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
 #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