public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/2] Prevent combining 'task' and 'thread' keywords
@ 2023-02-08 15:16 Andrew Burgess
  2023-02-08 15:16 ` [PATCH 1/2] gdb: only allow one of thread or task on breakpoints or watchpoints Andrew Burgess
  2023-02-08 15:16 ` [PATCH 2/2] gdb: use -1 for breakpoint::task default value Andrew Burgess
  0 siblings, 2 replies; 10+ messages in thread
From: Andrew Burgess @ 2023-02-08 15:16 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Inspired by a recent conversation about the expected behaviour of the
'thread' and 'task' keywords when combined together, this series
prohibits such combinations.  And then does a related code cleanup.

---

Andrew Burgess (2):
  gdb: only allow one of thread or task on breakpoints or watchpoints
  gdb: use -1 for breakpoint::task default value

 gdb/NEWS                        |  6 +++
 gdb/breakpoint.c                | 56 ++++++++++++++++------
 gdb/breakpoint.h                | 14 +++++-
 gdb/guile/scm-breakpoint.c      | 14 +++++-
 gdb/python/py-breakpoint.c      | 18 ++++++-
 gdb/testsuite/gdb.ada/tasks.exp | 85 +++++++++++++++++++++++++++++++--
 6 files changed, 169 insertions(+), 24 deletions(-)


base-commit: 1947a4a4bb7651a4656edceb1f9b246f96f89ebd
-- 
2.25.4


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

* [PATCH 1/2] gdb: only allow one of thread or task on breakpoints or watchpoints
  2023-02-08 15:16 [PATCH 0/2] Prevent combining 'task' and 'thread' keywords Andrew Burgess
@ 2023-02-08 15:16 ` Andrew Burgess
  2023-02-08 15:52   ` Eli Zaretskii
  2023-02-08 18:10   ` Pedro Alves
  2023-02-08 15:16 ` [PATCH 2/2] gdb: use -1 for breakpoint::task default value Andrew Burgess
  1 sibling, 2 replies; 10+ messages in thread
From: Andrew Burgess @ 2023-02-08 15:16 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

After this mailing list posting:

  https://sourceware.org/pipermail/gdb-patches/2023-February/196607.html

it seems to me that in practice an Ada task maps 1:1 with a GDB
thread, and so it doesn't really make sense to allow uses to give both
a thread and a task within a single breakpoint or watchpoint
condition.

This commit updates GDB so that the user will get an error if both
are specified.

I've added new tests to cover the CLI as well as the Python and Guile
APIs.  For the Python and Guile testing, as far as I can tell, this
was the first testing for this corner of the APIs, so I ended up
adding more than just a single test.

For documentation I've added a NEWS entry, but I've not added anything
to the docs themselves.  Currently we document the commands with a
thread-id or task-id as distinct command, e.g.:

  'break LOCSPEC task TASKNO'
  'break LOCSPEC task TASKNO if ...'
  'break LOCSPEC thread THREAD-ID'
  'break LOCSPEC thread THREAD-ID if ...'

As such, I don't believe there is any indication that combining 'task'
and 'thread' would be expected to work; it seems clear to me in the
above that those four options are all distinct commands.

I think the NEWS entry is enough that if someone is combining these
keywords (it's not clear what the expected behaviour would be in this
case) then they can figure out that this was a deliberate change in
GDB, but for a new user, the manual doesn't suggest combining them is
OK, and any future attempt to combine them will give an error.
---
 gdb/NEWS                        |  6 +++
 gdb/breakpoint.c                | 36 ++++++++++++--
 gdb/breakpoint.h                | 10 ++++
 gdb/guile/scm-breakpoint.c      | 10 ++++
 gdb/python/py-breakpoint.c      | 14 ++++++
 gdb/testsuite/gdb.ada/tasks.exp | 85 +++++++++++++++++++++++++++++++--
 6 files changed, 153 insertions(+), 8 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 1567cbea9bd..89b9d32817a 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -44,6 +44,12 @@
   keyword already gave an error when used multiple times with the
   watch command, this remains unchanged.
 
+* For both the break and watch commands, it is now invalid to use both
+  the 'thread' and 'task' keywords within the same command.  For
+  example the following commnds will now give an error:
+    break foo thread 1 task 1
+    watch var thread 2 task 3
+
 * New commands
 
 maintenance print record-instruction [ N ]
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index adf38e7d722..8963b10d516 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1454,12 +1454,16 @@ breakpoint_set_silent (struct breakpoint *b, int silent)
     gdb::observers::breakpoint_modified.notify (b);
 }
 
-/* Set the thread for this breakpoint.  If THREAD is -1, make the
-   breakpoint work for any thread.  */
+/* See breakpoint.h.  */
 
 void
 breakpoint_set_thread (struct breakpoint *b, int thread)
 {
+  /* It is invalid to set the thread field to anything other than -1 (which
+     means no thread restriction) if a task restriction is already in
+     place.  */
+  gdb_assert (thread == -1 || b->task == 0);
+
   int old_thread = b->thread;
 
   b->thread = thread;
@@ -1467,12 +1471,16 @@ breakpoint_set_thread (struct breakpoint *b, int thread)
     gdb::observers::breakpoint_modified.notify (b);
 }
 
