2005-05-23 Orjan Friberg <orjanf@axis.com>
authorOrjan Friberg <orjanf@axis.com>
Mon, 23 May 2005 11:20:07 +0000 (11:20 +0000)
committerOrjan Friberg <orjanf@axis.com>
Mon, 23 May 2005 11:20:07 +0000 (11:20 +0000)
* linux-cris-low.c: New file with support for CRIS.
* linux-crisv32-low.c: Ditto for CRISv32.
* Makefile.in (SFILES): Add linux-cris-low.c, linux-crisv32-low.c.
(clean): Add reg-cris.c and reg-crisv32.c.
Add linux-cris-low.o, linux-crisv32-low.o, reg-cris.o, reg-cris.c,
reg-crisv32.o, and reg-crisv32.c to make rules.
* configure.srv: Add cris-*-linux* and crisv32-*-linux* to list of
recognized targets.

gdb/gdbserver/ChangeLog
gdb/gdbserver/Makefile.in
gdb/gdbserver/configure.srv
gdb/gdbserver/linux-cris-low.c [new file with mode: 0644]
gdb/gdbserver/linux-crisv32-low.c [new file with mode: 0644]

index 90aa0d22a8b5f2e73d94c87452f40a2d1e77017a..248367a44a58a384cf3b7247bc7e8bcc5a519037 100644 (file)
@@ -1,3 +1,15 @@
+2005-05-23  Orjan Friberg  <orjanf@axis.com>
+
+       * linux-cris-low.c: New file with support for CRIS.
+       * linux-crisv32-low.c: Ditto for CRISv32.
+       * Makefile.in (SFILES): Add linux-cris-low.c, linux-crisv32-low.c.
+       (clean): Add reg-cris.c and reg-crisv32.c.
+       Add linux-cris-low.o, linux-crisv32-low.o, reg-cris.o, reg-cris.c, 
+       reg-crisv32.o, and reg-crisv32.c to make rules.
+       * configure.srv: Add cris-*-linux* and crisv32-*-linux* to list of
+       recognized targets.
+
+
 2005-05-16  Ulrich Weigand  <uweigand@de.ibm.com>
 
        * linux-low.c (fetch_register): Ensure buffer size is a multiple
index 6d64406d8676fd928da1e8fcc13fd01064e8dcd7..d4e0c9e253a66132b3f785853845e7a5533f54d8 100644 (file)
@@ -118,7 +118,8 @@ SFILES=     $(srcdir)/gdbreplay.c $(srcdir)/inferiors.c \
        $(srcdir)/mem-break.c $(srcdir)/proc-service.c $(srcdir)/regcache.c \
        $(srcdir)/remote-utils.c $(srcdir)/server.c $(srcdir)/target.c \
        $(srcdir)/thread-db.c $(srcdir)/utils.c \
-       $(srcdir)/linux-arm-low.c $(srcdir)/linux-i386-low.c \
+       $(srcdir)/linux-arm-low.c $(srcdir)/linux-cris-low.c \
+       $(srcdir)/linux-crisv32-low.c $(srcdir)/linux-i386-low.c \
        $(srcdir)/i387-fp.c \
        $(srcdir)/linux-ia64-low.c $(srcdir)/linux-low.c \
        $(srcdir)/linux-m32r-low.c \
@@ -201,6 +202,7 @@ clean:
        rm -f gdbserver gdbreplay core make.log
        rm -f reg-arm.c reg-i386.c reg-ia64.c reg-m32r.c reg-m68k.c reg-mips.c
        rm -f reg-ppc.c reg-sh.c reg-x86-64.c reg-i386-linux.c
+       rm -f reg-cris.c reg-crisv32.c
 
 maintainer-clean realclean distclean: clean
        rm -f nm.h tm.h xm.h config.status config.h stamp-h config.log
