BPatch functions that block are now locked (on a finer grain than the rest of the...
[dyninst.git] / dyninstAPI / src / BPatch_point.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 #include <stdio.h>
43 #ifdef rs6000_ibm_aix4_1
44 #include <memory.h>
45 #endif
46
47 #include "common/h/headers.h"
48
49 #define BPATCH_FILE
50
51 #include "BPatch_point.h"
52 #include "BPatch_snippet.h"
53 #include "BPatch_type.h"
54 #include "BPatch_image.h"
55 #include "BPatch_collections.h"
56 #include "BPatch_asyncEventHandler.h"
57 #include "BPatch.h"
58 #include "process.h"
59 #include "symtab.h"
60 #include "instPoint.h"
61 #include "instP.h"
62
63 /*
64  * Private constructor
65  */
66 BPatch_point::BPatch_point(process *_proc, BPatch_function *_func, instPoint *_point,
67              BPatch_procedureLocation _pointType, BPatch_memoryAccess* _ma) :
68   // Note: MIPSPro compiler complains about redefinition of default argument
69   proc(_proc), func(_func), point(_point), pointType(_pointType), memacc(_ma)
70 {
71   point->bppoint = this;
72   if (_pointType == BPatch_subroutine)
73     dynamic_call_site_flag = 2; // dynamic status unknown
74   else
75     dynamic_call_site_flag = 0; // not a call site, so not a dynamic call site.
76   // I'd love to have a "loop" constructor, but the code structure
77   // doesn't work right. We create an entry point as a set of edge points,
78   // but not all edge points are loop points.
79   loop = NULL;
80 }
81
82 /*
83  * BPatch_point::setLoop
84  *
85  * For a BPatch_point representing a loop instrumentation site,
86  * set the loop that it represents.
87  */
88
89 void BPatch_point::setLoop(BPatch_basicBlockLoop *l) {
90   // No changing loops in the middle of the inst point!
91   assert(!loop ||
92          (loop == l));
93
94   // Point must be for a loop.
95   assert(pointType == BPatch_locLoopEntry ||
96          pointType == BPatch_locLoopExit ||
97          pointType == BPatch_locLoopStartIter ||
98          pointType == BPatch_locLoopEndIter);
99
100   loop = l;
101 }
102
103 /*
104  * BPatch_point::getPointType
105  *
106  * Returns type of BPatch_point
107  */
108
109 const BPatch_procedureLocation BPatch_point::getPointTypeInt() 
110
111    return pointType; 
112 }
113
114 /*
115  * BPatch_point::getLoop
116  *
117  * Returns loop if of appropriate type
118  */
119
120 BPatch_basicBlockLoop *BPatch_point::getLoopInt() 
121
122    return loop; 
123 }
124
125 /*
126  * BPatch_point::getFunction
127  *
128  * Returns function to which this BPatch_point belongs
129  */
130
131 const BPatch_function *BPatch_point::getFunctionInt()
132 {
133    return func;
134 }
135
136 /*
137  * BPatch_point::getCalledFunction
138  *
139  * For a BPatch_point representing a call site, returns a pointer to a
140  * BPatch_function that represents the function being called.  If the point
141  * isn't a call site, returns NULL.
142  */
143 BPatch_function *BPatch_point::getCalledFunctionInt()
144 {
145    BPatch_function *ret;
146    
147    assert(point);
148    
149    if (point->getPointType() != callSite)
150       return NULL;
151    
152    int_function *_func;
153    
154    if (!proc->findCallee(*point, _func))
155         return NULL;
156    
157    if (_func != NULL)
158       ret = proc->PDFuncToBPFuncMap[_func];
159    else
160       ret = NULL;
161     
162    return ret;
163 }
164
165 const BPatch_memoryAccess *BPatch_point::getMemoryAccessInt()
166 {
167   return memacc;
168 }
169
170 const BPatch_Vector<BPatchSnippetHandle *> BPatch_point::getCurrentSnippetsInt() 
171 {
172     pdvector<miniTrampHandle *> mt_buf;
173
174     trampTemplate *baseTramp = proc->baseMap[point];
175
176     if (baseTramp && baseTramp->pre_minitramps) {
177         List<miniTrampHandle *>::iterator preIter = baseTramp->pre_minitramps->get_begin_iter();
178         List<miniTrampHandle *>::iterator preEnd = baseTramp->pre_minitramps->get_end_iter();
179         for (; preIter != preEnd; preIter++) {
180             mt_buf.push_back(*preIter);
181         }
182     }
183     if (baseTramp && baseTramp->post_minitramps) {
184         List<miniTrampHandle *>::iterator postIter = baseTramp->post_minitramps->get_begin_iter();
185         List<miniTrampHandle *>::iterator postEnd = baseTramp->post_minitramps->get_end_iter();
186         for (; postIter != postEnd; postIter++) {
187             mt_buf.push_back(*postIter);
188         }
189     }
190     
191     BPatch_Vector<BPatchSnippetHandle *> snippetVec;
192     
193     for(unsigned i=0; i<mt_buf.size(); i++) {
194         BPatchSnippetHandle *handle = new BPatchSnippetHandle(proc);
195         handle->add(mt_buf[i]);
196         
197         snippetVec.push_back(handle);
198     }
199     return snippetVec;
200 }
201
202 const BPatch_Vector<BPatchSnippetHandle *> 
203 BPatch_point::getCurrentSnippetsByWhen(BPatch_callWhen when) 
204 {
205     pdvector<miniTrampHandle *> mt_buf;
206
207     trampTemplate *baseTramp = proc->baseMap[point];
208
209     if(when == BPatch_callBefore) {
210         List<miniTrampHandle *>::iterator preIter = baseTramp->pre_minitramps->get_begin_iter();
211         List<miniTrampHandle *>::iterator preEnd = baseTramp->pre_minitramps->get_end_iter();
212         for (; preIter != preEnd; preIter++) {
213             mt_buf.push_back(*preIter);
214         }
215     } else if(when == BPatch_callAfter) {
216         List<miniTrampHandle *>::iterator postIter = baseTramp->post_minitramps->get_begin_iter();
217         List<miniTrampHandle *>::iterator postEnd = baseTramp->post_minitramps->get_end_iter();
218         for (; postIter != postEnd; postIter++) {
219             mt_buf.push_back(*postIter);
220         }
221     }
222
223     BPatch_Vector<BPatchSnippetHandle *> snippetVec;
224     
225     for(unsigned i=0; i<mt_buf.size(); i++) {
226         BPatchSnippetHandle *handle = new BPatchSnippetHandle(proc);
227         handle->add(mt_buf[i]);
228         
229         snippetVec.push_back(handle);
230     }
231
232     return snippetVec;
233 }
234
235 /*
236  * BPatch_point::getAddress
237  *
238  * Returns the original address of the first instruction at this point.
239  */
240 void *BPatch_point::getAddressInt()
241 {
242     return (void *)point->absPointAddr(proc);
243 }
244
245
246 /*
247  * BPatch_point::usesTrap_NP
248  *
249  * Returns true if this point is or would be instrumented with a trap, rather
250  * than a jump to the base tramp, false otherwise.  On platforms that do not
251  * use traps (everything other than x86), it always returns false;
252  */
253 bool BPatch_point::usesTrap_NPInt()
254 {
255 #if defined(i386_unknown_solaris2_5) \
256  || defined(i386_unknown_nt4_0) \
257  || defined(i386_unknown_linux2_0) \
258  || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */
259     assert(point);
260     assert(proc);
261
262     return point->usesTrap(proc);
263 #else
264     return false;
265 #endif
266 }
267
268 /*
269  * BPatch_point::isDynamic
270  *
271  * Returns true if this point is a dynamic call site.
272  *
273  */
274 bool BPatch_point::isDynamicInt()
275 {
276 #if !defined(ia64_unknown_linux2_4)
277
278     if (!dynamic_call_site_flag) return false;
279     if (dynamic_call_site_flag == 1) return true;
280
281     assert(proc);
282     assert(point);
283
284     bool is_dyn = proc->isDynamicCallSite(point);
285     dynamic_call_site_flag = is_dyn ? 1 : 0;
286     return is_dyn;
287 #else
288     fprintf(stderr, "%s[%d]:  Dynamic Call Sites not implemented for ia64 yet\n",
289             __FILE__, __LINE__);
290     return false;
291 #endif
292 }
293
294 /*
295  * BPatch_point::monitorCalls(BPatch_function *userCBFunc)
296  *
297  * Insert function call to user-defined callback function
298  * at dynamic call site.
299  *
300  * Returns false if BPatch_point is not a dynamic call site.
301  *
302  */
303
304 void *BPatch_point::monitorCallsInt( BPatch_function * user_cb ) {
305
306   if ( !isDynamic() ) {
307     fprintf(stderr, "%s[%d]:  call site is not dynamic, cannot monitor\n", 
308             __FILE__, __LINE__ );
309     return NULL;
310   }
311
312   // The callback takes two arguments: the first is the (address of the) callee,
313   // the second the (address of the) callsite. 
314
315   pdvector<AstNode *> args;
316   if ( (!proc->getDynamicCallSiteArgs( point,args )) || (args.size() != 2) ) {
317      fprintf(stderr,"%s[%d]:  could not get address arguments for dynamic call site\n",  
318              __FILE__, __LINE__);
319      return NULL;
320   }
321
322   // construct function call and insert
323   int_function * fb = user_cb->func;
324
325   // Monitoring function
326   AstNode * func = new AstNode( fb, args );
327   miniTrampHandle * mtHandle = NULL;
328   addInstFunc(  proc, mtHandle, point, func, callPreInsn,
329                                         orderLastAtPoint,
330                                         true,   /* noCost flag   */
331                                         false,  /* trampRecursiveDesired flag */
332                                         true ); /* allowTrap */
333
334   if ( ! mtHandle ) {
335      fprintf( stderr,"%s[%d]:  insertSnippet failed, cannot monitor call site\n",
336                __FILE__, __LINE__ );
337      return NULL;
338   }
339
340   dynamicMonitoringCalls.push_back(mtHandle);
341
342   //  Return pointer to handle as unique id, user does not need to know its a
343   //  miniTrampHandle.
344
345   return (void*) mtHandle;
346 } /* end monitorCalls() */
347
348 bool BPatch_point::stopMonitoringInt(void * handle)
349 {
350   miniTrampHandle *target = NULL, *mtHandle = (miniTrampHandle *) handle;
351
352   for (unsigned int i = 0 ; i < dynamicMonitoringCalls.size(); ++i) {
353     if (!target) {
354       // haven't found it yet -- keep looking
355       if (dynamicMonitoringCalls[i] == mtHandle) {
356         target = dynamicMonitoringCalls[i];
357       } 
358     }
359     if (target) {
360       //  target is found, shift everthing after it one to the left.
361       //  (this removes target from the array)
362       if ( (i+1) < dynamicMonitoringCalls.size()) {
363         dynamicMonitoringCalls[i] = dynamicMonitoringCalls[i+1];
364       }
365       else {
366         // last element, resize vector (length - 1)
367         dynamicMonitoringCalls.resize(dynamicMonitoringCalls.size()-1);
368       }
369     }    
370   }
371
372   if (!target) {
373     bperr("%s[%d]:  call site not currently monitored", __FILE__, __LINE__);
374     return false;
375   }
376
377   bool ret;
378   ret = deleteInst(proc, target);
379
380   return ret;
381 }
382
383 //  BPatch_point::registerDynamicCallCallback
384 //
385 //  Specifies a user-supplied function to be called when a dynamic call is
386 //  executed.
387 //
388 //  Returns a handle (useful for de-registering callback), NULL if error
389
390 void *BPatch_point::registerDynamicCallCallbackInt(BPatchDynamicCallSiteCallback cb)
391 {
392   void *ret = NULL;
393   BPatch_asyncEventHandler *eventHandler = BPatch::bpatch->eventHandler;
394   ret = eventHandler->registerDynamicCallCallback(cb, this);
395   if (ret) BPatch::bpatch->asyncActive = true;
396   return ret;
397 }
398
399 //  BPatch_point::removeDynamicCallCallback
400 //
401 //  Argument is (void *) handle to previously specified callback function to be
402 //  de-listed.
403 //
404 //  Returns true upon success, false if handle is not currently represented
405
406 bool BPatch_point::removeDynamicCallCallbackInt(void *handle)
407 {
408   BPatch_asyncEventHandler *eventHandler = BPatch::bpatch->eventHandler;
409   return eventHandler->removeDynamicCallCallback(handle);
410 }