xref: /csrg-svn/lib/libc/gmon/gmon.c (revision 4748)
1 static	char *sccsid = "@(#)gmon.c	1.4 (Berkeley) 11/06/81";
2 
3 #include <stdio.h>
4 
5 #include "gmcrt0.h"
6 
7     /*
8      *	C start up routines, for monitoring
9      *	Robert Henry, UCB, 20 Oct 81
10      *
11      *	We make the following (true) assumptions:
12      *	1) when the kernel calls start, it does a jump to location 2,
13      *	and thus avoids the register save mask.  We are NOT called
14      *	with a calls!  see sys1.c:setregs().
15      *	2) The only register variable that we can trust is sp,
16      *	which points to the base of the kernel calling frame.
17      *	Do NOT believe the documentation in exec(2) regarding the
18      *	values of fp and ap.
19      *	3) We can allocate as many register variables as we want,
20      *	and don't have to save them for anybody.
21      *	4) Because of the ways that asm's work, we can't have
22      *	any automatic variables allocated on the stack, because
23      *	we must catch the value of sp before any automatics are
24      *	allocated.
25      */
26 
27 char **environ;
28 extern	unsigned char	etext;
29 asm( "#define _eprol eprol" );
30 extern	unsigned char	eprol;
31 
32 asm( "#define _start start" );
33 start()
34 {
35     struct kframe {
36 	int	kargc;
37 	char	*kargv[1];		/* size depends on kargc */
38 	char	kargstr[1];		/* size varies */
39 	char	kenvstr[1];		/* size varies */
40     };
41 	/*
42 	 *	ALL REGISTER VARIABLES!!!
43 	 */
44     register struct kframe	*kfp;		/* r11 */
45     register char		**targv;
46     register char		**argv;
47 
48 #ifdef lint
49     kfp = 0;
50 #else not lint
51     asm( "	movl	sp,r11" );		/* catch it quick */
52 #endif not lint
53     for ( argv = targv = &kfp -> kargv[0] ; *targv++ ; /* void */ )
54 	/* VOID */ ;
55     if ( targv >= (char **) ( *argv ) )
56 	--targv;
57     environ = targv;
58 asm("eprol:");
59     _mstartup( &eprol , &etext );
60     exit( main( kfp -> kargc , argv , environ ) );
61 }
62 asm( "#undef _start" );
63 asm( "#undef _eprol" );
64 
65 exit( code )
66 	/* ARGSUSED */
67     register int	code;	/* r11 */
68 {
69 
70     fflush( stdout );
71     _mcleanup();
72     _cleanup();
73     asm( "	movl r11, r0" );
74     asm( "	chmk $1" );
75 }
76 
77     /*
78      *	froms is actually a bunch of unsigned shorts indexing tos
79      */
80 static unsigned short	*froms;
81 static struct tostruct	*tos = 0;
82 static unsigned short	tolimit = 0;
83 static char		*s_lowpc = 0;
84 static char		*s_highpc = 0;
85 
86 static int	ssiz;
87 static int	*sbuf;
88 
89 #define	MSG "No space for monitor buffer(s)\n"
90 
91 _mstartup(lowpc, highpc)
92     char	*lowpc;
93     char	*highpc;
94 {
95     int		monsize;
96     char	*buffer;
97     int		textsize;
98     char	*sbrk();
99 
100     s_lowpc = lowpc;
101     s_highpc = highpc;
102     textsize = ( (char *) highpc - (char *) lowpc );
103     monsize = textsize + sizeof(struct phdr);
104     buffer = sbrk( monsize );
105     if ( buffer == (char *) -1 ) {
106 	write( 2 , MSG , sizeof(MSG) );
107 	return;
108     }
109     froms = (unsigned short *) sbrk( textsize );
110     if ( froms == (unsigned short *) -1 ) {
111 	write( 2 , MSG , sizeof(MSG) );
112 	froms = 0;
113 	return;
114     }
115     tos = (struct tostruct *) sbrk(textsize);
116     if ( tos == (struct tostruct *) -1 ) {
117 	write( 2 , MSG , sizeof(MSG) );
118 	froms = 0;
119 	tos = 0;
120 	return;
121     }
122     tolimit = textsize / sizeof(struct tostruct);
123     tos[0].link = 0;
124     monitor( lowpc , highpc , buffer , monsize );
125 }
126 
127 _mcleanup()
128 {
129     FILE	*fd;
130     int		fromindex;
131     char	*frompc;
132     int		toindex;
133     int		textsize;
134 
135     monitor( (int (*)()) 0 );
136     fd = fopen( "gmon.out" , "w" );
137     if ( fd == NULL ) {
138 	perror( "mcount: gmon.out" );
139 	return;
140     }
141 #   ifdef DEBUG
142 	fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
143 #   endif DEBUG
144     fwrite( sbuf , 1 , ssiz , fd );
145     textsize = s_highpc - s_lowpc;
146     for ( fromindex = 0 ; fromindex < textsize>>1 ; fromindex++ ) {
147 	if ( froms[fromindex] == 0 ) {
148 	    continue;
149 	}
150 	frompc = s_lowpc + (fromindex<<1);
151 	for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
152 #	    ifdef DEBUG
153 		fprintf( stderr ,
154 			"[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
155 			frompc , tos[toindex].selfpc , tos[toindex].count );
156 #	    endif DEBUG
157 	    fwrite( &frompc, 1, sizeof frompc, fd );
158 	    fwrite( &tos[toindex].selfpc, 1, sizeof tos[toindex].selfpc, fd );
159 	    fwrite( &tos[toindex].count, 1, sizeof tos[toindex].count, fd );
160 	}
161     }
162     fclose( fd );
163 }
164 
165     /*
166      *	This routine is massaged so that it may be jsb'ed to
167      */
168 asm("#define _mcount mcount");
169 mcount()
170 {
171     register char		*selfpc;	/* r11 */
172     register unsigned short	*frompcindex;	/* r10 */
173     register struct tostruct	*top;		/* r9 */
174     static int			profiling = 0;
175 
176     asm( "	forgot to run ex script on gmcrt0.s" );
177     asm( "#define r11 r5" );
178     asm( "#define r10 r4" );
179     asm( "#define r9 r3" );
180 #ifdef lint
181     selfpc = (char *) 0;
182     frompcindex = 0;
183 #else not lint
184 	/*
185 	 *	find the return address for mcount,
186 	 *	and the return address for mcount's caller.
187 	 */
188     asm("	movl (sp), r11");	/* selfpc = ... (jsb frame) */
189     asm("	movl 16(fp), r10");	/* frompcindex =     (calls frame) */
190 #endif not lint
191 	/*
192 	 *	check that we are profiling
193 	 *	and that we aren't recursively invoked.
194 	 */
195     if ( tos == 0 ) {
196 	goto out;
197     }
198     if ( profiling ) {
199 	goto out;
200     }
201     profiling = 1;
202 	/*
203 	 *	check that frompcindex is a reasonable pc value.
204 	 *	for example:	signal catchers get called from the stack,
205 	 *			not from text space.  too bad.
206 	 */
207     if ( (char *) frompcindex < s_lowpc || (char *) frompcindex > s_highpc ) {
208 	goto done;
209     }
210     frompcindex = &froms[ ( (long) frompcindex - (long) s_lowpc ) >> 1 ];
211     if ( *frompcindex == 0 ) {
212 	*frompcindex = ++tos[0].link;
213 	if ( *frompcindex >= tolimit ) {
214 	    goto overflow;
215 	}
216 	top = &tos[ *frompcindex ];
217 	top->selfpc = selfpc;
218 	top->count = 0;
219 	top->link = 0;
220     } else {
221 	top = &tos[ *frompcindex ];
222     }
223     for ( ; /* goto done */ ; top = &tos[ top -> link ] ) {
224 	if ( top -> selfpc == selfpc ) {
225 	    top -> count++;
226 	    goto done;
227 	}
228 	if ( top -> link == 0 ) {
229 	    top -> link = ++tos[0].link;
230 	    if ( top -> link >= tolimit )
231 		goto overflow;
232 	    top = &tos[ top -> link ];
233 	    top -> selfpc = selfpc;
234 	    top -> count = 1;
235 	    top -> link = 0;
236 	    goto done;
237 	}
238     }
239 done:
240     profiling = 0;
241     /* and fall through */
242 out:
243     asm( "	rsb" );
244     asm( "#undef r11" );
245     asm( "#undef r10" );
246     asm( "#undef r9" );
247     asm( "#undef _mcount");
248 
249 overflow:
250 #   define	TOLIMIT	"mcount: tos overflow\n"
251     write( 2 , TOLIMIT , sizeof( TOLIMIT ) );
252     tos = 0;
253     froms = 0;
254     goto out;
255 }
256 
257 monitor( lowpc , highpc , buf , bufsiz )
258     char	*lowpc;
259     /* VARARGS1 */
260     char	*highpc;
261     int		*buf, bufsiz;
262 {
263     register o;
264 
265     if ( lowpc == 0 ) {
266 	profil( (char *) 0 , 0 , 0 , 0 );
267 	return;
268     }
269     sbuf = buf;
270     ssiz = bufsiz;
271     ( (struct phdr *) buf ) -> lpc = lowpc;
272     ( (struct phdr *) buf ) -> hpc = highpc;
273     ( (struct phdr *) buf ) -> ncnt = ssiz;
274     o = sizeof(struct phdr);
275     buf = (int *) ( ( (int) buf ) + o );
276     bufsiz -= o;
277     if ( bufsiz <= 0 )
278 	return;
279     o = ( ( (char *) highpc - (char *) lowpc) >> 1 );
280     if( bufsiz < o )
281 	o = ( (float) bufsiz / o ) * 32768;
282     else
283 	o = 0177777;
284     profil( buf , bufsiz , lowpc , o );
285 }
286