Пример #1
0
void
aarch64_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
{
  bfd_vma pc, dest_pc, offset;
  unsigned int insn;
  Sym *child;

  DBG (CALLDEBUG, printf ("[find_call] %s: 0x%lx to 0x%lx\n",
			  parent->name, (unsigned long) p_lowpc,
			  (unsigned long) p_highpc));

  for (pc = p_lowpc; pc < p_highpc; pc += 4)
    {

      insn = bfd_get_32 (core_bfd, ((unsigned char *) core_text_space
				    + pc - core_text_sect->vma));

      if ((insn & BRANCH_MASK) == BRANCH_PATTERN)
	{
	  DBG (CALLDEBUG,
	       printf ("[find_call] 0x%lx: bl", (unsigned long) pc));

	  /* Regular pc relative addressing check that this is the
	     address of a function.  */
	  offset = ((((bfd_vma) insn & 0x3ffffff) ^ 0x2000000) - 0x2000000) << 2;

	  dest_pc = pc + offset;

	  if (hist_check_address (dest_pc))
	    {
	      child = sym_lookup (&symtab, dest_pc);

	      if (child)
		{
		  DBG (CALLDEBUG,
		       printf ("\tdest_pc=0x%lx, (name=%s, addr=0x%lx)\n",
			       (unsigned long) dest_pc, child->name,
			       (unsigned long) child->addr));

		  if (child->addr == dest_pc)
		    {
		      /* a hit.  */
		      arc_add (parent, child, (unsigned long) 0);
		      continue;
		    }
		}
	    }

	  /* Something funny going on.  */
	  DBG (CALLDEBUG, printf ("\tbut it's a botch\n"));
	}
    }
}
Пример #2
0
void
i386_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
{
  unsigned char *instructp;
  Sym *child;
  bfd_vma pc, destpc;

  DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
			  parent->name, (unsigned long) p_lowpc,
			  (unsigned long) p_highpc));

  for (pc = p_lowpc; pc < p_highpc; ++pc)
    {
      instructp = (unsigned char *) core_text_space + pc - core_text_sect->vma;
      if (i386_iscall (instructp))
	{
	  DBG (CALLDEBUG,
	       printf ("[findcall]\t0x%lx:call", (unsigned long) pc));
	  /*
	   *  regular pc relative addressing
	   *    check that this is the address of
	   *    a function.
	   */

	  destpc = bfd_get_32 (core_bfd[0], instructp + 1) + pc + 5;
	  if (hist_check_address (destpc))
	    {
	      child = sym_lookup (&symtab, destpc);
	      if (child && child->addr == destpc)
		{
		  /*
		   *      a hit
		   */
		  DBG (CALLDEBUG,
		       printf ("\tdestpc 0x%lx (%s)\n",
			       (unsigned long) destpc, child->name));
		  arc_add (parent, child, (unsigned long) 0);
		  instructp += 4;	/* call is a 5 byte instruction */
		  continue;
		}
	    }
	  /*
	   *  else:
	   *    it looked like a callf, but it:
	   *      a) wasn't actually a callf, or
	   *      b) didn't point to a known function in the symtab, or
	   *      c) something funny is going on.
	   */
	  DBG (CALLDEBUG, printf ("\tbut it's a botch\n"));
	}
    }
}
Пример #3
0
/*
 * On the Alpha we can only detect PC relative calls, which are
 * usually generated for calls to functions within the same
 * object file only.  This is still better than nothing, however.
 * (In particular it should be possible to find functions that
 *  potentially call integer division routines, for example.)
 */
void
alpha_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
{
  bfd_vma pc, dest_pc;
  unsigned int insn;
  Sym *child;

  if (indirect_child.name == NULL)
    {
      sym_init (&indirect_child);
      indirect_child.name = _("<indirect child>");
      indirect_child.cg.prop.fract = 1.0;
      indirect_child.cg.cyc.head = &indirect_child;
    }

  DBG (CALLDEBUG, printf (_("[find_call] %s: 0x%lx to 0x%lx\n"),
			  parent->name, (unsigned long) p_lowpc,
			  (unsigned long) p_highpc));
  for (pc = (p_lowpc + 3) & ~(bfd_vma) 3; pc < p_highpc; pc += 4)
    {
      insn = bfd_get_32 (core_bfd[0], ((unsigned char *) core_text_space
				    + pc - core_text_sect->vma));
      switch (insn & (0x3f << 26))
	{
	case OP_Jxx << 26:
	  /*
	   * There is no simple and reliable way to determine the
	   * target of a jsr (the hint bits help, but there aren't
	   * enough bits to get a satisfactory hit rate).  Instead,
	   * for any indirect jump we simply add an arc from PARENT
	   * to INDIRECT_CHILD---that way the user it at least able
	   * to see that there are other calls as well.
	   */
	  if ((insn & (3 << 14)) == Jxx_FUNC_JSR << 14
	      || (insn & (3 << 14)) == Jxx_FUNC_JSR_COROUTINE << 14)
	    {
	      DBG (CALLDEBUG,
		   printf (_("[find_call] 0x%lx: jsr%s <indirect_child>\n"),
			   (unsigned long) pc,
			   ((insn & (3 << 14)) == Jxx_FUNC_JSR << 14
			    ? "" : "_coroutine")));
	      arc_add (parent, &indirect_child, (unsigned long) 0);
	    }
	  break;

	case OP_BSR << 26:
	  DBG (CALLDEBUG,
	       printf (_("[find_call] 0x%lx: bsr"), (unsigned long) pc));
	  /*
	   * Regular PC relative addressing.  Check that this is the
	   * address of a function.  The linker sometimes redirects
	   * the entry point by 8 bytes to skip loading the global
	   * pointer, so we allow for either address:
	   */
	  dest_pc = pc + 4 + (((bfd_signed_vma) (insn & 0x1fffff)
			       ^ 0x100000) - 0x100000);
	  if (hist_check_address (dest_pc))
	    {
	      child = sym_lookup (&symtab, dest_pc);
              if (child)
                {
	          DBG (CALLDEBUG,
		       printf (" 0x%lx\t; name=%s, addr=0x%lx",
			       (unsigned long) dest_pc, child->name,
			       (unsigned long) child->addr));
	          if (child->addr == dest_pc || child->addr == dest_pc - 8)
		    {
		      DBG (CALLDEBUG, printf ("\n"));
		      /* a hit:  */
		      arc_add (parent, child, (unsigned long) 0);
		      continue;
		    }
                }
	    }
	  /*
	   * Something funny going on.
	   */
	  DBG (CALLDEBUG, printf ("\tbut it's a botch\n"));
	  break;

	default:
	  break;
	}
    }
}