All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Tengda Wu" <wutengda@huaweicloud.com>
Cc: linux-perf-users@vger.kernel.org
Subject: Re: [PATCH v8 05/15] perf annotate-arm64: Support load instruction tracking
Date: Tue, 20 Oct 2026 14:36:34 +0000	[thread overview]
Message-ID: <sashiko-outbox-179159@kernel.org> (raw)
In-Reply-To: <a6085b6f08ba2ed533208ebe9227968770cd58ca.1792411435.git.wutengda@huaweicloud.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] perf annotate-arm64: unused type_die in propagate_load_reg_state()
- [Medium] perf annotate-arm64: missing reg2 extraction in ldp when reg1 is xzr/wzr
--

commit d4331cee155820a433821da388de2a7297699e0e
Author: Tengda Wu <wutengda@huaweicloud.com>

perf annotate-arm64: Support load instruction tracking

This commit extends update_insn_state_arm64() to track register state
changes across standard load and load-pair instructions, including
pre-index and post-index addressing modes.

> diff --git a/tools/perf/util/annotate-arch/annotate-arm64.c b/tools/perf/util/annotate-arch/annotate-arm64.c
> index c4cc8bca85cc0..0b5d1abbc5755 100644
> --- a/tools/perf/util/annotate-arch/annotate-arm64.c
> +++ b/tools/perf/util/annotate-arch/annotate-arm64.c
> @@ -527,11 +527,212 @@ static void invalidate_unhandled_insn_regs(struct type_state *state,
>  	/* TODO: Extend invalidation support to more special instructions. */
>  }
>  
> +static int arm64__reg_size(const char *reg)
> +{
> +	if (!reg || !*reg || !arm64__is_reg(reg))
> +		return -1;
> +
> +	if (reg[0] == 'w')
> +		return 4;
> +
> +	if (reg[0] == 'x' || !strncmp(reg, "sp", 2))
> +		return 8;
> +
> +	return -1;
> +}

[ ... ]

