Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Sema/SemaBPF.cpp
35234 views
1
//===------ SemaBPF.cpp ---------- BPF target-specific routines -----------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file implements semantic analysis functions specific to BPF.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "clang/Sema/SemaBPF.h"
14
#include "clang/AST/Decl.h"
15
#include "clang/AST/Type.h"
16
#include "clang/Basic/DiagnosticSema.h"
17
#include "clang/Basic/TargetBuiltins.h"
18
#include "clang/Sema/ParsedAttr.h"
19
#include "clang/Sema/Sema.h"
20
#include "llvm/ADT/APSInt.h"
21
#include <optional>
22
23
namespace clang {
24
25
SemaBPF::SemaBPF(Sema &S) : SemaBase(S) {}
26
27
static bool isValidPreserveFieldInfoArg(Expr *Arg) {
28
if (Arg->getType()->getAsPlaceholderType())
29
return false;
30
31
// The first argument needs to be a record field access.
32
// If it is an array element access, we delay decision
33
// to BPF backend to check whether the access is a
34
// field access or not.
35
return (Arg->IgnoreParens()->getObjectKind() == OK_BitField ||
36
isa<MemberExpr>(Arg->IgnoreParens()) ||
37
isa<ArraySubscriptExpr>(Arg->IgnoreParens()));
38
}
39
40
static bool isValidPreserveTypeInfoArg(Expr *Arg) {
41
QualType ArgType = Arg->getType();
42
if (ArgType->getAsPlaceholderType())
43
return false;
44
45
// for TYPE_EXISTENCE/TYPE_MATCH/TYPE_SIZEOF reloc type
46
// format:
47
// 1. __builtin_preserve_type_info(*(<type> *)0, flag);
48
// 2. <type> var;
49
// __builtin_preserve_type_info(var, flag);
50
if (!isa<DeclRefExpr>(Arg->IgnoreParens()) &&
51
!isa<UnaryOperator>(Arg->IgnoreParens()))
52
return false;
53
54
// Typedef type.
55
if (ArgType->getAs<TypedefType>())
56
return true;
57
58
// Record type or Enum type.
59
const Type *Ty = ArgType->getUnqualifiedDesugaredType();
60
if (const auto *RT = Ty->getAs<RecordType>()) {
61
if (!RT->getDecl()->getDeclName().isEmpty())
62
return true;
63
} else if (const auto *ET = Ty->getAs<EnumType>()) {
64
if (!ET->getDecl()->getDeclName().isEmpty())
65
return true;
66
}
67
68
return false;
69
}
70
71
static bool isValidPreserveEnumValueArg(Expr *Arg) {
72
QualType ArgType = Arg->getType();
73
if (ArgType->getAsPlaceholderType())
74
return false;
75
76
// for ENUM_VALUE_EXISTENCE/ENUM_VALUE reloc type
77
// format:
78
// __builtin_preserve_enum_value(*(<enum_type> *)<enum_value>,
79
// flag);
80
const auto *UO = dyn_cast<UnaryOperator>(Arg->IgnoreParens());
81
if (!UO)
82
return false;
83
84
const auto *CE = dyn_cast<CStyleCastExpr>(UO->getSubExpr());
85
if (!CE)
86
return false;
87
if (CE->getCastKind() != CK_IntegralToPointer &&
88
CE->getCastKind() != CK_NullToPointer)
89
return false;
90
91
// The integer must be from an EnumConstantDecl.
92
const auto *DR = dyn_cast<DeclRefExpr>(CE->getSubExpr());
93
if (!DR)
94
return false;
95
96
const EnumConstantDecl *Enumerator =
97
dyn_cast<EnumConstantDecl>(DR->getDecl());
98
if (!Enumerator)
99
return false;
100
101
// The type must be EnumType.
102
const Type *Ty = ArgType->getUnqualifiedDesugaredType();
103
const auto *ET = Ty->getAs<EnumType>();
104
if (!ET)
105
return false;
106
107
// The enum value must be supported.
108
return llvm::is_contained(ET->getDecl()->enumerators(), Enumerator);
109
}
110
111
bool SemaBPF::CheckBPFBuiltinFunctionCall(unsigned BuiltinID,
112
CallExpr *TheCall) {
113
assert((BuiltinID == BPF::BI__builtin_preserve_field_info ||
114
BuiltinID == BPF::BI__builtin_btf_type_id ||
115
BuiltinID == BPF::BI__builtin_preserve_type_info ||
116
BuiltinID == BPF::BI__builtin_preserve_enum_value) &&
117
"unexpected BPF builtin");
118
ASTContext &Context = getASTContext();
119
if (SemaRef.checkArgCount(TheCall, 2))
120
return true;
121
122
// The second argument needs to be a constant int
123
Expr *Arg = TheCall->getArg(1);
124
std::optional<llvm::APSInt> Value = Arg->getIntegerConstantExpr(Context);
125
diag::kind kind;
126
if (!Value) {
127
if (BuiltinID == BPF::BI__builtin_preserve_field_info)
128
kind = diag::err_preserve_field_info_not_const;
129
else if (BuiltinID == BPF::BI__builtin_btf_type_id)
130
kind = diag::err_btf_type_id_not_const;
131
else if (BuiltinID == BPF::BI__builtin_preserve_type_info)
132
kind = diag::err_preserve_type_info_not_const;
133
else
134
kind = diag::err_preserve_enum_value_not_const;
135
Diag(Arg->getBeginLoc(), kind) << 2 << Arg->getSourceRange();
136
return true;
137
}
138
139
// The first argument
140
Arg = TheCall->getArg(0);
141
bool InvalidArg = false;
142
bool ReturnUnsignedInt = true;
143
if (BuiltinID == BPF::BI__builtin_preserve_field_info) {
144
if (!isValidPreserveFieldInfoArg(Arg)) {
145
InvalidArg = true;
146
kind = diag::err_preserve_field_info_not_field;
147
}
148
} else if (BuiltinID == BPF::BI__builtin_preserve_type_info) {
149
if (!isValidPreserveTypeInfoArg(Arg)) {
150
InvalidArg = true;
151
kind = diag::err_preserve_type_info_invalid;
152
}
153
} else if (BuiltinID == BPF::BI__builtin_preserve_enum_value) {
154
if (!isValidPreserveEnumValueArg(Arg)) {
155
InvalidArg = true;
156
kind = diag::err_preserve_enum_value_invalid;
157
}
158
ReturnUnsignedInt = false;
159
} else if (BuiltinID == BPF::BI__builtin_btf_type_id) {
160
ReturnUnsignedInt = false;
161
}
162
163
if (InvalidArg) {
164
Diag(Arg->getBeginLoc(), kind) << 1 << Arg->getSourceRange();
165
return true;
166
}
167
168
if (ReturnUnsignedInt)
169
TheCall->setType(Context.UnsignedIntTy);
170
else
171
TheCall->setType(Context.UnsignedLongTy);
172
return false;
173
}
174
175
void SemaBPF::handlePreserveAIRecord(RecordDecl *RD) {
176
// Add preserve_access_index attribute to all fields and inner records.
177
for (auto *D : RD->decls()) {
178
if (D->hasAttr<BPFPreserveAccessIndexAttr>())
179
continue;
180
181
D->addAttr(BPFPreserveAccessIndexAttr::CreateImplicit(getASTContext()));
182
if (auto *Rec = dyn_cast<RecordDecl>(D))
183
handlePreserveAIRecord(Rec);
184
}
185
}
186
187
void SemaBPF::handlePreserveAccessIndexAttr(Decl *D, const ParsedAttr &AL) {
188
auto *Rec = cast<RecordDecl>(D);
189
handlePreserveAIRecord(Rec);
190
Rec->addAttr(::new (getASTContext())
191
BPFPreserveAccessIndexAttr(getASTContext(), AL));
192
}
193
194
} // namespace clang
195
196