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