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