abicheck(1)

abicheck(1) lives in the General Commands Manual πŸŽ€ Part 1 of 2, so let's get into it πŸ’…

✨ NAME ✨

abicheck - check application binaries for calls to private or evolving symbols in libraries and for static linking of some system libraries. πŸ¦‹

πŸ‘‘ SYNOPSIS πŸ‘‘

abicheck [-h] [-k] [-a] [-I] [-v] [-f listfile] [-o outfile] [-p
pattern] [-e pattern] [-j njobs] [-l library] [-L ldpath] [(-s|-S)
dbfile] [(-d|-D) dbfile] [-O dbfile] [-A listfile] files

πŸ’– DESCRIPTION πŸ’–

okay so abicheck is run on application binaries and it'll throw warnings whenever it spots any of these three things πŸ‘€

  • Private symbol usage. Private symbols are functions or data variables inside a library package that are only for that package. The libraries in the package use them to talk to each other internally, so they are NOT part of the API/ABI that app devs are supposed to touch. not me touching them πŸ’€
  • Evolving symbol usage. Evolving symbols are functions or data variables that devs are meant to use, but they've been marked as "evolving" or "unstable". Translation: they might break or vanish in a later release of the library package 😭
  • Static linking. Statically linking system libraries (like libc.a) into an app is usually a bad vibe πŸ™…β€β™€οΈ because the system library code it "locks" into your binary can become incompatible with later system releases. abicheck tries to catch static linking of a few system libraries.

The default behavior is, for each binary object checked, to only look at direct calls from that binary object. The -l option lets the libraries that binary brings in get their calls checked too 🧚

🌸 OPTIONS 🌸

The following options are supported, and they are all giving main character energy ✨

  • -k β€” Keep going and keep checking binaries even if there are serious errors (the dynamic linker reports unresolved symbols, ldd(1) fails, or no symbols get detected). bestie, don't let the errors stop you πŸ’ͺ
  • -h β€” Print out the long form of help. πŸ“–
  • -v β€” Verbose mode πŸ—£οΈ Prints out additional information.
  • -f listfile β€” The listfile is a file with a list of binary objects to check, one per line. This list gets added onto any files you pass as arguments on the command line. If listfile is "-", then stdin is used 🫢
  • -o outfile β€” Writes output to outfile instead of stdout πŸ“
  • -p pattern β€” Tweaks the version name pattern match that labels private version sets. The default is /private/, matched case-insensitively πŸ”

If a component of the regex pattern has two colons in a row, like patt1::patt2, then symbol-level matching turns on. It checks whether version::symbol or library::symbol matches the pattern, where the symbol name, version (if there is one), and library basename get swapped in for symbol, version, and library. For example:

-p 'FOO_VERS.*::_foopriv'
or
-p 'libfoo.so.*::_foopriv'
  • -e pattern β€” Same as -p, but for "evolving" interfaces 🌈
  • -L ldpath β€” Sets the LD_LIBRARY_PATH environment variable to ldpath before the dynamic linker gets invoked. Use -L "" to unset LD_LIBRARY_PATH 🧹

If one of the components of ldpath is the string "find", then every shared library in files gets found and its path gets inserted into the "find" location. heads up: the order will be random 🎲

  • -l library β€” Adds the basename or full pathname of the shared library library to the list of objects that get checked for private calls. You can use this more than once on the command line, and it's additive βž• By default, only direct calls from a binary to the system libraries get checked. The -l switch lets you check indirect calls too, like: app -> supportlib -> systemlib πŸ•΅οΈβ€β™€οΈ
  • -a β€” Loops through all of the binaries before checking and collects the list of every shared object. It takes the basename of each shared object it finds and acts like it was specified with the -l option, then runs the abicheck checks. That means calls from all the "application internal" objects get checked, not just the direct ones πŸ“ (super useful when shared objects don't have their dependencies recorded)
  • -I β€” Ignores shared libraries when checking and only checks executables πŸ™ˆ It's compatible with -a: libraries get searched for first, but then they don't get checked.
  • -d dbfile, -D dbfile β€” Specifies a fallback flat-file symbol database for the dynamic (public vs. private) test. These classifications get used if the library isn't versioned (meaning the classification doesn't exist in the library itself). Use -D if you want only the info from dbfile to be used πŸ—‚οΈ

