Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Andrew Burgess via Gdb-patches <gdb-patches@sourceware.org>
To: Simon Marchi via Gdb-patches <gdb-patches@sourceware.org>,
	gdb-patches@sourceware.org
Cc: Simon Marchi <simon.marchi@efficios.com>
Subject: Re: [PATCH] gdb: make "start" breakpoint inferior-specific
Date: Thu, 01 Sep 2022 11:42:38 +0100	[thread overview]
Message-ID: <87ler3cr4x.fsf@redhat.com> (raw)
In-Reply-To: <20220804174035.2441960-1-simon.marchi@efficios.com>

Simon Marchi via Gdb-patches <gdb-patches@sourceware.org> writes:

> I saw this failure on a CI:
>
>     (gdb) add-inferior
>     [New inferior 2]
>     Added inferior 2
>     (gdb) PASS: gdb.threads/vfork-multi-inferior.exp: method=non-stop: add-inferior
>     inferior 2
>     [Switching to inferior 2 [<null>] (<noexec>)]
>     (gdb) PASS: gdb.threads/vfork-multi-inferior.exp: method=non-stop: inferior 2
>     kill
>     The program is not being run.
>     (gdb) file /home/jenkins/workspace/binutils-gdb_master_linuxbuild/platform/jammy-amd64/target_board/unix/tmp/tmp.GYATAXR8Ku/gdb/testsuite/outputs/gdb.threads/vfork-multi-inferior/vfork-multi-inferior-sleep
>     Reading symbols from /home/jenkins/workspace/binutils-gdb_master_linuxbuild/platform/jammy-amd64/target_board/unix/tmp/tmp.GYATAXR8Ku/gdb/testsuite/outputs/gdb.threads/vfork-multi-inferior/vfork-multi-inferior-sleep...
>     (gdb) run &
>     Starting program: /home/jenkins/workspace/binutils-gdb_master_linuxbuild/platform/jammy-amd64/target_board/unix/tmp/tmp.GYATAXR8Ku/gdb/testsuite/outputs/gdb.threads/vfork-multi-inferior/vfork-multi-inferior-sleep
>     (gdb) PASS: gdb.threads/vfork-multi-inferior.exp: method=non-stop: run inferior 2
>     inferior 1
>     [Switching to inferior 1 [<null>] (<noexec>)]
>     (gdb) PASS: gdb.threads/vfork-multi-inferior.exp: method=non-stop: inferior 1
>     kill
>     The program is not being run.
>     (gdb) file /home/jenkins/workspace/binutils-gdb_master_linuxbuild/platform/jammy-amd64/target_board/unix/tmp/tmp.GYATAXR8Ku/gdb/testsuite/outputs/gdb.threads/vfork-multi-inferior/vfork-multi-inferior
>     Reading symbols from /home/jenkins/workspace/binutils-gdb_master_linuxbuild/platform/jammy-amd64/target_board/unix/tmp/tmp.GYATAXR8Ku/gdb/testsuite/outputs/gdb.threads/vfork-multi-inferior/vfork-multi-inferior...
>     (gdb) break should_break_here
>     Breakpoint 1 at 0x11b1: file /home/jenkins/workspace/binutils-gdb_master_linuxbuild/platform/jammy-amd64/target_board/unix/src/binutils-gdb/gdb/testsuite/gdb.threads/vfork-multi-inferior.c, line 25.
>     (gdb) PASS: gdb.threads/vfork-multi-inferior.exp: method=non-stop: break should_break_here
>     [Thread debugging using libthread_db enabled]
>     Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
>     start
>     Temporary breakpoint 2 at 0x11c0: -qualified main. (2 locations)
>     Starting program: /home/jenkins/workspace/binutils-gdb_master_linuxbuild/platform/jammy-amd64/target_board/unix/tmp/tmp.GYATAXR8Ku/gdb/testsuite/outputs/gdb.threads/vfork-multi-inferior/vfork-multi-inferior
>     [Thread debugging using libthread_db enabled]
>     Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
>
>     Thread 2.1 "vfork-multi-inf" hit Temporary breakpoint 2, main () at /home/jenkins/workspace/binutils-gdb_master_linuxbuild/platform/jammy-amd64/target_board/unix/src/binutils-gdb/gdb/testsuite/gdb.threads/vfork-multi-inferior-sleep.c:23
>     23	  sleep (30);
>     (gdb) FAIL: gdb.threads/vfork-multi-inferior.exp: method=non-stop: start inferior 1
>
> What happens is:
>
>  1. We start inferior 2 with "run&", it runs very slowly, takes time to
>     get to main
>  2. We switch to inferior 1, and run "start"
>  3. The temporary breakpoint inserted by "start" applies to all inferiors
>  4. Inferior 2 hits that breakpoint and GDB reports that hit
>
> To avoid this, breakpoints inserted by "start" should be
> inferior-specific.  However, we don't have a nice way to make
> inferior-specific breakpoints yet.  It's possible to make
> pspace-specific breakpoints (for example how the internal_breakpoint
> constructor does) by creating a symtab_and_line manually.  However,
> inferiors can share program spaces (usually on particular embedded
> targets), so we could have a situation where two inferiors run the same
> code in the same program space.  In that case, it would just not be
> possible to insert a breakpoint in one inferior but not the other.
>
> A simple solution that should work all the time is to add a condition to
> the breakpoint inserted by "start", to check the inferior reporting the
> hit is the expected one.  This is what this patch implements.
>
> Add a test that does:
>
>  - start a background inferior 1 that calls main in a loop
>  - start aninferior 2 with the "start" command
>  - validate that we hit the breakpoint in inferior 2
>
> Without the fix, we hit the breakpoint in inferior 1 pretty much all the
> time.
>
> Change-Id: Ib0148498a476bfa634ed62353c95f163623c686a
> ---
>  gdb/infcmd.c                                  |  3 +-
>  .../gdb.multi/start-inferior-specific-other.c | 30 ++++++++++
>  .../gdb.multi/start-inferior-specific.c       | 22 +++++++
>  .../gdb.multi/start-inferior-specific.exp     | 58 +++++++++++++++++++
>  4 files changed, 112 insertions(+), 1 deletion(-)
>  create mode 100644 gdb/testsuite/gdb.multi/start-inferior-specific-other.c
>  create mode 100644 gdb/testsuite/gdb.multi/start-inferior-specific.c
>  create mode 100644 gdb/testsuite/gdb.multi/start-inferior-specific.exp
>
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index 69a7896b560..e9107cef520 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -423,7 +423,8 @@ run_command_1 (const char *args, int from_tty, enum run_how run_how)
>    /* Insert temporary breakpoint in main function if requested.  */
>    if (run_how == RUN_STOP_AT_MAIN)
>      {
> -      std::string arg = string_printf ("-qualified %s", main_name ());
> +      std::string arg = string_printf ("-qualified %s if $_inferior == %d", main_name (),
> +				       current_inferior ()->num);
>        tbreak_command (arg.c_str (), 0);
>      }
>  
> diff --git a/gdb/testsuite/gdb.multi/start-inferior-specific-other.c b/gdb/testsuite/gdb.multi/start-inferior-specific-other.c
> new file mode 100644
> index 00000000000..b593c3aa068
> --- /dev/null
> +++ b/gdb/testsuite/gdb.multi/start-inferior-specific-other.c
> @@ -0,0 +1,30 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 2022 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/>.  */
> +
> +#include <stdlib.h>
> +
> +int
> +main (int argc, const char **argv)
> +{
> +  if (argc == 999)
> +    return 0;
> +
> +  for (;;)
> +    main (999, NULL);
> +
> +  return 0;
> +}

