MIPS software singlestep versus sigreturn syscall

Daniel Jacobowitz drow@false.org
Sun Jul 27 20:54:00 GMT 2008


Here's a refresh of a patch I posted in April 2005.

This patch lets mips32_next_pc call an architecure-specific hook to
work out the next PC for a SYSCALL instruction.  mips-linux supplies
the hook, and uses unwinding to find the resume address for a
sigreturn syscall.  This prevents a bogus breakpoint from being set in
the struct sigcontext when single-stepping out of a trampoline; in the
process, it fixes all of the easily fixable sigstep.exp failures on
mips-linux.

The remaining failures come from the fact that software single-step
can't be used to step into a signal handler.  We can work out in the
target code whether or not there is a signal handler, but not its
address.  Kernel changes to support this could be made; heck, we could
theoretically call sigaction () ourselves to find the address, but
that's above and beyond the call of duty - probably too complex to
bother with given the current state of GDB's execution control
mechanisms.

Tested on mips-linux and checked in.

-- 
Daniel Jacobowitz
CodeSourcery

2008-07-27  Daniel Jacobowitz  <dan@codesourcery.com>

	* mips-linux-tdep.c (mips_linux_syscall_next_pc): New function.
	(mips_linux_init_abi): Set tdep->syscall_next_pc.
	* mips-tdep.c (enum mips_fpu_type, struct gdbarch_tdep): Move to
	mips-tdep.h.
	(mips32_next_pc): Handle the syscall instruction.
	* mips-tdep.h (enum mips_fpu_type, struct gdbarch_tdep): New,
	from mips-tdep.c.  Add syscall_next_pc to gdbarch_tdep.

---
 gdb/mips-linux-tdep.c |   22 +++++++++++++++++++++
 gdb/mips-tdep.c       |   52 ++++++++++----------------------------------------
 gdb/mips-tdep.h       |   45 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 78 insertions(+), 41 deletions(-)

Index: gdb-only/gdb/mips-linux-tdep.c
===================================================================
--- gdb-only.orig/gdb/mips-linux-tdep.c	2008-07-26 14:45:53.000000000 -0400
+++ gdb-only/gdb/mips-linux-tdep.c	2008-07-26 14:50:16.000000000 -0400
@@ -1101,6 +1101,26 @@ mips_linux_restart_reg_p (struct gdbarch
   return register_size (gdbarch, MIPS_RESTART_REGNUM) > 0;
 }
 
+/* When FRAME is at a syscall instruction, return the PC of the next
+   instruction to be executed.  */
+
+CORE_ADDR
+mips_linux_syscall_next_pc (struct frame_info *frame)
+{
+  CORE_ADDR pc = get_frame_pc (frame);
+  ULONGEST v0 = get_frame_register_unsigned (frame, MIPS_V0_REGNUM);
+
+  /* If we are about to make a sigreturn syscall, use the unwinder to
+     decode the signal frame.  */
+  if (v0 == MIPS_NR_sigreturn
+      || v0 == MIPS_NR_rt_sigreturn
+      || v0 == MIPS_NR_N64_rt_sigreturn
+      || v0 == MIPS_NR_N32_rt_sigreturn)
+    return frame_pc_unwind (get_current_frame ());
+
+  return pc + 4;
+}
+
 /* Initialize one of the GNU/Linux OS ABIs.  */
 
 static void