> +static int propagate_load_reg_state(struct type_state *state,
> +				    struct data_loc_info *dloc,
> +				    struct disasm_line *dl, int dreg,
> +				    struct annotated_op_loc *src,
> +				    struct type_state_reg **src_states,
> +				    int mem_spacing)
> +{
> +	struct type_state_reg *tsr;
> +	struct type_state_reg *src_tsr = src_states[0];
> +	Dwarf_Die type_die;
> +	u32 insn_offset = dl->al.offset;
> +	int sreg = src->reg1;
> +	int reg_offset;
> +
> +	if (!has_reg_type(state, dreg))
> +		return -1;
> +
> +	tsr = &state->regs[dreg];
> +	tsr->copied_from = -1;
> +	tsr->lifetime_active = false;
> +	tsr->lifetime_end = 0;
> +
> +retry:
> +	if (arch_get_reg_offset(dloc->arch, src, sreg, state, false, &reg_offset))
> +		goto load_non_regoff;
> +
> +	reg_offset += mem_spacing;
> +
> +	if (!src_tsr || !src_tsr->ok)
> +		return -1;
> +
> +	/* Dereference the pointer if it has one */
> +	if (src_tsr->kind == TSR_KIND_TYPE &&
> +	    die_deref_ptr_type(&src_tsr->type,
> +			       src_tsr->offset + reg_offset, &type_die)) {
> +		tsr->type = type_die;
> +		tsr->kind = TSR_KIND_TYPE;
> +		tsr->offset = 0;
> +		tsr->ok = true;
> +
> +		pr_debug_dtp("%s [%x] %#x(reg%d) -> reg%d",
> +			     dl->ins.name, insn_offset, reg_offset, sreg, dreg);
> +		pr_debug_type_name(&tsr->type, tsr->kind);
> +		return 0;
> +	}
> +
> +	/* Handle dereference of TSR_KIND_POINTER registers */
> +	if (src_tsr->kind == TSR_KIND_POINTER &&
> +	    die_get_member_type(&src_tsr->type,
> +				src_tsr->offset + reg_offset, &type_die)) {
> +		tsr->type = src_tsr->type;
> +		tsr->kind = TSR_KIND_TYPE;
> +		tsr->offset = src_tsr->offset + reg_offset;

[Severity: Medium]
Should tsr->type be assigned type_die and tsr->offset set to 0 here?

When DWARF describes a struct variable via a register-based memory
location (where var->is_reg_var_addr is true), update_var_state() sets
the base register to TSR_KIND_POINTER with reg->type set to the struct
DIE.

When a load instruction reads a member from that struct into dreg,
update_insn_state_arm64() -> update_load_insn_state() ->
propagate_load_reg_state() calls die_get_member_type() to resolve the
loaded member's type into type_die.

However, type_die is left unused, and tsr->type is set to src_tsr->type
(the outer struct DIE) with tsr->offset set to src_tsr->offset +
reg_offset and tsr->kind set to TSR_KIND_TYPE. When a subsequent
instruction dereferences dreg, check_matching_type() or
die_deref_ptr_type() inspects dreg->type, sees the outer struct type
instead of the member's pointer type, and fails with PERF_TMR_NO_POINTER.

> +		tsr->imm_value = 0;
> +		tsr->ok = true;
> +
> +		pr_debug_dtp("%s [%x] addr %#x(reg%d) -> reg%d",
> +			     dl->ins.name, insn_offset, reg_offset, sreg, dreg);
> +		pr_debug_type_name(&tsr->type, tsr->kind);
> +		return 0;
> +	}
> +
> +load_non_regoff:
> +	/* Try another register if any */
> +	if (src->multi_regs && src->reg1 != src->reg2 && sreg != src->reg2 &&
> +	    !(src->extend_type || src->shift_type)) {
> +		sreg = src->reg2;
> +		src_tsr = src_states[1];
> +		goto retry;
> +	}
> +
> +	return -1;
> +}
> +
> +static void update_load_insn_state(struct type_state *state,
> +				   struct data_loc_info *dloc,
> +				   struct disasm_line *dl,
> +				   struct annotated_op_loc *src,
> +				   struct annotated_op_loc *dst)
> +{
> +	struct type_state_reg snapshots[2];
> +	struct type_state_reg *src_states[2] = {};
> +	int mem_spacing = 0;
> +
> +	if (!src->mem_ref ||  /* exclude PC-relative loads */
> +	    !has_reg_type(state, src->reg1)) {
> +		/* Invalidate tracked destination registers */
> +		if (has_reg_type(state, dst->reg1))
> +			invalidate_reg_state(&state->regs[dst->reg1]);
> +		if (dst->multi_regs && has_reg_type(state, dst->reg2))
> +			invalidate_reg_state(&state->regs[dst->reg2]);
> +		goto out_adjust;
> +	}
> +
> +	/*
> +	 * Snapshot source register states before updating destination registers.
> +	 * This preserves the original source state for aliased loads (e.g.,
> +	 * ldp x0, x1, [x0]), where updating the first destination may overwrite
> +	 * the source register.
> +	 */
> +	snapshots[0] = state->regs[src->reg1];
> +	src_states[0] = &snapshots[0];
> +	if (src->multi_regs && has_reg_type(state, src->reg2)) {
> +		snapshots[1] = state->regs[src->reg2];
> +		src_states[1] = &snapshots[1];
> +	}
> +
> +	/* Handle the first destination register */
> +	if (has_reg_type(state, dst->reg1)) {
> +		if (propagate_load_reg_state(state, dloc, dl, dst->reg1,
> +					     src, src_states, mem_spacing))
> +			invalidate_reg_state(&state->regs[dst->reg1]);
> +	}
> +
> +	if (!dst->multi_regs || !has_reg_type(state, dst->reg2))
> +		goto out_adjust;

[Severity: Medium]
What happens here when an ldp instruction uses the zero register (xzr or
wzr) as its first destination operand, such as "ldp xzr, x19, [sp], #16"
or "ldp xzr, x1, [x0]"?

In update_load_insn_state(), dst->reg1 is guarded by has_reg_type(state,
dst->reg1) without returning early, and arm64__reg_size() recognizes
xzr/wzr via arm64__is_reg() so dst->reg2 can still be updated or
invalidated.

However, when update_insn_state_arm64() calls
annotate_get_insn_location() -> extract_op_location_arm64(),
arch__dwarf_regnum() returns -1 for xzr and wzr, and
extract_op_location_arm64() returns before parsing reg2:

tools/perf/util/annotate-arch/annotate-arm64.c:extract_op_location_arm64() {
	...
	/* Extract the primary register */
	op_loc->reg1 = arch__dwarf_regnum(arch, s);
	if (op_loc->reg1 == -1)
		return;

	s = next_operand_field(s);
	if (s == NULL)
		return;

	/* Extract secondary register or immediate offset */
	if (op_loc->multi_regs) {
		op_loc->reg2 = arch__dwarf_regnum(arch, s);
	...
}

Doesn't this leave dst->reg2 as -1, causing update_load_insn_state() (and
invalidate_unhandled_insn_regs()) to skip the second register instead of
propagating its type or invalidating its previous state?

> +
> +	/* Handle the second destination register */
> +	if (!strcmp(dl->ins.name, "ldpsw"))
> +		mem_spacing = 4;  /* ldpsw loads two 32-bit signed words (4-byte spacing) */
> +	else
> +		mem_spacing = arm64__reg_size(dl->ops.target.raw);
> +
> +	if (mem_spacing < 0 ||
> +	    propagate_load_reg_state(state, dloc, dl, dst->reg2,
> +				     src, src_states, mem_spacing))
> +		invalidate_reg_state(&state->regs[dst->reg2]);
> +
> +out_adjust:
> +	adjust_reg_index_state(state, dloc, dl, src);
> +}