-/* Set the task for this breakpoint.  If TASK is 0, make the
-   breakpoint work for any task.  */
+/* See breakpoint.h.  */
 
 void
 breakpoint_set_task (struct breakpoint *b, int task)
 {
+  /* It is invalid to set the task field to anything other than 0 (which
+     means no task restriction) if a thread restriction is already in
+     place.  */
+  gdb_assert (task == 0 || b->thread == -1);
+
   int old_task = b->task;
 
   b->task = task;
@@ -8438,6 +8446,8 @@ code_breakpoint::code_breakpoint (struct gdbarch *gdbarch_,
 
   gdb_assert (!sals.empty ());
 
+  /* At most one of thread or task can be set on any breakpoint.  */
+  gdb_assert (thread == -1 || task == 0);
   thread = thread_;
   task = task_;
 
@@ -8806,6 +8816,9 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
 	  if (*thread != -1)
 	    error(_("You can specify only one thread."));
 
+	  if (*task != 0)
+	    error (_("You can specify only one of thread or task."));
+
 	  tok = end_tok + 1;
 	  thr = parse_thread_id (tok, &tmptok);
 	  if (tok == tmptok)
@@ -8820,6 +8833,9 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
 	  if (*task != 0)
 	    error(_("You can specify only one task."));
 
+	  if (*thread != -1)
+	    error (_("You can specify only one of thread or task."));
+
 	  tok = end_tok + 1;
 	  *task = strtol (tok, &tmptok, 0);
 	  if (tok == tmptok)
@@ -8854,7 +8870,7 @@ find_condition_and_thread_for_sals (const std::vector<symtab_and_line> &sals,
   for (auto &sal : sals)
     {
       gdb::unique_xmalloc_ptr<char> cond;
-      int thread_id = 0;
+      int thread_id = -1;
       int task_id = 0;
       gdb::unique_xmalloc_ptr<char> remaining;
 
@@ -8869,6 +8885,8 @@ find_condition_and_thread_for_sals (const std::vector<symtab_and_line> &sals,
 	  find_condition_and_thread (input, sal.pc, &cond, &thread_id,
 				     &task_id, &remaining);
 	  *cond_string = std::move (cond);
+	  /* At most one of thread or task can be set.  */
+	  gdb_assert (thread_id == -1 || task_id == 0);
 	  *thread = thread_id;
 	  *task = task_id;
 	  *rest = std::move (remaining);
@@ -10089,6 +10107,9 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
 	      if (thread != -1)
 		error(_("You can specify only one thread."));
 
+	      if (task != 0)
+		error (_("You can specify only one of thread or task."));
+
 	      /* Extract the thread ID from the next token.  */
 	      thr = parse_thread_id (value_start, &endp);
 
@@ -10105,6 +10126,9 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
 	      if (task != 0)
 		error(_("You can specify only one task."));
 
+	      if (thread != -1)
+		error (_("You can specify only one of thread or task."));
+
 	      task = strtol (value_start, &tmp, 0);
 	      if (tmp == value_start)
 		error (_("Junk after task keyword."));
@@ -10280,6 +10304,8 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
   else
     w.reset (new watchpoint (nullptr, bp_type));
 
+  /* At most one of thread or task can be set on a watchpoint.  */
+  gdb_assert (thread == -1 || task == 0);
   w->thread = thread;
   w->task = task;
   w->disposition = disp_donttouch;
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 352e8468537..5228c38fe02 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1673,8 +1673,18 @@ extern void breakpoint_set_commands (struct breakpoint *b,
 
 extern void breakpoint_set_silent (struct breakpoint *b, int silent);
 
+/* Set the thread for this breakpoint.  If THREAD is -1, make the
+   breakpoint work for any thread.  Passing a value other than -1 for
+   THREAD should only be done if b->task is 0; it is not valid to try and
+   set both a thread and task restriction on a breakpoint.  */
+
 extern void breakpoint_set_thread (struct breakpoint *b, int thread);
 
+/* Set the task for this breakpoint.  If TASK is 0, make the breakpoint
+   work for any task.  Passing a value other than 0 for TASK should only be
+   done if b->thread is -1; it is not valid to try and set both a thread
+   and task restriction on a breakpoint.  */
+
 extern void breakpoint_set_task (struct breakpoint *b, int task);
 
 /* Clear the "inserted" flag in all breakpoints.  */
diff --git a/gdb/guile/scm-breakpoint.c b/gdb/guile/scm-breakpoint.c
index a7e043d847b..d4f2b7310bd 100644
--- a/gdb/guile/scm-breakpoint.c
+++ b/gdb/guile/scm-breakpoint.c
@@ -773,6 +773,11 @@ gdbscm_set_breakpoint_thread_x (SCM self, SCM newvalue)
 	  gdbscm_out_of_range_error (FUNC_NAME, SCM_ARG2, newvalue,
 				     _("invalid thread id"));
 	}
+
+      if (bp_smob->bp->task != 0)
+	scm_misc_error (FUNC_NAME,
+			_("cannot set both task and thread attributes"),
+			SCM_EOL);
     }
   else if (gdbscm_is_false (newvalue))
     id = -1;
@@ -828,6 +833,11 @@ gdbscm_set_breakpoint_task_x (SCM self, SCM newvalue)
 	  gdbscm_out_of_range_error (FUNC_NAME, SCM_ARG2, newvalue,
 				     _("invalid task id"));
 	}
+
+      if (bp_smob->bp->thread != -1)
+	scm_misc_error (FUNC_NAME,
+			_("cannot set both task and thread attributes"),
+			SCM_EOL);
     }
   else if (gdbscm_is_false (newvalue))
     id = 0;
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 1b10ccd5415..52298935242 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -270,6 +270,13 @@ bppy_set_thread (PyObject *self, PyObject *newvalue, void *closure)
 			   _("Invalid thread ID."));
 	  return -1;
 	}
+
+      if (self_bp->bp->task != 0)
+	{
+	  PyErr_SetString (PyExc_RuntimeError,
+			   _("Cannot set both task and thread attributes."));
+	  return -1;
+	}
     }
   else if (newvalue == Py_None)
     id = -1;
@@ -321,6 +328,13 @@ bppy_set_task (PyObject *self, PyObject *newvalue, void *closure)
 			   _("Invalid task ID."));
 	  return -1;
 	}
+
+      if (self_bp->bp->thread != -1)
+	{
+	  PyErr_SetString (PyExc_RuntimeError,
+			   _("Cannot set both task and thread attributes."));
+	  return -1;
+	}
     }
   else if (newvalue == Py_None)
     id = 0;
