Skip to content

Commit

Permalink
[BPF] support btf_tag attribute in .BTF section
Browse files Browse the repository at this point in the history
A new kind BTF_KIND_TAG is added to .BTF to encode
btf_tag attributes. The format looks like
   CommonType.name : attribute string
   CommonType.type : attached to a struct/union/func/var.
   CommonType.info : encoding BTF_KIND_TAG
                     kflag == 1 to indicate the attribute is
                     for CommonType.type, or kflag == 0
                     for struct/union member or func argument.
   one uint32_t    : to encode which member/argument starting from 0.

If one particular type or member/argument has more than one attribute,
multiple BTF_KIND_TAG will be generated.

Differential Revision: https://reviews.llvm.org/D106622
  • Loading branch information
yonghong-song committed Aug 29, 2021
1 parent ca5f05d commit 4948927
Show file tree
Hide file tree
Showing 6 changed files with 304 additions and 6 deletions.
1 change: 1 addition & 0 deletions llvm/lib/Target/BPF/BTF.def
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ HANDLE_BTF_KIND(13, FUNC_PROTO)
HANDLE_BTF_KIND(14, VAR)
HANDLE_BTF_KIND(15, DATASEC)
HANDLE_BTF_KIND(16, FLOAT)
HANDLE_BTF_KIND(17, TAG)

