Added code to build procedure lists for the mdl
[dyninst.git] / dyninstAPI / src / symtab.C
1 /*
2  *  Copyright 1993 Jeff Hollingsworth.  All rights reserved.
3  *
4  */
5
6 #ifndef lint
7 static char Copyright[] = "@(#) Copyright (c) 1993 Jeff Hollingsowrth\
8     All rights reserved.";
9
10 static char rcsid[] = "@(#) $Header: /home/jaw/CVSROOT_20081103/CVSROOT/core/dyninstAPI/src/symtab.C,v 1.25 1995/05/18 10:42:40 markc Exp $";
11 #endif
12
13 /*
14  * symtab.C - generic symbol routines.  Implements an ADT for a symbol
15  *   table.  The make calls to machine and a.out specific routines to handle
16  *   the implementation dependent parts.
17  *
18  * $Log: symtab.C,v $
19  * Revision 1.25  1995/05/18 10:42:40  markc
20  * Added code to build procedure lists for the mdl
21  *
22  * Revision 1.24  1995/02/21  22:03:32  markc
23  * Added slightly better error recovery, with messages!  Paradynd reports back
24  * when it attempts to run an unusable executable.  It no longer aborts.
25  *
26  * Revision 1.23  1995/02/16  08:54:23  markc
27  * Corrected error in comments -- I put a "star slash" in the comment.
28  *
29  * Revision 1.22  1995/02/16  08:34:58  markc
30  * Changed igen interfaces to use strings/vectors rather than char igen-arrays
31  * Changed igen interfaces to use bool, not Boolean.
32  * Cleaned up symbol table parsing - favor properly labeled symbol table objects
33  * Updated binary search for modules
34  * Moved machine dependnent ptrace code to architecture specific files.
35  * Moved machine dependent code out of class process.
36  * Removed almost all compiler warnings.
37  * Use "posix" like library to remove compiler warnings
38  *
39  * Revision 1.21  1994/12/15  07:39:53  markc
40  * make resourceBatch request prior to defining resources.
41  *
42  * Revision 1.20  1994/11/10  21:01:21  markc
43  * Turn off creation of MODS file.
44  * Don't assume a .o is a module until all of the real modules have been seen.
45  *
46  * Revision 1.19  1994/11/10  18:58:19  jcargill
47  * The "Don't Blame Me Either" commit
48  *
49  * Revision 1.18  1994/11/09  18:40:38  rbi
50  * the "Don't Blame Me" commit
51  *
52  * Revision 1.17  1994/11/02  11:17:23  markc
53  * Made symbol table parsing machine independent.
54  *
55  * Revision 1.15  1994/10/13  07:25:04  krisna
56  * solaris porting and updates
57  *
58  * Revision 1.14  1994/10/04  21:40:12  jcargill
59  * Removed requirement that functions have valid line-number information to
60  * be consider user functions.
61  *
62  * Revision 1.13  1994/09/30  19:47:16  rbi
63  * Basic instrumentation for CMFortran
64  *
65  * Revision 1.12  1994/09/22  02:26:40  markc
66  * Made structs classes
67  *
68  * Revision 1.11  1994/08/08  20:13:47  hollings
69  * Added suppress instrumentation command.
70  *
71  * Revision 1.10  1994/08/02  18:25:07  hollings
72  * fixed modules to use list template for lists of functions.
73  *
74  * Revision 1.9  1994/07/28  22:40:48  krisna
75  * changed definitions/declarations of xalloc functions to conform to alloc.
76  *
77  * Revision 1.8  1994/07/22  19:21:10  hollings
78  * removed mistaken divid by 1Meg for predicted cost.
79  *
80  * Revision 1.7  1994/07/20  23:23:41  hollings
81  * added insn generated metric.
82  *
83  * Revision 1.6  1994/07/12  19:26:15  jcargill
84  * Added internal prefix for TRACELIB
85  *
86  * Revision 1.5  1994/06/29  02:52:51  hollings
87  * Added metricDefs-common.{C,h}
88  * Added module level performance data
89  * cleanedup types of inferrior addresses instrumentation defintions
90  * added firewalls for large branch displacements due to text+data over 2meg.
91  * assorted bug fixes.
92  *
93  * Revision 1.4  1994/06/27  21:28:23  rbi
94  * Abstraction-specific resources and mapping info
95  *
96  * Revision 1.3  1994/06/27  18:57:15  hollings
97  * removed printfs.  Now use logLine so it works in the remote case.
98  * added internalMetric class.
99  * added extra paramter to metric info for aggregation.
100  *
101  * Revision 1.2  1994/05/16  22:31:55  hollings
102  * added way to request unique resource name.
103  *
104  * Revision 1.1  1994/01/27  20:31:45  hollings
105  * Iinital version of paradynd speaking dynRPC igend protocol.
106  *
107  * Revision 1.8  1993/12/13  19:57:20  hollings
108  * added nearest line match for function to support Fortran convention of making
109  * first sline record be the first executable statement in the function.
110  *
111  * Revision 1.7  1993/10/12  20:10:35  hollings
112  * zero memory on a realloc.
113  *
114  * Revision 1.6  1993/10/04  21:39:08  hollings
115  * made missing internal symbols a fatal condition.
116  *
117  * Revision 1.5  1993/08/23  23:16:05  hollings
118  * added third parameter to findInternalSymbol.
119  *
120  * Revision 1.4  1993/08/20  22:02:39  hollings
121  * removed unused local variables.
122  *
123  * Revision 1.3  1993/07/13  18:32:46  hollings
124  * new include file syntax.
125  * added name demangler.
126  *
127  * Revision 1.2  1993/06/08  20:14:34  hollings
128  * state prior to bc net ptrace replacement.
129  *
130  * Revision 1.1  1993/03/19  22:45:45  hollings
131  * Initial revision
132  *
133  *
134  */
135
136 #include <stdio.h>
137 #include <stdlib.h>
138 #include <assert.h>
139
140 // TODO - machine independent instruction functions
141 #include "symtab.h"
142 #include "arch-sparc.h"
143 #include "util/h/Object.h"
144 #include <fstream.h>
145 #include "util.h"
146 #include "dyninstP.h"
147 #include "util/h/String.h"
148 #include "inst.h"
149 #include "main.h"
150 #include "util/h/Timer.h"
151 #include "init.h"
152
153 vector<watch_data> image::watch_vec;
154 vector<image*> image::allImages;
155
156 extern "C" char *cplus_demangle(char *, int);
157
158 /* imported from platform specific library list.  This is lists all
159    library functions we are interested in instrumenting. */
160
161 module *image::newModule(const string &name, const Address addr)
162 {
163     module *ret;
164     // modules can be defined several times in C++ due to templates and
165     //   in-line member functions.
166     if (ret = findModule(name))
167       return(ret);
168
169     string fullNm, fileNm;
170     char *out = P_strdup(name.string_of());
171     char *sl = P_strrchr(out, '/');
172     if (sl) {
173       *sl = (char)0;
174       fullNm = out;
175       fileNm = sl+1;
176     } else {
177       fullNm = string("/default/") + out;
178       fileNm = out;
179     }
180     delete out;
181
182     ret = new module(langUnknown, addr, fullNm, fileNm, this);
183     modsByFileName[ret->fileName()] = ret;
184     modsByFullName[ret->fullName()] = ret;
185     mods += ret;
186     return(ret);
187 }
188
189
190 // TODO -- is this g++ specific
191 bool buildDemangledName(const string mangled, string &use)
192 {
193     char *tempName = P_strdup(mangled.string_of());
194     char *demangled = cplus_demangle(tempName, 0);
195
196     if (demangled) {
197       use = demangled;
198       delete tempName;
199       delete demangled;
200       return true;
201     } else {
202       delete tempName;
203       return false;
204     }
205 }
206
207 // err is true if the function can't be defined
208 bool image::newFunc(module *mod, const string name, const Address addr,
209                     const unsigned tag, pdFunction *&retFunc)
210 {
211   pdFunction *func;
212   retFunc = NULL;
213   // KLUDGE
214   if (func = findFunction(addr))
215     return false;
216
217   if (!mod) {
218     logLine("Error function without module\n");
219     return false;
220   }
221   
222   char *out = P_strdup(name.string_of());
223   char *p = P_strchr(out, ':');
224   if (p) *p = '\0';
225
226   string demangled;
227   if (!buildDemangledName(out, demangled)) 
228     demangled = out;
229   delete out;
230
231   bool err;
232   func = new pdFunction(name, demangled, mod, addr, tag, this, err);
233   retFunc = func;
234   if (err) {
235     delete func;
236     retFunc = NULL;
237     return false;
238   }
239   
240   funcsByAddr[addr] = func;
241   mod->funcs += func;
242
243   if (!funcsByPretty.defines(func->prettyName())) {
244     vector<pdFunction*> *a1 = new vector<pdFunction*>;
245     funcsByPretty[func->prettyName()] = a1;      
246   }
247
248   // several functions may have the same demangled name, and each one
249   // will appear in a different module
250   vector<pdFunction*> *ap = funcsByPretty[func->prettyName()];
251   assert(ap);
252   (*ap) += func;
253   return true;
254 }
255
256 #ifdef DEBUG_TIME
257 static timer loadTimer;
258 static FILE *timeOut=0;
259 #endif /* DEBUG_TIME */
260
261 /*
262  * load an executable:
263  *   1.) parse symbol table and identify rotuines.
264  *   2.) scan executable to identify inst points.
265  *
266  *  offset is normally zero except on CM-5 where we have two images in one
267  *    file.  The offset passed to parseImage is the logical offset (0/1), not
268  *    the physical point in the file.  This makes it faster to "parse" multiple
269  *    copies of the same image since we don't have to stat and read to find the
270  *    physical offset. 
271  */
272 image *image::parseImage(const string file)
273 {
274 #ifdef DEBUG_TIME
275   timer parseTimer;
276   parseTimer.start();
277 #endif /* DEBUG_TIME */
278
279   /*
280    * Check to see if we have parsed this image at this offeset before.
281    */
282   // TODO -- better method to detect same image/offset --> offset only for CM5
283   unsigned i_size = allImages.size();
284   for (unsigned u=0; u<i_size; u++)
285     if (file == allImages[u]->file())
286       return allImages[u];
287
288   /*
289    * load the symbol table. (This is the a.out format specific routine).
290    */
291   statusLine("Process executable file");
292   bool err;
293
294 #ifdef DEBUG_TIME
295   loadTimer.clear(); loadTimer.start();
296   if (!timeOut) timeOut = fopen("/tmp/paradynd_times", "w");
297   if (!timeOut) P_abort();
298 #endif /* DEBUG_TIME */
299
300   // TODO -- kill process here
301   image *ret = new image(file, err);
302   if (err || !ret) {
303     if (ret)
304       delete ret;
305     return NULL;
306   }
307
308   // Add to master image list.
309   image::allImages += ret;
310
311 #ifdef DEBUG_TIME
312   char sline[256];
313   timer defTimer;
314   defTimer.start();
315 #endif /* DEBUG_TIME */
316
317   // define all modules.
318   ret->defineModules();
319
320 #ifdef DEBUG_TIME
321   defTimer.stop();
322   fprintf(timeOut, "It took %f:user %f:system %f:wall seconds to define resources %s\n",
323           defTimer.usecs(), defTimer.ssecs(),
324           defTimer.wsecs(), file.string_of());
325   timer postTimer;
326   postTimer.start();
327 #endif /* DEBUG_TIME */
328
329   //
330   // Optional post-processing step.  
331   if (ret->symbolExists("CMRT_init"))
332     ret->postProcess((char*)NULL);
333
334 #ifdef DEBUG_TIME
335   postTimer.stop();
336   fprintf(timeOut, "It took %f:user %f:system %f:wall seconds to post process %s\n",
337           postTimer.usecs(), postTimer.ssecs(),
338           postTimer.wsecs(), file.string_of());
339   parseTimer.stop();
340   fprintf(timeOut, "It took %f:user %f:system %f:wall seconds to process %s\n",
341           parseTimer.usecs(), parseTimer.ssecs(),
342           parseTimer.wsecs(), file.string_of());
343 #endif /* DEBUG_TIME */
344   
345   return(ret);
346 }
347
348 bool image::addInternalSymbol(const string &str, const Address symValue) {
349   // Internal symbols are prefixed by { DYNINST, TRACELIB }
350   // don't ignore the underscore
351   static string dyn = "_DYNINST"; 
352   static string tlib = "_TRACELIB";
353
354   // normalize all symbols -- remove the leading "_"
355   if (str.prefixed_by(dyn)) {
356     const char *s = str.string_of(); s++;
357     if (!iSymsMap.defines(s))
358       iSymsMap[s] = new internalSym(symValue, s);
359     return true;
360   } else if (str.prefixed_by(tlib)) {
361     const char *s = str.string_of(); s++;
362     if (!iSymsMap.defines(s))
363       iSymsMap[s] = new internalSym(symValue, s);
364     return true;
365   } else {
366     if (!iSymsMap.defines(str))
367       iSymsMap[str] = new internalSym(symValue, str);
368     return true;
369   }
370   return false;
371 }
372
373 Address image::findInternalAddress(const string name, const bool warn, bool &err)
374 {
375
376   err = false;
377
378   if (!iSymsMap.defines(name)) {
379     if (warn) {
380       char msg[100];
381       sprintf(msg, "Unable to find symbol: %s", name.string_of());
382       statusLine(msg);
383     }
384     err = true;
385     return 0;
386   } else
387     return (iSymsMap[name]->getAddr());
388 }
389
390 module *image::findModule(const string &name)
391 {
392   if (modsByFileName.defines(name))
393     return (modsByFileName[name]);
394   else if (modsByFullName.defines(name))
395     return (modsByFullName[name]);
396   else
397     return NULL;
398 }
399
400 // TODO -- this is only being used in cases where only one function
401 // should exist -- should I assert that the vector size <= 1 ?
402 pdFunction *image::findOneFunction(const string &name)
403 {
404   string demangName;
405
406   if (funcsByPretty.defines(name)) {
407     vector<pdFunction*> *a = funcsByPretty[name];
408     assert(a);
409     if (!a->size())
410       return NULL;
411     else
412       return ((*a)[0]);
413   } else if (buildDemangledName(name, demangName)) {
414     if (funcsByPretty.defines(demangName)) {
415       vector<pdFunction*> *a = funcsByPretty[name];
416       assert(a);
417       if (!a->size())
418         return NULL;
419       else
420         return ((*a)[0]);
421     } else
422       return NULL;
423   } else
424     return NULL;
425 }
426
427 bool image::findFunction(const string &name, vector<pdFunction*> &retList) {
428
429   if (funcsByPretty.defines(name)) {
430     retList = *funcsByPretty[name];
431     return true;
432   } else
433     return false;
434 }
435
436 pdFunction *image::findFunction(const Address &addr)
437 {
438   if (funcsByAddr.defines(addr))
439     return (funcsByAddr[addr]);
440   else 
441     return NULL;
442 }
443   
444 void image::changeLibFlag(resource *res, const bool setSuppress)
445 {
446   image *ret;
447   module *mod;
448
449   unsigned i_size = image::allImages.size();
450   for (unsigned u=0; u<i_size; u++) {
451     ret = image::allImages[u];
452     mod = ret->findModule(res->part_name());
453     if (mod) {
454       // suppress all procedures.
455       mod->changeLibFlag(setSuppress);
456     } else {
457       // more than one function may have this name --> templates, statics
458       vector<pdFunction*> pdfA;
459       if (ret->findFunction(res->part_name(), pdfA)) {
460         int i;
461         for (i=0; i<pdfA.size(); ++i) {
462           if (setSuppress) 
463             pdfA[i]->tagAsLib();
464           else
465             pdfA[i]->untagAsLib();
466         }
467       }
468     }
469   }
470 }
471
472
473 /* 
474  * return 0 if symbol <symname> exists in image, non-zero if it does not
475  */
476 bool image::symbolExists(const string symname)
477 {
478   pdFunction *dummy = findOneFunction(symname);
479   return (dummy != NULL);
480 }
481
482 void image::postProcess(const string pifname)
483 {
484   FILE *Fil;
485   string fname;
486   char temp[5000], errorstr[5000], key[5000];
487   char tmp1[5000], abstraction[500];
488   resource *parent;
489
490   return;
491
492   /* What file to open? */
493   if (!(pifname == (char*)NULL)) {
494     fname = pifname;
495   } else {
496     fname = file_ + ".pif";
497   }
498
499   /* Open the file */
500   Fil = P_fopen(fname.string_of(), "r");
501
502   if (Fil == NULL) {
503     sprintf(errorstr, 
504             "Tried to open PIF file %s, but could not (continuing)\n", 
505             fname.string_of());
506     logLine(errorstr);
507     return;
508   }
509
510   /* Process the file */
511   while (!feof(Fil)) {
512     fscanf(Fil, "%s", key);
513     switch (key[0]) {
514     case 'M':
515       /* Ignore mapping information for right now */
516       fgets(tmp1, 5000, Fil);
517       break;
518     case 'R':
519       /* Create a new resource */
520       fscanf(Fil, "%s {", abstraction);
521       parent = rootResource;
522       do {
523         fscanf(Fil, "%s", tmp1);
524         if (tmp1[0] != '}') {
525           parent = resource::newResource(parent, NULL, abstraction, tmp1, 0.0, "");
526         } else {
527           parent = NULL;
528         }
529       } while (parent != NULL);
530       break;
531     default:
532       sprintf(errorstr, 
533               "Ignoring bad line key (%s) in file %s\n", key, fname.string_of());
534       logLine(errorstr);
535       fgets(tmp1, 5000, Fil);
536       break;
537     }
538   }
539   return;
540 }
541
542 void image::defineModules() {
543   string pds; module *mod;
544   dictionary_hash_iter<string, module*> mi(modsByFileName);
545
546   statusLine("defining modules");
547   tp->resourceBatchMode(true);
548   while (mi.next(pds, mod))
549     mod->define();
550   statusLine("ready");
551   tp->resourceBatchMode(false);
552
553 #ifdef DEBUG_MDL
554 #include <strstream.h>
555   char buffer[100];
556   ostrstream osb(buffer, 100, ios::out);
557   osb << "IMAGE_" << name() << "__" << getpid() << ends;
558   ofstream of(buffer, ios::app);
559   unsigned n_size = mdlNormal.size();
560   of << "NORMAL\n";
561   for (unsigned ni=0; ni<n_size; ni++) {
562     of << mdlNormal[ni]->prettyName() << "\t\t" << mdlNormal[ni]->addr() << "\t\t" << 
563       mdlNormal[ni]->isLibTag() << endl;
564   }
565   n_size = mdlLib.size();
566   of << "\n\nLIB\n";
567   for (ni=0; ni<n_size; ni++) {
568     of << mdlLib[ni]->prettyName() << "\t\t" << mdlLib[ni]->addr() << "\t\t" <<
569       mdlLib[ni]->isLibTag() << endl;
570   }
571 #endif
572 }
573
574 void module::define() {
575   resource *modResource = NULL;
576 #ifdef DEBUG_MODS
577 #include <strstream.h>
578   char buffer[100];
579   ostrstream osb(buffer, 100, ios::out);
580   osb << "MODS_" << exec->name() << "__" << getpid() << ends;
581   ofstream of(buffer, ios::app);
582 #endif
583
584   unsigned f_size = funcs.size();
585   for (unsigned f=0; f<f_size; f++) {
586     pdFunction *pdf = funcs[f];
587 #ifdef DEBUG_MODS
588     of << fileName << ":  " << pdf->prettyName() <<  "  " <<
589       pdf->isLibTag() << "  " << pdf->addr() << endl;
590 #endif
591     // ignore line numbers for now 
592     if (!(pdf->isLibTag())) {
593       // see if we have created module yet.
594       if (!modResource) {
595         modResource = resource::newResource(moduleRoot, this, nullString, 
596                                             fileName(), 0.0, "");
597       }
598       resource::newResource(modResource, pdf, nullString, pdf->prettyName(), 0.0, "");
599     }
600   }
601 }
602
603 static inline bool findStartSymbol(Object &lf, Address &adr) {
604   Symbol lookUp;
605
606   if (lf.get_symbol("DYNINSTstartUserCode", lookUp) ||
607       lf.get_symbol("_DYNINSTstartUserCode", lookUp)) {
608     adr = lookUp.addr();
609     return true;
610   } else
611     return false;
612 }
613
614 static inline bool findEndSymbol(Object &lf, Address &adr) {
615   Symbol lookUp;
616
617   if (lf.get_symbol("DYNINSTendUserCode", lookUp) ||
618       lf.get_symbol("_DYNINSTendUserCode", lookUp)) {
619     adr = lookUp.addr();
620     return true;
621   } else
622     return false;
623 }
624
625 // TODO this assumes an ordering in the symbol table wrt modules KLUDGE
626 static inline bool notInUserRange(const Address adr,
627                                   const bool start, const Address startAdr,
628                                   const bool end, const Address endAdr) {
629   return ((start && (adr < startAdr)) || (end && (adr >= endAdr)));
630 }
631
632 static void binSearch (const Symbol &lookUp, vector<Symbol> &mods,
633                        string &modName, Address &modAddr, const string &def) {
634   int start=0, end=mods.size()-1, index;
635   bool found=false;
636
637   if (!mods.size()) {
638     modAddr = 0;
639     modName = def;
640     return;
641   }
642
643   while ((start <= end) && !found) {
644     index = (start+end)/2;
645
646     if ((index == (mods.size()-1)) ||
647         ((mods[index].addr() <= lookUp.addr()) && (mods[index+1].addr() > lookUp.addr()))) {
648       modName = mods[index].name();
649       modAddr = mods[index].addr();      
650       found = true;
651     } else if (lookUp.addr() < mods[index].addr()) {
652       end = index - 1;
653     } else {
654       start = index + 1;
655     }
656   }
657   if (!found) {
658     modName = mods[0].name();
659     modAddr = mods[0].addr();
660   }
661 }
662
663 bool image::addOneFunction(vector<Symbol> &mods, module *lib, module *dyn,
664                            const Symbol &lookUp, pdFunction  *&retFunc) {
665   // TODO mdc
666   // find the module
667   // this is a "user" symbol
668   string modName = lookUp.module();
669   Address modAddr = 0;
670   
671   string progName = name_ + "_module";
672   module *progModule = newModule(progName, 0);
673   
674   binSearch(lookUp, mods, modName, modAddr, progName);
675   return (defineFunction(lib, lookUp, modName, modAddr, retFunc));
676 }
677
678 bool inLibrary(Address addr, Address boundary_start, Address boundary_end,
679                       Address startAddr, bool startB,
680                       Address endAddr, bool endB) {
681   if ((addr >= boundary_start) && (addr <= boundary_end))
682     return true;
683   else if (startB) {
684     if (addr <= startAddr)
685       return true;
686     else if (endB) {
687       if (addr >= endAddr)
688         return true;
689       else 
690         return false;
691     } else 
692       return false;
693   } else if (endB) {
694     if (addr >= endAddr)
695       return true;
696     else
697       return false;
698   } else
699     return false;
700 }
701
702 bool image::addAllFunctions(vector<Symbol> &mods,
703                             module *lib, module *dyn, 
704                             const bool startB, const Address startAddr,
705                             const bool endB, const Address endAddr) {
706
707   Address boundary_start, boundary_end;
708   Symbol lookUp;
709   string symString;
710   SymbolIter symIter(linkedFile);
711
712   if (!linkedFile.get_symbol(symString="DYNINSTfirst", lookUp) &&
713       !linkedFile.get_symbol(symString="_DYNINSTfirst", lookUp)) {
714     statusLine("Internal symbol DYNINSTfirst not found");
715     return false;
716   } else
717     boundary_start = lookUp.addr();
718
719   if (!linkedFile.get_symbol(symString="DYNINSTend", lookUp) &&
720       !linkedFile.get_symbol(symString="_DYNINSTend", lookUp)) {
721     statusLine("Internal symbol DYNINSTend not found");
722     return false;
723   } else
724     boundary_end = lookUp.addr();
725
726   // TODO - find main and exit since other symbols may be mapped to their
727   // addresses which makes things confusing
728   // The rule is - the first function to define an address, gets it
729   if (!findKnownFunctions(linkedFile, lib, dyn, startB, startAddr, 
730                           endB, endAddr, boundary_start, boundary_end, mods)) {
731     return false;
732   }
733
734   // find the real functions -- those with the correct type in the symbol table
735   while (symIter.next(symString, lookUp)) {
736     if (funcsByAddr.defines(lookUp.addr())) {
737       // This function has been defined
738       ;
739     } else if (lookUp.type() == Symbol::ST_FUNCTION) {
740       if (!isValidAddress(lookUp.addr())) {
741         char msg[100];
742         sprintf(msg, "Function %s has bad address %x", lookUp.name().string_of(),
743                 lookUp.addr());
744         statusLine(msg);
745         return false;
746       }
747       pdFunction *pdf;
748       if (inLibrary(lookUp.addr(), boundary_start, boundary_end,
749                     startAddr, startB, endAddr, endB)) {
750         addInternalSymbol(lookUp.name(), lookUp.addr());
751         if (defineFunction(dyn, lookUp, TAG_LIB_FUNC, pdf)) {
752           assert(pdf); mdlLib += pdf;
753         }
754       } else {
755         if (addOneFunction(mods, lib, dyn, lookUp, pdf)) {
756           assert(pdf); mdlNormal += pdf;
757         }
758       }
759     }
760   }
761
762   // now find the pseudo functions -- this gets ugly
763   // kludge has been set if the symbol could be a function
764   symIter.reset();
765   while (symIter.next(symString, lookUp)) {
766     if (funcsByAddr.defines(lookUp.addr())) {
767       // This function has been defined
768       ;
769     } else if ((lookUp.type() == Symbol::ST_OBJECT) && lookUp.kludge()) {
770       pdFunction *pdf;
771       if (inLibrary(lookUp.addr(), boundary_start, boundary_end,
772                     startAddr, startB, endAddr, endB)) {
773         addInternalSymbol(lookUp.name(), lookUp.addr());
774         if (defineFunction(dyn, lookUp, TAG_LIB_FUNC, pdf)) {
775           assert(pdf); mdlLib += pdf;
776         }
777       } else {
778         if (addOneFunction(mods, lib, dyn, lookUp, pdf)) {
779           assert(pdf); mdlNormal += pdf;
780         }
781       }
782     }
783   }
784   return true;
785 }
786
787 // TODO - this should find all of the known functions in case 
788 // one of these functions has several names in the symbol table
789 // We want to declare the function by its known name and tag it
790 // before it is declared by its unknown name - which would make
791 // it untagged
792 //
793
794 bool image::findKnownFunctions(Object &linkedFile, module *lib, module *dyn,
795                                const bool startB, const Address startAddr,
796                                const bool endB, const Address endAddr,
797                                const Address boundary_start, 
798                                const Address boundary_end,
799                                vector<Symbol> &mods) {
800   Symbol sym;
801   string s;
802   // TODO -- this will be redundant until the mdl replacement is final
803   unsigned wv_size = watch_vec.size();
804   for (unsigned wv=0; wv<wv_size; wv++) {
805     if (watch_vec[wv].is_func) {
806       unsigned non_size = watch_vec[wv].non_prefix.size();
807       for (unsigned non=0; non<non_size; non++) {
808         pdFunction *pdf;
809         char buffer[200], *ptr;
810         string non_string(watch_vec[wv].non_prefix[non]);
811         string under_string(string("_") + non_string);
812
813         if (linkedFile.get_symbol(non_string, sym) ||
814             linkedFile.get_symbol(under_string, sym)) {
815           if (funcsByAddr.defines(sym.addr())) {
816             pdf = funcsByAddr[sym.addr()];
817             (*watch_vec[wv].funcs) += pdf;
818           } else if (watch_vec[wv].is_lib ||
819                      inLibrary(sym.addr(), boundary_start, boundary_end, startAddr,
820                                startB, endAddr, endB)) {
821             addInternalSymbol(sym.name(), sym.addr());
822             if (defineFunction(dyn, sym, TAG_LIB_FUNC, pdf)) {
823               assert(pdf); mdlLib += pdf; (*watch_vec[wv].funcs) += pdf;
824             }
825           } else {
826             if (addOneFunction(mods, lib, dyn, sym, pdf)) {
827               assert(pdf); mdlNormal += pdf; (*watch_vec[wv].funcs) += pdf;
828             }
829           }
830         }
831         // TODO -- get duplicates off of this list -- the watch_vec list
832         // Or let anyone who puts duplicate functions on a list suffer?
833       }
834     }
835   }
836   return true;
837 }
838
839 int symCompare(const void *s1, const void *s2) {
840   const Symbol *sym1 = (const Symbol*)s1, *sym2 = (const Symbol*)s2;
841   // TODO mdc
842   return (sym1->addr() - sym2->addr());
843 }
844
845 // Please note that this is now machine independent-almost.  Let us keep it that way
846 // 
847 image::image(const string &fileName, bool &err)
848 :   funcsByAddr(uiHash),
849     modsByFileName(string::hash),
850     modsByFullName(string::hash),
851     file_(fileName),
852     linkedFile(fileName, pd_log_perror),
853     iSymsMap(string::hash),
854     funcsByPretty(string::hash)
855 {
856   #ifdef DEBUG_TIME
857   loadTimer.stop();
858   char sline[256];
859   fprintf(timeOut, "It took %f:user %f:system %f:wall seconds to load %s\n",
860          loadTimer.usecs(), loadTimer.ssecs(),
861           loadTimer.wsecs(), fileName.string_of());
862   timer restTimer;
863   restTimer.start();
864 #endif /* DEBUG_TIME */
865
866   codeOffset_ = linkedFile.code_off();
867   dataOffset_ = linkedFile.data_off();
868   codeLen_ = linkedFile.code_len();
869   dataLen_ = linkedFile.data_len();
870
871   if (!codeLen_ || !linkedFile.code_ptr()) {
872     char msg[100];
873     sprintf(msg, "Could not open executable file: %s", fileName.string_of());
874     statusLine(msg);
875     err = true;
876     return;
877   }
878
879   Symbol version;
880   if (!linkedFile.get_symbol("DYNINSTversion", version) &&
881       !linkedFile.get_symbol("_DYNINSTversion", version)) {
882     statusLine("Could not find version number in instrumentation\n");
883     err = true;
884     return;
885   }
886
887   Word version_number = get_instruction(version.addr());
888   if (version_number != 1) {
889     char msg[100];
890     sprintf(msg, "Incorrect version number, expected %d, found %d\n", 1, version_number);
891     statusLine(msg);
892     err = true;
893     return;
894   }
895
896   const char *nm = fileName.string_of();
897   char *pos = P_strrchr(nm, '/');
898
899   err = false;
900   if (pos)
901     name_ = pos + 1;
902   else
903     name_ = fileName;
904
905   // TODO  -  dynamic ?
906   if (!heapIsOk(syms_to_find)) {
907     err = true; return;
908   }
909
910   // find the "user" code boundaries
911   statusLine("finding user code boundaries");
912   Address startUserAddr, endUserAddr;
913   bool startBound = findStartSymbol(linkedFile, startUserAddr);
914   bool endBound = findEndSymbol(linkedFile, endUserAddr);
915
916   // use the *DUMMY_MODULE* until a module is defined
917   module *dynModule = newModule(DYN_MODULE, 0);
918   module *libModule = newModule(LIBRARY_MODULE, 0);
919   // TODO -- define inst points in define function ?
920
921   // The functions cannot be verified until all of them have been seen
922   // because calls out of each function must be tagged as calls to user
923   // functions or call to "library" functions
924
925   Symbol lookUp;
926   string symString;
927   SymbolIter symIter(linkedFile);
928
929   // sort the modules by address into a vector to allow a binary search to 
930   // determine the module that a symbol will map to -- this may be bsd specific
931   vector<Symbol> mods;
932
933   while (symIter.next(symString, lookUp)) {
934
935     if (lookUp.type() == Symbol::ST_MODULE) {
936       const char *str = (lookUp.name()).string_of();
937       assert(str);
938       int ln = P_strlen(str);
939
940       // directory definition -- ignored for now
941       if (str[ln-1] != '/')
942         mods += lookUp;
943     }
944   }
945
946 #ifdef DEBUG_MODS
947   char buffer[100];
948   ostrstream osb(buffer, 100, ios::out);
949   osb << "UNSORTED_" << name() << "__" << getpid() << ends;
950   ofstream of(buffer, ios::app);
951   for (unsigned ve=0; ve<mods.size(); ve++)
952     of << mods[ve].name() << "  " << mods[ve].addr() << endl;
953   of.close();
954 #endif
955
956   // sort the modules by address
957   statusLine("sorting modules");
958   mods.sort(symCompare);
959   assert(mods.sorted(symCompare));
960
961 #ifdef DEBUG_MODS
962   ostrstream osb1(buffer, 100, ios::out);
963   osb1 << "SORTED_" << name() << "__" << getpid() << ends;
964   ofstream of1(buffer, ios::app);
965   for (unsigned ve1=0; ve1<mods.size(); ve1++)
966     of1 << mods[ve1].name() << "  " << mods[ve1].addr() << endl;
967   of1.close();
968 #endif
969
970   // remove duplicate entries -- some .o files may have the same address as .C files
971   // kludge is true for module symbols that I am guessing are modules
972   vector<Symbol> uniq;
973   unsigned loop=0;
974   while (loop < (mods.size()-1)) {
975     if (mods[loop].addr() == mods[loop+1].addr()) {
976       if (!mods[loop].kludge())
977         mods[loop+1] = mods[loop];
978     } else
979       uniq += mods[loop];
980     loop++;
981   }
982
983 #ifdef DEBUG_MODS
984   ostrstream osb2(buffer, 100, ios::out);
985   osb2 << "UNIQUE_" << name() << "__" << getpid() << ends;
986   ofstream of2(buffer, ios::app);
987   for (unsigned ve2=0; ve2<uniq.size(); ve2++)
988     of2 << uniq[ve2].name() << "  " << uniq[ve2].addr() << endl;
989   of2.close();
990 #endif
991   
992   // define all of the functions
993   statusLine("winnowing functions");
994   if (!addAllFunctions(uniq, libModule, dynModule, startBound, startUserAddr,
995                        endBound, endUserAddr)) {
996     err = true;
997     return;
998   }
999   statusLine("checking call points");
1000   checkAllCallPoints();
1001   statusLine("ready");
1002
1003 #ifdef DEBUG_TIME
1004   restTimer.stop();
1005   fprintf(timeOut, "It took %f:user %f:system %f:wall seconds to process after load %s\n",
1006           restTimer.usecs(), restTimer.ssecs(),
1007           restTimer.wsecs(), fileName.string_of());
1008 #endif /* DEBUG_TIME */
1009
1010   // TODO -- remove duplicates -- see earlier note
1011   dictionary_hash<unsigned, unsigned> addr_dict(uiHash);
1012   vector<pdFunction*> temp_vec;
1013   unsigned f_size = mdlLib.size(), index;
1014   for (index=0; index<f_size; index++) {
1015     if (!addr_dict.defines((unsigned)mdlLib[index]->addr())) {
1016       addr_dict[(unsigned)mdlLib[index]->addr()] = 1;
1017       temp_vec += mdlLib[index];
1018     }
1019   }
1020   mdlLib = temp_vec;
1021   temp_vec.resize(0); addr_dict.clear();
1022   f_size = mdlNormal.size();
1023   for (index=0; index<f_size; index++) {
1024     if (!addr_dict.defines((unsigned)mdlNormal[index]->addr())) {
1025       addr_dict[(unsigned)mdlNormal[index]->addr()] = 1;
1026       temp_vec += mdlNormal[index];
1027     }
1028   }
1029   mdlNormal = temp_vec;
1030 }
1031
1032 void module::checkAllCallPoints() {
1033   unsigned fsize = funcs.size();
1034   for (unsigned f=0; f<fsize; f++)
1035     funcs[f]->checkCallPoints();
1036 }
1037
1038 void image::checkAllCallPoints() {
1039   dictionary_hash_iter<string, module*> di(modsByFullName);
1040   string s; module *mod;
1041   while (di.next(s, mod))
1042     mod->checkAllCallPoints();
1043 }
1044
1045 // passing in tags allows a function to be tagged as TAG_LIB_FUNC even
1046 // if its entry is not in the tag dictionary of known functions
1047 bool image::defineFunction(module *use, const Symbol &sym, const unsigned tags,
1048                            pdFunction *&retFunc) {
1049   const char *str = (sym.name()).string_of();
1050
1051   // TODO - skip the underscore
1052   if (*str == '_') 
1053     str++;
1054
1055   unsigned dictTags = findTags(str);
1056   return (newFunc(use, str, sym.addr(), tags | dictTags, retFunc));
1057 }
1058
1059 module *image::getOrCreateModule(const string &modName, const Address modAddr) {
1060   const char *str = modName.string_of();
1061   int len = modName.length();
1062   assert(len>0);
1063
1064   // TODO ignore directory definitions for now
1065   if (str[len-1] == '/') {
1066     return NULL;
1067   } else {
1068     // TODO - navigate ".." and "."
1069     char *lastSlash = P_strrchr(str, '/');
1070     if (lastSlash)
1071       return (newModule(++lastSlash, modAddr));
1072     else
1073       return (newModule(modName, modAddr));
1074   }
1075 }
1076
1077 // KLUDGE TODO - internal functions are tagged with TAG_LIB_FUNC
1078 // but they won't have tags in the tag dict, so this happens...
1079 bool image::defineFunction(module *libModule, const Symbol &sym,
1080                            const string &modName, const Address modAddr,
1081                            pdFunction *&retFunc) {
1082   const char *str = (sym.name()).string_of();
1083
1084   // TODO - skip the underscore
1085   if (*str == '_') 
1086     str++;
1087   unsigned tags = findTags(str);
1088
1089   if (TAG_LIB_FUNC & tags)
1090     return (newFunc(libModule, str, sym.addr(), tags | TAG_LIB_FUNC, retFunc));
1091   else {
1092     module *use = getOrCreateModule(modName, modAddr);
1093     assert(use);
1094     return (newFunc(use, str, sym.addr(), tags, retFunc));
1095   }
1096 }
1097
1098 // Verify that this is code
1099 // Find the call points
1100 // Find the return address
1101 // TODO -- use an instruction object to remove
1102 // Sets err to false on error, true on success
1103 //
1104 // Note - this must define funcEntry and funcReturn
1105 // 
1106 pdFunction::pdFunction(const string symbol, const string &pretty, module *f,
1107                        Address adr, const unsigned tg, const image *owner, bool &err)
1108 : tag_(tg),
1109   symTabName_(symbol),
1110   prettyName_(pretty),
1111   line_(0),
1112   file_(f),
1113   addr_(adr),
1114   funcEntry_(NULL),
1115   funcReturn_(NULL)
1116 {
1117   instruction instr;
1118   err = false;
1119
1120   instr.raw = owner->get_instruction(adr);
1121   if (!IS_VALID_INSN(instr)) {
1122     err = true; return;
1123   }
1124
1125   // TODO - why not automatic?
1126   // define the entry point
1127   funcEntry_ = new instPoint(this, instr, owner, adr, true);
1128   assert(funcEntry_);
1129
1130   while (true) {
1131     instr.raw = owner->get_instruction(adr);
1132
1133     // this does not account for jump tables
1134     // if (!IS_VALID_INSN(instr)) {
1135     // err = true; return;
1136     // } else 
1137     if (isInsnType(instr, RETmask, RETmatch) ||
1138                isInsnType(instr, RETLmask, RETLmatch)) {
1139       // define the return point
1140       funcReturn_ = new instPoint(this, instr, owner, adr, false);
1141       assert(funcReturn_);
1142       // TODO -- move this to machine dependent area
1143       if ((instr.resti.simm13 != 8) && (instr.resti.simm13 != 12)) {
1144         logLine("*** FATAL Error:");
1145         sprintf(errorLine, " unsupported return at %x\n", funcReturn_->addr);
1146         logLine(errorLine);
1147         P_abort();
1148         err = false;
1149         return;
1150       }
1151       return;
1152     } else if (isCallInsn(instr)) {
1153       // define a call point
1154       // this may update address - sparc - aggregate return value
1155       // want to skip instructions
1156       adr = newCallPoint(adr, instr, owner, err);
1157     }
1158     // now do the next instruction
1159     adr += 4;
1160   }
1161 }
1162
1163 // find all DYNINST symbols that are data symbols
1164 bool image::heapIsOk(const vector<sym_data> &find_us) {
1165   Address curr, instHeapEnd;
1166   Symbol sym;
1167   string str;
1168
1169   for (unsigned i=0; i<find_us.size(); i++) {
1170     str = find_us[i].name;
1171     if (!linkedFile.get_symbol(str, sym)) {
1172       string str1 = string("_") + str.string_of();
1173       if (!linkedFile.get_symbol(str1, sym) && find_us[i].must_find) {
1174         char msg[100];
1175         sprintf(msg, "Cannot find %s, exiting", str.string_of());
1176         statusLine(msg);
1177         return false;
1178       }
1179     }
1180     addInternalSymbol(str, sym.addr());
1181   }
1182
1183   string ghb = GLOBAL_HEAP_BASE;
1184   if (!linkedFile.get_symbol(ghb, sym)) {
1185     ghb = U_GLOBAL_HEAP_BASE;
1186     if (!linkedFile.get_symbol(ghb, sym)) {
1187       char msg[100];
1188       sprintf(msg, "Cannot find %s, exiting", str.string_of());
1189       statusLine(msg);
1190       return false;
1191     }
1192   }
1193   instHeapEnd = sym.addr();
1194   addInternalSymbol(ghb, instHeapEnd);
1195   ghb = INFERIOR_HEAP_BASE;
1196
1197   if (!linkedFile.get_symbol(ghb, sym)) {
1198     ghb = UINFERIOR_HEAP_BASE;
1199     if (!linkedFile.get_symbol(ghb, sym)) {
1200       char msg[100];
1201       sprintf(msg, "Cannot find %s, cannot use this application", str.string_of());
1202       statusLine(msg);
1203       return false;
1204     }
1205   }
1206   curr = sym.addr();
1207   addInternalSymbol(ghb, curr);
1208   if (curr > instHeapEnd) instHeapEnd = curr;
1209
1210   // check that we can get to our heap.
1211   if (instHeapEnd > getMaxBranch()) {
1212     logLine("*** FATAL ERROR: Program text + data too big for dyninst\n");
1213     sprintf(errorLine, "    heap ends at %x\n", instHeapEnd);
1214     logLine(errorLine);
1215     return false;
1216   } else if (instHeapEnd + SYN_INST_BUF_SIZE > getMaxBranch()) {
1217     logLine("WARNING: Program text + data could be too big for dyninst\n");
1218     return false;
1219   }
1220   return true;
1221 }
1222
1223 // Store the mapping function:    name --> set of mdl resource lists
1224 void image::update_watch_map(unsigned index, vector<string> *vs,
1225                              vector<string>& prefix,
1226                              vector<string>& non_prefix) {
1227   unsigned vs_size = vs->size();
1228   for (unsigned v=0; v<vs_size; v++) {
1229     unsigned len = (*vs)[v].length();
1230
1231     // Check for wildcard character
1232     if (len && (((*vs)[v].string_of())[len-1] == '*')) {
1233       char *buffer = new char[len+1];
1234       P_strcpy(buffer, (*vs)[v].string_of());
1235       assert(buffer[len-1] == '*');
1236       buffer[len-1] = '\0';
1237       prefix += buffer;
1238       delete [] buffer;
1239     } else {
1240       non_prefix += (*vs)[v];
1241     }
1242   }
1243 }
1244
1245 void image::watch_functions(string& name, vector<string> *vs, bool is_lib,
1246                             vector<pdFunction*> *update) {
1247   unsigned wv_size = watch_vec.size();
1248   bool found = false; unsigned found_index=0;
1249   for (unsigned wv=0; wv<wv_size; wv++)
1250     if (watch_vec[wv].name == name) {
1251       delete watch_vec[wv].funcs;
1252       delete watch_vec[wv].mods;
1253       found = true;
1254       found_index = wv;
1255     }
1256
1257   if (!found) {
1258     watch_data wd;
1259     found_index = watch_vec.size();
1260     watch_vec += wd;
1261   }
1262
1263   update_watch_map(found_index, vs, watch_vec[found_index].prefix, 
1264                    watch_vec[found_index].non_prefix);
1265
1266   watch_vec[found_index].name = name;
1267   watch_vec[found_index].is_lib = is_lib;
1268   watch_vec[found_index].funcs = update;
1269   watch_vec[found_index].mods = NULL;
1270   watch_vec[found_index].is_func = true;
1271 }
1272
1273