xref: /freebsd/contrib/llvm-project/clang/lib/CodeGen/CGPointerAuth.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
1 //===--- CGPointerAuth.cpp - IR generation for pointer authentication -----===//
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 contains common routines relating to the emission of
10 // pointer authentication operations.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "CodeGenFunction.h"
15 #include "CodeGenModule.h"
16 #include "clang/CodeGen/CodeGenABITypes.h"
17 #include "clang/CodeGen/ConstantInitBuilder.h"
18 #include "llvm/Analysis/ValueTracking.h"
19 #include "llvm/Support/SipHash.h"
20 
21 using namespace clang;
22 using namespace CodeGen;
23 
24 /// Given a pointer-authentication schema, return a concrete "other"
25 /// discriminator for it.
26 llvm::ConstantInt *CodeGenModule::getPointerAuthOtherDiscriminator(
27     const PointerAuthSchema &Schema, GlobalDecl Decl, QualType Type) {
28   switch (Schema.getOtherDiscrimination()) {
29   case PointerAuthSchema::Discrimination::None:
30     return nullptr;
31 
32   case PointerAuthSchema::Discrimination::Type:
33     assert(!Type.isNull() && "type not provided for type-discriminated schema");
34     return llvm::ConstantInt::get(
35         IntPtrTy, getContext().getPointerAuthTypeDiscriminator(Type));
36 
37   case PointerAuthSchema::Discrimination::Decl:
38     assert(Decl.getDecl() &&
39            "declaration not provided for decl-discriminated schema");
40     return llvm::ConstantInt::get(IntPtrTy,
41                                   getPointerAuthDeclDiscriminator(Decl));
42 
43   case PointerAuthSchema::Discrimination::Constant:
44     return llvm::ConstantInt::get(IntPtrTy, Schema.getConstantDiscrimination());
45   }
46   llvm_unreachable("bad discrimination kind");
47 }
48 
49 uint16_t CodeGen::getPointerAuthTypeDiscriminator(CodeGenModule &CGM,
50                                                   QualType FunctionType) {
51   return CGM.getContext().getPointerAuthTypeDiscriminator(FunctionType);
52 }
53 
54 uint16_t CodeGen::getPointerAuthDeclDiscriminator(CodeGenModule &CGM,
55                                                   GlobalDecl Declaration) {
56   return CGM.getPointerAuthDeclDiscriminator(Declaration);
57 }
58 
59 /// Return the "other" decl-specific discriminator for the given decl.
60 uint16_t
61 CodeGenModule::getPointerAuthDeclDiscriminator(GlobalDecl Declaration) {
62   uint16_t &EntityHash = PtrAuthDiscriminatorHashes[Declaration];
63 
64   if (EntityHash == 0) {
65     StringRef Name = getMangledName(Declaration);
66     EntityHash = llvm::getPointerAuthStableSipHash(Name);
67   }
68 
69   return EntityHash;
70 }
71 
72 /// Return the abstract pointer authentication schema for a pointer to the given
73 /// function type.
74 CGPointerAuthInfo CodeGenModule::getFunctionPointerAuthInfo(QualType T) {
75   const auto &Schema = getCodeGenOpts().PointerAuth.FunctionPointers;
76   if (!Schema)
77     return CGPointerAuthInfo();
78 
79   assert(!Schema.isAddressDiscriminated() &&
80          "function pointers cannot use address-specific discrimination");
81 
82   llvm::Constant *Discriminator = nullptr;
83   if (T->isFunctionPointerType() || T->isFunctionReferenceType())
84     T = T->getPointeeType();
85   if (T->isFunctionType())
86     Discriminator = getPointerAuthOtherDiscriminator(Schema, GlobalDecl(), T);
87 
88   return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),
89                            /*IsaPointer=*/false, /*AuthenticatesNull=*/false,
90                            Discriminator);
91 }
92 
93 llvm::Value *
94 CodeGenFunction::EmitPointerAuthBlendDiscriminator(llvm::Value *StorageAddress,
95                                                    llvm::Value *Discriminator) {
96   StorageAddress = Builder.CreatePtrToInt(StorageAddress, IntPtrTy);
97   auto Intrinsic = CGM.getIntrinsic(llvm::Intrinsic::ptrauth_blend);
98   return Builder.CreateCall(Intrinsic, {StorageAddress, Discriminator});
99 }
100 
101 /// Emit the concrete pointer authentication informaton for the
102 /// given authentication schema.
103 CGPointerAuthInfo CodeGenFunction::EmitPointerAuthInfo(
104     const PointerAuthSchema &Schema, llvm::Value *StorageAddress,
105     GlobalDecl SchemaDecl, QualType SchemaType) {
106   if (!Schema)
107     return CGPointerAuthInfo();
108 
109   llvm::Value *Discriminator =
110       CGM.getPointerAuthOtherDiscriminator(Schema, SchemaDecl, SchemaType);
111 
112   if (Schema.isAddressDiscriminated()) {
113     assert(StorageAddress &&
114            "address not provided for address-discriminated schema");
115 
116     if (Discriminator)
117       Discriminator =
118           EmitPointerAuthBlendDiscriminator(StorageAddress, Discriminator);
119     else
120       Discriminator = Builder.CreatePtrToInt(StorageAddress, IntPtrTy);
121   }
122 
123   return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),
124                            Schema.isIsaPointer(),
125                            Schema.authenticatesNullValues(), Discriminator);
126 }
127 
128 CGPointerAuthInfo
129 CodeGenFunction::EmitPointerAuthInfo(PointerAuthQualifier Qual,
130                                      Address StorageAddress) {
131   assert(Qual && "don't call this if you don't know that the Qual is present");
132   if (Qual.hasKeyNone())
133     return CGPointerAuthInfo();
134 
135   llvm::Value *Discriminator = nullptr;
136   if (unsigned Extra = Qual.getExtraDiscriminator())
137     Discriminator = llvm::ConstantInt::get(IntPtrTy, Extra);
138 
139   if (Qual.isAddressDiscriminated()) {
140     assert(StorageAddress.isValid() &&
141            "address discrimination without address");
142     llvm::Value *StoragePtr = StorageAddress.emitRawPointer(*this);
143     if (Discriminator)
144       Discriminator =
145           EmitPointerAuthBlendDiscriminator(StoragePtr, Discriminator);
146     else
147       Discriminator = Builder.CreatePtrToInt(StoragePtr, IntPtrTy);
148   }
149 
150   return CGPointerAuthInfo(Qual.getKey(), Qual.getAuthenticationMode(),
151                            Qual.isIsaPointer(), Qual.authenticatesNullValues(),
152                            Discriminator);
153 }
154 
155 /// Return the natural pointer authentication for values of the given
156 /// pointee type.
157 static CGPointerAuthInfo
158 getPointerAuthInfoForPointeeType(CodeGenModule &CGM, QualType PointeeType) {
159   if (PointeeType.isNull())
160     return CGPointerAuthInfo();
161 
162   // Function pointers use the function-pointer schema by default.
163   if (PointeeType->isFunctionType())
164     return CGM.getFunctionPointerAuthInfo(PointeeType);
165 
166   // Normal data pointers never use direct pointer authentication by default.
167   return CGPointerAuthInfo();
168 }
169 
170 CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForPointeeType(QualType T) {
171   return ::getPointerAuthInfoForPointeeType(*this, T);
172 }
173 
174 /// Return the natural pointer authentication for values of the given
175 /// pointer type.
176 static CGPointerAuthInfo getPointerAuthInfoForType(CodeGenModule &CGM,
177                                                    QualType PointerType) {
178   assert(PointerType->isSignableType(CGM.getContext()));
179 
180   // Block pointers are currently not signed.
181   if (PointerType->isBlockPointerType())
182     return CGPointerAuthInfo();
183 
184   auto PointeeType = PointerType->getPointeeType();
185 
186   if (PointeeType.isNull())
187     return CGPointerAuthInfo();
188 
189   return ::getPointerAuthInfoForPointeeType(CGM, PointeeType);
190 }
191 
192 CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForType(QualType T) {
193   return ::getPointerAuthInfoForType(*this, T);
194 }
195 
196 static std::pair<llvm::Value *, CGPointerAuthInfo>
197 emitLoadOfOrigPointerRValue(CodeGenFunction &CGF, const LValue &LV,
198                             SourceLocation Loc) {
199   llvm::Value *Value = CGF.EmitLoadOfScalar(LV, Loc);
200   CGPointerAuthInfo AuthInfo;
201   if (PointerAuthQualifier PtrAuth = LV.getQuals().getPointerAuth())
202     AuthInfo = CGF.EmitPointerAuthInfo(PtrAuth, LV.getAddress());
203   else
204     AuthInfo = getPointerAuthInfoForType(CGF.CGM, LV.getType());
205   return {Value, AuthInfo};
206 }
207 
208 /// Retrieve a pointer rvalue and its ptrauth info. When possible, avoid
209 /// needlessly resigning the pointer.
210 std::pair<llvm::Value *, CGPointerAuthInfo>
211 CodeGenFunction::EmitOrigPointerRValue(const Expr *E) {
212   assert(E->getType()->isSignableType(getContext()));
213 
214   E = E->IgnoreParens();
215   if (const auto *Load = dyn_cast<ImplicitCastExpr>(E)) {
216     if (Load->getCastKind() == CK_LValueToRValue) {
217       E = Load->getSubExpr()->IgnoreParens();
218 
219       // We're semantically required to not emit loads of certain DREs naively.
220       if (const auto *RefExpr = dyn_cast<DeclRefExpr>(E)) {
221         if (ConstantEmission Result = tryEmitAsConstant(RefExpr)) {
222           // Fold away a use of an intermediate variable.
223           if (!Result.isReference())
224             return {Result.getValue(),
225                     getPointerAuthInfoForType(CGM, RefExpr->getType())};
226 
227           // Fold away a use of an intermediate reference.
228           LValue LV = Result.getReferenceLValue(*this, RefExpr);
229           return emitLoadOfOrigPointerRValue(*this, LV, RefExpr->getLocation());
230         }
231       }
232 
233       // Otherwise, load and use the pointer
234       LValue LV = EmitCheckedLValue(E, CodeGenFunction::TCK_Load);
235       return emitLoadOfOrigPointerRValue(*this, LV, E->getExprLoc());
236     }
237   }
238 
239   // Fallback: just use the normal rules for the type.
240   llvm::Value *Value = EmitScalarExpr(E);
241   return {Value, getPointerAuthInfoForType(CGM, E->getType())};
242 }
243 
244 llvm::Value *
245 CodeGenFunction::EmitPointerAuthQualify(PointerAuthQualifier DestQualifier,
246                                         const Expr *E,
247                                         Address DestStorageAddress) {
248   assert(DestQualifier);
249   auto [Value, CurAuthInfo] = EmitOrigPointerRValue(E);
250 
251   CGPointerAuthInfo DestAuthInfo =
252       EmitPointerAuthInfo(DestQualifier, DestStorageAddress);
253   return emitPointerAuthResign(Value, E->getType(), CurAuthInfo, DestAuthInfo,
254                                isPointerKnownNonNull(E));
255 }
256 
257 llvm::Value *CodeGenFunction::EmitPointerAuthQualify(
258     PointerAuthQualifier DestQualifier, llvm::Value *Value,
259     QualType PointerType, Address DestStorageAddress, bool IsKnownNonNull) {
260   assert(DestQualifier);
261 
262   CGPointerAuthInfo CurAuthInfo = getPointerAuthInfoForType(CGM, PointerType);
263   CGPointerAuthInfo DestAuthInfo =
264       EmitPointerAuthInfo(DestQualifier, DestStorageAddress);
265   return emitPointerAuthResign(Value, PointerType, CurAuthInfo, DestAuthInfo,
266                                IsKnownNonNull);
267 }
268 
269 llvm::Value *CodeGenFunction::EmitPointerAuthUnqualify(
270     PointerAuthQualifier CurQualifier, llvm::Value *Value, QualType PointerType,
271     Address CurStorageAddress, bool IsKnownNonNull) {
272   assert(CurQualifier);
273 
274   CGPointerAuthInfo CurAuthInfo =
275       EmitPointerAuthInfo(CurQualifier, CurStorageAddress);
276   CGPointerAuthInfo DestAuthInfo = getPointerAuthInfoForType(CGM, PointerType);
277   return emitPointerAuthResign(Value, PointerType, CurAuthInfo, DestAuthInfo,
278                                IsKnownNonNull);
279 }
280 
281 static bool isZeroConstant(const llvm::Value *Value) {
282   if (const auto *CI = dyn_cast<llvm::ConstantInt>(Value))
283     return CI->isZero();
284   return false;
285 }
286 
287 static bool equalAuthPolicies(const CGPointerAuthInfo &Left,
288                               const CGPointerAuthInfo &Right) {
289   assert((Left.isSigned() || Right.isSigned()) &&
290          "shouldn't be called if neither is signed");
291   if (Left.isSigned() != Right.isSigned())
292     return false;
293   return Left.getKey() == Right.getKey() &&
294          Left.getAuthenticationMode() == Right.getAuthenticationMode() &&
295          Left.isIsaPointer() == Right.isIsaPointer() &&
296          Left.authenticatesNullValues() == Right.authenticatesNullValues() &&
297          Left.getDiscriminator() == Right.getDiscriminator();
298 }
299 
300 // Return the discriminator or return zero if the discriminator is null.
301 static llvm::Value *getDiscriminatorOrZero(const CGPointerAuthInfo &Info,
302                                            CGBuilderTy &Builder) {
303   llvm::Value *Discriminator = Info.getDiscriminator();
304   return Discriminator ? Discriminator : Builder.getSize(0);
305 }
306 
307 llvm::Value *
308 CodeGenFunction::emitPointerAuthResignCall(llvm::Value *Value,
309                                            const CGPointerAuthInfo &CurAuth,
310                                            const CGPointerAuthInfo &NewAuth) {
311   assert(CurAuth && NewAuth);
312 
313   if (CurAuth.getAuthenticationMode() !=
314           PointerAuthenticationMode::SignAndAuth ||
315       NewAuth.getAuthenticationMode() !=
316           PointerAuthenticationMode::SignAndAuth) {
317     llvm::Value *AuthedValue = EmitPointerAuthAuth(CurAuth, Value);
318     return EmitPointerAuthSign(NewAuth, AuthedValue);
319   }
320   // Convert the pointer to intptr_t before signing it.
321   auto *OrigType = Value->getType();
322   Value = Builder.CreatePtrToInt(Value, IntPtrTy);
323 
324   auto *CurKey = Builder.getInt32(CurAuth.getKey());
325   auto *NewKey = Builder.getInt32(NewAuth.getKey());
326 
327   llvm::Value *CurDiscriminator = getDiscriminatorOrZero(CurAuth, Builder);
328   llvm::Value *NewDiscriminator = getDiscriminatorOrZero(NewAuth, Builder);
329 
330   // call i64 @llvm.ptrauth.resign(i64 %pointer,
331   //                               i32 %curKey, i64 %curDiscriminator,
332   //                               i32 %newKey, i64 %newDiscriminator)
333   auto *Intrinsic = CGM.getIntrinsic(llvm::Intrinsic::ptrauth_resign);
334   Value = EmitRuntimeCall(
335       Intrinsic, {Value, CurKey, CurDiscriminator, NewKey, NewDiscriminator});
336 
337   // Convert back to the original type.
338   Value = Builder.CreateIntToPtr(Value, OrigType);
339   return Value;
340 }
341 
342 llvm::Value *CodeGenFunction::emitPointerAuthResign(
343     llvm::Value *Value, QualType Type, const CGPointerAuthInfo &CurAuthInfo,
344     const CGPointerAuthInfo &NewAuthInfo, bool IsKnownNonNull) {
345   // Fast path: if neither schema wants a signature, we're done.
346   if (!CurAuthInfo && !NewAuthInfo)
347     return Value;
348 
349   llvm::Value *Null = nullptr;
350   // If the value is obviously null, we're done.
351   if (auto *PointerValue = dyn_cast<llvm::PointerType>(Value->getType())) {
352     Null = CGM.getNullPointer(PointerValue, Type);
353   } else {
354     assert(Value->getType()->isIntegerTy());
355     Null = llvm::ConstantInt::get(IntPtrTy, 0);
356   }
357   if (Value == Null)
358     return Value;
359 
360   // If both schemas sign the same way, we're done.
361   if (equalAuthPolicies(CurAuthInfo, NewAuthInfo)) {
362     const llvm::Value *CurD = CurAuthInfo.getDiscriminator();
363     const llvm::Value *NewD = NewAuthInfo.getDiscriminator();
364     if (CurD == NewD)
365       return Value;
366 
367     if ((CurD == nullptr && isZeroConstant(NewD)) ||
368         (NewD == nullptr && isZeroConstant(CurD)))
369       return Value;
370   }
371 
372   llvm::BasicBlock *InitBB = Builder.GetInsertBlock();
373   llvm::BasicBlock *ResignBB = nullptr, *ContBB = nullptr;
374 
375   // Null pointers have to be mapped to null, and the ptrauth_resign
376   // intrinsic doesn't do that.
377   if (!IsKnownNonNull && !llvm::isKnownNonZero(Value, CGM.getDataLayout())) {
378     ContBB = createBasicBlock("resign.cont");
379     ResignBB = createBasicBlock("resign.nonnull");
380 
381     auto *IsNonNull = Builder.CreateICmpNE(Value, Null);
382     Builder.CreateCondBr(IsNonNull, ResignBB, ContBB);
383     EmitBlock(ResignBB);
384   }
385 
386   // Perform the auth/sign/resign operation.
387   if (!NewAuthInfo)
388     Value = EmitPointerAuthAuth(CurAuthInfo, Value);
389   else if (!CurAuthInfo)
390     Value = EmitPointerAuthSign(NewAuthInfo, Value);
391   else
392     Value = emitPointerAuthResignCall(Value, CurAuthInfo, NewAuthInfo);
393 
394   // Clean up with a phi if we branched before.
395   if (ContBB) {
396     EmitBlock(ContBB);
397     auto *Phi = Builder.CreatePHI(Value->getType(), 2);
398     Phi->addIncoming(Null, InitBB);
399     Phi->addIncoming(Value, ResignBB);
400     Value = Phi;
401   }
402 
403   return Value;
404 }
405 
406 void CodeGenFunction::EmitPointerAuthCopy(PointerAuthQualifier Qual, QualType T,
407                                           Address DestAddress,
408                                           Address SrcAddress) {
409   assert(Qual);
410   llvm::Value *Value = Builder.CreateLoad(SrcAddress);
411 
412   // If we're using address-discrimination, we have to re-sign the value.
413   if (Qual.isAddressDiscriminated()) {
414     CGPointerAuthInfo SrcPtrAuth = EmitPointerAuthInfo(Qual, SrcAddress);
415     CGPointerAuthInfo DestPtrAuth = EmitPointerAuthInfo(Qual, DestAddress);
416     Value = emitPointerAuthResign(Value, T, SrcPtrAuth, DestPtrAuth,
417                                   /*IsKnownNonNull=*/false);
418   }
419 
420   Builder.CreateStore(Value, DestAddress);
421 }
422 
423 llvm::Constant *
424 CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key,
425                                         llvm::Constant *StorageAddress,
426                                         llvm::ConstantInt *OtherDiscriminator) {
427   llvm::Constant *AddressDiscriminator;
428   if (StorageAddress) {
429     assert(StorageAddress->getType() == UnqualPtrTy);
430     AddressDiscriminator = StorageAddress;
431   } else {
432     AddressDiscriminator = llvm::Constant::getNullValue(UnqualPtrTy);
433   }
434 
435   llvm::ConstantInt *IntegerDiscriminator;
436   if (OtherDiscriminator) {
437     assert(OtherDiscriminator->getType() == Int64Ty);
438     IntegerDiscriminator = OtherDiscriminator;
439   } else {
440     IntegerDiscriminator = llvm::ConstantInt::get(Int64Ty, 0);
441   }
442 
443   return llvm::ConstantPtrAuth::get(Pointer,
444                                     llvm::ConstantInt::get(Int32Ty, Key),
445                                     IntegerDiscriminator, AddressDiscriminator);
446 }
447 
448 /// Does a given PointerAuthScheme require us to sign a value
449 bool CodeGenModule::shouldSignPointer(const PointerAuthSchema &Schema) {
450   auto AuthenticationMode = Schema.getAuthenticationMode();
451   return AuthenticationMode == PointerAuthenticationMode::SignAndStrip ||
452          AuthenticationMode == PointerAuthenticationMode::SignAndAuth;
453 }
454 
455 /// Sign a constant pointer using the given scheme, producing a constant
456 /// with the same IR type.
457 llvm::Constant *CodeGenModule::getConstantSignedPointer(
458     llvm::Constant *Pointer, const PointerAuthSchema &Schema,
459     llvm::Constant *StorageAddress, GlobalDecl SchemaDecl,
460     QualType SchemaType) {
461   assert(shouldSignPointer(Schema));
462   llvm::ConstantInt *OtherDiscriminator =
463       getPointerAuthOtherDiscriminator(Schema, SchemaDecl, SchemaType);
464 
465   return getConstantSignedPointer(Pointer, Schema.getKey(), StorageAddress,
466                                   OtherDiscriminator);
467 }
468 
469 /// If applicable, sign a given constant function pointer with the ABI rules for
470 /// functionType.
471 llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer,
472                                                   QualType FunctionType) {
473   assert(FunctionType->isFunctionType() ||
474          FunctionType->isFunctionReferenceType() ||
475          FunctionType->isFunctionPointerType());
476 
477   if (auto PointerAuth = getFunctionPointerAuthInfo(FunctionType))
478     return getConstantSignedPointer(
479         Pointer, PointerAuth.getKey(), /*StorageAddress=*/nullptr,
480         cast_or_null<llvm::ConstantInt>(PointerAuth.getDiscriminator()));
481 
482   return Pointer;
483 }
484 
485 llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD,
486                                                   llvm::Type *Ty) {
487   const auto *FD = cast<FunctionDecl>(GD.getDecl());
488   QualType FuncType = FD->getType();
489 
490   // Annoyingly, K&R functions have prototypes in the clang AST, but
491   // expressions referring to them are unprototyped.
492   if (!FD->hasPrototype())
493     if (const auto *Proto = FuncType->getAs<FunctionProtoType>())
494       FuncType = Context.getFunctionNoProtoType(Proto->getReturnType(),
495                                                 Proto->getExtInfo());
496 
497   return getFunctionPointer(getRawFunctionPointer(GD, Ty), FuncType);
498 }
499 
500 CGPointerAuthInfo CodeGenModule::getMemberFunctionPointerAuthInfo(QualType FT) {
501   assert(FT->getAs<MemberPointerType>() && "MemberPointerType expected");
502   const auto &Schema = getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers;
503   if (!Schema)
504     return CGPointerAuthInfo();
505 
506   assert(!Schema.isAddressDiscriminated() &&
507          "function pointers cannot use address-specific discrimination");
508 
509   llvm::ConstantInt *Discriminator =
510       getPointerAuthOtherDiscriminator(Schema, GlobalDecl(), FT);
511   return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),
512                            /* IsIsaPointer */ false,
513                            /* AuthenticatesNullValues */ false, Discriminator);
514 }
515 
516 llvm::Constant *CodeGenModule::getMemberFunctionPointer(llvm::Constant *Pointer,
517                                                         QualType FT) {
518   if (CGPointerAuthInfo PointerAuth = getMemberFunctionPointerAuthInfo(FT))
519     return getConstantSignedPointer(
520         Pointer, PointerAuth.getKey(), nullptr,
521         cast_or_null<llvm::ConstantInt>(PointerAuth.getDiscriminator()));
522 
523   if (const auto *MFT = dyn_cast<MemberPointerType>(FT.getTypePtr())) {
524     if (MFT->hasPointeeToToCFIUncheckedCalleeFunctionType())
525       Pointer = llvm::NoCFIValue::get(cast<llvm::GlobalValue>(Pointer));
526   }
527 
528   return Pointer;
529 }
530 
531 llvm::Constant *CodeGenModule::getMemberFunctionPointer(const FunctionDecl *FD,
532                                                         llvm::Type *Ty) {
533   QualType FT = FD->getType();
534   FT = getContext().getMemberPointerType(FT, /*Qualifier=*/nullptr,
535                                          cast<CXXMethodDecl>(FD)->getParent());
536   return getMemberFunctionPointer(getRawFunctionPointer(FD, Ty), FT);
537 }
538 
539 std::optional<PointerAuthQualifier>
540 CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass) {
541   auto DefaultAuthentication = getCodeGenOpts().PointerAuth.CXXVTablePointers;
542   if (!DefaultAuthentication)
543     return std::nullopt;
544   const CXXRecordDecl *PrimaryBase =
545       Context.baseForVTableAuthentication(ThisClass);
546 
547   unsigned Key = DefaultAuthentication.getKey();
548   bool AddressDiscriminated = DefaultAuthentication.isAddressDiscriminated();
549   auto DefaultDiscrimination = DefaultAuthentication.getOtherDiscrimination();
550   unsigned TypeBasedDiscriminator =
551       Context.getPointerAuthVTablePointerDiscriminator(PrimaryBase);
552   unsigned Discriminator;
553   if (DefaultDiscrimination == PointerAuthSchema::Discrimination::Type) {
554     Discriminator = TypeBasedDiscriminator;
555   } else if (DefaultDiscrimination ==
556              PointerAuthSchema::Discrimination::Constant) {
557     Discriminator = DefaultAuthentication.getConstantDiscrimination();
558   } else {
559     assert(DefaultDiscrimination == PointerAuthSchema::Discrimination::None);
560     Discriminator = 0;
561   }
562   if (auto ExplicitAuthentication =
563           PrimaryBase->getAttr<VTablePointerAuthenticationAttr>()) {
564     auto ExplicitAddressDiscrimination =
565         ExplicitAuthentication->getAddressDiscrimination();
566     auto ExplicitDiscriminator =
567         ExplicitAuthentication->getExtraDiscrimination();
568 
569     unsigned ExplicitKey = ExplicitAuthentication->getKey();
570     if (ExplicitKey == VTablePointerAuthenticationAttr::NoKey)
571       return std::nullopt;
572 
573     if (ExplicitKey != VTablePointerAuthenticationAttr::DefaultKey) {
574       if (ExplicitKey == VTablePointerAuthenticationAttr::ProcessIndependent)
575         Key = (unsigned)PointerAuthSchema::ARM8_3Key::ASDA;
576       else {
577         assert(ExplicitKey ==
578                VTablePointerAuthenticationAttr::ProcessDependent);
579         Key = (unsigned)PointerAuthSchema::ARM8_3Key::ASDB;
580       }
581     }
582 
583     if (ExplicitAddressDiscrimination !=
584         VTablePointerAuthenticationAttr::DefaultAddressDiscrimination)
585       AddressDiscriminated =
586           ExplicitAddressDiscrimination ==
587           VTablePointerAuthenticationAttr::AddressDiscrimination;
588 
589     if (ExplicitDiscriminator ==
590         VTablePointerAuthenticationAttr::TypeDiscrimination)
591       Discriminator = TypeBasedDiscriminator;
592     else if (ExplicitDiscriminator ==
593              VTablePointerAuthenticationAttr::CustomDiscrimination)
594       Discriminator = ExplicitAuthentication->getCustomDiscriminationValue();
595     else if (ExplicitDiscriminator ==
596              VTablePointerAuthenticationAttr::NoExtraDiscrimination)
597       Discriminator = 0;
598   }
599   return PointerAuthQualifier::Create(Key, AddressDiscriminated, Discriminator,
600                                       PointerAuthenticationMode::SignAndAuth,
601                                       /* IsIsaPointer */ false,
602                                       /* AuthenticatesNullValues */ false);
603 }
604 
605 std::optional<PointerAuthQualifier>
606 CodeGenModule::getVTablePointerAuthentication(const CXXRecordDecl *Record) {
607   if (!Record->getDefinition() || !Record->isPolymorphic())
608     return std::nullopt;
609 
610   auto Existing = VTablePtrAuthInfos.find(Record);
611   std::optional<PointerAuthQualifier> Authentication;
612   if (Existing != VTablePtrAuthInfos.end()) {
613     Authentication = Existing->getSecond();
614   } else {
615     Authentication = computeVTPointerAuthentication(Record);
616     VTablePtrAuthInfos.insert(std::make_pair(Record, Authentication));
617   }
618   return Authentication;
619 }
620 
621 std::optional<CGPointerAuthInfo>
622 CodeGenModule::getVTablePointerAuthInfo(CodeGenFunction *CGF,
623                                         const CXXRecordDecl *Record,
624                                         llvm::Value *StorageAddress) {
625   auto Authentication = getVTablePointerAuthentication(Record);
626   if (!Authentication)
627     return std::nullopt;
628 
629   llvm::Value *Discriminator = nullptr;
630   if (auto ExtraDiscriminator = Authentication->getExtraDiscriminator())
631     Discriminator = llvm::ConstantInt::get(IntPtrTy, ExtraDiscriminator);
632 
633   if (Authentication->isAddressDiscriminated()) {
634     assert(StorageAddress &&
635            "address not provided for address-discriminated schema");
636     if (Discriminator)
637       Discriminator =
638           CGF->EmitPointerAuthBlendDiscriminator(StorageAddress, Discriminator);
639     else
640       Discriminator = CGF->Builder.CreatePtrToInt(StorageAddress, IntPtrTy);
641   }
642 
643   return CGPointerAuthInfo(Authentication->getKey(),
644                            PointerAuthenticationMode::SignAndAuth,
645                            /* IsIsaPointer */ false,
646                            /* AuthenticatesNullValues */ false, Discriminator);
647 }
648 
649 llvm::Value *CodeGenFunction::authPointerToPointerCast(llvm::Value *ResultPtr,
650                                                        QualType SourceType,
651                                                        QualType DestType) {
652   CGPointerAuthInfo CurAuthInfo, NewAuthInfo;
653   if (SourceType->isSignableType(getContext()))
654     CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType);
655 
656   if (DestType->isSignableType(getContext()))
657     NewAuthInfo = getPointerAuthInfoForType(CGM, DestType);
658 
659   if (!CurAuthInfo && !NewAuthInfo)
660     return ResultPtr;
661 
662   // If only one side of the cast is a function pointer, then we still need to
663   // resign to handle casts to/from opaque pointers.
664   if (!CurAuthInfo && DestType->isFunctionPointerType())
665     CurAuthInfo = CGM.getFunctionPointerAuthInfo(SourceType);
666 
667   if (!NewAuthInfo && SourceType->isFunctionPointerType())
668     NewAuthInfo = CGM.getFunctionPointerAuthInfo(DestType);
669 
670   return emitPointerAuthResign(ResultPtr, DestType, CurAuthInfo, NewAuthInfo,
671                                /*IsKnownNonNull=*/false);
672 }
673 
674 Address CodeGenFunction::authPointerToPointerCast(Address Ptr,
675                                                   QualType SourceType,
676                                                   QualType DestType) {
677   CGPointerAuthInfo CurAuthInfo, NewAuthInfo;
678   if (SourceType->isSignableType(getContext()))
679     CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType);
680 
681   if (DestType->isSignableType(getContext()))
682     NewAuthInfo = getPointerAuthInfoForType(CGM, DestType);
683 
684   if (!CurAuthInfo && !NewAuthInfo)
685     return Ptr;
686 
687   if (!CurAuthInfo && DestType->isFunctionPointerType()) {
688     // When casting a non-signed pointer to a function pointer, just set the
689     // auth info on Ptr to the assumed schema. The pointer will be resigned to
690     // the effective type when used.
691     Ptr.setPointerAuthInfo(CGM.getFunctionPointerAuthInfo(SourceType));
692     return Ptr;
693   }
694 
695   if (!NewAuthInfo && SourceType->isFunctionPointerType()) {
696     NewAuthInfo = CGM.getFunctionPointerAuthInfo(DestType);
697     Ptr = Ptr.getResignedAddress(NewAuthInfo, *this);
698     Ptr.setPointerAuthInfo(CGPointerAuthInfo());
699     return Ptr;
700   }
701 
702   return Ptr;
703 }
704 
705 Address CodeGenFunction::getAsNaturalAddressOf(Address Addr,
706                                                QualType PointeeTy) {
707   CGPointerAuthInfo Info =
708       PointeeTy.isNull() ? CGPointerAuthInfo()
709                          : CGM.getPointerAuthInfoForPointeeType(PointeeTy);
710   return Addr.getResignedAddress(Info, *this);
711 }
712 
713 Address Address::getResignedAddress(const CGPointerAuthInfo &NewInfo,
714                                     CodeGenFunction &CGF) const {
715   assert(isValid() && "pointer isn't valid");
716   CGPointerAuthInfo CurInfo = getPointerAuthInfo();
717   llvm::Value *Val;
718 
719   // Nothing to do if neither the current or the new ptrauth info needs signing.
720   if (!CurInfo.isSigned() && !NewInfo.isSigned())
721     return Address(getBasePointer(), getElementType(), getAlignment(),
722                    isKnownNonNull());
723 
724   assert(ElementType && "Effective type has to be set");
725   assert(!Offset && "unexpected non-null offset");
726 
727   // If the current and the new ptrauth infos are the same and the offset is
728   // null, just cast the base pointer to the effective type.
729   if (CurInfo == NewInfo && !hasOffset())
730     Val = getBasePointer();
731   else
732     Val = CGF.emitPointerAuthResign(getBasePointer(), QualType(), CurInfo,
733                                     NewInfo, isKnownNonNull());
734 
735   return Address(Val, getElementType(), getAlignment(), NewInfo,
736                  /*Offset=*/nullptr, isKnownNonNull());
737 }
738 
739 llvm::Value *Address::emitRawPointerSlow(CodeGenFunction &CGF) const {
740   return CGF.getAsNaturalPointerTo(*this, QualType());
741 }
742 
743 llvm::Value *LValue::getPointer(CodeGenFunction &CGF) const {
744   assert(isSimple());
745   return emitResignedPointer(getType(), CGF);
746 }
747 
748 llvm::Value *LValue::emitResignedPointer(QualType PointeeTy,
749                                          CodeGenFunction &CGF) const {
750   assert(isSimple());
751   return CGF.getAsNaturalAddressOf(Addr, PointeeTy).getBasePointer();
752 }
753 
754 llvm::Value *LValue::emitRawPointer(CodeGenFunction &CGF) const {
755   assert(isSimple());
756   return Addr.isValid() ? Addr.emitRawPointer(CGF) : nullptr;
757 }
758