Blame gprof/tahoe.c

Packit Service 72eb06
/*
Packit Service 72eb06
 * Copyright (c) 1983, 1993, 2001
Packit Service 72eb06
 *      The Regents of the University of California.  All rights reserved.
Packit Service 72eb06
 *
Packit Service 72eb06
 * Redistribution and use in source and binary forms, with or without
Packit Service 72eb06
 * modification, are permitted provided that the following conditions
Packit Service 72eb06
 * are met:
Packit Service 72eb06
 * 1. Redistributions of source code must retain the above copyright
Packit Service 72eb06
 *    notice, this list of conditions and the following disclaimer.
Packit Service 72eb06
 * 2. Redistributions in binary form must reproduce the above copyright
Packit Service 72eb06
 *    notice, this list of conditions and the following disclaimer in the
Packit Service 72eb06
 *    documentation and/or other materials provided with the distribution.
Packit Service 72eb06
 * 3. Neither the name of the University nor the names of its contributors
Packit Service 72eb06
 *    may be used to endorse or promote products derived from this software
Packit Service 72eb06
 *    without specific prior written permission.
Packit Service 72eb06
 *
Packit Service 72eb06
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
Packit Service 72eb06
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit Service 72eb06
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit Service 72eb06
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
Packit Service 72eb06
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit Service 72eb06
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
Packit Service 72eb06
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit Service 72eb06
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
Packit Service 72eb06
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
Packit Service 72eb06
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
Packit Service 72eb06
 * SUCH DAMAGE.
Packit Service 72eb06
 */
Packit Service 72eb06
#include "gprof.h"
Packit Service 72eb06
#include "search_list.h"
Packit Service 72eb06
#include "source.h"
Packit Service 72eb06
#include "symtab.h"
Packit Service 72eb06
#include "cg_arcs.h"
Packit Service 72eb06
#include "corefile.h"
Packit Service 72eb06
#include "hist.h"
Packit Service 72eb06
Packit Service 72eb06
    /*
Packit Service 72eb06
     *        opcode of the `callf' instruction
Packit Service 72eb06
     */
Packit Service 72eb06
#define	CALLF	0xfe
Packit Service 72eb06
Packit Service 72eb06
    /*
Packit Service 72eb06
     *        register for pc relative addressing
Packit Service 72eb06
     */
Packit Service 72eb06
#define	PC	0xf
Packit Service 72eb06
Packit Service 72eb06
enum tahoe_opermodes
Packit Service 72eb06
  {
Packit Service 72eb06
    literal, indexed, reg, regdef, autodec, autoinc, autoincdef,
Packit Service 72eb06
    bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef,
Packit Service 72eb06
    immediate, absolute, byterel, bytereldef, wordrel, wordreldef,
Packit Service 72eb06
    longrel, longreldef
Packit Service 72eb06
  };
Packit Service 72eb06
typedef enum tahoe_opermodes tahoe_operandenum;
Packit Service 72eb06
Packit Service 72eb06
/*
Packit Service 72eb06
 * A symbol to be the child of indirect callf:
Packit Service 72eb06
 */
