xref: /openbmc/linux/scripts/objdiff (revision b5f184fbdb03b4fcc1141de34dd5ec964ca5d99e)
1 #!/bin/bash
2 # SPDX-License-Identifier: GPL-2.0-only
3 
4 # objdiff - a small script for validating that a commit or series of commits
5 # didn't change object code.
6 #
7 # Copyright 2014, Jason Cooper <jason@lakedaemon.net>
8 #
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