# `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} <ignore-option>] ...
  [{-f|--format} <output-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 -
    ```
