xref: /csrg-svn/lib/libc/gmon/gmon.c (revision 9531)
1 static	char *sccsid = "@(#)gmon.c	4.7 (Berkeley) 12/04/82";
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 unsigned short	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     s_lowpc = lowpc;
35     s_highpc = highpc;
36     s_textsize = highpc - lowpc;
37     monsize = (s_textsize + 1) / 2 + sizeof(struct phdr);
38     buffer = sbrk( monsize );
39     if ( buffer == (char *) -1 ) {
40 	write( 2 , MSG , sizeof(MSG) );
41 	return;
42     }
43     froms = (unsigned short *) sbrk( s_textsize );
44     if ( froms == (unsigned short *) -1 ) {
45 	write( 2 , MSG , sizeof(MSG) );
46 	froms = 0;
47 	return;
48     }
49     limit = s_textsize * DENSITY / 100;
50     if ( limit < MINCNT ) {
51 	limit = MINCNT;
52     } else if ( limit > 65534 ) {
53 	limit = 65534;
54     }
55     tos = (struct tostruct *) sbrk( limit * sizeof( struct tostruct ) );
56     if ( tos == (struct tostruct *) -1 ) {
57 	write( 2 , MSG , sizeof(MSG) );
58 	froms = 0;
59 	tos = 0;
60 	return;
61     }
62     tos[0].link = 0;
63 	/*
64 	 *	tolimit is what mcount checks to see if
65 	 *	all the data structures are ready!!!
66 	 *	make sure it won't overflow.
67 	 */
68     tolimit = limit;
69     monitor( lowpc , highpc , buffer , monsize , tolimit );
70 }
71 
72 _mcleanup()
73 {
74     int			fd;
75     int			fromindex;
76     char		*frompc;
77     int			toindex;
78     struct rawarc	rawarc;
79 
80     fd = creat( "gmon.out" , 0666 );
81     if ( fd < 0 ) {
82 	perror( "mcount: gmon.out" );
83 	return;
84     }
85 #   ifdef DEBUG
86 	fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
87 #   endif DEBUG
88     write( fd , sbuf , ssiz );
89     for ( fromindex = 0 ; fromindex < s_textsize>>1 ; fromindex++ ) {
90 	if ( froms[fromindex] == 0 ) {
91 	    continue;
92 	}
93 	frompc = s_lowpc + (fromindex<<1);
94 	for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
95 #	    ifdef DEBUG
96 		fprintf( stderr ,
97 			"[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
98 			frompc , tos[toindex].selfpc , tos[toindex].count );
99 #	    endif DEBUG
100 	    rawarc.raw_frompc = (unsigned long) frompc;
101 	    rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc;
102 	    rawarc.raw_count = tos[toindex].count;
103 	    write( fd , &rawarc , sizeof rawarc );
104 	}
105     }
106     close( fd );
107 }
108 
109     /*
110      *	This routine is massaged so that it may be jsb'ed to
111      */
112 asm("#define _mcount mcount");
113 mcount()
114 {
115     register char		*selfpc;	/* r11 */
116     register unsigned short	*frompcindex;	/* r10 */
117     register struct tostruct	*top;		/* r9 */
118     static int			profiling = 0;
119 
120     asm( "	forgot to run ex script on gcrt0.s" );
121     asm( "#define r11 r5" );
122     asm( "#define r10 r4" );
123     asm( "#define r9 r3" );
124 #ifdef lint
125     selfpc = (char *) 0;
126     frompcindex = 0;
127 #else not lint
128 	/*
129 	 *	find the return address for mcount,
130 	 *	and the return address for mcount's caller.
131 	 */
132     asm("	movl (sp), r11");	/* selfpc = ... (jsb frame) */
133     asm("	movl 16(fp), r10");	/* frompcindex =     (calls frame) */
134 #endif not lint
135 	/*
136 	 *	check that we are profiling
137 	 *	and that we aren't recursively invoked.
138 	 */
139     if ( tolimit == 0 ) {
140 	goto out;
141     }
142     if ( profiling ) {
143 	goto out;
144     }
145     profiling = 1;
146 	/*
147 	 *	check that frompcindex is a reasonable pc value.
148 	 *	for example:	signal catchers get called from the stack,
149 	 *			not from text space.  too bad.
150 	 */
151     frompcindex = (unsigned short *) ( (long) frompcindex - (long) s_lowpc );
152     if ( (unsigned long) frompcindex > s_textsize ) {
153 	goto done;
154     }
155     frompcindex = &froms[ ( (long) frompcindex ) >> 1 ];
156     if ( *frompcindex == 0 ) {
157 	*frompcindex = ++tos[0].link;
158 	if ( *frompcindex >= tolimit ) {
159 	    goto overflow;
160 	}
161 	top = &tos[ *frompcindex ];
162 	top->selfpc = selfpc;
163 	top->count = 0;
164 	top->link = 0;
165     } else {
166 	top = &tos[ *frompcindex ];
167     }
168     for ( ; /* goto done */ ; top = &tos[ top -> link ] ) {
169 	if ( top -> selfpc == selfpc ) {
170 	    top -> count++;
171 	    goto done;
172 	}
173 	if ( top -> link == 0 ) {
174 	    top -> link = ++tos[0].link;
175 	    if ( top -> link >= tolimit )
176 		goto overflow;
177 	    top = &tos[ top -> link ];
178 	    top -> selfpc = selfpc;
179 	    top -> count = 1;
180 	    top -> link = 0;
181 	    goto done;
182 	}
183     }
184 done:
185     profiling = 0;
186     /* and fall through */
187 out:
188     asm( "	rsb" );
189     asm( "#undef r11" );
190     asm( "#undef r10" );
191     asm( "#undef r9" );
192     asm( "#undef _mcount");
193 
194 overflow:
195     tolimit = 0;
196 #   define	TOLIMIT	"mcount: tos overflow\n"
197     write( 2 , TOLIMIT , sizeof( TOLIMIT ) );
198     goto out;
199 }
200 
201 /*VARARGS1*/
202 monitor( lowpc , highpc , buf , bufsiz , nfunc )
203     char	*lowpc;
204     char	*highpc;
205     int		*buf, bufsiz;
206     int		nfunc;	/* not used, available for compatability only */
207 {
208     register o;
209 
210     if ( lowpc == 0 ) {
211 	profil( (char *) 0 , 0 , 0 , 0 );
212 	_mcleanup();
213 	return;
214     }
215     sbuf = buf;
216     ssiz = bufsiz;
217     ( (struct phdr *) buf ) -> lpc = lowpc;
218     ( (struct phdr *) buf ) -> hpc = highpc;
219     ( (struct phdr *) buf ) -> ncnt = ssiz;
220     o = sizeof(struct phdr);
221     buf = (int *) ( ( (int) buf ) + o );
222     bufsiz -= o;
223     if ( bufsiz <= 0 )
224 	return;
225     o = ( ( (char *) highpc - (char *) lowpc) );
226     if( bufsiz < o )
227 	o = ( (float) bufsiz / o ) * 65536;
228     else
229 	o = 65536;
230     profil( buf , bufsiz , lowpc , o );
231 }
232 
233 /*
234  * This is a stub for the "brk" system call, which we want to
235  * catch so that it will not deallocate our data space.
236  * (of which the program is not aware)
237  */
238 asm("#define _curbrk curbrk");
239 extern char *curbrk;
240 
241 brk(addr)
242 	char *addr;
243 {
244 
245 	if (addr < minsbrk)
246 		addr = minsbrk;
247 	asm("	chmk	$17");
248 	asm("	jcc	1f");
249 	asm("	jmp	cerror");
250 asm("1:");
251 	curbrk = addr;
252 	return (0);
253 }
254