summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@kernel.org>2022-06-01 17:42:22 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-06-22 14:13:17 +0200
commitb559ef9dfc8f21d5940beedc9e88a1e912c76b18 (patch)
tree34b0db7a697843f89cf6e2cecf93da19050a9001 /scripts
parent7fa28a7c3d74933a4fc22d341b60927952f31c19 (diff)
downloadlinux-stable-b559ef9dfc8f21d5940beedc9e88a1e912c76b18.tar.gz
linux-stable-b559ef9dfc8f21d5940beedc9e88a1e912c76b18.tar.bz2
linux-stable-b559ef9dfc8f21d5940beedc9e88a1e912c76b18.zip
faddr2line: Fix overlapping text section failures, the sequel
[ Upstream commit dcea997beed694cbd8705100ca1a6eb0d886de69 ] If a function lives in a section other than .text, but .text also exists in the object, faddr2line may wrongly assume .text. This can result in comically wrong output. For example: $ scripts/faddr2line vmlinux.o enter_from_user_mode+0x1c enter_from_user_mode+0x1c/0x30: find_next_bit at /home/jpoimboe/git/linux/./include/linux/find.h:40 (inlined by) perf_clear_dirty_counters at /home/jpoimboe/git/linux/arch/x86/events/core.c:2504 Fix it by passing the section name to addr2line, unless the object file is vmlinux, in which case the symbol table uses absolute addresses. Fixes: 1d1a0e7c5100 ("scripts/faddr2line: Fix overlapping text section failures") Reported-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org> Link: https://lore.kernel.org/r/7d25bc1408bd3a750ac26e60d2f2815a5f4a8363.1654130536.git.jpoimboe@kernel.org Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/faddr2line45
1 files changed, 34 insertions, 11 deletions
diff --git a/scripts/faddr2line b/scripts/faddr2line
index 0e6268d59883..94ed98dd899f 100755
--- a/scripts/faddr2line
+++ b/scripts/faddr2line
@@ -95,17 +95,25 @@ __faddr2line() {
local print_warnings=$4
local sym_name=${func_addr%+*}
- local offset=${func_addr#*+}
- offset=${offset%/*}
+ local func_offset=${func_addr#*+}
+ func_offset=${func_offset%/*}
local user_size=
+ local file_type
+ local is_vmlinux=0
[[ $func_addr =~ "/" ]] && user_size=${func_addr#*/}
- if [[ -z $sym_name ]] || [[ -z $offset ]] || [[ $sym_name = $func_addr ]]; then
+ if [[ -z $sym_name ]] || [[ -z $func_offset ]] || [[ $sym_name = $func_addr ]]; then
warn "bad func+offset $func_addr"
DONE=1
return
fi
+ # vmlinux uses absolute addresses in the section table rather than
+ # section offsets.
+ local file_type=$(${READELF} --file-header $objfile |
+ ${AWK} '$1 == "Type:" { print $2; exit }')
+ [[ $file_type = "EXEC" ]] && is_vmlinux=1
+
# Go through each of the object's symbols which match the func name.
# In rare cases there might be duplicates, in which case we print all
# matches.
@@ -114,9 +122,11 @@ __faddr2line() {
local sym_addr=0x${fields[1]}
local sym_elf_size=${fields[2]}
local sym_sec=${fields[6]}
+ local sec_size
+ local sec_name
# Get the section size:
- local sec_size=$(${READELF} --section-headers --wide $objfile |
+ sec_size=$(${READELF} --section-headers --wide $objfile |
sed 's/\[ /\[/' |
${AWK} -v sec=$sym_sec '$1 == "[" sec "]" { print "0x" $6; exit }')
@@ -126,6 +136,17 @@ __faddr2line() {
return
fi
+ # Get the section name:
+ sec_name=$(${READELF} --section-headers --wide $objfile |
+ sed 's/\[ /\[/' |
+ ${AWK} -v sec=$sym_sec '$1 == "[" sec "]" { print $2; exit }')
+
+ if [[ -z $sec_name ]]; then
+ warn "bad section name: section: $sym_sec"
+ DONE=1
+ return
+ fi
+
# Calculate the symbol size.
#
# Unfortunately we can't use the ELF size, because kallsyms
@@ -174,10 +195,10 @@ __faddr2line() {
sym_size=0x$(printf %x $sym_size)
- # Calculate the section address from user-supplied offset:
- local addr=$(($sym_addr + $offset))
+ # Calculate the address from user-supplied offset:
+ local addr=$(($sym_addr + $func_offset))
if [[ -z $addr ]] || [[ $addr = 0 ]]; then
- warn "bad address: $sym_addr + $offset"
+ warn "bad address: $sym_addr + $func_offset"
DONE=1
return
fi
@@ -191,9 +212,9 @@ __faddr2line() {
fi
# Make sure the provided offset is within the symbol's range:
- if [[ $offset -gt $sym_size ]]; then
+ if [[ $func_offset -gt $sym_size ]]; then
[[ $print_warnings = 1 ]] &&
- echo "skipping $sym_name address at $addr due to size mismatch ($offset > $sym_size)"
+ echo "skipping $sym_name address at $addr due to size mismatch ($func_offset > $sym_size)"
continue
fi
@@ -202,11 +223,13 @@ __faddr2line() {
[[ $FIRST = 0 ]] && echo
FIRST=0
- echo "$sym_name+$offset/$sym_size:"
+ echo "$sym_name+$func_offset/$sym_size:"
# Pass section address to addr2line and strip absolute paths
# from the output:
- local output=$(${ADDR2LINE} -fpie $objfile $addr | sed "s; $dir_prefix\(\./\)*; ;")
+ local args="--functions --pretty-print --inlines --exe=$objfile"
+ [[ $is_vmlinux = 0 ]] && args="$args --section=$sec_name"
+ local output=$(${ADDR2LINE} $args $addr | sed "s; $dir_prefix\(\./\)*; ;")
[[ -z $output ]] && continue
# Default output (non --list):