Skip to main content

check-symbols

Command-line utility for checking ELF symbols.

It lists the dynamic symbols exported by a shared library, checks them against a list of expected symbols, or compares them with the symbols an executable or another library imports. Symbol names are demangled and normalised before they are printed or compared.

Requirements

  • Linux, or another platform that uses ELF binaries
  • GNU nm (part of binutils) on the PATH
  • Python 3.9 or higher

Installation

pip3 install check-symbols

Usage

check-symbols is a command-line application:

usage: check-symbols [-h] [--version] [--check <path>] [--diff <path>] [--include <regex> [<regex> ...]]
                     [--exclude <regex> [<regex> ...]]
                     [<path>]

Command-line utility for checking ELF symbols.

positional arguments:
  <path>                path to the shared library, or a directory containing it (default: discover automatically)

options:
  -h, --help            show this help message and exit
  --version             print the version and exit
  --check <path>        path to a text file containing a list of expected symbols (one per line). use a dash ('-') to
                        read from stdin.
  --diff <path>         compiled executable or shared library expected to consume the symbols
  --include <regex> [<regex> ...]
                        one or more regular expressions to select the listed/checked symbols.
  --exclude <regex> [<regex> ...]
                        one or more regular expressions to exclude from the listed/checked symbols.

v0.1.0 - github.com/marzer/check-symbols

With neither --check nor --diff, the exported symbols are printed one per line. This output is valid input for --check, so check-symbols libfoo.so > symbols.txt makes a first check file.

When the path is a directory, the first .so file in it (in sorted order) is used. Without a path, the current directory is searched.

--check compares the exported symbols with a check file. --diff compares them with the undefined symbols of an executable or another shared library. Every import that the library does not export counts as missing, including imports from other libraries such as libc. A diff is therefore usually narrowed with --include or --exclude. Both modes can be used in one run.

--include keeps the symbols that match every pattern, and --exclude drops the symbols that match any pattern. They apply to both sides of a check or diff. Both options take one or more values, so give the library path before them, or end the patterns with --.

Check files

A check file holds one symbol per line, in the form that list mode prints. Blank lines are ignored. Comments start with #, ; or // and run to the end of the line. A marker inside braces, square brackets or parentheses, such as the # in {lambda(int)#1} or the ; in [u8; 16], does not start a comment.

Lines in a check file are normalised in the same way as the library's symbols, so ns::foo(int) const matches ns::foo.

Normalisation

Symbols are read with nm -PBDCg, which prints the demangled dynamic symbols, and are then normalised:

  • Only symbols of type B, D and T (uninitialised data, initialised data and code) are kept. Linker-generated symbols such as _edata and __bss_start are dropped.
  • Version tags are removed: adler32@@ZLIB_1.2.0 becomes adler32.
  • Parameter lists and cv- and ref-qualifiers are removed, so all overloads of a function share one name: ns::vec::get(int) const becomes ns::vec::get.
  • nm prints return types only for function templates. Everything before the first space outside brackets is removed, so int ns::vec::get<int>(int) becomes ns::vec::get<int> and unsigned int ns::vec::size<int>() becomes int ns::vec::size<int>.
  • Operators keep their names: ns::vec::operator new, ns::vec::operator(), ns::operator<<. Conversion operators keep their target type: ns::vec::operator bool.
  • Lambdas and other local entities keep the name and parameter list of the enclosing function: ns::foo()::{lambda(int)#1}::operator().
  • Common standard library types are shortened, and the [abi:cxx11] tag is removed (other ABI tags are kept): std::basic_string<char, std::char_traits<char>, std::allocator<char> > becomes std::string.
  • vtables, typeinfo objects, typeinfo names and VTTs become X::$vtable, X::$typeinfo, X::$typeinfo_name and X::$VTT.
  • The list is sorted, and duplicates are removed.

Exit codes

Mode Value Meaning
any 0 No issues were found
--check 1 Some expected symbols listed in the check file were missing from the shared library
--check 2 Some unexpected symbols not listed in the check file were found in the shared library
--check 3 Both of the above
--diff 1 Some symbols imported by the target binary were missing from the shared library
any 255 A fatal error occurred

Values 1 and 2 are bit flags. When --check and --diff are used together, their results are combined, so a missing symbol in either mode sets bit 1.

On invalid command-line arguments, argparse exits with 2. A script cannot tell this apart from bit 2 by the exit code alone.

Contributing

See CONTRIBUTING.md.

Changelog

v0.2.0 - 2026-10-15

  • fixed versioned symbols (foo@@VER) keeping a trailing @, which also stopped their parameter lists being removed
  • fixed soname version tags (foo@@libfoo-1.0.so.0) not being removed
  • fixed operator new, operator delete and conversion operators being listed as new, delete and the target type
  • fixed operator() names changing when read back from a check file
  • fixed conversion operators to function and member function pointer types changing when read back from a check file
  • fixed typeinfo name for X being normalised to name for X::$typeinfo (it is now X::$typeinfo_name)
  • fixed names containing # (e.g. lambdas) being cut short; comments are now only stripped from check files, and never inside braces, square brackets or parentheses
  • fixed a crash on check-file lines with an unmatched )
  • fixed a missing nm and invalid --include/--exclude patterns being reported as internal bugs
  • fixed directory discovery picking an arbitrary .so file when there were several (it now takes the first in sorted order)
  • improved speed on libraries with many symbols
  • dropped support for Python 3.8

v0.1.0 - 2024-06-14

  • First public release 🎉

Metadata

Release files for check-symbols 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for check-symbols 0.2.0
File Size Uploaded
check_symbols-0.2.0.tar.gz 20.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for check-symbols 0.2.0
File Interpreter ABI Platform
check_symbols-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 33.3 kB

Release files / check_symbols-0.2.0.tar.gz

Download URL check_symbols-0.2.0.tar.gz
Size 20.7 kB
Tags Source
SHA-256 checksum
How to use checksums
28b5e18f1e36b4a951b74c4005498753dca5b4424c5bf98f0d54886fb3fcc4d0
BLAKE2b-256 checksum
How to use checksums
350c2ed99f86fa5e643091859f97041a3f9bbaf1f5a04d4559487d57085893d9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release files / check_symbols-0.2.0-py3-none-any.whl

Download URL check_symbols-0.2.0-py3-none-any.whl
Size 12.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
edea09277c1080492bf99d1bcfa8968aa8a431bac090ddcd964cfdcf62b0b7b4
BLAKE2b-256 checksum
How to use checksums
8e5a389e26607f206d250cb9f26c833eb76aaf82d8b1833174e3ef561eac576b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.1

2 release files

0.3.0

2 release files

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page