1ABI Monitoring for Android Kernels 2================================== 3 4Overview 5-------- 6In order to stabilize the in-kernel ABI of Android kernels, the ABI Monitoring 7tooling has been created to collect and compare ABI representations from 8existing kernel binaries (vmlinux + modules). The tools can be used to track 9and mitigate changes to said ABI. This document describes the tooling, the 10process of collecting and analyzing ABI representations and how such 11representations can be used to ensure stability of the in-kernel ABI. Lastly, 12this document gives some details about the process of contributing changes to 13the Android kernels. 14 15This directory contains the specific tools for the ABI analysis. It should be 16used as part of the build scripts that are provided by this repository (see 17`../build_abi.sh`). 18 19Process Description 20------------------- 21 22Analyzing the kernel's ABI is done in multiple steps. Most of the steps can be 23automated: 24 25 1. Acquire the toolchain, build scripts and kernel sources through `repo` 26 2. Provide any prerequisites (e.g. libabigail) 27 3. Build the kernel and its ABI representation 28 4. Analyze ABI differences between the build and a reference 29 5. Update the ABI representation (if required) 30 6. Working with symbol whitelists 31 32 33The following instructions work for any kernel that can be built using a 34supported toolchain (i.e. a prebuilt Clang toolchain). There exist [`repo` 35manifests](https://android.googlesource.com/kernel/manifest/+refs) for all 36Android common kernel branches, for some upstream branches (e.g. 37upstream-linux-4.19.y) and several device specific kernels that ensure the 38correct toolchain is used when building a kernel distribution. 39 40 41Using the ABI Monitoring tooling 42-------------------------------- 43 44### 1. Acquire the toolchain, build scripts and kernel sources through repo 45 46Toolchain, build scripts (i.e. these scripts) and kernel sources can be 47acquired with `repo`. For detailed documentation, refer to the corresponding 48documentation on 49[source.android.com](https://source.android.com/setup/build/building-kernels). 50 51To illustrate the process, the following steps use `common-android-mainline`, 52an Android kernel branch that is kept up-to-date with the upstream Linux 53releases. In order to obtain this branch via `repo`, execute 54 55``` 56 $ repo init -u https://android.googlesource.com/kernel/manifest -b common-android-mainline 57 $ repo sync 58``` 59 60### 2. Provide any prerequisites 61 62**NOTE**: Googlers might want to follow the steps in 63[go/kernel-abi-monitoring](http://go/kernel-abi-monitoring) to use a prebuilt 64libabigail distribution. 65 66The ABI tooling makes use of [libabigail](https://sourceware.org/libabigail/), 67a library and collection of tools to analyze binaries. In order to use the 68tooling, users are required to provide a functional libabigail installation. 69The released version of your Linux distribution might not be a supported one; 70hence, it is recommended way to use the `bootstrap` script which can be found in 71this directory. The `bootstrap` script automates the process of acquiring and 72building a valid libabigail distribution and needs to be executed without any 73arguments like so: 74 75``` 76 $ build/abi/bootstrap 77``` 78 79The script will ensure the following system prerequisites are installed along 80with their dependencies: 81 82 - autoconf 83 - libtool 84 - libxml2-dev 85 - pkg-config 86 - python3 87 88**NOTE**: At the moment, only apt based package managers are supported, but 89`bootstrap` provides some hints to help users that have other package 90managers. 91 92The script continues with acquiring the sources for the correct versions of 93*elfutils* and *libabigail* and will build the required binaries. At the very 94end the script will print instructions to add the binaries to the local 95`${PATH}`. The output will look similar to: 96 97``` 98 NOTE: Export the following environment before running the executables: 99 100 export PATH="/src/kernel/build/abi/abigail-inst/d7ae619f/bin:${PATH}" 101 export LD_LIBRARY_PATH="/src/kernel/build/abi/abigail-inst/d7ae619f/lib:/src/kernel/build/abi/abigail-inst/d7ae619f/lib/elfutils:${LD_LIBRARY_PATH}" 102``` 103 104**NOTE**: It is probably a good idea to save these instructions to reuse the 105prebuilt binaries in a later session. 106 107Follow the instructions to enable the prerequisites in your environment. 108 109### 3. Build the kernel and its ABI representation 110 111At this point you are ready to build a kernel with the correct toolchain and to 112extract an ABI representation from its binaries (vmlinux + modules). 113 114Similar to the usual Android kernel build process (using `build.sh`), this step 115requires running `build_abi.sh`. 116 117``` 118 $ BUILD_CONFIG=common/build.config.gki.aarch64 build/build_abi.sh 119``` 120 121**NOTE**: `build_abi.sh` makes use of `build.sh` and therefore accepts the 122same environment variables to customize the build. It also *requires* the same 123variables that would need to be passed to `build.sh`, such as `BUILD_CONFIG`. 124 125That builds the kernel and extracts the ABI representation into the `out` 126directory. In this case `out/android-mainline/dist/abi.xml` would be a symbolic 127link to `out/android-mainline/dist/abi-<id>.xml`. `id` is computed from 128executing `git describe` against the kernel source tree. 129 130### 4. Analyze ABI differences between the build and a reference representation 131 132`build_abi.sh` is capable of analyzing and reporting any ABI differences when 133a reference is provided via the environment variable `ABI_DEFINITION`. 134`ABI_DEFINITION` should point to a reference file relative to the kernel source 135tree and can be specified on the command line or (more commonly) as a value in 136*build.config*. E.g. 137 138``` 139 $ BUILD_CONFIG=common/build.config.gki.aarch64 \ 140 ABI_DEFINITION=abi_gki_aarch64.xml \ 141 build/build_abi.sh 142``` 143 144Above, the `build.config.gki.aarch64` defines the reference file (as 145*abi_gki_aarch64.xml*) and therefore the analysis has been completed. If an 146abidiff was executed, then `build_abi.sh` will print the location of the report 147and identify any ABI breakage. If breakages are detected, then `build_abi.sh` 148will terminate and return a non-zero exit code. 149 150### 5. Update the ABI representation (if required) 151 152To update the ABI dump, `build_abi.sh` can be invoked with the `--update` flag. 153It will update the corresponding abi.xml file that is defined via the 154build.config. It might also be useful to invoke the script with `--print-report` 155to print the differences the update fixes. The report is useful to include in 156the commit message when updating the abi.xml. 157 158### 6. Working with symbol whitelists 159 160`build_abi.sh` can be parameterized to filter symbols during extraction and 161comparison with KMI (Kernel Module Interface) whitelists. These are simple 162plain text files that list relevant ABI kernel symbols. E.g. a whitelist file 163with the following content would limit ABI analysis to the ELF symbols with the 164names `symbol1` and `symbol2`: 165 166``` 167 [abi_whitelist] 168 symbol1 169 symbol2 170``` 171 172**NOTE**: Please refer to the [libabigail 173documentation](https://sourceware.org/libabigail/manual/kmidiff.html#environment) 174for details about the KMI whitelist file format. 175 176Changes to other ELF symbols would not be considered any longer unless they are 177indirectly affecting symbols that are whitelisted. A whitelist file can be 178specified -- similar to the abi baseline file via `ABI_DEFINITION=` -- in the 179corresponding `build.config` configuration file with `KMI_WHITELIST=` as a file 180relative to the kernel source directory (`$KERNEL_DIR`). In order to allow a 181certain level of organization, additional whitelist files can be specified by 182using `ADDITIONAL_KMI_WHITELISTS=` in the `build.config`. Similarly, it refers 183to whitelists in the `$KERNEL_DIR` and multiple files need to be separated by 184whitespaces. 185 186In order to **create an initial whitelist or to update an existing one**, the 187script `extract_symbols` is provided. When run pointing at a `DIST_DIR` of an 188Android Kernel build, it will extract the symbols that are exported from 189vmlinux _and_ are required by any module in the tree. 190 191Consider `vmlinux` exporting the following symbols (usually done via the 192EXPORT_SYMBOL* macros): 193 194``` 195 func1 196 func2 197 func3 198``` 199 200Also, consider there are two modules `modA.ko` and `modB.ko` which require the 201following symbols (i.e. `undefined` entries in the symbol table): 202 203``` 204 modA.ko: func1 func2 205 modB.ko: func2` 206``` 207 208From an ABI stability point of view we need to keep `func1` and `func2` stable 209as these are used by an external module. On the contrary, while `func3` is 210exported it is not actively used (i.e. required) by any module. The whitelist 211would therefore contain `func1` and `func2` only. 212 213`extract_symbols` offers a flag to update an existing or create a new whitelist 214based on the above analysis: `--whitelist <path/to/abi_whitelist>`. 215 216In order to update an existing whitelist based on a built Kernel tree, run 217`extract_symbols` as follows. The example uses the *common-android-mainline* 218branch of the Android Common Kernels following the official [build 219documentation](https://source.android.com/setup/build/building-kernels) and 220updates the whitelist for the GKI aarch64 Kernel. 221 222``` 223 (build the kernel) 224 $ BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh 225 226 (update/create the whitelist) 227 $ build/abi/extract_symbols out/android-mainline/dist --whitelist common/abi_gki_aarch64_whitelist 228``` 229 230**NOTE**: Be aware that `extract_symbols` recursively discovers Kernel modules 231by extension (*.ko) and considers all found ones. Orphan Kernel modules from 232prior runs might lead to incorrect results. Hence, make sure the directory you 233pass on to `extract_symbols` contains only the vmlinux and the modules you want 234it to consider. 235 236 237Working with the lower level ABI tooling 238---------------------------------------- 239 240Most users will need to use `build_abi.sh`. In some cases, it might be 241necessary to work with the lower level ABI tooling directly. There are 242currently two commands -- `dump_abi` and `diff_abi` -- that are available to 243collect and compare ABI files. These commands are used by `build_abi.sh`. See 244the following sections for their usages. 245 246### Creating ABI dumps from kernel trees 247 248Provided a linux kernel tree with built vmlinux and kernel modules, the tool 249`dump_abi` creates an ABI representation using the selected ABI tool. As of now 250there is only one option: 'libabigail' (default). A sample invocation looks as 251follows: 252 253``` 254 $ dump_abi --linux-tree path/to/out --out-file /path/to/abi.xml 255``` 256 257The file `abi.xml` will contain a combined textual ABI representation that can 258be observed from vmlinux and the kernel modules in the given directory. This 259file might be used for manual inspection, further analysis or as a reference 260file to enforce ABI stability. 261 262### Comparing ABI dumps 263 264ABI dumps created by `dump_abi` can be compared with `diff_abi`. Ensure to use 265the same abi-tool for `dump_abi` and `diff_abi`. A sample invocation looks like: 266 267``` 268 $ diff_abi --baseline abi1.xml --new abi2.xml --report report.out 269``` 270 271The report created is tool specific, but generally lists ABI changes detected 272that affect the kernel's module interface. The files specified as `baseline` 273and `new` are ABI representations collected with `dump_abi`. `diff_abi` 274propagates the exit code of the underlying tool and therefore returns a 275non-zero value in case the ABIs compared are incompatible. 276 277### Using KMI whitelists 278 279To filter dumps created with `dump_abi` or filter symbols compared with 280`diff_abi`, each of those tools provides a parameter `--kmi-whitelist` that 281takes a path to a KMI whitelist file: 282 283``` 284 $ dump_abi --linux-tree path/to/out --out-file /path/to/abi.xml --kmi-whitelist /path/to/whitelist 285``` 286 287Dealing with ABI breakages 288-------------------------- 289 290As an example, the following patch introduces a very obvious ABI breakage: 291 292``` 293 diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h 294 index 5ed8f6292a53..f2ecb34c7645 100644 295 --- a/include/linux/mm_types.h 296 +++ b/include/linux/mm_types.h 297 @@ -339,6 +339,7 @@ struct core_state { 298 struct kioctx_table; 299 struct mm_struct { 300 struct { 301 + int dummy; 302 struct vm_area_struct *mmap; /* list of VMAs */ 303 struct rb_root mm_rb; 304 u64 vmacache_seqnum; /* per-thread vmacache */ 305``` 306 307Running `build_abi.sh` again with this patch applied, the tooling will exit with 308a non-zero error code and will report an ABI difference similar to this: 309 310``` 311 Leaf changes summary: 1 artifact changed 312 Changed leaf types summary: 1 leaf type changed 313 Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function 314 Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable 315 316 'struct mm_struct at mm_types.h:372:1' changed: 317 type size changed from 6848 to 6912 (in bits) 318 there are data member changes: 319 [...] 320``` 321 322### How to fix a broken ABI on Android Gerrit 323 324If you didn't intentionally break the kernel ABI, then you need to investigate 325via the Android Gerrit test log to identify the issue(s) reported by the tool. Most 326common causes of breakages are added or deleted functions, changed data 327structures or changes to the ABI by adding config options that lead to any of 328the aforementioned. Most likely you want to start with addressing the issues 329found by the tool. 330 331You can reproduce the KernelABI test locally by running the following command 332with the same arguments that you would have run `build/build.sh` with. 333 334Example command for the GKI kernels: 335<pre> 336 $ BUILD_CONFIG=common/build.config.gki.aarch64 build/<b>build_abi.sh</b> 337</pre> 338 339### Updating the Kernel ABI 340 341If you need to update the kernel ABI, then you must update the corresponding 342`abi.xml` file in the kernel source tree. This is most conveniently done by 343using `build/build_abi.sh` like so: 344 345<pre> 346 $ build/<b>build_abi.sh</b> --update --print-report 347</pre> 348 349with the same arguments that you would have run `build/build.sh` with. This 350updates the correct `abi.xml` in the source tree and prints the detected 351differences. It is recommended to include the printed report in the commit 352message (at least partially). 353 354 355Android Kernel Branches with predefined ABI 356------------------------------------------- 357 358Some kernel branches might come with golden ABI representations for Android as 359part of their source distribution. These ABI representations are supposed to be 360accurate and should reflect the result of `build_abi.sh` as if you would execute 361it on your own. As the ABI is heavily influenced by various kernel configuration 362options, these .xml files usually belong to a certain configuration. E.g. the 363`common-android-mainline` branch contains an `abi_gki_aarch64.xml` that 364corresponds to the build result when using the `build.config.gki.aarch64`. In 365particular, `build.config.gki.aarch64` also refers to this file as its 366`ABI_DEFINITION`. 367 368Such predefined ABI representations are used as a baseline definition when 369comparing with `diff_abi` (s.a.). E.g. to validate a kernel patch in regards to 370any changes to the ABI, create the ABI representation with the patch applied and 371use `diff_abi` to compare it to the expected ABI for that particular source tree 372/ configuration. 373 374Caveats and known issues 375------------------------ 376- Version 1.7 of libabigail, that contains all currently required patches to 377 properly work on clang-built aarch64 Android kernels, has not been released 378 yet. Using a recent master is a sufficient workaround for that. The 379 `bootstrap` script refers to a sufficient commit from upstream. 380