BPatch functions that block are now locked (on a finer grain than the rest of the...
[dyninst.git] / dyninstAPI / src / BPatch_module.C
1 /*
2  * Copyright (c) 1996-2004 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 <ctype.h>
44
45 #define BPATCH_FILE
46
47 #include "process.h"
48 #include "symtab.h"
49 #include "showerror.h"
50 #include "BPatch.h"
51 #include "BPatch_module.h"
52 #include "BPatch_snippet.h" // For BPatch_function; remove if we move it
53 #include "BPatch_collections.h"
54 #include "common/h/String.h"
55 #include "BPatch_typePrivate.h"    // For BPatch_type related stuff
56 #include "BPatch_Vector.h"
57
58 #if defined(TIMED_PARSE)
59 #include <sys/time.h>
60 #endif
61 #ifdef TIMED_PARSE
62 int max_addr_per_line =0;
63 int max_line_per_addr =0;
64 #endif
65
66 #if defined(USES_DWARF_DEBUG)
67 #include "elf.h"
68 #include "dwarf.h"
69 #include "libdwarf.h"
70 #endif
71
72
73 //char * BPatch_module::current_func_name = NULL;
74 //char * BPatch_module::current_mangled_func_name = NULL;
75 //BPatch_function * BPatch_module::current_func = NULL;
76 char * current_func_name = NULL;
77 char * current_mangled_func_name = NULL;
78 BPatch_function *current_func = NULL;
79
80
81 /*
82  * BPatch_module::getSourceObj()
83  *
84  * Return the contained source objects (e.g. functions).
85  *
86  */
87 bool BPatch_module::getSourceObj(BPatch_Vector<BPatch_sourceObj *> &vect)
88 {
89     BPatch_Vector<BPatch_function *> *temp;
90     temp = getProcedures();
91     if (temp) {
92        vect = *(BPatch_Vector<BPatch_sourceObj *> *) temp;
93        return true;
94     } else {
95        return false;
96     }
97 }
98
99 /*
100  * BPatch_function::getObjParent()
101  *
102  * Return the parent of the function (i.e. the image)
103  *
104  */
105 BPatch_sourceObj *BPatch_module::getObjParent()
106 {
107     return (BPatch_sourceObj *) img;
108 }
109
110 /* XXX temporary */
111 char *BPatch_module::getNameInt(char *buffer, int length)
112 {
113     pdstring str = mod->fileName();
114
115     strncpy(buffer, str.c_str(), length);
116
117     return buffer;
118 }
119
120 const char *BPatch_module::libraryNameInt()
121 {
122    if (isSharedLib())      
123       return mod->fullName().c_str();
124    return NULL;
125 }
126
127 char *BPatch_module::getFullNameInt(char *buffer, int length)
128 {
129     pdstring str = mod->fullName();
130
131     strncpy(buffer, str.c_str(), length);
132
133     return buffer;
134 }
135
136
137 BPatch_module::BPatch_module( process *_proc, pdmodule *_mod,BPatch_image *_img ) :
138     proc( _proc ), mod( _mod ), img( _img ), BPfuncs( NULL ), BPfuncs_uninstrumentable( NULL )    
139 {
140 #if defined(TIMED_PARSE)
141         struct timeval starttime;
142         gettimeofday(&starttime, NULL);
143 #endif
144
145         _srcType = BPatch_sourceModule;
146         nativeCompiler = _mod->exec()->isNativeCompiler();
147
148         switch(mod->language()) {
149                 case lang_C:
150                         setLanguage( BPatch_c );
151                         break;
152                         
153                 case lang_CPlusPlus:
154                 case lang_GnuCPlusPlus:
155                         setLanguage( BPatch_cPlusPlus );
156                         break;
157                         
158                 case lang_Fortran_with_pretty_debug:
159                         setLanguage( BPatch_f90_demangled_stabstr );
160                         break;
161                         
162                 case lang_Fortran:
163                 case lang_CMFortran:
164                         setLanguage( BPatch_fortran );
165                         break;
166                         
167                 case lang_Assembly:
168                         setLanguage( BPatch_assembly );
169                         break;
170
171                 case lang_Unknown: 
172                 default:
173                         setLanguage( BPatch_unknownLanguage );
174                         break;
175         } /* end language switch */
176
177         pdvector< int_function * > * functions = mod->getFunctions();
178         for( unsigned int i = 0; i < functions->size(); i++ ) {
179           /* The bpfs for a shared object module won't have been built by now,
180              but generating them on the fly is OK because each .so is a single module
181              for our purposes. */
182           int_function * function = ( * functions )[i];
183           if(!proc->PDFuncToBPFuncMap.defines( function )) {
184             if (!BPatch::bpatch->delayedParsingOn()) {
185               // We're not delaying and there's no function. Make one.
186               BPatch_function *bpf = new BPatch_function(proc, function, this);
187               assert( bpf != NULL );
188               proc->PDFuncToBPFuncMap[ function ] = bpf;
189             }
190           }
191           else {
192             // There's a function... make sure we're its module
193             proc->PDFuncToBPFuncMap[function]->setModule(this);
194           }
195         }
196         moduleTypes = NULL;
197         parseTypesIfNecessary();
198
199 #if defined(TIMED_PARSE)
200     struct timeval endtime;
201     gettimeofday(&endtime, NULL);
202     unsigned long lstarttime = starttime.tv_sec * 1000 * 1000 + starttime.tv_usec;
203     unsigned long lendtime = endtime.tv_sec * 1000 * 1000 + endtime.tv_usec;
204     unsigned long difftime = lendtime - lstarttime;
205     double dursecs = difftime/(1000 );
206     cout << __FILE__ << ":" << __LINE__ <<": BPatch_module("<< mod->fileName()
207          <<") took "<<dursecs <<" msecs" << endl;
208 #endif
209 } /* end BPatch_module() */
210
211 BPatch_module::~BPatch_module()
212 {
213   if (moduleTypes) delete moduleTypes;
214
215     for (unsigned int f = 0; f < BPfuncs->size(); f++) {
216         delete (*BPfuncs)[f];
217     }
218     delete BPfuncs;
219
220     if (BPfuncs_uninstrumentable) {
221       for (unsigned int f = 0; f < BPfuncs_uninstrumentable->size(); f++) {
222         delete (*BPfuncs_uninstrumentable)[f];
223       }
224       delete BPfuncs_uninstrumentable;
225     }    
226 }
227
228 void BPatch_module::parseTypesIfNecessary() {
229   if (moduleTypes) return;
230
231   moduleTypes = new BPatch_typeCollection;
232 #if ! defined( mips_sgi_irix6_4 )
233   if( BPatch::bpatch->parseDebugInfo() ) {
234 #if defined( rs6000_ibm_aix4_1 ) || defined( alpha_dec_osf4_0 ) || defined( i386_unknown_nt4_0 )
235     /* These platforms don't have 2-phase parsing, so init
236        LineInformation and assume that parseTypes() fills it in. */
237     mod->initLineInformation();
238     parseTypes();
239     mod->cleanupLineInformation();
240 #else
241     parseTypes();
242 #endif
243   } /* end if we're supposed to parse debug information */
244   else {
245     cerr        << __FILE__ << __LINE__ << ":  WARNING:  skipping parse of debug info for " 
246                 << mod->fileName() << endl;
247   } /* end if we're not supposed to parse debug information */
248 #endif /* ! defined( mips_sgi_irix6_4 ) */
249 }
250
251 BPatch_typeCollection *BPatch_module::getModuleTypesInt() {
252   parseTypesIfNecessary();
253   return moduleTypes;
254 }
255
256 /*
257  * BPatch_module::getProcedures
258  *
259  * Returns a list of all procedures in the module upon success, and NULL
260  * upon failure.
261  */
262 BPatch_Vector<BPatch_function *> *
263 BPatch_module::getProceduresInt(bool incUninstrumentable)
264 {
265     if (BPfuncs) return BPfuncs;
266     
267     BPfuncs = new BPatch_Vector<BPatch_function *>;
268
269     if (BPfuncs == NULL) return NULL;
270
271     pdvector<int_function *> *funcs = mod->getFunctions();
272
273     for (unsigned int f = 0; f < funcs->size(); f++)
274       if (incUninstrumentable ||
275           (*funcs)[f]->isInstrumentable()) 
276         BPfuncs->push_back(
277                            proc->findOrCreateBPFunc((int_function*)(*funcs)[f], this));
278     
279     return BPfuncs;
280 }
281
282 /*
283  * BPatch_module::findFunction
284  *
285  * Returns a vector of BPatch_function* with the same name that is provided or
286  * NULL if no function with that name is in the module.  This function
287  * searches the BPatch_function vector of the module followed by
288  * the int_function of the module.  If a int_function is found, then
289  * a BPatch_function is created and added to the BPatch_function vector of
290  * the module.
291  * name The name of function to look up.
292  */
293
294 BPatch_Vector<BPatch_function *> *
295 BPatch_module::findFunctionInt(const char *name, 
296         BPatch_Vector<BPatch_function *> & funcs,
297         bool notify_on_failure, bool regex_case_sensitive,
298         bool incUninstrumentable, bool dont_use_regex)
299 {
300   pdvector<int_function *> pdfuncs;
301
302   if (!name) {
303     char msg[512];
304     sprintf(msg, "%s[%d]:  Module %s: findFunction(NULL)...  failing",
305            __FILE__, __LINE__, mod->fileName().c_str());
306     BPatch_reportError(BPatchSerious, 100, msg);
307     return NULL;
308   }
309
310   if ((mod->findFunctionFromAll(pdstring(name), &pdfuncs, 
311              regex_case_sensitive, dont_use_regex) == NULL) || 
312       !pdfuncs.size())
313   {
314      if(notify_on_failure) {
315        char msg[1024];
316        sprintf(msg, "%s[%d]:  Module %s: unable to find function %s",
317                __FILE__, __LINE__, mod->fileName().c_str(), name);
318        BPatch_reportError(BPatchSerious, 100, msg);
319
320      }
321      return NULL;
322   } 
323   
324   // found function(s), translate to BPatch_functions  
325   for (unsigned int i = 0; i < pdfuncs.size(); ++i) {
326      if (incUninstrumentable || pdfuncs[i]->isInstrumentable()) 
327      {
328         BPatch_function * bpfunc = proc->findOrCreateBPFunc(pdfuncs[i], this);
329         funcs.push_back(bpfunc);
330         if (!proc->PDFuncToBPFuncMap.defines(pdfuncs[i])) {
331            this->BPfuncs->push_back(bpfunc);
332         }
333      }
334   }
335
336   return & funcs;
337 }
338
339 /* The implementation of this function is incomplete.
340  * Eventually, it should accept any address and return the BPatch_functions
341  * which contain that address.
342  *
343  * For now, it only works on entry addresses.
344  */
345
346 BPatch_Vector<BPatch_function *> *
347 BPatch_module::findFunctionByAddressInt(void *addr, BPatch_Vector<BPatch_function *> &funcs,
348                                      bool notify_on_failure, 
349                                      bool incUninstrumentable)
350 {
351   int_function *pdfunc = NULL;
352   BPatch_function *bpfunc = NULL;
353
354   pdfunc = mod->exec()->findFuncByEntry((Address)addr);
355   if (!pdfunc) {
356     if (notify_on_failure) {
357       char msg[1024];
358       sprintf(msg, "%s[%d]:  Module %s: unable to find function %p",
359              __FILE__, __LINE__, mod->fileName().c_str(), addr);
360       BPatch_reportError(BPatchSerious, 100, msg);
361     }
362     return NULL;
363   }
364   if (incUninstrumentable ||
365       pdfunc->isInstrumentable()) {
366     bpfunc = proc->findOrCreateBPFunc(pdfunc, this);
367     if (bpfunc) {
368       funcs.push_back(bpfunc);
369       if (!proc->PDFuncToBPFuncMap.defines(pdfunc))
370         this->BPfuncs->push_back(bpfunc);
371     }
372   }
373   return &funcs;
374 }
375
376 BPatch_function * BPatch_module::findFunctionByMangledInt(const char *mangled_name,
377                                                        bool incUninstrumentable)
378 {
379   BPatch_function *bpfunc = NULL;
380
381   int_function *pdfunc = mod->findFunctionByMangled(pdstring(mangled_name));
382
383   if (!pdfunc) return NULL;
384
385   if (incUninstrumentable ||
386       pdfunc->isInstrumentable()) {
387     bpfunc = proc->findOrCreateBPFunc((int_function *)pdfunc, this);
388     if (!proc->PDFuncToBPFuncMap.defines(pdfunc)) {
389       this->BPfuncs->push_back(bpfunc);
390     }
391   }
392
393   return bpfunc;
394 }
395
396 bool BPatch_module::dumpMangledInt(char * prefix)
397 {
398   mod->dumpMangled(prefix);
399   return true;
400 }
401
402 extern char *parseStabString(BPatch_module *, int linenum, char *str, 
403         int fPtr, BPatch_typeCommon *commonBlock = NULL);
404
405
406 #if defined(rs6000_ibm_aix4_1)
407
408 #include <linenum.h>
409 #include <syms.h>
410
411 // Gets the stab and stabstring section and parses it for types
412 // and variables
413 void BPatch_module::parseTypes()
414 {
415
416     int i, j;
417     int nlines;
418     int nstabs;
419     char* lines;
420     SYMENT *syms;
421     SYMENT *tsym;
422     char *stringPool;
423     char tempName[9];
424     char *stabstr=NULL;
425     union auxent *aux;
426     image * imgPtr=NULL;
427     char* funcName = NULL;
428     Address staticBlockBaseAddr;
429     unsigned long linesfdptr;
430     BPatch_typeCommon *commonBlock = NULL;
431     BPatch_variableExpr *commonBlockVar;
432     pdstring* currentSourceFile = NULL;
433     bool inCommonBlock = false;
434
435 #if defined(TIMED_PARSE)
436   struct timeval starttime;
437   gettimeofday(&starttime, NULL);
438 #endif
439
440     imgPtr = mod->exec();
441
442     const Object &objPtr = imgPtr->getObject();
443
444     //Using the Object to get the pointers to the .stab and .stabstr
445     objPtr.get_stab_info(stabstr, nstabs, ((Address&) syms), stringPool); 
446
447     this->BPfuncs = this->getProcedures();
448
449
450     objPtr.get_line_info(nlines,lines,linesfdptr); 
451
452     bool parseActive = true;
453     for (i=0; i < nstabs; i++) {
454       /* do the pointer addition by hand since sizeof(struct syment)
455        *   seems to be 20 not 18 as it should be */
456       SYMENT *sym = (SYMENT *) (((unsigned) syms) + i * SYMESZ);
457       // SYMENT *sym = (SYMENT *) (((unsigned) syms) + i * sizeof(struct syment));
458
459
460       if (sym->n_sclass == C_FILE) {
461          char *moduleName;
462          if (!sym->n_zeroes) {
463             moduleName = &stringPool[sym->n_offset];
464          } else {
465             memset(tempName, 0, 9);
466             strncpy(tempName, sym->n_name, 8);
467             moduleName = tempName;
468          }
469          /* look in aux records */
470          for (j=1; j <= sym->n_numaux; j++) {
471             aux = (union auxent *) ((char *) sym + j * SYMESZ);
472             if (aux->x_file._x.x_ftype == XFT_FN) {
473                 if (!aux->x_file._x.x_zeroes) {
474                      moduleName = &stringPool[aux->x_file._x.x_offset];
475                 } else {
476                      // x_fname is 14 bytes
477                      memset(moduleName, 0, 15);
478                      strncpy(moduleName, aux->x_file.x_fname, 14);
479                 }
480             }
481          }
482
483          if(currentSourceFile) delete currentSourceFile;
484          currentSourceFile = new pdstring(moduleName);
485          currentSourceFile = mod->processDirectories(currentSourceFile);
486
487          if (strrchr(moduleName, '/')) {
488              moduleName = strrchr(moduleName, '/');
489              moduleName++;
490          }
491
492          if (!strcmp(moduleName, mod->fileName().c_str())) {
493                 parseActive = true;
494                 // Clear out old types
495                 moduleTypes->clearNumberedTypes();
496          } else {
497                 parseActive = false;
498          }
499       }
500
501       if (!parseActive) continue;
502
503       char *nmPtr;
504       if (!sym->n_zeroes && ((sym->n_sclass & DBXMASK) ||
505                              (sym->n_sclass == C_BINCL) ||
506                              (sym->n_sclass == C_EINCL))) {
507           if (sym->n_offset < 3) {
508               if (sym->n_offset == 2 && stabstr[0]) {
509                   nmPtr = &stabstr[0];
510               } else {
511                   nmPtr = &stabstr[sym->n_offset];
512               }
513           } else if (!stabstr[sym->n_offset-3]) {
514               nmPtr = &stabstr[sym->n_offset];
515           } else {
516               /* has off by two error */
517               nmPtr = &stabstr[sym->n_offset-2];
518           }
519 #ifdef notdef
520           bperr("using nmPtr = %s\n", nmPtr);
521           bperr("got n_offset = (%d) %s\n", sym->n_offset, &stabstr[sym->n_offset]);
522           if (sym->n_offset>=2) 
523               bperr("got n_offset-2 = %s\n", &stabstr[sym->n_offset-2]);
524           if (sym->n_offset>=3) 
525               bperr("got n_offset-3 = %x\n", stabstr[sym->n_offset-3]);
526           if (sym->n_offset>=4) 
527               bperr("got n_offset-4 = %x\n", stabstr[sym->n_offset-4]);
528 #endif
529       } else {
530           // names 8 or less chars on inline, not in stabstr
531           memset(tempName, 0, 9);
532           strncpy(tempName, sym->n_name, 8);
533           nmPtr = tempName;
534       }
535
536       if ((sym->n_sclass == C_BINCL) ||
537           (sym->n_sclass == C_EINCL) ||
538           (sym->n_sclass == C_FUN)) {
539                 if (funcName) { 
540                     free(funcName);
541                     funcName = NULL;
542                 }
543                 funcName = strdup(nmPtr);
544
545                 mod->parseLineInformation(proc, currentSourceFile, 
546                                           funcName, sym,
547                                           linesfdptr, lines, nlines);
548       }
549
550       if (sym->n_sclass & DBXMASK) {
551           if (sym->n_sclass == C_BCOMM) {
552               char *commonBlockName;
553
554               inCommonBlock = true;
555               commonBlockName = nmPtr;
556
557               // find the variable for the common block
558               BPatch_image *progam = (BPatch_image *) getObjParent();
559               
560               commonBlockVar = progam->findVariable(commonBlockName);
561               if (!commonBlockVar) {
562                   bperr("unable to find variable %s\n", commonBlockName);
563               } else {
564                   commonBlock = 
565                       dynamic_cast<BPatch_typeCommon *>(const_cast<BPatch_type *> (commonBlockVar->getType()));
566                   if (commonBlock == NULL) {
567                       // its still the null type, create a new one for it
568                       commonBlock = new BPatch_typeCommon(commonBlockName);
569                       commonBlockVar->setType(commonBlock);
570                       moduleTypes->addGlobalVariable(commonBlockName, commonBlock);
571                   }
572                   // reset field list
573                   commonBlock->beginCommonBlock();
574               }
575           } else if (sym->n_sclass == C_ECOMM) {
576              inCommonBlock = false;
577              if (commonBlock == NULL)
578                 continue;
579
580               // copy this set of fields
581             BPatch_Vector<BPatch_function *> bpmv;
582             if (NULL == findFunction(funcName, bpmv) || !bpmv.size()) {
583               bperr("unable to locate current function %s\n", funcName);
584               } else {
585                 BPatch_function *func = bpmv[0];
586                 commonBlock->endCommonBlock(func, commonBlockVar->getBaseAddr());
587               }
588
589               // update size if needed
590               if (commonBlockVar)
591                   commonBlockVar->setSize(commonBlock->getSize());
592               commonBlockVar = NULL;
593               commonBlock = NULL;
594           } else if (sym->n_sclass == C_BSTAT) {
595               char *staticName, tempName[9];
596               // begin static block
597               // find the variable for the common block
598               tsym = (SYMENT *) (((unsigned) syms) + sym->n_value * SYMESZ);
599
600               // We can't lookup the value by name, because the name might have been
601               // redefined later on (our lookup would then pick the last one)
602
603               // Since this whole function is AIX only, we're ok to get this info
604
605               staticBlockBaseAddr = tsym->n_value + mod->exec()->getObject().data_reloc();
606
607               /*
608               if (!tsym->n_zeroes) {
609                   staticName = &stringPool[tsym->n_offset];
610               } else {
611                   memset(tempName, 0, 9);
612                   strncpy(tempName, tsym->n_name, 8);
613                   staticName = tempName;
614               }
615               BPatch_image *progam = (BPatch_image *) getObjParent();
616
617               BPatch_variableExpr *staticBlockVar = progam->findVariable(staticName);
618               if (!staticBlockVar) {
619                   bperr("unable to find static block %s\n", staticName);
620                   staticBlockBaseAddr = 0;
621               } else {
622                   staticBlockBaseAddr = (Address) staticBlockVar->getBaseAddr();
623               }
624               */
625
626           } else if (sym->n_sclass == C_ESTAT) {
627               staticBlockBaseAddr = 0;
628           }
629
630           // There's a possibility that we were parsing a common block that
631           // was never instantiated (meaning there's type info, but no
632           // variable info
633
634           if (inCommonBlock && commonBlock == NULL)
635              continue;
636
637           if (staticBlockBaseAddr && (sym->n_sclass == C_STSYM)) {
638               parseStabString(this, 0, nmPtr, 
639                   sym->n_value+staticBlockBaseAddr, commonBlock);
640           } else {
641               parseStabString(this, 0, nmPtr, sym->n_value, commonBlock);
642           }
643       }
644     }
645 #if defined(TIMED_PARSE)
646   struct timeval endtime;
647   gettimeofday(&endtime, NULL);
648   unsigned long lstarttime = starttime.tv_sec * 1000 * 1000 + starttime.tv_usec;
649   unsigned long lendtime = endtime.tv_sec * 1000 * 1000 + endtime.tv_usec;
650   unsigned long difftime = lendtime - lstarttime;
651   double dursecs = difftime/(1000 );
652   cout << __FILE__ << ":" << __LINE__ <<": parseTypes("<< mod->fileName()
653        <<") took "<<dursecs <<" msecs" << endl;
654 #endif
655 }
656
657 #endif
658
659 #if defined(sparc_sun_solaris2_4) \
660  || defined(i386_unknown_solaris2_5) \
661  || defined(i386_unknown_linux2_0) \
662  || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */ \
663  || defined(ia64_unknown_linux2_4)
664
665
666 void BPatch_module::parseTypes() 
667 {
668    image * moduleImage = mod->exec();
669    assert( moduleImage != NULL );
670    const Object & moduleObject = moduleImage->getObject();      
671
672    this->BPfuncs = this->getProcedures();
673   
674    if (moduleObject.hasStabInfo()) { 
675       parseStabTypes(); 
676    }
677         
678 #if defined( USES_DWARF_DEBUG )
679    if (moduleObject.hasDwarfInfo()) { 
680       parseDwarfTypes(); 
681    }
682 #endif
683
684
685
686 // parseStabTypes:  parses type and variable info, does some init
687 // does NOT parse file-line info anymore, this is done later, upon request.
688 void BPatch_module::parseStabTypes() 
689 {
690   stab_entry *stabptr;
691   const char *next_stabstr;
692
693   int i;
694   char *modName;
695   char * temp=NULL;
696   image * imgPtr=NULL;
697   char *ptr, *ptr2, *ptr3;
698   bool parseActive = false;
699
700   pdstring* currentFunctionName = NULL;
701   Address currentFunctionBase = 0;
702   BPatch_variableExpr *commonBlockVar = NULL;
703  char *commonBlockName;
704   BPatch_typeCommon *commonBlock = NULL;
705  int mostRecentLinenum = 0;
706
707 #if defined(TIMED_PARSE)
708   struct timeval starttime;
709   gettimeofday(&starttime, NULL);
710   unsigned int pss_count = 0;
711   double pss_dur = 0;
712   unsigned int src_count = 0;
713   double src_dur = 0;
714   unsigned int fun_count = 0;
715   double fun_dur = 0;
716   struct timeval t1, t2;
717 #endif
718
719   imgPtr = mod->exec();
720   imgPtr->analyzeIfNeeded();
721   const Object &objPtr = imgPtr->getObject();
722
723   //Using the Object to get the pointers to the .stab and .stabstr
724   // XXX - Elf32 specific needs to be in seperate file -- jkh 3/18/99
725   stabptr = objPtr.get_stab_info();
726   next_stabstr = stabptr->getStringBase();
727
728   for (i=0; i<stabptr->count(); i++) {
729     switch(stabptr->type(i)){
730     case N_UNDF: /* start of object file */
731       /* value contains offset of the next string table for next module */
732       // assert(stabptr->nameIdx(i) == 1);
733       stabptr->setStringBase(next_stabstr);
734       next_stabstr = stabptr->getStringBase() + stabptr->val(i);
735
736       //N_UNDF is the start of object file. It is time to 
737       //clean source file name at this moment.
738       /*
739       if(currentSourceFile){
740         delete currentSourceFile;
741         currentSourceFile = NULL;
742         delete absoluteDirectory;
743         absoluteDirectory = NULL;
744         delete currentFunctionName;
745         currentFunctionName = NULL;
746         currentFileInfo = NULL;
747         currentFuncInfo = NULL;
748       }
749       */
750       break;
751       
752     case N_ENDM: /* end of object file */
753       break;
754
755     case N_SO: /* compilation source or file name */
756       /* bperr("Resetting CURRENT FUNCTION NAME FOR NEXT OBJECT FILE\n");*/
757 #ifdef TIMED_PARSE
758       src_count++;
759       gettimeofday(&t1, NULL);
760 #endif
761       current_func_name = NULL; // reset for next object file
762       current_mangled_func_name = NULL; // reset for next object file
763       current_func = NULL;
764
765       modName = const_cast<char*>(stabptr->name(i));
766       // cerr << "checkpoint B" << endl;
767       ptr = strrchr(modName, '/');
768       //  cerr << "checkpoint C" << endl;
769       if (ptr) {
770         ptr++;
771         modName = ptr;
772       }
773
774       if (!strcmp(modName, mod->fileName().c_str())) {
775         parseActive = true;
776         moduleTypes->clearNumberedTypes();
777         BPatch_language lang;
778         // language should be set in the constructor, this is probably redundant
779         switch (stabptr->desc(i)) {
780         case N_SO_FORTRAN:
781           lang = BPatch_fortran;
782           break;
783           
784         case N_SO_F90:
785           lang = BPatch_fortran90;
786           break;
787           
788         case N_SO_AS:
789           lang = BPatch_assembly;
790           break;
791           
792         case N_SO_ANSI_C:
793         case N_SO_C:
794           lang = BPatch_c;
795           break;
796           
797         case N_SO_CC:
798           lang = BPatch_cPlusPlus;
799           break;
800           
801         default:
802           lang = BPatch_unknownLanguage;
803           break;
804         }
805         if (BPatch_f90_demangled_stabstr != getLanguage())
806           setLanguage(lang);
807       } else {
808         parseActive = false;
809       }
810
811 #ifdef TIMED_PARSE
812             gettimeofday(&t2, NULL);
813             src_dur += (t2.tv_sec - t1.tv_sec)*1000.0 + (t2.tv_usec - t1.tv_usec)/1000.0;
814             //src_dur += (t2.tv_sec/1000 + t2.tv_usec*1000) - (t1.tv_sec/1000 + t1.tv_usec*1000) ;
815 #endif
816             break;
817     case N_SLINE:
818       mostRecentLinenum = stabptr->desc(i);
819       break;
820     default:
821       break;
822     }
823
824
825     if(parseActive || mod->isShared()) {
826       BPatch_Vector<BPatch_function *> bpfv;
827       switch(stabptr->type(i)){
828       case N_FUN:
829 #ifdef TIMED_PARSE
830         fun_count++;
831         gettimeofday(&t1, NULL);
832 #endif
833         //all we have to do with function stabs at this point is to assure that we have
834         //properly set the var currentFunctionName for the later case of (parseActive)
835       current_func = NULL;
836       int currentEntry = i;
837       int funlen = strlen(stabptr->name(currentEntry));
838       ptr = new char[funlen+1];
839       strcpy(ptr, stabptr->name(currentEntry));
840       while(strlen(ptr) != 0 && ptr[strlen(ptr)-1] == '\\'){
841         ptr[strlen(ptr)-1] = '\0';
842         currentEntry++;
843         strcat(ptr,stabptr->name(currentEntry));
844       }
845
846       char* colonPtr = NULL;
847       if(currentFunctionName) delete currentFunctionName;
848       if(!ptr || !(colonPtr = strchr(ptr,':')))
849         currentFunctionName = NULL;
850       else {
851         char* tmp = new char[colonPtr-ptr+1];
852         strncpy(tmp,ptr,colonPtr-ptr);
853         tmp[colonPtr-ptr] = '\0';
854         currentFunctionName = new pdstring(tmp);
855
856         currentFunctionBase = 0;
857         Symbol info;
858
859         if (!proc->getSymbolInfo(*currentFunctionName,
860                                  info,currentFunctionBase))
861           {
862             pdstring fortranName = *currentFunctionName + pdstring("_");
863             if (proc->getSymbolInfo(fortranName,info,
864                                     currentFunctionBase))
865               {
866                 delete currentFunctionName;
867                 currentFunctionName = new pdstring(fortranName);
868               }
869           }
870         
871         currentFunctionBase += info.addr();
872
873         delete[] tmp;
874                 
875         //      if(currentSourceFile && (currentFunctionBase > 0)){
876         //      lineInformation->insertSourceFileName(
877         //                      *currentFunctionName,
878         //                      *currentSourceFile,
879         //                      &currentFileInfo,&currentFuncInfo);
880         //}
881       }
882       //  used to be a symbol lookup here to find currentFunctionBase, do we need it?
883       delete[] ptr;
884 #ifdef TIMED_PARSE
885       gettimeofday(&t2, NULL);
886       fun_dur += (t2.tv_sec - t1.tv_sec)*1000.0 + (t2.tv_usec - t1.tv_usec)/1000.0;
887       //fun_dur += (t2.tv_sec/1000 + t2.tv_usec*1000) - (t1.tv_sec/1000 + t1.tv_usec*1000);
888 #endif
889       break;
890       }
891     if (!parseActive) continue;
892
893     switch(stabptr->type(i)){
894       case N_BCOMM:     {
895         // begin Fortran named common block 
896         commonBlockName = const_cast<char*>(stabptr->name(i));
897
898         // find the variable for the common block
899         BPatch_image *progam = (BPatch_image *) getObjParent();
900         commonBlockVar = progam->findVariable(commonBlockName);
901         if (!commonBlockVar) {
902           bperr("unable to find variable %s\n", commonBlockName);
903         } else {
904           commonBlock = dynamic_cast<BPatch_typeCommon *>(const_cast<BPatch_type *> (commonBlockVar->getType()));
905           if (commonBlock == NULL) {
906             // its still the null type, create a new one for it
907             commonBlock = new BPatch_typeCommon(commonBlockName);
908             commonBlockVar->setType(commonBlock);
909             moduleTypes->addGlobalVariable(commonBlockName, commonBlock);
910           }
911           // reset field list
912           commonBlock->beginCommonBlock();
913         }
914         break;
915       }
916       
917       case N_ECOMM: {
918         // copy this set of fields
919         
920         assert(currentFunctionName);
921         if (NULL == findFunction(currentFunctionName->c_str(), bpfv) || !bpfv.size()) {
922           bperr("unable to locate current function %s\n", currentFunctionName->c_str());
923         } else {
924           if (bpfv.size() > 1) {
925             // warn if we find more than one function with this name
926             bperr("%s[%d]:  WARNING: found %d funcs matching name %s, using the first\n",
927                    __FILE__, __LINE__, bpfv.size(), currentFunctionName->c_str());
928           }
929           
930           BPatch_function *func = bpfv[0];
931           commonBlock->endCommonBlock(func, commonBlockVar->getBaseAddr());
932         }
933         
934         // update size if needed
935         if (commonBlockVar)
936           commonBlockVar->setSize(commonBlock->getSize());
937         commonBlockVar = NULL;
938         commonBlock = NULL;
939         break;
940       }
941       
942       // case C_BINCL: -- what is the elf version of this jkh 8/21/01
943       // case C_EINCL: -- what is the elf version of this jkh 8/21/01
944       case 32:    // Global symbols -- N_GYSM 
945       case 38:    // Global Static -- N_STSYM
946       case N_FUN:
947       case 128:   // typedefs and variables -- N_LSYM
948       case 160:   // parameter variable -- N_PSYM 
949     case 0xc6:  // position-independant local typedefs -- N_ISYM
950     case 0xc8: // position-independant external typedefs -- N_ESYM
951 #ifdef TIMED_PARSE
952         pss_count++;
953         gettimeofday(&t1, NULL);
954 #endif
955         if (stabptr->type(i) == N_FUN) current_func = NULL;
956         ptr = const_cast<char *>(stabptr->name(i));
957         while (ptr[strlen(ptr)-1] == '\\') {
958           //ptr[strlen(ptr)-1] = '\0';
959           ptr2 =  const_cast<char *>(stabptr->name(i+1));
960           ptr3 = (char *) malloc(strlen(ptr) + strlen(ptr2));
961           strcpy(ptr3, ptr);
962           ptr3[strlen(ptr)-1] = '\0';
963           strcat(ptr3, ptr2);
964           
965           ptr = ptr3;
966           i++;
967           // XXX - memory leak on multiple cont. lines
968         }
969         
970         // bperr("stab #%d = %s\n", i, ptr);
971         // may be nothing to parse - XXX  jdd 5/13/99
972         if (nativeCompiler)
973           temp = parseStabString(this, mostRecentLinenum, (char *)ptr, stabptr->val(i), commonBlock);
974         else
975           temp = parseStabString(this, stabptr->desc(i), (char *)ptr, stabptr->val(i), commonBlock);
976         if (temp && *temp) {
977           //Error parsing the stabstr, return should be \0
978           bperr( "Stab string parsing ERROR!! More to parse: %s\n",
979                   temp);
980           bperr( "  symbol: %s\n", ptr);
981         }
982         
983 #ifdef TIMED_PARSE
984         gettimeofday(&t2, NULL);
985         pss_dur += (t2.tv_sec - t1.tv_sec)*1000.0 + (t2.tv_usec - t1.tv_usec)/1000.0;
986         //      pss_dur += (t2.tv_sec/1000 + t2.tv_usec*1000) - (t1.tv_sec/1000 + t1.tv_usec*1000);
987 #endif
988         break;
989       default:
990         break;
991       }
992     }                       
993   }
994
995 #if defined(TIMED_PARSE)
996   struct timeval endtime;
997   gettimeofday(&endtime, NULL);
998   unsigned long lstarttime = starttime.tv_sec * 1000 * 1000 + starttime.tv_usec;
999   unsigned long lendtime = endtime.tv_sec * 1000 * 1000 + endtime.tv_usec;
1000   unsigned long difftime = lendtime - lstarttime;
1001   double dursecs = difftime/(1000 );
1002   cout << __FILE__ << ":" << __LINE__ <<": parseTypes("<< mod->fileName()
1003        <<") took "<<dursecs <<" msecs" << endl;
1004   cout << "Breakdown:" << endl;
1005   cout << "     Functions: " << fun_count << " took " << fun_dur << "msec" << endl;
1006   cout << "     Sources: " << src_count << " took " << src_dur << "msec" << endl;
1007   cout << "     parseStabString: " << pss_count << " took " << pss_dur << "msec" << endl;
1008   cout << "     Total: " << pss_dur + fun_dur + src_dur 
1009        << " msec" << endl;
1010 #endif
1011 }
1012
1013 #endif //end of #if defined(i386_unknown_linux2_0)
1014
1015 // Parsing symbol table for Alpha platform
1016 // Mehmet
1017
1018 #if defined(alpha_dec_osf4_0)
1019 extern void parseCoff(BPatch_module *mod, char *exeName, 
1020                         const pdstring& modName, LineInformation* linfo);
1021
1022 void BPatch_module::parseTypes()
1023 {
1024   image * imgPtr=NULL;
1025
1026   //Using pdmodule to get the image Object.
1027   imgPtr = mod->exec();
1028
1029   //Get the path name of the process
1030   char *file = (char *)(imgPtr->file()).c_str();
1031
1032   // with BPatch_functions
1033   this->BPfuncs = this->getProcedures();
1034
1035   assert(mod->lineInformation);
1036
1037   parseCoff(this, file, mod->fileName(),mod->lineInformation);
1038 }
1039
1040 #endif
1041
1042
1043
1044 #if defined(i386_unknown_nt4_0) \
1045  || defined(mips_unknown_ce2_11) //ccw 6 apr 2001
1046
1047 // Parsing symbol table for NT platform
1048 // Mehmet 7/24/00
1049
1050 #include "CodeView.h"
1051
1052 void BPatch_module::parseTypes()
1053 {
1054   
1055   image * imgPtr=NULL;
1056
1057   //Using pdmodule to get the image Object.
1058   imgPtr = mod->exec();
1059
1060   // with BPatch_functions
1061   this->BPfuncs = this->getProcedures();
1062
1063   // trying to get at codeview symbols
1064   // need text section id and addr of codeview symbols
1065   unsigned int textSectionId = imgPtr->getObject().GetTextSectionId();
1066   PIMAGE_NT_HEADERS peHdr = imgPtr->getObject().GetImageHeader();
1067
1068   DWORD modBaseAddr = imgPtr->getObject().code_off();
1069   PVOID mapAddr = imgPtr->getObject().GetMapAddr();
1070
1071   PVOID pCodeViewSymbols = NULL;
1072   ULONG dirEntSize = 0;
1073   PIMAGE_SECTION_HEADER pDebugSectHeader = NULL;
1074   PIMAGE_DEBUG_DIRECTORY baseDirEnt = 
1075           (PIMAGE_DEBUG_DIRECTORY)ImageDirectoryEntryToDataEx( mapAddr,
1076                                                                                         FALSE,   // we mapped using MapViewOfFile
1077                                                                                         IMAGE_DIRECTORY_ENTRY_DEBUG,
1078                                                                                         &dirEntSize,
1079                                                                                         &pDebugSectHeader );
1080   if( baseDirEnt != NULL )
1081   {
1082         PIMAGE_DEBUG_DIRECTORY pDirEnt = baseDirEnt;
1083         unsigned int nDirEnts = dirEntSize / sizeof(IMAGE_DEBUG_DIRECTORY);
1084         for( unsigned int i = 0; i < nDirEnts; i++ )
1085         {
1086                 if( pDirEnt->Type == IMAGE_DEBUG_TYPE_CODEVIEW )
1087                 {
1088                         pCodeViewSymbols = (PVOID)(((char*)mapAddr) + pDirEnt->PointerToRawData);
1089                         break;
1090                 }
1091                 // advance to next entry
1092                 pDirEnt++;
1093         }
1094   }
1095
1096   if( pCodeViewSymbols != NULL )
1097   {
1098         CodeView* cv = new CodeView( (const char*)pCodeViewSymbols, 
1099                                         textSectionId );
1100
1101         cv->CreateTypeAndLineInfo(this, modBaseAddr, mod->lineInformation);
1102   }
1103 }
1104 #endif
1105
1106
1107 bool BPatch_module::getVariablesInt(BPatch_Vector<BPatch_variableExpr *> &vars)
1108 {
1109  
1110   BPatch_variableExpr *var;
1111   parseTypesIfNecessary();
1112   
1113   pdvector<pdstring> keys = moduleTypes->globalVarsByName.keys();
1114   int limit = keys.size();
1115   for (int j = 0; j < limit; j++) {
1116     pdstring name = keys[j];
1117     var = img->createVarExprByName(this, name.c_str());
1118     vars.push_back(var);
1119   }
1120   if (limit) 
1121     return true;
1122   
1123 #ifdef IBM_BPATCH_COMPAT
1124   //  IBM getVariables can be successful while returning an empty set of vars
1125   return true;
1126 #else
1127   return false;
1128 #endif
1129 }
1130
1131 /** method that finds the corresponding addresses for a source line
1132   * this methid returns true in sucess, otherwise false.
1133   * it can be called to find the exact match or, in case, exact match
1134   * does not occur, it will return the address set of the next
1135   * greater line. It uses the name of the module as a source file name
1136   * 
1137   */
1138 bool BPatch_module::getLineToAddrInt(unsigned short lineNo,
1139                                   BPatch_Vector<unsigned long>& buffer,
1140                                   bool exactMatch)
1141
1142 {
1143
1144         //if the line information is not created yet return false
1145
1146         if(!mod->lineInformation){
1147 #if !defined(rs6000_ibm_aix4_1) \
1148  && !defined(mips_sgi_irix6_4) \
1149  && !defined(alpha_dec_osf4_0) \
1150  && !defined(i386_unknown_nt4_0)
1151
1152           mod->parseFileLineInfo(proc);
1153 #else
1154           cerr << __FILE__ << ":" << __LINE__ << ": lineInfo == NULL" << endl;
1155           return false;
1156 #endif
1157         }
1158         
1159         //query the line info object to get set of addresses if it exists.
1160         BPatch_Set<Address> addresses;
1161         if(!mod->lineInformation->getAddrFromLine(addresses,lineNo,exactMatch)) {
1162           //cerr << __FILE__ << __LINE__ << ":  getAddrFromLine failed!" << endl;
1163                 return false;
1164         }
1165         //then insert the elements to the vector given
1166         Address* elements = new Address[addresses.size()];
1167         addresses.elements(elements);
1168         for(unsigned i=0;i<addresses.size();i++)
1169                 buffer.push_back(elements[i]);
1170         delete[] elements;
1171         return true;
1172 }
1173
1174
1175 LineInformation* BPatch_module::getLineInformationInt(){
1176    return this->mod->getLineInformation(this->proc);
1177 }
1178
1179 bool BPatch_module::isSharedLibInt() {
1180   return mod->isShared();
1181 }
1182
1183 bool BPatch_module::isNativeCompilerInt()
1184 {
1185   return nativeCompiler;
1186 }
1187
1188 size_t BPatch_module::getAddressWidthInt()
1189 {
1190   return mod->exec()->getObject().getAddressWidth();
1191 }
1192
1193 void BPatch_module::setDefaultNamespacePrefix(char *name) 
1194
1195     img->setDefaultNamespacePrefix(name); 
1196 }
1197
1198 #ifdef IBM_BPATCH_COMPAT
1199
1200 bool BPatch_module::getLineNumbersInt(unsigned int &start, unsigned int &end)
1201 {
1202     start = 0;
1203     end = 0;
1204     return true;
1205 }
1206
1207 bool BPatch_module::getAddressRangeInt(void * &start, void * &end)
1208 {
1209   return false;
1210 }
1211 char *BPatch_module::getUniqueStringInt(char *buffer, int length)
1212 {
1213     getName(buffer, length);
1214     return buffer;
1215 }
1216
1217 int BPatch_module::getSharedLibTypeInt()        
1218 {
1219     return 0;
1220 }
1221
1222 int BPatch_module::getBindingTypeInt()
1223 {
1224     return 0;
1225 }
1226
1227 #endif
1228