BSD 4_1c_2 release
[unix-history] / usr / src / lib / libc / csu / gmon.c
CommitLineData
e804469b 1static char *sccsid = "@(#)gmon.c 4.10 (Berkeley) 1/14/83";
50084e08 2
bb9c5045 3#ifdef DEBUG
50084e08 4#include <stdio.h>
bb9c5045 5#endif DEBUG
50084e08 6
ee56ba6f 7#include "gmon.h"
387d0540
PK
8
9 /*
10 * froms is actually a bunch of unsigned shorts indexing tos
11 */
5a9da8d5 12static int profiling = 3;
50084e08
PK
13static unsigned short *froms;
14static struct tostruct *tos = 0;
019e8582 15static long tolimit = 0;
50084e08
PK
16static char *s_lowpc = 0;
17static char *s_highpc = 0;
3a2b18f4 18static unsigned long s_textsize = 0;
63238688 19static char *minsbrk = 0;
50084e08 20
387d0540
PK
21static int ssiz;
22static int *sbuf;
50084e08 23
50084e08
PK
24#define MSG "No space for monitor buffer(s)\n"
25
ee56ba6f 26monstartup(lowpc, highpc)
387d0540
PK
27 char *lowpc;
28 char *highpc;
50084e08 29{
3a2b18f4
PK
30 int monsize;
31 char *buffer;
32 char *sbrk();
50084e08 33
019e8582
PK
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));
387d0540 40 s_lowpc = lowpc;
019e8582
PK
41 highpc = (char *)
42 ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER));
387d0540 43 s_highpc = highpc;
3a2b18f4 44 s_textsize = highpc - lowpc;
019e8582 45 monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr);
387d0540
PK
46 buffer = sbrk( monsize );
47 if ( buffer == (char *) -1 ) {
48 write( 2 , MSG , sizeof(MSG) );
49 return;
50 }
f4d8fa4a 51 froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION );
387d0540
PK
52 if ( froms == (unsigned short *) -1 ) {
53 write( 2 , MSG , sizeof(MSG) );
54 froms = 0;
55 return;
56 }
5a9da8d5
KM
57 tolimit = s_textsize * ARCDENSITY / 100;
58 if ( tolimit < MINARCS ) {
59 tolimit = MINARCS;
60 } else if ( tolimit > 65534 ) {
61 tolimit = 65534;
4dff44be 62 }
5a9da8d5 63 tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) );
387d0540
PK
64 if ( tos == (struct tostruct *) -1 ) {
65 write( 2 , MSG , sizeof(MSG) );
66 froms = 0;
67 tos = 0;
68 return;
69 }
019e8582 70 minsbrk = sbrk(0);
387d0540 71 tos[0].link = 0;
5a9da8d5 72 monitor( lowpc , highpc , buffer , monsize , tolimit );
3a2b18f4 73 /*
5a9da8d5 74 * profiling is what mcount checks to see if
3a2b18f4 75 * all the data structures are ready!!!
3a2b18f4 76 */
5a9da8d5 77 profiling = 0;
50084e08
PK
78}
79
80_mcleanup()
81{
bb9c5045
KM
82 int fd;
83 int fromindex;
f4d8fa4a 84 int endfrom;
bb9c5045
KM
85 char *frompc;
86 int toindex;
87 struct rawarc rawarc;
50084e08 88
bb9c5045
KM
89 fd = creat( "gmon.out" , 0666 );
90 if ( fd < 0 ) {
387d0540 91 perror( "mcount: gmon.out" );
50084e08
PK
92 return;
93 }
387d0540
PK
94# ifdef DEBUG
95 fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
96# endif DEBUG
bb9c5045 97 write( fd , sbuf , ssiz );
f4d8fa4a
KM
98 endfrom = s_textsize / (HASHFRACTION * sizeof(*froms));
99 for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) {
50084e08
PK
100 if ( froms[fromindex] == 0 ) {
101 continue;
102 }
f4d8fa4a 103 frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms));
50084e08
PK
104 for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
105# ifdef DEBUG
22f3ec41
PK
106 fprintf( stderr ,
107 "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
50084e08
PK
108 frompc , tos[toindex].selfpc , tos[toindex].count );
109# endif DEBUG
bb9c5045
KM
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 );
50084e08
PK
114 }
115 }
bb9c5045 116 close( fd );
50084e08
PK
117}
118
019e8582
PK
119asm(".text");
120asm("#the beginning of mcount()");
121asm(".data");
50084e08
PK
122mcount()
123{
019e8582
PK
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 */
019e8582 129
50084e08 130#ifdef lint
019e8582
PK
131 selfpc = (char *)0;
132 frompcindex = 0;
50084e08
PK
133#else not lint
134 /*
785a53a1
PK
135 * find the return address for mcount,
136 * and the return address for mcount's caller.
50084e08 137 */
019e8582
PK
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) */
50084e08 141#endif not lint
785a53a1
PK
142 /*
143 * check that we are profiling
387d0540 144 * and that we aren't recursively invoked.
785a53a1 145 */
019e8582
PK
146 if (profiling) {
147 goto out;
148 }
5a9da8d5 149 profiling++;
785a53a1
PK
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 */
019e8582
PK
155 frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc);
156 if ((unsigned long)frompcindex > s_textsize) {
157 goto done;
50084e08 158 }
019e8582 159 frompcindex =
f4d8fa4a 160 &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))];
019e8582
PK
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;
50084e08 176 }
019e8582
PK
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
50084e08 229 }
785a53a1 230done:
5a9da8d5 231 profiling--;
019e8582 232 /* and fall through */
50084e08 233out:
019e8582 234 asm(" rsb");
50084e08
PK
235
236overflow:
5a9da8d5 237 profiling++; /* halt further profiling */
50084e08 238# define TOLIMIT "mcount: tos overflow\n"
019e8582
PK
239 write(2, TOLIMIT, sizeof(TOLIMIT));
240 goto out;
50084e08 241}
019e8582
PK
242asm(".text");
243asm("#the end of mcount()");
244asm(".data");
50084e08 245
ee56ba6f
KM
246/*VARARGS1*/
247monitor( lowpc , highpc , buf , bufsiz , nfunc )
387d0540 248 char *lowpc;
387d0540
PK
249 char *highpc;
250 int *buf, bufsiz;
ee56ba6f 251 int nfunc; /* not used, available for compatability only */
50084e08 252{
387d0540 253 register o;
50084e08 254
387d0540 255 if ( lowpc == 0 ) {
5a9da8d5 256 profiling++; /* halt profiling */
387d0540 257 profil( (char *) 0 , 0 , 0 , 0 );
ee56ba6f 258 _mcleanup();
387d0540
PK
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;
ef7f2ecf 271 o = ( ( (char *) highpc - (char *) lowpc) );
387d0540 272 if( bufsiz < o )
ef7f2ecf 273 o = ( (float) bufsiz / o ) * 65536;
387d0540 274 else
ef7f2ecf 275 o = 65536;
387d0540 276 profil( buf , bufsiz , lowpc , o );
50084e08 277}
0bbf4774
KM
278
279/*
280 * This is a stub for the "brk" system call, which we want to
63238688
KM
281 * catch so that it will not deallocate our data space.
282 * (of which the program is not aware)
0bbf4774 283 */
63238688
KM
284extern char *curbrk;
285
0bbf4774 286brk(addr)
63238688 287 char *addr;
0bbf4774 288{
63238688
KM
289
290 if (addr < minsbrk)
291 addr = minsbrk;
292 asm(" chmk $17");
ee56ba6f
KM
293 asm(" jcc 1f");
294 asm(" jmp cerror");
295asm("1:");
63238688
KM
296 curbrk = addr;
297 return (0);
0bbf4774 298}