|
18 | 18 | #include "llvm/Analysis/DomTreeUpdater.h"
|
19 | 19 | #include "llvm/Analysis/TargetTransformInfo.h"
|
20 | 20 | #include "llvm/CodeGen/RuntimeLibcalls.h"
|
| 21 | +#include "llvm/CodeGen/StackProtector.h" |
21 | 22 | #include "llvm/CodeGen/TargetLowering.h"
|
22 | 23 | #include "llvm/CodeGen/TargetPassConfig.h"
|
23 | 24 | #include "llvm/CodeGen/TargetSubtargetInfo.h"
|
|
28 | 29 | #include "llvm/IR/Dominators.h"
|
29 | 30 | #include "llvm/IR/EHPersonalities.h"
|
30 | 31 | #include "llvm/IR/Function.h"
|
| 32 | +#include "llvm/IR/IRBuilder.h" |
31 | 33 | #include "llvm/IR/Instructions.h"
|
32 | 34 | #include "llvm/IR/Module.h"
|
33 | 35 | #include "llvm/IR/Type.h"
|
|
37 | 39 | #include "llvm/Target/TargetMachine.h"
|
38 | 40 | #include "llvm/TargetParser/Triple.h"
|
39 | 41 | #include "llvm/Transforms/Utils/Local.h"
|
| 42 | +#include "llvm/Transforms/Utils/BasicBlockUtils.h" |
40 | 43 | #include <cstddef>
|
41 | 44 |
|
42 | 45 | using namespace llvm;
|
@@ -166,7 +169,136 @@ size_t DwarfEHPrepare::pruneUnreachableResumes(
|
166 | 169 | return ResumesLeft;
|
167 | 170 | }
|
168 | 171 |
|
| 172 | +/// If a landingpad block doesn't already have a cleanup case, add one |
| 173 | +/// that feeds directly into a resume instruction. |
| 174 | +static void addCleanupResumeToLandingPad(BasicBlock &BB, DomTreeUpdater *DTU) { |
| 175 | + LandingPadInst *LP = BB.getLandingPadInst(); |
| 176 | + if (LP->isCleanup()) |
| 177 | + return; |
| 178 | + |
| 179 | + // There will usually be code testing for the other kinds of exception |
| 180 | + // immediately after the landingpad. Working out the far end of that chain is |
| 181 | + // tricky, so put our test for the new cleanup case (i.e. selector == 0) at |
| 182 | + // the beginning. |
| 183 | + BasicBlock *ContBB = SplitBlock(&BB, LP->getNextNode(), DTU); |
| 184 | + BB.getTerminator()->eraseFromParent(); |
| 185 | + |
| 186 | + LP->setCleanup(true); |
| 187 | + IRBuilder<> B(&BB); |
| 188 | + Value *Selector = B.CreateExtractValue(LP, 1); |
| 189 | + Value *Cmp = B.CreateICmpEQ(Selector, ConstantInt::get(Selector->getType(), 0)); |
| 190 | + |
| 191 | + Function *F = BB.getParent(); |
| 192 | + LLVMContext &Ctx = F->getContext(); |
| 193 | + BasicBlock *ResumeBB = BasicBlock::Create(Ctx, "resume", F); |
| 194 | + ResumeInst::Create(LP, ResumeBB); |
| 195 | + |
| 196 | + B.CreateCondBr(Cmp, ResumeBB, ContBB); |
| 197 | + if (DTU) { |
| 198 | + SmallVector<DominatorTree::UpdateType> Updates; |
| 199 | + Updates.push_back({DominatorTree::Insert, &BB, ResumeBB}); |
| 200 | + DTU->applyUpdates(Updates); |
| 201 | + } |
| 202 | +} |
| 203 | + |
| 204 | +/// Create a basic block that has a `landingpad` instruction feeding |
| 205 | +/// directly into a `resume`. Will be set to the unwind destination of a new |
| 206 | +/// invoke. |
| 207 | +static BasicBlock *createCleanupResumeBB(Function &F, Type *LandingPadTy) { |
| 208 | + LLVMContext &Ctx = F.getContext(); |
| 209 | + BasicBlock *BB = BasicBlock::Create(Ctx, "cleanup_resume", &F); |
| 210 | + IRBuilder<> B(BB); |
| 211 | + |
| 212 | + // If this is going to be the only landingpad in the function, synthesize the |
| 213 | + // standard type all ABIs use, which is essentially `{ ptr, i32 }`. |
| 214 | + if (!LandingPadTy) |
| 215 | + LandingPadTy = |
| 216 | + StructType::get(Type::getInt8PtrTy(Ctx), IntegerType::get(Ctx, 32)); |
| 217 | + |
| 218 | + LandingPadInst *Except = B.CreateLandingPad(LandingPadTy, 0); |
| 219 | + Except->setCleanup(true); |
| 220 | + B.CreateResume(Except); |
| 221 | + return BB; |
| 222 | +} |
| 223 | + |
| 224 | +/// Convert a call that might throw into an invoke that unwinds to the specified |
| 225 | +/// simple landingpad/resume block. |
| 226 | +static void changeCallToInvokeResume(CallInst &CI, BasicBlock *CleanupResumeBB, |
| 227 | + DomTreeUpdater *DTU) { |
| 228 | + BasicBlock *BB = CI.getParent(); |
| 229 | + BasicBlock *ContBB = SplitBlock(BB, &CI, DTU); |
| 230 | + BB->getTerminator()->eraseFromParent(); |
| 231 | + |
| 232 | + IRBuilder<> B(BB); |
| 233 | + SmallVector<Value *> Args(CI.args()); |
| 234 | + SmallVector<OperandBundleDef> Bundles; |
| 235 | + CI.getOperandBundlesAsDefs(Bundles); |
| 236 | + InvokeInst *NewCall = |
| 237 | + B.CreateInvoke(CI.getFunctionType(), CI.getCalledOperand(), ContBB, |
| 238 | + CleanupResumeBB, Args, Bundles, CI.getName()); |
| 239 | + NewCall->setAttributes(CI.getAttributes()); |
| 240 | + NewCall->setCallingConv(CI.getCallingConv()); |
| 241 | + NewCall->copyMetadata(CI); |
| 242 | + |
| 243 | + if (DTU) { |
| 244 | + SmallVector<DominatorTree::UpdateType> Updates; |
| 245 | + Updates.push_back({DominatorTree::Insert, BB, CleanupResumeBB}); |
| 246 | + DTU->applyUpdates(Updates); |
| 247 | + } |
| 248 | + CI.replaceAllUsesWith(NewCall); |
| 249 | + CI.eraseFromParent(); |
| 250 | +} |
| 251 | + |
| 252 | +/// Ensure that any call in this function that might throw has an associated |
| 253 | +/// cleanup/resume that the stack protector can instrument later. Existing |
| 254 | +/// invokes will get an added `cleanup` clause if needed, calls will be |
| 255 | +/// converted to an invoke with trivial unwind followup. |
| 256 | +static void addCleanupPathsForStackProtector(Function &F, DomTreeUpdater *DTU) { |
| 257 | + // First add cleanup -> resume paths to all existing landingpads, noting what |
| 258 | + // type landingpads in this function actually have along the way. |
| 259 | + Type *LandingPadTy = nullptr; |
| 260 | + for (Function::iterator FI = F.begin(); FI != F.end(); ++FI) { |
| 261 | + BasicBlock &BB = *FI; |
| 262 | + if (LandingPadInst *LP = BB.getLandingPadInst()) { |
| 263 | + // We can assume the type is broadly compatible with { ptr, i32 } since |
| 264 | + // other parts of this pass already try to extract values from it. |
| 265 | + LandingPadTy = LP->getType(); |
| 266 | + addCleanupResumeToLandingPad(BB, DTU); |
| 267 | + } |
| 268 | + } |
| 269 | + |
| 270 | + // Next convert any call that might throw into an invoke to a resume |
| 271 | + // instruction for later instrumentation. |
| 272 | + BasicBlock *CleanupResumeBB = nullptr; |
| 273 | + for (Function::iterator FI = F.begin(); FI != F.end(); ++FI) { |
| 274 | + BasicBlock &BB = *FI; |
| 275 | + for (Instruction &I : BB) { |
| 276 | + CallInst *CI = dyn_cast<CallInst>(&I); |
| 277 | + if (!CI || CI->doesNotThrow()) |
| 278 | + continue; |
| 279 | + |
| 280 | + // Tail calls cannot use our stack so no need to check whether it was |
| 281 | + // corrupted. |
| 282 | + if (CI->isTailCall()) |
| 283 | + continue; |
| 284 | + |
| 285 | + if (!CleanupResumeBB) |
| 286 | + CleanupResumeBB = createCleanupResumeBB(F, LandingPadTy); |
| 287 | + |
| 288 | + changeCallToInvokeResume(*CI, CleanupResumeBB, DTU); |
| 289 | + |
| 290 | + // This block has been split, start again on its continuation. |
| 291 | + break; |
| 292 | + } |
| 293 | + } |
| 294 | +} |
| 295 | + |
169 | 296 | bool DwarfEHPrepare::InsertUnwindResumeCalls() {
|
| 297 | + if (F.hasPersonalityFn() && |
| 298 | + !isScopedEHPersonality(classifyEHPersonality(F.getPersonalityFn())) && |
| 299 | + StackProtector::requiresStackProtector(&F, nullptr)) |
| 300 | + addCleanupPathsForStackProtector(F, DTU); |
| 301 | + |
170 | 302 | SmallVector<ResumeInst *, 16> Resumes;
|
171 | 303 | SmallVector<LandingPadInst *, 16> CleanupLPads;
|
172 | 304 | if (F.doesNotThrow())
|
|
0 commit comments