Currently btf_type_tag attributes are represented in DWARF as child DIEs with DW_TAG_LLVM_annotation tag. Such attributes are supported for derived types of type DW_TAG_pointer_type and designate that the pointee type should have the attribute.
For example, the following C code:
// (variable :name "g" // :type (pointer (int :btf_type_tag "tag1"))) int __attribute__((btf_type_tag("tag1"))) *g;
Corresponds to the following DWARF:
0x1e: DW_TAG_variable DW_AT_name ("g") DW_AT_type (0x29 "int *") 0x29: DW_TAG_pointer_type DW_AT_type (0x32 "int") 0x2e: DW_TAG_LLVM_annotation DW_AT_name ("btf_type_tag") DW_AT_const_value ("tag1") 0x32: DW_TAG_base_type DW_AT_name ("int")
Recent discussion in Kernel BPF mailing list came to conclusion, that such annotations should apply to the annotated type itself (multiple approaches are discussed in the linked thread, "Solution 2" is the one accepted). For example, new DWARF encoding for the code above should look as follows:
0xe: DW_TAG_variable DW_AT_name ("g") DW_AT_type (0x29 "int *") 0x9: DW_TAG_pointer_type DW_AT_type (0x32 "int") 0x2: DW_TAG_base_type DW_AT_name ("int") 0x6: DW_TAG_LLVM_annotation DW_AT_name ("btf:type_tag") DW_AT_const_value ("tag1")
The goal of this commit is to enable new btf_type_tag encoding scheme for debug information emitted by clang. A new tag name, btf:type_tag, is used so that DWARF consumers could distinguish between old and new attachment semantics.
In order to preserve backwards compatibility both btf_type_tag and btf:type_tag are generated. btf_type_tag might be deprecated in the future. The complete DWARF for the example above looks as follows:
0x1e: DW_TAG_variable DW_AT_name ("g") DW_AT_type (0x29 "int *") 0x29: DW_TAG_pointer_type DW_AT_type (0x32 "int") 0x2e: DW_TAG_LLVM_annotation DW_AT_name ("btf_type_tag") DW_AT_const_value ("tag1") 0x32: DW_TAG_base_type DW_AT_name ("int") 0x36: DW_TAG_LLVM_annotation DW_AT_name ("btf:type_tag") DW_AT_const_value ("tag1")
The commit includes the following changes:
- New overload for CGDebugInfo::CreateType method is added to handle BTFTagAttributedType type. It creates a temporary "placeholder" DIDerivedType instance with tag set to DW_TAG_LLVM_annotation, base type corresponding to the base type of the BTFTagAttributedType and annotations corresponding to BTFTagAttributedType. All such placeholder instances are registered in the CGDebugInfo::AnnotationPlaceholders vector.
- This overload is called from CGDebugInfo::CreateTypeNode and it overrides default qualifiers handling. This is necessary to put type tag annotations on the outermost CVR qualifier. Such representation makes downstream DWARF consumers simpler (eventually DWARF is used to construct BTF for kernel and kernel wants all type tag modifiers to precede const modifier).
- CGDebugInfo::finalize() is modified to replace annotation placeholders with real types. When base type of the annotation placeholder is an instance of DIBasicType, DICompositeType, DIDerivedType, DISubroutineType that type is cloned and replaceAnnotations() method is used to copy annotations from placeholder to clone. Such logic allows to handle types with cyclic references.
- ASTContext::getBTFTagAttributedType() is updated to ensure that BTFTagAttributedType always wraps QualType w/o local constant/volatile/restricted qualifiers.
Some additional example of DWARF generated after this commit follow (unrelated fields like file name and NULL entries are removed for brevity).
Type tag for primitive type
C:
int __attribute__((btf_type_tag("__a"))) a;
DWARF:
0x1e: DW_TAG_variable DW_AT_name ("a") DW_AT_type (0x29 "int") 0x29: DW_TAG_base_type DW_AT_name ("int") 0x2d: DW_TAG_LLVM_annotation DW_AT_name ("btf:type_tag") DW_AT_const_value ("__a")
Type tag for CVR modifier type
C:
volatile int __attribute__((btf_type_tag("__b"))) b;
DWARF:
0x1e: DW_TAG_variable DW_AT_name ("b") DW_AT_type (0x29 "volatile int") 0x29: DW_TAG_volatile_type DW_AT_type (0x2e "int") 0x2e: DW_TAG_base_type DW_AT_name ("int") DW_AT_encoding (DW_ATE_signed) DW_AT_byte_size (0x04) 0x32: DW_TAG_LLVM_annotation DW_AT_name ("btf:type_tag") DW_AT_const_value ("__b")
Type tag for typedef
C:
typedef int foo; foo __attribute__((btf_type_tag("__c"))) c;
DWARF:
0x49: DW_TAG_variable DW_AT_name ("c") DW_AT_type (0x54 "foo") 0x54: DW_TAG_typedef DW_AT_type (0x45 "int") DW_AT_name ("foo") 0x5c: DW_TAG_LLVM_annotation DW_AT_name ("btf:type_tag") DW_AT_const_value ("__c")
Type tag for composite type
C:
struct bar {}; struct bar __attribute__((btf_type_tag("__d"))) d1; struct bar d2;
DWARF (Note two copies of struct bar one with annotations, one without):
0x60: DW_TAG_variable DW_AT_name ("d1") DW_AT_type (0x6b "bar") 0x6b: DW_TAG_structure_type DW_AT_name ("bar") 0x70: DW_TAG_LLVM_annotation DW_AT_name ("btf:type_tag") DW_AT_const_value ("__d") 0x74: DW_TAG_variable DW_AT_name ("d2") DW_AT_type (0x7f "bar") 0x7f: DW_TAG_structure_type DW_AT_name ("bar")
Type tag for composite type with circular reference
C:
struct buz { struct buz __attribute__((btf_type_tag("__buz_self"))) *self; } e;
DWARF (Note two copies of struct buz one with annotations, one without):
0x84: DW_TAG_variable DW_AT_name ("e") DW_AT_type (0x8f "buz") 0x8f: DW_TAG_structure_type DW_AT_name ("buz") 0x94: DW_TAG_member DW_AT_name ("self") DW_AT_type (0x9e "buz *") 0x9e: DW_TAG_pointer_type DW_AT_type (0xa7 "buz") 0xa3: DW_TAG_LLVM_annotation DW_AT_name ("btf_type_tag") DW_AT_const_value ("__buz_self") 0xa7: DW_TAG_structure_type DW_AT_name ("buz") 0xac: DW_TAG_member DW_AT_name ("self") DW_AT_type (0x9e "buz *") 0xb5: DW_TAG_LLVM_annotation DW_AT_name ("btf:type_tag") DW_AT_const_value ("__buz_self")
Type tag for subroutine type
C:
void (__attribute__((btf_type_tag("__f"))) *f)(void);
DWARF:
0x000000b9: DW_TAG_variable DW_AT_name ("f") DW_AT_type (0xc4 "void (*)(") 0x000000c4: DW_TAG_pointer_type DW_AT_type (0xcd "void (") 0x000000c9: DW_TAG_LLVM_annotation DW_AT_name ("btf_type_tag") DW_AT_const_value ("f") 0x000000cd: DW_TAG_subroutine_type DW_AT_prototyped (true) 0x000000ce: DW_TAG_LLVM_annotation DW_AT_name ("btf:type_tag") DW_AT_const_value ("__f")
clang-format not found in user’s local PATH; not linting file.