@@ -1175,6 +1195,8 @@ mips_linux_init_abi (struct gdbarch_info
   set_gdbarch_core_read_description (gdbarch,
 				     mips_linux_core_read_description);
 
+  tdep->syscall_next_pc = mips_linux_syscall_next_pc;
+
   if (tdesc_data)
     {
       const struct tdesc_feature *feature;
Index: gdb-only/gdb/mips-tdep.c
===================================================================
--- gdb-only.orig/gdb/mips-tdep.c	2008-07-26 14:36:44.000000000 -0400
+++ gdb-only/gdb/mips-tdep.c	2008-07-26 14:45:01.000000000 -0400
@@ -142,16 +142,6 @@ const struct register_alias mips_registe
   { "fsr", MIPS_EMBED_FP0_REGNUM + 32 }
 };
 
-/* Some MIPS boards don't support floating point while others only
-   support single-precision floating-point operations.  */
-
-enum mips_fpu_type
-{
-  MIPS_FPU_DOUBLE,		/* Full double precision floating point.  */
-  MIPS_FPU_SINGLE,		/* Single precision floating point (R4650).  */
-  MIPS_FPU_NONE			/* No floating point.  */
-};
-
 #ifndef MIPS_DEFAULT_FPU_TYPE
 #define MIPS_DEFAULT_FPU_TYPE MIPS_FPU_DOUBLE
 #endif
@@ -168,37 +158,6 @@ static int mips_debug = 0;
 struct target_desc *mips_tdesc_gp32;
 struct target_desc *mips_tdesc_gp64;
 
-/* MIPS specific per-architecture information */
-struct gdbarch_tdep
-{
-  /* from the elf header */
-  int elf_flags;
-
-  /* mips options */
-  enum mips_abi mips_abi;
-  enum mips_abi found_abi;
-  enum mips_fpu_type mips_fpu_type;
-  int mips_last_arg_regnum;
-  int mips_last_fp_arg_regnum;
-  int default_mask_address_p;
-  /* Is the target using 64-bit raw integer registers but only
-     storing a left-aligned 32-bit value in each?  */
-  int mips64_transfers_32bit_regs_p;
-  /* Indexes for various registers.  IRIX and embedded have
-     different values.  This contains the "public" fields.  Don't
-     add any that do not need to be public.  */
-  const struct mips_regnum *regnum;
-  /* Register names table for the current register set.  */
-  const char **mips_processor_reg_names;
-
-  /* The size of register data available from the target, if known.
-     This doesn't quite obsolete the manual
-     mips64_transfers_32bit_regs_p, since that is documented to force
-     left alignment even for big endian (very strange).  */
-  int register_size_valid_p;
-  int register_size;
-};
-
 const struct mips_regnum *
 mips_regnum (struct gdbarch *gdbarch)
 {
@@ -1018,6 +977,17 @@ mips32_next_pc (struct frame_info *frame
 	      /* Set PC to that address */
 	      pc = get_frame_register_signed (frame, rtype_rs (inst));
 	      break;
+	    case 12:            /* SYSCALL */
+	      {
+		struct gdbarch_tdep *tdep;
+
+		tdep = gdbarch_tdep (get_frame_arch (frame));
+		if (tdep->syscall_next_pc != NULL)
+		  pc = tdep->syscall_next_pc (frame);
+		else
+		  pc += 4;
+	      }
+	      break;
 	    default:
 	      pc += 4;
 	    }
Index: gdb-only/gdb/mips-tdep.h
===================================================================
--- gdb-only.orig/gdb/mips-tdep.h	2008-07-26 14:36:42.000000000 -0400
+++ gdb-only/gdb/mips-tdep.h	2008-07-26 14:42:08.000000000 -0400
@@ -56,6 +56,51 @@ struct mips_regnum
 };
 extern const struct mips_regnum *mips_regnum (struct gdbarch *gdbarch);
 
+/* Some MIPS boards don't support floating point while others only
+   support single-precision floating-point operations.  */
+
+enum mips_fpu_type
+{
+  MIPS_FPU_DOUBLE,		/* Full double precision floating point.  */
+  MIPS_FPU_SINGLE,		/* Single precision floating point (R4650).  */
+  MIPS_FPU_NONE			/* No floating point.  */
+};
+
+/* MIPS specific per-architecture information */
+struct gdbarch_tdep
+{
+  /* from the elf header */
+  int elf_flags;
+
+  /* mips options */
+  enum mips_abi mips_abi;
+  enum mips_abi found_abi;
+  enum mips_fpu_type mips_fpu_type;
+  int mips_last_arg_regnum;
+  int mips_last_fp_arg_regnum;
+  int default_mask_address_p;
+  /* Is the target using 64-bit raw integer registers but only
+     storing a left-aligned 32-bit value in each?  */
+  int mips64_transfers_32bit_regs_p;
+  /* Indexes for various registers.  IRIX and embedded have
+     different values.  This contains the "public" fields.  Don't
+     add any that do not need to be public.  */
+  const struct mips_regnum *regnum;
+  /* Register names table for the current register set.  */
+  const char **mips_processor_reg_names;
+
+  /* The size of register data available from the target, if known.
+     This doesn't quite obsolete the manual
+     mips64_transfers_32bit_regs_p, since that is documented to force
+     left alignment even for big endian (very strange).  */
+  int register_size_valid_p;
+  int register_size;
+
+  /* Return the expected next PC if FRAME is stopped at a syscall
+     instruction.  */
+  CORE_ADDR (*syscall_next_pc) (struct frame_info *frame);
+};
+
 /* Register numbers of various important registers.  */
 
 enum



More information about the Gdb-patches mailing list