OSDN Git Service

* config/sparc/sparc.h (TARGET_CM_MEDMID): Fix documentation.
[pf3gnuchains/gcc-fork.git] / gcc / config / sparc / gmon-sol2.c
1 /*-
2  * Copyright (c) 1991 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 /* Mangled into a form that works on Sparc Solaris 2 by Mark Eichin
35  * for Cygnus Support, July 1992.
36  */
37
38 #ifndef lint
39 static char sccsid[] = "@(#)gmon.c      5.3 (Berkeley) 5/22/91";
40 #endif /* not lint */
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <limits.h>
46 #include <unistd.h>
47 #include <fcntl.h>
48
49 #if 0
50 #include "sparc/gmon.h"
51 #else
52 struct phdr {
53   char *lpc;
54   char *hpc;
55   int ncnt;
56 };
57 #define HISTFRACTION 2
58 #define HISTCOUNTER unsigned short
59 #define HASHFRACTION 1
60 #define ARCDENSITY 2
61 #define MINARCS 50
62 struct tostruct {
63   char *selfpc;
64   long count;
65   unsigned short link;
66 };
67 struct rawarc {
68     unsigned long       raw_frompc;
69     unsigned long       raw_selfpc;
70     long                raw_count;
71 };
72 #define ROUNDDOWN(x,y)  (((x)/(y))*(y))
73 #define ROUNDUP(x,y)    ((((x)+(y)-1)/(y))*(y))
74
75 #endif
76
77 /* extern mcount() asm ("mcount"); */
78 /*extern*/ char *minbrk /* asm ("minbrk") */;
79
80     /*
81      *  froms is actually a bunch of unsigned shorts indexing tos
82      */
83 static int              profiling = 3;
84 static unsigned short   *froms;
85 static struct tostruct  *tos = 0;
86 static long             tolimit = 0;
87 static char             *s_lowpc = 0;
88 static char             *s_highpc = 0;
89 static unsigned long    s_textsize = 0;
90
91 static int      ssiz;
92 static char     *sbuf;
93 static int      s_scale;
94     /* see profil(2) where this is describe (incorrectly) */
95 #define         SCALE_1_TO_1    0x10000L
96
97 #define MSG "No space for profiling buffer(s)\n"
98
99 static void moncontrol();
100
101 void monstartup(lowpc, highpc)
102     char        *lowpc;
103     char        *highpc;
104 {
105     int                 monsize;
106     char                *buffer;
107     register int        o;
108
109         /*
110          *      round lowpc and highpc to multiples of the density we're using
111          *      so the rest of the scaling (here and in gprof) stays in ints.
112          */
113     lowpc = (char *)
114             ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER));
115     s_lowpc = lowpc;
116     highpc = (char *)
117             ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER));
118     s_highpc = highpc;
119     s_textsize = highpc - lowpc;
120     monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr);
121     buffer = sbrk( monsize );
122     if ( buffer == (char *) -1 ) {
123         write( 2 , MSG , sizeof(MSG) );
124         return;
125     }
126     froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION );
127     if ( froms == (unsigned short *) -1 ) {
128         write( 2 , MSG , sizeof(MSG) );
129         froms = 0;
130         return;
131     }
132     tolimit = s_textsize * ARCDENSITY / 100;
133     if ( tolimit < MINARCS ) {
134         tolimit = MINARCS;
135     } else if ( tolimit > 65534 ) {
136         tolimit = 65534;
137     }
138     tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) );
139     if ( tos == (struct tostruct *) -1 ) {
140         write( 2 , MSG , sizeof(MSG) );
141         froms = 0;
142         tos = 0;
143         return;
144     }
145     minbrk = sbrk(0);
146     tos[0].link = 0;
147     sbuf = buffer;
148     ssiz = monsize;
149     ( (struct phdr *) buffer ) -> lpc = lowpc;
150     ( (struct phdr *) buffer ) -> hpc = highpc;
151     ( (struct phdr *) buffer ) -> ncnt = ssiz;
152     monsize -= sizeof(struct phdr);
153     if ( monsize <= 0 )
154         return;
155     o = highpc - lowpc;
156     if( monsize < o )
157 #ifndef hp300
158         s_scale = ( (float) monsize / o ) * SCALE_1_TO_1;
159 #else /* avoid floating point */
160     {
161         int quot = o / monsize;
162
163         if (quot >= 0x10000)
164                 s_scale = 1;
165         else if (quot >= 0x100)
166                 s_scale = 0x10000 / quot;
167         else if (o >= 0x800000)
168                 s_scale = 0x1000000 / (o / (monsize >> 8));
169         else
170                 s_scale = 0x1000000 / ((o << 8) / monsize);
171     }
172 #endif
173     else
174         s_scale = SCALE_1_TO_1;
175     moncontrol(1);
176 }
177
178 void
179 _mcleanup()
180 {
181     int                 fd;
182     int                 fromindex;
183     int                 endfrom;
184     char                *frompc;
185     int                 toindex;
186     struct rawarc       rawarc;
187     char                *profdir;
188     char                *proffile;
189     char                *progname;
190     char                 buf[PATH_MAX];
191     extern char        **___Argv;
192
193     moncontrol(0);
194
195     if ((profdir = getenv("PROFDIR")) != NULL) {
196         /* If PROFDIR contains a null value, no profiling output is produced */
197         if (*profdir == '\0') {
198             return;
199         }
200
201         progname=strrchr(___Argv[0], '/');
202         if (progname == NULL)
203             progname=___Argv[0];
204         else
205             progname++;
206
207         sprintf(buf, "%s/%ld.%s", profdir, getpid(), progname);
208         proffile = buf;
209     } else {
210         proffile = "gmon.out";
211     }
212
213     fd = creat( proffile, 0666 );
214     if ( fd < 0 ) {
215         perror( proffile );
216         return;
217     }
218 #   ifdef DEBUG
219         fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
220 #   endif DEBUG
221     write( fd , sbuf , ssiz );
222     endfrom = s_textsize / (HASHFRACTION * sizeof(*froms));
223     for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) {
224         if ( froms[fromindex] == 0 ) {
225             continue;
226         }
227         frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms));
228         for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
229 #           ifdef DEBUG
230                 fprintf( stderr ,
231                         "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
232                         frompc , tos[toindex].selfpc , tos[toindex].count );
233 #           endif DEBUG
234             rawarc.raw_frompc = (unsigned long) frompc;
235             rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc;
236             rawarc.raw_count = tos[toindex].count;
237             write( fd , &rawarc , sizeof rawarc );
238         }
239     }
240     close( fd );
241 }
242
243 /*
244  * The Sparc stack frame is only held together by the frame pointers
245  * in the register windows. According to the SVR4 SPARC ABI
246  * Supplement, Low Level System Information/Operating System
247  * Interface/Software Trap Types, a type 3 trap will flush all of the
248  * register windows to the stack, which will make it possible to walk
249  * the frames and find the return addresses.
250  *      However, it seems awfully expensive to incur a trap (system
251  * call) for every function call. It turns out that "call" simply puts
252  * the return address in %o7 expecting the "save" in the procedure to
253  * shift it into %i7; this means that before the "save" occurs, %o7
254  * contains the address of the call to mcount, and %i7 still contains
255  * the caller above that. The asm mcount here simply saves those
256  * registers in argument registers and branches to internal_mcount,
257  * simulating a call with arguments.
258  *      Kludges:
259  *      1) the branch to internal_mcount is hard coded; it should be
260  * possible to tell asm to use the assembler-name of a symbol.
261  *      2) in theory, the function calling mcount could have saved %i7
262  * somewhere and reused the register; in practice, I *think* this will
263  * break longjmp (and maybe the debugger) but I'm not certain. (I take
264  * some comfort in the knowledge that it will break the native mcount
265  * as well.)
266  *      3) if builtin_return_address worked, this could be portable.
267  * However, it would really have to be optimized for arguments of 0
268  * and 1 and do something like what we have here in order to avoid the
269  * trap per function call performance hit. 
270  *      4) the atexit and monsetup calls prevent this from simply
271  * being a leaf routine that doesn't do a "save" (and would thus have
272  * access to %o7 and %i7 directly) but the call to write() at the end
273  * would have also prevented this.
274  *
275  * -- [eichin:19920702.1107EST]
276  */
277
278 /* i7 == last ret, -> frompcindex */
279 /* o7 == current ret, -> selfpc */
280 /* Solaris 2 libraries use _mcount.  */
281 asm(".global _mcount; _mcount: mov %i7,%o1; mov %o7,%o0;b,a internal_mcount");
282 /* This is for compatibility with old versions of gcc which used mcount.  */
283 asm(".global mcount; mcount: mov %i7,%o1; mov %o7,%o0;b,a internal_mcount");
284
285 static void internal_mcount(selfpc, frompcindex)
286         register char                   *selfpc;
287         register unsigned short         *frompcindex;
288 {
289         register struct tostruct        *top;
290         register struct tostruct        *prevtop;
291         register long                   toindex;
292         static char already_setup;
293
294         /*
295          *      find the return address for mcount,
296          *      and the return address for mcount's caller.
297          */
298
299         if(!already_setup) {
300           extern etext();
301           already_setup = 1;
302           monstartup(0, etext);
303 #ifdef USE_ONEXIT
304           on_exit(_mcleanup, 0);
305 #else
306           atexit(_mcleanup);
307 #endif
308         }
309         /*
310          *      check that we are profiling
311          *      and that we aren't recursively invoked.
312          */
313         if (profiling) {
314                 goto out;
315         }
316         profiling++;
317         /*
318          *      check that frompcindex is a reasonable pc value.
319          *      for example:    signal catchers get called from the stack,
320          *                      not from text space.  too bad.
321          */
322         frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc);
323         if ((unsigned long)frompcindex > s_textsize) {
324                 goto done;
325         }
326         frompcindex =
327             &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))];
328         toindex = *frompcindex;
329         if (toindex == 0) {
330                 /*
331                  *      first time traversing this arc
332                  */
333                 toindex = ++tos[0].link;
334                 if (toindex >= tolimit) {
335                         goto overflow;
336                 }
337                 *frompcindex = toindex;
338                 top = &tos[toindex];
339                 top->selfpc = selfpc;
340                 top->count = 1;
341                 top->link = 0;
342                 goto done;
343         }
344         top = &tos[toindex];
345         if (top->selfpc == selfpc) {
346                 /*
347                  *      arc at front of chain; usual case.
348                  */
349                 top->count++;
350                 goto done;
351         }
352         /*
353          *      have to go looking down chain for it.
354          *      top points to what we are looking at,
355          *      prevtop points to previous top.
356          *      we know it is not at the head of the chain.
357          */
358         for (; /* goto done */; ) {
359                 if (top->link == 0) {
360                         /*
361                          *      top is end of the chain and none of the chain
362                          *      had top->selfpc == selfpc.
363                          *      so we allocate a new tostruct
364                          *      and link it to the head of the chain.
365                          */
366                         toindex = ++tos[0].link;
367                         if (toindex >= tolimit) {
368                                 goto overflow;
369                         }
370                         top = &tos[toindex];
371                         top->selfpc = selfpc;
372                         top->count = 1;
373                         top->link = *frompcindex;
374                         *frompcindex = toindex;
375                         goto done;
376                 }
377                 /*
378                  *      otherwise, check the next arc on the chain.
379                  */
380                 prevtop = top;
381                 top = &tos[top->link];
382                 if (top->selfpc == selfpc) {
383                         /*
384                          *      there it is.
385                          *      increment its count
386                          *      move it to the head of the chain.
387                          */
388                         top->count++;
389                         toindex = prevtop->link;
390                         prevtop->link = top->link;
391                         top->link = *frompcindex;
392                         *frompcindex = toindex;
393                         goto done;
394                 }
395
396         }
397 done:
398         profiling--;
399         /* and fall through */
400 out:
401         return;         /* normal return restores saved registers */
402
403 overflow:
404         profiling++; /* halt further profiling */
405 #   define      TOLIMIT "mcount: tos overflow\n"
406         write(2, TOLIMIT, sizeof(TOLIMIT));
407         goto out;
408 }
409
410 /*
411  * Control profiling
412  *      profiling is what mcount checks to see if
413  *      all the data structures are ready.
414  */
415 static void moncontrol(mode)
416     int mode;
417 {
418     if (mode) {
419         /* start */
420         profil((unsigned short *)(sbuf + sizeof(struct phdr)),
421                ssiz - sizeof(struct phdr),
422                (int)s_lowpc, s_scale);
423         profiling = 0;
424     } else {
425         /* stop */
426         profil((unsigned short *)0, 0, 0, 0);
427         profiling = 3;
428     }
429 }