Report ELF section/segment headers as such.

Previously we attributed section/segment headers themselves
to the section/segment they describe. eg. the `.text` header
was counted as part of the `.text` section. After this change
it is reported as part of `[ELF Section Headers]`.

The rationale was that we generally want to account for the
entire "footprint" of a given entity, including all of the
metadata emitted as part of that entity. For example, for
`-d symbols` we attribute the `.eh_frame` footprint of each
function to the corresponding function. This is much more
useful than just seeing a chunk of `[.eh_frame]` with no
breakdown.

However I think the case of section/segment headers is somewhat
different. These headers are small and fixed-length, so there is
nothing the section/segment itself could have done to grow or
shrink its length except not existing to begin with.

Consider a specific example: you have 100 functions that you
compile with `-ffunction-sections`. This generates 100 section
headers that total to 6400 bytes, since each section header is
64 bytes. It is not especially useful if Bloaty just reports
each section of length N as N+64 to account for the section
headers. In fact this obscures the fact that 6400 bytes of the
binary are spent on section headers. And that 64 bytes is not
really part of the "weight" of each function, the "weight"
is actually coming from the `-ffunction-sections` argument
which caused the 100 functions to emit 6400 bytes of section
headers instead of 64.

Ultimately, the strongest arguments for this change are:

1. As described above, the number of sections in the binary
   (and the resulting total section overhead) is really a
   function of the way the binary was compiled, and doesn't
   have much to do with the individual sections themselves
   or the data contained therein. If the section overhead
   is too high, the solution is to compile the binary in a
   different way, *not* to trim the contents of the individual
   sections.
2. If we do not surface the total weight of the section headers
   in `-d sections`, there is really no other way to get this
   information from Bloaty. There is no other data source
   that will split out section headers from section contents.
3. It makes the memory maps look much more concise and logical.
   I think the lit tests in this commit will make that clear.
   Seeing the section headers attributed by section made the
   memory map more noisy and less useful.
6 files changed
tree: 1244f4d9a71045b5167dd40b9ecbe284c5038c1c
  1. .github/
  2. doc/
  3. src/
  4. tests/
  5. third_party/
  6. .clang-format
  7. .gitignore
  8. .gitmodules
  9. CHANGES.md
  10. CMakeLists.txt
  11. config.bloaty
  12. CONTRIBUTING.md
  13. custom_sources.bloaty
  14. LICENSE
  15. make-release-tarball.sh
  16. README.md
  17. regen-readme.py
README.md

Bloaty: a size profiler for binaries

build

Ever wondered what‘s making your binary big? Bloaty will show you a size profile of the binary so you can understand what’s taking up space inside.

$ ./bloaty bloaty -d compileunits
    FILE SIZE        VM SIZE    
 --------------  -------------- 
  34.8%  10.2Mi  43.4%  2.91Mi    [163 Others]
  17.2%  5.08Mi   4.3%   295Ki    third_party/protobuf/src/google/protobuf/descriptor.cc
   7.3%  2.14Mi   2.6%   179Ki    third_party/protobuf/src/google/protobuf/descriptor.pb.cc
   4.6%  1.36Mi   1.1%  78.4Ki    third_party/protobuf/src/google/protobuf/text_format.cc
   3.7%  1.10Mi   4.5%   311Ki    third_party/capstone/arch/ARM/ARMDisassembler.c
   1.3%   399Ki  15.9%  1.07Mi    third_party/capstone/arch/M68K/M68KDisassembler.c
   3.2%   980Ki   1.1%  75.3Ki    third_party/protobuf/src/google/protobuf/generated_message_reflection.cc
   3.2%   965Ki   0.6%  40.7Ki    third_party/protobuf/src/google/protobuf/descriptor_database.cc
   2.8%   854Ki  12.0%   819Ki    third_party/capstone/arch/X86/X86Mapping.c
   2.8%   846Ki   1.0%  66.4Ki    third_party/protobuf/src/google/protobuf/extension_set.cc
   2.7%   800Ki   0.6%  41.2Ki    third_party/protobuf/src/google/protobuf/generated_message_util.cc
   2.3%   709Ki   0.7%  50.7Ki    third_party/protobuf/src/google/protobuf/wire_format.cc
   2.1%   637Ki   1.7%   117Ki    third_party/demumble/third_party/libcxxabi/cxa_demangle.cpp
   1.8%   549Ki   1.7%   114Ki    src/bloaty.cc
   1.7%   503Ki   0.7%  48.1Ki    third_party/protobuf/src/google/protobuf/repeated_field.cc
   1.6%   469Ki   6.2%   427Ki    third_party/capstone/arch/X86/X86DisassemblerDecoder.c
   1.4%   434Ki   0.2%  15.9Ki    third_party/protobuf/src/google/protobuf/message.cc
   1.4%   422Ki   0.3%  23.4Ki    third_party/re2/re2/dfa.cc
   1.3%   407Ki   0.4%  24.9Ki    third_party/re2/re2/regexp.cc
   1.3%   407Ki   0.4%  29.9Ki    third_party/protobuf/src/google/protobuf/map_field.cc
   1.3%   397Ki   0.4%  24.8Ki    third_party/re2/re2/re2.cc
 100.0%  29.5Mi 100.0%  6.69Mi    TOTAL

Bloaty performs a deep analysis of the binary. Using custom ELF, DWARF, and Mach-O parsers, Bloaty aims to accurately attribute every byte of the binary to the symbol or compileunit that produced it. It will even disassemble the binary looking for references to anonymous data.

Bloaty supports many features:

  • file formats: ELF, Mach-O, PE/COFF (experimental), WebAssembly (experimental)
  • data sources: compileunit (shown above), symbol, section, segment, etc.
  • hierarchical profiles: combine multiple data sources into a single report
  • size diffs: see where the binary grew, perfect for CI tests
  • separate debug files: strip the binary under test, while making debug data available for analysis
  • flexible demangling: demangle C++ symbols, optionally discarding function/template parameters
  • custom data sources: regex rewrites of built-in data sources, for custom munging/bucketing
  • regex filtering: filter out parts of the binary that do or don't match a given regex
  • easy to deploy: statically-linked C++ binary, easy to copy around

For detailed info on all of Bloaty's features, see the User Documentation.

For more information about the analysis performed by Bloaty, please see How Bloaty Works.

Install

To build, use cmake. For example:

$ cmake -B build -G Ninja -S .
$ cmake --build build
$ cmake --build build --target install

Bloaty bundles libprotobuf, re2, capstone, and pkg-config as Git submodules, and uses protoc build from libprotobuf, but it will prefer the system's versions of those dependencies if available. All other dependencies are included as Git submodules.

If the Git repository hasn't been cloned with the --recursive, the submodules can be checked out with:

$ git submodule update --init --recursive

To run the tests, see the info in tests/README.md.

Support

GitHub issues and PRs welcome. Please include tests when possible, see: tests/README.md.

This is not an official Google product.