aboutsummaryrefslogtreecommitdiff
path: root/gdb/mips-pinsn.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/mips-pinsn.c')
-rw-r--r--gdb/mips-pinsn.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/gdb/mips-pinsn.c b/gdb/mips-pinsn.c
new file mode 100644
index 0000000..b348339
--- /dev/null
+++ b/gdb/mips-pinsn.c
@@ -0,0 +1,149 @@
+/* Print mips instructions for GDB, the GNU debugger.
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp)
+
+This file is part of GDB.
+
+GDB 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 1, or (at your option)
+any later version.
+
+GDB 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 GDB; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "mips-opcode.h"
+
+/* Mips instructions are never longer than this many bytes. */
+#define MAXLEN 4
+
+/* Number of elements in the opcode table. */
+#define NOPCODES (sizeof mips_opcodes / sizeof mips_opcodes[0])
+
+#define MKLONG(p) *(unsigned long*)p
+
+extern char *reg_names[];
+
+
+/* subroutine */
+static unsigned char *
+print_insn_arg (d, l, stream, pc)
+ char *d;
+ register unsigned long int *l;
+ FILE *stream;
+ CORE_ADDR pc;
+{
+ switch (*d)
+ {
+ case ',':
+ case '(':
+ case ')':
+ fputc (*d, stream);
+ break;
+
+ case 's':
+ fprintf (stream, "$%s", reg_names[((struct op_i_fmt *) l)->rs]);
+ break;
+
+ case 't':
+ fprintf (stream, "$%s", reg_names[((struct op_i_fmt *) l)->rt]);
+ break;
+
+ case 'i':
+ fprintf (stream, "%d", ((struct op_i_fmt *) l)->immediate);
+ break;
+
+ case 'j': /* same as i, but sign-extended */
+ fprintf (stream, "%d", ((struct op_b_fmt *) l)->delta);
+ break;
+
+ case 'a':
+ print_address ((pc & 0xF0000000) | (((struct op_j_fmt *)l)->target << 2),
+ stream);
+ break;
+
+ case 'b':
+ print_address ((((struct op_b_fmt *) l)->delta << 2) + pc + 4, stream);
+ break;
+
+ case 'd':
+ fprintf (stream, "%s", reg_names[((struct op_r_fmt *) l)->rd]);
+ break;
+
+ case 'h':
+ fprintf (stream, "0x%x", ((struct op_r_fmt *) l)->shamt);
+ break;
+
+ case 'S':
+ fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->fs);
+ break;
+
+ case 'T':
+ fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->ft);
+ break;
+
+ case 'D':
+ fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->fd);
+ break;
+
+ default:
+ fprintf (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 always 4. */
+
+int
+print_insn (memaddr, stream)
+ CORE_ADDR memaddr;
+ FILE *stream;
+{
+ unsigned char buffer[MAXLEN];
+ register int i;
+ register char *d;
+ unsigned long int l;
+
+ read_memory (memaddr, buffer, MAXLEN);
+
+ for (i = 0; i < NOPCODES; i++)
+ {
+ register unsigned int opcode = mips_opcodes[i].opcode;
+ register unsigned int match = mips_opcodes[i].match;
+ if ((*(unsigned int*)buffer & match) == opcode)
+ break;
+ }
+
+ l = MKLONG (buffer);
+ /* Handle undefined instructions. */
+ if (i == NOPCODES)
+ {
+ fprintf (stream, "0x%x",l);
+ return 4;
+ }
+
+ fprintf (stream, "%s", mips_opcodes[i].name);
+
+ if (!(d = mips_opcodes[i].args))
+ return 4;
+
+ fputc (' ', stream);
+
+ while (*d)
+ print_insn_arg (d++, &l, stream, memaddr);
+
+ return 4;
+}