1 static char *sccsid = "@(#)gmon.c 4.4 (Berkeley) 05/19/82"; 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 int r11; /* init needs r11 */ 52 register struct kframe *kfp; /* r10 */ 53 register char **targv; 54 register char **argv; 55 56 #ifdef lint 57 kfp = 0; 58 #else not lint 59 asm( " movl sp,r10" ); /* catch it quick */ 60 #endif not lint 61 for ( argv = targv = &kfp -> kargv[0] ; *targv++ ; /* void */ ) 62 /* VOID */ ; 63 if ( targv >= (char **) ( *argv ) ) 64 --targv; 65 environ = targv; 66 asm("_eprol:"); 67 _mstartup( &eprol , &etext ); 68 exit( main( kfp -> kargc , argv , environ ) ); 69 } 70 asm( "#undef _start" ); 71 asm( "#undef _eprol" ); 72 73 exit( code ) 74 /* ARGSUSED */ 75 register int code; /* r11 */ 76 { 77 78 _mcleanup(); 79 _cleanup(); 80 asm( " movl r11, r0" ); 81 asm( " chmk $1" ); 82 } 83 84 /* 85 * froms is actually a bunch of unsigned shorts indexing tos 86 */ 87 static unsigned short *froms; 88 static struct tostruct *tos = 0; 89 static unsigned short tolimit = 0; 90 static char *s_lowpc = 0; 91 static char *s_highpc = 0; 92 static unsigned long s_textsize = 0; 93 static char *minsbrk = 0; 94 95 static int ssiz; 96 static int *sbuf; 97 98 #define MSG "No space for monitor buffer(s)\n" 99 100 _mstartup(lowpc, highpc) 101 char *lowpc; 102 char *highpc; 103 { 104 int monsize; 105 char *buffer; 106 char *sbrk(); 107 unsigned long limit; 108 109 s_lowpc = lowpc; 110 s_highpc = highpc; 111 s_textsize = highpc - lowpc; 112 monsize = s_textsize + sizeof(struct phdr); 113 buffer = sbrk( monsize ); 114 if ( buffer == (char *) -1 ) { 115 write( 2 , MSG , sizeof(MSG) ); 116 return; 117 } 118 froms = (unsigned short *) sbrk( s_textsize ); 119 if ( froms == (unsigned short *) -1 ) { 120 write( 2 , MSG , sizeof(MSG) ); 121 froms = 0; 122 return; 123 } 124 tos = (struct tostruct *) sbrk(s_textsize); 125 if ( tos == (struct tostruct *) -1 ) { 126 write( 2 , MSG , sizeof(MSG) ); 127 froms = 0; 128 tos = 0; 129 return; 130 } 131 tos[0].link = 0; 132 limit = s_textsize / sizeof(struct tostruct); 133 /* 134 * tolimit is what mcount checks to see if 135 * all the data structures are ready!!! 136 * make sure it won't overflow. 137 */ 138 tolimit = limit > 65534 ? 65534 : limit; 139 monitor( lowpc , highpc , buffer , monsize ); 140 } 141 142 _mcleanup() 143 { 144 int fd; 145 int fromindex; 146 char *frompc; 147 int toindex; 148 struct rawarc rawarc; 149 150 monitor( (int (*)()) 0 ); 151 fd = creat( "gmon.out" , 0666 ); 152 if ( fd < 0 ) { 153 perror( "mcount: gmon.out" ); 154 return; 155 } 156 # ifdef DEBUG 157 fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); 158 # endif DEBUG 159 write( fd , sbuf , ssiz ); 160 for ( fromindex = 0 ; fromindex < s_textsize>>1 ; fromindex++ ) { 161 if ( froms[fromindex] == 0 ) { 162 continue; 163 } 164 frompc = s_lowpc + (fromindex<<1); 165 for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 166 # ifdef DEBUG 167 fprintf( stderr , 168 "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 169 frompc , tos[toindex].selfpc , tos[toindex].count ); 170 # endif DEBUG 171 rawarc.raw_frompc = (unsigned long) frompc; 172 rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; 173 rawarc.raw_count = tos[toindex].count; 174 write( fd , &rawarc , sizeof rawarc ); 175 } 176 } 177 close( fd ); 178 } 179 180 /* 181 * This routine is massaged so that it may be jsb'ed to 182 */ 183 asm("#define _mcount mcount"); 184 mcount() 185 { 186 register char *selfpc; /* r11 */ 187 register unsigned short *frompcindex; /* r10 */ 188 register struct tostruct *top; /* r9 */ 189 static int profiling = 0; 190 191 asm( " forgot to run ex script on gcrt0.s" ); 192 asm( "#define r11 r5" ); 193 asm( "#define r10 r4" ); 194 asm( "#define r9 r3" ); 195 #ifdef lint 196 selfpc = (char *) 0; 197 frompcindex = 0; 198 #else not lint 199 /* 200 * find the return address for mcount, 201 * and the return address for mcount's caller. 202 */ 203 asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ 204 asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ 205 #endif not lint 206 /* 207 * check that we are profiling 208 * and that we aren't recursively invoked. 209 */ 210 if ( tolimit == 0 ) { 211 goto out; 212 } 213 if ( profiling ) { 214 goto out; 215 } 216 profiling = 1; 217 /* 218 * check that frompcindex is a reasonable pc value. 219 * for example: signal catchers get called from the stack, 220 * not from text space. too bad. 221 */ 222 frompcindex = (unsigned short *) ( (long) frompcindex - (long) s_lowpc ); 223 if ( (unsigned long) frompcindex > s_textsize ) { 224 goto done; 225 } 226 frompcindex = &froms[ ( (long) frompcindex ) >> 1 ]; 227 if ( *frompcindex == 0 ) { 228 *frompcindex = ++tos[0].link; 229 if ( *frompcindex >= tolimit ) { 230 goto overflow; 231 } 232 top = &tos[ *frompcindex ]; 233 top->selfpc = selfpc; 234 top->count = 0; 235 top->link = 0; 236 } else { 237 top = &tos[ *frompcindex ]; 238 } 239 for ( ; /* goto done */ ; top = &tos[ top -> link ] ) { 240 if ( top -> selfpc == selfpc ) { 241 top -> count++; 242 goto done; 243 } 244 if ( top -> link == 0 ) { 245 top -> link = ++tos[0].link; 246 if ( top -> link >= tolimit ) 247 goto overflow; 248 top = &tos[ top -> link ]; 249 top -> selfpc = selfpc; 250 top -> count = 1; 251 top -> link = 0; 252 goto done; 253 } 254 } 255 done: 256 profiling = 0; 257 /* and fall through */ 258 out: 259 asm( " rsb" ); 260 asm( "#undef r11" ); 261 asm( "#undef r10" ); 262 asm( "#undef r9" ); 263 asm( "#undef _mcount"); 264 265 overflow: 266 tolimit = 0; 267 # define TOLIMIT "mcount: tos overflow\n" 268 write( 2 , TOLIMIT , sizeof( TOLIMIT ) ); 269 goto out; 270 } 271 272 monitor( lowpc , highpc , buf , bufsiz ) 273 char *lowpc; 274 /* VARARGS1 */ 275 char *highpc; 276 int *buf, bufsiz; 277 { 278 register o; 279 280 if ( lowpc == 0 ) { 281 profil( (char *) 0 , 0 , 0 , 0 ); 282 return; 283 } 284 sbuf = buf; 285 ssiz = bufsiz; 286 ( (struct phdr *) buf ) -> lpc = lowpc; 287 ( (struct phdr *) buf ) -> hpc = highpc; 288 ( (struct phdr *) buf ) -> ncnt = ssiz; 289 o = sizeof(struct phdr); 290 buf = (int *) ( ( (int) buf ) + o ); 291 bufsiz -= o; 292 if ( bufsiz <= 0 ) 293 return; 294 o = ( ( (char *) highpc - (char *) lowpc) ); 295 if( bufsiz < o ) 296 o = ( (float) bufsiz / o ) * 65536; 297 else 298 o = 65536; 299 profil( buf , bufsiz , lowpc , o ); 300 } 301 302 /* 303 * This is a stub for the "brk" system call, which we want to 304 * catch so that it will not deallocate our data space. 305 * (of which the program is not aware) 306 */ 307 asm("#define _curbrk curbrk"); 308 extern char *curbrk; 309 310 brk(addr) 311 char *addr; 312 { 313 314 if (addr < minsbrk) 315 addr = minsbrk; 316 asm(" chmk $17"); 317 asm(" jcs cerror"); 318 curbrk = addr; 319 return (0); 320 } 321