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