From: Jim Kingdon Date: Wed, 31 Mar 1993 21:43:25 +0000 (+0000) Subject: provide a new interface (using read_memory_func) to call the disassemblers X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=5d0734a7d74cf01b73303aeb884b719b4b220035;p=binutils-gdb.git provide a new interface (using read_memory_func) to call the disassemblers which copes with errors in a plausible way --- diff --git a/binutils/ChangeLog b/binutils/ChangeLog index a9a0b7b329f..0e6dd4635b2 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,7 @@ +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 diff --git a/binutils/objdump.c b/binutils/objdump.c index 95f3a33717f..7d36ad0ad21 100644 --- a/binutils/objdump.c +++ b/binutils/objdump.c @@ -440,8 +440,12 @@ disassemble_data (abfd) 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) @@ -489,9 +493,13 @@ disassemble_data (abfd) 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, diff --git a/gdb/ChangeLog b/gdb/ChangeLog index d423e55634c..44f8877a7de 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,9 @@ +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. diff --git a/gdb/core.c b/gdb/core.c index ca52e39af10..a357352f8de 100644 --- a/gdb/core.c +++ b/gdb/core.c @@ -28,6 +28,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "bfd.h" #include "target.h" #include "gdbcore.h" +#include "dis-asm.h" extern char registers[]; @@ -160,6 +161,27 @@ read_memory (memaddr, myaddr, len) 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) diff --git a/gdb/h8500-tdep.c b/gdb/h8500-tdep.c index 50d5ae055a1..fc167648062 100644 --- a/gdb/h8500-tdep.c +++ b/gdb/h8500-tdep.c @@ -110,12 +110,9 @@ print_insn (memaddr, stream) 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. diff --git a/gdb/i386-pinsn.c b/gdb/i386-pinsn.c index 6c88de9100a..b6d7fe91e39 100644 --- a/gdb/i386-pinsn.c +++ b/gdb/i386-pinsn.c @@ -20,9 +20,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "defs.h" #include "dis-asm.h" -#define MAXLEN 20 -/* 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 @@ -30,16 +29,9 @@ print_insn (memaddr, stream) 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); } diff --git a/gdb/m68k-pinsn.c b/gdb/m68k-pinsn.c index 01bbd926ccf..321ff5dfa70 100644 --- a/gdb/m68k-pinsn.c +++ b/gdb/m68k-pinsn.c @@ -20,9 +20,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "defs.h" #include "dis-asm.h" -/* m68k instructions are never longer than this many bytes. */ -#define MAXLEN 22 - /* Print the m68k instruction at address MEMADDR in debugged memory, on STREAM. Returns length of the instruction, in bytes. */ @@ -31,16 +28,9 @@ print_insn (memaddr, stream) 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); } diff --git a/gdb/mips-pinsn.c b/gdb/mips-pinsn.c index da4232ed5b1..eec22c519a3 100644 --- a/gdb/mips-pinsn.c +++ b/gdb/mips-pinsn.c @@ -20,9 +20,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #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. */ @@ -32,16 +29,13 @@ print_insn (memaddr, stream) 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); } diff --git a/gdb/z8k-tdep.c b/gdb/z8k-tdep.c index ff91a76efe9..10e4e4b31ce 100644 --- a/gdb/z8k-tdep.c +++ b/gdb/z8k-tdep.c @@ -208,19 +208,17 @@ print_insn (memaddr, stream) 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); } } diff --git a/include/ChangeLog b/include/ChangeLog index 2b6accd399e..b118400fb6b 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,14 @@ +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__. diff --git a/include/dis-asm.h b/include/dis-asm.h index d229924aa28..da13bf7f9b6 100644 --- a/include/dis-asm.h +++ b/include/dis-asm.h @@ -7,26 +7,76 @@ typedef int (*fprintf_ftype) PARAMS((FILE*, const char*, ...)); 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*)); diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index ba4f85200c3..31c03ad7ea8 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,19 @@ +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. diff --git a/opcodes/Makefile.in b/opcodes/Makefile.in index 517f7531a7b..47dbd2eb4a5 100644 --- a/opcodes/Makefile.in +++ b/opcodes/Makefile.in @@ -62,7 +62,7 @@ DEP = mkdep 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. @@ -95,11 +95,12 @@ all: $(TARGETLIB) .NOEXPORT: -check: +installcheck check: info: clean-info: install-info: +dvi: # HDEPFILES comes from the host config; TDEPFILES from the target config. diff --git a/opcodes/h8500-dis.c b/opcodes/h8500-dis.c new file mode 100644 index 00000000000..856e580d7ae --- /dev/null +++ b/opcodes/h8500-dis.c @@ -0,0 +1,330 @@ +/* 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 + +#define DISASSEMBLER_TABLE +#define DEFINE_TABLE + +#include "h8500-opc.h" +#include "dis-asm.h" + +/* Maximum length of an instruction. */ +#define MAXLEN 8 + +#include + +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; + +} diff --git a/opcodes/i386-dis.c b/opcodes/i386-dis.c new file mode 100644 index 00000000000..6bdfa5f6f93 --- /dev/null +++ b/opcodes/i386-dis.c @@ -0,0 +1,1952 @@ +/* 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 + +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; + + +/* + * 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 (""); + 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 (""); + 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 = ""; + 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 (""); + 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 (""); + 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 (""); + 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 (""); + 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); +} diff --git a/opcodes/m68k-dis.c b/opcodes/m68k-dis.c new file mode 100644 index 00000000000..743ddac650b --- /dev/null +++ b/opcodes/m68k-dis.c @@ -0,0 +1,970 @@ +/* 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) + + +/* Maximum length of an instruction. */ +#define MAXLEN 22 + +#include + +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 void +m68k_opcode_error(info, code, place) + struct disassemble_info *info; + int code, place; +{ + (*info->fprintf_func)(info->stream, + "", + 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, + "", + (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]); +} diff --git a/opcodes/mips-dis.c b/opcodes/mips-dis.c index 1be0fbd04ca..aaf2beb0cc2 100644 --- a/opcodes/mips-dis.c +++ b/opcodes/mips-dis.c @@ -18,9 +18,9 @@ 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 #include "sysdep.h" -#include -#include "bfd.h" +#include "dis-asm.h" #include "opcode/mips.h" /* FIXME: we need direct access to the swapping functions. */ @@ -60,122 +60,159 @@ extern int print_address PARAMS ((bfd_vma, FILE *)); static CONST char * CONST reg_names[] = REGISTER_NAMES; /* 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; } } /* 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; + } +} diff --git a/opcodes/z8k-dis.c b/opcodes/z8k-dis.c index 2a2d3c343b0..d296f64c3dc 100644 --- a/opcodes/z8k-dis.c +++ b/opcodes/z8k-dis.c @@ -1,33 +1,111 @@ -#include +/* +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 +#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] = + +#include + + +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", @@ -47,473 +125,445 @@ static char *codes[16] = "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); }