public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Pedro Alves <palves@redhat.com>
To: gdb-patches@sourceware.org
Subject: [PATCH v2 01/23] Fix gdb.base/sigstep.exp with displaced stepping on software single-step targets
Date: Tue, 07 Apr 2015 12:50:00 -0000	[thread overview]
Message-ID: <1428410990-28560-2-git-send-email-palves@redhat.com> (raw)
In-Reply-To: <1428410990-28560-1-git-send-email-palves@redhat.com>

TL;DR:

When stepping over a breakpoint with displaced stepping, the core must
be notified of all signals, otherwise the displaced step fixup code
confuses a breakpoint trap in the signal handler for the expected trap
indicating the displaced instruction was single-stepped
normally/successfully.

Detailed version:

Running sigstep.exp with displaced stepping on, against my x86
software single-step branch, I got:

 FAIL: gdb.base/sigstep.exp: step on breakpoint, to handler: performing step
 FAIL: gdb.base/sigstep.exp: next on breakpoint, to handler: performing next
 FAIL: gdb.base/sigstep.exp: continue on breakpoint, to handler: performing continue

Turning on debug logs, we see:

 (gdb) step
 infrun: clear_proceed_status_thread (process 32147)
 infrun: proceed (addr=0xffffffffffffffff, signal=GDB_SIGNAL_DEFAULT)
 infrun: resume (step=1, signal=GDB_SIGNAL_0), trap_expected=1, current thread [process 32147] at 0x400842
 displaced: stepping process 32147 now
 displaced: saved 0x400622: 49 89 d1 5e 48 89 e2 48 83 e4 f0 50 54 49 c7 c0
 displaced: %rip-relative addressing used.
 displaced: using temp reg 2, old value 0x3615eafd37, new value 0x40084c
 displaced: copy 0x400842->0x400622: c7 81 1c 08 20 00 00 00 00 00
 displaced: displaced pc to 0x400622
 displaced: run 0x400622: c7 81 1c 08
 LLR: Preparing to resume process 32147, 0, inferior_ptid process 32147
 LLR: PTRACE_CONT process 32147, 0 (resume event thread)
 linux_nat_wait: [process -1], [TARGET_WNOHANG]
 LLW: enter
 LNW: waitpid(-1, ...) returned 32147, No child processes
 LLW: waitpid 32147 received Alarm clock (stopped)
 LLW: PTRACE_CONT process 32147, Alarm clock (preempt 'handle')
 LNW: waitpid(-1, ...) returned 0, No child processes
 LLW: exit (ignore)
 sigchld
 infrun: target_wait (-1.0.0, status) =
 infrun:   -1.0.0 [process -1],
 infrun:   status->kind = ignore
 infrun: TARGET_WAITKIND_IGNORE
 infrun: prepare_to_wait
 linux_nat_wait: [process -1], [TARGET_WNOHANG]
 LLW: enter
 LNW: waitpid(-1, ...) returned 32147, No child processes
 LLW: waitpid 32147 received Trace/breakpoint trap (stopped)
 CSBB: process 32147 stopped by software breakpoint
 LNW: waitpid(-1, ...) returned 0, No child processes
 LLW: trap ptid is process 32147.
 LLW: exit
 infrun: target_wait (-1.0.0, status) =
 infrun:   32147.32147.0 [process 32147],
 infrun:   status->kind = stopped, signal = GDB_SIGNAL_TRAP
 infrun: TARGET_WAITKIND_STOPPED
 displaced: restored process 32147 0x400622
 displaced: fixup (0x400842, 0x400622), insn = 0xc7 0x81 ...
 displaced: restoring reg 2 to 0x3615eafd37
 displaced: relocated %rip from 0x400717 to 0x400937
 infrun: stop_pc = 0x400937
 infrun: delayed software breakpoint trap, ignoring
 infrun: no line number info
 infrun: stop_waiting
 0x0000000000400937 in __dso_handle ()
 1: x/i $pc
 => 0x400937:    and    %ah,0xa0d64(%rip)        # 0x4a16a1
 (gdb) FAIL: gdb.base/sigstep.exp: displaced=on: step on breakpoint, to handler: performing step


What should have happened is that the breakpoint hit in the signal
handler should have been presented to the user.  But note that
"preempt 'handle'" -- what happened instead is that
displaced_step_fixup confused the breakpoint in the signal handler for
the expected SIGTRAP indicating the displaced instruction was
single-stepped normally/successfully.

This should be affecting all software single-step targets in the same
way.

