Home | History | Annotate | Download | only in scripts
      1 #!/bin/bash
      2 
      3 # objdiff - a small script for validating that a commit or series of commits
      4 # didn't change object code.
      5 #
      6 # Copyright 2014, Jason Cooper <jason (at] lakedaemon.net>
      7 #
      8 # Licensed under the terms of the GNU GPL version 2
      9 
     10 # usage example:
     11 #
     12 # $ git checkout COMMIT_A
     13 # $ <your fancy build command here>
     14 # $ ./scripts/objdiff record path/to/*.o
     15 #
     16 # $ git checkout COMMIT_B
     17 # $ <your fancy build command here>
     18 # $ ./scripts/objdiff record path/to/*.o
     19 #
     20 # $ ./scripts/objdiff diff COMMIT_A COMMIT_B
     21 # $
     22 
     23 # And to clean up (everything is in .tmp_objdiff/*)
     24 # $ ./scripts/objdiff clean all
     25 #
     26 # Note: 'make mrproper' will also remove .tmp_objdiff
     27 
     28 SRCTREE=$(cd $(git rev-parse --show-toplevel 2>/dev/null); pwd)
     29 
     30 if [ -z "$SRCTREE" ]; then
     31 	echo >&2 "ERROR: Not a git repository."
     32 	exit 1
     33 fi
     34 
     35 TMPD=$SRCTREE/.tmp_objdiff
     36 
     37 usage() {
     38 	echo >&2 "Usage: $0 <command> <args>"
     39 	echo >&2 "  record    <list of object files or directories>"
     40 	echo >&2 "  diff      <commitA> <commitB>"
     41 	echo >&2 "  clean     all | <commit>"
     42 	exit 1
     43 }
     44 
     45 get_output_dir() {
     46 	dir=${1%/*}
     47 
     48 	if [ "$dir" = "$1" ]; then
     49 		dir=.
     50 	fi
     51 
     52 	dir=$(cd $dir; pwd)
     53 
     54 	echo $TMPD/$CMT${dir#$SRCTREE}
     55 }
     56 
     57 do_objdump() {
     58 	dir=$(get_output_dir $1)
     59 	base=${1##*/}
     60 	stripped=$dir/${base%.o}.stripped
     61 	dis=$dir/${base%.o}.dis
     62 
     63 	[ ! -d "$dir" ] && mkdir -p $dir
     64 
     65 	# remove addresses for a cleaner diff
     66 	# http://dummdida.tumblr.com/post/60924060451/binary-diff-between-libc-from-scientificlinux-and
     67 	$STRIP -g $1 -R __bug_table -R .note -R .comment -o $stripped
     68 	$OBJDUMP -D $stripped | sed -e "s/^[[:space:]]\+[0-9a-f]\+//" -e "s:^$stripped:$1:" > $dis
     69 }
     70 
     71 dorecord() {
     72 	[ $# -eq 0 ] && usage
     73 
     74 	FILES="$*"
     75 
     76 	CMT="`git rev-parse --short HEAD`"
     77 
     78 	STRIP="${CROSS_COMPILE}strip"
     79 	OBJDUMP="${CROSS_COMPILE}objdump"
     80 
     81 	for d in $FILES; do
     82 		if [ -d "$d" ]; then
     83 			for f in $(find $d -name '*.o')
     84 			do
     85 				do_objdump $f
     86 			done
     87 		else
     88 			do_objdump $d
     89 		fi
     90 	done
     91 }
     92 
     93 dodiff() {
     94 	[ $# -ne 2 ] && [ $# -ne 0 ] && usage
     95 
     96 	if [ $# -eq 0 ]; then
     97 		SRC="`git rev-parse --short HEAD^`"
     98 		DST="`git rev-parse --short HEAD`"
     99 	else
    100 		SRC="`git rev-parse --short $1`"
    101 		DST="`git rev-parse --short $2`"
    102 	fi
    103 
    104 	DIFF="`which colordiff`"
    105 
    106 	if [ ${#DIFF} -eq 0 ] || [ ! -x "$DIFF" ]; then
    107 		DIFF="`which diff`"
    108 	fi
    109 
    110 	SRCD="$TMPD/$SRC"
    111 	DSTD="$TMPD/$DST"
    112 
    113 	if [ ! -d "$SRCD" ]; then
    114 		echo >&2 "ERROR: $SRCD doesn't exist"
    115 		exit 1
    116 	fi
    117 
    118 	if [ ! -d "$DSTD" ]; then
    119 		echo >&2 "ERROR: $DSTD doesn't exist"
    120 		exit 1
    121 	fi
    122 
    123 	$DIFF -Nurd $SRCD $DSTD
    124 }
    125 
    126 doclean() {
    127 	[ $# -eq 0 ] && usage
    128 	[ $# -gt 1 ] && usage
    129 
    130 	if [ "x$1" = "xall" ]; then
    131 		rm -rf $TMPD/*
    132 	else
    133 		CMT="`git rev-parse --short $1`"
    134 
    135 		if [ -d "$TMPD/$CMT" ]; then
    136 			rm -rf $TMPD/$CMT
    137 		else
    138 			echo >&2 "$CMT not found"
    139 		fi
    140 	fi
    141 }
    142 
    143 [ $# -eq 0 ] &&	usage
    144 
    145 case "$1" in
    146 	record)
    147 		shift
    148 		dorecord $*
    149 		;;
    150 	diff)
    151 		shift
    152 		dodiff $*
    153 		;;
    154 	clean)
    155 		shift
    156 		doclean $*
    157 		;;
    158 	*)
    159 		echo >&2 "Unrecognized command '$1'"
    160 		exit 1
    161 		;;
    162 esac
    163