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