I think test cases like this should have an `alarm` call, just in case
something goes wrong, this'll stop the test running forever.

> diff --git a/gdb/testsuite/gdb.multi/start-inferior-specific.c b/gdb/testsuite/gdb.multi/start-inferior-specific.c
> new file mode 100644
> index 00000000000..b69e218962a
> --- /dev/null
> +++ b/gdb/testsuite/gdb.multi/start-inferior-specific.c
> @@ -0,0 +1,22 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 2022 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/>.  */
> +
> +int
> +main ()
> +{
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.multi/start-inferior-specific.exp b/gdb/testsuite/gdb.multi/start-inferior-specific.exp
> new file mode 100644
> index 00000000000..5a5572f591a
> --- /dev/null
> +++ b/gdb/testsuite/gdb.multi/start-inferior-specific.exp
> @@ -0,0 +1,58 @@
> +# Copyright 2022 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 that "start"ing an inferior does not inadvertently stop in another
> +# inferior.
> +#
> +# To achieve this, we have an inferior (the  "other") running in background
> +# constantly re-calling main.  We then "start" a second inferior.  A buggy GDB
> +# would report a breakpoint hit in "other".
> +
> +standard_testfile .c -other.c
> +
> +if { [use_gdb_stub] } {
> +    return
> +}
> +
> +set srcfile_other ${srcfile2}
> +set binfile_other ${binfile}-other
> +
> +if { [build_executable ${testfile}.exp ${binfile} "${srcfile}" {debug}] != 0 } {
> +    return -1
> +}
> +
> +if { [build_executable ${testfile}.exp ${binfile_other} "${srcfile_other}" {debug}] != 0 } {
> +    return -1
> +}
> +
> +proc do_test {} {
> +    # With remote, to be able to start an inferior while another one is
> +    # running, we need to use the non-stop variant of the protocol.
> +    save_vars { ::GDBFLAGS } {
> +	if { [target_info gdb_protocol] == "extended-remote"} {
> +	    append ::GDBFLAGS " -ex \"maintenance set target-non-stop on\""
> +	}
> +
> +	clean_restart ${::binfile_other}
> +    }
> +
> +    gdb_test "run&" "Starting program: .*" "start background inferior"
> +    gdb_test "add-inferior" "Added inferior 2.*"
> +    gdb_test "inferior 2" "Switching to inferior 2.*"
> +    gdb_file_cmd ${::binfile}
> +    gdb_test "start" "Thread 2.1 .* hit Temporary breakpoint .*"

I'm pretty sure there's a race here.  We could set the breakpoint for
the 'start', start inferior 2 executing, hit the b/p and remove it, all
within the time it takes inferior 1 to perform a single iteration ... in
theory, though it does seem unlikely.

If, before the `start` you did `break *main` then we should hit the
`*main` breakpoint before the temporary `start` breakpoint, the
temporary breakpoint is left in place, which gives inferior 1 additional
time to not hit the breakpoint.

Of course, this relies on the `*main` and `start` breakpoints being at
different addresses, which should be the case if main has some prologue
to skip over.

I guess, ideally we would also do something to confirm that inferior 1
has gone past main while the temporary breakpoint is in place, right now
we're just relying on inferior 1 running fast enough.

In general I'm happy enough with the actual GDB change you propose here,
but like Bruno, I also wondered if it would be better to add inferior
specific breakpoints as an actual thing, rather than relying on the
condition logic like you do here?

I wasn't sure how you'd feel about this idea, so I didn't spend too
long, but below is a VERY rough proof of concept patch, that appies on
top of yours, that adds inferior specific breakpoints.  You temporary
breakpoint now becomes:

  tbreak -qualified main inferior 1

But this functionality would also be available to a user if they wanted
it, which might be nice.

When I say the code below is rough, I really mean it, here's a list of
things I think still need doing:

  * I initially added a `breakpoint::inferior` field just like we have a
    `breakpoint::thread` field, but I think a better solution would be
    to change `breakpoint::thread` into a ptid_t and store inferior and
    thread information in that one field,

  * Obviously it should give an error if a user specifies both `thread`
    and `inferior` for a breakpoint,

  * The `info breakpoints` output is fine for single location
    breakpoints, but I think multi-location breakpoints would need
    sorting out still,

  * There's a couple of TODO comments in there still to address,

  * Need to write docs, NEWS, and add tests,

Like I said, you might see a reason why this is a bad idea, so I didn't
want to put any more work in without having a discussion about the idea.

Thoughts?

Thanks,
Andrew

---

commit 26a101c678cd14828cbd7f8c15240854a50c91e2
Author: Andrew Burgess <aburgess@redhat.com>
Date:   Thu Sep 1 10:44:27 2022 +0100

    wip: per-inferior breakpoints

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 63feea9e9cd..2ea453ff2c4 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -96,7 +96,7 @@ static void create_breakpoints_sal (struct gdbarch *,
 				    gdb::unique_xmalloc_ptr<char>,
 				    gdb::unique_xmalloc_ptr<char>,
 				    enum bptype,
-				    enum bpdisp, int, int,
+				    enum bpdisp, int, int, int,
 				    int,
 				    int, int, int, unsigned);
 
@@ -3101,6 +3101,17 @@ update_inserted_breakpoint_locations (void)
     }
 }
 
+static bool
+valid_global_inferior_id (int id)
+{
+  for (inferior *inf : all_inferiors ())
+    if (inf->num == id)
+      return true;
+
+  return false;
+}
+
+
 /* Used when starting or continuing the program.  */
 
 static void
@@ -3132,6 +3143,10 @@ insert_breakpoint_locations (void)
 	  && !valid_global_thread_id (bl->owner->thread))
 	continue;
 
+      if (bl->owner->inferior != -1
+	  && !valid_global_inferior_id (bl->owner->inferior))
+	continue;
+
       switch_to_program_space_and_thread (bl->pspace);
 
       /* For targets that support global breakpoints, there's no need
@@ -3236,6 +3251,27 @@ Thread-specific breakpoint %d deleted - thread %s no longer in the thread list.\
     }
 }
 
+/* ... */
+
+static void
+remove_inferior_breakpoints (struct inferior *inf)
+{
+  for (breakpoint *b : all_breakpoints_safe ())
+    {
+      if (b->inferior == inf->num && user_breakpoint_p (b))
+	{
+	  b->disposition = disp_del_at_next_stop;
+
+	  gdb_printf (_("\
+Inferior-specific breakpoint %d deleted - inferior %d has exited.\n"),
+		      b->number, inf->num);
+
+	  /* Hide it from the user.  */
+	  b->number = 0;
+       }
+    }
+}
+
 /* See breakpoint.h.  */
 
 void
