[v2] python: Use console format for output of gdb.execute command

Message ID 1459420984-6582-1-git-send-email-catalin.udma@freescale.com
State New, archived
Headers

Commit Message

Catalin Udma March 31, 2016, 10:43 a.m. UTC
  When gdb is started in MI mode, the output of gdb.execute
command is in MI-format in case when it is executed from python stop
handler while for all other cases the output is in console-format.

To assure consistent output format, this is fixed by using the console
format for all python gdb command executions.

PR python/19743

gdb/ChangeLog:
2016-03-31  Catalin Udma  <catalin.udma@freescale.com>

	PR python/19743
	* python/python.c (execute_gdb_command): Use console uiout
	when executing gdb command.
	* utils.c (restore_ui_out_closure): New structure.
	(do_restore_ui_out): New function.
	(make_cleanup_restore_ui_out): Likewise.
	* utils.h (make_cleanup_restore_ui_out): Declare.

gdb/testsuite/ChangeLog:
2016-03-31  Catalin Udma  <catalin.udma@freescale.com>

	PR python/19743
	* gdb.python/py-mi-events-gdb.py: New file.
	* gdb.python/py-mi-events.c: New file.
	* gdb.python/py-mi-events.exp: New file.

Signed-off-by: Catalin Udma <catalin.udma@freescale.com>
---

Changes for v2:
  * add a cleanup restore for struct ui_out
  * restore current_ui_out with a cleanup
  * test python file: use assert for both stop and continue handlers
  * don't use test that runs forever

 gdb/python/python.c                          |    7 ++
 gdb/testsuite/gdb.python/py-mi-events-gdb.py |   48 +++++++++++++++
 gdb/testsuite/gdb.python/py-mi-events.c      |   26 ++++++++
 gdb/testsuite/gdb.python/py-mi-events.exp    |   84 ++++++++++++++++++++++++++
 gdb/utils.c                                  |   29 +++++++++
 gdb/utils.h                                  |    3 +
 6 files changed, 197 insertions(+), 0 deletions(-)
 create mode 100644 gdb/testsuite/gdb.python/py-mi-events-gdb.py
 create mode 100644 gdb/testsuite/gdb.python/py-mi-events.c
 create mode 100644 gdb/testsuite/gdb.python/py-mi-events.exp
  

Comments

Pedro Alves March 31, 2016, noon UTC | #1
On 03/31/2016 11:43 AM, Catalin Udma wrote:
> When gdb is started in MI mode, the output of gdb.execute
> command is in MI-format in case when it is executed from python stop
> handler while for all other cases the output is in console-format.
> 
> To assure consistent output format, this is fixed by using the console
> format for all python gdb command executions.
> 
> PR python/19743
> 
> gdb/ChangeLog:
> 2016-03-31  Catalin Udma  <catalin.udma@freescale.com>
> 
> 	PR python/19743
> 	* python/python.c (execute_gdb_command): Use console uiout
> 	when executing gdb command.
> 	* utils.c (restore_ui_out_closure): New structure.
> 	(do_restore_ui_out): New function.
> 	(make_cleanup_restore_ui_out): Likewise.
> 	* utils.h (make_cleanup_restore_ui_out): Declare.
> 
> gdb/testsuite/ChangeLog:
> 2016-03-31  Catalin Udma  <catalin.udma@freescale.com>
> 
> 	PR python/19743
> 	* gdb.python/py-mi-events-gdb.py: New file.
> 	* gdb.python/py-mi-events.c: New file.
> 	* gdb.python/py-mi-events.exp: New file.
> 
> Signed-off-by: Catalin Udma <catalin.udma@freescale.com>
> ---
> 
> Changes for v2:
>   * add a cleanup restore for struct ui_out
>   * restore current_ui_out with a cleanup
>   * test python file: use assert for both stop and continue handlers
>   * don't use test that runs forever

OK.

Thanks,
Pedro Alves
  
