Skip to content

Commit 1b194ef

Browse files
committed
[Clang] add btf_tag attribute
A new attribute btf_tag is added. The syntax looks like __attribute__((btf_tag(<string>))) Users may tag a particular structure/member/function/func_parameter/variable declaration with an arbitrary string and the intention is that this string is passed to dwarf so it is available for post-compilation analysis. The string will be also passed to .BTF section if the target is BPF. For each permitted declaration, multiple btf_tag's are allowed. For detailed use cases, please see https://lists.llvm.org/pipermail/llvm-dev/2021-June/151009.html In case that there exist redeclarations, the btf_tag attributes will be accumulated along with different declarations, and the last declaration will contain all attributes. Differential Revision: https://reviews.llvm.org/D106614
1 parent adb96d2 commit 1b194ef

File tree

7 files changed

+91
-0
lines changed

7 files changed

+91
-0
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1835,6 +1835,14 @@ def BPFPreserveAccessIndex : InheritableAttr,
18351835
let LangOpts = [COnly];
18361836
}
18371837

1838+
def BTFTag : InheritableAttr {
1839+
let Spellings = [Clang<"btf_tag">];
1840+
let Args = [StringArgument<"BTFTag">];
1841+
let Subjects = SubjectList<[Var, Function, Record, Field], ErrorDiag>;
1842+
let Documentation = [BTFTagDocs];
1843+
let LangOpts = [COnly];
1844+
}
1845+
18381846
def WebAssemblyExportName : InheritableAttr,
18391847
TargetSpecificAttr<TargetWebAssembly> {
18401848
let Spellings = [Clang<"export_name">];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2011,6 +2011,16 @@ preserving struct or union member access debuginfo indices of this
20112011
struct or union, similar to clang ``__builtin_preserve_access_index()``.
20122012
}];
20132013
}
2014+
def BTFTagDocs : Documentation {
2015+
let Category = DocCatFunction;
2016+
let Content = [{
2017+
Clang supports the ``__attribute__((btf_tag("ARGUMENT")))`` attribute for all
2018+
targets. This attribute may be attached to a struct/union, struct/union field,
2019+
function, function parameter or variable declaration. If -g is specified,
2020+
the ``ARGUMENT`` info will be preserved in IR and be emitted to dwarf.
2021+
For BPF targets, the ``ARGUMENT`` info will be emitted to .BTF ELF section too.
2022+
}];
2023+
}
20142024

20152025
def MipsInterruptDocs : Documentation {
20162026
let Category = DocCatFunction;

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3363,6 +3363,7 @@ class Sema final {
33633363
EnforceTCBAttr *mergeEnforceTCBAttr(Decl *D, const EnforceTCBAttr &AL);
33643364
EnforceTCBLeafAttr *mergeEnforceTCBLeafAttr(Decl *D,
33653365
const EnforceTCBLeafAttr &AL);
3366+
BTFTagAttr *mergeBTFTagAttr(Decl *D, const BTFTagAttr &AL);
33663367

33673368
void mergeDeclAttributes(NamedDecl *New, Decl *Old,
33683369
AvailabilityMergeKind AMK = AMK_Redeclaration);

clang/lib/Sema/SemaDecl.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2674,6 +2674,8 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
26742674
NewAttr = S.mergeEnforceTCBAttr(D, *TCBA);
26752675
else if (const auto *TCBLA = dyn_cast<EnforceTCBLeafAttr>(Attr))
26762676
NewAttr = S.mergeEnforceTCBLeafAttr(D, *TCBLA);
2677+
else if (const auto *BTFA = dyn_cast<BTFTagAttr>(Attr))
2678+
NewAttr = S.mergeBTFTagAttr(D, *BTFA);
26772679
else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr))
26782680
NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
26792681

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6842,6 +6842,30 @@ static void handleBPFPreserveAccessIndexAttr(Sema &S, Decl *D,
68426842
Rec->addAttr(::new (S.Context) BPFPreserveAccessIndexAttr(S.Context, AL));
68436843
}
68446844

