From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id CQY8BoGtdGn9wRIAWB0awg (envelope-from ) for ; Sat, 24 Jan 2026 06:31:13 -0500 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=IFUscuE5; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 0BA401E0AD; Sat, 24 Jan 2026 06:31:13 -0500 (EST) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id B92341E08D for ; Sat, 24 Jan 2026 06:31:11 -0500 (EST) Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 45D034BA9002 for ; Sat, 24 Jan 2026 11:31:11 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 45D034BA9002 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=IFUscuE5 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 E22134BA9016 for ; Sat, 24 Jan 2026 11:29:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E22134BA9016 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 E22134BA9016 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=1769254171; cv=none; b=lgZ21pTy6pEAwVHqITkusLe46xQ+P3thhc8nqSbwX10DBTpP/0odwKhumULRIp4RDaehmQTW3KDGSO9b4fWkuMls43eiV7GBFrGCgtvqUPIGXfe/TSgWn417E/s264oLKr6AkDZ1EGlff8qHfGhCWravJhOcvYzBvlPZkx6kuDc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1769254171; c=relaxed/simple; bh=Wm8B1EHazaifZr4LiqEsPbMOFbsohlOb0DBJjd8FyUU=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=ZlrgXjw/1xqcvMZalO+27ZPmfjPhtt4fbCHKpAvXRIh+V7DEPb+asBEgGpxU7G1vQvl9TzR30LNLg9CHVWLSnfOu4LGkzMG01cqcYh1KUx52/BIVtXYyERfQBuxAukdtt0dMyi6ZV60NSeW7ZqmS2IUbhGDh2mMtkRJcmlwIR2E= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E22134BA9016 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1769254170; 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=T/vKKPFRJpWmvq4GRl4OYNk1HA6Lb6elY6MMZ0ENOcQ=; b=IFUscuE5Ww90GKq5jSYHt0eJBNWLHJUPFDN5P3sE7LMUgqZbCmFL7/7Kzq7spU23gcF44j RIENZTRtL9Y8UlTa9q1uPnTUvRi9NTKSjVPkLUySHiv9Gc8KvmcvK21t8y1fHzBzxmx7AR zdtVn2T8sIlo8HofdDUdofPMMI+hSn4= 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-479-95EgiEAnNqe3QGAlj9M7Kg-1; Sat, 24 Jan 2026 06:29:29 -0500 X-MC-Unique: 95EgiEAnNqe3QGAlj9M7Kg-1 X-Mimecast-MFC-AGG-ID: 95EgiEAnNqe3QGAlj9M7Kg_1769254168 Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-4325b182e3cso2366238f8f.2 for ; Sat, 24 Jan 2026 03:29:29 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769254168; x=1769858968; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=T/vKKPFRJpWmvq4GRl4OYNk1HA6Lb6elY6MMZ0ENOcQ=; b=WZ+UBLsd5AwyE7wjLhYwPvmV6h4tFZBv+m+O5JozczqTEzVXKFZaHdi7hg7irXb8tw gvwdIHlyH40EbRC8tPQPtVa/bZfdzrizs0enZsQ6hlhYFWvSupPgvzb46AihRPsooauI FUQRP7KGUM3a5yjX3GqcUbHhLpYlshtQG/DTRnyEBwtU1glKIH4IJ1xRqfyG19zH6f3C k0WBwYeyp2UQOm8ushMJrrDqg0ts4+5TdBygZtj4CQ5ezmmkpw1GqkvJUoM0O1tGjVv2 s/GnvMq2P7cAMlXxrKHCJvEMsWs7S4yeZ14ysFYAQf3RLsEH5bm0K0Fe2/EjF3Bvpg/U Ug7A== X-Gm-Message-State: AOJu0YwnwBzpbUzDsLlt6HZ7MeucYmbKSfYB78szuT18+y2HNDiC70P6 EMOfISbOmHt1XHrZx5SeDbRQFPRtXd4kdaD/M10LSn+8iyXZXUM0sicsPGBXcZJIsX8+nsViaOM R7Zp9rP5Mk8oZ1RVbn+/JaXfBpe82z/2FL/lgyq3lvgB9m/jFZqEa7lBv4njwzkO6MjyYAbGjmk rGukYlOIwGx/4MBoGrb16sRTqI/p182sDbKT56ZiaeRrKytko= X-Gm-Gg: AZuq6aIuelBLRS4Y3YeWTpNJx6xhYNHAKqMVUBqJQR5sCQB3lO9tZlsEZZFScLrp+u0 wa6Xo1Fgp1kuScvvb9dmZ/rUkfCMEF6QGmiojvTy/yS706rybs0LnwzzjHvC+AbrRkyvFmbFOmA Vj9oPzrkmsOuqier2xDBhvOI5WK0JRVgTs3YwxRE5JOvXcdF8gjvleTPhWWA2SXAaoxUS1sdIty XkTnSe7ofQkuNi5vTBQroh8XaQTrhKFQl++lSEXPw9sZVRSZ+sXAG6zAbTwGK3eje87UXlX4er5 KlaHjWALYobkuCYzh4l3xRSLclZ02oDri5Eo6HaRaJ9QQU8bcV9cO8utLOc8VYa4ZwuGqa21jqh zpvxH80DKKQe6+Hpy2SOMYd7X/YDWTUg= X-Received: by 2002:a05:6000:290d:b0:435:ad51:ac89 with SMTP id ffacd0b85a97d-435b15d6ea8mr11418336f8f.20.1769254167518; Sat, 24 Jan 2026 03:29:27 -0800 (PST) X-Received: by 2002:a05:6000:290d:b0:435:ad51:ac89 with SMTP id ffacd0b85a97d-435b15d6ea8mr11418301f8f.20.1769254166846; Sat, 24 Jan 2026 03:29:26 -0800 (PST) Received: from localhost (92.40.184.43.threembb.co.uk. [92.40.184.43]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-435b1f74b15sm14180924f8f.35.2026.01.24.03.29.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 24 Jan 2026 03:29:26 -0800 (PST) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCH 3/4] gdb/python: don't allow FinishBreakpoints for inline frames Date: Sat, 24 Jan 2026 11:29:13 +0000 Message-Id: <37a173304a79718a39b3ca5d4e3fa51dab6fa835.1769253423.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: zVGZy8QuJlpZc7szla5VA3mbV33smboPJXl28pNYGtA_1769254168 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true 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~public-inbox=simark.ca@sourceware.org Creating a Python gdb.FinishBreakpoint for an inline frame doesn't work. If we look at the 'finish' command, in the finish_command function (infcmd.c) then we see that GDB handles inline frames very different to non-inline frames. For non-inline frames GDB creates a temporary breakpoint and then resumes the inferior until the breakpoint is hit. But for inline frames, GDB steps forward until we have left the inline frame. When it comes to gdb.FinishBreakpoint we only have the "create a temporary breakpoint" mechanism; that is, after all, what the FinishBreakpoint is, it's a temporary breakpoint placed at the return address in the caller. Currently, when a FinishBreakpoint is created within an inline frame, GDB ends up creating the breakpoint at the current $pc. As a result the breakpoint will not be hit before the current function exits (unless there's a loop going on, but that's not the point). We could imagine what a solution to this problem would look like, GDB would need to figure out the set of addresses for all possible exit points from the inline function, and place a breakpoint at each of these locations. I don't propose doing that in this commit. Instead, I plan to update the docs to note that creating a FinishBreakpoint within an inline frame is not allowed, and I will catch this case within bpfinishpy_init (python/py-finishbreakpoint.c) and throw an error. Though the error is new, all I'm doing is raising an error for a case that never worked. There's a new test to cover this case. --- gdb/doc/python.texi | 3 + gdb/python/py-finishbreakpoint.c | 8 +- .../gdb.python/py-finish-breakpoint-inline.c | 58 +++++++ .../py-finish-breakpoint-inline.exp | 147 ++++++++++++++++++ .../gdb.python/py-finish-breakpoint-inline.py | 27 ++++ 5 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 gdb/testsuite/gdb.python/py-finish-breakpoint-inline.c create mode 100644 gdb/testsuite/gdb.python/py-finish-breakpoint-inline.exp create mode 100644 gdb/testsuite/gdb.python/py-finish-breakpoint-inline.py diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index 1f88ea7e9ad..eccb7e523c7 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -7221,6 +7221,9 @@ Finish Breakpoints in Python Finish breakpoints are thread specific and must be create with the right thread selected. +It is not possible to create a @code{gdb.FinishBreakpoint} for an +inline frame (@pxref{Inline Functions}). + @defun FinishBreakpoint.__init__ (@r{[}frame@r{]} @r{[}, internal@r{]}) Create a finish breakpoint at the return address of the @code{gdb.Frame} object @var{frame}. If @var{frame} is not provided, this defaults to the diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c index 84d2abeb433..84d55c470a2 100644 --- a/gdb/python/py-finishbreakpoint.c +++ b/gdb/python/py-finishbreakpoint.c @@ -192,10 +192,16 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs) PyErr_SetString (PyExc_ValueError, _("Invalid ID for the `frame' object.")); } + else if (get_frame_type (frame) == INLINE_FRAME) + { + PyErr_SetString + (PyExc_ValueError, + _("Unable to create FinishBreakpoint for inline frame.")); + } else { prev_frame = get_prev_frame (frame); - if (prev_frame == 0) + if (prev_frame == nullptr) { PyErr_SetString (PyExc_ValueError, _("\"FinishBreakpoint\" not " diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint-inline.c b/gdb/testsuite/gdb.python/py-finish-breakpoint-inline.c new file mode 100644 index 00000000000..c955917a873 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint-inline.c @@ -0,0 +1,58 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2026 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 . */ + +/* Global used to create filler code within functions. */ +volatile int global_var = 1; + +static int __attribute__ ((noinline, noclone)) +baz (int arg) +{ + arg += global_var; + return arg; +} + +static inline int __attribute__ ((__always_inline__)) +bar (int arg) +{ + arg += global_var; + arg = baz (arg); /* Finish location. */ + arg -= global_var; + return arg; +} + +static inline int __attribute__ ((__always_inline__)) +foo (int arg) +{ + arg += global_var; + arg = bar (arg); + arg -= global_var; + return arg; +} + +int +main (void) +{ + int ans; + + ++global_var; + ++global_var; + ans = foo (42); + ++global_var; + ++global_var; + ans += global_var; + return ans; /* Final breakpoint. */ +} diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint-inline.exp b/gdb/testsuite/gdb.python/py-finish-breakpoint-inline.exp new file mode 100644 index 00000000000..d1c3f3de8f0 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint-inline.exp @@ -0,0 +1,147 @@ +# Copyright (C) 2026 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Check that attempting to create a FinishBreakpoint within an inline +# function will fail. +# +# For inline functions the 'finish' command steps forward until we are +# outside the inline function. +# +# For FinishBreakpoints though we need to pick an address an place a +# breakpoint there. Currently GDB doesn't know where to place such a +# breakpoint for an inline function, so our solution is to prevent +# creation of FinishBreakpoints for inline frames. + +load_lib gdb-python.exp + +require allow_python_tests + +standard_testfile + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile]} { + return +} + +if {![runto_main]} { + return +} + +# Source the Python script. +set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] +gdb_test "source $pyfile" "Python script imported" "import python scripts" + +# Breakpoint locations needed for this test. +gdb_breakpoint foo +gdb_breakpoint bar +gdb_breakpoint baz +set final_lineno [gdb_get_line_number "Final breakpoint."] +gdb_breakpoint $final_lineno + +# Depending on how the code is compiled, and exactly where the finish +# breakpoint is placed, the breakpoint could potentially be reported +# on either of these lines. +set lineno_1 [gdb_get_line_number "Finish location."] +set lineno_2 [expr {$lineno_1 + 1}] +set lineno_re "(?:$lineno_1|$lineno_2)" + +# Run to 'foo', which is an inline function called from a normal +# function, and try to create a MyFinishBreakpoint. This should fail. +gdb_continue_to_breakpoint "breakpoint in foo" +gdb_test "python MyFinishBreakpoint(gdb.selected_frame())" \ + "Error occurred in Python: Unable to create FinishBreakpoint for inline frame\\." \ + "try to create FinishBreakpoint for inline frame, caller is a normal frame" + +# Continue to 'bar', which is an inline function called from another +# inline function, and try to create a MyFinishBreakpoint. This +# should fail. +gdb_continue_to_breakpoint "breakpoint in bar" +gdb_test "python MyFinishBreakpoint(gdb.selected_frame())" \ + "Error occurred in Python: Unable to create FinishBreakpoint for inline frame\\." \ + "try to create FinishBreakpoint for inline frame, caller is an inline frame" + +# Continue to 'baz', which is a normal function called from an inline +# function, and create a MyFinishBreakpoint, which we expect to succeed. +gdb_continue_to_breakpoint "breakpoint in baz" +gdb_test "python MyFinishBreakpoint(gdb.selected_frame())" \ + "Temporary breakpoint $decimal at $hex: file \[^\r\n\]+/$srcfile, line $lineno_re\\." \ + "create FinishBreakpoint normal function, caller is an inline frame" + +# Continue and make sure we hit the MyFinishBreakpoint. +set saw_finish_breakpoint false +set saw_return_value false +set saw_breakpoint_location false +set saw_source_line false +gdb_test_multiple "continue" "continue to finish breakpoint" { + -re "^Stopped at MyFinishBreakpoint\r\n" { + set saw_finish_breakpoint true + exp_continue + } + -re "^Return value is 51\r\n" { + set saw_return_value true + exp_continue + } + -re "^Breakpoint $decimal, ($hex in )?bar \\(arg=$decimal\\) at \[^\r\n\]+/$srcfile:$lineno_re\r\n" { + set saw_breakpoint_location true + exp_continue + } + -re "^$lineno_re\\s+\[^\r\n\]+\r\n" { + set saw_source_line true + exp_continue + } + -re "^$gdb_prompt $" { + gdb_assert {$saw_finish_breakpoint \ + && $saw_return_value \ + && $saw_breakpoint_location \ + && $saw_source_line } $gdb_test_name + } + -re "^\[^\r\n\]*\r\n" { + exp_continue + } +} + +# Continue to the final breakpoint location. We don't expect to see +# any of the MyFinishBreakpoint output here. If we do then we've hit +# an unexpected FinishBreakpoint. +set saw_finish_breakpoint false +set saw_return_value false +set saw_breakpoint_location false +set saw_source_line false +gdb_test_multiple "continue" "continue to final breakpoint" { + -re "^Stopped at MyFinishBreakpoint\r\n" { + set saw_finish_breakpoint true + exp_continue + } + -re "^Return value is 51\r\n" { + set saw_return_value true + exp_continue + } + -re "^Breakpoint $decimal, main \\(\\) at \[^\r\n\]+/$srcfile:$final_lineno\r\n" { + set saw_breakpoint_location true + exp_continue + } + -re "^$final_lineno\\s+\[^\r\n\]+\r\n" { + set saw_source_line true + exp_continue + } + -re "^$gdb_prompt $" { + gdb_assert {!$saw_finish_breakpoint \ + && !$saw_return_value \ + && $saw_breakpoint_location \ + && $saw_source_line } $gdb_test_name + } + -re "^\[^\r\n\]*\r\n" { + exp_continue + } +} diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint-inline.py b/gdb/testsuite/gdb.python/py-finish-breakpoint-inline.py new file mode 100644 index 00000000000..e493dfa4017 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint-inline.py @@ -0,0 +1,27 @@ +# Copyright (C) 2026 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 . + + +import gdb + + +class MyFinishBreakpoint(gdb.FinishBreakpoint): + def stop(self): + print("Stopped at MyFinishBreakpoint") + print("Return value is {}".format(self.return_value)) + return True + + +print("Python script imported") -- 2.25.4