old versions; put these to bed
[unix-history] / usr / src / lib / libc / gmon / gmon.c
index a6a3122..1c9f0d6 100644 (file)
-static char *sccsid = "@(#)gmon.c      1.2 (Berkeley) %G%";
+static char *sccsid = "@(#)gmon.c      4.4 (Berkeley) %G%";
 
 
+#ifdef DEBUG
 #include <stdio.h>
 #include <stdio.h>
+#endif DEBUG
 
 
-#include "monitor.h"
+#include "gcrt0.h"
 
 
-    /* froms is actually a bunch of unsigned shorts indexing tos */
+    /*
+     * C start up routines, for monitoring
+     * Robert Henry, UCB, 20 Oct 81
+     *
+     * We make the following (true) assumptions:
+     * 1) when the kernel calls start, it does a jump to location 2,
+     * and thus avoids the register save mask.  We are NOT called
+     * with a calls!  see sys1.c:setregs().
+     * 2) The only register variable that we can trust is sp,
+     * which points to the base of the kernel calling frame.
+     * Do NOT believe the documentation in exec(2) regarding the
+     * values of fp and ap.
+     * 3) We can allocate as many register variables as we want,
+     * and don't have to save them for anybody.
+     * 4) Because of the ways that asm's work, we can't have
+     * any automatic variables allocated on the stack, because
+     * we must catch the value of sp before any automatics are
+     * allocated.
+     */
+
+char **environ;
+    /*
+     * etext is added by the loader, and is the end of the text space.
+     * eprol is a local symbol, and labels almost the beginning of text space.
+     *     its name is changed so it doesn't look like a function.
+     */
+extern unsigned char   etext;
+extern unsigned char   eprol;
+asm( "#define _eprol _$eprol" );
+
+asm( "#define _start start" );
+start()
+{
+    struct kframe {
+       int     kargc;
+       char    *kargv[1];              /* size depends on kargc */
+       char    kargstr[1];             /* size varies */
+       char    kenvstr[1];             /* size varies */
+    };
+       /*
+        *      ALL REGISTER VARIABLES!!!
+        */
+    register int               r11;            /* init needs r11 */
+    register struct kframe     *kfp;           /* r10 */
+    register char              **targv;
+    register char              **argv;
+
+#ifdef lint
+    kfp = 0;
+#else not lint
+    asm( "     movl    sp,r10" );              /* catch it quick */
+#endif not lint
+    for ( argv = targv = &kfp -> kargv[0] ; *targv++ ; /* void */ )
+       /* VOID */ ;
+    if ( targv >= (char **) ( *argv ) )
+       --targv;
+    environ = targv;
+asm("_eprol:");
+    _mstartup( &eprol , &etext );
+    exit( main( kfp -> kargc , argv , environ ) );
+}
+asm( "#undef _start" );
+asm( "#undef _eprol" );
+
+exit( code )
+       /* ARGSUSED */
+    register int       code;   /* r11 */
+{
+
+    _mcleanup();
+    _cleanup();
+    asm( "     movl r11, r0" );
+    asm( "     chmk $1" );
+}
+
+    /*
+     * froms is actually a bunch of unsigned shorts indexing tos
+     */
 static unsigned short  *froms;
 static struct tostruct *tos = 0;
 static unsigned short  tolimit = 0;
 static char            *s_lowpc = 0;
 static char            *s_highpc = 0;
 static unsigned short  *froms;
 static struct tostruct *tos = 0;
 static unsigned short  tolimit = 0;
 static char            *s_lowpc = 0;
 static char            *s_highpc = 0;
+static unsigned long   s_textsize = 0;
+static char            *minsbrk = 0;
 
 
-static int     ssiz;
-static int     *sbuf;
+static int     ssiz;
+static int     *sbuf;
 
 
-char   *sbrk();
 #define        MSG "No space for monitor buffer(s)\n"
 
 #define        MSG "No space for monitor buffer(s)\n"
 
-       /*ARGSUSED*/
-exit(code)
-       register int    code;
-{
-       fflush(stdout);
-       _mcleanup();
-       _cleanup();
-#ifdef lint
-       code = code;
-#endif lint
-       asm("   movl r11, r0");
-       asm("   chmk $1");
-}
-
 _mstartup(lowpc, highpc)
 _mstartup(lowpc, highpc)
-       char    *lowpc;
-       char    *highpc;
+    char       *lowpc;
+    char       *highpc;
 {
 {
-       int     monsize;
-       char    *buffer;
-       int     textsize;
-
-       s_lowpc = lowpc;
-       s_highpc = highpc;
-       textsize = ((char *)highpc - (char *)lowpc);
-       monsize = textsize + sizeof(struct phdr);
-       buffer = sbrk(monsize);
-       if ( buffer == (char *) -1 ) {
-           write(2, MSG, sizeof(MSG));
-           return;
-       }
-       froms = (unsigned short *) sbrk(textsize);
-       if ( froms == (unsigned short *) -1 ) {
-           write(2 , MSG , sizeof(MSG) );
-           froms = 0;
-           return;
-       }
-       tos = (struct tostruct *) sbrk(textsize);
-       if ( tos == (struct tostruct *) -1 ) {
-           write(2 , MSG , sizeof(MSG) );
-           froms = 0;
-           tos = 0;
-           return;
-       }
-       tolimit = textsize / sizeof(struct tostruct);
-       tos[0].link = 0;
-       monitor(lowpc, highpc, buffer, monsize);
-}
+    int                        monsize;
+    char               *buffer;
+    char               *sbrk();
+    unsigned long      limit;
 
 
-_peek()
-{
+    s_lowpc = lowpc;
+    s_highpc = highpc;
+    s_textsize = highpc - lowpc;
+    monsize = s_textsize + sizeof(struct phdr);
+    buffer = sbrk( monsize );
+    if ( buffer == (char *) -1 ) {
+       write( 2 , MSG , sizeof(MSG) );
+       return;
+    }
+    froms = (unsigned short *) sbrk( s_textsize );
+    if ( froms == (unsigned short *) -1 ) {
+       write( 2 , MSG , sizeof(MSG) );
+       froms = 0;
+       return;
+    }
+    tos = (struct tostruct *) sbrk(s_textsize);
+    if ( tos == (struct tostruct *) -1 ) {
+       write( 2 , MSG , sizeof(MSG) );
+       froms = 0;
+       tos = 0;
+       return;
+    }
+    tos[0].link = 0;
+    limit = s_textsize / sizeof(struct tostruct);
+       /*
+        *      tolimit is what mcount checks to see if
+        *      all the data structures are ready!!!
+        *      make sure it won't overflow.
+        */
+    tolimit = limit > 65534 ? 65534 : limit;
+    monitor( lowpc , highpc , buffer , monsize );
 }
 
 _mcleanup()
 {
 }
 
 _mcleanup()
 {
-    FILE       *fd;
-    int                fromindex;
-    char       *frompc;
-    int                toindex;
-    int                textsize;
-
-    monitor((int (*)())0);
-    fd = fopen( "dmon.out" , "w" );
-    if ( fd == NULL ) {
-       perror( "mcount: dmon.out" );
+    int                        fd;
+    int                        fromindex;
+    char               *frompc;
+    int                        toindex;
+    struct rawarc      rawarc;
+
+    monitor( (int (*)()) 0 );
+    fd = creat( "gmon.out" , 0666 );
+    if ( fd < 0 ) {
+       perror( "mcount: gmon.out" );
        return;
     }
        return;
     }
-    fwrite( sbuf , ssiz , 1 , fd );
-    textsize = s_highpc - s_lowpc;
-    for ( fromindex = 0 ; fromindex < textsize>>1 ; fromindex++ ) {
+#   ifdef DEBUG
+       fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
+#   endif DEBUG
+    write( fd , sbuf , ssiz );
+    for ( fromindex = 0 ; fromindex < s_textsize>>1 ; fromindex++ ) {
        if ( froms[fromindex] == 0 ) {
            continue;
        }
        frompc = s_lowpc + (fromindex<<1);
        for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
 #          ifdef DEBUG
        if ( froms[fromindex] == 0 ) {
            continue;
        }
        frompc = s_lowpc + (fromindex<<1);
        for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
 #          ifdef DEBUG
-               printf( "[mcleanup] frompc %d selfpc %d count %d\n" ,
+               fprintf( stderr ,
+                       "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
                        frompc , tos[toindex].selfpc , tos[toindex].count );
 #          endif DEBUG
                        frompc , tos[toindex].selfpc , tos[toindex].count );
 #          endif DEBUG
-           fwrite( &frompc, 1, sizeof frompc, fd );
-           fwrite( &tos[toindex].selfpc, 1, sizeof tos[toindex].selfpc, fd );
-           fwrite( &tos[toindex].count, 1, sizeof tos[toindex].count, fd );
+           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 );
        }
     }
        }
     }
-    fclose( fd );
+    close( fd );
 }
 
 }
 
-/*
*     This routine is massaged so that it may be jsb'ed to
- */
+    /*
    * This routine is massaged so that it may be jsb'ed to
    */
 asm("#define _mcount mcount");
 mcount()
 {
 asm("#define _mcount mcount");
 mcount()
 {
@@ -115,7 +188,7 @@ mcount()
     register struct tostruct   *top;           /* r9 */
     static int                 profiling = 0;
 
     register struct tostruct   *top;           /* r9 */
     static int                 profiling = 0;
 
-    asm( "     forgot to run ex script on monitor.s" );
+    asm( "     forgot to run ex script on gcrt0.s" );
     asm( "#define r11 r5" );
     asm( "#define r10 r4" );
     asm( "#define r9 r3" );
     asm( "#define r11 r5" );
     asm( "#define r10 r4" );
     asm( "#define r9 r3" );
@@ -132,8 +205,12 @@ mcount()
 #endif not lint
        /*
         *      check that we are profiling
 #endif not lint
        /*
         *      check that we are profiling
+        *      and that we aren't recursively invoked.
         */
         */
-    if ( profiling || tos == 0 ) {
+    if ( tolimit == 0 ) {
+       goto out;
+    }
+    if ( profiling ) {
        goto out;
     }
     profiling = 1;
        goto out;
     }
     profiling = 1;
@@ -142,10 +219,11 @@ mcount()
         *      for example:    signal catchers get called from the stack,
         *                      not from text space.  too bad.
         */
         *      for example:    signal catchers get called from the stack,
         *                      not from text space.  too bad.
         */
-    if ( (char *) frompcindex < s_lowpc || (char *) frompcindex > s_highpc ) {
+    frompcindex = (unsigned short *) ( (long) frompcindex - (long) s_lowpc );
+    if ( (unsigned long) frompcindex > s_textsize ) {
        goto done;
     }
        goto done;
     }
-    frompcindex = &froms[ ( (long) frompcindex - (long) s_lowpc ) >> 1 ];
+    frompcindex = &froms[ ( (long) frompcindex ) >> 1 ];
     if ( *frompcindex == 0 ) {
        *frompcindex = ++tos[0].link;
        if ( *frompcindex >= tolimit ) {
     if ( *frompcindex == 0 ) {
        *frompcindex = ++tos[0].link;
        if ( *frompcindex >= tolimit ) {
@@ -185,40 +263,58 @@ out:
     asm( "#undef _mcount");
 
 overflow:
     asm( "#undef _mcount");
 
 overflow:
+    tolimit = 0;
 #   define     TOLIMIT "mcount: tos overflow\n"
     write( 2 , TOLIMIT , sizeof( TOLIMIT ) );
 #   define     TOLIMIT "mcount: tos overflow\n"
     write( 2 , TOLIMIT , sizeof( TOLIMIT ) );
-    tos = 0;
-    froms = 0;
     goto out;
 }
 
     goto out;
 }
 
-monitor(lowpc, highpc, buf, bufsiz)
-       char    *lowpc;
-       /*VARARGS1*/
-       char    *highpc;
-       int *buf, bufsiz;
+monitor( lowpc , highpc , buf , bufsiz )
+    char       *lowpc;
+    /* VARARGS1 */
+    char       *highpc;
+    int                *buf, bufsiz;
 {
 {
-       register o;
+    register o;
 
 
-       if (lowpc == 0) {
-               profil((char *)0, 0, 0, 0);
-               return;
-       }
-       sbuf = buf;
-       ssiz = bufsiz;
-       ((struct phdr *)buf)->lpc = lowpc;
-       ((struct phdr *)buf)->hpc = highpc;
-       ((struct phdr *)buf)->ncnt = ssiz;
-       o = sizeof(struct phdr);
-       buf = (int *) (((int)buf) + o);
-       bufsiz -= o;
-       if (bufsiz<=0)
-               return;
-       o = (((char *)highpc - (char *)lowpc)>>1);
-       if(bufsiz < o)
-               o = ((float) bufsiz / o) * 32768;
-       else
-               o = 0177777;
-       profil(buf, bufsiz, lowpc, o);
+    if ( lowpc == 0 ) {
+       profil( (char *) 0 , 0 , 0 , 0 );
+       return;
+    }
+    sbuf = buf;
+    ssiz = bufsiz;
+    ( (struct phdr *) buf ) -> lpc = lowpc;
+    ( (struct phdr *) buf ) -> hpc = highpc;
+    ( (struct phdr *) buf ) -> ncnt = ssiz;
+    o = sizeof(struct phdr);
+    buf = (int *) ( ( (int) buf ) + o );
+    bufsiz -= o;
+    if ( bufsiz <= 0 )
+       return;
+    o = ( ( (char *) highpc - (char *) lowpc) );
+    if( bufsiz < o )
+       o = ( (float) bufsiz / o ) * 65536;
+    else
+       o = 65536;
+    profil( buf , bufsiz , lowpc , o );
 }
 
 }
 
+/*
+ * This is a stub for the "brk" system call, which we want to
+ * catch so that it will not deallocate our data space.
+ * (of which the program is not aware)
+ */
+asm("#define _curbrk curbrk");
+extern char *curbrk;
+
+brk(addr)
+       char *addr;
+{
+
+       if (addr < minsbrk)
+               addr = minsbrk;
+       asm("   chmk    $17");
+       asm("   jcs     cerror");
+       curbrk = addr;
+       return (0);
+}