18acf8852SChris Apple //===- RealtimeSanitizer.cpp - RealtimeSanitizer instrumentation *- C++ -*-===// 28acf8852SChris Apple // 38acf8852SChris Apple // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 48acf8852SChris Apple // See https://llvm.org/LICENSE.txt for license information. 58acf8852SChris Apple // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 68acf8852SChris Apple // 78acf8852SChris Apple //===----------------------------------------------------------------------===// 88acf8852SChris Apple // 98acf8852SChris Apple // This file is a part of the RealtimeSanitizer, an LLVM transformation for 108acf8852SChris Apple // detecting and reporting realtime safety violations. 118acf8852SChris Apple // 128acf8852SChris Apple // See also: llvm-project/compiler-rt/lib/rtsan/ 138acf8852SChris Apple // 148acf8852SChris Apple //===----------------------------------------------------------------------===// 158acf8852SChris Apple 168acf8852SChris Apple #include "llvm/IR/Analysis.h" 178acf8852SChris Apple #include "llvm/IR/IRBuilder.h" 184547d604Sdavidtrevelyan #include "llvm/IR/InstIterator.h" 198acf8852SChris Apple #include "llvm/IR/Module.h" 20ca3180adSChris Apple #include "llvm/Transforms/Utils/ModuleUtils.h" 218acf8852SChris Apple 224547d604Sdavidtrevelyan #include "llvm/Demangle/Demangle.h" 238acf8852SChris Apple #include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h" 248acf8852SChris Apple 258acf8852SChris Apple using namespace llvm; 268acf8852SChris Apple 27ca3180adSChris Apple const char kRtsanModuleCtorName[] = "rtsan.module_ctor"; 28ca3180adSChris Apple const char kRtsanInitName[] = "__rtsan_ensure_initialized"; 29ca3180adSChris Apple 304547d604Sdavidtrevelyan static SmallVector<Type *> getArgTypes(ArrayRef<Value *> FunctionArgs) { 314547d604Sdavidtrevelyan SmallVector<Type *> Types; 324547d604Sdavidtrevelyan for (Value *Arg : FunctionArgs) 334547d604Sdavidtrevelyan Types.push_back(Arg->getType()); 344547d604Sdavidtrevelyan return Types; 354547d604Sdavidtrevelyan } 364547d604Sdavidtrevelyan 378acf8852SChris Apple static void insertCallBeforeInstruction(Function &Fn, Instruction &Instruction, 384547d604Sdavidtrevelyan const char *FunctionName, 394547d604Sdavidtrevelyan ArrayRef<Value *> FunctionArgs) { 408acf8852SChris Apple LLVMContext &Context = Fn.getContext(); 414547d604Sdavidtrevelyan FunctionType *FuncType = FunctionType::get(Type::getVoidTy(Context), 424547d604Sdavidtrevelyan getArgTypes(FunctionArgs), false); 438acf8852SChris Apple FunctionCallee Func = 448acf8852SChris Apple Fn.getParent()->getOrInsertFunction(FunctionName, FuncType); 458acf8852SChris Apple IRBuilder<> Builder{&Instruction}; 464547d604Sdavidtrevelyan Builder.CreateCall(Func, FunctionArgs); 478acf8852SChris Apple } 488acf8852SChris Apple 498acf8852SChris Apple static void insertCallAtFunctionEntryPoint(Function &Fn, 504547d604Sdavidtrevelyan const char *InsertFnName, 514547d604Sdavidtrevelyan ArrayRef<Value *> FunctionArgs) { 524547d604Sdavidtrevelyan insertCallBeforeInstruction(Fn, Fn.front().front(), InsertFnName, 534547d604Sdavidtrevelyan FunctionArgs); 548acf8852SChris Apple } 558acf8852SChris Apple 568acf8852SChris Apple static void insertCallAtAllFunctionExitPoints(Function &Fn, 574547d604Sdavidtrevelyan const char *InsertFnName, 584547d604Sdavidtrevelyan ArrayRef<Value *> FunctionArgs) { 594547d604Sdavidtrevelyan for (auto &I : instructions(Fn)) 60f8659478SFangrui Song if (isa<ReturnInst>(&I)) 614547d604Sdavidtrevelyan insertCallBeforeInstruction(Fn, I, InsertFnName, FunctionArgs); 624547d604Sdavidtrevelyan } 634547d604Sdavidtrevelyan 644547d604Sdavidtrevelyan static PreservedAnalyses rtsanPreservedCFGAnalyses() { 654547d604Sdavidtrevelyan PreservedAnalyses PA; 664547d604Sdavidtrevelyan PA.preserveSet<CFGAnalyses>(); 674547d604Sdavidtrevelyan return PA; 684547d604Sdavidtrevelyan } 694547d604Sdavidtrevelyan 704547d604Sdavidtrevelyan static PreservedAnalyses runSanitizeRealtime(Function &Fn) { 714547d604Sdavidtrevelyan insertCallAtFunctionEntryPoint(Fn, "__rtsan_realtime_enter", {}); 724547d604Sdavidtrevelyan insertCallAtAllFunctionExitPoints(Fn, "__rtsan_realtime_exit", {}); 734547d604Sdavidtrevelyan return rtsanPreservedCFGAnalyses(); 744547d604Sdavidtrevelyan } 754547d604Sdavidtrevelyan 7641026253Sdavidtrevelyan static PreservedAnalyses runSanitizeRealtimeBlocking(Function &Fn) { 774547d604Sdavidtrevelyan IRBuilder<> Builder(&Fn.front().front()); 784547d604Sdavidtrevelyan Value *Name = Builder.CreateGlobalString(demangle(Fn.getName())); 794547d604Sdavidtrevelyan insertCallAtFunctionEntryPoint(Fn, "__rtsan_notify_blocking_call", {Name}); 804547d604Sdavidtrevelyan return rtsanPreservedCFGAnalyses(); 818acf8852SChris Apple } 828acf8852SChris Apple 83*4a658614SChris Apple PreservedAnalyses RealtimeSanitizerPass::run(Module &M, 84ca3180adSChris Apple ModuleAnalysisManager &MAM) { 85ca3180adSChris Apple getOrCreateSanitizerCtorAndInitFunctions( 86ca3180adSChris Apple M, kRtsanModuleCtorName, kRtsanInitName, /*InitArgTypes=*/{}, 87ca3180adSChris Apple /*InitArgs=*/{}, 88ca3180adSChris Apple // This callback is invoked when the functions are created the first 89ca3180adSChris Apple // time. Hook them into the global ctors list in that case: 90ca3180adSChris Apple [&](Function *Ctor, FunctionCallee) { appendToGlobalCtors(M, Ctor, 0); }); 91*4a658614SChris Apple 92*4a658614SChris Apple for (Function &F : M) { 93*4a658614SChris Apple if (F.hasFnAttribute(Attribute::SanitizeRealtime)) 94*4a658614SChris Apple runSanitizeRealtime(F); 95*4a658614SChris Apple 96*4a658614SChris Apple if (F.hasFnAttribute(Attribute::SanitizeRealtimeBlocking)) 97*4a658614SChris Apple runSanitizeRealtimeBlocking(F); 98*4a658614SChris Apple } 99*4a658614SChris Apple 100ca3180adSChris Apple return PreservedAnalyses::none(); 101ca3180adSChris Apple } 102