Try to find module in directory with vmlinux (for fresh build).
Then try standard paths where debuginfo are usually placed.
Pick first file which have elf section '.debug_line'.

Before:

$ echo 'tap_open+0x0/0x0 [tap]' |
  ./scripts/decode_stacktrace.sh /usr/lib/debug/boot/vmlinux-5.4.0-37-generic
WARNING! Modules path isn't set, but is needed to parse this symbol
tap_open+0x0/0x0 tap

After:

$ echo 'tap_open+0x0/0x0 [tap]' |
  ./scripts/decode_stacktrace.sh /usr/lib/debug/boot/vmlinux-5.4.0-37-generic
tap_open (drivers/net/tap.c:502) tap

Signed-off-by: Konstantin Khlebnikov <khlebni...@yandex-team.ru>
---
 scripts/decode_stacktrace.sh |   36 +++++++++++++++++++++++++++++++++---
 1 file changed, 33 insertions(+), 3 deletions(-)

diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh
index b1b85a7b2115..7f18ac10af03 100755
--- a/scripts/decode_stacktrace.sh
+++ b/scripts/decode_stacktrace.sh
@@ -12,9 +12,40 @@ fi
 vmlinux=$1
 basepath=${2-auto}
 modpath=$3
+release=""
+
 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 +58,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
 

Reply via email to