• Leo Yan's avatar
    perf symbol: Correct address for bss symbols · 2d86612a
    Leo Yan authored
    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: f17e04af ("perf report: Fix ELF symbol parsing")
    Reported-by: default avatarChang Rui <changruinj@gmail.com>
    Suggested-by: default avatarFangrui Song <maskray@google.com>
    Signed-off-by: default avatarLeo Yan <leo.yan@linaro.org>
    Acked-by: default avatarNamhyung Kim <namhyung@kernel.org>
    Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
    Cc: Ian Rogers <irogers@google.com>
    Cc: Ingo Molnar <mingo@redhat.com>
    Cc: Jiri Olsa <jolsa@kernel.org>
    Cc: Mark Rutland <mark.rutland@arm.com>
    Cc: Peter Zijlstra <peterz@infradead.org>
    Link: https://lore.kernel.org/r/20220724060013.171050-2-leo.yan@linaro.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
    2d86612a
symbol-elf.c 56.2 KB