LLVM 24.0.0git
CrossDSOCFI.cpp
Go to the documentation of this file.
1//===-- CrossDSOCFI.cpp - Externalize this module's CFI checks ------------===//
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 pass exports all llvm.bitset's found in the module in the form of a
10// __cfi_check function, which can be used to verify cross-DSO call targets.
11//
12//===----------------------------------------------------------------------===//
13
15#include "llvm/ADT/SetVector.h"
16#include "llvm/ADT/Statistic.h"
17#include "llvm/IR/Constants.h"
18#include "llvm/IR/Function.h"
20#include "llvm/IR/IRBuilder.h"
22#include "llvm/IR/Intrinsics.h"
23#include "llvm/IR/MDBuilder.h"
24#include "llvm/IR/Module.h"
26
27using namespace llvm;
28
29#define DEBUG_TYPE "cross-dso-cfi"
30
31STATISTIC(NumTypeIds, "Number of unique type identifiers");
32
33namespace {
34
35struct CrossDSOCFI {
36 MDNode *VeryLikelyWeights;
37
38 ConstantInt *extractNumericTypeId(MDNode *MD);
39 void buildCFICheck(Module &M);
40 bool runOnModule(Module &M);
41};
42
43} // anonymous namespace
44
45/// Extracts a numeric type identifier from an MDNode containing type metadata.
46ConstantInt *CrossDSOCFI::extractNumericTypeId(MDNode *MD) {
47 // This check excludes vtables for classes inside anonymous namespaces.
48 auto TM = dyn_cast<ValueAsMetadata>(MD->getOperand(1));
49 if (!TM)
50 return nullptr;
51 auto C = dyn_cast_or_null<ConstantInt>(TM->getValue());
52 if (!C) return nullptr;
53 // We are looking for i64 constants.
54 if (C->getBitWidth() != 64) return nullptr;
55
56 return C;
57}
58
59/// buildCFICheck - emits __cfi_check for the current module.
60void CrossDSOCFI::buildCFICheck(Module &M) {
61 // FIXME: verify that __cfi_check ends up near the end of the code section,
62 // but before the jump slots created in LowerTypeTests.
63 SetVector<uint64_t> TypeIds;
65 for (GlobalObject &GO : M.global_objects()) {
66 Types.clear();
67 GO.getMetadata(LLVMContext::MD_type, Types);
68 for (MDNode *Type : Types)
69 if (ConstantInt *TypeId = extractNumericTypeId(Type))
70 TypeIds.insert(TypeId->getZExtValue());
71 }
72
73 NamedMDNode *CfiFunctionsMD = M.getNamedMetadata("cfi.functions");
74 if (CfiFunctionsMD) {
75 for (auto *Func : CfiFunctionsMD->operands()) {
76 assert(Func->getNumOperands() >= 3);
77 assert(isa<ConstantAsMetadata>(Func->getOperand(2)));
78 for (unsigned I = 3; I < Func->getNumOperands(); ++I)
79 if (ConstantInt *TypeId =
80 extractNumericTypeId(cast<MDNode>(Func->getOperand(I).get())))
81 TypeIds.insert(TypeId->getZExtValue());
82 }
83 }
84
85 LLVMContext &Ctx = M.getContext();
86 FunctionCallee C = M.getOrInsertFunction(
87 "__cfi_check", Type::getVoidTy(Ctx), Type::getInt64Ty(Ctx),
88 PointerType::getUnqual(Ctx), PointerType::getUnqual(Ctx));
89 Function *F = cast<Function>(C.getCallee());
90 // Take over the existing function. The frontend emits a weak stub so that the
91 // linker knows about the symbol; this pass replaces the function body.
92 F->deleteBody();
93 F->setAlignment(Align(4096));
94
95 Triple T(M.getTargetTriple());
96 if (T.isARM() || T.isThumb())
97 F->addFnAttr("target-features", "+thumb-mode");
98
99 auto args = F->arg_begin();
100 Value &CallSiteTypeId = *(args++);
101 CallSiteTypeId.setName("CallSiteTypeId");
102 Value &Addr = *(args++);
103 Addr.setName("Addr");
104 Value &CFICheckFailData = *(args++);
105 CFICheckFailData.setName("CFICheckFailData");
106 assert(args == F->arg_end());
107
108 BasicBlock *BB = BasicBlock::Create(Ctx, "entry", F);
109 BasicBlock *ExitBB = BasicBlock::Create(Ctx, "exit", F);
110
111 BasicBlock *TrapBB = BasicBlock::Create(Ctx, "fail", F);
112 IRBuilder<> IRBFail(TrapBB);
113 FunctionCallee CFICheckFailFn = M.getOrInsertFunction(
114 "__cfi_check_fail", Type::getVoidTy(Ctx), PointerType::getUnqual(Ctx),
115 PointerType::getUnqual(Ctx));
116 IRBFail.CreateCall(CFICheckFailFn, {&CFICheckFailData, &Addr});
117 IRBFail.CreateBr(ExitBB);
118
119 IRBuilder<> IRBExit(ExitBB);
120 IRBExit.CreateRetVoid();
121
122 IRBuilder<> IRB(BB);
123 SwitchInst *SI = IRB.CreateSwitch(&CallSiteTypeId, TrapBB, TypeIds.size());
124 for (uint64_t TypeId : TypeIds) {
125 ConstantInt *CaseTypeId = ConstantInt::get(Type::getInt64Ty(Ctx), TypeId);
126 BasicBlock *TestBB = BasicBlock::Create(Ctx, "test", F);
127 IRBuilder<> IRBTest(TestBB);
128
129 Value *Test = IRBTest.CreateIntrinsic(
130 Intrinsic::type_test,
131 {&Addr,
133 CondBrInst *BI = IRBTest.CreateCondBr(Test, ExitBB, TrapBB);
134 BI->setMetadata(LLVMContext::MD_prof, VeryLikelyWeights);
135
136 SI->addCase(CaseTypeId, TestBB);
137 ++NumTypeIds;
138 }
139}
140
141bool CrossDSOCFI::runOnModule(Module &M) {
142 VeryLikelyWeights = MDBuilder(M.getContext()).createLikelyBranchWeights();
143 if (M.getModuleFlag("Cross-DSO CFI") == nullptr)
144 return false;
145 buildCFICheck(M);
146 return true;
147}
148
150 CrossDSOCFI Impl;
151 bool Changed = Impl.runOnModule(M);
152 if (!Changed)
153 return PreservedAnalyses::all();
155}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Machine Check Debug Module
#define T
nvptx lower args
This file implements a set that has insertion order iteration characteristics.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition BasicBlock.h:206
static ConstantAsMetadata * get(Constant *C)
Definition Metadata.h:537
This is the shared class of boolean and integer constants.
Definition Constants.h:87
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
Metadata node.
Definition Metadata.h:1069
const MDOperand & getOperand(unsigned I) const
Definition Metadata.h:1426
static LLVM_ABI MetadataAsValue * get(LLVMContext &Context, Metadata *MD)
Definition Metadata.cpp:111
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
iterator_range< op_iterator > operands()
Definition Metadata.h:1851
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
size_type size() const
Determine the number of elements in the SetVector.
Definition SetVector.h:103
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:157
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
Definition Value.cpp:394
Changed
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
@ BasicBlock
Various leaf nodes.
Definition ISDOpcodes.h:81
NodeAddr< FuncNode * > Func
Definition RDFGraph.h:393
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39