@@ -5331,6 +5367,7 @@ bpstat_check_breakpoint_conditions (bpstat *bs, thread_info *thread)
      evaluating the condition if this isn't the specified
      thread/task.  */
   if ((b->thread != -1 && b->thread != thread->global_num)
+      || (b->inferior != -1 && b->inferior != thread->inf->num)
       || (b->task != 0 && b->task != ada_get_task_number (thread)))
     {
       bs->stop = 0;
@@ -6339,6 +6376,11 @@ print_one_breakpoint_location (struct breakpoint *b,
 	  uiout->text (" task ");
 	  uiout->field_signed ("task", b->task);
 	}
+      else if (b->inferior != -1)
+	{
+	  uiout->text (" inferior ");
+	  uiout->field_signed ("inferior", b->inferior);
+	}
     }
 
   uiout->text ("\n");
@@ -6384,16 +6426,34 @@ print_one_breakpoint_location (struct breakpoint *b,
       /* FIXME should make an annotation for this.  */
       uiout->text ("\tstop only in thread ");
       if (uiout->is_mi_like_p ())
-	uiout->field_signed ("thread", b->thread);
+	{
+	  uiout->field_signed ("thread", b->thread);
+	}
       else
 	{
 	  struct thread_info *thr = find_thread_global_id (b->thread);
 
 	  uiout->field_string ("thread", print_thread_id (thr));
+	  uiout->field_signed ("thread", b->inferior);
 	}
       uiout->text ("\n");
     }
-  
+
+  if (!part_of_multiple && b->inferior != -1)
+    {
+      /* FIXME should make an annotation for this.  */
+      uiout->text ("\tstop only in inferior ");
+      if (uiout->is_mi_like_p ())
+	{
+	  uiout->field_signed ("inferior", b->inferior);
+	}
+      else
+	{
+	  uiout->field_signed ("inferior", b->inferior);
+	}
+      uiout->text ("\n");
+    }
+
   if (!part_of_multiple)
     {
       if (b->hit_count)
@@ -7366,7 +7426,10 @@ delete_longjmp_breakpoint (int thread)
     if (b->type == bp_longjmp || b->type == bp_exception)
       {
 	if (b->thread == thread)
-	  delete_breakpoint (b);
+	  {
+	    gdb_assert (b->inferior == -1);
+	    delete_breakpoint (b);
+	  }
       }
 }
 
