diff options
Diffstat (limited to '0088-faddr2line-Fix-overlapping-text-section-failures-the.patch')
-rw-r--r-- | 0088-faddr2line-Fix-overlapping-text-section-failures-the.patch | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/0088-faddr2line-Fix-overlapping-text-section-failures-the.patch b/0088-faddr2line-Fix-overlapping-text-section-failures-the.patch new file mode 100644 index 000000000000..3c636ebda7c7 --- /dev/null +++ b/0088-faddr2line-Fix-overlapping-text-section-failures-the.patch @@ -0,0 +1,134 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Josh Poimboeuf <jpoimboe@kernel.org> +Date: Wed, 1 Jun 2022 17:42:22 -0700 +Subject: [PATCH] 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> +--- + scripts/faddr2line | 45 ++++++++++++++++++++++++++++++++++----------- + 1 file changed, 34 insertions(+), 11 deletions(-) + +diff --git a/scripts/faddr2line b/scripts/faddr2line +index 0e6268d598835e7a6eec49474af1b5a2e3673745..94ed98dd899f3041c8ee5583ffa225f2f0eacc36 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): |