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