(root)/
binutils-2.41/
gprof/
vax.c
       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 `calls' instruction
      39       */
      40  #define	CALLS	0xfb
      41  
      42      /*
      43       *        register for pc relative addressing
      44       */
      45  #define	PC	0xf
      46  
      47  enum 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 opermodes operandenum;
      55  
      56  /* *INDENT-OFF* */
      57  /* Here to document only.  We can't use this when cross compiling as
      58     the bitfield layout might not be the same as native.
      59  
      60     struct modebyte
      61       {
      62         unsigned int regfield:4;
      63         unsigned int modefield:4;
      64       };
      65  */
      66  /* *INDENT-ON* */
      67  
      68  /*
      69   * A symbol to be the child of indirect calls:
      70   */
      71  static Sym indirectchild;
      72  
      73  static operandenum vax_operandmode (unsigned char *);
      74  static char *vax_operandname (operandenum);
      75  static long vax_operandlength (unsigned char *);
      76  static bfd_signed_vma vax_offset (unsigned char *);
      77  void vax_find_call (Sym *, bfd_vma, bfd_vma);
      78  
      79  static operandenum
      80  vax_operandmode (unsigned char *modep)
      81  {
      82    int usesreg = *modep & 0xf;
      83  
      84    switch ((*modep >> 4) & 0xf)
      85      {
      86      case 0:
      87      case 1:
      88      case 2:
      89      case 3:
      90        return literal;
      91      case 4:
      92        return indexed;
      93      case 5:
      94        return reg;
      95      case 6:
      96        return regdef;
      97      case 7:
      98        return autodec;
      99      case 8:
     100        return usesreg != PC ? autoinc : immediate;
     101      case 9:
     102        return usesreg != PC ? autoincdef : absolute;
     103      case 10:
     104        return usesreg != PC ? bytedisp : byterel;
     105      case 11:
     106        return usesreg != PC ? bytedispdef : bytereldef;
     107      case 12:
     108        return usesreg != PC ? worddisp : wordrel;
     109      case 13:
     110        return usesreg != PC ? worddispdef : wordreldef;
     111      case 14:
     112        return usesreg != PC ? longdisp : longrel;
     113      case 15:
     114        return usesreg != PC ? longdispdef : longreldef;
     115      }
     116    /* NOTREACHED */
     117    abort ();
     118  }
     119  
     120  static char *
     121  vax_operandname (operandenum mode)
     122  {
     123  
     124    switch (mode)
     125      {
     126      case literal:
     127        return "literal";
     128      case indexed:
     129        return "indexed";
     130      case reg:
     131        return "register";
     132      case regdef:
     133        return "register deferred";
     134      case autodec:
     135        return "autodecrement";
     136      case autoinc:
     137        return "autoincrement";
     138      case autoincdef:
     139        return "autoincrement deferred";
     140      case bytedisp:
     141        return "byte displacement";
     142      case bytedispdef:
     143        return "byte displacement deferred";
     144      case byterel:
     145        return "byte relative";
     146      case bytereldef:
     147        return "byte relative deferred";
     148      case worddisp:
     149        return "word displacement";
     150      case worddispdef:
     151        return "word displacement deferred";
     152      case wordrel:
     153        return "word relative";
     154      case wordreldef:
     155        return "word relative deferred";
     156      case immediate:
     157        return "immediate";
     158      case absolute:
     159        return "absolute";
     160      case longdisp:
     161        return "long displacement";
     162      case longdispdef:
     163        return "long displacement deferred";
     164      case longrel:
     165        return "long relative";
     166      case longreldef:
     167        return "long relative deferred";
     168      }
     169    /* NOTREACHED */
     170    abort ();
     171  }
     172  
     173  static long
     174  vax_operandlength (unsigned char *modep)
     175  {
     176  
     177    switch (vax_operandmode (modep))
     178      {
     179      case literal:
     180      case reg:
     181      case regdef:
     182      case autodec:
     183      case autoinc:
     184      case autoincdef:
     185        return 1;
     186      case bytedisp:
     187      case bytedispdef:
     188      case byterel:
     189      case bytereldef:
     190        return 2;
     191      case worddisp:
     192      case worddispdef:
     193      case wordrel:
     194      case wordreldef:
     195        return 3;
     196      case immediate:
     197      case absolute:
     198      case longdisp:
     199      case longdispdef:
     200      case longrel:
     201      case longreldef:
     202        return 5;
     203      case indexed:
     204        return 1 + vax_operandlength (modep + 1);
     205      }
     206    /* NOTREACHED */
     207    abort ();
     208  }
     209  
     210  static bfd_signed_vma
     211  vax_offset (unsigned char *modep)
     212  {
     213    operandenum mode = vax_operandmode (modep);
     214  
     215    ++modep;				/* skip over the mode */
     216    switch (mode)
     217      {
     218      default:
     219        fprintf (stderr, "[reladdr] not relative address\n");
     220        return 0;
     221      case byterel:
     222        return 1 + bfd_get_signed_8 (core_bfd, modep);
     223      case wordrel:
     224        return 2 + bfd_get_signed_16 (core_bfd, modep);
     225      case longrel:
     226        return 4 + bfd_get_signed_32 (core_bfd, modep);
     227      }
     228  }
     229  
     230  
     231  void
     232  vax_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
     233  {
     234    unsigned char *instructp;
     235    long length;
     236    Sym *child;
     237    operandenum mode;
     238    operandenum firstmode;
     239    bfd_vma pc, 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    DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
     251  			  parent->name, (unsigned long) p_lowpc,
     252  			  (unsigned long) p_highpc));
     253    for (pc = p_lowpc; pc < p_highpc; pc += length)
     254      {
     255        length = 1;
     256        instructp = ((unsigned char *) core_text_space
     257  		   + pc - core_text_sect->vma);
     258        if ((*instructp & 0xff) == CALLS)
     259  	{
     260  	  /*
     261  	   *    maybe a calls, better check it out.
     262  	   *      skip the count of the number of arguments.
     263  	   */
     264  	  DBG (CALLDEBUG,
     265  	       printf ("[findcall]\t0x%lx:calls", (unsigned long) pc));
     266  	  firstmode = vax_operandmode (instructp + length);
     267  	  switch (firstmode)
     268  	    {
     269  	    case literal:
     270  	    case immediate:
     271  	      break;
     272  	    default:
     273  	      goto botched;
     274  	    }
     275  	  length += vax_operandlength (instructp + length);
     276  	  mode = vax_operandmode (instructp + length);
     277  	  DBG (CALLDEBUG,
     278  	       printf ("\tfirst operand is %s", vax_operandname (firstmode));
     279  	       printf ("\tsecond operand is %s\n", vax_operandname (mode)));
     280  	  switch (mode)
     281  	    {
     282  	    case regdef:
     283  	    case bytedispdef:
     284  	    case worddispdef:
     285  	    case longdispdef:
     286  	    case bytereldef:
     287  	    case wordreldef:
     288  	    case longreldef:
     289  	      /*
     290  	       *    indirect call: call through pointer
     291  	       *      either  *d(r)   as a parameter or local
     292  	       *              (r)     as a return value
     293  	       *              *f      as a global pointer
     294  	       *      [are there others that we miss?,
     295  	       *       e.g. arrays of pointers to functions???]
     296  	       */
     297  	      arc_add (parent, &indirectchild, (unsigned long) 0);
     298  	      length += vax_operandlength (instructp + length);
     299  	      continue;
     300  	    case byterel:
     301  	    case wordrel:
     302  	    case longrel:
     303  	      /*
     304  	       *    regular pc relative addressing
     305  	       *      check that this is the address of
     306  	       *      a function.
     307  	       */
     308  	      destpc = pc + vax_offset (instructp + length);
     309  	      if (hist_check_address (destpc))
     310  		{
     311  		  child = sym_lookup (&symtab, destpc);
     312  		  if (child)
     313  		    {
     314  		      DBG (CALLDEBUG,
     315  		           printf ("[findcall]\tdestpc 0x%lx",
     316  			           (unsigned long) destpc);
     317  		           printf (" child->name %s", child->name);
     318  		           printf (" child->addr 0x%lx\n",
     319  			           (unsigned long) child->addr);
     320  		        );
     321  		      if (child->addr == destpc)
     322  		        {
     323  		          /*
     324  		           *    a hit
     325  		           */
     326  		          arc_add (parent, child, (unsigned long) 0);
     327  		          length += vax_operandlength (instructp + length);
     328  		          continue;
     329  		        }
     330  		    }
     331  		  goto botched;
     332  		}
     333  	      /*
     334  	       *    else:
     335  	       *      it looked like a calls,
     336  	       *      but it wasn't to anywhere.
     337  	       */
     338  	      goto botched;
     339  	    default:
     340  	    botched:
     341  	      /*
     342  	       *    something funny going on.
     343  	       */
     344  	      DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
     345  	      length = 1;
     346  	      continue;
     347  	    }
     348  	}
     349      }
     350  }