From 24a30ce9b14ce84b00105b970c4d16eabe09a62a Mon Sep 17 00:00:00 2001 From: Zecheng Li Date: Mon, 13 Oct 2025 18:15:59 +0000 Subject: perf annotate: Track address registers via TSR_KIND_POINTER Introduce TSR_KIND_POINTER to improve the data type profiler's ability to track pointer-based memory accesses and address register variables. TSR_KIND_POINTER represents that the location holds a pointer type to the type in the type state. The semantics match the `breg` registers that describe a memory location. This change implements handling for this new kind in mov instructions and in the check_matching_type() function. When a TSR_KIND_POINTER is moved to the stack, the stack state size is set to the architecture's pointer size. Signed-off-by: Zecheng Li Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 63 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 7 deletions(-) (limited to 'tools/perf/util/annotate-data.c') diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 903027a6fb7d..48f3bf20070f 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -59,6 +59,10 @@ void pr_debug_type_name(Dwarf_Die *die, enum type_state_kind kind) pr_info(" constant\n"); return; case TSR_KIND_PERCPU_POINTER: + pr_info(" percpu pointer"); + /* it also prints the type info */ + break; + case TSR_KIND_POINTER: pr_info(" pointer"); /* it also prints the type info */ break; @@ -578,16 +582,25 @@ void set_stack_state(struct type_state_stack *stack, int offset, u8 kind, int tag; Dwarf_Word size; - if (dwarf_aggregate_size(type_die, &size) < 0) + if (kind == TSR_KIND_POINTER) { + /* TODO: arch-dependent pointer size */ + size = sizeof(void *); + } + else if (dwarf_aggregate_size(type_die, &size) < 0) size = 0; - tag = dwarf_tag(type_die); - stack->type = *type_die; stack->size = size; stack->offset = offset; stack->kind = kind; + if (kind == TSR_KIND_POINTER) { + stack->compound = false; + return; + } + + tag = dwarf_tag(type_die); + switch (tag) { case DW_TAG_structure_type: case DW_TAG_union_type: @@ -898,13 +911,25 @@ static void update_var_state(struct type_state *state, struct data_loc_info *dlo reg = &state->regs[var->reg]; - /* For gp registers, skip the address registers for now */ - if (var->is_reg_var_addr) + if (reg->ok && reg->kind == TSR_KIND_TYPE && + (!is_better_type(®->type, &mem_die) || var->is_reg_var_addr)) continue; - if (reg->ok && reg->kind == TSR_KIND_TYPE && - !is_better_type(®->type, &mem_die)) + /* Handle address registers with TSR_KIND_POINTER */ + if (var->is_reg_var_addr) { + if (reg->ok && reg->kind == TSR_KIND_POINTER && + !is_better_type(®->type, &mem_die)) + continue; + + reg->type = mem_die; + reg->kind = TSR_KIND_POINTER; + reg->ok = true; + + pr_debug_dtp("var [%"PRIx64"] reg%d addr offset %x", + insn_offset, var->reg, var->offset); + pr_debug_type_name(&mem_die, TSR_KIND_POINTER); continue; + } orig_type = reg->type; @@ -1116,6 +1141,30 @@ again: return PERF_TMR_OK; } + if (state->regs[reg].kind == TSR_KIND_POINTER) { + struct strbuf sb; + + strbuf_init(&sb, 32); + die_get_typename_from_type(&state->regs[reg].type, &sb); + pr_debug_dtp("(ptr->%s)", sb.buf); + strbuf_release(&sb); + + /* + * Register holds a pointer (address) to the target variable. + * The type is the type of the variable it points to. + */ + *type_die = state->regs[reg].type; + + dloc->type_offset = dloc->op->offset; + + /* Get the size of the actual type */ + if (dwarf_aggregate_size(type_die, &size) < 0 || + (unsigned)dloc->type_offset >= size) + return PERF_TMR_BAD_OFFSET; + + return PERF_TMR_OK; + } + if (state->regs[reg].kind == TSR_KIND_PERCPU_POINTER) { pr_debug_dtp("percpu ptr"); -- cgit From 1f4cc4ae3f8ae661bae3722e973a0f5be650fcbf Mon Sep 17 00:00:00 2001 From: Zecheng Li Date: Mon, 13 Oct 2025 18:16:00 +0000 Subject: perf annotate: Track arithmetic instructions on pointers Track the arithmetic operations on registers with pointer types. We handle only add, sub and lea instructions. The original pointer information needs to be preserved for getting outermost struct types. For example, reg0 points to a struct cfs_rq, when we add 0x10 to reg0, it should preserve the information of struct cfs_rq + 0x10 in the register instead of a pointer type to the child field at 0x10. Details: 1. struct type_state_reg now includes an offset, indicating if the register points to the start or an internal part of its associated type. This offset is used in mem to reg and reg to stack mem transfers, and also applied to the final type offset. 2. lea offset(%sp/%fp), reg is now treated as taking the address of a stack variable. It worked fine in most cases, but an issue with this approach is the pointer type may not exist. 3. lea offset(%base), reg is handled by moving the type from %base and adding an offset, similar to an add operation followed by a mov reg to reg. 4. Non-stack variables from DWARF with non-zero offsets in their location expressions are now accepted with register offset tracking. Multi-register addressing modes in LEA are not supported. Signed-off-by: Zecheng Li Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'tools/perf/util/annotate-data.c') diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 48f3bf20070f..4204a7956ee5 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -905,7 +905,7 @@ static void update_var_state(struct type_state *state, struct data_loc_info *dlo insn_offset, -offset); } pr_debug_type_name(&mem_die, TSR_KIND_TYPE); - } else if (has_reg_type(state, var->reg) && var->offset == 0) { + } else if (has_reg_type(state, var->reg)) { struct type_state_reg *reg; Dwarf_Die orig_type; @@ -921,6 +921,7 @@ static void update_var_state(struct type_state *state, struct data_loc_info *dlo !is_better_type(®->type, &mem_die)) continue; + reg->offset = -var->offset; reg->type = mem_die; reg->kind = TSR_KIND_POINTER; reg->ok = true; @@ -932,13 +933,17 @@ static void update_var_state(struct type_state *state, struct data_loc_info *dlo } orig_type = reg->type; - + /* + * var->offset + reg value is the beginning of the struct + * reg->offset is the offset the reg points + */ + reg->offset = -var->offset; reg->type = mem_die; reg->kind = TSR_KIND_TYPE; reg->ok = true; - pr_debug_dtp("var [%"PRIx64"] reg%d", - insn_offset, var->reg); + pr_debug_dtp("var [%"PRIx64"] reg%d offset %x", + insn_offset, var->reg, var->offset); pr_debug_type_name(&mem_die, TSR_KIND_TYPE); /* @@ -1126,7 +1131,7 @@ again: if (__die_get_real_type(&state->regs[reg].type, type_die) == NULL) return PERF_TMR_NO_POINTER; - dloc->type_offset = dloc->op->offset; + dloc->type_offset = dloc->op->offset + state->regs[reg].offset; if (dwarf_tag(type_die) == DW_TAG_typedef) die_get_real_type(type_die, &sized_type); @@ -1155,7 +1160,7 @@ again: */ *type_die = state->regs[reg].type; - dloc->type_offset = dloc->op->offset; + dloc->type_offset = dloc->op->offset + state->regs[reg].offset; /* Get the size of the actual type */ if (dwarf_aggregate_size(type_die, &size) < 0 || -- cgit From 109218718de2f7173fabdd507cc6786e79ad1690 Mon Sep 17 00:00:00 2001 From: Zecheng Li Date: Mon, 13 Oct 2025 18:16:01 +0000 Subject: perf annotate: Save pointer offset in stack state The tracked pointer offset was not being preserved in the stack state, which could lead to incorrect type analysis. This change adds a ptr_offset field to the type_state_stack struct and passes it to set_stack_state and findnew_stack_state to ensure the offset is preserved after the pointer is loaded from a stack location. It improves the type annotation coverage and quality. Signed-off-by: Zecheng Li Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'tools/perf/util/annotate-data.c') diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 4204a7956ee5..e183c6104d59 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -577,7 +577,7 @@ struct type_state_stack *find_stack_state(struct type_state *state, } void set_stack_state(struct type_state_stack *stack, int offset, u8 kind, - Dwarf_Die *type_die) + Dwarf_Die *type_die, int ptr_offset) { int tag; Dwarf_Word size; @@ -592,6 +592,7 @@ void set_stack_state(struct type_state_stack *stack, int offset, u8 kind, stack->type = *type_die; stack->size = size; stack->offset = offset; + stack->ptr_offset = ptr_offset; stack->kind = kind; if (kind == TSR_KIND_POINTER) { @@ -614,18 +615,19 @@ void set_stack_state(struct type_state_stack *stack, int offset, u8 kind, struct type_state_stack *findnew_stack_state(struct type_state *state, int offset, u8 kind, - Dwarf_Die *type_die) + Dwarf_Die *type_die, + int ptr_offset) { struct type_state_stack *stack = find_stack_state(state, offset); if (stack) { - set_stack_state(stack, offset, kind, type_die); + set_stack_state(stack, offset, kind, type_die, ptr_offset); return stack; } stack = malloc(sizeof(*stack)); if (stack) { - set_stack_state(stack, offset, kind, type_die); + set_stack_state(stack, offset, kind, type_die, ptr_offset); list_add(&stack->list, &state->stack_vars); } return stack; @@ -895,7 +897,7 @@ static void update_var_state(struct type_state *state, struct data_loc_info *dlo continue; findnew_stack_state(state, offset, TSR_KIND_TYPE, - &mem_die); + &mem_die, /*ptr_offset=*/0); if (var->reg == state->stack_reg) { pr_debug_dtp("var [%"PRIx64"] %#x(reg%d)", -- cgit From ca016b6527e154013693722a2cdbec7c05fb6df7 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sun, 9 Nov 2025 17:31:52 -0800 Subject: perf auxtrace: Remove errno.h from auxtrace.h and fix transitive dependencies errno.h isn't used in auxtrace.h so remove it and fix build failures caused by transitive dependencies through auxtrace.h on errno.h. Signed-off-by: Ian Rogers Reviewed-by: James Clark Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util/annotate-data.c') diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index e183c6104d59..07cf9c334be0 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -4,7 +4,7 @@ * * Written by Namhyung Kim */ - +#include #include #include #include -- cgit