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 25 SemaBPF::SemaBPF(Sema &S) : SemaBase(S) {} 26 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 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 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 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 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 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