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