build_abi: add support for symbol whitelisting

This adds support for specifying a symbol whitelist (also known as
Kernel Module Interface (KMI) whitelist) as build.config parameter. The
option KMI_WHITELIST needs to refer to a whitelist file relative to
$KERNEL_DIR and follows a very simple format [1]. Usually it will be a
text file with content like
  [abi_whitelist]
    symbol1
    symbol2
    ...

build_abi.sh will propagate this setting to diff_abi and dump_abi, such
that creation and comparison are parameterized correctly. Symbols not
mentioned in the whitelist will not be extracted into the dump created
by dump_abi and will subsequently not be compared during diff_abi.

[1] https://sourceware.org/libabigail/manual/kmidiff.html#environment

Bug: 140596566
Change-Id: Id764b75b095ce5a0d09e04763c5b5ef10173aa75
Signed-off-by: Matthias Maennich <maennich@google.com>
diff --git a/abi/abitool.py b/abi/abitool.py
index 997e9d2..a54d5e5 100644
--- a/abi/abitool.py
+++ b/abi/abitool.py
@@ -22,10 +22,10 @@
 
 class AbiTool(object):
     """ Base class for different kinds of abi analysis tools"""
-    def dump_kernel_abi(self, linux_tree, dump_path):
+    def dump_kernel_abi(self, linux_tree, dump_path, whitelist):
         raise NotImplementedError()
 
-    def diff_abi(self, old_dump, new_dump, diff_report):
+    def diff_abi(self, old_dump, new_dump, diff_report, whitelist):
         raise NotImplementedError()
 
     def name(self):
@@ -33,7 +33,7 @@
 
 class Libabigail(AbiTool):
     """" Concrete AbiTool implementation for libabigail """
-    def dump_kernel_abi(self, linux_tree, dump_path):
+    def dump_kernel_abi(self, linux_tree, dump_path, whitelist):
         dump_abi_cmd = ['abidw',
                         # omit various sources of indeterministic abidw output
                         '--no-corpus-path',
@@ -43,9 +43,13 @@
                         linux_tree,
                         '--out-file',
                         dump_path]
+
+        if whitelist is not None:
+            dump_abi_cmd.extend(['--kmi-whitelist', whitelist])
+
         subprocess.check_call(dump_abi_cmd)
 
-    def diff_abi(self, old_dump, new_dump, diff_report):
+    def diff_abi(self, old_dump, new_dump, diff_report, whitelist):
         log.info('libabigail diffing: {} and {} at {}'.format(old_dump,
                                                                 new_dump,
                                                                 diff_report))
@@ -56,6 +60,9 @@
                         old_dump,
                         new_dump]
 
+        if whitelist is not None:
+            diff_abi_cmd.extend(['--kmi-whitelist', whitelist])
+
         with open(diff_report, 'w') as out:
             try:
                 subprocess.check_call(diff_abi_cmd, stdout=out, stderr=out)
diff --git a/abi/diff_abi b/abi/diff_abi
index 7ea4448..738466b 100755
--- a/abi/diff_abi
+++ b/abi/diff_abi
@@ -21,9 +21,9 @@
 
 from abitool import get_abi_tool
 
-def diff_abi(abitool, baseline, new, out_file):
+def diff_abi(abitool, baseline, new, out_file, whitelist):
     tool = get_abi_tool(abitool)
-    return tool.diff_abi(baseline, new, out_file)
+    return tool.diff_abi(baseline, new, out_file, whitelist)
 
 def main():
     """ Build the linux kernel, freshly cloning if needed"""
@@ -36,13 +36,16 @@
                         help='abi tool to be used to monitor abi')
     parser.add_argument('--report', help='where to write the report to',
                         required=True)
