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