0001
0002
0003
0004
0005
0006 usage() {
0007 echo "Usage:"
0008 echo " $0 -r <release> | <vmlinux> [<base path>|auto] [<modules path>]"
0009 }
0010
0011 if [[ $1 == "-r" ]] ; then
0012 vmlinux=""
0013 basepath="auto"
0014 modpath=""
0015 release=$2
0016
0017 for fn in {,/usr/lib/debug}/boot/vmlinux-$release{,.debug} /lib/modules/$release{,/build}/vmlinux ; do
0018 if [ -e "$fn" ] ; then
0019 vmlinux=$fn
0020 break
0021 fi
0022 done
0023
0024 if [[ $vmlinux == "" ]] ; then
0025 echo "ERROR! vmlinux image for release $release is not found" >&2
0026 usage
0027 exit 2
0028 fi
0029 else
0030 vmlinux=$1
0031 basepath=${2-auto}
0032 modpath=$3
0033 release=""
0034 debuginfod=
0035
0036
0037 if type debuginfod-find >/dev/null 2>&1 ; then
0038 debuginfod=${1-only}
0039 fi
0040
0041 if [[ $vmlinux == "" && -z $debuginfod ]] ; then
0042 echo "ERROR! vmlinux image must be specified" >&2
0043 usage
0044 exit 1
0045 fi
0046 fi
0047
0048 declare aarray_support=true
0049 declare -A cache 2>/dev/null
0050 if [[ $? != 0 ]]; then
0051 aarray_support=false
0052 else
0053 declare -A modcache
0054 fi
0055
0056 find_module() {
0057 if [[ -n $debuginfod ]] ; then
0058 if [[ -n $modbuildid ]] ; then
0059 debuginfod-find debuginfo $modbuildid && return
0060 fi
0061
0062
0063 if [[ $debuginfod == "only" ]] ; then
0064 return
0065 fi
0066 fi
0067
0068 if [[ "$modpath" != "" ]] ; then
0069 for fn in $(find "$modpath" -name "${module//_/[-_]}.ko*") ; do
0070 if readelf -WS "$fn" | grep -qwF .debug_line ; then
0071 echo $fn
0072 return
0073 fi
0074 done
0075 return 1
0076 fi
0077
0078 modpath=$(dirname "$vmlinux")
0079 find_module && return
0080
0081 if [[ $release == "" ]] ; then
0082 release=$(gdb -ex 'print init_uts_ns.name.release' -ex 'quit' -quiet -batch "$vmlinux" 2>/dev/null | sed -n 's/\$1 = "\(.*\)".*/\1/p')
0083 fi
0084
0085 for dn in {/usr/lib/debug,}/lib/modules/$release ; do
0086 if [ -e "$dn" ] ; then
0087 modpath="$dn"
0088 find_module && return
0089 fi
0090 done
0091
0092 modpath=""
0093 return 1
0094 }
0095
0096 parse_symbol() {
0097
0098
0099
0100
0101
0102
0103 if [[ $module == "" ]] ; then
0104 local objfile=$vmlinux
0105 elif [[ $aarray_support == true && "${modcache[$module]+isset}" == "isset" ]]; then
0106 local objfile=${modcache[$module]}
0107 else
0108 local objfile=$(find_module)
0109 if [[ $objfile == "" ]] ; then
0110 echo "WARNING! Modules path isn't set, but is needed to parse this symbol" >&2
0111 return
0112 fi
0113 if [[ $aarray_support == true ]]; then
0114 modcache[$module]=$objfile
0115 fi
0116 fi
0117
0118
0119 symbol=${symbol
0120 symbol=${symbol%\)}
0121
0122
0123 local segment
0124 if [[ $symbol == *:* ]] ; then
0125 segment=${symbol%%:*}:
0126 symbol=${symbol
0127 fi
0128
0129
0130 local name=${symbol%+*}
0131
0132
0133
0134
0135 if [[ $aarray_support == true && "${cache[$module,$name]+isset}" == "isset" ]]; then
0136 local base_addr=${cache[$module,$name]}
0137 else
0138 local base_addr=$(nm "$objfile" 2>/dev/null | awk '$3 == "'$name'" && ($2 == "t" || $2 == "T") {print $1; exit}')
0139 if [[ $base_addr == "" ]] ; then
0140
0141 return
0142 fi
0143 if [[ $aarray_support == true ]]; then
0144 cache[$module,$name]="$base_addr"
0145 fi
0146 fi
0147
0148
0149 local expr=${symbol%/*}
0150
0151
0152
0153 expr=${expr/$name/0x$base_addr}
0154
0155
0156 expr=$((expr))
0157 local address=$(printf "%x\n" "$expr")
0158
0159
0160
0161 if [[ $aarray_support == true && "${cache[$module,$address]+isset}" == "isset" ]]; then
0162 local code=${cache[$module,$address]}
0163 else
0164 local code=$(${CROSS_COMPILE}addr2line -i -e "$objfile" "$address" 2>/dev/null)
0165 if [[ $aarray_support == true ]]; then
0166 cache[$module,$address]=$code
0167 fi
0168 fi
0169
0170
0171
0172
0173 if [[ $code == "??:0" ]]; then
0174 return
0175 fi
0176
0177
0178 code=$(while read -r line; do echo "${line#$basepath/}"; done <<< "$code")
0179
0180
0181 code=${code//$'\n'/' '}
0182
0183
0184 symbol="$segment$name ($code)"
0185 }
0186
0187 debuginfod_get_vmlinux() {
0188 local vmlinux_buildid=${1
0189
0190 if [[ $vmlinux != "" ]]; then
0191 return
0192 fi
0193
0194 if [[ $vmlinux_buildid =~ ^[0-9a-f]+ ]]; then
0195 vmlinux=$(debuginfod-find debuginfo $vmlinux_buildid)
0196 if [[ $? -ne 0 ]] ; then
0197 echo "ERROR! vmlinux image not found via debuginfod-find" >&2
0198 usage
0199 exit 2
0200 fi
0201 return
0202 fi
0203 echo "ERROR! Build ID for vmlinux not found. Try passing -r or specifying vmlinux" >&2
0204 usage
0205 exit 2
0206 }
0207
0208 decode_code() {
0209 local scripts=`dirname "${BASH_SOURCE[0]}"`
0210
0211 echo "$1" | $scripts/decodecode
0212 }
0213
0214 handle_line() {
0215 if [[ $basepath == "auto" && $vmlinux != "" ]] ; then
0216 module=""
0217 symbol="kernel_init+0x0/0x0"
0218 parse_symbol
0219 basepath=${symbol
0220 basepath=${basepath%/init/main.c:*)}
0221 fi
0222
0223 local words
0224
0225
0226 read -a words <<<"$1"
0227
0228
0229
0230
0231
0232
0233 local last=$(( ${
0234
0235 for i in "${!words[@]}"; do
0236
0237 if [[ ${words[$i]} =~ \[\<([^]]+)\>\] ]]; then
0238 unset words[$i]
0239 fi
0240
0241
0242 if [[ ${words[$i]} == \[ && ${words[$i+1]} == *\] ]]; then
0243 unset words[$i]
0244 words[$i+1]=$(printf "[%13s\n" "${words[$i+1]}")
0245 fi
0246 done
0247
0248 if [[ ${words[$last]} =~ ^[0-9a-f]+\] ]]; then
0249 words[$last-1]="${words[$last-1]} ${words[$last]}"
0250 unset words[$last]
0251 last=$(( $last - 1 ))
0252 fi
0253
0254 if [[ ${words[$last]} =~ \[([^]]+)\] ]]; then
0255 module=${words[$last]}
0256 module=${module
0257 module=${module%\]}
0258 modbuildid=${module
0259 module=${module% *}
0260 if [[ $modbuildid == $module ]]; then
0261 modbuildid=
0262 fi
0263 symbol=${words[$last-1]}
0264 unset words[$last-1]
0265 else
0266
0267 symbol=${words[$last]}
0268 module=
0269 modbuildid=
0270 fi
0271
0272 unset words[$last]
0273 parse_symbol
0274
0275
0276 echo "${words[@]}" "$symbol $module"
0277 }
0278
0279 while read line; do
0280
0281 if [[ $line =~ \[\<([^]]+)\>\] ]] ||
0282 [[ $line =~ [^+\ ]+\+0x[0-9a-f]+/0x[0-9a-f]+ ]]; then
0283
0284 handle_line "$line"
0285
0286 elif [[ $line == *Code:* ]]; then
0287 decode_code "$line"
0288
0289 elif [[ -n $debuginfod && $line =~ PID:\ [0-9]+\ Comm: ]]; then
0290 debuginfod_get_vmlinux "$line"
0291 else
0292
0293 echo "$line"
0294 fi
0295 done