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