diff options
Diffstat (limited to 'gdb/gdbserver')
-rw-r--r-- | gdb/gdbserver/ChangeLog | 14 | ||||
-rw-r--r-- | gdb/gdbserver/Makefile.in | 5 | ||||
-rw-r--r-- | gdb/gdbserver/configure.srv | 7 | ||||
-rw-r--r-- | gdb/gdbserver/linux-mips-low.c | 184 | ||||
-rw-r--r-- | gdb/gdbserver/thread-db.c | 11 |
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, ®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, 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 |