Fix gdb.FinishBreakpoint when returning to an inlined function

Message ID 20231211181438.2851-1-ssbssa@yahoo.de
State New
Headers
Series Fix gdb.FinishBreakpoint when returning to an inlined function |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Testing passed

Commit Message

Hannes Domani Dec. 11, 2023, 6:14 p.m. UTC
  Currently, when creating a gdb.FinishBreakpoint in a function
called from an inline frame, it will never be hit:
```
(gdb) py fb=gdb.FinishBreakpoint()
Temporary breakpoint 1 at 0x13f1917b4: file C:/src/repos/binutils-gdb.git/gdb/testsuite/gdb.python/py-finish-breakpoint.c, line 47.
(gdb) c
Continuing.
Thread-specific breakpoint 1 deleted - thread 1 no longer in the thread list.
[Inferior 1 (process 1208) exited normally]
```

The reason is that the frame_id of a breakpoint has to be the
ID of a real frame, ignoring any inline frames.

With this fixed, it's working correctly:
```
(gdb) py fb=gdb.FinishBreakpoint()
Temporary breakpoint 1 at 0x13f5617b4: file C:/src/repos/binutils-gdb.git/gdb/testsuite/gdb.python/py-finish-breakpoint.c, line 47.
(gdb) c
Continuing.

Breakpoint 1, increase_inlined (a=0x40fa5c) at C:/src/repos/binutils-gdb.git/gdb/testsuite/gdb.python/py-finish-breakpoint.c:47
(gdb) py print(fb.return_value)
-8
```
---
 gdb/python/py-finishbreakpoint.c              |  3 ++-
 .../gdb.python/py-finish-breakpoint.c         | 14 +++++++++++
 .../gdb.python/py-finish-breakpoint.exp       | 25 +++++++++++++++++++
 3 files changed, 41 insertions(+), 1 deletion(-)
  

Comments

Tom Tromey Dec. 11, 2023, 8:26 p.m. UTC | #1
>>>>> "Hannes" == Hannes Domani <ssbssa@yahoo.de> writes:

Hannes> Currently, when creating a gdb.FinishBreakpoint in a function
Hannes> called from an inline frame, it will never be hit:

Hannes> ```
Hannes> (gdb) py fb=gdb.FinishBreakpoint()
Hannes> Temporary breakpoint 1 at 0x13f1917b4: file C:/src/repos/binutils-gdb.git/gdb/testsuite/gdb.python/py-finish-breakpoint.c, line 47.
Hannes> (gdb) c
Hannes> Continuing.
Hannes> Thread-specific breakpoint 1 deleted - thread 1 no longer in the thread list.
Hannes> [Inferior 1 (process 1208) exited normally]
Hannes> ```


Hannes> The reason is that the frame_id of a breakpoint has to be the
Hannes> ID of a real frame, ignoring any inline frames.

Hannes> With this fixed, it's working correctly:

Thank you, I think this is ok.

Approved-By: Tom Tromey <tom@tromey.com>

Tom
  
Hannes Domani Dec. 12, 2023, 2:59 p.m. UTC | #2
Am Montag, 11. Dezember 2023, 21:26:15 MEZ hat Tom Tromey <tom@tromey.com> Folgendes geschrieben:

> >>>>> "Hannes" == Hannes Domani <ssbssa@yahoo.de> writes:
>
> Hannes> Currently, when creating a gdb.FinishBreakpoint in a function
> Hannes> called from an inline frame, it will never be hit:
>
> Hannes> ```
> Hannes> (gdb) py fb=gdb.FinishBreakpoint()
> Hannes> Temporary breakpoint 1 at 0x13f1917b4: file C:/src/repos/binutils-gdb.git/gdb/testsuite/gdb.python/py-finish-breakpoint.c, line 47.
> Hannes> (gdb) c
> Hannes> Continuing.
> Hannes> Thread-specific breakpoint 1 deleted - thread 1 no longer in the thread list.
> Hannes> [Inferior 1 (process 1208) exited normally]
> Hannes> ```
>
>
> Hannes> The reason is that the frame_id of a breakpoint has to be the
> Hannes> ID of a real frame, ignoring any inline frames.
>
> Hannes> With this fixed, it's working correctly:
>
> Thank you, I think this is ok.
>
> Approved-By: Tom Tromey <tom@tromey.com>

Pushed, thanks.
  

Patch

diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c
index 627eb297542..7f3658decb3 100644
--- a/gdb/python/py-finishbreakpoint.c
+++ b/gdb/python/py-finishbreakpoint.c
@@ -212,7 +212,8 @@  bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
 				 "be set on a dummy frame."));
 	    }
 	  else
-	    frame_id = get_frame_id (prev_frame);
+	    /* Get the real calling frame ID, ignoring inline frames.  */
+	    frame_id = frame_unwind_caller_id (frame);
 	}
     }
   catch (const gdb_exception &except)
diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint.c b/gdb/testsuite/gdb.python/py-finish-breakpoint.c
index 4ae2d1889cd..76552a64b16 100644
--- a/gdb/testsuite/gdb.python/py-finish-breakpoint.c
+++ b/gdb/testsuite/gdb.python/py-finish-breakpoint.c
@@ -34,6 +34,19 @@  void increase (int *a)
   increase_1 (a);
 }
 
+int increase_2 (int *a)
+{
+  *a += 10;
+  return -8;
+}
+
+inline void __attribute__((always_inline))
+increase_inlined (int *a)
+{
+  increase_2 (a);
+  *a += 5;
+}
+
 int
 test_1 (int i, int j)
 {
@@ -85,6 +98,7 @@  int main (int argc, char *argv[])
   increase (&i);
   increase (&i);
   increase (&i);
+  increase_inlined (&i);
 
   for (i = 0; i < 10; i++)
     {
diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint.exp b/gdb/testsuite/gdb.python/py-finish-breakpoint.exp
index e5a46874afd..a6efd241e31 100644
--- a/gdb/testsuite/gdb.python/py-finish-breakpoint.exp
+++ b/gdb/testsuite/gdb.python/py-finish-breakpoint.exp
@@ -85,6 +85,31 @@  with_test_prefix "normal conditions" {
 	"check FinishBP not allowed in main"
 }
 
+#
+# Test FinishBreakpoint returning to an inlined function
+#
+
+with_test_prefix "return to inlined function" {
+    clean_restart ${testfile}
+    gdb_load_shlib ${lib_sl}
+
+    gdb_test "source $python_file" "Python script imported.*" \
+	"import python scripts"
+
+    if {![runto_main]} {
+	return 0
+    }
+
+    gdb_breakpoint "increase_2"
+    gdb_test "continue" "Breakpoint .*at.*" "continue to the function to finish"
+
+    gdb_test "python finishbp_inline = MyFinishBreakpoint (gdb.parse_and_eval ('a'), gdb.newest_frame ())" \
+	"Temporary breakpoint.*" "set FinishBreakpoint returning to inlined frame"
+    gdb_test "continue" "MyFinishBreakpoint stop with.*return_value is: -8.*#0.*increase_inlined.*" \
+	"check MyFinishBreakpoint hit"
+    gdb_test "python print (finishbp_inline.return_value)" "-8.*" "check return_value"
+}
+
 #
 # Test FinishBreakpoint with no debug symbol 
 #