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