blob: 3ac5941f9c6229279e807ca744a4347d254df294 [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright (C) 2020 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import argparse
import base64
import json
import logging
import os
import subprocess
import sys
import urllib.request
from abitool import get_abi_tool
_BASE_URL_ABI_XML = ('https://android.googlesource.com/kernel/common/'
'+/refs/heads/android-{}/abi_gki_aarch64.xml?format={}')
logger = logging.getLogger('gki_check')
logging.basicConfig(level=logging.INFO, format='%(message)s')
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
'--kernel-version',
help='The Kernel version to compare against',
choices=['4.19', '5.4'],
default='5.4')
parser.add_argument(
'--linux-tree',
help='Path to kernel tree containing '
'vmlinux and modules',
required=True)
parser.add_argument(
'--abi-tool',
default='libabigail',
help='tool to monitor the ABI')
parser.add_argument(
'--kmi-symbol-list', '--kmi-whitelist',
default=None,
help='KMI symbol list to filter for')
args = parser.parse_args()
abi_tool = get_abi_tool(args.abi_tool)
# We assume the --linux-tree to be our working directory, hence download all
# the stuff there.
gki_check_dir = os.path.join(args.linux_tree, '.gki_check')
logger.info('Creating working directory %s ...', gki_check_dir)
os.makedirs(gki_check_dir, exist_ok=True)
upstream_xml = os.path.join(gki_check_dir, 'upstream.xml')
local_xml = os.path.join(gki_check_dir, 'local.xml')
abi_report = os.path.join(gki_check_dir, 'abi.report')
abi_report_short = os.path.join(gki_check_dir, 'abi.report.short')
# Download GKI abi.xml from either 5.4 (default) or 4.19
abi_xml_url = _BASE_URL_ABI_XML.format(args.kernel_version, 'TEXT')
base_is_current = False
if os.path.exists(upstream_xml):
current_hash = subprocess.check_output(['git', 'hash-object',
upstream_xml]).strip().decode()
response = urllib.request.urlopen(
_BASE_URL_ABI_XML.format(args.kernel_version, 'JSON'))
data = response.read().decode('utf-8')
new_hash = json.loads(data[data.index('{'):])['id']
if current_hash == new_hash:
base_is_current = True
logger.info('ABI representation is already up-to-date. '
'Skipping download ...')
if not base_is_current:
logger.info('Downloading ABI representation for android-%s ...',
args.kernel_version)
response = urllib.request.urlopen(abi_xml_url)
data = response.read()
with open(upstream_xml, 'wb') as reference_xml:
reference_xml.write(base64.b64decode(data))
logger.info('Extracting ABI information from your local build ...')
abi_tool.dump_kernel_abi(args.linux_tree, local_xml, args.kmi_symbol_list)
logger.info('Comparing ABI information to reference ...')
abi_tool.diff_abi(local_xml, upstream_xml, abi_report, abi_report_short,
args.kmi_symbol_list)
logger.info('ABI Analysis complete, please find the result below')
with open(abi_report_short) as short_report:
print(short_report.read())
logger.info('Upstream %s', upstream_xml)
logger.info('Local representation: %s', local_xml)
logger.info('Full report: %s', abi_report)
logger.info('Short report: %s', abi_report_short)
if __name__ == '__main__':
sys.exit(main())