Skip to content

Commit

Permalink
[Attr] support btf_type_tag attribute
Browse files Browse the repository at this point in the history
This patch added clang codegen and llvm support
for btf_type_tag support. Currently, btf_type_tag
attribute info is preserved in DebugInfo IR only for
pointer types associated with typedef, global variable
and function declaration. Eventually, such information
is emitted to dwarf.

The following is an example:
  $ cat test.c
  #define __tag __attribute__((btf_type_tag("tag")))
  int __tag *g;
  $ clang -O2 -g -c test.c
  $ llvm-dwarfdump --debug-info test.o
  ...
  0x0000001e:   DW_TAG_variable
                  DW_AT_name      ("g")
                  DW_AT_type      (0x00000033 "int *")
                  DW_AT_external  (true)
                  DW_AT_decl_file ("/home/yhs/test.c")
                  DW_AT_decl_line (2)
                  DW_AT_location  (DW_OP_addr 0x0)

  0x00000033:   DW_TAG_pointer_type
                  DW_AT_type      (0x00000042 "int")

  0x00000038:     DW_TAG_LLVM_annotation
                    DW_AT_name    ("btf_type_tag")
                    DW_AT_const_value     ("tag")

  0x00000041:     NULL

  0x00000042:   DW_TAG_base_type
                  DW_AT_name      ("int")
                  DW_AT_encoding  (DW_ATE_signed)
                  DW_AT_byte_size (0x04)

  0x00000049:   NULL

Basically, a DW_TAG_LLVM_annotation tag will be inserted
under DW_TAG_pointer_type tag if that pointer has a btf_type_tag
associated with it.

Differential Revision: https://reviews.llvm.org/D111199
  • Loading branch information
yonghong-song committed Nov 4, 2021
1 parent 453fdeb commit 737e421
Show file tree
Hide file tree
Showing 9 changed files with 361 additions and 55 deletions.
185 changes: 150 additions & 35 deletions clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -929,8 +929,28 @@ static llvm::dwarf::Tag getNextQualifier(Qualifiers &Q) {
return (llvm::dwarf::Tag)0;
}

llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty,
llvm::DIFile *Unit) {
// Strip MacroQualifiedTypeLoc and AttributedTypeLoc
// as their corresponding types will be ignored
// during code generation. Stripping them allows
// to maintain proper TypeLoc for a given type
// during code generation.
static TypeLoc StripMacroAttributed(TypeLoc TL) {
if (!TL)
return TL;

while (true) {
if (auto MTL = TL.getAs<MacroQualifiedTypeLoc>())
TL = MTL.getInnerLoc();
else if (auto ATL = TL.getAs<AttributedTypeLoc>())
TL = ATL.getModifiedLoc();
else
break;
}
return TL;
}

llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile *Unit,
TypeLoc TL) {
QualifierCollector Qc;
const Type *T = Qc.strip(Ty);

Expand All @@ -944,7 +964,15 @@ llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty,
return getOrCreateType(QualType(T, 0), Unit);
}

auto *FromTy = getOrCreateType(Qc.apply(CGM.getContext(), T), Unit);
QualType NextTy = Qc.apply(CGM.getContext(), T);
TypeLoc NextTL;
if (NextTy.hasQualifiers())
NextTL = TL;
else if (TL) {
if (auto QTL = TL.getAs<QualifiedTypeLoc>())
NextTL = StripMacroAttributed(QTL.getNextTypeLoc());
}
auto *FromTy = getOrCreateType(NextTy, Unit, NextTL);

// No need to fill in the Name, Line, Size, Alignment, Offset in case of
// CVR derived types.
Expand Down Expand Up @@ -988,10 +1016,10 @@ llvm::DIType *CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty,
Ty->getPointeeType(), Unit);
}

llvm::DIType *CGDebugInfo::CreateType(const PointerType *Ty,
llvm::DIFile *Unit) {
llvm::DIType *CGDebugInfo::CreateType(const PointerType *Ty, llvm::DIFile *Unit,
TypeLoc TL) {
return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
Ty->getPointeeType(), Unit);
Ty->getPointeeType(), Unit, TL);
}

