]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gdb/python: fix FinishBreakpoint.return_value for tail call functions
authorAndrew Burgess <aburgess@redhat.com>
Fri, 23 Jan 2026 09:57:24 +0000 (09:57 +0000)
committerAndrew Burgess <aburgess@redhat.com>
Thu, 5 Mar 2026 17:45:27 +0000 (17:45 +0000)
The FinishBreakpoint.return_value attribute will not be populated
correctly for tail call functions.

In bpfinishpy_init (python/py-finishbreakpoint.c) we use the function
get_frame_pc_if_available to return an address, and then use this
address to lookup a function symbol.

The problem is that, for tail call functions, the address returned by
get_frame_pc_if_available can be outside the bounds of the function,
as a result GDB might find no function symbol at all, or might find
the wrong function symbol, if the tail call function is immediately
adjacent to the next function.

Fix this by using get_frame_address_in_block_if_available instead.
For tail call functions this will return an address within the bounds
of the function, which means that GDB should find the correct function
symbol, and from this the correct return type.

I've extended the existing FinishBreakpoint with tail call test case
to include printing the return value, this test fails without this
patch, but now works.

Approved-By: Tom Tromey <tom@tromey.com>
gdb/python/py-finishbreakpoint.c
gdb/testsuite/gdb.python/py-finish-breakpoint-tailcall.exp
gdb/testsuite/gdb.python/py-finish-breakpoint-tailcall.py

index 3370bb025805277fa5e14dfbdf52de3fd9ee967d..4af8ec6c75f251a584b379cb1296f4c755cb4a3f 100644 (file)
@@ -174,7 +174,6 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
   struct frame_id frame_id;
   PyObject *internal = NULL;
   int internal_bp = 0;
-  std::optional<CORE_ADDR> pc;
 
   if (!gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "|OO", keywords,
                                        &frame_obj, &internal))
@@ -248,9 +247,10 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
 
   try
     {
-      if ((pc = get_frame_pc_if_available (frame)))
+      CORE_ADDR pc;
+      if (get_frame_address_in_block_if_available (frame, &pc))
        {
-         struct symbol *function = find_symbol_for_pc (*pc);
+         struct symbol *function = find_symbol_for_pc (pc);
          if (function != nullptr)
            {
              struct type *ret_type =
index e5b5ebc5183e090a7fdff630ed6e7f0217775dd7..2ae61f389ef6e6399230282f373b53faf59178fb 100644 (file)
@@ -66,11 +66,16 @@ proc run_test {} {
     set saw_stopped_message false
     set saw_breakpoint_line false
     set saw_source_line false
+    set saw_return_value false
     gdb_test_multiple "continue" "" {
        -re "^Stopped at MyFinishBreakpoint\r\n" {
            set saw_stopped_message true
            exp_continue
        }
+       -re "^Return value is 43\r\n" {
+           set saw_return_value true
+           exp_continue
+       }
        -re "^Breakpoint $::decimal, main \\(\\) at \[^\r\n\]+/$::srcfile:$lineno\r\n" {
            set saw_breakpoint_line true
            exp_continue
@@ -82,7 +87,8 @@ proc run_test {} {
        -re "^$::gdb_prompt $" {
            gdb_assert { $saw_stopped_message \
                             && $saw_breakpoint_line \
-                            && $saw_source_line } $gdb_test_name
+                            && $saw_source_line \
+                            && $saw_return_value } $gdb_test_name
        }
        -re "^\[^\r\n\]*\r\n" {
            exp_continue
index bd10109a3dc81a353128b52e7aabb4f7349d155b..e493dfa4017d192e439e27b36a14d679673b0747 100644 (file)
@@ -20,6 +20,7 @@ import gdb
 class MyFinishBreakpoint(gdb.FinishBreakpoint):
     def stop(self):
         print("Stopped at MyFinishBreakpoint")
+        print("Return value is {}".format(self.return_value))
         return True