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 ;; 70*d738bcedSYouling Tang loongarch*) ARCH=loongarch ;; 71c5cfb62fSMarc Zyngier esac 72c5cfb62fSMarc Zyngierfi 73c5cfb62fSMarc Zyngier 74d72e720aSBorislav Petkov# Params: (tmp_file, pc_sub) 755358db0bSRabin Vincentdisas() { 76d72e720aSBorislav Petkov t=$1 77d72e720aSBorislav Petkov pc_sub=$2 78d72e720aSBorislav Petkov 79d72e720aSBorislav Petkov ${CROSS_COMPILE}as $AFLAGS -o $t.o $t.s > /dev/null 2>&1 805358db0bSRabin Vincent 81b396aa03SRabin Vincent if [ "$ARCH" = "arm" ]; then 82b396aa03SRabin Vincent if [ $width -eq 2 ]; then 835358db0bSRabin Vincent OBJDUMPFLAGS="-M force-thumb" 845358db0bSRabin Vincent fi 855358db0bSRabin Vincent 86d72e720aSBorislav Petkov ${CROSS_COMPILE}strip $t.o 875358db0bSRabin Vincent fi 885358db0bSRabin Vincent 89be9fa663SWill Deacon if [ "$ARCH" = "arm64" ]; then 90be9fa663SWill Deacon if [ $width -eq 4 ]; then 91be9fa663SWill Deacon type=inst 92be9fa663SWill Deacon fi 93be9fa663SWill Deacon 94d72e720aSBorislav Petkov ${CROSS_COMPILE}strip $t.o 95be9fa663SWill Deacon fi 96be9fa663SWill Deacon 9700b24250SBjörn Töpel if [ "$ARCH" = "riscv" ]; then 9800b24250SBjörn Töpel OBJDUMPFLAGS="-M no-aliases --section=.text -D" 9900b24250SBjörn Töpel ${CROSS_COMPILE}strip $t.o 10000b24250SBjörn Töpel fi 10100b24250SBjörn Töpel 102*d738bcedSYouling Tang if [ "$ARCH" = "loongarch" ]; then 103*d738bcedSYouling Tang ${CROSS_COMPILE}strip $t.o 104*d738bcedSYouling Tang fi 105*d738bcedSYouling Tang 106d72e720aSBorislav Petkov if [ $pc_sub -ne 0 ]; then 107d72e720aSBorislav Petkov if [ $PC ]; then 108d72e720aSBorislav Petkov adj_vma=$(( $PC - $pc_sub )) 109d72e720aSBorislav Petkov OBJDUMPFLAGS="$OBJDUMPFLAGS --adjust-vma=$adj_vma" 110d72e720aSBorislav Petkov fi 111d72e720aSBorislav Petkov fi 112d72e720aSBorislav Petkov 113d72e720aSBorislav Petkov ${CROSS_COMPILE}objdump $OBJDUMPFLAGS -S $t.o | \ 114d72e720aSBorislav Petkov grep -v "/tmp\|Disassembly\|\.text\|^$" > $t.dis 2>&1 1155358db0bSRabin Vincent} 1165358db0bSRabin Vincent 117765f2bf0SBorislav Petkov# Match the maximum number of opcode bytes from @op_bytes contained within 118765f2bf0SBorislav Petkov# @opline 119765f2bf0SBorislav Petkov# 120765f2bf0SBorislav Petkov# Params: 121765f2bf0SBorislav Petkov# @op_bytes: The string of bytes from the Code: line 122765f2bf0SBorislav Petkov# @opline: The disassembled line coming from objdump 123765f2bf0SBorislav Petkov# 124765f2bf0SBorislav Petkov# Returns: 125765f2bf0SBorislav Petkov# The max number of opcode bytes from the beginning of @op_bytes which match 126765f2bf0SBorislav Petkov# the opcode bytes in the objdump line. 127765f2bf0SBorislav Petkovget_substr_opcode_bytes_num() 128765f2bf0SBorislav Petkov{ 129765f2bf0SBorislav Petkov local op_bytes=$1 130765f2bf0SBorislav Petkov local opline=$2 131765f2bf0SBorislav Petkov 132765f2bf0SBorislav Petkov local retval=0 133765f2bf0SBorislav Petkov substr="" 134765f2bf0SBorislav Petkov 135765f2bf0SBorislav Petkov for opc in $op_bytes; 136765f2bf0SBorislav Petkov do 137765f2bf0SBorislav Petkov substr+="$opc" 138765f2bf0SBorislav Petkov 13900b24250SBjörn Töpel opcode="$substr" 14000b24250SBjörn Töpel if [ "$ARCH" = "riscv" ]; then 14100b24250SBjörn Töpel opcode=$(echo $opcode | tr ' ' '\n' | tac | tr -d '\n') 14200b24250SBjörn Töpel fi 14300b24250SBjörn Töpel 144765f2bf0SBorislav Petkov # return if opcode bytes do not match @opline anymore 14500b24250SBjörn Töpel if ! echo $opline | grep -q "$opcode"; 146765f2bf0SBorislav Petkov then 147765f2bf0SBorislav Petkov break 148765f2bf0SBorislav Petkov fi 149765f2bf0SBorislav Petkov 150765f2bf0SBorislav Petkov # add trailing space 151765f2bf0SBorislav Petkov substr+=" " 152765f2bf0SBorislav Petkov retval=$((retval+1)) 153765f2bf0SBorislav Petkov done 154765f2bf0SBorislav Petkov 155765f2bf0SBorislav Petkov return $retval 156765f2bf0SBorislav Petkov} 157765f2bf0SBorislav Petkov 158765f2bf0SBorislav Petkov# Return the line number in objdump output to where the IP marker in the Code: 159765f2bf0SBorislav Petkov# line points to 160765f2bf0SBorislav Petkov# 161765f2bf0SBorislav Petkov# Params: 162765f2bf0SBorislav Petkov# @all_code: code in bytes without the marker 163765f2bf0SBorislav Petkov# @dis_file: disassembled file 164765f2bf0SBorislav Petkov# @ip_byte: The byte to which the IP points to 165765f2bf0SBorislav Petkovget_faultlinenum() 166765f2bf0SBorislav Petkov{ 167765f2bf0SBorislav Petkov local all_code="$1" 168765f2bf0SBorislav Petkov local dis_file="$2" 169765f2bf0SBorislav Petkov 170765f2bf0SBorislav Petkov # num bytes including IP byte 171765f2bf0SBorislav Petkov local num_bytes_ip=$(( $3 + 1 * $width )) 172765f2bf0SBorislav Petkov 173765f2bf0SBorislav Petkov # Add the two header lines (we're counting from 1). 174765f2bf0SBorislav Petkov local retval=3 175765f2bf0SBorislav Petkov 176765f2bf0SBorislav Petkov # remove marker 177765f2bf0SBorislav Petkov all_code=$(echo $all_code | sed -e 's/[<>()]//g') 178765f2bf0SBorislav Petkov 179765f2bf0SBorislav Petkov while read line 180765f2bf0SBorislav Petkov do 181765f2bf0SBorislav Petkov get_substr_opcode_bytes_num "$all_code" "$line" 182765f2bf0SBorislav Petkov ate_opcodes=$? 183765f2bf0SBorislav Petkov 184765f2bf0SBorislav Petkov if ! (( $ate_opcodes )); then 185765f2bf0SBorislav Petkov continue 186765f2bf0SBorislav Petkov fi 187765f2bf0SBorislav Petkov 188765f2bf0SBorislav Petkov num_bytes_ip=$((num_bytes_ip - ($ate_opcodes * $width) )) 189765f2bf0SBorislav Petkov if (( $num_bytes_ip <= 0 )); then 190765f2bf0SBorislav Petkov break 191765f2bf0SBorislav Petkov fi 192765f2bf0SBorislav Petkov 193765f2bf0SBorislav Petkov # Delete matched opcode bytes from all_code. For that, compute 194765f2bf0SBorislav Petkov # how many chars those opcodes are represented by and include 195765f2bf0SBorislav Petkov # trailing space. 196765f2bf0SBorislav Petkov # 197765f2bf0SBorislav Petkov # a byte is 2 chars, ate_opcodes is also the number of trailing 198765f2bf0SBorislav Petkov # spaces 199765f2bf0SBorislav Petkov del_chars=$(( ($ate_opcodes * $width * 2) + $ate_opcodes )) 200765f2bf0SBorislav Petkov 201765f2bf0SBorislav Petkov all_code=$(echo $all_code | sed -e "s!^.\{$del_chars\}!!") 202765f2bf0SBorislav Petkov 203765f2bf0SBorislav Petkov let "retval+=1" 204765f2bf0SBorislav Petkov 205765f2bf0SBorislav Petkov done < $dis_file 206765f2bf0SBorislav Petkov 207765f2bf0SBorislav Petkov return $retval 208765f2bf0SBorislav Petkov} 209765f2bf0SBorislav Petkov 210dcecc6c7SRandy Dunlapmarker=`expr index "$code" "\<"` 211dcecc6c7SRandy Dunlapif [ $marker -eq 0 ]; then 212dcecc6c7SRandy Dunlap marker=`expr index "$code" "\("` 213dcecc6c7SRandy Dunlapfi 214dcecc6c7SRandy Dunlap 215846442c8SArjan van de Ventouch $T.oo 216dcecc6c7SRandy Dunlapif [ $marker -ne 0 ]; then 217765f2bf0SBorislav Petkov # How many bytes to subtract from the program counter 218765f2bf0SBorislav Petkov # in order to get to the beginning virtual address of the 219765f2bf0SBorislav Petkov # Code: 220765f2bf0SBorislav Petkov pc_sub=$(( (($marker - 1) / (2 * $width + 1)) * $width )) 221846442c8SArjan van de Ven echo All code >> $T.oo 222846442c8SArjan van de Ven echo ======== >> $T.oo 223846442c8SArjan van de Ven beforemark=`echo "$code"` 2245358db0bSRabin Vincent echo -n " .$type 0x" > $T.s 225765f2bf0SBorislav Petkov 2265358db0bSRabin Vincent echo $beforemark | sed -e 's/ /,0x/g; s/[<>()]//g' >> $T.s 227765f2bf0SBorislav Petkov 228d72e720aSBorislav Petkov disas $T $pc_sub 229765f2bf0SBorislav Petkov 2305358db0bSRabin Vincent cat $T.dis >> $T.oo 231765f2bf0SBorislav Petkov 232765f2bf0SBorislav Petkov get_faultlinenum "$code" "$T.dis" $pc_sub 233765f2bf0SBorislav Petkov faultlinenum=$? 234dcecc6c7SRandy Dunlap 235dcecc6c7SRandy Dunlap # and fix code at-and-after marker 236dcecc6c7SRandy Dunlap code=`echo "$code" | cut -c$((${marker} + 1))-` 237765f2bf0SBorislav Petkov 238765f2bf0SBorislav Petkov rm -f $T.o $T.s $T.dis 239dcecc6c7SRandy Dunlapfi 240765f2bf0SBorislav Petkov 241846442c8SArjan van de Venecho Code starting with the faulting instruction > $T.aa 242846442c8SArjan van de Venecho =========================================== >> $T.aa 24375e2f715Sweidonghuicode=`echo $code | sed -e 's/\r//;s/ [<(]/ /;s/[>)] / /;s/ /,0x/g; s/[>)]$//'` 2445358db0bSRabin Vincentecho -n " .$type 0x" > $T.s 245dcecc6c7SRandy Dunlapecho $code >> $T.s 246d72e720aSBorislav Petkovdisas $T 0 2475358db0bSRabin Vincentcat $T.dis >> $T.aa 248846442c8SArjan van de Ven 249e08df079SIvan Delalandecat $T.oo | sed -e "${faultlinenum}s/^\([^:]*:\)\(.*\)/\1\*\2\t\t<-- trapping instruction/" 250846442c8SArjan van de Venecho 251846442c8SArjan van de Vencat $T.aa 252846442c8SArjan van de Vencleanup 253