This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[gdbserver] MIPS64 gdbserver port
- From: Daniel Jacobowitz <drow at false dot org>
- To: gdb-patches at sourceware dot org
- Date: Thu, 9 Nov 2006 16:17:13 -0500
- Subject: [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, ®32, 4);
+}
+
+static void
+mips_supply_register_32bit (int use_64bit, int regno, const unsigned char *buf)
+{
+ union mips_register tmp_reg;
+ int reg32;
+
+ memcpy (®32, 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: