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 "search_list.h" 31 #include "source.h" 32 #include "symtab.h" 33 #include "cg_arcs.h" 34 #include "corefile.h" 35 #include "hist.h" 36 37 /* 38 * opcode of the `callf' instruction 39 */ 40 #define CALLF 0xfe 41 42 /* 43 * register for pc relative addressing 44 */ 45 #define PC 0xf 46 47 enum tahoe_opermodes 48 { 49 literal, indexed, reg, regdef, autodec, autoinc, autoincdef, 50 bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef, 51 immediate, absolute, byterel, bytereldef, wordrel, wordreldef, 52 longrel, longreldef 53 }; 54 typedef enum tahoe_opermodes tahoe_operandenum; 55 56 /* 57 * A symbol to be the child of indirect callf: 58 */ 59 static Sym indirectchild; 60 61 static tahoe_operandenum tahoe_operandmode PARAMS ((unsigned char *)); 62 static char *tahoe_operandname PARAMS ((tahoe_operandenum)); 63 static long tahoe_operandlength PARAMS ((unsigned char *)); 64 static bfd_signed_vma tahoe_offset PARAMS ((unsigned char *)); 65 void tahoe_find_call PARAMS ((Sym *, bfd_vma, bfd_vma)); 66 67 static tahoe_operandenum 68 tahoe_operandmode (modep) 69 unsigned char *modep; 70 { 71 long usesreg = *modep & 0xf; 72 73 switch ((*modep >> 4) & 0xf) 74 { 75 case 0: 76 case 1: 77 case 2: 78 case 3: 79 return literal; 80 case 4: 81 return indexed; 82 case 5: 83 return reg; 84 case 6: 85 return regdef; 86 case 7: 87 return autodec; 88 case 8: 89 return usesreg != 0xe ? autoinc : immediate; 90 case 9: 91 return usesreg != PC ? autoincdef : absolute; 92 case 10: 93 return usesreg != PC ? bytedisp : byterel; 94 case 11: 95 return usesreg != PC ? bytedispdef : bytereldef; 96 case 12: 97 return usesreg != PC ? worddisp : wordrel; 98 case 13: 99 return usesreg != PC ? worddispdef : wordreldef; 100 case 14: 101 return usesreg != PC ? longdisp : longrel; 102 case 15: 103 return usesreg != PC ? longdispdef : longreldef; 104 } 105 /* NOTREACHED */ 106 abort (); 107 } 108 109 static char * 110 tahoe_operandname (mode) 111 tahoe_operandenum mode; 112 { 113 114 switch (mode) 115 { 116 case literal: 117 return "literal"; 118 case indexed: 119 return "indexed"; 120 case reg: 121 return "register"; 122 case regdef: 123 return "register deferred"; 124 case autodec: 125 return "autodecrement"; 126 case autoinc: 127 return "autoincrement"; 128 case autoincdef: 129 return "autoincrement deferred"; 130 case bytedisp: 131 return "byte displacement"; 132 case bytedispdef: 133 return "byte displacement deferred"; 134 case byterel: 135 return "byte relative"; 136 case bytereldef: 137 return "byte relative deferred"; 138 case worddisp: 139 return "word displacement"; 140 case worddispdef: 141 return "word displacement deferred"; 142 case wordrel: 143 return "word relative"; 144 case wordreldef: 145 return "word relative deferred"; 146 case immediate: 147 return "immediate"; 148 case absolute: 149 return "absolute"; 150 case longdisp: 151 return "long displacement"; 152 case longdispdef: 153 return "long displacement deferred"; 154 case longrel: 155 return "long relative"; 156 case longreldef: 157 return "long relative deferred"; 158 } 159 /* NOTREACHED */ 160 abort (); 161 } 162 163 static long 164 tahoe_operandlength (modep) 165 unsigned char *modep; 166 { 167 168 switch (tahoe_operandmode (modep)) 169 { 170 case literal: 171 case reg: 172 case regdef: 173 case autodec: 174 case autoinc: 175 case autoincdef: 176 return 1; 177 case bytedisp: 178 case bytedispdef: 179 case byterel: 180 case bytereldef: 181 return 2; 182 case worddisp: 183 case worddispdef: 184 case wordrel: 185 case wordreldef: 186 return 3; 187 case immediate: 188 case absolute: 189 case longdisp: 190 case longdispdef: 191 case longrel: 192 case longreldef: 193 return 5; 194 case indexed: 195 return 1 + tahoe_operandlength (modep + 1); 196 } 197 /* NOTREACHED */ 198 abort (); 199 } 200 201 static bfd_signed_vma 202 tahoe_offset (modep) 203 unsigned char *modep; 204 { 205 tahoe_operandenum mode = tahoe_operandmode (modep); 206 207 ++modep; /* skip over the mode */ 208 switch (mode) 209 { 210 default: 211 fprintf (stderr, "[reladdr] not relative address\n"); 212 return 0; 213 case byterel: 214 return 1 + bfd_get_signed_8 (core_bfd, modep); 215 case wordrel: 216 return 2 + bfd_get_signed_16 (core_bfd, modep); 217 case longrel: 218 return 4 + bfd_get_signed_32 (core_bfd, modep); 219 } 220 } 221 222 void 223 tahoe_find_call (parent, p_lowpc, p_highpc) 224 Sym *parent; 225 bfd_vma p_lowpc; 226 bfd_vma p_highpc; 227 { 228 unsigned char *instructp; 229 long length; 230 Sym *child; 231 tahoe_operandenum mode; 232 tahoe_operandenum firstmode; 233 bfd_vma pc, destpc; 234 static bfd_boolean inited = FALSE; 235 236 if (!inited) 237 { 238 inited = TRUE; 239 sym_init (&indirectchild); 240 indirectchild.cg.prop.fract = 1.0; 241 indirectchild.cg.cyc.head = &indirectchild; 242 } 243 244 if (core_text_space == 0) 245 { 246 return; 247 } 248 if (p_lowpc < s_lowpc) 249 { 250 p_lowpc = s_lowpc; 251 } 252 if (p_highpc > s_highpc) 253 { 254 p_highpc = s_highpc; 255 } 256 DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n", 257 parent->name, (unsigned long) p_lowpc, 258 (unsigned long) p_highpc)); 259 for (pc = p_lowpc; pc < p_highpc; pc += length) 260 { 261 length = 1; 262 instructp = ((unsigned char *) core_text_space 263 + pc - core_text_sect->vma); 264 if ((*instructp & 0xff) == CALLF) 265 { 266 /* 267 * maybe a callf, better check it out. 268 * skip the count of the number of arguments. 269 */ 270 DBG (CALLDEBUG, printf ("[findcall]\t0x%lx:callf", 271 (unsigned long) pc)); 272 firstmode = tahoe_operandmode (instructp + length); 273 switch (firstmode) 274 { 275 case literal: 276 case immediate: 277 break; 278 default: 279 goto botched; 280 } 281 length += tahoe_operandlength (instructp + length); 282 mode = tahoe_operandmode (instructp + length); 283 DBG (CALLDEBUG, 284 printf ("\tfirst operand is %s", tahoe_operandname (firstmode)); 285 printf ("\tsecond operand is %s\n", tahoe_operandname (mode)); 286 ); 287 switch (mode) 288 { 289 case regdef: 290 case bytedispdef: 291 case worddispdef: 292 case longdispdef: 293 case bytereldef: 294 case wordreldef: 295 case longreldef: 296 /* 297 * indirect call: call through pointer 298 * either *d(r) as a parameter or local 299 * (r) as a return value 300 * *f as a global pointer 301 * [are there others that we miss?, 302 * e.g. arrays of pointers to functions???] 303 */ 304 arc_add (parent, &indirectchild, (unsigned long) 0); 305 length += tahoe_operandlength (instructp + length); 306 continue; 307 case byterel: 308 case wordrel: 309 case longrel: 310 /* 311 * regular pc relative addressing 312 * check that this is the address of 313 * a function. 314 */ 315 destpc = pc + tahoe_offset (instructp + length); 316 if (destpc >= s_lowpc && destpc <= s_highpc) 317 { 318 child = sym_lookup (&symtab, destpc); 319 DBG (CALLDEBUG, 320 printf ("[findcall]\tdestpc 0x%lx", 321 (unsigned long) destpc); 322 printf (" child->name %s", child->name); 323 printf (" child->addr 0x%lx\n", 324 (unsigned long) child->addr); 325 ); 326 if (child->addr == destpc) 327 { 328 /* 329 * a hit 330 */ 331 arc_add (parent, child, (unsigned long) 0); 332 length += tahoe_operandlength (instructp + length); 333 continue; 334 } 335 goto botched; 336 } 337 /* 338 * else: 339 * it looked like a callf, 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