1/*-
2 * Copyright (c) 1991, 1998 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char sccsid[] = "@(#)gmon.c	5.3 (Berkeley) 5/22/91";
36#endif /* not lint */
37
38#if 0
39#include <unistd.h>
40
41#endif
42#ifdef DEBUG
43#include <stdio.h>
44#endif
45
46#include "gmon.h"
47
48extern mcount() asm ("mcount");
49extern char *minbrk asm ("minbrk");
50
51#ifdef __alpha
52extern char *sbrk ();
53#endif
54
55    /*
56     *	froms is actually a bunch of unsigned shorts indexing tos
57     */
58static int		profiling = 3;
59static unsigned short	*froms;
60static struct tostruct	*tos = 0;
61static long		tolimit = 0;
62static char		*s_lowpc = 0;
63static char		*s_highpc = 0;
64static unsigned long	s_textsize = 0;
65
66static int	ssiz;
67static char	*sbuf;
68static int	s_scale;
69    /* see profil(2) where this is describe (incorrectly) */
70#define		SCALE_1_TO_1	0x10000L
71
72#define	MSG "No space for profiling buffer(s)\n"
73
74monstartup(lowpc, highpc)
75    char	*lowpc;
76    char	*highpc;
77{
78    int			monsize;
79    char		*buffer;
80    register int	o;
81
82	/*
83	 *	round lowpc and highpc to multiples of the density we're using
84	 *	so the rest of the scaling (here and in gprof) stays in ints.
85	 */
86    lowpc = (char *)
87	    ROUNDDOWN((unsigned) lowpc, HISTFRACTION*sizeof(HISTCOUNTER));
88    s_lowpc = lowpc;
89    highpc = (char *)
90	    ROUNDUP((unsigned) highpc, HISTFRACTION*sizeof(HISTCOUNTER));
91    s_highpc = highpc;
92    s_textsize = highpc - lowpc;
93    monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr);
94    buffer = sbrk( monsize );
95    if ( buffer == (char *) -1 ) {
96	write( 2 , MSG , sizeof(MSG) );
97	return;
98    }
99    froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION );
100    if ( froms == (unsigned short *) -1 ) {
101	write( 2 , MSG , sizeof(MSG) );
102	froms = 0;
103	return;
104    }
105    tolimit = s_textsize * ARCDENSITY / 100;
106    if ( tolimit < MINARCS ) {
107	tolimit = MINARCS;
108    } else if ( tolimit > 65534 ) {
109	tolimit = 65534;
110    }
111    tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) );
112    if ( tos == (struct tostruct *) -1 ) {
113	write( 2 , MSG , sizeof(MSG) );
114	froms = 0;
115	tos = 0;
116	return;
117    }
118    minbrk = sbrk(0);
119    tos[0].link = 0;
120    sbuf = buffer;
121    ssiz = monsize;
122    ( (struct phdr *) buffer ) -> lpc = lowpc;
123    ( (struct phdr *) buffer ) -> hpc = highpc;
124    ( (struct phdr *) buffer ) -> ncnt = ssiz;
125    monsize -= sizeof(struct phdr);
126    if ( monsize <= 0 )
127	return;
128    o = highpc - lowpc;
129    if( monsize < o )
130#ifndef hp300
131	s_scale = ( (float) monsize / o ) * SCALE_1_TO_1;
132#else /* avoid floating point */
133    {
134	int quot = o / monsize;
135
136	if (quot >= 0x10000)
137		s_scale = 1;
138	else if (quot >= 0x100)
139		s_scale = 0x10000 / quot;
140	else if (o >= 0x800000)
141		s_scale = 0x1000000 / (o / (monsize >> 8));
142	else
143		s_scale = 0x1000000 / ((o << 8) / monsize);
144    }
145#endif
146    else
147	s_scale = SCALE_1_TO_1;
148    moncontrol(1);
149}
150
151_mcleanup()
152{
153    int			fd;
154    int			fromindex;
155    int			endfrom;
156    char		*frompc;
157    int			toindex;
158    struct rawarc	rawarc;
159
160    moncontrol(0);
161    fd = creat( "gmon.out" , 0666 );
162    if ( fd < 0 ) {
163	perror( "mcount: gmon.out" );
164	return;
165    }
166#   ifdef DEBUG
167	fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
168#   endif DEBUG
169    write( fd , sbuf , ssiz );
170    endfrom = s_textsize / (HASHFRACTION * sizeof(*froms));
171    for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) {
172	if ( froms[fromindex] == 0 ) {
173	    continue;
174	}
175	frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms));
176	for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
177#	    ifdef DEBUG
178		fprintf( stderr ,
179			"[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
180			frompc , tos[toindex].selfpc , tos[toindex].count );
181#	    endif DEBUG
182	    rawarc.raw_frompc = (unsigned long) frompc;
183	    rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc;
184	    rawarc.raw_count = tos[toindex].count;
185	    write( fd , &rawarc , sizeof rawarc );
186	}
187    }
188    close( fd );
189}
190
191mcount()
192{
193	register char			*selfpc;
194	register unsigned short		*frompcindex;
195	register struct tostruct	*top;
196	register struct tostruct	*prevtop;
197	register long			toindex;
198
199	/*
200	 *	find the return address for mcount,
201	 *	and the return address for mcount's caller.
202	 */
203
204	/* selfpc = pc pushed by mcount call.
205	   This identifies the function that was just entered.  */
206	selfpc = (void *) __builtin_return_address (0);
207	/* frompcindex = pc in preceding frame.
208	   This identifies the caller of the function just entered.  */
209	frompcindex = (void *) __builtin_return_address (1);
210	/*
211	 *	check that we are profiling
212	 *	and that we aren't recursively invoked.
213	 */
214	if (profiling) {
215		goto out;
216	}
217	profiling++;
218	/*
219	 *	check that frompcindex is a reasonable pc value.
220	 *	for example:	signal catchers get called from the stack,
221	 *			not from text space.  too bad.
222	 */
223	frompcindex = (unsigned short *) ((long) frompcindex - (long) s_lowpc);
224	if ((unsigned long) frompcindex > s_textsize) {
225		goto done;
226	}
227	frompcindex =
228	    &froms[((long) frompcindex) / (HASHFRACTION * sizeof(*froms))];
229	toindex = *frompcindex;
230	if (toindex == 0) {
231		/*
232		 *	first time traversing this arc
233		 */
234		toindex = ++tos[0].link;
235		if (toindex >= tolimit) {
236			goto overflow;
237		}
238		*frompcindex = toindex;
239		top = &tos[toindex];
240		top->selfpc = selfpc;
241		top->count = 1;
242		top->link = 0;
243		goto done;
244	}
245	top = &tos[toindex];
246	if (top->selfpc == selfpc) {
247		/*
248		 *	arc at front of chain; usual case.
249		 */
250		top->count++;
251		goto done;
252	}
253	/*
254	 *	have to go looking down chain for it.
255	 *	top points to what we are looking at,
256	 *	prevtop points to previous top.
257	 *	we know it is not at the head of the chain.
258	 */
259	for (; /* goto done */; ) {
260		if (top->link == 0) {
261			/*
262			 *	top is end of the chain and none of the chain
263			 *	had top->selfpc == selfpc.
264			 *	so we allocate a new tostruct
265			 *	and link it to the head of the chain.
266			 */
267			toindex = ++tos[0].link;
268			if (toindex >= tolimit) {
269				goto overflow;
270			}
271			top = &tos[toindex];
272			top->selfpc = selfpc;
273			top->count = 1;
274			top->link = *frompcindex;
275			*frompcindex = toindex;
276			goto done;
277		}
278		/*
279		 *	otherwise, check the next arc on the chain.
280		 */
281		prevtop = top;
282		top = &tos[top->link];
283		if (top->selfpc == selfpc) {
284			/*
285			 *	there it is.
286			 *	increment its count
287			 *	move it to the head of the chain.
288			 */
289			top->count++;
290			toindex = prevtop->link;
291			prevtop->link = top->link;
292			top->link = *frompcindex;
293			*frompcindex = toindex;
294			goto done;
295		}
296
297	}
298done:
299	profiling--;
300	/* and fall through */
301out:
302	return;		/* normal return restores saved registers */
303
304overflow:
305	profiling++; /* halt further profiling */
306#   define	TOLIMIT	"mcount: tos overflow\n"
307	write(2, TOLIMIT, sizeof(TOLIMIT));
308	goto out;
309}
310
311/* Control profiling;
312  	profiling is what mcount checks to see if
313  	all the data structures are ready.  */
314
315moncontrol(mode)
316    int mode;
317{
318    if (mode) {
319	/* start */
320	profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr),
321		(int)s_lowpc, s_scale);
322	profiling = 0;
323    } else {
324	/* stop */
325	profil((char *) 0, 0, 0, 0);
326	profiling = 3;
327    }
328}
329
330