/// \return whether a C++ mangling exists for the type defined by TD.
Expand Down Expand Up @@ -1132,7 +1160,8 @@ CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty,
llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag,
const Type *Ty,
QualType PointeeTy,
llvm::DIFile *Unit) {
llvm::DIFile *Unit,
TypeLoc TL) {
// Bit size, align and offset of the type.
// Size is always the size of a pointer. We can't use getTypeSize here
// because that does not return the correct value for references.
Expand All @@ -1142,13 +1171,52 @@ llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag,
Optional<unsigned> DWARFAddressSpace =
CGM.getTarget().getDWARFAddressSpace(AddressSpace);

llvm::DINodeArray Annotations = nullptr;
TypeLoc NextTL;
if (TL) {
SmallVector<llvm::Metadata *, 4> Annots;
NextTL = TL.getNextTypeLoc();
if (NextTL) {
// Traverse all MacroQualifiedTypeLoc, QualifiedTypeLoc and
// AttributedTypeLoc type locations so we can collect
// BTFTypeTag attributes for this pointer.
while (true) {
if (auto MTL = NextTL.getAs<MacroQualifiedTypeLoc>()) {
NextTL = MTL.getInnerLoc();
} else if (auto QTL = NextTL.getAs<QualifiedTypeLoc>()) {
NextTL = QTL.getNextTypeLoc();
} else if (auto ATL = NextTL.getAs<AttributedTypeLoc>()) {
if (const auto *A = ATL.getAttrAs<BTFTypeTagAttr>()) {
StringRef BTFTypeTag = A->getBTFTypeTag();
if (!BTFTypeTag.empty()) {
llvm::Metadata *Ops[2] = {
llvm::MDString::get(CGM.getLLVMContext(),
StringRef("btf_type_tag")),
llvm::MDString::get(CGM.getLLVMContext(), BTFTypeTag)};
Annots.insert(Annots.begin(),
llvm::MDNode::get(CGM.getLLVMContext(), Ops));
}
}
NextTL = ATL.getModifiedLoc();
} else {
break;
}
}
}

NextTL = StripMacroAttributed(TL.getNextTypeLoc());
if (Annots.size() > 0)
Annotations = DBuilder.getOrCreateArray(Annots);
}

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);
return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit, NextTL),
Size, Align, DWARFAddressSpace,
StringRef(), Annotations);
}

llvm::DIType *CGDebugInfo::getOrCreateStructPtrType(StringRef Name,
Expand Down Expand Up @@ -1265,8 +1333,11 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,

llvm::DIType *CGDebugInfo::CreateType(const TypedefType *Ty,
llvm::DIFile *Unit) {
TypeLoc TL;
if (const TypeSourceInfo *TSI = Ty->getDecl()->getTypeSourceInfo())
TL = TSI->getTypeLoc();
llvm::DIType *Underlying =
getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit);
getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit, TL);

if (Ty->getDecl()->hasAttr<NoDebugAttr>())
return Underlying;
Expand Down Expand Up @@ -1340,7 +1411,7 @@ static llvm::DINode::DIFlags getRefFlags(const FunctionProtoType *Func) {
}

