• Namhyung Kim's avatar
    perf annotate-data: Support stack variables · bc10db8e
    Namhyung Kim authored
    Local variables are allocated in the stack and the location list
    should look like base register(s) and an offset.  Extend the
    die_find_variable_by_reg() to handle the following expressions
    
     * DW_OP_breg{0..31}
     * DW_OP_bregx
     * DW_OP_fbreg
    
    Ususally DWARF subprogram entries have frame base information and
    use it to locate stack variable like below:
    
     <2><43d1575>: Abbrev Number: 62 (DW_TAG_variable)
        <43d1576>   DW_AT_location    : 2 byte block: 91 7c         (DW_OP_fbreg: -4)  <--- here
        <43d1579>   DW_AT_name        : (indirect string, offset: 0x2c00c9): i
        <43d157d>   DW_AT_decl_file   : 1
        <43d157e>   DW_AT_decl_line   : 78
        <43d157f>   DW_AT_type        : <0x43d19d7>
    
    I found some differences on saving the frame base between gcc and clang.
    The gcc uses the CFA to get the base so it needs to check the current
    frame's CFI info.  In this case, stack offset needs to be adjusted from
    the start of the CFA.
    
     <1><1bb8d>: Abbrev Number: 102 (DW_TAG_subprogram)
        <1bb8e>   DW_AT_name        : (indirect string, offset: 0x74d41): kernel_init
        <1bb92>   DW_AT_decl_file   : 2
        <1bb92>   DW_AT_decl_line   : 1440
        <1bb94>   DW_AT_decl_column : 18
        <1bb95>   DW_AT_prototyped  : 1
        <1bb95>   DW_AT_type        : <0xcc>
        <1bb99>   DW_AT_low_pc      : 0xffffffff81bab9e0
        <1bba1>   DW_AT_high_pc     : 0x1b2
        <1bba9>   DW_AT_frame_base  : 1 byte block: 9c      (DW_OP_call_frame_cfa)  <------ here
        <1bbab>   DW_AT_call_all_calls: 1
        <1bbab>   DW_AT_sibling     : <0x1bf5a>
    
    While clang sets it to a register directly and it can check the register
    and offset in the instruction directly.
    
     <1><43d1542>: Abbrev Number: 60 (DW_TAG_subprogram)
        <43d1543>   DW_AT_low_pc      : 0xffffffff816a7c60
        <43d154b>   DW_AT_high_pc     : 0x98
        <43d154f>   DW_AT_frame_base  : 1 byte block: 56    (DW_OP_reg6 (rbp))  <---------- here
        <43d1551>   DW_AT_GNU_all_call_sites: 1
        <43d1551>   DW_AT_name        : (indirect string, offset: 0x3bce91): foo
        <43d1555>   DW_AT_decl_file   : 1
        <43d1556>   DW_AT_decl_line   : 75
        <43d1557>   DW_AT_prototyped  : 1
        <43d1557>   DW_AT_type        : <0x43c7332>
        <43d155b>   DW_AT_external    : 1
    
    Also it needs to update the offset after finding the type like global
    variables since the offset was from the frame base.  Factor out
    match_var_offset() to check global and local variables in the same way.
    
    The type stats are improved too:
    
      Annotate data type stats:
      total 294, ok 160 (54.4%), bad 134 (45.6%)
      -----------------------------------------------------------
              30 : no_sym
              32 : no_mem_ops
              51 : no_var
              14 : no_typeinfo
               7 : bad_offset
    Reviewed-by: default avatarIan Rogers <irogers@google.com>
    Cc: Stephane Eranian <eranian@google.com>
    Cc: Masami Hiramatsu <mhiramat@kernel.org>
    Link: https://lore.kernel.org/r/20240117062657.985479-9-namhyung@kernel.orgSigned-off-by: default avatarNamhyung Kim <namhyung@kernel.org>
    bc10db8e
dwarf-aux.h 6.42 KB