#!/bin/sh

# plt-checker - check for evidence of the ".plt - 1" bug
#
# Usage:
#	plt-checker
#		Check every installed debian package
#	plt-checker package-names/*.deb
#		Check *.deb files and/or installed packages.  Can be
#		intermixed on command line
#
# This thing is sorta interactive, and slow.  Final results are stored in
# plt-debchecker.out (so run it from a directory where you can write a file)

BASE=$(basename $0)
TMPDIR=${TMPDIR:-/tmp/${BASE}.$$}

if [ ! -z "$BASH_VERSION" ]
then
    function echo()
    {
	builtin echo -e "$@"
    }
    export -f echo
fi

if [ $(objdump -d /bin/ls 2>&- | wc -l) == 0 -o \
	$(nm -on --dynamic /lib/libc.so.6 2>&- | wc -l) == 0 ]
then
    echo "Either objdump or nm is busted -- can't run $0" >&2
    exit 3
fi

echo "$(date) $0 $*" '$Revision: 1.12 $' >>${BASE}.out

badstubcheck()
{
    reason="Bad-Stub"
    objdump -d $1 2>&- |
	grep -l 'ldw  *-*[0-9a-f].*[13579bdf](.*r1),r21' >/dev/null
}

badlibcheck()
{
    reason="Millicode-in-shlib"
    nm --dynamic -n $1 2>&- | grep -Fl '$$' >/dev/null
}

badplt()
{
    reason="unitialized-.plt"
    objdump -j .plt -s $1 2>/dev/null | grep -Fl 00000000 >/dev/null
}

badfile()
{
    case "$1" in
	"") return 5;;
	*bin*) true;;
	*lib*) true;;
	*) return 6;;
    esac
    case $(file $1) in
	*ELF*shared*PA-RISC*)
	    badstubcheck $1 && return 0
	    badlibcheck $1 && return 0
	    badplt $1 && return 0
	    ;;
	*ELF*PA-RISC*dynamic*)
	    badstubcheck $1 && return 0
	    badplt $1 && return 0
	    ;;
	*) return 3 ;;
    esac
    return 4
}

checkfiles()	# list on stdin please
{
    pkg=$1
    skip=false
    while read file
    do
	$skip && continue
	echo -e ".\c" >&2

	if badfile $file
	then
	    echo "bad=$reason" >&2
	    echo "$reason\t$pkg\t$file" >> ${BASE}.out
	    skip=true
	fi
    done
}

checkdotdeb()
{
    mkdir -p $TMPDIR
    pkg=$1
    echo -e "\nchecking $pkg \c" >&2
    dpkg-deb -x $n $TMPDIR
    find $TMPDIR -type f -print | checkfiles $pkg
    rm -fr ${TMPDIR}
}

checkdeb()
{
    pkg=$1
    echo -e "\nchecking installed $pkg \c" >&2
    dpkg --listfiles $pkg | checkfiles $pkg
}

if [ $# != 0 ]
then
    for n in $*
    do
	case $n in
	    *.deb) checkdotdeb $n;;
	    *) checkdeb $n
	esac
    done
else
    dpkg --get-selections |
	while read pkg status
	do
	    checkdeb $pkg $status
	done
fi

echo "\nSee ${BASE}.out for bad package list" >&2
