This commit implements the functions BPatch_function::isSharedLib() and
[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.30 2003/01/29 23:01:22 jodom 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.c_str(), 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.c_str(), 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 pdvector<instPoint *> &Rpoints = func->funcExits(proc);
278           const pdvector<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 pdvector<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 pdvector<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 = createInstructionInstPoint(proc, (void*) addr, NULL,
333                                                this);
334   if(p)
335     p->memacc = ma;
336   return p;
337 }
338
339 #else
340
341 BPatch_point* BPatch_function::createMemInstPoint(void *addr,
342                                                   BPatch_memoryAccess* ma)
343 {
344   return NULL;
345 }
346
347 // VG(09/17/01): created this 'cause didn't want to add more 
348 // platform independent code to inst-XXX.C
349 BPatch_point* createInstPointForMemAccess(process *proc,
350                                           void *addr,
351                                           BPatch_memoryAccess* ma,
352                                           BPatch_point** alternative = NULL)
353 {
354   // VG(09/17/01): This seems the right fuction to update all data structures
355   // Trouble is that updating these should be platfrom independent, while this
356   // function also does platform dependent stuff...
357   //fprintf(stderr, "memcreat@%p\n", addr);
358   BPatch_point *p = createInstructionInstPoint(proc, (void*) addr, alternative);
359   if(p)
360     p->memacc = ma;
361   return p;
362 }
363 #endif
364
365 /*
366  * BPatch_function::findPoint (VG 09/05/01)
367  *
368  * Returns a vector of the instrumentation points from a procedure that is
369  * identified by the parameters, or returns NULL upon failure.
370  * (Points are sorted by address in the vector returned.)
371  *
372  * ops          The points within the procedure to return. A set of op codes
373  *              defined in BPatch_opCode (BPatch_point.h)
374  */
375 BPatch_Vector<BPatch_point*> *BPatch_function::findPoint(
376         const BPatch_Set<BPatch_opCode>& ops)
377 {
378   // function does not exist!
379   if (func == NULL) return NULL;
380
381   // function is generally uninstrumentable (with current technology)
382   if (func->funcEntry(proc) == NULL) return NULL;
383   
384   BPatch_Vector<BPatch_point*> *result = new BPatch_Vector<BPatch_point *>;
385
386   int osize = ops.size();
387   BPatch_opCode* opa = new BPatch_opCode[osize];
388   ops.elements(opa);
389
390   bool findLoads = false, findStores = false, findPrefetch = false;
391
392   for(int i=0; i<osize; ++i) {
393     switch(opa[i]) {
394     case BPatch_opLoad: findLoads = true; break;
395     case BPatch_opStore: findStores = true; break;      
396     case BPatch_opPrefetch: findPrefetch = true; break; 
397     }
398   }
399
400   //Address relativeAddress = (Address)getBaseAddrRelative();
401
402   // Use an instruction iterator
403   InstrucIter ii(this);
404   
405   //instruction inst;
406   //int xx = -1;
407
408   while(ii.hasMore()) {
409
410     //inst = ii.getInstruction();
411     Address addr = *ii;     // XXX this gives the address *stored* by ii...
412
413     BPatch_memoryAccess* ma = ii.isLoadOrStore();
414     ii++;
415     
416     if(!ma)
417       continue;
418
419     //BPatch_addrSpec_NP start = ma.getStartAddr();
420     //BPatch_countSpec_NP count = ma.getByteCount();
421     //int imm = start.getImm();
422     //int ra  = start.getReg(0);
423     //int rb  = start.getReg(1);
424     //int cnt = count.getImm();
425     //short int fcn = ma.prefetchType();
426     bool skip = false;
427
428     if(findLoads && ma->hasALoad()) {
429       //fprintf(stderr, "LD[%d]: [%x -> %x], %d(%d)(%d) #%d\n",
430       //      ++xx, addr, inst, imm, ra, rb, cnt);
431 #ifdef rs6000_ibm_aix4_1
432       BPatch_point* p = createMemInstPoint((void *)addr, ma);
433 #else
434       BPatch_point* p = createInstPointForMemAccess(proc, (void*) addr, ma);
435 #endif
436       if(p)
437         result->push_back(p);
438       skip = true;
439     }
440
441     if(findStores && !skip && ma->hasAStore()) {
442       //fprintf(stderr, "ST[%d]: [%x -> %x], %d(%d)(%d) #%d\n",
443       //      ++xx, addr, inst, imm, ra, rb, cnt);
444 #ifdef rs6000_ibm_aix4_1
445       BPatch_point* p = createMemInstPoint((void *)addr, ma);
446 #else
447       BPatch_point* p = createInstPointForMemAccess(proc, (void*) addr, ma);
448 #endif
449       if(p)
450         result->push_back(p);
451       skip = true;
452     }
453
454     if(findPrefetch && !skip && ma->hasAPrefetch()) {
455       //fprintf(stderr, "PF[%d]: [%x -> %x], %d(%d)(%d) #%d %%%d\n",
456       //      ++xx, addr, inst, imm, ra, rb, cnt, fcn);
457       // XXX this leaks...
458 #ifdef rs6000_ibm_aix4_1
459       BPatch_point* p = createMemInstPoint((void *)addr, ma);
460 #else
461       BPatch_point* p = createInstPointForMemAccess(proc, (void*) addr, ma);
462 #endif
463       if(p)
464         result->push_back(p);
465       skip = true;
466     }
467   }
468
469   return result;
470 }
471
472 /*
473  * BPatch_function::addParam()
474  *
475  * This function adds a function parameter to the BPatch_function parameter
476  * vector.
477  */
478 void BPatch_function::addParam(char * _name, BPatch_type *_type, int _linenum,
479                                int _frameOffset, int _sc)
480 {
481   BPatch_localVar * param = new BPatch_localVar(_name, _type, _linenum,
482                                                 _frameOffset, _sc);
483
484   // Add parameter to list of parameters
485   params.push_back(param);
486 }
487
488 /*
489  * BPatch_function::findLocalVar()
490  *
491  * This function searchs for a local variable in the BPatch_function's
492  * local variable collection.
493  */
494 BPatch_localVar * BPatch_function::findLocalVar(const char * name)
495 {
496
497   BPatch_localVar * var = localVariables->findLocalVar(name);
498   return (var);
499
500 }
501
502 /*
503  * BPatch_function::findLocalParam()
504  *
505  * This function searchs for a function parameter in the BPatch_function's
506  * parameter collection.
507  */
508 BPatch_localVar * BPatch_function::findLocalParam(const char * name)
509 {
510
511   BPatch_localVar * var = funcParameters->findLocalVar(name);
512   return (var);
513
514 }
515
516 /** method to retrieve addresses for a given line in the function
517   * if the line number is not valid, or if the line info is not available
518   * or if the module does not contain entry for the function then it returns
519   * false. If exact match is not set then the line which is the next
520   * greater or equal will be used.
521   */
522 bool BPatch_function::getLineToAddr(unsigned short lineNo,
523                    BPatch_Vector<unsigned long>& buffer,
524                    bool exactMatch)
525 {
526
527         //get the line info object and check whether it is available
528         LineInformation* lineInformation = mod->lineInformation;
529         if(!lineInformation){
530                 return false;
531         }
532
533         //get the object which contains the function being asked
534         FileLineInformation* fLineInformation = 
535                         lineInformation->getFunctionLineInformation(func->symTabName());
536         if(!fLineInformation){
537                 return false;
538         }
539
540         //retrieve the addresses
541         BPatch_Set<Address> addresses;
542         if(!fLineInformation->getAddrFromLine(func->symTabName(),addresses,
543                                               lineNo,false,exactMatch))
544                 return false;
545
546         //then insert the elements to the vector given
547         Address* elements = new Address[addresses.size()];
548         addresses.elements(elements);
549         for(int i=0;i<addresses.size();i++)
550                 buffer.push_back(elements[i]);
551         delete[] elements;
552         
553         return true;
554 }
555
556 //
557 // Return the module name, first and last line numbers of the function.
558 //
559 bool BPatch_function::getLineAndFile(unsigned int &start,
560                                      unsigned int &end,
561                                      char *fileName, unsigned &length)
562 {
563     start = end = 0;
564
565     //get the line info object and check whether it is available
566     LineInformation* lineInformation = mod->lineInformation;
567
568     if (!lineInformation) {
569         logLine("BPatch_function::getLineToAddr : Line info is not available");
570         return false;
571     }
572
573     //get the object which contains the function being asked
574     FileLineInformation* fLineInformation = 
575         lineInformation->getFunctionLineInformation(func->symTabName());
576
577     if (!fLineInformation) {
578         logLine("BPatch_function::getLineToAddr: Line info is not available");
579         return false;
580     }
581
582     //retrieve the addresses
583     FunctionInfo *funcLineInfo;
584
585     funcLineInfo = fLineInformation->findFunctionInfo(func->symTabName());
586
587     if (!funcLineInfo) return false;
588
589     if (funcLineInfo->startLinePtr)
590         start = funcLineInfo->startLinePtr->lineNo;
591
592     if (funcLineInfo->endLinePtr)
593         end = funcLineInfo->endLinePtr->lineNo;
594
595     strncpy(fileName, fLineInformation->getFileName().c_str(), length);
596     if (strlen(fLineInformation->getFileName().c_str()) < length) {
597         length = strlen(fLineInformation->getFileName().c_str());
598     }
599
600     return true;
601 }
602
603 BPatch_flowGraph* BPatch_function::getCFG(){
604         if(cfg)
605                 return cfg;
606
607         cfg = new BPatch_flowGraph((BPatch_function*)this);
608
609         return cfg;
610 }
611
612
613 BPatch_Vector<BPatch_localVar *> *BPatch_function::getVars() {
614       return localVariables->getAllVars(); 
615 }
616
617 BPatch_Vector<BPatch_variableExpr *> *BPatch_function::findVariable(const char *name)
618 {
619     BPatch_Vector<BPatch_variableExpr *> *ret;
620     BPatch_localVar *lv = findLocalVar(name);
621
622     if (!lv) {
623         // look for it in the parameter scope now
624         lv = findLocalParam(name);
625     }
626     if (lv) {
627         // create a local expr with the correct frame offset or absolute
628         //   address if that is what is needed
629         ret = new BPatch_Vector<BPatch_variableExpr *>;
630         BPatch_Vector<BPatch_point*> *points = findPoint(BPatch_entry);
631         assert(points->size() == 1);
632         ret->push_back(new BPatch_variableExpr(proc, (void *) lv->getFrameOffset(), 
633             lv->getType(), lv->getFrameRelative(), (*points)[0]));
634         return ret;
635     } else {
636         // finally check the global scope.
637         BPatch_image *imgPtr = (BPatch_image *) mod->getObjParent();
638
639         if (!imgPtr) return NULL;
640
641         BPatch_variableExpr *vars = imgPtr->findVariable(name);
642         if (!vars) return NULL;
643
644         ret = new BPatch_Vector<BPatch_variableExpr *>;
645         ret->push_back(vars);
646         return ret;
647     }
648 }
649
650 bool BPatch_function::getVariables(BPatch_Vector<BPatch_variableExpr *> &/*vect*/)
651 {
652         return false;
653 }
654
655 char *BPatch_function::getModuleName(char *name, int maxLen) {
656     return getModule()->getName(name, maxLen);
657 }
658
659 #ifdef IBM_BPATCH_COMPAT
660
661 bool BPatch_function::getLineNumbers(unsigned int &start, unsigned int &end) {
662     unsigned int length = 0;
663     return getLineAndFile(start, end, NULL, length);
664 }
665
666 void *BPatch_function::getAddress() { return getBaseAddr(); }
667     
668 bool BPatch_function::getAddressRange(void * &start, void * &end) {
669         start = getBaseAddr();
670         unsigned long temp = (unsigned long) start;
671         end = (void *) (temp + getSize());
672
673         return true;
674 }
675
676 //BPatch_type *BPatch_function::returnType() { return retType; }
677
678 void BPatch_function::getIncPoints(BPatch_Vector<BPatch_point *> &vect) 
679 {
680     BPatch_Vector<BPatch_point *> *v1 = findPoint(BPatch_allLocations);
681     if (v1) {
682         for (unsigned int i=0; i < v1->size(); i++) {
683             vect.push_back((*v1)[i]);
684         }
685     }
686 }
687
688 int     BPatch_function::getMangledNameLen() { return 1024; }
689
690 void BPatch_function::getExcPoints(BPatch_Vector<BPatch_point*> &points) {
691   points.clear();
692   abort();
693   return;
694 };
695
696 // return a function that can be passed as a paramter
697 BPatch_variableExpr *BPatch_function::getFunctionRef() { abort(); return NULL; }
698
699 #endif
700
701 /*
702  * BPatch_function::isInstrumentable
703  *
704  * Returns true if the function is instrumentable, false otherwise.
705  */
706 bool BPatch_function::isInstrumentable()
707 {
708      return ((pd_Function *)func)->isInstrumentable();
709 }
710
711 // Return TRUE if the function resides in a shared lib, FALSE otherwise
712
713 bool BPatch_function::isSharedLib() const {
714   return mod->isSharedLib();
715