Packit Service 72eb06
static Sym indirectchild;
Packit Service 72eb06
Packit Service 72eb06
static tahoe_operandenum tahoe_operandmode (unsigned char *);
Packit Service 72eb06
static char *tahoe_operandname (tahoe_operandenum);
Packit Service 72eb06
static long tahoe_operandlength (unsigned char *);
Packit Service 72eb06
static bfd_signed_vma tahoe_offset (unsigned char *);
Packit Service 72eb06
void tahoe_find_call (Sym *, bfd_vma, bfd_vma);
Packit Service 72eb06
Packit Service 72eb06
static tahoe_operandenum
Packit Service 72eb06
tahoe_operandmode (unsigned char *modep)
Packit Service 72eb06
{
Packit Service 72eb06
  long usesreg = *modep & 0xf;
Packit Service 72eb06
Packit Service 72eb06
  switch ((*modep >> 4) & 0xf)
Packit Service 72eb06
    {
Packit Service 72eb06
    case 0:
Packit Service 72eb06
    case 1:
Packit Service 72eb06
    case 2:
Packit Service 72eb06
    case 3:
Packit Service 72eb06
      return literal;
Packit Service 72eb06
    case 4:
Packit Service 72eb06
      return indexed;
Packit Service 72eb06
    case 5:
Packit Service 72eb06
      return reg;
Packit Service 72eb06
    case 6:
Packit Service 72eb06
      return regdef;
Packit Service 72eb06
    case 7:
Packit Service 72eb06
      return autodec;
Packit Service 72eb06
    case 8:
Packit Service 72eb06
      return usesreg != 0xe ? autoinc : immediate;
Packit Service 72eb06
    case 9:
Packit Service 72eb06
      return usesreg != PC ? autoincdef : absolute;
Packit Service 72eb06
    case 10:
Packit Service 72eb06
      return usesreg != PC ? bytedisp : byterel;
Packit Service 72eb06
    case 11:
Packit Service 72eb06
      return usesreg != PC ? bytedispdef : bytereldef;
Packit Service 72eb06
    case 12:
Packit Service 72eb06
      return usesreg != PC ? worddisp : wordrel;
Packit Service 72eb06
    case 13:
Packit Service 72eb06
      return usesreg != PC ? worddispdef : wordreldef;
Packit Service 72eb06
    case 14:
Packit Service 72eb06
      return usesreg != PC ? longdisp : longrel;
Packit Service 72eb06
    case 15:
Packit Service 72eb06
      return usesreg != PC ? longdispdef : longreldef;
Packit Service 72eb06
    }
Packit Service 72eb06
  /* NOTREACHED */
Packit Service 72eb06
  abort ();
Packit Service 72eb06
}
Packit Service 72eb06
Packit Service 72eb06
static char *
Packit Service 72eb06
tahoe_operandname (tahoe_operandenum mode)
Packit Service 72eb06
{
Packit Service 72eb06
Packit Service 72eb06
  switch (mode)
Packit Service 72eb06
    {
Packit Service 72eb06
    case literal:
Packit Service 72eb06
      return "literal";
Packit Service 72eb06
    case indexed:
Packit Service 72eb06
      return "indexed";
Packit Service 72eb06
    case reg:
Packit Service 72eb06
      return "register";
Packit Service 72eb06
    case regdef:
Packit Service 72eb06
      return "register deferred";
Packit Service 72eb06
    case autodec:
Packit Service 72eb06
      return "autodecrement";
Packit Service 72eb06
    case autoinc:
Packit Service 72eb06
      return "autoincrement";
Packit Service 72eb06
    case autoincdef:
Packit Service 72eb06
      return "autoincrement deferred";
Packit Service 72eb06
    case bytedisp:
Packit Service 72eb06
      return "byte displacement";
Packit Service 72eb06
    case bytedispdef:
Packit Service 72eb06
      return "byte displacement deferred";
Packit Service 72eb06
    case byterel:
Packit Service 72eb06
      return "byte relative";
Packit Service 72eb06
    case bytereldef:
Packit Service 72eb06
      return "byte relative deferred";
Packit Service 72eb06
    case worddisp:
Packit Service 72eb06
      return "word displacement";
Packit Service 72eb06
    case worddispdef:
Packit Service 72eb06
      return "word displacement deferred";
Packit Service 72eb06
    case wordrel:
Packit Service 72eb06
      return "word relative";
Packit Service 72eb06
    case wordreldef:
Packit Service 72eb06
      return "word relative deferred";
Packit Service 72eb06
    case immediate:
Packit Service 72eb06
      return "immediate";
Packit Service 72eb06
    case absolute:
Packit Service 72eb06
      return "absolute";
Packit Service 72eb06
    case longdisp:
Packit Service 72eb06
      return "long displacement";
Packit Service 72eb06
    case longdispdef:
Packit Service 72eb06
      return "long displacement deferred";
Packit Service 72eb06
    case longrel:
Packit Service 72eb06
      return "long relative";
Packit Service 72eb06
    case longreldef:
Packit Service 72eb06
      return "long relative deferred";
Packit Service 72eb06
    }
Packit Service 72eb06
  /* NOTREACHED */
Packit Service 72eb06
  abort ();
Packit Service 72eb06
}
Packit Service 72eb06
Packit Service 72eb06
static long
Packit Service 72eb06
tahoe_operandlength (unsigned char *modep
Packit Service 72eb06
)
Packit Service 72eb06
{
Packit Service 72eb06
Packit Service 72eb06
  switch (tahoe_operandmode (modep))
Packit Service 72eb06
    {
Packit Service 72eb06
    case literal:
Packit Service 72eb06
    case reg:
Packit Service 72eb06
    case regdef:
Packit Service 72eb06
    case autodec:
Packit Service 72eb06
    case autoinc:
Packit Service 72eb06
    case autoincdef:
Packit Service 72eb06
      return 1;
Packit Service 72eb06
    case bytedisp:
Packit Service 72eb06
    case bytedispdef:
Packit Service 72eb06
    case byterel:
Packit Service 72eb06
    case bytereldef:
Packit Service 72eb06
      return 2;
Packit Service 72eb06
    case worddisp:
Packit Service 72eb06
    case worddispdef:
Packit Service 72eb06
    case wordrel:
Packit Service 72eb06
    case wordreldef:
Packit Service 72eb06
      return 3;
Packit Service 72eb06
    case immediate:
Packit Service 72eb06
    case absolute:
Packit Service 72eb06
    case longdisp:
Packit Service 72eb06
    case longdispdef:
Packit Service 72eb06
    case longrel:
Packit Service 72eb06
    case longreldef:
Packit Service 72eb06
      return 5;
Packit Service 72eb06
    case indexed:
Packit Service 72eb06
      return 1 + tahoe_operandlength (modep + 1);
Packit Service 72eb06
    }
Packit Service 72eb06
  /* NOTREACHED */
Packit Service 72eb06
  abort ();
Packit Service 72eb06
}
Packit Service 72eb06
Packit Service 72eb06
static bfd_signed_vma
Packit Service 72eb06
tahoe_offset (unsigned char *modep)
Packit Service 72eb06
{
Packit Service 72eb06
  tahoe_operandenum mode = tahoe_operandmode (modep);
Packit Service 72eb06
Packit Service 72eb06
  ++modep;				/* skip over the mode */
Packit Service 72eb06
  switch (mode)
Packit Service 72eb06
    {
Packit Service 72eb06
    default:
Packit Service 72eb06
      fprintf (stderr, "[reladdr] not relative address\n");
Packit Service 72eb06
      return 0;
Packit Service 72eb06
    case byterel:
Packit Service 72eb06
      return 1 + bfd_get_signed_8 (core_bfd, modep);
Packit Service 72eb06
    case wordrel:
Packit Service 72eb06
      return 2 + bfd_get_signed_16 (core_bfd, modep);
Packit Service 72eb06
    case longrel:
Packit Service 72eb06
      return 4 + bfd_get_signed_32 (core_bfd, modep);
Packit Service 72eb06
    }
Packit Service 72eb06
}
Packit Service 72eb06
Packit Service 72eb06
void
Packit Service 72eb06
tahoe_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
Packit Service 72eb06
{
Packit Service 72eb06
  unsigned char *instructp;
Packit Service 72eb06
  long length;
Packit Service 72eb06
  Sym *child;
Packit Service 72eb06
  tahoe_operandenum mode;
Packit Service 72eb06
  tahoe_operandenum firstmode;
Packit Service 72eb06
  bfd_vma pc, destpc;
Packit Service 72eb06
  static bfd_boolean inited = FALSE;
Packit Service 72eb06
Packit Service 72eb06
  if (!inited)
Packit Service 72eb06
    {
Packit Service 72eb06
      inited = TRUE;
Packit Service 72eb06
      sym_init (&indirectchild);
Packit Service 72eb06
      indirectchild.cg.prop.fract = 1.0;
Packit Service 72eb06
      indirectchild.cg.cyc.head = &indirectchild;
Packit Service 72eb06
    }
Packit Service 72eb06
Packit Service 72eb06
  DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
Packit Service 72eb06
			  parent->name, (unsigned long) p_lowpc,
Packit Service 72eb06
			  (unsigned long) p_highpc));
Packit Service 72eb06
  for (pc = p_lowpc; pc < p_highpc; pc += length)
Packit Service 72eb06
    {
Packit Service 72eb06
      length = 1;
Packit Service 72eb06
      instructp = ((unsigned char *) core_text_space
Packit Service 72eb06
		   + pc - core_text_sect->vma);
Packit Service 72eb06
      if ((*instructp & 0xff) == CALLF)
Packit Service 72eb06
	{
Packit Service 72eb06
	  /*
Packit Service 72eb06
	   *    maybe a callf, better check it out.
Packit Service 72eb06
	   *      skip the count of the number of arguments.
Packit Service 72eb06
	   */
Packit Service 72eb06
	  DBG (CALLDEBUG, printf ("[findcall]\t0x%lx:callf",
Packit Service 72eb06
				  (unsigned long) pc));
Packit Service 72eb06
	  firstmode = tahoe_operandmode (instructp + length);
Packit Service 72eb06
	  switch (firstmode)
Packit Service 72eb06
	    {
Packit Service 72eb06
	    case literal:
Packit Service 72eb06
	    case immediate:
Packit Service 72eb06
	      break;
Packit Service 72eb06
	    default:
Packit Service 72eb06
	      goto botched;
Packit Service 72eb06
	    }
Packit Service 72eb06
	  length += tahoe_operandlength (instructp + length);
Packit Service 72eb06
	  mode = tahoe_operandmode (instructp + length);
Packit Service 72eb06
	  DBG (CALLDEBUG,
Packit Service 72eb06
	       printf ("\tfirst operand is %s", tahoe_operandname (firstmode));
Packit Service 72eb06
	       printf ("\tsecond operand is %s\n", tahoe_operandname (mode));
Packit Service 72eb06
	    );
Packit Service 72eb06
	  switch (mode)
Packit Service 72eb06
	    {
Packit Service 72eb06
	    case regdef:
Packit Service 72eb06
	    case bytedispdef:
Packit Service 72eb06
	    case worddispdef:
Packit Service 72eb06
	    case longdispdef:
Packit Service 72eb06
	    case bytereldef:
Packit Service 72eb06
	    case wordreldef:
Packit Service 72eb06
	    case longreldef:
Packit Service 72eb06
	      /*
Packit Service 72eb06
	       *    indirect call: call through pointer
Packit Service 72eb06
	       *      either  *d(r)   as a parameter or local
Packit Service 72eb06
	       *              (r)     as a return value
Packit Service 72eb06
	       *              *f      as a global pointer
Packit Service 72eb06
	       *      [are there others that we miss?,
Packit Service 72eb06
	       *       e.g. arrays of pointers to functions???]
Packit Service 72eb06
	       */
Packit Service 72eb06
	      arc_add (parent, &indirectchild, (unsigned long) 0);
Packit Service 72eb06
	      length += tahoe_operandlength (instructp + length);
Packit Service 72eb06
	      continue;
Packit Service 72eb06
	    case byterel:
Packit Service 72eb06
	    case wordrel:
Packit Service 72eb06
	    case longrel:
Packit Service 72eb06
	      /*
Packit Service 72eb06
	       *    regular pc relative addressing
Packit Service 72eb06
	       *      check that this is the address of
Packit Service 72eb06
	       *      a function.
Packit Service 72eb06
	       */
Packit Service 72eb06
	      destpc = pc + tahoe_offset (instructp + length);
Packit Service 72eb06
	      if (hist_check_address (destpc))
Packit Service 72eb06
		{
Packit Service 72eb06
		  child = sym_lookup (&symtab, destpc);
Packit Service 72eb06
                  if (child)
Packit Service 72eb06
		    {
Packit Service 72eb06
		      DBG (CALLDEBUG,
Packit Service 72eb06
		           printf ("[findcall]\tdestpc 0x%lx",
Packit Service 72eb06
			           (unsigned long) destpc);
Packit Service 72eb06
		           printf (" child->name %s", child->name);
Packit Service 72eb06
		           printf (" child->addr 0x%lx\n",
Packit Service 72eb06
			           (unsigned long) child->addr);
Packit Service 72eb06
		        );
Packit Service 72eb06
		      if (child->addr == destpc)
Packit Service 72eb06
		        {
Packit Service 72eb06
		          /*
Packit Service 72eb06
		           *    a hit
Packit Service 72eb06
		           */
Packit Service 72eb06
		          arc_add (parent, child, (unsigned long) 0);
Packit Service 72eb06
		          length += tahoe_operandlength (instructp + length);
Packit Service 72eb06
		          continue;
Packit Service 72eb06
		        }
Packit Service 72eb06
		    }
Packit Service 72eb06
		  goto botched;
Packit Service 72eb06
		}
Packit Service 72eb06
	      /*
Packit Service 72eb06
	       *    else:
Packit Service 72eb06
	       *      it looked like a callf,
Packit Service 72eb06
	       *      but it wasn't to anywhere.
Packit Service 72eb06
	       */
Packit Service 72eb06
	      goto botched;
Packit Service 72eb06
	    default:
Packit Service 72eb06
	    botched:
Packit Service 72eb06
	      /*
Packit Service 72eb06
	       *    something funny going on.
Packit Service 72eb06
	       */
Packit Service 72eb06
	      DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
Packit Service 72eb06
	      length = 1;
Packit Service 72eb06
	      continue;
Packit Service 72eb06
	    }
Packit Service 72eb06
	}
Packit Service 72eb06
    }
Packit Service 72eb06
}