Merge tag 'kvm-s390-master-6.1-2' of https://git.kernel.org/pub/scm/linux/kernel...
[platform/kernel/linux-starfive.git] / scripts / decodecode
index c711a19..b28fd26 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 # SPDX-License-Identifier: GPL-2.0
 # Disassemble the Code: line in Linux oopses
 # usage: decodecode < oops.file
@@ -8,6 +8,8 @@
 # AFLAGS=--32 decodecode < 386.oops
 # PC=hex - the PC (program counter) the oops points to
 
+faultlinenum=1
+
 cleanup() {
        rm -f $T $T.s $T.o $T.oo $T.aa $T.dis
        exit 1
@@ -102,28 +104,125 @@ disas() {
                grep -v "/tmp\|Disassembly\|\.text\|^$" > $t.dis 2>&1
 }
 
+# Match the maximum number of opcode bytes from @op_bytes contained within
+# @opline
+#
+# Params:
+# @op_bytes: The string of bytes from the Code: line
+# @opline: The disassembled line coming from objdump
+#
+# Returns:
+# The max number of opcode bytes from the beginning of @op_bytes which match
+# the opcode bytes in the objdump line.
+get_substr_opcode_bytes_num()
+{
+       local op_bytes=$1
+       local opline=$2
+
+       local retval=0
+       substr=""
+
+       for opc in $op_bytes;
+       do
+               substr+="$opc"
+
+               # return if opcode bytes do not match @opline anymore
+               if ! echo $opline | grep -q "$substr";
+               then
+                       break
+               fi
+
+               # add trailing space
+               substr+=" "
+               retval=$((retval+1))
+       done
+
+       return $retval
+}
+
+# Return the line number in objdump output to where the IP marker in the Code:
+# line points to
+#
+# Params:
+# @all_code: code in bytes without the marker
+# @dis_file: disassembled file
+# @ip_byte: The byte to which the IP points to
+get_faultlinenum()
+{
+       local all_code="$1"
+       local dis_file="$2"
+
+       # num bytes including IP byte
+       local num_bytes_ip=$(( $3 + 1 * $width ))
+
+       # Add the two header lines (we're counting from 1).
+       local retval=3
+
+       # remove marker
+       all_code=$(echo $all_code | sed -e 's/[<>()]//g')
+
+       while read line
+       do
+               get_substr_opcode_bytes_num "$all_code" "$line"
+               ate_opcodes=$?
+
+               if ! (( $ate_opcodes )); then
+                       continue
+               fi
+
+               num_bytes_ip=$((num_bytes_ip - ($ate_opcodes * $width) ))
+               if (( $num_bytes_ip <= 0 )); then
+                       break
+               fi
+
+               # Delete matched opcode bytes from all_code. For that, compute
+               # how many chars those opcodes are represented by and include
+               # trailing space.
+               #
+               # a byte is 2 chars, ate_opcodes is also the number of trailing
+               # spaces
+               del_chars=$(( ($ate_opcodes * $width * 2) + $ate_opcodes ))
+
+               all_code=$(echo $all_code | sed -e "s!^.\{$del_chars\}!!")
+
+               let "retval+=1"
+
+       done < $dis_file
+
+       return $retval
+}
+
 marker=`expr index "$code" "\<"`
 if [ $marker -eq 0 ]; then
        marker=`expr index "$code" "\("`
 fi
 
-
 touch $T.oo
 if [ $marker -ne 0 ]; then
-       # 2 opcode bytes and a single space
-       pc_sub=$(( $marker / 3 ))
+       # How many bytes to subtract from the program counter
+       # in order to get to the beginning virtual address of the
+       # Code:
+       pc_sub=$(( (($marker - 1) / (2 * $width + 1)) * $width ))
        echo All code >> $T.oo
        echo ======== >> $T.oo
        beforemark=`echo "$code"`
        echo -n "       .$type 0x" > $T.s
+
        echo $beforemark | sed -e 's/ /,0x/g; s/[<>()]//g' >> $T.s
+
        disas $T $pc_sub
+
        cat $T.dis >> $T.oo
-       rm -f $T.o $T.s $T.dis
 
-# and fix code at-and-after marker
+       get_faultlinenum "$code" "$T.dis" $pc_sub
+       faultlinenum=$?
+
+       # and fix code at-and-after marker
        code=`echo "$code" | cut -c$((${marker} + 1))-`
+
+       rm -f $T.o $T.s $T.dis
 fi
+
 echo Code starting with the faulting instruction  > $T.aa
 echo =========================================== >> $T.aa
 code=`echo $code | sed -e 's/\r//;s/ [<(]/ /;s/[>)] / /;s/ /,0x/g; s/[>)]$//'`
@@ -132,15 +231,6 @@ echo $code >> $T.s
 disas $T 0
 cat $T.dis >> $T.aa
 
-# (lines of whole $T.oo) - (lines of $T.aa, i.e. "Code starting") + 3,
-# i.e. the title + the "===..=" line (sed is counting from 1, 0 address is
-# special)
-faultlinenum=$(( $(wc -l $T.oo  | cut -d" " -f1) - \
-                $(wc -l $T.aa  | cut -d" " -f1) + 3))
-
-faultline=`cat $T.dis | head -1 | cut -d":" -f2-`
-faultline=`echo "$faultline" | sed -e 's/\[/\\\[/g; s/\]/\\\]/g'`
-
 cat $T.oo | sed -e "${faultlinenum}s/^\([^:]*:\)\(.*\)/\1\*\2\t\t<-- trapping instruction/"
 echo
 cat $T.aa