This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gdbserver] MIPS64 gdbserver port


Been meaning to do this for ages.  This is a fairly straightforward port of
gdbserver to mips64-none-linux-gnu.  It works no matter which ABI it's
configured for.  It's hairy in places, but all the hair is the same as
in the native mips64-linux GDB.

Like native GDB, an o32 or n32 gdbserver won't quite be able to handle n64
inferiors, due to problems reading memory (fixable). And there's at least
one thread_db problem if you mix ABIs.  So my recommendation is still not
to.  An n64 gdbserver might work for all three; I'd have to do some more
testing.

I'll check this in when the previous patches from today are ready to go
in.  This version is somewhat simplified over previous versions I've done,
in that a MIPS64 gdbserver always returns 64-bit register information,
even if the inferior is o32 - in fact gdbserver doesn't even _know_ what
ABI the inferior is using, and has no easy way to find out!  So the
patches to correctly handle either register layout in GDB are quite
useful.

Tested manually on mips64-none-linux-gnu (n32, o32) and mips-none-linux-gnu
(o32).

Done for today.  Whew!

-- 
Daniel Jacobowitz
CodeSourcery

2006-11-09  Daniel Jacobowitz  <dan@codesourcery.com>

	* Makefile.in (clean): Remove reg-mips64.c.
	(reg-mips64.c, reg-mips64.o): New rules.
	* configure.srv: Handle mips64.  Include regset support for mips.
	* linux-mips-low.c (union mips_register): New.
	(mips_get_pc, mips_set_pc, mips_reinsert_addr): Use it.
	(mips_breakpoint, mips_breakpoint_at): Use int.
	(mips_collect_register, mips_supply_register)
	(mips_collect_register_32bit, mips_supply_register_32bit)
	(mips_fill_gregset, mips_store_gregset, mips_fill_fpregset)
	(mips_store_fpregset, target_regsets): New.
	* thread-db.c (thread_db_get_tls_address): Use uintptr_t.

2006-11-09  Daniel Jacobowitz  <dan@codesourcery.com>

	* regformats/reg-mips64.dat: New file.

---
 gdb/gdbserver/Makefile.in      |    5 -
 gdb/gdbserver/configure.srv    |    7 +
 gdb/gdbserver/linux-mips-low.c |  184 ++++++++++++++++++++++++++++++++++++++---
 gdb/gdbserver/thread-db.c      |   11 +-
 gdb/regformats/reg-mips64.dat  |  112 ++++++++++++++++++++++++
 5 files changed, 305 insertions(+), 14 deletions(-)

Index: src/gdb/gdbserver/Makefile.in
===================================================================
--- src.orig/gdb/gdbserver/Makefile.in	2006-11-09 11:21:22.000000000 -0500
+++ src/gdb/gdbserver/Makefile.in	2006-11-09 11:21:41.000000000 -0500
@@ -206,7 +206,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 reg-x86-64-linux.c
+	rm -f reg-cris.c reg-crisv32.c reg-x86-64-linux.c reg-mips64.c
 
 maintainer-clean realclean distclean: clean
 	rm -f nm.h tm.h xm.h config.status config.h stamp-h config.log
@@ -316,6 +316,9 @@ reg-m68k.c : $(srcdir)/../regformats/reg
 reg-mips.o : reg-mips.c $(regdef_h)
 reg-mips.c : $(srcdir)/../regformats/reg-mips.dat $(regdat_sh)
 	sh $(regdat_sh) $(srcdir)/../regformats/reg-mips.dat reg-mips.c
+reg-mips64.o : reg-mips64.c $(regdef_h)
+reg-mips64.c : $(srcdir)/../regformats/reg-mips64.dat $(regdat_sh)
+	sh $(regdat_sh) $(srcdir)/../regformats/reg-mips64.dat reg-mips64.c
 reg-ppc.o : reg-ppc.c $(regdef_h)
 reg-ppc.c : $(srcdir)/../regformats/reg-ppc.dat $(regdat_sh)
 	sh $(regdat_sh) $(srcdir)/../regformats/reg-ppc.dat reg-ppc.c
