[llvm] 1a3f886 - [llvm-objdump] Add an llvm-otool tool

Nico Weber via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 20 05:25:31 PDT 2021


Author: Nico Weber
Date: 2021-04-20T08:24:58-04:00
New Revision: 1a3f88658a02be6be5224fca9d9123b79958f289

URL: https://github.com/llvm/llvm-project/commit/1a3f88658a02be6be5224fca9d9123b79958f289
DIFF: https://github.com/llvm/llvm-project/commit/1a3f88658a02be6be5224fca9d9123b79958f289.diff

LOG: [llvm-objdump] Add an llvm-otool tool

This implements an LLVM tool that's flag- and output-compatible
with macOS's `otool` -- except for bugs, but from testing with both
`otool` and `xcrun otool-classic`, llvm-otool matches vanilla
otool's behavior very well already. It's not 100% perfect, but
it's a very solid start.

This uses the same approach as llvm-objcopy: llvm-objdump uses
a different OptTable when it's invoked as llvm-otool. This
is possible thanks to D100433.

Differential Revision: https://reviews.llvm.org/D100583

Added: 
    llvm/docs/CommandGuide/llvm-otool.rst
    llvm/test/tools/llvm-objdump/tool-name.test
    llvm/tools/llvm-objdump/OtoolOpts.td

Modified: 
    llvm/docs/CommandGuide/index.rst
    llvm/docs/CommandGuide/llvm-objdump.rst
    llvm/test/CMakeLists.txt
    llvm/test/lit.cfg.py
    llvm/test/tools/llvm-objdump/MachO/AArch64/macho-link-opt-hints.test
    llvm/test/tools/llvm-objdump/MachO/ARM/data-in-code.test
    llvm/test/tools/llvm-objdump/MachO/ARM/mcpu-arm.test
    llvm/test/tools/llvm-objdump/MachO/data-in-code.ll
    llvm/test/tools/llvm-objdump/MachO/dis-no-leading-addr.test
    llvm/test/tools/llvm-objdump/MachO/dis-symname.test
    llvm/test/tools/llvm-objdump/MachO/dylib.test
    llvm/test/tools/llvm-objdump/MachO/indirect-symbols.test
    llvm/test/tools/llvm-objdump/MachO/info-plist.test
    llvm/test/tools/llvm-objdump/MachO/macho-objc-meta-data.test
    llvm/test/tools/llvm-objdump/MachO/private-headers.test
    llvm/test/tools/llvm-objdump/MachO/relocations.test
    llvm/test/tools/llvm-objdump/MachO/sections.test
    llvm/test/tools/llvm-objdump/MachO/symbolized-disassembly.test
    llvm/test/tools/llvm-objdump/MachO/universal-arm64.test
    llvm/tools/llvm-objdump/CMakeLists.txt
    llvm/tools/llvm-objdump/MachODump.cpp
    llvm/tools/llvm-objdump/MachODump.h
    llvm/tools/llvm-objdump/ObjdumpOptID.h
    llvm/tools/llvm-objdump/llvm-objdump.cpp
    llvm/utils/gn/secondary/llvm/test/BUILD.gn
    llvm/utils/gn/secondary/llvm/tools/llvm-objdump/BUILD.gn

Removed: 
    


################################################################################
diff  --git a/llvm/docs/CommandGuide/index.rst b/llvm/docs/CommandGuide/index.rst
index 19ec9cf700cac..4f5c912bb4111 100644
--- a/llvm/docs/CommandGuide/index.rst
+++ b/llvm/docs/CommandGuide/index.rst
@@ -29,6 +29,7 @@ Basic Commands
    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
index 49edbcd91b072..acfe80763661d 100644
--- a/llvm/docs/CommandGuide/llvm-objdump.rst
+++ b/llvm/docs/CommandGuide/llvm-objdump.rst
@@ -390,4 +390,5 @@ To report bugs, please visit <https://bugs.llvm.org/>.
 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
