Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Andrew Burgess <aburgess@redhat.com>
To: gdb-patches@sourceware.org
Cc: Andrew Burgess <aburgess@redhat.com>
Subject: [PATCHv2 4/4] gdb/python: fix gdb.FinishBreakpoint returning to a tail call frame
Date: Thu,  5 Mar 2026 13:37:18 +0000	[thread overview]
Message-ID: <e1e5d1247672443cc6fdf312de11007b486de053.1772717770.git.aburgess@redhat.com> (raw)
In-Reply-To: <cover.1772717769.git.aburgess@redhat.com>

I noticed that gdb.FinishBreakpoint doesn't work if the parent
function is a tail call function.  In bpfinishpy_init we use
get_frame_pc to find the address at which the finish breakpoint should
be placed within the previous frame.

However, if the previous frame is a tail call frame, then get_frame_pc
will return an address outside of the tail call function, an address
which will not be reached on the return path.

Unlike other recent tail call fixes I've made, we cannot switch to
using something like get_frame_address_in_block here as in the tail
call case this will return an address within the function, but not an
address that will be executed when we return.

What we need to do in the tail call case is create the finish
breakpoint in the frame that called the tail call function.  Or if
that frame is itself a tail call, then we should walk back up the call
stack until we find a non-tail call function.

This can be achieved by adding a call to skip_tailcall_frames into
bpfinishpy_init after our existing call to get_prev_frame.

I've extended the existing test case to cover this additional
situation.
---
 gdb/python/py-finishbreakpoint.c              |  3 ++
 .../py-finish-breakpoint-tailcall.exp         | 29 +++++++++++++++----
 2 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c
index 834f85037c0..fbbb705a864 100644
--- a/gdb/python/py-finishbreakpoint.c
+++ b/gdb/python/py-finishbreakpoint.c
@@ -201,6 +201,9 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
       else
 	{
 	  prev_frame = get_prev_frame (frame);
+	  if (prev_frame != nullptr)
+	    prev_frame = skip_tailcall_frames (prev_frame);
+
 	  if (prev_frame == nullptr)
 	    {
 	      PyErr_SetString (PyExc_ValueError,
diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint-tailcall.exp b/gdb/testsuite/gdb.python/py-finish-breakpoint-tailcall.exp
index 2ae61f389ef..6a266abd790 100644
--- a/gdb/testsuite/gdb.python/py-finish-breakpoint-tailcall.exp
+++ b/gdb/testsuite/gdb.python/py-finish-breakpoint-tailcall.exp
@@ -40,9 +40,17 @@ if {[build_executable "failed to build" $testfile $srcfile \
 # For remote host testing.
 set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py]
 
-# Run to 'normal_function' and then try to create a FinishBreakpoint
-# in the parent frame.
-proc run_test {} {
+# Run to 'normal_function' and then try to create a FinishBreakpoint.
+#
+# When USE_PARENT_FRAME_P is true we use the parent frame, which is
+# for tailcall_function, to create the FinishBreakpoint.
+#
+# When USE_PARENT_FRAME_P is false we use the frame of normal_function
+# to create the FinishBreakpoint.
+#
+# In both cases the finish breakpoint should be placed back in main,
+# which is where the inferior should stop when resumed.
+proc run_test { use_parent_frame_p } {
     clean_restart $::testfile
 
     if {![runto normal_function]} {
@@ -59,7 +67,16 @@ proc run_test {} {
     gdb_test "source $::pyfile" "Python script imported" "import python scripts"
 
     set lineno [gdb_get_line_number "Temporary breakpoint here."]
-    gdb_test "python MyFinishBreakpoint(gdb.selected_frame().older())" \
+
+    if { $use_parent_frame_p } {
+	gdb_test_no_output "python frame=gdb.selected_frame().older()" \
+	    "store a reference to the parent frame"
+    } else {
+	gdb_test_no_output "python frame=gdb.selected_frame()" \
+	    "store a reference to the current frame"
+    }
+
+    gdb_test "python MyFinishBreakpoint(frame)" \
 	"Temporary breakpoint $::decimal at $::hex: file \[^\r\n\]+/$::srcfile, line $lineno\\." \
 	"create finish breakpoint"
 
@@ -96,4 +113,6 @@ proc run_test {} {
     }
 }
 
-run_test
+foreach_with_prefix parent_frame { true false } {
+    run_test $parent_frame
+}
-- 
2.25.4


  parent reply	other threads:[~2026-03-05 13:38 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-24 11:29 [PATCH 0/4] Fixes for tail call, until, and FinishBreakpoints Andrew Burgess
2026-01-24 11:29 ` [PATCH 1/4] gdb: fix frame_unwind_caller_WHAT functions for inline and tail calls Andrew Burgess
2026-01-27 16:37   ` Andrew Burgess
2026-01-24 11:29 ` [PATCH 2/4] gdb/python: fix FinishBreakpoint.return_value for tail call functions Andrew Burgess
2026-01-24 11:29 ` [PATCH 3/4] gdb/python: don't allow FinishBreakpoints for inline frames Andrew Burgess
2026-01-24 12:23   ` Eli Zaretskii
2026-01-24 11:29 ` [PATCH 4/4] gdb/python: fix gdb.FinishBreakpoint returning to a tail call frame Andrew Burgess
2026-03-05 13:37 ` [PATCHv2 0/4] Fixes for tail call, until, and FinishBreakpoints Andrew Burgess
2026-03-05 13:37   ` [PATCHv2 1/4] gdb: fix frame_unwind_caller_WHAT functions for inline and tail calls Andrew Burgess
2026-03-05 13:37   ` [PATCHv2 2/4] gdb/python: fix FinishBreakpoint.return_value for tail call functions Andrew Burgess
2026-03-05 13:37   ` [PATCHv2 3/4] gdb/python: don't allow FinishBreakpoints for inline frames Andrew Burgess
2026-03-05 13:37   ` Andrew Burgess [this message]
2026-03-05 15:59   ` [PATCHv2 0/4] Fixes for tail call, until, and FinishBreakpoints Tom Tromey
2026-03-05 17:49     ` Andrew Burgess

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=e1e5d1247672443cc6fdf312de11007b486de053.1772717770.git.aburgess@redhat.com \
    --to=aburgess@redhat.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox