From: Alan Maguire <alan.maguire@oracle.com>
To: acme@kernel.org, ast@kernel.org, andrii@kernel.org,
eddyz87@gmail.com, qmo@kernel.org
Cc: dwarves@vger.kernel.org, jolsa@kernel.org, daniel@iogearbox.net,
ihor.solodrai@linux.dev, yonghong.song@linux.dev,
song@kernel.org, martin.lau@linux.dev, memxor@gmail.com,
emil@etsalapatis.com, bpf@vger.kernel.org, nsc@kernel.org,
puranjay@kernel.org, yatsenko@meta.com,
Alan Maguire <alan.maguire@oracle.com>
Subject: [PATCH v3 dwarves 1/9] dwarf_loader: Add parameter list to inlined expansions
Date: Fri, 25 Sep 2026 19:51:50 +0100 [thread overview]
Message-ID: <20260925185200.1318067-2-alan.maguire@oracle.com> (raw)
In-Reply-To: <20260925185200.1318067-1-alan.maguire@oracle.com>
DW_TAG_formal_parameter children of DW_TAG_inlined_subroutine are
currently skipped, so callers cannot iterate parameters that belong to a
specific inline expansion. Store those parameters directly on struct
inline_expansion instead of leaving them in the surrounding lexical block.
Add an inline_expansion parameter list, populate it while processing
inline-subroutine children, and include it in tag cleanup and
cu__for_all_tags() traversal. Recode inline-expansion parameter types via
the same parameter recoding path used for function prototypes.
Signed-off-by: Thierry Treyer <ttreyer@meta.com>
Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
---
dwarf_loader.c | 211 ++++++++++++++++++++++++++-----------------------
dwarves.c | 34 ++++++++
dwarves.h | 6 ++
3 files changed, 153 insertions(+), 98 deletions(-)
diff --git a/dwarf_loader.c b/dwarf_loader.c
index 1e5363a..2165621 100644
--- a/dwarf_loader.c
+++ b/dwarf_loader.c
@@ -2022,6 +2022,8 @@ static struct inline_expansion *inline_expansion__new(Dwarf_Die *die, struct cu
dwarf_tag__set_attr_type(dtag, DWARF_TAG__REF_TYPE, die, DW_AT_abstract_origin, cu);
exp->ip.addr = 0;
exp->high_pc = 0;
+ exp->nr_parms = 0;
+ INIT_LIST_HEAD(&exp->parms);
if (!cu->has_addr_info)
goto out;
@@ -2559,6 +2561,7 @@ static struct tag *die__create_new_string_type(Dwarf_Die *die, struct cu *cu)
static struct tag *die__create_new_parameter(Dwarf_Die *die,
struct ftype *ftype,
struct lexblock *lexblock,
+ struct inline_expansion *exp,
struct cu *cu, struct conf_load *conf,
int param_idx)
{
@@ -2575,7 +2578,7 @@ static struct tag *die__create_new_parameter(Dwarf_Die *die,
if (add_gnu_annotation_chain(die, param_idx, conf, &(tag__function(&ftype->tag)->annots)))
return NULL;
}
- } else {
+ } else if (exp == NULL) {
/*
* DW_TAG_formal_parameters on a non DW_TAG_subprogram nor
* DW_TAG_subroutine_type tag happens sometimes, likely due to
@@ -2587,6 +2590,7 @@ static struct tag *die__create_new_parameter(Dwarf_Die *die,
*/
lexblock__add_tag(lexblock, &parm->tag);
}
+ /* Inline-expansion parameters are linked after CU-table registration. */
return &parm->tag;
}
@@ -2656,7 +2660,7 @@ static struct tag *die__create_new_subroutine_type(Dwarf_Die *die,
tag__print_not_supported(die);
continue;
case DW_TAG_formal_parameter:
- tag = die__create_new_parameter(die, ftype, NULL, cu, conf, -1);
+ tag = die__create_new_parameter(die, ftype, NULL, NULL, cu, conf, -1);
break;
case DW_TAG_unspecified_parameters:
ftype->unspec_parms = 1;
@@ -2946,10 +2950,14 @@ static struct tag *die__create_new_inline_expansion(Dwarf_Die *die,
struct lexblock *lexblock,
struct cu *cu, struct conf_load *conf);
-static int die__process_inline_expansion(Dwarf_Die *die, struct lexblock *lexblock, struct cu *cu, struct conf_load *conf)
+static int die__process_inline_expansion(Dwarf_Die *die,
+ struct inline_expansion *exp,
+ struct lexblock *lexblock,
+ struct cu *cu, struct conf_load *conf)
{
Dwarf_Die child;
struct tag *tag;
+ int parm_idx = 0;
if (!dwarf_haschildren(die) || dwarf_child(die, &child) != 0)
return 0;
@@ -2957,6 +2965,7 @@ static int die__process_inline_expansion(Dwarf_Die *die, struct lexblock *lexblo
die = &child;
do {
uint32_t id;
+ bool add_to_inline_expansion = false;
switch (dwarf_tag(die)) {
case DW_TAG_call_site:
@@ -2975,13 +2984,10 @@ static int die__process_inline_expansion(Dwarf_Die *die, struct lexblock *lexblo
goto out_enomem;
continue;
case DW_TAG_formal_parameter:
- /*
- * Inline expansions can have their own formal
- * parameter children duplicating the abstract
- * origin's parameters. These are not needed
- * for type reconstruction — skip them.
- */
- continue;
+ tag = die__create_new_parameter(die, NULL, lexblock, exp,
+ cu, conf, parm_idx++);
+ add_to_inline_expansion = true;
+ break;
case DW_TAG_inlined_subroutine:
tag = die__create_new_inline_expansion(die, lexblock, cu, conf);
break;
@@ -3010,6 +3016,8 @@ static int die__process_inline_expansion(Dwarf_Die *die, struct lexblock *lexblo
if (cu__table_add_tag(cu, tag, &id) < 0)
goto out_delete_tag;
+ if (add_to_inline_expansion)
+ inline_expansion__add_parameter(exp, tag__parameter(tag));
hash:
cu__hash(cu, tag);
struct dwarf_tag *dtag = tag__dwarf(tag);
@@ -3032,8 +3040,8 @@ static struct tag *die__create_new_inline_expansion(Dwarf_Die *die,
if (exp == NULL)
return NULL;
- if (die__process_inline_expansion(die, lexblock, cu, conf) != 0) {
- tag__free(&exp->ip.tag, cu);
+ if (die__process_inline_expansion(die, exp, lexblock, cu, conf) != 0) {
+ tag__delete(&exp->ip.tag, cu);
return NULL;
}
@@ -3115,7 +3123,8 @@ static int die__process_function(Dwarf_Die *die, struct ftype *ftype,
continue;
}
case DW_TAG_formal_parameter:
- tag = die__create_new_parameter(die, ftype, lexblock, cu, conf, param_idx++);
+ tag = die__create_new_parameter(die, ftype, lexblock, NULL,
+ cu, conf, param_idx++);
break;
case DW_TAG_variable:
tag = die__create_new_variable(die, cu, conf, 0);
@@ -3562,75 +3571,103 @@ static void __tag__print_abstract_origin_not_found(struct tag *tag,
#define tag__print_abstract_origin_not_found(tag) \
__tag__print_abstract_origin_not_found(tag, __func__, __LINE__)
-static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu)
+static void parameter__share_state_with_abstract_origin(struct parameter *parm,
+ struct parameter *oparm)
+{
+ if (parm->has_loc)
+ oparm->has_loc = parm->has_loc;
+ if (parm->has_const_value)
+ oparm->has_const_value = parm->has_const_value;
+ if (parm->loc_const_value)
+ oparm->loc_const_value = parm->loc_const_value;
+ if (parm->loc_stack)
+ oparm->loc_stack = parm->loc_stack;
+ if (parm->loc_reg != PARAMETER_UNKNOWN_REG)
+ oparm->loc_reg = parm->loc_reg;
+ if (parm->type_byte_size != 0)
+ oparm->type_byte_size = parm->type_byte_size;
+ if (parm->passed_in_memory)
+ oparm->passed_in_memory = parm->passed_in_memory;
+ oparm->first_reg_fields |= parm->first_reg_fields;
+ oparm->second_reg_fields |= parm->second_reg_fields;
+ if (parm->true_sig_member_name && !oparm->true_sig_member_name) {
+ oparm->true_sig_member_name = parm->true_sig_member_name;
+ oparm->true_sig_type = parm->true_sig_type;
+ oparm->true_sig_type_from_types = parm->true_sig_type_from_types;
+ }
+ if (parm->optimized)
+ oparm->optimized = parm->optimized;
+ if (parm->unexpected_reg)
+ oparm->unexpected_reg = parm->unexpected_reg;
+}
+
+static void parameter__recode_dwarf_type(struct parameter *parm, struct cu *cu,
+ struct ftype *ftype)
{
- struct parameter *pos;
struct dwarf_cu *dcu = cu->priv;
- struct ftype *type = tag__ftype(tag);
-
- ftype__for_each_parameter(type, pos) {
- struct dwarf_tag *dpos = tag__dwarf(&pos->tag);
- struct parameter *opos;
- struct dwarf_tag *dtype;
+ struct dwarf_tag *dparm = tag__dwarf(&parm->tag);
+ struct dwarf_tag *dtype;
- if (dpos->type == 0) {
- if (dpos->abstract_origin == 0) {
- /* Function without parameters */
- pos->tag.type = 0;
- continue;
- }
- dtype = dwarf_cu__find_tag_by_ref(dcu, dpos, abstract_origin);
- if (dtype == NULL) {
- tag__print_abstract_origin_not_found(&pos->tag);
- continue;
- }
- opos = tag__parameter(dtag__tag(dtype));
- pos->name = opos->name;
- if (pos->idx != opos->idx)
- type->reordered_parm = 1;
- pos->tag.type = dtag__tag(dtype)->type;
- /* share location information between parameter and
- * abstract origin; if neither have location, we will
- * mark the parameter as optimized out. Also share
- * info regarding unexpected register use for
- * parameters.
- */
- if (pos->has_loc)
- opos->has_loc = pos->has_loc;
- if (pos->has_const_value)
- opos->has_const_value = pos->has_const_value;
- if (pos->loc_const_value)
- opos->loc_const_value = pos->loc_const_value;
- if (pos->loc_stack)
- opos->loc_stack = pos->loc_stack;
- if (pos->loc_reg != PARAMETER_UNKNOWN_REG)
- opos->loc_reg = pos->loc_reg;
- if (pos->type_byte_size != 0)
- opos->type_byte_size = pos->type_byte_size;
- if (pos->passed_in_memory)
- opos->passed_in_memory = pos->passed_in_memory;
- opos->first_reg_fields |= pos->first_reg_fields;
- opos->second_reg_fields |= pos->second_reg_fields;
- if (pos->true_sig_member_name && !opos->true_sig_member_name) {
- opos->true_sig_member_name = pos->true_sig_member_name;
- opos->true_sig_type = pos->true_sig_type;
- opos->true_sig_type_from_types = pos->true_sig_type_from_types;
- }
+ if (dparm->type == 0) {
+ struct parameter *oparm;
- if (pos->optimized)
- opos->optimized = pos->optimized;
- if (pos->unexpected_reg)
- opos->unexpected_reg = pos->unexpected_reg;
- continue;
+ if (dparm->abstract_origin == 0) {
+ parm->tag.type = 0;
+ return;
}
- dtype = dwarf_cu__find_type_by_ref(dcu, dpos, type);
+ dtype = dwarf_cu__find_tag_by_ref(dcu, dparm, abstract_origin);
if (dtype == NULL) {
- tag__print_type_not_found(&pos->tag);
- continue;
+ tag__print_abstract_origin_not_found(&parm->tag);
+ return;
}
- pos->tag.type = dtype->small_id;
+
+ oparm = tag__parameter(dtag__tag(dtype));
+ parm->name = oparm->name;
+ if (ftype != NULL && parm->idx != oparm->idx)
+ ftype->reordered_parm = 1;
+ parm->tag.type = dtag__tag(dtype)->type;
+ if (ftype != NULL)
+ parameter__share_state_with_abstract_origin(parm, oparm);
+ return;
+ }
+
+ dtype = dwarf_cu__find_type_by_ref(dcu, dparm, type);
+ if (dtype == NULL) {
+ tag__print_type_not_found(&parm->tag);
+ return;
+ }
+ parm->tag.type = dtype->small_id;
+}
+
+static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu)
+{
+ struct ftype *type = tag__ftype(tag);
+ struct parameter *pos;
+
+ ftype__for_each_parameter(type, pos)
+ parameter__recode_dwarf_type(pos, cu, type);
+}
+
+static void inline_expansion__recode_dwarf_types(struct tag *tag, struct cu *cu)
+{
+ struct dwarf_cu *dcu = cu->priv;
+ struct dwarf_tag *dtag = tag__dwarf(tag);
+ struct dwarf_tag *dtype;
+ struct tag *pos;
+
+ /* The inline expansion's abstract origin is stored as its type ref. */
+ dtype = dwarf_cu__find_tag_by_ref(dcu, dtag, type);
+ if (dtype == NULL) {
+ tag__print_type_not_found(tag);
+ tag__check_pruned_alt_ref(dcu, dtag->type, dtag->from_alt.type);
+ return;
}
+
+ ftype__recode_dwarf_types(dtag__tag(dtype), cu);
+ list_for_each_entry(pos, &tag__inline_expansion(tag)->parms, node)
+ parameter__recode_dwarf_type(tag__parameter(pos), cu, NULL);
+ tag->type = dtype->small_id;
}
static struct parameter *ftype__next_parameter(struct ftype *ftype, struct parameter *parm)
@@ -3885,23 +3922,7 @@ static void lexblock__recode_dwarf_types(struct lexblock *tag, struct cu *cu)
lexblock__recode_dwarf_types(tag__lexblock(pos), cu);
continue;
case DW_TAG_inlined_subroutine:
- if (dpos->type != 0)
- dtype = dwarf_cu__find_tag_by_ref(dcu, dpos, type);
- else
- dtype = dwarf_cu__find_tag_by_ref(dcu, dpos, abstract_origin);
- if (dtype == NULL) {
- if (dpos->type != 0) {
- tag__print_type_not_found(pos);
- tag__check_pruned_alt_ref(dcu, dpos->type,
- dpos->from_alt.type);
- } else {
- tag__print_abstract_origin_not_found(pos);
- tag__check_pruned_alt_ref(dcu, dpos->abstract_origin,
- dpos->from_alt.abstract_origin);
- }
- continue;
- }
- ftype__recode_dwarf_types(dtag__tag(dtype), cu);
+ inline_expansion__recode_dwarf_types(pos, cu);
continue;
case DW_TAG_formal_parameter:
@@ -4081,15 +4102,9 @@ static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu)
case DW_TAG_namespace:
return namespace__recode_dwarf_types(tag, cu);
- /*
- * DW_TAG_inlined_subroutine uses DW_AT_abstract_origin to
- * reference the out-of-line subprogram. inline_expansion__new()
- * stores this in dtag->type (not dtag->abstract_origin) via
- * dwarf_tag__set_attr_type() with DW_AT_abstract_origin.
- * For dwz binaries, the target subprogram lives in the alt file,
- * so dtag->from_alt.type drives the lookup to dcu->alt->hash_tags.
- */
case DW_TAG_inlined_subroutine:
+ inline_expansion__recode_dwarf_types(tag, cu);
+ return 0;
case DW_TAG_imported_module:
dtype = dwarf_cu__find_tag_by_ref(cu->priv, dtag, type);
goto check_type;
diff --git a/dwarves.c b/dwarves.c
index 2164030..2bb5c18 100644
--- a/dwarves.c
+++ b/dwarves.c
@@ -203,6 +203,27 @@ void formal_parameter_pack__delete(struct formal_parameter_pack *pack, struct cu
cu__tag_free(cu, &pack->tag);
}
+static void inline_expansion__delete_tags(struct inline_expansion *exp,
+ struct cu *cu)
+{
+ struct tag *pos, *n;
+
+ list_for_each_entry_safe_reverse(pos, n, &exp->parms, node) {
+ list_del_init(&pos->node);
+ tag__delete(pos, cu);
+ }
+}
+
+static void inline_expansion__delete(struct inline_expansion *exp,
+ struct cu *cu)
+{
+ if (exp == NULL)
+ return;
+
+ inline_expansion__delete_tags(exp, cu);
+ cu__tag_free(cu, &exp->ip.tag);
+}
+
void tag__delete(struct tag *tag, struct cu *cu)
{
if (tag == NULL)
@@ -225,6 +246,8 @@ void tag__delete(struct tag *tag, struct cu *cu)
ftype__delete(tag__ftype(tag), cu); break;
case DW_TAG_subprogram:
function__delete(tag__function(tag), cu); break;
+ case DW_TAG_inlined_subroutine:
+ inline_expansion__delete(tag__inline_expansion(tag), cu); break;
case DW_TAG_lexical_block:
lexblock__delete(tag__lexblock(tag), cu); break;
case DW_TAG_GNU_template_parameter_pack:
@@ -1476,6 +1499,13 @@ void lexblock__add_tag(struct lexblock *block, struct tag *tag)
list_add_tail(&tag->node, &block->tags);
}
+void inline_expansion__add_parameter(struct inline_expansion *exp,
+ struct parameter *parm)
+{
+ ++exp->nr_parms;
+ list_add_tail(&parm->tag.node, &exp->parms);
+}
+
void lexblock__add_inline_expansion(struct lexblock *block,
struct inline_expansion *exp)
{
@@ -2059,6 +2089,10 @@ static int list__for_all_tags(struct list_head *list, struct cu *cu,
if (list__for_all_tags(&tag__lexblock(pos)->tags,
cu, iterator, cookie))
return 1;
+ } else if (pos->tag == DW_TAG_inlined_subroutine) {
+ if (list__for_all_tags(&tag__inline_expansion(pos)->parms,
+ cu, iterator, cookie))
+ return 1;
}
if (iterator(pos, cu, cookie))
diff --git a/dwarves.h b/dwarves.h
index f3453ed..f620db8 100644
--- a/dwarves.h
+++ b/dwarves.h
@@ -825,6 +825,8 @@ struct inline_expansion {
struct ip_tag ip;
size_t size;
uint64_t high_pc;
+ struct list_head parms;
+ uint16_t nr_parms;
};
static inline struct inline_expansion *
@@ -833,6 +835,10 @@ static inline struct inline_expansion *
return (struct inline_expansion *)tag;
}
+struct parameter;
+void inline_expansion__add_parameter(struct inline_expansion *exp,
+ struct parameter *parm);
+
struct label {
struct ip_tag ip;
const char *name;
--
2.43.5
next prev parent reply other threads:[~2026-09-25 18:52 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-25 18:51 [PATCH v3 dwarves 0/9] Encoding of inline functions using BTF Alan Maguire
2026-09-25 18:51 ` Alan Maguire [this message]
2026-09-30 15:45 ` [PATCH v3 dwarves 1/9] dwarf_loader: Add parameter list to inlined expansions Jiri Olsa
2026-10-02 11:02 ` Alan Maguire
2026-09-25 18:51 ` [PATCH v3 dwarves 2/9] dwarf_loader: Resolve inline expansion names during recoding Alan Maguire
2026-09-25 18:51 ` [PATCH v3 dwarves 3/9] dwarf_loader: Collect inline expansion location data Alan Maguire
2026-09-25 18:51 ` [PATCH v3 dwarves 4/9] pahole: Support inline BTF location encoding Alan Maguire
2026-09-25 18:51 ` [PATCH v3 dwarves 5/9] btf_loader: Add "inline" annotation for inlined functions Alan Maguire
2026-09-25 18:51 ` [PATCH v3 dwarves 6/9] btf_loader: Record inline sites in CU for BTF Alan Maguire
2026-09-25 18:51 ` [PATCH v3 dwarves 7/9] pfunct: Print inline site information Alan Maguire
2026-09-25 18:51 ` [PATCH v3 dwarves 8/9] tests: Validate inline BTF encoding Alan Maguire
2026-09-25 18:51 ` [PATCH v3 dwarves 9/9] man-pages: Document --inline_sites option Alan Maguire
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=20260925185200.1318067-2-alan.maguire@oracle.com \
--to=alan.maguire@oracle.com \
--cc=acme@kernel.org \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=dwarves@vger.kernel.org \
--cc=eddyz87@gmail.com \
--cc=emil@etsalapatis.com \
--cc=ihor.solodrai@linux.dev \
--cc=jolsa@kernel.org \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=nsc@kernel.org \
--cc=puranjay@kernel.org \
--cc=qmo@kernel.org \
--cc=song@kernel.org \
--cc=yatsenko@meta.com \
--cc=yonghong.song@linux.dev \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox