From: Thierry Treyer via B4 Relay <devnull+ttreyer.meta.com@kernel.org>
To: dwarves@vger.kernel.org, bpf@vger.kernel.org
Cc: Thierry Treyer <ttreyer@meta.com>,
acme@kernel.org, ast@kernel.org, yhs@meta.com,
andrii@kernel.org, ihor.solodrai@linux.dev,
songliubraving@meta.com, alan.maguire@oracle.com,
mykolal@meta.com
Subject: [PATCH RFC 1/3] dwarf_loader: Add parameters list to inlined expansion
Date: Wed, 16 Apr 2025 19:20:35 +0000 [thread overview]
Message-ID: <20250416-btf_inline-v1-1-e4bd2f8adae5@meta.com> (raw)
In-Reply-To: <20250416-btf_inline-v1-0-e4bd2f8adae5@meta.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.
Add location to 'struct parameter', so their location expression can be
referenced when consuming the DWARF.
Parameters with a constant value have their value stored in the location
too: 'location.expr' is set to NULL and 'location.exprlen' is set to the
constant's value.
Signed-off-by: Thierry Treyer <ttreyer@meta.com>
---
dwarf_loader.c | 167 ++++++++++++++++++++++++++++++++++-----------------------
dwarves.c | 26 +++++++++
dwarves.h | 6 +++
3 files changed, 132 insertions(+), 67 deletions(-)
diff --git a/dwarf_loader.c b/dwarf_loader.c
index 84122d04e42cab53c5598ae62b750a43e187e11d..24ac9afceb3793c165d3e92cfdfaf27ab67fd4d6 100644
--- a/dwarf_loader.c
+++ b/dwarf_loader.c
@@ -1297,6 +1297,8 @@ 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) {
+ attr_location(die, &parm->location.expr, &parm->location.exprlen);
+
int expected_reg = cu->register_params[param_idx];
int actual_reg = parameter__reg(&attr, expected_reg);
@@ -1312,6 +1314,8 @@ static struct parameter *parameter__new(Dwarf_Die *die, struct cu *cu,
parm->unexpected_reg = 1;
} else if (has_const_value) {
parm->optimized = 1;
+ parm->location.expr = NULL;
+ parm->location.exprlen = attr_numeric(die, DW_AT_const_value);
}
}
@@ -1374,6 +1378,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 +1800,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 +1815,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 +1892,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 +2144,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 +2190,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 +2242,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 +2327,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 +2619,87 @@ 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;
+ }
+ // FIXME: Should this use find_type_by_ref instead?
+ 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;
}
+
+ // TODO: Is ftype a prototype or a function?
+ 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 +2716,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 +2896,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 ef93239d26827711e23b405dd113986867d18507..2232ee713d57a92a700be56be7b7e1128741e24a 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 8234e1a09128c667a2a516dccb6d7c6a194f8c5b..38efd6a6e2b0b0e5a571a8d12bbec33502509d8b 100644
--- a/dwarves.h
+++ b/dwarves.h
@@ -811,6 +811,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 *
@@ -819,6 +821,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;
@@ -929,6 +934,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.47.1
next prev parent reply other threads:[~2025-04-16 19:21 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-16 19:20 [PATCH RFC 0/3] list inline expansions in .BTF.inline Thierry Treyer via B4 Relay
2025-04-16 19:20 ` Thierry Treyer via B4 Relay [this message]
2025-04-16 19:20 ` [PATCH RFC 2/3] dwarf_loader: Add name to inline expansion Thierry Treyer via B4 Relay
2025-04-16 19:20 ` [PATCH RFC 3/3] inline_encoder: Introduce inline encoder to emit BTF.inline Thierry Treyer via B4 Relay
2025-04-25 18:40 ` [PATCH RFC 0/3] list inline expansions in .BTF.inline Daniel Xu
2025-04-28 20:51 ` Alexei Starovoitov
2025-04-29 19:14 ` Thierry Treyer
2025-04-29 23:58 ` Alexei Starovoitov
2025-04-30 15:25 ` Alan Maguire
2025-05-01 19:38 ` Thierry Treyer
2025-05-02 8:31 ` Alan Maguire
2025-05-19 12:02 ` Alan Maguire
2025-05-22 17:56 ` Thierry Treyer
2025-05-22 20:03 ` Andrii Nakryiko
2025-05-22 20:16 ` Eduard Zingerman
2025-05-23 18:57 ` Thierry Treyer
2025-05-26 14:30 ` Alan Maguire
2025-05-27 21:41 ` Andrii Nakryiko
2025-05-28 10:14 ` Alan Maguire
2025-05-23 17:33 ` Alexei Starovoitov
2025-05-23 18:35 ` Thierry Treyer
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=20250416-btf_inline-v1-1-e4bd2f8adae5@meta.com \
--to=devnull+ttreyer.meta.com@kernel.org \
--cc=acme@kernel.org \
--cc=alan.maguire@oracle.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=dwarves@vger.kernel.org \
--cc=ihor.solodrai@linux.dev \
--cc=mykolal@meta.com \
--cc=songliubraving@meta.com \
--cc=ttreyer@meta.com \
--cc=yhs@meta.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox