1 //===- RealtimeSanitizer.cpp - RealtimeSanitizer instrumentation *- C++ -*-===// 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 file is a part of the RealtimeSanitizer, an LLVM transformation for 10 // detecting and reporting realtime safety violations. 11 // 12 // See also: llvm-project/compiler-rt/lib/rtsan/ 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "llvm/IR/Analysis.h" 17 #include "llvm/IR/IRBuilder.h" 18 #include "llvm/IR/InstIterator.h" 19 #include "llvm/IR/Module.h" 20 #include "llvm/Transforms/Utils/ModuleUtils.h" 21 22 #include "llvm/Demangle/Demangle.h" 23 #include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h" 24 25 using namespace llvm; 26 27 const char kRtsanModuleCtorName[] = "rtsan.module_ctor"; 28 const char kRtsanInitName[] = "__rtsan_ensure_initialized"; 29 30 static SmallVector<Type *> getArgTypes(ArrayRef<Value *> FunctionArgs) { 31 SmallVector<Type *> Types; 32 for (Value *Arg : FunctionArgs) 33 Types.push_back(Arg->getType()); 34 return Types; 35 } 36 37 static void insertCallBeforeInstruction(Function &Fn, Instruction &Instruction, 38 const char *FunctionName, 39 ArrayRef<Value *> FunctionArgs) { 40 LLVMContext &Context = Fn.getContext(); 41 FunctionType *FuncType = FunctionType::get(Type::getVoidTy(Context), 42 getArgTypes(FunctionArgs), false); 43 FunctionCallee Func = 44 Fn.getParent()->getOrInsertFunction(FunctionName, FuncType); 45 IRBuilder<> Builder{&Instruction}; 46 Builder.CreateCall(Func, FunctionArgs); 47 } 48 49 static void insertCallAtFunctionEntryPoint(Function &Fn, 50 const char *InsertFnName, 51 ArrayRef<Value *> FunctionArgs) { 52 insertCallBeforeInstruction(Fn, Fn.front().front(), InsertFnName, 53 FunctionArgs); 54 } 55 56 static void insertCallAtAllFunctionExitPoints(Function &Fn, 57 const char *InsertFnName, 58 ArrayRef<Value *> FunctionArgs) { 59 for (auto &I : instructions(Fn)) 60 if (isa<ReturnInst>(&I)) 61 insertCallBeforeInstruction(Fn, I, InsertFnName, FunctionArgs); 62 } 63 64 static PreservedAnalyses rtsanPreservedCFGAnalyses() { 65 PreservedAnalyses PA; 66 PA.preserveSet<CFGAnalyses>(); 67 return PA; 68 } 69 70 static PreservedAnalyses runSanitizeRealtime(Function &Fn) { 71 insertCallAtFunctionEntryPoint(Fn, "__rtsan_realtime_enter", {}); 72 insertCallAtAllFunctionExitPoints(Fn, "__rtsan_realtime_exit", {}); 73 return rtsanPreservedCFGAnalyses(); 74 } 75 76 static PreservedAnalyses runSanitizeRealtimeBlocking(Function &Fn) { 77 IRBuilder<> Builder(&Fn.front().front()); 78 Value *Name = Builder.CreateGlobalString(demangle(Fn.getName())); 79 insertCallAtFunctionEntryPoint(Fn, "__rtsan_notify_blocking_call", {Name}); 80 return rtsanPreservedCFGAnalyses(); 81 } 82 83 PreservedAnalyses RealtimeSanitizerPass::run(Module &M, 84 ModuleAnalysisManager &MAM) { 85 getOrCreateSanitizerCtorAndInitFunctions( 86 M, kRtsanModuleCtorName, kRtsanInitName, /*InitArgTypes=*/{}, 87 /*InitArgs=*/{}, 88 // This callback is invoked when the functions are created the first 89 // time. Hook them into the global ctors list in that case: 90 [&](Function *Ctor, FunctionCallee) { appendToGlobalCtors(M, Ctor, 0); }); 91 92 for (Function &F : M) { 93 if (F.hasFnAttribute(Attribute::SanitizeRealtime)) 94 runSanitizeRealtime(F); 95 96 if (F.hasFnAttribute(Attribute::SanitizeRealtimeBlocking)) 97 runSanitizeRealtimeBlocking(F); 98 } 99 100 return PreservedAnalyses::none(); 101 } 102