index 0000000000000..9284bd946bb99
--- /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 <value>
+
+ 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=<value>
+
+ Select cpu for disassembly.
+
+.. option:: -o
+
+ Print Objective-C segment.
+
+.. option:: -P
+
+ Print __TEXT,__info_plist section as strings.
+
+.. option:: -p <function name>
+
+ Start disassembly at <function name>.
+
+.. option:: -r
+
+ Print relocation entries.
+
+.. option:: -s <segname> <sectname>
+
+ 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:: @<FILE>
+
+ Read command-line options and commands from response file `<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 <https://bugs.llvm.org/>.
+
+SEE ALSO
+--------
+
+:manpage:`llvm-nm(1)`, :manpage:`llvm-objdump(1)`

diff  --git a/llvm/test/CMakeLists.txt b/llvm/test/CMakeLists.txt
index 81107be862dee..bd02027c06038 100644
--- a/llvm/test/CMakeLists.txt
+++ b/llvm/test/CMakeLists.txt
@@ -100,6 +100,7 @@ set(LLVM_TEST_DEPENDS
           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
index db94537bb4627..89c7497d0cdfd 100644
--- a/llvm/test/lit.cfg.py
+++ b/llvm/test/lit.cfg.py
@@ -160,7 +160,7 @@ def get_asan_rtlib():
     '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
index 2f39aba92af97..2cd044a3be34f 100644
--- 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
index b2f2b3e09a20f..f0d8f43a4b7da 100644
--- 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
index fed00c5fdb917..6d2577c00c954 100644
--- 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
index de78203c98cf5..d214bf65322cd 100644
--- 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
index 57d328ea3a25c..28319920d01ed 100644
--- 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
index 9c7a341e33b86..5990095725d9b 100644
--- 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
index 32c64f019c476..01fb4c6334a61 100644
--- 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/foo4.dylib (compatibility version 0.0.0, current version 0.0.0, l
 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
index dcdb068e711f1..1615109b78e06 100644
--- 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
index 8370b6b3e3921..a3390568a5128 100644
--- 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 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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
index 566bde6f45815..7f0c7a4654dc8 100644
--- 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
index 8ca13a383c795..c3a48820243a2 100644
--- 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
index 95db5ec1ab242..bc6aba0aae90f 100644
--- 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
index 2bed7871b49fa..b39e1b5040f1d 100644
--- 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
index 31016a2c1073c..c01fb168fb1d7 100644
--- 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
index e15b31159d2fa..4f39ee9a11225 100644
--- 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
index 0000000000000..8aefce82c83b8
--- /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
index 5a0c855b37cd5..89dea90d600fc 100644
--- a/llvm/tools/llvm-objdump/CMakeLists.txt
+++ b/llvm/tools/llvm-objdump/CMakeLists.txt
@@ -18,6 +18,10 @@ set(LLVM_TARGET_DEFINITIONS ObjdumpOpts.td)
 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 @@ add_llvm_tool(llvm-objdump
   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.cpp b/llvm/tools/llvm-objdump/MachODump.cpp
index fadb2999d2094..170dcae90ae02 100644
--- a/llvm/tools/llvm-objdump/MachODump.cpp
+++ b/llvm/tools/llvm-objdump/MachODump.cpp
@@ -71,8 +71,8 @@ bool objdump::LazyBind;
 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::LinkOptHints;
 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<std::string> ArchFlags;
 
 static bool ArchAll = false;

diff  --git a/llvm/tools/llvm-objdump/MachODump.h b/llvm/tools/llvm-objdump/MachODump.h
index 447749a23e592..70d8b80b36142 100644
--- a/llvm/tools/llvm-objdump/MachODump.h
+++ b/llvm/tools/llvm-objdump/MachODump.h
@@ -40,12 +40,17 @@ extern bool DylibsUsed;
 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/ObjdumpOptID.h b/llvm/tools/llvm-objdump/ObjdumpOptID.h
index 2c17f441a033c..65f6c60ad884f 100644
--- 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
index 0000000000000..61ea701ed75dd
--- /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<"<function name>">,
+  HelpText<"start disassembly at <function name>">;
+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<"<segname> <sectname>">,
+  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<grp_obsolete>,
+  HelpText<"force Thum disassembly (ARM 32-bit objects only)">;
+def : Flag<["-"], "H">, Flags<[HelpHidden]>, Group<grp_obsolete>,
+  HelpText<"print two-level hints table">;
+def : Flag<["-"], "M">, Flags<[HelpHidden]>, Group<grp_obsolete>,
+  HelpText<"print module table of shared library">;
+def : Flag<["-"], "R">, Flags<[HelpHidden]>, Group<grp_obsolete>,
+  HelpText<"print reference table of shared library">;
+def : Flag<["-"], "S">, Flags<[HelpHidden]>, Group<grp_obsolete>,
+  HelpText<"print table of contents of library">;
+def : Flag<["-"], "T">, Flags<[HelpHidden]>, Group<grp_obsolete>,
+  HelpText<"print table of contents of shared library">;
+def : Flag<["-"], "Q">, Flags<[HelpHidden]>, Group<grp_obsolete>,
+  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
index 8490a9156d1c0..e094468360202 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -88,32 +88,84 @@ using namespace llvm::opt;
 
 namespace {
 
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+class CommonOptTable : public opt::OptTable {
+public:
+  CommonOptTable(ArrayRef<Info> 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] <input object files>",
+                       "llvm object file dumper") {}
+};
 
-  void PrintObjdumpHelp(StringRef Argv0, bool ShowHidden = false) const {
-    Argv0 = sys::path::filename(Argv0);
-    PrintHelp(outs(), (Argv0 + " [options] <input object files>").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 @@ commaSeparatedValues(const llvm::opt::InputArgList &InputArgs, int ID) {
   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 @@ static void parseOptions(const llvm::opt::InputArgList &InputArgs) {
     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 @@ int main(int argc, char **argv) {
   InitLLVM X(argc, argv);
 
   ToolName = argv[0];
+  std::unique_ptr<CommonOptTable> 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<OtoolOptTable>();
+    Unknown = OTOOL_UNKNOWN;
+    HelpFlag = OTOOL_help;
+    HelpHiddenFlag = OTOOL_help_hidden;
+    VersionFlag = OTOOL_version;
+  } else {
+    T = std::make_unique<ObjdumpOptTable>();
+    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 @@ int main(int argc, char **argv) {
   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 @@ int main(int argc, char **argv) {
          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
index 3ec55ddd2db8b..c381df75be036 100644
--- a/llvm/utils/gn/secondary/llvm/test/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/test/BUILD.gn
@@ -250,7 +250,7 @@ group("test") {
     "//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
index bdf650b3a502a..33dfbc24efd13 100644
--- 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 @@ tablegen("ObjdumpOpts") {
   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",


        


More information about the llvm-commits mailing list