1*9608Speter static char *sccsid = "@(#)gmon.c 4.8 (Berkeley) 12/10/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; 14*9608Speter 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 34*9608Speter /* 35*9608Speter * round lowpc and highpc to multiples of the density we're using 36*9608Speter * so the rest of the scaling (here and in gprof) stays in ints. 37*9608Speter */ 38*9608Speter lowpc = (char *) 39*9608Speter ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); 404564Speter s_lowpc = lowpc; 41*9608Speter highpc = (char *) 42*9608Speter ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER)); 434564Speter s_highpc = highpc; 444850Speter s_textsize = highpc - lowpc; 45*9608Speter 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 } 514850Speter froms = (unsigned short *) sbrk( s_textsize ); 524564Speter if ( froms == (unsigned short *) -1 ) { 534564Speter write( 2 , MSG , sizeof(MSG) ); 544564Speter froms = 0; 554564Speter return; 564564Speter } 57*9608Speter limit = s_textsize * ARCDENSITY / 100; 58*9608Speter if ( limit < MINARCS ) { 59*9608Speter 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 } 70*9608Speter 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; 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 ); 984850Speter for ( fromindex = 0 ; fromindex < s_textsize>>1 ; fromindex++ ) { 994514Speter if ( froms[fromindex] == 0 ) { 1004514Speter continue; 1014514Speter } 1024514Speter frompc = s_lowpc + (fromindex<<1); 1034514Speter for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 1044514Speter # ifdef DEBUG 1054748Speter fprintf( stderr , 1064748Speter "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 1074514Speter frompc , tos[toindex].selfpc , tos[toindex].count ); 1084514Speter # endif DEBUG 1094869Smckusic rawarc.raw_frompc = (unsigned long) frompc; 1104869Smckusic rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; 1114869Smckusic rawarc.raw_count = tos[toindex].count; 1124869Smckusic write( fd , &rawarc , sizeof rawarc ); 1134514Speter } 1144514Speter } 1154869Smckusic close( fd ); 1164514Speter } 1174514Speter 118*9608Speter asm(".text"); 119*9608Speter asm("#the beginning of mcount()"); 120*9608Speter asm(".data"); 1214514Speter mcount() 1224514Speter { 123*9608Speter register char *selfpc; /* r11 => r5 */ 124*9608Speter register unsigned short *frompcindex; /* r10 => r4 */ 125*9608Speter register struct tostruct *top; /* r9 => r3 */ 126*9608Speter register struct tostruct *prevtop; /* r8 => r2 */ 127*9608Speter register long toindex; /* r7 => r1 */ 128*9608Speter static int profiling = 0; 1294514Speter 1304514Speter #ifdef lint 131*9608Speter selfpc = (char *)0; 132*9608Speter frompcindex = 0; 1334514Speter #else not lint 1344514Speter /* 1354540Speter * find the return address for mcount, 1364540Speter * and the return address for mcount's caller. 1374514Speter */ 138*9608Speter asm(" .text"); /* make sure we're in text space */ 139*9608Speter asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ 140*9608Speter 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 */ 146*9608Speter if (tolimit == 0) { 147*9608Speter goto out; 148*9608Speter } 149*9608Speter if (profiling) { 150*9608Speter goto out; 151*9608Speter } 152*9608Speter profiling = 1; 1534540Speter /* 1544540Speter * check that frompcindex is a reasonable pc value. 1554540Speter * for example: signal catchers get called from the stack, 1564540Speter * not from text space. too bad. 1574540Speter */ 158*9608Speter frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc); 159*9608Speter if ((unsigned long)frompcindex > s_textsize) { 160*9608Speter goto done; 1614514Speter } 162*9608Speter frompcindex = 163*9608Speter &froms[(((long)frompcindex) + sizeof(*froms) - 1) / sizeof(*froms)]; 164*9608Speter toindex = *frompcindex; 165*9608Speter if (toindex == 0) { 166*9608Speter /* 167*9608Speter * first time traversing this arc 168*9608Speter */ 169*9608Speter toindex = ++tos[0].link; 170*9608Speter if (toindex >= tolimit) { 171*9608Speter goto overflow; 172*9608Speter } 173*9608Speter *frompcindex = toindex; 174*9608Speter top = &tos[toindex]; 175*9608Speter top->selfpc = selfpc; 176*9608Speter top->count = 1; 177*9608Speter top->link = 0; 178*9608Speter goto done; 1794514Speter } 180*9608Speter top = &tos[toindex]; 181*9608Speter if (top->selfpc == selfpc) { 182*9608Speter /* 183*9608Speter * arc at front of chain; usual case. 184*9608Speter */ 185*9608Speter top->count++; 186*9608Speter goto done; 1874514Speter } 188*9608Speter /* 189*9608Speter * have to go looking down chain for it. 190*9608Speter * top points to what we are looking at, 191*9608Speter * prevtop points to previous top. 192*9608Speter * we know it is not at the head of the chain. 193*9608Speter */ 194*9608Speter for (; /* goto done */; ) { 195*9608Speter if (top->link == 0) { 196*9608Speter /* 197*9608Speter * top is end of the chain and none of the chain 198*9608Speter * had top->selfpc == selfpc. 199*9608Speter * so we allocate a new tostruct 200*9608Speter * and link it to the head of the chain. 201*9608Speter */ 202*9608Speter toindex = ++tos[0].link; 203*9608Speter if (toindex >= tolimit) { 204*9608Speter goto overflow; 205*9608Speter } 206*9608Speter top = &tos[toindex]; 207*9608Speter top->selfpc = selfpc; 208*9608Speter top->count = 1; 209*9608Speter top->link = *frompcindex; 210*9608Speter *frompcindex = toindex; 211*9608Speter goto done; 212*9608Speter } 213*9608Speter /* 214*9608Speter * otherwise, check the next arc on the chain. 215*9608Speter */ 216*9608Speter prevtop = top; 217*9608Speter top = &tos[top->link]; 218*9608Speter if (top->selfpc == selfpc) { 219*9608Speter /* 220*9608Speter * there it is. 221*9608Speter * increment its count 222*9608Speter * move it to the head of the chain. 223*9608Speter */ 224*9608Speter top->count++; 225*9608Speter toindex = prevtop->link; 226*9608Speter prevtop->link = top->link; 227*9608Speter top->link = *frompcindex; 228*9608Speter *frompcindex = toindex; 229*9608Speter goto done; 230*9608Speter } 231*9608Speter 232*9608Speter } 2334540Speter done: 234*9608Speter profiling = 0; 235*9608Speter /* and fall through */ 2364514Speter out: 237*9608Speter asm(" rsb"); 2384514Speter 2394514Speter overflow: 240*9608Speter tolimit = 0; 2414514Speter # define TOLIMIT "mcount: tos overflow\n" 242*9608Speter write(2, TOLIMIT, sizeof(TOLIMIT)); 243*9608Speter goto out; 2444514Speter } 245*9608Speter asm(".text"); 246*9608Speter asm("#the end of mcount()"); 247*9608Speter asm(".data"); 2484514Speter 2499433Smckusick /*VARARGS1*/ 2509433Smckusick monitor( lowpc , highpc , buf , bufsiz , nfunc ) 2514564Speter char *lowpc; 2524564Speter char *highpc; 2534564Speter int *buf, bufsiz; 2549433Smckusick int nfunc; /* not used, available for compatability only */ 2554514Speter { 2564564Speter register o; 2574514Speter 2584564Speter if ( lowpc == 0 ) { 2594564Speter profil( (char *) 0 , 0 , 0 , 0 ); 2609433Smckusick _mcleanup(); 2614564Speter return; 2624564Speter } 2634564Speter sbuf = buf; 2644564Speter ssiz = bufsiz; 2654564Speter ( (struct phdr *) buf ) -> lpc = lowpc; 2664564Speter ( (struct phdr *) buf ) -> hpc = highpc; 2674564Speter ( (struct phdr *) buf ) -> ncnt = ssiz; 2684564Speter o = sizeof(struct phdr); 2694564Speter buf = (int *) ( ( (int) buf ) + o ); 2704564Speter bufsiz -= o; 2714564Speter if ( bufsiz <= 0 ) 2724564Speter return; 2735070Smckusic o = ( ( (char *) highpc - (char *) lowpc) ); 2744564Speter if( bufsiz < o ) 2755070Smckusic o = ( (float) bufsiz / o ) * 65536; 2764564Speter else 2775070Smckusic o = 65536; 2784564Speter profil( buf , bufsiz , lowpc , o ); 2794514Speter } 2806177Smckusick 2816177Smckusick /* 2826177Smckusick * This is a stub for the "brk" system call, which we want to 2836253Smckusick * catch so that it will not deallocate our data space. 2846253Smckusick * (of which the program is not aware) 2856177Smckusick */ 2866253Smckusick extern char *curbrk; 2876253Smckusick 2886177Smckusick brk(addr) 2896253Smckusick char *addr; 2906177Smckusick { 2916253Smckusick 2926253Smckusick if (addr < minsbrk) 2936253Smckusick addr = minsbrk; 2946253Smckusick asm(" chmk $17"); 2959433Smckusick asm(" jcc 1f"); 2969433Smckusick asm(" jmp cerror"); 2979433Smckusick asm("1:"); 2986253Smckusick curbrk = addr; 2996253Smckusick return (0); 3006177Smckusick } 301