105 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of the RealtimeSanitizer, an LLVM transformation for10// 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 25using namespace llvm;26 27const char kRtsanModuleCtorName[] = "rtsan.module_ctor";28const char kRtsanInitName[] = "__rtsan_ensure_initialized";29 30static 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 37static 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 49static void insertCallAtFunctionEntryPoint(Function &Fn,50 const char *InsertFnName,51 ArrayRef<Value *> FunctionArgs) {52 insertCallBeforeInstruction(Fn, Fn.front().front(), InsertFnName,53 FunctionArgs);54}55 56static 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 64static PreservedAnalyses rtsanPreservedCFGAnalyses() {65 PreservedAnalyses PA;66 PA.preserveSet<CFGAnalyses>();67 return PA;68}69 70static PreservedAnalyses runSanitizeRealtime(Function &Fn) {71 insertCallAtFunctionEntryPoint(Fn, "__rtsan_realtime_enter", {});72 insertCallAtAllFunctionExitPoints(Fn, "__rtsan_realtime_exit", {});73 return rtsanPreservedCFGAnalyses();74}75 76static 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 83PreservedAnalyses 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 first89 // 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.empty())94 continue;95 96 if (F.hasFnAttribute(Attribute::SanitizeRealtime))97 runSanitizeRealtime(F);98 99 if (F.hasFnAttribute(Attribute::SanitizeRealtimeBlocking))100 runSanitizeRealtimeBlocking(F);101 }102 103 return PreservedAnalyses::none();104}105