xref: /csrg-svn/lib/libc/gmon/gmon.c (revision 9530)
1*9530Smckusick static	char *sccsid = "@(#)gmon.c	4.6 (Berkeley) 12/04/82";
24514Speter 
34869Smckusic #ifdef DEBUG
44514Speter #include <stdio.h>
54869Smckusic #endif DEBUG
64514Speter 
79433Smckusick #include "gmon.h"
84514Speter 
94564Speter     /*
104564Speter      *	froms is actually a bunch of unsigned shorts indexing tos
114564Speter      */
124514Speter static unsigned short	*froms;
134514Speter static struct tostruct	*tos = 0;
144514Speter static unsigned short	tolimit = 0;
154514Speter static char		*s_lowpc = 0;
164514Speter static char		*s_highpc = 0;
174850Speter static unsigned long	s_textsize = 0;
186253Smckusick static char		*minsbrk = 0;
194514Speter 
204564Speter static int	ssiz;
214564Speter static int	*sbuf;
224514Speter 
234514Speter #define	MSG "No space for monitor buffer(s)\n"
244514Speter 
259433Smckusick monstartup(lowpc, highpc)
264564Speter     char	*lowpc;
274564Speter     char	*highpc;
284514Speter {
294850Speter     int			monsize;
304850Speter     char		*buffer;
314850Speter     char		*sbrk();
324850Speter     unsigned long	limit;
334514Speter 
344564Speter     s_lowpc = lowpc;
354564Speter     s_highpc = highpc;
364850Speter     s_textsize = highpc - lowpc;
374850Speter     monsize = s_textsize + sizeof(struct phdr);
384564Speter     buffer = sbrk( monsize );
394564Speter     if ( buffer == (char *) -1 ) {
404564Speter 	write( 2 , MSG , sizeof(MSG) );
414564Speter 	return;
424564Speter     }
434850Speter     froms = (unsigned short *) sbrk( s_textsize );
444564Speter     if ( froms == (unsigned short *) -1 ) {
454564Speter 	write( 2 , MSG , sizeof(MSG) );
464564Speter 	froms = 0;
474564Speter 	return;
484564Speter     }
49*9530Smckusick     limit = s_textsize * DENSITY / 100;
50*9530Smckusick     if ( limit < MINCNT ) {
51*9530Smckusick 	limit = MINCNT;
52*9530Smckusick     } else if ( limit > 65534 ) {
53*9530Smckusick 	limit = 65534;
54*9530Smckusick     }
55*9530Smckusick     tos = (struct tostruct *) sbrk( limit * sizeof( struct tostruct ) );
564564Speter     if ( tos == (struct tostruct *) -1 ) {
574564Speter 	write( 2 , MSG , sizeof(MSG) );
584564Speter 	froms = 0;
594564Speter 	tos = 0;
604564Speter 	return;
614564Speter     }
624564Speter     tos[0].link = 0;
634850Speter 	/*
644850Speter 	 *	tolimit is what mcount checks to see if
654850Speter 	 *	all the data structures are ready!!!
664850Speter 	 *	make sure it won't overflow.
674850Speter 	 */
68*9530Smckusick     tolimit = limit;
699433Smckusick     monitor( lowpc , highpc , buffer , monsize , tolimit );
704514Speter }
714514Speter 
724514Speter _mcleanup()
734514Speter {
744869Smckusic     int			fd;
754869Smckusic     int			fromindex;
764869Smckusic     char		*frompc;
774869Smckusic     int			toindex;
784869Smckusic     struct rawarc	rawarc;
794514Speter 
804869Smckusic     fd = creat( "gmon.out" , 0666 );
814869Smckusic     if ( fd < 0 ) {
824564Speter 	perror( "mcount: gmon.out" );
834514Speter 	return;
844514Speter     }
854564Speter #   ifdef DEBUG
864564Speter 	fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
874564Speter #   endif DEBUG
884869Smckusic     write( fd , sbuf , ssiz );
894850Speter     for ( fromindex = 0 ; fromindex < s_textsize>>1 ; fromindex++ ) {
904514Speter 	if ( froms[fromindex] == 0 ) {
914514Speter 	    continue;
924514Speter 	}
934514Speter 	frompc = s_lowpc + (fromindex<<1);
944514Speter 	for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
954514Speter #	    ifdef DEBUG
964748Speter 		fprintf( stderr ,
974748Speter 			"[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
984514Speter 			frompc , tos[toindex].selfpc , tos[toindex].count );
994514Speter #	    endif DEBUG
1004869Smckusic 	    rawarc.raw_frompc = (unsigned long) frompc;
1014869Smckusic 	    rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc;
1024869Smckusic 	    rawarc.raw_count = tos[toindex].count;
1034869Smckusic 	    write( fd , &rawarc , sizeof rawarc );
1044514Speter 	}
1054514Speter     }
1064869Smckusic     close( fd );
1074514Speter }
1084514Speter 
1094564Speter     /*
1104564Speter      *	This routine is massaged so that it may be jsb'ed to
1114564Speter      */
1124514Speter asm("#define _mcount mcount");
1134514Speter mcount()
1144514Speter {
1154514Speter     register char		*selfpc;	/* r11 */
1164514Speter     register unsigned short	*frompcindex;	/* r10 */
1174514Speter     register struct tostruct	*top;		/* r9 */
1184540Speter     static int			profiling = 0;
1194514Speter 
1204869Smckusic     asm( "	forgot to run ex script on gcrt0.s" );
1214514Speter     asm( "#define r11 r5" );
1224514Speter     asm( "#define r10 r4" );
1234514Speter     asm( "#define r9 r3" );
1244514Speter #ifdef lint
1254514Speter     selfpc = (char *) 0;
1264514Speter     frompcindex = 0;
1274514Speter #else not lint
1284514Speter 	/*
1294540Speter 	 *	find the return address for mcount,
1304540Speter 	 *	and the return address for mcount's caller.
1314514Speter 	 */
1324514Speter     asm("	movl (sp), r11");	/* selfpc = ... (jsb frame) */
1334514Speter     asm("	movl 16(fp), r10");	/* frompcindex =     (calls frame) */
1344514Speter #endif not lint
1354540Speter 	/*
1364540Speter 	 *	check that we are profiling
1374564Speter 	 *	and that we aren't recursively invoked.
1384540Speter 	 */
1394850Speter     if ( tolimit == 0 ) {
1404514Speter 	goto out;
1414514Speter     }
1424564Speter     if ( profiling ) {
1434564Speter 	goto out;
1444564Speter     }
1454540Speter     profiling = 1;
1464540Speter 	/*
1474540Speter 	 *	check that frompcindex is a reasonable pc value.
1484540Speter 	 *	for example:	signal catchers get called from the stack,
1494540Speter 	 *			not from text space.  too bad.
1504540Speter 	 */
1514850Speter     frompcindex = (unsigned short *) ( (long) frompcindex - (long) s_lowpc );
1524850Speter     if ( (unsigned long) frompcindex > s_textsize ) {
1534540Speter 	goto done;
1544540Speter     }
1554850Speter     frompcindex = &froms[ ( (long) frompcindex ) >> 1 ];
1564514Speter     if ( *frompcindex == 0 ) {
1574514Speter 	*frompcindex = ++tos[0].link;
1584514Speter 	if ( *frompcindex >= tolimit ) {
1594514Speter 	    goto overflow;
1604514Speter 	}
1614514Speter 	top = &tos[ *frompcindex ];
1624514Speter 	top->selfpc = selfpc;
1634514Speter 	top->count = 0;
1644514Speter 	top->link = 0;
1654514Speter     } else {
1664514Speter 	top = &tos[ *frompcindex ];
1674514Speter     }
1684540Speter     for ( ; /* goto done */ ; top = &tos[ top -> link ] ) {
1694514Speter 	if ( top -> selfpc == selfpc ) {
1704514Speter 	    top -> count++;
1714540Speter 	    goto done;
1724514Speter 	}
1734514Speter 	if ( top -> link == 0 ) {
1744514Speter 	    top -> link = ++tos[0].link;
1754514Speter 	    if ( top -> link >= tolimit )
1764514Speter 		goto overflow;
1774514Speter 	    top = &tos[ top -> link ];
1784514Speter 	    top -> selfpc = selfpc;
1794514Speter 	    top -> count = 1;
1804514Speter 	    top -> link = 0;
1814540Speter 	    goto done;
1824514Speter 	}
1834514Speter     }
1844540Speter done:
1854540Speter     profiling = 0;
1864540Speter     /* and fall through */
1874514Speter out:
1884514Speter     asm( "	rsb" );
1894514Speter     asm( "#undef r11" );
1904514Speter     asm( "#undef r10" );
1914514Speter     asm( "#undef r9" );
1924514Speter     asm( "#undef _mcount");
1934514Speter 
1944514Speter overflow:
1954850Speter     tolimit = 0;
1964514Speter #   define	TOLIMIT	"mcount: tos overflow\n"
1974514Speter     write( 2 , TOLIMIT , sizeof( TOLIMIT ) );
1984514Speter     goto out;
1994514Speter }
2004514Speter 
2019433Smckusick /*VARARGS1*/
2029433Smckusick monitor( lowpc , highpc , buf , bufsiz , nfunc )
2034564Speter     char	*lowpc;
2044564Speter     char	*highpc;
2054564Speter     int		*buf, bufsiz;
2069433Smckusick     int		nfunc;	/* not used, available for compatability only */
2074514Speter {
2084564Speter     register o;
2094514Speter 
2104564Speter     if ( lowpc == 0 ) {
2114564Speter 	profil( (char *) 0 , 0 , 0 , 0 );
2129433Smckusick 	_mcleanup();
2134564Speter 	return;
2144564Speter     }
2154564Speter     sbuf = buf;
2164564Speter     ssiz = bufsiz;
2174564Speter     ( (struct phdr *) buf ) -> lpc = lowpc;
2184564Speter     ( (struct phdr *) buf ) -> hpc = highpc;
2194564Speter     ( (struct phdr *) buf ) -> ncnt = ssiz;
2204564Speter     o = sizeof(struct phdr);
2214564Speter     buf = (int *) ( ( (int) buf ) + o );
2224564Speter     bufsiz -= o;
2234564Speter     if ( bufsiz <= 0 )
2244564Speter 	return;
2255070Smckusic     o = ( ( (char *) highpc - (char *) lowpc) );
2264564Speter     if( bufsiz < o )
2275070Smckusic 	o = ( (float) bufsiz / o ) * 65536;
2284564Speter     else
2295070Smckusic 	o = 65536;
2304564Speter     profil( buf , bufsiz , lowpc , o );
2314514Speter }
2326177Smckusick 
2336177Smckusick /*
2346177Smckusick  * This is a stub for the "brk" system call, which we want to
2356253Smckusick  * catch so that it will not deallocate our data space.
2366253Smckusick  * (of which the program is not aware)
2376177Smckusick  */
2386253Smckusick asm("#define _curbrk curbrk");
2396253Smckusick extern char *curbrk;
2406253Smckusick 
2416177Smckusick brk(addr)
2426253Smckusick 	char *addr;
2436177Smckusick {
2446253Smckusick 
2456253Smckusick 	if (addr < minsbrk)
2466253Smckusick 		addr = minsbrk;
2476253Smckusick 	asm("	chmk	$17");
2489433Smckusick 	asm("	jcc	1f");
2499433Smckusick 	asm("	jmp	cerror");
2509433Smckusick asm("1:");
2516253Smckusick 	curbrk = addr;
2526253Smckusick 	return (0);
2536177Smckusick }
254