removed some warnings
[dyninst.git] / dyninstAPI / src / symtab.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 #include <stdio.h>
43 #include <stdlib.h>
44 #include <assert.h>
45
46 // TODO - machine independent instruction functions
47 #include "dyninstAPI/src/symtab.h"
48 #include "dyninstAPI/src/arch.h"
49 #include "util/h/Object.h"
50 #include <fstream.h>
51 #include "dyninstAPI/src/util.h"
52 #include "dyninstAPI/src/dyninstP.h"
53 #include "util/h/String.h"
54 #include "dyninstAPI/src/inst.h"
55 #include "util/h/Timer.h"
56 #include "paradynd/src/showerror.h"
57 #include "util/h/debugOstream.h"
58
59 #ifndef BPATCH_LIBRARY
60 #include "paradynd/src/main.h"
61 #include "paradynd/src/init.h"
62 #else
63 extern vector<sym_data> syms_to_find;
64 #endif
65
66 // All debug_ostream vrbles are defined in process.C (for no particular reason)
67 extern debug_ostream sharedobj_cerr;
68
69 vector<image*> image::allImages;
70
71 #if defined(i386_unknown_nt4_0)
72 extern char *cplus_demangle(char *, int);
73 #else
74 extern "C" char *cplus_demangle(char *, int);
75 #endif
76
77
78 /* imported from platform specific library list.  This is lists all
79    library functions we are interested in instrumenting. */
80
81 pdmodule *image::newModule(const string &name, const Address addr)
82 {
83     pdmodule *ret;
84     // modules can be defined several times in C++ due to templates and
85     //   in-line member functions.
86     if ((ret = findModule(name)))
87       return(ret);
88
89     string fullNm, fileNm;
90     char *out = P_strdup(name.string_of());
91     char *sl = P_strrchr(out, '/');
92     if (sl) {
93       *sl = (char)0;
94       fullNm = out;
95       fileNm = sl+1;
96     } else {
97       fullNm = string("/default/") + out;
98       fileNm = out;
99     }
100     free(out);
101
102     ret = new pdmodule(langUnknown, addr, fullNm, fileNm, this);
103     modsByFileName[ret->fileName()] = ret;
104     modsByFullName[ret->fullName()] = ret;
105     mods += ret;
106     return(ret);
107 }
108
109
110 // TODO -- is this g++ specific
111 bool buildDemangledName(const string &mangled, string &use)
112 {
113  /* The C++ demangling function demangles MPI__Allgather (and other MPI__
114   * functions with start with A) into the MPI constructor.  In order to
115   * prevent this a hack needed to be made, and this seemed the cleanest
116   * approach.
117   */
118   if(!mangled.prefixed_by("MPI__")) {
119     char *tempName = P_strdup(mangled.string_of());
120     char *demangled = cplus_demangle(tempName, 0);
121     
122     if (demangled) {
123       use = demangled;
124       free(tempName);
125       free(demangled);
126       return true;
127     } else {
128       free(tempName);
129       return false;
130     }
131   }
132   return(false);
133 }
134
135 // err is true if the function can't be defined
136 bool image::newFunc(pdmodule *mod, const string &name, const Address addr, 
137                     const unsigned size, const unsigned tag, 
138                     pd_Function *&retFunc) {
139   pd_Function *func;
140   retFunc = NULL;
141   // KLUDGE
142   if ((func = findFunction(addr))){
143     string temp = name;
144     temp += string(" findFunction failed\n");
145     logLine(P_strdup(temp.string_of()));
146     return false;
147   }
148
149   if (!mod) {
150     logLine("Error function without module\n");
151     showErrorCallback(34, "Error function without module");
152     return false;
153   }
154
155   string mangled_name = name;
156   const char *p = P_strchr(name.string_of(), ':');
157   if (p) {
158      unsigned nchars = p - name.string_of();
159      mangled_name = string(name.string_of(), nchars);
160   }
161      
162   string demangled;
163   if (!buildDemangledName(mangled_name, demangled)) 
164     demangled = mangled_name;
165
166   bool err;
167
168   func = new pd_Function(name, demangled, mod, addr, size, tag, this, err);
169   //cout << name << " pretty: " << demangled << " addr :" << addr <<endl;
170   retFunc = func;
171   if (err) {
172     //delete func;
173     retFunc = NULL;
174     notInstruFunction += func;
175     return false;
176   }
177   
178   funcsByAddr[addr] = func;
179   mod->funcs += func;
180
181   vector<pd_Function*> *funcsByPrettyEntry;
182   if (!funcsByPretty.find(func->prettyName(), funcsByPrettyEntry)) {
183     funcsByPrettyEntry = new vector<pd_Function*>;
184     funcsByPretty[func->prettyName()] = funcsByPrettyEntry;
185   }
186
187   // several functions may have the same demangled name, and each one
188   // will appear in a different module
189 //  vector<pdFunction*> *ap = funcsByPretty[func->prettyName()];
190   assert(funcsByPrettyEntry);
191   (*funcsByPrettyEntry) += func;
192   return true;
193 }
194
195 #ifdef DEBUG_TIME
196 static timer loadTimer;
197 static FILE *timeOut=0;
198 #endif /* DEBUG_TIME */
199
200 /*
201  * load an executable:
202  *   1.) parse symbol table and identify rotuines.
203  *   2.) scan executable to identify inst points.
204  *
205  *  offset is normally zero except on CM-5 where we have two images in one
206  *    file.  The offset passed to parseImage is the logical offset (0/1), not
207  *    the physical point in the file.  This makes it faster to "parse" multiple
208  *    copies of the same image since we don't have to stat and read to find the
209  *    physical offset. 
210  */
211 image *image::parseImage(const string file)
212 {
213   /*
214    * Check to see if we have parsed this image at this offeset before.
215    */
216   // TODO -- better method to detect same image/offset --> offset only for CM5
217
218   unsigned numImages = allImages.size();
219
220   for (unsigned u=0; u<numImages; u++)
221     if (file == allImages[u]->file())
222       return allImages[u];
223
224   /*
225    * load the symbol table. (This is the a.out format specific routine).
226    */
227
228   statusLine("Process executable file");
229   bool err;
230
231   // TODO -- kill process here
232   image *ret = new image(file, err);
233   if (err || !ret) {
234     if (ret)
235       delete ret;
236     return NULL;
237   }
238
239   // Add to master image list.
240   image::allImages += ret;
241
242   // define all modules.
243 #ifndef BPATCH_LIBRARY
244   tp->resourceBatchMode(true);
245 #endif
246
247   statusLine("defining modules");
248   ret->defineModules();
249
250 //  statusLine("ready"); // this shouldn't be here, right? (cuz we're not done, right?)
251
252 #ifndef BPATCH_LIBRARY
253   tp->resourceBatchMode(false);
254 #endif
255
256   return(ret);
257 }
258
259 /*
260  * load a shared object:
261  *   1.) parse symbol table and identify rotuines.
262  *   2.) scan executable to identify inst points.
263  *
264  */
265 image *image::parseImage(const string file,u_int baseAddr)
266 {
267   /*
268    * Check to see if we have parsed this image at this offeset before.
269    */
270   // TODO -- better method to detect same image/offset --> offset only for CM5
271
272   unsigned theSize = allImages.size();
273
274   for (unsigned u=0; u<theSize; u++)
275     if (file == allImages[u]->file())
276       return allImages[u];
277
278   /*
279    * load the symbol table. (This is the a.out format specific routine).
280    */
281
282   if(!baseAddr) statusLine("Processing an executable file");
283   else  statusLine("Processing a shared object file");
284   bool err;
285
286   // TODO -- kill process here
287   image *ret = new image(file, baseAddr,err);
288   if (err || !ret) {
289     if (ret)
290       delete ret;
291     logLine("error after new image in parseImage\n");
292     return NULL;
293   }
294
295   // Add to master image list.
296   image::allImages += ret;
297
298   // define all modules.
299   ret->defineModules();
300   return(ret);
301 }
302
303 bool image::addInternalSymbol(const string &str, const Address symValue) {
304   // Internal symbols are prefixed by { DYNINST, TRACELIB }
305   // don't ignore the underscore
306   static string dyn = "_DYNINST"; 
307   static string tlib = "_TRACELIB";
308
309
310   // normalize all symbols -- remove the leading "_"
311   if (str.prefixed_by(dyn)) {
312     const char *s = str.string_of(); s++;
313     if (!iSymsMap.defines(s)){
314       iSymsMap[s] = new internalSym(symValue, s);
315     }
316     return true;
317   } else if (str.prefixed_by(tlib)) {
318     const char *s = str.string_of(); s++;
319     if (!iSymsMap.defines(s))
320       iSymsMap[s] = new internalSym(symValue, s);
321     return true;
322   } else {
323     if (!iSymsMap.defines(str))
324       iSymsMap[str] = new internalSym(symValue, str);
325     return true;
326   }
327   return false;
328 }
329
330 /*
331  * will search for symbol NAME or _NAME
332  * returns false on failure 
333  */
334 bool image::findInternalSymbol(const string &name, const bool warn, internalSym &ret_sym){
335    Symbol lookUp;
336
337    if(linkedFile.get_symbol(name,lookUp)){
338       ret_sym = internalSym(lookUp.addr(),name); 
339       return true;
340    }
341    else {
342        string new_sym;
343        new_sym = string("_") + name;
344        if(linkedFile.get_symbol(new_sym,lookUp)){
345           ret_sym = internalSym(lookUp.addr(),name); 
346           return true;
347        }
348    } 
349    if(warn){
350       string msg;
351       msg = string("Unable to find symbol: ") + name;
352       statusLine(msg.string_of());
353       showErrorCallback(28, msg);
354    }
355    return false;
356 }
357
358 Address image::findInternalAddress(const string &name, const bool warn, bool &err)
359 {
360
361   err = false;
362
363   internalSym *theSym; // filled in by find()
364   if (!iSymsMap.find(name, theSym)) {
365     // not found!
366     if (warn) {
367       string msg = string("Unable to find symbol: ") + name;
368       statusLine(msg.string_of());
369       showErrorCallback(28, msg);
370     }
371     err = true;
372     return 0;
373   } 
374   else
375     return (theSym->getAddr());
376 }
377
378 pdmodule *image::findModule(const string &name)
379 {
380   if (modsByFileName.defines(name))
381     return (modsByFileName[name]);
382   else if (modsByFullName.defines(name))
383     return (modsByFullName[name]);
384   else
385     return NULL;
386 }
387
388 // TODO -- this is only being used in cases where only one function
389 // should exist -- should I assert that the vector size <= 1 ?
390 pd_Function *image::findOneFunction(const string &name)
391 {
392   string demangName;
393
394   if (funcsByPretty.defines(name)) {
395     vector<pd_Function*> *a = funcsByPretty[name];
396     assert(a);
397     if (!a->size())
398       return NULL;
399     else
400       return ((*a)[0]);
401   } else if (buildDemangledName(name, demangName)) {
402     if (funcsByPretty.defines(demangName)) {
403       vector<pd_Function*> *a = funcsByPretty[demangName];
404       assert(a);
405       if (!a->size())
406         return NULL;
407       else
408         return ((*a)[0]);
409     } else
410       return NULL;
411   } else
412     return NULL;
413 }
414
415 // This function supposely is only used to find function that
416 // is not instrumentable which may not be totally defined.
417 // Use with caution.  
418 pd_Function *image::findOneFunctionFromAll(const string &name) {
419
420     pd_Function *ret;
421     if ((ret = findOneFunction(name))) 
422         return ret;
423     else {
424         for (unsigned i = 0; i < notInstruFunction.size(); i++) {
425             ret = notInstruFunction[i];
426             if (ret->prettyName() == name)
427                 return ret;
428         }
429     }
430     return NULL;
431 }
432
433 bool image::findFunction(const string &name, vector<pd_Function*> &retList) {
434
435   if (funcsByPretty.defines(name)) {
436     retList = *funcsByPretty[name];
437     return true;
438   } else
439     return false;
440 }
441
442 pd_Function *image::findFunction(const Address &addr) 
443 {
444   pd_Function *result; // filled in by find()
445   if (funcsByAddr.find(addr, result))
446      return result;
447   else
448      return NULL;
449 }
450  
451 pd_Function *image::findFunctionInInstAndUnInst(const Address &addr,const process *p) const 
452 {
453   pd_Function *pdf;
454
455   if (funcsByAddr.find(addr, pdf))
456      return pdf;
457   else
458      return NULL;
459   
460   // If not found, we are going to search them in the 
461   // uninstrumentable function
462   for (unsigned i = 0; i < notInstruFunction.size(); i++) {
463       pdf = notInstruFunction[i];
464       if ((addr>=pdf->getAddress(p))&&(addr<=(pdf->getAddress(p)+pdf->size()))) 
465           return pdf;
466   }
467
468   return NULL; 
469 }
470  
471 pd_Function *image::findFunctionIn(const Address &addr,const process *p) const 
472 {
473   pd_Function *pdf;
474
475   dictionary_hash_iter<Address, pd_Function*> mi(funcsByAddr);
476   Address adr;
477   while (mi.next(adr, pdf)) {
478       if ((addr>=pdf->getAddress(p))&&(addr<=(pdf->getAddress(p)+pdf->size()))) 
479           return pdf;
480   }
481   
482   // If not found, we are going to search them in the 
483   // uninstrumentable function
484   for (unsigned i = 0; i < notInstruFunction.size(); i++) {
485       pdf = notInstruFunction[i];
486       if ((addr>=pdf->getAddress(p))&&(addr<=(pdf->getAddress(p)+pdf->size()))) 
487           return pdf;
488   }
489
490   return NULL; 
491 }
492
493
494 #ifndef BPATCH_LIBRARY
495 void image::changeLibFlag(resource *res, const bool setSuppress)
496 {
497   image *ret;
498   pdmodule *mod;
499
500   unsigned numImages = image::allImages.size();
501   for (unsigned u=0; u<numImages; u++) {
502     ret = image::allImages[u];
503     mod = ret->findModule(res->part_name());
504     if (mod) {
505       // suppress all procedures.
506       mod->changeLibFlag(setSuppress);
507     } else {
508       // more than one function may have this name --> templates, statics
509       vector<pd_Function*> pdfA;
510       if (ret->findFunction(res->part_name(), pdfA)) {
511         for (unsigned i=0; i<pdfA.size(); ++i) {
512           if (setSuppress) 
513             pdfA[i]->tagAsLib();
514           else
515             pdfA[i]->untagAsLib();
516         }
517       }
518     }
519   }
520 }
521 #endif
522
523
524 /* 
525  * return 0 if symbol <symname> exists in image, non-zero if it does not
526  */
527 bool image::symbolExists(const string &symname)
528 {
529   pd_Function *dummy = findOneFunction(symname);
530   return (dummy != NULL);
531 }
532
533 void image::postProcess(const string pifname)
534 {
535   FILE *Fil;
536   string fname, errorstr;
537   char key[5000];
538   char tmp1[5000], abstraction[500];
539 #ifndef BPATCH_LIBRARY
540   resource *parent;
541 #endif
542
543   return;
544
545   /* What file to open? */
546   if (!(pifname == (char*)NULL)) {
547     fname = pifname;
548   } else {
549     fname = file_ + ".pif";
550   }
551
552   /* Open the file */
553   Fil = P_fopen(fname.string_of(), "r");
554
555   if (Fil == NULL) {
556     errorstr = string("Tried to open PIF file ") + fname;
557     errorstr += string(", but could not (continuing)\n");
558     logLine(P_strdup(errorstr.string_of()));
559     showErrorCallback(35, errorstr); 
560     return;
561   }
562
563   /* Process the file */
564   while (!feof(Fil)) {
565     fscanf(Fil, "%s", key);
566     switch (key[0]) {
567     case 'M':
568       /* Ignore mapping information for right now */
569       fgets(tmp1, 5000, Fil);
570       break;
571     case 'R':
572 #ifndef BPATCH_LIBRARY
573       /* Create a new resource */
574       fscanf(Fil, "%s {", abstraction);
575       parent = rootResource;
576       do {
577         fscanf(Fil, "%s", tmp1);
578         if (tmp1[0] != '}') {
579           parent = resource::newResource(parent, NULL,
580                                          abstraction,
581                                          tmp1, 0.0,
582                                          nullString, // uniqifier
583                                          MDL_T_STRING,
584                                          true);
585         } else {
586           parent = NULL;
587         }
588       } while (parent != NULL);
589 #endif
590       break;
591     default:
592       errorstr = string("Ignoring bad line key (") + fname;
593       errorstr += string(") in file %s\n");
594       logLine(P_strdup(errorstr.string_of()));
595       fgets(tmp1, 5000, Fil);
596       break;
597     }
598   }
599   return;
600 }
601
602 void image::defineModules() {
603   string pds; pdmodule *mod;
604   dictionary_hash_iter<string, pdmodule*> mi(modsByFileName);
605
606   while (mi.next(pds, mod)){
607     mod->define();
608   }
609
610 #ifdef DEBUG_MDL
611   char buffer[100];
612   ostrstream osb(buffer, 100, ios::out);
613   osb << "IMAGE_" << name() << "__" << getpid() << ends;
614   ofstream of(buffer, ios::app);
615   unsigned n_size = mdlNormal.size();
616   of << "NORMAL\n";
617   for (unsigned ni=0; ni<n_size; ni++) {
618     of << mdlNormal[ni]->prettyName() << "\t\t" << mdlNormal[ni]->addr() << "\t\t" << 
619       mdlNormal[ni]->isLibTag() << endl;
620   }
621   n_size = mdlLib.size();
622   of << "\n\nLIB\n";
623   for (ni=0; ni<n_size; ni++) {
624     of << mdlLib[ni]->prettyName() << "\t\t" << mdlLib[ni]->addr() << "\t\t" <<
625       mdlLib[ni]->isLibTag() << endl;
626   }
627 #endif
628 }
629
630 void pdmodule::define() {
631 #ifndef BPATCH_LIBRARY
632   resource *modResource = NULL;
633 #endif
634 #ifdef DEBUG_MODS
635   char buffer[100];
636   ostrstream osb(buffer, 100, ios::out);
637   osb << "MODS_" << exec->name() << "__" << getpid() << ends;
638   ofstream of(buffer, ios::app);
639 #endif
640
641   unsigned f_size = funcs.size();
642
643   for (unsigned f=0; f<f_size; f++) {
644     pd_Function *pdf = funcs[f];
645 #ifdef DEBUG_MODS
646     of << fileName << ":  " << pdf->prettyName() <<  "  " <<
647       pdf->isLibTag() << "  " << pdf->addr() << endl;
648 #endif
649     // ignore line numbers for now 
650
651 #ifndef BPATCH_LIBRARY
652     if (!(pdf->isLibTag())) {
653       // see if we have created module yet.
654       if (!modResource) {
655         modResource = resource::newResource(moduleRoot, this,
656                                             nullString, // abstraction
657                                             fileName(), // name
658                                             0.0, // creation time
659                                             string::nil, // unique-ifier
660                                             MDL_T_MODULE,
661                                             false);
662       }
663       resource::newResource(modResource, pdf,
664                             nullString, // abstraction
665                             pdf->prettyName(), 0.0,
666                             nullString, // uniquifier
667                             MDL_T_PROCEDURE,
668                             false);
669     }
670 #endif
671   }
672
673 #ifndef BPATCH_LIBRARY
674   resource::send_now();
675 #endif
676 }
677
678 static inline bool findStartSymbol(Object &lf, Address &adr) {
679   Symbol lookUp;
680
681   if (lf.get_symbol("DYNINSTstartUserCode", lookUp) ||
682       lf.get_symbol("_DYNINSTstartUserCode", lookUp)) {
683     adr = lookUp.addr();
684     return true;
685   } else
686     return false;
687 }
688
689 static inline bool findEndSymbol(Object &lf, Address &adr) {
690   Symbol lookUp;
691
692   if (lf.get_symbol("DYNINSTendUserCode", lookUp) ||
693       lf.get_symbol("_DYNINSTendUserCode", lookUp)) {
694     adr = lookUp.addr();
695     return true;
696   } else
697     return false;
698 }
699
700 // TODO this assumes an ordering in the symbol table wrt modules KLUDGE
701 static inline bool notInUserRange(const Address adr,
702                                   const bool start, const Address startAdr,
703                                   const bool end, const Address endAdr) {
704   return ((start && (adr < startAdr)) || (end && (adr >= endAdr)));
705 }
706
707 // I commented this out since gcc says it ain't used --ari 10/97
708 // static void binSearch (const Symbol &lookUp, vector<Symbol> &mods,
709 //                     string &modName, Address &modAddr, const string &def) {
710 //   int start=0, end=mods.size()-1, index;
711 //   bool found=false;
712
713 //   if (!mods.size()) {
714 //     modAddr = 0;
715 //     modName = def;
716 //     return;
717 //   }
718
719 //   while ((start <= end) && !found) {
720 //     index = (start+end)/2;
721
722 //     if ((index == (((int)mods.size())-1)) ||
723 //      ((mods[index].addr() <= lookUp.addr()) && (mods[index+1].addr() > lookUp.addr()))) {
724 //       modName = mods[index].name();
725 //       modAddr = mods[index].addr();      
726 //       found = true;
727 //     } else if (lookUp.addr() < mods[index].addr()) {
728 //       end = index - 1;
729 //     } else {
730 //       start = index + 1;
731 //     }
732 //   }
733 //   if (!found) {
734 //     modName = mods[0].name();
735 //     modAddr = mods[0].addr();
736 //   }
737 // }
738
739 bool image::addOneFunction(vector<Symbol> &, // mods
740                            pdmodule *lib,
741                            pdmodule *, // dyn
742                            const Symbol &lookUp, pd_Function  *&retFunc) {
743   // TODO mdc
744   // find the module
745   // this is a "user" symbol
746   string modName = lookUp.module();
747   Address modAddr = 0;
748   
749   string progName = name_ + "_module";
750
751 #if defined (sparc_sun_solaris2_4) || defined (i386_unknown_solaris2_5) 
752   // In solaris there is no address for modules in the symbol table, 
753   // so the binary search will not work. The module field in a symbol
754   // already has the correct module name for a symbol, if it can be
755   // obtained from the symbol table, otherwise the module is an empty
756   // string.
757   if (modName == "") {
758     modName = progName;
759   }
760 #else
761   binSearch(lookUp, mods, modName, modAddr, progName);
762 #endif
763
764   return (defineFunction(lib, lookUp, modName, modAddr, retFunc));
765 }
766
767 bool inLibrary(Address addr, Address boundary_start, Address boundary_end,
768                       Address startAddr, bool startB,
769                       Address endAddr, bool endB) {
770   if ((addr >= boundary_start) && (addr <= boundary_end))
771     return true;
772   else if (startB) {
773     if (addr <= startAddr)
774       return true;
775     else if (endB) {
776       if (addr >= endAddr)
777         return true;
778       else 
779         return false;
780     } else 
781       return false;
782   } else if (endB) {
783     if (addr >= endAddr)
784       return true;
785     else
786       return false;
787   } else
788     return false;
789 }
790
791 bool image::addAllFunctions(vector<Symbol> &mods,
792                             pdmodule *lib, pdmodule *dyn, 
793                             const bool startB, const Address startAddr,
794                             const bool endB, const Address endAddr) {
795
796   Address boundary_start, boundary_end;
797   Symbol lookUp;
798   string symString;
799   SymbolIter symIter(linkedFile);
800
801 #ifdef BPATCH_LIBRARY
802   boundary_start = boundary_end = NULL;
803 #else
804   if (!linkedFile.get_symbol(symString="DYNINSTfirst", lookUp) &&
805       !linkedFile.get_symbol(symString="_DYNINSTfirst", lookUp)) {
806     //statusLine("Internal symbol DYNINSTfirst not found");
807     //showErrorCallback(31, "Internal symbol DYNINSTfirst not found");
808     //return false;
809     boundary_start = NULL;
810   } else
811     boundary_start = lookUp.addr();
812
813   if (!linkedFile.get_symbol(symString="DYNINSTend", lookUp) &&
814       !linkedFile.get_symbol(symString="_DYNINSTend", lookUp)) {
815     //statusLine("Internal symbol DYNINSTend not found");
816     //showErrorCallback(32, "Internal symbol DYNINSTend not found");
817     //return false;
818     boundary_end = NULL;
819   } else
820     boundary_end = lookUp.addr();
821 #endif
822
823   Symbol mainFuncSymbol;  //Keeps track of info on "main" function
824
825   //Checking "main" function names in same order as in the inst-*.C files
826   if (linkedFile.get_symbol(symString="main",     lookUp) ||
827       linkedFile.get_symbol(symString="_main",    lookUp) ||
828       linkedFile.get_symbol(symString="WinMain",  lookUp) ||
829       linkedFile.get_symbol(symString="_WinMain", lookUp)) 
830     mainFuncSymbol = lookUp;
831
832   // find the real functions -- those with the correct type in the symbol table
833   while (symIter.next(symString, lookUp)) {
834
835     if (funcsByAddr.defines(lookUp.addr()) ||
836         ((lookUp.addr() == mainFuncSymbol.addr()) &&
837          (lookUp.name() != mainFuncSymbol.name()))) {
838       // This function has been defined 
839       // *or*
840       // This function has the same address as the "main" function but does 
841       //   not have the same name as the "main" function.  Therefore, skip
842       //   it and let the "main" function be eventually associated with this
843       //   function address.  If we don't do this, paradynd will not have a
844       //   "main" function to start work with.
845       ;
846     } else if (lookUp.type() == Symbol::PDST_FUNCTION) {
847       if (!isValidAddress(lookUp.addr())) {
848         string msg;
849         char tempBuffer[40];
850         sprintf(tempBuffer,"%x",lookUp.addr());
851         msg = string("Function") + lookUp.name() + string("has bad address ") +
852               string(tempBuffer);
853         statusLine(msg.string_of());
854         showErrorCallback(29, msg);
855         return false;
856       }
857       pd_Function *pdf;
858       if (inLibrary(lookUp.addr(), boundary_start, boundary_end,
859                     startAddr, startB, endAddr, endB)) {
860         addInternalSymbol(lookUp.name(), lookUp.addr());
861         if (defineFunction(dyn, lookUp, TAG_LIB_FUNC, pdf)) {
862           assert(pdf); mdlLib += pdf;
863         }
864       } else {
865         if (addOneFunction(mods, lib, dyn, lookUp, pdf)) {
866           assert(pdf); mdlNormal += pdf;
867         }
868       }
869     }
870   }
871
872   // now find the pseudo functions -- this gets ugly
873   // kludge has been set if the symbol could be a function
874   symIter.reset();
875   while (symIter.next(symString, lookUp)) {
876     if (funcsByAddr.defines(lookUp.addr())) {
877       // This function has been defined
878       ;
879     } else if ((lookUp.type() == Symbol::PDST_OBJECT) && lookUp.kludge()) {
880       //logLine(P_strdup(symString.string_of()));
881       pd_Function *pdf;
882       if (inLibrary(lookUp.addr(), boundary_start, boundary_end,
883                     startAddr, startB, endAddr, endB)) {
884         addInternalSymbol(lookUp.name(), lookUp.addr());
885         if (defineFunction(dyn, lookUp, TAG_LIB_FUNC, pdf)) {
886           assert(pdf); mdlLib += pdf;
887         }
888       } else {
889         if (addOneFunction(mods, lib, dyn, lookUp, pdf)) {
890           assert(pdf); mdlNormal += pdf;
891         }
892       }
893     }
894   }
895   return true;
896 }
897
898 bool image::addAllSharedObjFunctions(vector<Symbol> &mods,
899                             pdmodule *lib, pdmodule *dyn) {
900
901   Symbol lookUp;
902   string symString;
903   SymbolIter symIter(linkedFile);
904
905   bool is_libdyninstRT = false; // true if this image is libdyninstRT
906 #if defined(i386_unknown_nt4_0)
907   if (linkedFile.get_symbol(symString="_DYNINSTfirst", lookUp)
908       || linkedFile.get_symbol(symString="_DYNINSTfirst", lookUp))
909     is_libdyninstRT = true;
910 #endif
911
912   // find the real functions -- those with the correct type in the symbol table
913   while (symIter.next(symString, lookUp)) {
914
915     if (funcsByAddr.defines(lookUp.addr())) {
916       // This function has been defined
917       ;
918     } else if (lookUp.type() == Symbol::PDST_FUNCTION) {
919       if (!isValidAddress(lookUp.addr())) {
920         string msg;
921         char tempBuffer[40];
922         sprintf(tempBuffer,"%x",lookUp.addr());
923         msg = string("Function") + lookUp.name() + string("has bad address ") +
924               string(tempBuffer);
925         statusLine(msg.string_of());
926         showErrorCallback(29, msg);
927         return false;
928       }
929       pd_Function *pdf;
930       if (is_libdyninstRT) {
931         addInternalSymbol(lookUp.name(), lookUp.addr());
932         if (defineFunction(dyn, lookUp, TAG_LIB_FUNC, pdf)) {
933           assert(pdf); mdlLib += pdf;
934         }
935       } else if (addOneFunction(mods, lib, dyn, lookUp, pdf)) {
936         assert(pdf); mdlNormal += pdf;
937       }
938     }
939   }
940
941   // now find the pseudo functions -- this gets ugly
942   // kludge has been set if the symbol could be a function
943   symIter.reset();
944   while (symIter.next(symString, lookUp)) {
945     if (funcsByAddr.defines(lookUp.addr())) {
946       // This function has been defined
947       ;
948     } else if ((lookUp.type() == Symbol::PDST_OBJECT) && lookUp.kludge()) {
949       //logLine(P_strdup(symString.string_of()));
950       pd_Function *pdf;
951       addInternalSymbol(lookUp.name(), lookUp.addr());
952       if (defineFunction(dyn, lookUp, TAG_LIB_FUNC, pdf)) {
953           assert(pdf); mdlLib += pdf;
954       }
955     }
956   }
957   return true;
958
959
960
961 bool image::addAllVariables()
962 {
963 /* Eventually we'll have to do this on all platforms (because we'll retrieve
964  * the type information here).
965  */
966 #ifdef i386_unknown_nt4_0
967   string mangledName; 
968   Symbol symInfo;
969   SymbolIter symIter(linkedFile);
970
971   while (symIter.next(mangledName, symInfo)) {
972     if (symInfo.type() == Symbol::PDST_OBJECT) {
973       char *name = cplus_demangle((char *)mangledName.string_of(), 0);
974       const char *unmangledName;
975       if (name) unmangledName = name;
976       else unmangledName = mangledName.string_of();
977       if (varsByPretty.defines(unmangledName)) {
978           *(varsByPretty[unmangledName]) += string(mangledName);
979       } else {
980           vector<string> *varEntry = new vector<string>;
981           *varEntry += string(mangledName);
982           varsByPretty[unmangledName] = varEntry;
983       }
984       if (name) free(name);
985     }
986   }
987 #endif
988   return true;
989 }
990
991 int symCompare(const void *s1, const void *s2) {
992   const Symbol *sym1 = (const Symbol*)s1, *sym2 = (const Symbol*)s2;
993   // TODO mdc
994   return (sym1->addr() - sym2->addr());
995 }
996
997
998 unsigned int_addrHash(const unsigned &addr) {
999   return addr;
1000 }
1001
1002 // Please note that this is now machine independent-almost.  Let us keep it that way
1003 // 
1004 image::image(const string &fileName, bool &err)
1005 :   funcsByAddr(addrHash4),
1006     modsByFileName(string::hash),
1007     modsByFullName(string::hash),
1008     file_(fileName),
1009     linkedFile(fileName, pd_log_perror),
1010     iSymsMap(string::hash),
1011     funcsByPretty(string::hash),
1012     varsByPretty(string::hash),
1013     knownJumpTargets(int_addrHash, 8192)
1014 {
1015 sharedobj_cerr << "image::image for non-sharedobj; file name=" << file_ << endl;
1016
1017   codeOffset_ = linkedFile.code_off();
1018   dataOffset_ = linkedFile.data_off();
1019   codeLen_ = linkedFile.code_len();
1020   dataLen_ = linkedFile.data_len();
1021
1022 #if defined(hppa1_1_hp_hpux)
1023   unwind   = linkedFile.unwind;
1024 #endif
1025
1026   if (!codeLen_ || !linkedFile.code_ptr()) {
1027     string msg = string("Unable to open executable file: ") + fileName;
1028     statusLine(msg.string_of());
1029
1030     msg += "\n";
1031     logLine(msg.string_of());
1032
1033     err = true;
1034
1035     showErrorCallback(27, msg); 
1036     return;
1037   }
1038
1039 #if !defined(i386_unknown_nt4_0) && !defined(USES_LIBDYNINSTRT_SO)
1040   Symbol version;
1041   if (!linkedFile.get_symbol("DYNINSTversion", version) &&
1042       !linkedFile.get_symbol("_DYNINSTversion", version)) {
1043     statusLine("Could not find version number in instrumentation\n");
1044     showErrorCallback(33, "Could not find version number in instrumentation");
1045     err = true;
1046     return;
1047   }
1048
1049   Word version_number = get_instruction(version.addr());
1050   if (version_number != 1) {
1051     string msg;
1052     msg = string("Incorrect version number, expected ") + string(1) + 
1053           string("found ") + string(version_number);
1054     statusLine(msg.string_of());
1055     showErrorCallback(30, msg);
1056     err = true;
1057     return;
1058   }
1059 #endif
1060
1061   const char *nm = fileName.string_of();
1062   const char *pos = P_strrchr(nm, '/');
1063
1064   err = false;
1065   if (pos)
1066     name_ = pos + 1;
1067   else
1068     name_ = fileName;
1069
1070   // find the "user" code boundaries
1071   statusLine("finding user code boundaries");
1072   Address startUserAddr=0, endUserAddr=0;
1073   bool startBound = findStartSymbol(linkedFile, startUserAddr);
1074   bool endBound = findEndSymbol(linkedFile, endUserAddr);
1075
1076   // use the *DUMMY_MODULE* until a module is defined
1077   pdmodule *dynModule = newModule(DYN_MODULE, 0);
1078   pdmodule *libModule = newModule(LIBRARY_MODULE, 0);
1079   // TODO -- define inst points in define function ?
1080
1081   // The functions cannot be verified until all of them have been seen
1082   // because calls out of each function must be tagged as calls to user
1083   // functions or call to "library" functions
1084
1085   Symbol lookUp;
1086   string symString;
1087   SymbolIter symIter(linkedFile);
1088
1089   // sort the modules by address into a vector to allow a binary search to 
1090   // determine the module that a symbol will map to -- this may be bsd specific
1091   vector<Symbol> mods;
1092
1093   while (symIter.next(symString, lookUp)) {
1094
1095     if (lookUp.type() == Symbol::PDST_MODULE) {
1096       const string &lookUpName = lookUp.name();
1097       const char *str = lookUpName.string_of();
1098       assert(str);
1099       int ln = lookUpName.length();
1100
1101       // directory definition -- ignored for now
1102       if (str[ln-1] != '/')
1103         mods += lookUp;
1104     }
1105   }
1106
1107   // sort the modules by address
1108   statusLine("sorting modules");
1109   mods.sort(symCompare);
1110 //  assert(mods.sorted(symCompare));
1111
1112   // remove duplicate entries -- some .o files may have the same address as .C files
1113   // kludge is true for module symbols that I am guessing are modules
1114   vector<Symbol> uniq;
1115   unsigned loop=0;
1116
1117   // must use loop+1 not mods.size()-1 since it is an unsigned compare
1118   //  which could go negative - jkh 5/29/95
1119   for (loop=0; loop < mods.size(); loop++) {
1120     if ((loop+1 < mods.size()) && 
1121         (mods[loop].addr() == mods[loop+1].addr())) {
1122       if (!mods[loop].kludge())
1123         mods[loop+1] = mods[loop];
1124     } else
1125       uniq += mods[loop];
1126   }
1127
1128   // define all of the functions
1129   statusLine("winnowing functions");
1130   if (!addAllFunctions(uniq, libModule, dynModule, startBound, startUserAddr,
1131                        endBound, endUserAddr)) {
1132     err = true;
1133     return;
1134   }
1135
1136   // XXX should have a statusLine("retrieving variable information") here,
1137   //     but it's left out for now since addAllVariables only does something
1138   //     when BPATCH_LIBRARY is defined
1139   addAllVariables();
1140
1141   statusLine("checking call points");
1142   checkAllCallPoints();
1143
1144 //  statusLine("ready"); // this shouldn't be here, right? (cuz we're not really ready)
1145
1146   // TODO -- remove duplicates -- see earlier note
1147   dictionary_hash<unsigned, unsigned> addr_dict(uiHash);
1148   vector<pd_Function*> temp_vec;
1149   unsigned f_size = mdlLib.size(), index;
1150   for (index=0; index<f_size; index++) {
1151     const unsigned the_address = (unsigned)mdlLib[index]->getAddress(0);
1152     if (!addr_dict.defines(the_address)) {
1153       addr_dict[the_address] = 1;
1154       temp_vec += mdlLib[index];
1155     }
1156   }
1157   mdlLib = temp_vec;
1158   temp_vec.resize(0); addr_dict.clear();
1159   f_size = mdlNormal.size();
1160   for (index=0; index<f_size; index++) {
1161     const unsigned the_address = (unsigned)mdlNormal[index]->getAddress(0);
1162     if (!addr_dict.defines(the_address)) {
1163       addr_dict[the_address] = 1;
1164       temp_vec += mdlNormal[index];
1165     }
1166   }
1167   mdlNormal = temp_vec;
1168 }
1169
1170 // 
1171 // load a shared object
1172 //
1173 image::image(const string &fileName, u_int baseAddr, bool &err)
1174 :   funcsByAddr(addrHash4),
1175     modsByFileName(string::hash),
1176     modsByFullName(string::hash),
1177     file_(fileName),
1178     linkedFile(fileName, baseAddr,pd_log_perror),
1179     iSymsMap(string::hash),
1180     funcsByPretty(string::hash),
1181     varsByPretty(string::hash),
1182     knownJumpTargets(int_addrHash, 8192)
1183 {
1184 sharedobj_cerr << "welcome to image::image for shared obj; file name=" << file_ << endl;
1185
1186   codeOffset_ = linkedFile.code_off();
1187   dataOffset_ = linkedFile.data_off();
1188   codeLen_ = linkedFile.code_len();
1189   dataLen_ = linkedFile.data_len();
1190   //logLine("IN image::image\n");
1191
1192 #if defined(hppa1_1_hp_hpux)
1193   unwind   = linkedFile.unwind;
1194 #endif
1195
1196   if (!codeLen_ || !linkedFile.code_ptr()) {
1197     string msg = string("Unable to open shared object file: ") + fileName;
1198     statusLine(msg.string_of());
1199     
1200     msg += "\n";
1201     logLine(msg.string_of());
1202
1203     err = true;
1204     showErrorCallback(27, msg); 
1205
1206     assert(false);
1207
1208     return;
1209   }
1210   else {
1211     string msg = string("Parsing shared object file: ") + fileName;
1212     statusLine(msg.string_of());
1213   }
1214
1215   const char *nm = fileName.string_of();
1216   const char *pos = P_strrchr(nm, '/');
1217
1218   err = false;
1219   if (pos)
1220     name_ = pos + 1;
1221   else
1222     name_ = fileName;
1223
1224   // use the *DUMMY_MODULE* until a module is defined
1225   pdmodule *dynModule = newModule(DYN_MODULE, 0);
1226   pdmodule *libModule = newModule(LIBRARY_MODULE, 0);
1227   // TODO -- define inst points in define function ?
1228
1229   // The functions cannot be verified until all of them have been seen
1230   // because calls out of each function must be tagged as calls to user
1231   // functions or call to "library" functions
1232
1233   Symbol lookUp;
1234   string symString;
1235   SymbolIter symIter(linkedFile);
1236
1237   // sort the modules by address into a vector to allow a binary search to 
1238   // determine the module that a symbol will map to -- this may be bsd specific
1239   vector<Symbol> mods;
1240
1241   while (symIter.next(symString, lookUp)) {
1242
1243     if (lookUp.type() == Symbol::PDST_MODULE) {
1244       const char *str = (lookUp.name()).string_of();
1245       assert(str);
1246       int ln = P_strlen(str);
1247
1248       // directory definition -- ignored for now
1249       if (str[ln-1] != '/')
1250         mods += lookUp;
1251       // string temp = string("NEW MODULE: ");
1252       // temp += lookUp.name();
1253       // temp += string("\n");
1254       // logLine(P_strdup(temp.string_of()));
1255     }
1256   }
1257
1258   // sort the modules by address
1259   mods.sort(symCompare);
1260 //  assert(mods.sorted(symCompare));
1261
1262   // remove duplicate entries -- some .o files may have the same address as .C files
1263   // kludge is true for module symbols that I am guessing are modules
1264   vector<Symbol> uniq;
1265   unsigned loop=0;
1266
1267   // must use loop+1 not mods.size()-1 since it is an unsigned compare
1268   //  which could go negative - jkh 5/29/95
1269   for (loop=0; loop < mods.size(); loop++) {
1270     if ((loop+1 < mods.size()) && 
1271          (mods[loop].addr() == mods[loop+1].addr())) {
1272       if (!mods[loop].kludge())
1273         mods[loop+1] = mods[loop];
1274     } else
1275       uniq += mods[loop];
1276   }
1277
1278   // define all of the functions
1279   if (!addAllSharedObjFunctions(uniq, libModule, dynModule)) {
1280     err = true;
1281     return;
1282   }
1283   checkAllCallPoints();
1284
1285   // TODO -- remove duplicates -- see earlier note
1286   dictionary_hash<unsigned, unsigned> addr_dict(uiHash);
1287   vector<pd_Function*> temp_vec;
1288   unsigned f_size = mdlLib.size(), index;
1289   for (index=0; index<f_size; index++) {
1290     const unsigned the_address = (unsigned)mdlLib[index]->getAddress(0);
1291     if (!addr_dict.defines(the_address)) {
1292       addr_dict[the_address] = 1;
1293       temp_vec += mdlLib[index];
1294     }
1295   }
1296   mdlLib = temp_vec;
1297   temp_vec.resize(0); addr_dict.clear();
1298   f_size = mdlNormal.size();
1299   for (index=0; index<f_size; index++) {
1300     const unsigned the_address = (unsigned)mdlNormal[index]->getAddress(0);
1301     if (!addr_dict.defines(the_address)) {
1302       addr_dict[the_address] = 1;
1303       temp_vec += mdlNormal[index];
1304     }
1305   }
1306   mdlNormal = temp_vec;
1307
1308 }
1309
1310
1311 void pdmodule::checkAllCallPoints() {
1312   unsigned fsize = funcs.size();
1313   for (unsigned f=0; f<fsize; f++)
1314       funcs[f]->checkCallPoints();
1315 }
1316
1317
1318 void image::checkAllCallPoints() {
1319   dictionary_hash_iter<string, pdmodule*> di(modsByFullName);
1320   string s; pdmodule *mod;
1321   while (di.next(s, mod))
1322     mod->checkAllCallPoints();
1323 }
1324
1325 // passing in tags allows a function to be tagged as TAG_LIB_FUNC even
1326 // if its entry is not in the tag dictionary of known functions
1327 bool image::defineFunction(pdmodule *use, const Symbol &sym, const unsigned tags,
1328                            pd_Function *&retFunc) {
1329   // We used to skip a leading underscore, but not anymore.
1330   // (I forgot why we ever did in the first place)
1331
1332   unsigned dictTags = findTags(sym.name());
1333   return (newFunc(use, sym.name(), sym.addr(), sym.size(), tags | dictTags, retFunc));
1334 }
1335
1336 pdmodule *image::getOrCreateModule(const string &modName, 
1337                                       const Address modAddr) {
1338   const char *str = modName.string_of();
1339   int len = modName.length();
1340   assert(len>0);
1341
1342   // TODO ignore directory definitions for now
1343   if (str[len-1] == '/') {
1344     return NULL;
1345   } else {
1346     // TODO - navigate ".." and "."
1347     const char *lastSlash = P_strrchr(str, '/');
1348     if (lastSlash)
1349       return (newModule(++lastSlash, modAddr));
1350     else
1351       return (newModule(modName, modAddr));
1352   }
1353 }
1354
1355 // KLUDGE TODO - internal functions are tagged with TAG_LIB_FUNC
1356 // but they won't have tags in the tag dict, so this happens...
1357 bool image::defineFunction(pdmodule *libModule, const Symbol &sym,
1358                            const string &modName, const Address modAddr,
1359                            pd_Function *&retFunc) {
1360
1361   // We used to skip a leading underscore, but not any more.
1362
1363   unsigned tags = findTags(sym.name());
1364
1365   if (TAG_LIB_FUNC & tags)
1366     return (newFunc(libModule, sym.name(), sym.addr(), sym.size(),
1367                     tags | TAG_LIB_FUNC, retFunc));
1368   else {
1369     pdmodule *use = getOrCreateModule(modName, modAddr);
1370     assert(use);
1371     return (newFunc(use, sym.name(), sym.addr(), sym.size(), tags, retFunc));
1372   }
1373 }
1374
1375 // Verify that this is code
1376 // Find the call points
1377 // Find the return address
1378 // TODO -- use an instruction object to remove
1379 // Sets err to false on error, true on success
1380 //
1381 // Note - this must define funcEntry and funcReturn
1382 // 
1383 pd_Function::pd_Function(const string &symbol, const string &pretty, 
1384                        pdmodule *f, Address adr, const unsigned size, 
1385                        const unsigned tg, const image *owner, bool &err) : 
1386   function_base(symbol, pretty, adr, size,tg),
1387   file_(f),
1388   funcEntry_(0),
1389   relocatable_(false)
1390 {
1391   err = findInstPoints(owner) == false;
1392 }
1393