1*765f2bf0SBorislav Petkov#!/bin/bash 2b2441318SGreg Kroah-Hartman# SPDX-License-Identifier: GPL-2.0 3dcecc6c7SRandy Dunlap# Disassemble the Code: line in Linux oopses 4dcecc6c7SRandy Dunlap# usage: decodecode < oops.file 5dcecc6c7SRandy Dunlap# 6dcecc6c7SRandy Dunlap# options: set env. variable AFLAGS=options to pass options to "as"; 7dcecc6c7SRandy Dunlap# e.g., to decode an i386 oops on an x86_64 system, use: 8dcecc6c7SRandy Dunlap# AFLAGS=--32 decodecode < 386.oops 9d72e720aSBorislav Petkov# PC=hex - the PC (program counter) the oops points to 10dcecc6c7SRandy Dunlap 11*765f2bf0SBorislav Petkovfaultlinenum=1 12*765f2bf0SBorislav Petkov 13fa220d89SRandy Dunlapcleanup() { 145358db0bSRabin Vincent rm -f $T $T.s $T.o $T.oo $T.aa $T.dis 15fa220d89SRandy Dunlap exit 1 16fa220d89SRandy Dunlap} 17fa220d89SRandy Dunlap 18fa220d89SRandy Dunlapdie() { 19fa220d89SRandy Dunlap echo "$@" 20fa220d89SRandy Dunlap exit 1 21fa220d89SRandy Dunlap} 22fa220d89SRandy Dunlap 23fa220d89SRandy Dunlaptrap cleanup EXIT 24fa220d89SRandy Dunlap 25fa220d89SRandy DunlapT=`mktemp` || die "cannot create temp file" 26dcecc6c7SRandy Dunlapcode= 277e68b361SAndy Shevchenkocont= 28dcecc6c7SRandy Dunlap 29dcecc6c7SRandy Dunlapwhile read i ; do 30dcecc6c7SRandy Dunlap 31dcecc6c7SRandy Dunlapcase "$i" in 32dcecc6c7SRandy Dunlap*Code:*) 33dcecc6c7SRandy Dunlap code=$i 347e68b361SAndy Shevchenko cont=yes 357e68b361SAndy Shevchenko ;; 367e68b361SAndy Shevchenko*) 377e68b361SAndy Shevchenko [ -n "$cont" ] && { 387e68b361SAndy Shevchenko xdump="$(echo $i | grep '^[[:xdigit:]<>[:space:]]\+$')" 397e68b361SAndy Shevchenko if [ -n "$xdump" ]; then 407e68b361SAndy Shevchenko code="$code $xdump" 417e68b361SAndy Shevchenko else 427e68b361SAndy Shevchenko cont= 437e68b361SAndy Shevchenko fi 447e68b361SAndy Shevchenko } 45dcecc6c7SRandy Dunlap ;; 46dcecc6c7SRandy Dunlapesac 47dcecc6c7SRandy Dunlap 48dcecc6c7SRandy Dunlapdone 49dcecc6c7SRandy Dunlap 50dcecc6c7SRandy Dunlapif [ -z "$code" ]; then 51fa220d89SRandy Dunlap rm $T 52dcecc6c7SRandy Dunlap exit 53dcecc6c7SRandy Dunlapfi 54dcecc6c7SRandy Dunlap 55dcecc6c7SRandy Dunlapecho $code 56dcecc6c7SRandy Dunlapcode=`echo $code | sed -e 's/.*Code: //'` 57dcecc6c7SRandy Dunlap 585358db0bSRabin Vincentwidth=`expr index "$code" ' '` 59b396aa03SRabin Vincentwidth=$((($width-1)/2)) 605358db0bSRabin Vincentcase $width in 615358db0bSRabin Vincent1) type=byte ;; 625358db0bSRabin Vincent2) type=2byte ;; 635358db0bSRabin Vincent4) type=4byte ;; 645358db0bSRabin Vincentesac 655358db0bSRabin Vincent 66c5cfb62fSMarc Zyngierif [ -z "$ARCH" ]; then 67c5cfb62fSMarc Zyngier case `uname -m` in 68c5cfb62fSMarc Zyngier aarch64*) ARCH=arm64 ;; 69c5cfb62fSMarc Zyngier arm*) ARCH=arm ;; 70c5cfb62fSMarc Zyngier esac 71c5cfb62fSMarc Zyngierfi 72c5cfb62fSMarc Zyngier 73d72e720aSBorislav Petkov# Params: (tmp_file, pc_sub) 745358db0bSRabin Vincentdisas() { 75d72e720aSBorislav Petkov t=$1 76d72e720aSBorislav Petkov pc_sub=$2 77d72e720aSBorislav Petkov 78d72e720aSBorislav Petkov ${CROSS_COMPILE}as $AFLAGS -o $t.o $t.s > /dev/null 2>&1 795358db0bSRabin Vincent 80b396aa03SRabin Vincent if [ "$ARCH" = "arm" ]; then 81b396aa03SRabin Vincent if [ $width -eq 2 ]; then 825358db0bSRabin Vincent OBJDUMPFLAGS="-M force-thumb" 835358db0bSRabin Vincent fi 845358db0bSRabin Vincent 85d72e720aSBorislav Petkov ${CROSS_COMPILE}strip $t.o 865358db0bSRabin Vincent fi 875358db0bSRabin Vincent 88be9fa663SWill Deacon if [ "$ARCH" = "arm64" ]; then 89be9fa663SWill Deacon if [ $width -eq 4 ]; then 90be9fa663SWill Deacon type=inst 91be9fa663SWill Deacon fi 92be9fa663SWill Deacon 93d72e720aSBorislav Petkov ${CROSS_COMPILE}strip $t.o 94be9fa663SWill Deacon fi 95be9fa663SWill Deacon 96d72e720aSBorislav Petkov if [ $pc_sub -ne 0 ]; then 97d72e720aSBorislav Petkov if [ $PC ]; then 98d72e720aSBorislav Petkov adj_vma=$(( $PC - $pc_sub )) 99d72e720aSBorislav Petkov OBJDUMPFLAGS="$OBJDUMPFLAGS --adjust-vma=$adj_vma" 100d72e720aSBorislav Petkov fi 101d72e720aSBorislav Petkov fi 102d72e720aSBorislav Petkov 103d72e720aSBorislav Petkov ${CROSS_COMPILE}objdump $OBJDUMPFLAGS -S $t.o | \ 104d72e720aSBorislav Petkov grep -v "/tmp\|Disassembly\|\.text\|^$" > $t.dis 2>&1 1055358db0bSRabin Vincent} 1065358db0bSRabin Vincent 107*765f2bf0SBorislav Petkov# Match the maximum number of opcode bytes from @op_bytes contained within 108*765f2bf0SBorislav Petkov# @opline 109*765f2bf0SBorislav Petkov# 110*765f2bf0SBorislav Petkov# Params: 111*765f2bf0SBorislav Petkov# @op_bytes: The string of bytes from the Code: line 112*765f2bf0SBorislav Petkov# @opline: The disassembled line coming from objdump 113*765f2bf0SBorislav Petkov# 114*765f2bf0SBorislav Petkov# Returns: 115*765f2bf0SBorislav Petkov# The max number of opcode bytes from the beginning of @op_bytes which match 116*765f2bf0SBorislav Petkov# the opcode bytes in the objdump line. 117*765f2bf0SBorislav Petkovget_substr_opcode_bytes_num() 118*765f2bf0SBorislav Petkov{ 119*765f2bf0SBorislav Petkov local op_bytes=$1 120*765f2bf0SBorislav Petkov local opline=$2 121*765f2bf0SBorislav Petkov 122*765f2bf0SBorislav Petkov local retval=0 123*765f2bf0SBorislav Petkov substr="" 124*765f2bf0SBorislav Petkov 125*765f2bf0SBorislav Petkov for opc in $op_bytes; 126*765f2bf0SBorislav Petkov do 127*765f2bf0SBorislav Petkov substr+="$opc" 128*765f2bf0SBorislav Petkov 129*765f2bf0SBorislav Petkov # return if opcode bytes do not match @opline anymore 130*765f2bf0SBorislav Petkov if ! echo $opline | grep -q "$substr"; 131*765f2bf0SBorislav Petkov then 132*765f2bf0SBorislav Petkov break 133*765f2bf0SBorislav Petkov fi 134*765f2bf0SBorislav Petkov 135*765f2bf0SBorislav Petkov # add trailing space 136*765f2bf0SBorislav Petkov substr+=" " 137*765f2bf0SBorislav Petkov retval=$((retval+1)) 138*765f2bf0SBorislav Petkov done 139*765f2bf0SBorislav Petkov 140*765f2bf0SBorislav Petkov return $retval 141*765f2bf0SBorislav Petkov} 142*765f2bf0SBorislav Petkov 143*765f2bf0SBorislav Petkov# Return the line number in objdump output to where the IP marker in the Code: 144*765f2bf0SBorislav Petkov# line points to 145*765f2bf0SBorislav Petkov# 146*765f2bf0SBorislav Petkov# Params: 147*765f2bf0SBorislav Petkov# @all_code: code in bytes without the marker 148*765f2bf0SBorislav Petkov# @dis_file: disassembled file 149*765f2bf0SBorislav Petkov# @ip_byte: The byte to which the IP points to 150*765f2bf0SBorislav Petkovget_faultlinenum() 151*765f2bf0SBorislav Petkov{ 152*765f2bf0SBorislav Petkov local all_code="$1" 153*765f2bf0SBorislav Petkov local dis_file="$2" 154*765f2bf0SBorislav Petkov 155*765f2bf0SBorislav Petkov # num bytes including IP byte 156*765f2bf0SBorislav Petkov local num_bytes_ip=$(( $3 + 1 * $width )) 157*765f2bf0SBorislav Petkov 158*765f2bf0SBorislav Petkov # Add the two header lines (we're counting from 1). 159*765f2bf0SBorislav Petkov local retval=3 160*765f2bf0SBorislav Petkov 161*765f2bf0SBorislav Petkov # remove marker 162*765f2bf0SBorislav Petkov all_code=$(echo $all_code | sed -e 's/[<>()]//g') 163*765f2bf0SBorislav Petkov 164*765f2bf0SBorislav Petkov while read line 165*765f2bf0SBorislav Petkov do 166*765f2bf0SBorislav Petkov get_substr_opcode_bytes_num "$all_code" "$line" 167*765f2bf0SBorislav Petkov ate_opcodes=$? 168*765f2bf0SBorislav Petkov 169*765f2bf0SBorislav Petkov if ! (( $ate_opcodes )); then 170*765f2bf0SBorislav Petkov continue 171*765f2bf0SBorislav Petkov fi 172*765f2bf0SBorislav Petkov 173*765f2bf0SBorislav Petkov num_bytes_ip=$((num_bytes_ip - ($ate_opcodes * $width) )) 174*765f2bf0SBorislav Petkov if (( $num_bytes_ip <= 0 )); then 175*765f2bf0SBorislav Petkov break 176*765f2bf0SBorislav Petkov fi 177*765f2bf0SBorislav Petkov 178*765f2bf0SBorislav Petkov # Delete matched opcode bytes from all_code. For that, compute 179*765f2bf0SBorislav Petkov # how many chars those opcodes are represented by and include 180*765f2bf0SBorislav Petkov # trailing space. 181*765f2bf0SBorislav Petkov # 182*765f2bf0SBorislav Petkov # a byte is 2 chars, ate_opcodes is also the number of trailing 183*765f2bf0SBorislav Petkov # spaces 184*765f2bf0SBorislav Petkov del_chars=$(( ($ate_opcodes * $width * 2) + $ate_opcodes )) 185*765f2bf0SBorislav Petkov 186*765f2bf0SBorislav Petkov all_code=$(echo $all_code | sed -e "s!^.\{$del_chars\}!!") 187*765f2bf0SBorislav Petkov 188*765f2bf0SBorislav Petkov let "retval+=1" 189*765f2bf0SBorislav Petkov 190*765f2bf0SBorislav Petkov done < $dis_file 191*765f2bf0SBorislav Petkov 192*765f2bf0SBorislav Petkov return $retval 193*765f2bf0SBorislav Petkov} 194*765f2bf0SBorislav Petkov 195dcecc6c7SRandy Dunlapmarker=`expr index "$code" "\<"` 196dcecc6c7SRandy Dunlapif [ $marker -eq 0 ]; then 197dcecc6c7SRandy Dunlap marker=`expr index "$code" "\("` 198dcecc6c7SRandy Dunlapfi 199dcecc6c7SRandy Dunlap 200846442c8SArjan van de Ventouch $T.oo 201dcecc6c7SRandy Dunlapif [ $marker -ne 0 ]; then 202*765f2bf0SBorislav Petkov # How many bytes to subtract from the program counter 203*765f2bf0SBorislav Petkov # in order to get to the beginning virtual address of the 204*765f2bf0SBorislav Petkov # Code: 205*765f2bf0SBorislav Petkov pc_sub=$(( (($marker - 1) / (2 * $width + 1)) * $width )) 206846442c8SArjan van de Ven echo All code >> $T.oo 207846442c8SArjan van de Ven echo ======== >> $T.oo 208846442c8SArjan van de Ven beforemark=`echo "$code"` 2095358db0bSRabin Vincent echo -n " .$type 0x" > $T.s 210*765f2bf0SBorislav Petkov 2115358db0bSRabin Vincent echo $beforemark | sed -e 's/ /,0x/g; s/[<>()]//g' >> $T.s 212*765f2bf0SBorislav Petkov 213d72e720aSBorislav Petkov disas $T $pc_sub 214*765f2bf0SBorislav Petkov 2155358db0bSRabin Vincent cat $T.dis >> $T.oo 216*765f2bf0SBorislav Petkov 217*765f2bf0SBorislav Petkov get_faultlinenum "$code" "$T.dis" $pc_sub 218*765f2bf0SBorislav Petkov faultlinenum=$? 219dcecc6c7SRandy Dunlap 220dcecc6c7SRandy Dunlap # and fix code at-and-after marker 221dcecc6c7SRandy Dunlap code=`echo "$code" | cut -c$((${marker} + 1))-` 222*765f2bf0SBorislav Petkov 223*765f2bf0SBorislav Petkov rm -f $T.o $T.s $T.dis 224dcecc6c7SRandy Dunlapfi 225*765f2bf0SBorislav Petkov 226846442c8SArjan van de Venecho Code starting with the faulting instruction > $T.aa 227846442c8SArjan van de Venecho =========================================== >> $T.aa 22875e2f715Sweidonghuicode=`echo $code | sed -e 's/\r//;s/ [<(]/ /;s/[>)] / /;s/ /,0x/g; s/[>)]$//'` 2295358db0bSRabin Vincentecho -n " .$type 0x" > $T.s 230dcecc6c7SRandy Dunlapecho $code >> $T.s 231d72e720aSBorislav Petkovdisas $T 0 2325358db0bSRabin Vincentcat $T.dis >> $T.aa 233846442c8SArjan van de Ven 234e08df079SIvan Delalandecat $T.oo | sed -e "${faultlinenum}s/^\([^:]*:\)\(.*\)/\1\*\2\t\t<-- trapping instruction/" 235846442c8SArjan van de Venecho 236846442c8SArjan van de Vencat $T.aa 237846442c8SArjan van de Vencleanup 238