C++ cleanup (#610)
[dyninst.git] / dyninstAPI / src / Relocation / Transformers / Modification.C
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  * 
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  * 
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  * 
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  * 
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  * 
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 #include "Transformer.h"
32 #include "Modification.h"
33 #include "../dyninstAPI/src/debug.h"
34 #include "../CFG/RelocTarget.h"
35 #include "../Widgets/Widget.h"
36 #include "../Widgets/CFWidget.h"
37 #include "../Widgets/ASTWidget.h"
38 #include "../Widgets/InstWidget.h"
39 #include "../CFG/RelocGraph.h"
40 #include "dyninstAPI/src/instPoint.h"
41 #include "dyninstAPI/src/function.h"
42 #include "../Widgets/CallbackWidget.h"
43
44
45 using namespace std;
46 using namespace Dyninst;
47 using namespace Relocation;
48
49 Modification::Modification(const CallModMap &callMod,
50                            const FuncModMap &funcRepl,
51                            const FuncWrapMap &funcWraps) :
52   callMods_(callMod),
53   funcReps_(funcRepl),
54   funcWraps_(funcWraps) {};
55
56 bool Modification::process(RelocBlock *cur, RelocGraph *cfg) {
57   //relocation_cerr << "Modification transformer, processing block" << endl;
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(), repl);
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 were something created later
113   if (trace->elements().empty()) return true;
114   
115    // See if we're the entry block
116    if (trace->block() != trace->func()->entryBlock()) return true;
117
118    FuncModMap::const_iterator iter = funcReps_.find(trace->func());
119    if (iter == funcReps_.end()) return true;
120    func_instance* oldfun = SCAST_FI(iter->first);
121    PatchFunction* pnewfun = iter->second;
122    //func_instance* newfun = SCAST_FI(iter->second);
123    func_instance* newfun = SCAST_FI(pnewfun);
124
125    relocation_cerr << "Performing function replacement in trace " << trace->id()
126                    << " going to function " << newfun->name()
127                    << " /w/ entry block "
128                    << (newfun->entryBlock() ? newfun->entryBlock()->start() : -1) << endl;
129    // Stub a jump to the replacement function
130    RelocBlock *stub = makeRelocBlock(oldfun->entryBlock(),
131                                      oldfun,
132                                      trace,
133                                      cfg);
134    RelocBlock *target = cfg->find(newfun->entryBlock(), newfun);
135    if (target) {
136       cfg->makeEdge(new Target<RelocBlock *>(stub),
137                     new Target<RelocBlock *>(target),
138                     NULL,
139                     ParseAPI::DIRECT);
140    }
141    else {
142       cfg->makeEdge(new Target<RelocBlock *>(stub),
143                     new Target<block_instance *>(newfun->entryBlock()),
144                     NULL,
145                     ParseAPI::DIRECT);
146    }
147
148    // Redirect the springboard to the replacement function
149    cfg->setSpringboard(trace->block(), trace->func(), stub);
150
151    // Redirect all call in-edges to the replacement function
152    Predicates::Interprocedural pred;
153    if (target) {
154       if (!cfg->changeTargets(pred, trace->ins(), target)) return false;
155    }
156    else {
157       if (!cfg->changeTargets(pred, trace->ins(), newfun->entryBlock())) return false;
158    }
159    return true;
160 }
161
162 bool Modification::wrapFunction(RelocBlock *trace, RelocGraph *cfg) {
163    // See if we're the entry block
164    if (trace->block() != trace->func()->entryBlock()) return true;
165
166    FuncWrapMap::const_iterator iter = funcWraps_.find(trace->func());
167    if (iter == funcWraps_.end()) return true;
168    
169    // func_instance* oldfun = SCAST_FI(iter->first);
170    func_instance* newfun = SCAST_FI(iter->second.first);
171    std::string newname = iter->second.second;
172    
173
174    relocation_cerr << "Performing function wrapping in trace " << trace->id()
175                    << " going to function " << newfun->name()
176                    << " /w/ entry block "
177                    << (newfun->entryBlock() ? newfun->entryBlock()->start() : -1) << endl;
178
179    // This is a special case of replaceFunction; the predicate is "all calls except from the
180    // wrapper are redirected".
181    RelocBlock *stub = makeRelocBlock(newfun->entryBlock(),
182                                      newfun,
183                                      trace,
184                                      cfg);
185    RelocBlock *target = cfg->find(newfun->entryBlock(), newfun);
186    if (target) {
187       relocation_cerr << "\t Also relocated new function, using target " << target->id() << endl;
188       cfg->makeEdge(new Target<RelocBlock *>(stub),
189                     new Target<RelocBlock *>(target),
190                     NULL,
191                     ParseAPI::DIRECT);
192    }
193    else {
194       relocation_cerr << "\t New function " << newfun->name() << " not relocated targeting entry block " 
195                       << hex << newfun->entryBlock()->start() << dec << " directly" << endl;
196       cfg->makeEdge(new Target<RelocBlock *>(stub),
197                     new Target<block_instance *>(newfun->entryBlock()),
198                     NULL,
199                     ParseAPI::DIRECT);
200    }
201    relocation_cerr << "Stub block is " << stub->format() << endl;
202    
203    cfg->setSpringboard(trace->block(), trace->func(), stub);
204
205    WrapperPredicate pred(trace->func());
206    if (target) {
207       if (!cfg->changeTargets(pred, trace->ins(), target)) return false;
208    }
209    else {
210       if (!cfg->changeTargets(pred, trace->ins(), newfun->entryBlock())) return false;
211    }
212    // We also need to track the "new" entry block so we can build a new symbol for it.
213    CallbackWidget::Ptr c = CallbackWidget::create(new WrapperPatch(trace->func(), newname));
214    trace->elements().push_front(c);
215
216    return true;
217 }
218
219 RelocBlock *Modification::makeRelocBlock(block_instance *block, func_instance *func, RelocBlock *trace, RelocGraph *cfg) {
220    RelocBlock *t = RelocBlock::createStub(block, func);
221
222    // Current, new. 
223    cfg->addRelocBlockBefore(trace, t);
224    return t;
225 }
226
227 // TODO: make this mildly more efficient. On the other hand, is it a big deal?
228 Modification::WrapperPredicate::WrapperPredicate(func_instance *f)
229    : f_(f) {};
230
231
232 bool Modification::WrapperPredicate::operator()(RelocEdge *e) {
233    if (e->src->type() != TargetInt::RelocBlockTarget) return false;
234    RelocBlock *t = static_cast<Target<RelocBlock *> *>(e->src)->t();
235    return t->func() == f_;
236 }
237
238 bool Modification::WrapperPatch::apply(codeGen &gen, CodeBuffer *) {
239    // Tell our function to create a wrapper symbol at this address
240    func_->createWrapperSymbol(gen.currAddr(), name_);
241    return true;
242 }
243