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