mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-11-01 00:11:00 +00:00
Implements low-level object file format specific output for COFF and
ELF with support for: - File headers - Section headers + data - Relocations - Symbols - Unwind data (only COFF/Win64) The output format follows a few rules: - Values are almost always output one per line (as elf-dump/coff-dump already do). - Many values are translated to something readable (like enum names), with the raw value in parentheses. - Hex numbers are output in uppercase, prefixed with "0x". - Flags are sorted alphabetically. - Lists and groups are always delimited. Example output: ---------- snip ---------- Sections [ Section { Index: 1 Name: .text (5) Type: SHT_PROGBITS (0x1) Flags [ (0x6) SHF_ALLOC (0x2) SHF_EXECINSTR (0x4) ] Address: 0x0 Offset: 0x40 Size: 33 Link: 0 Info: 0 AddressAlignment: 16 EntrySize: 0 Relocations [ 0x6 R_386_32 .rodata.str1.1 0x0 0xB R_386_PC32 puts 0x0 0x12 R_386_32 .rodata.str1.1 0x0 0x17 R_386_PC32 puts 0x0 ] SectionData ( 0000: 83EC04C7 04240000 0000E8FC FFFFFFC7 |.....$..........| 0010: 04240600 0000E8FC FFFFFF31 C083C404 |.$.........1....| 0020: C3 |.| ) } ] ---------- snip ---------- Relocations and symbols can be output standalone or together with the section header as displayed in the example. This feature set supports all tests in test/MC/COFF and test/MC/ELF (and I suspect all additional tests using elf-dump), making elf-dump and coff-dump deprecated. Patch by Nico Rieck! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@178679 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
99ff2ba240
commit
76e70f340c
@ -790,6 +790,7 @@ public:
|
||||
uint64_t getNumSections() const;
|
||||
uint64_t getStringTableIndex() const;
|
||||
ELF::Elf64_Word getSymbolTableIndex(const Elf_Sym *symb) const;
|
||||
const Elf_Ehdr *getElfHeader() const;
|
||||
const Elf_Shdr *getSection(const Elf_Sym *symb) const;
|
||||
const Elf_Shdr *getElfSection(section_iterator &It) const;
|
||||
const Elf_Sym *getElfSymbol(symbol_iterator &It) const;
|
||||
@ -968,6 +969,12 @@ ELFObjectFile<ELFT>::getSection(const Elf_Sym *symb) const {
|
||||
return getSection(symb->st_shndx);
|
||||
}
|
||||
|
||||
template<class ELFT>
|
||||
const typename ELFObjectFile<ELFT>::Elf_Ehdr *
|
||||
ELFObjectFile<ELFT>::getElfHeader() const {
|
||||
return Header;
|
||||
}
|
||||
|
||||
template<class ELFT>
|
||||
const typename ELFObjectFile<ELFT>::Elf_Shdr *
|
||||
ELFObjectFile<ELFT>::getElfSection(section_iterator &It) const {
|
||||
|
@ -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
|
||||
|
@ -106,12 +106,17 @@ struct UnwindInfo {
|
||||
return reinterpret_cast<void *>(&UnwindCodes[(NumCodes+1) & ~1]);
|
||||
}
|
||||
|
||||
/// \brief Return image-relativ offset of language-specific exception handler.
|
||||
uint32_t getLanguageSpecificHandlerOffset() {
|
||||
return *reinterpret_cast<uint32_t *>(getLanguageSpecificData());
|
||||
/// \brief Return pointer to language specific data part of UnwindInfo.
|
||||
const void *getLanguageSpecificData() const {
|
||||
return reinterpret_cast<const void *>(&UnwindCodes[(NumCodes+1) & ~1]);
|
||||
}
|
||||
|
||||
/// \brief 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<const uint32_t *>(getLanguageSpecificData());
|
||||
}
|
||||
|
||||
/// \brief Set image-relative offset of language-specific exception handler.
|
||||
void setLanguageSpecificHandlerOffset(uint32_t offset) {
|
||||
*reinterpret_cast<uint32_t *>(getLanguageSpecificData()) = offset;
|
||||
}
|
||||
@ -126,6 +131,11 @@ struct UnwindInfo {
|
||||
RuntimeFunction *getChainedFunctionEntry() {
|
||||
return reinterpret_cast<RuntimeFunction *>(getLanguageSpecificData());
|
||||
}
|
||||
|
||||
/// \brief Return pointer to chained unwind info.
|
||||
const RuntimeFunction *getChainedFunctionEntry() const {
|
||||
return reinterpret_cast<const RuntimeFunction *>(getLanguageSpecificData());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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: ]
|
||||
|
@ -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: ]
|
||||
|
19
test/tools/llvm-readobj/Inputs/trivial.ll
Normal file
19
test/tools/llvm-readobj/Inputs/trivial.ll
Normal file
@ -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(...)
|
BIN
test/tools/llvm-readobj/Inputs/trivial.obj.coff-i386
Normal file
BIN
test/tools/llvm-readobj/Inputs/trivial.obj.coff-i386
Normal file
Binary file not shown.
BIN
test/tools/llvm-readobj/Inputs/trivial.obj.coff-x86-64
Normal file
BIN
test/tools/llvm-readobj/Inputs/trivial.obj.coff-x86-64
Normal file
Binary file not shown.
BIN
test/tools/llvm-readobj/Inputs/trivial.obj.elf-i386
Normal file
BIN
test/tools/llvm-readobj/Inputs/trivial.obj.elf-i386
Normal file
Binary file not shown.
BIN
test/tools/llvm-readobj/Inputs/trivial.obj.elf-x86-64
Normal file
BIN
test/tools/llvm-readobj/Inputs/trivial.obj.elf-x86-64
Normal file
Binary file not shown.
BIN
test/tools/llvm-readobj/Inputs/trivial.obj.macho-i386
Normal file
BIN
test/tools/llvm-readobj/Inputs/trivial.obj.macho-i386
Normal file
Binary file not shown.
BIN
test/tools/llvm-readobj/Inputs/trivial.obj.macho-x86-64
Normal file
BIN
test/tools/llvm-readobj/Inputs/trivial.obj.macho-x86-64
Normal file
Binary file not shown.
100
test/tools/llvm-readobj/file-headers.test
Normal file
100
test/tools/llvm-readobj/file-headers.test
Normal file
@ -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: }
|
1
test/tools/llvm-readobj/lit.local.cfg
Normal file
1
test/tools/llvm-readobj/lit.local.cfg
Normal file
@ -0,0 +1 @@
|
||||
config.suffixes = ['.test']
|
32
test/tools/llvm-readobj/relocations.test
Normal file
32
test/tools/llvm-readobj/relocations.test
Normal file
@ -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: ]
|
175
test/tools/llvm-readobj/sections-ext.test
Normal file
175
test/tools/llvm-readobj/sections-ext.test
Normal file
@ -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: }
|
113
test/tools/llvm-readobj/sections.test
Normal file
113
test/tools/llvm-readobj/sections.test
Normal file
@ -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: }
|
44
test/tools/llvm-readobj/symbols.test
Normal file
44
test/tools/llvm-readobj/symbols.test
Normal file
@ -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: }
|
@ -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
|
||||
)
|
||||
|
1014
tools/llvm-readobj/COFFDumper.cpp
Normal file
1014
tools/llvm-readobj/COFFDumper.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,196 +0,0 @@
|
||||
//===- llvm-readobj/ELF.cpp - ELF Specific Dumper -------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm-readobj.h"
|
||||
|
||||
#include "llvm/Object/ELF.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
|
||||
namespace llvm {
|
||||
using namespace object;
|
||||
using namespace ELF;
|
||||
|
||||
const char *getTypeString(uint64_t Type) {
|
||||
switch (Type) {
|
||||
case DT_BIND_NOW:
|
||||
return "(BIND_NOW)";
|
||||
case DT_DEBUG:
|
||||
return "(DEBUG)";
|
||||
case DT_FINI:
|
||||
return "(FINI)";
|
||||
case DT_FINI_ARRAY:
|
||||
return "(FINI_ARRAY)";
|
||||
case DT_FINI_ARRAYSZ:
|
||||
return "(FINI_ARRAYSZ)";
|
||||
case DT_FLAGS:
|
||||
return "(FLAGS)";
|
||||
case DT_HASH:
|
||||
return "(HASH)";
|
||||
case DT_INIT:
|
||||
return "(INIT)";
|
||||
case DT_INIT_ARRAY:
|
||||
return "(INIT_ARRAY)";
|
||||
case DT_INIT_ARRAYSZ:
|
||||
return "(INIT_ARRAYSZ)";
|
||||
case DT_PREINIT_ARRAY:
|
||||
return "(PREINIT_ARRAY)";
|
||||
case DT_PREINIT_ARRAYSZ:
|
||||
return "(PREINIT_ARRAYSZ)";
|
||||
case DT_JMPREL:
|
||||
return "(JMPREL)";
|
||||
case DT_NEEDED:
|
||||
return "(NEEDED)";
|
||||
case DT_NULL:
|
||||
return "(NULL)";
|
||||
case DT_PLTGOT:
|
||||
return "(PLTGOT)";
|
||||
case DT_PLTREL:
|
||||
return "(PLTREL)";
|
||||
case DT_PLTRELSZ:
|
||||
return "(PLTRELSZ)";
|
||||
case DT_REL:
|
||||
return "(REL)";
|
||||
case DT_RELA:
|
||||
return "(RELA)";
|
||||
case DT_RELENT:
|
||||
return "(RELENT)";
|
||||
case DT_RELSZ:
|
||||
return "(RELSZ)";
|
||||
case DT_RELAENT:
|
||||
return "(RELAENT)";
|
||||
case DT_RELASZ:
|
||||
return "(RELASZ)";
|
||||
case DT_RPATH:
|
||||
return "(RPATH)";
|
||||
case DT_RUNPATH:
|
||||
return "(RUNPATH)";
|
||||
case DT_SONAME:
|
||||
return "(SONAME)";
|
||||
case DT_STRSZ:
|
||||
return "(STRSZ)";
|
||||
case DT_STRTAB:
|
||||
return "(STRTAB)";
|
||||
case DT_SYMBOLIC:
|
||||
return "(SYMBOLIC)";
|
||||
case DT_SYMENT:
|
||||
return "(SYMENT)";
|
||||
case DT_SYMTAB:
|
||||
return "(SYMTAB)";
|
||||
case DT_TEXTREL:
|
||||
return "(TEXTREL)";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void printValue(const ELFObjectFile<ELFT> *O, uint64_t Type, uint64_t Value,
|
||||
bool Is64, raw_ostream &OS) {
|
||||
switch (Type) {
|
||||
case DT_PLTREL:
|
||||
if (Value == DT_REL) {
|
||||
OS << "REL";
|
||||
break;
|
||||
} else if (Value == DT_RELA) {
|
||||
OS << "RELA";
|
||||
break;
|
||||
}
|
||||
// Fallthrough.
|
||||
case DT_PLTGOT:
|
||||
case DT_HASH:
|
||||
case DT_STRTAB:
|
||||
case DT_SYMTAB:
|
||||
case DT_RELA:
|
||||
case DT_INIT:
|
||||
case DT_FINI:
|
||||
case DT_REL:
|
||||
case DT_JMPREL:
|
||||
case DT_INIT_ARRAY:
|
||||
case DT_FINI_ARRAY:
|
||||
case DT_PREINIT_ARRAY:
|
||||
case DT_DEBUG:
|
||||
case DT_NULL:
|
||||
OS << format("0x%" PRIx64, Value);
|
||||
break;
|
||||
case DT_PLTRELSZ:
|
||||
case DT_RELASZ:
|
||||
case DT_RELAENT:
|
||||
case DT_STRSZ:
|
||||
case DT_SYMENT:
|
||||
case DT_RELSZ:
|
||||
case DT_RELENT:
|
||||
case DT_INIT_ARRAYSZ:
|
||||
case DT_FINI_ARRAYSZ:
|
||||
case DT_PREINIT_ARRAYSZ:
|
||||
OS << Value << " (bytes)";
|
||||
break;
|
||||
case DT_NEEDED:
|
||||
OS << "Shared library: ["
|
||||
<< O->getString(O->getDynamicStringTableSectionHeader(), Value) << "]";
|
||||
break;
|
||||
case DT_SONAME:
|
||||
OS << "Library soname: ["
|
||||
<< O->getString(O->getDynamicStringTableSectionHeader(), Value) << "]";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
ErrorOr<void> dumpDynamicTable(const ELFObjectFile<ELFT> *O, raw_ostream &OS) {
|
||||
typedef ELFObjectFile<ELFT> ELFO;
|
||||
typedef typename ELFO::Elf_Dyn_iterator EDI;
|
||||
EDI Start = O->begin_dynamic_table(),
|
||||
End = O->end_dynamic_table(true);
|
||||
|
||||
if (Start == End)
|
||||
return error_code::success();
|
||||
|
||||
ptrdiff_t Total = std::distance(Start, End);
|
||||
OS << "Dynamic section contains " << Total << " entries\n";
|
||||
|
||||
bool Is64 = O->getBytesInAddress() == 8;
|
||||
|
||||
OS << " Tag" << (Is64 ? " " : " ") << "Type"
|
||||
<< " " << "Name/Value\n";
|
||||
for (; Start != End; ++Start) {
|
||||
OS << " "
|
||||
<< format(Is64 ? "0x%016" PRIx64 : "0x%08" PRIx64, Start->getTag())
|
||||
<< " " << format("%-21s", getTypeString(Start->getTag()));
|
||||
printValue(O, Start->getTag(), Start->getVal(), Is64, OS);
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
OS << " Total: " << Total << "\n\n";
|
||||
return error_code::success();
|
||||
}
|
||||
|
||||
ErrorOr<void> dumpELFDynamicTable(ObjectFile *O, raw_ostream &OS) {
|
||||
// Little-endian 32-bit
|
||||
if (const ELFObjectFile<ELFType<support::little, 4, false> > *ELFObj =
|
||||
dyn_cast<ELFObjectFile<ELFType<support::little, 4, false> > >(O))
|
||||
return dumpDynamicTable(ELFObj, OS);
|
||||
|
||||
// Big-endian 32-bit
|
||||
if (const ELFObjectFile<ELFType<support::big, 4, false> > *ELFObj =
|
||||
dyn_cast<ELFObjectFile<ELFType<support::big, 4, false> > >(O))
|
||||
return dumpDynamicTable(ELFObj, OS);
|
||||
|
||||
// Little-endian 64-bit
|
||||
if (const ELFObjectFile<ELFType<support::little, 8, true> > *ELFObj =
|
||||
dyn_cast<ELFObjectFile<ELFType<support::little, 8, true> > >(O))
|
||||
return dumpDynamicTable(ELFObj, OS);
|
||||
|
||||
// Big-endian 64-bit
|
||||
if (const ELFObjectFile<ELFType<support::big, 8, true> > *ELFObj =
|
||||
dyn_cast<ELFObjectFile<ELFType<support::big, 8, true> > >(O))
|
||||
return dumpDynamicTable(ELFObj, OS);
|
||||
return error_code(object_error::invalid_file_type);
|
||||
}
|
||||
} // end namespace llvm
|
800
tools/llvm-readobj/ELFDumper.cpp
Normal file
800
tools/llvm-readobj/ELFDumper.cpp
Normal file
@ -0,0 +1,800 @@
|
||||
//===-- ELFDumper.cpp - ELF-specific dumper ---------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief This file implements the ELF-specific dumper for llvm-readobj.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm-readobj.h"
|
||||
#include "Error.h"
|
||||
#include "ObjDumper.h"
|
||||
#include "StreamWriter.h"
|
||||
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Object/ELF.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::object;
|
||||
using namespace ELF;
|
||||
|
||||
|
||||
#define LLVM_READOBJ_ENUM_CASE(ns, enum) \
|
||||
case ns::enum: return #enum;
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename ELFT>
|
||||
class ELFDumper : public ObjDumper {
|
||||
public:
|
||||
ELFDumper(const ELFObjectFile<ELFT> *Obj, StreamWriter& Writer)
|
||||
: ObjDumper(Writer)
|
||||
, Obj(Obj) { }
|
||||
|
||||
virtual void printFileHeaders() LLVM_OVERRIDE;
|
||||
virtual void printSections() LLVM_OVERRIDE;
|
||||
virtual void printRelocations() LLVM_OVERRIDE;
|
||||
virtual void printSymbols() LLVM_OVERRIDE;
|
||||
virtual void printDynamicSymbols() LLVM_OVERRIDE;
|
||||
virtual void printUnwindInfo() LLVM_OVERRIDE;
|
||||
|
||||
virtual void printDynamicTable() LLVM_OVERRIDE;
|
||||
virtual void printNeededLibraries() LLVM_OVERRIDE;
|
||||
|
||||
private:
|
||||
typedef typename ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr;
|
||||
typedef typename ELFObjectFile<ELFT>::Elf_Sym Elf_Sym;
|
||||
|
||||
void printSymbol(symbol_iterator SymI, bool IsDynamic = false);
|
||||
|
||||
void printRelocation(section_iterator SecI, relocation_iterator RelI);
|
||||
|
||||
const ELFObjectFile<ELFT> *Obj;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
namespace llvm {
|
||||
|
||||
error_code createELFDumper(const object::ObjectFile *Obj,
|
||||
StreamWriter& Writer,
|
||||
OwningPtr<ObjDumper> &Result) {
|
||||
typedef ELFType<support::little, 4, false> Little32ELF;
|
||||
typedef ELFType<support::big, 4, false> Big32ELF;
|
||||
typedef ELFType<support::little, 4, true > Little64ELF;
|
||||
typedef ELFType<support::big, 8, true > Big64ELF;
|
||||
|
||||
typedef ELFObjectFile<Little32ELF> LittleELF32Obj;
|
||||
typedef ELFObjectFile<Big32ELF > BigELF32Obj;
|
||||
typedef ELFObjectFile<Little64ELF> LittleELF64Obj;
|
||||
typedef ELFObjectFile<Big64ELF > BigELF64Obj;
|
||||
|
||||
// Little-endian 32-bit
|
||||
if (const LittleELF32Obj *ELFObj = dyn_cast<LittleELF32Obj>(Obj)) {
|
||||
Result.reset(new ELFDumper<Little32ELF>(ELFObj, Writer));
|
||||
return readobj_error::success;
|
||||
}
|
||||
|
||||
// Big-endian 32-bit
|
||||
if (const BigELF32Obj *ELFObj = dyn_cast<BigELF32Obj>(Obj)) {
|
||||
Result.reset(new ELFDumper<Big32ELF>(ELFObj, Writer));
|
||||
return readobj_error::success;
|
||||
}
|
||||
|
||||
// Little-endian 64-bit
|
||||
if (const LittleELF64Obj *ELFObj = dyn_cast<LittleELF64Obj>(Obj)) {
|
||||
Result.reset(new ELFDumper<Little64ELF>(ELFObj, Writer));
|
||||
return readobj_error::success;
|
||||
}
|
||||
|
||||
// Big-endian 64-bit
|
||||
if (const BigELF64Obj *ELFObj = dyn_cast<BigELF64Obj>(Obj)) {
|
||||
Result.reset(new ELFDumper<Big64ELF>(ELFObj, Writer));
|
||||
return readobj_error::success;
|
||||
}
|
||||
|
||||
return readobj_error::unsupported_obj_file_format;
|
||||
}
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
|
||||
static const EnumEntry<unsigned> ElfClass[] = {
|
||||
{ "None", ELF::ELFCLASSNONE },
|
||||
{ "32-bit", ELF::ELFCLASS32 },
|
||||
{ "64-bit", ELF::ELFCLASS64 },
|
||||
};
|
||||
|
||||
static const EnumEntry<unsigned> ElfDataEncoding[] = {
|
||||
{ "None", ELF::ELFDATANONE },
|
||||
{ "LittleEndian", ELF::ELFDATA2LSB },
|
||||
{ "BigEndian", ELF::ELFDATA2MSB },
|
||||
};
|
||||
|
||||
static const EnumEntry<unsigned> ElfObjectFileType[] = {
|
||||
{ "None", ELF::ET_NONE },
|
||||
{ "Relocatable", ELF::ET_REL },
|
||||
{ "Executable", ELF::ET_EXEC },
|
||||
{ "SharedObject", ELF::ET_DYN },
|
||||
{ "Core", ELF::ET_CORE },
|
||||
};
|
||||
|
||||
static const EnumEntry<unsigned> ElfOSABI[] = {
|
||||
{ "SystemV", ELF::ELFOSABI_NONE },
|
||||
{ "HPUX", ELF::ELFOSABI_HPUX },
|
||||
{ "NetBSD", ELF::ELFOSABI_NETBSD },
|
||||
{ "GNU/Linux", ELF::ELFOSABI_LINUX },
|
||||
{ "GNU/Hurd", ELF::ELFOSABI_HURD },
|
||||
{ "Solaris", ELF::ELFOSABI_SOLARIS },
|
||||
{ "AIX", ELF::ELFOSABI_AIX },
|
||||
{ "IRIX", ELF::ELFOSABI_IRIX },
|
||||
{ "FreeBSD", ELF::ELFOSABI_FREEBSD },
|
||||
{ "TRU64", ELF::ELFOSABI_TRU64 },
|
||||
{ "Modesto", ELF::ELFOSABI_MODESTO },
|
||||
{ "OpenBSD", ELF::ELFOSABI_OPENBSD },
|
||||
{ "OpenVMS", ELF::ELFOSABI_OPENVMS },
|
||||
{ "NSK", ELF::ELFOSABI_NSK },
|
||||
{ "AROS", ELF::ELFOSABI_AROS },
|
||||
{ "FenixOS", ELF::ELFOSABI_FENIXOS },
|
||||
{ "C6000_ELFABI", ELF::ELFOSABI_C6000_ELFABI },
|
||||
{ "C6000_LINUX" , ELF::ELFOSABI_C6000_LINUX },
|
||||
{ "ARM", ELF::ELFOSABI_ARM },
|
||||
{ "Standalone" , ELF::ELFOSABI_STANDALONE }
|
||||
};
|
||||
|
||||
static const EnumEntry<unsigned> ElfMachineType[] = {
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_NONE ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_M32 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARC ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_386 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_68K ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_88K ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_486 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_860 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_S370 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS_RS3_LE ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_PARISC ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_VPP500 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARC32PLUS ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_960 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_PPC ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_PPC64 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_S390 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_SPU ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_V800 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_FR20 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_RH32 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_RCE ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ARM ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ALPHA ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_SH ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARCV9 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_TRICORE ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_300 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_300H ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_H8S ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_500 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_IA_64 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS_X ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_COLDFIRE ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC12 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_MMA ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_PCP ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_NCPU ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_NDR1 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_STARCORE ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ME16 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ST100 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_TINYJ ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_X86_64 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_PDSP ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_PDP10 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_PDP11 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_FX66 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ST9PLUS ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ST7 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC16 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC11 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC08 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC05 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_SVX ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ST19 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_VAX ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_CRIS ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_JAVELIN ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_FIREPATH ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ZSP ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_MMIX ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_HUANY ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_PRISM ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_AVR ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_FR30 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_D10V ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_D30V ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_V850 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_M32R ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_MN10300 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_MN10200 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_PJ ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_OPENRISC ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC_COMPACT ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_XTENSA ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_TMM_GPP ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_NS32K ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_TPC ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_SNP1K ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ST200 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_IP2K ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_MAX ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_CR ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_F2MC16 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_MSP430 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_BLACKFIN ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_SE_C33 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_SEP ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ARCA ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_UNICORE ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_EXCESS ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_DXP ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ALTERA_NIOS2 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_CRX ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_XGATE ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_C166 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_M16C ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_DSPIC30F ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_CE ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_M32C ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_TSK3000 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_RS08 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_SHARC ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG2 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_SCORE7 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_DSP24 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE3 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_LATTICEMICO32),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_SE_C17 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C6000 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C2000 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C5500 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_MMDSP_PLUS ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_CYPRESS_M8C ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_R32C ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_TRIMEDIA ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_HEXAGON ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_8051 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_STXP7X ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_NDS32 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG1 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG1X ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_MAXQ30 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_XIMO16 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_MANIK ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_CRAYNV2 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_RX ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_METAG ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_MCST_ELBRUS ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG16 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_CR16 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ETPU ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_SLE9X ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_L10M ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_K10M ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_AARCH64 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_AVR32 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_STM8 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_TILE64 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_TILEPRO ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_MICROBLAZE ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_CUDA ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_TILEGX ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_CLOUDSHIELD ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_COREA_1ST ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_COREA_2ND ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC_COMPACT2 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_OPEN8 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_RL78 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE5 ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_78KOR ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_56800EX ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, EM_MBLAZE )
|
||||
};
|
||||
|
||||
static const EnumEntry<unsigned> ElfSymbolBindings[] = {
|
||||
{ "Local", ELF::STB_LOCAL },
|
||||
{ "Global", ELF::STB_GLOBAL },
|
||||
{ "Weak", ELF::STB_WEAK }
|
||||
};
|
||||
|
||||
static const EnumEntry<unsigned> ElfSymbolTypes[] = {
|
||||
{ "None", ELF::STT_NOTYPE },
|
||||
{ "Object", ELF::STT_OBJECT },
|
||||
{ "Function", ELF::STT_FUNC },
|
||||
{ "Section", ELF::STT_SECTION },
|
||||
{ "File", ELF::STT_FILE },
|
||||
{ "Common", ELF::STT_COMMON },
|
||||
{ "TLS", ELF::STT_TLS },
|
||||
{ "GNU_IFunc", ELF::STT_GNU_IFUNC }
|
||||
};
|
||||
|
||||
static const char *getElfSectionType(unsigned Arch, unsigned Type) {
|
||||
switch (Arch) {
|
||||
case Triple::arm:
|
||||
switch (Type) {
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_EXIDX);
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_PREEMPTMAP);
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_ATTRIBUTES);
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_DEBUGOVERLAY);
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_OVERLAYSECTION);
|
||||
}
|
||||
case Triple::hexagon:
|
||||
switch (Type) {
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_HEX_ORDERED);
|
||||
}
|
||||
case Triple::x86_64:
|
||||
switch (Type) {
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_X86_64_UNWIND);
|
||||
}
|
||||
case Triple::mips:
|
||||
case Triple::mipsel:
|
||||
switch (Type) {
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_REGINFO);
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
switch (Type) {
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_NULL );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_PROGBITS );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_SYMTAB );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_STRTAB );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_RELA );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_HASH );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_DYNAMIC );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_NOTE );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_NOBITS );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_REL );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_SHLIB );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_DYNSYM );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_INIT_ARRAY );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_FINI_ARRAY );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_PREINIT_ARRAY );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_GROUP );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_SYMTAB_SHNDX );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_HASH );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_verdef );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_verneed );
|
||||
LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_versym );
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
static const EnumEntry<unsigned> ElfSectionFlags[] = {
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, SHF_WRITE ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, SHF_ALLOC ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, SHF_EXECINSTR ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, SHF_MERGE ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, SHF_STRINGS ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, SHF_INFO_LINK ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, SHF_LINK_ORDER ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, SHF_OS_NONCONFORMING),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, SHF_GROUP ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, SHF_TLS ),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_CP_SECTION),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_DP_SECTION),
|
||||
LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NOSTRIP )
|
||||
};
|
||||
|
||||
|
||||
template<class ELFT>
|
||||
void ELFDumper<ELFT>::printFileHeaders() {
|
||||
error_code EC;
|
||||
typedef ELFObjectFile<ELFT> ELFO;
|
||||
|
||||
const typename ELFO::Elf_Ehdr *Header = Obj->getElfHeader();
|
||||
|
||||
{
|
||||
DictScope D(W, "ElfHeader");
|
||||
{
|
||||
DictScope D(W, "Ident");
|
||||
W.printBinary("Magic", makeArrayRef(Header->e_ident).slice(ELF::EI_MAG0,
|
||||
4));
|
||||
W.printEnum ("Class", Header->e_ident[ELF::EI_CLASS],
|
||||
makeArrayRef(ElfClass));
|
||||
W.printEnum ("DataEncoding", Header->e_ident[ELF::EI_DATA],
|
||||
makeArrayRef(ElfDataEncoding));
|
||||
W.printNumber("FileVersion", Header->e_ident[ELF::EI_VERSION]);
|
||||
W.printEnum ("OS/ABI", Header->e_ident[ELF::EI_OSABI],
|
||||
makeArrayRef(ElfOSABI));
|
||||
W.printNumber("ABIVersion", Header->e_ident[ELF::EI_ABIVERSION]);
|
||||
W.printBinary("Unused", makeArrayRef(Header->e_ident).slice(ELF::EI_PAD));
|
||||
}
|
||||
|
||||
W.printEnum ("Type", Header->e_type, makeArrayRef(ElfObjectFileType));
|
||||
W.printEnum ("Machine", Header->e_machine, makeArrayRef(ElfMachineType));
|
||||
W.printNumber("Version", Header->e_version);
|
||||
W.printHex ("Entry", Header->e_entry);
|
||||
W.printHex ("ProgramHeaderOffset", Header->e_phoff);
|
||||
W.printHex ("SectionHeaderOffset", Header->e_shoff);
|
||||
W.printFlags ("Flags", Header->e_flags);
|
||||
W.printNumber("HeaderSize", Header->e_ehsize);
|
||||
W.printNumber("ProgramHeaderEntrySize", Header->e_phentsize);
|
||||
W.printNumber("ProgramHeaderCount", Header->e_phnum);
|
||||
W.printNumber("SectionHeaderEntrySize", Header->e_shentsize);
|
||||
W.printNumber("SectionHeaderCount", Header->e_shnum);
|
||||
W.printNumber("StringTableSectionIndex", Header->e_shstrndx);
|
||||
}
|
||||
}
|
||||
|
||||
template<class ELFT>
|
||||
void ELFDumper<ELFT>::printSections() {
|
||||
ListScope SectionsD(W, "Sections");
|
||||
|
||||
int SectionIndex = -1;
|
||||
error_code EC;
|
||||
for (section_iterator SecI = Obj->begin_sections(),
|
||||
SecE = Obj->end_sections();
|
||||
SecI != SecE; SecI.increment(EC)) {
|
||||
if (error(EC)) break;
|
||||
|
||||
++SectionIndex;
|
||||
|
||||
const Elf_Shdr *Section = Obj->getElfSection(SecI);
|
||||
StringRef Name;
|
||||
if (error(SecI->getName(Name)))
|
||||
Name = "";
|
||||
|
||||
DictScope SectionD(W, "Section");
|
||||
W.printNumber("Index", SectionIndex);
|
||||
W.printNumber("Name", Name, Section->sh_name);
|
||||
W.printHex ("Type", getElfSectionType(Obj->getArch(), Section->sh_type),
|
||||
Section->sh_type);
|
||||
W.printFlags ("Flags", Section->sh_flags, makeArrayRef(ElfSectionFlags));
|
||||
W.printHex ("Address", Section->sh_addr);
|
||||
W.printHex ("Offset", Section->sh_offset);
|
||||
W.printNumber("Size", Section->sh_size);
|
||||
W.printNumber("Link", Section->sh_link);
|
||||
W.printNumber("Info", Section->sh_info);
|
||||
W.printNumber("AddressAlignment", Section->sh_addralign);
|
||||
W.printNumber("EntrySize", Section->sh_entsize);
|
||||
|
||||
if (opts::SectionRelocations) {
|
||||
ListScope D(W, "Relocations");
|
||||
for (relocation_iterator RelI = SecI->begin_relocations(),
|
||||
RelE = SecI->end_relocations();
|
||||
RelI != RelE; RelI.increment(EC)) {
|
||||
if (error(EC)) break;
|
||||
|
||||
printRelocation(SecI, RelI);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts::SectionSymbols) {
|
||||
ListScope D(W, "Symbols");
|
||||
for (symbol_iterator SymI = Obj->begin_symbols(),
|
||||
SymE = Obj->end_symbols();
|
||||
SymI != SymE; SymI.increment(EC)) {
|
||||
if (error(EC)) break;
|
||||
|
||||
bool Contained = false;
|
||||
if (SecI->containsSymbol(*SymI, Contained) || !Contained)
|
||||
continue;
|
||||
|
||||
printSymbol(SymI);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts::SectionData) {
|
||||
StringRef Data;
|
||||
if (error(SecI->getContents(Data))) break;
|
||||
|
||||
W.printBinaryBlock("SectionData", Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class ELFT>
|
||||
void ELFDumper<ELFT>::printRelocations() {
|
||||
ListScope D(W, "Relocations");
|
||||
|
||||
error_code EC;
|
||||
int SectionNumber = -1;
|
||||
for (section_iterator SecI = Obj->begin_sections(),
|
||||
SecE = Obj->end_sections();
|
||||
SecI != SecE; SecI.increment(EC)) {
|
||||
if (error(EC)) break;
|
||||
|
||||
++SectionNumber;
|
||||
StringRef Name;
|
||||
if (error(SecI->getName(Name)))
|
||||
continue;
|
||||
|
||||
bool PrintedGroup = false;
|
||||
for (relocation_iterator RelI = SecI->begin_relocations(),
|
||||
RelE = SecI->end_relocations();
|
||||
RelI != RelE; RelI.increment(EC)) {
|
||||
if (error(EC)) break;
|
||||
|
||||
if (!PrintedGroup) {
|
||||
W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n";
|
||||
W.indent();
|
||||
PrintedGroup = true;
|
||||
}
|
||||
|
||||
printRelocation(SecI, RelI);
|
||||
}
|
||||
|
||||
if (PrintedGroup) {
|
||||
W.unindent();
|
||||
W.startLine() << "}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class ELFT>
|
||||
void ELFDumper<ELFT>::printRelocation(section_iterator Sec,
|
||||
relocation_iterator RelI) {
|
||||
uint64_t Offset;
|
||||
SmallString<32> RelocName;
|
||||
int64_t Info;
|
||||
StringRef SymbolName;
|
||||
SymbolRef Symbol;
|
||||
if (error(RelI->getOffset(Offset))) return;
|
||||
if (error(RelI->getTypeName(RelocName))) return;
|
||||
if (error(RelI->getAdditionalInfo(Info))) return;
|
||||
if (error(RelI->getSymbol(Symbol))) return;
|
||||
if (error(Symbol.getName(SymbolName))) return;
|
||||
|
||||
raw_ostream& OS = W.startLine();
|
||||
OS << W.hex(Offset)
|
||||
<< " " << RelocName
|
||||
<< " " << (SymbolName.size() > 0 ? SymbolName : "-")
|
||||
<< " " << W.hex(Info)
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
template<class ELFT>
|
||||
void ELFDumper<ELFT>::printSymbols() {
|
||||
ListScope Group(W, "Symbols");
|
||||
|
||||
error_code EC;
|
||||
for (symbol_iterator SymI = Obj->begin_symbols(), SymE = Obj->end_symbols();
|
||||
SymI != SymE; SymI.increment(EC)) {
|
||||
if (error(EC)) break;
|
||||
|
||||
printSymbol(SymI);
|
||||
}
|
||||
}
|
||||
|
||||
template<class ELFT>
|
||||
void ELFDumper<ELFT>::printDynamicSymbols() {
|
||||
ListScope Group(W, "DynamicSymbols");
|
||||
|
||||
error_code EC;
|
||||
for (symbol_iterator SymI = Obj->begin_dynamic_symbols(),
|
||||
SymE = Obj->end_dynamic_symbols();
|
||||
SymI != SymE; SymI.increment(EC)) {
|
||||
if (error(EC)) break;
|
||||
|
||||
printSymbol(SymI, true);
|
||||
}
|
||||
}
|
||||
|
||||
template<class ELFT>
|
||||
void ELFDumper<ELFT>::printSymbol(symbol_iterator SymI, bool IsDynamic) {
|
||||
error_code EC;
|
||||
|
||||
const Elf_Sym *Symbol = Obj->getElfSymbol(SymI);
|
||||
const Elf_Shdr *Section = Obj->getSection(Symbol);
|
||||
|
||||
StringRef SymbolName;
|
||||
if (SymI->getName(SymbolName))
|
||||
SymbolName = "";
|
||||
|
||||
StringRef SectionName;
|
||||
if (Section && Obj->getSectionName(Section, SectionName))
|
||||
SectionName = "";
|
||||
|
||||
std::string FullSymbolName(SymbolName);
|
||||
if (IsDynamic) {
|
||||
StringRef Version;
|
||||
bool IsDefault;
|
||||
if (error(Obj->getSymbolVersion(*SymI, Version, IsDefault)))
|
||||
return;
|
||||
if (!Version.empty()) {
|
||||
FullSymbolName += (IsDefault ? "@@" : "@");
|
||||
FullSymbolName += Version;
|
||||
}
|
||||
}
|
||||
|
||||
DictScope D(W, "Symbol");
|
||||
W.printNumber("Name", FullSymbolName, Symbol->st_name);
|
||||
W.printHex ("Value", Symbol->st_value);
|
||||
W.printNumber("Size", Symbol->st_size);
|
||||
W.printEnum ("Binding", Symbol->getBinding(),
|
||||
makeArrayRef(ElfSymbolBindings));
|
||||
W.printEnum ("Type", Symbol->getType(), makeArrayRef(ElfSymbolTypes));
|
||||
W.printNumber("Other", Symbol->st_other);
|
||||
W.printHex ("Section", SectionName, Symbol->st_shndx);
|
||||
}
|
||||
|
||||
#define LLVM_READOBJ_TYPE_CASE(name) \
|
||||
case DT_##name: return #name
|
||||
|
||||
static const char *getTypeString(uint64_t Type) {
|
||||
switch (Type) {
|
||||
LLVM_READOBJ_TYPE_CASE(BIND_NOW);
|
||||
LLVM_READOBJ_TYPE_CASE(DEBUG);
|
||||
LLVM_READOBJ_TYPE_CASE(FINI);
|
||||
LLVM_READOBJ_TYPE_CASE(FINI_ARRAY);
|
||||
LLVM_READOBJ_TYPE_CASE(FINI_ARRAYSZ);
|
||||
LLVM_READOBJ_TYPE_CASE(FLAGS);
|
||||
LLVM_READOBJ_TYPE_CASE(HASH);
|
||||
LLVM_READOBJ_TYPE_CASE(INIT);
|
||||
LLVM_READOBJ_TYPE_CASE(INIT_ARRAY);
|
||||
LLVM_READOBJ_TYPE_CASE(INIT_ARRAYSZ);
|
||||
LLVM_READOBJ_TYPE_CASE(PREINIT_ARRAY);
|
||||
LLVM_READOBJ_TYPE_CASE(PREINIT_ARRAYSZ);
|
||||
LLVM_READOBJ_TYPE_CASE(JMPREL);
|
||||
LLVM_READOBJ_TYPE_CASE(NEEDED);
|
||||
LLVM_READOBJ_TYPE_CASE(NULL);
|
||||
LLVM_READOBJ_TYPE_CASE(PLTGOT);
|
||||
LLVM_READOBJ_TYPE_CASE(PLTREL);
|
||||
LLVM_READOBJ_TYPE_CASE(PLTRELSZ);
|
||||
LLVM_READOBJ_TYPE_CASE(REL);
|
||||
LLVM_READOBJ_TYPE_CASE(RELA);
|
||||
LLVM_READOBJ_TYPE_CASE(RELENT);
|
||||
LLVM_READOBJ_TYPE_CASE(RELSZ);
|
||||
LLVM_READOBJ_TYPE_CASE(RELAENT);
|
||||
LLVM_READOBJ_TYPE_CASE(RELASZ);
|
||||
LLVM_READOBJ_TYPE_CASE(RPATH);
|
||||
LLVM_READOBJ_TYPE_CASE(RUNPATH);
|
||||
LLVM_READOBJ_TYPE_CASE(SONAME);
|
||||
LLVM_READOBJ_TYPE_CASE(STRSZ);
|
||||
LLVM_READOBJ_TYPE_CASE(STRTAB);
|
||||
LLVM_READOBJ_TYPE_CASE(SYMBOLIC);
|
||||
LLVM_READOBJ_TYPE_CASE(SYMENT);
|
||||
LLVM_READOBJ_TYPE_CASE(SYMTAB);
|
||||
LLVM_READOBJ_TYPE_CASE(TEXTREL);
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
#undef LLVM_READOBJ_TYPE_CASE
|
||||
|
||||
template<class ELFT>
|
||||
static void printValue(const ELFObjectFile<ELFT> *O, uint64_t Type,
|
||||
uint64_t Value, bool Is64, raw_ostream &OS) {
|
||||
switch (Type) {
|
||||
case DT_PLTREL:
|
||||
if (Value == DT_REL) {
|
||||
OS << "REL";
|
||||
break;
|
||||
} else if (Value == DT_RELA) {
|
||||
OS << "RELA";
|
||||
break;
|
||||
}
|
||||
// Fallthrough.
|
||||
case DT_PLTGOT:
|
||||
case DT_HASH:
|
||||
case DT_STRTAB:
|
||||
case DT_SYMTAB:
|
||||
case DT_RELA:
|
||||
case DT_INIT:
|
||||
case DT_FINI:
|
||||
case DT_REL:
|
||||
case DT_JMPREL:
|
||||
case DT_INIT_ARRAY:
|
||||
case DT_FINI_ARRAY:
|
||||
case DT_PREINIT_ARRAY:
|
||||
case DT_DEBUG:
|
||||
case DT_NULL:
|
||||
OS << format("0x%" PRIX64, Value);
|
||||
break;
|
||||
case DT_PLTRELSZ:
|
||||
case DT_RELASZ:
|
||||
case DT_RELAENT:
|
||||
case DT_STRSZ:
|
||||
case DT_SYMENT:
|
||||
case DT_RELSZ:
|
||||
case DT_RELENT:
|
||||
case DT_INIT_ARRAYSZ:
|
||||
case DT_FINI_ARRAYSZ:
|
||||
case DT_PREINIT_ARRAYSZ:
|
||||
OS << Value << " (bytes)";
|
||||
break;
|
||||
case DT_NEEDED:
|
||||
OS << "SharedLibrary ("
|
||||
<< O->getString(O->getDynamicStringTableSectionHeader(), Value) << ")";
|
||||
break;
|
||||
case DT_SONAME:
|
||||
OS << "LibrarySoname ("
|
||||
<< O->getString(O->getDynamicStringTableSectionHeader(), Value) << ")";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<class ELFT>
|
||||
void ELFDumper<ELFT>::printUnwindInfo() {
|
||||
W.startLine() << "UnwindInfo not implemented.\n";
|
||||
}
|
||||
|
||||
template<class ELFT>
|
||||
void ELFDumper<ELFT>::printDynamicTable() {
|
||||
typedef ELFObjectFile<ELFT> ELFO;
|
||||
typedef typename ELFO::Elf_Dyn_iterator EDI;
|
||||
EDI Start = Obj->begin_dynamic_table(),
|
||||
End = Obj->end_dynamic_table(true);
|
||||
|
||||
if (Start == End)
|
||||
return;
|
||||
|
||||
ptrdiff_t Total = std::distance(Start, End);
|
||||
raw_ostream &OS = W.getOStream();
|
||||
W.startLine() << "DynamicSection [ (" << Total << " entries)\n";
|
||||
|
||||
bool Is64 = Obj->getBytesInAddress() == 8;
|
||||
|
||||
W.startLine()
|
||||
<< " Tag" << (Is64 ? " " : " ") << "Type"
|
||||
<< " " << "Name/Value\n";
|
||||
for (; Start != End; ++Start) {
|
||||
W.startLine()
|
||||
<< " "
|
||||
<< format(Is64 ? "0x%016" PRIX64 : "0x%08" PRIX64, Start->getTag())
|
||||
<< " " << format("%-21s", getTypeString(Start->getTag()));
|
||||
printValue(Obj, Start->getTag(), Start->getVal(), Is64, OS);
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
W.startLine() << "]\n";
|
||||
}
|
||||
|
||||
static bool compareLibraryName(const LibraryRef &L, const LibraryRef &R) {
|
||||
StringRef LPath, RPath;
|
||||
L.getPath(LPath);
|
||||
R.getPath(RPath);
|
||||
return LPath < RPath;
|
||||
}
|
||||
|
||||
template<class ELFT>
|
||||
void ELFDumper<ELFT>::printNeededLibraries() {
|
||||
ListScope D(W, "NeededLibraries");
|
||||
|
||||
error_code EC;
|
||||
|
||||
typedef std::vector<LibraryRef> LibsTy;
|
||||
LibsTy Libs;
|
||||
|
||||
for (library_iterator I = Obj->begin_libraries_needed(),
|
||||
E = Obj->end_libraries_needed();
|
||||
I != E; I.increment(EC)) {
|
||||
if (EC)
|
||||
report_fatal_error("Needed libraries iteration failed");
|
||||
|
||||
Libs.push_back(*I);
|
||||
}
|
||||
|
||||
std::sort(Libs.begin(), Libs.end(), &compareLibraryName);
|
||||
|
||||
for (LibsTy::const_iterator I = Libs.begin(), E = Libs.end();
|
||||
I != E; ++I) {
|
||||
StringRef Path;
|
||||
I->getPath(Path);
|
||||
outs() << " " << Path << "\n";
|
||||
}
|
||||
}
|
62
tools/llvm-readobj/Error.cpp
Normal file
62
tools/llvm-readobj/Error.cpp
Normal file
@ -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
|
48
tools/llvm-readobj/Error.h
Normal file
48
tools/llvm-readobj/Error.h
Normal file
@ -0,0 +1,48 @@
|
||||
//===- Error.h - system_error extensions for llvm-readobj -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This declares a new error_category for the llvm-readobj tool.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_READOBJ_ERROR_H
|
||||
#define LLVM_READOBJ_ERROR_H
|
||||
|
||||
#include "llvm/Support/system_error.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
const error_category &readobj_category();
|
||||
|
||||
struct readobj_error {
|
||||
enum _ {
|
||||
success = 0,
|
||||
file_not_found,
|
||||
unsupported_file_format,
|
||||
unrecognized_file_format,
|
||||
unsupported_obj_file_format,
|
||||
unknown_symbol
|
||||
};
|
||||
_ v_;
|
||||
|
||||
readobj_error(_ v) : v_(v) {}
|
||||
explicit readobj_error(int v) : v_(_(v)) {}
|
||||
operator int() const {return v_;}
|
||||
};
|
||||
|
||||
inline error_code make_error_code(readobj_error e) {
|
||||
return error_code(static_cast<int>(e), readobj_category());
|
||||
}
|
||||
|
||||
template <> struct is_error_code_enum<readobj_error> : true_type { };
|
||||
template <> struct is_error_code_enum<readobj_error::_> : true_type { };
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
@ -19,4 +19,4 @@
|
||||
type = Tool
|
||||
name = llvm-readobj
|
||||
parent = Tools
|
||||
required_libraries = Archive BitReader Object
|
||||
required_libraries = all-targets Archive BitReader Object
|
||||
|
438
tools/llvm-readobj/MachODumper.cpp
Normal file
438
tools/llvm-readobj/MachODumper.cpp
Normal file
@ -0,0 +1,438 @@
|
||||
//===-- MachODump.cpp - Object file dumping utility for llvm --------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the MachO-specific dumper for llvm-readobj.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm-readobj.h"
|
||||
#include "Error.h"
|
||||
#include "ObjDumper.h"
|
||||
#include "StreamWriter.h"
|
||||
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Object/MachO.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace object;
|
||||
|
||||
namespace {
|
||||
|
||||
class MachODumper : public ObjDumper {
|
||||
public:
|
||||
MachODumper(const llvm::object::MachOObjectFile *Obj, StreamWriter& Writer)
|
||||
: ObjDumper(Writer)
|
||||
, Obj(Obj) { }
|
||||
|
||||
virtual void printFileHeaders() LLVM_OVERRIDE;
|
||||
virtual void printSections() LLVM_OVERRIDE;
|
||||
virtual void printRelocations() LLVM_OVERRIDE;
|
||||
virtual void printSymbols() LLVM_OVERRIDE;
|
||||
virtual void printDynamicSymbols() LLVM_OVERRIDE;
|
||||
virtual void printUnwindInfo() LLVM_OVERRIDE;
|
||||
|
||||
private:
|
||||
void printSymbol(symbol_iterator SymI);
|
||||
|
||||
void printRelocation(section_iterator SecI, relocation_iterator RelI);
|
||||
|
||||
const llvm::object::MachOObjectFile *Obj;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
namespace llvm {
|
||||
|
||||
error_code createMachODumper(const object::ObjectFile *Obj,
|
||||
StreamWriter& Writer,
|
||||
OwningPtr<ObjDumper> &Result) {
|
||||
const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj);
|
||||
if (!MachOObj)
|
||||
return readobj_error::unsupported_obj_file_format;
|
||||
|
||||
Result.reset(new MachODumper(MachOObj, Writer));
|
||||
return readobj_error::success;
|
||||
}
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
|
||||
static const EnumEntry<unsigned> MachOSectionTypes[] = {
|
||||
{ "Regular" , 0x00 },
|
||||
{ "ZeroFill" , 0x01 },
|
||||
{ "CStringLiterals" , 0x02 },
|
||||
{ "4ByteLiterals" , 0x03 },
|
||||
{ "8ByteLiterals" , 0x04 },
|
||||
{ "LiteralPointers" , 0x05 },
|
||||
{ "NonLazySymbolPointers" , 0x06 },
|
||||
{ "LazySymbolPointers" , 0x07 },
|
||||
{ "SymbolStubs" , 0x08 },
|
||||
{ "ModInitFuncs" , 0x09 },
|
||||
{ "ModTermFuncs" , 0x0A },
|
||||
{ "Coalesced" , 0x0B },
|
||||
{ "GBZeroFill" , 0x0C },
|
||||
{ "Interposing" , 0x0D },
|
||||
{ "16ByteLiterals" , 0x0E },
|
||||
{ "DTraceDOF" , 0x0F },
|
||||
{ "LazyDylibSymbolPoints" , 0x10 },
|
||||
{ "ThreadLocalRegular" , 0x11 },
|
||||
{ "ThreadLocalZerofill" , 0x12 },
|
||||
{ "ThreadLocalVariables" , 0x13 },
|
||||
{ "ThreadLocalVariablePointers" , 0x14 },
|
||||
{ "ThreadLocalInitFunctionPointers", 0x15 }
|
||||
};
|
||||
|
||||
static const EnumEntry<unsigned> MachOSectionAttributes[] = {
|
||||
{ "LocReloc" , 1 << 0 /*S_ATTR_LOC_RELOC */ },
|
||||
{ "ExtReloc" , 1 << 1 /*S_ATTR_EXT_RELOC */ },
|
||||
{ "SomeInstructions" , 1 << 2 /*S_ATTR_SOME_INSTRUCTIONS */ },
|
||||
{ "Debug" , 1 << 17 /*S_ATTR_DEBUG */ },
|
||||
{ "SelfModifyingCode", 1 << 18 /*S_ATTR_SELF_MODIFYING_CODE*/ },
|
||||
{ "LiveSupport" , 1 << 19 /*S_ATTR_LIVE_SUPPORT */ },
|
||||
{ "NoDeadStrip" , 1 << 20 /*S_ATTR_NO_DEAD_STRIP */ },
|
||||
{ "StripStaticSyms" , 1 << 21 /*S_ATTR_STRIP_STATIC_SYMS */ },
|
||||
{ "NoTOC" , 1 << 22 /*S_ATTR_NO_TOC */ },
|
||||
{ "PureInstructions" , 1 << 23 /*S_ATTR_PURE_INSTRUCTIONS */ },
|
||||
};
|
||||
|
||||
static const EnumEntry<unsigned> MachOSymbolRefTypes[] = {
|
||||
{ "UndefinedNonLazy", 0 },
|
||||
{ "ReferenceFlagUndefinedLazy", 1 },
|
||||
{ "ReferenceFlagDefined", 2 },
|
||||
{ "ReferenceFlagPrivateDefined", 3 },
|
||||
{ "ReferenceFlagPrivateUndefinedNonLazy", 4 },
|
||||
{ "ReferenceFlagPrivateUndefinedLazy", 5 }
|
||||
};
|
||||
|
||||
static const EnumEntry<unsigned> MachOSymbolFlags[] = {
|
||||
{ "ReferencedDynamically", 0x10 },
|
||||
{ "NoDeadStrip", 0x20 },
|
||||
{ "WeakRef", 0x40 },
|
||||
{ "WeakDef", 0x80 }
|
||||
};
|
||||
|
||||
static const EnumEntry<unsigned> MachOSymbolTypes[] = {
|
||||
{ "Undef", 0x0 },
|
||||
{ "External", 0x1 },
|
||||
{ "Abs", 0x2 },
|
||||
{ "Indirect", 0xA },
|
||||
{ "PreboundUndef", 0xC },
|
||||
{ "Section", 0xE },
|
||||
{ "PrivateExternal", 0x10 }
|
||||
};
|
||||
|
||||
namespace {
|
||||
enum {
|
||||
N_STAB = 0xE0
|
||||
};
|
||||
|
||||
struct MachOSection {
|
||||
ArrayRef<char> Name;
|
||||
ArrayRef<char> SegmentName;
|
||||
uint64_t Address;
|
||||
uint64_t Size;
|
||||
uint32_t Offset;
|
||||
uint32_t Alignment;
|
||||
uint32_t RelocationTableOffset;
|
||||
uint32_t NumRelocationTableEntries;
|
||||
uint32_t Flags;
|
||||
uint32_t Reserved1;
|
||||
uint32_t Reserved2;
|
||||
};
|
||||
|
||||
struct MachOSymbol {
|
||||
uint32_t StringIndex;
|
||||
uint8_t Type;
|
||||
uint8_t SectionIndex;
|
||||
uint16_t Flags;
|
||||
uint64_t Value;
|
||||
};
|
||||
}
|
||||
|
||||
static StringRef parseSegmentOrSectionName(ArrayRef<char> P) {
|
||||
if (P[15] == 0)
|
||||
// Null terminated.
|
||||
return StringRef(P.data());
|
||||
// Not null terminated, so this is a 16 char string.
|
||||
return StringRef(P.data(), 16);
|
||||
}
|
||||
|
||||
static bool is64BitLoadCommand(const MachOObject *MachOObj, DataRefImpl DRI) {
|
||||
LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
|
||||
if (LCI.Command.Type == macho::LCT_Segment64)
|
||||
return true;
|
||||
assert(LCI.Command.Type == macho::LCT_Segment && "Unexpected Type.");
|
||||
return false;
|
||||
}
|
||||
|
||||
static void getSection(const MachOObject *MachOObj,
|
||||
DataRefImpl DRI,
|
||||
MachOSection &Section) {
|
||||
LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
|
||||
if (is64BitLoadCommand(MachOObj, DRI)) {
|
||||
InMemoryStruct<macho::Section64> Sect;
|
||||
MachOObj->ReadSection64(LCI, DRI.d.b, Sect);
|
||||
|
||||
Section.Name = ArrayRef<char>(Sect->Name);
|
||||
Section.SegmentName = ArrayRef<char>(Sect->SegmentName);
|
||||
Section.Address = Sect->Address;
|
||||
Section.Size = Sect->Size;
|
||||
Section.Offset = Sect->Offset;
|
||||
Section.Alignment = Sect->Align;
|
||||
Section.RelocationTableOffset = Sect->RelocationTableOffset;
|
||||
Section.NumRelocationTableEntries = Sect->NumRelocationTableEntries;
|
||||
Section.Flags = Sect->Flags;
|
||||
Section.Reserved1 = Sect->Reserved1;
|
||||
Section.Reserved2 = Sect->Reserved2;
|
||||
} else {
|
||||
InMemoryStruct<macho::Section> Sect;
|
||||
MachOObj->ReadSection(LCI, DRI.d.b, Sect);
|
||||
|
||||
Section.Name = Sect->Name;
|
||||
Section.SegmentName = Sect->SegmentName;
|
||||
Section.Address = Sect->Address;
|
||||
Section.Size = Sect->Size;
|
||||
Section.Offset = Sect->Offset;
|
||||
Section.Alignment = Sect->Align;
|
||||
Section.RelocationTableOffset = Sect->RelocationTableOffset;
|
||||
Section.NumRelocationTableEntries = Sect->NumRelocationTableEntries;
|
||||
Section.Flags = Sect->Flags;
|
||||
Section.Reserved1 = Sect->Reserved1;
|
||||
Section.Reserved2 = Sect->Reserved2;
|
||||
}
|
||||
}
|
||||
|
||||
static void getSymbolTableEntry(const MachOObject *MachO,
|
||||
DataRefImpl DRI,
|
||||
InMemoryStruct<macho::SymbolTableEntry> &Res) {
|
||||
InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd;
|
||||
LoadCommandInfo LCI = MachO->getLoadCommandInfo(DRI.d.a);
|
||||
MachO->ReadSymtabLoadCommand(LCI, SymtabLoadCmd);
|
||||
MachO->ReadSymbolTableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, Res);
|
||||
}
|
||||
|
||||
static void getSymbol64TableEntry(const MachOObject *MachO,
|
||||
DataRefImpl DRI,
|
||||
InMemoryStruct<macho::Symbol64TableEntry> &Res) {
|
||||
InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd;
|
||||
LoadCommandInfo LCI = MachO->getLoadCommandInfo(DRI.d.a);
|
||||
MachO->ReadSymtabLoadCommand(LCI, SymtabLoadCmd);
|
||||
MachO->ReadSymbol64TableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, Res);
|
||||
}
|
||||
|
||||
static void getSymbol(const MachOObject *MachOObj,
|
||||
DataRefImpl DRI,
|
||||
MachOSymbol &Symbol) {
|
||||
if (MachOObj->is64Bit()) {
|
||||
InMemoryStruct<macho::Symbol64TableEntry> Entry;
|
||||
getSymbol64TableEntry(MachOObj, DRI, Entry);
|
||||
Symbol.StringIndex = Entry->StringIndex;
|
||||
Symbol.Type = Entry->Type;
|
||||
Symbol.SectionIndex = Entry->SectionIndex;
|
||||
Symbol.Flags = Entry->Flags;
|
||||
Symbol.Value = Entry->Value;
|
||||
} else {
|
||||
InMemoryStruct<macho::SymbolTableEntry> Entry;
|
||||
getSymbolTableEntry(MachOObj, DRI, Entry);
|
||||
Symbol.StringIndex = Entry->StringIndex;
|
||||
Symbol.Type = Entry->Type;
|
||||
Symbol.SectionIndex = Entry->SectionIndex;
|
||||
Symbol.Flags = Entry->Flags;
|
||||
Symbol.Value = Entry->Value;
|
||||
}
|
||||
}
|
||||
|
||||
void MachODumper::printFileHeaders() {
|
||||
W.startLine() << "FileHeaders not implemented.\n";
|
||||
}
|
||||
|
||||
void MachODumper::printSections() {
|
||||
ListScope Group(W, "Sections");
|
||||
|
||||
int SectionIndex = -1;
|
||||
error_code EC;
|
||||
for (section_iterator SecI = Obj->begin_sections(),
|
||||
SecE = Obj->end_sections();
|
||||
SecI != SecE; SecI.increment(EC)) {
|
||||
if (error(EC)) break;
|
||||
|
||||
++SectionIndex;
|
||||
|
||||
const MachOObject *MachO = const_cast<MachOObjectFile*>(Obj)->getObject();
|
||||
|
||||
MachOSection Section;
|
||||
getSection(MachO, SecI->getRawDataRefImpl(), Section);
|
||||
StringRef Name;
|
||||
if (error(SecI->getName(Name)))
|
||||
Name = "";
|
||||
|
||||
DictScope SectionD(W, "Section");
|
||||
W.printNumber("Index", SectionIndex);
|
||||
W.printBinary("Name", Name, Section.Name);
|
||||
W.printBinary("Segment", parseSegmentOrSectionName(Section.SegmentName),
|
||||
Section.SegmentName);
|
||||
W.printHex ("Address", Section.Address);
|
||||
W.printHex ("Size", Section.Size);
|
||||
W.printNumber("Offset", Section.Offset);
|
||||
W.printNumber("Alignment", Section.Alignment);
|
||||
W.printHex ("RelocationOffset", Section.RelocationTableOffset);
|
||||
W.printNumber("RelocationCount", Section.NumRelocationTableEntries);
|
||||
W.printEnum ("Type", Section.Flags & 0xFF,
|
||||
makeArrayRef(MachOSectionAttributes));
|
||||
W.printFlags ("Attributes", Section.Flags >> 8,
|
||||
makeArrayRef(MachOSectionAttributes));
|
||||
W.printHex ("Reserved1", Section.Reserved1);
|
||||
W.printHex ("Reserved2", Section.Reserved2);
|
||||
|
||||
if (opts::SectionRelocations) {
|
||||
ListScope D(W, "Relocations");
|
||||
for (relocation_iterator RelI = SecI->begin_relocations(),
|
||||
RelE = SecI->end_relocations();
|
||||
RelI != RelE; RelI.increment(EC)) {
|
||||
if (error(EC)) break;
|
||||
|
||||
printRelocation(SecI, RelI);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts::SectionSymbols) {
|
||||
ListScope D(W, "Symbols");
|
||||
for (symbol_iterator SymI = Obj->begin_symbols(),
|
||||
SymE = Obj->end_symbols();
|
||||
SymI != SymE; SymI.increment(EC)) {
|
||||
if (error(EC)) break;
|
||||
|
||||
bool Contained = false;
|
||||
if (SecI->containsSymbol(*SymI, Contained) || !Contained)
|
||||
continue;
|
||||
|
||||
printSymbol(SymI);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts::SectionData) {
|
||||
StringRef Data;
|
||||
if (error(SecI->getContents(Data))) break;
|
||||
|
||||
W.printBinaryBlock("SectionData", Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MachODumper::printRelocations() {
|
||||
ListScope D(W, "Relocations");
|
||||
|
||||
error_code EC;
|
||||
for (section_iterator SecI = Obj->begin_sections(),
|
||||
SecE = Obj->end_sections();
|
||||
SecI != SecE; SecI.increment(EC)) {
|
||||
if (error(EC)) break;
|
||||
|
||||
StringRef Name;
|
||||
if (error(SecI->getName(Name)))
|
||||
continue;
|
||||
|
||||
bool PrintedGroup = false;
|
||||
for (relocation_iterator RelI = SecI->begin_relocations(),
|
||||
RelE = SecI->end_relocations();
|
||||
RelI != RelE; RelI.increment(EC)) {
|
||||
if (error(EC)) break;
|
||||
|
||||
if (!PrintedGroup) {
|
||||
W.startLine() << "Section " << Name << " {\n";
|
||||
W.indent();
|
||||
PrintedGroup = true;
|
||||
}
|
||||
|
||||
printRelocation(SecI, RelI);
|
||||
}
|
||||
|
||||
if (PrintedGroup) {
|
||||
W.unindent();
|
||||
W.startLine() << "}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MachODumper::printRelocation(section_iterator SecI,
|
||||
relocation_iterator RelI) {
|
||||
uint64_t Offset;
|
||||
SmallString<32> RelocName;
|
||||
int64_t Info;
|
||||
StringRef SymbolName;
|
||||
SymbolRef Symbol;
|
||||
if (error(RelI->getOffset(Offset))) return;
|
||||
if (error(RelI->getTypeName(RelocName))) return;
|
||||
if (error(RelI->getAdditionalInfo(Info))) return;
|
||||
if (error(RelI->getSymbol(Symbol))) return;
|
||||
if (error(Symbol.getName(SymbolName))) return;
|
||||
|
||||
raw_ostream& OS = W.startLine();
|
||||
OS << W.hex(Offset)
|
||||
<< " " << RelocName
|
||||
<< " " << (SymbolName.size() > 0 ? SymbolName : "-")
|
||||
<< " " << W.hex(Info)
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
void MachODumper::printSymbols() {
|
||||
ListScope Group(W, "Symbols");
|
||||
|
||||
error_code EC;
|
||||
for (symbol_iterator SymI = Obj->begin_symbols(),
|
||||
SymE = Obj->end_symbols();
|
||||
SymI != SymE; SymI.increment(EC)) {
|
||||
if (error(EC)) break;
|
||||
|
||||
printSymbol(SymI);
|
||||
}
|
||||
}
|
||||
|
||||
void MachODumper::printDynamicSymbols() {
|
||||
ListScope Group(W, "DynamicSymbols");
|
||||
}
|
||||
|
||||
void MachODumper::printSymbol(symbol_iterator SymI) {
|
||||
error_code EC;
|
||||
|
||||
StringRef SymbolName;
|
||||
if (SymI->getName(SymbolName))
|
||||
SymbolName = "";
|
||||
|
||||
const MachOObject *MachO = const_cast<MachOObjectFile*>(Obj)->getObject();
|
||||
|
||||
MachOSymbol Symbol;
|
||||
getSymbol(MachO, SymI->getRawDataRefImpl(), Symbol);
|
||||
|
||||
StringRef SectionName;
|
||||
section_iterator SecI(Obj->end_sections());
|
||||
if (error(SymI->getSection(SecI)) ||
|
||||
error(SecI->getName(SectionName)))
|
||||
SectionName = "";
|
||||
|
||||
DictScope D(W, "Symbol");
|
||||
W.printNumber("Name", SymbolName, Symbol.StringIndex);
|
||||
if (Symbol.Type & N_STAB) {
|
||||
W.printHex ("Type", "SymDebugTable", Symbol.Type);
|
||||
} else {
|
||||
W.printEnum("Type", Symbol.Type, makeArrayRef(MachOSymbolTypes));
|
||||
}
|
||||
W.printHex ("Section", SectionName, Symbol.SectionIndex);
|
||||
W.printEnum ("RefType", static_cast<uint16_t>(Symbol.Flags & 0xF),
|
||||
makeArrayRef(MachOSymbolRefTypes));
|
||||
W.printFlags ("Flags", static_cast<uint16_t>(Symbol.Flags & ~0xF),
|
||||
makeArrayRef(MachOSymbolFlags));
|
||||
W.printHex ("Value", Symbol.Value);
|
||||
}
|
||||
|
||||
void MachODumper::printUnwindInfo() {
|
||||
W.startLine() << "UnwindInfo not implemented.\n";
|
||||
}
|
@ -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
|
||||
|
33
tools/llvm-readobj/ObjDumper.cpp
Normal file
33
tools/llvm-readobj/ObjDumper.cpp
Normal file
@ -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
|
60
tools/llvm-readobj/ObjDumper.h
Normal file
60
tools/llvm-readobj/ObjDumper.h
Normal file
@ -0,0 +1,60 @@
|
||||
//===-- ObjDumper.h -------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_READOBJ_OBJDUMPER_H
|
||||
#define LLVM_READOBJ_OBJDUMPER_H
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace object {
|
||||
class ObjectFile;
|
||||
}
|
||||
|
||||
class error_code;
|
||||
|
||||
template<typename T>
|
||||
class OwningPtr;
|
||||
|
||||
class StreamWriter;
|
||||
|
||||
class ObjDumper {
|
||||
public:
|
||||
ObjDumper(StreamWriter& Writer);
|
||||
virtual ~ObjDumper();
|
||||
|
||||
virtual void printFileHeaders() = 0;
|
||||
virtual void printSections() = 0;
|
||||
virtual void printRelocations() = 0;
|
||||
virtual void printSymbols() = 0;
|
||||
virtual void printDynamicSymbols() = 0;
|
||||
virtual void printUnwindInfo() = 0;
|
||||
|
||||
// Only implemented for ELF at this time.
|
||||
virtual void printDynamicTable() { }
|
||||
virtual void printNeededLibraries() { }
|
||||
|
||||
protected:
|
||||
StreamWriter& W;
|
||||
};
|
||||
|
||||
error_code createCOFFDumper(const object::ObjectFile *Obj,
|
||||
StreamWriter& Writer,
|
||||
OwningPtr<ObjDumper> &Result);
|
||||
|
||||
error_code createELFDumper(const object::ObjectFile *Obj,
|
||||
StreamWriter& Writer,
|
||||
OwningPtr<ObjDumper> &Result);
|
||||
|
||||
error_code createMachODumper(const object::ObjectFile *Obj,
|
||||
StreamWriter& Writer,
|
||||
OwningPtr<ObjDumper> &Result);
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
79
tools/llvm-readobj/StreamWriter.cpp
Normal file
79
tools/llvm-readobj/StreamWriter.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
#include "StreamWriter.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include <cctype>
|
||||
|
||||
using namespace llvm::support;
|
||||
|
||||
namespace llvm {
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, const HexNumber& Value) {
|
||||
uint64_t N = Value.Value;
|
||||
// Zero is a special case.
|
||||
if (N == 0)
|
||||
return OS << "0x0";
|
||||
|
||||
char NumberBuffer[20];
|
||||
char *EndPtr = NumberBuffer + sizeof(NumberBuffer);
|
||||
char *CurPtr = EndPtr;
|
||||
|
||||
while (N) {
|
||||
uintptr_t X = N % 16;
|
||||
*--CurPtr = (X < 10 ? '0' + X : 'A' + X - 10);
|
||||
N /= 16;
|
||||
}
|
||||
|
||||
OS << "0x";
|
||||
return OS.write(CurPtr, EndPtr - CurPtr);
|
||||
}
|
||||
|
||||
void StreamWriter::printBinaryImpl(StringRef Label, StringRef Str,
|
||||
ArrayRef<uint8_t> Data, bool Block) {
|
||||
if (Data.size() > 16)
|
||||
Block = true;
|
||||
|
||||
if (Block) {
|
||||
startLine() << Label;
|
||||
if (Str.size() > 0)
|
||||
OS << ": " << Str;
|
||||
OS << " (\n";
|
||||
for (size_t addr = 0, end = Data.size(); addr < end; addr += 16) {
|
||||
startLine() << format(" %04" PRIX64 ": ", uint64_t(addr));
|
||||
// Dump line of hex.
|
||||
for (size_t i = 0; i < 16; ++i) {
|
||||
if (i != 0 && i % 4 == 0)
|
||||
OS << ' ';
|
||||
if (addr + i < end)
|
||||
OS << hexdigit((Data[addr + i] >> 4) & 0xF, false)
|
||||
<< hexdigit(Data[addr + i] & 0xF, false);
|
||||
else
|
||||
OS << " ";
|
||||
}
|
||||
// Print ascii.
|
||||
OS << " |";
|
||||
for (std::size_t i = 0; i < 16 && addr + i < end; ++i) {
|
||||
if (std::isprint(Data[addr + i] & 0xFF))
|
||||
OS << Data[addr + i];
|
||||
else
|
||||
OS << ".";
|
||||
}
|
||||
OS << "|\n";
|
||||
}
|
||||
|
||||
startLine() << ")\n";
|
||||
} else {
|
||||
startLine() << Label << ":";
|
||||
if (Str.size() > 0)
|
||||
OS << " " << Str;
|
||||
OS << " (";
|
||||
for (size_t i = 0; i < Data.size(); ++i) {
|
||||
if (i > 0)
|
||||
OS << " ";
|
||||
|
||||
OS << format("%02X", static_cast<int>(Data[i]));
|
||||
}
|
||||
OS << ")\n";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace llvm
|
282
tools/llvm-readobj/StreamWriter.h
Normal file
282
tools/llvm-readobj/StreamWriter.h
Normal file
@ -0,0 +1,282 @@
|
||||
//===-- StreamWriter.h ----------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_READOBJ_STREAMWRITER_H
|
||||
#define LLVM_READOBJ_STREAMWRITER_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::support;
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template<typename T>
|
||||
struct EnumEntry {
|
||||
StringRef Name;
|
||||
T Value;
|
||||
};
|
||||
|
||||
struct HexNumber {
|
||||
// To avoid sign-extension we have to explicitly cast to the appropriate
|
||||
// unsigned type. The overloads are here so that every type that is implicitly
|
||||
// convertible to an integer (including enums and endian helpers) can be used
|
||||
// without requiring type traits or call-site changes.
|
||||
HexNumber(int8_t Value) : Value(static_cast<uint8_t >(Value)) { }
|
||||
HexNumber(int16_t Value) : Value(static_cast<uint16_t>(Value)) { }
|
||||
HexNumber(int32_t Value) : Value(static_cast<uint32_t>(Value)) { }
|
||||
HexNumber(int64_t Value) : Value(static_cast<uint64_t>(Value)) { }
|
||||
HexNumber(uint8_t Value) : Value(Value) { }
|
||||
HexNumber(uint16_t Value) : Value(Value) { }
|
||||
HexNumber(uint32_t Value) : Value(Value) { }
|
||||
HexNumber(uint64_t Value) : Value(Value) { }
|
||||
uint64_t Value;
|
||||
};
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, const HexNumber& Value);
|
||||
|
||||
class StreamWriter {
|
||||
public:
|
||||
StreamWriter(raw_ostream &OS)
|
||||
: OS(OS)
|
||||
, IndentLevel(0) {
|
||||
}
|
||||
|
||||
void flush() {
|
||||
OS.flush();
|
||||
}
|
||||
|
||||
void indent(int Levels = 1) {
|
||||
IndentLevel += Levels;
|
||||
}
|
||||
|
||||
void unindent(int Levels = 1) {
|
||||
IndentLevel = std::max(0, IndentLevel - Levels);
|
||||
}
|
||||
|
||||
void printIndent() {
|
||||
for (int i = 0; i < IndentLevel; ++i)
|
||||
OS << " ";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
HexNumber hex(T Value) {
|
||||
return HexNumber(Value);
|
||||
}
|
||||
|
||||
template<typename T, typename TEnum>
|
||||
void printEnum(StringRef Label, T Value,
|
||||
ArrayRef<EnumEntry<TEnum> > EnumValues) {
|
||||
StringRef Name;
|
||||
bool Found = false;
|
||||
for (size_t i = 0; i < EnumValues.size(); ++i) {
|
||||
if (EnumValues[i].Value == Value) {
|
||||
Name = EnumValues[i].Name;
|
||||
Found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Found) {
|
||||
startLine() << Label << ": " << Name << " (" << hex(Value) << ")\n";
|
||||
} else {
|
||||
startLine() << Label << ": " << hex(Value) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename TFlag>
|
||||
void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag> > Flags,
|
||||
TFlag EnumMask = TFlag(0)) {
|
||||
typedef EnumEntry<TFlag> FlagEntry;
|
||||
typedef SmallVector<FlagEntry, 10> FlagVector;
|
||||
FlagVector SetFlags;
|
||||
|
||||
for (typename ArrayRef<FlagEntry>::const_iterator I = Flags.begin(),
|
||||
E = Flags.end(); I != E; ++I) {
|
||||
if (I->Value == 0)
|
||||
continue;
|
||||
|
||||
bool IsEnum = (I->Value & EnumMask) != 0;
|
||||
if ((!IsEnum && (Value & I->Value) == I->Value) ||
|
||||
(IsEnum && (Value & EnumMask) == I->Value)) {
|
||||
SetFlags.push_back(*I);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(SetFlags.begin(), SetFlags.end(), &flagName<TFlag>);
|
||||
|
||||
startLine() << Label << " [ (" << hex(Value) << ")\n";
|
||||
for (typename FlagVector::const_iterator I = SetFlags.begin(),
|
||||
E = SetFlags.end();
|
||||
I != E; ++I) {
|
||||
startLine() << " " << I->Name << " (" << hex(I->Value) << ")\n";
|
||||
}
|
||||
startLine() << "]\n";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void printFlags(StringRef Label, T Value) {
|
||||
startLine() << Label << " [ (" << hex(Value) << ")\n";
|
||||
uint64_t Flag = 1;
|
||||
uint64_t Curr = Value;
|
||||
while (Curr > 0) {
|
||||
if (Curr & 1)
|
||||
startLine() << " " << hex(Flag) << "\n";
|
||||
Curr >>= 1;
|
||||
Flag <<= 1;
|
||||
}
|
||||
startLine() << "]\n";
|
||||
}
|
||||
|
||||
void printNumber(StringRef Label, uint64_t Value) {
|
||||
startLine() << Label << ": " << Value << "\n";
|
||||
}
|
||||
|
||||
void printNumber(StringRef Label, uint32_t Value) {
|
||||
startLine() << Label << ": " << Value << "\n";
|
||||
}
|
||||
|
||||
void printNumber(StringRef Label, uint16_t Value) {
|
||||
startLine() << Label << ": " << Value << "\n";
|
||||
}
|
||||
|
||||
void printNumber(StringRef Label, uint8_t Value) {
|
||||
startLine() << Label << ": " << unsigned(Value) << "\n";
|
||||
}
|
||||
|
||||
void printNumber(StringRef Label, int64_t Value) {
|
||||
startLine() << Label << ": " << Value << "\n";
|
||||
}
|
||||
|
||||
void printNumber(StringRef Label, int32_t Value) {
|
||||
startLine() << Label << ": " << Value << "\n";
|
||||
}
|
||||
|
||||
void printNumber(StringRef Label, int16_t Value) {
|
||||
startLine() << Label << ": " << Value << "\n";
|
||||
}
|
||||
|
||||
void printNumber(StringRef Label, int8_t Value) {
|
||||
startLine() << Label << ": " << int(Value) << "\n";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void printHex(StringRef Label, T Value) {
|
||||
startLine() << Label << ": " << hex(Value) << "\n";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void printHex(StringRef Label, StringRef Str, T Value) {
|
||||
startLine() << Label << ": " << Str << " (" << hex(Value) << ")\n";
|
||||
}
|
||||
|
||||
void printString(StringRef Label, StringRef Value) {
|
||||
startLine() << Label << ": " << Value << "\n";
|
||||
}
|
||||
|
||||
void printString(StringRef Label, const std::string &Value) {
|
||||
startLine() << Label << ": " << Value << "\n";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void printNumber(StringRef Label, StringRef Str, T Value) {
|
||||
startLine() << Label << ": " << Str << " (" << Value << ")\n";
|
||||
}
|
||||
|
||||
void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) {
|
||||
printBinaryImpl(Label, Str, Value, false);
|
||||
}
|
||||
|
||||
void printBinary(StringRef Label, StringRef Str, ArrayRef<char> Value) {
|
||||
ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()),
|
||||
Value.size());
|
||||
printBinaryImpl(Label, Str, V, false);
|
||||
}
|
||||
|
||||
void printBinary(StringRef Label, ArrayRef<uint8_t> Value) {
|
||||
printBinaryImpl(Label, StringRef(), Value, false);
|
||||
}
|
||||
|
||||
void printBinary(StringRef Label, ArrayRef<char> Value) {
|
||||
ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()),
|
||||
Value.size());
|
||||
printBinaryImpl(Label, StringRef(), V, false);
|
||||
}
|
||||
|
||||
void printBinary(StringRef Label, StringRef Value) {
|
||||
ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()),
|
||||
Value.size());
|
||||
printBinaryImpl(Label, StringRef(), V, false);
|
||||
}
|
||||
|
||||
void printBinaryBlock(StringRef Label, StringRef Value) {
|
||||
ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()),
|
||||
Value.size());
|
||||
printBinaryImpl(Label, StringRef(), V, true);
|
||||
}
|
||||
|
||||
raw_ostream& startLine() {
|
||||
printIndent();
|
||||
return OS;
|
||||
}
|
||||
|
||||
raw_ostream& getOStream() {
|
||||
return OS;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
static bool flagName(const EnumEntry<T>& lhs, const EnumEntry<T>& rhs) {
|
||||
return lhs.Name < rhs.Name;
|
||||
}
|
||||
|
||||
void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value,
|
||||
bool Block);
|
||||
|
||||
raw_ostream &OS;
|
||||
int IndentLevel;
|
||||
};
|
||||
|
||||
struct DictScope {
|
||||
DictScope(StreamWriter& W, StringRef N) : W(W) {
|
||||
W.startLine() << N << " {\n";
|
||||
W.indent();
|
||||
}
|
||||
|
||||
~DictScope() {
|
||||
W.unindent();
|
||||
W.startLine() << "}\n";
|
||||
}
|
||||
|
||||
StreamWriter& W;
|
||||
};
|
||||
|
||||
struct ListScope {
|
||||
ListScope(StreamWriter& W, StringRef N) : W(W) {
|
||||
W.startLine() << N << " [\n";
|
||||
W.indent();
|
||||
}
|
||||
|
||||
~ListScope() {
|
||||
W.unindent();
|
||||
W.startLine() << "]\n";
|
||||
}
|
||||
|
||||
StreamWriter& W;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
@ -21,268 +21,263 @@
|
||||
|
||||
#include "llvm-readobj.h"
|
||||
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/Object/ELF.h"
|
||||
#include "Error.h"
|
||||
#include "ObjDumper.h"
|
||||
#include "StreamWriter.h"
|
||||
|
||||
#include "llvm/Object/Archive.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/system_error.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::object;
|
||||
|
||||
static cl::opt<std::string>
|
||||
InputFilename(cl::Positional, cl::desc("<input object>"), cl::init(""));
|
||||
namespace opts {
|
||||
cl::list<std::string> InputFilenames(cl::Positional,
|
||||
cl::desc("<input object files>"),
|
||||
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<bool> FileHeaders("file-headers",
|
||||
cl::desc("Display file headers "));
|
||||
cl::alias FileHeadersShort("h",
|
||||
cl::desc("Alias for --file-headers"),
|
||||
cl::aliasopt(FileHeaders));
|
||||
|
||||
// -sections, -s
|
||||
cl::opt<bool> Sections("sections",
|
||||
cl::desc("Display all sections."));
|
||||
cl::alias SectionsShort("s",
|
||||
cl::desc("Alias for --sections"),
|
||||
cl::aliasopt(Sections));
|
||||
|
||||
// -section-relocations, -sr
|
||||
cl::opt<bool> SectionRelocations("section-relocations",
|
||||
cl::desc("Display relocations for each section shown."));
|
||||
cl::alias SectionRelocationsShort("sr",
|
||||
cl::desc("Alias for --section-relocations"),
|
||||
cl::aliasopt(SectionRelocations));
|
||||
|
||||
// -section-symbols, -st
|
||||
cl::opt<bool> SectionSymbols("section-symbols",
|
||||
cl::desc("Display symbols for each section shown."));
|
||||
cl::alias SectionSymbolsShort("st",
|
||||
cl::desc("Alias for --section-symbols"),
|
||||
cl::aliasopt(SectionSymbols));
|
||||
|
||||
// -section-data, -sd
|
||||
cl::opt<bool> SectionData("section-data",
|
||||
cl::desc("Display section data for each section shown."));
|
||||
cl::alias SectionDataShort("sd",
|
||||
cl::desc("Alias for --section-data"),
|
||||
cl::aliasopt(SectionData));
|
||||
|
||||
// -relocations, -r
|
||||
cl::opt<bool> Relocations("relocations",
|
||||
cl::desc("Display the relocation entries in the file"));
|
||||
cl::alias RelocationsShort("r",
|
||||
cl::desc("Alias for --relocations"),
|
||||
cl::aliasopt(Relocations));
|
||||
|
||||
// -symbols, -t
|
||||
cl::opt<bool> Symbols("symbols",
|
||||
cl::desc("Display the symbol table"));
|
||||
cl::alias SymbolsShort("t",
|
||||
cl::desc("Alias for --symbols"),
|
||||
cl::aliasopt(Symbols));
|
||||
|
||||
// -dyn-symbols, -dt
|
||||
cl::opt<bool> DynamicSymbols("dyn-symbols",
|
||||
cl::desc("Display the dynamic symbol table"));
|
||||
cl::alias DynamicSymbolsShort("dt",
|
||||
cl::desc("Alias for --dyn-symbols"),
|
||||
cl::aliasopt(DynamicSymbols));
|
||||
|
||||
// -unwind, -u
|
||||
cl::opt<bool> UnwindInfo("unwind",
|
||||
cl::desc("Display unwind information"));
|
||||
cl::alias UnwindInfoShort("u",
|
||||
cl::desc("Alias for --unwind"),
|
||||
cl::aliasopt(UnwindInfo));
|
||||
|
||||
// -dynamic-table
|
||||
cl::opt<bool> DynamicTable("dynamic-table",
|
||||
cl::desc("Display the ELF .dynamic section table"));
|
||||
|
||||
// -needed-libs
|
||||
cl::opt<bool> NeededLibraries("needed-libs",
|
||||
cl::desc("Display the needed libraries"));
|
||||
} // namespace opts
|
||||
|
||||
namespace llvm {
|
||||
|
||||
bool error(error_code EC) {
|
||||
if (!EC)
|
||||
return false;
|
||||
|
||||
outs() << "\nError reading file: " << EC.message() << ".\n";
|
||||
outs().flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dumpSectionHeader() {
|
||||
outs() << format(" %-24s", (const char*)"Name")
|
||||
<< format(" %-16s", (const char*)"Address")
|
||||
<< format(" %-16s", (const char*)"Size")
|
||||
<< format(" %-8s", (const char*)"Align")
|
||||
<< format(" %-26s", (const char*)"Flags")
|
||||
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 = "<stdin>";
|
||||
|
||||
errs() << Input << ": " << EC.message() << "\n";
|
||||
errs().flush();
|
||||
}
|
||||
|
||||
static void reportError(StringRef Input, StringRef Message) {
|
||||
if (Input == "-")
|
||||
Input = "<stdin>";
|
||||
|
||||
errs() << Input << ": " << Message << "\n";
|
||||
}
|
||||
|
||||
/// @brief Creates an format-specific object file dumper.
|
||||
static error_code createDumper(const ObjectFile *Obj,
|
||||
StreamWriter &Writer,
|
||||
OwningPtr<ObjDumper> &Result) {
|
||||
if (!Obj)
|
||||
return readobj_error::unsupported_file_format;
|
||||
|
||||
if (Obj->isCOFF())
|
||||
return createCOFFDumper(Obj, Writer, Result);
|
||||
if (Obj->isELF())
|
||||
return createELFDumper(Obj, Writer, Result);
|
||||
if (Obj->isMachO())
|
||||
return createMachODumper(Obj, Writer, Result);
|
||||
|
||||
return readobj_error::unsupported_obj_file_format;
|
||||
}
|
||||
|
||||
|
||||
/// @brief Dumps the specified object file.
|
||||
static void dumpObject(const ObjectFile *Obj) {
|
||||
StreamWriter Writer(outs());
|
||||
OwningPtr<ObjDumper> Dumper;
|
||||
if (error_code EC = createDumper(Obj, Writer, Dumper)) {
|
||||
reportError(Obj->getFileName(), EC);
|
||||
return;
|
||||
}
|
||||
|
||||
outs() << '\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<Binary> child;
|
||||
if (error_code EC = ArcI->getAsBinary(child)) {
|
||||
// Ignore non-object files.
|
||||
if (EC != object_error::invalid_file_type)
|
||||
reportError(Arc->getFileName(), EC.message());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ObjectFile *Obj = dyn_cast<ObjectFile>(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<typename Iterator, typename Func>
|
||||
static void dump(const ObjectFile *obj, Func f, Iterator begin, Iterator end,
|
||||
const char *errStr) {
|
||||
error_code ec;
|
||||
uint32_t count = 0;
|
||||
Iterator it = begin, ie = end;
|
||||
while (it != ie) {
|
||||
f(*it, obj);
|
||||
it.increment(ec);
|
||||
if (ec)
|
||||
report_fatal_error(errStr);
|
||||
++count;
|
||||
// Attempt to open the binary.
|
||||
OwningPtr<Binary> Binary;
|
||||
if (error_code EC = createBinary(File, Binary)) {
|
||||
reportError(File, EC);
|
||||
return;
|
||||
}
|
||||
outs() << " Total: " << count << "\n\n";
|
||||
|
||||
if (Archive *Arc = dyn_cast<Archive>(Binary.get()))
|
||||
dumpArchive(Arc);
|
||||
else if (ObjectFile *Obj = dyn_cast<ObjectFile>(Binary.get()))
|
||||
dumpObject(Obj);
|
||||
else
|
||||
reportError(File, readobj_error::unrecognized_file_format);
|
||||
}
|
||||
|
||||
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<MemoryBuffer> File;
|
||||
if (MemoryBuffer::getFile(InputFilename, File)) {
|
||||
errs() << InputFilename << ": Open failed\n";
|
||||
return 1;
|
||||
}
|
||||
cl::ParseCommandLineOptions(argc, argv, "LLVM Object Reader\n");
|
||||
|
||||
OwningPtr<ObjectFile> 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<void> e = dumpELFDynamicTable(obj, outs()))
|
||||
;
|
||||
else
|
||||
errs() << "InputFilename" << ": " << error_code(e).message() << "\n";
|
||||
}
|
||||
|
||||
outs() << "Libraries needed:\n";
|
||||
dump(obj, &dumpLibrary, obj->begin_libraries_needed(),
|
||||
obj->end_libraries_needed(), "Needed libraries iteration failed");
|
||||
std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(),
|
||||
dumpInput);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===- llvm-readobj.h - Dump contents of an Object File -------------------===//
|
||||
//===-- llvm-readobj.h ----------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -10,13 +10,36 @@
|
||||
#ifndef LLVM_TOOLS_READ_OBJ_H
|
||||
#define LLVM_TOOLS_READ_OBJ_H
|
||||
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
namespace object { class ObjectFile; }
|
||||
class raw_ostream;
|
||||
namespace object {
|
||||
class RelocationRef;
|
||||
}
|
||||
|
||||
ErrorOr<void> dumpELFDynamicTable(object::ObjectFile *O, raw_ostream &OS);
|
||||
} // end namespace llvm
|
||||
class error_code;
|
||||
|
||||
// Various helper functions.
|
||||
bool error(error_code ec);
|
||||
bool relocAddressLess(object::RelocationRef A,
|
||||
object::RelocationRef B);
|
||||
} // namespace llvm
|
||||
|
||||
namespace opts {
|
||||
extern llvm::cl::list<std::string> InputFilenames;
|
||||
extern llvm::cl::opt<bool> FileHeaders;
|
||||
extern llvm::cl::opt<bool> Sections;
|
||||
extern llvm::cl::opt<bool> SectionRelocations;
|
||||
extern llvm::cl::opt<bool> SectionSymbols;
|
||||
extern llvm::cl::opt<bool> SectionData;
|
||||
extern llvm::cl::opt<bool> Relocations;
|
||||
extern llvm::cl::opt<bool> Symbols;
|
||||
extern llvm::cl::opt<bool> DynamicSymbols;
|
||||
extern llvm::cl::opt<bool> UnwindInfo;
|
||||
} // namespace opts
|
||||
|
||||
#define LLVM_READOBJ_ENUM_ENT(ns, enum) \
|
||||
{ #enum, ns::enum }
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user