From 822b65708d4030ccb4fd2a979de5292f730e30b8 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Wed, 13 Jun 2007 18:47:58 +0000 Subject: [PATCH] * config/mips/linux.mh (TDEP_XML): New. * features/mips-linux.xml, features/mips64-linux.xml: New files. * mips-linux-nat.c (mips_linux_register_addr): Handle MIPS_RESTART_REGNUM. (mips64_linux_register_addr): Likewise. (super_xfer_partial, mips_linux_xfer_partial): New. (_initialize_mips_linux_nat): Add them to the target_ops. * mips-linux-tdep.c (mips_supply_gregset): Handle MIPS_RESTART_REGNUM. (mips_fill_gregset, mips64_supply_gregset, mips64_fill_gregset) (mips_linux_o32_sigframe_init) (mips_linux_n32n64_sigframe_init): Likewise. (mips_linux_write_pc, mips_linux_restart_reg_p): New. (mips_linux_init_abi): Use mips_linux_write_pc. Check for the "org.gnu.gdb.mips.linux" feature. * mips-linux-tdep.h (MIPS_RESTART_REGNUM): New constant. (mips_linux_restart_reg_p): New prototype. * mips-tdep.c (mips_gdbarch_init): Pass tdesc_data to the OS/ABI initialization routine. * Makefile.in (mips-linux-tdep.o, mips-linux-nat.o): Update. * gdb.texinfo (MIPS Features): Document org.gnu.gdb.mips.linux. --- gdb/ChangeLog | 22 ++++++++++ gdb/Makefile.in | 6 ++- gdb/config/mips/linux.mh | 9 ++++ gdb/doc/ChangeLog | 4 ++ gdb/doc/gdb.texinfo | 4 ++ gdb/features/mips-linux.xml | 18 ++++++++ gdb/features/mips64-linux.xml | 18 ++++++++ gdb/mips-linux-nat.c | 41 +++++++++++++++++ gdb/mips-linux-tdep.c | 100 ++++++++++++++++++++++++++++++++++-------- gdb/mips-linux-tdep.h | 10 +++++ gdb/mips-tdep.c | 1 + 11 files changed, 212 insertions(+), 21 deletions(-) create mode 100644 gdb/features/mips-linux.xml create mode 100644 gdb/features/mips64-linux.xml diff --git a/gdb/ChangeLog b/gdb/ChangeLog index fe09eb5..248ce7b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,27 @@ 2007-06-13 Daniel Jacobowitz + * config/mips/linux.mh (TDEP_XML): New. + * features/mips-linux.xml, features/mips64-linux.xml: New files. + * mips-linux-nat.c (mips_linux_register_addr): Handle + MIPS_RESTART_REGNUM. + (mips64_linux_register_addr): Likewise. + (super_xfer_partial, mips_linux_xfer_partial): New. + (_initialize_mips_linux_nat): Add them to the target_ops. + * mips-linux-tdep.c (mips_supply_gregset): Handle MIPS_RESTART_REGNUM. + (mips_fill_gregset, mips64_supply_gregset, mips64_fill_gregset) + (mips_linux_o32_sigframe_init) + (mips_linux_n32n64_sigframe_init): Likewise. + (mips_linux_write_pc, mips_linux_restart_reg_p): New. + (mips_linux_init_abi): Use mips_linux_write_pc. Check for the + "org.gnu.gdb.mips.linux" feature. + * mips-linux-tdep.h (MIPS_RESTART_REGNUM): New constant. + (mips_linux_restart_reg_p): New prototype. + * mips-tdep.c (mips_gdbarch_init): Pass tdesc_data to the OS/ABI + initialization routine. + * Makefile.in (mips-linux-tdep.o, mips-linux-nat.o): Update. + +2007-06-13 Daniel Jacobowitz + * Makefile.in (mips-tdep.o): Update. * mips-tdep.c (struct register_alias, mips_o32_aliases) (mips_n32_n64_aliases, mips_register_aliases): New. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 9b786f2..8c12fb5 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -2337,12 +2337,14 @@ mips64obsd-tdep.o: mips64obsd-tdep.c $(defs_h) $(osabi_h) $(regcache_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) \ $(regcache_h) $(linux_nat_h) $(gdb_proc_service_h) $(gregset_h) \ - $(mips_linux_tdep_h) $(inferior_h) + $(mips_linux_tdep_h) $(inferior_h) $(target_descriptions_h) \ + $(xml_support_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) $(gdbtypes_h) $(solib_h) $(symtab_h) \ - $(mips_linux_tdep_h) $(solist_h) $(solib_svr4_h) + $(mips_linux_tdep_h) $(solist_h) $(solib_svr4_h) \ + $(target_descriptions_h) mipsnbsd-nat.o: mipsnbsd-nat.c $(defs_h) $(inferior_h) $(regcache_h) \ $(target_h) $(mips_tdep_h) $(mipsnbsd_tdep_h) $(inf_ptrace_h) mipsnbsd-tdep.o: mipsnbsd-tdep.c $(defs_h) $(gdbcore_h) $(regcache_h) \ diff --git a/gdb/config/mips/linux.mh b/gdb/config/mips/linux.mh index 32381a4..01478b6 100644 --- a/gdb/config/mips/linux.mh +++ b/gdb/config/mips/linux.mh @@ -5,3 +5,12 @@ NATDEPFILES= inf-ptrace.o fork-child.o mips-linux-nat.o \ linux-nat.o linux-fork.o LOADLIBES = -ldl -rdynamic + +TDEP_XML = $(srcdir)/features/mips-cpu.xml \ + $(srcdir)/features/mips-cp0.xml \ + $(srcdir)/features/mips-fpu.xml \ + $(srcdir)/features/mips-linux.xml \ + $(srcdir)/features/mips64-cpu.xml \ + $(srcdir)/features/mips64-cp0.xml \ + $(srcdir)/features/mips64-fpu.xml \ + $(srcdir)/features/mips64-linux.xml diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 20b2768..5211251 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,5 +1,9 @@ 2007-06-13 Daniel Jacobowitz + * gdb.texinfo (MIPS Features): Document org.gnu.gdb.mips.linux. + +2007-06-13 Daniel Jacobowitz + * gdb.texinfo (MIPS Features): New subsection. 2007-06-12 Ulrich Weigand diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 937106c..9c71ad2 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -25784,6 +25784,10 @@ it may be optional in a future version of @value{GDBN}. It should contain registers @samp{f0} through @samp{f31}, @samp{fcsr}, and @samp{fir}. They may be 32-bit or 64-bit depending on the target. +The @samp{org.gnu.gdb.mips.linux} feature is optional. It should +contain a single register, @samp{restart}, which is used by the +Linux kernel to control restartable syscalls. + @include gpl.texi @raisesections diff --git a/gdb/features/mips-linux.xml b/gdb/features/mips-linux.xml new file mode 100644 index 0000000..b1ece93 --- /dev/null +++ b/gdb/features/mips-linux.xml @@ -0,0 +1,18 @@ + + + + + + mips + + + + + + + + diff --git a/gdb/features/mips64-linux.xml b/gdb/features/mips64-linux.xml new file mode 100644 index 0000000..fd757eb --- /dev/null +++ b/gdb/features/mips64-linux.xml @@ -0,0 +1,18 @@ + + + + + + mips + + + + + + + + diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c index 2a383ab..79fa358 100644 --- a/gdb/mips-linux-nat.c +++ b/gdb/mips-linux-nat.c @@ -27,10 +27,13 @@ #include "regcache.h" #include "linux-nat.h" #include "mips-linux-tdep.h" +#include "target-descriptions.h" +#include "xml-support.h" #include "gdb_proc_service.h" #include "gregset.h" +#include #include #ifndef PTRACE_GET_THREAD_AREA @@ -81,6 +84,8 @@ mips_linux_register_addr (struct gdbarch *gdbarch, int regno, int store) regaddr = FPC_CSR; else if (regno == mips_regnum (gdbarch)->fp_implementation_revision) regaddr = store? (CORE_ADDR) -1 : FPC_EIR; + else if (mips_linux_restart_reg_p (gdbarch) && regno == MIPS_RESTART_REGNUM) + regaddr = 0; else regaddr = (CORE_ADDR) -1; @@ -114,6 +119,8 @@ mips64_linux_register_addr (struct gdbarch *gdbarch, int regno, int store) regaddr = MIPS64_FPC_CSR; else if (regno == mips_regnum (gdbarch)->fp_implementation_revision) regaddr = store? (CORE_ADDR) -1 : MIPS64_FPC_EIR; + else if (mips_linux_restart_reg_p (gdbarch) && regno == MIPS_RESTART_REGNUM) + regaddr = 0; else regaddr = (CORE_ADDR) -1; @@ -335,6 +342,36 @@ mips_linux_register_u_offset (struct gdbarch *gdbarch, int regno, int store_p) return mips_linux_register_addr (gdbarch, regno, store_p); } +static LONGEST (*super_xfer_partial) (struct target_ops *, enum target_object, + const char *, gdb_byte *, const gdb_byte *, + ULONGEST, LONGEST); + +static LONGEST +mips_linux_xfer_partial (struct target_ops *ops, + enum target_object object, + const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + if (object == TARGET_OBJECT_AVAILABLE_FEATURES) + { + if (annex != NULL && strcmp (annex, "target.xml") == 0) + { + /* Report that target registers are a size we know for sure + that we can get from ptrace. */ + if (_MIPS_SIM == _ABIO32) + annex = "mips-linux.xml"; + else + annex = "mips64-linux.xml"; + } + + return xml_builtin_xfer_partial (annex, readbuf, writebuf, offset, len); + } + + return super_xfer_partial (ops, object, annex, readbuf, writebuf, + offset, len); +} + void _initialize_mips_linux_nat (void); void @@ -348,5 +385,9 @@ _initialize_mips_linux_nat (void) t->to_fetch_registers = mips64_linux_fetch_registers; t->to_store_registers = mips64_linux_store_registers; + /* Override the default to_xfer_partial. */ + super_xfer_partial = t->to_xfer_partial; + t->to_xfer_partial = mips_linux_xfer_partial; + linux_nat_add_target (t); } diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c index 8b851f3..b16fc53 100644 --- a/gdb/mips-linux-tdep.c +++ b/gdb/mips-linux-tdep.c @@ -37,6 +37,7 @@ #include "solib-svr4.h" #include "solist.h" #include "symtab.h" +#include "target-descriptions.h" #include "mips-linux-tdep.h" static struct target_so_ops mips_svr4_so_ops; @@ -96,9 +97,12 @@ mips_supply_gregset (struct regcache *regcache, memset (zerobuf, 0, MAX_REGISTER_SIZE); - for (regi = EF_REG0; regi <= EF_REG31; regi++) + for (regi = EF_REG0 + 1; regi <= EF_REG31; regi++) supply_32bit_reg (regcache, regi - EF_REG0, regp + regi); + if (mips_linux_restart_reg_p (current_gdbarch)) + supply_32bit_reg (regcache, MIPS_RESTART_REGNUM, regp + EF_REG0); + supply_32bit_reg (regcache, mips_regnum (current_gdbarch)->lo, regp + EF_LO); supply_32bit_reg (regcache, mips_regnum (current_gdbarch)->hi, @@ -113,9 +117,10 @@ mips_supply_gregset (struct regcache *regcache, regp + EF_CP0_CAUSE); /* Fill inaccessible registers with zero. */ + regcache_raw_supply (regcache, MIPS_ZERO_REGNUM, zerobuf); regcache_raw_supply (regcache, MIPS_UNUSED_REGNUM, zerobuf); for (regi = MIPS_FIRST_EMBED_REGNUM; - regi < MIPS_LAST_EMBED_REGNUM; + regi <= MIPS_LAST_EMBED_REGNUM; regi++) regcache_raw_supply (regcache, regi, zerobuf); } @@ -133,7 +138,7 @@ mips_fill_gregset (const struct regcache *regcache, if (regno == -1) { memset (regp, 0, sizeof (mips_elf_gregset_t)); - for (regi = 0; regi < 32; regi++) + for (regi = 1; regi < 32; regi++) mips_fill_gregset (regcache, gregsetp, regi); mips_fill_gregset (regcache, gregsetp, mips_regnum (current_gdbarch)->lo); @@ -146,10 +151,11 @@ mips_fill_gregset (const struct regcache *regcache, mips_fill_gregset (regcache, gregsetp, MIPS_PS_REGNUM); mips_fill_gregset (regcache, gregsetp, mips_regnum (current_gdbarch)->cause); + mips_fill_gregset (regcache, gregsetp, MIPS_RESTART_REGNUM); return; } - if (regno < 32) + if (regno > 0 && regno < 32) { dst = regp + regno + EF_REG0; regcache_raw_collect (regcache, regno, dst); @@ -168,6 +174,9 @@ mips_fill_gregset (const struct regcache *regcache, regaddr = EF_CP0_STATUS; else if (regno == mips_regnum (current_gdbarch)->cause) regaddr = EF_CP0_CAUSE; + else if (mips_linux_restart_reg_p (current_gdbarch) + && regno == MIPS_RESTART_REGNUM) + regaddr = EF_REG0; else regaddr = -1; @@ -294,10 +303,14 @@ mips64_supply_gregset (struct regcache *regcache, memset (zerobuf, 0, MAX_REGISTER_SIZE); - for (regi = MIPS64_EF_REG0; regi <= MIPS64_EF_REG31; regi++) + for (regi = MIPS64_EF_REG0 + 1; regi <= MIPS64_EF_REG31; regi++) supply_64bit_reg (regcache, regi - MIPS64_EF_REG0, (const gdb_byte *)(regp + regi)); + if (mips_linux_restart_reg_p (current_gdbarch)) + supply_64bit_reg (regcache, MIPS_RESTART_REGNUM, + (const gdb_byte *)(regp + MIPS64_EF_REG0)); + supply_64bit_reg (regcache, mips_regnum (current_gdbarch)->lo, (const gdb_byte *) (regp + MIPS64_EF_LO)); supply_64bit_reg (regcache, mips_regnum (current_gdbarch)->hi, @@ -313,9 +326,10 @@ mips64_supply_gregset (struct regcache *regcache, (const gdb_byte *) (regp + MIPS64_EF_CP0_CAUSE)); /* Fill inaccessible registers with zero. */ + regcache_raw_supply (regcache, MIPS_ZERO_REGNUM, zerobuf); regcache_raw_supply (regcache, MIPS_UNUSED_REGNUM, zerobuf); for (regi = MIPS_FIRST_EMBED_REGNUM; - regi < MIPS_LAST_EMBED_REGNUM; + regi <= MIPS_LAST_EMBED_REGNUM; regi++) regcache_raw_supply (regcache, regi, zerobuf); } @@ -333,7 +347,7 @@ mips64_fill_gregset (const struct regcache *regcache, if (regno == -1) { memset (regp, 0, sizeof (mips64_elf_gregset_t)); - for (regi = 0; regi < 32; regi++) + for (regi = 1; regi < 32; regi++) mips64_fill_gregset (regcache, gregsetp, regi); mips64_fill_gregset (regcache, gregsetp, mips_regnum (current_gdbarch)->lo); @@ -346,10 +360,11 @@ mips64_fill_gregset (const struct regcache *regcache, mips64_fill_gregset (regcache, gregsetp, MIPS_PS_REGNUM); mips64_fill_gregset (regcache, gregsetp, mips_regnum (current_gdbarch)->cause); + mips64_fill_gregset (regcache, gregsetp, MIPS_RESTART_REGNUM); return; } - if (regno < 32) + if (regno > 0 && regno < 32) regaddr = regno + MIPS64_EF_REG0; else if (regno == mips_regnum (current_gdbarch)->lo) regaddr = MIPS64_EF_LO; @@ -363,6 +378,9 @@ mips64_fill_gregset (const struct regcache *regcache, regaddr = MIPS64_EF_CP0_STATUS; else if (regno == mips_regnum (current_gdbarch)->cause) regaddr = MIPS64_EF_CP0_CAUSE; + else if (mips_linux_restart_reg_p (current_gdbarch) + && regno == MIPS_RESTART_REGNUM) + regaddr = MIPS64_EF_REG0; else regaddr = -1; @@ -838,11 +856,11 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self, else regs_base = sigcontext_base; -#if 0 - trad_frame_set_reg_addr (this_cache, ORIG_ZERO_REGNUM - + gdbarch_num_regs (current_gdbarch), - regs_base + SIGCONTEXT_REGS); -#endif + if (mips_linux_restart_reg_p (current_gdbarch)) + trad_frame_set_reg_addr (this_cache, + (MIPS_RESTART_REGNUM + + gdbarch_num_regs (current_gdbarch)), + regs_base + SIGCONTEXT_REGS); for (ireg = 1; ireg < 32; ireg++) trad_frame_set_reg_addr (this_cache, @@ -988,12 +1006,11 @@ mips_linux_n32n64_sigframe_init (const struct tramp_frame *self, else sigcontext_base += N64_SIGFRAME_SIGCONTEXT_OFFSET; -#if 0 - trad_frame_set_reg_addr (this_cache, - ORIG_ZERO_REGNUM - + gdbarch_num_regs (current_gdbarch), - sigcontext_base + N64_SIGCONTEXT_REGS); -#endif + if (mips_linux_restart_reg_p (current_gdbarch)) + trad_frame_set_reg_addr (this_cache, + (MIPS_RESTART_REGNUM + + gdbarch_num_regs (current_gdbarch)), + sigcontext_base + N64_SIGCONTEXT_REGS); for (ireg = 1; ireg < 32; ireg++) trad_frame_set_reg_addr (this_cache, @@ -1036,6 +1053,30 @@ mips_linux_n32n64_sigframe_init (const struct tramp_frame *self, func)); } +static void +mips_linux_write_pc (CORE_ADDR pc, ptid_t ptid) +{ + write_register_pid (PC_REGNUM, pc, ptid); + + /* Clear the syscall restart flag. */ + if (mips_linux_restart_reg_p (current_gdbarch)) + write_register_pid (MIPS_RESTART_REGNUM, 0, ptid); +} + +/* Return 1 if MIPS_RESTART_REGNUM is usable. */ + +int +mips_linux_restart_reg_p (struct gdbarch *gdbarch) +{ + /* If we do not have a target description with registers, then + MIPS_RESTART_REGNUM will not be included in the register set. */ + if (!tdesc_has_registers (gdbarch_target_desc (gdbarch))) + return 0; + + /* If we do, then MIPS_RESTART_REGNUM is safe to check; it will + either be GPR-sized or missing. */ + return register_size (gdbarch, MIPS_RESTART_REGNUM) > 0; +} /* Initialize one of the GNU/Linux OS ABIs. */ @@ -1045,6 +1086,7 @@ mips_linux_init_abi (struct gdbarch_info info, { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); enum mips_abi abi = mips_abi (gdbarch); + struct tdesc_arch_data *tdesc_data = (void *) info.tdep_info; switch (abi) { @@ -1105,6 +1147,26 @@ mips_linux_init_abi (struct gdbarch_info info, = mips_linux_in_dynsym_resolve_code; } set_solib_ops (gdbarch, &mips_svr4_so_ops); + + set_gdbarch_write_pc (gdbarch, mips_linux_write_pc); + + if (tdesc_data) + { + const struct tdesc_feature *feature; + + /* If we have target-described registers, then we can safely + reserve a number for MIPS_RESTART_REGNUM (whether it is + described or not). */ + gdb_assert (gdbarch_num_regs (gdbarch) <= MIPS_RESTART_REGNUM); + set_gdbarch_num_regs (gdbarch, MIPS_RESTART_REGNUM + 1); + + /* If it's present, then assign it to the reserved number. */ + feature = tdesc_find_feature (info.target_desc, + "org.gnu.gdb.mips.linux"); + if (feature != NULL) + tdesc_numbered_register (feature, tdesc_data, MIPS_RESTART_REGNUM, + "restart"); + } } void diff --git a/gdb/mips-linux-tdep.h b/gdb/mips-linux-tdep.h index 213a745..764208a 100644 --- a/gdb/mips-linux-tdep.h +++ b/gdb/mips-linux-tdep.h @@ -92,3 +92,13 @@ void mips64_supply_gregset (struct regcache *, const mips64_elf_gregset_t *); void mips64_fill_gregset (const struct regcache *, mips64_elf_gregset_t *, int); void mips64_supply_fpregset (struct regcache *, const mips64_elf_fpregset_t *); void mips64_fill_fpregset (const struct regcache *, mips64_elf_fpregset_t *, int); + +enum { + /* The Linux kernel stores an error code from any interrupted + syscall in a "register" (in $0's save slot). */ + MIPS_RESTART_REGNUM = MIPS_LAST_EMBED_REGNUM + 1 +}; + +/* Return 1 if MIPS_RESTART_REGNUM is usable. */ + +int mips_linux_restart_reg_p (struct gdbarch *gdbarch); diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 72268fd..288d974 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -5457,6 +5457,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) mips_register_g_packet_guesses (gdbarch); /* Hook in OS ABI-specific overrides, if they have been registered. */ + info.tdep_info = (void *) tdesc_data; gdbarch_init_osabi (info, gdbarch); /* Unwind the frame. */ -- 2.7.4