]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
perf annotate-data: Invalidate caller-saved regs for all calls
authorZecheng Li <zli94@ncsu.edu>
Mon, 9 Mar 2026 17:55:22 +0000 (13:55 -0400)
committerNamhyung Kim <namhyung@kernel.org>
Thu, 19 Mar 2026 21:42:29 +0000 (14:42 -0700)
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 <zli94@ncsu.edu>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
tools/perf/util/annotate-arch/annotate-x86.c

index eb390a253d71cb22c6570689002abc456841ce58..df9fc0a51b39c24e4dd8061acec1f39afc2dd404 100644 (file)
@@ -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] <unknown>\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;