Skip to content

[BPF] Generate BTF info using 'btf:type_tag' annotation #91424

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 180 additions & 24 deletions clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@
using namespace clang;
using namespace clang::CodeGen;

// Temporarily hide new format for btf_type_tags / DW_TAG_LLVM_annotation
// behind an option to allow transitory period for tooling dependent on
// this annotation. The goal is to remove this flag after transitory period.
static llvm::cl::opt<bool> BTFTypeTagV2(
"btf-type-tag-v2", llvm::cl::Hidden,
llvm::cl::desc("For __attribute__((btf_type_tag(...))) generate "
"DW_TAG_LLVM_annotation tags with DW_AT_name 'btf:type_tag' "
"attached to annotated type itself"),
llvm::cl::init(false));

static uint32_t getTypeAlignIfRequired(const Type *Ty, const ASTContext &Ctx) {
auto TI = Ctx.getTypeInfo(Ty);
if (TI.isAlignRequired())
Expand Down Expand Up @@ -1194,6 +1204,129 @@ CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty,
return RetTy;
}

static QualType collectBTFTypeTagAnnotations(
llvm::LLVMContext &Context, llvm::DIBuilder &DBuilder,
llvm::SmallVectorImpl<llvm::Metadata *> &Annots,
const BTFTagAttributedType *BTFAttrTy, const char *TagName) {
QualType WrappedTy;

do {
StringRef TagValue = BTFAttrTy->getAttr()->getBTFTypeTag();
if (!TagValue.empty()) {
llvm::Metadata *Ops[] = {
llvm::MDString::get(Context, TagName),
llvm::MDString::get(Context, TagValue),
};
Annots.insert(Annots.begin(), llvm::MDNode::get(Context, Ops));
}
WrappedTy = BTFAttrTy->getWrappedType();
BTFAttrTy = dyn_cast<BTFTagAttributedType>(WrappedTy);
} while (BTFAttrTy);

return WrappedTy;
}

static bool retreiveCVR(llvm::DIDerivedType *DTy, QualifierCollector &Qc) {
switch (DTy->getTag()) {
case llvm::dwarf::DW_TAG_const_type:
Qc.addConst();
return true;
case llvm::dwarf::DW_TAG_volatile_type:
Qc.addVolatile();
return true;
case llvm::dwarf::DW_TAG_restrict_type:
Qc.addRestrict();
return true;
default:
return false;
}
}

// Tags returned by QualifierCollector::getNextQualifier() should be
// applied in the reverse order, thus use recursive function.
static llvm::DIType *applyQualifiers(llvm::DIBuilder &DBuilder,
llvm::DIType *Ty, QualifierCollector &Qc) {
llvm::dwarf::Tag Tag = getNextQualifier(Qc);
if (!Tag)
return Ty;
Ty = applyQualifiers(DBuilder, Ty, Qc);
return DBuilder.createQualifiedType(Tag, Ty);
}

static bool isAnnotationsPlaceholder(llvm::DIDerivedType *DTy) {
return DTy->isTemporary() &&
DTy->getTag() == llvm::dwarf::DW_TAG_LLVM_annotation;
}