6845+
static bool hasBTFTagAttr(Decl *D, StringRef Tag) {
6846+
for (const auto *I : D->specific_attrs<BTFTagAttr>()) {
6847+
if (I->getBTFTag() == Tag)
6848+
return true;
6849+
}
6850+
return false;
6851+
}
6852+
6853+
static void handleBTFTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
6854+
StringRef Str;
6855+
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
6856+
return;
6857+
if (hasBTFTagAttr(D, Str))
6858+
return;
6859+
6860+
D->addAttr(::new (S.Context) BTFTagAttr(S.Context, AL, Str));
6861+
}
6862+
6863+
BTFTagAttr *Sema::mergeBTFTagAttr(Decl *D, const BTFTagAttr &AL) {
6864+
if (hasBTFTagAttr(D, AL.getBTFTag()))
6865+
return nullptr;
6866+
return ::new (Context) BTFTagAttr(Context, AL, AL.getBTFTag());
6867+
}
6868+
68456869
static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
68466870
if (!isFunctionOrMethod(D)) {
68476871
S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
@@ -7879,6 +7903,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
78797903
case ParsedAttr::AT_BPFPreserveAccessIndex:
78807904
handleBPFPreserveAccessIndexAttr(S, D, AL);
78817905
break;
7906+
case ParsedAttr::AT_BTFTag:
7907+
handleBTFTagAttr(S, D, AL);
7908+
break;
78827909
case ParsedAttr::AT_WebAssemblyExportName:
78837910
handleWebAssemblyExportNameAttr(S, D, AL);
78847911
break;

clang/test/Misc/pragma-attribute-supported-attributes-list.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
// CHECK-NEXT: Assumption (SubjectMatchRule_function, SubjectMatchRule_objc_method)
2323
// CHECK-NEXT: Availability ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_implementation, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable))
2424
// CHECK-NEXT: BPFPreserveAccessIndex (SubjectMatchRule_record)
25+
// CHECK-NEXT: BTFTag (SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_record, SubjectMatchRule_field)
2526
// CHECK-NEXT: BuiltinAlias (SubjectMatchRule_function)
2627
// CHECK-NEXT: CFAuditedTransfer (SubjectMatchRule_function)
2728
// CHECK-NEXT: CFConsumed (SubjectMatchRule_variable_is_parameter)

clang/test/Sema/attr-btf_tag.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: %clang_cc1 -x c -triple x86_64-pc-linux-gnu -dwarf-version=4 -fsyntax-only -verify %s
2+
3+
#define __tag1 __attribute__((btf_tag("tag1")))
4+
#define __tag2 __attribute__((btf_tag("tag2")))
5+
#define __tag3 __attribute__((btf_tag("tag3")))
6+
7+
#define __tag_no_arg __attribute__((btf_tag()))
8+
#define __tag_2_arg __attribute__((btf_tag("tag1", "tag2")))
9+
#define __invalid __attribute__((btf_tag(1)))
10+
11+
struct __tag1 __tag2 t1;
12+
struct t1 {
13+
int a __tag1;
14+
} __tag3;
15+
16+
struct __tag1 t2;
17+
struct __tag2 __tag3 t2 {
18+
int a __tag1;
19+
};
20+
21+
int g1 __tag1;
22+
int g2 __tag_no_arg; // expected-error {{'btf_tag' attribute takes one argument}}
23+
int g3 __tag_2_arg; // expected-error {{'btf_tag' attribute takes one argument}}
24+
int i1 __invalid; // expected-error {{'btf_tag' attribute requires a string}}
25+
26+
enum e1 {
27+
E1
28+
} __tag1; // expected-error {{'btf_tag' attribute only applies to variables, functions, structs, unions, classes, and non-static data members}}
29+
30+
enum e2 {
31+
E2
32+
} __tag_no_arg; // expected-error {{'btf_tag' attribute only applies to variables, functions, structs, unions, classes, and non-static data members}}
33+
34+
enum e3 {
35+
E3
36+
} __tag_2_arg; // expected-error {{'btf_tag' attribute only applies to variables, functions, structs, unions, classes, and non-static data members}}
37+
38+
int __tag1 __tag2 foo(struct t1 *arg, struct t2 *arg2);
39+
int __tag2 __tag3 foo(struct t1 *arg, struct t2 *arg2);
40+
int __tag1 foo(struct t1 *arg __tag1, struct t2 *arg2) {
41+
return arg->a + arg2->a;
42+
}

0 commit comments

Comments
 (0)