1 #!/bin/bash !! 1 #!/bin/sh 2 # SPDX-License-Identifier: GPL-2.0 2 # SPDX-License-Identifier: GPL-2.0 3 # Disassemble the Code: line in Linux oopses 3 # Disassemble the Code: line in Linux oopses 4 # usage: decodecode < oops.file 4 # usage: decodecode < oops.file 5 # 5 # 6 # options: set env. variable AFLAGS=options to 6 # options: set env. variable AFLAGS=options to pass options to "as"; 7 # e.g., to decode an i386 oops on an x86_64 sy 7 # e.g., to decode an i386 oops on an x86_64 system, use: 8 # AFLAGS=--32 decodecode < 386.oops 8 # AFLAGS=--32 decodecode < 386.oops 9 # PC=hex - the PC (program counter) the oops p 9 # PC=hex - the PC (program counter) the oops points to 10 10 11 faultlinenum=1 << 12 << 13 cleanup() { 11 cleanup() { 14 rm -f $T $T.s $T.o $T.oo $T.aa $T.dis 12 rm -f $T $T.s $T.o $T.oo $T.aa $T.dis 15 exit 1 13 exit 1 16 } 14 } 17 15 18 die() { 16 die() { 19 echo "$@" 17 echo "$@" 20 exit 1 18 exit 1 21 } 19 } 22 20 23 trap cleanup EXIT 21 trap cleanup EXIT 24 22 25 T=`mktemp` || die "cannot create temp file" 23 T=`mktemp` || die "cannot create temp file" 26 code= 24 code= 27 cont= 25 cont= 28 26 29 while read i ; do 27 while read i ; do 30 28 31 case "$i" in 29 case "$i" in 32 *Code:*) 30 *Code:*) 33 code=$i 31 code=$i 34 cont=yes 32 cont=yes 35 ;; 33 ;; 36 *) 34 *) 37 [ -n "$cont" ] && { 35 [ -n "$cont" ] && { 38 xdump="$(echo $i | grep '^[[:x 36 xdump="$(echo $i | grep '^[[:xdigit:]<>[:space:]]\+$')" 39 if [ -n "$xdump" ]; then 37 if [ -n "$xdump" ]; then 40 code="$code $xdump" 38 code="$code $xdump" 41 else 39 else 42 cont= 40 cont= 43 fi 41 fi 44 } 42 } 45 ;; 43 ;; 46 esac 44 esac 47 45 48 done 46 done 49 47 50 if [ -z "$code" ]; then 48 if [ -z "$code" ]; then 51 rm $T 49 rm $T 52 exit 50 exit 53 fi 51 fi 54 52 55 echo $code 53 echo $code 56 code=`echo $code | sed -e 's/.*Code: //'` 54 code=`echo $code | sed -e 's/.*Code: //'` 57 55 58 width=`expr index "$code" ' '` 56 width=`expr index "$code" ' '` 59 width=$((($width-1)/2)) 57 width=$((($width-1)/2)) 60 case $width in 58 case $width in 61 1) type=byte ;; 59 1) type=byte ;; 62 2) type=2byte ;; 60 2) type=2byte ;; 63 4) type=4byte ;; 61 4) type=4byte ;; 64 esac 62 esac 65 63 66 if [ -z "$ARCH" ]; then 64 if [ -z "$ARCH" ]; then 67 case `uname -m` in 65 case `uname -m` in 68 aarch64*) ARCH=arm64 ;; 66 aarch64*) ARCH=arm64 ;; 69 arm*) ARCH=arm ;; 67 arm*) ARCH=arm ;; 70 loongarch*) ARCH=loongarch ;; << 71 esac 68 esac 72 fi 69 fi 73 70 74 # Params: (tmp_file, pc_sub) 71 # Params: (tmp_file, pc_sub) 75 disas() { 72 disas() { 76 t=$1 73 t=$1 77 pc_sub=$2 74 pc_sub=$2 78 75 79 ${CROSS_COMPILE}as $AFLAGS -o $t.o $t. 76 ${CROSS_COMPILE}as $AFLAGS -o $t.o $t.s > /dev/null 2>&1 80 77 81 if [ "$ARCH" = "arm" ]; then 78 if [ "$ARCH" = "arm" ]; then 82 if [ $width -eq 2 ]; then 79 if [ $width -eq 2 ]; then 83 OBJDUMPFLAGS="-M force 80 OBJDUMPFLAGS="-M force-thumb" 84 fi 81 fi 85 82 86 ${CROSS_COMPILE}strip $t.o 83 ${CROSS_COMPILE}strip $t.o 87 fi 84 fi 88 85 89 if [ "$ARCH" = "arm64" ]; then 86 if [ "$ARCH" = "arm64" ]; then 90 if [ $width -eq 4 ]; then 87 if [ $width -eq 4 ]; then 91 type=inst 88 type=inst 92 fi 89 fi 93 90 94 ${CROSS_COMPILE}strip $t.o 91 ${CROSS_COMPILE}strip $t.o 95 fi 92 fi 96 93 97 if [ "$ARCH" = "riscv" ]; then << 98 OBJDUMPFLAGS="-M no-aliases -- << 99 ${CROSS_COMPILE}strip $t.o << 100 fi << 101 << 102 if [ "$ARCH" = "loongarch" ]; then << 103 ${CROSS_COMPILE}strip $t.o << 104 fi << 105 << 106 if [ $pc_sub -ne 0 ]; then 94 if [ $pc_sub -ne 0 ]; then 107 if [ $PC ]; then 95 if [ $PC ]; then 108 adj_vma=$(( $PC - $pc_ 96 adj_vma=$(( $PC - $pc_sub )) 109 OBJDUMPFLAGS="$OBJDUMP 97 OBJDUMPFLAGS="$OBJDUMPFLAGS --adjust-vma=$adj_vma" 110 fi 98 fi 111 fi 99 fi 112 100 113 ${CROSS_COMPILE}objdump $OBJDUMPFLAGS 101 ${CROSS_COMPILE}objdump $OBJDUMPFLAGS -S $t.o | \ 114 grep -v "/tmp\|Disassembly\|\. 102 grep -v "/tmp\|Disassembly\|\.text\|^$" > $t.dis 2>&1 115 } 103 } 116 104 117 # Match the maximum number of opcode bytes fro << 118 # @opline << 119 # << 120 # Params: << 121 # @op_bytes: The string of bytes from the Code << 122 # @opline: The disassembled line coming from o << 123 # << 124 # Returns: << 125 # The max number of opcode bytes from the begi << 126 # the opcode bytes in the objdump line. << 127 get_substr_opcode_bytes_num() << 128 { << 129 local op_bytes=$1 << 130 local opline=$2 << 131 << 132 local retval=0 << 133 substr="" << 134 << 135 for opc in $op_bytes; << 136 do << 137 substr+="$opc" << 138 << 139 opcode="$substr" << 140 if [ "$ARCH" = "riscv" ]; then << 141 opcode=$(echo $opcode << 142 fi << 143 << 144 # return if opcode bytes do no << 145 if ! echo $opline | grep -q "$ << 146 then << 147 break << 148 fi << 149 << 150 # add trailing space << 151 substr+=" " << 152 retval=$((retval+1)) << 153 done << 154 << 155 return $retval << 156 } << 157 << 158 # Return the line number in objdump output to << 159 # line points to << 160 # << 161 # Params: << 162 # @all_code: code in bytes without the marker << 163 # @dis_file: disassembled file << 164 # @ip_byte: The byte to which the IP points to << 165 get_faultlinenum() << 166 { << 167 local all_code="$1" << 168 local dis_file="$2" << 169 << 170 # num bytes including IP byte << 171 local num_bytes_ip=$(( $3 + 1 * $width << 172 << 173 # Add the two header lines (we're coun << 174 local retval=3 << 175 << 176 # remove marker << 177 all_code=$(echo $all_code | sed -e 's/ << 178 << 179 while read line << 180 do << 181 get_substr_opcode_bytes_num "$ << 182 ate_opcodes=$? << 183 << 184 if ! (( $ate_opcodes )); then << 185 continue << 186 fi << 187 << 188 num_bytes_ip=$((num_bytes_ip - << 189 if (( $num_bytes_ip <= 0 )); t << 190 break << 191 fi << 192 << 193 # Delete matched opcode bytes << 194 # how many chars those opcodes << 195 # trailing space. << 196 # << 197 # a byte is 2 chars, ate_opcod << 198 # spaces << 199 del_chars=$(( ($ate_opcodes * << 200 << 201 all_code=$(echo $all_code | se << 202 << 203 let "retval+=1" << 204 << 205 done < $dis_file << 206 << 207 return $retval << 208 } << 209 << 210 marker=`expr index "$code" "\<"` 105 marker=`expr index "$code" "\<"` 211 if [ $marker -eq 0 ]; then 106 if [ $marker -eq 0 ]; then 212 marker=`expr index "$code" "\("` 107 marker=`expr index "$code" "\("` 213 fi 108 fi 214 109 >> 110 215 touch $T.oo 111 touch $T.oo 216 if [ $marker -ne 0 ]; then 112 if [ $marker -ne 0 ]; then 217 # How many bytes to subtract from the !! 113 # 2 opcode bytes and a single space 218 # in order to get to the beginning vir !! 114 pc_sub=$(( $marker / 3 )) 219 # Code: << 220 pc_sub=$(( (($marker - 1) / (2 * $widt << 221 echo All code >> $T.oo 115 echo All code >> $T.oo 222 echo ======== >> $T.oo 116 echo ======== >> $T.oo 223 beforemark=`echo "$code"` 117 beforemark=`echo "$code"` 224 echo -n " .$type 0x" > $T.s 118 echo -n " .$type 0x" > $T.s 225 << 226 echo $beforemark | sed -e 's/ /,0x/g; 119 echo $beforemark | sed -e 's/ /,0x/g; s/[<>()]//g' >> $T.s 227 << 228 disas $T $pc_sub 120 disas $T $pc_sub 229 << 230 cat $T.dis >> $T.oo 121 cat $T.dis >> $T.oo >> 122 rm -f $T.o $T.s $T.dis 231 123 232 get_faultlinenum "$code" "$T.dis" $pc_ !! 124 # and fix code at-and-after marker 233 faultlinenum=$? << 234 << 235 # and fix code at-and-after marker << 236 code=`echo "$code" | cut -c$((${marker 125 code=`echo "$code" | cut -c$((${marker} + 1))-` 237 << 238 rm -f $T.o $T.s $T.dis << 239 fi 126 fi 240 << 241 echo Code starting with the faulting instructi 127 echo Code starting with the faulting instruction > $T.aa 242 echo ========================================= 128 echo =========================================== >> $T.aa 243 code=`echo $code | sed -e 's/\r//;s/ [<(]/ /;s 129 code=`echo $code | sed -e 's/\r//;s/ [<(]/ /;s/[>)] / /;s/ /,0x/g; s/[>)]$//'` 244 echo -n " .$type 0x" > $T.s 130 echo -n " .$type 0x" > $T.s 245 echo $code >> $T.s 131 echo $code >> $T.s 246 disas $T 0 132 disas $T 0 247 cat $T.dis >> $T.aa 133 cat $T.dis >> $T.aa >> 134 >> 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'` 248 143 249 cat $T.oo | sed -e "${faultlinenum}s/^\([^:]*: 144 cat $T.oo | sed -e "${faultlinenum}s/^\([^:]*:\)\(.*\)/\1\*\2\t\t<-- trapping instruction/" 250 echo 145 echo 251 cat $T.aa 146 cat $T.aa 252 cleanup 147 cleanup
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.