1*21415Sdist /* 2*21415Sdist * Copyright (c) 1980 Regents of the University of California. 3*21415Sdist * All rights reserved. The Berkeley software License Agreement 4*21415Sdist * specifies the terms and conditions for redistribution. 5*21415Sdist */ 64514Speter 7*21415Sdist #ifndef lint 8*21415Sdist static char sccsid[] = "@(#)gmon.c 5.1 (Berkeley) 05/30/85"; 9*21415Sdist #endif not lint 10*21415Sdist 114869Smckusic #ifdef DEBUG 124514Speter #include <stdio.h> 134869Smckusic #endif DEBUG 144514Speter 159433Smckusick #include "gmon.h" 164514Speter 174564Speter /* 184564Speter * froms is actually a bunch of unsigned shorts indexing tos 194564Speter */ 2010279Smckusick static int profiling = 3; 214514Speter static unsigned short *froms; 224514Speter static struct tostruct *tos = 0; 239608Speter static long tolimit = 0; 244514Speter static char *s_lowpc = 0; 254514Speter static char *s_highpc = 0; 264850Speter static unsigned long s_textsize = 0; 274514Speter 284564Speter static int ssiz; 2911998Speter static char *sbuf; 3011796Speter static int s_scale; 3111998Speter /* see profil(2) where this is describe (incorrectly) */ 3211998Speter #define SCALE_1_TO_1 0x10000L 334514Speter 344514Speter #define MSG "No space for monitor buffer(s)\n" 354514Speter 369433Smckusick monstartup(lowpc, highpc) 374564Speter char *lowpc; 384564Speter char *highpc; 394514Speter { 404850Speter int monsize; 414850Speter char *buffer; 424850Speter char *sbrk(); 4314127Smckusick extern char *minbrk; 444514Speter 459608Speter /* 469608Speter * round lowpc and highpc to multiples of the density we're using 479608Speter * so the rest of the scaling (here and in gprof) stays in ints. 489608Speter */ 499608Speter lowpc = (char *) 509608Speter ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); 514564Speter s_lowpc = lowpc; 529608Speter highpc = (char *) 539608Speter ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER)); 544564Speter s_highpc = highpc; 554850Speter s_textsize = highpc - lowpc; 569608Speter monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr); 574564Speter buffer = sbrk( monsize ); 584564Speter if ( buffer == (char *) -1 ) { 594564Speter write( 2 , MSG , sizeof(MSG) ); 604564Speter return; 614564Speter } 6210268Smckusick froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION ); 634564Speter if ( froms == (unsigned short *) -1 ) { 644564Speter write( 2 , MSG , sizeof(MSG) ); 654564Speter froms = 0; 664564Speter return; 674564Speter } 6810279Smckusick tolimit = s_textsize * ARCDENSITY / 100; 6910279Smckusick if ( tolimit < MINARCS ) { 7010279Smckusick tolimit = MINARCS; 7110279Smckusick } else if ( tolimit > 65534 ) { 7210279Smckusick tolimit = 65534; 739530Smckusick } 7410279Smckusick tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) ); 754564Speter if ( tos == (struct tostruct *) -1 ) { 764564Speter write( 2 , MSG , sizeof(MSG) ); 774564Speter froms = 0; 784564Speter tos = 0; 794564Speter return; 804564Speter } 8114127Smckusick minbrk = sbrk(0); 824564Speter tos[0].link = 0; 8310279Smckusick monitor( lowpc , highpc , buffer , monsize , tolimit ); 844514Speter } 854514Speter 864514Speter _mcleanup() 874514Speter { 884869Smckusic int fd; 894869Smckusic int fromindex; 9010268Smckusick int endfrom; 914869Smckusic char *frompc; 924869Smckusic int toindex; 934869Smckusic struct rawarc rawarc; 944514Speter 954869Smckusic fd = creat( "gmon.out" , 0666 ); 964869Smckusic if ( fd < 0 ) { 974564Speter perror( "mcount: gmon.out" ); 984514Speter return; 994514Speter } 1004564Speter # ifdef DEBUG 1014564Speter fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); 1024564Speter # endif DEBUG 1034869Smckusic write( fd , sbuf , ssiz ); 10410268Smckusick endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); 10510268Smckusick for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { 1064514Speter if ( froms[fromindex] == 0 ) { 1074514Speter continue; 1084514Speter } 10910268Smckusick frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); 1104514Speter for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 1114514Speter # ifdef DEBUG 1124748Speter fprintf( stderr , 1134748Speter "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 1144514Speter frompc , tos[toindex].selfpc , tos[toindex].count ); 1154514Speter # endif DEBUG 1164869Smckusic rawarc.raw_frompc = (unsigned long) frompc; 1174869Smckusic rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; 1184869Smckusic rawarc.raw_count = tos[toindex].count; 1194869Smckusic write( fd , &rawarc , sizeof rawarc ); 1204514Speter } 1214514Speter } 1224869Smckusic close( fd ); 1234514Speter } 1244514Speter 1259608Speter asm(".text"); 12611796Speter asm(".align 2"); 1279608Speter asm("#the beginning of mcount()"); 1289608Speter asm(".data"); 1294514Speter mcount() 1304514Speter { 1319608Speter register char *selfpc; /* r11 => r5 */ 1329608Speter register unsigned short *frompcindex; /* r10 => r4 */ 1339608Speter register struct tostruct *top; /* r9 => r3 */ 1349608Speter register struct tostruct *prevtop; /* r8 => r2 */ 1359608Speter register long toindex; /* r7 => r1 */ 1364514Speter 1374514Speter #ifdef lint 1389608Speter selfpc = (char *)0; 1399608Speter frompcindex = 0; 1404514Speter #else not lint 1414514Speter /* 1424540Speter * find the return address for mcount, 1434540Speter * and the return address for mcount's caller. 1444514Speter */ 1459608Speter asm(" .text"); /* make sure we're in text space */ 1469608Speter asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ 1479608Speter asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ 1484514Speter #endif not lint 1494540Speter /* 1504540Speter * check that we are profiling 1514564Speter * and that we aren't recursively invoked. 1524540Speter */ 1539608Speter if (profiling) { 1549608Speter goto out; 1559608Speter } 15610279Smckusick profiling++; 1574540Speter /* 1584540Speter * check that frompcindex is a reasonable pc value. 1594540Speter * for example: signal catchers get called from the stack, 1604540Speter * not from text space. too bad. 1614540Speter */ 1629608Speter frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc); 1639608Speter if ((unsigned long)frompcindex > s_textsize) { 1649608Speter goto done; 1654514Speter } 1669608Speter frompcindex = 16710268Smckusick &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))]; 1689608Speter toindex = *frompcindex; 1699608Speter if (toindex == 0) { 1709608Speter /* 1719608Speter * first time traversing this arc 1729608Speter */ 1739608Speter toindex = ++tos[0].link; 1749608Speter if (toindex >= tolimit) { 1759608Speter goto overflow; 1769608Speter } 1779608Speter *frompcindex = toindex; 1789608Speter top = &tos[toindex]; 1799608Speter top->selfpc = selfpc; 1809608Speter top->count = 1; 1819608Speter top->link = 0; 1829608Speter goto done; 1834514Speter } 1849608Speter top = &tos[toindex]; 1859608Speter if (top->selfpc == selfpc) { 1869608Speter /* 1879608Speter * arc at front of chain; usual case. 1889608Speter */ 1899608Speter top->count++; 1909608Speter goto done; 1914514Speter } 1929608Speter /* 1939608Speter * have to go looking down chain for it. 1949608Speter * top points to what we are looking at, 1959608Speter * prevtop points to previous top. 1969608Speter * we know it is not at the head of the chain. 1979608Speter */ 1989608Speter for (; /* goto done */; ) { 1999608Speter if (top->link == 0) { 2009608Speter /* 2019608Speter * top is end of the chain and none of the chain 2029608Speter * had top->selfpc == selfpc. 2039608Speter * so we allocate a new tostruct 2049608Speter * and link it to the head of the chain. 2059608Speter */ 2069608Speter toindex = ++tos[0].link; 2079608Speter if (toindex >= tolimit) { 2089608Speter goto overflow; 2099608Speter } 2109608Speter top = &tos[toindex]; 2119608Speter top->selfpc = selfpc; 2129608Speter top->count = 1; 2139608Speter top->link = *frompcindex; 2149608Speter *frompcindex = toindex; 2159608Speter goto done; 2169608Speter } 2179608Speter /* 2189608Speter * otherwise, check the next arc on the chain. 2199608Speter */ 2209608Speter prevtop = top; 2219608Speter top = &tos[top->link]; 2229608Speter if (top->selfpc == selfpc) { 2239608Speter /* 2249608Speter * there it is. 2259608Speter * increment its count 2269608Speter * move it to the head of the chain. 2279608Speter */ 2289608Speter top->count++; 2299608Speter toindex = prevtop->link; 2309608Speter prevtop->link = top->link; 2319608Speter top->link = *frompcindex; 2329608Speter *frompcindex = toindex; 2339608Speter goto done; 2349608Speter } 2359608Speter 2369608Speter } 2374540Speter done: 23810279Smckusick profiling--; 2399608Speter /* and fall through */ 2404514Speter out: 2419608Speter asm(" rsb"); 2424514Speter 2434514Speter overflow: 24410279Smckusick profiling++; /* halt further profiling */ 2454514Speter # define TOLIMIT "mcount: tos overflow\n" 2469608Speter write(2, TOLIMIT, sizeof(TOLIMIT)); 2479608Speter goto out; 2484514Speter } 2499608Speter asm(".text"); 2509608Speter asm("#the end of mcount()"); 2519608Speter asm(".data"); 2524514Speter 2539433Smckusick /*VARARGS1*/ 2549433Smckusick monitor( lowpc , highpc , buf , bufsiz , nfunc ) 2554564Speter char *lowpc; 2564564Speter char *highpc; 25711998Speter char *buf; /* declared ``short buffer[]'' in monitor(3) */ 25811998Speter int bufsiz; 2599433Smckusick int nfunc; /* not used, available for compatability only */ 2604514Speter { 2614564Speter register o; 2624514Speter 2634564Speter if ( lowpc == 0 ) { 26411796Speter moncontrol(0); 2659433Smckusick _mcleanup(); 2664564Speter return; 2674564Speter } 2684564Speter sbuf = buf; 2694564Speter ssiz = bufsiz; 2704564Speter ( (struct phdr *) buf ) -> lpc = lowpc; 2714564Speter ( (struct phdr *) buf ) -> hpc = highpc; 2724564Speter ( (struct phdr *) buf ) -> ncnt = ssiz; 27311998Speter bufsiz -= sizeof(struct phdr); 2744564Speter if ( bufsiz <= 0 ) 2754564Speter return; 27611998Speter o = highpc - lowpc; 2774564Speter if( bufsiz < o ) 27811998Speter s_scale = ( (float) bufsiz / o ) * SCALE_1_TO_1; 2794564Speter else 28011998Speter s_scale = SCALE_1_TO_1; 28111796Speter moncontrol(1); 2824514Speter } 2836177Smckusick 2846177Smckusick /* 28511796Speter * Control profiling 28611796Speter * profiling is what mcount checks to see if 28711796Speter * all the data structures are ready. 28811796Speter */ 28911796Speter moncontrol(mode) 29011796Speter int mode; 29111796Speter { 29211796Speter if (mode) { 29311796Speter /* start */ 29411796Speter profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr), 29511796Speter s_lowpc, s_scale); 29611796Speter profiling = 0; 29711796Speter } else { 29811796Speter /* stop */ 29911796Speter profil((char *)0, 0, 0, 0); 30011796Speter profiling = 3; 30111796Speter } 30211796Speter } 303