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