Added additional functions to query start/end lines and source file names
[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.7 2000/08/17 20:45:02 hollings Exp $
43
44 #include <string.h>
45 #include "symtab.h"
46 #include "process.h"
47 #include "instPoint.h"
48
49 #include "BPatch.h"
50 #include "BPatch_type.h"
51 #include "BPatch_collections.h"
52 #include "BPatch_Vector.h"
53 #include "BPatch_flowGraph.h"
54 #include "LineInformation.h"
55
56 /* XXX Should be in a dyninst API include file (right now in perfStream.h) */
57 extern double cyclesPerSecond;
58
59
60 /**************************************************************************
61  * BPatch_function
62  *************************************************************************/
63 /*
64  * BPatch_function::BPatch_function
65  *
66  * Constructor that creates a BPatch_function.
67  *
68  */
69 BPatch_function::BPatch_function(process *_proc, function_base *_func,
70         BPatch_module *_mod) :
71         proc(_proc), mod(_mod), cfg(NULL), func(_func)
72 {
73
74   // there should be at most one BPatch_func for each function_base per process
75   assert(proc->thread && !proc->PDFuncToBPFuncMap[func]);
76
77   _srcType = BPatch_sourceFunction;
78
79   localVariables = new BPatch_localVarCollection;
80   funcParameters = new BPatch_localVarCollection;
81   retType = NULL;
82
83   proc->PDFuncToBPFuncMap[_func] = this;
84 };
85
86 /*
87  * BPatch_function::BPatch_function
88  *
89  * Constructor that creates the BPatch_function with return type.
90  *
91  */
92 BPatch_function::BPatch_function(process *_proc, function_base *_func,
93                                  BPatch_type * _retType, BPatch_module *_mod) :
94         proc(_proc), mod(_mod), cfg(NULL), func(_func)
95 {
96   _srcType = BPatch_sourceFunction;
97   localVariables = new BPatch_localVarCollection;
98   funcParameters = new BPatch_localVarCollection;
99   retType = _retType;
100 };
101
102
103 BPatch_function::~BPatch_function()
104 {
105     // if (ast != NULL)
106         // removeAst(ast);
107     if (localVariables) delete localVariables;
108     if (funcParameters) delete funcParameters;
109     if (cfg) delete cfg;
110 }
111
112 /* 
113  * BPatch_function::getSourceObj()
114  *
115  * Return the contained source objects (e.g. statements).
116  *    This is not currently supported.
117  *
118  */
119 BPatch_Vector<BPatch_sourceObj *> *BPatch_function::getSourceObj()
120 {
121     return NULL;
122 }
123
124 /*
125  * BPatch_function::getObjParent()
126  *
127  * Return the parent of the function (i.e. the module)
128  *
129  */
130 BPatch_sourceObj *BPatch_function::getObjParent()
131 {
132     return (BPatch_sourceObj *) mod;
133 }
134
135 /*
136  * BPatch_function::getName
137  *
138  * Copies the name of the function into a buffer, up to a given maximum
139  * length.  Returns a pointer to the beginning of the buffer that was
140  * passed in.
141  *
142  * s            The buffer into which the name will be copied.
143  * len          The size of the buffer.
144  */
145 char *BPatch_function::getName(char *s, int len)
146 {
147     assert(func);
148     string name = func->prettyName();
149     strncpy(s, name.string_of(), len);
150
151     return s;
152 }
153
154
155 /*
156  * BPatch_function::getBaseAddr
157  *
158  * Returns the starting address of the function.
159  */
160 void *BPatch_function::getBaseAddr()
161 {
162      return (void *)func->getEffectiveAddress(proc);
163 }
164
165 /*
166 * BPatch_function::getBaseAddrRelative
167 *
168 * Returns the starting address of the function in the module, relative
169 * to the module.
170 */
171 void *BPatch_function::getBaseAddrRelative()
172 {
173         return (void *)func->addr();
174 }
175
176
177 /*
178  * BPatch_function::getSize
179  *
180  * Returns the size of the function in bytes.
181  */
182 unsigned int BPatch_function::getSize()
183 {
184   return func->size();
185 }
186
187
188 /*
189  * BPatch_function::findPoint
190  *
191  * Returns a vector of the instrumentation points from a procedure that is
192  * identified by the parameters, or returns NULL upon failure.
193  * (Points are sorted by address in the vector returned.)
194  *
195  * loc          The points within the procedure to return.  The following
196  *              values are valid for this parameter:
197  *                BPatch_entry         The function's entry point.
198  *                BPatch_exit          The function's exit point(s).
199  *                BPatch_subroutine    The points at which the procedure calls
200  *                                     other procedures.
201  *                BPatch_longJump      The points at which the procedure make
202  *                                     long jump calls.
203  *                BPatch_allLocations  All of the points described above.
204  */
205 BPatch_Vector<BPatch_point*> *BPatch_function::findPoint(
206         const BPatch_procedureLocation loc)
207 {
208     // function does not exist!
209     if (func == NULL) return NULL;
210
211     // function is generally uninstrumentable (with current technology)
212     if (func->funcEntry(proc) == NULL) return NULL;
213
214     BPatch_Vector<BPatch_point*> *result = new BPatch_Vector<BPatch_point *>;
215
216     if (loc == BPatch_entry || loc == BPatch_allLocations) {
217         result->push_back(proc->findOrCreateBPPoint(
218             this,const_cast<instPoint *>(func->funcEntry(proc)),BPatch_entry));
219     }
220     switch (loc) {
221       case BPatch_entry: // already done
222           break;
223       case BPatch_allLocations:
224         {
225           const vector<instPoint *> &Rpoints = func->funcExits(proc);
226           const vector<instPoint *> &Cpoints = func->funcCalls(proc);
227           unsigned int c=0, r=0;
228           Address cAddr, rAddr;
229           while (c < Cpoints.size() || r < Rpoints.size()) {
230               if (c < Cpoints.size()) cAddr = Cpoints[c]->iPgetAddress();
231               else                    cAddr = (Address)(-1);
232               if (r < Rpoints.size()) rAddr = Rpoints[r]->iPgetAddress();
233               else                    rAddr = (Address)(-1);
234               if (cAddr <= rAddr) {
235                   result->push_back(proc->findOrCreateBPPoint(
236                       this, Cpoints[c], BPatch_subroutine));
237                   c++;
238               } else {
239                   result->push_back(proc->findOrCreateBPPoint(
240                       this, Rpoints[r], BPatch_exit));
241                   r++;
242               }
243           }
244           break;
245         }
246       case BPatch_exit:
247         {
248           const vector<instPoint *> &points = func->funcExits(proc);
249           for (unsigned i = 0; i < points.size(); i++) {
250               result->push_back(proc->findOrCreateBPPoint(
251                   this, points[i], BPatch_exit));
252           }
253           break;
254         }
255       case BPatch_subroutine:
256         {
257           const vector<instPoint *> &points = func->funcCalls(proc);
258           for (unsigned i = 0; i < points.size(); i++) {
259               result->push_back(proc->findOrCreateBPPoint(
260                   this, points[i], BPatch_subroutine));
261           }
262           break;
263         }
264       case BPatch_longJump:
265         /* XXX Not yet implemented */
266       default:
267         assert( 0 );
268     }
269
270     return result;
271 }
272 /*
273  * BPatch_function::addParam()
274  *
275  * This function adds a function parameter to the BPatch_function parameter
276  * vector.
277  */
278 void BPatch_function::addParam(char * _name, BPatch_type *_type, int _linenum,
279                                int _frameOffset, int _sc)
280 {
281   BPatch_localVar * param = new BPatch_localVar(_name, _type, _linenum,
282                                                 _frameOffset, _sc);
283
284   // Add parameter to list of parameters
285   params.push_back(param);
286 }
287
288 /*
289  * BPatch_function::findLocalVar()
290  *
291  * This function searchs for a local variable in the BPatch_function's
292  * local variable collection.
293  */
294 BPatch_localVar * BPatch_function::findLocalVar(const char * name)
295 {
296
297   BPatch_localVar * var = localVariables->findLocalVar(name);
298   return (var);
299
300 }
301
302 /*
303  * BPatch_function::findLocalParam()
304  *
305  * This function searchs for a function parameter in the BPatch_function's
306  * parameter collection.
307  */
308 BPatch_localVar * BPatch_function::findLocalParam(const char * name)
309 {
310
311   BPatch_localVar * var = funcParameters->findLocalVar(name);
312   return (var);
313
314 }
315
316 /** method to retrieve addresses for a given line in the function
317   * if the line number is not valid, or if the line info is not available
318   * or if the module does not contain entry for the function then it returns
319   * false. If exact match is not set then the line which is the next
320   * greater or equal will be used.
321   */
322 bool BPatch_function::getLineToAddr(unsigned short lineNo,
323                    BPatch_Vector<unsigned long>& buffer,
324                    bool exactMatch)
325 {
326
327         //get the line info object and check whether it is available
328         LineInformation* lineInformation = mod->lineInformation;
329         if(!lineInformation){
330 #ifdef DEBUG_LINE
331                 cerr << "BPatch_function::getLineToAddr : ";
332                 cerr << "Line information is not available\n";
333 #endif
334                 return false;
335         }
336
337         //get the object which contains the function being asked
338         FileLineInformation* fLineInformation = 
339                         lineInformation->getFunctionLineInformation(func->prettyName());
340         if(!fLineInformation){
341 #ifdef DEBUG_LINE
342                 cerr << "BPatch_function::getLineToAddr : ";
343                 cerr << func->prettyName() << " is not found in its module\n";
344 #endif
345                 return false;
346         }
347
348         //retrieve the addresses
349         BPatch_Set<Address> addresses;
350         if(!fLineInformation->getAddrFromLine(func->prettyName(),addresses,
351                                               lineNo,false,exactMatch))
352                 return false;
353
354         //then insert the elements to the vector given
355         Address* elements = new Address[addresses.size()];
356         addresses.elements(elements);
357         for(int i=0;i<addresses.size();i++)
358                 buffer.push_back(elements[i]);
359         delete[] elements;
360         
361         return true;
362 }
363
364 //
365 // Return the module name, first and last line numbers of the function.
366 //
367 bool BPatch_function::getLineAndFile(unsigned short &start,
368                                      unsigned short &end,
369                                      char *fileName, unsigned &length)
370 {
371     start = end = 0;
372
373     //get the line info object and check whether it is available
374     LineInformation* lineInformation = mod->lineInformation;
375
376     if (!lineInformation) {
377         logLine("BPatch_function::getLineToAddr : Line info is not available");
378         return false;
379     }
380
381     //get the object which contains the function being asked
382     FileLineInformation* fLineInformation = 
383         lineInformation->getFunctionLineInformation(func->prettyName());
384
385     if (!fLineInformation) {
386         logLine("BPatch_function::getLineToAddr: Line info is not available");
387         return false;
388     }
389
390     //retrieve the addresses
391     FunctionInfo *funcLineInfo;
392
393     funcLineInfo = fLineInformation->findFunctionInfo(func->prettyName());
394
395     if (!funcLineInfo) return false;
396
397     if (funcLineInfo->startLinePtr)
398         start = funcLineInfo->startLinePtr->lineNo;
399
400     if (funcLineInfo->endLinePtr)
401         end = funcLineInfo->endLinePtr->lineNo;
402
403     strncpy(fileName, fLineInformation->getFileName().string_of(), length);
404     if (strlen(fLineInformation->getFileName().string_of()) < length) {
405         length = strlen(fLineInformation->getFileName().string_of());
406     }
407
408     return true;
409 }
410
411
412
413 BPatch_flowGraph* BPatch_function::getCFG(){
414         if(cfg)
415                 return cfg;
416
417 #if defined(sparc_sun_solaris2_4) || defined(mips_sgi_irix6_4)
418         cfg = new BPatch_flowGraph((BPatch_function*)this);
419 #else
420         cerr << "WARNING : BPatch_function::getCFG is not implemented";
421         cerr << " for this platform\n";
422 #endif
423
424         return cfg;
425 }
426
427
428 BPatch_Vector<BPatch_localVar *> *BPatch_function::getVars() {
429       return localVariables->getAllVars(); 
430 }