@@ -262,6 +264,8 @@ linux-low.o: linux-low.c $(linux_low_h) $(server_h)
        $(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $< @USE_THREAD_DB@
 
 linux-arm-low.o: linux-arm-low.c $(linux_low_h) $(server_h)
+linux-cris-low.o: linux-cris-low.c $(linux_low_h) $(server_h)
+linux-crisv32-low.o: linux-crisv32-low.c $(linux_low_h) $(server_h)
 linux-i386-low.o: linux-i386-low.c $(linux_low_h) $(server_h)
 linux-ia64-low.o: linux-ia64-low.c $(linux_low_h) $(server_h)
 linux-m32r-low.o: linux-m32r-low.c $(linux_low_h) $(server_h)
@@ -274,6 +278,12 @@ linux-x86-64-low.o: linux-x86-64-low.c $(linux_low_h) $(server_h)
 reg-arm.o : reg-arm.c $(regdef_h)
 reg-arm.c : $(srcdir)/../regformats/reg-arm.dat $(regdat_sh)
        sh $(regdat_sh) $(srcdir)/../regformats/reg-arm.dat reg-arm.c
+reg-cris.o : reg-cris.c $(regdef_h)
+reg-cris.c : $(srcdir)/../regformats/reg-cris.dat $(regdat_sh)
+       sh $(regdat_sh) $(srcdir)/../regformats/reg-cris.dat reg-cris.c
+reg-crisv32.o : reg-crisv32.c $(regdef_h)
+reg-crisv32.c : $(srcdir)/../regformats/reg-crisv32.dat $(regdat_sh)
+       sh $(regdat_sh) $(srcdir)/../regformats/reg-crisv32.dat reg-crisv32.c
 reg-i386.o : reg-i386.c $(regdef_h)
 reg-i386.c : $(srcdir)/../regformats/reg-i386.dat $(regdat_sh)
        sh $(regdat_sh) $(srcdir)/../regformats/reg-i386.dat reg-i386.c
index 943e2289e358bbefa0ff917081d1f7e0f7ac04ad..648b202c9a16aa29d10d5d437c50a6e085843363 100644 (file)
@@ -23,6 +23,16 @@ case "${target}" in
                        srv_linux_usrregs=yes
                        srv_linux_thread_db=yes
                        ;;
+  crisv32-*-linux*)    srv_regobj=reg-crisv32.o
+                       srv_tgtobj="linux-low.o linux-crisv32-low.o"
+                       srv_linux_regsets=yes
+                       srv_linux_thread_db=yes
+                       ;;
+  cris-*-linux*)       srv_regobj=reg-cris.o
+                       srv_tgtobj="linux-low.o linux-cris-low.o"
+                       srv_linux_usrregs=yes
+                       srv_linux_thread_db=yes
+                       ;;
   i[34567]86-*-linux*) srv_regobj=reg-i386-linux.o
                        srv_tgtobj="linux-low.o linux-i386-low.o i387-fp.o"
                        srv_linux_usrregs=yes
