public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v4 00/18] All-stop on top of non-stop
@ 2015-05-21 23:19 Pedro Alves
  2015-05-21 23:19 ` [PATCH 01/18] Fix and test "checkpoint" in non-stop mode Pedro Alves
                   ` (18 more replies)
  0 siblings, 19 replies; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:19 UTC (permalink / raw)
  To: gdb-patches

v3: https://sourceware.org/ml/gdb-patches/2015-04/msg00662.html
v2: https://sourceware.org/ml/gdb-patches/2015-04/msg00198.html
v1: https://sourceware.org/ml/gdb-patches/2015-04/msg00073.html

Compared to v3, a set of minor changes accumulated, to address review
comments and discussions (i.e., no major functional/design changes),
plus fixes to a patch that touched all targets (that I noticed
converted a couple wrong).

I believe I addressed all review comments thus far.  Barring comments,
I'd like to push this in, and expose it to the build bots.

I tried to mention the differences to v3 in each patch that had
changes, if any (scroll past ChangeLog).

Documentation changes have not changed, and have already been
approved.

Note most of these patches could go in without the final bits that
actually do all-stop-on-top-of-non-stop, as they fix problems that
exist e.g., with "set non-stop on" or "set displaced-stepping on" too.

I've again (force) pushed this to users/palves/all-stop-non-stop for
review and testing convenience.

As nothing major changed, I retested the whole series on x86-64 only.

v3 was tested on:

     x86-64 GNU/Linux
     x86-64 GNU/Linux on top of software single-step branch
     PPC64 GNU/Linux
     S/390 GNU/Linux

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Series-intro proper follows:

This series implements user-visible all-stop mode running with the
target_ops backend always in non-stop mode.  This is a stepping stone
towards finer-grained control of threads, being able to do interesting
things like inferior and thread groups/sets (itsets), associating
groups with breakpoints (which threads cause a stop, which threads are
implicitly paused when a breakpoint triggers), etc.  From the user's
perspective, all-stop mode is really just a special case of being able
to stop and resume specific sets of threads, so it makes sense to do
this step first.

After this series, even in all-stop mode ("set non-stop off", the
default) the target is no longer in charge of stopping all threads
before reporting an event to the core -- the core takes care of it
when it sees fit.  For example, when "next"- or "step"-ing, we can
avoid stopping and resuming all threads at each internal single-step,
and instead only stop all threads when we're about to present the stop
to the user.

In order to get there, the series teaches GDB to do non-stop mode even
without displaced stepping (stop all threads, step over breakpoint,
restart threads), as displaced stepping isn't implemented everywhere,
and doesn't work in some scenarios (as in, we can't use it, not that
it's buggy).

And then it fixes all testsuite regressions (on native x86-64, ppc64
and s390 GNU/Linux) this new mode causes, compared to all-stop ("set
non-stop off") with the target backend in all-stop mode too (i.e., the
current default).  Making "target remote" work in always non-stop mode
is deferred for later (this will be even more useful for remote as the
all-stop mode RSP variant can't really do asynchronous debugging).

Tested on x86_64 Fedora 20, native, with and without "set displaced
off", and with and without "maint set target-non-stop on"; and also
against gdbserver.  Tested on x86-64 GNU/Linux native on top of x86
software single-step branch.  Tested on PPC64 Fedora 18.  Tested on
S/390 RHEL 7.1.

Pedro Alves (18):
  Fix and test "checkpoint" in non-stop mode
  Change adjust_pc_after_break's prototype
  remote.c/all-stop: Implement TARGET_WAITKIND_NO_RESUMED and
    TARGET_WNOHANG
  Make thread_still_needs_step_over consider stepping_over_watchpoint
    too
  Embed the pending step-over chain in thread_info objects
  Use keep_going in proceed and start_step_over too
  Misc switch_back_to_stepped_thread cleanups
  Add comments to currently_stepping and target_resume
  Factor out code to re-resume stepped thread
  Teach non-stop to do in-line step-overs (stop all, step, restart)
  Implement all-stop on top of a target running non-stop mode
  Fix signal-while-stepping-over-bp-other-thread.exp on targets always
    in non-stop
  Fix interrupt-noterm.exp on targets always in non-stop
  Fix step-over-{trips-on-watchpoint|lands-on-breakpoint}.exp race
  Disable displaced stepping if trying it fails
  PPC64: Fix gdb.arch/ppc64-atomic-inst.exp with displaced stepping
  S/390: displaced stepping and PC-relative RIL-b/RIL-c instructions
  native Linux: enable always non-stop by default

 gdb/ChangeLog                                      |   18 +
 gdb/testsuite/ChangeLog                            |    6 +
 gdb/NEWS                                           |    6 +
 gdb/breakpoint.c                                   |   11 +-
 gdb/darwin-nat.c                                   |    6 +-
 gdb/doc/gdb.texinfo                                |   24 +
 gdb/gdbarch.h                                      |    6 +-
 gdb/gdbarch.sh                                     |    4 +
 gdb/gdbthread.h                                    |   61 +-
 gdb/inf-ptrace.c                                   |    6 +-
 gdb/infcmd.c                                       |    6 +-
 gdb/infrun.c                                       | 2330 +++++++++++++++-----
 gdb/infrun.h                                       |    7 +
 gdb/linux-nat.c                                    |   33 +-
 gdb/nto-procfs.c                                   |   16 +-
 gdb/procfs.c                                       |    6 +-
 gdb/remote-m32r-sdi.c                              |    6 +-
 gdb/remote-sim.c                                   |   20 +-
 gdb/remote.c                                       |   57 +-
 gdb/rs6000-tdep.c                                  |   68 +-
 gdb/s390-linux-tdep.c                              |  115 +-
 gdb/target-delegates.c                             |   59 +
 gdb/target.c                                       |   92 +
 gdb/target.h                                       |   28 +-
 gdb/target/waitstatus.h                            |    5 +-
 gdb/testsuite/gdb.arch/ppc64-atomic-inst.exp       |   50 +-
 gdb/testsuite/gdb.base/checkpoint-ns.exp           |   26 +
 gdb/testsuite/gdb.base/checkpoint.exp              |    6 +-
 gdb/testsuite/gdb.base/valgrind-disp-step.c        |   32 +
 gdb/testsuite/gdb.base/valgrind-disp-step.exp      |  131 ++
 .../signal-while-stepping-over-bp-other-thread.exp |    2 +-
 .../gdb.threads/step-over-lands-on-breakpoint.c    |   17 +-
 .../gdb.threads/step-over-lands-on-breakpoint.exp  |    6 +-
 .../gdb.threads/step-over-trips-on-watchpoint.c    |   17 +-
 .../gdb.threads/step-over-trips-on-watchpoint.exp  |    9 +-
 gdb/thread.c                                       |  197 +-
 gdb/windows-nat.c                                  |    6 +-
 37 files changed, 2793 insertions(+), 702 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/checkpoint-ns.exp
 create mode 100644 gdb/testsuite/gdb.base/valgrind-disp-step.c
 create mode 100644 gdb/testsuite/gdb.base/valgrind-disp-step.exp

-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 16/18] PPC64: Fix gdb.arch/ppc64-atomic-inst.exp with displaced stepping
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
                   ` (2 preceding siblings ...)
  2015-05-21 23:19 ` [PATCH 14/18] Fix step-over-{trips-on-watchpoint|lands-on-breakpoint}.exp race Pedro Alves
@ 2015-05-21 23:19 ` Pedro Alves
  2015-05-21 23:19 ` [PATCH 09/18] Factor out code to re-resume stepped thread Pedro Alves
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:19 UTC (permalink / raw)
  To: gdb-patches

The ppc64 displaced step code can't handle atomic sequences.  Fallback
to stepping over the breakpoint in-line if we detect one.

gdb/ChangeLog:
2015-05-21  Pedro Alves  <palves@redhat.com>

	* infrun.c (displaced_step_prepare_throw): Return -1 if
	gdbarch_displaced_step_copy_insn returns NULL.  Update intro
	comment.
	* rs6000-tdep.c (LWARX_MASK, LWARX_INSTRUCTION, LDARX_INSTRUCTION)
	(STWCX_MASK, STWCX_INSTRUCTION, STDCX_INSTRUCTION): Move higher up
	in file.
	(ppc_displaced_step_copy_insn): New function.
	(ppc_displaced_step_fixup): Update comment.
	(rs6000_gdbarch_init): Install ppc_displaced_step_copy_insn as
	gdbarch_displaced_step_copy_insn hook.
	* gdbarch.sh (displaced_step_copy_insn): Document what happens on
	NULL return.
	* gdbarch.h: Regenerate.

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

	* gdb.arch/ppc64-atomic-inst.exp (do_test): New procedure, move
	tests here.
	(top level): Run do_test with and without displaced stepping.

v4:

   Fix ChangeLog.
   Fix typos in rs6000-tdep.c.
   Document that displaced_step_prepare_throw can return -1.

v3:

   - Document that gdbarch_displaced_step_copy_insn can return NULL.
---
 gdb/gdbarch.h                                |  6 ++-
 gdb/gdbarch.sh                               |  4 ++
 gdb/infrun.c                                 | 15 ++++--
 gdb/rs6000-tdep.c                            | 68 +++++++++++++++++++++++-----
 gdb/testsuite/gdb.arch/ppc64-atomic-inst.exp | 50 ++++++++++++--------
 5 files changed, 109 insertions(+), 34 deletions(-)

diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index c94c19c..b02225a 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -923,7 +923,11 @@ extern void set_gdbarch_max_insn_length (struct gdbarch *gdbarch, ULONGEST max_i
   
    If your architecture doesn't need to adjust instructions before
    single-stepping them, consider using simple_displaced_step_copy_insn
-   here. */
+   here.
+  
+   If the instruction cannot execute out of line, return NULL.  The
+   core falls back to stepping past the instruction in-line instead in
+   that case. */
 
 extern int gdbarch_displaced_step_copy_insn_p (struct gdbarch *gdbarch);
 
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 0f303a4..749cbda 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -763,6 +763,10 @@ V:ULONGEST:max_insn_length:::0:0
 # If your architecture doesn't need to adjust instructions before
 # single-stepping them, consider using simple_displaced_step_copy_insn
 # here.
+#
+# If the instruction cannot execute out of line, return NULL.  The
+# core falls back to stepping past the instruction in-line instead in
+# that case.
 M:struct displaced_step_closure *:displaced_step_copy_insn:CORE_ADDR from, CORE_ADDR to, struct regcache *regs:from, to, regs
 
 # Return true if GDB should use hardware single-stepping to execute
diff --git a/gdb/infrun.c b/gdb/infrun.c
index c321e03..09b4d94 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1705,7 +1705,9 @@ displaced_step_dump_bytes (struct ui_file *file,
    explain how we handle this case instead.
 
    Returns 1 if preparing was successful -- this thread is going to be
-   stepped now; or 0 if displaced stepping this thread got queued.  */
+   stepped now; 0 if displaced stepping this thread got queued; or -1
+   if this instruction can't be displaced stepped.  */
+
 static int
 displaced_step_prepare_throw (ptid_t ptid)
 {
@@ -1789,9 +1791,14 @@ displaced_step_prepare_throw (ptid_t ptid)
 
   closure = gdbarch_displaced_step_copy_insn (gdbarch,
 					      original, copy, regcache);
-
-  /* We don't support the fully-simulated case at present.  */
-  gdb_assert (closure);
+  if (closure == NULL)
+    {
+      /* The architecture doesn't know how or want to displaced step
+	 this instruction or instruction sequence.  Fallback to
+	 stepping over the breakpoint in-line.  */
+      do_cleanups (old_cleanups);
+      return -1;
+    }
 
   /* Save the information we need to fix things up if the step
      succeeds.  */
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index a125000..ce607fc 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -974,6 +974,61 @@ rs6000_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *bp_addr,
 #define BXL_INSN 0x4c000000
 #define BP_INSN 0x7C000008
 
+/* Instruction masks used during single-stepping of atomic
+   sequences.  */
+#define LWARX_MASK 0xfc0007fe
+#define LWARX_INSTRUCTION 0x7c000028
+#define LDARX_INSTRUCTION 0x7c0000A8
+#define STWCX_MASK 0xfc0007ff
+#define STWCX_INSTRUCTION 0x7c00012d
+#define STDCX_INSTRUCTION 0x7c0001ad
+
+/* We can't displaced step atomic sequences.  Otherwise this is just
+   like simple_displaced_step_copy_insn.  */
+
+static struct displaced_step_closure *
+ppc_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);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int insn;
+
+  read_memory (from, buf, len);
+
+  insn = extract_signed_integer (buf, PPC_INSN_SIZE, byte_order);
+
+  /* Assume all atomic sequences start with a lwarx/ldarx instruction.  */
+  if ((insn & LWARX_MASK) == LWARX_INSTRUCTION
+      || (insn & LWARX_MASK) == LDARX_INSTRUCTION)
+    {
+      if (debug_displaced)
+	{
+	  fprintf_unfiltered (gdb_stdlog,
+			      "displaced: can't displaced step "
+			      "atomic sequence at %s\n",
+			      paddress (gdbarch, from));
+	}
+      do_cleanups (old_chain);
+      return NULL;
+    }
+
+  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
@@ -983,8 +1038,7 @@ ppc_displaced_step_fixup (struct gdbarch *gdbarch,
 			  struct regcache *regs)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  /* Since we use simple_displaced_step_copy_insn, our closure is a
-     copy of the instruction.  */
+  /* Our closure is a copy of the instruction.  */
   ULONGEST insn  = extract_unsigned_integer ((gdb_byte *) closure,
 					      PPC_INSN_SIZE, byte_order);
   ULONGEST opcode = 0;
@@ -1077,14 +1131,6 @@ ppc_displaced_step_hw_singlestep (struct gdbarch *gdbarch,
   return 1;
 }
 
-/* Instruction masks used during single-stepping of atomic sequences.  */
-#define LWARX_MASK 0xfc0007fe
-#define LWARX_INSTRUCTION 0x7c000028
-#define LDARX_INSTRUCTION 0x7c0000A8
-#define STWCX_MASK 0xfc0007ff
-#define STWCX_INSTRUCTION 0x7c00012d
-#define STDCX_INSTRUCTION 0x7c0001ad
-
 /* Checks for an atomic sequence of instructions beginning with a LWARX/LDARX
    instruction and ending with a STWCX/STDCX instruction.  If such a sequence
    is found, attempt to step through it.  A breakpoint is placed at the end of 
@@ -5923,7 +5969,7 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   /* Setup displaced stepping.  */
   set_gdbarch_displaced_step_copy_insn (gdbarch,
-					simple_displaced_step_copy_insn);
+					ppc_displaced_step_copy_insn);
   set_gdbarch_displaced_step_hw_singlestep (gdbarch,
 					    ppc_displaced_step_hw_singlestep);
   set_gdbarch_displaced_step_fixup (gdbarch, ppc_displaced_step_fixup);
diff --git a/gdb/testsuite/gdb.arch/ppc64-atomic-inst.exp b/gdb/testsuite/gdb.arch/ppc64-atomic-inst.exp
index d251425..08518fb 100644
--- a/gdb/testsuite/gdb.arch/ppc64-atomic-inst.exp
+++ b/gdb/testsuite/gdb.arch/ppc64-atomic-inst.exp
@@ -32,27 +32,41 @@ if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug quiet}]
     return -1
 }
 
-if ![runto_main] then {
-    untested "could not run to main"
-    return -1
-}
+# The test proper.  DISPLACED is true if we should try with displaced
+# stepping.
+proc do_test { displaced } {
+    global decimal hex
+
+    if ![runto_main] then {
+	untested "could not run to main"
+	return -1
+    }
+
+    gdb_test_no_output "set displaced-stepping $displaced"
 
-set bp1 [gdb_get_line_number "lwarx"]
-gdb_breakpoint "$bp1" "Breakpoint $decimal at $hex" \
-  "Set the breakpoint at the start of the lwarx/stwcx sequence"
+    set bp1 [gdb_get_line_number "lwarx"]
+    gdb_breakpoint "$bp1" "Breakpoint $decimal at $hex" \
+	"Set the breakpoint at the start of the lwarx/stwcx sequence"
 
-set bp2 [gdb_get_line_number "ldarx"]
-gdb_breakpoint "$bp2" "Breakpoint $decimal at $hex" \
-  "Set the breakpoint at the start of the ldarx/stdcx sequence"
+    set bp2 [gdb_get_line_number "ldarx"]
+    gdb_breakpoint "$bp2" "Breakpoint $decimal at $hex" \
+	"Set the breakpoint at the start of the ldarx/stdcx sequence"
 
-gdb_test continue "Continuing.*Breakpoint $decimal.*" \
-  "Continue until lwarx/stwcx start breakpoint"
+    gdb_test continue "Continuing.*Breakpoint $decimal.*" \
+	"Continue until lwarx/stwcx start breakpoint"
 
-gdb_test nexti "bne.*1b" \
-  "Step through the lwarx/stwcx sequence"
+    gdb_test nexti "bne.*1b" \
+	"Step through the lwarx/stwcx sequence"
 
-gdb_test continue "Continuing.*Breakpoint $decimal.*" \
-  "Continue until ldarx/stdcx start breakpoint"
+    gdb_test continue "Continuing.*Breakpoint $decimal.*" \
+	"Continue until ldarx/stdcx start breakpoint"
 
-gdb_test nexti "bne.*1b" \
-  "Step through the ldarx/stdcx sequence"
+    gdb_test nexti "bne.*1b" \
+	"Step through the ldarx/stdcx sequence"
+}
+
+foreach displaced { "off" "on" } {
+    with_test_prefix "displaced=$displaced" {
+	do_test $displaced
+    }
+}
-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 01/18] Fix and test "checkpoint" in non-stop mode
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
@ 2015-05-21 23:19 ` Pedro Alves
  2015-05-21 23:19 ` [PATCH 18/18] native Linux: enable always non-stop by default Pedro Alves
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:19 UTC (permalink / raw)
  To: gdb-patches

Letting a "checkpoint" run to exit with "set non-stop on" behaves
differently compared to the default all-stop mode ("set non-stop
off").

Currently, in non-stop mode:

  (gdb) start
  Temporary breakpoint 1 at 0x40086b: file src/gdb/testsuite/gdb.base/checkpoint.c, line 28.
  Starting program: build/gdb/testsuite/gdb.base/checkpoint

  Temporary breakpoint 1, main () at src/gdb/testsuite/gdb.base/checkpoint.c:28
  28        char *tmp = &linebuf[0];
  (gdb) checkpoint
  checkpoint 1: fork returned pid 24948.
  (gdb) c
  Continuing.
  Copy complete.
  Deleting copy.
  [Inferior 1 (process 24944) exited normally]
  [Switching to process 24948]
  (gdb) info threads
    Id   Target Id         Frame
    1    process 24948 "checkpoint" (running)

  No selected thread.  See `help thread'.
  (gdb) c
  The program is not being run.
  (gdb)

Two issues above:

 1. Thread 1 got stuck in "(running)" state (it isn't really running)

 2. While checkpoints try to preserve the illusion that the thread is
    still the same when the process exits, GDB switched to "No thread
    selected." instead of staying with thread 1 selected.

Problem #1 is caused by handle_inferior_event and normal_stop not
considering that when a
TARGET_WAITKIND_SIGNALLED/TARGET_WAITKIND_EXITED event is reported,
and the inferior is mourned, the target may still have execution.

Problem #2 is caused by the make_cleanup_restore_current_thread
cleanup installed by fetch_inferior_event not being able to find the
original thread 1's ptid in the thread list, thus not being able to
restore thread 1 as selected thread.  The fix is to make the cleanup
installed by make_cleanup_restore_current_thread aware of thread ptid
changes, by installing a thread_ptid_changed observer that adjusts the
cleanup's data.

After the patch, we get the same in all-stop and non-stop modes:

  (gdb) c
  Continuing.
  Copy complete.
  Deleting copy.
  [Inferior 1 (process 25109) exited normally]
  [Switching to process 25113]
  (gdb) info threads
    Id   Target Id         Frame
  * 1    process 25113 "checkpoint" main () at src/gdb/testsuite/gdb.base/checkpoint.c:28
  (gdb)

Turns out the whole checkpoints.exp file can run in non-stop mode
unmodified.  I thought of moving most of the test file's contents to a
procedure that can be called twice, once in non-stop mode and another
in all-stop mode.  But then, the test already takes close to 30
seconds to run on my machine, so I thought it'd be nicer to run
all-stop and non-stop mode in parallel.  Thus I added a new
checkpoint-ns.exp file that just appends "set non-stop on" to GDBFLAGS
and sources checkpoint.exp.

gdb/ChangeLog:
2015-05-21  Pedro Alves  <palves@redhat.com>

	* infrun.c (handle_inferior_event): If we get
	TARGET_WAITKIND_SIGNALLED or TARGET_WAITKIND_EXITED in non-stop
	mode, mark all threads of the exiting process as not-executing.
	(normal_stop): If we get TARGET_WAITKIND_SIGNALLED or
	TARGET_WAITKIND_EXITED in non-stop mode, finish all threads of the
	exiting process, if inferior_ptid still points at a process.
	* thread.c (struct current_thread_cleanup) <next>: New field.
	(current_thread_cleanup_chain): New global.
	(restore_current_thread_ptid_changed): New function.
	(restore_current_thread_cleanup_dtor): Remove the cleanup from the
	current_thread_cleanup_chain list.
	(make_cleanup_restore_current_thread): Add the cleanup data to the
	current_thread_cleanup_chain list.
	(_initialize_thread): Install restore_current_thread_ptid_changed
	as thread_ptid_changed observer.

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

	* gdb.base/checkpoint-ns.exp: New file.
	* gdb.base/checkpoint.exp: Pass explicit "checkpoint.c" to
	standard_testfile.
---
 gdb/ChangeLog                            | 18 ++++++++++++
 gdb/testsuite/ChangeLog                  |  6 ++++
 gdb/infrun.c                             | 48 ++++++++++++++++++++++++++------
 gdb/testsuite/gdb.base/checkpoint-ns.exp | 26 +++++++++++++++++
 gdb/testsuite/gdb.base/checkpoint.exp    |  6 ++--
 gdb/thread.c                             | 38 +++++++++++++++++++++++++
 6 files changed, 131 insertions(+), 11 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/checkpoint-ns.exp

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 42ef67d..aae10e5 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,21 @@
+2015-05-19  Pedro Alves  <palves@redhat.com>
+
+	* infrun.c (handle_inferior_event): If we get
+	TARGET_WAITKIND_SIGNALLED or TARGET_WAITKIND_EXITED in non-stop
+	mode, mark all threads of the exiting process as not-executing.
+	(normal_stop): If we get TARGET_WAITKIND_SIGNALLED or
+	TARGET_WAITKIND_EXITED in non-stop mode, finish all threads of the
+	exiting process, if inferior_ptid still points at a process.
+	* thread.c (struct current_thread_cleanup) <next>: New field.
+	(current_thread_cleanup_chain): New global.
+	(restore_current_thread_ptid_changed): New function.
+	(restore_current_thread_cleanup_dtor): Remove the cleanup from the
+	current_thread_cleanup_chain list.
+	(make_cleanup_restore_current_thread): Add the cleanup data to the
+	current_thread_cleanup_chain list.
+	(_initialize_thread): Install restore_current_thread_ptid_changed
+	as thread_ptid_changed observer.
+
 2015-05-21  Andrew Burgess  <andrew.burgess@embecosm.com>
 
 	* tui/tui-regs.c (tui_reg_next_command): Use NULL not 0.
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 49f56f4..01af98a 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2015-05-19  Pedro Alves  <palves@redhat.com>
+
+	* gdb.base/checkpoint-ns.exp: New file.
+	* gdb.base/checkpoint.exp: Pass explicit "checkpoint.c" to
+	standard_testfile.
+
 2015-05-21  Andrew Burgess  <andrew.burgess@embecosm.com>
 
 	* gdb.base/completion.exp: Add test for completion of layout
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 2f6bc41..537de36 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3784,14 +3784,31 @@ handle_inferior_event_1 (struct execution_control_state *ecs)
 
   /* Mark the non-executing threads accordingly.  In all-stop, all
      threads of all processes are stopped when we get any event
-     reported.  In non-stop mode, only the event thread stops.  If
-     we're handling a process exit in non-stop mode, there's nothing
-     to do, as threads of the dead process are gone, and threads of
-     any other process were left running.  */
+     reported.  In non-stop mode, only the event thread stops.  */
   if (!non_stop)
     set_executing (minus_one_ptid, 0);
-  else if (ecs->ws.kind != TARGET_WAITKIND_SIGNALLED
-	   && ecs->ws.kind != TARGET_WAITKIND_EXITED)
+  else if (ecs->ws.kind == TARGET_WAITKIND_SIGNALLED
+	   || ecs->ws.kind == TARGET_WAITKIND_EXITED)
+    {
+      ptid_t pid_ptid;
+
+      /* If we're handling a process exit in non-stop mode, even
+	 though threads haven't been deleted yet, one would think that
+	 there is nothing to do, as threads of the dead process will
+	 be soon deleted, and threads of any other process were left
+	 running.  However, on some targets, threads survive a process
+	 exit event.  E.g., for the "checkpoint" command, when the
+	 current checkpoint/fork exits, linux-fork.c automatically
+	 switches to another fork from within target_mourn_inferior,
+	 by associating the same inferior/thread to another fork.  We
+	 haven't mourned yet at this point, but we must mark any
+	 threads left in the process as not-executing so that
+	 finish_thread_state marks them stopped (in the user's
+	 perspective) if/when we present the stop to the user.  */
+      pid_ptid = pid_to_ptid (ptid_get_pid (ecs->ptid));
+      set_executing (pid_ptid, 0);
+    }
+  else
     set_executing (ecs->ptid, 0);
 
   switch (ecs->ws.kind)
@@ -6552,6 +6569,7 @@ normal_stop (void)
   struct target_waitstatus last;
   ptid_t last_ptid;
   struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
+  ptid_t pid_ptid;
 
   get_last_target_status (&last_ptid, &last);
 
@@ -6561,9 +6579,21 @@ normal_stop (void)
      here, so do this before any filtered output.  */
   if (!non_stop)
     make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
-  else if (last.kind != TARGET_WAITKIND_SIGNALLED
-	   && last.kind != TARGET_WAITKIND_EXITED
-	   && last.kind != TARGET_WAITKIND_NO_RESUMED)
+  else if (last.kind == TARGET_WAITKIND_SIGNALLED
+	   || last.kind == TARGET_WAITKIND_EXITED)
+    {
+      /* On some targets, we may still have live threads in the
+	 inferior when we get a process exit event.  E.g., for
+	 "checkpoint", when the current checkpoint/fork exits,
+	 linux-fork.c automatically switches to another fork from
+	 within target_mourn_inferior.  */
+      if (!ptid_equal (inferior_ptid, null_ptid))
+	{
+	  pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+	  make_cleanup (finish_thread_state_cleanup, &pid_ptid);
+	}
+    }
+  else if (last.kind != TARGET_WAITKIND_NO_RESUMED)
     make_cleanup (finish_thread_state_cleanup, &inferior_ptid);
 
   /* As we're presenting a stop, and potentially removing breakpoints,
diff --git a/gdb/testsuite/gdb.base/checkpoint-ns.exp b/gdb/testsuite/gdb.base/checkpoint-ns.exp
new file mode 100644
index 0000000..d3698ba
--- /dev/null
+++ b/gdb/testsuite/gdb.base/checkpoint-ns.exp
@@ -0,0 +1,26 @@
+# Copyright 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 <http://www.gnu.org/licenses/>.  */
+
+# Test gdb checkpoint and restart in non-stop mode.
+
+# We drive non-stop mode from a separate file because the whole test
+# takes a while to run.  This way, we can test both modes in parallel.
+
+set saved_gdbflags $GDBFLAGS
+append GDBFLAGS " -ex \"set non-stop on\""
+
+source $srcdir/$subdir/checkpoint.exp
+
+set GDBFLAGS $saved_gdbflags
diff --git a/gdb/testsuite/gdb.base/checkpoint.exp b/gdb/testsuite/gdb.base/checkpoint.exp
index 6d94ab6..4a476be 100644
--- a/gdb/testsuite/gdb.base/checkpoint.exp
+++ b/gdb/testsuite/gdb.base/checkpoint.exp
@@ -24,8 +24,10 @@ if {![istarget "*-*-linux*"]} then {
     continue
 }
 
-
-standard_testfile .c
+# Must name the source file explicitly, otherwise when driven by
+# checkpoints-ns.exp, we'd try compiling checkpoints-ns.c, which
+# doesn't exist.
+standard_testfile checkpoint.c
 
 set pi_txt [gdb_remote_download host ${srcdir}/${subdir}/pi.txt]
 if {[is_remote host]} {
diff --git a/gdb/thread.c b/gdb/thread.c
index 23dfcc9..46b5947 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1279,8 +1279,16 @@ restore_selected_frame (struct frame_id a_frame_id, int frame_level)
     }
 }
 
+/* Data used by the cleanup installed by
+   'make_cleanup_restore_current_thread'.  */
+
 struct current_thread_cleanup
 {
+  /* Next in list of currently installed 'struct
+     current_thread_cleanup' cleanups.  See
+     'current_thread_cleanup_chain' below.  */
+  struct current_thread_cleanup *next;
+
   ptid_t inferior_ptid;
   struct frame_id selected_frame_id;
   int selected_frame_level;
@@ -1289,6 +1297,29 @@ struct current_thread_cleanup
   int was_removable;
 };
 
+/* A chain of currently installed 'struct current_thread_cleanup'
+   cleanups.  Restoring the previously selected thread looks up the
+   old thread in the thread list by ptid.  If the thread changes ptid,
+   we need to update the cleanup's thread structure so the look up
+   succeeds.  */
+static struct current_thread_cleanup *current_thread_cleanup_chain;
+
+/* A thread_ptid_changed observer.  Update all currently installed
+   current_thread_cleanup cleanups that want to switch back to
+   OLD_PTID to switch back to NEW_PTID instead.  */
+
+static void
+restore_current_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
+{
+  struct current_thread_cleanup *it;
+
+  for (it = current_thread_cleanup_chain; it != NULL; it = it->next)
+    {
+      if (ptid_equal (it->inferior_ptid, old_ptid))
+	it->inferior_ptid = new_ptid;
+    }
+}
+
 static void
 do_restore_current_thread_cleanup (void *arg)
 {
@@ -1329,6 +1360,8 @@ restore_current_thread_cleanup_dtor (void *arg)
   struct thread_info *tp;
   struct inferior *inf;
 
+  current_thread_cleanup_chain = current_thread_cleanup_chain->next;
+
   tp = find_thread_ptid (old->inferior_ptid);
   if (tp)
     tp->refcount--;
@@ -1362,6 +1395,9 @@ make_cleanup_restore_current_thread (void)
   old->inf_id = current_inferior ()->num;
   old->was_removable = current_inferior ()->removable;
 
+  old->next = current_thread_cleanup_chain;
+  current_thread_cleanup_chain = old;
+
   if (!ptid_equal (inferior_ptid, null_ptid))
     {
       old->was_stopped = is_stopped (inferior_ptid);
@@ -1815,4 +1851,6 @@ Show printing of thread events (such as thread start and exit)."), NULL,
          &setprintlist, &showprintlist);
 
   create_internalvar_type_lazy ("_thread", &thread_funcs, NULL);
+
+  observer_attach_thread_ptid_changed (restore_current_thread_ptid_changed);
 }
-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 05/18] Embed the pending step-over chain in thread_info objects
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
                   ` (6 preceding siblings ...)
  2015-05-21 23:19 ` [PATCH 02/18] Change adjust_pc_after_break's prototype Pedro Alves
@ 2015-05-21 23:19 ` Pedro Alves
  2015-05-21 23:19 ` [PATCH 04/18] Make thread_still_needs_step_over consider stepping_over_watchpoint too Pedro Alves
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:19 UTC (permalink / raw)
  To: gdb-patches

In order to teach non-stop mode to do in-line step-overs (pause all
threads, remove breakpoint, single-step, reinsert breakpoint, restart
threads), we'll need to be able to queue in-line step over requests,
much like we queue displaced stepping (out-of-line) requests.
Actually, the queue should be the same -- threads wait for their turn
to step past something (breakpoint, watchpoint), doesn't matter what
technique we end up using when the step over actually starts.

I found that the queue management ends up simpler and more efficient
if embedded in the thread objects themselves.  This commit converts
the existing displaced stepping queue to that.  Later patches will
make the in-line step-overs code paths use it too.

gdb/ChangeLog:
2015-05-21  Pedro Alves  <palves@redhat.com>

	* gdbthread.h (struct thread_info) <step_over_prev,
	step_over_next>: New fields.
	(thread_step_over_chain_enqueue, thread_step_over_chain_remove)
	(thread_step_over_chain_next, thread_is_in_step_over_chain): New
	declarations.
	* infrun.c (struct displaced_step_request): Delete.
	(struct displaced_step_inferior_state) <step_request_queue>:
	Delete field.
	(displaced_step_prepare): Assert that trap_expected is set.  Use
	thread_step_over_chain_enqueue.  Split starting a new displaced
	step to ...
	(start_step_over): ... this new function.
	(resume): Assert the thread isn't waiting for a step over already.
	(proceed): Assert the thread isn't waiting for a step over
	already.
	(infrun_thread_stop_requested): Adjust to remove threads from the
	embedded step-over chain.
	(handle_inferior_event) <fork/vfork>: Call start_step_over after
	displaced_step_fixup.
	(handle_signal_stop): Call start_step_over after
	displaced_step_fixup.
	* infrun.h (step_over_queue_head): New declaration.
	* thread.c (step_over_chain_enqueue, step_over_chain_remove)
	(thread_step_over_chain_next, thread_is_in_step_over_chain)
	(thread_step_over_chain_enqueue)
	(thread_step_over_chain_remove): New functions.
	(delete_thread_1): Remove thread from the step-over chain.
---
 gdb/gdbthread.h |  23 ++++++++++
 gdb/infrun.c    | 135 +++++++++++++++++++++++++++-----------------------------
 gdb/infrun.h    |   4 ++
 gdb/thread.c    |  84 +++++++++++++++++++++++++++++++++++
 4 files changed, 177 insertions(+), 69 deletions(-)

diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 0926f5f..3f689c4 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -285,6 +285,12 @@ struct thread_info
   /* Values that are stored as temporaries on stack while evaluating
      expressions.  */
   value_vec *stack_temporaries;
+
+  /* Step-over chain.  A thread is in the step-over queue if these are
+     non-NULL.  If only a single thread is in the chain, then these
+     fields point to self.  */
+  struct thread_info *step_over_prev;
+  struct thread_info *step_over_next;
 };
 
 /* Create an empty thread list, or empty the existing one.  */
@@ -502,6 +508,23 @@ extern struct value *get_last_thread_stack_temporary (ptid_t);
 
 extern int value_in_thread_stack_temporaries (struct value *, ptid_t);
 
+/* Add TP to the end of its inferior's pending step-over chain.  */
+
+extern void thread_step_over_chain_enqueue (struct thread_info *tp);
+
+/* Remove TP from its inferior's pending step-over chain.  */
+
+extern void thread_step_over_chain_remove (struct thread_info *tp);
+
+/* Return the next thread in the step-over chain starting at TP.  NULL
+   if TP is the last entry in the chain.  */
+
+extern struct thread_info *thread_step_over_chain_next (struct thread_info *tp);
+
+/* Return true if TP is in the step-over chain.  */
+
+extern int thread_is_in_step_over_chain (struct thread_info *tp);
+
 extern struct thread_info *thread_list;
 
 #endif /* GDBTHREAD_H */
diff --git a/gdb/infrun.c b/gdb/infrun.c
index b97d6e8..3843c0b 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1215,6 +1215,15 @@ follow_exec (ptid_t ptid, char *execd_pathname)
      matically get reset there in the new process.).  */
 }
 
+/* The queue of threads that need to do a step-over operation to get
+   past e.g., a breakpoint.  What technique is used to step over the
+   breakpoint/watchpoint does not matter -- all threads end up in the
+   same queue, to maintain rough temporal order of execution, in order
+   to avoid starvation, otherwise, we could e.g., find ourselves
+   constantly stepping the same couple threads past their breakpoints
+   over and over, if the single-step finish fast enough.  */
+struct thread_info *step_over_queue_head;
+
 /* Bit flags indicating what the thread needs to step over.  */
 
 enum step_over_what
@@ -1411,12 +1420,6 @@ step_over_info_valid_p (void)
    displaced step operation on it.  See displaced_step_prepare and
    displaced_step_fixup for details.  */
 
-struct displaced_step_request
-{
-  ptid_t ptid;
-  struct displaced_step_request *next;
-};
-
 /* Per-inferior displaced stepping state.  */
 struct displaced_step_inferior_state
 {
@@ -1426,10 +1429,6 @@ struct displaced_step_inferior_state
   /* The process this displaced step state refers to.  */
   int pid;
 
-  /* A queue of pending displaced stepping requests.  One entry per
-     thread that needs to do a displaced step.  */
-  struct displaced_step_request *step_request_queue;
-
   /* If this is not null_ptid, this is the thread carrying out a
      displaced single-step in process PID.  This thread's state will
      require fixing up once it has completed its step.  */
@@ -1661,6 +1660,9 @@ displaced_step_prepare (ptid_t ptid)
      support displaced stepping.  */
   gdb_assert (gdbarch_displaced_step_copy_insn_p (gdbarch));
 
+  /* Nor if the thread isn't meant to step over a breakpoint.  */
+  gdb_assert (tp->control.trap_expected);
+
   /* Disable range stepping while executing in the scratch pad.  We
      want a single-step even if executing the displaced instruction in
      the scratch buffer lands within the stepping range (e.g., a
@@ -1676,28 +1678,13 @@ displaced_step_prepare (ptid_t ptid)
     {
       /* Already waiting for a displaced step to finish.  Defer this
 	 request and place in queue.  */
-      struct displaced_step_request *req, *new_req;
 
       if (debug_displaced)
 	fprintf_unfiltered (gdb_stdlog,
-			    "displaced: defering step of %s\n",
+			    "displaced: deferring step of %s\n",
 			    target_pid_to_str (ptid));
 
-      new_req = xmalloc (sizeof (*new_req));
-      new_req->ptid = ptid;
-      new_req->next = NULL;
-
-      if (displaced->step_request_queue)
-	{
-	  for (req = displaced->step_request_queue;
-	       req && req->next;
-	       req = req->next)
-	    ;
-	  req->next = new_req;
-	}
-      else
-	displaced->step_request_queue = new_req;
-
+      thread_step_over_chain_enqueue (tp);
       return 0;
     }
   else
@@ -1847,24 +1834,45 @@ displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal)
   do_cleanups (old_cleanups);
 
   displaced->step_ptid = null_ptid;
+}
 
-  /* Are there any pending displaced stepping requests?  If so, run
-     one now.  Leave the state object around, since we're likely to
-     need it again soon.  */
-  while (displaced->step_request_queue)
+/* Are there any pending step-over requests?  If so, run all we can
+   now.  */
+
+static void
+start_step_over (void)
+{
+  struct thread_info *tp, *next;
+
+  for (tp = step_over_queue_head; tp != NULL; tp = next)
     {
-      struct displaced_step_request *head;
       ptid_t ptid;
+      struct displaced_step_inferior_state *displaced;
       struct regcache *regcache;
       struct gdbarch *gdbarch;
       CORE_ADDR actual_pc;
       struct address_space *aspace;
+      struct inferior *inf = find_inferior_ptid (tp->ptid);
+
+      next = thread_step_over_chain_next (tp);
 
-      head = displaced->step_request_queue;
-      ptid = head->ptid;
-      displaced->step_request_queue = head->next;
-      xfree (head);
+      displaced = get_displaced_stepping_state (inf->pid);
 
+      /* If this inferior already has a displaced step in process,
+	 don't start a new one.  */
+      if (!ptid_equal (displaced->step_ptid, null_ptid))
+	continue;
+
+      thread_step_over_chain_remove (tp);
+
+      if (step_over_queue_head == NULL)
+	{
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: step-over queue now empty\n");
+	}
+
+      ptid = tp->ptid;
       context_switch (ptid);
 
       regcache = get_thread_regcache (ptid);
@@ -1899,7 +1907,6 @@ displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal)
 	    target_resume (ptid, 0, GDB_SIGNAL_0);
 
 	  /* Done, we're stepping a thread.  */
-	  break;
 	}
       else
 	{
@@ -1927,6 +1934,10 @@ displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal)
 	  /* This request was discarded.  See if there's any other
 	     thread waiting for its turn.  */
 	}
+
+      /* A new displaced stepping sequence started.  Maybe we can
+	 start a displaced step on a thread of other process.
+	 Continue looking.  */
     }
 }
 
@@ -1947,10 +1958,6 @@ infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
     {
       if (ptid_equal (displaced->step_ptid, old_ptid))
 	displaced->step_ptid = new_ptid;
-
-      for (it = displaced->step_request_queue; it; it = it->next)
-	if (ptid_equal (it->ptid, old_ptid))
-	  it->ptid = new_ptid;
     }
 }
 
@@ -2129,6 +2136,8 @@ resume (enum gdb_signal sig)
 
   tp->stepped_breakpoint = 0;
 
+  gdb_assert (!thread_is_in_step_over_chain (tp));
+
   QUIT;
 
   /* Depends on stepped_breakpoint.  */
@@ -2653,6 +2662,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
   /* Fill in with reasonable starting values.  */
   init_thread_stepping_state (tp);
 
+  gdb_assert (!thread_is_in_step_over_chain (tp));
+
   if (addr == (CORE_ADDR) -1)
     {
       if (pc == stop_pc
@@ -2958,35 +2969,17 @@ infrun_thread_stop_requested_callback (struct thread_info *info, void *arg)
 static void
 infrun_thread_stop_requested (ptid_t ptid)
 {
-  struct displaced_step_inferior_state *displaced;
-
-  /* PTID was requested to stop.  Remove it from the displaced
-     stepping queue, so we don't try to resume it automatically.  */
-
-  for (displaced = displaced_step_inferior_states;
-       displaced;
-       displaced = displaced->next)
-    {
-      struct displaced_step_request *it, **prev_next_p;
-
-      it = displaced->step_request_queue;
-      prev_next_p = &displaced->step_request_queue;
-      while (it)
-	{
-	  if (ptid_match (it->ptid, ptid))
-	    {
-	      *prev_next_p = it->next;
-	      it->next = NULL;
-	      xfree (it);
-	    }
-	  else
-	    {
-	      prev_next_p = &it->next;
-	    }
+  struct thread_info *tp;
 
-	  it = *prev_next_p;
-	}
-    }
+  /* PTID was requested to stop.  Remove matching threads from the
+     step-over queue, so we don't try to resume them
+     automatically.  */
+  ALL_NON_EXITED_THREADS (tp)
+    if (ptid_match (tp->ptid, ptid))
+      {
+	if (thread_is_in_step_over_chain (tp))
+	  thread_step_over_chain_remove (tp);
+      }
 
   iterate_over_threads (infrun_thread_stop_requested_callback, &ptid);
 }
@@ -4044,6 +4037,9 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
 	       that this operation also cleans up the child process for vfork,
 	       because their pages are shared.  */
 	    displaced_step_fixup (ecs->ptid, GDB_SIGNAL_TRAP);
+	    /* Start a new step-over in another thread if there's one
+	       that needs it.  */
+	    start_step_over ();
 
 	    if (ecs->ws.kind == TARGET_WAITKIND_FORKED)
 	      {
@@ -4292,6 +4288,7 @@ handle_signal_stop (struct execution_control_state *ecs)
      the PC, so do it here, before we set stop_pc.)  */
   displaced_step_fixup (ecs->ptid,
 			ecs->event_thread->suspend.stop_signal);
+  start_step_over ();
 
   /* If we either finished a single-step or hit a breakpoint, but
      the user wanted this thread to be stopped, pretend we got a
diff --git a/gdb/infrun.h b/gdb/infrun.h
index 75bb075..7d1033c 100644
--- a/gdb/infrun.h
+++ b/gdb/infrun.h
@@ -189,4 +189,8 @@ extern void signal_catch_update (const unsigned int *);
    systems.  Use of symbolic signal names is strongly encouraged.  */
 enum gdb_signal gdb_signal_from_command (int num);
 
+/* The global queue of threads that need to do a step-over operation
+   to get past e.g., a breakpoint.  */
+extern struct thread_info *step_over_queue_head;
+
 #endif /* INFRUN_H */
diff --git a/gdb/thread.c b/gdb/thread.c
index 46b5947..28e5ef8 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -307,6 +307,86 @@ add_thread (ptid_t ptid)
   return add_thread_with_info (ptid, NULL);
 }
 
+/* Add TP to the end of the step-over chain LIST_P.  */
+
+static void
+step_over_chain_enqueue (struct thread_info **list_p, struct thread_info *tp)
+{
+  gdb_assert (tp->step_over_next == NULL);
+  gdb_assert (tp->step_over_prev == NULL);
+
+  if (*list_p == NULL)
+    {
+      *list_p = tp;
+      tp->step_over_prev = tp->step_over_next = tp;
+    }
+  else
+    {
+      struct thread_info *head = *list_p;
+      struct thread_info *tail = head->step_over_prev;
+
+      tp->step_over_prev = tail;
+      tp->step_over_next = head;
+      head->step_over_prev = tp;
+      tail->step_over_next = tp;
+    }
+}
+
+/* Remove TP from step-over chain LIST_P.  */
+
+static void
+step_over_chain_remove (struct thread_info **list_p, struct thread_info *tp)
+{
+  gdb_assert (tp->step_over_next != NULL);
+  gdb_assert (tp->step_over_prev != NULL);
+
+  if (*list_p == tp)
+    {
+      if (tp == tp->step_over_next)
+	*list_p = NULL;
+      else
+	*list_p = tp->step_over_next;
+    }
+
+  tp->step_over_prev->step_over_next = tp->step_over_next;
+  tp->step_over_next->step_over_prev = tp->step_over_prev;
+  tp->step_over_prev = tp->step_over_next = NULL;
+}
+
+/* See gdbthread.h.  */
+
+struct thread_info *
+thread_step_over_chain_next (struct thread_info *tp)
+{
+  struct thread_info *next = tp->step_over_next;
+
+  return (next == step_over_queue_head ? NULL : next);
+}
+
+/* See gdbthread.h.  */
+
+int
+thread_is_in_step_over_chain (struct thread_info *tp)
+{
+  return (tp->step_over_next != NULL);
+}
+
+/* See gdbthread.h.  */
+
+void
+thread_step_over_chain_enqueue (struct thread_info *tp)
+{
+  step_over_chain_enqueue (&step_over_queue_head, tp);
+}
+
+/* See gdbthread.h.  */
+
+void
+thread_step_over_chain_remove (struct thread_info *tp)
+{
+  step_over_chain_remove (&step_over_queue_head, tp);
+}
+
 /* Delete thread PTID.  If SILENT, don't notify the observer of this
    exit.  */
 static void
@@ -323,6 +403,10 @@ delete_thread_1 (ptid_t ptid, int silent)
   if (!tp)
     return;
 
+  /* Dead threads don't need to step-over.  Remove from queue.  */
+  if (tp->step_over_next != NULL)
+    thread_step_over_chain_remove (tp);
+
   /* If this is the current thread, or there's code out there that
      relies on it existing (refcount > 0) we can't delete yet.  Mark
      it as exited, and notify it.  */
-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 03/18] remote.c/all-stop: Implement TARGET_WAITKIND_NO_RESUMED and TARGET_WNOHANG
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
                   ` (8 preceding siblings ...)
  2015-05-21 23:19 ` [PATCH 04/18] Make thread_still_needs_step_over consider stepping_over_watchpoint too Pedro Alves
@ 2015-05-21 23:19 ` Pedro Alves
  2015-05-21 23:19 ` [PATCH 11/18] Implement all-stop on top of a target running non-stop mode Pedro Alves
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:19 UTC (permalink / raw)
  To: gdb-patches

Even though "target remote" supports target-async, the all-stop
target_wait implementation ignores TARGET_WNOHANG.  If the core
happens to poll for events and we've already read the stop reply out
of the serial/socket, remote_wait_as hangs forever instead of
returning an indication that there are no events to process.  This
can't happen currently, but later changes will trigger this.

gdb/ChangeLog:
2015-05-21  Pedro Alves  <palves@redhat.com>

	* remote.c (remote_wait_as): If not waiting for a stop reply,
	return TARGET_WAITKIND_NO_RESUMED.  If TARGET_WNOHANG is
	requested, don't block waiting forever.
---
 gdb/remote.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/gdb/remote.c b/gdb/remote.c
index dfe115b..db06def 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -6227,6 +6227,14 @@ remote_wait_as (ptid_t ptid, struct target_waitstatus *status, int options)
     {
       int ret;
       int is_notif;
+      int forever = ((options & TARGET_WNOHANG) == 0
+		     && wait_forever_enabled_p);
+
+      if (!rs->waiting_for_stop_reply)
+	{
+	  status->kind = TARGET_WAITKIND_NO_RESUMED;
+	  return minus_one_ptid;
+	}
 
       if (!target_is_async_p ())
 	{
@@ -6245,7 +6253,7 @@ remote_wait_as (ptid_t ptid, struct target_waitstatus *status, int options)
 	 However, before we do that we need to ensure that the caller
 	 knows how to take the target into/out of async mode.  */
       ret = getpkt_or_notif_sane (&rs->buf, &rs->buf_size,
-				  wait_forever_enabled_p, &is_notif);
+				  forever, &is_notif);
 
       if (!target_is_async_p ())
 	signal (SIGINT, ofunc);
@@ -6254,6 +6262,9 @@ remote_wait_as (ptid_t ptid, struct target_waitstatus *status, int options)
 	 not interesting.  */
       if (ret != -1 && is_notif)
 	return minus_one_ptid;
+
+      if (ret == -1 && (options & TARGET_WNOHANG) != 0)
+	return minus_one_ptid;
     }
 
   buf = rs->buf;
-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 02/18] Change adjust_pc_after_break's prototype
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
                   ` (5 preceding siblings ...)
  2015-05-21 23:19 ` [PATCH 06/18] Use keep_going in proceed and start_step_over too Pedro Alves
@ 2015-05-21 23:19 ` Pedro Alves
  2015-05-21 23:19 ` [PATCH 05/18] Embed the pending step-over chain in thread_info objects Pedro Alves
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:19 UTC (permalink / raw)
  To: gdb-patches

Prepare to use it in contexts without an ecs handy.  Follow up patches
will make use of this.

gdb/ChangeLog:
2015-05-21  Pedro Alves  <pedro@codesourcery.com>

	* infrun.c (adjust_pc_after_break): Now takes thread_info and
	waitstatus pointers instead of an ecs.  Adjust.
	(handle_inferior_event): Adjust caller.
---
 gdb/infrun.c | 24 +++++++++++++++---------
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/gdb/infrun.c b/gdb/infrun.c
index 537de36..cce021d 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3432,8 +3432,14 @@ context_switch (ptid_t ptid)
   switch_to_thread (ptid);
 }
 
+/* If the target can't tell whether we've hit breakpoints
+   (target_supports_stopped_by_sw_breakpoint), and we got a SIGTRAP,
+   check whether that could have been caused by a breakpoint.  If so,
+   adjust the PC, per gdbarch_decr_pc_after_break.  */
+
 static void
-adjust_pc_after_break (struct execution_control_state *ecs)
+adjust_pc_after_break (struct thread_info *thread,
+		       struct target_waitstatus *ws)
 {
   struct regcache *regcache;
   struct gdbarch *gdbarch;
@@ -3461,10 +3467,10 @@ adjust_pc_after_break (struct execution_control_state *ecs)
      target with both of these set in GDB history, and it seems unlikely to be
      correct, so gdbarch_have_nonsteppable_watchpoint is not checked here.  */
 
-  if (ecs->ws.kind != TARGET_WAITKIND_STOPPED)
+  if (ws->kind != TARGET_WAITKIND_STOPPED)
     return;
 
-  if (ecs->ws.value.sig != GDB_SIGNAL_TRAP)
+  if (ws->value.sig != GDB_SIGNAL_TRAP)
     return;
 
   /* In reverse execution, when a breakpoint is hit, the instruction
@@ -3510,7 +3516,7 @@ adjust_pc_after_break (struct execution_control_state *ecs)
 
   /* If this target does not decrement the PC after breakpoints, then
      we have nothing to do.  */
-  regcache = get_thread_regcache (ecs->ptid);
+  regcache = get_thread_regcache (thread->ptid);
   gdbarch = get_regcache_arch (regcache);
 
   decr_pc = gdbarch_decr_pc_after_break (gdbarch);
@@ -3564,10 +3570,10 @@ adjust_pc_after_break (struct execution_control_state *ecs)
 	 software breakpoint.  In this case (prev_pc == breakpoint_pc),
 	 we also need to back up to the breakpoint address.  */
 
-      if (thread_has_single_step_breakpoints_set (ecs->event_thread)
-	  || !currently_stepping (ecs->event_thread)
-	  || (ecs->event_thread->stepped_breakpoint
-	      && ecs->event_thread->prev_pc == breakpoint_pc))
+      if (thread_has_single_step_breakpoints_set (thread)
+	  || !currently_stepping (thread)
+	  || (thread->stepped_breakpoint
+	      && thread->prev_pc == breakpoint_pc))
 	regcache_write_pc (regcache, breakpoint_pc);
 
       do_cleanups (old_cleanups);
@@ -3748,7 +3754,7 @@ handle_inferior_event_1 (struct execution_control_state *ecs)
     }
 
   /* Dependent on valid ECS->EVENT_THREAD.  */
-  adjust_pc_after_break (ecs);
+  adjust_pc_after_break (ecs->event_thread, &ecs->ws);
 
   /* Dependent on the current PC value modified by adjust_pc_after_break.  */
   reinit_frame_cache ();
-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 14/18] Fix step-over-{trips-on-watchpoint|lands-on-breakpoint}.exp race
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
  2015-05-21 23:19 ` [PATCH 01/18] Fix and test "checkpoint" in non-stop mode Pedro Alves
  2015-05-21 23:19 ` [PATCH 18/18] native Linux: enable always non-stop by default Pedro Alves
@ 2015-05-21 23:19 ` Pedro Alves
  2015-05-21 23:19 ` [PATCH 16/18] PPC64: Fix gdb.arch/ppc64-atomic-inst.exp with displaced stepping Pedro Alves
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:19 UTC (permalink / raw)
  To: gdb-patches

On a target that is both always in non-stop mode and can do displaced
stepping (such as native x86_64 GNU/Linux, with "maint set
target-non-stop on"), the step-over-trips-on-watchpoint.exp test
sometimes fails like this:

   (gdb) PASS: gdb.threads/step-over-trips-on-watchpoint.exp: no thread-specific bp: step: thread 1
   set scheduler-locking off
   (gdb) PASS: gdb.threads/step-over-trips-on-watchpoint.exp: no thread-specific bp: step: set scheduler-locking off
   step
  -[Switching to Thread 0x7ffff7fc0700 (LWP 11782)]
  -Hardware watchpoint 4: watch_me
  -
  -Old value = 0
  -New value = 1
  -child_function (arg=0x0) at /home/pedro/gdb/mygit/src/gdb/testsuite/gdb.threads/step-over-trips-on-watchpoint.c:39
  -39           other = 1; /* set thread-specific breakpoint here */
  -(gdb) PASS: gdb.threads/step-over-trips-on-watchpoint.exp: no thread-specific bp: step: step
  +wait_threads () at /home/pedro/gdb/mygit/src/gdb/testsuite/gdb.threads/step-over-trips-on-watchpoint.c:49
  +49       return 1; /* in wait_threads */
  +(gdb) FAIL: gdb.threads/step-over-trips-on-watchpoint.exp: no thread-specific bp: step: step

Note "scheduler-locking" was set off.  The problem is that on such
targets, the step-over of thread 2 and the "step" of thread 1 can be
set to run simultaneously (since with displaced stepping the
breakpoint isn't ever removed from the target), and sometimes, the
"step" of thread 1 finishes first, so it'd take another resume to see
the watchpoint trigger.  Fix this by replacing the wait_threads
function with a one-line infinite loop that doesn't call any function,
so that the "step" of thread 1 never finishes.

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

	* gdb.threads/step-over-lands-on-breakpoint.c (wait_threads):
	Delete function.
	(main): Add alarm.  Run an infinite loop instead of calling
	wait_threads.
	* gdb.threads/step-over-lands-on-breakpoint.exp (do_test): Change
	comment.
	* gdb.threads/step-over-trips-on-watchpoint.c (wait_threads):
	Delete function.
	(main): Add alarm.  Run an infinite loop instead of calling
	wait_threads.
	* gdb.threads/step-over-trips-on-watchpoint.exp (do_test): Change
	comment.

v4:

	- No changes.

v3:

	- Rebased.
---
 .../gdb.threads/step-over-lands-on-breakpoint.c         | 17 ++++++++++-------
 .../gdb.threads/step-over-lands-on-breakpoint.exp       |  6 +++---
 .../gdb.threads/step-over-trips-on-watchpoint.c         | 17 ++++++++++-------
 .../gdb.threads/step-over-trips-on-watchpoint.exp       |  9 ++++-----
 4 files changed, 27 insertions(+), 22 deletions(-)

diff --git a/gdb/testsuite/gdb.threads/step-over-lands-on-breakpoint.c b/gdb/testsuite/gdb.threads/step-over-lands-on-breakpoint.c
index 0a6ed8f..2480164 100644
--- a/gdb/testsuite/gdb.threads/step-over-lands-on-breakpoint.c
+++ b/gdb/testsuite/gdb.threads/step-over-lands-on-breakpoint.c
@@ -41,23 +41,26 @@ child_function (void *arg)
   pthread_exit (NULL);
 }
 
-static int
-wait_threads (void)
-{
-  return 1; /* in wait_threads */
-}
-
 int
 main ()
 {
   int res;
   long i;
 
+  alarm (300);
+
   pthread_barrier_init (&barrier, NULL, 2);
 
   res = pthread_create (&child_thread, NULL, child_function, NULL);
   pthread_barrier_wait (&barrier);
-  wait_threads (); /* set wait-thread breakpoint here */
+
+  /* Use an infinite loop with no function calls so that "step" over
+     this line never finishes before the breakpoint in the other
+     thread triggers.  That can happen if the step-over of thread 2 is
+     done with displaced stepping on a target that is always in
+     non-stop mode, as in that case GDB runs both threads
+     simultaneously.  */
+  while (1); /* set wait-thread breakpoint here */
 
   pthread_join (child_thread, NULL);
 
diff --git a/gdb/testsuite/gdb.threads/step-over-lands-on-breakpoint.exp b/gdb/testsuite/gdb.threads/step-over-lands-on-breakpoint.exp
index 52b59ec..b38f23b 100644
--- a/gdb/testsuite/gdb.threads/step-over-lands-on-breakpoint.exp
+++ b/gdb/testsuite/gdb.threads/step-over-lands-on-breakpoint.exp
@@ -59,9 +59,9 @@ proc do_test {displaced command} {
 	gdb_test_no_output "set scheduler-locking off"
 
 	# Thread 2 is still stopped at a breakpoint that needs to be
-	# stepped over before proceeding thread 1.  However, right
-	# where the step-over lands there's another breakpoint
-	# installed, which should trap and be reported to the user.
+	# stepped over.  However, right where the step-over lands
+	# there's another breakpoint installed, which should trap and
+	# be reported to the user.
 	gdb_test "$command" "step-over here.*"
     }
 }
diff --git a/gdb/testsuite/gdb.threads/step-over-trips-on-watchpoint.c b/gdb/testsuite/gdb.threads/step-over-trips-on-watchpoint.c
index 6cf97fb..34ba079 100644
--- a/gdb/testsuite/gdb.threads/step-over-trips-on-watchpoint.c
+++ b/gdb/testsuite/gdb.threads/step-over-trips-on-watchpoint.c
@@ -43,23 +43,26 @@ child_function (void *arg)
   pthread_exit (NULL);
 }
 
-static int
-wait_threads (void)
-{
-  return 1; /* in wait_threads */
-}
-
 int
 main ()
 {
   int res;
   long i;
 
+  alarm (300);
+
   pthread_barrier_init (&barrier, NULL, 2);
 
   res = pthread_create (&child_thread, NULL, child_function, NULL);
   pthread_barrier_wait (&barrier);
-  wait_threads (); /* set wait-thread breakpoint here */
+
+  /* Use an infinite loop with no function calls so that "step" over
+     this line never finishes before the watchpoint in the other
+     thread triggers.  That can happen if the step-over of thread 2 is
+     done with displaced stepping on a target that is always in
+     non-stop mode, as in that case GDB runs both threads
+     simultaneously.  */
+  while (1); /* set wait-thread breakpoint here */
 
   pthread_join (child_thread, NULL);
 
diff --git a/gdb/testsuite/gdb.threads/step-over-trips-on-watchpoint.exp b/gdb/testsuite/gdb.threads/step-over-trips-on-watchpoint.exp
index 89b66e5..7e27f97 100644
--- a/gdb/testsuite/gdb.threads/step-over-trips-on-watchpoint.exp
+++ b/gdb/testsuite/gdb.threads/step-over-trips-on-watchpoint.exp
@@ -115,11 +115,10 @@ proc do_test { displaced with_bp } {
 		gdb_test "thread 1" "Switching to .*"
 		gdb_test_no_output "set scheduler-locking off"
 
-		# Thread 2 is still stopped at a breakpoint that needs to be
-		# stepped over before proceeding thread 1.  However, the
-		# instruction that is under the breakpoint triggers a
-		# watchpoint, which should trap and be reported to the
-		# user.
+		# Thread 2 is still stopped at a breakpoint that needs
+		# to be stepped over.  However, the instruction that
+		# is under the breakpoint triggers a watchpoint, which
+		# should trap and be reported to the user.
 		gdb_test "$command" "Hardware watchpoint.*: watch_me.*New value = 1.*"
 	    }
 	}
-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 12/18] Fix signal-while-stepping-over-bp-other-thread.exp on targets always in non-stop
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
                   ` (10 preceding siblings ...)
  2015-05-21 23:19 ` [PATCH 11/18] Implement all-stop on top of a target running non-stop mode Pedro Alves
@ 2015-05-21 23:19 ` Pedro Alves
  2015-05-21 23:19 ` [PATCH 08/18] Add comments to currently_stepping and target_resume Pedro Alves
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:19 UTC (permalink / raw)
  To: gdb-patches

With "maint set target-non-stop on" we get:

 -PASS: gdb.threads/signal-while-stepping-over-bp-other-thread.exp: step
 +FAIL: gdb.threads/signal-while-stepping-over-bp-other-thread.exp: step

The issue is simply that switch_back_to_stepped_thread is not used in
non-stop mode, thus infrun doesn't output the expected "switching back
to stepped thread" log.

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

	* signal-while-stepping-over-bp-other-thread.exp: Expect "restart
	threads" as alternative to "switching back to stepped thread".

v4:

  - no changes.

v3:

  - Cleanups were moved to a separate patch and pushed already.  Now a
    one-liner.  Also, v2 mentioned the wrong output by silly
    mistake....
---
 .../gdb.threads/signal-while-stepping-over-bp-other-thread.exp          | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gdb/testsuite/gdb.threads/signal-while-stepping-over-bp-other-thread.exp b/gdb/testsuite/gdb.threads/signal-while-stepping-over-bp-other-thread.exp
index 3201b1f..3713951 100644
--- a/gdb/testsuite/gdb.threads/signal-while-stepping-over-bp-other-thread.exp
+++ b/gdb/testsuite/gdb.threads/signal-while-stepping-over-bp-other-thread.exp
@@ -100,7 +100,7 @@ gdb_test_sequence $test $test {
     "need to step-over"
     "resume \\(step=1"
     "signal arrived while stepping over breakpoint"
-    "switching back to stepped thread"
+    "(restart threads|switching back to stepped thread)"
     "stepped to a different line"
     "callme"
 }
-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 18/18] native Linux: enable always non-stop by default
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
  2015-05-21 23:19 ` [PATCH 01/18] Fix and test "checkpoint" in non-stop mode Pedro Alves
@ 2015-05-21 23:19 ` Pedro Alves
  2015-05-21 23:19 ` [PATCH 14/18] Fix step-over-{trips-on-watchpoint|lands-on-breakpoint}.exp race Pedro Alves
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:19 UTC (permalink / raw)
  To: gdb-patches

The testsuite shows no regressions with this forced on, on:

 - Native x86_64 Fedora 20, with and output "set displaced off".

 - Native x86_64 Fedora 20, on top of x86 software single-step series.

 - PPC64 Fedora 18.

 - S/390 RHEL 7.1.

Let's try making it the default.

gdb/ChangeLog:
2015-05-21  Pedro Alves  <palves@redhat.com>

	* linux-nat.c (linux_nat_always_non_stop_p): Return 1.
---
 gdb/linux-nat.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index eaefa72..0a511ce 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -4588,7 +4588,7 @@ linux_nat_supports_non_stop (struct target_ops *self)
 static int
 linux_nat_always_non_stop_p (struct target_ops *self)
 {
-  return 0;
+  return 1;
 }
 
 /* True if we want to support multi-process.  To be removed when GDB
-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 09/18] Factor out code to re-resume stepped thread
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
                   ` (3 preceding siblings ...)
  2015-05-21 23:19 ` [PATCH 16/18] PPC64: Fix gdb.arch/ppc64-atomic-inst.exp with displaced stepping Pedro Alves
@ 2015-05-21 23:19 ` Pedro Alves
  2015-05-21 23:19 ` [PATCH 06/18] Use keep_going in proceed and start_step_over too Pedro Alves
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:19 UTC (permalink / raw)
  To: gdb-patches

Just a code refactor, no funcionality change intended.

gdb/ChangeLog:
2015-05-21  Pedro Alves  <palves@redhat.com>

	* infrun.c (keep_going_stepped_thread): New function, factored out
	from ...
	(switch_back_to_stepped_thread): ... here.
---
 gdb/infrun.c | 198 ++++++++++++++++++++++++++++++++---------------------------
 1 file changed, 106 insertions(+), 92 deletions(-)

diff --git a/gdb/infrun.c b/gdb/infrun.c
index 9f668a3..56b7c7b 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1871,6 +1871,7 @@ reset_ecs (struct execution_control_state *ecs, struct thread_info *tp)
 
 static void keep_going_pass_signal (struct execution_control_state *ecs);
 static void prepare_to_wait (struct execution_control_state *ecs);
+static int keep_going_stepped_thread (struct thread_info *tp);
 static int thread_still_needs_step_over (struct thread_info *tp);
 
 /* Are there any pending step-over requests?  If so, run all we can
@@ -5742,110 +5743,123 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
 
       if (stepping_thread != NULL)
 	{
-	  struct frame_info *frame;
-	  struct gdbarch *gdbarch;
-
-	  tp = stepping_thread;
-
-	  /* If the stepping thread exited, then don't try to switch
-	     back and resume it, which could fail in several different
-	     ways depending on the target.  Instead, just keep going.
-
-	     We can find a stepping dead thread in the thread list in
-	     two cases:
-
-	     - The target supports thread exit events, and when the
-	     target tries to delete the thread from the thread list,
-	     inferior_ptid pointed at the exiting thread.  In such
-	     case, calling delete_thread does not really remove the
-	     thread from the list; instead, the thread is left listed,
-	     with 'exited' state.
-
-	     - The target's debug interface does not support thread
-	     exit events, and so we have no idea whatsoever if the
-	     previously stepping thread is still alive.  For that
-	     reason, we need to synchronously query the target
-	     now.  */
-	  if (is_exited (tp->ptid)
-	      || !target_thread_alive (tp->ptid))
-	    {
-	      if (debug_infrun)
-		fprintf_unfiltered (gdb_stdlog,
-				    "infrun: not switching back to "
-				    "stepped thread, it has vanished\n");
-
-	      delete_thread (tp->ptid);
-	      return 0;
-	    }
-
 	  if (debug_infrun)
 	    fprintf_unfiltered (gdb_stdlog,
 				"infrun: switching back to stepped thread\n");
 
-	  reset_ecs (ecs, tp);
-	  switch_to_thread (tp->ptid);
+	  if (keep_going_stepped_thread (stepping_thread))
+	    {
+	      prepare_to_wait (ecs);
+	      return 1;
+	    }
+	}
+    }
 
-	  stop_pc = regcache_read_pc (get_thread_regcache (tp->ptid));
-	  frame = get_current_frame ();
-	  gdbarch = get_frame_arch (frame);
+  return 0;
+}
 
-	  /* If the PC of the thread we were trying to single-step has
-	     changed, then that thread has trapped or been signaled,
-	     but the event has not been reported to GDB yet.  Re-poll
-	     the target looking for this particular thread's event
-	     (i.e. temporarily enable schedlock) by:
+/* Set a previously stepped thread back to stepping.  Returns true on
+   success, false if the resume is not possible (e.g., the thread
+   vanished).  */
+
+static int
+keep_going_stepped_thread (struct thread_info *tp)
+{
+  struct frame_info *frame;
+  struct gdbarch *gdbarch;
+  struct execution_control_state ecss;
+  struct execution_control_state *ecs = &ecss;
 
-	       - setting a break at the current PC
-	       - resuming that particular thread, only (by setting
-		 trap expected)
+  /* If the stepping thread exited, then don't try to switch back and
+     resume it, which could fail in several different ways depending
+     on the target.  Instead, just keep going.
 
-	     This prevents us continuously moving the single-step
-	     breakpoint forward, one instruction at a time,
-	     overstepping.  */
+     We can find a stepping dead thread in the thread list in two
+     cases:
 
-	  if (stop_pc != tp->prev_pc)
-	    {
-	      ptid_t resume_ptid;
+     - The target supports thread exit events, and when the target
+       tries to delete the thread from the thread list, inferior_ptid
+       pointed at the exiting thread.  In such case, calling
+       delete_thread does not really remove the thread from the list;
+       instead, the thread is left listed, with 'exited' state.
 
-	      if (debug_infrun)
-		fprintf_unfiltered (gdb_stdlog,
-				    "infrun: expected thread advanced also "
-				    "(%s -> %s)\n",
-				    paddress (target_gdbarch (), tp->prev_pc),
-				    paddress (target_gdbarch (), stop_pc));
-
-	      /* Clear the info of the previous step-over, as it's no
-		 longer valid (if the thread was trying to step over a
-		 breakpoint, it has already succeeded).  It's what
-		 keep_going would do too, if we called it.  Do this
-		 before trying to insert the sss breakpoint, otherwise
-		 if we were previously trying to step over this exact
-		 address in another thread, the breakpoint is
-		 skipped.  */
-	      clear_step_over_info ();
-	      tp->control.trap_expected = 0;
-
-	      insert_single_step_breakpoint (get_frame_arch (frame),
-					     get_frame_address_space (frame),
-					     stop_pc);
-
-	      resume_ptid = user_visible_resume_ptid (tp->control.stepping_command);
-	      do_target_resume (resume_ptid, 0, GDB_SIGNAL_0);
-	      prepare_to_wait (ecs);
-	    }
-	  else
-	    {
-	      if (debug_infrun)
-		fprintf_unfiltered (gdb_stdlog,
-				    "infrun: expected thread still "
-				    "hasn't advanced\n");
-	      keep_going_pass_signal (ecs);
-	    }
+     - The target's debug interface does not support thread exit
+       events, and so we have no idea whatsoever if the previously
+       stepping thread is still alive.  For that reason, we need to
+       synchronously query the target now.  */
 
-	  return 1;
-	}
+  if (is_exited (tp->ptid)
+      || !target_thread_alive (tp->ptid))
+    {
+      if (debug_infrun)
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: not resuming previously  "
+			    "stepped thread, it has vanished\n");
+
+      delete_thread (tp->ptid);
+      return 0;
     }
-  return 0;
+
+  if (debug_infrun)
+    fprintf_unfiltered (gdb_stdlog,
+			"infrun: resuming previously stepped thread\n");
+
+  reset_ecs (ecs, tp);
+  switch_to_thread (tp->ptid);
+
+  stop_pc = regcache_read_pc (get_thread_regcache (tp->ptid));
+  frame = get_current_frame ();
+  gdbarch = get_frame_arch (frame);
+
+  /* If the PC of the thread we were trying to single-step has
+     changed, then that thread has trapped or been signaled, but the
+     event has not been reported to GDB yet.  Re-poll the target
+     looking for this particular thread's event (i.e. temporarily
+     enable schedlock) by:
+
+     - setting a break at the current PC
+     - resuming that particular thread, only (by setting trap
+     expected)
+
+     This prevents us continuously moving the single-step breakpoint
+     forward, one instruction at a time, overstepping.  */
+
+  if (stop_pc != tp->prev_pc)
+    {
+      ptid_t resume_ptid;
+
+      if (debug_infrun)
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: expected thread advanced also (%s -> %s)\n",
+			    paddress (target_gdbarch (), tp->prev_pc),
+			    paddress (target_gdbarch (), stop_pc));
+
+      /* Clear the info of the previous step-over, as it's no longer
+	 valid (if the thread was trying to step over a breakpoint, it
+	 has already succeeded).  It's what keep_going would do too,
+	 if we called it.  Do this before trying to insert the sss
+	 breakpoint, otherwise if we were previously trying to step
+	 over this exact address in another thread, the breakpoint is
+	 skipped.  */
+      clear_step_over_info ();
+      tp->control.trap_expected = 0;
+
+      insert_single_step_breakpoint (get_frame_arch (frame),
+				     get_frame_address_space (frame),
+				     stop_pc);
+
+      resume_ptid = user_visible_resume_ptid (tp->control.stepping_command);
+      do_target_resume (resume_ptid, 0, GDB_SIGNAL_0);
+    }
+  else
+    {
+      if (debug_infrun)
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: expected thread still hasn't advanced\n");
+
+      keep_going_pass_signal (ecs);
+    }
+  return 1;
 }
 
 /* Is thread TP in the middle of (software or hardware)
-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 11/18] Implement all-stop on top of a target running non-stop mode
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
                   ` (9 preceding siblings ...)
  2015-05-21 23:19 ` [PATCH 03/18] remote.c/all-stop: Implement TARGET_WAITKIND_NO_RESUMED and TARGET_WNOHANG Pedro Alves
@ 2015-05-21 23:19 ` Pedro Alves
  2015-09-11 20:53   ` Jan Kratochvil
  2015-05-21 23:19 ` [PATCH 12/18] Fix signal-while-stepping-over-bp-other-thread.exp on targets always in non-stop Pedro Alves
                   ` (7 subsequent siblings)
  18 siblings, 1 reply; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:19 UTC (permalink / raw)
  To: gdb-patches

[Documentation bit already approved, and have not changed.]

This finally implements user-visible all-stop mode running with the
target_ops backend always in non-stop mode.  This is a stepping stone
towards finer-grained control of threads, being able to do interesting
things like thread groups, associating groups with breakpoints, etc.
From the user's perspective, all-stop mode is really just a special
case of being able to stop and resume specific sets of threads, so it
makes sense to do this step first.

With this, even in all-stop, the target is no longer in charge of
stopping all threads before reporting an event to the core -- the core
takes care of it when it sees fit.  For example, when "next"- or
"step"-ing, we can avoid stopping and resuming all threads at each
internal single-step, and instead only stop all threads when we're
about to present the stop to the user.

The implementation is almost straight forward, as the heavy lifting
has been done already in previous patches.  Basically, we replace
checks for "set non-stop on/off" (the non_stop global), with calls to
a new target_is_non_stop_p function.  In a few places, if "set
non-stop off", we stop all threads explicitly, and in a few other
places we resume all threads explicitly, making use of existing
methods that were added for teaching non-stop to step over breakpoints
without displaced stepping.

This adds a new "maint set target-non-stop on/off/auto" knob that
allows both disabling the feature if we find problems, and
force-enable it for development (useful when teaching a target about
this.  The default is "auto", which means the feature is enabled if a
new target method says it should be enabled.  The patch implements the
method in linux-nat.c, just for illustration, because it still returns
false.  We'll need a few follow up fixes before turning it on by
default.  This is a separate target method from indicating regular
non-stop support, because e.g., while e.g., native linux-nat.c is
close to regression free with all-stop-non-stop (with following
patches will fixing the remaining regressions), remote.c+gdbserver
will still need more fixing, even though it supports "set non-stop
on".

Tested on x86_64 Fedora 20, native, with and without "set displaced
off", and with and without "maint set target-non-stop on"; and also
against gdbserver.

gdb/ChangeLog:
2015-05-21  Pedro Alves  <palves@redhat.com>

	* NEWS: Mention "maint set/show target-non-stop".
	* breakpoint.c (update_global_location_list): Check
	target_is_non_stop_p instead of non_stop.
	* infcmd.c (attach_command_post_wait, attach_command): Likewise.
	* infrun.c (show_can_use_displaced_stepping)
	(can_use_displaced_stepping_p, start_step_over_inferior):
	Likewise.
	(resume): Always resume a single thread if the target is in
	non-stop mode.
	(proceed): Check target_is_non_stop_p instead of non_stop.  If in
	all-stop mode but the target is always in non-stop mode, start all
	the other threads that are implicitly resumed too.
	(for_each_just_stopped_thread, fetch_inferior_event)
	(adjust_pc_after_break, stop_all_threads): Check
	target_is_non_stop_p instead of non_stop.
	(handle_inferior_event): Likewise.  Handle detach-fork in all-stop
	with the target always in non-stop mode.
	(handle_signal_stop) <random signal>: Check target_is_non_stop_p
	instead of non_stop.
	(switch_back_to_stepped_thread): Check target_is_non_stop_p
	instead of non_stop.
	(keep_going_stepped_thread): Always resume a single thread if the
	target is in non-stop mode.
	(stop_waiting): If in all-stop mode, and the target is in non-stop
	mode, stop all threads.
	(keep_going_pass): Likewise, when starting a new in-line step-over
	sequence.
	* linux-nat.c (get_pending_status, select_event_lwp)
	(linux_nat_filter_event, linux_nat_wait_1, linux_nat_wait): Check
	target_is_non_stop_p instead of non_stop.
	(linux_nat_always_non_stop_p): New function.
	(linux_nat_stop): Check target_is_non_stop_p instead of non_stop.
	(linux_nat_add_target): Install linux_nat_always_non_stop_p.
	* target-delegates.c: Regenerate.
	* target.c (target_is_non_stop_p): New function.
	(target_non_stop_enabled, target_non_stop_enabled_1): New globals.
	(maint_set_target_non_stop_command)
	(maint_show_target_non_stop_command): New functions.
	(_initilize_target): Install "maint set/show target-non-stop"
	commands.
	* target.h (struct target_ops) <to_always_non_stop_p>: New field.
	(target_non_stop_enabled): New declaration.
	(target_is_non_stop_p): New declaration.

gdb/doc/ChangeLog:
2015-05-21  Pedro Alves  <palves@redhat.com>

	* gdb.texinfo (Maintenance Commands): Document "maint set/show
	target-non-stop".

v4:

  "set non-stop on" + "maint show target-non-stop" would show "on"
  even if the target backend didn't force-enable non-stop.  (the
  command's show hook was calling target_non_stop_p instead of
  target_always_non_stop_p).

  Added/updated a few comments.

v3:

  Adjustments as per previous patches:

  - Change 'resumed' instead of 'executing' in 'proceed' to avoid
    resuming threads with pending statuses.

  - Adjust to use thread_is_in_step_over_chain.

v2:

 - Documentation adjusted per Eli's review.  NEWS entry added.
 - `proceed' change simplified, thanks to fixes in v2 of previous
   patches in the series.
---
 gdb/NEWS               |   6 +++
 gdb/breakpoint.c       |   2 +-
 gdb/doc/gdb.texinfo    |  24 +++++++++++
 gdb/infcmd.c           |   4 +-
 gdb/infrun.c           | 115 +++++++++++++++++++++++++++++++++++++++----------
 gdb/linux-nat.c        |  25 +++++++----
 gdb/target-delegates.c |  31 +++++++++++++
 gdb/target.c           |  71 ++++++++++++++++++++++++++++++
 gdb/target.h           |  13 ++++++
 9 files changed, 257 insertions(+), 34 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index e08dd0d..8b13582 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -75,6 +75,12 @@ maint print symbol-cache-statistics
 maint flush-symbol-cache
   Flush the contents of the symbol cache.
 
+maint set target-non-stop (on|off|auto)
+maint show target-non-stop
+  Control whether GDB targets always operate in non-stop mode even if
+  "set non-stop" is "off".  The default is "auto", meaning non-stop
+  mode is enabled if supported by the target.
+
 record btrace bts
 record bts
   Start branch trace recording using Branch Trace Store (BTS) format.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index ab0010b..78278a6 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -12344,7 +12344,7 @@ update_global_location_list (enum ugll_insert_mode insert_mode)
 
       if (!found_object)
 	{
-	  if (removed && non_stop
+	  if (removed && target_is_non_stop_p ()
 	      && need_moribund_for_location_type (old_loc))
 	    {
 	      /* This location was removed from the target.  In
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 1665372..cb84b81 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -34224,6 +34224,30 @@ asynchronous mode (@pxref{Background Execution}).  Normally the
 default is asynchronous, if it is available; but this can be changed
 to more easily debug problems occurring only in synchronous mode.
 
+@kindex maint set target-non-stop @var{mode} [on|off|auto]
+@kindex maint show target-non-stop
+@item maint set target-non-stop
+@itemx maint show target-non-stop
+
+This controls whether @value{GDBN} targets always operate in non-stop
+mode even if @code{set non-stop} is @code{off} (@pxref{Non-Stop
+Mode}).  The default is @code{auto}, meaning non-stop mode is enabled
+if supported by the target.
+
+@table @code
+@item maint set target-non-stop auto
+This is the default mode.  @value{GDBN} controls the target in
+non-stop mode if the target supports it.
+
+@item maint set target-non-stop on
+@value{GDBN} controls the target in non-stop mode even if the target
+does not indicate support.
+
+@item maint set target-non-stop off
+@value{GDBN} does not control the target in non-stop mode even if the
+target supports it.
+@end table
+
 @kindex maint set per-command
 @kindex maint show per-command
 @item maint set per-command
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 03282a7..d73c596 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -2540,7 +2540,7 @@ attach_command_post_wait (char *args, int from_tty, int async_exec)
 	 selected thread is stopped, others may still be executing.
 	 Be sure to explicitly stop all threads of the process.  This
 	 should have no effect on already stopped threads.  */
-      if (non_stop)
+      if (target_is_non_stop_p ())
 	target_stop (pid_to_ptid (inferior->pid));
 
       /* Tell the user/frontend where we're stopped.  */
@@ -2645,7 +2645,7 @@ attach_command (char *args, int from_tty)
   init_wait_for_inferior ();
   clear_proceed_status (0);
 
-  if (non_stop)
+  if (target_is_non_stop_p ())
     {
       /* If we find that the current thread isn't stopped, explicitly
 	 do so now, because we're going to install breakpoints and
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 75c5080..d9fc4e5 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1624,7 +1624,7 @@ show_can_use_displaced_stepping (struct ui_file *file, int from_tty,
     fprintf_filtered (file,
 		      _("Debugger's willingness to use displaced stepping "
 			"to step over breakpoints is %s (currently %s).\n"),
-		      value, non_stop ? "on" : "off");
+		      value, target_is_non_stop_p () ? "on" : "off");
   else
     fprintf_filtered (file,
 		      _("Debugger's willingness to use displaced stepping "
@@ -1637,7 +1637,8 @@ show_can_use_displaced_stepping (struct ui_file *file, int from_tty,
 static int
 use_displaced_stepping (struct gdbarch *gdbarch)
 {
-  return (((can_use_displaced_stepping == AUTO_BOOLEAN_AUTO && non_stop)
+  return (((can_use_displaced_stepping == AUTO_BOOLEAN_AUTO
+	    && target_is_non_stop_p ())
 	   || can_use_displaced_stepping == AUTO_BOOLEAN_TRUE)
 	  && gdbarch_displaced_step_copy_insn_p (gdbarch)
 	  && find_record_target () == NULL);
@@ -2008,7 +2009,7 @@ start_step_over (void)
 	 because we wouldn't be able to resume anything else until the
 	 target stops again.  In non-stop, the resume always resumes
 	 only TP, so it's OK to let the thread resume freely.  */
-      if (!non_stop && !step_what)
+      if (!target_is_non_stop_p () && !step_what)
 	continue;
 
       switch_to_thread (tp->ptid);
@@ -2027,7 +2028,7 @@ start_step_over (void)
 	  return 1;
 	}
 
-      if (!non_stop)
+      if (!target_is_non_stop_p ())
 	{
 	  /* On all-stop, shouldn't have resumed unless we needed a
 	     step over.  */
@@ -2383,7 +2384,15 @@ resume (enum gdb_signal sig)
 	      insert_single_step_breakpoint (gdbarch, aspace, pc);
 	      insert_breakpoints ();
 
-	      resume_ptid = user_visible_resume_ptid (user_step);
+	      /* In non-stop, we always control threads individually.
+		 Note that the target may always work in non-stop mode
+		 even with "set non-stop off", in which case
+		 user_visible_resume_ptid could return a wildcard
+		 ptid.  */
+	      if (target_is_non_stop_p ())
+		resume_ptid = inferior_ptid;
+	      else
+		resume_ptid = user_visible_resume_ptid (user_step);
 	      do_target_resume (resume_ptid, 0, GDB_SIGNAL_0);
 	      discard_cleanups (old_cleanups);
 	      tp->resumed = 1;
@@ -2498,8 +2507,14 @@ resume (enum gdb_signal sig)
   resume_ptid = user_visible_resume_ptid (user_step);
 
   /* Maybe resume a single thread after all.  */
-  if ((step || thread_has_single_step_breakpoints_set (tp))
-      && tp->control.trap_expected)
+  if (target_is_non_stop_p ())
+    {
+      /* If non-stop mode, threads are always controlled
+	 individually.  */
+      resume_ptid = inferior_ptid;
+    }
+  else if ((step || thread_has_single_step_breakpoints_set (tp))
+	   && tp->control.trap_expected)
     {
       /* We're allowing a thread to run past a breakpoint it has
 	 hit, by single-stepping the thread with the breakpoint
@@ -2929,11 +2944,52 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
 	 other thread was already doing one.  In either case, don't
 	 resume anything else until the step-over is finished.  */
     }
-  else if (started && !non_stop)
+  else if (started && !target_is_non_stop_p ())
     {
       /* A new displaced stepping sequence was started.  In all-stop,
 	 we can't talk to the target anymore until it next stops.  */
     }
+  else if (!non_stop && target_is_non_stop_p ())
+    {
+      /* In all-stop, but the target is always in non-stop mode.
+	 Start all other threads that are implicitly resumed too.  */
+      ALL_NON_EXITED_THREADS (tp)
+        {
+	  /* Ignore threads of processes we're not resuming.  */
+	  if (!ptid_match (tp->ptid, resume_ptid))
+	    continue;
+
+	  if (tp->resumed)
+	    {
+	      if (debug_infrun)
+		fprintf_unfiltered (gdb_stdlog,
+				    "infrun: proceed: [%s] resumed\n",
+				    target_pid_to_str (tp->ptid));
+	      gdb_assert (tp->executing || tp->suspend.waitstatus_pending_p);
+	      continue;
+	    }
+
+	  if (thread_is_in_step_over_chain (tp))
+	    {
+	      if (debug_infrun)
+		fprintf_unfiltered (gdb_stdlog,
+				    "infrun: proceed: [%s] needs step-over\n",
+				    target_pid_to_str (tp->ptid));
+	      continue;
+	    }
+
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: proceed: resuming %s\n",
+				target_pid_to_str (tp->ptid));
+
+	  reset_ecs (ecs, tp);
+	  switch_to_thread (tp->ptid);
+	  keep_going_pass_signal (ecs);
+	  if (!ecs->wait_some_more)
+	    error ("Command aborted.");
+	}
+    }
   else if (!tp->resumed && !thread_is_in_step_over_chain (tp))
     {
       /* The thread wasn't started, and isn't queued, run it now.  */
@@ -3145,7 +3201,7 @@ for_each_just_stopped_thread (for_each_just_stopped_thread_callback_func func)
   if (!target_has_execution || ptid_equal (inferior_ptid, null_ptid))
     return;
 
-  if (non_stop)
+  if (target_is_non_stop_p ())
     {
       /* If in non-stop mode, only the current thread stopped.  */
       func (inferior_thread ());
@@ -3626,7 +3682,7 @@ fetch_inferior_event (void *client_data)
   /* If an error happens while handling the event, propagate GDB's
      knowledge of the executing state to the frontend/user running
      state.  */
-  if (!non_stop)
+  if (!target_is_non_stop_p ())
     ts_old_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
   else
     ts_old_chain = make_cleanup (finish_thread_state_cleanup, &ecs->ptid);
@@ -3865,7 +3921,8 @@ adjust_pc_after_break (struct thread_info *thread,
      to get the "stopped by SW BP and needs adjustment" info out of
      the target/kernel (and thus never reach here; see above).  */
   if (software_breakpoint_inserted_here_p (aspace, breakpoint_pc)
-      || (non_stop && moribund_breakpoint_here_p (aspace, breakpoint_pc)))
+      || (target_is_non_stop_p ()
+	  && moribund_breakpoint_here_p (aspace, breakpoint_pc)))
     {
       struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL);
 
@@ -4142,7 +4199,7 @@ stop_all_threads (void)
   ptid_t entry_ptid;
   struct cleanup *old_chain;
 
-  gdb_assert (non_stop);
+  gdb_assert (target_is_non_stop_p ());
 
   if (debug_infrun)
     fprintf_unfiltered (gdb_stdlog, "infrun: stop_all_threads\n");
@@ -4454,7 +4511,7 @@ handle_inferior_event_1 (struct execution_control_state *ecs)
   {
     ptid_t mark_ptid;
 
-    if (!non_stop)
+    if (!target_is_non_stop_p ())
       mark_ptid = minus_one_ptid;
     else if (ecs->ws.kind == TARGET_WAITKIND_SIGNALLED
 	     || ecs->ws.kind == TARGET_WAITKIND_EXITED)
@@ -4768,7 +4825,8 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
 	  child = ecs->ws.value.related_pid;
 
 	  /* In non-stop mode, also resume the other branch.  */
-	  if (non_stop && !detach_fork)
+	  if (!detach_fork && (non_stop
+			       || (sched_multi && target_is_non_stop_p ())))
 	    {
 	      if (follow_child)
 		switch_to_thread (parent);
@@ -5052,7 +5110,7 @@ finish_step_over (struct execution_control_state *ecs)
 	clear_step_over_info ();
     }
 
-  if (!non_stop)
+  if (!target_is_non_stop_p ())
     return 0;
 
   /* Start a new step-over in another thread if there's one that
@@ -5632,15 +5690,17 @@ handle_signal_stop (struct execution_control_state *ecs)
 	  /* Reset trap_expected to ensure breakpoints are re-inserted.  */
 	  ecs->event_thread->control.trap_expected = 0;
 
-	  if (non_stop)
+	  if (target_is_non_stop_p ())
 	    {
+	      /* Either "set non-stop" is "on", or the target is
+		 always in non-stop mode.  In this case, we have a bit
+		 more work to do.  Resume the current thread, and if
+		 we had paused all threads, restart them while the
+		 signal handler runs.  */
 	      keep_going (ecs);
 
-	      /* The step-over has been canceled temporarily while the
-		 signal handler executes.  */
 	      if (was_in_line)
 		{
-		  /* We had paused all threads, restart them.  */
 		  restart_threads (ecs->event_thread);
 		}
 	      else if (debug_infrun)
@@ -6535,7 +6595,7 @@ process_event_stop_test (struct execution_control_state *ecs)
 static int
 switch_back_to_stepped_thread (struct execution_control_state *ecs)
 {
-  if (!non_stop)
+  if (!target_is_non_stop_p ())
     {
       struct thread_info *tp;
       struct thread_info *stepping_thread;
@@ -6626,7 +6686,8 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
 
       ALL_NON_EXITED_THREADS (tp)
         {
-	  /* Ignore threads of processes we're not resuming.  */
+	  /* Ignore threads of processes the caller is not
+	     resuming.  */
 	  if (!sched_multi
 	      && ptid_get_pid (tp->ptid) != ptid_get_pid (ecs->ptid))
 	    continue;
@@ -6772,7 +6833,10 @@ keep_going_stepped_thread (struct thread_info *tp)
 				     stop_pc);
 
       tp->resumed = 1;
-      resume_ptid = user_visible_resume_ptid (tp->control.stepping_command);
+      if (target_is_non_stop_p ())
+	resume_ptid = inferior_ptid;
+      else
+	resume_ptid = user_visible_resume_ptid (tp->control.stepping_command);
       do_target_resume (resume_ptid, 0, GDB_SIGNAL_0);
     }
   else
@@ -7192,6 +7256,11 @@ stop_waiting (struct execution_control_state *ecs)
 
   /* Let callers know we don't want to wait for the inferior anymore.  */
   ecs->wait_some_more = 0;
+
+  /* If all-stop, but the target is always in non-stop mode, stop all
+     threads now that we're presenting the stop to the user.  */
+  if (!non_stop && target_is_non_stop_p ())
+    stop_all_threads ();
 }
 
 /* Like keep_going, but passes the signal to the inferior, even if the
@@ -7306,7 +7375,7 @@ keep_going_pass_signal (struct execution_control_state *ecs)
 	 insert_breakpoints below, because that removes the breakpoint
 	 we're about to step over, otherwise other threads could miss
 	 it.  */
-      if (step_over_info_valid_p () && non_stop)
+      if (step_over_info_valid_p () && target_is_non_stop_p ())
 	stop_all_threads ();
 
       /* Stop stepping if inserting breakpoints fails.  */
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index f95e76c..3323a60 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -1396,13 +1396,13 @@ get_pending_status (struct lwp_info *lp, int *status)
     signo = GDB_SIGNAL_0; /* a pending ptrace event, not a real signal.  */
   else if (lp->status)
     signo = gdb_signal_from_host (WSTOPSIG (lp->status));
-  else if (non_stop && !is_executing (lp->ptid))
+  else if (target_is_non_stop_p () && !is_executing (lp->ptid))
     {
       struct thread_info *tp = find_thread_ptid (lp->ptid);
 
       signo = tp->suspend.stop_signal;
     }
-  else if (!non_stop)
+  else if (!target_is_non_stop_p ())
     {
       struct target_waitstatus last;
       ptid_t last_ptid;
@@ -2953,7 +2953,7 @@ select_event_lwp (ptid_t filter, struct lwp_info **orig_lp, int *status)
      having stepped the thread, wouldn't understand what the trap was
      for, and therefore would report it to the user as a random
      signal.  */
-  if (!non_stop)
+  if (!target_is_non_stop_p ())
     {
       event_lp = iterate_over_lwps (filter,
 				    select_singlestep_lwp_callback, NULL);
@@ -3301,7 +3301,7 @@ linux_nat_filter_event (int lwpid, int status)
     {
       enum gdb_signal signo = gdb_signal_from_host (WSTOPSIG (status));
 
-      if (!non_stop)
+      if (!target_is_non_stop_p ())
 	{
 	  /* Only do the below in all-stop, as we currently use SIGSTOP
 	     to implement target_stop (see linux_nat_stop) in
@@ -3567,7 +3567,7 @@ linux_nat_wait_1 (struct target_ops *ops,
   status = lp->status;
   lp->status = 0;
 
-  if (!non_stop)
+  if (!target_is_non_stop_p ())
     {
       /* Now stop all other LWP's ...  */
       iterate_over_lwps (minus_one_ptid, stop_callback, NULL);
@@ -3609,7 +3609,7 @@ linux_nat_wait_1 (struct target_ops *ops,
      clears it.  */
   last_resume_kind = lp->last_resume_kind;
 
-  if (!non_stop)
+  if (!target_is_non_stop_p ())
     {
       /* In all-stop, from the core's perspective, all LWPs are now
 	 stopped until a new resume action is sent over.  */
@@ -3742,7 +3742,7 @@ linux_nat_wait (struct target_ops *ops,
      specific_process, for example, see linux_nat_wait_1), and
      meanwhile the event became uninteresting.  Don't bother resuming
      LWPs we're not going to wait for if they'd stop immediately.  */
-  if (non_stop)
+  if (target_is_non_stop_p ())
     iterate_over_lwps (minus_one_ptid, resume_stopped_resumed_lwps, &ptid);
 
   event_ptid = linux_nat_wait_1 (ops, ptid, ourstatus, target_options);
@@ -4583,6 +4583,14 @@ linux_nat_supports_non_stop (struct target_ops *self)
   return 1;
 }
 
+/* to_always_non_stop_p implementation.  */
+
+static int
+linux_nat_always_non_stop_p (struct target_ops *self)
+{
+  return 0;
+}
+
 /* True if we want to support multi-process.  To be removed when GDB
    supports multi-exec.  */
 
@@ -4802,7 +4810,7 @@ linux_nat_stop_lwp (struct lwp_info *lwp, void *data)
 static void
 linux_nat_stop (struct target_ops *self, ptid_t ptid)
 {
-  if (non_stop)
+  if (target_is_non_stop_p ())
     iterate_over_lwps (ptid, linux_nat_stop_lwp, NULL);
   else
     linux_ops->to_stop (linux_ops, ptid);
@@ -4901,6 +4909,7 @@ linux_nat_add_target (struct target_ops *t)
   t->to_can_async_p = linux_nat_can_async_p;
   t->to_is_async_p = linux_nat_is_async_p;
   t->to_supports_non_stop = linux_nat_supports_non_stop;
+  t->to_always_non_stop_p = linux_nat_always_non_stop_p;
   t->to_async = linux_nat_async;
   t->to_terminal_inferior = linux_nat_terminal_inferior;
   t->to_terminal_ours = linux_nat_terminal_ours;
diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c
index 36eacbf..8a92acf 100644
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -1744,6 +1744,33 @@ debug_supports_non_stop (struct target_ops *self)
 }
 
 static int
+delegate_always_non_stop_p (struct target_ops *self)
+{
+  self = self->beneath;
+  return self->to_always_non_stop_p (self);
+}
+
+static int
+tdefault_always_non_stop_p (struct target_ops *self)
+{
+  return 0;
+}
+
+static int
+debug_always_non_stop_p (struct target_ops *self)
+{
+  int result;
+  fprintf_unfiltered (gdb_stdlog, "-> %s->to_always_non_stop_p (...)\n", debug_target.to_shortname);
+  result = debug_target.to_always_non_stop_p (&debug_target);
+  fprintf_unfiltered (gdb_stdlog, "<- %s->to_always_non_stop_p (", debug_target.to_shortname);
+  target_debug_print_struct_target_ops_p (&debug_target);
+  fputs_unfiltered (") = ", gdb_stdlog);
+  target_debug_print_int (result);
+  fputs_unfiltered ("\n", gdb_stdlog);
+  return result;
+}
+
+static int
 delegate_find_memory_regions (struct target_ops *self, find_memory_region_ftype arg1, void *arg2)
 {
   self = self->beneath;
@@ -4005,6 +4032,8 @@ install_delegators (struct target_ops *ops)
     ops->to_async = delegate_async;
   if (ops->to_supports_non_stop == NULL)
     ops->to_supports_non_stop = delegate_supports_non_stop;
+  if (ops->to_always_non_stop_p == NULL)
+    ops->to_always_non_stop_p = delegate_always_non_stop_p;
   if (ops->to_find_memory_regions == NULL)
     ops->to_find_memory_regions = delegate_find_memory_regions;
   if (ops->to_make_corefile_notes == NULL)
@@ -4232,6 +4261,7 @@ install_dummy_methods (struct target_ops *ops)
   ops->to_is_async_p = tdefault_is_async_p;
   ops->to_async = tdefault_async;
   ops->to_supports_non_stop = tdefault_supports_non_stop;
+  ops->to_always_non_stop_p = tdefault_always_non_stop_p;
   ops->to_find_memory_regions = dummy_find_memory_regions;
   ops->to_make_corefile_notes = dummy_make_corefile_notes;
   ops->to_get_bookmark = tdefault_get_bookmark;
@@ -4380,6 +4410,7 @@ init_debug_target (struct target_ops *ops)
   ops->to_is_async_p = debug_is_async_p;
   ops->to_async = debug_async;
   ops->to_supports_non_stop = debug_supports_non_stop;
+  ops->to_always_non_stop_p = debug_always_non_stop_p;
   ops->to_find_memory_regions = debug_find_memory_regions;
   ops->to_make_corefile_notes = debug_make_corefile_notes;
   ops->to_get_bookmark = debug_get_bookmark;
diff --git a/gdb/target.c b/gdb/target.c
index e992a35..0b0cc59 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3752,6 +3752,67 @@ maint_show_target_async_command (struct ui_file *file, int from_tty,
 		      "asynchronous mode is %s.\n"), value);
 }
 
+/* Return true if the target operates in non-stop mode even with "set
+   non-stop off".  */
+
+static int
+target_always_non_stop_p (void)
+{
+  return current_target.to_always_non_stop_p (&current_target);
+}
+
+/* See target.h.  */
+
+int
+target_is_non_stop_p (void)
+{
+  return (non_stop
+	  || target_non_stop_enabled == AUTO_BOOLEAN_TRUE
+	  || (target_non_stop_enabled == AUTO_BOOLEAN_AUTO
+	      && target_always_non_stop_p ()));
+}
+
+/* Controls if targets can report that they always run in non-stop
+   mode.  This is just for maintainers to use when debugging gdb.  */
+enum auto_boolean target_non_stop_enabled = AUTO_BOOLEAN_AUTO;
+
+/* The set command writes to this variable.  If the inferior is
+   executing, target_non_stop_enabled is *not* updated.  */
+static enum auto_boolean target_non_stop_enabled_1 = AUTO_BOOLEAN_AUTO;
+
+/* Implementation of "maint set target-non-stop".  */
+
+static void
+maint_set_target_non_stop_command (char *args, int from_tty,
+				   struct cmd_list_element *c)
+{
+  if (have_live_inferiors ())
+    {
+      target_non_stop_enabled_1 = target_non_stop_enabled;
+      error (_("Cannot change this setting while the inferior is running."));
+    }
+
+  target_non_stop_enabled = target_non_stop_enabled_1;
+}
+
+/* Implementation of "maint show target-non-stop".  */
+
+static void
+maint_show_target_non_stop_command (struct ui_file *file, int from_tty,
+				    struct cmd_list_element *c,
+				    const char *value)
+{
+  if (target_non_stop_enabled == AUTO_BOOLEAN_AUTO)
+    fprintf_filtered (file,
+		      _("Whether the target is always in non-stop mode "
+			"is %s (currently %s).\n"), value,
+		      target_always_non_stop_p () ? "on" : "off");
+  else
+    fprintf_filtered (file,
+		      _("Whether the target is always in non-stop mode "
+			"is %s.\n"), value);
+}
+
 /* Temporary copies of permission settings.  */
 
 static int may_write_registers_1 = 1;
@@ -3854,6 +3915,16 @@ Tells gdb whether to control the inferior in asynchronous mode."),
 			   &maintenance_set_cmdlist,
 			   &maintenance_show_cmdlist);
 
+  add_setshow_auto_boolean_cmd ("target-non-stop", no_class,
+				&target_non_stop_enabled_1, _("\
+Set whether gdb always controls the inferior in non-stop mode."), _("\
+Show whether gdb always controls the inferior in non-stop mode."), _("\
+Tells gdb whether to control the inferior in non-stop mode."),
+			   maint_set_target_non_stop_command,
+			   maint_show_target_non_stop_command,
+			   &maintenance_set_cmdlist,
+			   &maintenance_show_cmdlist);
+
   add_setshow_boolean_cmd ("may-write-registers", class_support,
 			   &may_write_registers_1, _("\
 Set permission to write into registers."), _("\
diff --git a/gdb/target.h b/gdb/target.h
index f14fbdb..10236f0 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -640,6 +640,10 @@ struct target_ops
        comment on 'to_can_run'.  */
     int (*to_supports_non_stop) (struct target_ops *)
       TARGET_DEFAULT_RETURN (0);
+    /* Return true if the target operates in non-stop mode even with
+       "set non-stop off".  */
+    int (*to_always_non_stop_p) (struct target_ops *)
+      TARGET_DEFAULT_RETURN (0);
     /* find_memory_regions support method for gcore */
     int (*to_find_memory_regions) (struct target_ops *,
 				   find_memory_region_ftype func, void *data)
@@ -1706,6 +1710,15 @@ extern int target_async_permitted;
 /* Enables/disabled async target events.  */
 extern void target_async (int enable);
 
+/* Whether support for controlling the target backends always in
+   non-stop mode is enabled.  */
+extern enum auto_boolean target_non_stop_enabled;
+
+/* Is the target in non-stop mode?  Some targets control the inferior
+   in non-stop mode even with "set non-stop off".  Always true if "set
+   non-stop" is on.  */
+extern int target_is_non_stop_p (void);
+
 #define target_execution_direction() \
   (current_target.to_execution_direction (&current_target))
 
-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 06/18] Use keep_going in proceed and start_step_over too
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
                   ` (4 preceding siblings ...)
  2015-05-21 23:19 ` [PATCH 09/18] Factor out code to re-resume stepped thread Pedro Alves
@ 2015-05-21 23:19 ` Pedro Alves
  2015-05-21 23:19 ` [PATCH 02/18] Change adjust_pc_after_break's prototype Pedro Alves
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:19 UTC (permalink / raw)
  To: gdb-patches

The main motivation of this patch is sharing more code between the
proceed (starting the inferior for the first time) and keep_going
(restarting the inferior after handling an event) paths and using the
step_over_chain queue now embedded in the thread_info object for
pending in-line step-overs too (instead of just for displaced
stepping).

So this commit:

 - splits out a new keep_going_pass_signal function out of keep_going
   that is just like keep_going except for the bits that clear the
   signal to pass if the signal is set to "handle nopass".

 - makes proceed use keep_going too.

 - Makes start_step_over use keep_going_pass_signal instead of lower
   level displaced stepping things.

One user visible change: if inserting breakpoints while trying to
proceed fails, we now get:

  (gdb) si
  Warning:
  Could not insert hardware watchpoint 7.
  Could not insert hardware breakpoints:
  You may have requested too many hardware breakpoints/watchpoints.

  Command aborted.
  (gdb)

while before we only saw warnings with no indication that the command
was cancelled:

  (gdb) si
  Warning:
  Could not insert hardware watchpoint 7.
  Could not insert hardware breakpoints:
  You may have requested too many hardware breakpoints/watchpoints.

  (gdb)

Tested on x86_64-linux-gnu, ppc64-linux-gnu and s390-linux-gnu.

gdb/ChangeLog:
2015-05-21  Pedro Alves  <palves@redhat.com>

	* gdbthread.h (struct thread_info) <prev_pc>: Extend comment.
	* infrun.c (struct execution_control_state): Move higher up in the
	file.
	(reset_ecs): New function.
	(start_step_over): Now returns int.  Rewrite to use
	keep_going_pass_signal instead of manually starting a displaced step.
	(resume): Don't call set_running here.  If displaced stepping
	can't start now, clear trap_expected.
	(find_thread_needs_step_over): Delete function.
	(proceed): Set up finish_thread_state_cleanup.  Call set_running.
	If the current thread needs a step over, push it in the step-over
	chain.  Don't set insert breakpoints nor call resume directly
	here.  Instead rewrite to use start_step_over and
	keep_going_pass_signal.
	(finish_step_over): New function.
	(handle_signal_stop): Call finish_step_over instead of
	start_step_over.
	(switch_back_to_stepped_thread): If the event thread needs another
	step-over do that first.  Use start_step_over.
	(keep_going_pass_signal): New function, factored out from ...
	(keep_going): ... here.
	(_initialize_infrun): Comment moved here.
	* thread.c (set_running_thread): New function.
	(set_running, finish_thread_state): Use set_running_thread.

v4:

 - Tweaked comment in start_step_over.
 - keep_going_pass -> keep_going_pass_signal

v3:

 - Adjusted to step_over_chain changes.  Fixed gdb internal error
   caught by signal-sigtrap.exp on ARM (software single-step target).

v2:

 - Testing on x86_64 with software single-step revealed v1 missed
   setting prev_pc on proceed, for switch_back_to_stepped_thread.
   Rewrite tail end of proceed to fix that.  This ends up simplifying
   later patches in the series.
---
 gdb/gdbthread.h |   6 +-
 gdb/infrun.c    | 579 ++++++++++++++++++++++++++++----------------------------
 gdb/thread.c    |  52 +++--
 3 files changed, 324 insertions(+), 313 deletions(-)

diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 3f689c4..60b4fd3 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -208,8 +208,10 @@ struct thread_info
 
   /* Internal stepping state.  */
 
-  /* Record the pc of the thread the last time it stopped.  This is
-     maintained by proceed and keep_going, and used in
+  /* Record the pc of the thread the last time it was resumed.  (It
+     can't be done on stop as the PC may change since the last stop,
+     e.g., "return" command, or "p $pc = 0xf000").  This is maintained
+     by proceed and keep_going, and among other things, it's used in
      adjust_pc_after_break to distinguish a hardware single-step
      SIGTRAP from a breakpoint SIGTRAP.  */
   CORE_ADDR prev_pc;
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 3843c0b..2c8a963 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1836,31 +1836,61 @@ displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal)
   displaced->step_ptid = null_ptid;
 }
 
-/* Are there any pending step-over requests?  If so, run all we can
-   now.  */
+/* Data to be passed around while handling an event.  This data is
+   discarded between events.  */
+struct execution_control_state
+{
+  ptid_t ptid;
+  /* The thread that got the event, if this was a thread event; NULL
+     otherwise.  */
+  struct thread_info *event_thread;
+
+  struct target_waitstatus ws;
+  int stop_func_filled_in;
+  CORE_ADDR stop_func_start;
+  CORE_ADDR stop_func_end;
+  const char *stop_func_name;
+  int wait_some_more;
+
+  /* True if the event thread hit the single-step breakpoint of
+     another thread.  Thus the event doesn't cause a stop, the thread
+     needs to be single-stepped past the single-step breakpoint before
+     we can switch back to the original stepping thread.  */
+  int hit_singlestep_breakpoint;
+};
+
+/* Clear ECS and set it to point at TP.  */
 
 static void
+reset_ecs (struct execution_control_state *ecs, struct thread_info *tp)
+{
+  memset (ecs, 0, sizeof (*ecs));
+  ecs->event_thread = tp;
+  ecs->ptid = tp->ptid;
+}
+
+static void keep_going_pass_signal (struct execution_control_state *ecs);
+static void prepare_to_wait (struct execution_control_state *ecs);
+static int thread_still_needs_step_over (struct thread_info *tp);
+
+/* Are there any pending step-over requests?  If so, run all we can
+   now and return true.  Otherwise, return false.  */
+
+static int
 start_step_over (void)
 {
   struct thread_info *tp, *next;
 
   for (tp = step_over_queue_head; tp != NULL; tp = next)
     {
-      ptid_t ptid;
-      struct displaced_step_inferior_state *displaced;
-      struct regcache *regcache;
-      struct gdbarch *gdbarch;
-      CORE_ADDR actual_pc;
-      struct address_space *aspace;
-      struct inferior *inf = find_inferior_ptid (tp->ptid);
+      struct execution_control_state ecss;
+      struct execution_control_state *ecs = &ecss;
 
       next = thread_step_over_chain_next (tp);
 
-      displaced = get_displaced_stepping_state (inf->pid);
-
       /* If this inferior already has a displaced step in process,
 	 don't start a new one.  */
-      if (!ptid_equal (displaced->step_ptid, null_ptid))
+      if (displaced_step_in_progress (ptid_get_pid (tp->ptid)))
 	continue;
 
       thread_step_over_chain_remove (tp);
@@ -1872,73 +1902,57 @@ start_step_over (void)
 				"infrun: step-over queue now empty\n");
 	}
 
-      ptid = tp->ptid;
-      context_switch (ptid);
-
-      regcache = get_thread_regcache (ptid);
-      actual_pc = regcache_read_pc (regcache);
-      aspace = get_regcache_aspace (regcache);
-      gdbarch = get_regcache_arch (regcache);
-
-      if (breakpoint_here_p (aspace, actual_pc))
+      if (tp->control.trap_expected || tp->executing)
 	{
-	  if (debug_displaced)
-	    fprintf_unfiltered (gdb_stdlog,
-				"displaced: stepping queued %s now\n",
-				target_pid_to_str (ptid));
-
-	  displaced_step_prepare (ptid);
-
-	  if (debug_displaced)
-	    {
-	      CORE_ADDR actual_pc = regcache_read_pc (regcache);
-	      gdb_byte buf[4];
-
-	      fprintf_unfiltered (gdb_stdlog, "displaced: run %s: ",
-				  paddress (gdbarch, actual_pc));
-	      read_memory (actual_pc, buf, sizeof (buf));
-	      displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf));
-	    }
-
-	  if (gdbarch_displaced_step_hw_singlestep (gdbarch,
-						    displaced->step_closure))
-	    target_resume (ptid, 1, GDB_SIGNAL_0);
-	  else
-	    target_resume (ptid, 0, GDB_SIGNAL_0);
-
-	  /* Done, we're stepping a thread.  */
+	  internal_error (__FILE__, __LINE__,
+			  "[%s] has inconsistent state: "
+			  "trap_expected=%d, executing=%d\n",
+			  target_pid_to_str (tp->ptid),
+			  tp->control.trap_expected,
+			  tp->executing);
 	}
-      else
-	{
-	  int step;
-	  struct thread_info *tp = inferior_thread ();
-
-	  /* The breakpoint we were sitting under has since been
-	     removed.  */
-	  tp->control.trap_expected = 0;
-
-	  /* Go back to what we were trying to do.  */
-	  step = currently_stepping (tp);
 
-	  if (step)
-	    step = maybe_software_singlestep (gdbarch, actual_pc);
+      if (debug_infrun)
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: resuming [%s] for step-over\n",
+			    target_pid_to_str (tp->ptid));
+
+      /* keep_going_pass_signal skips the step-over if the breakpoint
+	 is no longer inserted.  In all-stop, we want to keep looking
+	 for a thread that needs a step-over instead of resuming TP,
+	 because we wouldn't be able to resume anything else until the
+	 target stops again.  In non-stop, the resume always resumes
+	 only TP, so it's OK to let the thread resume freely.  */
+      if (!non_stop && !thread_still_needs_step_over (tp))
+	continue;
 
-	  if (debug_displaced)
-	    fprintf_unfiltered (gdb_stdlog,
-				"displaced: breakpoint is gone: %s, step(%d)\n",
-				target_pid_to_str (tp->ptid), step);
+      switch_to_thread (tp->ptid);
+      reset_ecs (ecs, tp);
+      keep_going_pass_signal (ecs);
 
-	  target_resume (ptid, step, GDB_SIGNAL_0);
-	  tp->suspend.stop_signal = GDB_SIGNAL_0;
+      if (!ecs->wait_some_more)
+	error (_("Command aborted."));
 
-	  /* This request was discarded.  See if there's any other
-	     thread waiting for its turn.  */
+      if (!non_stop)
+	{
+	  /* On all-stop, shouldn't have resumed unless we needed a
+	     step over.  */
+	  gdb_assert (tp->control.trap_expected
+		      || tp->step_after_step_resume_breakpoint);
+
+	  /* With remote targets (at least), in all-stop, we can't
+	     issue any further remote commands until the program stops
+	     again.  */
+	  return 1;
 	}
 
-      /* A new displaced stepping sequence started.  Maybe we can
-	 start a displaced step on a thread of other process.
-	 Continue looking.  */
+      /* Either the thread no longer needed a step-over, or a new
+	 displaced stepping sequence started.  Even in the latter
+	 case, continue looking.  Maybe we can also start another
+	 displaced step on a thread of other process. */
     }
+
+  return 0;
 }
 
 /* Update global variables holding ptids to hold NEW_PTID if they were
@@ -2275,16 +2289,11 @@ resume (enum gdb_signal sig)
 
       if (!displaced_step_prepare (inferior_ptid))
 	{
-	  /* Got placed in displaced stepping queue.  Will be resumed
-	     later when all the currently queued displaced stepping
-	     requests finish.  The thread is not executing at this
-	     point, and the call to set_executing will be made later.
-	     But we need to call set_running here, since from the
-	     user/frontend's point of view, threads were set running.
-	     Unless we're calling an inferior function, as in that
-	     case we pretend the inferior doesn't run at all.  */
-	  if (!tp->control.in_infcall)
-	    set_running (user_visible_resume_ptid (user_step), 1);
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"Got placed in step-over queue\n");
+
+	  tp->control.trap_expected = 0;
 	  discard_cleanups (old_cleanups);
 	  return;
 	}
@@ -2359,14 +2368,6 @@ resume (enum gdb_signal sig)
      by applying increasingly restricting conditions.  */
   resume_ptid = user_visible_resume_ptid (user_step);
 
-  /* Even if RESUME_PTID is a wildcard, and we end up resuming less
-     (e.g., we might need to step over a breakpoint), from the
-     user/frontend's point of view, all threads in RESUME_PTID are now
-     running.  Unless we're calling an inferior function, as in that
-     case pretend we inferior doesn't run at all.  */
-  if (!tp->control.in_infcall)
-    set_running (resume_ptid, 1);
-
   /* Maybe resume a single thread after all.  */
   if ((step || thread_has_single_step_breakpoints_set (tp))
       && tp->control.trap_expected)
@@ -2575,48 +2576,6 @@ schedlock_applies (struct thread_info *tp)
 	      && tp->control.stepping_command));
 }
 
-/* Look a thread other than EXCEPT that has previously reported a
-   breakpoint event, and thus needs a step-over in order to make
-   progress.  Returns NULL is none is found.  */
-
-static struct thread_info *
-find_thread_needs_step_over (struct thread_info *except)
-{
-  struct thread_info *tp, *current;
-
-  /* With non-stop mode on, threads are always handled individually.  */
-  gdb_assert (! non_stop);
-
-  current = inferior_thread ();
-
-  /* If scheduler locking applies, we can avoid iterating over all
-     threads.  */
-  if (schedlock_applies (except))
-    {
-      if (except != current
-	  && thread_still_needs_step_over (current))
-	return current;
-
-      return NULL;
-    }
-
-  ALL_NON_EXITED_THREADS (tp)
-    {
-      /* Ignore the EXCEPT thread.  */
-      if (tp == except)
-	continue;
-      /* Ignore threads of processes we're not resuming.  */
-      if (!sched_multi
-	  && ptid_get_pid (tp->ptid) != ptid_get_pid (inferior_ptid))
-	continue;
-
-      if (thread_still_needs_step_over (tp))
-	return tp;
-    }
-
-  return NULL;
-}
-
 /* Basic routine for continuing the program in various fashions.
 
    ADDR is the address to resume at, or -1 for resume where stopped.
@@ -2637,6 +2596,11 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
   struct thread_info *tp;
   CORE_ADDR pc;
   struct address_space *aspace;
+  ptid_t resume_ptid;
+  struct execution_control_state ecss;
+  struct execution_control_state *ecs = &ecss;
+  struct cleanup *old_chain;
+  int started;
 
   /* If we're stopped at a fork/vfork, follow the branch set by the
      "set follow-fork-mode" command; otherwise, we'll just proceed
@@ -2699,7 +2663,23 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
      (next/step/etc.), we'll want to print stop event output to the MI
      console channel (the stepped-to line, etc.), as if the user
      entered the execution command on a real GDB console.  */
-  inferior_thread ()->control.command_interp = command_interp ();
+  tp->control.command_interp = command_interp ();
+
+  resume_ptid = user_visible_resume_ptid (tp->control.stepping_command);
+
+  /* If an exception is thrown from this point on, make sure to
+     propagate GDB's knowledge of the executing state to the
+     frontend/user running state.  */
+  old_chain = make_cleanup (finish_thread_state_cleanup, &resume_ptid);
+
+  /* Even if RESUME_PTID is a wildcard, and we end up resuming fewer
+     threads (e.g., we might need to set threads stepping over
+     breakpoints first), from the user/frontend's point of view, all
+     threads in RESUME_PTID are now running.  Unless we're calling an
+     inferior function, as in that case we pretend the inferior
+     doesn't run at all.  */
+  if (!tp->control.in_infcall)
+   set_running (resume_ptid, 1);
 
   if (debug_infrun)
     fprintf_unfiltered (gdb_stdlog,
@@ -2707,91 +2687,92 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
 			paddress (gdbarch, addr),
 			gdb_signal_to_symbol_string (siggnal));
 
-  if (non_stop)
-    /* In non-stop, each thread is handled individually.  The context
-       must already be set to the right thread here.  */
-    ;
-  else
+  annotate_starting ();
+
+  /* Make sure that output from GDB appears before output from the
+     inferior.  */
+  gdb_flush (gdb_stdout);
+
+  /* In a multi-threaded task we may select another thread and
+     then continue or step.
+
+     But if a thread that we're resuming had stopped at a breakpoint,
+     it will immediately cause another breakpoint stop without any
+     execution (i.e. it will report a breakpoint hit incorrectly).  So
+     we must step over it first.
+
+     Look for threads other than the current (TP) that reported a
+     breakpoint hit and haven't been resumed yet since.  */
+
+  /* If scheduler locking applies, we can avoid iterating over all
+     threads.  */
+  if (!non_stop && !schedlock_applies (tp))
     {
-      struct thread_info *step_over;
+      struct thread_info *current = tp;
 
-      /* In a multi-threaded task we may select another thread and
-	 then continue or step.
+      ALL_NON_EXITED_THREADS (tp)
+        {
+	  /* Ignore the current thread here.  It's handled
+	     afterwards.  */
+	  if (tp == current)
+	    continue;
 
-	 But if the old thread was stopped at a breakpoint, it will
-	 immediately cause another breakpoint stop without any
-	 execution (i.e. it will report a breakpoint hit incorrectly).
-	 So we must step over it first.
+	  /* Ignore threads of processes we're not resuming.  */
+	  if (!ptid_match (tp->ptid, resume_ptid))
+	    continue;
+
+	  if (!thread_still_needs_step_over (tp))
+	    continue;
+
+	  gdb_assert (!thread_is_in_step_over_chain (tp));
 
-	 Look for a thread other than the current (TP) that reported a
-	 breakpoint hit and hasn't been resumed yet since.  */
-      step_over = find_thread_needs_step_over (tp);
-      if (step_over != NULL)
-	{
 	  if (debug_infrun)
 	    fprintf_unfiltered (gdb_stdlog,
 				"infrun: need to step-over [%s] first\n",
-				target_pid_to_str (step_over->ptid));
+				target_pid_to_str (tp->ptid));
 
-	  /* Store the prev_pc for the stepping thread too, needed by
-	     switch_back_to_stepped_thread.  */
-	  tp->prev_pc = regcache_read_pc (get_current_regcache ());
-	  switch_to_thread (step_over->ptid);
-	  tp = step_over;
+	  thread_step_over_chain_enqueue (tp);
 	}
-    }
-
-  /* If we need to step over a breakpoint, and we're not using
-     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))
-    {
-      struct regcache *regcache = get_current_regcache ();
 
-      set_step_over_info (get_regcache_aspace (regcache),
-			  regcache_read_pc (regcache), 0);
+      tp = current;
     }
-  else
-    clear_step_over_info ();
 
-  insert_breakpoints ();
+  /* Enqueue the current thread last, so that we move all other
+     threads over their breakpoints first.  */
+  if (tp->stepping_over_breakpoint)
+    thread_step_over_chain_enqueue (tp);
 
-  tp->control.trap_expected = tp->stepping_over_breakpoint;
+  /* If the thread isn't started, we'll still need to set its prev_pc,
+     so that switch_back_to_stepped_thread knows the thread hasn't
+     advanced.  Must do this before resuming any thread, as in
+     all-stop/remote, once we resume we can't send any other packet
+     until the target stops again.  */
+  tp->prev_pc = regcache_read_pc (regcache);
 
-  annotate_starting ();
+  started = start_step_over ();
 
-  /* Make sure that output from GDB appears before output from the
-     inferior.  */
-  gdb_flush (gdb_stdout);
+  if (step_over_info_valid_p ())
+    {
+      /* Either this thread started a new in-line step over, or some
+	 other thread was already doing one.  In either case, don't
+	 resume anything else until the step-over is finished.  */
+    }
+  else if (started && !non_stop)
+    {
+      /* A new displaced stepping sequence was started.  In all-stop,
+	 we can't talk to the target anymore until it next stops.  */
+    }
+  else if (!tp->executing && !thread_is_in_step_over_chain (tp))
+    {
+      /* The thread wasn't started, and isn't queued, run it now.  */
+      reset_ecs (ecs, tp);
+      switch_to_thread (tp->ptid);
+      keep_going_pass_signal (ecs);
+      if (!ecs->wait_some_more)
+	error ("Command aborted.");
+    }
 
-  /* Refresh prev_pc value just prior to resuming.  This used to be
-     done in stop_waiting, however, setting prev_pc there did not handle
-     scenarios such as inferior function calls or returning from
-     a function via the return command.  In those cases, the prev_pc
-     value was not set properly for subsequent commands.  The prev_pc value 
-     is used to initialize the starting line number in the ecs.  With an 
-     invalid value, the gdb next command ends up stopping at the position
-     represented by the next line table entry past our start position.
-     On platforms that generate one line table entry per line, this
-     is not a problem.  However, on the ia64, the compiler generates
-     extraneous line table entries that do not increase the line number.
-     When we issue the gdb next command on the ia64 after an inferior call
-     or a return command, we often end up a few instructions forward, still 
-     within the original line we started.
-
-     An attempt was made to refresh the prev_pc at the same time the
-     execution_control_state is initialized (for instance, just before
-     waiting for an inferior event).  But this approach did not work
-     because of platforms that use ptrace, where the pc register cannot
-     be read unless the inferior is stopped.  At that point, we are not
-     guaranteed the inferior is stopped and so the regcache_read_pc() call
-     can fail.  Setting the prev_pc value here ensures the value is updated
-     correctly when the inferior is stopped.  */
-  tp->prev_pc = regcache_read_pc (get_current_regcache ());
-
-  /* Resume inferior.  */
-  resume (tp->suspend.stop_signal);
+  discard_cleanups (old_chain);
 
   /* Wait for it to stop (if not standalone)
      and in any case decode why it stopped, and act accordingly.  */
@@ -2859,28 +2840,6 @@ init_wait_for_inferior (void)
 }
 
 \f
-/* Data to be passed around while handling an event.  This data is
-   discarded between events.  */
-struct execution_control_state
-{
-  ptid_t ptid;
-  /* The thread that got the event, if this was a thread event; NULL
-     otherwise.  */
-  struct thread_info *event_thread;
-
-  struct target_waitstatus ws;
-  int stop_func_filled_in;
-  CORE_ADDR stop_func_start;
-  CORE_ADDR stop_func_end;
-  const char *stop_func_name;
-  int wait_some_more;
-
-  /* True if the event thread hit the single-step breakpoint of
-     another thread.  Thus the event doesn't cause a stop, the thread
-     needs to be single-stepped past the single-step breakpoint before
-     we can switch back to the original stepping thread.  */
-  int hit_singlestep_breakpoint;
-};
 
 static void handle_inferior_event (struct execution_control_state *ecs);
 
@@ -2894,7 +2853,6 @@ static void check_exception_resume (struct execution_control_state *,
 
 static void end_stepping_range (struct execution_control_state *ecs);
 static void stop_waiting (struct execution_control_state *ecs);
-static void prepare_to_wait (struct execution_control_state *ecs);
 static void keep_going (struct execution_control_state *ecs);
 static void process_event_stop_test (struct execution_control_state *ecs);
 static int switch_back_to_stepped_thread (struct execution_control_state *ecs);
@@ -4270,6 +4228,34 @@ handle_inferior_event (struct execution_control_state *ecs)
   value_free_to_mark (mark);
 }
 
+/* Called when we get an event that may finish an in-line or
+   out-of-line (displaced stepping) step-over started previously.  */
+
+static void
+finish_step_over (struct execution_control_state *ecs)
+{
+  displaced_step_fixup (ecs->ptid,
+			ecs->event_thread->suspend.stop_signal);
+
+  if (step_over_info_valid_p ())
+    {
+      /* If we're stepping over a breakpoint with all threads locked,
+	 then only the thread that was stepped should be reporting
+	 back an event.  */
+      gdb_assert (ecs->event_thread->control.trap_expected);
+
+      if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
+	clear_step_over_info ();
+    }
+
+  if (!non_stop)
+    return;
+
+  /* Start a new step-over in another thread if there's one that
+     needs it.  */
+  start_step_over ();
+}
+
 /* Come here when the program has stopped with a signal.  */
 
 static void
@@ -4286,9 +4272,7 @@ handle_signal_stop (struct execution_control_state *ecs)
   /* Do we need to clean up the state of a thread that has
      completed a displaced single-step?  (Doing so usually affects
      the PC, so do it here, before we set stop_pc.)  */
-  displaced_step_fixup (ecs->ptid,
-			ecs->event_thread->suspend.stop_signal);
-  start_step_over ();
+  finish_step_over (ecs);
 
   /* If we either finished a single-step or hit a breakpoint, but
      the user wanted this thread to be stopped, pretend we got a
@@ -5638,7 +5622,6 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
     {
       struct thread_info *tp;
       struct thread_info *stepping_thread;
-      struct thread_info *step_over;
 
       /* If any thread is blocked on some internal breakpoint, and we
 	 simply need to step over that breakpoint to get it going
@@ -5681,14 +5664,20 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
 	 return 1;
        }
 
-      /* Otherwise, we no longer expect a trap in the current thread.
-	 Clear the trap_expected flag before switching back -- this is
-	 what keep_going does as well, if we call it.  */
-      ecs->event_thread->control.trap_expected = 0;
-
-      /* Likewise, clear the signal if it should not be passed.  */
-      if (!signal_program[ecs->event_thread->suspend.stop_signal])
-	ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
+      /* If this thread needs yet another step-over (e.g., stepping
+	 through a delay slot), do it first before moving on to
+	 another thread.  */
+      if (thread_still_needs_step_over (ecs->event_thread))
+	{
+	  if (debug_infrun)
+	    {
+	      fprintf_unfiltered (gdb_stdlog,
+				  "infrun: thread [%s] still needs step-over\n",
+				  target_pid_to_str (ecs->event_thread->ptid));
+	    }
+	  keep_going (ecs);
+	  return 1;
+	}
 
       /* If scheduler locking applies even if not stepping, there's no
 	 need to walk over threads.  Above we've checked whether the
@@ -5698,12 +5687,26 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
       if (schedlock_applies (ecs->event_thread))
 	return 0;
 
-      /* Look for the stepping/nexting thread, and check if any other
-	 thread other than the stepping thread needs to start a
-	 step-over.  Do all step-overs before actually proceeding with
+      /* Otherwise, we no longer expect a trap in the current thread.
+	 Clear the trap_expected flag before switching back -- this is
+	 what keep_going does as well, if we call it.  */
+      ecs->event_thread->control.trap_expected = 0;
+
+      /* Likewise, clear the signal if it should not be passed.  */
+      if (!signal_program[ecs->event_thread->suspend.stop_signal])
+	ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
+
+      /* Do all pending step-overs before actually proceeding with
 	 step/next/etc.  */
+      if (start_step_over ())
+	{
+	  prepare_to_wait (ecs);
+	  return 1;
+	}
+
+      /* Look for the stepping/nexting thread.  */
       stepping_thread = NULL;
-      step_over = NULL;
+
       ALL_NON_EXITED_THREADS (tp)
         {
 	  /* Ignore threads of processes we're not resuming.  */
@@ -5735,37 +5738,6 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
 
 	      stepping_thread = tp;
 	    }
-	  else if (thread_still_needs_step_over (tp))
-	    {
-	      step_over = tp;
-
-	      /* At the top we've returned early if the event thread
-		 is stepping.  If some other thread not the event
-		 thread is stepping, then scheduler locking can't be
-		 in effect, and we can resume this thread.  No need to
-		 keep looking for the stepping thread then.  */
-	      break;
-	    }
-	}
-
-      if (step_over != NULL)
-	{
-	  tp = step_over;
-	  if (debug_infrun)
-	    {
-	      fprintf_unfiltered (gdb_stdlog,
-				  "infrun: need to step-over [%s]\n",
-				  target_pid_to_str (tp->ptid));
-	    }
-
-	  /* Only the stepping thread should have this set.  */
-	  gdb_assert (tp->control.step_range_end == 0);
-
-	  ecs->ptid = tp->ptid;
-	  ecs->event_thread = tp;
-	  switch_to_thread (ecs->ptid);
-	  keep_going (ecs);
-	  return 1;
 	}
 
       if (stepping_thread != NULL)
@@ -5864,7 +5836,7 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
 		fprintf_unfiltered (gdb_stdlog,
 				    "infrun: expected thread still "
 				    "hasn't advanced\n");
-	      keep_going (ecs);
+	      keep_going_pass_signal (ecs);
 	    }
 
 	  return 1;
@@ -6279,24 +6251,32 @@ stop_waiting (struct execution_control_state *ecs)
   ecs->wait_some_more = 0;
 }
 
-/* Called when we should continue running the inferior, because the
-   current event doesn't cause a user visible stop.  This does the
-   resuming part; waiting for the next event is done elsewhere.  */
+/* Like keep_going, but passes the signal to the inferior, even if the
+   signal is set to nopass.  */
 
 static void
-keep_going (struct execution_control_state *ecs)
+keep_going_pass_signal (struct execution_control_state *ecs)
 {
   /* Make sure normal_stop is called if we get a QUIT handled before
      reaching resume.  */
   struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0);
 
+  gdb_assert (ptid_equal (ecs->event_thread->ptid, inferior_ptid));
+
   /* Save the pc before execution, to compare with pc after stop.  */
   ecs->event_thread->prev_pc
     = regcache_read_pc (get_thread_regcache (ecs->ptid));
 
-  if (ecs->event_thread->control.trap_expected
-      && ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_TRAP)
+  if (ecs->event_thread->control.trap_expected)
     {
+      struct thread_info *tp = ecs->event_thread;
+
+      if (debug_infrun)
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: %s has trap_expected set, "
+			    "resuming to collect trap\n",
+			    target_pid_to_str (tp->ptid));
+
       /* We haven't yet gotten our trap, and either: intercepted a
 	 non-signal event (e.g., a fork); or took a signal which we
 	 are supposed to pass through to the inferior.  Simply
@@ -6367,20 +6347,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);
     }
@@ -6388,6 +6354,22 @@ keep_going (struct execution_control_state *ecs)
   prepare_to_wait (ecs);
 }
 
+/* Called when we should continue running the inferior, because the
+   current event doesn't cause a user visible stop.  This does the
+   resuming part; waiting for the next event is done elsewhere.  */
+
+static void
+keep_going (struct execution_control_state *ecs)
+{
+  if (ecs->event_thread->control.trap_expected
+      && ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
+    ecs->event_thread->control.trap_expected = 0;
+
+  if (!signal_program[ecs->event_thread->suspend.stop_signal])
+    ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
+  keep_going_pass_signal (ecs);
+}
+
 /* This function normally comes after a resume, before
    handle_inferior_event exits.  It takes care of any last bits of
    housekeeping, and sets the all-important wait_some_more flag.  */
@@ -7803,8 +7785,19 @@ leave it stopped or free to run as needed."),
       signal_catch[i] = 0;
     }
 
-  /* Signals caused by debugger's own actions
-     should not be given to the program afterwards.  */
+  /* Signals caused by debugger's own actions should not be given to
+     the program afterwards.
+
+     Do not deliver GDB_SIGNAL_TRAP by default, except when the user
+     explicitly specifies that it 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.  */
   signal_program[GDB_SIGNAL_TRAP] = 0;
   signal_program[GDB_SIGNAL_INT] = 0;
 
diff --git a/gdb/thread.c b/gdb/thread.c
index 28e5ef8..3e3f419 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -852,44 +852,62 @@ thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid)
   observer_notify_thread_ptid_changed (old_ptid, new_ptid);
 }
 
+/* Helper for set_running, that marks one thread either running or
+   stopped.  */
+
+static int
+set_running_thread (struct thread_info *tp, int running)
+{
+  int started = 0;
+
+  if (running && tp->state == THREAD_STOPPED)
+    started = 1;
+  tp->state = running ? THREAD_RUNNING : THREAD_STOPPED;
+
+  if (!running)
+    {
+      /* If the thread is now marked stopped, remove it from
+	 the step-over queue, so that we don't try to resume
+	 it until the user wants it to.  */
+      if (tp->step_over_next != NULL)
+	thread_step_over_chain_remove (tp);
+    }
+
+  return started;
+}
+
 void
 set_running (ptid_t ptid, int running)
 {
   struct thread_info *tp;
   int all = ptid_equal (ptid, minus_one_ptid);
+  int any_started = 0;
 
   /* We try not to notify the observer if no thread has actually changed 
      the running state -- merely to reduce the number of messages to 
      frontend.  Frontend is supposed to handle multiple *running just fine.  */
   if (all || ptid_is_pid (ptid))
     {
-      int any_started = 0;
-
       for (tp = thread_list; tp; tp = tp->next)
 	if (all || ptid_get_pid (tp->ptid) == ptid_get_pid (ptid))
 	  {
 	    if (tp->state == THREAD_EXITED)
 	      continue;
-	    if (running && tp->state == THREAD_STOPPED)
+
+	    if (set_running_thread (tp, running))
 	      any_started = 1;
-	    tp->state = running ? THREAD_RUNNING : THREAD_STOPPED;
 	  }
-      if (any_started)
-	observer_notify_target_resumed (ptid);
     }
   else
     {
-      int started = 0;
-
       tp = find_thread_ptid (ptid);
-      gdb_assert (tp);
+      gdb_assert (tp != NULL);
       gdb_assert (tp->state != THREAD_EXITED);
-      if (running && tp->state == THREAD_STOPPED)
- 	started = 1;
-      tp->state = running ? THREAD_RUNNING : THREAD_STOPPED;
-      if (started)
-  	observer_notify_target_resumed (ptid);
+      if (set_running_thread (tp, running))
+	any_started = 1;
     }
+  if (any_started)
+    observer_notify_target_resumed (ptid);
 }
 
 static int
@@ -1008,9 +1026,8 @@ finish_thread_state (ptid_t ptid)
   	    continue;
 	  if (all || ptid_get_pid (ptid) == ptid_get_pid (tp->ptid))
 	    {
-	      if (tp->executing && tp->state == THREAD_STOPPED)
+	      if (set_running_thread (tp, tp->executing))
 		any_started = 1;
-	      tp->state = tp->executing ? THREAD_RUNNING : THREAD_STOPPED;
 	    }
 	}
     }
@@ -1020,9 +1037,8 @@ finish_thread_state (ptid_t ptid)
       gdb_assert (tp);
       if (tp->state != THREAD_EXITED)
 	{
-	  if (tp->executing && tp->state == THREAD_STOPPED)
+	  if (set_running_thread (tp, tp->executing))
 	    any_started = 1;
-	  tp->state = tp->executing ? THREAD_RUNNING : THREAD_STOPPED;
 	}
     }
 
-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 08/18] Add comments to currently_stepping and target_resume
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
                   ` (11 preceding siblings ...)
  2015-05-21 23:19 ` [PATCH 12/18] Fix signal-while-stepping-over-bp-other-thread.exp on targets always in non-stop Pedro Alves
@ 2015-05-21 23:19 ` Pedro Alves
  2015-05-21 23:25 ` [PATCH 07/18] Misc switch_back_to_stepped_thread cleanups Pedro Alves
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:19 UTC (permalink / raw)
  To: gdb-patches

Clarify that currently_stepping works at a higher level than
target_resume.

gdb/ChangeLog:
2015-05-21  Pedro Alves  <palves@redhat.com>

	* infrun.c (currently_stepping): Extend intro comment.
	* target.h (target_resume): Extend intro comment.

This is a new patch in v4.
---
 gdb/infrun.c | 4 +++-
 gdb/target.h | 4 ++--
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/gdb/infrun.c b/gdb/infrun.c
index 55a6622..9f668a3 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -5848,7 +5848,9 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
   return 0;
 }
 
-/* Is thread TP in the middle of single-stepping?  */
+/* Is thread TP in the middle of (software or hardware)
+   single-stepping?  (Note the result of this function must never be
+   passed directly as target_resume's STEP parameter.)  */
 
 static int
 currently_stepping (struct thread_info *tp)
diff --git a/gdb/target.h b/gdb/target.h
index 3a0ae7b..d398747 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1254,8 +1254,8 @@ extern void target_detach (const char *, int);
 extern void target_disconnect (const char *, int);
 
 /* Resume execution of the target process PTID (or a group of
-   threads).  STEP says whether to single-step or to run free; SIGGNAL
-   is the signal to be given to the target, or GDB_SIGNAL_0 for no
+   threads).  STEP says whether to hardware single-step or to run free;
+   SIGGNAL is the signal to be given to the target, or GDB_SIGNAL_0 for no
    signal.  The caller may not pass GDB_SIGNAL_DEFAULT.  A specific
    PTID means `step/resume only this process id'.  A wildcard PTID
    (all threads, or all threads of process) means `step/resume
-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 04/18] Make thread_still_needs_step_over consider stepping_over_watchpoint too
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
                   ` (7 preceding siblings ...)
  2015-05-21 23:19 ` [PATCH 05/18] Embed the pending step-over chain in thread_info objects Pedro Alves
@ 2015-05-21 23:19 ` Pedro Alves
  2015-05-21 23:19 ` [PATCH 03/18] remote.c/all-stop: Implement TARGET_WAITKIND_NO_RESUMED and TARGET_WNOHANG Pedro Alves
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:19 UTC (permalink / raw)
  To: gdb-patches

I noticed that even though keep_going knows to start a step over for a
watchpoint, thread_still_needs_step_over forgets it.

gdb/ChangeLog:
2015-05-21  Pedro Alves  <palves@redhat.com>

	* infrun.c (thread_still_needs_step_over): Rename to ...
	(thread_still_needs_step_over_bp): ... this.
	(enum step_over_what): New.
	(thread_still_needs_step_over): Reimplement.
---
 gdb/infrun.c | 43 +++++++++++++++++++++++++++++++++++++++----
 1 file changed, 39 insertions(+), 4 deletions(-)

diff --git a/gdb/infrun.c b/gdb/infrun.c
index cce021d..b97d6e8 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1215,6 +1215,19 @@ follow_exec (ptid_t ptid, char *execd_pathname)
      matically get reset there in the new process.).  */
 }
 
+/* Bit flags indicating what the thread needs to step over.  */
+
+enum step_over_what
+  {
+    /* Step over a breakpoint.  */
+    STEP_OVER_BREAKPOINT = 1,
+
+    /* Step past a non-continuable watchpoint, in order to let the
+       instruction execute so we can evaluate the watchpoint
+       expression.  */
+    STEP_OVER_WATCHPOINT = 2
+  };
+
 /* Info about an instruction that is being stepped over.  */
 
 struct step_over_info
@@ -2505,7 +2518,7 @@ clear_proceed_status (int step)
    meanwhile, we can skip the whole step-over dance.  */
 
 static int
-thread_still_needs_step_over (struct thread_info *tp)
+thread_still_needs_step_over_bp (struct thread_info *tp)
 {
   if (tp->stepping_over_breakpoint)
     {
@@ -2522,6 +2535,26 @@ thread_still_needs_step_over (struct thread_info *tp)
   return 0;
 }
 
+/* Check whether thread TP still needs to start a step-over in order
+   to make progress when resumed.  Returns an bitwise or of enum
+   step_over_what bits, indicating what needs to be stepped over.  */
+
+static int
+thread_still_needs_step_over (struct thread_info *tp)
+{
+  struct inferior *inf = find_inferior_ptid (tp->ptid);
+  int what = 0;
+
+  if (thread_still_needs_step_over_bp (tp))
+    what |= STEP_OVER_BREAKPOINT;
+
+  if (tp->stepping_over_watchpoint
+      && !target_have_steppable_watchpoint)
+    what |= STEP_OVER_WATCHPOINT;
+
+  return what;
+}
+
 /* Returns true if scheduler locking applies.  STEP indicates whether
    we're about to do a step/next-like command to a thread.  */
 
@@ -6279,6 +6312,7 @@ keep_going (struct execution_control_state *ecs)
       struct regcache *regcache = get_current_regcache ();
       int remove_bp;
       int remove_wps;
+      enum step_over_what step_what;
 
       /* Either the trap was not expected, but we are continuing
 	 anyway (if we got a signal, the user asked it be passed to
@@ -6299,10 +6333,11 @@ keep_going (struct execution_control_state *ecs)
 	 instruction, and then re-insert the breakpoint when that step
 	 is finished.  */
 
+      step_what = thread_still_needs_step_over (ecs->event_thread);
+
       remove_bp = (ecs->hit_singlestep_breakpoint
-		   || thread_still_needs_step_over (ecs->event_thread));
-      remove_wps = (ecs->event_thread->stepping_over_watchpoint
-		    && !target_have_steppable_watchpoint);
+		   || (step_what & STEP_OVER_BREAKPOINT));
+      remove_wps = (step_what & STEP_OVER_WATCHPOINT);
 
       /* We can't use displaced stepping if we need to step past a
 	 watchpoint.  The instruction copied to the scratch pad would
-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 07/18] Misc switch_back_to_stepped_thread cleanups
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
                   ` (12 preceding siblings ...)
  2015-05-21 23:19 ` [PATCH 08/18] Add comments to currently_stepping and target_resume Pedro Alves
@ 2015-05-21 23:25 ` Pedro Alves
  2015-05-21 23:28 ` [PATCH 13/18] Fix interrupt-noterm.exp on targets always in non-stop Pedro Alves
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:25 UTC (permalink / raw)
  To: gdb-patches

Several misc cleanups that prepare the tail end of this function, the
part that actually re-resumes the stepped thread.

The most non-obvious would be the currently_stepping change, I guess.
That's because it isn't ever correct to pass step=1 to target_resume
on software single-step targets, and currently_stepping works at a
conceptual higher level, it returns step=true even on software step
targets.  It doesn't really matter on hardware step targets, as the
breakpoint will be hit immediately, but it's just wrong on software
step targets.  I tested it against my x86 software single-step branch,
and it indeed fixes failed assertions (that catch spurious
PTRACE_SINGLESTEP requests) there.

gdb/ChangeLog:
2015-05-21  Pedro Alves  <palves@redhat.com>

	* infrun.c (switch_back_to_stepped_thread): Use ecs->ptid instead
	of inferior_ptid.  If the stepped thread vanished, return 0
	instead of resuming here.  Use reset_ecs.  Print the prev_pc and
	the current stop_pc in log message.  Clear trap_expected if the
	thread advanced.  Don't pass currently_stepping to
	do_target_resume.

v4:

	ChangeLog typo fixed.
---
 gdb/infrun.c | 33 ++++++++++++++++++---------------
 1 file changed, 18 insertions(+), 15 deletions(-)

diff --git a/gdb/infrun.c b/gdb/infrun.c
index 2c8a963..55a6622 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -5711,7 +5711,7 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
         {
 	  /* Ignore threads of processes we're not resuming.  */
 	  if (!sched_multi
-	      && ptid_get_pid (tp->ptid) != ptid_get_pid (inferior_ptid))
+	      && ptid_get_pid (tp->ptid) != ptid_get_pid (ecs->ptid))
 	    continue;
 
 	  /* When stepping over a breakpoint, we lock all threads
@@ -5775,19 +5775,17 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
 				    "stepped thread, it has vanished\n");
 
 	      delete_thread (tp->ptid);
-	      keep_going (ecs);
-	      return 1;
+	      return 0;
 	    }
 
 	  if (debug_infrun)
 	    fprintf_unfiltered (gdb_stdlog,
 				"infrun: switching back to stepped thread\n");
 
-	  ecs->event_thread = tp;
-	  ecs->ptid = tp->ptid;
-	  context_switch (ecs->ptid);
+	  reset_ecs (ecs, tp);
+	  switch_to_thread (tp->ptid);
 
-	  stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
+	  stop_pc = regcache_read_pc (get_thread_regcache (tp->ptid));
 	  frame = get_current_frame ();
 	  gdbarch = get_frame_arch (frame);
 
@@ -5811,23 +5809,28 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
 
 	      if (debug_infrun)
 		fprintf_unfiltered (gdb_stdlog,
-				    "infrun: expected thread advanced also\n");
+				    "infrun: expected thread advanced also "
+				    "(%s -> %s)\n",
+				    paddress (target_gdbarch (), tp->prev_pc),
+				    paddress (target_gdbarch (), stop_pc));
 
 	      /* Clear the info of the previous step-over, as it's no
-		 longer valid.  It's what keep_going would do too, if
-		 we called it.  Must do this before trying to insert
-		 the sss breakpoint, otherwise if we were previously
-		 trying to step over this exact address in another
-		 thread, the breakpoint ends up not installed.  */
+		 longer valid (if the thread was trying to step over a
+		 breakpoint, it has already succeeded).  It's what
+		 keep_going would do too, if we called it.  Do this
+		 before trying to insert the sss breakpoint, otherwise
+		 if we were previously trying to step over this exact
+		 address in another thread, the breakpoint is
+		 skipped.  */
 	      clear_step_over_info ();
+	      tp->control.trap_expected = 0;
 
 	      insert_single_step_breakpoint (get_frame_arch (frame),
 					     get_frame_address_space (frame),
 					     stop_pc);
 
 	      resume_ptid = user_visible_resume_ptid (tp->control.stepping_command);
-	      do_target_resume (resume_ptid,
-				currently_stepping (tp), GDB_SIGNAL_0);
+	      do_target_resume (resume_ptid, 0, GDB_SIGNAL_0);
 	      prepare_to_wait (ecs);
 	    }
 	  else
-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 13/18] Fix interrupt-noterm.exp on targets always in non-stop
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
                   ` (13 preceding siblings ...)
  2015-05-21 23:25 ` [PATCH 07/18] Misc switch_back_to_stepped_thread cleanups Pedro Alves
@ 2015-05-21 23:28 ` Pedro Alves
  2015-05-21 23:50 ` [PATCH 17/18] S/390: displaced stepping and PC-relative RIL-b/RIL-c instructions Pedro Alves
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:28 UTC (permalink / raw)
  To: gdb-patches

With "maint set target-non-stop on" we get:

 @@ -66,13 +66,16 @@ Continuing.
  interrupt
  (gdb) PASS: gdb.base/interrupt-noterm.exp: interrupt

 -Program received signal SIGINT, Interrupt.
 -PASS: gdb.base/interrupt-noterm.exp: inferior received SIGINT
 -testcase src/gdb/testsuite/gdb.base/interrupt-noterm.exp completed in 0 seconds
 +[process 12119] #1 stopped.
 +0x0000003615ebc6d0 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:81
 +81     T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
 +FAIL: gdb.base/interrupt-noterm.exp: inferior received SIGINT (timeout)
 +testcase src/gdb/testsuite/gdb.base/interrupt-noterm.exp completed in 10 seconds

That is, we get "[$thread] #1 stopped" instead of SIGINT.

The issue is that we don't currently distinguish send
"interrupt/ctrl-c" to target terminal vs "stop/pause" thread well;
both cases go through "target_stop".

And then, the native Linux backend (linux-nat.c) implements
target_stop with SIGSTOP in non-stop mode, and SIGINT in all-stop
mode.  Since "maint set target-non-stop on" forces the backend to be
always running in non-stop mode, even though the user-visible behavior
is "set non-stop" is "off", "interrupt" causes a SIGSTOP instead of
the SIGINT the test expects.

Fix this by introducing a target_interrupt method to use in the
"interrupt/ctrl-c" case, so "set non-stop off" can always work the
same irrespective of "maint set target-non-stop on/off".  I'm
explictly considering changing the "set non-stop on" behavior as out
of scope here.

Most of the patch is an across-the-board rename of to_stop hook
implementations to to_interrupt.  The only targets where something
more than a rename is being done are linux-nat.c and remote.c, which
are the only targets that support async, and thus are the only ones
the core side calls target_stop on.

gdb/ChangeLog:
2015-05-21  Pedro Alves  <palves@redhat.com>

	* darwin-nat.c (darwin_stop): Rename to ...
	(darwin_interrupt): ... this.
	(_initialize_darwin_inferior): Adjust.
	* gnu-nat.c (gnu_stop): Delete.
	(gnu_target): Don't install gnu_stop.
	* inf-ptrace.c (inf_ptrace_stop): Rename to ...
	(inf_ptrace_interrupt): ... this.
	(inf_ptrace_target): Adjust.
	* infcmd.c (interrupt_target_1): Use target_interrupt instead of
	target_stop.
	* linux-nat (linux_nat_stop): Rename to ...
	(linux_nat_interrupt): ... this.
	(linux_nat_stop): Reimplement.
	(linux_nat_add_target): Install linux_nat_interrupt.
	* nto-procfs.c (nto_interrupt_twice): Rename to ...
	(nto_handle_sigint_twice): ... this.
	(nto_interrupt): Rename to ...
	(nto_handle_sigint): ... this.  Call target_interrupt instead of
	target_stop.
	(procfs_wait): Adjust.
	(procfs_stop): Rename to ...
	(procfs_interrupt): ... this.
	(init_procfs_targets): Adjust.
	* procfs.c (procfs_stop): Rename to ...
	(procfs_interrupt): ... this.
	(procfs_target): Adjust.
	* remote-m32r-sdi.c (m32r_stop): Rename to ...
	(m32r_interrupt): ... this.
	(init_m32r_ops): Adjust.
	* remote-sim.c (gdbsim_stop_inferior): Rename to ...
	(gdbsim_interrupt_inferior): ... this.
	(gdbsim_stop): Rename to ...
	(gdbsim_interrupt): ... this.
	(gdbsim_cntrl_c): Adjust.
	(init_gdbsim_ops): Adjust.
	* remote.c (sync_remote_interrupt): Adjust comments.
	(remote_stop_as): Rename to ...
	(remote_interrupt_as): ... this.
	(remote_stop): Adjust comment.
	(remote_interrupt): New function.
	(init_remote_ops): Install remote_interrupt.
	* target.c (target_interrupt): New function.
	* target.h (struct target_ops) <to_interrupt>: New field.
	(target_interrupt): New declaration.
	* windows-nat.c (windows_stop): Rename to ...
	(windows_interrupt): ... this.
	* target-delegates.c: Regenerate.

v4:

	Split gnu-nat.c change to separate patch.

	Dropped monitor.c changes, they were wrong (broke build), and are
	really not necessary.

	Fixed nto-procfs.c and procfs.c changes, hopefully (was certainly
	breaking the build due to missing adjustments).

v3, v2:

	- No changes.
---
 gdb/darwin-nat.c       |  6 +++---
 gdb/inf-ptrace.c       |  6 +++---
 gdb/infcmd.c           |  2 +-
 gdb/linux-nat.c        | 12 +++++++++---
 gdb/nto-procfs.c       | 16 ++++++++--------
 gdb/procfs.c           |  6 +++---
 gdb/remote-m32r-sdi.c  |  6 +++---
 gdb/remote-sim.c       | 20 ++++++++++----------
 gdb/remote.c           | 44 +++++++++++++++++++++++++++++++++-----------
 gdb/target-delegates.c | 28 ++++++++++++++++++++++++++++
 gdb/target.c           | 12 ++++++++++++
 gdb/target.h           |  8 ++++++++
 gdb/windows-nat.c      |  6 +++---
 13 files changed, 124 insertions(+), 48 deletions(-)

diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index e1acc05..30e968f 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -83,7 +83,7 @@
 #define PTRACE(CMD, PID, ADDR, SIG) \
  darwin_ptrace(#CMD, CMD, (PID), (ADDR), (SIG))
 
-static void darwin_stop (struct target_ops *self, ptid_t);
+static void darwin_interrupt (struct target_ops *self, ptid_t);
 
 static void darwin_resume_to (struct target_ops *ops, ptid_t ptid, int step,
                               enum gdb_signal signal);
@@ -1198,7 +1198,7 @@ darwin_wait_to (struct target_ops *ops,
 }
 
 static void
-darwin_stop (struct target_ops *self, ptid_t t)
+darwin_interrupt (struct target_ops *self, ptid_t t)
 {
   struct inferior *inf = current_inferior ();
 
@@ -2156,7 +2156,7 @@ _initialize_darwin_inferior (void)
   darwin_ops->to_wait = darwin_wait_to;
   darwin_ops->to_mourn_inferior = darwin_mourn_inferior;
   darwin_ops->to_kill = darwin_kill_inferior;
-  darwin_ops->to_stop = darwin_stop;
+  darwin_ops->to_interrupt = darwin_interrupt;
   darwin_ops->to_resume = darwin_resume_to;
   darwin_ops->to_thread_alive = darwin_thread_alive;
   darwin_ops->to_pid_to_str = darwin_pid_to_str;
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index cd58dfb..17ba903 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -288,10 +288,10 @@ inf_ptrace_kill (struct target_ops *ops)
   target_mourn_inferior ();
 }
 
-/* Stop the inferior.  */
+/* Interrupt the inferior.  */
 
 static void
-inf_ptrace_stop (struct target_ops *self, ptid_t ptid)
+inf_ptrace_interrupt (struct target_ops *self, ptid_t ptid)
 {
   /* Send a SIGINT to the process group.  This acts just like the user
      typed a ^C on the controlling terminal.  Note that using a
@@ -686,7 +686,7 @@ inf_ptrace_target (void)
   t->to_mourn_inferior = inf_ptrace_mourn_inferior;
   t->to_thread_alive = inf_ptrace_thread_alive;
   t->to_pid_to_str = inf_ptrace_pid_to_str;
-  t->to_stop = inf_ptrace_stop;
+  t->to_interrupt = inf_ptrace_interrupt;
   t->to_xfer_partial = inf_ptrace_xfer_partial;
 #if defined (PT_IO) && defined (PIOD_READ_AUXV)
   t->to_auxv_parse = inf_ptrace_auxv_parse;
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index d73c596..b18130b 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -2828,7 +2828,7 @@ interrupt_target_1 (int all_threads)
     ptid = minus_one_ptid;
   else
     ptid = inferior_ptid;
-  target_stop (ptid);
+  target_interrupt (ptid);
 
   /* Tag the thread as having been explicitly requested to stop, so
      other parts of gdb know not to resume this thread automatically,
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 3323a60..eaefa72 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -4810,10 +4810,16 @@ linux_nat_stop_lwp (struct lwp_info *lwp, void *data)
 static void
 linux_nat_stop (struct target_ops *self, ptid_t ptid)
 {
-  if (target_is_non_stop_p ())
+  iterate_over_lwps (ptid, linux_nat_stop_lwp, NULL);
+}
+
+static void
+linux_nat_interrupt (struct target_ops *self, ptid_t ptid)
+{
+  if (non_stop)
     iterate_over_lwps (ptid, linux_nat_stop_lwp, NULL);
   else
-    linux_ops->to_stop (linux_ops, ptid);
+    linux_ops->to_interrupt (linux_ops, ptid);
 }
 
 static void
@@ -4917,8 +4923,8 @@ linux_nat_add_target (struct target_ops *t)
   super_close = t->to_close;
   t->to_close = linux_nat_close;
 
-  /* Methods for non-stop support.  */
   t->to_stop = linux_nat_stop;
+  t->to_interrupt = linux_nat_interrupt;
 
   t->to_supports_multi_process = linux_nat_supports_multi_process;
 
diff --git a/gdb/nto-procfs.c b/gdb/nto-procfs.c
index 7312060..118bdc3 100644
--- a/gdb/nto-procfs.c
+++ b/gdb/nto-procfs.c
@@ -692,20 +692,20 @@ Give up (and stop debugging it)? ")))
 
 /* The user typed ^C twice.  */
 static void
-nto_interrupt_twice (int signo)
+nto_handle_sigint_twice (int signo)
 {
   signal (signo, ofunc);
   interrupt_query ();
-  signal (signo, nto_interrupt_twice);
+  signal (signo, nto_handle_sigint_twice);
 }
 
 static void
-nto_interrupt (int signo)
+nto_handle_sigint (int signo)
 {
   /* If this doesn't work, try more severe steps.  */
-  signal (signo, nto_interrupt_twice);
+  signal (signo, nto_handle_sigint_twice);
 
-  target_stop (inferior_ptid);
+  target_interrupt (inferior_ptid);
 }
 
 static ptid_t
@@ -733,7 +733,7 @@ procfs_wait (struct target_ops *ops,
   devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
   while (!(status.flags & _DEBUG_FLAG_ISTOP))
     {
-      ofunc = (void (*)()) signal (SIGINT, nto_interrupt);
+      ofunc = (void (*)()) signal (SIGINT, nto_handle_sigint);
       sigwaitinfo (&set, &info);
       signal (SIGINT, ofunc);
       devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
@@ -1221,7 +1221,7 @@ procfs_create_inferior (struct target_ops *ops, char *exec_file,
 }
 
 static void
-procfs_stop (struct target_ops *self, ptid_t ptid)
+procfs_interrupt (struct target_ops *self, ptid_t ptid)
 {
   devctl (ctl_fd, DCMD_PROC_STOP, NULL, 0, 0);
 }
@@ -1444,7 +1444,7 @@ init_procfs_targets (void)
   t->to_thread_alive = procfs_thread_alive;
   t->to_update_thread_list = procfs_update_thread_list;
   t->to_pid_to_str = procfs_pid_to_str;
-  t->to_stop = procfs_stop;
+  t->to_interrupt = procfs_interrupt;
   t->to_have_continuable_watchpoint = 1;
   t->to_extra_thread_info = nto_extra_thread_info;
 
diff --git a/gdb/procfs.c b/gdb/procfs.c
index b62539f..731c681 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -111,7 +111,7 @@ static void procfs_attach (struct target_ops *, const char *, int);
 static void procfs_detach (struct target_ops *, const char *, int);
 static void procfs_resume (struct target_ops *,
 			   ptid_t, int, enum gdb_signal);
-static void procfs_stop (struct target_ops *self, ptid_t);
+static void procfs_interrupt (struct target_ops *self, ptid_t);
 static void procfs_files_info (struct target_ops *);
 static void procfs_fetch_registers (struct target_ops *,
 				    struct regcache *, int);
@@ -194,7 +194,7 @@ procfs_target (void)
   t->to_xfer_partial = procfs_xfer_partial;
   t->to_pass_signals = procfs_pass_signals;
   t->to_files_info = procfs_files_info;
-  t->to_stop = procfs_stop;
+  t->to_interrupt = procfs_interrupt;
 
   t->to_update_thread_list = procfs_update_thread_list;
   t->to_thread_alive = procfs_thread_alive;
@@ -4204,7 +4204,7 @@ procfs_files_info (struct target_ops *ignore)
    kill(SIGINT) to the child's process group.  */
 
 static void
-procfs_stop (struct target_ops *self, ptid_t ptid)
+procfs_interrupt (struct target_ops *self, ptid_t ptid)
 {
   kill (-inferior_process_group (), SIGINT);
 }
diff --git a/gdb/remote-m32r-sdi.c b/gdb/remote-m32r-sdi.c
index 01cb5b6..b246cd9 100644
--- a/gdb/remote-m32r-sdi.c
+++ b/gdb/remote-m32r-sdi.c
@@ -1407,10 +1407,10 @@ m32r_load (struct target_ops *self, const char *args, int from_tty)
 }
 
 static void
-m32r_stop (struct target_ops *self, ptid_t ptid)
+m32r_interrupt (struct target_ops *self, ptid_t ptid)
 {
   if (remote_debug)
-    fprintf_unfiltered (gdb_stdlog, "m32r_stop()\n");
+    fprintf_unfiltered (gdb_stdlog, "m32r_interrupt()\n");
 
   send_cmd (SDI_STOP_CPU);
 
@@ -1664,7 +1664,7 @@ init_m32r_ops (void)
   m32r_ops.to_load = m32r_load;
   m32r_ops.to_create_inferior = m32r_create_inferior;
   m32r_ops.to_mourn_inferior = m32r_mourn_inferior;
-  m32r_ops.to_stop = m32r_stop;
+  m32r_ops.to_interrupt = m32r_interrupt;
   m32r_ops.to_log_command = serial_log_command;
   m32r_ops.to_thread_alive = m32r_thread_alive;
   m32r_ops.to_pid_to_str = m32r_pid_to_str;
diff --git a/gdb/remote-sim.c b/gdb/remote-sim.c
index fd2fd58..766356a 100644
--- a/gdb/remote-sim.c
+++ b/gdb/remote-sim.c
@@ -87,7 +87,7 @@ static void gdbsim_files_info (struct target_ops *target);
 
 static void gdbsim_mourn_inferior (struct target_ops *target);
 
-static void gdbsim_stop (struct target_ops *self, ptid_t ptid);
+static void gdbsim_interrupt (struct target_ops *self, ptid_t ptid);
 
 void simulator_command (char *args, int from_tty);
 
@@ -888,17 +888,17 @@ gdbsim_resume (struct target_ops *ops,
     error (_("The program is not being run."));
 }
 
-/* Notify the simulator of an asynchronous request to stop.
+/* Notify the simulator of an asynchronous request to interrupt.
 
-   The simulator shall ensure that the stop request is eventually
+   The simulator shall ensure that the interrupt request is eventually
    delivered to the simulator.  If the call is made while the
-   simulator is not running then the stop request is processed when
+   simulator is not running then the interrupt request is processed when
    the simulator is next resumed.
 
    For simulators that do not support this operation, just abort.  */
 
 static int
-gdbsim_stop_inferior (struct inferior *inf, void *arg)
+gdbsim_interrupt_inferior (struct inferior *inf, void *arg)
 {
   struct sim_inferior_data *sim_data
     = get_sim_inferior_data (inf, SIM_INSTANCE_NEEDED);
@@ -918,13 +918,13 @@ gdbsim_stop_inferior (struct inferior *inf, void *arg)
 }
 
 static void
-gdbsim_stop (struct target_ops *self, ptid_t ptid)
+gdbsim_interrupt (struct target_ops *self, ptid_t ptid)
 {
   struct sim_inferior_data *sim_data;
 
   if (ptid_equal (ptid, minus_one_ptid))
     {
-      iterate_over_inferiors (gdbsim_stop_inferior, NULL);
+      iterate_over_inferiors (gdbsim_interrupt_inferior, NULL);
     }
   else
     {
@@ -934,7 +934,7 @@ gdbsim_stop (struct target_ops *self, ptid_t ptid)
 	error (_("Can't stop pid %d.  No inferior found."),
 	       ptid_get_pid (ptid));
 
-      gdbsim_stop_inferior (inf, NULL);
+      gdbsim_interrupt_inferior (inf, NULL);
     }
 }
 
@@ -962,7 +962,7 @@ gdb_os_poll_quit (host_callback *p)
 static void
 gdbsim_cntrl_c (int signo)
 {
-  gdbsim_stop (NULL, minus_one_ptid);
+  gdbsim_interrupt (NULL, minus_one_ptid);
 }
 
 static ptid_t
@@ -1320,7 +1320,7 @@ init_gdbsim_ops (void)
   gdbsim_ops.to_load = gdbsim_load;
   gdbsim_ops.to_create_inferior = gdbsim_create_inferior;
   gdbsim_ops.to_mourn_inferior = gdbsim_mourn_inferior;
-  gdbsim_ops.to_stop = gdbsim_stop;
+  gdbsim_ops.to_interrupt = gdbsim_interrupt;
   gdbsim_ops.to_thread_alive = gdbsim_thread_alive;
   gdbsim_ops.to_pid_to_str = gdbsim_pid_to_str;
   gdbsim_ops.to_stratum = process_stratum;
diff --git a/gdb/remote.c b/gdb/remote.c
index db06def..7cc9771 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -5175,11 +5175,12 @@ async_cleanup_sigint_signal_handler (void *dummy)
    packet.  */
 static void (*ofunc) (int);
 
-/* The command line interface's stop routine.  This function is installed
-   as a signal handler for SIGINT.  The first time a user requests a
-   stop, we call remote_stop to send a break or ^C.  If there is no
+/* The command line interface's interrupt routine.  This function is installed
+   as a signal handler for SIGINT.  The first time a user requests an
+   interrupt, we call remote_interrupt to send a break or ^C.  If there is no
    response from the target (it didn't stop when the user requested it),
    we ask the user if he'd like to detach from the target.  */
+
 static void
 sync_remote_interrupt (int signo)
 {
@@ -5250,12 +5251,12 @@ remote_stop_ns (ptid_t ptid)
     error (_("Stopping %s failed: %s"), target_pid_to_str (ptid), rs->buf);
 }
 
-/* All-stop version of target_stop.  Sends a break or a ^C to stop the
-   remote target.  It is undefined which thread of which process
-   reports the stop.  */
+/* All-stop version of target_interrupt.  Sends a break or a ^C to
+   interrupt the remote target.  It is undefined which thread of which
+   process reports the interrupt.  */
 
 static void
-remote_stop_as (ptid_t ptid)
+remote_interrupt_as (ptid_t ptid)
 {
   struct remote_state *rs = get_remote_state ();
 
@@ -5271,9 +5272,7 @@ remote_stop_as (ptid_t ptid)
   send_interrupt_sequence ();
 }
 
-/* This is the generic stop called via the target vector.  When a target
-   interrupt is requested, either by the command line or the GUI, we
-   will eventually end up here.  */
+/* Implement the to_stop function for the remote targets.  */
 
 static void
 remote_stop (struct target_ops *self, ptid_t ptid)
@@ -5284,7 +5283,29 @@ remote_stop (struct target_ops *self, ptid_t ptid)
   if (non_stop)
     remote_stop_ns (ptid);
   else
-    remote_stop_as (ptid);
+    {
+      /* We don't currently have a way to transparently pause the
+	 remote target in all-stop mode.  Interrupt it instead.  */
+      remote_interrupt_as (ptid);
+    }
+}
+
+/* Implement the to_interrupt function for the remote targets.  */
+
+static void
+remote_interrupt (struct target_ops *self, ptid_t ptid)
+{
+  if (remote_debug)
+    fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n");
+
+  if (non_stop)
+    {
+      /* We don't currently have a way to ^C the remote target in
+	 non-stop mode.  Stop it (with no signal) instead.  */
+      remote_stop_ns (ptid);
+    }
+  else
+    remote_interrupt_as (ptid);
 }
 
 /* Ask the user what to do when an interrupt is received.  */
@@ -12086,6 +12107,7 @@ Specify the serial device it is connected to\n\
   remote_ops.to_extra_thread_info = remote_threads_extra_info;
   remote_ops.to_get_ada_task_ptid = remote_get_ada_task_ptid;
   remote_ops.to_stop = remote_stop;
+  remote_ops.to_interrupt = remote_interrupt;
   remote_ops.to_xfer_partial = remote_xfer_partial;
   remote_ops.to_rcmd = remote_rcmd;
   remote_ops.to_pid_to_exec_file = remote_pid_to_exec_file;
diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c
index 8a92acf..054ad32 100644
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -1537,6 +1537,30 @@ debug_stop (struct target_ops *self, ptid_t arg1)
 }
 
 static void
+delegate_interrupt (struct target_ops *self, ptid_t arg1)
+{
+  self = self->beneath;
+  self->to_interrupt (self, arg1);
+}
+
+static void
+tdefault_interrupt (struct target_ops *self, ptid_t arg1)
+{
+}
+
+static void
+debug_interrupt (struct target_ops *self, ptid_t arg1)
+{
+  fprintf_unfiltered (gdb_stdlog, "-> %s->to_interrupt (...)\n", debug_target.to_shortname);
+  debug_target.to_interrupt (&debug_target, arg1);
+  fprintf_unfiltered (gdb_stdlog, "<- %s->to_interrupt (", debug_target.to_shortname);
+  target_debug_print_struct_target_ops_p (&debug_target);
+  fputs_unfiltered (", ", gdb_stdlog);
+  target_debug_print_ptid_t (arg1);
+  fputs_unfiltered (")\n", gdb_stdlog);
+}
+
+static void
 delegate_rcmd (struct target_ops *self, const char *arg1, struct ui_file *arg2)
 {
   self = self->beneath;
@@ -4016,6 +4040,8 @@ install_delegators (struct target_ops *ops)
     ops->to_thread_name = delegate_thread_name;
   if (ops->to_stop == NULL)
     ops->to_stop = delegate_stop;
+  if (ops->to_interrupt == NULL)
+    ops->to_interrupt = delegate_interrupt;
   if (ops->to_rcmd == NULL)
     ops->to_rcmd = delegate_rcmd;
   if (ops->to_pid_to_exec_file == NULL)
@@ -4253,6 +4279,7 @@ install_dummy_methods (struct target_ops *ops)
   ops->to_extra_thread_info = tdefault_extra_thread_info;
   ops->to_thread_name = tdefault_thread_name;
   ops->to_stop = tdefault_stop;
+  ops->to_interrupt = tdefault_interrupt;
   ops->to_rcmd = default_rcmd;
   ops->to_pid_to_exec_file = tdefault_pid_to_exec_file;
   ops->to_log_command = tdefault_log_command;
@@ -4402,6 +4429,7 @@ init_debug_target (struct target_ops *ops)
   ops->to_extra_thread_info = debug_extra_thread_info;
   ops->to_thread_name = debug_thread_name;
   ops->to_stop = debug_stop;
+  ops->to_interrupt = debug_interrupt;
   ops->to_rcmd = debug_rcmd;
   ops->to_pid_to_exec_file = debug_pid_to_exec_file;
   ops->to_log_command = debug_log_command;
diff --git a/gdb/target.c b/gdb/target.c
index 0b0cc59..39dade9 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3244,6 +3244,18 @@ target_stop (ptid_t ptid)
   (*current_target.to_stop) (&current_target, ptid);
 }
 
+void
+target_interrupt (ptid_t ptid)
+{
+  if (!may_stop)
+    {
+      warning (_("May not interrupt or stop the target, ignoring attempt"));
+      return;
+    }
+
+  (*current_target.to_interrupt) (&current_target, ptid);
+}
+
 /* See target/target.h.  */
 
 void
diff --git a/gdb/target.h b/gdb/target.h
index 10236f0..6f1d5a0 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -611,6 +611,8 @@ struct target_ops
       TARGET_DEFAULT_RETURN (NULL);
     void (*to_stop) (struct target_ops *, ptid_t)
       TARGET_DEFAULT_IGNORE ();
+    void (*to_interrupt) (struct target_ops *, ptid_t)
+      TARGET_DEFAULT_IGNORE ();
     void (*to_rcmd) (struct target_ops *,
 		     const char *command, struct ui_file *output)
       TARGET_DEFAULT_FUNC (default_rcmd);
@@ -1635,6 +1637,12 @@ extern void target_update_thread_list (void);
 
 extern void target_stop (ptid_t ptid);
 
+/* Interrupt the target just like the user typed a ^C on the
+   inferior's controlling terminal.  (For instance, under Unix, this
+   should act like SIGINT).  This function is asynchronous.  */
+
+extern void target_interrupt (ptid_t ptid);
+
 /* Send the specified COMMAND to the target's monitor
    (shell,interpreter) for execution.  The result of the query is
    placed in OUTBUF.  */
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 701d2c5..5bd20b7 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -162,7 +162,7 @@ static int windows_initialization_done;
 #define DEBUG_MEM(x)	if (debug_memory)	printf_unfiltered x
 #define DEBUG_EXCEPT(x)	if (debug_exceptions)	printf_unfiltered x
 
-static void windows_stop (struct target_ops *self, ptid_t);
+static void windows_interrupt (struct target_ops *self, ptid_t);
 static int windows_thread_alive (struct target_ops *, ptid_t);
 static void windows_kill_inferior (struct target_ops *);
 
@@ -2300,7 +2300,7 @@ windows_mourn_inferior (struct target_ops *ops)
    ^C on the controlling terminal.  */
 
 static void
-windows_stop (struct target_ops *self, ptid_t ptid)
+windows_interrupt (struct target_ops *self, ptid_t ptid)
 {
   DEBUG_EVENTS (("gdb: GenerateConsoleCtrlEvent (CTRLC_EVENT, 0)\n"));
   CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, current_event.dwProcessId));
@@ -2494,7 +2494,7 @@ windows_target (void)
   t->to_mourn_inferior = windows_mourn_inferior;
   t->to_thread_alive = windows_thread_alive;
   t->to_pid_to_str = windows_pid_to_str;
-  t->to_stop = windows_stop;
+  t->to_interrupt = windows_interrupt;
   t->to_pid_to_exec_file = windows_pid_to_exec_file;
   t->to_get_ada_task_ptid = windows_get_ada_task_ptid;
   t->to_get_tib_address = windows_get_tib_address;
-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 17/18] S/390: displaced stepping and PC-relative RIL-b/RIL-c instructions
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
                   ` (14 preceding siblings ...)
  2015-05-21 23:28 ` [PATCH 13/18] Fix interrupt-noterm.exp on targets always in non-stop Pedro Alves
@ 2015-05-21 23:50 ` Pedro Alves
  2015-05-21 23:56 ` [PATCH 10/18] Teach non-stop to do in-line step-overs (stop all, step, restart) Pedro Alves
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:50 UTC (permalink / raw)
  To: gdb-patches

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  <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.

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);
-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 10/18] Teach non-stop to do in-line step-overs (stop all, step, restart)
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
                   ` (15 preceding siblings ...)
  2015-05-21 23:50 ` [PATCH 17/18] S/390: displaced stepping and PC-relative RIL-b/RIL-c instructions Pedro Alves
@ 2015-05-21 23:56 ` Pedro Alves
  2015-05-21 23:59 ` [PATCH 15/18] Disable displaced stepping if trying it fails Pedro Alves
  2015-08-07 16:58 ` [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
  18 siblings, 0 replies; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:56 UTC (permalink / raw)
  To: gdb-patches

That is, step past breakpoints by:

 - pausing all threads
 - removing breakpoint at PC
 - single-step
 - reinsert breakpoint
 - restart threads

similarly to all-stop (with displaced stepping disabled).  This allows
non-stop to work on targets/architectures without displaced stepping
support.  That is, it makes displaced stepping an optimization instead
of a requirement.  For example, in principle, all GNU/Linux ports
support non-stop mode at the target_ops level, but not all
corresponding gdbarch's implement displaced stepping.  This should
make non-stop work for all (albeit, not as efficiently).  And then
there are scenarios where even if the architecture supports displaced
stepping, we can't use it, because we e.g., don't find a usable
address to use as displaced step scratch pad.  It should also fix
stepping past watchpoints on targets that have non-continuable
watchpoints in non-stop mode (e.g., PPC, untested).  Running the
instruction out of line in the displaced stepping scratch pad doesn't
help that case, as the copied instruction reads/writes the same
watched memory...  We can fix that too by teaching GDB to only remove
the watchpoint from the thread that we want to move past the
watchpoint (currently, removing a watchpoint always removes it from
all threads), but again, that can be considered an optimization; not
all targets would support it.

For those familiar with the gdb and gdbserver Linux target_ops
backends, the implementation should look similar, except it is done on
the core side.  When we pause threads, we may find they stop with an
interesting event that should be handled later when the thread is
re-resumed, thus we store such events in the thread object, and mark
the event as pending.  We should only consume pending events if the
thread is indeed resumed, thus we add a new "resumed" flag to the
thread object.  At a later stage, we might add new target methods to
accelerate some of this, like "pause all threads", with corresponding
RSP packets, but we'd still need a fallback method for remote targets
that don't support such packets, so, again, that can be deferred as
optimization.

My _real_ motivation here is making it possible to reimplement
all-stop mode on top of the target always working on non-stop mode, so
that e.g., we can send RSP packets to a remote target even while the
target is running -- can't do that in the all-stop RSP variant, by
design).

Tested on x86_64 Fedora 20, with and without "set displaced off"
forced.  The latter forces the new code paths whenever GDB needs to
step past a breakpoint.

gdb/ChangeLog:
2015-05-21  Pedro Alves  <pedro@codesourcery.com>

	* breakpoint.c (breakpoints_should_be_inserted_now): If any thread
	has a pending status, return true.
	* gdbthread.h: Include target/waitstatus.h.
	(struct thread_suspend_state) <stop_reason, waitstatus_pending_p,
	stop_pc>: New fields.
	(struct thread_info) <resumed>: New field.
	(set_resumed): Declare.
	* infrun.c: Include "event-loop.h".
	(infrun_async_inferior_event_token, infrun_is_async): New globals.
	(infrun_async): New function.
	(clear_step_over_info): Add debug output.
	(displaced_step_in_progress_any_inferior): New function.
	(displaced_step_fixup): New returns int.
	(start_step_over): Handle in-line step-overs too.  Assert the
	thread is marked resumed.
	(resume_cleanups): Clear the thread's resumed flag.
	(resume): Set the thread's resumed flag.  Return early if the
	thread has a pending status.  Allow stepping a breakpoint with no
	signal.
	(proceed): Adjust to check 'resumed' instead of 'executing'.
	(clear_proceed_status_thread): If the thread has a pending status,
	and that status is a finished step, discard the pending status.
	(clear_proceed_status): Don't clear step_over_info here.
	(random_pending_event_thread, do_target_wait): New functions.
	(prepare_for_detach, wait_for_inferior, fetch_inferior_event): Use
	do_target_wait.
	(wait_one): New function.
	(THREAD_STOPPED_BY): New macro.
	(thread_stopped_by_watchpoint, thread_stopped_by_sw_breakpoint)
	(thread_stopped_by_hw_breakpoint): New functions.
	(switch_to_thread_cleanup, save_waitstatus, stop_all_threads): New
	functions.
	(handle_inferior_event): Also call set_resumed(false) on all
	threads implicitly stopped by the event.
	(restart_threads, resumed_thread_with_pending_status): New
	functions.
	(finish_step_over): If we were doing an in-line step-over before,
	and no longer are after trying to start a new step-over, restart
	all threads.  If we have multiple threads with pending events,
	save the current event and go through the event loop again.
	(handle_signal_stop): Return early if finish_step_over returns
	false.
	<random signal>: If we get a signal while stepping over a
	breakpoint in-line in non-stop mode, restart all threads.  Clear
	step_over_info before delivering the signal.
	(keep_going_stepped_thread): Use internal_error instead of
	gdb_assert.  Mark the thread as resumed.
	(keep_going_pass_signal): Assert the thread isn't already resumed.
	If some other thread is doing an in-line step-over, defer the
	resume.  If we just started a new in-line step-over, stop all
	threads.  Don't clear step_over_info.
	(infrun_async_inferior_event_handler): New function.
	(_initialize_infrun): Create async event handler with
	infrun_async_inferior_event_handler as callback.
	(infrun_async): New declaration.
	* target.c (target_async): New function.
	* target.h (target_async): Declare macro and readd as function
	declaration.
	* target/waitstatus.h (enum target_stop_reason)
	<TARGET_STOPPED_BY_SINGLE_STEP>: New value.
	* thread.c (new_thread): Clear the new waitstatus field.
	(set_resumed): New function.


v4:

  - If we get a signal while stepping over a breakpoint in-line in
    non-stop mode, restart all threads.

v3:

  - pending status handing moved from keep_going_stepped_thread to
    restart_threads.  Fixes an assert triggered while testing with sss
    and no displaced stepping.

  - proceed and restart_threads now check "resumed" instead of
    "executing", because the thread that was started might have a
    pending status, and thus ends resumed, but not executing.  Caught
    by an assertion in keep_going_stepped_thread.

  - do_target_wait was missing a call to mark the infrun event source
    in case we are returning a pending wait status and there are other
    pending events to process.  Caught by testing with gdbserver + no
    displaced stepping + sss.

  - had finish_step_over detect that there are multiple pending events
    that could be consumed after an in-line step-over finishes, and
    pick one at random.  Fixes non-stop-fair-events.exp timeout due to
    event starvation on targets without displaced stepping.

  - start_step_over now waits for all displaced steps in progress
    before starting an in-line step over (avoid starvation/bouncing
    effects caused by pausing threads doing the displaced step, thus
    cancelling the displaced step, only to restart it again later).

  - resume now only sets the resume flag on success, instead of
    undoing it on error.  avoids the need for resume_cleanups change
    in v2.

  - Adjust to use the new thread_is_in_step_over_chain.

v2:

  - `proceed' changes dropped.  no longer needed after fix to previous patch.
  - "infrun.c" -> "infrun" in debug output.
  - clear trap_expected when displaced_step_fixup returns -1, when
    stopping threads (as the step-over was cancelled).  Testing on
    PPC64 caught this was missing ("inconsistent state" internal error
    in start_step_over_inferior).
---
 gdb/breakpoint.c        |    9 +
 gdb/gdbthread.h         |   32 ++
 gdb/infrun.c            | 1108 ++++++++++++++++++++++++++++++++++++++++++++---
 gdb/infrun.h            |    3 +
 gdb/target.c            |    9 +
 gdb/target.h            |    3 +-
 gdb/target/waitstatus.h |    5 +-
 gdb/thread.c            |   23 +
 8 files changed, 1125 insertions(+), 67 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index a3531a0..ab0010b 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -468,6 +468,8 @@ breakpoints_should_be_inserted_now (void)
     }
   else if (target_has_execution)
     {
+      struct thread_info *tp;
+
       if (always_inserted_mode)
 	{
 	  /* The user wants breakpoints inserted even if all threads
@@ -477,6 +479,13 @@ breakpoints_should_be_inserted_now (void)
 
       if (threads_are_executing ())
 	return 1;
+
+      /* Don't remove breakpoints yet if, even though all threads are
+	 stopped, we still have events to process.  */
+      ALL_NON_EXITED_THREADS (tp)
+	if (tp->resumed
+	    && tp->suspend.waitstatus_pending_p)
+	  return 1;
     }
   return 0;
 }
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 60b4fd3..901f099 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -29,6 +29,7 @@ struct symtab;
 #include "inferior.h"
 #include "btrace.h"
 #include "common/vec.h"
+#include "target/waitstatus.h"
 
 /* Frontend view of the thread state.  Possible extensions: stepping,
    finishing, until(ling),...  */
@@ -159,6 +160,23 @@ struct thread_suspend_state
      should be suppressed, the core will take care of clearing this
      before the target is resumed.  */
   enum gdb_signal stop_signal;
+
+  /* The reason the thread last stopped, if we need to track it
+     (breakpoint, watchpoint, etc.)  */
+  enum target_stop_reason stop_reason;
+
+  /* The waitstatus for this thread's last event.  */
+  struct target_waitstatus waitstatus;
+  /* If true WAITSTATUS hasn't been handled yet.  */
+  int waitstatus_pending_p;
+
+  /* Record the pc of the thread the last time it stopped.  (This is
+     not the current thread's PC as that may have changed since the
+     last stop, e.g., "return" command, or "p $pc = 0xf000").  This is
+     used in coordination with stop_reason and waitstatus_pending_p:
+     if the thread's PC is changed since it last stopped, a pending
+     breakpoint waitstatus is discarded.  */
+  CORE_ADDR stop_pc;
 };
 
 typedef struct value *value_ptr;
@@ -183,6 +201,15 @@ struct thread_info
      thread is off and running.  */
   int executing;
 
+  /* Non-zero if this thread is resumed from infrun's perspective.
+     Note that a thread can be marked both as not-executing and
+     resumed at the same time.  This happens if we try to resume a
+     thread that has a wait status pending.  We shouldn't let the
+     thread really run until that wait status has been processed, but
+     we should not process that wait status if we didn't try to let
+     the thread run.  */
+  int resumed;
+
   /* Frontend view of the thread state.  Note that the THREAD_RUNNING/
      THREAD_STOPPED states are different from EXECUTING.  When the
      thread is stopped internally while handling an internal event,
@@ -400,6 +427,11 @@ extern int thread_count (void);
 /* Switch from one thread to another.  */
 extern void switch_to_thread (ptid_t ptid);
 
+/* Marks or clears thread(s) PTID as resumed.  If PTID is
+   MINUS_ONE_PTID, applies to all threads.  If ptid_is_pid(PTID) is
+   true, applies to all threads of the process pointed at by PTID.  */
+extern void set_resumed (ptid_t ptid, int resumed);
+
 /* Marks thread PTID is running, or stopped. 
    If PTID is minus_one_ptid, marks all threads.  */
 extern void set_running (ptid_t ptid, int running);
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 56b7c7b..75c5080 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -61,6 +61,7 @@
 #include "target-dcache.h"
 #include "terminal.h"
 #include "solist.h"
+#include "event-loop.h"
 
 /* Prototypes for local functions */
 
@@ -101,6 +102,35 @@ static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR);
 
 static int maybe_software_singlestep (struct gdbarch *gdbarch, CORE_ADDR pc);
 
+/* Asynchronous signal handler registered as event loop source for
+   when we have pending events ready to be passed to the core.  */
+static struct async_event_handler *infrun_async_inferior_event_token;
+
+/* Stores whether infrun_async was previously enabled or disabled.
+   Starts off as -1, indicating "never enabled/disabled".  */
+static int infrun_is_async = -1;
+
+/* See infrun.h.  */
+
+void
+infrun_async (int enable)
+{
+  if (infrun_is_async != enable)
+    {
+      infrun_is_async = enable;
+
+      if (debug_infrun)
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: infrun_async(%d)\n",
+			    enable);
+
+      if (enable)
+	mark_async_event_handler (infrun_async_inferior_event_token);
+      else
+	clear_async_event_handler (infrun_async_inferior_event_token);
+    }
+}
+
 /* When set, stop the 'step' command if we enter a function which has
    no line number information.  The normal behavior is that we step
    over such function.  */
@@ -1297,6 +1327,9 @@ set_step_over_info (struct address_space *aspace, CORE_ADDR address,
 static void
 clear_step_over_info (void)
 {
+  if (debug_infrun)
+    fprintf_unfiltered (gdb_stdlog,
+			"infrun: clear_step_over_info\n");
   step_over_info.aspace = NULL;
   step_over_info.address = 0;
   step_over_info.nonsteppable_watchpoint_p = 0;
@@ -1469,6 +1502,23 @@ get_displaced_stepping_state (int pid)
   return NULL;
 }
 
+/* Returns true if any inferior has a thread doing a displaced
+   step.  */
+
+static int
+displaced_step_in_progress_any_inferior (void)
+{
+  struct displaced_step_inferior_state *state;
+
+  for (state = displaced_step_inferior_states;
+       state != NULL;
+       state = state->next)
+    if (!ptid_equal (state->step_ptid, null_ptid))
+      return 1;
+
+  return 0;
+}
+
 /* Return true if process PID has a thread doing a displaced step.  */
 
 static int
@@ -1782,21 +1832,28 @@ displaced_step_restore (struct displaced_step_inferior_state *displaced,
 				  displaced->step_copy));
 }
 
-static void
+/* If we displaced stepped an instruction successfully, adjust
+   registers and memory to yield the same effect the instruction would
+   have had if we had executed it at its original address, and return
+   1.  If the instruction didn't complete, relocate the PC and return
+   -1.  If the thread wasn't displaced stepping, return 0.  */
+
+static int
 displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal)
 {
   struct cleanup *old_cleanups;
   struct displaced_step_inferior_state *displaced
     = get_displaced_stepping_state (ptid_get_pid (event_ptid));
+  int ret;
 
   /* Was any thread of this process doing a displaced step?  */
   if (displaced == NULL)
-    return;
+    return 0;
 
   /* Was this event for the pid we displaced?  */
   if (ptid_equal (displaced->step_ptid, null_ptid)
       || ! ptid_equal (displaced->step_ptid, event_ptid))
-    return;
+    return 0;
 
   old_cleanups = make_cleanup (displaced_step_clear_cleanup, displaced);
 
@@ -1819,6 +1876,7 @@ displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal)
                                     displaced->step_original,
                                     displaced->step_copy,
                                     get_thread_regcache (displaced->step_ptid));
+      ret = 1;
     }
   else
     {
@@ -1829,11 +1887,14 @@ displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal)
 
       pc = displaced->step_original + (pc - displaced->step_copy);
       regcache_write_pc (regcache, pc);
+      ret = -1;
     }
 
   do_cleanups (old_cleanups);
 
   displaced->step_ptid = null_ptid;
+
+  return ret;
 }
 
 /* Data to be passed around while handling an event.  This data is
@@ -1882,10 +1943,19 @@ start_step_over (void)
 {
   struct thread_info *tp, *next;
 
+  /* Don't start a new step-over if we already have an in-line
+     step-over operation ongoing.  */
+  if (step_over_info_valid_p ())
+    return 0;
+
   for (tp = step_over_queue_head; tp != NULL; tp = next)
     {
       struct execution_control_state ecss;
       struct execution_control_state *ecs = &ecss;
+      enum step_over_what step_what;
+      int must_be_in_line;
+      struct regcache *regcache = get_thread_regcache (tp->ptid);
+      struct gdbarch *gdbarch = get_regcache_arch (regcache);
 
       next = thread_step_over_chain_next (tp);
 
@@ -1894,6 +1964,17 @@ start_step_over (void)
       if (displaced_step_in_progress (ptid_get_pid (tp->ptid)))
 	continue;
 
+      step_what = thread_still_needs_step_over (tp);
+      must_be_in_line = ((step_what & STEP_OVER_WATCHPOINT)
+			 || ((step_what & STEP_OVER_BREAKPOINT)
+			     && !use_displaced_stepping (gdbarch)));
+
+      /* We currently stop all threads of all processes to step-over
+	 in-line.  If we need to start a new in-line step-over, let
+	 any pending displaced steps finish first.  */
+      if (must_be_in_line && displaced_step_in_progress_any_inferior ())
+	return 0;
+
       thread_step_over_chain_remove (tp);
 
       if (step_over_queue_head == NULL)
@@ -1903,13 +1984,16 @@ start_step_over (void)
 				"infrun: step-over queue now empty\n");
 	}
 
-      if (tp->control.trap_expected || tp->executing)
+      if (tp->control.trap_expected
+	  || tp->resumed
+	  || tp->executing)
 	{
 	  internal_error (__FILE__, __LINE__,
 			  "[%s] has inconsistent state: "
-			  "trap_expected=%d, executing=%d\n",
+			  "trap_expected=%d, resumed=%d, executing=%d\n",
 			  target_pid_to_str (tp->ptid),
 			  tp->control.trap_expected,
+			  tp->resumed,
 			  tp->executing);
 	}
 
@@ -1924,7 +2008,7 @@ start_step_over (void)
 	 because we wouldn't be able to resume anything else until the
 	 target stops again.  In non-stop, the resume always resumes
 	 only TP, so it's OK to let the thread resume freely.  */
-      if (!non_stop && !thread_still_needs_step_over (tp))
+      if (!non_stop && !step_what)
 	continue;
 
       switch_to_thread (tp->ptid);
@@ -1934,6 +2018,15 @@ start_step_over (void)
       if (!ecs->wait_some_more)
 	error (_("Command aborted."));
 
+      gdb_assert (tp->resumed);
+
+      /* If we started a new in-line step-over, we're done.  */
+      if (step_over_info_valid_p ())
+	{
+	  gdb_assert (tp->control.trap_expected);
+	  return 1;
+	}
+
       if (!non_stop)
 	{
 	  /* On all-stop, shouldn't have resumed unless we needed a
@@ -2149,12 +2242,46 @@ resume (enum gdb_signal sig)
      single-step).  */
   int step;
 
-  tp->stepped_breakpoint = 0;
-
   gdb_assert (!thread_is_in_step_over_chain (tp));
 
   QUIT;
 
+  if (tp->suspend.waitstatus_pending_p)
+    {
+      if (debug_infrun)
+	{
+	  char *statstr;
+
+	  statstr = target_waitstatus_to_string (&tp->suspend.waitstatus);
+	  fprintf_unfiltered (gdb_stdlog,
+			      "infrun: resume: thread %s has pending wait status %s "
+			      "(currently_stepping=%d).\n",
+			      target_pid_to_str (tp->ptid),  statstr,
+			      currently_stepping (tp));
+	  xfree (statstr);
+	}
+
+      tp->resumed = 1;
+
+      /* FIXME: What should we do if we are supposed to resume this
+	 thread with a signal?  Maybe we should maintain a queue of
+	 pending signals to deliver.  */
+      if (sig != GDB_SIGNAL_0)
+	{
+	  warning (_("Couldn't deliver signal %s to %s.\n"),
+		   gdb_signal_to_name (sig), target_pid_to_str (tp->ptid));
+	}
+
+      tp->suspend.stop_signal = GDB_SIGNAL_0;
+      discard_cleanups (old_cleanups);
+
+      if (target_can_async_p ())
+	target_async (1);
+      return;
+    }
+
+  tp->stepped_breakpoint = 0;
+
   /* Depends on stepped_breakpoint.  */
   step = currently_stepping (tp);
 
@@ -2259,6 +2386,7 @@ resume (enum gdb_signal sig)
 	      resume_ptid = user_visible_resume_ptid (user_step);
 	      do_target_resume (resume_ptid, 0, GDB_SIGNAL_0);
 	      discard_cleanups (old_cleanups);
+	      tp->resumed = 1;
 	      return;
 	    }
 	}
@@ -2384,11 +2512,12 @@ resume (enum gdb_signal sig)
   if (execution_direction != EXEC_REVERSE
       && step && breakpoint_inserted_here_p (aspace, pc))
     {
-      /* The only case we currently need to step a breakpoint
-	 instruction is when we have a signal to deliver.  See
-	 handle_signal_stop where we handle random signals that could
-	 take out us out of the stepping range.  Normally, in that
-	 case we end up continuing (instead of stepping) over the
+      /* There are two cases where we currently need to step a
+	 breakpoint instruction when we have a signal to deliver:
+
+	 - See handle_signal_stop where we handle random signals that
+	 could take out us out of the stepping range.  Normally, in
+	 that case we end up continuing (instead of stepping) over the
 	 signal handler with a breakpoint at PC, but there are cases
 	 where we should _always_ single-step, even if we have a
 	 step-resume breakpoint, like when a software watchpoint is
@@ -2401,8 +2530,20 @@ resume (enum gdb_signal sig)
 	 recurses and executes PC again, it'll miss the breakpoint.
 	 So we leave the breakpoint inserted anyway, but we need to
 	 record that we tried to step a breakpoint instruction, so
-	 that adjust_pc_after_break doesn't end up confused.  */
-      gdb_assert (sig != GDB_SIGNAL_0);
+	 that adjust_pc_after_break doesn't end up confused.
+
+         - In non-stop if we insert a breakpoint (e.g., a step-resume)
+	 in one thread after another thread that was stepping had been
+	 momentarily paused for a step-over.  When we re-resume the
+	 stepping thread, it may be resumed from that address with a
+	 breakpoint that hasn't trapped yet.  Seen with
+	 gdb.threads/non-stop-fair-events.exp, on targets that don't
+	 do displaced stepping.  */
+
+      if (debug_infrun)
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: resume: [%s] stepped breakpoint\n",
+			    target_pid_to_str (tp->ptid));
 
       tp->stepped_breakpoint = 1;
 
@@ -2440,6 +2581,7 @@ resume (enum gdb_signal sig)
     }
 
   do_target_resume (resume_ptid, step, sig);
+  tp->resumed = 1;
   discard_cleanups (old_cleanups);
 }
 \f
@@ -2456,6 +2598,37 @@ clear_proceed_status_thread (struct thread_info *tp)
 			"infrun: clear_proceed_status_thread (%s)\n",
 			target_pid_to_str (tp->ptid));
 
+  /* If we're starting a new sequence, then the previous finished
+     single-step is no longer relevant.  */
+  if (tp->suspend.waitstatus_pending_p)
+    {
+      if (tp->suspend.stop_reason == TARGET_STOPPED_BY_SINGLE_STEP)
+	{
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: clear_proceed_status: pending "
+				"event of %s was a finished step. "
+				"Discarding.\n",
+				target_pid_to_str (tp->ptid));
+
+	  tp->suspend.waitstatus_pending_p = 0;
+	  tp->suspend.stop_reason = TARGET_STOPPED_BY_NO_REASON;
+	}
+      else if (debug_infrun)
+	{
+	  char *statstr;
+
+	  statstr = target_waitstatus_to_string (&tp->suspend.waitstatus);
+	  fprintf_unfiltered (gdb_stdlog,
+			      "infrun: clear_proceed_status_thread: thread %s "
+			      "has pending wait status %s "
+			      "(currently_stepping=%d).\n",
+			      target_pid_to_str (tp->ptid), statstr,
+			      currently_stepping (tp));
+	  xfree (statstr);
+	}
+    }
+
   /* If this signal should not be seen by program, give it zero.
      Used for debugging signals.  */
   if (!signal_pass_state (tp->suspend.stop_signal))
@@ -2519,8 +2692,6 @@ clear_proceed_status (int step)
 
   stop_after_trap = 0;
 
-  clear_step_over_info ();
-
   observer_notify_about_to_proceed ();
 }
 
@@ -2763,7 +2934,7 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
       /* A new displaced stepping sequence was started.  In all-stop,
 	 we can't talk to the target anymore until it next stops.  */
     }
-  else if (!tp->executing && !thread_is_in_step_over_chain (tp))
+  else if (!tp->resumed && !thread_is_in_step_over_chain (tp))
     {
       /* The thread wasn't started, and isn't queued, run it now.  */
       reset_ecs (ecs, tp);
@@ -3062,6 +3233,179 @@ print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid,
   ui_file_delete (tmp_stream);
 }
 
+/* Select a thread at random, out of those which are resumed and have
+   had events.  */
+
+static struct thread_info *
+random_pending_event_thread (ptid_t waiton_ptid)
+{
+  struct thread_info *event_tp;
+  int num_events = 0;
+  int random_selector;
+
+  /* First see how many events we have.  Count only resumed threads
+     that have an event pending.  */
+  ALL_NON_EXITED_THREADS (event_tp)
+    if (ptid_match (event_tp->ptid, waiton_ptid)
+	&& event_tp->resumed
+	&& event_tp->suspend.waitstatus_pending_p)
+      num_events++;
+
+  if (num_events == 0)
+    return NULL;
+
+  /* Now randomly pick a thread out of those that have had events.  */
+  random_selector = (int)
+    ((num_events * (double) rand ()) / (RAND_MAX + 1.0));
+
+  if (debug_infrun && num_events > 1)
+    fprintf_unfiltered (gdb_stdlog,
+			"infrun: Found %d events, selecting #%d\n",
+			num_events, random_selector);
+
+  /* Select the Nth thread that has had an event.  */
+  ALL_NON_EXITED_THREADS (event_tp)
+    if (ptid_match (event_tp->ptid, waiton_ptid)
+	&& event_tp->resumed
+	&& event_tp->suspend.waitstatus_pending_p)
+      if (random_selector-- == 0)
+	break;
+
+  return event_tp;
+}
+
+/* Wrapper for target_wait that first checks whether threads have
+   pending statuses to report before actually asking the target for
+   more events.  */
+
+static ptid_t
+do_target_wait (ptid_t ptid, struct target_waitstatus *status, int options)
+{
+  ptid_t event_ptid;
+  struct thread_info *tp;
+
+  /* First check if there is a resumed thread with a wait status
+     pending.  */
+  if (ptid_equal (ptid, minus_one_ptid) || ptid_is_pid (ptid))
+    {
+      tp = random_pending_event_thread (ptid);
+    }
+  else
+    {
+      if (debug_infrun)
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: Waiting for specific thread %s.\n",
+			    target_pid_to_str (ptid));
+
+      /* We have a specific thread to check.  */
+      tp = find_thread_ptid (ptid);
+      gdb_assert (tp != NULL);
+      if (!tp->suspend.waitstatus_pending_p)
+	tp = NULL;
+    }
+
+  if (tp != NULL
+      && (tp->suspend.stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT
+	  || tp->suspend.stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT))
+    {
+      struct regcache *regcache = get_thread_regcache (tp->ptid);
+      struct gdbarch *gdbarch = get_regcache_arch (regcache);
+      CORE_ADDR pc;
+      int discard = 0;
+
+      pc = regcache_read_pc (regcache);
+
+      if (pc != tp->suspend.stop_pc)
+	{
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: PC of %s changed.  was=%s, now=%s\n",
+				target_pid_to_str (tp->ptid),
+				paddress (gdbarch, tp->prev_pc),
+				paddress (gdbarch, pc));
+	  discard = 1;
+	}
+      else if (!breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc))
+	{
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: previous breakpoint of %s, at %s gone\n",
+				target_pid_to_str (tp->ptid),
+				paddress (gdbarch, pc));
+
+	  discard = 1;
+	}
+
+      if (discard)
+	{
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: pending event of %s cancelled.\n",
+				target_pid_to_str (tp->ptid));
+
+	  tp->suspend.waitstatus.kind = TARGET_WAITKIND_SPURIOUS;
+	  tp->suspend.stop_reason = TARGET_STOPPED_BY_NO_REASON;
+	}
+    }
+
+  if (tp != NULL)
+    {
+      if (debug_infrun)
+	{
+	  char *statstr;
+
+	  statstr = target_waitstatus_to_string (&tp->suspend.waitstatus);
+	  fprintf_unfiltered (gdb_stdlog,
+			      "infrun: Using pending wait status %s for %s.\n",
+			      statstr,
+			      target_pid_to_str (tp->ptid));
+	  xfree (statstr);
+	}
+
+      /* Now that we've selected our final event LWP, un-adjust its PC
+	 if it was a software breakpoint (and the target doesn't
+	 always adjust the PC itself).  */
+      if (tp->suspend.stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT
+	  && !target_supports_stopped_by_sw_breakpoint ())
+	{
+	  struct regcache *regcache;
+	  struct gdbarch *gdbarch;
+	  int decr_pc;
+
+	  regcache = get_thread_regcache (tp->ptid);
+	  gdbarch = get_regcache_arch (regcache);
+
+	  decr_pc = gdbarch_decr_pc_after_break (gdbarch);
+	  if (decr_pc != 0)
+	    {
+	      CORE_ADDR pc;
+
+	      pc = regcache_read_pc (regcache);
+	      regcache_write_pc (regcache, pc + decr_pc);
+	    }
+	}
+
+      tp->suspend.stop_reason = TARGET_STOPPED_BY_NO_REASON;
+      *status = tp->suspend.waitstatus;
+      tp->suspend.waitstatus_pending_p = 0;
+
+      /* Wake up the event loop again, until all pending events are
+	 processed.  */
+      if (target_is_async_p ())
+	mark_async_event_handler (infrun_async_inferior_event_token);
+      return tp->ptid;
+    }
+
+  /* But if we don't find one, we'll have to wait.  */
+
+  if (deprecated_target_wait_hook)
+    event_ptid = deprecated_target_wait_hook (ptid, status, options);
+  else
+    event_ptid = target_wait (ptid, status, options);
+
+  return event_ptid;
+}
+
 /* Prepare and stabilize the inferior for detaching it.  E.g.,
    detaching while a thread is displaced stepping is a recipe for
    crashing it, as nothing would readjust the PC out of the scratch
@@ -3105,10 +3449,7 @@ prepare_for_detach (void)
 	 don't get any event.  */
       target_dcache_invalidate ();
 
-      if (deprecated_target_wait_hook)
-	ecs->ptid = deprecated_target_wait_hook (pid_ptid, &ecs->ws, 0);
-      else
-	ecs->ptid = target_wait (pid_ptid, &ecs->ws, 0);
+      ecs->ptid = do_target_wait (pid_ptid, &ecs->ws, 0);
 
       if (debug_infrun)
 	print_target_wait_results (pid_ptid, ecs->ptid, &ecs->ws);
@@ -3180,10 +3521,7 @@ wait_for_inferior (void)
 	 don't get any event.  */
       target_dcache_invalidate ();
 
-      if (deprecated_target_wait_hook)
-	ecs->ptid = deprecated_target_wait_hook (waiton_ptid, &ecs->ws, 0);
-      else
-	ecs->ptid = target_wait (waiton_ptid, &ecs->ws, 0);
+      ecs->ptid = do_target_wait (waiton_ptid, &ecs->ws, 0);
 
       if (debug_infrun)
 	print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws);
@@ -3280,11 +3618,7 @@ fetch_inferior_event (void *client_data)
   make_cleanup_restore_integer (&execution_direction);
   execution_direction = target_execution_direction ();
 
-  if (deprecated_target_wait_hook)
-    ecs->ptid =
-      deprecated_target_wait_hook (waiton_ptid, &ecs->ws, TARGET_WNOHANG);
-  else
-    ecs->ptid = target_wait (waiton_ptid, &ecs->ws, TARGET_WNOHANG);
+  ecs->ptid = do_target_wait (waiton_ptid, &ecs->ws, TARGET_WNOHANG);
 
   if (debug_infrun)
     print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws);
@@ -3657,6 +3991,347 @@ get_inferior_stop_soon (ptid_t ptid)
   return inf->control.stop_soon;
 }
 
+/* Wait for one event.  Store the resulting waitstatus in WS, and
+   return the event ptid.  */
+
+static ptid_t
+wait_one (struct target_waitstatus *ws)
+{
+  ptid_t event_ptid;
+  ptid_t wait_ptid = minus_one_ptid;
+
+  overlay_cache_invalid = 1;
+
+  /* Flush target cache before starting to handle each event.
+     Target was running and cache could be stale.  This is just a
+     heuristic.  Running threads may modify target memory, but we
+     don't get any event.  */
+  target_dcache_invalidate ();
+
+  if (deprecated_target_wait_hook)
+    event_ptid = deprecated_target_wait_hook (wait_ptid, ws, 0);
+  else
+    event_ptid = target_wait (wait_ptid, ws, 0);
+
+  if (debug_infrun)
+    print_target_wait_results (wait_ptid, event_ptid, ws);
+
+  return event_ptid;
+}
+
+/* Generate a wrapper for target_stopped_by_REASON that works on PTID
+   instead of the current thread.  */
+#define THREAD_STOPPED_BY(REASON)		\
+static int					\
+thread_stopped_by_ ## REASON (ptid_t ptid)	\
+{						\
+  struct cleanup *old_chain;			\
+  int res;					\
+						\
+  old_chain = save_inferior_ptid ();		\
+  inferior_ptid = ptid;				\
+						\
+  res = target_stopped_by_ ## REASON ();	\
+						\
+  do_cleanups (old_chain);			\
+						\
+  return res;					\
+}
+
+/* Generate thread_stopped_by_watchpoint.  */
+THREAD_STOPPED_BY (watchpoint)
+/* Generate thread_stopped_by_sw_breakpoint.  */
+THREAD_STOPPED_BY (sw_breakpoint)
+/* Generate thread_stopped_by_hw_breakpoint.  */
+THREAD_STOPPED_BY (hw_breakpoint)
+
+/* Cleanups that switches to the PTID pointed at by PTID_P.  */
+
+static void
+switch_to_thread_cleanup (void *ptid_p)
+{
+  ptid_t ptid = *(ptid_t *) ptid_p;
+
+  switch_to_thread (ptid);
+}
+
+/* Save the thread's event and stop reason to process it later.  */
+
+static void
+save_waitstatus (struct thread_info *tp, struct target_waitstatus *ws)
+{
+  struct regcache *regcache;
+  struct address_space *aspace;
+
+  if (debug_infrun)
+    {
+      char *statstr;
+
+      statstr = target_waitstatus_to_string (ws);
+      fprintf_unfiltered (gdb_stdlog,
+			  "infrun: saving status %s for %d.%ld.%ld\n",
+			  statstr,
+			  ptid_get_pid (tp->ptid),
+			  ptid_get_lwp (tp->ptid),
+			  ptid_get_tid (tp->ptid));
+      xfree (statstr);
+    }
+
+  /* Record for later.  */
+  tp->suspend.waitstatus = *ws;
+  tp->suspend.waitstatus_pending_p = 1;
+
+  regcache = get_thread_regcache (tp->ptid);
+  aspace = get_regcache_aspace (regcache);
+
+  if (ws->kind == TARGET_WAITKIND_STOPPED
+      && ws->value.sig == GDB_SIGNAL_TRAP)
+    {
+      CORE_ADDR pc = regcache_read_pc (regcache);
+
+      adjust_pc_after_break (tp, &tp->suspend.waitstatus);
+
+      if (thread_stopped_by_watchpoint (tp->ptid))
+	{
+	  tp->suspend.stop_reason
+	    = TARGET_STOPPED_BY_WATCHPOINT;
+	}
+      else if (target_supports_stopped_by_sw_breakpoint ()
+	       && thread_stopped_by_sw_breakpoint (tp->ptid))
+	{
+	  tp->suspend.stop_reason
+	    = TARGET_STOPPED_BY_SW_BREAKPOINT;
+	}
+      else if (target_supports_stopped_by_hw_breakpoint ()
+	       && thread_stopped_by_hw_breakpoint (tp->ptid))
+	{
+	  tp->suspend.stop_reason
+	    = TARGET_STOPPED_BY_HW_BREAKPOINT;
+	}
+      else if (!target_supports_stopped_by_hw_breakpoint ()
+	       && hardware_breakpoint_inserted_here_p (aspace,
+						       pc))
+	{
+	  tp->suspend.stop_reason
+	    = TARGET_STOPPED_BY_HW_BREAKPOINT;
+	}
+      else if (!target_supports_stopped_by_sw_breakpoint ()
+	       && software_breakpoint_inserted_here_p (aspace,
+						       pc))
+	{
+	  tp->suspend.stop_reason
+	    = TARGET_STOPPED_BY_SW_BREAKPOINT;
+	}
+      else if (!thread_has_single_step_breakpoints_set (tp)
+	       && currently_stepping (tp))
+	{
+	  tp->suspend.stop_reason
+	    = TARGET_STOPPED_BY_SINGLE_STEP;
+	}
+    }
+}
+
+/* Stop all threads.  */
+
+static void
+stop_all_threads (void)
+{
+  /* We may need multiple passes to discover all threads.  */
+  int pass;
+  int iterations = 0;
+  ptid_t entry_ptid;
+  struct cleanup *old_chain;
+
+  gdb_assert (non_stop);
+
+  if (debug_infrun)
+    fprintf_unfiltered (gdb_stdlog, "infrun: stop_all_threads\n");
+
+  entry_ptid = inferior_ptid;
+  old_chain = make_cleanup (switch_to_thread_cleanup, &entry_ptid);
+
+  /* Request threads to stop, and then wait for the stops.  Because
+     threads we already know about can spawn more threads while we're
+     trying to stop them, and we only learn about new threads when we
+     update the thread list, do this in a loop, and keep iterating
+     until two passes find no threads that need to be stopped.  */
+  for (pass = 0; pass < 2; pass++, iterations++)
+    {
+      if (debug_infrun)
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: stop_all_threads, pass=%d, "
+			    "iterations=%d\n", pass, iterations);
+      while (1)
+	{
+	  ptid_t event_ptid;
+	  struct target_waitstatus ws;
+	  int need_wait = 0;
+	  struct thread_info *t;
+
+	  update_thread_list ();
+
+	  /* Go through all threads looking for threads that we need
+	     to tell the target to stop.  */
+	  ALL_NON_EXITED_THREADS (t)
+	    {
+	      if (t->executing)
+		{
+		  /* If already stopping, don't request a stop again.
+		     We just haven't seen the notification yet.  */
+		  if (!t->stop_requested)
+		    {
+		      if (debug_infrun)
+			fprintf_unfiltered (gdb_stdlog,
+					    "infrun:   %s executing, "
+					    "need stop\n",
+					    target_pid_to_str (t->ptid));
+		      target_stop (t->ptid);
+		      t->stop_requested = 1;
+		    }
+		  else
+		    {
+		      if (debug_infrun)
+			fprintf_unfiltered (gdb_stdlog,
+					    "infrun:   %s executing, "
+					    "already stopping\n",
+					    target_pid_to_str (t->ptid));
+		    }
+
+		  if (t->stop_requested)
+		    need_wait = 1;
+		}
+	      else
+		{
+		  if (debug_infrun)
+		    fprintf_unfiltered (gdb_stdlog,
+					"infrun:   %s not executing\n",
+					target_pid_to_str (t->ptid));
+
+		  /* The thread may be not executing, but still be
+		     resumed with a pending status to process.  */
+		  t->resumed = 0;
+		}
+	    }
+
+	  if (!need_wait)
+	    break;
+
+	  /* If we find new threads on the second iteration, restart
+	     over.  We want to see two iterations in a row with all
+	     threads stopped.  */
+	  if (pass > 0)
+	    pass = -1;
+
+	  event_ptid = wait_one (&ws);
+	  if (ws.kind == TARGET_WAITKIND_NO_RESUMED)
+	    {
+	      /* All resumed threads exited.  */
+	    }
+	  else if (ws.kind == TARGET_WAITKIND_EXITED
+		   || ws.kind == TARGET_WAITKIND_SIGNALLED)
+	    {
+	      if (debug_infrun)
+		{
+		  ptid_t ptid = pid_to_ptid (ws.value.integer);
+
+		  fprintf_unfiltered (gdb_stdlog,
+				      "infrun: %s exited while "
+				      "stopping threads\n",
+				      target_pid_to_str (ptid));
+		}
+	    }
+	  else
+	    {
+	      t = find_thread_ptid (event_ptid);
+	      if (t == NULL)
+		t = add_thread (event_ptid);
+
+	      t->stop_requested = 0;
+	      t->executing = 0;
+	      t->resumed = 0;
+	      t->control.may_range_step = 0;
+
+	      if (ws.kind == TARGET_WAITKIND_STOPPED
+		  && ws.value.sig == GDB_SIGNAL_0)
+		{
+		  /* We caught the event that we intended to catch, so
+		     there's no event pending.  */
+		  t->suspend.waitstatus.kind = TARGET_WAITKIND_IGNORE;
+		  t->suspend.waitstatus_pending_p = 0;
+
+		  if (displaced_step_fixup (t->ptid, GDB_SIGNAL_0) < 0)
+		    {
+		      /* Add it back to the step-over queue.  */
+		      if (debug_infrun)
+			{
+			  fprintf_unfiltered (gdb_stdlog,
+					      "infrun: displaced-step of %s "
+					      "canceled: adding back to the "
+					      "step-over queue\n",
+					      target_pid_to_str (t->ptid));
+			}
+		      t->control.trap_expected = 0;
+		      thread_step_over_chain_enqueue (t);
+		    }
+		}
+	      else
+		{
+		  enum gdb_signal sig;
+		  struct regcache *regcache;
+		  struct address_space *aspace;
+
+		  if (debug_infrun)
+		    {
+		      char *statstr;
+
+		      statstr = target_waitstatus_to_string (&ws);
+		      fprintf_unfiltered (gdb_stdlog,
+					  "infrun: target_wait %s, saving "
+					  "status for %d.%ld.%ld\n",
+					  statstr,
+					  ptid_get_pid (t->ptid),
+					  ptid_get_lwp (t->ptid),
+					  ptid_get_tid (t->ptid));
+		      xfree (statstr);
+		    }
+
+		  /* Record for later.  */
+		  save_waitstatus (t, &ws);
+
+		  sig = (ws.kind == TARGET_WAITKIND_STOPPED
+			 ? ws.value.sig : GDB_SIGNAL_0);
+
+		  if (displaced_step_fixup (t->ptid, sig) < 0)
+		    {
+		      /* Add it back to the step-over queue.  */
+		      t->control.trap_expected = 0;
+		      thread_step_over_chain_enqueue (t);
+		    }
+
+		  regcache = get_thread_regcache (t->ptid);
+		  t->suspend.stop_pc = regcache_read_pc (regcache);
+
+		  if (debug_infrun)
+		    {
+		      fprintf_unfiltered (gdb_stdlog,
+					  "infrun: saved stop_pc=%s for %s "
+					  "(currently_stepping=%d)\n",
+					  paddress (target_gdbarch (),
+						    t->suspend.stop_pc),
+					  target_pid_to_str (t->ptid),
+					  currently_stepping (t));
+		    }
+		}
+	    }
+	}
+    }
+
+  do_cleanups (old_chain);
+
+  if (debug_infrun)
+    fprintf_unfiltered (gdb_stdlog, "infrun: stop_all_threads done\n");
+}
+
 /* Given an execution control state that has been freshly filled in by
    an event from the inferior, figure out what it means and take
    appropriate action.
@@ -3776,31 +4451,38 @@ handle_inferior_event_1 (struct execution_control_state *ecs)
   /* Mark the non-executing threads accordingly.  In all-stop, all
      threads of all processes are stopped when we get any event
      reported.  In non-stop mode, only the event thread stops.  */
-  if (!non_stop)
-    set_executing (minus_one_ptid, 0);
-  else if (ecs->ws.kind == TARGET_WAITKIND_SIGNALLED
-	   || ecs->ws.kind == TARGET_WAITKIND_EXITED)
-    {
-      ptid_t pid_ptid;
-
-      /* If we're handling a process exit in non-stop mode, even
-	 though threads haven't been deleted yet, one would think that
-	 there is nothing to do, as threads of the dead process will
-	 be soon deleted, and threads of any other process were left
-	 running.  However, on some targets, threads survive a process
-	 exit event.  E.g., for the "checkpoint" command, when the
-	 current checkpoint/fork exits, linux-fork.c automatically
-	 switches to another fork from within target_mourn_inferior,
-	 by associating the same inferior/thread to another fork.  We
-	 haven't mourned yet at this point, but we must mark any
-	 threads left in the process as not-executing so that
-	 finish_thread_state marks them stopped (in the user's
-	 perspective) if/when we present the stop to the user.  */
-      pid_ptid = pid_to_ptid (ptid_get_pid (ecs->ptid));
-      set_executing (pid_ptid, 0);
-    }
-  else
-    set_executing (ecs->ptid, 0);
+  {
+    ptid_t mark_ptid;
+
+    if (!non_stop)
+      mark_ptid = minus_one_ptid;
+    else if (ecs->ws.kind == TARGET_WAITKIND_SIGNALLED
+	     || ecs->ws.kind == TARGET_WAITKIND_EXITED)
+      {
+	/* If we're handling a process exit in non-stop mode, even
+	   though threads haven't been deleted yet, one would think
+	   that there is nothing to do, as threads of the dead process
+	   will be soon deleted, and threads of any other process were
+	   left running.  However, on some targets, threads survive a
+	   process exit event.  E.g., for the "checkpoint" command,
+	   when the current checkpoint/fork exits, linux-fork.c
+	   automatically switches to another fork from within
+	   target_mourn_inferior, by associating the same
+	   inferior/thread to another fork.  We haven't mourned yet at
+	   this point, but we must mark any threads left in the
+	   process as not-executing so that finish_thread_state marks
+	   them stopped (in the user's perspective) if/when we present
+	   the stop to the user.  */
+	mark_ptid = pid_to_ptid (ptid_get_pid (ecs->ptid));
+      }
+    else
+      mark_ptid = ecs->ptid;
+
+    set_executing (mark_ptid, 0);
+
+    /* Likewise the resumed flag.  */
+    set_resumed (mark_ptid, 0);
+  }
 
   switch (ecs->ws.kind)
     {
@@ -4229,16 +4911,137 @@ handle_inferior_event (struct execution_control_state *ecs)
   value_free_to_mark (mark);
 }
 
-/* Called when we get an event that may finish an in-line or
-   out-of-line (displaced stepping) step-over started previously.  */
+/* Restart threads back to what they were trying to do back when we
+   paused them for an in-line step-over.  The EVENT_THREAD thread is
+   ignored.  */
 
 static void
+restart_threads (struct thread_info *event_thread)
+{
+  struct thread_info *tp;
+  struct thread_info *step_over = NULL;
+
+  /* In case the instruction just stepped spawned a new thread.  */
+  update_thread_list ();
+
+  ALL_NON_EXITED_THREADS (tp)
+    {
+      if (tp == event_thread)
+	{
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: restart threads: "
+				"[%s] is event thread\n",
+				target_pid_to_str (tp->ptid));
+	  continue;
+	}
+
+      if (!(tp->state == THREAD_RUNNING || tp->control.in_infcall))
+	{
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: restart threads: "
+				"[%s] not meant to be running\n",
+				target_pid_to_str (tp->ptid));
+	  continue;
+	}
+
+      if (tp->resumed)
+	{
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: restart threads: [%s] resumed\n",
+				target_pid_to_str (tp->ptid));
+	  gdb_assert (tp->executing || tp->suspend.waitstatus_pending_p);
+	  continue;
+	}
+
+      if (thread_is_in_step_over_chain (tp))
+	{
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: restart threads: "
+				"[%s] needs step-over\n",
+				target_pid_to_str (tp->ptid));
+	  gdb_assert (!tp->resumed);
+	  continue;
+	}
+
+
+      if (tp->suspend.waitstatus_pending_p)
+	{
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: restart threads: "
+				"[%s] has pending status\n",
+				target_pid_to_str (tp->ptid));
+	  tp->resumed = 1;
+	  continue;
+	}
+
+      /* If some thread needs to start a step-over at this point, it
+	 should still be in the step-over queue, and thus skipped
+	 above.  */
+      if (thread_still_needs_step_over (tp))
+	{
+	  internal_error (__FILE__, __LINE__,
+			  "thread [%s] needs a step-over, but not in "
+			  "step-over queue\n",
+			  target_pid_to_str (tp->ptid));
+	}
+
+      if (currently_stepping (tp))
+	{
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: restart threads: [%s] was stepping\n",
+				target_pid_to_str (tp->ptid));
+	  keep_going_stepped_thread (tp);
+	}
+      else
+	{
+	  struct execution_control_state ecss;
+	  struct execution_control_state *ecs = &ecss;
+
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: restart threads: [%s] continuing\n",
+				target_pid_to_str (tp->ptid));
+	  reset_ecs (ecs, tp);
+	  switch_to_thread (tp->ptid);
+	  keep_going_pass_signal (ecs);
+	}
+    }
+}
+
+/* Callback for iterate_over_threads.  Find a resumed thread that has
+   a pending waitstatus.  */
+
+static int
+resumed_thread_with_pending_status (struct thread_info *tp,
+				    void *arg)
+{
+  return (tp->resumed
+	  && tp->suspend.waitstatus_pending_p);
+}
+
+/* Called when we get an event that may finish an in-line or
+   out-of-line (displaced stepping) step-over started previously.
+   Return true if the event is processed and we should go back to the
+   event loop; false if the caller should continue processing the
+   event.  */
+
+static int
 finish_step_over (struct execution_control_state *ecs)
 {
+  int had_step_over_info;
+
   displaced_step_fixup (ecs->ptid,
 			ecs->event_thread->suspend.stop_signal);
 
-  if (step_over_info_valid_p ())
+  had_step_over_info = step_over_info_valid_p ();
+
+  if (had_step_over_info)
     {
       /* If we're stepping over a breakpoint with all threads locked,
 	 then only the thread that was stepped should be reporting
@@ -4250,11 +5053,99 @@ finish_step_over (struct execution_control_state *ecs)
     }
 
   if (!non_stop)
-    return;
+    return 0;
 
   /* Start a new step-over in another thread if there's one that
      needs it.  */
   start_step_over ();
+
+  /* If we were stepping over a breakpoint before, and haven't started
+     a new in-line step-over sequence, then restart all other threads
+     (except the event thread).  We can't do this in all-stop, as then
+     e.g., we wouldn't be able to issue any other remote packet until
+     these other threads stop.  */
+  if (had_step_over_info && !step_over_info_valid_p ())
+    {
+      struct thread_info *pending;
+
+      /* If we only have threads with pending statuses, the restart
+	 below won't restart any thread and so nothing re-inserts the
+	 breakpoint we just stepped over.  But we need it inserted
+	 when we later process the pending events, otherwise if
+	 another thread has a pending event for this breakpoint too,
+	 we'd discard its event (because the breakpoint that
+	 originally caused the event was no longer inserted).  */
+      context_switch (ecs->ptid);
+      insert_breakpoints ();
+
+      restart_threads (ecs->event_thread);
+
+      /* If we have events pending, go through handle_inferior_event
+	 again, picking up a pending event at random.  This avoids
+	 thread starvation.  */
+
+      /* But not if we just stepped over a watchpoint in order to let
+	 the instruction execute so we can evaluate its expression.
+	 The set of watchpoints that triggered is recorded in the
+	 breakpoint objects themselves (see bp->watchpoint_triggered).
+	 If we processed another event first, that other event could
+	 clobber this info.  */
+      if (ecs->event_thread->stepping_over_watchpoint)
+	return 0;
+
+      pending = iterate_over_threads (resumed_thread_with_pending_status,
+				      NULL);
+      if (pending != NULL)
+	{
+	  struct thread_info *tp = ecs->event_thread;
+	  struct regcache *regcache;
+
+	  if (debug_infrun)
+	    {
+	      fprintf_unfiltered (gdb_stdlog,
+				  "infrun: found resumed threads with "
+				  "pending events, saving status\n");
+	    }
+
+	  gdb_assert (pending != tp);
+
+	  /* Record the event thread's event for later.  */
+	  save_waitstatus (tp, &ecs->ws);
+	  /* This was cleared early, by handle_inferior_event.  Set it
+	     so this pending event is considered by
+	     do_target_wait.  */
+	  tp->resumed = 1;
+
+	  gdb_assert (!tp->executing);
+
+	  regcache = get_thread_regcache (tp->ptid);
+	  tp->suspend.stop_pc = regcache_read_pc (regcache);
+
+	  if (debug_infrun)
+	    {
+	      fprintf_unfiltered (gdb_stdlog,
+				  "infrun: saved stop_pc=%s for %s "
+				  "(currently_stepping=%d)\n",
+				  paddress (target_gdbarch (),
+					    tp->suspend.stop_pc),
+				  target_pid_to_str (tp->ptid),
+				  currently_stepping (tp));
+	    }
+
+	  /* This in-line step-over finished; clear this so we won't
+	     start a new one.  This is what handle_signal_stop would
+	     do, if we returned false.  */
+	  tp->stepping_over_breakpoint = 0;
+
+	  /* Wake up the event loop again.  */
+	  mark_async_event_handler (infrun_async_inferior_event_token);
+
+	  prepare_to_wait (ecs);
+	  return 1;
+	}
+    }
+
+  return 0;
 }
 
 /* Come here when the program has stopped with a signal.  */
@@ -4273,7 +5164,8 @@ handle_signal_stop (struct execution_control_state *ecs)
   /* Do we need to clean up the state of a thread that has
      completed a displaced single-step?  (Doing so usually affects
      the PC, so do it here, before we set stop_pc.)  */
-  finish_step_over (ecs);
+  if (finish_step_over (ecs))
+    return;
 
   /* If we either finished a single-step or hit a breakpoint, but
      the user wanted this thread to be stopped, pretend we got a
@@ -4716,6 +5608,8 @@ handle_signal_stop (struct execution_control_state *ecs)
 	  && ecs->event_thread->control.trap_expected
 	  && ecs->event_thread->control.step_resume_breakpoint == NULL)
 	{
+	  int was_in_line;
+
 	  /* We were just starting a new sequence, attempting to
 	     single-step off of a breakpoint and expecting a SIGTRAP.
 	     Instead this signal arrives.  This signal will take us out
@@ -4731,11 +5625,32 @@ handle_signal_stop (struct execution_control_state *ecs)
                                 "infrun: signal arrived while stepping over "
                                 "breakpoint\n");
 
+	  was_in_line = step_over_info_valid_p ();
+	  clear_step_over_info ();
 	  insert_hp_step_resume_breakpoint_at_frame (frame);
 	  ecs->event_thread->step_after_step_resume_breakpoint = 1;
 	  /* Reset trap_expected to ensure breakpoints are re-inserted.  */
 	  ecs->event_thread->control.trap_expected = 0;
 
+	  if (non_stop)
+	    {
+	      keep_going (ecs);
+
+	      /* The step-over has been canceled temporarily while the
+		 signal handler executes.  */
+	      if (was_in_line)
+		{
+		  /* We had paused all threads, restart them.  */
+		  restart_threads (ecs->event_thread);
+		}
+	      else if (debug_infrun)
+		{
+		  fprintf_unfiltered (gdb_stdlog,
+				      "infrun: no need to restart threads\n");
+		}
+	      return;
+	    }
+
 	  /* If we were nexting/stepping some other thread, switch to
 	     it, so that we don't continue it, losing control.  */
 	  if (!switch_back_to_stepped_thread (ecs))
@@ -4764,6 +5679,7 @@ handle_signal_stop (struct execution_control_state *ecs)
                                 "infrun: signal may take us out of "
                                 "single-step range\n");
 
+	  clear_step_over_info ();
 	  insert_hp_step_resume_breakpoint_at_frame (frame);
 	  ecs->event_thread->step_after_step_resume_breakpoint = 1;
 	  /* Reset trap_expected to ensure breakpoints are re-inserted.  */
@@ -5719,7 +6635,14 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
 	     except the one that needs to move past the breakpoint.
 	     If a non-event thread has this set, the "incomplete
 	     step-over" check above should have caught it earlier.  */
-	  gdb_assert (!tp->control.trap_expected);
+	  if (tp->control.trap_expected)
+	    {
+	      internal_error (__FILE__, __LINE__,
+			      "[%s] has inconsistent state: "
+			      "trap_expected=%d\n",
+			      target_pid_to_str (tp->ptid),
+			      tp->control.trap_expected);
+	    }
 
 	  /* Did we find the stepping thread?  */
 	  if (tp->control.step_range_end)
@@ -5848,6 +6771,7 @@ keep_going_stepped_thread (struct thread_info *tp)
 				     get_frame_address_space (frame),
 				     stop_pc);
 
+      tp->resumed = 1;
       resume_ptid = user_visible_resume_ptid (tp->control.stepping_command);
       do_target_resume (resume_ptid, 0, GDB_SIGNAL_0);
     }
@@ -6281,6 +7205,7 @@ keep_going_pass_signal (struct execution_control_state *ecs)
   struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0);
 
   gdb_assert (ptid_equal (ecs->event_thread->ptid, inferior_ptid));
+  gdb_assert (!ecs->event_thread->resumed);
 
   /* Save the pc before execution, to compare with pc after stop.  */
   ecs->event_thread->prev_pc
@@ -6303,6 +7228,34 @@ keep_going_pass_signal (struct execution_control_state *ecs)
       discard_cleanups (old_cleanups);
       resume (ecs->event_thread->suspend.stop_signal);
     }
+  else if (step_over_info_valid_p ())
+    {
+      /* Another thread is stepping over a breakpoint in-line.  If
+	 this thread needs a step-over too, queue the request.  In
+	 either case, this resume must be deferred for later.  */
+      struct thread_info *tp = ecs->event_thread;
+
+      if (ecs->hit_singlestep_breakpoint
+	  || thread_still_needs_step_over (tp))
+	{
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: step-over already in progress: "
+				"step-over for %s deferred\n",
+				target_pid_to_str (tp->ptid));
+	  thread_step_over_chain_enqueue (tp);
+	}
+      else
+	{
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: step-over in progress: "
+				"resume of %s deferred\n",
+				target_pid_to_str (tp->ptid));
+	}
+
+      discard_cleanups (old_cleanups);
+    }
   else
     {
       struct regcache *regcache = get_current_regcache ();
@@ -6347,8 +7300,14 @@ keep_going_pass_signal (struct execution_control_state *ecs)
 	}
       else if (remove_wps)
 	set_step_over_info (NULL, 0, remove_wps);
-      else
-	clear_step_over_info ();
+
+      /* If we now need to do an in-line step-over, we need to stop
+	 all other threads.  Note this must be done before
+	 insert_breakpoints below, because that removes the breakpoint
+	 we're about to step over, otherwise other threads could miss
+	 it.  */
+      if (step_over_info_valid_p () && non_stop)
+	stop_all_threads ();
 
       /* Stop stepping if inserting breakpoints fails.  */
       TRY
@@ -7704,6 +8663,23 @@ static const struct internalvar_funcs siginfo_funcs =
   NULL
 };
 
+/* Callback for infrun's target events source.  This is marked when a
+   thread has a pending status to process.  */
+
+static void
+infrun_async_inferior_event_handler (gdb_client_data data)
+{
+  /* If the target is closed while this event source is marked, we
+     will reach here without execution, or a target to call
+     target_wait on, which is an error.  Instead of tracking whether
+     the target has been popped already, or whether we do have threads
+     with pending statutes, simply ignore the event.  */
+  if (!target_is_async_p ())
+    return;
+
+  inferior_event_handler (INF_REG_EVENT, NULL);
+}
+
 void
 _initialize_infrun (void)
 {
@@ -7711,6 +8687,10 @@ _initialize_infrun (void)
   int numsigs;
   struct cmd_list_element *c;
 
+  /* Register extra event sources in the event loop.  */
+  infrun_async_inferior_event_token
+    = create_async_event_handler (infrun_async_inferior_event_handler, NULL);
+
   add_info ("signals", signals_info, _("\
 What debugger does when program gets various signals.\n\
 Specify a signal as argument to print info on that signal only."));
diff --git a/gdb/infrun.h b/gdb/infrun.h
index 7d1033c..6108648 100644
--- a/gdb/infrun.h
+++ b/gdb/infrun.h
@@ -189,6 +189,9 @@ extern void signal_catch_update (const unsigned int *);
    systems.  Use of symbolic signal names is strongly encouraged.  */
 enum gdb_signal gdb_signal_from_command (int num);
 
+/* Enables/disables infrun's async event source in the event loop.  */
+extern void infrun_async (int enable);
+
 /* The global queue of threads that need to do a step-over operation
    to get past e.g., a breakpoint.  */
 extern struct thread_info *step_over_queue_head;
diff --git a/gdb/target.c b/gdb/target.c
index 306c21d..e992a35 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3712,6 +3712,15 @@ maintenance_print_target_stack (char *cmd, int from_tty)
     }
 }
 
+/* See target.h.  */
+
+void
+target_async (int enable)
+{
+  infrun_async (enable);
+  current_target.to_async (&current_target, enable);
+}
+
 /* Controls if targets can report that they can/are async.  This is
    just for maintainers to use when debugging gdb.  */
 int target_async_permitted = 1;
diff --git a/gdb/target.h b/gdb/target.h
index d398747..f14fbdb 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1704,8 +1704,7 @@ extern int target_async_permitted;
 #define target_is_async_p() (current_target.to_is_async_p (&current_target))
 
 /* Enables/disabled async target events.  */
-#define target_async(ENABLE) \
-     (current_target.to_async (&current_target, (ENABLE)))
+extern void target_async (int enable);
 
 #define target_execution_direction() \
   (current_target.to_execution_direction (&current_target))
diff --git a/gdb/target/waitstatus.h b/gdb/target/waitstatus.h
index d4ef3b8..ffaddc1 100644
--- a/gdb/target/waitstatus.h
+++ b/gdb/target/waitstatus.h
@@ -131,7 +131,10 @@ enum target_stop_reason
   TARGET_STOPPED_BY_HW_BREAKPOINT,
 
   /* Stopped by a watchpoint.  */
-  TARGET_STOPPED_BY_WATCHPOINT
+  TARGET_STOPPED_BY_WATCHPOINT,
+
+  /* Stopped by a single step finishing.  */
+  TARGET_STOPPED_BY_SINGLE_STEP
 };
 
 /* Prototypes */
diff --git a/gdb/thread.c b/gdb/thread.c
index 3e3f419..4dde722 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -232,6 +232,7 @@ new_thread (ptid_t ptid)
   /* Nothing to follow yet.  */
   tp->pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
   tp->state = THREAD_STOPPED;
+  tp->suspend.waitstatus.kind = TARGET_WAITKIND_IGNORE;
 
   return tp;
 }
@@ -852,6 +853,28 @@ thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid)
   observer_notify_thread_ptid_changed (old_ptid, new_ptid);
 }
 
+/* See gdbthread.h.  */
+
+void
+set_resumed (ptid_t ptid, int resumed)
+{
+  struct thread_info *tp;
+  int all = ptid_equal (ptid, minus_one_ptid);
+
+  if (all || ptid_is_pid (ptid))
+    {
+      for (tp = thread_list; tp; tp = tp->next)
+	if (all || ptid_get_pid (tp->ptid) == ptid_get_pid (ptid))
+	  tp->resumed = resumed;
+    }
+  else
+    {
+      tp = find_thread_ptid (ptid);
+      gdb_assert (tp != NULL);
+      tp->resumed = resumed;
+    }
+}
+
 /* Helper for set_running, that marks one thread either running or
    stopped.  */
 
-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 15/18] Disable displaced stepping if trying it fails
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
                   ` (16 preceding siblings ...)
  2015-05-21 23:56 ` [PATCH 10/18] Teach non-stop to do in-line step-overs (stop all, step, restart) Pedro Alves
@ 2015-05-21 23:59 ` Pedro Alves
  2015-08-07 16:58 ` [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
  18 siblings, 0 replies; 40+ messages in thread
From: Pedro Alves @ 2015-05-21 23:59 UTC (permalink / raw)
  To: gdb-patches

Running the testsuite with "maint set target-non-stop on" shows:

 (gdb) PASS: gdb.base/valgrind-infcall.exp: continue #98 (false warning)
 continue
 Continuing.
 dl_main (phdr=<optimized out>..., auxv=<optimized out>) at rtld.c:2302
 2302      LIBC_PROBE (init_complete, 2, LM_ID_BASE, r);
 Cannot access memory at address 0x400532
 (gdb) PASS: gdb.base/valgrind-infcall.exp: continue #99 (false warning)
 p gdb_test_infcall ()
 $1 = 1
 (gdb) FAIL: gdb.base/valgrind-infcall.exp: p gdb_test_infcall ()

Even though that was a native GNU/Linux test run, this test spawns
Valgrind and connects to it with "target remote".  The error above is
actually orthogonal to target-non-stop.  The real issue is that that
enables displaced stepping, and displaced stepping doesn't work with
Valgrind, because we can't write to the inferior memory (thus can't
copy the instruction to the scratch pad area).

I'm sure there will be other targets with the same issue, so trying to
identify Valgrind wouldn't be sufficient.  The fix is to try setting
up the displaced step anyway.  If we get a MEMORY_ERROR, we disable
displaced stepping for that inferior, and fall back to doing an
in-line step-over.  If "set displaced-stepping" is "on" (as opposed to
"auto), GDB warns displaced stepping failed ("on" is mainly useful for
the testsuite, not for users).

Tested on x86_64 Fedora 20.

gdb/ChangeLog:
2015-05-21  Pedro Alves  <palves@redhat.com>

	* inferior.h (struct inferior) <displaced_stepping_failed>: New
	field.
	* infrun.c (use_displaced_stepping_now_p): New parameter 'inf'.
	Return false if dispaced stepping failed before.
	(resume): Pass the current inferior to
	use_displaced_stepping_now_p.  Wrap displaced_step_prepare in
	TRY/CATCH.  If we get a MEMORY_ERROR, set the inferior's
	displaced_stepping_failed flag, and fall back to an in-line
	step-over.

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

	* gdb.base/valgrind-disp-step.c: New file.
	* gdb.base/valgrind-disp-step.exp: New file.

v4:

   - no changes.

v3:

   - displaced_stepping_failed flag moved from "struct inferior" to
     "struct displaced_step_inferior_state", and renamed "failed_before".

   - use_displaced_stepping_now_p in v2 eliminated.  Simply change the
     prototype of use_displaced_stepping to take a thread pointer
     instead.

   - TRY/CATCH around displaced_step_prepare moved to separate
     function.

v2:

   - warn if displaced stepping fails, and "set displaced-stepping" is
     "on" (but not "auto").
---
 gdb/infrun.c                                  | 112 ++++++++++++++++++----
 gdb/testsuite/gdb.base/valgrind-disp-step.c   |  32 +++++++
 gdb/testsuite/gdb.base/valgrind-disp-step.exp | 131 ++++++++++++++++++++++++++
 3 files changed, 255 insertions(+), 20 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/valgrind-disp-step.c
 create mode 100644 gdb/testsuite/gdb.base/valgrind-disp-step.exp

diff --git a/gdb/infrun.c b/gdb/infrun.c
index d9fc4e5..c321e03 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1462,6 +1462,10 @@ struct displaced_step_inferior_state
   /* The process this displaced step state refers to.  */
   int pid;
 
+  /* True if preparing a displaced step ever failed.  If so, we won't
+     try displaced stepping for this inferior again.  */
+  int failed_before;
+
   /* If this is not null_ptid, this is the thread carrying out a
      displaced single-step in process PID.  This thread's state will
      require fixing up once it has completed its step.  */
@@ -1632,16 +1636,24 @@ show_can_use_displaced_stepping (struct ui_file *file, int from_tty,
 }
 
 /* Return non-zero if displaced stepping can/should be used to step
-   over breakpoints.  */
+   over breakpoints of thread TP.  */
 
 static int
-use_displaced_stepping (struct gdbarch *gdbarch)
+use_displaced_stepping (struct thread_info *tp)
 {
+  struct regcache *regcache = get_thread_regcache (tp->ptid);
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct displaced_step_inferior_state *displaced_state;
+
+  displaced_state = get_displaced_stepping_state (ptid_get_pid (tp->ptid));
+
   return (((can_use_displaced_stepping == AUTO_BOOLEAN_AUTO
 	    && target_is_non_stop_p ())
 	   || can_use_displaced_stepping == AUTO_BOOLEAN_TRUE)
 	  && gdbarch_displaced_step_copy_insn_p (gdbarch)
-	  && find_record_target () == NULL);
+	  && find_record_target () == NULL
+	  && (displaced_state == NULL
+	      || !displaced_state->failed_before));
 }
 
 /* Clean out any stray displaced stepping state.  */
@@ -1695,7 +1707,7 @@ displaced_step_dump_bytes (struct ui_file *file,
    Returns 1 if preparing was successful -- this thread is going to be
    stepped now; or 0 if displaced stepping this thread got queued.  */
 static int
-displaced_step_prepare (ptid_t ptid)
+displaced_step_prepare_throw (ptid_t ptid)
 {
   struct cleanup *old_cleanups, *ignore_cleanups;
   struct thread_info *tp = find_thread_ptid (ptid);
@@ -1805,6 +1817,50 @@ displaced_step_prepare (ptid_t ptid)
   return 1;
 }
 
+/* Wrapper for displaced_step_prepare_throw that disabled further
+   attempts at displaced stepping if we get a memory error.  */
+
+static int
+displaced_step_prepare (ptid_t ptid)
+{
+  int prepared = -1;
+
+  TRY
+    {
+      prepared = displaced_step_prepare_throw (ptid);
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      struct displaced_step_inferior_state *displaced_state;
+
+      if (ex.error != MEMORY_ERROR)
+	throw_exception (ex);
+
+      if (debug_infrun)
+	{
+	  fprintf_unfiltered (gdb_stdlog,
+			      "infrun: disabling displaced stepping: %s\n",
+			      ex.message);
+	}
+
+      /* Be verbose if "set displaced-stepping" is "on", silent if
+	 "auto".  */
+      if (can_use_displaced_stepping == AUTO_BOOLEAN_TRUE)
+	{
+	  warning (_("disabling displaced stepping: %s\n"),
+		   ex.message);
+	}
+
+      /* Disable further displaced stepping attempts.  */
+      displaced_state
+	= get_displaced_stepping_state (ptid_get_pid (ptid));
+      displaced_state->failed_before = 1;
+    }
+  END_CATCH
+
+  return prepared;
+}
+
 static void
 write_memory_ptid (ptid_t ptid, CORE_ADDR memaddr,
 		   const gdb_byte *myaddr, int len)
@@ -1935,6 +1991,7 @@ static void keep_going_pass_signal (struct execution_control_state *ecs);
 static void prepare_to_wait (struct execution_control_state *ecs);
 static int keep_going_stepped_thread (struct thread_info *tp);
 static int thread_still_needs_step_over (struct thread_info *tp);
+static void stop_all_threads (void);
 
 /* Are there any pending step-over requests?  If so, run all we can
    now and return true.  Otherwise, return false.  */
@@ -1955,8 +2012,6 @@ start_step_over (void)
       struct execution_control_state *ecs = &ecss;
       enum step_over_what step_what;
       int must_be_in_line;
-      struct regcache *regcache = get_thread_regcache (tp->ptid);
-      struct gdbarch *gdbarch = get_regcache_arch (regcache);
 
       next = thread_step_over_chain_next (tp);
 
@@ -1968,7 +2023,7 @@ start_step_over (void)
       step_what = thread_still_needs_step_over (tp);
       must_be_in_line = ((step_what & STEP_OVER_WATCHPOINT)
 			 || ((step_what & STEP_OVER_BREAKPOINT)
-			     && !use_displaced_stepping (gdbarch)));
+			     && !use_displaced_stepping (tp)));
 
       /* We currently stop all threads of all processes to step-over
 	 in-line.  If we need to start a new in-line step-over, let
@@ -2417,15 +2472,15 @@ resume (enum gdb_signal sig)
      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
+  if (tp->control.trap_expected
+      && use_displaced_stepping (tp)
       && !step_over_info_valid_p ()
       && sig == GDB_SIGNAL_0
       && !current_inferior ()->waiting_for_vfork_done)
     {
-      struct displaced_step_inferior_state *displaced;
+      int prepared = displaced_step_prepare (inferior_ptid);
 
-      if (!displaced_step_prepare (inferior_ptid))
+      if (prepared == 0)
 	{
 	  if (debug_infrun)
 	    fprintf_unfiltered (gdb_stdlog,
@@ -2435,14 +2490,32 @@ resume (enum gdb_signal sig)
 	  discard_cleanups (old_cleanups);
 	  return;
 	}
+      else if (prepared < 0)
+	{
+	  /* Fallback to stepping over the breakpoint in-line.  */
+
+	  if (target_is_non_stop_p ())
+	    stop_all_threads ();
+
+	  set_step_over_info (get_regcache_aspace (regcache),
+			      regcache_read_pc (regcache), 0);
+
+	  step = maybe_software_singlestep (gdbarch, pc);
+
+	  insert_breakpoints ();
+	}
+      else if (prepared > 0)
+	{
+	  struct displaced_step_inferior_state *displaced;
 
-      /* Update pc to reflect the new address from which we will execute
-	 instructions due to displaced stepping.  */
-      pc = regcache_read_pc (get_thread_regcache (inferior_ptid));
+	  /* Update pc to reflect the new address from which we will
+	     execute instructions due to displaced stepping.  */
+	  pc = regcache_read_pc (get_thread_regcache (inferior_ptid));
 
-      displaced = get_displaced_stepping_state (ptid_get_pid (inferior_ptid));
-      step = gdbarch_displaced_step_hw_singlestep (gdbarch,
-						   displaced->step_closure);
+	  displaced = get_displaced_stepping_state (ptid_get_pid (inferior_ptid));
+	  step = gdbarch_displaced_step_hw_singlestep (gdbarch,
+						       displaced->step_closure);
+	}
     }
 
   /* Do we need to do it the hard way, w/temp breakpoints?  */
@@ -2570,8 +2643,8 @@ resume (enum gdb_signal sig)
     }
 
   if (debug_displaced
-      && use_displaced_stepping (gdbarch)
       && tp->control.trap_expected
+      && use_displaced_stepping (tp)
       && !step_over_info_valid_p ())
     {
       struct regcache *resume_regcache = get_thread_regcache (tp->ptid);
@@ -7361,8 +7434,7 @@ keep_going_pass_signal (struct execution_control_state *ecs)
 	 watchpoint.  The instruction copied to the scratch pad would
 	 still trigger the watchpoint.  */
       if (remove_bp
-	  && (remove_wps
-	      || !use_displaced_stepping (get_regcache_arch (regcache))))
+	  && (remove_wps || !use_displaced_stepping (ecs->event_thread)))
 	{
 	  set_step_over_info (get_regcache_aspace (regcache),
 			      regcache_read_pc (regcache), remove_wps);
diff --git a/gdb/testsuite/gdb.base/valgrind-disp-step.c b/gdb/testsuite/gdb.base/valgrind-disp-step.c
new file mode 100644
index 0000000..baba74e
--- /dev/null
+++ b/gdb/testsuite/gdb.base/valgrind-disp-step.c
@@ -0,0 +1,32 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 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 <http://www.gnu.org/licenses/>.  */
+
+static int
+foo (void)
+{
+}
+
+int
+main (void)
+{
+  foo (); /* stop 0 */
+  foo (); /* stop 1 */
+  foo (); /* stop 2 */
+  foo (); /* stop 3 */
+  foo (); /* stop 4 */
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/valgrind-disp-step.exp b/gdb/testsuite/gdb.base/valgrind-disp-step.exp
new file mode 100644
index 0000000..7e6803b
--- /dev/null
+++ b/gdb/testsuite/gdb.base/valgrind-disp-step.exp
@@ -0,0 +1,131 @@
+# Copyright 2012-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 <http://www.gnu.org/licenses/>.
+
+# Step over breakpoints with displaced stepping on, against Valgrind.
+# We can't really use displaced stepping with Valgrind, so what this
+# really tests is that GDB falls back to in-line stepping
+# automatically instead of getting stuck or crashing.
+
+if [is_remote target] {
+    # The test always runs locally.
+    return 0
+}
+
+standard_testfile .c
+if {[build_executable "failed to build" $testfile $srcfile {debug}] == -1} {
+    return -1
+}
+
+set test "spawn valgrind"
+set cmd "valgrind --vgdb-error=0 $binfile"
+set res [remote_spawn host $cmd]
+if { $res < 0 || $res == "" } {
+    verbose -log "Spawning $cmd failed."
+    unsupported $test
+    return -1
+}
+pass $test
+# Declare GDB now as running.
+set gdb_spawn_id $res
+
+# GDB started by vgdb stops already after the startup is executed, like with
+# non-extended gdbserver.  It is also not correct to run/attach the inferior.
+set use_gdb_stub 1
+
+set test "valgrind started"
+# The trailing '.' differs for different memcheck versions.
+gdb_test_multiple "" $test {
+    -re "Memcheck, a memory error detector\\.?\r\n" {
+	pass $test
+    }
+    -re "valgrind: failed to start tool 'memcheck' for platform '.*': No such file or directory" {
+	unsupported $test
+	return -1
+    }
+    -re "valgrind: wrong ELF executable class" {
+	unsupported $test
+	return -1
+    }
+    -re "command not found" {
+	# The spawn succeeded, but then valgrind was not found - e.g. if
+	# we spawned SSH to a remote system.
+	unsupported $test
+	return -1
+    }
+    -re "valgrind: Bad option.*--vgdb-error=0" {
+	# valgrind is not >= 3.7.0.
+	unsupported $test
+	return -1
+    }
+}
+
+set test "vgdb prompt"
+# The trailing '.' differs for different memcheck versions.
+gdb_test_multiple "" $test {
+    -re "  (target remote | \[^\r\n\]*/vgdb \[^\r\n\]*)\r\n" {
+	set vgdbcmd $expect_out(1,string)
+	pass $test
+    }
+}
+
+# Do not kill valgrind.
+set valgrind_pid [exp_pid -i [board_info host fileid]]
+unset gdb_spawn_id
+set board [host_info name]
+unset_board_info fileid
+
+clean_restart $testfile
+
+gdb_test "$vgdbcmd" " in \\.?_start .*" "target remote for vgdb"
+
+gdb_test "monitor v.set gdb_output" "valgrind output will go to gdb.*"
+
+gdb_test_no_output "set displaced-stepping off"
+gdb_breakpoint "main" "breakpoint at main"
+gdb_test "continue" " stop 0 .*" "continue to main"
+delete_breakpoints
+
+set curr_stop 0
+foreach displaced { "off" "on" } {
+    with_test_prefix "displaced $displaced" {
+
+	gdb_test_no_output "set displaced-stepping $displaced"
+
+	foreach go { "once" "twice" } {
+	    with_test_prefix $go {
+		gdb_test "break" "Breakpoint .* at .*" "set breakpoint"
+
+		# Whether we should see a warning.
+		set should_warn [expr {$go == "once" && $displaced == "on"}]
+
+		incr curr_stop
+
+		set msg "step over breakpoint"
+		set pattern " stop $curr_stop .*$gdb_prompt $"
+		gdb_test_multiple "next" $msg {
+		    -re "warning: disabling displaced stepping.*$pattern" {
+			gdb_assert $should_warn $msg
+		    }
+		    -re "$pattern" {
+			gdb_assert !$should_warn $msg
+		    }
+		}
+	    }
+	}
+    }
+}
+
+# Only if valgrind got stuck.
+remote_exec host "kill -9 ${valgrind_pid}"
-- 
1.9.3

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4 00/18] All-stop on top of non-stop
  2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
                   ` (17 preceding siblings ...)
  2015-05-21 23:59 ` [PATCH 15/18] Disable displaced stepping if trying it fails Pedro Alves
@ 2015-08-07 16:58 ` Pedro Alves
  2015-08-12 18:32   ` Joel Brobecker
  18 siblings, 1 reply; 40+ messages in thread
From: Pedro Alves @ 2015-08-07 16:58 UTC (permalink / raw)
  To: gdb-patches

On 05/22/2015 12:18 AM, Pedro Alves wrote:
> v3: https://sourceware.org/ml/gdb-patches/2015-04/msg00662.html
> v2: https://sourceware.org/ml/gdb-patches/2015-04/msg00198.html
> v1: https://sourceware.org/ml/gdb-patches/2015-04/msg00073.html
> 
> Compared to v3, a set of minor changes accumulated, to address review
> comments and discussions (i.e., no major functional/design changes),
> plus fixes to a patch that touched all targets (that I noticed
> converted a couple wrong).
> 
> I believe I addressed all review comments thus far.  Barring comments,
> I'd like to push this in, and expose it to the build bots.

FYI, I pushed this in.  I'm keeping an eye on the build bots.

If you spot any related problem, please confirm whether
"maint set target-non-stop off" fixes it.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4 00/18] All-stop on top of non-stop
  2015-08-07 16:58 ` [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
@ 2015-08-12 18:32   ` Joel Brobecker
  2015-08-12 19:05     ` Pedro Alves
  2015-08-12 19:39     ` Luis Machado
  0 siblings, 2 replies; 40+ messages in thread
From: Joel Brobecker @ 2015-08-12 18:32 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1394 bytes --]

Hi Pedro,

On Fri, Aug 07, 2015 at 05:58:37PM +0100, Pedro Alves wrote:
> On 05/22/2015 12:18 AM, Pedro Alves wrote:
> > v3: https://sourceware.org/ml/gdb-patches/2015-04/msg00662.html
> > v2: https://sourceware.org/ml/gdb-patches/2015-04/msg00198.html
> > v1: https://sourceware.org/ml/gdb-patches/2015-04/msg00073.html
> > 
> > Compared to v3, a set of minor changes accumulated, to address review
> > comments and discussions (i.e., no major functional/design changes),
> > plus fixes to a patch that touched all targets (that I noticed
> > converted a couple wrong).
> > 
> > I believe I addressed all review comments thus far.  Barring comments,
> > I'd like to push this in, and expose it to the build bots.
> 
> FYI, I pushed this in.  I'm keeping an eye on the build bots.
> 
> If you spot any related problem, please confirm whether
> "maint set target-non-stop off" fixes it.

This uncovered what I think is a latent bug in the "how-did-we-never-
see-this-before" category. Does this patch look OK to you?

gdb/ChangeLog:

        * amd64-tdep.c (amd64_displaced_step_fixup): Fix the mask used to
        compute RETADDR.

gdb/testsuite/ChangeLog:

        * gdb.base/dso2dso-impl.c, gdb.base/dso2dso-impl.h,
        gdb.base/dso2dso-pck.c, gdb.base/dso2dso-pck.h, gdb.base/dso2dso.c,
        gdb.base/dso2dso.exp: New files.

Tested on x86_64-linux, no regression.

Thanks!
-- 
Joel

[-- Attachment #2: 0001-amd64-Invalid-return-address-after-displaced-steppin.patch --]
[-- Type: text/x-diff, Size: 12805 bytes --]

From 63cf63b54b7b303b07dcc3ab5206fef8b3bde418 Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Wed, 12 Aug 2015 09:33:19 -0700
Subject: [PATCH] [amd64] Invalid return address after displaced stepping

Making all-stop run on top of non-stop caused a small regression
in behavior. This was observed on x86_64-linux. The attached testcase
is in C whereas the investigation was done with an Ada program,
but it's the same scenario, and using a C testcase allows wider testing.
Basically: I am debugging a single-threaded program, and currently
stopped inside a function provided by a shared-library, at a line
calling a subprogram provided by a second shared library, and trying
to "next" over that function call.

Before we changed the default all-stop behavior, we had:

    7             Impl_Initialize;  -- Stop here and try "next" over this line
    (gdb) n
    8             return 5;  <<-- OK

But now, "next" just stops much earlier:

    (gdb) n
    0x00007ffff7bd8560 in impl.initialize@plt () from /[...]/lib/libpck.so

What happens is that next stops at a call instruction, which calls
the function's PLT, and GDB fails to notice that the inferior stepped
into a subroutine, and so decides that we're done. We can see another
symptom of the same issue by looking at the backtrace at the point
GDB stopped:

    (gdb) bt
    #0  0x00007ffff7bd8560 in impl.initialize@plt ()
       from /[...]/lib/libpck.so
    #1  0x00000000f7bd86f9 in ?? ()
    #2  0x00007fffffffdf50 in ?? ()
    #3  0x0000000000401893 in a () at /[...]/a.adb:7
    Backtrace stopped: frame did not save the PC

With a functioning GDB, the backtrace looks like the following instead:

    #0  0x00007ffff7bd8560 in impl.initialize@plt ()
       from /[...]/lib/libpck.so
    #1  0x00007ffff7bd86f9 in sub () at /[...]/pck.adb:7
    #2  0x0000000000401893 in a () at /[...]/a.adb:7

Note how, for frame #1, the address looks quite similar, except
for the high-order bits not being set:

    #1  0x00007ffff7bd86f9 in sub () at /[...]/pck.adb:7   <<<--  OK
    #1  0x00000000f7bd86f9 in ?? ()                        <<<--  WRONG
              ^^^^
              ||||
              Wrong

Investigating this further led me to displaced stepping.
As we are "next"-ing from a location where a breakpoint is inserted,
we need to step out of it, and since we're on non-stop mode, we need
to do it using displaced stepping. And looking at
amd64-tdep.c:amd64_displaced_step_fixup, I found the code that handles
the return address:

    regcache_cooked_read_unsigned (regs, AMD64_RSP_REGNUM, &rsp);
    retaddr = read_memory_unsigned_integer (rsp, retaddr_len, byte_order);
    retaddr = (retaddr - insn_offset) & 0xffffffffUL;

The mask used to compute retaddr looks wrong to me, keeping only
4 bytes instead of 8, and explains why the high order bits of
the backtrace are unset. What happens is that, after the displaced
stepping has completed, GDB restores that return address at the location
where the program expects it.  But because the top half bits of
the address have been masked out, the return address is now invalid.
The incorrect behavior of the "next" command and the backtrace at
that location are the first symptoms of that.  Another symptom is
that this actually alters the behavior of the program, where a "cont"
from there soon leads to a SEGV when the inferior tries to jump back
to that incorrect return address:

    (gdb) c
    Continuing.

    Program received signal SIGSEGV, Segmentation fault.
    0x00000000f7bd86f9 in ?? ()
    ^^^^^^^^^^^^^^^^^^

This patch fixes the issue by using a mask that seems more appropriate
for this architecture.

gdb/ChangeLog:

        * amd64-tdep.c (amd64_displaced_step_fixup): Fix the mask used to
        compute RETADDR.

gdb/testsuite/ChangeLog:

        * gdb.base/dso2dso-impl.c, gdb.base/dso2dso-impl.h,
        gdb.base/dso2dso-pck.c, gdb.base/dso2dso-pck.h, gdb.base/dso2dso.c,
        gdb.base/dso2dso.exp: New files.

Tested on x86_64-linux, no regression.
---
 gdb/amd64-tdep.c                      |  2 +-
 gdb/testsuite/gdb.base/dso2dso-impl.c | 24 +++++++++++++
 gdb/testsuite/gdb.base/dso2dso-impl.h | 23 +++++++++++++
 gdb/testsuite/gdb.base/dso2dso-pck.c  | 26 +++++++++++++++
 gdb/testsuite/gdb.base/dso2dso-pck.h  | 23 +++++++++++++
 gdb/testsuite/gdb.base/dso2dso.c      | 25 ++++++++++++++
 gdb/testsuite/gdb.base/dso2dso.exp    | 63 +++++++++++++++++++++++++++++++++++
 7 files changed, 185 insertions(+), 1 deletion(-)
 create mode 100644 gdb/testsuite/gdb.base/dso2dso-impl.c
 create mode 100644 gdb/testsuite/gdb.base/dso2dso-impl.h
 create mode 100644 gdb/testsuite/gdb.base/dso2dso-pck.c
 create mode 100644 gdb/testsuite/gdb.base/dso2dso-pck.h
 create mode 100644 gdb/testsuite/gdb.base/dso2dso.c
 create mode 100644 gdb/testsuite/gdb.base/dso2dso.exp

diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index 5e63b5e..5b4a8f4 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -1662,7 +1662,7 @@ amd64_displaced_step_fixup (struct gdbarch *gdbarch,
 
       regcache_cooked_read_unsigned (regs, AMD64_RSP_REGNUM, &rsp);
       retaddr = read_memory_unsigned_integer (rsp, retaddr_len, byte_order);
-      retaddr = (retaddr - insn_offset) & 0xffffffffUL;
+      retaddr = (retaddr - insn_offset) & 0xffffffffffffffffUL;
       write_memory_unsigned_integer (rsp, retaddr_len, byte_order, retaddr);
 
       if (debug_displaced)
diff --git a/gdb/testsuite/gdb.base/dso2dso-impl.c b/gdb/testsuite/gdb.base/dso2dso-impl.c
new file mode 100644
index 0000000..0b34aa9
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dso2dso-impl.c
@@ -0,0 +1,24 @@
+/* Copyright 2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 <http://www.gnu.org/licenses/>.  */
+
+#include "dso2dso-impl.h"
+
+void
+impl__initialize (void)
+{
+  /* Do nothing.  */
+}
diff --git a/gdb/testsuite/gdb.base/dso2dso-impl.h b/gdb/testsuite/gdb.base/dso2dso-impl.h
new file mode 100644
index 0000000..58b9d13
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dso2dso-impl.h
@@ -0,0 +1,23 @@
+/* Copyright 2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 <http://www.gnu.org/licenses/>.  */
+
+#ifndef DSO2DSO_IMPL_H
+#define DSO2DSO_IMPL_H
+
+extern void impl__initialize (void);
+
+#endif
diff --git a/gdb/testsuite/gdb.base/dso2dso-pck.c b/gdb/testsuite/gdb.base/dso2dso-pck.c
new file mode 100644
index 0000000..a6a38f9
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dso2dso-pck.c
@@ -0,0 +1,26 @@
+/* Copyright 2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 <http://www.gnu.org/licenses/>.  */
+
+#include "dso2dso-pck.h"
+#include "dso2dso-impl.h"
+
+int
+sub (void)
+{
+  impl__initialize ();
+  return 5;
+}
diff --git a/gdb/testsuite/gdb.base/dso2dso-pck.h b/gdb/testsuite/gdb.base/dso2dso-pck.h
new file mode 100644
index 0000000..11e8643
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dso2dso-pck.h
@@ -0,0 +1,23 @@
+/* Copyright 2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 <http://www.gnu.org/licenses/>.  */
+
+#ifndef DSO2DSO_PCK_H
+#define DSO2DSO_PCK_H
+
+extern int sub (void);
+
+#endif
diff --git a/gdb/testsuite/gdb.base/dso2dso.c b/gdb/testsuite/gdb.base/dso2dso.c
new file mode 100644
index 0000000..a085c00
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dso2dso.c
@@ -0,0 +1,25 @@
+/* Copyright 2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 <http://www.gnu.org/licenses/>.  */
+
+#include "dso2dso-pck.h"
+
+int
+main (void)
+{
+  int ignored = sub ();
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/dso2dso.exp b/gdb/testsuite/gdb.base/dso2dso.exp
new file mode 100644
index 0000000..3d08b79
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dso2dso.exp
@@ -0,0 +1,63 @@
+# Copyright 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 <http://www.gnu.org/licenses/>.
+
+if { [skip_shlib_tests] } {
+    return 0
+}
+
+standard_testfile
+
+set output_dir [standard_output_file {}]
+
+set libimpl $testfile-impl
+set srcfile_libimpl $srcdir/$subdir/$libimpl.c
+set binfile_libimpl [standard_output_file $libimpl.so]
+
+set libpck $testfile-pck
+set srcfile_libpck $srcdir/$subdir/$libpck.c
+set binfile_libpck [standard_output_file $libpck.so]
+
+if { [gdb_compile_shlib $srcfile_libimpl $binfile_libimpl \
+	[list debug additional_flags=-fPIC]] != "" } {
+  untested "Could not compile $binfile_libimpl."
+  return -1
+}
+
+if { [gdb_compile_shlib $srcfile_libpck $binfile_libpck \
+	[list debug additional_flags=-fPIC]] != "" } {
+  untested "Could not compile $binfile_libpck."
+  return -1
+}
+
+if { [gdb_compile $srcdir/$subdir/$srcfile $binfile executable \
+	[list debug shlib=$binfile_libimpl shlib=$binfile_libpck]] != "" } {
+  return -1
+}
+
+clean_restart $binfile
+
+if { ![runto_main] } {
+  return -1
+}
+
+set bp_location [gdb_get_line_number "impl__initialize" $srcfile_libpck]
+gdb_breakpoint ${srcfile_libpck}:${bp_location}
+
+gdb_continue_to_breakpoint "at call to impl__initialize" \
+    ".*impl__initialize ().*"
+
+gdb_test "next" \
+    ".*return 5;.*" \
+    "next over call to impl__initialize"
-- 
2.1.4


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4 00/18] All-stop on top of non-stop
  2015-08-12 18:32   ` Joel Brobecker
@ 2015-08-12 19:05     ` Pedro Alves
  2015-08-12 20:26       ` Joel Brobecker
  2015-08-12 19:39     ` Luis Machado
  1 sibling, 1 reply; 40+ messages in thread
From: Pedro Alves @ 2015-08-12 19:05 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

On 08/12/2015 07:32 PM, Joel Brobecker wrote:

> This uncovered what I think is a latent bug in the "how-did-we-never-
> see-this-before" category. 

Wow!  Indeed.  Many thanks for tracking this down and fixing it.

A couple minor comments below, but this looks good to me.

> Does this patch look OK to you?

>         * gdb.base/dso2dso-impl.c, gdb.base/dso2dso-impl.h,
>         gdb.base/dso2dso-pck.c, gdb.base/dso2dso-pck.h, gdb.base/dso2dso.c,
>         gdb.base/dso2dso.exp: New files.
> 

Nit: the "pck" and "impl"s here confuse me -- I guess they meant something
in the original test?  Do they still have any meaning here?  I'd suggest
renaming to dso2dso-dso1.c, dso2dso-dso2.c, and then
 sub() -> sub1(), impl__initialize() -> sub2().  That way, it should
be clearer that a function in dso1 calls a function in dso2.

> diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
> index 5e63b5e..5b4a8f4 100644
> --- a/gdb/amd64-tdep.c
> +++ b/gdb/amd64-tdep.c
> @@ -1662,7 +1662,7 @@ amd64_displaced_step_fixup (struct gdbarch *gdbarch,
>  
>        regcache_cooked_read_unsigned (regs, AMD64_RSP_REGNUM, &rsp);
>        retaddr = read_memory_unsigned_integer (rsp, retaddr_len, byte_order);
> -      retaddr = (retaddr - insn_offset) & 0xffffffffUL;
> +      retaddr = (retaddr - insn_offset) & 0xffffffffffffffffUL;

I think this should use the ULL suffix now.

> +
> +if { [gdb_compile_shlib $srcfile_libimpl $binfile_libimpl \
> +	[list debug additional_flags=-fPIC]] != "" } {
> +  untested "Could not compile $binfile_libimpl."
> +  return -1
> +}
> +
> +if { [gdb_compile_shlib $srcfile_libpck $binfile_libpck \
> +	[list debug additional_flags=-fPIC]] != "" } {
> +  untested "Could not compile $binfile_libpck."
> +  return -1
> +}
> +
> +if { [gdb_compile $srcdir/$subdir/$srcfile $binfile executable \
> +	[list debug shlib=$binfile_libimpl shlib=$binfile_libpck]] != "" } {
> +  return -1
> +}
> +
> +clean_restart $binfile
> +

I think a

 gdb_load_shlibs $binfile_libimpl $binfile_libpck

is missing here.

> +if { ![runto_main] } {
> +  return -1
> +}
> +
> +set bp_location [gdb_get_line_number "impl__initialize" $srcfile_libpck]
> +gdb_breakpoint ${srcfile_libpck}:${bp_location}
> +
> +gdb_continue_to_breakpoint "at call to impl__initialize" \
> +    ".*impl__initialize ().*"
> +
> +gdb_test "next" \
> +    ".*return 5;.*" \
> +    "next over call to impl__initialize"
> -- 2.1.4

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4 00/18] All-stop on top of non-stop
  2015-08-12 18:32   ` Joel Brobecker
  2015-08-12 19:05     ` Pedro Alves
@ 2015-08-12 19:39     ` Luis Machado
  2015-08-12 19:51       ` Sergio Durigan Junior
  2015-08-12 19:59       ` Joel Brobecker
  1 sibling, 2 replies; 40+ messages in thread
From: Luis Machado @ 2015-08-12 19:39 UTC (permalink / raw)
  To: Joel Brobecker, Pedro Alves; +Cc: gdb-patches

Hi Joel,

On 08/12/2015 03:32 PM, Joel Brobecker wrote:
> Hi Pedro,
>
> On Fri, Aug 07, 2015 at 05:58:37PM +0100, Pedro Alves wrote:
>> On 05/22/2015 12:18 AM, Pedro Alves wrote:
>>> v3: https://sourceware.org/ml/gdb-patches/2015-04/msg00662.html
>>> v2: https://sourceware.org/ml/gdb-patches/2015-04/msg00198.html
>>> v1: https://sourceware.org/ml/gdb-patches/2015-04/msg00073.html
>>>
>>> Compared to v3, a set of minor changes accumulated, to address review
>>> comments and discussions (i.e., no major functional/design changes),
>>> plus fixes to a patch that touched all targets (that I noticed
>>> converted a couple wrong).
>>>
>>> I believe I addressed all review comments thus far.  Barring comments,
>>> I'd like to push this in, and expose it to the build bots.
>>
>> FYI, I pushed this in.  I'm keeping an eye on the build bots.
>>
>> If you spot any related problem, please confirm whether
>> "maint set target-non-stop off" fixes it.
>
> This uncovered what I think is a latent bug in the "how-did-we-never-
> see-this-before" category. Does this patch look OK to you?
>
> gdb/ChangeLog:
>
>          * amd64-tdep.c (amd64_displaced_step_fixup): Fix the mask used to
>          compute RETADDR.
>
> gdb/testsuite/ChangeLog:
>
>          * gdb.base/dso2dso-impl.c, gdb.base/dso2dso-impl.h,
>          gdb.base/dso2dso-pck.c, gdb.base/dso2dso-pck.h, gdb.base/dso2dso.c,
>          gdb.base/dso2dso.exp: New files.
>
> Tested on x86_64-linux, no regression.
>
> Thanks!
>

Two things about the patch. I see that the change to GDB's code is 
almost trivial, but the testcase looks quite involved.

The first thing is that one wouldn't be able to tell what the testcase 
does without looking at the commit log. dso2dso doesn't particularly 
translate to "displaced stepping instruction masking problem on amd64". 
Should we change the testcase name to something a bit more meaningful? 
Maybe document it a bit?

The second point is, should we restrict this testcase to be executed 
only for amd64? Maybe move it to gdb.arch? Unless you actually tried 
this testcase with different architectures and confirmed the testcase is 
sane there, it feels a bit iffy to add/execute this for non-amd64 targets.

In the worst case, we could have a failure due to different instruction 
scheduling schemes (or maybe even a displaced stepping bug) on non-amd64 
targets. At a minimum, we'd have a spurious PASS that wouldn't be 
meaningful for the overall test results since things never failed on 
said architecture in the first place.

Alternatively, for such a trivial fix, shouldn't we go without a testcase?

Luis

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4 00/18] All-stop on top of non-stop
  2015-08-12 19:39     ` Luis Machado
@ 2015-08-12 19:51       ` Sergio Durigan Junior
  2015-08-12 19:59       ` Joel Brobecker
  1 sibling, 0 replies; 40+ messages in thread
From: Sergio Durigan Junior @ 2015-08-12 19:51 UTC (permalink / raw)
  To: Luis Machado; +Cc: Joel Brobecker, Pedro Alves, gdb-patches

On Wednesday, August 12 2015, Luis Machado wrote:

> Alternatively, for such a trivial fix, shouldn't we go without a testcase?

Not commenting on the other points, but I don't think we should.  No
matter how trivial is the fix, a testcase is always welcome.  Of course,
I do agree about your suggestion to document better what the testcase
does.

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4 00/18] All-stop on top of non-stop
  2015-08-12 19:39     ` Luis Machado
  2015-08-12 19:51       ` Sergio Durigan Junior
@ 2015-08-12 19:59       ` Joel Brobecker
  2015-08-12 20:18         ` Luis Machado
  1 sibling, 1 reply; 40+ messages in thread
From: Joel Brobecker @ 2015-08-12 19:59 UTC (permalink / raw)
  To: Luis Machado; +Cc: Pedro Alves, gdb-patches

> Two things about the patch. I see that the change to GDB's code is almost
> trivial, but the testcase looks quite involved.
> 
> The first thing is that one wouldn't be able to tell what the testcase does
> without looking at the commit log. dso2dso doesn't particularly translate to
> "displaced stepping instruction masking problem on amd64". Should we change
> the testcase name to something a bit more meaningful? Maybe document it a
> bit?
> 
> The second point is, should we restrict this testcase to be executed only
> for amd64? Maybe move it to gdb.arch? Unless you actually tried this
> testcase with different architectures and confirmed the testcase is sane
> there, it feels a bit iffy to add/execute this for non-amd64 targets.
> 
> In the worst case, we could have a failure due to different instruction
> scheduling schemes (or maybe even a displaced stepping bug) on non-amd64
> targets. At a minimum, we'd have a spurious PASS that wouldn't be meaningful
> for the overall test results since things never failed on said architecture
> in the first place.
> 
> Alternatively, for such a trivial fix, shouldn't we go without a testcase?

Some good points. To me, the purpose of the test is to verify that
stepping from some code in one DSO over a call to a function in another
DSO, is working on all platforms that support shared libraries. That's
the main purpose of the test. If, one day, the implementation changes
so that displaced stepping is no longer necessary, then what matters
at the user level is that this testcase continues to behave the same.

Even if you wanted a gdb.arch test that verified this specific bug,
you'd have to find a way for the test to load at an address that's
high enough that the mask starts causing problems. I don't think
that's very easy, and I'm not sure it's worth our time.

Regarding the complexity of the test, I think we need to try it and
see.  At AdaCore, we run the equivalent Ada testcase nightly on Linux
(x86, x86_64 and ppc), Windows (x86 and x86_64), Solaris (sparc) and
Darwin (x86_64), and it passes everywhere. It passes with GDBserver
too. My take would be that we'd be fixing trivial errors in the testcase
itself, and just accept the failures on platforms where it reveals
a bona fide issue, as we've beeing doing with all the other tests.

-- 
Joel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4 00/18] All-stop on top of non-stop
  2015-08-12 19:59       ` Joel Brobecker
@ 2015-08-12 20:18         ` Luis Machado
  2015-08-12 20:33           ` Joel Brobecker
  0 siblings, 1 reply; 40+ messages in thread
From: Luis Machado @ 2015-08-12 20:18 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Pedro Alves, gdb-patches

On 08/12/2015 04:59 PM, Joel Brobecker wrote:
>> Two things about the patch. I see that the change to GDB's code is almost
>> trivial, but the testcase looks quite involved.
>>
>> The first thing is that one wouldn't be able to tell what the testcase does
>> without looking at the commit log. dso2dso doesn't particularly translate to
>> "displaced stepping instruction masking problem on amd64". Should we change
>> the testcase name to something a bit more meaningful? Maybe document it a
>> bit?
>>
>> The second point is, should we restrict this testcase to be executed only
>> for amd64? Maybe move it to gdb.arch? Unless you actually tried this
>> testcase with different architectures and confirmed the testcase is sane
>> there, it feels a bit iffy to add/execute this for non-amd64 targets.
>>
>> In the worst case, we could have a failure due to different instruction
>> scheduling schemes (or maybe even a displaced stepping bug) on non-amd64
>> targets. At a minimum, we'd have a spurious PASS that wouldn't be meaningful
>> for the overall test results since things never failed on said architecture
>> in the first place.
>>
>> Alternatively, for such a trivial fix, shouldn't we go without a testcase?
>
> Some good points. To me, the purpose of the test is to verify that
> stepping from some code in one DSO over a call to a function in another
> DSO, is working on all platforms that support shared libraries. That's
> the main purpose of the test. If, one day, the implementation changes
> so that displaced stepping is no longer necessary, then what matters
> at the user level is that this testcase continues to behave the same.

Ok. So i think i misunderstood the purpose of the testcase there. In 
reality the testcase is not testing the fix itself, but rather 
introducing a new test not related to the problem, except in the amd64 
architecture, where it really tests the problem.

It just confused me that the test is generic for other non-amd64 
architectures and specific to the amd64 problem you saw.

I'd expect a generic solib test to be included in one of our shared 
library tests, but then you'd have to shape it in a way that would 
exercise your displaced stepping problem.

>
> Even if you wanted a gdb.arch test that verified this specific bug,
> you'd have to find a way for the test to load at an address that's
> high enough that the mask starts causing problems. I don't think
> that's very easy, and I'm not sure it's worth our time.
>
> Regarding the complexity of the test, I think we need to try it and
> see.  At AdaCore, we run the equivalent Ada testcase nightly on Linux
> (x86, x86_64 and ppc), Windows (x86 and x86_64), Solaris (sparc) and
> Darwin (x86_64), and it passes everywhere. It passes with GDBserver
> too. My take would be that we'd be fixing trivial errors in the testcase
> itself, and just accept the failures on platforms where it reveals
> a bona fide issue, as we've beeing doing with all the other tests.

It is not a big deal. In recent times i've been seeing a number of 
testcases that shouldn't be generally executed for all architectures. 
That ends up causing spurious failures and bringing the signal/noise 
ratio of the testsuite down for the affect architectures (usually not 
x86 or Linux).

I see your targets are mostly x86. I can give it a try on a few more 
(powerpc, mips, arm, nios) and let you know what i see. How does that sound?

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4 00/18] All-stop on top of non-stop
  2015-08-12 19:05     ` Pedro Alves
@ 2015-08-12 20:26       ` Joel Brobecker
  2015-08-12 20:31         ` Luis Machado
                           ` (2 more replies)
  0 siblings, 3 replies; 40+ messages in thread
From: Joel Brobecker @ 2015-08-12 20:26 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Luis Machado, Sergio Durigan Junior

[-- Attachment #1: Type: text/plain, Size: 1007 bytes --]

> > This uncovered what I think is a latent bug in the "how-did-we-never-
> > see-this-before" category. 
> 
> Wow!  Indeed.  Many thanks for tracking this down and fixing it.
> 
> A couple minor comments below, but this looks good to me.

And thanks for the super-quick review.

Attached is what I ended up pushing. It should address all your
comments, and also add a comment in the testcase script to explain
its purpose. If this isn't sufficient for Luis and Sergio, then
we can try to find other solutions (including renaming the testcase,
if necessary).

gdb/ChangeLog:

        * amd64-tdep.c (amd64_displaced_step_fixup): Fix the mask used to
        compute RETADDR.

gdb/testsuite/ChangeLog:

        * gdb.base/dso2dso-dso2.c, gdb.base/dso2dso-dso2.h,
        gdb.base/dso2dso-dso1.c, gdb.base/dso2dso-dso1.h, gdb.base/dso2dso.c,
        gdb.base/dso2dso.exp: New files.

Re-tested on x86_64-linux.

One last thought: Should we put it in GDB 7.10? Seems fairly safe,
but is it worth it?

-- 
Joel

[-- Attachment #2: 0001-amd64-Invalid-return-address-after-displaced-steppin.patch --]
[-- Type: text/x-diff, Size: 12976 bytes --]

From a5c001e82a96328ae097fecb7a61c7f49636b3ff Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Wed, 12 Aug 2015 09:33:19 -0700
Subject: [PATCH] [amd64] Invalid return address after displaced stepping

Making all-stop run on top of non-stop caused a small regression
in behavior. This was observed on x86_64-linux. The attached testcase
is in C whereas the investigation was done with an Ada program,
but it's the same scenario, and using a C testcase allows wider testing.
Basically: I am debugging a single-threaded program, and currently
stopped inside a function provided by a shared-library, at a line
calling a subprogram provided by a second shared library, and trying
to "next" over that function call.

Before we changed the default all-stop behavior, we had:

    7             Impl_Initialize;  -- Stop here and try "next" over this line
    (gdb) n
    8             return 5;  <<-- OK

But now, "next" just stops much earlier:

    (gdb) n
    0x00007ffff7bd8560 in impl.initialize@plt () from /[...]/lib/libpck.so

What happens is that next stops at a call instruction, which calls
the function's PLT, and GDB fails to notice that the inferior stepped
into a subroutine, and so decides that we're done. We can see another
symptom of the same issue by looking at the backtrace at the point
GDB stopped:

    (gdb) bt
    #0  0x00007ffff7bd8560 in impl.initialize@plt ()
       from /[...]/lib/libpck.so
    #1  0x00000000f7bd86f9 in ?? ()
    #2  0x00007fffffffdf50 in ?? ()
    #3  0x0000000000401893 in a () at /[...]/a.adb:7
    Backtrace stopped: frame did not save the PC

With a functioning GDB, the backtrace looks like the following instead:

    #0  0x00007ffff7bd8560 in impl.initialize@plt ()
       from /[...]/lib/libpck.so
    #1  0x00007ffff7bd86f9 in sub () at /[...]/pck.adb:7
    #2  0x0000000000401893 in a () at /[...]/a.adb:7

Note how, for frame #1, the address looks quite similar, except
for the high-order bits not being set:

    #1  0x00007ffff7bd86f9 in sub () at /[...]/pck.adb:7   <<<--  OK
    #1  0x00000000f7bd86f9 in ?? ()                        <<<--  WRONG
              ^^^^
              ||||
              Wrong

Investigating this further led me to displaced stepping.
As we are "next"-ing from a location where a breakpoint is inserted,
we need to step out of it, and since we're on non-stop mode, we need
to do it using displaced stepping. And looking at
amd64-tdep.c:amd64_displaced_step_fixup, I found the code that handles
the return address:

    regcache_cooked_read_unsigned (regs, AMD64_RSP_REGNUM, &rsp);
    retaddr = read_memory_unsigned_integer (rsp, retaddr_len, byte_order);
    retaddr = (retaddr - insn_offset) & 0xffffffffUL;

The mask used to compute retaddr looks wrong to me, keeping only
4 bytes instead of 8, and explains why the high order bits of
the backtrace are unset. What happens is that, after the displaced
stepping has completed, GDB restores that return address at the location
where the program expects it.  But because the top half bits of
the address have been masked out, the return address is now invalid.
The incorrect behavior of the "next" command and the backtrace at
that location are the first symptoms of that.  Another symptom is
that this actually alters the behavior of the program, where a "cont"
from there soon leads to a SEGV when the inferior tries to jump back
to that incorrect return address:

    (gdb) c
    Continuing.

    Program received signal SIGSEGV, Segmentation fault.
    0x00000000f7bd86f9 in ?? ()
    ^^^^^^^^^^^^^^^^^^

This patch fixes the issue by using a mask that seems more appropriate
for this architecture.

gdb/ChangeLog:

        * amd64-tdep.c (amd64_displaced_step_fixup): Fix the mask used to
        compute RETADDR.

gdb/testsuite/ChangeLog:

        * gdb.base/dso2dso-dso2.c, gdb.base/dso2dso-dso2.h,
        gdb.base/dso2dso-dso1.c, gdb.base/dso2dso-dso1.h, gdb.base/dso2dso.c,
        gdb.base/dso2dso.exp: New files.

Tested on x86_64-linux, no regression.
---
 gdb/amd64-tdep.c                      |  2 +-
 gdb/testsuite/gdb.base/dso2dso-dso1.c | 26 ++++++++++++++
 gdb/testsuite/gdb.base/dso2dso-dso1.h | 23 ++++++++++++
 gdb/testsuite/gdb.base/dso2dso-dso2.c | 24 +++++++++++++
 gdb/testsuite/gdb.base/dso2dso-dso2.h | 23 ++++++++++++
 gdb/testsuite/gdb.base/dso2dso.c      | 25 +++++++++++++
 gdb/testsuite/gdb.base/dso2dso.exp    | 68 +++++++++++++++++++++++++++++++++++
 7 files changed, 190 insertions(+), 1 deletion(-)
 create mode 100644 gdb/testsuite/gdb.base/dso2dso-dso1.c
 create mode 100644 gdb/testsuite/gdb.base/dso2dso-dso1.h
 create mode 100644 gdb/testsuite/gdb.base/dso2dso-dso2.c
 create mode 100644 gdb/testsuite/gdb.base/dso2dso-dso2.h
 create mode 100644 gdb/testsuite/gdb.base/dso2dso.c
 create mode 100644 gdb/testsuite/gdb.base/dso2dso.exp

diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index 5e63b5e..a672cde 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -1662,7 +1662,7 @@ amd64_displaced_step_fixup (struct gdbarch *gdbarch,
 
       regcache_cooked_read_unsigned (regs, AMD64_RSP_REGNUM, &rsp);
       retaddr = read_memory_unsigned_integer (rsp, retaddr_len, byte_order);
-      retaddr = (retaddr - insn_offset) & 0xffffffffUL;
+      retaddr = (retaddr - insn_offset) & 0xffffffffffffffffULL;
       write_memory_unsigned_integer (rsp, retaddr_len, byte_order, retaddr);
 
       if (debug_displaced)
diff --git a/gdb/testsuite/gdb.base/dso2dso-dso1.c b/gdb/testsuite/gdb.base/dso2dso-dso1.c
new file mode 100644
index 0000000..a360e20
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dso2dso-dso1.c
@@ -0,0 +1,26 @@
+/* Copyright 2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 <http://www.gnu.org/licenses/>.  */
+
+#include "dso2dso-dso1.h"
+#include "dso2dso-dso2.h"
+
+int
+sub1 (void)
+{
+  sub2 ();  /* STOP HERE.  */
+  return 5;
+}
diff --git a/gdb/testsuite/gdb.base/dso2dso-dso1.h b/gdb/testsuite/gdb.base/dso2dso-dso1.h
new file mode 100644
index 0000000..2423360
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dso2dso-dso1.h
@@ -0,0 +1,23 @@
+/* Copyright 2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 <http://www.gnu.org/licenses/>.  */
+
+#ifndef DSO2DSO_DSO1_H
+#define DSO2DSO_DSO1_H
+
+extern int sub1 (void);
+
+#endif
diff --git a/gdb/testsuite/gdb.base/dso2dso-dso2.c b/gdb/testsuite/gdb.base/dso2dso-dso2.c
new file mode 100644
index 0000000..14de6a8
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dso2dso-dso2.c
@@ -0,0 +1,24 @@
+/* Copyright 2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 <http://www.gnu.org/licenses/>.  */
+
+#include "dso2dso-dso2.h"
+
+void
+sub2 (void)
+{
+  /* Do nothing.  */
+}
diff --git a/gdb/testsuite/gdb.base/dso2dso-dso2.h b/gdb/testsuite/gdb.base/dso2dso-dso2.h
new file mode 100644
index 0000000..e33ca0a
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dso2dso-dso2.h
@@ -0,0 +1,23 @@
+/* Copyright 2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 <http://www.gnu.org/licenses/>.  */
+
+#ifndef DSO2DSO_DSO2_H
+#define DSO2DSO_DSO2_H
+
+extern void sub2 (void);
+
+#endif
diff --git a/gdb/testsuite/gdb.base/dso2dso.c b/gdb/testsuite/gdb.base/dso2dso.c
new file mode 100644
index 0000000..563bd96
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dso2dso.c
@@ -0,0 +1,25 @@
+/* Copyright 2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 <http://www.gnu.org/licenses/>.  */
+
+#include "dso2dso-dso1.h"
+
+int
+main (void)
+{
+  int ignored = sub1 ();
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/dso2dso.exp b/gdb/testsuite/gdb.base/dso2dso.exp
new file mode 100644
index 0000000..b604012
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dso2dso.exp
@@ -0,0 +1,68 @@
+# Copyright 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 <http://www.gnu.org/licenses/>.
+
+if { [skip_shlib_tests] } {
+    return 0
+}
+
+standard_testfile
+
+set output_dir [standard_output_file {}]
+
+set libdso2 $testfile-dso2
+set srcfile_libdso2 $srcdir/$subdir/$libdso2.c
+set binfile_libdso2 [standard_output_file $libdso2.so]
+
+set libdso1 $testfile-dso1
+set srcfile_libdso1 $srcdir/$subdir/$libdso1.c
+set binfile_libdso1 [standard_output_file $libdso1.so]
+
+if { [gdb_compile_shlib $srcfile_libdso2 $binfile_libdso2 \
+	[list debug additional_flags=-fPIC]] != "" } {
+  untested "Could not compile $binfile_libdso2."
+  return -1
+}
+
+if { [gdb_compile_shlib $srcfile_libdso1 $binfile_libdso1 \
+	[list debug additional_flags=-fPIC]] != "" } {
+  untested "Could not compile $binfile_libdso1."
+  return -1
+}
+
+if { [gdb_compile $srcdir/$subdir/$srcfile $binfile executable \
+	[list debug shlib=$binfile_libdso2 shlib=$binfile_libdso1]] != "" } {
+  return -1
+}
+
+clean_restart $binfile
+gdb_load_shlibs $binfile_libdso2 $binfile_libdso1
+
+if { ![runto_main] } {
+  return -1
+}
+
+# Verify that we can "next" over the call to sub2 (provided by
+# libdso2) make from sub1 (provided by libdso1), and land at
+# the expected location.
+
+set bp_location [gdb_get_line_number "STOP HERE" $srcfile_libdso1]
+gdb_breakpoint ${srcfile_libdso1}:${bp_location}
+
+gdb_continue_to_breakpoint "at call to sub2" \
+    ".*sub2 ().*"
+
+gdb_test "next" \
+    ".*return 5;.*" \
+    "next over call to sub2"
-- 
2.1.4


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4 00/18] All-stop on top of non-stop
  2015-08-12 20:26       ` Joel Brobecker
@ 2015-08-12 20:31         ` Luis Machado
  2015-08-12 20:50           ` Joel Brobecker
  2015-08-13  1:46         ` [pushed] gdb.base/dso2dso.exp sometimes broken Joel Brobecker
  2015-08-13 17:27         ` [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
  2 siblings, 1 reply; 40+ messages in thread
From: Luis Machado @ 2015-08-12 20:31 UTC (permalink / raw)
  To: Joel Brobecker, Pedro Alves; +Cc: gdb-patches, Sergio Durigan Junior

On 08/12/2015 05:26 PM, Joel Brobecker wrote:
>>> This uncovered what I think is a latent bug in the "how-did-we-never-
>>> see-this-before" category.
>>
>> Wow!  Indeed.  Many thanks for tracking this down and fixing it.
>>
>> A couple minor comments below, but this looks good to me.
>
> And thanks for the super-quick review.
>
> Attached is what I ended up pushing. It should address all your
> comments, and also add a comment in the testcase script to explain
> its purpose. If this isn't sufficient for Luis and Sergio, then
> we can try to find other solutions (including renaming the testcase,
> if necessary).

My idea of a testcase comment is at the beginning of the testcase file, 
explaining what the test does and why it does it. I'd mention the amd64 
example as well, since it is part of why the test was created in the 
first place.

That should give others enough background to pursue an investigation 
about why this potentially fails for them.

My 2 cents anyway.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4 00/18] All-stop on top of non-stop
  2015-08-12 20:18         ` Luis Machado
@ 2015-08-12 20:33           ` Joel Brobecker
  2015-08-12 20:40             ` Luis Machado
  0 siblings, 1 reply; 40+ messages in thread
From: Joel Brobecker @ 2015-08-12 20:33 UTC (permalink / raw)
  To: Luis Machado; +Cc: Pedro Alves, gdb-patches

I tried to clarify the purpose of the testcase by adding a comment
inside it. Let me know if this isn't enough, and we'll try to improve.

> Ok. So i think i misunderstood the purpose of the testcase there. In reality
> the testcase is not testing the fix itself, but rather introducing a new
> test not related to the problem, except in the amd64 architecture, where it
> really tests the problem.
> 
> It just confused me that the test is generic for other non-amd64
> architectures and specific to the amd64 problem you saw.
> 
> I'd expect a generic solib test to be included in one of our shared library
> tests, but then you'd have to shape it in a way that would exercise your
> displaced stepping problem.

I understand the first paragraph, but I'm having trouble with the last
one. The testcase as I wrote it does exercise the issue being fixed
on amd64, and I verified that I get 1 FAIL without the patch. Did
I misunderstand you?

> I see your targets are mostly x86. I can give it a try on a few more
> (powerpc, mips, arm, nios) and let you know what i see. How does that sound?

Sounds good to me.

Bare in mind that the list of targets AdaCore tests on already includes
powerpc and sparc, and I forgot ARM that we also test (as a cross,
debugging via GDBserver). So I think it's fairly wide already.
Our testsuite uses a different technology than dejagnu, though, so we
might indeed get some surprises, but I think they will have more to do
with scripting than GDB: Except for the platforms that we don't test
at AdaCore, I'd expect that any error will mostly be about building
the program rather than debugging it.

-- 
Joel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4 00/18] All-stop on top of non-stop
  2015-08-12 20:33           ` Joel Brobecker
@ 2015-08-12 20:40             ` Luis Machado
  2015-08-12 20:56               ` Joel Brobecker
  0 siblings, 1 reply; 40+ messages in thread
From: Luis Machado @ 2015-08-12 20:40 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Pedro Alves, gdb-patches

On 08/12/2015 05:33 PM, Joel Brobecker wrote:
> I tried to clarify the purpose of the testcase by adding a comment
> inside it. Let me know if this isn't enough, and we'll try to improve.
>
>> Ok. So i think i misunderstood the purpose of the testcase there. In reality
>> the testcase is not testing the fix itself, but rather introducing a new
>> test not related to the problem, except in the amd64 architecture, where it
>> really tests the problem.
>>
>> It just confused me that the test is generic for other non-amd64
>> architectures and specific to the amd64 problem you saw.
>>
>> I'd expect a generic solib test to be included in one of our shared library
>> tests, but then you'd have to shape it in a way that would exercise your
>> displaced stepping problem.
>
> I understand the first paragraph, but I'm having trouble with the last
> one. The testcase as I wrote it does exercise the issue being fixed
> on amd64, and I verified that I get 1 FAIL without the patch. Did
> I misunderstand you?

I was just pointing at the fact that we already have shared library 
tests, so those could be expanded to include this inter-dso call as 
opposed to having a different set of tests like your patch did. But 
you'd need to shape it in a way that exercises your amd64 failure mode then.

In any case, i'm good with the test. I just want to give it a try to be 
sure.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4 00/18] All-stop on top of non-stop
  2015-08-12 20:31         ` Luis Machado
@ 2015-08-12 20:50           ` Joel Brobecker
  2015-08-12 21:07             ` Luis Machado
  2015-08-13 16:04             ` Pedro Alves
  0 siblings, 2 replies; 40+ messages in thread
From: Joel Brobecker @ 2015-08-12 20:50 UTC (permalink / raw)
  To: Luis Machado; +Cc: Pedro Alves, gdb-patches, Sergio Durigan Junior

[-- Attachment #1: Type: text/plain, Size: 1310 bytes --]

> My idea of a testcase comment is at the beginning of the testcase file,
> explaining what the test does and why it does it. I'd mention the amd64
> example as well, since it is part of why the test was created in the first
> place.
> 
> That should give others enough background to pursue an investigation about
> why this potentially fails for them.
> 
> My 2 cents anyway.

There is this perception that the testcase was created because
of the issue on amd64, but that's not true. The testcase was
created, albeit in AdaCore's infrastructure only, to test that
"next" in that context works as expected. Only later on did it
allow us to find another bug which actually has nothing to do
with the initial reason for creating the testcase. I hope I'm not
looking like I'm splitting hair, but I feel like there is a bit
of a misunderstanding somewhere, probably because the testcase
appears as new to the  GDB community and was combined with an
amd64-specific fix.

That being said, I propose the attached patch. I confess I'm not
super convinced about the comment on amd64, as I think it might
become one day irrelevant. But I don't mind it that much; if
it is helpful to others...

What do you think?

gdb/testsuite/ChangeLog:

        * gdb.base/dso2dso.exp: Improve the testcase's documentation.

-- 
Joel

[-- Attachment #2: 0001-gdb.base-dso2dso.exp-Improve-testcase-documentation.patch --]
[-- Type: text/x-diff, Size: 1716 bytes --]

From bbb505f2f822997b4285c61cede194fe2617b295 Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Wed, 12 Aug 2015 13:40:54 -0700
Subject: [PATCH] gdb.base/dso2dso.exp: Improve testcase documentation.

gdb/testsuite/ChangeLog:

        * gdb.base/dso2dso.exp: Improve the testcase's documentation.
---
 gdb/testsuite/gdb.base/dso2dso.exp | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/gdb/testsuite/gdb.base/dso2dso.exp b/gdb/testsuite/gdb.base/dso2dso.exp
index b604012..16eb1f3 100644
--- a/gdb/testsuite/gdb.base/dso2dso.exp
+++ b/gdb/testsuite/gdb.base/dso2dso.exp
@@ -13,6 +13,16 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+# The purpose of that testcase is to verify that we can "next" over
+# a call to a function provided by one shared library made from another
+# shared library, and that GDB stops at the expected location. In this
+# case, the call is made from sub1 (provided by libdso1) and we are
+# calling sub2 (provided by libdso2).
+#
+# Note that, while this is not the main purpose of this testcase, it
+# also happens to exercise an issue with displaced stepping on amd64
+# when libdso1 is mapped at an address greater than 0xffffffff.
+
 if { [skip_shlib_tests] } {
     return 0
 }
@@ -53,10 +63,6 @@ if { ![runto_main] } {
   return -1
 }
 
-# Verify that we can "next" over the call to sub2 (provided by
-# libdso2) make from sub1 (provided by libdso1), and land at
-# the expected location.
-
 set bp_location [gdb_get_line_number "STOP HERE" $srcfile_libdso1]
 gdb_breakpoint ${srcfile_libdso1}:${bp_location}
 
-- 
2.1.4


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4 00/18] All-stop on top of non-stop
  2015-08-12 20:40             ` Luis Machado
@ 2015-08-12 20:56               ` Joel Brobecker
  0 siblings, 0 replies; 40+ messages in thread
From: Joel Brobecker @ 2015-08-12 20:56 UTC (permalink / raw)
  To: Luis Machado; +Cc: Pedro Alves, gdb-patches

> I was just pointing at the fact that we already have shared library tests,
> so those could be expanded to include this inter-dso call as opposed to
> having a different set of tests like your patch did. But you'd need to shape
> it in a way that exercises your amd64 failure mode then.

Ah, OK!

Speaking in general terms and for myself, I usually prefer to create new
testcases rather than piggy-back on existing ones, because I find it
simpler to do, and I also find it simpler to be certain that I'm not
altering the older testcases in a way that some tests are no longer
doing what they are supposed to do. And finally, it makes it easier to
investigate regressions, because the testcase is usually simpler that
way. Have you tried debugging a testcase where you have about 250 tests
before the failure, and you're not sure what's relevant and what is not?
;-)

-- 
Joel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4 00/18] All-stop on top of non-stop
  2015-08-12 20:50           ` Joel Brobecker
@ 2015-08-12 21:07             ` Luis Machado
  2015-08-13 16:04             ` Pedro Alves
  1 sibling, 0 replies; 40+ messages in thread
From: Luis Machado @ 2015-08-12 21:07 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Pedro Alves, gdb-patches, Sergio Durigan Junior

On 08/12/2015 05:50 PM, Joel Brobecker wrote:
>> My idea of a testcase comment is at the beginning of the testcase file,
>> explaining what the test does and why it does it. I'd mention the amd64
>> example as well, since it is part of why the test was created in the first
>> place.
>>
>> That should give others enough background to pursue an investigation about
>> why this potentially fails for them.
>>
>> My 2 cents anyway.
>
> There is this perception that the testcase was created because
> of the issue on amd64, but that's not true. The testcase was
> created, albeit in AdaCore's infrastructure only, to test that
> "next" in that context works as expected. Only later on did it
> allow us to find another bug which actually has nothing to do
> with the initial reason for creating the testcase. I hope I'm not
> looking like I'm splitting hair, but I feel like there is a bit
> of a misunderstanding somewhere, probably because the testcase
> appears as new to the  GDB community and was combined with an
> amd64-specific fix.
>

What caused confusion was the fact that the test was sent together with 
a fix, which seemed to imply it was a fix-specific test as opposed to a 
testcase-less fix and a generic new testcase in the same patch.

> That being said, I propose the attached patch. I confess I'm not
> super convinced about the comment on amd64, as I think it might
> become one day irrelevant. But I don't mind it that much; if
> it is helpful to others...

The description looks good. Feel free to drop the amd64 reference if you 
think it is not worth it. I don't have a strong opinion on it.

It just felt like the testcase needed a bit more information on why it 
was created in the first place.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [pushed] gdb.base/dso2dso.exp sometimes broken
  2015-08-12 20:26       ` Joel Brobecker
  2015-08-12 20:31         ` Luis Machado
@ 2015-08-13  1:46         ` Joel Brobecker
  2015-08-13 17:27         ` [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
  2 siblings, 0 replies; 40+ messages in thread
From: Joel Brobecker @ 2015-08-13  1:46 UTC (permalink / raw)
  To: gdb-patches; +Cc: Keith Seitz

From: Keith Seitz <keiths@redhat.com>

Hello,

Keith reported that gdb.base/dso2dso.exp is broken, with the following
error:

| $ make check RUNTESTFLAGS=dso2dso.exp
| [snip]
| Running ../../../src/gdb/testsuite/gdb.base/dso2dso.exp ...
| ERROR: tcl error sourcing ../../../src/gdb/testsuite/gdb.base/dso2dso.exp.
| ERROR: couldn't open
| "../../../src/gdb/testsuite/gdb.base/../../../src/gdb/testsuite/gdb.base/dso2dso-dso1.c":
| no such file or directory
|     while executing
| "error "$message""
|     (procedure "gdb_get_line_number" line 14)
|     invoked from within
| "gdb_get_line_number "STOP HERE" $srcfile_libdso1"
|     (file "../../../src/gdb/testsuite/gdb.base/dso2dso.exp" line 60)
|     invoked from within
| "source ../../../src/gdb/testsuite/gdb.base/dso2dso.exp"
|     ("uplevel" body line 1)
|     invoked from within
| "uplevel #0 source ../../../src/gdb/testsuite/gdb.base/dso2dso.exp"
|     invoked from within
| "catch "uplevel #0 source $test_file_name""

This happens because gdb_get_line_number will prepend $srcdir/$subdir
if the given filename does not start with "/", and this happens when
GDB was configured using a relative path to the configure script.
When using an absolute path like I do, we avoid the pre-pending that
Keith is seeing.

gdb/testsuite/ChangeLog:

        Keith Seitz  <keiths@redhat.com>:
        * gdb.base/dso2dso.exp: Pass basename of source file in call
        to gdb_get_line_number.

Tested on x86_64-linux with both scenarios.
Pushing now...

Thanks Keith!
-- 
Joel

---
 gdb/testsuite/ChangeLog            | 5 +++++
 gdb/testsuite/gdb.base/dso2dso.exp | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 738c927..b44869d 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2015-08-12  Keith Seitz  <keiths@redhat.com>
+
+	* gdb.base/dso2dso.exp: Pass basename of source file in call to
+	gdb_get_line_number.
+
 2015-08-12  Joel Brobecker  <brobecker@adacore.com>
 
 	* gdb.base/dso2dso-dso2.c, gdb.base/dso2dso-dso2.h,
diff --git a/gdb/testsuite/gdb.base/dso2dso.exp b/gdb/testsuite/gdb.base/dso2dso.exp
index 16eb1f3..c1873ba 100644
--- a/gdb/testsuite/gdb.base/dso2dso.exp
+++ b/gdb/testsuite/gdb.base/dso2dso.exp
@@ -63,7 +63,7 @@ if { ![runto_main] } {
   return -1
 }
 
-set bp_location [gdb_get_line_number "STOP HERE" $srcfile_libdso1]
+set bp_location [gdb_get_line_number "STOP HERE" [file tail $srcfile_libdso1]]
 gdb_breakpoint ${srcfile_libdso1}:${bp_location}
 
 gdb_continue_to_breakpoint "at call to sub2" \
-- 
2.1.4

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4 00/18] All-stop on top of non-stop
  2015-08-12 20:50           ` Joel Brobecker
  2015-08-12 21:07             ` Luis Machado
@ 2015-08-13 16:04             ` Pedro Alves
  2015-08-13 18:17               ` Joel Brobecker
  1 sibling, 1 reply; 40+ messages in thread
From: Pedro Alves @ 2015-08-13 16:04 UTC (permalink / raw)
  To: Joel Brobecker, Luis Machado; +Cc: gdb-patches, Sergio Durigan Junior

On 08/12/2015 09:50 PM, Joel Brobecker wrote:

> That being said, I propose the attached patch. I confess I'm not
> super convinced about the comment on amd64, as I think it might
> become one day irrelevant. But I don't mind it that much; if
> it is helpful to others...
> 
> What do you think?
> 
> gdb/testsuite/ChangeLog:
> 
>         * gdb.base/dso2dso.exp: Improve the testcase's documentation.
> 

Seems fine to me.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4 00/18] All-stop on top of non-stop
  2015-08-12 20:26       ` Joel Brobecker
  2015-08-12 20:31         ` Luis Machado
  2015-08-13  1:46         ` [pushed] gdb.base/dso2dso.exp sometimes broken Joel Brobecker
@ 2015-08-13 17:27         ` Pedro Alves
  2015-08-13 18:29           ` Joel Brobecker
  2 siblings, 1 reply; 40+ messages in thread
From: Pedro Alves @ 2015-08-13 17:27 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches, Luis Machado, Sergio Durigan Junior

On 08/12/2015 09:26 PM, Joel Brobecker wrote:
> 
> One last thought: Should we put it in GDB 7.10? Seems fairly safe,
> but is it worth it?

I think so.  The bug should trigger on 7.10 in "set non-stop on" mode,
which enables displaced stepping too.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4 00/18] All-stop on top of non-stop
  2015-08-13 16:04             ` Pedro Alves
@ 2015-08-13 18:17               ` Joel Brobecker
  0 siblings, 0 replies; 40+ messages in thread
From: Joel Brobecker @ 2015-08-13 18:17 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Luis Machado, gdb-patches, Sergio Durigan Junior

> > gdb/testsuite/ChangeLog:
> > 
> >         * gdb.base/dso2dso.exp: Improve the testcase's documentation.
> > 
> 
> Seems fine to me.

Thank you, pushed!

-- 
Joel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v4 00/18] All-stop on top of non-stop
  2015-08-13 17:27         ` [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
@ 2015-08-13 18:29           ` Joel Brobecker
  0 siblings, 0 replies; 40+ messages in thread
From: Joel Brobecker @ 2015-08-13 18:29 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Luis Machado, Sergio Durigan Junior

> > One last thought: Should we put it in GDB 7.10? Seems fairly safe,
> > but is it worth it?
> 
> I think so.  The bug should trigger on 7.10 in "set non-stop on" mode,
> which enables displaced stepping too.

OK. I've pushed this patch, as well as the two other patches
that adjust the testcase, to the gdb-7.10-branch.

Thank you!
-- 
Joel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 11/18] Implement all-stop on top of a target running non-stop mode
  2015-05-21 23:19 ` [PATCH 11/18] Implement all-stop on top of a target running non-stop mode Pedro Alves
@ 2015-09-11 20:53   ` Jan Kratochvil
  2015-09-14 14:24     ` Pedro Alves
  0 siblings, 1 reply; 40+ messages in thread
From: Jan Kratochvil @ 2015-09-11 20:53 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Fri, 22 May 2015 01:19:07 +0200, Pedro Alves wrote:
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -75,6 +75,12 @@ maint print symbol-cache-statistics
>  maint flush-symbol-cache
>    Flush the contents of the symbol cache.
>  
> +maint set target-non-stop (on|off|auto)
> +maint show target-non-stop
> +  Control whether GDB targets always operate in non-stop mode even if
> +  "set non-stop" is "off".  The default is "auto", meaning non-stop
> +  mode is enabled if supported by the target.
> +
>  record btrace bts
>  record bts
>    Start branch trace recording using Branch Trace Store (BTS) format.

This part got checked-in twice:
	https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blobdiff;f=gdb/NEWS;h=3fe603615afc858428bc085f345fca3ee12314d5;hp=7e58cc3f31aa961f700ca9b511a0b6c558f73a90;hb=fbea99ea8a062e5cd96e2d88336984ed3adc93d4;hpb=372316f12874a30c62e6d71079ca3b86c786fb7e

I haven't fixed it.


Jan

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 11/18] Implement all-stop on top of a target running non-stop mode
  2015-09-11 20:53   ` Jan Kratochvil
@ 2015-09-14 14:24     ` Pedro Alves
  0 siblings, 0 replies; 40+ messages in thread
From: Pedro Alves @ 2015-09-14 14:24 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

On 09/11/2015 09:53 PM, Jan Kratochvil wrote:
> On Fri, 22 May 2015 01:19:07 +0200, Pedro Alves wrote:
>> --- a/gdb/NEWS
>> +++ b/gdb/NEWS
>> @@ -75,6 +75,12 @@ maint print symbol-cache-statistics
>>  maint flush-symbol-cache
>>    Flush the contents of the symbol cache.
>>  
>> +maint set target-non-stop (on|off|auto)
>> +maint show target-non-stop
>> +  Control whether GDB targets always operate in non-stop mode even if
>> +  "set non-stop" is "off".  The default is "auto", meaning non-stop
>> +  mode is enabled if supported by the target.
>> +
>>  record btrace bts
>>  record bts
>>    Start branch trace recording using Branch Trace Store (BTS) format.
> 
> This part got checked-in twice:
> 	https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blobdiff;f=gdb/NEWS;h=3fe603615afc858428bc085f345fca3ee12314d5;hp=7e58cc3f31aa961f700ca9b511a0b6c558f73a90;hb=fbea99ea8a062e5cd96e2d88336984ed3adc93d4;hpb=372316f12874a30c62e6d71079ca3b86c786fb7e
> 
> I haven't fixed it.

Whoops, thanks.  I pushed the obvious patch below to fix it.

From b027a8fa7dc4854e72ddada0b495b52166be2974 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Mon, 14 Sep 2015 14:43:53 +0100
Subject: [PATCH] Remove duplicate gdb/NEWS entry

Commit fbea99ea8a06 added this to both the "Changes in GDB 7.10" and
"Changes since GDB 7.10" sections by mistake.

gdb/ChangeLog:
2015-09-14  Pedro Alves  <palves@redhat.com>

	* NEWS (Changes in GDB 7.10, New commands>: Remove duplicate
	mention of maint set/show target-non-stop.
---
 gdb/ChangeLog | 5 +++++
 gdb/NEWS      | 6 ------
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 3cb3427..dadb7a0 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,8 @@
+2015-09-14  Pedro Alves  <palves@redhat.com>
+
+	* NEWS (Changes in GDB 7.10, New commands>: Remove duplicate
+	mention of maint set/show target-non-stop.
+
 2015-09-11  Don Breazeal  <donb@codesourcery.com>
 
 	* NEWS: Announce new remote packets for the exec-events
diff --git a/gdb/NEWS b/gdb/NEWS
index bb1c8d9..f563b8c 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -172,12 +172,6 @@ maint print symbol-cache-statistics
 maint flush-symbol-cache
   Flush the contents of the symbol cache.
 
-maint set target-non-stop (on|off|auto)
-maint show target-non-stop
-  Control whether GDB targets always operate in non-stop mode even if
-  "set non-stop" is "off".  The default is "auto", meaning non-stop
-  mode is enabled if supported by the target.
-
 record btrace bts
 record bts
   Start branch trace recording using Branch Trace Store (BTS) format.
-- 
1.9.3


^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2015-09-14 14:24 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-21 23:19 [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
2015-05-21 23:19 ` [PATCH 01/18] Fix and test "checkpoint" in non-stop mode Pedro Alves
2015-05-21 23:19 ` [PATCH 18/18] native Linux: enable always non-stop by default Pedro Alves
2015-05-21 23:19 ` [PATCH 14/18] Fix step-over-{trips-on-watchpoint|lands-on-breakpoint}.exp race Pedro Alves
2015-05-21 23:19 ` [PATCH 16/18] PPC64: Fix gdb.arch/ppc64-atomic-inst.exp with displaced stepping Pedro Alves
2015-05-21 23:19 ` [PATCH 09/18] Factor out code to re-resume stepped thread Pedro Alves
2015-05-21 23:19 ` [PATCH 06/18] Use keep_going in proceed and start_step_over too Pedro Alves
2015-05-21 23:19 ` [PATCH 02/18] Change adjust_pc_after_break's prototype Pedro Alves
2015-05-21 23:19 ` [PATCH 05/18] Embed the pending step-over chain in thread_info objects Pedro Alves
2015-05-21 23:19 ` [PATCH 04/18] Make thread_still_needs_step_over consider stepping_over_watchpoint too Pedro Alves
2015-05-21 23:19 ` [PATCH 03/18] remote.c/all-stop: Implement TARGET_WAITKIND_NO_RESUMED and TARGET_WNOHANG Pedro Alves
2015-05-21 23:19 ` [PATCH 11/18] Implement all-stop on top of a target running non-stop mode Pedro Alves
2015-09-11 20:53   ` Jan Kratochvil
2015-09-14 14:24     ` Pedro Alves
2015-05-21 23:19 ` [PATCH 12/18] Fix signal-while-stepping-over-bp-other-thread.exp on targets always in non-stop Pedro Alves
2015-05-21 23:19 ` [PATCH 08/18] Add comments to currently_stepping and target_resume Pedro Alves
2015-05-21 23:25 ` [PATCH 07/18] Misc switch_back_to_stepped_thread cleanups Pedro Alves
2015-05-21 23:28 ` [PATCH 13/18] Fix interrupt-noterm.exp on targets always in non-stop Pedro Alves
2015-05-21 23:50 ` [PATCH 17/18] S/390: displaced stepping and PC-relative RIL-b/RIL-c instructions Pedro Alves
2015-05-21 23:56 ` [PATCH 10/18] Teach non-stop to do in-line step-overs (stop all, step, restart) Pedro Alves
2015-05-21 23:59 ` [PATCH 15/18] Disable displaced stepping if trying it fails Pedro Alves
2015-08-07 16:58 ` [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
2015-08-12 18:32   ` Joel Brobecker
2015-08-12 19:05     ` Pedro Alves
2015-08-12 20:26       ` Joel Brobecker
2015-08-12 20:31         ` Luis Machado
2015-08-12 20:50           ` Joel Brobecker
2015-08-12 21:07             ` Luis Machado
2015-08-13 16:04             ` Pedro Alves
2015-08-13 18:17               ` Joel Brobecker
2015-08-13  1:46         ` [pushed] gdb.base/dso2dso.exp sometimes broken Joel Brobecker
2015-08-13 17:27         ` [PATCH v4 00/18] All-stop on top of non-stop Pedro Alves
2015-08-13 18:29           ` Joel Brobecker
2015-08-12 19:39     ` Luis Machado
2015-08-12 19:51       ` Sergio Durigan Junior
2015-08-12 19:59       ` Joel Brobecker
2015-08-12 20:18         ` Luis Machado
2015-08-12 20:33           ` Joel Brobecker
2015-08-12 20:40             ` Luis Machado
2015-08-12 20:56               ` Joel Brobecker

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).