189 lines · cpp
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-exception6//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 23namespace clang {24 25SemaBPF::SemaBPF(Sema &S) : SemaBase(S) {}26 27static 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 decision33 // to BPF backend to check whether the access is a34 // field access or not.35 return (Arg->IgnoreParens()->getObjectKind() == OK_BitField ||36 isa<MemberExpr>(Arg->IgnoreParens()) ||37 isa<ArraySubscriptExpr>(Arg->IgnoreParens()));38}39 40static 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 type46 // 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 if (const auto *RT = ArgType->getAsCanonical<TagType>())60 if (!RT->getDecl()->getDeclName().isEmpty())61 return true;62 63 return false;64}65 66static bool isValidPreserveEnumValueArg(Expr *Arg) {67 QualType ArgType = Arg->getType();68 if (ArgType->getAsPlaceholderType())69 return false;70 71 // for ENUM_VALUE_EXISTENCE/ENUM_VALUE reloc type72 // format:73 // __builtin_preserve_enum_value(*(<enum_type> *)<enum_value>,74 // flag);75 const auto *UO = dyn_cast<UnaryOperator>(Arg->IgnoreParens());76 if (!UO)77 return false;78 79 const auto *CE = dyn_cast<CStyleCastExpr>(UO->getSubExpr());80 if (!CE)81 return false;82 if (CE->getCastKind() != CK_IntegralToPointer &&83 CE->getCastKind() != CK_NullToPointer)84 return false;85 86 // The integer must be from an EnumConstantDecl.87 const auto *DR = dyn_cast<DeclRefExpr>(CE->getSubExpr());88 if (!DR)89 return false;90 91 const EnumConstantDecl *Enumerator =92 dyn_cast<EnumConstantDecl>(DR->getDecl());93 if (!Enumerator)94 return false;95 96 // The type must be EnumType.97 const auto *ED = ArgType->getAsEnumDecl();98 if (!ED)99 return false;100 101 // The enum value must be supported.102 return llvm::is_contained(ED->enumerators(), Enumerator);103}104 105bool SemaBPF::CheckBPFBuiltinFunctionCall(unsigned BuiltinID,106 CallExpr *TheCall) {107 assert((BuiltinID == BPF::BI__builtin_preserve_field_info ||108 BuiltinID == BPF::BI__builtin_btf_type_id ||109 BuiltinID == BPF::BI__builtin_preserve_type_info ||110 BuiltinID == BPF::BI__builtin_preserve_enum_value) &&111 "unexpected BPF builtin");112 ASTContext &Context = getASTContext();113 if (SemaRef.checkArgCount(TheCall, 2))114 return true;115 116 // The second argument needs to be a constant int117 Expr *Arg = TheCall->getArg(1);118 std::optional<llvm::APSInt> Value = Arg->getIntegerConstantExpr(Context);119 diag::kind kind;120 if (!Value) {121 if (BuiltinID == BPF::BI__builtin_preserve_field_info)122 kind = diag::err_preserve_field_info_not_const;123 else if (BuiltinID == BPF::BI__builtin_btf_type_id)124 kind = diag::err_btf_type_id_not_const;125 else if (BuiltinID == BPF::BI__builtin_preserve_type_info)126 kind = diag::err_preserve_type_info_not_const;127 else128 kind = diag::err_preserve_enum_value_not_const;129 Diag(Arg->getBeginLoc(), kind) << 2 << Arg->getSourceRange();130 return true;131 }132 133 // The first argument134 Arg = TheCall->getArg(0);135 bool InvalidArg = false;136 bool ReturnUnsignedInt = true;137 if (BuiltinID == BPF::BI__builtin_preserve_field_info) {138 if (!isValidPreserveFieldInfoArg(Arg)) {139 InvalidArg = true;140 kind = diag::err_preserve_field_info_not_field;141 }142 } else if (BuiltinID == BPF::BI__builtin_preserve_type_info) {143 if (!isValidPreserveTypeInfoArg(Arg)) {144 InvalidArg = true;145 kind = diag::err_preserve_type_info_invalid;146 }147 } else if (BuiltinID == BPF::BI__builtin_preserve_enum_value) {148 if (!isValidPreserveEnumValueArg(Arg)) {149 InvalidArg = true;150 kind = diag::err_preserve_enum_value_invalid;151 }152 ReturnUnsignedInt = false;153 } else if (BuiltinID == BPF::BI__builtin_btf_type_id) {154 ReturnUnsignedInt = false;155 }156 157 if (InvalidArg) {158 Diag(Arg->getBeginLoc(), kind) << 1 << Arg->getSourceRange();159 return true;160 }161 162 if (ReturnUnsignedInt)163 TheCall->setType(Context.UnsignedIntTy);164 else165 TheCall->setType(Context.UnsignedLongTy);166 return false;167}168 169void SemaBPF::handlePreserveAIRecord(RecordDecl *RD) {170 // Add preserve_access_index attribute to all fields and inner records.171 for (auto *D : RD->decls()) {172 if (D->hasAttr<BPFPreserveAccessIndexAttr>())173 continue;174 175 D->addAttr(BPFPreserveAccessIndexAttr::CreateImplicit(getASTContext()));176 if (auto *Rec = dyn_cast<RecordDecl>(D))177 handlePreserveAIRecord(Rec);178 }179}180 181void SemaBPF::handlePreserveAccessIndexAttr(Decl *D, const ParsedAttr &AL) {182 auto *Rec = cast<RecordDecl>(D);183 handlePreserveAIRecord(Rec);184 Rec->addAttr(::new (getASTContext())185 BPFPreserveAccessIndexAttr(getASTContext(), AL));186}187 188} // namespace clang189