From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-il1-x131.google.com (mail-il1-x131.google.com [IPv6:2607:f8b0:4864:20::131]) by sourceware.org (Postfix) with ESMTPS id 980D73858036 for ; Thu, 4 Nov 2021 17:37:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 980D73858036 Received: by mail-il1-x131.google.com with SMTP id k1so6952091ilo.7 for ; Thu, 04 Nov 2021 10:37:54 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Toj/L2hC3CyWGMstBBu7t+PeA4ZKIYfb64Hf0WLdz/A=; b=s8jHHfJSdqzYSgg7CYjvg/mH4ALley7JMbN7Wf2n5Uk0Cu3+BsjlB6nElG04EMZSfR tfnATj1lrJPK6nKME7fvlNha+Mhwxn1Y1lEbcbzrlvDyPCusvwfiaZ+HeSsfXj/0d9Wm NHaJPRffyDv9mD1hlxGE9Gb2dL7o5NwRLdsICd4Zt0keEcjnic1SYF/l6EU3ksOO1Mj0 +refRaaxo0RLYYH/ax8OTnMXz8bN0Bu42JreTMJpBTNa6d5lF63nNQsd3BHr0XbQ3wp7 rKh5gfJvjD4b2dATyhh+DH2QYFrUgvZUE5pX4ERSP7rXpeC5DOaXOtZmDPiAljh5r7N2 IqKw== X-Gm-Message-State: AOAM532Ha0Cgcsbx5KwI+EYWitHRMuvdNFl2MV8z2QLv7Dl7IF5Pwkee Ufc5LTFIUqTrGwQ8fzx5mZYnrisUis2/yA== X-Google-Smtp-Source: ABdhPJyZyuRoNt7p17aj6v7U3f0AoqQ380V1CSZPZVCt+xMBsjr+Kej/RZBxjKRDpz/RD36dX505Mg== X-Received: by 2002:a05:6e02:144b:: with SMTP id p11mr25342195ilo.70.1636047473911; Thu, 04 Nov 2021 10:37:53 -0700 (PDT) Received: from murgatroyd.Home (75-166-134-234.hlrn.qwest.net. [75.166.134.234]) by smtp.gmail.com with ESMTPSA id e17sm3388368iow.18.2021.11.04.10.37.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Nov 2021 10:37:53 -0700 (PDT) From: Tom Tromey To: gdb-patches@sourceware.org Cc: Tom Tromey Subject: [PATCH 1/2] Add "task" keyword to the "watch" command Date: Thu, 4 Nov 2021 11:37:50 -0600 Message-Id: <20211104173751.3029898-2-tromey@adacore.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211104173751.3029898-1-tromey@adacore.com> References: <20211104173751.3029898-1-tromey@adacore.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-11.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Nov 2021 17:37:56 -0000 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 . + +# 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 . + +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