PR gdb/21698: Fix synchronization problems under python interface

Message ID 1504453086-9952-1-git-send-email-Hsiangkai@gmail.com
State New, archived
Headers

Commit Message

Hsiangkai Wang Sept. 3, 2017, 3:38 p.m. UTC
  When executing multiple steppings through gdb.post_event(), prompt will
show first and current_ui->prompt_state will be changed to PROMPTED.
There is no chance to switch prompt_state to PROMPT_NEEDED or
PROMPT_BLOCK.  So, synchronous commands will behave like asynchronous
commands under gdb.post_event().  In addition, GDB will raise an
exception while checking thread state in ensure_not_running() and GDB
will hang.

I propose a solution to initialize current_ui->prompt_state to
PROMPT_NEEDED in execute_gdb_command() to ensure synchronous commands
will behave as expected.

gdb/ChangeLog
2017-09-03  Hsiangkai Wang  <hsiangkai@gmail.com>

	PR gdb/21698
	* python/python.c (execute_gdb_command): Initialize prompt_state.

testsuite/ChangeLog
2017-09-03  Hsiangkai Wang  <Hsiangkai@gmail.com>

	PR gdb/21698
	* gdb.python/python.exp: Test multiple synchronous stepping
	through gdb.post_event().
	* gdb.python/step.py: New file.
---
 gdb/ChangeLog                       |  5 +++++
 gdb/python/python.c                 |  1 +
 gdb/testsuite/ChangeLog             |  7 +++++++
 gdb/testsuite/gdb.python/python.exp | 23 +++++++++++++++++++++++
 gdb/testsuite/gdb.python/step.py    |  7 +++++++
 5 files changed, 43 insertions(+)
 create mode 100644 gdb/testsuite/gdb.python/step.py
  

Comments

Yao Qi Dec. 11, 2017, 12:06 p.m. UTC | #1
On Sun, Sep 3, 2017 at 4:38 PM, Hsiangkai Wang <Hsiangkai@gmail.com> wrote:

[This patch was not reviewed, and my Arm colleague reminds me
taking a look at this patch, because ARM embedded toolchain needs
this fix]

> When executing multiple steppings through gdb.post_event(), prompt will
> show first and current_ui->prompt_state will be changed to PROMPTED.
> There is no chance to switch prompt_state to PROMPT_NEEDED or
> PROMPT_BLOCK.  So, synchronous commands will behave like asynchronous
> commands under gdb.post_event().  In addition, GDB will raise an
> exception while checking thread state in ensure_not_running() and GDB
> will hang.
>
> I propose a solution to initialize current_ui->prompt_state to
> PROMPT_NEEDED in execute_gdb_command() to ensure synchronous commands
> will behave as expected.
>

The fix is not my area, so I took some time to understand it.
However, when I read the test below, I start to wonder whether it is a
right way to use python API gdb.post_event.

> diff --git a/gdb/testsuite/gdb.python/step.py b/gdb/testsuite/gdb.python/step.py
> new file mode 100644
> index 0000000..c8cb866
> --- /dev/null
> +++ b/gdb/testsuite/gdb.python/step.py
> @@ -0,0 +1,7 @@
> +def test_steps():
> +    for _ in range(6):
> +        gdb.execute("si")
> +
> +    print("Stepping successful.")
> +
> +gdb.post_event(test_steps)

Phil and Tom,
Is it the expected way to use this python interface?  It is quite
ambiguous to me in this case, that is, the callable is called in
event processing, but the callable has side-effect which causes
inferior running, and generating more events.
  
