Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/scripts/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 8 kB image not shown  

Quelle  decode_stacktrace.sh   Sprache: Shell

 
#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-2.0
# (c) 2014, Sasha Levin <sasha.levin@oracle.com>
#set -x

usage() {
 echo "Usage:"
 echo " $0 -r "
 echo " $0 [ [|auto []]]"
 echo " $0 -h"
}

# Try to find a Rust demangler
if type llvm-cxxfilt >/dev/null 2>&1 ; then
 cppfilt=llvm-cxxfilt
elif type c++filt >/dev/null 2>&1 ; then
 cppfilt=c++filt
 cppfilt_opts=-i
fi

UTIL_SUFFIX=
if [[ -z ${LLVM:-} ]]; then
 UTIL_PREFIX=${CROSS_COMPILE:-}
else
 UTIL_PREFIX=llvm-
 if [[ ${LLVM} == */ ]]; then
  UTIL_PREFIX=${LLVM}${UTIL_PREFIX}
 elif [[ ${LLVM} == -* ]]; then
  UTIL_SUFFIX=${LLVM}
 fi
fi

READELF=${UTIL_PREFIX}readelf${UTIL_SUFFIX}
ADDR2LINE=${UTIL_PREFIX}addr2line${UTIL_SUFFIX}
NM=${UTIL_PREFIX}nm${UTIL_SUFFIX}

if [[ $1 == "-h" ]] ; then
 usage
 exit 0
elif [[ $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
  usage
  exit 2
 fi
else
 vmlinux=$1
 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 aarray_support=true
declare -A cache 2>/dev/null
if [[ $? != 0 ]]; then
 aarray_support=false
else
 declare -A modcache
fi

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 [ -z $release ] ; then
  release=$(gdb -ex 'print init_uts_ns.name.release' -ex 'quit' -quiet -batch "$vmlinux" 2>/dev/null | sed -n 's/\$1 = "\(.*\)".*/\1/p')
 fi
 if [ -n "${release}" ] ; then
  release_dirs="/usr/lib/debug/lib/modules/$release /lib/modules/$release"
 fi

 found_without_debug_info=false
 for dir in "$modpath" "$(dirname "$vmlinux")" ${release_dirs}; do
  if [ -n "${dir}" ] && [ -e "${dir}" ]; then
   for fn in $(find "$dir" -name "${module//_/[-_]}.ko*") ; do
    if ${READELF} -WS "$fn" | grep -qwF .debug_line ; then
     echo $fn
     return
    fi
    found_without_debug_info=true
   done
  fi
 done

 if [[ ${found_without_debug_info} == true ]]; then
  echo "WARNING! No debugging info in module ${module}, rebuild with DEBUG_KERNEL and DEBUG_INFO" >&2
 else
  echo "WARNING! Cannot find .ko for module ${module}, please pass a valid module path" >&2
 fi

 return 1
}

parse_symbol() {
 # The structure of symbol at this point is:
 #   ([name]+[offset]/[total length])
 #
 # For example:
 #   do_basic_setup+0x9c/0xbf

 if [[ $module == "" ]] ; then
  local objfile=$vmlinux
 elif [[ $aarray_support == true && "${modcache[$module]+isset}" == "isset" ]]; then
  local objfile=${modcache[$module]}
 else
  local objfile=$(find_module)
  if [[ $objfile == "" ]] ; then
   return
  fi
  if [[ $aarray_support == true ]]; then
   modcache[$module]=$objfile
  fi
 fi

 # Remove the englobing parenthesis
 symbol=${symbol#\(}
 symbol=${symbol%\)}

 # Strip segment
 local segment
 if [[ $symbol == *:* ]] ; then
  segment=${symbol%%:*}:
  symbol=${symbol#*:}
 fi

 # Strip the symbol name so that we could look it up
 local name=${symbol%+*}

 # Use 'nm vmlinux' to figure out the base address of said symbol.
 # It's actually faster to call it every time than to load it
 # all into bash.
 if [[ $aarray_support == true && "${cache[$module,$name]+isset}" == "isset" ]]; then
  local base_addr=${cache[$module,$name]}
 else
  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
  fi
  if [[ $aarray_support == true ]]; then
   cache[$module,$name]="$base_addr"
  fi
 fi
 # Let's start doing the math to get the exact address into the
 # symbol. First, strip out the symbol total length.
 local expr=${symbol%/*}

 # 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))
 local address=$(printf "%x\n" "$expr")

 # Pass it to addr2line to get filename and line number
 # Could get more than one result
 if [[ $aarray_support == true && "${cache[$module,$address]+isset}" == "isset" ]]; then
  local code=${cache[$module,$address]}
 else
  local code=$(${ADDR2LINE} -i -e "$objfile" "$address" 2>/dev/null)
  if [[ $aarray_support == true ]]; then
   cache[$module,$address]=$code
  fi
 fi

 # addr2line doesn't return a proper error code if it fails, so
 # we detect it using the value it prints so that we could preserve
 # the offset/size into the function and bail out
 if [[ $code == "??:0" ]]; then
  return
 fi

 # Strip out the base of the path on each line
 code=$(while read -r line; do echo "${line#$basepath/}"; done <<< "$code")

 # In the case of inlines, move everything to same line
 code=${code//$'\n'/' '}

 # Demangle if the name looks like a Rust symbol and if
 # we got a Rust demangler
 if [[ $name =~ ^_R && $cppfilt != "" ]] ; then
  name=$("$cppfilt" "$cppfilt_opts" "$name")
 fi

 # Replace old address with pretty line numbers
 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]}"`

 echo "$1" | $scripts/decodecode
}

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 spaces

 # 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

 # We need to know the index of the last element before we
 # remove elements because arrays are sparse
 local last=$(( ${#words[@]} - 1 ))

 for i in "${!words[@]}"do
  # Remove the address
  if [[ ${words[$i]} =~ \[\<([^]]+)\>\] ]]; then
   unset words[$i] spaces[$i]
  fi
 done

 # Extract info after the symbol if present. E.g.:
 # func_name+0x54/0x80 (P)
 #                     ^^^
 # The regex assumes only uppercase letters will be used. To be
 # extended if needed.
 local info_str=""
 if [[ ${words[$last]} =~ \([A-Z]*\) ]]; then
  info_str=${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

 if [[ ${words[$last]} =~ \[([^]]+)\] ]]; then
  module=${words[$last]}
  # some traces format is "(%pS)", which like "(foo+0x0/0x1 [bar])"
  # so $module may like "[bar])". Strip the right parenthesis firstly
  module=${module%\)}
  module=${module#\[}
  module=${module%\]}
  modbuildid=${module#* }
  module=${module% *}
  if [[ $modbuildid == $module ]]; then
   modbuildid=
  fi
  symbol=${words[$last-1]}
  unset words[$last-1] spaces[$last-1]
 else
  # The symbol is the last element, process it
  symbol=${words[$last]}
  module=
  modbuildid=
 fi

 unset words[$last]
 parse_symbol # modifies $symbol

 # Add up the line number to the symbol
 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
 # Strip unexpected carriage return at end of line
 line=${line%$'\r'}

 # Let's see if we have an address in the line
 if [[ $line =~ \[\<([^]]+)\>\] ]] ||
    [[ $line =~ [^+\ ]+\+0x[0-9a-f]+/0x[0-9a-f]+ ]]; then
  # Translate address to line numbers
  handle_line "$line"
 # 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"
 fi
done

92%


¤ Dauer der Verarbeitung: 0.40 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.