xref: /src/contrib/llvm-project/llvm/lib/CodeGen/CFGuardLongjmp.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1706b4fc4SDimitry Andric //===-- CFGuardLongjmp.cpp - Longjmp symbols for CFGuard --------*- C++ -*-===//
2706b4fc4SDimitry Andric //
3706b4fc4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4706b4fc4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5706b4fc4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6706b4fc4SDimitry Andric //
7706b4fc4SDimitry Andric //===----------------------------------------------------------------------===//
8706b4fc4SDimitry Andric ///
9706b4fc4SDimitry Andric /// \file
10706b4fc4SDimitry Andric /// This file contains a machine function pass to insert a symbol after each
11706b4fc4SDimitry Andric /// call to _setjmp and store this in the MachineFunction's LongjmpTargets
12706b4fc4SDimitry Andric /// vector. This will be used to emit the table of valid longjmp targets used
13706b4fc4SDimitry Andric /// by Control Flow Guard.
14706b4fc4SDimitry Andric ///
15706b4fc4SDimitry Andric //===----------------------------------------------------------------------===//
16706b4fc4SDimitry Andric 
17706b4fc4SDimitry Andric #include "llvm/ADT/Statistic.h"
18706b4fc4SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
19706b4fc4SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
20706b4fc4SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
21706b4fc4SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
22706b4fc4SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
23706b4fc4SDimitry Andric #include "llvm/CodeGen/Passes.h"
24ac9a064cSDimitry Andric #include "llvm/IR/Module.h"
25706b4fc4SDimitry Andric #include "llvm/InitializePasses.h"
26706b4fc4SDimitry Andric 
27706b4fc4SDimitry Andric using namespace llvm;
28706b4fc4SDimitry Andric 
29706b4fc4SDimitry Andric #define DEBUG_TYPE "cfguard-longjmp"
30706b4fc4SDimitry Andric 
31706b4fc4SDimitry Andric STATISTIC(CFGuardLongjmpTargets,
32706b4fc4SDimitry Andric           "Number of Control Flow Guard longjmp targets");
33706b4fc4SDimitry Andric 
34706b4fc4SDimitry Andric namespace {
35706b4fc4SDimitry Andric 
36706b4fc4SDimitry Andric /// MachineFunction pass to insert a symbol after each call to _setjmp and store
37706b4fc4SDimitry Andric /// this in the MachineFunction's LongjmpTargets vector.
38706b4fc4SDimitry Andric class CFGuardLongjmp : public MachineFunctionPass {
39706b4fc4SDimitry Andric public:
40706b4fc4SDimitry Andric   static char ID;
41706b4fc4SDimitry Andric 
CFGuardLongjmp()42706b4fc4SDimitry Andric   CFGuardLongjmp() : MachineFunctionPass(ID) {
43706b4fc4SDimitry Andric     initializeCFGuardLongjmpPass(*PassRegistry::getPassRegistry());
44706b4fc4SDimitry Andric   }
45706b4fc4SDimitry Andric 
getPassName() const46706b4fc4SDimitry Andric   StringRef getPassName() const override {
47706b4fc4SDimitry Andric     return "Control Flow Guard longjmp targets";
48706b4fc4SDimitry Andric   }
49706b4fc4SDimitry Andric 
50706b4fc4SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
51706b4fc4SDimitry Andric };
52706b4fc4SDimitry Andric 
53706b4fc4SDimitry Andric } // end anonymous namespace
54706b4fc4SDimitry Andric 
55706b4fc4SDimitry Andric char CFGuardLongjmp::ID = 0;
56706b4fc4SDimitry Andric 
57706b4fc4SDimitry Andric INITIALIZE_PASS(CFGuardLongjmp, "CFGuardLongjmp",
58706b4fc4SDimitry Andric                 "Insert symbols at valid longjmp targets for /guard:cf", false,
59706b4fc4SDimitry Andric                 false)
createCFGuardLongjmpPass()60706b4fc4SDimitry Andric FunctionPass *llvm::createCFGuardLongjmpPass() { return new CFGuardLongjmp(); }
61706b4fc4SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)62706b4fc4SDimitry Andric bool CFGuardLongjmp::runOnMachineFunction(MachineFunction &MF) {
63706b4fc4SDimitry Andric 
64706b4fc4SDimitry Andric   // Skip modules for which the cfguard flag is not set.
65ac9a064cSDimitry Andric   if (!MF.getFunction().getParent()->getModuleFlag("cfguard"))
66706b4fc4SDimitry Andric     return false;
67706b4fc4SDimitry Andric 
68706b4fc4SDimitry Andric   // Skip functions that do not have calls to _setjmp.
69706b4fc4SDimitry Andric   if (!MF.getFunction().callsFunctionThatReturnsTwice())
70706b4fc4SDimitry Andric     return false;
71706b4fc4SDimitry Andric 
72706b4fc4SDimitry Andric   SmallVector<MachineInstr *, 8> SetjmpCalls;
73706b4fc4SDimitry Andric 
74706b4fc4SDimitry Andric   // Iterate over all instructions in the function and add calls to functions
75706b4fc4SDimitry Andric   // that return twice to the list of targets.
76706b4fc4SDimitry Andric   for (MachineBasicBlock &MBB : MF) {
77706b4fc4SDimitry Andric     for (MachineInstr &MI : MBB) {
78706b4fc4SDimitry Andric 
79706b4fc4SDimitry Andric       // Skip instructions that are not calls.
80706b4fc4SDimitry Andric       if (!MI.isCall() || MI.getNumOperands() < 1)
81706b4fc4SDimitry Andric         continue;
82706b4fc4SDimitry Andric 
83706b4fc4SDimitry Andric       // Iterate over operands to find calls to global functions.
84706b4fc4SDimitry Andric       for (MachineOperand &MO : MI.operands()) {
85706b4fc4SDimitry Andric         if (!MO.isGlobal())
86706b4fc4SDimitry Andric           continue;
87706b4fc4SDimitry Andric 
88706b4fc4SDimitry Andric         auto *F = dyn_cast<Function>(MO.getGlobal());
89706b4fc4SDimitry Andric         if (!F)
90706b4fc4SDimitry Andric           continue;
91706b4fc4SDimitry Andric 
92706b4fc4SDimitry Andric         // If the instruction calls a function that returns twice, add
93706b4fc4SDimitry Andric         // it to the list of targets.
94706b4fc4SDimitry Andric         if (F->hasFnAttribute(Attribute::ReturnsTwice)) {
95706b4fc4SDimitry Andric           SetjmpCalls.push_back(&MI);
96706b4fc4SDimitry Andric           break;
97706b4fc4SDimitry Andric         }
98706b4fc4SDimitry Andric       }
99706b4fc4SDimitry Andric     }
100706b4fc4SDimitry Andric   }
101706b4fc4SDimitry Andric 
102706b4fc4SDimitry Andric   if (SetjmpCalls.empty())
103706b4fc4SDimitry Andric     return false;
104706b4fc4SDimitry Andric 
105706b4fc4SDimitry Andric   unsigned SetjmpNum = 0;
106706b4fc4SDimitry Andric 
107706b4fc4SDimitry Andric   // For each possible target, create a new symbol and insert it immediately
108706b4fc4SDimitry Andric   // after the call to setjmp. Add this symbol to the MachineFunction's list
109706b4fc4SDimitry Andric   // of longjmp targets.
110706b4fc4SDimitry Andric   for (MachineInstr *Setjmp : SetjmpCalls) {
111706b4fc4SDimitry Andric     SmallString<128> SymbolName;
112706b4fc4SDimitry Andric     raw_svector_ostream(SymbolName) << "$cfgsj_" << MF.getName() << SetjmpNum++;
113706b4fc4SDimitry Andric     MCSymbol *SjSymbol = MF.getContext().getOrCreateSymbol(SymbolName);
114706b4fc4SDimitry Andric 
115706b4fc4SDimitry Andric     Setjmp->setPostInstrSymbol(MF, SjSymbol);
116706b4fc4SDimitry Andric     MF.addLongjmpTarget(SjSymbol);
117706b4fc4SDimitry Andric     CFGuardLongjmpTargets++;
118706b4fc4SDimitry Andric   }
119706b4fc4SDimitry Andric 
120706b4fc4SDimitry Andric   return true;
121706b4fc4SDimitry Andric }
122