The fix is to make sure the core sees all signals when displaced
stepping, just like we already must see all signals when doing an
stepping over a breakpoint in-line.  We now get:

 infrun: target_wait (-1.0.0, status) =
 infrun:   570.570.0 [process 570],
 infrun:   status->kind = stopped, signal = GDB_SIGNAL_ALRM
 infrun: TARGET_WAITKIND_STOPPED
 displaced: restored process 570 0x400622
 infrun: stop_pc = 0x400842
 infrun: random signal (GDB_SIGNAL_ALRM)
 infrun: signal arrived while stepping over breakpoint
 infrun: inserting step-resume breakpoint at 0x400842
 infrun: resume (step=0, signal=GDB_SIGNAL_ALRM), trap_expected=0, current thread [process 570] at 0x400842
 LLR: Preparing to resume process 570, Alarm clock, inferior_ptid process 570
 LLR: PTRACE_CONT process 570, Alarm clock (resume event thread)
 infrun: prepare_to_wait
 linux_nat_wait: [process -1], [TARGET_WNOHANG]
 LLW: enter
 LNW: waitpid(-1, ...) returned 0, No child processes
 LLW: exit (ignore)
 infrun: target_wait (-1.0.0, status) =
 infrun:   -1.0.0 [process -1],
 infrun:   status->kind = ignore
 sigchld
 infrun: TARGET_WAITKIND_IGNORE
 infrun: prepare_to_wait
 linux_nat_wait: [process -1], [TARGET_WNOHANG]
 LLW: enter
 LNW: waitpid(-1, ...) returned 570, No child processes
 LLW: waitpid 570 received Trace/breakpoint trap (stopped)
 CSBB: process 570 stopped by software breakpoint
 LNW: waitpid(-1, ...) returned 0, No child processes
 LLW: trap ptid is process 570.
 LLW: exit
 infrun: target_wait (-1.0.0, status) =
 infrun:   570.570.0 [process 570],
 infrun:   status->kind = stopped, signal = GDB_SIGNAL_TRAP
 infrun: TARGET_WAITKIND_STOPPED
 infrun: stop_pc = 0x400717
 infrun: BPSTAT_WHAT_STOP_NOISY
 infrun: stop_waiting

 Breakpoint 3, handler (sig=14) at /home/pedro/gdb/mygit/src/gdb/testsuite/gdb.base/sigstep.c:35
 35        done = 1;

Hardware single-step targets already behave this way, because the
Linux backends (both native and gdbserver) always report signals to
the core if the thread was single-stepping.

As mentioned in the new comment in do_target_resume, we can't fix this
by instead making the displaced_step_fixup phase skip fixing up the PC
if the single step stopped somewhere we didn't expect.  Here's what
the backtrace would look like if we did that:

 Breakpoint 3, handler (sig=14) at /home/pedro/gdb/mygit/src/gdb/testsuite/gdb.base/sigstep.c:35
 35        done = 1;
 1: x/i $pc
 => 0x400717 <handler+7>:        movl   $0x1,0x200943(%rip)        # 0x601064 <done>
 (gdb) bt
 #0  handler (sig=14) at /home/pedro/gdb/mygit/src/gdb/testsuite/gdb.base/sigstep.c:35
 #1  <signal handler called>
 #2  0x0000000000400622 in _start ()
 (gdb) FAIL: gdb.base/sigstep.exp: displaced=on: step on breakpoint, to handler: backtrace

gdb/ChangeLog:
2015-04-07  Pedro Alves  <palves@redhat.com>

	* infrun.c (displaced_step_in_progress): New function.
	(do_target_resume): Advise target to report all signals if
	displaced stepping.

gdb/testsuite/ChangeLog:
2015-04-07  Pedro Alves  <palves@redhat.com>

	* gdb.base/sigstep.exp (breakpoint_to_handler)
	(breakpoint_to_handler_entry): New parameter 'displaced'.  Use it.
	Test "backtrace" in handler.
	(breakpoint_over_handler): New parameter 'displaced'.  Use it.
	(top level): Add new "displaced" test axis to
	breakpoint_to_handler, breakpoint_to_handler_entry and
	breakpoint_over_handler.
---
 gdb/infrun.c                       | 40 +++++++++++++++---
 gdb/testsuite/gdb.base/sigstep.exp | 86 ++++++++++++++++++++++++++++----------
 2 files changed, 98 insertions(+), 28 deletions(-)

diff --git a/gdb/infrun.c b/gdb/infrun.c
index 607a6e4..a270ca9 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1465,6 +1465,20 @@ get_displaced_stepping_state (int pid)
   return NULL;
 }
 
