A native macOS GUI front-end for otool — a structured, searchable Mach-O binary inspector. Drop an app, framework, or binary on OTool and it discovers every Mach-O inside, then presents the most useful otool outputs (linked libraries, load commands, headers, sections, disassembly, and symbols) in a multi-tab window.
Requires macOS 14.6 (Sonoma) or later.
Drop a file or bundle onto the OTool app icon (or use Finder's Open With); each dropped item opens its own independent window. Launching OTool plain presents an open panel instead. The window discovers every Mach-O binary inside the dropped item, lists them in a searchable left sidebar, and shows structured otool output for the selected binary on the right. For fat (universal) binaries, an architecture picker selects which slice to inspect.
| Requirement | Notes |
|---|---|
| macOS 14.6+ | Sonoma minimum |
| Xcode Command Line Tools | Provides otool, nm, lipo, swift-demangle, and c++filt. Install with xcode-select --install (or a full Xcode). OTool bundles none of the inspection tools - it drives the ones already on your system. |
| Input | Discovery |
|---|---|
.app / .framework / .bundle / .plugin / .kext |
Recursive scan for Mach-O binaries; the bundle's CFBundleExecutable is listed first |
Standalone binary / .dylib / .so |
Used directly |
Discovery lists regular Mach-O files only, so framework symlinks (for example Foo.framework/Foo) do not duplicate the versioned binary. Each candidate is verified with file before being added.
In window order:
| Tab | Shows | Underlying tool |
|---|---|---|
| Libraries | Linked dynamic libraries, the install name, and resolved @rpath / @loader_path references |
otool -L / -D |
| Headers | Mach header flags and, for fat binaries, per-slice detail | otool -hv, lipo -detailed_info |
| Load Commands | Parsed load commands (segments, dylib references, version and entry-point info, and more), each with its fields decoded and a plain-English description | otool -l |
| Sections | Segment / section contents as a hex + ASCII dump; disassembly for __TEXT,__text |
otool -s / -tV |
| Symbols | The symbol table and indirect (stub / GOT) symbols, filterable by All, Defined, Exported, Undefined (imported), or Indirect | nm, otool -Iv |
| Disassemble | Function list on the left, the selected function's disassembly on the right | otool -tV |
The sidebar and the Load Commands, Symbols and Disassemble tabs each have a filter field that narrows their list as you type. Selecting a symbol demangles it below the table: C++ through c++filt, Swift through swift-demangle, and Objective-C runtime symbols described from their naming conventions. Output can be copied, and the selected binary revealed in Finder.
Very large outputs are capped for display, and whenever that happens the tab's status line says so. Copy hands over the full output rather than the shortened view. (For a binary whose disassembly is enormous, the cached listing itself is bounded - the status line reports that too.)
For fat (universal) binaries, a segmented picker in the content header exposes every slice, populated from lipo -archs. The host architecture (uname -m, with an arm64e-only slice accepted on an arm64 host) is preselected, falling back to the first slice. The chosen architecture is remembered per window and passed to every otool invocation, so all tabs reflect the same slice. The picker is hidden for thin binaries.
OTool is an OMC applet. The OMC framework handles the app lifecycle, per-item windows, the open panel, and Finder integration. The UI is defined declaratively in ActionUI JSON (OTool.json, Sidebar.json, Content.json, and one Tab*.json per tab). All business logic runs as shell scripts in Contents/Resources/Scripts/, with shared discovery and tool-invocation helpers in lib.otool.sh.
Multiple dropped items are handled separately, so each gets its own command invocation and window. Command routing (sidebar load and filtering, per-tab load and filtering, architecture change, binary selection, copy, reveal) is declared in Contents/Resources/Command.json.
The app runs as-is; it invokes the system command-line tools and bundles nothing to build. After changing scripts or UI JSON, re-sign the bundle so the signature stays valid:
./codesign_applet.sh OTool.app - # ad-hoc (local use)
./codesign_applet.sh OTool.app "Developer ID Application: ..." # for distributionDeveloper ID signing enables the hardened runtime and a timestamp; for distribution the app should then be notarized with xcrun notarytool.
OTool is licensed under the Apache License 2.0 — see LICENSE.