Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI / src / inst.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 // $Id: inst.C,v 1.166 2008/06/26 20:40:15 bill Exp $
33 // Code to install and remove instrumentation from a running process.
34 // Misc constructs.
35
36 #include <assert.h>
37 //#include <sys/signal.h>
38 //#include <sys/param.h>
39 #include "dyninstAPI/src/symtab.h"
40 #include "dyninstAPI/src/process.h"
41 #include "dyninstAPI/src/inst.h"
42 #include "dyninstAPI/src/instP.h"
43 #include "dyninstAPI/src/ast.h"
44 #include "dyninstAPI/src/util.h"
45 #include "common/h/stats.h"
46 #include "dyninstAPI/src/debug.h"
47 #include "dyninstAPI/src/instPoint.h"
48 #include "dyninstAPI/src/miniTramp.h"
49 #include "dyninstAPI/src/baseTramp.h"
50 //#include "dyninstAPI/src/InstrucIter.h"
51 #include "dyninstAPI/src/function.h"
52 #include "dyninstAPI/src/image-func.h"
53 #include "dyninstAPI/src/arch.h"
54
55
56 /*
57  * return the time required to execute the passed primitive.
58  *
59  */
60 unsigned getPrimitiveCost(const std::string &name)
61 {
62
63     static bool init=false;
64
65     if (!init) { init = 1; initPrimitiveCost(); }
66
67     if (!primitiveCosts.defines(name)) {
68       return 1;
69     } else
70       return (primitiveCosts[name]);
71 }
72
73
74 // find any tags to associate semantic meaning to function
75 unsigned findTags(const std::string ) {
76   return 0;
77 #ifdef notdef
78   if (tagDict.defines(funcName))
79     return (tagDict[funcName]);
80   else
81     return 0;
82 #endif
83 }
84
85 // IA64 has its own version; dunno if this would work there, so skipping for now
86 unsigned generateAndWriteBranch(AddressSpace *proc, 
87                                 Address fromAddr, 
88                                 Address newAddr,
89                                 unsigned fillSize)
90 {
91     assert(fillSize != 0);
92
93     codeGen gen(fillSize);
94
95 #if defined(os_aix)
96     instruction::generateInterFunctionBranch(gen, fromAddr, newAddr);
97 #else
98     instruction::generateBranch(gen, fromAddr, newAddr);
99 #endif
100     gen.fillRemaining(codeGen::cgNOP);
101     
102     proc->writeTextSpace((caddr_t)fromAddr, gen.used(), gen.start_ptr());
103     return gen.used();
104 }
105
106 unsigned trampEnd::maxSizeRequired() {
107 #if defined(arch_x86) || defined(arch_x86_64)
108     unsigned illegalSize = 2;
109 #else
110     unsigned illegalSize = instruction::size();
111 #endif
112     // Return branch, illegal.
113     return (instruction::maxJumpSize(multi_->proc()->getAddressWidth()) + illegalSize);
114 }
115
116
117 trampEnd::trampEnd(multiTramp *multi, Address target) :
118     multi_(multi), target_(target) 
119 {}
120
121 Address relocatedInstruction::originalTarget() const {
122 #if defined(cap_relocation)
123     if (targetAddr_) return targetAddr_;
124 #else
125     assert(targetAddr_ == 0);
126 #endif
127   return insn->getTarget(origAddr_);
128 }
129
130 void relocatedInstruction::overrideTarget(patchTarget *newTarget) {
131   targetOverride_ = newTarget;
132 }
133
134 #if defined (cap_unwind)
135 bool trampEnd::generateCode(codeGen &gen,
136                             Address baseInMutatee,
137                             UNW_INFO_TYPE ** unwindRegion ) 
138 #else
139 bool trampEnd::generateCode(codeGen &gen,
140                             Address baseInMutatee,
141                             UNW_INFO_TYPE ** /*unwindRegion*/ )
142 #endif
143 {
144     generateSetup(gen, baseInMutatee);
145
146     if (target_) {
147         instruction::generateBranch(gen,
148                                     gen.currAddr(baseInMutatee),
149                                     target_);
150     }
151
152     // And a sigill insn
153     instruction::generateIllegal(gen);
154     
155     size_ = gen.currAddr(baseInMutatee) - addrInMutatee_;
156     generated_ = true;
157     hasChanged_ = false;
158
159 #if defined( cap_unwind )
160     /* The jump back is an zero-length ALIAS to the original location, followed
161        by a no-op region covering the jump bundle. */
162     dyn_unw_printf( "%s[%d]: aliasing tramp end to 0x%lx\n", __FILE__, __LINE__, multi_->instAddr() );
163     unw_dyn_region_info_t * aliasRegion = (unw_dyn_region_info_t *)malloc( _U_dyn_region_info_size( 2 ) );
164     assert( aliasRegion != NULL );
165     aliasRegion->insn_count = 0;
166     aliasRegion->op_count = 2;
167     
168     _U_dyn_op_alias( & aliasRegion->op[0], _U_QP_TRUE, -1, multi_->instAddr() );
169     _U_dyn_op_stop( & aliasRegion->op[1] );
170     
171     unw_dyn_region_info_t * jumpRegion = (unw_dyn_region_info_t *)malloc( _U_dyn_region_info_size( 1 ) );
172     assert( jumpRegion != NULL );
173 #if defined( arch_ia64 )    
174     jumpRegion->insn_count = (size_ / 16) * 3;
175 #else
176 #error How do I know how many instructions are in the jump region?
177 #endif /* defined( arch_ia64 ) */
178     jumpRegion->op_count = 1;
179     
180     _U_dyn_op_stop( & jumpRegion->op[0] );
181     
182     /* The care and feeding of pointers. */
183     assert( unwindRegion != NULL );
184     unw_dyn_region_info_t * prevRegion = * unwindRegion;
185     prevRegion->next = aliasRegion;
186     aliasRegion->next = jumpRegion;
187     jumpRegion->next = NULL;
188     * unwindRegion = jumpRegion;
189 #endif /* defined( cap_unwind ) */
190         
191     return true;
192 }
193
194 instMapping::instMapping(const instMapping *parIM,
195                          process *child) :
196     func(parIM->func),
197     inst(parIM->inst),
198     where(parIM->where),
199     when(parIM->when),
200     order(parIM->order),
201     useTrampGuard(parIM->useTrampGuard),
202     mt_only(parIM->mt_only),
203     allow_trap(parIM->allow_trap)
204 {
205     for (unsigned i = 0; i < parIM->args.size(); i++) {
206         args.push_back(parIM->args[i]);
207     }
208     for (unsigned j = 0; j < parIM->miniTramps.size(); j++) {
209         miniTramp *cMT = NULL;
210         cMT = parIM->miniTramps[j]->getInheritedMiniTramp(child);
211         assert(cMT);
212         miniTramps.push_back(cMT);
213     }
214 }
215
216 Address relocatedInstruction::relocAddr() const {
217     return addrInMutatee_;
218 }
219
220 void *relocatedInstruction::getPtrToInstruction(Address) const {
221     assert(0); // FIXME if we do out-of-line baseTramps
222     return NULL;
223 }
224
225 void *trampEnd::getPtrToInstruction(Address) const {
226     assert(0); // FIXME if we do out-of-line baseTramps
227     return NULL;
228 }
229
230 // process::replaceFunctionCall
231 //
232 // Replace the function call at the given instrumentation point with a call to
233 // a different function, or with a NOOP.  In order to replace the call with a
234 // NOOP, pass NULL as the parameter "func."
235 // Returns true if sucessful, false if not.  Fails if the site is not a call
236 // site, or if the site has already been instrumented using a base tramp.
237 //
238 // Note that right now we can only replace a call instruction that is five
239 // bytes long (like a call to a 32-bit relative address).
240 // 18APR05: don't see why we can't fix up a base tramp, it's just a little more
241 // complicated.
242
243 // By the way, we want to be able to disable these, which means keeping
244 // track of what we put in. Since addresses are unique, we can do it with
245 // a dictionary in the process class.
246
247 #if !defined(arch_ia64)
248 // arch-ia64 has its own version (of course...) since it's a lot
249 // more complicated
250 bool AddressSpace::replaceFunctionCall(instPoint *point,
251                                        const int_function *func) {
252     // Must be a call site
253   if (point->getPointType() != callSite)
254     return false;
255
256 #if defined(cap_instruction_replacement) 
257     if (func) {
258         pdvector<AstNodePtr> emptyArgs;
259         // To do this we must be able to make a non-state-affecting
260         // function call. Currently it's only implemented on POWER, although
261         // it would be easy to do for x86 as well...
262         AstNodePtr call = AstNode::funcCallNode(const_cast<int_function *>(func), emptyArgs);
263         return point->replaceCode(call);
264     }
265     else {
266         // Remove the function call entirely
267         AstNodePtr nullNode = AstNode::nullNode();
268         return point->replaceCode(nullNode);
269     }
270     
271 #else
272
273   return point->replaceCode(AstNode::funcCallNode(const_cast<int_function *>(func)));
274
275   instPointIter ipIter(point);
276   instPointInstance *ipInst;
277   while ((ipInst = ipIter++)) {  
278       // Multiple replacements. Wheee...
279       Address pointAddr = ipInst->addr();
280
281       codeRange *range = findModByAddr(pointAddr);
282       if (range) {
283             multiTramp *multi = range->is_multitramp();
284           if (multi) {
285                 // We pre-create these guys... so check to see if
286               // there's anything there
287               if (!multi->generated()) {
288                   removeMultiTramp(multi);
289               }
290               else {
291                   // TODO: modify the callsite in the multitramp.
292                   assert(0);
293               }
294           }
295           else if (dynamic_cast<functionReplacement *>(range)) {
296               // We overwrote this in a function replacement...
297               continue; 
298           }
299       }
300 #if defined(cap_instruction_api)      
301       codeGen gen(point->insn()->size());
302 #else //defined(cap_instruction_api)
303       codeGen gen(point->insn().size());
304 #endif //defined(cap_instruction_api)
305       gen.setAddrSpace(this);
306       gen.setPoint(point);
307
308       // Uninstrumented
309       // Replace the call
310       if (func == NULL) {       // Replace with NOOPs
311           gen.fillRemaining(codeGen::cgNOP);
312       } else { // Replace with a call to a different function
313           // XXX Right only, call has to be 5 bytes -- sometime, we should make
314           // it work for other calls as well.
315           //assert(point->insn().size() == CALL_REL32_SZ);
316           instruction::generateCall(gen, pointAddr, func->getAddress());
317       }
318       
319       // Before we replace, track the code.
320       // We could be clever with instpoints keeping instructions around, but
321       // it's really not worth it.
322       replacedFunctionCall *newRFC = new replacedFunctionCall();
323       newRFC->callAddr = pointAddr;
324 #if defined(cap_instruction_api)
325       newRFC->callSize = point->insn()->size();
326 #else //defined(cap_instruction_api)
327       newRFC->callSize = point->insn().size();
328 #endif //defined(cap_instruction_api)
329       if (func)
330           newRFC->newTargetAddr = func->getAddress();
331       else
332           newRFC->newTargetAddr = 0;
333
334 #if defined(cap_instruction_api)
335       codeGen old(point->insn()->size());
336       old.copy(point->insn()->ptr(), point->insn()->size());
337 #else //defined(cap_instruction_api)
338       codeGen old(point->insn().size());
339       old.copy(point->insn().ptr(), point->insn().size());
340 #endif //defined(cap_instruction_api)
341       
342       newRFC->oldCall = old;
343       newRFC->newCall = gen;
344       
345       addReplacedCall(newRFC);
346
347       writeTextSpace((void *)pointAddr, gen.used(), gen.start_ptr());
348   }
349   return true;
350 #endif
351 }
352 #endif