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