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
SemaBPF(Sema & S)25 SemaBPF::SemaBPF(Sema &S) : SemaBase(S) {}
26
isValidPreserveFieldInfoArg(Expr * Arg)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
isValidPreserveTypeInfoArg(Expr * Arg)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
isValidPreserveEnumValueArg(Expr * Arg)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
CheckBPFBuiltinFunctionCall(unsigned BuiltinID,CallExpr * TheCall)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
handlePreserveAIRecord(RecordDecl * RD)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
handlePreserveAccessIndexAttr(Decl * D,const ParsedAttr & AL)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