1#!/bin/bash 2 3# Copyright (C) 2019 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17# Usage: 18# build/build_abi.sh 19# 20# The following environment variables are considered during execution: 21# 22# ABI_OUT_TAG 23# Customize the output file name for the abi dump. If undefined, the tag is 24# derived from `git describe`. 25# 26# ABI_DEFINITION 27# Specify an expected Kernel ABI representation. If defined, this script 28# will, in addition to extracting the ABI representation from the currently 29# built kernel, compare the extracted ABI to the expected one. In case of 30# any significant differences, it will exit with the return code of 31# diff_abi and optionally (-r) print a report. 32# ABI_DEFINITION is supposed to be defined relative to $KERNEL_DIR/ 33# 34# KMI_WHITELIST 35# Define a Kernel Module Interface white list description. If defined, it 36# will be taken into account when extracting Kernel ABI information from 37# vmlinux and kernel modules. 38# KMI_WHITELIST is supposed to be defined relative to $KERNEL_DIR/ 39# 40 41export ROOT_DIR=$(readlink -f $(dirname $0)/..) 42 43function show_help { 44 echo "USAGE: $0 [-u|--update] [-n|--nodiff]" 45 echo 46 echo " -u | --update Update the abi.xml in the source directory" 47 echo " -n | --nodiff Do not generate a ABI report with abidiff" 48 echo " -r | --print-report Print ABI report in case of differences" 49} 50 51UPDATE=0 52DIFF=1 53PRINT_REPORT=0 54 55ARGS=() 56for i in "$@" 57do 58case $i in 59 -u|--update) 60 UPDATE=1 61 shift # past argument=value 62 ;; 63 -n|--nodiff) 64 DIFF=0 65 shift # past argument=value 66 ;; 67 -r|--print-report) 68 PRINT_REPORT=1 69 shift # past argument=value 70 ;; 71 -h|--help) 72 show_help 73 exit 0 74 ;; 75 *) 76 ARGS+=("$1") 77 shift 78 ;; 79esac 80done 81 82set -- "${ARGS[@]}" 83 84set -e 85set -a 86 87# if we are using the default OUT_DIR, add a suffix so we are free to wipe it 88# before building to ensure a clean build/analysis. That is the default case. 89if [[ -z "$OUT_DIR" ]]; then 90 export OUT_DIR_SUFFIX="_abi" 91 wipe_out_dir=1 92fi 93 94source "${ROOT_DIR}/build/_setup_env.sh" 95 96# Now actually do the wipe out as above. 97if [[ $wipe_out_dir -eq 1 ]]; then 98 rm -rf "${COMMON_OUT_DIR}" 99fi 100 101# inject CONFIG_DEBUG_INFO=y 102export POST_DEFCONFIG_CMDS="${POST_DEFCONFIG_CMDS} : && update_config_for_abi_dump" 103function update_config_for_abi_dump() { 104 ${KERNEL_DIR}/scripts/config --file ${OUT_DIR}/.config \ 105 -e CONFIG_DEBUG_INFO 106 (cd ${OUT_DIR} && \ 107 make O=${OUT_DIR} "${TOOL_ARGS[@]}" $archsubarch CROSS_COMPILE=${CROSS_COMPILE} olddefconfig) 108} 109export -f check_defconfig 110export -f update_config_for_abi_dump 111 112function version_greater_than() { 113 test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; 114} 115 116# ensure that abigail is present in path 117if ! ( hash abidiff 2>/dev/null); then 118 echo "ERROR: libabigail is not found in \$PATH at all!" 119 echo "Have you run build/abi/bootstrap and followed the instructions?" 120 exit 1 121fi 122 123# ensure we have a "new enough" version of abigail present before continuing 124if ! ( version_greater_than "$(abidiff --version | awk '{print $2}')" \ 125 "1.6.0" ); then 126 echo "ERROR: no suitable libabigail (>= 1.6.0) in \$PATH." 127 echo "Have you run build/abi/bootstrap and followed the instructions?" 128 exit 1 129fi 130 131# For now we require a specific versions of libabigail identified by a commit 132# hash. That is a bit inconvenient, but we do not have another reliable 133# identifier at this time. 134required_abigail_version="1.7.0-$(cat ${ROOT_DIR}/build/abi/bootstrap| grep 'ABIGAIL_VERSION=' | cut -d= -f2)" 135if [[ ! $(abidiff --version) =~ $required_abigail_version ]]; then 136 echo "ERROR: required libabigail version is $required_abigail_version" 137 echo "Have you run build/abi/bootstrap and followed the instructions?" 138 exit 1 139fi 140 141# delegate the actual build to build.sh. 142# suppress possible values of ABI_DEFINITION when invoking build.sh to avoid 143# the generated abi.xml to be copied to <DIST_DIR>/abi.out. 144ABI_DEFINITION= ${ROOT_DIR}/build/build.sh $* 145 146# define a common KMI whitelist flag for the abi tools 147KMI_WHITELIST_FLAG= 148if [ -n "$KMI_WHITELIST" ]; then 149 150 if [ $UPDATE -eq 1 ]; then 151 echo "========================================================" 152 echo " Updating the ABI whitelist" 153 ${ROOT_DIR}/build/abi/extract_symbols \ 154 --whitelist $KERNEL_DIR/$KMI_WHITELIST \ 155 ${DIST_DIR} 156 fi 157 158 KMI_WHITELIST_FLAG="--kmi-whitelist ${DIST_DIR}/abi_whitelist" 159fi 160 161echo "========================================================" 162echo " Creating ABI dump" 163 164# create abi dump 165COMMON_OUT_DIR=$(readlink -m ${OUT_DIR:-${ROOT_DIR}/out/${BRANCH}}) 166id=${ABI_OUT_TAG:-$(git -C $KERNEL_DIR describe --dirty --always)} 167abi_out_file=abi-${id}.xml 168${ROOT_DIR}/build/abi/dump_abi \ 169 --linux-tree ${DIST_DIR} \ 170 --out-file ${DIST_DIR}/${abi_out_file} \ 171 $KMI_WHITELIST_FLAG 172 173# sanitize the abi.xml by removing any occurences of the kernel path 174sed -i "s#${ROOT_DIR}/${KERNEL_DIR}/##g" ${DIST_DIR}/${abi_out_file} 175# now also do that with any left over paths sneaking in 176# (e.g. from the prebuilts) 177sed -i "s#${ROOT_DIR}/##g" ${DIST_DIR}/${abi_out_file} 178 179# Append debug information to abi file 180echo " 181<!-- 182 libabigail: $(abidw --version) 183 built with: $CC: $($CC --version | head -n1) 184-->" >> ${DIST_DIR}/${abi_out_file} 185 186ln -sf ${abi_out_file} ${DIST_DIR}/abi.xml 187 188echo "========================================================" 189echo " ABI dump has been created at ${DIST_DIR}/${abi_out_file}" 190 191rc=0 192if [ -n "$ABI_DEFINITION" ]; then 193 if [ $DIFF -eq 1 ]; then 194 echo "========================================================" 195 echo " Comparing ABI against expected definition ($ABI_DEFINITION)" 196 abi_report=${DIST_DIR}/abi.report 197 set +e 198 ${ROOT_DIR}/build/abi/diff_abi --baseline $KERNEL_DIR/$ABI_DEFINITION \ 199 --new ${DIST_DIR}/${abi_out_file} \ 200 --report ${abi_report} \ 201 --short-report ${abi_report}.short \ 202 $KMI_WHITELIST_FLAG 203 rc=$? 204 set -e 205 echo "========================================================" 206 echo " ABI report has been created at ${abi_report}" 207 208 if [ $rc -ne 0 ]; then 209 echo " ABI DIFFERENCES HAVE BEEN DETECTED! (RC=$rc)" 210 fi 211 212 if [ $PRINT_REPORT -eq 1 ] && [ $rc -ne 0 ] ; then 213 echo "========================================================" 214 cat ${abi_report}.short 215 fi 216 fi 217 if [ $UPDATE -eq 1 ] ; then 218 echo "========================================================" 219 echo " Updating expected ABI definition ($ABI_DEFINITION)" 220 cp -v ${DIST_DIR}/${abi_out_file} $KERNEL_DIR/$ABI_DEFINITION 221 fi 222fi 223 224exit $rc 225 226