From: Zecheng Li Date: Mon, 9 Mar 2026 17:55:22 +0000 (-0400) Subject: perf annotate-data: Invalidate caller-saved regs for all calls X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d35b0d5877109ecca106cc3835d4d23ac2cdc33c;p=thirdparty%2Flinux.git perf annotate-data: Invalidate caller-saved regs for all calls Previously, the x86 call handler returned early without invalidating caller-saved registers when the call target symbol could not be resolved (func == NULL). This violated the ABI which requires caller-saved registers to be considered clobbered after any call instruction. Fix this by: 1. Always invalidating caller-saved registers for any call instruction (except __fentry__ which preserves registers) 2. Using dl->ops.target.name as fallback when func->name is unavailable, allowing return type lookup for more call targets This is a conservative change that may reduce type coverage for indirect calls (e.g., callq *(%rax)) where we cannot determine the return type but it ensures correctness. Signed-off-by: Zecheng Li Signed-off-by: Namhyung Kim --- diff --git a/tools/perf/util/annotate-arch/annotate-x86.c b/tools/perf/util/annotate-arch/annotate-x86.c index eb390a253d71c..df9fc0a51b39c 100644 --- a/tools/perf/util/annotate-arch/annotate-x86.c +++ b/tools/perf/util/annotate-arch/annotate-x86.c @@ -229,24 +229,31 @@ static void update_insn_state_x86(struct type_state *state, if (ins__is_call(&dl->ins)) { struct symbol *func = dl->ops.target.sym; + const char *call_name; - if (func == NULL) - return; + /* Try to resolve the call target name */ + if (func) + call_name = func->name; + else + call_name = dl->ops.target.name; /* __fentry__ will preserve all registers */ - if (!strcmp(func->name, "__fentry__")) + if (call_name && !strcmp(call_name, "__fentry__")) return; - pr_debug_dtp("call [%x] %s\n", insn_offset, func->name); + if (call_name) + pr_debug_dtp("call [%x] %s\n", insn_offset, call_name); + else + pr_debug_dtp("call [%x] \n", insn_offset); - /* Otherwise invalidate caller-saved registers after call */ + /* Invalidate caller-saved registers after call (ABI requirement) */ for (unsigned i = 0; i < ARRAY_SIZE(state->regs); i++) { if (state->regs[i].caller_saved) invalidate_reg_state(&state->regs[i]); } /* Update register with the return type (if any) */ - if (die_find_func_rettype(cu_die, func->name, &type_die)) { + if (call_name && die_find_func_rettype(cu_die, call_name, &type_die)) { tsr = &state->regs[state->ret_reg]; tsr->type = type_die; tsr->kind = TSR_KIND_TYPE;