+/* Return true if process PID has a thread doing a displaced step.  */
+
+static int
+displaced_step_in_progress (int pid)
+{
+  struct displaced_step_inferior_state *displaced;
+
+  displaced = get_displaced_stepping_state (pid);
+  if (displaced != NULL && !ptid_equal (displaced->step_ptid, null_ptid))
+    return 1;
+
+  return 0;
+}
+
 /* Add a new displaced stepping state for process PID to the displaced
    stepping state list, or return a pointer to an already existing
    entry, if it already exists.  Never returns NULL.  */
@@ -2047,11 +2061,27 @@ do_target_resume (ptid_t resume_ptid, int step, enum gdb_signal sig)
      happens to apply to another thread.  */
   tp->suspend.stop_signal = GDB_SIGNAL_0;
 
-  /* Advise target which signals may be handled silently.  If we have
-     removed breakpoints because we are stepping over one (in any
-     thread), we need to receive all signals to avoid accidentally
-     skipping a breakpoint during execution of a signal handler.  */
-  if (step_over_info_valid_p ())
+  /* Advise target which signals may be handled silently.
+
+     If we have removed breakpoints because we are stepping over one
+     in-line (in any thread), we need to receive all signals to avoid
+     accidentally skipping a breakpoint during execution of a signal
+     handler.
+
+     Likewise if we're displaced stepping, otherwise a trap for a
+     breakpoint in a signal handler might be confused with the
+     displaced step finishing.  We don't make the displaced_step_fixup
+     step distinguish the cases instead, because:
+
+     - a backtrace while stopped in the signal handler would show the
+       scratch pad as frame older than the signal handler, instead of
+       the real mainline code.
+
+     - when the thread is later resumed, the signal handler would
+       return to the scratch pad area, which would no longer be
+       valid.  */
+  if (step_over_info_valid_p ()
+      || displaced_step_in_progress (ptid_get_pid (tp->ptid)))
     target_pass_signals (0, NULL);
   else
     target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass);
