Changes to work towards compatability with IBM's version of dyninst.
[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.14 2001/08/29 23:25:27 hollings 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 "LineInformation.h"
57
58 /* XXX Should be in a dyninst API include file (right now in perfStream.h) */
59
60
61 /**************************************************************************
62  * BPatch_function
63  *************************************************************************/
64 /*
65  * BPatch_function::BPatch_function
66  *
67  * Constructor that creates a BPatch_function.
68  *
69  */
70 BPatch_function::BPatch_function(process *_proc, function_base *_func,
71         BPatch_module *_mod) :
72         proc(_proc), mod(_mod), cfg(NULL), func(_func)
73 {
74
75   // there should be at most one BPatch_func for each function_base per process
76   assert(proc->thread && !proc->PDFuncToBPFuncMap[func]);
77
78   _srcType = BPatch_sourceFunction;
79
80   localVariables = new BPatch_localVarCollection;
81   funcParameters = new BPatch_localVarCollection;
82   retType = NULL;
83
84   proc->PDFuncToBPFuncMap[_func] = this;
85 };
86
87 /*
88  * BPatch_function::BPatch_function
89  *
90  * Constructor that creates the BPatch_function with return type.
91  *
92  */
93 BPatch_function::BPatch_function(process *_proc, function_base *_func,
94                                  BPatch_type * _retType, BPatch_module *_mod) :
95         proc(_proc), mod(_mod), cfg(NULL), func(_func)
96 {
97   _srcType = BPatch_sourceFunction;
98   localVariables = new BPatch_localVarCollection;
99   funcParameters = new BPatch_localVarCollection;
100   retType = _retType;
101 };
102
103
104 BPatch_function::~BPatch_function()
105 {
106     // if (ast != NULL)
107         // removeAst(ast);
108     if (localVariables) delete localVariables;
109     if (funcParameters) delete funcParameters;
110     if (cfg) delete cfg;
111 }
112
113 /* 
114  * BPatch_function::getSourceObj()
115  *
116  * Return the contained source objects (e.g. statements).
117  *    This is not currently supported.
118  *
119  */
120 bool BPatch_function::getSourceObj(BPatch_Vector<BPatch_sourceObj *> &children)
121 {
122     // init and empty vector
123     BPatch_Vector<BPatch_sourceObj *> dummy;
124
125     children = dummy;
126     return false;
127 }
128
129 /*
130  * BPatch_function::getObjParent()
131  *
132  * Return the parent of the function (i.e. the module)
133  *
134  */
135 BPatch_sourceObj *BPatch_function::getObjParent()
136 {
137     return (BPatch_sourceObj *) mod;
138 }
139
140 /*
141  * BPatch_function::getName
142  *
143  * Copies the name of the function into a buffer, up to a given maximum
144  * length.  Returns a pointer to the beginning of the buffer that was
145  * passed in.
146  *
147  * s            The buffer into which the name will be copied.
148  * len          The size of the buffer.
149  */
150 char *BPatch_function::getName(char *s, int len)
151 {
152     assert(func);
153     string name = func->prettyName();
154     strncpy(s, name.string_of(), len);
155
156     return s;
157 }
158
159 /*
160  * BPatch_function::getMangledName
161  *
162  * Copies the mangled name of the function into a buffer, up to a given maximum
163  * length.  Returns a pointer to the beginning of the buffer that was
164  * passed in.
165  *
166  * s            The buffer into which the name will be copied.
167  * len          The size of the buffer.
168  */
169 char *BPatch_function::getMangledName(char *s, int len)
170 {
171     assert(func);
172     string name = func->symTabName();
173     strncpy(s, name.string_of(), len);
174
175     return s;
176 }
177
178 /*
179  * BPatch_function::getBaseAddr
180  *
181  * Returns the starting address of the function.
182  */
183 void *BPatch_function::getBaseAddr()
184 {
185      return (void *)func->getEffectiveAddress(proc);
186 }
187
188 /*
189 * BPatch_function::getBaseAddrRelative
190 *
191 * Returns the starting address of the function in the module, relative
192 * to the module.
193 */
194 void *BPatch_function::getBaseAddrRelative()
195 {
196         return (void *)func->addr();
197 }
198
199
200 /*
201  * BPatch_function::getSize
202  *
203  * Returns the size of the function in bytes.
204  */
205 unsigned int BPatch_function::getSize()
206 {
207   return func->size();
208 }
209
210
211 /*
212  * BPatch_function::findPoint
213  *
214  * Returns a vector of the instrumentation points from a procedure that is
215  * identified by the parameters, or returns NULL upon failure.
216  * (Points are sorted by address in the vector returned.)
217  *
218  * loc          The points within the procedure to return.  The following
219  *              values are valid for this parameter:
220  *                BPatch_entry         The function's entry point.
221  *                BPatch_exit          The function's exit point(s).
222  *                BPatch_subroutine    The points at which the procedure calls
223  *                                     other procedures.
224  *                BPatch_longJump      The points at which the procedure make
225  *                                     long jump calls.
226  *                BPatch_allLocations  All of the points described above.
227  */
228 BPatch_Vector<BPatch_point*> *BPatch_function::findPoint(
229         const BPatch_procedureLocation loc)
230 {
231     // function does not exist!
232     if (func == NULL) return NULL;
233
234     // function is generally uninstrumentable (with current technology)
235     if (func->funcEntry(proc) == NULL) return NULL;
236
237     BPatch_Vector<BPatch_point*> *result = new BPatch_Vector<BPatch_point *>;
238
239     if (loc == BPatch_entry || loc == BPatch_allLocations) {
240         result->push_back(proc->findOrCreateBPPoint(
241             this,const_cast<instPoint *>(func->funcEntry(proc)),BPatch_entry));
242     }
243     switch (loc) {
244       case BPatch_entry: // already done
245           break;
246       case BPatch_allLocations:
247         {
248           const vector<instPoint *> &Rpoints = func->funcExits(proc);
249           const vector<instPoint *> &Cpoints = func->funcCalls(proc);
250           unsigned int c=0, r=0;
251           Address cAddr, rAddr;
252           while (c < Cpoints.size() || r < Rpoints.size()) {
253               if (c < Cpoints.size()) cAddr = Cpoints[c]->iPgetAddress();
254               else                    cAddr = (Address)(-1);
255               if (r < Rpoints.size()) rAddr = Rpoints[r]->iPgetAddress();
256               else                    rAddr = (Address)(-1);
257               if (cAddr <= rAddr) {
258                   result->push_back(proc->findOrCreateBPPoint(
259                       this, Cpoints[c], BPatch_subroutine));
260                   c++;
261               } else {
262                   result->push_back(proc->findOrCreateBPPoint(
263                       this, Rpoints[r], BPatch_exit));
264                   r++;
265               }
266           }
267           break;
268         }
269       case BPatch_exit:
270         {
271           const vector<instPoint *> &points = func->funcExits(proc);
272           for (unsigned i = 0; i < points.size(); i++) {
273               result->push_back(proc->findOrCreateBPPoint(
274                   this, points[i], BPatch_exit));
275           }
276           break;
277         }
278       case BPatch_subroutine:
279         {
280           const vector<instPoint *> &points = func->funcCalls(proc);
281           for (unsigned i = 0; i < points.size(); i++) {
282               result->push_back(proc->findOrCreateBPPoint(
283                   this, points[i], BPatch_subroutine));
284           }
285           break;
286         }
287       case BPatch_longJump:
288         /* XXX Not yet implemented */
289       default:
290         assert( 0 );
291     }
292
293     return result;
294 }
295 /*
296  * BPatch_function::addParam()
297  *
298  * This function adds a function parameter to the BPatch_function parameter
299  * vector.
300  */
301 void BPatch_function::addParam(char * _name, BPatch_type *_type, int _linenum,
302                                int _frameOffset, int _sc)
303 {
304   BPatch_localVar * param = new BPatch_localVar(_name, _type, _linenum,
305                                                 _frameOffset, _sc);
306
307   // Add parameter to list of parameters
308   params.push_back(param);
309 }
310
311 /*
312  * BPatch_function::findLocalVar()
313  *
314  * This function searchs for a local variable in the BPatch_function's
315  * local variable collection.
316  */
317 BPatch_localVar * BPatch_function::findLocalVar(const char * name)
318 {
319
320   BPatch_localVar * var = localVariables->findLocalVar(name);
321   return (var);
322
323 }
324
325 /*
326  * BPatch_function::findLocalParam()
327  *
328  * This function searchs for a function parameter in the BPatch_function's
329  * parameter collection.
330  */
331 BPatch_localVar * BPatch_function::findLocalParam(const char * name)
332 {
333
334   BPatch_localVar * var = funcParameters->findLocalVar(name);
335   return (var);
336
337 }
338
339 /** method to retrieve addresses for a given line in the function
340   * if the line number is not valid, or if the line info is not available
341   * or if the module does not contain entry for the function then it returns
342   * false. If exact match is not set then the line which is the next
343   * greater or equal will be used.
344   */
345 bool BPatch_function::getLineToAddr(unsigned short lineNo,
346                    BPatch_Vector<unsigned long>& buffer,
347                    bool exactMatch)
348 {
349
350         //get the line info object and check whether it is available
351         LineInformation* lineInformation = mod->lineInformation;
352         if(!lineInformation){
353 #ifdef DEBUG_LINE
354                 cerr << "BPatch_function::getLineToAddr : ";
355                 cerr << "Line information is not available\n";
356 #endif
357                 return false;
358         }
359
360         //get the object which contains the function being asked
361         FileLineInformation* fLineInformation = 
362                         lineInformation->getFunctionLineInformation(func->prettyName());
363         if(!fLineInformation){
364 #ifdef DEBUG_LINE
365                 cerr << "BPatch_function::getLineToAddr : ";
366                 cerr << func->prettyName() << " is not found in its module\n";
367 #endif
368                 return false;
369         }
370
371         //retrieve the addresses
372         BPatch_Set<Address> addresses;
373         if(!fLineInformation->getAddrFromLine(func->prettyName(),addresses,
374                                               lineNo,false,exactMatch))
375                 return false;
376
377         //then insert the elements to the vector given
378         Address* elements = new Address[addresses.size()];
379         addresses.elements(elements);
380         for(int i=0;i<addresses.size();i++)
381                 buffer.push_back(elements[i]);
382         delete[] elements;
383         
384         return true;
385 }
386
387 //
388 // Return the module name, first and last line numbers of the function.
389 //
390 bool BPatch_function::getLineAndFile(unsigned int &start,
391                                      unsigned int &end,
392                                      char *fileName, unsigned &length)
393 {
394     start = end = 0;
395
396     //get the line info object and check whether it is available
397     LineInformation* lineInformation = mod->lineInformation;
398
399     if (!lineInformation) {
400         logLine("BPatch_function::getLineToAddr : Line info is not available");
401         return false;
402     }
403
404     //get the object which contains the function being asked
405     FileLineInformation* fLineInformation = 
406         lineInformation->getFunctionLineInformation(func->prettyName());
407
408     if (!fLineInformation) {
409         logLine("BPatch_function::getLineToAddr: Line info is not available");
410         return false;
411     }
412
413     //retrieve the addresses
414     FunctionInfo *funcLineInfo;
415
416     funcLineInfo = fLineInformation->findFunctionInfo(func->prettyName());
417
418     if (!funcLineInfo) return false;
419
420     if (funcLineInfo->startLinePtr)
421         start = funcLineInfo->startLinePtr->lineNo;
422
423     if (funcLineInfo->endLinePtr)
424         end = funcLineInfo->endLinePtr->lineNo;
425
426     strncpy(fileName, fLineInformation->getFileName().string_of(), length);
427     if (strlen(fLineInformation->getFileName().string_of()) < length) {
428         length = strlen(fLineInformation->getFileName().string_of());
429     }
430
431     return true;
432 }
433
434 BPatch_flowGraph* BPatch_function::getCFG(){
435         if(cfg)
436                 return cfg;
437
438         cfg = new BPatch_flowGraph((BPatch_function*)this);
439
440         return cfg;
441 }
442
443
444 BPatch_Vector<BPatch_localVar *> *BPatch_function::getVars() {
445       return localVariables->getAllVars(); 
446 }
447
448 BPatch_Vector<BPatch_variableExpr *> *BPatch_function::findVariable(const char *name)
449 {
450     BPatch_Vector<BPatch_variableExpr *> *ret;
451     BPatch_localVar *lv = findLocalVar(name);
452
453     if (!lv) {
454         // look for it in the parameter scope now
455         lv = findLocalParam(name);
456     }
457     if (lv) {
458         // create a local expr with the correct frame offset or absolute
459         //   address if that is what is needed
460         ret = new BPatch_Vector<BPatch_variableExpr *>;
461         BPatch_Vector<BPatch_point*> *points = findPoint(BPatch_entry);
462         assert(points->size() == 1);
463         ret->push_back(new BPatch_variableExpr(proc, (void *) lv->getFrameOffset(), 
464             lv->getType(), lv->getFrameRelative(), (*points)[0]));
465         return ret;
466     } else {
467         // finally check the global scope.
468         BPatch_image *imgPtr = (BPatch_image *) mod->getObjParent();
469
470
471         if (!imgPtr) return NULL;
472
473         BPatch_variableExpr *vars = imgPtr->findVariable(name);
474         if (!vars) return NULL;
475
476         ret = new BPatch_Vector<BPatch_variableExpr *>;
477         ret->push_back(vars);
478         return ret;
479     }
480 }
481
482 bool BPatch_function::getVariables(BPatch_Vector<BPatch_variableExpr *> &vect)
483 {
484         return false;
485 }
486
487 char *BPatch_function::getModuleName(char *name, int maxLen) {
488     return getModule()->getName(name, maxLen);
489 }
490
491 #ifdef IBM_BPATCH_COMPAT
492
493 bool BPatch_function::getLineNumbers(unsigned int &start, unsigned int &end) {
494     unsigned int length = 0;
495     return getLineAndFile(start, end, NULL, length);
496 }
497
498 void *BPatch_function::getAddress() { return getBaseAddr(); }
499     
500 bool BPatch_function::getAddressRange(void * &start, void * &end) {
501         start = getBaseAddr();
502         unsigned long temp = (unsigned long) start;
503         end = (void *) (temp + getSize());
504
505         return true;
506 }
507
508 BPatch_type *BPatch_function::returnType() { return retType; }
509
510 void BPatch_function::getIncPoints(BPatch_Vector<BPatch_point *> &vect) 
511 {
512     BPatch_Vector<BPatch_point *> *v1 = findPoint(BPatch_allLocations);
513     if (v1) {
514         for (int i=0; i < v1->size(); i++) {
515             vect.push_back((*v1)[i]);
516         }
517     }
518 }
519
520 int     BPatch_function::getMangledNameLen() { return 1024; }
521
522 void BPatch_function::getExcPoints(BPatch_Vector<BPatch_point*> &points) {
523     abort();
524     return;
525 };
526
527 // return a function that can be passed as a paramter
528 BPatch_variableExpr *BPatch_function::getFunctionRef() { abort(); return NULL; }
529
530 #endif