From f643b9ee97766e1846fab237c58a56277bf7e530 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Thu, 6 Aug 2020 23:17:35 -0700 Subject: scripts/decode_stacktrace.sh: skip missing symbols For now script turns missing symbols into '0' and make bogus decode. Skip them instead. Also simplify parsing output of 'nm'. Before: $ echo 'xxx+0x0/0x0' | ./scripts/decode_stacktrace.sh vmlinux "" xxx (home/khlebnikov/src/linux/./arch/x86/include/asm/processor.h:398) After: $ echo 'xxx+0x0/0x0' | ./scripts/decode_stacktrace.sh vmlinux "" xxx+0x0/0x0 Signed-off-by: Konstantin Khlebnikov Signed-off-by: Andrew Morton Cc: Sasha Levin Link: http://lkml.kernel.org/r/159282922499.248444.4883465570858385250.stgit@buzz Signed-off-by: Linus Torvalds --- scripts/decode_stacktrace.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'scripts/decode_stacktrace.sh') diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh index 0869def435ee..b157037af6df 100755 --- a/scripts/decode_stacktrace.sh +++ b/scripts/decode_stacktrace.sh @@ -56,7 +56,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 -- cgit From ecda6e27fa834b2aa37fc9ad49f89b80e9ee8f97 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Thu, 6 Aug 2020 23:17:38 -0700 Subject: scripts/decode_stacktrace.sh: guess basepath if not specified Guess path to kernel sources using known location of symbol "kernel_init". Make basepath argument optional. Before: $ echo 'vfs_open+0x0/0x0' | ./scripts/decode_stacktrace.sh vmlinux "" vfs_open (home/khlebnikov/src/linux/fs/open.c:912) After: $ echo 'vfs_open+0x0/0x0' | ./scripts/decode_stacktrace.sh vmlinux vfs_open (fs/open.c:912) Signed-off-by: Konstantin Khlebnikov Signed-off-by: Andrew Morton Cc: Sasha Levin Link: http://lkml.kernel.org/r/159282922803.248444.2379229451667913634.stgit@buzz Signed-off-by: Linus Torvalds --- scripts/decode_stacktrace.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'scripts/decode_stacktrace.sh') diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh index b157037af6df..62a70ede7f3e 100755 --- a/scripts/decode_stacktrace.sh +++ b/scripts/decode_stacktrace.sh @@ -3,14 +3,14 @@ # (c) 2014, Sasha Levin #set -x -if [[ $# < 2 ]]; then +if [[ $# < 1 ]]; then echo "Usage:" - echo " $0 [vmlinux] [base path] [modules path]" + echo " $0 [base path] [modules path]" exit 1 fi vmlinux=$1 -basepath=$2 +basepath=${2-auto} modpath=$3 declare -A cache declare -A modcache @@ -152,6 +152,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 =~ \[\<([^]]+)\>\] ]] || -- cgit From 431151b64af6c8ebec85ee1db3597b56a613f526 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Thu, 6 Aug 2020 23:17:41 -0700 Subject: scripts/decode_stacktrace.sh: guess path to modules 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 Signed-off-by: Andrew Morton Cc: Sasha Levin Link: http://lkml.kernel.org/r/159282923068.248444.5461337458421616083.stgit@buzz Signed-off-by: Linus Torvalds --- scripts/decode_stacktrace.sh | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) (limited to 'scripts/decode_stacktrace.sh') diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh index 62a70ede7f3e..e31e253fe5bd 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 -- cgit From f90dde44c57a1cf338ae01a691110eb980e48563 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Thu, 6 Aug 2020 23:17:43 -0700 Subject: scripts/decode_stacktrace.sh: guess path to vmlinux by release name Add option decode_stacktrace -r to specify only release name. This is enough to guess standard paths to vmlinux and modules: $ echo -e 'schedule+0x0/0x0 tap_open+0x0/0x0 [tap]' | ./scripts/decode_stacktrace.sh -r 5.4.0-37-generic schedule (kernel/sched/core.c:4138) tap_open (drivers/net/tap.c:502) tap Signed-off-by: Konstantin Khlebnikov Signed-off-by: Andrew Morton Cc: Sasha Levin Link: http://lkml.kernel.org/r/159282923334.248444.2399153100007347838.stgit@buzz Signed-off-by: Linus Torvalds --- scripts/decode_stacktrace.sh | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'scripts/decode_stacktrace.sh') diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh index e31e253fe5bd..90398347e366 100755 --- a/scripts/decode_stacktrace.sh +++ b/scripts/decode_stacktrace.sh @@ -5,14 +5,33 @@ if [[ $# < 1 ]]; then echo "Usage:" - echo " $0 [base path] [modules path]" + echo " $0 -r | [base path] [modules path]" exit 1 fi -vmlinux=$1 -basepath=${2-auto} -modpath=$3 -release="" +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 -- cgit