diff --git a/gdb/testsuite/gdb.base/sigstep.exp b/gdb/testsuite/gdb.base/sigstep.exp
index c4f7e91..3c9454c 100644
--- a/gdb/testsuite/gdb.base/sigstep.exp
+++ b/gdb/testsuite/gdb.base/sigstep.exp
@@ -409,13 +409,19 @@ foreach cmd {"stepi" "nexti" "step" "next" "continue"} {
 
 # Try stepping when there's a signal pending, a pre-existing
 # breakpoint at the current instruction, and a breakpoint in the
-# handler.  Should advance to the signal handler.
+# handler.  Should advance to the signal handler.  DISPLACED indicates
+# whether to try with or without displaced stepping (to exercise the
+# different techniques of stepping over the breakpoint at the current
+# instruction).
 
-proc breakpoint_to_handler { cmd } {
+proc breakpoint_to_handler { displaced cmd } {
     global infinite_loop
 
-    with_test_prefix "$cmd on breakpoint, to handler" {
+    with_test_prefix "displaced=$displaced: $cmd on breakpoint, to handler" {
 	restart
+
+	gdb_test_no_output "set displaced-stepping $displaced"
+
 	# Use the real-time itimer, as otherwize the process never gets
 	# enough time to expire the timer.
 	gdb_test_no_output "set itimer = itimer_real"
@@ -430,11 +436,21 @@ proc breakpoint_to_handler { cmd } {
 	sleep 1
 
 	gdb_test "$cmd" " handler .*" "performing $cmd"
+
+	# Make sure we the displaced stepping scratch pad isn't in the
+	# backtrace.
+	gdb_test_sequence "bt" "backtrace" {
+	    "\[\r\n\]+.0 \[^\r\n\]* handler "
+	    "\[\r\n\]+.1  .signal handler called."
+	    "\[\r\n\]+.2 \[^\r\n\]* main "
+	}
     }
 }
 
-foreach cmd {"step" "next" "continue"} {
-    breakpoint_to_handler $cmd
+foreach displaced {"off" "on"} {
+    foreach cmd {"step" "next" "continue"} {
+	breakpoint_to_handler $displaced $cmd
+    }
 }
 
 # Try stepping when there's a signal pending, and a breakpoint at the
@@ -449,11 +465,17 @@ foreach cmd {"step" "next" "continue"} {
 # have been called by the trampoline code.  This test checks that it
 # is possible to stop the inferior, even at that first instruction.
 
-proc breakpoint_to_handler_entry { cmd } {
+# DISPLACED indicates whether to try with or without displaced
+# stepping (to exercise the different techniques of stepping over the
+# breakpoint at the current instruction).
+proc breakpoint_to_handler_entry { displaced cmd } {
     global infinite_loop
 
-    with_test_prefix "$cmd on breakpoint, to handler entry" {
+    with_test_prefix "displaced=$displaced: $cmd on breakpoint, to handler entry" {
 	restart
+
+	gdb_test_no_output "set displaced-stepping $displaced"
+
 	# Use the real-time itimer, as otherwize the process never gets
 	# enough time to expire the timer.
 	gdb_test_no_output "set itimer = itimer_real"
@@ -468,24 +490,37 @@ proc breakpoint_to_handler_entry { cmd } {
 	sleep 1
 
 	gdb_test "$cmd" " handler .*" "performing $cmd"
+
+	# Make sure we the displaced stepping scratch pad isn't in the
+	# backtrace.
+	gdb_test_sequence "bt" "backtrace" {
+	    "\[\r\n\]+.0 \[^\r\n\]* handler "
+	    "\[\r\n\]+.1  .signal handler called."
+	    "\[\r\n\]+.2 \[^\r\n\]* main "
+	}
     }
 }
 
-foreach cmd {"step" "next" "continue"} {
-    breakpoint_to_handler_entry $cmd
+foreach displaced {"off" "on"} {
+    foreach cmd {"step" "next" "continue"} {
+	breakpoint_to_handler_entry $displaced $cmd
+    }
 }
 
 # Try stepping when there's a signal pending, and a pre-existing
 # breakpoint at the current instruction, and no breakpoint in the
-# handler.  Should advance to the next line/instruction.  If SW_WATCH
-# is true, set a software watchpoint, which exercises stepping the
-# breakpoint instruction while delivering a signal at the same time.
-# If NO_HANDLER, arrange for the signal's handler be SIG_IGN, thus
-# when the software watchpoint is also set, testing stepping a
-# breakpoint instruction and immediately triggering the breakpoint
-# (exercises adjust_pc_after_break logic).
-
-proc breakpoint_over_handler { cmd with_sw_watch no_handler } {
+# handler.  Should advance to the next line/instruction.  DISPLACED
+# indicates whether to try with or without displaced stepping (to
+# exercise the different techniques of stepping over the breakpoint at
+# the current instruction).  If SW_WATCH is true, set a software
+# watchpoint, which exercises stepping the breakpoint instruction
+# while delivering a signal at the same time.  If NO_HANDLER, arrange
+# for the signal's handler be SIG_IGN, thus when the software
+# watchpoint is also set, testing stepping a breakpoint instruction
+# and immediately triggering the breakpoint (exercises
+# adjust_pc_after_break logic).
+
+proc breakpoint_over_handler { displaced cmd with_sw_watch no_handler } {
     global infinite_loop
     global clear_done
 
@@ -497,8 +532,11 @@ proc breakpoint_over_handler { cmd with_sw_watch no_handler } {
 	append prefix ", no handler"
     }
 
-    with_test_prefix "$prefix" {
+    with_test_prefix "displaced=$displaced: $prefix" {
 	restart
+
+	gdb_test_no_output "set displaced-stepping $displaced"
+
 	# Use the real-time itimer, as otherwize the process never gets
 	# enough time to expire the timer.
 	gdb_test_no_output "set itimer = itimer_real"
@@ -534,10 +572,12 @@ proc breakpoint_over_handler { cmd with_sw_watch no_handler } {
     }
 }
 
-foreach cmd {"stepi" "nexti" "step" "next" "continue"} {
-    foreach with_sw_watch {0 1} {
-	foreach no_handler {0 1} {
-	    breakpoint_over_handler $cmd $with_sw_watch $no_handler
+foreach displaced {"off" "on"} {
+    foreach cmd {"stepi" "nexti" "step" "next" "continue"} {
+	foreach with_sw_watch {0 1} {
+	    foreach no_handler {0 1} {
+		breakpoint_over_handler $displaced $cmd $with_sw_watch $no_handler
+	    }
 	}
     }
 }
-- 
1.9.3

  parent reply	other threads:[~2015-04-07 12:49 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-04-07 12:49 [PATCH v2 00/23] All-stop on top of non-stop Pedro Alves
2015-04-07 12:50 ` [PATCH v2 23/23] native Linux: enable always non-stop by default Pedro Alves
2015-04-07 12:50 ` [PATCH v2 19/23] Disable displaced stepping if trying it fails Pedro Alves
2015-04-07 12:50 ` [PATCH v2 03/23] PR13858 - Can't do displaced stepping with no symbols Pedro Alves
2015-04-09 12:46   ` Pedro Alves
2015-04-07 12:50 ` Pedro Alves [this message]
2015-04-10  9:56   ` [PATCH v2 01/23] Fix gdb.base/sigstep.exp with displaced stepping on software single-step targets Pedro Alves
2015-04-07 12:50 ` [PATCH v2 10/23] PPC64: Fix step-over-trips-on-watchpoint.exp with displaced stepping on Pedro Alves
2015-04-07 12:50 ` [PATCH v2 09/23] Make gdb.threads/step-over-trips-on-watchpoint.exp effective on !x86 Pedro Alves
2015-04-07 12:50 ` [PATCH v2 05/23] remote.c/all-stop: Implement TARGET_WAITKIND_NO_RESUMED and TARGET_WNOHANG Pedro Alves
2015-04-07 12:50 ` [PATCH v2 21/23] PPC64: Fix gdb.arch/ppc64-atomic-inst.exp with displaced stepping Pedro Alves
2015-04-07 12:50 ` [PATCH v2 20/23] PPC64: symbol-file + exec-file results in broken " Pedro Alves
2015-04-07 12:50 ` [PATCH v2 12/23] Misc switch_back_to_stepped_thread cleanups Pedro Alves
2015-04-07 12:50 ` [PATCH v2 04/23] Change adjust_pc_after_break's prototype Pedro Alves
2015-04-07 12:50 ` [PATCH v2 11/23] Use keep_going in proceed and start_step_over too Pedro Alves
2015-04-07 12:50 ` [PATCH v2 22/23] S/390: displaced stepping and PC-relative RIL-b/RIL-c instructions Pedro Alves
2015-04-07 12:50 ` [PATCH v2 15/23] Implement all-stop on top of a target running non-stop mode Pedro Alves
2015-04-07 13:36   ` Eli Zaretskii
2015-04-08  9:34   ` Yao Qi
2015-04-08  9:53     ` Pedro Alves
2015-04-08 11:08       ` Pedro Alves
2015-04-08 19:35         ` Pedro Alves
2015-04-08 19:41           ` Pedro Alves
2015-04-07 12:50 ` [PATCH v2 16/23] Fix signal-while-stepping-over-bp-other-thread.exp on targets always in non-stop Pedro Alves
2015-04-07 12:50 ` [PATCH v2 02/23] Fix and test "checkpoint" in non-stop mode Pedro Alves
2015-04-07 12:55 ` [PATCH v2 17/23] Fix interrupt-noterm.exp on targets always in non-stop Pedro Alves
2015-04-07 12:57 ` [PATCH v2 08/23] Test step-over-{lands-on-breakpoint|trips-on-watchpoint}.exp with displaced stepping Pedro Alves
2015-04-10 14:54   ` Pedro Alves
2015-04-07 12:59 ` [PATCH v2 14/23] Teach non-stop to do in-line step-overs (stop all, step, restart) Pedro Alves
2015-04-07 12:59 ` [PATCH v2 07/23] Embed the pending step-over chain in thread_info objects Pedro Alves
2015-04-07 12:59 ` [PATCH v2 13/23] Factor out code to re-resume stepped thread Pedro Alves
2015-04-07 13:30 ` [PATCH v2 06/23] Make thread_still_needs_step_over consider stepping_over_watchpoint too Pedro Alves
2015-04-08  9:28   ` Yao Qi
2015-04-13 10:47     ` Pedro Alves
2015-04-07 13:30 ` [PATCH v2 18/23] Fix step-over-{trips-on-watchpoint|lands-on-breakpoint}.exp race Pedro Alves
2015-04-08  9:45 ` [PATCH v2 00/23] All-stop on top of non-stop Yao Qi
2015-04-08 10:17   ` Pedro Alves
2015-04-08 10:30     ` Pedro Alves
2015-04-10  8:41     ` Yao Qi
2015-04-10  8:50       ` Pedro Alves
2015-04-10  8:22 ` Yao Qi
2015-04-10  8:34   ` Pedro Alves
2015-04-10  9:26     ` Yao Qi
2015-04-13 15:28       ` Pedro Alves
2015-04-13 16:16         ` Yao Qi
2015-04-13 16:23           ` Pedro Alves
2015-04-13 16:23           ` Pedro Alves

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1428410990-28560-2-git-send-email-palves@redhat.com \
    --to=palves@redhat.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).