Added code to suppress "functions" that have aninvalid instruction
[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[] = "@(#) $Header: /home/jaw/CVSROOT_20081103/CVSROOT/core/paradynd/src/Attic/symtab.C,v 1.16 1994/10/25 22:20:29 hollings Exp $";
11 #endif
12
13 /*
14  * symtab.C - generic symbol routines.  Implements an ADT for a symbol
15  *   table.  The make calls to machine and a.out specific routines to handle
16  *   the implementation dependent parts.
17  *
18  * $Log: symtab.C,v $
19  * Revision 1.16  1994/10/25 22:20:29  hollings
20  * Added code to suppress "functions" that have aninvalid instruction
21  * as their first instruction.  These are really read-only data that has
22  * been placed in the text segment to protect it from writing.
23  *
24  * Revision 1.15  1994/10/13  07:25:04  krisna
25  * solaris porting and updates
26  *
27  * Revision 1.14  1994/10/04  21:40:12  jcargill
28  * Removed requirement that functions have valid line-number information to
29  * be consider user functions.
30  *
31  * Revision 1.13  1994/09/30  19:47:16  rbi
32  * Basic instrumentation for CMFortran
33  *
34  * Revision 1.12  1994/09/22  02:26:40  markc
35  * Made structs classes
36  *
37  * Revision 1.11  1994/08/08  20:13:47  hollings
38  * Added suppress instrumentation command.
39  *
40  * Revision 1.10  1994/08/02  18:25:07  hollings
41  * fixed modules to use list template for lists of functions.
42  *
43  * Revision 1.9  1994/07/28  22:40:48  krisna
44  * changed definitions/declarations of xalloc functions to conform to alloc.
45  *
46  * Revision 1.8  1994/07/22  19:21:10  hollings
47  * removed mistaken divid by 1Meg for predicted cost.
48  *
49  * Revision 1.7  1994/07/20  23:23:41  hollings
50  * added insn generated metric.
51  *
52  * Revision 1.6  1994/07/12  19:26:15  jcargill
53  * Added internal prefix for TRACELIB
54  *
55  * Revision 1.5  1994/06/29  02:52:51  hollings
56  * Added metricDefs-common.{C,h}
57  * Added module level performance data
58  * cleanedup types of inferrior addresses instrumentation defintions
59  * added firewalls for large branch displacements due to text+data over 2meg.
60  * assorted bug fixes.
61  *
62  * Revision 1.4  1994/06/27  21:28:23  rbi
63  * Abstraction-specific resources and mapping info
64  *
65  * Revision 1.3  1994/06/27  18:57:15  hollings
66  * removed printfs.  Now use logLine so it works in the remote case.
67  * added internalMetric class.
68  * added extra paramter to metric info for aggregation.
69  *
70  * Revision 1.2  1994/05/16  22:31:55  hollings
71  * added way to request unique resource name.
72  *
73  * Revision 1.1  1994/01/27  20:31:45  hollings
74  * Iinital version of paradynd speaking dynRPC igend protocol.
75  *
76  * Revision 1.8  1993/12/13  19:57:20  hollings
77  * added nearest line match for function to support Fortran convention of making
78  * first sline record be the first executable statement in the function.
79  *
80  * Revision 1.7  1993/10/12  20:10:35  hollings
81  * zero memory on a realloc.
82  *
83  * Revision 1.6  1993/10/04  21:39:08  hollings
84  * made missing internal symbols a fatal condition.
85  *
86  * Revision 1.5  1993/08/23  23:16:05  hollings
87  * added third parameter to findInternalSymbol.
88  *
89  * Revision 1.4  1993/08/20  22:02:39  hollings
90  * removed unused local variables.
91  *
92  * Revision 1.3  1993/07/13  18:32:46  hollings
93  * new include file syntax.
94  * added name demangler.
95  *
96  * Revision 1.2  1993/06/08  20:14:34  hollings
97  * state prior to bc net ptrace replacement.
98  *
99  * Revision 1.1  1993/03/19  22:45:45  hollings
100  * Initial revision
101  *
102  *
103  */
104
105 extern "C" {
106 #include <string.h>
107 #include <stdio.h>
108 #include <stdlib.h>
109 #include <assert.h>
110 #include <memory.h>
111 }
112
113 #include "util/h/list.h"
114 #include "symtab.h"
115 #include "util.h"
116 #include "dyninstP.h"
117
118 resource *moduleRoot;
119 extern "C" char *cplus_demangle(char *, int);
120 static image *allImages;
121 extern stringPool pool;
122
123 extern image *loadSymTable(const char *file, int offset, List<libraryFunc*> libraryFunctions, 
124                            const char **iSym);
125
126 /* imported from platform specific library list.  This is lists all
127    library functions we are interested in instrumenting. */
128 extern List<libraryFunc*> libraryFunctions;
129
130 /* store text address of source code line numbers */
131 void lineTable::setLineAddr(int line, caddr_t lineAddr)
132 {
133   if (line < 0) {
134     sprintf(errorLine, "symbol table entry: N_SLINE, line#=%d, addr=%x\n",
135             line, (unsigned)lineAddr);
136     logLine(errorLine);
137     return;
138   }
139   if (line >= maxLine) {
140     int increment;
141     int moreLines = line - maxLine + 100;
142     addr = (caddr_t *) xrealloc(addr, sizeof(caddr_t)*(moreLines + maxLine));
143     increment = moreLines;
144     memset((char*)&addr[maxLine],'\0',sizeof(caddr_t)*increment);
145     maxLine = moreLines;
146   }
147   addr[line] = lineAddr;
148 }
149
150 module *newModule(image *curr, const char *currentDirectory, const char *name, caddr_t addr)
151 {
152     module *ret;
153     char fileName[255];
154
155     // modules can be defined several times in C++ due to templates and
156     //   in-line member functions.
157     ret = findModule(curr, name);
158     if (ret) {
159         return(ret);
160     }
161
162     ret = new module;
163     sprintf(fileName, "%s%s", currentDirectory, name);
164     ret->compileInfo = NULL;
165     ret->fullName = pool.findAndAdd(fileName);
166     ret->fileName = pool.findAndAdd(name);
167     ret->language = unknown;
168     ret->addr = addr;
169     ret->exec = curr;
170     ret->next = curr->modules;
171
172     curr->modules = ret;
173     curr->moduleCount++;
174     return(ret);
175 }
176
177 module *moduleFindOrAdd(image *exec, caddr_t addr, char *name)
178 {
179     module *curr;
180
181     for (curr=exec->modules; curr; curr = curr->next) {
182         if (curr->addr == addr) {
183             return(curr);
184         }
185     }
186     sprintf(errorLine, "warning no symbol table for module %s\n", name);
187     logLine(errorLine);
188     curr = new module;
189     curr->fileName = pool.findAndAdd(name);
190     curr->fullName = NULL;
191     curr->language = unknown;
192     curr->addr = addr;
193     curr->next = exec->modules;
194     exec->modules = curr;
195     return(curr);
196 }
197
198 stringHandle buildDemangledName(pdFunction *func)
199 {
200     char *tempName;
201     stringHandle prettyName;
202
203     tempName = cplus_demangle((char*)func->symTabName, 0);
204     if (tempName) {
205         prettyName = pool.findAndAdd(tempName);
206         free(tempName);
207     } else {
208         prettyName = func->symTabName;
209     }
210     return(prettyName);
211 }
212
213 pdFunction *funcFindOrAdd(image *exec, module *mod, caddr_t addr, char *name)
214 {
215     pdFunction *func;
216
217     for (func = exec->funcs; func; func=func->next) {
218         if (func->addr == addr) {
219             return(func);
220         }
221     }
222
223     func = new pdFunction;
224     func->symTabName = pool.findAndAdd(name);
225     func->prettyName = buildDemangledName(func);
226     func->line = UNKNOWN_LINE;  
227     func->file = mod;
228     func->addr = addr;
229     func->next = exec->funcs;
230
231     mod->funcs.add(func);
232
233     exec->funcs = func;
234     exec->funcCount++;
235     return(func);
236 }
237
238 pdFunction *newFunc(image *exec, module *mod, const char *name, int addr)
239 {
240     if (exec->funcAddrHash.find((void *) addr)) {
241         sprintf(errorLine, "function defined twice, ignoring this function\n");
242         logLine(errorLine);
243         return 0;
244     }
245
246     char *p;
247     pdFunction *func;
248
249     if (!mod) {
250         logLine("Error function without module\n");
251     }
252     func = new pdFunction;
253
254     exec->funcAddrHash.add(func, (void *) addr);
255
256     p = strchr(name, ':');
257     if (p) *p = '\0';
258     func->symTabName = pool.findAndAdd(name);
259     func->prettyName = buildDemangledName(func);
260     func->line = UNKNOWN_LINE;  /* ???? fix this */
261     func->file = mod;
262     func->addr = (caddr_t) addr;
263     func->sibling = findFunction(exec, name);
264
265     mod->funcs.add(func);
266
267     func->next = exec->funcs;
268     exec->funcs = func;
269     exec->funcCount++;
270     return(func);
271 }
272
273 /*
274  * List of prefixes for internal symbols we need to find.
275  *
276  */
277 const char *internalPrefix[] = {
278     "DYNINST",
279     "TRACELIB",
280     NULL
281 };
282
283 /*
284  * load an executable:
285  *   1.) parse symbol table and identify rotuines.
286  *   2.) scan executable to identify inst points.
287  *
288  *  offset is normally zero except on CM-5 where we have two images in one
289  *    file.  The offset passed to parseImage is the logical offset (0/1), not
290  *    the physical point in the file.  This makes it faster to "parse" multiple
291  *    copies of the same image since we don't have to stat and read to find the
292  *    physical offset. 
293  */
294 image *parseImage(char *file, int offset)
295 {
296     image *ret;
297     module *mod;
298     Boolean status;
299     pdFunction *func;
300     caddr_t endUserAddr;
301     List<pdFunction*> curr;
302     resource *modResource;
303     caddr_t startUserAddr;
304     internalSym *endUserFunc;
305     internalSym *startUserFunc;
306     extern findNodeOffset(char *, int);
307
308     /*
309      * Check to see if we have parsed this image at this offeset before.
310      *
311      */
312     for (ret=allImages; ret; ret = ret->next) {
313         if (!strcmp((char*)ret->file, file) && (ret->offset == offset)) {
314             return(ret);
315         }
316     }
317
318     /*
319      * load the symbol table. (This is the a.out format specific routine).
320      *
321      */
322     ret = loadSymTable(file, findNodeOffset(file, offset), libraryFunctions, 
323         internalPrefix);
324
325     /* check that we loaded o.k. */
326     if (!ret) {
327         return(NULL);
328     }
329
330     /*
331      * Add to master image list.
332      *
333      */
334     ret->next = allImages;
335     ret->offset = offset;
336     allImages = ret;
337
338     /*
339      * mark as lib, library pdFunctions that were compiled with symbols.
340      *
341      */
342     startUserFunc = findInternalSymbol(ret, "DYNINSTstartUserCode", False);
343     startUserAddr = (caddr_t) ((startUserFunc) ? startUserFunc->addr : 0x0);
344
345     endUserFunc = findInternalSymbol(ret, "DYNINSTendUserCode", False);
346     if (endUserFunc && endUserFunc->addr) {
347         endUserAddr = (caddr_t) endUserFunc->addr;
348     } else {
349         endUserAddr = (caddr_t) startUserAddr;
350     }
351
352     // if (endUserFunc) {
353     if (1) {
354         for (func = ret->funcs; func; func=func->next) {
355             if ((func->addr >= endUserAddr) ||
356                 (func->addr <= startUserAddr)) {
357                 func->tag |= TAG_LIB_FUNC;
358 //              printf ("function %s tagged as a library function\n",
359 //                      func->prettyName);
360             }
361 //          else
362 //              printf ("function %s NOT tagged as a library function\n",
363 //                      func->prettyName);
364         }
365     }
366     
367
368     /*
369      * Now identify the points in the functions to instrument.
370      *   This is the machine specific routine.
371      *
372      */
373     status = locateAllInstPoints(ret);
374     if (status == FALSE) {
375         return(NULL);
376     }
377
378     moduleRoot = newResource(rootResource, NULL, NULL, "Procedure", 0.0, FALSE);
379
380     // define all modules.
381     for (mod = ret->modules; mod; mod=mod->next) {
382         modResource = NULL;
383         for (curr = mod->funcs;  func = *curr; curr++) {
384             if ((!func->tag & TAG_LIB_FUNC) &&
385                 (!(func->tag & TAG_NON_FUNC))) { 
386             
387             // IGNORE LINE NUMBERS FOR NOW
388             // if ((!func->tag & TAG_LIB_FUNC) && (func->line)) {
389
390                 // see if we have created module yet.
391                 if (!modResource) {
392                     modResource = newResource(moduleRoot, mod, NULL, 
393                         (const char*) mod->fileName, 0.0, FALSE);
394                 }
395                 (void) newResource(modResource, func, NULL, 
396                     (const char*) func->prettyName,0.0,FALSE);
397             } else {
398                 // Temporarily commented out by Jon.  The following line
399                 // broke many programs and metrics, by causing user functions
400                 // without line-number information to turn into library funcs.
401                 // func->tag |= TAG_LIB_FUNC;
402             }
403         }
404     }
405
406     /*
407      * Optional post-processing step.  
408      */
409     if (ret->symbolExists("CMRT_init")) {
410       ret->postProcess(NULL);
411     }
412
413     /* this may not be heap allocated memory, comment out for now */
414     /* will look at this later */
415     /* zero out ret->code so it can't be followed - mdc */
416     /* free(ret->code); */
417     ret->code = 0;
418
419     return(ret);
420 }
421
422
423 internalSym *findInternalSymbol(image *i, const char *name, Boolean warn)
424 {
425     int count;
426     stringHandle iName;
427
428     iName = pool.findAndAdd(name);
429     for (count = 0; count < i->iSymCount; count++) {
430         if (i->iSyms[count].name == iName) {
431             return(&i->iSyms[count]);
432         }
433     }
434     if (warn) {
435         sprintf(errorLine, "unable to find internal symbol %s\n", name);
436         logLine(errorLine);
437     }
438     
439     return(NULL);
440 }
441
442 caddr_t findInternalAddress(image *i, const char *name, Boolean warn)
443 {
444     int count;
445     stringHandle iName;
446     internalSym *curr;
447
448     iName = pool.findAndAdd(name);
449     for (count = 0, curr=i->iSyms; count < i->iSymCount; count++, curr++) {
450         if (curr->name == iName) {
451             return((caddr_t) curr->addr);
452         }
453     }
454     if (warn) {
455         printf("unable to find internal symbol %s\n", name);
456         abort();
457     }
458     return(NULL);
459 }
460
461 module *findModule(image *i, const char *name)
462 {
463     stringHandle iName;
464     module *mod;
465
466     iName = pool.findAndAdd(name);
467     for (mod = i->modules; mod; mod=mod->next) {
468         if (iName == mod->fileName) {
469              return(mod);
470         } else if (iName == mod->fullName) {
471              return(mod);
472         }
473     }
474     return(NULL);
475 }
476
477 //
478 // Warning the sibling code depends on findFunction working down the
479 //    function list in order!!  
480 //
481 pdFunction *findFunction(image *i, const char *name)
482 {
483     stringHandle iName;
484     pdFunction *func;
485
486     iName = pool.findAndAdd(name);
487     for (func = i->funcs; func; func=func->next) {
488         if (iName == func->prettyName) {
489              return(func);
490         } else if (iName == func->symTabName) {
491              return(func);
492         }
493     }
494     return(NULL);
495 }
496
497 pdFunction *findFunctionByAddr(image *i, caddr_t addr)
498 {
499     pdFunction *func;
500
501     func = i->funcAddrHash.find((void *) addr);
502 #ifdef notdef
503     for (func = i->funcs; func; func=func->next) {
504         if (addr == func->addr) {
505              return(func);
506         }
507     }
508     return(NULL);
509 #endif
510     return(func);
511 }
512
513
514 void mapLines(module *mod)
515 {
516     int j;
517     pdFunction *func;
518     List<pdFunction*> curr;
519
520     if (!mod) return;
521
522     mod->lines.qsortLines();
523     for (curr = mod->funcs; func = *curr; curr++) {
524         for (j=0; j < mod->lines.getMaxLine(); j++) {
525             if (func->addr <= (caddr_t) mod->lines.getLineAddr(j)) {
526                 func->line = j;
527                 break;
528             }
529         }
530     }
531 }
532
533 void changeLibFlag(resource *res, Boolean setSuppress)
534 {
535     image *ret;
536     module *mod;
537     pdFunction *func;
538     List<pdFunction*> curr;
539
540     for (ret=allImages; ret; ret = ret->next) {
541         mod = findModule(ret, res->getName());
542         if (mod) {
543             // suppress all procedures.
544             for (curr = mod->funcs; func = *curr; curr++) {
545                 if (setSuppress) {
546                     func->tag |= TAG_LIB_FUNC;
547                 } else {
548                     func->tag &= ~TAG_LIB_FUNC;
549                 }
550             }
551         } else {
552             func = findFunction(ret, res->getName());
553             if (func) {
554                 if (setSuppress) {
555                     func->tag |= TAG_LIB_FUNC;
556                 } else {
557                     func->tag &= ~TAG_LIB_FUNC;
558                 }
559             }
560         }
561     }
562 }
563
564 image::image()
565 {
566   file = NULL;
567   name = NULL;
568   moduleCount = 0;
569   modules = NULL;
570   funcCount = 0;
571   funcs = NULL;
572   iSymCount=0;
573   iSyms = NULL;
574   code = NULL;
575   textOffset = 0;
576   offset  = 0;
577   next = 0;
578 }
579
580 /* 
581  * return 0 if symbol <symname> exists in image, non-zero if it does not
582  */
583 int image::symbolExists(const char *symname)
584 {
585   pdFunction *dummy;
586   
587   dummy = findFunction(this, symname);
588   return (dummy != NULL);
589 }
590
591 void image::postProcess(const char *pifname)
592 {
593   FILE *Fil;
594   stringHandle fname;
595   char temp[5000], errorstr[5000], key[5000];
596   char tmp1[5000], abstraction[500];
597   resource *parent;
598
599   /* What file to open? */
600   if (pifname) {
601     fname = pool.findAndAdd(pifname);
602   } else {
603     sprintf(temp, "%s.pif", (char *) file);
604     fname = pool.findAndAdd(temp);
605   }
606
607   /* Open the file */
608   Fil = fopen((char *) fname, "r");
609   if (Fil == NULL) {
610     sprintf(errorstr, 
611             "Tried to open PIF file %s, but could not (continuing)\n", 
612             (char *) fname);
613     logLine(errorstr);
614     return;
615   }
616
617   /* Process the file */
618   while (!feof(Fil)) {
619     fscanf(Fil, "%s", key);
620     switch (key[0]) {
621     case 'M':
622       /* Ignore mapping information for right now */
623       fgets(tmp1, 5000, Fil);
624       break;
625     case 'R':
626       /* Create a new resource */
627       fscanf(Fil, "%s {", abstraction);
628       parent = rootResource;
629       do {
630         fscanf(Fil, "%s", tmp1);
631         if (tmp1[0] != '}') {
632           parent = newResource(parent, NULL, abstraction, tmp1, 0.0, FALSE);
633         } else {
634           parent = NULL;
635         }
636       } while (parent != NULL);
637       break;
638     default:
639       sprintf(errorstr, 
640               "Ignoring bad line key (%s) in file %s\n", key, (char *) fname);
641       logLine(errorstr);
642       fgets(tmp1, 5000, Fil);
643       break;
644     }
645   }
646   return;
647 }
648
649 module::module()
650 {
651   compileInfo = NULL;
652   fileName = NULL;
653   fullName = NULL;
654   language = unknown;
655   addr = 0;
656   exec = 0;
657   next = 0;
658 }
659
660 pdFunction::pdFunction()
661 {
662   symTabName = NULL;
663   prettyName = NULL;
664   line = 0;
665   file = NULL;
666   addr = 0;
667   funcEntry = NULL;
668   funcReturn = NULL;
669   callLimit = 0;
670   callCount = 0;
671   calls = NULL;
672   ljmpCount = 0;
673   jmps = NULL;
674   tag = 0;
675   next = NULL;
676   sibling = NULL;
677 }