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