dwarf_loader: Support btf_type_tag attribute
LLVM patches ([1] for clang, [2] and [3] for BPF backend) added support for btf_type_tag attributes. The following is an example: [$ ~] cat t.c #define __tag1 __attribute__((btf_type_tag("tag1"))) #define __tag2 __attribute__((btf_type_tag("tag2"))) int __tag1 * __tag1 __tag2 *g __attribute__((section(".data..percpu"))); [$ ~] clang -O2 -g -c t.c [$ ~] llvm-dwarfdump --debug-info t.o t.o: file format elf64-x86-64 ... 0x0000001e: DW_TAG_variable DW_AT_name ("g") DW_AT_type (0x00000033 "int **") DW_AT_external (true) DW_AT_decl_file ("/home/yhs/t.c") DW_AT_decl_line (3) DW_AT_location (DW_OP_addr 0x0) 0x00000033: DW_TAG_pointer_type DW_AT_type (0x0000004b "int *") 0x00000038: DW_TAG_LLVM_annotation DW_AT_name ("btf_type_tag") DW_AT_const_value ("tag1") 0x00000041: DW_TAG_LLVM_annotation DW_AT_name ("btf_type_tag") DW_AT_const_value ("tag2") 0x0000004a: NULL 0x0000004b: DW_TAG_pointer_type DW_AT_type (0x0000005a "int") 0x00000050: DW_TAG_LLVM_annotation DW_AT_name ("btf_type_tag") DW_AT_const_value ("tag1") 0x00000059: NULL 0x0000005a: DW_TAG_base_type DW_AT_name ("int") DW_AT_encoding (DW_ATE_signed) DW_AT_byte_size (0x04) 0x00000061: NULL From the above example, you can see that DW_TAG_pointer_type may contain one or more DW_TAG_LLVM_annotation btf_type_tag tags. If DW_TAG_LLVM_annotation tags are present inside DW_TAG_pointer_type, for BTF encoding, pahole will need to follow [3] to generate a type chain like: var -> ptr -> tag2 -> tag1 -> ptr -> tag1 -> int This patch implemented dwarf_loader support. If a pointer type contains DW_TAG_LLVM_annotation tags, a new type btf_type_tag_ptr_type will be created which will store the pointer tag itself and all DW_TAG_LLVM_annotation tags. During recoding stage, the type chain will be formed properly based on the above example. An option "--skip_encoding_btf_type_tag" is added to disable this new functionality. [1] https://reviews.llvm.org/D111199 [2] https://reviews.llvm.org/D113222 [3] https://reviews.llvm.org/D113496 Signed-off-by: Yonghong Song <yhs@fb.com> Acked-by: Andrii Nakryiko <andrii@kernel.org> Cc: Alexei Starovoitov <ast@kernel.org> Cc: Daniel Borkmann <daniel@iogearbox.net> Cc: bpf@vger.kernel.org Cc: dwarves@vger.kernel.org Cc: kernel-team@fb.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
a0cc68687f
commit
b488c8d328
136
dwarf_loader.c
136
dwarf_loader.c
|
@ -1206,6 +1206,89 @@ 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)
|
||||
{
|
||||
struct btf_type_tag_ptr_type *tag;
|
||||
|
||||
tag = tag__alloc_with_spec(cu, sizeof(struct btf_type_tag_ptr_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;
|
||||
|
||||
tag = tag__alloc_with_spec(cu, sizeof(struct btf_type_tag_type));
|
||||
if (tag == NULL)
|
||||
return NULL;
|
||||
|
||||
tag__init(&tag->tag, cu, die);
|
||||
tag->value = attr_string(die, DW_AT_const_value, conf);
|
||||
return tag;
|
||||
}
|
||||
|
||||
static struct tag *die__create_new_pointer_tag(Dwarf_Die *die, struct cu *cu,
|
||||
struct conf_load *conf)
|
||||
{
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
|
||||
struct dwarf_tag *dtag = annot->tag.priv;
|
||||
dtag->small_id = id;
|
||||
cu__hash(cu, &annot->tag);
|
||||
|
||||
/* 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);
|
||||
|
||||
return tag ? &tag->tag : tag__new(die, cu);
|
||||
}
|
||||
|
||||
static struct tag *die__create_new_ptr_to_member_type(Dwarf_Die *die,
|
||||
struct cu *cu)
|
||||
{
|
||||
|
@ -1903,12 +1986,13 @@ static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu,
|
|||
case DW_TAG_const_type:
|
||||
case DW_TAG_imported_declaration:
|
||||
case DW_TAG_imported_module:
|
||||
case DW_TAG_pointer_type:
|
||||
case DW_TAG_reference_type:
|
||||
case DW_TAG_restrict_type:
|
||||
case DW_TAG_unspecified_type:
|
||||
case DW_TAG_volatile_type:
|
||||
tag = die__create_new_tag(die, cu); break;
|
||||
case DW_TAG_pointer_type:
|
||||
tag = die__create_new_pointer_tag(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:
|
||||
|
@ -2192,6 +2276,45 @@ 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)
|
||||
{
|
||||
struct btf_type_tag_type *annot;
|
||||
struct dwarf_tag *annot_dtag;
|
||||
struct tag *prev_tag;
|
||||
|
||||
/* Given source like
|
||||
* int tag1 tag2 tag3 *p;
|
||||
* the tag->tags contains tag3 -> tag2 -> tag1, the final type chain looks like:
|
||||
* pointer -> tag3 -> tag2 -> tag1 -> pointee
|
||||
*
|
||||
* Basically it means
|
||||
* - '*' applies to "int tag1 tag2 tag3"
|
||||
* - tag3 applies to "int tag1 tag2"
|
||||
* - tag2 applies to "int tag1"
|
||||
* - tag1 applies to "int"
|
||||
*
|
||||
* This also makes final source code (format c) easier as we can do
|
||||
* emit for "tag3 -> tag2 -> tag1 -> int"
|
||||
* emit '*'
|
||||
*
|
||||
* For 'tag3 -> tag2 -> tag1 -> int":
|
||||
* emit for "tag2 -> tag1 -> int"
|
||||
* emit tag3
|
||||
*
|
||||
* Eventually we can get the source code like
|
||||
* 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->type = pointee_type;
|
||||
}
|
||||
|
||||
static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu)
|
||||
{
|
||||
struct dwarf_tag *dtag = tag->priv;
|
||||
|
@ -2301,7 +2424,10 @@ static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu)
|
|||
}
|
||||
|
||||
if (dtag->type.off == 0) {
|
||||
tag->type = 0; /* void */
|
||||
if (tag->tag != DW_TAG_pointer_type || !tag->has_btf_type_tag)
|
||||
tag->type = 0; /* void */
|
||||
else
|
||||
dwarf_cu__recode_btf_type_tag_ptr(tag__btf_type_tag_ptr(tag), 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2313,7 +2439,11 @@ check_type:
|
|||
return 0;
|
||||
}
|
||||
out:
|
||||
tag->type = dtype->small_id;
|
||||
if (tag->tag != DW_TAG_pointer_type || !tag->has_btf_type_tag)
|
||||
tag->type = dtype->small_id;
|
||||
else
|
||||
dwarf_cu__recode_btf_type_tag_ptr(tag__btf_type_tag_ptr(tag), dtype->small_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
33
dwarves.h
33
dwarves.h
|
@ -63,6 +63,7 @@ struct conf_load {
|
|||
bool ptr_table_stats;
|
||||
bool skip_encoding_btf_decl_tag;
|
||||
bool skip_missing;
|
||||
bool skip_encoding_btf_type_tag;
|
||||
uint8_t hashtable_bits;
|
||||
uint8_t max_hashtable_bits;
|
||||
uint16_t kabi_prefix_len;
|
||||
|
@ -413,6 +414,7 @@ struct tag {
|
|||
uint16_t tag;
|
||||
bool visited;
|
||||
bool top_level;
|
||||
bool has_btf_type_tag;
|
||||
uint16_t recursivity_level;
|
||||
void *priv;
|
||||
};
|
||||
|
@ -533,7 +535,8 @@ static inline int tag__is_tag_type(const struct tag *tag)
|
|||
tag->tag == DW_TAG_restrict_type ||
|
||||
tag->tag == DW_TAG_subroutine_type ||
|
||||
tag->tag == DW_TAG_unspecified_type ||
|
||||
tag->tag == DW_TAG_volatile_type;
|
||||
tag->tag == DW_TAG_volatile_type ||
|
||||
tag->tag == DW_TAG_LLVM_annotation;
|
||||
}
|
||||
|
||||
static inline const char *tag__decl_file(const struct tag *tag,
|
||||
|
@ -606,6 +609,34 @@ struct llvm_annotation {
|
|||
struct list_head node;
|
||||
};
|
||||
|
||||
/** struct btf_type_tag_type - representing a btf_type_tag annotation
|
||||
*
|
||||
* @tag - DW_TAG_LLVM_annotation tag
|
||||
* @value - btf_type_tag value string
|
||||
* @node - list_head node
|
||||
*/
|
||||
struct btf_type_tag_type {
|
||||
struct tag tag;
|
||||
const char *value;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
/** The struct btf_type_tag_ptr_type - type containing both pointer type and
|
||||
* its btf_type_tag annotations
|
||||
*
|
||||
* @tag - pointer type tag
|
||||
* @tags - btf_type_tag annotations for the pointer type
|
||||
*/
|
||||
struct btf_type_tag_ptr_type {
|
||||
struct tag tag;
|
||||
struct list_head tags;
|
||||
};
|
||||
|
||||
static inline struct btf_type_tag_ptr_type *tag__btf_type_tag_ptr(struct tag *tag)
|
||||
{
|
||||
return (struct btf_type_tag_ptr_type *)tag;
|
||||
}
|
||||
|
||||
/** struct namespace - base class for enums, structs, unions, typedefs, etc
|
||||
*
|
||||
* @tags - class_member, enumerators, etc
|
||||
|
|
8
pahole.c
8
pahole.c
|
@ -1126,6 +1126,7 @@ ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
|
|||
#define ARGP_devel_stats 330
|
||||
#define ARGP_skip_encoding_btf_decl_tag 331
|
||||
#define ARGP_skip_missing 332
|
||||
#define ARGP_skip_encoding_btf_type_tag 333
|
||||
|
||||
static const struct argp_option pahole__options[] = {
|
||||
{
|
||||
|
@ -1506,6 +1507,11 @@ static const struct argp_option pahole__options[] = {
|
|||
.key = ARGP_skip_missing,
|
||||
.doc = "skip missing types passed to -C rather than stop",
|
||||
},
|
||||
{
|
||||
.name = "skip_encoding_btf_type_tag",
|
||||
.key = ARGP_skip_encoding_btf_type_tag,
|
||||
.doc = "Do not encode TAGs in BTF."
|
||||
},
|
||||
{
|
||||
.name = NULL,
|
||||
}
|
||||
|
@ -1658,6 +1664,8 @@ static error_t pahole__options_parser(int key, char *arg,
|
|||
conf_load.skip_encoding_btf_decl_tag = true; break;
|
||||
case ARGP_skip_missing:
|
||||
conf_load.skip_missing = true; break;
|
||||
case ARGP_skip_encoding_btf_type_tag:
|
||||
conf_load.skip_encoding_btf_type_tag = true; break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue