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