Add support for arbitrary inst points and control flow graphs on MIPS/Irix.
[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.6 2000/07/12 17:55:57 buck 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), func(_func),cfg(NULL)
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), func(_func),cfg(NULL)
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           BPatch_point *the_point;
228           unsigned int c=0, r=0;
229           Address cAddr, rAddr;
230           while (c < Cpoints.size() || r < Rpoints.size()) {
231               if (c < Cpoints.size()) cAddr = Cpoints[c]->iPgetAddress();
232               else                    cAddr = (Address)(-1);
233               if (r < Rpoints.size()) rAddr = Rpoints[r]->iPgetAddress();
234               else                    rAddr = (Address)(-1);
235               if (cAddr <= rAddr) {
236                   result->push_back(proc->findOrCreateBPPoint(
237                       this, Cpoints[c], BPatch_subroutine));
238                   c++;
239               } else {
240                   result->push_back(proc->findOrCreateBPPoint(
241                       this, Rpoints[r], BPatch_exit));
242                   r++;
243               }
244           }
245           break;
246         }
247       case BPatch_exit:
248         {
249           const vector<instPoint *> &points = func->funcExits(proc);
250           for (unsigned i = 0; i < points.size(); i++) {
251               result->push_back(proc->findOrCreateBPPoint(
252                   this, points[i], BPatch_exit));
253           }
254           break;
255         }
256       case BPatch_subroutine:
257         {
258           const vector<instPoint *> &points = func->funcCalls(proc);
259           for (unsigned i = 0; i < points.size(); i++) {
260               result->push_back(proc->findOrCreateBPPoint(
261                   this, points[i], BPatch_subroutine));
262           }
263           break;
264         }
265       case BPatch_longJump:
266         /* XXX Not yet implemented */
267       default:
268         assert( 0 );
269     }
270
271     return result;
272 }
273 /*
274  * BPatch_function::addParam()
275  *
276  * This function adds a function parameter to the BPatch_function parameter
277  * vector.
278  */
279 void BPatch_function::addParam(char * _name, BPatch_type *_type, int _linenum,
280                                int _frameOffset, int _sc)
281 {
282   BPatch_localVar * param = new BPatch_localVar(_name, _type, _linenum,
283                                                 _frameOffset, _sc);
284
285   // Add parameter to list of parameters
286   params.push_back(param);
287 }
288
289 /*
290  * BPatch_function::findLocalVar()
291  *
292  * This function searchs for a local variable in the BPatch_function's
293  * local variable collection.
294  */
295 BPatch_localVar * BPatch_function::findLocalVar(const char * name)
296 {
297
298   BPatch_localVar * var = localVariables->findLocalVar(name);
299   return (var);
300
301 }
302
303 /*
304  * BPatch_function::findLocalParam()
305  *
306  * This function searchs for a function parameter in the BPatch_function's
307  * parameter collection.
308  */
309 BPatch_localVar * BPatch_function::findLocalParam(const char * name)
310 {
311
312   BPatch_localVar * var = funcParameters->findLocalVar(name);
313   return (var);
314
315 }
316
317 /** method to retrieve addresses for a given line in the function
318   * if the line number is not valid, or if the line info is not available
319   * or if the module does not contain entry for the function then it returns
320   * false. If exact match is not set then the line which is the next
321   * greater or equal will be used.
322   */
323 bool BPatch_function::getLineToAddr(unsigned short lineNo,
324                    BPatch_Vector<unsigned long>& buffer,
325                    bool exactMatch)
326 {
327
328         //get the line info object and check whether it is available
329         LineInformation* lineInformation = mod->lineInformation;
330         if(!lineInformation){
331 #ifdef DEBUG_LINE
332                 cerr << "BPatch_function::getLineToAddr : ";
333                 cerr << "Line information is not available\n";
334 #endif
335                 return false;
336         }
337
338         //get the object which contains the function being asked
339         FileLineInformation* fLineInformation = 
340                         lineInformation->getFunctionLineInformation(func->prettyName());
341         if(!fLineInformation){
342 #ifdef DEBUG_LINE
343                 cerr << "BPatch_function::getLineToAddr : ";
344                 cerr << func->prettyName() << " is not found in its module\n";
345 #endif
346                 return false;
347         }
348
349         //retrieve the addresses
350         BPatch_Set<Address> addresses;
351         if(!fLineInformation->getAddrFromLine(func->prettyName(),addresses,
352                                               lineNo,false,exactMatch))
353                 return false;
354
355         //then insert the elements to the vector given
356         Address* elements = new Address[addresses.size()];
357         addresses.elements(elements);
358         for(int i=0;i<addresses.size();i++)
359                 buffer.push_back(elements[i]);
360         delete[] elements;
361         
362         return true;
363 }
364
365
366 BPatch_flowGraph* BPatch_function::getCFG(){
367         if(cfg)
368                 return cfg;
369
370 #if defined(sparc_sun_solaris2_4) || defined(mips_sgi_irix6_4)
371         cfg = new BPatch_flowGraph((BPatch_function*)this);
372 #else
373         cerr << "WARNING : BPatch_function::getCFG is not implemented";
374         cerr << " for this platform\n";
375 #endif
376
377         return cfg;
378 }
379
380
381 BPatch_Vector<BPatch_localVar *> *BPatch_function::getVars() {
382       return localVariables->getAllVars(); 
383 }