[binutils-gdb] s390: Fix displaced-stepping certain relative branch insns

Andreas Arnez arnez@sourceware.org
Mon Mar 20 16:31:00 GMT 2017


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

commit dcb84eda0c5f25835251a311c4d6704e70cfa498
Author: Andreas Arnez <arnez@linux.vnet.ibm.com>
Date:   Mon Mar 20 17:30:01 2017 +0100

    s390: Fix displaced-stepping certain relative branch insns
    
    On s390x targets GDB can not handle displaced stepping correctly for some
    relative branch instructions, such as cij (compare immediate and branch
    relative).  When setting a breakpoint on such an instruction and
    single-stepping over it, the branch is never taken.  This is because the
    check in s390_displaced_step_fixup for relative branch instructions is
    incomplete.
    
    Instead of completing the list of relative branch instructions to check
    against, this patch just treats relative branches and non-branching
    instructions in the same way and adjusts the PC with the negated
    displacement in both cases.
    
    gdb/ChangeLog:
    
    	* s390-linux-tdep.c (is_rsi, is_rie): Remove functions.
    	(s390_displaced_step_fixup): Cover relative branches with the
    	default fixup handling.  This fixes lack of support for some
    	relative branch instructions.

Diff:
---
 gdb/ChangeLog         |  7 +++++++
 gdb/s390-linux-tdep.c | 55 ++++-----------------------------------------------
 2 files changed, 11 insertions(+), 51 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 9061347..2cff118 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,10 @@
+2017-03-20  Andreas Arnez  <arnez@linux.vnet.ibm.com>
+
+	* s390-linux-tdep.c (is_rsi, is_rie): Remove functions.
+	(s390_displaced_step_fixup): Cover relative branches with the
+	default fixup handling.  This fixes lack of support for some
+	relative branch instructions.
+
 2017-03-17  Simon Marchi  <simon.marchi@polymtl.ca>
 
 	* i386-gnu-nat.c (gnu_fetch_registers, gnu_store_registers): Use
diff --git a/gdb/s390-linux-tdep.c b/gdb/s390-linux-tdep.c
index abc9438..2af2c7a 100644
--- a/gdb/s390-linux-tdep.c
+++ b/gdb/s390-linux-tdep.c
@@ -1212,41 +1212,6 @@ is_rsy (bfd_byte *insn, int op1, int op2,
 
 
 static int
-is_rsi (bfd_byte *insn, int op,
-	unsigned int *r1, unsigned int *r3, int *i2)
-{
-  if (insn[0] == op)
-    {
-      *r1 = (insn[1] >> 4) & 0xf;
-      *r3 = insn[1] & 0xf;
-      /* i2 is a 16-bit signed quantity.  */
-      *i2 = (((insn[2] << 8) | insn[3]) ^ 0x8000) - 0x8000;
-      return 1;
-    }
-  else
-    return 0;
-}
-
-
-static int
-is_rie (bfd_byte *insn, int op1, int op2,
-	unsigned int *r1, unsigned int *r3, int *i2)
-{
-  if (insn[0] == op1
-      && insn[5] == op2)
-    {
-      *r1 = (insn[1] >> 4) & 0xf;
-      *r3 = insn[1] & 0xf;
-      /* i2 is a 16-bit signed quantity.  */
-      *i2 = (((insn[2] << 8) | insn[3]) ^ 0x8000) - 0x8000;
-      return 1;
-    }
-  else
-    return 0;
-}
-
-
-static int
 is_rx (bfd_byte *insn, int op,
        unsigned int *r1, int *d2, unsigned int *x2, unsigned int *b2)
 {
@@ -1976,20 +1941,6 @@ s390_displaced_step_fixup (struct gdbarch *gdbarch,
 				      amode | (from + insnlen));
     }
 
-  /* Handle PC-relative branch instructions.  */
-  else if (is_ri (insn, op1_brc, op2_brc, &r1, &i2)
-	   || is_ril (insn, op1_brcl, op2_brcl, &r1, &i2)
-	   || is_ri (insn, op1_brct, op2_brct, &r1, &i2)
-	   || is_ri (insn, op1_brctg, op2_brctg, &r1, &i2)
-	   || is_rsi (insn, op_brxh, &r1, &r3, &i2)
-	   || is_rie (insn, op1_brxhg, op2_brxhg, &r1, &r3, &i2)
-	   || is_rsi (insn, op_brxle, &r1, &r3, &i2)
-	   || is_rie (insn, op1_brxlg, op2_brxlg, &r1, &r3, &i2))
-    {
-      /* Update PC.  */
-      regcache_write_pc (regs, pc - to + from);
-    }
-
   /* Handle LOAD ADDRESS RELATIVE LONG.  */
   else if (is_ril (insn, op1_larl, op2_larl, &r1, &i2))
     {
@@ -2004,9 +1955,11 @@ s390_displaced_step_fixup (struct gdbarch *gdbarch,
   else if (insn[0] == 0x0 && insn[1] == 0x1)
     regcache_write_pc (regs, from);
 
-  /* For any other insn, PC points right after the original instruction.  */
+  /* For any other insn, adjust PC by negated displacement.  PC then
+     points right after the original instruction, except for PC-relative
+     branches, where it points to the adjusted branch target.  */
   else
-    regcache_write_pc (regs, from + insnlen);
+    regcache_write_pc (regs, pc - to + from);
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog,



More information about the Gdb-cvs mailing list