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