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