1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 03:02:36 +01:00
llvm-mirror/lib/CodeGen/EHContGuardCatchret.cpp
Arlo Siemsen d4eefe6819 Add ehcont section support
In the future Windows will enable Control-flow Enforcement Technology (CET aka shadow stacks). To protect the path where the context is updated during exception handling, the binary is required to enumerate valid unwind entrypoints in a dedicated section which is validated when the context is being set during exception handling.

This change allows llvm to generate the section that contains the appropriate symbol references in the form expected by the msvc linker.

This feature is enabled through a new module flag, ehcontguard, which was modelled on the cfguard flag.

The change includes a test that when the module flag is enabled the section is correctly generated.

The set of exception continuation information includes returns from exceptional control flow (catchret in llvm).

In order to collect catchret we:
1) Includes an additional flag on machine basic blocks to indicate that the given block is the target of a catchret operation,
2) Introduces a new machine function pass to insert and collect symbols at the start of each block, and
3) Combines these targets with the other EHCont targets that were already being collected.

Change originally authored by Daniel Frampton <dframpto@microsoft.com>

For more details, see MSVC documentation for `/guard:ehcont`
  https://docs.microsoft.com/en-us/cpp/build/reference/guard-enable-eh-continuation-metadata

Reviewed By: pengfei

Differential Revision: https://reviews.llvm.org/D94835
2021-02-15 14:27:12 +08:00

85 lines
2.5 KiB
C++

//===-- EHContGuardCatchret.cpp - Catchret target symbols -------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file contains a machine function pass to insert a symbol before each
/// valid catchret target and store this in the MachineFunction's
/// CatchRetTargets vector. This will be used to emit the table of valid targets
/// used by EHCont Guard.
///
//===----------------------------------------------------------------------===//
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/InitializePasses.h"
using namespace llvm;
#define DEBUG_TYPE "ehcontguard-catchret"
STATISTIC(EHContGuardCatchretTargets,
"Number of EHCont Guard catchret targets");
namespace {
/// MachineFunction pass to insert a symbol before each valid catchret target
/// and store these in the MachineFunction's CatchRetTargets vector.
class EHContGuardCatchret : public MachineFunctionPass {
public:
static char ID;
EHContGuardCatchret() : MachineFunctionPass(ID) {
initializeEHContGuardCatchretPass(*PassRegistry::getPassRegistry());
}
StringRef getPassName() const override {
return "EH Cont Guard catchret targets";
}
bool runOnMachineFunction(MachineFunction &MF) override;
};
} // end anonymous namespace
char EHContGuardCatchret::ID = 0;
INITIALIZE_PASS(EHContGuardCatchret, "EHContGuardCatchret",
"Insert symbols at valid catchret targets for /guard:ehcont",
false, false)
FunctionPass *llvm::createEHContGuardCatchretPass() {
return new EHContGuardCatchret();
}
bool EHContGuardCatchret::runOnMachineFunction(MachineFunction &MF) {
// Skip modules for which the ehcontguard flag is not set.
if (!MF.getMMI().getModule()->getModuleFlag("ehcontguard"))
return false;
// Skip functions that do not have catchret
if (!MF.hasEHCatchret())
return false;
bool Result = false;
for (MachineBasicBlock &MBB : MF) {
if (MBB.isEHCatchretTarget()) {
MF.addCatchretTarget(MBB.getEHCatchretSymbol());
EHContGuardCatchretTargets++;
Result = true;
}
}
return Result;
}