From nobody Fri Apr 3 06:25:01 2026 Received: from mail-yx1-f43.google.com (mail-yx1-f43.google.com [74.125.224.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3EB7240B6CB for ; Mon, 9 Mar 2026 17:56:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.224.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773078970; cv=none; b=Dr/T+NAVyslXZX5BlF5bjSUHU80MPT+uDv6bINbqTelSlxgGNY+KuLfp8AfrUic4Ec6mMD/bk3k3pP6aGcLU4B7FMo0NIyAJ+MjvzQ22+RW0qe9QdJCEk7KbpAOpWN0wC7IAYMUwHA/h/+Jw68mm5nZclQdfca3VfAF/RwROUnA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773078970; c=relaxed/simple; bh=q6LE+ixU1zVz16lgmY2eKxe6TkipgC5NpO0sfrkT0Wk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lKZ59IhSzN6f2UgAKHqdq/TSGCMHEUO6HGv58igAusFeS71Gd+AT6INqrozJZyfAXBvWdaECG04u6U66JQAQc6+f6HYAWtW5R5Q8QUAZZ36lkmBOK9J+zhCAME/bXPr0bTq1qojRkH5re5sz2JatpVKLUbGrIJQOahZb35hl/NQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ncsu.edu; spf=pass smtp.mailfrom=ncsu.edu; dkim=pass (2048-bit key) header.d=ncsu.edu header.i=@ncsu.edu header.b=cBzKWTyS; arc=none smtp.client-ip=74.125.224.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ncsu.edu Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ncsu.edu Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ncsu.edu header.i=@ncsu.edu header.b="cBzKWTyS" Received: by mail-yx1-f43.google.com with SMTP id 956f58d0204a3-64937edbc9eso10913732d50.2 for ; Mon, 09 Mar 2026 10:56:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ncsu.edu; s=google; t=1773078964; x=1773683764; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=NXlD/hErpPiic9ODLls/lxSmno+4Yc8/kOa6LrdepnM=; b=cBzKWTySOn8qXWCA4XoDCCaM89ZzObrOqD9Fc2Svj6oxV35rMxDbg5PREo9gKAjeGB zSrRaQ0+R4KLgzjOeBafv+5dj4rUkgD/DVk+WS8hp6ZgVGsrRUbKacrdPjnF6LXMi4FV Sjh0HiOamRjgqZixyIkC9Wl/iPVRo63+9cGRzi0b9uF3/aZGW5tB3HEWziI84xLj3ibS 3DFzN06IQ/pPzyOPH+P/6TC27syAn6HUzYM94G798r5BF0Pw6s2WEGkEMBoRm8I0lTvs 0vKWCitfZhzO9/bhcbe+91Y0ZpoOuCn8D+NJlclP9G+B8Fb3zIwtNZ5YXGM0/+uZ4TUK hVMg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773078964; x=1773683764; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=NXlD/hErpPiic9ODLls/lxSmno+4Yc8/kOa6LrdepnM=; b=ts7MwY/4MSMw7+SVbDXyW+b90C+WzohEvmiBrGn4Gij00q7JzuAhxK2jJunQqWiQRw xbFilcoCGhfE3ufgaHW6AbvXfepPtYicbznPTSdnQz8aKX7Ixe0BLY509/yZN/Ea0y8t 2SyQPNBavLXSPcV4HH+dM2yLsYwone69KIZZFHH7oyA7azlCNCOdcOCFqdrf6SUjW/2S WNLntliuZX6QjM1WWiQB5XMkCRDANbLsL92YZcwmrj5T3UxCY52DdTabNUFdCBc+TUGm yFhYtF2pPYFoCx9Zd6Fhcpi/smm+9Pdf5yJu0voZla0fvIwLl/6jWWum7/eUjISJzj7q cj6w== X-Forwarded-Encrypted: i=1; AJvYcCXiQUj1CBK2Y3e8XlzmGlC7O4qp/avRsok2jtlP5KHVVJU01SU7uLhl0Bm2Wjbbgt1b606nfgVo1EwO4zA=@vger.kernel.org X-Gm-Message-State: AOJu0YwU2mVqu2Yb5yZLKwkVAw/RP0G70qQ8a87mJntyk4oKEuNLFXTx ss8WO9DhjJnnyP2uVM8Tr3SYKjCgMVFGv1aYv5St2AUb88ToxVxquuwictORmTKFSw== X-Gm-Gg: ATEYQzxKLtV3g/vVxBNFxh7sXBpAdVWleLVGQJp21ABfAxferw9mE0pELiY9yqMDJxS prXx4yRIX9AuPFZXUh3sGx0n2dILk4mFMQKngIDT/FIxR1HL72edUiyTE77oykhE7hpeD+Wal+e ULFQtzH98AA4Oicr/svMP1uqExLVt2aQVbKZOLdjmic+xF1MuOYBMw3M4CZHDVejpyCxJyIlz9i oEfo/QreNIRr9JamRUYCkOD7vIJEz77CzZ1QT3jObgHE5fyY5hYd4Q7A3hfFeQCqj0HFIoM1YwD xE5xRtKwiSrAprUXy5y7K2vJdvoECikd2jfCmZFDhpvcByS7jq1KPue93ooGWYtajJcKmXjyrRz EkRw0jMQVjbXjj4HcW0ouT8yPH5fbahjEZKEihsfTS+A4bPv+ccrNOyCub6/yOs46d2egLgO2aX 3J7+KbjO2F+eEIYzEgTko3la7QskmBULAkmb31b/IFf1UohJYWj7cVtBN2 X-Received: by 2002:a05:690e:b88:b0:64d:29a4:c933 with SMTP id 956f58d0204a3-64d29a4cc49mr5162990d50.56.1773078963881; Mon, 09 Mar 2026 10:56:03 -0700 (PDT) Received: from um773-cachyos.sd.ncsu.edu ([152.7.255.206]) by smtp.gmail.com with ESMTPSA id 956f58d0204a3-64d176e70e7sm4992535d50.20.2026.03.09.10.56.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Mar 2026 10:56:01 -0700 (PDT) From: Zecheng Li To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim Cc: Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , James Clark , Zecheng Li , xliuprof@google.com, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 10/11] perf annotate-data: Use DWARF location ranges to preserve reg state Date: Mon, 9 Mar 2026 13:55:23 -0400 Message-ID: <20260309175546.916039-11-zli94@ncsu.edu> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260309175546.916039-1-zli94@ncsu.edu> References: <20260309175546.916039-1-zli94@ncsu.edu> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" When a function call occurs, caller-saved registers are typically invalidated since the callee may clobber them. However, DWARF debug info provides location ranges that indicate exactly where a variable is valid in a register. Track the DWARF location range end address in type_state_reg and use it to determine if a caller-saved register should be preserved across a call. If the current call address is within the DWARF-specified lifetime of the variable, keep the register state valid instead of invalidating it. This improves type annotation for code where the compiler knows a register value survives across calls (e.g., when the callee is known not to clobber certain registers or when the value is reloaded after the call at the same logical location). Changes: - Add `end` and `has_range` fields to die_var_type to capture DWARF location range information - Add `lifetime_active` and `lifetime_end` fields to type_state_reg - Check location lifetime before invalidating caller-saved registers Signed-off-by: Zecheng Li --- tools/perf/util/annotate-arch/annotate-x86.c | 25 +++++++++++++++++--- tools/perf/util/annotate-data.c | 24 +++++++++++++++++-- tools/perf/util/annotate-data.h | 3 +++ tools/perf/util/dwarf-aux.c | 6 ++++- tools/perf/util/dwarf-aux.h | 2 ++ 5 files changed, 54 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/annotate-arch/annotate-x86.c b/tools/perf/util= /annotate-arch/annotate-x86.c index df9fc0a51b39..c77aabd48eba 100644 --- a/tools/perf/util/annotate-arch/annotate-x86.c +++ b/tools/perf/util/annotate-arch/annotate-x86.c @@ -208,6 +208,8 @@ static void invalidate_reg_state(struct type_state_reg = *reg) { reg->kind =3D TSR_KIND_INVALID; reg->ok =3D false; + reg->lifetime_active =3D false; + reg->lifetime_end =3D 0; reg->copied_from =3D -1; } =20 @@ -230,6 +232,7 @@ static void update_insn_state_x86(struct type_state *st= ate, if (ins__is_call(&dl->ins)) { struct symbol *func =3D dl->ops.target.sym; const char *call_name; + u64 call_addr; =20 /* Try to resolve the call target name */ if (func) @@ -246,10 +249,18 @@ static void update_insn_state_x86(struct type_state *= state, else pr_debug_dtp("call [%x] \n", insn_offset); =20 - /* Invalidate caller-saved registers after call (ABI requirement) */ + /* Invalidate caller-saved registers after call */ + call_addr =3D map__rip_2objdump(dloc->ms->map, + dloc->ms->sym->start + dl->al.offset); for (unsigned i =3D 0; i < ARRAY_SIZE(state->regs); i++) { - if (state->regs[i].caller_saved) - invalidate_reg_state(&state->regs[i]); + struct type_state_reg *reg =3D &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); } =20 /* Update register with the return type (if any) */ @@ -279,6 +290,8 @@ static void update_insn_state_x86(struct type_state *st= ate, =20 tsr =3D &state->regs[dst->reg1]; tsr->copied_from =3D -1; + tsr->lifetime_active =3D false; + tsr->lifetime_end =3D 0; =20 if (src->imm) imm_value =3D src->offset; @@ -344,6 +357,8 @@ static void update_insn_state_x86(struct type_state *st= ate, =20 tsr =3D &state->regs[dst->reg1]; tsr->copied_from =3D -1; + tsr->lifetime_active =3D false; + tsr->lifetime_end =3D 0; =20 if (src->imm) imm_value =3D src->offset; @@ -458,6 +473,8 @@ static void update_insn_state_x86(struct type_state *st= ate, state->regs[dst->reg1].kind =3D TSR_KIND_CONST; state->regs[dst->reg1].imm_value =3D 0; state->regs[dst->reg1].ok =3D true; + state->regs[dst->reg1].lifetime_active =3D false; + state->regs[dst->reg1].lifetime_end =3D 0; state->regs[dst->reg1].copied_from =3D -1; return; } @@ -544,6 +561,8 @@ static void update_insn_state_x86(struct type_state *st= ate, tsr->kind =3D state->regs[src->reg1].kind; tsr->imm_value =3D state->regs[src->reg1].imm_value; tsr->offset =3D state->regs[src->reg1].offset; + tsr->lifetime_active =3D state->regs[src->reg1].lifetime_active; + tsr->lifetime_end =3D state->regs[src->reg1].lifetime_end; tsr->ok =3D true; =20 /* To copy back the variable type later (hopefully) */ diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-dat= a.c index 50c82c91f828..1eff0a27237d 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -840,6 +840,18 @@ static bool die_is_same(Dwarf_Die *die_a, Dwarf_Die *d= ie_b) return (die_a->cu =3D=3D die_b->cu) && (die_a->addr =3D=3D die_b->addr); } =20 +static void tsr_set_lifetime(struct type_state_reg *tsr, + const struct die_var_type *var) +{ + if (var && var->has_range && var->end > var->addr) { + tsr->lifetime_active =3D true; + tsr->lifetime_end =3D var->end; + } else { + tsr->lifetime_active =3D false; + tsr->lifetime_end =3D 0; + } +} + /** * update_var_state - Update type state using given variables * @state: type state table @@ -865,8 +877,14 @@ static void update_var_state(struct type_state *state,= struct data_loc_info *dlo } =20 for (var =3D var_types; var !=3D NULL; var =3D var->next) { - if (var->addr !=3D addr) - continue; + /* Check if addr falls within the variable's valid range */ + if (var->has_range) { + if (addr < var->addr || (var->end && addr >=3D var->end)) + continue; + } else { + if (addr !=3D var->addr) + continue; + } /* Get the type DIE using the offset */ if (!dwarf_offdie(dloc->di->dbg, var->die_off, &mem_die)) continue; @@ -923,6 +941,7 @@ static void update_var_state(struct type_state *state, = struct data_loc_info *dlo reg->type =3D mem_die; reg->kind =3D TSR_KIND_POINTER; reg->ok =3D true; + tsr_set_lifetime(reg, var); =20 pr_debug_dtp("var [%"PRIx64"] reg%d addr offset %x", insn_offset, var->reg, var->offset); @@ -939,6 +958,7 @@ static void update_var_state(struct type_state *state, = struct data_loc_info *dlo reg->type =3D mem_die; reg->kind =3D TSR_KIND_TYPE; reg->ok =3D true; + tsr_set_lifetime(reg, var); =20 pr_debug_dtp("var [%"PRIx64"] reg%d offset %x", insn_offset, var->reg, var->offset); diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-dat= a.h index 9b222869e42d..c26130744260 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -182,6 +182,9 @@ struct type_state_reg { s32 offset; bool ok; bool caller_saved; + /* DWARF location range tracking for register lifetime */ + bool lifetime_active; + u64 lifetime_end; u8 kind; u8 copied_from; }; diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 1feefc329154..0710c875416f 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1641,7 +1641,7 @@ static int __die_collect_vars_cb(Dwarf_Die *die_mem, = void *arg) Dwarf_Die type_die; int tag =3D dwarf_tag(die_mem); Dwarf_Attribute attr; - Dwarf_Addr base, start, end; + Dwarf_Addr base, start, end =3D 0; Dwarf_Op *ops; size_t nops; struct die_var_type *vt; @@ -1681,6 +1681,8 @@ static int __die_collect_vars_cb(Dwarf_Die *die_mem, = void *arg) =20 vt->die_off =3D dwarf_dieoffset(&type_die); vt->addr =3D start; + vt->end =3D end; + vt->has_range =3D (end !=3D 0 || start !=3D 0); vt->reg =3D reg_from_dwarf_op(ops); vt->offset =3D offset_from_dwarf_op(ops); vt->next =3D *var_types; @@ -1743,6 +1745,8 @@ static int __die_collect_global_vars_cb(Dwarf_Die *di= e_mem, void *arg) =20 vt->die_off =3D dwarf_dieoffset(&type_die); vt->addr =3D ops->number; + vt->end =3D 0; + vt->has_range =3D false; vt->reg =3D -1; vt->offset =3D 0; vt->next =3D *var_types; diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index 939a59c91796..a79968a2e573 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -148,10 +148,12 @@ struct die_var_type { struct die_var_type *next; u64 die_off; u64 addr; + u64 end; /* end address of location range */ int reg; int offset; /* Whether the register holds a address to the type */ bool is_reg_var_addr; + bool has_range; /* whether end is valid */ }; =20 /* Return type info of a member at offset */ --=20 2.53.0