Re: [PATCH v2 11/16] perf annotate-arm64: Support stack variable tracking
From: Tengda Wu
Date: Fri Apr 10 2026 - 06:44:05 EST
On 2026/4/10 14:29, Namhyung Kim wrote:
> On Fri, Apr 03, 2026 at 09:47:55AM +0000, Tengda Wu wrote:
>> Extend update_insn_state() for arm64 to track data types stored on the
>> stack. This allows 'perf annotate' to maintain type information for
>> local variables that are spilled to or loaded from stack slots.
>>
>> The implementation handles:
>> 1. Stack Loads (LDR): Identify when a register is loaded from a stack
>> slot and update the register's type state based on the tracked
>> stack content or compound member types.
>> 2. Stack Stores (STR): Update or create new stack state entries when
>> a tracked register type is stored to the stack.
>>
>> This enables the instruction tracker to follow data types as they move
>> between registers and memory, specifically for function local variables
>> and compiler-spilled values on arm64.
>>
>> Signed-off-by: Tengda Wu <wutengda@xxxxxxxxxxxxxxx>
>> ---
>> .../perf/util/annotate-arch/annotate-arm64.c | 83 ++++++++++++++++++-
>> 1 file changed, 80 insertions(+), 3 deletions(-)
>>
>> diff --git a/tools/perf/util/annotate-arch/annotate-arm64.c b/tools/perf/util/annotate-arch/annotate-arm64.c
>> index 28647a778802..f9100230c2f6 100644
>> --- a/tools/perf/util/annotate-arch/annotate-arm64.c
>> +++ b/tools/perf/util/annotate-arch/annotate-arm64.c
>> @@ -11,6 +11,8 @@
>> #include "../disasm.h"
>> #include "../annotate-data.h"
>> #include "../debug.h"
>> +#include "../map.h"
>> +#include "../symbol.h"
>>
>> struct arch_arm64 {
>> struct arch arch;
>> @@ -297,6 +299,8 @@ static void update_insn_state_arm64(struct type_state *state,
>> Dwarf_Die type_die;
>> u32 insn_offset = dl->al.offset;
>> int sreg, dreg;
>> + int fbreg = dloc->fbreg;
>> + int fboff = 0;
>>
>> if (annotate_get_insn_location(dloc->arch, dl, &loc) < 0)
>> return;
>> @@ -304,17 +308,59 @@ static void update_insn_state_arm64(struct type_state *state,
>> sreg = src->reg1;
>> dreg = dst->reg1;
>>
>> + if (dloc->fb_cfa) {
>> + u64 ip = dloc->ms->sym->start + dl->al.offset;
>> + u64 pc = map__rip_2objdump(dloc->ms->map, ip);
>> +
>> + if (die_get_cfa(dloc->di->dbg, pc, &fbreg, &fboff) < 0)
>> + fbreg = -1;
>> + }
>> +
>> /* Memory to register transfers */
>> if (!strncmp(dl->ins.name, "ld", 2)) {
>> struct type_state_reg dst_tsr;
>>
>> - if (!has_reg_type(state, sreg) ||
>> - !has_reg_type(state, dreg) ||
>> - !state->regs[dreg].ok)
>> + if (!has_reg_type(state, sreg))
>> return;
>>
>> tsr = &state->regs[sreg];
>> tsr->copied_from = -1;
>> +
>> + /* Check stack variables with offset */
>> + if (sreg == fbreg || sreg == state->stack_reg) {
>> + struct type_state_stack *stack;
>> + int offset = src->offset - fboff;
>> +
>> + stack = find_stack_state(state, offset);
>> + if (stack == NULL) {
>> + tsr->ok = false;
>> + return;
>> + } else if (!stack->compound) {
>> + tsr->type = stack->type;
>> + tsr->kind = stack->kind;
>> + tsr->offset = stack->ptr_offset;
>> + tsr->ok = true;
>> + } else if (die_get_member_type(&stack->type,
>> + offset - stack->offset,
>> + &type_die)) {
>> + tsr->type = type_die;
>> + tsr->kind = TSR_KIND_TYPE;
>> + tsr->offset = 0;
>> + tsr->ok = true;
>> + } else {
>> + tsr->ok = false;
>> + return;
>> + }
>> +
>> + pr_debug_dtp("ldr [%x] -%#x(stack) -> reg%d",
>> + insn_offset, -offset, sreg);
>> + pr_debug_type_name(&tsr->type, tsr->kind);
>> + return;
>
> Any chance the stack register changes the offset with the addressing
> mode? I think it should be updated regardless of the result of this
> operation.
>
>> + }
>> +
>> + if (!has_reg_type(state, dreg) || !state->regs[dreg].ok)
>> + return;
>> +
>> dst_tsr = state->regs[dreg];
>>
>> /* Dereference the pointer if it has one */
>> @@ -338,6 +384,37 @@ static void update_insn_state_arm64(struct type_state *state,
>>
>> /* Register to memory transfers */
>> if (!strncmp(dl->ins.name, "st", 2)) {
>> + /* Check stack variables with offset */
>> + if (dreg == fbreg || dreg == state->stack_reg) {
>> + struct type_state_stack *stack;
>> + int offset = dst->offset - fboff;
>> +
>> + if (!has_reg_type(state, sreg) ||
>> + !state->regs[sreg].ok)
>> + return;
>> +
>> + tsr = &state->regs[sreg];
>> +
>> + stack = find_stack_state(state, offset);
>> + if (stack) {
>> + if (!stack->compound)
>> + set_stack_state(stack, offset, tsr->kind,
>> + &tsr->type, tsr->offset);
>> + } else {
>> + findnew_stack_state(state, offset, tsr->kind,
>> + &tsr->type, tsr->offset);
>> + }
>> +
>> + pr_debug_dtp("str [%x] reg%d -> -%#x(stack)",
>> + insn_offset, sreg, -offset);
>> + if (tsr->offset != 0) {
>> + pr_debug_dtp(" reg%d offset %#x ->",
>> + sreg, tsr->offset);
>> + }
>> + pr_debug_type_name(&tsr->type, tsr->kind);
>> + return;
>
> Ditto.
>
> Thanks,
> Namhyung
>
Indeed. Pre/post-index addressing modes are very common for stack operations
in arm64. It’s definitely necessary to update the offset regardless of the
lookup result.
-- Tengda
>
>> + }
>> +
>> /*
>> * Store instructions do not change the register type,
>> * but the base register must be updated for pre/post-index
>> --
>> 2.34.1
>>