Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.bin / gprof / aout.c
1 #include <a.out.h>
2
3 #include "gprof.h"
4
5 static void getstrtab(FILE *, const char *);
6 static void getsymtab(FILE *, const char *);
7 static void gettextspace(FILE *);
8 static bool funcsymbol(struct nlist *);
9
10 static char     *strtab;                /* string table in core */
11 static long     ssiz;                   /* size of the string table */
12 static struct   exec xbuf;              /* exec header of a.out */
13
14 /* Things which get -E excluded by default. */
15 static char     *excludes[] = { "mcount", "__mcleanup", NULL };
16
17     /*
18      * Set up string and symbol tables from a.out.
19      *  and optionally the text space.
20      * On return symbol table is sorted by value.
21      *
22      * Returns 0 on success, -1 on failure.
23      */
24 int
25 aout_getnfile(const char *filename, char ***defaultEs)
26 {
27     FILE        *nfile;
28     int         valcmp();
29
30     nfile = fopen( filename ,"r");
31     if (nfile == NULL) {
32         perror( filename );
33         done();
34     }
35     fread(&xbuf, 1, sizeof(xbuf), nfile);
36     if (N_BADMAG(xbuf)) {
37         fclose(nfile);
38         return -1;
39     }
40     getstrtab(nfile, filename);
41     getsymtab(nfile, filename);
42     gettextspace( nfile );
43     fclose(nfile);
44 #   ifdef DEBUG
45         if ( debug & AOUTDEBUG ) {
46             register int j;
47
48             for (j = 0; j < nname; j++){
49                 printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name);
50             }
51         }
52 #   endif DEBUG
53     *defaultEs = excludes;
54     return 0;
55 }
56
57 static void
58 getstrtab(FILE *nfile, const char *filename)
59 {
60
61     fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
62     if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
63         warnx("%s: no string table (old format?)" , filename );
64         done();
65     }
66     strtab = calloc(ssiz, 1);
67     if (strtab == NULL) {
68         warnx("%s: no room for %d bytes of string table", filename , ssiz);
69         done();
70     }
71     if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
72         warnx("%s: error reading string table", filename );
73         done();
74     }
75 }
76
77     /*
78      * Read in symbol table
79      */
80 static void
81 getsymtab(FILE *nfile, const char *filename)
82 {
83     register long       i;
84     int                 askfor;
85     struct nlist        nbuf;
86
87     /* pass1 - count symbols */
88     fseek(nfile, (long)N_SYMOFF(xbuf), 0);
89     nname = 0;
90     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
91         fread(&nbuf, sizeof(nbuf), 1, nfile);
92         if ( ! funcsymbol( &nbuf ) ) {
93             continue;
94         }
95         nname++;
96     }
97     if (nname == 0) {
98         warnx("%s: no symbols", filename );
99         done();
100     }
101     askfor = nname + 1;
102     nl = (nltype *) calloc( askfor , sizeof(nltype) );
103     if (nl == 0) {
104         warnx("no room for %d bytes of symbol table", askfor * sizeof(nltype) );
105         done();
106     }
107
108     /* pass2 - read symbols */
109     fseek(nfile, (long)N_SYMOFF(xbuf), 0);
110     npe = nl;
111     nname = 0;
112     for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
113         fread(&nbuf, sizeof(nbuf), 1, nfile);
114         if ( ! funcsymbol( &nbuf ) ) {
115 #           ifdef DEBUG
116                 if ( debug & AOUTDEBUG ) {
117                     printf( "[getsymtab] rejecting: 0x%x %s\n" ,
118                             nbuf.n_type , strtab + nbuf.n_un.n_strx );
119                 }
120 #           endif DEBUG
121             continue;
122         }
123         npe->value = nbuf.n_value;
124         npe->name = strtab+nbuf.n_un.n_strx;
125 #       ifdef DEBUG
126             if ( debug & AOUTDEBUG ) {
127                 printf( "[getsymtab] %d %s 0x%08x\n" ,
128                         nname , npe -> name , npe -> value );
129             }
130 #       endif DEBUG
131         npe++;
132         nname++;
133     }
134     npe->value = -1;
135 }
136
137     /*
138      *  read in the text space of an a.out file
139      */
140 static void
141 gettextspace(FILE *nfile)
142 {
143
144     if ( cflag == 0 ) {
145         return;
146     }
147     textspace = (u_char *) malloc( xbuf.a_text );
148     if ( textspace == 0 ) {
149         warnx("ran out room for %d bytes of text space: can't do -c" ,
150                   xbuf.a_text );
151         return;
152     }
153     (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 );
154     if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) {
155         warnx("couldn't read text space: can't do -c");
156         free( textspace );
157         textspace = 0;
158         return;
159     }
160 }
161
162 static bool
163 funcsymbol(struct nlist *nlistp)
164 {
165     char        *name, c;
166
167         /*
168          *      must be a text symbol,
169          *      and static text symbols don't qualify if aflag set.
170          */
171     if ( ! (  ( nlistp -> n_type == ( N_TEXT | N_EXT ) )
172            || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) {
173         return FALSE;
174     }
175         /*
176          *      name must start with an underscore if uflag is set.
177          *      can't have any `funny' characters in name,
178          *      where `funny' means `.' (.o file names)
179          *      need to make an exception for sparc .mul & co.
180          *      perhaps we should just drop this code entirely...
181          */
182     name = strtab + nlistp -> n_un.n_strx;
183     if ( uflag && *name != '_' )
184         return FALSE;
185 #ifdef sparc
186     if ( *name == '.' ) {
187         char *p = name + 1;
188         if ( *p == 'u' )
189             p++;
190         if ( strcmp ( p, "mul" ) == 0 || strcmp ( p, "div" ) == 0 ||
191              strcmp ( p, "rem" ) == 0 )
192                 return TRUE;
193     }
194 #endif
195     while ( c = *name++ ) {
196         if ( c == '.' ) {
197             return FALSE;
198         }
199     }
200     return TRUE;
201 }