diff --git a/llvm/docs/CommandGuide/llvm-readobj.rst b/llvm/docs/CommandGuide/llvm-readobj.rst --- a/llvm/docs/CommandGuide/llvm-readobj.rst +++ b/llvm/docs/CommandGuide/llvm-readobj.rst @@ -106,6 +106,11 @@ When used with :option:`--sections`, display symbols for each section shown. This option has no effect for GNU style output. +.. option:: --sort-symbols= + + Specify the keys to sort symbols before displaying symtab. + Valid values for sort_key are ``name`` and ``type`` + .. option:: --stackmap Display contents of the stackmap section. diff --git a/llvm/test/tools/llvm-readobj/MachO/stabs-sorted.yaml b/llvm/test/tools/llvm-readobj/MachO/stabs-sorted.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/MachO/stabs-sorted.yaml @@ -0,0 +1,342 @@ +## Verify that llvm-readobj can dump files with stabs symbols in a sorted order, + +# RUN: yaml2obj %s -o %t + +# RUN: not llvm-readobj --syms --sort-symbols=foo %t 2>&1 | FileCheck %s --check-prefix ERR-KEY +# RUN: llvm-readobj --syms --sort-symbols=,, %t 2>&1 | FileCheck %s --check-prefix WARN-KEY + +# RUN: llvm-readobj --syms --sort-symbols=type,name %t | FileCheck %s --strict-whitespace --match-full-lines --check-prefix TYPE-NAME +# RUN: llvm-readobj --syms --sort-symbols=name,type %t | FileCheck %s --strict-whitespace --match-full-lines --check-prefix NAME-TYPE + +# ERR-KEY: error: --sort-symbols value should be 'name' or 'type', but was 'foo' + +# WARN-KEY: warning: ignored empty sort key specified in --sort-symbols=',,' at position 0 +# WARN-KEY-NEXT: warning: ignored empty sort key specified in --sort-symbols=',,' at position 1 +# WARN-KEY-NEXT: warning: ignored empty sort key specified in --sort-symbols=',,' at position 2 +# WARN-KEY: File: {{.+}} + +# TYPE-NAME:File: {{.+}} +# TYPE-NAME-NEXT:Format: Mach-O {{.+}} +# TYPE-NAME-NEXT:Arch: {{.+}} +# TYPE-NAME-NEXT:AddressSize: {{.+}}bit +# TYPE-NAME-NEXT:Symbols [ +# TYPE-NAME-NEXT: Symbol { +# TYPE-NAME-NEXT: Name: _a (19) +# TYPE-NAME-NEXT: Type: Section (0xE) +# TYPE-NAME-NEXT: Section: __data (0x3) +# TYPE-NAME-NEXT: RefType: UndefinedNonLazy (0x0) +# TYPE-NAME-NEXT: Flags [ (0x0) +# TYPE-NAME-NEXT: ] +# TYPE-NAME-NEXT: Value: 0x11 +# TYPE-NAME-NEXT: } +# TYPE-NAME-NEXT: Symbol { +# TYPE-NAME-NEXT: Name: _d (10) +# TYPE-NAME-NEXT: Type: Section (0xE) +# TYPE-NAME-NEXT: Section: __text (0x1) +# TYPE-NAME-NEXT: RefType: UndefinedNonLazy (0x0) +# TYPE-NAME-NEXT: Flags [ (0x0) +# TYPE-NAME-NEXT: ] +# TYPE-NAME-NEXT: Value: 0x8 +# TYPE-NAME-NEXT: } +# TYPE-NAME-NEXT: Symbol { +# TYPE-NAME-NEXT: Name: _f (7) +# TYPE-NAME-NEXT: Type: SymDebugTable (0x2E) +# TYPE-NAME-NEXT: Section: (0x3) +# TYPE-NAME-NEXT: RefType: UndefinedNonLazy (0x0) +# TYPE-NAME-NEXT: Flags [ (0x0) +# TYPE-NAME-NEXT: ] +# TYPE-NAME-NEXT: Value: 0x19 +# TYPE-NAME-NEXT: } +# TYPE-NAME-NEXT: Symbol { +# TYPE-NAME-NEXT: Name: _z (1) +# TYPE-NAME-NEXT: Type: SymDebugTable (0x2E) +# TYPE-NAME-NEXT: Section: (0x0) +# TYPE-NAME-NEXT: RefType: UndefinedNonLazy (0x0) +# TYPE-NAME-NEXT: Flags [ (0x0) +# TYPE-NAME-NEXT: ] +# TYPE-NAME-NEXT: Value: 0x0 +# TYPE-NAME-NEXT: } +# TYPE-NAME-NEXT: Symbol { +# TYPE-NAME-NEXT: Name: _c (13) +# TYPE-NAME-NEXT: Type: SymDebugTable (0x64) +# TYPE-NAME-NEXT: Section: (0x4) +# TYPE-NAME-NEXT: RefType: UndefinedNonLazy (0x0) +# TYPE-NAME-NEXT: Flags [ (0x0) +# TYPE-NAME-NEXT: ] +# TYPE-NAME-NEXT: Value: 0x1C +# TYPE-NAME-NEXT: } +# TYPE-NAME-NEXT: Symbol { +# TYPE-NAME-NEXT: Name: _g (4) +# TYPE-NAME-NEXT: Type: SymDebugTable (0x64) +# TYPE-NAME-NEXT: Section: (0x1) +# TYPE-NAME-NEXT: RefType: UndefinedNonLazy (0x0) +# TYPE-NAME-NEXT: Flags [ (0x0) +# TYPE-NAME-NEXT: ] +# TYPE-NAME-NEXT: Value: 0x0 +# TYPE-NAME-NEXT: } +# TYPE-NAME-NEXT: Symbol { +# TYPE-NAME-NEXT: Name: _b (16) +# TYPE-NAME-NEXT: Type: SymDebugTable (0x66) +# TYPE-NAME-NEXT: Section: (0x2) +# TYPE-NAME-NEXT: RefType: UndefinedNonLazy (0x0) +# TYPE-NAME-NEXT: Flags [ (0x0) +# TYPE-NAME-NEXT: ] +# TYPE-NAME-NEXT: Value: 0x9 +# TYPE-NAME-NEXT: } +# TYPE-NAME-NEXT: Symbol { +# TYPE-NAME-NEXT: Name: _d2 (22) +# TYPE-NAME-NEXT: Type: SymDebugTable (0x66) +# TYPE-NAME-NEXT: Section: (0x1) +# TYPE-NAME-NEXT: RefType: UndefinedNonLazy (0x0) +# TYPE-NAME-NEXT: Flags [ (0x0) +# TYPE-NAME-NEXT: ] +# TYPE-NAME-NEXT: Value: 0x8 +# TYPE-NAME-NEXT: } +# TYPE-NAME-NEXT:] + +# NAME-TYPE:File: {{.+}} +# NAME-TYPE-NEXT:Format: Mach-O 64-bit x86-64 +# NAME-TYPE-NEXT:Arch: x86_64 +# NAME-TYPE-NEXT:AddressSize: 64bit +# NAME-TYPE-NEXT:Symbols [ +# NAME-TYPE-NEXT: Symbol { +# NAME-TYPE-NEXT: Name: _a (19) +# NAME-TYPE-NEXT: Type: Section (0xE) +# NAME-TYPE-NEXT: Section: __data (0x3) +# NAME-TYPE-NEXT: RefType: UndefinedNonLazy (0x0) +# NAME-TYPE-NEXT: Flags [ (0x0) +# NAME-TYPE-NEXT: ] +# NAME-TYPE-NEXT: Value: 0x11 +# NAME-TYPE-NEXT: } +# NAME-TYPE-NEXT: Symbol { +# NAME-TYPE-NEXT: Name: _b (16) +# NAME-TYPE-NEXT: Type: SymDebugTable (0x66) +# NAME-TYPE-NEXT: Section: (0x2) +# NAME-TYPE-NEXT: RefType: UndefinedNonLazy (0x0) +# NAME-TYPE-NEXT: Flags [ (0x0) +# NAME-TYPE-NEXT: ] +# NAME-TYPE-NEXT: Value: 0x9 +# NAME-TYPE-NEXT: } +# NAME-TYPE-NEXT: Symbol { +# NAME-TYPE-NEXT: Name: _c (13) +# NAME-TYPE-NEXT: Type: SymDebugTable (0x64) +# NAME-TYPE-NEXT: Section: (0x4) +# NAME-TYPE-NEXT: RefType: UndefinedNonLazy (0x0) +# NAME-TYPE-NEXT: Flags [ (0x0) +# NAME-TYPE-NEXT: ] +# NAME-TYPE-NEXT: Value: 0x1C +# NAME-TYPE-NEXT: } +# NAME-TYPE-NEXT: Symbol { +# NAME-TYPE-NEXT: Name: _d (10) +# NAME-TYPE-NEXT: Type: Section (0xE) +# NAME-TYPE-NEXT: Section: __text (0x1) +# NAME-TYPE-NEXT: RefType: UndefinedNonLazy (0x0) +# NAME-TYPE-NEXT: Flags [ (0x0) +# NAME-TYPE-NEXT: ] +# NAME-TYPE-NEXT: Value: 0x8 +# NAME-TYPE-NEXT: } +# NAME-TYPE-NEXT: Symbol { +# NAME-TYPE-NEXT: Name: _d2 (22) +# NAME-TYPE-NEXT: Type: SymDebugTable (0x66) +# NAME-TYPE-NEXT: Section: (0x1) +# NAME-TYPE-NEXT: RefType: UndefinedNonLazy (0x0) +# NAME-TYPE-NEXT: Flags [ (0x0) +# NAME-TYPE-NEXT: ] +# NAME-TYPE-NEXT: Value: 0x8 +# NAME-TYPE-NEXT: } +# NAME-TYPE-NEXT: Symbol { +# NAME-TYPE-NEXT: Name: _f (7) +# NAME-TYPE-NEXT: Type: SymDebugTable (0x2E) +# NAME-TYPE-NEXT: Section: (0x3) +# NAME-TYPE-NEXT: RefType: UndefinedNonLazy (0x0) +# NAME-TYPE-NEXT: Flags [ (0x0) +# NAME-TYPE-NEXT: ] +# NAME-TYPE-NEXT: Value: 0x19 +# NAME-TYPE-NEXT: } +# NAME-TYPE-NEXT: Symbol { +# NAME-TYPE-NEXT: Name: _g (4) +# NAME-TYPE-NEXT: Type: SymDebugTable (0x64) +# NAME-TYPE-NEXT: Section: (0x1) +# NAME-TYPE-NEXT: RefType: UndefinedNonLazy (0x0) +# NAME-TYPE-NEXT: Flags [ (0x0) +# NAME-TYPE-NEXT: ] +# NAME-TYPE-NEXT: Value: 0x0 +# NAME-TYPE-NEXT: } +# NAME-TYPE-NEXT: Symbol { +# NAME-TYPE-NEXT: Name: _z (1) +# NAME-TYPE-NEXT: Type: SymDebugTable (0x2E) +# NAME-TYPE-NEXT: Section: (0x0) +# NAME-TYPE-NEXT: RefType: UndefinedNonLazy (0x0) +# NAME-TYPE-NEXT: Flags [ (0x0) +# NAME-TYPE-NEXT: ] +# NAME-TYPE-NEXT: Value: 0x0 +# NAME-TYPE-NEXT: } +# NAME-TYPE-NEXT:] +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x1000007 + cpusubtype: 0x3 + filetype: 0x1 + ncmds: 3 + sizeofcmds: 496 + flags: 0x2000 + reserved: 0x0 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 392 + segname: '' + vmaddr: 0 + vmsize: 32 + fileoff: 528 + filesize: 28 + maxprot: 7 + initprot: 7 + nsects: 4 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0 + size: 9 + offset: 0x210 + align: 0 + reloff: 0x230 + nreloc: 1 + flags: 0x80000000 + reserved1: 0x0 + reserved2: 0x0 + reserved3: 0x0 + content: '000000000000000000' + relocations: + - address: 0x0 + symbolnum: 7 + pcrel: false + length: 3 + extern: true + type: 0 + scattered: false + value: 0 + - sectname: more_data + segname: __DATA + addr: 0x9 + size: 8 + offset: 0x219 + align: 0 + reloff: 0x0 + nreloc: 0 + flags: 0x0 + reserved1: 0x0 + reserved2: 0x0 + reserved3: 0x0 + content: 7B00000000000000 + - sectname: __data + segname: __DATA + addr: 0x11 + size: 11 + offset: 0x221 + align: 0 + reloff: 0x0 + nreloc: 0 + flags: 0x0 + reserved1: 0x0 + reserved2: 0x0 + reserved3: 0x0 + content: 7B00000000000000000000 + - sectname: __common + segname: __DATA + addr: 0x1C + size: 4 + offset: 0x0 + align: 2 + reloff: 0x0 + nreloc: 0 + flags: 0x1 + reserved1: 0x0 + reserved2: 0x0 + reserved3: 0x0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 568 + nsyms: 8 + stroff: 696 + strsize: 32 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 7 + iextdefsym: 7 + nextdefsym: 0 + iundefsym: 7 + nundefsym: 1 + tocoff: 0 + ntoc: 0 + modtaboff: 0 + nmodtab: 0 + extrefsymoff: 0 + nextrefsyms: 0 + indirectsymoff: 0 + nindirectsyms: 0 + extreloff: 0 + nextrel: 0 + locreloff: 0 + nlocrel: 0 +LinkEditData: + NameList: + - n_strx: 4 + n_type: 0x64 + n_sect: 1 + n_desc: 0 + n_value: 0 + - n_strx: 10 + n_type: 0xE + n_sect: 1 + n_desc: 0 + n_value: 8 + - n_strx: 22 + n_type: 0x66 + n_sect: 1 + n_desc: 0 + n_value: 8 + - n_strx: 16 + n_type: 0x66 + n_sect: 2 + n_desc: 0 + n_value: 9 + - n_strx: 19 + n_type: 0xE + n_sect: 3 + n_desc: 0 + n_value: 17 + - n_strx: 13 + n_type: 0x64 + n_sect: 4 + n_desc: 0 + n_value: 28 + - n_strx: 7 + n_type: 0x2E + n_sect: 3 + n_desc: 0 + n_value: 25 + - n_strx: 1 + n_type: 0x2E + n_sect: 0 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - _z + - _g + - _f + - _d + - _c + - _b + - _a + - _d2 + - '' + - '' + - '' + - '' + - '' + - '' +... diff --git a/llvm/tools/llvm-readobj/MachODumper.cpp b/llvm/tools/llvm-readobj/MachODumper.cpp --- a/llvm/tools/llvm-readobj/MachODumper.cpp +++ b/llvm/tools/llvm-readobj/MachODumper.cpp @@ -18,7 +18,12 @@ #include "llvm/Object/MachO.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/FormattedStream.h" #include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include using namespace llvm; using namespace object; @@ -45,16 +50,18 @@ void printMachODysymtab() override; void printMachOSegment() override; void printMachOIndirectSymbols() override; - void printMachOLinkerOptions () override; + void printMachOLinkerOptions() override; private: - template - void printFileHeaders(const MachHeader &Header); + template void printFileHeaders(const MachHeader &Header); StringRef getSymbolName(const SymbolRef &Symbol); - void printSymbols() override; - void printDynamicSymbols() override; + void printSymbols( + const llvm::SmallVector *SortKeys) override; + void printDynamicSymbols( + const llvm::SmallVector *SortKeys) override; + void printSymbol(const SymbolRef &Symbol, ScopedPrinter &W); void printSymbol(const SymbolRef &Symbol); void printRelocation(const RelocationRef &Reloc); @@ -68,7 +75,6 @@ } // namespace - namespace llvm { std::unique_ptr createMachODumper(const object::MachOObjectFile &Obj, @@ -79,82 +85,79 @@ } // namespace llvm const EnumEntry MachOMagics[] = { - { "Magic", MachO::MH_MAGIC }, - { "Cigam", MachO::MH_CIGAM }, - { "Magic64", MachO::MH_MAGIC_64 }, - { "Cigam64", MachO::MH_CIGAM_64 }, - { "FatMagic", MachO::FAT_MAGIC }, - { "FatCigam", MachO::FAT_CIGAM }, + {"Magic", MachO::MH_MAGIC}, {"Cigam", MachO::MH_CIGAM}, + {"Magic64", MachO::MH_MAGIC_64}, {"Cigam64", MachO::MH_CIGAM_64}, + {"FatMagic", MachO::FAT_MAGIC}, {"FatCigam", MachO::FAT_CIGAM}, }; const EnumEntry MachOHeaderFileTypes[] = { - { "Relocatable", MachO::MH_OBJECT }, - { "Executable", MachO::MH_EXECUTE }, - { "FixedVMLibrary", MachO::MH_FVMLIB }, - { "Core", MachO::MH_CORE }, - { "PreloadedExecutable", MachO::MH_PRELOAD }, - { "DynamicLibrary", MachO::MH_DYLIB }, - { "DynamicLinker", MachO::MH_DYLINKER }, - { "Bundle", MachO::MH_BUNDLE }, - { "DynamicLibraryStub", MachO::MH_DYLIB_STUB }, - { "DWARFSymbol", MachO::MH_DSYM }, - { "KextBundle", MachO::MH_KEXT_BUNDLE }, + {"Relocatable", MachO::MH_OBJECT}, + {"Executable", MachO::MH_EXECUTE}, + {"FixedVMLibrary", MachO::MH_FVMLIB}, + {"Core", MachO::MH_CORE}, + {"PreloadedExecutable", MachO::MH_PRELOAD}, + {"DynamicLibrary", MachO::MH_DYLIB}, + {"DynamicLinker", MachO::MH_DYLINKER}, + {"Bundle", MachO::MH_BUNDLE}, + {"DynamicLibraryStub", MachO::MH_DYLIB_STUB}, + {"DWARFSymbol", MachO::MH_DSYM}, + {"KextBundle", MachO::MH_KEXT_BUNDLE}, }; const EnumEntry MachOHeaderCpuTypes[] = { - { "Any" , static_cast(MachO::CPU_TYPE_ANY) }, - { "X86" , MachO::CPU_TYPE_X86 }, - { "X86-64" , MachO::CPU_TYPE_X86_64 }, - { "Mc98000" , MachO::CPU_TYPE_MC98000 }, - { "Arm" , MachO::CPU_TYPE_ARM }, - { "Arm64" , MachO::CPU_TYPE_ARM64 }, - { "Sparc" , MachO::CPU_TYPE_SPARC }, - { "PowerPC" , MachO::CPU_TYPE_POWERPC }, - { "PowerPC64" , MachO::CPU_TYPE_POWERPC64 }, + {"Any", static_cast(MachO::CPU_TYPE_ANY)}, + {"X86", MachO::CPU_TYPE_X86}, + {"X86-64", MachO::CPU_TYPE_X86_64}, + {"Mc98000", MachO::CPU_TYPE_MC98000}, + {"Arm", MachO::CPU_TYPE_ARM}, + {"Arm64", MachO::CPU_TYPE_ARM64}, + {"Sparc", MachO::CPU_TYPE_SPARC}, + {"PowerPC", MachO::CPU_TYPE_POWERPC}, + {"PowerPC64", MachO::CPU_TYPE_POWERPC64}, }; const EnumEntry MachOHeaderCpuSubtypesX86[] = { - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_I386_ALL), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_386), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_486), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_486SX), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_586), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTPRO), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTII_M3), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTII_M5), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_CELERON), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_CELERON_MOBILE), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3_M), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3_XEON), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_M), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_4), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_4_M), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ITANIUM), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ITANIUM_2), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_XEON), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_XEON_MP), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_I386_ALL), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_386), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_486), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_486SX), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_586), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTPRO), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTII_M3), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTII_M5), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_CELERON), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_CELERON_MOBILE), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3_M), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3_XEON), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_M), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_4), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_4_M), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ITANIUM), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ITANIUM_2), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_XEON), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_XEON_MP), }; const EnumEntry MachOHeaderCpuSubtypesX64[] = { - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_64_ALL), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_ARCH1), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_64_H), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_64_ALL), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_ARCH1), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_64_H), }; const EnumEntry MachOHeaderCpuSubtypesARM[] = { - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_ALL), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V4T), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V6), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V5), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V5TEJ), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_XSCALE), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7S), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7K), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V6M), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7M), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7EM), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_ALL), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V4T), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V6), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V5), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V5TEJ), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_XSCALE), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7S), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7K), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V6M), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7M), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7EM), }; const EnumEntry MachOHeaderCpuSubtypesARM64[] = { @@ -164,161 +167,153 @@ }; const EnumEntry MachOHeaderCpuSubtypesSPARC[] = { - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_SPARC_ALL), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_SPARC_ALL), }; const EnumEntry MachOHeaderCpuSubtypesPPC[] = { - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_ALL), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_601), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_602), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603e), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603ev), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_604), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_604e), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_620), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_750), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_7400), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_7450), - LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_970), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_ALL), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_601), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_602), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603e), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603ev), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_604), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_604e), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_620), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_750), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_7400), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_7450), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_970), }; const EnumEntry MachOHeaderFlags[] = { - LLVM_READOBJ_ENUM_ENT(MachO, MH_NOUNDEFS), - LLVM_READOBJ_ENUM_ENT(MachO, MH_INCRLINK), - LLVM_READOBJ_ENUM_ENT(MachO, MH_DYLDLINK), - LLVM_READOBJ_ENUM_ENT(MachO, MH_BINDATLOAD), - LLVM_READOBJ_ENUM_ENT(MachO, MH_PREBOUND), - LLVM_READOBJ_ENUM_ENT(MachO, MH_SPLIT_SEGS), - LLVM_READOBJ_ENUM_ENT(MachO, MH_LAZY_INIT), - LLVM_READOBJ_ENUM_ENT(MachO, MH_TWOLEVEL), - LLVM_READOBJ_ENUM_ENT(MachO, MH_FORCE_FLAT), - LLVM_READOBJ_ENUM_ENT(MachO, MH_NOMULTIDEFS), - LLVM_READOBJ_ENUM_ENT(MachO, MH_NOFIXPREBINDING), - LLVM_READOBJ_ENUM_ENT(MachO, MH_PREBINDABLE), - LLVM_READOBJ_ENUM_ENT(MachO, MH_ALLMODSBOUND), - LLVM_READOBJ_ENUM_ENT(MachO, MH_SUBSECTIONS_VIA_SYMBOLS), - LLVM_READOBJ_ENUM_ENT(MachO, MH_CANONICAL), - LLVM_READOBJ_ENUM_ENT(MachO, MH_WEAK_DEFINES), - LLVM_READOBJ_ENUM_ENT(MachO, MH_BINDS_TO_WEAK), - LLVM_READOBJ_ENUM_ENT(MachO, MH_ALLOW_STACK_EXECUTION), - LLVM_READOBJ_ENUM_ENT(MachO, MH_ROOT_SAFE), - LLVM_READOBJ_ENUM_ENT(MachO, MH_SETUID_SAFE), - LLVM_READOBJ_ENUM_ENT(MachO, MH_NO_REEXPORTED_DYLIBS), - LLVM_READOBJ_ENUM_ENT(MachO, MH_PIE), - LLVM_READOBJ_ENUM_ENT(MachO, MH_DEAD_STRIPPABLE_DYLIB), - LLVM_READOBJ_ENUM_ENT(MachO, MH_HAS_TLV_DESCRIPTORS), - LLVM_READOBJ_ENUM_ENT(MachO, MH_NO_HEAP_EXECUTION), - LLVM_READOBJ_ENUM_ENT(MachO, MH_APP_EXTENSION_SAFE), + LLVM_READOBJ_ENUM_ENT(MachO, MH_NOUNDEFS), + LLVM_READOBJ_ENUM_ENT(MachO, MH_INCRLINK), + LLVM_READOBJ_ENUM_ENT(MachO, MH_DYLDLINK), + LLVM_READOBJ_ENUM_ENT(MachO, MH_BINDATLOAD), + LLVM_READOBJ_ENUM_ENT(MachO, MH_PREBOUND), + LLVM_READOBJ_ENUM_ENT(MachO, MH_SPLIT_SEGS), + LLVM_READOBJ_ENUM_ENT(MachO, MH_LAZY_INIT), + LLVM_READOBJ_ENUM_ENT(MachO, MH_TWOLEVEL), + LLVM_READOBJ_ENUM_ENT(MachO, MH_FORCE_FLAT), + LLVM_READOBJ_ENUM_ENT(MachO, MH_NOMULTIDEFS), + LLVM_READOBJ_ENUM_ENT(MachO, MH_NOFIXPREBINDING), + LLVM_READOBJ_ENUM_ENT(MachO, MH_PREBINDABLE), + LLVM_READOBJ_ENUM_ENT(MachO, MH_ALLMODSBOUND), + LLVM_READOBJ_ENUM_ENT(MachO, MH_SUBSECTIONS_VIA_SYMBOLS), + LLVM_READOBJ_ENUM_ENT(MachO, MH_CANONICAL), + LLVM_READOBJ_ENUM_ENT(MachO, MH_WEAK_DEFINES), + LLVM_READOBJ_ENUM_ENT(MachO, MH_BINDS_TO_WEAK), + LLVM_READOBJ_ENUM_ENT(MachO, MH_ALLOW_STACK_EXECUTION), + LLVM_READOBJ_ENUM_ENT(MachO, MH_ROOT_SAFE), + LLVM_READOBJ_ENUM_ENT(MachO, MH_SETUID_SAFE), + LLVM_READOBJ_ENUM_ENT(MachO, MH_NO_REEXPORTED_DYLIBS), + LLVM_READOBJ_ENUM_ENT(MachO, MH_PIE), + LLVM_READOBJ_ENUM_ENT(MachO, MH_DEAD_STRIPPABLE_DYLIB), + LLVM_READOBJ_ENUM_ENT(MachO, MH_HAS_TLV_DESCRIPTORS), + LLVM_READOBJ_ENUM_ENT(MachO, MH_NO_HEAP_EXECUTION), + LLVM_READOBJ_ENUM_ENT(MachO, MH_APP_EXTENSION_SAFE), }; const EnumEntry MachOSectionTypes[] = { - { "Regular" , MachO::S_REGULAR }, - { "ZeroFill" , MachO::S_ZEROFILL }, - { "CStringLiterals" , MachO::S_CSTRING_LITERALS }, - { "4ByteLiterals" , MachO::S_4BYTE_LITERALS }, - { "8ByteLiterals" , MachO::S_8BYTE_LITERALS }, - { "LiteralPointers" , MachO::S_LITERAL_POINTERS }, - { "NonLazySymbolPointers" , MachO::S_NON_LAZY_SYMBOL_POINTERS }, - { "LazySymbolPointers" , MachO::S_LAZY_SYMBOL_POINTERS }, - { "SymbolStubs" , MachO::S_SYMBOL_STUBS }, - { "ModInitFuncPointers" , MachO::S_MOD_INIT_FUNC_POINTERS }, - { "ModTermFuncPointers" , MachO::S_MOD_TERM_FUNC_POINTERS }, - { "Coalesced" , MachO::S_COALESCED }, - { "GBZeroFill" , MachO::S_GB_ZEROFILL }, - { "Interposing" , MachO::S_INTERPOSING }, - { "16ByteLiterals" , MachO::S_16BYTE_LITERALS }, - { "DTraceDOF" , MachO::S_DTRACE_DOF }, - { "LazyDylibSymbolPointers" , MachO::S_LAZY_DYLIB_SYMBOL_POINTERS }, - { "ThreadLocalRegular" , MachO::S_THREAD_LOCAL_REGULAR }, - { "ThreadLocalZerofill" , MachO::S_THREAD_LOCAL_ZEROFILL }, - { "ThreadLocalVariables" , MachO::S_THREAD_LOCAL_VARIABLES }, - { "ThreadLocalVariablePointers" , MachO::S_THREAD_LOCAL_VARIABLE_POINTERS }, - { "ThreadLocalInitFunctionPointers", MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS } -}; + {"Regular", MachO::S_REGULAR}, + {"ZeroFill", MachO::S_ZEROFILL}, + {"CStringLiterals", MachO::S_CSTRING_LITERALS}, + {"4ByteLiterals", MachO::S_4BYTE_LITERALS}, + {"8ByteLiterals", MachO::S_8BYTE_LITERALS}, + {"LiteralPointers", MachO::S_LITERAL_POINTERS}, + {"NonLazySymbolPointers", MachO::S_NON_LAZY_SYMBOL_POINTERS}, + {"LazySymbolPointers", MachO::S_LAZY_SYMBOL_POINTERS}, + {"SymbolStubs", MachO::S_SYMBOL_STUBS}, + {"ModInitFuncPointers", MachO::S_MOD_INIT_FUNC_POINTERS}, + {"ModTermFuncPointers", MachO::S_MOD_TERM_FUNC_POINTERS}, + {"Coalesced", MachO::S_COALESCED}, + {"GBZeroFill", MachO::S_GB_ZEROFILL}, + {"Interposing", MachO::S_INTERPOSING}, + {"16ByteLiterals", MachO::S_16BYTE_LITERALS}, + {"DTraceDOF", MachO::S_DTRACE_DOF}, + {"LazyDylibSymbolPointers", MachO::S_LAZY_DYLIB_SYMBOL_POINTERS}, + {"ThreadLocalRegular", MachO::S_THREAD_LOCAL_REGULAR}, + {"ThreadLocalZerofill", MachO::S_THREAD_LOCAL_ZEROFILL}, + {"ThreadLocalVariables", MachO::S_THREAD_LOCAL_VARIABLES}, + {"ThreadLocalVariablePointers", MachO::S_THREAD_LOCAL_VARIABLE_POINTERS}, + {"ThreadLocalInitFunctionPointers", + MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS}}; const EnumEntry MachOSectionAttributes[] = { - { "LocReloc" , 1 << 0 /*S_ATTR_LOC_RELOC */ }, - { "ExtReloc" , 1 << 1 /*S_ATTR_EXT_RELOC */ }, - { "SomeInstructions" , 1 << 2 /*S_ATTR_SOME_INSTRUCTIONS */ }, - { "Debug" , 1 << 17 /*S_ATTR_DEBUG */ }, - { "SelfModifyingCode", 1 << 18 /*S_ATTR_SELF_MODIFYING_CODE*/ }, - { "LiveSupport" , 1 << 19 /*S_ATTR_LIVE_SUPPORT */ }, - { "NoDeadStrip" , 1 << 20 /*S_ATTR_NO_DEAD_STRIP */ }, - { "StripStaticSyms" , 1 << 21 /*S_ATTR_STRIP_STATIC_SYMS */ }, - { "NoTOC" , 1 << 22 /*S_ATTR_NO_TOC */ }, - { "PureInstructions" , 1 << 23 /*S_ATTR_PURE_INSTRUCTIONS */ }, + {"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 */}, }; const EnumEntry MachOSymbolRefTypes[] = { - { "UndefinedNonLazy", 0 }, - { "ReferenceFlagUndefinedLazy", 1 }, - { "ReferenceFlagDefined", 2 }, - { "ReferenceFlagPrivateDefined", 3 }, - { "ReferenceFlagPrivateUndefinedNonLazy", 4 }, - { "ReferenceFlagPrivateUndefinedLazy", 5 } -}; + {"UndefinedNonLazy", 0}, + {"ReferenceFlagUndefinedLazy", 1}, + {"ReferenceFlagDefined", 2}, + {"ReferenceFlagPrivateDefined", 3}, + {"ReferenceFlagPrivateUndefinedNonLazy", 4}, + {"ReferenceFlagPrivateUndefinedLazy", 5}}; const EnumEntry MachOSymbolFlags[] = { - { "ThumbDef", 0x8 }, - { "ReferencedDynamically", 0x10 }, - { "NoDeadStrip", 0x20 }, - { "WeakRef", 0x40 }, - { "WeakDef", 0x80 }, - { "SymbolResolver", 0x100 }, - { "AltEntry", 0x200 }, - { "ColdFunc", 0x400 }, + {"ThumbDef", 0x8}, {"ReferencedDynamically", 0x10}, + {"NoDeadStrip", 0x20}, {"WeakRef", 0x40}, + {"WeakDef", 0x80}, {"SymbolResolver", 0x100}, + {"AltEntry", 0x200}, {"ColdFunc", 0x400}, }; -const EnumEntry MachOSymbolTypes[] = { - { "Undef", 0x0 }, - { "Abs", 0x2 }, - { "Indirect", 0xA }, - { "PreboundUndef", 0xC }, - { "Section", 0xE } -}; +const EnumEntry MachOSymbolTypes[] = {{"Undef", 0x0}, + {"Abs", 0x2}, + {"Indirect", 0xA}, + {"PreboundUndef", 0xC}, + {"Section", 0xE}}; namespace { - struct MachOSection { - ArrayRef Name; - ArrayRef SegmentName; - uint64_t Address; - uint64_t Size; - uint32_t Offset; - uint32_t Alignment; - uint32_t RelocationTableOffset; - uint32_t NumRelocationTableEntries; - uint32_t Flags; - uint32_t Reserved1; - uint32_t Reserved2; - uint32_t Reserved3; - }; - - struct MachOSegment { - std::string CmdName; - std::string SegName; - uint64_t cmdsize; - uint64_t vmaddr; - uint64_t vmsize; - uint64_t fileoff; - uint64_t filesize; - uint32_t maxprot; - uint32_t initprot; - uint32_t nsects; - uint32_t flags; - }; - - struct MachOSymbol { - uint32_t StringIndex; - uint8_t Type; - uint8_t SectionIndex; - uint16_t Flags; - uint64_t Value; - }; -} +struct MachOSection { + ArrayRef Name; + ArrayRef SegmentName; + uint64_t Address; + uint64_t Size; + uint32_t Offset; + uint32_t Alignment; + uint32_t RelocationTableOffset; + uint32_t NumRelocationTableEntries; + uint32_t Flags; + uint32_t Reserved1; + uint32_t Reserved2; + uint32_t Reserved3; +}; + +struct MachOSegment { + std::string CmdName; + std::string SegName; + uint64_t cmdsize; + uint64_t vmaddr; + uint64_t vmsize; + uint64_t fileoff; + uint64_t filesize; + uint32_t maxprot; + uint32_t initprot; + uint32_t nsects; + uint32_t flags; +}; + +struct MachOSymbol { + uint32_t StringIndex; + uint8_t Type; + uint8_t SectionIndex; + uint16_t Flags; + uint64_t Value; +}; +} // namespace -static std::string getMask(uint32_t prot) -{ +static std::string getMask(uint32_t prot) { // TODO (davide): This always assumes prot is valid. // Catch mistakes and report if needed. std::string Prot; @@ -329,33 +324,32 @@ return Prot; } -static void getSection(const MachOObjectFile *Obj, - DataRefImpl Sec, +static void getSection(const MachOObjectFile *Obj, DataRefImpl Sec, MachOSection &Section) { if (!Obj->is64Bit()) { MachO::section Sect = Obj->getSection(Sec); - Section.Address = Sect.addr; - Section.Size = Sect.size; - Section.Offset = Sect.offset; - Section.Alignment = Sect.align; + Section.Address = Sect.addr; + Section.Size = Sect.size; + Section.Offset = Sect.offset; + Section.Alignment = Sect.align; Section.RelocationTableOffset = Sect.reloff; Section.NumRelocationTableEntries = Sect.nreloc; - Section.Flags = Sect.flags; - Section.Reserved1 = Sect.reserved1; - Section.Reserved2 = Sect.reserved2; + Section.Flags = Sect.flags; + Section.Reserved1 = Sect.reserved1; + Section.Reserved2 = Sect.reserved2; return; } MachO::section_64 Sect = Obj->getSection64(Sec); - Section.Address = Sect.addr; - Section.Size = Sect.size; - Section.Offset = Sect.offset; - Section.Alignment = Sect.align; + Section.Address = Sect.addr; + Section.Size = Sect.size; + Section.Offset = Sect.offset; + Section.Alignment = Sect.align; Section.RelocationTableOffset = Sect.reloff; Section.NumRelocationTableEntries = Sect.nreloc; - Section.Flags = Sect.flags; - Section.Reserved1 = Sect.reserved1; - Section.Reserved2 = Sect.reserved2; - Section.Reserved3 = Sect.reserved3; + Section.Flags = Sect.flags; + Section.Reserved1 = Sect.reserved1; + Section.Reserved2 = Sect.reserved2; + Section.Reserved3 = Sect.reserved3; } static void getSegment(const MachOObjectFile *Obj, @@ -390,24 +384,23 @@ Segment.flags = SC.flags; } -static void getSymbol(const MachOObjectFile *Obj, - DataRefImpl DRI, +static void getSymbol(const MachOObjectFile *Obj, DataRefImpl DRI, MachOSymbol &Symbol) { if (!Obj->is64Bit()) { MachO::nlist Entry = Obj->getSymbolTableEntry(DRI); - Symbol.StringIndex = Entry.n_strx; - Symbol.Type = Entry.n_type; + Symbol.StringIndex = Entry.n_strx; + Symbol.Type = Entry.n_type; Symbol.SectionIndex = Entry.n_sect; - Symbol.Flags = Entry.n_desc; - Symbol.Value = Entry.n_value; + Symbol.Flags = Entry.n_desc; + Symbol.Value = Entry.n_value; return; } MachO::nlist_64 Entry = Obj->getSymbol64TableEntry(DRI); - Symbol.StringIndex = Entry.n_strx; - Symbol.Type = Entry.n_type; + Symbol.StringIndex = Entry.n_strx; + Symbol.Type = Entry.n_type; Symbol.SectionIndex = Entry.n_sect; - Symbol.Flags = Entry.n_desc; - Symbol.Value = Entry.n_value; + Symbol.Flags = Entry.n_desc; + Symbol.Value = Entry.n_value; } void MachODumper::printFileHeaders() { @@ -420,7 +413,7 @@ } } -template +template void MachODumper::printFileHeaders(const MachHeader &Header) { W.printEnum("Magic", Header.magic, makeArrayRef(MachOMagics)); W.printEnum("CpuType", Header.cputype, makeArrayRef(MachOHeaderCpuTypes)); @@ -439,10 +432,12 @@ W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesPPC)); break; case MachO::CPU_TYPE_SPARC: - W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesSPARC)); + W.printEnum("CpuSubType", subtype, + makeArrayRef(MachOHeaderCpuSubtypesSPARC)); break; case MachO::CPU_TYPE_ARM64: - W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesARM64)); + W.printEnum("CpuSubType", subtype, + makeArrayRef(MachOHeaderCpuSubtypesARM64)); break; case MachO::CPU_TYPE_POWERPC64: default: @@ -587,17 +582,14 @@ SymbolNameOrOffset = TargetName; } - raw_ostream& OS = W.startLine(); - OS << W.hex(Offset) - << " " << Obj->getAnyRelocationPCRel(RE) - << " " << Obj->getAnyRelocationLength(RE); + raw_ostream &OS = W.startLine(); + OS << W.hex(Offset) << " " << Obj->getAnyRelocationPCRel(RE) << " " + << Obj->getAnyRelocationLength(RE); if (IsScattered) OS << " n/a"; else OS << " " << Obj->getPlainRelocationExternal(RE); - OS << " " << RelocName - << " " << IsScattered - << " " << SymbolNameOrOffset + OS << " " << RelocName << " " << IsScattered << " " << SymbolNameOrOffset << "\n"; } } @@ -610,20 +602,145 @@ return *SymbolNameOrErr; } -void MachODumper::printSymbols() { +namespace { +// Tuple of (type, name, string-representation) +using ExtractedSymbolInfo = std::tuple; +static constexpr int TYPE_IDX = 0; +static constexpr int NAME_IDX = 1; +static constexpr int STRINGREP_IDX = 2; + +class BaseSymbolCmp { +public: + explicit BaseSymbolCmp(opts::SortSymbolKeyTy SortKeyType) + : SortKeyType(SortKeyType) {} + virtual ~BaseSymbolCmp() = default; + + virtual bool EQ(const ExtractedSymbolInfo &LHS, + const ExtractedSymbolInfo &RHS) const = 0; + virtual bool LT(const ExtractedSymbolInfo &LHS, + const ExtractedSymbolInfo &RHS) const = 0; + opts::SortSymbolKeyTy SortKey() const { return SortKeyType; } + +private: + opts::SortSymbolKeyTy SortKeyType; +}; + +class SymbolNameCmp : public BaseSymbolCmp { +public: + SymbolNameCmp() : BaseSymbolCmp(opts::SortSymbolKeyTy::NAME) {} + bool EQ(const ExtractedSymbolInfo &LHS, + const ExtractedSymbolInfo &RHS) const override { + return std::get(LHS) == std::get(RHS); + } + + bool LT(const ExtractedSymbolInfo &LHS, + const ExtractedSymbolInfo &RHS) const override { + return std::get(LHS).compare(std::get(RHS)) < 0; + } +}; + +class SymbolTypeCmp : public BaseSymbolCmp { +public: + SymbolTypeCmp() : BaseSymbolCmp(opts::SortSymbolKeyTy::TYPE) {} + bool EQ(const ExtractedSymbolInfo &LHS, + const ExtractedSymbolInfo &RHS) const override { + return std::get(LHS) == std::get(RHS); + } + + bool LT(const ExtractedSymbolInfo &LHS, + const ExtractedSymbolInfo &RHS) const override { + return std::get(LHS) < std::get(RHS); + } +}; + +const BaseSymbolCmp &GetSymbolCmp(opts::SortSymbolKeyTy key) { + static const llvm::SmallVector SymbolCmpMap = []() { + llvm::SmallVector RetVal(2); + + const BaseSymbolCmp *ByType = new SymbolTypeCmp(); + RetVal[ByType->SortKey()] = ByType; + + const BaseSymbolCmp *ByName = new SymbolNameCmp; + RetVal[ByName->SortKey()] = ByName; + + return RetVal; + }(); + + assert(key < SymbolCmpMap.size() && "sort key out of range"); + + return *SymbolCmpMap[key]; +} +} // namespace + +void MachODumper::printSymbols( + const llvm::SmallVector *SortKeys) { ListScope Group(W, "Symbols"); - for (const SymbolRef &Symbol : Obj->symbols()) { - printSymbol(Symbol); + if (SortKeys && !SortKeys->empty()) { + // The references returned by calling Obj->symbols() are temporary, + // and we can't hold onto them after the loop. In order to sort the + // symbols, we have to print their representation to string and sort them + // later. + + // Sort by type (local/external/undefined) or name, or both, depending + // on the specified sort-keys. + std::vector SortedSymbols; + for (SymbolRef Symbol : Obj->symbols()) { + std::string SymRep; + raw_string_ostream StringOs(SymRep); + formatted_raw_ostream FormattedOs(StringOs); + ScopedPrinter Printer(FormattedOs); + Printer.indent(W.getIndentLevel()); + printSymbol(Symbol, Printer); + + const DataRefImpl &DRI = Symbol.getRawDataRefImpl(); + SortedSymbols.emplace_back(Obj->getSymbol64TableEntry(DRI).n_type, + Symbol.getName()->str(), std::move(SymRep)); + } + + llvm::stable_sort( + SortedSymbols, + [SortKeys](const std::tuple &LHS, + const std::tuple &RHS) { + for (opts::SortSymbolKeyTy key : *SortKeys) { + const BaseSymbolCmp &cmp = GetSymbolCmp(key); + if (cmp.EQ(LHS, RHS)) + continue; + return cmp.LT(LHS, RHS); + } + + return false; + }); + + // Unindent one level because the Symbols were already padded. + W.unindent(); + for (auto &Tup : SortedSymbols) + W.startLine() << std::get(Tup); + // Restore previous indentation. + W.indent(); + } else { + for (SymbolRef Symbol : Obj->symbols()) + printSymbol(Symbol); } } -void MachODumper::printDynamicSymbols() { +void MachODumper::printDynamicSymbols( + const llvm::SmallVector *SortKeys) { ListScope Group(W, "DynamicSymbols"); } void MachODumper::printSymbol(const SymbolRef &Symbol) { - StringRef SymbolName = getSymbolName(Symbol); + printSymbol(Symbol, W); +} + +void MachODumper::printSymbol(const SymbolRef &Symbol, ScopedPrinter &W) { + StringRef SymbolName; + Expected SymbolNameOrErr = Symbol.getName(); + if (!SymbolNameOrErr) { + // TODO: Actually report errors helpfully. + consumeError(SymbolNameOrErr.takeError()); + } else + SymbolName = *SymbolNameOrErr; MachOSymbol MOSymbol; getSymbol(Obj, Symbol.getRawDataRefImpl(), MOSymbol); @@ -692,11 +809,10 @@ arrayRefFromStringRef(StackMapContents); if (Obj->isLittleEndian()) - prettyPrintStackMap( - W, StackMapParser(StackMapContentsArray)); + prettyPrintStackMap(W, + StackMapParser(StackMapContentsArray)); else - prettyPrintStackMap( - W, StackMapParser(StackMapContentsArray)); + prettyPrintStackMap(W, StackMapParser(StackMapContentsArray)); } void MachODumper::printCGProfile() { @@ -756,7 +872,7 @@ Command.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) { MachO::dylib_command Dl = Obj->getDylibIDLoadCommand(Command); if (Dl.dylib.name < Dl.cmdsize) { - auto *P = static_cast(Command.Ptr) + Dl.dylib.name; + auto *P = static_cast(Command.Ptr) + Dl.dylib.name; Libs.push_back(P); } } @@ -771,7 +887,7 @@ void MachODumper::printMachODataInCode() { for (const auto &Load : Obj->load_commands()) { - if (Load.C.cmd == MachO::LC_DATA_IN_CODE) { + if (Load.C.cmd == MachO::LC_DATA_IN_CODE) { MachO::linkedit_data_command LLC = Obj->getLinkeditDataLoadCommand(Load); DictScope Group(W, "DataInCode"); W.printNumber("Data offset", LLC.dataoff); @@ -779,8 +895,8 @@ ListScope D(W, "Data entries"); unsigned NumRegions = LLC.datasize / sizeof(MachO::data_in_code_entry); for (unsigned i = 0; i < NumRegions; ++i) { - MachO::data_in_code_entry DICE = Obj->getDataInCodeTableEntry( - LLC.dataoff, i); + MachO::data_in_code_entry DICE = + Obj->getDataInCodeTableEntry(LLC.dataoff, i); DictScope Group(W, "Entry"); W.printNumber("Index", i); W.printNumber("Offset", DICE.offset); @@ -929,7 +1045,7 @@ const char *P = Load.Ptr + sizeof(MachO::linker_option_command); StringRef Data(P, DataSize); for (unsigned i = 0; i < LOLC.count; ++i) { - std::pair Split = Data.split('\0'); + std::pair Split = Data.split('\0'); W.printString("Value", Split.first); Data = Split.second; } diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h --- a/llvm/tools/llvm-readobj/ObjDumper.h +++ b/llvm/tools/llvm-readobj/ObjDumper.h @@ -12,12 +12,22 @@ #include #include +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" #include +namespace opts { +enum SortSymbolKeyTy { + NAME = 0, + TYPE = 1, + UNSPEC = 100, + // TODO: add ADDRESS, SIZE as needed. +}; +} + namespace llvm { namespace object { class Archive; @@ -25,7 +35,7 @@ class ObjectFile; class XCOFFObjectFile; class ELFObjectFileBase; -} +} // namespace object namespace codeview { class GlobalTypeTableBuilder; class MergingTypeTableBuilder; @@ -47,11 +57,17 @@ virtual void printSectionHeaders() = 0; virtual void printRelocations() = 0; virtual void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) { + printSymbols(PrintSymbols, PrintDynamicSymbols, nullptr); + } + virtual void + printSymbols(bool PrintSymbols, bool PrintDynamicSymbols, + const llvm::SmallVector *SortKeys) { if (PrintSymbols) - printSymbols(); + printSymbols(SortKeys); if (PrintDynamicSymbols) - printDynamicSymbols(); + printDynamicSymbols(SortKeys); } + virtual void printProgramHeaders(bool PrintProgramHeaders, cl::boolOrDefault PrintSectionMapping) { if (PrintProgramHeaders) @@ -64,11 +80,11 @@ // Only implemented for ELF at this time. virtual void printDependentLibs() {} - virtual void printDynamicRelocations() { } - virtual void printDynamicTable() { } - virtual void printNeededLibraries() { } + virtual void printDynamicRelocations() {} + virtual void printDynamicTable() {} + virtual void printNeededLibraries() {} virtual void printSectionAsHex(StringRef SectionName) {} - virtual void printHashTable() { } + virtual void printHashTable() {} virtual void printGnuHashTable() {} virtual void printHashSymbols() {} virtual void printLoadName() {} @@ -85,15 +101,15 @@ virtual void printArchSpecificInfo() {} // Only implemented for PE/COFF. - virtual void printCOFFImports() { } - virtual void printCOFFExports() { } - virtual void printCOFFDirectives() { } - virtual void printCOFFBaseReloc() { } - virtual void printCOFFDebugDirectory() { } + virtual void printCOFFImports() {} + virtual void printCOFFExports() {} + virtual void printCOFFDirectives() {} + virtual void printCOFFBaseReloc() {} + virtual void printCOFFDebugDirectory() {} virtual void printCOFFTLSDirectory() {} virtual void printCOFFResources() {} - virtual void printCOFFLoadConfig() { } - virtual void printCodeViewDebugInfo() { } + virtual void printCOFFLoadConfig() {} + virtual void printCodeViewDebugInfo() {} virtual void mergeCodeViewTypes(llvm::codeview::MergingTypeTableBuilder &CVIDs, llvm::codeview::MergingTypeTableBuilder &CVTypes, @@ -105,15 +121,15 @@ virtual void printAuxiliaryHeader() {} // Only implemented for MachO. - virtual void printMachODataInCode() { } - virtual void printMachOVersionMin() { } - virtual void printMachODysymtab() { } - virtual void printMachOSegment() { } - virtual void printMachOIndirectSymbols() { } - virtual void printMachOLinkerOptions() { } + virtual void printMachODataInCode() {} + virtual void printMachOVersionMin() {} + virtual void printMachODysymtab() {} + virtual void printMachOSegment() {} + virtual void printMachOIndirectSymbols() {} + virtual void printMachOLinkerOptions() {} // Currently only implemented for XCOFF. - virtual void printStringTable() { } + virtual void printStringTable() {} virtual void printStackMap() const = 0; @@ -132,8 +148,12 @@ ScopedPrinter &W; private: - virtual void printSymbols() {} - virtual void printDynamicSymbols() {} + virtual void printSymbols() { printSymbols(nullptr); } + virtual void + printSymbols(const llvm::SmallVector *SortKeys) {} + virtual void printDynamicSymbols() { printDynamicSymbols(nullptr); } + virtual void printDynamicSymbols( + const llvm::SmallVector *SortKeys) {} virtual void printProgramHeaders() {} virtual void printSectionMapping() {} diff --git a/llvm/tools/llvm-readobj/Opts.td b/llvm/tools/llvm-readobj/Opts.td --- a/llvm/tools/llvm-readobj/Opts.td +++ b/llvm/tools/llvm-readobj/Opts.td @@ -37,6 +37,8 @@ def section_mapping_EQ_false : FF<"section-mapping=false", "Don't display the section to segment mapping">, Flags<[HelpHidden]>; def section_relocations : FF<"section-relocations", "Display relocations for each section shown. This option has no effect for GNU style output">; def section_symbols : FF<"section-symbols", "Display symbols for each section shown. This option has no effect for GNU style output">; +defm sort_symbols : Eq<"sort-symbols", "Specify the keys to sort the symbols before displaying symtab">; + def stack_sizes : FF<"stack-sizes", "Display contents of all stack sizes sections. This option has no effect for GNU style output">; def stackmap : FF<"stackmap", "Display contents of stackmap section">; defm string_dump : Eq<"string-dump", "Display the specified section(s) as a list of strings">, MetaVarName<"">; diff --git a/llvm/tools/llvm-readobj/llvm-readobj.h b/llvm/tools/llvm-readobj/llvm-readobj.h --- a/llvm/tools/llvm-readobj/llvm-readobj.h +++ b/llvm/tools/llvm-readobj/llvm-readobj.h @@ -9,26 +9,28 @@ #ifndef LLVM_TOOLS_LLVM_READOBJ_LLVM_READOBJ_H #define LLVM_TOOLS_LLVM_READOBJ_LLVM_READOBJ_H +#include "ObjDumper.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/ErrorOr.h" #include "llvm/Support/Error.h" +#include "llvm/Support/ErrorOr.h" #include namespace llvm { - namespace object { - class RelocationRef; - } - - // Various helper functions. - [[noreturn]] void reportError(Error Err, StringRef Input); - void reportWarning(Error Err, StringRef Input); - - template T unwrapOrError(StringRef Input, Expected EO) { - if (EO) - return *EO; - reportError(EO.takeError(), Input); - } +namespace object { +class RelocationRef; +} + +// Various helper functions. +[[noreturn]] void reportError(Error Err, StringRef Input); +void reportWarning(Error Err, StringRef Input); + +template T unwrapOrError(StringRef Input, Expected EO) { + if (EO) + return *EO; + reportError(EO.takeError(), Input); +} } // namespace llvm namespace opts { @@ -41,12 +43,13 @@ extern bool Demangle; enum OutputStyleTy { LLVM, GNU, JSON, UNKNOWN }; extern OutputStyleTy Output; +extern llvm::SmallVector SortKeys; } // namespace opts -#define LLVM_READOBJ_ENUM_ENT(ns, enum) \ +#define LLVM_READOBJ_ENUM_ENT(ns, enum) \ { #enum, ns::enum } -#define LLVM_READOBJ_ENUM_CLASS_ENT(enum_class, enum) \ - { #enum, std::underlying_type::type(enum_class::enum) } +#define LLVM_READOBJ_ENUM_CLASS_ENT(enum_class, enum) \ + { #enum, std::underlying_type < enum_class> ::type(enum_class::enum) } #endif diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -21,6 +21,7 @@ #include "llvm-readobj.h" #include "ObjDumper.h" #include "WindowsResourceDumper.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h" #include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h" #include "llvm/MC/TargetRegistry.h" @@ -113,6 +114,7 @@ static bool Symbols; static bool UnwindInfo; static cl::boolOrDefault SectionMapping; +llvm::SmallVector SortKeys; // ELF specific options. static bool DynamicTable; @@ -178,6 +180,11 @@ llvm_unreachable("error() call should never return"); } +static void warn(Twine Msg) { + fouts().flush(); + WithColor::warning(errs(), ToolName) << Msg << "\n"; +} + void reportWarning(Error Err, StringRef Input) { assert(Err); if (Input == "-") @@ -253,6 +260,28 @@ opts::ProgramHeaders = Args.hasArg(OPT_program_headers); opts::RawRelr = Args.hasArg(OPT_raw_relr); opts::SectionGroups = Args.hasArg(OPT_section_groups); + if (Arg *A = Args.getLastArg(OPT_sort_symbols_EQ)) { + std::string SortKeysString = A->getValue(); + int pos = 0; + for (llvm::StringRef KeyStr : llvm::split(A->getValue(), ",")) { + if (!KeyStr.empty()) { + opts::SortSymbolKeyTy KeyType = + StringSwitch(KeyStr) + .Case("name", opts::SortSymbolKeyTy::NAME) + .Case("type", opts::SortSymbolKeyTy::TYPE) + .Default(opts::SortSymbolKeyTy::UNSPEC); + if (KeyType == opts::SortSymbolKeyTy::UNSPEC) + error("--sort-symbols value should be 'name' or 'type', but was '" + + Twine(KeyStr) + "'"); + else + opts::SortKeys.push_back(KeyType); + } else { + warn("ignored empty sort key specified in --sort-symbols='" + + SortKeysString + "' at position " + Twine(pos)); + } + ++pos; + } + } opts::VersionInfo = Args.hasArg(OPT_version_info); // Mach-O specific options. @@ -374,7 +403,7 @@ if (opts::UnwindInfo) Dumper->printUnwindInfo(); if (opts::Symbols || opts::DynamicSymbols) - Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols); + Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols, &opts::SortKeys); if (!opts::StringDump.empty()) Dumper->printSectionsAsString(Obj, opts::StringDump); if (!opts::HexDump.empty()) @@ -505,7 +534,6 @@ reportError(std::move(Err), WinRes->getFileName()); } - /// Opens \a File and dumps it. static void dumpInput(StringRef File, ScopedPrinter &Writer) { ErrorOr> FileOrErr =