From: Alan Maguire <alan.maguire@oracle.com>
To: dwarves@vger.kernel.org
Cc: andrii@kernel.org, eddyz87@gmail.com, ast@kernel.org,
daniel@iogearbox.net, martin.lau@linux.dev, acme@kernel.org,
ttreyer@meta.com, yonghong.song@linux.dev, song@kernel.org,
john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me,
haoluo@google.com, jolsa@kernel.org, qmo@kernel.org,
ihor.solodrai@linux.dev, david.faust@oracle.com,
jose.marchesi@oracle.com, bpf@vger.kernel.org,
Alan Maguire <alan.maguire@oracle.com>
Subject: [RFC dwarves 1/5] dwarf_loader: Add parameters list to inlined expansion
Date: Fri, 24 Oct 2025 08:33:24 +0100 [thread overview]
Message-ID: <20251024073328.370457-2-alan.maguire@oracle.com> (raw)
In-Reply-To: <20251024073328.370457-1-alan.maguire@oracle.com>
From: Thierry Treyer <ttreyer@meta.com>
The parameters of inlined expansions are stored in the lexblock tag
list, making it difficult to iterate over the parameters of a given
inlined expansion.
Add a list of parameters to 'struct inline_expansion', so the parameters
are stored in their expansion instead of the lexblock.
Omitted the storage of struct location in parameters here as a later
patch will persist location information until after CUs have gone;
this is necessary to ensure we can delay adding it until base BTF
has been generated.
Signed-off-by: Thierry Treyer <ttreyer@meta.com>
Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
---
dwarf_loader.c | 164 +++++++++++++++++++++++++++++--------------------
dwarves.c | 26 ++++++++
dwarves.h | 6 ++
3 files changed, 129 insertions(+), 67 deletions(-)
diff --git a/dwarf_loader.c b/dwarf_loader.c
index 79be3f5..e19414d 100644
--- a/dwarf_loader.c
+++ b/dwarf_loader.c
@@ -1297,6 +1297,9 @@ static struct parameter *parameter__new(Dwarf_Die *die, struct cu *cu,
parm->has_loc = dwarf_attr(die, DW_AT_location, &attr) != NULL;
if (parm->has_loc) {
+ struct location location;
+ attr_location(die, &location.expr, &location.exprlen);
+
int expected_reg = cu->register_params[param_idx];
int actual_reg = parameter__reg(&attr, expected_reg);
@@ -1374,6 +1377,8 @@ static struct inline_expansion *inline_expansion__new(Dwarf_Die *die, struct cu
dwarf_tag__set_attr_type(dtag, type, die, DW_AT_abstract_origin);
exp->ip.addr = 0;
exp->high_pc = 0;
+ exp->nr_parms = 0;
+ INIT_LIST_HEAD(&exp->parms);
if (!cu->has_addr_info)
goto out;
@@ -1794,6 +1799,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)
{
@@ -1808,15 +1814,16 @@ static struct tag *die__create_new_parameter(Dwarf_Die *die,
if (add_child_llvm_annotations(die, param_idx, conf, &(tag__function(&ftype->tag)->annots)))
return NULL;
}
+ } else if (exp != NULL) {
+ /*
+ * Inline expansion stores the parameters in a list to emit
+ * .BTF_inline parameter location.
+ */
+ inline_expansion__add_parameter(exp, parm);
} else {
/*
- * DW_TAG_formal_parameters on a non DW_TAG_subprogram nor
- * DW_TAG_subroutine_type tag happens sometimes, likely due to
- * compiler optimizing away a inline expansion (at least this
- * was observed in some cases, such as in the Linux kernel
- * current_kernel_time function circa 2.6.20-rc5), keep it in
- * the lexblock tag list because it can be referenced as an
- * DW_AT_abstract_origin in another DW_TAG_formal_parameter.
+ * Keep it in the lexblock tag list because it can be referenced
+ * as an DW_AT_abstract_origin in another DW_TAG_formal_parameter.
*/
lexblock__add_tag(lexblock, &parm->tag);
}
@@ -1884,7 +1891,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;
@@ -2136,10 +2143,13 @@ 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;
@@ -2179,6 +2189,7 @@ static int die__process_inline_expansion(Dwarf_Die *die, struct lexblock *lexblo
*
* cu__tag_not_handled(cu, die);
*/
+ tag = die__create_new_parameter(die, NULL, lexblock, exp, cu, conf, parm_idx++);
continue;
case DW_TAG_inlined_subroutine:
tag = die__create_new_inline_expansion(die, lexblock, cu, conf);
@@ -2230,7 +2241,7 @@ 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) {
+ if (die__process_inline_expansion(die, exp, lexblock, cu, conf) != 0) {
tag__free(&exp->ip.tag, cu);
return NULL;
}
@@ -2315,7 +2326,7 @@ 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);
@@ -2607,54 +2618,85 @@ 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 parameter__recode_dwarf_type(struct parameter *parm, struct cu *cu)
+{
+ struct dwarf_cu *dcu = cu->priv;
+ struct dwarf_tag *dparm = tag__dwarf(&parm->tag);
+
+ if (dparm->type == 0) {
+ if (dparm->abstract_origin == 0) {
+ /* Function without parameters */
+ parm->tag.type = 0;
+ return;
+ }
+ struct dwarf_tag *dtype = dwarf_cu__find_tag_by_ref(dcu, dparm, abstract_origin);
+ if (dtype == NULL) {
+ tag__print_abstract_origin_not_found(&parm->tag);
+ return;
+ }
+ struct parameter *oparm = tag__parameter(dtag__tag(dtype));
+ parm->name = oparm->name;
+ parm->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 (parm->has_loc)
+ oparm->has_loc = parm->has_loc;
+
+ if (parm->optimized)
+ oparm->optimized = parm->optimized;
+ if (parm->unexpected_reg)
+ oparm->unexpected_reg = parm->unexpected_reg;
+ return;
+ }
+
+ struct dwarf_tag *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 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;
-
- 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;
- 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;
+ ftype__for_each_parameter(type, pos)
+ parameter__recode_dwarf_type(pos, cu);
+}
- if (pos->optimized)
- opos->optimized = pos->optimized;
- if (pos->unexpected_reg)
- opos->unexpected_reg = pos->unexpected_reg;
- continue;
- }
+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);
- dtype = dwarf_cu__find_type_by_ref(dcu, dpos, type);
- if (dtype == NULL) {
- tag__print_type_not_found(&pos->tag);
- continue;
- }
- pos->tag.type = dtype->small_id;
+ /* DW_TAG_inlined_subroutine is an special case as dwarf_tag->id is
+ * in fact an abtract origin, i.e. must be looked up in the tags_table,
+ * not in the types_table.
+ */
+ struct dwarf_tag *ftype = NULL;
+ if (dtag->type != 0)
+ ftype = dwarf_cu__find_tag_by_ref(dcu, dtag, type);
+ else
+ ftype = dwarf_cu__find_tag_by_ref(dcu, dtag, abstract_origin);
+ if (ftype == NULL) {
+ if (dtag->type != 0)
+ tag__print_type_not_found(tag);
+ else
+ tag__print_abstract_origin_not_found(tag);
+ return;
}
+
+ ftype__recode_dwarf_types(dtag__tag(ftype), cu);
+
+ struct tag *pos;
+ struct inline_expansion *exp = tag__inline_expansion(tag);
+ list_for_each_entry(pos, &exp->parms, node)
+ parameter__recode_dwarf_type(tag__parameter(pos), cu);
+ exp->ip.tag.type = ftype->small_id;
}
static void lexblock__recode_dwarf_types(struct lexblock *tag, struct cu *cu)
@@ -2671,18 +2713,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);
- else
- tag__print_abstract_origin_not_found(pos);
- continue;
- }
- ftype__recode_dwarf_types(dtag__tag(dtype), cu);
+ inline_expansion__recode_dwarf_types(pos, cu);
continue;
case DW_TAG_formal_parameter:
@@ -2862,12 +2893,11 @@ static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu)
case DW_TAG_namespace:
return namespace__recode_dwarf_types(tag, cu);
- /* Damn, DW_TAG_inlined_subroutine is an special case
- as dwarf_tag->id is in fact an abtract origin, i.e. must be
- looked up in the tags_table, not in the types_table.
- The others also point to routines, so are in tags_table */
case DW_TAG_inlined_subroutine:
+ inline_expansion__recode_dwarf_types(tag, cu);
+ return 0;
case DW_TAG_imported_module:
+ /* Modules point to routines, so are in tags_table */
dtype = dwarf_cu__find_tag_by_ref(cu->priv, dtag, type);
goto check_type;
/* Can be for both types and non types */
diff --git a/dwarves.c b/dwarves.c
index ef93239..2232ee7 100644
--- a/dwarves.c
+++ b/dwarves.c
@@ -203,6 +203,20 @@ void formal_parameter_pack__delete(struct formal_parameter_pack *pack, struct cu
cu__tag_free(cu, &pack->tag);
}
+static void parameter__delete(struct parameter *parm, struct cu *cu);
+
+static void inline_expansion__delete(struct inline_expansion *exp, struct cu *cu)
+{
+ if (exp == NULL)
+ return;
+
+ struct tag *parm, *n;
+ list_for_each_entry_safe_reverse(parm, n, &exp->parms, node) {
+ list_del_init(&parm->node);
+ parameter__delete(tag__parameter(parm), cu);
+ }
+}
+
void tag__delete(struct tag *tag, struct cu *cu)
{
if (tag == NULL)
@@ -225,6 +239,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:
@@ -1514,6 +1530,12 @@ void formal_parameter_pack__add(struct formal_parameter_pack *pack, struct param
list_add_tail(¶m->tag.node, &pack->params);
}
+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_tag(struct lexblock *block, struct tag *tag)
{
list_add_tail(&tag->node, &block->tags);
@@ -2116,6 +2138,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 21d4166..4e91e8f 100644
--- a/dwarves.h
+++ b/dwarves.h
@@ -823,6 +823,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 *
@@ -831,6 +833,9 @@ 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;
@@ -941,6 +946,7 @@ size_t lexblock__fprintf(const struct lexblock *lexblock, const struct cu *cu,
struct parameter {
struct tag tag;
const char *name;
+ struct location location;
uint8_t optimized:1;
uint8_t unexpected_reg:1;
uint8_t has_loc:1;
--
2.39.3
next prev parent reply other threads:[~2025-10-24 7:34 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-10-24 7:33 [RFC dwarves 0/5] pahole: support BTF inline encoding Alan Maguire
2025-10-24 7:33 ` Alan Maguire [this message]
2025-10-24 7:33 ` [RFC dwarves 2/5] dwarf_loader: Add name to inline expansion Alan Maguire
2025-10-24 7:33 ` [RFC dwarves 3/5] dwarf_loader: Collect inline expansion location information Alan Maguire
2025-10-24 17:55 ` Eduard Zingerman
2025-10-29 17:40 ` Alan Maguire
2025-10-29 18:32 ` Eduard Zingerman
2025-10-29 18:46 ` Alan Maguire
2025-10-24 7:33 ` [RFC dwarves 4/5] btf_encoder: Support encoding of inline " Alan Maguire
2025-10-24 18:04 ` Eduard Zingerman
2025-10-24 7:33 ` [RFC dwarves 5/5] pahole: Support inline encoding with inline[.extra] BTF feature 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=20251024073328.370457-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=david.faust@oracle.com \
--cc=dwarves@vger.kernel.org \
--cc=eddyz87@gmail.com \
--cc=haoluo@google.com \
--cc=ihor.solodrai@linux.dev \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=jose.marchesi@oracle.com \
--cc=kpsingh@kernel.org \
--cc=martin.lau@linux.dev \
--cc=qmo@kernel.org \
--cc=sdf@fomichev.me \
--cc=song@kernel.org \
--cc=ttreyer@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