1*9530Smckusick static char *sccsid = "@(#)gmon.c 4.6 (Berkeley) 12/04/82"; 24514Speter 34869Smckusic #ifdef DEBUG 44514Speter #include <stdio.h> 54869Smckusic #endif DEBUG 64514Speter 79433Smckusick #include "gmon.h" 84514Speter 94564Speter /* 104564Speter * froms is actually a bunch of unsigned shorts indexing tos 114564Speter */ 124514Speter static unsigned short *froms; 134514Speter static struct tostruct *tos = 0; 144514Speter static unsigned short tolimit = 0; 154514Speter static char *s_lowpc = 0; 164514Speter static char *s_highpc = 0; 174850Speter static unsigned long s_textsize = 0; 186253Smckusick static char *minsbrk = 0; 194514Speter 204564Speter static int ssiz; 214564Speter static int *sbuf; 224514Speter 234514Speter #define MSG "No space for monitor buffer(s)\n" 244514Speter 259433Smckusick monstartup(lowpc, highpc) 264564Speter char *lowpc; 274564Speter char *highpc; 284514Speter { 294850Speter int monsize; 304850Speter char *buffer; 314850Speter char *sbrk(); 324850Speter unsigned long limit; 334514Speter 344564Speter s_lowpc = lowpc; 354564Speter s_highpc = highpc; 364850Speter s_textsize = highpc - lowpc; 374850Speter monsize = s_textsize + sizeof(struct phdr); 384564Speter buffer = sbrk( monsize ); 394564Speter if ( buffer == (char *) -1 ) { 404564Speter write( 2 , MSG , sizeof(MSG) ); 414564Speter return; 424564Speter } 434850Speter froms = (unsigned short *) sbrk( s_textsize ); 444564Speter if ( froms == (unsigned short *) -1 ) { 454564Speter write( 2 , MSG , sizeof(MSG) ); 464564Speter froms = 0; 474564Speter return; 484564Speter } 49*9530Smckusick limit = s_textsize * DENSITY / 100; 50*9530Smckusick if ( limit < MINCNT ) { 51*9530Smckusick limit = MINCNT; 52*9530Smckusick } else if ( limit > 65534 ) { 53*9530Smckusick limit = 65534; 54*9530Smckusick } 55*9530Smckusick tos = (struct tostruct *) sbrk( limit * sizeof( struct tostruct ) ); 564564Speter if ( tos == (struct tostruct *) -1 ) { 574564Speter write( 2 , MSG , sizeof(MSG) ); 584564Speter froms = 0; 594564Speter tos = 0; 604564Speter return; 614564Speter } 624564Speter tos[0].link = 0; 634850Speter /* 644850Speter * tolimit is what mcount checks to see if 654850Speter * all the data structures are ready!!! 664850Speter * make sure it won't overflow. 674850Speter */ 68*9530Smckusick tolimit = limit; 699433Smckusick monitor( lowpc , highpc , buffer , monsize , tolimit ); 704514Speter } 714514Speter 724514Speter _mcleanup() 734514Speter { 744869Smckusic int fd; 754869Smckusic int fromindex; 764869Smckusic char *frompc; 774869Smckusic int toindex; 784869Smckusic struct rawarc rawarc; 794514Speter 804869Smckusic fd = creat( "gmon.out" , 0666 ); 814869Smckusic if ( fd < 0 ) { 824564Speter perror( "mcount: gmon.out" ); 834514Speter return; 844514Speter } 854564Speter # ifdef DEBUG 864564Speter fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); 874564Speter # endif DEBUG 884869Smckusic write( fd , sbuf , ssiz ); 894850Speter for ( fromindex = 0 ; fromindex < s_textsize>>1 ; fromindex++ ) { 904514Speter if ( froms[fromindex] == 0 ) { 914514Speter continue; 924514Speter } 934514Speter frompc = s_lowpc + (fromindex<<1); 944514Speter for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 954514Speter # ifdef DEBUG 964748Speter fprintf( stderr , 974748Speter "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 984514Speter frompc , tos[toindex].selfpc , tos[toindex].count ); 994514Speter # endif DEBUG 1004869Smckusic rawarc.raw_frompc = (unsigned long) frompc; 1014869Smckusic rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; 1024869Smckusic rawarc.raw_count = tos[toindex].count; 1034869Smckusic write( fd , &rawarc , sizeof rawarc ); 1044514Speter } 1054514Speter } 1064869Smckusic close( fd ); 1074514Speter } 1084514Speter 1094564Speter /* 1104564Speter * This routine is massaged so that it may be jsb'ed to 1114564Speter */ 1124514Speter asm("#define _mcount mcount"); 1134514Speter mcount() 1144514Speter { 1154514Speter register char *selfpc; /* r11 */ 1164514Speter register unsigned short *frompcindex; /* r10 */ 1174514Speter register struct tostruct *top; /* r9 */ 1184540Speter static int profiling = 0; 1194514Speter 1204869Smckusic asm( " forgot to run ex script on gcrt0.s" ); 1214514Speter asm( "#define r11 r5" ); 1224514Speter asm( "#define r10 r4" ); 1234514Speter asm( "#define r9 r3" ); 1244514Speter #ifdef lint 1254514Speter selfpc = (char *) 0; 1264514Speter frompcindex = 0; 1274514Speter #else not lint 1284514Speter /* 1294540Speter * find the return address for mcount, 1304540Speter * and the return address for mcount's caller. 1314514Speter */ 1324514Speter asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ 1334514Speter asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ 1344514Speter #endif not lint 1354540Speter /* 1364540Speter * check that we are profiling 1374564Speter * and that we aren't recursively invoked. 1384540Speter */ 1394850Speter if ( tolimit == 0 ) { 1404514Speter goto out; 1414514Speter } 1424564Speter if ( profiling ) { 1434564Speter goto out; 1444564Speter } 1454540Speter profiling = 1; 1464540Speter /* 1474540Speter * check that frompcindex is a reasonable pc value. 1484540Speter * for example: signal catchers get called from the stack, 1494540Speter * not from text space. too bad. 1504540Speter */ 1514850Speter frompcindex = (unsigned short *) ( (long) frompcindex - (long) s_lowpc ); 1524850Speter if ( (unsigned long) frompcindex > s_textsize ) { 1534540Speter goto done; 1544540Speter } 1554850Speter frompcindex = &froms[ ( (long) frompcindex ) >> 1 ]; 1564514Speter if ( *frompcindex == 0 ) { 1574514Speter *frompcindex = ++tos[0].link; 1584514Speter if ( *frompcindex >= tolimit ) { 1594514Speter goto overflow; 1604514Speter } 1614514Speter top = &tos[ *frompcindex ]; 1624514Speter top->selfpc = selfpc; 1634514Speter top->count = 0; 1644514Speter top->link = 0; 1654514Speter } else { 1664514Speter top = &tos[ *frompcindex ]; 1674514Speter } 1684540Speter for ( ; /* goto done */ ; top = &tos[ top -> link ] ) { 1694514Speter if ( top -> selfpc == selfpc ) { 1704514Speter top -> count++; 1714540Speter goto done; 1724514Speter } 1734514Speter if ( top -> link == 0 ) { 1744514Speter top -> link = ++tos[0].link; 1754514Speter if ( top -> link >= tolimit ) 1764514Speter goto overflow; 1774514Speter top = &tos[ top -> link ]; 1784514Speter top -> selfpc = selfpc; 1794514Speter top -> count = 1; 1804514Speter top -> link = 0; 1814540Speter goto done; 1824514Speter } 1834514Speter } 1844540Speter done: 1854540Speter profiling = 0; 1864540Speter /* and fall through */ 1874514Speter out: 1884514Speter asm( " rsb" ); 1894514Speter asm( "#undef r11" ); 1904514Speter asm( "#undef r10" ); 1914514Speter asm( "#undef r9" ); 1924514Speter asm( "#undef _mcount"); 1934514Speter 1944514Speter overflow: 1954850Speter tolimit = 0; 1964514Speter # define TOLIMIT "mcount: tos overflow\n" 1974514Speter write( 2 , TOLIMIT , sizeof( TOLIMIT ) ); 1984514Speter goto out; 1994514Speter } 2004514Speter 2019433Smckusick /*VARARGS1*/ 2029433Smckusick monitor( lowpc , highpc , buf , bufsiz , nfunc ) 2034564Speter char *lowpc; 2044564Speter char *highpc; 2054564Speter int *buf, bufsiz; 2069433Smckusick int nfunc; /* not used, available for compatability only */ 2074514Speter { 2084564Speter register o; 2094514Speter 2104564Speter if ( lowpc == 0 ) { 2114564Speter profil( (char *) 0 , 0 , 0 , 0 ); 2129433Smckusick _mcleanup(); 2134564Speter return; 2144564Speter } 2154564Speter sbuf = buf; 2164564Speter ssiz = bufsiz; 2174564Speter ( (struct phdr *) buf ) -> lpc = lowpc; 2184564Speter ( (struct phdr *) buf ) -> hpc = highpc; 2194564Speter ( (struct phdr *) buf ) -> ncnt = ssiz; 2204564Speter o = sizeof(struct phdr); 2214564Speter buf = (int *) ( ( (int) buf ) + o ); 2224564Speter bufsiz -= o; 2234564Speter if ( bufsiz <= 0 ) 2244564Speter return; 2255070Smckusic o = ( ( (char *) highpc - (char *) lowpc) ); 2264564Speter if( bufsiz < o ) 2275070Smckusic o = ( (float) bufsiz / o ) * 65536; 2284564Speter else 2295070Smckusic o = 65536; 2304564Speter profil( buf , bufsiz , lowpc , o ); 2314514Speter } 2326177Smckusick 2336177Smckusick /* 2346177Smckusick * This is a stub for the "brk" system call, which we want to 2356253Smckusick * catch so that it will not deallocate our data space. 2366253Smckusick * (of which the program is not aware) 2376177Smckusick */ 2386253Smckusick asm("#define _curbrk curbrk"); 2396253Smckusick extern char *curbrk; 2406253Smckusick 2416177Smckusick brk(addr) 2426253Smckusick char *addr; 2436177Smckusick { 2446253Smckusick 2456253Smckusick if (addr < minsbrk) 2466253Smckusick addr = minsbrk; 2476253Smckusick asm(" chmk $17"); 2489433Smckusick asm(" jcc 1f"); 2499433Smckusick asm(" jmp cerror"); 2509433Smckusick asm("1:"); 2516253Smckusick curbrk = addr; 2526253Smckusick return (0); 2536177Smckusick } 254