diff --git a/gdb/testsuite/gdb.ada/tasks.exp b/gdb/testsuite/gdb.ada/tasks.exp
index 88ef123865b..9d4f396e88e 100644
--- a/gdb/testsuite/gdb.ada/tasks.exp
+++ b/gdb/testsuite/gdb.ada/tasks.exp
@@ -14,6 +14,8 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 load_lib "ada.exp"
+load_lib "gdb-guile.exp"
+load_lib "gdb-python.exp"
 
 require allow_ada_tests
 
@@ -39,17 +41,35 @@ gdb_test "info tasks" \
                "\r\n"] \
          "info tasks before inserting breakpoint"
 
+# Confirm that the "info threads" output lines up with the tasks list.
+gdb_test "info threads" \
+    [multi_line \
+	 "\\*\\s+1\\s+\[^\r\n\]+\\s\"foo\"\\s\[^\r\n\]+" \
+	 "\\s+2\\s+\[^\r\n\]+\\s\"task_list\\(1\\)\"\\s\[^\r\n\]+" \
+	 "\\s+3\\s+\[^\r\n\]+\\s\"task_list\\(2\\)\"\\s\[^\r\n\]+" \
+	 "\\s+4\\s+\[^\r\n\]+\\s\"task_list\\(3\\)\"\\s\[^\r\n\]+"]
+
 # Check that multiple uses of the 'task' keyword will give an error.
 gdb_test "break break_me task 1 task 3" "You can specify only one task\\."
 gdb_test "watch j task 1 task 3" "You can specify only one task\\."
 
+# Check that attempting to combine 'task' and 'thread' gives an error.
+gdb_test "break break_me task 1 thread 1" \
+    "You can specify only one of thread or task\\."
+gdb_test "break break_me thread 1 task 1" \
+    "You can specify only one of thread or task\\."
+gdb_test "watch j task 1 thread 1" \
+    "You can specify only one of thread or task\\."
+gdb_test "watch j thread 1 task 1" \
+    "You can specify only one of thread or task\\."
+
 # Insert a breakpoint that should stop only if task 1 stops.  Since
 # task 1 never calls break_me, this shouldn't actually ever trigger.
 # The fact that this breakpoint is created _before_ the next one
 # matters.  GDB used to have a bug where it would report the first
 # breakpoint in the list that matched the triggered-breakpoint's
 # address, no matter which task it was specific to.
-gdb_test "break break_me task 1" "Breakpoint .* at .*"
+gdb_breakpoint "break_me task 1" message
 gdb_test "info breakpoints" "foo.adb:${decimal}\r\n\\s+stop only in task 1" \
     "check info breakpoints for task 1 breakpoint"
 
@@ -57,8 +77,67 @@ gdb_test "info breakpoints" "foo.adb:${decimal}\r\n\\s+stop only in task 1" \
 # extract its number.
 gdb_breakpoint "break_me task 3" message
 set bp_number [get_integer_valueof "\$bpnum" -1]