llvm::DIType *CGDebugInfo::CreateType(const FunctionType *Ty,
llvm::DIFile *Unit) {
llvm::DIFile *Unit, TypeLoc TL) {
const auto *FPT = dyn_cast<FunctionProtoType>(Ty);
if (FPT) {
if (llvm::DIType *QTy = CreateQualifiedType(FPT, Unit))
Expand All @@ -1352,17 +1423,41 @@ llvm::DIType *CGDebugInfo::CreateType(const FunctionType *Ty,
SmallVector<llvm::Metadata *, 16> EltTys;

// Add the result type at least.
EltTys.push_back(getOrCreateType(Ty->getReturnType(), Unit));
TypeLoc RetTL;
if (TL) {
if (auto FTL = TL.getAs<FunctionTypeLoc>())
RetTL = FTL.getReturnLoc();
}
EltTys.push_back(getOrCreateType(Ty->getReturnType(), Unit, RetTL));

llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
// Set up remainder of arguments if there is a prototype.
// otherwise emit it as a variadic function.
if (!FPT)
if (!FPT) {
EltTys.push_back(DBuilder.createUnspecifiedParameter());
else {
} else {
Flags = getRefFlags(FPT);
for (const QualType &ParamType : FPT->param_types())
EltTys.push_back(getOrCreateType(ParamType, Unit));
bool DoneWithTL = false;
if (TL) {
if (auto FTL = TL.getAs<FunctionTypeLoc>()) {
DoneWithTL = true;
int Idx = 0;
for (const QualType &ParamType : FPT->param_types()) {
TypeLoc ParamTL;
if (ParmVarDecl *Param = FTL.getParam(Idx)) {
if (const TypeSourceInfo *TSI = Param->getTypeSourceInfo())
ParamTL = TSI->getTypeLoc();
}
EltTys.push_back(getOrCreateType(ParamType, Unit, ParamTL));
Idx++;
}
}
}

if (!DoneWithTL) {
for (const QualType &ParamType : FPT->param_types())
EltTys.push_back(getOrCreateType(ParamType, Unit));
}
if (FPT->isVariadic())
EltTys.push_back(DBuilder.createUnspecifiedParameter());
}
Expand Down Expand Up @@ -1433,11 +1528,13 @@ llvm::DIType *CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl,
Flags, DebugType, Annotations);
}

llvm::DIType *CGDebugInfo::createFieldType(
StringRef name, QualType type, SourceLocation loc, AccessSpecifier AS,
uint64_t offsetInBits, uint32_t AlignInBits, llvm::DIFile *tunit,
llvm::DIScope *scope, const RecordDecl *RD, llvm::DINodeArray Annotations) {
llvm::DIType *debugType = getOrCreateType(type, tunit);
llvm::DIType *
CGDebugInfo::createFieldType(StringRef name, QualType type, SourceLocation loc,
AccessSpecifier AS, uint64_t offsetInBits,
uint32_t AlignInBits, llvm::DIFile *tunit,
llvm::DIScope *scope, const RecordDecl *RD,
llvm::DINodeArray Annotations, TypeLoc TL) {
llvm::DIType *debugType = getOrCreateType(type, tunit, TL);

// Get the location for the field.
llvm::DIFile *file = getOrCreateFile(loc);
Expand Down Expand Up @@ -1545,9 +1642,12 @@ void CGDebugInfo::CollectRecordNormalField(
} else {
auto Align = getDeclAlignIfRequired(field, CGM.getContext());
llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(field);
FieldType =
createFieldType(name, type, field->getLocation(), field->getAccess(),
OffsetInBits, Align, tunit, RecordTy, RD, Annotations);
TypeLoc TL;
if (const TypeSourceInfo *TSI = field->getTypeSourceInfo())
TL = TSI->getTypeLoc();
FieldType = createFieldType(name, type, field->getLocation(),
field->getAccess(), OffsetInBits, Align, tunit,
RecordTy, RD, Annotations, TL);
}

elements.push_back(FieldType);
Expand Down Expand Up @@ -3305,7 +3405,8 @@ void CGDebugInfo::completeUnusedClass(const CXXRecordDecl &D) {
RetainedTypes.push_back(CGM.getContext().getRecordType(&D).getAsOpaquePtr());
}

llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) {
llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit,
TypeLoc TL) {
if (Ty.isNull())
return nullptr;

Expand All @@ -3322,7 +3423,7 @@ llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) {
if (auto *T = getTypeOrNull(Ty))
return T;

llvm::DIType *Res = CreateTypeNode(Ty, Unit);
llvm::DIType *Res = CreateTypeNode(Ty, Unit, TL);
void *TyPtr = Ty.getAsOpaquePtr();

// And update the type cache.
Expand Down Expand Up @@ -3366,10 +3467,11 @@ llvm::DIModule *CGDebugInfo::getParentModuleOrNull(const Decl *D) {
return nullptr;
}

llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) {
llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit,
TypeLoc TL) {
// Handle qualifiers, which recursively handles what they refer to.
if (Ty.hasLocalQualifiers())
return CreateQualifiedType(Ty, Unit);
return CreateQualifiedType(Ty, Unit, TL);

// Work out details of type.
switch (Ty->getTypeClass()) {
Expand Down Expand Up @@ -3398,7 +3500,7 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) {
case Type::Complex:
return CreateType(cast<ComplexType>(Ty));
case Type::Pointer:
return CreateType(cast<PointerType>(Ty), Unit);
return CreateType(cast<PointerType>(Ty), Unit, TL);
case Type::BlockPointer:
return CreateType(cast<BlockPointerType>(Ty), Unit);
case Type::Typedef:
Expand All @@ -3409,7 +3511,7 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) {
return CreateEnumType(cast<EnumType>(Ty));
case Type::FunctionProto:
case Type::FunctionNoProto:
return CreateType(cast<FunctionType>(Ty), Unit);
return CreateType(cast<FunctionType>(Ty), Unit, TL);
case Type::ConstantArray:
case Type::VariableArray:
case Type::IncompleteArray:
Expand Down Expand Up @@ -3954,7 +4056,12 @@ llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D,
getDwarfCC(CC));
}

return cast<llvm::DISubroutineType>(getOrCreateType(FnType, F));
TypeLoc TL;
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
if (const TypeSourceInfo *TSI = FD->getTypeSourceInfo())
TL = TSI->getTypeLoc();
}
return cast<llvm::DISubroutineType>(getOrCreateType(FnType, F, TL));
}

QualType
Expand Down Expand Up @@ -4356,8 +4463,12 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD,
uint64_t XOffset = 0;
if (VD->hasAttr<BlocksAttr>())
Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset).WrappedType;
else
Ty = getOrCreateType(VD->getType(), Unit);
else {
TypeLoc TL;
if (const TypeSourceInfo *TSI = VD->getTypeSourceInfo())
TL = TSI->getTypeLoc();
Ty = getOrCreateType(VD->getType(), Unit, TL);
}

// If there is no debug info for this type then do not emit debug info
// for this variable.
Expand Down Expand Up @@ -5081,10 +5192,14 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
}
AppendAddressSpaceXDeref(AddressSpace, Expr);

