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