removed mistaken divid by 1Meg for predicted cost.
[dyninst.git] / paradynd / src / sym-bsd.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/sym-bsd.C,v 1.6 1994/07/22 19:21:09 hollings Exp $";
11 #endif
12
13 /*
14  * sym-bsd.C - parse BSD style a.out files.
15  *
16  * $Log: sym-bsd.C,v $
17  * Revision 1.6  1994/07/22 19:21:09  hollings
18  * removed mistaken divid by 1Meg for predicted cost.
19  *
20  * Revision 1.5  1994/07/12  19:38:34  jcargill
21  * Fixed iSymCount problem, improved speed of search for lib functions,
22  * removed old/dead CM5 code, and fixed pagemask error
23  *
24  * Revision 1.4  1994/07/05  03:26:19  hollings
25  * observed cost model
26  *
27  * Revision 1.3  1994/06/29  02:52:49  hollings
28  * Added metricDefs-common.{C,h}
29  * Added module level performance data
30  * cleanedup types of inferrior addresses instrumentation defintions
31  * added firewalls for large branch displacements due to text+data over 2meg.
32  * assorted bug fixes.
33  *
34  * Revision 1.2  1994/06/27  18:57:11  hollings
35  * removed printfs.  Now use logLine so it works in the remote case.
36  * added internalMetric class.
37  * added extra paramter to metric info for aggregation.
38  *
39  * Revision 1.1  1994/01/27  20:31:43  hollings
40  * Iinital version of paradynd speaking dynRPC igend protocol.
41  *
42  * Revision 1.9  1993/12/13  19:56:24  hollings
43  * include initalized data segment with text segment in things that we
44  * read from the binary image.  This was required by binist utility which
45  * puts rtinst code into the data segment.
46  *
47  * Revision 1.8  1993/09/10  20:32:37  hollings
48  * New, faster function to find library functions.
49  *
50  * Revision 1.7  1993/08/26  18:20:59  hollings
51  * further refinements of which symbols get processed.
52  *
53  * Revision 1.6  1993/08/23  22:57:07  hollings
54  * added check that internal symbols are only N_TEXT, N_DATA, or N_BSS.
55  *
56  * Revision 1.5  1993/08/11  01:42:30  hollings
57  * added checks/fixes for ZMAGIC vs. OMAGIC (jkh for jcargill).
58  *
59  * Revision 1.4  1993/08/11  01:37:41  hollings
60  * removed processing of dummy gnu symbols.
61  *
62  * Revision 1.3  1993/07/13  18:31:15  hollings
63  *  new include file syntax.
64  *  added support for N_SOL stab (included file).
65  *  changed defauly endUserAddr to exec.a_entry to prevent extra symbols from
66  *  getting into the dyninst.
67  *
68  * Revision 1.2  1993/06/08  20:14:34  hollings
69  * state prior to bc net ptrace replacement.
70  *
71  * Revision 1.1  1993/03/19  22:45:45  hollings
72  * Initial revision
73  *
74  *
75  */
76 #include <stdio.h>
77 #include <a.out.h>
78 #include <stab.h>
79 #include <string.h>
80 #include <stdlib.h>
81 #include <unistd.h>
82 #include <fcntl.h>
83 #include <sys/types.h>
84 #include <sys/mman.h>
85 #include <errno.h>
86
87 #include "symtab.h"
88 #include "util.h"
89
90 /* these three really are global to the symbol table module */
91 static int nsyms;
92 static char *strings;
93 static struct nlist *stabs;
94
95 void findInternalSymbols(image *ret, char **iSym)
96 {
97     int i;
98     int len;
99     char *str;
100     int iCount;
101     char **curr;
102
103     ret->iSymCount=0;
104
105     for (curr = iSym; *curr; curr++) {
106         len = strlen(*curr);
107         for (i=0; i < nsyms; i++) {
108             str = &strings[stabs[i].n_un.n_strx];
109             if (!strncmp(str+1, *curr, len))  {
110                 ret->iSymCount++;
111                 // sprintf(errorLine, "Counting internal symbol:  '%s'\n", str);
112                 // logLine(errorLine);
113             }
114         }
115     }
116
117     ret->iSyms = (internalSym*) xcalloc(sizeof(internalSym), ret->iSymCount);
118     iCount=0;
119     for (curr = iSym; *curr; curr++) {
120         len = strlen(*curr);
121         for (i=0; i < nsyms; i++) {
122             switch (stabs[i].n_type & 0xfe) {
123                 case N_TEXT:
124                 case N_DATA:
125                 case N_BSS:
126                     str = &strings[stabs[i].n_un.n_strx];
127                     if (!strncmp(str+1, *curr, len)) {
128                         ret->iSyms[iCount].addr = stabs[i].n_value;
129                         ret->iSyms[iCount].name = pool.findAndAdd(str+1);
130                         // printf ("Found internal symbol:  '%s'\n", str);
131                         iCount++;
132                         break;
133                     
134                     default:
135                         break;
136                 }
137             }
138         }
139     }
140     /* actual useful items found */
141     ret->iSymCount = iCount;
142 }
143
144
145 /*
146  * Check for user functions that were compiled without -g.
147  *
148  *   We only load routines that are between DYNINSTstartUserCode and
149  *     DYNINSTendUserCode.  This prevents loading non-user code from
150  *     program that were not compiled for dyninst.
151  *
152  */
153 void locateRogueFuncations(image *ret, struct exec *exec)
154 {
155     int endUserAddr;
156     int startUserAddr;
157     internalSym *endUserFunc;
158     internalSym *startUserFunc;
159 #ifdef notdef
160     int i;
161     char *str;
162     module *currentModule;
163     function *currentFunc;
164 #endif
165
166     startUserFunc = findInternalSymbol(ret, "DYNINSTstartUserCode", False);
167     startUserAddr = startUserFunc ? startUserFunc->addr: exec->a_entry;
168
169     endUserFunc = findInternalSymbol(ret, "DYNINSTendUserCode", False);
170     //endUserAddr = endUserFunc?endUserFunc->addr: exec->a_entry + exec->a_text;
171     endUserAddr = endUserFunc ? endUserFunc->addr: exec->a_entry;
172
173 #ifdef notdef
174     currentModule = newModule(ret, "", NO_SYMS_MODULE, 0);
175     for (i=0; i < nsyms; i++) {
176         str = &strings[stabs[i].n_un.n_strx];
177         if (((stabs[i].n_type & 0xfe) == N_TEXT) &&
178              (stabs[i].n_value >= startUserAddr) && 
179              (stabs[i].n_value <= endUserAddr) && 
180              (*str == '_') && (strcmp(str, "___gnu_compiled_c"))) {
181                 /* a user function */
182                 currentFunc = findFunction(ret, str+1);
183                 if (!currentFunc || (currentFunc->addr != stabs[i].n_value)) {
184                     /* that is not in our symbol table */
185                     (void) newFunc(ret, currentModule, str+1, stabs[i].n_value);
186                 }
187         }
188     }
189 #endif
190 }
191
192 void locateLibFunctions(image *ret, libraryList libraryFunctions)
193 {
194     int i, j;
195     char *str;
196     int scount;
197     libraryFunc *lSym;
198     module *currentModule;
199     function *currentFunc;
200     libraryFunc **tempSyms;
201
202
203     tempSyms = (libraryFunc**) 
204             calloc(libraryFunctions.count(), sizeof(libraryFunc*));
205     for (scount=0; lSym = *libraryFunctions; libraryFunctions++) {
206         currentFunc = findFunction(ret, lSym->name);
207         if (currentFunc) {
208 //          printf ("locateLibFunctions: found %s\n", lSym->name);
209             currentFunc->tag = lSym->tags;
210             locateInstPoints(currentFunc, ret->code, ret->textOffset, 0);
211         } else {
212 //          printf ("locateLibFunctions: did NOT find %s\n", lSym->name);
213             tempSyms[scount++] = lSym;
214         }
215     }
216
217     /*
218      * Create a special module for library functions, and do the inst on
219      *   the desired functions.
220      *
221      */
222     currentModule = newModule(ret, LIBRARY_MODULE, LIBRARY_MODULE, 0);
223     for (i=0; i < nsyms; i++) {
224         if ((stabs[i].n_type & 0xfe) == N_TEXT)  {
225             str = &strings[stabs[i].n_un.n_strx];
226 //          printf ("Checking for lib function, found %s\n", str+1);
227             for (j=0; j < scount; j++) {
228                 if (!strcmp(str+1, tempSyms[j]->name))  {
229                     currentFunc = newFunc(ret, currentModule, tempSyms[j]->name,
230                         stabs[i].n_value);
231                     currentFunc->tag = tempSyms[j]->tags;
232                     locateInstPoints(currentFunc, ret->code, ret->textOffset,0);
233                     tempSyms[j]=tempSyms[--scount];  /* delete if found */
234                     break;      /* why look further? */
235                 }
236                 
237             }
238         }
239     }
240
241     /* Check for library functions not found... */
242     for (j=0; j < scount; j++) {
243         printf ("Warning:  Couldn't find library function %s\n", 
244                 tempSyms[j]->name);
245     }
246
247     free(tempSyms);
248 }
249
250 extern "C" {
251 int getpagesize();
252 }
253
254 image *loadSymTable(char *file, int offset, libraryList libraryFunctions,
255     char **iSym)
256 {
257     int i;
258     int fd;
259     char *str;
260     image *ret;
261     char *name;
262     int dynamic;
263     int pagemask;
264     int fileOffset;
265     caddr_t mapAddr;
266     int stringLength;
267     struct exec exec;
268     function *currentFunc;
269     module *currentModule;
270     char *currentDirectory;
271
272     ret = (image *) xcalloc(sizeof(image),1);
273     ret->file = pool.findAndAdd(file);
274
275     name = strrchr(file, '/');
276     name = (name ? name+1: file);
277     ret->name = pool.findAndAdd(name);
278
279     fd = open(file, 2);
280     if (fd < 0) {
281         perror(file);
282         free(ret);
283         return(NULL);
284     }
285
286     lseek(fd, offset, 0);
287     if (read(fd, (char *) &exec, sizeof(exec)) != sizeof(exec)) {
288         perror("read");
289         free(ret);
290         return(NULL);
291     }
292
293     if (N_BADMAG(exec)) {
294         perror("Bad exec");
295         free(ret);
296         return(NULL);
297     }
298
299     dynamic = 0;
300     if (exec.a_dynamic) {
301         logLine("Warning: Program dynamicly linked, can not inst system calls\n");
302         dynamic = 1;
303     }
304
305     ret->textOffset = (unsigned) N_TXTADDR(exec);
306 #ifdef notdef
307     ret->code = (void *) xmalloc(exec.a_text+exec.a_data);
308     lseek(fd, N_TXTOFF(exec)+offset, 0);
309     if (read(fd, (char *) ret->code, exec.a_text+exec.a_data) != exec.a_text+exec.a_data) {
310 #endif
311
312     // pagemask is the mask to remove page offset bits.
313     pagemask = getpagesize() - 1;
314     fileOffset = (N_TXTOFF(exec)+offset) & ~pagemask;
315
316     // use mmap to get program into memory.
317     mapAddr = mmap(0, exec.a_text+exec.a_data, PROT_READ, MAP_SHARED, fd, fileOffset);
318
319     // get correct offset into the first mapped page.
320     ret->code = mapAddr + (N_TXTOFF(exec)+offset - fileOffset);
321     if (((int) mapAddr) == -1) {
322         extern char *sys_errlist[];
323
324         free(stabs);
325         free(ret->code);
326         free(strings);
327         free(ret);
328         sprintf(errorLine,"Unable to map text segment: %s\n", 
329             sys_errlist[errno]);
330         logLine(errorLine);
331         return(NULL);
332     }
333
334     stabs = (struct nlist *) xmalloc(exec.a_syms);
335     lseek(fd, N_SYMOFF(exec)+offset, 0);
336     if (read(fd, (char *) stabs, exec.a_syms) != exec.a_syms) {
337         free(stabs);
338         free(ret->code);
339         free(strings);
340         free(ret);
341         logLine("Unable to read symbols segment\n");
342         return(NULL);
343     }
344
345     /* now read the string pool */
346     (void) lseek(fd,  N_STROFF(exec)+offset, 0);
347     if (read(fd, (char *) &stringLength, sizeof(int)) != sizeof(int)) {
348         free(ret->code);
349         free(stabs);
350         free(strings);
351         free(ret);
352         return(NULL);
353     }
354
355     strings = (char *) xmalloc(stringLength);
356     (void) lseek(fd,  N_STROFF(exec)+offset, 0);
357     if (read(fd, strings, stringLength) != stringLength) {
358         free(ret->code);
359         free(stabs);
360         free(strings);
361         free(ret);
362         return(NULL);
363     }
364
365     (void) close(fd);
366     nsyms = exec.a_syms/sizeof(struct nlist);
367     currentDirectory = "./";
368
369     currentModule = NULL;
370     for (i=0; i < nsyms; i++) {
371         /* switch on symbol type to call correct routine */
372         switch (stabs[i].n_type & 0xfe) {
373             case N_SLINE:
374                 processLine(currentModule, stabs[i].n_desc, 
375                     (caddr_t) stabs[i].n_value);
376                 break;
377
378             case N_SO:
379             case N_SOL:
380                 str = &strings[stabs[i].n_un.n_strx];
381                 if (str[strlen(str)-1] == '/') {
382                     /* directory definition */
383                     currentDirectory = str;
384                 } else {
385                         mapLines(currentModule);
386                     currentModule = newModule(ret, currentDirectory, 
387                         str, (caddr_t) stabs[i].n_value);
388                 }
389                 break;
390
391             case N_FUN:
392                 str = &strings[stabs[i].n_un.n_strx];
393                 currentFunc = newFunc(ret, currentModule, str,stabs[i].n_value);
394                 break;
395             case N_ENTRY:
396                 logLine("warning code contains alternate entry point\n");
397                 break;
398             default:
399                 break;
400         }
401     }
402
403
404     if (!dynamic) {
405         locateLibFunctions(ret, libraryFunctions);
406     }
407
408     /*
409      * Now find all of the symbols used by dyninst.
410      *
411      */
412     findInternalSymbols(ret, iSym);
413
414     locateRogueFuncations(ret, &exec);
415
416     free(strings);
417     free(stabs);
418     return(ret);
419 }