Simon Marchi April 4, 2016, 10:05 p.m. UTC | #2
On 16-03-31 06:43 AM, Catalin Udma wrote:
> When gdb is started in MI mode, the output of gdb.execute
> command is in MI-format in case when it is executed from python stop
> handler while for all other cases the output is in console-format.
> 
> To assure consistent output format, this is fixed by using the console
> format for all python gdb command executions.
> 
> PR python/19743
> 
> gdb/ChangeLog:
> 2016-03-31  Catalin Udma  <catalin.udma@freescale.com>
> 
> 	PR python/19743
> 	* python/python.c (execute_gdb_command): Use console uiout
> 	when executing gdb command.
> 	* utils.c (restore_ui_out_closure): New structure.
> 	(do_restore_ui_out): New function.
> 	(make_cleanup_restore_ui_out): Likewise.
> 	* utils.h (make_cleanup_restore_ui_out): Declare.
> 
> gdb/testsuite/ChangeLog:
> 2016-03-31  Catalin Udma  <catalin.udma@freescale.com>
> 
> 	PR python/19743
> 	* gdb.python/py-mi-events-gdb.py: New file.
> 	* gdb.python/py-mi-events.c: New file.
> 	* gdb.python/py-mi-events.exp: New file.
> 
> Signed-off-by: Catalin Udma <catalin.udma@freescale.com>
> ---
> 
> Changes for v2:
>   * add a cleanup restore for struct ui_out
>   * restore current_ui_out with a cleanup
>   * test python file: use assert for both stop and continue handlers
>   * don't use test that runs forever
> 
>  gdb/python/python.c                          |    7 ++
>  gdb/testsuite/gdb.python/py-mi-events-gdb.py |   48 +++++++++++++++
>  gdb/testsuite/gdb.python/py-mi-events.c      |   26 ++++++++
>  gdb/testsuite/gdb.python/py-mi-events.exp    |   84 ++++++++++++++++++++++++++
>  gdb/utils.c                                  |   29 +++++++++
>  gdb/utils.h                                  |    3 +
>  6 files changed, 197 insertions(+), 0 deletions(-)
>  create mode 100644 gdb/testsuite/gdb.python/py-mi-events-gdb.py
>  create mode 100644 gdb/testsuite/gdb.python/py-mi-events.c
>  create mode 100644 gdb/testsuite/gdb.python/py-mi-events.exp
> 
> diff --git a/gdb/python/python.c b/gdb/python/python.c
> index 84f0596..e467134 100644
> --- a/gdb/python/python.c
> +++ b/gdb/python/python.c
> @@ -658,10 +658,17 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
>        /* Copy the argument text in case the command modifies it.  */
>        char *copy = xstrdup (arg);
>        struct cleanup *cleanup = make_cleanup (xfree, copy);
> +      struct interp *interp;
>  
>        make_cleanup_restore_integer (&interpreter_async);
>        interpreter_async = 0;
>  
> +      make_cleanup_restore_ui_out (&current_uiout);
> +      /* Use the console interpreter uiout to have the same print format
> +	for console or MI.  */
> +      interp = interp_lookup ("console");
> +      current_uiout = interp_ui_out (interp);
> +
>        prevent_dont_repeat ();
>        if (to_string)
>  	result = execute_command_to_string (copy, from_tty);
> diff --git a/gdb/testsuite/gdb.python/py-mi-events-gdb.py b/gdb/testsuite/gdb.python/py-mi-events-gdb.py
> new file mode 100644
> index 0000000..0aa4fda
> --- /dev/null
> +++ b/gdb/testsuite/gdb.python/py-mi-events-gdb.py
> @@ -0,0 +1,48 @@
> +# Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
> +
> +# This file is part of the GDB testsuite.  It tests python printing
> +# to string from event handlers.
> +
> +
> +import gdb
> +
> +
> +def signal_stop_handler (event):
> +    """Stop event handler"""
> +    assert (isinstance (event, gdb.StopEvent))
> +    print ("stop_handler")
> +    print gdb.execute("info break", False, True)
> +
> +
> +def continue_handler (event):
> +    """Continue event handler"""
> +    assert (isinstance (event, gdb.ContinueEvent))
> +    print ("continue_handler")
> +    print gdb.execute("info break", False, True)
> +
> +
> +class test_events (gdb.Command):
> +    """Test events."""
> +
> +    def __init__ (self):
> +        gdb.Command.__init__ (self, "test-events", gdb.COMMAND_STACK)
> +
> +    def invoke (self, arg, from_tty):
> +        gdb.events.stop.connect (signal_stop_handler)
> +        gdb.events.cont.connect (continue_handler)
> +        print ("Event testers registered.")
> +
> +test_events ()
> diff --git a/gdb/testsuite/gdb.python/py-mi-events.c b/gdb/testsuite/gdb.python/py-mi-events.c
> new file mode 100644
> index 0000000..5e12bd9
> --- /dev/null
> +++ b/gdb/testsuite/gdb.python/py-mi-events.c
> @@ -0,0 +1,26 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 2016 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  <http://www.gnu.org/licenses/>.  */
> +
> +int
> +main (void)
> +{
> +  int i = 0;
> +  while (i < 10)
> +    i++;
> +
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.python/py-mi-events.exp b/gdb/testsuite/gdb.python/py-mi-events.exp
> new file mode 100644
> index 0000000..6f063e1
> --- /dev/null
> +++ b/gdb/testsuite/gdb.python/py-mi-events.exp
> @@ -0,0 +1,84 @@
> +# Copyright (C) 2008-2016 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 <http://www.gnu.org/licenses/>.
> +
> +# This file is part of the GDB testsuite.  It tests PR 19743.
> +
> +load_lib mi-support.exp
> +set MIFLAGS "-i=mi2"
> +
> +gdb_exit
> +if [mi_gdb_start] {
> +    continue
> +}
> +
> +standard_testfile
> +set pyfile ${testfile}-gdb.py
> +
> +if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
> +    untested ${testfile}.exp
> +    return -1
> +}
> +
> +if { [mi_skip_python_tests] } { continue }
> +
> +set remote_python_file [gdb_remote_download host ${srcdir}/${subdir}/${pyfile}]
> +
> +mi_delete_breakpoints
> +mi_gdb_reinitialize_dir $srcdir/$subdir
> +mi_gdb_test "set auto-load safe-path ${remote_python_file}" \
> +    {.*\^done} \
> +    "set safe-path"
> +
> +if [is_remote host] {
> +    set filename ${testfile}
> +    remote_download host ${binfile} ${filename}
> +} else {
> +    set filename ${binfile}
> +}
> +
> +mi_gdb_test "-file-exec-and-symbols ${filename}"  ".*\\^done" "file-exec-and-symbols operation"
> +mi_run_to_main
> +
> +
> +# register the python event handlers with test-events command
> +mi_gdb_test "test-events" \
> +    ".*~\"Event testers registered.*\\^done" \
> +    "register events"
> +
> +
> +# set a breakpoint into the for loop
> +mi_gdb_test "break ${srcfile}:[gdb_get_line_number "i++;"]" \
> +    ".*Breakpoint $decimal at 0x\[0-9a-fA-F\]+: file .*${srcfile}.*\\\.*\\^done" \
> +    "set the breakpoint"
> +
> +
> +# resume the program
> +mi_send_resuming_command "exec-continue" "continue"
> +
> +
> +# test the python event handlers execution. The following checks are performed:
> +# - python continue handler is executed
> +# - the continue handler prints "info breakpoints" output in console format
> +# - breakpoint is hit and python stop handler is executed
> +# - the stop handler prints "info breakpoints" output in console format
> +mi_gdb_test "" ".*continue_handler.*
> +.*Num.*Type.*Disp.*Enb.*Address.*\
> +.*$decimal.*breakpoint.*keep.*y.* 0x\[0-9a-fA-F\]+.*${srcfile}.*
> +.*stop_handler.*
> +.*Num.*Type.*Disp.*Enb.*Address.*\
> +.*$decimal.*breakpoint.*keep.*y.* 0x\[0-9a-fA-F\]+.*${srcfile}.*" \
> +"check python continue and stop handlers"
> +
> +mi_gdb_exit
> diff --git a/gdb/utils.c b/gdb/utils.c
> index 97e5133..62e169a 100644
> --- a/gdb/utils.c
> +++ b/gdb/utils.c
> @@ -345,6 +345,35 @@ make_cleanup_htab_delete (htab_t htab)
>    return make_cleanup (do_htab_delete_cleanup, htab);
>  }
>  
> +struct restore_ui_out_closure
> +{
> +  struct ui_out **variable;
> +  struct ui_out *value;
> +};
> +
> +static void
> +do_restore_ui_out (void *p)
> +{
> +  struct restore_ui_out_closure *closure
> +    = (struct restore_ui_out_closure *) p;
> +
> +  *(closure->variable) = closure->value;
> +}
> +
> +/* Remember the current value of *VARIABLE and make it restored when
> +   the cleanup is run.  */
> +
> +struct cleanup *
> +make_cleanup_restore_ui_out (struct ui_out **variable)
> +{
> +  struct restore_ui_out_closure *c = XNEW (struct restore_ui_out_closure);
> +
> +  c->variable = variable;
> +  c->value = *variable;
> +
> +  return make_cleanup_dtor (do_restore_ui_out, (void *) c, xfree);
> +}
> +
>  struct restore_ui_file_closure
>  {
>    struct ui_file **variable;
> diff --git a/gdb/utils.h b/gdb/utils.h
> index 0687c86..87bb9c0 100644
> --- a/gdb/utils.h
> +++ b/gdb/utils.h
> @@ -93,6 +93,9 @@ extern struct cleanup *make_cleanup_restore_uinteger (unsigned int *variable);
>  struct target_ops;
>  extern struct cleanup *make_cleanup_unpush_target (struct target_ops *ops);
>  
> +
> +extern struct cleanup *
> +  make_cleanup_restore_ui_out (struct ui_out **variable);
>  extern struct cleanup *
>    make_cleanup_restore_ui_file (struct ui_file **variable);
>  
> 

Hi Catalin,

I think that gdb.python/py-mi-objfile.exp started failing with this commit.  Buildbot seems to
agree:

http://gdb-build.sergiodj.net/cgit/Fedora-x86_64-m64/.git/tree/?id=9473ce97ff66c5f312080c983992b4581accef94

I haven't debugged it yet, so I can't tell whether it's gdb or the test who's at fault.

Would you have time to take a look?

Thanks,

Simon
  
Catalin-Dan Udma April 5, 2016, 7:55 a.m. UTC | #3
> -----Original Message-----
> From: gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] On Behalf Of Simon Marchi
> Hi Catalin,
> 
> I think that gdb.python/py-mi-objfile.exp started failing with this commit.
> Buildbot seems to
> agree:
> 
> http://gdb-build.sergiodj.net/cgit/Fedora-x86_64-
> m64/.git/tree/?id=9473ce97ff66c5f312080c983992b4581accef94
> 
> I haven't debugged it yet, so I can't tell whether it's gdb or the test who's at
> fault.
> 
> Would you have time to take a look?
> 
> Thanks,
> 
> Simon

