After tested under windows.
[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 "../CFG/RelocTarget.h"
36 #include "../Widgets/Widget.h"
37 #include "../Widgets/CFWidget.h"
38 #include "../Widgets/ASTWidget.h"
39 #include "../Widgets/InstWidget.h"
40 #include "../CFG/RelocGraph.h"
41 #include "dyninstAPI/src/instPoint.h"
42 #include "dyninstAPI/src/function.h"
43 #include "../Widgets/CallbackWidget.h"
44
45
46 using namespace std;
47 using namespace Dyninst;
48 using namespace Relocation;
49
50 Modification::Modification(const CallModMap &callMod,
51                            const FuncModMap &funcRepl,
52                            const FuncModMap &funcWraps) :
53   callMods_(callMod),
54   funcReps_(funcRepl),
55   funcWraps_(funcWraps) {};
56
57 bool Modification::process(RelocBlock *cur, RelocGraph *cfg) {
58   // We define three types of program modification:
59   // 1) Function call replacement; change the target of the corresponding
60   //    call element
61   // 2) Function call removal; modify the CFelement to have only a
62   //    fallthrough edge
63   // 3) Function replacement; TODO
64
65    if (!replaceCall(cur, cfg)) return false;
66    if (!replaceFunction(cur, cfg)) return false;
67    if (!wrapFunction(cur, cfg)) return false;
68
69    return true;
70 }
71
72 bool Modification::replaceCall(RelocBlock *trace, RelocGraph *cfg) {
73    // See if we have a modification for this point
74    CallModMap::const_iterator iter = callMods_.find(trace->block());
75    if (iter == callMods_.end()) return true;
76    std::map<PatchFunction*, PatchFunction*>::const_iterator iter2 = iter->second.find(trace->func());
77    if (iter2 == iter->second.end()) return true;
78
79    func_instance *repl = SCAST_FI(iter2->second);
80
81    relocation_cerr << "Replacing call in trace "
82                    << trace->id() << " with call to "
83                    << (repl ? repl->name() : "<NULL>")
84                    << ", " << hex
85                    << (repl ? repl->addr() : 0)
86                    << dec << endl;
87
88
89    // Replace the call at the end of this trace /w/ repl (if non-NULL),
90    // or elide completely (if NULL)
91    // We do this via edge twiddling in the RelocBlock
92
93    Predicates::Type pred(ParseAPI::CALL);
94
95    if (!repl) {
96       if (!cfg->removeEdge(pred, trace->outs())) return false;
97       return true;
98    }
99
100    RelocBlock *target = cfg->find(repl->entryBlock());
101    if (target) {
102       if (!cfg->changeTargets(pred, trace->outs(), target)) return false;
103    }
104    else {
105       if (!cfg->changeTargets(pred, trace->outs(), repl->entryBlock())) return false;
106    }
107
108    return true;
109 }
110
111 bool Modification::replaceFunction(RelocBlock *trace, RelocGraph *cfg) {
112    // See if we're the entry block
113    if (trace->block() != trace->func()->entryBlock()) return true;
114
115    FuncModMap::const_iterator iter = funcReps_.find(trace->func());
116    if (iter == funcReps_.end()) return true;
117    //func_instance* oldfun = SCAST_FI(iter->first);
118    PatchFunction* pnewfun = iter->second;
119    //func_instance* newfun = SCAST_FI(iter->second);
120    func_instance* newfun = SCAST_FI(pnewfun);
121
122    relocation_cerr << "Performing function replacement in trace " << trace->id()
123                    << " going to function " << newfun->name()
124                    << " /w/ entry block "
125                    << (newfun->entryBlock() ? newfun->entryBlock()->start() : -1) << endl;
126    // Stub a jump to the replacement function
127    RelocBlock *stub = makeRelocBlock(newfun->entryBlock(),
128                            newfun,
129                            cfg);
130    RelocBlock *target = cfg->find(newfun->entryBlock());
131    if (target) {
132       cfg->makeEdge(new Target<RelocBlock *>(stub),
133                     new Target<RelocBlock *>(target),
134                     ParseAPI::DIRECT);
135    }
136    else {
137       cfg->makeEdge(new Target<RelocBlock *>(stub),
138                     new Target<block_instance *>(newfun->entryBlock()),
139                     ParseAPI::DIRECT);
140    }
141
142    // Redirect the springboard to the replacement function
143    cfg->setSpringboard(trace->block(), stub);
144
145    // Redirect all call in-edges to the replacement function
146    Predicates::Interprocedural pred;
147    if (target) {
148       if (!cfg->changeTargets(pred, trace->ins(), target)) return false;
149    }
150    else {
151       if (!cfg->changeTargets(pred, trace->ins(), newfun->entryBlock())) return false;
152    }
153    return true;
154 }
155
156 bool Modification::wrapFunction(RelocBlock *trace, RelocGraph *cfg) {
157    // See if we're the entry block
158    if (trace->block() != trace->func()->entryBlock()) return true;
159
160    FuncModMap::const_iterator iter = funcWraps_.find(trace->func());
161    if (iter == funcWraps_.end()) return true;
162
163    // func_instance* oldfun = SCAST_FI(iter->first);
164    func_instance* newfun = SCAST_FI(iter->second);
165
166
167    relocation_cerr << "Performing function wrapping in trace " << trace->id()
168                    << " going to function " << newfun->name()
169                    << " /w/ entry block "
170                    << (newfun->entryBlock() ? newfun->entryBlock()->start() : -1) << endl;
171
172    // This is a special case of replaceFunction; the predicate is "all calls except from the
173    // wrapper are redirected".
174    RelocBlock *stub = makeRelocBlock(newfun->entryBlock(),
175                            newfun,
176                            cfg);
177    RelocBlock *target = cfg->find(newfun->entryBlock());
178    if (target) {
179       cfg->makeEdge(new Target<RelocBlock *>(stub),
180                     new Target<RelocBlock *>(target),
181                     ParseAPI::DIRECT);
182    }
183    else {
184       cfg->makeEdge(new Target<RelocBlock *>(stub),
185                     new Target<block_instance *>(newfun->entryBlock()),
186                     ParseAPI::DIRECT);
187    }
188
189    cfg->setSpringboard(trace->block(), stub);
190
191    WrapperPredicate pred(trace->func());
192    if (target) {
193       if (!cfg->changeTargets(pred, trace->ins(), target)) return false;
194    }
195    else {
196       if (!cfg->changeTargets(pred, trace->ins(), newfun->entryBlock())) return false;
197    }
198    // We also need to track the "new" entry block so we can build a new symbol for it.
199    CallbackWidget::Ptr c = CallbackWidget::create(new WrapperPatch(trace->func()));
200    trace->elements().push_front(c);
201
202    return true;
203 }
204
205 RelocBlock *Modification::makeRelocBlock(block_instance *block, func_instance *func, RelocGraph *cfg) {
206    RelocBlock *t = RelocBlock::createStub(block, func);
207    // Put it at the end, why not.
208    cfg->addRelocBlock(t);
209    return t;
210 }
211
212 // TODO: make this mildly more efficient. On the other hand, is it a big deal?
213 Modification::WrapperPredicate::WrapperPredicate(func_instance *f)
214    : f_(f) {};
215
216
217 bool Modification::WrapperPredicate::operator()(RelocEdge *e) {
218    if (e->src->type() != TargetInt::RelocBlockTarget) return false;
219    RelocBlock *t = static_cast<Target<RelocBlock *> *>(e->src)->t();
220    return t->func() == f_;
221 }
222
223 bool Modification::WrapperPatch::apply(codeGen &gen, CodeBuffer *) {
224    // Tell our function to create a wrapper symbol at this address
225    func_->createWrapperSymbol(gen.currAddr());
226    return true;
227 }
228