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>
This commit is contained in:
parent
5e25d5bdf6
commit
efdb4167e6
|
@ -105,9 +105,18 @@ __faddr2line() {
|
|||
# In rare cases there might be duplicates.
|
||||
while read symbol; do
|
||||
local fields=($symbol)
|
||||
local sym_base=0x${fields[1]}
|
||||
local sym_size=${fields[2]}
|
||||
local sym_type=${fields[3]}
|
||||
local sym_base=0x${fields[0]}
|
||||
local sym_type=${fields[1]}
|
||||
local sym_end=0x${fields[3]}
|
||||
|
||||
# calculate the size
|
||||
local sym_size=$(($sym_end - $sym_base))
|
||||
if [[ -z $sym_size ]] || [[ $sym_size -le 0 ]]; then
|
||||
warn "bad symbol size: base: $sym_base end: $sym_end"
|
||||
DONE=1
|
||||
return
|
||||
fi
|
||||
sym_size=0x$(printf %x $sym_size)
|
||||
|
||||
# calculate the address
|
||||
local addr=$(($sym_base + $offset))
|
||||
|
@ -116,26 +125,26 @@ __faddr2line() {
|
|||
DONE=1
|
||||
return
|
||||
fi
|
||||
local hexaddr=0x$(printf %x $addr)
|
||||
addr=0x$(printf %x $addr)
|
||||
|
||||
# weed out non-function symbols
|
||||
if [[ $sym_type != "FUNC" ]]; then
|
||||
if [[ $sym_type != t ]] && [[ $sym_type != T ]]; then
|
||||
[[ $print_warnings = 1 ]] &&
|
||||
echo "skipping $func address at $hexaddr due to non-function symbol"
|
||||
echo "skipping $func address at $addr due to non-function symbol of type '$sym_type'"
|
||||
continue
|
||||
fi
|
||||
|
||||
# if the user provided a size, make sure it matches the symbol's size
|
||||
if [[ -n $size ]] && [[ $size -ne $sym_size ]]; then
|
||||
[[ $print_warnings = 1 ]] &&
|
||||
echo "skipping $func address at $hexaddr due to size mismatch ($size != $sym_size)"
|
||||
echo "skipping $func address at $addr due to size mismatch ($size != $sym_size)"
|
||||
continue;
|
||||
fi
|
||||
|
||||
# make sure the provided offset is within the symbol's range
|
||||
if [[ $offset -gt $sym_size ]]; then
|
||||
[[ $print_warnings = 1 ]] &&
|
||||
echo "skipping $func address at $hexaddr due to size mismatch ($offset > $sym_size)"
|
||||
echo "skipping $func address at $addr due to size mismatch ($offset > $sym_size)"
|
||||
continue
|
||||
fi
|
||||
|
||||
|
@ -143,12 +152,12 @@ __faddr2line() {
|
|||
[[ $FIRST = 0 ]] && echo
|
||||
FIRST=0
|
||||
|
||||
local hexsize=0x$(printf %x $sym_size)
|
||||
echo "$func+$offset/$hexsize:"
|
||||
addr2line -fpie $objfile $hexaddr | sed "s; $dir_prefix\(\./\)*; ;"
|
||||
# pass real address to addr2line
|
||||
echo "$func+$offset/$sym_size:"
|
||||
addr2line -fpie $objfile $addr | sed "s; $dir_prefix\(\./\)*; ;"
|
||||
DONE=1
|
||||
|
||||
done < <(readelf -sW $objfile | awk -v f=$func '$8 == f {print}')
|
||||
done < <(nm -n $objfile | awk -v fn=$func '$3 == fn { found=1; line=$0; start=$1; next } found == 1 { found=0; print line, $1 }')
|
||||
}
|
||||
|
||||
[[ $# -lt 2 ]] && usage
|
||||
|
|
Loading…
Reference in New Issue