diff --git a/llvm/docs/CommandGuide/index.rst b/llvm/docs/CommandGuide/index.rst --- a/llvm/docs/CommandGuide/index.rst +++ b/llvm/docs/CommandGuide/index.rst @@ -29,6 +29,7 @@ llvm-link llvm-lipo llvm-mca + llvm-otool llvm-profdata llvm-readobj llvm-stress diff --git a/llvm/docs/CommandGuide/llvm-objdump.rst b/llvm/docs/CommandGuide/llvm-objdump.rst --- a/llvm/docs/CommandGuide/llvm-objdump.rst +++ b/llvm/docs/CommandGuide/llvm-objdump.rst @@ -390,4 +390,5 @@ SEE ALSO -------- -:manpage:`llvm-nm(1)`, :manpage:`llvm-readelf(1)`, :manpage:`llvm-readobj(1)` +:manpage:`llvm-nm(1)`, :manpage:`llvm-otool(1)`, :manpage:`llvm-readelf(1)`, +:manpage:`llvm-readobj(1)` diff --git a/llvm/docs/CommandGuide/llvm-otool.rst b/llvm/docs/CommandGuide/llvm-otool.rst new file mode 100644 --- /dev/null +++ b/llvm/docs/CommandGuide/llvm-otool.rst @@ -0,0 +1,140 @@ +llvm-otool - Mach-O dumping tool +================================ + +.. program:: llvm-otool + +SYNOPSIS +-------- + +:program:`llvm-otool` [*option...*] *[file...]* + +DESCRIPTION +----------- + +:program:`llvm-otool` is a tool for dumping Mach-O files. + +It attempts to be command-line-compatible and output-compatible with macOS's +:program:`otool`. + +OPTIONS +------- + +.. option:: -arch + + Select slice of universal Mach-O file. + +.. option:: -C + + Print linker optimization hints. + +.. option:: -D + + Print shared library id. + +.. option:: -d + + Print data section. + +.. option:: -f + + Print universal headers. + +.. option:: -G + + Print data-in-code table. + +.. option:: --help-hidden + + Print help for hidden flags. + +.. option:: --help + + Print help. + +.. option:: -h + + Print mach header. + +.. option:: -I + + Print indirect symbol table. + +.. option:: -j + + Print opcode bytes. + +.. option:: -L + + Print used shared libraries. + +.. option:: -l + + Print load commnads. + +.. option:: -mcpu= + + Select cpu for disassembly. + +.. option:: -o + + Print Objective-C segment. + +.. option:: -P + + Print __TEXT,__info_plist section as strings. + +.. option:: -p + + Start disassembly at . + +.. option:: -r + + Print relocation entries. + +.. option:: -s + + Print contents of section. + +.. option:: -t + + Print text section. + +.. option:: --version + + Print version. + +.. option:: -V + + Symbolize disassembled operands (implies :option:`-v`). + +.. option:: -v + + Verbose output / disassemble when printing text sections. + +.. option:: -X + + Omit leading addresses or headers. + +.. option:: -x + + Print all text sections. + +.. option:: @ + + Read command-line options and commands from response file ``. + +EXIT STATUS +----------- + +:program:`llvm-otool` exits with a non-zero exit code if there is an error. +Otherwise, it exits with code 0. + +BUGS +---- + +To report bugs, please visit . + +SEE ALSO +-------- + +:manpage:`llvm-nm(1)`, :manpage:`llvm-objdump(1)` diff --git a/llvm/test/CMakeLists.txt b/llvm/test/CMakeLists.txt --- a/llvm/test/CMakeLists.txt +++ b/llvm/test/CMakeLists.txt @@ -100,6 +100,7 @@ llvm-objdump llvm-opt-fuzzer llvm-opt-report + llvm-otool llvm-pdbutil llvm-profdata llvm-profgen diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py --- a/llvm/test/lit.cfg.py +++ b/llvm/test/lit.cfg.py @@ -160,7 +160,7 @@ 'llvm-isel-fuzzer', 'llvm-ifs', 'llvm-install-name-tool', 'llvm-jitlink', 'llvm-opt-fuzzer', 'llvm-lib', 'llvm-link', 'llvm-lto', 'llvm-lto2', 'llvm-mc', 'llvm-mca', - 'llvm-modextract', 'llvm-nm', 'llvm-objcopy', 'llvm-objdump', + 'llvm-modextract', 'llvm-nm', 'llvm-objcopy', 'llvm-objdump', 'llvm-otool', 'llvm-pdbutil', 'llvm-profdata', 'llvm-ranlib', 'llvm-rc', 'llvm-readelf', 'llvm-readobj', 'llvm-rtdyld', 'llvm-size', 'llvm-split', 'llvm-strings', 'llvm-strip', 'llvm-tblgen', 'llvm-undname', 'llvm-c-test', 'llvm-cxxfilt', diff --git a/llvm/test/tools/llvm-objdump/MachO/AArch64/macho-link-opt-hints.test b/llvm/test/tools/llvm-objdump/MachO/AArch64/macho-link-opt-hints.test --- a/llvm/test/tools/llvm-objdump/MachO/AArch64/macho-link-opt-hints.test +++ b/llvm/test/tools/llvm-objdump/MachO/AArch64/macho-link-opt-hints.test @@ -1,4 +1,5 @@ RUN: llvm-objdump -m --link-opt-hints %p/Inputs/link-opt-hints.macho-aarch64 | FileCheck %s +RUN: llvm-otool -C %p/Inputs/link-opt-hints.macho-aarch64 | FileCheck %s CHECK: Linker optimiztion hints (8 total bytes) CHECK: identifier 8 AdrpLdrGot diff --git a/llvm/test/tools/llvm-objdump/MachO/ARM/data-in-code.test b/llvm/test/tools/llvm-objdump/MachO/ARM/data-in-code.test --- a/llvm/test/tools/llvm-objdump/MachO/ARM/data-in-code.test +++ b/llvm/test/tools/llvm-objdump/MachO/ARM/data-in-code.test @@ -1,5 +1,7 @@ RUN: llvm-objdump -m --data-in-code %p/Inputs/data-in-code.macho-arm | FileCheck %s +RUN: llvm-otool -Gv %p/Inputs/data-in-code.macho-arm | FileCheck %s RUN: llvm-objdump -m --data-in-code --non-verbose %p/Inputs/data-in-code.macho-arm | FileCheck %s --check-prefix=NON_VERBOSE +RUN: llvm-otool -G %p/Inputs/data-in-code.macho-arm | FileCheck %s --check-prefix=NON_VERBOSE CHECK: Data in code table (4 entries) CHECK: offset length kind diff --git a/llvm/test/tools/llvm-objdump/MachO/ARM/mcpu-arm.test b/llvm/test/tools/llvm-objdump/MachO/ARM/mcpu-arm.test --- a/llvm/test/tools/llvm-objdump/MachO/ARM/mcpu-arm.test +++ b/llvm/test/tools/llvm-objdump/MachO/ARM/mcpu-arm.test @@ -1,4 +1,6 @@ -@ RUN: llvm-mc < %s -triple thumbv7-apple-darwin -mcpu=cortex-a7 -filetype=obj | llvm-objdump --triple thumbv7-apple-darwin10 -m -d --mcpu=cortex-a7 - | FileCheck %s +@ RUN: llvm-mc %s -triple thumbv7-apple-darwin -mcpu=cortex-a7 -filetype=obj -o %t.o +@ RUN: llvm-objdump --triple thumbv7-apple-darwin10 -m -d --mcpu=cortex-a7 %t.o | FileCheck %s +@ RUN: llvm-otool -tv -mcpu=cortex-a7 %t.o | FileCheck %s .thumb .thumb_func _t diff --git a/llvm/test/tools/llvm-objdump/MachO/data-in-code.ll b/llvm/test/tools/llvm-objdump/MachO/data-in-code.ll --- a/llvm/test/tools/llvm-objdump/MachO/data-in-code.ll +++ b/llvm/test/tools/llvm-objdump/MachO/data-in-code.ll @@ -1,5 +1,6 @@ ; RUN: llc --mtriple x86_64-apple-darwin -filetype=obj -O0 %s -o %t.o ; RUN: llvm-objdump --macho -d --no-show-raw-insn %t.o | FileCheck %s +; RUN: llvm-otool -tv %t.o | FileCheck %s ; CHECK: .long {{[0-9]+}} @ KIND_JUMP_TABLE32 ; CHECK: .long {{[0-9]+}} @ KIND_JUMP_TABLE32 diff --git a/llvm/test/tools/llvm-objdump/MachO/dis-no-leading-addr.test b/llvm/test/tools/llvm-objdump/MachO/dis-no-leading-addr.test --- a/llvm/test/tools/llvm-objdump/MachO/dis-no-leading-addr.test +++ b/llvm/test/tools/llvm-objdump/MachO/dis-no-leading-addr.test @@ -1,6 +1,7 @@ -# RUN: llvm-objdump --macho -d %p/Inputs/hello.obj.macho-x86_64 --no-show-raw-insn --print-imm-hex --no-leading-addr | FileCheck %s +# RUN: llvm-objdump --macho -d %p/Inputs/hello.obj.macho-x86_64 --no-show-raw-insn --print-imm-hex --no-leading-addr | FileCheck --check-prefixes=CHECK,HEAD %s +# RUN: llvm-otool -tVX %p/Inputs/hello.obj.macho-x86_64 | FileCheck --implicit-check-not=section %s -# CHECK: (__TEXT,__text) section +# HEAD: (__TEXT,__text) section # CHECK: _main: # CHECK: pushq %rbp # CHECK: movq %rsp, %rbp diff --git a/llvm/test/tools/llvm-objdump/MachO/dis-symname.test b/llvm/test/tools/llvm-objdump/MachO/dis-symname.test --- a/llvm/test/tools/llvm-objdump/MachO/dis-symname.test +++ b/llvm/test/tools/llvm-objdump/MachO/dis-symname.test @@ -1,4 +1,5 @@ # RUN: llvm-objdump --macho -d %p/Inputs/exeThread.macho-x86_64 --dis-symname start --no-show-raw-insn --full-leading-addr --print-imm-hex | FileCheck %s +# RUN: llvm-otool -tV %p/Inputs/exeThread.macho-x86_64 -p start | FileCheck %s # CHECK: (__TEXT,__text) section # CHECK: start: @@ -18,8 +19,8 @@ # CHECK-NOT: 0000000100000d22 # CHECK-NOT: _main: -# not RUN: llvm-objdump --macho -d %p/Inputs/exeThread.macho-x86_64 --dis-symname _environ 2>&1 | FileCheck --check-prefix BAD-SYMAME-1 %s +# RUN: llvm-objdump --macho -d %p/Inputs/exeThread.macho-x86_64 --dis-symname _environ 2>&1 | FileCheck --check-prefix BAD-SYMAME-1 %s BAD-SYMAME-1: -dis-symname: _environ not in the section -# not RUN: llvm-objdump --macho -d %p/Inputs/exeThread.macho-x86_64 --dis-symname __mh_execute_header 2>&1 | FileCheck --check-prefix BAD-SYMAME-2 %s +# RUN: llvm-objdump --macho -d %p/Inputs/exeThread.macho-x86_64 --dis-symname __mh_execute_header 2>&1 | FileCheck --check-prefix BAD-SYMAME-2 %s BAD-SYMAME-2: -dis-symname: __mh_execute_header not in any section diff --git a/llvm/test/tools/llvm-objdump/MachO/dylib.test b/llvm/test/tools/llvm-objdump/MachO/dylib.test --- a/llvm/test/tools/llvm-objdump/MachO/dylib.test +++ b/llvm/test/tools/llvm-objdump/MachO/dylib.test @@ -1,4 +1,5 @@ RUN: llvm-objdump --macho --dylibs-used %p/Inputs/dylibLoadKinds.macho-x86_64 | FileCheck %s --check-prefix=USED +RUN: llvm-otool -L %p/Inputs/dylibLoadKinds.macho-x86_64 | FileCheck %s --check-prefix=USED USED: /usr/lib/foo1.dylib (compatibility version 0.0.0, current version 0.0.0) USED: /usr/lib/foo2.dylib (compatibility version 0.0.0, current version 0.0.0, weak) USED: /usr/lib/foo3.dylib (compatibility version 0.0.0, current version 0.0.0, reexport) @@ -6,8 +7,10 @@ USED: /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1) RUN: llvm-objdump --macho --dylib-id %p/Inputs/dylibLoadKinds.macho-x86_64 | FileCheck %s --check-prefix=ID +RUN: llvm-otool -D %p/Inputs/dylibLoadKinds.macho-x86_64 | FileCheck %s --check-prefix=ID ID: /usr/lib/foo.dylib RUN: llvm-objdump --macho --dylib-id --no-leading-headers %p/Inputs/dylibLoadKinds.macho-x86_64 | FileCheck %s --check-prefix=IDNOHEADERS +RUN: llvm-otool -DX %p/Inputs/dylibLoadKinds.macho-x86_64 | FileCheck %s --check-prefix=IDNOHEADERS IDNOHEADERS-NOT: dylibLoadKinds.macho-x86_64: IDNOHEADERS: /usr/lib/foo.dylib diff --git a/llvm/test/tools/llvm-objdump/MachO/indirect-symbols.test b/llvm/test/tools/llvm-objdump/MachO/indirect-symbols.test --- a/llvm/test/tools/llvm-objdump/MachO/indirect-symbols.test +++ b/llvm/test/tools/llvm-objdump/MachO/indirect-symbols.test @@ -1,5 +1,7 @@ RUN: llvm-objdump --macho --indirect-symbols %p/Inputs/hello.exe.macho-x86_64 | FileCheck %s +RUN: llvm-otool -Iv %p/Inputs/hello.exe.macho-x86_64 | FileCheck %s RUN: llvm-objdump --macho --indirect-symbols --non-verbose %p/Inputs/hello.exe.macho-x86_64 | FileCheck %s --check-prefix=NON_VERBOSE +RUN: llvm-otool -I %p/Inputs/hello.exe.macho-x86_64 | FileCheck %s --check-prefix=NON_VERBOSE CHECK: Indirect symbols for (__TEXT,__stubs) 1 entries CHECK: address index name diff --git a/llvm/test/tools/llvm-objdump/MachO/info-plist.test b/llvm/test/tools/llvm-objdump/MachO/info-plist.test --- a/llvm/test/tools/llvm-objdump/MachO/info-plist.test +++ b/llvm/test/tools/llvm-objdump/MachO/info-plist.test @@ -1,5 +1,8 @@ -# RUN: llvm-mc < %s --triple x86_64-apple-darwin -filetype=obj | llvm-objdump --macho --info-plist - | FileCheck %s -# RUN: llvm-mc < %s --triple x86_64-apple-darwin -filetype=obj | llvm-objdump --macho --info-plist --no-leading-headers - | FileCheck --check-prefix=NOHEADER %s +# RUN: llvm-mc %s --triple x86_64-apple-darwin -filetype=obj -o %t.o +# RUN: llvm-objdump --macho --info-plist %t.o | FileCheck %s +# RUN: llvm-otool -P %t.o | FileCheck %s +# RUN: llvm-objdump --macho --info-plist --no-leading-headers %t.o | FileCheck --check-prefix=NOHEADER %s +# RUN: llvm-otool -PX %t.o | FileCheck --check-prefix=NOHEADER %s .section __TEXT, __info_plist .asciz "\n" diff --git a/llvm/test/tools/llvm-objdump/MachO/macho-objc-meta-data.test b/llvm/test/tools/llvm-objdump/MachO/macho-objc-meta-data.test --- a/llvm/test/tools/llvm-objdump/MachO/macho-objc-meta-data.test +++ b/llvm/test/tools/llvm-objdump/MachO/macho-objc-meta-data.test @@ -1,4 +1,5 @@ # RUN: llvm-objdump --macho --objc-meta-data %p/Inputs/Objc2.64bit.exe.macho-x86_64 | FileCheck %s --check-prefix=OBJC2_64BIT_EXE +# RUN: llvm-otool -o %p/Inputs/Objc2.64bit.exe.macho-x86_64 | FileCheck %s --check-prefix=OBJC2_64BIT_EXE # RUN: llvm-objdump --macho --objc-meta-data %p/Inputs/Objc2.64bit.obj.macho-x86_64 | FileCheck %s --check-prefix=OBJC2_64BIT_OBJ # RUN: llvm-objdump --macho --objc-meta-data %p/Inputs/Objc2.32bit.exe.macho-i386 | FileCheck %s --check-prefix=OBJC2_32BIT_EXE # RUN: llvm-objdump --macho --objc-meta-data %p/Inputs/Objc2.32bit.obj.macho-i386 | FileCheck %s --check-prefix=OBJC2_32BIT_OBJ diff --git a/llvm/test/tools/llvm-objdump/MachO/private-headers.test b/llvm/test/tools/llvm-objdump/MachO/private-headers.test --- a/llvm/test/tools/llvm-objdump/MachO/private-headers.test +++ b/llvm/test/tools/llvm-objdump/MachO/private-headers.test @@ -1,4 +1,5 @@ // RUN: llvm-objdump -p %p/Inputs/hello.obj.macho-x86_64 | FileCheck %s +// RUN: llvm-otool -lv %p/Inputs/hello.obj.macho-x86_64 | FileCheck %s // RUN: llvm-objdump -p %p/Inputs/hello.exe.macho-x86_64 \ // RUN: | FileCheck %s -check-prefix=EXE // RUN: llvm-objdump -p %p/Inputs/dylibLoadKinds.macho-x86_64 \ diff --git a/llvm/test/tools/llvm-objdump/MachO/relocations.test b/llvm/test/tools/llvm-objdump/MachO/relocations.test --- a/llvm/test/tools/llvm-objdump/MachO/relocations.test +++ b/llvm/test/tools/llvm-objdump/MachO/relocations.test @@ -1,9 +1,24 @@ -RUN: llvm-objdump --macho -r %p/Inputs/hello.obj.macho-x86_64 | FileCheck %s +RUN: llvm-objdump --macho -r %p/Inputs/hello.obj.macho-x86_64 | \ +RUN: FileCheck --check-prefix=VERBOSE %s +RUN: llvm-otool -rv %p/Inputs/hello.obj.macho-x86_64 | \ +RUN: FileCheck --check-prefix=VERBOSE %s +RUN: llvm-objdump --macho -r --non-verbose %p/Inputs/hello.obj.macho-x86_64 | \ +RUN: FileCheck --check-prefix=NONVERBOSE %s +RUN: llvm-otool -r %p/Inputs/hello.obj.macho-x86_64 | \ +RUN: FileCheck --check-prefix=NONVERBOSE %s -CHECK: Relocation information (__TEXT,__text) 2 entries -CHECK: address pcrel length extern type scattered symbolnum/value -CHECK: 00000027 True long True BRANCH False _printf -CHECK: 0000000b True long True SIGNED False L_.str -CHECK: Relocation information (__LD,__compact_unwind) 1 entries -CHECK: address pcrel length extern type scattered symbolnum/value -CHECK: 00000000 False quad False UNSIGND False 1 (__TEXT,__text) +VERBOSE: Relocation information (__TEXT,__text) 2 entries +VERBOSE-NEXT: address pcrel length extern type scattered symbolnum/value +VERBOSE-NEXT: 00000027 True long True BRANCH False _printf +VERBOSE-NEXT: 0000000b True long True SIGNED False L_.str +VERBOSE-NEXT: Relocation information (__LD,__compact_unwind) 1 entries +VERBOSE-NEXT: address pcrel length extern type scattered symbolnum/value +VERBOSE-NEXT: 00000000 False quad False UNSIGND False 1 (__TEXT,__text) + +NONVERBOSE: Relocation information (__TEXT,__text) 2 entries +NONVERBOSE-NEXT: address pcrel length extern type scattered symbolnum/value +NONVERBOSE-NEXT: 00000027 1 2 1 2 0 4 +NONVERBOSE-NEXT: 0000000b 1 2 1 1 0 0 +NONVERBOSE-NEXT: Relocation information (__LD,__compact_unwind) 1 entries +NONVERBOSE-NEXT: address pcrel length extern type scattered symbolnum/value +NONVERBOSE-NEXT: 00000000 0 3 0 0 0 1 diff --git a/llvm/test/tools/llvm-objdump/MachO/sections.test b/llvm/test/tools/llvm-objdump/MachO/sections.test --- a/llvm/test/tools/llvm-objdump/MachO/sections.test +++ b/llvm/test/tools/llvm-objdump/MachO/sections.test @@ -1,4 +1,5 @@ # RUN: llvm-objdump --macho --section=__data %p/Inputs/bind2.macho-x86_64 | FileCheck %s +# RUN: llvm-otool -d %p/Inputs/bind2.macho-x86_64 | FileCheck %s # CHECK: bind2.macho-x86_64: diff --git a/llvm/test/tools/llvm-objdump/MachO/symbolized-disassembly.test b/llvm/test/tools/llvm-objdump/MachO/symbolized-disassembly.test --- a/llvm/test/tools/llvm-objdump/MachO/symbolized-disassembly.test +++ b/llvm/test/tools/llvm-objdump/MachO/symbolized-disassembly.test @@ -1,5 +1,7 @@ // RUN: llvm-objdump -d --macho --no-show-raw-insn --full-leading-addr --print-imm-hex %p/Inputs/hello.obj.macho-x86_64 | FileCheck %s --check-prefix=OBJ +// RUN: llvm-otool -tV %p/Inputs/hello.obj.macho-x86_64 | FileCheck %s --check-prefix=OBJ // RUN: llvm-objdump -d --macho --no-show-raw-insn --full-leading-addr --print-imm-hex %p/Inputs/hello.exe.macho-x86_64 | FileCheck %s --check-prefix=EXE +// RUN: llvm-otool -tV %p/Inputs/hello.exe.macho-x86_64 | FileCheck %s --check-prefix=EXE // RUN: llvm-objdump -d --macho --no-show-raw-insn --full-leading-addr --print-imm-hex %p/Inputs/ObjC.obj.macho-x86_64 | FileCheck %s --check-prefix=ObjC-OBJ // RUN: llvm-objdump -d --macho --no-show-raw-insn --full-leading-addr --print-imm-hex %p/Inputs/ObjC.exe.macho-x86_64 | FileCheck %s --check-prefix=ObjC-EXE // RUN: llvm-objdump -d --macho --no-show-raw-insn --full-leading-addr --print-imm-hex %p/Inputs/hello_cpp.exe.macho-x86_64 | FileCheck %s --check-prefix=CXX-EXE @@ -8,7 +10,9 @@ // RUN: llvm-objdump -d --macho --no-show-raw-insn --full-leading-addr --print-imm-hex %p/Inputs/hello.exe.macho-i386 | FileCheck %s --check-prefix=i386-EXE // RUN: llvm-objdump -d --macho --no-show-raw-insn --full-leading-addr --print-imm-hex --no-symbolic-operands %p/Inputs/hello.obj.macho-x86_64 | FileCheck %s --check-prefix=NO-SYM-OPS-OBJ +// RUN: llvm-otool -tv %p/Inputs/hello.obj.macho-x86_64 | FileCheck %s --check-prefix=NO-SYM-OPS-OBJ // RUN: llvm-objdump -d --macho --no-show-raw-insn --full-leading-addr --print-imm-hex --no-symbolic-operands %p/Inputs/hello.exe.macho-x86_64 | FileCheck %s --check-prefix=NO-SYM-OPS-EXE +// RUN: llvm-otool -tv %p/Inputs/hello.exe.macho-x86_64 | FileCheck %s --check-prefix=NO-SYM-OPS-EXE OBJ: 0000000000000008 leaq L_.str(%rip), %rax ## literal pool for: "Hello world\n" OBJ: 0000000000000026 callq _printf diff --git a/llvm/test/tools/llvm-objdump/MachO/universal-arm64.test b/llvm/test/tools/llvm-objdump/MachO/universal-arm64.test --- a/llvm/test/tools/llvm-objdump/MachO/universal-arm64.test +++ b/llvm/test/tools/llvm-objdump/MachO/universal-arm64.test @@ -4,6 +4,10 @@ # RUN: yaml2obj %s -o %tarm.o # RUN: llvm-objdump %tarm.o --universal-headers --macho | \ # RUN: FileCheck %s --match-full-lines +# RUN: llvm-otool -fv %tarm.o | FileCheck %s --match-full-lines +# RUN: llvm-objdump %tarm.o --universal-headers --macho --non-verbose | \ +# RUN: FileCheck %s --match-full-lines --check-prefix=NONVERBOSE +# RUN: llvm-otool -f %tarm.o | FileCheck %s --match-full-lines --check-prefix=NONVERBOSE # CHECK: Fat headers # CHECK-NEXT: fat_magic FAT_MAGIC @@ -31,6 +35,33 @@ # CHECK-NEXT: align 2^12 (4096) # CHECK-NOT:{{.}} +# NONVERBOSE: Fat headers +# NONVERBOSE-NEXT: fat_magic 0xcafebabe +# NONVERBOSE-NEXT: nfat_arch 3 +# NONVERBOSE-NEXT: architecture 0 +# NONVERBOSE-NEXT: cputype 16777228 +# NONVERBOSE-NEXT: cpusubtype 0 +# NONVERBOSE-NEXT: capabilities 0x0 +# NONVERBOSE-NEXT: offset 4096 +# NONVERBOSE-NEXT: size 352 +# NONVERBOSE-NEXT: align 2^12 (4096) +# NONVERBOSE-NEXT: architecture 1 +# NONVERBOSE-NEXT: cputype 16777228 +# NONVERBOSE-NEXT: cpusubtype 1 +# NONVERBOSE-NEXT: capabilities 0x0 +# NONVERBOSE-NEXT: offset 16384 +# NONVERBOSE-NEXT: size 384 +# NONVERBOSE-NEXT: align 2^14 (16384) +# NONVERBOSE-NEXT: architecture 2 +# NONVERBOSE-NEXT: cputype 16777228 +# NONVERBOSE-NEXT: cpusubtype 2 +# NONVERBOSE-NEXT: capabilities 0x0 +# NONVERBOSE-NEXT: offset 28672 +# NONVERBOSE-NEXT: size 384 +# NONVERBOSE-NEXT: align 2^12 (4096) +# NONVERBOSE-NOT:{{.}} + + --- !fat-mach-o FatHeader: magic: 0xCAFEBABE diff --git a/llvm/test/tools/llvm-objdump/tool-name.test b/llvm/test/tools/llvm-objdump/tool-name.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/tool-name.test @@ -0,0 +1,15 @@ +## Don't make symlinks on Windows. +# UNSUPPORTED: system-windows + +# RUN: rm -rf %t +# RUN: mkdir %t + +# RUN: ln -s llvm-objdump %t/llvm-otool-11.exe +# RUN: ln -s llvm-objdump %t/powerpc64-unknown-freebsd13-objdump + +# RUN: %t/llvm-otool-11.exe --help | FileCheck --check-prefix=OTOOL %s +# RUN: %t/powerpc64-unknown-freebsd13-objdump --help | \ +# RUN: FileCheck --check-prefix=OBJDUMP %s + +# OBJDUMP: OVERVIEW: llvm object file dumper +# OTOOL: OVERVIEW: Mach-O object file displaying tool diff --git a/llvm/tools/llvm-objdump/CMakeLists.txt b/llvm/tools/llvm-objdump/CMakeLists.txt --- a/llvm/tools/llvm-objdump/CMakeLists.txt +++ b/llvm/tools/llvm-objdump/CMakeLists.txt @@ -18,6 +18,10 @@ tablegen(LLVM ObjdumpOpts.inc -gen-opt-parser-defs) add_public_tablegen_target(ObjdumpOptsTableGen) +set(LLVM_TARGET_DEFINITIONS OtoolOpts.td) +tablegen(LLVM OtoolOpts.inc -gen-opt-parser-defs) +add_public_tablegen_target(OtoolOptsTableGen) + add_llvm_tool(llvm-objdump llvm-objdump.cpp COFFDump.cpp @@ -27,12 +31,15 @@ XCOFFDump.cpp DEPENDS ObjdumpOptsTableGen + OtoolOptsTableGen ) if(HAVE_LIBXAR) target_link_libraries(llvm-objdump PRIVATE ${XAR_LIB}) endif() +add_llvm_tool_symlink(llvm-otool llvm-objdump) + if(LLVM_INSTALL_BINUTILS_SYMLINKS) add_llvm_tool_symlink(objdump llvm-objdump) endif() diff --git a/llvm/tools/llvm-objdump/MachODump.h b/llvm/tools/llvm-objdump/MachODump.h --- a/llvm/tools/llvm-objdump/MachODump.h +++ b/llvm/tools/llvm-objdump/MachODump.h @@ -40,12 +40,17 @@ extern bool DylibId; extern bool ExportsTrie; extern bool FirstPrivateHeader; +extern bool FullLeadingAddr; extern bool FunctionStarts; extern bool IndirectSymbols; extern bool InfoPlist; extern bool LazyBind; extern bool LinkOptHints; +extern bool NoLeadingHeaders; +extern bool NoSymbolicOperands; +extern bool NonVerbose; extern bool ObjcMetaData; +extern std::string DisSymName; extern bool Rebase; extern bool UniversalHeaders; extern bool WeakBind; diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp --- a/llvm/tools/llvm-objdump/MachODump.cpp +++ b/llvm/tools/llvm-objdump/MachODump.cpp @@ -71,8 +71,8 @@ bool objdump::WeakBind; static bool UseDbg; static std::string DSYMFile; -static bool FullLeadingAddr; -static bool NoLeadingHeaders; +bool objdump::FullLeadingAddr; +bool objdump::NoLeadingHeaders; bool objdump::UniversalHeaders; static bool ArchiveMemberOffsets; bool objdump::IndirectSymbols; @@ -82,10 +82,10 @@ bool objdump::InfoPlist; bool objdump::DylibsUsed; bool objdump::DylibId; -static bool NonVerbose; +bool objdump::NonVerbose; bool objdump::ObjcMetaData; -static std::string DisSymName; -static bool NoSymbolicOperands; +std::string objdump::DisSymName; +bool objdump::NoSymbolicOperands; static std::vector ArchFlags; static bool ArchAll = false; diff --git a/llvm/tools/llvm-objdump/ObjdumpOptID.h b/llvm/tools/llvm-objdump/ObjdumpOptID.h --- a/llvm/tools/llvm-objdump/ObjdumpOptID.h +++ b/llvm/tools/llvm-objdump/ObjdumpOptID.h @@ -1,7 +1,7 @@ #ifndef LLVM_TOOLS_LLVM_OBJDUMP_OBJDUMP_OPT_ID_H #define LLVM_TOOLS_LLVM_OBJDUMP_OBJDUMP_OPT_ID_H -enum ID { +enum ObjdumpOptID { OBJDUMP_INVALID = 0, // This is not an option ID. #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ HELPTEXT, METAVAR, VALUES) \ diff --git a/llvm/tools/llvm-objdump/OtoolOpts.td b/llvm/tools/llvm-objdump/OtoolOpts.td new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objdump/OtoolOpts.td @@ -0,0 +1,68 @@ +include "llvm/Option/OptParser.td" + +def help : Flag<["--"], "help">, HelpText<"print help">; +def help_hidden : Flag<["--"], "help-hidden">, + HelpText<"print help for hidden flags">; + +def arch : Separate<["-"], "arch">, + HelpText<"select slice of universal Mach-O file">; +def C : Flag<["-"], "C">, HelpText<"print linker optimization hints">; +def d : Flag<["-"], "d">, HelpText<"print data section">; +def D : Flag<["-"], "D">, HelpText<"print shared library id">; +def f : Flag<["-"], "f">, HelpText<"print universal headers">; +def G : Flag<["-"], "G">, HelpText<"print data-in-code table">; +def h : Flag<["-"], "h">, HelpText<"print mach header">; +def I : Flag<["-"], "I">, HelpText<"print indirect symbol table">; +def j : Flag<["-"], "j">, HelpText<"print opcode bytes">; +def l : Flag<["-"], "l">, HelpText<"print load commnads">; +def L : Flag<["-"], "L">, HelpText<"print used shared libraries">; +def mcpu_EQ : Joined<["-"], "mcpu=">, HelpText<"select cpu for disassembly">; +def o : Flag<["-"], "o">, HelpText<"print Objective-C segment">; +def p : Separate<["-"], "p">, + MetaVarName<"">, + HelpText<"start disassembly at ">; +def P : Flag<["-"], "P">, HelpText<"print __TEXT,__info_plist section as strings">; +def : Flag<["-"], "q">, Flags<[HelpHidden]>, + HelpText<"use LLVM's disassembler (default)">; +def r : Flag<["-"], "r">, HelpText<"print relocation entries">; +def s : MultiArg<["-"], "s", 2>, + MetaVarName<" ">, + HelpText<"print contents of section">; +def t : Flag<["-"], "t">, HelpText<"print text section">; +def version : Flag<["--"], "version">, HelpText<"print version">; +def v : Flag<["-"], "v">, + HelpText<"verbose output / disassemble when printing text sections">; +def V : Flag<["-"], "V">, + HelpText<"symbolize disassembled operands (implies -v)">; +def x : Flag<["-"], "x">, HelpText<"print all text sections">; +def X : Flag<["-"], "X">, HelpText<"omit leading addresses or headers">; + +// Not (yet?) implemented: +// def a : Flag<["-"], "a">, HelpText<"print archive header">; +// -c print argument strings of a core file +// -m don't use archive(member) syntax +// -dyld_info +// -dyld_opcodes +// -chained_fixups +// -addr_slide=arg +// -function_offsets + + +// Obsolete and unsupported: +def grp_obsolete : OptionGroup<"kind">, + HelpText<"Obsolete and unsupported flags">; + +def : Flag<["-"], "B">, Flags<[HelpHidden]>, Group, + HelpText<"force Thum disassembly (ARM 32-bit objects only)">; +def : Flag<["-"], "H">, Flags<[HelpHidden]>, Group, + HelpText<"print two-level hints table">; +def : Flag<["-"], "M">, Flags<[HelpHidden]>, Group, + HelpText<"print module table of shared library">; +def : Flag<["-"], "R">, Flags<[HelpHidden]>, Group, + HelpText<"print reference table of shared library">; +def : Flag<["-"], "S">, Flags<[HelpHidden]>, Group, + HelpText<"print table of contents of library">; +def : Flag<["-"], "T">, Flags<[HelpHidden]>, Group, + HelpText<"print table of contents of shared library">; +def : Flag<["-"], "Q">, Flags<[HelpHidden]>, Group, + HelpText<"llvm-otool cannot use otool-classic's disassembler">; diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -88,32 +88,84 @@ namespace { -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +class CommonOptTable : public opt::OptTable { +public: + CommonOptTable(ArrayRef OptionInfos, const char *Usage, + const char *Description) + : OptTable(OptionInfos), Usage(Usage), Description(Description) { + setGroupedShortOptions(true); + } + + void printHelp(StringRef Argv0, bool ShowHidden = false) const { + Argv0 = sys::path::filename(Argv0); + PrintHelp(outs(), (Argv0 + Usage).str().c_str(), Description, ShowHidden, + ShowHidden); + // TODO Replace this with OptTable API once it adds extrahelp support. + outs() << "\nPass @FILE as argument to read options from FILE.\n"; + } + +private: + const char *Usage; + const char *Description; +}; + +// ObjdumpOptID is in ObjdumpOptID.h + +#define PREFIX(NAME, VALUE) const char *const OBJDUMP_##NAME[] = VALUE; #include "ObjdumpOpts.inc" #undef PREFIX static constexpr opt::OptTable::Info ObjdumpInfoTable[] = { +#define OBJDUMP_nullptr nullptr #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ HELPTEXT, METAVAR, VALUES) \ - {PREFIX, NAME, HELPTEXT, \ - METAVAR, OBJDUMP_##ID, opt::Option::KIND##Class, \ - PARAM, FLAGS, OBJDUMP_##GROUP, \ - OBJDUMP_##ALIAS, ALIASARGS, VALUES}, + {OBJDUMP_##PREFIX, NAME, HELPTEXT, \ + METAVAR, OBJDUMP_##ID, opt::Option::KIND##Class, \ + PARAM, FLAGS, OBJDUMP_##GROUP, \ + OBJDUMP_##ALIAS, ALIASARGS, VALUES}, #include "ObjdumpOpts.inc" #undef OPTION +#undef OBJDUMP_nullptr }; -class ObjdumpOptTable : public opt::OptTable { +class ObjdumpOptTable : public CommonOptTable { public: - ObjdumpOptTable() : OptTable(ObjdumpInfoTable) {} + ObjdumpOptTable() + : CommonOptTable(ObjdumpInfoTable, " [options] ", + "llvm object file dumper") {} +}; - void PrintObjdumpHelp(StringRef Argv0, bool ShowHidden = false) const { - Argv0 = sys::path::filename(Argv0); - PrintHelp(outs(), (Argv0 + " [options] ").str().c_str(), - "llvm object file dumper", ShowHidden, ShowHidden); - // TODO Replace this with OptTable API once it adds extrahelp support. - outs() << "\nPass @FILE as argument to read options from FILE.\n"; - } +enum OtoolOptID { + OTOOL_INVALID = 0, // This is not an option ID. +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + OTOOL_##ID, +#include "OtoolOpts.inc" +#undef OPTION +}; + +#define PREFIX(NAME, VALUE) const char *const OTOOL_##NAME[] = VALUE; +#include "OtoolOpts.inc" +#undef PREFIX + +static constexpr opt::OptTable::Info OtoolInfoTable[] = { +#define OTOOL_nullptr nullptr +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + {OTOOL_##PREFIX, NAME, HELPTEXT, \ + METAVAR, OTOOL_##ID, opt::Option::KIND##Class, \ + PARAM, FLAGS, OTOOL_##GROUP, \ + OTOOL_##ALIAS, ALIASARGS, VALUES}, +#include "OtoolOpts.inc" +#undef OPTION +#undef OTOOL_nullptr +}; + +class OtoolOptTable : public CommonOptTable { +public: + OtoolOptTable() + : CommonOptTable(OtoolInfoTable, " [option...] [file...]", + "Mach-O object file displaying tool") {} }; } // namespace @@ -2787,7 +2839,55 @@ return Values; } -static void parseOptions(const llvm::opt::InputArgList &InputArgs) { +static void parseOtoolOptions(const llvm::opt::InputArgList &InputArgs) { + MachOOpt = true; + FullLeadingAddr = true; + PrintImmHex = true; + + ArchName = InputArgs.getLastArgValue(OTOOL_arch).str(); + LinkOptHints = InputArgs.hasArg(OTOOL_C); + if (InputArgs.hasArg(OTOOL_d)) + FilterSections.push_back("__DATA,__data"); + DylibId = InputArgs.hasArg(OTOOL_D); + UniversalHeaders = InputArgs.hasArg(OTOOL_f); + DataInCode = InputArgs.hasArg(OTOOL_G); + FirstPrivateHeader = InputArgs.hasArg(OTOOL_h); + IndirectSymbols = InputArgs.hasArg(OTOOL_I); + NoShowRawInsn = !InputArgs.hasArg(OTOOL_j); + PrivateHeaders = InputArgs.hasArg(OTOOL_l); + DylibsUsed = InputArgs.hasArg(OTOOL_L); + MCPU = InputArgs.getLastArgValue(OTOOL_mcpu_EQ).str(); + ObjcMetaData = InputArgs.hasArg(OTOOL_o); + DisSymName = InputArgs.getLastArgValue(OTOOL_p).str(); + InfoPlist = InputArgs.hasArg(OTOOL_P); + Relocations = InputArgs.hasArg(OTOOL_r); + if (const Arg *A = InputArgs.getLastArg(OTOOL_s)) { + auto Filter = (A->getValue(0) + StringRef(",") + A->getValue(1)).str(); + FilterSections.push_back(Filter); + } + if (InputArgs.hasArg(OTOOL_t)) + FilterSections.push_back("__TEXT,__text"); + NonVerbose = !(InputArgs.hasArg(OTOOL_v) || InputArgs.hasArg(OTOOL_V) || + InputArgs.hasArg(OTOOL_o)); + NoSymbolicOperands = !InputArgs.hasArg(OTOOL_V); + if (InputArgs.hasArg(OTOOL_x)) + FilterSections.push_back(",__text"); + NoLeadingAddr = NoLeadingHeaders = InputArgs.hasArg(OTOOL_X); + + InputFilenames = InputArgs.getAllArgValues(OTOOL_INPUT); + if (InputFilenames.empty()) + reportCmdLineError("no input file"); + + for (const Arg *A : InputArgs) { + const Option &O = A->getOption(); + if (O.getGroup().isValid() && O.getGroup().getID() == OTOOL_grp_obsolete) { + reportCmdLineWarning(O.getPrefixedName() + + " is obsolete and not implemented"); + } + } +} + +static void parseObjdumpOptions(const llvm::opt::InputArgList &InputArgs) { parseIntArg(InputArgs, OBJDUMP_adjust_vma_EQ, AdjustVMA); AllHeaders = InputArgs.hasArg(OBJDUMP_all_headers); ArchName = InputArgs.getLastArgValue(OBJDUMP_arch_name_EQ).str(); @@ -2880,6 +2980,10 @@ LLVMArgs.push_back("--riscv-no-aliases"); LLVMArgs.push_back(nullptr); llvm::cl::ParseCommandLineOptions(LLVMArgs.size() - 1, LLVMArgs.data()); + + // objdump defaults to a.out if no filenames specified. + if (InputFilenames.empty()) + InputFilenames.push_back("a.out"); } int main(int argc, char **argv) { @@ -2887,27 +2991,46 @@ InitLLVM X(argc, argv); ToolName = argv[0]; + std::unique_ptr T; + OptSpecifier Unknown, HelpFlag, HelpHiddenFlag, VersionFlag; + + StringRef Stem = sys::path::stem(ToolName); + auto Is = [=](StringRef Tool) { + // We need to recognize the following filenames: + // + // llvm-objdump -> objdump + // llvm-otool-10.exe -> otool + // powerpc64-unknown-freebsd13-objdump -> objdump + auto I = Stem.rfind_lower(Tool); + return I != StringRef::npos && + (I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()])); + }; + if (Is("otool")) { + T = std::make_unique(); + Unknown = OTOOL_UNKNOWN; + HelpFlag = OTOOL_help; + HelpHiddenFlag = OTOOL_help_hidden; + VersionFlag = OTOOL_version; + } else { + T = std::make_unique(); + Unknown = OBJDUMP_UNKNOWN; + HelpFlag = OBJDUMP_help; + HelpHiddenFlag = OBJDUMP_help_hidden; + VersionFlag = OBJDUMP_version; + } - ObjdumpOptTable T; - T.setGroupedShortOptions(true); - - bool HasError = false; BumpPtrAllocator A; StringSaver Saver(A); opt::InputArgList InputArgs = - T.parseArgs(argc, argv, OBJDUMP_UNKNOWN, Saver, [&](StringRef Msg) { - errs() << "error: " << Msg << '\n'; - HasError = true; - }); - if (HasError) - exit(1); + T->parseArgs(argc, argv, Unknown, Saver, + [&](StringRef Msg) { reportCmdLineError(Msg); }); - if (InputArgs.size() == 0 || InputArgs.hasArg(OBJDUMP_help)) { - T.PrintObjdumpHelp(ToolName); + if (InputArgs.size() == 0 || InputArgs.hasArg(HelpFlag)) { + T->printHelp(ToolName); return 0; } - if (InputArgs.hasArg(OBJDUMP_help_hidden)) { - T.PrintObjdumpHelp(ToolName, /*show_hidden=*/true); + if (InputArgs.hasArg(HelpHiddenFlag)) { + T->printHelp(ToolName, /*show_hidden=*/true); return 0; } @@ -2916,23 +3039,23 @@ InitializeAllTargetMCs(); InitializeAllDisassemblers(); - if (InputArgs.hasArg(OBJDUMP_version)) { + if (InputArgs.hasArg(VersionFlag)) { cl::PrintVersionMessage(); - outs() << '\n'; - TargetRegistry::printRegisteredTargetsForVersion(outs()); - exit(0); + if (!Is("otool")) { + outs() << '\n'; + TargetRegistry::printRegisteredTargetsForVersion(outs()); + } + return 0; } - parseOptions(InputArgs); + if (Is("otool")) + parseOtoolOptions(InputArgs); + else + parseObjdumpOptions(InputArgs); if (StartAddress >= StopAddress) reportCmdLineError("start address should be less than stop address"); - - // Defaults to a.out if no filenames specified. - if (InputFilenames.empty()) - InputFilenames.push_back("a.out"); - // Removes trailing separators from prefix. while (!Prefix.empty() && sys::path::is_separator(Prefix.back())) Prefix.pop_back(); @@ -2954,7 +3077,7 @@ FirstPrivateHeader || FunctionStarts || IndirectSymbols || InfoPlist || LazyBind || LinkOptHints || ObjcMetaData || Rebase || UniversalHeaders || WeakBind || !FilterSections.empty()))) { - T.PrintObjdumpHelp(ToolName); + T->printHelp(ToolName); return 2; } diff --git a/llvm/utils/gn/secondary/llvm/test/BUILD.gn b/llvm/utils/gn/secondary/llvm/test/BUILD.gn --- a/llvm/utils/gn/secondary/llvm/test/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/test/BUILD.gn @@ -250,7 +250,7 @@ "//llvm/tools/llvm-mt", "//llvm/tools/llvm-nm", "//llvm/tools/llvm-objcopy:symlinks", - "//llvm/tools/llvm-objdump", + "//llvm/tools/llvm-objdump:symlinks", "//llvm/tools/llvm-opt-fuzzer", "//llvm/tools/llvm-opt-report", "//llvm/tools/llvm-pdbutil", diff --git a/llvm/utils/gn/secondary/llvm/tools/llvm-objdump/BUILD.gn b/llvm/utils/gn/secondary/llvm/tools/llvm-objdump/BUILD.gn --- a/llvm/utils/gn/secondary/llvm/tools/llvm-objdump/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/tools/llvm-objdump/BUILD.gn @@ -7,25 +7,36 @@ args = [ "-gen-opt-parser-defs" ] } +tablegen("OtoolOpts") { + visibility = [ ":llvm-objdump" ] + args = [ "-gen-opt-parser-defs" ] +} + +symlinks = [ "llvm-otool" ] if (llvm_install_binutils_symlinks) { - symlink_or_copy("objdump") { + symlinks += [ "objdump" ] +} + +foreach(target, symlinks) { + symlink_or_copy(target) { deps = [ ":llvm-objdump" ] source = "llvm-objdump" - output = "$root_out_dir/bin/objdump" + output = "$root_out_dir/bin/$target" } } # //:llvm-objdump depends on this symlink target, see comment in //BUILD.gn. group("symlinks") { deps = [ ":llvm-objdump" ] - if (llvm_install_binutils_symlinks) { - deps += [ ":objdump" ] + foreach(target, symlinks) { + deps += [ ":$target" ] } } executable("llvm-objdump") { deps = [ ":ObjdumpOpts", + ":OtoolOpts", "//llvm/include/llvm/Config:config", "//llvm/lib/CodeGen", "//llvm/lib/DebugInfo/DWARF",