1*14127Smckusick static char *sccsid = "@(#)gmon.c 4.13 (Berkeley) 07/26/83"; 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 */ 1210279Smckusick static int profiling = 3; 134514Speter static unsigned short *froms; 144514Speter static struct tostruct *tos = 0; 159608Speter static long tolimit = 0; 164514Speter static char *s_lowpc = 0; 174514Speter static char *s_highpc = 0; 184850Speter static unsigned long s_textsize = 0; 194514Speter 204564Speter static int ssiz; 2111998Speter static char *sbuf; 2211796Speter static int s_scale; 2311998Speter /* see profil(2) where this is describe (incorrectly) */ 2411998Speter #define SCALE_1_TO_1 0x10000L 254514Speter 264514Speter #define MSG "No space for monitor buffer(s)\n" 274514Speter 289433Smckusick monstartup(lowpc, highpc) 294564Speter char *lowpc; 304564Speter char *highpc; 314514Speter { 324850Speter int monsize; 334850Speter char *buffer; 344850Speter char *sbrk(); 35*14127Smckusick extern char *minbrk; 364514Speter 379608Speter /* 389608Speter * round lowpc and highpc to multiples of the density we're using 399608Speter * so the rest of the scaling (here and in gprof) stays in ints. 409608Speter */ 419608Speter lowpc = (char *) 429608Speter ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); 434564Speter s_lowpc = lowpc; 449608Speter highpc = (char *) 459608Speter ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER)); 464564Speter s_highpc = highpc; 474850Speter s_textsize = highpc - lowpc; 489608Speter monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr); 494564Speter buffer = sbrk( monsize ); 504564Speter if ( buffer == (char *) -1 ) { 514564Speter write( 2 , MSG , sizeof(MSG) ); 524564Speter return; 534564Speter } 5410268Smckusick froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION ); 554564Speter if ( froms == (unsigned short *) -1 ) { 564564Speter write( 2 , MSG , sizeof(MSG) ); 574564Speter froms = 0; 584564Speter return; 594564Speter } 6010279Smckusick tolimit = s_textsize * ARCDENSITY / 100; 6110279Smckusick if ( tolimit < MINARCS ) { 6210279Smckusick tolimit = MINARCS; 6310279Smckusick } else if ( tolimit > 65534 ) { 6410279Smckusick tolimit = 65534; 659530Smckusick } 6610279Smckusick tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) ); 674564Speter if ( tos == (struct tostruct *) -1 ) { 684564Speter write( 2 , MSG , sizeof(MSG) ); 694564Speter froms = 0; 704564Speter tos = 0; 714564Speter return; 724564Speter } 73*14127Smckusick minbrk = sbrk(0); 744564Speter tos[0].link = 0; 7510279Smckusick monitor( lowpc , highpc , buffer , monsize , tolimit ); 764514Speter } 774514Speter 784514Speter _mcleanup() 794514Speter { 804869Smckusic int fd; 814869Smckusic int fromindex; 8210268Smckusick int endfrom; 834869Smckusic char *frompc; 844869Smckusic int toindex; 854869Smckusic struct rawarc rawarc; 864514Speter 874869Smckusic fd = creat( "gmon.out" , 0666 ); 884869Smckusic if ( fd < 0 ) { 894564Speter perror( "mcount: gmon.out" ); 904514Speter return; 914514Speter } 924564Speter # ifdef DEBUG 934564Speter fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); 944564Speter # endif DEBUG 954869Smckusic write( fd , sbuf , ssiz ); 9610268Smckusick endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); 9710268Smckusick for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { 984514Speter if ( froms[fromindex] == 0 ) { 994514Speter continue; 1004514Speter } 10110268Smckusick frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); 1024514Speter for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 1034514Speter # ifdef DEBUG 1044748Speter fprintf( stderr , 1054748Speter "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 1064514Speter frompc , tos[toindex].selfpc , tos[toindex].count ); 1074514Speter # endif DEBUG 1084869Smckusic rawarc.raw_frompc = (unsigned long) frompc; 1094869Smckusic rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; 1104869Smckusic rawarc.raw_count = tos[toindex].count; 1114869Smckusic write( fd , &rawarc , sizeof rawarc ); 1124514Speter } 1134514Speter } 1144869Smckusic close( fd ); 1154514Speter } 1164514Speter 1179608Speter asm(".text"); 11811796Speter asm(".align 2"); 1199608Speter asm("#the beginning of mcount()"); 1209608Speter asm(".data"); 1214514Speter mcount() 1224514Speter { 1239608Speter register char *selfpc; /* r11 => r5 */ 1249608Speter register unsigned short *frompcindex; /* r10 => r4 */ 1259608Speter register struct tostruct *top; /* r9 => r3 */ 1269608Speter register struct tostruct *prevtop; /* r8 => r2 */ 1279608Speter register long toindex; /* r7 => r1 */ 1284514Speter 1294514Speter #ifdef lint 1309608Speter selfpc = (char *)0; 1319608Speter frompcindex = 0; 1324514Speter #else not lint 1334514Speter /* 1344540Speter * find the return address for mcount, 1354540Speter * and the return address for mcount's caller. 1364514Speter */ 1379608Speter asm(" .text"); /* make sure we're in text space */ 1389608Speter asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ 1399608Speter asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ 1404514Speter #endif not lint 1414540Speter /* 1424540Speter * check that we are profiling 1434564Speter * and that we aren't recursively invoked. 1444540Speter */ 1459608Speter if (profiling) { 1469608Speter goto out; 1479608Speter } 14810279Smckusick profiling++; 1494540Speter /* 1504540Speter * check that frompcindex is a reasonable pc value. 1514540Speter * for example: signal catchers get called from the stack, 1524540Speter * not from text space. too bad. 1534540Speter */ 1549608Speter frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc); 1559608Speter if ((unsigned long)frompcindex > s_textsize) { 1569608Speter goto done; 1574514Speter } 1589608Speter frompcindex = 15910268Smckusick &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))]; 1609608Speter toindex = *frompcindex; 1619608Speter if (toindex == 0) { 1629608Speter /* 1639608Speter * first time traversing this arc 1649608Speter */ 1659608Speter toindex = ++tos[0].link; 1669608Speter if (toindex >= tolimit) { 1679608Speter goto overflow; 1689608Speter } 1699608Speter *frompcindex = toindex; 1709608Speter top = &tos[toindex]; 1719608Speter top->selfpc = selfpc; 1729608Speter top->count = 1; 1739608Speter top->link = 0; 1749608Speter goto done; 1754514Speter } 1769608Speter top = &tos[toindex]; 1779608Speter if (top->selfpc == selfpc) { 1789608Speter /* 1799608Speter * arc at front of chain; usual case. 1809608Speter */ 1819608Speter top->count++; 1829608Speter goto done; 1834514Speter } 1849608Speter /* 1859608Speter * have to go looking down chain for it. 1869608Speter * top points to what we are looking at, 1879608Speter * prevtop points to previous top. 1889608Speter * we know it is not at the head of the chain. 1899608Speter */ 1909608Speter for (; /* goto done */; ) { 1919608Speter if (top->link == 0) { 1929608Speter /* 1939608Speter * top is end of the chain and none of the chain 1949608Speter * had top->selfpc == selfpc. 1959608Speter * so we allocate a new tostruct 1969608Speter * and link it to the head of the chain. 1979608Speter */ 1989608Speter toindex = ++tos[0].link; 1999608Speter if (toindex >= tolimit) { 2009608Speter goto overflow; 2019608Speter } 2029608Speter top = &tos[toindex]; 2039608Speter top->selfpc = selfpc; 2049608Speter top->count = 1; 2059608Speter top->link = *frompcindex; 2069608Speter *frompcindex = toindex; 2079608Speter goto done; 2089608Speter } 2099608Speter /* 2109608Speter * otherwise, check the next arc on the chain. 2119608Speter */ 2129608Speter prevtop = top; 2139608Speter top = &tos[top->link]; 2149608Speter if (top->selfpc == selfpc) { 2159608Speter /* 2169608Speter * there it is. 2179608Speter * increment its count 2189608Speter * move it to the head of the chain. 2199608Speter */ 2209608Speter top->count++; 2219608Speter toindex = prevtop->link; 2229608Speter prevtop->link = top->link; 2239608Speter top->link = *frompcindex; 2249608Speter *frompcindex = toindex; 2259608Speter goto done; 2269608Speter } 2279608Speter 2289608Speter } 2294540Speter done: 23010279Smckusick profiling--; 2319608Speter /* and fall through */ 2324514Speter out: 2339608Speter asm(" rsb"); 2344514Speter 2354514Speter overflow: 23610279Smckusick profiling++; /* halt further profiling */ 2374514Speter # define TOLIMIT "mcount: tos overflow\n" 2389608Speter write(2, TOLIMIT, sizeof(TOLIMIT)); 2399608Speter goto out; 2404514Speter } 2419608Speter asm(".text"); 2429608Speter asm("#the end of mcount()"); 2439608Speter asm(".data"); 2444514Speter 2459433Smckusick /*VARARGS1*/ 2469433Smckusick monitor( lowpc , highpc , buf , bufsiz , nfunc ) 2474564Speter char *lowpc; 2484564Speter char *highpc; 24911998Speter char *buf; /* declared ``short buffer[]'' in monitor(3) */ 25011998Speter int bufsiz; 2519433Smckusick int nfunc; /* not used, available for compatability only */ 2524514Speter { 2534564Speter register o; 2544514Speter 2554564Speter if ( lowpc == 0 ) { 25611796Speter moncontrol(0); 2579433Smckusick _mcleanup(); 2584564Speter return; 2594564Speter } 2604564Speter sbuf = buf; 2614564Speter ssiz = bufsiz; 2624564Speter ( (struct phdr *) buf ) -> lpc = lowpc; 2634564Speter ( (struct phdr *) buf ) -> hpc = highpc; 2644564Speter ( (struct phdr *) buf ) -> ncnt = ssiz; 26511998Speter bufsiz -= sizeof(struct phdr); 2664564Speter if ( bufsiz <= 0 ) 2674564Speter return; 26811998Speter o = highpc - lowpc; 2694564Speter if( bufsiz < o ) 27011998Speter s_scale = ( (float) bufsiz / o ) * SCALE_1_TO_1; 2714564Speter else 27211998Speter s_scale = SCALE_1_TO_1; 27311796Speter moncontrol(1); 2744514Speter } 2756177Smckusick 2766177Smckusick /* 27711796Speter * Control profiling 27811796Speter * profiling is what mcount checks to see if 27911796Speter * all the data structures are ready. 28011796Speter */ 28111796Speter moncontrol(mode) 28211796Speter int mode; 28311796Speter { 28411796Speter if (mode) { 28511796Speter /* start */ 28611796Speter profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr), 28711796Speter s_lowpc, s_scale); 28811796Speter profiling = 0; 28911796Speter } else { 29011796Speter /* stop */ 29111796Speter profil((char *)0, 0, 0, 0); 29211796Speter profiling = 3; 29311796Speter } 29411796Speter } 295