[Catalin Udma]  I reproduced the failure, I'll look at it.

Regards,
Catalin
  
Catalin-Dan Udma April 5, 2016, 9:52 a.m. UTC | #4
> -----Original Message-----
> From: gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] On Behalf Of Simon Marchi

> On 16-03-31 06:43 AM, Catalin Udma wrote:
> > When gdb is started in MI mode, the output of gdb.execute
> > command is in MI-format in case when it is executed from python stop
> > handler while for all other cases the output is in console-format.
> >
> > To assure consistent output format, this is fixed by using the console
> > format for all python gdb command executions.
> >
> > PR python/19743
> >
> > gdb/ChangeLog:
> > 2016-03-31  Catalin Udma  <catalin.udma@freescale.com>
> >
> > 	PR python/19743
> > 	* python/python.c (execute_gdb_command): Use console uiout
> > 	when executing gdb command.
> > 	* utils.c (restore_ui_out_closure): New structure.
> > 	(do_restore_ui_out): New function.
> > 	(make_cleanup_restore_ui_out): Likewise.
> > 	* utils.h (make_cleanup_restore_ui_out): Declare.
> >
> > gdb/testsuite/ChangeLog:
> > 2016-03-31  Catalin Udma  <catalin.udma@freescale.com>
> >
> > 	PR python/19743
> > 	* gdb.python/py-mi-events-gdb.py: New file.
> > 	* gdb.python/py-mi-events.c: New file.
> > 	* gdb.python/py-mi-events.exp: New file.
> >
> > Signed-off-by: Catalin Udma <catalin.udma@freescale.com>
> > ---
> Hi Catalin,
> 
> I think that gdb.python/py-mi-objfile.exp started failing with this commit.
> Buildbot seems to
> agree:
> 
> http://gdb-build.sergiodj.net/cgit/Fedora-x86_64-
> m64/.git/tree/?id=9473ce97ff66c5f312080c983992b4581accef94
> 
> I haven't debugged it yet, so I can't tell whether it's gdb or the test who's at
> fault.
> 
> Would you have time to take a look?
> 
> Thanks,
> 
> Simon
[Catalin Udma] The py-mi-objfile.exp test needs to be fixed. This is exactly what my patch
is trying to fix:
- when the python script is called from command line, it prints the "list" command in console format
- when the python script is called as an event triggered by symbol loading, the unpatched gdb would
 prints the "list" command in MI format. With my patch, the output is consistent and the python 
