Changes for 4.5.0 snapshot
[newlib-cygwin.git] / libgloss / i386 / cygmon-gmon.c
blob3c15b70d363c9631a5dbe1c625e9f649535afdab
1 /*-
2 * Copyright (c) 1991, 2000 The Regents of the University of California.
3 * All rights reserved.
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. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
31 * This is a modified gmon.c by J.W.Hawtin <oolon@ankh.org>,
32 * 14/8/96 based on the original gmon.c in GCC and the hacked version
33 * solaris 2 sparc version (config/sparc/gmon-sol.c) by Mark Eichin. To do
34 * process profiling on solaris 2.X X86
36 * It must be used in conjunction with sol2-gc1.asm, which is used to start
37 * and stop process monitoring.
39 * Differences.
41 * On Solaris 2 _mcount is called by library functions not mcount, so support
42 * has been added for both.
44 * Also the prototype for profil() is different
46 * Solaris 2 does not seem to have char *minbrk which allows the setting of
47 * the minimum SBRK region so this code has been removed and lets pray malloc
48 * does not mess it up.
50 * Notes
52 * This code could easily be integrated with the original gmon.c and perhaps
53 * should be.
56 #ifndef lint
57 static char sccsid[] = "@(#)gmon.c 5.3 (Berkeley) 5/22/91";
58 #endif /* not lint */
60 #define DEBUG
61 #ifdef DEBUG
62 #include <stdio.h>
63 #endif
65 #include "cygmon-gmon.h"
68 * froms is actually a bunch of unsigned shorts indexing tos
70 static int profiling = 3;
71 static unsigned short *froms;
72 static struct tostruct *tos = 0;
73 static long tolimit = 0;
74 static char *s_lowpc = 0;
75 static char *s_highpc = 0;
76 static unsigned long s_textsize = 0;
78 static int ssiz;
79 static char *sbuf;
80 static int s_scale;
81 /* see profil(2) where this is describe (incorrectly) */
82 #define SCALE_1_TO_1 0x10000L
84 #define MSG "No space for profiling buffer(s)\n"
86 extern int errno;
88 int
89 monstartup(lowpc, highpc)
90 char *lowpc;
91 char *highpc;
93 int monsize;
94 char *buffer;
95 register int o;
98 * round lowpc and highpc to multiples of the density we're using
99 * so the rest of the scaling (here and in gprof) stays in ints.
101 lowpc = (char *)
102 ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER));
103 s_lowpc = lowpc;
104 highpc = (char *)
105 ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER));
106 s_highpc = highpc;
107 s_textsize = highpc - lowpc;
108 monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr);
109 buffer = (char *) sbrk (monsize);
110 if (buffer == (char *) -1)
112 write (2, MSG , sizeof(MSG));
113 return;
115 bzero (buffer, monsize);
116 froms = (unsigned short *) sbrk (s_textsize / HASHFRACTION);
117 if (froms == (unsigned short *) -1)
119 write(2, MSG, sizeof(MSG));
120 froms = 0;
121 return;
123 bzero (froms, s_textsize / HASHFRACTION);
124 tolimit = s_textsize * ARCDENSITY / 100;
125 if (tolimit < MINARCS)
127 tolimit = MINARCS;
129 else
131 if (tolimit > 65534)
133 tolimit = 65534;
136 tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) );
137 if (tos == (struct tostruct *) -1)
139 write (2, MSG, sizeof(MSG));
140 froms = 0;
141 tos = 0;
142 return;
144 bzero (tos, tolimit * sizeof( struct tostruct ) );
145 tos[0].link = 0;
146 sbuf = buffer;
147 ssiz = monsize;
148 ( (struct phdr *) buffer ) -> lpc = lowpc;
149 ( (struct phdr *) buffer ) -> hpc = highpc;
150 ( (struct phdr *) buffer ) -> ncnt = ssiz;
151 monsize -= sizeof(struct phdr);
152 if ( monsize <= 0 )
153 return;
154 o = highpc - lowpc;
155 if (monsize < o)
157 s_scale = ( (float) monsize / o ) * SCALE_1_TO_1;
159 else
160 s_scale = SCALE_1_TO_1;
161 moncontrol (1);
164 void
165 _mcleanup()
167 int fd;
168 int fromindex;
169 int endfrom;
170 char *frompc;
171 int toindex;
172 struct rawarc rawarc;
174 moncontrol (0);
175 profil_write (1, sbuf, ssiz);
177 endfrom = s_textsize / (HASHFRACTION * sizeof(*froms));
178 for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ )
180 if ( froms[fromindex] == 0 )
182 continue;
184 frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms));
185 for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link)
187 rawarc.raw_frompc = (unsigned long) frompc;
188 rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc;
189 rawarc.raw_count = tos[toindex].count;
190 profil_write (2, &rawarc, sizeof (rawarc));
193 profil_write (3, 0, 0);
196 static char already_setup = 0;
198 _mcount()
200 register char *selfpc;
201 register unsigned short *frompcindex;
202 register struct tostruct *top;
203 register struct tostruct *prevtop;
204 register long toindex;
207 * find the return address for mcount,
208 * and the return address for mcount's caller.
211 /* selfpc = pc pushed by mcount call.
212 This identifies the function that was just entered. */
213 selfpc = (void *) __builtin_return_address (0);
214 /* frompcindex = pc in preceding frame.
215 This identifies the caller of the function just entered. */
216 frompcindex = (void *) __builtin_return_address (1);
218 if (! already_setup)
220 extern _etext();
221 extern _ftext();
222 already_setup = 1;
223 monstartup(_ftext, _etext);
224 atexit(_mcleanup);
227 * check that we are profiling
228 * and that we aren't recursively invoked.
230 if (profiling)
232 goto out;
234 profiling++;
236 * check that frompcindex is a reasonable pc value.
237 * for example: signal catchers get called from the stack,
238 * not from text space. too bad.
240 frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc);
241 if ((unsigned long)frompcindex > s_textsize)
243 goto done;
245 frompcindex =
246 &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))];
247 toindex = *frompcindex;
248 if (toindex == 0)
251 * first time traversing this arc
253 toindex = ++tos[0].link;
254 if (toindex >= tolimit)
256 goto overflow;
258 *frompcindex = toindex;
259 top = &tos[toindex];
260 top->selfpc = selfpc;
261 top->count = 1;
262 top->link = 0;
263 goto done;
265 top = &tos[toindex];
266 if (top->selfpc == selfpc)
269 * arc at front of chain; usual case.
271 top->count++;
272 goto done;
275 * have to go looking down chain for it.
276 * top points to what we are looking at,
277 * prevtop points to previous top.
278 * we know it is not at the head of the chain.
280 for (; /* goto done */; )
282 if (top->link == 0)
285 * top is end of the chain and none of the chain
286 * had top->selfpc == selfpc.
287 * so we allocate a new tostruct
288 * and link it to the head of the chain.
290 toindex = ++tos[0].link;
291 if (toindex >= tolimit)
293 goto overflow;
295 top = &tos[toindex];
296 top->selfpc = selfpc;
297 top->count = 1;
298 top->link = *frompcindex;
299 *frompcindex = toindex;
300 goto done;
303 * otherwise, check the next arc on the chain.
305 prevtop = top;
306 top = &tos[top->link];
307 if (top->selfpc == selfpc)
310 * there it is.
311 * increment its count
312 * move it to the head of the chain.
314 top->count++;
315 toindex = prevtop->link;
316 prevtop->link = top->link;
317 top->link = *frompcindex;
318 *frompcindex = toindex;
319 goto done;
322 done:
323 profiling--;
324 /* and fall through */
325 out:
326 return; /* normal return restores saved registers */
328 overflow:
329 profiling++; /* halt further profiling */
330 # define TOLIMIT "mcount: tos overflow\n"
331 write (2, TOLIMIT, sizeof(TOLIMIT));
332 goto out;
336 * Control profiling
337 * profiling is what mcount checks to see if
338 * all the data structures are ready.
340 moncontrol(mode)
341 int mode;
343 if (mode)
345 /* start */
346 profil((unsigned short *)(sbuf + sizeof(struct phdr)),
347 ssiz - sizeof(struct phdr),
348 (int)s_lowpc, s_scale);
350 profiling = 0;
352 else
354 /* stop */
355 profil((unsigned short *)0, 0, 0, 0);
356 profiling = 3;