1*10268Smckusick static char *sccsid = "@(#)gmon.c 4.9 (Berkeley) 01/13/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 */ 124514Speter static unsigned short *froms; 134514Speter static struct tostruct *tos = 0; 149608Speter static long 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 349608Speter /* 359608Speter * round lowpc and highpc to multiples of the density we're using 369608Speter * so the rest of the scaling (here and in gprof) stays in ints. 379608Speter */ 389608Speter lowpc = (char *) 399608Speter ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); 404564Speter s_lowpc = lowpc; 419608Speter highpc = (char *) 429608Speter ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER)); 434564Speter s_highpc = highpc; 444850Speter s_textsize = highpc - lowpc; 459608Speter monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr); 464564Speter buffer = sbrk( monsize ); 474564Speter if ( buffer == (char *) -1 ) { 484564Speter write( 2 , MSG , sizeof(MSG) ); 494564Speter return; 504564Speter } 51*10268Smckusick froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION ); 524564Speter if ( froms == (unsigned short *) -1 ) { 534564Speter write( 2 , MSG , sizeof(MSG) ); 544564Speter froms = 0; 554564Speter return; 564564Speter } 579608Speter limit = s_textsize * ARCDENSITY / 100; 589608Speter if ( limit < MINARCS ) { 599608Speter limit = MINARCS; 609530Smckusick } else if ( limit > 65534 ) { 619530Smckusick limit = 65534; 629530Smckusick } 639530Smckusick tos = (struct tostruct *) sbrk( limit * sizeof( struct tostruct ) ); 644564Speter if ( tos == (struct tostruct *) -1 ) { 654564Speter write( 2 , MSG , sizeof(MSG) ); 664564Speter froms = 0; 674564Speter tos = 0; 684564Speter return; 694564Speter } 709608Speter minsbrk = sbrk(0); 714564Speter tos[0].link = 0; 724850Speter /* 734850Speter * tolimit is what mcount checks to see if 744850Speter * all the data structures are ready!!! 754850Speter * make sure it won't overflow. 764850Speter */ 779530Smckusick tolimit = limit; 789433Smckusick monitor( lowpc , highpc , buffer , monsize , tolimit ); 794514Speter } 804514Speter 814514Speter _mcleanup() 824514Speter { 834869Smckusic int fd; 844869Smckusic int fromindex; 85*10268Smckusick int endfrom; 864869Smckusic char *frompc; 874869Smckusic int toindex; 884869Smckusic struct rawarc rawarc; 894514Speter 904869Smckusic fd = creat( "gmon.out" , 0666 ); 914869Smckusic if ( fd < 0 ) { 924564Speter perror( "mcount: gmon.out" ); 934514Speter return; 944514Speter } 954564Speter # ifdef DEBUG 964564Speter fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); 974564Speter # endif DEBUG 984869Smckusic write( fd , sbuf , ssiz ); 99*10268Smckusick endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); 100*10268Smckusick for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { 1014514Speter if ( froms[fromindex] == 0 ) { 1024514Speter continue; 1034514Speter } 104*10268Smckusick frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); 1054514Speter for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 1064514Speter # ifdef DEBUG 1074748Speter fprintf( stderr , 1084748Speter "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 1094514Speter frompc , tos[toindex].selfpc , tos[toindex].count ); 1104514Speter # endif DEBUG 1114869Smckusic rawarc.raw_frompc = (unsigned long) frompc; 1124869Smckusic rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; 1134869Smckusic rawarc.raw_count = tos[toindex].count; 1144869Smckusic write( fd , &rawarc , sizeof rawarc ); 1154514Speter } 1164514Speter } 1174869Smckusic close( fd ); 1184514Speter } 1194514Speter 1209608Speter asm(".text"); 1219608Speter asm("#the beginning of mcount()"); 1229608Speter asm(".data"); 1234514Speter mcount() 1244514Speter { 1259608Speter register char *selfpc; /* r11 => r5 */ 1269608Speter register unsigned short *frompcindex; /* r10 => r4 */ 1279608Speter register struct tostruct *top; /* r9 => r3 */ 1289608Speter register struct tostruct *prevtop; /* r8 => r2 */ 1299608Speter register long toindex; /* r7 => r1 */ 1309608Speter static int profiling = 0; 1314514Speter 1324514Speter #ifdef lint 1339608Speter selfpc = (char *)0; 1349608Speter frompcindex = 0; 1354514Speter #else not lint 1364514Speter /* 1374540Speter * find the return address for mcount, 1384540Speter * and the return address for mcount's caller. 1394514Speter */ 1409608Speter asm(" .text"); /* make sure we're in text space */ 1419608Speter asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ 1429608Speter asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ 1434514Speter #endif not lint 1444540Speter /* 1454540Speter * check that we are profiling 1464564Speter * and that we aren't recursively invoked. 1474540Speter */ 1489608Speter if (tolimit == 0) { 1499608Speter goto out; 1509608Speter } 1519608Speter if (profiling) { 1529608Speter goto out; 1539608Speter } 1549608Speter profiling = 1; 1554540Speter /* 1564540Speter * check that frompcindex is a reasonable pc value. 1574540Speter * for example: signal catchers get called from the stack, 1584540Speter * not from text space. too bad. 1594540Speter */ 1609608Speter frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc); 1619608Speter if ((unsigned long)frompcindex > s_textsize) { 1629608Speter goto done; 1634514Speter } 1649608Speter frompcindex = 165*10268Smckusick &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))]; 1669608Speter toindex = *frompcindex; 1679608Speter if (toindex == 0) { 1689608Speter /* 1699608Speter * first time traversing this arc 1709608Speter */ 1719608Speter toindex = ++tos[0].link; 1729608Speter if (toindex >= tolimit) { 1739608Speter goto overflow; 1749608Speter } 1759608Speter *frompcindex = toindex; 1769608Speter top = &tos[toindex]; 1779608Speter top->selfpc = selfpc; 1789608Speter top->count = 1; 1799608Speter top->link = 0; 1809608Speter goto done; 1814514Speter } 1829608Speter top = &tos[toindex]; 1839608Speter if (top->selfpc == selfpc) { 1849608Speter /* 1859608Speter * arc at front of chain; usual case. 1869608Speter */ 1879608Speter top->count++; 1889608Speter goto done; 1894514Speter } 1909608Speter /* 1919608Speter * have to go looking down chain for it. 1929608Speter * top points to what we are looking at, 1939608Speter * prevtop points to previous top. 1949608Speter * we know it is not at the head of the chain. 1959608Speter */ 1969608Speter for (; /* goto done */; ) { 1979608Speter if (top->link == 0) { 1989608Speter /* 1999608Speter * top is end of the chain and none of the chain 2009608Speter * had top->selfpc == selfpc. 2019608Speter * so we allocate a new tostruct 2029608Speter * and link it to the head of the chain. 2039608Speter */ 2049608Speter toindex = ++tos[0].link; 2059608Speter if (toindex >= tolimit) { 2069608Speter goto overflow; 2079608Speter } 2089608Speter top = &tos[toindex]; 2099608Speter top->selfpc = selfpc; 2109608Speter top->count = 1; 2119608Speter top->link = *frompcindex; 2129608Speter *frompcindex = toindex; 2139608Speter goto done; 2149608Speter } 2159608Speter /* 2169608Speter * otherwise, check the next arc on the chain. 2179608Speter */ 2189608Speter prevtop = top; 2199608Speter top = &tos[top->link]; 2209608Speter if (top->selfpc == selfpc) { 2219608Speter /* 2229608Speter * there it is. 2239608Speter * increment its count 2249608Speter * move it to the head of the chain. 2259608Speter */ 2269608Speter top->count++; 2279608Speter toindex = prevtop->link; 2289608Speter prevtop->link = top->link; 2299608Speter top->link = *frompcindex; 2309608Speter *frompcindex = toindex; 2319608Speter goto done; 2329608Speter } 2339608Speter 2349608Speter } 2354540Speter done: 2369608Speter profiling = 0; 2379608Speter /* and fall through */ 2384514Speter out: 2399608Speter asm(" rsb"); 2404514Speter 2414514Speter overflow: 2429608Speter tolimit = 0; 2434514Speter # define TOLIMIT "mcount: tos overflow\n" 2449608Speter write(2, TOLIMIT, sizeof(TOLIMIT)); 2459608Speter goto out; 2464514Speter } 2479608Speter asm(".text"); 2489608Speter asm("#the end of mcount()"); 2499608Speter asm(".data"); 2504514Speter 2519433Smckusick /*VARARGS1*/ 2529433Smckusick monitor( lowpc , highpc , buf , bufsiz , nfunc ) 2534564Speter char *lowpc; 2544564Speter char *highpc; 2554564Speter int *buf, bufsiz; 2569433Smckusick int nfunc; /* not used, available for compatability only */ 2574514Speter { 2584564Speter register o; 2594514Speter 2604564Speter if ( lowpc == 0 ) { 2614564Speter profil( (char *) 0 , 0 , 0 , 0 ); 2629433Smckusick _mcleanup(); 2634564Speter return; 2644564Speter } 2654564Speter sbuf = buf; 2664564Speter ssiz = bufsiz; 2674564Speter ( (struct phdr *) buf ) -> lpc = lowpc; 2684564Speter ( (struct phdr *) buf ) -> hpc = highpc; 2694564Speter ( (struct phdr *) buf ) -> ncnt = ssiz; 2704564Speter o = sizeof(struct phdr); 2714564Speter buf = (int *) ( ( (int) buf ) + o ); 2724564Speter bufsiz -= o; 2734564Speter if ( bufsiz <= 0 ) 2744564Speter return; 2755070Smckusic o = ( ( (char *) highpc - (char *) lowpc) ); 2764564Speter if( bufsiz < o ) 2775070Smckusic o = ( (float) bufsiz / o ) * 65536; 2784564Speter else 2795070Smckusic o = 65536; 2804564Speter profil( buf , bufsiz , lowpc , o ); 2814514Speter } 2826177Smckusick 2836177Smckusick /* 2846177Smckusick * This is a stub for the "brk" system call, which we want to 2856253Smckusick * catch so that it will not deallocate our data space. 2866253Smckusick * (of which the program is not aware) 2876177Smckusick */ 2886253Smckusick extern char *curbrk; 2896253Smckusick 2906177Smckusick brk(addr) 2916253Smckusick char *addr; 2926177Smckusick { 2936253Smckusick 2946253Smckusick if (addr < minsbrk) 2956253Smckusick addr = minsbrk; 2966253Smckusick asm(" chmk $17"); 2979433Smckusick asm(" jcc 1f"); 2989433Smckusick asm(" jmp cerror"); 2999433Smckusick asm("1:"); 3006253Smckusick curbrk = addr; 3016253Smckusick return (0); 3026177Smckusick } 303