public inbox for gdb-cvs@sourceware.org
help / color / mirror / Atom feed
* [binutils-gdb] gdb: make "start" breakpoint inferior-specific
@ 2022-11-10 18:05 Simon Marchi
  0 siblings, 0 replies; only message in thread
From: Simon Marchi @ 2022-11-10 18:05 UTC (permalink / raw)
  To: gdb-cvs

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=0be837be9fb4fc1f882a52a6fb7ad27e2f3023ae

commit 0be837be9fb4fc1f882a52a6fb7ad27e2f3023ae
Author: Simon Marchi <simon.marchi@efficios.com>
Date:   Thu Aug 4 11:49:12 2022 -0400

    gdb: make "start" breakpoint inferior-specific
    
    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 in background inferior 1 that sleeps before reaching its main
       function (using a sleep in a global C++ object's constructor)
     - start inferior 2 with the "start" command, which also sleeps before
       reaching its main function
     - validate that we hit the breakpoint in inferior 2
    
    Without the fix, we hit the breakpoint in inferior 1 pretty much all the
    time.  There could be some unfortunate scheduling causing the test not
    to catch the bug, for instance if the scheduler decides not to schedule
    inferior 1 for a long time, but it would be really rare.  If the bug is
    re-introduced, the test will catch it much more often than not, so it
    will be noticed.
    
    Reviewed-By: Bruno Larsen <blarsen@redhat.com>
    Approved-By: Pedro Alves <pedro@palves.net>
    Change-Id: Ib0148498a476bfa634ed62353c95f163623c686a

Diff:
---
 gdb/infcmd.c                                       |  8 ++-
 .../gdb.multi/start-inferior-specific-other.c      | 34 ++++++++++++
 gdb/testsuite/gdb.multi/start-inferior-specific.c  | 31 +++++++++++
 .../gdb.multi/start-inferior-specific.exp          | 61 ++++++++++++++++++++++
 4 files changed, 133 insertions(+), 1 deletion(-)

diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index c03ca103c91..bf4a68e3557 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -423,7 +423,13 @@ 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 ());
+      /* To avoid other inferiors hitting this breakpoint, make it
+	 inferior-specific using a condition.  A better solution would be to
+	 have proper inferior-specific breakpoint support, in the breakpoint
+	 machinery.  We could then avoid inserting a breakpoint in the program
+	 spaces unrelated to this inferior.  */
+      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..17a06a54443
--- /dev/null
+++ b/gdb/testsuite/gdb.multi/start-inferior-specific-other.c
@@ -0,0 +1,34 @@
+/* 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 <unistd.h>
+
+__attribute__((constructor))
+static void
+ctor (void)
+{
+  sleep (2);
+}
+
+int
+main (int argc, const char **argv)
+{
+  /* We don't want this program finishing and causing spurious "inferior
+     exited" notifications in GDB, so keep sleeping here.  */
+  sleep (60);
+  return 0;
+}
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..930010cbca6
--- /dev/null
+++ b/gdb/testsuite/gdb.multi/start-inferior-specific.c
@@ -0,0 +1,31 @@
+/* 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 <unistd.h>
+
+__attribute__((constructor))
+static void
+ctor (void)
+{
+  sleep (4);
+}
+
+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..45e8e8e2cc5
--- /dev/null
+++ b/gdb/testsuite/gdb.multi/start-inferior-specific.exp
@@ -0,0 +1,61 @@
+# 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 start inferior 1 in background, which sleeps for a bit
+# before reaching its main function.  We then "start" inferior 2, which also
+# sleeps before reaching its main function.  The goal is that inferior 1
+# "crosses" inferior 2's start breakpoint (at the time of writing this test, the
+# breakpoint inserted for start is global and has locations in both inferiors).
+# A buggy GDB would report a breakpoint hit in inferior 1.
+
+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 -no-prompt-anchor "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 .*"
+}
+
+do_test

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-11-10 18:05 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-10 18:05 [binutils-gdb] gdb: make "start" breakpoint inferior-specific Simon Marchi

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