cris-dis.c

来自「基于4个mips核的noc设计」· C语言 代码 · 共 1,405 行 · 第 1/3 页

C
1,405
字号
			    number = prefix_buffer[2];			    if (number > 127)			      number -= 256;			    break;			  case 2:			    number = prefix_buffer[2] + prefix_buffer[3] * 256;			    if (number > 32767)			      number -= 65536;			    break;			  case 4:			    number			      = prefix_buffer[2] + prefix_buffer[3] * 256			      + prefix_buffer[4] * 65536			      + prefix_buffer[5] * 0x1000000;			    break;			  default:			    strcpy (tp, "bug");			    tp += 3;			    number = 42;			  }			info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG;			info->target2 = (bfd_vma) number;			/* If the size is dword, then assume it's an			   address.  */			if (nbytes == 4)			  {			    /* Finish off and output previous formatted			       bytes.  */			    *tp++ = '+';			    *tp = 0;			    tp = temp;			    (*info->fprintf_func) (info->stream, "%s", temp);			    (*info->print_address_func) ((bfd_vma) number, info);			  }			else			  {			    if (number >= 0)			      *tp++ = '+';			    tp = format_dec (number, tp, 1);			  }		      }		    else		      {			/* Output "r+[R].m" or "r+[R+].m".  */			*tp++ = '+';			*tp++ = '[';			tp = format_reg (prefix_insn & 15, tp,					 with_reg_prefix);			if (prefix_insn & 0x400)			  *tp++ = '+';			*tp++ = ']';			*tp++ = '.';			*tp++ = mode_char[(prefix_insn >> 4) & 3];			info->flags			  |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG			      | CRIS_DIS_FLAG_MEM_TARGET2_MEM			      | CRIS_DIS_FLAG_MEM_TARGET_IS_REG			      | (((prefix_insn >> 4) == 2)				 ? 0				 : (((prefix_insn >> 4) & 3) == 1				    ? CRIS_DIS_FLAG_MEM_TARGET2_MEM_WORD				    : CRIS_DIS_FLAG_MEM_TARGET2_MEM_BYTE)));		      }		    break;		  default:		    (*info->fprintf_func) (info->stream, "?prefix-bug");		  }		/* To mark that the prefix is used, reset it.  */		prefix_opcodep = NULL;	      }	    else	      {		tp = format_reg (insn & 15, tp, with_reg_prefix);		info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG;		info->target = insn & 15;		if (insn & 0x400)		  *tp++ = '+';	      }	    *tp++ = ']';	  }	break;      case 'x':	tp = format_reg ((insn >> 12) & 15, tp, with_reg_prefix);	*tp++ = '.';	*tp++ = mode_char[(insn >> 4) & 3];	break;      case 'I':	tp = format_dec (insn & 63, tp, 0);	break;      case 'b':	{	  int where = buffer[2] + buffer[3] * 256;	  if (where > 32767)	    where -= 65536;	  where += addr + 4;	  if (insn == BA_PC_INCR_OPCODE)	    info->insn_type = dis_branch;	  else	    info->insn_type = dis_condbranch;	  info->target = (bfd_vma) where;	  *tp = 0;	  tp = temp;	  (*info->fprintf_func) (info->stream, "%s%s ",				 temp, cris_cc_strings[insn >> 12]);	  (*info->print_address_func) ((bfd_vma) where, info);	}      break;    case 'c':      tp = format_dec (insn & 31, tp, 0);      break;    case 'C':      tp = format_dec (insn & 15, tp, 0);      break;    case 'o':      {	long offset = insn & 0xfe;	if (insn & 1)	  offset |= ~0xff;	if (opcodep->match == BA_QUICK_OPCODE)	  info->insn_type = dis_branch;	else	  info->insn_type = dis_condbranch;	info->target = (bfd_vma) (addr + 2 + offset);	*tp = 0;	tp = temp;	(*info->fprintf_func) (info->stream, "%s", temp);	(*info->print_address_func) ((bfd_vma) (addr + 2 + offset), info);      }      break;    case 'O':      {	long number = buffer[0];	if (number > 127)	  number = number - 256;	tp = format_dec (number, tp, 1);	*tp++ = ',';	tp = format_reg ((insn >> 12) & 15, tp, with_reg_prefix);      }      break;    case 'f':      tp = print_flags (insn, tp);      break;    case 'i':      tp = format_dec ((insn & 32) ? (insn & 31) | ~31 : insn & 31, tp, 1);      break;    case 'P':      {	const struct cris_spec_reg *sregp	  = spec_reg_info ((insn >> 12) & 15);	if (sregp->name == NULL)	  /* Should have been caught as a non-match eariler.  */	  *tp++ = '?';	else	  {	    if (with_reg_prefix)	      *tp++ = REGISTER_PREFIX_CHAR;	    strcpy (tp, sregp->name);	    tp += strlen (tp);	  }      }      break;    default:      strcpy (tp, "???");      tp += 3;    }  }  *tp = 0;  if (prefix_opcodep)    (*info->fprintf_func) (info->stream, " (OOPS unused prefix \"%s: %s\")",			   prefix_opcodep->name, prefix_opcodep->args);  (*info->fprintf_func) (info->stream, "%s", temp);  /* Get info for matching case-tables, if we don't have any active.     We assume that the last constant seen is used; either in the insn     itself or in a "move.d const,rN, sub.d rN,rM"-like sequence.  */  if (TRACE_CASE && case_offset_counter == 0)    {      if (strncmp (opcodep->name, "sub", 3) == 0)	case_offset = last_immediate;      /* It could also be an "add", if there are negative case-values.  */      else if (strncmp (opcodep->name, "add", 3) == 0)	{	  /* The first case is the negated operand to the add.  */	  case_offset = -last_immediate;	}      /* A bound insn will tell us the number of cases.  */      else if (strncmp (opcodep->name, "bound", 5) == 0)	{	  no_of_case_offsets = last_immediate + 1;	}      /* A jump or jsr or branch breaks the chain of insns for a	 case-table, so assume default first-case again.  */      else if (info->insn_type == dis_jsr	       || info->insn_type == dis_branch	       || info->insn_type == dis_condbranch)	case_offset = 0;    }}/* Print the CRIS instruction at address memaddr on stream.  Returns   length of the instruction, in bytes.  Prefix register names with `$' if   WITH_REG_PREFIX.  */static intprint_insn_cris_generic (memaddr, info, with_reg_prefix)     bfd_vma memaddr;     disassemble_info *info;     boolean with_reg_prefix;{  int nbytes;  unsigned int insn;  const struct cris_opcode *matchedp;  int advance = 0;  /* No instruction will be disassembled as longer than this number of     bytes; stacked prefixes will not be expanded.  */  unsigned char buffer[MAX_BYTES_PER_CRIS_INSN];  unsigned char *bufp;  int status;  bfd_vma addr;  /* There will be an "out of range" error after the last instruction.     Reading pairs of bytes in decreasing number, we hope that we will get     at least the amount that we will consume.     If we can't get any data, or we do not get enough data, we print     the error message.  */  for (nbytes = MAX_BYTES_PER_CRIS_INSN; nbytes > 0; nbytes -= 2)    {      status = (*info->read_memory_func) (memaddr, buffer, nbytes, info);      if (status == 0)	break;    }  /* If we did not get all we asked for, then clear the rest.     Hopefully this makes a reproducible result in case of errors.  */  if (nbytes != MAX_BYTES_PER_CRIS_INSN)    memset (buffer + nbytes, 0, MAX_BYTES_PER_CRIS_INSN - nbytes);  addr = memaddr;  bufp = buffer;  /* Set some defaults for the insn info.  */  info->insn_info_valid = 1;  info->branch_delay_insns = 0;  info->data_size = 0;  info->insn_type = dis_nonbranch;  info->flags = 0;  info->target = 0;  info->target2 = 0;  /* If we got any data, disassemble it.  */  if (nbytes != 0)    {      matchedp = NULL;      insn = bufp[0] + bufp[1] * 256;      /* If we're in a case-table, don't disassemble the offsets.  */      if (TRACE_CASE && case_offset_counter != 0)	{	  info->insn_type = dis_noninsn;	  advance += 2;	  /* If to print data as offsets, then shortcut here.  */	  (*info->fprintf_func) (info->stream, "case %d%s: -> ",				 case_offset + no_of_case_offsets				 - case_offset_counter,				 case_offset_counter == 1 ? "/default" :				 "");	  (*info->print_address_func) ((bfd_vma)				       ((short) (insn)					+ (long) (addr						  - (no_of_case_offsets						     - case_offset_counter)						  * 2)), info);	  case_offset_counter--;	  /* The default case start (without a "sub" or "add") must be	     zero.  */	  if (case_offset_counter == 0)	    case_offset = 0;	}      else if (insn == 0)	{	  /* We're often called to disassemble zeroes.  While this is a	     valid "bcc .+2" insn, it is also useless enough and enough	     of a nuiscance that we will just output "bcc .+2" for it	     and signal it as a noninsn.  */	  (*info->fprintf_func) (info->stream, "bcc .+2");	  info->insn_type = dis_noninsn;	  advance += 2;	}      else	{	  const struct cris_opcode *prefix_opcodep = NULL;	  unsigned char *prefix_buffer = bufp;	  unsigned int prefix_insn = insn;	  int prefix_size = 0;	  matchedp = get_opcode_entry (insn, NO_CRIS_PREFIX);	  /* Check if we're supposed to write out prefixes as address	     modes and if this was a prefix.  */	  if (matchedp != NULL && PARSE_PREFIX && matchedp->args[0] == 'p')	    {	      /* If it's a prefix, put it into the prefix vars and get the		 main insn.  */	      prefix_size = bytes_to_skip (prefix_insn, matchedp);	      prefix_opcodep = matchedp;	      insn = bufp[prefix_size] + bufp[prefix_size + 1] * 256;	      matchedp = get_opcode_entry (insn, prefix_insn);	      if (matchedp != NULL)		{		  addr += prefix_size;		  bufp += prefix_size;		  advance += prefix_size;		}	      else		{		  /* The "main" insn wasn't valid, at least not when		     prefixed.  Put back things enough to output the		     prefix insn only, as a normal insn.  */		  matchedp = prefix_opcodep;		  insn = prefix_insn;		  prefix_opcodep = NULL;		}	    }	  if (matchedp == NULL)	    {	      (*info->fprintf_func) (info->stream, "??0x%lx", insn);	      advance += 2;	      info->insn_type = dis_noninsn;	    }	  else	    {	      advance += bytes_to_skip (insn, matchedp);	      /* The info_type and assorted fields will be set according		 to the operands.   */	      print_with_operands (matchedp, insn, bufp, addr, info,				   prefix_opcodep, prefix_insn,				   prefix_buffer, with_reg_prefix);	    }	}    }  else    info->insn_type = dis_noninsn;  /* If we read less than MAX_BYTES_PER_CRIS_INSN, i.e. we got an error     status when reading that much, and the insn decoding indicated a     length exceeding what we read, there is an error.  */  if (status != 0 && (nbytes == 0 || advance > nbytes))    {      (*info->memory_error_func) (status, memaddr, info);      return -1;    }  /* Max supported insn size with one folded prefix insn.  */  info->bytes_per_line = MAX_BYTES_PER_CRIS_INSN;  /* I would like to set this to a fixed value larger than the actual     number of bytes to print in order to avoid spaces between bytes,     but objdump.c (2.9.1) does not like that, so we print 16-bit     chunks, which is the next choice.  */  info->bytes_per_chunk = 2;  /* Printing bytes in order of increasing addresses makes sense,     especially on a little-endian target.     This is completely the opposite of what you think; setting this to     BFD_ENDIAN_LITTLE will print bytes in order N..0 rather than the 0..N     we want.  */  info->display_endian = BFD_ENDIAN_BIG;  return advance;}/* Disassemble, prefixing register names with `$'.  */static intprint_insn_cris_with_register_prefix (vma, info)     bfd_vma vma;     disassemble_info *info;{  return print_insn_cris_generic (vma, info, true);}/* Disassemble, no prefixes on register names.  */static intprint_insn_cris_without_register_prefix (vma, info)     bfd_vma vma;     disassemble_info *info;{  return print_insn_cris_generic (vma, info, false);}/* Return a disassembler-function that prints registers with a `$' prefix,   or one that prints registers without a prefix.  */disassembler_ftypecris_get_disassembler (abfd)     bfd *abfd;{  /* If there's no bfd in sight, we return what is valid as input in all     contexts if fed back to the assembler: disassembly *with* register     prefix.  */  if (abfd == NULL || bfd_get_symbol_leading_char (abfd) == 0)    return print_insn_cris_with_register_prefix;  return print_insn_cris_without_register_prefix;}/* * Local variables: * eval: (c-set-style "gnu") * indent-tabs-mode: t * End: */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?