From patchwork Thu May 21 23:19:13 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pedro Alves X-Patchwork-Id: 6878 Received: (qmail 114522 invoked by alias); 21 May 2015 23:50:10 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 114506 invoked by uid 89); 21 May 2015 23:50:09 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.5 required=5.0 tests=AWL, BAYES_20, KAM_LAZY_DOMAIN_SECURITY, SPF_HELO_PASS, T_RP_MATCHES_RCVD autolearn=no version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Thu, 21 May 2015 23:50:08 +0000 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t4LNJXYW006446 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Thu, 21 May 2015 19:19:33 -0400 Received: from brno.lan (ovpn01.gateway.prod.ext.ams2.redhat.com [10.39.146.11]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t4LNJEJF027592 for ; Thu, 21 May 2015 19:19:32 -0400 From: Pedro Alves To: gdb-patches@sourceware.org Subject: [PATCH 17/18] S/390: displaced stepping and PC-relative RIL-b/RIL-c instructions Date: Fri, 22 May 2015 00:19:13 +0100 Message-Id: <1432250354-2721-18-git-send-email-palves@redhat.com> In-Reply-To: <1432250354-2721-1-git-send-email-palves@redhat.com> References: <1432250354-2721-1-git-send-email-palves@redhat.com> 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-05-21 Pedro Alves * 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. v4: - No changes. v3: - No changes. --- gdb/s390-linux-tdep.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 3 deletions(-) diff --git a/gdb/s390-linux-tdep.c b/gdb/s390-linux-tdep.c index edc0da1..2fa65e8 100644 --- a/gdb/s390-linux-tdep.c +++ b/gdb/s390-linux-tdep.c @@ -1540,6 +1540,116 @@ s390_in_function_epilogue_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 @@ -1548,8 +1658,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);