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/sh1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.02# SPDX-License-Identifier: GPL-2.0
3# Disassemble the Code: line in Linux oopses3# Disassemble the Code: line in Linux oopses
4# usage: decodecode < oops.file4# usage: decodecode < oops.file
@@ -8,6 +8,8 @@ · 3 unmodified lines
8# AFLAGS=--32 decodecode < 386.oops8# AFLAGS=--32 decodecode < 386.oops
9# PC=hex - the PC (program counter) the oops points to9# PC=hex - the PC (program counter) the oops points to
10 10
11faultlinenum=1
12
11cleanup() {13cleanup() {
12 rm -f $T $T.s $T.o $T.oo $T.aa $T.dis14 rm -f $T $T.s $T.o $T.oo $T.aa $T.dis
13 exit 115 exit 1
@@ -102,28 +104,125 @@ disas() { · 88 unmodified lines
102 grep -v "/tmp\|Disassembly\|\.text\|^$" > $t.dis 2>&1104 grep -v "/tmp\|Disassembly\|\.text\|^$" > $t.dis 2>&1
103}105}
104 106
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.
117get_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
150get_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
105marker=`expr index "$code" "\<"`195marker=`expr index "$code" "\<"`
106if [ $marker -eq 0 ]; then196if [ $marker -eq 0 ]; then
107 marker=`expr index "$code" "\("`197 marker=`expr index "$code" "\("`
108fi198fi
109 199
110
111touch $T.oo200touch $T.oo
112if [ $marker -ne 0 ]; then201if [ $marker -ne 0 ]; then
113 # 2 opcode bytes and a single space202 # How many bytes to subtract from the program counter
114 pc_sub=$(( $marker / 3 ))203 # in order to get to the beginning virtual address of the
204 # Code:
205 pc_sub=$(( (($marker - 1) / (2 * $width + 1)) * $width ))
115 echo All code >> $T.oo206 echo All code >> $T.oo
116 echo ======== >> $T.oo207 echo ======== >> $T.oo
117 beforemark=`echo "$code"`208 beforemark=`echo "$code"`
118 echo -n " .$type 0x" > $T.s209 echo -n " .$type 0x" > $T.s
210
119 echo $beforemark | sed -e 's/ /,0x/g; s/[<>()]//g' >> $T.s211 echo $beforemark | sed -e 's/ /,0x/g; s/[<>()]//g' >> $T.s
212
120 disas $T $pc_sub213 disas $T $pc_sub
214
121 cat $T.dis >> $T.oo215 cat $T.dis >> $T.oo
122 rm -f $T.o $T.s $T.dis
123 216
124# and fix code at-and-after marker217 get_faultlinenum "$code" "$T.dis" $pc_sub
218 faultlinenum=$?
219
220 # and fix code at-and-after marker
125 code=`echo "$code" | cut -c$((${marker} + 1))-`221 code=`echo "$code" | cut -c$((${marker} + 1))-`
222
223 rm -f $T.o $T.s $T.dis
126fi224fi
225
127echo Code starting with the faulting instruction > $T.aa226echo Code starting with the faulting instruction > $T.aa
128echo =========================================== >> $T.aa227echo =========================================== >> $T.aa
129code=`echo $code | sed -e 's/\r//;s/ [<(]/ /;s/[>)] / /;s/ /,0x/g; s/[>)]$//'`228code=`echo $code | sed -e 's/\r//;s/ [<(]/ /;s/[>)] / /;s/ /,0x/g; s/[>)]$//'`
@@ -132,15 +231,6 @@ echo $code >> $T.s · 2 unmodified lines
132disas $T 0231disas $T 0
133cat $T.dis >> $T.aa232cat $T.dis >> $T.aa
134 233
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)
138faultlinenum=$(( $(wc -l $T.oo | cut -d" " -f1) - \
139 $(wc -l $T.aa | cut -d" " -f1) + 3))
140
141faultline=`cat $T.dis | head -1 | cut -d":" -f2-`
142faultline=`echo "$faultline" | sed -e 's/\[/\\\[/g; s/\]/\\\]/g'`
143
144cat $T.oo | sed -e "${faultlinenum}s/^\([^:]*:\)\(.*\)/\1\*\2\t\t<-- trapping instruction/"234cat $T.oo | sed -e "${faultlinenum}s/^\([^:]*:\)\(.*\)/\1\*\2\t\t<-- trapping instruction/"
145echo235echo
146cat $T.aa236cat $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