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
  [-t|--types]
  [{-i|--ignore} <ignore-option>] ...
  [{-f|--format} <output-format>] ...
  [{-o|--output} {filename|-}] ...
  [{-F|--fidelity} {filename|-}]
implicit defaults: --stg --format small
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 primitive 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=""]
    }
    

Other options:

  • -m|--metrics: print duration of ABI parsing, comparison and reporting.

Return code

If input files' ABIs are equivalent, 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 -