1 /* 2 * Copyright (c) 1983 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 static char sccsid[] = "@(#)tahoe.c 1.4 (Berkeley) 06/29/88"; 20 #endif /* not lint */ 21 22 #include "gprof.h" 23 24 /* 25 * a namelist entry to be the child of indirect callf 26 */ 27 nltype indirectchild = { 28 "(*)" , /* the name */ 29 (unsigned long) 0 , /* the pc entry point */ 30 (unsigned long) 0 , /* entry point aligned to histogram */ 31 (double) 0.0 , /* ticks in this routine */ 32 (double) 0.0 , /* cumulative ticks in children */ 33 (long) 0 , /* how many times called */ 34 (long) 0 , /* how many calls to self */ 35 (double) 1.0 , /* propagation fraction */ 36 (double) 0.0 , /* self propagation time */ 37 (double) 0.0 , /* child propagation time */ 38 (bool) 0 , /* print flag */ 39 (int) 0 , /* index in the graph list */ 40 (int) 0 , /* graph call chain top-sort order */ 41 (int) 0 , /* internal number of cycle on */ 42 (struct nl *) &indirectchild , /* pointer to head of cycle */ 43 (struct nl *) 0 , /* pointer to next member of cycle */ 44 (arctype *) 0 , /* list of caller arcs */ 45 (arctype *) 0 /* list of callee arcs */ 46 }; 47 48 operandenum 49 operandmode( modep ) 50 unsigned char *modep; 51 { 52 long usesreg = ((long)*modep) & 0xf; 53 54 switch ( ((long)*modep) >> 4 ) { 55 case 0: 56 case 1: 57 case 2: 58 case 3: 59 return literal; 60 case 4: 61 return indexed; 62 case 5: 63 return reg; 64 case 6: 65 return regdef; 66 case 7: 67 return autodec; 68 case 8: 69 return ( usesreg != 0xe ? autoinc : immediate ); 70 case 9: 71 return ( usesreg != PC ? autoincdef : absolute ); 72 case 10: 73 return ( usesreg != PC ? bytedisp : byterel ); 74 case 11: 75 return ( usesreg != PC ? bytedispdef : bytereldef ); 76 case 12: 77 return ( usesreg != PC ? worddisp : wordrel ); 78 case 13: 79 return ( usesreg != PC ? worddispdef : wordreldef ); 80 case 14: 81 return ( usesreg != PC ? longdisp : longrel ); 82 case 15: 83 return ( usesreg != PC ? longdispdef : longreldef ); 84 } 85 /* NOTREACHED */ 86 } 87 88 char * 89 operandname( mode ) 90 operandenum mode; 91 { 92 93 switch ( mode ) { 94 case literal: 95 return "literal"; 96 case indexed: 97 return "indexed"; 98 case reg: 99 return "register"; 100 case regdef: 101 return "register deferred"; 102 case autodec: 103 return "autodecrement"; 104 case autoinc: 105 return "autoincrement"; 106 case autoincdef: 107 return "autoincrement deferred"; 108 case bytedisp: 109 return "byte displacement"; 110 case bytedispdef: 111 return "byte displacement deferred"; 112 case byterel: 113 return "byte relative"; 114 case bytereldef: 115 return "byte relative deferred"; 116 case worddisp: 117 return "word displacement"; 118 case worddispdef: 119 return "word displacement deferred"; 120 case wordrel: 121 return "word relative"; 122 case wordreldef: 123 return "word relative deferred"; 124 case immediate: 125 return "immediate"; 126 case absolute: 127 return "absolute"; 128 case longdisp: 129 return "long displacement"; 130 case longdispdef: 131 return "long displacement deferred"; 132 case longrel: 133 return "long relative"; 134 case longreldef: 135 return "long relative deferred"; 136 } 137 /* NOTREACHED */ 138 } 139 140 long 141 operandlength( modep ) 142 unsigned char *modep; 143 { 144 145 switch ( operandmode( modep ) ) { 146 case literal: 147 case reg: 148 case regdef: 149 case autodec: 150 case autoinc: 151 case autoincdef: 152 return 1; 153 case bytedisp: 154 case bytedispdef: 155 case byterel: 156 case bytereldef: 157 return 2; 158 case worddisp: 159 case worddispdef: 160 case wordrel: 161 case wordreldef: 162 return 3; 163 case immediate: 164 case absolute: 165 case longdisp: 166 case longdispdef: 167 case longrel: 168 case longreldef: 169 return 5; 170 case indexed: 171 return 1+operandlength( modep + 1 ); 172 } 173 /* NOTREACHED */ 174 } 175 176 unsigned long 177 reladdr( modep ) 178 char *modep; 179 { 180 operandenum mode = operandmode( modep ); 181 char *cp; 182 short *sp; 183 long *lp; 184 int i; 185 long value = 0; 186 187 cp = modep; 188 cp += 1; /* skip over the mode */ 189 switch ( mode ) { 190 default: 191 fprintf( stderr , "[reladdr] not relative address\n" ); 192 return (unsigned long) modep; 193 case byterel: 194 return (unsigned long) ( cp + sizeof *cp + *cp ); 195 case wordrel: 196 for (i = 0; i < sizeof *sp; i++) 197 value = (value << 8) + (cp[i] & 0xff); 198 return (unsigned long) ( cp + sizeof *sp + value ); 199 case longrel: 200 for (i = 0; i < sizeof *lp; i++) 201 value = (value << 8) + (cp[i] & 0xff); 202 return (unsigned long) ( cp + sizeof *lp + value ); 203 } 204 } 205 206 findcall( parentp , p_lowpc , p_highpc ) 207 nltype *parentp; 208 unsigned long p_lowpc; 209 unsigned long p_highpc; 210 { 211 unsigned char *instructp; 212 long length; 213 nltype *childp; 214 operandenum mode; 215 operandenum firstmode; 216 unsigned long destpc; 217 218 if ( textspace == 0 ) { 219 return; 220 } 221 if ( p_lowpc < s_lowpc ) { 222 p_lowpc = s_lowpc; 223 } 224 if ( p_highpc > s_highpc ) { 225 p_highpc = s_highpc; 226 } 227 # ifdef DEBUG 228 if ( debug & CALLDEBUG ) { 229 printf( "[findcall] %s: 0x%x to 0x%x\n" , 230 parentp -> name , p_lowpc , p_highpc ); 231 } 232 # endif DEBUG 233 for ( instructp = textspace + p_lowpc ; 234 instructp < textspace + p_highpc ; 235 instructp += length ) { 236 length = 1; 237 if ( *instructp == CALLF ) { 238 /* 239 * maybe a callf, better check it out. 240 * skip the count of the number of arguments. 241 */ 242 # ifdef DEBUG 243 if ( debug & CALLDEBUG ) { 244 printf( "[findcall]\t0x%x:callf" , instructp - textspace ); 245 } 246 # endif DEBUG 247 firstmode = operandmode( instructp+length ); 248 switch ( firstmode ) { 249 case literal: 250 case immediate: 251 break; 252 default: 253 goto botched; 254 } 255 length += operandlength( instructp+length ); 256 mode = operandmode( instructp + length ); 257 # ifdef DEBUG 258 if ( debug & CALLDEBUG ) { 259 printf( "\tfirst operand is %s", operandname( firstmode ) ); 260 printf( "\tsecond operand is %s\n" , operandname( mode ) ); 261 } 262 # endif DEBUG 263 switch ( mode ) { 264 case regdef: 265 case bytedispdef: 266 case worddispdef: 267 case longdispdef: 268 case bytereldef: 269 case wordreldef: 270 case longreldef: 271 /* 272 * indirect call: call through pointer 273 * either *d(r) as a parameter or local 274 * (r) as a return value 275 * *f as a global pointer 276 * [are there others that we miss?, 277 * e.g. arrays of pointers to functions???] 278 */ 279 addarc( parentp , &indirectchild , (long) 0 ); 280 length += operandlength( instructp + length ); 281 continue; 282 case byterel: 283 case wordrel: 284 case longrel: 285 /* 286 * regular pc relative addressing 287 * check that this is the address of 288 * a function. 289 */ 290 destpc = reladdr( instructp+length ) 291 - (unsigned long) textspace; 292 if ( destpc >= s_lowpc && destpc <= s_highpc ) { 293 childp = nllookup( destpc ); 294 # ifdef DEBUG 295 if ( debug & CALLDEBUG ) { 296 printf( "[findcall]\tdestpc 0x%x" , destpc ); 297 printf( " childp->name %s" , childp -> name ); 298 printf( " childp->value 0x%x\n" , 299 childp -> value ); 300 } 301 # endif DEBUG 302 if ( childp -> value == destpc ) { 303 /* 304 * a hit 305 */ 306 addarc( parentp , childp , (long) 0 ); 307 length += operandlength( instructp + length ); 308 continue; 309 } 310 goto botched; 311 } 312 /* 313 * else: 314 * it looked like a callf, 315 * but it wasn't to anywhere. 316 */ 317 goto botched; 318 default: 319 botched: 320 /* 321 * something funny going on. 322 */ 323 # ifdef DEBUG 324 if ( debug & CALLDEBUG ) { 325 printf( "[findcall]\tbut it's a botch\n" ); 326 } 327 # endif DEBUG 328 length = 1; 329 continue; 330 } 331 } 332 } 333 } 334