Fixed bugs (both typos and algorithmic) bugs. It now matches native gprof's
[external/binutils.git] / gprof / gprof.c
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that: (1) source distributions retain this entire copyright
7  * notice and comment, and (2) distributions including binaries display
8  * the following acknowledgement:  ``This product includes software
9  * developed by the University of California, Berkeley and its contributors''
10  * in the documentation or other materials provided with the distribution
11  * and in all advertising materials mentioning features or use of this
12  * software. Neither the name of the University nor the names of its
13  * contributors may be used to endorse or promote products derived
14  * from this software without specific prior written permission.
15  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18  */
19
20 #ifndef lint
21 char copyright[] =
22 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
23  All rights reserved.\n";
24 #endif /* not lint */
25
26 #ifndef lint
27 static char sccsid[] = "@(#)gprof.c     5.6 (Berkeley) 6/1/90";
28 #endif /* not lint */
29
30 #include "gprof.h"
31
32 bfd     *abfd;
33
34 char    *whoami = "gprof";
35
36     /*
37      *  things which get -E excluded by default.
38      */
39 char    *defaultEs[] = { "mcount" , "__mcleanup" , 0 };
40
41 main(argc, argv)
42     int argc;
43     char **argv;
44 {
45     char        **sp;
46     nltype      **timesortnlp;
47
48     --argc;
49     argv++;
50     debug = 0;
51     bflag = TRUE;
52     while ( *argv != 0 && **argv == '-' ) {
53         (*argv)++;
54         switch ( **argv ) {
55         case 'a':
56             aflag = TRUE;
57             break;
58         case 'b':
59             bflag = FALSE;
60             break;
61         case 'c':
62             cflag = TRUE;
63             break;
64         case 'd':
65             dflag = TRUE;
66             (*argv)++;
67             debug |= atoi( *argv );
68             debug |= ANYDEBUG;
69 #           ifdef DEBUG
70                 printf("[main] debug = %d\n", debug);
71 #           else not DEBUG
72                 printf("%s: -d ignored\n", whoami);
73 #           endif DEBUG
74             break;
75         case 'E':
76             ++argv;
77             addlist( Elist , *argv );
78             Eflag = TRUE;
79             addlist( elist , *argv );
80             eflag = TRUE;
81             break;
82         case 'e':
83             addlist( elist , *++argv );
84             eflag = TRUE;
85             break;
86         case 'F':
87             ++argv;
88             addlist( Flist , *argv );
89             Fflag = TRUE;
90             addlist( flist , *argv );
91             fflag = TRUE;
92             break;
93         case 'f':
94             addlist( flist , *++argv );
95             fflag = TRUE;
96             break;
97         case 'k':
98             addlist( kfromlist , *++argv );
99             addlist( ktolist , *++argv );
100             kflag = TRUE;
101             break;
102         case 's':
103             sflag = TRUE;
104             break;
105         case 'z':
106             zflag = TRUE;
107             break;
108         }
109         argv++;
110     }
111     if ( *argv != 0 ) {
112         a_outname  = *argv;
113         argv++;
114     } else {
115         a_outname  = A_OUTNAME;
116     }
117     if ( *argv != 0 ) {
118         gmonname = *argv;
119         argv++;
120     } else {
121         gmonname = GMONNAME;
122     }
123         /*
124          *      turn off default functions
125          */
126     for ( sp = &defaultEs[0] ; *sp ; sp++ ) {
127         Eflag = TRUE;
128         addlist( Elist , *sp );
129         eflag = TRUE;
130         addlist( elist , *sp );
131     }
132         /*
133          *      how many ticks per second?
134          *      if we can't tell, report time in ticks.
135          */
136     hz = hertz();
137     if (hz == 0) {
138         hz = 1;
139         fprintf(stderr, "time is in ticks, not seconds\n");
140     }
141         /*
142          *      get information about a.out file.
143          */
144     getnfile();
145         /*
146          *      get information about mon.out file(s).
147          */
148     do  {
149         getpfile( gmonname );
150         if ( *argv != 0 ) {
151             gmonname = *argv;
152         }
153     } while ( *argv++ != 0 );
154         /*
155          *      dump out a gmon.sum file if requested
156          */
157     if ( sflag ) {
158         dumpsum( GMONSUM );
159     }
160         /*
161          *      assign samples to procedures
162          */
163     asgnsamples();
164         /*
165          *      assemble the dynamic profile
166          */
167     timesortnlp = doarcs();
168         /*
169          *      print the dynamic profile
170          */
171     printgprof( timesortnlp );  
172         /*
173          *      print the flat profile
174          */
175     printprof();        
176         /*
177          *      print the index
178          */
179     printindex();       
180     done();
181 }
182
183     /*
184      * Set up string and symbol tables from a.out.
185      *  and optionally the text space.
186      * On return symbol table is sorted by value.
187      */
188 getnfile()
189 {
190   int           valcmp();
191
192   abfd = bfd_openr (a_outname, NULL);
193
194   if (abfd == NULL) {
195     perror (a_outname);
196     done();
197   }
198
199   if (!bfd_check_format (abfd, bfd_object)) {
200     fprintf (stderr, "%s: %s: bad format\n", whoami, a_outname);
201     done();
202   }
203
204 /*  getstrtab(nfile); */
205   getsymtab(abfd);
206   gettextspace( abfd );
207   qsort(nl, nname, sizeof(nltype), valcmp);
208
209 #   ifdef DEBUG
210   if ( debug & AOUTDEBUG ) {
211     register int j;
212     
213     for (j = 0; j < nname; j++){
214       printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name);
215     }
216   }
217 #   endif DEBUG
218 }
219
220 /*
221  * Read in symbol table
222  */
223 getsymtab(abfd)
224 bfd     *abfd;
225 {
226     register long       i;
227     int                 askfor;
228     int                 nosyms;
229     asymbol             **syms;
230     i = get_symtab_upper_bound (abfd);  /* This will probably give us more
231                                          * than we need, but that's ok.
232                                          */
233     syms = malloc (i);
234     nosyms = bfd_canonicalize_symtab (abfd, syms);
235
236     nname = 0;
237     for (i = 0; i < nosyms; i++) {
238       if (!funcsymbol (syms[i]))
239         continue;
240       nname++;
241     }
242
243     if (nname == 0) {
244       fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname );
245       done();
246     }
247     askfor = nname + 1;
248     nl = (nltype *) calloc( askfor , sizeof(nltype) );
249     if (nl == 0) {
250         fprintf(stderr, "%s: No room for %d bytes of symbol table\n",
251                 whoami, askfor * sizeof(nltype) );
252         done();
253     }
254
255     /* pass2 - read symbols */
256     npe = nl;
257     nname = 0;
258     for (i = 0; i < nosyms; i++) {
259       if (!funcsymbol (syms[i])) {
260 #           ifdef DEBUG
261         if ( debug & AOUTDEBUG ) {
262           printf( "[getsymtab] rejecting: 0x%x %s\n" ,
263                  syms[i]->value, syms[i]->name);
264         }
265 #           endif DEBUG
266         continue;
267       }
268       npe->value = syms[i]->value + syms[i]->section->vma;
269       npe->name = syms[i]->name;
270 #       ifdef DEBUG
271       if ( debug & AOUTDEBUG ) {
272         printf( "[getsymtab] %d %s 0x%08x\n" ,
273                nname , npe -> name , npe -> value );
274       }
275 #       endif DEBUG
276       npe++;
277       nname++;
278     }
279     npe->value = -1;
280 }
281
282 /*
283  *      read in the text space of an a.out file
284  */
285 gettextspace( abfd )
286      bfd        *abfd;
287 {
288   asection      *texsec;
289     
290   if ( cflag == 0 ) {
291     return;
292   }
293
294   texsec = bfd_get_section_by_name (abfd, ".text");
295   if (texsec == NULL) {
296     return;
297   }
298
299   textspace = (u_char *) malloc( texsec->_cooked_size );
300
301   if ( textspace == 0 ) {
302     fprintf( stderr , "%s: ran out room for %d bytes of text space:  " ,
303             whoami , texsec->_cooked_size);
304     fprintf( stderr , "can't do -c\n" );
305     return;
306   }
307   bfd_get_section_contents (abfd, texsec, textspace, texsec->filepos, 
308                             texsec->_cooked_size);
309 }
310 /*
311  *      information from a gmon.out file is in two parts:
312  *      an array of sampling hits within pc ranges,
313  *      and the arcs.
314  */
315 getpfile(filename)
316     char *filename;
317 {
318     FILE                *pfile;
319     FILE                *openpfile();
320     struct rawarc       arc;
321
322     pfile = openpfile(filename);
323     readsamples(pfile);
324         /*
325          *      the rest of the file consists of
326          *      a bunch of <from,self,count> tuples.
327          */
328     while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
329       arc.raw_frompc = bfd_get_32 (abfd, &arc.raw_frompc);
330       arc.raw_selfpc = bfd_get_32 (abfd, &arc.raw_selfpc);
331       arc.raw_count = bfd_get_32 (abfd, &arc.raw_count);
332 #       ifdef DEBUG
333             if ( debug & SAMPLEDEBUG ) {
334                 printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" ,
335                         arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
336             }
337 #       endif DEBUG
338             /*
339              *  add this arc
340              */
341         tally( &arc );
342     }
343     fclose(pfile);
344 }
345
346 FILE *
347 openpfile(filename)
348     char *filename;
349 {
350     struct hdr  tmp;
351     FILE        *pfile;
352
353     if((pfile = fopen(filename, "r")) == NULL) {
354         perror(filename);
355         done();
356     }
357     fread(&tmp, sizeof(struct hdr), 1, pfile);
358     tmp.lowpc = bfd_get_32 (abfd, &tmp.lowpc);
359     tmp.highpc = bfd_get_32 (abfd, &tmp.highpc);
360     tmp.ncnt = bfd_get_32 (abfd, &tmp.ncnt);
361
362     if ( s_highpc != 0 && ( tmp.lowpc != h.lowpc ||
363          tmp.highpc != h.highpc || tmp.ncnt != h.ncnt ) ) {
364         fprintf(stderr, "%s: incompatible with first gmon file\n", filename);
365         done();
366     }
367     h = tmp;
368     s_lowpc = (unsigned long) h.lowpc;
369     s_highpc = (unsigned long) h.highpc;
370     lowpc = (unsigned long)h.lowpc / sizeof(UNIT);
371     highpc = (unsigned long)h.highpc / sizeof(UNIT);
372     sampbytes = h.ncnt - sizeof(struct hdr);
373     nsamples = sampbytes / sizeof (UNIT);
374 #   ifdef DEBUG
375         if ( debug & SAMPLEDEBUG ) {
376             printf( "[openpfile] hdr.lowpc 0x%x hdr.highpc 0x%x hdr.ncnt %d\n",
377                 h.lowpc , h.highpc , h.ncnt );
378             printf( "[openpfile]   s_lowpc 0x%x   s_highpc 0x%x\n" ,
379                 s_lowpc , s_highpc );
380             printf( "[openpfile]     lowpc 0x%x     highpc 0x%x\n" ,
381                 lowpc , highpc );
382             printf( "[openpfile] sampbytes %d nsamples %d\n" ,
383                 sampbytes , nsamples );
384         }
385 #   endif DEBUG
386     return(pfile);
387 }
388
389 tally( rawp )
390     struct rawarc       *rawp;
391 {
392     nltype              *parentp;
393     nltype              *childp;
394
395     parentp = nllookup( rawp -> raw_frompc );
396     childp = nllookup( rawp -> raw_selfpc );
397     if ( kflag
398          && onlist( kfromlist , parentp -> name )
399          && onlist( ktolist , childp -> name ) ) {
400         return;
401     }
402     childp -> ncall += rawp -> raw_count;
403 #   ifdef DEBUG
404         if ( debug & TALLYDEBUG ) {
405             printf( "[tally] arc from %s to %s traversed %d times\n" ,
406                     parentp -> name , childp -> name , rawp -> raw_count );
407         }
408 #   endif DEBUG
409     addarc( parentp , childp , rawp -> raw_count );
410 }
411
412 /*
413  * dump out the gmon.sum file
414  */
415 dumpsum( sumfile )
416     char *sumfile;
417 {
418     register nltype *nlp;
419     register arctype *arcp;
420     struct rawarc arc;
421     FILE *sfile;
422
423     if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) {
424         perror( sumfile );
425         done();
426     }
427     /*
428      * dump the header; use the last header read in
429      */
430     if ( fwrite( &h , sizeof h , 1 , sfile ) != 1 ) {
431         perror( sumfile );
432         done();
433     }
434     /*
435      * dump the samples
436      */
437     if (fwrite(samples, sizeof (UNIT), nsamples, sfile) != nsamples) {
438         perror( sumfile );
439         done();
440     }
441     /*
442      * dump the normalized raw arc information
443      */
444     for ( nlp = nl ; nlp < npe ; nlp++ ) {
445         for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
446             arc.raw_frompc = arcp -> arc_parentp -> value;
447             arc.raw_selfpc = arcp -> arc_childp -> value;
448             arc.raw_count = arcp -> arc_count;
449             if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) {
450                 perror( sumfile );
451                 done();
452             }
453 #           ifdef DEBUG
454                 if ( debug & SAMPLEDEBUG ) {
455                     printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" ,
456                             arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
457                 }
458 #           endif DEBUG
459         }
460     }
461     fclose( sfile );
462 }
463
464 valcmp(p1, p2)
465     nltype *p1, *p2;
466 {
467     if ( p1 -> value < p2 -> value ) {
468         return LESSTHAN;
469     }
470     if ( p1 -> value > p2 -> value ) {
471         return GREATERTHAN;
472     }
473     return EQUALTO;
474 }
475
476 readsamples(pfile)
477     FILE        *pfile;
478 {
479     register i;
480     UNIT        sample;
481     
482     if (samples == 0) {
483         samples = (UNIT *) malloc (sampbytes * sizeof(UNIT));
484         if (samples == 0) {
485             fprintf( stderr , "%s: No room for %d sample pc's\n", 
486                 whoami , sampbytes / sizeof (UNIT));
487             done();
488         }
489         memset (samples, 0, sampbytes * sizeof(UNIT));
490     }
491     for (i = 0; i < nsamples; i++) {
492         fread(&sample, sizeof (UNIT), 1, pfile);
493         sample = bfd_get_16 (abfd, &sample);
494         if (feof(pfile))
495                 break;
496         samples[i] += sample;
497     }
498     if (i != nsamples) {
499         fprintf(stderr,
500             "%s: unexpected EOF after reading %d/%d samples\n",
501                 whoami , --i , nsamples );
502         done();
503     }
504 }
505
506 /*
507  *      Assign samples to the procedures to which they belong.
508  *
509  *      There are three cases as to where pcl and pch can be
510  *      with respect to the routine entry addresses svalue0 and svalue1
511  *      as shown in the following diagram.  overlap computes the
512  *      distance between the arrows, the fraction of the sample
513  *      that is to be credited to the routine which starts at svalue0.
514  *
515  *          svalue0                                         svalue1
516  *             |                                               |
517  *             v                                               v
518  *
519  *             +-----------------------------------------------+
520  *             |                                               |
521  *        |  ->|    |<-         ->|         |<-         ->|    |<-  |
522  *        |         |             |         |             |         |
523  *        +---------+             +---------+             +---------+
524  *
525  *        ^         ^             ^         ^             ^         ^
526  *        |         |             |         |             |         |
527  *       pcl       pch           pcl       pch           pcl       pch
528  *
529  *      For the vax we assert that samples will never fall in the first
530  *      two bytes of any routine, since that is the entry mask,
531  *      thus we give call alignentries() to adjust the entry points if
532  *      the entry mask falls in one bucket but the code for the routine
533  *      doesn't start until the next bucket.  In conjunction with the
534  *      alignment of routine addresses, this should allow us to have
535  *      only one sample for every four bytes of text space and never
536  *      have any overlap (the two end cases, above).
537  */
538 asgnsamples()
539 {
540     register int        j;
541     UNIT                ccnt;
542     double              time;
543     unsigned long       pcl, pch;
544     register int        i;
545     unsigned long       overlap;
546     unsigned long       svalue0, svalue1;
547
548     /* read samples and assign to namelist symbols */
549     scale = highpc - lowpc;
550     scale /= nsamples;
551     alignentries();
552     for (i = 0, j = 1; i < nsamples; i++) {
553         ccnt = samples[i];
554         if (ccnt == 0)
555                 continue;
556         pcl = lowpc + scale * i;
557         pch = lowpc + scale * (i + 1);
558         time = ccnt;
559 #       ifdef DEBUG
560             if ( debug & SAMPLEDEBUG ) {
561                 printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" ,
562                         pcl , pch , ccnt );
563             }
564 #       endif DEBUG
565         totime += time;
566         for (j = j - 1; j < nname; j++) {
567             svalue0 = nl[j].svalue;
568             svalue1 = nl[j+1].svalue;
569                 /*
570                  *      if high end of tick is below entry address, 
571                  *      go for next tick.
572                  */
573             if (pch < svalue0)
574                     break;
575                 /*
576                  *      if low end of tick into next routine,
577                  *      go for next routine.
578                  */
579             if (pcl >= svalue1)
580                     continue;
581             overlap = min(pch, svalue1) - max(pcl, svalue0);
582             if (overlap > 0) {
583 #               ifdef DEBUG
584                     if (debug & SAMPLEDEBUG) {
585                         printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n",
586                                 nl[j].value/sizeof(UNIT), svalue0, svalue1,
587                                 nl[j].name, 
588                                 overlap * time / scale, overlap);
589                     }
590 #               endif DEBUG
591                 nl[j].time += overlap * time / scale;
592             }
593         }
594     }
595 #   ifdef DEBUG
596         if (debug & SAMPLEDEBUG) {
597             printf("[asgnsamples] totime %f\n", totime);
598         }
599 #   endif DEBUG
600 }
601
602
603 unsigned long
604 min(a, b)
605     unsigned long a,b;
606 {
607     if (a<b)
608         return(a);
609     return(b);
610 }
611
612 unsigned long
613 max(a, b)
614     unsigned long a,b;
615 {
616     if (a>b)
617         return(a);
618     return(b);
619 }
620
621     /*
622      *  calculate scaled entry point addresses (to save time in asgnsamples),
623      *  and possibly push the scaled entry points over the entry mask,
624      *  if it turns out that the entry point is in one bucket and the code
625      *  for a routine is in the next bucket.
626      */
627 alignentries()
628 {
629     register struct nl  *nlp;
630     unsigned long       bucket_of_entry;
631     unsigned long       bucket_of_code;
632
633     for (nlp = nl; nlp < npe; nlp++) {
634         nlp -> svalue = nlp -> value / sizeof(UNIT);
635         bucket_of_entry = (nlp->svalue - lowpc) / scale;
636         bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale;
637         if (bucket_of_entry < bucket_of_code) {
638 #           ifdef DEBUG
639                 if (debug & SAMPLEDEBUG) {
640                     printf("[alignentries] pushing svalue 0x%x to 0x%x\n",
641                             nlp->svalue, nlp->svalue + UNITS_TO_CODE);
642                 }
643 #           endif DEBUG
644             nlp->svalue += UNITS_TO_CODE;
645         }
646     }
647 }
648
649 bool
650 funcsymbol( symp )
651      asymbol *symp;
652 {
653   extern char   *strtab;        /* string table from a.out */
654   extern int    aflag;          /* if static functions aren't desired */
655   char  *name;
656   int i;
657
658   /*
659    *    must be a text symbol,
660    *    and static text symbols don't qualify if aflag set.
661    */
662   
663
664   if (!symp->section)
665     return FALSE;
666
667 #if 0
668   if (!aflag && (symp->flags&BSF_LOCAL)) {
669 #if defined(DEBUG)
670     fprintf (stderr, "%s(%d):  %s:  not a function\n", __FILE__, __LINE__, symp->name);
671 #endif
672     return FALSE;
673   }
674 #endif  /* 0 */
675   /*
676    *    can't have any `funny' characters in name,
677    *    where `funny' includes  `.', .o file names
678    *                    and     `$', pascal labels.
679    */
680   if (!symp->name)
681     return FALSE;
682
683   for (name = symp->name; *name; name++) {
684     if ( *name == '.' || *name == '$' ) {
685       return FALSE;
686     }
687   }
688
689   i = bfd_decode_symclass (symp);
690 #if defined(DEBUG) && 0
691   if (i != 'T' && i != 't')
692     fprintf (stderr, "%s(%d):  %s is of class %c\n", __FILE__, __LINE__, symp->name, i);
693 #endif
694
695   return (i == 'T' || i == 't');
696 }
697
698 done()
699 {
700
701     exit(0);
702 }