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