Implement cheap version of function replacement.
[dyninst.git] / dyninstAPI / src / Relocation / Transformers / Modification.C
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 #include "Transformer.h"
33 #include "Modification.h"
34 #include "dyninstAPI/src/debug.h"
35 #include "../Atoms/Target.h"
36 #include "../Atoms/Atom.h"
37 #include "../Atoms/CFAtom.h"
38 #include "../Atoms/ASTAtom.h"
39 #include "../Atoms/Instrumentation.h"
40 #include "dyninstAPI/src/instPoint.h"
41 #include "dyninstAPI/src/function.h"
42
43 using namespace std;
44 using namespace Dyninst;
45 using namespace Relocation;
46
47 Modification::Modification(const ext_CallReplaceMap &callRepl,
48                            const ext_FuncReplaceMap &funcRepl,
49                            const ext_CallRemovalSet &callRem) {
50   for (ext_CallReplaceMap::const_iterator iter = callRepl.begin();
51        iter != callRepl.end(); ++iter) {
52     int_block *bbl = iter->first->block();
53     callRep_[bbl] = std::make_pair<int_function *, instPoint *>(iter->second, iter->first);
54   }
55
56   for (ext_FuncReplaceMap::const_iterator iter = funcRepl.begin();
57        iter != funcRepl.end(); ++iter) {
58     int_block *bbl = iter->first->entryBlock();
59     funcRep_[bbl] = iter->second;
60   }
61
62   for (ext_CallRemovalSet::const_iterator iter = callRem.begin();
63        iter != callRem.end(); ++iter) {
64     int_block *bbl = (*iter)->block();
65     callRem_.insert(bbl);
66   }
67 }
68
69 bool Modification::processTrace(TraceList::iterator &iter) {
70   // We define three types of program modification:
71   // 1) Function call replacement; change the target of the corresponding
72   //    call element
73   // 2) Function call removal; modify the CFelement to have only a
74   //    fallthrough edge
75   // 3) Function replacement; TODO
76
77   Trace::Ptr block = *iter;
78   
79   CallReplaceMap::iterator c_rep = callRep_.find(block->bbl());
80   if (c_rep != callRep_.end()) {
81     replaceCall(block, c_rep->second.first, c_rep->second.second);
82   }
83
84   FuncReplaceMap::iterator f_rep = funcRep_.find(block->bbl());
85   if (f_rep != funcRep_.end()) {
86     replaceFunction(block, f_rep->second);
87   }
88
89   CallRemovalSet::iterator c_rem = callRem_.find(block->bbl());
90   if (c_rem != callRem_.end()) {
91     removeCall(block);
92   }
93
94   return true;
95 }
96
97 void Modification::replaceCall(TracePtr block, int_function *target, instPoint *cur) {
98   Trace::AtomList &elements = block->elements();
99
100   CFAtom::Ptr cf = dyn_detail::boost::dynamic_pointer_cast<CFAtom>(elements.back());
101
102   if (!cf) return;
103
104   if (!cf->insn()) return;
105   
106   if (cf->insn()->getCategory() != InstructionAPI::c_CallInsn) return;
107
108   relocation_cerr << "Replacing call @" << hex << cf->addr() << dec
109                   << " with a call to " << target->prettyName() << " @"
110                   << hex << target->getAddress() << dec << endl;
111
112   if (block->bbl()->func()->obj() == target->obj()) {
113     // In the same mapped object; we can do an efficient replace that just
114     // modifies the call distance. 
115     CFAtom::DestinationMap::iterator d_iter = cf->destMap_.find(CFAtom::Taken);
116     if (d_iter == cf->destMap_.end()) return;
117
118     // Don't leak target objects
119     delete d_iter->second;
120     
121     int_block *tbbl = target->entryBlock();
122     
123     Target<int_block *> *new_target = new Target<int_block *>(tbbl);
124     assert(new_target);
125     
126     d_iter->second = new_target;
127   }
128   else {
129     // Yuck!
130     vector<AstNodePtr> args;
131     Atom::Ptr callAST = ASTAtom::create(AstNode::funcCallNode(target, args), cur);
132     elements.back().swap(callAST);
133   }
134 }
135
136
137 void Modification::replaceFunction(TracePtr block, int_function *to) {
138     // We replace the original function with a jump to the new function.
139     // Did I say "jump"? I meant "CFAtom". 
140
141     // No reason to keep the rest of the stuff, and we often assume CFAtoms are
142     // the last thing in the list.
143
144     block->elements().clear();
145
146     CFAtom::Ptr cf = CFAtom::create(block->bbl());
147     cf->updateAddr(block->bbl()->start());
148
149     int_block *dest = to->entryBlock();
150     assert(dest);
151
152     cf->addDestination(CFAtom::Taken, new Target<int_block *>(dest));
153     block->elements().push_back(cf);
154     return;
155
156
157
158     // We handle this by "instrumenting" with a AST callReplacementNode.
159   // This is primarily due to needing registers to calculate the
160   // destination, but means that we need to forge an Inst node
161   // and prepend it to the block.
162
163   
164
165   Inst::Ptr inst = Inst::create();
166   block->elements().push_front(inst);
167
168   // And now to create a AtomTramp. Let's see if we can find one
169   // in the function...
170   int_function *from = block->bbl()->func();
171   const vector<instPoint *> &entries = from->funcEntries();
172   assert(!entries.empty());
173   for (unsigned i = 0; i < entries.size(); ++i) {
174     entries[i]->addInst(AstNode::funcReplacementNode(to, false),
175                         callPreInsn, 
176                         orderFirstAtPoint,
177                         true,
178                         false);
179   }
180 }
181
182
183 void Modification::removeCall(TracePtr block) {
184   const Trace::AtomList &elements = block->elements();
185
186   CFAtom::Ptr cf = dyn_detail::boost::dynamic_pointer_cast<CFAtom>(elements.back());
187
188   if (!cf) return;
189
190   if (!cf->insn()) return;
191   
192   if (cf->insn()->getCategory() != InstructionAPI::c_CallInsn) return;
193
194   CFAtom::DestinationMap::iterator d_iter = cf->destMap_.find(CFAtom::Fallthrough);
195   TargetInt *ftTarg = d_iter->second;
196
197   for (CFAtom::DestinationMap::iterator e_iter = cf->destMap_.begin();
198        e_iter != cf->destMap_.end(); ++e_iter) {
199     if (e_iter->second != ftTarg)
200       delete e_iter->second;
201   }
202   cf->destMap_.clear();
203   cf->destMap_[CFAtom::Fallthrough] = ftTarg;
204 }
205
206
207