TypeLoc TL;
if (const TypeSourceInfo *TSI = D->getTypeSourceInfo())
TL = TSI->getTypeLoc();

llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(D);
GVE = DBuilder.createGlobalVariableExpression(
DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit),
Var->hasLocalLinkage(), true,
DContext, DeclName, LinkageName, Unit, LineNo,
getOrCreateType(T, Unit, TL), Var->hasLocalLinkage(), true,
Expr.empty() ? nullptr : DBuilder.createExpression(Expr),
getOrCreateStaticDataMemberDeclarationOrNull(D), TemplateParameters,
Align, Annotations);
Expand Down
21 changes: 14 additions & 7 deletions clang/lib/CodeGen/CGDebugInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,16 +178,19 @@ class CGDebugInfo {
llvm::DIType *CreateType(const ComplexType *Ty);
llvm::DIType *CreateType(const AutoType *Ty);
llvm::DIType *CreateType(const ExtIntType *Ty);
llvm::DIType *CreateQualifiedType(QualType Ty, llvm::DIFile *Fg);
llvm::DIType *CreateQualifiedType(QualType Ty, llvm::DIFile *Fg,
TypeLoc TL = TypeLoc());
llvm::DIType *CreateQualifiedType(const FunctionProtoType *Ty,
llvm::DIFile *Fg);
llvm::DIType *CreateType(const TypedefType *Ty, llvm::DIFile *Fg);
llvm::DIType *CreateType(const TemplateSpecializationType *Ty,
llvm::DIFile *Fg);
llvm::DIType *CreateType(const ObjCObjectPointerType *Ty, llvm::DIFile *F);
llvm::DIType *CreateType(const PointerType *Ty, llvm::DIFile *F);
llvm::DIType *CreateType(const PointerType *Ty, llvm::DIFile *F,
TypeLoc TL = TypeLoc());
llvm::DIType *CreateType(const BlockPointerType *Ty, llvm::DIFile *F);
llvm::DIType *CreateType(const FunctionType *Ty, llvm::DIFile *F);
llvm::DIType *CreateType(const FunctionType *Ty, llvm::DIFile *F,
TypeLoc TL = TypeLoc());
/// Get structure or union type.
llvm::DIType *CreateType(const RecordType *Tyg);
llvm::DIType *CreateTypeDefinition(const RecordType *Ty);
Expand Down Expand Up @@ -242,7 +245,8 @@ class CGDebugInfo {
/// \return namespace descriptor for the given namespace decl.
llvm::DINamespace *getOrCreateNamespace(const NamespaceDecl *N);
llvm::DIType *CreatePointerLikeType(llvm::dwarf::Tag Tag, const Type *Ty,
QualType PointeeTy, llvm::DIFile *F);
QualType PointeeTy, llvm::DIFile *F,
TypeLoc TL = TypeLoc());
llvm::DIType *getOrCreateStructPtrType(StringRef Name, llvm::DIType *&Cache);

/// A helper function to create a subprogram for a single member
Expand Down Expand Up @@ -308,7 +312,8 @@ class CGDebugInfo {
uint64_t offsetInBits, uint32_t AlignInBits,
llvm::DIFile *tunit, llvm::DIScope *scope,
const RecordDecl *RD = nullptr,
llvm::DINodeArray Annotations = nullptr);
llvm::DINodeArray Annotations = nullptr,
TypeLoc TL = TypeLoc());

llvm::DIType *createFieldType(StringRef name, QualType type,
SourceLocation loc, AccessSpecifier AS,
Expand Down Expand Up @@ -628,7 +633,8 @@ class CGDebugInfo {
Optional<StringRef> Source);

/// Get the type from the cache or create a new type if necessary.
llvm::DIType *getOrCreateType(QualType Ty, llvm::DIFile *Fg);
llvm::DIType *getOrCreateType(QualType Ty, llvm::DIFile *Fg,
TypeLoc TL = TypeLoc());

/// Get a reference to a clang module. If \p CreateSkeletonCU is true,
/// this also creates a split dwarf skeleton compile unit.
Expand All @@ -643,7 +649,8 @@ class CGDebugInfo {
llvm::DICompositeType *getOrCreateLimitedType(const RecordType *Ty);

/// Create type metadata for a source language type.
llvm::DIType *CreateTypeNode(QualType Ty, llvm::DIFile *Fg);
llvm::DIType *CreateTypeNode(QualType Ty, llvm::DIFile *Fg,
TypeLoc TL = TypeLoc());

/// Create new member and increase Offset by FType's size.
llvm::DIType *CreateMemberType(llvm::DIFile *Unit, QualType FType,
Expand Down
Loading

0 comments on commit 737e421

Please sign in to comment.