summaryrefslogtreecommitdiff
path: root/scripts/decode_stacktrace.sh
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/decode_stacktrace.sh')
-rwxr-xr-xscripts/decode_stacktrace.sh73
1 files changed, 44 insertions, 29 deletions
diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh
index 17abc4e7a985..39d60d477bf3 100755
--- a/scripts/decode_stacktrace.sh
+++ b/scripts/decode_stacktrace.sh
@@ -5,9 +5,11 @@
usage() {
echo "Usage:"
- echo " $0 -r <release>"
- echo " $0 [<vmlinux> [<base_path>|auto [<modules_path>]]]"
+ echo " $0 [-R] -r <release>"
+ echo " $0 [-R] [<vmlinux> [<base_path>|auto [<modules_path>]]]"
echo " $0 -h"
+ echo "Options:"
+ echo " -R: decode return address instead of caller address."
}
# Try to find a Rust demangler
@@ -33,11 +35,17 @@ fi
READELF=${UTIL_PREFIX}readelf${UTIL_SUFFIX}
ADDR2LINE=${UTIL_PREFIX}addr2line${UTIL_SUFFIX}
NM=${UTIL_PREFIX}nm${UTIL_SUFFIX}
+decode_retaddr=false
if [[ $1 == "-h" ]] ; then
usage
exit 0
-elif [[ $1 == "-r" ]] ; then
+elif [[ $1 == "-R" ]] ; then
+ decode_retaddr=true
+ shift 1
+fi
+
+if [[ $1 == "-r" ]] ; then
vmlinux=""
basepath="auto"
modpath=""
@@ -176,13 +184,23 @@ parse_symbol() {
# Let's start doing the math to get the exact address into the
# symbol. First, strip out the symbol total length.
local expr=${symbol%/*}
+ # Also parse the offset from symbol.
+ local offset=${expr#*+}
+ offset=$((offset))
# Now, replace the symbol name with the base address we found
# before.
expr=${expr/$name/0x$base_addr}
# Evaluate it to find the actual address
- expr=$((expr))
+ # The stack trace shows the return address, which is the next
+ # instruction after the actual call, so as long as it's in the same
+ # symbol, subtract one from that to point the call instruction.
+ if [[ $decode_retaddr == false && $offset != 0 ]]; then
+ expr=$((expr-1))
+ else
+ expr=$((expr))
+ fi
local address=$(printf "%x\n" "$expr")
# Pass it to addr2line to get filename and line number
@@ -242,8 +260,10 @@ debuginfod_get_vmlinux() {
decode_code() {
local scripts=`dirname "${BASH_SOURCE[0]}"`
+ local lim="Code: "
- echo "$1" | $scripts/decodecode
+ echo -n "${1%%${lim}*}"
+ echo "${lim}${1##*${lim}}" | $scripts/decodecode
}
handle_line() {
@@ -255,10 +275,11 @@ handle_line() {
basepath=${basepath%/init/main.c:*)}
fi
- local words
+ local words spaces
- # Tokenize
- read -a words <<<"$1"
+ # Tokenize: words and spaces to preserve the alignment
+ read -ra words <<<"$1"
+ IFS='#' read -ra spaces <<<"$(shopt -s extglob; echo "${1//+([^[:space:]])/#}")"
# Remove hex numbers. Do it ourselves until it happens in the
# kernel
@@ -270,22 +291,10 @@ handle_line() {
for i in "${!words[@]}"; do
# Remove the address
if [[ ${words[$i]} =~ \[\<([^]]+)\>\] ]]; then
- unset words[$i]
- fi
-
- # Format timestamps with tabs
- if [[ ${words[$i]} == \[ && ${words[$i+1]} == *\] ]]; then
- unset words[$i]
- words[$i+1]=$(printf "[%13s\n" "${words[$i+1]}")
+ unset words[$i] spaces[$i]
fi
done
- if [[ ${words[$last]} =~ ^[0-9a-f]+\] ]]; then
- words[$last-1]="${words[$last-1]} ${words[$last]}"
- unset words[$last]
- last=$(( $last - 1 ))
- fi
-
# Extract info after the symbol if present. E.g.:
# func_name+0x54/0x80 (P)
# ^^^
@@ -294,7 +303,15 @@ handle_line() {
local info_str=""
if [[ ${words[$last]} =~ \([A-Z]*\) ]]; then
info_str=${words[$last]}
- unset words[$last]
+ unset words[$last] spaces[$last]
+ last=$(( $last - 1 ))
+ fi
+
+ # Join module name with its build id if present, as these were
+ # split during tokenization (e.g. "[module" and "modbuildid]").
+ if [[ ${words[$last]} =~ ^[0-9a-f]+\] ]]; then
+ words[$last-1]="${words[$last-1]} ${words[$last]}"
+ unset words[$last] spaces[$last]
last=$(( $last - 1 ))
fi
@@ -311,7 +328,7 @@ handle_line() {
modbuildid=
fi
symbol=${words[$last-1]}
- unset words[$last-1]
+ unset words[$last-1] spaces[$last-1]
else
# The symbol is the last element, process it
symbol=${words[$last]}
@@ -323,12 +340,10 @@ handle_line() {
parse_symbol # modifies $symbol
# Add up the line number to the symbol
- if [[ -z ${module} ]]
- then
- echo "${words[@]}" "$symbol ${info_str}"
- else
- echo "${words[@]}" "$symbol $module ${info_str}"
- fi
+ for i in "${!words[@]}"; do
+ echo -n "${spaces[i]}${words[i]}"
+ done
+ echo "${spaces[$last]}${symbol}${module:+ ${module}}${info_str:+ ${info_str}}"
}
while read line; do