aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbserver
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/gdbserver')
-rw-r--r--gdb/gdbserver/ChangeLog14
-rw-r--r--gdb/gdbserver/Makefile.in5
-rw-r--r--gdb/gdbserver/configure.srv7
-rw-r--r--gdb/gdbserver/linux-mips-low.c184
-rw-r--r--gdb/gdbserver/thread-db.c11
5 files changed, 207 insertions, 14 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 52c34e9..29c6904 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,17 @@
+2006-11-28 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-22 Ulrich Weigand <uweigand@de.ibm.com>
* configure.srv: Add target "spu*-*-*".
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 9748c95..eda7751 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -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-spu.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
@@ -318,6 +318,9 @@ reg-m68k.c : $(srcdir)/../regformats/reg-m68k.dat $(regdat_sh)
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
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 5a4792c..a1f6971 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -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
;;
diff --git a/gdb/gdbserver/linux-mips-low.c b/gdb/gdbserver/linux-mips-low.c
index 7829550..797d046 100644
--- a/gdb/gdbserver/linux-mips-low.c
+++ b/gdb/gdbserver/linux-mips-low.c
@@ -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_breakpoint = 0x0005000d;
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_prochandle *ph,
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,
diff --git a/gdb/gdbserver/thread-db.c b/gdb/gdbserver/thread-db.c
index 78bc6434..e1f0653d 100644
--- a/gdb/gdbserver/thread-db.c
+++ b/gdb/gdbserver/thread-db.c
@@ -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_info *thread, CORE_ADDR offset,
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