aboutsummaryrefslogtreecommitdiff
path: root/gdb/gould-pinsn.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/gould-pinsn.c')
-rw-r--r--gdb/gould-pinsn.c294
1 files changed, 294 insertions, 0 deletions
diff --git a/gdb/gould-pinsn.c b/gdb/gould-pinsn.c
new file mode 100644
index 0000000..b655f26
--- /dev/null
+++ b/gdb/gould-pinsn.c
@@ -0,0 +1,294 @@
+/* Print GOULD RISC instructions for GDB, the GNU debugger.
+ Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
+
+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 "gdbcore.h"
+
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+#if defined GOULD_PN
+#include "pn-opcode.h"
+#else
+#include "np1-opcode.h"
+#endif
+
+/* GOULD RISC instructions are never longer than this many bytes. */
+#define MAXLEN 4
+
+/* Number of elements in the opcode table. */
+#define NOPCODES (sizeof gld_opcodes / sizeof gld_opcodes[0])
+
+
+/* Print the GOULD instruction at address MEMADDR in debugged memory,
+ on STREAM. Returns length of the instruction, in bytes. */
+
+int
+print_insn (memaddr, stream)
+ CORE_ADDR memaddr;
+ FILE *stream;
+{
+ unsigned char buffer[MAXLEN];
+ register int i;
+ register char *d;
+ register int bestmask;
+ unsigned best;
+ int temp, index, bestlen;
+
+ read_memory (memaddr, buffer, MAXLEN);
+
+ bestmask = 0;
+ index = -1;
+ best = 0xffffffff;
+ for (i = 0; i < NOPCODES; i++)
+ {
+ register unsigned int opcode = gld_opcodes[i].opcode;
+ register unsigned int mask = gld_opcodes[i].mask;
+ register unsigned int len = gld_opcodes[i].length;
+ register unsigned int test;
+
+ /* Get possible opcode bytes into integer */
+ test = buffer[0] << 24;
+ test |= buffer[1] << 16;
+ test |= buffer[2] << 8;
+ test |= buffer[3];
+
+ /* Mask with opcode and see if match */
+ if ((opcode & mask) == (test & mask))
+ {
+ /* See if second or third match */
+ if (index >= 0)
+ {
+ /* Take new one if it looks good */
+ if (bestlen == MAXLEN && len == MAXLEN)
+ {
+ /* See if lower bits matched */
+ if (((bestmask & 3) == 0) &&
+ ((mask & 3) != 0))
+ {
+ bestmask = mask;
+ bestlen = len;
+ best = test;
+ index = i;
+ }
+ }
+ }
+ else
+ {
+ /* First match, save it */
+ bestmask = mask;
+ bestlen = len;
+ best = test;
+ index = i;
+ }
+ }
+ }
+
+ /* Handle undefined instructions. */
+ if (index < 0)
+ {
+ fprintf (stream, "undefined 0%o",(buffer[0]<<8)+buffer[1]);
+ return 2;
+ }
+
+ /* Print instruction name */
+ fprintf (stream, "%-12s", gld_opcodes[index].name);
+
+ /* Adjust if short instruction */
+ if (gld_opcodes[index].length < 4)
+ {
+ best >>= 16;
+ i = 0;
+ }
+ else
+ {
+ i = 16;
+ }
+
+ /* Dump out instruction arguments */
+ for (d = gld_opcodes[index].args; *d; ++d)
+ {
+ switch (*d)
+ {
+ case 'f':
+ fprintf (stream, "%d", (best >> (7 + i)) & 7);
+ break;
+ case 'r':
+ fprintf (stream, "r%d", (best >> (7 + i)) & 7);
+ break;
+ case 'R':
+ fprintf (stream, "r%d", (best >> (4 + i)) & 7);
+ break;
+ case 'b':
+ fprintf (stream, "b%d", (best >> (7 + i)) & 7);
+ break;
+ case 'B':
+ fprintf (stream, "b%d", (best >> (4 + i)) & 7);
+ break;
+ case 'v':
+ fprintf (stream, "b%d", (best >> (7 + i)) & 7);
+ break;
+ case 'V':
+ fprintf (stream, "b%d", (best >> (4 + i)) & 7);
+ break;
+ case 'X':
+ temp = (best >> 20) & 7;
+ if (temp)
+ fprintf (stream, "r%d", temp);
+ else
+ putc ('0', stream);
+ break;
+ case 'A':
+ temp = (best >> 16) & 7;
+ if (temp)
+ fprintf (stream, "(b%d)", temp);
+ break;
+ case 'S':
+ fprintf (stream, "#%d", best & 0x1f);
+ break;
+ case 'I':
+ fprintf (stream, "#%x", best & 0xffff);
+ break;
+ case 'O':
+ fprintf (stream, "%x", best & 0xffff);
+ break;
+ case 'h':
+ fprintf (stream, "%d", best & 0xfffe);
+ break;
+ case 'd':
+ fprintf (stream, "%d", best & 0xfffc);
+ break;
+ case 'T':
+ fprintf (stream, "%d", (best >> 8) & 0xff);
+ break;
+ case 'N':
+ fprintf (stream, "%d", best & 0xff);
+ break;
+ default:
+ putc (*d, stream);
+ break;
+ }
+ }
+
+ /* Return length of instruction */
+ return (gld_opcodes[index].length);
+}
+
+/*
+ * Find the number of arguments to a function.
+ */
+findarg(frame)
+ struct frame_info *frame;
+{
+ register struct symbol *func;
+ register unsigned pc;
+
+#ifdef notdef
+ /* find starting address of frame function */
+ pc = get_pc_function_start (frame->pc);
+
+ /* find function symbol info */
+ func = find_pc_function (pc);
+
+ /* call blockframe code to look for match */
+ if (func != NULL)
+ return (func->value.block->nsyms / sizeof(int));
+#endif
+
+ return (-1);
+}
+
+/*
+ * In the case of the NPL, the frame's norminal address is Br2 and the
+ * previous routines frame is up the stack X bytes. Finding out what
+ * 'X' is can be tricky.
+ *
+ * 1.) stored in the code function header xA(Br1).
+ * 2.) must be careful of recurssion.
+ */
+FRAME_ADDR
+findframe(thisframe)
+ FRAME thisframe;
+{
+ register FRAME_ADDR pointer;
+ FRAME_ADDR framechain();
+#if 0
+ struct frame_info *frame;
+
+ /* Setup toplevel frame structure */
+ frame->pc = read_pc();
+ frame->next_frame = 0;
+ frame->frame = read_register (SP_REGNUM); /* Br2 */
+
+ /* Search for this frame (start at current Br2) */
+ do
+ {
+ pointer = framechain(frame);
+ frame->next_frame = frame->frame;
+ frame->frame = pointer;
+ frame->pc = FRAME_SAVED_PC(frame);
+ }
+ while (frame->next_frame != thisframe);
+#endif
+
+ pointer = framechain (thisframe);
+
+ /* stop gap for now, end at __base3 */
+ if (thisframe->pc == 0)
+ return 0;
+
+ return pointer;
+}
+
+/*
+ * Gdb front-end and internal framechain routine.
+ * Go back up stack one level. Tricky...
+ */
+FRAME_ADDR
+framechain(frame)
+ register struct frame_info *frame;
+{
+ register CORE_ADDR func, prevsp;
+ register unsigned value;
+
+ /* Get real function start address from internal frame address */
+ func = get_pc_function_start(frame->pc);
+
+ /* If no stack given, read register Br1 "(sp)" */
+ if (!frame->frame)
+ prevsp = read_register (SP_REGNUM);
+ else
+ prevsp = frame->frame;
+
+ /* Check function header, case #2 */
+ value = read_memory_integer (func, 4);
+ if (value)
+ {
+ /* 32bit call push value stored in function header */
+ prevsp += value;
+ }
+ else
+ {
+ /* read half-word from suabr at start of function */
+ prevsp += read_memory_integer (func + 10, 2);
+ }
+
+ return (prevsp);
+}