@@ -7377,7 +7440,10 @@ delete_longjmp_breakpoint_at_next_stop (int thread)
     if (b->type == bp_longjmp || b->type == bp_exception)
       {
 	if (b->thread == thread)
-	  b->disposition = disp_del_at_next_stop;
+	  {
+	    gdb_assert (b->inferior == -1);
+	    b->disposition = disp_del_at_next_stop;
+	  }
       }
 }
 
@@ -7430,6 +7496,7 @@ check_longjmp_breakpoint_for_call_dummy (struct thread_info *tp)
   ALL_BREAKPOINTS_SAFE (b, b_tmp)
     if (b->type == bp_longjmp_call_dummy && b->thread == tp->global_num)
       {
+	gdb_assert (b->inferior == -1);
 	struct breakpoint *dummy_b = b->related_breakpoint;
 
 	/* Find the bp_call_dummy breakpoint in the list of breakpoints
@@ -8263,7 +8330,8 @@ code_breakpoint::code_breakpoint (struct gdbarch *gdbarch_,
 				  gdb::unique_xmalloc_ptr<char> cond_string_,
 				  gdb::unique_xmalloc_ptr<char> extra_string_,
 				  enum bpdisp disposition_,
-				  int thread_, int task_, int ignore_count_,
+				  int thread_, int task_, int inferior_,
+				  int ignore_count_,
 				  int from_tty,
 				  int enabled_, unsigned flags,
 				  int display_canonical_)
@@ -8289,6 +8357,7 @@ code_breakpoint::code_breakpoint (struct gdbarch *gdbarch_,
 
   thread = thread_;
   task = task_;
+  inferior = inferior_;
 
   cond_string = std::move (cond_string_);
   extra_string = std::move (extra_string_);
@@ -8390,7 +8459,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
 		       gdb::unique_xmalloc_ptr<char> cond_string,
 		       gdb::unique_xmalloc_ptr<char> extra_string,
 		       enum bptype type, enum bpdisp disposition,
-		       int thread, int task, int ignore_count,
+		       int thread, int task, int inferior, int ignore_count,
 		       int from_tty,
 		       int enabled, int internal, unsigned flags,
 		       int display_canonical)
@@ -8404,7 +8473,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
 				std::move (cond_string),
 				std::move (extra_string),
 				disposition,
-				thread, task, ignore_count,
+				thread, task, inferior, ignore_count,
 				from_tty,
 				enabled, flags,
 				display_canonical);
@@ -8433,7 +8502,8 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
 			gdb::unique_xmalloc_ptr<char> cond_string,
 			gdb::unique_xmalloc_ptr<char> extra_string,
 			enum bptype type, enum bpdisp disposition,
-			int thread, int task, int ignore_count,
+			int thread, int task, int inferior,
+			int ignore_count,
 			int from_tty,
 			int enabled, int internal, unsigned flags)
 {
@@ -8457,7 +8527,7 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
 			     std::move (cond_string),
 			     std::move (extra_string),
 			     type, disposition,
-			     thread, task, ignore_count,
+			     thread, task, inferior, ignore_count,
 			     from_tty, enabled, internal, flags,
 			     canonical->special_display);
     }
@@ -8597,11 +8667,12 @@ check_fast_tracepoint_sals (struct gdbarch *gdbarch,
 static void
 find_condition_and_thread (const char *tok, CORE_ADDR pc,
 			   gdb::unique_xmalloc_ptr<char> *cond_string,
-			   int *thread, int *task,
+			   int *thread, int *inferior, int *task,
 			   gdb::unique_xmalloc_ptr<char> *rest)
 {
   cond_string->reset ();
   *thread = -1;
+  *inferior = -1;
   *task = 0;
   rest->reset ();
   bool force = false;
@@ -8659,6 +8730,16 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
 	  *thread = thr->global_num;
 	  tok = tmptok;
 	}
+      else if (toklen >= 1 && strncmp (tok, "inferior", toklen) == 0)
+	{
+	  char *tmptok;
+
+	  tok = end_tok + 1;
+	  *inferior = strtol (tok, &tmptok, 0);
+	  if (tok == tmptok)
+	    error (_("Junk after thread keyword."));
+	  tok = tmptok;
+	}
       else if (toklen >= 1 && strncmp (tok, "task", toklen) == 0)
 	{
 	  char *tmptok;
@@ -8690,7 +8771,7 @@ static void
 find_condition_and_thread_for_sals (const std::vector<symtab_and_line> &sals,
 				    const char *input,
 				    gdb::unique_xmalloc_ptr<char> *cond_string,
-				    int *thread, int *task,
+				    int *thread, int *inferior, int *task,
 				    gdb::unique_xmalloc_ptr<char> *rest)
 {
   int num_failures = 0;
@@ -8698,6 +8779,7 @@ find_condition_and_thread_for_sals (const std::vector<symtab_and_line> &sals,
     {
       gdb::unique_xmalloc_ptr<char> cond;
       int thread_id = 0;
+      int inferior_id = 0;
       int task_id = 0;
       gdb::unique_xmalloc_ptr<char> remaining;
 
@@ -8710,9 +8792,10 @@ find_condition_and_thread_for_sals (const std::vector<symtab_and_line> &sals,
       try
 	{
 	  find_condition_and_thread (input, sal.pc, &cond, &thread_id,
-				     &task_id, &remaining);
+				     &inferior_id, &task_id, &remaining);
 	  *cond_string = std::move (cond);
 	  *thread = thread_id;
+	  *inferior = inferior_id;
 	  *task = task_id;
 	  *rest = std::move (remaining);
 	  break;
@@ -8814,6 +8897,7 @@ create_breakpoint (struct gdbarch *gdbarch,
   struct linespec_result canonical;
   int pending = 0;
   int task = 0;
+  int inferior = 0;
   int prev_bkpt_count = breakpoint_count;
 
   gdb_assert (ops != NULL);
@@ -8891,7 +8975,8 @@ create_breakpoint (struct gdbarch *gdbarch,
 	  const linespec_sals &lsal = canonical.lsals[0];
 
 	  find_condition_and_thread_for_sals (lsal.sals, extra_string,
-					      &cond, &thread, &task, &rest);
+					      &cond, &thread, &inferior,
+					      &task, &rest);
 	  cond_string_copy = std::move (cond);
 	  extra_string_copy = std::move (rest);
 	}
@@ -8941,7 +9026,7 @@ create_breakpoint (struct gdbarch *gdbarch,
 				   std::move (extra_string_copy),
 				   type_wanted,
 				   tempflag ? disp_del : disp_donttouch,
-				   thread, task, ignore_count,
+				   thread, task, inferior, ignore_count,
 				   from_tty, enabled, internal, flags);
     }
   else
@@ -9886,6 +9971,7 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
   const char *cond_end = NULL;
   enum bptype bp_type;
   int thread = -1;
+  int inferior = -1;
   /* Flag to indicate whether we are going to use masks for
      the hardware watchpoint.  */
   bool use_mask = false;
@@ -9956,6 +10042,15 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
 	      if (!valid_task_id (task))
 		error (_("Unknown task %d."), task);
 	    }