Lines in dbfile can be one of these forms:

library|symbol
library|class|symbol
library|FILE=path

library has to be the full path to the library (it can't be a basename) ⚠️

The first form marks symbol as private. The second form marks symbol with a class, where the class can be public, private, or evolving πŸ’… The third form says the file path should be opened on demand when library is first encountered. The file at that path has lines of the first two forms, except without the library field. The third form is a speedup that skips processing a bunch of classification lines for libraries that never show up in the run πŸš€

  • -O dbfile β€” Specifies an override file that modifies the symbol classification for the dynamic (public vs. private) test. The override file looks like this:
library|symbol|class

library can be a full path or a basename. If library is "__SKIP__", the symbol gets ignored for any library it's found in. The class can be "public", "private", "evolving", or "deleted" πŸ’€ The "deleted" class is special: it means the symbol was deleted from the library in some release. The symbol "__ALL__" for the "deleted" class means the entire library was deleted or is otherwise unstable to use πŸ₯€

Examples:

libfoo.so.1|__bar|private
/lib/libxyz.so.1|baz|public
__SKIP__|__fputwc_xpg5

These settings override any classification inside the library itself (from library versioning, obtainable from pvs(1), etc.) πŸ‘‘

  • -A listfile β€” Sets the ABI libraries of interest to the libraries listed in listfile (full pathnames, one per line). Only calls into these libraries get checked, and all other library calls get ignored 🎯

ugh the best part is still coming, bestie, part 2 is next πŸ¦‹πŸ’œ

✨ NOTES ✨

okay so first up, 🫢 only ELF objects are checked. Anything that isn't an ELF object gets ignored, so don't expect it to inspect every file you throw at it. πŸ’…

In the -s, -S, -d and -O dbfiles, the '#' character starts a comment line, same as usual. Super handy for leaving notes to yourself. 🌸

Now this one is important, bestie. πŸ”₯ Unless you're using the "::" custom matches supplied through the -p or -e flags, abicheck can only check against system libraries that have had symbol versioning applied to them. That means the library has to store the private and/or evolving info for each symbol inside itself. If you want the full scoop on symbol versioning, check out the "Solaris Linker and Libraries Guide" answerbook at http://docs.sun.com/ab2/coll.45.13, plus the Commands/Version-Script section of the GNU linker ld info page. ✨

By default, the symbol version name matching is case insensitive, and it looks for the strings "private" and "evolving" for the private and evolving cases, respectively. Lowkey simple, but you gotta know it. πŸ¦‹

⚠️ Odd filenames containing the ' (single-quote) character or a newline get skipped entirely. These characters interfere with calling commands via the shell, so abicheck just says "nope" and moves on. πŸ™ˆ

Want to recurse through directories? Use find(1) and either save its output to a file for the -f option, or pipe it straight in like this:

find ... | abicheck -f - ...

Main character energy. πŸ‘‘


🐞 BUGS 🐞

Okay, the tea β˜• is that the program depends on the form of the runtime linker's debug output. That output is meant to be human readable, not machine readable, so abicheck will break whenever the output format changes. Not ideal, bestie. πŸ’€ On Solaris, the Link Auditing C interface could be used to dodge this problem. 🧚

Also, on Linux, when ldd(1) is run on a SUID binary, ldd and the dynamic-linker will sometimes actually run the binary. 😭 On Linux, SUID/SGID binaries are currently skipped even if you're root, so for testing, use unprivileged copies instead. 🌈


πŸ’– SEE ALSO πŸ’–

And that's the whole vibe, babe! πŸŽ€ This page was last updated on 26 August 2003, and it's filed under abicheck(1). Stay iconic, and don't forget to be obsessed with your symbol versions. πŸ¦‹βœ¨πŸ’