From df46cef31b470299ae174aaa8cebea642e30d613 Mon Sep 17 00:00:00 2001 From: Eric Christopher Date: Wed, 3 Apr 2013 18:31:38 +0000 Subject: [PATCH] Implements low-level object file format specific output for COFF and ELF with support for: - File headers - Section headers + data - Relocations - Symbols - Unwind data (only COFF/Win64) The output format follows a few rules: - Values are almost always output one per line (as elf-dump/coff-dump already do). - Many values are translated to something readable (like enum names), with the raw value in parentheses. - Hex numbers are output in uppercase, prefixed with "0x". - Flags are sorted alphabetically. - Lists and groups are always delimited. Example output: ---------- snip ---------- Sections [ Section { Index: 1 Name: .text (5) Type: SHT_PROGBITS (0x1) Flags [ (0x6) SHF_ALLOC (0x2) SHF_EXECINSTR (0x4) ] Address: 0x0 Offset: 0x40 Size: 33 Link: 0 Info: 0 AddressAlignment: 16 EntrySize: 0 Relocations [ 0x6 R_386_32 .rodata.str1.1 0x0 0xB R_386_PC32 puts 0x0 0x12 R_386_32 .rodata.str1.1 0x0 0x17 R_386_PC32 puts 0x0 ] SectionData ( 0000: 83EC04C7 04240000 0000E8FC FFFFFFC7 |.....$..........| 0010: 04240600 0000E8FC FFFFFF31 C083C404 |.$.........1....| 0020: C3 |.| ) } ] ---------- snip ---------- Relocations and symbols can be output standalone or together with the section header as displayed in the example. This feature set supports all tests in test/MC/COFF and test/MC/ELF (and I suspect all additional tests using elf-dump), making elf-dump and coff-dump deprecated. Patch by Nico Rieck! llvm-svn: 178679 --- include/llvm/Object/ELF.h | 7 + include/llvm/Support/COFF.h | 3 +- include/llvm/Support/Win64EH.h | 18 +- test/MC/ELF/many-sections-2.s | 2 +- test/Object/readobj-elf-versioning.test | 49 +- test/Object/readobj-shared-object.test | 387 +++++-- test/tools/llvm-readobj/Inputs/trivial.ll | 19 + .../llvm-readobj/Inputs/trivial.obj.coff-i386 | Bin 0 -> 314 bytes .../Inputs/trivial.obj.coff-x86-64 | Bin 0 -> 319 bytes .../llvm-readobj/Inputs/trivial.obj.elf-i386 | Bin 0 -> 896 bytes .../Inputs/trivial.obj.elf-x86-64 | Bin 0 -> 1256 bytes .../Inputs/trivial.obj.macho-i386 | Bin 0 -> 472 bytes .../Inputs/trivial.obj.macho-x86-64 | Bin 0 -> 532 bytes test/tools/llvm-readobj/file-headers.test | 100 ++ test/tools/llvm-readobj/lit.local.cfg | 1 + test/tools/llvm-readobj/relocations.test | 32 + test/tools/llvm-readobj/sections-ext.test | 175 +++ test/tools/llvm-readobj/sections.test | 113 ++ test/tools/llvm-readobj/symbols.test | 44 + tools/llvm-readobj/CMakeLists.txt | 13 +- tools/llvm-readobj/COFFDumper.cpp | 1014 +++++++++++++++++ tools/llvm-readobj/ELF.cpp | 196 ---- tools/llvm-readobj/ELFDumper.cpp | 800 +++++++++++++ tools/llvm-readobj/Error.cpp | 62 + tools/llvm-readobj/Error.h | 48 + tools/llvm-readobj/LLVMBuild.txt | 2 +- tools/llvm-readobj/MachODumper.cpp | 438 +++++++ tools/llvm-readobj/Makefile | 2 +- tools/llvm-readobj/ObjDumper.cpp | 33 + tools/llvm-readobj/ObjDumper.h | 60 + tools/llvm-readobj/StreamWriter.cpp | 79 ++ tools/llvm-readobj/StreamWriter.h | 282 +++++ tools/llvm-readobj/llvm-readobj.cpp | 459 ++++---- tools/llvm-readobj/llvm-readobj.h | 35 +- 34 files changed, 3940 insertions(+), 533 deletions(-) create mode 100644 test/tools/llvm-readobj/Inputs/trivial.ll create mode 100644 test/tools/llvm-readobj/Inputs/trivial.obj.coff-i386 create mode 100644 test/tools/llvm-readobj/Inputs/trivial.obj.coff-x86-64 create mode 100644 test/tools/llvm-readobj/Inputs/trivial.obj.elf-i386 create mode 100644 test/tools/llvm-readobj/Inputs/trivial.obj.elf-x86-64 create mode 100644 test/tools/llvm-readobj/Inputs/trivial.obj.macho-i386 create mode 100644 test/tools/llvm-readobj/Inputs/trivial.obj.macho-x86-64 create mode 100644 test/tools/llvm-readobj/file-headers.test create mode 100644 test/tools/llvm-readobj/lit.local.cfg create mode 100644 test/tools/llvm-readobj/relocations.test create mode 100644 test/tools/llvm-readobj/sections-ext.test create mode 100644 test/tools/llvm-readobj/sections.test create mode 100644 test/tools/llvm-readobj/symbols.test create mode 100644 tools/llvm-readobj/COFFDumper.cpp delete mode 100644 tools/llvm-readobj/ELF.cpp create mode 100644 tools/llvm-readobj/ELFDumper.cpp create mode 100644 tools/llvm-readobj/Error.cpp create mode 100644 tools/llvm-readobj/Error.h create mode 100644 tools/llvm-readobj/MachODumper.cpp create mode 100644 tools/llvm-readobj/ObjDumper.cpp create mode 100644 tools/llvm-readobj/ObjDumper.h create mode 100644 tools/llvm-readobj/StreamWriter.cpp create mode 100644 tools/llvm-readobj/StreamWriter.h diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index 719bc08915d..ac6f386032e 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -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::getSection(const Elf_Sym *symb) const { return getSection(symb->st_shndx); } +template +const typename ELFObjectFile::Elf_Ehdr * +ELFObjectFile::getElfHeader() const { + return Header; +} + template const typename ELFObjectFile::Elf_Shdr * ELFObjectFile::getElfSection(section_iterator &It) const { diff --git a/include/llvm/Support/COFF.h b/include/llvm/Support/COFF.h index 02c44cdfad2..823b43ad938 100644 --- a/include/llvm/Support/COFF.h +++ b/include/llvm/Support/COFF.h @@ -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 diff --git a/include/llvm/Support/Win64EH.h b/include/llvm/Support/Win64EH.h index 164aca16bf3..ecce7136804 100644 --- a/include/llvm/Support/Win64EH.h +++ b/include/llvm/Support/Win64EH.h @@ -106,12 +106,17 @@ struct UnwindInfo { return reinterpret_cast(&UnwindCodes[(NumCodes+1) & ~1]); } - /// \brief Return image-relativ offset of language-specific exception handler. - uint32_t getLanguageSpecificHandlerOffset() { - return *reinterpret_cast(getLanguageSpecificData()); + /// \brief Return pointer to language specific data part of UnwindInfo. + const void *getLanguageSpecificData() const { + return reinterpret_cast(&UnwindCodes[(NumCodes+1) & ~1]); } - /// \brief Set image-relativ offset of language-specific exception handler. + /// \brief Return image-relative offset of language-specific exception handler. + uint32_t getLanguageSpecificHandlerOffset() const { + return *reinterpret_cast(getLanguageSpecificData()); + } + + /// \brief Set image-relative offset of language-specific exception handler. void setLanguageSpecificHandlerOffset(uint32_t offset) { *reinterpret_cast(getLanguageSpecificData()) = offset; } @@ -126,6 +131,11 @@ struct UnwindInfo { RuntimeFunction *getChainedFunctionEntry() { return reinterpret_cast(getLanguageSpecificData()); } + + /// \brief Return pointer to chained unwind info. + const RuntimeFunction *getChainedFunctionEntry() const { + return reinterpret_cast(getLanguageSpecificData()); + } }; diff --git a/test/MC/ELF/many-sections-2.s b/test/MC/ELF/many-sections-2.s index f5a1a0e4376..789ebf378d8 100644 --- a/test/MC/ELF/many-sections-2.s +++ b/test/MC/ELF/many-sections-2.s @@ -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 diff --git a/test/Object/readobj-elf-versioning.test b/test/Object/readobj-elf-versioning.test index be1a39d9c48..1f09ef32a11 100644 --- a/test/Object/readobj-elf-versioning.test +++ b/test/Object/readobj-elf-versioning.test @@ -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: ] diff --git a/test/Object/readobj-shared-object.test b/test/Object/readobj-shared-object.test index 548bd3801e0..72dbd32ea9d 100644 --- a/test/Object/readobj-shared-object.test +++ b/test/Object/readobj-shared-object.test @@ -1,92 +1,319 @@ -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 index 00000000000..2cd7ec89e24 --- /dev/null +++ b/test/tools/llvm-readobj/Inputs/trivial.ll @@ -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 index 0000000000000000000000000000000000000000..282e5699a767d8bc132e5e415161ae71445ffb87 GIT binary patch literal 314 zcmeZaWMYW>;TgD;fq{V?h(SQFB(*=U@|b{_je!$LvI4OP10R?VVtJ(I4Dkh}CB;w? j5Cu^OavBUUF^B`1@xl4Iss1GysYPz3dC4W2`FRWgA5AgcmXF2fx<^L4ukAu0%8^h9w5mIW(fjGHZaR0H76%u zAw0h*Cxr{eS&TqwW=4?1K#lMI literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..f85e40d6261f1d9081b87f4da4244bada2970828 GIT binary patch literal 896 zcma)4u}%U(5S^0~0X0!7V7ofD=Q!YEG|-j(S!mIxP*%bXYLjwl`&Kn{u2on zehP(+y$Q}cb_KQ2m+ZZHJF_!8bNf)VN`_&?NWq{O8Co#ED*GhjeM-^Ff|sZ|d`nEQ zQ-2&I$@386$=scMOsCW6lN}9T67@0Bnd5nW=F$(mc8W*@jwhsZFG)1RkVMayjwqjB z9EQ?v-H-@7p$w$mWJ~j)8|k(!Z9eXU;mnFGivA1B9EJYkDmuq}plr~FvJsP1Ht3q0 z%P=Q+!DlM_RB7}Mcr*I?A`V#Pg|mOfk4aM4*VXbSz zg}4d~1s#WaOL~*}ip7W-Gr+yk2Wnzgi}|)#6nRfW=hIsA;=W1m(>>)tZwBG7%<=sN zqTXUfXg$^0nb@!MaavR9aNjgnIG(4E`q=!T#Scv~aPM5(6P`z1+wD=KY*h+*t5GSH zs>NEPmM>Vv1_=ufkZ$`jq^jR_Dzf7QrGBp^UB8EvxJQa#dzv}PGu>u3`7!K(dAOfo CD^%kE literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..95285c1f230c6d2655c5bab22c52133a62f239b7 GIT binary patch literal 1256 zcmbtT%}T>S5T2U)SAS3s;ziK2xKh0cqO^tn9D*%aQM{Dc23kxTNw%UVpTKwUF+2*s zj92eMoiE*u%UUlwu=~w?GqbaqojjJ^%2X!fkdh3YP(~XDz8HET(F>HLS!&dtj$yv1 zTmJRxji}}aLAZ4hMnNY>BqBfXg!JzviR(BfF$kqEs;B3>vGm$EB;sx?Bk5hUrtzVl z*d0%LoF4+=%!_U+Hb2^W7a-410;XJOy3%dQ_)hJ&{3g#&6;-Fm6$w(6D2S-IJ27E5lqg}VAn@zz+M Vqp{#!A@DEo()=<=7VwDC{1-XeUWWhx literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..5048171ccb0ce2beaf1abd6629a748c40af04f49 GIT binary patch literal 472 zcmX^2>+L^w1_lOZAZCQp8X$%Ognt0Y#0K<%f-XRHAR43}gqeUC1mfdMQY%UzYzRNZ zH6jGT2eFiZ7^I&CNS8oqAg2My1%vqbT|%)E3sAJq(yeqJC>1L{QvFgJk2Kx_#h zo&r<@^4|_1tpKFCfj9t&kpajU5JuLIERT=f{D$WRNIs&sK?+E9vZ%ax`Tzg_7f*nM z;eqBOJcm6}b8_+(!t;xAQn(;)0@}qZ3{(uXj~D2kB}yOz7#J3E011#g_(22^fcyw$ pg2NcbW{A&C%*+L^w1_nlE1|R{%AUXiVPyk{ekOblvU>0^l87f==(gOrAKF~}C5M}}i0zrIy zNoqw2gbm?`xJHB^_%N0jlmRl21<0NPq(N>1avDGs48+GL7nc-e=A}ag;^R@xgPFq% zm2ZQ(52hdHE@Zw0kh2DA?;9Yk0pxQ7aR5{i$Osq)=|?vMsthj`;L&RfQUDH9FkyHg z>aa&@PENi;cz#h%3Ks(dA5b1>wk{`-2KrqW6b?Wjs{kbUfD$mjf!x9mBA@`|S0pYt v{E_(#@wthac?|Idr6t7-@xl4Iss1GysYPz3dC4W2`FRXJ@p`~8WncgROX)1x literal 0 HcmV?d00001 diff --git a/test/tools/llvm-readobj/file-headers.test b/test/tools/llvm-readobj/file-headers.test new file mode 100644 index 00000000000..226eb934233 --- /dev/null +++ b/test/tools/llvm-readobj/file-headers.test @@ -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 index 00000000000..df9b335dd13 --- /dev/null +++ b/test/tools/llvm-readobj/lit.local.cfg @@ -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 index 00000000000..06085653735 --- /dev/null +++ b/test/tools/llvm-readobj/relocations.test @@ -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 index 00000000000..a972c9ab51d --- /dev/null +++ b/test/tools/llvm-readobj/sections-ext.test @@ -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 index 00000000000..84154d759cd --- /dev/null +++ b/test/tools/llvm-readobj/sections.test @@ -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 index 00000000000..d33bd8ed2cd --- /dev/null +++ b/test/tools/llvm-readobj/symbols.test @@ -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: } diff --git a/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt index 676c23d7ae6..3d20def8f51 100644 --- a/tools/llvm-readobj/CMakeLists.txt +++ b/tools/llvm-readobj/CMakeLists.txt @@ -1,6 +1,15 @@ -set(LLVM_LINK_COMPONENTS archive bitreader object) +set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + archive + bitreader + object) add_llvm_tool(llvm-readobj - ELF.cpp llvm-readobj.cpp + ObjDumper.cpp + COFFDumper.cpp + ELFDumper.cpp + MachODumper.cpp + Error.cpp + StreamWriter.cpp ) diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp new file mode 100644 index 00000000000..be4e76cc634 --- /dev/null +++ b/tools/llvm-readobj/COFFDumper.cpp @@ -0,0 +1,1014 @@ +//===-- COFFDumper.cpp - COFF-specific dumper -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements the COFF-specific dumper for llvm-readobj. +/// +//===----------------------------------------------------------------------===// + +#include "llvm-readobj.h" +#include "ObjDumper.h" + +#include "Error.h" +#include "StreamWriter.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/Win64EH.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" + +#include +#include +#include + +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 &Rels); + + void printUnwindInfo( + const Win64EH::UnwindInfo& UI, + uint64_t OffsetInSection, + const std::vector &Rels); + + void printUnwindCode(const Win64EH::UnwindInfo& UI, ArrayRef UCs); + + void cacheRelocations(); + + error_code getSectionContents( + const std::vector &Rels, + uint64_t Offset, + ArrayRef &Contents, + uint64_t &Addr); + + error_code getSection( + const std::vector &Rels, + uint64_t Offset, + const coff_section **Section, + uint64_t *AddrPtr); + + typedef DenseMap > RelocMapTy; + + const llvm::object::COFFObjectFile *Obj; + RelocMapTy RelocMap; + std::vector EmptyRelocs; +}; + +} // namespace + + +namespace llvm { + +error_code createCOFFDumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr &Result) { + const COFFObjectFile *COFFObj = dyn_cast(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 &Rels, + uint64_t Offset, SymbolRef &Sym) { + for (std::vector::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 &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 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 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 +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 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 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 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 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 +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 UnwindFlags[] = { + { "ExceptionHandler", Win64EH::UNW_ExceptionHandler }, + { "TerminateHandler", Win64EH::UNW_TerminateHandler }, + { "ChainInfo" , Win64EH::UNW_ChainInfo } +}; + +static const EnumEntry 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(UI.getLanguageSpecificData()) + - reinterpret_cast(&UI); +} + +static uint32_t getLargeSlotValue(ArrayRef UCs) { + if (UCs.size() < 3) + return 0; + + return UCs[1].FrameOffset + (static_cast(UCs[2].FrameOffset) << 16); +} + +template +static error_code getSymbolAuxData(const COFFObjectFile *Obj, + const coff_symbol *Symbol, const T* &Aux) { + ArrayRef AuxData = Obj->getSymbolAuxData(Symbol); + Aux = reinterpret_cast(AuxData.data()); + return readobj_error::success; +} + +static std::string formatSymbol(const std::vector &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 &Rels, uint64_t Offset, + ArrayRef &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 &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() << "\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 Contents; + if (error(Obj->getSectionContents(PData, Contents)) || + Contents.empty()) + continue; + + ArrayRef RFs( + reinterpret_cast(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 &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 XContents; + if (error(Obj->getSectionContents(XData, XContents)) || XContents.empty()) + return; + + UnwindInfoOffset += RTF.UnwindInfoOffset; + if (UnwindInfoOffset > XContents.size()) + return; + + const Win64EH::UnwindInfo *UI = + reinterpret_cast( + XContents.data() + UnwindInfoOffset); + + printUnwindInfo(*UI, UnwindInfoOffset, RelocMap[XData]); +} + +void COFFDumper::printUnwindInfo( + const Win64EH::UnwindInfo& UI, + uint64_t OffsetInSection, + const std::vector &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 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(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 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="; + } 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(UCs[0].getOpInfo()) + << format(", offset=0x%X", UCs[1].FrameOffset * 16); + break; + case UOP_SaveXMM128Big: + outs() << " reg=XMM" << static_cast(UCs[0].getOpInfo()) + << format(", offset=0x%X", getLargeSlotValue(UCs)); + break; + case UOP_PushMachFrame: + outs() << " errcode=" << (UCs[0].getOpInfo() == 0 ? "no" : "yes"); + break; + } + + outs() << "\n"; +} diff --git a/tools/llvm-readobj/ELF.cpp b/tools/llvm-readobj/ELF.cpp deleted file mode 100644 index 07f15b3a6d4..00000000000 --- a/tools/llvm-readobj/ELF.cpp +++ /dev/null @@ -1,196 +0,0 @@ -//===- llvm-readobj/ELF.cpp - ELF Specific Dumper -------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm-readobj.h" - -#include "llvm/Object/ELF.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/Format.h" - -namespace llvm { -using namespace object; -using namespace ELF; - -const char *getTypeString(uint64_t Type) { - switch (Type) { - case DT_BIND_NOW: - return "(BIND_NOW)"; - case DT_DEBUG: - return "(DEBUG)"; - case DT_FINI: - return "(FINI)"; - case DT_FINI_ARRAY: - return "(FINI_ARRAY)"; - case DT_FINI_ARRAYSZ: - return "(FINI_ARRAYSZ)"; - case DT_FLAGS: - return "(FLAGS)"; - case DT_HASH: - return "(HASH)"; - case DT_INIT: - return "(INIT)"; - case DT_INIT_ARRAY: - return "(INIT_ARRAY)"; - case DT_INIT_ARRAYSZ: - return "(INIT_ARRAYSZ)"; - case DT_PREINIT_ARRAY: - return "(PREINIT_ARRAY)"; - case DT_PREINIT_ARRAYSZ: - return "(PREINIT_ARRAYSZ)"; - case DT_JMPREL: - return "(JMPREL)"; - case DT_NEEDED: - return "(NEEDED)"; - case DT_NULL: - return "(NULL)"; - case DT_PLTGOT: - return "(PLTGOT)"; - case DT_PLTREL: - return "(PLTREL)"; - case DT_PLTRELSZ: - return "(PLTRELSZ)"; - case DT_REL: - return "(REL)"; - case DT_RELA: - return "(RELA)"; - case DT_RELENT: - return "(RELENT)"; - case DT_RELSZ: - return "(RELSZ)"; - case DT_RELAENT: - return "(RELAENT)"; - case DT_RELASZ: - return "(RELASZ)"; - case DT_RPATH: - return "(RPATH)"; - case DT_RUNPATH: - return "(RUNPATH)"; - case DT_SONAME: - return "(SONAME)"; - case DT_STRSZ: - return "(STRSZ)"; - case DT_STRTAB: - return "(STRTAB)"; - case DT_SYMBOLIC: - return "(SYMBOLIC)"; - case DT_SYMENT: - return "(SYMENT)"; - case DT_SYMTAB: - return "(SYMTAB)"; - case DT_TEXTREL: - return "(TEXTREL)"; - default: - return "unknown"; - } -} - -template -void printValue(const ELFObjectFile *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 -ErrorOr dumpDynamicTable(const ELFObjectFile *O, raw_ostream &OS) { - typedef ELFObjectFile 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 dumpELFDynamicTable(ObjectFile *O, raw_ostream &OS) { - // Little-endian 32-bit - if (const ELFObjectFile > *ELFObj = - dyn_cast > >(O)) - return dumpDynamicTable(ELFObj, OS); - - // Big-endian 32-bit - if (const ELFObjectFile > *ELFObj = - dyn_cast > >(O)) - return dumpDynamicTable(ELFObj, OS); - - // Little-endian 64-bit - if (const ELFObjectFile > *ELFObj = - dyn_cast > >(O)) - return dumpDynamicTable(ELFObj, OS); - - // Big-endian 64-bit - if (const ELFObjectFile > *ELFObj = - dyn_cast > >(O)) - return dumpDynamicTable(ELFObj, OS); - return error_code(object_error::invalid_file_type); -} -} // end namespace llvm diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp new file mode 100644 index 00000000000..9e111dd905c --- /dev/null +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -0,0 +1,800 @@ +//===-- ELFDumper.cpp - ELF-specific dumper ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements the ELF-specific dumper for llvm-readobj. +/// +//===----------------------------------------------------------------------===// + +#include "llvm-readobj.h" +#include "Error.h" +#include "ObjDumper.h" +#include "StreamWriter.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::object; +using namespace ELF; + + +#define LLVM_READOBJ_ENUM_CASE(ns, enum) \ + case ns::enum: return #enum; + +namespace { + +template +class ELFDumper : public ObjDumper { +public: + ELFDumper(const ELFObjectFile *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::Elf_Shdr Elf_Shdr; + typedef typename ELFObjectFile::Elf_Sym Elf_Sym; + + void printSymbol(symbol_iterator SymI, bool IsDynamic = false); + + void printRelocation(section_iterator SecI, relocation_iterator RelI); + + const ELFObjectFile *Obj; +}; + +} // namespace + + +namespace llvm { + +error_code createELFDumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr &Result) { + typedef ELFType Little32ELF; + typedef ELFType Big32ELF; + typedef ELFType Little64ELF; + typedef ELFType Big64ELF; + + typedef ELFObjectFile LittleELF32Obj; + typedef ELFObjectFile BigELF32Obj; + typedef ELFObjectFile LittleELF64Obj; + typedef ELFObjectFile BigELF64Obj; + + // Little-endian 32-bit + if (const LittleELF32Obj *ELFObj = dyn_cast(Obj)) { + Result.reset(new ELFDumper(ELFObj, Writer)); + return readobj_error::success; + } + + // Big-endian 32-bit + if (const BigELF32Obj *ELFObj = dyn_cast(Obj)) { + Result.reset(new ELFDumper(ELFObj, Writer)); + return readobj_error::success; + } + + // Little-endian 64-bit + if (const LittleELF64Obj *ELFObj = dyn_cast(Obj)) { + Result.reset(new ELFDumper(ELFObj, Writer)); + return readobj_error::success; + } + + // Big-endian 64-bit + if (const BigELF64Obj *ELFObj = dyn_cast(Obj)) { + Result.reset(new ELFDumper(ELFObj, Writer)); + return readobj_error::success; + } + + return readobj_error::unsupported_obj_file_format; +} + +} // namespace llvm + + +static const EnumEntry ElfClass[] = { + { "None", ELF::ELFCLASSNONE }, + { "32-bit", ELF::ELFCLASS32 }, + { "64-bit", ELF::ELFCLASS64 }, +}; + +static const EnumEntry ElfDataEncoding[] = { + { "None", ELF::ELFDATANONE }, + { "LittleEndian", ELF::ELFDATA2LSB }, + { "BigEndian", ELF::ELFDATA2MSB }, +}; + +static const EnumEntry ElfObjectFileType[] = { + { "None", ELF::ET_NONE }, + { "Relocatable", ELF::ET_REL }, + { "Executable", ELF::ET_EXEC }, + { "SharedObject", ELF::ET_DYN }, + { "Core", ELF::ET_CORE }, +}; + +static const EnumEntry 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 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 ElfSymbolBindings[] = { + { "Local", ELF::STB_LOCAL }, + { "Global", ELF::STB_GLOBAL }, + { "Weak", ELF::STB_WEAK } +}; + +static const EnumEntry 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 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 +void ELFDumper::printFileHeaders() { + error_code EC; + typedef ELFObjectFile 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 +void ELFDumper::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 +void ELFDumper::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 +void ELFDumper::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 +void ELFDumper::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 +void ELFDumper::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 +void ELFDumper::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 +static void printValue(const ELFObjectFile *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 +void ELFDumper::printUnwindInfo() { + W.startLine() << "UnwindInfo not implemented.\n"; +} + +template +void ELFDumper::printDynamicTable() { + typedef ELFObjectFile 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 +void ELFDumper::printNeededLibraries() { + ListScope D(W, "NeededLibraries"); + + error_code EC; + + typedef std::vector LibsTy; + LibsTy Libs; + + for (library_iterator I = Obj->begin_libraries_needed(), + E = Obj->end_libraries_needed(); + I != E; I.increment(EC)) { + if (EC) + report_fatal_error("Needed libraries iteration failed"); + + Libs.push_back(*I); + } + + std::sort(Libs.begin(), Libs.end(), &compareLibraryName); + + for (LibsTy::const_iterator I = Libs.begin(), E = Libs.end(); + I != E; ++I) { + StringRef Path; + I->getPath(Path); + outs() << " " << Path << "\n"; + } +} diff --git a/tools/llvm-readobj/Error.cpp b/tools/llvm-readobj/Error.cpp new file mode 100644 index 00000000000..a6c61321c6d --- /dev/null +++ b/tools/llvm-readobj/Error.cpp @@ -0,0 +1,62 @@ +//===- Error.cpp - system_error extensions for llvm-readobj -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines a new error_category for the llvm-readobj tool. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +namespace { +class _readobj_error_category : public _do_message { +public: + virtual const char* name() const; + virtual std::string message(int ev) const; + virtual error_condition default_error_condition(int ev) const; +}; +} // namespace + +const char *_readobj_error_category::name() const { + return "llvm.readobj"; +} + +std::string _readobj_error_category::message(int ev) const { + switch (ev) { + case readobj_error::success: return "Success"; + case readobj_error::file_not_found: + return "No such file."; + case readobj_error::unsupported_file_format: + return "The file was not recognized as a valid object file."; + case readobj_error::unrecognized_file_format: + return "Unrecognized file type."; + case readobj_error::unsupported_obj_file_format: + return "Unsupported object file format."; + case readobj_error::unknown_symbol: + return "Unknown symbol."; + default: + llvm_unreachable("An enumerator of readobj_error does not have a message " + "defined."); + } +} + +error_condition _readobj_error_category::default_error_condition(int ev) const { + if (ev == readobj_error::success) + return errc::success; + return errc::invalid_argument; +} + +namespace llvm { +const error_category &readobj_category() { + static _readobj_error_category o; + return o; +} +} // namespace llvm diff --git a/tools/llvm-readobj/Error.h b/tools/llvm-readobj/Error.h new file mode 100644 index 00000000000..cf68da89c1d --- /dev/null +++ b/tools/llvm-readobj/Error.h @@ -0,0 +1,48 @@ +//===- Error.h - system_error extensions for llvm-readobj -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This declares a new error_category for the llvm-readobj tool. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_READOBJ_ERROR_H +#define LLVM_READOBJ_ERROR_H + +#include "llvm/Support/system_error.h" + +namespace llvm { + +const error_category &readobj_category(); + +struct readobj_error { + enum _ { + success = 0, + file_not_found, + unsupported_file_format, + unrecognized_file_format, + unsupported_obj_file_format, + unknown_symbol + }; + _ v_; + + readobj_error(_ v) : v_(v) {} + explicit readobj_error(int v) : v_(_(v)) {} + operator int() const {return v_;} +}; + +inline error_code make_error_code(readobj_error e) { + return error_code(static_cast(e), readobj_category()); +} + +template <> struct is_error_code_enum : true_type { }; +template <> struct is_error_code_enum : true_type { }; + +} // namespace llvm + +#endif diff --git a/tools/llvm-readobj/LLVMBuild.txt b/tools/llvm-readobj/LLVMBuild.txt index c9f934f4b6f..813c12b752b 100644 --- a/tools/llvm-readobj/LLVMBuild.txt +++ b/tools/llvm-readobj/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llvm-readobj parent = Tools -required_libraries = Archive BitReader Object +required_libraries = all-targets Archive BitReader Object diff --git a/tools/llvm-readobj/MachODumper.cpp b/tools/llvm-readobj/MachODumper.cpp new file mode 100644 index 00000000000..798c9417720 --- /dev/null +++ b/tools/llvm-readobj/MachODumper.cpp @@ -0,0 +1,438 @@ +//===-- MachODump.cpp - Object file dumping utility for llvm --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the MachO-specific dumper for llvm-readobj. +// +//===----------------------------------------------------------------------===// + +#include "llvm-readobj.h" +#include "Error.h" +#include "ObjDumper.h" +#include "StreamWriter.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/Object/MachO.h" +#include "llvm/Support/Casting.h" + +using namespace llvm; +using namespace object; + +namespace { + +class MachODumper : public ObjDumper { +public: + MachODumper(const llvm::object::MachOObjectFile *Obj, StreamWriter& Writer) + : ObjDumper(Writer) + , Obj(Obj) { } + + virtual void printFileHeaders() LLVM_OVERRIDE; + virtual void printSections() LLVM_OVERRIDE; + virtual void printRelocations() LLVM_OVERRIDE; + virtual void printSymbols() LLVM_OVERRIDE; + virtual void printDynamicSymbols() LLVM_OVERRIDE; + virtual void printUnwindInfo() LLVM_OVERRIDE; + +private: + void printSymbol(symbol_iterator SymI); + + void printRelocation(section_iterator SecI, relocation_iterator RelI); + + const llvm::object::MachOObjectFile *Obj; +}; + +} // namespace + + +namespace llvm { + +error_code createMachODumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr &Result) { + const MachOObjectFile *MachOObj = dyn_cast(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 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 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 MachOSymbolRefTypes[] = { + { "UndefinedNonLazy", 0 }, + { "ReferenceFlagUndefinedLazy", 1 }, + { "ReferenceFlagDefined", 2 }, + { "ReferenceFlagPrivateDefined", 3 }, + { "ReferenceFlagPrivateUndefinedNonLazy", 4 }, + { "ReferenceFlagPrivateUndefinedLazy", 5 } +}; + +static const EnumEntry MachOSymbolFlags[] = { + { "ReferencedDynamically", 0x10 }, + { "NoDeadStrip", 0x20 }, + { "WeakRef", 0x40 }, + { "WeakDef", 0x80 } +}; + +static const EnumEntry MachOSymbolTypes[] = { + { "Undef", 0x0 }, + { "External", 0x1 }, + { "Abs", 0x2 }, + { "Indirect", 0xA }, + { "PreboundUndef", 0xC }, + { "Section", 0xE }, + { "PrivateExternal", 0x10 } +}; + +namespace { + enum { + N_STAB = 0xE0 + }; + + struct MachOSection { + ArrayRef Name; + ArrayRef 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 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 Sect; + MachOObj->ReadSection64(LCI, DRI.d.b, Sect); + + Section.Name = ArrayRef(Sect->Name); + Section.SegmentName = ArrayRef(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 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 &Res) { + InMemoryStruct 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 &Res) { + InMemoryStruct 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 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 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(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(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(Symbol.Flags & 0xF), + makeArrayRef(MachOSymbolRefTypes)); + W.printFlags ("Flags", static_cast(Symbol.Flags & ~0xF), + makeArrayRef(MachOSymbolFlags)); + W.printHex ("Value", Symbol.Value); +} + +void MachODumper::printUnwindInfo() { + W.startLine() << "UnwindInfo not implemented.\n"; +} diff --git a/tools/llvm-readobj/Makefile b/tools/llvm-readobj/Makefile index a7a7de35630..1bb72955f08 100644 --- a/tools/llvm-readobj/Makefile +++ b/tools/llvm-readobj/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-readobj -LINK_COMPONENTS := archive bitreader object +LINK_COMPONENTS := archive bitreader object all-targets # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-readobj/ObjDumper.cpp b/tools/llvm-readobj/ObjDumper.cpp new file mode 100644 index 00000000000..61f511740a2 --- /dev/null +++ b/tools/llvm-readobj/ObjDumper.cpp @@ -0,0 +1,33 @@ +//===-- ObjDumper.cpp - Base dumper class -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements ObjDumper. +/// +//===----------------------------------------------------------------------===// + +#include "ObjDumper.h" + +#include "Error.h" +#include "StreamWriter.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +ObjDumper::ObjDumper(StreamWriter& Writer) + : W(Writer) { +} + +ObjDumper::~ObjDumper() { +} + +} // namespace llvm diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h new file mode 100644 index 00000000000..8d191cbe07d --- /dev/null +++ b/tools/llvm-readobj/ObjDumper.h @@ -0,0 +1,60 @@ +//===-- ObjDumper.h -------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_READOBJ_OBJDUMPER_H +#define LLVM_READOBJ_OBJDUMPER_H + +namespace llvm { + +namespace object { + class ObjectFile; +} + +class error_code; + +template +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 &Result); + +error_code createELFDumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr &Result); + +error_code createMachODumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr &Result); + +} // namespace llvm + +#endif diff --git a/tools/llvm-readobj/StreamWriter.cpp b/tools/llvm-readobj/StreamWriter.cpp new file mode 100644 index 00000000000..871811233a6 --- /dev/null +++ b/tools/llvm-readobj/StreamWriter.cpp @@ -0,0 +1,79 @@ +#include "StreamWriter.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Format.h" +#include + +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 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(Data[i])); + } + OS << ")\n"; + } +} + +} // namespace llvm diff --git a/tools/llvm-readobj/StreamWriter.h b/tools/llvm-readobj/StreamWriter.h new file mode 100644 index 00000000000..129f6e79336 --- /dev/null +++ b/tools/llvm-readobj/StreamWriter.h @@ -0,0 +1,282 @@ +//===-- StreamWriter.h ----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_READOBJ_STREAMWRITER_H +#define LLVM_READOBJ_STREAMWRITER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace llvm; +using namespace llvm::support; + +namespace llvm { + +template +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(Value)) { } + HexNumber(int16_t Value) : Value(static_cast(Value)) { } + HexNumber(int32_t Value) : Value(static_cast(Value)) { } + HexNumber(int64_t Value) : Value(static_cast(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 + HexNumber hex(T Value) { + return HexNumber(Value); + } + + template + void printEnum(StringRef Label, T Value, + ArrayRef > 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 + void printFlags(StringRef Label, T Value, ArrayRef > Flags, + TFlag EnumMask = TFlag(0)) { + typedef EnumEntry FlagEntry; + typedef SmallVector FlagVector; + FlagVector SetFlags; + + for (typename ArrayRef::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); + + 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 + 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 + void printHex(StringRef Label, T Value) { + startLine() << Label << ": " << hex(Value) << "\n"; + } + + template + 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 + void printNumber(StringRef Label, StringRef Str, T Value) { + startLine() << Label << ": " << Str << " (" << Value << ")\n"; + } + + void printBinary(StringRef Label, StringRef Str, ArrayRef Value) { + printBinaryImpl(Label, Str, Value, false); + } + + void printBinary(StringRef Label, StringRef Str, ArrayRef Value) { + ArrayRef V(reinterpret_cast(Value.data()), + Value.size()); + printBinaryImpl(Label, Str, V, false); + } + + void printBinary(StringRef Label, ArrayRef Value) { + printBinaryImpl(Label, StringRef(), Value, false); + } + + void printBinary(StringRef Label, ArrayRef Value) { + ArrayRef V(reinterpret_cast(Value.data()), + Value.size()); + printBinaryImpl(Label, StringRef(), V, false); + } + + void printBinary(StringRef Label, StringRef Value) { + ArrayRef V(reinterpret_cast(Value.data()), + Value.size()); + printBinaryImpl(Label, StringRef(), V, false); + } + + void printBinaryBlock(StringRef Label, StringRef Value) { + ArrayRef V(reinterpret_cast(Value.data()), + Value.size()); + printBinaryImpl(Label, StringRef(), V, true); + } + + raw_ostream& startLine() { + printIndent(); + return OS; + } + + raw_ostream& getOStream() { + return OS; + } + +private: + template + static bool flagName(const EnumEntry& lhs, const EnumEntry& rhs) { + return lhs.Name < rhs.Name; + } + + void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef Value, + bool Block); + + raw_ostream &OS; + int IndentLevel; +}; + +struct DictScope { + DictScope(StreamWriter& W, StringRef N) : W(W) { + W.startLine() << N << " {\n"; + W.indent(); + } + + ~DictScope() { + W.unindent(); + W.startLine() << "}\n"; + } + + StreamWriter& W; +}; + +struct ListScope { + ListScope(StreamWriter& W, StringRef N) : W(W) { + W.startLine() << N << " [\n"; + W.indent(); + } + + ~ListScope() { + W.unindent(); + W.startLine() << "]\n"; + } + + StreamWriter& W; +}; + +} // namespace llvm + +#endif diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index ea37d105dc6..67c9a98f40f 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -21,268 +21,263 @@ #include "llvm-readobj.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Object/ELF.h" +#include "Error.h" +#include "ObjDumper.h" +#include "StreamWriter.h" + +#include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/system_error.h" + +#include + using namespace llvm; using namespace llvm::object; -static cl::opt -InputFilename(cl::Positional, cl::desc(""), cl::init("")); +namespace opts { + cl::list InputFilenames(cl::Positional, + cl::desc(""), + cl::ZeroOrMore); -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"; + // -file-headers, -h + cl::opt 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 Sections("sections", + cl::desc("Display all sections.")); + cl::alias SectionsShort("s", + cl::desc("Alias for --sections"), + cl::aliasopt(Sections)); + + // -section-relocations, -sr + cl::opt 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 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 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 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 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 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 UnwindInfo("unwind", + cl::desc("Display unwind information")); + cl::alias UnwindInfoShort("u", + cl::desc("Alias for --unwind"), + cl::aliasopt(UnwindInfo)); + + // -dynamic-table + cl::opt DynamicTable("dynamic-table", + cl::desc("Display the ELF .dynamic section table")); + + // -needed-libs + cl::opt 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") +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; +} + +} // namespace llvm + + +static void reportError(StringRef Input, error_code EC) { + if (Input == "-") + Input = ""; + + errs() << Input << ": " << EC.message() << "\n"; + errs().flush(); +} + +static void reportError(StringRef Input, StringRef Message) { + if (Input == "-") + Input = ""; + + errs() << Input << ": " << Message << "\n"; +} + +/// @brief Creates an format-specific object file dumper. +static error_code createDumper(const ObjectFile *Obj, + StreamWriter &Writer, + OwningPtr &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; +} + + +/// @brief Dumps the specified object file. +static void dumpObject(const ObjectFile *Obj) { + StreamWriter Writer(outs()); + OwningPtr Dumper; + if (error_code EC = createDumper(Obj, Writer, Dumper)) { + reportError(Obj->getFileName(), EC); + return; + } + + outs() << '\n'; + outs() << "File: " << Obj->getFileName() << "\n"; + outs() << "Format: " << Obj->getFileFormatName() << "\n"; + outs() << "Arch: " + << Triple::getArchTypeName((llvm::Triple::ArchType)Obj->getArch()) << "\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(); } -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; -} - -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; - } - - // Remove trailing comma - if (result.size() > 0) { - result.erase(result.size() - 1); - } - return result; -} - -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; +/// @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 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 (ObjectFile *Obj = dyn_cast(child.get())) + dumpObject(Obj); + else + reportError(Arc->getFileName(), readobj_error::unrecognized_file_format); + } +} + + +/// @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; } - // 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"; -} - -static void dumpStaticSymbol(const SymbolRef &Sym, const ObjectFile *obj) { - return dumpSymbol(Sym, obj, false); -} - -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 -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; + // Attempt to open the binary. + OwningPtr Binary; + if (error_code EC = createBinary(File, Binary)) { + reportError(File, EC); + return; } - outs() << " Total: " << count << "\n\n"; + + if (Archive *Arc = dyn_cast(Binary.get())) + dumpArchive(Arc); + else if (ObjectFile *Obj = dyn_cast(Binary.get())) + dumpObject(Obj); + else + reportError(File, readobj_error::unrecognized_file_format); } -static void dumpHeaders(const ObjectFile *obj) { - outs() << "File 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"; -} -int main(int argc, char** argv) { - error_code ec; +int main(int argc, const char *argv[]) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; - cl::ParseCommandLineOptions(argc, argv, - "LLVM Object Reader\n"); + // Initialize targets. + llvm::InitializeAllTargetInfos(); - if (InputFilename.empty()) { - errs() << "Please specify an input filename\n"; - return 1; - } + // Register the target printer for --version. + cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); - // Open the object file - OwningPtr File; - if (MemoryBuffer::getFile(InputFilename, File)) { - errs() << InputFilename << ": Open failed\n"; - return 1; - } + cl::ParseCommandLineOptions(argc, argv, "LLVM Object Reader\n"); - OwningPtr o(ObjectFile::createObjectFile(File.take())); - ObjectFile *obj = o.get(); - if (!obj) { - errs() << InputFilename << ": Object type not recognized\n"; - } + // Default to stdin if no filename is specified. + if (opts::InputFilenames.size() == 0) + opts::InputFilenames.push_back("-"); - dumpHeaders(obj); - - 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"); - - outs() << "Sections:\n"; - dumpSectionHeader(); - dump(obj, &dumpSection, obj->begin_sections(), obj->end_sections(), - "Section iteration failed"); - - if (obj->isELF()) { - if (ErrorOr e = dumpELFDynamicTable(obj, outs())) - ; - else - errs() << "InputFilename" << ": " << error_code(e).message() << "\n"; - } - - outs() << "Libraries needed:\n"; - dump(obj, &dumpLibrary, obj->begin_libraries_needed(), - obj->end_libraries_needed(), "Needed libraries iteration failed"); + std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(), + dumpInput); return 0; } - diff --git a/tools/llvm-readobj/llvm-readobj.h b/tools/llvm-readobj/llvm-readobj.h index cf492b2a8da..be18268a7f6 100644 --- a/tools/llvm-readobj/llvm-readobj.h +++ b/tools/llvm-readobj/llvm-readobj.h @@ -1,4 +1,4 @@ -//===- llvm-readobj.h - Dump contents of an Object File -------------------===// +//===-- llvm-readobj.h ----------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -10,13 +10,36 @@ #ifndef LLVM_TOOLS_READ_OBJ_H #define LLVM_TOOLS_READ_OBJ_H -#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/CommandLine.h" +#include namespace llvm { -namespace object { class ObjectFile; } -class raw_ostream; + namespace object { + class RelocationRef; + } -ErrorOr 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 InputFilenames; + extern llvm::cl::opt FileHeaders; + extern llvm::cl::opt Sections; + extern llvm::cl::opt SectionRelocations; + extern llvm::cl::opt SectionSymbols; + extern llvm::cl::opt SectionData; + extern llvm::cl::opt Relocations; + extern llvm::cl::opt Symbols; + extern llvm::cl::opt DynamicSymbols; + extern llvm::cl::opt UnwindInfo; +} // namespace opts + +#define LLVM_READOBJ_ENUM_ENT(ns, enum) \ + { #enum, ns::enum } #endif