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