home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / gmon.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  20.4 KB  |  870 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. /*
  39.  *    Largely hacked, ANSI-afied and re-written for use at Netscape
  40.  *    by djw@netscape.com.
  41.  *    Algorithms and code are based on BSD gmon.c, rev 5.3.
  42.  */
  43.  
  44. #include <unistd.h>
  45. #include <stdio.h>
  46. #include <stdlib.h>
  47. #include <ctype.h>
  48. #include <string.h>
  49. #include <mon.h>
  50. #include <unistd.h>
  51. #include <sys/types.h>
  52. #include <sys/stat.h>
  53. #include <fcntl.h>
  54. #include <sys/wait.h>
  55. #include <signal.h>
  56.  
  57. #if 0
  58. #include "sparc/gmon.h"
  59. #else
  60. struct phdr {
  61.   char *lpc;
  62.   char *hpc;
  63.   int ncnt;
  64. };
  65. #define HISTFRACTION 2
  66. #define HISTCOUNTER  unsigned short
  67. #define HASHFRACTION 1
  68. #define ARCDENSITY   2
  69. #define MINARCS      50
  70. struct tostruct {
  71.   char *selfpc;
  72.   long count;
  73.   unsigned short link;
  74. };
  75. struct rawarc {
  76.     unsigned long       raw_frompc;
  77.     unsigned long       raw_selfpc;
  78.     long                raw_count;
  79. };
  80. #define ROUNDDOWN(x,y)  (((x)/(y))*(y))
  81. #define ROUNDUP(x,y)    ((((x)+(y)-1)/(y))*(y))
  82.  
  83. #endif
  84.  
  85. /* extern mcount() asm ("mcount"); */
  86. /*extern*/ char *minbrk /* asm ("minbrk") */;
  87.  
  88. /*
  89.  *    froms is actually a bunch of unsigned shorts indexing tos
  90.  */
  91. static int                profiling = 3;
  92. static unsigned short*  froms;
  93. static struct tostruct* tos = 0;
  94. static long                tolimit = 0;
  95. static char*            s_lowpc = 0;
  96. static char*            s_highpc = 0;
  97. static unsigned long    s_textsize = 0;
  98.  
  99. static int                ssiz;
  100. static char*            sbuf;
  101. static int              s_scale;
  102.  
  103. /* see profil(2) where this is describe (incorrectly) */
  104. #define        SCALE_1_TO_1    0x10000L
  105.  
  106. #define    MSG "No space for profiling buffer(s)\n"
  107.  
  108. static void moncontrol();
  109.  
  110. static void
  111. monstartup(char* lowpc, char* highpc)
  112. {
  113.     int            monsize;
  114.     char        *buffer;
  115.     register int    o;
  116.  
  117.     /*
  118.      *    round lowpc and highpc to multiples of the density we're using
  119.      *    so the rest of the scaling (here and in gprof) stays in ints.
  120.      */
  121.     lowpc = (char *)
  122.         ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER));
  123.     s_lowpc = lowpc;
  124.     highpc = (char *)
  125.         ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER));
  126.     s_highpc = highpc;
  127.     s_textsize = highpc - lowpc;
  128.     monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr);
  129.     buffer = sbrk( monsize );
  130.     if ( buffer == (char *) -1 ) {
  131.         write( 2 , MSG , sizeof(MSG) );
  132.         return;
  133.     }
  134.     froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION );
  135.     if ( froms == (unsigned short *) -1 ) {
  136.         write( 2 , MSG , sizeof(MSG) );
  137.         froms = 0;
  138.         return;
  139.     }
  140.     tolimit = s_textsize * ARCDENSITY / 100;
  141.     if ( tolimit < MINARCS ) {
  142.         tolimit = MINARCS;
  143.     } else if ( tolimit > 65534 ) {
  144.         tolimit = 65534;
  145.     }
  146.     tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) );
  147.     if ( tos == (struct tostruct *) -1 ) {
  148.         write( 2 , MSG , sizeof(MSG) );
  149.         froms = 0;
  150.         tos = 0;
  151.         return;
  152.     }
  153.     minbrk = sbrk(0);
  154.     tos[0].link = 0;
  155.     sbuf = buffer;
  156.     ssiz = monsize;
  157.     ( (struct phdr *) buffer ) -> lpc = lowpc;
  158.     ( (struct phdr *) buffer ) -> hpc = highpc;
  159.     ( (struct phdr *) buffer ) -> ncnt = ssiz;
  160.     monsize -= sizeof(struct phdr);
  161.     if ( monsize <= 0 )
  162.         return;
  163.     o = highpc - lowpc;
  164.     if( monsize < o )
  165. #ifndef hp300
  166.         s_scale = ( (float) monsize / o ) * SCALE_1_TO_1;
  167. #else /* avoid floating point */
  168.     {
  169.         int quot = o / monsize;
  170.         
  171.         if (quot >= 0x10000)
  172.             s_scale = 1;
  173.         else if (quot >= 0x100)
  174.             s_scale = 0x10000 / quot;
  175.         else if (o >= 0x800000)
  176.             s_scale = 0x1000000 / (o / (monsize >> 8));
  177.         else
  178.             s_scale = 0x1000000 / ((o << 8) / monsize);
  179.     }
  180. #endif
  181.     else
  182.         s_scale = SCALE_1_TO_1;
  183. #if 0
  184.     moncontrol(1);
  185. #endif
  186. }
  187.  
  188. static void
  189. _mcleanup(char* filename)
  190. {
  191.     int            fd;
  192.     int            fromindex;
  193.     int            endfrom;
  194.     char        *frompc;
  195.     int            toindex;
  196.     struct rawarc    rawarc;
  197.  
  198.     moncontrol(0);
  199.     fd = creat( filename , 0666 );
  200.     if ( fd < 0 ) {
  201.         perror( "mcount: gmon.out" );
  202.         return;
  203.     }
  204. #   ifdef DEBUG
  205.     fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
  206. #   endif DEBUG
  207.     write( fd , sbuf , ssiz );
  208.     endfrom = s_textsize / (HASHFRACTION * sizeof(*froms));
  209.     for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) {
  210.         if ( froms[fromindex] == 0 ) {
  211.             continue;
  212.         }
  213.         frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms));
  214.         for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
  215. #        ifdef DEBUG
  216.             fprintf( stderr ,
  217.                      "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
  218.                      frompc , tos[toindex].selfpc , tos[toindex].count );
  219. #        endif DEBUG
  220.             rawarc.raw_frompc = (unsigned long) frompc;
  221.             rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc;
  222.             rawarc.raw_count = tos[toindex].count;
  223.             write( fd , &rawarc , sizeof rawarc );
  224.         }
  225.     }
  226.     close( fd );
  227. }
  228.  
  229. /*
  230.  * The Sparc stack frame is only held together by the frame pointers
  231.  * in the register windows. According to the SVR4 SPARC ABI
  232.  * Supplement, Low Level System Information/Operating System
  233.  * Interface/Software Trap Types, a type 3 trap will flush all of the
  234.  * register windows to the stack, which will make it possible to walk
  235.  * the frames and find the return addresses.
  236.  *     However, it seems awfully expensive to incur a trap (system
  237.  * call) for every function call. It turns out that "call" simply puts
  238.  * the return address in %o7 expecting the "save" in the procedure to
  239.  * shift it into %i7; this means that before the "save" occurs, %o7
  240.  * contains the address of the call to mcount, and %i7 still contains
  241.  * the caller above that. The asm mcount here simply saves those
  242.  * registers in argument registers and branches to internal_mcount,
  243.  * simulating a call with arguments.
  244.  *     Kludges:
  245.  *     1) the branch to internal_mcount is hard coded; it should be
  246.  * possible to tell asm to use the assembler-name of a symbol.
  247.  *     2) in theory, the function calling mcount could have saved %i7
  248.  * somewhere and reused the register; in practice, I *think* this will
  249.  * break longjmp (and maybe the debugger) but I'm not certain. (I take
  250.  * some comfort in the knowledge that it will break the native mcount
  251.  * as well.)
  252.  *     3) if builtin_return_address worked, this could be portable.
  253.  * However, it would really have to be optimized for arguments of 0
  254.  * and 1 and do something like what we have here in order to avoid the
  255.  * trap per function call performance hit. 
  256.  *     4) the atexit and monsetup calls prevent this from simply
  257.  * being a leaf routine that doesn't do a "save" (and would thus have
  258.  * access to %o7 and %i7 directly) but the call to write() at the end
  259.  * would have also prevented this.
  260.  *
  261.  * -- [eichin:19920702.1107EST]
  262.  */
  263.  
  264. /* i7 == last ret, -> frompcindex */
  265. /* o7 == current ret, -> selfpc */
  266. asm(".global mcount; mcount: mov %i7,%o1; mov %o7,%o0;b,a internal_mcount");
  267.  
  268. static void
  269. internal_mcount(register char* selfpc, register unsigned short* frompcindex)
  270. {
  271.     register struct tostruct    *top;
  272.     register struct tostruct    *prevtop;
  273.     register long            toindex;
  274.     /*
  275.      *    check that we are profiling
  276.      *    and that we aren't recursively invoked.
  277.      */
  278.     if (profiling) {
  279.         goto out;
  280.     }
  281.     profiling++;
  282.     /*
  283.      *    check that frompcindex is a reasonable pc value.
  284.      *    for example:    signal catchers get called from the stack,
  285.      *            not from text space.  too bad.
  286.      */
  287.     frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc);
  288.     if ((unsigned long)frompcindex > s_textsize) {
  289.         goto done;
  290.     }
  291.     frompcindex =
  292.         &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))];
  293.     toindex = *frompcindex;
  294.     if (toindex == 0) {
  295.         /*
  296.          *    first time traversing this arc
  297.          */
  298.         toindex = ++tos[0].link;
  299.         if (toindex >= tolimit) {
  300.             goto overflow;
  301.         }
  302.         *frompcindex = toindex;
  303.         top = &tos[toindex];
  304.         top->selfpc = selfpc;
  305.         top->count = 1;
  306.         top->link = 0;
  307.         goto done;
  308.     }
  309.     top = &tos[toindex];
  310.     if (top->selfpc == selfpc) {
  311.         /*
  312.          *    arc at front of chain; usual case.
  313.          */
  314.         top->count++;
  315.         goto done;
  316.     }
  317.     /*
  318.      *    have to go looking down chain for it.
  319.      *    top points to what we are looking at,
  320.      *    prevtop points to previous top.
  321.      *    we know it is not at the head of the chain.
  322.      */
  323.     for (; /* goto done */; ) {
  324.         if (top->link == 0) {
  325.             /*
  326.              *    top is end of the chain and none of the chain
  327.              *    had top->selfpc == selfpc.
  328.              *    so we allocate a new tostruct
  329.              *    and link it to the head of the chain.
  330.              */
  331.             toindex = ++tos[0].link;
  332.             if (toindex >= tolimit) {
  333.                 goto overflow;
  334.             }
  335.             top = &tos[toindex];
  336.             top->selfpc = selfpc;
  337.             top->count = 1;
  338.             top->link = *frompcindex;
  339.             *frompcindex = toindex;
  340.             goto done;
  341.         }
  342.         /*
  343.          *    otherwise, check the next arc on the chain.
  344.          */
  345.         prevtop = top;
  346.         top = &tos[top->link];
  347.         if (top->selfpc == selfpc) {
  348.             /*
  349.              *    there it is.
  350.              *    increment its count
  351.              *    move it to the head of the chain.
  352.              */
  353.             top->count++;
  354.             toindex = prevtop->link;
  355.             prevtop->link = top->link;
  356.             top->link = *frompcindex;
  357.             *frompcindex = toindex;
  358.             goto done;
  359.         }
  360.  
  361.     }
  362. done:
  363.     profiling--;
  364.     /* and fall through */
  365. out:
  366.     return;        /* normal return restores saved registers */
  367.  
  368. overflow:
  369.     profiling++; /* halt further profiling */
  370. #   define    TOLIMIT    "mcount: tos overflow\n"
  371.     write(2, TOLIMIT, sizeof(TOLIMIT));
  372.     goto out;
  373. }
  374.  
  375. /*
  376.  * Control profiling
  377.  *    profiling is what mcount checks to see if
  378.  *    all the data structures are ready.
  379.  */
  380. static void
  381. moncontrol(int mode)
  382. {
  383.     if (mode) {
  384.         /* start */
  385.         profil((unsigned short *)(sbuf + sizeof(struct phdr)),
  386.                ssiz - sizeof(struct phdr),
  387.                (int)s_lowpc, s_scale);
  388.         profiling = 0;
  389.     } else {
  390.         /* stop */
  391.         profil((unsigned short *)0, 0, 0, 0);
  392.         profiling = 3;
  393.     }
  394. }
  395.  
  396. /*
  397.  *    Mozilla-isms:
  398.  */
  399.  
  400. /*
  401.  *    Deal with nspr system traps.
  402.  */
  403. extern int _pr_intsOff; /* in nspr */
  404.  
  405. #define CONTROL_VARIABLE "MOZILLA_GPROF"
  406. #define DEFAULT_NCALLS   10000
  407. #define DEFAULT_RUNNING  (1)
  408. #define DEFAULT_DATAFILE "gmon.out"
  409. #define BARSIZE          8 /* same as ld.so does */
  410.  
  411. typedef int (*funcptr_t)();
  412.  
  413. extern _etext;
  414.  
  415. #define PROG_LOW  ((funcptr_t)0)
  416. #define PROG_HIGH ((funcptr_t)&_etext)
  417.  
  418. static unsigned gmon_running;
  419. #if 0
  420. static WORD*    gmon_buf;
  421. static size_t   gmon_nelems;
  422. #endif
  423. static size_t   gmon_ncalls;
  424. static char*    gmon_filename;
  425.  
  426. static void
  427. gmon_parse_env(char* s, size_t* ncalls_r, unsigned* running_r, char** file)
  428. {
  429.     char* p = (char*)&internal_mcount; /* just so it gets used somewhere */
  430.     char* name;
  431.     char* value;
  432.     char  buf[1024]; /* big enough to hold a long filename */
  433.  
  434.     if (s == NULL)
  435.         return; /* no change */
  436.  
  437.     strcpy(buf, s);
  438.  
  439.     for (p = buf; *p != '\0';) {
  440.         while (*p != '\0' && isspace(*p)) /* skip white */
  441.             ;
  442.         if (*p == '\0')
  443.             break;
  444.  
  445.         name = p;
  446.  
  447.         if ((p = strchr(name, '=')) == NULL)
  448.             break;
  449.         *p++ = '\0';
  450.  
  451.         value = p;
  452.  
  453.         if ((p = strchr(name, ';')) != NULL) {
  454.             *p++ = '\0';
  455.         } else {
  456.             for (p = name; *p != '\0'; p++)
  457.                 ;
  458.         }
  459.  
  460.         if (strncmp(name, "NCALLS", 6) == 0) {
  461.             unsigned foo = atoi(value);
  462.             *ncalls_r = foo;
  463.         } else if (strncmp(name, "RUNNING", 7) == 0) {
  464.             if (strcmp(name, "true") == 0)
  465.                 *running_r = 1;
  466.             else
  467.                 *running_r = 0;
  468.         } else if (strncmp(name, "FILE", 4) == 0) {
  469.             *file = strdup(value);
  470.         }
  471.     }
  472. }
  473.  
  474. static void
  475. gmon_change_state(unsigned running)
  476. {
  477.     int s;
  478.     /*
  479.      *    At the moment, dump_to() doesn't work. Just always dump to
  480.      *    gmon.out.
  481.      */
  482.     s = _pr_intsOff; /* stop annoying assert from nspr */
  483.     _pr_intsOff = 0;
  484.  
  485.     moncontrol(running);
  486.  
  487.     _pr_intsOff = s;
  488.  
  489.     gmon_running = running;
  490. }
  491.  
  492. void gmon_dump();
  493.  
  494. static void
  495. gmon_onexit_cb()
  496. {
  497.     if (gmon_running)
  498.         gmon_dump();
  499. }
  500.  
  501.  
  502. void
  503. gmon_init()
  504. {
  505.     char*     p = getenv(CONTROL_VARIABLE);
  506.  
  507.     gmon_ncalls = DEFAULT_NCALLS;
  508.     gmon_filename = DEFAULT_DATAFILE;
  509.     gmon_running = DEFAULT_RUNNING;
  510.  
  511.     if (p != NULL)
  512.         gmon_parse_env(p, &gmon_ncalls, &gmon_running, &gmon_filename);
  513.  
  514. #if 0
  515.     size_t    bufsize;
  516.     bufsize =
  517.         sizeof(struct hdr) + 
  518.         (gmon_ncalls * sizeof(struct cnt)) +
  519.         (((PROG_HIGH - PROG_LOW)/BARSIZE) * sizeof(WORD)) +
  520.         sizeof(WORD) - 1;
  521.     
  522.     gmon_nelems = (bufsize / sizeof(WORD));
  523.  
  524.     gmon_buf = (WORD*)malloc(bufsize);
  525.  
  526.     if (!gmon_buf) {
  527.         fprintf(stderr,
  528.                 "gmon_init() failed to allocate data buffers.\n"
  529.                 "Sorry, I just cannot continue like this. How about\n"
  530.                 "checking " CONTROL_VARIABLE ", currently set to:\n"
  531.                 CONTROL_VARIABLE "=" "%s\n", (p != NULL)? p: "unset");
  532.         exit(3);
  533.     }
  534. #endif
  535.  
  536.     atexit(gmon_onexit_cb);
  537.  
  538.     monstartup((char*)PROG_LOW, (char*)PROG_HIGH);
  539.  
  540.     gmon_change_state(gmon_running);
  541. }
  542.  
  543. void
  544. gmon_start()
  545. {
  546.     gmon_change_state(1);
  547. }
  548.  
  549. void
  550. gmon_stop()
  551. {
  552.     gmon_change_state(0);
  553. }
  554.  
  555. void
  556. gmon_dump_to(char* name)
  557. {
  558.     int s;
  559.     /*
  560.      *    At the moment, dump_to() doesn't work. Just always dump to
  561.      *    gmon.out.
  562.      */
  563.     s = _pr_intsOff; /* stop annoying assert from nspr */
  564.     _pr_intsOff = 0;
  565.  
  566.     _mcleanup(name);
  567.  
  568.     _pr_intsOff = s;
  569. }
  570.  
  571. void
  572. gmon_dump()
  573. {
  574.     gmon_dump_to(gmon_filename);
  575. }
  576.  
  577. static int
  578. gprof_out_filter_section_1(FILE* ifp, FILE* ofp)
  579. {
  580.     char buf[512];
  581.     char* p;
  582.     char* q;
  583.     char* rest;
  584.     unsigned link;
  585.     unsigned target;
  586.  
  587.     while (fgets(buf, sizeof(buf), ifp) != NULL) {
  588.  
  589.         if (buf[0] == '\f')
  590.             break; /* done for this section */
  591.  
  592.         if ((p = strchr(buf, '[')) == NULL) { /* heading or data line */
  593.             fputs(buf, ofp); /* white space, etc */
  594.             continue;
  595.         }
  596.  
  597.         target = 0;
  598.         rest = buf;
  599.         if (p == buf && (q = strchr(p+1, '[')) != NULL) { /* heading line */
  600.             target = strtol(p+1, &rest, 10);
  601.             if (*rest == ']')
  602.                 rest++;
  603.             p = q;
  604.         }
  605.  
  606.         link = atoi(p+1);
  607.         *p = '\0';
  608.         
  609.         if (rest != buf) {
  610.             fprintf(ofp,
  611.                     "<A NAME=s1i%d>[%d]</A>%s<A HREF=#s2i%d>[%d]</A>\n",
  612.                     target, target, rest, link, link);
  613.         } else {
  614.             fprintf(ofp,
  615.                     "%s<A HREF=#s2i%d>[%d]</A>\n",
  616.                     rest, link, link);
  617.         }
  618.     }
  619.     return 0; /* ok */
  620. }
  621.  
  622. static int
  623. gprof_out_filter_section_2(FILE* ifp, FILE* ofp)
  624. {
  625.     char buf[512];
  626.     char* p;
  627.     unsigned link;
  628.  
  629.     while (fgets(buf, sizeof(buf), ifp) != NULL) {
  630.     
  631.  
  632.         if (buf[0] == '\f')
  633.             break; /* done for this section */
  634.  
  635.         if ((p = strchr(buf, '[')) == NULL) { /* data line */
  636.             fputs(buf, ofp); /* white space, etc */
  637.             continue;
  638.         }
  639.  
  640.         link = atoi(p+1);
  641.         *p = '\0';
  642.         
  643.         fprintf(ofp,
  644.                 "<A NAME=s2i%d></A>%s<A HREF=#s1i%d>[%d]</A>\n",
  645.                 link, buf, link, link);
  646.     }
  647.     return 0; /* ok */
  648. }
  649.  
  650. int
  651. gprof_out_filter(FILE* ifp, FILE* ofp, unsigned do_reverse)
  652. {
  653.     /* only needed if we want to reverse the output order */
  654.     FILE* tfp;
  655.  
  656.     if (do_reverse) {
  657.         if ((tfp = tmpfile()) == NULL) {
  658.             fprintf(stderr, "gprof filter: could not create tmp file\n");
  659.             return -1;
  660.         }
  661.     } else {
  662.         tfp = ofp;
  663.     }
  664.  
  665.     fprintf(ofp, "<HTML>\n<BODY>\n<PRE>\n");
  666.  
  667.     if (gprof_out_filter_section_1(ifp, tfp) == -1)
  668.         return -1;
  669.     
  670.     if (gprof_out_filter_section_2(ifp, ofp) == -1)
  671.         return -1;
  672.  
  673.     if (tfp != ofp) {
  674.         int c;
  675.  
  676.         rewind(tfp);
  677.  
  678.         while ((c = getc(tfp)) != -1)
  679.             putc(c, ofp);
  680.  
  681.         fclose(tfp);
  682.     }
  683.  
  684.     fprintf(ofp, "</PRE>\n</BODY>\n</HTML>\n");
  685.  
  686.     return 0;
  687. }
  688.  
  689. extern const char *fe_progname_long; /* defined in xfe.h */
  690.  
  691. int
  692. gmon_gprof_to(char* gmon_out, char* gprof_out, unsigned nfuncs)
  693. {
  694.     char* argv[16];
  695.     int   argc = 0;
  696.     int   child_pid;
  697.     int status;
  698.     char buf[16];
  699.     FILE* fp = NULL;
  700.     int rv = 0;
  701.     int s;
  702.     struct sigaction newact;
  703.     struct sigaction oldact;
  704.  
  705.     s = _pr_intsOff; /* stop annoying assert from nspr */
  706.     _pr_intsOff = 0;
  707.  
  708.     if ((fp = fopen(gprof_out, "w+")) == NULL) {
  709.         fprintf(stderr, "gmon_gprof_to(): could not create %s: ", gprof_out);
  710.         perror(NULL);
  711.         rv = -1;
  712.         goto return_point;
  713.     }
  714.  
  715.     /*
  716.      *    gprof -b [-n topn] progname gmon_filename > tmpfile
  717.      */
  718.     argv[argc++] = "gprof";
  719.     argv[argc++] = "-b";
  720.     argv[argc++] = "-E";
  721.     argv[argc++] = "mcount";
  722.     argv[argc++] = "-E";
  723.     argv[argc++] = "internal_mcount";
  724.     if (nfuncs != 0) {
  725.         sprintf(buf, "%d", nfuncs);
  726.         argv[argc++] = "-n";
  727.         argv[argc++] = buf;
  728.     }
  729.     argv[argc++] = (char*)fe_progname_long;
  730.     argv[argc++] = gmon_out;
  731.     argv[argc] = NULL;
  732.  
  733.     /* Setup signals so that SIGCHLD is ignored as we want to do waitpid */
  734.     newact.sa_handler = SIG_DFL;
  735.     newact.sa_flags = 0;
  736.     sigfillset(&newact.sa_mask);
  737.     sigaction(SIGCHLD, &newact, &oldact);
  738.  
  739.     if ((child_pid = fork()) == -1) {
  740.         fprintf(stderr, "gmon_dump_html_to(): could not fork()\n");
  741.         rv = -1;
  742.         goto return_point;
  743.     }
  744.  
  745.     if (child_pid == 0) { /* I am the child */
  746.  
  747.         int fd = fileno(fp);
  748.  
  749.         /*
  750.          *    Redirect standard out.
  751.          */
  752.         close(1);
  753.         dup(fd);
  754.         close(fd);
  755.  
  756.         /*
  757.          *    Close all but standard in, out, error.
  758.          */
  759.         for (fd--; fd > 2; fd--)
  760.             close(fd);
  761.  
  762.         printf("doing exec now dude!\n");
  763.  
  764.         if (execvp(argv[0], argv) == -1) {
  765.             fprintf(stderr, "could not exec %s: ", argv[0]);
  766.             perror(NULL);
  767.             exit(3);
  768.         }
  769.         /*NOTREACHED*/
  770.     }
  771.  
  772.     /*
  773.      *    wait
  774.      */
  775.     if (waitpid(child_pid, &status, 0) == -1) {
  776.         fprintf(stderr, "wait on %s failed: ", argv[0]);
  777.         perror(NULL);
  778.         rv = -1;
  779.     }
  780.  
  781. return_point:
  782.  
  783.     /* Reset SIGCHLD signal hander before returning */
  784.     sigaction(SIGCHLD, &oldact, NULL);
  785.  
  786.     if (fp != NULL)
  787.         fclose(fp);
  788.  
  789.     _pr_intsOff = s;
  790.  
  791.     return rv;
  792. }
  793.  
  794. static unsigned gmon_report_reverse = 1; /* flat then graph */
  795. static unsigned gmon_report_size = 0;
  796.  
  797. unsigned
  798. gmon_is_running()
  799. {
  800.     return (gmon_running != 0); /* maybe should check profiling */
  801. }
  802.  
  803. unsigned
  804. gmon_report_get_reverse()
  805. {
  806.     return gmon_report_reverse;
  807. }
  808.  
  809. void
  810. gmon_report_set_reverse(unsigned yep)
  811. {
  812.     gmon_report_reverse = yep;
  813. }
  814.  
  815. unsigned
  816. gmon_report_get_size()
  817. {
  818.     return gmon_report_size;
  819. }
  820.  
  821. void
  822. gmon_report_set_size(unsigned yep)
  823. {
  824.     gmon_report_size = yep;
  825. }
  826.  
  827. void
  828. gmon_reset()
  829. {
  830.     gmon_change_state(0); /* maybe we don't need to do this, but ahhh */
  831.  
  832.     memset(sbuf, 0, ssiz);
  833.     memset(froms, 0, (s_textsize / HASHFRACTION));
  834.     memset(tos, 0, (tolimit * sizeof(struct tostruct)));
  835.  
  836.     ((struct phdr *)sbuf)->lpc = s_lowpc;
  837.     ((struct phdr *)sbuf)->hpc = s_highpc;
  838.     ((struct phdr *)sbuf)->ncnt = ssiz;
  839. }
  840.  
  841. int
  842. gmon_html_filter_to(char* gprofout, char* html, unsigned reverse)
  843. {
  844.     FILE* ifp;
  845.     FILE* ofp;
  846.     int rv = 0;
  847.  
  848.     if ((ifp = fopen(gprofout, "r")) == NULL) {
  849.         fprintf(stderr, "gmon_html_filter_to(): could not open %s", gprofout);
  850.         perror(NULL);
  851.         return -1;
  852.     }
  853.  
  854.     if ((ofp = fopen(html, "w")) == NULL) {
  855.         fprintf(stderr, "gmon_html_filter_to(): could not create %s", html);
  856.         perror(NULL);
  857.         fclose(ifp);
  858.         return -1;
  859.     }
  860.  
  861.     if (gprof_out_filter(ifp, ofp, reverse) == -1)
  862.         rv = -1;
  863.     
  864.     fclose(ifp);
  865.     fclose(ofp);
  866.  
  867.     return rv;
  868. }
  869.  
  870.