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