1*11796Speter static char *sccsid = "@(#)gmon.c 4.11 (Berkeley) 03/30/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; 196253Smckusick static char *minsbrk = 0; 204514Speter 214564Speter static int ssiz; 224564Speter static int *sbuf; 23*11796Speter static int s_scale; 244514Speter 254514Speter #define MSG "No space for monitor buffer(s)\n" 264514Speter 279433Smckusick monstartup(lowpc, highpc) 284564Speter char *lowpc; 294564Speter char *highpc; 304514Speter { 314850Speter int monsize; 324850Speter char *buffer; 334850Speter char *sbrk(); 344514Speter 359608Speter /* 369608Speter * round lowpc and highpc to multiples of the density we're using 379608Speter * so the rest of the scaling (here and in gprof) stays in ints. 389608Speter */ 399608Speter lowpc = (char *) 409608Speter ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); 414564Speter s_lowpc = lowpc; 429608Speter highpc = (char *) 439608Speter ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER)); 444564Speter s_highpc = highpc; 454850Speter s_textsize = highpc - lowpc; 469608Speter monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr); 474564Speter buffer = sbrk( monsize ); 484564Speter if ( buffer == (char *) -1 ) { 494564Speter write( 2 , MSG , sizeof(MSG) ); 504564Speter return; 514564Speter } 5210268Smckusick froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION ); 534564Speter if ( froms == (unsigned short *) -1 ) { 544564Speter write( 2 , MSG , sizeof(MSG) ); 554564Speter froms = 0; 564564Speter return; 574564Speter } 5810279Smckusick tolimit = s_textsize * ARCDENSITY / 100; 5910279Smckusick if ( tolimit < MINARCS ) { 6010279Smckusick tolimit = MINARCS; 6110279Smckusick } else if ( tolimit > 65534 ) { 6210279Smckusick tolimit = 65534; 639530Smckusick } 6410279Smckusick tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) ); 654564Speter if ( tos == (struct tostruct *) -1 ) { 664564Speter write( 2 , MSG , sizeof(MSG) ); 674564Speter froms = 0; 684564Speter tos = 0; 694564Speter return; 704564Speter } 719608Speter minsbrk = sbrk(0); 724564Speter tos[0].link = 0; 7310279Smckusick monitor( lowpc , highpc , buffer , monsize , tolimit ); 74*11796Speter moncontrol(1); 754514Speter } 764514Speter 774514Speter _mcleanup() 784514Speter { 794869Smckusic int fd; 804869Smckusic int fromindex; 8110268Smckusick int endfrom; 824869Smckusic char *frompc; 834869Smckusic int toindex; 844869Smckusic struct rawarc rawarc; 854514Speter 864869Smckusic fd = creat( "gmon.out" , 0666 ); 874869Smckusic if ( fd < 0 ) { 884564Speter perror( "mcount: gmon.out" ); 894514Speter return; 904514Speter } 914564Speter # ifdef DEBUG 924564Speter fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); 934564Speter # endif DEBUG 944869Smckusic write( fd , sbuf , ssiz ); 9510268Smckusick endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); 9610268Smckusick for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { 974514Speter if ( froms[fromindex] == 0 ) { 984514Speter continue; 994514Speter } 10010268Smckusick frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); 1014514Speter for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 1024514Speter # ifdef DEBUG 1034748Speter fprintf( stderr , 1044748Speter "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 1054514Speter frompc , tos[toindex].selfpc , tos[toindex].count ); 1064514Speter # endif DEBUG 1074869Smckusic rawarc.raw_frompc = (unsigned long) frompc; 1084869Smckusic rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; 1094869Smckusic rawarc.raw_count = tos[toindex].count; 1104869Smckusic write( fd , &rawarc , sizeof rawarc ); 1114514Speter } 1124514Speter } 1134869Smckusic close( fd ); 1144514Speter } 1154514Speter 1169608Speter asm(".text"); 117*11796Speter asm(".align 2"); 1189608Speter asm("#the beginning of mcount()"); 1199608Speter asm(".data"); 1204514Speter mcount() 1214514Speter { 1229608Speter register char *selfpc; /* r11 => r5 */ 1239608Speter register unsigned short *frompcindex; /* r10 => r4 */ 1249608Speter register struct tostruct *top; /* r9 => r3 */ 1259608Speter register struct tostruct *prevtop; /* r8 => r2 */ 1269608Speter register long toindex; /* r7 => r1 */ 1274514Speter 1284514Speter #ifdef lint 1299608Speter selfpc = (char *)0; 1309608Speter frompcindex = 0; 1314514Speter #else not lint 1324514Speter /* 1334540Speter * find the return address for mcount, 1344540Speter * and the return address for mcount's caller. 1354514Speter */ 1369608Speter asm(" .text"); /* make sure we're in text space */ 1379608Speter asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ 1389608Speter asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ 1394514Speter #endif not lint 1404540Speter /* 1414540Speter * check that we are profiling 1424564Speter * and that we aren't recursively invoked. 1434540Speter */ 1449608Speter if (profiling) { 1459608Speter goto out; 1469608Speter } 14710279Smckusick profiling++; 1484540Speter /* 1494540Speter * check that frompcindex is a reasonable pc value. 1504540Speter * for example: signal catchers get called from the stack, 1514540Speter * not from text space. too bad. 1524540Speter */ 1539608Speter frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc); 1549608Speter if ((unsigned long)frompcindex > s_textsize) { 1559608Speter goto done; 1564514Speter } 1579608Speter frompcindex = 15810268Smckusick &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))]; 1599608Speter toindex = *frompcindex; 1609608Speter if (toindex == 0) { 1619608Speter /* 1629608Speter * first time traversing this arc 1639608Speter */ 1649608Speter toindex = ++tos[0].link; 1659608Speter if (toindex >= tolimit) { 1669608Speter goto overflow; 1679608Speter } 1689608Speter *frompcindex = toindex; 1699608Speter top = &tos[toindex]; 1709608Speter top->selfpc = selfpc; 1719608Speter top->count = 1; 1729608Speter top->link = 0; 1739608Speter goto done; 1744514Speter } 1759608Speter top = &tos[toindex]; 1769608Speter if (top->selfpc == selfpc) { 1779608Speter /* 1789608Speter * arc at front of chain; usual case. 1799608Speter */ 1809608Speter top->count++; 1819608Speter goto done; 1824514Speter } 1839608Speter /* 1849608Speter * have to go looking down chain for it. 1859608Speter * top points to what we are looking at, 1869608Speter * prevtop points to previous top. 1879608Speter * we know it is not at the head of the chain. 1889608Speter */ 1899608Speter for (; /* goto done */; ) { 1909608Speter if (top->link == 0) { 1919608Speter /* 1929608Speter * top is end of the chain and none of the chain 1939608Speter * had top->selfpc == selfpc. 1949608Speter * so we allocate a new tostruct 1959608Speter * and link it to the head of the chain. 1969608Speter */ 1979608Speter toindex = ++tos[0].link; 1989608Speter if (toindex >= tolimit) { 1999608Speter goto overflow; 2009608Speter } 2019608Speter top = &tos[toindex]; 2029608Speter top->selfpc = selfpc; 2039608Speter top->count = 1; 2049608Speter top->link = *frompcindex; 2059608Speter *frompcindex = toindex; 2069608Speter goto done; 2079608Speter } 2089608Speter /* 2099608Speter * otherwise, check the next arc on the chain. 2109608Speter */ 2119608Speter prevtop = top; 2129608Speter top = &tos[top->link]; 2139608Speter if (top->selfpc == selfpc) { 2149608Speter /* 2159608Speter * there it is. 2169608Speter * increment its count 2179608Speter * move it to the head of the chain. 2189608Speter */ 2199608Speter top->count++; 2209608Speter toindex = prevtop->link; 2219608Speter prevtop->link = top->link; 2229608Speter top->link = *frompcindex; 2239608Speter *frompcindex = toindex; 2249608Speter goto done; 2259608Speter } 2269608Speter 2279608Speter } 2284540Speter done: 22910279Smckusick profiling--; 2309608Speter /* and fall through */ 2314514Speter out: 2329608Speter asm(" rsb"); 2334514Speter 2344514Speter overflow: 23510279Smckusick profiling++; /* halt further profiling */ 2364514Speter # define TOLIMIT "mcount: tos overflow\n" 2379608Speter write(2, TOLIMIT, sizeof(TOLIMIT)); 2389608Speter goto out; 2394514Speter } 2409608Speter asm(".text"); 2419608Speter asm("#the end of mcount()"); 2429608Speter asm(".data"); 2434514Speter 2449433Smckusick /*VARARGS1*/ 2459433Smckusick monitor( lowpc , highpc , buf , bufsiz , nfunc ) 2464564Speter char *lowpc; 2474564Speter char *highpc; 2484564Speter int *buf, bufsiz; 2499433Smckusick int nfunc; /* not used, available for compatability only */ 2504514Speter { 2514564Speter register o; 2524514Speter 2534564Speter if ( lowpc == 0 ) { 254*11796Speter moncontrol(0); 2559433Smckusick _mcleanup(); 2564564Speter return; 2574564Speter } 2584564Speter sbuf = buf; 2594564Speter ssiz = bufsiz; 2604564Speter ( (struct phdr *) buf ) -> lpc = lowpc; 2614564Speter ( (struct phdr *) buf ) -> hpc = highpc; 2624564Speter ( (struct phdr *) buf ) -> ncnt = ssiz; 2634564Speter o = sizeof(struct phdr); 2644564Speter buf = (int *) ( ( (int) buf ) + o ); 2654564Speter bufsiz -= o; 2664564Speter if ( bufsiz <= 0 ) 2674564Speter return; 2685070Smckusic o = ( ( (char *) highpc - (char *) lowpc) ); 2694564Speter if( bufsiz < o ) 2705070Smckusic o = ( (float) bufsiz / o ) * 65536; 2714564Speter else 2725070Smckusic o = 65536; 273*11796Speter s_scale = o; 274*11796Speter moncontrol(1); 2754514Speter } 2766177Smckusick 2776177Smckusick /* 278*11796Speter * Control profiling 279*11796Speter * profiling is what mcount checks to see if 280*11796Speter * all the data structures are ready. 281*11796Speter */ 282*11796Speter moncontrol(mode) 283*11796Speter int mode; 284*11796Speter { 285*11796Speter if (mode) { 286*11796Speter /* start */ 287*11796Speter profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr), 288*11796Speter s_lowpc, s_scale); 289*11796Speter profiling = 0; 290*11796Speter } else { 291*11796Speter /* stop */ 292*11796Speter profil((char *)0, 0, 0, 0); 293*11796Speter profiling = 3; 294*11796Speter } 295*11796Speter } 296*11796Speter 297*11796Speter /* 2986177Smckusick * This is a stub for the "brk" system call, which we want to 2996253Smckusick * catch so that it will not deallocate our data space. 3006253Smckusick * (of which the program is not aware) 3016177Smckusick */ 3026253Smckusick extern char *curbrk; 3036253Smckusick 3046177Smckusick brk(addr) 3056253Smckusick char *addr; 3066177Smckusick { 3076253Smckusick 3086253Smckusick if (addr < minsbrk) 3096253Smckusick addr = minsbrk; 3106253Smckusick asm(" chmk $17"); 3119433Smckusick asm(" jcc 1f"); 3129433Smckusick asm(" jmp cerror"); 3139433Smckusick asm("1:"); 3146253Smckusick curbrk = addr; 3156253Smckusick return (0); 3166177Smckusick } 317