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