# `stgdiff` `stgdiff` is used to compare ABI representations from various sources, like libabigail XML, BTF and ELF/DWARF. ## Usage ``` stgdiff [-m|--metrics] [-a|--abi|-b|--btf|-e|--elf|-s|--stg] file1 [-a|--abi|-b|--btf|-e|--elf|-s|--stg] file2 [-x|--exact] [-t|--types] [{-i|--ignore} ] ... [{-f|--format} ] ... [{-o|--output} {filename|-}] ... [{-F|--fidelity} {filename|-}] implicit defaults: --abi --format small --exact (node equality) cannot be combined with --output output formats: plain flat small short viz ignore options: type_declaration_status symbol_type_presence primitive_type_encoding member_size enum_underlying_type qualifier linux_symbol_crc interface_addition type_definition_addition ``` ## Input ### Formats * `-a|--abi` Read ABI XML representation generated by libabigail's `abidw`. Not all ABI XML features are consumed. Some XML "tidying" is performed before parsing: * types with naming typedefs are re-anonymised * (rare) duplicate data members are removed * (partial and entire) duplicate type definitions are removed After parsing, function parameter and return type qualifiers are removed. * `-b|--btf` Read ABI information from the `.BTF` ELF section. BTF only covers the C type system and can be obtained in the following ways: * `gcc -gbtf` generates BTF instead of DWARF * `clang -c -g -target bpf` works similarly, but only for BPF targets * `pahole -J` reads existing DWARF debug information and adds BTF * `-e|--elf` Read ABI information from ELF symbols and DWARF types. * `-s|--stg` Read ABI information from a `.stg` file. ### Options * `--types` Captures all named types found in ELF files as interface types, regardless of whether those types are reachable by any symbol. ## Comparison The default behaviour is to compare two ABIs for equivalence. ### Options * `-i|--ignore` The following two ignore options suppress noisy diffs that are inevitable when consuming ABI XML output from `abidw`. * `symbol_type_presence` Ignore changes in symbol type presence, thus `stgdiff` does not report loss or gain of symbol type information. * `type_declaration_status` Ignore changes in type declaration status, thus `stgdiff` does not report loss or gain of user-defined type definitions. The following options are useful when comparing ABI representations that differ in how much (DWARF) information they preserve. * `primitive_type_encoding` Ignore primitve type encodings during comparison. BTF provides a subset of encoding information. libabigail XML lacks encoding information. * `member_size` Ignore member sizes during comparison. libabigail XML does not model them. * `enum_underlying_type` Ignore enum-underlying types during comparison. BTF doesn't model them. libabigail provides incomplete information. * `qualifier` Ignore qualifiers during comparison. Both libabigail and STG interpret and adjust type qualifiers but sometimes do so differently. * `linux_symbol_crc` Ignore Linux kernel symbol CRC changes during comparison. This can be useful for ABI comparisons across different toolchains, where CRC changes are often large and not useful. These two options can be used for ABI compatibility testing where the first ABI is expected to be a subset of the second. * `interface_addition` Ignore interface (symbol and type root) additions during comparison. * `type_definition_addition` Ignore type definition additions during comparison. Any extra symbol and type roots may reach extra definitions of existing types. ### Fidelity Reporting * `-F|--fidelity` Compares ABI representations for fidelity of symbol and type information. It reports the following kinds of fidelity changes: * Addition or removal of types (fully defined or declaration only) * Loss or gain of type definitions * Loss or gain of type information for symbols ## Output All outputs are based on a diff graph which is rooted at the comparison of two symbol table nodes. The `--format` and `--output` options may be repeated to obtain outputs of different formats. ### Formats * `plain` Serialise the diff graph via depth first search, avoiding revisiting nodes that have been visited or are being visited. The report mirrors the search tree. This format is only suitable for small inputs because the indentation level is proportional to recursion depth and the resulting output may be unreadable. Example: ``` function symbol 'unsigned int fun(enum A, enum B)' changed type 'unsigned int(enum A, enum B)' changed parameter 1 type 'enum A' changed enumerator 'Ae' value changed from 0 to 1 parameter 2 type 'enum B' changed enumerator 'Be' value changed from 1 to 2 ``` * `flat` Serialise the diff graph being broken into smaller pieces, each rooted at a symbol, a user-defined type or a primitive type. Each piece is serialised as a tree at the top level. Example: ``` function symbol 'unsigned int fun(enum A, enum B)' changed type 'unsigned int(enum A, enum B)' changed parameter 1 type 'enum A' changed parameter 2 type 'enum B' changed type 'enum A' changed enumerator 'Ae' value changed from 0 to 1 type 'enum B' changed enumerator 'Be' value changed from 1 to 2 ``` * `small` Like the `flat` output, but any subtrees that contain no diffs are pruned. This report excludes symbols and types that have changed only due to some other type change. Example: ``` type 'enum A' changed enumerator 'Ae' value changed from 0 to 1 type 'enum B' changed enumerator 'Be' value changed from 1 to 2 ``` * `short` The `short` report is a result of the following post-processing transformations on the `small` report: * Changes in symbols where only the CRC value has changed are collapsed and the total number of changes is reported. * Runs of member offset changes are collapsed and the amount by which the offsets have shifted is reported. * Added and removed symbols are reported in a compact manner with variable and function symbols separated. * `viz` Print the difference graph in Graphviz format. Example: ``` digraph "ABI diff" { "0" [shape=rectangle, label="'symbols'"] "1" [label="'unsigned int fun(enum A, enum B)'"] "2" [label="'unsigned int(enum A, enum B)'"] "3" [color=red, shape=rectangle, label="'enum A'"] "3" -> "3:0" "3:0" [color=red, label="enumerator 'Ae' value changed from 0 to 1"] "2" -> "3" [label="parameter 1"] "4" [color=red, shape=rectangle, label="'enum B'"] "4" -> "4:0" "4:0" [color=red, label="enumerator 'Be' value changed from 1 to 2"] "2" -> "4" [label="parameter 2"] "1" -> "2" [label=""] "0" -> "1" [label=""] } ``` ## Exact Node Equality * `-x|--exact`: perform exact node equality (ignoring node identity) instead of generating an ABI equivalence diff graph; no outputs may be specified. ## Other options: * `-m|--metrics`: print duration of ABI parsing, comparison and reporting. ## Return code If input files' ABIs are equivalent (or equal with `--exact`), `stgdiff` will return 0. Otherwise: * Return code 1: there was an exception during comparison, see `stderr` for the exception reason. * Return code 4: ABIs differ. ## Examples * Compare two ABI XML files, and print a short report to stdout: ``` stgdiff -a abi.0.xml abi.1.xml -f short -o - ``` * Compare two ABI XML files **without printing anything**: ``` stgdiff -a abi.0.xml abi.1.xml && echo "Equivalent" || echo "Not equivalent, return code: $?" ``` * Compare two ABI XML files, print short report to stdout and also print diff graph visualisation to the file: ``` stgdiff -a abi.0.xml abi.1.xml -f short -o - -f viz -o graph.viz ``` * Compare two ABI XML files, ignoring type presence and type declaration status changes, and print short report to stdout: ``` stgdiff -i symbol_type_presence -i type_declaration_status -a abi.0.xml abi.1.xml -f short -o - ``` * Compare ABI XML to ABI from ELF and print a short report to file: ``` stgdiff -a abi.xml -e example.o -f short -o example.diff ``` * Compare two STG files and print fidelity report to stdout: ``` stgdiff -s abi.0.stg abi.1.stg -F - ``` * Compare symbols and named types in two ELF files and print a short report to stdout: ``` stgdiff -t -e example1.o example2.o -f short -o - ```