236 lines
5.0 KiB
Plaintext
236 lines
5.0 KiB
Plaintext
|
#!/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
|