exex

command module
v0.3.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2026 License: MIT Imports: 15 Imported by: 0

README

exex

A fast terminal UI for exploring ELF, Mach-O and PE binaries — header, sections, segments, symbols, disassembly, hex/raw bytes, strings, libraries, relocations, syscall sites and DWARF source mapping in one keyboard- and mouse-driven interface.

Its standout feature: when a binary has debug info (DWARF, or a Mach-O .dSYM), exex shows the original source side by side with the exact disassembly it maps to — navigable both ways, and entirely static: no debugger, no running process, no decompiler.

exex [-debug PATH] [-s STRING] [-o [VIEW]] <binary> [goto]

ExEx usage animation

Highlights

  • One explorer for three formats: ELF, Mach-O, PE and universal/fat Mach-O slices.
  • Source ↔ disassembly: original source beside machine code, from DWARF or a .dSYM.
  • Fast first look: read-only, no project database, no debugger session.
  • Many views: symbols, sections, segments, strings, relocations, libraries, syscall sites, CPU features, hex/raw bytes and disassembly.
  • Scriptable: -o emits plain text for pipes and automation.
  • Text scripts too: shell/Python/etc. open in a linked text viewer instead of failing as "not a binary".

See how exex compares to other tools for the tradeoffs against binutils, debuggers and RE platforms.

Install

brew install shellcell/tap/exex              # Homebrew
go install github.com/shellcell/exex@latest   # Go

Or download the asset for your OS/arch from Releases:

tar -xzf exex-<version>-<os>-<arch>.tar.gz
chmod +x exex && sudo mv exex /usr/local/bin/
shasum -a 256 -c checksums.txt        # optional

Or build from source:

make build       # -> ./exex
make test        # go test
make test-cross  # cross-compile and parse/disassemble readable targets; needs Go + Zig
Man page and completions

A man page (docs/exex.1) and bash/zsh/fish completions (completions/) ship with the source and release archives. Completions cover the flags, the -o view names, and the <binary> argument — both files and commands on $PATH, so exex ls<Tab> works.

make install-man           # -> $MANPREFIX/man1/exex.1   (sudo for a system prefix)
make install-completions   # -> bash/zsh/fish completion dirs (override *COMPDIR vars)

To install one by hand: source completions/exex.bash; copy completions/_exex onto your zsh $fpath (before compinit); or copy completions/exex.fish to ~/.config/fish/completions/.

Usage

exex [flags] <binary> [goto]
  • <binary> — an ELF/Mach-O/PE file, or a command name on $PATH (exex ls opens /bin/ls).
  • goto — optional address (0x401000) or symbol to jump to on open. A unique symbol jumps straight there; an ambiguous one opens Symbols filtered by it.

Flags are accepted in any position:

Flag Description
-s STRING search printable strings; opens the match in Hex, or Strings filtered when several match
-debug PATH / -d PATH external debug symbols (ELF .debug companion, or a Mach-O .dSYM bundle/file)
-arch NAME which slice of a universal (fat) Mach-O to open (e.g. x86_64, arm64); defaults to the host arch. Info lists all slices; press t there to switch
-o VIEW print a view to stdout and exit: info, sections, segments, symbols, strings, libs, sources, relocs, syscalls, syscalls-all, syscalls-full, disasm, disasm-all
-o (bare) print the goto symbol/address's function disassembly and exit
Scripting with -o

exex -o symbols ./bin, exex -o disasm ./bin | less, exex -o ./bin main (one function). disasm covers executable sections (like objdump -d), disasm-all every section (like objdump -D). Output streams, so | head returns immediately even on large binaries. relocs prints the relocation table (like readelf -r).

The syscall views find each kernel-entry instruction (syscall/svc/int 0x80/ecall), recovering the call number from the immediate loaded into the syscall-number register where possible, plus calls to vDSO helpers (__vdso_*):

  • syscalls — the distinct calls the binary makes.
  • syscalls-all — every site, with its address.
  • syscalls-full — also scans directly linked libraries (a dynamically linked program often makes no direct syscalls — they live in libc), tagging each with its originating object and listing libraries it couldn't resolve.
