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