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