xref: /llvm-project/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp (revision 4a6586140211cc9aed02d9177dba0c01622139f4)
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