+	  else if (toklen == 8 && startswith (tok, "inferior"))
+	    {
+	      char *tmp;
+
+	      inferior = strtol (value_start, &tmp, 0);
+	      if (tmp == value_start)
+		error (_("Junk after task keyword."));
+	      /* TODO: Validate the inferior number.  */
+	    }
 	  else if (toklen == 4 && startswith (tok, "mask"))
 	    {
 	      /* We've found a "mask" token, which means the user wants to
@@ -10127,6 +10222,7 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
     w.reset (new watchpoint (nullptr, bp_type));
 
   w->thread = thread;
+  w->inferior = inferior;
   w->task = task;
   w->disposition = disp_donttouch;
   w->pspace = current_program_space;
@@ -12026,7 +12122,8 @@ strace_marker_create_breakpoints_sal (struct gdbarch *gdbarch,
 				      enum bptype type_wanted,
 				      enum bpdisp disposition,
 				      int thread,
-				      int task, int ignore_count,
+				      int task, int inferior,
+				      int ignore_count,
 				      int from_tty, int enabled,
 				      int internal, unsigned flags)
 {
@@ -12052,7 +12149,8 @@ strace_marker_create_breakpoints_sal (struct gdbarch *gdbarch,
 			 std::move (cond_string),
 			 std::move (extra_string),
 			 disposition,
-			 thread, task, ignore_count,
+			 /* TODO: Inferior.  */
+			 thread, task, -1, ignore_count,
 			 from_tty, enabled, flags,
 			 canonical->special_display));
 
