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