Patch "perf symbol: Correct address for bss symbols" has been added to the 4.19-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    perf symbol: Correct address for bss symbols

to the 4.19-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     perf-symbol-correct-address-for-bss-symbols.patch
and it can be found in the queue-4.19 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 5912671ed38ff5a8dabcdf46974a55ae17ff3f92
Author: Leo Yan <leo.yan@xxxxxxxxxx>
Date:   Sun Jul 24 14:00:12 2022 +0800

    perf symbol: Correct address for bss symbols
    
    [ Upstream commit 2d86612aacb7805f72873691a2644d7279ed0630 ]
    
    When using 'perf mem' and 'perf c2c', an issue is observed that tool
    reports the wrong offset for global data symbols.  This is a common
    issue on both x86 and Arm64 platforms.
    
    Let's see an example, for a test program, below is the disassembly for
    its .bss section which is dumped with objdump:
    
      ...
    
      Disassembly of section .bss:
    
      0000000000004040 <completed.0>:
            ...
    
      0000000000004080 <buf1>:
            ...
    
      00000000000040c0 <buf2>:
            ...
    
      0000000000004100 <thread>:
            ...
    
    First we used 'perf mem record' to run the test program and then used
    'perf --debug verbose=4 mem report' to observe what's the symbol info
    for 'buf1' and 'buf2' structures.
    
      # ./perf mem record -e ldlat-loads,ldlat-stores -- false_sharing.exe 8
      # ./perf --debug verbose=4 mem report
        ...
        dso__load_sym_internal: adjusting symbol: st_value: 0x40c0 sh_addr: 0x4040 sh_offset: 0x3028
        symbol__new: buf2 0x30a8-0x30e8
        ...
        dso__load_sym_internal: adjusting symbol: st_value: 0x4080 sh_addr: 0x4040 sh_offset: 0x3028
        symbol__new: buf1 0x3068-0x30a8
        ...
    
    The perf tool relies on libelf to parse symbols, in executable and
    shared object files, 'st_value' holds a virtual address; 'sh_addr' is
    the address at which section's first byte should reside in memory, and
    'sh_offset' is the byte offset from the beginning of the file to the
    first byte in the section.  The perf tool uses below formula to convert
    a symbol's memory address to a file address:
    
      file_address = st_value - sh_addr + sh_offset
                        ^
                        ` Memory address
    
    We can see the final adjusted address ranges for buf1 and buf2 are
    [0x30a8-0x30e8) and [0x3068-0x30a8) respectively, apparently this is
    incorrect, in the code, the structure for 'buf1' and 'buf2' specifies
    compiler attribute with 64-byte alignment.
    
    The problem happens for 'sh_offset', libelf returns it as 0x3028 which
    is not 64-byte aligned, combining with disassembly, it's likely libelf
    doesn't respect the alignment for .bss section, therefore, it doesn't
    return the aligned value for 'sh_offset'.
    
    Suggested by Fangrui Song, ELF file contains program header which
    contains PT_LOAD segments, the fields p_vaddr and p_offset in PT_LOAD
    segments contain the execution info.  A better choice for converting
    memory address to file address is using the formula:
    
      file_address = st_value - p_vaddr + p_offset
    
    This patch introduces elf_read_program_header() which returns the
    program header based on the passed 'st_value', then it uses the formula
    above to calculate the symbol file address; and the debugging log is
    updated respectively.
    
    After applying the change:
    
      # ./perf --debug verbose=4 mem report
        ...
        dso__load_sym_internal: adjusting symbol: st_value: 0x40c0 p_vaddr: 0x3d28 p_offset: 0x2d28
        symbol__new: buf2 0x30c0-0x3100
        ...
        dso__load_sym_internal: adjusting symbol: st_value: 0x4080 p_vaddr: 0x3d28 p_offset: 0x2d28
        symbol__new: buf1 0x3080-0x30c0
        ...
    
    Fixes: f17e04afaff84b5c ("perf report: Fix ELF symbol parsing")
    Reported-by: Chang Rui <changruinj@xxxxxxxxx>
    Suggested-by: Fangrui Song <maskray@xxxxxxxxxx>
    Signed-off-by: Leo Yan <leo.yan@xxxxxxxxxx>
    Acked-by: Namhyung Kim <namhyung@xxxxxxxxxx>
    Cc: Alexander Shishkin <alexander.shishkin@xxxxxxxxxxxxxxx>
    Cc: Ian Rogers <irogers@xxxxxxxxxx>
    Cc: Ingo Molnar <mingo@xxxxxxxxxx>
    Cc: Jiri Olsa <jolsa@xxxxxxxxxx>
    Cc: Mark Rutland <mark.rutland@xxxxxxx>
    Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
    Link: https://lore.kernel.org/r/20220724060013.171050-2-leo.yan@xxxxxxxxxx
    Signed-off-by: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 166c621e0223..bd33d6613929 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -201,6 +201,33 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
 	return NULL;
 }
 
+static int elf_read_program_header(Elf *elf, u64 vaddr, GElf_Phdr *phdr)
+{
+	size_t i, phdrnum;
+	u64 sz;
+
+	if (elf_getphdrnum(elf, &phdrnum))
+		return -1;
+
+	for (i = 0; i < phdrnum; i++) {
+		if (gelf_getphdr(elf, i, phdr) == NULL)
+			return -1;
+
+		if (phdr->p_type != PT_LOAD)
+			continue;
+
+		sz = max(phdr->p_memsz, phdr->p_filesz);
+		if (!sz)
+			continue;
+
+		if (vaddr >= phdr->p_vaddr && (vaddr < phdr->p_vaddr + sz))
+			return 0;
+	}
+
+	/* Not found any valid program header */
+	return -1;
+}
+
 static bool want_demangle(bool is_kernel_sym)
 {
 	return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle;
@@ -1063,6 +1090,7 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
 					sym.st_value);
 			used_opd = true;
 		}
+
 		/*
 		 * When loading symbols in a data mapping, ABS symbols (which
 		 * has a value of SHN_ABS in its st_shndx) failed at
@@ -1099,11 +1127,20 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
 				goto out_elf_end;
 		} else if ((used_opd && runtime_ss->adjust_symbols) ||
 			   (!used_opd && syms_ss->adjust_symbols)) {
+			GElf_Phdr phdr;
+
+			if (elf_read_program_header(syms_ss->elf,
+						    (u64)sym.st_value, &phdr)) {
+				pr_warning("%s: failed to find program header for "
+					   "symbol: %s st_value: %#" PRIx64 "\n",
+					   __func__, elf_name, (u64)sym.st_value);
+				continue;
+			}
 			pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
-				  "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
-				  (u64)sym.st_value, (u64)shdr.sh_addr,
-				  (u64)shdr.sh_offset);
-			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
+				  "p_vaddr: %#" PRIx64 " p_offset: %#" PRIx64 "\n",
+				  __func__, (u64)sym.st_value, (u64)phdr.p_vaddr,
+				  (u64)phdr.p_offset);
+			sym.st_value -= phdr.p_vaddr - phdr.p_offset;
 		}
 
 		demangled = demangle_sym(dso, kmodule, elf_name);



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux