1*10279Smckusick static char *sccsid = "@(#)gmon.c 4.10 (Berkeley) 01/14/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 */ 12*10279Smckusick 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; 196253Smckusick static char *minsbrk = 0; 204514Speter 214564Speter static int ssiz; 224564Speter static int *sbuf; 234514Speter 244514Speter #define MSG "No space for monitor buffer(s)\n" 254514Speter 269433Smckusick monstartup(lowpc, highpc) 274564Speter char *lowpc; 284564Speter char *highpc; 294514Speter { 304850Speter int monsize; 314850Speter char *buffer; 324850Speter char *sbrk(); 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 } 5110268Smckusick 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 } 57*10279Smckusick tolimit = s_textsize * ARCDENSITY / 100; 58*10279Smckusick if ( tolimit < MINARCS ) { 59*10279Smckusick tolimit = MINARCS; 60*10279Smckusick } else if ( tolimit > 65534 ) { 61*10279Smckusick tolimit = 65534; 629530Smckusick } 63*10279Smckusick tos = (struct tostruct *) sbrk( tolimit * 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; 72*10279Smckusick monitor( lowpc , highpc , buffer , monsize , tolimit ); 734850Speter /* 74*10279Smckusick * profiling is what mcount checks to see if 754850Speter * all the data structures are ready!!! 764850Speter */ 77*10279Smckusick profiling = 0; 784514Speter } 794514Speter 804514Speter _mcleanup() 814514Speter { 824869Smckusic int fd; 834869Smckusic int fromindex; 8410268Smckusick int endfrom; 854869Smckusic char *frompc; 864869Smckusic int toindex; 874869Smckusic struct rawarc rawarc; 884514Speter 894869Smckusic fd = creat( "gmon.out" , 0666 ); 904869Smckusic if ( fd < 0 ) { 914564Speter perror( "mcount: gmon.out" ); 924514Speter return; 934514Speter } 944564Speter # ifdef DEBUG 954564Speter fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); 964564Speter # endif DEBUG 974869Smckusic write( fd , sbuf , ssiz ); 9810268Smckusick endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); 9910268Smckusick for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { 1004514Speter if ( froms[fromindex] == 0 ) { 1014514Speter continue; 1024514Speter } 10310268Smckusick frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); 1044514Speter for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 1054514Speter # ifdef DEBUG 1064748Speter fprintf( stderr , 1074748Speter "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 1084514Speter frompc , tos[toindex].selfpc , tos[toindex].count ); 1094514Speter # endif DEBUG 1104869Smckusic rawarc.raw_frompc = (unsigned long) frompc; 1114869Smckusic rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; 1124869Smckusic rawarc.raw_count = tos[toindex].count; 1134869Smckusic write( fd , &rawarc , sizeof rawarc ); 1144514Speter } 1154514Speter } 1164869Smckusic close( fd ); 1174514Speter } 1184514Speter 1199608Speter asm(".text"); 1209608Speter asm("#the beginning of mcount()"); 1219608Speter asm(".data"); 1224514Speter mcount() 1234514Speter { 1249608Speter register char *selfpc; /* r11 => r5 */ 1259608Speter register unsigned short *frompcindex; /* r10 => r4 */ 1269608Speter register struct tostruct *top; /* r9 => r3 */ 1279608Speter register struct tostruct *prevtop; /* r8 => r2 */ 1289608Speter register long toindex; /* r7 => r1 */ 1294514Speter 1304514Speter #ifdef lint 1319608Speter selfpc = (char *)0; 1329608Speter frompcindex = 0; 1334514Speter #else not lint 1344514Speter /* 1354540Speter * find the return address for mcount, 1364540Speter * and the return address for mcount's caller. 1374514Speter */ 1389608Speter asm(" .text"); /* make sure we're in text space */ 1399608Speter asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ 1409608Speter asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ 1414514Speter #endif not lint 1424540Speter /* 1434540Speter * check that we are profiling 1444564Speter * and that we aren't recursively invoked. 1454540Speter */ 1469608Speter if (profiling) { 1479608Speter goto out; 1489608Speter } 149*10279Smckusick profiling++; 1504540Speter /* 1514540Speter * check that frompcindex is a reasonable pc value. 1524540Speter * for example: signal catchers get called from the stack, 1534540Speter * not from text space. too bad. 1544540Speter */ 1559608Speter frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc); 1569608Speter if ((unsigned long)frompcindex > s_textsize) { 1579608Speter goto done; 1584514Speter } 1599608Speter frompcindex = 16010268Smckusick &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))]; 1619608Speter toindex = *frompcindex; 1629608Speter if (toindex == 0) { 1639608Speter /* 1649608Speter * first time traversing this arc 1659608Speter */ 1669608Speter toindex = ++tos[0].link; 1679608Speter if (toindex >= tolimit) { 1689608Speter goto overflow; 1699608Speter } 1709608Speter *frompcindex = toindex; 1719608Speter top = &tos[toindex]; 1729608Speter top->selfpc = selfpc; 1739608Speter top->count = 1; 1749608Speter top->link = 0; 1759608Speter goto done; 1764514Speter } 1779608Speter top = &tos[toindex]; 1789608Speter if (top->selfpc == selfpc) { 1799608Speter /* 1809608Speter * arc at front of chain; usual case. 1819608Speter */ 1829608Speter top->count++; 1839608Speter goto done; 1844514Speter } 1859608Speter /* 1869608Speter * have to go looking down chain for it. 1879608Speter * top points to what we are looking at, 1889608Speter * prevtop points to previous top. 1899608Speter * we know it is not at the head of the chain. 1909608Speter */ 1919608Speter for (; /* goto done */; ) { 1929608Speter if (top->link == 0) { 1939608Speter /* 1949608Speter * top is end of the chain and none of the chain 1959608Speter * had top->selfpc == selfpc. 1969608Speter * so we allocate a new tostruct 1979608Speter * and link it to the head of the chain. 1989608Speter */ 1999608Speter toindex = ++tos[0].link; 2009608Speter if (toindex >= tolimit) { 2019608Speter goto overflow; 2029608Speter } 2039608Speter top = &tos[toindex]; 2049608Speter top->selfpc = selfpc; 2059608Speter top->count = 1; 2069608Speter top->link = *frompcindex; 2079608Speter *frompcindex = toindex; 2089608Speter goto done; 2099608Speter } 2109608Speter /* 2119608Speter * otherwise, check the next arc on the chain. 2129608Speter */ 2139608Speter prevtop = top; 2149608Speter top = &tos[top->link]; 2159608Speter if (top->selfpc == selfpc) { 2169608Speter /* 2179608Speter * there it is. 2189608Speter * increment its count 2199608Speter * move it to the head of the chain. 2209608Speter */ 2219608Speter top->count++; 2229608Speter toindex = prevtop->link; 2239608Speter prevtop->link = top->link; 2249608Speter top->link = *frompcindex; 2259608Speter *frompcindex = toindex; 2269608Speter goto done; 2279608Speter } 2289608Speter 2299608Speter } 2304540Speter done: 231*10279Smckusick profiling--; 2329608Speter /* and fall through */ 2334514Speter out: 2349608Speter asm(" rsb"); 2354514Speter 2364514Speter overflow: 237*10279Smckusick profiling++; /* halt further profiling */ 2384514Speter # define TOLIMIT "mcount: tos overflow\n" 2399608Speter write(2, TOLIMIT, sizeof(TOLIMIT)); 2409608Speter goto out; 2414514Speter } 2429608Speter asm(".text"); 2439608Speter asm("#the end of mcount()"); 2449608Speter asm(".data"); 2454514Speter 2469433Smckusick /*VARARGS1*/ 2479433Smckusick monitor( lowpc , highpc , buf , bufsiz , nfunc ) 2484564Speter char *lowpc; 2494564Speter char *highpc; 2504564Speter int *buf, bufsiz; 2519433Smckusick int nfunc; /* not used, available for compatability only */ 2524514Speter { 2534564Speter register o; 2544514Speter 2554564Speter if ( lowpc == 0 ) { 256*10279Smckusick profiling++; /* halt profiling */ 2574564Speter profil( (char *) 0 , 0 , 0 , 0 ); 2589433Smckusick _mcleanup(); 2594564Speter return; 2604564Speter } 2614564Speter sbuf = buf; 2624564Speter ssiz = bufsiz; 2634564Speter ( (struct phdr *) buf ) -> lpc = lowpc; 2644564Speter ( (struct phdr *) buf ) -> hpc = highpc; 2654564Speter ( (struct phdr *) buf ) -> ncnt = ssiz; 2664564Speter o = sizeof(struct phdr); 2674564Speter buf = (int *) ( ( (int) buf ) + o ); 2684564Speter bufsiz -= o; 2694564Speter if ( bufsiz <= 0 ) 2704564Speter return; 2715070Smckusic o = ( ( (char *) highpc - (char *) lowpc) ); 2724564Speter if( bufsiz < o ) 2735070Smckusic o = ( (float) bufsiz / o ) * 65536; 2744564Speter else 2755070Smckusic o = 65536; 2764564Speter profil( buf , bufsiz , lowpc , o ); 2774514Speter } 2786177Smckusick 2796177Smckusick /* 2806177Smckusick * This is a stub for the "brk" system call, which we want to 2816253Smckusick * catch so that it will not deallocate our data space. 2826253Smckusick * (of which the program is not aware) 2836177Smckusick */ 2846253Smckusick extern char *curbrk; 2856253Smckusick 2866177Smckusick brk(addr) 2876253Smckusick char *addr; 2886177Smckusick { 2896253Smckusick 2906253Smckusick if (addr < minsbrk) 2916253Smckusick addr = minsbrk; 2926253Smckusick asm(" chmk $17"); 2939433Smckusick asm(" jcc 1f"); 2949433Smckusick asm(" jmp cerror"); 2959433Smckusick asm("1:"); 2966253Smckusick curbrk = addr; 2976253Smckusick return (0); 2986177Smckusick } 299