* Copyright (c) 1991 The Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid
[] = "@(#)gmon.c 5.3 (Berkeley) 5/22/91";
#endif /* LIBC_SCCS and not lint */
extern mcount() asm ("mcount");
extern char *minbrk
asm ("minbrk");
* froms is actually a bunch of unsigned shorts indexing tos
static int profiling
= 3;
static unsigned short *froms
;
static struct tostruct
*tos
= 0;
static char *s_lowpc
= 0;
static char *s_highpc
= 0;
static unsigned long s_textsize
= 0;
/* see profil(2) where this is describe (incorrectly) */
#define SCALE_1_TO_1 0x10000L
#define MSG "No space for profiling buffer(s)\n"
monstartup(lowpc
, highpc
)
* round lowpc and highpc to multiples of the density we're using
* so the rest of the scaling (here and in gprof) stays in ints.
ROUNDDOWN((unsigned)lowpc
, HISTFRACTION
*sizeof(HISTCOUNTER
));
ROUNDUP((unsigned)highpc
, HISTFRACTION
*sizeof(HISTCOUNTER
));
s_textsize
= highpc
- lowpc
;
monsize
= (s_textsize
/ HISTFRACTION
) + sizeof(struct phdr
);
buffer
= sbrk( monsize
);
if ( buffer
== (char *) -1 ) {
write( 2 , MSG
, sizeof(MSG
) );
froms
= (unsigned short *) sbrk( s_textsize
/ HASHFRACTION
);
if ( froms
== (unsigned short *) -1 ) {
write( 2 , MSG
, sizeof(MSG
) );
tolimit
= s_textsize
* ARCDENSITY
/ 100;
if ( tolimit
< MINARCS
) {
} else if ( tolimit
> 65534 ) {
tos
= (struct tostruct
*) sbrk( tolimit
* sizeof( struct tostruct
) );
if ( tos
== (struct tostruct
*) -1 ) {
write( 2 , MSG
, sizeof(MSG
) );
( (struct phdr
*) buffer
) -> lpc
= lowpc
;
( (struct phdr
*) buffer
) -> hpc
= highpc
;
( (struct phdr
*) buffer
) -> ncnt
= ssiz
;
monsize
-= sizeof(struct phdr
);
s_scale
= ( (float) monsize
/ o
) * SCALE_1_TO_1
;
#else /* avoid floating point */
s_scale
= 0x10000 / quot
;
s_scale
= 0x1000000 / (o
/ (monsize
>> 8));
s_scale
= 0x1000000 / ((o
<< 8) / monsize
);
fd
= creat( "gmon.out" , 0666 );
perror( "mcount: gmon.out" );
fprintf( stderr
, "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf
, ssiz
);
write( fd
, sbuf
, ssiz
);
endfrom
= s_textsize
/ (HASHFRACTION
* sizeof(*froms
));
for ( fromindex
= 0 ; fromindex
< endfrom
; fromindex
++ ) {
if ( froms
[fromindex
] == 0 ) {
frompc
= s_lowpc
+ (fromindex
* HASHFRACTION
* sizeof(*froms
));
for (toindex
=froms
[fromindex
]; toindex
!=0; toindex
=tos
[toindex
].link
) {
"[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
frompc
, tos
[toindex
].selfpc
, tos
[toindex
].count
);
rawarc
.raw_frompc
= (unsigned long) frompc
;
rawarc
.raw_selfpc
= (unsigned long) tos
[toindex
].selfpc
;
rawarc
.raw_count
= tos
[toindex
].count
;
write( fd
, &rawarc
, sizeof rawarc
);
register unsigned short *frompcindex
;
register struct tostruct
*top
;
register struct tostruct
*prevtop
;
* find the return address for mcount,
* and the return address for mcount's caller.
asm(".text"); /* make sure we're in text space */
* selfpc = pc pushed by mcount call
asm("movl 4(%%ebp),%0" : "=r" (selfpc
));
* frompcindex = pc pushed by jsr into self.
* In GCC the caller's stack frame has already been built so we
* have to chase a6 to find caller's raddr.
asm("movl (%%ebp),%0" : "=r" (frompcindex
));
frompcindex
= ((unsigned short **)frompcindex
)[1];
* check that we are profiling
* and that we aren't recursively invoked.
* check that frompcindex is a reasonable pc value.
* for example: signal catchers get called from the stack,
* not from text space. too bad.
frompcindex
= (unsigned short *)((long)frompcindex
- (long)s_lowpc
);
if ((unsigned long)frompcindex
> s_textsize
) {
&froms
[((long)frompcindex
) / (HASHFRACTION
* sizeof(*froms
))];
* first time traversing this arc
if (toindex
>= tolimit
) {
if (top
->selfpc
== selfpc
) {
* arc at front of chain; usual case.
* have to go looking down chain for it.
* top points to what we are looking at,
* prevtop points to previous top.
* we know it is not at the head of the chain.
for (; /* goto done */; ) {
* top is end of the chain and none of the chain
* had top->selfpc == selfpc.
* so we allocate a new tostruct
* and link it to the head of the chain.
if (toindex
>= tolimit
) {
top
->link
= *frompcindex
;
* otherwise, check the next arc on the chain.
if (top
->selfpc
== selfpc
) {
* move it to the head of the chain.
prevtop
->link
= top
->link
;
top
->link
= *frompcindex
;
return; /* normal return restores saved registers */
profiling
++; /* halt further profiling */
# define TOLIMIT "mcount: tos overflow\n"
write(2, TOLIMIT
, sizeof(TOLIMIT
));
* profiling is what mcount checks to see if
* all the data structures are ready.
profil(sbuf
+ sizeof(struct phdr
), ssiz
- sizeof(struct phdr
),
profil((char *)0, 0, 0, 0);