@@ -12685,10 +12783,11 @@ code_breakpoint::location_spec_to_sals (location_spec *locspec,
       if (condition_not_parsed && extra_string != NULL)
 	{
 	  gdb::unique_xmalloc_ptr<char> local_cond, local_extra;
-	  int local_thread, local_task;
+	  int local_thread, local_task, local_inferior;
 
 	  find_condition_and_thread_for_sals (sals, extra_string.get (),
 					      &local_cond, &local_thread,
+					      &local_inferior,
 					      &local_task, &local_extra);
 	  gdb_assert (cond_string == nullptr);
 	  if (local_cond != nullptr)
@@ -14806,4 +14905,6 @@ This is useful for formatted output in user-defined commands."));
 					   "breakpoint");
   gdb::observers::thread_exit.attach (remove_threaded_breakpoints,
 				      "breakpoint");
+  gdb::observers::inferior_exit.attach (remove_inferior_breakpoints,
+					"breakpoint");
 }
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 360fa760577..f1df5128c0e 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -584,7 +584,7 @@ struct breakpoint_ops
 				  struct linespec_result *,
 				  gdb::unique_xmalloc_ptr<char>,
 				  gdb::unique_xmalloc_ptr<char>,
-				  enum bptype, enum bpdisp, int, int,
+				  enum bptype, enum bpdisp, int, int, int,
 				  int, int, int, int, unsigned);
 };
 
@@ -801,6 +801,9 @@ struct breakpoint
      care.  */
   int thread = -1;
 
+  /* ... */
+  int inferior = -1;
+
   /* Ada task number for task-specific breakpoint, or 0 if don't
      care.  */
   int task = 0;
@@ -856,7 +859,7 @@ struct code_breakpoint : public breakpoint
 		   gdb::unique_xmalloc_ptr<char> cond_string,
 		   gdb::unique_xmalloc_ptr<char> extra_string,
 		   enum bpdisp disposition,
-		   int thread, int task, int ignore_count,
+		   int thread, int task, int inferior, int ignore_count,
 		   int from_tty,
 		   int enabled, unsigned flags,
 		   int display_canonical);
diff --git a/gdb/dummy-frame.c b/gdb/dummy-frame.c
index 40b455c7e4a..5e48dca2982 100644
--- a/gdb/dummy-frame.c
+++ b/gdb/dummy-frame.c
@@ -132,6 +132,7 @@ pop_dummy_frame_bpt (struct breakpoint *b, struct dummy_frame *dummy)
   if (b->thread == dummy->id.thread->global_num
       && b->disposition == disp_del && frame_id_eq (b->frame_id, dummy->id.id))
     {
+      gdb_assert (b->inferior == -1);
       while (b->related_breakpoint != b)
 	delete_breakpoint (b->related_breakpoint);
 
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 13dbaf0227a..0087b19b44b 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -947,7 +947,10 @@ elf_gnu_ifunc_resolver_stop (code_breakpoint *b)
       if (b_return->thread == thread_id
 	  && b_return->loc->requested_address == prev_pc
 	  && frame_id_eq (b_return->frame_id, prev_frame_id))
-	break;
+	{
+	  gdb_assert (b_return->inferior == -1);
+	  break;
+	}
     }
 
   if (b_return == b)
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index e9107cef520..68b1fca7c51 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -423,7 +423,10 @@ run_command_1 (const char *args, int from_tty, enum run_how run_how)
   /* Insert temporary breakpoint in main function if requested.  */
   if (run_how == RUN_STOP_AT_MAIN)
     {
-      std::string arg = string_printf ("-qualified %s if $_inferior == %d", main_name (),
+      //std::string arg = string_printf ("-qualified %s if $_inferior == %d", main_name (),
+      //			       current_inferior ()->num);
+      std::string arg = string_printf ("-qualified %s inferior %d",
+				       main_name (),
 				       current_inferior ()->num);
       tbreak_command (arg.c_str (), 0);
     }
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 033699bc3f7..e23bbd8dfa1 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -8041,6 +8041,7 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
 	  frame = NULL;
 
 	  bp->thread = tp->global_num;
+	  bp->inferior = -1;
 	  inferior_thread ()->control.exception_resume_breakpoint = bp;
 	}
     }
