Computer Laboratory

Callee.cpp
Go to the documentation of this file.
1 
2 /*
3  * Copyright (c) 2012-2013 Jonathan Anderson
4  * All rights reserved.
5  *
6  * This software was developed by SRI International and the University of
7  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
8  * ("CTSRD"), as part of the DARPA CRASH research programme.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include "Automaton.h"
33 #include "Callee.h"
34 #include "Instrumentation.h"
35 #include "Manifest.h"
36 #include "Names.h"
37 #include "State.h"
38 #include "Transition.h"
39 
40 #include "llvm/ADT/SmallPtrSet.h"
41 #include "llvm/IR/Function.h"
42 #include "llvm/IR/Instructions.h"
43 #include "llvm/IR/IRBuilder.h"
44 #include "llvm/IR/Module.h"
45 #include "llvm/Support/InstIterator.h"
46 
47 using namespace llvm;
48 
49 using std::string;
50 using std::vector;
51 
52 namespace tesla {
53 
54 // ==== FnCalleeInstrumenter implementation ======================================
55 char FnCalleeInstrumenter::ID = 0;
56 
57 FnCalleeInstrumenter::~FnCalleeInstrumenter() {
58  google::protobuf::ShutdownProtobufLibrary();
59 }
60 
61 bool FnCalleeInstrumenter::runOnModule(Module &Mod) {
62  bool ModifiedIR = false;
63 
64  for (auto i : M.RootAutomata()) {
65  auto& A = *M.FindAutomaton(i->identifier());
66  for (auto EquivClass : A) {
67  assert(!EquivClass.empty());
68 
69  auto *Head = dyn_cast<FnTransition>(*EquivClass.begin());
70  if (!Head)
71  continue;
72 
73  auto& FnEvent = Head->FnEvent();
74  if (FnEvent.context() != FunctionEvent::Callee)
75  continue;
76 
77  Function *Target = Mod.getFunction(FnEvent.function().name());
78 
79  // Only handle functions that are defined in this module.
80  if (!Target || Target->empty())
81  continue;
82 
83  GetOrCreateInstr(Mod, Target, FnEvent.direction())
84  ->AppendInstrumentation(A, FnEvent, EquivClass);
85 
86  ModifiedIR = true;
87  }
88  }
89 
90  return ModifiedIR;
91 }
92 
93 
94 CalleeInstr* FnCalleeInstrumenter::GetOrCreateInstr(
95  Module& M, Function *F, FunctionEvent::Direction Dir) {
96 
97  assert(F != NULL);
98  StringRef Name = F->getName();
99 
100  auto& Map = (Dir == FunctionEvent::Entry) ? Entry : Exit;
101  CalleeInstr *Instr = Map[Name];
102  if (!Instr)
103  Instr = Map[Name] = CalleeInstr::Build(M, F, Dir, SuppressDebugInstr);
104 
105  return Instr;
106 }
107 
108 
109 
110 // ==== FnCalleeInstr implementation ===========================================
111 CalleeInstr* CalleeInstr::Build(Module& M, Function *Target,
113  bool SuppressDebugInstr) {
114 
115  // Find (or create) the instrumentation function.
116  // Note: it doesn't yet contain the code to translate events and
117  // dispatch them to tesla_update_state().
118  Function *InstrFn = FunctionInstrumentation(M, *Target, Dir,
119  FunctionEvent::Callee,
120  SuppressDebugInstr);
121 
122  // Record the arguments passed to the instrumented function.
123  //
124  // LLVM's SSA magic will keep these around for us until we need them, even if
125  // C code overwrites its parameters.
126  ArgVector Args;
127  for (auto &Arg : Target->getArgumentList())
128  Args.push_back(&Arg);
129 
130  // Instrument either the entry or return points of the target function.
131  switch (Dir) {
132  case FunctionEvent::Entry: {
133  // Instrumenting function entry is easy: just add a new call to
134  // instrumentation at the beginning of the function's entry block.
135  BasicBlock& Entry = Target->getEntryBlock();
136  CallInst::Create(InstrFn, Args)->insertBefore(Entry.getFirstNonPHI());
137  break;
138  }
139 
140  case FunctionEvent::Exit: {
141  SmallPtrSet<ReturnInst*, 16> Returns;
142  for (auto i = inst_begin(Target), End = inst_end(Target); i != End; i++)
143  if (auto *Return = dyn_cast<ReturnInst>(&*i))
144  Returns.insert(Return);
145 
146  for (ReturnInst *Return : Returns) {
147  ArgVector InstrArgs(Args);
148 
149  if (Dir == FunctionEvent::Exit && !Target->getReturnType()->isVoidTy())
150  InstrArgs.push_back(Return->getReturnValue());
151 
152  CallInst::Create(InstrFn, InstrArgs)->insertBefore(Return);
153  }
154  break;
155  }
156  }
157 
158  return new CalleeInstr(M, Target, InstrFn, Dir);
159 }
160 
161 
162 CalleeInstr::CalleeInstr(Module& M, Function *Target, Function *InstrFn,
164  : FnInstrumentation(M, Target, InstrFn, Dir)
165 {
166  assert(TargetFn != NULL);
167  assert(InstrFn != NULL);
168 
169  // Record the arguments passed to the instrumented function.
170  //
171  // LLVM's SSA magic will keep these around for us until we need them, even if
172  // C code overwrites its parameters.
173  for (auto &Arg : Target->getArgumentList())
174  Args.push_back(&Arg);
175 }
176 
177 } /* namespace tesla */
178