Merge tag 'pinctrl-v5.14-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
[linux-2.6-microblaze.git] / scripts / decode_stacktrace.sh
index 9039834..5fbad61 100755 (executable)
@@ -3,11 +3,10 @@
 # (c) 2014, Sasha Levin <sasha.levin@oracle.com>
 #set -x
 
-if [[ $# < 1 ]]; then
+usage() {
        echo "Usage:"
-       echo "  $0 -r <release> | <vmlinux> [base path] [modules path]"
-       exit 1
-fi
+       echo "  $0 -r <release> | <vmlinux> [<base path>|auto] [<modules path>]"
+}
 
 if [[ $1 == "-r" ]] ; then
        vmlinux=""
@@ -24,6 +23,7 @@ if [[ $1 == "-r" ]] ; then
 
        if [[ $vmlinux == "" ]] ; then
                echo "ERROR! vmlinux image for release $release is not found" >&2
+               usage
                exit 2
        fi
 else
@@ -31,12 +31,35 @@ else
        basepath=${2-auto}
        modpath=$3
        release=""
+       debuginfod=
+
+       # Can we use debuginfod-find?
+       if type debuginfod-find >/dev/null 2>&1 ; then
+               debuginfod=${1-only}
+       fi
+
+       if [[ $vmlinux == "" && -z $debuginfod ]] ; then
+               echo "ERROR! vmlinux image must be specified" >&2
+               usage
+               exit 1
+       fi
 fi
 
 declare -A cache
 declare -A modcache
 
 find_module() {
+       if [[ -n $debuginfod ]] ; then
+               if [[ -n $modbuildid ]] ; then
+                       debuginfod-find debuginfo $modbuildid && return
+               fi
+
+               # Only using debuginfod so don't try to find vmlinux module path
+               if [[ $debuginfod == "only" ]] ; then
+                       return
+               fi
+       fi
+
        if [[ "$modpath" != "" ]] ; then
                for fn in $(find "$modpath" -name "${module//_/[-_]}.ko*") ; do
                        if readelf -WS "$fn" | grep -qwF .debug_line ; then
@@ -51,7 +74,7 @@ find_module() {
        find_module && return
 
        if [[ $release == "" ]] ; then
-               release=$(gdb -ex 'print init_uts_ns.name.release' -ex 'quit' -quiet -batch "$vmlinux" | sed -n 's/\$1 = "\(.*\)".*/\1/p')
+               release=$(gdb -ex 'print init_uts_ns.name.release' -ex 'quit' -quiet -batch "$vmlinux" 2>/dev/null | sed -n 's/\$1 = "\(.*\)".*/\1/p')
        fi
 
        for dn in {/usr/lib/debug,}/lib/modules/$release ; do
@@ -105,7 +128,7 @@ parse_symbol() {
        if [[ "${cache[$module,$name]+isset}" == "isset" ]]; then
                local base_addr=${cache[$module,$name]}
        else
-               local base_addr=$(nm "$objfile" | awk '$3 == "'$name'" && ($2 == "t" || $2 == "T") {print $1; exit}')
+               local base_addr=$(nm "$objfile" 2>/dev/null | awk '$3 == "'$name'" && ($2 == "t" || $2 == "T") {print $1; exit}')
                if [[ $base_addr == "" ]] ; then
                        # address not found
                        return
@@ -129,7 +152,7 @@ parse_symbol() {
        if [[ "${cache[$module,$address]+isset}" == "isset" ]]; then
                local code=${cache[$module,$address]}
        else
-               local code=$(${CROSS_COMPILE}addr2line -i -e "$objfile" "$address")
+               local code=$(${CROSS_COMPILE}addr2line -i -e "$objfile" "$address" 2>/dev/null)
                cache[$module,$address]=$code
        fi
 
@@ -150,6 +173,27 @@ parse_symbol() {
        symbol="$segment$name ($code)"
 }
 
+debuginfod_get_vmlinux() {
+       local vmlinux_buildid=${1##* }
+
+       if [[ $vmlinux != "" ]]; then
+               return
+       fi
+
+       if [[ $vmlinux_buildid =~ ^[0-9a-f]+ ]]; then
+               vmlinux=$(debuginfod-find debuginfo $vmlinux_buildid)
+               if [[ $? -ne 0 ]] ; then
+                       echo "ERROR! vmlinux image not found via debuginfod-find" >&2
+                       usage
+                       exit 2
+               fi
+               return
+       fi
+       echo "ERROR! Build ID for vmlinux not found. Try passing -r or specifying vmlinux" >&2
+       usage
+       exit 2
+}
+
 decode_code() {
        local scripts=`dirname "${BASH_SOURCE[0]}"`
 
@@ -157,6 +201,14 @@ decode_code() {
 }
 
 handle_line() {
+       if [[ $basepath == "auto" && $vmlinux != "" ]] ; then
+               module=""
+               symbol="kernel_init+0x0/0x0"
+               parse_symbol
+               basepath=${symbol#kernel_init (}
+               basepath=${basepath%/init/main.c:*)}
+       fi
+
        local words
 
        # Tokenize
@@ -182,16 +234,28 @@ handle_line() {
                fi
        done
 
+       if [[ ${words[$last]} =~ ^[0-9a-f]+\] ]]; then
+               words[$last-1]="${words[$last-1]} ${words[$last]}"
+               unset words[$last]
+               last=$(( $last - 1 ))
+       fi
+
        if [[ ${words[$last]} =~ \[([^]]+)\] ]]; then
                module=${words[$last]}
                module=${module#\[}
                module=${module%\]}
+               modbuildid=${module#* }
+               module=${module% *}
+               if [[ $modbuildid == $module ]]; then
+                       modbuildid=
+               fi
                symbol=${words[$last-1]}
                unset words[$last-1]
        else
                # The symbol is the last element, process it
                symbol=${words[$last]}
                module=
+               modbuildid=
        fi
 
        unset words[$last]
@@ -201,14 +265,6 @@ handle_line() {
        echo "${words[@]}" "$symbol $module"
 }
 
-if [[ $basepath == "auto" ]] ; then
-       module=""
-       symbol="kernel_init+0x0/0x0"
-       parse_symbol
-       basepath=${symbol#kernel_init (}
-       basepath=${basepath%/init/main.c:*)}
-fi
-
 while read line; do
        # Let's see if we have an address in the line
        if [[ $line =~ \[\<([^]]+)\>\] ]] ||
@@ -218,6 +274,9 @@ while read line; do
        # Is it a code line?
        elif [[ $line == *Code:* ]]; then
                decode_code "$line"
+       # Is it a version line?
+       elif [[ -n $debuginfod && $line =~ PID:\ [0-9]+\ Comm: ]]; then
+               debuginfod_get_vmlinux "$line"
        else
                # Nothing special in this line, show it as is
                echo "$line"