A colleague hands you a Mach-O binary from someone else's Mac, and llvm-otool-18 shows what is inside without running it. This guide uses the installed llvm-otool-18 from the Debian llvm-18 package to identify the file, read its headers and load commands, list dependencies, and inspect selected sections. Allow about 10 minutes for a first pass. You need a readable Mach-O file and a normal shell account; none of the inspection commands require sudo.
Start by checking which binary will run and which LLVM build it reports:
$ command -v llvm-otool-18
/usr/bin/llvm-otool-18
$ llvm-otool-18 --version
Ubuntu LLVM version 18.1.3
Optimized build.
The exact version matters when comparing output from another machine. The installed manpage describes the command as a Mach-O dumping tool and documents a command-line and output compatibility goal with macOS otool. It is a reader: the options below print information and do not rewrite the input.
Checkpoint: If command -v finds a different path, stop and record it before comparing results. Do not solve a path problem by installing another LLVM package in the middle of an investigation.
Set a shell variable to a file you intend to inspect, then ask for its Mach header:
$ MACHO='/path/to/sample'
$ llvm-otool-18 -h "$MACHO"
A valid input produces a Mach header with fields such as the CPU type, file type, number of load commands and flags. The command is read-only. If the file is an ordinary Linux ELF binary, the tool reports an error like object is not a Mach-O file type. That is an input-format problem, not a reason to add more flags.
Checkpoint: Keep the original error and verify the path with file "$MACHO". A copied, truncated or compressed download must be corrected before interpretation. Do not feed untrusted files to other tools just to make them look like Mach-O.
A universal, or fat, Mach-O file contains more than one architecture. Print its slice headers first:
$ llvm-otool-18 -f "$MACHO"
Use the architecture name reported by that output to select one slice for later inspection:
$ llvm-otool-18 -arch arm64 -h "$MACHO"
$ llvm-otool-18 -arch x86_64 -l "$MACHO"
-arch selects a slice; it does not convert the file or change its default slice. If the requested architecture is absent, choose one that -f actually listed. This is a common distraction when a header command appears to work for one machine but not another.
Load commands describe how the Mach-O image is laid out and loaded. Print them without disassembling code:
$ llvm-otool-18 -l "$MACHO"
To focus on the libraries recorded by the file, use -L:
$ llvm-otool-18 -L "$MACHO"
Look for the install name and dependency paths, then compare those paths with the deployment environment. A dependency listed here is metadata, not proof that the library exists on your Linux host. The command also does not execute the Mach-O file, so it cannot prove that a macOS loader would successfully start it.
For a dylib, -D prints its shared-library identifier:
$ llvm-otool-18 -D "$MACHO"
Use -s when you know the segment and section names. This example prints the contents of the named section:
$ llvm-otool-18 -s __TEXT __cstring "$MACHO"
The names must match the file. Use -l first if you are unsure which sections exist. For text sections, -t prints the text section, while -x prints all text sections. Add -v for verbose output and disassembly-related detail:
$ llvm-otool-18 -arch x86_64 -t -v "$MACHO"
$ llvm-otool-18 -arch arm64 -x -v "$MACHO"
These outputs can be large. Redirect them to a new file if you need to search them, rather than overwriting the binary:
$ llvm-otool-18 -l "$MACHO" > load-commands.txt
$ rg 'LC_LOAD_DYLIB|LC_RPATH' load-commands.txt
That redirection creates or replaces load-commands.txt, not the Mach-O input. If the report is valuable, choose a new destination or make a backup first. Recovery is simply to remove the report or restore the previous copy of that report; the inspected binary is unchanged.
The tool exits non-zero when it encounters an error, and it may write diagnostics to standard error. Capture both streams when preserving a failed attempt:
$ llvm-otool-18 -l "$MACHO" > inspection.txt 2> inspection.err
$ printf 'status: %s\n' "$?"
$ sed -n '1,12p' inspection.err
Run the status command immediately. If the file is not Mach-O, check the path and file type. If a universal file rejects an architecture, return to -f. If a section name fails, inspect -l rather than inventing a spelling. Some options are specialised: -dyld_info prints bind and rebase information, -r prints relocations, and -p FUNCTION starts disassembly at a named function. Use them only when the file and question justify them.
llvm-otool-18 --version identified the installed LLVM build.-h or -f established the Mach-O type and, where relevant, available slices.-l and -L gave you load-command and dependency evidence.