add OpenBSD/alpha support to gdb (taken from cgd's cygnus binutils
authorgraichen <graichen@openbsd.org>
Sun, 2 Feb 1997 00:39:40 +0000 (00:39 +0000)
committergraichen <graichen@openbsd.org>
Sun, 2 Feb 1997 00:39:40 +0000 (00:39 +0000)
snapshots for NetBSD/alpha and adapted to compile with our binutils)

i've just tested it roughly - but it should work and is at least a start

gnu/usr.bin/binutils/gdb/alpha-tdep.c
gnu/usr.bin/binutils/gdb/alphaobsd-nat.c [new file with mode: 0644]
gnu/usr.bin/binutils/gdb/config/alpha/nm-obsd.h [new file with mode: 0644]
gnu/usr.bin/binutils/gdb/config/alpha/obsd.mh [new file with mode: 0644]
gnu/usr.bin/binutils/gdb/config/alpha/obsd.mt [new file with mode: 0644]
gnu/usr.bin/binutils/gdb/config/alpha/tm-alphaobsd.h [new file with mode: 0644]
gnu/usr.bin/binutils/gdb/config/alpha/xm-alphaobsd.h [new file with mode: 0644]

index e07d75a..bec8ca7 100644 (file)
@@ -1396,3 +1396,209 @@ search.  The only need to set it is when debugging a stripped executable.",
   c->function.sfunc = reinit_frame_cache_sfunc;
   add_show_from_set (c, &showlist);
 }
