/* 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. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #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; }