From patchwork Tue Apr 7 12:49:30 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pedro Alves X-Patchwork-Id: 6046 Received: (qmail 130010 invoked by alias); 7 Apr 2015 12:50:00 -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 129895 invoked by uid 89); 7 Apr 2015 12:50:00 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.0 required=5.0 tests=AWL, BAYES_00, SPF_HELO_PASS, SPF_PASS, T_RP_MATCHES_RCVD autolearn=ham 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; Tue, 07 Apr 2015 12:49:57 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (Postfix) with ESMTPS id C6361385900 for ; Tue, 7 Apr 2015 12:49:55 +0000 (UTC) Received: from brno.lan (ovpn01.gateway.prod.ext.ams2.redhat.com [10.39.146.11]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t37Cnown022139 for ; Tue, 7 Apr 2015 08:49:55 -0400 From: Pedro Alves To: gdb-patches@sourceware.org Subject: [PATCH v2 03/23] PR13858 - Can't do displaced stepping with no symbols Date: Tue, 7 Apr 2015 13:49:30 +0100 Message-Id: <1428410990-28560-4-git-send-email-palves@redhat.com> In-Reply-To: <1428410990-28560-1-git-send-email-palves@redhat.com> References: <1428410990-28560-1-git-send-email-palves@redhat.com> Running break-interp.exp with the target always in non-stop mode trips on PR13858, as enabling non-stop also enables displaced stepping. The problem is that when GDB doesn't know where the entry point is, it doesn't know where to put the displaced stepping scratch pad. The test added by this commit exercises this. Without the fix, we get: (gdb) PASS: gdb.base/step-over-no-symbols.exp: displaced=on: break *$pc set displaced-stepping on (gdb) PASS: gdb.base/step-over-no-symbols.exp: displaced=on: set displaced-stepping on stepi 0x00000000004005be in ?? () Entry point address is not known. (gdb) PASS: gdb.base/step-over-no-symbols.exp: displaced=on: stepi p /x $pc $2 = 0x4005be (gdb) PASS: gdb.base/step-over-no-symbols.exp: displaced=on: get after PC FAIL: gdb.base/step-over-no-symbols.exp: displaced=on: advanced The fix is to fall back to stepping over the breakpoint in-line if we don't know where the entry point address is. This is enough to fix all-stop + "set displaced on". For non-stop, we'll need to teach core gdb to pause all threads to be able to start the in-line step-over (because then we need to remove the breakpoint from the target temporarily). gdb/ChangeLog: 2015-04-07 Pedro Alves PR gdb/13858 * infrun.c (use_displaced_stepping): Rename to ... (can_use_displaced_stepping_p): ... this. (use_displaced_stepping_now_p): New function. (resume): Clear trap_expected if waiting for vfork-done. Use use_displaced_stepping_now_p. (keep_going): Use use_displaced_stepping_now_p now. gdb/testsuite/ 2015-04-07 Pedro Alves PR gdb/13858 * gdb.base/step-over-no-symbols.exp: New file. --- gdb/infrun.c | 83 +++++++++++++---------- gdb/testsuite/gdb.base/step-over-no-symbols.exp | 88 +++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 33 deletions(-) create mode 100644 gdb/testsuite/gdb.base/step-over-no-symbols.exp diff --git a/gdb/infrun.c b/gdb/infrun.c index 466bc4a..48da790 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1581,7 +1581,7 @@ show_can_use_displaced_stepping (struct ui_file *file, int from_tty, over breakpoints. */ static int -use_displaced_stepping (struct gdbarch *gdbarch) +can_use_displaced_stepping_p (struct gdbarch *gdbarch) { return (((can_use_displaced_stepping == AUTO_BOOLEAN_AUTO && non_stop) || can_use_displaced_stepping == AUTO_BOOLEAN_TRUE) @@ -1589,6 +1589,24 @@ use_displaced_stepping (struct gdbarch *gdbarch) && find_record_target () == NULL); } +/* Return non-zero if displaced stepping should be used to step + over a breakpoint in the current thread. */ + +static int +use_displaced_stepping_now_p (struct gdbarch *gdbarch, + enum gdb_signal sig) +{ + CORE_ADDR retval; + + /* We can't use displaced stepping when we have a signal to deliver; + the comments for displaced_step_prepare explain why. The + comments in the handle_inferior event for dealing with 'random + signals' explain what we do instead. */ + return (sig == GDB_SIGNAL_0 + && can_use_displaced_stepping_p (gdbarch) + && entry_point_address_query (&retval)); +} + /* Clean out any stray displaced stepping state. */ static void displaced_step_clear (struct displaced_step_inferior_state *displaced) @@ -2140,6 +2158,10 @@ resume (enum gdb_signal sig) fprintf_unfiltered (gdb_stdlog, "infrun: resume : clear step\n"); step = 0; + + /* Likewise, make sure we don't use displaced stepping, which + would poke the scratch buffer in the child. */ + tp->control.trap_expected = 0; } if (debug_infrun) @@ -2235,20 +2257,8 @@ resume (enum gdb_signal sig) tp->control.may_range_step = 0; /* If enabled, step over breakpoints by executing a copy of the - instruction at a different address. - - We can't use displaced stepping when we have a signal to deliver; - the comments for displaced_step_prepare explain why. The - comments in the handle_inferior event for dealing with 'random - signals' explain what we do instead. - - We can't use displaced stepping when we are waiting for vfork_done - event, displaced stepping breaks the vfork child similarly as single - step software breakpoint. */ - if (use_displaced_stepping (gdbarch) - && tp->control.trap_expected - && sig == GDB_SIGNAL_0 - && !current_inferior ()->waiting_for_vfork_done) + instruction at a different address. */ + if (tp->control.trap_expected && use_displaced_stepping_now_p (gdbarch, sig)) { struct displaced_step_inferior_state *displaced; @@ -2391,8 +2401,8 @@ resume (enum gdb_signal sig) } if (debug_displaced - && use_displaced_stepping (gdbarch) - && tp->control.trap_expected) + && tp->control.trap_expected + && use_displaced_stepping_now_p (gdbarch, sig)) { struct regcache *resume_regcache = get_thread_regcache (tp->ptid); struct gdbarch *resume_gdbarch = get_regcache_arch (resume_regcache); @@ -2707,7 +2717,9 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) displaced stepping to do so, insert all breakpoints (watchpoints, etc.) but the one we're stepping over, step one instruction, and then re-insert the breakpoint when that step is finished. */ - if (tp->stepping_over_breakpoint && !use_displaced_stepping (gdbarch)) + if (tp->stepping_over_breakpoint + && !use_displaced_stepping_now_p (gdbarch, + tp->suspend.stop_signal)) { struct regcache *regcache = get_current_regcache (); @@ -6255,6 +6267,7 @@ keep_going (struct execution_control_state *ecs) struct regcache *regcache = get_current_regcache (); int remove_bp; int remove_wps; + enum gdb_signal signo; /* Either the trap was not expected, but we are continuing anyway (if we got a signal, the user asked it be passed to @@ -6280,7 +6293,25 @@ keep_going (struct execution_control_state *ecs) remove_wps = (ecs->event_thread->stepping_over_watchpoint && !target_have_steppable_watchpoint); - if (remove_bp && !use_displaced_stepping (get_regcache_arch (regcache))) + /* Do not deliver GDB_SIGNAL_TRAP (except when the user + explicitly specifies that such a signal should be delivered + to the target program). Typically, that would occur when a + user is debugging a target monitor on a simulator: the target + monitor sets a breakpoint; the simulator encounters this + breakpoint and halts the simulation handing control to GDB; + GDB, noting that the stop address doesn't map to any known + breakpoint, returns control back to the simulator; the + simulator then delivers the hardware equivalent of a + GDB_SIGNAL_TRAP to the program being debugged. */ + if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP + && !signal_program[ecs->event_thread->suspend.stop_signal]) + ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0; + + signo = ecs->event_thread->suspend.stop_signal; + + if (remove_bp + && !use_displaced_stepping_now_p (get_regcache_arch (regcache), + signo)) { set_step_over_info (get_regcache_aspace (regcache), regcache_read_pc (regcache), remove_wps); @@ -6306,20 +6337,6 @@ keep_going (struct execution_control_state *ecs) ecs->event_thread->control.trap_expected = (remove_bp || remove_wps); - /* Do not deliver GDB_SIGNAL_TRAP (except when the user - explicitly specifies that such a signal should be delivered - to the target program). Typically, that would occur when a - user is debugging a target monitor on a simulator: the target - monitor sets a breakpoint; the simulator encounters this - breakpoint and halts the simulation handing control to GDB; - GDB, noting that the stop address doesn't map to any known - breakpoint, returns control back to the simulator; the - simulator then delivers the hardware equivalent of a - GDB_SIGNAL_TRAP to the program being debugged. */ - if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP - && !signal_program[ecs->event_thread->suspend.stop_signal]) - ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0; - discard_cleanups (old_cleanups); resume (ecs->event_thread->suspend.stop_signal); } diff --git a/gdb/testsuite/gdb.base/step-over-no-symbols.exp b/gdb/testsuite/gdb.base/step-over-no-symbols.exp new file mode 100644 index 0000000..d7bfd64 --- /dev/null +++ b/gdb/testsuite/gdb.base/step-over-no-symbols.exp @@ -0,0 +1,88 @@ +# Copyright (C) 2015 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Test that GDB can step past a breakpoint even if GDB doesn't have +# symbols for the main binary. + +standard_testfile start.c + +if { ![support_displaced_stepping] } { + unsupported "displaced stepping" + return -1 +} + +if { [build_executable "failed to build" ${testfile} $srcfile] } { + return -1 +} + +# Get the current PC. MSG is used as test message. + +proc get_pc { msg } { + global hex gdb_prompt + + set addr "" + gdb_test_multiple "p /x \$pc" "$msg" { + -re " = ($hex).*$gdb_prompt $" { + set addr $expect_out(1,string) + pass "$msg" + } + } + + return $addr +} + +# Test stepping past a breakpoint with no symbols. DISPLACED is one +# of the "set displaced-stepping" options. GDB should be able to fall +# back to stepping past the breakpoint using an in-line step-over. + +proc test_step_over {displaced} { + global hex + global binfile + + clean_restart $binfile + + if ![runto_main] { + fail "couldn't run to main" + untested "stepping over breakpoint with displaced=$displaced" + return -1 + } + + delete_breakpoints + + set msg "purging symbols" + gdb_test_multiple "symbol-file" "$msg" { + -re "Discard symbol table.*y or n. $" { + gdb_test "y" "No symbol file now." "$msg" + } + } + + set before_addr [get_pc "get before PC"] + + gdb_test "break *\$pc" "Breakpoint .* at $hex" + + gdb_test_no_output "set displaced-stepping $displaced" + + gdb_test "stepi" "$hex in \?\? .*" + + set after_addr [get_pc "get after PC"] + + gdb_assert {$before_addr != $after_addr} "advanced" +} + +foreach displaced { "off" "on" "auto" } { + with_test_prefix "displaced=$displaced" { + test_step_over $displaced + } +}