+
+#ifdef NO_SINGLE_STEP
+/*
+ * If NO_SINGLE_STEP defined, we're simulating single step with
+ * breakpoints, either because the kernel doesn't provide it or
+ * Just Because We Want To.
+ */
+
+/*
+ * Branch types.  Only two types are distinguished:
+ * conditional and unconditional.
+ *
+ * We don't bother to set breakpoint after an unconditional
+ * branch, as it's (supposedly 8-) unconditional!
+ */
+
+typedef enum {
+       Error, not_branch,
+       branch_conditional, branch_unconditional,
+} branch_type;
+
+/*
+ * Information about the various breakpoints we may have set:
+ * (1) their addresses, (2) whether or not we actually set them,
+ * and (3) the previous contents of the memory.
+ */
+
+static CORE_ADDR next_pc, target;
+static int brk_next_pc, brk_target;
+typedef char binsn_quantum[BREAKPOINT_MAX];
+static binsn_quantum brkmem_next_pc, brkmem_target;
+
+/*
+ * Non-zero if we just simulated a single-step ptrace call.  This is
+ * needed because we cannot remove the breakpoints in the inferior
+ * process until after the `wait' in `wait_for_inferior'.
+ */  
+
+int one_stepped;
+
+/*
+ * single_step() is called just before we want to resume the inferior,
+ * if we want to single-step it but there is no hardware or kernel
+ * single-step support (as in NetBSD, on the Alpha).  We find all the
+ * possible targets of the coming instruction and breakpoint them.
+ *
+ * single_step() is also called just after the inferior stops.  IF we
+ * had set up a simulated single-step, we undo our damage.
+ */
+
+void
+single_step(ignore)
+       enum target_signal ignore;                      /* pid, but we don't need it. */
+{
+       branch_type br, isbranch();
+       CORE_ADDR pc;
+       unsigned int pc_instruction;
+
+       pc = read_register(PC_REGNUM);
+
+       if (one_stepped) {
+               /*
+                * The inferior has stopped.  Adjust the PC to
+                * deal with the breakpoint we just took and
+                * clean up the breakpoints we set.
+                */
+
+               write_pc(pc - DECR_PC_AFTER_BREAK);
+
+               /* If no breakpoints set, we have a problem. */
+               if (!brk_next_pc && !brk_target)
+                       abort();
+
+               if (brk_next_pc)
+                       target_remove_breakpoint(next_pc, brkmem_next_pc);
+
+               if (brk_target)
+                       target_remove_breakpoint(target, brkmem_target);
+
+               one_stepped = 0;
+               return;
+       }
+
+       pc_instruction = read_memory_integer(pc, sizeof(pc_instruction));
+       br = isbranch(pc_instruction, pc, &target);
+
+       switch (br) {
+       default:
+       case Error:
+               abort();
+
+       case not_branch:
+               next_pc = pc + 4;
+               brk_next_pc = 1;
+               brk_target = 0;
+               break;
+
+       case branch_unconditional:
+               brk_next_pc = 0;
+               brk_target = 1;
+               break;
+
+       case branch_conditional:
+               next_pc = pc + 4;
+               brk_next_pc = brk_target = 1;
+               break;
+       }
+       
+       if (brk_next_pc)
+               target_insert_breakpoint(next_pc, brkmem_next_pc);
+       if (brk_target)
+               target_insert_breakpoint(target, brkmem_target);
+
+       /* Let it go. */
+       one_stepped = 1;
+}
+
+/*
+ * Check instruction at ADDR to see if it is a branch or other
+ * instruction whose target isn't pc+4.  All other instructions
+ * will go to NPC or will trap.  Set *TARGET if we find a
+ * candidate branch.
+ */
+
+branch_type
+isbranch(instruction, addr, target)
+       unsigned int instruction;
+       CORE_ADDR addr, *target;
+{
+       branch_type val;
+       long offset;                    /* Must be signed for sign-extend. */
+       union {
+               unsigned int code;                      /* raw bits */
+               struct {                                /* common bits */
+                       unsigned int unk:26;
+                       unsigned int op:6;
+               } common;
+               struct {                                /* memory format */
+                                int disp:16;
+                       unsigned int rb:5;
+                       unsigned int ra:5;
+                       unsigned int op:6;
+               } m;
+               struct {                                /* branch format */
+                                int disp:21;
+                       unsigned int ra:5;
+                       unsigned int op:6;
+               } b;
+       } insn;
+
+       insn.code = instruction;
+       switch (insn.common.op) {
+       /*
+        * memory-format branches.  all unconditional.
+        */
+       case 0x1a:                      /* JMP/RET/JSR/JSR_C; memory format */
+               val = branch_unconditional;
+
+               /*
+                * Target PC is (contents of instruction's "RB") & ~3.
+                */
+               *target = read_register(insn.m.rb) & ~3;
+               break;
+
+       /*
+        * branch-format branches.  conditional unless otherwise noted.
+        */
+       case 0x30:                      /* BR; unconditional*/
+       case 0x31:                      /* FBEQ */
+       case 0x32:                      /* FBLT */
+       case 0x33:                      /* FBLE */
+       case 0x34:                      /* BSR; unconditional */
+       case 0x35:                      /* FBNE */
+       case 0x36:                      /* FBGE */
+       case 0x37:                      /* FBGT */
+       case 0x38:                      /* BLBC */
+       case 0x39:                      /* BEQ */
+       case 0x3a:                      /* BLT */
+       case 0x3b:                      /* BLE */
+       case 0x3c:                      /* BLBS */
+       case 0x3d:                      /* BNE */
+       case 0x3e:                      /* BGE */
+       case 0x3f:                      /* BGT */
+
+               if (insn.b.op == 0x30 || insn.b.op == 0x34)
+                       val = branch_unconditional;
+               else
+                       val = branch_conditional;
+               
+               /*
+                * Branch format is easy.
+                * Target PC is (new PC) + (4 * sign-ext(displacement)).
+                */
+               offset = 4 + (4 * insn.b.disp);
+               *target = addr + offset;
+               break;
+
+
+       default:
+               val = not_branch;
+               break;
+       }
+
+       return val;
+}
+#endif
diff --git a/gnu/usr.bin/binutils/gdb/alphaobsd-nat.c b/gnu/usr.bin/binutils/gdb/alphaobsd-nat.c
new file mode 100644 (file)
index 0000000..128faa1
--- /dev/null
@@ -0,0 +1,268 @@
+/* Low level Alpha interface, for GDB when running native.
+   Copyright 1993, 1995 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.  */
+
+#include "defs.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "target.h"
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+#include <machine/frame.h>
+#include <machine/pcb.h>
+#include <string.h>
+
+/* Size of elements in jmpbuf */
+
+#define JB_ELEMENT_SIZE 8
+
+/* The definition for JB_PC in machine/reg.h is wrong.
+   And we can't get at the correct definition in setjmp.h as it is
+   not always available (eg. if _POSIX_SOURCE is defined which is the
+   default). As the defintion is unlikely to change (see comment
+   in <setjmp.h>, define the correct value here.  */
+
+#undef JB_PC
+#define JB_PC 2
+
+/* Figure out where the longjmp will land.
+   We expect the first arg to be a pointer to the jmp_buf structure from which
+   we extract the pc (JB_PC) that we will land at.  The pc is copied into PC.
+   This routine returns true on success. */
+
+int
+get_longjmp_target (pc)
+     CORE_ADDR *pc;
+{
+  CORE_ADDR jb_addr;
+  char raw_buffer[MAX_REGISTER_RAW_SIZE];
+
+  jb_addr = read_register(A0_REGNUM);
+
+  if (target_read_memory(jb_addr + JB_PC * JB_ELEMENT_SIZE, raw_buffer,
+                        sizeof(CORE_ADDR)))
+    return 0;
+
+  *pc = extract_address (raw_buffer, sizeof(CORE_ADDR));
+  return 1;
+}
+
+/* Extract the register values out of the core file and store
+   them where `read_register' will find them.
+
+   CORE_REG_SECT points to the register values themselves, read into memory.
+   CORE_REG_SIZE is the size of that area.
+   WHICH says which set of registers we are handling (0 = int, 2 = float
+         on machines where they are discontiguous).
+   REG_ADDR is the offset from u.u_ar0 to the register values relative to
+            core_reg_sect.  This is used with old-fashioned core files to
+           locate the registers in a large upage-plus-stack ".reg" section.
+           Original upage address X is at location core_reg_sect+x+reg_addr.
+ */
+
+#define oi(name) \
+           offsetof(struct md_coredump, md_tf.tf_regs[__CONCAT(FRAME_,name)])
+#define of(num) \
+           offsetof(struct md_coredump, md_fpstate.fpr_regs[num])
+
+void
+fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr)
+     char *core_reg_sect;
+     unsigned core_reg_size;
+     int which;
+     unsigned reg_addr;
+{
+  register int regno;
+  register int addr;
+  int bad_reg = -1;
+  static char zerobuf[MAX_REGISTER_RAW_SIZE] = {0};
+  int regoff[NUM_REGS] = {
+      oi(V0),  oi(T0),  oi(T1),  oi(T2),  oi(T3),  oi(T4),  oi(T5),  oi(T6),
+      oi(T7),  oi(S0),  oi(S1),  oi(S2),  oi(S3),  oi(S4),  oi(S5),  oi(S6),
+      oi(A0),  oi(A1),  oi(A2),  oi(A3),  oi(A4),  oi(A5),  oi(T8),  oi(T9), 
+      oi(T10), oi(T11), oi(RA),  oi(T12), oi(AT),  oi(GP),  oi(SP),  -1,
+      of(0),   of(1),   of(2),   of(3),   of(4),   of(5),   of(6),   of(7),
+      of(8),   of(9),   of(10),  of(11),  of(12),  of(13),  of(14),  of(15),
+      of(16),  of(17),  of(18),  of(19),  of(20),  of(21),  of(22),  of(23),  
+      of(24),  of(25),  of(26),  of(27),  of(28),  of(29),  of(30),  of(31),
+      oi(PC),  -1,
+  };
+
+  for (regno = 0; regno < NUM_REGS; regno++)
+    {
+      if (CANNOT_FETCH_REGISTER (regno))
+       {
+         supply_register (regno, zerobuf);
+         continue;
+       }
+      addr = regoff[regno];
+      if (addr < 0 || addr >= core_reg_size)
+       {
+         if (bad_reg < 0)
+           bad_reg = regno;
+       }
+      else
+       {
+         supply_register (regno, core_reg_sect + addr);
+       }
+    }
+  if (bad_reg >= 0)
+    {
+      error ("Register %s not found in core file.", reg_names[bad_reg]);
+    }
+}
+
+register_t
+rrf_to_register(regno, reg, fpreg)
+       int regno;
+       struct reg *reg;
+       struct fpreg *fpreg;
+{
+
+       if (regno < 0)
+               abort();
+       else if (regno < FP0_REGNUM)
+               return (reg->r_regs[regno]);
+       else if (regno == PC_REGNUM)
+               return (reg->r_regs[R_ZERO]);
+       else if (regno >= FP0_REGNUM)
+               return (fpreg->fpr_regs[regno - FP0_REGNUM]);
+       else
+               abort();
+}
+
+void
+fetch_inferior_registers (regno)
+       int regno;
+{
+       struct reg reg;
+       struct fpreg fpreg;
+       register_t regval;
+       static char zerobuf[MAX_REGISTER_RAW_SIZE] = {0};
+       char *rp;
+
+       ptrace(PT_GETREGS, inferior_pid, (PTRACE_ARG3_TYPE)&reg, 0);
+       ptrace(PT_GETFPREGS, inferior_pid, (PTRACE_ARG3_TYPE)&fpreg, 0);
+
+       if (regno < 0) {
+               for (regno = 0; regno < NUM_REGS; regno++) {
+                       if (CANNOT_FETCH_REGISTER (regno))
+                               rp = zerobuf;
+                       else {
+                               regval = rrf_to_register(regno, &reg, &fpreg);
+                               rp = (char *)&regval;
+                       }
+                       supply_register(regno, rp);
+               }
+       } else {
+               if (CANNOT_FETCH_REGISTER (regno))
+                       rp = zerobuf;
+               else {
+                       regval = rrf_to_register(regno, &reg, &fpreg);
+                       rp = (char *)&regval;
+               }
+
+               supply_register(regno, rp);
+       }
+}
+
+void
+register_into_rrf(val, regno, reg, fpreg)
+       register_t val;
+       int regno;
+       struct reg *reg;
+       struct fpreg *fpreg;
+{
+
+       if (regno < 0)
+               abort();
+       else if (regno < FP0_REGNUM)
+               reg->r_regs[regno] = val;
+       else if (regno == PC_REGNUM)
+               reg->r_regs[R_ZERO] = val;
+       else if (regno >= FP0_REGNUM)
+               fpreg->fpr_regs[regno - FP0_REGNUM] = val;
+       else
+               abort();
+}
+
+void
+store_inferior_registers (regno)
+       int regno;
+{
+       struct reg reg;
+       struct fpreg fpreg;
+       register_t regval;
+
+       if (regno < 0) {
+               for (regno = 0; regno < NUM_REGS; regno++) {
+                       if (CANNOT_STORE_REGISTER (regno))
+                               continue;
+       
+                       if (REGISTER_RAW_SIZE (regno) != sizeof regval)
+                               abort();
+                       memcpy(&regval, &registers[REGISTER_BYTE (regno)],
+                           REGISTER_RAW_SIZE (regno));
+                       register_into_rrf(regval, regno, &reg, &fpreg);
+               }
+       } else {
+               ptrace(PT_GETREGS, inferior_pid, (PTRACE_ARG3_TYPE)&reg, 0);
+               ptrace(PT_GETFPREGS, inferior_pid, (PTRACE_ARG3_TYPE)&fpreg, 0);
+               
+               memcpy(&regval, &registers[REGISTER_BYTE (regno)],
+                   REGISTER_RAW_SIZE (regno));
+               register_into_rrf(regval, regno, &reg, &fpreg);
+       }
+       
+       ptrace(PT_SETREGS, inferior_pid, (PTRACE_ARG3_TYPE)&reg, 0);
+       ptrace(PT_SETFPREGS, inferior_pid, (PTRACE_ARG3_TYPE)&fpreg, 0);
+}
+
+void 
+child_resume (pid, step, signal)
+       int pid;
+       int step;
+       enum target_signal signal;
+{    
+
+  errno = 0;
+
+  if (pid == -1)
+    /* Resume all threads.  */
+    /* I think this only gets used in the non-threaded case, where "resume
+       all threads" and "resume inferior_pid" are the same.  */
+    pid = inferior_pid;
+
+  /* An address of (PTRACE_ARG3_TYPE)1 tells ptrace to continue from where
+     it was.  (If GDB wanted it to start some other way, we have already
+     written a new PC value to the child.)
+
+     If this system does not support PT_STEP, a higher level function will
+     have called single_step() to transmute the step request into a
+     continue request (by setting breakpoints on all possible successor
+     instructions), so we don't have to worry about that here.  */
+
+  if (step)
+       abort();
+  else
+    ptrace (PT_CONTINUE, pid, (PTRACE_ARG3_TYPE) 1,
+           target_signal_to_host (signal));
+
+  if (errno)
+    perror_with_name ("ptrace");
+}
diff --git a/gnu/usr.bin/binutils/gdb/config/alpha/nm-obsd.h b/gnu/usr.bin/binutils/gdb/config/alpha/nm-obsd.h
new file mode 100644 (file)
index 0000000..322189d
--- /dev/null
@@ -0,0 +1,43 @@
+/* Native definitions for alpha running OSF/1.
+   Copyright (C) 1993, 1994 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.  */
+
+/* Figure out where the longjmp will land.  We expect that we have just entered
+   longjmp and haven't yet setup the stack frame, so the args are still in the
+   argument regs.  A0_REGNUM points at the jmp_buf structure from which we
+   extract the pc (JB_PC) that we will land at.  The pc is copied into ADDR.
+   This routine returns true on success */
+
+#define GET_LONGJMP_TARGET(ADDR) get_longjmp_target(ADDR)
+extern int
+get_longjmp_target PARAMS ((CORE_ADDR *));
+
+/* #include "nm-obsd.h" */
+#include <machine/alpha_cpu.h>
+
+/* unnneeded here. */
+#define PTRACE_ARG3_TYPE char*
+
+#define PTRACE_XFER_TYPE int
+
+/* The alpha does not step over a breakpoint, the manpage is lying again.  */
+
+#define CANNOT_STEP_BREAKPOINT /* ??? */
+
+#define        FETCH_INFERIOR_REGISTERS
+#define        CHILD_RESUME
diff --git a/gnu/usr.bin/binutils/gdb/config/alpha/obsd.mh b/gnu/usr.bin/binutils/gdb/config/alpha/obsd.mh
new file mode 100644 (file)
index 0000000..50cb237
--- /dev/null
@@ -0,0 +1,8 @@
+# Host: Little-endian Alpha running OpenBSD/Alpha
+XDEPFILES= 
+XM_FILE= xm-alpha.h
+NAT_FILE= nm-obsd.h
+NATDEPFILES= infptrace.o inftarg.o corelow.o alphaobsd-nat.o fork-child.o
+
+MMALLOC = 
+MMALLOC_DISABLE = -DNO_MMALLOC 
diff --git a/gnu/usr.bin/binutils/gdb/config/alpha/obsd.mt b/gnu/usr.bin/binutils/gdb/config/alpha/obsd.mt
new file mode 100644 (file)
index 0000000..32a32d4
--- /dev/null
@@ -0,0 +1,3 @@
+# Target: Little-endian Alpha
+TDEPFILES= alpha-tdep.o
+TM_FILE= tm-alphaobsd.h
diff --git a/gnu/usr.bin/binutils/gdb/config/alpha/tm-alphaobsd.h b/gnu/usr.bin/binutils/gdb/config/alpha/tm-alphaobsd.h
new file mode 100644 (file)
index 0000000..86ac4f9
--- /dev/null
@@ -0,0 +1,10 @@
+/* GDB target definitions for Alpha running OpenBSD. */
+
+#include "alpha/tm-alpha.h"
+
+#undef START_INFERIOR_TRAPS_EXPECTED
+#define START_INFERIOR_TRAPS_EXPECTED 2
+
+#undef NO_SINGLE_STEP
+#define NO_SINGLE_STEP
+#undef CANNOT_STEP_BREAKPOINT 
diff --git a/gnu/usr.bin/binutils/gdb/config/alpha/xm-alphaobsd.h b/gnu/usr.bin/binutils/gdb/config/alpha/xm-alphaobsd.h
new file mode 100644 (file)
index 0000000..08024bb
--- /dev/null
@@ -0,0 +1,27 @@
+/* Host definitions for GDB running on an alpha under OpenBSD/alpha.
+   Copyright (C) 1992, 1993 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.  */
+
+#if !defined (HOST_BYTE_ORDER)
+#define HOST_BYTE_ORDER LITTLE_ENDIAN
+#endif
+
+/* The alpha has no siginterrupt routine.  */
+#define NO_SIGINTERRUPT
+
+#define HAVE_TERMIOS