diff options
author | Maciej W. Rozycki <macro@linux-mips.org> | 2012-03-01 22:19:48 +0000 |
---|---|---|
committer | Maciej W. Rozycki <macro@linux-mips.org> | 2012-03-01 22:19:48 +0000 |
commit | 1faeff088bbbd037d7769d214378b4faf805fa2e (patch) | |
tree | 8cb63635e8ec7e66e95a6224b52c725e8149305d /gdb/gdbserver | |
parent | f3b4f45c3398591eed0bf54bb2a51266aa8a2c4a (diff) | |
download | gdb-1faeff088bbbd037d7769d214378b4faf805fa2e.zip gdb-1faeff088bbbd037d7769d214378b4faf805fa2e.tar.gz gdb-1faeff088bbbd037d7769d214378b4faf805fa2e.tar.bz2 |
gdb/
* features/mips-dsp.xml: New file.
* features/mips64-dsp.xml: New file.
* features/mips-dsp-linux.xml: New file.
* features/mips64-dsp-linux.xml: New file.
* features/Makefile (WHICH): Add mips-dsp-linux and
mips64-dsp-linux.
(mips-dsp-expedite, mips64-dsp-expedite): New variables.
* features/mips-dsp-linux.c: New file.
* features/mips64-dsp-linux.c: New file.
* regformats/mips-dsp-linux.dat: New file.
* regformats/mips64-dsp-linux.dat: New file.
* mips-linux-nat.c (mips_linux_register_addr): Handle DSP
registers.
(mips64_linux_register_addr): Likewise.
(mips64_linux_regsets_fetch_registers): Likewise.
(mips64_linux_regsets_store_registers): Likewise.
(mips64_linux_fetch_registers): Update call to
mips64_linux_regsets_fetch_registers.
(mips64_linux_store_registers): Update call to
mips64_linux_regsets_store_registers.
(mips_linux_read_description): Probe for DSP registers.
(_initialize_mips_linux_nat): Call initialize_tdesc_mips_dsp_linux
and initialize_tdesc_mips64_dsp_linux.
* mips-linux-tdep.c (supply_gregset, mips64_supply_gregset):
Remove padding of no longer used embedded register slots.
* mips-linux-tdep.h (DSP_BASE, DSP_CONTROL): New macros.
(MIPS_RESTART_REGNUM): Redefine enum value.
* mips-tdep.c (mips_generic_reg_names): Remove trailing null
strings.
(mips_tx39_reg_names): Likewise.
(mips_linux_reg_names): New array of register names for Linux
targets.
(mips_register_name): Check for a null pointer in
mips_processor_reg_names and return an empty string.
(mips_register_type): Exclude embedded registers for the IRIX
and Linux ABIs.
(mips_pseudo_register_type): Likewise. Use dynamic numbers to
refer to FP registers, LO, HI, BadVAddr, Cause and PC. Handle
DSP registers.
(mips_stab_reg_to_regnum): Handle DSP accumulators.
(mips_dwarf_dwarf2_ecoff_reg_to_regnum): Likewise.
(mips_gdbarch_init): Likewise. Initialize internal register
indices for the Linux ABI. Use dynamic numbers to refer to
registers, as applicable, while parsing the target description.
* mips-tdep.h (struct mips_regnum): Add dspacc/dspctl offsets.
gdb/doc/
* gdb.texinfo (MIPS Features): Add org.gnu.gdb.mips.dsp.
gdb/gdbserver/
* linux-low.h (linux_target_ops): Add regset_bitmap member.
* linux-low.c (use_linux_regsets): New macro.
[!HAVE_LINUX_REGSETS] (regsets_fetch_inferior_registers): Likewise.
[!HAVE_LINUX_REGSETS] (regsets_store_inferior_registers): Likewise.
(linux_register_in_regsets): New function.
(usr_fetch_inferior_registers): Skip registers covered by
regsets.
(usr_store_inferior_registers): Likewise.
(usr_fetch_inferior_registers): New macro.
(usr_store_inferior_registers): Likewise.
(linux_fetch_registers): Handle mixed regset/non-regset targets.
(linux_store_registers): Likewise.
* linux-mips-low.c (init_registers_mips_dsp_linux): New
prototype.
(init_registers_mips64_dsp_linux): Likewise.
(init_registers_mips_linux): New macro.
(init_registers_mips_dsp_linux): Likewise.
(mips_dsp_num_regs): Likewise.
(DSP_BASE, DSP_CONTROL): New fallback macros.
(mips_base_regs): New macro.
(mips_regmap): Use it. Fix the size.
(mips_dsp_regmap): New variable.
(mips_dsp_regset_bitmap): Likewise.
(mips_arch_setup): New function.
(mips_cannot_fetch_register): Use the_low_target.regmap rather
than mips_regmap.
(mips_cannot_store_register): Likewise.
(the_low_target): Update .arch_setup, .num_regs and .regmap
initializers. Add .regset_bitmap initializer.
* linux-arm-low.c (the_low_target): Add .regset_bitmap
initializer.
* linux-bfin-low.c (the_low_target): Likewise.
* linux-cris-low.c (the_low_target): Likewise.
* linux-crisv32-low.c (the_low_target): Likewise.
* linux-ia64-low.c (the_low_target): Likewise.
* linux-m32r-low.c (the_low_target): Likewise.
* linux-m68k-low.c (the_low_target): Likewise.
* linux-ppc-low.c (the_low_target): Likewise.
* linux-s390-low.c (the_low_target): Likewise.
* linux-sh-low.c (the_low_target): Likewise.
* linux-sparc-low.c (the_low_target): Likewise.
* linux-tic6x-low.c (the_low_target): Likewise.
* linux-x86-low.c (the_low_target): Likewise.
* linux-xtensa-low.c (the_low_target): Likewise.
* configure.srv <mips*-*-linux*>: Add mips-dsp-linux.o and
mips64-dsp-linux.o to srv_regobj. Add mips-dsp-linux.xml,
mips64-dsp-linux.xml, mips-dsp.xml and mips64-dsp.xml to
srv_xmlfiles.
* Makefile.in (mips-dsp-linux.o, mips-dsp-linux.c): New targets.
(mips64-dsp-linux.o, mips64-dsp-linux.c): Likewise.
gdb/testsuite/
* gdb.xml/tdesc-regs.exp: Add "mips-dsp.xml" to the list of MIPS
core registers.
Diffstat (limited to 'gdb/gdbserver')
-rw-r--r-- | gdb/gdbserver/ChangeLog | 53 | ||||
-rw-r--r-- | gdb/gdbserver/Makefile.in | 6 | ||||
-rw-r--r-- | gdb/gdbserver/configure.srv | 9 | ||||
-rw-r--r-- | gdb/gdbserver/linux-arm-low.c | 1 | ||||
-rw-r--r-- | gdb/gdbserver/linux-bfin-low.c | 1 | ||||
-rw-r--r-- | gdb/gdbserver/linux-cris-low.c | 1 | ||||
-rw-r--r-- | gdb/gdbserver/linux-crisv32-low.c | 1 | ||||
-rw-r--r-- | gdb/gdbserver/linux-ia64-low.c | 1 | ||||
-rw-r--r-- | gdb/gdbserver/linux-low.c | 360 | ||||
-rw-r--r-- | gdb/gdbserver/linux-low.h | 6 | ||||
-rw-r--r-- | gdb/gdbserver/linux-m32r-low.c | 1 | ||||
-rw-r--r-- | gdb/gdbserver/linux-m68k-low.c | 1 | ||||
-rw-r--r-- | gdb/gdbserver/linux-mips-low.c | 119 | ||||
-rw-r--r-- | gdb/gdbserver/linux-ppc-low.c | 1 | ||||
-rw-r--r-- | gdb/gdbserver/linux-s390-low.c | 1 | ||||
-rw-r--r-- | gdb/gdbserver/linux-sh-low.c | 1 | ||||
-rw-r--r-- | gdb/gdbserver/linux-sparc-low.c | 1 | ||||
-rw-r--r-- | gdb/gdbserver/linux-tic6x-low.c | 1 | ||||
-rw-r--r-- | gdb/gdbserver/linux-x86-low.c | 1 | ||||
-rw-r--r-- | gdb/gdbserver/linux-xtensa-low.c | 1 |
20 files changed, 389 insertions, 178 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 454e64f..82971cd 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,56 @@ +2012-03-01 Maciej W. Rozycki <macro@codesourcery.com> + + * linux-low.h (linux_target_ops): Add regset_bitmap member. + * linux-low.c (use_linux_regsets): New macro. + [!HAVE_LINUX_REGSETS] (regsets_fetch_inferior_registers): Likewise. + [!HAVE_LINUX_REGSETS] (regsets_store_inferior_registers): Likewise. + (linux_register_in_regsets): New function. + (usr_fetch_inferior_registers): Skip registers covered by + regsets. + (usr_store_inferior_registers): Likewise. + (usr_fetch_inferior_registers): New macro. + (usr_store_inferior_registers): Likewise. + (linux_fetch_registers): Handle mixed regset/non-regset targets. + (linux_store_registers): Likewise. + * linux-mips-low.c (init_registers_mips_dsp_linux): New + prototype. + (init_registers_mips64_dsp_linux): Likewise. + (init_registers_mips_linux): New macro. + (init_registers_mips_dsp_linux): Likewise. + (mips_dsp_num_regs): Likewise. + (DSP_BASE, DSP_CONTROL): New fallback macros. + (mips_base_regs): New macro. + (mips_regmap): Use it. Fix the size. + (mips_dsp_regmap): New variable. + (mips_dsp_regset_bitmap): Likewise. + (mips_arch_setup): New function. + (mips_cannot_fetch_register): Use the_low_target.regmap rather + than mips_regmap. + (mips_cannot_store_register): Likewise. + (the_low_target): Update .arch_setup, .num_regs and .regmap + initializers. Add .regset_bitmap initializer. + * linux-arm-low.c (the_low_target): Add .regset_bitmap + initializer. + * linux-bfin-low.c (the_low_target): Likewise. + * linux-cris-low.c (the_low_target): Likewise. + * linux-crisv32-low.c (the_low_target): Likewise. + * linux-ia64-low.c (the_low_target): Likewise. + * linux-m32r-low.c (the_low_target): Likewise. + * linux-m68k-low.c (the_low_target): Likewise. + * linux-ppc-low.c (the_low_target): Likewise. + * linux-s390-low.c (the_low_target): Likewise. + * linux-sh-low.c (the_low_target): Likewise. + * linux-sparc-low.c (the_low_target): Likewise. + * linux-tic6x-low.c (the_low_target): Likewise. + * linux-x86-low.c (the_low_target): Likewise. + * linux-xtensa-low.c (the_low_target): Likewise. + * configure.srv <mips*-*-linux*>: Add mips-dsp-linux.o and + mips64-dsp-linux.o to srv_regobj. Add mips-dsp-linux.xml, + mips64-dsp-linux.xml, mips-dsp.xml and mips64-dsp.xml to + srv_xmlfiles. + * Makefile.in (mips-dsp-linux.o, mips-dsp-linux.c): New targets. + (mips64-dsp-linux.o, mips64-dsp-linux.c): Likewise. + 2012-02-29 Yao Qi <yao@codesourcery.com> Pedro Alves <palves@redhat.com> diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index b4d2006..551a8f1 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -544,9 +544,15 @@ reg-cf.c : $(srcdir)/../regformats/reg-cf.dat $(regdat_sh) mips-linux.o : mips-linux.c $(regdef_h) mips-linux.c : $(srcdir)/../regformats/mips-linux.dat $(regdat_sh) $(SHELL) $(regdat_sh) $(srcdir)/../regformats/mips-linux.dat mips-linux.c +mips-dsp-linux.o : mips-dsp-linux.c $(regdef_h) +mips-dsp-linux.c : $(srcdir)/../regformats/mips-dsp-linux.dat $(regdat_sh) + $(SHELL) $(regdat_sh) $(srcdir)/../regformats/mips-dsp-linux.dat mips-dsp-linux.c mips64-linux.o : mips64-linux.c $(regdef_h) mips64-linux.c : $(srcdir)/../regformats/mips64-linux.dat $(regdat_sh) $(SHELL) $(regdat_sh) $(srcdir)/../regformats/mips64-linux.dat mips64-linux.c +mips64-dsp-linux.o : mips64-dsp-linux.c $(regdef_h) +mips64-dsp-linux.c : $(srcdir)/../regformats/mips64-dsp-linux.dat $(regdat_sh) + $(SHELL) $(regdat_sh) $(srcdir)/../regformats/mips64-dsp-linux.dat mips64-dsp-linux.c powerpc-32.o : powerpc-32.c $(regdef_h) powerpc-32.c : $(srcdir)/../regformats/rs6000/powerpc-32.dat $(regdat_sh) $(SHELL) $(regdat_sh) $(srcdir)/../regformats/rs6000/powerpc-32.dat powerpc-32.c diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv index 7c47c86..3358c33 100644 --- a/gdb/gdbserver/configure.srv +++ b/gdb/gdbserver/configure.srv @@ -151,16 +151,23 @@ case "${target}" in srv_linux_regsets=yes srv_linux_thread_db=yes ;; - mips*-*-linux*) srv_regobj="mips-linux.o mips64-linux.o" + mips*-*-linux*) srv_regobj="mips-linux.o" + srv_regobj="${srv_regobj} mips-dsp-linux.o" + srv_regobj="${srv_regobj} mips64-linux.o" + srv_regobj="${srv_regobj} mips64-dsp-linux.o" srv_tgtobj="linux-low.o linux-osdata.o linux-mips-low.o linux-procfs.o" srv_xmlfiles="mips-linux.xml" + srv_xmlfiles="${srv_xmlfiles} mips-dsp-linux.xml" srv_xmlfiles="${srv_xmlfiles} mips-cpu.xml" srv_xmlfiles="${srv_xmlfiles} mips-cp0.xml" srv_xmlfiles="${srv_xmlfiles} mips-fpu.xml" + srv_xmlfiles="${srv_xmlfiles} mips-dsp.xml" srv_xmlfiles="${srv_xmlfiles} mips64-linux.xml" + srv_xmlfiles="${srv_xmlfiles} mips64-dsp-linux.xml" srv_xmlfiles="${srv_xmlfiles} mips64-cpu.xml" srv_xmlfiles="${srv_xmlfiles} mips64-cp0.xml" srv_xmlfiles="${srv_xmlfiles} mips64-fpu.xml" + srv_xmlfiles="${srv_xmlfiles} mips64-dsp.xml" srv_linux_regsets=yes srv_linux_usrregs=yes srv_linux_thread_db=yes diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c index 3096546..ff2437d 100644 --- a/gdb/gdbserver/linux-arm-low.c +++ b/gdb/gdbserver/linux-arm-low.c @@ -834,6 +834,7 @@ struct linux_target_ops the_low_target = { arm_arch_setup, arm_num_regs, arm_regmap, + NULL, arm_cannot_fetch_register, arm_cannot_store_register, arm_get_pc, diff --git a/gdb/gdbserver/linux-bfin-low.c b/gdb/gdbserver/linux-bfin-low.c index 5e5aed2..b6fe58a 100644 --- a/gdb/gdbserver/linux-bfin-low.c +++ b/gdb/gdbserver/linux-bfin-low.c @@ -94,6 +94,7 @@ struct linux_target_ops the_low_target = { init_registers_bfin, bfin_num_regs, bfin_regmap, + NULL, bfin_cannot_fetch_register, bfin_cannot_store_register, bfin_get_pc, diff --git a/gdb/gdbserver/linux-cris-low.c b/gdb/gdbserver/linux-cris-low.c index 60188b2..a399789 100644 --- a/gdb/gdbserver/linux-cris-low.c +++ b/gdb/gdbserver/linux-cris-low.c @@ -112,6 +112,7 @@ struct linux_target_ops the_low_target = { init_registers_cris, cris_num_regs, cris_regmap, + NULL, cris_cannot_fetch_register, cris_cannot_store_register, cris_get_pc, diff --git a/gdb/gdbserver/linux-crisv32-low.c b/gdb/gdbserver/linux-crisv32-low.c index e0e5504..e33372d 100644 --- a/gdb/gdbserver/linux-crisv32-low.c +++ b/gdb/gdbserver/linux-crisv32-low.c @@ -376,6 +376,7 @@ struct linux_target_ops the_low_target = { NULL, NULL, NULL, + NULL, cris_get_pc, cris_set_pc, (const unsigned char *) &cris_breakpoint, diff --git a/gdb/gdbserver/linux-ia64-low.c b/gdb/gdbserver/linux-ia64-low.c index 1b0ad81..8753190 100644 --- a/gdb/gdbserver/linux-ia64-low.c +++ b/gdb/gdbserver/linux-ia64-low.c @@ -282,6 +282,7 @@ struct linux_target_ops the_low_target = { init_registers_ia64, ia64_num_regs, ia64_regmap, + NULL, ia64_cannot_fetch_register, ia64_cannot_store_register, }; diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 17d4694..bc14ec3 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -3781,145 +3781,11 @@ unstop_all_lwps (int unsuspend, struct lwp_info *except) find_inferior (&all_lwps, proceed_one_lwp, except); } -#ifdef HAVE_LINUX_USRREGS - -int -register_addr (int regnum) -{ - int addr; - - if (regnum < 0 || regnum >= the_low_target.num_regs) - error ("Invalid register number %d.", regnum); - - addr = the_low_target.regmap[regnum]; - - return addr; -} - -/* Fetch one register. */ -static void -fetch_register (struct regcache *regcache, int regno) -{ - CORE_ADDR regaddr; - int i, size; - char *buf; - int pid; - - if (regno >= the_low_target.num_regs) - return; - if ((*the_low_target.cannot_fetch_register) (regno)) - return; - - regaddr = register_addr (regno); - if (regaddr == -1) - return; - - size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1) - & -sizeof (PTRACE_XFER_TYPE)); - buf = alloca (size); - - pid = lwpid_of (get_thread_lwp (current_inferior)); - for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE)) - { - errno = 0; - *(PTRACE_XFER_TYPE *) (buf + i) = - ptrace (PTRACE_PEEKUSER, pid, - /* Coerce to a uintptr_t first to avoid potential gcc warning - of coercing an 8 byte integer to a 4 byte pointer. */ - (PTRACE_ARG3_TYPE) (uintptr_t) regaddr, 0); - regaddr += sizeof (PTRACE_XFER_TYPE); - if (errno != 0) - error ("reading register %d: %s", regno, strerror (errno)); - } - - if (the_low_target.supply_ptrace_register) - the_low_target.supply_ptrace_register (regcache, regno, buf); - else - supply_register (regcache, regno, buf); -} - -/* Store one register. */ -static void -store_register (struct regcache *regcache, int regno) -{ - CORE_ADDR regaddr; - int i, size; - char *buf; - int pid; - - if (regno >= the_low_target.num_regs) - return; - if ((*the_low_target.cannot_store_register) (regno)) - return; - - regaddr = register_addr (regno); - if (regaddr == -1) - return; - - size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1) - & -sizeof (PTRACE_XFER_TYPE)); - buf = alloca (size); - memset (buf, 0, size); - - if (the_low_target.collect_ptrace_register) - the_low_target.collect_ptrace_register (regcache, regno, buf); - else - collect_register (regcache, regno, buf); - - pid = lwpid_of (get_thread_lwp (current_inferior)); - for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE)) - { - errno = 0; - ptrace (PTRACE_POKEUSER, pid, - /* Coerce to a uintptr_t first to avoid potential gcc warning - about coercing an 8 byte integer to a 4 byte pointer. */ - (PTRACE_ARG3_TYPE) (uintptr_t) regaddr, - (PTRACE_ARG4_TYPE) *(PTRACE_XFER_TYPE *) (buf + i)); - if (errno != 0) - { - /* At this point, ESRCH should mean the process is - already gone, in which case we simply ignore attempts - to change its registers. See also the related - comment in linux_resume_one_lwp. */ - if (errno == ESRCH) - return; - - if ((*the_low_target.cannot_store_register) (regno) == 0) - error ("writing register %d: %s", regno, strerror (errno)); - } - regaddr += sizeof (PTRACE_XFER_TYPE); - } -} - -/* Fetch all registers, or just one, from the child process. */ -static void -usr_fetch_inferior_registers (struct regcache *regcache, int regno) -{ - if (regno == -1) - for (regno = 0; regno < the_low_target.num_regs; regno++) - fetch_register (regcache, regno); - else - fetch_register (regcache, regno); -} - -/* Store our register values back into the inferior. - If REGNO is -1, do this for all registers. - Otherwise, REGNO specifies which register (so we can save time). */ -static void -usr_store_inferior_registers (struct regcache *regcache, int regno) -{ - if (regno == -1) - for (regno = 0; regno < the_low_target.num_regs; regno++) - store_register (regcache, regno); - else - store_register (regcache, regno); -} -#endif /* HAVE_LINUX_USRREGS */ - - #ifdef HAVE_LINUX_REGSETS +#define use_linux_regsets 1 + static int regsets_fetch_inferior_registers (struct regcache *regcache) { @@ -4079,34 +3945,224 @@ regsets_store_inferior_registers (struct regcache *regcache) return 0; else return 1; - return 0; } -#endif /* HAVE_LINUX_REGSETS */ +#else /* !HAVE_LINUX_REGSETS */ +#define use_linux_regsets 0 +#define regsets_fetch_inferior_registers(regcache) 1 +#define regsets_store_inferior_registers(regcache) 1 -void -linux_fetch_registers (struct regcache *regcache, int regno) -{ -#ifdef HAVE_LINUX_REGSETS - if (regsets_fetch_inferior_registers (regcache) == 0) - return; #endif + +/* Return 1 if register REGNO is supported by one of the regset ptrace + calls or 0 if it has to be transferred individually. */ + +static int +linux_register_in_regsets (int regno) +{ + unsigned char mask = 1 << (regno % 8); + size_t index = regno / 8; + + return (use_linux_regsets + && (the_low_target.regset_bitmap == NULL + || (the_low_target.regset_bitmap[index] & mask) != 0)); +} + #ifdef HAVE_LINUX_USRREGS - usr_fetch_inferior_registers (regcache, regno); + +int +register_addr (int regnum) +{ + int addr; + + if (regnum < 0 || regnum >= the_low_target.num_regs) + error ("Invalid register number %d.", regnum); + + addr = the_low_target.regmap[regnum]; + + return addr; +} + +/* Fetch one register. */ +static void +fetch_register (struct regcache *regcache, int regno) +{ + CORE_ADDR regaddr; + int i, size; + char *buf; + int pid; + + if (regno >= the_low_target.num_regs) + return; + if ((*the_low_target.cannot_fetch_register) (regno)) + return; + + regaddr = register_addr (regno); + if (regaddr == -1) + return; + + size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1) + & -sizeof (PTRACE_XFER_TYPE)); + buf = alloca (size); + + pid = lwpid_of (get_thread_lwp (current_inferior)); + for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE)) + { + errno = 0; + *(PTRACE_XFER_TYPE *) (buf + i) = + ptrace (PTRACE_PEEKUSER, pid, + /* Coerce to a uintptr_t first to avoid potential gcc warning + of coercing an 8 byte integer to a 4 byte pointer. */ + (PTRACE_ARG3_TYPE) (uintptr_t) regaddr, 0); + regaddr += sizeof (PTRACE_XFER_TYPE); + if (errno != 0) + error ("reading register %d: %s", regno, strerror (errno)); + } + + if (the_low_target.supply_ptrace_register) + the_low_target.supply_ptrace_register (regcache, regno, buf); + else + supply_register (regcache, regno, buf); +} + +/* Store one register. */ +static void +store_register (struct regcache *regcache, int regno) +{ + CORE_ADDR regaddr; + int i, size; + char *buf; + int pid; + + if (regno >= the_low_target.num_regs) + return; + if ((*the_low_target.cannot_store_register) (regno)) + return; + + regaddr = register_addr (regno); + if (regaddr == -1) + return; + + size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1) + & -sizeof (PTRACE_XFER_TYPE)); + buf = alloca (size); + memset (buf, 0, size); + + if (the_low_target.collect_ptrace_register) + the_low_target.collect_ptrace_register (regcache, regno, buf); + else + collect_register (regcache, regno, buf); + + pid = lwpid_of (get_thread_lwp (current_inferior)); + for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE)) + { + errno = 0; + ptrace (PTRACE_POKEUSER, pid, + /* Coerce to a uintptr_t first to avoid potential gcc warning + about coercing an 8 byte integer to a 4 byte pointer. */ + (PTRACE_ARG3_TYPE) (uintptr_t) regaddr, + (PTRACE_ARG4_TYPE) *(PTRACE_XFER_TYPE *) (buf + i)); + if (errno != 0) + { + /* At this point, ESRCH should mean the process is + already gone, in which case we simply ignore attempts + to change its registers. See also the related + comment in linux_resume_one_lwp. */ + if (errno == ESRCH) + return; + + if ((*the_low_target.cannot_store_register) (regno) == 0) + error ("writing register %d: %s", regno, strerror (errno)); + } + regaddr += sizeof (PTRACE_XFER_TYPE); + } +} + +/* Fetch all registers, or just one, from the child process. + If REGNO is -1, do this for all registers, skipping any that are + assumed to have been retrieved by regsets_fetch_inferior_registers, + unless ALL is non-zero. + Otherwise, REGNO specifies which register (so we can save time). */ +static void +usr_fetch_inferior_registers (struct regcache *regcache, int regno, int all) +{ + if (regno == -1) + { + for (regno = 0; regno < the_low_target.num_regs; regno++) + if (all || !linux_register_in_regsets (regno)) + fetch_register (regcache, regno); + } + else + fetch_register (regcache, regno); +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers, skipping any that are + assumed to have been saved by regsets_store_inferior_registers, + unless ALL is non-zero. + Otherwise, REGNO specifies which register (so we can save time). */ +static void +usr_store_inferior_registers (struct regcache *regcache, int regno, int all) +{ + if (regno == -1) + { + for (regno = 0; regno < the_low_target.num_regs; regno++) + if (all || !linux_register_in_regsets (regno)) + store_register (regcache, regno); + } + else + store_register (regcache, regno); +} + +#else /* !HAVE_LINUX_USRREGS */ + +#define usr_fetch_inferior_registers(regcache, regno, all) do {} while (0) +#define usr_store_inferior_registers(regcache, regno, all) do {} while (0) + #endif + + +void +linux_fetch_registers (struct regcache *regcache, int regno) +{ + int use_regsets; + int all = 0; + + if (regno == -1) + { + all = regsets_fetch_inferior_registers (regcache); + usr_fetch_inferior_registers (regcache, regno, all); + } + else + { + use_regsets = linux_register_in_regsets (regno); + if (use_regsets) + all = regsets_fetch_inferior_registers (regcache); + if (!use_regsets || all) + usr_fetch_inferior_registers (regcache, regno, 1); + } } void linux_store_registers (struct regcache *regcache, int regno) { -#ifdef HAVE_LINUX_REGSETS - if (regsets_store_inferior_registers (regcache) == 0) - return; -#endif -#ifdef HAVE_LINUX_USRREGS - usr_store_inferior_registers (regcache, regno); -#endif + int use_regsets; + int all = 0; + + if (regno == -1) + { + all = regsets_store_inferior_registers (regcache); + usr_store_inferior_registers (regcache, regno, all); + } + else + { + use_regsets = linux_register_in_regsets (regno); + if (use_regsets) + all = regsets_store_inferior_registers (regcache); + if (!use_regsets || all) + usr_store_inferior_registers (regcache, regno, 1); + } } diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h index 3ba004c..677d261 100644 --- a/gdb/gdbserver/linux-low.h +++ b/gdb/gdbserver/linux-low.h @@ -70,6 +70,12 @@ struct linux_target_ops int num_regs; int *regmap; + + /* Regset support bitmap: 1 for registers that are transferred as a part + of a regset, 0 for ones that need to be handled individually. This + can be NULL if all registers are transferred with regsets or regsets + are not supported. */ + unsigned char *regset_bitmap; int (*cannot_fetch_register) (int); /* Returns 0 if we can store the register, 1 if we can not diff --git a/gdb/gdbserver/linux-m32r-low.c b/gdb/gdbserver/linux-m32r-low.c index 6df1a0a..fd70cf2 100644 --- a/gdb/gdbserver/linux-m32r-low.c +++ b/gdb/gdbserver/linux-m32r-low.c @@ -91,6 +91,7 @@ struct linux_target_ops the_low_target = { init_registers_m32r, m32r_num_regs, m32r_regmap, + NULL, m32r_cannot_fetch_register, m32r_cannot_store_register, m32r_get_pc, diff --git a/gdb/gdbserver/linux-m68k-low.c b/gdb/gdbserver/linux-m68k-low.c index 9843d17..a640e4c 100644 --- a/gdb/gdbserver/linux-m68k-low.c +++ b/gdb/gdbserver/linux-m68k-low.c @@ -179,6 +179,7 @@ struct linux_target_ops the_low_target = { init_registers_m68k, m68k_num_regs, m68k_regmap, + NULL, m68k_cannot_fetch_register, m68k_cannot_store_register, m68k_get_pc, diff --git a/gdb/gdbserver/linux-mips-low.c b/gdb/gdbserver/linux-mips-low.c index 1fb6237..1f58442 100644 --- a/gdb/gdbserver/linux-mips-low.c +++ b/gdb/gdbserver/linux-mips-low.c @@ -27,8 +27,17 @@ /* Defined in auto-generated file mips-linux.c. */ void init_registers_mips_linux (void); +/* Defined in auto-generated file mips-dsp-linux.c. */ +void init_registers_mips_dsp_linux (void); /* Defined in auto-generated file mips64-linux.c. */ void init_registers_mips64_linux (void); +/* Defined in auto-generated file mips64-dsp-linux.c. */ +void init_registers_mips64_dsp_linux (void); + +#ifdef __mips64 +#define init_registers_mips_linux init_registers_mips64_linux +#define init_registers_mips_dsp_linux init_registers_mips64_dsp_linux +#endif #ifndef PTRACE_GET_THREAD_AREA #define PTRACE_GET_THREAD_AREA 25 @@ -39,9 +48,15 @@ void init_registers_mips64_linux (void); #endif #define mips_num_regs 73 +#define mips_dsp_num_regs 80 #include <asm/ptrace.h> +#ifndef DSP_BASE +#define DSP_BASE 71 +#define DSP_CONTROL 77 +#endif + union mips_register { unsigned char buf[8]; @@ -53,27 +68,84 @@ union mips_register /* Return the ptrace ``address'' of register REGNO. */ -static int mips_regmap[] = { - -1, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, +#define mips_base_regs \ + -1, 1, 2, 3, 4, 5, 6, 7, \ + 8, 9, 10, 11, 12, 13, 14, 15, \ + 16, 17, 18, 19, 20, 21, 22, 23, \ + 24, 25, 26, 27, 28, 29, 30, 31, \ + \ + -1, MMLO, MMHI, BADVADDR, CAUSE, PC, \ + \ + FPR_BASE, FPR_BASE + 1, FPR_BASE + 2, FPR_BASE + 3, \ + FPR_BASE + 4, FPR_BASE + 5, FPR_BASE + 6, FPR_BASE + 7, \ + FPR_BASE + 8, FPR_BASE + 9, FPR_BASE + 10, FPR_BASE + 11, \ + FPR_BASE + 12, FPR_BASE + 13, FPR_BASE + 14, FPR_BASE + 15, \ + FPR_BASE + 16, FPR_BASE + 17, FPR_BASE + 18, FPR_BASE + 19, \ + FPR_BASE + 20, FPR_BASE + 21, FPR_BASE + 22, FPR_BASE + 23, \ + FPR_BASE + 24, FPR_BASE + 25, FPR_BASE + 26, FPR_BASE + 27, \ + FPR_BASE + 28, FPR_BASE + 29, FPR_BASE + 30, FPR_BASE + 31, \ + FPC_CSR, FPC_EIR + +#define mips_dsp_regs \ + DSP_BASE, DSP_BASE + 1, DSP_BASE + 2, DSP_BASE + 3, \ + DSP_BASE + 4, DSP_BASE + 5, \ + DSP_CONTROL + +static int mips_regmap[mips_num_regs] = { + mips_base_regs, + 0 +}; - -1, MMLO, MMHI, BADVADDR, CAUSE, PC, +static int mips_dsp_regmap[mips_dsp_num_regs] = { + mips_base_regs, + mips_dsp_regs, + 0 +}; - FPR_BASE, FPR_BASE + 1, FPR_BASE + 2, FPR_BASE + 3, - FPR_BASE + 4, FPR_BASE + 5, FPR_BASE + 6, FPR_BASE + 7, - FPR_BASE + 8, FPR_BASE + 9, FPR_BASE + 10, FPR_BASE + 11, - FPR_BASE + 12, FPR_BASE + 13, FPR_BASE + 14, FPR_BASE + 15, - FPR_BASE + 16, FPR_BASE + 17, FPR_BASE + 18, FPR_BASE + 19, - FPR_BASE + 20, FPR_BASE + 21, FPR_BASE + 22, FPR_BASE + 23, - FPR_BASE + 24, FPR_BASE + 25, FPR_BASE + 26, FPR_BASE + 27, - FPR_BASE + 28, FPR_BASE + 29, FPR_BASE + 30, FPR_BASE + 31, - FPC_CSR, FPC_EIR, +/* DSP registers are not in any regset and can only be accessed + individually. */ - 0 +static unsigned char mips_dsp_regset_bitmap[(mips_dsp_num_regs + 7) / 8] = { + 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x80 }; +/* Try peeking at an arbitrarily chosen DSP register and pick the available + user register set accordingly. */ + +static void +mips_arch_setup (void) +{ + static void (*init_registers) (void); + + gdb_assert (current_inferior); + + if (init_registers == NULL) + { + int pid = lwpid_of (get_thread_lwp (current_inferior)); + + ptrace (PTRACE_PEEKUSER, pid, DSP_CONTROL, 0); + switch (errno) + { + case 0: + the_low_target.num_regs = mips_dsp_num_regs; + the_low_target.regmap = mips_dsp_regmap; + the_low_target.regset_bitmap = mips_dsp_regset_bitmap; + init_registers = init_registers_mips_dsp_linux; + break; + case EIO: + the_low_target.num_regs = mips_num_regs; + the_low_target.regmap = mips_regmap; + the_low_target.regset_bitmap = NULL; + init_registers = init_registers_mips_linux; + break; + default: + perror_with_name ("ptrace"); + break; + } + } + init_registers (); +} + /* From mips-linux-nat.c. */ /* Pseudo registers can not be read. ptrace does not provide a way to @@ -84,7 +156,7 @@ static int mips_regmap[] = { static int mips_cannot_fetch_register (int regno) { - if (mips_regmap[regno] == -1) + if (the_low_target.regmap[regno] == -1) return 1; if (find_regno ("r0") == regno) @@ -96,7 +168,7 @@ mips_cannot_fetch_register (int regno) static int mips_cannot_store_register (int regno) { - if (mips_regmap[regno] == -1) + if (the_low_target.regmap[regno] == -1) return 1; if (find_regno ("r0") == regno) @@ -352,13 +424,10 @@ struct regset_info target_regsets[] = { }; struct linux_target_ops the_low_target = { -#ifdef __mips64 - init_registers_mips64_linux, -#else - init_registers_mips_linux, -#endif - mips_num_regs, - mips_regmap, + mips_arch_setup, + -1, + NULL, + NULL, mips_cannot_fetch_register, mips_cannot_store_register, mips_get_pc, diff --git a/gdb/gdbserver/linux-ppc-low.c b/gdb/gdbserver/linux-ppc-low.c index 36d3cb1..518a59e 100644 --- a/gdb/gdbserver/linux-ppc-low.c +++ b/gdb/gdbserver/linux-ppc-low.c @@ -610,6 +610,7 @@ struct linux_target_ops the_low_target = { ppc_arch_setup, ppc_num_regs, ppc_regmap, + NULL, ppc_cannot_fetch_register, ppc_cannot_store_register, ppc_get_pc, diff --git a/gdb/gdbserver/linux-s390-low.c b/gdb/gdbserver/linux-s390-low.c index be8d441..8a32795 100644 --- a/gdb/gdbserver/linux-s390-low.c +++ b/gdb/gdbserver/linux-s390-low.c @@ -461,6 +461,7 @@ struct linux_target_ops the_low_target = { s390_arch_setup, s390_num_regs, s390_regmap, + NULL, s390_cannot_fetch_register, s390_cannot_store_register, s390_get_pc, diff --git a/gdb/gdbserver/linux-sh-low.c b/gdb/gdbserver/linux-sh-low.c index 4f2ba39..e2537d6 100644 --- a/gdb/gdbserver/linux-sh-low.c +++ b/gdb/gdbserver/linux-sh-low.c @@ -112,6 +112,7 @@ struct linux_target_ops the_low_target = { init_registers_sh, sh_num_regs, sh_regmap, + NULL, sh_cannot_fetch_register, sh_cannot_store_register, sh_get_pc, diff --git a/gdb/gdbserver/linux-sparc-low.c b/gdb/gdbserver/linux-sparc-low.c index 834f63f..dc9c0cc 100644 --- a/gdb/gdbserver/linux-sparc-low.c +++ b/gdb/gdbserver/linux-sparc-low.c @@ -281,6 +281,7 @@ struct linux_target_ops the_low_target = { sparc_num_regs, /* No regmap needs to be provided since this impl. doesn't use USRREGS. */ NULL, + NULL, sparc_cannot_fetch_register, sparc_cannot_store_register, sparc_get_pc, diff --git a/gdb/gdbserver/linux-tic6x-low.c b/gdb/gdbserver/linux-tic6x-low.c index 895d99d..db7c5a4 100644 --- a/gdb/gdbserver/linux-tic6x-low.c +++ b/gdb/gdbserver/linux-tic6x-low.c @@ -321,6 +321,7 @@ struct linux_target_ops the_low_target = { tic6x_arch_setup, TIC6X_NUM_REGS, 0, + NULL, tic6x_cannot_fetch_register, tic6x_cannot_store_register, tic6x_get_pc, diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c index 365cd52..7fca416 100644 --- a/gdb/gdbserver/linux-x86-low.c +++ b/gdb/gdbserver/linux-x86-low.c @@ -2944,6 +2944,7 @@ struct linux_target_ops the_low_target = NULL, NULL, NULL, + NULL, x86_get_pc, x86_set_pc, x86_breakpoint, diff --git a/gdb/gdbserver/linux-xtensa-low.c b/gdb/gdbserver/linux-xtensa-low.c index 4158395..bf7f064 100644 --- a/gdb/gdbserver/linux-xtensa-low.c +++ b/gdb/gdbserver/linux-xtensa-low.c @@ -180,6 +180,7 @@ struct linux_target_ops the_low_target = { init_registers_xtensa, 0, 0, + NULL, 0, 0, xtensa_get_pc, |