Skip to content

Commit 765f2bf

Browse files
suryasaimadhuakpm00
authored andcommitted
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. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Borislav Petkov <[email protected]> Cc: Marc Zyngier <[email protected]> Cc: Will Deacon <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 9f25f35 commit 765f2bf

File tree

1 file changed

+105
-15
lines changed

1 file changed

+105
-15
lines changed

scripts/decodecode

+105-15
Original file line numberDiff line numberDiff line change
@@ -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 @@
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() {
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
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

0 commit comments

Comments
 (0)