Added instruction iterator
[dyninst.git] / dyninstAPI / src / BPatch_function.C
1 /*
2  * Copyright (c) 1996 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 // $Id: BPatch_function.C,v 1.24 2002/04/05 17:13:03 gaburici Exp $
43
44 #define BPATCH_FILE
45
46 #include <string.h>
47 #include "symtab.h"
48 #include "process.h"
49 #include "instPoint.h"
50
51 #include "BPatch.h"
52 #include "BPatch_type.h"
53 #include "BPatch_collections.h"
54 #include "BPatch_Vector.h"
55 #include "BPatch_flowGraph.h"
56 #include "BPatch_memoryAccess_NP.h"
57
58 #include "LineInformation.h"
59 #include "common/h/Types.h"
60 #include "InstrucIter.h"
61
62
63 /**************************************************************************
64  * BPatch_function
65  *************************************************************************/
66 /*
67  * BPatch_function::BPatch_function
68  *
69  * Constructor that creates a BPatch_function.
70  *
71  */
72 BPatch_function::BPatch_function(process *_proc, function_base *_func,
73         BPatch_module *_mod) :
74         proc(_proc), mod(_mod), cfg(NULL), func(_func)
75 {
76   // there should be at most one BPatch_func for each function_base per process
77   assert(proc->thread && !proc->PDFuncToBPFuncMap[func]);
78
79   _srcType = BPatch_sourceFunction;
80
81   localVariables = new BPatch_localVarCollection;
82   funcParameters = new BPatch_localVarCollection;
83   retType = NULL;
84
85   proc->PDFuncToBPFuncMap[_func] = this;
86
87 #if defined(i386_unknown_linux2_0) ||\
88      defined(i386_unknown_solaris2_5) ||\
89      defined(i386_unknown_nt4_0) ||\
90      defined(ia64_unknown_linux2_4) /* Temporary duplication - TLM */
91   iptrs = NULL;
92 #endif
93 };
94
95 /*
96  * BPatch_function::BPatch_function
97  *
98  * Constructor that creates the BPatch_function with return type.
99  *
100  */
101 BPatch_function::BPatch_function(process *_proc, function_base *_func,
102                                  BPatch_type * _retType, BPatch_module *_mod) :
103         proc(_proc), mod(_mod), cfg(NULL), func(_func)
104 {
105   assert(!proc->PDFuncToBPFuncMap[_func]);
106
107   _srcType = BPatch_sourceFunction;
108   localVariables = new BPatch_localVarCollection;
109   funcParameters = new BPatch_localVarCollection;
110   retType = _retType;
111
112   proc->PDFuncToBPFuncMap[_func] = this;
113 #if defined(i386_unknown_linux2_0) ||\
114     defined(i386_unknown_solaris2_5) ||\
115     defined(i386_unknown_nt4_0) ||\
116     defined(ia64_unknown_linux2_4) /* Temporary duplication - TLM */
117   iptrs = NULL;
118 #endif
119 };
120
121
122 BPatch_function::~BPatch_function()
123 {
124     // if (ast != NULL)
125         // removeAst(ast);
126     if (localVariables) delete localVariables;
127     if (funcParameters) delete funcParameters;
128     if (cfg) delete cfg;
129
130 #if defined(i386_unknown_linux2_0) ||\
131     defined(i386_unknown_solaris2_5) ||\
132     defined(i386_unknown_nt4_0) ||\
133     defined(ia64_unknown_linux2_4) /* Temporary duplication - TLM */
134     if (iptrs) delete[] iptrs;
135 #endif
136 }
137
138 /* 
139  * BPatch_function::getSourceObj()
140  *
141  * Return the contained source objects (e.g. statements).
142  *    This is not currently supported.
143  *
144  */
145 bool BPatch_function::getSourceObj(BPatch_Vector<BPatch_sourceObj *> &children)
146 {
147     // init and empty vector
148     BPatch_Vector<BPatch_sourceObj *> dummy;
149
150     children = dummy;
151     return false;
152 }
153
154 /*
155  * BPatch_function::getObjParent()
156  *
157  * Return the parent of the function (i.e. the module)
158  *
159  */
160 BPatch_sourceObj *BPatch_function::getObjParent()
161 {
162     return (BPatch_sourceObj *) mod;
163 }
164
165 /*
166  * BPatch_function::getName
167  *
168  * Copies the name of the function into a buffer, up to a given maximum
169  * length.  Returns a pointer to the beginning of the buffer that was
170  * passed in.
171  *
172  * s            The buffer into which the name will be copied.
173  * len          The size of the buffer.
174  */
175 char *BPatch_function::getName(char *s, int len) const
176 {
177     assert(func);
178     string name = func->prettyName();
179     strncpy(s, name.string_of(), len);
180
181     return s;
182 }
183
184 /*
185  * BPatch_function::getMangledName
186  *
187  * Copies the mangled name of the function into a buffer, up to a given maximum
188  * length.  Returns a pointer to the beginning of the buffer that was
189  * passed in.
190  *
191  * s            The buffer into which the name will be copied.
192  * len          The size of the buffer.
193  */
194 char *BPatch_function::getMangledName(char *s, int len) const
195 {
196     assert(func);
197     string name = func->symTabName();
198     strncpy(s, name.string_of(), len);
199
200     return s;
201 }
202
203 /*
204  * BPatch_function::getBaseAddr
205  *
206  * Returns the starting address of the function.
207  */
208 void *BPatch_function::getBaseAddr() const
209 {
210      return (void *)func->getEffectiveAddress(proc);
211 }
212
213 /*
214 * BPatch_function::getBaseAddrRelative
215 *
216 * Returns the starting address of the function in the module, relative
217 * to the module.
218 */
219 void *BPatch_function::getBaseAddrRelative() const
220 {
221         return (void *)func->addr();
222 }
223
224
225 /*
226  * BPatch_function::getSize
227  *
228  * Returns the size of the function in bytes.
229  */
230 unsigned int BPatch_function::getSize() const
231 {
232   return func->size();
233 }
234
235
236 /*
237  * BPatch_function::findPoint
238  *
239  * Returns a vector of the instrumentation points from a procedure that is
240  * identified by the parameters, or returns NULL upon failure.
241  * (Points are sorted by address in the vector returned.)
242  *
243  * loc          The points within the procedure to return.  The following
244  *              values are valid for this parameter:
245  *                BPatch_entry         The function's entry point.
246  *                BPatch_exit          The function's exit point(s).
247  *                BPatch_subroutine    The points at which the procedure calls
248  *                                     other procedures.
249  *                BPatch_longJump      The points at which the procedure make
250  *                                     long jump calls.
251  *                BPatch_allLocations  All of the points described above.
252  */
253 BPatch_Vector<BPatch_point*> *BPatch_function::findPoint(
254         const BPatch_procedureLocation loc)
255 {
256     // function does not exist!
257     if (func == NULL) return NULL;
258
259     // if the function is not instrumentable, we won't find the point
260     if (!isInstrumentable())
261         return NULL;
262
263     // function is generally uninstrumentable (with current technology)
264     if (func->funcEntry(proc) == NULL) return NULL;
265
266     BPatch_Vector<BPatch_point*> *result = new BPatch_Vector<BPatch_point *>;
267
268     if (loc == BPatch_entry || loc == BPatch_allLocations) {
269         result->push_back(proc->findOrCreateBPPoint(
270             this,const_cast<instPoint *>(func->funcEntry(proc)),BPatch_entry));
271     }
272     switch (loc) {
273       case BPatch_entry: // already done
274           break;
275       case BPatch_allLocations:
276         {
277           const vector<instPoint *> &Rpoints = func->funcExits(proc);
278           const vector<instPoint *> &Cpoints = func->funcCalls(proc);
279           unsigned int c=0, r=0;
280           Address cAddr, rAddr;
281           while (c < Cpoints.size() || r < Rpoints.size()) {
282               if (c < Cpoints.size()) cAddr = Cpoints[c]->iPgetAddress();
283               else                    cAddr = (Address)(-1);
284               if (r < Rpoints.size()) rAddr = Rpoints[r]->iPgetAddress();
285               else                    rAddr = (Address)(-1);
286               if (cAddr <= rAddr) {
287                   result->push_back(proc->findOrCreateBPPoint(
288                       this, Cpoints[c], BPatch_subroutine));
289                   c++;
290               } else {
291                   result->push_back(proc->findOrCreateBPPoint(
292                       this, Rpoints[r], BPatch_exit));
293                   r++;
294               }
295           }
296           break;
297         }
298       case BPatch_exit:
299         {
300           const vector<instPoint *> &points = func->funcExits(proc);
301           for (unsigned i = 0; i < points.size(); i++) {
302               result->push_back(proc->findOrCreateBPPoint(
303                   this, points[i], BPatch_exit));
304           }
305           break;
306         }
307       case BPatch_subroutine:
308         {
309           const vector<instPoint *> &points = func->funcCalls(proc);
310           for (unsigned i = 0; i < points.size(); i++) {
311               result->push_back(proc->findOrCreateBPPoint(
312                   this, points[i], BPatch_subroutine));
313           }
314           break;
315         }
316       case BPatch_longJump:
317         /* XXX Not yet implemented */
318       default:
319         assert( 0 );
320     }
321
322     return result;
323 }
324
325 // VG(03/01/02): Temporary speed fix - use the new function on AIX
326 #ifdef rs6000_ibm_aix4_1
327
328 // VG(03/01/02): There can be NO alternative point for a mem inst point
329 BPatch_point* BPatch_function::createMemInstPoint(void *addr,
330                                                   BPatch_memoryAccess* ma)
331 {
332   BPatch_point *p = createArbitraryPoint(this, (void*)addr);
333   if(p)
334     p->memacc = ma;
335   return p;
336 }
337
338 #else
339
340 BPatch_point* BPatch_function::createMemInstPoint(void *addr,
341                                                   BPatch_memoryAccess* ma)
342 {
343   return NULL;
344 }
345
346 // VG(09/17/01): created this 'cause didn't want to add more 
347 // platform independent code to inst-XXX.C
348 BPatch_point* createInstPointForMemAccess(process *proc,
349                                           void *addr,
350                                           BPatch_memoryAccess* ma,
351                                           BPatch_point** alternative = NULL)
352 {
353   // VG(09/17/01): This seems the right fuction to update all data structures
354   // Trouble is that updating these should be platfrom independent, while this
355   // function also does platform dependent stuff...
356   BPatch_point *p = createInstructionInstPoint(proc, (void*) addr, alternative);
357   if(p)
358     p->memacc = ma;
359   return p;
360 }
361 #endif
362
363 /*
364  * BPatch_function::findPoint (VG 09/05/01)
365  *
366  * Returns a vector of the instrumentation points from a procedure that is
367  * identified by the parameters, or returns NULL upon failure.
368  * (Points are sorted by address in the vector returned.)
369  *
370  * ops          The points within the procedure to return. A set of op codes
371  *              defined in BPatch_opCode (BPatch_point.h)
372  */
373 BPatch_Vector<BPatch_point*> *BPatch_function::findPoint(
374         const BPatch_Set<BPatch_opCode>& ops)
375 {
376   // function does not exist!
377   if (func == NULL) return NULL;
378
379   // function is generally uninstrumentable (with current technology)
380   if (func->funcEntry(proc) == NULL) return NULL;
381   
382   BPatch_Vector<BPatch_point*> *result = new BPatch_Vector<BPatch_point *>;
383
384   int osize = ops.size();
385   BPatch_opCode* opa = new BPatch_opCode[osize];
386   ops.elements(opa);
387
388   bool findLoads = false, findStores = false, findPrefetch = false;
389
390   for(int i=0; i<osize; ++i) {
391     switch(opa[i]) {
392     case BPatch_opLoad: findLoads = true; break;
393     case BPatch_opStore: findStores = true; break;      
394     case BPatch_opPrefetch: findPrefetch = true; break; 
395     }
396   }
397
398   //Address relativeAddress = (Address)getBaseAddrRelative();
399
400   // Use an instruction iterator
401   InstrucIter ii(this);
402   
403   //instruction inst;
404   //int xx = -1;
405
406   while(ii.hasMore()) {
407
408     //inst = ii.getInstruction();
409     Address addr = *ii;     // XXX this gives the address *stored* by ii...
410
411     BPatch_memoryAccess ma = ii.isLoadOrStore();
412
413     //fprintf(stderr, "?????: %x\n", addr);
414     ii++;
415
416     //BPatch_addrSpec_NP start = ma.getStartAddr();
417     //BPatch_countSpec_NP count = ma.getByteCount();
418     //int imm = start.getImm();
419     //int ra  = start.getReg(0);
420     //int rb  = start.getReg(1);
421     //int cnt = count.getImm();
422     //short int fcn = ma.prefetchType();
423     bool skip = false;
424
425     if(findLoads && ma.isALoad()) {
426       //fprintf(stderr, "LD[%d]: [%x -> %x], %d(%d)(%d) #%d\n",
427       //      ++xx, addr, inst, imm, ra, rb, cnt);
428       // XXX this leaks...
429 #ifdef rs6000_ibm_aix4_1
430       BPatch_point* p = createMemInstPoint((void *)addr,
431                                            new BPatch_memoryAccess(ma));
432 #else
433       BPatch_point* p = createInstPointForMemAccess(proc, (void*) addr,
434                                                     new BPatch_memoryAccess(ma));
435 #endif
436       if(p)
437         result->push_back(p);
438       skip = true;
439     }
440
441     if(findStores && !skip && ma.isAStore()) {
442       //fprintf(stderr, "ST[%d]: [%x -> %x], %d(%d)(%d) #%d\n",
443       //      ++xx, addr, inst, imm, ra, rb, cnt);
444       // XXX this leaks...
445 #ifdef rs6000_ibm_aix4_1
446       BPatch_point* p = createMemInstPoint((void *)addr,
447                                            new BPatch_memoryAccess(ma));
448 #else
449       BPatch_point* p = createInstPointForMemAccess(proc, (void*) addr,
450                                                     new BPatch_memoryAccess(ma));
451 #endif
452       if(p)
453         result->push_back(p);
454       skip = true;
455     }
456
457     if(findPrefetch && !skip && ma.isAPrefetch()) {
458       //fprintf(stderr, "PF[%d]: [%x -> %x], %d(%d)(%d) #%d %%%d\n",
459       //      ++xx, addr, inst, imm, ra, rb, cnt, fcn);
460       // XXX this leaks...
461 #ifdef rs6000_ibm_aix4_1
462       BPatch_point* p = createMemInstPoint((void *)addr,
463                                            new BPatch_memoryAccess(ma));
464 #else
465       BPatch_point* p = createInstPointForMemAccess(proc, (void*) addr,
466                                                     new BPatch_memoryAccess(ma));
467 #endif
468       if(p)
469         result->push_back(p);
470       skip = true;
471     }
472   }
473
474   return result;
475 }
476
477 /*
478  * BPatch_function::addParam()
479  *
480  * This function adds a function parameter to the BPatch_function parameter
481  * vector.
482  */
483 void BPatch_function::addParam(char * _name, BPatch_type *_type, int _linenum,
484                                int _frameOffset, int _sc)
485 {
486   BPatch_localVar * param = new BPatch_localVar(_name, _type, _linenum,
487                                                 _frameOffset, _sc);
488
489   // Add parameter to list of parameters
490   params.push_back(param);
491 }
492
493 /*
494  * BPatch_function::findLocalVar()
495  *
496  * This function searchs for a local variable in the BPatch_function's
497  * local variable collection.
498  */
499 BPatch_localVar * BPatch_function::findLocalVar(const char * name)
500 {
501
502   BPatch_localVar * var = localVariables->findLocalVar(name);
503   return (var);
504
505 }
506
507 /*
508  * BPatch_function::findLocalParam()
509  *
510  * This function searchs for a function parameter in the BPatch_function's
511  * parameter collection.
512  */
513 BPatch_localVar * BPatch_function::findLocalParam(const char * name)
514 {
515
516   BPatch_localVar * var = funcParameters->findLocalVar(name);
517   return (var);
518
519 }
520
521 /** method to retrieve addresses for a given line in the function
522   * if the line number is not valid, or if the line info is not available
523   * or if the module does not contain entry for the function then it returns
524   * false. If exact match is not set then the line which is the next
525   * greater or equal will be used.
526   */
527 bool BPatch_function::getLineToAddr(unsigned short lineNo,
528                    BPatch_Vector<unsigned long>& buffer,
529                    bool exactMatch)
530 {
531
532         //get the line info object and check whether it is available
533         LineInformation* lineInformation = mod->lineInformation;
534         if(!lineInformation){
535                 return false;
536         }
537
538         //get the object which contains the function being asked
539         FileLineInformation* fLineInformation = 
540                         lineInformation->getFunctionLineInformation(func->symTabName());
541         if(!fLineInformation){
542                 return false;
543         }
544
545         //retrieve the addresses
546         BPatch_Set<Address> addresses;
547         if(!fLineInformation->getAddrFromLine(func->symTabName(),addresses,
548                                               lineNo,false,exactMatch))
549                 return false;
550
551         //then insert the elements to the vector given
552         Address* elements = new Address[addresses.size()];
553         addresses.elements(elements);
554         for(int i=0;i<addresses.size();i++)
555                 buffer.push_back(elements[i]);
556         delete[] elements;
557         
558         return true;
559 }
560
561 //
562 // Return the module name, first and last line numbers of the function.
563 //
564 bool BPatch_function::getLineAndFile(unsigned int &start,
565                                      unsigned int &end,
566                                      char *fileName, unsigned &length)
567 {
568     start = end = 0;
569
570     //get the line info object and check whether it is available
571     LineInformation* lineInformation = mod->lineInformation;
572
573     if (!lineInformation) {
574         logLine("BPatch_function::getLineToAddr : Line info is not available");
575         return false;
576     }
577
578     //get the object which contains the function being asked
579     FileLineInformation* fLineInformation = 
580         lineInformation->getFunctionLineInformation(func->symTabName());
581
582     if (!fLineInformation) {
583         logLine("BPatch_function::getLineToAddr: Line info is not available");
584         return false;
585     }
586
587     //retrieve the addresses
588     FunctionInfo *funcLineInfo;
589
590     funcLineInfo = fLineInformation->findFunctionInfo(func->symTabName());
591
592     if (!funcLineInfo) return false;
593
594     if (funcLineInfo->startLinePtr)
595         start = funcLineInfo->startLinePtr->lineNo;
596
597     if (funcLineInfo->endLinePtr)
598         end = funcLineInfo->endLinePtr->lineNo;
599
600     strncpy(fileName, fLineInformation->getFileName().string_of(), length);
601     if (strlen(fLineInformation->getFileName().string_of()) < length) {
602         length = strlen(fLineInformation->getFileName().string_of());
603     }
604
605     return true;
606 }
607
608 BPatch_flowGraph* BPatch_function::getCFG(){
609         if(cfg)
610                 return cfg;
611
612         cfg = new BPatch_flowGraph((BPatch_function*)this);
613
614         return cfg;
615 }
616
617
618 BPatch_Vector<BPatch_localVar *> *BPatch_function::getVars() {
619       return localVariables->getAllVars(); 
620 }
621
622 BPatch_Vector<BPatch_variableExpr *> *BPatch_function::findVariable(const char *name)
623 {
624     BPatch_Vector<BPatch_variableExpr *> *ret;
625     BPatch_localVar *lv = findLocalVar(name);
626
627     if (!lv) {
628         // look for it in the parameter scope now
629         lv = findLocalParam(name);
630     }
631     if (lv) {
632         // create a local expr with the correct frame offset or absolute
633         //   address if that is what is needed
634         ret = new BPatch_Vector<BPatch_variableExpr *>;
635         BPatch_Vector<BPatch_point*> *points = findPoint(BPatch_entry);
636         assert(points->size() == 1);
637         ret->push_back(new BPatch_variableExpr(proc, (void *) lv->getFrameOffset(), 
638             lv->getType(), lv->getFrameRelative(), (*points)[0]));
639         return ret;
640     } else {
641         // finally check the global scope.
642         BPatch_image *imgPtr = (BPatch_image *) mod->getObjParent();
643
644         if (!imgPtr) return NULL;
645
646         BPatch_variableExpr *vars = imgPtr->findVariable(name);
647         if (!vars) return NULL;
648
649         ret = new BPatch_Vector<BPatch_variableExpr *>;
650         ret->push_back(vars);
651         return ret;
652     }
653 }
654
655 bool BPatch_function::getVariables(BPatch_Vector<BPatch_variableExpr *> &/*vect*/)
656 {
657         return false;
658 }
659
660 char *BPatch_function::getModuleName(char *name, int maxLen) {
661     return getModule()->getName(name, maxLen);
662 }
663
664 #ifdef IBM_BPATCH_COMPAT
665
666 bool BPatch_function::getLineNumbers(unsigned int &start, unsigned int &end) {
667     unsigned int length = 0;
668     return getLineAndFile(start, end, NULL, length);
669 }
670
671 void *BPatch_function::getAddress() { return getBaseAddr(); }
672     
673 bool BPatch_function::getAddressRange(void * &start, void * &end) {
674         start = getBaseAddr();
675         unsigned long temp = (unsigned long) start;
676         end = (void *) (temp + getSize());
677
678         return true;
679 }
680
681 //BPatch_type *BPatch_function::returnType() { return retType; }
682
683 void BPatch_function::getIncPoints(BPatch_Vector<BPatch_point *> &vect) 
684 {
685     BPatch_Vector<BPatch_point *> *v1 = findPoint(BPatch_allLocations);
686     if (v1) {
687         for (unsigned int i=0; i < v1->size(); i++) {
688             vect.push_back((*v1)[i]);
689         }
690     }
691 }
692
693 int     BPatch_function::getMangledNameLen() { return 1024; }
694
695 void BPatch_function::getExcPoints(BPatch_Vector<BPatch_point*> &points) {
696   points.clear();
697   abort();
698   return;
699 };
700
701 // return a function that can be passed as a paramter
702 BPatch_variableExpr *BPatch_function::getFunctionRef() { abort(); return NULL; }
703
704 #endif
705
706 /*
707  * BPatch_function::isInstrumentable
708  *
709  * Returns true if the function is instrumentable, false otherwise.
710  */
711 bool BPatch_function::isInstrumentable()
712 {
713      return ((pd_Function *)func)->isInstrumentable();
714 }
715