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