llvm::DIType *CGDebugInfo::CreateType(const BTFTagAttributedType *Ty,
llvm::DIFile *Unit) {
SmallVector<llvm::Metadata *, 4> Annotations;
auto WrappedTy = collectBTFTypeTagAnnotations(
CGM.getLLVMContext(), DBuilder, Annotations, Ty, "btf:type_tag");

if (!BTFTypeTagV2 || Annotations.empty())
return getOrCreateType(WrappedTy, Unit);

// After discussion with GCC BPF team in [1] it was decided to avoid
// attaching BTF type tags to const/volatile/restrict DWARF DIEs.
// So, strip qualifiers from WrappedTy and apply those to a final
// annotations placeholder instance at the end of this function.
//
// [1] https://reviews.llvm.org/D143967
QualifierCollector Qc;
Qc.addCVRQualifiers(WrappedTy.getLocalCVRQualifiers());
WrappedTy.removeLocalFastQualifiers(Qualifiers::CVRMask);

llvm::DIType *WrappedDI = getOrCreateType(WrappedTy, Unit);
if (!WrappedDI)
WrappedDI = DBuilder.createUnspecifiedType("void");

// Stripping local CVR qualifiers might not be enough in cases like this:
//
// #define __tag __attribute__((btf_type_tag("tag")))
// const int *foo;
// const int *bar(void) {
// return (typeof(*foo) __tag *)(0);
// }
//
// Here the AST looks like:
//
// BTFTagAttributedType
// | 'typeof (*foo) __attribute__((btf_type_tag("tag")))' sugar
// `-TypeOfExprType 'typeof (*foo)' sugar
// |-ParenExpr 'const int' lvalue
// | `- ...
// `-QualType 'const int' const
// `-BuiltinType 'int'
//
// The BTFTagAttributedType is applied to TypeOfExpr.
// For TypeOfExpr the getOrCreateType(), would return instance of
// DIDerivedType with tag DW_TAG_const_type.
//
// To avoid repeating UnwrapTypeForDebugInfo() logic here just
// rebuild CVR metadata nodes if necessary.
// The above local CVR qualifiers processing is redundant,
// but avoids rebuilding metadata nodes in the most common case.
while (auto *DTy = dyn_cast<llvm::DIDerivedType>(WrappedDI)) {
if (!retreiveCVR(DTy, Qc))
break;
WrappedDI = DTy->getBaseType();
}

if (auto *DTy = dyn_cast<llvm::DIDerivedType>(WrappedDI))
if (isAnnotationsPlaceholder(DTy)) {
WrappedDI = DTy->getBaseType();
for (llvm::Metadata *O : DTy->getAnnotations()->operands())
Annotations.push_back(O);
}

auto *Placeholder = DBuilder.createAnnotationsPlaceholder(
WrappedDI, DBuilder.getOrCreateArray(Annotations));
AnnotationPlaceholders.push_back(Placeholder);

return applyQualifiers(DBuilder, Placeholder, Qc);
}

llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag,
const Type *Ty,
QualType PointeeTy,
Expand All @@ -1206,32 +1339,23 @@ llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag,
CGM.getTarget().getDWARFAddressSpace(
CGM.getTypes().getTargetAddressSpace(PointeeTy));

SmallVector<llvm::Metadata *, 4> Annots;
auto *BTFAttrTy = dyn_cast<BTFTagAttributedType>(PointeeTy);
while (BTFAttrTy) {
StringRef Tag = BTFAttrTy->getAttr()->getBTFTypeTag();
if (!Tag.empty()) {
llvm::Metadata *Ops[2] = {
llvm::MDString::get(CGM.getLLVMContext(), StringRef("btf_type_tag")),
llvm::MDString::get(CGM.getLLVMContext(), Tag)};
Annots.insert(Annots.begin(),
llvm::MDNode::get(CGM.getLLVMContext(), Ops));
}
BTFAttrTy = dyn_cast<BTFTagAttributedType>(BTFAttrTy->getWrappedType());
}

llvm::DINodeArray Annotations = nullptr;
if (Annots.size() > 0)
Annotations = DBuilder.getOrCreateArray(Annots);
auto *BTFAttrTy = dyn_cast<BTFTagAttributedType>(PointeeTy.getTypePtr());
if (!BTFTypeTagV2 && BTFAttrTy) {
SmallVector<llvm::Metadata *, 4> AnnotationsVec;
collectBTFTypeTagAnnotations(CGM.getLLVMContext(), DBuilder, AnnotationsVec,
BTFAttrTy, "btf_type_tag");
Annotations = DBuilder.getOrCreateArray(AnnotationsVec);
}

if (Tag == llvm::dwarf::DW_TAG_reference_type ||
Tag == llvm::dwarf::DW_TAG_rvalue_reference_type)
return DBuilder.createReferenceType(Tag, getOrCreateType(PointeeTy, Unit),
Size, Align, DWARFAddressSpace);
else
return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit), Size,
Align, DWARFAddressSpace, StringRef(),
Annotations);

return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit), Size,
Align, DWARFAddressSpace, StringRef(),
Annotations);
}

