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