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