Hsiangkai Wang April 21, 2018, 11:06 p.m. UTC | #2
On Mon, Dec 11, 2017 at 8:06 PM, Yao Qi <qiyaoltc@gmail.com> wrote:
> On Sun, Sep 3, 2017 at 4:38 PM, Hsiangkai Wang <Hsiangkai@gmail.com> wrote:
>
> [This patch was not reviewed, and my Arm colleague reminds me
> taking a look at this patch, because ARM embedded toolchain needs
> this fix]
>
>> When executing multiple steppings through gdb.post_event(), prompt will
>> show first and current_ui->prompt_state will be changed to PROMPTED.
>> There is no chance to switch prompt_state to PROMPT_NEEDED or
>> PROMPT_BLOCK.  So, synchronous commands will behave like asynchronous
>> commands under gdb.post_event().  In addition, GDB will raise an
>> exception while checking thread state in ensure_not_running() and GDB
>> will hang.
>>
>> I propose a solution to initialize current_ui->prompt_state to
>> PROMPT_NEEDED in execute_gdb_command() to ensure synchronous commands
>> will behave as expected.
>>
>
> The fix is not my area, so I took some time to understand it.
> However, when I read the test below, I start to wonder whether it is a
> right way to use python API gdb.post_event.
>
>> diff --git a/gdb/testsuite/gdb.python/step.py b/gdb/testsuite/gdb.python/step.py
>> new file mode 100644
>> index 0000000..c8cb866
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.python/step.py
>> @@ -0,0 +1,7 @@
>> +def test_steps():
>> +    for _ in range(6):
>> +        gdb.execute("si")
>> +
>> +    print("Stepping successful.")
>> +
>> +gdb.post_event(test_steps)
>
> Phil and Tom,
> Is it the expected way to use this python interface?  It is quite
> ambiguous to me in this case, that is, the callable is called in
> event processing, but the callable has side-effect which causes
> inferior running, and generating more events.

If it is not the expected way to use post_event(), is there any
suggestions to execute multiple steps in Python scripts?
  

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 71566bd..7713b2f 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,8 @@ 
+2017-09-03  Hsiangkai Wang  <hsiangkai@gmail.com>
+
+	PR gdb/21698
+	* python/python.c (execute_gdb_command): Initialize prompt_state.
+
 2017-09-03  Simon Marchi  <simon.marchi@ericsson.com>
 
 	* target/waitstatus.h (target_waitstatus_to_string): Change
diff --git a/gdb/python/python.c b/gdb/python/python.c
index c53e10f..49b5eff 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -589,6 +589,7 @@  execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
       struct interp *interp;
 
       scoped_restore save_async = make_scoped_restore (&current_ui->async, 0);
+      current_ui->prompt_state = PROMPT_NEEDED;
 
       scoped_restore save_uiout = make_scoped_restore (&current_uiout);
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index c15743b..1c1b75b 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,10 @@ 
+2017-09-03  Hsiangkai Wang  <Hsiangkai@gmail.com>
+
+	PR gdb/21698
+	* gdb.python/python.exp: Test multiple synchronous stepping
+	through gdb.post_event().
+	* gdb.python/step.py: New file.
+
 2017-08-31  Sergio Durigan Junior  <sergiodj@redhat.com>
 
 	* gdb.base/share-env-with-gdbserver.c: New file.
diff --git a/gdb/testsuite/gdb.python/python.exp b/gdb/testsuite/gdb.python/python.exp
index de8daad..6f46786 100644
--- a/gdb/testsuite/gdb.python/python.exp
+++ b/gdb/testsuite/gdb.python/python.exp
@@ -32,6 +32,9 @@  gdb_reinitialize_dir $srcdir/$subdir
 
 set remote_source2_py [gdb_remote_download host \
 			   ${srcdir}/${subdir}/source2.py]
+set remote_step_py [gdb_remote_download host \
+			   ${srcdir}/${subdir}/step.py]
+
 
 # Do this instead of the skip_python_check.
 # We want to do some tests when Python is not present.
@@ -474,3 +477,23 @@  gdb_py_test_silent_cmd "step" "Step into func2" 1
 gdb_py_test_silent_cmd "up" "Step out of func2" 1
 
 gdb_test "python print (gdb.find_pc_line(gdb.selected_frame().pc()).line > line)" "True" "test find_pc_line with resume address"
+
+# Start with a fresh gdb.
+clean_restart ${testfile}
+
+# The following tests require execution.
+
+if ![runto_main] then {
+    fail "can't run to main"
+    return 0
+}
+
+send_gdb "source $remote_step_py\n"
+gdb_expect {
+    -re ".*${gdb_prompt}.*Stepping successful" {
+        pass "multiple stepping in python script through post_event()"
+    }
+    timeout {
+        fail "multiple stepping in python script through post_event()"
+    }
+}
diff --git a/gdb/testsuite/gdb.python/step.py b/gdb/testsuite/gdb.python/step.py
new file mode 100644
index 0000000..c8cb866
--- /dev/null
+++ b/gdb/testsuite/gdb.python/step.py
@@ -0,0 +1,7 @@ 
+def test_steps():
+    for _ in range(6):
+        gdb.execute("si")
+
+    print("Stepping successful.")
+
+gdb.post_event(test_steps)