m68k-dis.c

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

C
1,329
字号
/* Print Motorola 68k instructions.   Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,   1998, 1999, 2000, 2001   Free Software Foundation, Inc.This file is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2 of the License, or(at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */#include "sysdep.h"#include "dis-asm.h"#include "floatformat.h"#include <libiberty.h>#include "opintl.h"#include "opcode/m68k.h"/* Local function prototypes */static intfetch_data PARAMS ((struct disassemble_info *, bfd_byte *));static voiddummy_print_address PARAMS ((bfd_vma, struct disassemble_info *));static intfetch_arg PARAMS ((unsigned char *, int, int, disassemble_info *));static voidprint_base PARAMS ((int, bfd_vma, disassemble_info*));static unsigned char *print_indexed PARAMS ((int, unsigned char *, bfd_vma, disassemble_info *));static intprint_insn_arg PARAMS ((const char *, unsigned char *, unsigned char *,			bfd_vma, disassemble_info *));CONST char * CONST fpcr_names[] =  {    "", "%fpiar", "%fpsr", "%fpiar/%fpsr", "%fpcr",    "%fpiar/%fpcr", "%fpsr/%fpcr", "%fpiar/%fpsr/%fpcr"  };static char *const reg_names[] =  {    "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",    "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp",    "%ps", "%pc"  };/* Sign-extend an (unsigned char). */#if __STDC__ == 1#define COERCE_SIGNED_CHAR(ch) ((signed char)(ch))#else#define COERCE_SIGNED_CHAR(ch) ((int)(((ch) ^ 0x80) & 0xFF) - 128)#endif/* Get a 1 byte signed integer.  */#define NEXTBYTE(p)  (p += 2, FETCH_DATA (info, p), COERCE_SIGNED_CHAR(p[-1]))/* Get a 2 byte signed integer.  */#define COERCE16(x) ((int) (((x) ^ 0x8000) - 0x8000))#define NEXTWORD(p)  \  (p += 2, FETCH_DATA (info, p), \   COERCE16 ((p[-2] << 8) + p[-1]))/* Get a 4 byte signed integer.  */#define COERCE32(x) ((bfd_signed_vma) ((x) ^ 0x80000000) - 0x80000000)#define NEXTLONG(p)  \  (p += 4, FETCH_DATA (info, p), \   (COERCE32 ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])))/* Get a 4 byte unsigned integer.  */#define NEXTULONG(p)  \  (p += 4, FETCH_DATA (info, p), \   (unsigned int) ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]))/* Get a single precision float.  */#define NEXTSINGLE(val, p) \  (p += 4, FETCH_DATA (info, p), \   floatformat_to_double (&floatformat_ieee_single_big, (char *) p - 4, &val))/* Get a double precision float.  */#define NEXTDOUBLE(val, p) \  (p += 8, FETCH_DATA (info, p), \   floatformat_to_double (&floatformat_ieee_double_big, (char *) p - 8, &val))/* Get an extended precision float.  */#define NEXTEXTEND(val, p) \  (p += 12, FETCH_DATA (info, p), \   floatformat_to_double (&floatformat_m68881_ext, (char *) p - 12, &val))/* Need a function to convert from packed to double   precision.   Actually, it's easier to print a   packed number than a double anyway, so maybe   there should be a special case to handle this... */#define NEXTPACKED(p) \  (p += 12, FETCH_DATA (info, p), 0.0)/* Maximum length of an instruction.  */#define MAXLEN 22#include <setjmp.h>struct private{  /* Points to first byte not fetched.  */  bfd_byte *max_fetched;  bfd_byte the_buffer[MAXLEN];  bfd_vma insn_start;  jmp_buf bailout;};/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)   to ADDR (exclusive) are valid.  Returns 1 for success, longjmps   on error.  */#define FETCH_DATA(info, addr) \  ((addr) <= ((struct private *)(info->private_data))->max_fetched \   ? 1 : fetch_data ((info), (addr)))static intfetch_data (info, addr)     struct disassemble_info *info;     bfd_byte *addr;{  int status;  struct private *priv = (struct private *)info->private_data;  bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);  status = (*info->read_memory_func) (start,				      priv->max_fetched,				      addr - priv->max_fetched,				      info);  if (status != 0)    {      (*info->memory_error_func) (status, start, info);      longjmp (priv->bailout, 1);    }  else    priv->max_fetched = addr;  return 1;}/* This function is used to print to the bit-bucket. */static int#ifdef __STDC__dummy_printer (FILE * file ATTRIBUTE_UNUSED,	       const char * format ATTRIBUTE_UNUSED, ...)#elsedummy_printer (file) FILE *file ATTRIBUTE_UNUSED;#endif { return 0; }static voiddummy_print_address (vma, info)     bfd_vma vma ATTRIBUTE_UNUSED;     struct disassemble_info *info ATTRIBUTE_UNUSED;{}/* Print the m68k instruction at address MEMADDR in debugged memory,   on INFO->STREAM.  Returns length of the instruction, in bytes.  */intprint_insn_m68k (memaddr, info)     bfd_vma memaddr;     disassemble_info *info;{  register int i;  register unsigned char *p;  unsigned char *save_p;  register const char *d;  register unsigned long bestmask;  const struct m68k_opcode *best;  unsigned int arch_mask;  struct private priv;  bfd_byte *buffer = priv.the_buffer;  fprintf_ftype save_printer = info->fprintf_func;  void (*save_print_address) PARAMS((bfd_vma, struct disassemble_info*))    = info->print_address_func;  int major_opcode;  static int numopcodes[16];  static const struct m68k_opcode **opcodes[16];  if (!opcodes[0])    {      /* Speed up the matching by sorting the opcode table on the upper	 four bits of the opcode.  */      const struct m68k_opcode **opc_pointer[16];      /* First count how many opcodes are in each of the sixteen buckets.  */      for (i = 0; i < m68k_numopcodes; i++)	numopcodes[(m68k_opcodes[i].opcode >> 28) & 15]++;      /* Then create a sorted table of pointers that point into the	 unsorted table.  */      opc_pointer[0] = ((const struct m68k_opcode **)			xmalloc (sizeof (struct m68k_opcode *)				 * m68k_numopcodes));      opcodes[0] = opc_pointer[0];      for (i = 1; i < 16; i++)	{	  opc_pointer[i] = opc_pointer[i - 1] + numopcodes[i - 1];	  opcodes[i] = opc_pointer[i];	}      for (i = 0; i < m68k_numopcodes; i++)	*opc_pointer[(m68k_opcodes[i].opcode >> 28) & 15]++ = &m68k_opcodes[i];    }  info->private_data = (PTR) &priv;  /* Tell objdump to use two bytes per chunk and six bytes per line for     displaying raw data.  */  info->bytes_per_chunk = 2;  info->bytes_per_line = 6;  info->display_endian = BFD_ENDIAN_BIG;  priv.max_fetched = priv.the_buffer;  priv.insn_start = memaddr;  if (setjmp (priv.bailout) != 0)    /* Error return.  */    return -1;  best = NULL;  switch (info->mach)    {    default:    case 0:      arch_mask = (unsigned int) -1;      break;    case bfd_mach_m68000:      arch_mask = m68000;      break;    case bfd_mach_m68008:      arch_mask = m68008;      break;    case bfd_mach_m68010:      arch_mask = m68010;      break;    case bfd_mach_m68020:      arch_mask = m68020;      break;    case bfd_mach_m68030:      arch_mask = m68030;      break;    case bfd_mach_m68040:      arch_mask = m68040;      break;    case bfd_mach_m68060:      arch_mask = m68060;      break;    case bfd_mach_mcf5200:      arch_mask = mcf5200;      break;    case bfd_mach_mcf5206e:      arch_mask = mcf5206e;      break;    case bfd_mach_mcf5307:      arch_mask = mcf5307;      break;    case bfd_mach_mcf5407:      arch_mask = mcf5407;      break;    }  arch_mask |= m68881 | m68851;  bestmask = 0;  FETCH_DATA (info, buffer + 2);  major_opcode = (buffer[0] >> 4) & 15;  for (i = 0; i < numopcodes[major_opcode]; i++)    {      const struct m68k_opcode *opc = opcodes[major_opcode][i];      unsigned long opcode = opc->opcode;      unsigned long match = opc->match;      if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))	  && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))	  /* Only fetch the next two bytes if we need to.  */	  && (((0xffff & match) == 0)	      ||	      (FETCH_DATA (info, buffer + 4)	       && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))	       && ((0xff & buffer[3] & match) == (0xff & opcode)))	      )	  && (opc->arch & arch_mask) != 0)	{	  /* Don't use for printout the variants of divul and divsl	     that have the same register number in two places.	     The more general variants will match instead.  */	  for (d = opc->args; *d; d += 2)	    if (d[1] == 'D')	      break;	  /* Don't use for printout the variants of most floating	     point coprocessor instructions which use the same	     register number in two places, as above. */	  if (*d == '\0')	    for (d = opc->args; *d; d += 2)	      if (d[1] == 't')		break;	  /* Don't match fmovel with more than one register; wait for             fmoveml.  */	  if (*d == '\0')	    {	      for (d = opc->args; *d; d += 2)		{		  if (d[0] == 's' && d[1] == '8')		    {		      int val;		      val = fetch_arg (buffer, d[1], 3, info);		      if ((val & (val - 1)) != 0)			break;		    }		}	    }	  if (*d == '\0' && match > bestmask)	    {	      best = opc;	      bestmask = match;	    }	}    }  if (best == NULL)    goto invalid;  /* Point at first word of argument data,     and at descriptor for first argument.  */  p = buffer + 2;    /* Figure out how long the fixed-size portion of the instruction is.     The only place this is stored in the opcode table is     in the arguments--look for arguments which specify fields in the 2nd     or 3rd words of the instruction.  */  for (d = best->args; *d; d += 2)    {      /* I don't think it is necessary to be checking d[0] here; I suspect	 all this could be moved to the case statement below.  */      if (d[0] == '#')	{	  if (d[1] == 'l' && p - buffer < 6)	    p = buffer + 6;	  else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' )	    p = buffer + 4;	}      if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4)	p = buffer + 4;      switch (d[1])	{	case '1':	case '2':	case '3':	case '7':	case '8':	case '9':	case 'i':	  if (p - buffer < 4)	    p = buffer + 4;	  break;	case '4':	case '5':	case '6':	  if (p - buffer < 6)	    p = buffer + 6;	  break;	default:	  break;	}    }  /* pflusha is an exceptions.  It takes no arguments but is two words     long.  Recognize it by looking at the lower 16 bits of the mask.  */  if (p - buffer < 4 && (best->match & 0xFFFF) != 0)    p = buffer + 4;  /* lpstop is another exception.  It takes a one word argument but is     three words long.  */  if (p - buffer < 6      && (best->match & 0xffff) == 0xffff      && best->args[0] == '#'      && best->args[1] == 'w')    {      /* Copy the one word argument into the usual location for a one	 word argument, to simplify printing it.  We can get away with	 this because we know exactly what the second word is, and we	 aren't going to print anything based on it.  */      p = buffer + 6;      FETCH_DATA (info, p);      buffer[2] = buffer[4];      buffer[3] = buffer[5];    }  FETCH_DATA (info, p);    d = best->args;  /* We can the operands twice.  The first time we don't print anything,     but look for errors. */  save_p = p;  info->print_address_func = dummy_print_address;  info->fprintf_func = (fprintf_ftype)dummy_printer;  for ( ; *d; d += 2)    {      int eaten = print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);      if (eaten >= 0)	p += eaten;      else if (eaten == -1)	goto invalid;      else	{	  (*info->fprintf_func)(info->stream,				/* xgettext:c-format */				_("<internal error in opcode table: %s %s>\n"),				best->name,				best->args);	  goto invalid;	}    }  p = save_p;  info->fprintf_func = save_printer;  info->print_address_func = save_print_address;  d = best->args;  (*info->fprintf_func) (info->stream, "%s", best->name);

⌨️ 快捷键说明

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