diff options
author | Daniel Jacobowitz <dan@debian.org> | 2006-03-15 19:53:38 +0000 |
---|---|---|
committer | Daniel Jacobowitz <dan@debian.org> | 2006-03-15 19:53:38 +0000 |
commit | bcb1742124488f3c1e386cd46f3f732267a47ead (patch) | |
tree | 723511ae23e81d87a3eca5322fce95fec79ea775 | |
parent | 3b5523feb62288960e78ec3ae8e8f2701a46eaa7 (diff) | |
download | gdb-bcb1742124488f3c1e386cd46f3f732267a47ead.tar.gz |
Merge ten gdb and gdbserver patches for MIPS/MIPS64 support.
-rw-r--r-- | gdb/Makefile.in | 6 | ||||
-rw-r--r-- | gdb/gdb_proc_service.h | 7 | ||||
-rw-r--r-- | gdb/gdbserver/Makefile.in | 11 | ||||
-rw-r--r-- | gdb/gdbserver/config.in | 6 | ||||
-rwxr-xr-x | gdb/gdbserver/configure | 125 | ||||
-rw-r--r-- | gdb/gdbserver/configure.ac | 32 | ||||
-rw-r--r-- | gdb/gdbserver/gdb_proc_service.h | 75 | ||||
-rw-r--r-- | gdb/gdbserver/linux-i386-low.c | 16 | ||||
-rw-r--r-- | gdb/gdbserver/linux-mips-low.c | 27 | ||||
-rw-r--r-- | gdb/gdbserver/linux-x86-64-low.c | 16 | ||||
-rw-r--r-- | gdb/gdbserver/proc-service.c | 34 | ||||
-rw-r--r-- | gdb/gdbserver/thread-db.c | 16 | ||||
-rw-r--r-- | gdb/mips-linux-nat.c | 193 | ||||
-rw-r--r-- | gdb/mips-linux-tdep.c | 339 | ||||
-rw-r--r-- | gdb/mips-linux-tdep.h | 94 | ||||
-rw-r--r-- | gdb/mips-mdebug-tdep.c | 16 | ||||
-rw-r--r-- | gdb/mips-tdep.c | 42 | ||||
-rw-r--r-- | gdb/proc-service.c | 6 |
18 files changed, 662 insertions, 399 deletions
diff --git a/gdb/Makefile.in b/gdb/Makefile.in index acba593b0eb..99aa888c29f 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -737,6 +737,7 @@ macrotab_h = macrotab.h main_h = main.h mdebugread_h = mdebugread.h $(coff_sym_h) $(coff_symconst_h) memattr_h = memattr.h +mips_linux_tdep_h = mips-linux-tdep.h mips_mdebug_tdep_h = mips-mdebug-tdep.h mipsnbsd_tdep_h = mipsnbsd-tdep.h mips_tdep_h = mips-tdep.h @@ -2295,11 +2296,12 @@ mips64obsd-tdep.o: mips64obsd-tdep.c $(defs_h) $(osabi_h) $(regcache_h) \ $(gdb_string_h) $(mips_tdep_h) $(solib_svr4_h) mips-irix-tdep.o: mips-irix-tdep.c $(defs_h) $(osabi_h) $(elf_bfd_h) mips-linux-nat.o: mips-linux-nat.c $(defs_h) $(mips_tdep_h) $(target_h) \ - $(linux_nat_h) + $(linux_nat_h) $(gdb_proc_service_h) $(mips_linux_tdep_h) \ + $(inferior_h) mips-linux-tdep.o: mips-linux-tdep.c $(defs_h) $(gdbcore_h) $(target_h) \ $(solib_svr4_h) $(osabi_h) $(mips_tdep_h) $(gdb_string_h) \ $(gdb_assert_h) $(frame_h) $(regcache_h) $(trad_frame_h) \ - $(tramp_frame_h) + $(tramp_frame_h) $(floatformat_h) $(mips_linux_tdep_h) mips-mdebug-tdep.o: mips-mdebug-tdep.c $(defs_h) $(frame_h) $(mips_tdep_h) \ $(trad_frame_h) $(block_h) $(symtab_h) $(objfiles_h) $(elf_mips_h) \ $(elf_bfd_h) $(gdb_assert_h) $(frame_unwind_h) $(frame_base_h) \ diff --git a/gdb/gdb_proc_service.h b/gdb/gdb_proc_service.h index 408a87b0d4e..fc559bed88f 100644 --- a/gdb/gdb_proc_service.h +++ b/gdb/gdb_proc_service.h @@ -1,5 +1,5 @@ /* <proc_service.h> replacement for systems that don't have it. - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000, 2006 Free Software Foundation, Inc. This file is part of GDB. @@ -48,10 +48,11 @@ typedef enum typedef unsigned int lwpid_t; #endif -typedef unsigned long paddr_t; - #ifndef HAVE_PSADDR_T typedef unsigned long psaddr_t; +typedef unsigned long paddr_t; +#else +typedef psaddr_t paddr_t; #endif #ifndef HAVE_PRGREGSET_T diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index 19ee78b221f..0da5f6cde68 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -242,7 +242,7 @@ version.o: version.c $(server_h) # will remove them. MAKEOVERRIDES= -gdb_proc_service_h = $(srcdir)/../gdb_proc_service.h $(srcdir)/../gregset.h +gdb_proc_service_h = $(srcdir)/gdb_proc_service.h regdat_sh = $(srcdir)/../regformats/regdat.sh regdef_h = $(srcdir)/../regformats/regdef.h regcache_h = $(srcdir)/regcache.h @@ -272,15 +272,18 @@ linux-low.o: linux-low.c $(linux_low_h) $(server_h) 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-i386-low.o: linux-i386-low.c $(linux_low_h) $(server_h) \ + $(gdb_proc_service_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) -linux-mips-low.o: linux-mips-low.c $(linux_low_h) $(server_h) +linux-mips-low.o: linux-mips-low.c $(linux_low_h) $(server_h) \ + $(gdb_proc_service_h) linux-ppc-low.o: linux-ppc-low.c $(linux_low_h) $(server_h) linux-ppc64-low.o: linux-ppc64-low.c $(linux_low_h) $(server_h) linux-s390-low.o: linux-s390-low.c $(linux_low_h) $(server_h) linux-sh-low.o: linux-sh-low.c $(linux_low_h) $(server_h) -linux-x86-64-low.o: linux-x86-64-low.c $(linux_low_h) $(server_h) +linux-x86-64-low.o: linux-x86-64-low.c $(linux_low_h) $(server_h) \ + $(gdb_proc_service_h) reg-arm.o : reg-arm.c $(regdef_h) reg-arm.c : $(srcdir)/../regformats/reg-arm.dat $(regdat_sh) diff --git a/gdb/gdbserver/config.in b/gdb/gdbserver/config.in index 59e56bc8e8e..3aa2811ecef 100644 --- a/gdb/gdbserver/config.in +++ b/gdb/gdbserver/config.in @@ -25,9 +25,6 @@ /* Define to 1 if you have the <memory.h> header file. */ #undef HAVE_MEMORY_H -/* Define if <sys/procfs.h> has prfpregset_t. */ -#undef HAVE_PRFPREGSET_T - /* Define if <sys/procfs.h> has prgregset_t. */ #undef HAVE_PRGREGSET_T @@ -104,8 +101,5 @@ /* Define to the version of this package. */ #undef PACKAGE_VERSION -/* Define if the prfpregset_t type is broken. */ -#undef PRFPREGSET_T_BROKEN - /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS diff --git a/gdb/gdbserver/configure b/gdb/gdbserver/configure index 1373538d1dd..262d5ef99ac 100755 --- a/gdb/gdbserver/configure +++ b/gdb/gdbserver/configure @@ -3544,131 +3544,6 @@ _ACEOF echo "$as_me:$LINENO: result: $bfd_cv_have_sys_procfs_type_prgregset_t" >&5 echo "${ECHO_T}$bfd_cv_have_sys_procfs_type_prgregset_t" >&6 - echo "$as_me:$LINENO: checking for prfpregset_t in sys/procfs.h" >&5 -echo $ECHO_N "checking for prfpregset_t in sys/procfs.h... $ECHO_C" >&6 - if test "${bfd_cv_have_sys_procfs_type_prfpregset_t+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -#define _SYSCALL32 -#include <sys/procfs.h> -int -main () -{ -prfpregset_t avar - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - bfd_cv_have_sys_procfs_type_prfpregset_t=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -bfd_cv_have_sys_procfs_type_prfpregset_t=no - -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi - - if test $bfd_cv_have_sys_procfs_type_prfpregset_t = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_PRFPREGSET_T 1 -_ACEOF - - fi - echo "$as_me:$LINENO: result: $bfd_cv_have_sys_procfs_type_prfpregset_t" >&5 -echo "${ECHO_T}$bfd_cv_have_sys_procfs_type_prfpregset_t" >&6 - - - - - if test $bfd_cv_have_sys_procfs_type_prfpregset_t = yes; then - echo "$as_me:$LINENO: checking whether prfpregset_t type is broken" >&5 -echo $ECHO_N "checking whether prfpregset_t type is broken... $ECHO_C" >&6 - if test "${gdb_cv_prfpregset_t_broken+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - if test "$cross_compiling" = yes; then - gdb_cv_prfpregset_t_broken=yes -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <sys/procfs.h> - int main () - { - if (sizeof (prfpregset_t) == sizeof (void *)) - return 1; - return 0; - } -_ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - gdb_cv_prfpregset_t_broken=no -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -( exit $ac_status ) -gdb_cv_prfpregset_t_broken=yes -fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi -fi - - echo "$as_me:$LINENO: result: $gdb_cv_prfpregset_t_broken" >&5 -echo "${ECHO_T}$gdb_cv_prfpregset_t_broken" >&6 - if test $gdb_cv_prfpregset_t_broken = yes; then - -cat >>confdefs.h <<\_ACEOF -#define PRFPREGSET_T_BROKEN 1 -_ACEOF - - fi - fi - echo "$as_me:$LINENO: checking for elf_fpregset_t in sys/procfs.h" >&5 echo $ECHO_N "checking for elf_fpregset_t in sys/procfs.h... $ECHO_C" >&6 if test "${bfd_cv_have_sys_procfs_type_elf_fpregset_t+set}" = set; then diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac index fabd94db517..a952af5d83c 100644 --- a/gdb/gdbserver/configure.ac +++ b/gdb/gdbserver/configure.ac @@ -1,5 +1,6 @@ dnl Autoconf configure script for GDB server. -dnl Copyright (C) 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. +dnl Copyright (C) 2000, 2002, 2003, 2004, 2005, 2006 +dnl Free Software Foundation, Inc. dnl dnl This file is part of GDB. dnl @@ -88,35 +89,6 @@ if test "$ac_cv_header_sys_procfs_h" = yes; then BFD_HAVE_SYS_PROCFS_TYPE(lwpid_t) BFD_HAVE_SYS_PROCFS_TYPE(psaddr_t) BFD_HAVE_SYS_PROCFS_TYPE(prgregset_t) - BFD_HAVE_SYS_PROCFS_TYPE(prfpregset_t) - - dnl Check for broken prfpregset_t type - - dnl For Linux/i386, glibc 2.1.3 was released with a bogus - dnl prfpregset_t type (it's a typedef for the pointer to a struct - dnl instead of the struct itself). We detect this here, and work - dnl around it in gdb_proc_service.h. - - if test $bfd_cv_have_sys_procfs_type_prfpregset_t = yes; then - AC_MSG_CHECKING(whether prfpregset_t type is broken) - AC_CACHE_VAL(gdb_cv_prfpregset_t_broken, - [AC_TRY_RUN([#include <sys/procfs.h> - int main () - { - if (sizeof (prfpregset_t) == sizeof (void *)) - return 1; - return 0; - }], - gdb_cv_prfpregset_t_broken=no, - gdb_cv_prfpregset_t_broken=yes, - gdb_cv_prfpregset_t_broken=yes)]) - AC_MSG_RESULT($gdb_cv_prfpregset_t_broken) - if test $gdb_cv_prfpregset_t_broken = yes; then - AC_DEFINE(PRFPREGSET_T_BROKEN, 1, - [Define if the prfpregset_t type is broken.]) - fi - fi - BFD_HAVE_SYS_PROCFS_TYPE(elf_fpregset_t) fi diff --git a/gdb/gdbserver/gdb_proc_service.h b/gdb/gdbserver/gdb_proc_service.h new file mode 100644 index 00000000000..e5aefbdd418 --- /dev/null +++ b/gdb/gdbserver/gdb_proc_service.h @@ -0,0 +1,75 @@ +/* <proc_service.h> replacement for systems that don't have it. + Copyright (C) 2000, 2006 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#ifndef GDB_PROC_SERVICE_H +#define GDB_PROC_SERVICE_H + +#include <sys/types.h> + +#ifdef HAVE_PROC_SERVICE_H +#include <proc_service.h> +#else + +#ifdef HAVE_SYS_PROCFS_H +#include <sys/procfs.h> +#endif + +/* Not all platforms bring in <linux/elf.h> via <sys/procfs.h>. If + <sys/procfs.h> wasn't enough to find elf_fpregset_t, try the kernel + headers also (but don't if we don't need to). */ +#ifndef HAVE_ELF_FPREGSET_T +# ifdef HAVE_LINUX_ELF_H +# include <linux/elf.h> +# endif +#endif + +typedef enum +{ + PS_OK, /* Success. */ + PS_ERR, /* Generic error. */ + PS_BADPID, /* Bad process handle. */ + PS_BADLID, /* Bad LWP id. */ + PS_BADADDR, /* Bad address. */ + PS_NOSYM, /* Symbol not found. */ + PS_NOFREGS /* FPU register set not available. */ +} ps_err_e; + +#ifndef HAVE_LWPID_T +typedef unsigned int lwpid_t; +#endif + +#ifndef HAVE_PSADDR_T +typedef unsigned long psaddr_t; +#endif + +#ifndef HAVE_PRGREGSET_T +typedef elf_gregset_t prgregset_t; +#endif + +#endif /* HAVE_PROC_SERVICE_H */ + +/* Structure that identifies the target process. */ +struct ps_prochandle +{ + /* The process id is all we need. */ + pid_t pid; +}; + +#endif /* gdb_proc_service.h */ diff --git a/gdb/gdbserver/linux-i386-low.c b/gdb/gdbserver/linux-i386-low.c index 96359fb92e1..c0daf0b76ca 100644 --- a/gdb/gdbserver/linux-i386-low.c +++ b/gdb/gdbserver/linux-i386-low.c @@ -1,5 +1,5 @@ /* GNU/Linux/i386 specific low level interface, for the remote server for GDB. - Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2004, 2005 + Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GDB. @@ -23,19 +23,7 @@ #include "linux-low.h" #include "i387-fp.h" -/* Correct for all GNU/Linux targets (for quite some time). */ -#define GDB_GREGSET_T elf_gregset_t -#define GDB_FPREGSET_T elf_fpregset_t - -#ifndef HAVE_ELF_FPREGSET_T -/* Make sure we have said types. Not all platforms bring in <linux/elf.h> - via <sys/procfs.h>. */ -#ifdef HAVE_LINUX_ELF_H -#include <linux/elf.h> -#endif -#endif - -#include "../gdb_proc_service.h" +#include "gdb_proc_service.h" #include <sys/ptrace.h> diff --git a/gdb/gdbserver/linux-mips-low.c b/gdb/gdbserver/linux-mips-low.c index 695bd29bf0d..78295505f31 100644 --- a/gdb/gdbserver/linux-mips-low.c +++ b/gdb/gdbserver/linux-mips-low.c @@ -1,5 +1,5 @@ /* GNU/Linux/MIPS specific low level interface, for the remote server for GDB. - Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2005 + Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2005, 2006 Free Software Foundation, Inc. This file is part of GDB. @@ -22,6 +22,14 @@ #include "server.h" #include "linux-low.h" +#include <sys/ptrace.h> + +#include "gdb_proc_service.h" + +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA 25 +#endif + #ifdef HAVE_SYS_REG_H #include <sys/reg.h> #endif @@ -140,6 +148,23 @@ mips_breakpoint_at (CORE_ADDR where) return 0; } +/* Fetch the thread-local storage pointer for libthread_db. */ + +ps_err_e +ps_get_thread_area (const struct ps_prochandle *ph, + lwpid_t lwpid, int idx, void **base) +{ + if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) + return PS_ERR; + + /* IDX is the bias from the thread pointer to the beginning of the + thread descriptor. It has to be subtracted due to implementation + quirks in libthread_db. */ + *base = (void *) ((char *)*base - idx); + + return PS_OK; +} + struct linux_target_ops the_low_target = { mips_num_regs, mips_regmap, diff --git a/gdb/gdbserver/linux-x86-64-low.c b/gdb/gdbserver/linux-x86-64-low.c index 7a4a76aa443..43cd10b0b39 100644 --- a/gdb/gdbserver/linux-x86-64-low.c +++ b/gdb/gdbserver/linux-x86-64-low.c @@ -1,6 +1,6 @@ /* GNU/Linux/x86-64 specific low level interface, for the remote server for GDB. - Copyright (C) 2002, 2004, 2005 + Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GDB. @@ -24,19 +24,7 @@ #include "linux-low.h" #include "i387-fp.h" -/* Correct for all GNU/Linux targets (for quite some time). */ -#define GDB_GREGSET_T elf_gregset_t -#define GDB_FPREGSET_T elf_fpregset_t - -#ifndef HAVE_ELF_FPREGSET_T -/* Make sure we have said types. Not all platforms bring in <linux/elf.h> - via <sys/procfs.h>. */ -#ifdef HAVE_LINUX_ELF_H -#include <linux/elf.h> -#endif -#endif - -#include "../gdb_proc_service.h" +#include "gdb_proc_service.h" #include <sys/reg.h> #include <sys/procfs.h> diff --git a/gdb/gdbserver/proc-service.c b/gdb/gdbserver/proc-service.c index a64919e54ee..99083f17333 100644 --- a/gdb/gdbserver/proc-service.c +++ b/gdb/gdbserver/proc-service.c @@ -1,5 +1,5 @@ /* libthread_db helper functions for the remote server for GDB. - Copyright (C) 2002, 2004, 2005 + Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. Contributed by MontaVista Software. @@ -29,19 +29,7 @@ #include "linux-low.h" -/* Correct for all GNU/Linux targets (for quite some time). */ -#define GDB_GREGSET_T elf_gregset_t -#define GDB_FPREGSET_T elf_fpregset_t - -#ifndef HAVE_ELF_FPREGSET_T -/* Make sure we have said types. Not all platforms bring in <linux/elf.h> - via <sys/procfs.h>. */ -#ifdef HAVE_LINUX_ELF_H -#include <linux/elf.h> -#endif -#endif - -#include "../gdb_proc_service.h" +#include "gdb_proc_service.h" typedef struct ps_prochandle *gdb_ps_prochandle_t; typedef void *gdb_ps_read_buf_t; @@ -75,14 +63,14 @@ gregset_info(void) ps_err_e ps_pglobal_lookup (gdb_ps_prochandle_t ph, const char *obj, - const char *name, paddr_t *sym_addr) + const char *name, psaddr_t *sym_addr) { CORE_ADDR addr; if (look_up_one_symbol (name, &addr) == 0) return PS_NOSYM; - *sym_addr = (paddr_t) (unsigned long) addr; + *sym_addr = (psaddr_t) (unsigned long) addr; return PS_OK; } @@ -90,20 +78,20 @@ ps_pglobal_lookup (gdb_ps_prochandle_t ph, const char *obj, them into BUF. */ ps_err_e -ps_pdread (gdb_ps_prochandle_t ph, paddr_t addr, +ps_pdread (gdb_ps_prochandle_t ph, psaddr_t addr, gdb_ps_read_buf_t buf, gdb_ps_size_t size) { - read_inferior_memory (addr, buf, size); + read_inferior_memory ((unsigned long) addr, buf, size); return PS_OK; } /* Write SIZE bytes from BUF into the target process PH at address ADDR. */ ps_err_e -ps_pdwrite (gdb_ps_prochandle_t ph, paddr_t addr, +ps_pdwrite (gdb_ps_prochandle_t ph, psaddr_t addr, gdb_ps_write_buf_t buf, gdb_ps_size_t size) { - return write_inferior_memory (addr, buf, size); + return write_inferior_memory ((unsigned long) addr, buf, size); } /* Get the general registers of LWP LWPID within the target process PH @@ -149,8 +137,7 @@ ps_lsetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, const prgregset_t gregset) process PH and store them in FPREGSET. */ ps_err_e -ps_lgetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, - gdb_prfpregset_t *fpregset) +ps_lgetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, void *fpregset) { /* Unneeded. */ return PS_ERR; @@ -160,8 +147,7 @@ ps_lgetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, process PH from FPREGSET. */ ps_err_e -ps_lsetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, - const gdb_prfpregset_t *fpregset) +ps_lsetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, void *fpregset) { /* Unneeded. */ return PS_ERR; diff --git a/gdb/gdbserver/thread-db.c b/gdb/gdbserver/thread-db.c index 561e3809231..b47f576d2e9 100644 --- a/gdb/gdbserver/thread-db.c +++ b/gdb/gdbserver/thread-db.c @@ -1,5 +1,5 @@ /* Thread management interface, for the remote server for GDB. - Copyright (C) 2002, 2004, 2005 + Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. Contributed by MontaVista Software. @@ -31,19 +31,7 @@ extern int debug_threads; #include <thread_db.h> #endif -/* Correct for all GNU/Linux targets (for quite some time). */ -#define GDB_GREGSET_T elf_gregset_t -#define GDB_FPREGSET_T elf_fpregset_t - -#ifndef HAVE_ELF_FPREGSET_T -/* Make sure we have said types. Not all platforms bring in <linux/elf.h> - via <sys/procfs.h>. */ -#ifdef HAVE_LINUX_ELF_H -#include <linux/elf.h> -#endif -#endif - -#include "../gdb_proc_service.h" +#include "gdb_proc_service.h" /* Structure that identifies the child process for the <proc_service.h> interface. */ diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c index 0d581d180ba..985ff2781d3 100644 --- a/gdb/mips-linux-nat.c +++ b/gdb/mips-linux-nat.c @@ -1,6 +1,7 @@ /* Native-dependent code for GNU/Linux on MIPS processors. - Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. This file is part of GDB. @@ -20,9 +21,29 @@ Boston, MA 02110-1301, USA. */ #include "defs.h" +#include "inferior.h" #include "mips-tdep.h" #include "target.h" #include "linux-nat.h" +#include "mips-linux-tdep.h" + +#include "gdb_proc_service.h" + +#include <sys/ptrace.h> + +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA 25 +#endif + +/* Assume that we have PTRACE_GETREGS et al. support. If we do not, + we'll clear this and use PTRACE_PEEKUSER instead. */ +static int have_ptrace_regsets = 1; + +/* Saved function pointers to fetch and store a single register using + PTRACE_PEEKUSER and PTRACE_POKEUSER. */ + +void (*super_fetch_registers) (int); +void (*super_store_registers) (int); /* Pseudo registers can not be read. ptrace does not provide a way to read (or set) MIPS_PS_REGNUM, and there's no point in reading or @@ -65,10 +86,178 @@ mips_linux_cannot_store_register (int regno) return 1; } +/* Fetch the thread-local storage pointer for libthread_db. */ + +ps_err_e +ps_get_thread_area (const struct ps_prochandle *ph, + lwpid_t lwpid, int idx, void **base) +{ + if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) + return PS_ERR; + + /* IDX is the bias from the thread pointer to the beginning of the + thread descriptor. It has to be subtracted due to implementation + quirks in libthread_db. */ + *base = (void *) ((char *)*base - idx); + + return PS_OK; +} + +/* Fetch REGNO (or all registers if REGNO == -1) from the target + using PTRACE_GETREGS et al. */ + +static void +mips64_linux_regsets_fetch_registers (int regno) +{ + int is_fp; + int tid; + + if (regno >= mips_regnum (current_gdbarch)->fp0 + && regno <= mips_regnum (current_gdbarch)->fp0 + 32) + is_fp = 1; + else if (regno == mips_regnum (current_gdbarch)->fp_control_status) + is_fp = 1; + else if (regno == mips_regnum (current_gdbarch)->fp_implementation_revision) + is_fp = 1; + else + is_fp = 0; + + tid = ptid_get_lwp (inferior_ptid); + if (tid == 0) + tid = ptid_get_pid (inferior_ptid); + + if (regno == -1 || !is_fp) + { + mips64_elf_gregset_t regs; + + if (ptrace (PTRACE_GETREGS, tid, 0L, (PTRACE_TYPE_ARG3) ®s) == -1) + { + if (errno == EIO) + { + have_ptrace_regsets = 0; + return; + } + perror_with_name (_("Couldn't get registers")); + } + + mips64_supply_gregset (®s); + } + + if (regno == -1 || is_fp) + { + mips64_elf_fpregset_t fp_regs; + + if (ptrace (PTRACE_GETFPREGS, tid, 0L, + (PTRACE_TYPE_ARG3) &fp_regs) == -1) + { + if (errno == EIO) + { + have_ptrace_regsets = 0; + return; + } + perror_with_name (_("Couldn't get FP registers")); + } + + mips64_supply_fpregset (&fp_regs); + } +} + +/* Store REGNO (or all registers if REGNO == -1) to the target + using PTRACE_SETREGS et al. */ + +static void +mips64_linux_regsets_store_registers (int regno) +{ + int is_fp; + int tid; + + if (regno >= mips_regnum (current_gdbarch)->fp0 + && regno <= mips_regnum (current_gdbarch)->fp0 + 32) + is_fp = 1; + else if (regno == mips_regnum (current_gdbarch)->fp_control_status) + is_fp = 1; + else if (regno == mips_regnum (current_gdbarch)->fp_implementation_revision) + is_fp = 1; + else + is_fp = 0; + + tid = ptid_get_lwp (inferior_ptid); + if (tid == 0) + tid = ptid_get_pid (inferior_ptid); + + if (regno == -1 || !is_fp) + { + mips64_elf_gregset_t regs; + + if (ptrace (PTRACE_GETREGS, tid, 0L, (PTRACE_TYPE_ARG3) ®s) == -1) + perror_with_name (_("Couldn't get registers")); + + mips64_fill_gregset (®s, regno); + + if (ptrace (PTRACE_SETREGS, tid, 0L, (PTRACE_TYPE_ARG3) ®s) == -1) + perror_with_name (_("Couldn't set registers")); + } + + if (regno == -1 || is_fp) + { + mips64_elf_fpregset_t fp_regs; + + if (ptrace (PTRACE_GETFPREGS, tid, 0L, + (PTRACE_TYPE_ARG3) &fp_regs) == -1) + perror_with_name (_("Couldn't get FP registers")); + + mips64_fill_fpregset (&fp_regs, regno); + + if (ptrace (PTRACE_SETFPREGS, tid, 0L, + (PTRACE_TYPE_ARG3) &fp_regs) == -1) + perror_with_name (_("Couldn't set FP registers")); + } +} + +/* Fetch REGNO (or all registers if REGNO == -1) from the target + using any working method. */ + +static void +mips64_linux_fetch_registers (int regnum) +{ + /* Unless we already know that PTRACE_GETREGS does not work, try it. */ + if (have_ptrace_regsets) + mips64_linux_regsets_fetch_registers (regnum); + + /* If we know, or just found out, that PTRACE_GETREGS does not work, fall + back to PTRACE_PEEKUSER. */ + if (!have_ptrace_regsets) + super_fetch_registers (regnum); +} + +/* Store REGNO (or all registers if REGNO == -1) to the target + using any working method. */ + +static void +mips64_linux_store_registers (int regnum) +{ + /* Unless we already know that PTRACE_GETREGS does not work, try it. */ + if (have_ptrace_regsets) + mips64_linux_regsets_store_registers (regnum); + + /* If we know, or just found out, that PTRACE_GETREGS does not work, fall + back to PTRACE_PEEKUSER. */ + if (!have_ptrace_regsets) + super_store_registers (regnum); +} + void _initialize_mips_linux_nat (void); void _initialize_mips_linux_nat (void) { - add_target (linux_target ()); + struct target_ops *t = linux_target (); + + super_fetch_registers = t->to_fetch_registers; + super_store_registers = t->to_store_registers; + + t->to_fetch_registers = mips64_linux_fetch_registers; + t->to_store_registers = mips64_linux_store_registers; + + add_target (t); } diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c index 021edc7116b..5d789d24577 100644 --- a/gdb/mips-linux-tdep.c +++ b/gdb/mips-linux-tdep.c @@ -32,37 +32,8 @@ #include "regcache.h" #include "trad-frame.h" #include "tramp-frame.h" - -/* Copied from <asm/elf.h>. */ -#define ELF_NGREG 45 -#define ELF_NFPREG 33 - -typedef unsigned char elf_greg_t[4]; -typedef elf_greg_t elf_gregset_t[ELF_NGREG]; - -typedef unsigned char elf_fpreg_t[8]; -typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; - -/* 0 - 31 are integer registers, 32 - 63 are fp registers. */ -#define FPR_BASE 32 -#define PC 64 -#define CAUSE 65 -#define BADVADDR 66 -#define MMHI 67 -#define MMLO 68 -#define FPC_CSR 69 -#define FPC_EIR 70 - -#define EF_REG0 6 -#define EF_REG31 37 -#define EF_LO 38 -#define EF_HI 39 -#define EF_CP0_EPC 40 -#define EF_CP0_BADVADDR 41 -#define EF_CP0_STATUS 42 -#define EF_CP0_CAUSE 43 - -#define EF_SIZE 180 +#include "floatformat.h" +#include "mips-linux-tdep.h" /* Figure out where the longjmp will land. We expect the first arg to be a pointer to the jmp_buf structure @@ -98,7 +69,7 @@ mips_linux_get_longjmp_target (CORE_ADDR *pc) static void supply_32bit_reg (int regnum, const void *addr) { - char buf[MAX_REGISTER_SIZE]; + gdb_byte buf[MAX_REGISTER_SIZE]; store_signed_integer (buf, register_size (current_gdbarch, regnum), extract_signed_integer (addr, 4)); regcache_raw_supply (current_regcache, regnum, buf); @@ -106,11 +77,11 @@ supply_32bit_reg (int regnum, const void *addr) /* Unpack an elf_gregset_t into GDB's register cache. */ -void -supply_gregset (elf_gregset_t *gregsetp) +void +mips_supply_gregset (mips_elf_gregset_t *gregsetp) { int regi; - elf_greg_t *regp = *gregsetp; + mips_elf_greg_t *regp = *gregsetp; char zerobuf[MAX_REGISTER_SIZE]; memset (zerobuf, 0, MAX_REGISTER_SIZE); @@ -142,23 +113,23 @@ supply_gregset (elf_gregset_t *gregsetp) /* Pack our registers (or one register) into an elf_gregset_t. */ void -fill_gregset (elf_gregset_t *gregsetp, int regno) +mips_fill_gregset (mips_elf_gregset_t *gregsetp, int regno) { int regaddr, regi; - elf_greg_t *regp = *gregsetp; + mips_elf_greg_t *regp = *gregsetp; void *dst; if (regno == -1) { - memset (regp, 0, sizeof (elf_gregset_t)); + memset (regp, 0, sizeof (mips_elf_gregset_t)); for (regi = 0; regi < 32; regi++) - fill_gregset (gregsetp, regi); - fill_gregset (gregsetp, mips_regnum (current_gdbarch)->lo); - fill_gregset (gregsetp, mips_regnum (current_gdbarch)->hi); - fill_gregset (gregsetp, mips_regnum (current_gdbarch)->pc); - fill_gregset (gregsetp, mips_regnum (current_gdbarch)->badvaddr); - fill_gregset (gregsetp, MIPS_PS_REGNUM); - fill_gregset (gregsetp, mips_regnum (current_gdbarch)->cause); + mips_fill_gregset (gregsetp, regi); + mips_fill_gregset (gregsetp, mips_regnum (current_gdbarch)->lo); + mips_fill_gregset (gregsetp, mips_regnum (current_gdbarch)->hi); + mips_fill_gregset (gregsetp, mips_regnum (current_gdbarch)->pc); + mips_fill_gregset (gregsetp, mips_regnum (current_gdbarch)->badvaddr); + mips_fill_gregset (gregsetp, MIPS_PS_REGNUM); + mips_fill_gregset (gregsetp, mips_regnum (current_gdbarch)->cause); return; } @@ -195,7 +166,7 @@ fill_gregset (elf_gregset_t *gregsetp, int regno) /* Likewise, unpack an elf_fpregset_t. */ void -supply_fpregset (elf_fpregset_t *fpregsetp) +mips_supply_fpregset (mips_elf_fpregset_t *fpregsetp) { int regi; char zerobuf[MAX_REGISTER_SIZE]; @@ -220,7 +191,7 @@ supply_fpregset (elf_fpregset_t *fpregsetp) elf_fpregset_t. */ void -fill_fpregset (elf_fpregset_t *fpregsetp, int regno) +mips_fill_fpregset (mips_elf_fpregset_t *fpregsetp, int regno) { char *from, *to; @@ -239,9 +210,9 @@ fill_fpregset (elf_fpregset_t *fpregsetp, int regno) int regi; for (regi = 0; regi < 32; regi++) - fill_fpregset (fpregsetp, FP0_REGNUM + regi); - fill_fpregset (fpregsetp, - mips_regnum (current_gdbarch)->fp_control_status); + mips_fill_fpregset (fpregsetp, FP0_REGNUM + regi); + mips_fill_fpregset (fpregsetp, + mips_regnum (current_gdbarch)->fp_control_status); } } @@ -283,37 +254,6 @@ mips_linux_register_addr (int regno, CORE_ADDR blockend) /* Support for 64-bit ABIs. */ -/* Copied from <asm/elf.h>. */ -#define MIPS64_ELF_NGREG 45 -#define MIPS64_ELF_NFPREG 33 - -typedef unsigned char mips64_elf_greg_t[8]; -typedef mips64_elf_greg_t mips64_elf_gregset_t[MIPS64_ELF_NGREG]; - -typedef unsigned char mips64_elf_fpreg_t[8]; -typedef mips64_elf_fpreg_t mips64_elf_fpregset_t[MIPS64_ELF_NFPREG]; - -/* 0 - 31 are integer registers, 32 - 63 are fp registers. */ -#define MIPS64_FPR_BASE 32 -#define MIPS64_PC 64 -#define MIPS64_CAUSE 65 -#define MIPS64_BADVADDR 66 -#define MIPS64_MMHI 67 -#define MIPS64_MMLO 68 -#define MIPS64_FPC_CSR 69 -#define MIPS64_FPC_EIR 70 - -#define MIPS64_EF_REG0 0 -#define MIPS64_EF_REG31 31 -#define MIPS64_EF_LO 32 -#define MIPS64_EF_HI 33 -#define MIPS64_EF_CP0_EPC 34 -#define MIPS64_EF_CP0_BADVADDR 35 -#define MIPS64_EF_CP0_STATUS 36 -#define MIPS64_EF_CP0_CAUSE 37 - -#define MIPS64_EF_SIZE 304 - /* Figure out where the longjmp will land. We expect the first arg to be a pointer to the jmp_buf structure from which we extract the pc (MIPS_LINUX_JB_PC) that we will land @@ -342,39 +282,49 @@ mips64_linux_get_longjmp_target (CORE_ADDR *pc) return 1; } -/* Unpack an elf_gregset_t into GDB's register cache. */ +/* Register set support functions. These operate on standard 64-bit + regsets, but work whether the target is 32-bit or 64-bit. A 32-bit + target will still use the 64-bit format for PTRACE_GETREGS. */ + +/* Supply a 64-bit register. */ + +void +supply_64bit_reg (int regnum, const gdb_byte *buf) +{ + if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG + && register_size (current_gdbarch, regnum) == 4) + regcache_raw_supply (current_regcache, regnum, buf + 4); + else + regcache_raw_supply (current_regcache, regnum, buf); +} + +/* Unpack a 64-bit elf_gregset_t into GDB's register cache. */ -static void +void mips64_supply_gregset (mips64_elf_gregset_t *gregsetp) { int regi; mips64_elf_greg_t *regp = *gregsetp; - char zerobuf[MAX_REGISTER_SIZE]; + gdb_byte zerobuf[MAX_REGISTER_SIZE]; memset (zerobuf, 0, MAX_REGISTER_SIZE); for (regi = MIPS64_EF_REG0; regi <= MIPS64_EF_REG31; regi++) - regcache_raw_supply (current_regcache, (regi - MIPS64_EF_REG0), - (char *)(regp + regi)); - - regcache_raw_supply (current_regcache, - mips_regnum (current_gdbarch)->lo, - (char *) (regp + MIPS64_EF_LO)); - regcache_raw_supply (current_regcache, - mips_regnum (current_gdbarch)->hi, - (char *) (regp + MIPS64_EF_HI)); - - regcache_raw_supply (current_regcache, - mips_regnum (current_gdbarch)->pc, - (char *) (regp + MIPS64_EF_CP0_EPC)); - regcache_raw_supply (current_regcache, - mips_regnum (current_gdbarch)->badvaddr, - (char *) (regp + MIPS64_EF_CP0_BADVADDR)); - regcache_raw_supply (current_regcache, MIPS_PS_REGNUM, - (char *) (regp + MIPS64_EF_CP0_STATUS)); - regcache_raw_supply (current_regcache, - mips_regnum (current_gdbarch)->cause, - (char *) (regp + MIPS64_EF_CP0_CAUSE)); + supply_64bit_reg (regi - MIPS64_EF_REG0, (gdb_byte *)(regp + regi)); + + supply_64bit_reg (mips_regnum (current_gdbarch)->lo, + (gdb_byte *) (regp + MIPS64_EF_LO)); + supply_64bit_reg (mips_regnum (current_gdbarch)->hi, + (gdb_byte *) (regp + MIPS64_EF_HI)); + + supply_64bit_reg (mips_regnum (current_gdbarch)->pc, + (gdb_byte *) (regp + MIPS64_EF_CP0_EPC)); + supply_64bit_reg (mips_regnum (current_gdbarch)->badvaddr, + (gdb_byte *) (regp + MIPS64_EF_CP0_BADVADDR)); + supply_64bit_reg (MIPS_PS_REGNUM, + (gdb_byte *) (regp + MIPS64_EF_CP0_STATUS)); + supply_64bit_reg (mips_regnum (current_gdbarch)->cause, + (gdb_byte *) (regp + MIPS64_EF_CP0_CAUSE)); /* Fill inaccessible registers with zero. */ regcache_raw_supply (current_regcache, MIPS_UNUSED_REGNUM, zerobuf); @@ -384,9 +334,9 @@ mips64_supply_gregset (mips64_elf_gregset_t *gregsetp) regcache_raw_supply (current_regcache, regi, zerobuf); } -/* Pack our registers (or one register) into an elf_gregset_t. */ +/* Pack our registers (or one register) into a 64-bit elf_gregset_t. */ -static void +void mips64_fill_gregset (mips64_elf_gregset_t *gregsetp, int regno) { int regaddr, regi; @@ -411,13 +361,8 @@ mips64_fill_gregset (mips64_elf_gregset_t *gregsetp, int regno) } if (regno < 32) - { - dst = regp + regno + MIPS64_EF_REG0; - regcache_raw_collect (current_regcache, regno, dst); - return; - } - - if (regno == mips_regnum (current_gdbarch)->lo) + regaddr = regno + MIPS64_EF_REG0; + else if (regno == mips_regnum (current_gdbarch)->lo) regaddr = MIPS64_EF_LO; else if (regno == mips_regnum (current_gdbarch)->hi) regaddr = MIPS64_EF_HI; @@ -434,52 +379,97 @@ mips64_fill_gregset (mips64_elf_gregset_t *gregsetp, int regno) if (regaddr != -1) { + gdb_byte buf[MAX_REGISTER_SIZE]; + LONGEST val; + + regcache_raw_collect (current_regcache, regno, buf); + val = extract_signed_integer (buf, + register_size (current_gdbarch, regno)); dst = regp + regaddr; - regcache_raw_collect (current_regcache, regno, dst); + store_signed_integer (dst, 8, val); } } /* Likewise, unpack an elf_fpregset_t. */ -static void +void mips64_supply_fpregset (mips64_elf_fpregset_t *fpregsetp) { int regi; - char zerobuf[MAX_REGISTER_SIZE]; - memset (zerobuf, 0, MAX_REGISTER_SIZE); - - for (regi = 0; regi < 32; regi++) - regcache_raw_supply (current_regcache, FP0_REGNUM + regi, - (char *)(*fpregsetp + regi)); - - regcache_raw_supply (current_regcache, - mips_regnum (current_gdbarch)->fp_control_status, - (char *)(*fpregsetp + 32)); - - /* FIXME: how can we supply FCRIR? The ABI doesn't tell us. */ - regcache_raw_supply (current_regcache, - mips_regnum (current_gdbarch)->fp_implementation_revision, - zerobuf); + /* See mips_linux_o32_sigframe_init for a description of the + peculiar FP register layout. */ + if (register_size (current_gdbarch, FP0_REGNUM) == 4) + for (regi = 0; regi < 32; regi++) + { + gdb_byte *reg_ptr = (gdb_byte *) (*fpregsetp + (regi & ~1)); + if ((TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) != (regi & 1)) + reg_ptr += 4; + regcache_raw_supply (current_regcache, FP0_REGNUM + regi, reg_ptr); + } + else + for (regi = 0; regi < 32; regi++) + regcache_raw_supply (current_regcache, FP0_REGNUM + regi, + (char *)(*fpregsetp + regi)); + + supply_32bit_reg (mips_regnum (current_gdbarch)->fp_control_status, + (gdb_byte *)(*fpregsetp + 32)); + + /* The ABI doesn't tell us how to supply FCRIR, and core dumps don't + include it - but the result of PTRACE_GETFPREGS does. The best we + can do is to assume that its value is present. */ + supply_32bit_reg (mips_regnum (current_gdbarch)->fp_implementation_revision, + (gdb_byte *)(*fpregsetp + 32) + 4); } /* Likewise, pack one or all floating point registers into an elf_fpregset_t. */ -static void +void mips64_fill_fpregset (mips64_elf_fpregset_t *fpregsetp, int regno) { - char *from, *to; + gdb_byte *to; if ((regno >= FP0_REGNUM) && (regno < FP0_REGNUM + 32)) { - to = (char *) (*fpregsetp + regno - FP0_REGNUM); - regcache_raw_collect (current_regcache, regno, to); + /* See mips_linux_o32_sigframe_init for a description of the + peculiar FP register layout. */ + if (register_size (current_gdbarch, regno) == 4) + { + int regi = regno - FP0_REGNUM; + + to = (gdb_byte *) (*fpregsetp + (regi & ~1)); + if ((TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) != (regi & 1)) + to += 4; + regcache_raw_collect (current_regcache, regno, to); + } + else + { + to = (gdb_byte *) (*fpregsetp + regno - FP0_REGNUM); + regcache_raw_collect (current_regcache, regno, to); + } } else if (regno == mips_regnum (current_gdbarch)->fp_control_status) { - to = (char *) (*fpregsetp + 32); - regcache_raw_collect (current_regcache, regno, to); + gdb_byte buf[MAX_REGISTER_SIZE]; + LONGEST val; + + regcache_raw_collect (current_regcache, regno, buf); + val = extract_signed_integer (buf, + register_size (current_gdbarch, regno)); + to = (gdb_byte *) (*fpregsetp + 32); + store_signed_integer (to, 4, val); + } + else if (regno == mips_regnum (current_gdbarch)->fp_implementation_revision) + { + gdb_byte buf[MAX_REGISTER_SIZE]; + LONGEST val; + + regcache_raw_collect (current_regcache, regno, buf); + val = extract_signed_integer (buf, + register_size (current_gdbarch, regno)); + to = (gdb_byte *) (*fpregsetp + 32) + 4; + store_signed_integer (to, 4, val); } else if (regno == -1) { @@ -487,8 +477,10 @@ mips64_fill_fpregset (mips64_elf_fpregset_t *fpregsetp, int regno) for (regi = 0; regi < 32; regi++) mips64_fill_fpregset (fpregsetp, FP0_REGNUM + regi); - mips64_fill_fpregset(fpregsetp, - mips_regnum (current_gdbarch)->fp_control_status); + mips64_fill_fpregset (fpregsetp, + mips_regnum (current_gdbarch)->fp_control_status); + mips64_fill_fpregset (fpregsetp, (mips_regnum (current_gdbarch) + ->fp_implementation_revision)); } } @@ -536,8 +528,8 @@ static void fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which, CORE_ADDR reg_addr) { - elf_gregset_t gregset; - elf_fpregset_t fpregset; + mips_elf_gregset_t gregset; + mips_elf_fpregset_t fpregset; mips64_elf_gregset_t gregset64; mips64_elf_fpregset_t fpregset64; @@ -546,7 +538,7 @@ fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, if (core_reg_size == sizeof (gregset)) { memcpy ((char *) &gregset, core_reg_sect, sizeof (gregset)); - supply_gregset (&gregset); + mips_supply_gregset (&gregset); } else if (core_reg_size == sizeof (gregset64)) { @@ -563,7 +555,7 @@ fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, if (core_reg_size == sizeof (fpregset)) { memcpy ((char *) &fpregset, core_reg_sect, sizeof (fpregset)); - supply_fpregset (&fpregset); + mips_supply_fpregset (&fpregset); } else if (core_reg_size == sizeof (fpregset64)) { @@ -1084,6 +1076,49 @@ mips_linux_n32n64_sigframe_init (const struct tramp_frame *self, func)); } +/* Wrapper functions. These are only used by libthread_db. */ + +void +supply_gregset (mips_elf_gregset_t *gregsetp) +{ + if (mips_isa_regsize (current_gdbarch) == 4) + mips_supply_gregset (gregsetp); + else + mips64_supply_gregset ((void *) gregsetp); +} + +void +fill_gregset (mips_elf_gregset_t *gregsetp, int regno) +{ + if (mips_isa_regsize (current_gdbarch) == 4) + mips_fill_gregset (gregsetp, regno); + else + mips64_fill_gregset ((void *) gregsetp, regno); +} + +/* Likewise, unpack an elf_fpregset_t. */ + +void +supply_fpregset (mips_elf_fpregset_t *fpregsetp) +{ + if (mips_isa_regsize (current_gdbarch) == 4) + mips_supply_fpregset (fpregsetp); + else + mips64_supply_fpregset ((void *) fpregsetp); +} + +/* Likewise, pack one or all floating point registers into an + elf_fpregset_t. */ + +void +fill_fpregset (mips_elf_fpregset_t *fpregsetp, int regno) +{ + if (mips_isa_regsize (current_gdbarch) == 4) + mips_fill_fpregset (fpregsetp, regno); + else + mips64_fill_fpregset ((void *) fpregsetp, regno); +} + /* Initialize one of the GNU/Linux OS ABIs. */ static void @@ -1110,6 +1145,15 @@ mips_linux_init_abi (struct gdbarch_info info, set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_ilp32_fetch_link_map_offsets); set_mips_linux_register_addr (gdbarch, mips64_linux_register_addr); + set_gdbarch_long_double_bit (gdbarch, 128); + /* These floatformats should probably be renamed. MIPS uses + the same 128-bit IEEE floating point format that IA-64 uses, + except that the quiet/signalling NaN bit is reversed (GDB + does not distinguish between quiet and signalling NaNs). */ + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + set_gdbarch_long_double_format (gdbarch, &floatformat_ia64_quad_big); + else + set_gdbarch_long_double_format (gdbarch, &floatformat_ia64_quad_little); tramp_frame_prepend_unwinder (gdbarch, &mips_linux_n32_rt_sigframe); break; case MIPS_ABI_N64: @@ -1118,6 +1162,15 @@ mips_linux_init_abi (struct gdbarch_info info, set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_lp64_fetch_link_map_offsets); set_mips_linux_register_addr (gdbarch, mips64_linux_register_addr); + set_gdbarch_long_double_bit (gdbarch, 128); + /* These floatformats should probably be renamed. MIPS uses + the same 128-bit IEEE floating point format that IA-64 uses, + except that the quiet/signalling NaN bit is reversed (GDB + does not distinguish between quiet and signalling NaNs). */ + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + set_gdbarch_long_double_format (gdbarch, &floatformat_ia64_quad_big); + else + set_gdbarch_long_double_format (gdbarch, &floatformat_ia64_quad_little); tramp_frame_prepend_unwinder (gdbarch, &mips_linux_n64_rt_sigframe); break; default: diff --git a/gdb/mips-linux-tdep.h b/gdb/mips-linux-tdep.h new file mode 100644 index 00000000000..4914b638a23 --- /dev/null +++ b/gdb/mips-linux-tdep.h @@ -0,0 +1,94 @@ +/* Target-dependent code for GNU/Linux on MIPS processors. + + Copyright 2006 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. */ + +/* Copied from <asm/elf.h>. */ +#define ELF_NGREG 45 +#define ELF_NFPREG 33 + +typedef unsigned char mips_elf_greg_t[4]; +typedef mips_elf_greg_t mips_elf_gregset_t[ELF_NGREG]; + +typedef unsigned char mips_elf_fpreg_t[8]; +typedef mips_elf_fpreg_t mips_elf_fpregset_t[ELF_NFPREG]; + +/* 0 - 31 are integer registers, 32 - 63 are fp registers. */ +#define FPR_BASE 32 +#define PC 64 +#define CAUSE 65 +#define BADVADDR 66 +#define MMHI 67 +#define MMLO 68 +#define FPC_CSR 69 +#define FPC_EIR 70 + +#define EF_REG0 6 +#define EF_REG31 37 +#define EF_LO 38 +#define EF_HI 39 +#define EF_CP0_EPC 40 +#define EF_CP0_BADVADDR 41 +#define EF_CP0_STATUS 42 +#define EF_CP0_CAUSE 43 + +#define EF_SIZE 180 + +void mips_supply_gregset (mips_elf_gregset_t *); +void mips_fill_gregset (mips_elf_gregset_t *, int); +void mips_supply_fpregset (mips_elf_fpregset_t *); +void mips_fill_fpregset (mips_elf_fpregset_t *, int); + +/* 64-bit support. */ + +/* Copied from <asm/elf.h>. */ +#define MIPS64_ELF_NGREG 45 +#define MIPS64_ELF_NFPREG 33 + +typedef unsigned char mips64_elf_greg_t[8]; +typedef mips64_elf_greg_t mips64_elf_gregset_t[MIPS64_ELF_NGREG]; + +typedef unsigned char mips64_elf_fpreg_t[8]; +typedef mips64_elf_fpreg_t mips64_elf_fpregset_t[MIPS64_ELF_NFPREG]; + +/* 0 - 31 are integer registers, 32 - 63 are fp registers. */ +#define MIPS64_FPR_BASE 32 +#define MIPS64_PC 64 +#define MIPS64_CAUSE 65 +#define MIPS64_BADVADDR 66 +#define MIPS64_MMHI 67 +#define MIPS64_MMLO 68 +#define MIPS64_FPC_CSR 69 +#define MIPS64_FPC_EIR 70 + +#define MIPS64_EF_REG0 0 +#define MIPS64_EF_REG31 31 +#define MIPS64_EF_LO 32 +#define MIPS64_EF_HI 33 +#define MIPS64_EF_CP0_EPC 34 +#define MIPS64_EF_CP0_BADVADDR 35 +#define MIPS64_EF_CP0_STATUS 36 +#define MIPS64_EF_CP0_CAUSE 37 + +#define MIPS64_EF_SIZE 304 + +void mips64_supply_gregset (mips64_elf_gregset_t *); +void mips64_fill_gregset (mips64_elf_gregset_t *, int); +void mips64_supply_fpregset (mips64_elf_fpregset_t *); +void mips64_fill_fpregset (mips64_elf_fpregset_t *, int); diff --git a/gdb/mips-mdebug-tdep.c b/gdb/mips-mdebug-tdep.c index 43e1c9646f8..db79713a6f4 100644 --- a/gdb/mips-mdebug-tdep.c +++ b/gdb/mips-mdebug-tdep.c @@ -2,8 +2,8 @@ the GNU Debugger. Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, - 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software - Foundation, Inc. + 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006 + Free Software Foundation, Inc. This file is part of GDB. @@ -63,8 +63,8 @@ static bfd *the_bfd; static int compare_pdr_entries (const void *a, const void *b) { - CORE_ADDR lhs = bfd_get_32 (the_bfd, (bfd_byte *) a); - CORE_ADDR rhs = bfd_get_32 (the_bfd, (bfd_byte *) b); + CORE_ADDR lhs = bfd_get_signed_32 (the_bfd, (bfd_byte *) a); + CORE_ADDR rhs = bfd_get_signed_32 (the_bfd, (bfd_byte *) b); if (lhs < rhs) return -1; @@ -215,17 +215,17 @@ non_heuristic_proc_desc (CORE_ADDR pc, CORE_ADDR *addrptr) PROC_LOW_ADDR (proc_desc) = pdr_pc; PROC_FRAME_OFFSET (proc_desc) - = bfd_get_32 (sec->objfile->obfd, ptr + 20); + = bfd_get_signed_32 (sec->objfile->obfd, ptr + 20); PROC_FRAME_REG (proc_desc) = bfd_get_32 (sec->objfile->obfd, ptr + 24); PROC_REG_MASK (proc_desc) = bfd_get_32 (sec->objfile->obfd, ptr + 4); PROC_FREG_MASK (proc_desc) = bfd_get_32 (sec->objfile->obfd, ptr + 12); - PROC_REG_OFFSET (proc_desc) = bfd_get_32 (sec->objfile->obfd, - ptr + 8); + PROC_REG_OFFSET (proc_desc) + = bfd_get_signed_32 (sec->objfile->obfd, ptr + 8); PROC_FREG_OFFSET (proc_desc) - = bfd_get_32 (sec->objfile->obfd, ptr + 16); + = bfd_get_signed_32 (sec->objfile->obfd, ptr + 16); PROC_PC_REG (proc_desc) = bfd_get_32 (sec->objfile->obfd, ptr + 28); proc_desc->pdr.isym = (long) sym; diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 679dd9df9c7..880dfcc3494 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -1,7 +1,7 @@ /* Target-dependent code for the MIPS architecture, for GDB, the GNU Debugger. Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, - 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU @@ -202,7 +202,7 @@ is_mips16_addr (CORE_ADDR addr) static CORE_ADDR unmake_mips16_addr (CORE_ADDR addr) { - return ((addr) & ~1); + return ((addr) & ~(CORE_ADDR) 1); } /* Return the contents of register REGNUM as a signed integer. */ @@ -989,14 +989,14 @@ mips32_next_pc (CORE_ADDR pc) unsigned long reg; reg = jtype_target (inst) << 2; /* Upper four bits get never changed... */ - pc = reg + ((pc + 4) & 0xf0000000); + pc = reg + ((pc + 4) & ~(CORE_ADDR) 0x0fffffff); } break; /* FIXME case JALX : */ { unsigned long reg; reg = jtype_target (inst) << 2; - pc = reg + ((pc + 4) & 0xf0000000) + 1; /* yes, +1 */ + pc = reg + ((pc + 4) & ~(CORE_ADDR) 0x0fffffff) + 1; /* yes, +1 */ /* Add 1 to indicate 16 bit mode - Invert ISA mode */ } break; /* The new PC will be alternate mode */ @@ -1202,7 +1202,7 @@ unpack_mips16 (CORE_ADDR pc, static CORE_ADDR add_offset_16 (CORE_ADDR pc, int offset) { - return ((offset << 2) | ((pc + 2) & (0xf0000000))); + return ((offset << 2) | ((pc + 2) & (~(CORE_ADDR) 0x0fffffff))); } static CORE_ADDR @@ -2911,6 +2911,24 @@ mips_n32n64_return_value (struct gdbarch *gdbarch, || TYPE_LENGTH (type) > 2 * mips_abi_regsize (gdbarch)) return RETURN_VALUE_STRUCT_CONVENTION; else if (TYPE_CODE (type) == TYPE_CODE_FLT + && TYPE_LENGTH (type) == 16 + && tdep->mips_fpu_type != MIPS_FPU_NONE) + { + /* A 128-bit floating-point value fills both $f0 and $f2. The + two registers are used in the same as memory order, so the + eight bytes with the lower memory address are in $f0. */ + if (mips_debug) + fprintf_unfiltered (gdb_stderr, "Return float in $f0 and $f2\n"); + mips_xfer_register (regcache, + NUM_REGS + mips_regnum (current_gdbarch)->fp0, + 8, TARGET_BYTE_ORDER, readbuf, writebuf, 0); + mips_xfer_register (regcache, + NUM_REGS + mips_regnum (current_gdbarch)->fp0 + 2, + 8, TARGET_BYTE_ORDER, readbuf ? readbuf + 8 : readbuf, + writebuf ? writebuf + 8 : writebuf, 0); + return RETURN_VALUE_REGISTER_CONVENTION; + } + else if (TYPE_CODE (type) == TYPE_CODE_FLT && tdep->mips_fpu_type != MIPS_FPU_NONE) { /* A floating-point value belongs in the least significant part @@ -4037,7 +4055,6 @@ print_gp_register_row (struct ui_file *file, struct frame_info *frame, int regnum; /* For GP registers, we print a separate row of names above the vals */ - fprintf_filtered (file, " "); for (col = 0, regnum = start_regnum; col < ncols && regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++) { @@ -4046,11 +4063,17 @@ print_gp_register_row (struct ui_file *file, struct frame_info *frame, if (TYPE_CODE (gdbarch_register_type (gdbarch, regnum)) == TYPE_CODE_FLT) break; /* end the row: reached FP register */ + if (col == 0) + fprintf_filtered (file, " "); fprintf_filtered (file, mips_abi_regsize (current_gdbarch) == 8 ? "%17s" : "%9s", REGISTER_NAME (regnum)); col++; } + + if (col == 0) + return regnum; + /* print the R0 to R31 names */ if ((start_regnum % NUM_REGS) < MIPS_NUMREGS) fprintf_filtered (file, "\n R%-4d", start_regnum % NUM_REGS); @@ -4741,6 +4764,13 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) } } + /* Default 64-bit objects to N64 instead of O32. */ + if (found_abi == MIPS_ABI_UNKNOWN + && info.abfd != NULL + && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour + && elf_elfheader (info.abfd)->e_ident[EI_CLASS] == ELFCLASS64) + found_abi = MIPS_ABI_N64; + if (gdbarch_debug) fprintf_unfiltered (gdb_stdlog, "mips_gdbarch_init: found_abi = %d\n", found_abi); diff --git a/gdb/proc-service.c b/gdb/proc-service.c index 0bcac05c0b2..2829924581e 100644 --- a/gdb/proc-service.c +++ b/gdb/proc-service.c @@ -75,9 +75,9 @@ ps_xfer_memory (const struct ps_prochandle *ph, paddr_t addr, inferior_ptid = pid_to_ptid (ph->pid); if (write) - ret = target_write_memory (addr, buf, len); + ret = target_write_memory ((unsigned long) addr, buf, len); else - ret = target_read_memory (addr, buf, len); + ret = target_read_memory ((unsigned long) addr, buf, len); do_cleanups (old_chain); @@ -181,7 +181,7 @@ ps_pglobal_lookup (gdb_ps_prochandle_t ph, const char *obj, if (ms == NULL) return PS_NOSYM; - *sym_addr = SYMBOL_VALUE_ADDRESS (ms); + *sym_addr = (paddr_t) (unsigned long) SYMBOL_VALUE_ADDRESS (ms); return PS_OK; } |