+    parser.add_argument('--kmi-whitelist', default=None,
+                        help='KMI whitelist to filter for')
 
     args = parser.parse_args()
 
     abi_changed = diff_abi(args.abi_tool,
                            args.baseline,
                            args.new,
-                           args.report)
+                           args.report,
+                           args.kmi_whitelist)
     if abi_changed:
         return 8
 
diff --git a/abi/dump_abi b/abi/dump_abi
index 93ba3d5..dc4544d 100755
--- a/abi/dump_abi
+++ b/abi/dump_abi
@@ -21,9 +21,9 @@
 
 from abitool import get_abi_tool
 
-def dump_abi(abitool, linux_tree, out_file):
+def dump_abi(abitool, linux_tree, out_file, whitelist):
     tool = get_abi_tool(abitool)
-    tool.dump_kernel_abi(linux_tree, out_file)
+    tool.dump_kernel_abi(linux_tree, out_file, whitelist)
 
 def main():
     """ Build the linux kernel, freshly cloning if needed"""
@@ -36,12 +36,15 @@
                         help='abi tool to be used to monitor abi')
     parser.add_argument('--out-file', default=None,
                         help='where to write the abi dump to')
+    parser.add_argument('--kmi-whitelist', default=None,
+                        help='KMI whitelist to filter for')
 
     args = parser.parse_args()
 
     dump_abi(args.abi_tool,
              args.linux_tree,
-             args.out_file or os.path.join(args.linux_tree, "abi.xml"))
+             args.out_file or os.path.join(args.linux_tree, "abi.xml"),
+             args.kmi_whitelist)
 
 if __name__ == "__main__":
     sys.exit(main())
diff --git a/build_abi.sh b/build_abi.sh
index 28f8e14..6566fa9 100755
--- a/build_abi.sh
+++ b/build_abi.sh
@@ -30,6 +30,13 @@
 #     any significant differences, it will exit with the return code of
 #     diff_abi and optionally (-r) print a report.
 #     ABI_DEFINITION is supposed to be defined relative to $KERNEL_DIR/
+#
+#   KMI_WHITELIST
+#     Define a Kernel Module Interface white list description. If defined, it
+#     will be taken into account when extracting Kernel ABI information from
+#     vmlinux and kernel modules.
+#     KMI_WHITELIST is supposed to be defined relative to $KERNEL_DIR/
+#
 
 export ROOT_DIR=$(readlink -f $(dirname $0)/..)
 
@@ -114,6 +121,12 @@
 # the generated abi.xml to be copied to <DIST_DIR>/abi.out.
 ABI_DEFINITION= ${ROOT_DIR}/build/build.sh $*
 
+# define a common KMI whitelist flag for the abi tools
+KMI_WHITELIST_FLAG=
+if [ -n "$KMI_WHITELIST" ]; then
+    KMI_WHITELIST_FLAG="--kmi-whitelist $KERNEL_DIR/$KMI_WHITELIST"
+fi
+
 echo "========================================================"
 echo " Creating ABI dump"
 
@@ -123,7 +136,8 @@
 abi_out_file=abi-${id}.xml
 ${ROOT_DIR}/build/abi/dump_abi                \
     --linux-tree $OUT_DIR                     \
-    --out-file ${DIST_DIR}/${abi_out_file}
+    --out-file ${DIST_DIR}/${abi_out_file}    \
+    $KMI_WHITELIST_FLAG
 
 # sanitize the abi.xml by removing any occurences of the kernel path
 sed -i "s#${ROOT_DIR}/${KERNEL_DIR}/##g" ${DIST_DIR}/${abi_out_file}
@@ -145,7 +159,8 @@
         set +e
         ${ROOT_DIR}/build/abi/diff_abi --baseline $KERNEL_DIR/$ABI_DEFINITION \
                                        --new      ${DIST_DIR}/${abi_out_file} \
-                                       --report   ${abi_report}
+                                       --report   ${abi_report}               \
+                                       $KMI_WHITELIST_FLAG
         rc=$?
         set -e
         echo "========================================================"