public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Tom Tromey <tromey@adacore.com>
To: gdb-patches@sourceware.org
Cc: Tom Tromey <tromey@adacore.com>
Subject: [PATCH 1/2] Add "task" keyword to the "watch" command
Date: Thu,  4 Nov 2021 11:37:50 -0600	[thread overview]
Message-ID: <20211104173751.3029898-2-tromey@adacore.com> (raw)
In-Reply-To: <20211104173751.3029898-1-tromey@adacore.com>

Breakpoints in gdb can be made specific to an Ada task using the
"task" qualifier.  This patch applies this same idea to watchpoints.
---
 gdb/NEWS                                 |  3 +
 gdb/breakpoint.c                         | 12 ++++
 gdb/doc/gdb.texinfo                      |  5 +-
 gdb/testsuite/gdb.ada/task_watch.exp     | 83 ++++++++++++++++++++++++
 gdb/testsuite/gdb.ada/task_watch/foo.adb | 73 +++++++++++++++++++++
 5 files changed, 175 insertions(+), 1 deletion(-)
 create mode 100644 gdb/testsuite/gdb.ada/task_watch.exp
 create mode 100644 gdb/testsuite/gdb.ada/task_watch/foo.adb

diff --git a/gdb/NEWS b/gdb/NEWS
index 9e950d2f80d..b6331d5585f 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -24,6 +24,9 @@ show varsize-limit
   These are now deprecated aliases for "set max-value-size" and
   "show max-value-size".
 
+watch [...] task ID
+  Watchpoints can now be restricted to a specific Ada task.
+
 maint set internal-error backtrace on|off
 maint show internal-error backtrace
 maint set internal-warning backtrace on|off
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 4ec60f334a2..c17eb01a3d9 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -10557,6 +10557,7 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
      the hardware watchpoint.  */
   bool use_mask = false;
   CORE_ADDR mask = 0;
+  int task = 0;
 
   /* Make sure that we actually have parameters to parse.  */
   if (arg != NULL && arg[0] != '\0')
@@ -10612,6 +10613,16 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
 
 	      thread = thr->global_num;
 	    }
