aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog22
-rw-r--r--gdb/Makefile.in6
-rw-r--r--gdb/config/mips/linux.mh9
-rw-r--r--gdb/doc/ChangeLog4
-rw-r--r--gdb/doc/gdb.texinfo4
-rw-r--r--gdb/features/mips-linux.xml18
-rw-r--r--gdb/features/mips64-linux.xml18
-rw-r--r--gdb/mips-linux-nat.c41
-rw-r--r--gdb/mips-linux-tdep.c100
-rw-r--r--gdb/mips-linux-tdep.h10
-rw-r--r--gdb/mips-tdep.c1
11 files changed, 212 insertions, 21 deletions
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 <dan@codesourcery.com>
+ * 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 <dan@codesourcery.com>
+
* 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 <dan@codesourcery.com>
+ * gdb.texinfo (MIPS Features): Document org.gnu.gdb.mips.linux.
+
+2007-06-13 Daniel Jacobowitz <dan@codesourcery.com>
+
* gdb.texinfo (MIPS Features): New subsection.
2007-06-12 Ulrich Weigand <uweigand@de.ibm.com>
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 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+ <architecture>mips</architecture>
+ <xi:include href="mips-cpu.xml"/>
+ <xi:include href="mips-cp0.xml"/>
+ <xi:include href="mips-fpu.xml"/>
+
+ <feature name="org.gnu.gdb.mips.linux">
+ <reg name="restart" bitsize="32" group="system"/>
+ </feature>
+</target>
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 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+ <architecture>mips</architecture>
+ <xi:include href="mips64-cpu.xml"/>
+ <xi:include href="mips64-cp0.xml"/>
+ <xi:include href="mips64-fpu.xml"/>
+
+ <feature name="org.gnu.gdb.mips.linux">
+ <reg name="restart" bitsize="64" group="system"/>
+ </feature>
+</target>
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 <sgidefs.h>
#include <sys/ptrace.h>
#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. */