use tolimit for data structure initialization checks;
[unix-history] / usr / src / usr.bin / gprof / gprof.c
CommitLineData
3966d652 1#ifndef lint
3f722622 2 static char *sccsid = "@(#)gprof.c 1.6 (Berkeley) %G%";
3966d652
PK
3#endif lint
4
31f0a970 5#include "gprof.h"
3966d652
PK
6
7main(argc, argv)
8 int argc;
9 char **argv;
10{
11
12 --argc;
13 argv++;
14 debug = 0;
15 while ( *argv != 0 && **argv == '-' ) {
16 (*argv)++;
17 if ( **argv == 'd' ) {
18 (*argv)++;
19 debug |= atoi( *argv );
20 debug |= ANYDEBUG;
21# ifdef DEBUG
22 printf( "[main] debug = %d\n" , debug );
23# endif DEBUG
3f722622
PK
24 } else if ( **argv == 'a' ) {
25 aflag++;
29da1d26
PK
26 } else if ( **argv == 'c' ) {
27 cflag++;
3f722622
PK
28 } else if ( **argv == 'z' ) {
29 zflg++;
3966d652
PK
30 }
31 argv++;
32 }
33 if ( *argv != 0 ) {
34 a_outname = *argv;
35 argv++;
36 } else {
37 a_outname = A_OUTNAME;
38 }
39 if ( *argv != 0 ) {
31f0a970 40 gmonname = *argv;
3966d652
PK
41 argv++;
42 } else {
31f0a970 43 gmonname = GMONNAME;
3966d652
PK
44 }
45 /*
46 * get information about a.out file.
47 */
48 getnfile();
49 /*
50 * get information about mon.out file(s).
51 */
31f0a970 52 getpfile( gmonname );
3966d652
PK
53 /*
54 * assign samples to procedures
55 */
56 asgnsamples();
57 /*
58 * print the usual profile
59 */
60 printprof();
61 /*
62 * assemble and print the dynamic profile
63 */
64 doarcs();
65 done();
66}
67
3966d652
PK
68/*
69 * Set up string and symbol tables from a.out.
29da1d26 70 * and optionally the text space.
3966d652
PK
71 * On return symbol table is sorted by value.
72 */
73getnfile()
74{
75 FILE *nfile;
76
77 nfile = fopen( a_outname ,"r");
78 if (nfile == NULL) {
79 perror( a_outname );
80 done();
81 }
82 fread(&xbuf, 1, sizeof(xbuf), nfile);
83 if (N_BADMAG(xbuf)) {
84 fprintf(stderr, "%s: bad format\n", a_outname );
85 done();
86 }
87 getstrtab(nfile);
88 getsymtab(nfile);
29da1d26 89 gettextspace( nfile );
3966d652
PK
90 qsort(nl, nname, sizeof(nltype), valcmp);
91 fclose(nfile);
92# ifdef DEBUG
93 if ( debug & AOUTDEBUG ) {
94 register int j;
95
96 for (j = 0; j < nname; j++){
97 printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name);
98 }
99 }
100# endif DEBUG
101}
102
103getstrtab(nfile)
104 FILE *nfile;
105{
106
107 fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
108 if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
109 fprintf(stderr, "%s: no string table (old format?)\n", a_outname );
110 done();
111 }
112 strtab = (char *)calloc(ssiz, 1);
113 if (strtab == NULL) {
114 fprintf(stderr, "%s: no room for %d bytes of string table",
115 a_outname , ssiz);
116 done();
117 }
118 if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
119 fprintf(stderr, "%s: error reading string table\n", a_outname );
120 done();
121 }
122}
123
124 /*
125 * Read in symbol table
126 */
127getsymtab(nfile)
128 FILE *nfile;
129{
130 register long i;
131 int askfor;
132 struct nlist nbuf;
133
134 /* pass1 - count symbols */
135 fseek(nfile, (long)N_SYMOFF(xbuf), 0);
136 nname = 0;
137 for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
138 fread(&nbuf, sizeof(nbuf), 1, nfile);
3f722622 139 if ( ! funcsymbol( &nbuf ) ) {
3966d652
PK
140 continue;
141 }
142 nname++;
143 }
144 if (nname == 0) {
145 fprintf(stderr, "%s: no symbols\n", a_outname );
146 done();
147 }
148 /*
149 * ask also for CYCLEFRACTION extra namelist entries for
150 * cycle entries. these hide out at the end of the namelist
151 * and aren't accessed unless the whole namelist (nname+ncycles)
152 * is sorted and searched.
153 */
154 ncycles = nname * CYCLEFRACTION;
155 askfor = nname + 1 + ncycles;
156 nl = (nltype *) calloc( askfor , sizeof(nltype) );
157 if (nl == 0) {
158 fprintf(stderr, "prof: No room for %d bytes of symbol table\n",
159 askfor * sizeof(nltype) );
160 done();
161 }
162
163 /* pass2 - read symbols */
164 fseek(nfile, (long)N_SYMOFF(xbuf), 0);
165 npe = nl;
166 nname = 0;
167 for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
168 fread(&nbuf, sizeof(nbuf), 1, nfile);
3f722622
PK
169 if ( ! funcsymbol( &nbuf ) ) {
170# ifdef DEBUG
171 if ( debug & AOUTDEBUG ) {
172 printf( "[getsymtab] rejecting: 0x%x %s\n" ,
173 nbuf.n_type , strtab + nbuf.n_un.n_strx );
174 }
175# endif DEBUG
3966d652
PK
176 continue;
177 }
178 npe->value = nbuf.n_value;
179 npe->name = strtab+nbuf.n_un.n_strx;
180# ifdef DEBUG
181 if ( debug & AOUTDEBUG ) {
182 printf( "[getsymtab] %d %s 0x%08x\n" ,
183 nname , npe -> name , npe -> value );
184 }
185# endif DEBUG
186 npe++;
187 nname++;
188 }
189 npe->value = -1;
190 npe++;
191}
192
29da1d26
PK
193 /*
194 * read in the text space of an a.out file
195 */
196gettextspace( nfile )
197 FILE *nfile;
198{
199 unsigned char *malloc();
200
201 if ( cflag == 0 ) {
202 return;
203 }
204 textspace = malloc( xbuf.a_text );
205 if ( textspace == 0 ) {
206 fprintf( stderr , "gprof: ran out room for %d bytes of text space: " );
207 fprintf( stderr , "can't do -c\n" , xbuf.a_text );
208 return;
209 }
210 (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 );
211 if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) {
212 fprintf( stderr , "couldn't read text space: " );
213 fprintf( stderr , "can't do -c\n" , xbuf.a_text );
214 free( textspace );
215 textspace = 0;
216 return;
217 }
218}
3966d652 219 /*
31f0a970 220 * information from a gmon.out file is in two parts:
3966d652
PK
221 * an array of sampling hits within pc ranges,
222 * and the arcs.
223 */
224getpfile(filename)
225 char *filename;
226{
227 FILE *pfile;
228 FILE *openpfile();
229 struct rawarc arc;
230
231 pfile = openpfile(filename);
232 readsamples(pfile);
233 /*
234 * the rest of the file consists of
235 * a bunch of <from,self,count> tuples.
236 */
237 while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
238# ifdef DEBUG
239 if ( debug & SAMPLEDEBUG ) {
06ac0fb1 240 printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" ,
3966d652
PK
241 arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
242 }
243# endif DEBUG
244 /*
245 * add this arc
246 */
247 tally( &arc );
248 }
249 fclose(pfile);
250}
251
35e3e365
PK
252FILE *
253openpfile(filename)
3966d652
PK
254 char *filename;
255{
256 FILE *pfile;
257
258 if((pfile = fopen(filename, "r")) == NULL) {
259 perror(filename);
260 done();
261 }
262 fread(&h, sizeof(struct hdr), 1, pfile);
06ac0fb1
PK
263 s_lowpc = (unsigned long) h.lowpc;
264 s_highpc = (unsigned long) h.highpc;
3966d652
PK
265 lowpc = h.lowpc - (UNIT *)0;
266 highpc = h.highpc - (UNIT *)0;
267 sampbytes = h.ncnt - sizeof(struct hdr);
268 nsamples = sampbytes / sizeof (unsigned UNIT);
269 return(pfile);
270}
271
272tally( rawp )
273 struct rawarc *rawp;
274{
275 nltype *parentp;
276 nltype *childp;
3966d652
PK
277
278 parentp = nllookup( rawp -> raw_frompc );
279 childp = nllookup( rawp -> raw_selfpc );
280 childp -> ncall += rawp -> raw_count;
281# ifdef DEBUG
282 if ( debug & TALLYDEBUG ) {
283 printf( "[tally] arc from %s to %s traversed %d times\n" ,
284 parentp -> name , childp -> name , rawp -> raw_count );
285 }
286# endif DEBUG
29da1d26 287 addarc( parentp , childp , rawp -> raw_count );
3966d652
PK
288}
289
290valcmp(p1, p2)
291 nltype *p1, *p2;
292{
293 if ( p1 -> value < p2 -> value ) {
294 return LESSTHAN;
295 }
296 if ( p1 -> value > p2 -> value ) {
297 return GREATERTHAN;
298 }
299 return EQUALTO;
300}
301
302readsamples(pfile)
303 FILE *pfile;
304{
305 register i;
306 unsigned UNIT sample;
307
308 if (samples == 0) {
309 samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT));
310 if (samples == 0) {
311 fprintf( stderr , "prof: No room for %d sample pc's\n",
312 sampbytes / sizeof (unsigned UNIT));
313 done();
314 }
315 }
316 for (i = 0; i < nsamples; i++) {
317 fread(&sample, sizeof (unsigned UNIT), 1, pfile);
318 if (feof(pfile))
319 break;
320 samples[i] += sample;
321 }
322 if (i != nsamples) {
323 fprintf(stderr,
324 "prof: unexpected EOF after reading %d/%d samples\n",
325 --i, nsamples);
326 done();
327 }
328}
329
330/*
331 * Assign samples to the procedures to which they belong.
332 */
333asgnsamples()
334{
335 register int j;
336 unsigned UNIT ccnt;
337 double time;
338 unsigned long pcl, pch;
339 register int i;
35e3e365 340 unsigned long overlap;
3966d652
PK
341 unsigned long svalue0, svalue1;
342
343 /* read samples and assign to namelist symbols */
344 scale = highpc - lowpc;
345 scale /= nsamples;
346 for (i=0; i < nsamples; i++) {
347 ccnt = samples[i];
348 if (ccnt == 0)
349 continue;
350 pcl = lowpc + scale*i;
351 pch = lowpc + scale*(i+1);
352 time = ccnt;
353# ifdef DEBUG
354 if ( debug & SAMPLEDEBUG ) {
355 printf( "[asgnsamples] ccnt %d time %f totime %f\n" ,
356 ccnt , time , totime );
357 }
358# endif DEBUG
359 totime += time;
360 for (j=0; j<nname; j++) {
361 svalue0 = nl[j].value / sizeof(UNIT);
362 svalue1 = nl[j+1].value / sizeof(UNIT);
363 if (pch < svalue0)
364 break;
365 if (pcl >= svalue1)
366 continue;
367 overlap=min(pch,svalue1) - max(pcl,svalue0);
368 if (overlap>0) {
369# ifdef DEBUG
370 if ( debug & SAMPLEDEBUG ) {
371 printf( "[asgnsamples] %s gets %f ticks\n" ,
372 nl[j].name , overlap*time/scale );
373 }
374# endif DEBUG
375 nl[j].time += overlap*time/scale;
376 }
377 }
378 }
379# ifdef DEBUG
380 if ( debug & SAMPLEDEBUG ) {
381 printf( "[asgnsamples] totime %f\n" , totime );
382 }
383# endif DEBUG
384 if (totime==0.0) {
385 fprintf( stderr , "No time accumulated\n" );
386 totime=1.0;
387 }
388}
389
390
35e3e365 391unsigned long
3966d652 392min(a, b)
35e3e365 393 unsigned long a,b;
3966d652
PK
394{
395 if (a<b)
396 return(a);
397 return(b);
398}
399
35e3e365 400unsigned long
3966d652 401max(a, b)
35e3e365 402 unsigned long a,b;
3966d652
PK
403{
404 if (a>b)
405 return(a);
406 return(b);
407}
408
3f722622
PK
409bool
410funcsymbol( nlistp )
411 struct nlist *nlistp;
412{
413 extern char *strtab; /* string table from a.out */
414 extern int aflag; /* if static functions desired */
415 char *name;
416
417 /*
418 * must be a text symbol,
419 * and static text symbols qualify if aflag set.
420 */
421 if ( ! ( ( nlistp -> n_type == ( N_TEXT | N_EXT ) )
422 || ( ( nlistp -> n_type == N_TEXT ) && aflag ) ) ) {
423 return FALSE;
424 }
425 /*
426 * can't have any `funny characters in name,
427 * where `funny' includes `.', .o file names
428 * and `$', pascal labels.
429 */
430 for ( name = strtab + nlistp -> n_un.n_strx ; *name ; name += 1 ) {
431 if ( *name == '.' || *name == '$' ) {
432 return FALSE;
433 }
434 }
435 return TRUE;
436}
437
3966d652
PK
438done()
439{
440
441 exit(0);
442}