extended parseThat to use new addressSpace abstraction
[dyninst.git] / dyninstAPI / src / BPatch_addressSpace.C
1 /*
2  * Copyright (c) 1996-2004 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  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42
43
44 #define BPATCH_FILE
45
46
47 #include "process.h"
48 #include "EventHandler.h"
49 #include "mailbox.h"
50 #include "signalgenerator.h"
51 #include "inst.h"
52 #include "instP.h"
53 #include "instPoint.h"
54 #include "function.h" // int_function
55 #include "codeRange.h"
56 #include "dyn_thread.h"
57 #include "miniTramp.h"
58
59 #include "mapped_module.h"
60
61 #include "BPatch_libInfo.h"
62 #include "BPatch_asyncEventHandler.h"
63 #include "BPatch.h"
64 #include "BPatch_thread.h"
65 #include "LineInformation.h"
66 #include "BPatch_function.h"
67 #include "callbacks.h"
68
69 #include "BPatch_private.h"
70
71 #include "ast.h"
72
73 #include "BPatch_addressSpace.h"
74
75
76 BPatch_addressSpace::BPatch_addressSpace() :
77    func_map(NULL),
78    instp_map(NULL),
79    image(NULL)
80 {
81 }
82
83 BPatch_addressSpace::~BPatch_addressSpace()
84 {}
85
86
87 BPatch_function *BPatch_addressSpace::findOrCreateBPFunc(int_function* ifunc,
88                                                     BPatch_module *bpmod)
89 {
90   if( func_map->defines(ifunc) ) {
91     assert( func_map->get(ifunc) != NULL );
92     return func_map->get(ifunc);
93   }
94   
95   // Find the module that contains the function
96   if (bpmod == NULL && ifunc->mod() != NULL) {
97       bpmod = getImage()->findModule(ifunc->mod()->fileName().c_str());
98   }
99
100   // findModule has a tendency to make new function objects... so
101   // check the map again
102   if (func_map->defines(ifunc)) {
103     assert( func_map->get(ifunc) != NULL );
104     return func_map->get(ifunc);
105   }
106
107   BPatch_function *ret = new BPatch_function(this, ifunc, bpmod);
108   assert( ret != NULL );
109   return ret;
110 }
111
112 BPatch_point *BPatch_addressSpace::findOrCreateBPPoint(BPatch_function *bpfunc, 
113                                                   instPoint *ip, 
114                                                   BPatch_procedureLocation pointType)
115 {
116     assert(ip);
117    if (instp_map->defines(ip)) 
118       return instp_map->get(ip);
119
120    if (bpfunc == NULL) 
121        bpfunc = findOrCreateBPFunc(ip->func(), NULL);
122
123    
124    
125    BPatch_point *pt = new BPatch_point(this, bpfunc, ip, pointType);
126
127    instp_map->add(ip, pt);
128
129    return pt;
130 }
131
132
133
134
135 /***************************************************************************
136  * Bpatch_snippetHandle
137  ***************************************************************************/
138
139 /*
140  * BPatchSnippetHandle::BPatchSnippetHandle
141  *
142  * Constructor for BPatchSnippetHandle.  Delete the snippet instance(s)
143  * associated with the BPatchSnippetHandle.
144  */
145 BPatchSnippetHandle::BPatchSnippetHandle(BPatch_addressSpace * addSpace) :
146     addSpace_(addSpace)
147 {
148 }
149
150 /*
151  * BPatchSnippetHandle::~BPatchSnippetHandle
152  *
153  * Destructor for BPatchSnippetHandle.  Delete the snippet instance(s)
154  * associated with the BPatchSnippetHandle.
155  */
156 void BPatchSnippetHandle::BPatchSnippetHandle_dtor()
157 {
158    // don't delete inst instances since they are might have been copied
159 }
160
161 BPatch_addressSpace *BPatchSnippetHandle::getAddressSpaceInt()
162 {
163   return addSpace_;
164 }
165
166
167 BPatch_process *BPatchSnippetHandle::getProcessInt()
168 {
169   return proc_;
170 }
171
172
173 BPatch_Vector<BPatch_thread *> &BPatchSnippetHandle::getCatchupThreadsInt()
174 {
175   return catchup_threads;
176 }
177
178
179 BPatch_image * BPatch_addressSpace::getImageInt()
180 {
181   return image;
182 }
183
184
185 /*
186  * BPatch_addressSpace::deleteSnippet
187  * 
188  * Deletes an instance of a snippet.
189  *
190  * handle       The handle returned by insertSnippet when the instance to
191  *              deleted was created.
192  */
193
194 bool BPatch_addressSpace::deleteSnippetInt(BPatchSnippetHandle *handle)
195 {   
196     if (getTerminated()) return true;
197
198     //    if (handle->proc_ == this) {
199     if (handle->addSpace_ == this) {  
200       for (unsigned int i=0; i < handle->mtHandles_.size(); i++)
201         handle->mtHandles_[i]->uninstrument();
202       delete handle;
203       return true;
204     } 
205     // Handle isn't to a snippet instance in this process
206     cerr << "Error: wrong address space in deleteSnippet" << endl;     
207     return false;
208 }
209
210 /*
211  * BPatch_addressSpace::replaceCode
212  *
213  * Replace a given instruction with a BPatch_snippet.
214  *
215  * point       Represents the instruction to be replaced
216  * snippet     The replacing snippet
217  */
218
219 bool BPatch_addressSpace::replaceCodeInt(BPatch_point *point,
220                                     BPatch_snippet *snippet) {
221    if (!getMutationsActive())
222       return false;
223
224     if (!point) {
225         return false;
226     }
227     if (getTerminated()) {
228         return true;
229     }
230
231     if (point->edge_) {
232         return false;
233     }
234
235     // Calculate liveness to make things cheaper
236
237 #if defined(os_aix) || defined(arch_x86_64)
238         // Toss the const; the function _pointer_ doesn't though.
239         BPatch_function *func = point->getFunction();
240         func->calc_liveness(point);
241 #endif 
242
243
244     return point->point->replaceCode(*(snippet->ast_wrapper));
245 }
246
247
248
249 /*
250  * BPatch_addressSpace::replaceFunctionCall
251  *
252  * Replace a function call with a call to a different function.  Returns true
253  * upon success, false upon failure.
254  * 
255  * point        The call site that is to be changed.
256  * newFunc      The function that the call site will now call.
257  */
258 bool BPatch_addressSpace::replaceFunctionCallInt(BPatch_point &point,
259                                             BPatch_function &newFunc)
260 {
261    // Can't make changes to code when mutations are not active.
262    if (!getMutationsActive())
263       return false;
264    assert(point.point && newFunc.lowlevel_func());
265    return getAS()->replaceFunctionCall(point.point, newFunc.lowlevel_func());
266 }
267
268 /*
269  * BPatch_addressSpace::removeFunctionCall
270  *
271  * Replace a function call with a NOOP.  Returns true upon success, false upon
272  * failure.
273  * 
274  * point        The call site that is to be NOOPed out.
275  */
276 bool BPatch_addressSpace::removeFunctionCallInt(BPatch_point &point)
277 {
278    // Can't make changes to code when mutations are not active.
279    if (!getMutationsActive())
280       return false;   
281    assert(point.point);
282    return getAS()->replaceFunctionCall(point.point, NULL);
283 }
284
285
286 /*
287  * BPatch_addressSpace::replaceFunction
288  *
289  * Replace all calls to function OLDFUNC with calls to NEWFUNC.
290  * Returns true upon success, false upon failure.
291  * 
292  * oldFunc      The function to replace
293  * newFunc      The replacement function
294  */
295 bool BPatch_addressSpace::replaceFunctionInt(BPatch_function &oldFunc,
296                                         BPatch_function &newFunc)
297 {
298 #if defined(os_solaris) || defined(os_osf) || defined(os_linux) || \
299     defined(os_windows) \
300
301     assert(oldFunc.lowlevel_func() && newFunc.lowlevel_func());
302     if (!getMutationsActive())
303         return false;
304     
305     // Self replacement is a nop
306     // We should just test direct equivalence here...
307     if (oldFunc.lowlevel_func() == newFunc.lowlevel_func()) {
308         return true;
309     }
310
311    bool old_recursion_flag = BPatch::bpatch->isTrampRecursive();
312    BPatch::bpatch->setTrampRecursive( true );
313    
314    // We replace functions by instrumenting the entry of OLDFUNC with
315    // a non-linking jump to NEWFUNC.  Calls to OLDFUNC do actually
316    // transfer to OLDFUNC, but then our jump shunts them to NEWFUNC.
317    // The non-linking jump ensures that when NEWFUNC returns, it
318    // returns directly to the caller of OLDFUNC.
319    BPatch_Vector<BPatch_point *> *pts = oldFunc.findPoint(BPatch_entry);
320    if (! pts || ! pts->size()) {
321       BPatch::bpatch->setTrampRecursive( old_recursion_flag );
322       return false;
323    }
324    BPatch_funcJumpExpr fje(newFunc);
325    BPatchSnippetHandle * result = insertSnippet(fje, *pts, BPatch_callBefore);
326    
327    BPatch::bpatch->setTrampRecursive( old_recursion_flag );
328    
329    return (NULL != result);
330 #else
331    char msg[2048];
332    char buf1[512], buf2[512];
333    sprintf(msg, "cannot replace func %s with func %s, not implemented",
334            oldFunc.getName(buf1, 512), newFunc.getName(buf2, 512));
335     
336    BPatch_reportError(BPatchSerious, 109, msg);
337    BPatch_reportError(BPatchSerious, 109,
338                       "replaceFunction is not implemented on this platform");
339    return false;
340 #endif
341 }
342
343
344 bool BPatch_addressSpace::getAddressRangesInt( const char * fileName, unsigned int lineNo, std::vector< std::pair< unsigned long, unsigned long > > & ranges ) {
345         unsigned int originalSize = ranges.size();
346
347         /* Iteratate over the modules, looking for addr in each. */
348         BPatch_Vector< BPatch_module * > * modules = image->getModules();
349         for( unsigned int i = 0; i < modules->size(); i++ ) {
350                 LineInformation *lineInformation = (* modules)[i]->mod->getLineInformation();           
351                 if(lineInformation)
352                         lineInformation->getAddressRanges( fileName, lineNo, ranges );
353                 } /* end iteration over modules */
354         if( ranges.size() != originalSize ) { return true; }
355         
356         return false;
357         } /* end getAddressRangesInt() */
358
359 bool BPatch_addressSpace::getSourceLinesInt( unsigned long addr, 
360                                         BPatch_Vector< BPatch_statement > & lines ) 
361 {
362    return image->getSourceLinesInt(addr, lines);
363 } /* end getLineAndFile() */
364
365
366 /*
367  * BPatch_process::malloc
368  *
369  * Allocate memory in the thread's address space.
370  *
371  * n    The number of bytes to allocate.
372  *
373  * Returns:
374  *      A pointer to a BPatch_variableExpr representing the memory.
375  *
376  */
377 BPatch_variableExpr *BPatch_addressSpace::mallocInt(int n)
378 {
379    assert(BPatch::bpatch != NULL);
380    void *ptr = (void *) getAS()->inferiorMalloc(n, dataHeap);
381    if (!ptr) return NULL;
382    return new BPatch_variableExpr(this, ptr, Null_Register, 
383                                   BPatch::bpatch->type_Untyped);
384 }
385
386
387 /*
388  * BPatch_process::malloc
389  *
390  * Allocate memory in the thread's address space for a variable of the given
391  * type.
392  *
393  * type         The type of variable for which to allocate space.
394  *
395  * Returns:
396  *      A pointer to a BPatch_variableExpr representing the memory.
397  *
398  * XXX Should return NULL on failure, but the function which it calls,
399  *     inferiorMalloc, calls exit rather than returning an error, so this
400  *     is not currently possible.
401  */
402 BPatch_variableExpr *BPatch_addressSpace::mallocByType(const BPatch_type &type)
403 {
404    assert(BPatch::bpatch != NULL);
405    BPatch_type &t = const_cast<BPatch_type &>(type);
406    void *mem = (void *) getAS()->inferiorMalloc(t.getSize(), dataHeap);
407    if (!mem) return NULL;
408    return new BPatch_variableExpr(this, mem, Null_Register, &t);
409 }
410
411
412 /*
413  * BPatch_process::free
414  *
415  * Free memory that was allocated with BPatch_process::malloc.
416  *
417  * ptr          A BPatch_variableExpr representing the memory to free.
418  */
419 bool BPatch_addressSpace::freeInt(BPatch_variableExpr &ptr)
420 {
421    getAS()->inferiorFree((Address)ptr.getBaseAddr());
422    return true;
423 }
424
425
426
427 /*
428  * BPatch_addressSpace::findFunctionByAddr
429  *
430  * Returns the function that contains the specified address, or NULL if the
431  * address is not within a function.
432  *
433  * addr         The address to use for the lookup.
434  */
435 BPatch_function *BPatch_addressSpace::findFunctionByAddrInt(void *addr)
436 {
437    int_function *func;
438    
439    codeRange *range = getAS()->findOrigByAddr((Address) addr);
440    if (!range)
441       return NULL;
442
443    func = range->is_function();
444     
445    if (!func)
446       return NULL;
447     
448    return findOrCreateBPFunc(func, NULL);
449 }
450
451