1 #ifndef lint 2 static char *sccsid = "@(#)vax.c 1.4 (Berkeley) 03/30/83"; 3 #endif not lint 4 5 #include "gprof.h" 6 7 /* 8 * a namelist entry to be the child of indirect calls 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 struct modebyte *modep; 34 { 35 long usesreg = modep -> regfield; 36 37 switch ( modep -> modefield ) { 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 != PC ? 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 struct modebyte *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( (struct modebyte *) ((char *) modep) + 1 ); 155 } 156 /* NOTREACHED */ 157 } 158 159 unsigned long 160 reladdr( modep ) 161 struct modebyte *modep; 162 { 163 operandenum mode = operandmode( modep ); 164 char *cp; 165 short *sp; 166 long *lp; 167 168 cp = (char *) modep; 169 cp += 1; /* skip over the mode */ 170 switch ( mode ) { 171 default: 172 fprintf( stderr , "[reladdr] not relative address\n" ); 173 return (unsigned long) modep; 174 case byterel: 175 return (unsigned long) ( cp + sizeof *cp + *cp ); 176 case wordrel: 177 sp = (short *) cp; 178 return (unsigned long) ( cp + sizeof *sp + *sp ); 179 case longrel: 180 lp = (long *) cp; 181 return (unsigned long) ( cp + sizeof *lp + *lp ); 182 } 183 } 184 185 findcalls( parentp , p_lowpc , p_highpc ) 186 nltype *parentp; 187 unsigned long p_lowpc; 188 unsigned long p_highpc; 189 { 190 unsigned char *instructp; 191 long length; 192 nltype *childp; 193 operandenum mode; 194 operandenum firstmode; 195 unsigned long destpc; 196 197 if ( textspace == 0 ) { 198 return; 199 } 200 if ( p_lowpc < s_lowpc ) { 201 p_lowpc = s_lowpc; 202 } 203 if ( p_highpc > s_highpc ) { 204 p_highpc = s_highpc; 205 } 206 # ifdef DEBUG 207 if ( debug & CALLSDEBUG ) { 208 printf( "[findcalls] %s: 0x%x to 0x%x\n" , 209 parentp -> name , p_lowpc , p_highpc ); 210 } 211 # endif DEBUG 212 for ( instructp = textspace + p_lowpc ; 213 instructp < textspace + p_highpc ; 214 instructp += length ) { 215 length = 1; 216 if ( *instructp == CALLS ) { 217 /* 218 * maybe a calls, better check it out. 219 * skip the count of the number of arguments. 220 */ 221 # ifdef DEBUG 222 if ( debug & CALLSDEBUG ) { 223 printf( "[findcalls]\t0x%x:calls" , instructp - textspace ); 224 } 225 # endif DEBUG 226 firstmode = operandmode( (struct modebyte *) (instructp+length) ); 227 switch ( firstmode ) { 228 case literal: 229 case immediate: 230 break; 231 default: 232 goto botched; 233 } 234 length += operandlength( (struct modebyte *) (instructp+length) ); 235 mode = operandmode( (struct modebyte *) ( instructp + length ) ); 236 # ifdef DEBUG 237 if ( debug & CALLSDEBUG ) { 238 printf( "\tfirst operand is %s", operandname( firstmode ) ); 239 printf( "\tsecond operand is %s\n" , operandname( mode ) ); 240 } 241 # endif DEBUG 242 switch ( mode ) { 243 case regdef: 244 case bytedispdef: 245 case worddispdef: 246 case longdispdef: 247 case bytereldef: 248 case wordreldef: 249 case longreldef: 250 /* 251 * indirect call: call through pointer 252 * either *d(r) as a parameter or local 253 * (r) as a return value 254 * *f as a global pointer 255 * [are there others that we miss?, 256 * e.g. arrays of pointers to functions???] 257 */ 258 addarc( parentp , &indirectchild , (long) 0 ); 259 length += operandlength( 260 (struct modebyte *) ( instructp + length ) ); 261 continue; 262 case byterel: 263 case wordrel: 264 case longrel: 265 /* 266 * regular pc relative addressing 267 * check that this is the address of 268 * a function. 269 */ 270 destpc = reladdr( (struct modebyte *) (instructp+length) ) 271 - (unsigned long) textspace; 272 if ( destpc >= s_lowpc && destpc <= s_highpc ) { 273 childp = nllookup( destpc ); 274 # ifdef DEBUG 275 if ( debug & CALLSDEBUG ) { 276 printf( "[findcalls]\tdestpc 0x%x" , destpc ); 277 printf( " childp->name %s" , childp -> name ); 278 printf( " childp->value 0x%x\n" , 279 childp -> value ); 280 } 281 # endif DEBUG 282 if ( childp -> value == destpc ) { 283 /* 284 * a hit 285 */ 286 addarc( parentp , childp , (long) 0 ); 287 length += operandlength( (struct modebyte *) 288 ( instructp + length ) ); 289 continue; 290 } 291 goto botched; 292 } 293 /* 294 * else: 295 * it looked like a calls, 296 * but it wasn't to anywhere. 297 */ 298 goto botched; 299 default: 300 botched: 301 /* 302 * something funny going on. 303 */ 304 # ifdef DEBUG 305 if ( debug & CALLSDEBUG ) { 306 printf( "[findcalls]\tbut it's a botch\n" ); 307 } 308 # endif DEBUG 309 length = 1; 310 continue; 311 } 312 } 313 } 314 } 315