1765f2bf0SBorislav 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 11765f2bf0SBorislav Petkovfaultlinenum=1 12765f2bf0SBorislav 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 96*00b24250SBjörn Töpel if [ "$ARCH" = "riscv" ]; then 97*00b24250SBjörn Töpel OBJDUMPFLAGS="-M no-aliases --section=.text -D" 98*00b24250SBjörn Töpel ${CROSS_COMPILE}strip $t.o 99*00b24250SBjörn Töpel fi 100*00b24250SBjörn Töpel 101d72e720aSBorislav Petkov if [ $pc_sub -ne 0 ]; then 102d72e720aSBorislav Petkov if [ $PC ]; then 103d72e720aSBorislav Petkov adj_vma=$(( $PC - $pc_sub )) 104d72e720aSBorislav Petkov OBJDUMPFLAGS="$OBJDUMPFLAGS --adjust-vma=$adj_vma" 105d72e720aSBorislav Petkov fi 106d72e720aSBorislav Petkov fi 107d72e720aSBorislav Petkov 108d72e720aSBorislav Petkov ${CROSS_COMPILE}objdump $OBJDUMPFLAGS -S $t.o | \ 109d72e720aSBorislav Petkov grep -v "/tmp\|Disassembly\|\.text\|^$" > $t.dis 2>&1 1105358db0bSRabin Vincent} 1115358db0bSRabin Vincent 112765f2bf0SBorislav Petkov# Match the maximum number of opcode bytes from @op_bytes contained within 113765f2bf0SBorislav Petkov# @opline 114765f2bf0SBorislav Petkov# 115765f2bf0SBorislav Petkov# Params: 116765f2bf0SBorislav Petkov# @op_bytes: The string of bytes from the Code: line 117765f2bf0SBorislav Petkov# @opline: The disassembled line coming from objdump 118765f2bf0SBorislav Petkov# 119765f2bf0SBorislav Petkov# Returns: 120765f2bf0SBorislav Petkov# The max number of opcode bytes from the beginning of @op_bytes which match 121765f2bf0SBorislav Petkov# the opcode bytes in the objdump line. 122765f2bf0SBorislav Petkovget_substr_opcode_bytes_num() 123765f2bf0SBorislav Petkov{ 124765f2bf0SBorislav Petkov local op_bytes=$1 125765f2bf0SBorislav Petkov local opline=$2 126765f2bf0SBorislav Petkov 127765f2bf0SBorislav Petkov local retval=0 128765f2bf0SBorislav Petkov substr="" 129765f2bf0SBorislav Petkov 130765f2bf0SBorislav Petkov for opc in $op_bytes; 131765f2bf0SBorislav Petkov do 132765f2bf0SBorislav Petkov substr+="$opc" 133765f2bf0SBorislav Petkov 134*00b24250SBjörn Töpel opcode="$substr" 135*00b24250SBjörn Töpel if [ "$ARCH" = "riscv" ]; then 136*00b24250SBjörn Töpel opcode=$(echo $opcode | tr ' ' '\n' | tac | tr -d '\n') 137*00b24250SBjörn Töpel fi 138*00b24250SBjörn Töpel 139765f2bf0SBorislav Petkov # return if opcode bytes do not match @opline anymore 140*00b24250SBjörn Töpel if ! echo $opline | grep -q "$opcode"; 141765f2bf0SBorislav Petkov then 142765f2bf0SBorislav Petkov break 143765f2bf0SBorislav Petkov fi 144765f2bf0SBorislav Petkov 145765f2bf0SBorislav Petkov # add trailing space 146765f2bf0SBorislav Petkov substr+=" " 147765f2bf0SBorislav Petkov retval=$((retval+1)) 148765f2bf0SBorislav Petkov done 149765f2bf0SBorislav Petkov 150765f2bf0SBorislav Petkov return $retval 151765f2bf0SBorislav Petkov} 152765f2bf0SBorislav Petkov 153765f2bf0SBorislav Petkov# Return the line number in objdump output to where the IP marker in the Code: 154765f2bf0SBorislav Petkov# line points to 155765f2bf0SBorislav Petkov# 156765f2bf0SBorislav Petkov# Params: 157765f2bf0SBorislav Petkov# @all_code: code in bytes without the marker 158765f2bf0SBorislav Petkov# @dis_file: disassembled file 159765f2bf0SBorislav Petkov# @ip_byte: The byte to which the IP points to 160765f2bf0SBorislav Petkovget_faultlinenum() 161765f2bf0SBorislav Petkov{ 162765f2bf0SBorislav Petkov local all_code="$1" 163765f2bf0SBorislav Petkov local dis_file="$2" 164765f2bf0SBorislav Petkov 165765f2bf0SBorislav Petkov # num bytes including IP byte 166765f2bf0SBorislav Petkov local num_bytes_ip=$(( $3 + 1 * $width )) 167765f2bf0SBorislav Petkov 168765f2bf0SBorislav Petkov # Add the two header lines (we're counting from 1). 169765f2bf0SBorislav Petkov local retval=3 170765f2bf0SBorislav Petkov 171765f2bf0SBorislav Petkov # remove marker 172765f2bf0SBorislav Petkov all_code=$(echo $all_code | sed -e 's/[<>()]//g') 173765f2bf0SBorislav Petkov 174765f2bf0SBorislav Petkov while read line 175765f2bf0SBorislav Petkov do 176765f2bf0SBorislav Petkov get_substr_opcode_bytes_num "$all_code" "$line" 177765f2bf0SBorislav Petkov ate_opcodes=$? 178765f2bf0SBorislav Petkov 179765f2bf0SBorislav Petkov if ! (( $ate_opcodes )); then 180765f2bf0SBorislav Petkov continue 181765f2bf0SBorislav Petkov fi 182765f2bf0SBorislav Petkov 183765f2bf0SBorislav Petkov num_bytes_ip=$((num_bytes_ip - ($ate_opcodes * $width) )) 184765f2bf0SBorislav Petkov if (( $num_bytes_ip <= 0 )); then 185765f2bf0SBorislav Petkov break 186765f2bf0SBorislav Petkov fi 187765f2bf0SBorislav Petkov 188765f2bf0SBorislav Petkov # Delete matched opcode bytes from all_code. For that, compute 189765f2bf0SBorislav Petkov # how many chars those opcodes are represented by and include 190765f2bf0SBorislav Petkov # trailing space. 191765f2bf0SBorislav Petkov # 192765f2bf0SBorislav Petkov # a byte is 2 chars, ate_opcodes is also the number of trailing 193765f2bf0SBorislav Petkov # spaces 194765f2bf0SBorislav Petkov del_chars=$(( ($ate_opcodes * $width * 2) + $ate_opcodes )) 195765f2bf0SBorislav Petkov 196765f2bf0SBorislav Petkov all_code=$(echo $all_code | sed -e "s!^.\{$del_chars\}!!") 197765f2bf0SBorislav Petkov 198765f2bf0SBorislav Petkov let "retval+=1" 199765f2bf0SBorislav Petkov 200765f2bf0SBorislav Petkov done < $dis_file 201765f2bf0SBorislav Petkov 202765f2bf0SBorislav Petkov return $retval 203765f2bf0SBorislav Petkov} 204765f2bf0SBorislav Petkov 205dcecc6c7SRandy Dunlapmarker=`expr index "$code" "\<"` 206dcecc6c7SRandy Dunlapif [ $marker -eq 0 ]; then 207dcecc6c7SRandy Dunlap marker=`expr index "$code" "\("` 208dcecc6c7SRandy Dunlapfi 209dcecc6c7SRandy Dunlap 210846442c8SArjan van de Ventouch $T.oo 211dcecc6c7SRandy Dunlapif [ $marker -ne 0 ]; then 212765f2bf0SBorislav Petkov # How many bytes to subtract from the program counter 213765f2bf0SBorislav Petkov # in order to get to the beginning virtual address of the 214765f2bf0SBorislav Petkov # Code: 215765f2bf0SBorislav Petkov pc_sub=$(( (($marker - 1) / (2 * $width + 1)) * $width )) 216846442c8SArjan van de Ven echo All code >> $T.oo 217846442c8SArjan van de Ven echo ======== >> $T.oo 218846442c8SArjan van de Ven beforemark=`echo "$code"` 2195358db0bSRabin Vincent echo -n " .$type 0x" > $T.s 220765f2bf0SBorislav Petkov 2215358db0bSRabin Vincent echo $beforemark | sed -e 's/ /,0x/g; s/[<>()]//g' >> $T.s 222765f2bf0SBorislav Petkov 223d72e720aSBorislav Petkov disas $T $pc_sub 224765f2bf0SBorislav Petkov 2255358db0bSRabin Vincent cat $T.dis >> $T.oo 226765f2bf0SBorislav Petkov 227765f2bf0SBorislav Petkov get_faultlinenum "$code" "$T.dis" $pc_sub 228765f2bf0SBorislav Petkov faultlinenum=$? 229dcecc6c7SRandy Dunlap 230dcecc6c7SRandy Dunlap # and fix code at-and-after marker 231dcecc6c7SRandy Dunlap code=`echo "$code" | cut -c$((${marker} + 1))-` 232765f2bf0SBorislav Petkov 233765f2bf0SBorislav Petkov rm -f $T.o $T.s $T.dis 234dcecc6c7SRandy Dunlapfi 235765f2bf0SBorislav Petkov 236846442c8SArjan van de Venecho Code starting with the faulting instruction > $T.aa 237846442c8SArjan van de Venecho =========================================== >> $T.aa 23875e2f715Sweidonghuicode=`echo $code | sed -e 's/\r//;s/ [<(]/ /;s/[>)] / /;s/ /,0x/g; s/[>)]$//'` 2395358db0bSRabin Vincentecho -n " .$type 0x" > $T.s 240dcecc6c7SRandy Dunlapecho $code >> $T.s 241d72e720aSBorislav Petkovdisas $T 0 2425358db0bSRabin Vincentcat $T.dis >> $T.aa 243846442c8SArjan van de Ven 244e08df079SIvan Delalandecat $T.oo | sed -e "${faultlinenum}s/^\([^:]*:\)\(.*\)/\1\*\2\t\t<-- trapping instruction/" 245846442c8SArjan van de Venecho 246846442c8SArjan van de Vencat $T.aa 247846442c8SArjan van de Vencleanup 248