Exemple #1
0
static CORE_ADDR
tilegx_analyze_prologue (struct gdbarch* gdbarch,
			 CORE_ADDR start_addr, CORE_ADDR end_addr,
			 struct tilegx_frame_cache *cache,
			 struct frame_info *next_frame)
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  CORE_ADDR next_addr;
  CORE_ADDR prolog_end = end_addr;
  gdb_byte instbuf[32 * TILEGX_BUNDLE_SIZE_IN_BYTES];
  CORE_ADDR instbuf_start;
  unsigned int instbuf_size;
  int status;
  bfd_uint64_t bundle;
  struct tilegx_decoded_instruction
    decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
  int num_insns;
  struct tilegx_reverse_regs reverse_frame[TILEGX_NUM_PHYS_REGS];
  struct tilegx_reverse_regs
    new_reverse_frame[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
  int dest_regs[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
  int reverse_frame_valid, prolog_done, branch_seen, lr_saved_on_stack_p;
  LONGEST prev_sp_value;
  int i, j;

  if (start_addr >= end_addr
      || (start_addr % TILEGX_BUNDLE_ALIGNMENT_IN_BYTES) != 0)
    return end_addr;

  /* Initialize the reverse frame.  This maps the CURRENT frame's
     registers to the outer frame's registers (the frame on the
     stack goes the other way).  */
  memcpy (&reverse_frame, &template_reverse_regs, sizeof (reverse_frame));

  prolog_done = 0;
  branch_seen = 0;
  prev_sp_value = 0;
  lr_saved_on_stack_p = 0;

  /* To cut down on round-trip overhead, we fetch multiple bundles
     at once.  These variables describe the range of memory we have
     prefetched.  */
  instbuf_start = 0;
  instbuf_size = 0;

  for (next_addr = start_addr;
       next_addr < end_addr;
       next_addr += TILEGX_BUNDLE_SIZE_IN_BYTES)
    {
      /* Retrieve the next instruction.  */
      if (next_addr - instbuf_start >= instbuf_size)
	{
	  /* Figure out how many bytes to fetch.  Don't span a page
	     boundary since that might cause an unnecessary memory
	     error.  */
	  unsigned int size_on_same_page = 4096 - (next_addr & 4095);

	  instbuf_size = sizeof instbuf;

	  if (instbuf_size > size_on_same_page)
	    instbuf_size = size_on_same_page;

	  instbuf_size = min (instbuf_size, (end_addr - next_addr));
	  instbuf_start = next_addr;

	  status = safe_frame_unwind_memory (next_frame, instbuf_start,
					     instbuf, instbuf_size);
	  if (status == 0)
	    memory_error (TARGET_XFER_E_IO, next_addr);
	}

      reverse_frame_valid = 0;

      bundle = extract_unsigned_integer (&instbuf[next_addr - instbuf_start],
					 8, byte_order);

      num_insns = parse_insn_tilegx (bundle, next_addr, decoded);

      for (i = 0; i < num_insns; i++)
	{
	  struct tilegx_decoded_instruction *this_insn = &decoded[i];
	  int64_t *operands = (int64_t *) this_insn->operand_values;
	  const struct tilegx_opcode *opcode = this_insn->opcode;

	  switch (opcode->mnemonic)
	    {
	    case TILEGX_OPC_ST:
	      if (cache
		  && reverse_frame[operands[0]].state == REVERSE_STATE_VALUE
		  && reverse_frame[operands[1]].state
		  == REVERSE_STATE_REGISTER)
		{
		  LONGEST saved_address = reverse_frame[operands[0]].value;
		  unsigned saved_register
		    = (unsigned) reverse_frame[operands[1]].value;

		  /* realreg >= 0 and addr != -1 indicates that the
		     value of saved_register is in memory location
		     saved_address.  The value of realreg is not
		     meaningful in this case but it must be >= 0.
		     See trad-frame.h.  */
		  cache->saved_regs[saved_register].realreg = saved_register;
		  cache->saved_regs[saved_register].addr = saved_address;
		} 
	      else if (cache
		       && (operands[0] == TILEGX_SP_REGNUM) 
		       && (operands[1] == TILEGX_LR_REGNUM))
		lr_saved_on_stack_p = 1;
	      break;
	    case TILEGX_OPC_ADDI:
	    case TILEGX_OPC_ADDLI:
	      if (cache
		  && operands[0] == TILEGX_SP_REGNUM
		  && operands[1] == TILEGX_SP_REGNUM
		  && reverse_frame[operands[1]].state == REVERSE_STATE_REGISTER)
		{
		  /* Special case.  We're fixing up the stack frame.  */
		  uint64_t hopefully_sp
		    = (unsigned) reverse_frame[operands[1]].value;
		  short op2_as_short = (short) operands[2];
		  signed char op2_as_char = (signed char) operands[2];

		  /* Fix up the sign-extension.  */
		  if (opcode->mnemonic == TILEGX_OPC_ADDI)
		    op2_as_short = op2_as_char;
		  prev_sp_value = (cache->saved_regs[hopefully_sp].addr
				   - op2_as_short);

		  new_reverse_frame[i].state = REVERSE_STATE_VALUE;
		  new_reverse_frame[i].value
		    = cache->saved_regs[hopefully_sp].addr;
		  trad_frame_set_value (cache->saved_regs,
					hopefully_sp, prev_sp_value);
		}
	      else
		{
		  short op2_as_short = (short) operands[2];
		  signed char op2_as_char = (signed char) operands[2];

		  /* Fix up the sign-extension.  */
		  if (opcode->mnemonic == TILEGX_OPC_ADDI)
		    op2_as_short = op2_as_char;

		  new_reverse_frame[i] = reverse_frame[operands[1]];
		  if (new_reverse_frame[i].state == REVERSE_STATE_VALUE)
		    new_reverse_frame[i].value += op2_as_short;
		  else
		    new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
		}
	      reverse_frame_valid |= 1 << i;
	      dest_regs[i] = operands[0];
	      break;
	    case TILEGX_OPC_ADD:
	      if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
		  && reverse_frame[operands[2]].state == REVERSE_STATE_VALUE)
		{
		  /* We have values -- we can do this.  */
		  new_reverse_frame[i] = reverse_frame[operands[2]];
		  new_reverse_frame[i].value
		    += reverse_frame[operands[i]].value;
		}
	      else
		{
		  /* We don't know anything about the values.  Punt.  */
		  new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
		}
	      reverse_frame_valid |= 1 << i;
	      dest_regs[i] = operands[0];
	      break;
	    case TILEGX_OPC_MOVE:
	      new_reverse_frame[i] = reverse_frame[operands[1]];
	      reverse_frame_valid |= 1 << i;
	      dest_regs[i] = operands[0];
	      break;
	    case TILEGX_OPC_MOVEI:
	    case TILEGX_OPC_MOVELI:
	      new_reverse_frame[i].state = REVERSE_STATE_VALUE;
	      new_reverse_frame[i].value = operands[1];
	      reverse_frame_valid |= 1 << i;
	      dest_regs[i] = operands[0];
	      break;
	    case TILEGX_OPC_ORI:
	      if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE)
		{
		  /* We have a value in A -- we can do this.  */
		  new_reverse_frame[i] = reverse_frame[operands[1]];
		  new_reverse_frame[i].value
		    = reverse_frame[operands[1]].value | operands[2];
		}
	      else if (operands[2] == 0)
		{
		  /* This is a move.  */
		  new_reverse_frame[i] = reverse_frame[operands[1]];
		}
	      else
		{
		  /* We don't know anything about the values.  Punt.  */
		  new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
		}
	      reverse_frame_valid |= 1 << i;
	      dest_regs[i] = operands[0];
	      break;
	    case TILEGX_OPC_OR:
	      if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
		  && reverse_frame[operands[1]].value == 0)
		{
		  /* This is a move.  */
		  new_reverse_frame[i] = reverse_frame[operands[2]];
		}
	      else if (reverse_frame[operands[2]].state == REVERSE_STATE_VALUE
		       && reverse_frame[operands[2]].value == 0)
		{
		  /* This is a move.  */
		  new_reverse_frame[i] = reverse_frame[operands[1]];
		}
	      else
		{
		  /* We don't know anything about the values.  Punt.  */
		  new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
		}
	      reverse_frame_valid |= 1 << i;
	      dest_regs[i] = operands[0];
	      break;
	    case TILEGX_OPC_SUB:
	      if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
		  && reverse_frame[operands[2]].state == REVERSE_STATE_VALUE)
		{
		  /* We have values -- we can do this.  */
		  new_reverse_frame[i] = reverse_frame[operands[1]];
		  new_reverse_frame[i].value
		    -= reverse_frame[operands[2]].value;
		}
	      else
		{
		  /* We don't know anything about the values.  Punt.  */
		  new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
		}
	      reverse_frame_valid |= 1 << i;
	      dest_regs[i] = operands[0];
	      break;

	    case TILEGX_OPC_FNOP:
	    case TILEGX_OPC_INFO:
	    case TILEGX_OPC_INFOL:
	      /* Nothing to see here, move on.
		 Note that real NOP is treated as a 'real' instruction
		 because someone must have intended that it be there.
		 It therefore terminates the prolog.  */
	      break;

	    case TILEGX_OPC_J:
	    case TILEGX_OPC_JAL:

	    case TILEGX_OPC_BEQZ:
	    case TILEGX_OPC_BEQZT:
	    case TILEGX_OPC_BGEZ:
	    case TILEGX_OPC_BGEZT:
	    case TILEGX_OPC_BGTZ:
	    case TILEGX_OPC_BGTZT:
	    case TILEGX_OPC_BLBC:
	    case TILEGX_OPC_BLBCT:
	    case TILEGX_OPC_BLBS:
	    case TILEGX_OPC_BLBST:
	    case TILEGX_OPC_BLEZ:
	    case TILEGX_OPC_BLEZT:
	    case TILEGX_OPC_BLTZ:
	    case TILEGX_OPC_BLTZT:
	    case TILEGX_OPC_BNEZ:
	    case TILEGX_OPC_BNEZT:

	    case TILEGX_OPC_IRET:
	    case TILEGX_OPC_JALR:
	    case TILEGX_OPC_JALRP:
	    case TILEGX_OPC_JR:
	    case TILEGX_OPC_JRP:
	    case TILEGX_OPC_SWINT0:
	    case TILEGX_OPC_SWINT1:
	    case TILEGX_OPC_SWINT2:
	    case TILEGX_OPC_SWINT3:
	      /* We're really done -- this is a branch.  */
	      branch_seen = 1;
	      prolog_done = 1;
	      break;
	    default:
	      /* We don't know or care what this instruction is.
		 All we know is that it isn't part of a prolog, and if
		 there's a destination register, we're trashing it.  */
	      prolog_done = 1;
	      for (j = 0; j < opcode->num_operands; j++)
		{
		  if (this_insn->operands[j]->is_dest_reg)
		    {
		      dest_regs[i] = operands[j];
		      new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
		      reverse_frame_valid |= 1 << i;
		      break;
		    }
		}
	      break;
	    }
	}

      /* Now update the reverse frames.  */
      for (i = 0; i < num_insns; i++)
	{
	  /* ISSUE: Does this properly handle "network" registers?  */
	  if ((reverse_frame_valid & (1 << i))
	      && dest_regs[i] != TILEGX_ZERO_REGNUM)
	    reverse_frame[dest_regs[i]] = new_reverse_frame[i];
	}

      if (prev_sp_value != 0)
	{
	  /* GCC uses R52 as a frame pointer.  Have we seen "move r52, sp"?  */
	  if (reverse_frame[TILEGX_R52_REGNUM].state == REVERSE_STATE_REGISTER
	      && reverse_frame[TILEGX_R52_REGNUM].value == TILEGX_SP_REGNUM)
	  {
	    reverse_frame[TILEGX_R52_REGNUM].state = REVERSE_STATE_VALUE;
	    reverse_frame[TILEGX_R52_REGNUM].value = prev_sp_value;
	  }

	  prev_sp_value = 0;
	}

      if (prolog_done && prolog_end == end_addr)
	{
	  /* We found non-prolog code.	As such, _this_ instruction
	     is the one after the prolog.  We keep processing, because
	     there may be more prolog code in there, but this is what
	     we'll return.  */
	  /* ISSUE: There may not have actually been a prologue, and
	     we may have simply skipped some random instructions.  */
	  prolog_end = next_addr;
	}
      if (branch_seen)
	{
	  /* We saw a branch.  The prolog absolutely must be over.  */
	  break;
	}
    }

  if (prolog_end == end_addr && cache)
    {
      /* We may have terminated the prolog early, and we're certainly
	 at THIS point right now.  It's possible that the values of
	 registers we need are currently actually in other registers
	 (and haven't been written to memory yet).  Go find them.  */
      for (i = 0; i < TILEGX_NUM_PHYS_REGS; i++)
	{
	  if (reverse_frame[i].state == REVERSE_STATE_REGISTER
	      && reverse_frame[i].value != i)
	    {
	      unsigned saved_register = (unsigned) reverse_frame[i].value;

	      cache->saved_regs[saved_register].realreg = i;
	      cache->saved_regs[saved_register].addr = (LONGEST) -1;
	    }
	}
    }

  if (lr_saved_on_stack_p)
    {
      cache->saved_regs[TILEGX_LR_REGNUM].realreg = TILEGX_LR_REGNUM;
      cache->saved_regs[TILEGX_LR_REGNUM].addr =
	cache->saved_regs[TILEGX_SP_REGNUM].addr;
    }

  return prolog_end;
}
Exemple #2
0
int
print_insn_tilegx (bfd_vma memaddr, disassemble_info *info)
{
  struct tilegx_decoded_instruction
    decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
  bfd_byte opbuf[TILEGX_BUNDLE_SIZE_IN_BYTES];
  int status, i, num_instructions, num_printed;
  tilegx_mnemonic padding_mnemonic;

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

  info->bytes_per_line = TILEGX_BUNDLE_SIZE_IN_BYTES;
  info->bytes_per_chunk = TILEGX_BUNDLE_SIZE_IN_BYTES;
  info->octets_per_byte = 1;
  info->display_endian = BFD_ENDIAN_LITTLE;

  /* Parse the instructions in the bundle.  */
  num_instructions =
    parse_insn_tilegx (bfd_getl64 (opbuf), memaddr, decoded);

  /* Print the instructions in the bundle.  */
  info->fprintf_func (info->stream, "{ ");
  num_printed = 0;

  /* Determine which nop opcode is used for padding and should be skipped.  */
  padding_mnemonic = TILEGX_OPC_FNOP;
  for (i = 0; i < num_instructions; i++)
    {
      if (!decoded[i].opcode->can_bundle)
	{
	  /* Instructions that cannot be bundled are padded out with nops,
	     rather than fnops. Displaying them is always clutter. */
	  padding_mnemonic = TILEGX_OPC_NOP;
	  break;
	}
    }

  for (i = 0; i < num_instructions; i++)
    {
      const struct tilegx_opcode *opcode = decoded[i].opcode;
      const char *name;
      int j;

      /* Do not print out fnops, unless everything is an fnop, in
	 which case we will print out just the last one. */
      if (opcode->mnemonic == padding_mnemonic
	  && (num_printed > 0 || i + 1 < num_instructions))
	continue;

      if (num_printed > 0)
	info->fprintf_func (info->stream, " ; ");
      ++num_printed;

      name = opcode->name;
      if (name == NULL)
	name = "<invalid>";
      info->fprintf_func (info->stream, "%s", name);

      for (j = 0; j < opcode->num_operands; j++)
	{
	  bfd_vma num;
	  const struct tilegx_operand *op;
	  const char *spr_name;

	  if (j > 0)
	    info->fprintf_func (info->stream, ",");
	  info->fprintf_func (info->stream, " ");

	  num = decoded[i].operand_values[j];

	  op = decoded[i].operands[j];
	  switch (op->type)
	    {
	    case TILEGX_OP_TYPE_REGISTER:
	      info->fprintf_func (info->stream, "%s",
				  tilegx_register_names[(int) num]);
	      break;
	    case TILEGX_OP_TYPE_SPR:
	      spr_name = get_tilegx_spr_name (num);
	      if (spr_name != NULL)
		info->fprintf_func (info->stream, "%s", spr_name);
	      else
		info->fprintf_func (info->stream, "%d", (int)num);
	      break;
	    case TILEGX_OP_TYPE_IMMEDIATE:
	      info->fprintf_func (info->stream, "%d", (int)num);
	      break;
	    case TILEGX_OP_TYPE_ADDRESS:
	      info->print_address_func (num, info);
	      break;
	    default:
	      abort ();
	    }
	}
    }
  info->fprintf_func (info->stream, " }");

  return TILEGX_BUNDLE_SIZE_IN_BYTES;
}