#!/bin/bash

# The purpose of this test script is to determine if create-diff-object can
# properly recognize object file equivalence when passed the same file for both
# the original and patched objects.  This verifies that create-diff-object is
# correctly parsing, correlating, and comparing the different elements of the
# object file.  In practice, a situation similar to the test case occurs when a
# commonly included header file changes, causing Make to rebuild many objects
# that have no functional change.

# This script requires a built kernel object tree to be in the kpatch cache
# directory at $HOME/.kpatch/obj

#set -x

OBJDIR="$HOME/.kpatch/obj"
SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))"
TEMPDIR=$(mktemp -d)
RESULTSDIR="$TEMPDIR/results"
VMVLINUX="/usr/lib/debug/lib/modules/$(uname -r)/vmlinux" # path for F20

if [[ ! -d $OBJDIR ]]; then
	echo "please run kpatch-build to populate the object tree in $OBJDIR"
fi

cd "$OBJDIR" || exit 1
for i in $(find * -name '*.o')
do
	# copied from kpatch-build/kpatch-gcc; keep in sync
	case $i in
		*.mod.o|\
		*built-in.o|\
		vmlinux.o|\
		.tmp_kallsyms1.o|\
		.tmp_kallsyms2.o|\
		init/version.o|\
		arch/x86/boot/version.o|\
		arch/x86/boot/compressed/eboot.o|\
		arch/x86/boot/header.o|\
		arch/x86/boot/compressed/efi_stub_64.o|\
		arch/x86/boot/compressed/piggy.o|\
		kernel/system_certificates.o|\
		.*.o)
		continue
		;;
	esac
	# skip objects that are the linked product of more than one object file
	[[ $(eu-readelf -s $i | grep FILE | wc -l) -ne 1 ]] && continue
	$SCRIPTDIR/../kpatch-build/create-diff-object $i $i /usr/lib/debug/lib/modules/$(uname -r)/vmlinux "$TEMPDIR/output.o" > "$TEMPDIR/log.txt" 2>&1
	RETCODE=$?
	# expect RETCODE to be 3 indicating no change
	[[ $RETCODE -eq 3 ]] && continue
	# otherwise record error
	mkdir -p $RESULTSDIR/$(dirname $i) || exit 1
	cp "$i" "$RESULTSDIR/$i" || exit 1
	case $RETCODE in
		139)
			echo "$i: segfault" | tee 
			if [[ ! -e core ]]; then
				echo "no corefile, run "ulimit -c unlimited" to capture corefile"
			else
				mv core "$RESULTSDIR/$i.core" || exit 1
			fi
			;;
		0)
			echo "$i: incorrectly detected change"
			mv "$TEMPDIR/log.txt" "$RESULTSDIR/$i.log" || exit 1
			;;
		1|2)
			echo "$i: error code $RETCODE"
			mv "$TEMPDIR/log.txt" "$RESULTSDIR/$i.log" || exit 1
			;;
		*)
			exit 1 # script error
			;;
	esac
done
rm -f "$TEMPDIR/log.txt" > /dev/null 2>&1

# try to group the errors together in some meaningful way
cd "$RESULTSDIR" || exit 1
echo ""
echo "Results:"
for i in $(find * -iname '*.log')
do
	echo $(cat $i | head -1 | cut -f2-3 -d':')
done | sort | uniq -c | sort -n -r | tee "$TEMPDIR/results.log"

echo "results are in $TEMPDIR"
