Computer Laboratory

Caller.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 "Caller.h"
33 #include "Manifest.h"
34 #include "Names.h"
35 #include "State.h"
36 #include "Transition.h"
37 
38 #include "llvm/IR/Instructions.h"
39 #include "llvm/IR/IRBuilder.h"
40 #include "llvm/IR/Module.h"
41 
42 #include "llvm/Support/raw_ostream.h"
43 
44 using namespace llvm;
45 
46 using std::string;
47 
48 namespace tesla {
49 
50 // ==== FnCallerInstrumenter implementation =================================
51 char FnCallerInstrumenter::ID = 0;
52 
53 FnCallerInstrumenter::~FnCallerInstrumenter() {
54  ::google::protobuf::ShutdownProtobufLibrary();
55 }
56 
57 bool FnCallerInstrumenter::doInitialization(Module &Mod) {
58  bool ModifiedIR = true;
59 
60  for (auto i : M.RootAutomata()) {
61  auto& A = *M.FindAutomaton(i->identifier());
62  for (auto EquivClass : A) {
63  assert(!EquivClass.empty());
64 
65  auto *Head = dyn_cast<FnTransition>(*EquivClass.begin());
66  if (!Head)
67  continue;
68 
69  auto& FnEvent = Head->FnEvent();
70  if (FnEvent.context() != FunctionEvent::Caller)
71  continue;
72 
73  Function *Target = Mod.getFunction(FnEvent.function().name());
74  if (!Target)
75  continue;
76 
77  GetOrCreateInstr(Mod, Target, FnEvent.direction())
78  ->AppendInstrumentation(A, FnEvent, EquivClass);
79 
80  ModifiedIR = true;
81  }
82  }
83 
84  return ModifiedIR;
85 }
86 
87 
88 CallerInstrumentation* FnCallerInstrumenter::GetOrCreateInstr(
89  Module& M, Function *F, FunctionEvent::Direction Dir) {
90 
91  assert(F != NULL);
92  StringRef Name = F->getName();
93 
94  auto& Map = (Dir == FunctionEvent::Entry) ? Calls : Returns;
95  CallerInstrumentation *Instr = Map[Name];
96  if (!Instr)
97  Instr = Map[Name] = CallerInstrumentation::Build(M, F, Dir,
98  SuppressDebugInstr);
99 
100  return Instr;
101 }
102 
103 
104 bool FnCallerInstrumenter::runOnFunction(Function &Fn) {
105  bool modifiedIR = false;
106 
107  for (auto &Block : Fn) {
108  modifiedIR |= runOnBasicBlock(Block);
109  }
110 
111  return modifiedIR;
112 }
113 
114 bool FnCallerInstrumenter::runOnBasicBlock(BasicBlock &Block) {
115  bool ModifiedIR = false;
116 
117  for (auto &Inst : Block) {
118  if (!isa<CallInst>(Inst)) continue;
119  CallInst &Call = cast<CallInst>(Inst);
120  Function *Callee = Call.getCalledFunction();
121 
122  // TODO: handle indirection (e.g. function pointers)?
123  if (!Callee)
124  continue;
125 
126  StringRef Name = Callee->getName();
127  if (auto Instr = Calls.lookup(Name))
128  ModifiedIR |= Instr->Instrument(Call);
129 
130  if (auto Instr = Returns.lookup(Name))
131  ModifiedIR |= Instr->Instrument(Call);
132  }
133 
134  return ModifiedIR;
135 }
136 
137 
138 // ==== CallerInstrumentation implementation ===================================
140  CallerInstrumentation::Build(Module& M, Function *Target,
142  bool SuppressDebugInstr) {
143 
144  assert(Target != NULL);
145 
146  Function *InstrFn = FunctionInstrumentation(M, *Target, Dir,
147  FunctionEvent::Caller,
148  SuppressDebugInstr);
149 
150  return new CallerInstrumentation(M, Target, InstrFn, Dir);
151 }
152 
153 
154 bool CallerInstrumentation::Instrument(Instruction &Inst) {
155  assert(isa<CallInst>(Inst));
156  CallInst &Call = cast<CallInst>(Inst);
157 
158  ArgVector Args;
159  for (size_t i = 0; i < Call.getNumArgOperands(); i++)
160  Args.push_back(Call.getArgOperand(i));
161 
162  switch (Dir) {
163  case FunctionEvent::Entry:
164  CallInst::Create(InstrFn, Args)->insertBefore(&Inst);
165  break;
166 
167  case FunctionEvent::Exit:
168  if (!Call.getType()->isVoidTy())
169  Args.push_back(&Call);
170 
171  CallInst::Create(InstrFn, Args)->insertAfter(&Inst);
172  break;
173  }
174 
175  return true;
176 }
177 
178 
179 }
180