xref: /csrg-svn/lib/libc/gmon/gmon.c (revision 11796)
1 static	char *sccsid = "@(#)gmon.c	4.11 (Berkeley) 03/30/83";
2 
3 #ifdef DEBUG
4 #include <stdio.h>
5 #endif DEBUG
6 
7 #include "gmon.h"
8 
9     /*
10      *	froms is actually a bunch of unsigned shorts indexing tos
11      */
12 static int		profiling = 3;
13 static unsigned short	*froms;
14 static struct tostruct	*tos = 0;
15 static long		tolimit = 0;
16 static char		*s_lowpc = 0;
17 static char		*s_highpc = 0;
18 static unsigned long	s_textsize = 0;
19 static char		*minsbrk = 0;
20 
21 static int	ssiz;
22 static int	*sbuf;
23 static int	s_scale;
24 
25 #define	MSG "No space for monitor buffer(s)\n"
26 
27 monstartup(lowpc, highpc)
28     char	*lowpc;
29     char	*highpc;
30 {
31     int			monsize;
32     char		*buffer;
33     char		*sbrk();
34 
35 	/*
36 	 *	round lowpc and highpc to multiples of the density we're using
37 	 *	so the rest of the scaling (here and in gprof) stays in ints.
38 	 */
39     lowpc = (char *)
40 	    ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER));
41     s_lowpc = lowpc;
42     highpc = (char *)
43 	    ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER));
44     s_highpc = highpc;
45     s_textsize = highpc - lowpc;
46     monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr);
47     buffer = sbrk( monsize );
48     if ( buffer == (char *) -1 ) {
49 	write( 2 , MSG , sizeof(MSG) );
50 	return;
51     }
52     froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION );
53     if ( froms == (unsigned short *) -1 ) {
54 	write( 2 , MSG , sizeof(MSG) );
55 	froms = 0;
56 	return;
57     }
58     tolimit = s_textsize * ARCDENSITY / 100;
59     if ( tolimit < MINARCS ) {
60 	tolimit = MINARCS;
61     } else if ( tolimit > 65534 ) {
62 	tolimit = 65534;
63     }
64     tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) );
65     if ( tos == (struct tostruct *) -1 ) {
66 	write( 2 , MSG , sizeof(MSG) );
67 	froms = 0;
68 	tos = 0;
69 	return;
70     }
71     minsbrk = sbrk(0);
72     tos[0].link = 0;
73     monitor( lowpc , highpc , buffer , monsize , tolimit );
74     moncontrol(1);
75 }
76 
77 _mcleanup()
78 {
79     int			fd;
80     int			fromindex;
81     int			endfrom;
82     char		*frompc;
83     int			toindex;
84     struct rawarc	rawarc;
85 
86     fd = creat( "gmon.out" , 0666 );
87     if ( fd < 0 ) {
88 	perror( "mcount: gmon.out" );
89 	return;
90     }
91 #   ifdef DEBUG
92 	fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
93 #   endif DEBUG
94     write( fd , sbuf , ssiz );
95     endfrom = s_textsize / (HASHFRACTION * sizeof(*froms));
96     for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) {
97 	if ( froms[fromindex] == 0 ) {
98 	    continue;
99 	}
100 	frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms));
101 	for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
102 #	    ifdef DEBUG
103 		fprintf( stderr ,
104 			"[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
105 			frompc , tos[toindex].selfpc , tos[toindex].count );
106 #	    endif DEBUG
107 	    rawarc.raw_frompc = (unsigned long) frompc;
108 	    rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc;
109 	    rawarc.raw_count = tos[toindex].count;
110 	    write( fd , &rawarc , sizeof rawarc );
111 	}
112     }
113     close( fd );
114 }
115 
116 asm(".text");
117 asm(".align 2");
118 asm("#the beginning of mcount()");
119 asm(".data");
120 mcount()
121 {
122 	register char			*selfpc;	/* r11 => r5 */
123 	register unsigned short		*frompcindex;	/* r10 => r4 */
124 	register struct tostruct	*top;		/* r9  => r3 */
125 	register struct tostruct	*prevtop;	/* r8  => r2 */
126 	register long			toindex;	/* r7  => r1 */
127 
128 #ifdef lint
129 	selfpc = (char *)0;
130 	frompcindex = 0;
131 #else not lint
132 	/*
133 	 *	find the return address for mcount,
134 	 *	and the return address for mcount's caller.
135 	 */
136 	asm("	.text");		/* make sure we're in text space */
137 	asm("	movl (sp), r11");	/* selfpc = ... (jsb frame) */
138 	asm("	movl 16(fp), r10");	/* frompcindex =     (calls frame) */
139 #endif not lint
140 	/*
141 	 *	check that we are profiling
142 	 *	and that we aren't recursively invoked.
143 	 */
144 	if (profiling) {
145 		goto out;
146 	}
147 	profiling++;
148 	/*
149 	 *	check that frompcindex is a reasonable pc value.
150 	 *	for example:	signal catchers get called from the stack,
151 	 *			not from text space.  too bad.
152 	 */
153 	frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc);
154 	if ((unsigned long)frompcindex > s_textsize) {
155 		goto done;
156 	}
157 	frompcindex =
158 	    &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))];
159 	toindex = *frompcindex;
160 	if (toindex == 0) {
161 		/*
162 		 *	first time traversing this arc
163 		 */
164 		toindex = ++tos[0].link;
165 		if (toindex >= tolimit) {
166 			goto overflow;
167 		}
168 		*frompcindex = toindex;
169 		top = &tos[toindex];
170 		top->selfpc = selfpc;
171 		top->count = 1;
172 		top->link = 0;
173 		goto done;
174 	}
175 	top = &tos[toindex];
176 	if (top->selfpc == selfpc) {
177 		/*
178 		 *	arc at front of chain; usual case.
179 		 */
180 		top->count++;
181 		goto done;
182 	}
183 	/*
184 	 *	have to go looking down chain for it.
185 	 *	top points to what we are looking at,
186 	 *	prevtop points to previous top.
187 	 *	we know it is not at the head of the chain.
188 	 */
189 	for (; /* goto done */; ) {
190 		if (top->link == 0) {
191 			/*
192 			 *	top is end of the chain and none of the chain
193 			 *	had top->selfpc == selfpc.
194 			 *	so we allocate a new tostruct
195 			 *	and link it to the head of the chain.
196 			 */
197 			toindex = ++tos[0].link;
198 			if (toindex >= tolimit) {
199 				goto overflow;
200 			}
201 			top = &tos[toindex];
202 			top->selfpc = selfpc;
203 			top->count = 1;
204 			top->link = *frompcindex;
205 			*frompcindex = toindex;
206 			goto done;
207 		}
208 		/*
209 		 *	otherwise, check the next arc on the chain.
210 		 */
211 		prevtop = top;
212 		top = &tos[top->link];
213 		if (top->selfpc == selfpc) {
214 			/*
215 			 *	there it is.
216 			 *	increment its count
217 			 *	move it to the head of the chain.
218 			 */
219 			top->count++;
220 			toindex = prevtop->link;
221 			prevtop->link = top->link;
222 			top->link = *frompcindex;
223 			*frompcindex = toindex;
224 			goto done;
225 		}
226 
227 	}
228 done:
229 	profiling--;
230 	/* and fall through */
231 out:
232 	asm("	rsb");
233 
234 overflow:
235 	profiling++; /* halt further profiling */
236 #   define	TOLIMIT	"mcount: tos overflow\n"
237 	write(2, TOLIMIT, sizeof(TOLIMIT));
238 	goto out;
239 }
240 asm(".text");
241 asm("#the end of mcount()");
242 asm(".data");
243 
244 /*VARARGS1*/
245 monitor( lowpc , highpc , buf , bufsiz , nfunc )
246     char	*lowpc;
247     char	*highpc;
248     int		*buf, bufsiz;
249     int		nfunc;	/* not used, available for compatability only */
250 {
251     register o;
252 
253     if ( lowpc == 0 ) {
254 	moncontrol(0);
255 	_mcleanup();
256 	return;
257     }
258     sbuf = buf;
259     ssiz = bufsiz;
260     ( (struct phdr *) buf ) -> lpc = lowpc;
261     ( (struct phdr *) buf ) -> hpc = highpc;
262     ( (struct phdr *) buf ) -> ncnt = ssiz;
263     o = sizeof(struct phdr);
264     buf = (int *) ( ( (int) buf ) + o );
265     bufsiz -= o;
266     if ( bufsiz <= 0 )
267 	return;
268     o = ( ( (char *) highpc - (char *) lowpc) );
269     if( bufsiz < o )
270 	o = ( (float) bufsiz / o ) * 65536;
271     else
272 	o = 65536;
273     s_scale = o;
274     moncontrol(1);
275 }
276 
277 /*
278  * Control profiling
279  *	profiling is what mcount checks to see if
280  *	all the data structures are ready.
281  */
282 moncontrol(mode)
283     int mode;
284 {
285     if (mode) {
286 	/* start */
287 	profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr),
288 		s_lowpc, s_scale);
289 	profiling = 0;
290     } else {
291 	/* stop */
292 	profil((char *)0, 0, 0, 0);
293 	profiling = 3;
294     }
295 }
296 
297 /*
298  * This is a stub for the "brk" system call, which we want to
299  * catch so that it will not deallocate our data space.
300  * (of which the program is not aware)
301  */
302 extern char *curbrk;
303 
304 brk(addr)
305 	char *addr;
306 {
307 
308 	if (addr < minsbrk)
309 		addr = minsbrk;
310 	asm("	chmk	$17");
311 	asm("	jcc	1f");
312 	asm("	jmp	cerror");
313 asm("1:");
314 	curbrk = addr;
315 	return (0);
316 }
317