From: Eduard Zingerman <eddyz87@gmail.com>
To: dwarves@vger.kernel.org, arnaldo.melo@gmail.com
Cc: bpf@vger.kernel.org, kernel-team@fb.com, ast@kernel.org,
daniel@iogearbox.net, andrii@kernel.org, yhs@fb.com,
jose.marchesi@oracle.com, david.faust@oracle.com,
Eduard Zingerman <eddyz87@gmail.com>
Subject: [PATCH dwarves 1/1] dwarf_loader: Support for btf:type_tag
Date: Mon, 13 Mar 2023 04:17:44 +0200 [thread overview]
Message-ID: <20230313021744.406197-2-eddyz87@gmail.com> (raw)
In-Reply-To: <20230313021744.406197-1-eddyz87@gmail.com>
"btf:type_tag" is an DW_TAG_LLVM_annotation object that encodes
btf_type_tag attributes in DWARF. Contrary to existing "btf_type_tag"
it allows to associate such attributes with non-pointer types.
When "btf:type_tag" is attached to a type it applies to this type.
For example the following C code:
struct echo {
int __attribute__((btf_type_tag("__c"))) c;
}
Produces the following DWARF:
0x29: DW_TAG_structure_type
DW_AT_name ("echo")
0x40: DW_TAG_member
DW_AT_name ("c")
DW_AT_type (0x8c "int")
0x8c: DW_TAG_base_type
DW_AT_name ("int")
DW_AT_encoding (DW_ATE_signed)
DW_AT_byte_size (0x04)
0x90: DW_TAG_LLVM_annotation
DW_AT_name ("btf:type_tag")
DW_AT_const_value ("__c")
Meaning that type 0x8c is an `int` with type tag `__c`.
Corresponding BTF looks as follows:
[1] STRUCT 'echo'
...
'c' type_id=8 bits_offset=128
[4] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED
[8] TYPE_TAG '__c' type_id=4
Void pointers with type tag annotations are represented as objects
of unspecified type with name "void", here is an example:
struct st {
void __attribute__((btf_type_tag("__d"))) *d;
}
And corresponding DWARF:
0x29: DW_TAG_structure_type
DW_AT_name ("st")
0x49: DW_TAG_member
DW_AT_name ("d")
DW_AT_type (0xa6 "void *")
0xa6: DW_TAG_pointer_type
DW_AT_type (0xaf "void")
0xaf: DW_TAG_unspecified_type
DW_AT_name ("void")
0xb1: DW_TAG_LLVM_annotation
DW_AT_name ("btf:type_tag")
DW_AT_const_value ("__d")
This commit adds support for DW_TAG_LLVM_annotation "btf:type_tag"
attached to the following entities:
- base types;
- arrays;
- pointers;
- structs
- unions;
- enums;
- typedefs.
This is achieved via the following modifications:
- Types `struct btf_type_tag_type` and `struct llvm_annotation` are
consolidated as a single type `struct llvm_annotation`, in order to
reside in a single `annots` list associated with struct/union/enum
or typedef.
- `struct unspecified_type` is added to handle `void *` types annotated
with `btf:type_tag`.
- `struct tag` is extended with `annots` list.
- DWARF load phase is modified to fill `annots` fields for the above
mentioned types.
- Recode phase is split in two sub-phases:
- The existing `tag__recode_dwarf_type()` is executed first;
- Newly added `update_btf_type_tag_refs()` is executed to update
`->type` field of each tag if that type refers to an object with
`btf:type_tag` annotation. The id of the type is replaced by id
of the type tag.
- When `btf:type_tag` annotations are present in compilation unit,
all `btf_type_tag` annotations are ignored during BTF dump.
See also:
[1] Mailing list discussion regarding `btf:type_tag`
https://lore.kernel.org/bpf/87r0w9jjoq.fsf@oracle.com/
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
---
btf_encoder.c | 13 +-
btf_loader.c | 15 +-
dwarf_loader.c | 763 +++++++++++++++++++++++++++++++++++++---------
dwarves.c | 1 +
dwarves.h | 68 +++--
dwarves_fprintf.c | 13 +
6 files changed, 693 insertions(+), 180 deletions(-)
diff --git a/btf_encoder.c b/btf_encoder.c
index 07a9dc5..b74911b 100644
--- a/btf_encoder.c
+++ b/btf_encoder.c
@@ -899,6 +899,9 @@ static int32_t btf_encoder__add_func(struct btf_encoder *encoder, struct functio
return -1;
}
list_for_each_entry(annot, &fn->annots, node) {
+ if (annot->kind != BTF_DECL_TAG)
+ continue;
+
tag_type_id = btf_encoder__add_decl_tag(encoder, annot->value, btf_fn_id,
annot->component_idx);
if (tag_type_id < 0) {
@@ -1180,7 +1183,7 @@ static int btf_encoder__encode_tag(struct btf_encoder *encoder, struct tag *tag,
name = namespace__name(tag__namespace(tag));
return btf_encoder__add_ref_type(encoder, BTF_KIND_TYPEDEF, ref_type_id, name, false);
case DW_TAG_LLVM_annotation:
- name = tag__btf_type_tag(tag)->value;
+ name = tag__llvm_annotation(tag)->value;
return btf_encoder__add_ref_type(encoder, BTF_KIND_TYPE_TAG, ref_type_id, name, false);
case DW_TAG_structure_type:
case DW_TAG_union_type:
@@ -1605,6 +1608,9 @@ static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder)
}
list_for_each_entry(annot, &var->annots, node) {
+ if (annot->kind != BTF_DECL_TAG)
+ continue;
+
int tag_type_id = btf_encoder__add_decl_tag(encoder, annot->value, id, annot->component_idx);
if (tag_type_id < 0) {
fprintf(stderr, "error: failed to encode tag '%s' to variable '%s' with component_idx %d\n",
@@ -1798,7 +1804,10 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co
btf_type_id = encoder->type_id_off + core_id;
ns = tag__namespace(pos);
- list_for_each_entry(annot, &ns->annots, node) {
+ list_for_each_entry(annot, &ns->tag.annots, node) {
+ if (annot->kind != BTF_DECL_TAG)
+ continue;
+
tag_type_id = btf_encoder__add_decl_tag(encoder, annot->value, btf_type_id, annot->component_idx);
if (tag_type_id < 0) {
fprintf(stderr, "error: failed to encode tag '%s' to %s '%s' with component_idx %d\n",
diff --git a/btf_loader.c b/btf_loader.c
index e579323..3fe07d0 100644
--- a/btf_loader.c
+++ b/btf_loader.c
@@ -429,10 +429,11 @@ static int create_new_tag(struct cu *cu, int type, const struct btf_type *tp, ui
return -ENOMEM;
switch (type) {
- case BTF_KIND_CONST: tag->tag = DW_TAG_const_type; break;
- case BTF_KIND_PTR: tag->tag = DW_TAG_pointer_type; break;
- case BTF_KIND_RESTRICT: tag->tag = DW_TAG_restrict_type; break;
- case BTF_KIND_VOLATILE: tag->tag = DW_TAG_volatile_type; break;
+ case BTF_KIND_CONST: tag->tag = DW_TAG_const_type; break;
+ case BTF_KIND_PTR: tag->tag = DW_TAG_pointer_type; break;
+ case BTF_KIND_RESTRICT: tag->tag = DW_TAG_restrict_type; break;
+ case BTF_KIND_VOLATILE: tag->tag = DW_TAG_volatile_type; break;
+ case BTF_KIND_TYPE_TAG: tag->tag = DW_TAG_LLVM_annotation; break;
default:
free(tag);
printf("%s: Unknown type %d\n\n", __func__, type);
@@ -489,6 +490,12 @@ static int btf__load_types(struct btf *btf, struct cu *cu)
case BTF_KIND_PTR:
case BTF_KIND_CONST:
case BTF_KIND_RESTRICT:
+ /* For type tag it's a bit of a lie.
+ * In DWARF it is encoded as a child tag of whatever type it
+ * applies to. Here we load it as a standalone tag with a pointer
+ * to a next type only to have a valid ID in the types table.
+ */
+ case BTF_KIND_TYPE_TAG:
err = create_new_tag(cu, type, type_ptr, type_index);
break;
case BTF_KIND_UNKN:
diff --git a/dwarf_loader.c b/dwarf_loader.c
index 4efa4e1..7846b94 100644
--- a/dwarf_loader.c
+++ b/dwarf_loader.c
@@ -57,6 +57,36 @@
#define EM_RISCV 243
#endif
+/** struct btf_type_tag_mapping - information about btf type tags attached
+ * to a particular host type. Each field is a small_id of the dwarf tag.
+ * This information is used to replace references to host type with
+ * references to first btf type tag during the recode phase.
+ *
+ * @host_type_id - type annotated with btf_type_tag annotations
+ * @first_tag_id - first btf type tag attached to host_type_id
+ * @last_tag_id - last btf type tag attached to host_type_id
+ *
+ */
+struct btf_type_tag_mapping {
+ uint32_t host_type_id;
+ uint32_t first_tag_id;
+ uint32_t last_tag_id;
+};
+
+/** struct recode_context - information local to recode phase,
+ * currently only btf type tag mappings.
+ *
+ * @mappings - an array of host id to btf type tag mappings,
+ * dynamically enlarged when new mappings are added;
+ * @nr_allocated - number of elements allocated for @mappings array;
+ * @nr_entries - index of the next free entry in the @mappings array.
+ */
+struct recode_context {
+ struct btf_type_tag_mapping *mappings;
+ uint32_t nr_allocated;
+ uint32_t nr_entries;
+};
+
static pthread_mutex_t libdw__lock = PTHREAD_MUTEX_INITIALIZER;
static uint32_t hashtags__bits = 12;
@@ -112,6 +142,17 @@ static dwarf_off_ref dwarf_tag__spec(struct dwarf_tag *dtag)
return *(dwarf_off_ref *)(dtag + 1);
}
+#define cu__tag_not_handled(die) __cu__tag_not_handled(die, __FUNCTION__)
+
+static void __cu__tag_not_handled(Dwarf_Die *die, const char *fn)
+{
+ uint32_t tag = dwarf_tag(die);
+
+ fprintf(stderr, "%s: DW_TAG_%s (%#x) @ <%#llx> not handled!\n",
+ fn, dwarf_tag_name(tag), tag,
+ (unsigned long long)dwarf_dieoffset(die));
+}
+
static void dwarf_tag__set_spec(struct dwarf_tag *dtag, dwarf_off_ref spec)
{
*(dwarf_off_ref *)(dtag + 1) = spec;
@@ -165,14 +206,21 @@ static struct dwarf_cu *dwarf_cu__new(struct cu *cu)
return dwarf_cu;
}
+static void unspecified_type__delete(struct cu *cu, struct unspecified_type *utype);
+
static void dwarf_cu__delete(struct cu *cu)
{
if (cu == NULL || cu->priv == NULL)
return;
struct dwarf_cu *dcu = cu->priv;
+ struct list_head *pos, *n;
// dcu->hash_tags & dcu->hash_types are on cu->obstack
+ cu__free(cu, dcu->hash_tags);
+ cu__free(cu, dcu->hash_types);
+ list_for_each_safe(pos, n, &cu->unspecified_types)
+ unspecified_type__delete(cu, container_of(pos, struct unspecified_type, node));
cu__free(cu, dcu);
cu->priv = NULL;
}
@@ -519,6 +567,7 @@ static void tag__init(struct tag *tag, struct cu *cu, Dwarf_Die *die)
}
INIT_LIST_HEAD(&tag->node);
+ INIT_LIST_HEAD(&tag->annots);
}
static struct tag *tag__new(Dwarf_Die *die, struct cu *cu)
@@ -608,7 +657,6 @@ static void namespace__init(struct namespace *namespace, Dwarf_Die *die,
{
tag__init(&namespace->tag, cu, die);
INIT_LIST_HEAD(&namespace->tags);
- INIT_LIST_HEAD(&namespace->annots);
namespace->name = attr_string(die, DW_AT_name, conf);
namespace->nr_tags = 0;
namespace->shared_tags = 0;
@@ -876,8 +924,40 @@ static int tag__recode_dwarf_bitfield(struct tag *tag, struct cu *cu, uint16_t b
return -ENOMEM;
}
-static int add_llvm_annotation(Dwarf_Die *die, int component_idx, struct conf_load *conf,
- struct list_head *head)
+static struct llvm_annotation *die__create_new_llvm_annotation(Dwarf_Die *die,
+ struct cu *cu,
+ struct conf_load *conf)
+{
+ struct llvm_annotation *tag;
+
+ tag = tag__alloc_with_spec(cu, sizeof(struct llvm_annotation));
+ if (tag == NULL)
+ return NULL;
+
+ tag__init(&tag->tag, cu, die);
+ return tag;
+}
+
+/** Allocate small_id for specified @tag */
+static int cu__assign_tag_id(struct cu *cu, struct tag *tag)
+{
+ struct dwarf_tag *dtag = tag->priv;
+ uint32_t id;
+
+ if (cu__table_add_tag(cu, tag, &id) < 0)
+ return -ENOMEM;
+
+ dtag->small_id = id;
+ cu__hash(cu, tag);
+
+ return 0;
+}
+
+static int add_btf_decl_tag(Dwarf_Die *die,
+ struct cu *cu,
+ int component_idx,
+ struct conf_load *conf,
+ struct list_head *head)
{
struct llvm_annotation *annot;
const char *name;
@@ -890,17 +970,60 @@ static int add_llvm_annotation(Dwarf_Die *die, int component_idx, struct conf_lo
if (strcmp(name, "btf_decl_tag") != 0)
return 0;
- annot = zalloc(sizeof(*annot));
+ annot = die__create_new_llvm_annotation(die, cu, conf);
if (!annot)
return -ENOMEM;
+ /* Don't assign id for btf_decl_tag */
+
+ annot->kind = BTF_DECL_TAG;
annot->value = attr_string(die, DW_AT_const_value, conf);
annot->component_idx = component_idx;
list_add_tail(&annot->node, head);
return 0;
}
-static int add_child_llvm_annotations(Dwarf_Die *die, int component_idx,
+static int add_btf_type_tag(Dwarf_Die *die,
+ struct cu *cu,
+ struct conf_load *conf,
+ struct list_head *head)
+{
+ struct llvm_annotation *annot;
+ const char *name;
+ bool v1, v2;
+
+ if (conf->skip_encoding_btf_type_tag)
+ return 0;
+
+ name = attr_string(die, DW_AT_name, conf);
+ v1 = strcmp(name, "btf_type_tag") == 0;
+ v2 = strcmp(name, "btf:type_tag") == 0;
+
+ if (!v1 && !v2)
+ return 0;
+
+ /* Create a btf_type_tag type for this annotation. */
+ annot = die__create_new_llvm_annotation(die, cu, conf);
+ if (annot == NULL)
+ return -ENOMEM;
+
+ annot->kind = v2 ? BTF_TYPE_TAG : BTF_TYPE_TAG_POINTEE;
+ annot->value = attr_string(die, DW_AT_const_value, conf);
+ annot->component_idx = -1;
+ if (v2)
+ cu->ignore_btf_type_tag_pointee = 1;
+
+ /* For a list of DW_TAG_LLVM_annotation like tag1 -> tag2 -> tag3,
+ * the tag->tags contains tag3 -> tag2 -> tag1.
+ */
+ list_add(&annot->node, head);
+
+ return 0;
+}
+
+static int add_child_llvm_annotations(Dwarf_Die *die,
+ struct cu *cu,
+ int component_idx,
struct conf_load *conf, struct list_head *head)
{
Dwarf_Die child;
@@ -912,9 +1035,14 @@ static int add_child_llvm_annotations(Dwarf_Die *die, int component_idx,
die = &child;
do {
if (dwarf_tag(die) == DW_TAG_LLVM_annotation) {
- ret = add_llvm_annotation(die, component_idx, conf, head);
+ ret = add_btf_decl_tag(die, cu, component_idx, conf, head);
+ if (ret)
+ return ret;
+ ret = add_btf_type_tag(die, cu, conf, head);
if (ret)
return ret;
+ } else {
+ cu__tag_not_handled(die);
}
} while (dwarf_siblingof(die, die) == 0);
@@ -1340,19 +1468,8 @@ static uint64_t attr_upper_bound(Dwarf_Die *die)
return 0;
}
-static void __cu__tag_not_handled(Dwarf_Die *die, const char *fn)
-{
- uint32_t tag = dwarf_tag(die);
-
- fprintf(stderr, "%s: DW_TAG_%s (%#x) @ <%#llx> not handled!\n",
- fn, dwarf_tag_name(tag), tag,
- (unsigned long long)dwarf_dieoffset(die));
-}
-
static struct tag unsupported_tag;
-#define cu__tag_not_handled(die) __cu__tag_not_handled(die, __FUNCTION__)
-
static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu,
int toplevel, const char *fn, struct conf_load *conf);
@@ -1372,87 +1489,44 @@ static struct tag *die__create_new_tag(Dwarf_Die *die, struct cu *cu)
return tag;
}
-static struct btf_type_tag_ptr_type *die__create_new_btf_type_tag_ptr_type(Dwarf_Die *die, struct cu *cu)
+static struct tag *die__create_new_unspecified_type(Dwarf_Die *die, struct cu *cu,
+ struct conf_load *conf)
{
- struct btf_type_tag_ptr_type *tag;
+ struct unspecified_type *tag;
- tag = tag__alloc_with_spec(cu, sizeof(struct btf_type_tag_ptr_type));
+ tag = tag__alloc_with_spec(cu, sizeof(struct unspecified_type));
if (tag == NULL)
return NULL;
tag__init(&tag->tag, cu, die);
- tag->tag.has_btf_type_tag = true;
- INIT_LIST_HEAD(&tag->tags);
- return tag;
-}
-
-static struct btf_type_tag_type *die__create_new_btf_type_tag_type(Dwarf_Die *die, struct cu *cu,
- struct conf_load *conf)
-{
- struct btf_type_tag_type *tag;
+ INIT_LIST_HEAD(&tag->node);
- tag = tag__alloc_with_spec(cu, sizeof(struct btf_type_tag_type));
- if (tag == NULL)
+ tag->name = attr_string(die, DW_AT_name, conf);
+ if (add_child_llvm_annotations(die, cu, -1, conf, &tag->tag.annots))
return NULL;
- tag__init(&tag->tag, cu, die);
- tag->value = attr_string(die, DW_AT_const_value, conf);
- return tag;
+ list_add(&tag->node, &cu->unspecified_types);
+
+ return &tag->tag;
}
-static struct tag *die__create_new_pointer_tag(Dwarf_Die *die, struct cu *cu,
- struct conf_load *conf)
+static void unspecified_type__delete(struct cu *cu, struct unspecified_type *utype)
{
- struct btf_type_tag_ptr_type *tag = NULL;
- struct btf_type_tag_type *annot;
- Dwarf_Die *cdie, child;
- const char *name;
- uint32_t id;
-
- /* If no child tags or skipping btf_type_tag encoding, just create a new tag
- * and return
- */
- if (!dwarf_haschildren(die) || dwarf_child(die, &child) != 0 ||
- conf->skip_encoding_btf_type_tag)
- return tag__new(die, cu);
+ struct dwarf_tag *dtag = utype->tag.priv;
- /* Otherwise, check DW_TAG_LLVM_annotation child tags */
- cdie = &child;
- do {
- if (dwarf_tag(cdie) != DW_TAG_LLVM_annotation)
- continue;
-
- /* Only check btf_type_tag annotations */
- name = attr_string(cdie, DW_AT_name, conf);
- if (strcmp(name, "btf_type_tag") != 0)
- continue;
-
- if (tag == NULL) {
- /* Create a btf_type_tag_ptr type. */
- tag = die__create_new_btf_type_tag_ptr_type(die, cu);
- if (!tag)
- return NULL;
- }
-
- /* Create a btf_type_tag type for this annotation. */
- annot = die__create_new_btf_type_tag_type(cdie, cu, conf);
- if (annot == NULL)
- return NULL;
-
- if (cu__table_add_tag(cu, &annot->tag, &id) < 0)
- return NULL;
+ cu__free(cu, dtag);
+ cu__free(cu, utype);
+}
- struct dwarf_tag *dtag = annot->tag.priv;
- dtag->small_id = id;
- cu__hash(cu, &annot->tag);
+static struct tag *die__create_new_annotated_tag(Dwarf_Die *die, struct cu *cu,
+ struct conf_load *conf)
+{
+ struct tag *tag = tag__new(die, cu);
- /* For a list of DW_TAG_LLVM_annotation like tag1 -> tag2 -> tag3,
- * the tag->tags contains tag3 -> tag2 -> tag1.
- */
- list_add(&annot->node, &tag->tags);
- } while (dwarf_siblingof(cdie, cdie) == 0);
+ if (add_child_llvm_annotations(die, cu, -1, conf, &tag->annots))
+ return NULL;
- return tag ? &tag->tag : tag__new(die, cu);
+ return tag;
}
static struct tag *die__create_new_ptr_to_member_type(Dwarf_Die *die,
@@ -1527,9 +1601,8 @@ static struct tag *die__create_new_base_type(Dwarf_Die *die, struct cu *cu, stru
if (base == NULL)
return NULL;
- if (dwarf_haschildren(die))
- fprintf(stderr, "%s: DW_TAG_base_type WITH children!\n",
- __func__);
+ if (add_child_llvm_annotations(die, cu, -1, conf, &base->tag.annots))
+ return NULL;
return &base->tag;
}
@@ -1541,13 +1614,13 @@ static struct tag *die__create_new_typedef(Dwarf_Die *die, struct cu *cu, struct
if (tdef == NULL)
return NULL;
- if (add_child_llvm_annotations(die, -1, conf, &tdef->namespace.annots))
+ if (add_child_llvm_annotations(die, cu, -1, conf, &tdef->namespace.tag.annots))
return NULL;
return &tdef->namespace.tag;
}
-static struct tag *die__create_new_array(Dwarf_Die *die, struct cu *cu)
+static struct tag *die__create_new_array(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
Dwarf_Die child;
/* "64 dimensions will be enough for everybody." acme, 2006 */
@@ -1563,17 +1636,25 @@ static struct tag *die__create_new_array(Dwarf_Die *die, struct cu *cu)
die = &child;
do {
- if (dwarf_tag(die) == DW_TAG_subrange_type) {
+ switch (dwarf_tag(die)) {
+ case DW_TAG_subrange_type:
nr_entries[array->dimensions++] = attr_upper_bound(die);
if (array->dimensions == max_dimensions) {
fprintf(stderr, "%s: only %u dimensions are "
"supported!\n",
__FUNCTION__, max_dimensions);
- break;
+ goto _break;
}
- } else
+ break;
+ case DW_TAG_LLVM_annotation:
+ if (add_btf_type_tag(die, cu, conf, &array->tag.annots))
+ goto out_free;
+ break;
+ default:
cu__tag_not_handled(die);
+ }
} while (dwarf_siblingof(die, die) == 0);
+_break:
array->nr_entries = memdup(nr_entries,
array->dimensions * sizeof(uint32_t), cu);
@@ -1610,7 +1691,8 @@ static struct tag *die__create_new_parameter(Dwarf_Die *die,
if (ftype != NULL) {
ftype__add_parameter(ftype, parm);
if (param_idx >= 0) {
- if (add_child_llvm_annotations(die, param_idx, conf, &(tag__function(&ftype->tag)->annots)))
+ if (add_child_llvm_annotations(die, cu, param_idx, conf,
+ &ftype->tag.annots))
return NULL;
}
} else {
@@ -1651,7 +1733,7 @@ static struct tag *die__create_new_variable(Dwarf_Die *die, struct cu *cu, struc
{
struct variable *var = variable__new(die, cu, conf);
- if (var == NULL || add_child_llvm_annotations(die, -1, conf, &var->annots))
+ if (var == NULL || add_child_llvm_annotations(die, cu, -1, conf, &var->annots))
return NULL;
return &var->ip.tag;
@@ -1684,6 +1766,10 @@ static struct tag *die__create_new_subroutine_type(Dwarf_Die *die,
case DW_TAG_unspecified_parameters:
ftype->unspec_parms = 1;
continue;
+ case DW_TAG_LLVM_annotation:
+ if (add_btf_type_tag(die, cu, conf, &ftype->tag.annots))
+ goto out_delete;
+ continue;
default:
tag = die__process_tag(die, cu, 0, conf);
if (tag == NULL)
@@ -1740,17 +1826,25 @@ static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu, st
die = &child;
do {
- struct enumerator *enumerator;
+ switch (dwarf_tag(die)) {
+ case DW_TAG_enumerator: {
+ struct enumerator *enumerator;
- if (dwarf_tag(die) != DW_TAG_enumerator) {
+ enumerator = enumerator__new(die, cu, conf);
+ if (enumerator == NULL)
+ goto out_delete;
+
+ enumeration__add(enumeration, enumerator);
+ break;
+ }
+ case DW_TAG_LLVM_annotation:
+ if (add_btf_type_tag(die, cu, conf,
+ &enumeration->namespace.tag.annots))
+ goto out_delete;
+ break;
+ default:
cu__tag_not_handled(die);
- continue;
}
- enumerator = enumerator__new(die, cu, conf);
- if (enumerator == NULL)
- goto out_delete;
-
- enumeration__add(enumeration, enumerator);
} while (dwarf_siblingof(die, die) == 0);
out:
return &enumeration->namespace.tag;
@@ -1806,13 +1900,16 @@ static int die__process_class(Dwarf_Die *die, struct type *class,
type__add_member(class, member);
cu__hash(cu, &member->tag);
- if (add_child_llvm_annotations(die, member_idx, conf, &class->namespace.annots))
+ if (add_child_llvm_annotations(die, cu, member_idx, conf,
+ &class->namespace.tag.annots))
return -ENOMEM;
member_idx++;
}
continue;
case DW_TAG_LLVM_annotation:
- if (add_llvm_annotation(die, -1, conf, &class->namespace.annots))
+ if (add_btf_decl_tag(die, cu, -1, conf, &class->namespace.tag.annots))
+ return -ENOMEM;
+ if (add_btf_type_tag(die, cu, conf, &class->namespace.tag.annots))
return -ENOMEM;
continue;
default: {
@@ -2089,7 +2186,8 @@ static int die__process_function(Dwarf_Die *die, struct ftype *ftype,
goto out_enomem;
continue;
case DW_TAG_LLVM_annotation:
- if (add_llvm_annotation(die, -1, conf, &(tag__function(&ftype->tag)->annots)))
+ if (add_btf_decl_tag(die, cu, -1, conf,
+ &(tag__function(&ftype->tag)->annots)))
goto out_enomem;
continue;
default:
@@ -2149,23 +2247,23 @@ static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu,
case DW_TAG_imported_unit:
return NULL; // We don't support imported units yet, so to avoid segfaults
case DW_TAG_array_type:
- tag = die__create_new_array(die, cu); break;
+ tag = die__create_new_array(die, cu, conf); break;
case DW_TAG_string_type: // FORTRAN stuff, looks like an array
tag = die__create_new_string_type(die, cu); break;
case DW_TAG_base_type:
tag = die__create_new_base_type(die, cu, conf); break;
- case DW_TAG_const_type:
case DW_TAG_imported_declaration:
case DW_TAG_imported_module:
case DW_TAG_reference_type:
- case DW_TAG_restrict_type:
- case DW_TAG_volatile_type:
case DW_TAG_atomic_type:
tag = die__create_new_tag(die, cu); break;
- case DW_TAG_unspecified_type:
- tag = die__create_new_tag(die, cu); break;
+ case DW_TAG_const_type:
+ case DW_TAG_restrict_type:
+ case DW_TAG_volatile_type:
case DW_TAG_pointer_type:
- tag = die__create_new_pointer_tag(die, cu, conf); break;
+ tag = die__create_new_annotated_tag(die, cu, conf); break;
+ case DW_TAG_unspecified_type:
+ tag = die__create_new_unspecified_type(die, cu, conf); break;
case DW_TAG_ptr_to_member_type:
tag = die__create_new_ptr_to_member_type(die, cu); break;
case DW_TAG_enumeration_type:
@@ -2252,20 +2350,100 @@ static int die__process_unit(Dwarf_Die *die, struct cu *cu, struct conf_load *co
return 0;
}
-static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu);
+/** Add @tuple to @ctx->mappings array, extend it if necessary. */
+static int push_btf_type_tag_mapping(struct btf_type_tag_mapping *tuple,
+ struct recode_context *ctx)
+{
+ if (ctx->nr_allocated == ctx->nr_entries) {
+ uint32_t new_nr = ctx->nr_allocated * 2;
+ void *new_array = reallocarray(ctx->mappings, new_nr,
+ sizeof(ctx->mappings[0]));
+ if (!new_array)
+ return -ENOMEM;
+ ctx->mappings = new_array;
+ ctx->nr_allocated = new_nr;
+ }
+
+ ctx->mappings[ctx->nr_entries++] = *tuple;
+
+ return 0;
+}
+
+/** Connect `type` fields of btf:type_tag annotations attached to a
+ * host type. Collect information about first and last tag.
+ * `type` field are connected as below:
+ *
+ * tag1.type -> tag2.type -> host_type
+ *
+ * @tags - list of llvm_annotation objects;
+ * @host_type - small_id of the type with attached annotations.
+ */
+static void __recode_btf_type_tags(struct list_head *tags,
+ uint32_t host_type,
+ struct btf_type_tag_mapping *mapping)
+{
+ struct llvm_annotation *annot;
+ struct dwarf_tag *annot_dtag;
+ struct tag *prev_tag = NULL;
+ uint32_t first_tag_id = 0;
+
+ list_for_each_entry(annot, tags, node) {
+ if (annot->kind != BTF_TYPE_TAG)
+ continue;
+ annot_dtag = annot->tag.priv;
+ if (prev_tag)
+ prev_tag->type = annot_dtag->small_id;
+ if (!first_tag_id)
+ first_tag_id = annot_dtag->small_id;
+ prev_tag = &annot->tag;
+ }
-static int namespace__recode_dwarf_types(struct tag *tag, struct cu *cu)
+ mapping->host_type_id = host_type;
+ if (prev_tag) {
+ prev_tag->type = host_type;
+ mapping->first_tag_id = first_tag_id;
+ mapping->last_tag_id = annot_dtag->small_id;
+ } else {
+ mapping->first_tag_id = 0;
+ mapping->last_tag_id = 0;
+ }
+}
+
+static int recode_btf_type_tags(struct list_head *tags,
+ uint32_t host_type,
+ struct recode_context *ctx)
+{
+ struct btf_type_tag_mapping mapping;
+
+ if (list_empty(tags))
+ return 0;
+
+ __recode_btf_type_tags(tags, host_type, &mapping);
+ if (!mapping.first_tag_id)
+ return 0;
+
+ return push_btf_type_tag_mapping(&mapping, ctx);
+}
+
+static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu,
+ struct recode_context *ctx);
+
+static int namespace__recode_dwarf_types(struct tag *tag, struct cu *cu,
+ struct recode_context *ctx)
{
struct tag *pos;
struct dwarf_cu *dcu = cu->priv;
+ struct dwarf_tag *dtag = tag->priv;
struct namespace *ns = tag__namespace(tag);
+ recode_btf_type_tags(&tag->annots, dtag->small_id, ctx);
+
namespace__for_each_tag(ns, pos) {
struct dwarf_tag *dtype;
struct dwarf_tag *dpos = pos->priv;
if (tag__has_namespace(pos)) {
- if (namespace__recode_dwarf_types(pos, cu))
+ if (namespace__recode_dwarf_types(pos, cu, ctx))
return -1;
continue;
}
@@ -2286,7 +2464,7 @@ static int namespace__recode_dwarf_types(struct tag *tag, struct cu *cu)
break;
case DW_TAG_subroutine_type:
case DW_TAG_subprogram:
- ftype__recode_dwarf_types(pos, cu);
+ ftype__recode_dwarf_types(pos, cu, ctx);
break;
case DW_TAG_imported_module:
dtype = dwarf_cu__find_tag_by_ref(dcu, &dpos->type);
@@ -2351,7 +2529,8 @@ 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__)
-static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu)
+static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu,
+ struct recode_context *ctx)
{
struct parameter *pos;
struct dwarf_cu *dcu = cu->priv;
@@ -2399,9 +2578,13 @@ static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu)
}
pos->tag.type = dtype->small_id;
}
+
+ struct dwarf_tag *dtag = tag->priv;
+ recode_btf_type_tags(&tag->annots, dtag->small_id, ctx);
}
-static void lexblock__recode_dwarf_types(struct lexblock *tag, struct cu *cu)
+static void lexblock__recode_dwarf_types(struct lexblock *tag, struct cu *cu,
+ struct recode_context *ctx)
{
struct tag *pos;
struct dwarf_cu *dcu = cu->priv;
@@ -2412,7 +2595,7 @@ static void lexblock__recode_dwarf_types(struct lexblock *tag, struct cu *cu)
switch (pos->tag) {
case DW_TAG_lexical_block:
- lexblock__recode_dwarf_types(tag__lexblock(pos), cu);
+ lexblock__recode_dwarf_types(tag__lexblock(pos), cu, ctx);
continue;
case DW_TAG_inlined_subroutine:
if (dpos->type.off != 0)
@@ -2426,7 +2609,7 @@ static void lexblock__recode_dwarf_types(struct lexblock *tag, struct cu *cu)
tag__print_abstract_origin_not_found(pos);
continue;
}
- ftype__recode_dwarf_types(dtype->tag, cu);
+ ftype__recode_dwarf_types(dtype->tag, cu, ctx);
continue;
case DW_TAG_formal_parameter:
@@ -2493,10 +2676,146 @@ static void lexblock__recode_dwarf_types(struct lexblock *tag, struct cu *cu)
}
}
-static void dwarf_cu__recode_btf_type_tag_ptr(struct btf_type_tag_ptr_type *tag,
- uint32_t pointee_type)
+static int recode_context_init(struct recode_context *ctx)
+{
+ const int initial_nr = 16;
+
+ ctx->mappings = reallocarray(NULL, initial_nr, sizeof(ctx->mappings[0]));
+ if (!ctx->mappings)
+ return -ENOMEM;
+
+ ctx->nr_allocated = initial_nr;
+ ctx->nr_entries = 0;
+
+ return 0;
+}
+
+static void recode_context_free(struct recode_context *ctx)
+{
+ free(ctx->mappings);
+ ctx->nr_allocated = 0;
+ ctx->nr_entries = 0;
+}
+
+/** Compare two `btf_type_tag_mapping` objects using host_type_id as key. */
+static int compare_btf_type_tag_recode_mappings(const void *_a, const void *_b)
+{
+ const struct btf_type_tag_mapping *a = _a;
+ const struct btf_type_tag_mapping *b = _b;
+ long diff = (long)a->host_type_id - (long)b->host_type_id;
+
+ if (diff < 0)
+ return -1;
+ if (diff > 0)
+ return 1;
+ return 0;
+}
+
+/** Sort @ctx->mappings array by btf_type_tag_mapping::host_type_id,
+ * function `lookup_btf_type_tag_by_host()` uses binary search to find
+ * elements of this array.
+ */
+static void sort_btf_type_tags(struct recode_context *ctx)
+{
+ qsort(ctx->mappings, ctx->nr_entries, sizeof(ctx->mappings[0]),
+ compare_btf_type_tag_recode_mappings);
+}
+
+static struct btf_type_tag_mapping *lookup_btf_type_tag_by_host(uint32_t host_type_id,
+ struct recode_context *ctx)
+{
+ struct btf_type_tag_mapping key = { .host_type_id = host_type_id };
+
+ return bsearch(&key, ctx->mappings, ctx->nr_entries, sizeof(key),
+ compare_btf_type_tag_recode_mappings);
+}
+
+/** Update @tag->type fields by replacing types by ids of associated
+ * btf:type_tag objects. @ctx->mappings should be sorted when this
+ * function is called.
+ *
+ * When "btf:type_tag" is attached to a type it applies to this type.
+ * For example, the following dwarf:
+ *
+ * 0x00000040: DW_TAG_member
+ * DW_AT_name ("c")
+ * DW_AT_type (0x0000008c "int")
+ * DW_AT_decl_file ("/home/eddy/work/tmp/test.c")
+ * DW_AT_decl_line (13)
+ * DW_AT_data_member_location (0x10)
+ *
+ * 0x0000008c: DW_TAG_base_type
+ * DW_AT_name ("int")
+ * DW_AT_encoding (DW_ATE_signed)
+ * DW_AT_byte_size (0x04)
+ *
+ * 0x00000090: DW_TAG_LLVM_annotation
+ * DW_AT_name ("btf:type_tag")
+ * DW_AT_const_value ("__c")
+ *
+ * Means that type 0x0000008c is an `int` with type tag `__c`.
+ * Corresponding BTF looks as follows:
+ *
+ * [1] STRUCT 'echo'
+ * ...
+ * 'c' type_id=8 bits_offset=128
+ * [4] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED
+ * [8] TYPE_TAG '__c' type_id=4
+ *
+ * Before the call to `update_btf_type_tag_refs` for member 0x00000040
+ * its `type` field points to 0x0000008c. `update_btf_type_tag_refs`
+ * updates this link to point to `0x00000090` instead, thus obtaining the
+ * desired BTF shape.
+ */
+static int update_btf_type_tag_refs(struct tag *tag,
+ struct cu *cu,
+ struct recode_context *ctx)
+{
+ struct btf_type_tag_mapping *tuple;
+ struct dwarf_tag *dtag = tag->priv;
+
+ /* Kernel does not support VAR entries with types of form
+ * 'VAR -> TYPE_TAG -> something':
+ * - in verifier.c:check_pseudo_btf_id() instruction auxiliary
+ * data is set to point to variable type w/o stripping modifiers;
+ * - btf.c:btf_struct_access() -> btf.c:btf_struct_walk()
+ * does not skip modifiers prior to btf_type_is_struct() check.
+ *
+ * So, skip type tag recoding for variables.
+ */
+ if (tag->tag == DW_TAG_variable)
+ return 0;
+
+ tuple = lookup_btf_type_tag_by_host(tag->type, ctx);
+ /* Avoid creation of circular references, last btf:type_tag
+ * object points to the host type.
+ */
+ if (tuple && tuple->last_tag_id != dtag->small_id)
+ tag->type = tuple->first_tag_id;
+
+ if (tag__is_type(tag)) {
+ struct type *type = tag__type(tag);
+ struct class_member *pos;
+
+ type__for_each_data_member(type, pos)
+ update_btf_type_tag_refs(&pos->tag, cu, ctx);
+ } else if (tag->tag == DW_TAG_subprogram ||
+ tag->tag == DW_TAG_subroutine_type) {
+ struct ftype *ftype = tag__ftype(tag);
+ struct parameter *pos;
+
+ ftype__for_each_parameter(ftype, pos)
+ update_btf_type_tag_refs(&pos->tag, cu, ctx);
+ }
+
+ return 0;
+}
+
+static void dwarf_cu__recode_btf_type_tag_ptr(struct tag *tag,
+ uint32_t pointee_type,
+ struct cu *cu)
{
- struct btf_type_tag_type *annot;
+ struct llvm_annotation *annot;
struct dwarf_tag *annot_dtag;
struct tag *prev_tag;
@@ -2523,16 +2842,20 @@ static void dwarf_cu__recode_btf_type_tag_ptr(struct btf_type_tag_ptr_type *tag,
* int tag1 tag2 tag3 *p;
* and this matches the user/kernel code.
*/
- prev_tag = &tag->tag;
- list_for_each_entry(annot, &tag->tags, node) {
- annot_dtag = annot->tag.priv;
- prev_tag->type = annot_dtag->small_id;
- prev_tag = &annot->tag;
+ prev_tag = tag;
+ if (!cu->ignore_btf_type_tag_pointee) {
+ list_for_each_entry(annot, &tag->annots, node) {
+ if (annot->kind != BTF_TYPE_TAG_POINTEE)
+ continue;
+ annot_dtag = annot->tag.priv;
+ prev_tag->type = annot_dtag->small_id;
+ prev_tag = &annot->tag;
+ }
}
prev_tag->type = pointee_type;
}
-static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu)
+static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu, struct recode_context *ctx)
{
struct dwarf_tag *dtag = tag->priv;
struct dwarf_tag *dtype;
@@ -2545,7 +2868,7 @@ static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu)
type__recode_dwarf_specification(tag, cu);
if (tag__has_namespace(tag))
- return namespace__recode_dwarf_types(tag, cu);
+ return namespace__recode_dwarf_types(tag, cu, ctx);
switch (tag->tag) {
case DW_TAG_subprogram: {
@@ -2577,17 +2900,17 @@ static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu)
(unsigned long long)specification.off);
}
}
- lexblock__recode_dwarf_types(&fn->lexblock, cu);
+ lexblock__recode_dwarf_types(&fn->lexblock, cu, ctx);
}
/* Fall thru */
case DW_TAG_subroutine_type:
- ftype__recode_dwarf_types(tag, cu);
+ ftype__recode_dwarf_types(tag, cu, ctx);
/* Fall thru, for the function return type */
break;
case DW_TAG_lexical_block:
- lexblock__recode_dwarf_types(tag__lexblock(tag), cu);
+ lexblock__recode_dwarf_types(tag__lexblock(tag), cu, ctx);
return 0;
case DW_TAG_ptr_to_member_type: {
@@ -2608,7 +2931,7 @@ static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu)
break;
case DW_TAG_namespace:
- return namespace__recode_dwarf_types(tag, cu);
+ return namespace__recode_dwarf_types(tag, cu, ctx);
/* 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.
@@ -2636,15 +2959,19 @@ static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu)
var->spec = tag__variable(dtype->tag);
}
}
+ break;
}
-
+ case DW_TAG_LLVM_annotation:
+ return 0;
}
+ recode_btf_type_tags(&tag->annots, dtag->small_id, ctx);
+
if (dtag->type.off == 0) {
- if (tag->tag != DW_TAG_pointer_type || !tag->has_btf_type_tag)
+ if (tag->tag != DW_TAG_pointer_type)
tag->type = 0; /* void */
else
- dwarf_cu__recode_btf_type_tag_ptr(tag__btf_type_tag_ptr(tag), 0);
+ dwarf_cu__recode_btf_type_tag_ptr(tag, 0, cu);
return 0;
}
@@ -2656,10 +2983,10 @@ check_type:
return 0;
}
out:
- if (tag->tag != DW_TAG_pointer_type || !tag->has_btf_type_tag)
+ if (tag->tag != DW_TAG_pointer_type)
tag->type = dtype->small_id;
else
- dwarf_cu__recode_btf_type_tag_ptr(tag__btf_type_tag_ptr(tag), dtype->small_id);
+ dwarf_cu__recode_btf_type_tag_ptr(tag, dtype->small_id, cu);
return 0;
}
@@ -2744,28 +3071,168 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu)
return 0;
}
-static int cu__recode_dwarf_types_table(struct cu *cu,
- struct ptr_table *pt,
- uint32_t i)
+typedef int (*recode_tag_visitor)(struct tag *, struct cu*, struct recode_context *);
+
+static int cu__visit_all_tags(struct cu *cu, recode_tag_visitor fn, struct recode_context *ctx)
{
- for (; i < pt->nr_entries; ++i) {
- struct tag *tag = pt->entries[i];
+ const int nr_tables = 3;
+ struct {
+ struct ptr_table *table;
+ uint32_t start_idx;
+ } tables[] = {
+ { &cu->types_table, 1 },
+ { &cu->tags_table, 0 },
+ { &cu->functions_table, 0 }
+ };
+ struct ptr_table *pt;
+ struct tag *tag;
+ uint32_t i, t;
- if (tag != NULL) /* void, see cu__new */
- if (tag__recode_dwarf_type(tag, cu))
+ for (t = 0; t < nr_tables; ++t) {
+ pt = tables[t].table;
+ for (i = tables[t].start_idx; i < pt->nr_entries; ++i) {
+ tag = pt->entries[i];
+ if (!tag) /* void, see cu__new */
+ continue;
+ if (fn(tag, cu, ctx))
return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* See comment for cu__allocate_btf_type_tags() below. */
+static int tag__allocate_btf_type_tags(struct tag *tag, struct cu *cu)
+{
+ enum annotation_kind target = cu->ignore_btf_type_tag_pointee
+ ? BTF_TYPE_TAG
+ : BTF_TYPE_TAG_POINTEE;
+ struct list_head *annots = &tag->annots;
+ struct llvm_annotation *annot;
+
+ list_for_each_entry(annot, annots, node) {
+ if (annot->kind != target)
+ continue;
+
+ int err = cu__assign_tag_id(cu, &annot->tag);
+ if (err)
+ return err;
}
return 0;
}
+/* The flag `cu->ignore_btf_type_tag_pointee` is set at DWARF load phase.
+ * Before it is set it is not known what kind of type tags is used in
+ * the program, BTF_TYPE_TAG or BTF_TYPE_TAG_POINTEE.
+ * It is necessary to allocate only a single kind of tags to avoid
+ * spurious entries in the type table (and resultant BTF).
+ * Thus, the allocation of type tags is done as a separate step.
+ */
+static int cu__allocate_btf_type_tags(struct cu *cu)
+{
+ struct unspecified_type *utype;
+ struct tag *pos;
+ uint32_t id;
+ int err = 0;
+
+ cu__for_each_type(cu, id, pos) {
+ err = tag__allocate_btf_type_tags(pos, cu);
+ if (err)
+ return err;
+ }
+
+ list_for_each_entry(utype, &cu->unspecified_types, node) {
+ err = tag__allocate_btf_type_tags(&utype->tag, cu);
+ if (err)
+ return err;
+ }
+
+ return err;
+}
+
+/* `btf:type_tag` tags have special representation, when attached to void type.
+ * For example, DWARF for the following C code:
+ *
+ * struct st {
+ * void __attribute__(btf_type_tag("__d")) *d;
+ * }
+ *
+ * Looks as follows:
+ *
+ * 0x29: DW_TAG_structure_type
+ * DW_AT_name ("st")
+ *
+ * 0x49: DW_TAG_member
+ * DW_AT_name ("d")
+ * DW_AT_type (0xa6 "void *")
+ *
+ * 0xa6: DW_TAG_pointer_type
+ * DW_AT_type (0xaf "void")
+ *
+ * 0xaf: DW_TAG_unspecified_type
+ * DW_AT_name ("void")
+ *
+ * 0xb1: DW_TAG_LLVM_annotation
+ * DW_AT_name ("btf:type_tag")
+ * DW_AT_const_value ("__d")
+ *
+ * Here `void` type is encoded as `DW_TAG_unspecified_type` with
+ * `DW_TAG_LLVM_annotation` children.
+ *
+ * This function replaces `small_id` of the unspecified type (0xaf) with
+ * `small_id` of the first `btf:type_tag` annotation (0xb1).
+ * Thus further recode passes will use id of the type tag in place of the
+ * unspecified type id, when references to unspecified type are resolved.
+ */
+static void cu__recode_unspecified_types(struct cu *cu)
+{
+ struct btf_type_tag_mapping mapping;
+ struct unspecified_type *utype;
+ struct dwarf_tag *dtag;
+
+ list_for_each_entry(utype, &cu->unspecified_types, node) {
+ __recode_btf_type_tags(&utype->tag.annots, 0, &mapping);
+ dtag = utype->tag.priv;
+ dtag->small_id = mapping.first_tag_id;
+ }
+}
+
static int cu__recode_dwarf_types(struct cu *cu)
{
- if (cu__recode_dwarf_types_table(cu, &cu->types_table, 1) ||
- cu__recode_dwarf_types_table(cu, &cu->tags_table, 0) ||
- cu__recode_dwarf_types_table(cu, &cu->functions_table, 0))
+ struct recode_context ctx = {};
+ int err = 0;
+
+ if (recode_context_init(&ctx))
return -1;
- return 0;
+
+ if (cu__allocate_btf_type_tags(cu)) {
+ err = -1;
+ goto cleanup;
+ }
+
+ cu__recode_unspecified_types(cu);
+
+ if (cu__visit_all_tags(cu, tag__recode_dwarf_type, &ctx)) {
+ err = -1;
+ goto cleanup;
+ }
+
+ /* No need for second pass if there are no btf type tags */
+ if (ctx.nr_entries == 0)
+ goto cleanup;
+
+ sort_btf_type_tags(&ctx);
+
+ if (cu__visit_all_tags(cu, update_btf_type_tag_refs, &ctx)) {
+ err = -1;
+ goto cleanup;
+ }
+
+cleanup:
+ recode_context_free(&ctx);
+ return err;
}
static const char *dwarf_tag__decl_file(const struct tag *tag,
diff --git a/dwarves.c b/dwarves.c
index b43031c..7e66a98 100644
--- a/dwarves.c
+++ b/dwarves.c
@@ -681,6 +681,7 @@ struct cu *cu__new(const char *name, uint8_t addr_size,
cu->dfops = NULL;
INIT_LIST_HEAD(&cu->tags);
INIT_LIST_HEAD(&cu->tool_list);
+ INIT_LIST_HEAD(&cu->unspecified_types);
cu->addr_size = addr_size;
cu->extra_dbg_info = 0;
diff --git a/dwarves.h b/dwarves.h
index e92b2fd..8547fea 100644
--- a/dwarves.h
+++ b/dwarves.h
@@ -240,6 +240,7 @@ struct cu {
struct list_head node;
struct list_head tags;
struct list_head tool_list; /* To be used by tools such as ctracer */
+ struct list_head unspecified_types;
struct ptr_table types_table;
struct ptr_table functions_table;
struct ptr_table tags_table;
@@ -258,6 +259,10 @@ struct cu {
uint8_t has_addr_info:1;
uint8_t uses_global_strings:1;
uint8_t little_endian:1;
+ /* When set means that "btf:type_tags" annotations are present
+ * and "btf_type_tags" annotations should be ignored during export.
+ */
+ uint8_t ignore_btf_type_tag_pointee:1;
uint8_t nr_register_params;
int register_params[ARCH_MAX_REGISTER_PARAMS];
uint16_t language;
@@ -417,8 +422,8 @@ int cu__for_all_tags(struct cu *cu,
void *cookie);
/** struct tag - basic representation of a debug info element
- * @priv - extra data, for instance, DWARF offset, id, decl_{file,line}
- * @top_level -
+ * @priv - extra data, for instance, DWARF offset, id, decl_{file,line}
+ * @annots - list of btf_type_tag and btf_decl_tag annotations.
*/
struct tag {
struct list_head node;
@@ -426,8 +431,8 @@ struct tag {
uint16_t tag;
bool visited;
bool top_level;
- bool has_btf_type_tag;
uint16_t recursivity_level;
+ struct list_head annots;
void *priv;
};
@@ -623,43 +628,51 @@ static inline struct ptr_to_member_type *
return (struct ptr_to_member_type *)tag;
}
-struct llvm_annotation {
- const char *value;
- int16_t component_idx;
- struct list_head node;
+enum annotation_kind {
+ BTF_DECL_TAG,
+ /* "btf_type_tag" in DWARF, attached to a pointer, applies to pointee type.
+ * Old-style encoding kept for backwards compatibility.
+ */
+ BTF_TYPE_TAG_POINTEE,
+ /* "btf:type_tag" in DWARF, attached to any type, applies to parent type */
+ BTF_TYPE_TAG,
};
-/** struct btf_type_tag_type - representing a btf_type_tag annotation
+/** struct llvm_annotation - representing objects with DW_TAG_LLVM_annotation tag
*
- * @tag - DW_TAG_LLVM_annotation tag
- * @value - btf_type_tag value string
- * @node - list_head node
+ * @tag - DW_TAG_LLVM_annotation tag
+ * @kind - annotation kind
+ * @value - value string, valid for both "btf_decl_tag" and "btf_type_tag"
+ * @component_idx - component index, valid only for "btf_decl_tag"
+ * @node - list_head node
*/
-struct btf_type_tag_type {
+struct llvm_annotation {
struct tag tag;
+ enum annotation_kind kind;
const char *value;
+ int16_t component_idx;
struct list_head node;
};
-/** The struct btf_type_tag_ptr_type - type containing both pointer type and
- * its btf_type_tag annotations
+static inline struct llvm_annotation *tag__llvm_annotation(struct tag *tag)
+{
+ return (struct llvm_annotation *)tag;
+}
+
+/** struct unspecified_type - representation of DW_TAG_unspecified_type.
*
- * @tag - pointer type tag
- * @tags - btf_type_tag annotations for the pointer type
+ * @name - DW_AT_name associated with this tag
+ * @node - a node for cu::unspecified_types list
*/
-struct btf_type_tag_ptr_type {
+struct unspecified_type {
struct tag tag;
- struct list_head tags;
+ const char *name;
+ struct list_head node;
};
-static inline struct btf_type_tag_ptr_type *tag__btf_type_tag_ptr(struct tag *tag)
-{
- return (struct btf_type_tag_ptr_type *)tag;
-}
-
-static inline struct btf_type_tag_type *tag__btf_type_tag(struct tag *tag)
+static inline struct unspecified_type *tag__unspecified_type(struct tag *tag)
{
- return (struct btf_type_tag_type *)tag;
+ return (struct unspecified_type *)tag;
}
/** struct namespace - base class for enums, structs, unions, typedefs, etc
@@ -673,7 +686,6 @@ struct namespace {
uint16_t nr_tags;
uint8_t shared_tags;
struct list_head tags;
- struct list_head annots;
};
static inline struct namespace *tag__namespace(const struct tag *tag)
@@ -1339,6 +1351,10 @@ enum base_type_float_type {
BT_FP_IMGRY_LDBL
};
+/** struct base_type - represents types with DW_TAG_base_type
+ *
+ * @tags - an optional list of btf_type_tag annotations
+ */
struct base_type {
struct tag tag;
const char *name;
diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c
index 30355b4..baa5924 100644
--- a/dwarves_fprintf.c
+++ b/dwarves_fprintf.c
@@ -571,6 +571,7 @@ static const char *__tag__name(const struct tag *tag, const struct cu *cu,
case DW_TAG_restrict_type:
case DW_TAG_atomic_type:
case DW_TAG_unspecified_type:
+ case DW_TAG_LLVM_annotation:
type = cu__type(cu, tag->type);
if (type == NULL && tag->type != 0)
tag__id_not_found_snprintf(bf, len, tag->type);
@@ -782,6 +783,10 @@ next_type:
n = tag__has_type_loop(type, ptype, NULL, 0, fp);
if (n)
return printed + n;
+ if (ptype->tag == DW_TAG_LLVM_annotation) {
+ type = ptype;
+ goto next_type;
+ }
if (ptype->tag == DW_TAG_subroutine_type) {
printed += ftype__fprintf(tag__ftype(ptype),
cu, name, 0, 1,
@@ -874,6 +879,14 @@ print_modifier: {
else
printed += enumeration__fprintf(type, &tconf, fp);
break;
+ case DW_TAG_LLVM_annotation: {
+ struct tag *ttype = cu__type(cu, type->type);
+ if (ttype) {
+ type = ttype;
+ goto next_type;
+ }
+ goto out_type_not_found;
+ }
}
out:
if (type_expanded)
--
2.39.1
next prev parent reply other threads:[~2023-03-13 2:18 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-03-13 2:17 [PATCH dwarves 0/1] Support for new btf_type_tag encoding Eduard Zingerman
2023-03-13 2:17 ` Eduard Zingerman [this message]
2023-03-14 10:30 ` [PATCH dwarves 1/1] dwarf_loader: Support for btf:type_tag Alan Maguire
2023-03-14 11:21 ` Eduard Zingerman
2023-03-13 20:32 ` [PATCH dwarves 0/1] Support for new btf_type_tag encoding Arnaldo Carvalho de Melo
2023-03-13 23:35 ` Eduard Zingerman
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=20230313021744.406197-2-eddyz87@gmail.com \
--to=eddyz87@gmail.com \
--cc=andrii@kernel.org \
--cc=arnaldo.melo@gmail.com \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=david.faust@oracle.com \
--cc=dwarves@vger.kernel.org \
--cc=jose.marchesi@oracle.com \
--cc=kernel-team@fb.com \
--cc=yhs@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.