1 static char *sccsid = "@(#)gmon.c 1.6 (Berkeley) 11/10/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 /* 29 * etext is added by the loader, and is the end of the text space. 30 * eprol is a local symbol, and labels almost the beginning of text space. 31 * its name is changed so it doesn't look like a function. 32 */ 33 extern unsigned char etext; 34 extern unsigned char eprol; 35 asm( "#define _eprol _$eprol" ); 36 37 asm( "#define _start start" ); 38 start() 39 { 40 struct kframe { 41 int kargc; 42 char *kargv[1]; /* size depends on kargc */ 43 char kargstr[1]; /* size varies */ 44 char kenvstr[1]; /* size varies */ 45 }; 46 /* 47 * ALL REGISTER VARIABLES!!! 48 */ 49 register struct kframe *kfp; /* r11 */ 50 register char **targv; 51 register char **argv; 52 53 #ifdef lint 54 kfp = 0; 55 #else not lint 56 asm( " movl sp,r11" ); /* catch it quick */ 57 #endif not lint 58 for ( argv = targv = &kfp -> kargv[0] ; *targv++ ; /* void */ ) 59 /* VOID */ ; 60 if ( targv >= (char **) ( *argv ) ) 61 --targv; 62 environ = targv; 63 asm("_eprol:"); 64 _mstartup( &eprol , &etext ); 65 exit( main( kfp -> kargc , argv , environ ) ); 66 } 67 asm( "#undef _start" ); 68 asm( "#undef _eprol" ); 69 70 exit( code ) 71 /* ARGSUSED */ 72 register int code; /* r11 */ 73 { 74 75 fflush( stdout ); 76 _mcleanup(); 77 _cleanup(); 78 asm( " movl r11, r0" ); 79 asm( " chmk $1" ); 80 } 81 82 /* 83 * froms is actually a bunch of unsigned shorts indexing tos 84 */ 85 static unsigned short *froms; 86 static struct tostruct *tos = 0; 87 static unsigned short tolimit = 0; 88 static char *s_lowpc = 0; 89 static char *s_highpc = 0; 90 static unsigned long s_textsize = 0; 91 92 static int ssiz; 93 static int *sbuf; 94 95 #define MSG "No space for monitor buffer(s)\n" 96 97 _mstartup(lowpc, highpc) 98 char *lowpc; 99 char *highpc; 100 { 101 int monsize; 102 char *buffer; 103 char *sbrk(); 104 unsigned long limit; 105 106 s_lowpc = lowpc; 107 s_highpc = highpc; 108 s_textsize = highpc - lowpc; 109 monsize = s_textsize + sizeof(struct phdr); 110 buffer = sbrk( monsize ); 111 if ( buffer == (char *) -1 ) { 112 write( 2 , MSG , sizeof(MSG) ); 113 return; 114 } 115 froms = (unsigned short *) sbrk( s_textsize ); 116 if ( froms == (unsigned short *) -1 ) { 117 write( 2 , MSG , sizeof(MSG) ); 118 froms = 0; 119 return; 120 } 121 tos = (struct tostruct *) sbrk(s_textsize); 122 if ( tos == (struct tostruct *) -1 ) { 123 write( 2 , MSG , sizeof(MSG) ); 124 froms = 0; 125 tos = 0; 126 return; 127 } 128 tos[0].link = 0; 129 limit = s_textsize / sizeof(struct tostruct); 130 /* 131 * tolimit is what mcount checks to see if 132 * all the data structures are ready!!! 133 * make sure it won't overflow. 134 */ 135 tolimit = limit > 65534 ? 65534 : limit; 136 monitor( lowpc , highpc , buffer , monsize ); 137 } 138 139 _mcleanup() 140 { 141 FILE *fd; 142 int fromindex; 143 char *frompc; 144 int toindex; 145 146 monitor( (int (*)()) 0 ); 147 fd = fopen( "gmon.out" , "w" ); 148 if ( fd == NULL ) { 149 perror( "mcount: gmon.out" ); 150 return; 151 } 152 # ifdef DEBUG 153 fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); 154 # endif DEBUG 155 fwrite( sbuf , 1 , ssiz , fd ); 156 for ( fromindex = 0 ; fromindex < s_textsize>>1 ; fromindex++ ) { 157 if ( froms[fromindex] == 0 ) { 158 continue; 159 } 160 frompc = s_lowpc + (fromindex<<1); 161 for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 162 # ifdef DEBUG 163 fprintf( stderr , 164 "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 165 frompc , tos[toindex].selfpc , tos[toindex].count ); 166 # endif DEBUG 167 fwrite( &frompc, 1, sizeof frompc, fd ); 168 fwrite( &tos[toindex].selfpc, 1, sizeof tos[toindex].selfpc, fd ); 169 fwrite( &tos[toindex].count, 1, sizeof tos[toindex].count, fd ); 170 } 171 } 172 fclose( fd ); 173 } 174 175 /* 176 * This routine is massaged so that it may be jsb'ed to 177 */ 178 asm("#define _mcount mcount"); 179 mcount() 180 { 181 register char *selfpc; /* r11 */ 182 register unsigned short *frompcindex; /* r10 */ 183 register struct tostruct *top; /* r9 */ 184 static int profiling = 0; 185 186 asm( " forgot to run ex script on gmcrt0.s" ); 187 asm( "#define r11 r5" ); 188 asm( "#define r10 r4" ); 189 asm( "#define r9 r3" ); 190 #ifdef lint 191 selfpc = (char *) 0; 192 frompcindex = 0; 193 #else not lint 194 /* 195 * find the return address for mcount, 196 * and the return address for mcount's caller. 197 */ 198 asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ 199 asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ 200 #endif not lint 201 /* 202 * check that we are profiling 203 * and that we aren't recursively invoked. 204 */ 205 if ( tolimit == 0 ) { 206 goto out; 207 } 208 if ( profiling ) { 209 goto out; 210 } 211 profiling = 1; 212 /* 213 * check that frompcindex is a reasonable pc value. 214 * for example: signal catchers get called from the stack, 215 * not from text space. too bad. 216 */ 217 frompcindex = (unsigned short *) ( (long) frompcindex - (long) s_lowpc ); 218 if ( (unsigned long) frompcindex > s_textsize ) { 219 goto done; 220 } 221 frompcindex = &froms[ ( (long) frompcindex ) >> 1 ]; 222 if ( *frompcindex == 0 ) { 223 *frompcindex = ++tos[0].link; 224 if ( *frompcindex >= tolimit ) { 225 goto overflow; 226 } 227 top = &tos[ *frompcindex ]; 228 top->selfpc = selfpc; 229 top->count = 0; 230 top->link = 0; 231 } else { 232 top = &tos[ *frompcindex ]; 233 } 234 for ( ; /* goto done */ ; top = &tos[ top -> link ] ) { 235 if ( top -> selfpc == selfpc ) { 236 top -> count++; 237 goto done; 238 } 239 if ( top -> link == 0 ) { 240 top -> link = ++tos[0].link; 241 if ( top -> link >= tolimit ) 242 goto overflow; 243 top = &tos[ top -> link ]; 244 top -> selfpc = selfpc; 245 top -> count = 1; 246 top -> link = 0; 247 goto done; 248 } 249 } 250 done: 251 profiling = 0; 252 /* and fall through */ 253 out: 254 asm( " rsb" ); 255 asm( "#undef r11" ); 256 asm( "#undef r10" ); 257 asm( "#undef r9" ); 258 asm( "#undef _mcount"); 259 260 overflow: 261 tolimit = 0; 262 # define TOLIMIT "mcount: tos overflow\n" 263 write( 2 , TOLIMIT , sizeof( TOLIMIT ) ); 264 goto out; 265 } 266 267 monitor( lowpc , highpc , buf , bufsiz ) 268 char *lowpc; 269 /* VARARGS1 */ 270 char *highpc; 271 int *buf, bufsiz; 272 { 273 register o; 274 275 if ( lowpc == 0 ) { 276 profil( (char *) 0 , 0 , 0 , 0 ); 277 return; 278 } 279 sbuf = buf; 280 ssiz = bufsiz; 281 ( (struct phdr *) buf ) -> lpc = lowpc; 282 ( (struct phdr *) buf ) -> hpc = highpc; 283 ( (struct phdr *) buf ) -> ncnt = ssiz; 284 o = sizeof(struct phdr); 285 buf = (int *) ( ( (int) buf ) + o ); 286 bufsiz -= o; 287 if ( bufsiz <= 0 ) 288 return; 289 o = ( ( (char *) highpc - (char *) lowpc) >> 1 ); 290 if( bufsiz < o ) 291 o = ( (float) bufsiz / o ) * 32768; 292 else 293 o = 0177777; 294 profil( buf , bufsiz , lowpc , o ); 295 } 296