public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Andrew Burgess <aburgess@redhat.com>
To: "Aktemur, Tankut Baris" <tankut.baris.aktemur@intel.com>,
	"gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
Cc: "Saiapova, Natalia" <natalia.saiapova@intel.com>
Subject: RE: [PATCHv7 2/6] gdb: fix b/p conditions with infcalls in multi-threaded inferiors
Date: Mon, 05 Jun 2023 14:53:01 +0100	[thread overview]
Message-ID: <875y823tj6.fsf@redhat.com> (raw)
In-Reply-To: <DM4PR11MB73035467DF8EAAB1DA8A5601C4799@DM4PR11MB7303.namprd11.prod.outlook.com>

"Aktemur, Tankut Baris" <tankut.baris.aktemur@intel.com> writes:

> On Monday, May 15, 2023 9:22 PM, Andrew Burgess wrote:
>> This commit fixes bug PR 28942, that is, creating a conditional
>> breakpoint in a multi-threaded inferior, where the breakpoint
>> condition includes an inferior function call.
>> 
>> Currently, when a user tries to create such a breakpoint, then GDB
>> will fail with:
>> 
>>   (gdb) break infcall-from-bp-cond-single.c:61 if (return_true ())
>>   Breakpoint 2 at 0x4011fa: file
>> /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.threads/infcall-from-bp-cond-
>> single.c, line 61.
>>   (gdb) continue
>>   Continuing.
>>   [New Thread 0x7ffff7c5d700 (LWP 2460150)]
>>   [New Thread 0x7ffff745c700 (LWP 2460151)]
>>   [New Thread 0x7ffff6c5b700 (LWP 2460152)]
>>   [New Thread 0x7ffff645a700 (LWP 2460153)]
>>   [New Thread 0x7ffff5c59700 (LWP 2460154)]
>>   Error in testing breakpoint condition:
>>   Couldn't get registers: No such process.
>>   An error occurred while in a function called from GDB.
>>   Evaluation of the expression containing the function
>>   (return_true) will be abandoned.
>>   When the function is done executing, GDB will silently stop.
>>   Selected thread is running.
>>   (gdb)
>> 
>> Or, in some cases, like this:
>> 
>>   (gdb) break infcall-from-bp-cond-simple.c:56 if (is_matching_tid (arg, 1))
>>   Breakpoint 2 at 0x401194: file
>> /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.threads/infcall-from-bp-cond-
>> simple.c, line 56.
>>   (gdb) continue
>>   Continuing.
>>   [New Thread 0x7ffff7c5d700 (LWP 2461106)]
>>   [New Thread 0x7ffff745c700 (LWP 2461107)]
>>   ../../src.release/gdb/nat/x86-linux-dregs.c:146: internal-error:
>> x86_linux_update_debug_registers: Assertion `lwp_is_stopped (lwp)' failed.
>>   A problem internal to GDB has been detected,
>>   further debugging may prove unreliable.
>> 
>> The precise error depends on the exact thread state; so there's race
>> conditions depending on which threads have fully started, and which
>> have not.  But the underlying problem is always the same; when GDB
>> tries to execute the inferior function call from within the breakpoint
>> condition, GDB will, incorrectly, try to resume threads that are
>> already running - GDB doesn't realise that some threads might already
>> be running.
>> 
>> The solution proposed in this patch requires an additional member
>> variable thread_info::in_cond_eval.  This flag is set to true (in
>> breakpoint.c) when GDB is evaluating a breakpoint condition.
>> 
>> In user_visible_resume_ptid (infrun.c), when the in_cond_eval flag is
>> true, then GDB will only try to resume the current thread, that is,
>> the thread for which the breakpoint condition is being evaluated.
>> This solves the problem of GDB trying to resume threads that are
>> already running.
>> 
>> The next problem is that inferior function calls are assumed to be
>> synchronous, that is, GDB doesn't expect to start an inferior function
>> call in thread #1, then receive a stop from thread #2 for some other,
>> unrelated reason.  To prevent GDB responding to an event from another
>> thread, we update fetch_inferior_event and do_target_wait in infrun.c,
>> so that, when an inferior function call (on behalf of a breakpoint
>> condition) is in progress, we only wait for events from the current
>> thread (the one evaluating the condition).
>> 
>> In do_target_wait I had to change the inferior_matches lambda
>> function, which is used to select which inferior to wait on.
>> Previously the logic was this:
>> 
>>    auto inferior_matches = [&wait_ptid] (inferior *inf)
>>      {
>>        return (inf->process_target () != nullptr
>>                && ptid_t (inf->pid).matches (wait_ptid));
>>      };
>> 
>> This compares the pid of the inferior against the complete ptid we
>> want to wait on.  Before this commit wait_ptid was only ever
>> minus_one_ptid (which is special, and means any process), and so every
>> inferior would match.
>> 
>> After this commit though wait_ptid might represent a specific thread
>> in a specific inferior.  If we compare the pid of the inferior to a
>> specific ptid then these will not match.  The fix is to compare
>> against the pid extracted from the wait_ptid, not against the complete
>> wait_ptid itself.
>> 
>> In fetch_inferior_event, after receiving the event, we only want to
>> stop all the other threads, and call inferior_event_handler with
>> INF_EXEC_COMPLETE, if we are not evaluating a conditional breakpoint.
>> If we are, then all the other threads should be left doing whatever
>> they were before.  The inferior_event_handler call will be performed
>> once the breakpoint condition has finished being evaluated, and GDB
>> decides to stop or not.
>> 
>> The final problem that needs solving relates to GDB's commit-resume
>> mechanism, which allows GDB to collect resume requests into a single
>> packet in order to reduce traffic to a remote target.
>> 
>> The problem is that the commit-resume mechanism will not send any
>> resume requests for an inferior if there are already events pending on
>> the GDB side.
>> 
>> Imagine an inferior with two threads.  Both threads hit a breakpoint,
>> maybe the same conditional breakpoint.  At this point there are two
>> pending events, one for each thread.
>> 
>> GDB selects one of the events and spots that this is a conditional
>> breakpoint, GDB evaluates the condition.
>> 
>> The condition includes an inferior function call, so GDB sets up for
>> the call and resumes the one thread, the resume request is added to
>> the commit-resume queue.
>> 
>> When the commit-resume queue is committed GDB sees that there is a
>> pending event from another thread, and so doesn't send any resume
>> requests to the actual target, GDB is assuming that when we wait we
>> will select the event from the other thread.
>> 
>> However, as this is an inferior function call for a condition
>> evaluation, we will not select the event from the other thread, we
>> only care about events from the thread that is evaluating the
>> condition - and the resume for this thread was never sent to the
>> target.
>> 
>> And so, GDB hangs, waiting for an event from a thread that was never
>> fully resumed.
>> 
>> To fix this issue I have added the concept of "forcing" the
>> commit-resume queue.  When enabling commit resume, if the force flag
>> is true, then any resumes will be committed to the target, even if
>> there are other threads with pending events.
>> 
>> A note on authorship: this patch was based on some work done by
>> Natalia Saiapova and Tankut Baris Aktemur from Intel[1].  I have made
>> some changes to their work in this version.
>> 
>> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28942
>> 
>> [1] https://sourceware.org/pipermail/gdb-patches/2020-October/172454.html
>> 
>> Co-authored-by: Natalia Saiapova <natalia.saiapova@intel.com>
>> Co-authored-by: Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
>
> Thanks again for this.
>
> I have a few minor comments inlined below.  Except those, it looks good to me.
> There is already Co-authored-by above, but in case you'd like to also add:
> Reviewed-By: Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>

I fixed this issues you highlighted and added your reviewed-by tag.

Thanks,
Andrew

>
> Regards
> -Baris
>
>
>> ---
>>  gdb/breakpoint.c                              |   2 +
>>  gdb/gdbthread.h                               |   3 +
>>  gdb/infcall.c                                 |   6 +
>>  gdb/infrun.c                                  |  64 +++--
>>  gdb/infrun.h                                  |   3 +-
>>  .../infcall-from-bp-cond-other-thread-event.c | 135 ++++++++++
>>  ...nfcall-from-bp-cond-other-thread-event.exp | 174 +++++++++++++
>>  .../gdb.threads/infcall-from-bp-cond-simple.c |  89 +++++++
>>  .../infcall-from-bp-cond-simple.exp           | 235 ++++++++++++++++++
>>  .../gdb.threads/infcall-from-bp-cond-single.c | 139 +++++++++++
>>  .../infcall-from-bp-cond-single.exp           | 117 +++++++++
>>  11 files changed, 952 insertions(+), 15 deletions(-)
>>  create mode 100644 gdb/testsuite/gdb.threads/infcall-from-bp-cond-other-thread-event.c
>>  create mode 100644 gdb/testsuite/gdb.threads/infcall-from-bp-cond-other-thread-event.exp
>>  create mode 100644 gdb/testsuite/gdb.threads/infcall-from-bp-cond-simple.c
>>  create mode 100644 gdb/testsuite/gdb.threads/infcall-from-bp-cond-simple.exp
>>  create mode 100644 gdb/testsuite/gdb.threads/infcall-from-bp-cond-single.c
>>  create mode 100644 gdb/testsuite/gdb.threads/infcall-from-bp-cond-single.exp
>> 
>> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
>> index fdb184ae81f..6fceed8f408 100644
>> --- a/gdb/breakpoint.c
>> +++ b/gdb/breakpoint.c
>> @@ -5548,6 +5548,8 @@ bpstat_check_breakpoint_conditions (bpstat *bs, thread_info *thread)
>>  	{
>>  	  try
>>  	    {
>> +	      scoped_restore reset_in_cond_eval
>> +		= make_scoped_restore (&thread->control.in_cond_eval, true);
>>  	      condition_result = breakpoint_cond_eval (cond);
>>  	    }
>>  	  catch (const gdb_exception_error &ex)
>> diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
>> index 7135515bf45..897752f2691 100644
>> --- a/gdb/gdbthread.h
>> +++ b/gdb/gdbthread.h
>> @@ -171,6 +171,9 @@ struct thread_control_state
>>       command.  This is used to decide whether "set scheduler-locking
>>       step" behaves like "on" or "off".  */
>>    int stepping_command = 0;
>> +
>> +  /* True if the thread is evaluating a BP condition.  */
>> +  bool in_cond_eval = false;
>>  };
>> 
>>  /* Inferior thread specific part of `struct infcall_suspend_state'.  */
>> diff --git a/gdb/infcall.c b/gdb/infcall.c
>> index 233ef5f29e9..49c88add394 100644
>> --- a/gdb/infcall.c
>> +++ b/gdb/infcall.c
>> @@ -642,6 +642,12 @@ run_inferior_call (std::unique_ptr<call_thread_fsm> sm,
>> 
>>        proceed (real_pc, GDB_SIGNAL_0);
>> 
>> +      /* Enable commit resume, but pass true for the force flag.  This
>> +	 ensures any thread we set running in proceed will actually be
>> +	 committed to the target, even if some other thread in the current
>> +	 target has a pending event.  */
>> +      scoped_enable_commit_resumed enable ("infcall", true);
>> +
>>        infrun_debug_show_threads ("non-exited threads after proceed for inferior-call",
>>  				 all_non_exited_threads ());
>> 
>> diff --git a/gdb/infrun.c b/gdb/infrun.c
>> index 07ef3c7c187..ea7ab6187ee 100644
>> --- a/gdb/infrun.c
>> +++ b/gdb/infrun.c
>> @@ -2275,6 +2275,14 @@ user_visible_resume_ptid (int step)
>>  	 mode.  */
>>        resume_ptid = inferior_ptid;
>>      }
>> +  else if (inferior_ptid != null_ptid
>> +	   && inferior_thread ()->control.in_cond_eval)
>> +    {
>> +      /* The inferior thread is evaluating a BP condition.  Other threads
>> +	 might be stopped or running and we do not want to change their
>> +	 state, thus, resume only the current thread.  */
>> +      resume_ptid = inferior_ptid;
>> +    }
>>    else if (!sched_multi && target_supports_multi_process ())
>>      {
>>        /* Resume all threads of the current process (and none of other
>> @@ -2992,12 +3000,24 @@ schedlock_applies (struct thread_info *tp)
>>  					    execution_direction)));
>>  }
>> 
>> -/* Set process_stratum_target::COMMIT_RESUMED_STATE in all target
>> -   stacks that have threads executing and don't have threads with
>> -   pending events.  */
>> +/* When FORCE_P is false, set process_stratum_target::COMMIT_RESUMED_STATE
>> +   in all target stacks that have threads executing and don't have threads
>> +   with pending events.
>> +
>> +   When FORCE_P is true, set process_stratum_target::COMMIT_RESUMED_STATE
>> +   in all target stacks that have threads executing regardless of whether
>> +   there are pending events or not.
>> +
>> +    Passing FORCE_P as false makes sense when GDB is going to wait for
>> +    events from all threads and will therefore spot the pending events.
>> +    However, if GDB is only going to wait for events from select threads
>> +    (i.e. when performing an inferior call) then a pending event on some
>> +    other thread will not be spotted, and if we fail to commit the resume
>> +    state for the thread performing the inferior call, then the inferior
>> +    call will never complete (or even start).  */
>
> There is one extra space of indentation above.  Is that intentional?
>
>>  static void
>> -maybe_set_commit_resumed_all_targets ()
>> +maybe_set_commit_resumed_all_targets (bool force_p)
>>  {
>>    scoped_restore_current_thread restore_thread;
>> 
>> @@ -3026,7 +3046,7 @@ maybe_set_commit_resumed_all_targets ()
>>  	 status to report, handle it before requiring the target to
>>  	 commit its resumed threads: handling the status might lead to
>>  	 resuming more threads.  */
>> -      if (proc_target->has_resumed_with_pending_wait_status ())
>> +      if (!force_p && proc_target->has_resumed_with_pending_wait_status ())
>>  	{
>>  	  infrun_debug_printf ("not requesting commit-resumed for target %s, a"
>>  			       " thread has a pending waitstatus",
>> @@ -3036,7 +3056,7 @@ maybe_set_commit_resumed_all_targets ()
>> 
>>        switch_to_inferior_no_thread (inf);
>> 
>> -      if (target_has_pending_events ())
>> +      if (!force_p && target_has_pending_events ())
>>  	{
>>  	  infrun_debug_printf ("not requesting commit-resumed for target %s, "
>>  			       "target has pending events",
>> @@ -3129,7 +3149,7 @@ scoped_disable_commit_resumed::reset ()
>>      {
>>        /* This is the outermost instance, re-enable
>>  	 COMMIT_RESUMED_STATE on the targets where it's possible.  */
>> -      maybe_set_commit_resumed_all_targets ();
>> +      maybe_set_commit_resumed_all_targets (false);
>>      }
>>    else
>>      {
>> @@ -3162,7 +3182,7 @@ scoped_disable_commit_resumed::reset_and_commit ()
>>  /* See infrun.h.  */
>> 
>>  scoped_enable_commit_resumed::scoped_enable_commit_resumed
>> -  (const char *reason)
>> +  (const char *reason, bool force_p)
>>    : m_reason (reason),
>>      m_prev_enable_commit_resumed (enable_commit_resumed)
>>  {
>> @@ -3174,7 +3194,7 @@ scoped_enable_commit_resumed::scoped_enable_commit_resumed
>> 
>>        /* Re-enable COMMIT_RESUMED_STATE on the targets where it's
>>  	 possible.  */
>> -      maybe_set_commit_resumed_all_targets ();
>> +      maybe_set_commit_resumed_all_targets (force_p);
>> 
>>        maybe_call_commit_resumed_all_targets ();
>>      }
>> @@ -3880,10 +3900,11 @@ do_target_wait (ptid_t wait_ptid, execution_control_state *ecs,
>>       polling the rest of the inferior list starting from that one in a
>>       circular fashion until the whole list is polled once.  */
>> 
>> -  auto inferior_matches = [&wait_ptid] (inferior *inf)
>> +  ptid_t wait_ptid_pid {wait_ptid.pid ()};
>> +  auto inferior_matches = [&wait_ptid_pid] (inferior *inf)
>>      {
>>        return (inf->process_target () != nullptr
>> -	      && ptid_t (inf->pid).matches (wait_ptid));
>> +	      && ptid_t (inf->pid).matches (wait_ptid_pid));
>>      };
>> 
>>    /* First see how many matching inferiors we have.  */
>> @@ -4352,7 +4373,17 @@ fetch_inferior_event ()
>>         the event.  */
>>      scoped_disable_commit_resumed disable_commit_resumed ("handling event");
>> 
>> -    if (!do_target_wait (minus_one_ptid, &ecs, TARGET_WNOHANG))
>> +    /* Is the current thread performing an inferior function call as part
>> +       of a breakpoint condition evaluation?  */
>> +    bool in_cond_eval = (inferior_ptid != null_ptid
>> +			 && inferior_thread ()->control.in_cond_eval);
>> +
>> +    /* If the thread is in the middle of the condition evaluation, wait for
>> +       an event from the current thread.  Otherwise, wait for an event from
>> +       any thread.  */
>> +    ptid_t waiton_ptid = in_cond_eval ? inferior_ptid : minus_one_ptid;
>> +
>> +    if (!do_target_wait (waiton_ptid, &ecs, TARGET_WNOHANG))
>>        {
>>  	infrun_debug_printf ("do_target_wait returned no event");
>>  	disable_commit_resumed.reset_and_commit ();
>> @@ -4408,7 +4439,12 @@ fetch_inferior_event ()
>>  	    bool should_notify_stop = true;
>>  	    bool proceeded = false;
>> 
>> -	    stop_all_threads_if_all_stop_mode ();
>> +	    /* If the thread that stopped just completed an inferior
>> +	       function call as part of a condition evaluation, then we
>> +	       don't want to stop all the other threads.  */
>> +	    if (ecs.event_thread == nullptr
>> +		|| !ecs.event_thread->control.in_cond_eval)
>> +	      stop_all_threads_if_all_stop_mode ();
>> 
>>  	    clean_up_just_stopped_threads_fsms (&ecs);
>> 
>> @@ -4423,7 +4459,7 @@ fetch_inferior_event ()
>>  		  proceeded = normal_stop ();
>>  	      }
>> 
>> -	    if (!proceeded)
>> +	    if (!proceeded && !in_cond_eval)
>>  	      {
>>  		inferior_event_handler (INF_EXEC_COMPLETE);
>>  		cmd_done = 1;
>> diff --git a/gdb/infrun.h b/gdb/infrun.h
>> index 9513bc570e4..1a6743aa45e 100644
>> --- a/gdb/infrun.h
>> +++ b/gdb/infrun.h
>> @@ -395,7 +395,8 @@ extern void maybe_call_commit_resumed_all_targets ();
>> 
>>  struct scoped_enable_commit_resumed
>>  {
>> -  explicit scoped_enable_commit_resumed (const char *reason);
>> +  explicit scoped_enable_commit_resumed (const char *reason,
>> +					 bool force_p = false);
>>    ~scoped_enable_commit_resumed ();
>> 
>>    DISABLE_COPY_AND_ASSIGN (scoped_enable_commit_resumed);
>> diff --git a/gdb/testsuite/gdb.threads/infcall-from-bp-cond-other-thread-event.c
>> b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-other-thread-event.c
>> new file mode 100644
>> index 00000000000..e2a8ccb4ebe
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-other-thread-event.c
>> @@ -0,0 +1,135 @@
>> +/* Copyright 2022-2023 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 <pthread.h>
>> +#include <unistd.h>
>> +#include <stdlib.h>
>> +#include <sched.h>
>> +
>> +#define NUM_THREADS 2
>> +
>> +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
>> +
>> +/* Some global variables to poke, just for something to do.  */
>> +volatile int global_var_0 = 0;
>> +volatile int global_var_1 = 0;
>> +
>> +/* This flag is updated from GDB.  */
>> +volatile int raise_signal = 0;
>> +
>> +/* Implement the breakpoint condition function.  Release the other thread
>> +   and try to give the other thread a chance to run.  Then return ANSWER.  */
>> +int
>> +condition_core_func (int answer)
>> +{
>> +  /* This unlock should release the other thread.  */
>> +  if (pthread_mutex_unlock (&mutex) != 0)
>> +    abort ();
>> +
>> +  /* And this yield and sleep should (hopefully) give the other thread a
>> +     chance to run.  This isn't guaranteed of course, but once the other
>> +     thread does run it should hit a breakpoint, which GDB should
>> +     (temporarily) ignore, so there's no easy way for us to know the other
>> +     thread has done what it needs to, thus, yielding and sleeping is the
>> +     best we can do.  */
>> +  sched_yield ();
>> +  sleep (2);
>> +
>> +  return answer;
>> +}
>> +
>> +void
>> +stop_marker ()
>> +{
>> +  int a = 100;	/* Final breakpoint here.  */
>> +}
>> +
>> +/* A breakpoint condition function that always returns true.  */
>> +int
>> +condition_true_func ()
>> +{
>> +  return condition_core_func (1);
>> +}
>> +
>> +/* A breakpoint condition function that always returns false.  */
>> +int
>> +condition_false_func ()
>> +{
>> +  return condition_core_func (0);
>> +}
>> +
>> +void *
>> +worker_func (void *arg)
>> +{
>> +  volatile int *ptr = 0;
>> +  int tid = *((int *) arg);
>> +
>> +  switch (tid)
>> +    {
>> +    case 0:
>> +      global_var_0 = 11;	/* First thread breakpoint.  */
>> +      break;
>> +
>> +    case 1:
>> +      if (pthread_mutex_lock (&mutex) != 0)
>> +	abort ();
>> +      if (raise_signal)
>> +	global_var_1 = *ptr;	/* Signal here.  */
>> +      else
>> +	global_var_1 = 99;	/* Other thread breakpoint.  */
>> +      break;
>> +
>> +    default:
>> +      abort ();
>> +    }
>> +
>> +  return NULL;
>> +}
>> +
>> +int
>> +main ()
>> +{
>> +  pthread_t threads[NUM_THREADS];
>> +  int args[NUM_THREADS];
>> +
>> +  /* Set an alarm, just in case the test deadlocks.  */
>> +  alarm (300);
>> +
>> +  /* We want the mutex to start locked.  */
>> +  if (pthread_mutex_lock (&mutex) != 0)
>> +    abort ();
>> +
>> +  for (int i = 0; i < NUM_THREADS; i++)
>> +    {
>> +      args[i] = i;
>> +      pthread_create (&threads[i], NULL, worker_func, &args[i]);
>> +    }
>> +
>> +  for (int i = 0; i < NUM_THREADS; i++)
>> +    {
>> +      void *retval;
>> +      pthread_join (threads[i], &retval);
>> +    }
>> +
>> +  /* Unlock once we're done, just for cleanliness.  */
>> +  if (pthread_mutex_unlock (&mutex) != 0)
>> +    abort ();
>> +
>> +  stop_marker ();
>> +
>> +  return 0;
>> +}
>> diff --git a/gdb/testsuite/gdb.threads/infcall-from-bp-cond-other-thread-event.exp
>> b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-other-thread-event.exp
>> new file mode 100644
>> index 00000000000..6d4e1e13ab2
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-other-thread-event.exp
>> @@ -0,0 +1,174 @@
>> +# Copyright 2022-2023 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 for conditional breakpoints where the breakpoint condition includes
>> +# an inferior function call.
>> +#
>> +# The tests in this script are testing what happens when an event arrives in
>> +# another thread while GDB is waiting for the inferior function call (in the
>> +# breakpoint condition) to finish.
>> +#
>> +# The expectation is that GDB will queue events for other threads and wait
>> +# for the inferior function call to complete, if the condition is true, then
>> +# the conditional breakpoint should be reported first.  The other thread
>> +# event should of course, not get lost, and should be reported as soon as
>> +# the user tries to continue the inferior.
>> +#
>> +# If the conditional breakpoint ends up not being taken (the condition is
>> +# false), then the other thread event should be reported immediately.
>> +#
>> +# This script tests what happens when the other thread event is (a) the
>> +# other thread hitting a breakpoint, and (b) the other thread taking a
>> +# signal (SIGSEGV in this case).
>> +
>> +standard_testfile
>> +
>> +if { [build_executable "failed to prepare" ${binfile} "${srcfile}" \
>> +	  {debug pthreads}] == -1 } {
>> +    return
>> +}
>> +
>> +set cond_bp_line [gdb_get_line_number "First thread breakpoint"]
>> +set other_bp_line [gdb_get_line_number "Other thread breakpoint"]
>> +set final_bp_line [gdb_get_line_number "Final breakpoint here"]
>> +set signal_line [gdb_get_line_number "Signal here"]
>> +
>> +# Start GDB based on TARGET_ASYNC and TARGET_NON_STOP, and then runto main.
>> +proc start_gdb_and_runto_main { target_async target_non_stop } {
>> +    save_vars { ::GDBFLAGS } {
>> +	append ::GDBFLAGS \
>> +	    " -ex \"maint set target-non-stop $target_non_stop\""
>> +	append ::GDBFLAGS \
>> +	    " -ex \"maintenance set target-async ${target_async}\""
>> +
>> +	clean_restart ${::binfile}
>> +    }
>> +
>> +    if { ![runto_main] } {
>> +	return -1
>> +    }
>> +
>> +    return 0
>> +}
>> +
>> +# Run a test of GDB's conditional breakpoints, where the conditions include
>> +# inferior function calls.  While the inferior function call is executing
>> +# another thread will hit a breakpoint (when OTHER_THREAD_SIGNAL is false),
>> +# or receive a signal (when OTHER_THREAD_SIGNAL is true).  GDB should report
>> +# the conditional breakpoint first (if the condition is true), and then
>> +# report the second thread event once the inferior is continued again.
>> +#
>> +# When STOP_AT_COND is true then the conditional breakpoint will have a
>> +# condition that evaluates to true (and the GDB will stop at the
>
> Nit: No "the" before "GDB".
>
>> +# breakpoint), otherwise, the condition will evaluate to false (and GDB will
>> +# not stop at the breakpoint).
>> +proc run_condition_test { stop_at_cond other_thread_signal \
>> +			      target_async target_non_stop } {
>> +    if { [start_gdb_and_runto_main $target_async \
>> +	      $target_non_stop] == -1 } {
>> +	return
>> +    }
>> +
>> +    # Setup the conditional breakpoint.
>> +    if { $stop_at_cond } {
>> +	set cond_func "condition_true_func"
>> +    } else {
>> +	set cond_func "condition_false_func"
>> +    }
>> +    gdb_breakpoint \
>> +	"${::srcfile}:${::cond_bp_line} if (${cond_func} ())"
>> +    set cond_bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \
>> +			"get number for conditional breakpoint"]
>> +
>> +    if { $other_thread_signal } {
>> +	# Arrange for the other thread to raise a signal while GDB is
>> +	# evaluating the breakpoint condition.
>> +	gdb_test_no_output "set raise_signal = 1"
>> +    } else {
>> +	# And a breakpoint that will be hit by another thread only once the
>> +	# breakpoint condition starts to be evaluated.
>> +	gdb_breakpoint "${::srcfile}:${::other_bp_line}"
>> +	set other_bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \
>> +			      "get number for other breakpoint"]
>> +    }
>> +
>> +    # A final breakpoint once the test has completed.
>> +    gdb_breakpoint "${::srcfile}:${::final_bp_line}"
>> +    set final_bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \
>> +			  "get number for final breakpoint"]
>> +
>> +    if { $stop_at_cond } {
>> +	# Continue.  The first breakpoint we hit should be the conditional
>> +	# breakpoint.  The other thread will have hit its breakpoint, but
>> +	# that will have been deferred until the conditional breakpoint is
>> +	# reported.
>> +	gdb_test "continue" \
>> +	    [multi_line \
>> +		 "Continuing\\." \
>> +		 ".*" \
>> +		 "" \
>> +		 "Thread ${::decimal} \"\[^\"\r\n\]+\" hit Breakpoint ${cond_bp_num},
>> worker_func \[^\r\n\]+:${::cond_bp_line}" \
>> +		 "${::decimal}\\s+\[^\r\n\]+First thread breakpoint\[^\r\n\]+"] \
>> +	    "hit the conditional breakpoint"
>> +    }
>> +
>> +    if { $other_thread_signal } {
>> +	# Now continue again, the other thread will now report that it
>> +	# received a signal.
>> +	gdb_test "continue" \
>> +	    [multi_line \
>> +		 "Continuing\\." \
>> +		 ".*" \
>> +		 "Thread ${::decimal} \"\[^\"\r\n\]+\" received signal SIGSEGV, Segmentation
>> fault\\." \
>> +		 "\\\[Switching to Thread \[^\r\n\]+\\\]" \
>> +		 "${::hex} in worker_func \[^\r\n\]+:${::signal_line}" \
>> +		 "${::decimal}\\s+\[^\r\n\]+Signal here\[^\r\n\]+"] \
>> +	    "received signal in other thread"
>> +    } else {
>> +	# Now continue again, the other thread will now report its
>> +	# breakpoint.
>> +	gdb_test "continue" \
>> +	    [multi_line \
>> +		 "Continuing\\." \
>> +		 ".*" \
>> +		 "" \
>> +		 "Thread ${::decimal} \"\[^\"\r\n\]+\" hit Breakpoint ${other_bp_num},
>> worker_func \[^\r\n\]+:${::other_bp_line}" \
>> +		 "${::decimal}\\s+\[^\r\n\]+Other thread breakpoint\[^\r\n\]+"] \
>> +	    "hit the breakpoint in other thread"
>> +
>> +	# Run to the stop marker.
>> +	gdb_test "continue" \
>> +	    [multi_line \
>> +		 "Continuing\\." \
>> +		 ".*" \
>> +		 "" \
>> +		 "Thread ${::decimal} \"\[^\"\r\n\]+\" hit Breakpoint ${final_bp_num},
>> stop_marker \[^\r\n\]+:${::final_bp_line}" \
>> +		 "${::decimal}\\s+\[^\r\n\]+Final breakpoint here\[^\r\n\]+"] \
>> +	    "hit the final breakpoint"
>> +    }
>> +
>> +    gdb_exit
>
> Is this really necessary?  We do clean_restart at the beginning of a test,
> which exits GDB as the first thing.
>
>> +}
>> +
>> +foreach_with_prefix target_async { "on" "off" } {
>> +    foreach_with_prefix target_non_stop { "on" "off" } {
>> +	foreach_with_prefix other_thread_signal { true false } {
>> +	    foreach_with_prefix stop_at_cond { true false } {
>> +		run_condition_test $stop_at_cond $other_thread_signal \
>> +		    $target_async $target_non_stop
>> +	    }
>> +	}
>> +    }
>> +}
>> diff --git a/gdb/testsuite/gdb.threads/infcall-from-bp-cond-simple.c
>> b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-simple.c
>> new file mode 100644
>> index 00000000000..9d746d8be49
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-simple.c
>> @@ -0,0 +1,89 @@
>> +/* Copyright 2022-2023 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 <pthread.h>
>> +#include <unistd.h>
>> +
>> +#define NUM_THREADS 3
>> +
>> +int
>> +is_matching_tid (int *tid_ptr, int tid_value)
>> +{
>> +  return *tid_ptr == tid_value;
>> +}
>> +
>> +int
>> +return_true ()
>> +{
>> +  return 1;
>> +}
>> +
>> +int
>> +return_false ()
>> +{
>> +  return 0;
>> +}
>> +
>> +int
>> +function_that_segfaults ()
>> +{
>> +  int *p = 0;
>> +  *p = 1;	/* Segfault happens here.   */
>> +}
>> +
>> +int
>> +function_with_breakpoint ()
>> +{
>> +  return 1;	/* Nested breakpoint.  */
>> +}
>> +
>> +void *
>> +worker_func (void *arg)
>> +{
>> +  int a = 42;	/* Breakpoint here.  */
>> +}
>> +
>> +void
>> +stop_marker ()
>> +{
>> +  int b = 99;	/* Stop marker.  */
>> +}
>> +
>> +int
>> +main ()
>> +{
>> +  pthread_t threads[NUM_THREADS];
>> +  int args[NUM_THREADS];
>> +
>> +  alarm (300);
>> +
>> +  for (int i = 0; i < NUM_THREADS; i++)
>> +    {
>> +      args[i] = i;
>> +      pthread_create (&threads[i], NULL, worker_func, &args[i]);
>> +    }
>> +
>> +  for (int i = 0; i < NUM_THREADS; i++)
>> +    {
>> +      void *retval;
>> +      pthread_join (threads[i], &retval);
>> +    }
>> +
>> +  stop_marker ();
>> +
>> +  return 0;
>> +}
>> diff --git a/gdb/testsuite/gdb.threads/infcall-from-bp-cond-simple.exp
>> b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-simple.exp
>> new file mode 100644
>> index 00000000000..37e1b64d9a4
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-simple.exp
>> @@ -0,0 +1,235 @@
>> +# Copyright 2022-2023 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/>.
>> +
>> +# Some simple tests of inferior function calls from breakpoint
>> +# conditions, in multi-threaded inferiors.
>> +#
>> +# This test sets up a multi-threaded inferior, and places a breakpoint
>> +# at a location that many of the threads will reach.  We repeat the
>> +# test with different conditions, sometimes a single thread should
>> +# stop at the breakpoint, sometimes multiple threads should stop, and
>> +# sometime no threads should stop.
>
> Typo: sometime -> sometimes
>
>> +
>> +standard_testfile
>> +
>> +if { [build_executable "failed to prepare" ${binfile} "${srcfile}" \
>> +	  {debug pthreads}] == -1 } {
>> +    return
>> +}
>> +
>> +set cond_bp_line [gdb_get_line_number "Breakpoint here"]
>> +set stop_bp_line [gdb_get_line_number "Stop marker"]
>> +set nested_bp_line [gdb_get_line_number "Nested breakpoint"]
>> +set segv_line [gdb_get_line_number "Segfault happens here"]
>> +
>> +# Start GDB based on TARGET_ASYNC and TARGET_NON_STOP, and then runto main.
>> +proc start_gdb_and_runto_main { target_async target_non_stop } {
>> +    save_vars { ::GDBFLAGS } {
>> +	append ::GDBFLAGS \
>> +	    " -ex \"maint set target-non-stop $target_non_stop\""
>> +	append ::GDBFLAGS \
>> +	    " -ex \"maintenance set target-async ${target_async}\""
>> +
>> +	clean_restart ${::binfile}
>> +    }
>> +
>> +    if { ![runto_main] } {
>> +	return -1
>> +    }
>> +
>> +    return 0
>> +}
>> +
>> +# Run a test of GDB's conditional breakpoints, where the conditions include
>> +# inferior function calls.
>> +#
>> +# CONDITION is the expression to be used as the breakpoint condition.
>> +#
>> +# N_EXPECTED_HITS is the number of threads that we expect to stop due to
>> +# CONDITON.
>> +#
>> +# MESSAGE is used as a test name prefix.
>> +proc run_condition_test { message n_expected_hits condition \
>> +			      target_async target_non_stop } {
>> +    with_test_prefix $message {
>> +
>> +	if { [start_gdb_and_runto_main $target_async \
>> +		  $target_non_stop] == -1 } {
>> +	    return
>> +	}
>> +
>> +	# Use this convenience variable to track how often the
>> +	# breakpoint condition has been evaluated.  This should be
>> +	# once per thread.
>> +	gdb_test "set \$n_cond_eval = 0"
>> +
>> +	# Setup the conditional breakpoint.
>> +	gdb_breakpoint \
>> +	    "${::srcfile}:${::cond_bp_line} if ((++\$n_cond_eval) && (${condition}))"
>> +
>> +	# And a breakpoint that we hit when the test is over, this one is
>> +	# not conditional.  Only the main thread gets here once all the
>> +	# other threads have finished.
>> +	gdb_breakpoint "${::srcfile}:${::stop_bp_line}"
>> +
>> +	# The number of times we stop at the conditional breakpoint.
>> +	set n_hit_condition 0
>> +
>> +	# Now keep 'continue'-ing GDB until all the threads have finished
>> +	# and we reach the stop_marker breakpoint.
>> +	gdb_test_multiple "continue" "spot all breakpoint hits" {
>> +	    -re " worker_func
>> \[^\r\n\]+${::srcfile}:${::cond_bp_line}\r\n${::decimal}\\s+\[^\r\n\]+Breakpoint
>> here\[^\r\n\]+\r\n${::gdb_prompt} $" {
>> +		incr n_hit_condition
>> +		send_gdb "continue\n"
>> +		exp_continue
>> +	    }
>> +
>> +	    -re " stop_marker
>> \[^\r\n\]+${::srcfile}:${::stop_bp_line}\r\n${::decimal}\\s+\[^\r\n\]+Stop
>> marker\[^\r\n\]+\r\n${::gdb_prompt} $" {
>> +		pass $gdb_test_name
>> +	    }
>> +	}
>> +
>> +	gdb_assert { $n_hit_condition == $n_expected_hits } \
>> +	    "stopped at breakpoint the expected number of times"
>> +
>> +	# Ensure the breakpoint condition was evaluated once per thread.
>> +	gdb_test "print \$n_cond_eval" "= 3" \
>> +	    "condition was evaluated in each thread"
>> +    }
>> +}
>> +
>> +# Check that after handling a conditional breakpoint (where the condition
>> +# includes an inferior call), it is still possible to kill the running
>> +# inferior, and then restart the inferior.
>> +#
>> +# At once point doing this would result in GDB giving an assertion error.
>> +proc_with_prefix run_kill_and_restart_test { target_async target_non_stop } {
>> +    # This test relies on the 'start' command, which is not possible with
>> +    # the plain 'remote' target.
>> +    if { [target_info gdb_protocol] == "remote" } {
>> +	return
>> +    }
>> +
>> +    if { [start_gdb_and_runto_main $target_async \
>> +	      $target_non_stop] == -1 } {
>> +	return
>> +    }
>> +
>> +    # Setup the conditional breakpoint.
>> +    gdb_breakpoint \
>> +	"${::srcfile}:${::cond_bp_line} if (is_matching_tid (arg, 1))"
>> +    gdb_continue_to_breakpoint "worker_func"
>> +
>> +    # Now kill the program being debugged.
>> +    gdb_test "kill" "" "kill process" \
>> +	"Kill the program being debugged.*y or n. $" "y"
>> +
>> +    # Check we can restart the inferior.  At one point this would trigger an
>> +    # assertion.
>> +    gdb_test "start" ".*"
>
> I believe using 'gdb_start_cmd' is preferred.
>
>> +}
>> +
>> +# Create a conditional breakpoint which includes a call to a function that
>> +# segfaults.  Run GDB and check what happens when the inferior segfaults
>> +# during the inferior call.
>> +proc_with_prefix run_bp_cond_segfaults { target_async target_non_stop } {
>> +    if { [start_gdb_and_runto_main $target_async \
>> +	      $target_non_stop] == -1 } {
>> +	return
>> +    }
>> +
>> +    # This test relies on the inferior segfaulting when trying to
>> +    # access address zero.
>> +    if { [is_address_zero_readable] } {
>> +	return
>> +    }
>> +
>> +    # Setup the conditional breakpoint, include a call to
>> +    # 'function_that_segfaults', which triggers the segfault.
>> +    gdb_breakpoint \
>> +	"${::srcfile}:${::cond_bp_line} if (is_matching_tid (arg, 0) &&
>> function_that_segfaults ())"
>> +    set bp_1_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \
>> +		      "get number of conditional breakpoint"]
>> +
>> +    gdb_test "continue" \
>> +	[multi_line \
>> +	     "Continuing\\." \
>> +	     ".*" \
>> +	     "Thread ${::decimal} \"infcall-from-bp\" received signal SIGSEGV, Segmentation
>> fault\\." \
>> +	     "${::hex} in function_that_segfaults \\(\\) at \[^\r\n\]+:${::segv_line}" \
>> +	     "${::decimal}\\s+\[^\r\n\]+Segfault happens here\[^\r\n\]+" \
>> +	     "Error in testing condition for breakpoint ${bp_1_num}:" \
>> +	     "The program being debugged was signaled while in a function called from GDB\\."
>> \
>> +	     "GDB remains in the frame where the signal was received\\." \
>> +	     "To change this behavior use \"set unwindonsignal on\"\\." \
>> +	     "Evaluation of the expression containing the function" \
>> +	     "\\(function_that_segfaults\\) will be abandoned\\." \
>> +	     "When the function is done executing, GDB will silently stop\\."]
>> +}
>> +
>> +# Create a conditional breakpoint which includes a call to a function that
>> +# itself has a breakpoint set within it.  Run GDB and check what happens
>> +# when GDB hits the nested breakpoint.
>> +proc_with_prefix run_bp_cond_hits_breakpoint { target_async target_non_stop } {
>> +    if { [start_gdb_and_runto_main $target_async \
>> +	      $target_non_stop] == -1 } {
>> +	return
>> +    }
>> +
>> +    # Setup the conditional breakpoint, include a call to
>> +    # 'function_with_breakpoint' in which we will shortly place a
>> +    # breakpoint.
>> +    gdb_breakpoint \
>> +	"${::srcfile}:${::cond_bp_line} if (is_matching_tid (arg, 0) &&
>> function_with_breakpoint ())"
>> +    set bp_1_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \
>> +		      "get number of conditional breakpoint"]
>> +
>> +    gdb_breakpoint "${::srcfile}:${::nested_bp_line}"
>> +    set bp_2_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \
>> +		      "get number of nested breakpoint"]
>> +
>> +    gdb_test "continue" \
>> +	[multi_line \
>> +	     "Continuing\\." \
>> +	     ".*" \
>> +	     "Thread ${::decimal} \"infcall-from-bp\" hit Breakpoint ${bp_2_num},
>> function_with_breakpoint \\(\\) at \[^\r\n\]+:${::nested_bp_line}" \
>> +	     "${::decimal}\\s+\[^\r\n\]+Nested breakpoint\[^\r\n\]+" \
>> +	     "Error in testing condition for breakpoint ${bp_1_num}:" \
>> +	     "The program being debugged stopped while in a function called from GDB\\." \
>> +	     "Evaluation of the expression containing the function" \
>> +	     "\\(function_with_breakpoint\\) will be abandoned\\." \
>> +	     "When the function is done executing, GDB will silently stop\\."]
>> +}
>> +
>> +foreach_with_prefix target_async { "on" "off" } {
>> +    foreach_with_prefix target_non_stop { "on" "off" } {
>> +	run_condition_test "exactly one thread is hit" \
>> +	    1 "is_matching_tid (arg, 1)" \
>> +	    $target_async $target_non_stop
>> +	run_condition_test "exactly two threads are hit" \
>> +	    2 "(is_matching_tid (arg, 0) || is_matching_tid (arg, 2))" \
>> +	    $target_async $target_non_stop
>> +	run_condition_test "all three threads are hit" \
>> +	    3 "return_true ()" \
>> +	    $target_async $target_non_stop
>> +	run_condition_test "no thread is hit" \
>> +	    0 "return_false ()" \
>> +	    $target_async $target_non_stop
>> +
>> +	run_kill_and_restart_test $target_async $target_non_stop
>> +	run_bp_cond_segfaults $target_async $target_non_stop
>> +	run_bp_cond_hits_breakpoint $target_async $target_non_stop
>> +    }
>> +}
>> diff --git a/gdb/testsuite/gdb.threads/infcall-from-bp-cond-single.c
>> b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-single.c
>> new file mode 100644
>> index 00000000000..835c72f03cf
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-single.c
>> @@ -0,0 +1,139 @@
>> +/* Copyright 2022-2023 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 <pthread.h>
>> +#include <unistd.h>
>> +#include <semaphore.h>
>> +#include <stdlib.h>
>> +
>> +#define NUM_THREADS 5
>> +
>> +/* Semaphores, used to track when threads have started, and to control
>> +   when the threads finish.  */
>> +sem_t startup_semaphore;
>> +sem_t finish_semaphore;
>> +
>> +/* Mutex to control when the first worker thread hit a breakpoint
>> +   location.  */
>> +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
>> +
>> +/* Global variable to poke, just so threads have something to do.  */
>> +volatile int global_var = 0;
>> +
>> +int
>> +return_true ()
>> +{
>> +  return 1;
>> +}
>> +
>> +int
>> +return_false ()
>> +{
>> +  return 0;
>> +}
>> +
>> +void *
>> +worker_func (void *arg)
>> +{
>> +  int tid = *((int *) arg);
>> +
>> +  switch (tid)
>> +    {
>> +    case 0:
>> +      /* Wait for MUTEX to become available, then pass through the
>> +	 conditional breakpoint location.  */
>> +      if (pthread_mutex_lock (&mutex) != 0)
>> +	abort ();
>> +      global_var = 99;	/* Conditional breakpoint here.  */
>> +      if (pthread_mutex_unlock (&mutex) != 0)
>> +	abort ();
>> +      break;
>> +
>> +    default:
>> +      /* Notify the main thread that the thread has started, then wait for
>> +	 the main thread to tell us to finish.  */
>> +      sem_post (&startup_semaphore);
>> +      if (sem_wait (&finish_semaphore) != 0)
>> +	abort ();
>> +      break;
>> +    }
>> +}
>> +
>> +void
>> +stop_marker ()
>> +{
>> +  global_var = 99;	/* Stop marker.  */
>> +}
>> +
>> +int
>> +main ()
>> +{
>> +  pthread_t threads[NUM_THREADS];
>> +  int args[NUM_THREADS];
>> +  void *retval;
>> +
>> +  /* An alarm, just in case the thread deadlocks.  */
>> +  alarm (300);
>> +
>> +  /* Semaphore initialization.  */
>> +  if (sem_init (&startup_semaphore, 0, 0) != 0)
>> +    abort ();
>> +  if (sem_init (&finish_semaphore, 0, 0) != 0)
>> +    abort ();
>> +
>> +  /* Lock MUTEX, this prevents the first worker thread from rushing ahead.  */
>> +  if (pthread_mutex_lock (&mutex) != 0)
>> +    abort ();
>> +
>> +  /* Worker thread creation.  */
>> +  for (int i = 0; i < NUM_THREADS; i++)
>> +    {
>> +      args[i] = i;
>> +      pthread_create (&threads[i], NULL, worker_func, &args[i]);
>> +    }
>> +
>> +  /* Wait for every thread (other than the first) to tell us it has started
>> +     up.  */
>> +  for (int i = 1; i < NUM_THREADS; i++)
>> +    {
>> +      if (sem_wait (&startup_semaphore) != 0)
>> +	abort ();
>> +    }
>> +
>> +  /* Unlock the first thread so it can proceed.  */
>> +  if (pthread_mutex_unlock (&mutex) != 0)
>> +    abort ();
>> +
>> +  /* Wait for the first thread only.  */
>> +  pthread_join (threads[0], &retval);
>> +
>> +  /* Now post FINISH_SEMAPHORE to allow all the other threads to finish.  */
>> +  for (int i = 1; i < NUM_THREADS; i++)
>> +    sem_post (&finish_semaphore);
>> +
>> +  /* Now wait for the remaining threads to complete.  */
>> +  for (int i = 1; i < NUM_THREADS; i++)
>> +    pthread_join (threads[i], &retval);
>> +
>> +  /* Semaphore cleanup.  */
>> +  sem_destroy (&finish_semaphore);
>> +  sem_destroy (&startup_semaphore);
>> +
>> +  stop_marker ();
>> +
>> +  return 0;
>> +}
>> diff --git a/gdb/testsuite/gdb.threads/infcall-from-bp-cond-single.exp
>> b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-single.exp
>> new file mode 100644
>> index 00000000000..787dee3aa8e
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-single.exp
>> @@ -0,0 +1,117 @@
>> +# Copyright 2022-2023 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/>.
>> +
>> +# This test reprocuces bug gdb/28942, performing an inferior function
>> +# call from a breakpoint condition in a multi-threaded inferior.
>> +#
>> +# The important part of this test is that, when the conditional
>> +# breakpoint is hit, and the condition (which includes an inferior
>> +# function call) is evaluated, the other threads are running.
>> +
>> +standard_testfile
>> +
>> +if { [build_executable "failed to prepare" ${binfile} "${srcfile}" \
>> +	  {debug pthreads}] == -1 } {
>> +    return
>> +}
>> +
>> +set cond_bp_line [gdb_get_line_number "Conditional breakpoint here"]
>> +set final_bp_line [gdb_get_line_number "Stop marker"]
>> +
>> +# Start GDB based on TARGET_ASYNC and TARGET_NON_STOP, and then runto main.
>> +proc start_gdb_and_runto_main { target_async target_non_stop } {
>> +    save_vars { ::GDBFLAGS } {
>> +	append ::GDBFLAGS \
>> +	    " -ex \"maint set target-non-stop $target_non_stop\""
>> +	append ::GDBFLAGS \
>> +	    " -ex \"maintenance set target-async ${target_async}\""
>> +
>> +	clean_restart ${::binfile}
>> +    }
>> +
>> +    if { ![runto_main] } {
>> +	return -1
>> +    }
>> +
>> +    return 0
>> +}
>> +
>> +# Run a test of GDB's conditional breakpoints, where the conditions include
>> +# inferior function calls.
>> +#
>> +# TARGET_ASYNC and TARGET_NON_STOP are used when starting up GDB.
>> +#
>> +# When STOP_AT_COND is true the breakpoint condtion will evaluate to
>> +# true, and GDB will stop at the breakpoint.  Otherwise, the
>> +# breakpoint condition will evaluate to false and GDB will not stop at
>> +# the breakpoint.
>> +proc run_condition_test { stop_at_cond \
>> +			      target_async target_non_stop } {
>> +    if { [start_gdb_and_runto_main $target_async \
>> +	      $target_non_stop] == -1 } {
>> +	return
>> +    }
>> +
>> +    # Setup the conditional breakpoint.
>> +    if { $stop_at_cond } {
>> +	set cond_func "return_true"
>> +    } else {
>> +	set cond_func "return_false"
>> +    }
>> +    gdb_breakpoint \
>> +	"${::srcfile}:${::cond_bp_line} if (${cond_func} ())"
>> +    set cond_bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \
>> +			"get number for conditional breakpoint"]
>> +
>> +    # And a breakpoint that we hit when the test is over, this one is
>> +    # not conditional.
>> +    gdb_breakpoint "${::srcfile}:${::final_bp_line}"
>> +    set final_bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \
>> +			  "get number for final breakpoint"]
>> +
>> +    if { $stop_at_cond } {
>> +	# Continue.  The first breakpoint we hit should be the conditional
>> +	# breakpoint.  The other thread will have hit its breakpoint, but
>> +	# that will have been deferred until the conditional breakpoint is
>> +	# reported.
>> +	gdb_test "continue" \
>> +	    [multi_line \
>> +		 "Continuing\\." \
>> +		 ".*" \
>> +		 "" \
>> +		 "Thread ${::decimal} \"\[^\"\r\n\]+\" hit Breakpoint ${cond_bp_num},
>> worker_func \[^\r\n\]+:${::cond_bp_line}" \
>> +		 "${::decimal}\\s+\[^\r\n\]+Conditional breakpoint here\[^\r\n\]+"] \
>> +	    "hit the conditional breakpoint"
>> +    }
>> +
>> +    # Run to the stop marker.
>> +    gdb_test "continue" \
>> +	[multi_line \
>> +	     "Continuing\\." \
>> +	     ".*" \
>> +	     "" \
>> +	     "Thread ${::decimal} \"\[^\"\r\n\]+\" hit Breakpoint ${final_bp_num},
>> stop_marker \[^\r\n\]+:${::final_bp_line}" \
>> +	     "${::decimal}\\s+\[^\r\n\]+Stop marker\[^\r\n\]+"] \
>> +	"hit the final breakpoint"
>> +}
>> +
>> +foreach_with_prefix target_async { "on" "off" } {
>> +    foreach_with_prefix target_non_stop { "on" "off" } {
>> +	foreach_with_prefix stop_at_cond { true false } {
>> +	    run_condition_test $stop_at_cond \
>> +		$target_async $target_non_stop
>> +	}
>> +    }
>> +}
>> --
>> 2.25.4
>
> Intel Deutschland GmbH
> Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
> Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
> Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
> Chairperson of the Supervisory Board: Nicole Lau
> Registered Office: Munich
> Commercial Register: Amtsgericht Muenchen HRB 186928


  reply	other threads:[~2023-06-05 13:53 UTC|newest]

Thread overview: 202+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-21  8:43 [PATCH 00/12] Infcalls from B/P conditions " Andrew Burgess
2022-10-21  8:43 ` [PATCH 01/12] gdb: int to bool conversion for normal_stop Andrew Burgess
2022-11-04 12:20   ` Lancelot SIX
2023-01-13 16:35     ` Andrew Burgess
2022-10-21  8:43 ` [PATCH 02/12] gdb/infrun: add debug print in print_signal_received_reason Andrew Burgess
2023-01-13 16:38   ` Andrew Burgess
2022-10-21  8:43 ` [PATCH 03/12] gdb: include breakpoint number in testing condition error message Andrew Burgess
2022-10-21  8:43 ` [PATCH 04/12] gdbserver: add comments to read_inferior_memory function Andrew Burgess
2023-01-13 16:42   ` Andrew Burgess
2022-10-21  8:43 ` [PATCH 05/12] gdbserver: allows agent_mem_read to return an error code Andrew Burgess
2022-10-21  8:43 ` [PATCH 06/12] gdbserver: allow agent expressions to fail with invalid memory access Andrew Burgess
2022-10-21  8:43 ` [PATCH 07/12] gdb: avoid repeated signal reporting during failed conditional breakpoint Andrew Burgess
2022-10-21  8:43 ` [PATCH 08/12] gdb: don't always print breakpoint location after failed condition check Andrew Burgess
2022-10-21  8:43 ` [PATCH 09/12] Revert "gdb: remove unnecessary parameter wait_ptid from do_target_wait" Andrew Burgess
2022-10-21  8:43 ` [PATCH 10/12] gdb: fix b/p conditions with infcalls in multi-threaded inferiors Andrew Burgess
2022-10-21  8:43 ` [PATCH 11/12] gdb: add timeouts for inferior function calls Andrew Burgess
2022-10-21 11:08   ` Eli Zaretskii
2023-01-14 11:00     ` Andrew Burgess
2023-01-14 11:48       ` Eli Zaretskii
2023-01-16 17:22         ` Andrew Burgess
2023-01-16 17:27           ` Eli Zaretskii
2022-11-04 23:17   ` Lancelot SIX
2023-01-13 16:49     ` Andrew Burgess
2023-01-16  9:44       ` Lancelot SIX
2022-10-21  8:43 ` [PATCH 12/12] gdb/remote: avoid SIGINT after calling remote_target::stop Andrew Burgess
2023-01-18 16:17 ` [PATCHv2 00/13] Infcalls from B/P conditions in multi-threaded inferiors Andrew Burgess
2023-01-18 16:17   ` [PATCHv2 01/13] gdb/doc: extended documentation for inferior function calls Andrew Burgess
2023-01-18 17:20     ` Eli Zaretskii
2023-03-16 17:15       ` Andrew Burgess
2023-01-19  9:00     ` Aktemur, Tankut Baris
2023-01-18 16:17   ` [PATCHv2 02/13] gdb/doc: extend the documentation for conditional breakpoints Andrew Burgess
2023-01-18 17:22     ` Eli Zaretskii
2023-01-19  9:04     ` Aktemur, Tankut Baris
2023-01-19 10:07       ` Eli Zaretskii
2023-01-18 16:17   ` [PATCHv2 03/13] gdb: include breakpoint number in testing condition error message Andrew Burgess
2023-01-19  9:54     ` Aktemur, Tankut Baris
2023-01-19 10:54     ` Aktemur, Tankut Baris
2023-01-19 11:34       ` Eli Zaretskii
2023-01-20  9:46         ` Aktemur, Tankut Baris
2023-01-25 16:49           ` Andrew Burgess
2023-01-25 17:09             ` Eli Zaretskii
2023-01-18 16:18   ` [PATCHv2 04/13] gdbserver: allows agent_mem_read to return an error code Andrew Burgess
2023-01-19  9:59     ` Aktemur, Tankut Baris
2023-01-18 16:18   ` [PATCHv2 05/13] gdbserver: allow agent expressions to fail with invalid memory access Andrew Burgess
2023-01-19 10:13     ` Aktemur, Tankut Baris
2023-01-18 16:18   ` [PATCHv2 06/13] gdb: avoid repeated signal reporting during failed conditional breakpoint Andrew Burgess
2023-01-19 10:33     ` Aktemur, Tankut Baris
2023-01-18 16:18   ` [PATCHv2 07/13] gdb: don't always print breakpoint location after failed condition check Andrew Burgess
2023-01-19 10:49     ` Aktemur, Tankut Baris
2023-01-18 16:18   ` [PATCHv2 08/13] Revert "gdb: remove unnecessary parameter wait_ptid from do_target_wait" Andrew Burgess
2023-01-19 11:05     ` Aktemur, Tankut Baris
2023-01-18 16:18   ` [PATCHv2 09/13] gdb: fix b/p conditions with infcalls in multi-threaded inferiors Andrew Burgess
2023-01-20  7:13     ` Aktemur, Tankut Baris
2023-01-18 16:18   ` [PATCHv2 10/13] gdb: add timeouts for inferior function calls Andrew Burgess
2023-01-18 17:30     ` Eli Zaretskii
2023-01-20  8:50     ` Aktemur, Tankut Baris
2023-01-18 16:18   ` [PATCHv2 11/13] gdb/remote: avoid SIGINT after calling remote_target::stop Andrew Burgess
2023-01-20  9:14     ` Aktemur, Tankut Baris
2023-01-18 16:18   ` [PATCHv2 12/13] gdb: introduce unwind-on-timeout setting Andrew Burgess
2023-01-18 17:33     ` Eli Zaretskii
2023-01-20  9:26     ` Aktemur, Tankut Baris
2023-01-18 16:18   ` [PATCHv2 13/13] gdb: rename unwindonsignal to unwind-on-signal Andrew Burgess
2023-01-18 17:35     ` Eli Zaretskii
2023-01-20  9:34   ` [PATCHv2 00/13] Infcalls from B/P conditions in multi-threaded inferiors Aktemur, Tankut Baris
2023-01-25 15:53     ` Andrew Burgess
2023-02-16 11:09       ` Aktemur, Tankut Baris
2023-01-31 17:27   ` [PATCHv3 " Andrew Burgess
2023-01-31 17:27     ` [PATCHv3 01/13] gdb/doc: extended documentation for inferior function calls Andrew Burgess
2023-01-31 17:27     ` [PATCHv3 02/13] gdb/doc: extend the documentation for conditional breakpoints Andrew Burgess
2023-01-31 18:07       ` Eli Zaretskii
2023-02-01 17:47         ` Andrew Burgess
2023-02-01 18:25           ` Eli Zaretskii
2023-02-02 13:34             ` Andrew Burgess
2023-01-31 17:27     ` [PATCHv3 03/13] gdb: include breakpoint number in testing condition error message Andrew Burgess
2023-02-16 10:15       ` Aktemur, Tankut Baris
2023-01-31 17:27     ` [PATCHv3 04/13] gdbserver: allows agent_mem_read to return an error code Andrew Burgess
2023-01-31 17:27     ` [PATCHv3 05/13] gdbserver: allow agent expressions to fail with invalid memory access Andrew Burgess
2023-02-16 10:29       ` Aktemur, Tankut Baris
2023-01-31 17:27     ` [PATCHv3 06/13] gdb: avoid repeated signal reporting during failed conditional breakpoint Andrew Burgess
2023-01-31 17:27     ` [PATCHv3 07/13] gdb: don't always print breakpoint location after failed condition check Andrew Burgess
2023-01-31 17:27     ` [PATCHv3 08/13] Revert "gdb: remove unnecessary parameter wait_ptid from do_target_wait" Andrew Burgess
2023-01-31 17:27     ` [PATCHv3 09/13] gdb: fix b/p conditions with infcalls in multi-threaded inferiors Andrew Burgess
2023-02-16 10:47       ` Aktemur, Tankut Baris
2023-01-31 17:27     ` [PATCHv3 10/13] gdb: add timeouts for inferior function calls Andrew Burgess
2023-01-31 18:11       ` Eli Zaretskii
2023-02-01 17:50         ` Andrew Burgess
2023-02-01 18:29           ` Eli Zaretskii
2023-02-16 10:53       ` Aktemur, Tankut Baris
2023-01-31 17:27     ` [PATCHv3 11/13] gdb/remote: avoid SIGINT after calling remote_target::stop Andrew Burgess
2023-01-31 17:27     ` [PATCHv3 12/13] gdb: introduce unwind-on-timeout setting Andrew Burgess
2023-01-31 18:09       ` Eli Zaretskii
2023-02-16 11:01       ` Aktemur, Tankut Baris
2023-01-31 17:27     ` [PATCHv3 13/13] gdb: rename unwindonsignal to unwind-on-signal Andrew Burgess
2023-01-31 18:12       ` Eli Zaretskii
2023-02-28 16:42     ` [PATCHv4 00/12] Infcalls from B/P conditions in multi-threaded inferiors Andrew Burgess
2023-02-28 16:42       ` [PATCHv4 01/12] gdb/doc: extended documentation for inferior function calls Andrew Burgess
2024-03-21  9:03         ` Tom de Vries
2024-03-21  9:11           ` Tom de Vries
2023-02-28 16:42       ` [PATCHv4 02/12] gdb: include breakpoint number in testing condition error message Andrew Burgess
2023-02-28 16:42       ` [PATCHv4 03/12] gdbserver: allows agent_mem_read to return an error code Andrew Burgess
2023-02-28 16:42       ` [PATCHv4 04/12] gdbserver: allow agent expressions to fail with invalid memory access Andrew Burgess
2023-02-28 16:42       ` [PATCHv4 05/12] gdb: avoid repeated signal reporting during failed conditional breakpoint Andrew Burgess
2023-02-28 16:42       ` [PATCHv4 06/12] gdb: don't always print breakpoint location after failed condition check Andrew Burgess
2023-02-28 16:42       ` [PATCHv4 07/12] Revert "gdb: remove unnecessary parameter wait_ptid from do_target_wait" Andrew Burgess
2023-02-28 16:42       ` [PATCHv4 08/12] gdb: fix b/p conditions with infcalls in multi-threaded inferiors Andrew Burgess
2023-02-28 16:42       ` [PATCHv4 09/12] gdb: add timeouts for inferior function calls Andrew Burgess
2023-02-28 16:42       ` [PATCHv4 10/12] gdb/remote: avoid SIGINT after calling remote_target::stop Andrew Burgess
2023-02-28 16:42       ` [PATCHv4 11/12] gdb: introduce unwind-on-timeout setting Andrew Burgess
2023-02-28 16:42       ` [PATCHv4 12/12] gdb: rename unwindonsignal to unwind-on-signal Andrew Burgess
2023-03-16 17:36       ` [PATCHv5 00/11] Infcalls from B/P conditions in multi-threaded inferiors Andrew Burgess
2023-03-16 17:36         ` [PATCHv5 01/11] gdb: include breakpoint number in testing condition error message Andrew Burgess
2023-04-03 13:50           ` Andrew Burgess
2023-07-07 12:08           ` Pedro Alves
2023-07-07 15:43             ` Andrew Burgess
2023-07-07 16:19               ` Pedro Alves
2023-07-10 10:30                 ` Andrew Burgess
2023-03-16 17:36         ` [PATCHv5 02/11] gdbserver: allows agent_mem_read to return an error code Andrew Burgess
2023-04-03 13:50           ` Andrew Burgess
2023-03-16 17:36         ` [PATCHv5 03/11] gdbserver: allow agent expressions to fail with invalid memory access Andrew Burgess
2023-04-03 13:50           ` Andrew Burgess
2023-07-07 12:25           ` Pedro Alves
2023-07-07 16:28             ` Andrew Burgess
2023-07-07 17:26               ` Pedro Alves
2023-07-07 21:19                 ` Andrew Burgess
2023-07-10 10:32                 ` Andrew Burgess
2023-07-10 10:44                   ` Pedro Alves
2023-07-10 13:44                     ` Andrew Burgess
2023-03-16 17:36         ` [PATCHv5 04/11] gdb: avoid repeated signal reporting during failed conditional breakpoint Andrew Burgess
2023-04-03 13:50           ` Andrew Burgess
2023-03-16 17:37         ` [PATCHv5 05/11] gdb: don't always print breakpoint location after failed condition check Andrew Burgess
2023-04-03 13:51           ` Andrew Burgess
2023-07-07 15:20           ` Pedro Alves
2023-07-07 15:24             ` Pedro Alves
2023-07-07 21:18               ` Andrew Burgess
2023-07-11 12:06                 ` Pedro Alves
2023-07-14 12:17                   ` Andrew Burgess
2023-07-17 17:17                     ` Pedro Alves
2023-08-03 13:57                       ` Andrew Burgess
2023-03-16 17:37         ` [PATCHv5 06/11] Revert "gdb: remove unnecessary parameter wait_ptid from do_target_wait" Andrew Burgess
2023-03-16 17:37         ` [PATCHv5 07/11] gdb: fix b/p conditions with infcalls in multi-threaded inferiors Andrew Burgess
2023-03-16 17:37         ` [PATCHv5 08/11] gdb: add timeouts for inferior function calls Andrew Burgess
2023-03-16 17:37         ` [PATCHv5 09/11] gdb/remote: avoid SIGINT after calling remote_target::stop Andrew Burgess
2023-03-16 17:37         ` [PATCHv5 10/11] gdb: introduce unwind-on-timeout setting Andrew Burgess
2023-03-16 17:37         ` [PATCHv5 11/11] gdb: rename unwindonsignal to unwind-on-signal Andrew Burgess
2023-04-03 14:01         ` [PATCHv6 0/6] Infcalls from B/P conditions in multi-threaded inferiors Andrew Burgess
2023-04-03 14:01           ` [PATCHv6 1/6] Revert "gdb: remove unnecessary parameter wait_ptid from do_target_wait" Andrew Burgess
2023-04-03 14:01           ` [PATCHv6 2/6] gdb: fix b/p conditions with infcalls in multi-threaded inferiors Andrew Burgess
2023-04-03 14:01           ` [PATCHv6 3/6] gdb: add timeouts for inferior function calls Andrew Burgess
2023-07-11 14:23             ` Pedro Alves
2023-07-14 15:20               ` Andrew Burgess
2023-07-14 19:52                 ` Andrew Burgess
2023-04-03 14:01           ` [PATCHv6 4/6] gdb/remote: avoid SIGINT after calling remote_target::stop Andrew Burgess
2023-04-03 14:01           ` [PATCHv6 5/6] gdb: introduce unwind-on-timeout setting Andrew Burgess
2023-04-03 14:01           ` [PATCHv6 6/6] gdb: rename unwindonsignal to unwind-on-signal Andrew Burgess
2023-05-15 19:22           ` [PATCHv7 0/6] Infcalls from B/P conditions in multi-threaded inferiors Andrew Burgess
2023-05-15 19:22             ` [PATCHv7 1/6] Revert "gdb: remove unnecessary parameter wait_ptid from do_target_wait" Andrew Burgess
2023-05-16 15:08               ` Aktemur, Tankut Baris
2023-05-15 19:22             ` [PATCHv7 2/6] gdb: fix b/p conditions with infcalls in multi-threaded inferiors Andrew Burgess
2023-05-16 15:09               ` Aktemur, Tankut Baris
2023-06-05 13:53                 ` Andrew Burgess [this message]
2023-05-15 19:22             ` [PATCHv7 3/6] gdb: add timeouts for inferior function calls Andrew Burgess
2023-05-16 15:42               ` Aktemur, Tankut Baris
2023-06-05 13:54                 ` Andrew Burgess
2023-05-15 19:22             ` [PATCHv7 4/6] gdb/remote: avoid SIGINT after calling remote_target::stop Andrew Burgess
2023-05-16 16:00               ` Aktemur, Tankut Baris
2023-06-05 13:55                 ` Andrew Burgess
2023-05-15 19:22             ` [PATCHv7 5/6] gdb: introduce unwind-on-timeout setting Andrew Burgess
2023-05-15 19:22             ` [PATCHv7 6/6] gdb: rename unwindonsignal to unwind-on-signal Andrew Burgess
2023-06-07 10:01             ` [PATCHv8 0/6] Infcalls from B/P conditions in multi-threaded inferiors Andrew Burgess
2023-06-07 10:01               ` [PATCHv8 1/6] Revert "gdb: remove unnecessary parameter wait_ptid from do_target_wait" Andrew Burgess
2023-06-07 10:01               ` [PATCHv8 2/6] gdb: fix b/p conditions with infcalls in multi-threaded inferiors Andrew Burgess
2023-06-07 10:01               ` [PATCHv8 3/6] gdb: add timeouts for inferior function calls Andrew Burgess
2023-06-07 10:01               ` [PATCHv8 4/6] gdb/remote: avoid SIGINT after calling remote_target::stop Andrew Burgess
2023-07-07 17:18                 ` Pedro Alves
2023-07-10 20:04                   ` Andrew Burgess
2023-06-07 10:01               ` [PATCHv8 5/6] gdb: introduce unwind-on-timeout setting Andrew Burgess
2023-06-07 10:01               ` [PATCHv8 6/6] gdb: rename unwindonsignal to unwind-on-signal Andrew Burgess
2023-06-07 12:41                 ` Eli Zaretskii
2023-06-07 14:29                   ` Andrew Burgess
2023-06-07 15:31                     ` Eli Zaretskii
2023-07-04 11:20               ` [PATCHv8 0/6] Infcalls from B/P conditions in multi-threaded inferiors Andrew Burgess
2023-12-02 10:52               ` [PATCHv9 0/5] " Andrew Burgess
2023-12-02 10:52                 ` [PATCHv9 1/5] Revert "gdb: remove unnecessary parameter wait_ptid from do_target_wait" Andrew Burgess
2023-12-02 10:52                 ` [PATCHv9 2/5] gdb: fix b/p conditions with infcalls in multi-threaded inferiors Andrew Burgess
2023-12-02 10:52                 ` [PATCHv9 3/5] gdb: add timeouts for inferior function calls Andrew Burgess
2023-12-02 10:52                 ` [PATCHv9 4/5] gdb: introduce unwind-on-timeout setting Andrew Burgess
2023-12-02 10:52                 ` [PATCHv9 5/5] gdb: rename unwindonsignal to unwind-on-signal Andrew Burgess
2024-01-02 15:57                 ` [PATCHv10 0/5] Infcalls from B/P conditions in multi-threaded inferiors Andrew Burgess
2024-01-02 15:57                   ` [PATCHv10 1/5] Revert "gdb: remove unnecessary parameter wait_ptid from do_target_wait" Andrew Burgess
2024-01-02 15:57                   ` [PATCHv10 2/5] gdb: fix b/p conditions with infcalls in multi-threaded inferiors Andrew Burgess
2024-01-02 15:57                   ` [PATCHv10 3/5] gdb: add timeouts for inferior function calls Andrew Burgess
2024-01-02 15:57                   ` [PATCHv10 4/5] gdb: introduce unwind-on-timeout setting Andrew Burgess
2024-01-02 15:57                   ` [PATCHv10 5/5] gdb: rename unwindonsignal to unwind-on-signal Andrew Burgess
2024-03-05 15:40                   ` [PATCHv11 0/5] Infcalls from B/P conditions in multi-threaded inferiors Andrew Burgess
2024-03-05 15:40                     ` [PATCHv11 1/5] Revert "gdb: remove unnecessary parameter wait_ptid from do_target_wait" Andrew Burgess
2024-03-05 15:40                     ` [PATCHv11 2/5] gdb: fix b/p conditions with infcalls in multi-threaded inferiors Andrew Burgess
2024-03-05 15:40                     ` [PATCHv11 3/5] gdb: add timeouts for inferior function calls Andrew Burgess
2024-03-05 15:40                     ` [PATCHv11 4/5] gdb: introduce unwind-on-timeout setting Andrew Burgess
2024-03-05 15:40                     ` [PATCHv11 5/5] gdb: rename unwindonsignal to unwind-on-signal Andrew Burgess
2024-03-14 16:08                     ` [PATCHv11 0/5] Infcalls from B/P conditions in multi-threaded inferiors Keith Seitz
2024-03-15 13:26                     ` Luis Machado
2024-03-25 17:47                     ` Andrew Burgess

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=875y823tj6.fsf@redhat.com \
    --to=aburgess@redhat.com \
    --cc=gdb-patches@sourceware.org \
    --cc=natalia.saiapova@intel.com \
    --cc=tankut.baris.aktemur@intel.com \
    /path/to/YOUR_REPLY

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

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