Index: src/gdb/gdbserver/configure.srv
===================================================================
--- src.orig/gdb/gdbserver/configure.srv	2006-11-09 11:23:50.000000000 -0500
+++ src/gdb/gdbserver/configure.srv	2006-11-09 11:42:15.000000000 -0500
@@ -67,8 +67,15 @@ case "${target}" in
 			srv_linux_regsets=yes
 			srv_linux_thread_db=yes
 			;;
+  mips*64*-*-linux*)	srv_regobj=reg-mips64.o
+			srv_tgtobj="linux-low.o linux-mips-low.o"
+			srv_linux_regsets=yes
+			srv_linux_usrregs=yes
+			srv_linux_thread_db=yes
+			;;
   mips*-*-linux*)	srv_regobj=reg-mips.o
 			srv_tgtobj="linux-low.o linux-mips-low.o"
+			srv_linux_regsets=yes
 			srv_linux_usrregs=yes
 			srv_linux_thread_db=yes
 			;;
Index: src/gdb/gdbserver/linux-mips-low.c
===================================================================
--- src.orig/gdb/gdbserver/linux-mips-low.c	2006-11-09 11:25:37.000000000 -0500
+++ src/gdb/gdbserver/linux-mips-low.c	2006-11-09 13:06:04.000000000 -0500
@@ -23,6 +23,7 @@
 #include "linux-low.h"
 
 #include <sys/ptrace.h>
+#include <endian.h>
 
 #include "gdb_proc_service.h"
 
@@ -38,6 +39,15 @@
 
 #include <asm/ptrace.h>
 
+union mips_register
+{
+  unsigned char buf[8];
+
+  /* Deliberately signed, for proper sign extension.  */
+  int reg32;
+  long long reg64;
+};
+
 /* Return the ptrace ``address'' of register REGNO. */
 
 /* Matches mips_generic32_regs */
@@ -107,20 +117,25 @@ mips_cannot_store_register (int regno)
 static CORE_ADDR
 mips_get_pc ()
 {
-  unsigned long pc;
-  collect_register_by_name ("pc", &pc);
-  return pc;
+  union mips_register pc;
+  collect_register_by_name ("pc", pc.buf);
+  return register_size (0) == 4 ? pc.reg32 : pc.reg64;
 }
 
 static void
 mips_set_pc (CORE_ADDR pc)
 {
-  unsigned long newpc = pc;
-  supply_register_by_name ("pc", &newpc);
+  union mips_register newpc;
+  if (register_size (0) == 4)
+    newpc.reg32 = pc;
+  else
+    newpc.reg64 = pc;
+
+  supply_register_by_name ("pc", newpc.buf);
 }
 
 /* Correct in either endianness.  */
