This is the mail archive of the gdb-cvs@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb] S/390: displaced stepping and PC-relative RIL-b/RIL-c instructions


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=5ac213430b710e8aaed1f4cea6ff809783201df9

commit 5ac213430b710e8aaed1f4cea6ff809783201df9
Author: Pedro Alves <palves@redhat.com>
Date:   Thu Aug 6 18:23:01 2015 +0100

    S/390: displaced stepping and PC-relative RIL-b/RIL-c instructions
    
    This adds displaced stepping support for the General-Instruction
    Extension Facility instructions, which have a PC-relative displacement
    (RIL-b/RIL-c).  We already handle RIL branches, but not others.
    
    Currently, displaced stepping a breakpoint put on any of these
    instructions results in the inferior crashing when or after the
    instruction is executed out-of-line in the scratch pad.
    
    This patch takes the easy route of patching the displacement in the
    copy of the instruction in the scratch pad.  As the displacement is a
    signed 32-bit field, it's possible that the stratch pad ends too far
    that the needed displacement doesn't fit in the adjusted instruction,
    as e.g., if stepping over a breakpoint in a shared library (the
    scratch pad is around the main program's entry point).  That case is
    detected and GDB falls back to stepping over the breakpoint in-line
    (which involves pausing all threads momentarily).
    
    (We could probably do something smarter, but I don't plan on doing it
    myself.  This was already sufficient to get "maint set target-non-stop
    on" working regression free on S/390.)
    
    Tested on S/390 RHEL 7.1, where it fixes a few hundred FAILs when
    testing with displaced stepping force-enabled, with the end result
    being no regressions compared to a test run that doesn't force
    displaced stepping.  Fixes the non-stop tests compared to mainline
    too; most are crashing due to this on the machine I run tests on.
    
    gdb/ChangeLog:
    2015-08-07  Pedro Alves  <palves@redhat.com>
    
    	* s390-linux-tdep.c (is_non_branch_ril)
    	(s390_displaced_step_copy_insn): New functions.
    	(s390_displaced_step_fixup): Update comment.
    	(s390_gdbarch_init): Install s390_displaced_step_copy_insn as
    	gdbarch_displaced_step_copy_insn hook.

Diff:
---
 gdb/ChangeLog         |   8 ++++
 gdb/s390-linux-tdep.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 120 insertions(+), 3 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index af26b58..4c95b27 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,13 @@
 2015-08-07  Pedro Alves  <palves@redhat.com>
 
+	* s390-linux-tdep.c (is_non_branch_ril)
+	(s390_displaced_step_copy_insn): New functions.
+	(s390_displaced_step_fixup): Update comment.
+	(s390_gdbarch_init): Install s390_displaced_step_copy_insn as
+	gdbarch_displaced_step_copy_insn hook.
+
+2015-08-07  Pedro Alves  <palves@redhat.com>
+
 	* infrun.c (displaced_step_prepare_throw): Return -1 if
 	gdbarch_displaced_step_copy_insn returns NULL.  Update intro
 	comment.
diff --git a/gdb/s390-linux-tdep.c b/gdb/s390-linux-tdep.c
index 32a5ed6..1e20c92 100644
--- a/gdb/s390-linux-tdep.c
+++ b/gdb/s390-linux-tdep.c
@@ -1539,6 +1539,116 @@ s390_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
 
 /* Displaced stepping.  */
 
+/* Return true if INSN is a non-branch RIL-b or RIL-c format
+   instruction.  */
+
+static int
+is_non_branch_ril (gdb_byte *insn)
+{
+  gdb_byte op1 = insn[0];
+
+  if (op1 == 0xc4)
+    {
+      gdb_byte op2 = insn[1] & 0x0f;
+
+      switch (op2)
+	{
+	case 0x02: /* llhrl */
+	case 0x04: /* lghrl */
+	case 0x05: /* lhrl */
+	case 0x06: /* llghrl */
+	case 0x07: /* sthrl */
+	case 0x08: /* lgrl */
+	case 0x0b: /* stgrl */
+	case 0x0c: /* lgfrl */
+	case 0x0d: /* lrl */
+	case 0x0e: /* llgfrl */
+	case 0x0f: /* strl */
+	  return 1;
+	}
+    }
+  else if (op1 == 0xc6)
+    {
+      gdb_byte op2 = insn[1] & 0x0f;
+
+      switch (op2)
+	{
+	case 0x00: /* exrl */
+	case 0x02: /* pfdrl */
+	case 0x04: /* cghrl */
+	case 0x05: /* chrl */
+	case 0x06: /* clghrl */
+	case 0x07: /* clhrl */
+	case 0x08: /* cgrl */
+	case 0x0a: /* clgrl */
+	case 0x0c: /* cgfrl */
+	case 0x0d: /* crl */
+	case 0x0e: /* clgfrl */
+	case 0x0f: /* clrl */
+	  return 1;
+	}
+    }
+
+  return 0;
+}
+
+/* Implementation of gdbarch_displaced_step_copy_insn.  */
+
+static struct displaced_step_closure *
+s390_displaced_step_copy_insn (struct gdbarch *gdbarch,
+			       CORE_ADDR from, CORE_ADDR to,
+			       struct regcache *regs)
+{
+  size_t len = gdbarch_max_insn_length (gdbarch);
+  gdb_byte *buf = xmalloc (len);
+  struct cleanup *old_chain = make_cleanup (xfree, buf);
+
+  read_memory (from, buf, len);
+
+  /* Adjust the displacement field of PC-relative RIL instructions,
+     except branches.  The latter are handled in the fixup hook.  */
+  if (is_non_branch_ril (buf))
+    {
+      LONGEST offset;
+
+      offset = extract_signed_integer (buf + 2, 4, BFD_ENDIAN_BIG);
+      offset = (from - to + offset * 2) / 2;
+
+      /* If the instruction is too far from the jump pad, punt.  This
+	 will usually happen with instructions in shared libraries.
+	 We could probably support these by rewriting them to be
+	 absolute or fully emulating them.  */
+      if (offset < INT32_MIN || offset > INT32_MAX)
+	{
+	  /* Let the core fall back to stepping over the breakpoint
+	     in-line.  */
+	  if (debug_displaced)
+	    {
+	      fprintf_unfiltered (gdb_stdlog,
+				  "displaced: can't displaced step "
+				  "RIL instruction: offset %s out of range\n",
+				  plongest (offset));
+	    }
+	  do_cleanups (old_chain);
+	  return NULL;
+	}
+
+      store_signed_integer (buf + 2, 4, BFD_ENDIAN_BIG, offset);
+    }
+
+  write_memory (to, buf, len);
+
+  if (debug_displaced)
+    {
+      fprintf_unfiltered (gdb_stdlog, "displaced: copy %s->%s: ",
+                          paddress (gdbarch, from), paddress (gdbarch, to));
+      displaced_step_dump_bytes (gdb_stdlog, buf, len);
+    }
+
+  discard_cleanups (old_chain);
+  return (struct displaced_step_closure *) buf;
+}
+
 /* Fix up the state of registers and memory after having single-stepped
    a displaced instruction.  */
 static void
@@ -1547,8 +1657,7 @@ s390_displaced_step_fixup (struct gdbarch *gdbarch,
 			   CORE_ADDR from, CORE_ADDR to,
 			   struct regcache *regs)
 {
-  /* Since we use simple_displaced_step_copy_insn, our closure is a
-     copy of the instruction.  */
+  /* Our closure is a copy of the instruction.  */
   gdb_byte *insn = (gdb_byte *) closure;
   static int s390_instrlen[] = { 2, 4, 4, 6 };
   int insnlen = s390_instrlen[insn[0] >> 6];
@@ -3285,7 +3394,7 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   /* Displaced stepping.  */
   set_gdbarch_displaced_step_copy_insn (gdbarch,
-					simple_displaced_step_copy_insn);
+					s390_displaced_step_copy_insn);
   set_gdbarch_displaced_step_fixup (gdbarch, s390_displaced_step_fixup);
   set_gdbarch_displaced_step_free_closure (gdbarch,
 					   simple_displaced_step_free_closure);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]