Provide Windows-friendly relative paths.
[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     bblInstance *bbl = iter->first->block()->origInstance();
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     bblInstance *bbl = iter->first->entryBlock()->origInstance();
59     funcRep_[bbl] = iter->second;
60   }
61
62   for (ext_CallRemovalSet::const_iterator iter = callRem.begin();
63        iter != callRem.end(); ++iter) {
64     bblInstance *bbl = (*iter)->block()->origInstance();
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     bblInstance *tbbl = target->entryBlock()->origInstance();
122     
123     Target<bblInstance *> *new_target = new Target<bblInstance *>(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 handle this by "instrumenting" with a AST callReplacementNode.
139   // This is primarily due to needing registers to calculate the
140   // destination, but means that we need to forge an Inst node
141   // and prepend it to the block.
142   Inst::Ptr inst = Inst::create();
143   block->elements().push_front(inst);
144
145   // And now to create a AtomTramp. Let's see if we can find one
146   // in the function...
147   int_function *from = block->bbl()->func();
148   const vector<instPoint *> &entries = from->funcEntries();
149   assert(!entries.empty());
150   for (unsigned i = 0; i < entries.size(); ++i) {
151     entries[i]->addInst(AstNode::funcReplacementNode(to, false),
152                         callPreInsn, 
153                         orderFirstAtPoint,
154                         true,
155                         false);
156   }
157 }
158
159
160 void Modification::removeCall(TracePtr block) {
161   const Trace::AtomList &elements = block->elements();
162
163   CFAtom::Ptr cf = dyn_detail::boost::dynamic_pointer_cast<CFAtom>(elements.back());
164
165   if (!cf) return;
166
167   if (!cf->insn()) return;
168   
169   if (cf->insn()->getCategory() != InstructionAPI::c_CallInsn) return;
170
171   CFAtom::DestinationMap::iterator d_iter = cf->destMap_.find(CFAtom::Fallthrough);
172   TargetInt *ftTarg = d_iter->second;
173
174   for (CFAtom::DestinationMap::iterator e_iter = cf->destMap_.begin();
175        e_iter != cf->destMap_.end(); ++e_iter) {
176     if (e_iter->second != ftTarg)
177       delete e_iter->second;
178   }
179   cf->destMap_.clear();
180   cf->destMap_[CFAtom::Fallthrough] = ftTarg;
181 }
182
183
184