mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-21 01:12:32 +08:00
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.
This commit is contained in:
parent
7f03bd92e3
commit
5ac213430b
@ -1,3 +1,11 @@
|
||||
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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user