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