-static const unsigned long mips_breakpoint = 0x0005000d;
+static const unsigned int mips_breakpoint = 0x0005000d;
 #define mips_breakpoint_len 4
 
 /* We only place breakpoints in empty marker functions, and thread locking
@@ -129,15 +144,15 @@ static const unsigned long mips_breakpoi
 static CORE_ADDR
 mips_reinsert_addr ()
 {
-  unsigned long pc;
-  collect_register_by_name ("ra", &pc);
-  return pc;
+  union mips_register ra;
+  collect_register_by_name ("ra", ra.buf);
+  return register_size (0) == 4 ? ra.reg32 : ra.reg64;
 }
 
 static int
 mips_breakpoint_at (CORE_ADDR where)
 {
-  unsigned long insn;
+  unsigned int insn;
 
   (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
   if (insn == mips_breakpoint)
@@ -165,6 +180,155 @@ ps_get_thread_area (const struct ps_proc
   return PS_OK;
 }
 
+#ifdef HAVE_PTRACE_GETREGS
+
+static void
+mips_collect_register (int use_64bit, int regno, union mips_register *reg)
+{
+  union mips_register tmp_reg;
+
+  if (use_64bit)
+    {
+      collect_register (regno, &tmp_reg.reg64);
+      *reg = tmp_reg;
+    }
+  else
+    {
+      collect_register (regno, &tmp_reg.reg32);
+      reg->reg64 = tmp_reg.reg32;
+    }
+}
+
+static void
+mips_supply_register (int use_64bit, int regno, const union mips_register *reg)
+{
+  int offset = 0;
+
+  /* For big-endian 32-bit targets, ignore the high four bytes of each
+     eight-byte slot.  */
+  if (__BYTE_ORDER == __BIG_ENDIAN && !use_64bit)
+    offset = 4;
+
+  supply_register (regno, reg->buf + offset);
+}
+
+static void
+mips_collect_register_32bit (int use_64bit, int regno, unsigned char *buf)
+{
+  union mips_register tmp_reg;
+  int reg32;
+
+  mips_collect_register (use_64bit, regno, &tmp_reg);
+  reg32 = tmp_reg.reg64;
+  memcpy (buf, &reg32, 4);
+}
+
+static void
+mips_supply_register_32bit (int use_64bit, int regno, const unsigned char *buf)
+{
+  union mips_register tmp_reg;
+  int reg32;
+
+  memcpy (&reg32, buf, 4);
+  tmp_reg.reg64 = reg32;
+  mips_supply_register (use_64bit, regno, &tmp_reg);
+}
+
+static void
+mips_fill_gregset (void *buf)
+{
+  union mips_register *regset = buf;
+  int i, use_64bit;
+
+  use_64bit = (register_size (0) == 8);
+
+  for (i = 0; i < 32; i++)
+    mips_collect_register (use_64bit, i, regset + i);
+
+  mips_collect_register (use_64bit, find_regno ("lo"), regset + 32);
+  mips_collect_register (use_64bit, find_regno ("hi"), regset + 33);
+  mips_collect_register (use_64bit, find_regno ("pc"), regset + 34);
+  mips_collect_register (use_64bit, find_regno ("bad"), regset + 35);
+  mips_collect_register (use_64bit, find_regno ("sr"), regset + 36);
+  mips_collect_register (use_64bit, find_regno ("cause"), regset + 37);
+}
+
+static void
+mips_store_gregset (const void *buf)
+{
+  const union mips_register *regset = buf;
+  int i, use_64bit;
+
+  use_64bit = (register_size (0) == 8);
+
+  for (i = 0; i < 32; i++)
+    mips_supply_register (use_64bit, i, regset + i);
+
+  mips_supply_register (use_64bit, find_regno ("lo"), regset + 32);
+  mips_supply_register (use_64bit, find_regno ("hi"), regset + 33);
+  mips_supply_register (use_64bit, find_regno ("pc"), regset + 34);
+  mips_supply_register (use_64bit, find_regno ("bad"), regset + 35);
+  mips_supply_register (use_64bit, find_regno ("sr"), regset + 36);
+  mips_supply_register (use_64bit, find_regno ("cause"), regset + 37);
+}
+
+static void
+mips_fill_fpregset (void *buf)
+{
+  union mips_register *regset = buf;
+  int i, use_64bit, first_fp, big_endian;
+
+  use_64bit = (register_size (0) == 8);
+  first_fp = find_regno ("f0");
+  big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
+
+  /* See GDB for a discussion of this peculiar layout.  */
+  for (i = 0; i < 32; i++)
+    if (use_64bit)
+      collect_register (first_fp + i, regset[i].buf);
+    else
+      collect_register (first_fp + i,
+			regset[i & ~1].buf + 4 * (big_endian != (i & 1)));
+
+  mips_collect_register_32bit (use_64bit, find_regno ("fsr"), regset[32].buf);
+  mips_collect_register_32bit (use_64bit, find_regno ("fir"),
+			       regset[32].buf + 4);
+}
+
+static void
+mips_store_fpregset (const void *buf)
+{
+  const union mips_register *regset = buf;
+  int i, use_64bit, first_fp, big_endian;
+
+  use_64bit = (register_size (0) == 8);
+  first_fp = find_regno ("f0");
+  big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
+
+  /* See GDB for a discussion of this peculiar layout.  */
+  for (i = 0; i < 32; i++)
+    if (use_64bit)
+      supply_register (first_fp + i, regset[i].buf);
+    else
+      supply_register (first_fp + i,
+		       regset[i & ~1].buf + 4 * (big_endian != (i & 1)));
+
+  mips_supply_register_32bit (use_64bit, find_regno ("fsr"), regset[32].buf);
+  mips_supply_register_32bit (use_64bit, find_regno ("fir"),
+			      regset[32].buf + 4);
+}
+#endif /* HAVE_PTRACE_GETREGS */
+
+struct regset_info target_regsets[] = {
+#ifdef HAVE_PTRACE_GETREGS
+  { PTRACE_GETREGS, PTRACE_SETREGS, 38 * 8, GENERAL_REGS,
+    mips_fill_gregset, mips_store_gregset },
+  { PTRACE_GETFPREGS, PTRACE_SETFPREGS, 33 * 8, FP_REGS,
+    mips_fill_fpregset, mips_store_fpregset },
+#endif /* HAVE_PTRACE_GETREGS */
+  { 0, 0, -1, -1, NULL, NULL }
+};
+
 struct linux_target_ops the_low_target = {
   mips_num_regs,
   mips_regmap,
Index: src/gdb/gdbserver/thread-db.c
===================================================================
--- src.orig/gdb/gdbserver/thread-db.c	2006-11-09 12:42:33.000000000 -0500
+++ src/gdb/gdbserver/thread-db.c	2006-11-09 12:43:50.000000000 -0500
@@ -33,6 +33,8 @@ extern int debug_threads;
 
 #include "gdb_proc_service.h"
 
+#include <stdint.h>
+
 /* Structure that identifies the child process for the
    <proc_service.h> interface.  */
 static struct ps_prochandle proc_handle;
@@ -333,11 +335,14 @@ thread_db_get_tls_address (struct thread
   if (!process->thread_known)
     return TD_NOTHR;
 
-  err = td_thr_tls_get_addr (&process->th, (psaddr_t) load_module, offset,
-			     &addr);
+  /* Note the cast through uintptr_t: this interface only works if
+     a target address fits in a psaddr_t, which is a host pointer.
+     So a 32-bit debugger can not access 64-bit TLS through this.  */
+  err = td_thr_tls_get_addr (&process->th, (psaddr_t) (uintptr_t) load_module,
+			     offset, &addr);
   if (err == TD_OK)
     {
-      *address = (CORE_ADDR) addr;
+      *address = (CORE_ADDR) (uintptr_t) addr;
       return 0;
     }
   else
Index: src/gdb/regformats/reg-mips64.dat
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/regformats/reg-mips64.dat	2006-11-09 11:19:51.000000000 -0500
@@ -0,0 +1,112 @@
+name:mips
+expedite:pc,sp
+64:zero
+64:at
+64:v0
+64:v1
+
+64:a0
+64:a1
+64:a2
+64:a3
+
+64:t0
+64:t1
+64:t2
+64:t3
+
+64:t4
+64:t5
+64:t6
+64:t7
+
+64:s0
+64:s1
+64:s2
+64:s3
+
+64:s4
+64:s5
+64:s6
+64:s7
+
+64:t8
+64:t9
+64:k0
+64:k1
+
+64:gp
+64:sp
+64:s8
+64:ra
+
+64:sr
+64:lo
+64:hi
+64:bad
+
+64:cause
+64:pc
+
+64:f0
+64:f1
+64:f2
+64:f3
+
+64:f4
+64:f5
+64:f6
+64:f7
+
+64:f8
+64:f9
+64:f10
+64:f11
+
+64:f12
+64:f13
+64:f14
+64:f15
+
+64:f16
+64:f17
+64:f18
+64:f19
+
+64:f20
+64:f21
+64:f22
+64:f23
+
+64:f24
+64:f25
+64:f26
+64:f27
+
+64:f28
+64:f29
+64:f30
+64:f31
+
+64:fsr
+64:fir
+
+64:fp
+64:
+
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:
+64:


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]