12159047fSniklas /*
26e421504Sfgsch * Copyright (c) 1983, 1993, 2001
36e421504Sfgsch * The Regents of the University of California. All rights reserved.
42159047fSniklas *
56e421504Sfgsch * Redistribution and use in source and binary forms, with or without
66e421504Sfgsch * modification, are permitted provided that the following conditions
76e421504Sfgsch * are met:
86e421504Sfgsch * 1. Redistributions of source code must retain the above copyright
96e421504Sfgsch * notice, this list of conditions and the following disclaimer.
106e421504Sfgsch * 2. Redistributions in binary form must reproduce the above copyright
116e421504Sfgsch * notice, this list of conditions and the following disclaimer in the
126e421504Sfgsch * documentation and/or other materials provided with the distribution.
136e421504Sfgsch * 3. Neither the name of the University nor the names of its contributors
146e421504Sfgsch * may be used to endorse or promote products derived from this software
156e421504Sfgsch * without specific prior written permission.
166e421504Sfgsch *
176e421504Sfgsch * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
186e421504Sfgsch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
196e421504Sfgsch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
206e421504Sfgsch * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
216e421504Sfgsch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
226e421504Sfgsch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
236e421504Sfgsch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
246e421504Sfgsch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
256e421504Sfgsch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
266e421504Sfgsch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
276e421504Sfgsch * SUCH DAMAGE.
282159047fSniklas */
292159047fSniklas #include "gprof.h"
30*c074d1c9Sdrahn #include "search_list.h"
31*c074d1c9Sdrahn #include "source.h"
32*c074d1c9Sdrahn #include "symtab.h"
332159047fSniklas #include "cg_arcs.h"
34b305b0f1Sespie #include "corefile.h"
352159047fSniklas #include "hist.h"
362159047fSniklas
372159047fSniklas /*
38b305b0f1Sespie * opcode of the `calls' instruction
39b305b0f1Sespie */
40b305b0f1Sespie #define CALLS 0xfb
41b305b0f1Sespie
42b305b0f1Sespie /*
43b305b0f1Sespie * register for pc relative addressing
44b305b0f1Sespie */
45b305b0f1Sespie #define PC 0xf
46b305b0f1Sespie
47b305b0f1Sespie enum opermodes
48b305b0f1Sespie {
49b305b0f1Sespie literal, indexed, reg, regdef, autodec, autoinc, autoincdef,
50b305b0f1Sespie bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef,
51b305b0f1Sespie immediate, absolute, byterel, bytereldef, wordrel, wordreldef,
52b305b0f1Sespie longrel, longreldef
53b305b0f1Sespie };
54b305b0f1Sespie typedef enum opermodes operandenum;
55b305b0f1Sespie
56*c074d1c9Sdrahn #if 0
57*c074d1c9Sdrahn /* Here to document only. We can't use this when cross compiling as
58*c074d1c9Sdrahn the bitfield layout might not be the same as native. */
59b305b0f1Sespie struct modebyte
60b305b0f1Sespie {
61b305b0f1Sespie unsigned int regfield:4;
62b305b0f1Sespie unsigned int modefield:4;
63b305b0f1Sespie };
64*c074d1c9Sdrahn #endif
65b305b0f1Sespie
66b305b0f1Sespie /*
672159047fSniklas * A symbol to be the child of indirect calls:
682159047fSniklas */
69*c074d1c9Sdrahn static Sym indirectchild;
702159047fSniklas
71*c074d1c9Sdrahn static operandenum vax_operandmode PARAMS ((unsigned char *));
72*c074d1c9Sdrahn static char *vax_operandname PARAMS ((operandenum));
73*c074d1c9Sdrahn static long vax_operandlength PARAMS ((unsigned char *));
74*c074d1c9Sdrahn static bfd_signed_vma vax_offset PARAMS ((unsigned char *));
75*c074d1c9Sdrahn void vax_find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
762159047fSniklas
772159047fSniklas static operandenum
vax_operandmode(modep)78b305b0f1Sespie vax_operandmode (modep)
79*c074d1c9Sdrahn unsigned char *modep;
802159047fSniklas {
81*c074d1c9Sdrahn int usesreg = *modep & 0xf;
822159047fSniklas
83*c074d1c9Sdrahn switch ((*modep >> 4) & 0xf)
842159047fSniklas {
852159047fSniklas case 0:
862159047fSniklas case 1:
872159047fSniklas case 2:
882159047fSniklas case 3:
892159047fSniklas return literal;
902159047fSniklas case 4:
912159047fSniklas return indexed;
922159047fSniklas case 5:
932159047fSniklas return reg;
942159047fSniklas case 6:
952159047fSniklas return regdef;
962159047fSniklas case 7:
972159047fSniklas return autodec;
982159047fSniklas case 8:
992159047fSniklas return usesreg != PC ? autoinc : immediate;
1002159047fSniklas case 9:
1012159047fSniklas return usesreg != PC ? autoincdef : absolute;
1022159047fSniklas case 10:
1032159047fSniklas return usesreg != PC ? bytedisp : byterel;
1042159047fSniklas case 11:
1052159047fSniklas return usesreg != PC ? bytedispdef : bytereldef;
1062159047fSniklas case 12:
1072159047fSniklas return usesreg != PC ? worddisp : wordrel;
1082159047fSniklas case 13:
1092159047fSniklas return usesreg != PC ? worddispdef : wordreldef;
1102159047fSniklas case 14:
1112159047fSniklas return usesreg != PC ? longdisp : longrel;
1122159047fSniklas case 15:
1132159047fSniklas return usesreg != PC ? longdispdef : longreldef;
1142159047fSniklas }
1152159047fSniklas /* NOTREACHED */
116b305b0f1Sespie abort ();
1172159047fSniklas }
1182159047fSniklas
1192159047fSniklas static char *
vax_operandname(mode)120b305b0f1Sespie vax_operandname (mode)
1212159047fSniklas operandenum mode;
1222159047fSniklas {
1232159047fSniklas
1242159047fSniklas switch (mode)
1252159047fSniklas {
1262159047fSniklas case literal:
1272159047fSniklas return "literal";
1282159047fSniklas case indexed:
1292159047fSniklas return "indexed";
1302159047fSniklas case reg:
1312159047fSniklas return "register";
1322159047fSniklas case regdef:
1332159047fSniklas return "register deferred";
1342159047fSniklas case autodec:
1352159047fSniklas return "autodecrement";
1362159047fSniklas case autoinc:
1372159047fSniklas return "autoincrement";
1382159047fSniklas case autoincdef:
1392159047fSniklas return "autoincrement deferred";
1402159047fSniklas case bytedisp:
1412159047fSniklas return "byte displacement";
1422159047fSniklas case bytedispdef:
1432159047fSniklas return "byte displacement deferred";
1442159047fSniklas case byterel:
1452159047fSniklas return "byte relative";
1462159047fSniklas case bytereldef:
1472159047fSniklas return "byte relative deferred";
1482159047fSniklas case worddisp:
1492159047fSniklas return "word displacement";
1502159047fSniklas case worddispdef:
1512159047fSniklas return "word displacement deferred";
1522159047fSniklas case wordrel:
1532159047fSniklas return "word relative";
1542159047fSniklas case wordreldef:
1552159047fSniklas return "word relative deferred";
1562159047fSniklas case immediate:
1572159047fSniklas return "immediate";
1582159047fSniklas case absolute:
1592159047fSniklas return "absolute";
1602159047fSniklas case longdisp:
1612159047fSniklas return "long displacement";
1622159047fSniklas case longdispdef:
1632159047fSniklas return "long displacement deferred";
1642159047fSniklas case longrel:
1652159047fSniklas return "long relative";
1662159047fSniklas case longreldef:
1672159047fSniklas return "long relative deferred";
1682159047fSniklas }
1692159047fSniklas /* NOTREACHED */
170b305b0f1Sespie abort ();
1712159047fSniklas }
1722159047fSniklas
1732159047fSniklas static long
vax_operandlength(modep)174b305b0f1Sespie vax_operandlength (modep)
175*c074d1c9Sdrahn unsigned char *modep;
1762159047fSniklas {
1772159047fSniklas
178b305b0f1Sespie switch (vax_operandmode (modep))
1792159047fSniklas {
1802159047fSniklas case literal:
1812159047fSniklas case reg:
1822159047fSniklas case regdef:
1832159047fSniklas case autodec:
1842159047fSniklas case autoinc:
1852159047fSniklas case autoincdef:
1862159047fSniklas return 1;
1872159047fSniklas case bytedisp:
1882159047fSniklas case bytedispdef:
1892159047fSniklas case byterel:
1902159047fSniklas case bytereldef:
1912159047fSniklas return 2;
1922159047fSniklas case worddisp:
1932159047fSniklas case worddispdef:
1942159047fSniklas case wordrel:
1952159047fSniklas case wordreldef:
1962159047fSniklas return 3;
1972159047fSniklas case immediate:
1982159047fSniklas case absolute:
1992159047fSniklas case longdisp:
2002159047fSniklas case longdispdef:
2012159047fSniklas case longrel:
2022159047fSniklas case longreldef:
2032159047fSniklas return 5;
2042159047fSniklas case indexed:
205*c074d1c9Sdrahn return 1 + vax_operandlength (modep + 1);
2062159047fSniklas }
2072159047fSniklas /* NOTREACHED */
208b305b0f1Sespie abort ();
2092159047fSniklas }
2102159047fSniklas
211*c074d1c9Sdrahn static bfd_signed_vma
vax_offset(modep)212*c074d1c9Sdrahn vax_offset (modep)
213*c074d1c9Sdrahn unsigned char *modep;
2142159047fSniklas {
215b305b0f1Sespie operandenum mode = vax_operandmode (modep);
2162159047fSniklas
217*c074d1c9Sdrahn ++modep; /* skip over the mode */
2182159047fSniklas switch (mode)
2192159047fSniklas {
2202159047fSniklas default:
2212159047fSniklas fprintf (stderr, "[reladdr] not relative address\n");
222*c074d1c9Sdrahn return 0;
2232159047fSniklas case byterel:
224*c074d1c9Sdrahn return 1 + bfd_get_signed_8 (core_bfd, modep);
2252159047fSniklas case wordrel:
226*c074d1c9Sdrahn return 2 + bfd_get_signed_16 (core_bfd, modep);
2272159047fSniklas case longrel:
228*c074d1c9Sdrahn return 4 + bfd_get_signed_32 (core_bfd, modep);
2292159047fSniklas }
2302159047fSniklas }
2312159047fSniklas
2322159047fSniklas
2332159047fSniklas void
vax_find_call(parent,p_lowpc,p_highpc)234b305b0f1Sespie vax_find_call (parent, p_lowpc, p_highpc)
2352159047fSniklas Sym *parent;
2362159047fSniklas bfd_vma p_lowpc;
2372159047fSniklas bfd_vma p_highpc;
2382159047fSniklas {
2392159047fSniklas unsigned char *instructp;
2402159047fSniklas long length;
2412159047fSniklas Sym *child;
2422159047fSniklas operandenum mode;
2432159047fSniklas operandenum firstmode;
244*c074d1c9Sdrahn bfd_vma pc, destpc;
245*c074d1c9Sdrahn static bfd_boolean inited = FALSE;
2462159047fSniklas
2472159047fSniklas if (!inited)
2482159047fSniklas {
2492159047fSniklas inited = TRUE;
2502159047fSniklas sym_init (&indirectchild);
2512159047fSniklas indirectchild.cg.prop.fract = 1.0;
2522159047fSniklas indirectchild.cg.cyc.head = &indirectchild;
2532159047fSniklas }
2542159047fSniklas
2552159047fSniklas if (core_text_space == 0)
2562159047fSniklas {
2572159047fSniklas return;
2582159047fSniklas }
2592159047fSniklas if (p_lowpc < s_lowpc)
2602159047fSniklas {
2612159047fSniklas p_lowpc = s_lowpc;
2622159047fSniklas }
2632159047fSniklas if (p_highpc > s_highpc)
2642159047fSniklas {
2652159047fSniklas p_highpc = s_highpc;
2662159047fSniklas }
2672159047fSniklas DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
268b305b0f1Sespie parent->name, (unsigned long) p_lowpc,
269b305b0f1Sespie (unsigned long) p_highpc));
270*c074d1c9Sdrahn for (pc = p_lowpc; pc < p_highpc; pc += length)
2712159047fSniklas {
2722159047fSniklas length = 1;
273*c074d1c9Sdrahn instructp = ((unsigned char *) core_text_space
274*c074d1c9Sdrahn + pc - core_text_sect->vma);
275*c074d1c9Sdrahn if ((*instructp & 0xff) == CALLS)
2762159047fSniklas {
2772159047fSniklas /*
2782159047fSniklas * maybe a calls, better check it out.
2792159047fSniklas * skip the count of the number of arguments.
2802159047fSniklas */
2812159047fSniklas DBG (CALLDEBUG,
282*c074d1c9Sdrahn printf ("[findcall]\t0x%lx:calls", (unsigned long) pc));
283*c074d1c9Sdrahn firstmode = vax_operandmode (instructp + length);
2842159047fSniklas switch (firstmode)
2852159047fSniklas {
2862159047fSniklas case literal:
2872159047fSniklas case immediate:
2882159047fSniklas break;
2892159047fSniklas default:
2902159047fSniklas goto botched;
2912159047fSniklas }
292*c074d1c9Sdrahn length += vax_operandlength (instructp + length);
293*c074d1c9Sdrahn mode = vax_operandmode (instructp + length);
2942159047fSniklas DBG (CALLDEBUG,
295b305b0f1Sespie printf ("\tfirst operand is %s", vax_operandname (firstmode));
296b305b0f1Sespie printf ("\tsecond operand is %s\n", vax_operandname (mode)));
2972159047fSniklas switch (mode)
2982159047fSniklas {
2992159047fSniklas case regdef:
3002159047fSniklas case bytedispdef:
3012159047fSniklas case worddispdef:
3022159047fSniklas case longdispdef:
3032159047fSniklas case bytereldef:
3042159047fSniklas case wordreldef:
3052159047fSniklas case longreldef:
3062159047fSniklas /*
3072159047fSniklas * indirect call: call through pointer
3082159047fSniklas * either *d(r) as a parameter or local
3092159047fSniklas * (r) as a return value
3102159047fSniklas * *f as a global pointer
3112159047fSniklas * [are there others that we miss?,
3122159047fSniklas * e.g. arrays of pointers to functions???]
3132159047fSniklas */
314b305b0f1Sespie arc_add (parent, &indirectchild, (unsigned long) 0);
315*c074d1c9Sdrahn length += vax_operandlength (instructp + length);
3162159047fSniklas continue;
3172159047fSniklas case byterel:
3182159047fSniklas case wordrel:
3192159047fSniklas case longrel:
3202159047fSniklas /*
3212159047fSniklas * regular pc relative addressing
3222159047fSniklas * check that this is the address of
3232159047fSniklas * a function.
3242159047fSniklas */
325*c074d1c9Sdrahn destpc = pc + vax_offset (instructp + length);
3262159047fSniklas if (destpc >= s_lowpc && destpc <= s_highpc)
3272159047fSniklas {
3282159047fSniklas child = sym_lookup (&symtab, destpc);
3292159047fSniklas DBG (CALLDEBUG,
330b305b0f1Sespie printf ("[findcall]\tdestpc 0x%lx",
331b305b0f1Sespie (unsigned long) destpc);
3322159047fSniklas printf (" child->name %s", child->name);
333b305b0f1Sespie printf (" child->addr 0x%lx\n",
334b305b0f1Sespie (unsigned long) child->addr);
3352159047fSniklas );
3362159047fSniklas if (child->addr == destpc)
3372159047fSniklas {
3382159047fSniklas /*
3392159047fSniklas * a hit
3402159047fSniklas */
341b305b0f1Sespie arc_add (parent, child, (unsigned long) 0);
342*c074d1c9Sdrahn length += vax_operandlength (instructp + length);
3432159047fSniklas continue;
3442159047fSniklas }
3452159047fSniklas goto botched;
3462159047fSniklas }
3472159047fSniklas /*
3482159047fSniklas * else:
3492159047fSniklas * it looked like a calls,
3502159047fSniklas * but it wasn't to anywhere.
3512159047fSniklas */
3522159047fSniklas goto botched;
3532159047fSniklas default:
3542159047fSniklas botched:
3552159047fSniklas /*
3562159047fSniklas * something funny going on.
3572159047fSniklas */
3582159047fSniklas DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
3592159047fSniklas length = 1;
3602159047fSniklas continue;
3612159047fSniklas }
3622159047fSniklas }
3632159047fSniklas }
3642159047fSniklas }
365