예제 #1
0
CORE_ADDR
sparcnbsd_step_trap (struct frame_info *frame, unsigned long insn)
{
  if ((X_I (insn) == 0 && X_RS1 (insn) == 0 && X_RS2 (insn) == 0)
      || (X_I (insn) == 1 && X_RS1 (insn) == 0 && (insn & 0x7f) == 0))
    {
      /* "New" system call.  */
      ULONGEST number = get_frame_register_unsigned (frame, SPARC_G1_REGNUM);

      if (number & 0x400)
	return get_frame_register_unsigned (frame, SPARC_G2_REGNUM);
      if (number & 0x800)
	return get_frame_register_unsigned (frame, SPARC_G7_REGNUM);
    }

  return 0;
}
예제 #2
0
static CORE_ADDR
sparc32_skip_prologue (CORE_ADDR start_pc)
{
  struct symtab_and_line sal;
  CORE_ADDR func_start, func_end;
  struct sparc_frame_cache cache;

  /* This is the preferred method, find the end of the prologue by
     using the debugging information.  */
  if (find_pc_partial_function (start_pc, NULL, &func_start, &func_end))
    {
      sal = find_pc_line (func_start, 0);

      if (sal.end < func_end
	  && start_pc <= sal.end)
	return sal.end;
    }

  start_pc = sparc_analyze_prologue (start_pc, 0xffffffffUL, &cache);

  /* The psABI says that "Although the first 6 words of arguments
     reside in registers, the standard stack frame reserves space for
     them.".  It also suggests that a function may use that space to
     "write incoming arguments 0 to 5" into that space, and that's
     indeed what GCC seems to be doing.  In that case GCC will
     generate debug information that points to the stack slots instead
     of the registers, so we should consider the instructions that
     write out these incoming arguments onto the stack.  Of course we
     only need to do this if we have a stack frame.  */

  while (!cache.frameless_p)
    {
      unsigned long insn = sparc_fetch_instruction (start_pc);

      /* Recognize instructions that store incoming arguments in
         %i0...%i5 into the corresponding stack slot.  */
      if (X_OP (insn) == 3 && (X_OP3 (insn) & 0x3c) == 0x04 && X_I (insn)
	  && (X_RD (insn) >= 24 && X_RD (insn) <= 29) && X_RS1 (insn) == 30
	  && X_SIMM13 (insn) == 68 + (X_RD (insn) - 24) * 4)
	{
	  start_pc += 4;
	  continue;
	}

      break;
    }

  return start_pc;
}
예제 #3
0
int
print_insn_sparc (bfd_vma memaddr, disassemble_info *info)
{
  FILE *stream = info->stream;
  bfd_byte buffer[4];
  unsigned long insn;
  sparc_opcode_hash *op;
  /* Nonzero of opcode table has been initialized.  */
  static int opcodes_initialized = 0;
  /* bfd mach number of last call.  */
  static unsigned long current_mach = 0;
  bfd_vma (*getword) (const void *);

  if (!opcodes_initialized
      || info->mach != current_mach)
    {
      int i;

      current_arch_mask = compute_arch_mask (info->mach);

      if (!opcodes_initialized)
	sorted_opcodes =
	  xmalloc (sparc_num_opcodes * sizeof (sparc_opcode *));
      /* Reset the sorted table so we can resort it.  */
      for (i = 0; i < sparc_num_opcodes; ++i)
	sorted_opcodes[i] = &sparc_opcodes[i];
      qsort ((char *) sorted_opcodes, sparc_num_opcodes,
	     sizeof (sorted_opcodes[0]), compare_opcodes);

      build_hash_table (sorted_opcodes, opcode_hash_table, sparc_num_opcodes);
      current_mach = info->mach;
      opcodes_initialized = 1;
    }

  {
    int status =
      (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info);

    if (status != 0)
      {
	(*info->memory_error_func) (status, memaddr, info);
	return -1;
      }
  }

  /* On SPARClite variants such as DANlite (sparc86x), instructions
     are always big-endian even when the machine is in little-endian mode.  */
  if (info->endian == BFD_ENDIAN_BIG || info->mach == bfd_mach_sparc_sparclite)
    getword = bfd_getb32;
  else
    getword = bfd_getl32;

  insn = getword (buffer);

  info->insn_info_valid = 1;			/* We do return this info.  */
  info->insn_type = dis_nonbranch;		/* Assume non branch insn.  */
  info->branch_delay_insns = 0;			/* Assume no delay.  */
  info->target = 0;				/* Assume no target known.  */

  for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next)
    {
      const sparc_opcode *opcode = op->opcode;

      /* If the insn isn't supported by the current architecture, skip it.  */
      if (! (opcode->architecture & current_arch_mask))
	continue;

      if ((opcode->match & insn) == opcode->match
	  && (opcode->lose & insn) == 0)
	{
	  /* Nonzero means that we have found an instruction which has
	     the effect of adding or or'ing the imm13 field to rs1.  */
	  int imm_added_to_rs1 = 0;
	  int imm_ored_to_rs1 = 0;

	  /* Nonzero means that we have found a plus sign in the args
	     field of the opcode table.  */
	  int found_plus = 0;

	  /* Nonzero means we have an annulled branch.  */
	  int is_annulled = 0;

	  /* Do we have an `add' or `or' instruction combining an
             immediate with rs1?  */
	  if (opcode->match == 0x80102000) /* or */
	    imm_ored_to_rs1 = 1;
	  if (opcode->match == 0x80002000) /* add */
	    imm_added_to_rs1 = 1;

	  if (X_RS1 (insn) != X_RD (insn)
	      && strchr (opcode->args, 'r') != 0)
	      /* Can't do simple format if source and dest are different.  */
	      continue;
	  if (X_RS2 (insn) != X_RD (insn)
	      && strchr (opcode->args, 'O') != 0)
	      /* Can't do simple format if source and dest are different.  */
	      continue;

	  (*info->fprintf_func) (stream, "%s", opcode->name);

	  {
	    const char *s;

	    if (opcode->args[0] != ',')
	      (*info->fprintf_func) (stream, " ");

	    for (s = opcode->args; *s != '\0'; ++s)
	      {
		while (*s == ',')
		  {
		    (*info->fprintf_func) (stream, ",");
		    ++s;
		    switch (*s)
		      {
		      case 'a':
			(*info->fprintf_func) (stream, "a");
			is_annulled = 1;
			++s;
			continue;
		      case 'N':
			(*info->fprintf_func) (stream, "pn");
			++s;
			continue;

		      case 'T':
			(*info->fprintf_func) (stream, "pt");
			++s;
			continue;

		      default:
			break;
		      }
		  }

		(*info->fprintf_func) (stream, " ");

		switch (*s)
		  {
		  case '+':
		    found_plus = 1;
		    /* Fall through.  */

		  default:
		    (*info->fprintf_func) (stream, "%c", *s);
		    break;

		  case '#':
		    (*info->fprintf_func) (stream, "0");
		    break;

#define	reg(n)	(*info->fprintf_func) (stream, "%%%s", reg_names[n])
		  case '1':
		  case 'r':
		    reg (X_RS1 (insn));
		    break;

		  case '2':
		  case 'O':
		    reg (X_RS2 (insn));
		    break;

		  case 'd':
		    reg (X_RD (insn));
		    break;
#undef	reg

#define	freg(n)		(*info->fprintf_func) (stream, "%%%s", freg_names[n])
#define	fregx(n)	(*info->fprintf_func) (stream, "%%%s", freg_names[((n) & ~1) | (((n) & 1) << 5)])
		  case 'e':
		    freg (X_RS1 (insn));
		    break;
		  case 'v':	/* Double/even.  */
		  case 'V':	/* Quad/multiple of 4.  */
		    fregx (X_RS1 (insn));
		    break;

		  case 'f':
		    freg (X_RS2 (insn));
		    break;
		  case 'B':	/* Double/even.  */
		  case 'R':	/* Quad/multiple of 4.  */
		    fregx (X_RS2 (insn));
		    break;

		  case '4':
		    freg (X_RS3 (insn));
		    break;
		  case '5':	/* Double/even.  */
		    fregx (X_RS3 (insn));
		    break;

		  case 'g':
		    freg (X_RD (insn));
		    break;
		  case 'H':	/* Double/even.  */
		  case 'J':	/* Quad/multiple of 4.  */
		  case '}':     /* Double/even.  */
		    fregx (X_RD (insn));
		    break;
#undef	freg
#undef	fregx

#define	creg(n)	(*info->fprintf_func) (stream, "%%c%u", (unsigned int) (n))
		  case 'b':
		    creg (X_RS1 (insn));
		    break;

		  case 'c':
		    creg (X_RS2 (insn));
		    break;

		  case 'D':
		    creg (X_RD (insn));
		    break;
#undef	creg

		  case 'h':
		    (*info->fprintf_func) (stream, "%%hi(%#x)",
					   ((unsigned) 0xFFFFFFFF
					    & ((int) X_IMM22 (insn) << 10)));
		    break;

		  case 'i':	/* 13 bit immediate.  */
		  case 'I':	/* 11 bit immediate.  */
		  case 'j':	/* 10 bit immediate.  */
		    {
		      int imm;

		      if (*s == 'i')
		        imm = X_SIMM (insn, 13);
		      else if (*s == 'I')
			imm = X_SIMM (insn, 11);
		      else
			imm = X_SIMM (insn, 10);

		      /* Check to see whether we have a 1+i, and take
			 note of that fact.

			 Note: because of the way we sort the table,
			 we will be matching 1+i rather than i+1,
			 so it is OK to assume that i is after +,
			 not before it.  */
		      if (found_plus)
			imm_added_to_rs1 = 1;

		      if (imm <= 9)
			(*info->fprintf_func) (stream, "%d", imm);
		      else
			(*info->fprintf_func) (stream, "%#x", imm);
		    }
		    break;

		  case ')':	/* 5 bit unsigned immediate from RS3.  */
		    (info->fprintf_func) (stream, "%#x", (unsigned int) X_RS3 (insn));
		    break;

		  case 'X':	/* 5 bit unsigned immediate.  */
		  case 'Y':	/* 6 bit unsigned immediate.  */
		    {
		      int imm = X_IMM (insn, *s == 'X' ? 5 : 6);

		      if (imm <= 9)
			(info->fprintf_func) (stream, "%d", imm);
		      else
			(info->fprintf_func) (stream, "%#x", (unsigned) imm);
		    }
		    break;

		  case '3':
		    (info->fprintf_func) (stream, "%ld", X_IMM (insn, 3));
		    break;

		  case 'K':
		    {
		      int mask = X_MEMBAR (insn);
		      int bit = 0x40, printed_one = 0;
		      const char *name;

		      if (mask == 0)
			(info->fprintf_func) (stream, "0");
		      else
			while (bit)
			  {
			    if (mask & bit)
			      {
				if (printed_one)
				  (info->fprintf_func) (stream, "|");
				name = sparc_decode_membar (bit);
				(info->fprintf_func) (stream, "%s", name);
				printed_one = 1;
			      }
			    bit >>= 1;
			  }
		      break;
		    }

		  case '=':
		    info->target = memaddr + SEX (X_DISP10 (insn), 10) * 4;
		    (*info->print_address_func) (info->target, info);
		    break;

		  case 'k':
		    info->target = memaddr + SEX (X_DISP16 (insn), 16) * 4;
		    (*info->print_address_func) (info->target, info);
		    break;

		  case 'G':
		    info->target = memaddr + SEX (X_DISP19 (insn), 19) * 4;
		    (*info->print_address_func) (info->target, info);
		    break;

		  case '6':
		  case '7':
		  case '8':
		  case '9':
		    (*info->fprintf_func) (stream, "%%fcc%c", *s - '6' + '0');
		    break;

		  case 'z':
		    (*info->fprintf_func) (stream, "%%icc");
		    break;

		  case 'Z':
		    (*info->fprintf_func) (stream, "%%xcc");
		    break;

		  case 'E':
		    (*info->fprintf_func) (stream, "%%ccr");
		    break;

		  case 's':
		    (*info->fprintf_func) (stream, "%%fprs");
		    break;

		  case '{':
		    (*info->fprintf_func) (stream, "%%mcdper");
		    break;

		  case 'o':
		    (*info->fprintf_func) (stream, "%%asi");
		    break;

		  case 'W':
		    (*info->fprintf_func) (stream, "%%tick");
		    break;

		  case 'P':
		    (*info->fprintf_func) (stream, "%%pc");
		    break;

		  case '?':
		    if (X_RS1 (insn) == 31)
		      (*info->fprintf_func) (stream, "%%ver");
		    else if (X_RS1 (insn) == 23)
		      (*info->fprintf_func) (stream, "%%pmcdper");
		    else if ((unsigned) X_RS1 (insn) < 17)
		      (*info->fprintf_func) (stream, "%%%s",
					     v9_priv_reg_names[X_RS1 (insn)]);
		    else
		      (*info->fprintf_func) (stream, "%%reserved");
		    break;

		  case '!':
                    if (X_RD (insn) == 31)
                      (*info->fprintf_func) (stream, "%%ver");
		    else if (X_RD (insn) == 23)
		      (*info->fprintf_func) (stream, "%%pmcdper");
		    else if ((unsigned) X_RD (insn) < 17)
		      (*info->fprintf_func) (stream, "%%%s",
					     v9_priv_reg_names[X_RD (insn)]);
		    else
		      (*info->fprintf_func) (stream, "%%reserved");
		    break;

		  case '$':
		    if ((unsigned) X_RS1 (insn) < 32)
		      (*info->fprintf_func) (stream, "%%%s",
					     v9_hpriv_reg_names[X_RS1 (insn)]);
		    else
		      (*info->fprintf_func) (stream, "%%reserved");
		    break;

		  case '%':
		    if ((unsigned) X_RD (insn) < 32)
		      (*info->fprintf_func) (stream, "%%%s",
					     v9_hpriv_reg_names[X_RD (insn)]);
		    else
		      (*info->fprintf_func) (stream, "%%reserved");
		    break;

		  case '/':
		    if (X_RS1 (insn) < 16 || X_RS1 (insn) > 28)
		      (*info->fprintf_func) (stream, "%%reserved");
		    else
		      (*info->fprintf_func) (stream, "%%%s",
					     v9a_asr_reg_names[X_RS1 (insn)-16]);
		    break;

		  case '_':
		    if (X_RD (insn) < 16 || X_RD (insn) > 28)
		      (*info->fprintf_func) (stream, "%%reserved");
		    else
		      (*info->fprintf_func) (stream, "%%%s",
					     v9a_asr_reg_names[X_RD (insn)-16]);
		    break;

		  case '*':
		    {
		      const char *name = sparc_decode_prefetch (X_RD (insn));

		      if (name)
			(*info->fprintf_func) (stream, "%s", name);
		      else
			(*info->fprintf_func) (stream, "%ld", X_RD (insn));
		      break;
		    }

		  case 'M':
		    (*info->fprintf_func) (stream, "%%asr%ld", X_RS1 (insn));
		    break;

		  case 'm':
		    (*info->fprintf_func) (stream, "%%asr%ld", X_RD (insn));
		    break;

		  case 'L':
		    info->target = memaddr + SEX (X_DISP30 (insn), 30) * 4;
		    (*info->print_address_func) (info->target, info);
		    break;

		  case 'n':
		    (*info->fprintf_func)
		      (stream, "%#x", SEX (X_DISP22 (insn), 22));
		    break;

		  case 'l':
		    info->target = memaddr + SEX (X_DISP22 (insn), 22) * 4;
		    (*info->print_address_func) (info->target, info);
		    break;

		  case 'A':
		    {
		      const char *name = sparc_decode_asi (X_ASI (insn));

		      if (name)
			(*info->fprintf_func) (stream, "%s", name);
		      else
			(*info->fprintf_func) (stream, "(%ld)", X_ASI (insn));
		      break;
		    }

		  case 'C':
		    (*info->fprintf_func) (stream, "%%csr");
		    break;

		  case 'F':
		    (*info->fprintf_func) (stream, "%%fsr");
		    break;

		  case '(':
		    (*info->fprintf_func) (stream, "%%efsr");
		    break;

		  case 'p':
		    (*info->fprintf_func) (stream, "%%psr");
		    break;

		  case 'q':
		    (*info->fprintf_func) (stream, "%%fq");
		    break;

		  case 'Q':
		    (*info->fprintf_func) (stream, "%%cq");
		    break;

		  case 't':
		    (*info->fprintf_func) (stream, "%%tbr");
		    break;

		  case 'w':
		    (*info->fprintf_func) (stream, "%%wim");
		    break;

		  case 'x':
		    (*info->fprintf_func) (stream, "%ld",
					   ((X_LDST_I (insn) << 8)
					    + X_ASI (insn)));
		    break;

		  case 'y':
		    (*info->fprintf_func) (stream, "%%y");
		    break;

		  case 'u':
		  case 'U':
		    {
		      int val = *s == 'U' ? X_RS1 (insn) : X_RD (insn);
		      const char *name = sparc_decode_sparclet_cpreg (val);

		      if (name)
			(*info->fprintf_func) (stream, "%s", name);
		      else
			(*info->fprintf_func) (stream, "%%cpreg(%d)", val);
		      break;
		    }
		  }
	      }
	  }

	  /* If we are adding or or'ing something to rs1, then
	     check to see whether the previous instruction was
	     a sethi to the same register as in the sethi.
	     If so, attempt to print the result of the add or
	     or (in this context add and or do the same thing)
	     and its symbolic value.  */
	  if (imm_ored_to_rs1 || imm_added_to_rs1)
	    {
	      unsigned long prev_insn;
	      int errcode;

	      if (memaddr >= 4)
		errcode =
		  (*info->read_memory_func)
		  (memaddr - 4, buffer, sizeof (buffer), info);
	      else
		errcode = 1;

	      prev_insn = getword (buffer);

	      if (errcode == 0)
		{
		  /* If it is a delayed branch, we need to look at the
		     instruction before the delayed branch.  This handles
		     sequences such as:

		     sethi %o1, %hi(_foo), %o1
		     call _printf
		     or %o1, %lo(_foo), %o1  */

		  if (is_delayed_branch (prev_insn))
		    {
		      if (memaddr >= 8)
			errcode = (*info->read_memory_func)
			  (memaddr - 8, buffer, sizeof (buffer), info);
		      else
			errcode = 1;

		      prev_insn = getword (buffer);
		    }
		}

	      /* If there was a problem reading memory, then assume
		 the previous instruction was not sethi.  */
	      if (errcode == 0)
		{
		  /* Is it sethi to the same register?  */
		  if ((prev_insn & 0xc1c00000) == 0x01000000
		      && X_RD (prev_insn) == X_RS1 (insn))
		    {
		      (*info->fprintf_func) (stream, "\t! ");
		      info->target =
			((unsigned) 0xFFFFFFFF
			 & ((int) X_IMM22 (prev_insn) << 10));
		      if (imm_added_to_rs1)
			info->target += X_SIMM (insn, 13);
		      else
			info->target |= X_SIMM (insn, 13);
		      (*info->print_address_func) (info->target, info);
		      info->insn_type = dis_dref;
		      info->data_size = 4;  /* FIXME!!! */
		    }
		}
	    }

	  if (opcode->flags & (F_UNBR|F_CONDBR|F_JSR))
	    {
	      /* FIXME -- check is_annulled flag.  */
	      (void) is_annulled;
	      if (opcode->flags & F_UNBR)
		info->insn_type = dis_branch;
	      if (opcode->flags & F_CONDBR)
		info->insn_type = dis_condbranch;
	      if (opcode->flags & F_JSR)
		info->insn_type = dis_jsr;
	      if (opcode->flags & F_DELAYED)
		info->branch_delay_insns = 1;
	    }

	  return sizeof (buffer);
	}
    }