llvm::DIType *CGDebugInfo::getOrCreateStructPtrType(StringRef Name,
Expand Down Expand Up @@ -3552,9 +3676,6 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
case Type::Attributed:
T = cast<AttributedType>(T)->getEquivalentType();
break;
case Type::BTFTagAttributed:
T = cast<BTFTagAttributedType>(T)->getWrappedType();
break;
case Type::CountAttributed:
T = cast<CountAttributedType>(T)->desugar();
break;
Expand Down Expand Up @@ -3754,10 +3875,12 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) {
case Type::TemplateSpecialization:
return CreateType(cast<TemplateSpecializationType>(Ty), Unit);

case Type::BTFTagAttributed:
return CreateType(cast<BTFTagAttributedType>(Ty), Unit);

case Type::CountAttributed:
case Type::Auto:
case Type::Attributed:
case Type::BTFTagAttributed:
case Type::Adjusted:
case Type::Decayed:
case Type::DeducedTemplateSpecialization:
Expand Down Expand Up @@ -5930,6 +6053,35 @@ void CGDebugInfo::setDwoId(uint64_t Signature) {
TheCU->setDWOId(Signature);
}

static llvm::DIType *copyAnnotations(llvm::DIBuilder &DBuilder,
llvm::DIDerivedType *Placeholder) {
auto *WrappedDI = Placeholder->getBaseType();
SmallVector<llvm::Metadata *, 4> Annotations;

for (const llvm::Metadata *O : Placeholder->getAnnotations()->operands())
Annotations.push_back(const_cast<llvm::Metadata *>(O));

auto AddAnnotations = [&](auto *Type) {
if (llvm::DINodeArray OldAnnotations = Type->getAnnotations())
for (const llvm::Metadata *O : OldAnnotations->operands())
Annotations.push_back(const_cast<llvm::Metadata *>(O));
auto Clone = Type->clone();
Clone->replaceAnnotations(DBuilder.getOrCreateArray(Annotations));
return llvm::MDNode::replaceWithPermanent(std::move(Clone));
};

if (auto *Ty = dyn_cast<llvm::DIBasicType>(WrappedDI))
return AddAnnotations(Ty);
if (auto *Ty = dyn_cast<llvm::DICompositeType>(WrappedDI))
return AddAnnotations(Ty);
if (auto *Ty = dyn_cast<llvm::DIDerivedType>(WrappedDI))
return AddAnnotations(Ty);
if (auto *Ty = dyn_cast<llvm::DISubroutineType>(WrappedDI))
return AddAnnotations(Ty);

return WrappedDI;
}

void CGDebugInfo::finalize() {
// Creating types might create further types - invalidating the current
// element and the size(), so don't cache/reference them.
Expand Down Expand Up @@ -6003,6 +6155,10 @@ void CGDebugInfo::finalize() {
if (auto MD = TypeCache[RT])
DBuilder.retainType(cast<llvm::DIType>(MD));

for (auto &Placeholder : AnnotationPlaceholders)
DBuilder.replaceTemporary(llvm::TempDIType(Placeholder),
copyAnnotations(DBuilder, Placeholder));

DBuilder.finalize();
}

Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CGDebugInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ class CGDebugInfo {
/// The key is coroutine real parameters, value is DIVariable in LLVM IR.
Param2DILocTy ParamDbgMappings;

std::vector<llvm::DIDerivedType *> AnnotationPlaceholders;

/// Helper functions for getOrCreateType.
/// @{
/// Currently the checksum of an interface includes the number of
Expand Down Expand Up @@ -218,6 +220,7 @@ class CGDebugInfo {
llvm::DIType *CreateType(const MemberPointerType *Ty, llvm::DIFile *F);
llvm::DIType *CreateType(const AtomicType *Ty, llvm::DIFile *F);
llvm::DIType *CreateType(const PipeType *Ty, llvm::DIFile *F);
llvm::DIType *CreateType(const BTFTagAttributedType *Ty, llvm::DIFile *F);
/// Get enumeration type.
llvm::DIType *CreateEnumType(const EnumType *Ty);
llvm::DIType *CreateTypeDefinition(const EnumType *Ty);
Expand Down
18 changes: 18 additions & 0 deletions clang/test/CodeGen/attr-btf_type_tag-circular.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// RUN: %clang_cc1 \
// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \
// RUN: -mllvm -btf-type-tag-v2 -emit-llvm -o - %s | FileCheck %s

#define __tag1 __attribute__((btf_type_tag("tag1")))

struct st {
struct st __tag1 *self;
} g;

// CHECK: distinct !DIGlobalVariable(name: "g", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[L1:[0-9]+]], isLocal: false, isDefinition: true)
// CHECK: ![[L1]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "st", file: ![[#]], line: [[#]], size: [[#]], elements: ![[L2:[0-9]+]])
// CHECK: ![[L2]] = !{![[L3:[0-9]+]]}
// CHECK: ![[L3]] = !DIDerivedType(tag: DW_TAG_member, name: "self", scope: ![[L1]], file: ![[#]], line: [[#]], baseType: ![[L4:[0-9]+]], size: [[#]])
// CHECK: ![[L4]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L5:[0-9]+]], size: [[#]])
// CHECK: ![[L5]] = !DICompositeType(tag: DW_TAG_structure_type, name: "st", file: ![[#]], line: [[#]], size: [[#]], elements: ![[L2]], annotations: ![[L7:[0-9]+]])
// CHECK: ![[L7]] = !{![[L8:[0-9]+]]}
// CHECK: ![[L8]] = !{!"btf:type_tag", !"tag1"}
41 changes: 41 additions & 0 deletions clang/test/CodeGen/attr-btf_type_tag-const.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// RUN: %clang_cc1 \
// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \
// RUN: -mllvm -btf-type-tag-v2 -emit-llvm -o - %s | FileCheck %s

// Check that BTF type tags are not attached to DW_TAG_const_type DIEs
// in presence of "sugar" expressions that are transparent for
// CGDebugInfo.cpp:UnwrapTypeForDebugInfo(), but are not transparent
// for local qualifiers.
//
// For details see:
// CGDebugInfo::CreateType(const BTFTagAttributedType, llvm::DIFile)

#define __tag1 __attribute__((btf_type_tag("tag1")))
#define __tag2 __attribute__((btf_type_tag("tag2")))
#define __tag3 __attribute__((btf_type_tag("tag3")))

const int *foo;
typeof(*foo) __tag1 bar;

// CHECK: distinct !DIGlobalVariable(name: "bar", {{.*}}, type: ![[L01:[0-9]+]], {{.*}})
// CHECK: ![[L01]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[L02:[0-9]+]])
// CHECK: ![[L02]] = !DIBasicType(name: "int", {{.*}}, annotations: ![[L03:[0-9]+]])
// CHECK: ![[L03]] = !{![[L04:[0-9]+]]}
// CHECK: ![[L04]] = !{!"btf:type_tag", !"tag1"}

const int __tag2 *buz;

// CHECK: distinct !DIGlobalVariable(name: "buz", {{.*}}, type: ![[L05:[0-9]+]], {{.*}})
// CHECK: ![[L05]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L06:[0-9]+]], {{.*}})
// CHECK: ![[L06]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[L08:[0-9]+]])
// CHECK: ![[L08]] = !DIBasicType(name: "int", size: [[#]], {{.*}}, annotations: ![[L09:[0-9]+]])
// CHECK: ![[L09]] = !{![[L10:[0-9]+]]}
// CHECK: ![[L10]] = !{!"btf:type_tag", !"tag2"}

typeof(*buz) __tag3 quux;

// CHECK: distinct !DIGlobalVariable(name: "quux", {{.*}}, type: ![[L12:[0-9]+]], {{.*}})
// CHECK: ![[L12]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[L13:[0-9]+]])
// CHECK: ![[L13]] = !DIBasicType(name: "int", {{.*}}, annotations: ![[L14:[0-9]+]])
// CHECK: ![[L14]] = !{![[L15:[0-9]+]], ![[L10]]}
// CHECK: ![[L15]] = !{!"btf:type_tag", !"tag3"}
19 changes: 14 additions & 5 deletions clang/test/CodeGen/attr-btf_type_tag-func-ptr.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
// RUN: %clang_cc1 -triple %itanium_abi_triple -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 \
// RUN: -triple %itanium_abi_triple -debug-info-kind=limited \
// RUN: -mllvm -btf-type-tag-v2 -emit-llvm -o - %s \
// RUN: | FileCheck --check-prefix CHECK-V2 %s

struct t {
int (__attribute__((btf_type_tag("rcu"))) *f)();
Expand All @@ -8,8 +12,13 @@ int foo(struct t *arg) {
return arg->a;
}

// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "f"
// CHECK-SAME: baseType: ![[L18:[0-9]+]]
// CHECK: ![[L18]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[#]], size: [[#]], annotations: ![[L21:[0-9]+]])
// CHECK: ![[L21]] = !{![[L22:[0-9]+]]}
// CHECK: ![[L22]] = !{!"btf_type_tag", !"rcu"}
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "f", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[L1:[0-9]+]], size: [[#]])
// CHECK: ![[L1]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[#]], size: [[#]], annotations: ![[L2:[0-9]+]])
// CHECK: ![[L2]] = !{![[L3:[0-9]+]]}
// CHECK: ![[L3]] = !{!"btf_type_tag", !"rcu"}

// CHECK-V2: !DIDerivedType(tag: DW_TAG_member, name: "f", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[L1:[0-9]+]], size: [[#]])
// CHECK-V2: ![[L1]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L2:[0-9]+]], size: [[#]])
// CHECK-V2: ![[L2]] = !DISubroutineType(types: ![[#]], annotations: ![[L4:[0-9]+]])
// CHECK-V2: ![[L4]] = !{![[L5:[0-9]+]]}
// CHECK-V2: ![[L5]] = !{!"btf:type_tag", !"rcu"}
Loading
Loading