1 static char *sccsid = "@(#)gmon.c 1.4 (Berkeley) 11/06/81"; 2 3 #include <stdio.h> 4 5 #include "gmcrt0.h" 6 7 /* 8 * C start up routines, for monitoring 9 * Robert Henry, UCB, 20 Oct 81 10 * 11 * We make the following (true) assumptions: 12 * 1) when the kernel calls start, it does a jump to location 2, 13 * and thus avoids the register save mask. We are NOT called 14 * with a calls! see sys1.c:setregs(). 15 * 2) The only register variable that we can trust is sp, 16 * which points to the base of the kernel calling frame. 17 * Do NOT believe the documentation in exec(2) regarding the 18 * values of fp and ap. 19 * 3) We can allocate as many register variables as we want, 20 * and don't have to save them for anybody. 21 * 4) Because of the ways that asm's work, we can't have 22 * any automatic variables allocated on the stack, because 23 * we must catch the value of sp before any automatics are 24 * allocated. 25 */ 26 27 char **environ; 28 extern unsigned char etext; 29 asm( "#define _eprol eprol" ); 30 extern unsigned char eprol; 31 32 asm( "#define _start start" ); 33 start() 34 { 35 struct kframe { 36 int kargc; 37 char *kargv[1]; /* size depends on kargc */ 38 char kargstr[1]; /* size varies */ 39 char kenvstr[1]; /* size varies */ 40 }; 41 /* 42 * ALL REGISTER VARIABLES!!! 43 */ 44 register struct kframe *kfp; /* r11 */ 45 register char **targv; 46 register char **argv; 47 48 #ifdef lint 49 kfp = 0; 50 #else not lint 51 asm( " movl sp,r11" ); /* catch it quick */ 52 #endif not lint 53 for ( argv = targv = &kfp -> kargv[0] ; *targv++ ; /* void */ ) 54 /* VOID */ ; 55 if ( targv >= (char **) ( *argv ) ) 56 --targv; 57 environ = targv; 58 asm("eprol:"); 59 _mstartup( &eprol , &etext ); 60 exit( main( kfp -> kargc , argv , environ ) ); 61 } 62 asm( "#undef _start" ); 63 asm( "#undef _eprol" ); 64 65 exit( code ) 66 /* ARGSUSED */ 67 register int code; /* r11 */ 68 { 69 70 fflush( stdout ); 71 _mcleanup(); 72 _cleanup(); 73 asm( " movl r11, r0" ); 74 asm( " chmk $1" ); 75 } 76 77 /* 78 * froms is actually a bunch of unsigned shorts indexing tos 79 */ 80 static unsigned short *froms; 81 static struct tostruct *tos = 0; 82 static unsigned short tolimit = 0; 83 static char *s_lowpc = 0; 84 static char *s_highpc = 0; 85 86 static int ssiz; 87 static int *sbuf; 88 89 #define MSG "No space for monitor buffer(s)\n" 90 91 _mstartup(lowpc, highpc) 92 char *lowpc; 93 char *highpc; 94 { 95 int monsize; 96 char *buffer; 97 int textsize; 98 char *sbrk(); 99 100 s_lowpc = lowpc; 101 s_highpc = highpc; 102 textsize = ( (char *) highpc - (char *) lowpc ); 103 monsize = textsize + sizeof(struct phdr); 104 buffer = sbrk( monsize ); 105 if ( buffer == (char *) -1 ) { 106 write( 2 , MSG , sizeof(MSG) ); 107 return; 108 } 109 froms = (unsigned short *) sbrk( textsize ); 110 if ( froms == (unsigned short *) -1 ) { 111 write( 2 , MSG , sizeof(MSG) ); 112 froms = 0; 113 return; 114 } 115 tos = (struct tostruct *) sbrk(textsize); 116 if ( tos == (struct tostruct *) -1 ) { 117 write( 2 , MSG , sizeof(MSG) ); 118 froms = 0; 119 tos = 0; 120 return; 121 } 122 tolimit = textsize / sizeof(struct tostruct); 123 tos[0].link = 0; 124 monitor( lowpc , highpc , buffer , monsize ); 125 } 126 127 _mcleanup() 128 { 129 FILE *fd; 130 int fromindex; 131 char *frompc; 132 int toindex; 133 int textsize; 134 135 monitor( (int (*)()) 0 ); 136 fd = fopen( "gmon.out" , "w" ); 137 if ( fd == NULL ) { 138 perror( "mcount: gmon.out" ); 139 return; 140 } 141 # ifdef DEBUG 142 fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); 143 # endif DEBUG 144 fwrite( sbuf , 1 , ssiz , fd ); 145 textsize = s_highpc - s_lowpc; 146 for ( fromindex = 0 ; fromindex < textsize>>1 ; fromindex++ ) { 147 if ( froms[fromindex] == 0 ) { 148 continue; 149 } 150 frompc = s_lowpc + (fromindex<<1); 151 for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 152 # ifdef DEBUG 153 fprintf( stderr , 154 "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 155 frompc , tos[toindex].selfpc , tos[toindex].count ); 156 # endif DEBUG 157 fwrite( &frompc, 1, sizeof frompc, fd ); 158 fwrite( &tos[toindex].selfpc, 1, sizeof tos[toindex].selfpc, fd ); 159 fwrite( &tos[toindex].count, 1, sizeof tos[toindex].count, fd ); 160 } 161 } 162 fclose( fd ); 163 } 164 165 /* 166 * This routine is massaged so that it may be jsb'ed to 167 */ 168 asm("#define _mcount mcount"); 169 mcount() 170 { 171 register char *selfpc; /* r11 */ 172 register unsigned short *frompcindex; /* r10 */ 173 register struct tostruct *top; /* r9 */ 174 static int profiling = 0; 175 176 asm( " forgot to run ex script on gmcrt0.s" ); 177 asm( "#define r11 r5" ); 178 asm( "#define r10 r4" ); 179 asm( "#define r9 r3" ); 180 #ifdef lint 181 selfpc = (char *) 0; 182 frompcindex = 0; 183 #else not lint 184 /* 185 * find the return address for mcount, 186 * and the return address for mcount's caller. 187 */ 188 asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ 189 asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ 190 #endif not lint 191 /* 192 * check that we are profiling 193 * and that we aren't recursively invoked. 194 */ 195 if ( tos == 0 ) { 196 goto out; 197 } 198 if ( profiling ) { 199 goto out; 200 } 201 profiling = 1; 202 /* 203 * check that frompcindex is a reasonable pc value. 204 * for example: signal catchers get called from the stack, 205 * not from text space. too bad. 206 */ 207 if ( (char *) frompcindex < s_lowpc || (char *) frompcindex > s_highpc ) { 208 goto done; 209 } 210 frompcindex = &froms[ ( (long) frompcindex - (long) s_lowpc ) >> 1 ]; 211 if ( *frompcindex == 0 ) { 212 *frompcindex = ++tos[0].link; 213 if ( *frompcindex >= tolimit ) { 214 goto overflow; 215 } 216 top = &tos[ *frompcindex ]; 217 top->selfpc = selfpc; 218 top->count = 0; 219 top->link = 0; 220 } else { 221 top = &tos[ *frompcindex ]; 222 } 223 for ( ; /* goto done */ ; top = &tos[ top -> link ] ) { 224 if ( top -> selfpc == selfpc ) { 225 top -> count++; 226 goto done; 227 } 228 if ( top -> link == 0 ) { 229 top -> link = ++tos[0].link; 230 if ( top -> link >= tolimit ) 231 goto overflow; 232 top = &tos[ top -> link ]; 233 top -> selfpc = selfpc; 234 top -> count = 1; 235 top -> link = 0; 236 goto done; 237 } 238 } 239 done: 240 profiling = 0; 241 /* and fall through */ 242 out: 243 asm( " rsb" ); 244 asm( "#undef r11" ); 245 asm( "#undef r10" ); 246 asm( "#undef r9" ); 247 asm( "#undef _mcount"); 248 249 overflow: 250 # define TOLIMIT "mcount: tos overflow\n" 251 write( 2 , TOLIMIT , sizeof( TOLIMIT ) ); 252 tos = 0; 253 froms = 0; 254 goto out; 255 } 256 257 monitor( lowpc , highpc , buf , bufsiz ) 258 char *lowpc; 259 /* VARARGS1 */ 260 char *highpc; 261 int *buf, bufsiz; 262 { 263 register o; 264 265 if ( lowpc == 0 ) { 266 profil( (char *) 0 , 0 , 0 , 0 ); 267 return; 268 } 269 sbuf = buf; 270 ssiz = bufsiz; 271 ( (struct phdr *) buf ) -> lpc = lowpc; 272 ( (struct phdr *) buf ) -> hpc = highpc; 273 ( (struct phdr *) buf ) -> ncnt = ssiz; 274 o = sizeof(struct phdr); 275 buf = (int *) ( ( (int) buf ) + o ); 276 bufsiz -= o; 277 if ( bufsiz <= 0 ) 278 return; 279 o = ( ( (char *) highpc - (char *) lowpc) >> 1 ); 280 if( bufsiz < o ) 281 o = ( (float) bufsiz / o ) * 32768; 282 else 283 o = 0177777; 284 profil( buf , bufsiz , lowpc , o ); 285 } 286