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