Keys
Key Action
19 / 0 switch view (Info, Sections, Symbols, Disasm, Hex, Raw, Strings, Libs, Sources · 0 Relocations)
⇧h / ⇧f / , / ^o raw header overlay · CPU-feature scan · settings · back to the previous file
↑/↓ j/k, PgUp/PgDn, Home/End move / page (also ⌘↑/⌘↓, ^A/^E on macOS)
/ filter / search the current view
Enter open / follow / jump
g go to address or symbol
[ / ] page up / down in list views; previous / next section (Hex/Raw) or symbol (Disasm)
⇧[ / ⇧] previous / next non-zero byte (Hex/Raw)
d / h / m go to the address under the cursor in the Disasm / Hex / Raw view
s / r cycle sort field · reverse it (Sections, Symbols, Strings, Sources, Relocations; r reverses Libs by name)
x / y Disasm: find references (xrefs) · list system calls (scoped to the function / whole binary / unique)
^t / ^s / ^b / ^f / ^p column filters — Symbols: type / scope / bind · Sections: type (^t) / flags (^f) · Strings: section (^s) · Relocations: type (^t) / section (^s) · Libs/Sources: availability (^p)
t (or Tab) toggle the view's mode — Symbols/Sources: tree ↔ flat list; Sections: sections ↔ segments; Libs: flat ↔ tree; Hex/Raw: ascii ↔ pointer decode; Info: fat-Mach-O arch slice (Tab is the source pane in Disasm)
/ · Enter · +/ tree: collapse / expand group ( on a leaf folds its branch) · expand/collapse all below · all
e / . collapse long (…)/<…> argument & template lists to ...e all (also from Disasm/Hex/Raw), . current Symbols row
⇧a / ⇧s / ⇧p / ⇧c copy address / name / pointer (Hex/Raw) / function disassembly (Disasm)
⇧l copy the whole current row (all columns)
w toggle long-line wrap
Tab / ⇧Tab show-hide / swap the disasm source pane
? full key reference · q quit

Keys are rebindable. The mouse wheel scrolls, click selects, and double-click follows in the disasm view.

Configuration

Config is optional YAML at $XDG_CONFIG_HOME/exex/config.yaml (or $HOME/.config/exex/config.yaml if XDG_CONFIG_HOME is unset). Every field is optional — unset entries keep their defaults. You can:

  • pick a built-in theme: theme: nord | dark | solarized-dark | solarized-light,
  • override individual colours under colors: (instruction classes, address links, tables, source/asm highlight, hex byte ramp, paths, …) — a #RRGGBB string or an ANSI-256 index (e.g. "203"),
  • rebind top-level keys,
  • set behaviour: default view, default wrap, disasm landing target, decode window size.

docs/config.example.yaml has the full annotated schema.

How exex compares to other tools

exex deliberately overlaps with the classic binary tools: it rolls what you'd normally get from several one-shot commands into one interactive, multi-format TUI — and can still emit their plain text for scripts via -o.

Classic CLI tools
Tool What it does In exex
readelf dump header, sections, program headers, symbols, dynamic info, DWARF Info / Sections / Segments / Symbols / Libs views; -o info|sections|segments|symbols|libs. (readelf is ELF-only; exex also reads Mach-O & PE)
objdump -d / -D disassemble executable (or all) sections Disasm view (navigation, xrefs, source mapping); -o disasm / -o disasm-all for the objdump-style listing
nm list symbols Symbols view (filter, sort by name/addr/size, scope, type/bind); -o symbols
c++filt demangle mangled names inline everywhere (C++/Rust built in, Swift via swift-demangle)
strings printable strings Strings view (mapped to address & section); -o strings, or -s
hexdump / xxd / od hex + ASCII dump Hex view (virtual-address, section-aware, pointer decode, data inspector) and Raw view (file-offset)
addr2line address → source file:line via DWARF the source pane and Sources view — address ↔ source, both directions
size section/segment sizes Info, Sections and Segments views
otool (macOS) / dumpbin (Windows) the Mach-O / PE counterparts of the above one tool across ELF, Mach-O and PE
dyld_info (macOS) a Mach-O's dyld metadata: bind/rebase & chained fixups, dylibs, exports Relocs view decodes both bind/rebase opcodes and chained fixups into one table (-o relocs); Libs view lists dependent dylibs, including re-export/weak/upward variants
dyld_shared_cache_util (macOS) list / extract dylibs from the dyld shared cache opens a cache-resident system dylib straight from Libs (o), un-sharing it into a browsable Mach-O — no separate extraction step
dyld_usage (macOS) live-trace a process's dyld / shared-cache activity exex follows a binary's imports through the cache statically (e.g. libSystem → libsystem_kernel) to surface the transitive syscall surface (-o syscalls-full) — without running the program