script would print in console format.

I'll send a patch updating the py-mi-objfile.exp test to expect the script printing in console format.

Regards,
Catalin
  

Patch

diff --git a/gdb/python/python.c b/gdb/python/python.c
index 84f0596..e467134 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -658,10 +658,17 @@  execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
       /* Copy the argument text in case the command modifies it.  */
       char *copy = xstrdup (arg);
       struct cleanup *cleanup = make_cleanup (xfree, copy);
+      struct interp *interp;
 
       make_cleanup_restore_integer (&interpreter_async);
       interpreter_async = 0;
 
+      make_cleanup_restore_ui_out (&current_uiout);
+      /* Use the console interpreter uiout to have the same print format
+	for console or MI.  */
+      interp = interp_lookup ("console");
+      current_uiout = interp_ui_out (interp);
+
       prevent_dont_repeat ();
       if (to_string)
 	result = execute_command_to_string (copy, from_tty);
diff --git a/gdb/testsuite/gdb.python/py-mi-events-gdb.py b/gdb/testsuite/gdb.python/py-mi-events-gdb.py
new file mode 100644
index 0000000..0aa4fda
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-mi-events-gdb.py
@@ -0,0 +1,48 @@ 
+# Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite.  It tests python printing
+# to string from event handlers.
+
+
+import gdb
+
+
+def signal_stop_handler (event):
+    """Stop event handler"""
+    assert (isinstance (event, gdb.StopEvent))
+    print ("stop_handler")
+    print gdb.execute("info break", False, True)
+
+
+def continue_handler (event):
+    """Continue event handler"""
+    assert (isinstance (event, gdb.ContinueEvent))
+    print ("continue_handler")
+    print gdb.execute("info break", False, True)
+
+
+class test_events (gdb.Command):
+    """Test events."""
+
+    def __init__ (self):
+        gdb.Command.__init__ (self, "test-events", gdb.COMMAND_STACK)
+
+    def invoke (self, arg, from_tty):
+        gdb.events.stop.connect (signal_stop_handler)
+        gdb.events.cont.connect (continue_handler)
+        print ("Event testers registered.")
+
+test_events ()
diff --git a/gdb/testsuite/gdb.python/py-mi-events.c b/gdb/testsuite/gdb.python/py-mi-events.c
new file mode 100644
index 0000000..5e12bd9
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-mi-events.c
@@ -0,0 +1,26 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2016 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  <http://www.gnu.org/licenses/>.  */
+
+int
+main (void)
+{
+  int i = 0;
+  while (i < 10)
+    i++;
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.python/py-mi-events.exp b/gdb/testsuite/gdb.python/py-mi-events.exp
new file mode 100644
index 0000000..6f063e1
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-mi-events.exp
@@ -0,0 +1,84 @@ 
+# Copyright (C) 2008-2016 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 <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite.  It tests PR 19743.
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi2"
+
+gdb_exit
+if [mi_gdb_start] {
+    continue
+}
+
+standard_testfile
+set pyfile ${testfile}-gdb.py
+
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+    untested ${testfile}.exp
+    return -1
+}
+
+if { [mi_skip_python_tests] } { continue }
+
+set remote_python_file [gdb_remote_download host ${srcdir}/${subdir}/${pyfile}]
+
+mi_delete_breakpoints
+mi_gdb_reinitialize_dir $srcdir/$subdir
+mi_gdb_test "set auto-load safe-path ${remote_python_file}" \
+    {.*\^done} \
+    "set safe-path"
+
+if [is_remote host] {
+    set filename ${testfile}
+    remote_download host ${binfile} ${filename}
+} else {
+    set filename ${binfile}
+}
+
+mi_gdb_test "-file-exec-and-symbols ${filename}"  ".*\\^done" "file-exec-and-symbols operation"
+mi_run_to_main
+
+
+# register the python event handlers with test-events command
+mi_gdb_test "test-events" \
+    ".*~\"Event testers registered.*\\^done" \
+    "register events"
+
+
+# set a breakpoint into the for loop
+mi_gdb_test "break ${srcfile}:[gdb_get_line_number "i++;"]" \
+    ".*Breakpoint $decimal at 0x\[0-9a-fA-F\]+: file .*${srcfile}.*\\\.*\\^done" \
+    "set the breakpoint"
+
+
+# resume the program
+mi_send_resuming_command "exec-continue" "continue"
+
+
+# test the python event handlers execution. The following checks are performed:
+# - python continue handler is executed
+# - the continue handler prints "info breakpoints" output in console format
+# - breakpoint is hit and python stop handler is executed
+# - the stop handler prints "info breakpoints" output in console format
+mi_gdb_test "" ".*continue_handler.*
+.*Num.*Type.*Disp.*Enb.*Address.*\
+.*$decimal.*breakpoint.*keep.*y.* 0x\[0-9a-fA-F\]+.*${srcfile}.*
+.*stop_handler.*
+.*Num.*Type.*Disp.*Enb.*Address.*\
+.*$decimal.*breakpoint.*keep.*y.* 0x\[0-9a-fA-F\]+.*${srcfile}.*" \
+"check python continue and stop handlers"
+
+mi_gdb_exit
diff --git a/gdb/utils.c b/gdb/utils.c
index 97e5133..62e169a 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -345,6 +345,35 @@  make_cleanup_htab_delete (htab_t htab)
   return make_cleanup (do_htab_delete_cleanup, htab);
 }
 
