some modifications for teh code to be compiled in
[dyninst.git] / dyninstAPI / src / BPatch_image.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_image.C,v 1.19 2000/03/15 22:14:31 tikir Exp $
43
44 #include <stdio.h>
45 #include <assert.h>
46 #include <string.h>
47
48 #include "process.h"
49 #include "symtab.h"
50 #include "instPoint.h"
51
52 #include "BPatch.h"
53 #include "BPatch_image.h"
54 #include "BPatch_type.h"
55 #include "BPatch_collections.h"
56 #include "LineInformation.h"
57
58 //
59 // We made this a seperate class to allow us to only expose a pointer to
60 //    it in the public header files of the dyninst API.  This keeps 
61 //    dictionary_hash and other internal dyninst things hidden.  The
62 //    things we do decouple interface from implementation! - jkh 8/28/99
63 //
64 class AddrToVarExprHash {
65     public:
66         AddrToVarExprHash(): hash(addrHash) { }
67         dictionary_hash <Address, BPatch_variableExpr*> hash;
68 };
69
70 /*
71  * BPatch_image::BPatch_image
72  *
73  * Construct a BPatch_image for the given process.
74  */
75
76 BPatch_image::BPatch_image(process *_proc) : proc(_proc)
77 {
78     modlist = NULL;
79     AddrToVarExpr = new AddrToVarExprHash();
80
81     _srcType = BPatch_sourceProgram;
82 }
83
84 /*
85  * BPatch_image::BPatch_image
86  *
87  * Construct a BPatch_image.
88  */
89 BPatch_image::BPatch_image() : proc(NULL), modlist(NULL) 
90 {
91     AddrToVarExpr = new AddrToVarExprHash();
92
93     _srcType = BPatch_sourceProgram;
94 }
95
96 /* 
97  * Cleanup the image's memory usage when done.
98  *
99  */
100 BPatch_image::~BPatch_image()
101 {
102     // modules are shared by multuple programs, don't delete them
103     // for (unsigned int i = 0; i < modlist->size(); i++) {
104          // delete (*modlist)[i];
105     // }
106
107     delete AddrToVarExpr;
108 }
109
110 /* 
111  * getSourceObj - Return the children (modules)
112  *
113  */
114 BPatch_Vector<BPatch_sourceObj *> *BPatch_image::getSourceObj()
115 {
116     return (BPatch_Vector<BPatch_sourceObj *> *) getModules();
117 }
118
119 /* 
120  * getObjParent - Return the parent (this is the top level so its null)
121  *
122  */
123 BPatch_sourceObj *BPatch_image::getObjParent()
124 {
125     return NULL;
126 }
127
128 /*
129  * BPatch_image::getProcedures
130  *
131  * Returns a list of all procedures in the image upon success, and NULL
132  * upon failure.
133  */
134 BPatch_Vector<BPatch_function *> *BPatch_image::getProcedures()
135 {
136     BPatch_Vector<BPatch_function *> *proclist =
137         new BPatch_Vector<BPatch_function *>;
138
139     if (proclist == NULL) return NULL;
140
141     // XXX Also, what should we do about getting rid of this?  Should
142     //     the BPatch_functions already be made and kept around as long
143     //     as the process is, so the user doesn't have to delete them?
144     BPatch_Vector<BPatch_module *> *mods = getModules();
145
146     for (unsigned int i = 0; i < mods->size(); i++) {
147         BPatch_Vector<BPatch_function *> *funcs = (*mods)[i]->getProcedures();
148         for (unsigned int j=0; j < funcs->size(); j++) {
149             proclist->push_back((*funcs)[j]);
150         }
151     }
152
153     return proclist;
154 }
155
156
157 /*
158  * BPatch_image::getProcedures
159  *
160  * Returns a list of all procedures in the image upon success, and NULL
161  * upon failure.
162  */
163 BPatch_Vector<BPatch_variableExpr *> *BPatch_image::getGlobalVariables()
164 {
165     BPatch_variableExpr *var;
166     BPatch_Vector<BPatch_variableExpr *> *varlist =
167         new BPatch_Vector<BPatch_variableExpr *>;
168
169     if (varlist == NULL) return NULL;
170
171     // XXX - should this stuff really be by image ??? jkh 3/19/99
172     BPatch_Vector<BPatch_module *> *mods = getModules();
173     BPatch_type *type;
174     for (int m = 0; m < mods->size(); m++) {
175         BPatch_module *module = (*mods)[m];
176         char name[255];
177         module->getName(name, sizeof(name));
178         vector<string> keys = module->moduleTypes->globalVarsByName.keys();
179         int limit = keys.size();
180         for (int j = 0; j < limit; j++) {
181             Symbol syminfo;
182             string name = keys[j];
183             type = module->moduleTypes->globalVarsByName[name];
184             assert(type);
185             if (!proc->getSymbolInfo(name, syminfo)) {
186                 printf("unable to find variable %s\n", name.string_of());
187             }
188             var = AddrToVarExpr->hash[syminfo.addr()];
189             if (!var) {
190                 var = new BPatch_variableExpr((char *) name.string_of(), proc, 
191                     (void *)syminfo.addr(), (const BPatch_type *) type);
192                 AddrToVarExpr->hash[syminfo.addr()] = var;
193             }
194             varlist->push_back(var);
195         }
196     }
197
198
199     return varlist;
200 }
201
202 /*
203  * BPatch_image::getModules
204  *
205  * Returns a list of all procedures in the image upon success, and NULL
206  * upon failure.
207  */
208 BPatch_Vector<BPatch_module *> *BPatch_image::getModules()
209 {
210   if (modlist) {
211     return modlist;
212   }
213   
214   modlist = new BPatch_Vector<BPatch_module *>;
215   if (modlist == NULL) return NULL;
216   
217   // XXX Also, what should we do about getting rid of this?  Should
218   //     the BPatch_modules already be made and kept around as long
219   //     as the process is, so the user doesn't have to delete them?
220   vector<module *> *mods = proc->getAllModules();
221   
222   for (unsigned int m = 0; m < mods->size(); m++) {
223     pdmodule *curr = (pdmodule *) (*mods)[m];
224     BPatch_module *bpmod = new BPatch_module(proc, curr, this);
225     modlist->push_back(bpmod);
226   }
227   
228   // BPatch_procedures are only built on demand, and we need to make sure
229   //    they get built.
230   BPatch_Vector<BPatch_function *> *procedures = getProcedures();
231
232   return modlist;
233 }
234
235 /*
236  * BPatch_image::findProcedurePoint
237  *
238  * Returns a vector of the instrumentation points from a procedure that is
239  * identified by the parameters, or returns NULL upon failure.
240  *
241  * name         The name of the procedure in which to look up the points.
242  * loc          The points within the procedure to return.  The following
243  *              values are valid for this parameter:
244  *                BPatch_entry         The function's entry point.
245  *                BPatch_exit          The function's exit point(s).
246  *                BPatch_subroutine    The points at which the procedure calls
247  *                                     other procedures.
248  *                BPatch_longJump      The points at which the procedure make
249  *                                     long jump calls.
250  *                BPatch_allLocations  All of the points described above.
251  */
252 BPatch_Vector<BPatch_point*> *BPatch_image::findProcedurePoint(
253         const char *name, const BPatch_procedureLocation loc)
254 {
255     /* XXX Right now this assumes that there's only one function with
256      * the given name.
257      */
258
259     BPatch_function *func = findBPFunction(name);
260     if (func == NULL) return NULL;
261
262     return func->findPoint(loc);
263 }
264
265
266 /*
267  * BPatch_image::createInstPointAtAddr
268  *
269  * Returns a pointer to a BPatch_point object representing an
270  * instrumentation point at the given address.
271  *
272  * Returns the pointer to the BPatch_point on success, or NULL upon
273  * failure.
274  *
275  * address      The address that the instrumenation point should refer to.
276  */
277 BPatch_point *BPatch_image::createInstPointAtAddr(void *address)
278 {
279     unsigned i;
280
281     /* First look in the list of non-standard instPoints. */
282     if (proc->instPointMap.defines((Address)address)) {
283         instPoint *ip = proc->instPointMap[(Address)address];
284         return new BPatch_point(proc, NULL, ip, BPatch_allLocations);
285     }
286
287     /* Look in the regular instPoints of the enclosing function. */
288     function_base *func = proc->findFunctionIn((Address)address);
289
290     if (func != NULL) {
291         instPoint *entry = const_cast<instPoint *>(func->funcEntry(proc));
292         assert(entry);
293         if (entry->iPgetAddress() == (Address)address) {
294             return new BPatch_point(proc, NULL, entry, BPatch_entry);
295         }
296
297         const vector<instPoint*> &exits = func->funcExits(proc);
298         for (i = 0; i < exits.size(); i++) {
299             assert(exits[i]);
300             if (exits[i]->iPgetAddress() == (Address)address) {
301                 return new BPatch_point(proc, NULL, exits[i], BPatch_exit);
302             }
303         }
304
305         const vector<instPoint*> &calls = func->funcCalls(proc);
306         for (i = 0; i < calls.size(); i++) {
307             assert(calls[i]);
308             if (calls[i]->iPgetAddress() == (Address)address) {
309                 return new BPatch_point(proc, NULL, calls[i], BPatch_subroutine);
310             }
311         }
312     }
313
314     /* We don't have an instPoint for this address, so make one. */
315 #if defined(rs6000_ibm_aix4_1) || defined(alpha_dec_osf4_0)
316     /*
317      * XXX This is machine dependent and should be moved to somewhere else.
318      */
319     if (!isAligned((Address)address))
320         return NULL;
321
322     instruction instr;
323     proc->readTextSpace(address, sizeof(instruction), &instr.raw);
324
325 #if defined(rs6000_ibm_aix4_1)
326     instPoint *newpt = new instPoint((pd_Function *)func,
327                                      instr,
328                                      NULL, // image *owner - this is ignored
329                                      (Address)address,
330                                      false, // bool delayOk - this is ignored
331                                      ipOther);
332 #elif defined(alpha_dec_osf4_0)
333     instPoint *newpt = new instPoint((pd_Function *)func,
334                                     (const instructUnion &) instr,
335                                     (const image *) NULL, // image * - ignored
336                                     (Address &)address,
337                                     false, // bool delayOk - ignored
338                                     otherPoint);
339 #endif
340
341
342     proc->instPointMap[(Address)address] = newpt; // Save this instPoint
343
344     return new BPatch_point(proc, NULL, newpt, BPatch_instruction);
345 #else
346     /* Not implemented on this platform (yet). */
347     assert(false);
348     return NULL;
349 #endif
350 }
351
352
353 /*
354  * BPatch_image::findFunction
355  *
356  * Returns a NEW BPatch_function* representing the named function upon success,
357  * and NULL upon failure.
358  *
359  * name         The name of function to look up.
360  */
361 BPatch_function *BPatch_image::findFunction(const char *name)
362 {
363     function_base *func = proc->findOneFunction(name);
364
365     if (func == NULL) {
366         string fullname = string("_") + string(name);
367         func = proc->findOneFunction(fullname);
368     }
369
370     if (func == NULL) {
371         string msg = string("Unable to find function: ") + string(name);
372         showErrorCallback(100, msg);
373         return NULL;
374     }
375
376     BPatch_function *bpfunc = proc->PDFuncToBPFuncMap[func];
377     if (!bpfunc) {
378         bpfunc = new BPatch_function(proc, func, NULL);
379     }
380     return bpfunc;
381 }
382
383
384 /*
385  * BPatch_image::findVariable
386  *
387  * Returns a BPatch_variableExpr* representing the given variable in the
388  * application image.  If no such variable exists, returns NULL.
389  *
390  * name         The name of the variable to look up.
391  *
392  * First look for the name with an `_' prepended to it, and if that is not
393  *   found try the original name.
394  */
395 BPatch_variableExpr *BPatch_image::findVariable(const char *name)
396 {
397     string full_name = string("_") + string(name);
398
399     Symbol syminfo;
400     if (!proc->getSymbolInfo(full_name, syminfo)) {
401         string short_name(name);
402         if (!proc->getSymbolInfo(short_name, syminfo)) {
403             string msg = string("Unable to find variable: ") + string(name);
404             showErrorCallback(100, msg);
405             return NULL;
406         }
407     }
408     if( syminfo.type() == Symbol::PDST_FUNCTION)
409       return NULL;
410     
411     BPatch_variableExpr *bpvar = AddrToVarExpr->hash[syminfo.addr()];
412     if (bpvar) return bpvar;
413
414     // XXX - should this stuff really be by image ??? jkh 3/19/99
415     BPatch_Vector<BPatch_module *> *mods = getModules();
416     BPatch_type *type;
417     for (int m = 0; m < mods->size(); m++) {
418         BPatch_module *module = (*mods)[m];
419         //printf("The moduleType address is : %x\n", &(module->moduleTypes));
420         type = module->moduleTypes->findVariableType(name);
421         if (type) break;
422     }
423     if (!type) {
424         type = BPatch::bpatch->type_Untyped;
425     }
426
427     BPatch_variableExpr *ret = new BPatch_variableExpr((char *) name, 
428         proc, (void *)syminfo.addr(), (const BPatch_type *) type);
429     AddrToVarExpr->hash[syminfo.addr()] = ret;
430     return ret;
431 }
432
433 //
434 // findVariable
435 //      scp     - a BPatch_point that defines the scope of the current search
436 //      name    - name of the variable to find.
437 //
438 BPatch_variableExpr *BPatch_image::findVariable(BPatch_point &scp,
439                                                 const char *name)
440 {
441     // Get the function to search for it's local variables.
442     // XXX - should really use more detailed scoping info here - jkh 6/30/99
443     BPatch_function *func = (BPatch_function *) scp.getFunction();
444     if (!func) {
445         string msg = string("point passed to findVariable lacks a function\n address point type passed?");
446         showErrorCallback(100, msg);
447         return NULL;
448     }
449
450     BPatch_localVar *lv = func->findLocalVar(name);
451
452     if (!lv) {
453         // look for it in the parameter scope now
454         lv = func->findLocalParam(name);
455     }
456     if (lv) {
457         // create a local expr with the correct frame offset 
458         return new BPatch_variableExpr(proc, (void *) lv->getFrameOffset(), 
459             lv->getType(), true, &scp);
460     }
461
462     // finally check the global scope.
463     return findVariable(name);
464 }
465
466 /*
467  * BPatch_image::findType
468  *
469  * Returns a BPatch_type* representing the named type.  If no such type
470  * exists, returns NULL.
471  *
472  * name         The name of type to look up.
473  */
474 BPatch_type *BPatch_image::findType(const char *name)
475 {
476     BPatch_type *type;
477
478     assert(BPatch::bpatch != NULL);
479
480     // XXX - should this stuff really be by image ??? jkh 3/19/99
481     BPatch_Vector<BPatch_module *> *mods = getModules();
482     for (int m = 0; m < mods->size(); m++) {
483         BPatch_module *module = (*mods)[m];
484         type = module->moduleTypes->findType(name);
485         if (type) return type;
486     }
487
488     // check the default base types
489     type = BPatch::bpatch->stdTypes->findType(name);
490     if(type) return type;
491
492     // check the API types of last resort
493     return BPatch::bpatch->APITypes->findType(name);
494
495 }
496
497 /*
498  * BPatch_image::findBPFunnction
499  *
500  * Returns a BPatch_function* representing the named function or if no func
501  * exists, returns NULL.
502  *
503  * name         The name of function to look up.
504  */
505 BPatch_function  *BPatch_image::findBPFunction(const char *name)
506 {
507     BPatch_function *func;
508     BPatch_Vector<BPatch_function *> * funclist =
509       new BPatch_Vector<BPatch_function *>;
510       
511     assert(BPatch::bpatch != NULL);
512
513     // XXX - should this stuff really be by image ??? jkh 3/19/99
514     BPatch_Vector<BPatch_module *> *mods = getModules();
515     //printf(" Number of Modules %d\n",mods->size());
516     for (int m = 0; m < mods->size(); m++) {
517         BPatch_module *module = (*mods)[m];
518         func = module->findFunction(name);
519         if (func) {
520             if (func->getProc() != proc) {
521                 printf("got func in the wrong proc\n");
522             }
523             funclist->push_back(func);
524         }
525     }
526     if( funclist->size()){
527       //printf("Function list has %d functions\n", funclist->size());
528       if( funclist->size() == 2)
529         return (*funclist)[1];
530       else 
531         return (*funclist)[0];
532     }
533     // check the default base types of last resort
534     else
535       return NULL;
536 }
537
538
539 /*
540  * BPatch_image::addModule
541  *
542  * Adds a new module to the BPatch_module vector
543  * if modlist exists. 
544  *
545  * bpmod is a pointer to the BPatch_module to add to the vector
546  */
547 void BPatch_image::addModuleIfExist(BPatch_module *bpmod){
548
549   if( modlist )
550     modlist->push_back(bpmod);
551   
552 }
553
554 /*
555  * BPatch_image::ModuleListExist
556  *
557  * Checks to see if modlist has been created.
558  */
559 bool BPatch_image::ModuleListExist(){
560
561   if ( modlist )
562     return true;
563   else
564     return false;
565 }
566
567 /** method that retrieves the addresses corresponding to a line number
568   * in a file.It returns true in success. If the file is not in the image
569   * or line number is not found it retuns false. In case of exact match is not
570   * asked then the next line number which is greater or equal to the given one
571   * is used
572   */
573 //method to get the addresses corresponding to a line number given
574 //in case of success it returns true and inserts the addresses in to
575 //the vector given. If the file name is not found or the line information
576 //is not valid or if the exact match is not found it retuns false.
577 //If exact match is not asked then the line number is taken to be the
578 //first one greater or equal to the given one.
579 bool BPatch_image::getLineToAddr(const char* fileName,unsigned short lineNo,
580                                  BPatch_Vector<unsigned long>& buffer,
581                                  bool exactMatch)
582 {
583         string fName(fileName);
584
585         //first get all modules
586         BPatch_Vector<BPatch_module*>* appModules =  getModules();
587
588         LineInformation* lineInformation;
589         FileLineInformation* fLineInformation = NULL;
590                 
591         //in each module try to find the file
592         for(int i=0;i<appModules->size();i++){
593                 lineInformation = (*appModules)[i]->lineInformation;
594                 if(!lineInformation)
595                         continue;
596                 fLineInformation = lineInformation->getFileLineInformation(fName);              
597                 if(fLineInformation)
598                         break;
599         }
600         
601         //if there is no entry for the file is being found then give warning and return
602         if(!fLineInformation){
603 #ifdef DEBUG_LINE
604                 cerr << "BPatch_image::getLineToAddr : ";
605                 cerr << fileName << "/line information  is not found/available in the image\n";
606 #endif
607                 return false;
608         }
609
610         //get the addresses for the line number
611         BPatch_Set<Address> addresses;
612         if(!fLineInformation->getAddrFromLine(fName,addresses,lineNo,true,exactMatch))
613                 return false;
614
615         //then insert the elements to the vector given
616         Address* elements = new Address[addresses.size()];
617         addresses.elements(elements);
618         for(int j=0;j<addresses.size();j++)
619                 buffer.push_back(elements[j]);
620         delete[] elements;
621
622         return true;
623 }