From patchwork Mon Dec 9 11:17:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 102662 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 010E6385841E for ; Mon, 9 Dec 2024 11:21:38 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 010E6385841E Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Y6e4h1vu 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 ESMTP id E76B0385841E for ; Mon, 9 Dec 2024 11:18:13 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E76B0385841E Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org E76B0385841E Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1733743094; cv=none; b=D1W+KXFMRE/qXUQvh7lAx8ugt54nxzAS7sHD+ap/z9TBMbBo3kqHbpTVYZTtFbObGMLSmcj4Wi4t99I1NCzJv9PtcFSM6riHqmukLyzVHj1+/B5I8zhq+5gPEkhtQ1mqwKdDa2jru4Lix1RB1v/n6OU+MMPo0XvZl56Qf5G09eM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1733743094; c=relaxed/simple; bh=Obn+uFdcTClzefDjzkce1Khzl1/h64Yj0i0Fke5uSl8=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=fkLSxURUsyhXdHnCCX0lBfSX1zJEo6rPrg8ksDIPt75XPlzhnqD+AvdTswZ4tOaH0u6kHw/SduVWAHhh6e9PyL/RHiM0WKmghlnsZM2WkX+g8vt5hrtMoxOZ0KhPuq2EqfhCPWNjsqLaOZaCsckQCtkyH3rIUu3/KHoqgBRQX+Q= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E76B0385841E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1733743093; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mgHf0ggKiSo/Tz0z9pCSon3nHQ4wiqUIvi+OLg4+sxQ=; b=Y6e4h1vuOI490ORLCsDN5/IbHg3Ca30t+0Xh+K6t1CGoy6puxefKCvoqqRXfB8vaIHdtMU sKss3ihcFzu+3LMMpBP3qAgZBPyIvlQHD68KIvHmsGvb+d5drdHfN5fSwK0XrTpOSpDif2 kEXWZEM7TmCVmw7+WMsSQVxhUfLjeu0= Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-596-JEE-fU0uNjKzzMFIttD5SA-1; Mon, 09 Dec 2024 06:18:12 -0500 X-MC-Unique: JEE-fU0uNjKzzMFIttD5SA-1 X-Mimecast-MFC-AGG-ID: JEE-fU0uNjKzzMFIttD5SA Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-386333ea577so722871f8f.1 for ; Mon, 09 Dec 2024 03:18:12 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733743090; x=1734347890; 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=mgHf0ggKiSo/Tz0z9pCSon3nHQ4wiqUIvi+OLg4+sxQ=; b=poYxRbmAwov+hfNwIzyO1mMQufzdqP0bsFmHSqA5RHwb74EUZQAktpCfzAABKUs/i1 oTY+Cu0Vj0b3AEZVqkclHirHg21VLBMnZdxyNufHmozamcvRODLlacSjqLOkSfA7RUJo RGxQokKPJuyxjfSfMvhO+CO8wsBI3gpd8KgvEljVKTULIeeOmd9lwrfCYJr90at5t/qo sFcxC+ROZ5XBsZaVdc4bZUn4qMd940fuJGEkE/Jp/h0OMy+tI4qRG3M/0AbwJfV3AuTN 2LW1MoHEHflKmrpxg04zORTxFruRBeoBJxg5W3zr0SxnwEBzdInxbUKJIrIH9HsxvwhN ptZA== X-Gm-Message-State: AOJu0YyMxwyQi/bjF4sttcVbALOKC/wpNjhwTnjLy+Ueoaw4hAcgG/9/ j84mvbr73NiBn8NH2pZGI0GG7LGzDDB/WvxjLgxNM1t0+r4QhdGRCM71+Nuzu38sGbvbgRrI3FF Rq94Wd6ZkPhrFpgy1B7SAp333I1gvtcwNfW6EqW6XJp129ZsMV2HAkiPRrErQkNEtU1rXP5vDxu xIvmx1H2Pa651vCsQxWXukeB3cqrDYu3TW6VTQhjkt7pw= X-Gm-Gg: ASbGncuNpDL4TWENgMr3IfXUW1I+W5EEU7ghHTBpOCnxr1tdCFeOsSc7QZibtCT/bvg 0bFBgwDFpfHvU61c+WpONBcHl+LB2255tgBgGwhYqNlMHn9aaqjJgO6O+/sfpCC04UGHWP9ecRr LVwzSmhek1Fg2aGra8RWe3LIhH3ON2YYc6g6aXaL6XonMDhiMx6ea//INONeiKTioiQARN1Aczo kNlmNZu1LlYAB46SeyI5dZfAL354gtbwui6WzViMlDXfOZ3kjniRWowelMVoPxF8ZutHZ4Kw6Du QA== X-Received: by 2002:a05:6000:1565:b0:385:df73:2f3a with SMTP id ffacd0b85a97d-3862b3516aemr7798233f8f.14.1733743089951; Mon, 09 Dec 2024 03:18:09 -0800 (PST) X-Google-Smtp-Source: AGHT+IGNM0P0DI034EZZfqfHvD8LgkLQvRgA+mqGdPKpw4nsOjuTXBL9NxpayASSoLaI8CCiX/3kNw== X-Received: by 2002:a05:6000:1565:b0:385:df73:2f3a with SMTP id ffacd0b85a97d-3862b3516aemr7798195f8f.14.1733743089197; Mon, 09 Dec 2024 03:18:09 -0800 (PST) Received: from localhost (197.209.200.146.dyn.plus.net. [146.200.209.197]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-38637072adasm7045015f8f.81.2024.12.09.03.18.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Dec 2024 03:18:08 -0800 (PST) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess , Tom Tromey , Hannes Domani Subject: [PATCHv5 1/7] gdb/testsuite: avoid incorrect symbols in gdb.base/condbreak-multi-context.cc Date: Mon, 9 Dec 2024 11:17:58 +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-MFC-PROC-ID: W4feWjpLUYQSkti4G4v2KQJf4AlBeiuH57d9DXSBXeM_1733743091 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-12.0 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, WEIRD_PORT 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.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org In a later commit I tweak how disabled_by_cond is handled in update_breakpoint_locations for code_breakpoint objects. I believe this fixes a bug in GDB, but when I did this I ran into a regression in the test script gdb.base/condbreak-multi-context.cc which I think is actually an issue with this test. The test relies on creating a multi-location breakpoint with a condition and having GDB disable some of the locations as the condition is only valid in some of the locations. Here's an example of the test creating one such breakpoint: Reading symbols from /tmp/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context... (gdb) break func if a == 10 warning: failed to validate condition at location 1, disabling: No symbol "a" in current context. warning: failed to validate condition at location 3, disabling: No symbol "a" in current context. Breakpoint 1 at 0x401142: func. (3 locations) (gdb) info breakpoints Num Type Disp Enb Address What 1 breakpoint keep y stop only if a == 10 1.1 N* 0x0000000000401142 in Base::func() at /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23 1.2 y 0x000000000040114e in A::func() at /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31 1.3 N* 0x000000000040115a in C::func() at /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39 (*): Breakpoint condition is invalid at this location. (gdb) Notice that only location 1.2 is actually enabled, 1.1 and 1.3 are disabled due to the condition 'a == 10' not being valid. However, notice that this b/p is created before GDB has started the inferior. What I noticed is that if I first start the inferior then I get a different behaviour: Reading symbols from /tmp/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context... (gdb) start Temporary breakpoint 1 at 0x40110e: file /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/condbreak-multi-context.cc, line 49. Starting program: /tmp/build/gdb/testsuite/outputs/gdb.base/condbreak-multi-context/condbreak-multi-context Temporary breakpoint 1, main () at /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:49 49 aobj.func (); (gdb) break func if a == 10 Breakpoint 2 at 0x401142: func. (3 locations) (gdb) info breakpoints Num Type Disp Enb Address What 2 breakpoint keep y stop only if a == 10 2.1 y 0x0000000000401142 in Base::func() at /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:23 2.2 y 0x000000000040114e in A::func() at /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:31 2.3 y 0x000000000040115a in C::func() at /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/condbreak-multi-context.cc:39 (gdb) Notice that now all three locations are valid. What's actually happening is that, on my machine libm.so contains a global symbol 'a' which for 2.1 and 2.3 is being used to satisfy the condition. I don't believe this is actually the intention of the test, this is just an unfortunate consequence of name collision. The test actually relies on the local variables 'a' and 'c', and my libm.so contains both a global version of both. So I propose that we just update the test, I've gone for the super inventive 'aaa' and 'ccc'. With this change, after starting the inferior I now see the expected behaviour where only one of the three locations is enabled. However, while I'm fixing this I figure that it would be nice if the test checked both cases, creating the breakpoints before starting the inferior, and after starting the inferior. So I've updated the test to check both cases. This has meant converting the mostly linear test script into a set of parameterised functions when I then call with a flag to indicate if the inferior should be started before of after creating the breakpoints. Approved-By: Tom Tromey Tested-By: Hannes Domani --- .../gdb.base/condbreak-multi-context.cc | 6 +- .../gdb.base/condbreak-multi-context.exp | 231 ++++++++++++------ 2 files changed, 165 insertions(+), 72 deletions(-) diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.cc b/gdb/testsuite/gdb.base/condbreak-multi-context.cc index b5628f01bd0..a674fd24a66 100644 --- a/gdb/testsuite/gdb.base/condbreak-multi-context.cc +++ b/gdb/testsuite/gdb.base/condbreak-multi-context.cc @@ -18,7 +18,7 @@ class Base { public: - static const int b = 20; + static const int bbb = 20; void func () {} }; @@ -26,7 +26,7 @@ public: class A : public Base { public: - static const int a = 10; + static const int aaa = 10; void func () {} }; @@ -34,7 +34,7 @@ public: class C : public Base { public: - static const int c = 30; + static const int ccc = 30; void func () {} }; diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp index 3af37081e44..3d609a2272c 100644 --- a/gdb/testsuite/gdb.base/condbreak-multi-context.exp +++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp @@ -18,7 +18,7 @@ standard_testfile .cc -if {[prepare_for_testing "failed to prepare" ${binfile} ${srcfile}]} { +if {[build_executable "failed to prepare" ${binfile} ${srcfile}]} { return } @@ -37,17 +37,32 @@ set loc_index(A) 0 set loc_index(Base) 0 set loc_index(C) 0 -# Find breakpoint location contexts. +# Find breakpoint location contexts. This is called before any of the +# tests are run and captures the order in which GDB will create the +# breakpoint locations. +# +# This whole test script does rely on GDB always creating the b/p +# locations in the same order, but that's true right now, and doesn't +# seem likely to change in the near future. + +proc find_location_contexts { } { + global loc_name loc_index fill + global decimal hex gdb_prompt binfile + + clean_restart ${binfile} + + if {![runto_main]} { + return + } -proc find_location_contexts {} { - global loc_name loc_index bpnum1 fill - global decimal hex gdb_prompt + gdb_breakpoint func + set bpnum [get_integer_valueof "\$bpnum" "*UNKNOWN*"] - gdb_test_multiple "info breakpoint $bpnum1" "find_location_indices" { - -re "stop only if ${fill}\r\n" { + gdb_test_multiple "info breakpoint $bpnum" "find_location_indices" { + -re "\r\n$bpnum\\s+breakpoint\\s+keep\\s+y\\s+\\s*\r\n" { exp_continue } - -re "^${bpnum1}\.($decimal) ${fill} ${hex} in (A|Base|C)::func${fill}\r\n" { + -re "^${bpnum}\.($decimal) ${fill} ${hex} in (A|Base|C)::func${fill}\r\n" { set index $expect_out(1,string) set name $expect_out(2,string) set loc_name($index) $name @@ -72,7 +87,7 @@ proc find_location_contexts {} { # B::func, and 'n' at C::func, respectively. proc check_bp_locations {bpnum states cond {msg ""}} { - global loc_name fill + global loc_name fill loc_states # Map location names to location states. set loc_states(A) [lindex $states 0] @@ -103,67 +118,87 @@ proc check_bp_locations {bpnum states cond {msg ""}} { # Scenario 1: Define breakpoints conditionally, using the "break N if # cond" syntax. Run the program, check that we hit those locations # only. +# +# When START_BEFORE is true we create the breakpoints after running to +# main. When START_BEFORE is false we create the breakpoints after +# starting GDB, but before running to main. + +proc_with_prefix scenario_1 { start_before } { + global warning decimal fill bkptno_num_re binfile + + clean_restart ${binfile} + + if { $start_before } { + if {![runto_main temporary]} { + return + } + } -with_test_prefix "scenario 1" { # Define the conditional breakpoints. Two locations (Base::func # and C::func) should be disabled. We do not test location # indices strictly at this moment, because we don't know them, # yet. We have strict location index tests below. - gdb_test "break func if a == 10" \ + gdb_test "break func if aaa == 10" \ [multi_line \ "${warning} at location $decimal, disabling:" \ - " No symbol \"a\" in current context." \ + " No symbol \"aaa\" in current context." \ "${warning} at location $decimal, disabling:" \ - " No symbol \"a\" in current context." \ + " No symbol \"aaa\" in current context." \ "Breakpoint $decimal at $fill .3 locations."] \ - "define bp with condition a == 10" + "define bp with condition aaa == 10" set bpnum1 [get_integer_valueof "\$bpnum" 0 "get bpnum1"] - gdb_test "break func if c == 30" \ + gdb_test "break func if ccc == 30" \ [multi_line \ ".*${warning} at location $decimal, disabling:" \ - " No symbol \"c\" in current context." \ + " No symbol \"ccc\" in current context." \ ".*${warning} at location $decimal, disabling:" \ - " No symbol \"c\" in current context." \ + " No symbol \"ccc\" in current context." \ ".*Breakpoint $decimal at $fill .3 locations."] \ - "define bp with condition c == 30" + "define bp with condition ccc == 30" set bpnum2 [get_integer_valueof "\$bpnum" 0 "get bpnum2"] - find_location_contexts - - with_test_prefix "before run" { - check_bp_locations $bpnum1 {y N* N*} "a == 10" - check_bp_locations $bpnum2 {N* N* y} "c == 30" + with_test_prefix "after creating b/p" { + check_bp_locations $bpnum1 {y N* N*} "aaa == 10" + check_bp_locations $bpnum2 {N* N* y} "ccc == 30" } - # Do not use runto_main, it deletes all breakpoints. - gdb_run_cmd + if { !$start_before } { + if {![runto_main temporary no-delete-breakpoints]} { + return + } + } # Check our conditional breakpoints. - gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \ + gdb_test "continue" ".*Breakpoint $bkptno_num_re, A::func .*" \ "run until A::func" - gdb_test "print a" " = 10" + gdb_test "print aaa" " = 10" gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \ "run until C::func" - gdb_test "print c" " = 30" + gdb_test "print ccc" " = 30" # No more hits! gdb_continue_to_end with_test_prefix "after run" { - check_bp_locations $bpnum1 {y N* N*} "a == 10" - check_bp_locations $bpnum2 {N* N* y} "c == 30" + check_bp_locations $bpnum1 {y N* N*} "aaa == 10" + check_bp_locations $bpnum2 {N* N* y} "ccc == 30" } } -# Start GDB with two breakpoints and define the conditions separately. +# Assuming GDB is already started, create two breakpoints and define +# the conditions separately. +# +# BPNUM1_NAME and BPNUM2_NAME contain the name of two variables in the +# parent contents. The breakpoint numbers of the two created +# breakpoints are placed into these variables in the parent content. -proc setup_bps {} { - global srcfile binfile srcfile2 decimal - global bpnum1 bpnum2 bp_location warning loc_index +proc setup_bps { bpnum1_name bpnum2_name } { + global warning loc_index - clean_restart ${binfile} + upvar $bpnum1_name bpnum1 + upvar $bpnum2_name bpnum2 # Define the breakpoints. gdb_breakpoint "func" @@ -172,74 +207,105 @@ proc setup_bps {} { gdb_breakpoint "func" set bpnum2 [get_integer_valueof "\$bpnum" 0 "get bpnum2"] - # Defining a condition on 'a' disables 2 locations. + # Defining a condition on 'aaa' disables 2 locations. set locs [lsort -integer "$loc_index(Base) $loc_index(C)"] - gdb_test "cond $bpnum1 a == 10" \ + gdb_test "cond $bpnum1 aaa == 10" \ [multi_line \ "$warning at location ${bpnum1}.[lindex $locs 0], disabling:" \ - " No symbol \"a\" in current context." \ + " No symbol \"aaa\" in current context." \ "$warning at location ${bpnum1}.[lindex $locs 1], disabling:" \ - " No symbol \"a\" in current context."] + " No symbol \"aaa\" in current context."] # Defining a condition on 'c' disables 2 locations. set locs [lsort -integer "$loc_index(Base) $loc_index(A)"] - gdb_test "cond $bpnum2 c == 30" \ + gdb_test "cond $bpnum2 ccc == 30" \ [multi_line \ "$warning at location ${bpnum2}.[lindex $locs 0], disabling:" \ - " No symbol \"c\" in current context." \ + " No symbol \"ccc\" in current context." \ "$warning at location ${bpnum2}.[lindex $locs 1], disabling:" \ - " No symbol \"c\" in current context."] + " No symbol \"ccc\" in current context."] } # Scenario 2: Define breakpoints unconditionally, and then define # conditions using the "cond N " syntax. Expect that the # locations where is not evaluatable are disabled. Run the # program, check that we hit the enabled locations only. +# +# When START_BEFORE is true we create the breakpoints after running to +# main. When START_BEFORE is false we create the breakpoints after +# starting GDB, but before running to main. + +proc_with_prefix scenario_2 { start_before } { + global binfile bkptno_num_re + + clean_restart ${binfile} -with_test_prefix "scenario 2" { - setup_bps + if { $start_before } { + if {![runto_main temporary]} { + return + } + } + + setup_bps bpnum1 bpnum2 - with_test_prefix "before run" { - check_bp_locations $bpnum1 {y N* N*} "a == 10" - check_bp_locations $bpnum2 {N* N* y} "c == 30" + with_test_prefix "after creating b/p" { + check_bp_locations $bpnum1 {y N* N*} "aaa == 10" + check_bp_locations $bpnum2 {N* N* y} "ccc == 30" } - # Do not use runto_main, it deletes all breakpoints. - gdb_run_cmd + if { !$start_before } { + if {![runto_main temporary no-delete-breakpoints]} { + return + } + } # Check that we hit enabled locations only. - gdb_test "" ".*Breakpoint $bkptno_num_re, A::func .*" \ + gdb_test "continue" ".*Breakpoint $bkptno_num_re, A::func .*" \ "run until A::func" - gdb_test "print a" " = 10" + gdb_test "print aaa" " = 10" gdb_test "continue" "Continuing.*Breakpoint $bkptno_num_re, C::func .*" \ "run until C::func" - gdb_test "print c" " = 30" + gdb_test "print ccc" " = 30" # No more hits! gdb_continue_to_end with_test_prefix "after run" { - check_bp_locations $bpnum1 {y N* N*} "a == 10" - check_bp_locations $bpnum2 {N* N* y} "c == 30" + check_bp_locations $bpnum1 {y N* N*} "aaa == 10" + check_bp_locations $bpnum2 {N* N* y} "ccc == 30" } } # Scenario 3: Apply misc. checks on the already-defined breakpoints. +# +# When START_BEFORE is true we create the breakpoints after running to +# main. When START_BEFORE is false we create the breakpoints after +# starting GDB, but before running to main. + +proc_with_prefix scenario_3 { start_before } { + global binfile bkptno_num_re loc_index warning + + clean_restart ${binfile} -with_test_prefix "scenario 3" { - setup_bps + if { $start_before } { + if {![runto_main temporary]} { + return + } + } + + setup_bps bpnum1 bpnum2 set locs [lsort -integer "$loc_index(Base) $loc_index(A)"] - gdb_test "cond $bpnum1 c == 30" \ + gdb_test "cond $bpnum1 ccc == 30" \ [multi_line \ "${warning} at location ${bpnum1}.[lindex $locs 0], disabling:" \ - " No symbol \"c\" in current context." \ + " No symbol \"ccc\" in current context." \ "${warning} at location ${bpnum1}.[lindex $locs 1], disabling:" \ - " No symbol \"c\" in current context." \ + " No symbol \"ccc\" in current context." \ "Breakpoint ${bpnum1}'s condition is now valid at location $loc_index(C), enabling."] \ "change the condition of bp 1" - check_bp_locations $bpnum1 {N* N* y} "c == 30" "after changing the condition" + check_bp_locations $bpnum1 {N* N* y} "ccc == 30" "after changing the condition" gdb_test "cond $bpnum1" \ [multi_line \ @@ -250,7 +316,7 @@ with_test_prefix "scenario 3" { check_bp_locations $bpnum1 {y y y} "" "after resetting the condition" gdb_test_no_output "disable ${bpnum2}.$loc_index(A)" - check_bp_locations $bpnum2 {N* N* y} "c == 30" "after disabling loc for A" + check_bp_locations $bpnum2 {N* N* y} "ccc == 30" "after disabling loc for A" gdb_test "cond $bpnum2" ".*" "reset the condition of bp 2" check_bp_locations $bpnum2 {n y y} "" "loc for A should remain disabled" @@ -258,17 +324,17 @@ with_test_prefix "scenario 3" { gdb_test_no_output "disable ${bpnum2}.$loc_index(C)" check_bp_locations $bpnum2 {n y n} "" "after disabling loc for C" - gdb_test "cond $bpnum2 c == 30" \ + gdb_test "cond $bpnum2 ccc == 30" \ [multi_line \ "${warning} at location ${bpnum2}.$loc_index(Base), disabling:" \ - " No symbol \"c\" in current context."] \ + " No symbol \"ccc\" in current context."] \ "re-define a condition" - check_bp_locations $bpnum2 {N* N* n} "c == 30" "loc for C should remain disabled" + check_bp_locations $bpnum2 {N* N* n} "ccc == 30" "loc for C should remain disabled" gdb_test "enable ${bpnum2}.$loc_index(Base)" \ "Breakpoint ${bpnum2}'s condition is invalid at location $loc_index(Base), cannot enable." \ "reject enabling a location that is disabled-by-cond" - check_bp_locations $bpnum2 {N* N* n} "c == 30" "after enable attempt" + check_bp_locations $bpnum2 {N* N* n} "ccc == 30" "after enable attempt" gdb_test "cond $bpnum2 garbage" \ "No symbol \"garbage\" in current context." \ @@ -277,19 +343,34 @@ with_test_prefix "scenario 3" { gdb_test_no_output "delete $bpnum1" # Do not use runto_main, it deletes all breakpoints. - gdb_breakpoint "main" - gdb_run_cmd - gdb_test "" ".*reakpoint .*, main .*${srcfile}.*" "start" + if { !$start_before } { + if {![runto_main temporary no-delete-breakpoints]} { + return + } + } # The second BP's locations are all disabled. No more hits! gdb_continue_to_end } # Scenario 4: Test the '-force'/'-force-condition' flag. +# +# When START_BEFORE is true we create the breakpoints after running to +# main. When START_BEFORE is false we create the breakpoints after +# starting GDB, but before running to main, in fact we don't even +# bother with a run to main in this case. + +proc_with_prefix scenario_4 { start_before } { + global binfile bkptno_num_re loc_index warning -with_test_prefix "force" { clean_restart ${binfile} + if { $start_before } { + if {![runto_main temporary]} { + return + } + } + gdb_breakpoint "func" # Pick a condition that is invalid at every location. set bpnum1 [get_integer_valueof "\$bpnum" 0 "get bpnum1"] @@ -309,3 +390,15 @@ with_test_prefix "force" { set bpnum2 [get_integer_valueof "\$bpnum" 0 "get bpnum2"] check_bp_locations $bpnum2 {N* N* N*} "baz" "set using the break command" } + +# Some initial setup. Needed for most of the different scenarios +# below. +find_location_contexts + +# Now run all of the separate scenarios. +foreach_with_prefix start_before { true false } { + scenario_1 $start_before + scenario_2 $start_before + scenario_3 $start_before + scenario_4 $start_before +} From patchwork Mon Dec 9 11:17:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 102661 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 0ED5D3858416 for ; Mon, 9 Dec 2024 11:20:46 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0ED5D3858416 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=dTD+DUT2 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 ESMTP id ECE61385841F for ; Mon, 9 Dec 2024 11:18:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org ECE61385841F Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org ECE61385841F Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1733743095; cv=none; b=JCgNRWy7XuTLH8DeXbz37Kv/ot5XFB0HLlah9H1SYsYYI8ilU7Bzy9v+LGchcbvLgnc9KNtk40pVJVrJ/0jAJ9nzrCRAOOgN5WLaBkooh5g36sq2P9Oapf/3hNq4DjAuZr88u4Mf0MTveta5Z/6tPjStNizp9YMX/UfEmVeXlIM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1733743095; c=relaxed/simple; bh=8tL919slJniD0tN2/QrO8ChBCGxm/Eu4iWpShO5xdDs=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=mX6hxAaWEqAxpvHuglAGIiBX3bl4YPAGW2rLh6gxWjsXleP+BsM2mSd39USpwlDV9afD+DyfoaZh0iji+LW3Eo7UlSpaSamZyVfPjhfS335aRJRXG77IUTdnvTQD2MbRG4BEEI9B2+/5zz5t3GFJLlyC9dC85xgtIAwPhHhEdcY= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org ECE61385841F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1733743094; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=RpevVn+wcHw7SMhZvUWufVAjhkSRdpunUYenm/ecDN0=; b=dTD+DUT2pNZVq+0emC2Xi2Ml6MqsLY7o27rMPE3HY4fBXwpXoBSBXqBqRp+WXEZhiTLpIl a2lb1+nQz9BXnxsuHEh/5t5mrJkqa9IUxo3WdbRXTdie+TiVV7JasNE77NVqdP0nZdvT9U DLUN90KlFa9s7o5GOLgPdnlY7iLJ9Y4= Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-623-q0BZsjvNOPKhUTwL9M0XRw-1; Mon, 09 Dec 2024 06:18:13 -0500 X-MC-Unique: q0BZsjvNOPKhUTwL9M0XRw-1 X-Mimecast-MFC-AGG-ID: q0BZsjvNOPKhUTwL9M0XRw Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-434fff37885so60845e9.3 for ; Mon, 09 Dec 2024 03:18:13 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733743092; x=1734347892; 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=RpevVn+wcHw7SMhZvUWufVAjhkSRdpunUYenm/ecDN0=; b=kFkaJw4bmzuLUbWe9fQyUupMixSTRf7RylhBZIaa5dHgbEzEoGGbe2XHLsCt7mcb/K 1bGXu/+13N/UC5f875Il60CsClpxa3tFDNemL1dfkg7nOYvCrMIOyHgjK3Y3pckoUrqL 73LfVYYuCfea3tYZjpaPedJqm2vG2LhlXmqCUHP2jdT9FBgw8uQZtE5fYCvHxlH43KTg GUaJ0MYYRjte2thX9oGMot+g2wQbG5+MXHoufmGZ3jLClVURb2IRz6w7/Q9czc6/onz+ 8EgvQFZRuF3YA1b5AgHEOBYi456B0AYBEitQSC0e7D0gUy36wqKM2pJnVzw4IwqCMh3g 8ODQ== X-Gm-Message-State: AOJu0Ywo180eyFm89mG8idiJwNTJMTH7zJP4MaQU/QheuwP7HJBCHidF 7KXHjFsb5iXNQI+sGlv4tmp/2S4jUR0/4K8WV1txtqB6vfAYMIUBCJZcZ+u+Nsgl9ImI176tDAn o1cKy6buiV1KmJEwo5DUK8Temd4gp37ES9UQ+EIBbbOXhFtatsKglA+9H/W4FY6P6GoNTNXqx4M V4cdzC1+9oJpWvL8EAvsNkLg6YU1sX0yyezNACoq/pZ3Q= X-Gm-Gg: ASbGncuUjq7FJyKCgh/lL8gjzxDSodfaSN/Serq66J0qMiEWqxj8YbLpwx0rHCNSLxU IODKcUbhda6i/1sRCjfSmUqZPFDCnOWlvnePD+kUrZI0tPWda9bVG9fwOWYt0ejAktpJcmJhE4s zWb3enLkVba1OeytISJEMgS11dhyOEmszuqNntGymxXWlUD7Px7L63NBFhmt/91GuYv0r43B043 GfMfVy3l2nkYhNmTKkaqEjBvurXGPn55yiY1kRyCAmh+b+Jlu5yfOGXgBXmC/KhTKHWMZbF5zK4 Ng== X-Received: by 2002:a7b:cb8d:0:b0:434:f335:855 with SMTP id 5b1f17b1804b1-434f3350d44mr28789955e9.28.1733743091097; Mon, 09 Dec 2024 03:18:11 -0800 (PST) X-Google-Smtp-Source: AGHT+IFDDVz6dNjxlaNHXUELgIvnliJUK89OZqAF4SveXUxbM/TUsMBA9tZdiuBKDkhqdasumXy6kA== X-Received: by 2002:a7b:cb8d:0:b0:434:f335:855 with SMTP id 5b1f17b1804b1-434f3350d44mr28789555e9.28.1733743090324; Mon, 09 Dec 2024 03:18:10 -0800 (PST) Received: from localhost (197.209.200.146.dyn.plus.net. [146.200.209.197]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-434eba653a0sm79134735e9.22.2024.12.09.03.18.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Dec 2024 03:18:09 -0800 (PST) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess , Hannes Domani Subject: [PATCHv5 2/7] gdb: fixes for code_breakpoint::disabled_by_cond logic Date: Mon, 9 Dec 2024 11:17:59 +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-MFC-PROC-ID: cPHpDT9zzEDZze1K9h5ojhhXpl4sM7pmk9yQs3khVik_1733743092 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-12.0 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.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org I spotted that the code_breakpoint::disabled_by_cond flag doesn't work how I'd expect it too. The flag appears to be "sticky" in some situations; once a code_breakpoint::disabled_by_cond flag is marked true, then, in some cases the flag wont automatically become false again, even when you'd think it should. The problem is in update_breakpoint_locations. In this function, which is called as a worker of code_breakpoint::re_set, GDB computes a new set of locations for a breakpoint, the new locations are then installed into the breakpoint. However, before installing the new locations GDB attempts to copy the bp_location::enabled and bp_location::disabled_by_cond flag from the old locations into the new locations. The reason for copying the ::enabled flag makes sense. This flag is controlled by the user. When we create the new locations if GDB can see that a new location is equivalent to one of the old locations, and if the old location was disabled by the user, then the new location should also be disabled. However, I think the logic behind copying the ::disabled_by_cond flag is wrong. The disabled_by_cond flag is controlled by GDB and should toggle automatically. If the condition string can be parsed then the flag should be false (b/p enabled), if the condition string can't be parsed then the flag should be true (b/p disabled). As we always parse the condition string in update_breakpoint_locations before we try to copy the ::enabled flag value then the ::disabled_by_cond flag should already be correct, there's no need to copy over the ::disabled_by_cond value from the old location. As a concrete example, consider a b/p placed within the main executable, but with a condition that depends on a variable within a shared library. When the b/p is initially created the b/p will be disabled as the condition string will be invalid (the shared library variable isn't available yet). When the inferior starts the shared library is loaded and the condition variable becomes available to GDB. When the shared library is loaded breakpoint_re_set is called which (eventually) calls update_breakpoint_locations. A new location is computed for the breakpoint and the condition string is parsed. As the shared library variable is now know the expression parses correctly and ::disabled_by_cond is left false for the new location. But currently GDB spots that the new location is at the same address as the old location and copies disabled_by_cond over from the old location, which marks the b/p location as disabled. This is not what I would expect. The solution is simple, don't copy over disabled_by_cond. While writing a test I found another problem though. The disabled_by_cond flag doesn't get set true when it should! This is the exact opposite of the above. The problem here is in solib_add which is (despite the name) called whenever the shared library set changes, including when a shared library is unloaded. Imagine an executable that uses dlopen/dlclose to load a shared library. Given an example of a b/p in the main executable that has a condition that uses a variable from our shared library, a library which might be unloaded with dlclose. My expectation is that, when the library is unloaded, GDB will automatically mark the breakpoint as disabled_by_cond, however, this was not happening. The problem is that in solib_add we only call breakpoint_re_set when shared libraries are added, not when shared libraries are removed. The solution I think is to just call breakpoint_re_set in both cases, now the disabled_by_cond flag is updated as I'd expect. Unfortunately, making this change causes a regression when running: make check-gdb \ TESTS="gdb.trace/change-loc.exp" \ RUNTESTFLAGS="--target_board=native-gdbserver" This test unloads a shared library and expects breakpoints within the shared library to enter the PENDING state (because the bp_location's shlib_disabled flag will be set). However, the new call to breakpoint_re_set means that this is no longer the case. The breakpoint_re_set call means that update_breakpoint_locations is called, which then checks if all locations for a breakpoint are pending or not. In this test not all locations are pending, and so GDB recalculates the locations of each breakpoint, this means that pending locations are discarded. There is a but report PR gdb/32404 which mentions the problems with shlib_disabled pending breakpoints, and how they are prone to being randomly deleted if the user can cause GDB to trigger a call to breakpoint_re_set. This patch just adds another call to breakpoint_re_set, which triggers this bug in this one test case. For now I have marked this test as KFAIL. I do plan to try and address the pending (shlib_disabled) breakpoint problem in the future, but I'm not sure when that will be right now. There are, of course, tests to cover all these cases. During review I was pointed at bug PR gdb/32079 as something that this commit might fix, or help in fixing. And this commit is part of the fix for that bug, but is not the complete solution. However, the remaining parts of the fix for that bug are not really related to the content of this commit. The problem in PR gdb/32079 is that the inferior maps multiple copies of libc in different linker namespaces using dlmopen (actually libc is loaded as a consequence of loading some other library into a different namespace, but that's just a detail). The user then uses a 'next' command to move the inferior forward. GDB sets up internal breakpoints on the longjmp symbols, of which there are multiple copies (there is a copy in every loaded libc). However, the 'next' command is, in the problem case, stepping over a dlclose call which unloads one of the loaded libc libraries. In current HEAD GDB in solib_add we fail to call breakpoint_re_set() when the library is unloaded; breakpoint_re_set() would delete and then recreate the longjmp breakpoints. As breakpoint_re_set() is not called GDB thinks that the the longjmp breakpoint in the now unloaded libc still exists, and is still inserted. When the inferior stops after the 'next' GDB tries to delete and remove the longjmp breakpoint which fails as the libc in which the breakpoint was inserted is no longer mapped in. When the user tries to 'next' again GDB tries to re-insert the still existing longjmp breakpoint which again fails as the memory in which the b/p should be inserted is no longer part of the inferior memory space. This commit helps a little. Now when the libc library is unmapped GDB does call breakpoint_re_set(). This deletes the longjmp breakpoints including the one in the unmapped library, then, when we try to recreate the longjmp breakpoints (at the end of breakpoint_re_set) we don't create a b/p in the now unmapped copy of libc. However GDB does still think that the deleted breakpoint is inserted. The breakpoint location remains in GDB's data structures until the next time the inferior stops, at which point GDB tries to remove the breakpoint .... and fails. However, as the b/p is now deleted, when the user tries to 'next' GDB no longer tries to re-insert the b/p, and so one of the problems reported in PR gdb/32079 is resolved. I'll fix the remaining issues from PR gdb/32079 in a later commit in this series. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32079 Tested-By: Hannes Domani --- gdb/breakpoint.c | 5 +- gdb/solib.c | 2 +- .../gdb.base/bp-disabled-by-cond-lib.c | 24 ++ gdb/testsuite/gdb.base/bp-disabled-by-cond.c | 64 ++++++ .../gdb.base/bp-disabled-by-cond.exp | 206 ++++++++++++++++++ gdb/testsuite/gdb.base/bp-disabled-by-cond.py | 21 ++ gdb/testsuite/gdb.trace/change-loc.exp | 2 + 7 files changed, 319 insertions(+), 5 deletions(-) create mode 100644 gdb/testsuite/gdb.base/bp-disabled-by-cond-lib.c create mode 100644 gdb/testsuite/gdb.base/bp-disabled-by-cond.c create mode 100644 gdb/testsuite/gdb.base/bp-disabled-by-cond.exp create mode 100644 gdb/testsuite/gdb.base/bp-disabled-by-cond.py diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 8dafb0a0c75..bfff3bd8ee1 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -13017,8 +13017,7 @@ update_breakpoint_locations (code_breakpoint *b, for (const bp_location &e : existing_locations) { - if (e.function_name == nullptr - || (e.enabled && !e.disabled_by_cond)) + if (e.function_name == nullptr || e.enabled) continue; if (have_ambiguous_names) @@ -13035,7 +13034,6 @@ update_breakpoint_locations (code_breakpoint *b, if (breakpoint_locations_match (&e, &l, true)) { l.enabled = e.enabled; - l.disabled_by_cond = e.disabled_by_cond; break; } } @@ -13048,7 +13046,6 @@ update_breakpoint_locations (code_breakpoint *b, l.function_name.get ()) == 0) { l.enabled = e.enabled; - l.disabled_by_cond = e.disabled_by_cond; break; } } diff --git a/gdb/solib.c b/gdb/solib.c index fdefdf0b142..0c63d31f645 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -973,7 +973,7 @@ solib_add (const char *pattern, int from_tty, int readsyms) } } - if (loaded_any_symbols) + if (loaded_any_symbols || !current_program_space->deleted_solibs.empty ()) breakpoint_re_set (); if (from_tty && pattern && !any_matches) diff --git a/gdb/testsuite/gdb.base/bp-disabled-by-cond-lib.c b/gdb/testsuite/gdb.base/bp-disabled-by-cond-lib.c new file mode 100644 index 00000000000..ab0cb9dcb16 --- /dev/null +++ b/gdb/testsuite/gdb.base/bp-disabled-by-cond-lib.c @@ -0,0 +1,24 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2024 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 lib_global = 0; + +void +lib_func (void) +{ + /* Nothing. */ +} diff --git a/gdb/testsuite/gdb.base/bp-disabled-by-cond.c b/gdb/testsuite/gdb.base/bp-disabled-by-cond.c new file mode 100644 index 00000000000..cf61c2821df --- /dev/null +++ b/gdb/testsuite/gdb.base/bp-disabled-by-cond.c @@ -0,0 +1,64 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2024 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 + +#ifdef __WIN32__ +#include +#define dlopen(name, mode) LoadLibrary (TEXT (name)) +#ifdef _WIN32_WCE +# define dlsym(handle, func) GetProcAddress (handle, TEXT (func)) +#else +# define dlsym(handle, func) GetProcAddress (handle, func) +#endif +#define dlclose(handle) FreeLibrary (handle) +#else +#include +#endif + +void +breakpt () +{ + /* Nothing. */ +} + +int +main (void) +{ + int res; + void *handle; + void (*func) (void); + + handle = dlopen (SHLIB_NAME, RTLD_LAZY); + assert (handle != NULL); + + func = (void (*)(void)) dlsym (handle, "lib_func"); + assert (func != NULL); + + breakpt (); /* Conditional BP location. */ + breakpt (); /* Other BP location. */ + + func (); + + res = dlclose (handle); + assert (res == 0); + + breakpt (); /* BP before exit. */ + + return 0; +} diff --git a/gdb/testsuite/gdb.base/bp-disabled-by-cond.exp b/gdb/testsuite/gdb.base/bp-disabled-by-cond.exp new file mode 100644 index 00000000000..6104787ed3a --- /dev/null +++ b/gdb/testsuite/gdb.base/bp-disabled-by-cond.exp @@ -0,0 +1,206 @@ +# Copyright 2024 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 . + +# Breakpoint locations can be marked as "disabled due to their +# condition". This test sets up a breakpoint which depends on reading +# a variable in a shared library. We then check that the b/p is +# correctly disabled before the shared library is loaded, becomes +# enabled once the shared library is loaded. And becomes disabled +# again when the shared libraries are unloaded. + +standard_testfile .c -lib.c + +set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] + +# Build the library and copy it to the target. +set libname ${testfile}-lib +set libfile [standard_output_file $libname] +if { [build_executable "build shlib" $libfile $srcfile2 {debug shlib}] == -1} { + return +} +set libfile_on_target [gdb_download_shlib $libfile] + +# Build the executable. +set opts [list debug shlib_load additional_flags=-DSHLIB_NAME=\"${libname}\"] +if { [build_executable "build exec" $binfile $srcfile $opts] == -1} { + return +} + +set other_bp_line [gdb_get_line_number "Other BP location" $srcfile] +set cond_bp_line [gdb_get_line_number "Conditional BP location" $srcfile] +set exit_bp_line [gdb_get_line_number "BP before exit" $srcfile] + +# Setup a conditional b/p, the condition of which depends on reading a +# variable from a shared library. The b/p will initially be created +# disabled (due to the condition). +# +# Continue the inferior, when the shared library is loaded GDB should +# make the b/p enabled. +# +# Restart the inferior, which should unload the shared library, GDB +# should mark the b/p as disabled due to its condition again. +proc run_test { hit_cond } { + clean_restart $::binfile + + if {![runto_main]} { + return + } + + # Setup breakpoints. + gdb_breakpoint $::srcfile:$::other_bp_line + set other_bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \ + "get number of other b/p"] + + gdb_breakpoint $::srcfile:$::exit_bp_line + set exit_bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \ + "get number of exit b/p"] + + gdb_breakpoint $::srcfile:$::cond_bp_line + set cond_bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \ + "get number of conditional b/p"] + + if { $hit_cond } { + set lib_global_val 0 + } else { + set lib_global_val 1 + } + + # Set the condition. Use 'force' as we're referencing a variable in + # the shared library, which hasn't been loaded yet. The breakpoint + # will immediately be marked as disabled_by_cond. + gdb_test "condition -force $cond_bp_num lib_global == $lib_global_val" \ + [multi_line \ + "warning: failed to validate condition at location $cond_bp_num\\.1, disabling:" \ + " No symbol \"lib_global\" in current context\\."] \ + "set b/p condition, it will be disabled" + + # Source Python script if supported. + if { [allow_python_tests] } { + gdb_test_no_output "source $::pyfile" "import python scripts" + gdb_test "python print(bp_modified_list)" "\\\[\\\]" \ + "check b/p modified observer has not yet triggered" + } + + # Check the b/p is indeed marked as disabled (based on its condition). + gdb_test "info breakpoint $cond_bp_num" \ + [multi_line \ + "\r\n$cond_bp_num\\.1\\s+N\\*\\s+$::hex in main at \[^\r\n\]+" \ + "\\(\\*\\): Breakpoint condition is invalid at this location\\."] \ + "conditional breakpoint is disabled based on condition" + + if { $hit_cond } { + # Continue the inferior. The shared library is loaded and the + # breakpoint condition should become valid. We should then stop at + # the conditional breakpoint. + gdb_test "continue" \ + [multi_line \ + "Breakpoint $cond_bp_num, main \\(\\) at \[^\r\n\]+:$::cond_bp_line" \ + "$::cond_bp_line\\s+breakpt \\(\\);\\s+/\\* Conditional BP location\\. \\*/"] \ + "continue until conditional b/p is hit" + } else { + # Continue the inferior. The shared library is loaded and the + # breakpoint condition should become valid. As the condition + # is going to be false GDB will stop at the other line. + gdb_test "continue" \ + [multi_line \ + "Breakpoint $other_bp_num, main \\(\\) at \[^\r\n\]+:$::other_bp_line" \ + "$::other_bp_line\\s+breakpt \\(\\);\\s+/\\* Other BP location\\. \\*/"] \ + "continue until conditional b/p is hit" + } + + if { [allow_python_tests] } { + # We're going to look at the list of b/p that have been + # modified since we loaded the Python script. The first b/p + # modified will be the conditional b/p, this occurs when the + # b/p condition became valid. + # + # The second b/p will be whichever b/p we hit (the hit count + # increased). So figure out which b/p we are going to hit. + if { $hit_cond } { + set second_bp_num $cond_bp_num + } else { + set second_bp_num $other_bp_num + } + + # Now check the list of modified b/p. + gdb_test "python print(bp_modified_list)" \ + "\\\[$cond_bp_num, $second_bp_num\\\]" \ + "check b/p modified observer was triggered" + } + + if {[gdb_protocol_is_remote]} { + set evals_re "(?: \\(\[^) \]+ evals\\))?" + } else { + set evals_re "" + } + + # Check the b/p is no longer marked as disabled. The output is + # basically the same here whether the b/p was hit or not. It's + # just the hit counter line that we need to append or not. + set re_list \ + [list \ + "$cond_bp_num\\s+breakpoint\\s+keep\\s+y\\s+$::hex in main at \[^\r\n\]+:$::cond_bp_line" \ + "\\s+stop only if lib_global == $lib_global_val$evals_re"] + if { $hit_cond } { + lappend re_list "\\s+breakpoint already hit 1 time" + } + set re [multi_line {*}$re_list] + gdb_test "info breakpoint $cond_bp_num" $re \ + "conditional breakpoint is now enabled" + + if { $hit_cond } { + gdb_test "continue" \ + [multi_line \ + "Breakpoint $other_bp_num, main \\(\\) at \[^\r\n\]+:$::other_bp_line" \ + "$::other_bp_line\\s+breakpt \\(\\);\\s+/\\* Other BP location\\. \\*/"] \ + "continue to other b/p" + } + + if {[allow_python_tests]} { + # Clear out the list of modified b/p. This makes the results + # (see below) clearer. + gdb_test_no_output "python bp_modified_list=\[\]" \ + "clear bp_modified_list" + } + + gdb_test "continue" \ + [multi_line \ + "Breakpoint $exit_bp_num, main \\(\\) at \[^\r\n\]+:$::exit_bp_line" \ + "$::exit_bp_line\\s+breakpt \\(\\);\\s+/\\* BP before exit\\. \\*/"] \ + "continue b/p before exit" + + # Check the b/p is once again marked as disabled based on its + # condition. + gdb_test "info breakpoint $cond_bp_num" \ + [multi_line \ + "\r\n$cond_bp_num\\.1\\s+N\\*\\s+$::hex in main at \[^\r\n\]+" \ + "\\(\\*\\): Breakpoint condition is invalid at this location\\."] \ + "conditional breakpoint is again disabled based on condition" + + if { [allow_python_tests] } { + # The condition breakpoint will have been modified (moved to + # the disabled state) when GDB unloaded the shared libraries. + # And the b/p in main will have been modified in that it's hit + # count will have gone up. + gdb_test "python print(bp_modified_list)" \ + "\\\[$cond_bp_num, $exit_bp_num\\\]" \ + "check b/p modified observer was triggered during restart" + } +} + +# The tests. +foreach_with_prefix hit_cond { true false } { + run_test $hit_cond +} diff --git a/gdb/testsuite/gdb.base/bp-disabled-by-cond.py b/gdb/testsuite/gdb.base/bp-disabled-by-cond.py new file mode 100644 index 00000000000..87b374c201e --- /dev/null +++ b/gdb/testsuite/gdb.base/bp-disabled-by-cond.py @@ -0,0 +1,21 @@ +# Copyright (C) 2024 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 . + +bp_modified_list = [] + +def bp_modified(bp): + bp_modified_list.append (bp.number) + +gdb.events.breakpoint_modified.connect(bp_modified) diff --git a/gdb/testsuite/gdb.trace/change-loc.exp b/gdb/testsuite/gdb.trace/change-loc.exp index 1316d92b116..a01cb712887 100644 --- a/gdb/testsuite/gdb.trace/change-loc.exp +++ b/gdb/testsuite/gdb.trace/change-loc.exp @@ -149,6 +149,7 @@ proc tracepoint_change_loc_1 { trace_type } { (4\.\[1-3].* in func4.*\tinstalled on target.*){2}" \ "tracepoint with two locations - installed (unload)" + setup_kfail gdb/32404 "*-*-*" gdb_test "info trace" \ "Num Type\[ \]+Disp Enb Address\[ \]+What.* \[0-9\]+\[\t \]+\(|fast \)tracepoint\[ \]+keep y.*\.* @@ -263,6 +264,7 @@ proc tracepoint_change_loc_2 { trace_type } { (1\.\[1-3].* in func4.*\tinstalled on target.*){2}" \ "tracepoint with two locations - installed (unload)" + setup_kfail gdb/32404 "*-*-*" gdb_test "info trace" \ "Num Type\[ \]+Disp Enb Address\[ \]+What.* \[0-9\]+\[\t \]+\(|fast \)tracepoint\[ \]+keep y.*\.* From patchwork Mon Dec 9 11:18:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 102667 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 76B69385828B for ; Mon, 9 Dec 2024 11:24:27 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 76B69385828B Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=HnFzedC8 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 ESMTP id 12B143858423 for ; Mon, 9 Dec 2024 11:18:19 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 12B143858423 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 12B143858423 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1733743099; cv=none; b=RuDZsEkwQC2/y6uHx78XFRXERAK5LnrQPcgTxRmA0ke0pAv/nhnU0AtN61mrAOQrK93bTFUR4BRXmaiKXLZ3LsnzwKWh4Xt+J7LE/aD5ZWtxlA5IovzSQMfF+HcTqPZBVWvpNEQszDaw0U/AbtP+LP95+N5I838ymJ5LDEVtm/4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1733743099; c=relaxed/simple; bh=CS31jLmWgz2EwwTT+hHZ8AK++W9z59bmJlbHv1d4A6U=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=NKDDYJC+IDnkfzfoB9DSkDrP47yqYND8SWsB8A3VFAcCXvt1tpnAjE9UVI9kf+0lR4g840xDiR7HopbROnMBoEUzPjqjmXOkwHDDEQwtmPyRm6ygFalgENLBsEFxnkiamvabvy0cDHpPXw5U7un7bCtfjBQGCL4fmkgn3AnZB5k= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 12B143858423 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1733743098; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HzfWfTgcNMFO0NKPb0vClNTVXTtiaZUmjOkl50+zuIw=; b=HnFzedC8vL4QY+1BKo1fOAw/kwZ+xKYoQmn4Qs3IBkq6dDTe5HQ9G+b66wBRganPk8s627 KEMqmTJx4+6o+vMl/A7f2lHhfqrOMWiYy+K8bgcLZuxEMr31odegREcqF/ecahYvBfygZe 8tThNSQUWCIpR/WF5Z813BolQPOxblU= Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-205-J6KdaNjJPI2YBH_mjWxsuQ-1; Mon, 09 Dec 2024 06:18:17 -0500 X-MC-Unique: J6KdaNjJPI2YBH_mjWxsuQ-1 X-Mimecast-MFC-AGG-ID: J6KdaNjJPI2YBH_mjWxsuQ Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-434f02ea82dso13581665e9.3 for ; Mon, 09 Dec 2024 03:18:16 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733743094; x=1734347894; 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=HzfWfTgcNMFO0NKPb0vClNTVXTtiaZUmjOkl50+zuIw=; b=u52iecAduOLavPXN7Qtkiy8y28eHkc+jMCNW38DCWZv3YTw9f9Q6o2Fms5BShVh09n Cot5xwGabf0v+nAYHQZdbVpfIDb8FlN5PWJnPXcg6vNbqcxG7JZt7DlzIUU1LJ/tQUJk lYjA/b+t1KW+OhQe1LK6Fsx8yZveIez9uPoiLMK8kHl1Zsmxmr8gKWrm6a7wuOiJAdhQ iyyzUgLOAKvFSkjZl6CwuHBjb1c/dZXMCys4LsmP6gddrL5COFBcHzztnElac4w8sSdj 3UJWao+gkn8iohURMX1MF+Cw23/x0Rs3CSxYIMfGo+xhyl24YpvRPT76SV03iRm/ApZI /fww== X-Gm-Message-State: AOJu0YxMVyx89QomNTKMksT3dyYtyVZS5jou1Xz/AhvsJ/c+nI3x8+FS nyAaID+sEbVf9ybiCNVXO3kXgVsijZX78LBSa+uwp6Y730iu4MU4Ehi0z+EFlNgy5wXN02Jec4y 7097EsG8AEhMSN/ktlM1pgyrhrQTvADFC4E65/sF5U4vh7Crqy8mY9onvXmhyL4M7QdJ/S58ouI 2z2r233XQwHpyfR7kdcmAvWR41Sp7kkCrH/+MYxO4KE7o= X-Gm-Gg: ASbGncs/3fkFLNwoVzIxAyHA4I6HrG4hzoyoUbPlx+aXiqXKAQn+e0ThK8lTI2tx2mi CWvxK1mUvE7tngZLzbYHIZaeWCxcZKaE+WL/2CA83UdlXGjZnI7cqQ/t9wqduiWpW976Y+ddowJ 1AubgY/X/Bz2KcTy43ApFg65FWfwWReaeO1x6hAF0twP7AeszjejVqtcTJeNii/mCVU31NLO9Sx 36QT/jW08prf+uFfSicJLyT1N0d8J/EZwdzclb0haESP2U4GV9fwUMol/Pu4u1xp6DjP/4fXoCI hA== X-Received: by 2002:a05:600c:5246:b0:434:a8ef:442f with SMTP id 5b1f17b1804b1-434fffc0b36mr11105e9.32.1733743093841; Mon, 09 Dec 2024 03:18:13 -0800 (PST) X-Google-Smtp-Source: AGHT+IGEVpqzqkRIdgvFBnalxTx68k8mHiXJZ1yrK6e9RikBwPSWewAEbyLF7R7UyhYY33fqgy45lQ== X-Received: by 2002:a05:600c:5246:b0:434:a8ef:442f with SMTP id 5b1f17b1804b1-434fffc0b36mr10805e9.32.1733743093228; Mon, 09 Dec 2024 03:18:13 -0800 (PST) Received: from localhost (197.209.200.146.dyn.plus.net. [146.200.209.197]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3862229a88asm12690464f8f.106.2024.12.09.03.18.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Dec 2024 03:18:11 -0800 (PST) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess , Hannes Domani Subject: [PATCHv5 3/7] gdb: restructure disable_breakpoints_in_unloaded_shlib Date: Mon, 9 Dec 2024 11:18:00 +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-MFC-PROC-ID: WfUb9YUF3tHvaQg3dgFWVGzrLg6Vew8CtN6xLjZgupM_1733743094 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-12.0 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.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org This commit rewrites disable_breakpoints_in_unloaded_shlib to be more like disable_breakpoints_in_freed_objfile. Instead of looping over all b/p locations, we instead loop over all b/p and then over all locations for each b/p. The advantage of doing this is that we can fix the small bug that was documented in a comment in the code: /* This may cause duplicate notifications for the same breakpoint. */ notify_breakpoint_modified (b); By calling notify_breakpoint_modified() as we modify each location we can potentially send multiple notifications for a single b/p. Is this a bug? Maybe not. After all, at each notification one of the locations will have changed, so its probably fine. But it's not ideal, and we can easily do better, so lets do that. There's a new test which checks that we only get a single notification when the shared library is unloaded. Note that the test is written as if there are multiple related but different tests within the same test file ... but there aren't currently! The next commit will add another test proc to this test script at which point the comments will make sense. I've done this to avoid unnecessary churn in the next commit. Tested-By: Hannes Domani --- gdb/breakpoint.c | 45 +++++---- gdb/testsuite/gdb.base/shlib-unload-lib.c | 30 ++++++ gdb/testsuite/gdb.base/shlib-unload.c | 63 ++++++++++++ gdb/testsuite/gdb.base/shlib-unload.exp | 114 ++++++++++++++++++++++ gdb/testsuite/gdb.base/shlib-unload.h | 26 +++++ gdb/testsuite/gdb.base/shlib-unload.py | 31 ++++++ 6 files changed, 292 insertions(+), 17 deletions(-) create mode 100644 gdb/testsuite/gdb.base/shlib-unload-lib.c create mode 100644 gdb/testsuite/gdb.base/shlib-unload.c create mode 100644 gdb/testsuite/gdb.base/shlib-unload.exp create mode 100644 gdb/testsuite/gdb.base/shlib-unload.h create mode 100644 gdb/testsuite/gdb.base/shlib-unload.py diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index bfff3bd8ee1..b663277aeb7 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -8079,29 +8079,37 @@ disable_breakpoints_in_unloaded_shlib (program_space *pspace, const solib &solib { bool disabled_shlib_breaks = false; - for (bp_location *loc : all_bp_locations ()) + for (breakpoint &b : all_breakpoints ()) { - /* ALL_BP_LOCATIONS bp_location has LOC->OWNER always non-NULL. */ - struct breakpoint *b = loc->owner; + bool bp_modified = false; - if (pspace == loc->pspace - && !loc->shlib_disabled - && (((b->type == bp_breakpoint - || b->type == bp_jit_event - || b->type == bp_hardware_breakpoint) - && (loc->loc_type == bp_loc_hardware_breakpoint - || loc->loc_type == bp_loc_software_breakpoint)) - || is_tracepoint (b)) - && solib_contains_address_p (solib, loc->address)) + if (b.type != bp_breakpoint + && b.type != bp_jit_event + && b.type != bp_hardware_breakpoint + && !is_tracepoint (&b)) + continue; + + for (bp_location &loc : b.locations ()) { - loc->shlib_disabled = 1; + if (pspace != loc.pspace || loc.shlib_disabled) + continue; + + if (loc.loc_type != bp_loc_hardware_breakpoint + && loc.loc_type != bp_loc_software_breakpoint + && !is_tracepoint (&b)) + continue; + + if (!solib_contains_address_p (solib, loc.address)) + continue; + + loc.shlib_disabled = 1; + /* At this point, we cannot rely on remove_breakpoint succeeding so we must mark the breakpoint as not inserted to prevent future errors occurring in remove_breakpoints. */ - loc->inserted = 0; + loc.inserted = 0; - /* This may cause duplicate notifications for the same breakpoint. */ - notify_breakpoint_modified (b); + bp_modified = true; if (!disabled_shlib_breaks) { @@ -8109,9 +8117,12 @@ disable_breakpoints_in_unloaded_shlib (program_space *pspace, const solib &solib warning (_("Temporarily disabling breakpoints " "for unloaded shared library \"%s\""), solib.so_name.c_str ()); + disabled_shlib_breaks = true; } - disabled_shlib_breaks = true; } + + if (bp_modified) + notify_breakpoint_modified (&b); } } diff --git a/gdb/testsuite/gdb.base/shlib-unload-lib.c b/gdb/testsuite/gdb.base/shlib-unload-lib.c new file mode 100644 index 00000000000..c38715f7ac9 --- /dev/null +++ b/gdb/testsuite/gdb.base/shlib-unload-lib.c @@ -0,0 +1,30 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2024 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 "shlib-unload.h" + +int +foo (void) +{ + return inline_func (); +} + +int +bar (void) +{ + return inline_func (); +} diff --git a/gdb/testsuite/gdb.base/shlib-unload.c b/gdb/testsuite/gdb.base/shlib-unload.c new file mode 100644 index 00000000000..4a3cb5d8b5d --- /dev/null +++ b/gdb/testsuite/gdb.base/shlib-unload.c @@ -0,0 +1,63 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2024 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 + +#ifdef __WIN32__ +#include +#define dlopen(name, mode) LoadLibrary (TEXT (name)) +#ifdef _WIN32_WCE +# define dlsym(handle, func) GetProcAddress (handle, TEXT (func)) +#else +# define dlsym(handle, func) GetProcAddress (handle, func) +#endif +#define dlclose(handle) FreeLibrary (handle) +#else +#include +#endif + +#include + +#include "shlib-unload.h" + +int +main (void) +{ + int res; + void *handle; + int (*func) (void); + + int val = inline_func (); + + handle = dlopen (SHLIB_NAME, RTLD_LAZY); + assert (handle != NULL); + + func = (int (*)(void)) dlsym (handle, "foo"); + assert (func != NULL); + + val += func (); + + func = (int (*)(void)) dlsym (handle, "bar"); + assert (func != NULL); + + val += func (); + + res = dlclose (handle); /* Break here. */ + assert (res == 0); + + return val; +} diff --git a/gdb/testsuite/gdb.base/shlib-unload.exp b/gdb/testsuite/gdb.base/shlib-unload.exp new file mode 100644 index 00000000000..791f9f518e8 --- /dev/null +++ b/gdb/testsuite/gdb.base/shlib-unload.exp @@ -0,0 +1,114 @@ +# Copyright 2024 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 . + +# Tests for GDB's handling of a shared library being unloaded via a +# call to dlclose. See the individual test_* procs for a description +# of each test. + +standard_testfile .c -lib.c + +# One of the tests uses this Python file. The test_* proc checks that +# GDB supports Python tests. Some of the other procs don't use this +# Python file. +set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] + +# Build the library and copy it to the target. +set libname ${testfile}-lib +set libfile [standard_output_file $libname] +if { [build_executable "build shlib" $libfile $srcfile2 {debug shlib}] == -1} { + return +} +set libfile_on_target [gdb_download_shlib $libfile] + +# Build the executable. +set opts [list debug shlib_load additional_flags=-DSHLIB_NAME=\"${libname}\"] +if { [build_executable "build exec" $binfile $srcfile $opts] == -1} { + return +} + +# The line number of the dlclose call. +set bp_line [gdb_get_line_number "Break here" $srcfile] + +# If the target is remote, then the library name in the bp_disabled_re +# below will have a 'target:' prefix. +if {[is_remote target]} { + set target_prefix_re "target:" +} else { + set target_prefix_re "" +} + +# The line emitted when GDB disables breakpoints after unloading a +# shared library. +set bp_disabled_re "warning: Temporarily disabling breakpoints for unloaded shared library \"$target_prefix_re[string_to_regexp $::libfile_on_target]\"" + +# The complete regexp for when GDB stops on the line after BP_LINE, +# assuming that GDB has disabled some breakpoints. +set stop_after_bp_re [multi_line \ + "^$::bp_disabled_re" \ + "[expr $::bp_line + 1]\\s+assert \\(res == 0\\);"] + +# Checking that a breakpoint with multiple locations in a shared +# library only triggers a single breakpoint modified event from +# disable_breakpoints_in_unloaded_shlib when the shared library is +# unloaded. +proc_with_prefix test_bp_modified_events {} { + if { ![allow_python_tests] } { + unsupported "python support needed" + return + } + + clean_restart $::binfile + + if {![runto_main]} { + return + } + + # If the debug information doesn't allow GDB to identify inline + # functions then this test isn't going to work. + get_debug_format + if { [skip_inline_frame_tests] } { + unsupported "skipping inline frame tests" + return + } + + gdb_breakpoint $::srcfile:$::bp_line + gdb_continue_to_breakpoint "stop before dlclose" + + gdb_breakpoint inline_func + set bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \ + "get b/p number"] + + gdb_test_no_output "source $::pyfile" "import python scripts" + + gdb_test "next" $::stop_after_bp_re + + # The breakpoint should have been modified once when some of its + # locations are made pending after the shared library is unloaded. + gdb_test_multiple "python print(bp_modified_counts\[$bp_num\])" "" { + -re -wrap "^1" { + pass $gdb_test_name + } + -re -wrap "^2" { + # A second event occurs when the pending breakpoint is + # incorrectly deleted. + kfail gdb/32404 $gdb_test_name + } + -re -wrap "^$::decimal" { + fail $gdb_test_name + } + } +} + +test_bp_modified_events diff --git a/gdb/testsuite/gdb.base/shlib-unload.h b/gdb/testsuite/gdb.base/shlib-unload.h new file mode 100644 index 00000000000..3448eed5cb9 --- /dev/null +++ b/gdb/testsuite/gdb.base/shlib-unload.h @@ -0,0 +1,26 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2024 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 inline int __attribute__((__always_inline__)) +inline_func () +{ + return 0; +} + +/* Two library functions. */ +extern int foo (void); +extern int bar (void); diff --git a/gdb/testsuite/gdb.base/shlib-unload.py b/gdb/testsuite/gdb.base/shlib-unload.py new file mode 100644 index 00000000000..eb541fd53fd --- /dev/null +++ b/gdb/testsuite/gdb.base/shlib-unload.py @@ -0,0 +1,31 @@ +# Copyright (C) 2024 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 . + +# Breakpoint modification events will be recorded in this dictionary. +# The keys are the b/p numbers, and the values are the number of +# modification events seen. +bp_modified_counts = {} + +# Record breakpoint modification events into the global +# bp_modified_counts dictionary. +def bp_modified(bp): + global bp_modified_counts + if bp.number not in bp_modified_counts: + bp_modified_counts[bp.number] = 1 + else: + bp_modified_counts[bp.number] += 1 + +# Register the event handler. +gdb.events.breakpoint_modified.connect(bp_modified) From patchwork Mon Dec 9 11:18:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 102666 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 0C9DB385828E for ; Mon, 9 Dec 2024 11:23:45 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0C9DB385828E Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=eK9hTe5k 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 ESMTP id 794CF3858428 for ; Mon, 9 Dec 2024 11:18:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 794CF3858428 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 794CF3858428 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1733743097; cv=none; b=cylDiCGXz2m7MDd+NbfEfTxhzCb63QfdeRZaRjmBiwo7Z+zHG5VVmt0kKUP6iK9qvTRrUk+YnsK8cxY2XkdDFNfyGxZh91ulrQAWEumNDDXfqkf//AFHMgOSAs3EuRBJSCc3YfkO3kqgMf4BTBYW2MMzMK8mfWNC2sfYDnWUrkI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1733743097; c=relaxed/simple; bh=OtpdqV9J50UDgO2g/Sv7v5OU0Y7CY33zVRLTr0t3ep0=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=noJIVaYdatBxPgmV4nTs81rNSSufpe8nwe3HVjSAOyUAKq8ZygYT/AKE/LlV68y6l33iqPd//UF/uDdB32fZuZNT0fElJrvx2Yr7LXGp/yTVKRgBI8R79ytfxBCUD/x7kT1Cjki9WkdbZi6JGJciMN1heKM7VExUbcJO183cdMo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 794CF3858428 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1733743097; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wZl/op9u0C8+mZgw2HEmWSlFRDTCIx2sm1xjasDUz1E=; b=eK9hTe5kSWKhL8F+t+A+jmCqHZdA96q/GnAHkgBnOLmAeBO1G0UdTj/VOxdSYl7zm3w67U jlYMy5dLjg+jwjYg/f8mwbbpRd7ckwuCrPgdxfONjuHJLoLYkTgk0FTCEfQbOPU6GV/R/l 3cPMw03i0rqcKfBlPmLAMY8QE38pUgQ= Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-223-4hTwuZSqMEWctZ6eMUGXCw-1; Mon, 09 Dec 2024 06:18:16 -0500 X-MC-Unique: 4hTwuZSqMEWctZ6eMUGXCw-1 X-Mimecast-MFC-AGG-ID: 4hTwuZSqMEWctZ6eMUGXCw Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-434f40667e5so7216905e9.1 for ; Mon, 09 Dec 2024 03:18:16 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733743095; x=1734347895; 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=wZl/op9u0C8+mZgw2HEmWSlFRDTCIx2sm1xjasDUz1E=; b=s92dIWzILr7jkLddJlqmt16/NgVhHD7Gdao468xcN4/UKKEsYoAuzBq6Q436UcGcyb yxYB+WiOs6hxMqMW3xUlO7kA30nZlgA1rmkQujCKcQzpvZUSXRt3DB3O1KIBCFxysYx+ k/1ORgjkpTOFg7Tsaa/ASQjyTHTs/Ccy057ETRWBvrWqOHJCS8NU4kuhPxqOp+tGldF4 iywQTJVts9CooM87RSGs1Hja6DbQD460HOcSgTV241e8UUJMthiswHgMuWp62hf4yCPH e68N7Ra+cyhp08qnl6cdOz6tjGP3QRG22P6Z7uxO8qlBV+OgXwpKW9UriBwb0GsDwnXW hCFQ== X-Gm-Message-State: AOJu0YxxFiQO0OubJAJY16KmPA5cY5qwqw85bkZzgtbb3HnLitq8MwF+ kqGJrFpEnL2tSwcnhsY8OyZ/7gl24xj3/3e+g17L27dQcRhCIMCDAbodW/H1kf8s6i6pt2btG0U P8NH8c5N0jISp04I7c2vvHDLI4a99scdton2BXyvNqVgVEsY87GYyb4fKIIn8548IM32+H5GxMW GzlOfeLKsD6Jc6gY+8MUwGOgf201XefDSnkq9FscMAzm4= X-Gm-Gg: ASbGncvE82mET6YafDuXJcDMaAPwWzBQ765Ex7NR89C3P0ZWLlJe/KTGApbkq4Tt8r6 RM2zUqKRBnzVYQwfsuiH0PGzv3o2RoBDa6DcmOgdghINFncRtkoxR6YcXsd+5ARcYbebqo+JIf+ cJRP8GUEEnPqtCHLBTQDBmX3+DjPNHKGz6ERS/hi9lgJmk6TQd1bGVR0pdu3mqRa1OLXsaywkgM 3/n0FrCTr7MqQzgeOlaoxcVRl60pIHXehYmiZ6otI+fH7Wo8QPU2IAQFTwHvR/4fj+W7YnYWvuH Dw== X-Received: by 2002:adf:e18a:0:b0:385:e2c4:1f8d with SMTP id ffacd0b85a97d-3862b351423mr9047179f8f.19.1733743094772; Mon, 09 Dec 2024 03:18:14 -0800 (PST) X-Google-Smtp-Source: AGHT+IEWeSTA4TiBjsTMW3jGxuoswgj8H2QIpMZEIjFxneRACmh6fPcDgajFGMDMOjKcY/LINNNXpw== X-Received: by 2002:adf:e18a:0:b0:385:e2c4:1f8d with SMTP id ffacd0b85a97d-3862b351423mr9047154f8f.19.1733743094255; Mon, 09 Dec 2024 03:18:14 -0800 (PST) Received: from localhost (197.209.200.146.dyn.plus.net. [146.200.209.197]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-38634bb1669sm7615373f8f.60.2024.12.09.03.18.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Dec 2024 03:18:14 -0800 (PST) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess , Hannes Domani Subject: [PATCHv5 4/7] gdb: handle dprintf breakpoints when unloading a shared library Date: Mon, 9 Dec 2024 11:18:01 +0000 Message-Id: <540204eab68597c954e84c3014fcaff0a2a107f9.1733742925.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-MFC-PROC-ID: 3pfIRzQDy5SnzuHqDNt-XT3zd-be3ZcI7czpvjJ-4rY_1733743095 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-12.0 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.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org While working on the previous commit I realised that GDB would not handle dprintf breakpoints correctly when a shared library was unloaded. Consider this example using the test binary from the previous commit, the function 'foo' where we create a dprintf is in a shared library: (gdb) b 59 Breakpoint 1 at 0x401215: file /tmp/projects/binutils-gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/shlib-unload.c, line 59. (gdb) r Starting program: /tmp/projects/binutils-gdb/build/gdb/testsuite/outputs/gdb.base/shlib-unload/shlib-unload Breakpoint 1, main () at /tmp/projects/binutils-gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/shlib-unload.c:59 59 res = dlclose (handle); /* Break here. */ (gdb) dprintf foo,"In foo" Dprintf 2 at 0x7ffff7fc50fd: file /tmp/projects/binutils-gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/shlib-unload-lib.c, line 23. (gdb) n Error in re-setting breakpoint 2: Function "foo" not defined. warning: error removing breakpoint 2 at 0x7ffff7fc50fd warning: error removing breakpoint 2 at 0x7ffff7fc50fd warning: error removing breakpoint 2 at 0x7ffff7fc50fd warning: error removing breakpoint 2 at 0x7ffff7fc50fd warning: error removing breakpoint 2 at 0x7ffff7fc50fd warning: error removing breakpoint 2 at 0x7ffff7fc50fd warning: error removing breakpoint 2 at 0x7ffff7fc50fd warning: error removing breakpoint 2 at 0x7ffff7fc50fd Cannot remove breakpoints because program is no longer writable. Further execution is probably impossible. 60 assert (res == 0); (gdb) What happens here is that as the inferior steps over the dlclose call the shared library containing 'foo' is unloaded and disable_breakpoints_in_unloaded_shlib is called. However in disable_breakpoints_in_unloaded_shlib we have this check: if (b.type != bp_breakpoint && b.type != bp_jit_event && b.type != bp_hardware_breakpoint && !is_tracepoint (&b)) continue; As the dprintf has type bp_dprintf then this check triggers and we ignore the dprintf, meaning the dprintf is not disabled. When the inferior stops after the 'next' GDB tries to remove all breakpoints but the dprintf can no longer be removed, the memory in which it was placed has been unmapped from the inferior. The fix is to start using is_breakpoint() in disable_breakpoints_in_unloaded_shlib instead of the bp_breakpoint and bp_hardware_breakpoint checks. The is_breakpoint() function also checks for bp_dprintf. With this fix in place GDB now correctly disables the breakpoint and we no longer see the warning about removing the breakpoint. Tested-By: Hannes Domani --- gdb/breakpoint.c | 5 ++--- gdb/testsuite/gdb.base/shlib-unload.exp | 29 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index b663277aeb7..99c216b0271 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -8083,9 +8083,8 @@ disable_breakpoints_in_unloaded_shlib (program_space *pspace, const solib &solib { bool bp_modified = false; - if (b.type != bp_breakpoint - && b.type != bp_jit_event - && b.type != bp_hardware_breakpoint + if (b.type != bp_jit_event + && !is_breakpoint (&b) && !is_tracepoint (&b)) continue; diff --git a/gdb/testsuite/gdb.base/shlib-unload.exp b/gdb/testsuite/gdb.base/shlib-unload.exp index 791f9f518e8..7516ee2a292 100644 --- a/gdb/testsuite/gdb.base/shlib-unload.exp +++ b/gdb/testsuite/gdb.base/shlib-unload.exp @@ -111,4 +111,33 @@ proc_with_prefix test_bp_modified_events {} { } } +# Check that GDB disables dprintf breakpoints within a shared library +# when the shared library is unloaded. +proc_with_prefix test_dprintf_at_unload {} { + clean_restart $::binfile + + if {![runto_main]} { + return + } + + gdb_breakpoint $::srcfile:$::bp_line + gdb_continue_to_breakpoint "stop before dlclose" + + # Setup a dprintf within the shared library. + gdb_test "dprintf foo,\"In foo\"" + set bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \ + "get b/p number"] + + # Unload the shared library, GDB should disable our b/p. + gdb_test "next" $::stop_after_bp_re + + # Check that our b/p is now showing as disabled. + gdb_test "info breakpoints $bp_num" \ + [multi_line \ + "^Num\\s+Type\\s+Disp\\s+Enb\\s+Address\\s+What" \ + "$bp_num\\s+dprintf\\s+keep\\s+y\\s+\\s+foo" \ + "\\s+printf \"In foo\""] +} + test_bp_modified_events +test_dprintf_at_unload From patchwork Mon Dec 9 11:18:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 102665 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 DA0C3385801B for ; Mon, 9 Dec 2024 11:22:55 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org DA0C3385801B Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=MQf+OdKG 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 ESMTP id 5688E385843F for ; Mon, 9 Dec 2024 11:18:19 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 5688E385843F Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 5688E385843F Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1733743099; cv=none; b=wPiW115GGF4ZyjcdIP6C1YG1WrvV/ms87YKELOEhHJPMnkVzin3UZciXcOFN6c1yCFyAm2V6W6TermEwUok3yOCeMX/vn64Hd7EZ7Uju6cd09dX6lhRPE9UwyYU/rke/TiqNljqs4OJ3t2cGi8w0N8+1kebI9WgyIxSc48klZUs= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1733743099; c=relaxed/simple; bh=FxTXuJmEcHjh//pL6OPaY9FfoOkfsVIaDtlopFf/KPg=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=sC923rwL76noyOAaIuUnpghKcLHr/f/NwKo4ghU8ib5tQwDkOqN4+2EagJC8Db8u326F0JY8GZgS/csXoJUCjxFHssZQ67kc3mVO3ihNbUMkxvDKJaKt3tgr1x/q3KVBpON357BePKc+59bxlcpgZXkbN8lm73/ojEhM6g6wmxo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5688E385843F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1733743099; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=xALDtxGnBtCIaK5JDfLRAc4Wd8uMmwixjedNzB/eGCw=; b=MQf+OdKGfUxz1Qhsi0Z4AgNOnCpwc7H8dfnpo48E8WLjXzkByFMh5V3sTQEu/U9+6yujBT vmhb5tGYycpZlKSqENexnRixnX2dZa+whFfAJcn7J8OjHgtVc2FWKLsjjTYagpYExL+TOB hFEMWuQyIRTt43TZirkwUkKh+mcfxIs= Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-572-NnNH8lY_PmyZRTAYH3PFrQ-1; Mon, 09 Dec 2024 06:18:18 -0500 X-MC-Unique: NnNH8lY_PmyZRTAYH3PFrQ-1 X-Mimecast-MFC-AGG-ID: NnNH8lY_PmyZRTAYH3PFrQ Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-385e1339790so2739265f8f.2 for ; Mon, 09 Dec 2024 03:18:17 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733743096; x=1734347896; 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=xALDtxGnBtCIaK5JDfLRAc4Wd8uMmwixjedNzB/eGCw=; b=QFq1gtPZngX+Ih/R9PJJt8WWhdGDGgF+tqL5XVqLEQ6OKQ5zJQUxu1Orj2/+LC0w6u vlAYAnzMupQjEr+iMcOykyQZnL692kV9qpGYf4XhUOillRLT3ev2Wolzgh8PD2McsVO/ DMcLb0m8zDsaZWbo7odplNW7IMkATCOL2b8ibumWkXbC3Ikd78fpHA6F82jqBc0HgP7u F3pVm0eZk9dScNIpRSIKOXYE2ICT3IPfdqK7yitbQZQSrKLXoAxI7FHuksf7QEYBcNmn tV3U90uy3qqb7ZTbBWvqYyQ9XmvVyjhTht1EXFTo7jVFtnMzBHtJlMabVXRypOTN6J60 ajBg== X-Gm-Message-State: AOJu0Yz57vyKH0cQC0b6h6gMDFURE0RA51ECidD7WQNNgSg1XGAWXIzK ZfaIvWRP8LdgqcuFA1WbsjhmY/dCmBkYG7QAwXtVUUzvX1vHlOOSa2rfxV62MUQxFVZBF13WHLz SAMfO5qtTaNAm4r9H9v9xMilMefZOAIHjD50vzamMIqpB2CWP4G7riGfmsPLXwD3oV9RlCe7zC5 SWn18iLY6k2Sy49BXfkus+hQsLxqt5iVAxnmRvm/yyIqs= X-Gm-Gg: ASbGnct1e3qamBhmPLxuM89+sjWUahYqkD8xiwquAoqMZh9WlFR9WAITVoP9aBalJLe 0iSrAKsEdo1VS4mI7qyZ7e3YWqz39GOyguxUK9E/2VBz/+EANnBUYqILDIWo19D4h03cvOiI2T7 PP7s7mqZe41fsCA1SlWh/htjgkdUWE4rPm04fgX4z2MxBtF887vv0tXoPnTiijVVPcUpU39q9I1 gmmfTzQFBo3fRktU9jLQoQlUlO0lASY2qXlgdSRZ00AzXs7tzikFjHI6brFv9GQhz8ajpB6KHvz MQ== X-Received: by 2002:a5d:6da5:0:b0:382:46ea:113f with SMTP id ffacd0b85a97d-3862b33e3d9mr8364649f8f.10.1733743096180; Mon, 09 Dec 2024 03:18:16 -0800 (PST) X-Google-Smtp-Source: AGHT+IFvzwQqGdkj/gZCIt3U9x/jOa9B+awxxS+4dnnbKMfYi7WX9RWipUicGjO0blIfFHuOF02z5A== X-Received: by 2002:a5d:6da5:0:b0:382:46ea:113f with SMTP id ffacd0b85a97d-3862b33e3d9mr8364621f8f.10.1733743095595; Mon, 09 Dec 2024 03:18:15 -0800 (PST) Received: from localhost (197.209.200.146.dyn.plus.net. [146.200.209.197]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3862c611242sm9912049f8f.36.2024.12.09.03.18.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Dec 2024 03:18:15 -0800 (PST) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv5 5/7] gdb: don't clear inserted flag in disable_breakpoints_in_unloaded_shlib Date: Mon, 9 Dec 2024 11:18:02 +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-MFC-PROC-ID: sPYrDndoqKDQLYcE_T8qf1ihL658WAW8c56_rZZHgdM_1733743097 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-12.0 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.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org This commit removes the clearing of bp_location::inserted from disable_breakpoints_in_unloaded_shlib, my claim is that this call is not needed (any more), and with the next commit, this line actually causes some problems. The disable_breakpoints_in_unloaded_shlib function was added back in 2004 with commit 84acb35a5a97c, and from this first version the function cleared the bp_location::inserted flag. The motivation for this is that the shared library might have already been unmapped, in which case, a later attempt to remove the location could fail. In 2013 a similar function disable_breakpoints_in_freed_objfile was added. This function also cleared bp_location::inserted for similar reasons. This code was added in commit: commit 63644780babdca3f40e1978a236b6cd78473c91b Date: Tue Mar 12 11:10:18 2013 +0100 New remove-symbol-file command. Then in 2014 the clearing of bp_location::inserted was removed from disable_breakpoints_in_freed_objfile in the commit: commit 08351840eabb44799e3d01026610420758f4fa40 Date: Tue Apr 22 23:19:19 2014 +0100 Stale breakpoint instructions, spurious SIGTRAPS. The reason that clearing the ::inserted flag was removed in this commit is that if the disable_breakpoints_in_freed_objfile function was called when the b/p were actually inserted, and the memory for the associated objfile wasn't actually unmapped, then we could end up leaving breakpoints inserted into the inferior, which leads to spurious SIGTRAPs. In the next commit I'll change disable_breakpoints_in_unloaded_shlib so that all breakpoints, not just user breakpoints, will be disabled (via shlib_disabled) when a shared library is unloaded. This addresses PR gdb/32079, see the next commit for a fuller justification for this change. The problem is that when I tested the next commit I ran into some regressions from the gdb.base/nostdlib.exp test when run on an AArch64 GNU/Linux system where executables are compiled as PIE by default. This test compiles a simple binary with the -nostdlib flag. What happens is this: - The executable is compiled as PIE, this means that we get a dynamically linked executable, the dynamic linker is used to perform the PIE relocation, but the executable uses no other shared libraries. - When GDB starts the inferior, initially the dynamic linker is discovered as a shared library being used by the application, GDB loads in the library and its debug symbols, placing the internal "shlib event" breakpoints so that future shared library events can be tracked. - For the target I tested on systemtap probes were not used, instead GDB fell back to the old style even breakpoint. - As the inferior progresses, after the PIE relocation has been performed, the dynamic linker performs some house keeping on the list of shared libraries being used by the application. During this process the dynamic linker is removed from the list of shared libraries being used by the inferior, this causes GDB see a shared library event, which GDB understands to mean that it should unload the dynamic linker from the inferior. I spoke with the glibc engineers at RH, and the feeling is that this is likely a bug (it's still being investigated). But I don't think it really matters if this is a bug or not. There are versions of glibc in the wild that have this behaviour, so GDB should (if the cost is not too great) be updated to handle this. Obviously after removing the dynamic linker from the list of shared libraries, the dynamic linker is not actually unmapped, that would not be possible, it's the dynamic linker that does the unmapping, so the dynamic linker is left mapped into the inferior's address space. - With the next patch in place all breakpoints (user and internal) within the dynamic linker are disabled (shlib_disabled) and currently marked as not inserted (bp_location::inserted flag is cleared). - Having processed the shared library event GDB then resumes the inferior. As the shared library event is not a full stop of the inferior (i.e. we don't remove all breakpoints before handling the event), all of the breakpoints in the dynamic linker are still inserted, but are now marked as not-inserted. - GDB then resumes the inferior and immediately hits the breakpoint that is still inserted. As GDB thinks this breakpoint is not inserted, this is reported to the user as a SIGTRAP. The fix I think is just to not clear the bp_location::inserted flag in disable_breakpoints_in_unloaded_shlib. This will leave the breakpoint as inserted in the case above. GDB will now be able to successfully resume the inferior after the shared library event (knowing there is a breakpoint inserted GDB will step over it and continue as expected). The next time the inferior performs a full stop the now shlib_disabled breakpoint will be removed from the inferior we would want. For the usual case, where a shared library is being unloaded due to say a dlclose, the breakpoints in the library will be marked as disabled, but will be left inserted. The next time remove_breakpoints is called GDB will try to remove those breakpoint locations. If the removal fails, as the breakpoint is marked shlib_disabled, GDB will hide the error message from the user and just assume that the shared library has been unmapped. This functionality was first added in 2008 in commit 879d1e6b4674bc8. There are two aspects to testing this change. First whether no clearing the ::inserted flag causes general problems. That is tested by running the full testsuite (I see no regressions). Then there is the specific problem that caused me to make this change. That issue only occurs on AArch64, with GNU/Linux using glibc, when the executable is compiled as PIE, and doesn't use any shared libraries other than the dynamic linker (which can be the gdb.base/nostdlib.exp test if run on the right system). What I don't know is how to recreate this setup in a more general form. We can't use add-symbol-file/remove-symbol-file as that passes through disable_breakpoints_in_freed_objfile instead, which the ::installed flag is already not adjusted. Also the bug doesn't trigger on x86 targets due to code in handle_signal_stop which sees the inserted breakpoint, and decides this must be a breakpoint that actually exists in the program, and then because gdbarch_decr_pc_after_break returns non-zero for x86, GDB steps the inferior past the breakpoint. This is the big difference from AArch64 where gdbarch_decr_pc_after_break returns zero, and so the inferior gets stuck hitting the unexpectedly inserted breakpoint. --- gdb/breakpoint.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 99c216b0271..2ef4a3b2b8d 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -8103,10 +8103,21 @@ disable_breakpoints_in_unloaded_shlib (program_space *pspace, const solib &solib loc.shlib_disabled = 1; - /* At this point, we cannot rely on remove_breakpoint - succeeding so we must mark the breakpoint as not inserted - to prevent future errors occurring in remove_breakpoints. */ - loc.inserted = 0; + /* At this point, we don't know whether the shared library + was unmapped from the inferior or not, so leave the + inserted flag alone. We'll handle failure to uninsert + quietly, in case the library was indeed unmapped. + + The test gdb.base/nostdlib.exp when run on AArch64 + GNU/Linux using glibc will cause the dynamic linker to be + unloaded from the inferior, but the linker will never be + unmapped. Additionally, at the time the dynamic linker + is unloaded the inferior will be stopped within the + dynamic linker. + + If we clear the inserted flag here then GDB will fail to + remove the internal breakpoints from the dynamic linker + leading to unexpected SIGTRAPs. */ bp_modified = true; From patchwork Mon Dec 9 11:18:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 102664 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 A699F385828E for ; Mon, 9 Dec 2024 11:22:42 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A699F385828E Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=c0aoO/gK 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 ESMTP id 143FB3858289 for ; Mon, 9 Dec 2024 11:18:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 143FB3858289 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 143FB3858289 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1733743101; cv=none; b=ex5+AMtp+8qTRMIQzLJ/NSH2F5JICBLjjy1nzl8Dbc6+j1QSxuCNRHdl2fbFwDiyoibDhwf+yD/QhCT5k/QBWtBP0CJSmwzKzaaiT015mX2vPCWmA1qMw/vGOwXyRpF6+zDg+JBr+hFM3kelT39AvsSYAJjbsUS7hPVBV5eIAAQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1733743101; c=relaxed/simple; bh=vy9U1ApXEzFlMQCjQOnKVn8Md4yAccYPNu1Kh6BouW8=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=PNNAmk4L3VgEKCVFN5vh4MSry626PInOOnggZX2WNPbqD6wxsy2k4U4bDo6SFyxwBvgbD8MES2rEp6vxchkoy0OgyDjGA6fQ8QwoKbWgjWXJHtLqEZtqB6gre/3KSgKpNEE81p/Bj4VYkSRqJm19LT0QdFoC1eJajj6Te3AQ5ds= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 143FB3858289 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1733743100; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=kTs3ZhuoAuC4ypAC9z6n5W3Lm18sr1hoC5VjmFpRKtQ=; b=c0aoO/gKPm+A4AmuFKAmn/pril6r/N4m172721x0ne2I62RiGyER4bC0eHw7J4rvck3/hV GDeF5FAAnPTeO23xqCtFSDpjRR+G2yL17K1dXQ6vORE2cyW9xJ6j0e3fdMm5u5laQ1tU36 A+Z+5aLoTcyTDfe4o4sgkCSuXye99Vs= Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-527-YcGvfauoPLShgVMRgHbl4g-1; Mon, 09 Dec 2024 06:18:19 -0500 X-MC-Unique: YcGvfauoPLShgVMRgHbl4g-1 X-Mimecast-MFC-AGG-ID: YcGvfauoPLShgVMRgHbl4g Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-385e3cbf308so763914f8f.2 for ; Mon, 09 Dec 2024 03:18:19 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733743097; x=1734347897; 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=kTs3ZhuoAuC4ypAC9z6n5W3Lm18sr1hoC5VjmFpRKtQ=; b=KJF3lphaVRgAlb+8MmcJzPRoIpvHd/D2oB67KUcx0ZQyjoVRdnc0fHKVXXpEUw5kgS qxl9YltijaZVF2JTTseUlmmmelErmbczrvLv2o6le9R5nfibtNIjPCwRrCZjlY4b6Suv leYZhroqkzZSxmw8YlbzdvQsegHWbz96AOkj2Z9zpjntbLGajQENUC8Z9m4TToCauWnf UTNe5PlTbCpT/G9J5ucSWunq1h6Mbh3pX033PeROUThj76jCjwiTXgulp7Q0oIPaRNzV JdlvQI9jFmwdyMfVBpMij8BkKt7M12haoV+dy53cQW+YEeAoyXDtVxpBAeaF3/tJ0NOC MTYQ== X-Gm-Message-State: AOJu0YxAOLsFyY1g9cG+daOW1bB+Zaf165ARJUDpDhnqiy7xH1OC0EDB f5E5pWw/I2C+JGKCrIHYzxLK6v2xMa7gBpLBzO4t+Ghp4R6bzWilKAnzGHYTcOtPX3Wi7+2W5Nq Uhfl688J3WHF/7GxkkKsaAwtINkbRwru2yZZCbup6Mf/StyxQIpvjH1X9LhqwkduZOpunJ0erSw /nQJCHZsyUX+PfzKhUfI+ETTsfJkJ5cans6e+d8fbveMk= X-Gm-Gg: ASbGncv2yRd8HK30eTF6afPc4xJMsh/UYM/rQ+OB6ypAYKd4bJm3hJw6t/2HT425eE6 pdcFJn+5OJ3CV0yKDb/T83RbkxLcvoixOIGenptfNidtxb3Gc+U4idwRWuYmt8+GC2NwogE1Ixb Sq89eZYw5I9XI9s/W9jDwVbnpz3dEgngmhhV8VdLCOoHTRgpVARf8nWHWnl+ZvelhXXzzntgCsV G713Mv2x0e7JewRjsjYCdSBWBTO6Bg+673AuffegzG+u7wESo5Yvz5QVD9oH0MiMwJ4Peci3RPA 6g== X-Received: by 2002:a5d:6f03:0:b0:385:e961:6589 with SMTP id ffacd0b85a97d-3862b351329mr7604870f8f.20.1733743097161; Mon, 09 Dec 2024 03:18:17 -0800 (PST) X-Google-Smtp-Source: AGHT+IFUn59dLOKO0Z5SSCXsbpYdPfrzcnfslLpWXMxLLfoBCaCiR7xvv0z9OirwuFYJpTZrxch8WA== X-Received: by 2002:a5d:6f03:0:b0:385:e961:6589 with SMTP id ffacd0b85a97d-3862b351329mr7604848f8f.20.1733743096598; Mon, 09 Dec 2024 03:18:16 -0800 (PST) Received: from localhost (197.209.200.146.dyn.plus.net. [146.200.209.197]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-38638415730sm5698640f8f.21.2024.12.09.03.18.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Dec 2024 03:18:16 -0800 (PST) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess , Hannes Domani Subject: [PATCHv5 6/7] gdb: disable internal b/p when a solib is unloaded Date: Mon, 9 Dec 2024 11:18:03 +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-MFC-PROC-ID: _WsVENX7wnTAqrp6GgAwJd3rUBL5W2sqJ-QuaIHus5s_1733743099 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-12.0 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.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org Bug PR gdb/32079 highlights an issue where GDB will try to remove a breakpoint for a shared library that has been unloaded. This will trigger an error from GDB like: (gdb) next 61 dlclose (handle[dl]); (gdb) next warning: error removing breakpoint 0 at 0x7ffff78169b9 warning: error removing breakpoint 0 at 0x7ffff7730b57 warning: error removing breakpoint 0 at 0x7ffff7730ad3 54 for (dl = 0; dl < 4; ++dl) (gdb) What happens is that as the inferior steps over the dlclose() call GDB notices that the library has been unloaded and calls disable_breakpoints_in_unloaded_shlib. However, this function only operates on user breakpoints and tracepoints. In the example above what is happening is that the test loads multiple copies of libc into different linker namespsaces. When we 'next' over the dlclose call one of the copies of libc is unloaded. As GDB placed longjmp master breakpoints within the copy of libc that was just unloaded, the warnings we see are GDB trying (and failing) to remove these breakpoints. I think the solution is for disable_breakpoints_in_unloaded_shlib to handle all breakpoints, even internal ones like the longjmp master breakpoints. If we do this then the breakpoint will be marked as shlib_disabled and also will be marked as not inserted. Later when we call breakpoint_re_set() and the longjmp breakpoints are deleted we will no longer try to remove them. This solution is inspired by a patch suggested in the bug report: https://sourceware.org/bugzilla/show_bug.cgi?id=32079#c3 There are some differences with my approach compared to the patch suggested in the bug. First I have no need to delete the breakpoint inside disable_breakpoints_in_unloaded_shlib as an earlier patch in this series arranged for breakpoint_re_set to be called when shared libraries are removed. Calling breakpoint_re_set will take care of deleting the breakpoint for us. For details see the earlier commit titled: gdb: fixes for code_breakpoint::disabled_by_cond logic Next, rather than only handling bp_longjmp and bp_longjmp_master, I allow all breakpoints to be handled. I also only give the warning about disabling breakpoints for user breakpoints, I don't see the point of warning the user about internal b/p changes. The biggest change though is that I've added some code to detect shared libraries that appear to be mapped multiple times. Here's the 'info sharedlibrary' output for the binary for gdb.base/dlmopen.exp after all the shared libraries have been loaded: 61 dlclose (handle[dl]); (gdb) info sharedlibrary From To Syms Read Shared Object Library 0x00007ffff7fca000 0x00007ffff7ff03f5 Yes /lib64/ld-linux-x86-64.so.2 0x00007ffff7edb3d0 0x00007ffff7f4f898 Yes (*) /lib64/libm.so.6 0x00007ffff7d0f800 0x00007ffff7e6eacd Yes (*) /lib64/libc.so.6 0x00007ffff7fb8040 0x00007ffff7fb80f9 Yes /tmp/build/gdb/testsuite/outputs/gdb.base/dlmopen/dlmopen-lib-dep.so 0x00007ffff7c003d0 0x00007ffff7c74898 Yes (*) /lib64/libm.so.6 0x00007ffff7a34800 0x00007ffff7b93acd Yes (*) /lib64/libc.so.6 0x00007ffff7fca000 0x00007ffff7ff03f5 Yes /lib64/ld-linux-x86-64.so.2 0x00007ffff7ce2040 0x00007ffff7ce2116 Yes /tmp/build/gdb/testsuite/outputs/gdb.base/dlmopen/dlmopen-lib.1.so 0x00007ffff7cdd040 0x00007ffff7cdd0f9 Yes /tmp/build/gdb/testsuite/outputs/gdb.base/dlmopen/dlmopen-lib-dep.so 0x00007ffff79283d0 0x00007ffff799c898 Yes (*) /lib64/libm.so.6 0x00007ffff775c800 0x00007ffff78bbacd Yes (*) /lib64/libc.so.6 0x00007ffff7fca000 0x00007ffff7ff03f5 Yes /lib64/ld-linux-x86-64.so.2 0x00007ffff7cd8040 0x00007ffff7cd8116 Yes /tmp/build/gdb/testsuite/outputs/gdb.base/dlmopen/dlmopen-lib.2.so (*): Shared library is missing debugging information. (gdb) The important thing to spot here is /lib64/ld-linux-x86-64.so.2. This library appears 3 times in the list but is at the same address in each case. This indicates three copies of this library mapped into three different linker namespaces, but the linker has spotted a single instance of the library can be shared. When the inferior calls dlclose() GDB will still see an event for this library being unloaded. If we disable all the b/p within this library on the first event then we end up leaving software b/p in the code as the library isn't really unmapped at this point. What we need to do is spot that the library is mapped multiple times and only perform the b/p disable logic if this is the last instance of the library. With this done the issues in PR gdb/32079 are resolved. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32079 Tested-By: Hannes Domani --- gdb/breakpoint.c | 39 ++++++++++++--- gdb/testsuite/gdb.base/dlmopen.exp | 76 ++++++++++++++++++++++++------ 2 files changed, 95 insertions(+), 20 deletions(-) diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 2ef4a3b2b8d..c6bd6f68363 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -8077,17 +8077,44 @@ disable_breakpoints_in_shlibs (program_space *pspace) static void disable_breakpoints_in_unloaded_shlib (program_space *pspace, const solib &solib) { + /* A shared library can appear twice on the runtime-linkers shared + library list, but the shared library is actually mapped in only once. + This can happen when linker namespaces are used. When one of those + mappings is removed this function is called. If we then disable and + mark as removed all the b/p within the library then we'll end up + leaving software breakpoints in the code (as the library was never + actually unmapped). + + To prevent this, we check the shared library list. If we find some + other shared library with the same objfile then we can leave the + breakpoints alone. + + If a shared library is mapped a second time, but at a different + address, then the shared library will be given a new objfile. */ + for (const struct solib &so : pspace->solibs ()) + { + if (&solib == &so) + continue; + + /* SOLIB and SO are two different solib objects, but, if they share + the same objfile then there is really only a single mapped + instance of the library. + + If SOLIB has no objfile then it will have no target sections (as + target sections are derived from the objfile) and so the + solib_contains_address_p call below will always return false, thus + we don't need to worry about the case where neither SOLIB and SO + have no objfile. */ + if (solib.objfile != nullptr && solib.objfile == so.objfile) + return; + } + bool disabled_shlib_breaks = false; for (breakpoint &b : all_breakpoints ()) { bool bp_modified = false; - if (b.type != bp_jit_event - && !is_breakpoint (&b) - && !is_tracepoint (&b)) - continue; - for (bp_location &loc : b.locations ()) { if (pspace != loc.pspace || loc.shlib_disabled) @@ -8121,7 +8148,7 @@ disable_breakpoints_in_unloaded_shlib (program_space *pspace, const solib &solib bp_modified = true; - if (!disabled_shlib_breaks) + if (!disabled_shlib_breaks && user_breakpoint_p (&b)) { target_terminal::ours_for_output (); warning (_("Temporarily disabling breakpoints " diff --git a/gdb/testsuite/gdb.base/dlmopen.exp b/gdb/testsuite/gdb.base/dlmopen.exp index 264c5180f3f..f0a29280d8b 100644 --- a/gdb/testsuite/gdb.base/dlmopen.exp +++ b/gdb/testsuite/gdb.base/dlmopen.exp @@ -144,27 +144,75 @@ gdb_breakpoint $srcfile:$bp_main test_dlmopen # Try the same again when attaching after dlmopen(). -require can_spawn_for_attach +if { [can_spawn_for_attach] } { -clean_restart $binfile + clean_restart $binfile -# Start the test program. -set test_spawn_id [spawn_wait_for_attach $binfile] -set testpid [spawn_id_get_pid $test_spawn_id] + # Start the test program. + set test_spawn_id [spawn_wait_for_attach $binfile] + set testpid [spawn_id_get_pid $test_spawn_id] -# Attach. -if { ![gdb_attach $testpid] } { - return + # Attach. + if { ![gdb_attach $testpid] } { + return + } + + with_test_prefix "attach" { + # Remove the pause. We no longer need it. + gdb_test "print wait_for_gdb = 0" "\\\$1 = 0" + + # Set the same breakpoints again. This time, however, we do not allow the + # breakpoint to be pending since the library has already been loaded. + gdb_breakpoint $srcfile_lib:$bp_inc + gdb_breakpoint $srcfile:$bp_main + + test_dlmopen + } } -with_test_prefix "attach" { +# Check that we can 'next' over the dlclose calls without GDB giving any +# warnings or errors. +with_test_prefix "next over dlclose" { + clean_restart $binfile + + if { ![runto_main] } { + return + } + + set dlclose_lineno [gdb_get_line_number "dlclose" $srcfile] + gdb_breakpoint $srcfile:$dlclose_lineno + gdb_breakpoint $srcfile:$bp_main + # Remove the pause. We no longer need it. gdb_test "print wait_for_gdb = 0" "\\\$1 = 0" - # Set the same breakpoints again. This time, however, we do not allow the - # breakpoint to be pending since the library has already been loaded. - gdb_breakpoint $srcfile_lib:$bp_inc - gdb_breakpoint $srcfile:$bp_main + set loc_re [multi_line \ + "\[^\r\n\]+/[string_to_regexp $srcfile]:$dlclose_lineno" \ + "$dlclose_lineno\\s+dlclose \[^\r\n\]+"] + + # This loop mirrors the loop in dlmopen.c where the inferior performs + # four calls to dlclose. Here we continue to the dlclose, and then use + # 'next' to step over the call. As part of the 'next' GDB will insert + # breakpoints to catch longjmps into the multiple copies of libc which + # have been loaded. Each dlclose call will cause a copy of libc to be + # unloaded, which should disable the longjmp breakpoint that GDB + # previously inserted. + # + # At one point a bug in GDB meant that we failed to correctly disable + # the longjmp breakpoints and GDB would try to remove the breakpoint + # from a library after it had been unloaded, which would trigger a + # warning. + for { set i 0 } { $i < 4 } { incr i } { + gdb_continue_to_breakpoint "continue to dlclose $i" $loc_re + gdb_test "next" "^$decimal\\s+for \\(dl = 0;\[^\r\n\]+\\)" \ + "next over dlclose $i" + } - test_dlmopen + # Just to confirm that we are where we think we are, continue to the + # final 'return' line in main. If this isn't hit then we likely went + # wrong earlier. + gdb_continue_to_breakpoint "continue to final return" \ + [multi_line \ + "\[^\r\n\]+/[string_to_regexp $srcfile]:$bp_main" \ + "$bp_main\\s+return 0;\[^\r\n\]+"] } From patchwork Mon Dec 9 11:18:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 102663 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 9858A3858420 for ; Mon, 9 Dec 2024 11:22:34 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9858A3858420 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=gWvAwBkL 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 ESMTP id 8D458385841D for ; Mon, 9 Dec 2024 11:18:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8D458385841D Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 8D458385841D Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1733743102; cv=none; b=HAKKqXRArToXP8FuZSaP5N3T9Yd4nSvbP0rE/9Ak+M4g6vZh9zOFw8T86rst6rFOsSOhKTr4xXq4D3lyg29tqlpxvlwumWjT74jLVrRSvZzm8H5a3Zr6ww2HP2JyGPrcTDXjAawazmLBY+r1gRrwDIpov0jIPRkhLj59rH/Z1MM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1733743102; c=relaxed/simple; bh=3C6gglOBgT5nvLLjY7fUkztodxITKlrV2yodhmX4lLQ=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=wtE8kreB9M9ohyNZK2PHs9JEV2yCg8oYU3ulqQwEk0ye3O2f5urCpkzPjioAIBmCFrKlhnA714AVq/8MEW2/zejdp5sGNiwnp2L3unk6qPa9Rdf8jSx8tfII44D+cppwnHstOSH1ZAyic6RRbBTL9zX24QqZ1pL3KCvixUsa5X8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8D458385841D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1733743101; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=jw1LLWXDpiVIKE0dwf04o0PvXtBtquOEdBBt6uxU/zM=; b=gWvAwBkLlGcuskd8SInlClzt8Oo3YwlIZ8qM4RHlxe7Jj/L75ujOGIKAYdHNdpwYtQm/D9 VCL1wCtYsTys0KXwnDxJZkFwrS0SjzhxAvz6Q+xuYknN4smOzNqtvKtDIQ8nTorkyDlVu1 O8wZbKPPXLpAjM33Vmg4QG3HcJI/srk= Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-584-vE_uVTLsOwWjYklivP5Qfw-1; Mon, 09 Dec 2024 06:18:20 -0500 X-MC-Unique: vE_uVTLsOwWjYklivP5Qfw-1 X-Mimecast-MFC-AGG-ID: vE_uVTLsOwWjYklivP5Qfw Received: by mail-wr1-f69.google.com with SMTP id ffacd0b85a97d-3862a49fbdaso1361584f8f.1 for ; Mon, 09 Dec 2024 03:18:19 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733743098; x=1734347898; 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=jw1LLWXDpiVIKE0dwf04o0PvXtBtquOEdBBt6uxU/zM=; b=cNm1JAalfvOD8taCnExvLu0H+3XDBZcZ82niEDSilRNT+gFlETuSFiCk4Ikl4jmADV ucICHXQH6UqyGzim1SDssg7vwrq1VKWCXiYbgnWeAWXUHwNHr2GGs/0pZd2XkP6pTAhW GPzwIYoTvf7Gb8Dexi/jZgz9jQSu3mWVReMrpi8SYqJnNH+p8OwdU//PH7s25xlT06vL wUk3owRKAv9YuuRBJsx9sFAcz9yhNgJeDhuenpreMWUUHC4i6iv38F6RsXQRJzMMMoxy INJ1ejrFJ1MRnfuvUEs9HFCdJCglXPG9+pi0aRjjqB5MqzU3GG+8FNiTFnFD4bItXLHY JpLw== X-Gm-Message-State: AOJu0YyjMVFZ163F6W70CLwaByPT9fL7CHkA3vH3mA/FdNd44WvihuUR HuhDvPXpEIcExrtrF6aoFsggs1V6N+ujo06BhG6UWHBlAteyNry+X5SRnUoiMf06IDY3rd+LK5e Fnrwv6qrDFD9QjUKRgc+9Gdiz2dHdNX9WjDV3A1HJxB75elXGLXfR8QqI0vnKhHKMVCDS2gGYaA c2mgClZEyXOyQTDwDRTMHjNr65MRbxAkWnVxnJ4g+RgTE= X-Gm-Gg: ASbGncslqOtk6Fi0TP9LP6E7bETHL032RgODW/BVZB7fvMoNrNSO+iFOfx5SuJUvsMO 0JqAtyoSVsQnwJULyGDlIpCpiZDRKiWykkYOT7BYz4oVDAPLM+1DysY2tFJj8n0PC0THXOXZTtj 0c9sSlJmUaZ7aeuoUGWvurDrYgwwSPFhPmmY84wmUD/e9HPD3IBzEmT7AJ7AzMfNpzJD4BOFniC emAecC66FK2WJShGeBspUOh7iHsvoz7iAxgqrZe30D3efNfw9WkILArG4g9F2H0mXs4gzCHm4jS lw== X-Received: by 2002:a05:6000:1566:b0:386:39fd:5ec with SMTP id ffacd0b85a97d-38639fd07edmr3739027f8f.57.1733743098037; Mon, 09 Dec 2024 03:18:18 -0800 (PST) X-Google-Smtp-Source: AGHT+IEAdsrbB56MVnWdzH1h3H/20ra/udQUWwkoQMtuUtuQWwgcsCfnBXTJjgBoiPMzhmuDB0wkEA== X-Received: by 2002:a05:6000:1566:b0:386:39fd:5ec with SMTP id ffacd0b85a97d-38639fd07edmr3738995f8f.57.1733743097577; Mon, 09 Dec 2024 03:18:17 -0800 (PST) Received: from localhost (197.209.200.146.dyn.plus.net. [146.200.209.197]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3861ecf4087sm13127164f8f.5.2024.12.09.03.18.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Dec 2024 03:18:17 -0800 (PST) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv5 7/7] gdb: handle empty locspec when printing breakpoints Date: Mon, 9 Dec 2024 11:18:04 +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-MFC-PROC-ID: ddZvHyW8_6KiBqKmbFbPrDVmdRa4iod9hyjzFqVshDY_1733743099 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-12.0 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.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org For background reading, please see the previous patch, and the patch before that! After the last two patches, internal breakpoints can now be marked as shlib_disabled if the library in which they are placed is unloaded. The patch before last discusses a situation related to the gdb.base/nostdlib.exp test, when run on a GNU/Linux glibc based system where executables are compiled as PIE by default. In this case it is observed that the dynamic linker will actually report itself as unloaded (i.e. remove itself from the list of currently loaded shared libraries). This behaviour is likely a bug in the dynamic linker, but this behaviour exists in released versions of the dynamic linker, so GDB should (if the cost is not too great) be changed to handle this situation. This commit handles a problem with the 'maint info breakpoints' command. When the dynamic linker is unloaded the 'shlib event' breakpoint is marked as shlib_disabled (i.e. placed into the pending state). When displaying the breakpoint in the 'maint info breakpoints' output, GDB will try to print the locspec (location_spec *) as a string Unfortunately, the locspec will be nullptr as the internal breakpoints are not created via a location_spec, this means that GDB ends up trying to call location_sepc::to_string() on a nullptr, resulting in undefined behaviour (and a crash). For most internal breakpoint types this is not a problem. If we consider bp_longjmp_master for example, if the shared library containing a breakpoint of this type is unloaded then first GDB marks the breakpoint as shlib_disabled, then after unloading the shared library breakpoint_re_set is called, which will delete the internal breakpoint, and then try to re-create it (if needed). As a result, the user never gets a change to run 'maint info breakpoints' on a bp_longjmp_master breakpoint in the shlib_disabled state. But bp_shlib_event and bp_thread_event breakpoints are not deleted and recreated like this (see internal_breakpoint::re_set), so it is possible, in rare cases, that we could end up trying to view one of these breakpoint in a shlib_disabled state, and it would be nice if GDB didn't crash as a result. I've updated the printing code to check for and handle this case, and I've updated the docs to mention this (rare) case. For testing, I've extended gdb.base/nostdlib.exp to compile as pie and nopie, and then run 'maint info breakpoints'. If we're running on a buggy glibc then this will trigger the crash. I don't know how I can trigger this problem without a buggy glibc as this would require forcing the dynamic linker to be unloaded. --- gdb/breakpoint.c | 23 +++++++++- gdb/doc/gdb.texinfo | 5 +++ gdb/testsuite/gdb.base/nostdlib.exp | 69 +++++++++++++++++++---------- 3 files changed, 72 insertions(+), 25 deletions(-) diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index c6bd6f68363..5fdfdea3f05 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -6406,7 +6406,28 @@ print_breakpoint_location (const breakpoint *b, const bp_location *loc) uiout->field_stream ("at", stb); } else - uiout->field_string ("pending", b->locspec->to_string ()); + { + /* Internal breakpoints don't have a locspec string, but can become + pending if the shared library the breakpoint is in is unloaded. + For most internal breakpoint types though, after unloading the + shared library, the breakpoint will be deleted and never recreated + (see internal_breakpoint::re_set). But for two internal + breakpoint types bp_shlib_event and bp_thread_event this is not + true. Usually we don't expect the libraries that contain these + breakpoints to ever be unloaded, but a buggy inferior might do + such a thing, in which case GDB should be prepared to handle this + case. + + If these two breakpoint types become pending then there will be no + locspec string. */ + gdb_assert (b->locspec != nullptr + || (!user_breakpoint_p (b) + && (b->type == bp_shlib_event + || b->type == bp_thread_event))); + const char *locspec_str + = (b->locspec != nullptr ? b->locspec->to_string () : ""); + uiout->field_string ("pending", locspec_str); + } if (loc && is_breakpoint (b) && breakpoint_condition_evaluation_mode () == condition_evaluation_target diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 85ac3d9aab6..ea8d6421fd6 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -32290,6 +32290,11 @@ If this breakpoint is pending, this field is present and holds the text used to set the breakpoint, as entered by the user. +@value{GDBN}'s internal breakpoints (@pxref{maint info breakpoints}) +can sometime become pending too, for these breakpoints the +@var{pending} field will be empty as @value{GDBN} automatically +creates these breakpoints as shared libraries are loaded. + @item evaluated-by Where this breakpoint's condition is evaluated, either @samp{host} or @samp{target}. diff --git a/gdb/testsuite/gdb.base/nostdlib.exp b/gdb/testsuite/gdb.base/nostdlib.exp index 906e627a068..7c32e87ebdb 100644 --- a/gdb/testsuite/gdb.base/nostdlib.exp +++ b/gdb/testsuite/gdb.base/nostdlib.exp @@ -24,33 +24,54 @@ require !use_gdb_stub # dependent on whether the system libraries are already prelinked. # prelink: Could not set /lib64/libm-2.11.1.so owner or mode: Operation not permitted set compile { - gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-nostdlib} -} -set board [target_info name] -if [board_info $board exists mathlib] { - set mathlib [board_info $dest mathlib] - set_board_info mathlib "" - set err [eval $compile] - set_board_info mathlib $mathlib -} else { - set_board_info mathlib "" - set err [eval $compile] - unset_board_info mathlib -} -if {$err != ""} { - untested "failed to compile" - return -1 + gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable $opts } -clean_restart $binfile +foreach_with_prefix pie { "nopie" "pie" } { + # OPTS and BINFILE are used by the COMPILE string (defined above) + # when it is evaluated below. + set opts [list debug additional_flags=-nostdlib $pie] + set binfile [standard_output_file $testfile-$pie] + + set board [target_info name] + if [board_info $board exists mathlib] { + set mathlib [board_info $dest mathlib] + set_board_info mathlib "" + set err [eval $compile] + set_board_info mathlib $mathlib + } else { + set_board_info mathlib "" + set err [eval $compile] + unset_board_info mathlib + } + if {$err != ""} { + untested "failed to compile" + return -1 + } -gdb_breakpoint "*marker" -gdb_breakpoint "*_start" + clean_restart $binfile -gdb_run_cmd + gdb_breakpoint "*marker" + gdb_breakpoint "*_start" -# Breakpoint 2, Stopped due to shared library event -# _start () at ./gdb.base/nostdlib.c:20 -gdb_test "" {Breakpoint [0-9]+, .*_start .*} "stop at run" + gdb_run_cmd -gdb_test "continue" {Breakpoint [0-9]+, marker .*} "continue to marker" + # Breakpoint 2, Stopped due to shared library event + # _start () at ./gdb.base/nostdlib.c:20 + gdb_test "" {Breakpoint [0-9]+, .*_start .*} "stop at run" + + gdb_test "continue" {Breakpoint [0-9]+, marker .*} "continue to marker" + + # When compiling as PIE the executable will be a dynamic + # executable, the dynamic linker performs the PIE relocation. + # Some versions of glibc would (possibly due to a bug) report the + # dynamic linker as unmapped during startup, which places the + # 'shlib event' breakpoint(s) into the PENDING state. + # + # At one point trying to print these internal breakpoints in a + # PENDING state would crash GDB, so lets make sure that doesn't + # happen now. We don't really care about the exact output, + # gdb_test will spot if running this command crashes GDB, which is + # all we're really checking for. + gdb_test "maint info breakpoints" ".*" +}