to 'max-value-size', GDB will now still print the array, however only
'max-value-size' worth of data will be added into the value history.
+* 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 ]
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;
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;
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_;
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)
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)
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;
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);
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);
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."));
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;
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. */
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;
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;
_("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;
_("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;
# 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
"\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
gdb_test "info breakpoints" "foo.adb:${decimal}\r\n\\s+stop only in task 3" \
"check info breakpoints for task 3 breakpoint"
+# Test the Python API for the breakpoint task attribute.
+if {[allow_python_tests]} {
+ gdb_test_no_output "python bp = gdb.breakpoints()\[$bp_number - 1\]" \
+ "get gdb.Breakpoint from list"
+ 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 <gdb: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"
+}
+
# Continue to that breakpoint. 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 breakpoint, and GDB is expected to stop at that