From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 8BBFC385023D for ; Wed, 13 Jul 2022 10:46:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 8BBFC385023D 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.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-187-aFsQZJcaNgewpTD4djWcqQ-1; Wed, 13 Jul 2022 06:46:13 -0400 X-MC-Unique: aFsQZJcaNgewpTD4djWcqQ-1 Received: by mail-wr1-f70.google.com with SMTP id k26-20020adfb35a000000b0021d6c3b9363so2002163wrd.1 for ; Wed, 13 Jul 2022 03:46:13 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:in-reply-to:references:date :message-id:mime-version; bh=yISVdIV88mCNCRgk8sIcVLKDIPtw5nXJF0Eq1+NwnWc=; b=n5Z+xQQY340BfTb2X+24RZ8gUqQsCrDHfxHMTPdG3v8jAwWrr0vtNQp+rnePkqivnM EW6xNi+rymLnJ9ptA0wHbft2Q/xMi5BayH+2NnLmzKJ95Be8n/wYfBtpbVpELDBDFpzj x68v3RKCAEySKgnCX5s940N+a+eXMSsl39pZGq9+eZmKy00OwTPoDpZX7Un6i9OhdOAS F6OSqFWBprVbigx+cv3utrAbxH06roPxu4cV+hAp2rfiGno9yO2TJyAjpFEXQG1s4NiU z26AWiBmCtozNP+A4Z1Mwd5gLUN1/8dPvwk99x6Fp7tx5Y5cY6NicTPgRN1DYUNxCoGY frPA== X-Gm-Message-State: AJIora8tiJ8PJgy9TzQfYbGGsIoccJo43n5jRq/CKvx4Qe+HJjyCSOch OgHnRlhH97iAprGcjOzVM8JfDa6xGkNtd/jxL1KGbHu71FA37fSNolVMts45af7KQ5kEZidy4tO ykqO6LTYWxS4DCbzKW4dMwA== X-Received: by 2002:a5d:6d84:0:b0:21d:a7c7:d44a with SMTP id l4-20020a5d6d84000000b0021da7c7d44amr2747282wrs.710.1657709171673; Wed, 13 Jul 2022 03:46:11 -0700 (PDT) X-Google-Smtp-Source: AGRyM1teOkAzb+q1ay+tVhFwFs4njXSMB9hJWZlr2HyKYSLIFOzWGUny95mclh01q7aD0D9781OQPQ== X-Received: by 2002:a5d:6d84:0:b0:21d:a7c7:d44a with SMTP id l4-20020a5d6d84000000b0021da7c7d44amr2747256wrs.710.1657709171410; Wed, 13 Jul 2022 03:46:11 -0700 (PDT) Received: from localhost (15.72.115.87.dyn.plus.net. [87.115.72.15]) by smtp.gmail.com with ESMTPSA id r10-20020a05600c35ca00b003a2e5296befsm1829179wmq.32.2022.07.13.03.46.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 13 Jul 2022 03:46:10 -0700 (PDT) From: Andrew Burgess To: Pedro Alves , gdb-patches@sourceware.org Subject: Re: [PATCH] Fix "until LINE" in main, when "until" runs into longjmp In-Reply-To: <20220713100133.3879810-1-pedro@palves.net> References: <20220713100133.3879810-1-pedro@palves.net> Date: Wed, 13 Jul 2022 11:46:10 +0100 Message-ID: <87o7xts32l.fsf@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain X-Spam-Status: No, score=-10.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 13 Jul 2022 10:46:16 -0000 Pedro Alves writes: > With a test like this: > > 1 #include > 2 int > 3 main () > 4 { > 5 dlsym (RTLD_DEFAULT, "FOO"); > 6 return 0; > 7 } > > and then "start" followed by "until 6", GDB currently incorrectly > stops inside the runtime loader, instead of line 6. Vis: > > ... > Temporary breakpoint 1, main () at until.c:5 > 4 { > (gdb) until 6 > 0x00007ffff7f0a90d in __GI__dl_catch_exception (exception=exception@entry=0x7fffffffdb00, operate=, args=0x7ffff7f0a90d <__GI__dl_catch_exception+109>) at dl-error-skeleton.c:206 > 206 dl-error-skeleton.c: No such file or directory. > (gdb) > > The problem is related to longjmp handling -- dlsym internally > longjmps on error. The testcase can be reduced to this: > > 1 #include > 2 void func () { > 3 jmp_buf buf; > 4 if (setjmp (buf) == 0) > 5 longjmp (buf, 1); > 6 } > 7 > 8 int main () { > 9 func (); > 10 return 0; /* until to here */ > 11 } > > and then with "start" followed by "until 10", GDB currently > incorrectly stops at line 4 (returning from setjmp), instead of line > 10. > > The problem is that the BPSTAT_WHAT_CLEAR_LONGJMP_RESUME code in > infrun.c fails to find the initiating frame, and so infrun thinks that > the longjmp jumped somewhere outer to "until"'s originating frame. > > Here: > > case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME: > { > struct frame_info *init_frame; > > /* There are several cases to consider. > > 1. The initiating frame no longer exists. In this case we > must stop, because the exception or longjmp has gone too > far. > > ... > > init_frame = frame_find_by_id (ecs->event_thread->initiating_frame); > > if (init_frame) // this is NULL! > { > ... > } > > /* For Cases 1 and 2, remove the step-resume breakpoint, if it > exists. */ > delete_step_resume_breakpoint (ecs->event_thread); > > end_stepping_range (ecs); // case 1., so we stop. > } > > The initiating frame is set by until_break_command -> > set_longjmp_breakpoint. The initiating frame is supposed to be the > frame that is selected when the command was issued, but > until_break_command instead passes the frame id of the _caller_ frame > by mistake. When the "until LINE" command is issued from main, the > caller frame is the caller of main. When later infrun tries to find > that frame by id, it fails to find it, because frame_find_by_id > doesn't unwind past main. > > The bug is that we passed the caller frame's id to > set_longjmp_breakpoint. We should have passed the selected frame's id > instead. LGTM. Thanks, Andrew > > Change-Id: Iaae1af7cdddf296b7c5af82c3b5b7d9b66755b1c > --- > gdb/breakpoint.c | 2 +- > .../gdb.base/longjmp-until-in-main.c | 34 ++++++++++++++ > .../gdb.base/longjmp-until-in-main.exp | 44 +++++++++++++++++++ > 3 files changed, 79 insertions(+), 1 deletion(-) > create mode 100644 gdb/testsuite/gdb.base/longjmp-until-in-main.c > create mode 100644 gdb/testsuite/gdb.base/longjmp-until-in-main.exp > > diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c > index a3be12557f6..74f53368464 100644 > --- a/gdb/breakpoint.c > +++ b/gdb/breakpoint.c > @@ -10489,7 +10489,7 @@ until_break_command (const char *arg, int from_tty, int anywhere) > caller_frame_id, bp_until); > breakpoints.emplace_back (std::move (caller_breakpoint)); > > - set_longjmp_breakpoint (tp, caller_frame_id); > + set_longjmp_breakpoint (tp, stack_frame_id); > lj_deleter.emplace (thread); > } > > diff --git a/gdb/testsuite/gdb.base/longjmp-until-in-main.c b/gdb/testsuite/gdb.base/longjmp-until-in-main.c > new file mode 100644 > index 00000000000..3b9ef945a34 > --- /dev/null > +++ b/gdb/testsuite/gdb.base/longjmp-until-in-main.c > @@ -0,0 +1,34 @@ > +/* This testcase is part of GDB, the GNU debugger. > + > + Copyright 2022 Free Software Foundation, Inc. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see . */ > + > +#include > + > +void > +func () > +{ > + jmp_buf buf; > + > + if (setjmp (buf) == 0) > + longjmp (buf, 1); > +} > + > +int > +main () > +{ > + func (); > + return 0; /* until to here */ > +} > diff --git a/gdb/testsuite/gdb.base/longjmp-until-in-main.exp b/gdb/testsuite/gdb.base/longjmp-until-in-main.exp > new file mode 100644 > index 00000000000..33a907fb83e > --- /dev/null > +++ b/gdb/testsuite/gdb.base/longjmp-until-in-main.exp > @@ -0,0 +1,44 @@ > +# Copyright 2008-2022 Free Software Foundation, Inc. > + > +# This program is free software; you can redistribute it and/or modify > +# it under the terms of the GNU General Public License as published by > +# the Free Software Foundation; either version 3 of the License, or > +# (at your option) any later version. > +# > +# This program is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +# GNU General Public License for more details. > +# > +# You should have received a copy of the GNU General Public License > +# along with this program. If not, see . > + > +# Test "until LINE", started in the "main()" frame, where the until > +# command runs into a longjmp that lands in a frame that is inner than > +# main. GDB internally intercepts the longjmp, sets a breakpoint at > +# the jump destination, and once there, decides whether to stop or > +# ignore the breakpoint hit depending on whether the initiating frame > +# is present on the frame chain. GDB used to have a bug where it > +# recorded the frame of the caller of main instead of the frame of > +# main as the initiating frame, and then later on when deciding > +# whether the longjmp landed somewhere inner than main, since > +# unwinding normally stops at main, GDB would fail to find the > +# initiating frame. > + > +standard_testfile > + > +if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile}]} { > + return > +} > + > +if {![runto_main]} { > + return > +} > + > +delete_breakpoints > + > +set until_to_line [gdb_get_line_number "until to here"] > + > +gdb_test "until $until_to_line" \ > + " until to here .*" \ > + "until \$line, in main" > > base-commit: dd4c046506cd4da46b439a2b4f8b6d933ecbb961 > -- > 2.36.0