+struct restore_ui_out_closure
+{
+  struct ui_out **variable;
+  struct ui_out *value;
+};
+
+static void
+do_restore_ui_out (void *p)
+{
+  struct restore_ui_out_closure *closure
+    = (struct restore_ui_out_closure *) p;
+
+  *(closure->variable) = closure->value;
+}
+
+/* Remember the current value of *VARIABLE and make it restored when
+   the cleanup is run.  */
+
+struct cleanup *
+make_cleanup_restore_ui_out (struct ui_out **variable)
+{
+  struct restore_ui_out_closure *c = XNEW (struct restore_ui_out_closure);
+
+  c->variable = variable;
+  c->value = *variable;
+
+  return make_cleanup_dtor (do_restore_ui_out, (void *) c, xfree);
+}
+
 struct restore_ui_file_closure
 {
   struct ui_file **variable;
diff --git a/gdb/utils.h b/gdb/utils.h
index 0687c86..87bb9c0 100644
--- a/gdb/utils.h
+++ b/gdb/utils.h
@@ -93,6 +93,9 @@  extern struct cleanup *make_cleanup_restore_uinteger (unsigned int *variable);
 struct target_ops;
 extern struct cleanup *make_cleanup_unpush_target (struct target_ops *ops);
 
+
+extern struct cleanup *
+  make_cleanup_restore_ui_out (struct ui_out **variable);
 extern struct cleanup *
   make_cleanup_restore_ui_file (struct ui_file **variable);