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(Elt: 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(Result: Type::getVoidTy(C&: Context), |
42 | Params: getArgTypes(FunctionArgs), isVarArg: false); |
43 | FunctionCallee Func = |
44 | Fn.getParent()->getOrInsertFunction(Name: FunctionName, T: FuncType); |
45 | IRBuilder<> Builder{&Instruction}; |
46 | Builder.CreateCall(Callee: Func, Args: FunctionArgs); |
47 | } |
48 | |
49 | static void insertCallAtFunctionEntryPoint(Function &Fn, |
50 | const char *InsertFnName, |
51 | ArrayRef<Value *> FunctionArgs) { |
52 | insertCallBeforeInstruction(Fn, Instruction&: Fn.front().front(), FunctionName: InsertFnName, |
53 | FunctionArgs); |
54 | } |
55 | |
56 | static void insertCallAtAllFunctionExitPoints(Function &Fn, |
57 | const char *InsertFnName, |
58 | ArrayRef<Value *> FunctionArgs) { |
59 | for (auto &I : instructions(F&: Fn)) |
60 | if (isa<ReturnInst>(Val: &I)) |
61 | insertCallBeforeInstruction(Fn, Instruction&: I, FunctionName: 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, InsertFnName: "__rtsan_realtime_enter" , FunctionArgs: {}); |
72 | insertCallAtAllFunctionExitPoints(Fn, InsertFnName: "__rtsan_realtime_exit" , FunctionArgs: {}); |
73 | return rtsanPreservedCFGAnalyses(); |
74 | } |
75 | |
76 | static PreservedAnalyses runSanitizeRealtimeBlocking(Function &Fn) { |
77 | IRBuilder<> Builder(&Fn.front().front()); |
78 | Value *Name = Builder.CreateGlobalString(Str: demangle(MangledName: Fn.getName())); |
79 | insertCallAtFunctionEntryPoint(Fn, InsertFnName: "__rtsan_notify_blocking_call" , FunctionArgs: {Name}); |
80 | return rtsanPreservedCFGAnalyses(); |
81 | } |
82 | |
83 | PreservedAnalyses RealtimeSanitizerPass::run(Module &M, |
84 | ModuleAnalysisManager &MAM) { |
85 | getOrCreateSanitizerCtorAndInitFunctions( |
86 | M, CtorName: kRtsanModuleCtorName, InitName: 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 | FunctionsCreatedCallback: [&](Function *Ctor, FunctionCallee) { appendToGlobalCtors(M, F: Ctor, Priority: 0); }); |
91 | |
92 | for (Function &F : M) { |
93 | if (F.hasFnAttribute(Kind: Attribute::SanitizeRealtime)) |
94 | runSanitizeRealtime(Fn&: F); |
95 | |
96 | if (F.hasFnAttribute(Kind: Attribute::SanitizeRealtimeBlocking)) |
97 | runSanitizeRealtimeBlocking(Fn&: F); |
98 | } |
99 | |
100 | return PreservedAnalyses::none(); |
101 | } |
102 | |