• Fangrui Song's avatar
    perf unwind: Fix segbase for ld.lld linked objects · dc2cf4ca
    Fangrui Song authored
    segbase is the address of .eh_frame_hdr and table_data is segbase plus
    the header size. find_proc_info computes segbase as `map->start +
    segbase - map->pgoff` which is wrong when
    
    * .eh_frame_hdr and .text are in different PT_LOAD program headers
    * and their p_vaddr difference does not equal their p_offset difference
    
    Since 10.0, ld.lld's default --rosegment -z noseparate-code layout has
    such R and RX PT_LOAD program headers.
    
        ld.lld (default) => perf report fails to unwind `perf record
        --call-graph dwarf` recorded data
        ld.lld --no-rosegment => ok (trivial, no R PT_LOAD)
        ld.lld -z separate-code => ok but by luck: there are two PT_LOAD but
        their p_vaddr difference equals p_offset difference
    
        ld.bfd -z noseparate-code => ok (trivial, no R PT_LOAD)
        ld.bfd -z separate-code (default for Linux/x86) => ok but by luck:
        there are two PT_LOAD but their p_vaddr difference equals p_offset
        difference
    
    To fix the issue, compute segbase as dso's base address plus
    PT_GNU_EH_FRAME's p_vaddr. The base address is computed by iterating
    over all dso-associated maps and then subtract the first PT_LOAD p_vaddr
    (the minimum guaranteed by generic ABI) from the minimum address.
    
    In libunwind, find_proc_info transitively called by unw_step is cached,
    so the iteration overhead is acceptable.
    Reported-by: default avatarSebastian Ullrich <sebasti@nullri.ch>
    Reviewed-by: default avatarIan Rogers <irogers@google.com>
    Signed-off-by: default avatarFangrui Song <maskray@google.com>
    Cc: Ingo Molnar <mingo@redhat.com>
    Cc: Peter Zijlstra <peterz@infradead.org>
    Cc: llvm@lists.linux.dev
    Link: https://github.com/ClangBuiltLinux/linux/issues/1646
    Link: https://lore.kernel.org/r/20220527182039.673248-1-maskray@google.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
    dc2cf4ca
unwind-libunwind-local.c 18.1 KB