summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorTengda Wu <wutengda@huaweicloud.com>2026-10-20 13:44:58 +0000
committerArnaldo Carvalho de Melo <acme@redhat.com>2026-10-22 17:17:01 -0300
commit059f12f8cd29adcf59973a8ea4ca96ea4873fcf0 (patch)
tree03b1ac7a58e2ecd6aa0d28a3355ce3ec6f914684 /tools
parentedc11f5794424988314966df3bde1d8573972cd7 (diff)
downloadlinux-059f12f8cd29adcf59973a8ea4ca96ea4873fcf0.tar.gz
linux-059f12f8cd29adcf59973a8ea4ca96ea4873fcf0.zip
perf annotate-arm64: Enable instruction tracking support
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. For now the invalidation path does not treat special instructions individually; doing so for every such instruction up front would be costly. A TODO is therefore left in invalidate_unhandled_insn_regs() marking where per-instruction invalidation handling is to be extended in future 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> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/util/annotate-arch/annotate-arm64.c87
-rw-r--r--tools/perf/util/annotate-data.c15
2 files changed, 101 insertions, 1 deletions
diff --git a/tools/perf/util/annotate-arch/annotate-arm64.c b/tools/perf/util/annotate-arch/annotate-arm64.c
index 6549535961a9..d591d556ad40 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,86 @@ check_modifiers:
}
}
+#ifdef HAVE_LIBDW_SUPPORT
+/* Check if the instruction is read-only (does not modify register state). */
+static bool is_readonly_insn(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_call_insn_state(struct type_state *state,
+ struct data_loc_info *dloc,
+ struct disasm_line *dl)
+{
+ struct symbol *func = dl->ops.target.sym;
+ const char *call_name;
+ u64 call_addr;
+ u32 insn_offset = dl->al.offset;
+
+ 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);
+ }
+}
+
+/* Invalidate registers explicitly written by an unhandled instruction. */
+static void invalidate_unhandled_insn_regs(struct type_state *state,
+ struct disasm_line *dl,
+ struct annotated_op_loc *dst)
+{
+ u32 insn_offset = dl->al.offset;
+
+ /* Invalidate destination registers */
+ 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");
+ }
+
+ /* TODO: Extend invalidation support to more special instructions. */
+}
+
+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];
+
+ if (is_readonly_insn(dl->ins.name))
+ return;
+
+ if (annotate_get_insn_location(dloc->arch, dl, &loc) < 0)
+ return;
+
+ if (ins__is_call(&dl->ins))
+ update_call_insn_state(state, dloc, dl);
+ else
+ invalidate_unhandled_insn_regs(state, dl, dst);
+}
+#endif
+
const struct arch *arch__new_arm64(const struct e_machine_and_e_flags *id,
const char *cpuid __maybe_unused)
{
@@ -467,6 +551,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 @@ out:
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;
}