Those tools each answer one question, print, and exit. exex answers all of them in one place and lets you navigate between them — follow a call into disasm, jump from a symbol to its hex, map an address to its source line, list a function's xrefs — and can still print like them for a pipe.

Reverse-engineering platforms

Binary Ninja, IDA Pro, Ghidra are full RE/decompilation suites: recursive analysis, decompilers, type systems, persistent databases, scripting, patching. They are powerful and heavy. exex sits at the opposite end: a tiny, read-only, instant terminal explorer with no project, no database, no decompiler. Reach for them for deep analysis; reach for exex to look at a binary in seconds.

radare2 / rizin are closest in spirit — terminal-based, scriptable, multi-format — but they are broad frameworks (analysis, patching, debugging, emulation) with a steep command language. exex is far narrower on purpose: a discoverable, point-and-look explorer, not an analysis or patching framework.

Source ↔ disassembly

exex shows original source beside the disassembly it maps to, navigable in both directions, with carets marking which columns of a source line map to which instructions. Other tools combine source and assembly, but differently:

Tool How vs exex
objdump -S / -dl interleaves DWARF source lines into the listing same data, but a flat one-shot dump — no panes, no navigation, no column mapping
gdb (layout split), lldb, IDE disassembly windows interactive source + asm, side by side requires a debug session (a launched/attached process); exex needs only the file on disk
IDA Pro, Ghidra, Binary Ninja, Hopper, Cutter disassembly next to decompiler pseudocode reconstructed C, not your original source; DWARF used mostly for names/types
Compiler Explorer (godbolt.org) colour-linked source ↔ asm compiles source, rather than reading an existing binary's debug info

So exex isn't trying to replace the binutils suite or a disassembler platform — it's the fast first look: open any ELF/Mach-O/PE, read its layout and code, follow references and source mappings interactively, and drop to plain text when you need to script.

Architecture

For contributors, docs/architecture.md describes the package layering (core binfile/disasm, domain services, the two frontends), the TUI's view contract (view.Context / view.Host) and the rendering & performance conventions, with diagrams.

Acknowledgements

exex builds on the Go toolchain and standard library, plus:

See go.mod for the full dependency list, including transitive packages.

ChatGPT was used as a development and documentation assistant.

License

exex is released under the MIT License — see LICENSE.

Documentation

Overview

Command exex is a terminal UI for exploring ELF, Mach-O, and PE binaries: header, sections, symbols, disassembly, and DWARF-driven source mapping.

Directories

