aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/faddr2line
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@redhat.com>2016-10-25 10:51:11 -0400
committerIngo Molnar <mingo@kernel.org>2016-10-25 12:40:37 -0400
commitefdb4167e676aaba7505bec739785b76e206cb45 (patch)
tree3901f1f610162898d2d5dad52f01818bf060a1af /scripts/faddr2line
parent5e25d5bdf6d407224ad185a3fb8b870ad7d6c627 (diff)
scripts/faddr2line: Fix "size mismatch" error
I'm not sure how we missed this problem before. When I take a function address and size from an oops and give it to faddr2line, it usually complains about a size mismatch: $ scripts/faddr2line ~/k/vmlinux write_sysrq_trigger+0x51/0x60 skipping write_sysrq_trigger address at 0xffffffff815731a1 due to size mismatch (0x60 != 83) no match for write_sysrq_trigger+0x51/0x60 The problem is caused by differences in how kallsyms and faddr2line determine a function's size. kallsyms calculates a function's size by parsing the output of 'nm -n' and subtracting the next function's address from the current function's address. This means that nop instructions after the end of the function are included in the size. In contrast, faddr2line reads the size from the symbol table, which does *not* include the ending nops in the function's size. Change faddr2line to calculate the size from the output of 'nm -n' to be consistent with kallsyms and oops outputs. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Andy Lutomirski <luto@kernel.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/bd313ed7c4003f6b1fda63e825325c44a9d837de.1477405374.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'scripts/faddr2line')
-rwxr-xr-xscripts/faddr2line33
1 files changed, 21 insertions, 12 deletions
diff --git a/scripts/faddr2line b/scripts/faddr2line
index 450b33257339..29df825d375c 100755
--- a/scripts/faddr2line
+++ b/scripts/faddr2line
@@ -105,9 +105,18 @@ __faddr2line() {
105 # In rare cases there might be duplicates. 105 # In rare cases there might be duplicates.
106 while read symbol; do 106 while read symbol; do
107 local fields=($symbol) 107 local fields=($symbol)
108 local sym_base=0x${fields[1]} 108 local sym_base=0x${fields[0]}
109 local sym_size=${fields[2]} 109 local sym_type=${fields[1]}
110 local sym_type=${fields[3]} 110 local sym_end=0x${fields[3]}
111
112 # calculate the size
113 local sym_size=$(($sym_end - $sym_base))
114 if [[ -z $sym_size ]] || [[ $sym_size -le 0 ]]; then
115 warn "bad symbol size: base: $sym_base end: $sym_end"
116 DONE=1
117 return
118 fi
119 sym_size=0x$(printf %x $sym_size)
111 120
112 # calculate the address 121 # calculate the address
113 local addr=$(($sym_base + $offset)) 122 local addr=$(($sym_base + $offset))
@@ -116,26 +125,26 @@ __faddr2line() {
116 DONE=1 125 DONE=1
117 return 126 return
118 fi 127 fi
119 local hexaddr=0x$(printf %x $addr) 128 addr=0x$(printf %x $addr)
120 129
121 # weed out non-function symbols 130 # weed out non-function symbols
122 if [[ $sym_type != "FUNC" ]]; then 131 if [[ $sym_type != t ]] && [[ $sym_type != T ]]; then
123 [[ $print_warnings = 1 ]] && 132 [[ $print_warnings = 1 ]] &&
124 echo "skipping $func address at $hexaddr due to non-function symbol" 133 echo "skipping $func address at $addr due to non-function symbol of type '$sym_type'"
125 continue 134 continue
126 fi 135 fi
127 136
128 # if the user provided a size, make sure it matches the symbol's size 137 # if the user provided a size, make sure it matches the symbol's size
129 if [[ -n $size ]] && [[ $size -ne $sym_size ]]; then 138 if [[ -n $size ]] && [[ $size -ne $sym_size ]]; then
130 [[ $print_warnings = 1 ]] && 139 [[ $print_warnings = 1 ]] &&
131 echo "skipping $func address at $hexaddr due to size mismatch ($size != $sym_size)" 140 echo "skipping $func address at $addr due to size mismatch ($size != $sym_size)"
132 continue; 141 continue;
133 fi 142 fi
134 143
135 # make sure the provided offset is within the symbol's range 144 # make sure the provided offset is within the symbol's range
136 if [[ $offset -gt $sym_size ]]; then 145 if [[ $offset -gt $sym_size ]]; then
137 [[ $print_warnings = 1 ]] && 146 [[ $print_warnings = 1 ]] &&
138 echo "skipping $func address at $hexaddr due to size mismatch ($offset > $sym_size)" 147 echo "skipping $func address at $addr due to size mismatch ($offset > $sym_size)"
139 continue 148 continue
140 fi 149 fi
141 150
@@ -143,12 +152,12 @@ __faddr2line() {
143 [[ $FIRST = 0 ]] && echo 152 [[ $FIRST = 0 ]] && echo
144 FIRST=0 153 FIRST=0
145 154
146 local hexsize=0x$(printf %x $sym_size) 155 # pass real address to addr2line
147 echo "$func+$offset/$hexsize:" 156 echo "$func+$offset/$sym_size:"
148 addr2line -fpie $objfile $hexaddr | sed "s; $dir_prefix\(\./\)*; ;" 157 addr2line -fpie $objfile $addr | sed "s; $dir_prefix\(\./\)*; ;"
149 DONE=1 158 DONE=1
150 159
151 done < <(readelf -sW $objfile | awk -v f=$func '$8 == f {print}') 160 done < <(nm -n $objfile | awk -v fn=$func '$3 == fn { found=1; line=$0; start=$1; next } found == 1 { found=0; print line, $1 }')
152} 161}
153 162
154[[ $# -lt 2 ]] && usage 163[[ $# -lt 2 ]] && usage