#undef HANDLE_BTF_KIND
4 changes: 2 additions & 2 deletions llvm/lib/Target/BPF/BTF.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,14 @@ struct CommonType {
/// Bits 24-27: kind (e.g. int, ptr, array...etc)
/// Bits 28-30: unused
/// Bit 31: kind_flag, currently used by
/// struct, union and fwd
/// struct, union, fwd and tag
uint32_t Info;

/// "Size" is used by INT, ENUM, STRUCT and UNION.
/// "Size" tells the size of the type it is describing.
///
/// "Type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
/// FUNC, FUNC_PROTO and VAR.
/// FUNC, FUNC_PROTO, VAR and TAG.
/// "Type" is a type_id referring to another type.
union {
uint32_t Size;
Expand Down
73 changes: 69 additions & 4 deletions llvm/lib/Target/BPF/BTFDebug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,27 @@ void BTFTypeFloat::completeType(BTFDebug &BDebug) {
BTFType.NameOff = BDebug.addString(Name);
}

BTFTypeTag::BTFTypeTag(uint32_t BaseTypeId, int ComponentId, StringRef Tag)
: Tag(Tag) {
Kind = BTF::BTF_KIND_TAG;
BTFType.Info = ((ComponentId < 0) << 31) | (Kind << 24);
BTFType.Type = BaseTypeId;
Info = ComponentId < 0 ? 0 : ComponentId;
}

void BTFTypeTag::completeType(BTFDebug &BDebug) {
if (IsCompleted)
return;
IsCompleted = true;

BTFType.NameOff = BDebug.addString(Tag);
}

void BTFTypeTag::emitType(MCStreamer &OS) {
BTFTypeBase::emitType(OS);
OS.emitInt32(Info);
}

uint32_t BTFStringTable::addString(StringRef S) {
// Check whether the string already exists.
for (auto &OffsetM : OffsetToIdMap) {
Expand Down Expand Up @@ -475,6 +496,24 @@ void BTFDebug::visitSubroutineType(
}
}

void BTFDebug::processAnnotations(DINodeArray Annotations, uint32_t BaseTypeId,
int ComponentId) {
if (!Annotations)
return;

for (const Metadata *Annotation : Annotations->operands()) {
const MDNode *MD = cast<MDNode>(Annotation);
const MDString *Name = cast<MDString>(MD->getOperand(0));
if (!Name->getString().equals("btf_tag"))
continue;

const MDString *Value = cast<MDString>(MD->getOperand(1));
auto TypeEntry = std::make_unique<BTFTypeTag>(BaseTypeId, ComponentId,
Value->getString());
addType(std::move(TypeEntry));
}
}

/// Handle structure/union types.
void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct,
uint32_t &TypeId) {
Expand All @@ -498,9 +537,17 @@ void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct,
StructTypes.push_back(TypeEntry.get());
TypeId = addType(std::move(TypeEntry), CTy);

// Check struct/union annotations
processAnnotations(CTy->getAnnotations(), TypeId, -1);

// Visit all struct members.
for (const auto *Element : Elements)
visitTypeEntry(cast<DIDerivedType>(Element));
int FieldNo = 0;
for (const auto *Element : Elements) {
const auto Elem = cast<DIDerivedType>(Element);
visitTypeEntry(Elem);
processAnnotations(Elem->getAnnotations(), TypeId, FieldNo);
FieldNo++;
}
}

void BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) {
Expand Down Expand Up @@ -964,6 +1011,17 @@ void BTFDebug::beginFunctionImpl(const MachineFunction *MF) {
std::make_unique<BTFTypeFunc>(SP->getName(), ProtoTypeId, Scope);
uint32_t FuncTypeId = addType(std::move(FuncTypeEntry));

// Process argument annotations.
for (const DINode *DN : SP->getRetainedNodes()) {
if (const auto *DV = dyn_cast<DILocalVariable>(DN)) {
uint32_t Arg = DV->getArg();
if (Arg)
processAnnotations(DV->getAnnotations(), FuncTypeId, Arg - 1);
}
}

processAnnotations(SP->getAnnotations(), FuncTypeId, -1);

for (const auto &TypeEntry : TypeEntries)
TypeEntry->completeType(*this);

Expand Down Expand Up @@ -1176,11 +1234,13 @@ void BTFDebug::processGlobals(bool ProcessingMapDef) {
continue;

uint32_t GVTypeId = 0;
DIGlobalVariable *DIGlobal = nullptr;
for (auto *GVE : GVs) {
DIGlobal = GVE->getVariable();
if (SecName.startswith(".maps"))
visitMapDefType(GVE->getVariable()->getType(), GVTypeId);
visitMapDefType(DIGlobal->getType(), GVTypeId);
else
visitTypeEntry(GVE->getVariable()->getType(), GVTypeId, false, false);
visitTypeEntry(DIGlobal->getType(), GVTypeId, false, false);
break;
}

Expand Down Expand Up @@ -1212,6 +1272,8 @@ void BTFDebug::processGlobals(bool ProcessingMapDef) {
std::make_unique<BTFKindVar>(Global.getName(), GVTypeId, GVarInfo);
uint32_t VarId = addType(std::move(VarEntry));

processAnnotations(DIGlobal->getAnnotations(), VarId, -1);

// An empty SecName means an extern variable without section attribute.
if (SecName.empty())
continue;
Expand Down Expand Up @@ -1306,6 +1368,9 @@ void BTFDebug::processFuncPrototypes(const Function *F) {
auto FuncTypeEntry =
std::make_unique<BTFTypeFunc>(SP->getName(), ProtoTypeId, Scope);
uint32_t FuncId = addType(std::move(FuncTypeEntry));

processAnnotations(SP->getAnnotations(), FuncId, -1);

if (F->hasSection()) {
StringRef SecName = F->getSection();

Expand Down
16 changes: 16 additions & 0 deletions llvm/lib/Target/BPF/BTFDebug.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,18 @@ class BTFTypeFloat : public BTFTypeBase {
void completeType(BTFDebug &BDebug) override;
};

/// Handle tags.
class BTFTypeTag : public BTFTypeBase {
uint32_t Info;
StringRef Tag;

public:
BTFTypeTag(uint32_t BaseTypeId, int ComponentId, StringRef Tag);
uint32_t getSize() override { return BTFTypeBase::getSize() + 4; }
void completeType(BTFDebug &BDebug) override;
void emitType(MCStreamer &OS) override;
};

/// String table.
class BTFStringTable {
/// String table size in bytes.
Expand Down Expand Up @@ -313,6 +325,10 @@ class BTFDebug : public DebugHandlerBase {
/// Generate types for function prototypes.
void processFuncPrototypes(const Function *);

/// Generate types for annotations.
void processAnnotations(DINodeArray Annotations, uint32_t BaseTypeId,
int ComponentId);

/// Generate one field relocation record.
void generatePatchImmReloc(const MCSymbol *ORSym, uint32_t RootId,
const GlobalVariable *, bool IsAma);
Expand Down
91 changes: 91 additions & 0 deletions llvm/test/CodeGen/BPF/BTF/tag-1.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s

; Source code:
; #define __tag1 __attribute__((btf_tag("tag1")))
; #define __tag2 __attribute__((btf_tag("tag2")))
; struct t1 {
; int a1;
; int a2 __tag1 __tag2;
; } __tag1 __tag2;
; struct t1 g1 __tag1 __tag2;
; Compilation flag:
; clang -target bpf -O2 -g -S -emit-llvm t.c

%struct.t1 = type { i32, i32 }

@g1 = dso_local local_unnamed_addr global %struct.t1 zeroinitializer, align 4, !dbg !0

!llvm.dbg.cu = !{!2}
!llvm.module.flags = !{!14, !15, !16, !17}
!llvm.ident = !{!18}

!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "g1", scope: !2, file: !3, line: 7, type: !6, isLocal: false, isDefinition: true, annotations: !11)
!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 13.0.0 (https://github.com/llvm/llvm-project.git 825661b8e31d0b29d78178df1e518949dfec9f9a)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, splitDebugInlining: false, nameTableKind: None)
!3 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/llvm/btf_tag")
!4 = !{}
!5 = !{!0}
!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !3, line: 3, size: 64, elements: !7, annotations: !11)
!7 = !{!8, !10}
!8 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !6, file: !3, line: 4, baseType: !9, size: 32)
!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!10 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !6, file: !3, line: 5, baseType: !9, size: 32, offset: 32, annotations: !11)
!11 = !{!12, !13}
!12 = !{!"btf_tag", !"tag1"}
!13 = !{!"btf_tag", !"tag2"}
!14 = !{i32 7, !"Dwarf Version", i32 4}
!15 = !{i32 2, !"Debug Info Version", i32 3}
!16 = !{i32 1, !"wchar_size", i32 4}
!17 = !{i32 7, !"frame-pointer", i32 2}
!18 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git 825661b8e31d0b29d78178df1e518949dfec9f9a)"}

; CHECK: .long 1 # BTF_KIND_STRUCT(id = 1)
; CHECK-NEXT: .long 67108866 # 0x4000002
; CHECK-NEXT: .long 8
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long 0 # 0x0
; CHECK-NEXT: .long 7
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long 32 # 0x20
; CHECK-NEXT: .long 10 # BTF_KIND_TAG(id = 2)
; CHECK-NEXT: .long 2432696320 # 0x91000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 15 # BTF_KIND_TAG(id = 3)
; CHECK-NEXT: .long 2432696320 # 0x91000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 20 # BTF_KIND_INT(id = 4)
; CHECK-NEXT: .long 16777216 # 0x1000000
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long 16777248 # 0x1000020
; CHECK-NEXT: .long 10 # BTF_KIND_TAG(id = 5)
; CHECK-NEXT: .long 285212672 # 0x11000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 15 # BTF_KIND_TAG(id = 6)
; CHECK-NEXT: .long 285212672 # 0x11000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 24 # BTF_KIND_VAR(id = 7)
; CHECK-NEXT: .long 234881024 # 0xe000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 10 # BTF_KIND_TAG(id = 8)
; CHECK-NEXT: .long 2432696320 # 0x91000000
; CHECK-NEXT: .long 7
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 15 # BTF_KIND_TAG(id = 9)
; CHECK-NEXT: .long 2432696320 # 0x91000000
; CHECK-NEXT: .long 7
; CHECK-NEXT: .long 0

; CHECK: .ascii "t1" # string offset=1
; CHECK: .ascii "a1" # string offset=4
; CHECK: .ascii "a2" # string offset=7
; CHECK: .ascii "tag1" # string offset=10
; CHECK: .ascii "tag2" # string offset=15
; CHECK: .ascii "int" # string offset=20
; CHECK: .ascii "g1" # string offset=24
125 changes: 125 additions & 0 deletions llvm/test/CodeGen/BPF/BTF/tag-2.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s

; Source code:
; #define __tag1 __attribute__((btf_tag("tag1")))
; #define __tag2 __attribute__((btf_tag("tag2")))
; extern int bar(int a1, int a2) __tag1 __tag2;
; int __tag1 foo(int arg1, int *arg2 __tag1) {
; ; return arg1 + *arg2 + bar(arg1, arg1 + 1);
; }
; Compilation flag:
; clang -target bpf -O2 -g -S -emit-llvm t.c

; Function Attrs: nounwind
define dso_local i32 @foo(i32 %arg1, i32* nocapture readonly %arg2) local_unnamed_addr #0 !dbg !8 {
entry:
call void @llvm.dbg.value(metadata i32 %arg1, metadata !14, metadata !DIExpression()), !dbg !18
call void @llvm.dbg.value(metadata i32* %arg2, metadata !15, metadata !DIExpression()), !dbg !18
%0 = load i32, i32* %arg2, align 4, !dbg !19, !tbaa !20
%add = add nsw i32 %0, %arg1, !dbg !24
%add1 = add nsw i32 %arg1, 1, !dbg !25
%call = tail call i32 @bar(i32 %arg1, i32 %add1) #3, !dbg !26
%add2 = add nsw i32 %add, %call, !dbg !27
ret i32 %add2, !dbg !28
}

declare !dbg !29 dso_local i32 @bar(i32, i32) local_unnamed_addr #1

; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
declare void @llvm.dbg.value(metadata, metadata, metadata) #2

attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
attributes #1 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
attributes #2 = { nofree nosync nounwind readnone speculatable willreturn }
attributes #3 = { nounwind }

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5, !6}
!llvm.ident = !{!7}

!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 14.0.0 (https://github.com/llvm/llvm-project.git 4be11596b26383c6666f471f07463a3f79e11964)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/llvm/btf_tag")
!2 = !{}
!3 = !{i32 7, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"wchar_size", i32 4}
!6 = !{i32 7, !"frame-pointer", i32 2}
!7 = !{!"clang version 14.0.0 (https://github.com/llvm/llvm-project.git 4be11596b26383c6666f471f07463a3f79e11964)"}
!8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 4, type: !9, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !13, annotations: !16)
!9 = !DISubroutineType(types: !10)
!10 = !{!11, !11, !12}
!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64)
!13 = !{!14, !15}
!14 = !DILocalVariable(name: "arg1", arg: 1, scope: !8, file: !1, line: 4, type: !11)
!15 = !DILocalVariable(name: "arg2", arg: 2, scope: !8, file: !1, line: 4, type: !12, annotations: !16)
!16 = !{!17}
!17 = !{!"btf_tag", !"tag1"}
!18 = !DILocation(line: 0, scope: !8)
!19 = !DILocation(line: 5, column: 17, scope: !8)
!20 = !{!21, !21, i64 0}
!21 = !{!"int", !22, i64 0}
!22 = !{!"omnipotent char", !23, i64 0}
!23 = !{!"Simple C/C++ TBAA"}
!24 = !DILocation(line: 5, column: 15, scope: !8)
!25 = !DILocation(line: 5, column: 40, scope: !8)
!26 = !DILocation(line: 5, column: 25, scope: !8)
!27 = !DILocation(line: 5, column: 23, scope: !8)
!28 = !DILocation(line: 5, column: 3, scope: !8)
!29 = !DISubprogram(name: "bar", scope: !1, file: !1, line: 3, type: !30, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2, annotations: !32)
!30 = !DISubroutineType(types: !31)
!31 = !{!11, !11, !11}
!32 = !{!17, !33}
!33 = !{!"btf_tag", !"tag2"}

; CHECK: .long 1 # BTF_KIND_INT(id = 1)
; CHECK-NEXT: .long 16777216 # 0x1000000
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long 16777248 # 0x1000020
; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 2)
; CHECK-NEXT: .long 33554432 # 0x2000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 3)
; CHECK-NEXT: .long 218103810 # 0xd000002
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 5
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 10
; CHECK-NEXT: .long 2
; CHECK-NEXT: .long 15 # BTF_KIND_FUNC(id = 4)
; CHECK-NEXT: .long 201326593 # 0xc000001
; CHECK-NEXT: .long 3
; CHECK-NEXT: .long 19 # BTF_KIND_TAG(id = 5)
; CHECK-NEXT: .long 285212672 # 0x11000000
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 19 # BTF_KIND_TAG(id = 6)
; CHECK-NEXT: .long 2432696320 # 0x91000000
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 7)
; CHECK-NEXT: .long 218103810 # 0xd000002
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 72 # BTF_KIND_FUNC(id = 8)
; CHECK-NEXT: .long 201326594 # 0xc000002
; CHECK-NEXT: .long 7
; CHECK-NEXT: .long 19 # BTF_KIND_TAG(id = 9)
; CHECK-NEXT: .long 2432696320 # 0x91000000
; CHECK-NEXT: .long 8
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 76 # BTF_KIND_TAG(id = 10)
; CHECK-NEXT: .long 2432696320 # 0x91000000
; CHECK-NEXT: .long 8

; CHECK: .ascii "int" # string offset=1
; CHECK: .ascii "arg1" # string offset=5
; CHECK: .ascii "arg2" # string offset=10
; CHECK: .ascii "foo" # string offset=15
; CHECK: .ascii "tag1" # string offset=19
; CHECK: .ascii "bar" # string offset=72
; CHECK: .ascii "tag2" # string offset=76

0 comments on commit 4948927

Please sign in to comment.