xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/CFGuardLongjmp.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1480093f4SDimitry Andric //===-- CFGuardLongjmp.cpp - Longjmp symbols for CFGuard --------*- C++ -*-===//
2480093f4SDimitry Andric //
3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6480093f4SDimitry Andric //
7480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8480093f4SDimitry Andric ///
9480093f4SDimitry Andric /// \file
10480093f4SDimitry Andric /// This file contains a machine function pass to insert a symbol after each
11480093f4SDimitry Andric /// call to _setjmp and store this in the MachineFunction's LongjmpTargets
12480093f4SDimitry Andric /// vector. This will be used to emit the table of valid longjmp targets used
13480093f4SDimitry Andric /// by Control Flow Guard.
14480093f4SDimitry Andric ///
15480093f4SDimitry Andric //===----------------------------------------------------------------------===//
16480093f4SDimitry Andric 
17480093f4SDimitry Andric #include "llvm/ADT/Statistic.h"
18480093f4SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
19480093f4SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
20480093f4SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
21480093f4SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
22480093f4SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
23480093f4SDimitry Andric #include "llvm/CodeGen/Passes.h"
24*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h"
25480093f4SDimitry Andric #include "llvm/InitializePasses.h"
26480093f4SDimitry Andric 
27480093f4SDimitry Andric using namespace llvm;
28480093f4SDimitry Andric 
29480093f4SDimitry Andric #define DEBUG_TYPE "cfguard-longjmp"
30480093f4SDimitry Andric 
31480093f4SDimitry Andric STATISTIC(CFGuardLongjmpTargets,
32480093f4SDimitry Andric           "Number of Control Flow Guard longjmp targets");
33480093f4SDimitry Andric 
34480093f4SDimitry Andric namespace {
35480093f4SDimitry Andric 
36480093f4SDimitry Andric /// MachineFunction pass to insert a symbol after each call to _setjmp and store
37480093f4SDimitry Andric /// this in the MachineFunction's LongjmpTargets vector.
38480093f4SDimitry Andric class CFGuardLongjmp : public MachineFunctionPass {
39480093f4SDimitry Andric public:
40480093f4SDimitry Andric   static char ID;
41480093f4SDimitry Andric 
42480093f4SDimitry Andric   CFGuardLongjmp() : MachineFunctionPass(ID) {
43480093f4SDimitry Andric     initializeCFGuardLongjmpPass(*PassRegistry::getPassRegistry());
44480093f4SDimitry Andric   }
45480093f4SDimitry Andric 
46480093f4SDimitry Andric   StringRef getPassName() const override {
47480093f4SDimitry Andric     return "Control Flow Guard longjmp targets";
48480093f4SDimitry Andric   }
49480093f4SDimitry Andric 
50480093f4SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
51480093f4SDimitry Andric };
52480093f4SDimitry Andric 
53480093f4SDimitry Andric } // end anonymous namespace
54480093f4SDimitry Andric 
55480093f4SDimitry Andric char CFGuardLongjmp::ID = 0;
56480093f4SDimitry Andric 
57480093f4SDimitry Andric INITIALIZE_PASS(CFGuardLongjmp, "CFGuardLongjmp",
58480093f4SDimitry Andric                 "Insert symbols at valid longjmp targets for /guard:cf", false,
59480093f4SDimitry Andric                 false)
60480093f4SDimitry Andric FunctionPass *llvm::createCFGuardLongjmpPass() { return new CFGuardLongjmp(); }
61480093f4SDimitry Andric 
62480093f4SDimitry Andric bool CFGuardLongjmp::runOnMachineFunction(MachineFunction &MF) {
63480093f4SDimitry Andric 
64480093f4SDimitry Andric   // Skip modules for which the cfguard flag is not set.
65*0fca6ea1SDimitry Andric   if (!MF.getFunction().getParent()->getModuleFlag("cfguard"))
66480093f4SDimitry Andric     return false;
67480093f4SDimitry Andric 
68480093f4SDimitry Andric   // Skip functions that do not have calls to _setjmp.
69480093f4SDimitry Andric   if (!MF.getFunction().callsFunctionThatReturnsTwice())
70480093f4SDimitry Andric     return false;
71480093f4SDimitry Andric 
72480093f4SDimitry Andric   SmallVector<MachineInstr *, 8> SetjmpCalls;
73480093f4SDimitry Andric 
74480093f4SDimitry Andric   // Iterate over all instructions in the function and add calls to functions
75480093f4SDimitry Andric   // that return twice to the list of targets.
76480093f4SDimitry Andric   for (MachineBasicBlock &MBB : MF) {
77480093f4SDimitry Andric     for (MachineInstr &MI : MBB) {
78480093f4SDimitry Andric 
79480093f4SDimitry Andric       // Skip instructions that are not calls.
80480093f4SDimitry Andric       if (!MI.isCall() || MI.getNumOperands() < 1)
81480093f4SDimitry Andric         continue;
82480093f4SDimitry Andric 
83480093f4SDimitry Andric       // Iterate over operands to find calls to global functions.
84480093f4SDimitry Andric       for (MachineOperand &MO : MI.operands()) {
85480093f4SDimitry Andric         if (!MO.isGlobal())
86480093f4SDimitry Andric           continue;
87480093f4SDimitry Andric 
88480093f4SDimitry Andric         auto *F = dyn_cast<Function>(MO.getGlobal());
89480093f4SDimitry Andric         if (!F)
90480093f4SDimitry Andric           continue;
91480093f4SDimitry Andric 
92480093f4SDimitry Andric         // If the instruction calls a function that returns twice, add
93480093f4SDimitry Andric         // it to the list of targets.
94480093f4SDimitry Andric         if (F->hasFnAttribute(Attribute::ReturnsTwice)) {
95480093f4SDimitry Andric           SetjmpCalls.push_back(&MI);
96480093f4SDimitry Andric           break;
97480093f4SDimitry Andric         }
98480093f4SDimitry Andric       }
99480093f4SDimitry Andric     }
100480093f4SDimitry Andric   }
101480093f4SDimitry Andric 
102480093f4SDimitry Andric   if (SetjmpCalls.empty())
103480093f4SDimitry Andric     return false;
104480093f4SDimitry Andric 
105480093f4SDimitry Andric   unsigned SetjmpNum = 0;
106480093f4SDimitry Andric 
107480093f4SDimitry Andric   // For each possible target, create a new symbol and insert it immediately
108480093f4SDimitry Andric   // after the call to setjmp. Add this symbol to the MachineFunction's list
109480093f4SDimitry Andric   // of longjmp targets.
110480093f4SDimitry Andric   for (MachineInstr *Setjmp : SetjmpCalls) {
111480093f4SDimitry Andric     SmallString<128> SymbolName;
112480093f4SDimitry Andric     raw_svector_ostream(SymbolName) << "$cfgsj_" << MF.getName() << SetjmpNum++;
113480093f4SDimitry Andric     MCSymbol *SjSymbol = MF.getContext().getOrCreateSymbol(SymbolName);
114480093f4SDimitry Andric 
115480093f4SDimitry Andric     Setjmp->setPostInstrSymbol(MF, SjSymbol);
116480093f4SDimitry Andric     MF.addLongjmpTarget(SjSymbol);
117480093f4SDimitry Andric     CFGuardLongjmpTargets++;
118480093f4SDimitry Andric   }
119480093f4SDimitry Andric 
120480093f4SDimitry Andric   return true;
121480093f4SDimitry Andric }
122