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