static char *sccsid
= "@(#)gmon.c 1.7 (Berkeley) %G%";
* C start up routines, for monitoring
* Robert Henry, UCB, 20 Oct 81
* We make the following (true) assumptions:
* 1) when the kernel calls start, it does a jump to location 2,
* and thus avoids the register save mask. We are NOT called
* with a calls! see sys1.c:setregs().
* 2) The only register variable that we can trust is sp,
* which points to the base of the kernel calling frame.
* Do NOT believe the documentation in exec(2) regarding the
* 3) We can allocate as many register variables as we want,
* and don't have to save them for anybody.
* 4) Because of the ways that asm's work, we can't have
* any automatic variables allocated on the stack, because
* we must catch the value of sp before any automatics are
* etext is added by the loader, and is the end of the text space.
* eprol is a local symbol, and labels almost the beginning of text space.
* its name is changed so it doesn't look like a function.
extern unsigned char etext
;
extern unsigned char eprol
;
asm( "#define _eprol _$eprol" );
asm( "#define _start start" );
char *kargv
[1]; /* size depends on kargc */
char kargstr
[1]; /* size varies */
char kenvstr
[1]; /* size varies */
* ALL REGISTER VARIABLES!!!
register struct kframe
*kfp
; /* r11 */
asm( " movl sp,r11" ); /* catch it quick */
for ( argv
= targv
= &kfp
-> kargv
[0] ; *targv
++ ; /* void */ )
if ( targv
>= (char **) ( *argv
) )
_mstartup( &eprol
, &etext
);
exit( main( kfp
-> kargc
, argv
, environ
) );
register int code
; /* r11 */
* froms is actually a bunch of unsigned shorts indexing tos
static unsigned short *froms
;
static struct tostruct
*tos
= 0;
static unsigned short tolimit
= 0;
static char *s_lowpc
= 0;
static char *s_highpc
= 0;
static unsigned long s_textsize
= 0;
#define MSG "No space for monitor buffer(s)\n"
s_textsize
= highpc
- lowpc
;
monsize
= s_textsize
+ sizeof(struct phdr
);
buffer
= sbrk( monsize
);
if ( buffer
== (char *) -1 ) {
write( 2 , MSG
, sizeof(MSG
) );
froms
= (unsigned short *) sbrk( s_textsize
);
if ( froms
== (unsigned short *) -1 ) {
write( 2 , MSG
, sizeof(MSG
) );
tos
= (struct tostruct
*) sbrk(s_textsize
);
if ( tos
== (struct tostruct
*) -1 ) {
write( 2 , MSG
, sizeof(MSG
) );
limit
= s_textsize
/ sizeof(struct tostruct
);
* tolimit is what mcount checks to see if
* all the data structures are ready!!!
* make sure it won't overflow.
tolimit
= limit
> 65534 ? 65534 : limit
;
monitor( lowpc
, highpc
, buffer
, monsize
);
monitor( (int (*)()) 0 );
fd
= creat( "gmon.out" , 0666 );
perror( "mcount: gmon.out" );
fprintf( stderr
, "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf
, ssiz
);
write( fd
, sbuf
, ssiz
);
for ( fromindex
= 0 ; fromindex
< s_textsize
>>1 ; fromindex
++ ) {
if ( froms
[fromindex
] == 0 ) {
frompc
= s_lowpc
+ (fromindex
<<1);
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
);
* This routine is massaged so that it may be jsb'ed to
asm("#define _mcount mcount");
register char *selfpc
; /* r11 */
register unsigned short *frompcindex
; /* r10 */
register struct tostruct
*top
; /* r9 */
static int profiling
= 0;
asm( " forgot to run ex script on gcrt0.s" );
* find the return address for mcount,
* and the return address for mcount's caller.
asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */
asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */
* 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
) {
frompcindex
= &froms
[ ( (long) frompcindex
) >> 1 ];
if ( *frompcindex
== 0 ) {
*frompcindex
= ++tos
[0].link
;
if ( *frompcindex
>= tolimit
) {
top
= &tos
[ *frompcindex
];
top
= &tos
[ *frompcindex
];
for ( ; /* goto done */ ; top
= &tos
[ top
-> link
] ) {
if ( top
-> selfpc
== selfpc
) {
if ( top
-> link
== 0 ) {
top
-> link
= ++tos
[0].link
;
if ( top
-> link
>= tolimit
)
top
= &tos
[ top
-> link
];
# define TOLIMIT "mcount: tos overflow\n"
write( 2 , TOLIMIT
, sizeof( TOLIMIT
) );
monitor( lowpc
, highpc
, buf
, bufsiz
)
profil( (char *) 0 , 0 , 0 , 0 );
( (struct phdr
*) buf
) -> lpc
= lowpc
;
( (struct phdr
*) buf
) -> hpc
= highpc
;
( (struct phdr
*) buf
) -> ncnt
= ssiz
;
buf
= (int *) ( ( (int) buf
) + o
);
o
= ( ( (char *) highpc
- (char *) lowpc
) >> 1 );
o
= ( (float) bufsiz
/ o
) * 32768;
profil( buf
, bufsiz
, lowpc
, o
);