]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - debian/scripts/retpoline-extract-one
09d7585a16ebb0d32e5d793049c216f2dbe0e657
[mirror_ubuntu-bionic-kernel.git] / debian / scripts / retpoline-extract-one
1 #!/bin/bash
2
3 exec </dev/null
4
5 object="$1"
6 src="$2"
7 bit16="$3"
8
9 SECTION=".discard.retpoline_safe"
10
11 # Form an associative lookup for the symbol numbers in the ELF symbol table.
12 # Uses 8 character 0 expanded hexadecimal key for ease of consumption.
13 __symbolmap_init()
14 {
15 readelf -W --syms "$1" |
16 awk '($4 == "SECTION" && $1 ~ /^[0-9]*:/) { printf("%08x %08x\n", int($1), int($7)); }' | \
17 while read symbol_num section_num
18 do
19 echo "symbolmap_$symbol_num='$section_num'"
20 done
21 }
22 symbolmap_init()
23 {
24 eval $(__symbolmap_init "$1")
25 }
26 symbolmap()
27 {
28 eval RET="\$symbolmap_$1"
29 if [ "$RET" = '' ]; then
30 echo "symbolmap: $1: invalid section" 1>&2
31 exit 1
32 fi
33 }
34
35 # Form an associative lookup for the section numbers in the ELF symbol table.
36 # Uses 8 character 0 expanded hexadecimal key for ease of consumption.
37 __sectionmap_init()
38 {
39 readelf -W --headers "$1" | \
40 awk '
41 { sub("\\[", ""); sub("\\]", ""); }
42 ($1 ~ /^[0-9][0-9]*/) { printf("%08x %s %s %s\n", int($1), $2, $3, $4); }
43 ' | \
44 {
45 while read section_num section_name section_type section_vma
46 do
47 echo "sectionmap_$section_num='$section_name'"
48 echo "sectionvma_$section_num='$section_vma'"
49 case "$section_type" in
50 REL|RELA) section_relocation="$section_type" ;;
51 esac
52 done
53 echo "section_relocation='$section_relocation'"
54 }
55 }
56 sectionmap_init()
57 {
58 eval $(__sectionmap_init "$1")
59 }
60 sectionmap()
61 {
62 eval RET="\$sectionmap_$1"
63 if [ "$RET" = '' ]; then
64 echo "sectionmap: $1: invalid section" 1>&2
65 exit 1
66 fi
67 }
68 sectionvma()
69 {
70 eval RET="\$sectionvma_$1"
71 if [ "$RET" = '' ]; then
72 echo "sectionvma: $1: invalid section" 1>&2
73 exit 1
74 fi
75 }
76
77 # Read and parse the hex-dump output.
78 hex="[0-9a-f]"
79 hex_8="$hex$hex$hex$hex$hex$hex$hex$hex"
80 hexspc="[0-9a-f ]"
81 hexspc_8="$hexspc$hexspc$hexspc$hexspc$hexspc$hexspc$hexspc$hexspc"
82
83 raw32()
84 {
85 readelf --hex-dump "$2" "$1" 2>/dev/null |
86 sed \
87 -e '/^Hex/d' -e '/^$/d' -e '/^ *NOTE/d' \
88 -e 's/ *[^ ][^ ]* *\('"$hex_8"'\) \('"$hexspc_8"'\) \('"$hexspc_8"'\) \('"$hexspc_8"'\) .*/\1 \2 \3 \4 /' \
89 -e 's/\('"$hex$hex"'\)\('"$hex$hex"'\)\('"$hex$hex"'\)\('"$hex$hex"'\) /\4\3\2\1 /g' \
90 -e 's/ $//g' -e 's/ /\n/g'
91 }
92 #-e 's/\([^ ][^ ][^ ][^ ][^ ][^ ][^ ][^ ]\) \([^ ][^ ][^ ][^ ][^ ][^ ][^ ][^ ]\) /\2\1 /g' \
93
94 rela()
95 {
96 #file="$(basename "$1")"
97 file="$1"
98
99 # Read relocation information for a 64bit binary. Each relocation entry
100 # is 3 long longs so we collect 6 quads here. Note that the dump is in
101 # listed in increasing byte order not withstanding the quad split.
102 #
103 # The record says to take the value of <symbol> add <symbol offset> and
104 # shove that into <write offset> in the segment of the <symbol>.
105 #
106 # Format:
107 # <write offset> 64 bits
108 # <symbol number> 32 bits
109 # <relocation type> 32 bits
110 # <symbol offset> 64 bits
111 raw32 "$1" ".rela$SECTION" | \
112 {
113 a1=''; a2=''; a3=''; a4=''; a5=''
114 while read a6
115 do
116 [ "$a1" = '' ] && { a1="$a6"; continue; }
117 [ "$a2" = '' ] && { a2="$a6"; continue; }
118 [ "$a3" = '' ] && { a3="$a6"; continue; }
119 [ "$a4" = '' ] && { a4="$a6"; continue; }
120 [ "$a5" = '' ] && { a5="$a6"; continue; }
121
122 #echo ">$a1< >$a2< >$a3< >$a4< >$a5< >$a6<" 1>&2
123 #echo "type<$a3> symbol<$a4> offset<$a2$a1> addr<$a6a5>" 1>&2
124
125 symbolmap "$a4"; section_num="$RET"
126 #echo "section_num<$section_num>" 1>&2
127
128 sectionmap "$section_num"; section="$RET"
129 sectionvma "$section_num"; vma="$RET"
130 #echo "section<$section> vma<$vma>" 1>&2
131
132 # Adjust the segment addressing by the segment offset.
133 printf -v addr "%u" "0x$a6$a5"
134 printf -v vma "%u" "0x$vma"
135 let offset="$addr + $vma"
136 printf -v offset "%x" "$offset"
137
138 echo "$file-$section-$offset"
139
140 a1=''; a2=''; a3=''; a4=''; a5=''
141 done
142 } | sed -e 's/-00*\([0-9a-f]\)/-\1/'
143 }
144
145 # Form an associative lookup for the raw contents for an ELF section.
146 # Uses 8 character 0 expanded hexadecimal key for ease of consumption.
147 contentmap_init()
148 {
149 raw32 "$1" "$2" >"$tmp.cm"
150 let offset=0
151 while read value
152 do
153 printf -v offset_hex "%08x" $offset
154 eval contentmap_$offset_hex=\'$value\'
155
156 let offset="$offset + 4"
157 done <"$tmp.cm"
158 rm -f "$tmp.cm"
159 }
160 contentmap()
161 {
162 eval RET="\$contentmap_$1"
163 if [ "$RET" = '' ]; then
164 echo "contentmap: $1: invalid offset" 1>&2
165 exit 1
166 fi
167 }
168
169 rel()
170 {
171 # Load up the current contents of the $SECTION segment
172 # as the offsets (see below) are recorded there and we will need
173 # those to calculate the actuall address.
174 contentmap_init "$1" "$SECTION"
175
176 #file="$(basename "$1")"
177 file="$1"
178
179 # Read relocation information for a 32bit binary. Each relocation entry
180 # is 3 longs so we collect 3 quads here. Note that the dump is in
181 # listed in increasing byte order not withstanding the quad split.
182 #
183 # The record says to take the value of <symbol> and add that to the
184 # existing contents of <write offset> in the segment of the <symbol>.
185 #
186 # Format:
187 # <write offset> 32 bits
188 # <symbol number> 24 bits
189 # <relocation type> 8 bits
190 raw32 "$1" ".rel$SECTION" | \
191 {
192 a1=''
193 while read a2
194 do
195 [ "$a1" = '' ] && { a1="$a2"; continue; }
196
197 #echo ">$a1< >$a2<"
198 contentmap "$a1"; offset="$RET"
199 symbolmap "00${a2%??}"; section_num="$RET"
200
201 sectionmap "$section_num"; section="$RET"
202 sectionvma "$section_num"; vma="$RET"
203 #echo ">$a1< >$a2< >$offset< >$section<"
204
205 echo "$file-$section-$offset"
206
207 a1=''
208 done
209 } | sed -e 's/-00*\([0-9a-f]\)/-\1/'
210 }
211
212 tmp="/tmp/retpoline-extract.$$"
213
214 disassemble()
215 {
216 local object="$1"
217 local src="$2"
218 local options="$3"
219 local selector="$4"
220
221 objdump $options --disassemble --no-show-raw-insn "$object" | \
222 awk -F' ' '
223 BEGIN { file="'"$object"'"; src="'"$src"'"; }
224 /Disassembly of section/ { segment=$4; sub(":", "", segment); }
225 /^[0-9a-f][0-9a-f]* <.*>:/ { tag=$0; sub(".*<", "", tag); sub(">.*", "", tag); }
226 $0 ~ /(call|jmp)q? *\*.*%/ {
227 sub(":", "", $1);
228 if ('"$selector"') {
229 offset=$1
230 $1=tag
231 print(file "-" segment "-" offset " " src " " segment " " $0);
232 }
233 }
234 '
235 }
236
237 # Accumulate potentially vunerable indirect call/jmp sequences. We do this
238 # by examining the raw disassembly for affected forms, recording the location
239 # of each.
240 case "$bit16" in
241 '') disassemble "$object" "$src" '' 'segment != ".init.text"' ;;
242 *) disassemble "$object" "$src" '--disassembler-options=i8086' 'segment != ".init.text" && segment != ".text32" && segment != ".text64"'
243 disassemble "$object" "$src" '--disassembler-options=i386' 'segment == ".text32"'
244 disassemble "$object" "$src" '--disassembler-options=x86-64' 'segment == ".text64"'
245 ;;
246 esac | sort -k 1b,1 >"$object.ur-detected"
247 [ ! -s "$object.ur-detected" ] && rm -f "$object.ur-detected"
248
249 # Load up the symbol table and section mappings.
250 symbolmap_init "$object"
251 sectionmap_init "$object"
252
253 # Accumulate annotated safe indirect call/jmp sequences. We do this by examining
254 # the $SECTION sections (and their associated relocation information),
255 # each entry represents the address of an instruction which has been marked
256 # as ok.
257 case "$section_relocation" in
258 REL) rel "$object" ;;
259 RELA) rela "$object" ;;
260 esac | sort -k 1b,1 >"$object.ur-safe"
261 [ ! -s "$object.ur-safe" ] && rm -f "$object.ur-safe"
262
263 # We will perform the below join on the summarised and sorted fragments
264 # formed above. This is performed in retpoline-check.
265 #join -v 1 -j 1 "$tmp.extracted" "$tmp.safe" | sed -s 's/[^ ]* *//'
266
267 rm -f "$tmp".*