From: Yonghong Song <yonghong.song@linux.dev>
To: Alan Maguire <alan.maguire@oracle.com>,
Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com>,
dwarves@vger.kernel.org
Cc: Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
bpf@vger.kernel.org, kernel-team@fb.com
Subject: [PATCH dwarves v6 3/5] dwarf_loader: Analyze per-parameter information for true signatures
Date: Wed, 17 Jun 2026 18:14:14 -0700 [thread overview]
Message-ID: <20260618011414.638700-1-yonghong.song@linux.dev> (raw)
In-Reply-To: <20260618011358.632394-1-yonghong.song@linux.dev>
Add a function-level pass, function__analyze_parameter_locations(), run
from cu__resolve_func_ret_types_optimized() which walks a function's
parameters in ABI argument-register order and consumes the location state
decoded by parameter__decode_location() in the previous commit. Each
parameter advances the expected-register index by the number of argument
registers it occupies (parameter__abi_slots(), e.g. a two-eightbyte
aggregate consumes two registers).
For every producer it keeps the existing bookkeeping, now driven by the
decoded fields:
- a parameter with no location, a constant value, or (for non-clang) no
register found is marked optimized out
- a parameter found in a register other than the expected one is marked
unexpected_reg
When true_signature is enabled for a signature-changed function it
reconstructs the real register-level signature:
- parameters that were optimized out are dropped from the signature
- a parameter whose location cannot be tied to its expected register,
wrong register, no register found, or a non-aggregate sitting on the
stack - marks the function unexpected_reg so no untrustworthy signature
is emitted;
- an aggregate genuinely passed on the stack (passed_in_memory) is kept;
- an aggregate split across registers via DW_OP_piece is kept whole when
it is fully used or the next parameter still lands on its expected
register, otherwise it is rewritten to the single member actually passed
in a register (true_sig_*).
Together with the decoding commit this replaces the previous inline,
per-parameter register check in parameter__new().
Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
---
dwarf_loader.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 148 insertions(+), 3 deletions(-)
diff --git a/dwarf_loader.c b/dwarf_loader.c
index ae4ac2f..31498e5 100644
--- a/dwarf_loader.c
+++ b/dwarf_loader.c
@@ -2931,6 +2931,149 @@ static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu)
}
}
+static struct parameter *ftype__next_parameter(struct ftype *ftype, struct parameter *parm)
+{
+ if (parm->tag.node.next == &ftype->parms)
+ return NULL;
+ return list_entry(parm->tag.node.next, struct parameter, tag.node);
+}
+
+static int parameter__abi_slots(const struct parameter *parm, const struct cu *cu)
+{
+ int slots;
+
+ if (!cu->agg_use_two_regs || parm->type_byte_size <= cu->addr_size)
+ return 1;
+
+ slots = (parm->type_byte_size + cu->addr_size - 1) / cu->addr_size;
+ return slots > 0 ? slots : 1;
+}
+
+static bool parameter__has_piece_info(const struct parameter *parm)
+{
+ return parm->first_reg_fields || parm->second_reg_fields;
+}
+
+static bool parameter__uses_full_aggregate(const struct parameter *parm)
+{
+ return parm->first_reg_fields && parm->second_reg_fields;
+}
+
+static bool ftype__next_parameter_preserves_slots(struct ftype *ftype, struct parameter *parm,
+ int reg_idx, int slots, struct cu *cu)
+{
+ struct parameter *next = ftype__next_parameter(ftype, parm);
+ int next_reg_idx;
+
+ if (!next || next->loc_reg == PARAMETER_UNKNOWN_REG)
+ return false;
+
+ next_reg_idx = reg_idx + slots;
+ return next_reg_idx < cu->nr_register_params &&
+ next->loc_reg == cu->register_params[next_reg_idx];
+}
+
+static bool parameter__apply_true_sig_member(struct parameter *parm, struct cu *cu)
+{
+ struct dwarf_tag tmp = {};
+ struct dwarf_tag *dtype;
+
+ if (!parm->true_sig_member_name || parm->true_sig_type == 0)
+ return false;
+
+ tmp.type = parm->true_sig_type;
+ tmp.from_types_section.type = parm->true_sig_type_from_types;
+ dtype = __dwarf_cu__find_type_by_ref(cu->priv, tmp.type, tmp.from_types_section.type);
+ if (!dtype)
+ return false;
+
+ parm->tag.type = dtype->small_id;
+ return true;
+}
+
+static void function__analyze_parameter_locations(struct function *fn, struct cu *cu,
+ struct conf_load *conf)
+{
+ struct ftype *ftype = &fn->proto;
+ struct parameter *pos;
+ bool true_sig_enabled = conf->true_signature && ftype->signature_changed;
+ bool check_registers = !cu->producer_clang || true_sig_enabled;
+ int reg_idx = 0;
+
+ if (!check_registers)
+ return;
+
+ ftype__for_each_parameter(ftype, pos) {
+ bool consumes_register = true;
+ bool regs_available = reg_idx < cu->nr_register_params;
+ int slots = parameter__abi_slots(pos, cu);
+ int expected_reg = regs_available ? cu->register_params[reg_idx] : -1;
+ int reg_slots = pos->passed_in_memory ? 1 : slots;
+
+ if (pos->has_loc) {
+ if (true_sig_enabled && pos->loc_const_value) {
+ pos->optimized = 1;
+ consumes_register = false;
+ goto next;
+ }
+
+ if (!regs_available) {
+ consumes_register = false;
+ goto next;
+ }
+
+ if (true_sig_enabled && pos->loc_stack) {
+ if (pos->passed_in_memory)
+ consumes_register = false;
+ else
+ pos->unexpected_reg = 1;
+ goto next;
+ }
+
+ if (pos->loc_reg == PARAMETER_UNKNOWN_REG) {
+ if (true_sig_enabled)
+ pos->unexpected_reg = 1;
+ else
+ pos->optimized = 1;
+ goto next;
+ }
+
+ if (expected_reg >= 0 && expected_reg != pos->loc_reg) {
+ pos->unexpected_reg = 1;
+ goto next;
+ }
+
+ if (true_sig_enabled && parameter__has_piece_info(pos)) {
+ if (parameter__uses_full_aggregate(pos) ||
+ ftype__next_parameter_preserves_slots(ftype, pos, reg_idx, slots, cu)) {
+ reg_idx += slots;
+ continue;
+ }
+
+ if (parameter__apply_true_sig_member(pos, cu)) {
+ reg_idx++;
+ continue;
+ }
+ }
+ } else if (pos->has_const_value && !cu->producer_clang) {
+ pos->optimized = 1;
+ } else if (true_sig_enabled) {
+ if (regs_available &&
+ ftype__next_parameter_preserves_slots(ftype, pos, reg_idx, slots, cu)) {
+ reg_idx += slots;
+ continue;
+ }
+
+ pos->optimized = 1;
+ consumes_register = false;
+ }
+
+next:
+ if (consumes_register)
+ reg_idx += reg_slots;
+ }
+}
+
static void lexblock__recode_dwarf_types(struct lexblock *tag, struct cu *cu)
{
struct tag *pos;
@@ -3206,7 +3349,7 @@ static bool param__is_struct(struct cu *cu, struct tag *tag)
}
}
-static int cu__resolve_func_ret_types_optimized(struct cu *cu)
+static int cu__resolve_func_ret_types_optimized(struct cu *cu, struct conf_load *conf)
{
struct ptr_table *pt = &cu->functions_table;
uint32_t i;
@@ -3217,6 +3360,8 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu)
struct function *fn = tag__function(tag);
bool has_unexpected_reg = false, has_struct_param = false;
+ function__analyze_parameter_locations(fn, cu, conf);
+
/* mark function as optimized if parameter is, or
* if parameter does not have a location; at this
* point location presence has been marked in
@@ -3395,7 +3540,7 @@ static int die__process_and_recode(Dwarf_Die *die, struct cu *cu, struct conf_lo
if (ret != 0)
return ret;
- return cu__resolve_func_ret_types_optimized(cu);
+ return cu__resolve_func_ret_types_optimized(cu, conf);
}
static int class_member__cache_byte_size(struct tag *tag, struct cu *cu,
@@ -4158,7 +4303,7 @@ static int cus__merge_and_process_cu(struct cus *cus, struct conf_load *conf,
* encoded in another subprogram through abstract_origin
* tag. Let us visit all subprograms again to resolve this.
*/
- if (cu__resolve_func_ret_types_optimized(cu) != LSK__KEEPIT)
+ if (cu__resolve_func_ret_types_optimized(cu, conf) != LSK__KEEPIT)
goto out_abort;
cu__finalize(cu, cus, conf);
--
2.53.0-Meta
next prev parent reply other threads:[~2026-06-18 1:14 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-18 1:13 [PATCH dwarves v6 0/5] pahole: Encode true signatures in kernel BTF Yonghong Song
2026-06-18 1:14 ` [PATCH dwarves v6 1/5] dwarf_loader: Detect aggregate ABI register usage and signature changes Yonghong Song
2026-06-18 1:14 ` [PATCH dwarves v6 2/5] dwarf_loader: Collect per-parameter information Yonghong Song
2026-06-18 1:14 ` Yonghong Song [this message]
2026-06-18 1:14 ` [PATCH dwarves v6 4/5] btf_encoder: Emit true function signatures Yonghong Song
2026-06-18 1:14 ` [PATCH dwarves v6 5/5] tests: add BTF true_signature encoding tests Yonghong Song
2026-06-20 8:46 ` [PATCH dwarves v6 0/5] pahole: Encode true signatures in kernel BTF Alan Maguire
2026-06-21 16:47 ` Yonghong Song
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260618011414.638700-1-yonghong.song@linux.dev \
--to=yonghong.song@linux.dev \
--cc=alan.maguire@oracle.com \
--cc=andrii@kernel.org \
--cc=arnaldo.melo@gmail.com \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=dwarves@vger.kernel.org \
--cc=kernel-team@fb.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.