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.
This commit is contained in:
parent
4ea0266c22
commit
dcb84eda0c
2 changed files with 11 additions and 51 deletions
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Reference in a new issue