public inbox for linux-perf-users@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] perf symbols: Fix module symbol resolution for non-zero .text sh_addr
@ 2026-03-23 15:58 Chuck Lever
  2026-03-24 11:07 ` Thomas Richter
  0 siblings, 1 reply; 2+ messages in thread
From: Chuck Lever @ 2026-03-23 15:58 UTC (permalink / raw)
  To: peterz, mingo, acme, namhyung; +Cc: linux-perf-users, Chuck Lever

From: Chuck Lever <chuck.lever@oracle.com>

When perf resolves symbols from kernel module ELF files (ET_REL),
it converts symbol addresses to file offsets so that sample IPs
can be matched to the correct symbol. The conversion adjusts each
symbol's st_value:

  sym->st_value -= shdr->sh_addr - shdr->sh_offset;

For vmlinux (ET_EXEC), st_value is a virtual address and sh_addr
is the section's virtual base, so subtracting sh_addr and adding
sh_offset correctly yields a file offset.

For kernel modules (ET_REL), st_value is a section-relative
offset. The module loader ignores sh_addr entirely and places
symbols at module_base + st_value. Converting to file offset
requires only adding sh_offset; subtracting sh_addr introduces an
error equal to sh_addr bytes.

When .text has sh_addr == 0 -- the historical norm for simple
modules -- both formulas produce the same result and the bug is
latent. As modules gain more metadata sections before .text (.note,
.static_call.text, etc.), the linker assigns .text a non-zero
sh_addr, exposing the defect. For example, nfsd.ko on this kernel
has sh_addr=0xa80, kvm-intel.ko has sh_addr=0x1e90.

The effect is that all .text symbols in affected modules
shift by sh_addr bytes relative to sample IPs, causing perf
report to attribute samples to incorrect, nearby symbols. This
was observed as 13% of LLC-load-miss samples misattributed
to nfsd_file_get_dio_attrs when the actual hot function was
nfsd_cache_lookup, approximately 0xa80 bytes away in the symbol
table.

Use the existing dso__rel() flag (already set for ET_REL modules)
to select the correct adjustment: add sh_offset for ET_REL,
subtract (sh_addr - sh_offset) for ET_EXEC/ET_DYN.

Fixes: 0131c4ec794a ("perf tools: Make it possible to read object code from kernel modules")
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 tools/perf/util/symbol-elf.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 76912c62b6a0..968e269d9be1 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1356,8 +1356,12 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map,
 	char dso_name[PATH_MAX];
 
 	/* Adjust symbol to map to file offset */
-	if (adjust_kernel_syms)
-		sym->st_value -= shdr->sh_addr - shdr->sh_offset;
+	if (adjust_kernel_syms) {
+		if (dso__rel(dso))
+			sym->st_value += shdr->sh_offset;
+		else
+			sym->st_value -= shdr->sh_addr - shdr->sh_offset;
+	}
 
 	if (strcmp(section_name, (dso__short_name(curr_dso) + dso__short_name_len(dso))) == 0)
 		return 0;
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] perf symbols: Fix module symbol resolution for non-zero .text sh_addr
  2026-03-23 15:58 [PATCH] perf symbols: Fix module symbol resolution for non-zero .text sh_addr Chuck Lever
@ 2026-03-24 11:07 ` Thomas Richter
  0 siblings, 0 replies; 2+ messages in thread
From: Thomas Richter @ 2026-03-24 11:07 UTC (permalink / raw)
  To: Chuck Lever, peterz, mingo, acme, namhyung; +Cc: linux-perf-users, Chuck Lever

On 3/23/26 16:58, Chuck Lever wrote:
> From: Chuck Lever <chuck.lever@oracle.com>
> 
> When perf resolves symbols from kernel module ELF files (ET_REL),
> it converts symbol addresses to file offsets so that sample IPs
> can be matched to the correct symbol. The conversion adjusts each
> symbol's st_value:
> 
>   sym->st_value -= shdr->sh_addr - shdr->sh_offset;
> 
> For vmlinux (ET_EXEC), st_value is a virtual address and sh_addr
> is the section's virtual base, so subtracting sh_addr and adding
> sh_offset correctly yields a file offset.
> 
> For kernel modules (ET_REL), st_value is a section-relative
> offset. The module loader ignores sh_addr entirely and places
> symbols at module_base + st_value. Converting to file offset
> requires only adding sh_offset; subtracting sh_addr introduces an
> error equal to sh_addr bytes.
> 
> When .text has sh_addr == 0 -- the historical norm for simple
> modules -- both formulas produce the same result and the bug is
> latent. As modules gain more metadata sections before .text (.note,
> .static_call.text, etc.), the linker assigns .text a non-zero
> sh_addr, exposing the defect. For example, nfsd.ko on this kernel
> has sh_addr=0xa80, kvm-intel.ko has sh_addr=0x1e90.
> 
> The effect is that all .text symbols in affected modules
> shift by sh_addr bytes relative to sample IPs, causing perf
> report to attribute samples to incorrect, nearby symbols. This
> was observed as 13% of LLC-load-miss samples misattributed
> to nfsd_file_get_dio_attrs when the actual hot function was
> nfsd_cache_lookup, approximately 0xa80 bytes away in the symbol
> table.
> 
> Use the existing dso__rel() flag (already set for ET_REL modules)
> to select the correct adjustment: add sh_offset for ET_REL,
> subtract (sh_addr - sh_offset) for ET_EXEC/ET_DYN.
> 
> Fixes: 0131c4ec794a ("perf tools: Make it possible to read object code from kernel modules")
> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> ---
>  tools/perf/util/symbol-elf.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
> index 76912c62b6a0..968e269d9be1 100644
> --- a/tools/perf/util/symbol-elf.c
> +++ b/tools/perf/util/symbol-elf.c
> @@ -1356,8 +1356,12 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map,
>  	char dso_name[PATH_MAX];
>  
>  	/* Adjust symbol to map to file offset */
> -	if (adjust_kernel_syms)
> -		sym->st_value -= shdr->sh_addr - shdr->sh_offset;
> +	if (adjust_kernel_syms) {
> +		if (dso__rel(dso))
> +			sym->st_value += shdr->sh_offset;
> +		else
> +			sym->st_value -= shdr->sh_addr - shdr->sh_offset;
> +	}
>  
>  	if (strcmp(section_name, (dso__short_name(curr_dso) + dso__short_name_len(dso))) == 0)
>  		return 0;

For s390

Tested-by: Thomas Richter <tmricht@linux.ibm.com>
-- 
Thomas Richter, Dept 3303, IBM s390 Linux Development, Boeblingen, Germany
--
IBM Deutschland Research & Development GmbH

Vorsitzender des Aufsichtsrats: Wolfgang Wendt

Geschäftsführung: David Faller

Sitz der Gesellschaft: Böblingen / Registergericht: Amtsgericht Stuttgart, HRB 243294

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-03-24 11:07 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-23 15:58 [PATCH] perf symbols: Fix module symbol resolution for non-zero .text sh_addr Chuck Lever
2026-03-24 11:07 ` Thomas Richter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox