home *** CD-ROM | disk | FTP | other *** search
/ OpenStep 4.2J (Developer) / os42jdev.iso / NextDeveloper / Source / GNU / gcc / config / sparc / gmon-sol2.c < prev    next >
C/C++ Source or Header  |  1995-12-11  |  12KB  |  403 lines

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