.. | .. |
---|
3 | 3 | # (c) 2014, Sasha Levin <sasha.levin@oracle.com> |
---|
4 | 4 | #set -x |
---|
5 | 5 | |
---|
6 | | -if [[ $# < 2 ]]; then |
---|
| 6 | +if [[ $# < 1 ]]; then |
---|
7 | 7 | echo "Usage:" |
---|
8 | | - echo " $0 [vmlinux] [base path] [modules path]" |
---|
| 8 | + echo " $0 -r <release> | <vmlinux> [base path] [modules path]" |
---|
9 | 9 | exit 1 |
---|
10 | 10 | fi |
---|
11 | 11 | |
---|
12 | | -vmlinux=$1 |
---|
13 | | -basepath=$2 |
---|
14 | | -modpath=$3 |
---|
| 12 | +if [[ $1 == "-r" ]] ; then |
---|
| 13 | + vmlinux="" |
---|
| 14 | + basepath="auto" |
---|
| 15 | + modpath="" |
---|
| 16 | + release=$2 |
---|
| 17 | + |
---|
| 18 | + for fn in {,/usr/lib/debug}/boot/vmlinux-$release{,.debug} /lib/modules/$release{,/build}/vmlinux ; do |
---|
| 19 | + if [ -e "$fn" ] ; then |
---|
| 20 | + vmlinux=$fn |
---|
| 21 | + break |
---|
| 22 | + fi |
---|
| 23 | + done |
---|
| 24 | + |
---|
| 25 | + if [[ $vmlinux == "" ]] ; then |
---|
| 26 | + echo "ERROR! vmlinux image for release $release is not found" >&2 |
---|
| 27 | + exit 2 |
---|
| 28 | + fi |
---|
| 29 | +else |
---|
| 30 | + vmlinux=$1 |
---|
| 31 | + basepath=${2-auto} |
---|
| 32 | + modpath=$3 |
---|
| 33 | + release="" |
---|
| 34 | +fi |
---|
| 35 | + |
---|
15 | 36 | declare -A cache |
---|
16 | 37 | declare -A modcache |
---|
| 38 | + |
---|
| 39 | +find_module() { |
---|
| 40 | + if [[ "$modpath" != "" ]] ; then |
---|
| 41 | + for fn in $(find "$modpath" -name "${module//_/[-_]}.ko*") ; do |
---|
| 42 | + if readelf -WS "$fn" | grep -qwF .debug_line ; then |
---|
| 43 | + echo $fn |
---|
| 44 | + return |
---|
| 45 | + fi |
---|
| 46 | + done |
---|
| 47 | + return 1 |
---|
| 48 | + fi |
---|
| 49 | + |
---|
| 50 | + modpath=$(dirname "$vmlinux") |
---|
| 51 | + find_module && return |
---|
| 52 | + |
---|
| 53 | + if [[ $release == "" ]] ; then |
---|
| 54 | + release=$(gdb -ex 'print init_uts_ns.name.release' -ex 'quit' -quiet -batch "$vmlinux" | sed -n 's/\$1 = "\(.*\)".*/\1/p') |
---|
| 55 | + fi |
---|
| 56 | + |
---|
| 57 | + for dn in {/usr/lib/debug,}/lib/modules/$release ; do |
---|
| 58 | + if [ -e "$dn" ] ; then |
---|
| 59 | + modpath="$dn" |
---|
| 60 | + find_module && return |
---|
| 61 | + fi |
---|
| 62 | + done |
---|
| 63 | + |
---|
| 64 | + modpath="" |
---|
| 65 | + return 1 |
---|
| 66 | +} |
---|
17 | 67 | |
---|
18 | 68 | parse_symbol() { |
---|
19 | 69 | # The structure of symbol at this point is: |
---|
.. | .. |
---|
27 | 77 | elif [[ "${modcache[$module]+isset}" == "isset" ]]; then |
---|
28 | 78 | local objfile=${modcache[$module]} |
---|
29 | 79 | else |
---|
30 | | - [[ $modpath == "" ]] && return |
---|
31 | | - local objfile=$(find "$modpath" -name $module.ko -print -quit) |
---|
32 | | - [[ $objfile == "" ]] && return |
---|
| 80 | + local objfile=$(find_module) |
---|
| 81 | + if [[ $objfile == "" ]] ; then |
---|
| 82 | + echo "WARNING! Modules path isn't set, but is needed to parse this symbol" >&2 |
---|
| 83 | + return |
---|
| 84 | + fi |
---|
33 | 85 | modcache[$module]=$objfile |
---|
34 | 86 | fi |
---|
35 | 87 | |
---|
36 | 88 | # Remove the englobing parenthesis |
---|
37 | 89 | symbol=${symbol#\(} |
---|
38 | 90 | symbol=${symbol%\)} |
---|
| 91 | + |
---|
| 92 | + # Strip segment |
---|
| 93 | + local segment |
---|
| 94 | + if [[ $symbol == *:* ]] ; then |
---|
| 95 | + segment=${symbol%%:*}: |
---|
| 96 | + symbol=${symbol#*:} |
---|
| 97 | + fi |
---|
39 | 98 | |
---|
40 | 99 | # Strip the symbol name so that we could look it up |
---|
41 | 100 | local name=${symbol%+*} |
---|
.. | .. |
---|
46 | 105 | if [[ "${cache[$module,$name]+isset}" == "isset" ]]; then |
---|
47 | 106 | local base_addr=${cache[$module,$name]} |
---|
48 | 107 | else |
---|
49 | | - local base_addr=$(nm "$objfile" | grep -i ' t ' | awk "/ $name\$/ {print \$1}" | head -n1) |
---|
| 108 | + local base_addr=$(nm "$objfile" | awk '$3 == "'$name'" && ($2 == "t" || $2 == "T") {print $1; exit}') |
---|
| 109 | + if [[ $base_addr == "" ]] ; then |
---|
| 110 | + # address not found |
---|
| 111 | + return |
---|
| 112 | + fi |
---|
50 | 113 | cache[$module,$name]="$base_addr" |
---|
51 | 114 | fi |
---|
52 | 115 | # Let's start doing the math to get the exact address into the |
---|
.. | .. |
---|
84 | 147 | code=${code//$'\n'/' '} |
---|
85 | 148 | |
---|
86 | 149 | # Replace old address with pretty line numbers |
---|
87 | | - symbol="$name ($code)" |
---|
| 150 | + symbol="$segment$name ($code)" |
---|
88 | 151 | } |
---|
89 | 152 | |
---|
90 | 153 | decode_code() { |
---|
.. | .. |
---|
138 | 201 | echo "${words[@]}" "$symbol $module" |
---|
139 | 202 | } |
---|
140 | 203 | |
---|
| 204 | +if [[ $basepath == "auto" ]] ; then |
---|
| 205 | + module="" |
---|
| 206 | + symbol="kernel_init+0x0/0x0" |
---|
| 207 | + parse_symbol |
---|
| 208 | + basepath=${symbol#kernel_init (} |
---|
| 209 | + basepath=${basepath%/init/main.c:*)} |
---|
| 210 | +fi |
---|
| 211 | + |
---|
141 | 212 | while read line; do |
---|
142 | 213 | # Let's see if we have an address in the line |
---|
143 | 214 | if [[ $line =~ \[\<([^]]+)\>\] ]] || |
---|