xref: /freebsd/contrib/llvm-project/clang/lib/Sema/SemaBPF.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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