diff options
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/NEWS | 6 | ||||
-rw-r--r-- | gdb/breakpoint.c | 36 | ||||
-rw-r--r-- | gdb/breakpoint.h | 10 | ||||
-rw-r--r-- | gdb/guile/scm-breakpoint.c | 10 | ||||
-rw-r--r-- | gdb/python/py-breakpoint.c | 14 | ||||
-rw-r--r-- | gdb/testsuite/gdb.ada/tasks.exp | 82 |
6 files changed, 153 insertions, 5 deletions
@@ -50,6 +50,12 @@ 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 ] diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 5959013..11d0c3e 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; @@ -8443,6 +8451,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_; @@ -8811,6 +8821,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) @@ -8825,6 +8838,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) @@ -8859,7 +8875,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; @@ -8874,6 +8890,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); @@ -10091,6 +10109,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); @@ -10107,6 +10128,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.")); @@ -10282,6 +10306,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 352e846..5228c38 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 a7e043d..d4f2b73 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 1b10ccd..5229893 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 19aca7a..a73a191 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,10 +41,28 @@ 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 @@ -68,6 +88,68 @@ set bp_number [get_integer_valueof "\$bpnum" "INVALID" \ 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 |