-
Notifications
You must be signed in to change notification settings - Fork 0
/
build_abi.sh
executable file
·377 lines (334 loc) · 13.1 KB
/
build_abi.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
#!/bin/bash
# Copyright (C) 2019 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.
# Usage:
# build/build_abi.sh
#
# The following environment variables are considered during execution:
#
# ABI_OUT_TAG
# Customize the output file name for the abi dump. If undefined, the tag is
# derived from `git describe`.
#
# ABI_DEFINITION
# Specify an expected Kernel ABI representation. If defined, this script
# will, in addition to extracting the ABI representation from the currently
# built kernel, compare the extracted ABI to the expected one. In case of
# 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/
#
# TIDY_ABI
# If set to 1, any ABI dump created will be post-processed by the abitidy
# utility. This is done to minimise the XML and XML diffs. The utility
# removes unreachable parts of the ABI XML, sorts its elements into a
# canonical order and gives anonymous types consistent internal names.
#
# KMI_SYMBOL_LIST
# Define a Kernel Module Interface symbol list description. If defined, it
# will be taken into account when extracting Kernel ABI information from
# vmlinux and kernel modules.
# KMI_SYMBOL_LIST is supposed to be defined relative to $KERNEL_DIR/
#
# KMI_SYMBOL_LIST_MODULE_GROUPING
# If set to 1, then the symbol list will group symbols based on the kernel
# modules that reference the symbol. Otherwise the symbol list will simply
# be a sorted list of symbols used by all the kernel modules. This property
# is enabled by default.
#
# KMI_SYMBOL_LIST_ADD_ONLY
# If set to 1, then any symbols in the symbol list that would have been
# removed are preserved (at the end of the file). Symbol list update will
# fail if there is no pre-existing symbol list file to read from. This
# property is intended to prevent unintentional shrinkage of a stable ABI.
# It is disabled by default.
#
# GKI_MODULES_LIST
# If set to a file name, then this file will be read to determine the list
# of GKI modules (those subject to ABI monitoring) and, by elimination, the
# list of vendor modules (those which can rely on a stable ABI). Only vendor
# modules' undefined symbols are considered when updating the symbol list.
# GKI_MODULES_LIST is supposed to be defined relative to $KERNEL_DIR/
#
# FULL_GKI_ABI
# If this is set to 1 then, when updating the symbol list, use all defined
# symbols from vmlinux and GKI modules, instead of the undefined symbols
# from vendor modules. This property is disabled by default.
export ROOT_DIR=$(readlink -f $(dirname $0)/..)
function show_help {
echo "USAGE: $0 [-u|--update] [-n|--nodiff]"
echo
echo " -u | --update Update ABI representation and main symbol list in the source directory"
echo " -s | --update-symbol-list Update main symbol list in the source directory"
echo " -n | --nodiff Do not generate an ABI report with diff_abi"
echo " -r | --print-report Print ABI short report in case of any differences"
echo " -a | --full-report Create a detailed ABI report"
}
UPDATE=0
UPDATE_SYMBOL_LIST=0
DIFF=1
PRINT_REPORT=0
FULL_REPORT=0
if [[ -z "${KMI_SYMBOL_LIST_MODULE_GROUPING}" ]]; then
KMI_SYMBOL_LIST_MODULE_GROUPING=1
fi
if [[ -z "$KMI_SYMBOL_LIST_ADD_ONLY" ]]; then
KMI_SYMBOL_LIST_ADD_ONLY=0
fi
if [[ -z "$FULL_GKI_ABI" ]]; then
FULL_GKI_ABI=0
fi
if [[ -z "$TIDY_ABI" ]]; then
TIDY_ABI=0
fi
ARGS=()
for i in "$@"
do
case $i in
-u|--update)
UPDATE=1
shift # past argument=value
;;
-s|--update-symbol-list)
UPDATE_SYMBOL_LIST=1
shift # past argument=value
;;
-n|--nodiff)
DIFF=0
shift # past argument=value
;;
-r|--print-report)
PRINT_REPORT=1
shift # past argument=value
;;
-a|--full-report)
FULL_REPORT=1
shift # past argument=value
;;
-h|--help)
show_help
exit 0
;;
*)
ARGS+=("$1")
shift
;;
esac
done
set -- "${ARGS[@]}"
set -e
set -a
# if we are using the default OUT_DIR, add a suffix so we are free to wipe it
# before building to ensure a clean build/analysis. That is the default case.
if [[ -z "$OUT_DIR" ]]; then
export OUT_DIR_SUFFIX="_abi"
wipe_out_dir=1
fi
source "${ROOT_DIR}/build/_setup_env.sh"
if [ -z "${KMI_SYMBOL_LIST}" ]; then
if [ $UPDATE_SYMBOL_LIST -eq 1 ]; then
echo "ERROR: --update-symbol-list requires a KMI_SYMBOL_LIST" >&2
exit 1
fi
elif [ $UPDATE -eq 1 ]; then
UPDATE_SYMBOL_LIST=1
fi
# Now actually do the wipe out as above.
if [[ $wipe_out_dir -eq 1 && -d ${COMMON_OUT_DIR} ]]; then
find "${COMMON_OUT_DIR}" \( -name 'vmlinux' -o -name '*.ko' \) -delete -print
fi
# assert CONFIG_DEBUG_INFO=y
append_cmd POST_DEFCONFIG_CMDS 'check_config_for_abi_dump'
export POST_DEFCONFIG_CMDS
function check_config_for_abi_dump() {
local debug=$(${KERNEL_DIR}/scripts/config --file ${OUT_DIR}/.config -s DEBUG_INFO)
if [ "$debug" != y ]; then
echo "ERROR: DEBUG_INFO is not set in config" >&2
exit 1
fi
}
export -f check_config_for_abi_dump
# Disable mixed build when comparing ABI snapshots. Device kernel ABI should compared, even in a
# mixed build environment.
GKI_BUILD_CONFIG=
# Mixed build device kernels would not compile vmlinux. When using build_abi.sh to compile, we
# do want to compile vmlinux since we are comparing the ABI of the device kernel.
MAKE_GOALS+=" vmlinux"
function build_kernel() {
# Delegate the actual build to build.sh.
# Suppress possible values of ABI_DEFINITION when invoking build.sh to avoid
# the generated abi.xml to be copied to <DIST_DIR>/abi.out.
# Turn on symtypes generation to assist in the diagnosis of CRC differences.
ABI_DEFINITION= \
KBUILD_SYMTYPES=1 \
${ROOT_DIR}/build/build.sh "$@"
}
# define a common KMI symbol list flag for the abi tools
KMI_SYMBOL_LIST_FLAG=
# define a flag control ABI tidying
TIDY_ABI_FLAG=
if [ "$TIDY_ABI" -eq 1 ]; then
TIDY_ABI_FLAG=--tidy
fi
# We want to track whether the main symbol list (i.e. KMI_SYMBOL_LIST) actually
# got updated. If so we need to rerun the kernel build.
if [ -n "$KMI_SYMBOL_LIST" ]; then
if [ $UPDATE_SYMBOL_LIST -eq 1 ]; then
# Disable KMI trimming as the symbol list may be out of date.
TRIM_NONLISTED_KMI= KMI_SYMBOL_LIST_STRICT_MODE= build_kernel "$@"
echo "========================================================"
echo " Updating the ABI symbol list"
# Exclude GKI modules from non-GKI builds
if [ -n "${GKI_MODULES_LIST}" ]; then
GKI_MOD_FLAG="--gki-modules ${DIST_DIR}/$(basename ${GKI_MODULES_LIST})"
fi
if [ "$KMI_SYMBOL_LIST_ADD_ONLY" -eq 1 ]; then
ADD_ONLY_FLAG="--additions-only"
fi
# Specify a full GKI ABI if requested
if [ "$FULL_GKI_ABI" -eq 1 ]; then
FULL_ABI_FLAG="--full-gki-abi"
fi
if [ "${KMI_SYMBOL_LIST_MODULE_GROUPING}" -eq "0" ]; then
SKIP_MODULE_GROUPING="--skip-module-grouping"
fi
${ROOT_DIR}/build/abi/extract_symbols \
--symbol-list $KERNEL_DIR/$KMI_SYMBOL_LIST \
${SKIP_MODULE_GROUPING} \
${ADD_ONLY_FLAG} \
${GKI_MOD_FLAG} \
${FULL_ABI_FLAG} \
${DIST_DIR}
# Redo what build.sh has done, with possibly fresher symbol lists.
ABI_SL="${DIST_DIR}/abi_symbollist"
${ROOT_DIR}/build/copy_symbols.sh "$ABI_SL" "$ROOT_DIR/$KERNEL_DIR" \
"${KMI_SYMBOL_LIST}" ${ADDITIONAL_KMI_SYMBOL_LISTS}
# In case of a simple --update-symbol-list call we can bail out early
[ $UPDATE -eq 0 ] && exit 0
if [ -n "${TRIM_NONLISTED_KMI}" ]; then
# Rerun the kernel build with symbol list trimming enabled, as applicable. That
# influences the combined symbol list as well as the list of exported symbols in
# the kernel binary. Possibly more.
echo "========================================================"
echo " Rerunning the build with symbol trimming re-enabled"
SKIP_MRPROPER=1
fi
fi
KMI_SYMBOL_LIST_FLAG="--kmi-symbol-list ${DIST_DIR}/abi_symbollist"
fi
# Already built the final kernel if updating symbol list and trimming symbol list is disabled
if ! [ $UPDATE_SYMBOL_LIST -eq 1 -a -z "${TRIM_NONLISTED_KMI}" -a "$FULL_GKI_ABI" -eq 0 ]; then
SKIP_MRPROPER="${SKIP_MRPROPER}" build_kernel "$@"
fi
echo "========================================================"
echo " Creating ABI dump"
ABI_LINUX_TREE=${DIST_DIR}
ABI_VMLINUX_PATH=
DELETE_UNSTRIPPED_MODULES=
if [ -z "${DO_NOT_STRIP_MODULES}" ] && [ $(echo "${UNSTRIPPED_MODULES}" | tr -d '\n') = "*.ko" ]; then
if [ -n "${COMPRESS_UNSTRIPPED_MODULES}" ] && [ ! -f "${UNSTRIPPED_DIR}" ]; then
tar -xzf ${DIST_DIR}/${UNSTRIPPED_MODULES_ARCHIVE} -C $(dirname ${UNSTRIPPED_DIR})
DELETE_UNSTRIPPED_MODULES=1
fi
ABI_LINUX_TREE=${UNSTRIPPED_DIR}
ABI_VMLINUX_PATH="--vmlinux ${DIST_DIR}/vmlinux"
fi
# create ABI dump
COMMON_OUT_DIR=$(readlink -m ${OUT_DIR:-${ROOT_DIR}/out/${BRANCH}})
id=${ABI_OUT_TAG:-$(git -C $KERNEL_DIR describe --dirty --always)}
abi_out_file=abi-${id}.xml
full_abi_out_file=abi-full-${id}.xml
# if we have two to do, do them in parallel
${ROOT_DIR}/build/abi/dump_abi \
--linux-tree ${ABI_LINUX_TREE} \
${ABI_VMLINUX_PATH} \
--out-file ${DIST_DIR}/${abi_out_file} \
$KMI_SYMBOL_LIST_FLAG $TIDY_ABI_FLAG &
if [ -n "$KMI_SYMBOL_LIST_FLAG" ]; then
${ROOT_DIR}/build/abi/dump_abi \
--linux-tree ${ABI_LINUX_TREE} \
${ABI_VMLINUX_PATH} \
--out-file ${DIST_DIR}/${full_abi_out_file} \
$TIDY_ABI_FLAG &
wait -n
wait -n
else
wait -n
cp ${DIST_DIR}/${abi_out_file} ${DIST_DIR}/${full_abi_out_file}
fi
effective_kernel_dir=$(readlink -f ${ROOT_DIR}/${KERNEL_DIR})
if [ -n "${LLVM}" ]; then
CC=clang
fi
for f in "$abi_out_file" "$full_abi_out_file"; do
# sanitize the abi.xml by removing any occurrences of the kernel path
# and also do that with any left over paths sneaking in
# (e.g. from the prebuilts)
sed -i -e "s#${effective_kernel_dir}/##g" \
-e "s#${ROOT_DIR}/${KERNEL_DIR}/##g" \
-e "s#${ROOT_DIR}/##g" "$DIST_DIR/$f"
# Append debug information to abi file
echo "
<!--
libabigail: $(abidw --version)
built with: $CC: $($CC --version | head -n1)
-->" >> ${DIST_DIR}/$f
done
ln -sf ${abi_out_file} ${DIST_DIR}/abi.xml
ln -sf ${full_abi_out_file} ${DIST_DIR}/abi-full.xml
echo "========================================================"
echo " ABI dump has been created at ${DIST_DIR}/${abi_out_file}"
echo " Full ABI dump has been created at ${DIST_DIR}/${full_abi_out_file}"
rc=0
if [ -n "$ABI_DEFINITION" ]; then
if [ $DIFF -eq 1 ]; then
echo "========================================================"
echo " Comparing ABI against expected definition ($ABI_DEFINITION)"
abi_report=${DIST_DIR}/abi.report
FULL_REPORT_FLAG=
if [ $FULL_REPORT -eq 1 ]; then
FULL_REPORT_FLAG="--full-report"
fi
set +e
${ROOT_DIR}/build/abi/diff_abi --baseline $KERNEL_DIR/$ABI_DEFINITION \
--new ${DIST_DIR}/${abi_out_file} \
--report ${abi_report} \
--short-report ${abi_report}.short \
$FULL_REPORT_FLAG
rc=$?
set -e
echo "========================================================"
echo " A brief ABI report has been created at ${abi_report}.short"
echo
echo " The detailed report is available in the same directory."
if [ $rc -ne 0 ]; then
echo " ABI DIFFERENCES HAVE BEEN DETECTED! (RC=$rc)" 1>&2
fi
if [ $PRINT_REPORT -eq 1 ] && [ $rc -ne 0 ] ; then
echo "========================================================" 1>&2
cat ${abi_report}.short 1>&2
fi
fi
if [ $UPDATE -eq 1 ] ; then
echo "========================================================"
echo " Updating expected ABI definition ($ABI_DEFINITION)"
cp -v ${DIST_DIR}/${abi_out_file} $KERNEL_DIR/$ABI_DEFINITION
fi
fi
[ -n "${DELETE_UNSTRIPPED_MODULES}" ] && rm -rf ${UNSTRIPPED_DIR}
if [ -n "${KMI_ENFORCED}" ]; then
exit $rc
else
exit 0
fi