allow only /bin/csh, not /bin/oldcsh
[unix-history] / usr / src / usr.bin / gprof / gprof.c
CommitLineData
3966d652 1#ifndef lint
0fcb1e15 2 static char *sccsid = "@(#)gprof.c 1.18 (Berkeley) %G%";
3966d652
PK
3#endif lint
4
31f0a970 5#include "gprof.h"
3966d652 6
ad3b82ad
PK
7char *whoami = "gprof";
8
a441395b
PK
9 /*
10 * things which get -E excluded by default.
11 */
12char *defaultEs[] = { "mcount" , "__mcleanup" , 0 };
7ec9eedc 13
3966d652 14main(argc, argv)
7ec9eedc
PK
15 int argc;
16 char **argv;
3966d652 17{
7ec9eedc 18 char **sp;
3966d652
PK
19
20 --argc;
21 argv++;
22 debug = 0;
23 while ( *argv != 0 && **argv == '-' ) {
24 (*argv)++;
0c0ac747 25 switch ( **argv ) {
7ec9eedc
PK
26 case 'a':
27 aflag = TRUE;
28 break;
29 case 'b':
30 bflag = TRUE;
31 break;
32 case 'c':
33 cflag = TRUE;
34 break;
0c0ac747 35 case 'd':
7ec9eedc 36 dflag = TRUE;
3966d652
PK
37 (*argv)++;
38 debug |= atoi( *argv );
39 debug |= ANYDEBUG;
40# ifdef DEBUG
41 printf( "[main] debug = %d\n" , debug );
42# endif DEBUG
0c0ac747 43 break;
a441395b
PK
44 case 'E':
45 ++argv;
46 addlist( Elist , *argv );
47 Eflag = TRUE;
48 addlist( elist , *argv );
49 eflag = TRUE;
50 break;
7ec9eedc 51 case 'e':
a441395b 52 addlist( elist , *++argv );
7ec9eedc 53 eflag = TRUE;
a441395b
PK
54 break;
55 case 'F':
56 ++argv;
57 addlist( Flist , *argv );
58 Fflag = TRUE;
59 addlist( flist , *argv );
60 fflag = TRUE;
0c0ac747 61 break;
7ec9eedc 62 case 'f':
a441395b 63 addlist( flist , *++argv );
7ec9eedc 64 fflag = TRUE;
0c0ac747
KM
65 break;
66 case 's':
7ec9eedc 67 sflag = TRUE;
0c0ac747
KM
68 break;
69 case 'z':
7ec9eedc 70 zflag = TRUE;
0c0ac747 71 break;
3966d652
PK
72 }
73 argv++;
74 }
75 if ( *argv != 0 ) {
76 a_outname = *argv;
77 argv++;
78 } else {
79 a_outname = A_OUTNAME;
80 }
81 if ( *argv != 0 ) {
31f0a970 82 gmonname = *argv;
3966d652
PK
83 argv++;
84 } else {
31f0a970 85 gmonname = GMONNAME;
7ec9eedc
PK
86 }
87 /*
88 * turn off default functions
89 */
a441395b
PK
90 for ( sp = &defaultEs[0] ; *sp ; sp++ ) {
91 Eflag = TRUE;
92 addlist( Elist , *sp );
7ec9eedc 93 eflag = TRUE;
a441395b 94 addlist( elist , *sp );
3966d652
PK
95 }
96 /*
97 * get information about a.out file.
98 */
99 getnfile();
100 /*
101 * get information about mon.out file(s).
102 */
0c0ac747
KM
103 do {
104 getpfile( gmonname );
105 if ( *argv != 0 ) {
106 gmonname = *argv;
107 }
ad3b82ad 108 } while ( *argv++ != 0 );
0c0ac747
KM
109 /*
110 * dump out a gmon.sum file if requested
111 */
ad3b82ad
PK
112 if ( sflag ) {
113 dumpsum( GMONSUM );
114 }
3966d652
PK
115 /*
116 * assign samples to procedures
117 */
118 asgnsamples();
119 /*
120 * print the usual profile
121 */
122 printprof();
123 /*
124 * assemble and print the dynamic profile
125 */
126 doarcs();
127 done();
128}
129
ad3b82ad
PK
130 /*
131 * Set up string and symbol tables from a.out.
132 * and optionally the text space.
133 * On return symbol table is sorted by value.
134 */
3966d652
PK
135getnfile()
136{
137 FILE *nfile;
138
139 nfile = fopen( a_outname ,"r");
140 if (nfile == NULL) {
141 perror( a_outname );
142 done();
143 }
144 fread(&xbuf, 1, sizeof(xbuf), nfile);
145 if (N_BADMAG(xbuf)) {
ad3b82ad 146 fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname );
3966d652
PK
147 done();
148 }
149 getstrtab(nfile);
150 getsymtab(nfile);
29da1d26 151 gettextspace( nfile );
3966d652
PK
152 qsort(nl, nname, sizeof(nltype), valcmp);
153 fclose(nfile);
154# ifdef DEBUG
155 if ( debug & AOUTDEBUG ) {
156 register int j;
157
158 for (j = 0; j < nname; j++){
159 printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name);
160 }
161 }
162# endif DEBUG
163}
164
165getstrtab(nfile)
166 FILE *nfile;
167{
168
169 fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
170 if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
ad3b82ad
PK
171 fprintf(stderr, "%s: %s: no string table (old format?)\n" ,
172 whoami , a_outname );
3966d652
PK
173 done();
174 }
175 strtab = (char *)calloc(ssiz, 1);
176 if (strtab == NULL) {
ad3b82ad
PK
177 fprintf(stderr, "%s: %s: no room for %d bytes of string table",
178 whoami , a_outname , ssiz);
3966d652
PK
179 done();
180 }
181 if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
ad3b82ad
PK
182 fprintf(stderr, "%s: %s: error reading string table\n",
183 whoami , a_outname );
3966d652
PK
184 done();
185 }
186}
187
188 /*
189 * Read in symbol table
190 */
191getsymtab(nfile)
192 FILE *nfile;
193{
194 register long i;
195 int askfor;
196 struct nlist nbuf;
197
198 /* pass1 - count symbols */
199 fseek(nfile, (long)N_SYMOFF(xbuf), 0);
200 nname = 0;
201 for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
202 fread(&nbuf, sizeof(nbuf), 1, nfile);
3f722622 203 if ( ! funcsymbol( &nbuf ) ) {
3966d652
PK
204 continue;
205 }
206 nname++;
207 }
208 if (nname == 0) {
ad3b82ad 209 fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname );
3966d652
PK
210 done();
211 }
ad3b82ad 212 askfor = nname + 1;
3966d652
PK
213 nl = (nltype *) calloc( askfor , sizeof(nltype) );
214 if (nl == 0) {
ad3b82ad
PK
215 fprintf(stderr, "%s: No room for %d bytes of symbol table\n",
216 whoami, askfor * sizeof(nltype) );
3966d652
PK
217 done();
218 }
219
220 /* pass2 - read symbols */
221 fseek(nfile, (long)N_SYMOFF(xbuf), 0);
222 npe = nl;
223 nname = 0;
224 for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
225 fread(&nbuf, sizeof(nbuf), 1, nfile);
3f722622
PK
226 if ( ! funcsymbol( &nbuf ) ) {
227# ifdef DEBUG
228 if ( debug & AOUTDEBUG ) {
229 printf( "[getsymtab] rejecting: 0x%x %s\n" ,
230 nbuf.n_type , strtab + nbuf.n_un.n_strx );
231 }
232# endif DEBUG
3966d652
PK
233 continue;
234 }
235 npe->value = nbuf.n_value;
236 npe->name = strtab+nbuf.n_un.n_strx;
237# ifdef DEBUG
238 if ( debug & AOUTDEBUG ) {
239 printf( "[getsymtab] %d %s 0x%08x\n" ,
240 nname , npe -> name , npe -> value );
241 }
242# endif DEBUG
243 npe++;
244 nname++;
245 }
246 npe->value = -1;
247 npe++;
248}
249
29da1d26
PK
250 /*
251 * read in the text space of an a.out file
252 */
253gettextspace( nfile )
254 FILE *nfile;
255{
256 unsigned char *malloc();
257
258 if ( cflag == 0 ) {
259 return;
260 }
261 textspace = malloc( xbuf.a_text );
262 if ( textspace == 0 ) {
ad3b82ad
PK
263 fprintf( stderr , "%s: ran out room for %d bytes of text space: " ,
264 whoami , xbuf.a_text );
265 fprintf( stderr , "can't do -c\n" );
29da1d26
PK
266 return;
267 }
268 (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 );
269 if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) {
ad3b82ad
PK
270 fprintf( stderr , "%s: couldn't read text space: " , whoami );
271 fprintf( stderr , "can't do -c\n" );
29da1d26
PK
272 free( textspace );
273 textspace = 0;
274 return;
275 }
276}
3966d652 277 /*
31f0a970 278 * information from a gmon.out file is in two parts:
3966d652
PK
279 * an array of sampling hits within pc ranges,
280 * and the arcs.
281 */
282getpfile(filename)
283 char *filename;
284{
285 FILE *pfile;
286 FILE *openpfile();
287 struct rawarc arc;
288
289 pfile = openpfile(filename);
290 readsamples(pfile);
291 /*
292 * the rest of the file consists of
293 * a bunch of <from,self,count> tuples.
294 */
295 while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
296# ifdef DEBUG
297 if ( debug & SAMPLEDEBUG ) {
06ac0fb1 298 printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" ,
3966d652
PK
299 arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
300 }
301# endif DEBUG
302 /*
303 * add this arc
304 */
305 tally( &arc );
306 }
307 fclose(pfile);
308}
309
35e3e365
PK
310FILE *
311openpfile(filename)
3966d652
PK
312 char *filename;
313{
0c0ac747 314 struct hdr tmp;
3966d652
PK
315 FILE *pfile;
316
317 if((pfile = fopen(filename, "r")) == NULL) {
318 perror(filename);
319 done();
320 }
0c0ac747
KM
321 fread(&tmp, sizeof(struct hdr), 1, pfile);
322 if ( s_highpc != 0 && ( tmp.lowpc != h.lowpc ||
323 tmp.highpc != h.highpc || tmp.ncnt != h.ncnt ) ) {
324 fprintf(stderr, "%s: incompatible with first gmon file\n", filename);
325 done();
326 }
327 h = tmp;
06ac0fb1
PK
328 s_lowpc = (unsigned long) h.lowpc;
329 s_highpc = (unsigned long) h.highpc;
6d94fded
KM
330 lowpc = (unsigned long)h.lowpc / sizeof(UNIT);
331 highpc = (unsigned long)h.highpc / sizeof(UNIT);
3966d652
PK
332 sampbytes = h.ncnt - sizeof(struct hdr);
333 nsamples = sampbytes / sizeof (unsigned UNIT);
33e41a83
PK
334# ifdef DEBUG
335 if ( debug & SAMPLEDEBUG ) {
336 printf( "[openpfile] hdr.lowpc 0x%x hdr.highpc 0x%x hdr.ncnt %d\n",
337 h.lowpc , h.highpc , h.ncnt );
338 printf( "[openpfile] s_lowpc 0x%x s_highpc 0x%x\n" ,
339 s_lowpc , s_highpc );
340 printf( "[openpfile] lowpc 0x%x highpc 0x%x\n" ,
341 lowpc , highpc );
342 printf( "[openpfile] sampbytes %d nsamples %d\n" ,
343 sampbytes , nsamples );
344 }
345# endif DEBUG
3966d652
PK
346 return(pfile);
347}
348
349tally( rawp )
350 struct rawarc *rawp;
351{
352 nltype *parentp;
353 nltype *childp;
3966d652
PK
354
355 parentp = nllookup( rawp -> raw_frompc );
356 childp = nllookup( rawp -> raw_selfpc );
357 childp -> ncall += rawp -> raw_count;
358# ifdef DEBUG
359 if ( debug & TALLYDEBUG ) {
360 printf( "[tally] arc from %s to %s traversed %d times\n" ,
361 parentp -> name , childp -> name , rawp -> raw_count );
362 }
363# endif DEBUG
29da1d26 364 addarc( parentp , childp , rawp -> raw_count );
3966d652
PK
365}
366
0c0ac747
KM
367/*
368 * dump out the gmon.sum file
369 */
370dumpsum( sumfile )
371 char *sumfile;
372{
373 register nltype *nlp;
374 register arctype *arcp;
375 struct rawarc arc;
376 FILE *sfile;
377
378 if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) {
379 perror( sumfile );
380 done();
381 }
382 /*
383 * dump the header; use the last header read in
384 */
385 if ( fwrite( &h , sizeof h , 1 , sfile ) != 1 ) {
386 perror( sumfile );
387 done();
388 }
389 /*
390 * dump the samples
391 */
392 if (fwrite(samples, sizeof(unsigned UNIT), nsamples, sfile) != nsamples) {
393 perror( sumfile );
394 done();
395 }
396 /*
397 * dump the normalized raw arc information
398 */
399 for ( nlp = nl ; nlp < npe - 1 ; nlp++ ) {
400 for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
401 arc.raw_frompc = arcp -> arc_parentp -> value;
402 arc.raw_selfpc = arcp -> arc_childp -> value;
403 arc.raw_count = arcp -> arc_count;
404 if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) {
405 perror( sumfile );
406 done();
407 }
408# ifdef DEBUG
409 if ( debug & SAMPLEDEBUG ) {
410 printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" ,
411 arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
412 }
413# endif DEBUG
414 }
415 }
416 fclose( sfile );
417}
418
3966d652
PK
419valcmp(p1, p2)
420 nltype *p1, *p2;
421{
422 if ( p1 -> value < p2 -> value ) {
423 return LESSTHAN;
424 }
425 if ( p1 -> value > p2 -> value ) {
426 return GREATERTHAN;
427 }
428 return EQUALTO;
429}
430
431readsamples(pfile)
432 FILE *pfile;
433{
434 register i;
435 unsigned UNIT sample;
436
437 if (samples == 0) {
438 samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT));
439 if (samples == 0) {
ad3b82ad
PK
440 fprintf( stderr , "%s: No room for %d sample pc's\n",
441 whoami , sampbytes / sizeof (unsigned UNIT));
3966d652
PK
442 done();
443 }
444 }
445 for (i = 0; i < nsamples; i++) {
446 fread(&sample, sizeof (unsigned UNIT), 1, pfile);
447 if (feof(pfile))
448 break;
449 samples[i] += sample;
450 }
451 if (i != nsamples) {
452 fprintf(stderr,
ad3b82ad
PK
453 "%s: unexpected EOF after reading %d/%d samples\n",
454 whoami , --i , nsamples );
3966d652
PK
455 done();
456 }
457}
458
459/*
460 * Assign samples to the procedures to which they belong.
461 */
462asgnsamples()
463{
464 register int j;
465 unsigned UNIT ccnt;
466 double time;
467 unsigned long pcl, pch;
468 register int i;
35e3e365 469 unsigned long overlap;
3966d652
PK
470 unsigned long svalue0, svalue1;
471
472 /* read samples and assign to namelist symbols */
473 scale = highpc - lowpc;
474 scale /= nsamples;
0fcb1e15 475 for (i = 0, j = 1; i < nsamples; i++) {
3966d652
PK
476 ccnt = samples[i];
477 if (ccnt == 0)
478 continue;
479 pcl = lowpc + scale*i;
480 pch = lowpc + scale*(i+1);
481 time = ccnt;
482# ifdef DEBUG
483 if ( debug & SAMPLEDEBUG ) {
eb6d6a16
KM
484 printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" ,
485 pcl , pch , ccnt );
3966d652
PK
486 }
487# endif DEBUG
488 totime += time;
16051da5 489 for (j = j - 1; j < nname; j++) {
3966d652
PK
490 svalue0 = nl[j].value / sizeof(UNIT);
491 svalue1 = nl[j+1].value / sizeof(UNIT);
492 if (pch < svalue0)
493 break;
494 if (pcl >= svalue1)
495 continue;
496 overlap=min(pch,svalue1) - max(pcl,svalue0);
497 if (overlap>0) {
498# ifdef DEBUG
499 if ( debug & SAMPLEDEBUG ) {
eb6d6a16
KM
500 printf( "[asgnsamples] (0x%x-0x%x) %s gets %f ticks\n" ,
501 svalue0 , svalue1 , nl[j].name ,
502 overlap*time/scale );
3966d652
PK
503 }
504# endif DEBUG
505 nl[j].time += overlap*time/scale;
506 }
507 }
508 }
509# ifdef DEBUG
510 if ( debug & SAMPLEDEBUG ) {
511 printf( "[asgnsamples] totime %f\n" , totime );
512 }
513# endif DEBUG
3966d652
PK
514}
515
516
35e3e365 517unsigned long
3966d652 518min(a, b)
35e3e365 519 unsigned long a,b;
3966d652
PK
520{
521 if (a<b)
522 return(a);
523 return(b);
524}
525
35e3e365 526unsigned long
3966d652 527max(a, b)
35e3e365 528 unsigned long a,b;
3966d652
PK
529{
530 if (a>b)
531 return(a);
532 return(b);
533}
534
3f722622
PK
535bool
536funcsymbol( nlistp )
537 struct nlist *nlistp;
538{
539 extern char *strtab; /* string table from a.out */
d51dad81 540 extern int aflag; /* if static functions aren't desired */
3f722622
PK
541 char *name;
542
543 /*
544 * must be a text symbol,
d51dad81 545 * and static text symbols don't qualify if aflag set.
3f722622
PK
546 */
547 if ( ! ( ( nlistp -> n_type == ( N_TEXT | N_EXT ) )
d51dad81 548 || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) {
3f722622
PK
549 return FALSE;
550 }
551 /*
ad3b82ad 552 * can't have any `funny' characters in name,
3f722622
PK
553 * where `funny' includes `.', .o file names
554 * and `$', pascal labels.
555 */
556 for ( name = strtab + nlistp -> n_un.n_strx ; *name ; name += 1 ) {
557 if ( *name == '.' || *name == '$' ) {
558 return FALSE;
559 }
560 }
561 return TRUE;
562}
563
3966d652
PK
564done()
565{
566
567 exit(0);
568}