History

scripts/decodecode: improve faulting line determination

There are cases where the IP pointer in a Code: line in an oops doesn't point at the beginning of an instruction: Code: 0f bd c2 e9 a0 cd b5 e4 48 0f bd c2 e9 97 cd b5 e4 0f 1f 80 00 00 00 00 \ e9 8b cd b5 e4 0f 1f 00 66 0f a3 d0 e9 7f cd b5 e4 0f 1f <80> 00 00 00 \ 00 0f a3 d0 e9 70 cd b5 e4 48 0f a3 d0 e9 67 cd b5 e9 7f cd b5 e4 jmp 0xffffffffe4b5cda8 0f 1f 80 00 00 00 00 nopl 0x0(%rax) ^^ and the current way of determining the faulting instruction line doesn't work because disassembled instructions are counted from the IP byte to the end and when that thing points in the middle, the trailing bytes can be interpreted as different insns: Code starting with the faulting instruction =========================================== 0: 80 00 00 addb $0x0,(%rax) 3: 00 00 add %al,(%rax) whereas, this is part of 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 5: 0f a3 d0 bt %edx,%eax ... leading to: 1d: 0f 1f 00 nopl (%rax) 20: 66 0f a3 d0 bt %dx,%ax 24:* e9 7f cd b5 e4 jmp 0xffffffffe4b5cda8 <-- trapping instruction 29: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 30: 0f a3 d0 bt %edx,%eax which is the wrong faulting instruction. Change the way the faulting line number is determined by matching the opcode bytes from the beginning, leading to correct output: 1d: 0f 1f 00 nopl (%rax) 20: 66 0f a3 d0 bt %dx,%ax 24: e9 7f cd b5 e4 jmp 0xffffffffe4b5cda8 29:* 0f 1f 80 00 00 00 00 nopl 0x0(%rax) <-- trapping instruction 30: 0f a3 d0 bt %edx,%eax While at it, make decodecode use bash as the interpreter - that thing should be present on everything by now. It simplifies the code a lot too.

Borislav Petkov committed 4 years ago

Commit 765f2bf1 parent 9f25f351 file · +105 −15Browse files

Unified · Split

