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