Path Synopsis
internal
arch
Package arch defines CPU architecture identifiers shared by binary parsers and decoder adapters.
Package arch defines CPU architecture identifiers shared by binary parsers and decoder adapters.
binfile
Package binfile loads an executable (ELF or Mach-O) and exposes the bits the explorer needs through a single, format-neutral model: header info, sections, symbols, address→source mapping, and continuous virtual-address / raw-file byte images for the hex and disassembly views.
Package binfile loads an executable (ELF or Mach-O) and exposes the bits the explorer needs through a single, format-neutral model: header info, sections, symbols, address→source mapping, and continuous virtual-address / raw-file byte images for the hex and disassembly views.
bytesearch
Package bytesearch turns UI search queries into byte patterns and scans byte slices in either direction.
Package bytesearch turns UI search queries into byte patterns and scans byte slices in either direction.
chromalexers
Package chromalexers provides the curated Chroma lexer registry bundled by exex's default build.
Package chromalexers provides the curated Chroma lexer registry bundled by exex's default build.
chromastyles
Package chromastyles provides the curated Chroma style registry bundled by exex's default build.
Package chromastyles provides the curated Chroma style registry bundled by exex's default build.
chromasubset
Package chromasubset owns the curated Chroma XML manifests bundled by exex.
Package chromasubset owns the curated Chroma XML manifests bundled by exex.
config
Package config loads user customisation for exex: colour palette and top-level keybindings.
Package config loads user customisation for exex: colour palette and top-level keybindings.
cpufeat
Package cpufeat classifies disassembled instructions into the CPU-feature families they require, so a binary can be summarised as "needs AVX2, SSE4.2, FMA" → an implied baseline (x86-64-v3).
Package cpufeat classifies disassembled instructions into the CPU-feature families they require, so a binary can be summarised as "needs AVX2, SSE4.2, FMA" → an implied baseline (x86-64-v3).
disasm
Package disasm wraps golang.org/x/arch to provide a uniform decoder across x86, x86-64, ARM64, RISC-V 64, 32-bit ARM, PowerPC (32- and 64-bit, both endians), s390x and LoongArch 64.
Package disasm wraps golang.org/x/arch to provide a uniform decoder across x86, x86-64, ARM64, RISC-V 64, 32-bit ARM, PowerPC (32- and 64-bit, both endians), s390x and LoongArch 64.
dump
Package dump renders a binary's views as plain, non-interactive text for stdout (the `-o` flag), turning exex into a scriptable readelf/nm/objdump-lite.
Package dump renders a binary's views as plain, non-interactive text for stdout (the `-o` flag), turning exex into a scriptable readelf/nm/objdump-lite.
dyldcache
Package dyldcache reads Apple's dyld shared cache: the single large mapped image (split across a main file plus ".NN" subcache files) that macOS/iOS ship their system dylibs in instead of as standalone files on disk.
Package dyldcache reads Apple's dyld shared cache: the single large mapped image (split across a main file plus ".NN" subcache files) that macOS/iOS ship their system dylibs in instead of as standalone files on disk.
explorer
Package explorer contains format-neutral navigation and service logic shared by the TUI.
Package explorer contains format-neutral navigation and service logic shared by the TUI.
integration
Package integration holds slow, toolchain-dependent end-to-end tests guarded by the "crosscompile" build tag (see cross_test.go).
Package integration holds slow, toolchain-dependent end-to-end tests guarded by the "crosscompile" build tag (see cross_test.go).
sourcefiles
Package sourcefiles ranks and searches source files referenced by debug info.
Package sourcefiles ranks and searches source files referenced by debug info.
syntax
Package syntax highlights source files for display in the TUI source pane.
Package syntax highlights source files for display in the TUI source pane.
syscalls
Package syscalls maps system-call numbers to names per OS/architecture.
Package syscalls maps system-call numbers to names per OS/architecture.
testbin
Package testbin hand-builds tiny, byte-for-byte deterministic binaries for tests.
Package testbin hand-builds tiny, byte-for-byte deterministic binaries for tests.
theme
Package theme provides colour palettes extracted from Chroma's styles as plain data, so both the full and lite builds can theme the whole UI (and the built-in highlighter) from any Chroma style name without importing Chroma.
Package theme provides colour palettes extracted from Chroma's styles as plain data, so both the full and lite builds can theme the whole UI (and the built-in highlighter) from any Chroma style name without importing Chroma.
ui
Package ui implements the Bubble Tea TUI for exex.
Package ui implements the Bubble Tea TUI for exex.
ui/asmhl
Package asmhl highlights a single line of disassembled instruction text.
Package asmhl highlights a single line of disassembled instruction text.
ui/layout
Package layout holds the pure, Model-independent scroll/viewport geometry the TUI views share: given a cursor, a window height and a per-row height function, it computes which row to anchor at the top and which logical item sits at a visual row.
Package layout holds the pure, Model-independent scroll/viewport geometry the TUI views share: given a cursor, a window height and a per-row height function, it computes which row to anchor at the top and which logical item sits at a visual row.
ui/modal
Package modal is the neutral contract between the exex TUI shell (package ui) and the overlay modals, mirroring what package view is for the top-level views.
Package modal is the neutral contract between the exex TUI shell (package ui) and the overlay modals, mirroring what package view is for the top-level views.
ui/modals/cpufeat
Package cpufeat is the CPU-features overlay: the set of optional instruction families (SSE/AVX/NEON/…) a binary requires, the baseline they imply, and how often each is used.
Package cpufeat is the CPU-features overlay: the set of optional instruction families (SSE/AVX/NEON/…) a binary requires, the baseline they imply, and how often each is used.
ui/modals/findquery
Package findquery is the free-text global-search prompt (the `l` key): type a symbol name, a string, or a hex address, and it runs the same content scan the caret-seeded Find does.
Package findquery is the free-text global-search prompt (the `l` key): type a symbol name, a string, or a hex address, and it runs the same content scan the caret-seeded Find does.
ui/modals/findresults
Package findresults is the global value search's results overlay: every place a value occurs across the binary — disasm operands, data words, string contents, relocation targets — in one list, tagged by the view it belongs to and filterable by that view.
Package findresults is the global value search's results overlay: every place a value occurs across the binary — disasm operands, data words, string contents, relocation targets — in one list, tagged by the view it belongs to and filterable by that view.
ui/modals/findto
Package findto is the "Find from here" seed picker (the `f` key): it lists the things at the caret — its address, the pointer it holds, the symbol or section covering it, a string, a library path — and on selection launches the global value search for that seed.
Package findto is the "Find from here" seed picker (the `f` key): it lists the things at the caret — its address, the pointer it holds, the symbol or section covering it, a string, a library path — and on selection launches the global value search for that seed.
ui/modals/help
Package help is the keybinding cheat-sheet overlay (the `?` key): a static, two-column table of every binding, scrolled when it is taller than the terminal and dismissed by any other key.
Package help is the keybinding cheat-sheet overlay (the `?` key): a static, two-column table of every binding, scrolled when it is taller than the terminal and dismissed by any other key.
ui/modals/jumpto
Package jumpto is the "open caret position in…" overlay: take the address under the cursor and offer to reopen it in each of the other views, each row previewing exactly where it would land, above a header describing what the address *is*.
Package jumpto is the "open caret position in…" overlay: take the address under the cursor and offer to reopen it in each of the other views, each row previewing exactly where it would land, above a header describing what the address *is*.
ui/modals/palette
Package palette is the "Jump to" command palette (the `g` key): type a query, pick a scope, and jump to a symbol, section, string, library or address.
Package palette is the "Jump to" command palette (the `g` key): type a query, pick a scope, and jump to a symbol, section, string, library or address.
ui/modals/rawheader
Package rawheader is the raw container-header overlay (⇧H): the ELF e_* fields, the Mach-O mach_header and load commands, or the PE COFF/optional header, as an aligned field table.
Package rawheader is the raw container-header overlay (⇧H): the ELF e_* fields, the Mach-O mach_header and load commands, or the PE COFF/optional header, as an aligned field table.
ui/modals/search
Package search is the in-view search prompt (the `/` key): a query box above a strip of clickable toggles for the match mode, case sensitivity, direction and origin.
Package search is the in-view search prompt (the `/` key): a query box above a strip of clickable toggles for the match mode, case sensitivity, direction and origin.
ui/modals/settings
Package settings is the settings overlay: a scrollable list of preferences grouped under headings, cycled left/right, applied live, and saved on Enter.
Package settings is the settings overlay: a scrollable list of preferences grouped under headings, cycled left/right, applied live, and saved on Enter.
ui/modals/syscalls
Package syscalls is the system-calls results overlay: every place the binary enters the kernel, grouped by scope (this function / the whole binary / one row per distinct call / the binary plus its linked libraries), sortable, filterable and followable with Enter.
Package syscalls is the system-calls results overlay: every place the binary enters the kernel, grouped by scope (this function / the whole binary / one row per distinct call / the binary plus its linked libraries), sortable, filterable and followable with Enter.
ui/modals/textoverlay
Package textoverlay is the shared behaviour of exex's scrollable text overlays: the keybinding cheat-sheet and the raw container header.
Package textoverlay is the shared behaviour of exex's scrollable text overlays: the keybinding cheat-sheet and the raw container header.
ui/modals/xref
Package xref is the cross-references results overlay: every instruction that references the address under the disasm cursor, sortable, filterable, and followable with Enter.
Package xref is the cross-references results overlay: every instruction that references the address under the disasm cursor, sortable, filterable, and followable with Enter.
ui/scope
Package scope names what a search looks through.
Package scope names what a search looks through.
ui/view
Package view is the neutral contract between the exex TUI shell (package ui) and the individual views.
Package view is the neutral contract between the exex TUI shell (package ui) and the individual views.
ui/views/disasm
Package disasm implements the disassembly view: the column geometry the rows are laid out on, and the rendering built over it.
Package disasm implements the disassembly view: the column geometry the rows are laid out on, and the rendering built over it.
ui/views/hexraw
Package hexraw implements the Hex and Raw byte-dump views.
Package hexraw implements the Hex and Raw byte-dump views.
ui/views/info
Package info implements the normal Info overview page: the file header re-aligned into one column, plus overview, hardening, dynamic-linking and toolchain blocks.
Package info implements the normal Info overview page: the file header re-aligned into one column, plus overview, hardening, dynamic-linking and toolchain blocks.
ui/views/libs
Package libs implements the dynamic-libraries view: the DT_NEEDED entries together with the linkage context (interpreter, libc kind, RPATH, RUNPATH), as a flat list or a collapsible path tree, with name filtering and an on-disk/in-cache availability lens.
Package libs implements the dynamic-libraries view: the DT_NEEDED entries together with the linkage context (interpreter, libc kind, RPATH, RUNPATH), as a flat list or a collapsible path tree, with name filtering and an on-disk/in-cache availability lens.
ui/views/relocs
Package relocs implements the Relocations view: a filterable table of the binary's relocations — the GOT/PLT slots and base fixups the loader patches.
Package relocs implements the Relocations view: a filterable table of the binary's relocations — the GOT/PLT slots and base fixups the loader patches.
ui/views/sections
Package sections implements the Sections view: a filterable table of the binary's sections.
Package sections implements the Sections view: a filterable table of the binary's sections.
ui/views/sources
Package sources implements the Sources view's file list (DWARF only): every source file referenced by the line table, as a project-first flat list or a directory tree, with name filtering and an on-disk availability lens.
Package sources implements the Sources view's file list (DWARF only): every source file referenced by the line table, as a project-first flat list or a directory tree, with name filtering and an on-disk availability lens.
ui/views/strs
Package strs implements the Strings view: the printable runs found in the file (à la strings(1)), each annotated with its file offset and — when the bytes are mapped — the virtual address and owning section.
Package strs implements the Strings view: the printable runs found in the file (à la strings(1)), each annotated with its file offset and — when the bytes are mapped — the virtual address and owning section.
ui/views/symbols
Package symbols implements the Symbols view: a filterable, sortable table of the merged symbol table (matching on both raw and demangled names), with an alternative collapsible namespace-tree mode, kind/scope/bind facet filters, clickable facet chips on the status row, and per-row or global abbreviation of bracketed argument/template lists.
Package symbols implements the Symbols view: a filterable, sortable table of the merged symbol table (matching on both raw and demangled names), with an alternative collapsible namespace-tree mode, kind/scope/bind facet filters, clickable facet chips on the status row, and per-row or global abbreviation of bracketed argument/template lists.
tools
perfreport command
Command perfreport measures exex against a sample binary and prints a Markdown table: the parse/startup cost, every `-o` view's render time and allocation volume, each interactive (TUI) view's full-frame render cost, and the process's peak resident memory.
Command perfreport measures exex against a sample binary and prints a Markdown table: the parse/startup cost, every `-o` view's render time and allocation volume, each interactive (TUI) view's full-frame render cost, and the process's peak resident memory.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL