OSDN Git Service

Initial revision
authorcoxs <coxs@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 30 Aug 1996 18:14:14 +0000 (18:14 +0000)
committercoxs <coxs@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 30 Aug 1996 18:14:14 +0000 (18:14 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@12679 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/config/i386/gmon-sol2.c [new file with mode: 0644]
gcc/config/i386/sol2-gc1.asm [new file with mode: 0644]

diff --git a/gcc/config/i386/gmon-sol2.c b/gcc/config/i386/gmon-sol2.c
new file mode 100644 (file)
index 0000000..13d87ec
--- /dev/null
@@ -0,0 +1,402 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* 
+ * Re rework of the solaris 2 version of gmon by J.W.Hawtin 12/8/1996
+ * Does not work right yet.
+ */
+
+/*
+ * This is a modified gmon.c by J.W.Hawtin <J.W.Hawtin@lboro.ac.uk>,
+ * 14/8/96 based on the original gmon.c in GCC and the hacked version
+ * solaris 2 sparc version (config/sparc/gmon-sol.c) by Mark Eichin. To do
+ * process profiling on solaris 2.4 X86
+ *
+ * It must be used in conjunction with sol2-gc1.asm, which is used to start
+ * and stop process monitoring.
+ *
+ * Differences.
+ *
+ * On Solaris 2 _mcount is called my library functions not mcount, so support
+ * has been added for both.
+ *
+ * Also the prototype for profil() is different
+ *
+ * Solaris 2 does not seem to have char *minbrk whcih allows the setting of
+ * the minimum SBRK region so this code has been removed and lets pray malloc
+ * does not mess it up.
+ *
+ * Notes
+ *
+ * This code could easily be integrated with the orginal gmon.c and perhaps
+ * should be.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)gmon.c     5.3 (Berkeley) 5/22/91";
+#endif /* not lint */
+
+#if 0
+#include <unistd.h>
+
+#endif
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+#if 0
+#include "i386/gmon.h"
+#else
+
+struct phdr {
+                char    *lpc;
+                char    *hpc;
+                int     ncnt;
+};
+
+
+#define HISTFRACTION 2
+#define HISTCOUNTER unsigned short
+#define HASHFRACTION 1
+#define ARCDENSITY 2
+#define MINARCS 50
+#define BASEADDRESS 0x8000000 /* On Solaris 2 X86 all excutables start here
+                                and not at 0 */ 
+
+struct tostruct {
+  char *selfpc;
+  long count;
+  unsigned short link;
+};
+struct rawarc {
+    unsigned long       raw_frompc;
+    unsigned long       raw_selfpc;
+    long                raw_count;
+};
+#define ROUNDDOWN(x,y)  (((x)/(y))*(y))
+#define ROUNDUP(x,y)    ((((x)+(y)-1)/(y))*(y))
+#endif
+
+/* char *minbrk; */
+
+#ifdef __alpha
+extern char *sbrk ();
+#endif
+
+    /*
+     * froms is actually a bunch of unsigned shorts indexing tos
+     */
+static int             profiling = 3;
+static unsigned short  *froms;
+static struct tostruct *tos = 0;
+static long            tolimit = 0;
+static char            *s_lowpc = 0;
+static char            *s_highpc = 0;
+static unsigned long   s_textsize = 0;
+
+static int     ssiz;
+static char    *sbuf;
+static int     s_scale;
+    /* see profil(2) where this is describe (incorrectly) */
+#define                SCALE_1_TO_1    0x10000L
+
+#define        MSG "No space for profiling buffer(s)\n"
+
+extern int errno;
+
+monstartup(lowpc, highpc)
+    char       *lowpc;
+    char       *highpc;
+{
+    int                        monsize;
+    char               *buffer;
+    register int       o;
+
+       /*
+        *      round lowpc and highpc to multiples of the density we're using
+        *      so the rest of the scaling (here and in gprof) stays in ints.
+        */
+    lowpc = (char *)
+           ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER));
+    s_lowpc = lowpc;
+    highpc = (char *)
+           ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER));
+    s_highpc = highpc;
+    s_textsize = highpc - lowpc;
+    monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr);
+    buffer = (char *) sbrk( monsize );
+    if ( buffer == (char *) -1 ) {
+       write( 2 , MSG , sizeof(MSG) );
+       return;
+    }
+    froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION );
+    if ( froms == (unsigned short *) -1 ) {
+       write( 2 , MSG , sizeof(MSG) );
+       froms = 0;
+       return;
+    }
+    tolimit = s_textsize * ARCDENSITY / 100;
+    if ( tolimit < MINARCS ) {
+       tolimit = MINARCS;
+    } else if ( tolimit > 65534 ) {
+       tolimit = 65534;
+    }
+    tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) );
+    if ( tos == (struct tostruct *) -1 ) {
+       write( 2 , MSG , sizeof(MSG) );
+       froms = 0;
+       tos = 0;
+       return;
+    }
+/*    minbrk = (char *) sbrk(0);*/
+    tos[0].link = 0;
+    sbuf = buffer;
+    ssiz = monsize;
+    ( (struct phdr *) buffer ) -> lpc = lowpc;
+    ( (struct phdr *) buffer ) -> hpc = highpc;
+    ( (struct phdr *) buffer ) -> ncnt = ssiz;
+    monsize -= sizeof(struct phdr);
+    if ( monsize <= 0 )
+       return;
+    o = highpc - lowpc;
+    if( monsize < o )
+#ifndef hp300
+       s_scale = ( (float) monsize / o ) * SCALE_1_TO_1;
+#else /* avoid floating point */
+    {
+       int quot = o / monsize;
+
+       if (quot >= 0x10000)
+               s_scale = 1;
+       else if (quot >= 0x100)
+               s_scale = 0x10000 / quot;
+       else if (o >= 0x800000)
+               s_scale = 0x1000000 / (o / (monsize >> 8));
+       else
+               s_scale = 0x1000000 / ((o << 8) / monsize);
+    }
+#endif
+    else
+       s_scale = SCALE_1_TO_1;
+    moncontrol(1);
+}
+
+_mcleanup()
+{
+    int                        fd;
+    int                        fromindex;
+    int                        endfrom;
+    char               *frompc;
+    int                        toindex;
+    struct rawarc      rawarc;
+
+    moncontrol(0);
+    fd = creat( "gmon.out" , 0666 );
+    if ( fd < 0 ) {
+       perror( "mcount: gmon.out" );
+       return;
+    }
+#   ifdef DEBUG
+       fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
+#   endif DEBUG
+
+    write( fd , sbuf , ssiz );
+    endfrom = s_textsize / (HASHFRACTION * sizeof(*froms));
+    for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) {
+       if ( froms[fromindex] == 0 ) {
+           continue;
+       }
+       frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms));
+       for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
+#          ifdef DEBUG
+               fprintf( stderr ,
+                       "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
+                       frompc , tos[toindex].selfpc , tos[toindex].count );
+#          endif DEBUG
+           rawarc.raw_frompc = (unsigned long) frompc;
+           rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc;
+           rawarc.raw_count = tos[toindex].count;
+           write( fd , &rawarc , sizeof rawarc );
+       }
+    }
+    close( fd );
+}
+
+/* Solaris 2 libraries use _mcount.  */
+asm(".globl _mcount; _mcount: jmp internal_mcount");
+/* This is for compatibility with old versions of gcc which used mcount.  */
+asm(".globl mcount; mcount: jmp internal_mcount");
+
+internal_mcount()
+{
+       register char                   *selfpc;
+       register unsigned short         *frompcindex;
+       register struct tostruct        *top;
+       register struct tostruct        *prevtop;
+       register long                   toindex;
+
+       /*
+        *      find the return address for mcount,
+        *      and the return address for mcount's caller.
+        */
+
+       /* selfpc = pc pushed by mcount call.
+          This identifies the function that was just entered.  */
+       selfpc = (void *) __builtin_return_address (0);
+       /* frompcindex = pc in preceding frame.
+          This identifies the caller of the function just entered.  */
+       frompcindex = (void *) __builtin_return_address (1);
+
+       /*
+        *      check that we are profiling
+        *      and that we aren't recursively invoked.
+        */
+       if (profiling) {
+               goto out;
+       }
+       profiling++;
+       /*
+        *      check that frompcindex is a reasonable pc value.
+        *      for example:    signal catchers get called from the stack,
+        *                      not from text space.  too bad.
+        */
+       frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc);
+       if ((unsigned long)frompcindex > s_textsize) {
+               goto done;
+       }
+       frompcindex =
+           &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))];
+       toindex = *frompcindex;
+       if (toindex == 0) {
+               /*
+                *      first time traversing this arc
+                */
+               toindex = ++tos[0].link;
+               if (toindex >= tolimit) {
+                       goto overflow;
+               }
+               *frompcindex = toindex;
+               top = &tos[toindex];
+               top->selfpc = selfpc;
+               top->count = 1;
+               top->link = 0;
+               goto done;
+       }
+       top = &tos[toindex];
+       if (top->selfpc == selfpc) {
+               /*
+                *      arc at front of chain; usual case.
+                */
+               top->count++;
+               goto done;
+       }
+       /*
+        *      have to go looking down chain for it.
+        *      top points to what we are looking at,
+        *      prevtop points to previous top.
+        *      we know it is not at the head of the chain.
+        */
+       for (; /* goto done */; ) {
+               if (top->link == 0) {
+                       /*
+                        *      top is end of the chain and none of the chain
+                        *      had top->selfpc == selfpc.
+                        *      so we allocate a new tostruct
+                        *      and link it to the head of the chain.
+                        */
+                       toindex = ++tos[0].link;
+                       if (toindex >= tolimit) {
+                               goto overflow;
+                       }
+                       top = &tos[toindex];
+                       top->selfpc = selfpc;
+                       top->count = 1;
+                       top->link = *frompcindex;
+                       *frompcindex = toindex;
+                       goto done;
+               }
+               /*
+                *      otherwise, check the next arc on the chain.
+                */
+               prevtop = top;
+               top = &tos[top->link];
+               if (top->selfpc == selfpc) {
+                       /*
+                        *      there it is.
+                        *      increment its count
+                        *      move it to the head of the chain.
+                        */
+                       top->count++;
+                       toindex = prevtop->link;
+                       prevtop->link = top->link;
+                       top->link = *frompcindex;
+                       *frompcindex = toindex;
+                       goto done;
+               }
+
+       }
+done:
+       profiling--;
+       /* and fall through */
+out:
+       return;         /* normal return restores saved registers */
+
+overflow:
+       profiling++; /* halt further profiling */
+#   define     TOLIMIT "mcount: tos overflow\n"
+       write(2, TOLIMIT, sizeof(TOLIMIT));
+       goto out;
+}
+
+/*
+ * Control profiling
+ *     profiling is what mcount checks to see if
+ *     all the data structures are ready.
+ */
+moncontrol(mode)
+    int mode;
+{
+    if (mode)
+    {
+      /* start */
+      profil((unsigned short *)(sbuf + sizeof(struct phdr)),
+            ssiz - sizeof(struct phdr),
+            (int)s_lowpc, s_scale);
+      
+      profiling = 0;
+    } else {
+      /* stop */
+      profil((unsigned short *)0, 0, 0, 0);
+      profiling = 3;
+    }
+}
diff --git a/gcc/config/i386/sol2-gc1.asm b/gcc/config/i386/sol2-gc1.asm
new file mode 100644 (file)
index 0000000..8983a67
--- /dev/null
@@ -0,0 +1,160 @@
+! gcrt1.s for Solaris 2, x86
+
+!   Copyright (C) 1993 Free Software Foundation, Inc.
+!   Written By Fred Fish, Nov 1992
+! 
+! This file is free software; you can redistribute it and/or modify it
+! under the terms of the GNU General Public License as published by the
+! Free Software Foundation; either version 2, or (at your option) any
+! later version.
+! 
+! In addition to the permissions in the GNU General Public License, the
+! Free Software Foundation gives you unlimited permission to link the
+! compiled version of this file with other programs, and to distribute
+! those programs without any restriction coming from the use of this
+! file.  (The General Public License restrictions do apply in other
+! respects; for example, they cover modification of the file, and
+! distribution when not linked into another program.)
+! 
+! This file is distributed in the hope that it will be useful, but
+! WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+! General Public License for more details.
+! 
+! You should have received a copy of the GNU General Public License
+! along with this program; see the file COPYING.  If not, write to
+! the Free Software Foundation, 59 Temple Place - Suite 330,
+! Boston, MA 02111-1307, USA.
+! 
+!    As a special exception, if you link this library with files
+!    compiled with GCC to produce an executable, this does not cause
+!    the resulting executable to be covered by the GNU General Public License.
+!    This exception does not however invalidate any other reasons why
+!    the executable file might be covered by the GNU General Public License.
+! 
+
+! This file takes control of the process from the kernel, as specified
+! in section 3 of the System V Application Binary Interface, Intel386
+! Processor Supplement.  It has been constructed from information obtained
+! from the ABI, information obtained from single stepping existing
+! Solaris executables through their startup code with gdb, and from
+! information obtained by single stepping executables on other i386 SVR4
+! implementations.  This file is the first thing linked into any executable.
+
+! This is a modified crt1.s by J.W.Hawtin <J.W.Hawtin@lboro.ac.uk> 15/8/96, 
+! to allow program profiling, by calling monstartup on entry and _mcleanup 
+! on exit
+
+       .file   "gcrt1.s"
+       .ident  "GNU C gcrt1.s"
+       .weak   _DYNAMIC
+       .text
+
+! Start creating the initial frame by pushing a NULL value for the return
+! address of the initial frame, and mark the end of the stack frame chain
+! (the innermost stack frame) with a NULL value, per page 3-32 of the ABI.
+! Initialize the first stack frame pointer in %ebp (the contents of which
+! are unspecified at process initialization).
+
+       .globl  _start
+_start:
+       pushl   $0x0
+       pushl   $0x0
+       movl    %esp,%ebp
+
+! As specified per page 3-32 of the ABI, %edx contains a function 
+! pointer that should be registered with atexit(), for proper
+! shared object termination.  Just push it onto the stack for now
+! to preserve it.  We want to register _cleanup() first.
+
+       pushl   %edx
+
+! Check to see if there is an _cleanup() function linked in, and if
+! so, register it with atexit() as the last thing to be run by
+! atexit().
+
+       movl    $_mcleanup,%eax
+       testl   %eax,%eax
+       je      .L1
+       pushl   $_mcleanup
+       call    atexit
+       addl    $0x4,%esp
+.L1:
+
+! Now check to see if we have an _DYNAMIC table, and if so then
+! we need to register the function pointer previously in %edx, but
+! now conveniently saved on the stack as the argument to pass to
+! atexit().
+
+       movl    $_DYNAMIC,%eax
+       testl   %eax,%eax
+       je      .L2
+       call    atexit
+.L2:
+
+! Register _fini() with atexit().  We will take care of calling _init()
+! directly.
+
+       pushl   $_fini
+       call    atexit
+
+! Start profiling
+
+        pushl %ebp
+        movl %esp,%ebp
+        pushl $_etext
+        pushl $_start
+        call monstartup
+        addl $8,%esp
+       popl %ebp
+
+! Compute the address of the environment vector on the stack and load
+! it into the global variable _environ.  Currently argc is at 8 off
+! the frame pointer.  Fetch the argument count into %eax, scale by the
+! size of each arg (4 bytes) and compute the address of the environment
+! vector which is 16 bytes (the two zero words we pushed, plus argc,
+! plus the null word terminating the arg vector) further up the stack,
+! off the frame pointer (whew!).
+
+       movl    8(%ebp),%eax
+       leal    16(%ebp,%eax,4),%edx
+       movl    %edx,_environ
+
+! Push the environment vector pointer, the argument vector pointer,
+! and the argument count on to the stack to set up the arguments
+! for _init(), _fpstart(), and main().  Note that the environment
+! vector pointer and the arg count were previously loaded into
+! %edx and %eax respectively.  The only new value we need to compute
+! is the argument vector pointer, which is at a fixed address off
+! the initial frame pointer.
+
+       pushl   %edx
+       leal    12(%ebp),%edx
+       pushl   %edx
+       pushl   %eax
+
+! Call _init(argc, argv, environ), _fpstart(argc, argv, environ), and
+! main(argc, argv, environ).
+
+       call    _init
+       call    __fpstart
+       call    main
+
+! Pop the argc, argv, and environ arguments off the stack, push the
+! value returned from main(), and call exit().
+
+       addl    $12,%esp
+       pushl   %eax
+       call    exit
+
+! An inline equivalent of _exit, as specified in Figure 3-26 of the ABI.
+
+       pushl   $0x0
+       movl    $0x1,%eax
+       lcall   $7,$0
+
+! If all else fails, just try a halt!
+
+       hlt
+       .type   _start,@function
+       .size   _start,.-_start