diff --git a/gdb/gdbserver/linux-cris-low.c b/gdb/gdbserver/linux-cris-low.c
new file mode 100644 (file)
index 0000000..7777685
--- /dev/null
@@ -0,0 +1,124 @@
+/* GNU/Linux/CRIS specific low level interface, for the remote server for GDB.
+   Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "server.h"
+#include "linux-low.h"
+#include <sys/ptrace.h>
+
+/* CRISv10 */
+#define cris_num_regs 32
+
+/* Locations need to match <include/asm/arch/ptrace.h>.  */
+static int cris_regmap[] = {
+  15*4, 14*4, 13*4, 12*4,
+  11*4, 10*4, 9*4, 8*4,
+  7*4, 6*4, 5*4, 4*4,
+  3*4, 2*4, 23*4, 19*4,
+
+  -1, -1, -1, -1,
+  -1, 17*4, -1, 16*4,
+  -1, -1, -1, 18*4,
+  -1, 17*4, -1, -1
+  
+};
+
+static int
+cris_cannot_store_register (int regno)
+{
+  if (cris_regmap[regno] == -1)
+    return 1;
+  
+  return (regno >= cris_num_regs);
+}
+
+static int
+cris_cannot_fetch_register (int regno)
+{
+  if (cris_regmap[regno] == -1)
+    return 1;
+
+  return (regno >= cris_num_regs);
+}
+
+extern int debug_threads;
+
+static CORE_ADDR
+cris_get_pc (void)
+{
+  unsigned long pc;
+  collect_register_by_name ("pc", &pc);
+  if (debug_threads)
+    fprintf (stderr, "stop pc is %08lx\n", pc);
+  return pc;
+}
+
+static void
+cris_set_pc (CORE_ADDR pc)
+{
+  unsigned long newpc = pc;
+  supply_register_by_name ("pc", &newpc);
+}
+
+static const unsigned short cris_breakpoint = 0xe938;
+#define cris_breakpoint_len 2
+
+static int
+cris_breakpoint_at (CORE_ADDR where)
+{
+  unsigned short insn;
+
+  (*the_target->read_memory) (where, (char *) &insn, cris_breakpoint_len);
+  if (insn == cris_breakpoint)
+    return 1;
+
+  /* If necessary, recognize more trap instructions here.  GDB only uses the
+     one.  */
+  return 0;
+}
+
+/* We only place breakpoints in empty marker functions, and thread locking
+   is outside of the function.  So rather than importing software single-step,
+   we can just run until exit.  */
+static CORE_ADDR
+cris_reinsert_addr (void)
+{
+  unsigned long pc;
+  collect_register_by_name ("srp", &pc);
+  return pc;
+}
+
+struct linux_target_ops the_low_target = {
+  cris_num_regs,
+  cris_regmap,
+  cris_cannot_fetch_register,
+  cris_cannot_store_register,
+  cris_get_pc,
+  cris_set_pc,
+  (const char *) &cris_breakpoint,
+  cris_breakpoint_len,
+  cris_reinsert_addr,
+  0,
+  cris_breakpoint_at,
+  0,
+  0,
+  0,
+  0,
+};
diff --git a/gdb/gdbserver/linux-crisv32-low.c b/gdb/gdbserver/linux-crisv32-low.c
new file mode 100644 (file)
index 0000000..21940b3
--- /dev/null
@@ -0,0 +1,379 @@
+/* GNU/Linux/CRIS specific low level interface, for the remote server for GDB.
+   Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "server.h"
+#include "linux-low.h"
+#include <sys/ptrace.h>
+
+/* CRISv32 */
+#define cris_num_regs 49
+
+/* Note: Ignoring USP (having the stack pointer in two locations causes trouble
+   without any significant gain).  */
+
+/* Locations need to match <include/asm/arch/ptrace.h>.  */
+static int cris_regmap[] = {
+  1*4, 2*4, 3*4, 4*4,
+  5*4, 6*4, 7*4, 8*4,
+  9*4, 10*4, 11*4, 12*4,
+  13*4, 14*4, 24*4, 15*4,
+
+  -1, -1, -1, 16*4,
+  -1, 22*4, 23*4, 17*4,
+  -1, -1, 21*4, 20*4,
+  -1, 19*4, -1, 18*4,
+
+  25*4,
+
+  26*4, -1,   -1,   29*4, 
+  30*4, 31*4, 32*4, 33*4,
+  34*4, 35*4, 36*4, 37*4,
+  38*4, 39*4, 40*4, -1
+  
+};
+
+extern int debug_threads;
+
+static CORE_ADDR
+cris_get_pc (void)
+{
+  unsigned long pc;
+  collect_register_by_name ("pc", &pc);
+  if (debug_threads)
+    fprintf (stderr, "stop pc is %08lx\n", pc);
+  return pc;
+}
+
+static void
+cris_set_pc (CORE_ADDR pc)
+{
+  unsigned long newpc = pc;
+  supply_register_by_name ("pc", &newpc);
+}
+
+static const unsigned short cris_breakpoint = 0xe938;
+#define cris_breakpoint_len 2
+
+static int
+cris_breakpoint_at (CORE_ADDR where)
+{
+  unsigned short insn;
+
+  (*the_target->read_memory) (where, (char *) &insn, cris_breakpoint_len);
+  if (insn == cris_breakpoint)
+    return 1;
+
+  /* If necessary, recognize more trap instructions here.  GDB only uses the
+     one.  */
+  return 0;
+}
+
+/* We only place breakpoints in empty marker functions, and thread locking
+   is outside of the function.  So rather than importing software single-step,
+   we can just run until exit.  */
+
+/* FIXME: This function should not be needed, since we have PTRACE_SINGLESTEP
+   for CRISv32.  Without it, td_ta_event_getmsg in thread_db_create_event
+   will fail when debugging multi-threaded applications.  */
+
+static CORE_ADDR
+cris_reinsert_addr (void)
+{
+  unsigned long pc;
+  collect_register_by_name ("srp", &pc);
+  return pc;
+}
+
+static void
+cris_write_data_breakpoint (int bp, unsigned long start, unsigned long end)
+{
+  switch (bp)
+    {
+    case 0:
+      supply_register_by_name ("s3", &start);
+      supply_register_by_name ("s4", &end);
+      break;
+    case 1:
+      supply_register_by_name ("s5", &start);
+      supply_register_by_name ("s6", &end);
+      break;
+    case 2:
+      supply_register_by_name ("s7", &start);
+      supply_register_by_name ("s8", &end);
+      break;
+    case 3:
+      supply_register_by_name ("s9", &start);
+      supply_register_by_name ("s10", &end);
+      break;
+    case 4:
+      supply_register_by_name ("s11", &start);
+      supply_register_by_name ("s12", &end);
+      break;
+    case 5:
+      supply_register_by_name ("s13", &start);
+      supply_register_by_name ("s14", &end);
+      break;
+    }
+}
+
+static int
+cris_insert_watchpoint (char type, CORE_ADDR addr, int len)
+{
+  int bp;
+  unsigned long bp_ctrl;
+  unsigned long start, end;
+  unsigned long ccs;
+  
+  /* Breakpoint/watchpoint types (GDB terminology):
+     0 = memory breakpoint for instructions
+     (not supported; done via memory write instead)
+     1 = hardware breakpoint for instructions (not supported)
+     2 = write watchpoint (supported)
+     3 = read watchpoint (supported)
+     4 = access watchpoint (supported).  */
+  
+  if (type < '2' || type > '4') 
+    {
+      /* Unsupported.  */
+      return 1;
+    }
+
+  /* Read watchpoints are set as access watchpoints, because of GDB's
+     inability to deal with pure read watchpoints.  */
+  if (type == '3')
+    type = '4';
+
+  /* Get the configuration register.  */
+  collect_register_by_name ("s0", &bp_ctrl);
+
+  /* The watchpoint allocation scheme is the simplest possible.
+     For example, if a region is watched for read and
+     a write watch is requested, a new watchpoint will
+     be used.  Also, if a watch for a region that is already
+     covered by one or more existing watchpoints, a new
+     watchpoint will be used.  */
+    
+  /* First, find a free data watchpoint.  */
+  for (bp = 0; bp < 6; bp++)
+    {
+      /* Each data watchpoint's control registers occupy 2 bits
+        (hence the 3), starting at bit 2 for D0 (hence the 2)
+        with 4 bits between for each watchpoint (yes, the 4).  */
+      if (!(bp_ctrl & (0x3 << (2 + (bp * 4))))) 
+       break;
+    }
+    
+  if (bp > 5)
+    {
+      /* We're out of watchpoints.  */
+      return -1;
+    }
+
+  /* Configure the control register first.  */
+  if (type == '3' || type == '4')
+    {
+      /* Trigger on read.  */
+      bp_ctrl |= (1 << (2 + bp * 4));
+    }
+  if (type == '2' || type == '4') 
+    {
+      /* Trigger on write.  */
+      bp_ctrl |= (2 << (2 + bp * 4));
+    }
+  
+  /* Setup the configuration register.  */
+  supply_register_by_name ("s0", &bp_ctrl);
+  
+  /* Setup the range.  */
+  start = addr;
+  end = addr + len - 1;
+
+  /* Configure the watchpoint register.  */
+  cris_write_data_breakpoint (bp, start, end);
+
+  collect_register_by_name ("ccs", &ccs);
+  /* Set the S1 flag to enable watchpoints.  */
+  ccs |= (1 << 19);
+  supply_register_by_name ("ccs", &ccs);
+
+  return 0;
+}
+
+static int
+cris_remove_watchpoint (char type, CORE_ADDR addr, int len)
+{
+  int bp;
+  unsigned long bp_ctrl;
+  unsigned long start, end;
+  
+  /* Breakpoint/watchpoint types:
+     0 = memory breakpoint for instructions
+     (not supported; done via memory write instead)
+     1 = hardware breakpoint for instructions (not supported)
+     2 = write watchpoint (supported)
+     3 = read watchpoint (supported)
+     4 = access watchpoint (supported).  */
+  if (type < '2' || type > '4')
+    return -1;
+  
+  /* Read watchpoints are set as access watchpoints, because of GDB's
+     inability to deal with pure read watchpoints.  */
+  if (type == '3')
+    type = '4';
+  
+  /* Get the configuration register.  */
+  collect_register_by_name ("s0", &bp_ctrl);
+
+  /* Try to find a watchpoint that is configured for the
+     specified range, then check that read/write also matches.  */
+  
+  /* Ugly pointer arithmetic, since I cannot rely on a
+     single switch (addr) as there may be several watchpoints with
+     the same start address for example.  */
+
+  unsigned long bp_d_regs[12];
+
+  /* Get all range registers to simplify search.  */
+  collect_register_by_name ("s3", &bp_d_regs[0]);
+  collect_register_by_name ("s4", &bp_d_regs[1]);
+  collect_register_by_name ("s5", &bp_d_regs[2]);
+  collect_register_by_name ("s6", &bp_d_regs[3]);
+  collect_register_by_name ("s7", &bp_d_regs[4]);
+  collect_register_by_name ("s8", &bp_d_regs[5]);
+  collect_register_by_name ("s9", &bp_d_regs[6]);
+  collect_register_by_name ("s10", &bp_d_regs[7]);
+  collect_register_by_name ("s11", &bp_d_regs[8]);
+  collect_register_by_name ("s12", &bp_d_regs[9]);
+  collect_register_by_name ("s13", &bp_d_regs[10]);
+  collect_register_by_name ("s14", &bp_d_regs[11]);
+
+  for (bp = 0; bp < 6; bp++) 
+    {
+      if (bp_d_regs[bp * 2] == addr 
+         && bp_d_regs[bp * 2 + 1] == (addr + len - 1)) {
+       /* Matching range.  */
+       int bitpos = 2 + bp * 4;
+       int rw_bits;
+      
+       /* Read/write bits for this BP.  */
+       rw_bits = (bp_ctrl & (0x3 << bitpos)) >> bitpos;
+      
+       if ((type == '3' && rw_bits == 0x1)
+           || (type == '2' && rw_bits == 0x2) 
+           || (type == '4' && rw_bits == 0x3))
+         {
+           /* Read/write matched.  */
+           break;
+         }
+      }
+    }
+    
+  if (bp > 5)
+    {
+      /* No watchpoint matched.  */
+      return -1;
+    }
+    
+  /* Found a matching watchpoint.  Now, deconfigure it by
+     both disabling read/write in bp_ctrl and zeroing its
+     start/end addresses.  */
+  bp_ctrl &= ~(3 << (2 + (bp * 4)));
+  /* Setup the configuration register.  */
+  supply_register_by_name ("s0", &bp_ctrl);
+
+  start = end = 0;
+  /* Configure the watchpoint register.  */
+  cris_write_data_breakpoint (bp, start, end);
+
+  /* Note that we don't clear the S1 flag here.  It's done when continuing.  */
+  return 0;
+}
+
+static int
+cris_stopped_by_watchpoint (void)
+{
+  unsigned long exs;
+
+  collect_register_by_name ("exs", &exs);
+
+  return (((exs & 0xff00) >> 8) == 0xc);
+}
+
+static CORE_ADDR
+cris_stopped_data_address (void)
+{
+  unsigned long eda;
+
+  collect_register_by_name ("eda", &eda);
+
+  /* FIXME: Possibly adjust to match watched range.  */
+  return eda;
+}
+
+static void
+cris_fill_gregset (void *buf)
+{
+  int i;
+
+  for (i = 0; i < cris_num_regs; i++)
+    {
+      if (cris_regmap[i] != -1)
+       collect_register (i, ((char *) buf) + cris_regmap[i]);
+    }
+}
+
+static void
+cris_store_gregset (const void *buf)
+{
+  int i;
+
+  for (i = 0; i < cris_num_regs; i++)
+    {
+      if (cris_regmap[i] != -1)
+       supply_register (i, ((char *) buf) + cris_regmap[i]);
+    }
+}
+
+typedef unsigned long elf_gregset_t[cris_num_regs];
+
+struct regset_info target_regsets[] = {
+  { PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
+    GENERAL_REGS, cris_fill_gregset, cris_store_gregset },
+  { 0, 0, -1, -1, NULL, NULL }
+};
+
+struct linux_target_ops the_low_target = {
+  -1,
+  NULL,
+  NULL,
+  NULL,
+  cris_get_pc,
+  cris_set_pc,
+  (const char *) &cris_breakpoint,
+  cris_breakpoint_len,
+  cris_reinsert_addr,
+  0,
+  cris_breakpoint_at,
+  cris_insert_watchpoint,
+  cris_remove_watchpoint,
+  cris_stopped_by_watchpoint,
+  cris_stopped_data_address,
+};