vax.c revision 1.3
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: (1) source distributions retain this entire copyright 7 * notice and comment, and (2) distributions including binaries display 8 * the following acknowledgement: ``This product includes software 9 * developed by the University of California, Berkeley and its contributors'' 10 * in the documentation or other materials provided with the distribution 11 * and in all advertising materials mentioning features or use of this 12 * software. Neither the name of the University nor the names of its 13 * contributors may be used to endorse or promote products derived 14 * from this software without specific prior written permission. 15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 18 */ 19#include "gprof.h" 20#include "cg_arcs.h" 21#include "corefile.h" 22#include "hist.h" 23#include "symtab.h" 24 25 /* 26 * opcode of the `calls' instruction 27 */ 28#define CALLS 0xfb 29 30 /* 31 * register for pc relative addressing 32 */ 33#define PC 0xf 34 35enum opermodes 36 { 37 literal, indexed, reg, regdef, autodec, autoinc, autoincdef, 38 bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef, 39 immediate, absolute, byterel, bytereldef, wordrel, wordreldef, 40 longrel, longreldef 41 }; 42typedef enum opermodes operandenum; 43 44struct modebyte 45 { 46 unsigned int regfield:4; 47 unsigned int modefield:4; 48 }; 49 50/* 51 * A symbol to be the child of indirect calls: 52 */ 53Sym indirectchild; 54 55 56static operandenum 57vax_operandmode (modep) 58 struct modebyte *modep; 59{ 60 long usesreg = modep->regfield; 61 62 switch (modep->modefield) 63 { 64 case 0: 65 case 1: 66 case 2: 67 case 3: 68 return literal; 69 case 4: 70 return indexed; 71 case 5: 72 return reg; 73 case 6: 74 return regdef; 75 case 7: 76 return autodec; 77 case 8: 78 return usesreg != PC ? autoinc : immediate; 79 case 9: 80 return usesreg != PC ? autoincdef : absolute; 81 case 10: 82 return usesreg != PC ? bytedisp : byterel; 83 case 11: 84 return usesreg != PC ? bytedispdef : bytereldef; 85 case 12: 86 return usesreg != PC ? worddisp : wordrel; 87 case 13: 88 return usesreg != PC ? worddispdef : wordreldef; 89 case 14: 90 return usesreg != PC ? longdisp : longrel; 91 case 15: 92 return usesreg != PC ? longdispdef : longreldef; 93 } 94 /* NOTREACHED */ 95 abort (); 96} 97 98static char * 99vax_operandname (mode) 100 operandenum mode; 101{ 102 103 switch (mode) 104 { 105 case literal: 106 return "literal"; 107 case indexed: 108 return "indexed"; 109 case reg: 110 return "register"; 111 case regdef: 112 return "register deferred"; 113 case autodec: 114 return "autodecrement"; 115 case autoinc: 116 return "autoincrement"; 117 case autoincdef: 118 return "autoincrement deferred"; 119 case bytedisp: 120 return "byte displacement"; 121 case bytedispdef: 122 return "byte displacement deferred"; 123 case byterel: 124 return "byte relative"; 125 case bytereldef: 126 return "byte relative deferred"; 127 case worddisp: 128 return "word displacement"; 129 case worddispdef: 130 return "word displacement deferred"; 131 case wordrel: 132 return "word relative"; 133 case wordreldef: 134 return "word relative deferred"; 135 case immediate: 136 return "immediate"; 137 case absolute: 138 return "absolute"; 139 case longdisp: 140 return "long displacement"; 141 case longdispdef: 142 return "long displacement deferred"; 143 case longrel: 144 return "long relative"; 145 case longreldef: 146 return "long relative deferred"; 147 } 148 /* NOTREACHED */ 149 abort (); 150} 151 152static long 153vax_operandlength (modep) 154 struct modebyte *modep; 155{ 156 157 switch (vax_operandmode (modep)) 158 { 159 case literal: 160 case reg: 161 case regdef: 162 case autodec: 163 case autoinc: 164 case autoincdef: 165 return 1; 166 case bytedisp: 167 case bytedispdef: 168 case byterel: 169 case bytereldef: 170 return 2; 171 case worddisp: 172 case worddispdef: 173 case wordrel: 174 case wordreldef: 175 return 3; 176 case immediate: 177 case absolute: 178 case longdisp: 179 case longdispdef: 180 case longrel: 181 case longreldef: 182 return 5; 183 case indexed: 184 return 1 + vax_operandlength ((struct modebyte *) ((char *) modep) + 1); 185 } 186 /* NOTREACHED */ 187 abort (); 188} 189 190static bfd_vma 191vax_reladdr (modep) 192 struct modebyte *modep; 193{ 194 operandenum mode = vax_operandmode (modep); 195 char *cp; 196 short *sp; 197 long *lp; 198 199 cp = (char *) modep; 200 ++cp; /* skip over the mode */ 201 switch (mode) 202 { 203 default: 204 fprintf (stderr, "[reladdr] not relative address\n"); 205 return (bfd_vma) modep; 206 case byterel: 207 return (bfd_vma) (cp + sizeof *cp + *cp); 208 case wordrel: 209 sp = (short *) cp; 210 return (bfd_vma) (cp + sizeof *sp + *sp); 211 case longrel: 212 lp = (long *) cp; 213 return (bfd_vma) (cp + sizeof *lp + *lp); 214 } 215} 216 217 218void 219vax_find_call (parent, p_lowpc, p_highpc) 220 Sym *parent; 221 bfd_vma p_lowpc; 222 bfd_vma p_highpc; 223{ 224 unsigned char *instructp; 225 long length; 226 Sym *child; 227 operandenum mode; 228 operandenum firstmode; 229 bfd_vma destpc; 230 static bool inited = FALSE; 231 232 if (!inited) 233 { 234 inited = TRUE; 235 sym_init (&indirectchild); 236 indirectchild.cg.prop.fract = 1.0; 237 indirectchild.cg.cyc.head = &indirectchild; 238 } 239 240 if (core_text_space == 0) 241 { 242 return; 243 } 244 if (p_lowpc < s_lowpc) 245 { 246 p_lowpc = s_lowpc; 247 } 248 if (p_highpc > s_highpc) 249 { 250 p_highpc = s_highpc; 251 } 252 DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n", 253 parent->name, (unsigned long) p_lowpc, 254 (unsigned long) p_highpc)); 255 for (instructp = (unsigned char *) core_text_space + p_lowpc; 256 instructp < (unsigned char *) core_text_space + p_highpc; 257 instructp += length) 258 { 259 length = 1; 260 if (*instructp == CALLS) 261 { 262 /* 263 * maybe a calls, better check it out. 264 * skip the count of the number of arguments. 265 */ 266 DBG (CALLDEBUG, 267 printf ("[findcall]\t0x%lx:calls", 268 ((unsigned long) 269 (instructp - (unsigned char *) core_text_space)))); 270 firstmode = vax_operandmode ((struct modebyte *) (instructp + length)); 271 switch (firstmode) 272 { 273 case literal: 274 case immediate: 275 break; 276 default: 277 goto botched; 278 } 279 length += vax_operandlength ((struct modebyte *) (instructp + length)); 280 mode = vax_operandmode ((struct modebyte *) (instructp + length)); 281 DBG (CALLDEBUG, 282 printf ("\tfirst operand is %s", vax_operandname (firstmode)); 283 printf ("\tsecond operand is %s\n", vax_operandname (mode))); 284 switch (mode) 285 { 286 case regdef: 287 case bytedispdef: 288 case worddispdef: 289 case longdispdef: 290 case bytereldef: 291 case wordreldef: 292 case longreldef: 293 /* 294 * indirect call: call through pointer 295 * either *d(r) as a parameter or local 296 * (r) as a return value 297 * *f as a global pointer 298 * [are there others that we miss?, 299 * e.g. arrays of pointers to functions???] 300 */ 301 arc_add (parent, &indirectchild, (unsigned long) 0); 302 length += vax_operandlength ( 303 (struct modebyte *) (instructp + length)); 304 continue; 305 case byterel: 306 case wordrel: 307 case longrel: 308 /* 309 * regular pc relative addressing 310 * check that this is the address of 311 * a function. 312 */ 313 destpc = vax_reladdr ((struct modebyte *) (instructp + length)) 314 - (bfd_vma) core_text_space; 315 if (destpc >= s_lowpc && destpc <= s_highpc) 316 { 317 child = sym_lookup (&symtab, destpc); 318 DBG (CALLDEBUG, 319 printf ("[findcall]\tdestpc 0x%lx", 320 (unsigned long) destpc); 321 printf (" child->name %s", child->name); 322 printf (" child->addr 0x%lx\n", 323 (unsigned long) child->addr); 324 ); 325 if (child->addr == destpc) 326 { 327 /* 328 * a hit 329 */ 330 arc_add (parent, child, (unsigned long) 0); 331 length += vax_operandlength ((struct modebyte *) 332 (instructp + length)); 333 continue; 334 } 335 goto botched; 336 } 337 /* 338 * else: 339 * it looked like a calls, 340 * but it wasn't to anywhere. 341 */ 342 goto botched; 343 default: 344 botched: 345 /* 346 * something funny going on. 347 */ 348 DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n")); 349 length = 1; 350 continue; 351 } 352 } 353 } 354} 355