xref: /openbsd-src/gnu/usr.bin/binutils/gprof/vax.c (revision c074d1c999f3e07019cd5e9a2f190b057ef3b935)
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