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