scripts/decodecode+105−15
@@ -1,4 +1,4 @@
1−#!/bin/sh
1+#!/bin/bash
22 # SPDX-License-Identifier: GPL-2.0
33 # Disassemble the Code: line in Linux oopses
44 # usage: decodecode < oops.file
@@ -8,6 +8,8 @@ · 3 unmodified lines
88 # AFLAGS=--32 decodecode < 386.oops
99 # PC=hex - the PC (program counter) the oops points to
1010
11+faultlinenum=1
12+
1113 cleanup() {
1214 rm -f $T $T.s $T.o $T.oo $T.aa $T.dis
1315 exit 1
@@ -102,28 +104,125 @@ disas() { · 88 unmodified lines
102104 grep -v "/tmp\|Disassembly\|\.text\|^$" > $t.dis 2>&1
103105 }
104106
107+# Match the maximum number of opcode bytes from @op_bytes contained within
108+# @opline
109+#
110+# Params:
111+# @op_bytes: The string of bytes from the Code: line
112+# @opline: The disassembled line coming from objdump
113+#
114+# Returns:
115+# The max number of opcode bytes from the beginning of @op_bytes which match
116+# the opcode bytes in the objdump line.
117+get_substr_opcode_bytes_num()
118+{
119+ local op_bytes=$1
120+ local opline=$2
121+
122+ local retval=0
123+ substr=""
124+
125+ for opc in $op_bytes;
126+ do
127+ substr+="$opc"
128+
129+ # return if opcode bytes do not match @opline anymore
130+ if ! echo $opline | grep -q "$substr";
131+ then
132+ break
133+ fi
134+
135+ # add trailing space
136+ substr+=" "
137+ retval=$((retval+1))
138+ done
139+
140+ return $retval
141+}
142+
143+# Return the line number in objdump output to where the IP marker in the Code:
144+# line points to
145+#
146+# Params:
147+# @all_code: code in bytes without the marker
148+# @dis_file: disassembled file
149+# @ip_byte: The byte to which the IP points to
150+get_faultlinenum()
151+{
152+ local all_code="$1"
153+ local dis_file="$2"
154+
155+ # num bytes including IP byte
156+ local num_bytes_ip=$(( $3 + 1 * $width ))
157+
158+ # Add the two header lines (we're counting from 1).
159+ local retval=3
160+
161+ # remove marker
162+ all_code=$(echo $all_code | sed -e 's/[<>()]//g')
163+
164+ while read line
165+ do
166+ get_substr_opcode_bytes_num "$all_code" "$line"
167+ ate_opcodes=$?
168+
169+ if ! (( $ate_opcodes )); then
170+ continue
171+ fi
172+
173+ num_bytes_ip=$((num_bytes_ip - ($ate_opcodes * $width) ))
174+ if (( $num_bytes_ip <= 0 )); then
175+ break
176+ fi
177+
178+ # Delete matched opcode bytes from all_code. For that, compute
179+ # how many chars those opcodes are represented by and include
180+ # trailing space.
181+ #
182+ # a byte is 2 chars, ate_opcodes is also the number of trailing
183+ # spaces
184+ del_chars=$(( ($ate_opcodes * $width * 2) + $ate_opcodes ))
185+
186+ all_code=$(echo $all_code | sed -e "s!^.\{$del_chars\}!!")
187+
188+ let "retval+=1"
189+
190+ done < $dis_file
191+
192+ return $retval
193+}
194+
105195 marker=`expr index "$code" "\<"`
106196 if [ $marker -eq 0 ]; then
107197 marker=`expr index "$code" "\("`
108198 fi
109199
110−
111200 touch $T.oo
112201 if [ $marker -ne 0 ]; then
113− # 2 opcode bytes and a single space
114− pc_sub=$(( $marker / 3 ))
202+ # How many bytes to subtract from the program counter
203+ # in order to get to the beginning virtual address of the
204+ # Code:
205+ pc_sub=$(( (($marker - 1) / (2 * $width + 1)) * $width ))
115206 echo All code >> $T.oo
116207 echo ======== >> $T.oo
117208 beforemark=`echo "$code"`
118209 echo -n " .$type 0x" > $T.s
210+
119211 echo $beforemark | sed -e 's/ /,0x/g; s/[<>()]//g' >> $T.s
212+
120213 disas $T $pc_sub
214+
121215 cat $T.dis >> $T.oo
122− rm -f $T.o $T.s $T.dis
123216
124−# and fix code at-and-after marker
217+ get_faultlinenum "$code" "$T.dis" $pc_sub
218+ faultlinenum=$?
219+
220+ # and fix code at-and-after marker
125221 code=`echo "$code" | cut -c$((${marker} + 1))-`
222+
223+ rm -f $T.o $T.s $T.dis
126224 fi
225+
127226 echo Code starting with the faulting instruction > $T.aa
128227 echo =========================================== >> $T.aa
129228 code=`echo $code | sed -e 's/\r//;s/ [<(]/ /;s/[>)] / /;s/ /,0x/g; s/[>)]$//'`
@@ -132,15 +231,6 @@ echo $code >> $T.s · 2 unmodified lines
132231 disas $T 0
133232 cat $T.dis >> $T.aa
134233
135−# (lines of whole $T.oo) - (lines of $T.aa, i.e. "Code starting") + 3,
136−# i.e. the title + the "===..=" line (sed is counting from 1, 0 address is
137−# special)
138−faultlinenum=$(( $(wc -l $T.oo | cut -d" " -f1) - \
139− $(wc -l $T.aa | cut -d" " -f1) + 3))
140−
141−faultline=`cat $T.dis | head -1 | cut -d":" -f2-`
142−faultline=`echo "$faultline" | sed -e 's/\[/\\\[/g; s/\]/\\\]/g'`
143−
144234 cat $T.oo | sed -e "${faultlinenum}s/^\([^:]*:\)\(.*\)/\1\*\2\t\t<-- trapping instruction/"
145235 echo
146236 cat $T.aa

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t