From dcb84eda0c5f25835251a311c4d6704e70cfa498 Mon Sep 17 00:00:00 2001 From: Andreas Arnez Date: Mon, 20 Mar 2017 17:30:01 +0100 Subject: [PATCH] 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. --- 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 9061347967..2cff118773 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +2017-03-20 Andreas Arnez + + * 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 * 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 abc9438cd7..2af2c7a313 100644 --- a/gdb/s390-linux-tdep.c +++ b/gdb/s390-linux-tdep.c @@ -1211,41 +1211,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, -- 2.34.1