static char *sccsid
= "@(#)gprof.c 1.23 (Berkeley) %G%";
* things which get -E excluded by default.
char *defaultEs
[] = { "mcount" , "__mcleanup" , 0 };
while ( *argv
!= 0 && **argv
== '-' ) {
printf("[main] debug = %d\n", debug
);
printf("%s: -d ignored\n", whoami
);
addlist( Elist
, *argv
);
addlist( elist
, *argv
);
addlist( elist
, *++argv
);
addlist( Flist
, *argv
);
addlist( flist
, *argv
);
addlist( flist
, *++argv
);
* turn off default functions
for ( sp
= &defaultEs
[0] ; *sp
; sp
++ ) {
* how many ticks per second?
* if we can't tell, report time in ticks.
fprintf(stderr
, "time is in ticks, not seconds\n");
* get information about a.out file.
* get information about mon.out file(s).
} while ( *argv
++ != 0 );
* dump out a gmon.sum file if requested
* assign samples to procedures
* print the usual profile
* assemble and print the dynamic profile
* Set up string and symbol tables from a.out.
* and optionally the text space.
* On return symbol table is sorted by value.
nfile
= fopen( a_outname
,"r");
fread(&xbuf
, 1, sizeof(xbuf
), nfile
);
fprintf(stderr
, "%s: %s: bad format\n", whoami
, a_outname
);
qsort(nl
, nname
, sizeof(nltype
), valcmp
);
if ( debug
& AOUTDEBUG
) {
for (j
= 0; j
< nname
; j
++){
printf("[getnfile] 0X%08x\t%s\n", nl
[j
].value
, nl
[j
].name
);
fseek(nfile
, (long)(N_SYMOFF(xbuf
) + xbuf
.a_syms
), 0);
if (fread(&ssiz
, sizeof (ssiz
), 1, nfile
) == 0) {
fprintf(stderr
, "%s: %s: no string table (old format?)\n" ,
strtab
= (char *)calloc(ssiz
, 1);
fprintf(stderr
, "%s: %s: no room for %d bytes of string table",
whoami
, a_outname
, ssiz
);
if (fread(strtab
+sizeof(ssiz
), ssiz
-sizeof(ssiz
), 1, nfile
) != 1) {
fprintf(stderr
, "%s: %s: error reading string table\n",
/* pass1 - count symbols */
fseek(nfile
, (long)N_SYMOFF(xbuf
), 0);
for (i
= xbuf
.a_syms
; i
> 0; i
-= sizeof(struct nlist
)) {
fread(&nbuf
, sizeof(nbuf
), 1, nfile
);
if ( ! funcsymbol( &nbuf
) ) {
fprintf(stderr
, "%s: %s: no symbols\n", whoami
, a_outname
);
nl
= (nltype
*) calloc( askfor
, sizeof(nltype
) );
fprintf(stderr
, "%s: No room for %d bytes of symbol table\n",
whoami
, askfor
* sizeof(nltype
) );
/* pass2 - read symbols */
fseek(nfile
, (long)N_SYMOFF(xbuf
), 0);
for (i
= xbuf
.a_syms
; i
> 0; i
-= sizeof(struct nlist
)) {
fread(&nbuf
, sizeof(nbuf
), 1, nfile
);
if ( ! funcsymbol( &nbuf
) ) {
if ( debug
& AOUTDEBUG
) {
printf( "[getsymtab] rejecting: 0x%x %s\n" ,
nbuf
.n_type
, strtab
+ nbuf
.n_un
.n_strx
);
npe
->value
= nbuf
.n_value
;
npe
->name
= strtab
+nbuf
.n_un
.n_strx
;
if ( debug
& AOUTDEBUG
) {
printf( "[getsymtab] %d %s 0x%08x\n" ,
nname
, npe
-> name
, npe
-> value
);
* read in the text space of an a.out file
textspace
= malloc( xbuf
.a_text
);
fprintf( stderr
, "%s: ran out room for %d bytes of text space: " ,
fprintf( stderr
, "can't do -c\n" );
(void) fseek( nfile
, N_TXTOFF( xbuf
) , 0 );
if ( fread( textspace
, 1 , xbuf
.a_text
, nfile
) != xbuf
.a_text
) {
fprintf( stderr
, "%s: couldn't read text space: " , whoami
);
fprintf( stderr
, "can't do -c\n" );
* information from a gmon.out file is in two parts:
* an array of sampling hits within pc ranges,
pfile
= openpfile(filename
);
* the rest of the file consists of
* a bunch of <from,self,count> tuples.
while ( fread( &arc
, sizeof arc
, 1 , pfile
) == 1 ) {
if ( debug
& SAMPLEDEBUG
) {
printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" ,
arc
.raw_frompc
, arc
.raw_selfpc
, arc
.raw_count
);
if((pfile
= fopen(filename
, "r")) == NULL
) {
fread(&tmp
, sizeof(struct hdr
), 1, pfile
);
if ( s_highpc
!= 0 && ( tmp
.lowpc
!= h
.lowpc
||
tmp
.highpc
!= h
.highpc
|| tmp
.ncnt
!= h
.ncnt
) ) {
fprintf(stderr
, "%s: incompatible with first gmon file\n", filename
);
s_lowpc
= (unsigned long) h
.lowpc
;
s_highpc
= (unsigned long) h
.highpc
;
lowpc
= (unsigned long)h
.lowpc
/ sizeof(UNIT
);
highpc
= (unsigned long)h
.highpc
/ sizeof(UNIT
);
sampbytes
= h
.ncnt
- sizeof(struct hdr
);
nsamples
= sampbytes
/ sizeof (unsigned UNIT
);
if ( debug
& SAMPLEDEBUG
) {
printf( "[openpfile] hdr.lowpc 0x%x hdr.highpc 0x%x hdr.ncnt %d\n",
h
.lowpc
, h
.highpc
, h
.ncnt
);
printf( "[openpfile] s_lowpc 0x%x s_highpc 0x%x\n" ,
printf( "[openpfile] lowpc 0x%x highpc 0x%x\n" ,
printf( "[openpfile] sampbytes %d nsamples %d\n" ,
parentp
= nllookup( rawp
-> raw_frompc
);
childp
= nllookup( rawp
-> raw_selfpc
);
childp
-> ncall
+= rawp
-> raw_count
;
if ( debug
& TALLYDEBUG
) {
printf( "[tally] arc from %s to %s traversed %d times\n" ,
parentp
-> name
, childp
-> name
, rawp
-> raw_count
);
addarc( parentp
, childp
, rawp
-> raw_count
);
* dump out the gmon.sum file
if ( ( sfile
= fopen ( sumfile
, "w" ) ) == NULL
) {
* dump the header; use the last header read in
if ( fwrite( &h
, sizeof h
, 1 , sfile
) != 1 ) {
if (fwrite(samples
, sizeof(unsigned UNIT
), nsamples
, sfile
) != nsamples
) {
* dump the normalized raw arc information
for ( nlp
= nl
; nlp
< npe
; nlp
++ ) {
for ( arcp
= nlp
-> children
; arcp
; arcp
= arcp
-> arc_childlist
) {
arc
.raw_frompc
= arcp
-> arc_parentp
-> value
;
arc
.raw_selfpc
= arcp
-> arc_childp
-> value
;
arc
.raw_count
= arcp
-> arc_count
;
if ( fwrite ( &arc
, sizeof arc
, 1 , sfile
) != 1 ) {
if ( debug
& SAMPLEDEBUG
) {
printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" ,
arc
.raw_frompc
, arc
.raw_selfpc
, arc
.raw_count
);
if ( p1
-> value
< p2
-> value
) {
if ( p1
-> value
> p2
-> value
) {
samples
= (unsigned UNIT
*) calloc(sampbytes
, sizeof (unsigned UNIT
));
fprintf( stderr
, "%s: No room for %d sample pc's\n",
whoami
, sampbytes
/ sizeof (unsigned UNIT
));
for (i
= 0; i
< nsamples
; i
++) {
fread(&sample
, sizeof (unsigned UNIT
), 1, pfile
);
"%s: unexpected EOF after reading %d/%d samples\n",
whoami
, --i
, nsamples
);
* Assign samples to the procedures to which they belong.
* There are three cases as to where pcl and pch can be
* with respect to the routine entry addresses svalue0 and svalue1
* as shown in the following diagram. overlap computes the
* distance between the arrows, the fraction of the sample
* that is to be credited to the routine which starts at svalue0.
* +-----------------------------------------------+
* | ->| |<- ->| |<- ->| |<- |
* +---------+ +---------+ +---------+
* pcl pch pcl pch pcl pch
* For the vax we assert that samples will never fall in the first
* two bytes of any routine, since that is the entry mask,
* thus we give call alignentries() to adjust the entry points if
* the entry mask falls in one bucket but the code for the routine
* doesn't start until the next bucket. In conjunction with the
* alignment of routine addresses, this should allow us to have
* only one sample for every four bytes of text space and never
* have any overlap (the two end cases, above).
unsigned long svalue0
, svalue1
;
/* read samples and assign to namelist symbols */
for (i
= 0, j
= 1; i
< nsamples
; i
++) {
pch
= lowpc
+ scale
* (i
+ 1);
if ( debug
& SAMPLEDEBUG
) {
printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" ,
for (j
= j
- 1; j
< nname
; j
++) {
svalue1
= nl
[j
+1].svalue
;
* if high end of tick is below entry address,
* if low end of tick into next routine,
overlap
= min(pch
, svalue1
) - max(pcl
, svalue0
);
if (debug
& SAMPLEDEBUG
) {
printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n",
nl
[j
].value
/sizeof(UNIT
), svalue0
, svalue1
,
overlap
* time
/ scale
, overlap
);
nl
[j
].time
+= overlap
* time
/ scale
;
if (debug
& SAMPLEDEBUG
) {
printf("[asgnsamples] totime %f\n", totime
);
* calculate scaled entry point addresses (to save time in asgnsamples),
* and possibly push the scaled entry points over the entry mask,
* if it turns out that the entry point is in one bucket and the code
* for a routine is in the next bucket.
unsigned long bucket_of_entry
;
unsigned long bucket_of_code
;
for (nlp
= nl
; nlp
< npe
; nlp
++) {
nlp
-> svalue
= nlp
-> value
/ sizeof(UNIT
);
bucket_of_entry
= (nlp
->svalue
- lowpc
) / scale
;
bucket_of_code
= (nlp
->svalue
+ UNITS_TO_CODE
- lowpc
) / scale
;
if (bucket_of_entry
< bucket_of_code
) {
if (debug
& SAMPLEDEBUG
) {
printf("[alignentries] pushing svalue 0x%x to 0x%x\n",
nlp
->svalue
, nlp
->svalue
+ UNITS_TO_CODE
);
nlp
->svalue
+= UNITS_TO_CODE
;
extern char *strtab
; /* string table from a.out */
extern int aflag
; /* if static functions aren't desired */
* and static text symbols don't qualify if aflag set.
if ( ! ( ( nlistp
-> n_type
== ( N_TEXT
| N_EXT
) )
|| ( ( nlistp
-> n_type
== N_TEXT
) && ( aflag
== 0 ) ) ) ) {
* can't have any `funny' characters in name,
* where `funny' includes `.', .o file names
* and `$', pascal labels.
for ( name
= strtab
+ nlistp
-> n_un
.n_strx
; *name
; name
+= 1 ) {
if ( *name
== '.' || *name
== '$' ) {