xref: /original-bsd/lib/libc/gmon/gmon.c (revision 62734ea8)
1 static	char *sccsid = "@(#)gmon.c	4.4 (Berkeley) 05/19/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 int		r11;		/* init needs r11 */
52     register struct kframe	*kfp;		/* r10 */
53     register char		**targv;
54     register char		**argv;
55 
56 #ifdef lint
57     kfp = 0;
58 #else not lint
59     asm( "	movl	sp,r10" );		/* catch it quick */
60 #endif not lint
61     for ( argv = targv = &kfp -> kargv[0] ; *targv++ ; /* void */ )
62 	/* VOID */ ;
63     if ( targv >= (char **) ( *argv ) )
64 	--targv;
65     environ = targv;
66 asm("_eprol:");
67     _mstartup( &eprol , &etext );
68     exit( main( kfp -> kargc , argv , environ ) );
69 }
70 asm( "#undef _start" );
71 asm( "#undef _eprol" );
72 
73 exit( code )
74 	/* ARGSUSED */
75     register int	code;	/* r11 */
76 {
77 
78     _mcleanup();
79     _cleanup();
80     asm( "	movl r11, r0" );
81     asm( "	chmk $1" );
82 }
83 
84     /*
85      *	froms is actually a bunch of unsigned shorts indexing tos
86      */
87 static unsigned short	*froms;
88 static struct tostruct	*tos = 0;
89 static unsigned short	tolimit = 0;
90 static char		*s_lowpc = 0;
91 static char		*s_highpc = 0;
92 static unsigned long	s_textsize = 0;
93 static char		*minsbrk = 0;
94 
95 static int	ssiz;
96 static int	*sbuf;
97 
98 #define	MSG "No space for monitor buffer(s)\n"
99 
100 _mstartup(lowpc, highpc)
101     char	*lowpc;
102     char	*highpc;
103 {
104     int			monsize;
105     char		*buffer;
106     char		*sbrk();
107     unsigned long	limit;
108 
109     s_lowpc = lowpc;
110     s_highpc = highpc;
111     s_textsize = highpc - lowpc;
112     monsize = s_textsize + sizeof(struct phdr);
113     buffer = sbrk( monsize );
114     if ( buffer == (char *) -1 ) {
115 	write( 2 , MSG , sizeof(MSG) );
116 	return;
117     }
118     froms = (unsigned short *) sbrk( s_textsize );
119     if ( froms == (unsigned short *) -1 ) {
120 	write( 2 , MSG , sizeof(MSG) );
121 	froms = 0;
122 	return;
123     }
124     tos = (struct tostruct *) sbrk(s_textsize);
125     if ( tos == (struct tostruct *) -1 ) {
126 	write( 2 , MSG , sizeof(MSG) );
127 	froms = 0;
128 	tos = 0;
129 	return;
130     }
131     tos[0].link = 0;
132     limit = s_textsize / sizeof(struct tostruct);
133 	/*
134 	 *	tolimit is what mcount checks to see if
135 	 *	all the data structures are ready!!!
136 	 *	make sure it won't overflow.
137 	 */
138     tolimit = limit > 65534 ? 65534 : limit;
139     monitor( lowpc , highpc , buffer , monsize );
140 }
141 
142 _mcleanup()
143 {
144     int			fd;
145     int			fromindex;
146     char		*frompc;
147     int			toindex;
148     struct rawarc	rawarc;
149 
150     monitor( (int (*)()) 0 );
151     fd = creat( "gmon.out" , 0666 );
152     if ( fd < 0 ) {
153 	perror( "mcount: gmon.out" );
154 	return;
155     }
156 #   ifdef DEBUG
157 	fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
158 #   endif DEBUG
159     write( fd , sbuf , ssiz );
160     for ( fromindex = 0 ; fromindex < s_textsize>>1 ; fromindex++ ) {
161 	if ( froms[fromindex] == 0 ) {
162 	    continue;
163 	}
164 	frompc = s_lowpc + (fromindex<<1);
165 	for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
166 #	    ifdef DEBUG
167 		fprintf( stderr ,
168 			"[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
169 			frompc , tos[toindex].selfpc , tos[toindex].count );
170 #	    endif DEBUG
171 	    rawarc.raw_frompc = (unsigned long) frompc;
172 	    rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc;
173 	    rawarc.raw_count = tos[toindex].count;
174 	    write( fd , &rawarc , sizeof rawarc );
175 	}
176     }
177     close( fd );
178 }
179 
180     /*
181      *	This routine is massaged so that it may be jsb'ed to
182      */
183 asm("#define _mcount mcount");
184 mcount()
185 {
186     register char		*selfpc;	/* r11 */
187     register unsigned short	*frompcindex;	/* r10 */
188     register struct tostruct	*top;		/* r9 */
189     static int			profiling = 0;
190 
191     asm( "	forgot to run ex script on gcrt0.s" );
192     asm( "#define r11 r5" );
193     asm( "#define r10 r4" );
194     asm( "#define r9 r3" );
195 #ifdef lint
196     selfpc = (char *) 0;
197     frompcindex = 0;
198 #else not lint
199 	/*
200 	 *	find the return address for mcount,
201 	 *	and the return address for mcount's caller.
202 	 */
203     asm("	movl (sp), r11");	/* selfpc = ... (jsb frame) */
204     asm("	movl 16(fp), r10");	/* frompcindex =     (calls frame) */
205 #endif not lint
206 	/*
207 	 *	check that we are profiling
208 	 *	and that we aren't recursively invoked.
209 	 */
210     if ( tolimit == 0 ) {
211 	goto out;
212     }
213     if ( profiling ) {
214 	goto out;
215     }
216     profiling = 1;
217 	/*
218 	 *	check that frompcindex is a reasonable pc value.
219 	 *	for example:	signal catchers get called from the stack,
220 	 *			not from text space.  too bad.
221 	 */
222     frompcindex = (unsigned short *) ( (long) frompcindex - (long) s_lowpc );
223     if ( (unsigned long) frompcindex > s_textsize ) {
224 	goto done;
225     }
226     frompcindex = &froms[ ( (long) frompcindex ) >> 1 ];
227     if ( *frompcindex == 0 ) {
228 	*frompcindex = ++tos[0].link;
229 	if ( *frompcindex >= tolimit ) {
230 	    goto overflow;
231 	}
232 	top = &tos[ *frompcindex ];
233 	top->selfpc = selfpc;
234 	top->count = 0;
235 	top->link = 0;
236     } else {
237 	top = &tos[ *frompcindex ];
238     }
239     for ( ; /* goto done */ ; top = &tos[ top -> link ] ) {
240 	if ( top -> selfpc == selfpc ) {
241 	    top -> count++;
242 	    goto done;
243 	}
244 	if ( top -> link == 0 ) {
245 	    top -> link = ++tos[0].link;
246 	    if ( top -> link >= tolimit )
247 		goto overflow;
248 	    top = &tos[ top -> link ];
249 	    top -> selfpc = selfpc;
250 	    top -> count = 1;
251 	    top -> link = 0;
252 	    goto done;
253 	}
254     }
255 done:
256     profiling = 0;
257     /* and fall through */
258 out:
259     asm( "	rsb" );
260     asm( "#undef r11" );
261     asm( "#undef r10" );
262     asm( "#undef r9" );
263     asm( "#undef _mcount");
264 
265 overflow:
266     tolimit = 0;
267 #   define	TOLIMIT	"mcount: tos overflow\n"
268     write( 2 , TOLIMIT , sizeof( TOLIMIT ) );
269     goto out;
270 }
271 
272 monitor( lowpc , highpc , buf , bufsiz )
273     char	*lowpc;
274     /* VARARGS1 */
275     char	*highpc;
276     int		*buf, bufsiz;
277 {
278     register o;
279 
280     if ( lowpc == 0 ) {
281 	profil( (char *) 0 , 0 , 0 , 0 );
282 	return;
283     }
284     sbuf = buf;
285     ssiz = bufsiz;
286     ( (struct phdr *) buf ) -> lpc = lowpc;
287     ( (struct phdr *) buf ) -> hpc = highpc;
288     ( (struct phdr *) buf ) -> ncnt = ssiz;
289     o = sizeof(struct phdr);
290     buf = (int *) ( ( (int) buf ) + o );
291     bufsiz -= o;
292     if ( bufsiz <= 0 )
293 	return;
294     o = ( ( (char *) highpc - (char *) lowpc) );
295     if( bufsiz < o )
296 	o = ( (float) bufsiz / o ) * 65536;
297     else
298 	o = 65536;
299     profil( buf , bufsiz , lowpc , o );
300 }
301 
302 /*
303  * This is a stub for the "brk" system call, which we want to
304  * catch so that it will not deallocate our data space.
305  * (of which the program is not aware)
306  */
307 asm("#define _curbrk curbrk");
308 extern char *curbrk;
309 
310 brk(addr)
311 	char *addr;
312 {
313 
314 	if (addr < minsbrk)
315 		addr = minsbrk;
316 	asm("	chmk	$17");
317 	asm("	jcs	cerror");
318 	curbrk = addr;
319 	return (0);
320 }
321