From patchwork Fri Jan 20 09:46:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 63440 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C583A3857C45 for ; Fri, 20 Jan 2023 09:47:17 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C583A3857C45 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1674208037; bh=4DHcahhUHwf1MnlMpWZRyFzq1B0Ijhy7E/rTsZnyAFc=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=FDl0iTYqgDIpejRGTChrVhI624NCMiyxi8rXLJyHGTuamdBeNpLr/ZIiIAEcicpq+ /TIXRcjm+p4FdZPsY0TQphQRc9zgpaEJlFes0whXyjvE0Nj56SaItu++POn/ahQP77 g89eOYHsfKW40Qwtl4KfppMLRjqMot6MOuazLhq8= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 114E53858433 for ; Fri, 20 Jan 2023 09:46:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 114E53858433 Received: from mail-qk1-f197.google.com (mail-qk1-f197.google.com [209.85.222.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-441-A9hL-hNNNR6FSlp8_3QeBA-1; Fri, 20 Jan 2023 04:46:37 -0500 X-MC-Unique: A9hL-hNNNR6FSlp8_3QeBA-1 Received: by mail-qk1-f197.google.com with SMTP id bp33-20020a05620a45a100b007090e2e1b0cso1507303qkb.16 for ; Fri, 20 Jan 2023 01:46:37 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=4DHcahhUHwf1MnlMpWZRyFzq1B0Ijhy7E/rTsZnyAFc=; b=sNFPvBYRVCJ8He6RabyXiWPrKYgu/HfNS8YvzLgSS9xZriGReGNfikDwmPRk3T39ML gXyQ70q00jrDwnoTAJU1iOJoea3SHsoo6FP6G697bmzHOjkI18NO/zrQh8xMc6HgUv9H 37mt1qTh/iD+6UDDug3nOY36rjNdN8x6aQVr5XGca9KzimfTvYJWVB1zvPRc7aHQQhPd hcA3cZ/7DpHtSBgKm+t13RyyuST8fpo/y90+zHgvRnW2QovpUB8w/4asM/LTVFNORLxN M20SXBGCCu4IfEV309k8K4miEoT79VaMSkltczMjGUC7V2DcpOPc9DMfKji/YfLqduQ5 7/fA== X-Gm-Message-State: AFqh2krODyeppVggt5IoXuhIlTOKCe7sTiJmGxOlVC5DuF+BzswqNUaK MNv8SLnnbCZnffW0lKgwozDbR1UJdro4hyPNo2IAqXMDDto1T2tb67UTlHwUr+O9NMkv6ifmCk1 vEAggt4LS/PYFlJh9swia9EUg1a1zRBj73eZY3vcxWXZBfDRiK/qQAozlLpTEiCgcooRaK89/og == X-Received: by 2002:ac8:1346:0:b0:3b6:2b5c:97e5 with SMTP id f6-20020ac81346000000b003b62b5c97e5mr20553013qtj.17.1674207997292; Fri, 20 Jan 2023 01:46:37 -0800 (PST) X-Google-Smtp-Source: AMrXdXvPbu+QIlIuKgS3yXMofW51ZYHjEYWVj8bJqRmW+CZcuf1lMq4JTvypg5cHrXPWqYU7Sl2azA== X-Received: by 2002:ac8:1346:0:b0:3b6:2b5c:97e5 with SMTP id f6-20020ac81346000000b003b62b5c97e5mr20552990qtj.17.1674207996962; Fri, 20 Jan 2023 01:46:36 -0800 (PST) Received: from localhost (95.72.115.87.dyn.plus.net. [87.115.72.95]) by smtp.gmail.com with ESMTPSA id d13-20020ac8668d000000b003b637642405sm6062337qtp.5.2023.01.20.01.46.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Jan 2023 01:46:36 -0800 (PST) To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv2 1/6] gdb/remote: announce thread exit events for remote targets Date: Fri, 20 Jan 2023 09:46:24 +0000 Message-Id: X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) 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-Patchwork-Original-From: Andrew Burgess via Gdb-patches From: Andrew Burgess Reply-To: Andrew Burgess Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" For some reason the "[Thread XXXX exited]" messages are not printed inside thread.c from functions like delete_thread, etc as might be expected. Instead, each target seems to print the message before calling delete_thread. This doesn't seem ideal, and I can't help but feel that the printing should be moved into thread.c, however, I have not tried to do that in this commit, as I suspect there will be lots of fallout that needs fixing up. Instead, in this commit, I have added the printing code into remote.c, so that the remote target will now correctly tell the user when a thread has exited. This fixes some test failures in gdb.threads/thread-specific-bp.exp when run with the native-gdbserver and native-extended-gdbserver board. When using the native-extended-gdbserver board I still see 1 test failure, but I think this is not related to the issue fixed in this commit, so I'm ignoring that for now. --- gdb/remote.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gdb/remote.c b/gdb/remote.c index 0a6e293c095..4a508981a96 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -3977,6 +3977,10 @@ remote_target::update_thread_list () if (has_single_non_exited_thread (tp->inf)) continue; + if (print_thread_events) + gdb_printf (_("[%s exited]\n"), + target_pid_to_str (tp->ptid).c_str ()); + /* Not found. */ delete_thread (tp); } From patchwork Fri Jan 20 09:46:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 63441 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E80953858035 for ; Fri, 20 Jan 2023 09:47:26 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E80953858035 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1674208046; bh=v9tx9u2f1K7uWsGZG6GWFhihjolhzYYh2KV73+RcHQY=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=pHfH+iG4RD3K8f6MVnWCu0AbXd63LbOeeERrBSQYOfJlfdthKq8bbOfpw/G6XJnOD 365/LwvmacR7DMkY6LH6+KJxzu5LriFp86Ctk/5QptMapaD9aLL04uf+OfpX0Trglb 9l7a2ahExFtWpNohBaLapVQAcmeRn8C4J+d8Jm5w= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 8080F3858C33 for ; Fri, 20 Jan 2023 09:46:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8080F3858C33 Received: from mail-qt1-f199.google.com (mail-qt1-f199.google.com [209.85.160.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-151-_KkOROaZPeW3SEwmK44Lfw-1; Fri, 20 Jan 2023 04:46:40 -0500 X-MC-Unique: _KkOROaZPeW3SEwmK44Lfw-1 Received: by mail-qt1-f199.google.com with SMTP id q26-20020ac8735a000000b003b63165d87cso2180311qtp.11 for ; Fri, 20 Jan 2023 01:46:39 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=v9tx9u2f1K7uWsGZG6GWFhihjolhzYYh2KV73+RcHQY=; b=kln6xl51m5pKEtMWo+NQBKWasqz6FR/DrS27JfLhhi3fSYtQAUQZpojmxHx4awbVko RzOpUnBr6i89YWEHOo07WakdQcgO6QwFsIgfoZLvR97MA3P3V7Wa8fUurL5DWM2aYqbH 5U+DhWoM25hBKj9zieK/TbsLWDVm5RMfPHvxBIeSyYxwusf1qwAr0SkzIWNFZbUimmUs AiNHfzAU1YAn/MVT0RwkCyJEIg4lUJ2mxftBs7CtBZ4uM0ryF3vgaY7nx66gFHsiQ/+h vFXVG1zW1MMnocUl4f1uGwGCDKLXceGLCBFC+upCdIjZs3R2xDvFv3+uxdfHKllC9TK6 UkWw== X-Gm-Message-State: AFqh2krN9LLy6L89aKsDUClB90kq2XqGs1L7+FWeR3i3Djmf3N5DV29A eWakWAH1yp7tUMvvWAA0vc/RDahXS0hquugwPs23yOhf/XJLNBTPosspmZG24yEsc6exa+LH4XT nlH+vsb24xmCDeK4BW709J0MO1OLQ9ttUuH35OYOgFfnuCE3aP4I4PnqhmpEsnkkDbaz3irHw/w == X-Received: by 2002:ac8:6f09:0:b0:3a7:e271:fc05 with SMTP id bs9-20020ac86f09000000b003a7e271fc05mr23130222qtb.3.1674207999356; Fri, 20 Jan 2023 01:46:39 -0800 (PST) X-Google-Smtp-Source: AMrXdXuhiirYVsYpyirqakkaQLiKpog6o/AZ61rVEbpwMadnA/VzcJRo+QjAxcvFjcHDtMVGtFoK8A== X-Received: by 2002:ac8:6f09:0:b0:3a7:e271:fc05 with SMTP id bs9-20020ac86f09000000b003a7e271fc05mr23130202qtb.3.1674207998976; Fri, 20 Jan 2023 01:46:38 -0800 (PST) Received: from localhost (95.72.115.87.dyn.plus.net. [87.115.72.95]) by smtp.gmail.com with ESMTPSA id j25-20020ac874d9000000b003b0b903720esm13180478qtr.13.2023.01.20.01.46.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Jan 2023 01:46:38 -0800 (PST) To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv2 2/6] gdb/testsuite: don't try to set non-stop mode on a running target Date: Fri, 20 Jan 2023 09:46:25 +0000 Message-Id: X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) 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-Patchwork-Original-From: Andrew Burgess via Gdb-patches From: Andrew Burgess Reply-To: Andrew Burgess Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" The test gdb.threads/thread-specific-bp.exp tries to set non-stop mode on a running target, something which the manual makes clear is not allowed. The consequence of this is that the gdb.threads/thread-specific-bp.exp test has one failure when run with the native-extended-gdbserver board. This commit restructures the test a little, we now set the non-stop mode as part of the GDBFLAGS, so the mode will be set before GDB connects to the target. As a consequence I'm able to move the with_test_prefix out of the check_thread_specific_breakpoint proc. The check_thread_specific_breakpoint proc is now called within a loop. After this commit the gdb.threads/thread-specific-bp.exp test has zero failures for me with native-extended-gdbserver, native-gdbserver, and the unix board. --- .../gdb.threads/thread-specific-bp.exp | 138 +++++++++--------- 1 file changed, 67 insertions(+), 71 deletions(-) diff --git a/gdb/testsuite/gdb.threads/thread-specific-bp.exp b/gdb/testsuite/gdb.threads/thread-specific-bp.exp index f603b24fa31..d33b4f47258 100644 --- a/gdb/testsuite/gdb.threads/thread-specific-bp.exp +++ b/gdb/testsuite/gdb.threads/thread-specific-bp.exp @@ -24,8 +24,6 @@ if {[gdb_compile_pthreads \ return -1 } -clean_restart ${binfile} - # Extract and return the thread ID of the thread stopped at function # FUNC. @@ -45,86 +43,84 @@ proc get_thread_id {func} { return $thre } -proc check_thread_specific_breakpoint {mode} { - with_test_prefix "$mode" { - global gdb_prompt +proc check_thread_specific_breakpoint {non_stop} { + global gdb_prompt - if ![runto_main] { - return -1 - } + if ![runto_main] { + return -1 + } - set main_thre [get_thread_id "main"] - if { $main_thre < 0 } { - return -1 - } + set main_thre [get_thread_id "main"] + if { $main_thre < 0 } { + return -1 + } - gdb_breakpoint "start" - gdb_continue_to_breakpoint "start" + gdb_breakpoint "start" + gdb_continue_to_breakpoint "start" - set start_thre [get_thread_id "start"] - if { $start_thre < 0 } { - return -1 - } + set start_thre [get_thread_id "start"] + if { $start_thre < 0 } { + return -1 + } - # Set a thread-specific breakpoint at "main". This can't ever - # be hit, but that's OK. - gdb_breakpoint "main thread $start_thre" - gdb_test "info break" ".*breakpoint.*thread $start_thre" "breakpoint set" - - # Set breakpoint at a place only reacheable after the "start" - # thread exits. - gdb_breakpoint "end" - - # Switch back to the main thread, and resume all threads. The - # "start" thread exits, and the main thread reaches "end". - gdb_test "thread $main_thre" \ - "Switching to thread $main_thre.*" \ - "thread $main_thre selected" - - if { $mode == "non-stop" } { - set cmd "continue -a" - } else { - set cmd "continue" - } - set test "continue to end" - set thread_exited 0 - set prompt 0 - gdb_test_multiple "$cmd" $test -lbl { - -re "(^|\r\n)\\\[Thread \[^\r\n\]* exited](?=\r\n)" { - if { $prompt } { - pass $gdb_test_name - } else { - set thread_exited 1 - exp_continue - } + # Set a thread-specific breakpoint at "main". This can't ever + # be hit, but that's OK. + gdb_breakpoint "main thread $start_thre" + gdb_test "info break" ".*breakpoint.*thread $start_thre" "breakpoint set" + + # Set breakpoint at a place only reacheable after the "start" + # thread exits. + gdb_breakpoint "end" + + # Switch back to the main thread, and resume all threads. The + # "start" thread exits, and the main thread reaches "end". + gdb_test "thread $main_thre" \ + "Switching to thread $main_thre.*" \ + "thread $main_thre selected" + + if { $non_stop } { + set cmd "continue -a" + } else { + set cmd "continue" + } + set test "continue to end" + set thread_exited 0 + set prompt 0 + gdb_test_multiple "$cmd" $test -lbl { + -re "(^|\r\n)\\\[Thread \[^\r\n\]* exited](?=\r\n)" { + if { $prompt } { + pass $gdb_test_name + } else { + set thread_exited 1 + exp_continue } - -re "\r\n$gdb_prompt " { - if { $thread_exited } { - pass $gdb_test_name - } else { - set prompt 1 - exp_continue - } + } + -re "\r\n$gdb_prompt " { + if { $thread_exited } { + pass $gdb_test_name + } else { + set prompt 1 + exp_continue } } + } - set test "thread-specific breakpoint was deleted" - gdb_test_multiple "info breakpoint" $test { - -re "thread $start_thre\n$gdb_prompt $" { - fail $test - } - -re "$gdb_prompt $" { - pass $test - } + set test "thread-specific breakpoint was deleted" + gdb_test_multiple "info breakpoint" $test { + -re "thread $start_thre\n$gdb_prompt $" { + fail $test + } + -re "$gdb_prompt $" { + pass $test } } } -# Test all-stop mode. -check_thread_specific_breakpoint "all-stop" - -clean_restart ${binfile} +foreach_with_prefix non_stop {on off} { + save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set non-stop $non_stop\"" + clean_restart $binfile + } -# Test non-stop mode. -gdb_test_no_output "set non-stop on" "set non-stop mode" -check_thread_specific_breakpoint "non-stop" + check_thread_specific_breakpoint $non_stop +} From patchwork Fri Jan 20 09:46:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 63444 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7BF573854386 for ; Fri, 20 Jan 2023 09:47:48 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7BF573854386 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1674208068; bh=JQzdSJCbJWsLOw0OqVRSuqXAomBJM0byM0lNhL8pFbc=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=t1EXg6qiHowlZ8Q3nkSo7YbGR2B9wGg4ERnkJECDtxhOtkeTgEkFKwH5/DTf5nITJ hhtN4mkcxuoNnjTD0qiR7AVC12CTYPte3m/LUYOXhuqSQRJYRLdcuo+/NXmA9VquF1 staz7ozbxz972Amn5qQ14BPgQA4ekGTjUsLhXmn0= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 42954385840E for ; Fri, 20 Jan 2023 09:46:44 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 42954385840E Received: from mail-qk1-f200.google.com (mail-qk1-f200.google.com [209.85.222.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-185-GgYjR0zXPOGgqPkNAaz2Fg-1; Fri, 20 Jan 2023 04:46:42 -0500 X-MC-Unique: GgYjR0zXPOGgqPkNAaz2Fg-1 Received: by mail-qk1-f200.google.com with SMTP id bl13-20020a05620a1a8d00b00709117e3125so961714qkb.18 for ; Fri, 20 Jan 2023 01:46:42 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=JQzdSJCbJWsLOw0OqVRSuqXAomBJM0byM0lNhL8pFbc=; b=sRGf9NcISrSrRH3U2HgBvWRPOtq4PZmZEtUwMowGr597BBk/upIHF6b6jTjLaodVyN AYQYgQN59/8Jsm9JRP9dpNsjp94MP64EQJDC8A9sUHhahMfBsd/90OiCnLs3b2PMO363 dYTiLaTlMKuCWZy+oP7JHJ1F7Yjcc2r0bIGHzEllX7PEfw5Ywvln1A3Q5D/dFqWYHzAe 3wxoQVR6MwGN2Dm3dh3uSMNCLD66AALpa3cxX1GqlD/MeckslX/rZtm5nSB+5DfMLam4 8Z/Q/twqrEr7kLQ1/9F7QEGPiRv9q68WRWT545SpCVCDEv6u9Z49qUYQ4wnVlGQF1G76 vLdg== X-Gm-Message-State: AFqh2kpBnV2Hf9qo4R8E73/iS7Zajz2RbyqdKd8szfNVwGjbzb5Q6DIB WP5/6y5AUZUZClcePE1UUPAqKarRKzVs+YSmzWt+AUNIyTRqALeW8ao3xIcCr6AGZcDkGFJhYNo 67T8wiQTumrby16tZoxsWs8z6Msi0U0xPeePSBBbOfJNNVs6azC4RgsZhWx5LWM2BTXNpithu+A == X-Received: by 2002:a05:622a:4a83:b0:3a8:55c:a893 with SMTP id fw3-20020a05622a4a8300b003a8055ca893mr21951813qtb.0.1674208001464; Fri, 20 Jan 2023 01:46:41 -0800 (PST) X-Google-Smtp-Source: AMrXdXuqHQRp4GOpfQFMvcUoF8lEu5ss0LjpEjxP6ZojvmIzL3gBJ0Wb3itnLQOLLQij2Xk5o0A3Zw== X-Received: by 2002:a05:622a:4a83:b0:3a8:55c:a893 with SMTP id fw3-20020a05622a4a8300b003a8055ca893mr21951785qtb.0.1674208001012; Fri, 20 Jan 2023 01:46:41 -0800 (PST) Received: from localhost (95.72.115.87.dyn.plus.net. [87.115.72.95]) by smtp.gmail.com with ESMTPSA id l5-20020ac87245000000b003b62bc6cd1csm3104213qtp.82.2023.01.20.01.46.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Jan 2023 01:46:40 -0800 (PST) To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv2 3/6] gdb: fix display of thread condition for multi-location breakpoints Date: Fri, 20 Jan 2023 09:46:26 +0000 Message-Id: <403eeb015d985423d995b34a345e4e7816b8c349.1674207665.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) 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-Patchwork-Original-From: Andrew Burgess via Gdb-patches From: Andrew Burgess Reply-To: Andrew Burgess Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" If a breakpoint with multiple locations has a thread condition, then the 'info breakpoints' output is a little messed up, here's an example of the current output: (gdb) break foo thread 1 Breakpoint 2 at 0x401114: foo. (3 locations) (gdb) break bar thread 1 Breakpoint 3 at 0x40110a: file /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c, line 32. (gdb) info breakpoints Num Type Disp Enb Address What 2 breakpoint keep y thread 1 stop only in thread 1 2.1 y 0x0000000000401114 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 2.2 y 0x0000000000401146 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 2.3 y 0x0000000000401168 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 3 breakpoint keep y 0x000000000040110a in bar at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:32 thread 1 stop only in thread 1 Notice that, at the end of the location for breakpoint 3, the 'thread 1' condition is printed, but this is then repeated on the next line with 'stop only in thread 1'. In contrast, for breakpoint 2, the 'thread 1' appears randomly, in the "What" column, though slightly offset, non of the separate locations have the 'thread 1' information. Additionally for breakpoint 2 we also get a 'stop only in thread 1' line. There's two things going on here. First the randomly placed 'thread 1' for breakpoint 2 is due to a bug in print_one_breakpoint_location, where we check the variable part_of_multiple instead of header_of_multiple. If I fix this oversight, then the output is now: (gdb) break foo thread 1 Breakpoint 2 at 0x401114: foo. (3 locations) (gdb) break bar thread 1 Breakpoint 3 at 0x40110a: file /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c, line 32. (gdb) info breakpoints Num Type Disp Enb Address What 2 breakpoint keep y stop only in thread 1 2.1 y 0x0000000000401114 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 thread 1 2.2 y 0x0000000000401146 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 thread 1 2.3 y 0x0000000000401168 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 thread 1 3 breakpoint keep y 0x000000000040110a in bar at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:32 thread 1 stop only in thread 1 The 'thread 1' condition is now displayed at the end of each location, which makes the output the same for single location breakpoints and multi-location breakpoints. However, there's still some duplication here. Both breakpoints 2 and 3 include a 'stop only in thread 1' line, and it feels like the additional 'thread 1' is redundant. In fact, there's a comment to this very effect in the code: /* FIXME: This seems to be redundant and lost here; see the "stop only in" line a little further down. */ So, lets fix this FIXME. The new plan is to remove all the trailing 'thread 1' markers from the CLI output, we now get this: (gdb) break foo thread 1 Breakpoint 2 at 0x401114: foo. (3 locations) (gdb) break bar thread 1 Breakpoint 3 at 0x40110a: file /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c, line 32. (gdb) info breakpoints Num Type Disp Enb Address What 2 breakpoint keep y stop only in thread 1 2.1 y 0x0000000000401114 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 2.2 y 0x0000000000401146 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 2.3 y 0x0000000000401168 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 3 breakpoint keep y 0x000000000040110a in bar at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:32 stop only in thread 1 All of the above points are also true for the Ada 'task' breakpoint condition, and the changes I've made also update how the task information is printed, though in the case of the Ada task there was no 'stop only in task XXX' line printed, so I've added one of those. Obviously it can't be quite that easy. For MI backwards compatibility I've retained the existing code (but now only for MI like outputs), which ensures we should generate backwards compatible output. I've extended an Ada test to cover the new task related output, and updated all the tests I could find that checked for the old output. --- gdb/breakpoint.c | 30 ++++---- gdb/testsuite/gdb.ada/tasks.exp | 15 ++-- gdb/testsuite/gdb.base/save-bp.exp | 2 +- gdb/testsuite/gdb.base/thread-bp-multi-loc.c | 44 ++++++++++++ .../gdb.base/thread-bp-multi-loc.exp | 72 +++++++++++++++++++ 5 files changed, 141 insertions(+), 22 deletions(-) create mode 100644 gdb/testsuite/gdb.base/thread-bp-multi-loc.c create mode 100644 gdb/testsuite/gdb.base/thread-bp-multi-loc.exp diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 00cc2ab401c..b2cd89511fb 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -6468,20 +6468,19 @@ print_one_breakpoint_location (struct breakpoint *b, output_thread_groups (uiout, "thread-groups", inf_nums, mi_only); } - if (!part_of_multiple) + /* In the MI output, each location of a thread or task specific + breakpoint is with the relevant thread or task ID. This is done for + backwards compatibility reasons. + + For the CLI output, the thread/task information is printed on a + separate line, see the 'stop only in thread' and 'stop only in task' + output below. */ + if (!header_of_multiple && uiout->is_mi_like_p ()) { if (b->thread != -1) - { - /* FIXME: This seems to be redundant and lost here; see the - "stop only in" line a little further down. */ - uiout->text (" thread "); - uiout->field_signed ("thread", b->thread); - } + uiout->field_signed ("thread", b->thread); else if (b->task != 0) - { - uiout->text (" task "); - uiout->field_signed ("task", b->task); - } + uiout->field_signed ("task", b->task); } uiout->text ("\n"); @@ -6536,7 +6535,14 @@ print_one_breakpoint_location (struct breakpoint *b, } uiout->text ("\n"); } - + + if (!part_of_multiple && b->task != 0) + { + uiout->text ("\tstop only in task "); + uiout->field_signed ("task", b->task); + uiout->text ("\n"); + } + if (!part_of_multiple) { if (b->hit_count) diff --git a/gdb/testsuite/gdb.ada/tasks.exp b/gdb/testsuite/gdb.ada/tasks.exp index a9b58f20cf6..23bf3937a20 100644 --- a/gdb/testsuite/gdb.ada/tasks.exp +++ b/gdb/testsuite/gdb.ada/tasks.exp @@ -46,21 +46,18 @@ gdb_test "info tasks" \ # 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_test "info breakpoints" "foo.adb:${decimal}\r\n\\s+stop only in task 1" \ + "check info breakpoints for task 1 breakpoint" # Now, insert a breakpoint that should stop only if task 3 stops, and # extract its number. -set bp_number -1 -set test "break break_me task 3" -gdb_test_multiple $test $test { - -re "Breakpoint (.*) at .*$gdb_prompt $" { - set bp_number $expect_out(1,string) - pass $test - } -} - +gdb_breakpoint "break_me task 3" +set bp_number [get_integer_valueof "\$bpnum" -1] if {$bp_number < 0} { return } +gdb_test "info breakpoints" "foo.adb:${decimal}\r\n\\s+stop only in task 3" \ + "check info breakpoints for task 3 breakpoint" # Continue to that breakpoint. Task 2 should hit it first, and GDB # is expected to ignore that hit and resume the execution. Only then diff --git a/gdb/testsuite/gdb.base/save-bp.exp b/gdb/testsuite/gdb.base/save-bp.exp index a39712c7f5c..41d71837fb6 100644 --- a/gdb/testsuite/gdb.base/save-bp.exp +++ b/gdb/testsuite/gdb.base/save-bp.exp @@ -79,7 +79,7 @@ gdb_test_sequence "info break" "info break" [list \ "\[\r\n\]+Num +Type +Disp +Enb +Address +What" \ "\[\r\n\]+$bp_row_start break_me at \[^\r\n\]*$srcfile:\[0-9\]+" \ "\[\r\n\]+$bp_row_start main at \[^\r\n\]*$srcfile:$loc_bp2" \ - "\[\r\n\]+$bp_row_start main at \[^\r\n\]*$srcfile:$loc_bp3 +thread 1" \ + "\[\r\n\]+$bp_row_start main at \[^\r\n\]*$srcfile:$loc_bp3" \ "\[\r\n\]+\[ \t]+stop only in thread 1" \ "\[\r\n\]+$bp_row_start main at \[^\r\n\]*$srcfile:$loc_bp4" \ "\[\r\n\]+\[ \t\]+stop only if i == 1( \\((host|target) evals\\))?" \ diff --git a/gdb/testsuite/gdb.base/thread-bp-multi-loc.c b/gdb/testsuite/gdb.base/thread-bp-multi-loc.c new file mode 100644 index 00000000000..cab009c39ec --- /dev/null +++ b/gdb/testsuite/gdb.base/thread-bp-multi-loc.c @@ -0,0 +1,44 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2022 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 . */ + +volatile int global_var = 0; + +__attribute__((__always_inline__)) static inline void +foo (void) +{ + int i; + + for (i = 0; i < 10; ++i) + global_var = i; +} + +static void +bar (void) +{ + global_var = 0; + foo (); +} + +int +main (void) +{ + global_var = 0; + foo (); + bar (); + foo (); + return 0; +} diff --git a/gdb/testsuite/gdb.base/thread-bp-multi-loc.exp b/gdb/testsuite/gdb.base/thread-bp-multi-loc.exp new file mode 100644 index 00000000000..9665fe9e21f --- /dev/null +++ b/gdb/testsuite/gdb.base/thread-bp-multi-loc.exp @@ -0,0 +1,72 @@ +# Copyright 2022 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 . + +# Create a multi-location breakpoint with a thread condition, then check the +# output of 'info breakpoints' to ensure that the thread condition is +# displayed correctly. + +standard_testfile + +if { [prepare_for_testing "failed to prepare" $testfile $srcfile] } { + return -1 +} + +if {![runto_main]} { + return -1 +} + +delete_breakpoints + +gdb_breakpoint "foo thread 1" +set bp_number [get_integer_valueof "\$bpnum" 0] +if { $bp_number == 0 } { + unresolved "breakpoint not placed correctly" + return -1 +} + +set saw_header false +set saw_cond false +set loc_count 0 +gdb_test_multiple "info breakpoints" "" { + -re "\r\nNum\\s+\[^\r\n\]+\r\n" { + exp_continue + } + + -re "^$bp_number\\s+breakpoint\\s+keep\\s+y\\s+\\s*\r\n" { + set saw_header true + exp_continue + } + + -re "^\\s+stop only in thread 1\r\n" { + set saw_cond true + exp_continue + } + + -re "^$bp_number\\.\[123\]\\s+\[^\r\n\]+:${decimal}\r\n" { + incr loc_count + exp_continue + } + + -re "^$gdb_prompt $" { + with_test_prefix $gdb_test_name { + gdb_assert { $saw_header } \ + "saw header line" + gdb_assert { $saw_cond } \ + "saw b/p condition line" + gdb_assert { $loc_count == 3 } \ + "saw all three locations" + } + } +} From patchwork Fri Jan 20 09:46:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 63443 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A4A0238493D0 for ; Fri, 20 Jan 2023 09:47:43 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A4A0238493D0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1674208063; bh=VPYKM/inPaEgz0ub78Z3IPCd+GHCrzFHZ0dYuU4qUXM=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=b+Hex4vcctXv4jiwbKZGCcTvgYB1dx+YewJag9hZnf2lGEcEBbKzKIB9nK7qFRpf3 +K7DJe9rqtOcHNZNn4ySd2wkb82aDwxlbMK1bHds4WTd8gFKxjaRX6J4wGLVcDxeui aqjPZDkPqSIVaadubuTbuwNKdrKoTXnuakPS419M= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id CD58638582BC for ; Fri, 20 Jan 2023 09:46:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CD58638582BC Received: from mail-qt1-f200.google.com (mail-qt1-f200.google.com [209.85.160.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-332-0ZGLFB9ANDOLVRmKq4DF2w-1; Fri, 20 Jan 2023 04:46:44 -0500 X-MC-Unique: 0ZGLFB9ANDOLVRmKq4DF2w-1 Received: by mail-qt1-f200.google.com with SMTP id a13-20020ac84d8d000000b003b63a85ae73so2183356qtw.21 for ; Fri, 20 Jan 2023 01:46:44 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=VPYKM/inPaEgz0ub78Z3IPCd+GHCrzFHZ0dYuU4qUXM=; b=QgDVUZCyxXSVFiGYUB05WWKhfFAGKQEnec3qCUaMqseyYnc92gFcU0wSSYfV1VjHWX 9Y+VHzJ9R7xs7yKzOoLtGqTpcztULnVDlXj3lbJd7adjXFsa6GZicvLmHdInd8yS4Lxg kbDrzTm7B61yS8ug1AvjDcNbMytTFRsJOXfo4yAhufENn1uGGsf13UlPxJMbSgshIR5V GRk+sahBQDVAivg8E8saywklZ4VlaGntWPbaPO14hWP2VYW0thvUKFI2V9qivXf+0XdC 7lnyBJIbpO6w3As2K+SXrFyPWbIx0V61mTbTqx3jSsEj3WPxgKzyfrRG5fJY+7mt1uAp JvUw== X-Gm-Message-State: AFqh2kq+UDR2hoeAx9AuSNpoajD/43FIty4OPv1LLxXh2v3+EBNFIdhf OnS1fOKcWDlpkRKMRb1IANanFhIL4vzSxIvN6zihEh+JpH6YY1gnxLJEWOsp4Y3cW1l1p/entTD gAiFIfqVJnEGR5sWCyUtxo2Yl9ysVMqUES8e02w2lLYeahD6pc0AFMREOMIpeGomOpv8eg8qmFg == X-Received: by 2002:a05:622a:5d86:b0:3b6:301f:7b3d with SMTP id fu6-20020a05622a5d8600b003b6301f7b3dmr19212306qtb.65.1674208003530; Fri, 20 Jan 2023 01:46:43 -0800 (PST) X-Google-Smtp-Source: AMrXdXvQLTCofZv0xoWcEPEuVhWzdUe8r6cuzabLO3GFNdKmDWxkMHYy4w9D3qg8eMDYbzwSeUt/Qw== X-Received: by 2002:a05:622a:5d86:b0:3b6:301f:7b3d with SMTP id fu6-20020a05622a5d8600b003b6301f7b3dmr19212281qtb.65.1674208003069; Fri, 20 Jan 2023 01:46:43 -0800 (PST) Received: from localhost (95.72.115.87.dyn.plus.net. [87.115.72.95]) by smtp.gmail.com with ESMTPSA id cb15-20020a05622a1f8f00b003ab43dabfb1sm7429015qtb.55.2023.01.20.01.46.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Jan 2023 01:46:42 -0800 (PST) To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv2 4/6] gdb: error if 'thread' or 'task' keywords are overused Date: Fri, 20 Jan 2023 09:46:27 +0000 Message-Id: X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) 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-Patchwork-Original-From: Andrew Burgess via Gdb-patches From: Andrew Burgess Reply-To: Andrew Burgess Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" When creating a breakpoint or watchpoint, the 'thread' and 'task' keywords can be used to create a thread or task specific breakpoint or watchpoint. Currently, a thread or task specific breakpoint can only apply for a single thread or task, if multiple threads or tasks are specified when creating the breakpoint (or watchpoint), then the last specified id will be used. The exception to the above is that when the 'thread' keyword is used during the creation of a watchpoint, GDB will give an error if 'thread' is given more than once. In this commit I propose making this behaviour consistent, if the 'thread' or 'task' keywords are used more than once when creating either a breakpoint or watchpoint, then GDB will give an error. I haven't updated the manual, we don't explicitly say that these keywords can be repeated, and (to me), given the keyword takes a single id, I don't think it makes much sense to repeat the keyword. As such, I see this more as adding a missing error to GDB, rather than making some big change. However, I have added an entry to the NEWS file as I guess it is possible that some people might hit this new error with an existing (I claim, badly written) GDB script. I've added some new tests to check for the new error. Just one test needed updating, gdb.linespec/keywords.exp, this test did use the 'thread' keyword twice, and expected the breakpoint to be created. Looking at what this test was for though, it was checking the use of '-force-condition', and I don't think that being able to repeat 'thread' was actually a critical part of this test. As such, I've updated this test to expect the error when 'thread' is repeated. --- gdb/NEWS | 9 +++++++++ gdb/breakpoint.c | 9 +++++++++ gdb/testsuite/gdb.ada/tasks.exp | 4 ++++ gdb/testsuite/gdb.linespec/keywords.exp | 10 ++++++++-- gdb/testsuite/gdb.threads/thread-specific-bp.exp | 4 ++++ gdb/testsuite/gdb.threads/watchthreads2.exp | 3 +++ 6 files changed, 37 insertions(+), 2 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index c0aac212e30..fb49f62f7e6 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -9,6 +9,15 @@ This support requires that GDB be built with Python scripting enabled. +* For the break command, multiple uses of the 'thread' or 'task' + keywords will now give an error instead of just using the thread or + task id from the last instance of the keyword. + +* For the watch command, multiple uses of the 'task' keyword will now + give an error instead of just using the task id from the last + instance of the keyword. The 'thread' keyword already gave an error + when used multiple times with the watch command, this remains unchanged. + * New commands maintenance print record-instruction [ N ] diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index b2cd89511fb..1400fd49642 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -8801,6 +8801,9 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc, const char *tmptok; struct thread_info *thr; + if (*thread != -1) + error(_("You can specify only one thread.")); + tok = end_tok + 1; thr = parse_thread_id (tok, &tmptok); if (tok == tmptok) @@ -8812,6 +8815,9 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc, { char *tmptok; + if (*task != 0) + error(_("You can specify only one task.")); + tok = end_tok + 1; *task = strtol (tok, &tmptok, 0); if (tok == tmptok) @@ -10094,6 +10100,9 @@ watch_command_1 (const char *arg, int accessflag, int from_tty, { char *tmp; + if (task != 0) + error(_("You can specify only one task.")); + task = strtol (value_start, &tmp, 0); if (tmp == value_start) error (_("Junk after task keyword.")); diff --git a/gdb/testsuite/gdb.ada/tasks.exp b/gdb/testsuite/gdb.ada/tasks.exp index 23bf3937a20..4441d92719c 100644 --- a/gdb/testsuite/gdb.ada/tasks.exp +++ b/gdb/testsuite/gdb.ada/tasks.exp @@ -39,6 +39,10 @@ gdb_test "info tasks" \ "\r\n"] \ "info tasks before inserting breakpoint" +# 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\\." + # 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 diff --git a/gdb/testsuite/gdb.linespec/keywords.exp b/gdb/testsuite/gdb.linespec/keywords.exp index bff64249542..dc66e32237c 100644 --- a/gdb/testsuite/gdb.linespec/keywords.exp +++ b/gdb/testsuite/gdb.linespec/keywords.exp @@ -80,8 +80,14 @@ foreach prefix {"" "thread 1 "} { foreach suffix {"" " " " thread 1"} { foreach cond {"" " if 1"} { with_test_prefix "prefix: '$prefix', suffix: '$suffix', cond: '$cond'" { - gdb_breakpoint "main ${prefix}-force-condition${suffix}${cond}"\ - "message" + + if { [regexp thread $prefix] && [regexp thread $suffix] } { + gdb_test "break main ${prefix}-force-condition${suffix}${cond}" \ + "You can specify only one thread\\." + } else { + gdb_breakpoint "main ${prefix}-force-condition${suffix}${cond}"\ + "message" + } } } } diff --git a/gdb/testsuite/gdb.threads/thread-specific-bp.exp b/gdb/testsuite/gdb.threads/thread-specific-bp.exp index d33b4f47258..008ae5ed05e 100644 --- a/gdb/testsuite/gdb.threads/thread-specific-bp.exp +++ b/gdb/testsuite/gdb.threads/thread-specific-bp.exp @@ -63,6 +63,10 @@ proc check_thread_specific_breakpoint {non_stop} { return -1 } + # Check that multiple uses of 'thread' keyword give an error. + gdb_test "break main thread $start_thre thread $main_thre" \ + "You can specify only one thread\\." + # Set a thread-specific breakpoint at "main". This can't ever # be hit, but that's OK. gdb_breakpoint "main thread $start_thre" diff --git a/gdb/testsuite/gdb.threads/watchthreads2.exp b/gdb/testsuite/gdb.threads/watchthreads2.exp index 09858aee486..a1398d668a4 100644 --- a/gdb/testsuite/gdb.threads/watchthreads2.exp +++ b/gdb/testsuite/gdb.threads/watchthreads2.exp @@ -71,6 +71,9 @@ if { $nr_started == $NR_THREADS } { return -1 } +# Check that multiple uses of the 'thread' keyword will give an error. +gdb_test "watch x thread 1 thread 2" "You can specify only one thread\\." + # Watch X, it will be modified by all threads. # We want this watchpoint to be set *after* all threads are running. gdb_test "watch x" "Hardware watchpoint 3: x" From patchwork Fri Jan 20 09:46:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 63445 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 3D36C385843E for ; Fri, 20 Jan 2023 09:48:02 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3D36C385843E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1674208082; bh=OhsgseiMs+W4XeVeLzfAEvXUAkMYzUIzzIC28him6Go=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=LA/dF64XAI5F/cOyHkjYhu2SgdO7hywJieKsrpgHgy+e8MSToae0l3W311S3zkuMj r2ORibi+Lv+GR7CKoK9IjId1y9qNVOXbOq9V5V2ov2qXJxFx+YafMWpGyyI0fvzD6j gDvABrr+5O/XXTSMFDFdBM++9RyCswp7c9jRuFoc= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 96255385840C for ; Fri, 20 Jan 2023 09:46:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 96255385840C Received: from mail-qv1-f71.google.com (mail-qv1-f71.google.com [209.85.219.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-650-hTPlUxwTNKe5pO26SSIO0A-1; Fri, 20 Jan 2023 04:46:48 -0500 X-MC-Unique: hTPlUxwTNKe5pO26SSIO0A-1 Received: by mail-qv1-f71.google.com with SMTP id i7-20020a056214020700b004ffce246a2bso2265383qvt.3 for ; Fri, 20 Jan 2023 01:46:48 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=OhsgseiMs+W4XeVeLzfAEvXUAkMYzUIzzIC28him6Go=; b=puQJbGpeft8Fde3r3xq0gEpl1eFx03LmdX+t9oBzJZB8okQ2velu+jz88yIkeswao2 XB5r5+jfv/6HmlwXaAHUaP8DU/ynlESl/ivh9X9o7R5tWVRvciF/3BQkaJAkdpiCbku+ CONFy7/cdcFQu9rhtV1IkB/tdwwNKpLTrzqp8g5yRC4yE2C7EKFMzUpeFKvKelZ3bu+q UE5bpNSGDhwCQyyKwLOhqzYm0rDufOPv5Hnq8GugzSaNexD75SQsSbK6TXvEsc9SAbyo FvHZGsq8zNv2/NE67nSjylXBlH4RFsLPsYit+SxZrwwjP71El5dZJ6gkxp5KL70qwaMv 1MnQ== X-Gm-Message-State: AFqh2kqHUO+qKvmhwhJ+w02isINlzQwBDiDMYTV+Oq5qaML3/USDmv+T 5/FJ3w47vQbbRa3wzNrLeN3y9h6wja2boW7z5AIVgs2mM7mCbNO0kwCe6Q6LmFh0EvzRjmcMz3y eFmoYCcGafq6NaXl4Cst/2hgC1JpCHNS6gzm1yFyiohvUqyjZ8uISBdn4kbySOS5OfzfaEJGxHw == X-Received: by 2002:a05:622a:50e:b0:3b6:9753:6429 with SMTP id l14-20020a05622a050e00b003b697536429mr4794899qtx.39.1674208006814; Fri, 20 Jan 2023 01:46:46 -0800 (PST) X-Google-Smtp-Source: AMrXdXsDjX2OjVQojy86q7qwR8Hds+YL6ScEaVO3wCj9ZDXR1uMWubnZCPlOF0/2apB562+CvStf3Q== X-Received: by 2002:a05:622a:50e:b0:3b6:9753:6429 with SMTP id l14-20020a05622a050e00b003b697536429mr4794785qtx.39.1674208005375; Fri, 20 Jan 2023 01:46:45 -0800 (PST) Received: from localhost (95.72.115.87.dyn.plus.net. [87.115.72.95]) by smtp.gmail.com with ESMTPSA id p16-20020a05620a057000b006fafaac72a6sm25194911qkp.84.2023.01.20.01.46.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Jan 2023 01:46:45 -0800 (PST) To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv2 5/6] gdb: add inferior-specific breakpoints and watchpoints Date: Fri, 20 Jan 2023 09:46:28 +0000 Message-Id: <050da90b0b8c886983ec472a957b1075d4ecf7d6.1674207665.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) 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-Patchwork-Original-From: Andrew Burgess via Gdb-patches From: Andrew Burgess Reply-To: Andrew Burgess Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" This commit extends the breakpoint mechanism to allow for inferior specific breakpoints (and watchpoints). As GDB gains better support for multiple connections, and so for running multiple (possibly unrelated) inferiors, then it is not hard to imagine that a user might wish to create breakpoints that apply to any thread in a single inferior. To achieve this currently, the user would need to create a condition possibly making use of the $_inferior convenience variable, which, though functional, isn't the most user friendly. This commit adds a new 'inferior' keyword that allows for the creation of inferior specific breakpoints. Like thread specific breakpoints, the inferior specific breakpoints are automatically deleted once the inferior in question exits. --- gdb/NEWS | 7 + gdb/breakpoint.c | 171 +++++++++++++--- gdb/breakpoint.h | 10 +- gdb/doc/gdb.texinfo | 74 ++++++- gdb/doc/python.texi | 24 ++- gdb/dummy-frame.c | 1 + gdb/elfread.c | 5 +- gdb/guile/scm-breakpoint.c | 5 + gdb/inferior.h | 11 ++ gdb/infrun.c | 2 + gdb/linespec.c | 4 +- gdb/python/py-breakpoint.c | 77 ++++++++ gdb/testsuite/gdb.linespec/cpcompletion.exp | 4 +- gdb/testsuite/gdb.linespec/explicit.exp | 1 + .../gdb.multi/inferior-specific-bp-1.c | 52 +++++ .../gdb.multi/inferior-specific-bp-2.c | 52 +++++ .../gdb.multi/inferior-specific-bp.exp | 182 ++++++++++++++++++ gdb/testsuite/gdb.python/py-breakpoint.exp | 43 +++++ gdb/testsuite/lib/completion-support.exp | 2 +- 19 files changed, 680 insertions(+), 47 deletions(-) create mode 100644 gdb/testsuite/gdb.multi/inferior-specific-bp-1.c create mode 100644 gdb/testsuite/gdb.multi/inferior-specific-bp-2.c create mode 100644 gdb/testsuite/gdb.multi/inferior-specific-bp.exp diff --git a/gdb/NEWS b/gdb/NEWS index fb49f62f7e6..cde9a835b2e 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -18,6 +18,13 @@ instance of the keyword. The 'thread' keyword already gave an error when used multiple times with the watch command, this remains unchanged. +* Breakpoints can now be inferior-specific. This is similar to the + existing thread-specific breakpoint support. Breakpoint conditions + can include the 'inferior' keyword followed by an inferior id (as + displayed in the 'info inferiors' output). It is invalid to use + both the 'inferior' and 'thread' keywords when creating a + breakpoint. + * New commands maintenance print record-instruction [ N ] diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 1400fd49642..a7c7c27017b 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -96,7 +96,7 @@ static void create_breakpoints_sal (struct gdbarch *, gdb::unique_xmalloc_ptr, gdb::unique_xmalloc_ptr, enum bptype, - enum bpdisp, int, int, + enum bpdisp, int, int, int, int, int, int, int, unsigned); @@ -1462,11 +1462,28 @@ breakpoint_set_thread (struct breakpoint *b, int thread) { int old_thread = b->thread; + gdb_assert (thread == -1 || b->inferior == -1); + b->thread = thread; if (old_thread != thread) gdb::observers::breakpoint_modified.notify (b); } +/* Set the inferior for breakpoint B to INFERIOR. If INFERIOR is -1, make + the breakpoint work for any inferior. */ + +void +breakpoint_set_inferior (struct breakpoint *b, int inferior) +{ + int old_inferior = b->inferior; + + gdb_assert (inferior == -1 || b->thread == -1); + + b->inferior = inferior; + if (old_inferior != inferior) + gdb::observers::breakpoint_modified.notify (b); +} + /* Set the task for this breakpoint. If TASK is 0, make the breakpoint work for any task. */ @@ -3152,6 +3169,12 @@ insert_breakpoint_locations (void) && !valid_global_thread_id (bl->owner->thread)) continue; + /* Or inferior specific breakpoints if the inferior no longer + exists. */ + if (bl->owner->inferior != -1 + && !valid_global_inferior_id (bl->owner->inferior)) + continue; + switch_to_program_space_and_thread (bl->pspace); /* For targets that support global breakpoints, there's no need @@ -3256,6 +3279,31 @@ Thread-specific breakpoint %d deleted - thread %s no longer in the thread list.\ } } +/* Called when inferior INF has exited. Remove per-inferior breakpoints. */ + +static void +remove_inferior_breakpoints (struct inferior *inf) +{ + for (breakpoint *b : all_breakpoints_safe ()) + { + if (b->inferior == inf->num && user_breakpoint_p (b)) + { + /* Tell the user the breakpoint has been deleted. But only for + breakpoints that would not normally have been deleted at the + next stop anyway. */ + if (b->disposition != disp_del + && b->disposition != disp_del_at_next_stop) + gdb_printf (_("\ +Inferior-specific breakpoint %d deleted - inferior %d has exited.\n"), + b->number, inf->num); + + /* Hide it from the user and mark it for deletion. */ + b->number = 0; + b->disposition = disp_del_at_next_stop; + } + } +} + /* See breakpoint.h. */ void @@ -5465,6 +5513,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->inferior != -1 && b->inferior != thread->inf->num) || (b->task != 0 && b->task != ada_get_task_number (thread))) { infrun_debug_printf ("incorrect thread or task, not stopping"); @@ -6481,6 +6530,8 @@ print_one_breakpoint_location (struct breakpoint *b, uiout->field_signed ("thread", b->thread); else if (b->task != 0) uiout->field_signed ("task", b->task); + else if (b->inferior != -1) + uiout->field_signed ("inferior", b->inferior); } uiout->text ("\n"); @@ -6543,6 +6594,13 @@ print_one_breakpoint_location (struct breakpoint *b, uiout->text ("\n"); } + if (!part_of_multiple && b->inferior != -1) + { + uiout->text ("\tstop only in inferior "); + uiout->field_signed ("inferior", b->inferior); + uiout->text ("\n"); + } + if (!part_of_multiple) { if (b->hit_count) @@ -7516,7 +7574,10 @@ delete_longjmp_breakpoint (int thread) if (b->type == bp_longjmp || b->type == bp_exception) { if (b->thread == thread) - delete_breakpoint (b); + { + gdb_assert (b->inferior == -1); + delete_breakpoint (b); + } } } @@ -7527,7 +7588,10 @@ delete_longjmp_breakpoint_at_next_stop (int thread) if (b->type == bp_longjmp || b->type == bp_exception) { if (b->thread == thread) - b->disposition = disp_del_at_next_stop; + { + gdb_assert (b->inferior == -1); + b->disposition = disp_del_at_next_stop; + } } } @@ -7580,6 +7644,7 @@ check_longjmp_breakpoint_for_call_dummy (struct thread_info *tp) ALL_BREAKPOINTS_SAFE (b, b_tmp) if (b->type == bp_longjmp_call_dummy && b->thread == tp->global_num) { + gdb_assert (b->inferior == -1); struct breakpoint *dummy_b = b->related_breakpoint; /* Find the bp_call_dummy breakpoint in the list of breakpoints @@ -8412,7 +8477,8 @@ code_breakpoint::code_breakpoint (struct gdbarch *gdbarch_, gdb::unique_xmalloc_ptr cond_string_, gdb::unique_xmalloc_ptr extra_string_, enum bpdisp disposition_, - int thread_, int task_, int ignore_count_, + int thread_, int task_, int inferior_, + int ignore_count_, int from_tty, int enabled_, unsigned flags, int display_canonical_) @@ -8438,6 +8504,11 @@ code_breakpoint::code_breakpoint (struct gdbarch *gdbarch_, thread = thread_; task = task_; + inferior = inferior_; + + /* A breakpoint can be thread specific, or inferior specific, but not + both. This should be checked when the breakpoint condition is parsed. */ + gdb_assert (thread == -1 || inferior == -1); cond_string = std::move (cond_string_); extra_string = std::move (extra_string_); @@ -8539,7 +8610,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch, gdb::unique_xmalloc_ptr cond_string, gdb::unique_xmalloc_ptr extra_string, enum bptype type, enum bpdisp disposition, - int thread, int task, int ignore_count, + int thread, int task, int inferior, int ignore_count, int from_tty, int enabled, int internal, unsigned flags, int display_canonical) @@ -8553,7 +8624,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch, std::move (cond_string), std::move (extra_string), disposition, - thread, task, ignore_count, + thread, task, inferior, ignore_count, from_tty, enabled, flags, display_canonical); @@ -8582,7 +8653,8 @@ create_breakpoints_sal (struct gdbarch *gdbarch, gdb::unique_xmalloc_ptr cond_string, gdb::unique_xmalloc_ptr extra_string, enum bptype type, enum bpdisp disposition, - int thread, int task, int ignore_count, + int thread, int task, int inferior, + int ignore_count, int from_tty, int enabled, int internal, unsigned flags) { @@ -8606,7 +8678,7 @@ create_breakpoints_sal (struct gdbarch *gdbarch, std::move (cond_string), std::move (extra_string), type, disposition, - thread, task, ignore_count, + thread, task, inferior, ignore_count, from_tty, enabled, internal, flags, canonical->special_display); } @@ -8736,21 +8808,26 @@ check_fast_tracepoint_sals (struct gdbarch *gdbarch, } } -/* Given TOK, a string specification of condition and thread, as - accepted by the 'break' command, extract the condition - string and thread number and set *COND_STRING and *THREAD. - PC identifies the context at which the condition should be parsed. - If no condition is found, *COND_STRING is set to NULL. - If no thread is found, *THREAD is set to -1. */ +/* Given TOK, a string specification of condition and thread, as accepted + by the 'break' command, extract the condition string into *COND_STRING. + If no condition string is found then *COND_STRING is set to nullptr. + + If the breakpoint specification has an associated thread, task, or + inferior, these are extracted into *THREAD, *TASK, and *INFERIOR + respectively, otherwise these arguments are set to -1 (for THREAD and + INFERIOR) or 0 (for TASK). + + PC identifies the context at which the condition should be parsed. */ static void find_condition_and_thread (const char *tok, CORE_ADDR pc, gdb::unique_xmalloc_ptr *cond_string, - int *thread, int *task, + int *thread, int *inferior, int *task, gdb::unique_xmalloc_ptr *rest) { cond_string->reset (); *thread = -1; + *inferior = -1; *task = 0; rest->reset (); bool force = false; @@ -8767,7 +8844,7 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc, if ((*tok == '"' || *tok == ',') && rest) { rest->reset (savestring (tok, strlen (tok))); - return; + break; } end_tok = skip_to_space (tok); @@ -8811,6 +8888,18 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc, *thread = thr->global_num; tok = tmptok; } + else if (toklen >= 1 && strncmp (tok, "inferior", toklen) == 0) + { + char *tmptok; + + tok = end_tok + 1; + *inferior = strtol (tok, &tmptok, 0); + if (tok == tmptok) + error (_("Junk after inferior keyword.")); + if (!valid_global_inferior_id (*inferior)) + error (_("Unknown inferior number %d."), *inferior); + tok = tmptok; + } else if (toklen >= 1 && strncmp (tok, "task", toklen) == 0) { char *tmptok; @@ -8829,11 +8918,15 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc, else if (rest) { rest->reset (savestring (tok, strlen (tok))); - return; + break; } else error (_("Junk at end of arguments.")); } + + if (*thread != -1 && *inferior != -1) + error (_("Cannot have both 'thread' and 'inferior' conditions on " + "a breakpoint")); } /* Call 'find_condition_and_thread' for each sal in SALS until a parse @@ -8845,7 +8938,7 @@ static void find_condition_and_thread_for_sals (const std::vector &sals, const char *input, gdb::unique_xmalloc_ptr *cond_string, - int *thread, int *task, + int *thread, int *inferior, int *task, gdb::unique_xmalloc_ptr *rest) { int num_failures = 0; @@ -8853,6 +8946,7 @@ find_condition_and_thread_for_sals (const std::vector &sals, { gdb::unique_xmalloc_ptr cond; int thread_id = 0; + int inferior_id = 0; int task_id = 0; gdb::unique_xmalloc_ptr remaining; @@ -8865,9 +8959,10 @@ find_condition_and_thread_for_sals (const std::vector &sals, try { find_condition_and_thread (input, sal.pc, &cond, &thread_id, - &task_id, &remaining); + &inferior_id, &task_id, &remaining); *cond_string = std::move (cond); *thread = thread_id; + *inferior = inferior_id; *task = task_id; *rest = std::move (remaining); break; @@ -8969,6 +9064,7 @@ create_breakpoint (struct gdbarch *gdbarch, struct linespec_result canonical; bool pending = false; int task = 0; + int inferior = -1; int prev_bkpt_count = breakpoint_count; gdb_assert (ops != NULL); @@ -9046,7 +9142,8 @@ create_breakpoint (struct gdbarch *gdbarch, const linespec_sals &lsal = canonical.lsals[0]; find_condition_and_thread_for_sals (lsal.sals, extra_string, - &cond, &thread, &task, &rest); + &cond, &thread, &inferior, + &task, &rest); cond_string_copy = std::move (cond); extra_string_copy = std::move (rest); } @@ -9096,7 +9193,7 @@ create_breakpoint (struct gdbarch *gdbarch, std::move (extra_string_copy), type_wanted, tempflag ? disp_del : disp_donttouch, - thread, task, ignore_count, + thread, task, inferior, ignore_count, from_tty, enabled, internal, flags); } else @@ -10036,6 +10133,7 @@ watch_command_1 (const char *arg, int accessflag, int from_tty, const char *cond_end = NULL; enum bptype bp_type; int thread = -1; + int inferior = -1; /* Flag to indicate whether we are going to use masks for the hardware watchpoint. */ bool use_mask = false; @@ -10076,6 +10174,10 @@ watch_command_1 (const char *arg, int accessflag, int from_tty, tok++; toklen = end_tok - tok + 1; + if (thread != -1 && inferior != -1) + error (_("Cannot have both 'thread' and 'inferior' conditions " + "on a watchpoint")); + if (toklen == 6 && startswith (tok, "thread")) { struct thread_info *thr; @@ -10089,10 +10191,8 @@ watch_command_1 (const char *arg, int accessflag, int from_tty, /* Extract the thread ID from the next token. */ thr = parse_thread_id (value_start, &endp); - - /* Check if the user provided a valid thread ID. */ - if (*endp != ' ' && *endp != '\t' && *endp != '\0') - invalid_thread_id_error (value_start); + if (value_start == endp) + error (_("Junk after thread keyword.")); thread = thr->global_num; } @@ -10109,6 +10209,16 @@ watch_command_1 (const char *arg, int accessflag, int from_tty, if (!valid_task_id (task)) error (_("Unknown task %d."), task); } + else if (toklen == 8 && startswith (tok, "inferior")) + { + char *tmp; + + inferior = strtol (value_start, &tmp, 0); + if (tmp == value_start) + error (_("Junk after inferior keyword.")); + if (!valid_global_inferior_id (inferior)) + error (_("Unknown inferior number %d."), inferior); + } else if (toklen == 4 && startswith (tok, "mask")) { /* We've found a "mask" token, which means the user wants to @@ -10279,6 +10389,7 @@ watch_command_1 (const char *arg, int accessflag, int from_tty, w.reset (new watchpoint (nullptr, bp_type)); w->thread = thread; + w->inferior = inferior; w->task = task; w->disposition = disp_donttouch; w->pspace = current_program_space; @@ -12189,7 +12300,8 @@ strace_marker_create_breakpoints_sal (struct gdbarch *gdbarch, enum bptype type_wanted, enum bpdisp disposition, int thread, - int task, int ignore_count, + int task, int inferior, + int ignore_count, int from_tty, int enabled, int internal, unsigned flags) { @@ -12215,7 +12327,7 @@ strace_marker_create_breakpoints_sal (struct gdbarch *gdbarch, std::move (cond_string), std::move (extra_string), disposition, - thread, task, ignore_count, + thread, task, inferior, ignore_count, from_tty, enabled, flags, canonical->special_display)); @@ -12848,10 +12960,11 @@ code_breakpoint::location_spec_to_sals (location_spec *locspec, if (condition_not_parsed && extra_string != NULL) { gdb::unique_xmalloc_ptr local_cond, local_extra; - int local_thread, local_task; + int local_thread, local_task, local_inferior; find_condition_and_thread_for_sals (sals, extra_string.get (), &local_cond, &local_thread, + &local_inferior, &local_task, &local_extra); gdb_assert (cond_string == nullptr); if (local_cond != nullptr) @@ -14937,4 +15050,6 @@ This is useful for formatted output in user-defined commands.")); "breakpoint"); gdb::observers::thread_exit.attach (remove_threaded_breakpoints, "breakpoint"); + gdb::observers::inferior_exit.attach (remove_inferior_breakpoints, + "breakpoint"); } diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index 399bd037977..0ec7c4fe8e1 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -584,7 +584,7 @@ struct breakpoint_ops struct linespec_result *, gdb::unique_xmalloc_ptr, gdb::unique_xmalloc_ptr, - enum bptype, enum bpdisp, int, int, + enum bptype, enum bpdisp, int, int, int, int, int, int, int, unsigned); }; @@ -802,6 +802,10 @@ struct breakpoint care. */ int thread = -1; + /* Inferior number for inferior-specific breakpoint, or -1 if this + breakpoint is for all inferiors. */ + int inferior = -1; + /* Ada task number for task-specific breakpoint, or 0 if don't care. */ int task = 0; @@ -857,7 +861,7 @@ struct code_breakpoint : public breakpoint gdb::unique_xmalloc_ptr cond_string, gdb::unique_xmalloc_ptr extra_string, enum bpdisp disposition, - int thread, int task, int ignore_count, + int thread, int task, int inferior, int ignore_count, int from_tty, int enabled, unsigned flags, int display_canonical); @@ -1673,6 +1677,8 @@ extern void breakpoint_set_silent (struct breakpoint *b, int silent); extern void breakpoint_set_thread (struct breakpoint *b, int thread); +extern void breakpoint_set_inferior (struct breakpoint *b, int inferior); + extern void breakpoint_set_task (struct breakpoint *b, int task); /* Clear the "inserted" flag in all breakpoints. */ diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 9c0018ea5c1..6f07193af77 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -3504,6 +3504,58 @@ space as a result of inferior 1 having executed a @code{vfork} call. @end table +@menu +* Inferior-Specific Breakpoints:: Controlling breakpoints +@end menu + +@node Inferior-Specific Breakpoints +@subsection Inferior-Specific Breakpoints + +When debugging multiple inferiors, you can choose whether to set +breakpoints for all inferiors, or for a particular inferior. + +@table @code +@cindex breakpoints and inferiors +@cindex inferior-specific breakpoints +@kindex break @dots{} inferior @var{inferior-id} +@item break @var{locspec} inferior @var{inferior-id} +@itemx break @var{locspec} inferior @var{inferior-id} if @dots{} +@var{locspec} specifies a code location or locations in your program. +@xref{Location Specifications}, for details. + +Use the qualifier @samp{inferior @var{inferior-id}} with a breakpoint +command to specify that you only want @value{GDBN} to stop when a +particular inferior reaches this breakpoint. The @var{inferior-id} +specifier is one of the inferior identifiers assigned by @value{GDBN}, +shown in the first column of the @samp{info inferiors} output. + +If you do not specify @samp{inferior @var{inferior-id}} when you set a +breakpoint, the breakpoint applies to @emph{all} inferiors of your +program. + +You can use the @code{inferior} qualifier on conditional breakpoints as +well; in this case, place @samp{inferior @var{inferior-id}} before or +after the breakpoint condition, like this: + +@smallexample +(@value{GDBP}) break frik.c:13 inferior 2 if bartab > lim +@end smallexample +@end table + +Inferior-specific breakpoints are automatically deleted when +@value{GDBN} detects that the corresponding inferior has exited. For +example: + +@smallexample +(@value{GDBP}) c +Inferior-specific breakpoint 3 deleted - inferior 2 has exited. +@end smallexample + +A breakpoint can't be both inferior-specific and thread-specific +(@pxref{Thread-Specific Breakpoints}); using both the @code{inferior} +and @code{thread} keywords when creating a breakpoint will give an +error. + @node Threads @section Debugging Programs with Multiple Threads @@ -4466,8 +4518,9 @@ situation. It is also possible to insert a breakpoint that will stop the program -only if a specific thread (@pxref{Thread-Specific Breakpoints}) -or a specific task (@pxref{Ada Tasks}) hits that breakpoint. +only if a specific thread (@pxref{Thread-Specific Breakpoints}), +specific inferior (@pxref{Inferior-Specific Breakpoints}), or a +specific task (@pxref{Ada Tasks}) hits that breakpoint. @item break When called without any arguments, @code{break} sets a breakpoint at @@ -4983,7 +5036,7 @@ @table @code @kindex watch -@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{]} +@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{thread-id}@r{]} @r{[}inferior @var{inferior-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 @@ -5000,8 +5053,10 @@ 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}). +Similarly, if the @code{inferior} argument is given, then the +watchpoint will trigger only for the specific inferior, or 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 @@ -5030,12 +5085,12 @@ @end smallexample @kindex rwatch -@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{thread-id}@r{]} @r{[}mask @var{maskvalue}@r{]} +@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{thread-id}@r{]} @r{[}inferior @var{inferior-id}@r{]} @r{[}mask @var{maskvalue}@r{]} Set a watchpoint that will break when the value of @var{expr} is read by the program. @kindex awatch -@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{thread-id}@r{]} @r{[}mask @var{maskvalue}@r{]} +@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{thread-id}@r{]} @r{[}inferior @var{inferior-id}@r{]} @r{[}mask @var{maskvalue}@r{]} Set a watchpoint that will break when @var{expr} is either read from or written into by the program. @@ -7318,6 +7373,11 @@ explictly asks for the thread list with the @code{info threads} command. +A breakpoint can't be both thread-specific and inferior-specific +(@pxref{Inferior-Specific Breakpoints}) using both the @code{thread} +and @code{inferior} keywords when creating a breakpoint will give an +error. + @node Interrupted System Calls @subsection Interrupted System Calls diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index 7208af3ee7d..5420324ce2c 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -3281,7 +3281,10 @@ A @code{gdb.Inferior} object has the following attributes: @defvar Inferior.num -ID of inferior, as assigned by GDB. +ID of inferior, as assigned by @value{GDBN}. You can use this to make +Python breakpoints inferior-specific, for example +(@pxref{python_breakpoint_inferior,,The Breakpoint.inferior +attribute}). @end defvar @anchor{gdbpy_inferior_connection} @@ -6077,9 +6080,22 @@ @anchor{python_breakpoint_thread} @defvar Breakpoint.thread -If the breakpoint is thread-specific, this attribute holds the -thread's global id. If the breakpoint is not thread-specific, this -attribute is @code{None}. This attribute is writable. +If the breakpoint is thread-specific (@pxref{Thread-Specific +Breakpoints}), this attribute holds the thread's global id. If the +breakpoint is not thread-specific, this attribute is @code{None}. +This attribute is writable. + +Only one of @code{Breakpoint.thread} or @code{Breakpoint.inferior} can +be set to a valid id at any time, that is, a breakpoint can be thread +specific, or inferior specific, but not both. +@end defvar + +@anchor{python_breakpoint_inferior} +@defvar Breakpoint.inferior +If the breakpoint is inferior-specific (@pxref{Inferior-Specific +Breakpoints}), this attribute holds the inferior's id. If the +breakpoint is not inferior-specific, this attribute is @code{None}. +This attribute is writable. @end defvar @defvar Breakpoint.task diff --git a/gdb/dummy-frame.c b/gdb/dummy-frame.c index 784ac103eec..ad861d8d87f 100644 --- a/gdb/dummy-frame.c +++ b/gdb/dummy-frame.c @@ -132,6 +132,7 @@ pop_dummy_frame_bpt (struct breakpoint *b, struct dummy_frame *dummy) if (b->thread == dummy->id.thread->global_num && b->disposition == disp_del && b->frame_id == dummy->id.id) { + gdb_assert (b->inferior == -1); while (b->related_breakpoint != b) delete_breakpoint (b->related_breakpoint); diff --git a/gdb/elfread.c b/gdb/elfread.c index ccee37406c8..cc1b339da75 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -968,7 +968,10 @@ elf_gnu_ifunc_resolver_stop (code_breakpoint *b) if (b_return->thread == thread_id && b_return->loc->requested_address == prev_pc && b_return->frame_id == prev_frame_id) - break; + { + gdb_assert (b_return->inferior == -1); + break; + } } if (b_return == b) diff --git a/gdb/guile/scm-breakpoint.c b/gdb/guile/scm-breakpoint.c index a7e043d847b..4c6fff070cf 100644 --- a/gdb/guile/scm-breakpoint.c +++ b/gdb/guile/scm-breakpoint.c @@ -779,6 +779,11 @@ gdbscm_set_breakpoint_thread_x (SCM self, SCM newvalue) else SCM_ASSERT_TYPE (0, newvalue, SCM_ARG2, FUNC_NAME, _("integer or #f")); + if (bp_smob->bp->inferior != -1) + scm_misc_error (FUNC_NAME, + _("Cannot have both thread and inferior conditions " + "on a breakpoint"), SCM_EOL); + breakpoint_set_thread (bp_smob->bp, id); return SCM_UNSPECIFIED; diff --git a/gdb/inferior.h b/gdb/inferior.h index 4d001b0ad50..e728a3481ad 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -787,4 +787,15 @@ extern void print_selected_inferior (struct ui_out *uiout); extern void switch_to_inferior_and_push_target (inferior *new_inf, bool no_connection, inferior *org_inf); +/* Return true if ID is a valid global inferior number. */ + +inline bool +valid_global_inferior_id (int id) +{ + for (inferior *inf : all_inferiors ()) + if (inf->num == id) + return true; + return false; +} + #endif /* !defined (INFERIOR_H) */ diff --git a/gdb/infrun.c b/gdb/infrun.c index edfb5ab0a91..6cfb097c03a 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -8004,6 +8004,7 @@ insert_exception_resume_breakpoint (struct thread_info *tp, frame = nullptr; bp->thread = tp->global_num; + bp->inferior = -1; inferior_thread ()->control.exception_resume_breakpoint = bp; } } @@ -8037,6 +8038,7 @@ insert_exception_resume_from_probe (struct thread_info *tp, bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame), handler, bp_exception_resume).release (); bp->thread = tp->global_num; + bp->inferior = -1; inferior_thread ()->control.exception_resume_breakpoint = bp; } diff --git a/gdb/linespec.c b/gdb/linespec.c index d3def7ae070..93cc68f28e8 100644 --- a/gdb/linespec.c +++ b/gdb/linespec.c @@ -254,9 +254,9 @@ enum linespec_token_type /* List of keywords. This is NULL-terminated so that it can be used as enum completer. */ -const char * const linespec_keywords[] = { "if", "thread", "task", "-force-condition", NULL }; +const char * const linespec_keywords[] = { "if", "thread", "task", "inferior", "-force-condition", NULL }; #define IF_KEYWORD_INDEX 0 -#define FORCE_KEYWORD_INDEX 3 +#define FORCE_KEYWORD_INDEX 4 /* A token of the linespec lexer */ diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c index 1b10ccd5415..fc99bbf162c 100644 --- a/gdb/python/py-breakpoint.c +++ b/gdb/python/py-breakpoint.c @@ -280,11 +280,69 @@ bppy_set_thread (PyObject *self, PyObject *newvalue, void *closure) return -1; } + if (self_bp->bp->inferior != -1 && id != -1) + { + PyErr_SetString (PyExc_RuntimeError, + _("Cannot have both thread and inferior conditions " + "on a breakpoint")); + return -1; + } + breakpoint_set_thread (self_bp->bp, id); return 0; } +/* Python function to set the inferior of a breakpoint. */ + +static int +bppy_set_inferior (PyObject *self, PyObject *newvalue, void *closure) +{ + gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self; + long id; + + BPPY_SET_REQUIRE_VALID (self_bp); + + if (newvalue == NULL) + { + PyErr_SetString (PyExc_TypeError, + _("Cannot delete `inferior' attribute.")); + return -1; + } + else if (PyLong_Check (newvalue)) + { + if (!gdb_py_int_as_long (newvalue, &id)) + return -1; + + if (!valid_global_inferior_id (id)) + { + PyErr_SetString (PyExc_RuntimeError, + _("Invalid inferior ID.")); + return -1; + } + } + else if (newvalue == Py_None) + id = -1; + else + { + PyErr_SetString (PyExc_TypeError, + _("The value of `inferior' must be an integer or None.")); + return -1; + } + + if (self_bp->bp->thread != -1 && id != -1) + { + PyErr_SetString (PyExc_RuntimeError, + _("Cannot have both thread and inferior conditions " + "on a breakpoint")); + return -1; + } + + breakpoint_set_inferior (self_bp->bp, id); + + return 0; +} + /* Python function to set the (Ada) task of a breakpoint. */ static int bppy_set_task (PyObject *self, PyObject *newvalue, void *closure) @@ -689,6 +747,20 @@ bppy_get_thread (PyObject *self, void *closure) return gdb_py_object_from_longest (self_bp->bp->thread).release (); } +/* Python function to get the breakpoint's inferior ID. */ +static PyObject * +bppy_get_inferior (PyObject *self, void *closure) +{ + gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self; + + BPPY_REQUIRE_VALID (self_bp); + + if (self_bp->bp->inferior == -1) + Py_RETURN_NONE; + + return gdb_py_object_from_longest (self_bp->bp->inferior).release (); +} + /* Python function to get the breakpoint's task ID (in Ada). */ static PyObject * bppy_get_task (PyObject *self, void *closure) @@ -1333,6 +1405,11 @@ static gdb_PyGetSetDef breakpoint_object_getset[] = { If the value is a thread ID (integer), then this is a thread-specific breakpoint.\n\ If the value is None, then this breakpoint is not thread-specific.\n\ No other type of value can be used.", NULL }, + { "inferior", bppy_get_inferior, bppy_set_inferior, + "Inferior ID for the breakpoint.\n\ +If the value is an inferior ID (integer), then this is an inferior-specific\n\ +breakpoint. If the value is None, then this breakpoint is not\n\ +inferior-specific. No other type of value can be used.", NULL }, { "task", bppy_get_task, bppy_set_task, "Thread ID for the breakpoint.\n\ If the value is a task ID (integer), then this is an Ada task-specific breakpoint.\n\ diff --git a/gdb/testsuite/gdb.linespec/cpcompletion.exp b/gdb/testsuite/gdb.linespec/cpcompletion.exp index fbe19b49d43..f005707b9da 100644 --- a/gdb/testsuite/gdb.linespec/cpcompletion.exp +++ b/gdb/testsuite/gdb.linespec/cpcompletion.exp @@ -1259,8 +1259,8 @@ proc_with_prefix function-labels {} { } # Test that completion after a function name offers keyword -# (if/task/thread/-force-condition) matches in linespec mode, and also -# the explicit location options in explicit locations mode. +# (if/inferior/task/thread/-force-condition) matches in linespec mode, +# and also the explicit location options in explicit locations mode. proc_with_prefix keywords-after-function {} { set explicit_list \ diff --git a/gdb/testsuite/gdb.linespec/explicit.exp b/gdb/testsuite/gdb.linespec/explicit.exp index 637470e6763..3845bab8bc6 100644 --- a/gdb/testsuite/gdb.linespec/explicit.exp +++ b/gdb/testsuite/gdb.linespec/explicit.exp @@ -412,6 +412,7 @@ namespace eval $testfile { "-qualified" "-source" "if" + "inferior" "task" "thread" } diff --git a/gdb/testsuite/gdb.multi/inferior-specific-bp-1.c b/gdb/testsuite/gdb.multi/inferior-specific-bp-1.c new file mode 100644 index 00000000000..26cb01911d2 --- /dev/null +++ b/gdb/testsuite/gdb.multi/inferior-specific-bp-1.c @@ -0,0 +1,52 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2022 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 . */ + +volatile int global_var = 0; + +static void +stop_breakpt (void) +{ + /* Nothing. */ +} + +static inline void __attribute__((__always_inline__)) +foo (void) +{ + int i; + + for (i = 0; i < 10; ++i) + global_var = 0; +} + +static void +bar (void) +{ + global_var = 0; + + foo (); +} + + +int +main (void) +{ + global_var = 0; + foo (); + bar (); + stop_breakpt (); + return 0; +} diff --git a/gdb/testsuite/gdb.multi/inferior-specific-bp-2.c b/gdb/testsuite/gdb.multi/inferior-specific-bp-2.c new file mode 100644 index 00000000000..3ddb1a17446 --- /dev/null +++ b/gdb/testsuite/gdb.multi/inferior-specific-bp-2.c @@ -0,0 +1,52 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2022 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 . */ + +static int bar (void); +static int baz (void); +static int foo (void); + +static void +stop_breakpt (void) +{ + /* Nothing. */ +} + +int +main (void) +{ + int ret = baz (); + stop_breakpt (); + return ret; +} + +static int +bar (void) +{ + return baz (); +} + +static int +foo (void) +{ + return 0; +} + +static int +baz (void) +{ + return foo (); +} diff --git a/gdb/testsuite/gdb.multi/inferior-specific-bp.exp b/gdb/testsuite/gdb.multi/inferior-specific-bp.exp new file mode 100644 index 00000000000..4e80adf76ae --- /dev/null +++ b/gdb/testsuite/gdb.multi/inferior-specific-bp.exp @@ -0,0 +1,182 @@ +# Copyright 2022 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 inferior-specific breakpoints. + +standard_testfile -1.c -2.c + +if {[use_gdb_stub]} { + return +} + +set srcfile1 ${srcfile} +set binfile1 ${binfile}-1 +set binfile2 ${binfile}-2 + +if {[build_executable ${testfile}.exp ${binfile1} "${srcfile1}"] != 0} { + return -1 +} + +if {[build_executable ${testfile}.exp ${binfile2} "${srcfile2}"] != 0} { + return -1 +} + +# Start the first inferior. +clean_restart ${binfile1} +if {![runto_main]} { + return +} + +# Add a second inferior, and start this one too. +gdb_test "add-inferior" "Added inferior 2.*" "add empty inferior 2" +gdb_test "inferior 2" "Switching to inferior 2.*" "switch to inferior 2" +gdb_load $binfile2 +if {![runto_main]} { + return +} + +# Try to create a breakpoint using both the 'inferior' and 'thread' keywords, +# this should fail. Try with the keywords in both orders just in case the +# parser has a bug. +gdb_test "break foo thread 1.1 inferior 1" \ + "Cannot have both 'thread' and 'inferior' conditions on a breakpoint" +gdb_test "break foo inferior 1 thread 1.1" \ + "Cannot have both 'thread' and 'inferior' conditions on a breakpoint" + +# While we're here, check that we can't create a watchpoint with both thread +# and inferior keywords. As above, test with keywords in both orders. +foreach type {watch rwatch awatch} { + gdb_test "$type global_var thread 1.1 inferior 1" \ + "Cannot have both 'thread' and 'inferior' conditions on a watchpoint" + gdb_test "$type global_var inferior 1 thread 1.1" \ + "Cannot have both 'thread' and 'inferior' conditions on a watchpoint" +} + +# Clear out any other breakpoints. +delete_breakpoints + +# Create an inferior-specific breakpoint. Use gdb_test instead of +# gdb_breakpoint here as we want to check the breakpoint was placed in +# multiple locations. +gdb_test "break foo inferior 1" \ + "Breakpoint $decimal at $hex: foo\\. \\(3 locations\\)" + +set saw_header false +set location_count 0 +set saw_inf_cond false +gdb_test_multiple "info breakpoints" "" { + -re "\r\nNum\\s+\[^\r\n\]+\r\n" { + exp_continue + } + + -re "^$decimal\\s+breakpoint\\s+keep\\s+y\\s+\\s*\r\n" { + set saw_header true + exp_continue + } + + -re "^\\s+stop only in inferior 1\r\n" { + set saw_inf_cond true + exp_continue + } + + -re "^$decimal\\.\[123\]\\s+y\\s+ $hex in foo at \[^\r\n\]+ inf \[12\]\r\n" { + incr location_count + exp_continue + } + + -re "^$gdb_prompt $" { + with_test_prefix $gdb_test_name { + gdb_assert { $saw_header } + gdb_assert { $location_count == 3 } + gdb_assert { $saw_inf_cond } + } + } +} + +# Create a multi-inferior breakpoint to stop at. +gdb_test "break stop_breakpt" + +# Now resume inferior 2, this should reach 'stop_breakpt'. +gdb_test "continue" "hit Breakpoint $decimal\.$decimal, stop_breakpt \\(\\) .*" \ + "continue in inferior 2" + +# Switch to inferior 1, and try there. +gdb_test "inferior 1" ".*" \ + "select inferior 1 to check the inferior-specific b/p works" +gdb_test "continue " \ + "Thread 1\\.${decimal}\[^\r\n\]* hit Breakpoint $decimal\.$decimal, foo \\(\\) .*" \ + "first continue in inferior 1" + +# Now back to inferior 2, let the inferior exit, the inferior-specific +# breakpoint should not be deleted. +gdb_test "inferior 2" ".*" \ + "switch back to allow inferior 2 to exit" +gdb_test "continue" "Inferior 2 \[^\r\n\]+ exited normally.*" \ + "allow inferior 2 to exit" + +gdb_test "inferior 1" ".*" \ + "select inferior 1 to check inferior-specific b/p still works" +gdb_test "continue " "hit Breakpoint $decimal\.$decimal, foo \\(\\) .*" \ + "second continue in inferior 1" +gdb_test "continue " "hit Breakpoint $decimal\.$decimal, stop_breakpt \\(\\) .*" \ + "third continue in inferior 1" + +# Now allow inferior 1 to exit, the inferior specific breakpoint should be +# deleted. +gdb_test "continue" \ + [multi_line \ + "\\\[Inferior 1 \[^\r\n\]+ exited normally\\\]" \ + "Inferior-specific breakpoint $decimal deleted - inferior 1 has exited\\."] + +set saw_header false +set location_count 0 +set saw_inf_cond false +gdb_test_multiple "info breakpoints" "info breakpoint after inferior 1 exited" { + -re "^info breakpoints\r\n" { + exp_continue + } + + -re "^Num\\s+\[^\r\n\]+\r\n" { + exp_continue + } + + -re "^$decimal\\s+breakpoint\\s+keep\\s+y\\s+\\s*\r\n" { + set saw_header true + exp_continue + } + + -re "^\\s+stop only in inferior 1\r\n" { + # This should not happen, this breakpoint should have been deleted. + set saw_inf_cond true + exp_continue + } + + -re "^\\s+breakpoint already hit 2 times\r\n" { + exp_continue + } + + -re "^$decimal\\.\[12\]\\s+y\\s+ $hex in stop_breakpt at \[^\r\n\]+ inf \[12\]\r\n" { + incr location_count + exp_continue + } + + -re "^$gdb_prompt $" { + with_test_prefix $gdb_test_name { + gdb_assert { $saw_header } + gdb_assert { $location_count == 2 } + gdb_assert { !$saw_inf_cond } + } + } +} diff --git a/gdb/testsuite/gdb.python/py-breakpoint.exp b/gdb/testsuite/gdb.python/py-breakpoint.exp index 9535040e3a2..30e2ab1e4d8 100644 --- a/gdb/testsuite/gdb.python/py-breakpoint.exp +++ b/gdb/testsuite/gdb.python/py-breakpoint.exp @@ -111,6 +111,8 @@ proc_with_prefix test_bkpt_basic { } { "Get Breakpoint List" 0 gdb_test "python print (blist\[1\].thread)" \ "None" "Check breakpoint thread" + gdb_test "python print (blist\[1\].inferior)" \ + "None" "Check breakpoint inferior" gdb_test "python print (blist\[1\].type == gdb.BP_BREAKPOINT)" \ "True" "Check breakpoint type" gdb_test "python print (blist\[0\].number)" \ @@ -213,6 +215,46 @@ proc_with_prefix test_bkpt_cond_and_cmds { } { "check number of lines in commands" } +# Test breakpoint thread and inferior attributes. +proc_with_prefix test_bkpt_thread_and_inferior { } { + global srcfile testfile hex decimal + + # Start with a fresh gdb. + clean_restart ${testfile} + + if {![runto_main]} { + return 0 + } + + with_test_prefix "thread" { + delete_breakpoints + gdb_test "break multiply thread 1" + gdb_test "python bp = gdb.breakpoints ()\[0\]" + gdb_test "python print(bp.thread)" "1" + gdb_test "python print(bp.inferior)" "None" + gdb_test "python bp.inferior = 1" \ + "RuntimeError: Cannot have both thread and inferior conditions on a breakpoint.*" + gdb_test_no_output "python bp.thread = None" + gdb_test_no_output "python bp.inferior = 1" \ + "set the inferior now the thread has been cleared" + gdb_test "info breakpoints" "stop only in inferior 1\r\n.*" + } + + with_test_prefix "inferior" { + delete_breakpoints + gdb_test "break multiply inferior 1" + gdb_test "python bp = gdb.breakpoints ()\[0\]" + gdb_test "python print(bp.thread)" "None" + gdb_test "python print(bp.inferior)" "1" + gdb_test "python bp.thread = 1" \ + "RuntimeError: Cannot have both thread and inferior conditions on a breakpoint.*" + gdb_test_no_output "python bp.inferior = None" + gdb_test_no_output "python bp.thread = 1" \ + "set the thread now the inferior has been cleared" + gdb_test "info breakpoints" "stop only in thread 1\r\n.*" + } +} + proc_with_prefix test_bkpt_invisible { } { global srcfile testfile hex decimal @@ -849,6 +891,7 @@ proc_with_prefix test_bkpt_auto_disable { } { test_bkpt_basic test_bkpt_deletion test_bkpt_cond_and_cmds +test_bkpt_thread_and_inferior test_bkpt_invisible test_hardware_breakpoints test_catchpoints diff --git a/gdb/testsuite/lib/completion-support.exp b/gdb/testsuite/lib/completion-support.exp index bf9c5ad352c..5f68d198adc 100644 --- a/gdb/testsuite/lib/completion-support.exp +++ b/gdb/testsuite/lib/completion-support.exp @@ -27,7 +27,7 @@ namespace eval completion { # List of all quote chars, including no-quote at all. variable maybe_quoted_list {"" "'" "\""} - variable keyword_list {"-force-condition" "if" "task" "thread"} + variable keyword_list {"-force-condition" "if" "inferior" "task" "thread"} variable explicit_opts_list \ {"-function" "-label" "-line" "-qualified" "-source"} From patchwork Fri Jan 20 09:46:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 63442 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4BF6B38543AE for ; Fri, 20 Jan 2023 09:47:28 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4BF6B38543AE DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1674208048; bh=BIxgI7MCPbrp+tljCoAoYqc/1auXAlovLqIgAMGcbXo=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=vfAD9x6NBNkJnh1mGHdfMWnXxq+ZEWDY0ELyle8SFsUFfVh7yWf9jctragW2ZfMCv sgNdg+qoYE+/1zASLZC43cX09rpPZI2KMEfL0JY9jYYdn86Wjjez/mZwADuH+aQe90 TEqfwD6yrCesqn/+WSlYYgnzR8jJa35g3ZW3bPoo= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id E21033858CDA for ; Fri, 20 Jan 2023 09:46:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E21033858CDA Received: from mail-qv1-f71.google.com (mail-qv1-f71.google.com [209.85.219.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-650-KvrZwa6vPumXqHtgzI3k-A-1; Fri, 20 Jan 2023 04:46:48 -0500 X-MC-Unique: KvrZwa6vPumXqHtgzI3k-A-1 Received: by mail-qv1-f71.google.com with SMTP id x6-20020a0cc506000000b005349c8b39d6so2260885qvi.2 for ; Fri, 20 Jan 2023 01:46:48 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BIxgI7MCPbrp+tljCoAoYqc/1auXAlovLqIgAMGcbXo=; b=1f6V9S3OXqT4P+Gm9eaGrHj43RGwsrie7fojHMxmkRLDGHl+J9P2sF4ndsiyT1lwyw hzcG3Mnbk0OI/qA0XBXFjvZqQQKGiDzRGbBryysfoMFS8xPga+UmZ5Nou9QzGCTEwV7K Pn+gze8N3MGwE9sXHN0K2EI0bNNGzF1MJeSX2Apiraowvp7goRapLdmXLT8wvv7Fn737 GNSJJmPxwrUwqhwOAx75fAZze/bw3KLNKxdaP8RWzZfWNyENgpYPG5DRELtNqtMm7Ego GTO43y+HeMSHURVhPtUYL2gwt3vtT5KmLu4D7vRkEEG337xjYmMbgNpU2zL9NPv7OpQU II/A== X-Gm-Message-State: AFqh2krd64uqzZh1vSpRR6dihai2W6XQRK+CvK12lz7Ng8U75mgbGGA/ 2JR8TpQxt3r/FpbAPD1jyVKO6rKNVSI2Z6nJcTRL9OVohKHJRQoDMUHSq6hW0gvm+swxcHaa6Li JShpaEZd16G7YzXGpAHYZ7gMjg95YBX1cdcfbSV8GCax6FRRcKlqdXH5Ltft1mwf3sGES/sOpAQ == X-Received: by 2002:a0c:e114:0:b0:534:d4ea:a49b with SMTP id w20-20020a0ce114000000b00534d4eaa49bmr20222816qvk.48.1674208007906; Fri, 20 Jan 2023 01:46:47 -0800 (PST) X-Google-Smtp-Source: AMrXdXt0Y9ragW4JMGapkfyahl4zZx8WzFLKibkSbOLPisHKkhg5zQl4e0R+GrObBPJZAU7132whXQ== X-Received: by 2002:a0c:e114:0:b0:534:d4ea:a49b with SMTP id w20-20020a0ce114000000b00534d4eaa49bmr20222793qvk.48.1674208007480; Fri, 20 Jan 2023 01:46:47 -0800 (PST) Received: from localhost (95.72.115.87.dyn.plus.net. [87.115.72.95]) by smtp.gmail.com with ESMTPSA id v16-20020ac87490000000b003b691005020sm1879497qtq.96.2023.01.20.01.46.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Jan 2023 01:46:47 -0800 (PST) To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv2 6/6] gdb: convert the 'start' breakpoint to use inferior keyword Date: Fri, 20 Jan 2023 09:46:29 +0000 Message-Id: <0823d00de1408044915aa3bbcac4de0361d4ac30.1674207665.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) 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-Patchwork-Original-From: Andrew Burgess via Gdb-patches From: Andrew Burgess Reply-To: Andrew Burgess Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" Now that we have support for inferior specific breakpoints, the breakpoint created for the 'start' command can make use of this keyword. In most cases the observed functionality should be unchanged from a user's point of view, though the code in GDB is a little cleaner now, we no longer need to change the expression used based on the language. I do wonder if the current mechanism could run into problems if we had different inferiors of different languages. For example, if we had an Ada inferior and a C inferior and followed a process a little like this: 1. Start C inferior, the inferior stops before main for some reason, 2. Start the Ada inferior, this runs to main, 3. I think when we hit main, the condition for both breakpoints will be evaluated, this will include evaluating the expression for the C 'start' breakpoint, which uses '==' and is, I guess, not valid for Ada. I haven't tried to create a testcase for this situation, but it's a possibly interesting edge case. One place where the observed behaviour is different, is that inferior breakpoints, like thread breakpoints, will be auto-deleted when the contained inferior exits. As a result, if an inferior exits before hitting the start breakpoint, then the 'start' breakpoint will be auto-deleted. I have got a test that covers this situation. --- gdb/infcmd.c | 10 +--- .../gdb.base/start-inferior-specific-1.c | 32 +++++++++++ .../gdb.base/start-inferior-specific-2.c | 22 ++++++++ .../gdb.base/start-inferior-specific.exp | 55 +++++++++++++++++++ 4 files changed, 112 insertions(+), 7 deletions(-) create mode 100644 gdb/testsuite/gdb.base/start-inferior-specific-1.c create mode 100644 gdb/testsuite/gdb.base/start-inferior-specific-2.c create mode 100644 gdb/testsuite/gdb.base/start-inferior-specific.exp diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 7d5ec77ff57..7dfef4b5a23 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -429,13 +429,9 @@ run_command_1 (const char *args, int from_tty, enum run_how run_how) have proper inferior-specific breakpoint support, in the breakpoint machinery. We could then avoid inserting a breakpoint in the program spaces unrelated to this inferior. */ - const char *op - = ((current_language->la_language == language_ada - || current_language->la_language == language_pascal - || current_language->la_language == language_m2) ? "=" : "=="); - std::string arg = string_printf - ("-qualified %s if $_inferior %s %d", main_name (), op, - current_inferior ()->num); + std::string arg = string_printf ("-qualified %s inferior %d", + main_name (), + current_inferior ()->num); tbreak_command (arg.c_str (), 0); } diff --git a/gdb/testsuite/gdb.base/start-inferior-specific-1.c b/gdb/testsuite/gdb.base/start-inferior-specific-1.c new file mode 100644 index 00000000000..1717a82b75d --- /dev/null +++ b/gdb/testsuite/gdb.base/start-inferior-specific-1.c @@ -0,0 +1,32 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2022 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 . */ + +#include +#include + +__attribute__((constructor)) +static void +ctor (void) +{ + exit (1); +} + +int +main () +{ + return 0; +} diff --git a/gdb/testsuite/gdb.base/start-inferior-specific-2.c b/gdb/testsuite/gdb.base/start-inferior-specific-2.c new file mode 100644 index 00000000000..b69e218962a --- /dev/null +++ b/gdb/testsuite/gdb.base/start-inferior-specific-2.c @@ -0,0 +1,22 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2022 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 . */ + +int +main () +{ + return 0; +} diff --git a/gdb/testsuite/gdb.base/start-inferior-specific.exp b/gdb/testsuite/gdb.base/start-inferior-specific.exp new file mode 100644 index 00000000000..7271f6d49d3 --- /dev/null +++ b/gdb/testsuite/gdb.base/start-inferior-specific.exp @@ -0,0 +1,55 @@ +# Copyright 2022 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 . + +# Check that a breakpoint created for the 'start' command, will be +# silently deleted if the inferior being started exits before reaching +# main. + +standard_testfile -1.c -2.c + +if {[use_gdb_stub]} { + return +} + +set srcfile1 ${srcfile} + +set binfile1 ${binfile}-1 +set binfile2 ${binfile}-2 + +if {[build_executable ${testfile}.exp ${binfile1} "${srcfile1}"] != 0} { + return -1 +} + +if {[build_executable ${testfile}.exp ${binfile2} "${srcfile2}"] != 0} { + return -1 +} + +clean_restart ${binfile1} + +# Start the first inferior, this will exit before hitting the 'start' +# breakpoint in main. +gdb_test "start" \ + [multi_line \ + "Temporary breakpoint $decimal at \[^\r\n\]+" \ + "Starting program: \[^\r\n\]+" \ + "$inferior_exited_re with code 01\\\]"] + +# Now load a different binary and run it. This inferior should run +# all the way to completion without hitting a breakpoint in main. +gdb_load ${binfile2} +gdb_test "run" \ + [multi_line \ + "Starting program: \[^\r\n\]+" \ + "$inferior_exited_re normally\\\]"]