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