121415Sdist /* 221415Sdist * Copyright (c) 1980 Regents of the University of California. 321415Sdist * All rights reserved. The Berkeley software License Agreement 421415Sdist * specifies the terms and conditions for redistribution. 521415Sdist */ 64514Speter 726667Sdonn #if defined(LIBC_SCCS) && !defined(lint) 8*32074Smckusick static char sccsid[] = "@(#)gmon.c 5.4 (Berkeley) 08/27/87"; 926667Sdonn #endif LIBC_SCCS and not lint 1021415Sdist 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 ) { 59*32074Smckusick write( 2 , MSG , sizeof(MSG) - 1 ); 604564Speter return; 614564Speter } 6210268Smckusick froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION ); 634564Speter if ( froms == (unsigned short *) -1 ) { 64*32074Smckusick write( 2 , MSG , sizeof(MSG) - 1 ); 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 ) { 76*32074Smckusick write( 2 , MSG , sizeof(MSG) - 1 ); 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 /* 1384540Speter * find the return address for mcount, 1394540Speter * and the return address for mcount's caller. 1404514Speter */ 1419608Speter asm(" .text"); /* make sure we're in text space */ 1429608Speter asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ 1439608Speter asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ 1444540Speter /* 1454540Speter * check that we are profiling 1464564Speter * and that we aren't recursively invoked. 1474540Speter */ 1489608Speter if (profiling) { 1499608Speter goto out; 1509608Speter } 15110279Smckusick profiling++; 1524540Speter /* 1534540Speter * check that frompcindex is a reasonable pc value. 1544540Speter * for example: signal catchers get called from the stack, 1554540Speter * not from text space. too bad. 1564540Speter */ 1579608Speter frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc); 1589608Speter if ((unsigned long)frompcindex > s_textsize) { 1599608Speter goto done; 1604514Speter } 1619608Speter frompcindex = 16210268Smckusick &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))]; 1639608Speter toindex = *frompcindex; 1649608Speter if (toindex == 0) { 1659608Speter /* 1669608Speter * first time traversing this arc 1679608Speter */ 1689608Speter toindex = ++tos[0].link; 1699608Speter if (toindex >= tolimit) { 1709608Speter goto overflow; 1719608Speter } 1729608Speter *frompcindex = toindex; 1739608Speter top = &tos[toindex]; 1749608Speter top->selfpc = selfpc; 1759608Speter top->count = 1; 1769608Speter top->link = 0; 1779608Speter goto done; 1784514Speter } 1799608Speter top = &tos[toindex]; 1809608Speter if (top->selfpc == selfpc) { 1819608Speter /* 1829608Speter * arc at front of chain; usual case. 1839608Speter */ 1849608Speter top->count++; 1859608Speter goto done; 1864514Speter } 1879608Speter /* 1889608Speter * have to go looking down chain for it. 1899608Speter * top points to what we are looking at, 1909608Speter * prevtop points to previous top. 1919608Speter * we know it is not at the head of the chain. 1929608Speter */ 1939608Speter for (; /* goto done */; ) { 1949608Speter if (top->link == 0) { 1959608Speter /* 1969608Speter * top is end of the chain and none of the chain 1979608Speter * had top->selfpc == selfpc. 1989608Speter * so we allocate a new tostruct 1999608Speter * and link it to the head of the chain. 2009608Speter */ 2019608Speter toindex = ++tos[0].link; 2029608Speter if (toindex >= tolimit) { 2039608Speter goto overflow; 2049608Speter } 2059608Speter top = &tos[toindex]; 2069608Speter top->selfpc = selfpc; 2079608Speter top->count = 1; 2089608Speter top->link = *frompcindex; 2099608Speter *frompcindex = toindex; 2109608Speter goto done; 2119608Speter } 2129608Speter /* 2139608Speter * otherwise, check the next arc on the chain. 2149608Speter */ 2159608Speter prevtop = top; 2169608Speter top = &tos[top->link]; 2179608Speter if (top->selfpc == selfpc) { 2189608Speter /* 2199608Speter * there it is. 2209608Speter * increment its count 2219608Speter * move it to the head of the chain. 2229608Speter */ 2239608Speter top->count++; 2249608Speter toindex = prevtop->link; 2259608Speter prevtop->link = top->link; 2269608Speter top->link = *frompcindex; 2279608Speter *frompcindex = toindex; 2289608Speter goto done; 2299608Speter } 2309608Speter 2319608Speter } 2324540Speter done: 23310279Smckusick profiling--; 2349608Speter /* and fall through */ 2354514Speter out: 2369608Speter asm(" rsb"); 2374514Speter 2384514Speter overflow: 23910279Smckusick profiling++; /* halt further profiling */ 2404514Speter # define TOLIMIT "mcount: tos overflow\n" 241*32074Smckusick write(2, TOLIMIT, sizeof(TOLIMIT) - 1); 2429608Speter goto out; 2434514Speter } 2449608Speter asm(".text"); 2459608Speter asm("#the end of mcount()"); 2469608Speter asm(".data"); 2474514Speter 2489433Smckusick /*VARARGS1*/ 2499433Smckusick monitor( lowpc , highpc , buf , bufsiz , nfunc ) 2504564Speter char *lowpc; 2514564Speter char *highpc; 25211998Speter char *buf; /* declared ``short buffer[]'' in monitor(3) */ 25311998Speter int bufsiz; 2549433Smckusick int nfunc; /* not used, available for compatability only */ 2554514Speter { 2564564Speter register o; 2574514Speter 2584564Speter if ( lowpc == 0 ) { 25911796Speter moncontrol(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; 26811998Speter bufsiz -= sizeof(struct phdr); 2694564Speter if ( bufsiz <= 0 ) 2704564Speter return; 27111998Speter o = highpc - lowpc; 2724564Speter if( bufsiz < o ) 27311998Speter s_scale = ( (float) bufsiz / o ) * SCALE_1_TO_1; 2744564Speter else 27511998Speter s_scale = SCALE_1_TO_1; 27611796Speter moncontrol(1); 2774514Speter } 2786177Smckusick 2796177Smckusick /* 28011796Speter * Control profiling 28111796Speter * profiling is what mcount checks to see if 28211796Speter * all the data structures are ready. 28311796Speter */ 28411796Speter moncontrol(mode) 28511796Speter int mode; 28611796Speter { 28711796Speter if (mode) { 28811796Speter /* start */ 28911796Speter profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr), 29011796Speter s_lowpc, s_scale); 29111796Speter profiling = 0; 29211796Speter } else { 29311796Speter /* stop */ 29411796Speter profil((char *)0, 0, 0, 0); 29511796Speter profiling = 3; 29611796Speter } 29711796Speter } 298