* [PATCH v7 00/15] perf annotate arm64: Support instruction tracking for data type profiling
@ 2026-10-13 13:27 Tengda Wu
2026-10-13 13:27 ` [PATCH v7 01/15] perf annotate-data: Extract invalidate_reg_state() as a common helper Tengda Wu
` (14 more replies)
0 siblings, 15 replies; 31+ messages in thread
From: Tengda Wu @ 2026-10-13 13:27 UTC (permalink / raw)
To: Namhyung Kim, james.clark, xueshuai, Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, leo.yan, Li Huafei, Ian Rogers, Kim Phillips,
Mark Rutland, Ingo Molnar, Bill Wendling, Nick Desaulniers,
Alexander Shishkin, Adrian Hunter, Zecheng Li, linux-perf-users,
linux-kernel, llvm, Tengda Wu
This series adds arm64 support to perf's data type profiling by
implementing instruction tracking for the arm64 architecture.
Patches 01-11 of v6 have already been merged. This version only
contains the remaining instruction tracking part, renumbered from 01.
The main changes since v6 include:
v6: https://lore.kernel.org/all/cover.1789521520.git.wutengda@huaweicloud.com/
* Rebase on the latest tree, since flex array support patches have been
merged recently.
* Invalidate lifetime in propagate_load_reg_state(). (Sashiko)
* Remove the has_reg_type() guard in update_store_insn_state() to avoid
skipping the stack state invalidation logic. (Sashiko)
* Fix the issue where TSR_KIND_PERCPU_BASE fails to retry as expected. (Sashiko)
Patch organization
==================
Patches 1-3: Shared infrastructure. Extract invalidate_reg_state() as
a common helper, add the arch_get_reg_offset() helper for
computing operand base offsets, and wire up the arm64
entry points (arch_supports_insn_tracking(),
init_type_state(), and update_insn_state_arm64()).
Patches 4-6: Core instruction tracking for arm64: function return
types after calls, load instructions (ldr/ldp and their
addressing modes), and store instructions (str/stp).
Patches 7-9: Shared data structure improvements and an x86 fix.
Expand type_state_reg.imm_value to u64 so 64-bit
addresses can be tracked, preserve imm_value for stack
variables, and delete stale stack state on store of an
untracked register on x86.
Patches 10-15: Remaining arm64 patterns: stack variable tracking,
'mov' (register and immediate forms), 'add' member
address calculation, 'adrp' global variable tracking,
per-cpu variable access, and 'mrs sp_el0' to resolve the
'current' pointer.
Each patch's type profiling results are as follows:
Patch | Feature | no_sym | no_var | no_typeinfo | bad_offset | insn_track | ok(%)
------+----------------------------+--------+--------+-------------+------------+------------+------
base | baseline | 6 | 493 | - | - | - | 56.2%
0002 | enable insn tracking | 6 | 42 | 437 | 2 | 12 | 57.2%
0005 | support 'load' insn | 6 | 42 | 398 | 1 | 52 | 60.7%
0006 | support 'store' insn | 6 | 42 | 398 | 1 | 52 | 60.7%
0010 | support stack variable | 6 | 42 | 391 | 1 | 59 | 61.3%
0011 | support 'mov' insn | 6 | 42 | 372 | 3 | 76 | 62.8%
0012 | support 'add' insn | 6 | 42 | 318 | 7 | 126 | 67.2%
0013 | support 'adrp' insn | 6 | 42 | 238 | 8 | 205 | 74.2%
0014 | support per-cpu variable | 6 | 42 | 233 | 8 | 210 | 74.6%
0015 | support 'mrs' insn | 6 | 42 | 230 | 8 | 213 | 74.9%
Testing
=======
Tested on arm64 (all passed):
# perf test -v "perf data type profiling tests"
81: perf data type profiling tests : Ok
=== Test Summary ===
Passed main tests : 1
Passed subtests : 0
Skipped tests : 0
Failed tests : 0
Tested on x86. The profiling results show no change before/after applying
this patch series:
before : total 880, ok 711 (80.8%), bad 169 (19.2%)
after : total 880, ok 711 (80.8%), bad 169 (19.2%)
Changelog
=========
v6 -> v7:
- v6: https://lore.kernel.org/all/cover.1789521520.git.wutengda@huaweicloud.com/
- Invalidate lifetime in propagate_load_reg_state().
- Remove the has_reg_type() guard in update_store_insn_state().
- Fix the issue where TSR_KIND_PERCPU_BASE fails to retry as expected.
Please let me know if you have any feedback.
Thanks,
Tengda
Tengda Wu (15):
perf annotate-data: Extract invalidate_reg_state() as a common helper
perf annotate-arm64: Enable instruction tracking support
perf annotate-data: Add arch_get_reg_offset helper
perf annotate-arm64: Track return type after call instructions
perf annotate-arm64: Support load instruction tracking
perf annotate-arm64: Support store instruction tracking
perf annotate-data: Expand type_state_reg imm_value to u64
perf annotate-data: Track imm_value for stack variables
perf annotate-x86: Delete stale stack state on store of untracked
register
perf annotate-arm64: Support stack variable tracking
perf annotate-arm64: Support 'mov' instruction tracking
perf annotate-arm64: Support 'add' instruction tracking
perf annotate-arm64: Support 'adrp' instruction to track global
variables
perf annotate-arm64: Support per-cpu variable access tracking
perf annotate-arm64: Support 'mrs' instruction to track 'current'
pointer
.../perf/util/annotate-arch/annotate-arm64.c | 750 ++++++++++++++++++
tools/perf/util/annotate-arch/annotate-x86.c | 38 +-
tools/perf/util/annotate-data.c | 209 ++++-
tools/perf/util/annotate-data.h | 14 +-
4 files changed, 963 insertions(+), 48 deletions(-)
base-commit: aac26bee2287c88af5be5a5ff96d783b19a28790
--
2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v7 01/15] perf annotate-data: Extract invalidate_reg_state() as a common helper
2026-10-13 13:27 [PATCH v7 00/15] perf annotate arm64: Support instruction tracking for data type profiling Tengda Wu
@ 2026-10-13 13:27 ` Tengda Wu
2026-10-13 13:34 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 02/15] perf annotate-arm64: Enable instruction tracking support Tengda Wu
` (13 subsequent siblings)
14 siblings, 1 reply; 31+ messages in thread
From: Tengda Wu @ 2026-10-13 13:27 UTC (permalink / raw)
To: Namhyung Kim, james.clark, xueshuai, Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, leo.yan, Li Huafei, Ian Rogers, Kim Phillips,
Mark Rutland, Ingo Molnar, Bill Wendling, Nick Desaulniers,
Alexander Shishkin, Adrian Hunter, Zecheng Li, linux-perf-users,
linux-kernel, llvm, Tengda Wu
The invalidate_reg_state() function is currently static and only used
within the x86 data type profiling implementation. To prepare for adding
arm64 instruction tracking support, extract it as a common helper that
can be shared across architectures.
No functional change intended.
Reviewed-by: Shuai Xue <xueshuai@linux.alibaba.com>
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
---
tools/perf/util/annotate-arch/annotate-x86.c | 9 ---------
tools/perf/util/annotate-data.c | 9 +++++++++
tools/perf/util/annotate-data.h | 1 +
3 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/tools/perf/util/annotate-arch/annotate-x86.c b/tools/perf/util/annotate-arch/annotate-x86.c
index 1acf31a2c759..aa381d25a63b 100644
--- a/tools/perf/util/annotate-arch/annotate-x86.c
+++ b/tools/perf/util/annotate-arch/annotate-x86.c
@@ -207,15 +207,6 @@ static int x86__cpuid_parse(struct arch *arch, const char *cpuid)
}
#ifdef HAVE_LIBDW_SUPPORT
-static void invalidate_reg_state(struct type_state_reg *reg)
-{
- reg->kind = TSR_KIND_INVALID;
- reg->ok = false;
- reg->lifetime_active = false;
- reg->lifetime_end = 0;
- reg->copied_from = -1;
-}
-
static void update_insn_state_x86(struct type_state *state,
struct data_loc_info *dloc, Dwarf_Die *cu_die,
struct disasm_line *dl)
diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c
index 19a6ecd67f28..32af1be4e451 100644
--- a/tools/perf/util/annotate-data.c
+++ b/tools/perf/util/annotate-data.c
@@ -748,6 +748,15 @@ struct type_state_stack *findnew_stack_state(struct type_state *state,
return stack;
}
+void invalidate_reg_state(struct type_state_reg *reg)
+{
+ reg->kind = TSR_KIND_INVALID;
+ reg->ok = false;
+ reg->lifetime_active = false;
+ reg->lifetime_end = 0;
+ reg->copied_from = -1;
+}
+
/* Maintain a cache for quick global variable lookup */
struct global_var_entry {
struct rb_node node;
diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h
index bbf4fd35c1d7..d0dc056fb13a 100644
--- a/tools/perf/util/annotate-data.h
+++ b/tools/perf/util/annotate-data.h
@@ -267,6 +267,7 @@ void set_stack_state(struct type_state_stack *stack, int offset, u8 kind,
Dwarf_Die *type_die, int ptr_offset);
struct type_state_stack *find_stack_state(struct type_state *state,
int offset);
+void invalidate_reg_state(struct type_state_reg *reg);
bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc,
u64 ip, u64 var_addr, int *var_offset,
Dwarf_Die *type_die);
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v7 02/15] perf annotate-arm64: Enable instruction tracking support
2026-10-13 13:27 [PATCH v7 00/15] perf annotate arm64: Support instruction tracking for data type profiling Tengda Wu
2026-10-13 13:27 ` [PATCH v7 01/15] perf annotate-data: Extract invalidate_reg_state() as a common helper Tengda Wu
@ 2026-10-13 13:28 ` Tengda Wu
2026-10-13 13:38 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 03/15] perf annotate-data: Add arch_get_reg_offset helper Tengda Wu
` (12 subsequent siblings)
14 siblings, 1 reply; 31+ messages in thread
From: Tengda Wu @ 2026-10-13 13:28 UTC (permalink / raw)
To: Namhyung Kim, james.clark, xueshuai, Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, leo.yan, Li Huafei, Ian Rogers, Kim Phillips,
Mark Rutland, Ingo Molnar, Bill Wendling, Nick Desaulniers,
Alexander Shishkin, Adrian Hunter, Zecheng Li, linux-perf-users,
linux-kernel, llvm, Tengda Wu
Enable basic instruction tracking for arm64 by implementing three
essential functions in the find_data_type_block() call path:
find_data_type_block
-> arch_supports_insn_tracking (1)
-> find_data_type_insn
-> init_type_state (2)
-> update_var_state
-> update_insn_state (3)
Changes:
* arch_supports_insn_tracking(): add arm64 to the list of supported
architectures, allowing find_data_type_block() to proceed with data
type analysis.
* init_type_state(): correctly identify ret_reg, stack_reg, and
caller-saved registers for arm64 during type state initialization.
* update_insn_state(): add the update_insn_state_arm64() callback with
conservative register invalidation for call instructions and those with
destination register(s), preventing stale type propagation. Full
instruction-level analysis support will be added incrementally in
later patches.
With these changes, arm64 gains support for basic variable type
inference during instruction tracking.
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Li Huafei <lihuafei1@huawei.com>
Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
---
.../perf/util/annotate-arch/annotate-arm64.c | 78 +++++++++++++++++++
tools/perf/util/annotate-data.c | 15 +++-
2 files changed, 92 insertions(+), 1 deletion(-)
diff --git a/tools/perf/util/annotate-arch/annotate-arm64.c b/tools/perf/util/annotate-arch/annotate-arm64.c
index 6549535961a9..d6f3d180cb7d 100644
--- a/tools/perf/util/annotate-arch/annotate-arm64.c
+++ b/tools/perf/util/annotate-arch/annotate-arm64.c
@@ -9,6 +9,10 @@
#include <regex.h>
#include "../annotate.h"
#include "../disasm.h"
+#include "../annotate-data.h"
+#include "../debug.h"
+#include "../map.h"
+#include "../symbol.h"
struct arch_arm64 {
struct arch arch;
@@ -448,6 +452,77 @@ static void extract_op_location_arm64(const struct arch *arch,
}
}
+#ifdef HAVE_LIBDW_SUPPORT
+static bool is_readonly_branch_or_cmp(const char *name)
+{
+ return !strncmp(name, "cb", 2) || !strncmp(name, "tb", 2) ||
+ !strcmp(name, "tst") || !strcmp(name, "teq") ||
+ !strcmp(name, "cmp") || !strcmp(name, "cmn") ||
+ !strcmp(name, "ccmp") || !strcmp(name, "ccmn");
+}
+
+static void update_insn_state_arm64(struct type_state *state,
+ struct data_loc_info *dloc, Dwarf_Die *cu_die __maybe_unused,
+ struct disasm_line *dl)
+{
+ struct annotated_insn_loc loc;
+ struct annotated_op_loc *dst = &loc.ops[INSN_OP_TARGET];
+ u32 insn_offset = dl->al.offset;
+
+ /* Skip read-only instructions that do not affect register type state */
+ if (is_readonly_branch_or_cmp(dl->ins.name))
+ return;
+
+ if (annotate_get_insn_location(dloc->arch, dl, &loc) < 0)
+ return;
+
+ /*
+ * Invalidate caller-saved registers on function calls per ARM64 AAPCS64
+ * ABI, unless DWARF location info indicates the register remains valid
+ * beyond the call address.
+ */
+ if (ins__is_call(&dl->ins)) {
+ struct symbol *func = dl->ops.target.sym;
+ const char *call_name;
+ u64 call_addr;
+
+ call_name = func ? func->name : dl->ops.target.name;
+ pr_debug_dtp("call [%x] %s\n", insn_offset, call_name ?: "<unknown>");
+
+ /* Invalidate caller-saved registers after call */
+ call_addr = map__rip_2objdump(dloc->ms->map,
+ dloc->ms->sym->start + dl->al.offset);
+ for (unsigned int i = 0; i < ARRAY_SIZE(state->regs); i++) {
+ struct type_state_reg *reg = &state->regs[i];
+
+ if (!reg->caller_saved)
+ continue;
+ /* Keep register valid within DWARF location lifetime */
+ if (reg->lifetime_active && call_addr < reg->lifetime_end)
+ continue;
+ invalidate_reg_state(reg);
+ }
+ return;
+ }
+
+ /*
+ * Invalidate destination register(s) for unsupported instructions to
+ * prevent stale type info from propagating to subsequent instructions.
+ */
+ if (has_reg_type(state, dst->reg1) && !dst->mem_ref) {
+ pr_debug_dtp("%s [%x] invalidate reg%d",
+ dl->ins.name, insn_offset, dst->reg1);
+ invalidate_reg_state(&state->regs[dst->reg1]);
+ if (dst->multi_regs && has_reg_type(state, dst->reg2)) {
+ pr_debug_dtp(" and reg%d", dst->reg2);
+ invalidate_reg_state(&state->regs[dst->reg2]);
+ }
+ pr_debug_dtp("\n");
+ return;
+ }
+}
+#endif
+
const struct arch *arch__new_arm64(const struct e_machine_and_e_flags *id,
const char *cpuid __maybe_unused)
{
@@ -467,6 +542,9 @@ const struct arch *arch__new_arm64(const struct e_machine_and_e_flags *id,
arch->objdump.imm_char = '#';
arch->associate_instruction_ops = arm64__associate_instruction_ops;
arch->extract_op_location = extract_op_location_arm64;
+#ifdef HAVE_LIBDW_SUPPORT
+ arch->update_insn_state = update_insn_state_arm64;
+#endif
/* bl, blr */
err = regcomp(&arm->call_insn, "^blr?$", REG_EXTENDED);
diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c
index 32af1be4e451..398795ba3694 100644
--- a/tools/perf/util/annotate-data.c
+++ b/tools/perf/util/annotate-data.c
@@ -29,6 +29,7 @@
/* register number of the stack pointer */
#define X86_REG_SP 7
+#define ARM64_REG_SP 31
static void delete_var_types(struct die_var_type *var_types);
@@ -179,6 +180,17 @@ static void init_type_state(struct type_state *state, const struct arch *arch)
state->regs[11].caller_saved = true;
state->ret_reg = 0;
state->stack_reg = X86_REG_SP;
+ } else if (arch__is_arm64(arch)) {
+ /*
+ * Mark x0..x18 as caller-saved. x30 (LR) is intentionally
+ * omitted from the caller_saved set: it is clobbered by
+ * calls, but holds only the return address and is not used
+ * to carry data type information.
+ */
+ for (int i = 0; i < 19; i++)
+ state->regs[i].caller_saved = true;
+ state->ret_reg = 0;
+ state->stack_reg = ARM64_REG_SP;
}
}
@@ -1543,7 +1555,8 @@ static enum type_match_result find_data_type_insn(struct data_loc_info *dloc,
static int arch_supports_insn_tracking(struct data_loc_info *dloc)
{
- if ((arch__is_x86(dloc->arch)) || (arch__is_powerpc(dloc->arch)))
+ if (arch__is_x86(dloc->arch) || arch__is_powerpc(dloc->arch) ||
+ arch__is_arm64(dloc->arch))
return 1;
return 0;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v7 03/15] perf annotate-data: Add arch_get_reg_offset helper
2026-10-13 13:27 [PATCH v7 00/15] perf annotate arm64: Support instruction tracking for data type profiling Tengda Wu
2026-10-13 13:27 ` [PATCH v7 01/15] perf annotate-data: Extract invalidate_reg_state() as a common helper Tengda Wu
2026-10-13 13:28 ` [PATCH v7 02/15] perf annotate-arm64: Enable instruction tracking support Tengda Wu
@ 2026-10-13 13:28 ` Tengda Wu
2026-10-13 13:38 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 04/15] perf annotate-arm64: Track return type after call instructions Tengda Wu
` (11 subsequent siblings)
14 siblings, 1 reply; 31+ messages in thread
From: Tengda Wu @ 2026-10-13 13:28 UTC (permalink / raw)
To: Namhyung Kim, james.clark, xueshuai, Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, leo.yan, Li Huafei, Ian Rogers, Kim Phillips,
Mark Rutland, Ingo Molnar, Bill Wendling, Nick Desaulniers,
Alexander Shishkin, Adrian Hunter, Zecheng Li, linux-perf-users,
linux-kernel, llvm, Tengda Wu
Add a helper to compute the effective offset from a base register
for instruction operands. Currently handles arm64 addressing modes
including post-indexed, single-register, SIB-style indexed with
shift/extension, and constant-offset register pairs.
Fallback to instruction's raw offset for other architectures.
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
---
tools/perf/util/annotate-data.c | 115 ++++++++++++++++++++++++++------
tools/perf/util/annotate-data.h | 4 +-
2 files changed, 98 insertions(+), 21 deletions(-)
diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c
index 398795ba3694..24d82739b2ec 100644
--- a/tools/perf/util/annotate-data.c
+++ b/tools/perf/util/annotate-data.c
@@ -1241,6 +1241,74 @@ static void setup_stack_canary(struct data_loc_info *dloc)
}
}
+int arch_get_reg_offset(const struct arch *arch, struct annotated_op_loc *op_loc,
+ int breg, struct type_state *state, bool apply_index,
+ int *offset)
+{
+ if (arch__is_arm64(arch)) {
+ int reg2;
+
+ /* Post-indexed addressing: offset is 0 when not applying index */
+ if (op_loc->addr_mode == PERF_AAM_POST_INDEX && !apply_index) {
+ *offset = 0;
+ return 0;
+ }
+
+ /* Single-register addressing: return the stored offset directly */
+ if (!op_loc->multi_regs) {
+ *offset = op_loc->offset;
+ return 0;
+ }
+
+ /*
+ * SIB (Scale-Index-Base) style indexed addressing, e.g.:
+ * Array element load: ldr dst, [base, index, lsl #3]
+ * Array element load: ldr dst, [base, index, uxtw #3]
+ * Array address calc: add dst, base, index lsl #3
+ *
+ * The index reg only computes element offset without modifying
+ * the underlying data type; the dst type is inherited from base.
+ * Therefore, the base reg offset can be treated as 0.
+ */
+ if (op_loc->extend_type || op_loc->shift_type) {
+ /* A memory reference implies breg is a pointer. */
+ if (op_loc->mem_ref) {
+ *offset = 0;
+ return 0;
+ }
+ /*
+ * Otherwise, require breg to be a known pointer to avoid
+ * treating integer arithmetic as indexed address calculation.
+ */
+ if (has_reg_type(state, breg) && state->regs[breg].ok &&
+ (state->regs[breg].kind == TSR_KIND_POINTER ||
+ (state->regs[breg].kind == TSR_KIND_TYPE &&
+ dwarf_tag(&state->regs[breg].type) == DW_TAG_pointer_type))) {
+ *offset = 0;
+ return 0;
+ }
+ return -1;
+ }
+
+ /*
+ * For register-based addressing without shift/extension,
+ * reg2 may be a constant offset. Use its value as the offset
+ * from the base register.
+ */
+ reg2 = op_loc->reg1 == breg ? op_loc->reg2 : op_loc->reg1;
+ if (has_reg_type(state, reg2) && state->regs[reg2].ok &&
+ state->regs[reg2].kind == TSR_KIND_CONST) {
+ *offset = (s64)state->regs[reg2].imm_value;
+ return 0;
+ }
+
+ return -1;
+ }
+
+ *offset = op_loc->offset;
+ return 0;
+}
+
/*
* It's at the target address, check if it has a matching type.
* It returns PERF_TMR_BAIL_OUT when it looks up per-cpu variables which
@@ -1254,18 +1322,25 @@ static enum type_match_result check_matching_type(struct type_state *state,
{
u32 insn_offset = dl->al.offset;
int reg = dloc->op->reg1;
- int offset = dloc->op->offset;
- const char *offset_sign = "";
+ int offset;
+ const char *offset_sign;
bool retry = true;
- if (offset < 0) {
- offset = -offset;
- offset_sign = "-";
+again:
+ if (arch_get_reg_offset(dloc->arch, dloc->op, reg, state, false, &offset)) {
+ /*
+ * Fall back to the instruction's offset. This prevents the
+ * register type of the instruction from being completely lost.
+ * Compared to dropping this type inference entirely, providing
+ * a rough type hint is likely more useful.
+ */
+ offset = dloc->op->offset;
}
-again:
+ offset_sign = offset < 0 ? "-" : "";
+
pr_debug_dtp("chk [%x] reg%d offset=%s%#x ok=%d kind=%d ",
- insn_offset, reg, offset_sign, offset,
+ insn_offset, reg, offset_sign, abs(offset),
state->regs[reg].ok, state->regs[reg].kind);
if (!state->regs[reg].ok)
@@ -1288,7 +1363,7 @@ static enum type_match_result check_matching_type(struct type_state *state,
*/
ptr_type = die_get_pointer_type(&state->regs[reg].type, &ptr_die);
if (!ptr_type) {
- if (dloc->op->offset < 0 && reg != state->stack_reg)
+ if (offset < 0 && reg != state->stack_reg)
goto check_kernel;
return PERF_TMR_NO_POINTER;
@@ -1298,7 +1373,7 @@ static enum type_match_result check_matching_type(struct type_state *state,
if (__die_get_real_type(ptr_type, type_die) == NULL)
return PERF_TMR_NO_POINTER;
- dloc->type_offset = dloc->op->offset + state->regs[reg].offset;
+ dloc->type_offset = offset + state->regs[reg].offset;
if (dwarf_tag(type_die) == DW_TAG_typedef)
die_get_real_type(type_die, &sized_type);
@@ -1322,7 +1397,7 @@ static enum type_match_result check_matching_type(struct type_state *state,
*/
*type_die = state->regs[reg].type;
- dloc->type_offset = dloc->op->offset + state->regs[reg].offset;
+ dloc->type_offset = offset + state->regs[reg].offset;
return check_type_offset(type_die, dloc->type_offset);
}
@@ -1336,7 +1411,7 @@ static enum type_match_result check_matching_type(struct type_state *state,
*/
*type_die = state->regs[reg].type;
- dloc->type_offset = dloc->op->offset;
+ dloc->type_offset = offset;
if (check_type_offset(type_die, dloc->type_offset) != PERF_TMR_OK)
return PERF_TMR_BAIL_OUT;
@@ -1358,7 +1433,7 @@ static enum type_match_result check_matching_type(struct type_state *state,
}
if (state->regs[reg].kind == TSR_KIND_PERCPU_BASE) {
- u64 var_addr = dloc->op->offset;
+ u64 var_addr = (s64) offset;
int var_offset;
pr_debug_dtp("percpu var");
@@ -1385,7 +1460,7 @@ static enum type_match_result check_matching_type(struct type_state *state,
if (state->regs[reg].kind == TSR_KIND_CONST &&
dso__kernel(map__dso(dloc->ms->map))) {
- if (dloc->op->offset < 0 && reg != state->stack_reg && reg != dloc->fbreg)
+ if (offset < 0 && reg != state->stack_reg && reg != dloc->fbreg)
goto check_kernel;
}
check_non_register:
@@ -1394,7 +1469,7 @@ static enum type_match_result check_matching_type(struct type_state *state,
pr_debug_dtp("%s", reg == dloc->fbreg ? "fbreg" : "stack");
- stack = find_stack_state(state, dloc->type_offset);
+ stack = find_stack_state(state, offset);
if (stack == NULL) {
if (retry) {
pr_debug_dtp(" : retry\n");
@@ -1417,7 +1492,7 @@ static enum type_match_result check_matching_type(struct type_state *state,
*type_die = stack->type;
/* Update the type offset from the start of slot */
- dloc->type_offset -= stack->offset;
+ dloc->type_offset = offset - stack->offset;
return PERF_TMR_OK;
}
@@ -1435,7 +1510,7 @@ static enum type_match_result check_matching_type(struct type_state *state,
if (reg != fbreg)
return PERF_TMR_NO_TYPE;
- stack = find_stack_state(state, dloc->type_offset - fboff);
+ stack = find_stack_state(state, offset - fboff);
if (stack == NULL) {
if (retry) {
pr_debug_dtp(" : retry\n");
@@ -1458,7 +1533,7 @@ static enum type_match_result check_matching_type(struct type_state *state,
*type_die = stack->type;
/* Update the type offset from the start of slot */
- dloc->type_offset -= fboff + stack->offset;
+ dloc->type_offset = offset - fboff - stack->offset;
return PERF_TMR_OK;
}
@@ -1472,7 +1547,7 @@ static enum type_match_result check_matching_type(struct type_state *state,
arch__is_x86(dloc->arch)) {
pr_debug_dtp("this-cpu var");
- addr = dloc->op->offset;
+ addr = (s64) offset;
if (get_global_var_type(cu_die, dloc, dloc->ip, addr,
&offset, type_die)) {
@@ -1483,8 +1558,8 @@ static enum type_match_result check_matching_type(struct type_state *state,
}
/* Access to global variable like "-0x7dcf0500(,%rdx,8)" */
- if (dloc->op->offset < 0 && reg != state->stack_reg) {
- addr = (s64) dloc->op->offset;
+ if (offset < 0 && reg != state->stack_reg) {
+ addr = (s64) offset;
if (get_global_var_type(cu_die, dloc, dloc->ip, addr,
&offset, type_die)) {
diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h
index d0dc056fb13a..453efdf6afa6 100644
--- a/tools/perf/util/annotate-data.h
+++ b/tools/perf/util/annotate-data.h
@@ -274,7 +274,9 @@ bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc,
bool get_global_var_info(struct data_loc_info *dloc, u64 addr,
const char **var_name, int *var_offset);
void pr_debug_type_name(Dwarf_Die *die, enum type_state_kind kind);
-
+int arch_get_reg_offset(const struct arch *arch, struct annotated_op_loc *op_loc,
+ int breg, struct type_state *state, bool apply_index,
+ int *offset);
#else /* HAVE_LIBDW_SUPPORT */
static inline struct annotated_data_type *
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v7 04/15] perf annotate-arm64: Track return type after call instructions
2026-10-13 13:27 [PATCH v7 00/15] perf annotate arm64: Support instruction tracking for data type profiling Tengda Wu
` (2 preceding siblings ...)
2026-10-13 13:28 ` [PATCH v7 03/15] perf annotate-data: Add arch_get_reg_offset helper Tengda Wu
@ 2026-10-13 13:28 ` Tengda Wu
2026-10-13 13:36 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 05/15] perf annotate-arm64: Support load instruction tracking Tengda Wu
` (10 subsequent siblings)
14 siblings, 1 reply; 31+ messages in thread
From: Tengda Wu @ 2026-10-13 13:28 UTC (permalink / raw)
To: Namhyung Kim, james.clark, xueshuai, Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, leo.yan, Li Huafei, Ian Rogers, Kim Phillips,
Mark Rutland, Ingo Molnar, Bill Wendling, Nick Desaulniers,
Alexander Shishkin, Adrian Hunter, Zecheng Li, linux-perf-users,
linux-kernel, llvm, Tengda Wu
Enable data type profiling to track function return values in arm64
annotations by looking up the DWARF return type of called functions.
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
---
tools/perf/util/annotate-arch/annotate-arm64.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/tools/perf/util/annotate-arch/annotate-arm64.c b/tools/perf/util/annotate-arch/annotate-arm64.c
index d6f3d180cb7d..8df462e5da5a 100644
--- a/tools/perf/util/annotate-arch/annotate-arm64.c
+++ b/tools/perf/util/annotate-arch/annotate-arm64.c
@@ -462,7 +462,7 @@ static bool is_readonly_branch_or_cmp(const char *name)
}
static void update_insn_state_arm64(struct type_state *state,
- struct data_loc_info *dloc, Dwarf_Die *cu_die __maybe_unused,
+ struct data_loc_info *dloc, Dwarf_Die *cu_die,
struct disasm_line *dl)
{
struct annotated_insn_loc loc;
@@ -485,6 +485,8 @@ static void update_insn_state_arm64(struct type_state *state,
struct symbol *func = dl->ops.target.sym;
const char *call_name;
u64 call_addr;
+ struct type_state_reg *tsr;
+ Dwarf_Die type_die;
call_name = func ? func->name : dl->ops.target.name;
pr_debug_dtp("call [%x] %s\n", insn_offset, call_name ?: "<unknown>");
@@ -502,6 +504,20 @@ static void update_insn_state_arm64(struct type_state *state,
continue;
invalidate_reg_state(reg);
}
+
+ /* Update register with the return type (if any) */
+ if (call_name && die_find_func_rettype(cu_die, call_name, &type_die)) {
+ tsr = &state->regs[state->ret_reg];
+ invalidate_reg_state(tsr);
+ tsr->type = type_die;
+ tsr->kind = TSR_KIND_TYPE;
+ tsr->offset = 0;
+ tsr->ok = true;
+
+ pr_debug_dtp("call [%x] return -> reg%d",
+ insn_offset, state->ret_reg);
+ pr_debug_type_name(&type_die, tsr->kind);
+ }
return;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v7 05/15] perf annotate-arm64: Support load instruction tracking
2026-10-13 13:27 [PATCH v7 00/15] perf annotate arm64: Support instruction tracking for data type profiling Tengda Wu
` (3 preceding siblings ...)
2026-10-13 13:28 ` [PATCH v7 04/15] perf annotate-arm64: Track return type after call instructions Tengda Wu
@ 2026-10-13 13:28 ` Tengda Wu
2026-10-13 13:38 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 06/15] perf annotate-arm64: Support store " Tengda Wu
` (9 subsequent siblings)
14 siblings, 1 reply; 31+ messages in thread
From: Tengda Wu @ 2026-10-13 13:28 UTC (permalink / raw)
To: Namhyung Kim, james.clark, xueshuai, Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, leo.yan, Li Huafei, Ian Rogers, Kim Phillips,
Mark Rutland, Ingo Molnar, Bill Wendling, Nick Desaulniers,
Alexander Shishkin, Adrian Hunter, Zecheng Li, linux-perf-users,
linux-kernel, llvm, Tengda Wu
Extend update_insn_state_arm64() to handle load instructions, tracking
register state changes when data is loaded from memory to registers.
Two main categories are considered: standard load (e.g, ldr variants)
and load pair (ldp), for example:
ldr dst, [src, #imm]
ldp dst1, dst2, [src, #imm]
For data type propagation, a load pair can be treated as two standard
loads combined, first loading dst1 and then dst2. The difference is
that when loading dst2, an additional memory spacing 'mem_spacing' after
the first load must be added. This mem_spacing can be derived from the
instruction mnemonic and the size of the dst register. Each load operation
is handled by introducing propagate_load_reg_state().
When processing a load pair, the case where dst and src registers are
the same (e.g., ldp x0, x1, [x0]) also needs to be considered. Therefore,
before propagating data types, a snapshot of the src register's state
must be saved and then passed to propagate_load_reg_state().
Finally, handle the side effects of pre-index and post-index addressing
via adjust_reg_index_state().
A real-world example is shown below:
ffff80008011f5b0 <pick_task_stop>:
ffff80008011f5b8: ldr x0, [x0, #2712] // x0: struct rq* -> task_struct*
* ffff80008011f5c0: ldr w1, [x0, #104]
Before this commit, the type of x0 was incorrectly inferred as 'struct rq':
find data type for 0x68(reg0) at pick_task_stop+0x10
var [8] reg0 offset 0 type='struct rq*'
chk [10] reg0 offset=0x68 ok=1 kind=1 (struct rq*) : Good!
final result: type='struct rq'
After this commit, the type of x0 is correctly inferred as 'struct task_struct':
find data type for 0x68(reg0) at pick_task_stop+0x10
var [8] reg0 offset 0 type='struct rq*'
ldr [8] 0xa98(reg0) -> reg0 type='struct task_struct*'
chk [10] reg0 offset=0x68 ok=1 kind=1 (struct task_struct*) : Good!
final result: type='struct task_struct'
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Li Huafei <lihuafei1@huawei.com>
Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
---
.../perf/util/annotate-arch/annotate-arm64.c | 208 +++++++++++++++++-
1 file changed, 207 insertions(+), 1 deletion(-)
diff --git a/tools/perf/util/annotate-arch/annotate-arm64.c b/tools/perf/util/annotate-arch/annotate-arm64.c
index 8df462e5da5a..fb48bf95b32f 100644
--- a/tools/perf/util/annotate-arch/annotate-arm64.c
+++ b/tools/perf/util/annotate-arch/annotate-arm64.c
@@ -461,11 +461,212 @@ static bool is_readonly_branch_or_cmp(const char *name)
!strcmp(name, "ccmp") || !strcmp(name, "ccmn");
}
+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;
+}
+
+/* Apply addressing mode (pre-index, post-index) to register state */
+static void adjust_reg_index_state(struct type_state *state,
+ struct data_loc_info *dloc,
+ struct disasm_line *dl,
+ struct annotated_op_loc *op_loc)
+{
+ struct type_state_reg *tsr;
+ int reg = op_loc->reg1;
+ int offset;
+
+ if (op_loc->addr_mode != PERF_AAM_PRE_INDEX &&
+ op_loc->addr_mode != PERF_AAM_POST_INDEX)
+ return;
+
+ if (!has_reg_type(state, reg) || !state->regs[reg].ok)
+ return;
+
+ tsr = &state->regs[reg];
+ tsr->copied_from = -1;
+
+ if (arch_get_reg_offset(dloc->arch, op_loc, reg, state, true, &offset)) {
+ invalidate_reg_state(tsr);
+ return;
+ }
+
+ tsr->offset += offset;
+
+ pr_debug_dtp("%s [%x] %s-index %#x(reg%d) -> reg%d", dl->ins.name,
+ (u32) dl->al.offset, op_loc->addr_mode == PERF_AAM_PRE_INDEX ?
+ "pre" : "post", offset, reg, reg);
+ pr_debug_type_name(&tsr->type, tsr->kind);
+}
+
+/*
+ * Match standard load variants (ldr, ldur, ldar, ldp) that follow
+ * straightforward load semantics: memory source on the right
+ * and target registers on the left (written). Excludes exclusive loads
+ * (ldxr, ldxp, etc.) and acquire/exclusive combination variants.
+ */
+static bool is_standard_load_insn(const char *name)
+{
+ return !strncmp(name, "ldr", 3) || /* ldr, ldrb, ldrh, ldrsb, ldrsh, ldrsw */
+ !strncmp(name, "ldur", 4) || /* ldur, ldurb, ldurh, ldursb, ldursh, ldursw */
+ !strncmp(name, "ldar", 4) || /* ldar, ldarb, ldarh */
+ !strncmp(name, "ldp", 3); /* ldp, ldpsw */
+}
+
+/*
+ * For load insns: propagate type from source reg state @src_states to @dreg.
+ *
+ * @mem_spacing accounts for the additional in-memory spacing between the two
+ * loads when handling multi-reg loads (e.g. the second target reg in 'ldp'),
+ * which is added to the reg offset.
+ */
+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, ®_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;
+ 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;
+
+ /* 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);
+}
+
static void update_insn_state_arm64(struct type_state *state,
struct data_loc_info *dloc, Dwarf_Die *cu_die,
struct disasm_line *dl)
{
struct annotated_insn_loc loc;
+ struct annotated_op_loc *src = &loc.ops[INSN_OP_SOURCE];
struct annotated_op_loc *dst = &loc.ops[INSN_OP_TARGET];
u32 insn_offset = dl->al.offset;
@@ -525,7 +726,8 @@ static void update_insn_state_arm64(struct type_state *state,
* Invalidate destination register(s) for unsupported instructions to
* prevent stale type info from propagating to subsequent instructions.
*/
- if (has_reg_type(state, dst->reg1) && !dst->mem_ref) {
+ if (has_reg_type(state, dst->reg1) && !dst->mem_ref &&
+ !is_standard_load_insn(dl->ins.name)) {
pr_debug_dtp("%s [%x] invalidate reg%d",
dl->ins.name, insn_offset, dst->reg1);
invalidate_reg_state(&state->regs[dst->reg1]);
@@ -536,6 +738,10 @@ static void update_insn_state_arm64(struct type_state *state,
pr_debug_dtp("\n");
return;
}
+
+ /* Memory to register transfers */
+ if (is_standard_load_insn(dl->ins.name))
+ update_load_insn_state(state, dloc, dl, src, dst);
}
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v7 06/15] perf annotate-arm64: Support store instruction tracking
2026-10-13 13:27 [PATCH v7 00/15] perf annotate arm64: Support instruction tracking for data type profiling Tengda Wu
` (4 preceding siblings ...)
2026-10-13 13:28 ` [PATCH v7 05/15] perf annotate-arm64: Support load instruction tracking Tengda Wu
@ 2026-10-13 13:28 ` Tengda Wu
2026-10-13 13:36 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 07/15] perf annotate-data: Expand type_state_reg imm_value to u64 Tengda Wu
` (8 subsequent siblings)
14 siblings, 1 reply; 31+ messages in thread
From: Tengda Wu @ 2026-10-13 13:28 UTC (permalink / raw)
To: Namhyung Kim, james.clark, xueshuai, Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, leo.yan, Li Huafei, Ian Rogers, Kim Phillips,
Mark Rutland, Ingo Molnar, Bill Wendling, Nick Desaulniers,
Alexander Shishkin, Adrian Hunter, Zecheng Li, linux-perf-users,
linux-kernel, llvm, Tengda Wu
Extend update_insn_state_arm64() to handle standard store instructions
(str, stur, stlr, stp). Exclusive stores (e.g., stxr, stxp) are omitted
as they exhibit different operand semantics.
Unlike load instructions, a store instruction sets a value in the struct
within the memory where the destination register resides, and does not
alter its type. Therefore, no processing is required for the transfer.
The only point to note is that store instructions support pre-index and
post-index addressing modes, so calling adjust_reg_index_state() is still
necessary to handle their addressing.
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
---
.../perf/util/annotate-arch/annotate-arm64.c | 25 +++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/tools/perf/util/annotate-arch/annotate-arm64.c b/tools/perf/util/annotate-arch/annotate-arm64.c
index fb48bf95b32f..54d9928b536f 100644
--- a/tools/perf/util/annotate-arch/annotate-arm64.c
+++ b/tools/perf/util/annotate-arch/annotate-arm64.c
@@ -661,6 +661,20 @@ static void update_load_insn_state(struct type_state *state,
adjust_reg_index_state(state, dloc, dl, src);
}
+/*
+ * Match standard store variants (str, stur, stlr, stp) that follow
+ * straightforward store semantics: source registers on the left (read-only)
+ * and memory target on the right. Excludes exclusive stores (stxr, stxp, etc.)
+ * which have status/result register side effects.
+ */
+static bool is_standard_store_insn(const char *name)
+{
+ return !strncmp(name, "str", 3) || /* str, strb, strh */
+ !strncmp(name, "stur", 4) || /* stur, sturb, sturh */
+ !strncmp(name, "stlr", 4) || /* stlr, stlrb, stlrh */
+ !strncmp(name, "stp", 3); /* stp */
+}
+
static void update_insn_state_arm64(struct type_state *state,
struct data_loc_info *dloc, Dwarf_Die *cu_die,
struct disasm_line *dl)
@@ -742,6 +756,17 @@ static void update_insn_state_arm64(struct type_state *state,
/* Memory to register transfers */
if (is_standard_load_insn(dl->ins.name))
update_load_insn_state(state, dloc, dl, src, dst);
+ /* Register to memory transfers */
+ else if (is_standard_store_insn(dl->ins.name)) {
+ /*
+ * Ignore transfers since it'd set a value in a struct
+ * and won't change the type.
+ *
+ * Needs to update the pre-index and post-index addressing
+ * modes for the destination register.
+ */
+ adjust_reg_index_state(state, dloc, dl, dst);
+ }
}
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v7 07/15] perf annotate-data: Expand type_state_reg imm_value to u64
2026-10-13 13:27 [PATCH v7 00/15] perf annotate arm64: Support instruction tracking for data type profiling Tengda Wu
` (5 preceding siblings ...)
2026-10-13 13:28 ` [PATCH v7 06/15] perf annotate-arm64: Support store " Tengda Wu
@ 2026-10-13 13:28 ` Tengda Wu
2026-10-13 13:45 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 08/15] perf annotate-data: Track imm_value for stack variables Tengda Wu
` (7 subsequent siblings)
14 siblings, 1 reply; 31+ messages in thread
From: Tengda Wu @ 2026-10-13 13:28 UTC (permalink / raw)
To: Namhyung Kim, james.clark, xueshuai, Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, leo.yan, Li Huafei, Ian Rogers, Kim Phillips,
Mark Rutland, Ingo Molnar, Bill Wendling, Nick Desaulniers,
Alexander Shishkin, Adrian Hunter, Zecheng Li, linux-perf-users,
linux-kernel, llvm, Tengda Wu
The arm64 'adrp + add/ldr' instruction pair involves global variable address
calculation and passing, which requires storing the 64-bit address in
type_state_reg. Currently, there is no field in type_state_reg that can
hold such an address. The most likely candidate for reuse is imm_value,
but it is defined as u32, which limits the size of values it can carry.
To address this, expand imm_value from u32 to u64. Also update related
compilation warnings and fix the sign-extension issue introduced by this
change.
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
---
tools/perf/util/annotate-arch/annotate-x86.c | 4 ++--
tools/perf/util/annotate-data.h | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/tools/perf/util/annotate-arch/annotate-x86.c b/tools/perf/util/annotate-arch/annotate-x86.c
index aa381d25a63b..f5e40cef08ab 100644
--- a/tools/perf/util/annotate-arch/annotate-x86.c
+++ b/tools/perf/util/annotate-arch/annotate-x86.c
@@ -536,11 +536,11 @@ static void update_insn_state_x86(struct type_state *state,
if (src->imm) {
tsr->kind = TSR_KIND_CONST;
- tsr->imm_value = src->offset;
+ tsr->imm_value = (s64)src->offset;
tsr->offset = 0;
tsr->ok = true;
- pr_debug_dtp("mov [%x] imm=%#x -> reg%d\n",
+ pr_debug_dtp("mov [%x] imm=%#"PRIx64" -> reg%d\n",
insn_offset, tsr->imm_value, dst->reg1);
return;
}
diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h
index 453efdf6afa6..12b5b6db5f57 100644
--- a/tools/perf/util/annotate-data.h
+++ b/tools/perf/util/annotate-data.h
@@ -182,7 +182,7 @@ extern struct annotated_data_stat ann_data_stat;
*/
struct type_state_reg {
Dwarf_Die type;
- u32 imm_value;
+ u64 imm_value;
/*
* The offset within the struct that the register points to.
* A value of 0 means the register points to the beginning.
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v7 08/15] perf annotate-data: Track imm_value for stack variables
2026-10-13 13:27 [PATCH v7 00/15] perf annotate arm64: Support instruction tracking for data type profiling Tengda Wu
` (6 preceding siblings ...)
2026-10-13 13:28 ` [PATCH v7 07/15] perf annotate-data: Expand type_state_reg imm_value to u64 Tengda Wu
@ 2026-10-13 13:28 ` Tengda Wu
2026-10-13 13:47 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 09/15] perf annotate-x86: Delete stale stack state on store of untracked register Tengda Wu
` (6 subsequent siblings)
14 siblings, 1 reply; 31+ messages in thread
From: Tengda Wu @ 2026-10-13 13:28 UTC (permalink / raw)
To: Namhyung Kim, james.clark, xueshuai, Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, leo.yan, Li Huafei, Ian Rogers, Kim Phillips,
Mark Rutland, Ingo Molnar, Bill Wendling, Nick Desaulniers,
Alexander Shishkin, Adrian Hunter, Zecheng Li, linux-perf-users,
linux-kernel, llvm, Tengda Wu
Currently, imm_value is tracked in registers but dropped when values
are saved to or loaded from stack variables during type profiling.
If a register of type TSR_KIND_CONST is stored to the stack, its value
will be lost.
Add an imm_value field to struct type_state_stack and update
set_stack_state() and findnew_stack_state() to accept and preserve the
immediate value when updating stack state.
Reviewed-by: Shuai Xue <xueshuai@linux.alibaba.com>
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
---
tools/perf/util/annotate-arch/annotate-x86.c | 8 ++++++--
tools/perf/util/annotate-data.c | 13 +++++++------
tools/perf/util/annotate-data.h | 5 +++--
3 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/tools/perf/util/annotate-arch/annotate-x86.c b/tools/perf/util/annotate-arch/annotate-x86.c
index f5e40cef08ab..21729e153fa0 100644
--- a/tools/perf/util/annotate-arch/annotate-x86.c
+++ b/tools/perf/util/annotate-arch/annotate-x86.c
@@ -591,6 +591,7 @@ static void update_insn_state_x86(struct type_state *state,
tsr->type = stack->type;
tsr->kind = stack->kind;
tsr->offset = stack->ptr_offset;
+ tsr->imm_value = stack->imm_value;
tsr->ok = true;
} else if (die_get_member_type(&stack->type,
offset - stack->offset,
@@ -598,6 +599,7 @@ static void update_insn_state_x86(struct type_state *state,
tsr->type = type_die;
tsr->kind = TSR_KIND_TYPE;
tsr->offset = 0;
+ tsr->imm_value = 0;
tsr->ok = true;
} else {
invalidate_reg_state(tsr);
@@ -773,10 +775,12 @@ static void update_insn_state_x86(struct type_state *state,
*/
if (!stack->compound)
set_stack_state(stack, offset, tsr->kind,
- &tsr->type, tsr->offset);
+ &tsr->type, tsr->offset,
+ tsr->imm_value);
} else {
findnew_stack_state(state, offset, tsr->kind,
- &tsr->type, tsr->offset);
+ &tsr->type, tsr->offset,
+ tsr->imm_value);
}
if (dst->reg1 == fbreg) {
diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c
index 24d82739b2ec..9ed0780d6244 100644
--- a/tools/perf/util/annotate-data.c
+++ b/tools/perf/util/annotate-data.c
@@ -704,7 +704,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, int ptr_offset)
+ Dwarf_Die *type_die, int ptr_offset, u64 imm_value)
{
int tag;
Dwarf_Word size;
@@ -721,8 +721,9 @@ void set_stack_state(struct type_state_stack *stack, int offset, u8 kind,
stack->offset = offset;
stack->ptr_offset = ptr_offset;
stack->kind = kind;
+ stack->imm_value = imm_value;
- if (kind == TSR_KIND_POINTER) {
+ if (kind == TSR_KIND_POINTER || kind == TSR_KIND_CONST) {
stack->compound = false;
return;
}
@@ -743,18 +744,18 @@ 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,
- int ptr_offset)
+ int ptr_offset, u64 imm_value)
{
struct type_state_stack *stack = find_stack_state(state, offset);
if (stack) {
- set_stack_state(stack, offset, kind, type_die, ptr_offset);
+ set_stack_state(stack, offset, kind, type_die, ptr_offset, imm_value);
return stack;
}
stack = malloc(sizeof(*stack));
if (stack) {
- set_stack_state(stack, offset, kind, type_die, ptr_offset);
+ set_stack_state(stack, offset, kind, type_die, ptr_offset, imm_value);
list_add(&stack->list, &state->stack_vars);
}
return stack;
@@ -1058,7 +1059,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, /*ptr_offset=*/0);
+ &mem_die, /*ptr_offset=*/0, /*imm_value=*/0);
if (var->reg == state->stack_reg) {
pr_debug_dtp("var [%"PRIx64"] %#x(reg%d)",
diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h
index 12b5b6db5f57..dccd56759cea 100644
--- a/tools/perf/util/annotate-data.h
+++ b/tools/perf/util/annotate-data.h
@@ -208,6 +208,7 @@ struct type_state_stack {
int size;
bool compound;
u8 kind;
+ u64 imm_value;
};
/*
@@ -262,9 +263,9 @@ bool has_reg_type(struct type_state *state, int reg);
struct type_state_stack *findnew_stack_state(struct type_state *state,
int offset, u8 kind,
Dwarf_Die *type_die,
- int ptr_offset);
+ int ptr_offset, u64 imm_value);
void set_stack_state(struct type_state_stack *stack, int offset, u8 kind,
- Dwarf_Die *type_die, int ptr_offset);
+ Dwarf_Die *type_die, int ptr_offset, u64 imm_value);
struct type_state_stack *find_stack_state(struct type_state *state,
int offset);
void invalidate_reg_state(struct type_state_reg *reg);
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v7 09/15] perf annotate-x86: Delete stale stack state on store of untracked register
2026-10-13 13:27 [PATCH v7 00/15] perf annotate arm64: Support instruction tracking for data type profiling Tengda Wu
` (7 preceding siblings ...)
2026-10-13 13:28 ` [PATCH v7 08/15] perf annotate-data: Track imm_value for stack variables Tengda Wu
@ 2026-10-13 13:28 ` Tengda Wu
2026-10-13 13:44 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 10/15] perf annotate-arm64: Support stack variable tracking Tengda Wu
` (5 subsequent siblings)
14 siblings, 1 reply; 31+ messages in thread
From: Tengda Wu @ 2026-10-13 13:28 UTC (permalink / raw)
To: Namhyung Kim, james.clark, xueshuai, Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, leo.yan, Li Huafei, Ian Rogers, Kim Phillips,
Mark Rutland, Ingo Molnar, Bill Wendling, Nick Desaulniers,
Alexander Shishkin, Adrian Hunter, Zecheng Li, linux-perf-users,
linux-kernel, llvm, Tengda Wu
When a register without a tracked type is stored to a stack slot that
previously held a valid type, the code currently performs an early return.
This leaves the old type information intact in the stack state.
As a result, a stale type bug occurs:
1. A tracked register is stored into a stack slot.
2. The register becomes untracked/invalid (e.g., across a function call).
3. The now-untracked register is stored into the same stack slot.
4. Subsequent loads from that slot erroneously pick up the old stale type
because the stack entry was never invalidated.
Fix this by introducing delete_stack_state() to search and free a stack
entry for a given offset. When storing an untracked or invalid source
register into a stack location, call delete_stack_state() to delete the
stale entry before returning.
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
---
tools/perf/util/annotate-arch/annotate-x86.c | 17 +++++++++++++----
tools/perf/util/annotate-data.c | 10 ++++++++++
tools/perf/util/annotate-data.h | 1 +
3 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/tools/perf/util/annotate-arch/annotate-x86.c b/tools/perf/util/annotate-arch/annotate-x86.c
index 21729e153fa0..3a6ea7e978e0 100644
--- a/tools/perf/util/annotate-arch/annotate-x86.c
+++ b/tools/perf/util/annotate-arch/annotate-x86.c
@@ -753,15 +753,24 @@ static void update_insn_state_x86(struct type_state *state,
}
/* Case 3. register to memory transfers */
if (!src->mem_ref && dst->mem_ref) {
- if (!has_reg_type(state, src->reg1) ||
- !state->regs[src->reg1].ok)
- return;
-
/* Check stack variables with offset */
if (dst->reg1 == fbreg || dst->reg1 == state->stack_reg) {
struct type_state_stack *stack;
int offset = dst->offset - fboff;
+ if (!has_reg_type(state, src->reg1) ||
+ !state->regs[src->reg1].ok) {
+ stack = find_stack_state(state, offset);
+ /*
+ * Preserve compound states when only a member
+ * is overwritten.
+ */
+ if (stack && !stack->compound)
+ delete_stack_state(state, offset);
+
+ return;
+ }
+
tsr = &state->regs[src->reg1];
stack = find_stack_state(state, offset);
diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c
index 9ed0780d6244..1d47db3a9dd9 100644
--- a/tools/perf/util/annotate-data.c
+++ b/tools/perf/util/annotate-data.c
@@ -761,6 +761,16 @@ struct type_state_stack *findnew_stack_state(struct type_state *state,
return stack;
}
+void delete_stack_state(struct type_state *state, int offset)
+{
+ struct type_state_stack *stack = find_stack_state(state, offset);
+
+ if (stack) {
+ list_del(&stack->list);
+ free(stack);
+ }
+}
+
void invalidate_reg_state(struct type_state_reg *reg)
{
reg->kind = TSR_KIND_INVALID;
diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h
index dccd56759cea..425d9ddfad41 100644
--- a/tools/perf/util/annotate-data.h
+++ b/tools/perf/util/annotate-data.h
@@ -268,6 +268,7 @@ void set_stack_state(struct type_state_stack *stack, int offset, u8 kind,
Dwarf_Die *type_die, int ptr_offset, u64 imm_value);
struct type_state_stack *find_stack_state(struct type_state *state,
int offset);
+void delete_stack_state(struct type_state *state, int offset);
void invalidate_reg_state(struct type_state_reg *reg);
bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc,
u64 ip, u64 var_addr, int *var_offset,
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v7 10/15] perf annotate-arm64: Support stack variable tracking
2026-10-13 13:27 [PATCH v7 00/15] perf annotate arm64: Support instruction tracking for data type profiling Tengda Wu
` (8 preceding siblings ...)
2026-10-13 13:28 ` [PATCH v7 09/15] perf annotate-x86: Delete stale stack state on store of untracked register Tengda Wu
@ 2026-10-13 13:28 ` Tengda Wu
2026-10-13 13:44 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 11/15] perf annotate-arm64: Support 'mov' instruction tracking Tengda Wu
` (4 subsequent siblings)
14 siblings, 1 reply; 31+ messages in thread
From: Tengda Wu @ 2026-10-13 13:28 UTC (permalink / raw)
To: Namhyung Kim, james.clark, xueshuai, Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, leo.yan, Li Huafei, Ian Rogers, Kim Phillips,
Mark Rutland, Ingo Molnar, Bill Wendling, Nick Desaulniers,
Alexander Shishkin, Adrian Hunter, Zecheng Li, linux-perf-users,
linux-kernel, llvm, Tengda Wu
Extend update_insn_state_arm64() to track data types stored on the
stack.
The implementation handles:
1. Stack Loads: 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: Update or create new stack state entries when
a tracked register type is stored to the stack.
Similar to loads, stores also support saving one or two registers
(in the case of 'stp'). Therefore, propagate_store_reg_state() is
introduced.
With these changes, the instruction tracker can now 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@huaweicloud.com>
---
.../perf/util/annotate-arch/annotate-arm64.c | 164 ++++++++++++++++--
1 file changed, 154 insertions(+), 10 deletions(-)
diff --git a/tools/perf/util/annotate-arch/annotate-arm64.c b/tools/perf/util/annotate-arch/annotate-arm64.c
index 54d9928b536f..d17d9b2456dc 100644
--- a/tools/perf/util/annotate-arch/annotate-arm64.c
+++ b/tools/perf/util/annotate-arch/annotate-arm64.c
@@ -542,6 +542,8 @@ static int propagate_load_reg_state(struct type_state *state,
u32 insn_offset = dl->al.offset;
int sreg = src->reg1;
int reg_offset;
+ int fbreg = dloc->fbreg;
+ int fboff = 0;
if (!has_reg_type(state, dreg))
return -1;
@@ -551,12 +553,57 @@ static int propagate_load_reg_state(struct type_state *state,
tsr->lifetime_active = false;
tsr->lifetime_end = 0;
+ 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;
+ }
+
retry:
if (arch_get_reg_offset(dloc->arch, src, sreg, state, false, ®_offset))
goto load_non_regoff;
reg_offset += mem_spacing;
+ /* Check stack variables with offset */
+ if (sreg != -1 && (sreg == fbreg || sreg == state->stack_reg)) {
+ struct type_state_stack *stack;
+ int offset = sreg == fbreg ? reg_offset - fboff : reg_offset;
+
+ stack = find_stack_state(state, offset);
+ if (stack == NULL) {
+ return -1;
+ } else if (!stack->compound) {
+ tsr->type = stack->type;
+ tsr->kind = stack->kind;
+ tsr->offset = stack->ptr_offset;
+ tsr->imm_value = stack->imm_value;
+ 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->imm_value = 0;
+ tsr->ok = true;
+ } else {
+ return -1;
+ }
+
+ if (sreg == fbreg) {
+ pr_debug_dtp("%s [%x] -%#x(stack) -> reg%d",
+ dl->ins.name, insn_offset, -offset, dreg);
+ } else {
+ pr_debug_dtp("%s [%x] %#x(reg%d) -> reg%d",
+ dl->ins.name, insn_offset, offset, sreg, dreg);
+ }
+ pr_debug_type_name(&tsr->type, tsr->kind);
+ return 0;
+ }
+
if (!src_tsr || !src_tsr->ok)
return -1;
@@ -675,6 +722,111 @@ static bool is_standard_store_insn(const char *name)
!strncmp(name, "stp", 3); /* stp */
}
+/*
+ * For store insns: propagate type from @sreg to the memory location referenced
+ * by @dst, applying @mem_spacing to account for multi-regs stores (e.g. stp).
+ */
+static void propagate_store_reg_state(struct type_state *state,
+ struct data_loc_info *dloc,
+ struct disasm_line *dl, int sreg,
+ struct annotated_op_loc *dst,
+ int mem_spacing)
+{
+ struct type_state_reg *tsr;
+ u32 insn_offset = dl->al.offset;
+ int dreg = dst->reg1;
+ int reg_offset;
+ int fbreg = dloc->fbreg;
+ int fboff = 0;
+
+ if (arch_get_reg_offset(dloc->arch, dst, dreg, state, false, ®_offset))
+ return;
+
+ reg_offset += mem_spacing;
+
+ 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;
+ }
+
+ /* Check stack variables with offset */
+ if (dreg != -1 && (dreg == fbreg || dreg == state->stack_reg)) {
+ struct type_state_stack *stack;
+ int offset = dreg == fbreg ? reg_offset - fboff : reg_offset;
+
+ if (!has_reg_type(state, sreg) || !state->regs[sreg].ok) {
+ stack = find_stack_state(state, offset);
+ /* Preserve compound states when only a member is overwritten. */
+ if (stack && !stack->compound)
+ delete_stack_state(state, offset);
+
+ 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, tsr->imm_value);
+ /*
+ * If it's a compound type, it means attempting to
+ * write to a member value of the compound type without
+ * changing the compound type itself, so do nothing.
+ */
+ } else {
+ findnew_stack_state(state, offset, tsr->kind, &tsr->type,
+ tsr->offset, tsr->imm_value);
+ }
+
+ if (dreg == fbreg) {
+ pr_debug_dtp("%s [%x] reg%d -> -%#x(stack)",
+ dl->ins.name, insn_offset, sreg, -offset);
+ } else {
+ pr_debug_dtp("%s [%x] reg%d -> %#x(reg%d)",
+ dl->ins.name, insn_offset, sreg, offset, dreg);
+ }
+ if (tsr->offset != 0)
+ pr_debug_dtp(" reg%d offset %#x ->", sreg, tsr->offset);
+
+ pr_debug_type_name(&tsr->type, tsr->kind);
+ }
+ /*
+ * Ignore other transfers since it'd set a value in a struct
+ * and won't change the type.
+ */
+}
+
+static void update_store_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)
+{
+ int mem_spacing = 0;
+
+ if (!has_reg_type(state, dst->reg1))
+ return;
+
+ /* Handle the first source register */
+ propagate_store_reg_state(state, dloc, dl, src->reg1, dst, mem_spacing);
+
+ /* Handle the second source register (if any) */
+ if (src->multi_regs) {
+ mem_spacing = arm64__reg_size(dl->ops.source.raw);
+
+ if (mem_spacing >= 0)
+ propagate_store_reg_state(state, dloc, dl, src->reg2,
+ dst, mem_spacing);
+ }
+
+ adjust_reg_index_state(state, dloc, dl, dst);
+}
+
static void update_insn_state_arm64(struct type_state *state,
struct data_loc_info *dloc, Dwarf_Die *cu_die,
struct disasm_line *dl)
@@ -757,16 +909,8 @@ static void update_insn_state_arm64(struct type_state *state,
if (is_standard_load_insn(dl->ins.name))
update_load_insn_state(state, dloc, dl, src, dst);
/* Register to memory transfers */
- else if (is_standard_store_insn(dl->ins.name)) {
- /*
- * Ignore transfers since it'd set a value in a struct
- * and won't change the type.
- *
- * Needs to update the pre-index and post-index addressing
- * modes for the destination register.
- */
- adjust_reg_index_state(state, dloc, dl, dst);
- }
+ else if (is_standard_store_insn(dl->ins.name))
+ update_store_insn_state(state, dloc, dl, src, dst);
}
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v7 11/15] perf annotate-arm64: Support 'mov' instruction tracking
2026-10-13 13:27 [PATCH v7 00/15] perf annotate arm64: Support instruction tracking for data type profiling Tengda Wu
` (9 preceding siblings ...)
2026-10-13 13:28 ` [PATCH v7 10/15] perf annotate-arm64: Support stack variable tracking Tengda Wu
@ 2026-10-13 13:28 ` Tengda Wu
2026-10-13 13:45 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 12/15] perf annotate-arm64: Support 'add' " Tengda Wu
` (3 subsequent siblings)
14 siblings, 1 reply; 31+ messages in thread
From: Tengda Wu @ 2026-10-13 13:28 UTC (permalink / raw)
To: Namhyung Kim, james.clark, xueshuai, Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, leo.yan, Li Huafei, Ian Rogers, Kim Phillips,
Mark Rutland, Ingo Molnar, Bill Wendling, Nick Desaulniers,
Alexander Shishkin, Adrian Hunter, Zecheng Li, linux-perf-users,
linux-kernel, llvm, Tengda Wu
Extend update_insn_state_arm64() to support register-to-register and
immediate-to-register 'mov' instructions.
For register-to-register 'mov' (e.g., mov dreg, sreg), propagate data type
information from the source register to the destination register.
For immediate-to-register 'mov' (e.g., mov dreg, #imm), store the immediate
value in the destination register's imm_value field and set its kind to
TSR_KIND_CONST, allowing subsequent instructions to resolve it as a
constant.
A real-world example is shown below:
ffff8000803eebf8 <get_vma_policy>:
ffff8000803eec20: mov x21, x0 // x0 (struct vm_area_struct*) -> x21
ffff8000803eec28: ldr x2, [x0, #112]
ffff8000803eec2c: cbz x2, ffff8000803eec94 <get_vma_policy+0x9c>
* ffff8000803eec94: ldr x0, [x21, #152]
Before this commit, the type of x21 was unknown, causing the subsequent
inference to fail:
var [0] reg0 offset 0 type='struct vm_area_struct*' size=0x8
chk [9c] reg21 offset=0x98 ok=0 kind=0 cfa : no type information
final result: no type information
After this commit, the type of x21 is correctly inferred as 'vm_area_struct':
var [0] reg0 offset 0 type='struct vm_area_struct*' size=0x8
mov [28] reg0 -> reg21 type='struct vm_area_struct*' size=0x8
chk [9c] reg21 offset=0x98 ok=1 kind=1 (struct vm_area_struct*) : Good!
found by insn track: 0x98(reg21) type-offset=0x98
final result: type='struct vm_area_struct' size=0xb0
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
---
.../perf/util/annotate-arch/annotate-arm64.c | 56 ++++++++++++++++++-
1 file changed, 55 insertions(+), 1 deletion(-)
diff --git a/tools/perf/util/annotate-arch/annotate-arm64.c b/tools/perf/util/annotate-arch/annotate-arm64.c
index d17d9b2456dc..ed574aba0b56 100644
--- a/tools/perf/util/annotate-arch/annotate-arm64.c
+++ b/tools/perf/util/annotate-arch/annotate-arm64.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/compiler.h>
#include <errno.h>
+#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <linux/ctype.h>
@@ -614,6 +615,7 @@ static int propagate_load_reg_state(struct type_state *state,
tsr->type = type_die;
tsr->kind = TSR_KIND_TYPE;
tsr->offset = 0;
+ tsr->imm_value = 0;
tsr->ok = true;
pr_debug_dtp("%s [%x] %#x(reg%d) -> reg%d",
@@ -827,6 +829,54 @@ static void update_store_insn_state(struct type_state *state,
adjust_reg_index_state(state, dloc, dl, dst);
}
+static void update_mov_insn_state(struct type_state *state,
+ struct disasm_line *dl,
+ struct annotated_op_loc *src,
+ struct annotated_op_loc *dst)
+{
+ struct type_state_reg *tsr;
+ u32 insn_offset = dl->al.offset;
+ int sreg = src->reg1;
+ int dreg = dst->reg1;
+
+ if (!has_reg_type(state, dreg))
+ return;
+
+ tsr = &state->regs[dreg];
+ tsr->copied_from = -1;
+
+ if (src->imm) {
+ invalidate_reg_state(tsr);
+ tsr->kind = TSR_KIND_CONST;
+ tsr->imm_value = (s64)src->offset;
+ tsr->offset = 0;
+ tsr->ok = true;
+
+ pr_debug_dtp("mov [%x] imm=%#"PRIx64" -> reg%d\n",
+ insn_offset, tsr->imm_value, dreg);
+ return;
+ }
+
+ if (!has_reg_type(state, sreg) || !state->regs[sreg].ok) {
+ invalidate_reg_state(tsr);
+ return;
+ }
+
+ tsr->type = state->regs[sreg].type;
+ tsr->kind = state->regs[sreg].kind;
+ tsr->imm_value = state->regs[sreg].imm_value;
+ tsr->offset = state->regs[sreg].offset;
+ tsr->lifetime_active = state->regs[sreg].lifetime_active;
+ tsr->lifetime_end = state->regs[sreg].lifetime_end;
+ tsr->ok = state->regs[sreg].ok;
+
+ if (tsr->kind == TSR_KIND_TYPE || tsr->kind == TSR_KIND_POINTER)
+ tsr->copied_from = sreg;
+
+ pr_debug_dtp("mov [%x] reg%d -> reg%d", insn_offset, sreg, dreg);
+ pr_debug_type_name(&tsr->type, tsr->kind);
+}
+
static void update_insn_state_arm64(struct type_state *state,
struct data_loc_info *dloc, Dwarf_Die *cu_die,
struct disasm_line *dl)
@@ -893,6 +943,7 @@ static void update_insn_state_arm64(struct type_state *state,
* prevent stale type info from propagating to subsequent instructions.
*/
if (has_reg_type(state, dst->reg1) && !dst->mem_ref &&
+ strcmp(dl->ins.name, "mov") &&
!is_standard_load_insn(dl->ins.name)) {
pr_debug_dtp("%s [%x] invalidate reg%d",
dl->ins.name, insn_offset, dst->reg1);
@@ -905,8 +956,11 @@ static void update_insn_state_arm64(struct type_state *state,
return;
}
+ /* Register to register or imm value to register transfers */
+ if (!strcmp(dl->ins.name, "mov"))
+ update_mov_insn_state(state, dl, src, dst);
/* Memory to register transfers */
- if (is_standard_load_insn(dl->ins.name))
+ else if (is_standard_load_insn(dl->ins.name))
update_load_insn_state(state, dloc, dl, src, dst);
/* Register to memory transfers */
else if (is_standard_store_insn(dl->ins.name))
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v7 12/15] perf annotate-arm64: Support 'add' instruction tracking
2026-10-13 13:27 [PATCH v7 00/15] perf annotate arm64: Support instruction tracking for data type profiling Tengda Wu
` (10 preceding siblings ...)
2026-10-13 13:28 ` [PATCH v7 11/15] perf annotate-arm64: Support 'mov' instruction tracking Tengda Wu
@ 2026-10-13 13:28 ` Tengda Wu
2026-10-13 13:47 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 13/15] perf annotate-arm64: Support 'adrp' instruction to track global variables Tengda Wu
` (2 subsequent siblings)
14 siblings, 1 reply; 31+ messages in thread
From: Tengda Wu @ 2026-10-13 13:28 UTC (permalink / raw)
To: Namhyung Kim, james.clark, xueshuai, Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, leo.yan, Li Huafei, Ian Rogers, Kim Phillips,
Mark Rutland, Ingo Molnar, Bill Wendling, Nick Desaulniers,
Alexander Shishkin, Adrian Hunter, Zecheng Li, linux-perf-users,
linux-kernel, llvm, Tengda Wu
Extend update_insn_state_arm64() to track 'add' instructions for
structure member address calculation.
Unlike x86, the arm64 'add' instruction has an extra base register among
its source operands. Therefore, in terms of propagating the data type,
it is essentially performing a 'mov', except that before the 'mov', it
first needs to be updated by adding the offset or reg2.
A real-world example is shown below:
ffff80008001c9a8 <flush_ptrace_hw_breakpoint>:
ffff80008001c9c4: add x19, x0, #0xeb8 // x0 (task_struct*) + 0xeb8 -> x19
* ffff80008001c9d0: ldr x0, [x19]
Before this commit, the type flow broke at the 'add' instruction,
leaving the subsequent load with no type information:
chk [28] reg19 offset=0 ok=0 kind=0 cfa : no type information
final result: no type information
After this commit, the tracker correctly follows the member address
calculation:
var [0] reg0 offset 0 type='struct task_struct*'
add [1c] address of 0xeb8(reg0) -> reg19 type='struct task_struct*'
chk [28] reg19 offset=0 ok=1 kind=1 (struct task_struct*) : Good!
found by insn track: 0(reg19) type-offset=0xeb8
final result: type='struct task_struct'
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
---
.../perf/util/annotate-arch/annotate-arm64.c | 74 ++++++++++++++++++-
1 file changed, 72 insertions(+), 2 deletions(-)
diff --git a/tools/perf/util/annotate-arch/annotate-arm64.c b/tools/perf/util/annotate-arch/annotate-arm64.c
index ed574aba0b56..e27ba26f3b8a 100644
--- a/tools/perf/util/annotate-arch/annotate-arm64.c
+++ b/tools/perf/util/annotate-arch/annotate-arm64.c
@@ -877,6 +877,74 @@ static void update_mov_insn_state(struct type_state *state,
pr_debug_type_name(&tsr->type, tsr->kind);
}
+static void update_add_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 *tsr;
+ struct type_state_reg src_tsr;
+ u32 insn_offset = dl->al.offset;
+ int sreg = src->reg1;
+ int dreg = dst->reg1;
+ int reg_offset;
+
+ if (!has_reg_type(state, dreg))
+ return;
+
+ tsr = &state->regs[dreg];
+ tsr->copied_from = -1;
+ tsr->lifetime_active = false;
+ tsr->lifetime_end = 0;
+
+retry:
+ if (!has_reg_type(state, sreg) || !state->regs[sreg].ok) {
+ invalidate_reg_state(tsr);
+ return;
+ }
+
+ src_tsr = state->regs[sreg];
+
+ if (arch_get_reg_offset(dloc->arch, src, sreg, state, false, ®_offset))
+ goto add_non_regoff;
+
+ if (src_tsr.kind == TSR_KIND_CONST) {
+ tsr->kind = src_tsr.kind;
+ tsr->imm_value = src_tsr.imm_value + reg_offset;
+ tsr->offset = 0;
+ tsr->ok = src_tsr.ok;
+
+ pr_debug_dtp("add [%x] imm %#x(reg%d) -> reg%d\n",
+ insn_offset, reg_offset, sreg, dreg);
+ return;
+ }
+
+ if (src_tsr.kind == TSR_KIND_POINTER ||
+ (src_tsr.kind == TSR_KIND_TYPE &&
+ dwarf_tag(&src_tsr.type) == DW_TAG_pointer_type)) {
+ tsr->type = src_tsr.type;
+ tsr->kind = src_tsr.kind;
+ tsr->imm_value = src_tsr.imm_value;
+ tsr->offset = src_tsr.offset + reg_offset;
+ tsr->ok = src_tsr.ok;
+
+ pr_debug_dtp("add [%x] address of %#x(reg%d) -> reg%d",
+ insn_offset, reg_offset, sreg, dreg);
+ pr_debug_type_name(&tsr->type, tsr->kind);
+ return;
+ }
+
+add_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;
+ goto retry;
+ }
+ invalidate_reg_state(tsr);
+}
+
static void update_insn_state_arm64(struct type_state *state,
struct data_loc_info *dloc, Dwarf_Die *cu_die,
struct disasm_line *dl)
@@ -943,7 +1011,7 @@ static void update_insn_state_arm64(struct type_state *state,
* prevent stale type info from propagating to subsequent instructions.
*/
if (has_reg_type(state, dst->reg1) && !dst->mem_ref &&
- strcmp(dl->ins.name, "mov") &&
+ strcmp(dl->ins.name, "add") && strcmp(dl->ins.name, "mov") &&
!is_standard_load_insn(dl->ins.name)) {
pr_debug_dtp("%s [%x] invalidate reg%d",
dl->ins.name, insn_offset, dst->reg1);
@@ -956,8 +1024,10 @@ static void update_insn_state_arm64(struct type_state *state,
return;
}
+ if (!strcmp(dl->ins.name, "add"))
+ update_add_insn_state(state, dloc, dl, src, dst);
/* Register to register or imm value to register transfers */
- if (!strcmp(dl->ins.name, "mov"))
+ else if (!strcmp(dl->ins.name, "mov"))
update_mov_insn_state(state, dl, src, dst);
/* Memory to register transfers */
else if (is_standard_load_insn(dl->ins.name))
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v7 13/15] perf annotate-arm64: Support 'adrp' instruction to track global variables
2026-10-13 13:27 [PATCH v7 00/15] perf annotate arm64: Support instruction tracking for data type profiling Tengda Wu
` (11 preceding siblings ...)
2026-10-13 13:28 ` [PATCH v7 12/15] perf annotate-arm64: Support 'add' " Tengda Wu
@ 2026-10-13 13:28 ` Tengda Wu
2026-10-13 13:57 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 14/15] perf annotate-arm64: Support per-cpu variable access tracking Tengda Wu
2026-10-13 13:28 ` [PATCH v7 15/15] perf annotate-arm64: Support 'mrs' instruction to track 'current' pointer Tengda Wu
14 siblings, 1 reply; 31+ messages in thread
From: Tengda Wu @ 2026-10-13 13:28 UTC (permalink / raw)
To: Namhyung Kim, james.clark, xueshuai, Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, leo.yan, Li Huafei, Ian Rogers, Kim Phillips,
Mark Rutland, Ingo Molnar, Bill Wendling, Nick Desaulniers,
Alexander Shishkin, Adrian Hunter, Zecheng Li, linux-perf-users,
linux-kernel, llvm, Tengda Wu
Extend update_insn_state_arm64() to track global variable types
calculated via page-relative addressing.
On arm64, global variables are typically accessed by first calculating
the page address using 'adrp', followed by an 'add' or 'ldr' to get the
specific symbol address. Without tracking 'adrp', the instruction
tracker loses the base address, making it impossible to resolve
global symbols and their associated DWARF types.
Introduce TSR_KIND_GLOBAL_ADDR to represent a partial global address
state. When encountering 'adrp', store the page-aligned target address
in the register's type state. Upon a subsequent 'add' or 'ldr'
instruction that references a TSR_KIND_GLOBAL_ADDR register, combine
the page address with the immediate offset.
A real-world example is shown below:
ffff80008032e008 <folios_put_refs>:
ffff80008032e048: adrp x24, ffff80008202f000 <nr_cpu_ids>
ffff80008032e050: add x24, x24, #0xd40
* ffff80008032e078: ldr x0, [x24]
Before this commit, x24 was unknown, leading to no type information:
chk [70] reg24 offset=0 ok=0 kind=0 cfa : no type information
final result: no type information
After this commit, the tracker correctly follows the adrp/add flow:
adrp [40] global addr=0xffff80008202f000 -> reg24
add [48] global 0xd40(reg24) -> reg24
chk [70] reg24 offset=0 ok=1 kind=7 global addr : Good!
final result: type='struct folio*'
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Li Huafei <lihuafei1@huawei.com>
Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
---
.../perf/util/annotate-arch/annotate-arm64.c | 83 +++++++++++++++++--
tools/perf/util/annotate-data.c | 25 +++++-
tools/perf/util/annotate-data.h | 1 +
3 files changed, 99 insertions(+), 10 deletions(-)
diff --git a/tools/perf/util/annotate-arch/annotate-arm64.c b/tools/perf/util/annotate-arch/annotate-arm64.c
index e27ba26f3b8a..f34b944dd285 100644
--- a/tools/perf/util/annotate-arch/annotate-arm64.c
+++ b/tools/perf/util/annotate-arch/annotate-arm64.c
@@ -531,7 +531,7 @@ static bool is_standard_load_insn(const char *name)
* which is added to the reg offset.
*/
static int propagate_load_reg_state(struct type_state *state,
- struct data_loc_info *dloc,
+ struct data_loc_info *dloc, Dwarf_Die *cu_die,
struct disasm_line *dl, int dreg,
struct annotated_op_loc *src,
struct type_state_reg **src_states,
@@ -640,6 +640,33 @@ static int propagate_load_reg_state(struct type_state *state,
return 0;
}
+ /* Or check if it's a global variable */
+ if (src_tsr->kind == TSR_KIND_GLOBAL_ADDR) {
+ u64 ip = dloc->ms->sym->start + dl->al.offset;
+ u64 addr = src_tsr->imm_value + reg_offset;
+ int offset;
+
+ if (!get_global_var_type(cu_die, dloc, ip, addr, &offset, &type_die) ||
+ !die_get_member_type(&type_die, offset, &type_die))
+ return -1;
+
+ tsr->type = type_die;
+ tsr->kind = TSR_KIND_TYPE;
+ tsr->offset = 0;
+ tsr->imm_value = 0;
+ tsr->ok = true;
+
+ if (src->multi_regs) {
+ pr_debug_dtp("%s [%x] global (reg%d, reg%d) -> reg%d",
+ dl->ins.name, insn_offset, src->reg1, src->reg2, dreg);
+ } else {
+ pr_debug_dtp("%s [%x] global (reg%d) -> reg%d",
+ dl->ins.name, insn_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 &&
@@ -653,7 +680,7 @@ static int propagate_load_reg_state(struct type_state *state,
}
static void update_load_insn_state(struct type_state *state,
- struct data_loc_info *dloc,
+ struct data_loc_info *dloc, Dwarf_Die *cu_die,
struct disasm_line *dl,
struct annotated_op_loc *src,
struct annotated_op_loc *dst)
@@ -687,7 +714,7 @@ static void update_load_insn_state(struct type_state *state,
/* Handle the first destination register */
if (has_reg_type(state, dst->reg1)) {
- if (propagate_load_reg_state(state, dloc, dl, dst->reg1,
+ if (propagate_load_reg_state(state, dloc, cu_die, dl, dst->reg1,
src, src_states, mem_spacing))
invalidate_reg_state(&state->regs[dst->reg1]);
}
@@ -702,7 +729,7 @@ static void update_load_insn_state(struct type_state *state,
mem_spacing = arm64__reg_size(dl->ops.target.raw);
if (mem_spacing < 0 ||
- propagate_load_reg_state(state, dloc, dl, dst->reg2,
+ propagate_load_reg_state(state, dloc, cu_die, dl, dst->reg2,
src, src_states, mem_spacing))
invalidate_reg_state(&state->regs[dst->reg2]);
@@ -909,14 +936,16 @@ static void update_add_insn_state(struct type_state *state,
if (arch_get_reg_offset(dloc->arch, src, sreg, state, false, ®_offset))
goto add_non_regoff;
- if (src_tsr.kind == TSR_KIND_CONST) {
+ if (src_tsr.kind == TSR_KIND_CONST || src_tsr.kind == TSR_KIND_GLOBAL_ADDR) {
tsr->kind = src_tsr.kind;
+ /* For 'adrp + add' pair: resolve the full global variable address. */
tsr->imm_value = src_tsr.imm_value + reg_offset;
tsr->offset = 0;
tsr->ok = src_tsr.ok;
- pr_debug_dtp("add [%x] imm %#x(reg%d) -> reg%d\n",
- insn_offset, reg_offset, sreg, dreg);
+ pr_debug_dtp("add [%x] %s %#x(reg%d) -> reg%d\n",
+ insn_offset, src_tsr.kind == TSR_KIND_CONST ?
+ "imm" : "global", reg_offset, sreg, dreg);
return;
}
@@ -945,6 +974,39 @@ static void update_add_insn_state(struct type_state *state,
invalidate_reg_state(tsr);
}
+static void update_adrp_insn_state(struct type_state *state,
+ struct disasm_line *dl,
+ struct annotated_op_loc *dst)
+{
+ struct type_state_reg *tsr;
+ u32 insn_offset = dl->al.offset;
+ int dreg = dst->reg1;
+
+ if (!has_reg_type(state, dreg))
+ return;
+
+ tsr = &state->regs[dreg];
+ tsr->copied_from = -1;
+
+ if (!dl->ops.source.addr) {
+ invalidate_reg_state(tsr);
+ return;
+ }
+
+ tsr->kind = TSR_KIND_GLOBAL_ADDR;
+ /*
+ * Stores a partial page-relative address. The full absolute address
+ * of the global variable will be resolved when a subsequent 'add' or
+ * 'ldr' instruction consumes this register.
+ */
+ tsr->imm_value = dl->ops.source.addr;
+ tsr->offset = 0;
+ tsr->ok = true;
+
+ pr_debug_dtp("adrp [%x] global addr=%#"PRIx64" -> reg%d\n",
+ insn_offset, tsr->imm_value, dreg);
+}
+
static void update_insn_state_arm64(struct type_state *state,
struct data_loc_info *dloc, Dwarf_Die *cu_die,
struct disasm_line *dl)
@@ -1011,6 +1073,7 @@ static void update_insn_state_arm64(struct type_state *state,
* prevent stale type info from propagating to subsequent instructions.
*/
if (has_reg_type(state, dst->reg1) && !dst->mem_ref &&
+ strcmp(dl->ins.name, "adrp") &&
strcmp(dl->ins.name, "add") && strcmp(dl->ins.name, "mov") &&
!is_standard_load_insn(dl->ins.name)) {
pr_debug_dtp("%s [%x] invalidate reg%d",
@@ -1024,14 +1087,16 @@ static void update_insn_state_arm64(struct type_state *state,
return;
}
- if (!strcmp(dl->ins.name, "add"))
+ if (!strcmp(dl->ins.name, "adrp"))
+ update_adrp_insn_state(state, dl, dst);
+ else if (!strcmp(dl->ins.name, "add"))
update_add_insn_state(state, dloc, dl, src, dst);
/* Register to register or imm value to register transfers */
else if (!strcmp(dl->ins.name, "mov"))
update_mov_insn_state(state, dl, src, dst);
/* Memory to register transfers */
else if (is_standard_load_insn(dl->ins.name))
- update_load_insn_state(state, dloc, dl, src, dst);
+ update_load_insn_state(state, dloc, cu_die, dl, src, dst);
/* Register to memory transfers */
else if (is_standard_store_insn(dl->ins.name))
update_store_insn_state(state, dloc, dl, src, dst);
diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c
index 1d47db3a9dd9..43cd09c0662a 100644
--- a/tools/perf/util/annotate-data.c
+++ b/tools/perf/util/annotate-data.c
@@ -71,6 +71,9 @@ void pr_debug_type_name(Dwarf_Die *die, enum type_state_kind kind)
case TSR_KIND_CANARY:
pr_info(" stack canary\n");
return;
+ case TSR_KIND_GLOBAL_ADDR:
+ pr_info(" global address\n");
+ return;
case TSR_KIND_TYPE:
default:
break;
@@ -723,7 +726,8 @@ void set_stack_state(struct type_state_stack *stack, int offset, u8 kind,
stack->kind = kind;
stack->imm_value = imm_value;
- if (kind == TSR_KIND_POINTER || kind == TSR_KIND_CONST) {
+ if (kind == TSR_KIND_POINTER || kind == TSR_KIND_CONST ||
+ kind == TSR_KIND_GLOBAL_ADDR) {
stack->compound = false;
return;
}
@@ -1474,6 +1478,25 @@ static enum type_match_result check_matching_type(struct type_state *state,
if (offset < 0 && reg != state->stack_reg && reg != dloc->fbreg)
goto check_kernel;
}
+
+ if (state->regs[reg].kind == TSR_KIND_GLOBAL_ADDR) {
+ u64 var_addr = state->regs[reg].imm_value + offset;
+ int var_offset;
+
+ pr_debug_dtp("global addr");
+
+ /*
+ * The register holds the address of a global variable. Try to
+ * find the variable by the address and get its type.
+ */
+ if (get_global_var_type(cu_die, dloc, dloc->ip, var_addr,
+ &var_offset, type_die)) {
+ dloc->type_offset = var_offset;
+ return PERF_TMR_OK;
+ }
+ /* No need to retry global variables */
+ return PERF_TMR_BAIL_OUT;
+ }
check_non_register:
if (reg == dloc->fbreg || reg == state->stack_reg) {
struct type_state_stack *stack;
diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h
index 425d9ddfad41..eee1f8dae3dc 100644
--- a/tools/perf/util/annotate-data.h
+++ b/tools/perf/util/annotate-data.h
@@ -37,6 +37,7 @@ enum type_state_kind {
TSR_KIND_PERCPU_POINTER,
TSR_KIND_POINTER,
TSR_KIND_CANARY,
+ TSR_KIND_GLOBAL_ADDR,
};
/**
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v7 14/15] perf annotate-arm64: Support per-cpu variable access tracking
2026-10-13 13:27 [PATCH v7 00/15] perf annotate arm64: Support instruction tracking for data type profiling Tengda Wu
` (12 preceding siblings ...)
2026-10-13 13:28 ` [PATCH v7 13/15] perf annotate-arm64: Support 'adrp' instruction to track global variables Tengda Wu
@ 2026-10-13 13:28 ` Tengda Wu
2026-10-13 13:49 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 15/15] perf annotate-arm64: Support 'mrs' instruction to track 'current' pointer Tengda Wu
14 siblings, 1 reply; 31+ messages in thread
From: Tengda Wu @ 2026-10-13 13:28 UTC (permalink / raw)
To: Namhyung Kim, james.clark, xueshuai, Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, leo.yan, Li Huafei, Ian Rogers, Kim Phillips,
Mark Rutland, Ingo Molnar, Bill Wendling, Nick Desaulniers,
Alexander Shishkin, Adrian Hunter, Zecheng Li, linux-perf-users,
linux-kernel, llvm, Tengda Wu
Extend update_insn_state_arm64() to handle per-cpu variable addressing.
On arm64, per-cpu variables are accessed by adding a per-cpu offset
(typically from the '__per_cpu_offset' array) to the address of a global
variable or a structure field with '__percpu' modifier (e.g.,
's32 __percpu *counters' in struct percpu_counter). This results in
instruction patterns like:
ldr x0, [x6, x5] // Pattern A: direct load per-cpu instance
add x0, x6, x5 // Pattern B: compute per-cpu address
where x6 holds the per-cpu offset retrieved from:
adrp x4, <page>
add x4, x4, #offset // x4 = &__per_cpu_offset
ldr x6, [x4, w0, sxtw #3] // x6 = __per_cpu_offset[cpu]
And x5 holds the base address being offset, which can come from one of
two cases:
Case 1: global variable
adrp x5, <page>
add x5, x5, #offset // x5 = &global_var
Case 2: '__percpu' field embedded in a structure
ldr x5, [x25, #32] // x5 = &percpu_field
To handle such cases:
1. Identify per-cpu base initialization: Detect 'adrp + ldr' pairs that
resolve to the '__per_cpu_offset' symbol and mark the destination
register as TSR_KIND_PERCPU_BASE.
2. Propagate type information: During subsequent 'ldr' or 'add'
instructions, if one register is TSR_KIND_PERCPU_BASE, attempt to
resolve the type from the other register.
A real-world example is shown below:
ffff8000808f2d28 <cppc_set_perf>:
ffff8000808f2d38: adrp x2, ffff800082033000
ffff8000808f2d3c: add x5, x2, #0x3f8 // x5 = &__per_cpu_offset
ffff8000808f2d44: adrp x2, ffff800081f73000
ffff8000808f2d48: add x2, x2, #0x6b8 // x2 = &cpu_pcc_subspace_idx
ffff8000808f2d6c: ldr x5, [x5, w0, sxtw #3] // x5 = __per_cpu_offset[cpu]
* ffff8000808f2d80: ldr w23, [x5, x2] // per_cpu_var(cpu_pcc_subspace_idx)
Before this commit, the tracker could not link x5 back to a per-cpu
context, resulting in an incorrect data type resolution:
adrp [10] global addr=0xffff800082033000 -> reg2
add [14] global 0x3f8(reg2) -> reg5
adrp [1c] global addr=0xffff800081f73000 -> reg2
add [20] global 0x6b8(reg2) -> reg2
ldr [44] global (reg5, reg0) -> reg5 type='long unsigned int[]' size=0x1000
chk [58] reg5 offset=0 ok=1 kind=1 (long unsigned int[]) : Good!
found by insn track: 0(reg5, reg2) type-offset=0
final result: type='long unsigned int' size=0x8
After this commit, the tracker correctly identifies the per-cpu flow and
resolves the actual variable type:
ldr [44] global (reg5, reg0) -> reg5 percpu base
chk [58] reg5 offset=0 ok=1 kind=2 percpu var : retry
chk [58] reg2 offset=0 ok=1 kind=7 global addr : Good!
found by insn track: 0(reg5, reg2) type-offset=0
final result: type='int' size=0x4
Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
---
.../perf/util/annotate-arch/annotate-arm64.c | 25 ++++++++++++-
tools/perf/util/annotate-data.c | 36 +++++++++++++++----
2 files changed, 54 insertions(+), 7 deletions(-)
diff --git a/tools/perf/util/annotate-arch/annotate-arm64.c b/tools/perf/util/annotate-arch/annotate-arm64.c
index f34b944dd285..5683215f0770 100644
--- a/tools/perf/util/annotate-arch/annotate-arm64.c
+++ b/tools/perf/util/annotate-arch/annotate-arm64.c
@@ -12,6 +12,7 @@
#include "../disasm.h"
#include "../annotate-data.h"
#include "../debug.h"
+#include "../dso.h"
#include "../map.h"
#include "../symbol.h"
@@ -645,13 +646,23 @@ static int propagate_load_reg_state(struct type_state *state,
u64 ip = dloc->ms->sym->start + dl->al.offset;
u64 addr = src_tsr->imm_value + reg_offset;
int offset;
+ u8 kind;
+ const char *var_name = NULL;
+
+ /* it might be per-cpu offset */
+ if (dso__kernel(map__dso(dloc->ms->map)) &&
+ get_global_var_info(dloc, addr, &var_name, &offset) &&
+ !strcmp(var_name, "__per_cpu_offset"))
+ kind = TSR_KIND_PERCPU_BASE;
+ else
+ kind = TSR_KIND_TYPE;
if (!get_global_var_type(cu_die, dloc, ip, addr, &offset, &type_die) ||
!die_get_member_type(&type_die, offset, &type_die))
return -1;
tsr->type = type_die;
- tsr->kind = TSR_KIND_TYPE;
+ tsr->kind = kind;
tsr->offset = 0;
tsr->imm_value = 0;
tsr->ok = true;
@@ -667,6 +678,12 @@ static int propagate_load_reg_state(struct type_state *state,
return 0;
}
+ /*
+ * If src_tsr->kind is TSR_KIND_PERCPU_BASE, treat it as an array.
+ * No special handling is needed here; just fall through to retry
+ * and resolve the type from the second register.
+ */
+
load_non_regoff:
/* Try another register if any */
if (src->multi_regs && src->reg1 != src->reg2 && sreg != src->reg2 &&
@@ -964,6 +981,12 @@ static void update_add_insn_state(struct type_state *state,
return;
}
+ /*
+ * If src_tsr->kind is TSR_KIND_PERCPU_BASE, treat it as an array.
+ * No special handling is needed here; just fall through to retry
+ * and resolve the type from the second register.
+ */
+
add_non_regoff:
/* Try another register if any */
if (src->multi_regs && src->reg1 != src->reg2 && sreg != src->reg2 &&
diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c
index 43cd09c0662a..b3de1ca688a2 100644
--- a/tools/perf/util/annotate-data.c
+++ b/tools/perf/util/annotate-data.c
@@ -1307,13 +1307,17 @@ int arch_get_reg_offset(const struct arch *arch, struct annotated_op_loc *op_loc
/*
* For register-based addressing without shift/extension,
- * reg2 may be a constant offset. Use its value as the offset
- * from the base register.
+ * derive the offset from the type of reg2.
*/
reg2 = op_loc->reg1 == breg ? op_loc->reg2 : op_loc->reg1;
- if (has_reg_type(state, reg2) && state->regs[reg2].ok &&
- state->regs[reg2].kind == TSR_KIND_CONST) {
- *offset = (s64)state->regs[reg2].imm_value;
+ if (has_reg_type(state, reg2) && state->regs[reg2].ok) {
+ if (state->regs[reg2].kind == TSR_KIND_CONST)
+ *offset = (s64)state->regs[reg2].imm_value;
+ else if (state->regs[reg2].kind == TSR_KIND_PERCPU_BASE)
+ *offset = 0; /* it does not contribute to the offset */
+ else
+ return -1;
+
return 0;
}
@@ -1448,11 +1452,31 @@ static enum type_match_result check_matching_type(struct type_state *state,
}
if (state->regs[reg].kind == TSR_KIND_PERCPU_BASE) {
- u64 var_addr = (s64) offset;
+ u64 var_addr;
int var_offset;
pr_debug_dtp("percpu var");
+ if (arch__is_arm64(dloc->arch)) {
+ int reg2;
+
+ if (!retry || !dloc->op->multi_regs ||
+ dloc->op->reg1 == dloc->op->reg2 ||
+ dloc->op->extend_type || dloc->op->shift_type)
+ return PERF_TMR_BAIL_OUT;
+
+ reg2 = dloc->op->reg2;
+ if (!has_reg_type(state, reg2) || !state->regs[reg2].ok)
+ return PERF_TMR_NO_TYPE;
+
+ pr_debug_dtp(" : retry\n");
+ retry = false;
+ reg = reg2;
+ goto again;
+ }
+
+ var_addr = (s64) offset;
+
if (dloc->op->multi_regs) {
int reg2 = dloc->op->reg2;
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v7 15/15] perf annotate-arm64: Support 'mrs' instruction to track 'current' pointer
2026-10-13 13:27 [PATCH v7 00/15] perf annotate arm64: Support instruction tracking for data type profiling Tengda Wu
` (13 preceding siblings ...)
2026-10-13 13:28 ` [PATCH v7 14/15] perf annotate-arm64: Support per-cpu variable access tracking Tengda Wu
@ 2026-10-13 13:28 ` Tengda Wu
2026-10-13 14:03 ` sashiko-bot
14 siblings, 1 reply; 31+ messages in thread
From: Tengda Wu @ 2026-10-13 13:28 UTC (permalink / raw)
To: Namhyung Kim, james.clark, xueshuai, Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, leo.yan, Li Huafei, Ian Rogers, Kim Phillips,
Mark Rutland, Ingo Molnar, Bill Wendling, Nick Desaulniers,
Alexander Shishkin, Adrian Hunter, Zecheng Li, linux-perf-users,
linux-kernel, llvm, Tengda Wu
Extend update_insn_state_arm64() to handle the 'mrs' instruction,
enabling the tracking of the 'current' task pointer in the kernel.
On arm64, the kernel uses the 'sp_el0' system register to store the
address of the currently executing 'struct task_struct'. This is
typically accessed via the 'get_current()' inline function, resulting
in the instruction 'mrs xN, sp_el0'.
To resolve the data type of the target register, first verify the
access is to 'sp_el0' within a kernel DSO. Then, locate the
'get_current()' inline function's DWARF Die at the current PC and
extract its return type (which should be 'struct task_struct*').
A real-world example is shown below:
ffff8000800deee8 <kthread_blkcg>:
ffff8000800deef0: mrs x0, sp_el0 // x0 = current
* ffff8000800deef4: ldr w1, [x0, #44]
Before this commit, the type flow starts with no information:
chk [c] reg0 offset=0x2c ok=0 kind=0 cfa : no type information
final result: no type information
After this commit, the tracker identifies the 'current' pointer
from the system register:
mrs [8] sp_el0 -> reg0 type='struct task_struct*'
chk [c] reg0 offset=0x2c ok=1 kind=1 (struct task_struct*) : Good!
found by insn track: 0x2c(reg0) type-offset=0x2c
final result: type='struct task_struct'
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Li Huafei <lihuafei1@huawei.com>
Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
---
.../perf/util/annotate-arch/annotate-arm64.c | 73 ++++++++++++++++++-
1 file changed, 71 insertions(+), 2 deletions(-)
diff --git a/tools/perf/util/annotate-arch/annotate-arm64.c b/tools/perf/util/annotate-arch/annotate-arm64.c
index 5683215f0770..6da558f7e864 100644
--- a/tools/perf/util/annotate-arch/annotate-arm64.c
+++ b/tools/perf/util/annotate-arch/annotate-arm64.c
@@ -4,6 +4,7 @@
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
+#include <strings.h>
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/zalloc.h>
@@ -15,6 +16,7 @@
#include "../dso.h"
#include "../map.h"
#include "../symbol.h"
+#include "../strbuf.h"
struct arch_arm64 {
struct arch arch;
@@ -1030,6 +1032,71 @@ static void update_adrp_insn_state(struct type_state *state,
insn_offset, tsr->imm_value, dreg);
}
+static void update_mrs_insn_state(struct type_state *state,
+ struct data_loc_info *dloc, Dwarf_Die *cu_die,
+ struct disasm_line *dl,
+ struct annotated_op_loc *dst)
+{
+ struct type_state_reg *tsr;
+ Dwarf_Die type_die;
+ u32 insn_offset = dl->al.offset;
+ int dreg = dst->reg1;
+ Dwarf_Die func_die;
+ Dwarf_Attribute attr;
+ u64 ip, pc;
+ struct strbuf sb;
+ char *type_name;
+
+ if (!has_reg_type(state, dreg))
+ return;
+
+ tsr = &state->regs[dreg];
+ tsr->copied_from = -1;
+
+ /* Handle case difference: LLVM (SP_EL0) vs objdump (sp_el0) */
+ if (!dso__kernel(map__dso(dloc->ms->map)) ||
+ strcasecmp(dl->ops.source.raw, "sp_el0")) {
+ invalidate_reg_state(tsr);
+ return;
+ }
+
+ ip = dloc->ms->sym->start + dl->al.offset;
+ pc = map__rip_2objdump(dloc->ms->map, ip);
+
+ /*
+ * Find the inline function 'get_current()' Dwarf_Die and obtain its
+ * return value data type, which should be 'struct task_struct*'.
+ */
+ if (!die_find_inlinefunc(cu_die, pc, &func_die) ||
+ !die_compare_name(&func_die, "get_current") ||
+ !dwarf_attr_integrate(&func_die, DW_AT_type, &attr) ||
+ !dwarf_formref_die(&attr, &type_die)) {
+ invalidate_reg_state(tsr);
+ return;
+ }
+
+ strbuf_init(&sb, 32);
+ die_get_typename_from_type(&type_die, &sb);
+ type_name = strbuf_detach(&sb, NULL);
+
+ if (!type_name || strcmp(type_name, "struct task_struct*")) {
+ invalidate_reg_state(tsr);
+ goto out_free;
+ }
+
+ tsr->type = type_die;
+ tsr->kind = TSR_KIND_TYPE;
+ tsr->offset = 0;
+ tsr->imm_value = 0;
+ tsr->ok = true;
+
+ pr_debug_dtp("mrs [%x] sp_el0 -> reg%d", insn_offset, dreg);
+ pr_debug_type_name(&type_die, tsr->kind);
+
+out_free:
+ free(type_name);
+}
+
static void update_insn_state_arm64(struct type_state *state,
struct data_loc_info *dloc, Dwarf_Die *cu_die,
struct disasm_line *dl)
@@ -1096,7 +1163,7 @@ static void update_insn_state_arm64(struct type_state *state,
* prevent stale type info from propagating to subsequent instructions.
*/
if (has_reg_type(state, dst->reg1) && !dst->mem_ref &&
- strcmp(dl->ins.name, "adrp") &&
+ strcmp(dl->ins.name, "mrs") && strcmp(dl->ins.name, "adrp") &&
strcmp(dl->ins.name, "add") && strcmp(dl->ins.name, "mov") &&
!is_standard_load_insn(dl->ins.name)) {
pr_debug_dtp("%s [%x] invalidate reg%d",
@@ -1110,7 +1177,9 @@ static void update_insn_state_arm64(struct type_state *state,
return;
}
- if (!strcmp(dl->ins.name, "adrp"))
+ if (!strcmp(dl->ins.name, "mrs"))
+ update_mrs_insn_state(state, dloc, cu_die, dl, dst);
+ else if (!strcmp(dl->ins.name, "adrp"))
update_adrp_insn_state(state, dl, dst);
else if (!strcmp(dl->ins.name, "add"))
update_add_insn_state(state, dloc, dl, src, dst);
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH v7 01/15] perf annotate-data: Extract invalidate_reg_state() as a common helper
2026-10-13 13:27 ` [PATCH v7 01/15] perf annotate-data: Extract invalidate_reg_state() as a common helper Tengda Wu
@ 2026-10-13 13:34 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-10-13 13:34 UTC (permalink / raw)
To: Tengda Wu; +Cc: linux-perf-users
> The invalidate_reg_state() function is currently static and only used
> within the x86 data type profiling implementation. To prepare for adding
> arm64 instruction tracking support, extract it as a common helper that
> can be shared across architectures.
>
> No functional change intended.
>
> Reviewed-by: Shuai Xue <xueshuai@linux.alibaba.com>
> Reviewed-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791629326.git.wutengda@huaweicloud.com?part=1
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v7 04/15] perf annotate-arm64: Track return type after call instructions
2026-10-13 13:28 ` [PATCH v7 04/15] perf annotate-arm64: Track return type after call instructions Tengda Wu
@ 2026-10-13 13:36 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-10-13 13:36 UTC (permalink / raw)
To: Tengda Wu; +Cc: linux-perf-users
> Enable data type profiling to track function return values in arm64
> annotations by looking up the DWARF return type of called functions.
>
> Reviewed-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791629326.git.wutengda@huaweicloud.com?part=4
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v7 06/15] perf annotate-arm64: Support store instruction tracking
2026-10-13 13:28 ` [PATCH v7 06/15] perf annotate-arm64: Support store " Tengda Wu
@ 2026-10-13 13:36 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-10-13 13:36 UTC (permalink / raw)
To: Tengda Wu; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] perf annotate-arm64: Stale type tracking on status register in exclusive stores
--
commit e02fcbc321646663dec228cbae05f99e569cc5a5
Author: Tengda Wu <wutengda@huaweicloud.com>
perf annotate-arm64: Support store instruction tracking
Extend update_insn_state_arm64() to handle standard store instructions
(str, stur, stlr, stp). Exclusive stores (e.g., stxr, stxp) are omitted
as they exhibit different operand semantics. The patch also updates
pre-index and post-index addressing modes for the destination register.
> diff --git a/tools/perf/util/annotate-arch/annotate-arm64.c b/tools/perf/util/annotate-arch/annotate-arm64.c
> index fb48bf95b32ff..54d9928b536fd 100644
> --- a/tools/perf/util/annotate-arch/annotate-arm64.c
> +++ b/tools/perf/util/annotate-arch/annotate-arm64.c
> @@ -661,6 +661,20 @@ static void update_load_insn_state(struct type_state *state,
> adjust_reg_index_state(state, dloc, dl, src);
> }
>
> +/*
> + * Match standard store variants (str, stur, stlr, stp) that follow
> + * straightforward store semantics: source registers on the left (read-only)
> + * and memory target on the right. Excludes exclusive stores (stxr, stxp, etc.)
> + * which have status/result register side effects.
> + */
> +static bool is_standard_store_insn(const char *name)
> +{
> + return !strncmp(name, "str", 3) || /* str, strb, strh */
> + !strncmp(name, "stur", 4) || /* stur, sturb, sturh */
> + !strncmp(name, "stlr", 4) || /* stlr, stlrb, stlrh */
> + !strncmp(name, "stp", 3); /* stp */
> +}
[Severity: Medium]
Will this result in stale type tracking for the status registers modified
by exclusive store instructions?
Since exclusive stores like stxr are excluded here, they fall through and
are ignored. However, because arm64__insn_is_target_on_right("stxr")
places the memory operand in dst (so dst->mem_ref is true), the generic
invalidation block in update_insn_state_arm64() is also completely bypassed:
if (has_reg_type(state, dst->reg1) && !dst->mem_ref &&
!is_standard_load_insn(dl->ins.name)) {
...
For an instruction like "stxr w0, x1, [x2]", the CPU modifies the status
register (w0, parsed into src->reg1). Since it skips both standard store
processing and the generic invalidation block, does the tracker leave the
status register's type state unaltered and allow stale types to propagate?
[ ... ]
> @@ -742,6 +756,17 @@ static void update_insn_state_arm64(struct type_state *state,
> /* Memory to register transfers */
> if (is_standard_load_insn(dl->ins.name))
> update_load_insn_state(state, dloc, dl, src, dst);
> + /* Register to memory transfers */
> + else if (is_standard_store_insn(dl->ins.name)) {
> + /*
> + * Ignore transfers since it'd set a value in a struct
> + * and won't change the type.
> + *
> + * Needs to update the pre-index and post-index addressing
> + * modes for the destination register.
> + */
> + adjust_reg_index_state(state, dloc, dl, dst);
> + }
> }
> #endif
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791629326.git.wutengda@huaweicloud.com?part=6
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v7 05/15] perf annotate-arm64: Support load instruction tracking
2026-10-13 13:28 ` [PATCH v7 05/15] perf annotate-arm64: Support load instruction tracking Tengda Wu
@ 2026-10-13 13:38 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-10-13 13:38 UTC (permalink / raw)
To: Tengda Wu; +Cc: linux-perf-users
> Extend update_insn_state_arm64() to handle load instructions, tracking
> register state changes when data is loaded from memory to registers.
>
> Two main categories are considered: standard load (e.g, ldr variants)
> and load pair (ldp), for example:
>
> ldr dst, [src, #imm]
> ldp dst1, dst2, [src, #imm]
>
> For data type propagation, a load pair can be treated as two standard
> loads combined, first loading dst1 and then dst2. The difference is
> that when loading dst2, an additional memory spacing 'mem_spacing' after
> the first load must be added. This mem_spacing can be derived from the
> instruction mnemonic and the size of the dst register. Each load operation
> is handled by introducing propagate_load_reg_state().
> [ ... ]
> final result: type='struct task_struct'
>
> Reviewed-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Li Huafei <lihuafei1@huawei.com>
> Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791629326.git.wutengda@huaweicloud.com?part=5
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v7 02/15] perf annotate-arm64: Enable instruction tracking support
2026-10-13 13:28 ` [PATCH v7 02/15] perf annotate-arm64: Enable instruction tracking support Tengda Wu
@ 2026-10-13 13:38 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-10-13 13:38 UTC (permalink / raw)
To: Tengda Wu; +Cc: linux-perf-users
> Enable basic instruction tracking for arm64 by implementing three
> essential functions in the find_data_type_block() call path:
>
> find_data_type_block
> -> arch_supports_insn_tracking (1)
> -> find_data_type_insn
> -> init_type_state (2)
> -> update_var_state
> -> update_insn_state (3)
>
> Changes:
>
> * arch_supports_insn_tracking(): add arm64 to the list of supported
> architectures, allowing find_data_type_block() to proceed with data
> type analysis.
> [ ... ]
> inference during instruction tracking.
>
> Reviewed-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Li Huafei <lihuafei1@huawei.com>
> Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791629326.git.wutengda@huaweicloud.com?part=2
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v7 03/15] perf annotate-data: Add arch_get_reg_offset helper
2026-10-13 13:28 ` [PATCH v7 03/15] perf annotate-data: Add arch_get_reg_offset helper Tengda Wu
@ 2026-10-13 13:38 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-10-13 13:38 UTC (permalink / raw)
To: Tengda Wu; +Cc: linux-perf-users
> Add a helper to compute the effective offset from a base register
> for instruction operands. Currently handles arm64 addressing modes
> including post-indexed, single-register, SIB-style indexed with
> shift/extension, and constant-offset register pairs.
>
> Fallback to instruction's raw offset for other architectures.
>
> Reviewed-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791629326.git.wutengda@huaweicloud.com?part=3
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v7 10/15] perf annotate-arm64: Support stack variable tracking
2026-10-13 13:28 ` [PATCH v7 10/15] perf annotate-arm64: Support stack variable tracking Tengda Wu
@ 2026-10-13 13:44 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-10-13 13:44 UTC (permalink / raw)
To: Tengda Wu; +Cc: linux-perf-users
> Extend update_insn_state_arm64() to track data types stored on the
> stack.
>
> The implementation handles:
> 1. Stack Loads: 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: Update or create new stack state entries when
> a tracked register type is stored to the stack.
>
> Similar to loads, stores also support saving one or two registers
> (in the case of 'stp'). Therefore, propagate_store_reg_state() is
> introduced.
>
> With these changes, the instruction tracker can now 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@huaweicloud.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791629326.git.wutengda@huaweicloud.com?part=10
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v7 09/15] perf annotate-x86: Delete stale stack state on store of untracked register
2026-10-13 13:28 ` [PATCH v7 09/15] perf annotate-x86: Delete stale stack state on store of untracked register Tengda Wu
@ 2026-10-13 13:44 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-10-13 13:44 UTC (permalink / raw)
To: Tengda Wu; +Cc: linux-perf-users
> When a register without a tracked type is stored to a stack slot that
> previously held a valid type, the code currently performs an early return.
> This leaves the old type information intact in the stack state.
>
> As a result, a stale type bug occurs:
> 1. A tracked register is stored into a stack slot.
> 2. The register becomes untracked/invalid (e.g., across a function call).
> 3. The now-untracked register is stored into the same stack slot.
> 4. Subsequent loads from that slot erroneously pick up the old stale type
> because the stack entry was never invalidated.
>
> Fix this by introducing delete_stack_state() to search and free a stack
> entry for a given offset. When storing an untracked or invalid source
> register into a stack location, call delete_stack_state() to delete the
> stale entry before returning.
>
> Reviewed-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791629326.git.wutengda@huaweicloud.com?part=9
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v7 07/15] perf annotate-data: Expand type_state_reg imm_value to u64
2026-10-13 13:28 ` [PATCH v7 07/15] perf annotate-data: Expand type_state_reg imm_value to u64 Tengda Wu
@ 2026-10-13 13:45 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-10-13 13:45 UTC (permalink / raw)
To: Tengda Wu; +Cc: linux-perf-users
> The arm64 'adrp + add/ldr' instruction pair involves global variable address
> calculation and passing, which requires storing the 64-bit address in
> type_state_reg. Currently, there is no field in type_state_reg that can
> hold such an address. The most likely candidate for reuse is imm_value,
> but it is defined as u32, which limits the size of values it can carry.
>
> To address this, expand imm_value from u32 to u64. Also update related
> compilation warnings and fix the sign-extension issue introduced by this
> change.
>
> Reviewed-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791629326.git.wutengda@huaweicloud.com?part=7
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v7 11/15] perf annotate-arm64: Support 'mov' instruction tracking
2026-10-13 13:28 ` [PATCH v7 11/15] perf annotate-arm64: Support 'mov' instruction tracking Tengda Wu
@ 2026-10-13 13:45 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-10-13 13:45 UTC (permalink / raw)
To: Tengda Wu; +Cc: linux-perf-users
> Extend update_insn_state_arm64() to support register-to-register and
> immediate-to-register 'mov' instructions.
>
> For register-to-register 'mov' (e.g., mov dreg, sreg), propagate data type
> information from the source register to the destination register.
>
> For immediate-to-register 'mov' (e.g., mov dreg, #imm), store the immediate
> value in the destination register's imm_value field and set its kind to
> TSR_KIND_CONST, allowing subsequent instructions to resolve it as a
> constant.
>
> A real-world example is shown below:
>
> ffff8000803eebf8 <get_vma_policy>:
> ffff8000803eec20: mov x21, x0 // x0 (struct vm_area_struct*) -> x21
> [ ... ]
> found by insn track: 0x98(reg21) type-offset=0x98
> final result: type='struct vm_area_struct' size=0xb0
>
> Reviewed-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791629326.git.wutengda@huaweicloud.com?part=11
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v7 12/15] perf annotate-arm64: Support 'add' instruction tracking
2026-10-13 13:28 ` [PATCH v7 12/15] perf annotate-arm64: Support 'add' " Tengda Wu
@ 2026-10-13 13:47 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-10-13 13:47 UTC (permalink / raw)
To: Tengda Wu; +Cc: linux-perf-users
> Extend update_insn_state_arm64() to track 'add' instructions for
> structure member address calculation.
>
> Unlike x86, the arm64 'add' instruction has an extra base register among
> its source operands. Therefore, in terms of propagating the data type,
> it is essentially performing a 'mov', except that before the 'mov', it
> first needs to be updated by adding the offset or reg2.
>
> A real-world example is shown below:
>
> ffff80008001c9a8 <flush_ptrace_hw_breakpoint>:
> ffff80008001c9c4: add x19, x0, #0xeb8 // x0 (task_struct*) + 0xeb8 -> x19
> * ffff80008001c9d0: ldr x0, [x19]
>
> Before this commit, the type flow broke at the 'add' instruction,
> [ ... ]
> found by insn track: 0(reg19) type-offset=0xeb8
> final result: type='struct task_struct'
>
> Reviewed-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791629326.git.wutengda@huaweicloud.com?part=12
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v7 08/15] perf annotate-data: Track imm_value for stack variables
2026-10-13 13:28 ` [PATCH v7 08/15] perf annotate-data: Track imm_value for stack variables Tengda Wu
@ 2026-10-13 13:47 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-10-13 13:47 UTC (permalink / raw)
To: Tengda Wu; +Cc: linux-perf-users
> Currently, imm_value is tracked in registers but dropped when values
> are saved to or loaded from stack variables during type profiling.
> If a register of type TSR_KIND_CONST is stored to the stack, its value
> will be lost.
>
> Add an imm_value field to struct type_state_stack and update
> set_stack_state() and findnew_stack_state() to accept and preserve the
> immediate value when updating stack state.
>
> Reviewed-by: Shuai Xue <xueshuai@linux.alibaba.com>
> Reviewed-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791629326.git.wutengda@huaweicloud.com?part=8
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v7 14/15] perf annotate-arm64: Support per-cpu variable access tracking
2026-10-13 13:28 ` [PATCH v7 14/15] perf annotate-arm64: Support per-cpu variable access tracking Tengda Wu
@ 2026-10-13 13:49 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-10-13 13:49 UTC (permalink / raw)
To: Tengda Wu; +Cc: linux-perf-users
> Extend update_insn_state_arm64() to handle per-cpu variable addressing.
>
> On arm64, per-cpu variables are accessed by adding a per-cpu offset
> (typically from the '__per_cpu_offset' array) to the address of a global
> variable or a structure field with '__percpu' modifier (e.g.,
> 's32 __percpu *counters' in struct percpu_counter). This results in
> instruction patterns like:
>
> ldr x0, [x6, x5] // Pattern A: direct load per-cpu instance
> add x0, x6, x5 // Pattern B: compute per-cpu address
>
> where x6 holds the per-cpu offset retrieved from:
>
> adrp x4, <page>
> add x4, x4, #offset // x4 = &__per_cpu_offset
> [ ... ]
> chk [58] reg2 offset=0 ok=1 kind=7 global addr : Good!
> found by insn track: 0(reg5, reg2) type-offset=0
> final result: type='int' size=0x4
>
> Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791629326.git.wutengda@huaweicloud.com?part=14
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v7 13/15] perf annotate-arm64: Support 'adrp' instruction to track global variables
2026-10-13 13:28 ` [PATCH v7 13/15] perf annotate-arm64: Support 'adrp' instruction to track global variables Tengda Wu
@ 2026-10-13 13:57 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-10-13 13:57 UTC (permalink / raw)
To: Tengda Wu; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] perf: Stale DWARF lifetime metadata preserved in update_adrp_insn_state
--
commit e2010b4bef31520f5bbfd7a86530f7efd90eacaa
Author: Tengda Wu <wutengda@huaweicloud.com>
perf annotate-arm64: Support 'adrp' instruction to track global variables
Extend update_insn_state_arm64() to track global variable types calculated
via page-relative addressing by introducing TSR_KIND_GLOBAL_ADDR.
> diff --git a/tools/perf/util/annotate-arch/annotate-arm64.c b/tools/perf/util/annotate-arch/annotate-arm64.c
> index e27ba26f3b8ab..f34b944dd285d 100644
> --- a/tools/perf/util/annotate-arch/annotate-arm64.c
> +++ b/tools/perf/util/annotate-arch/annotate-arm64.c
[ ... ]
> @@ -945,6 +974,39 @@ static void update_add_insn_state(struct type_state *state,
> invalidate_reg_state(tsr);
> }
>
> +static void update_adrp_insn_state(struct type_state *state,
> + struct disasm_line *dl,
> + struct annotated_op_loc *dst)
> +{
> + struct type_state_reg *tsr;
> + u32 insn_offset = dl->al.offset;
> + int dreg = dst->reg1;
> +
> + if (!has_reg_type(state, dreg))
> + return;
> +
> + tsr = &state->regs[dreg];
> + tsr->copied_from = -1;
> +
> + if (!dl->ops.source.addr) {
> + invalidate_reg_state(tsr);
> + return;
> + }
> +
> + tsr->kind = TSR_KIND_GLOBAL_ADDR;
> + /*
> + * Stores a partial page-relative address. The full absolute address
> + * of the global variable will be resolved when a subsequent 'add' or
> + * 'ldr' instruction consumes this register.
> + */
> + tsr->imm_value = dl->ops.source.addr;
> + tsr->offset = 0;
> + tsr->ok = true;
[Severity: Medium]
When assigning the new state to the target register, does this code leak
stale DWARF lifetime metadata?
If the register was previously tracking a local variable with an active DWARF
lifetime, the new global address state inherits this stale metadata because
lifetime_active and lifetime_end are not cleared.
When a subsequent function call instruction is encountered, caller-saved
registers are incorrectly preserved if the stale metadata evaluates to true for
reg->lifetime_active and call_addr < reg->lifetime_end. This can poison type
propagation if the register is accidentally reused in subsequent instructions.
Should invalidate_reg_state() be called before assigning the new state, or
should the lifetime fields be manually cleared?
> +
> + pr_debug_dtp("adrp [%x] global addr=%#"PRIx64" -> reg%d\n",
> + insn_offset, tsr->imm_value, dreg);
> +}
> +
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791629326.git.wutengda@huaweicloud.com?part=13
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v7 15/15] perf annotate-arm64: Support 'mrs' instruction to track 'current' pointer
2026-10-13 13:28 ` [PATCH v7 15/15] perf annotate-arm64: Support 'mrs' instruction to track 'current' pointer Tengda Wu
@ 2026-10-13 14:03 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-10-13 14:03 UTC (permalink / raw)
To: Tengda Wu; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] perf annotate-arm64: missing lifetime cleanup in update_mrs_insn_state()
--
commit 084f7875323701c8124c43b96de264a478df7634
Author: Tengda Wu <wutengda@huaweicloud.com>
perf annotate-arm64: Support 'mrs' instruction to track 'current' pointer
This patch extends update_insn_state_arm64() to handle the mrs instruction.
It enables tracking the current task pointer in the kernel, which is
typically accessed via the sp_el0 system register.
> diff --git a/tools/perf/util/annotate-arch/annotate-arm64.c b/tools/perf/util/annotate-arch/annotate-arm64.c
> index 5683215f07708..6da558f7e8648 100644
> --- a/tools/perf/util/annotate-arch/annotate-arm64.c
> +++ b/tools/perf/util/annotate-arch/annotate-arm64.c
[ ... ]
> @@ -1030,6 +1032,71 @@ static void update_adrp_insn_state(struct type_state *state,
> insn_offset, tsr->imm_value, dreg);
> }
>
> +static void update_mrs_insn_state(struct type_state *state,
> + struct data_loc_info *dloc, Dwarf_Die *cu_die,
> + struct disasm_line *dl,
> + struct annotated_op_loc *dst)
> +{
> + struct type_state_reg *tsr;
> + Dwarf_Die type_die;
> + u32 insn_offset = dl->al.offset;
> + int dreg = dst->reg1;
> + Dwarf_Die func_die;
> + Dwarf_Attribute attr;
> + u64 ip, pc;
> + struct strbuf sb;
> + char *type_name;
> +
> + if (!has_reg_type(state, dreg))
> + return;
> +
> + tsr = &state->regs[dreg];
> + tsr->copied_from = -1;
> +
> + /* Handle case difference: LLVM (SP_EL0) vs objdump (sp_el0) */
> + if (!dso__kernel(map__dso(dloc->ms->map)) ||
> + strcasecmp(dl->ops.source.raw, "sp_el0")) {
> + invalidate_reg_state(tsr);
> + return;
> + }
[ ... ]
> + if (!type_name || strcmp(type_name, "struct task_struct*")) {
> + invalidate_reg_state(tsr);
> + goto out_free;
> + }
> +
> + tsr->type = type_die;
> + tsr->kind = TSR_KIND_TYPE;
> + tsr->offset = 0;
> + tsr->imm_value = 0;
> + tsr->ok = true;
[Severity: Medium]
Are we missing a cleanup of the previous lifetime state for the destination
register here?
If the target register previously held a variable with an active Dwarf
lifetime, the lifetime_active flag remains true. Upon a subsequent function
call, the register tracking logic skips invalidating caller-saved registers
that have an active lifetime.
This could cause the target register (e.g., x0 holding current) to
incorrectly survive the function call in the analysis state, even though
the hardware register is clobbered by the callee.
Should this path clear tsr->lifetime_active and tsr->lifetime_end, or
perhaps call invalidate_reg_state() earlier before assigning the new
properties?
> +
> + pr_debug_dtp("mrs [%x] sp_el0 -> reg%d", insn_offset, dreg);
> + pr_debug_type_name(&type_die, tsr->kind);
> +
> +out_free:
> + free(type_name);
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791629326.git.wutengda@huaweicloud.com?part=15
^ permalink raw reply [flat|nested] 31+ messages in thread
end of thread, other threads:[~2026-10-13 14:03 UTC | newest]
Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-13 13:27 [PATCH v7 00/15] perf annotate arm64: Support instruction tracking for data type profiling Tengda Wu
2026-10-13 13:27 ` [PATCH v7 01/15] perf annotate-data: Extract invalidate_reg_state() as a common helper Tengda Wu
2026-10-13 13:34 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 02/15] perf annotate-arm64: Enable instruction tracking support Tengda Wu
2026-10-13 13:38 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 03/15] perf annotate-data: Add arch_get_reg_offset helper Tengda Wu
2026-10-13 13:38 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 04/15] perf annotate-arm64: Track return type after call instructions Tengda Wu
2026-10-13 13:36 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 05/15] perf annotate-arm64: Support load instruction tracking Tengda Wu
2026-10-13 13:38 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 06/15] perf annotate-arm64: Support store " Tengda Wu
2026-10-13 13:36 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 07/15] perf annotate-data: Expand type_state_reg imm_value to u64 Tengda Wu
2026-10-13 13:45 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 08/15] perf annotate-data: Track imm_value for stack variables Tengda Wu
2026-10-13 13:47 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 09/15] perf annotate-x86: Delete stale stack state on store of untracked register Tengda Wu
2026-10-13 13:44 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 10/15] perf annotate-arm64: Support stack variable tracking Tengda Wu
2026-10-13 13:44 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 11/15] perf annotate-arm64: Support 'mov' instruction tracking Tengda Wu
2026-10-13 13:45 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 12/15] perf annotate-arm64: Support 'add' " Tengda Wu
2026-10-13 13:47 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 13/15] perf annotate-arm64: Support 'adrp' instruction to track global variables Tengda Wu
2026-10-13 13:57 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 14/15] perf annotate-arm64: Support per-cpu variable access tracking Tengda Wu
2026-10-13 13:49 ` sashiko-bot
2026-10-13 13:28 ` [PATCH v7 15/15] perf annotate-arm64: Support 'mrs' instruction to track 'current' pointer Tengda Wu
2026-10-13 14:03 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox