dissect#
Attribute a compiled binary's size to the OCaml modules and libraries that fill
it -- a native, no-nm answer to "why is this binary so large".
Installation#
Install with opam:
$ opam install dissect
If opam cannot find the package, it may not yet be released in the public
opam-repository. Add the overlay repository, then install it:
$ opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git
$ opam update
$ opam install dissect
Overview#
dissect reads a compiled OCaml binary (Mach-O or ELF, detected from its
leading bytes), attributes every byte to the OCaml module and library that
produced it, and prints a sorted weight-map of proportional bars in the
terminal. The binary formats are parsed natively by mach-o and
elf (both built on the wire codec library); the rendering
uses console.
Usage#
dissect path/to/binary # group by library, top 20 (the default)
dissect --by-module ./a.out # group by individual module
dissect -n 40 ./a.out # show more rows (0 shows all)
! 5.4 MiB (34%) is not code: symbol & string tables, constants, unwind data
and headers. Most is removed by `strip`.
╭────────────────────┬───────────┬─────┬───...╮
│ Module │ Size │ % │ │
├────────────────────┼───────────┼─────┼───...┤
│ Stdlib │ 713.7 KiB │ 6% │ ███ │
│ Parser │ 700.7 KiB │ 6% │ ███ │
│ Typecore │ 455.0 KiB │ 4% │ ██ │
│ (... 190 more) │ 4.9 MiB │ 46% │ ████ │
╰────────────────────┴───────────┴─────┴───...╯
10.5 MiB of code across 210 module(s), 65% of the 15.9 MiB file
The bytes no symbol covers -- the symbol and string tables (Mach-O
__LINKEDIT, removed by strip), constant and exception sections, and the
headers -- are summarised in the warning rather than given table rows, so the
percentages are shares of the attributed code, not of the whole file.
How symbols are bucketed#
Each linker symbol is classified by name. A wrapped library's symbol has the
form caml<Lib>__<Module>$<function>, so it is grouped under <Lib>; a symbol
with no __ is bucketed by its own module name (the library is not encoded in
the symbol); anything that is not a caml-prefixed module symbol goes to the
C runtime bucket:
# Dissect.Demangle.classify "_camlStdlib__Arg$go_42"
- : Dissect.Demangle.t =
Dissect.Demangle.Ocaml {Dissect.Demangle.library = "Stdlib"; modul = "Arg"}
# Dissect.Demangle.classify "_caml_alloc"
- : Dissect.Demangle.t = Dissect.Demangle.C_runtime
Mach-O symbol records carry no size, so a symbol's size is reconstructed as the distance to the next symbol in its section; ELF records carry an explicit size, used directly.
Licence#
ISC. See LICENSE.md.