xref: /csrg-svn/lib/libc/gmon/gmon.c (revision 4850)
1 static	char *sccsid = "@(#)gmon.c	1.6 (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 static unsigned long	s_textsize = 0;
91 
92 static int	ssiz;
93 static int	*sbuf;
94 
95 #define	MSG "No space for monitor buffer(s)\n"
96 
97 _mstartup(lowpc, highpc)
98     char	*lowpc;
99     char	*highpc;
100 {
101     int			monsize;
102     char		*buffer;
103     char		*sbrk();
104     unsigned long	limit;
105 
106     s_lowpc = lowpc;
107     s_highpc = highpc;
108     s_textsize = highpc - lowpc;
109     monsize = s_textsize + sizeof(struct phdr);
110     buffer = sbrk( monsize );
111     if ( buffer == (char *) -1 ) {
112 	write( 2 , MSG , sizeof(MSG) );
113 	return;
114     }
115     froms = (unsigned short *) sbrk( s_textsize );
116     if ( froms == (unsigned short *) -1 ) {
117 	write( 2 , MSG , sizeof(MSG) );
118 	froms = 0;
119 	return;
120     }
121     tos = (struct tostruct *) sbrk(s_textsize);
122     if ( tos == (struct tostruct *) -1 ) {
123 	write( 2 , MSG , sizeof(MSG) );
124 	froms = 0;
125 	tos = 0;
126 	return;
127     }
128     tos[0].link = 0;
129     limit = s_textsize / sizeof(struct tostruct);
130 	/*
131 	 *	tolimit is what mcount checks to see if
132 	 *	all the data structures are ready!!!
133 	 *	make sure it won't overflow.
134 	 */
135     tolimit = limit > 65534 ? 65534 : limit;
136     monitor( lowpc , highpc , buffer , monsize );
137 }
138 
139 _mcleanup()
140 {
141     FILE	*fd;
142     int		fromindex;
143     char	*frompc;
144     int		toindex;
145 
146     monitor( (int (*)()) 0 );
147     fd = fopen( "gmon.out" , "w" );
148     if ( fd == NULL ) {
149 	perror( "mcount: gmon.out" );
150 	return;
151     }
152 #   ifdef DEBUG
153 	fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
154 #   endif DEBUG
155     fwrite( sbuf , 1 , ssiz , fd );
156     for ( fromindex = 0 ; fromindex < s_textsize>>1 ; fromindex++ ) {
157 	if ( froms[fromindex] == 0 ) {
158 	    continue;
159 	}
160 	frompc = s_lowpc + (fromindex<<1);
161 	for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
162 #	    ifdef DEBUG
163 		fprintf( stderr ,
164 			"[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
165 			frompc , tos[toindex].selfpc , tos[toindex].count );
166 #	    endif DEBUG
167 	    fwrite( &frompc, 1, sizeof frompc, fd );
168 	    fwrite( &tos[toindex].selfpc, 1, sizeof tos[toindex].selfpc, fd );
169 	    fwrite( &tos[toindex].count, 1, sizeof tos[toindex].count, fd );
170 	}
171     }
172     fclose( fd );
173 }
174 
175     /*
176      *	This routine is massaged so that it may be jsb'ed to
177      */
178 asm("#define _mcount mcount");
179 mcount()
180 {
181     register char		*selfpc;	/* r11 */
182     register unsigned short	*frompcindex;	/* r10 */
183     register struct tostruct	*top;		/* r9 */
184     static int			profiling = 0;
185 
186     asm( "	forgot to run ex script on gmcrt0.s" );
187     asm( "#define r11 r5" );
188     asm( "#define r10 r4" );
189     asm( "#define r9 r3" );
190 #ifdef lint
191     selfpc = (char *) 0;
192     frompcindex = 0;
193 #else not lint
194 	/*
195 	 *	find the return address for mcount,
196 	 *	and the return address for mcount's caller.
197 	 */
198     asm("	movl (sp), r11");	/* selfpc = ... (jsb frame) */
199     asm("	movl 16(fp), r10");	/* frompcindex =     (calls frame) */
200 #endif not lint
201 	/*
202 	 *	check that we are profiling
203 	 *	and that we aren't recursively invoked.
204 	 */
205     if ( tolimit == 0 ) {
206 	goto out;
207     }
208     if ( profiling ) {
209 	goto out;
210     }
211     profiling = 1;
212 	/*
213 	 *	check that frompcindex is a reasonable pc value.
214 	 *	for example:	signal catchers get called from the stack,
215 	 *			not from text space.  too bad.
216 	 */
217     frompcindex = (unsigned short *) ( (long) frompcindex - (long) s_lowpc );
218     if ( (unsigned long) frompcindex > s_textsize ) {
219 	goto done;
220     }
221     frompcindex = &froms[ ( (long) frompcindex ) >> 1 ];
222     if ( *frompcindex == 0 ) {
223 	*frompcindex = ++tos[0].link;
224 	if ( *frompcindex >= tolimit ) {
225 	    goto overflow;
226 	}
227 	top = &tos[ *frompcindex ];
228 	top->selfpc = selfpc;
229 	top->count = 0;
230 	top->link = 0;
231     } else {
232 	top = &tos[ *frompcindex ];
233     }
234     for ( ; /* goto done */ ; top = &tos[ top -> link ] ) {
235 	if ( top -> selfpc == selfpc ) {
236 	    top -> count++;
237 	    goto done;
238 	}
239 	if ( top -> link == 0 ) {
240 	    top -> link = ++tos[0].link;
241 	    if ( top -> link >= tolimit )
242 		goto overflow;
243 	    top = &tos[ top -> link ];
244 	    top -> selfpc = selfpc;
245 	    top -> count = 1;
246 	    top -> link = 0;
247 	    goto done;
248 	}
249     }
250 done:
251     profiling = 0;
252     /* and fall through */
253 out:
254     asm( "	rsb" );
255     asm( "#undef r11" );
256     asm( "#undef r10" );
257     asm( "#undef r9" );
258     asm( "#undef _mcount");
259 
260 overflow:
261     tolimit = 0;
262 #   define	TOLIMIT	"mcount: tos overflow\n"
263     write( 2 , TOLIMIT , sizeof( TOLIMIT ) );
264     goto out;
265 }
266 
267 monitor( lowpc , highpc , buf , bufsiz )
268     char	*lowpc;
269     /* VARARGS1 */
270     char	*highpc;
271     int		*buf, bufsiz;
272 {
273     register o;
274 
275     if ( lowpc == 0 ) {
276 	profil( (char *) 0 , 0 , 0 , 0 );
277 	return;
278     }
279     sbuf = buf;
280     ssiz = bufsiz;
281     ( (struct phdr *) buf ) -> lpc = lowpc;
282     ( (struct phdr *) buf ) -> hpc = highpc;
283     ( (struct phdr *) buf ) -> ncnt = ssiz;
284     o = sizeof(struct phdr);
285     buf = (int *) ( ( (int) buf ) + o );
286     bufsiz -= o;
287     if ( bufsiz <= 0 )
288 	return;
289     o = ( ( (char *) highpc - (char *) lowpc) >> 1 );
290     if( bufsiz < o )
291 	o = ( (float) bufsiz / o ) * 32768;
292     else
293 	o = 0177777;
294     profil( buf , bufsiz , lowpc , o );
295 }
296