#!/bin/sh # shellcheck disable=SC2086,SC2119,SC2120 # shellcheck source=../lib/load-configuration . "${0%/*}/../lib/load-configuration" usage( ) { >&2 cat < ] possible optons: -h|--help: Show this help page -a|--architecture: architecture family to check against, one of i486, i686, pentium3 (meaning target architecture the package should be runnable on) -v|--verbose: Verbose output, print result of check for logs -d|--debug: Debug output, used for development and testing EOF exit 1 } VERBOSE=0 DEBUG=0 EXIT_CODE=0 verbose( ) { if test $VERBOSE = 1; then echo "$@" fi } debug( ) { if test $DEBUG = 1; then echo "$@" fi } err( ) { echo "ERROR: $*" EXIT_CODE=1 } tmp_dir=$(mktemp -d "${work_dir}/tmp.check-opcodes.XXXXXX") trap 'rm -rf --one-file-system "${tmp_dir:?}"' EXIT ARCH=i686 while getopts ":vda:h-:" opt; do case $opt in -) case "$OPTARG" in help) usage ;; verbose) VERBOSE=1 ;; debug) DEBUG=1 ;; *) echo "ERROR: Invalid option: --$OPTARG" >&2 usage ;; esac ;; h) usage ;; v) VERBOSE=1 ;; d) DEBUG=1 ;; a) ARCH=$OPTARG ;; \?) echo "ERROR: Invalid option: -$OPTARG" >&2 usage ;; esac done shift $((OPTIND-1)) PACKAGE=$1 if test "x$PACKAGE" = "x"; then echo "ERROR: Filename of a package required as argument" >&2 usage exit 1 fi OPCODE_ARGS="" case $ARCH in i486) OPCODE_ARGS='-r -a 386 -v' ;; i686) OPCODE_ARGS='-s MMX -s SSE' ;; # TODO: pentium4 pentium3) OPCODE_ARGS='-s SSE2 -s SSE3' ;; *) echo "ERROR: architecture must currently be one of i486, i686 and pentium3" >&2 usage exit 1 esac debug "Unpacking $PACKAGE to $tmp_dir.." bsdtar --no-fflags -x -C $tmp_dir -f $PACKAGE debug "Checking for architecture: $ARCH ($OPCODE_ARGS).." # shellcheck disable=SC2044 for absfile in $(find $tmp_dir \( -regextype grep -regex '.*\.so\(\.[0-9.]\+\)\?' -type f \) -o \( -executable -type f \) ); do file=$(basename $absfile) relfile=${absfile#$tmp_dir} debug "Checking file: $relfile" if ! readelf -a $absfile > $tmp_dir/$file.elf 2>/dev/null; then debug "readelf failed, ignoring file" continue fi if ! objdump -f $absfile > $tmp_dir/$file.objdump 2>/dev/null; then debug "objdump failed, ignoring file" continue fi file $absfile > $tmp_dir/$file.file arch=$(grep ^architecture $tmp_dir/$file.objdump | sed 's/^architecture: //g' | cut -f 1 -d ,) case $arch in i386:x86-64) arch='x86_64' ;; i386) arch='x86' ;; *) arch='unknown' ;; esac debug " Objdump architecture: $arch" archelf=$(grep '^ \+Class' $tmp_dir/$file.elf | cut -f 2 -d : | tr -d ' ') case $archelf in ELF64) archelf='x86_64' ;; ELF32) archelf='x86' ;; *) archelf='unknown' ;; esac debug " Readelf architecture: $archelf" if test $arch != $archelf; then err "ERROR: $file ambigous architecture information (objdump: $arch, ELF: $archelf)" fi if test $arch = "x86_64"; then err "ERROR: $file is a 64-bit library!" continue fi objdump -M intel -d $absfile > $tmp_dir/$file.asm bad_opcodes=$(${base_dir}/bin/opcode $OPCODE_ARGS -m 1 < $tmp_dir/$file.asm | wc -l) if test $bad_opcodes != 0; then case $ARCH in i486) err "$relfile is not built for plain i486 opcodes" ;; i686) err "$relfile contains MMX, SSE or newer opcodes" ;; pentium3) err "$relfile contains SSE2 or newer opcodes" ;; esac if test $DEBUG = 1; then ${base_dir}/bin/opcode $OPCODE_ARGS -B 2 -A 2 < $tmp_dir/$file.asm fi else if test $VERBOSE = 1; then verbose "OK: $relfile fullfills architecture constraint for $ARCH" fi fi done exit $EXIT_CODE