@@ -8074,6 +8075,7 @@ insert_exception_resume_from_probe (struct thread_info *tp,
   bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame),
 				       handler, bp_exception_resume).release ();
   bp->thread = tp->global_num;
+  bp->inferior = -1;
   inferior_thread ()->control.exception_resume_breakpoint = bp;
 }
 
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 3db35998f7e..ca09f630382 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -254,7 +254,7 @@ enum linespec_token_type
 
 /* List of keywords.  This is NULL-terminated so that it can be used
    as enum completer.  */
-const char * const linespec_keywords[] = { "if", "thread", "task", "-force-condition", NULL };
+const char * const linespec_keywords[] = { "if", "thread", "task", "inferior", "-force-condition", NULL };
 #define IF_KEYWORD_INDEX 0
 #define FORCE_KEYWORD_INDEX 3
 


  parent reply	other threads:[~2022-09-01 10:43 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-04 17:40 Simon Marchi via Gdb-patches
2022-08-17 17:56 ` Simon Marchi via Gdb-patches
2022-08-31 14:03 ` Bruno Larsen via Gdb-patches
2022-11-04 16:52   ` Simon Marchi via Gdb-patches
2022-11-07  8:14     ` Bruno Larsen via Gdb-patches
2022-11-08 17:24     ` Tom Tromey
2022-09-01 10:42 ` Andrew Burgess via Gdb-patches [this message]
2022-11-04 17:24   ` Simon Marchi via Gdb-patches
     [not found]     ` <8735asb7cj.fsf@redhat.com>
2022-11-09 13:19       ` Simon Marchi via Gdb-patches
2022-11-08 19:43 ` Pedro Alves
2022-11-08 20:14   ` Simon Marchi via Gdb-patches
2022-11-08 21:09     ` Pedro Alves
2022-11-08 21:20       ` [PATCH v2] " Simon Marchi via Gdb-patches
2022-11-10 16:45         ` Pedro Alves
2022-11-10 17:33           ` Simon Marchi via Gdb-patches
2022-11-10 17:36             ` Simon Marchi via Gdb-patches
2022-11-10 17:47             ` Pedro Alves
2022-11-10 17:53               ` Simon Marchi via Gdb-patches
2022-11-11 12:37         ` Tom de Vries via Gdb-patches
2022-11-11 13:53           ` Simon Marchi via Gdb-patches
2022-11-11 15:21             ` Tom de Vries via Gdb-patches
2022-11-11 19:03               ` Simon Marchi via Gdb-patches
2022-11-12 10:43                 ` Tom de Vries via Gdb-patches
2022-11-14 11:29                 ` Tom de Vries via Gdb-patches
2022-11-14 13:19                   ` Simon Marchi via Gdb-patches
2022-11-14 14:18                     ` Tom de Vries via Gdb-patches
2022-11-16 16:22                     ` Tom Tromey
2022-11-16 16:26                       ` Simon Marchi via Gdb-patches

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=87ler3cr4x.fsf@redhat.com \
    --to=gdb-patches@sourceware.org \
    --cc=aburgess@redhat.com \
    --cc=simon.marchi@efficios.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