[ ... ]

>

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1792411435.git.wutengda@huaweicloud.com?part=5

  reply	other threads:[~2026-10-20 14:36 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-20 13:44 [PATCH v8 00/15] perf annotate arm64: Support instruction tracking for data type profiling Tengda Wu
2026-10-20 13:44 ` [PATCH v8 01/15] perf annotate-data: Extract invalidate_reg_state() as a common helper Tengda Wu
2026-10-20 13:57   ` sashiko-bot
2026-10-20 13:44 ` [PATCH v8 02/15] perf annotate-arm64: Enable instruction tracking support Tengda Wu
2026-10-20 14:05   ` sashiko-bot
2026-10-20 13:44 ` [PATCH v8 03/15] perf annotate-data: Add arch_get_reg_offset helper Tengda Wu
2026-10-20 14:13   ` sashiko-bot
2026-10-20 13:45 ` [PATCH v8 04/15] perf annotate-arm64: Track return type after call instructions Tengda Wu
2026-10-20 14:15   ` sashiko-bot
2026-10-20 13:45 ` [PATCH v8 05/15] perf annotate-arm64: Support load instruction tracking Tengda Wu
2026-10-20 14:36   ` sashiko-bot [this message]
2026-10-20 13:45 ` [PATCH v8 06/15] perf annotate-arm64: Support store " Tengda Wu
2026-10-20 14:39   ` sashiko-bot
2026-10-20 13:45 ` [PATCH v8 07/15] perf annotate-data: Expand type_state_reg imm_value to u64 Tengda Wu
2026-10-20 14:43   ` sashiko-bot
2026-10-20 13:45 ` [PATCH v8 08/15] perf annotate-data: Track imm_value for stack variables Tengda Wu
2026-10-20 14:46   ` sashiko-bot
2026-10-20 13:45 ` [PATCH v8 09/15] perf annotate-x86: Delete stale stack state on store of untracked register Tengda Wu
2026-10-20 14:50   ` sashiko-bot
2026-10-20 13:45 ` [PATCH v8 10/15] perf annotate-arm64: Support stack variable tracking Tengda Wu
2026-10-20 14:59   ` sashiko-bot
2026-10-20 13:45 ` [PATCH v8 11/15] perf annotate-arm64: Support 'mov' instruction tracking Tengda Wu
2026-10-20 15:01   ` sashiko-bot
2026-10-20 13:45 ` [PATCH v8 12/15] perf annotate-arm64: Support 'add' " Tengda Wu
2026-10-20 15:05   ` sashiko-bot
2026-10-20 13:45 ` [PATCH v8 13/15] perf annotate-arm64: Support 'adrp' instruction to track global variables Tengda Wu
2026-10-20 15:15   ` sashiko-bot
2026-10-20 13:45 ` [PATCH v8 14/15] perf annotate-arm64: Support per-cpu variable access tracking Tengda Wu
2026-10-20 15:24   ` sashiko-bot
2026-10-20 13:45 ` [PATCH v8 15/15] perf annotate-arm64: Support 'mrs' instruction to track 'current' pointer Tengda Wu
2026-10-20 15:30   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-179159@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=wutengda@huaweicloud.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.