+	  else if (toklen == 4 && startswith (tok, "task"))
+	    {
+	      char *tmp;
+
+	      task = strtol (value_start, &tmp, 0);
+	      if (tmp == value_start)
+		error (_("Junk after task keyword."));
+	      if (!valid_task_id (task))
+		error (_("Unknown task %d."), task);
+	    }
 	  else if (toklen == 4 && startswith (tok, "mask"))
 	    {
 	      /* We've found a "mask" token, which means the user wants to
@@ -10785,6 +10796,7 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
     init_raw_breakpoint_without_location (w.get (), NULL, bp_type,
 					  &watchpoint_breakpoint_ops);
   w->thread = thread;
+  w->task = task;
   w->disposition = disp_donttouch;
   w->pspace = current_program_space;
   w->exp = std::move (exp);
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 308a97aeb82..b2bb079785e 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4862,7 +4862,7 @@ slow down the running of your program.
 
 @table @code
 @kindex watch
-@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{thread-id}@r{]} @r{[}mask @var{maskvalue}@r{]}
+@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{thread-id}@r{]} @r{[}mask @var{maskvalue}@r{]} @r{[}task @var{task-id}@r{]}
 Set a watchpoint for an expression.  @value{GDBN} will break when the
 expression @var{expr} is written into by the program and its value
 changes.  The simplest (and the most popular) use of this command is
@@ -4879,6 +4879,9 @@ change the value of @var{expr}, @value{GDBN} will not break.  Note
 that watchpoints restricted to a single thread in this way only work
 with Hardware Watchpoints.
 
+Similarly, if the @code{task} argument is given, then the watchpoint
+will be specific to the indicated Ada task (@pxref{Ada Tasks}).
+
 Ordinarily a watchpoint respects the scope of variables in @var{expr}
 (see below).  The @code{-location} argument tells @value{GDBN} to
 instead watch the memory referred to by @var{expr}.  In this case,
diff --git a/gdb/testsuite/gdb.ada/task_watch.exp b/gdb/testsuite/gdb.ada/task_watch.exp
new file mode 100644
index 00000000000..fc276ef5f0e
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/task_watch.exp
@@ -0,0 +1,83 @@
+# Copyright 2009-2021 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 task-specific watchpoints.
+
+load_lib "ada.exp"
+
+if { [skip_ada_tests] } { return -1 }
+
+standard_ada_testfile foo
+
+if {[gdb_compile_ada "${srcfile}" "${binfile}" executable {debug}] != ""} {
+  return -1
+}
+
+clean_restart ${testfile}
+
+set bp_location [gdb_get_line_number "STOP_HERE" ${testdir}/foo.adb]
+runto "foo.adb:$bp_location"
+
+# Make sure that all tasks appear in the "info tasks" listing, and
+# that the active task is the environment task.
+gdb_test "info tasks" \
+    [join {" +ID +TID P-ID Pri State +Name" \
+	       "\\* +1 .* main_task" \
+	       " +2 .* task_list\\(1\\)" \
+	       " +3 .* task_list\\(2\\)" \
+	       " +4 .* task_list\\(3\\)"} \
+	 "\r\n"] \
+    "info tasks before inserting breakpoint"
+
+# Insert a watchpoint that should stop only if task 3 stops, and
+# extract its number.
+set bp_number -1
+set test "watch -location value task 3"
+gdb_test_multiple $test $test {
+    -re "atchpoint ($decimal): -location value\r\n$gdb_prompt $" {
+	set bp_number $expect_out(1,string)
+	pass $test
+    }
+}
+
+if {$bp_number < 0} {
+    return
+}
+
+# Continue to that watchpoint.  Task 2 should hit it first, and GDB
+# is expected to ignore that hit and resume the execution.  Only then
+# task 3 will hit our watchpoint, and GDB is expected to stop at that
+# point.  Also make sure that GDB reports the correct watchpoint number.
+gdb_test "continue" \
+    ".* hit .*atchpoint $bp_number: -location value.*Old value = 1.*New value = 2.*" \
+    "continue to watchpoint"
+
+# Check that it is indeed task 3 that hit the watchpoint by checking
+# which is the active task.
+gdb_test "info tasks" \
+    [join {" +ID +TID P-ID Pri State +Name" \
+	       " +1 .* main_task" \
+	       " +2 .* task_list\\(1\\)" \
+	       "\\* +3 .* task_list\\(2\\)" \
+	       " +4 .* task_list\\(3\\)"} \
+	 "\r\n"] \
+    "info tasks after hitting watchpoint"
+
+# Now, resume the execution and make sure that GDB does not stop when
+# task 4 hits the watchpoint. Continuing thus results in our program
+# running to completion.
+set bp_location [gdb_get_line_number "STOP_HERE_2" ${testdir}/foo.adb]
+gdb_breakpoint foo.adb:$bp_location
+gdb_continue_to_breakpoint second ".*foo.adb:$bp_location.*null; -- STOP_HERE_2"
diff --git a/gdb/testsuite/gdb.ada/task_watch/foo.adb b/gdb/testsuite/gdb.ada/task_watch/foo.adb
new file mode 100644
index 00000000000..f3540ec05c7
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/task_watch/foo.adb
@@ -0,0 +1,73 @@
+--  Copyright 2009-2021 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/>.
+
+procedure Foo is
+
+   Value : Integer := 0;
+
+   task type Caller is
+      entry Initialize;
+      entry Call_Break_Me;
+      entry Finalize;
+   end Caller;
+   type Caller_Ptr is access Caller;
+
+   procedure Break_Me is
+   begin
+      Value := Value + 1;
+   end Break_Me;
+
+   task body Caller is
+   begin
+      accept Initialize do
+         null;
+      end Initialize;
+      accept Call_Break_Me do
+         Break_Me;
+      end Call_Break_Me;
+      accept Finalize do
+         null;
+      end Finalize;
+   end Caller;
+
+   Task_List : array (1 .. 3) of Caller_Ptr;
+
+begin
+
+   --  Start all our tasks, and call the "Initialize" entry to make
+   --  sure all of them have now been started.  We call that entry
+   --  immediately after having created the task in order to make sure
+   --  that we wait for that task to be created before we try to create
+   --  another one.  That way, we know that the order in our Task_List
+   --  corresponds to the order in the GNAT runtime.
+   for J in Task_List'Range loop
+      Task_List (J) := new Caller;
+      Task_List (J).Initialize;
+   end loop;
+
+   --  Next, call their Call_Break_Me entry of each task, using the same
+   --  order as the order used to create them.
+   for J in Task_List'Range loop  -- STOP_HERE
+      Task_List (J).Call_Break_Me;
+   end loop;
+
+   --  And finally, let all the tasks die...
+   for J in Task_List'Range loop
+      Task_List (J).Finalize;
+   end loop;
+
+   null; -- STOP_HERE_2
+
+end Foo;
-- 
2.31.1


  reply	other threads:[~2021-11-04 17:37 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-04 17:37 [PATCH 0/2] Two Ada task improvements Tom Tromey
2021-11-04 17:37 ` Tom Tromey [this message]
2021-11-04 18:48   ` [PATCH 1/2] Add "task" keyword to the "watch" command Eli Zaretskii
2021-11-04 17:37 ` [PATCH 2/2] Implement 'task apply' Tom Tromey
2021-11-04 18:52   ` Eli Zaretskii
2021-12-02 15:57 ` [PATCH 0/2] Two Ada task improvements Tom Tromey

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=20211104173751.3029898-2-tromey@adacore.com \
    --to=tromey@adacore.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

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

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