-if {$bp_number < 0} {
-    return
+gdb_assert { $bp_number > 0 } "check for a valid breakpoint number"
+
+# Test the Python API for the breakpoint task attribute.
+if {[allow_python_tests]} {
+    gdb_test_no_output "python bp = gdb.breakpoints()\[$bp_number - 1\]"
+    gdb_test "python print(bp.task)" "3"
+    gdb_test "python print(bp.thread)" "None"
+    gdb_test "python bp.thread = 1" \
+	[multi_line \
+	     "RuntimeError: Cannot set both task and thread attributes\\." \
+	     "Error while executing Python code\\."] \
+	"try setting the thread, but expect an error"
+    gdb_test_no_output "python bp.task = None"
+    gdb_test_no_output "python bp.thread = 1"
+    gdb_test "python bp.task = 3" \
+	[multi_line \
+	     "RuntimeError: Cannot set both task and thread attributes\\." \
+	     "Error while executing Python code\\."] \
+	"try setting the task, but expect an error"
+
+    # Reset the breakpoint to the state required for the rest of this
+    # test.
+    gdb_test_no_output "python bp.thread = None"
+    gdb_test_no_output "python bp.task = 3"
+}
+
+# Test the Guile API for the breakpoint task attribute.
+if {[allow_guile_tests]} {
+    gdb_install_guile_utils
+    gdb_install_guile_module
+
+    gdb_scm_test_silent_cmd "guile (define blist (breakpoints))" \
+	"get breakpoint list"
+    gdb_scm_test_silent_cmd "guile (define bp (list-ref blist (- $bp_number 1)))" \
+	"get breakpoint from list"
+    gdb_test "guile (print (breakpoint-task bp))" "= 3"
+    gdb_test "guile (print (breakpoint-thread bp))" "= #f"
+    gdb_test "guile (set-breakpoint-thread! bp 1)" \
+	[multi_line \
+	     "ERROR: In procedure set-breakpoint-thread!:" \
+	     "In procedure gdbscm_set_breakpoint_thread_x: cannot set both task and thread attributes" \
+	     "Error while executing Scheme code."] \
+	"attempt to set thread, but expect an error"
+
+    gdb_scm_test_silent_cmd "guile (set-breakpoint-task! bp #f)" \
+	"clear breakpoint task attribute"
+    gdb_scm_test_silent_cmd "guile (set-breakpoint-thread! bp 1)" \
+	"set breakpoint thread now task is unset"
+    gdb_test "guile (set-breakpoint-task! bp 1)" \
+	[multi_line \
+	     "ERROR: In procedure set-breakpoint-task!:" \
+	     "In procedure gdbscm_set_breakpoint_task_x: cannot set both task and thread attributes" \
+	     "Error while executing Scheme code."] \
+	"attempt to set task, but expect an error"
+
+    # Reset the breakpoint to the state required for the rest of this
+    # test.
+    gdb_scm_test_silent_cmd "guile (set-breakpoint-thread! bp #f)" \
+	"clear breakpoint thread attribute"
+    gdb_scm_test_silent_cmd "guile (set-breakpoint-task! bp 3)" \
+	"restore breakpoint task attribute"
 }
 gdb_test "info breakpoints" "foo.adb:${decimal}\r\n\\s+stop only in task 3" \
     "check info breakpoints for task 3 breakpoint"
-- 
2.25.4


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

* [PATCH 2/2] gdb: use -1 for breakpoint::task default value
  2023-02-08 15:16 [PATCH 0/2] Prevent combining 'task' and 'thread' keywords Andrew Burgess
  2023-02-08 15:16 ` [PATCH 1/2] gdb: only allow one of thread or task on breakpoints or watchpoints Andrew Burgess
@ 2023-02-08 15:16 ` Andrew Burgess
  2023-02-08 18:10   ` Pedro Alves
  1 sibling, 1 reply; 10+ messages in thread
From: Andrew Burgess @ 2023-02-08 15:16 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Within the breakpoint struct we have two fields ::thread and ::task
which are used for thread or task specific breakpoints.  When a
breakpoint doesn't have a specific thread or task then these fields
have the values -1 and 0 respectively.

There's no particular reason (as far as I can tell) why these two
"default" values are different, and I find the difference a little
confusing.  Long term I'd like to potentially fold these two fields
into a single field, but that isn't what this commit does.

What this commit does is switch to using -1 as the "default" value for
both fields, this means that the default for breakpoint::task has
changed from 0 to -1.   I've updated all the code I can find that
relied on the value of 0, and I see no test regressions, especially in
gdb.ada/tasks.exp, which still fully passes.

There should be no user visible changes after this commit.
---
 gdb/breakpoint.c           | 36 ++++++++++++++++++------------------
 gdb/breakpoint.h           | 10 +++++-----
 gdb/guile/scm-breakpoint.c |  6 +++---
 gdb/python/py-breakpoint.c |  6 +++---
 4 files changed, 29 insertions(+), 29 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 8963b10d516..4792bc8263d 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1462,7 +1462,7 @@ breakpoint_set_thread (struct breakpoint *b, int thread)
   /* It is invalid to set the thread field to anything other than -1 (which
      means no thread restriction) if a task restriction is already in
      place.  */
-  gdb_assert (thread == -1 || b->task == 0);
+  gdb_assert (thread == -1 || b->task == -1);
 
   int old_thread = b->thread;
 
@@ -1476,10 +1476,10 @@ breakpoint_set_thread (struct breakpoint *b, int thread)
 void
 breakpoint_set_task (struct breakpoint *b, int task)
 {
-  /* It is invalid to set the task field to anything other than 0 (which
+  /* It is invalid to set the task field to anything other than -1 (which
      means no task restriction) if a thread restriction is already in
      place.  */
-  gdb_assert (task == 0 || b->thread == -1);
+  gdb_assert (task == -1 || b->thread == -1);
 
   int old_task = b->task;
 
@@ -5473,7 +5473,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->task != 0 && b->task != ada_get_task_number (thread)))
+      || (b->task != -1 && b->task != ada_get_task_number (thread)))
     {
       infrun_debug_printf ("incorrect thread or task, not stopping");
       bs->stop = false;
@@ -6487,7 +6487,7 @@ print_one_breakpoint_location (struct breakpoint *b,
     {
       if (b->thread != -1)
 	uiout->field_signed ("thread", b->thread);
-      else if (b->task != 0)
+      else if (b->task != -1)
 	uiout->field_signed ("task", b->task);
     }
 
@@ -6544,7 +6544,7 @@ print_one_breakpoint_location (struct breakpoint *b,
       uiout->text ("\n");
     }
 
-  if (!part_of_multiple && b->task != 0)
+  if (!part_of_multiple && b->task != -1)
     {
       uiout->text ("\tstop only in task ");
       uiout->field_signed ("task", b->task);
@@ -8447,7 +8447,7 @@ code_breakpoint::code_breakpoint (struct gdbarch *gdbarch_,
   gdb_assert (!sals.empty ());
 
   /* At most one of thread or task can be set on any breakpoint.  */
-  gdb_assert (thread == -1 || task == 0);
+  gdb_assert (thread == -1 || task == -1);
   thread = thread_;
   task = task_;
 
@@ -8763,7 +8763,7 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
 {
   cond_string->reset ();
   *thread = -1;
-  *task = 0;
+  *task = -1;
   rest->reset ();
   bool force = false;
 
@@ -8816,7 +8816,7 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
 	  if (*thread != -1)
 	    error(_("You can specify only one thread."));
 
-	  if (*task != 0)
+	  if (*task != -1)
 	    error (_("You can specify only one of thread or task."));
 
 	  tok = end_tok + 1;
@@ -8830,7 +8830,7 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
 	{
 	  char *tmptok;
 
-	  if (*task != 0)
+	  if (*task != -1)
 	    error(_("You can specify only one task."));
 
 	  if (*thread != -1)
@@ -8871,7 +8871,7 @@ find_condition_and_thread_for_sals (const std::vector<symtab_and_line> &sals,
     {
       gdb::unique_xmalloc_ptr<char> cond;
       int thread_id = -1;
-      int task_id = 0;
+      int task_id = -1;
       gdb::unique_xmalloc_ptr<char> remaining;
 
       /* Here we want to parse 'arg' to separate condition from thread
@@ -8886,7 +8886,7 @@ find_condition_and_thread_for_sals (const std::vector<symtab_and_line> &sals,
 				     &task_id, &remaining);
 	  *cond_string = std::move (cond);
 	  /* At most one of thread or task can be set.  */
-	  gdb_assert (thread_id == -1 || task_id == 0);
+	  gdb_assert (thread_id == -1 || task_id == -1);
 	  *thread = thread_id;
 	  *task = task_id;
 	  *rest = std::move (remaining);
@@ -8988,7 +8988,7 @@ create_breakpoint (struct gdbarch *gdbarch,
 {
   struct linespec_result canonical;
   bool pending = false;
-  int task = 0;
+  int task = -1;
   int prev_bkpt_count = breakpoint_count;
 
   gdb_assert (ops != NULL);
@@ -10060,7 +10060,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;
+  int task = -1;
 
   /* Make sure that we actually have parameters to parse.  */
   if (arg != NULL && arg[0] != '\0')
@@ -10107,7 +10107,7 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
 	      if (thread != -1)
 		error(_("You can specify only one thread."));
 
-	      if (task != 0)
+	      if (task != -1)
 		error (_("You can specify only one of thread or task."));
 
 	      /* Extract the thread ID from the next token.  */
@@ -10123,7 +10123,7 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
 	    {
 	      char *tmp;
 
-	      if (task != 0)
+	      if (task != -1)
 		error(_("You can specify only one task."));
 
 	      if (thread != -1)
@@ -10305,7 +10305,7 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
     w.reset (new watchpoint (nullptr, bp_type));
 
   /* At most one of thread or task can be set on a watchpoint.  */
-  gdb_assert (thread == -1 || task == 0);
+  gdb_assert (thread == -1 || task == -1);
   w->thread = thread;
   w->task = task;
   w->disposition = disp_donttouch;
@@ -14143,7 +14143,7 @@ breakpoint::print_recreate_thread (struct ui_file *fp) const
   if (thread != -1)
     gdb_printf (fp, " thread %d", thread);
 
-  if (task != 0)
+  if (task != -1)
     gdb_printf (fp, " task %d", task);
 
   gdb_printf (fp, "\n");
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 5228c38fe02..03aecd15eff 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -802,9 +802,9 @@ struct breakpoint
      care.  */
   int thread = -1;
 
-  /* Ada task number for task-specific breakpoint, or 0 if don't
+  /* Ada task number for task-specific breakpoint, or -1 if don't
      care.  */
-  int task = 0;
+  int task = -1;
 
   /* Count of the number of times this breakpoint was taken, dumped
      with the info, but not used for anything else.  Useful for seeing
@@ -1680,9 +1680,9 @@ extern void breakpoint_set_silent (struct breakpoint *b, int silent);
 
 extern void breakpoint_set_thread (struct breakpoint *b, int thread);
 
-/* Set the task for this breakpoint.  If TASK is 0, make the breakpoint
-   work for any task.  Passing a value other than 0 for TASK should only be
-   done if b->thread is -1; it is not valid to try and set both a thread
+/* Set the task for this breakpoint.  If TASK is -1, make the breakpoint
+   work for any task.  Passing a value other than -1 for TASK should only
+   be done if b->thread is -1; it is not valid to try and set both a thread
    and task restriction on a breakpoint.  */
 
 extern void breakpoint_set_task (struct breakpoint *b, int task);
diff --git a/gdb/guile/scm-breakpoint.c b/gdb/guile/scm-breakpoint.c
index d4f2b7310bd..2931df265d7 100644
--- a/gdb/guile/scm-breakpoint.c
+++ b/gdb/guile/scm-breakpoint.c
@@ -774,7 +774,7 @@ gdbscm_set_breakpoint_thread_x (SCM self, SCM newvalue)
 				     _("invalid thread id"));
 	}
 
-      if (bp_smob->bp->task != 0)
+      if (bp_smob->bp->task != -1)
 	scm_misc_error (FUNC_NAME,
 			_("cannot set both task and thread attributes"),
 			SCM_EOL);
@@ -797,7 +797,7 @@ gdbscm_breakpoint_task (SCM self)
   breakpoint_smob *bp_smob
     = bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
 
-  if (bp_smob->bp->task == 0)
+  if (bp_smob->bp->task == -1)
     return SCM_BOOL_F;
 
   return scm_from_long (bp_smob->bp->task);
@@ -840,7 +840,7 @@ gdbscm_set_breakpoint_task_x (SCM self, SCM newvalue)
 			SCM_EOL);
     }
   else if (gdbscm_is_false (newvalue))
-    id = 0;
+    id = -1;
   else
     SCM_ASSERT_TYPE (0, newvalue, SCM_ARG2, FUNC_NAME, _("integer or #f"));
 
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 52298935242..ecf52a4637c 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -271,7 +271,7 @@ bppy_set_thread (PyObject *self, PyObject *newvalue, void *closure)
 	  return -1;
 	}
 
-      if (self_bp->bp->task != 0)
+      if (self_bp->bp->task != -1)
 	{
 	  PyErr_SetString (PyExc_RuntimeError,
 			   _("Cannot set both task and thread attributes."));
@@ -337,7 +337,7 @@ bppy_set_task (PyObject *self, PyObject *newvalue, void *closure)
 	}
     }
   else if (newvalue == Py_None)
-    id = 0;
+    id = -1;
   else
     {
       PyErr_SetString (PyExc_TypeError,
@@ -711,7 +711,7 @@ bppy_get_task (PyObject *self, void *closure)
 
   BPPY_REQUIRE_VALID (self_bp);
 
-  if (self_bp->bp->task == 0)
+  if (self_bp->bp->task == -1)
     Py_RETURN_NONE;
 
   return gdb_py_object_from_longest (self_bp->bp->task).release ();
-- 
2.25.4


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

* Re: [PATCH 1/2] gdb: only allow one of thread or task on breakpoints or watchpoints
  2023-02-08 15:16 ` [PATCH 1/2] gdb: only allow one of thread or task on breakpoints or watchpoints Andrew Burgess
@ 2023-02-08 15:52   ` Eli Zaretskii
  2023-02-08 18:10   ` Pedro Alves
  1 sibling, 0 replies; 10+ messages in thread
From: Eli Zaretskii @ 2023-02-08 15:52 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

> Cc: Andrew Burgess <aburgess@redhat.com>
> Date: Wed,  8 Feb 2023 15:16:16 +0000
> From: Andrew Burgess via Gdb-patches <gdb-patches@sourceware.org>
> 
> After this mailing list posting:
> 
>   https://sourceware.org/pipermail/gdb-patches/2023-February/196607.html
> 
> it seems to me that in practice an Ada task maps 1:1 with a GDB
> thread, and so it doesn't really make sense to allow uses to give both
> a thread and a task within a single breakpoint or watchpoint
> condition.
> 
> This commit updates GDB so that the user will get an error if both
> are specified.
> 
> I've added new tests to cover the CLI as well as the Python and Guile
> APIs.  For the Python and Guile testing, as far as I can tell, this
> was the first testing for this corner of the APIs, so I ended up
> adding more than just a single test.
> 
> For documentation I've added a NEWS entry, but I've not added anything
> to the docs themselves.  Currently we document the commands with a
> thread-id or task-id as distinct command, e.g.:
> 
>   'break LOCSPEC task TASKNO'
>   'break LOCSPEC task TASKNO if ...'
>   'break LOCSPEC thread THREAD-ID'
>   'break LOCSPEC thread THREAD-ID if ...'
> 
> As such, I don't believe there is any indication that combining 'task'
> and 'thread' would be expected to work; it seems clear to me in the
> above that those four options are all distinct commands.
> 
> I think the NEWS entry is enough that if someone is combining these
> keywords (it's not clear what the expected behaviour would be in this
> case) then they can figure out that this was a deliberate change in
> GDB, but for a new user, the manual doesn't suggest combining them is
> OK, and any future attempt to combine them will give an error.
> ---
>  gdb/NEWS                        |  6 +++
>  gdb/breakpoint.c                | 36 ++++++++++++--
>  gdb/breakpoint.h                | 10 ++++
>  gdb/guile/scm-breakpoint.c      | 10 ++++
>  gdb/python/py-breakpoint.c      | 14 ++++++
>  gdb/testsuite/gdb.ada/tasks.exp | 85 +++++++++++++++++++++++++++++++--
>  6 files changed, 153 insertions(+), 8 deletions(-)

OK for the NEWS part, thanks.

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

* Re: [PATCH 1/2] gdb: only allow one of thread or task on breakpoints or watchpoints
  2023-02-08 15:16 ` [PATCH 1/2] gdb: only allow one of thread or task on breakpoints or watchpoints Andrew Burgess
  2023-02-08 15:52   ` Eli Zaretskii
@ 2023-02-08 18:10   ` Pedro Alves
  2023-02-12  5:50     ` Andrew Burgess
  1 sibling, 1 reply; 10+ messages in thread
From: Pedro Alves @ 2023-02-08 18:10 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 2023-02-08 3:16 p.m., Andrew Burgess via Gdb-patches wrote:

> @@ -57,8 +77,67 @@ gdb_test "info breakpoints" "foo.adb:${decimal}\r\n\\s+stop only in task 1" \
>  # extract its number.
>  gdb_breakpoint "break_me task 3" message
>  set bp_number [get_integer_valueof "\$bpnum" -1]
> -if {$bp_number < 0} {
> -    return
> +gdb_assert { $bp_number > 0 } "check for a valid breakpoint number"
> +
> +# Test the Python API for the breakpoint task attribute.
> +if {[allow_python_tests]} {
> +    gdb_test_no_output "python bp = gdb.breakpoints()\[$bp_number - 1\]"

AFAICS, this leaks the $bp_number number to gdb.sum.  Typically we'll avoid it, by
writing an explicit test message, sometimes by using "\$bp_number" in the 
test message so that "$bp_number" is written literally instead of the expanded
number.  Like:

   gdb_test_no_output \
     "python bp = gdb.breakpoints()\[$bp_number - 1\]" \
     "python bp = gdb.breakpoints()\[\$bp_number - 1\]"

but a descriptive test message would be fine too, of course.  I see now that in
Guile below you used "get breakpoint from list":

> +
> +    gdb_scm_test_silent_cmd "guile (define blist (breakpoints))" \
> +	"get breakpoint list"
> +    gdb_scm_test_silent_cmd "guile (define bp (list-ref blist (- $bp_number 1)))" \
> +	"get breakpoint from list"

Otherwise,

 Approved-By: Pedro Alves <pedro@palves.net>

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

* Re: [PATCH 2/2] gdb: use -1 for breakpoint::task default value
  2023-02-08 15:16 ` [PATCH 2/2] gdb: use -1 for breakpoint::task default value Andrew Burgess
@ 2023-02-08 18:10   ` Pedro Alves
  2023-02-12  7:23     ` Andrew Burgess
  0 siblings, 1 reply; 10+ messages in thread
From: Pedro Alves @ 2023-02-08 18:10 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 2023-02-08 3:16 p.m., Andrew Burgess via Gdb-patches wrote:
> Within the breakpoint struct we have two fields ::thread and ::task
> which are used for thread or task specific breakpoints.  When a
> breakpoint doesn't have a specific thread or task then these fields
> have the values -1 and 0 respectively.
> 
> There's no particular reason (as far as I can tell) why these two
> "default" values are different, and I find the difference a little
> confusing.  Long term I'd like to potentially fold these two fields
> into a single field, but that isn't what this commit does.
> 
> What this commit does is switch to using -1 as the "default" value for
> both fields, this means that the default for breakpoint::task has
> changed from 0 to -1.   I've updated all the code I can find that
> relied on the value of 0, and I see no test regressions, especially in
> gdb.ada/tasks.exp, which still fully passes.
> 
> There should be no user visible changes after this commit.

This bothered me before as well.  Thanks for doing this.

Approved-By: Pedro Alves <pedro@palves.net>


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

* Re: [PATCH 1/2] gdb: only allow one of thread or task on breakpoints or watchpoints
  2023-02-08 18:10   ` Pedro Alves
@ 2023-02-12  5:50     ` Andrew Burgess
  2023-02-12 22:58       ` Tom Tromey
  0 siblings, 1 reply; 10+ messages in thread
From: Andrew Burgess @ 2023-02-12  5:50 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

Pedro Alves <pedro@palves.net> writes:

> On 2023-02-08 3:16 p.m., Andrew Burgess via Gdb-patches wrote:
>
>> @@ -57,8 +77,67 @@ gdb_test "info breakpoints" "foo.adb:${decimal}\r\n\\s+stop only in task 1" \
>>  # extract its number.
>>  gdb_breakpoint "break_me task 3" message
>>  set bp_number [get_integer_valueof "\$bpnum" -1]
>> -if {$bp_number < 0} {
>> -    return
>> +gdb_assert { $bp_number > 0 } "check for a valid breakpoint number"
>> +
>> +# Test the Python API for the breakpoint task attribute.
>> +if {[allow_python_tests]} {
>> +    gdb_test_no_output "python bp = gdb.breakpoints()\[$bp_number - 1\]"
>
> AFAICS, this leaks the $bp_number number to gdb.sum.  Typically we'll avoid it, by
> writing an explicit test message, sometimes by using "\$bp_number" in the 
> test message so that "$bp_number" is written literally instead of the expanded
> number.  Like:
>
>    gdb_test_no_output \
>      "python bp = gdb.breakpoints()\[$bp_number - 1\]" \
>      "python bp = gdb.breakpoints()\[\$bp_number - 1\]"
>
> but a descriptive test message would be fine too, of course.  I see now that in
> Guile below you used "get breakpoint from list":

I gave the test a more descriptive name, and pushed both patches in this
series.

Thanks,
Andrew

>
>> +
>> +    gdb_scm_test_silent_cmd "guile (define blist (breakpoints))" \
>> +	"get breakpoint list"
>> +    gdb_scm_test_silent_cmd "guile (define bp (list-ref blist (- $bp_number 1)))" \
>> +	"get breakpoint from list"
>
> Otherwise,
>
>  Approved-By: Pedro Alves <pedro@palves.net>


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

* Re: [PATCH 2/2] gdb: use -1 for breakpoint::task default value
  2023-02-08 18:10   ` Pedro Alves
@ 2023-02-12  7:23     ` Andrew Burgess
  0 siblings, 0 replies; 10+ messages in thread
From: Andrew Burgess @ 2023-02-12  7:23 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

Pedro Alves <pedro@palves.net> writes:

> On 2023-02-08 3:16 p.m., Andrew Burgess via Gdb-patches wrote:
>> Within the breakpoint struct we have two fields ::thread and ::task
>> which are used for thread or task specific breakpoints.  When a
>> breakpoint doesn't have a specific thread or task then these fields
>> have the values -1 and 0 respectively.
>> 
>> There's no particular reason (as far as I can tell) why these two
>> "default" values are different, and I find the difference a little
>> confusing.  Long term I'd like to potentially fold these two fields
>> into a single field, but that isn't what this commit does.
>> 
>> What this commit does is switch to using -1 as the "default" value for
>> both fields, this means that the default for breakpoint::task has
>> changed from 0 to -1.   I've updated all the code I can find that
>> relied on the value of 0, and I see no test regressions, especially in
>> gdb.ada/tasks.exp, which still fully passes.
>> 
>> There should be no user visible changes after this commit.
>
> This bothered me before as well.  Thanks for doing this.
>
> Approved-By: Pedro Alves <pedro@palves.net>

I pushed this.  Then realised I'd forgotten to update it to take account
of another patch that added a new comparison to 0, so I then pushed the
patch below as a fix.

Sorry for the temporary breakage.

Thanks,
Andrew

---

commit 8282ad74c302a8e0db7a588e500ae117a1df68c5
Author: Andrew Burgess <aburgess@redhat.com>
Date:   Sun Feb 12 07:14:31 2023 +0000

    gdb: fix describe_other_breakpoints for default task being -1
    
    Commit:
    
      commit 2ecee236752932672fb3d6cd63c6976927f747d8
      CommitDate: Sun Feb 12 05:46:44 2023 +0000
    
          gdb: use -1 for breakpoint::task default value
    
    Failed to take account of an earlier commit:
    
      commit f1f517e81039f6aa673b7d87a66bfbd25a66e3d3
      CommitDate: Sat Feb 11 17:36:24 2023 +0000
    
          gdb: show task number in describe_other_breakpoints
    
    That both of these are my own commits is only more embarrassing.
    
    This small fix updates describe_other_breakpoints to take account of
    the default task number now being -1.  This fixes regressions in
    gdb.base/break.exp, gdb.base/break-always.exp, and many other tests.

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 4b0a909d60c..97dee5cd0fe 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -7057,7 +7057,7 @@ describe_other_breakpoints (struct gdbarch *gdbarch,
 		struct thread_info *thr = find_thread_global_id (b->thread);
 		gdb_printf (" (thread %s)", print_thread_id (thr));
 	      }
-	    else if (b->task != 0)
+	    else if (b->task != -1)
 	      gdb_printf (" (task %d)", b->task);
 	    gdb_printf ("%s%s ",
 			((b->enable_state == bp_disabled


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

* Re: [PATCH 1/2] gdb: only allow one of thread or task on breakpoints or watchpoints
  2023-02-12  5:50     ` Andrew Burgess
@ 2023-02-12 22:58       ` Tom Tromey
  2023-02-13 11:26         ` Andrew Burgess
  0 siblings, 1 reply; 10+ messages in thread
From: Tom Tromey @ 2023-02-12 22:58 UTC (permalink / raw)
  To: Andrew Burgess via Gdb-patches; +Cc: Pedro Alves, Andrew Burgess

Andrew> I gave the test a more descriptive name, and pushed both patches in this
Andrew> series.

I didn't bisect but I suspect this caused:

guile (set-breakpoint-thread! bp 1)
ERROR: In procedure set-breakpoint-thread!:
ERROR: In procedure gdbscm_set_breakpoint_thread_x: cannot set both task and thread attributes
Error while executing Scheme code.
(gdb) FAIL: gdb.ada/tasks.exp: attempt to set thread, but expect an error

and

guile (set-breakpoint-task! bp 1)
ERROR: In procedure set-breakpoint-task!:
ERROR: In procedure gdbscm_set_breakpoint_task_x: cannot set both task and thread attributes
Error while executing Scheme code.
(gdb) FAIL: gdb.ada/tasks.exp: attempt to set task, but expect an error

Tom

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

* Re: [PATCH 1/2] gdb: only allow one of thread or task on breakpoints or watchpoints
  2023-02-12 22:58       ` Tom Tromey
@ 2023-02-13 11:26         ` Andrew Burgess
  0 siblings, 0 replies; 10+ messages in thread
From: Andrew Burgess @ 2023-02-13 11:26 UTC (permalink / raw)
  To: Tom Tromey, Andrew Burgess via Gdb-patches; +Cc: Pedro Alves

Tom Tromey <tom@tromey.com> writes:

> Andrew> I gave the test a more descriptive name, and pushed both patches in this
> Andrew> series.
>
> I didn't bisect but I suspect this caused:
>
> guile (set-breakpoint-thread! bp 1)
> ERROR: In procedure set-breakpoint-thread!:
> ERROR: In procedure gdbscm_set_breakpoint_thread_x: cannot set both task and thread attributes
> Error while executing Scheme code.
> (gdb) FAIL: gdb.ada/tasks.exp: attempt to set thread, but expect an error

Tom,

Oh, I see.  You're getting a second 'ERROR:' prefix that I don't get.  I
could only find one other test that tries to match an error string like
I'm doing, in gdb.guile/scm-parameter.exp, and in there we do treat this
extra 'ERROR: ' as optional.

I pushed the patch below which I think should fix the issue.  Let me
know if you are still seeing failures.

Sorry for the breakage.

Thanks,
Andrew

---

commit 97c195191578e9a68bfbb810eea373f5f3efcb7d
Author: Andrew Burgess <aburgess@redhat.com>
Date:   Mon Feb 13 11:19:57 2023 +0000

    gdb/testsuite: handle differences in guile error string output
    
    A new guile test added in commit:
    
      commit 0a9ccb9dd79384f3ba3f8cd75940e8868f3b526f
      Date:   Mon Feb 6 13:04:16 2023 +0000
    
          gdb: only allow one of thread or task on breakpoints or watchpoints
    
    fails for some versions of guile.  It turns out that some versions of
    guile emit an error like this:
    
      (gdb) guile (set-breakpoint-thread! bp 1)
      ERROR: In procedure set-breakpoint-thread!:
      In procedure gdbscm_set_breakpoint_thread_x: cannot set both task and thread attributes
      Error while executing Scheme code.
    
    while other versions of guile emit the error like this:
    
      (gdb) guile (set-breakpoint-thread! bp 1)
      ERROR: In procedure set-breakpoint-thread!:
      ERROR: In procedure gdbscm_set_breakpoint_thread_x: cannot set both task and thread attributes
      Error while executing Scheme code.
    
    notice the extra 'ERROR: ' on the second line of output.  This commit
    updates the test regexp to handle this optional 'ERROR: ' string.

diff --git a/gdb/testsuite/gdb.ada/tasks.exp b/gdb/testsuite/gdb.ada/tasks.exp
index a73a1919419..eb7ee5c9951 100644
--- a/gdb/testsuite/gdb.ada/tasks.exp
+++ b/gdb/testsuite/gdb.ada/tasks.exp
@@ -127,7 +127,8 @@ if {[allow_guile_tests]} {
     gdb_test "guile (set-breakpoint-thread! bp 1)" \
 	[multi_line \
 	     "ERROR: In procedure set-breakpoint-thread!:" \
-	     "In procedure gdbscm_set_breakpoint_thread_x: cannot set both task and thread attributes" \
+	     "(ERROR: )?In procedure gdbscm_set_breakpoint_thread_x:\
+	      cannot set both task and thread attributes" \
 	     "Error while executing Scheme code."] \
 	"attempt to set thread, but expect an error"
 
@@ -138,7 +139,8 @@ if {[allow_guile_tests]} {
     gdb_test "guile (set-breakpoint-task! bp 1)" \
 	[multi_line \
 	     "ERROR: In procedure set-breakpoint-task!:" \
-	     "In procedure gdbscm_set_breakpoint_task_x: cannot set both task and thread attributes" \
+	     "(ERROR: )?In procedure gdbscm_set_breakpoint_task_x:\
+	      cannot set both task and thread attributes" \
 	     "Error while executing Scheme code."] \
 	"attempt to set task, but expect an error"
 


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

end of thread, other threads:[~2023-02-13 11:26 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-08 15:16 [PATCH 0/2] Prevent combining 'task' and 'thread' keywords Andrew Burgess
2023-02-08 15:16 ` [PATCH 1/2] gdb: only allow one of thread or task on breakpoints or watchpoints Andrew Burgess
2023-02-08 15:52   ` Eli Zaretskii
2023-02-08 18:10   ` Pedro Alves
2023-02-12  5:50     ` Andrew Burgess
2023-02-12 22:58       ` Tom Tromey
2023-02-13 11:26         ` Andrew Burgess
2023-02-08 15:16 ` [PATCH 2/2] gdb: use -1 for breakpoint::task default value Andrew Burgess
2023-02-08 18:10   ` Pedro Alves
2023-02-12  7:23     ` Andrew Burgess

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