Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[linux-2.6-microblaze.git] / scripts / decode_stacktrace.sh
index 0869def..9039834 100755 (executable)
@@ -3,18 +3,68 @@
 # (c) 2014, Sasha Levin <sasha.levin@oracle.com>
 #set -x
 
-if [[ $# < 2 ]]; then
+if [[ $# < 1 ]]; then
        echo "Usage:"
-       echo "  $0 [vmlinux] [base path] [modules path]"
+       echo "  $0 -r <release> | <vmlinux> [base path] [modules path]"
        exit 1
 fi
 
-vmlinux=$1
-basepath=$2
-modpath=$3
+if [[ $1 == "-r" ]] ; then
+       vmlinux=""
+       basepath="auto"
+       modpath=""
+       release=$2
+
+       for fn in {,/usr/lib/debug}/boot/vmlinux-$release{,.debug} /lib/modules/$release{,/build}/vmlinux ; do
+               if [ -e "$fn" ] ; then
+                       vmlinux=$fn
+                       break
+               fi
+       done
+
+       if [[ $vmlinux == "" ]] ; then
+               echo "ERROR! vmlinux image for release $release is not found" >&2
+               exit 2
+       fi
+else
+       vmlinux=$1
+       basepath=${2-auto}
+       modpath=$3
+       release=""
+fi
+
 declare -A cache
 declare -A modcache
 
+find_module() {
+       if [[ "$modpath" != "" ]] ; then
+               for fn in $(find "$modpath" -name "${module//_/[-_]}.ko*") ; do
+                       if readelf -WS "$fn" | grep -qwF .debug_line ; then
+                               echo $fn
+                               return
+                       fi
+               done
+               return 1
+       fi
+
+       modpath=$(dirname "$vmlinux")
+       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')
+       fi
+
+       for dn in {/usr/lib/debug,}/lib/modules/$release ; do
+               if [ -e "$dn" ] ; then
+                       modpath="$dn"
+                       find_module && return
+               fi
+       done
+
+       modpath=""
+       return 1
+}
+
 parse_symbol() {
        # The structure of symbol at this point is:
        #   ([name]+[offset]/[total length])
@@ -27,12 +77,11 @@ parse_symbol() {
        elif [[ "${modcache[$module]+isset}" == "isset" ]]; then
                local objfile=${modcache[$module]}
        else
-               if [[ $modpath == "" ]]; then
+               local objfile=$(find_module)
+               if [[ $objfile == "" ]] ; then
                        echo "WARNING! Modules path isn't set, but is needed to parse this symbol" >&2
                        return
                fi
-               local objfile=$(find "$modpath" -name "${module//_/[-_]}.ko*" -print -quit)
-               [[ $objfile == "" ]] && return
                modcache[$module]=$objfile
        fi
 
@@ -56,7 +105,11 @@ parse_symbol() {
        if [[ "${cache[$module,$name]+isset}" == "isset" ]]; then
                local base_addr=${cache[$module,$name]}
        else
-               local base_addr=$(nm "$objfile" | grep -i ' t ' | awk "/ $name\$/ {print \$1}" | head -n1)
+               local base_addr=$(nm "$objfile" | awk '$3 == "'$name'" && ($2 == "t" || $2 == "T") {print $1; exit}')
+               if [[ $base_addr == "" ]] ; then
+                       # address not found
+                       return
+               fi
                cache[$module,$name]="$base_addr"
        fi
        # Let's start doing the math to get the exact address into the
@@ -148,6 +201,14 @@ 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 =~ \[\<([^]]+)\>\] ]] ||