kernel-source/kabi-checks

236 lines
5.0 KiB
Bash

#!/bin/bash
# Tool to do kABI checks.
# (c) Kurt Garloff <garloff@suse.de>, GNU GPL, 11/2005
# $Id$
#
# This tool looks at the generated symvers and compares it to the
# reference file (if existent). It prints warnings for changed symbol
# versions.
#
# Return value:
# 0 -- no changes
# 1 -- usage/input error
# 2 -- internal error
# 4 -- only additions
# >= 8 -- removed or changed symbols (see below)
#
# Severity classification:
# - 8 -- 15: if it's not found in a list (commonsyms or usedsyms)
# The score depends on the source; symbols in vmlinux are more
# likely to be used by anyone.
# - 16 -- 23: symbol is found in the list usedsyms
# - 24 -- 31: symbol is found in the list commonsyms
severities="
# unimportant ---. .--- important
# v v
drivers/base/* 13
drivers/char/ipmi/* 10
drivers/char/tpm/tpm 9
drivers/hwmon/* 10
drivers/i2c/i2c-core 9
drivers/md/* 13
drivers/message/fusion/* 6
drivers/pci/* 12
drivers/pci/hotplug/pci_hotplug 10
drivers/scsi/libata 12
drivers/scsi/scsi* 12
drivers/scsi/*/scsi_transport_* 12
drivers/scsi/libiscsi* 12
drivers/ide/ide-core 11
drivers/usb/core/usbcore 10
drivers/usb/serial/usbserial 9
fs/dmapi/dmapi 11
fs/fat/fat 11
fs/jbd/jbd 11
net/ipv4/netfilter/ip_tables 9
vmlinux 15
"
# Turning off UTF-8 processing provides a major speedup.
export LC_ALL=C
echo "${0##*/} $@"
unset quiet verbose
if [ "$1" = "-q" ]; then
shift
quiet=1
fi
if [ "$1" = "-v" ]; then
shift
verbose=1
fi
if [ $# -lt 2 -o $# -gt 4 ]; then
echo "Usage: ${0##*/} [-q] [-v] reference symvers [commonsyms [usedsyms]]" >&2
exit 1
fi
for file in "$@"; do
[ -r "$file" ] && continue
echo "Cannot read from '$file'" >&2
exit 1
done
declare_symbol_severity() {
declare severity=$1
while [ $# -ge 2 ]; do
if ! eval "severity_of_${2//[^a-zA-Z0-9_]/_}=$severity"; then
echo "Internal error" >&2
exit 2
fi
shift
done
}
consistency_check() {
declare_symbol_severity 16 consistency_check_foo
check_modified_symbols >/dev/null <<-EOF
consistency_check_foo -0x12345678 consistency/check/foo +0x98765432 consistency/check/foo
EOF
if [ $? -ne 31 ]; then
echo "Internal error" >&2
exit 2
fi
}
#set -x
eval '
severity() {
case $2 in
'"$(
( echo "$severities"
echo "consistency/check/* 15" # For the consistency test
) \
| sed -e '/^#/d' -e '/^$/d' \
| while read glob severity; do
echo " ($glob) _rc=$severity ;;"
done
)"'
(*) _rc=8 ;;
esac
# Is a particular severity defined for this symbol?
declare severity=severity_of_$1
if [ -n "${!severity}" ]; then
((_rc += ${!severity}))
fi
return $_rc
}'
#set +x
grab_symvers_from_rpm() {(
# (Run in subshell to make trap work.)
tmpdir=$(mktemp -t -d ${0##*/}.XXXXXX)
trap "cd /; rm -rf $tmpdir" EXIT
cd $tmpdir
rpm2cpio "$file" \
| cpio -dim --quiet './boot/symvers-*.gz'
set -- boot/symvers-*.gz
if ! [ -e "$1" ]; then
echo "Failed to extract symvers-*.gz from $file" >&2
exit 1
fi
zcat "$1"
)}
grab_symvers() {
declare tag=$1 file=$2 pwd tmpdir
case "$(file -b - <"$file")" in
gzip*)
zcat "$file"
;;
RPM*)
grab_symvers_from_rpm "$file"
;;
*)
cat "$file"
;;
esac \
| sed -e "/^#/d" -e "s/^/$tag/" \
| sort -k 2
}
filter_out_identical_symbols() {
# This expression works no matter how many columns the files have.
grep -v -P '^\S+ -(\S+)( \S+)+ \+\1( \S+)+$'
}
check_modified_symbols() {
declare -i RC=0 _rc
declare ignored
while read symbol tail; do
# Split in half no matter how many columns the files have.
set -- $tail ; half=$(($#/2+1))
version1=$1 ; version2=${!half} ; shift
source1=$1 ; source2=${!half} ; shift
case "$version1$version2" in
-\#*)
continue
;;
-*+* | -*)
ignored=
case "$version1" in
*=\>*)
if [ "${version1#*=>}" = "${version2#+}" ]; then
version1="${version1%=>*}"
ignored="; ignored"
fi
;;
esac
severity $symbol $source1 && continue
_rc=$?
if [ -z "$quiet" ]; then
echo -n "Warning: $source1: $symbol(${version1#-}) "
if [ -n "$version2" ]; then
echo -n "changed to $symbol(${version2#+})"
[ "$source1" != "$source2" ] &&
echo -n " and moved to $source2"
else
echo -n "removed"
fi
echo " (badness ${_rc}$ignored)"
fi
[ -n "$ignored" ] && _rc=0
;;
*)
if [ -n "$verbose" ]; then
echo " new symbol $symbol: ${version1#+}"
fi
_rc=4
;;
esac
if [ ${_rc} -gt $RC ]; then RC=${_rc}; fi
done
return $RC
}
sort_by_badness() {
sed -e 's/.*(badness \([0-9]\+\)).*/\1 &/' -e 't' -e 's/^/0 /' \
| sort -n -r \
| sed -e 's/^[0-9]* //'
}
consistency_check
[ -n "$4" ] && declare_symbol_severity 8 $(< $4)
[ -n "$3" ] && declare_symbol_severity 16 $(< $3)
join -j 2 -a 1 -a 2 <(grab_symvers - $1) <(grab_symvers + $2) \
| filter_out_identical_symbols \
| check_modified_symbols \
| sort_by_badness
RC=${PIPESTATUS[2]}
echo "kABI verdict: $RC"
exit $RC