Skip to content

Commit 1d33763

Browse files
committed
dwarf_loader: support btf:type_tag DW_TAG_LLVM_annotation
"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 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. To allow backwards compatibility and void additional invocation options, implementation acts in a following way: - both `btf_type_tag` and `btf:type_tag` could be present in the debug info; - if `btf:type_tag` are present in the debug info, `btf_type_tag` annotations are ignored. Code changes could be summarized as follows: - add `enum type_tag_kind` with the following values: - TYPE_TAG_SELF for `btf:type_tag` - TYPE_TAG_POINTEE for `btf_type_tag`; - add field `struct dwarf_cu::effective_type_tag_kind` to decide which type tag kind should be used for CU; - change `dwarf_cu::type_tags` records format to convey tag kind; - add calls to add_btf_type_tag() / add_child_btf_type_tags() for die__create_new_*** functions corresponding to types listed above; - change dwarf_cu__recode_type_tags() to recode TYPE_TAG_SELF type tags *before* main recode phase, so `struct dwarf_cu::hash_types` changes would be visible during main phase. See also: [1] Mailing list discussion regarding `btf:type_tag` Various approaches are discussed, Solution acmel#2 is accepted https://lore.kernel.org/bpf/87r0w9jjoq.fsf@oracle.com/ Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
1 parent 29c337b commit 1d33763

1 file changed

Lines changed: 160 additions & 35 deletions

File tree

dwarf_loader.c

Lines changed: 160 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,29 @@ static void dwarf_tag__set_spec(struct dwarf_tag *dtag, dwarf_off_ref spec)
117117
*(dwarf_off_ref *)(dtag + 1) = spec;
118118
}
119119

120+
enum type_tag_kind {
121+
/* Corresponds to type tags of form:
122+
*
123+
* DW_TAG_LLVM_annotation
124+
* DW_AT_name ("btf:type_tag")
125+
* DW_AT_const_value ("...")
126+
*
127+
* Such entries could be subordinate to any DWARF type.
128+
* The tag applies to the parent type.
129+
*/
130+
TYPE_TAG_SELF = 1u,
131+
/* Corresponds to type tags of form:
132+
*
133+
* DW_TAG_LLVM_annotation
134+
* DW_AT_name ("btf_type_tag")
135+
* DW_AT_const_value ("...")
136+
*
137+
* Such entries are subordinate to DW_TAG_pointer_type type only.
138+
* The tag applies to DW_AT_type of the pointer.
139+
*/
140+
TYPE_TAG_POINTEE = 2u
141+
};
142+
120143
struct dwarf_cu {
121144
struct hlist_head *hash_tags;
122145
struct hlist_head *hash_types;
@@ -125,6 +148,7 @@ struct dwarf_cu {
125148
struct dwarf_tag *last_type_lookup;
126149
struct cu *cu;
127150
struct dwarf_cu *type_unit;
151+
enum type_tag_kind effective_type_tag_kind;
128152
};
129153

130154
static int dwarf_cu__init(struct dwarf_cu *dcu, struct cu *cu)
@@ -153,6 +177,7 @@ static int dwarf_cu__init(struct dwarf_cu *dcu, struct cu *cu)
153177
// To avoid a per-lookup check against NULL in dwarf_cu__find_type_by_ref()
154178
dcu->last_type_lookup = &sentinel_dtag;
155179
ptr_table__init(&dcu->type_tags);
180+
dcu->effective_type_tag_kind = TYPE_TAG_POINTEE;
156181
return 0;
157182
}
158183

@@ -232,6 +257,20 @@ static void cu__hash(struct cu *cu, struct tag *tag)
232257
hashtags__hash(hashtable, tag->priv);
233258
}
234259

