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