perf annotate-data: Support stack variables
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: Ian 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.org
Signed-off-by: Namhyung Kim <namhyung@kernel.org>