+Wed Mar 31 10:25:29 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * objdump.c (disassemble_data): Use new read_memory_func stuff.
+
Thu Mar 25 10:38:11 1993 Ken Raeburn (raeburn@cambridge.cygnus.com)
* objdump.c (fprintf): Declaration of variadic function had better
bfd_get_section_contents (abfd, section, data, 0, bfd_get_section_size_before_reloc (section));
+ disasm_info.buffer = data;
+ disasm_info.buffer_vma = section->vma;
+ disasm_info.buffer_length =
+ bfd_get_section_size_before_reloc (section);
i = 0;
- while (i < bfd_get_section_size_before_reloc (section))
+ while (i < disasm_info.buffer_length)
{
if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0 &&
data[i + 3] == 0)
printf (" ");
if (disassemble) /* New style */
- i += (*disassemble)(section->vma + i,
- data + i,
- &disasm_info);
+ {
+ int bytes = (*disassemble)(section->vma + i,
+ &disasm_info);
+ if (bytes < 0)
+ break;
+ i += bytes;
+ }
else /* Old style */
i += print (section->vma + i,
data + i,
+Wed Mar 31 12:52:12 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * core.c (dis_asm_{read_memory,memory_error}): New functions.
+ m68k-pinsn.c, h8500-tdep.c, i386-pinsn.c, mips-pinsn.c, z8k-tdep.c:
+ Use read_memory_func interface to disassembler.
+
Tue Mar 30 15:46:14 1993 K. Richard Pixley (rich@rtl.cygnus.com)
Teach sparc solaris to next over shared library functions.
#include "bfd.h"
#include "target.h"
#include "gdbcore.h"
+#include "dis-asm.h"
extern char registers[];
memory_error (status, memaddr);
}
+/* Like target_read_memory, but slightly different parameters. */
+int
+dis_asm_read_memory (memaddr, myaddr, len, info)
+ bfd_vma memaddr;
+ bfd_byte *myaddr;
+ int len;
+ disassemble_info *info;
+{
+ return target_read_memory (memaddr, myaddr, len);
+}
+
+/* Like memory_error with slightly different parameters. */
+void
+dis_asm_memory_error (status, memaddr, info)
+ int status;
+ bfd_vma memaddr;
+ disassemble_info *info;
+{
+ memory_error (status, memaddr);
+}
+
/* Same as target_write_memory, but report an error if can't write. */
void
write_memory (memaddr, myaddr, len)
CORE_ADDR memaddr;
FILE *stream;
{
- /* Nothing is bigger than 8 bytes */
- char data[8];
disassemble_info info;
- read_memory (memaddr, data, sizeof (data));
GDB_INIT_DISASSEMBLE_INFO(info, stream);
- return print_insn_h8500 (memaddr, data, &info);
+ return print_insn_h8500 (memaddr, &info);
}
/* Given a GDB frame, determine the address of the calling function's frame.
#include "defs.h"
#include "dis-asm.h"
-#define MAXLEN 20
\f
-/* Print the m68k instruction at address MEMADDR in debugged memory,
+/* Print the instruction at address MEMADDR in debugged memory,
on STREAM. Returns length of the instruction, in bytes. */
int
CORE_ADDR memaddr;
FILE *stream;
{
- unsigned char buffer[MAXLEN];
- register int i;
- register unsigned char *p;
- register char *d;
- register int bestmask;
- int best;
disassemble_info info;
GDB_INIT_DISASSEMBLE_INFO(info, stream);
- read_memory (memaddr, (char *) buffer, MAXLEN);
- return print_insn_i386 (memaddr, buffer, &info);
+ return print_insn_i386 (memaddr, &info);
}
#include "defs.h"
#include "dis-asm.h"
-/* m68k instructions are never longer than this many bytes. */
-#define MAXLEN 22
-\f
/* Print the m68k instruction at address MEMADDR in debugged memory,
on STREAM. Returns length of the instruction, in bytes. */
CORE_ADDR memaddr;
FILE *stream;
{
- unsigned char buffer[MAXLEN];
- register int i;
- register unsigned char *p;
- register char *d;
- register int bestmask;
- int best;
disassemble_info info;
GDB_INIT_DISASSEMBLE_INFO(info, stream);
- read_memory (memaddr, (char *) buffer, MAXLEN);
- return print_insn_m68k (memaddr, buffer, &info);
+ return print_insn_m68k (memaddr, &info);
}
#include "defs.h"
#include "dis-asm.h"
-/* Mips instructions are never longer than this many bytes. */
-#define MAXLEN 4
-
/* Print the mips instruction at address MEMADDR in debugged memory,
on STREAM. Returns length of the instruction, in bytes, which
is always 4. */
CORE_ADDR memaddr;
FILE *stream;
{
- unsigned char buffer[MAXLEN];
disassemble_info info;
GDB_INIT_DISASSEMBLE_INFO(info, stream);
- read_memory (memaddr, buffer, MAXLEN);
-
/* print_insn_mips is in opcodes/mips-dis.c. */
if (TARGET_BYTE_ORDER == BIG_ENDIAN)
- print_insn_big_mips (memaddr, buffer, &info);
+ print_insn_big_mips (memaddr, &info);
else
- print_insn_little_mips (memaddr, buffer, &info);
+ print_insn_little_mips (memaddr, &info);
}
CORE_ADDR memaddr;
FILE *stream;
{
- char temp[20];
disassemble_info info;
GDB_INIT_DISASSEMBLE_INFO(info, stream);
- read_memory (memaddr, temp, 20);
if (BIG)
{
- return print_insn_z8001 (memaddr, temp, &info);
+ return print_insn_z8001 (memaddr, &info);
}
else
{
- return print_insn_z8002 (memaddr, temp, &info);
+ return print_insn_z8002 (memaddr, &info);
}
}
+Tue Mar 30 19:09:23 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * dis-asm.h (disassembler_info): Add read_memory_func,
+ memory_error_func, buffer, buffer_length, and buffer_vma.
+ ({GDB_,}INIT_DISASSEMBLE_INFO): Set them.
+ print_insn_*: Remove second argument.
+
+Tue Mar 30 14:48:55 1993 Steve Chamberlain (sac@thepub.cygnus.com)
+
+ * bfd.h: Update for lma field of section.
+
Tue Mar 30 12:22:55 1993 Jim Kingdon (kingdon@cygnus.com)
* ansidecl.h: Use ANSI versions on AIX regardless of __STDC__.
typedef struct disassemble_info {
fprintf_ftype fprintf_func;
FILE *stream;
+
+ /* For use by the disassembler. */
int flags;
+ PTR private_data;
+
+ /* Function used to get bytes to disassemble. MEMADDR is the
+ address of the stuff to be disassembled, MYADDR is the address to
+ put the bytes in, and LENGTH is the number of bytes to read.
+ INFO is a pointer to this struct.
+ Returns an errno value or 0 for success. */
+ int (*read_memory_func)
+ PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, int length,
+ struct disassemble_info *info));
+
+ /* Function which should be called if we get an error that we can't
+ recover from. STATUS is the errno value from read_memory_func and
+ MEMADDR is the address that we were trying to read. INFO is a
+ pointer to this struct. */
+ void (*memory_error_func)
+ PARAMS ((int status, bfd_vma memaddr, struct disassemble_info *info));
+
+ /* These are for buffer_read_memory. */
+ bfd_byte *buffer;
+ bfd_vma buffer_vma;
+ int buffer_length;
} disassemble_info;
-typedef int (*disassembler_ftype)
- PARAMS((bfd_vma, bfd_byte *, disassemble_info *));
+/* Here is a function which callers may wish to use for read_memory_func.
+ It gets bytes from a buffer. */
+extern int buffer_read_memory
+ PARAMS ((bfd_vma, bfd_byte *, int, struct disassemble_info *));
+
+/* This function goes with buffer_read_memory.
+ It prints a message using info->fprintf_func and info->stream. */
+extern void perror_memory PARAMS ((int, bfd_vma, struct disassemble_info *));
#define INIT_DISASSEMBLE_INFO(INFO, STREAM) \
- INFO.fprintf_func = (fprintf_ftype)fprintf, \
- INFO.stream = (STREAM)
+ (INFO).fprintf_func = (fprintf_ftype)fprintf, \
+ (INFO).stream = (STREAM), \
+ (INFO).buffer = NULL, \
+ (INFO).buffer_vma = 0, \
+ (INFO).buffer_length = 0, \
+ (INFO).read_memory_func = buffer_read_memory, \
+ (INFO).memory_error_func = perror_memory
+
+/* GDB--Like target_read_memory, but slightly different parameters. */
+extern int
+dis_asm_read_memory PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, int len));
+
+/* GDB--Like memory_error with slightly different parameters. */
+extern void
+dis_asm_memory_error
+ PARAMS ((int status, bfd_vma memaddr, disassembler_info *info));
#define GDB_INIT_DISASSEMBLE_INFO(INFO, STREAM) \
- INFO.fprintf_func = (fprintf_ftype)fprintf_filtered, \
- INFO.stream = (STREAM)
-
-/* Standard dis-assemblers. */
-
-extern int print_insn_big_mips PARAMS ((bfd_vma, bfd_byte*,disassemble_info*));
-extern int print_insn_little_mips
- PARAMS ((bfd_vma,bfd_byte*,disassemble_info*));
-extern int print_insn_i386 PARAMS ((bfd_vma,bfd_byte*,disassemble_info*));
-extern int print_insn_m68k PARAMS ((bfd_vma,bfd_byte*,disassemble_info*));
-extern int print_insn_z8001 PARAMS ((bfd_vma,bfd_byte*,disassemble_info*));
-extern int print_insn_z8002 PARAMS ((bfd_vma,bfd_byte*,disassemble_info*));
+ (INFO).fprintf_func = (fprintf_ftype)fprintf_filtered, \
+ (INFO).stream = (STREAM), \
+ (INFO).read_memory_func = dis_asm_read_memory, \
+ (INFO).memory_error_func = dis_asm_memory_error
+
+
+/* Standard disassemblers. Disassemble one instruction at the given
+ target address. Return number of bytes processed. */
+typedef int (*disassembler_ftype)
+ PARAMS((bfd_vma, disassemble_info *));
+
+extern int print_insn_big_mips PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_little_mips PARAMS ((bfd_vma,disassemble_info*));
+extern int print_insn_i386 PARAMS ((bfd_vma,disassemble_info*));
+extern int print_insn_m68k PARAMS ((bfd_vma,disassemble_info*));
+extern int print_insn_z8001 PARAMS ((bfd_vma,disassemble_info*));
+extern int print_insn_z8002 PARAMS ((bfd_vma,disassemble_info*));
+extern int print_insn_h8500 PARAMS ((bfd_vma,disassemble_info*));
+Wed Mar 31 10:07:04 1993 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * dis-buf.c: New file, for new read_memory_func interface.
+ Makefile.in (OFILES): Include it.
+ m68k-dis.c, i386-dis.c, h8500-dis.c, mips-dis.c, z8k-dis.c:
+ Use new read_memory_func interface.
+
+Mon Mar 29 14:02:17 1993 Steve Chamberlain (sac@thepub.cygnus.com)
+
+ * h8500-dis.c (print_insn_h8500): Get sign of fp offsets right.
+ * h8500-opc.h: Fix couple of opcodes.
+
+Wed Mar 24 02:03:36 1993 david d `zoo' zuhn (zoo at poseidon.cygnus.com)
+
+ * Makefile.in: add dvi & installcheck targets
+
Mon Mar 22 18:55:04 1993 John Gilmore (gnu@cygnus.com)
* Makefile.in: Update for h8500-dis.c.
TARGETLIB = libopcodes.a
-DIS_LIBS = i386-dis.o z8k-dis.o m68k-dis.o mips-dis.o h8500-dis.o
+DIS_LIBS = i386-dis.o z8k-dis.o m68k-dis.o mips-dis.o h8500-dis.o dis-buf.o
OFILES = $(DIS_LIBS) sparc-opc.o m68881-ext.o
#### host and target dependent Makefile fragments come in here.
.NOEXPORT:
-check:
+installcheck check:
info:
clean-info:
install-info:
+dvi:
# HDEPFILES comes from the host config; TDEPFILES from the target config.
--- /dev/null
+/* Disassemble h8500 instructions.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the 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 of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+
+#define DISASSEMBLER_TABLE
+#define DEFINE_TABLE
+
+#include "h8500-opc.h"
+#include "dis-asm.h"
+
+/* Maximum length of an instruction. */
+#define MAXLEN 8
+
+#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 int
+fetch_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);
+ }
+ else
+ priv->max_fetched = addr;
+ return 1;
+}
+
+static char *crname[] =
+{"sr", "ccr", "*", "br", "ep", "dp", "*", "tp"};
+
+int
+print_insn_h8500 (addr, info)
+ unsigned long addr;
+ disassemble_info *info;
+{
+ h8500_opcode_info *opcode;
+ void *stream = info->stream;
+ fprintf_ftype func = info->fprintf_func;
+
+ struct private priv;
+ bfd_byte *buffer = priv.the_buffer;
+
+ info->private_data = (PTR) &priv;
+ priv.max_fetched = priv.the_buffer;
+ priv.insn_start = addr;
+ if (setjmp (priv.bailout) != 0)
+ /* Error return. */
+ return -1;
+
+ /* Run down the table to find the one which matches */
+ for (opcode = h8500_table; opcode->name; opcode++)
+ {
+ int byte;
+ int rn;
+ int rd;
+ int rs;
+ int disp;
+ int abs;
+ int imm;
+ int pcrel;
+ int qim;
+ int i;
+ int cr;
+ for (byte = 0; byte < opcode->length; byte++)
+ {
+ FETCH_DATA (info, buffer + byte + 1);
+ if ((buffer[byte] & opcode->bytes[byte].mask)
+ != (opcode->bytes[byte].contents))
+ {
+ goto next;
+ }
+ else
+ {
+ /* extract any info parts */
+ switch (opcode->bytes[byte].insert)
+ {
+ case 0:
+ case FP:
+ break;
+ default:
+ func (stream, "can't cope with insert %d\n",
+ opcode->bytes[byte].insert);
+ break;
+ case RN:
+ rn = buffer[byte] & 0x7;
+ break;
+ case RS:
+ rs = buffer[byte] & 0x7;
+ break;
+ case CRB:
+ cr = buffer[byte] & 0x7;
+ if (cr == 0)
+ goto next;
+ break;
+ case CRW:
+ cr = buffer[byte] & 0x7;
+ if (cr != 0)
+ goto next;
+ break;
+ case DISP16:
+ FETCH_DATA (info, buffer + byte + 2);
+ disp = (buffer[byte] << 8) | (buffer[byte + 1]);
+ break;
+ case FPIND_D8:
+ case DISP8:
+ disp = ((char) (buffer[byte]));
+ break;
+ case RD:
+ case RDIND:
+ rd = buffer[byte] & 0x7;
+ break;
+ case ABS24:
+ FETCH_DATA (info, buffer + byte + 3);
+ abs =
+ (buffer[byte] << 16)
+ | (buffer[byte + 1] << 8)
+ | (buffer[byte + 2]);
+ break;
+ case ABS16:
+ FETCH_DATA (info, buffer + byte + 2);
+ abs = (buffer[byte] << 8) | (buffer[byte + 1]);
+ break;
+ case ABS8:
+ abs = (buffer[byte]);
+ break;
+ case IMM16:
+ FETCH_DATA (info, buffer + byte + 2);
+ imm = (buffer[byte] << 8) | (buffer[byte + 1]);
+ break;
+ case IMM4:
+ imm = (buffer[byte]) & 0xf;
+ break;
+ case IMM8:
+ case RLIST:
+ imm = (buffer[byte]);
+ break;
+ case PCREL16:
+ FETCH_DATA (info, buffer + byte + 2);
+ pcrel = (buffer[byte] << 8) | (buffer[byte + 1]);
+ break;
+ case PCREL8:
+ pcrel = (buffer[byte]);
+ break;
+ case QIM:
+ switch (buffer[byte] & 0x7)
+ {
+ case 0:
+ qim = 1;
+ break;
+ case 1:
+ qim = 2;
+ break;
+ case 4:
+ qim = -1;
+ break;
+ case 5:
+ qim = -2;
+ break;
+ }
+ break;
+
+ }
+ }
+ }
+ /* We get here when all the masks have passed so we can output the
+ operands*/
+ FETCH_DATA (info, buffer + opcode->length);
+ for (i = 0; i < opcode->length; i++)
+ {
+ (func) (stream, "%02x ", buffer[i]);
+ }
+ for (; i < 6; i++)
+ {
+ (func) (stream, " ");
+ }
+ (func) (stream, "%s\t", opcode->name);
+ for (i = 0; i < opcode->nargs; i++)
+ {
+ if (i)
+ (func) (stream, ",");
+ switch (opcode->arg_type[i])
+ {
+ case FP:
+ func (stream, "fp");
+ break;
+ case RNIND_D16:
+ func (stream, "@(0x%x:16,r%d)", disp, rn);
+ break;
+ case RNIND_D8:
+ func (stream, "@(0x%x:8 (%d),r%d)", disp & 0xff, disp, rn);
+ break;
+ case RDIND_D16:
+ func (stream, "@(0x%x:16,r%d)", disp, rd);
+ break;
+ case RDIND_D8:
+ func (stream, "@(0x%x:8 (%d), r%d)", disp & 0xff, disp, rd);
+ break;
+ case FPIND_D8:
+ func (stream, "@(0x%x:8 (%d), fp)", disp & 0xff, disp, rn);
+ break;
+ case CRB:
+ case CRW:
+ func (stream, "%s", crname[cr]);
+ break;
+ case RN:
+ func (stream, "r%d", rn);
+ break;
+ case RD:
+ func (stream, "r%d", rd);
+ break;
+ case RS:
+ func (stream, "r%d", rs);
+ break;
+ case RNDEC:
+ func (stream, "@-r%d", rn);
+ break;
+ case RNINC:
+ func (stream, "@r%d+", rn);
+ break;
+ case RNIND:
+ func (stream, "@r%d", rn);
+ break;
+ case RDIND:
+ func (stream, "@r%d", rd);
+ break;
+ case SPINC:
+ func (stream, "@sp+");
+ break;
+ case SPDEC:
+ func (stream, "@-sp");
+ break;
+ case ABS24:
+ func (stream, "@0x%0x:24", abs);
+ break;
+ case ABS16:
+ func (stream, "@0x%0x:16", abs & 0xffff);
+ break;
+ case ABS8:
+ func (stream, "@0x%0x:8", abs & 0xff);
+ break;
+ case IMM16:
+ func (stream, "#0x%0x:16", imm & 0xffff);
+ break;
+ case RLIST:
+ {
+ int i;
+ int nc = 0;
+ func (stream, "(");
+ for (i = 0; i < 8; i++)
+ {
+ if (imm & (1 << i))
+ {
+ if (nc)
+ func (stream, ",");
+ nc += 1;
+ }
+ func (stream, "r%d", i);
+ }
+ func (stream, ")");
+ }
+ break;
+ case IMM8:
+ func (stream, "#0x%0x:8", imm & 0xff);
+ break;
+ case PCREL16:
+ func (stream, "0x%0x:16", (pcrel + addr + opcode->length) & 0xffff);
+ break;
+ case PCREL8:
+ func (stream, "#0x%0x:8",
+ ((char) pcrel + addr + opcode->length) & 0xffff);
+ break;
+ case QIM:
+ func (stream, "#%d:q", qim);
+ break;
+ case IMM4:
+ func (stream, "#%d:4", imm);
+ break;
+ }
+ }
+ return opcode->length;
+ next:;
+ }
+
+ /* Couldn't understand anything */
+ func (stream, "%02x\t\t*unknown*", buffer[0]);
+ return 1;
+
+}
--- /dev/null
+/* Print i386 instructions for GDB, the GNU debugger.
+ Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the 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 of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu)
+ * July 1988
+ * modified by John Hassey (hassey@dg-rtp.dg.com)
+ */
+
+/*
+ * The main tables describing the instructions is essentially a copy
+ * of the "Opcode Map" chapter (Appendix A) of the Intel 80386
+ * Programmers Manual. Usually, there is a capital letter, followed
+ * by a small letter. The capital letter tell the addressing mode,
+ * and the small letter tells about the operand size. Refer to
+ * the Intel manual for details.
+ */
+
+#include "dis-asm.h"
+
+#define MAXLEN 20
+
+#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 int
+fetch_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);
+ }
+ else
+ priv->max_fetched = addr;
+ return 1;
+}
+
+#define Eb OP_E, b_mode
+#define indirEb OP_indirE, b_mode
+#define Gb OP_G, b_mode
+#define Ev OP_E, v_mode
+#define indirEv OP_indirE, v_mode
+#define Ew OP_E, w_mode
+#define Ma OP_E, v_mode
+#define M OP_E, 0
+#define Mp OP_E, 0 /* ? */
+#define Gv OP_G, v_mode
+#define Gw OP_G, w_mode
+#define Rw OP_rm, w_mode
+#define Rd OP_rm, d_mode
+#define Ib OP_I, b_mode
+#define sIb OP_sI, b_mode /* sign extened byte */
+#define Iv OP_I, v_mode
+#define Iw OP_I, w_mode
+#define Jb OP_J, b_mode
+#define Jv OP_J, v_mode
+#define ONE OP_ONE, 0
+#define Cd OP_C, d_mode
+#define Dd OP_D, d_mode
+#define Td OP_T, d_mode
+
+#define eAX OP_REG, eAX_reg
+#define eBX OP_REG, eBX_reg
+#define eCX OP_REG, eCX_reg
+#define eDX OP_REG, eDX_reg
+#define eSP OP_REG, eSP_reg
+#define eBP OP_REG, eBP_reg
+#define eSI OP_REG, eSI_reg
+#define eDI OP_REG, eDI_reg
+#define AL OP_REG, al_reg
+#define CL OP_REG, cl_reg
+#define DL OP_REG, dl_reg
+#define BL OP_REG, bl_reg
+#define AH OP_REG, ah_reg
+#define CH OP_REG, ch_reg
+#define DH OP_REG, dh_reg
+#define BH OP_REG, bh_reg
+#define AX OP_REG, ax_reg
+#define DX OP_REG, dx_reg
+#define indirDX OP_REG, indir_dx_reg
+
+#define Sw OP_SEG, w_mode
+#define Ap OP_DIR, lptr
+#define Av OP_DIR, v_mode
+#define Ob OP_OFF, b_mode
+#define Ov OP_OFF, v_mode
+#define Xb OP_DSSI, b_mode
+#define Xv OP_DSSI, v_mode
+#define Yb OP_ESDI, b_mode
+#define Yv OP_ESDI, v_mode
+
+#define es OP_REG, es_reg
+#define ss OP_REG, ss_reg
+#define cs OP_REG, cs_reg
+#define ds OP_REG, ds_reg
+#define fs OP_REG, fs_reg
+#define gs OP_REG, gs_reg
+
+int OP_E(), OP_indirE(), OP_G(), OP_I(), OP_sI(), OP_REG();
+int OP_J(), OP_SEG();
+int OP_DIR(), OP_OFF(), OP_DSSI(), OP_ESDI(), OP_ONE(), OP_C();
+int OP_D(), OP_T(), OP_rm();
+
+static void dofloat (), putop (), append_prefix (), set_op ();
+static int get16 (), get32 ();
+
+#define b_mode 1
+#define v_mode 2
+#define w_mode 3
+#define d_mode 4
+
+#define es_reg 100
+#define cs_reg 101
+#define ss_reg 102
+#define ds_reg 103
+#define fs_reg 104
+#define gs_reg 105
+#define eAX_reg 107
+#define eCX_reg 108
+#define eDX_reg 109
+#define eBX_reg 110
+#define eSP_reg 111
+#define eBP_reg 112
+#define eSI_reg 113
+#define eDI_reg 114
+
+#define lptr 115
+
+#define al_reg 116
+#define cl_reg 117
+#define dl_reg 118
+#define bl_reg 119
+#define ah_reg 120
+#define ch_reg 121
+#define dh_reg 122
+#define bh_reg 123
+
+#define ax_reg 124
+#define cx_reg 125
+#define dx_reg 126
+#define bx_reg 127
+#define sp_reg 128
+#define bp_reg 129
+#define si_reg 130
+#define di_reg 131
+
+#define indir_dx_reg 150
+
+#define GRP1b NULL, NULL, 0
+#define GRP1S NULL, NULL, 1
+#define GRP1Ss NULL, NULL, 2
+#define GRP2b NULL, NULL, 3
+#define GRP2S NULL, NULL, 4
+#define GRP2b_one NULL, NULL, 5
+#define GRP2S_one NULL, NULL, 6
+#define GRP2b_cl NULL, NULL, 7
+#define GRP2S_cl NULL, NULL, 8
+#define GRP3b NULL, NULL, 9
+#define GRP3S NULL, NULL, 10
+#define GRP4 NULL, NULL, 11
+#define GRP5 NULL, NULL, 12
+#define GRP6 NULL, NULL, 13
+#define GRP7 NULL, NULL, 14
+#define GRP8 NULL, NULL, 15
+
+#define FLOATCODE 50
+#define FLOAT NULL, NULL, FLOATCODE
+
+struct dis386 {
+ char *name;
+ int (*op1)();
+ int bytemode1;
+ int (*op2)();
+ int bytemode2;
+ int (*op3)();
+ int bytemode3;
+};
+
+struct dis386 dis386[] = {
+ /* 00 */
+ { "addb", Eb, Gb },
+ { "addS", Ev, Gv },
+ { "addb", Gb, Eb },
+ { "addS", Gv, Ev },
+ { "addb", AL, Ib },
+ { "addS", eAX, Iv },
+ { "pushl", es },
+ { "popl", es },
+ /* 08 */
+ { "orb", Eb, Gb },
+ { "orS", Ev, Gv },
+ { "orb", Gb, Eb },
+ { "orS", Gv, Ev },
+ { "orb", AL, Ib },
+ { "orS", eAX, Iv },
+ { "pushl", cs },
+ { "(bad)" }, /* 0x0f extended opcode escape */
+ /* 10 */
+ { "adcb", Eb, Gb },
+ { "adcS", Ev, Gv },
+ { "adcb", Gb, Eb },
+ { "adcS", Gv, Ev },
+ { "adcb", AL, Ib },
+ { "adcS", eAX, Iv },
+ { "pushl", ss },
+ { "popl", ss },
+ /* 18 */
+ { "sbbb", Eb, Gb },
+ { "sbbS", Ev, Gv },
+ { "sbbb", Gb, Eb },
+ { "sbbS", Gv, Ev },
+ { "sbbb", AL, Ib },
+ { "sbbS", eAX, Iv },
+ { "pushl", ds },
+ { "popl", ds },
+ /* 20 */
+ { "andb", Eb, Gb },
+ { "andS", Ev, Gv },
+ { "andb", Gb, Eb },
+ { "andS", Gv, Ev },
+ { "andb", AL, Ib },
+ { "andS", eAX, Iv },
+ { "(bad)" }, /* SEG ES prefix */
+ { "daa" },
+ /* 28 */
+ { "subb", Eb, Gb },
+ { "subS", Ev, Gv },
+ { "subb", Gb, Eb },
+ { "subS", Gv, Ev },
+ { "subb", AL, Ib },
+ { "subS", eAX, Iv },
+ { "(bad)" }, /* SEG CS prefix */
+ { "das" },
+ /* 30 */
+ { "xorb", Eb, Gb },
+ { "xorS", Ev, Gv },
+ { "xorb", Gb, Eb },
+ { "xorS", Gv, Ev },
+ { "xorb", AL, Ib },
+ { "xorS", eAX, Iv },
+ { "(bad)" }, /* SEG SS prefix */
+ { "aaa" },
+ /* 38 */
+ { "cmpb", Eb, Gb },
+ { "cmpS", Ev, Gv },
+ { "cmpb", Gb, Eb },
+ { "cmpS", Gv, Ev },
+ { "cmpb", AL, Ib },
+ { "cmpS", eAX, Iv },
+ { "(bad)" }, /* SEG DS prefix */
+ { "aas" },
+ /* 40 */
+ { "incS", eAX },
+ { "incS", eCX },
+ { "incS", eDX },
+ { "incS", eBX },
+ { "incS", eSP },
+ { "incS", eBP },
+ { "incS", eSI },
+ { "incS", eDI },
+ /* 48 */
+ { "decS", eAX },
+ { "decS", eCX },
+ { "decS", eDX },
+ { "decS", eBX },
+ { "decS", eSP },
+ { "decS", eBP },
+ { "decS", eSI },
+ { "decS", eDI },
+ /* 50 */
+ { "pushS", eAX },
+ { "pushS", eCX },
+ { "pushS", eDX },
+ { "pushS", eBX },
+ { "pushS", eSP },
+ { "pushS", eBP },
+ { "pushS", eSI },
+ { "pushS", eDI },
+ /* 58 */
+ { "popS", eAX },
+ { "popS", eCX },
+ { "popS", eDX },
+ { "popS", eBX },
+ { "popS", eSP },
+ { "popS", eBP },
+ { "popS", eSI },
+ { "popS", eDI },
+ /* 60 */
+ { "pusha" },
+ { "popa" },
+ { "boundS", Gv, Ma },
+ { "arpl", Ew, Gw },
+ { "(bad)" }, /* seg fs */
+ { "(bad)" }, /* seg gs */
+ { "(bad)" }, /* op size prefix */
+ { "(bad)" }, /* adr size prefix */
+ /* 68 */
+ { "pushS", Iv }, /* 386 book wrong */
+ { "imulS", Gv, Ev, Iv },
+ { "pushl", sIb }, /* push of byte really pushes 4 bytes */
+ { "imulS", Gv, Ev, Ib },
+ { "insb", Yb, indirDX },
+ { "insS", Yv, indirDX },
+ { "outsb", indirDX, Xb },
+ { "outsS", indirDX, Xv },
+ /* 70 */
+ { "jo", Jb },
+ { "jno", Jb },
+ { "jb", Jb },
+ { "jae", Jb },
+ { "je", Jb },
+ { "jne", Jb },
+ { "jbe", Jb },
+ { "ja", Jb },
+ /* 78 */
+ { "js", Jb },
+ { "jns", Jb },
+ { "jp", Jb },
+ { "jnp", Jb },
+ { "jl", Jb },
+ { "jnl", Jb },
+ { "jle", Jb },
+ { "jg", Jb },
+ /* 80 */
+ { GRP1b },
+ { GRP1S },
+ { "(bad)" },
+ { GRP1Ss },
+ { "testb", Eb, Gb },
+ { "testS", Ev, Gv },
+ { "xchgb", Eb, Gb },
+ { "xchgS", Ev, Gv },
+ /* 88 */
+ { "movb", Eb, Gb },
+ { "movS", Ev, Gv },
+ { "movb", Gb, Eb },
+ { "movS", Gv, Ev },
+ { "movw", Ew, Sw },
+ { "leaS", Gv, M },
+ { "movw", Sw, Ew },
+ { "popS", Ev },
+ /* 90 */
+ { "nop" },
+ { "xchgS", eCX, eAX },
+ { "xchgS", eDX, eAX },
+ { "xchgS", eBX, eAX },
+ { "xchgS", eSP, eAX },
+ { "xchgS", eBP, eAX },
+ { "xchgS", eSI, eAX },
+ { "xchgS", eDI, eAX },
+ /* 98 */
+ { "cwtl" },
+ { "cltd" },
+ { "lcall", Ap },
+ { "(bad)" }, /* fwait */
+ { "pushf" },
+ { "popf" },
+ { "sahf" },
+ { "lahf" },
+ /* a0 */
+ { "movb", AL, Ob },
+ { "movS", eAX, Ov },
+ { "movb", Ob, AL },
+ { "movS", Ov, eAX },
+ { "movsb", Yb, Xb },
+ { "movsS", Yv, Xv },
+ { "cmpsb", Yb, Xb },
+ { "cmpsS", Yv, Xv },
+ /* a8 */
+ { "testb", AL, Ib },
+ { "testS", eAX, Iv },
+ { "stosb", Yb, AL },
+ { "stosS", Yv, eAX },
+ { "lodsb", AL, Xb },
+ { "lodsS", eAX, Xv },
+ { "scasb", AL, Xb },
+ { "scasS", eAX, Xv },
+ /* b0 */
+ { "movb", AL, Ib },
+ { "movb", CL, Ib },
+ { "movb", DL, Ib },
+ { "movb", BL, Ib },
+ { "movb", AH, Ib },
+ { "movb", CH, Ib },
+ { "movb", DH, Ib },
+ { "movb", BH, Ib },
+ /* b8 */
+ { "movS", eAX, Iv },
+ { "movS", eCX, Iv },
+ { "movS", eDX, Iv },
+ { "movS", eBX, Iv },
+ { "movS", eSP, Iv },
+ { "movS", eBP, Iv },
+ { "movS", eSI, Iv },
+ { "movS", eDI, Iv },
+ /* c0 */
+ { GRP2b },
+ { GRP2S },
+ { "ret", Iw },
+ { "ret" },
+ { "lesS", Gv, Mp },
+ { "ldsS", Gv, Mp },
+ { "movb", Eb, Ib },
+ { "movS", Ev, Iv },
+ /* c8 */
+ { "enter", Iw, Ib },
+ { "leave" },
+ { "lret", Iw },
+ { "lret" },
+ { "int3" },
+ { "int", Ib },
+ { "into" },
+ { "iret" },
+ /* d0 */
+ { GRP2b_one },
+ { GRP2S_one },
+ { GRP2b_cl },
+ { GRP2S_cl },
+ { "aam", Ib },
+ { "aad", Ib },
+ { "(bad)" },
+ { "xlat" },
+ /* d8 */
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ /* e0 */
+ { "loopne", Jb },
+ { "loope", Jb },
+ { "loop", Jb },
+ { "jCcxz", Jb },
+ { "inb", AL, Ib },
+ { "inS", eAX, Ib },
+ { "outb", Ib, AL },
+ { "outS", Ib, eAX },
+ /* e8 */
+ { "call", Av },
+ { "jmp", Jv },
+ { "ljmp", Ap },
+ { "jmp", Jb },
+ { "inb", AL, indirDX },
+ { "inS", eAX, indirDX },
+ { "outb", indirDX, AL },
+ { "outS", indirDX, eAX },
+ /* f0 */
+ { "(bad)" }, /* lock prefix */
+ { "(bad)" },
+ { "(bad)" }, /* repne */
+ { "(bad)" }, /* repz */
+ { "hlt" },
+ { "cmc" },
+ { GRP3b },
+ { GRP3S },
+ /* f8 */
+ { "clc" },
+ { "stc" },
+ { "cli" },
+ { "sti" },
+ { "cld" },
+ { "std" },
+ { GRP4 },
+ { GRP5 },
+};
+
+struct dis386 dis386_twobyte[] = {
+ /* 00 */
+ { GRP6 },
+ { GRP7 },
+ { "larS", Gv, Ew },
+ { "lslS", Gv, Ew },
+ { "(bad)" },
+ { "(bad)" },
+ { "clts" },
+ { "(bad)" },
+ /* 08 */
+ { "invd" },
+ { "wbinvd" },
+ { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 10 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 18 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 20 */
+ /* these are all backward in appendix A of the intel book */
+ { "movl", Rd, Cd },
+ { "movl", Rd, Dd },
+ { "movl", Cd, Rd },
+ { "movl", Dd, Rd },
+ { "movl", Rd, Td },
+ { "(bad)" },
+ { "movl", Td, Rd },
+ { "(bad)" },
+ /* 28 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 30 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 38 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 40 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 48 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 50 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 58 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 60 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 68 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 70 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 78 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 80 */
+ { "jo", Jv },
+ { "jno", Jv },
+ { "jb", Jv },
+ { "jae", Jv },
+ { "je", Jv },
+ { "jne", Jv },
+ { "jbe", Jv },
+ { "ja", Jv },
+ /* 88 */
+ { "js", Jv },
+ { "jns", Jv },
+ { "jp", Jv },
+ { "jnp", Jv },
+ { "jl", Jv },
+ { "jge", Jv },
+ { "jle", Jv },
+ { "jg", Jv },
+ /* 90 */
+ { "seto", Eb },
+ { "setno", Eb },
+ { "setb", Eb },
+ { "setae", Eb },
+ { "sete", Eb },
+ { "setne", Eb },
+ { "setbe", Eb },
+ { "seta", Eb },
+ /* 98 */
+ { "sets", Eb },
+ { "setns", Eb },
+ { "setp", Eb },
+ { "setnp", Eb },
+ { "setl", Eb },
+ { "setge", Eb },
+ { "setle", Eb },
+ { "setg", Eb },
+ /* a0 */
+ { "pushl", fs },
+ { "popl", fs },
+ { "(bad)" },
+ { "btS", Ev, Gv },
+ { "shldS", Ev, Gv, Ib },
+ { "shldS", Ev, Gv, CL },
+ { "(bad)" },
+ { "(bad)" },
+ /* a8 */
+ { "pushl", gs },
+ { "popl", gs },
+ { "(bad)" },
+ { "btsS", Ev, Gv },
+ { "shrdS", Ev, Gv, Ib },
+ { "shrdS", Ev, Gv, CL },
+ { "(bad)" },
+ { "imulS", Gv, Ev },
+ /* b0 */
+ { "cmpxchgb", Eb, Gb },
+ { "cmpxchgS", Ev, Gv },
+ { "lssS", Gv, Mp }, /* 386 lists only Mp */
+ { "btrS", Ev, Gv },
+ { "lfsS", Gv, Mp }, /* 386 lists only Mp */
+ { "lgsS", Gv, Mp }, /* 386 lists only Mp */
+ { "movzbS", Gv, Eb },
+ { "movzwS", Gv, Ew },
+ /* b8 */
+ { "(bad)" },
+ { "(bad)" },
+ { GRP8 },
+ { "btcS", Ev, Gv },
+ { "bsfS", Gv, Ev },
+ { "bsrS", Gv, Ev },
+ { "movsbS", Gv, Eb },
+ { "movswS", Gv, Ew },
+ /* c0 */
+ { "xaddb", Eb, Gb },
+ { "xaddS", Ev, Gv },
+ { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* c8 */
+ { "bswap", eAX },
+ { "bswap", eCX },
+ { "bswap", eDX },
+ { "bswap", eBX },
+ { "bswap", eSP },
+ { "bswap", eBP },
+ { "bswap", eSI },
+ { "bswap", eDI },
+ /* d0 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* d8 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* e0 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* e8 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* f0 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* f8 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+};
+
+static char obuf[100];
+static char *obufp;
+static char scratchbuf[100];
+static unsigned char *start_codep;
+static unsigned char *codep;
+static disassemble_info *the_info;
+static int mod;
+static int rm;
+static int reg;
+static void oappend ();
+
+static char *names32[]={
+ "%eax","%ecx","%edx","%ebx", "%esp","%ebp","%esi","%edi",
+};
+static char *names16[] = {
+ "%ax","%cx","%dx","%bx","%sp","%bp","%si","%di",
+};
+static char *names8[] = {
+ "%al","%cl","%dl","%bl","%ah","%ch","%dh","%bh",
+};
+static char *names_seg[] = {
+ "%es","%cs","%ss","%ds","%fs","%gs","%?","%?",
+};
+
+struct dis386 grps[][8] = {
+ /* GRP1b */
+ {
+ { "addb", Eb, Ib },
+ { "orb", Eb, Ib },
+ { "adcb", Eb, Ib },
+ { "sbbb", Eb, Ib },
+ { "andb", Eb, Ib },
+ { "subb", Eb, Ib },
+ { "xorb", Eb, Ib },
+ { "cmpb", Eb, Ib }
+ },
+ /* GRP1S */
+ {
+ { "addS", Ev, Iv },
+ { "orS", Ev, Iv },
+ { "adcS", Ev, Iv },
+ { "sbbS", Ev, Iv },
+ { "andS", Ev, Iv },
+ { "subS", Ev, Iv },
+ { "xorS", Ev, Iv },
+ { "cmpS", Ev, Iv }
+ },
+ /* GRP1Ss */
+ {
+ { "addS", Ev, sIb },
+ { "orS", Ev, sIb },
+ { "adcS", Ev, sIb },
+ { "sbbS", Ev, sIb },
+ { "andS", Ev, sIb },
+ { "subS", Ev, sIb },
+ { "xorS", Ev, sIb },
+ { "cmpS", Ev, sIb }
+ },
+ /* GRP2b */
+ {
+ { "rolb", Eb, Ib },
+ { "rorb", Eb, Ib },
+ { "rclb", Eb, Ib },
+ { "rcrb", Eb, Ib },
+ { "shlb", Eb, Ib },
+ { "shrb", Eb, Ib },
+ { "(bad)" },
+ { "sarb", Eb, Ib },
+ },
+ /* GRP2S */
+ {
+ { "rolS", Ev, Ib },
+ { "rorS", Ev, Ib },
+ { "rclS", Ev, Ib },
+ { "rcrS", Ev, Ib },
+ { "shlS", Ev, Ib },
+ { "shrS", Ev, Ib },
+ { "(bad)" },
+ { "sarS", Ev, Ib },
+ },
+ /* GRP2b_one */
+ {
+ { "rolb", Eb },
+ { "rorb", Eb },
+ { "rclb", Eb },
+ { "rcrb", Eb },
+ { "shlb", Eb },
+ { "shrb", Eb },
+ { "(bad)" },
+ { "sarb", Eb },
+ },
+ /* GRP2S_one */
+ {
+ { "rolS", Ev },
+ { "rorS", Ev },
+ { "rclS", Ev },
+ { "rcrS", Ev },
+ { "shlS", Ev },
+ { "shrS", Ev },
+ { "(bad)" },
+ { "sarS", Ev },
+ },
+ /* GRP2b_cl */
+ {
+ { "rolb", Eb, CL },
+ { "rorb", Eb, CL },
+ { "rclb", Eb, CL },
+ { "rcrb", Eb, CL },
+ { "shlb", Eb, CL },
+ { "shrb", Eb, CL },
+ { "(bad)" },
+ { "sarb", Eb, CL },
+ },
+ /* GRP2S_cl */
+ {
+ { "rolS", Ev, CL },
+ { "rorS", Ev, CL },
+ { "rclS", Ev, CL },
+ { "rcrS", Ev, CL },
+ { "shlS", Ev, CL },
+ { "shrS", Ev, CL },
+ { "(bad)" },
+ { "sarS", Ev, CL }
+ },
+ /* GRP3b */
+ {
+ { "testb", Eb, Ib },
+ { "(bad)", Eb },
+ { "notb", Eb },
+ { "negb", Eb },
+ { "mulb", AL, Eb },
+ { "imulb", AL, Eb },
+ { "divb", AL, Eb },
+ { "idivb", AL, Eb }
+ },
+ /* GRP3S */
+ {
+ { "testS", Ev, Iv },
+ { "(bad)" },
+ { "notS", Ev },
+ { "negS", Ev },
+ { "mulS", eAX, Ev },
+ { "imulS", eAX, Ev },
+ { "divS", eAX, Ev },
+ { "idivS", eAX, Ev },
+ },
+ /* GRP4 */
+ {
+ { "incb", Eb },
+ { "decb", Eb },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ },
+ /* GRP5 */
+ {
+ { "incS", Ev },
+ { "decS", Ev },
+ { "call", indirEv },
+ { "lcall", indirEv },
+ { "jmp", indirEv },
+ { "ljmp", indirEv },
+ { "pushS", Ev },
+ { "(bad)" },
+ },
+ /* GRP6 */
+ {
+ { "sldt", Ew },
+ { "str", Ew },
+ { "lldt", Ew },
+ { "ltr", Ew },
+ { "verr", Ew },
+ { "verw", Ew },
+ { "(bad)" },
+ { "(bad)" }
+ },
+ /* GRP7 */
+ {
+ { "sgdt", Ew },
+ { "sidt", Ew },
+ { "lgdt", Ew },
+ { "lidt", Ew },
+ { "smsw", Ew },
+ { "(bad)" },
+ { "lmsw", Ew },
+ { "invlpg", Ew },
+ },
+ /* GRP8 */
+ {
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "btS", Ev, Ib },
+ { "btsS", Ev, Ib },
+ { "btrS", Ev, Ib },
+ { "btcS", Ev, Ib },
+ }
+};
+
+#define PREFIX_REPZ 1
+#define PREFIX_REPNZ 2
+#define PREFIX_LOCK 4
+#define PREFIX_CS 8
+#define PREFIX_SS 0x10
+#define PREFIX_DS 0x20
+#define PREFIX_ES 0x40
+#define PREFIX_FS 0x80
+#define PREFIX_GS 0x100
+#define PREFIX_DATA 0x200
+#define PREFIX_ADR 0x400
+#define PREFIX_FWAIT 0x800
+
+static int prefixes;
+
+static void
+ckprefix ()
+{
+ prefixes = 0;
+ while (1)
+ {
+ FETCH_DATA (the_info, codep + 1);
+ switch (*codep)
+ {
+ case 0xf3:
+ prefixes |= PREFIX_REPZ;
+ break;
+ case 0xf2:
+ prefixes |= PREFIX_REPNZ;
+ break;
+ case 0xf0:
+ prefixes |= PREFIX_LOCK;
+ break;
+ case 0x2e:
+ prefixes |= PREFIX_CS;
+ break;
+ case 0x36:
+ prefixes |= PREFIX_SS;
+ break;
+ case 0x3e:
+ prefixes |= PREFIX_DS;
+ break;
+ case 0x26:
+ prefixes |= PREFIX_ES;
+ break;
+ case 0x64:
+ prefixes |= PREFIX_FS;
+ break;
+ case 0x65:
+ prefixes |= PREFIX_GS;
+ break;
+ case 0x66:
+ prefixes |= PREFIX_DATA;
+ break;
+ case 0x67:
+ prefixes |= PREFIX_ADR;
+ break;
+ case 0x9b:
+ prefixes |= PREFIX_FWAIT;
+ break;
+ default:
+ return;
+ }
+ codep++;
+ }
+}
+
+static int dflag;
+static int aflag;
+
+static char op1out[100], op2out[100], op3out[100];
+static int op_address[3], op_ad, op_index[3];
+static int start_pc;
+
+\f
+/*
+ * On the 386's of 1988, the maximum length of an instruction is 15 bytes.
+ * (see topic "Redundant prefixes" in the "Differences from 8086"
+ * section of the "Virtual 8086 Mode" chapter.)
+ * 'pc' should be the address of this instruction, it will
+ * be used to print the target address if this is a relative jump or call
+ * The function returns the length of this instruction in bytes.
+ */
+
+int
+print_insn_i386 (pc, info)
+ bfd_vma pc;
+ disassemble_info *info;
+{
+ struct dis386 *dp;
+ int i;
+ int enter_instruction;
+ char *first, *second, *third;
+ int needcomma;
+
+ struct private priv;
+ bfd_byte *inbuf = priv.the_buffer;
+
+ info->private_data = (PTR) &priv;
+ priv.max_fetched = priv.the_buffer;
+ priv.insn_start = pc;
+ if (setjmp (priv.bailout) != 0)
+ /* Error return. */
+ return -1;
+
+ obuf[0] = 0;
+ op1out[0] = 0;
+ op2out[0] = 0;
+ op3out[0] = 0;
+
+ op_index[0] = op_index[1] = op_index[2] = -1;
+
+ the_info = info;
+ start_pc = pc;
+ start_codep = inbuf;
+ codep = inbuf;
+
+ ckprefix ();
+
+ FETCH_DATA (info, codep + 1);
+ if (*codep == 0xc8)
+ enter_instruction = 1;
+ else
+ enter_instruction = 0;
+
+ obufp = obuf;
+
+ if (prefixes & PREFIX_REPZ)
+ oappend ("repz ");
+ if (prefixes & PREFIX_REPNZ)
+ oappend ("repnz ");
+ if (prefixes & PREFIX_LOCK)
+ oappend ("lock ");
+
+ if ((prefixes & PREFIX_FWAIT)
+ && ((*codep < 0xd8) || (*codep > 0xdf)))
+ {
+ /* fwait not followed by floating point instruction */
+ (*info->fprintf_func) (info->stream, "fwait");
+ return (1);
+ }
+
+ /* these would be initialized to 0 if disassembling for 8086 or 286 */
+ dflag = 1;
+ aflag = 1;
+
+ if (prefixes & PREFIX_DATA)
+ dflag ^= 1;
+
+ if (prefixes & PREFIX_ADR)
+ {
+ aflag ^= 1;
+ oappend ("addr16 ");
+ }
+
+ if (*codep == 0x0f)
+ {
+ FETCH_DATA (info, codep + 2);
+ dp = &dis386_twobyte[*++codep];
+ }
+ else
+ dp = &dis386[*codep];
+ codep++;
+ FETCH_DATA (info, codep + 1);
+ mod = (*codep >> 6) & 3;
+ reg = (*codep >> 3) & 7;
+ rm = *codep & 7;
+
+ if (dp->name == NULL && dp->bytemode1 == FLOATCODE)
+ {
+ dofloat ();
+ }
+ else
+ {
+ if (dp->name == NULL)
+ dp = &grps[dp->bytemode1][reg];
+
+ putop (dp->name);
+
+ obufp = op1out;
+ op_ad = 2;
+ if (dp->op1)
+ (*dp->op1)(dp->bytemode1);
+
+ obufp = op2out;
+ op_ad = 1;
+ if (dp->op2)
+ (*dp->op2)(dp->bytemode2);
+
+ obufp = op3out;
+ op_ad = 0;
+ if (dp->op3)
+ (*dp->op3)(dp->bytemode3);
+ }
+
+ obufp = obuf + strlen (obuf);
+ for (i = strlen (obuf); i < 6; i++)
+ oappend (" ");
+ oappend (" ");
+ (*info->fprintf_func) (info->stream, "%s", obuf);
+
+ /* enter instruction is printed with operands in the
+ * same order as the intel book; everything else
+ * is printed in reverse order
+ */
+ if (enter_instruction)
+ {
+ first = op1out;
+ second = op2out;
+ third = op3out;
+ op_ad = op_index[0];
+ op_index[0] = op_index[2];
+ op_index[2] = op_ad;
+ }
+ else
+ {
+ first = op3out;
+ second = op2out;
+ third = op1out;
+ }
+ needcomma = 0;
+ if (*first)
+ {
+ if (op_index[0] != -1)
+ print_address (op_address[op_index[0]], info->stream);
+ else
+ (*info->fprintf_func) (info->stream, "%s", first);
+ needcomma = 1;
+ }
+ if (*second)
+ {
+ if (needcomma)
+ (*info->fprintf_func) (info->stream, ",");
+ if (op_index[1] != -1)
+ print_address (op_address[op_index[1]], info->stream);
+ else
+ (*info->fprintf_func) (info->stream, "%s", second);
+ needcomma = 1;
+ }
+ if (*third)
+ {
+ if (needcomma)
+ (*info->fprintf_func) (info->stream, ",");
+ if (op_index[2] != -1)
+ print_address (op_address[op_index[2]], info->stream);
+ else
+ (*info->fprintf_func) (info->stream, "%s", third);
+ }
+ return (codep - inbuf);
+}
+
+char *float_mem[] = {
+ /* d8 */
+ "fadds",
+ "fmuls",
+ "fcoms",
+ "fcomps",
+ "fsubs",
+ "fsubrs",
+ "fdivs",
+ "fdivrs",
+ /* d9 */
+ "flds",
+ "(bad)",
+ "fsts",
+ "fstps",
+ "fldenv",
+ "fldcw",
+ "fNstenv",
+ "fNstcw",
+ /* da */
+ "fiaddl",
+ "fimull",
+ "ficoml",
+ "ficompl",
+ "fisubl",
+ "fisubrl",
+ "fidivl",
+ "fidivrl",
+ /* db */
+ "fildl",
+ "(bad)",
+ "fistl",
+ "fistpl",
+ "(bad)",
+ "fldt",
+ "(bad)",
+ "fstpt",
+ /* dc */
+ "faddl",
+ "fmull",
+ "fcoml",
+ "fcompl",
+ "fsubl",
+ "fsubrl",
+ "fdivl",
+ "fdivrl",
+ /* dd */
+ "fldl",
+ "(bad)",
+ "fstl",
+ "fstpl",
+ "frstor",
+ "(bad)",
+ "fNsave",
+ "fNstsw",
+ /* de */
+ "fiadd",
+ "fimul",
+ "ficom",
+ "ficomp",
+ "fisub",
+ "fisubr",
+ "fidiv",
+ "fidivr",
+ /* df */
+ "fild",
+ "(bad)",
+ "fist",
+ "fistp",
+ "fbld",
+ "fildll",
+ "fbstp",
+ "fistpll",
+};
+
+#define ST OP_ST, 0
+#define STi OP_STi, 0
+int OP_ST(), OP_STi();
+
+#define FGRPd9_2 NULL, NULL, 0
+#define FGRPd9_4 NULL, NULL, 1
+#define FGRPd9_5 NULL, NULL, 2
+#define FGRPd9_6 NULL, NULL, 3
+#define FGRPd9_7 NULL, NULL, 4
+#define FGRPda_5 NULL, NULL, 5
+#define FGRPdb_4 NULL, NULL, 6
+#define FGRPde_3 NULL, NULL, 7
+#define FGRPdf_4 NULL, NULL, 8
+
+struct dis386 float_reg[][8] = {
+ /* d8 */
+ {
+ { "fadd", ST, STi },
+ { "fmul", ST, STi },
+ { "fcom", STi },
+ { "fcomp", STi },
+ { "fsub", ST, STi },
+ { "fsubr", ST, STi },
+ { "fdiv", ST, STi },
+ { "fdivr", ST, STi },
+ },
+ /* d9 */
+ {
+ { "fld", STi },
+ { "fxch", STi },
+ { FGRPd9_2 },
+ { "(bad)" },
+ { FGRPd9_4 },
+ { FGRPd9_5 },
+ { FGRPd9_6 },
+ { FGRPd9_7 },
+ },
+ /* da */
+ {
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { FGRPda_5 },
+ { "(bad)" },
+ { "(bad)" },
+ },
+ /* db */
+ {
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { FGRPdb_4 },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ },
+ /* dc */
+ {
+ { "fadd", STi, ST },
+ { "fmul", STi, ST },
+ { "(bad)" },
+ { "(bad)" },
+ { "fsub", STi, ST },
+ { "fsubr", STi, ST },
+ { "fdiv", STi, ST },
+ { "fdivr", STi, ST },
+ },
+ /* dd */
+ {
+ { "ffree", STi },
+ { "(bad)" },
+ { "fst", STi },
+ { "fstp", STi },
+ { "fucom", STi },
+ { "fucomp", STi },
+ { "(bad)" },
+ { "(bad)" },
+ },
+ /* de */
+ {
+ { "faddp", STi, ST },
+ { "fmulp", STi, ST },
+ { "(bad)" },
+ { FGRPde_3 },
+ { "fsubp", STi, ST },
+ { "fsubrp", STi, ST },
+ { "fdivp", STi, ST },
+ { "fdivrp", STi, ST },
+ },
+ /* df */
+ {
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { FGRPdf_4 },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ },
+};
+
+
+char *fgrps[][8] = {
+ /* d9_2 0 */
+ {
+ "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+ },
+
+ /* d9_4 1 */
+ {
+ "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)",
+ },
+
+ /* d9_5 2 */
+ {
+ "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)",
+ },
+
+ /* d9_6 3 */
+ {
+ "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp",
+ },
+
+ /* d9_7 4 */
+ {
+ "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos",
+ },
+
+ /* da_5 5 */
+ {
+ "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+ },
+
+ /* db_4 6 */
+ {
+ "feni(287 only)","fdisi(287 only)","fNclex","fNinit",
+ "fNsetpm(287 only)","(bad)","(bad)","(bad)",
+ },
+
+ /* de_3 7 */
+ {
+ "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+ },
+
+ /* df_4 8 */
+ {
+ "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+ },
+};
+
+static void
+dofloat ()
+{
+ struct dis386 *dp;
+ unsigned char floatop;
+
+ floatop = codep[-1];
+
+ if (mod != 3)
+ {
+ putop (float_mem[(floatop - 0xd8) * 8 + reg]);
+ obufp = op1out;
+ OP_E (v_mode);
+ return;
+ }
+ codep++;
+
+ dp = &float_reg[floatop - 0xd8][reg];
+ if (dp->name == NULL)
+ {
+ putop (fgrps[dp->bytemode1][rm]);
+ /* instruction fnstsw is only one with strange arg */
+ if (floatop == 0xdf
+ && FETCH_DATA (the_info, codep + 1)
+ && *codep == 0xe0)
+ strcpy (op1out, "%eax");
+ }
+ else
+ {
+ putop (dp->name);
+ obufp = op1out;
+ if (dp->op1)
+ (*dp->op1)(dp->bytemode1);
+ obufp = op2out;
+ if (dp->op2)
+ (*dp->op2)(dp->bytemode2);
+ }
+}
+
+/* ARGSUSED */
+int
+OP_ST (ignore)
+ int ignore;
+{
+ oappend ("%st");
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_STi (ignore)
+ int ignore;
+{
+ sprintf (scratchbuf, "%%st(%d)", rm);
+ oappend (scratchbuf);
+ return (0);
+}
+
+
+/* capital letters in template are macros */
+static void
+putop (template)
+ char *template;
+{
+ char *p;
+
+ for (p = template; *p; p++)
+ {
+ switch (*p)
+ {
+ default:
+ *obufp++ = *p;
+ break;
+ case 'C': /* For jcxz/jecxz */
+ if (aflag == 0)
+ *obufp++ = 'e';
+ break;
+ case 'N':
+ if ((prefixes & PREFIX_FWAIT) == 0)
+ *obufp++ = 'n';
+ break;
+ case 'S':
+ /* operand size flag */
+ if (dflag)
+ *obufp++ = 'l';
+ else
+ *obufp++ = 'w';
+ break;
+ }
+ }
+ *obufp = 0;
+}
+
+static void
+oappend (s)
+ char *s;
+{
+ strcpy (obufp, s);
+ obufp += strlen (s);
+ *obufp = 0;
+}
+
+static void
+append_prefix ()
+{
+ if (prefixes & PREFIX_CS)
+ oappend ("%cs:");
+ if (prefixes & PREFIX_DS)
+ oappend ("%ds:");
+ if (prefixes & PREFIX_SS)
+ oappend ("%ss:");
+ if (prefixes & PREFIX_ES)
+ oappend ("%es:");
+ if (prefixes & PREFIX_FS)
+ oappend ("%fs:");
+ if (prefixes & PREFIX_GS)
+ oappend ("%gs:");
+}
+
+int
+OP_indirE (bytemode)
+ int bytemode;
+{
+ oappend ("*");
+ OP_E (bytemode);
+ return (0);
+}
+
+int
+OP_E (bytemode)
+ int bytemode;
+{
+ int disp;
+ int havesib;
+ int base;
+ int index;
+ int scale;
+ int havebase;
+
+ /* skip mod/rm byte */
+ codep++;
+
+ havesib = 0;
+ havebase = 0;
+ disp = 0;
+
+ if (mod == 3)
+ {
+ switch (bytemode)
+ {
+ case b_mode:
+ oappend (names8[rm]);
+ break;
+ case w_mode:
+ oappend (names16[rm]);
+ break;
+ case v_mode:
+ if (dflag)
+ oappend (names32[rm]);
+ else
+ oappend (names16[rm]);
+ break;
+ default:
+ oappend ("<bad dis table>");
+ break;
+ }
+ return (0);
+ }
+
+ append_prefix ();
+ if (rm == 4)
+ {
+ havesib = 1;
+ havebase = 1;
+ FETCH_DATA (the_info, codep + 1);
+ scale = (*codep >> 6) & 3;
+ index = (*codep >> 3) & 7;
+ base = *codep & 7;
+ codep++;
+ }
+
+ switch (mod)
+ {
+ case 0:
+ switch (rm)
+ {
+ case 4:
+ /* implies havesib and havebase */
+ if (base == 5) {
+ havebase = 0;
+ disp = get32 ();
+ }
+ break;
+ case 5:
+ disp = get32 ();
+ break;
+ default:
+ havebase = 1;
+ base = rm;
+ break;
+ }
+ break;
+ case 1:
+ FETCH_DATA (the_info, codep + 1);
+ disp = *(char *)codep++;
+ if (rm != 4)
+ {
+ havebase = 1;
+ base = rm;
+ }
+ break;
+ case 2:
+ disp = get32 ();
+ if (rm != 4)
+ {
+ havebase = 1;
+ base = rm;
+ }
+ break;
+ }
+
+ if (mod != 0 || rm == 5 || (havesib && base == 5))
+ {
+ sprintf (scratchbuf, "0x%x", disp);
+ oappend (scratchbuf);
+ }
+
+ if (havebase || havesib)
+ {
+ oappend ("(");
+ if (havebase)
+ oappend (names32[base]);
+ if (havesib)
+ {
+ if (index != 4)
+ {
+ sprintf (scratchbuf, ",%s", names32[index]);
+ oappend (scratchbuf);
+ }
+ sprintf (scratchbuf, ",%d", 1 << scale);
+ oappend (scratchbuf);
+ }
+ oappend (")");
+ }
+ return (0);
+}
+
+int
+OP_G (bytemode)
+ int bytemode;
+{
+ switch (bytemode)
+ {
+ case b_mode:
+ oappend (names8[reg]);
+ break;
+ case w_mode:
+ oappend (names16[reg]);
+ break;
+ case d_mode:
+ oappend (names32[reg]);
+ break;
+ case v_mode:
+ if (dflag)
+ oappend (names32[reg]);
+ else
+ oappend (names16[reg]);
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ break;
+ }
+ return (0);
+}
+
+static int
+get32 ()
+{
+ int x = 0;
+
+ FETCH_DATA (the_info, codep + 4);
+ x = *codep++ & 0xff;
+ x |= (*codep++ & 0xff) << 8;
+ x |= (*codep++ & 0xff) << 16;
+ x |= (*codep++ & 0xff) << 24;
+ return (x);
+}
+
+static int
+get16 ()
+{
+ int x = 0;
+
+ FETCH_DATA (the_info, codep + 2);
+ x = *codep++ & 0xff;
+ x |= (*codep++ & 0xff) << 8;
+ return (x);
+}
+
+static void
+set_op (op)
+ int op;
+{
+ op_index[op_ad] = op_ad;
+ op_address[op_ad] = op;
+}
+
+int
+OP_REG (code)
+ int code;
+{
+ char *s;
+
+ switch (code)
+ {
+ case indir_dx_reg: s = "(%dx)"; break;
+ case ax_reg: case cx_reg: case dx_reg: case bx_reg:
+ case sp_reg: case bp_reg: case si_reg: case di_reg:
+ s = names16[code - ax_reg];
+ break;
+ case es_reg: case ss_reg: case cs_reg:
+ case ds_reg: case fs_reg: case gs_reg:
+ s = names_seg[code - es_reg];
+ break;
+ case al_reg: case ah_reg: case cl_reg: case ch_reg:
+ case dl_reg: case dh_reg: case bl_reg: case bh_reg:
+ s = names8[code - al_reg];
+ break;
+ case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg:
+ case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg:
+ if (dflag)
+ s = names32[code - eAX_reg];
+ else
+ s = names16[code - eAX_reg];
+ break;
+ default:
+ s = "<internal disassembler error>";
+ break;
+ }
+ oappend (s);
+ return (0);
+}
+
+int
+OP_I (bytemode)
+ int bytemode;
+{
+ int op;
+
+ switch (bytemode)
+ {
+ case b_mode:
+ FETCH_DATA (the_info, codep + 1);
+ op = *codep++ & 0xff;
+ break;
+ case v_mode:
+ if (dflag)
+ op = get32 ();
+ else
+ op = get16 ();
+ break;
+ case w_mode:
+ op = get16 ();
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ return (0);
+ }
+ sprintf (scratchbuf, "$0x%x", op);
+ oappend (scratchbuf);
+ return (0);
+}
+
+int
+OP_sI (bytemode)
+ int bytemode;
+{
+ int op;
+
+ switch (bytemode)
+ {
+ case b_mode:
+ FETCH_DATA (the_info, codep + 1);
+ op = *(char *)codep++;
+ break;
+ case v_mode:
+ if (dflag)
+ op = get32 ();
+ else
+ op = (short)get16();
+ break;
+ case w_mode:
+ op = (short)get16 ();
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ return (0);
+ }
+ sprintf (scratchbuf, "$0x%x", op);
+ oappend (scratchbuf);
+ return (0);
+}
+
+int
+OP_J (bytemode)
+ int bytemode;
+{
+ int disp;
+ int mask = -1;
+
+ switch (bytemode)
+ {
+ case b_mode:
+ FETCH_DATA (the_info, codep + 1);
+ disp = *(char *)codep++;
+ break;
+ case v_mode:
+ if (dflag)
+ disp = get32 ();
+ else
+ {
+ disp = (short)get16 ();
+ /* for some reason, a data16 prefix on a jump instruction
+ means that the pc is masked to 16 bits after the
+ displacement is added! */
+ mask = 0xffff;
+ }
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ return (0);
+ }
+ disp = (start_pc + codep - start_codep + disp) & mask;
+ set_op (disp);
+ sprintf (scratchbuf, "0x%x", disp);
+ oappend (scratchbuf);
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_SEG (dummy)
+ int dummy;
+{
+ static char *sreg[] = {
+ "%es","%cs","%ss","%ds","%fs","%gs","%?","%?",
+ };
+
+ oappend (sreg[reg]);
+ return (0);
+}
+
+int
+OP_DIR (size)
+ int size;
+{
+ int seg, offset;
+
+ switch (size)
+ {
+ case lptr:
+ if (aflag)
+ {
+ offset = get32 ();
+ seg = get16 ();
+ }
+ else
+ {
+ offset = get16 ();
+ seg = get16 ();
+ }
+ sprintf (scratchbuf, "0x%x,0x%x", seg, offset);
+ oappend (scratchbuf);
+ break;
+ case v_mode:
+ if (aflag)
+ offset = get32 ();
+ else
+ offset = (short)get16 ();
+
+ offset = start_pc + codep - start_codep + offset;
+ set_op (offset);
+ sprintf (scratchbuf, "0x%x", offset);
+ oappend (scratchbuf);
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ break;
+ }
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_OFF (bytemode)
+ int bytemode;
+{
+ int off;
+
+ if (aflag)
+ off = get32 ();
+ else
+ off = get16 ();
+
+ sprintf (scratchbuf, "0x%x", off);
+ oappend (scratchbuf);
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_ESDI (dummy)
+ int dummy;
+{
+ oappend ("%es:(");
+ oappend (aflag ? "%edi" : "%di");
+ oappend (")");
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_DSSI (dummy)
+ int dummy;
+{
+ oappend ("%ds:(");
+ oappend (aflag ? "%esi" : "%si");
+ oappend (")");
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_ONE (dummy)
+ int dummy;
+{
+ oappend ("1");
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_C (dummy)
+ int dummy;
+{
+ codep++; /* skip mod/rm */
+ sprintf (scratchbuf, "%%cr%d", reg);
+ oappend (scratchbuf);
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_D (dummy)
+ int dummy;
+{
+ codep++; /* skip mod/rm */
+ sprintf (scratchbuf, "%%db%d", reg);
+ oappend (scratchbuf);
+ return (0);
+}
+
+/* ARGSUSED */
+int
+OP_T (dummy)
+ int dummy;
+{
+ codep++; /* skip mod/rm */
+ sprintf (scratchbuf, "%%tr%d", reg);
+ oappend (scratchbuf);
+ return (0);
+}
+
+int
+OP_rm (bytemode)
+ int bytemode;
+{
+ switch (bytemode)
+ {
+ case d_mode:
+ oappend (names32[rm]);
+ break;
+ case w_mode:
+ oappend (names16[rm]);
+ break;
+ }
+ return (0);
+}
--- /dev/null
+/* Print Motorola 68k instructions.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the 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 of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "dis-asm.h"
+#include "ieee-float.h"
+
+extern CONST struct ext_format ext_format_68881;
+
+/* Opcode/m68k.h is a massive table. As a kludge, break it up into
+ two pieces. This makes nonportable C -- FIXME -- it assumes that
+ two data items declared near each other will be contiguous in
+ memory. This kludge can be removed, FIXME, when GCC is fixed to not
+ be a hog about initializers. */
+
+#ifdef __GNUC__
+#define BREAK_UP_BIG_DECL }; \
+ struct m68k_opcode m68k_opcodes_2[] = {
+#define AND_OTHER_PART sizeof (m68k_opcodes_2)
+#endif
+
+#include "opcode/m68k.h"
+
+
+/* Local function prototypes */
+
+static int
+fetch_arg PARAMS ((unsigned char *, int, int));
+
+static void
+print_base PARAMS ((int, int, disassemble_info*));
+
+static unsigned char *
+print_indexed PARAMS ((int, unsigned char *, bfd_vma, disassemble_info *));
+
+static unsigned char *
+print_insn_arg PARAMS ((char *, unsigned char *, unsigned char *, bfd_vma,
+ disassemble_info *));
+
+/* 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
+
+CONST char * CONST fpcr_names[] = {
+ "", "fpiar", "fpsr", "fpiar/fpsr", "fpcr",
+ "fpiar/fpcr", "fpsr/fpcr", "fpiar/fpsr/fpcr"};
+
+static char *reg_names[] = {
+ "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "a0",
+ "a1", "a2", "a3", "a4", "a5", "fp", "sp", "ps", "pc"};
+
+/* Define accessors for 68K's 1, 2, and 4-byte signed quantities.
+ The _SHIFT values move the quantity to the high order end of an
+ `int' value, so it will sign-extend. Probably a few more casts
+ are needed to make it compile without warnings on finicky systems. */
+#define BITS_PER_BYTE 8
+#define WORD_SHIFT (BITS_PER_BYTE * ((sizeof (int)) - 2))
+#define LONG_SHIFT (BITS_PER_BYTE * ((sizeof (int)) - 4))
+
+#define NEXTBYTE(p) (p += 2, FETCH_DATA (info, p), COERCE_SIGNED_CHAR(p[-1]))
+
+#define NEXTWORD(p) \
+ (p += 2, FETCH_DATA (info, p), \
+ (((int)((p[-2] << 8) + p[-1])) << WORD_SHIFT) >> WORD_SHIFT)
+
+#define NEXTLONG(p) \
+ (p += 4, FETCH_DATA (info, p), \
+ (((int)((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])) \
+ << LONG_SHIFT) >> LONG_SHIFT)
+
+/* NEXTSINGLE and NEXTDOUBLE handle alignment problems, but not
+ * byte-swapping or other float format differences. FIXME! */
+
+union number {
+ double d;
+ float f;
+ char c[10];
+};
+
+#define NEXTSINGLE(val, p) \
+ { int i; union number u;\
+ FETCH_DATA (info, p + sizeof (float));\
+ for (i = 0; i < sizeof(float); i++) u.c[i] = *p++; \
+ val = u.f; }
+
+#define NEXTDOUBLE(val, p) \
+ { int i; union number u;\
+ FETCH_DATA (info, p + sizeof (double));\
+ for (i = 0; i < sizeof(double); i++) u.c[i] = *p++; \
+ val = u.d; }
+
+/* Need a function to convert from extended to double precision... */
+#define NEXTEXTEND(p) \
+ (p += 12, FETCH_DATA (info, p), 0.0)
+
+/* 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)
+
+\f
+/* 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 int
+fetch_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);
+ }
+ else
+ priv->max_fetched = addr;
+ return 1;
+}
+\f
+static void
+m68k_opcode_error(info, code, place)
+ struct disassemble_info *info;
+ int code, place;
+{
+ (*info->fprintf_func)(info->stream,
+ "<internal error in opcode table: \"%c%c\">",
+ code, place);
+}
+
+/* Print the m68k instruction at address MEMADDR in debugged memory,
+ on STREAM. Returns length of the instruction, in bytes. */
+
+int
+print_insn_m68k (memaddr, info)
+ bfd_vma memaddr;
+ disassemble_info *info;
+{
+ register int i;
+ register unsigned char *p;
+ register char *d;
+ register unsigned long bestmask;
+ int best;
+ struct private priv;
+ bfd_byte *buffer = priv.the_buffer;
+
+ info->private_data = (PTR) &priv;
+ priv.max_fetched = priv.the_buffer;
+ priv.insn_start = memaddr;
+ if (setjmp (priv.bailout) != 0)
+ /* Error return. */
+ return -1;
+
+ bestmask = 0;
+ best = -1;
+ FETCH_DATA (info, buffer + 2);
+ for (i = 0; i < numopcodes; i++)
+ {
+ register unsigned long opcode = m68k_opcodes[i].opcode;
+ register unsigned long match = m68k_opcodes[i].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)))
+ ))
+ {
+ /* 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 = m68k_opcodes[i].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 = m68k_opcodes[i].args; *d; d += 2)
+ if (d[1] == 't')
+ break;
+
+ if (*d == 0 && match > bestmask)
+ {
+ best = i;
+ bestmask = match;
+ }
+ }
+ }
+
+ /* Handle undefined instructions. */
+ if (best < 0)
+ {
+ (*info->fprintf_func) (info->stream, "0%o",
+ (buffer[0] << 8) + buffer[1]);
+ return 2;
+ }
+
+ (*info->fprintf_func) (info->stream, "%s", m68k_opcodes[best].name);
+
+ /* Point at first word of argument data,
+ and at descriptor for first argument. */
+ p = buffer + 2;
+
+ /* Why do this this way? -MelloN */
+ for (d = m68k_opcodes[best].args; *d; d += 2)
+ {
+ 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[1] >= '1' && d[1] <= '3' && p - buffer < 4)
+ p = buffer + 4;
+ if (d[1] >= '4' && d[1] <= '6' && p - buffer < 6)
+ p = buffer + 6;
+ if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4)
+ p = buffer + 4;
+ }
+
+ FETCH_DATA (info, p);
+
+ d = m68k_opcodes[best].args;
+
+ if (*d)
+ (*info->fprintf_func) (info->stream, " ");
+
+ while (*d)
+ {
+ p = print_insn_arg (d, buffer, p, memaddr + p - buffer, info);
+ d += 2;
+ if (*d && *(d - 2) != 'I' && *d != 'k')
+ (*info->fprintf_func) (info->stream, ",");
+ }
+ return p - buffer;
+}
+
+static unsigned char *
+print_insn_arg (d, buffer, p, addr, info)
+ char *d;
+ unsigned char *buffer;
+ register unsigned char *p;
+ bfd_vma addr; /* PC for this arg to be relative to */
+ disassemble_info *info;
+{
+ register int val = 0;
+ register int place = d[1];
+ int regno;
+ register CONST char *regname;
+ register unsigned char *p1;
+ double flval;
+ int flt_p;
+
+ switch (*d)
+ {
+ case 'c': /* cache identifier */
+ {
+ static char *cacheFieldName[] = { "NOP", "dc", "ic", "bc" };
+ val = fetch_arg (buffer, place, 2, info);
+ (*info->fprintf_func) (info->stream, cacheFieldName[val]);
+ break;
+ }
+
+ case 'a': /* address register indirect only. Cf. case '+'. */
+ {
+ (*info->fprintf_func)
+ (info->stream,
+ "%s@",
+ reg_names [fetch_arg (buffer, place, 3, info) + 8]);
+ break;
+ }
+
+ case '_': /* 32-bit absolute address for move16. */
+ {
+ val = NEXTLONG (p);
+ (*info->fprintf_func) (info->stream, "@#");
+ print_address (val, info->stream);
+ break;
+ }
+
+ case 'C':
+ (*info->fprintf_func) (info->stream, "ccr");
+ break;
+
+ case 'S':
+ (*info->fprintf_func) (info->stream, "sr");
+ break;
+
+ case 'U':
+ (*info->fprintf_func) (info->stream, "usp");
+ break;
+
+ case 'J':
+ {
+ static struct { char *name; int value; } names[]
+ = {{"sfc", 0x000}, {"dfc", 0x001}, {"cacr", 0x002},
+ {"tc", 0x003}, {"itt0",0x004}, {"itt1", 0x005},
+ {"dtt0",0x006}, {"dtt1",0x007},
+ {"usp", 0x800}, {"vbr", 0x801}, {"caar", 0x802},
+ {"msp", 0x803}, {"isp", 0x804}, {"mmusr",0x805},
+ {"urp", 0x806}, {"srp", 0x807}};
+
+ val = fetch_arg (buffer, place, 12, info);
+ for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--)
+ if (names[regno].value == val)
+ {
+ (*info->fprintf_func) (info->stream, names[regno].name);
+ break;
+ }
+ if (regno < 0)
+ (*info->fprintf_func) (info->stream, "%d", val);
+ }
+ break;
+
+ case 'Q':
+ val = fetch_arg (buffer, place, 3, info);
+ /* 0 means 8, except for the bkpt instruction... */
+ if (val == 0 && d[1] != 's')
+ val = 8;
+ (*info->fprintf_func) (info->stream, "#%d", val);
+ break;
+
+ case 'M':
+ val = fetch_arg (buffer, place, 8, info);
+ if (val & 0x80)
+ val = val - 0x100;
+ (*info->fprintf_func) (info->stream, "#%d", val);
+ break;
+
+ case 'T':
+ val = fetch_arg (buffer, place, 4, info);
+ (*info->fprintf_func) (info->stream, "#%d", val);
+ break;
+
+ case 'D':
+ (*info->fprintf_func) (info->stream, "%s",
+ reg_names[fetch_arg (buffer, place, 3, info)]);
+ break;
+
+ case 'A':
+ (*info->fprintf_func)
+ (info->stream, "%s",
+ reg_names[fetch_arg (buffer, place, 3, info) + 010]);
+ break;
+
+ case 'R':
+ (*info->fprintf_func)
+ (info->stream, "%s",
+ reg_names[fetch_arg (buffer, place, 4, info)]);
+ break;
+
+ case 'r':
+ (*info->fprintf_func)
+ (info->stream, "%s@",
+ reg_names[fetch_arg (buffer, place, 4, info)]);
+ break;
+
+ case 'F':
+ (*info->fprintf_func)
+ (info->stream, "fp%d",
+ fetch_arg (buffer, place, 3, info));
+ break;
+
+ case 'O':
+ val = fetch_arg (buffer, place, 6, info);
+ if (val & 0x20)
+ (*info->fprintf_func) (info->stream, "%s", reg_names [val & 7]);
+ else
+ (*info->fprintf_func) (info->stream, "%d", val);
+ break;
+
+ case '+':
+ (*info->fprintf_func)
+ (info->stream, "%s@+",
+ reg_names[fetch_arg (buffer, place, 3, info) + 8]);
+ break;
+
+ case '-':
+ (*info->fprintf_func)
+ (info->stream, "%s@-",
+ reg_names[fetch_arg (buffer, place, 3, info) + 8]);
+ break;
+
+ case 'k':
+ if (place == 'k')
+ (*info->fprintf_func)
+ (info->stream, "{%s}",
+ reg_names[fetch_arg (buffer, place, 3, info)]);
+ else if (place == 'C')
+ {
+ val = fetch_arg (buffer, place, 7, info);
+ if ( val > 63 ) /* This is a signed constant. */
+ val -= 128;
+ (*info->fprintf_func) (info->stream, "{#%d}", val);
+ }
+ else
+ m68k_opcode_error (info, *d, place);
+ break;
+
+ case '#':
+ case '^':
+ p1 = buffer + (*d == '#' ? 2 : 4);
+ if (place == 's')
+ val = fetch_arg (buffer, place, 4, info);
+ else if (place == 'C')
+ val = fetch_arg (buffer, place, 7, info);
+ else if (place == '8')
+ val = fetch_arg (buffer, place, 3, info);
+ else if (place == '3')
+ val = fetch_arg (buffer, place, 8, info);
+ else if (place == 'b')
+ val = NEXTBYTE (p1);
+ else if (place == 'w')
+ val = NEXTWORD (p1);
+ else if (place == 'l')
+ val = NEXTLONG (p1);
+ else
+ m68k_opcode_error (info, *d, place);
+ (*info->fprintf_func) (info->stream, "#%d", val);
+ break;
+
+ case 'B':
+ if (place == 'b')
+ val = NEXTBYTE (p);
+ else if (place == 'B')
+ val = COERCE_SIGNED_CHAR(buffer[1]);
+ else if (place == 'w' || place == 'W')
+ val = NEXTWORD (p);
+ else if (place == 'l' || place == 'L')
+ val = NEXTLONG (p);
+ else if (place == 'g')
+ {
+ val = NEXTBYTE (buffer);
+ if (val == 0)
+ val = NEXTWORD (p);
+ else if (val == -1)
+ val = NEXTLONG (p);
+ }
+ else if (place == 'c')
+ {
+ if (buffer[1] & 0x40) /* If bit six is one, long offset */
+ val = NEXTLONG (p);
+ else
+ val = NEXTWORD (p);
+ }
+ else
+ m68k_opcode_error (info, *d, place);
+
+ print_address (addr + val, info->stream);
+ break;
+
+ case 'd':
+ val = NEXTWORD (p);
+ (*info->fprintf_func)
+ (info->stream, "%s@(%d)",
+ reg_names[fetch_arg (buffer, place, 3, info)], val);
+ break;
+
+ case 's':
+ (*info->fprintf_func) (info->stream, "%s",
+ fpcr_names[fetch_arg (buffer, place, 3, info)]);
+ break;
+
+ case 'I':
+ /* Get coprocessor ID... */
+ val = fetch_arg (buffer, 'd', 3, info);
+
+ if (val != 1) /* Unusual coprocessor ID? */
+ (*info->fprintf_func) (info->stream, "(cpid=%d) ", val);
+ if (place == 'i')
+ p += 2; /* Skip coprocessor extended operands */
+ break;
+
+ case '*':
+ case '~':
+ case '%':
+ case ';':
+ case '@':
+ case '!':
+ case '$':
+ case '?':
+ case '/':
+ case '&':
+ case '`':
+
+ if (place == 'd')
+ {
+ val = fetch_arg (buffer, 'x', 6, info);
+ val = ((val & 7) << 3) + ((val >> 3) & 7);
+ }
+ else
+ val = fetch_arg (buffer, 's', 6, info);
+
+ /* Get register number assuming address register. */
+ regno = (val & 7) + 8;
+ regname = reg_names[regno];
+ switch (val >> 3)
+ {
+ case 0:
+ (*info->fprintf_func) (info->stream, "%s", reg_names[val]);
+ break;
+
+ case 1:
+ (*info->fprintf_func) (info->stream, "%s", regname);
+ break;
+
+ case 2:
+ (*info->fprintf_func) (info->stream, "%s@", regname);
+ break;
+
+ case 3:
+ (*info->fprintf_func) (info->stream, "%s@+", regname);
+ break;
+
+ case 4:
+ (*info->fprintf_func) (info->stream, "%s@-", regname);
+ break;
+
+ case 5:
+ val = NEXTWORD (p);
+ (*info->fprintf_func) (info->stream, "%s@(%d)", regname, val);
+ break;
+
+ case 6:
+ p = print_indexed (regno, p, addr, info);
+ break;
+
+ case 7:
+ switch (val & 7)
+ {
+ case 0:
+ val = NEXTWORD (p);
+ (*info->fprintf_func) (info->stream, "@#");
+ print_address (val, info->stream);
+ break;
+
+ case 1:
+ val = NEXTLONG (p);
+ (*info->fprintf_func) (info->stream, "@#");
+ print_address (val, info->stream);
+ break;
+
+ case 2:
+ val = NEXTWORD (p);
+ print_address (addr + val, info->stream);
+ break;
+
+ case 3:
+ p = print_indexed (-1, p, addr, info);
+ break;
+
+ case 4:
+ flt_p = 1; /* Assume it's a float... */
+ switch( place )
+ {
+ case 'b':
+ val = NEXTBYTE (p);
+ flt_p = 0;
+ break;
+
+ case 'w':
+ val = NEXTWORD (p);
+ flt_p = 0;
+ break;
+
+ case 'l':
+ val = NEXTLONG (p);
+ flt_p = 0;
+ break;
+
+ case 'f':
+ NEXTSINGLE(flval, p);
+ break;
+
+ case 'F':
+ NEXTDOUBLE(flval, p);
+ break;
+
+ case 'x':
+ ieee_extended_to_double (&ext_format_68881,
+ (char *)p, &flval);
+ p += 12;
+ break;
+
+ case 'p':
+ flval = NEXTPACKED(p);
+ break;
+
+ default:
+ m68k_opcode_error (info, *d, place);
+ }
+ if ( flt_p ) /* Print a float? */
+ (*info->fprintf_func) (info->stream, "#%g", flval);
+ else
+ (*info->fprintf_func) (info->stream, "#%d", val);
+ break;
+
+ default:
+ (*info->fprintf_func) (info->stream,
+ "<invalid address mode 0%o>",
+ (unsigned) val);
+ }
+ }
+ break;
+
+ case 'L':
+ case 'l':
+ if (place == 'w')
+ {
+ char doneany;
+ p1 = buffer + 2;
+ val = NEXTWORD (p1);
+ /* Move the pointer ahead if this point is farther ahead
+ than the last. */
+ p = p1 > p ? p1 : p;
+ if (val == 0)
+ {
+ (*info->fprintf_func) (info->stream, "#0");
+ break;
+ }
+ if (*d == 'l')
+ {
+ register int newval = 0;
+ for (regno = 0; regno < 16; ++regno)
+ if (val & (0x8000 >> regno))
+ newval |= 1 << regno;
+ val = newval;
+ }
+ val &= 0xffff;
+ doneany = 0;
+ for (regno = 0; regno < 16; ++regno)
+ if (val & (1 << regno))
+ {
+ int first_regno;
+ if (doneany)
+ (*info->fprintf_func) (info->stream, "/");
+ doneany = 1;
+ (*info->fprintf_func) (info->stream, "%s", reg_names[regno]);
+ first_regno = regno;
+ while (val & (1 << (regno + 1)))
+ ++regno;
+ if (regno > first_regno)
+ (*info->fprintf_func) (info->stream, "-%s",
+ reg_names[regno]);
+ }
+ }
+ else if (place == '3')
+ {
+ /* `fmovem' insn. */
+ char doneany;
+ val = fetch_arg (buffer, place, 8, info);
+ if (val == 0)
+ {
+ (*info->fprintf_func) (info->stream, "#0");
+ break;
+ }
+ if (*d == 'l')
+ {
+ register int newval = 0;
+ for (regno = 0; regno < 8; ++regno)
+ if (val & (0x80 >> regno))
+ newval |= 1 << regno;
+ val = newval;
+ }
+ val &= 0xff;
+ doneany = 0;
+ for (regno = 0; regno < 8; ++regno)
+ if (val & (1 << regno))
+ {
+ int first_regno;
+ if (doneany)
+ (*info->fprintf_func) (info->stream, "/");
+ doneany = 1;
+ (*info->fprintf_func) (info->stream, "fp%d", regno);
+ first_regno = regno;
+ while (val & (1 << (regno + 1)))
+ ++regno;
+ if (regno > first_regno)
+ (*info->fprintf_func) (info->stream, "-fp%d", regno);
+ }
+ }
+ else
+ goto de_fault;
+ break;
+
+ default: de_fault:
+ m68k_opcode_error (info, *d, ' ');
+ }
+
+ return (unsigned char *) p;
+}
+
+/* Fetch BITS bits from a position in the instruction specified by CODE.
+ CODE is a "place to put an argument", or 'x' for a destination
+ that is a general address (mode and register).
+ BUFFER contains the instruction. */
+
+static int
+fetch_arg (buffer, code, bits, info)
+ unsigned char *buffer;
+ int code;
+ int bits;
+ disassemble_info *info;
+{
+ register int val = 0;
+ switch (code)
+ {
+ case 's':
+ val = buffer[1];
+ break;
+
+ case 'd': /* Destination, for register or quick. */
+ val = (buffer[0] << 8) + buffer[1];
+ val >>= 9;
+ break;
+
+ case 'x': /* Destination, for general arg */
+ val = (buffer[0] << 8) + buffer[1];
+ val >>= 6;
+ break;
+
+ case 'k':
+ FETCH_DATA (info, buffer + 3);
+ val = (buffer[3] >> 4);
+ break;
+
+ case 'C':
+ FETCH_DATA (info, buffer + 3);
+ val = buffer[3];
+ break;
+
+ case '1':
+ FETCH_DATA (info, buffer + 3);
+ val = (buffer[2] << 8) + buffer[3];
+ val >>= 12;
+ break;
+
+ case '2':
+ FETCH_DATA (info, buffer + 3);
+ val = (buffer[2] << 8) + buffer[3];
+ val >>= 6;
+ break;
+
+ case '3':
+ case 'j':
+ FETCH_DATA (info, buffer + 3);
+ val = (buffer[2] << 8) + buffer[3];
+ break;
+
+ case '4':
+ FETCH_DATA (info, buffer + 5);
+ val = (buffer[4] << 8) + buffer[5];
+ val >>= 12;
+ break;
+
+ case '5':
+ FETCH_DATA (info, buffer + 5);
+ val = (buffer[4] << 8) + buffer[5];
+ val >>= 6;
+ break;
+
+ case '6':
+ FETCH_DATA (info, buffer + 5);
+ val = (buffer[4] << 8) + buffer[5];
+ break;
+
+ case '7':
+ FETCH_DATA (info, buffer + 3);
+ val = (buffer[2] << 8) + buffer[3];
+ val >>= 7;
+ break;
+
+ case '8':
+ FETCH_DATA (info, buffer + 3);
+ val = (buffer[2] << 8) + buffer[3];
+ val >>= 10;
+ break;
+
+ case '9':
+ FETCH_DATA (info, buffer + 3);
+ val = (buffer[2] << 8) + buffer[3];
+ val >>= 5;
+ break;
+
+ case 'e':
+ val = (buffer[1] >> 6);
+ break;
+
+ default:
+ abort ();
+ }
+
+ switch (bits)
+ {
+ case 2:
+ return val & 3;
+ case 3:
+ return val & 7;
+ case 4:
+ return val & 017;
+ case 5:
+ return val & 037;
+ case 6:
+ return val & 077;
+ case 7:
+ return val & 0177;
+ case 8:
+ return val & 0377;
+ case 12:
+ return val & 07777;
+ default:
+ abort ();
+ }
+}
+
+/* Print an indexed argument. The base register is BASEREG (-1 for pc).
+ P points to extension word, in buffer.
+ ADDR is the nominal core address of that extension word. */
+
+static unsigned char *
+print_indexed (basereg, p, addr, info)
+ int basereg;
+ unsigned char *p;
+ bfd_vma addr;
+ disassemble_info *info;
+{
+ register int word;
+ static char *scales[] = {"", "*2", "*4", "*8"};
+ register int base_disp;
+ register int outer_disp;
+ char buf[40];
+
+ word = NEXTWORD (p);
+
+ /* Generate the text for the index register.
+ Where this will be output is not yet determined. */
+ sprintf (buf, "[%s.%c%s]",
+ reg_names[(word >> 12) & 0xf],
+ (word & 0x800) ? 'l' : 'w',
+ scales[(word >> 9) & 3]);
+
+ /* Handle the 68000 style of indexing. */
+
+ if ((word & 0x100) == 0)
+ {
+ print_base (basereg,
+ ((word & 0x80) ? word | 0xff00 : word & 0xff)
+ + ((basereg == -1) ? addr : 0),
+ info);
+ (*info->fprintf_func) (info->stream, "%s", buf);
+ return p;
+ }
+
+ /* Handle the generalized kind. */
+ /* First, compute the displacement to add to the base register. */
+
+ if (word & 0200)
+ basereg = -2;
+ if (word & 0100)
+ buf[0] = 0;
+ base_disp = 0;
+ switch ((word >> 4) & 3)
+ {
+ case 2:
+ base_disp = NEXTWORD (p);
+ break;
+ case 3:
+ base_disp = NEXTLONG (p);
+ }
+ if (basereg == -1)
+ base_disp += addr;
+
+ /* Handle single-level case (not indirect) */
+
+ if ((word & 7) == 0)
+ {
+ print_base (basereg, base_disp, info);
+ (*info->fprintf_func) (info->stream, "%s", buf);
+ return p;
+ }
+
+ /* Two level. Compute displacement to add after indirection. */
+
+ outer_disp = 0;
+ switch (word & 3)
+ {
+ case 2:
+ outer_disp = NEXTWORD (p);
+ break;
+ case 3:
+ outer_disp = NEXTLONG (p);
+ }
+
+ (*info->fprintf_func) (info->stream, "%d(", outer_disp);
+ print_base (basereg, base_disp, info);
+
+ /* If postindexed, print the closeparen before the index. */
+ if (word & 4)
+ (*info->fprintf_func) (info->stream, ")%s", buf);
+ /* If preindexed, print the closeparen after the index. */
+ else
+ (*info->fprintf_func) (info->stream, "%s)", buf);
+
+ return p;
+}
+
+/* Print a base register REGNO and displacement DISP, on INFO->STREAM.
+ REGNO = -1 for pc, -2 for none (suppressed). */
+
+static void
+print_base (regno, disp, info)
+ int regno;
+ int disp;
+ disassemble_info *info;
+{
+ if (regno == -2)
+ (*info->fprintf_func) (info->stream, "%d", disp);
+ else if (regno == -1)
+ (*info->fprintf_func) (info->stream, "0x%x", (unsigned) disp);
+ else
+ (*info->fprintf_func) (info->stream, "%d(%s)", disp, reg_names[regno]);
+}
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <ansidecl.h>
#include "sysdep.h"
-#include <stdio.h>
-#include "bfd.h"
+#include "dis-asm.h"
#include "opcode/mips.h"
/* FIXME: we need direct access to the swapping functions. */
static CONST char * CONST reg_names[] = REGISTER_NAMES;
\f
/* subroutine */
-static unsigned char *
-print_insn_arg (d, l, stream, pc)
+static void
+print_insn_arg (d, l, pc, info)
char *d;
- register unsigned long int *l;
- FILE *stream;
+ register unsigned long int l;
bfd_vma pc;
+ struct disassemble_info *info;
{
switch (*d)
{
case ',':
case '(':
case ')':
- fputc (*d, stream);
+ (*info->fprintf_func) (info->stream, "%c", *d);
break;
case 's':
- fprintf (stream, "$%s", reg_names[((struct op_i_fmt *) l)->rs]);
+ (*info->fprintf_func) (info->stream, "$%s",
+ reg_names[(l >> OP_SH_RS) & OP_MASK_RS]);
break;
case 't':
- fprintf (stream, "$%s", reg_names[((struct op_i_fmt *) l)->rt]);
+ (*info->fprintf_func) (info->stream, "$%s",
+ reg_names[(l >> OP_SH_RT) & OP_MASK_RT]);
break;
case 'i':
- fprintf (stream, "%d", ((struct op_i_fmt *) l)->immediate);
+ (*info->fprintf_func) (info->stream, "%d",
+ (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE);
break;
case 'j': /* same as i, but sign-extended */
- fprintf (stream, "%d", ((struct op_b_fmt *) l)->delta);
+ (*info->fprintf_func) (info->stream, "%d",
+ (l >> OP_SH_DELTA) & OP_MASK_DELTA);
break;
case 'a':
- print_address ((pc & 0xF0000000) | (((struct op_j_fmt *)l)->target << 2),
- stream);
+ print_address (((pc & 0xF0000000)
+ | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2)),
+ info->stream);
break;
case 'b':
- print_address ((((struct op_b_fmt *) l)->delta << 2) + pc + 4, stream);
+ print_address ((((l >> OP_SH_DELTA) & OP_MASK_DELTA) << 2) + pc + 4,
+ info->stream);
break;
case 'd':
- fprintf (stream, "$%s", reg_names[((struct op_r_fmt *) l)->rd]);
+ (*info->fprintf_func) (info->stream, "$%s",
+ reg_names[(l >> OP_SH_RD) & OP_MASK_RD]);
break;
case 'h':
- fprintf (stream, "0x%x", ((struct op_r_fmt *) l)->shamt);
+ (*info->fprintf_func) (info->stream, "0x%x",
+ (l >> OP_SH_SHAMT) & OP_MASK_SHAMT);
break;
case 'B':
- fprintf (stream, "0x%x", ((struct op_brk_fmt *) l)->code);
+ (*info->fprintf_func) (info->stream, "0x%x",
+ (l >> OP_SH_CODE) & OP_MASK_CODE);
break;
case 'S':
- fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->fs);
+ (*info->fprintf_func) (info->stream, "$f%d",
+ (l >> OP_SH_FS) & OP_MASK_FS);
break;
case 'T':
- fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->ft);
+ (*info->fprintf_func) (info->stream, "$f%d",
+ (l >> OP_SH_FT) & OP_MASK_FT);
break;
case 'D':
- fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->fd);
+ (*info->fprintf_func) (info->stream, "$f%d",
+ (l >> OP_SH_FD) & OP_MASK_FD);
break;
default:
- fprintf (stream, "# internal error, undefined modifier(%c)", *d);
+ (*info->fprintf_func) (info->stream,
+ "# internal error, undefined modifier(%c)", *d);
break;
}
}
\f
/* Print the mips instruction at address MEMADDR in debugged memory,
- on STREAM. Returns length of the instruction, in bytes, which is
+ on using INFO. Returns length of the instruction, in bytes, which is
always 4. BIGENDIAN must be 1 if this is big-endian code, 0 if
this is little-endian code. */
int
-print_insn_mips (memaddr, buffer, stream, bigendian)
+_print_insn_mips (memaddr, word, info)
bfd_vma memaddr;
- bfd_byte *buffer;
- FILE *stream;
- int bigendian;
+ struct disassemble_info *info;
+ unsigned long int word;
{
register int i;
register char *d;
- unsigned long int l;
-
- /* FIXME: can't we export these functions from bfd? */
- if (bigendian)
- l = _do_getb32 (buffer);
- else
- l = _do_getl32 (buffer);
for (i = 0; i < NOPCODES; i++)
{
register unsigned int opcode = mips_opcodes[i].opcode;
register unsigned int match = mips_opcodes[i].match;
- if ((l & match) == opcode)
+ if ((word & match) == opcode)
break;
}
/* Handle undefined instructions. */
if (i == NOPCODES)
{
- fprintf (stream, "0x%x",l);
+ (*info->fprintf_func) (info->stream, "0x%x", word);
return 4;
}
- fprintf (stream, "%s", mips_opcodes[i].name);
+ (*info->fprintf_func) (info->stream, "%s", mips_opcodes[i].name);
if (!(d = mips_opcodes[i].args))
return 4;
- fputc (' ', stream);
+ (*info->fprintf_func) (info->stream, " ");
while (*d)
- print_insn_arg (d++, &l, stream, memaddr);
+ print_insn_arg (d++, word, memaddr, info);
return 4;
}
+
+int
+print_insn_big_mips (memaddr, info)
+ bfd_vma memaddr;
+ struct disassemble_info *info;
+{
+ bfd_byte buffer[4];
+ int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
+ if (status == 0)
+ return _print_insn_mips (memaddr, _do_getb32 (buffer), info);
+ else
+ {
+ (*info->memory_error_func) (status, memaddr, info);
+ return -1;
+ }
+}
+
+int
+print_insn_little_mips (memaddr, info)
+ bfd_vma memaddr;
+ struct disassemble_info *info;
+{
+ bfd_byte buffer[4];
+ int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
+ if (status == 0)
+ return _print_insn_mips (memaddr, _do_getl32 (buffer), info);
+ else
+ {
+ (*info->memory_error_func) (status, memaddr, info);
+ return -1;
+ }
+}
-#include <stdio.h>
+/*
+This file is part of GNU Binutils.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the 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 of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <ansidecl.h>
+#include "sysdep.h"
+#include "dis-asm.h"
+
#define DEFINE_TABLE
#include "z8k-opc.h"
-static void fetch_data();
-static void fetch_instr();
-static unsigned long get_val();
-static int is_segmented();
-static int lookup_instr();
-static void output_instr();
-static void unpack_instr();
-static void unparse_instr();
-
-typedef struct {
- unsigned char instr_buf[24];
- unsigned long bytes_fetched;
- unsigned long tabl_index;
- char instr_asmsrc[80];
- unsigned long arg_reg[0x0f];
- unsigned long immediate;
- unsigned long displacement;
- unsigned long address;
- unsigned long cond_code;
- unsigned long ctrl_code;
- unsigned long flags;
- unsigned long interrupts;
-} instr_data_s;
-
-
-static char *codes[16] =
+\f
+#include <setjmp.h>
+
+\f
+typedef struct
+{
+ /* These are all indexed by nibble number (i.e only every other entry
+ of bytes is used, and every 4th entry of words). */
+ unsigned char nibbles[24];
+ unsigned char bytes[24];
+ unsigned short words[24];
+
+ /* Nibble number of first word not yet fetched. */
+ int max_fetched;
+ bfd_vma insn_start;
+ jmp_buf bailout;
+
+ long tabl_index;
+ char instr_asmsrc[80];
+ unsigned long arg_reg[0x0f];
+ unsigned long immediate;
+ unsigned long displacement;
+ unsigned long address;
+ unsigned long cond_code;
+ unsigned long ctrl_code;
+ unsigned long flags;
+ unsigned long interrupts;
+}
+instr_data_s;
+
+/* 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, nibble) \
+ ((nibble) <= ((instr_data_s *)(info->private_data))->max_fetched \
+ ? 1 : fetch_data ((info), (nibble)))
+
+static int
+fetch_data (info, nibble)
+ struct disassemble_info *info;
+ int nibble;
+{
+ char mybuf[20];
+ int status;
+ instr_data_s *priv = (instr_data_s *)info->private_data;
+ bfd_vma start = priv->insn_start + priv->max_fetched / 2;
+
+ if ((nibble % 4) != 0)
+ abort ();
+ status = (*info->read_memory_func) (start,
+ mybuf,
+ (nibble - priv->max_fetched) / 2,
+ info);
+ if (status != 0)
+ {
+ (*info->memory_error_func) (status, start, info);
+ longjmp (priv->bailout);
+ }
+
+ {
+ int i;
+ char *p = mybuf + priv->max_fetched / 2;
+
+ for (i = priv->max_fetched; i < nibble;)
+ {
+ priv->words[i] = (p[0] << 8) | p[1];
+
+ priv->bytes[i] = *p;
+ priv->nibbles[i++] = *p >> 4;
+ priv->nibbles[i++] = *p &0xf;
+
+ ++p;
+ priv->bytes[i] = *p;
+ priv->nibbles[i++] = *p >> 4;
+ priv->nibbles[i++] = *p & 0xf;
+
+ ++p;
+ }
+ }
+ priv->max_fetched = nibble;
+ return 1;
+}
+
+static char *codes[16] =
{
"f",
"lt",
"nc/uge"
};
-
-int print_insn_z8k(addr, in_buf, stream)
-unsigned long addr;
-unsigned char *in_buf;
-FILE *stream;
+int z8k_lookup_instr PARAMS ((unsigned char*, disassemble_info *));
+static void output_instr
+ PARAMS ((instr_data_s *, unsigned long, disassemble_info *));
+static void unpack_instr PARAMS ((instr_data_s *, int, disassemble_info *));
+static void unparse_instr PARAMS ((instr_data_s *));
+
+static int
+print_insn_z8k (addr, info, is_segmented)
+ unsigned long addr;
+ disassemble_info *info;
+ int is_segmented;
{
- instr_data_s instr_data;
+ instr_data_s instr_data;
- fetch_instr( &in_buf, &instr_data );
- if ( lookup_instr( &instr_data ))
- {
- fetch_data( &in_buf, &instr_data );
- unpack_instr( &instr_data );
- unparse_instr( &instr_data );
- output_instr( &instr_data, addr, stream );
- return instr_data.bytes_fetched;
- }
- else {
- fprintf(stream,".word %02x%02x", in_buf[0], in_buf[1]);
- return 2;
- }
-
-}
-
-
-static void fetch_data( in_buf, instr_data )
-unsigned char **in_buf;
-instr_data_s *instr_data;
-{
- int bytes_2fetch;
-
- bytes_2fetch = z8k_table[instr_data->tabl_index].length -
- instr_data->bytes_fetched;
- while( bytes_2fetch-- )
- instr_data->instr_buf[instr_data->bytes_fetched++] = *(*in_buf)++;
-}
-
-static void fetch_instr( in_buf, instr_data )
-unsigned char **in_buf;
-instr_data_s *instr_data;
-{
- unsigned int loop = 2;
-
- instr_data->bytes_fetched = 0;
- while( loop-- )
- instr_data->instr_buf[instr_data->bytes_fetched++] = *(*in_buf)++;
+ info->private_data = (PTR) &instr_data;
+ instr_data.max_fetched = 0;
+ instr_data.insn_start = addr;
+ if (setjmp (instr_data.bailout) != 0)
+ /* Error return. */
+ return -1;
+ instr_data.tabl_index = z8k_lookup_instr (instr_data.nibbles, info);
+ if (instr_data.tabl_index > 0)
+ {
+ unpack_instr (&instr_data, is_segmented, info);
+ unparse_instr (&instr_data);
+ output_instr (&instr_data, addr, info);
+ return z8k_table[instr_data.tabl_index].length;
+ }
+ else
+ {
+ FETCH_DATA (info, 4);
+ (*info->fprintf_func) (info->stream, ".word %02x%02x",
+ instr_data.bytes[0], instr_data.bytes[2]);
+ return 2;
+ }
}
-static unsigned long get_val( instr_buf, start_nibl, nibls_long )
-unsigned char (*instr_buf)[];
-unsigned int start_nibl, nibls_long;
+print_insn_z8001 (addr, info)
+ unsigned long addr;
+ disassemble_info *info;
{
- unsigned long ret_val;
- unsigned char byte_val, nibl_val;
- unsigned int nibl_index, nibl_lim;
- unsigned int byte_index;
- unsigned int which_nibl;
-
- ret_val = 0;
- nibl_lim = start_nibl + nibls_long;
- for( nibl_index = start_nibl; nibl_index < nibl_lim; nibl_index++ )
- {
- byte_index = nibl_index / 2;
- which_nibl = nibl_index % 2;
- switch( which_nibl )
- {
- case 0:
- byte_val = (*instr_buf)[byte_index];
- nibl_val = (byte_val >> 4) & 0x0f;
- break;
- case 1:
- nibl_val = byte_val & 0x0f;
- break;
- }
- ret_val = (ret_val << 4) | nibl_val;
- }
-
- return ret_val;
-
+ return print_insn_z8k (addr, info, 1);
}
-static int is_segmented()
+print_insn_z8002 (addr, info)
+ unsigned long addr;
+ disassemble_info *info;
{
- return 1;
+ return print_insn_z8k (addr, info, 0);
}
-static
-int lookup_instr( instr_data )
-instr_data_s *instr_data;
+int
+z8k_lookup_instr (nibbles, info)
+ unsigned char *nibbles;
+ disassemble_info *info;
{
- int nibl_index, tabl_index;
- int tablent_found, nibl_matched;
+ int nibl_index, tabl_index;
+ int nibl_matched;
unsigned short instr_nibl;
unsigned short tabl_datum, datum_class, datum_value;
nibl_matched = 0;
tabl_index = 0;
- while( ! nibl_matched && z8k_table[tabl_index].name)
- {
- nibl_matched = 1;
- for( nibl_index = 0; nibl_index < 4 && nibl_matched; nibl_index++ )
+ while (!nibl_matched && z8k_table[tabl_index].name)
{
- instr_nibl = get_val( instr_data->instr_buf, nibl_index, 1 );
-
- tabl_datum = z8k_table[tabl_index].byte_info[nibl_index];
- datum_class = tabl_datum & CLASS_MASK;
- datum_value = ~CLASS_MASK & tabl_datum;
-
- switch( datum_class )
- {
- case CLASS_BIT:
- if( datum_value != instr_nibl ) nibl_matched = 0;
- break;
- case CLASS_00II:
- if( ! ((~instr_nibl) & 0x4) ) nibl_matched = 0;
- break;
- case CLASS_01II:
- if( ! (instr_nibl & 0x4) ) nibl_matched = 0;
- break;
- case CLASS_0CCC:
- if( ! ((~instr_nibl) & 0x8) ) nibl_matched = 0;
- break;
- case CLASS_1CCC:
- if( ! (instr_nibl & 0x8) ) nibl_matched = 0;
- break;
- case CLASS_0DISP7:
- if( ! ((~instr_nibl) & 0x8) ) nibl_matched = 0;
- nibl_index += 1;
- break;
- case CLASS_1DISP7:
- if( ! (instr_nibl & 0x8) ) nibl_matched = 0;
- nibl_index += 1;
- break;
- case CLASS_REGN0:
- if( instr_nibl == 0 ) nibl_matched = 0;
- break;
- default:
- break;
- }
+ nibl_matched = 1;
+ for (nibl_index = 0; nibl_index < z8k_table[tabl_index].length * 2 && nibl_matched; nibl_index++)
+ {
+ if ((nibl_index % 4) == 0)
+ /* Fetch one word at a time. */
+ FETCH_DATA (info, nibl_index + 4);
+ instr_nibl = nibbles[nibl_index];
+
+ tabl_datum = z8k_table[tabl_index].byte_info[nibl_index];
+ datum_class = tabl_datum & CLASS_MASK;
+ datum_value = ~CLASS_MASK & tabl_datum;
+
+ switch (datum_class)
+ {
+ case CLASS_BIT:
+ if (datum_value != instr_nibl)
+ nibl_matched = 0;
+ break;
+ case CLASS_00II:
+ if (!((~instr_nibl) & 0x4))
+ nibl_matched = 0;
+ break;
+ case CLASS_01II:
+ if (!(instr_nibl & 0x4))
+ nibl_matched = 0;
+ break;
+ case CLASS_0CCC:
+ if (!((~instr_nibl) & 0x8))
+ nibl_matched = 0;
+ break;
+ case CLASS_1CCC:
+ if (!(instr_nibl & 0x8))
+ nibl_matched = 0;
+ break;
+ case CLASS_0DISP7:
+ if (!((~instr_nibl) & 0x8))
+ nibl_matched = 0;
+ nibl_index += 1;
+ break;
+ case CLASS_1DISP7:
+ if (!(instr_nibl & 0x8))
+ nibl_matched = 0;
+ nibl_index += 1;
+ break;
+ case CLASS_REGN0:
+ if (instr_nibl == 0)
+ nibl_matched = 0;
+ break;
+ case CLASS_BIT_1OR2:
+ if ((instr_nibl | 0x2) != (datum_value | 0x2))
+ nibl_matched = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ if (nibl_matched)
+ {
+ return tabl_index;
+ }
+
+ tabl_index++;
}
- tabl_index++;
- }
-
-
- instr_data->tabl_index = tabl_index;
-
- return nibl_matched;
+ return -1;
}
-static void output_instr( instr_data, addr, stream )
-instr_data_s *instr_data;
-unsigned long addr;
-FILE *stream;
+static void
+output_instr (instr_data, addr, info)
+ instr_data_s *instr_data;
+ unsigned long addr;
+ disassemble_info *info;
{
- int loop, loop_limit;
- unsigned long word_val;
- char tmp_str[20];
- char out_str[100];
+ int loop, loop_limit;
+ char tmp_str[20];
+ char out_str[100];
- strcpy( out_str, "" );
+ strcpy (out_str, "\t");
- loop_limit = z8k_table[instr_data->tabl_index].length / 2;
- for( loop = 0; loop < loop_limit; loop++ )
- {
- word_val = get_val( instr_data->instr_buf, loop * 4, 4 );
- sprintf( tmp_str, "%04x ", word_val );
- strcat( out_str, tmp_str );
- }
+ loop_limit = z8k_table[instr_data->tabl_index].length * 2;
+ FETCH_DATA (info, loop_limit);
+ for (loop = 0; loop < loop_limit; loop++)
+ {
+ sprintf (tmp_str, "%x", instr_data->nibbles[loop]);
+ strcat (out_str, tmp_str);
+ }
- while( loop++ < 5 )
- {
- strcat( out_str, " " );
- }
+ while (loop++ < 8)
+ {
+ strcat (out_str, " ");
+ }
- strcat( out_str, instr_data->instr_asmsrc );
+ strcat (out_str, instr_data->instr_asmsrc);
- fprintf( stream, "%s", out_str );
+ (*info->fprintf_func) (info->stream, "%s", out_str);
}
-static void unpack_instr( instr_data )
-instr_data_s *instr_data;
+static void
+unpack_instr (instr_data, is_segmented, info)
+ instr_data_s *instr_data;
+ int is_segmented;
+ disassemble_info *info;
{
- int nibl_index, word_index;
- int nibl_count, loop;
- unsigned short instr_nibl, instr_byte, instr_word, instr_long;
- unsigned short tabl_datum, datum_class, datum_value;
-
- nibl_count = 0;
- loop = 0;
- while( z8k_table[instr_data->tabl_index].byte_info[loop] != 0 )
- {
- word_index = (int) nibl_count / 4;
- nibl_index = (int) nibl_count % 4;
-
- switch( nibl_index )
- {
- case 0:
- instr_nibl = get_val( instr_data->instr_buf, nibl_count, 1 );
- instr_byte = get_val( instr_data->instr_buf, nibl_count, 2 );
- instr_word = get_val( instr_data->instr_buf, nibl_count, 4 );
- instr_long = get_val( instr_data->instr_buf, nibl_count, 8 );
- break;
- case 1:
- instr_nibl = get_val( instr_data->instr_buf, nibl_count, 1 );
- break;
- case 2:
- instr_nibl = get_val( instr_data->instr_buf, nibl_count, 1 );
- instr_byte = get_val( instr_data->instr_buf, nibl_count, 2 );
- break;
- case 3:
- instr_nibl = get_val( instr_data->instr_buf, nibl_count, 1 );
- break;
- default:
- break;
- }
+ int nibl_count, loop;
+ unsigned short instr_nibl, instr_byte, instr_word;
+ long instr_long;
+ unsigned short tabl_datum, datum_class, datum_value;
+
+ nibl_count = 0;
+ loop = 0;
+ while (z8k_table[instr_data->tabl_index].byte_info[loop] != 0)
+ {
+ FETCH_DATA (info, nibl_count + 4 - (nibl_count % 4));
+ instr_nibl = instr_data->nibbles[nibl_count];
+ instr_byte = instr_data->bytes[nibl_count];
+ instr_word = instr_data->words[nibl_count];
tabl_datum = z8k_table[instr_data->tabl_index].byte_info[loop];
datum_class = tabl_datum & CLASS_MASK;
datum_value = tabl_datum & ~CLASS_MASK;
- switch( datum_class )
- {
- case CLASS_X:
- instr_data->address = instr_nibl;
- break;
- case CLASS_BA:
- instr_data->displacement = instr_nibl;
- break;
- case CLASS_BX:
- instr_data->arg_reg[datum_value] = instr_nibl;
- break;
- case CLASS_DISP:
- switch( datum_value )
- {
- case ARG_DISP16:
- instr_data->displacement = instr_word;
- nibl_count += 3;
- break;
- case ARG_DISP12:
- instr_data->displacement = instr_word & 0x0fff;
- nibl_count += 2;
- break;
- default:
- break;
- }
- break;
- case CLASS_IMM:
- switch( datum_value )
- {
- case ARG_IMM4:
- instr_data->immediate = instr_nibl;
- break;
- case ARG_IMM8:
- instr_data->immediate = instr_byte;
- nibl_count += 1;
- break;
- case ARG_IMM16:
- instr_data->immediate = instr_word;
- nibl_count += 3;
- break;
- case ARG_IMM32:
- instr_data->immediate = instr_long;
- nibl_count += 7;
- break;
- case ARG_IMMN:
- instr_data->immediate = instr_nibl -1;
- break;
- /* ????? */
- /* missing ARG_IMMNMINUS1 */
- case ARG_IMM_1:
- instr_data->immediate = 1;
- break;
- case ARG_IMM_2:
- instr_data->immediate = 2;
- break;
- case ARG_NIM16:
- instr_data->immediate = (- instr_word);
- nibl_count += 3;
- break;
- case ARG_IMM2:
- instr_data->immediate = instr_nibl & 0x3;
- break;
- default:
- break;
- }
- break;
- case CLASS_CC:
- instr_data->cond_code = instr_nibl;
- break;
- case CLASS_CTRL:
- instr_data->ctrl_code = instr_nibl;
- break;
- case CLASS_DA:
- case CLASS_ADDRESS:
- if( is_segmented() )
- {
- if( instr_nibl & 0x8 )
- {
- instr_data->address = ((instr_word & 0x7f00) << 8) +
- (instr_long & 0xffff);
- nibl_count += 7;
- }
- else
- {
- instr_data->address = ((instr_word & 0x7f00) << 8) +
- (instr_word & 0x00ff);
- nibl_count += 3;
- }
- }
- else
- {
- instr_data->address = instr_word;
- nibl_count += 3;
- }
- break;
- case CLASS_0CCC:
- instr_data->cond_code = instr_nibl & 0x7;
- break;
- case CLASS_1CCC:
- instr_data->cond_code = instr_nibl & 0x7;
- break;
- case CLASS_0DISP7:
- instr_data->displacement = instr_byte & 0x7f;
- nibl_count += 1;
- break;
- case CLASS_1DISP7:
- instr_data->displacement = instr_byte & 0x7f;
- nibl_count += 1;
- break;
- case CLASS_01II:
- instr_data->interrupts = instr_nibl & 0x3;
- break;
- case CLASS_00II:
- instr_data->interrupts = instr_nibl & 0x3;
- break;
- case CLASS_BIT:
- /* do nothing */
- break;
- case CLASS_IR:
- instr_data->arg_reg[datum_value] = instr_nibl;
- break;
- case CLASS_FLAGS:
- instr_data->flags = instr_nibl;
- break;
- case CLASS_REG:
- instr_data->arg_reg[datum_value] = instr_nibl;
- break;
- case CLASS_REG_BYTE:
- instr_data->arg_reg[datum_value] = instr_nibl;
- break;
- case CLASS_REG_WORD:
- instr_data->arg_reg[datum_value] = instr_nibl;
- break;
- case CLASS_REG_QUAD:
- instr_data->arg_reg[datum_value] = instr_nibl;
- break;
- case CLASS_REG_LONG:
- instr_data->arg_reg[datum_value] = instr_nibl;
- break;
- case CLASS_REGN0:
- instr_data->arg_reg[datum_value] = instr_nibl;
- break;
- default:
- break;
- }
+ switch (datum_class)
+ {
+ case CLASS_X:
+ instr_data->address = instr_nibl;
+ break;
+ case CLASS_BA:
+ instr_data->displacement = instr_nibl;
+ break;
+ case CLASS_BX:
+ instr_data->arg_reg[datum_value] = instr_nibl;
+ break;
+ case CLASS_DISP:
+ switch (datum_value)
+ {
+ case ARG_DISP16:
+ instr_data->displacement = instr_word;
+ nibl_count += 3;
+ break;
+ case ARG_DISP12:
+ instr_data->displacement = instr_word & 0x0fff;
+ nibl_count += 2;
+ break;
+ default:
+ break;
+ }
+ break;
+ case CLASS_IMM:
+ switch (datum_value)
+ {
+ case ARG_IMM4:
+ instr_data->immediate = instr_nibl;
+ break;
+ case ARG_NIM8:
+ instr_data->immediate = (-instr_byte);
+ nibl_count += 1;
+ break;
+ case ARG_IMM8:
+ instr_data->immediate = instr_byte;
+ nibl_count += 1;
+ break;
+ case ARG_IMM16:
+ instr_data->immediate = instr_word;
+ nibl_count += 3;
+ break;
+ case ARG_IMM32:
+ FETCH_DATA (info, nibl_count + 8);
+ instr_long = (instr_data->words[nibl_count] << 16)
+ | (instr_data->words[nibl_count + 4]);
+ instr_data->immediate = instr_long;
+ nibl_count += 7;
+ break;
+ case ARG_IMMN:
+ instr_data->immediate = instr_nibl - 1;
+ break;
+ /* ????? */
+ /* missing ARG_IMMNMINUS1 */
+ case ARG_IMM_1:
+ instr_data->immediate = 1;
+ break;
+ case ARG_IMM_2:
+ instr_data->immediate = 2;
+ break;
+ case ARG_IMM2:
+ instr_data->immediate = instr_nibl & 0x3;
+ break;
+ default:
+ break;
+ }
+ break;
+ case CLASS_CC:
+ instr_data->cond_code = instr_nibl;
+ break;
+ case CLASS_CTRL:
+ instr_data->ctrl_code = instr_nibl;
+ break;
+ case CLASS_DA:
+ case CLASS_ADDRESS:
+ if (is_segmented)
+ {
+ if (instr_nibl & 0x8)
+ {
+ FETCH_DATA (info, nibl_count + 8);
+ instr_long = (instr_data->words[nibl_count] << 16)
+ | (instr_data->words[nibl_count + 4]);
+ instr_data->address = ((instr_word & 0x7f00) << 8) +
+ (instr_long & 0xffff);
+ nibl_count += 7;
+ }
+ else
+ {
+ instr_data->address = ((instr_word & 0x7f00) << 8) +
+ (instr_word & 0x00ff);
+ nibl_count += 3;
+ }
+ }
+ else
+ {
+ instr_data->address = instr_word;
+ nibl_count += 3;
+ }
+ break;
+ case CLASS_0CCC:
+ instr_data->cond_code = instr_nibl & 0x7;
+ break;
+ case CLASS_1CCC:
+ instr_data->cond_code = instr_nibl & 0x7;
+ break;
+ case CLASS_0DISP7:
+ instr_data->displacement = instr_byte & 0x7f;
+ nibl_count += 1;
+ break;
+ case CLASS_1DISP7:
+ instr_data->displacement = instr_byte & 0x7f;
+ nibl_count += 1;
+ break;
+ case CLASS_01II:
+ instr_data->interrupts = instr_nibl & 0x3;
+ break;
+ case CLASS_00II:
+ instr_data->interrupts = instr_nibl & 0x3;
+ break;
+ case CLASS_BIT:
+ /* do nothing */
+ break;
+ case CLASS_IR:
+ instr_data->arg_reg[datum_value] = instr_nibl;
+ break;
+ case CLASS_FLAGS:
+ instr_data->flags = instr_nibl;
+ break;
+ case CLASS_REG:
+ instr_data->arg_reg[datum_value] = instr_nibl;
+ break;
+ case CLASS_REG_BYTE:
+ instr_data->arg_reg[datum_value] = instr_nibl;
+ break;
+ case CLASS_REG_WORD:
+ instr_data->arg_reg[datum_value] = instr_nibl;
+ break;
+ case CLASS_REG_QUAD:
+ instr_data->arg_reg[datum_value] = instr_nibl;
+ break;
+ case CLASS_REG_LONG:
+ instr_data->arg_reg[datum_value] = instr_nibl;
+ break;
+ case CLASS_REGN0:
+ instr_data->arg_reg[datum_value] = instr_nibl;
+ break;
+ default:
+ break;
+ }
loop += 1;
nibl_count += 1;
- }
+ }
}
-static void unparse_instr( instr_data )
-instr_data_s *instr_data;
+static void
+unparse_instr (instr_data)
+ instr_data_s *instr_data;
{
- unsigned short tabl_datum, datum_class, datum_value;
- int loop, loop_limit;
- char out_str[80], tmp_str[25];
+ unsigned short tabl_datum, datum_class, datum_value;
+ int loop, loop_limit;
+ char out_str[80], tmp_str[25];
- sprintf( out_str, "\t%s\t", z8k_table[instr_data->tabl_index].name );
+ sprintf (out_str, "\t%s\t", z8k_table[instr_data->tabl_index].name);
- loop_limit = z8k_table[instr_data->tabl_index].noperands;
- for( loop = 0; loop < loop_limit; loop++ )
- {
- if( loop )
- strcat( out_str, "," );
+ loop_limit = z8k_table[instr_data->tabl_index].noperands;
+ for (loop = 0; loop < loop_limit; loop++)
+ {
+ if (loop)
+ strcat (out_str, ",");
tabl_datum = z8k_table[instr_data->tabl_index].arg_info[loop];
datum_class = tabl_datum & CLASS_MASK;
datum_value = tabl_datum & ~CLASS_MASK;
- switch( datum_class )
- {
- case CLASS_X:
- sprintf( tmp_str, "0x%0x(R%d)", instr_data->address,
- instr_data->arg_reg[datum_value] );
- strcat( out_str, tmp_str );
- break;
- case CLASS_BA:
- sprintf( tmp_str, "r%d(#%x)", instr_data->arg_reg[datum_value],
- instr_data->displacement);
- strcat( out_str, tmp_str );
- break;
- case CLASS_BX:
- sprintf( tmp_str, "r%d(R%d)", instr_data->arg_reg[datum_value],
- instr_data->arg_reg[ARG_RX] );
- strcat( out_str, tmp_str );
- break;
- case CLASS_DISP:
- sprintf( tmp_str, "#0x%0x", instr_data->displacement );
- strcat( out_str, tmp_str );
- break;
- case CLASS_IMM:
- sprintf( tmp_str, "#0x%0x", instr_data->immediate );
- strcat( out_str, tmp_str );
- break;
- case CLASS_CC:
- sprintf( tmp_str, "%s", codes[instr_data->cond_code] );
- strcat( out_str, tmp_str );
- break;
- case CLASS_CTRL:
- sprintf( tmp_str, "0x%0x", instr_data->ctrl_code );
- strcat( out_str, tmp_str );
- break;
- case CLASS_DA:
- case CLASS_ADDRESS:
- sprintf( tmp_str, "#0x%0x", instr_data->address );
- strcat( out_str, tmp_str );
- break;
- case CLASS_IR:
- sprintf( tmp_str, "@R%d", instr_data->arg_reg[datum_value] );
- strcat( out_str, tmp_str );
- break;
- case CLASS_FLAGS:
- sprintf( tmp_str, "0x%0x", instr_data->flags );
- strcat( out_str, tmp_str );
- break;
- case CLASS_REG_BYTE:
- if( instr_data->arg_reg[datum_value] >= 0x8 )
- {
- sprintf( tmp_str, "rl%d",
- instr_data->arg_reg[datum_value] - 0x8 );
- }
- else
- {
- sprintf( tmp_str, "rh%d", instr_data->arg_reg[datum_value] );
- }
- strcat( out_str, tmp_str );
- break;
- case CLASS_REG_WORD:
- sprintf( tmp_str, "r%d", instr_data->arg_reg[datum_value] );
- strcat( out_str, tmp_str );
- break;
- case CLASS_REG_QUAD:
- sprintf( tmp_str, "rq%d", instr_data->arg_reg[datum_value] );
- strcat( out_str, tmp_str );
- break;
- case CLASS_REG_LONG:
- sprintf( tmp_str, "rr%d", instr_data->arg_reg[datum_value] );
- strcat( out_str, tmp_str );
- break;
- default:
- break;
- }
- }
+ switch (datum_class)
+ {
+ case CLASS_X:
+ sprintf (tmp_str, "0x%0x(R%d)", instr_data->address,
+ instr_data->arg_reg[datum_value]);
+ strcat (out_str, tmp_str);
+ break;
+ case CLASS_BA:
+ sprintf (tmp_str, "r%d(#%x)", instr_data->arg_reg[datum_value],
+ instr_data->immediate);
+ strcat (out_str, tmp_str);
+ break;
+ case CLASS_BX:
+ sprintf (tmp_str, "r%d(R%d)", instr_data->arg_reg[datum_value],
+ instr_data->arg_reg[ARG_RX]);
+ strcat (out_str, tmp_str);
+ break;
+ case CLASS_DISP:
+ sprintf (tmp_str, "#0x%0x", instr_data->displacement);
+ strcat (out_str, tmp_str);
+ break;
+ case CLASS_IMM:
+ sprintf (tmp_str, "#0x%0x", instr_data->immediate);
+ strcat (out_str, tmp_str);
+ break;
+ case CLASS_CC:
+ sprintf (tmp_str, "%s", codes[instr_data->cond_code]);
+ strcat (out_str, tmp_str);
+ break;
+ case CLASS_CTRL:
+ sprintf (tmp_str, "0x%0x", instr_data->ctrl_code);
+ strcat (out_str, tmp_str);
+ break;
+ case CLASS_DA:
+ case CLASS_ADDRESS:
+ sprintf (tmp_str, "#0x%0x", instr_data->address);
+ strcat (out_str, tmp_str);
+ break;
+ case CLASS_IR:
+ sprintf (tmp_str, "@R%d", instr_data->arg_reg[datum_value]);
+ strcat (out_str, tmp_str);
+ break;
+ case CLASS_FLAGS:
+ sprintf (tmp_str, "0x%0x", instr_data->flags);
+ strcat (out_str, tmp_str);
+ break;
+ case CLASS_REG_BYTE:
+ if (instr_data->arg_reg[datum_value] >= 0x8)
+ {
+ sprintf (tmp_str, "rl%d",
+ instr_data->arg_reg[datum_value] - 0x8);
+ }
+ else
+ {
+ sprintf (tmp_str, "rh%d", instr_data->arg_reg[datum_value]);
+ }
+ strcat (out_str, tmp_str);
+ break;
+ case CLASS_REG_WORD:
+ sprintf (tmp_str, "r%d", instr_data->arg_reg[datum_value]);
+ strcat (out_str, tmp_str);
+ break;
+ case CLASS_REG_QUAD:
+ sprintf (tmp_str, "rq%d", instr_data->arg_reg[datum_value]);
+ strcat (out_str, tmp_str);
+ break;
+ case CLASS_REG_LONG:
+ sprintf (tmp_str, "rr%d", instr_data->arg_reg[datum_value]);
+ strcat (out_str, tmp_str);
+ break;
+ default:
+ break;
+ }
+ }
- strcpy( instr_data->instr_asmsrc, out_str );
+ strcpy (instr_data->instr_asmsrc, out_str);
}