Exemplo n.º 1
0
/* The function nios2_print_insn_arg uses the character pointed
   to by ARGPTR to determine how it print the next token or separator
   character in the arguments to an instruction.  */
static int
nios2_print_insn_arg (const char *argptr,
		      unsigned long opcode, bfd_vma address,
		      disassemble_info *info,
		      const struct nios2_opcode *op)
{
  unsigned long i = 0;
  struct nios2_reg *reg_base;

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

    case 'c':
      /* Control register index.  */
      switch (op->format)
	{
	case iw_r_type:
	  i = GET_IW_R_IMM5 (opcode);
	  break;
	case iw_F3X6L5_type:
	  i = GET_IW_F3X6L5_IMM5 (opcode);
	  break;
	default:
	  bad_opcode (op);
	}
      reg_base = nios2_control_regs ();
      (*info->fprintf_func) (info->stream, "%s", reg_base[i].name);
      break;

    case 'd':
      reg_base = nios2_regs;
      switch (op->format)
	{
	case iw_r_type:
	  i = GET_IW_R_C (opcode);
	  break;
	case iw_custom_type:
	  i = GET_IW_CUSTOM_C (opcode);
	  if (GET_IW_CUSTOM_READC (opcode) == 0)
	    reg_base = nios2_coprocessor_regs ();
	  break;
	case iw_F3X6L5_type:
	case iw_F3X6_type:
	  i = GET_IW_F3X6L5_C (opcode);
	  break;
	case iw_F3X8_type:
	  i = GET_IW_F3X8_C (opcode);
	  if (GET_IW_F3X8_READC (opcode) == 0)
	    reg_base = nios2_coprocessor_regs ();
	  break;
	case iw_F2_type:
	  i = GET_IW_F2_B (opcode);
	  break;
	default:
	  bad_opcode (op);
	}
      if (i < NUMREGNAMES)
	(*info->fprintf_func) (info->stream, "%s", reg_base[i].name);
      else
	(*info->fprintf_func) (info->stream, "unknown");
      break;

    case 's':
      reg_base = nios2_regs;
      switch (op->format)
	{
	case iw_r_type:
	  i = GET_IW_R_A (opcode);
	  break;
	case iw_i_type:
	  i = GET_IW_I_A (opcode);
	  break;
	case iw_custom_type:
	  i = GET_IW_CUSTOM_A (opcode);
	  if (GET_IW_CUSTOM_READA (opcode) == 0)
	    reg_base = nios2_coprocessor_regs ();
	  break;
	case iw_F2I16_type:
	  i = GET_IW_F2I16_A (opcode);
	  break;
	case iw_F2X4I12_type:
	  i = GET_IW_F2X4I12_A (opcode);
	  break;
	case iw_F1X4I12_type:
	  i = GET_IW_F1X4I12_A (opcode);
	  break;
	case iw_F1X4L17_type:
	  i = GET_IW_F1X4L17_A (opcode);
	  break;
	case iw_F3X6L5_type:
	case iw_F3X6_type:
	  i = GET_IW_F3X6L5_A (opcode);
	  break;
	case iw_F2X6L10_type:
	  i = GET_IW_F2X6L10_A (opcode);
	  break;
	case iw_F3X8_type:
	  i = GET_IW_F3X8_A (opcode);
	  if (GET_IW_F3X8_READA (opcode) == 0)
	    reg_base = nios2_coprocessor_regs ();
	  break;
	case iw_F1X1_type:
	  i = GET_IW_F1X1_A (opcode);
	  break;
	case iw_F1I5_type:
	  i = 27;   /* Implicit stack pointer reference.  */
	  break;
	case iw_F2_type:
	  i = GET_IW_F2_A (opcode);
	  break;
	default:
	  bad_opcode (op);
	}
      if (i < NUMREGNAMES)
	(*info->fprintf_func) (info->stream, "%s", reg_base[i].name);
      else
	(*info->fprintf_func) (info->stream, "unknown");
      break;

    case 't':
      reg_base = nios2_regs;
      switch (op->format)
	{
	case iw_r_type:
	  i = GET_IW_R_B (opcode);
	  break;
	case iw_i_type:
	  i = GET_IW_I_B (opcode);
	  break;
	case iw_custom_type:
	  i = GET_IW_CUSTOM_B (opcode);
	  if (GET_IW_CUSTOM_READB (opcode) == 0)
	    reg_base = nios2_coprocessor_regs ();
	  break;
	case iw_F2I16_type:
	  i = GET_IW_F2I16_B (opcode);
	  break;
	case iw_F2X4I12_type:
	  i = GET_IW_F2X4I12_B (opcode);
	  break;
	case iw_F3X6L5_type:
	case iw_F3X6_type:
	  i = GET_IW_F3X6L5_B (opcode);
	  break;
	case iw_F2X6L10_type:
	  i = GET_IW_F2X6L10_B (opcode);
	  break;
	case iw_F3X8_type:
	  i = GET_IW_F3X8_B (opcode);
	  if (GET_IW_F3X8_READB (opcode) == 0)
	    reg_base = nios2_coprocessor_regs ();
	  break;
	case iw_F1I5_type:
	  i = GET_IW_F1I5_B (opcode);
	  break;
	case iw_F2_type:
	  i = GET_IW_F2_B (opcode);
	  break;
	case iw_T1X1I6_type:
	  i = 0;
	  break;
	default:
	  bad_opcode (op);
	}
      if (i < NUMREGNAMES)
	(*info->fprintf_func) (info->stream, "%s", reg_base[i].name);
      else
	(*info->fprintf_func) (info->stream, "unknown");
      break;

    case 'D':
      switch (op->format)
	{
	case iw_T1I7_type:
	  i = GET_IW_T1I7_A3 (opcode);
	  break;
	case iw_T2X1L3_type:
	  i = GET_IW_T2X1L3_B3 (opcode);
	  break;
	case iw_T2X1I3_type:
	  i = GET_IW_T2X1I3_B3 (opcode);
	  break;
	case iw_T3X1_type:
	  i = GET_IW_T3X1_C3 (opcode);
	  break;
	case iw_T2X3_type:
	  if (op->num_args == 3)
	    i = GET_IW_T2X3_A3 (opcode);
	  else
	    i = GET_IW_T2X3_B3 (opcode);
	  break;
	default:
	  bad_opcode (op);
	}
      i = nios2_r2_reg3_mappings[i];
      (*info->fprintf_func) (info->stream, "%s", nios2_regs[i].name);
      break;

    case 'M':
      /* 6-bit unsigned immediate with no shift.  */
      switch (op->format)
	{
	case iw_T1X1I6_type:
	  i = GET_IW_T1X1I6_IMM6 (opcode);
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%ld", i);
      break;

    case 'N':
      /* 6-bit unsigned immediate with 2-bit shift.  */
      switch (op->format)
	{
	case iw_T1X1I6_type:
	  i = GET_IW_T1X1I6_IMM6 (opcode) << 2;
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%ld", i);
      break;

    case 'S':
      switch (op->format)
	{
	case iw_T1I7_type:
	  i = GET_IW_T1I7_A3 (opcode);
	  break;
	case iw_T2I4_type:
	  i = GET_IW_T2I4_A3 (opcode);
	  break;
	case iw_T2X1L3_type:
	  i = GET_IW_T2X1L3_A3 (opcode);
	  break;
	case iw_T2X1I3_type:
	  i = GET_IW_T2X1I3_A3 (opcode);
	  break;
	case iw_T3X1_type:
	  i = GET_IW_T3X1_A3 (opcode);
	  break;
	case iw_T2X3_type:
	  i = GET_IW_T2X3_A3 (opcode);
	  break;
	case iw_T1X1I6_type:
	  i = GET_IW_T1X1I6_A3 (opcode);
	  break;
	default:
	  bad_opcode (op);
	}
      i = nios2_r2_reg3_mappings[i];
      (*info->fprintf_func) (info->stream, "%s", nios2_regs[i].name);
      break;

    case 'T':
      switch (op->format)
	{
	case iw_T2I4_type:
	  i = GET_IW_T2I4_B3 (opcode);
	  break;
	case iw_T3X1_type:
	  i = GET_IW_T3X1_B3 (opcode);
	  break;
	case iw_T2X3_type:
	  i = GET_IW_T2X3_B3 (opcode);
	  break;
	default:
	  bad_opcode (op);
	}
      i = nios2_r2_reg3_mappings[i];
      (*info->fprintf_func) (info->stream, "%s", nios2_regs[i].name);
      break;

    case 'i':
      /* 16-bit signed immediate.  */
      switch (op->format)
	{
	case iw_i_type:
	  i = (signed) (GET_IW_I_IMM16 (opcode) << 16) >> 16;
	  break;
	case iw_F2I16_type:
	  i = (signed) (GET_IW_F2I16_IMM16 (opcode) << 16) >> 16;
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%ld", i);
      break;

    case 'I':
      /* 12-bit signed immediate.  */
      switch (op->format)
	{
	case iw_F2X4I12_type:
	  i = (signed) (GET_IW_F2X4I12_IMM12 (opcode) << 20) >> 20;
	  break;
	case iw_F1X4I12_type:
	  i = (signed) (GET_IW_F1X4I12_IMM12 (opcode) << 20) >> 20;
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%ld", i);
      break;

    case 'u':
      /* 16-bit unsigned immediate.  */
      switch (op->format)
	{
	case iw_i_type:
	  i = GET_IW_I_IMM16 (opcode);
	  break;
	case iw_F2I16_type:
	  i = GET_IW_F2I16_IMM16 (opcode);
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%ld", i);
      break;

    case 'U':
      /* 7-bit unsigned immediate with 2-bit shift.  */
      switch (op->format)
	{
	case iw_T1I7_type:
	  i = GET_IW_T1I7_IMM7 (opcode) << 2;
	  break;
	case iw_X1I7_type:
	  i = GET_IW_X1I7_IMM7 (opcode) << 2;
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%ld", i);
      break;

    case 'V':
      /* 5-bit unsigned immediate with 2-bit shift.  */
      switch (op->format)
	{
	case iw_F1I5_type:
	  i = GET_IW_F1I5_IMM5 (opcode) << 2;
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%ld", i);
      break;

    case 'W':
      /* 4-bit unsigned immediate with 2-bit shift.  */
      switch (op->format)
	{
	case iw_T2I4_type:
	  i = GET_IW_T2I4_IMM4 (opcode) << 2;
	  break;
	case iw_L5I4X1_type:
	  i = GET_IW_L5I4X1_IMM4 (opcode) << 2;
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%ld", i);
      break;

    case 'X':
      /* 4-bit unsigned immediate with 1-bit shift.  */
      switch (op->format)
	{
	case iw_T2I4_type:
	  i = GET_IW_T2I4_IMM4 (opcode) << 1;
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%ld", i);
      break;

    case 'Y':
      /* 4-bit unsigned immediate without shift.  */
      switch (op->format)
	{
	case iw_T2I4_type:
	  i = GET_IW_T2I4_IMM4 (opcode);
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%ld", i);
      break;

    case 'o':
      /* 16-bit signed immediate address offset.  */
      switch (op->format)
	{
	case iw_i_type:
	  i = (signed) (GET_IW_I_IMM16 (opcode) << 16) >> 16;
	  break;
	case iw_F2I16_type:
	  i = (signed) (GET_IW_F2I16_IMM16 (opcode) << 16) >> 16;
	  break;
	default:
	  bad_opcode (op);
	}
      address = address + 4 + i;
      (*info->print_address_func) (address, info);
      break;

    case 'O':
      /* 10-bit signed address offset with 1-bit shift.  */
      switch (op->format)
	{
	case iw_I10_type:
	  i = (signed) (GET_IW_I10_IMM10 (opcode) << 22) >> 21;
	  break;
	default:
	  bad_opcode (op);
	}
      address = address + 2 + i;
      (*info->print_address_func) (address, info);
      break;

    case 'P':
      /* 7-bit signed address offset with 1-bit shift.  */
      switch (op->format)
	{
	case iw_T1I7_type:
	  i = (signed) (GET_IW_T1I7_IMM7 (opcode) << 25) >> 24;
	  break;
	default:
	  bad_opcode (op);
	}
      address = address + 2 + i;
      (*info->print_address_func) (address, info);
      break;

    case 'j':
      /* 5-bit unsigned immediate.  */
      switch (op->format)
	{
	case iw_r_type:
	  i = GET_IW_R_IMM5 (opcode);
	  break;
	case iw_F3X6L5_type:
	  i = GET_IW_F3X6L5_IMM5 (opcode);
	  break;
	case iw_F2X6L10_type:
	  i = GET_IW_F2X6L10_MSB (opcode);
	  break;
	case iw_X2L5_type:
	  i = GET_IW_X2L5_IMM5 (opcode);
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%ld", i);
      break;

    case 'k':
      /* Second 5-bit unsigned immediate field.  */
      switch (op->format)
	{
	case iw_F2X6L10_type:
	  i = GET_IW_F2X6L10_LSB (opcode);
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%ld", i);
      break;

    case 'l':
      /* 8-bit unsigned immediate.  */
      switch (op->format)
	{
	case iw_custom_type:
	  i = GET_IW_CUSTOM_N (opcode);
	  break;
	case iw_F3X8_type:
	  i = GET_IW_F3X8_N (opcode);
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%lu", i);
      break;

    case 'm':
      /* 26-bit unsigned immediate.  */
      switch (op->format)
	{
	case iw_j_type:
	  i = GET_IW_J_IMM26 (opcode);
	  break;
	case iw_L26_type:
	  i = GET_IW_L26_IMM26 (opcode);
	  break;
	default:
	  bad_opcode (op);
	}
      /* This translates to an address because it's only used in call
	 instructions.  */
      address = (address & 0xf0000000) | (i << 2);
      (*info->print_address_func) (address, info);
      break;

    case 'e':
      /* Encoded enumeration for addi.n/subi.n.  */
      switch (op->format)
	{
	case iw_T2X1I3_type:
	  i = nios2_r2_asi_n_mappings[GET_IW_T2X1I3_IMM3 (opcode)];
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%lu", i);
      break;

    case 'f':
      /* Encoded enumeration for slli.n/srli.n.  */
      switch (op->format)
	{
	case iw_T2X1L3_type:
	  i = nios2_r2_shi_n_mappings[GET_IW_T2X1I3_IMM3 (opcode)];
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%lu", i);
      break;

    case 'g':
      /* Encoded enumeration for andi.n.  */
      switch (op->format)
	{
	case iw_T2I4_type:
	  i = nios2_r2_andi_n_mappings[GET_IW_T2I4_IMM4 (opcode)];
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%lu", i);
      break;

    case 'h':
      /* Encoded enumeration for movi.n.  */
      switch (op->format)
	{
	case iw_T1I7_type:
	  i = GET_IW_T1I7_IMM7 (opcode);
	  if (i == 125)
	    i = 0xff;
	  else if (i == 126)
	    i = -2;
	  else if (i == 127)
	    i = -1;
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%ld", i);
      break;

    case 'R':
      {
	unsigned long reglist = 0;
	int dir = 1;
	int k, t;

	switch (op->format)
	  {
	  case iw_F1X4L17_type:
	    /* Encoding for ldwm/stwm.  */
	    i = GET_IW_F1X4L17_REGMASK (opcode);
	    if (GET_IW_F1X4L17_RS (opcode))
	      {
		reglist = ((i << 14) & 0x00ffc000);
		if (i & (1 << 10))
		  reglist |= (1 << 28);
		if (i & (1 << 11))
		  reglist |= (1 << 31);
	      }
	    else
	      reglist = i << 2;
	    dir = GET_IW_F1X4L17_REGMASK (opcode) ? 1 : -1;
	    break;

	  case iw_L5I4X1_type:
	    /* Encoding for push.n/pop.n.  */
	    reglist |= (1 << 31);
	    if (GET_IW_L5I4X1_FP (opcode))
	      reglist |= (1 << 28);
	    if (GET_IW_L5I4X1_CS (opcode))
	      {
		int val = GET_IW_L5I4X1_REGRANGE (opcode);
		reglist |= nios2_r2_reg_range_mappings[val];
	      }
	    dir = (op->match == MATCH_R2_POP_N ? 1 : -1);
	    break;

	  default:
	    bad_opcode (op);
	  }

	t = 0;
	(*info->fprintf_func) (info->stream, "{");
	for (k = (dir == 1 ? 0 : 31);
	     (dir == 1 && k < 32) || (dir == -1 && k >= 0);
	     k += dir)
	  if (reglist & (1 << k))
	    {
	      if (t)
		(*info->fprintf_func) (info->stream, ",");
	      else
		t++;
	      (*info->fprintf_func) (info->stream, "%s", nios2_regs[k].name);
	    }
	(*info->fprintf_func) (info->stream, "}");
	break;
      }

    case 'B':
      /* Base register and options for ldwm/stwm.  */
      switch (op->format)
	{
	case iw_F1X4L17_type:
	  if (GET_IW_F1X4L17_ID (opcode) == 0)
	    (*info->fprintf_func) (info->stream, "--");

	  i = GET_IW_F1X4I12_A (opcode);
	  (*info->fprintf_func) (info->stream, "(%s)",
				 nios2_builtin_regs[i].name);

	  if (GET_IW_F1X4L17_ID (opcode))
	    (*info->fprintf_func) (info->stream, "++");
	  if (GET_IW_F1X4L17_WB (opcode))
	    (*info->fprintf_func) (info->stream, ",writeback");
	  if (GET_IW_F1X4L17_PC (opcode))
	    (*info->fprintf_func) (info->stream, ",ret");
	  break;
	default:
	  bad_opcode (op);
	}
      break;

    default:
      (*info->fprintf_func) (info->stream, "unknown");
      break;
    }
  return 0;
}
Exemplo n.º 2
0
static CORE_ADDR
nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc,
			const CORE_ADDR current_pc,
			struct nios2_unwind_cache *cache,
			struct frame_info *this_frame)
{
  /* Maximum lines of prologue to check.
     Note that this number should not be too large, else we can
     potentially end up iterating through unmapped memory.  */
  CORE_ADDR limit_pc = start_pc + 200;
  int regno;
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);

  /* Does the frame set up the FP register?  */
  int base_reg = 0;

  struct reg_value *value = cache->reg_value;
  struct reg_value temp_value[NIOS2_NUM_REGS];

  int i;

  /* Save the starting PC so we can correct the pc after running
     through the prolog, using symbol info.  */
  CORE_ADDR pc = start_pc;

  /* Is this an exception handler?  */
  int exception_handler = 0;

  /* What was the original value of SP (or fake original value for
     functions which switch stacks?  */
  CORE_ADDR frame_high;

  /* Is this the end of the prologue?  */
  int within_prologue = 1;

  CORE_ADDR prologue_end;

  /* Is this the innermost function?  */
  int innermost = (this_frame ? (frame_relative_level (this_frame) == 0) : 1);

  if (nios2_debug)
    fprintf_unfiltered (gdb_stdlog,
			"{ nios2_analyze_prologue start=%s, current=%s ",
			paddress (gdbarch, start_pc),
			paddress (gdbarch, current_pc));

  /* Set up the default values of the registers.  */
  nios2_setup_default (cache);
  prologue_end = start_pc;

  /* Find the prologue instructions.  */
  while (pc < limit_pc && within_prologue)
    {
      /* Present instruction.  */
      uint32_t insn;

      int prologue_insn = 0;

      if (pc == current_pc)
      {
	/* When we reach the current PC we must save the current
	   register state (for the backtrace) but keep analysing
	   because there might be more to find out (eg. is this an
	   exception handler).  */
	memcpy (temp_value, value, sizeof (temp_value));
	value = temp_value;
	if (nios2_debug)
	  fprintf_unfiltered (gdb_stdlog, "*");
      }

      insn = read_memory_unsigned_integer (pc, NIOS2_OPCODE_SIZE, byte_order);
      pc += NIOS2_OPCODE_SIZE;

      if (nios2_debug)
	fprintf_unfiltered (gdb_stdlog, "[%08X]", insn);

      /* The following instructions can appear in the prologue.  */

      if ((insn & MASK_R1_ADD) == MATCH_R1_ADD)
	{
	  /* ADD   rc, ra, rb  (also used for MOV) */

	  int ra = GET_IW_R_A (insn);
	  int rb = GET_IW_R_B (insn);
	  int rc = GET_IW_R_C (insn);

	  if (rc == NIOS2_SP_REGNUM
	      && rb == 0
	      && value[ra].reg == cache->reg_saved[NIOS2_SP_REGNUM].basereg)
	    {
	      /* If the previous value of SP is available somewhere
		 near the new stack pointer value then this is a
		 stack switch.  */

	      /* If any registers were saved on the stack before then
		 we can't backtrace into them now.  */
	      for (i = 0 ; i < NIOS2_NUM_REGS ; i++)
		{
		  if (cache->reg_saved[i].basereg == NIOS2_SP_REGNUM)
		    cache->reg_saved[i].basereg = -1;
		  if (value[i].reg == NIOS2_SP_REGNUM)
		    value[i].reg = -1;
		}

	      /* Create a fake "high water mark" 4 bytes above where SP
		 was stored and fake up the registers to be consistent
		 with that.  */
	      value[NIOS2_SP_REGNUM].reg = NIOS2_SP_REGNUM;
	      value[NIOS2_SP_REGNUM].offset
		= (value[ra].offset
		   - cache->reg_saved[NIOS2_SP_REGNUM].addr
		   - 4);
	      cache->reg_saved[NIOS2_SP_REGNUM].basereg = NIOS2_SP_REGNUM;
	      cache->reg_saved[NIOS2_SP_REGNUM].addr = -4;
	    }

	  else if (rc != 0)
	    {
	      if (value[rb].reg == 0)
		value[rc].reg = value[ra].reg;
	      else if (value[ra].reg == 0)
		value[rc].reg = value[rb].reg;
	      else
		value[rc].reg = -1;
	      value[rc].offset = value[ra].offset + value[rb].offset;
	    }
	  prologue_insn = 1;
	}

      else if ((insn & MASK_R1_SUB) == MATCH_R1_SUB)
	{
	  /* SUB   rc, ra, rb */

	  int ra = GET_IW_R_A (insn);
	  int rb = GET_IW_R_B (insn);
	  int rc = GET_IW_R_C (insn);

	  if (rc != 0)
	    {
	      if (value[rb].reg == 0)
		value[rc].reg = value[ra].reg;
	      else
		value[rc].reg = -1;
	      value[rc].offset = value[ra].offset - value[rb].offset;
	    }
	}

      else if ((insn & MASK_R1_ADDI) == MATCH_R1_ADDI)
	{
	  /* ADDI  rb, ra, immed   (also used for MOVI) */
	  short immed = GET_IW_I_IMM16 (insn);
	  int ra = GET_IW_I_A (insn);
	  int rb = GET_IW_I_B (insn);

	  /* The first stack adjustment is part of the prologue.
	     Any subsequent stack adjustments are either down to
	     alloca or the epilogue so stop analysing when we hit
	     them.  */
	  if (rb == NIOS2_SP_REGNUM
	      && (value[rb].offset != 0 || value[ra].reg != NIOS2_SP_REGNUM))
	    break;

	  if (rb != 0)
	    {
	      value[rb].reg    = value[ra].reg;
	      value[rb].offset = value[ra].offset + immed;
	    }

	  prologue_insn = 1;
	}

      else if ((insn & MASK_R1_ORHI) == MATCH_R1_ORHI)
	{
	  /* ORHI  rb, ra, immed   (also used for MOVHI) */
	  unsigned int immed = GET_IW_I_IMM16 (insn);
	  int ra = GET_IW_I_A (insn);
	  int rb = GET_IW_I_B (insn);

	  if (rb != 0)
	    {
  	      value[rb].reg    = (value[ra].reg == 0) ? 0 : -1;
	      value[rb].offset = value[ra].offset | (immed << 16);
	    }
	}

      else if ((insn & MASK_R1_STW) == MATCH_R1_STW
	       || (insn & MASK_R1_STWIO) == MATCH_R1_STWIO)
        {
	  /* STW rb, immediate(ra) */

	  short immed16 = GET_IW_I_IMM16 (insn);
	  int ra = GET_IW_I_A (insn);
	  int rb = GET_IW_I_B (insn);

	  /* Are we storing the original value of a register?
	     For exception handlers the value of EA-4 (return
	     address from interrupts etc) is sometimes stored.  */
	  int orig = value[rb].reg;
	  if (orig > 0
	      && (value[rb].offset == 0
		  || (orig == NIOS2_EA_REGNUM && value[rb].offset == -4)))
	    {
	      /* We are most interested in stores to the stack, but
		 also take note of stores to other places as they
		 might be useful later.  */
	      if ((value[ra].reg == NIOS2_SP_REGNUM
		   && cache->reg_saved[orig].basereg != NIOS2_SP_REGNUM)
		  || cache->reg_saved[orig].basereg == -1)
		{
		  if (pc < current_pc)
		    {
		      /* Save off callee saved registers.  */
		      cache->reg_saved[orig].basereg = value[ra].reg;
		      cache->reg_saved[orig].addr = value[ra].offset + immed16;
		    }

		  prologue_insn = 1;

		  if (orig == NIOS2_EA_REGNUM || orig == NIOS2_ESTATUS_REGNUM)
		    exception_handler = 1;
		}
	    }
	  else
	    /* Non-stack memory writes are not part of the
	       prologue.  */
	    within_prologue = 0;
        }

      else if ((insn & MASK_R1_RDCTL) == MATCH_R1_RDCTL)
	{
	  /* RDCTL rC, ctlN */
	  int rc = GET_IW_R_C (insn);
	  int n = GET_IW_R_A (insn);

	  if (rc != 0)
	    {
	      value[rc].reg    = NIOS2_STATUS_REGNUM + n;
	      value[rc].offset = 0;
	    }

	  prologue_insn = 1;
        }

      else if ((insn & MASK_R1_CALL) == MATCH_R1_CALL
	       && value[8].reg == NIOS2_RA_REGNUM
	       && value[8].offset == 0
	       && value[NIOS2_SP_REGNUM].reg == NIOS2_SP_REGNUM
	       && value[NIOS2_SP_REGNUM].offset == 0)
	{
	  /* A CALL instruction.  This is treated as a call to mcount
	     if ra has been stored into r8 beforehand and if it's
	     before the stack adjust.
	     Note mcount corrupts r2-r3, r9-r15 & ra.  */
	  for (i = 2 ; i <= 3 ; i++)
	    value[i].reg = -1;
	  for (i = 9 ; i <= 15 ; i++)
	    value[i].reg = -1;
	  value[NIOS2_RA_REGNUM].reg = -1;

	  prologue_insn = 1;
	}

      else if ((insn & 0xf83fffff) == 0xd800012e)
	{
	   /* BGEU sp, rx, +8
	      BREAK 3
	      This instruction sequence is used in stack checking;
	      we can ignore it.  */
	  unsigned int next_insn
	    = read_memory_unsigned_integer (pc, NIOS2_OPCODE_SIZE, byte_order);

	  if (next_insn != 0x003da0fa)
	    within_prologue = 0;
	  else
	    pc += NIOS2_OPCODE_SIZE;
	}

      else if ((insn & 0xf800003f) == 0xd8000036)
	{
	   /* BLTU sp, rx, .Lstackoverflow
	      If the location branched to holds a BREAK 3 instruction
	      then this is also stack overflow detection.  We can
	      ignore it.  */
	  CORE_ADDR target_pc = pc + ((insn & 0x3fffc0) >> 6);
	  unsigned int target_insn
	    = read_memory_unsigned_integer (target_pc, NIOS2_OPCODE_SIZE,
					    byte_order);

	  if (target_insn != 0x003da0fa)
	    within_prologue = 0;
	}

      /* Any other instructions are allowed to be moved up into the
	 prologue.  If we reach a branch, call or return then the
	 prologue is considered over.  We also consider a second stack
	 adjustment as terminating the prologue (see above).  */
      else
	{
	  switch (GET_IW_R1_OP (insn))
Exemplo n.º 3
0
/* The function nios2_print_insn_arg uses the character pointed
   to by ARGPTR to determine how it print the next token or separator
   character in the arguments to an instruction.  */
static int
nios2_print_insn_arg (const char *argptr,
		      unsigned long opcode, bfd_vma address,
		      disassemble_info *info,
		      const struct nios2_opcode *op)
{
  unsigned long i = 0;
  struct nios2_reg *reg_base;

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

    case 'd':
      switch (op->format)
	{
	case iw_r_type:
	  i = GET_IW_R_C (opcode);
	  reg_base = nios2_regs;
	  break;
	case iw_custom_type:
	  i = GET_IW_CUSTOM_C (opcode);
	  if (GET_IW_CUSTOM_READC (opcode) == 0)
	    reg_base = nios2_coprocessor_regs ();
	  else
	    reg_base = nios2_regs;
	  break;
	default:
	  bad_opcode (op);
	}
      if (i < NUMREGNAMES)
	(*info->fprintf_func) (info->stream, "%s", reg_base[i].name);
      else
	(*info->fprintf_func) (info->stream, "unknown");
      break;

    case 's':
      switch (op->format)
	{
	case iw_r_type:
	  i = GET_IW_R_A (opcode);
	  reg_base = nios2_regs;
	  break;
	case iw_i_type:
	  i = GET_IW_I_A (opcode);
	  reg_base = nios2_regs;
	  break;
	case iw_custom_type:
	  i = GET_IW_CUSTOM_A (opcode);
	  if (GET_IW_CUSTOM_READA (opcode) == 0)
	    reg_base = nios2_coprocessor_regs ();
	  else
	    reg_base = nios2_regs;
	  break;
	default:
	  bad_opcode (op);
	}
      if (i < NUMREGNAMES)
	(*info->fprintf_func) (info->stream, "%s", reg_base[i].name);
      else
	(*info->fprintf_func) (info->stream, "unknown");
      break;

    case 't':
      switch (op->format)
	{
	case iw_r_type:
	  i = GET_IW_R_B (opcode);
	  reg_base = nios2_regs;
	  break;
	case iw_i_type:
	  i = GET_IW_I_B (opcode);
	  reg_base = nios2_regs;
	  break;
	case iw_custom_type:
	  i = GET_IW_CUSTOM_B (opcode);
	  if (GET_IW_CUSTOM_READB (opcode) == 0)
	    reg_base = nios2_coprocessor_regs ();
	  else
	    reg_base = nios2_regs;
	  break;
	default:
	  bad_opcode (op);
	}
      if (i < NUMREGNAMES)
	(*info->fprintf_func) (info->stream, "%s", reg_base[i].name);
      else
	(*info->fprintf_func) (info->stream, "unknown");
      break;

    case 'i':
      /* 16-bit signed immediate.  */
      switch (op->format)
	{
	case iw_i_type:
	  i = (signed) (GET_IW_I_IMM16 (opcode) << 16) >> 16;
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%ld", i);
      break;

    case 'u':
      /* 16-bit unsigned immediate.  */
      switch (op->format)
	{
	case iw_i_type:
	  i = GET_IW_I_IMM16 (opcode);
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%ld", i);
      break;

    case 'o':
      /* 16-bit signed immediate address offset.  */
      switch (op->format)
	{
	case iw_i_type:
	  i = (signed) (GET_IW_I_IMM16 (opcode) << 16) >> 16;
	  break;
	default:
	  bad_opcode (op);
	}
      address = address + 4 + i;
      (*info->print_address_func) (address, info);
      break;

    case 'j':
      /* 5-bit unsigned immediate.  */
      switch (op->format)
	{
	case iw_r_type:
	  i = GET_IW_R_IMM5 (opcode);
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%ld", i);
      break;

    case 'l':
      /* 8-bit unsigned immediate.  */
      switch (op->format)
	{
	case iw_custom_type:
	  i = GET_IW_CUSTOM_N (opcode);
	  break;
	default:
	  bad_opcode (op);
	}
      (*info->fprintf_func) (info->stream, "%lu", i);
      break;

    case 'm':
      /* 26-bit unsigned immediate.  */
      switch (op->format)
	{
	case iw_j_type:
	  i = GET_IW_J_IMM26 (opcode);
	  break;
	default:
	  bad_opcode (op);
	}
      /* This translates to an address because it's only used in call
	 instructions.  */
      address = (address & 0xf0000000) | (i << 2);
      (*info->print_address_func) (address, info);
      break;

    case 'c':
      /* Control register index.  */
      switch (op->format)
	{
	case iw_r_type:
	  i = GET_IW_R_IMM5 (opcode);
	  break;
	default:
	  bad_opcode (op);
	}
      reg_base = nios2_control_regs ();
      (*info->fprintf_func) (info->stream, "%s", reg_base[i].name);
      break;

    default:
      (*info->fprintf_func) (info->stream, "unknown");
      break;
    }
  return 0;
}