260+
/* Change impostor->priv->id to match tag->priv->id and replace `tag`
261+
* by `impostor` in the `cu` types/tags table.
262+
*/
263+
static void cu__hash_impersonate(struct cu *cu, struct tag *tag, struct tag *impostor)
264+
{
265+
struct dwarf_tag *dimpostor = impostor->priv;
266+
struct dwarf_tag *dtag = tag->priv;
267+
268+
hlist_del_init(&dimpostor->hash_node);
269+
hlist_del_init(&dtag->hash_node);
270+
dimpostor->id = dtag->id;
271+
cu__hash(cu, impostor);
272+
}
273+
235274
static struct dwarf_tag *dwarf_cu__find_tag_by_ref(const struct dwarf_cu *cu,
236275
const struct dwarf_off_ref *ref)
237276
{
@@ -980,28 +1019,34 @@ static void type_tags_writer__init(struct type_tags_writer *writer,
9801019
* treat `writer->dcu->type_tags` as a stream of records with the
9811020
* following format:
9821021
*
983-
* ... parent-pointer tag-value* NULL ...
984-
* ^ ^ ^
985-
* | | '----- terminator
986-
* struct tag* char*
1022+
* ... parent-pointer (tag-value tag-kind)* NULL ...
1023+
* ^ ^ ^ ^
1024+
* | | | '----- terminator
1025+
* struct tag* char* enum type_tag_kind
9871026
*/
9881027
static int add_btf_type_tag(struct type_tags_writer *writer, Dwarf_Die *die,
9891028
struct conf_load *conf)
9901029
{
9911030
struct ptr_table *type_tags = &writer->dcu->type_tags;
9921031
const char *name, *value;
1032+
uintptr_t kind = 0;
9931033
uint32_t ignored;
9941034
int ret = 0;
9951035

9961036
if (conf->skip_encoding_btf_type_tag)
9971037
return 0;
9981038

9991039
name = attr_string(die, DW_AT_name, conf);
1000-
if (strcmp(name, "btf_type_tag") != 0)
1040+
kind = strcmp(name, "btf_type_tag") == 0 ? TYPE_TAG_POINTEE : kind;
1041+
kind = strcmp(name, "btf:type_tag") == 0 ? TYPE_TAG_SELF : kind;
1042+
if (!kind)
10011043
return 0;
10021044

10031045
value = attr_string(die, DW_AT_const_value, conf);
10041046

1047+
if (kind == TYPE_TAG_SELF)
1048+
writer->dcu->effective_type_tag_kind = TYPE_TAG_SELF;
1049+
10051050
if (!writer->started) {
10061051
writer->started = true;
10071052
/* Terminate previous record */
@@ -1016,7 +1061,11 @@ static int add_btf_type_tag(struct type_tags_writer *writer, Dwarf_Die *die,
10161061
return ret;
10171062
}
10181063

1019-
return ptr_table__add(type_tags, (void *)value, &ignored);
1064+
ret = ptr_table__add(type_tags, (void *)value, &ignored);
1065+
if (ret)
1066+
return ret;
1067+
1068+
return ptr_table__add(type_tags, (void *)kind, &ignored);
10201069
}
10211070

10221071
/* Collect all type tag values attached to `parent` and save those in
@@ -1510,6 +1559,7 @@ static struct tag *die__create_new_unspecified_type(Dwarf_Die *die, struct cu *c
15101559
INIT_LIST_HEAD(&tag->node);
15111560

15121561
tag->name = attr_string(die, DW_AT_name, conf);
1562+
add_child_btf_type_tags(die, cu, &tag->tag, conf);
15131563

15141564
list_add(&tag->node, &cu->unspecified_types);
15151565

@@ -1611,9 +1661,7 @@ static struct tag *die__create_new_base_type(Dwarf_Die *die, struct cu *cu, stru
16111661
if (base == NULL)
16121662
return NULL;
16131663

1614-
if (dwarf_haschildren(die))
1615-
fprintf(stderr, "%s: DW_TAG_base_type WITH children!\n",
1616-
__func__);
1664+
add_child_btf_type_tags(die, cu, &base->tag, conf);
16171665

16181666
return &base->tag;
16191667
}
@@ -1628,11 +1676,15 @@ static struct tag *die__create_new_typedef(Dwarf_Die *die, struct cu *cu, struct
16281676
if (add_child_llvm_annotations(die, -1, conf, &tdef->namespace.annots))
16291677
return NULL;
16301678

1679+
if (add_child_btf_type_tags(die, cu, &tdef->namespace.tag, conf))
1680+
return NULL;
1681+
16311682
return &tdef->namespace.tag;
16321683
}
16331684

1634-
static struct tag *die__create_new_array(Dwarf_Die *die, struct cu *cu)
1685+
static struct tag *die__create_new_array(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
16351686
{
1687+
struct type_tags_writer ttw;
16361688
Dwarf_Die child;
16371689
/* "64 dimensions will be enough for everybody." acme, 2006 */
16381690
const uint8_t max_dimensions = 64;
@@ -1645,19 +1697,29 @@ static struct tag *die__create_new_array(Dwarf_Die *die, struct cu *cu)
16451697
if (!dwarf_haschildren(die) || dwarf_child(die, &child) != 0)
16461698
return &array->tag;
16471699

1700+
type_tags_writer__init(&ttw, cu->priv, &array->tag);
16481701
die = &child;
16491702
do {
1650-
if (dwarf_tag(die) == DW_TAG_subrange_type) {
1703+
switch (dwarf_tag(die)) {
1704+
case DW_TAG_subrange_type:
16511705
nr_entries[array->dimensions++] = attr_upper_bound(die);
16521706
if (array->dimensions == max_dimensions) {
16531707
fprintf(stderr, "%s: only %u dimensions are "
16541708
"supported!\n",
16551709
__FUNCTION__, max_dimensions);
1656-
break;
1710+
goto _break_loop;
16571711
}
1658-
} else
1712+
break;
1713+
case DW_TAG_LLVM_annotation:
1714+
if (add_btf_type_tag(&ttw, die, conf))
1715+
goto out_free;
1716+
break;
1717+
default:
16591718
cu__tag_not_handled(die);
1719+
break;
1720+
}
16601721
} while (dwarf_siblingof(die, die) == 0);
1722+
_break_loop:
16611723

16621724
array->nr_entries = memdup(nr_entries,
16631725
array->dimensions * sizeof(uint32_t), cu);
@@ -1754,6 +1816,7 @@ static struct tag *die__create_new_constant(Dwarf_Die *die, struct cu *cu, struc
17541816
static struct tag *die__create_new_subroutine_type(Dwarf_Die *die,
17551817
struct cu *cu, struct conf_load *conf)
17561818
{
1819+
struct type_tags_writer ttw;
17571820
Dwarf_Die child;
17581821
struct ftype *ftype = ftype__new(die, cu);
17591822
struct tag *tag;
@@ -1764,6 +1827,7 @@ static struct tag *die__create_new_subroutine_type(Dwarf_Die *die,
17641827
if (!dwarf_haschildren(die) || dwarf_child(die, &child) != 0)
17651828
goto out;
17661829

1830+
type_tags_writer__init(&ttw, cu->priv, &ftype->tag);
17671831
die = &child;
17681832
do {
17691833
uint32_t id;
@@ -1778,6 +1842,10 @@ static struct tag *die__create_new_subroutine_type(Dwarf_Die *die,
17781842
case DW_TAG_unspecified_parameters:
17791843
ftype->unspec_parms = 1;
17801844
continue;
1845+
case DW_TAG_LLVM_annotation:
1846+
if (add_btf_type_tag(&ttw, die, conf))
1847+
goto out_delete;
1848+
continue;
17811849
default:
17821850
tag = die__process_tag(die, cu, 0, conf);
17831851
if (tag == NULL)
@@ -1817,6 +1885,7 @@ static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu, st
18171885
{
18181886
Dwarf_Die child;
18191887
struct type *enumeration = type__new(die, cu, conf);
1888+
struct type_tags_writer ttw;
18201889

18211890
if (enumeration == NULL)
18221891
return NULL;
@@ -1832,19 +1901,27 @@ static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu, st
18321901
goto out;
18331902
}
18341903

1904+
type_tags_writer__init(&ttw, cu->priv, &enumeration->namespace.tag);
18351905
die = &child;
18361906
do {
18371907
struct enumerator *enumerator;
18381908

1839-
if (dwarf_tag(die) != DW_TAG_enumerator) {
1909+
switch (dwarf_tag(die)) {
1910+
case DW_TAG_enumerator:
1911+
enumerator = enumerator__new(die, cu, conf);
1912+
if (enumerator == NULL)
1913+
goto out_delete;
1914+
1915+
enumeration__add(enumeration, enumerator);
1916+
break;
1917+
case DW_TAG_LLVM_annotation:
1918+
if (add_btf_type_tag(&ttw, die, conf))
1919+
goto out_delete;
1920+
break;
1921+
default:
18401922
cu__tag_not_handled(die);
1841-
continue;
1923+
break;
18421924
}
1843-
enumerator = enumerator__new(die, cu, conf);
1844-
if (enumerator == NULL)
1845-
goto out_delete;
1846-
1847-
enumeration__add(enumeration, enumerator);
18481925
} while (dwarf_siblingof(die, die) == 0);
18491926
out:
18501927
return &enumeration->namespace.tag;
@@ -1857,8 +1934,10 @@ static int die__process_class(Dwarf_Die *die, struct type *class,
18571934
struct cu *cu, struct conf_load *conf)
18581935
{
18591936
const bool is_union = tag__is_union(&class->namespace.tag);
1937+
struct type_tags_writer ttw;
18601938
int member_idx = 0;
18611939

1940+
type_tags_writer__init(&ttw, cu->priv, &class->namespace.tag);
18621941
do {
18631942
switch (dwarf_tag(die)) {
18641943
case DW_TAG_subrange_type: // XXX: ADA stuff, its a type tho, will have other entries referencing it...
@@ -1906,6 +1985,8 @@ static int die__process_class(Dwarf_Die *die, struct type *class,
19061985
}
19071986
continue;
19081987
case DW_TAG_LLVM_annotation:
1988+
if (add_btf_type_tag(&ttw, die, conf))
1989+
return -ENOMEM;
19091990
if (add_llvm_annotation(die, -1, conf, &class->namespace.annots))
19101991
return -ENOMEM;
19111992
continue;
@@ -2243,7 +2324,7 @@ static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu,
22432324
case DW_TAG_imported_unit:
22442325
return NULL; // We don't support imported units yet, so to avoid segfaults
22452326
case DW_TAG_array_type:
2246-
tag = die__create_new_array(die, cu); break;
2327+
tag = die__create_new_array(die, cu, conf); break;
22472328
case DW_TAG_string_type: // FORTRAN stuff, looks like an array
22482329
tag = die__create_new_string_type(die, cu); break;
22492330
case DW_TAG_base_type:
@@ -2866,11 +2947,20 @@ static struct btf_type_tag_type *new_btf_type_tag_type(struct cu *cu,
28662947
*
28672948
* tag3 -> tag2 -> tag1
28682949
*
2869-
* And complete the chain as follows for each type tag group:
2950+
* And for kind == TYPE_TAG_POINTEE complete the chain as follows for
2951+
* each type tag group:
28702952
*
28712953
* '*' -> tag3 -> tag2 -> tag1 -> int
2954+
*
2955+
* For kind == TYPE_TAG_SELF the tag1..3 would be applied to `int`
2956+
* entry itself, thus complete the chain as below:
2957+
*
2958+
* tag3 -> tag2 -> tag1 -> int
2959+
*
2960+
* And do cu__hash_impersonate(cu, int, tag3), so that each lookup of
2961+
* `int` by Dwarf_Off would return `tag3`.
28722962
*/
2873-
static int dwarf_cu__recode_type_tags(struct cu *cu)
2963+
static int dwarf_cu__recode_type_tags(struct cu *cu, enum type_tag_kind target_kind)
28742964
{
28752965
struct dwarf_cu *dcu = cu->priv;
28762966
void **entries = dcu->type_tags.entries;
@@ -2885,12 +2975,18 @@ static int dwarf_cu__recode_type_tags(struct cu *cu)
28852975
struct btf_type_tag_type *prev = NULL;
28862976

28872977
while (i < N) {
2888-
const char *value = entries[i++];
2978+
const char *value;
2979+
uintptr_t kind;
28892980
uint32_t id;
28902981

2891-
if (value == NULL)
2982+
value = entries[i++];
2983+
if (value == NULL || i >= N)
28922984
break;
28932985

2986+
kind = (uintptr_t)entries[i++];
2987+
if (kind != target_kind)
2988+
continue;
2989+
28942990
last = new_btf_type_tag_type(cu, value);
28952991
if (last == NULL)
28962992
return -ENOMEM;
@@ -2912,27 +3008,56 @@ static int dwarf_cu__recode_type_tags(struct cu *cu)
29123008
if (first == NULL)
29133009
continue;
29143010

2915-
/* Type tags are recoded *after* main recode phase,
2916-
* so parent->type is valid.
2917-
*
2918-
* parent last first parent->type
2919-
* | | | |
2920-
* '*' -> tag3 -> tag2 -> tag1 -> int
2921-
*/
2922-
first->tag.type = parent->type;
2923-
parent->type = tag__small_id(&last->tag);
3011+
switch (target_kind) {
3012+
case TYPE_TAG_POINTEE:
3013+
/* For POINTEE type tags are recoded *after*
3014+
* main recode phase, so parent->type is valid.
3015+
*
3016+
* parent last first parent->type
3017+
* | | | |
3018+
* '*' -> tag3 -> tag2 -> tag1 -> int
3019+
*/
3020+
first->tag.type = parent->type;
3021+
parent->type = tag__small_id(&last->tag);
3022+
break;
3023+
case TYPE_TAG_SELF:
3024+
/* For SELF type tags are recoded *before*
3025+
* main recode phase, so dcu->hash_types
3026+
* changes would be visible during that phase.
3027+
*
3028+
* last first parent
3029+
* | | |
3030+
* tag3 -> tag2 -> tag1 -> int
3031+
* ^ |
3032+
* '-----------------------'
3033+
* copy parent->tag.priv->id
3034+
*/
3035+
first->tag.type = tag__small_id(parent);
3036+
cu__hash_impersonate(cu, parent, &last->tag);
3037+
break;
3038+
}
29243039
}
29253040

29263041
return 0;
29273042
}
29283043

29293044
static int cu__recode_dwarf_types(struct cu *cu)
29303045
{
3046+
struct dwarf_cu *dcu = cu->priv;
3047+
3048+
if (dcu->effective_type_tag_kind == TYPE_TAG_SELF &&
3049+
dwarf_cu__recode_type_tags(cu, TYPE_TAG_SELF) != 0)
3050+
return -1;
3051+
29313052
if (cu__recode_dwarf_types_table(cu, &cu->types_table, 1) ||
29323053
cu__recode_dwarf_types_table(cu, &cu->tags_table, 0) ||
29333054
cu__recode_dwarf_types_table(cu, &cu->functions_table, 0))
29343055
return -1;
2935-
dwarf_cu__recode_type_tags(cu);
3056+
3057+
if (dcu->effective_type_tag_kind == TYPE_TAG_POINTEE &&
3058+
dwarf_cu__recode_type_tags(cu, TYPE_TAG_POINTEE) != 0)
3059+
return -1;
3060+
29363061
return 0;
29373062
}
29383063

0 commit comments

Comments
 (0)