From 14d0abcfea146fbb5e4254d7b592d4666c8b8c44 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Sat, 24 Mar 2018 19:53:56 +0100 Subject: reverted opcode to original (no shellcheck) added a -d option to check-opcodes renamed pentium4 to pentium3 (because without SSE2 this is the architecture we are aiming at) be more tolerant on failing readelf and objdump handle binaries too --- bin/check-opcodes | 86 ++++++++++++++++++++++++++++++++++++++----------------- bin/opcode | 46 ++++++++++++++--------------- 2 files changed, 81 insertions(+), 51 deletions(-) diff --git a/bin/check-opcodes b/bin/check-opcodes index bd96cc6..b8ad89c 100755 --- a/bin/check-opcodes +++ b/bin/check-opcodes @@ -2,32 +2,42 @@ # shellcheck disable=SC2086 -# shellcheck source=conf/default.conf +# shellcheck source=../conf/default.conf . "${0%/*}/../conf/default.conf" usage( ) { >&2 cat < ] +check_opcodes: [options] [ -a ] possible optons: -h|--help: Show this help page - -v|--verbose: Verbose output -a|--architecture: architecture family to check against, one of - i486, i686, pentium4 + 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 -log( ) { + +verbose( ) { if test $VERBOSE = 1; then echo "$@" fi } +debug( ) { + if test $DEBUG = 1; then + echo "$@" + fi +} + err( ) { echo "ERROR: $*" EXIT_CODE=1 @@ -38,7 +48,7 @@ trap 'rm -rf --one-file-system "${tmp_dir:?}"' EXIT ARCH=i686 -while getopts ":va:h-:" opt; do +while getopts ":vda:h-:" opt; do case $opt in -) case "$OPTARG" in @@ -48,6 +58,9 @@ while getopts ":va:h-:" opt; do verbose) VERBOSE=1 ;; + debug) + DEBUG=1 + ;; *) echo "ERROR: Invalid option: --$OPTARG" >&2 usage @@ -60,6 +73,9 @@ while getopts ":va:h-:" opt; do v) VERBOSE=1 ;; + d) + DEBUG=1 + ;; a) ARCH=$OPTARG ;; @@ -83,29 +99,42 @@ fi OPCODE_ARGS="" case $ARCH in i486) - OPCODE_ARGS='-r -a 486 -v' + OPCODE_ARGS='-r -a 386 -v' ;; - i686) - OPCODE_ARGS='-s MMX -s SSE -s SSE2' + i686) + OPCODE_ARGS='-s MMX -s SSE' ;; - pentium4) - OPCODE_ARGS='-s SSE3 -s SSSE3 -s AVX' + pentium3) + OPCODE_ARGS='-s SSE2 -s SSE3' ;; - *) + *) echo "ERROR: architecture must currently be one of i486 and i686" >&2 usage exit 1 esac -log "Checking for architecture: $ARCH ($OPCODE_ARGS)" +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); do - file=$(basename $absfile) - log "Checking shared library: $file" - readelf -a $absfile > $tmp_dir/$file.elf - objdump -f $absfile > $tmp_dir/$file.objdump +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" + set +e + readelf -a $absfile > $tmp_dir/$file.elf 2>/dev/null + if test $? != 0; then + debug "readelf failed, ignoring file" + continue + fi + objdump -f $absfile > $tmp_dir/$file.objdump 2>/dev/null + if test $? != 0; then + debug "objdump failed, ignoring file" + continue + fi + set -e file $absfile > $tmp_dir/$file.file arch=$(grep ^architecture $tmp_dir/$file.objdump | sed 's/^architecture: //g' | cut -f 1 -d ,) @@ -120,7 +149,7 @@ for absfile in $(find $tmp_dir -regextype grep -regex '.*\.so\(\.[0-9.]\+\)\?' - arch='unknown' ;; esac - log " Objdump architecture: $arch" + debug " Objdump architecture: $arch" archelf=$(grep '^ \+Class' $tmp_dir/$file.elf | cut -f 2 -d : | tr -d ' ') case $archelf in @@ -134,14 +163,14 @@ for absfile in $(find $tmp_dir -regextype grep -regex '.*\.so\(\.[0-9.]\+\)\?' - archelf='unknown' ;; esac - log " Readelf architecture: $archelf" + debug " Readelf architecture: $archelf" if test $arch != $archelf; then - err "$file ambigous architecture information (objdump: $arch, ELF: $archelf)" + err "ERROR: $file ambigous architecture information (objdump: $arch, ELF: $archelf)" fi if test $arch = "x86_64"; then - err "$file is a 64-bit library!" + err "ERROR: $file is a 64-bit library!" continue fi @@ -150,18 +179,21 @@ for absfile in $(find $tmp_dir -regextype grep -regex '.*\.so\(\.[0-9.]\+\)\?' - if test $bad_opcodes != 0; then case $ARCH in i486) - err "$file is not built for plain i486 opcodes" + err "$relfile is not built for plain i486 opcodes" ;; i686) - err "$file contains MMX, SSE or SSE2 opcodes" + err "$relfile contains MMX, SSE or newer opcodes" ;; - pentium4) - err "$file contains SSE3 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 - log "$file fullfills architecture constraint for $ARCH" + verbose "OK: $relfile fullfills architecture constraint for $ARCH" fi fi diff --git a/bin/opcode b/bin/opcode index 8840e97..544c763 100755 --- a/bin/opcode +++ b/bin/opcode @@ -25,8 +25,8 @@ # * Remove all line in Opcode_ARM_THUMB # return values -# shellcheck disable=SC2001,SC2034,SC2086 +# return values EXIT_FOUND=0 EXIT_NOT_FOUND=1 EXIT_USAGE=2 @@ -45,7 +45,6 @@ Line_Numbers=false Leading_Context=0 Trailing_Context=0 -# shellcheck source=lib/opcode_list source "${0%/*}/../lib/opcode_list" # include opcodes from a separate file # GAS-specific opcodes (unofficial names) belonging to the x64 instruction set. @@ -166,7 +165,7 @@ usage() { echo "The script uses Intel opcode syntax. When used in conjunction with objdump, \`-M intel' must be set in order to prevent opcode translation using AT&T syntax." echo echo "BE AWARE THAT THE LIST OF KNOWN INSTRUCTIONS OR INSTRUCTIONS SUPPORTED BY PARTICULAR ARCHITECTURES (ESPECIALLY AMD'S) IS ONLY TENTATIVE AND MAY CONTAIN MISTAKES!" - kill -TRAP "$TOP_PID" + kill -TRAP $TOP_PID } list_contains() { # Returns 0 if $2 is in array $1, 1 otherwise. @@ -179,25 +178,25 @@ list_contains() { # Returns 0 if $2 is in array $1, 1 otherwise. build_instruction_set() { # $1 = enum { Arch, InstSet }, $2 = architecture or instruction set as obtained using -L or -l, $3 = "architecture"/"instruction set" to be used in error message local e - list_contains "$(eval echo \\\$${1}List)" "$2" || (echo "$2 is not a valid $3."; usage) # Test if the architecture/instruction set is valid. - if [ -n "$(eval echo \\\$${1}_${2})" ]; then # Add the instruction set(s) if any. - for e in $(eval echo \\\$${1}_${2}); do # Skip duplicates. + list_contains "`eval echo \\\$${1}List`" "$2" || (echo "$2 is not a valid $3."; usage) # Test if the architecture/instruction set is valid. + if [ -n "`eval echo \\\$${1}_${2}`" ]; then # Add the instruction set(s) if any. + for e in `eval echo \\\$${1}_${2}`; do # Skip duplicates. list_contains "$InstSet_Base" $e || InstSet_Base="$e $InstSet_Base" done fi if [ $Recursive = true ]; then - for a in $(eval echo \\\$${1}Dep_$2); do + for a in `eval echo \\\$${1}Dep_$2`; do build_instruction_set $1 $a "$3" done fi - InstSet_Base=$(echo $InstSet_Base | sed 's/$ *//') # Remove trailing space. + InstSet_Base="`echo $InstSet_Base | sed 's/$ *//'`" # Remove trailing space. } -trap 'exit $EXIT_USAGE' TRAP # Allow usage() function to abort script execution. +trap "exit $EXIT_USAGE" TRAP # Allow usage() function to abort script execution. export TOP_PID=$$ # PID of executing process. # Parse command line arguments. -while getopts ":ra:s:LliIcf:d:D:CvVm:nB:A:h" o; do +while getopts ":ra:s:LliIcf:Fd:D:CvVm:nB:A:h" o; do case $o in r) Recursive=true ;; a) build_instruction_set Arch "$OPTARG" "architecture" ;; @@ -209,19 +208,19 @@ while getopts ":ra:s:LliIcf:d:D:CvVm:nB:A:h" o; do echo $InstSet_Base exit $EXIT_USAGE else - echo -e "No instruction set or architecture set.\\n" + echo -e "No instruction set or architecture set.\n" usage fi ;; I) if [ -n "$InstSet_Base" ]; then for s in $InstSet_Base; do - echo -ne "\\e[31;1m$s:\\e[0m " + echo -ne "\e[31;1m$s:\e[0m " eval echo "\$Opcode_$s" done exit $EXIT_USAGE else - echo -e "No instruction set or architecture set.\\n" + echo -e "No instruction set or architecture set.\n" usage fi ;; @@ -230,12 +229,12 @@ while getopts ":ra:s:LliIcf:d:D:CvVm:nB:A:h" o; do # Unlike architectures, instruction sets are disjoint. Found=false for s in $InstSetList; do - for b in $(eval echo \\\$InstSet_$s); do + for b in `eval echo \\\$InstSet_$s`; do Found_In_Base=false - for i in $(eval echo \\\$Opcode_$b); do + for i in `eval echo \\\$Opcode_$b`; do if [[ "$i" =~ ^$OPTARG$ ]]; then - $Found_In_Base || echo -ne "Instruction set \\e[33;1m$s\\e[0m (base instruction set \\e[32;1m$b\\e[0m):" - echo -ne " \\e[31;1m$i\\e[0m" + $Found_In_Base || echo -ne "Instruction set \e[33;1m$s\e[0m (base instruction set \e[32;1m$b\e[0m):" + echo -ne " \e[31;1m$i\e[0m" Found_In_Base=true Found=true fi @@ -244,7 +243,7 @@ while getopts ":ra:s:LliIcf:d:D:CvVm:nB:A:h" o; do done done if [ $Found = false ]; then - echo -e "Operation code \\e[31;1m$OPTARG\\e[0m has not been found in the database of known instructions." \ + echo -e "Operation code \e[31;1m$OPTARG\e[0m has not been found in the database of known instructions." \ "Perhaps it is translated using other than Intel syntax. If obtained from objdump, check if the \`-M intel' flag is set." \ "Be aware that the search is case sensitive by default (you may use the -C flag, otherwise only lower case opcodes are accepted)." exit $EXIT_NOT_FOUND @@ -263,13 +262,13 @@ while getopts ":ra:s:LliIcf:d:D:CvVm:nB:A:h" o; do A) Trailing_Context=$OPTARG ;; h) usage ;; \?) - echo -e "Unknown option: -$OPTARG\\n" + echo -e "Unknown option: -$OPTARG\n" usage ;; esac done shift $((OPTIND-1)) -[ -n "$1" ] && echo -e "Unknown command line parameter: $1\\n" && usage +[ -n "$1" ] && echo -e "Unknown command line parameter: $1\n" && usage [ -z "$InstSet_Base" ] && usage # Create list of grep parameters. @@ -283,13 +282,12 @@ Grep_Params="--color=auto -B $Leading_Context -A $Trailing_Context" # Build regular expression for use in grep. RegEx="" for s in $InstSet_Base; do - eval 'RegEx="$RegEx $Opcode_'"$s"'"' + eval RegEx=\"$RegEx \$Opcode_$s\" done # Add leading and trailing opcode separators to prevent false positives. -RegEx="$Leading_Separator$(echo $RegEx | sed "s/ /$(echo "$Trailing_Separator"|sed 's/[\/&]/\\\&/g')|$(echo "$Leading_Separator"|sed 's/[\/&]/\\\&/g')/g")$Trailing_Separator" +RegEx="$Leading_Separator`echo $RegEx | sed "s/ /$(echo "$Trailing_Separator"|sed 's/[\/&]/\\\&/g')|$(echo "$Leading_Separator"|sed 's/[\/&]/\\\&/g')/g"`$Trailing_Separator" -[ $Verbose = true ] && [ $Count_Matching = false ] && RegEx="$RegEx|\$" +[ $Verbose = true -a $Count_Matching = false ] && RegEx="$RegEx|\$" -# shellcheck disable=SC2086 # The actual search. grep $Grep_Params -E "$RegEx" && exit $EXIT_FOUND || exit $EXIT_NOT_FOUND -- cgit v1.2.3