Rename image_* to parse_* and int_* to *_instance
[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 "../patchapi_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/InstAtom.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     block_instance *bbl = iter->first->block();
53     callRep_[bbl] = std::make_pair<func_instance *, instPoint *>(iter->second, iter->first);
54   }
55
56   for (ext_FuncReplaceMap::const_iterator iter = funcRepl.begin();
57        iter != funcRepl.end(); ++iter) {
58      block_instance *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     block_instance *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->block());
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->block());
85   if (f_rep != funcRep_.end()) {
86     replaceFunction(block, f_rep->second);
87   }
88
89   CallRemovalSet::iterator c_rem = callRem_.find(block->block());
90   if (c_rem != callRem_.end()) {
91     removeCall(block);
92   }
93
94   return true;
95 }
96
97 void Modification::replaceCall(TracePtr block, func_instance *target, instPoint *cur) {
98   Trace::AtomList &elements = block->elements();
99
100   cerr << "Warning: skipping replacement of call" << endl;
101
102   CFAtom::Ptr cf = dyn_detail::boost::dynamic_pointer_cast<CFAtom>(elements.back());
103
104   if (!cf) return;
105
106   if (!cf->insn()) return;
107   
108   if (cf->insn()->getCategory() != InstructionAPI::c_CallInsn) return;
109
110   relocation_cerr << "Replacing call @" << hex << cf->addr() << dec
111                   << " with a call to " << target->prettyName() << " @"
112                   << hex << target->getAddress() << dec << endl;
113
114   if (block->block()->func()->obj() == target->obj()) {
115     // In the same mapped object; we can do an efficient replace that just
116     // modifies the call distance. 
117     CFAtom::DestinationMap::iterator d_iter = cf->destMap_.find(CFAtom::Taken);
118     if (d_iter == cf->destMap_.end()) return;
119
120     // Don't leak target objects
121     delete d_iter->second;
122     
123     block_instance *tbbl = target->entryBlock();
124     
125     Target<block_instance *> *new_target = new Target<block_instance *>(tbbl);
126     assert(new_target);
127     
128     d_iter->second = new_target;
129   }
130   else {
131     // Yuck!
132     vector<AstNodePtr> args;
133     Atom::Ptr callAST = ASTAtom::create(AstNode::funcCallNode(target, args), cur);
134     elements.back().swap(callAST);
135   }
136 }
137
138
139 void Modification::replaceFunction(TracePtr block, func_instance *to) {
140     // We replace the original function with a jump to the new function.
141     // Did I say "jump"? I meant "CFAtom". 
142
143     // No reason to keep the rest of the stuff, and we often assume CFAtoms are
144     // the last thing in the list.
145    
146    cerr << "Warning: skipping function replacement" << endl;
147
148 #if 0
149     block->elements().clear();
150
151     CFAtom::Ptr cf = CFAtom::create(block->block());
152     cf->updateAddr(block->block()->start());
153
154     block_instance *dest = to->entryBlock();
155     assert(dest);
156
157     cf->addDestination(CFAtom::Taken, new Target<block_instance *>(dest));
158     block->elements().push_back(cf);
159     return;
160
161
162
163     // We handle this by "instrumenting" with a AST callReplacementNode.
164   // This is primarily due to needing registers to calculate the
165   // destination, but means that we need to forge an Inst node
166   // and prepend it to the block.
167
168   
169
170   Inst::Ptr inst = Inst::create();
171   block->elements().push_front(inst);
172
173   // And now to create a AtomTramp. Let's see if we can find one
174   // in the function...
175   block_instance *from = block->block()->func();
176   const vector<instPoint *> &entries = from->funcEntries();
177   assert(!entries.empty());
178   for (unsigned i = 0; i < entries.size(); ++i) {
179     entries[i]->addInst(AstNode::funcReplacementNode(to, false),
180                         callPreInsn, 
181                         orderFirstAtPoint,
182                         true,
183                         false);
184   }
185
186 #endif
187 }
188
189
190 void Modification::removeCall(TracePtr block) {
191   const Trace::AtomList &elements = block->elements();
192
193   cerr << "Warning: skipping removal of call" << endl;
194   return;
195
196
197   CFAtom::Ptr cf = dyn_detail::boost::dynamic_pointer_cast<CFAtom>(elements.back());
198
199   if (!cf) return;
200
201   if (!cf->insn()) return;
202   
203   if (cf->insn()->getCategory() != InstructionAPI::c_CallInsn) return;
204
205   CFAtom::DestinationMap::iterator d_iter = cf->destMap_.find(CFAtom::Fallthrough);
206   TargetInt *ftTarg = d_iter->second;
207
208   for (CFAtom::DestinationMap::iterator e_iter = cf->destMap_.begin();
209        e_iter != cf->destMap_.end(); ++e_iter) {
210     if (e_iter->second != ftTarg)
211       delete e_iter->second;
212   }
213   cf->destMap_.clear();
214   cf->destMap_[CFAtom::Fallthrough] = ftTarg;
215 }
216
217
218