From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 25831 invoked by alias); 12 Nov 2009 21:07:22 -0000 Received: (qmail 25809 invoked by uid 22791); 12 Nov 2009 21:07:21 -0000 X-SWARE-Spam-Status: No, hits=-2.6 required=5.0 tests=BAYES_00,SPF_PASS X-Spam-Check-By: sourceware.org Received: from mailgw1.fnal.gov (HELO mailgw1.fnal.gov) (131.225.111.11) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 12 Nov 2009 21:07:15 +0000 Received: from mailav2.fnal.gov (mailav2.fnal.gov [131.225.111.20]) by mailgw1.fnal.gov (iPlanet Messaging Server 5.2 HotFix 2.06 (built Mar 28 2005)) with SMTP id <0KT000GZZL8M6V@mailgw1.fnal.gov> for gdb@sourceware.org; Thu, 12 Nov 2009 15:07:14 -0600 (CST) Received: from mailgw1.fnal.gov ([131.225.111.11]) by mailav2.fnal.gov (SAVSMTP 3.1.7.47) with SMTP id M2009111215071300063 for ; Thu, 12 Nov 2009 15:07:13 -0600 Received: from conversion-daemon.mailgw1.fnal.gov by mailgw1.fnal.gov (iPlanet Messaging Server 5.2 HotFix 2.06 (built Mar 28 2005)) id <0KT000601L1TJR@mailgw1.fnal.gov> (original mail from snyder@fnal.gov) for gdb@sourceware.org; Thu, 12 Nov 2009 15:07:14 -0600 (CST) Received: from d0mino02.fnal.gov (d0mino02.fnal.gov [131.225.219.201]) by mailgw1.fnal.gov (iPlanet Messaging Server 5.2 HotFix 2.06 (built Mar 28 2005)) with ESMTPS id <0KT000GDVLC27O@mailgw1.fnal.gov>; Thu, 12 Nov 2009 15:07:14 -0600 (CST) Received: from d0mino02.fnal.gov (localhost.localdomain [127.0.0.1]) by d0mino02.fnal.gov (8.12.11.20060308/8.12.11) with ESMTP id nACL7Df7032156; Thu, 12 Nov 2009 15:07:13 -0600 Received: from d0mino02.fnal.gov (snyder@localhost) by d0mino02.fnal.gov (8.12.11.20060308/8.12.11/Submit) with ESMTP id nACL7DiB032152; Thu, 12 Nov 2009 15:07:13 -0600 Date: Fri, 13 Nov 2009 21:37:00 -0000 From: scott snyder Subject: Re: Some feedback about the python scripting feature In-reply-to: <20091110153803.GA26779@caradoc.them.org> To: Tom Tromey , Marcelo Taube , gdb@sourceware.org Reply-to: scott snyder Message-id: <200911122107.nACL7DiB032152@d0mino02.fnal.gov> MIME-version: 1.0 Content-type: TEXT/PLAIN Content-transfer-encoding: 7BIT References: <4AF898F3.50908@gmail.com> <4AF8993D.2050507@gmail.com> <20091110153803.GA26779@caradoc.them.org> Comments: In-reply-to Daniel Jacobowitz message dated "Tue, 10 Nov 2009 10:38:03 -0500." X-IsSubscribed: yes Mailing-List: contact gdb-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-owner@sourceware.org X-SW-Source: 2009-11/txt/msg00137.txt.bz2 >From: Daniel Jacobowitz > py import code > py code.InteractiveConsole().interact() I tried this a while ago, and couldn't get readline to work. This is because gdb set sys.stdout/stderr to objects which python didn't recognize as a tty. And if i hacked around that, i'd get crashes, because gdb and python were each trying to configure readline differently. I ended up adding a new function to the python api to read a line of input using gdb's input reader: === modified file 'gdb/python/python.c' --- gdb/python/python.c 2009-10-14 22:45:34 +0000 +++ gdb/python/python.c 2009-10-14 22:46:03 +0000 @@ -28,6 +28,7 @@ #include "value.h" #include "language.h" #include "tui/tui-io.h" +#include "readline/history.h" #include @@ -459,6 +460,37 @@ +/* Reading. */ + +static PyObject* +gdbpy_input (PyObject* self, PyObject* args) +{ + const char* prompt_str = ""; + char* line = 0; + volatile struct gdb_exception e; + + if (!PyArg_ParseTuple (args, "|s", &prompt_str)) + return NULL; + + TRY_CATCH (e, RETURN_MASK_QUIT) { + line = gdb_readline_wrapper ((char*)prompt_str); + } + if (e.reason < 0) { + PyErr_SetNone (PyExc_KeyboardInterrupt); + return NULL; + } + + if (!line) { + PyErr_SetNone (PyExc_EOFError); + return NULL; + } + + add_history (line); + return PyString_FromString (line); +} + + + /* The "current" objfile. This is set when gdb detects that a new objfile has been loaded. It is only set for the duration of a call to gdbpy_new_objfile; it is NULL at other times. */ @@ -784,6 +816,8 @@ "Write a string using gdb's filtered stream." }, { "flush", gdbpy_flush, METH_NOARGS, "Flush gdb's filtered stdout stream." }, + { "input", gdbpy_input, METH_VARARGS, + "Read a line of input from the user." }, { "parse_and_eval", gdbpy_parse_and_eval, METH_VARARGS, "Parse a string as an expression, evaluate it, and return the result." }, Then this can be used with this command: import gdb import code import sys class PyInteract (gdb.Command): """Start a python read-eval-print loop from within gdb.""" def __init__ (self): super (PyInteract, self).__init__ ("pyinteract", gdb.COMMAND_OBSCURE) return def invoke (self, arg, from_tty): self.dont_repeat() code.interact("Press Ctrl-D to return to gdb.", gdb.input, sys.modules['__main__'].__dict__) return PyInteract() This has a drawback in that Ctrl-C won't interrupt python code, meaning it's possible to lose control of the debugger by executing an infinite loop in python. I'm currently using these patches to try to fix that. This is rather uglier than i'd like, but it's worked for me so far. sss === modified file 'gdb/python/py-cmd.c' --- gdb/python/py-cmd.c 2009-10-14 16:48:13 +0000 +++ gdb/python/py-cmd.c 2009-10-15 04:22:35 +0000 @@ -207,6 +207,8 @@ Py_DECREF (wordobj); if (! resultobj) { + if (PyErr_Occurred() == PyExc_KeyboardInterrupt) + quit_flag = 1; /* Just swallow errors here. */ PyErr_Clear (); goto done; @@ -228,6 +230,8 @@ PyObject *elt = PySequence_GetItem (resultobj, i); if (elt == NULL || ! gdbpy_is_string (elt)) { + if (PyErr_Occurred() == PyExc_KeyboardInterrupt) + quit_flag = 1; /* Skip problem elements. */ PyErr_Clear (); continue; === modified file 'gdb/python/py-prettyprint.c' --- gdb/python/py-prettyprint.c 2009-10-14 16:48:13 +0000 +++ gdb/python/py-prettyprint.c 2009-10-15 04:22:35 +0000 @@ -49,8 +49,11 @@ return NULL; printer = PyObject_CallFunctionObjArgs (function, value, NULL); - if (! printer) + if (! printer) { + if (PyErr_Occurred() == PyExc_KeyboardInterrupt) + quit_flag = 1; return NULL; + } else if (printer != Py_None) return printer; @@ -77,6 +80,8 @@ PyObject *objf = objfile_to_objfile_object (obj); if (!objf) { + if (PyErr_Occurred() == PyExc_KeyboardInterrupt) + quit_flag = 1; /* Ignore the error and continue. */ PyErr_Clear (); continue; @@ -109,8 +114,11 @@ goto done; } pp_list = PyObject_GetAttrString (gdb_module, "pretty_printers"); - if (! pp_list) + if (! pp_list) { + if (PyErr_Occurred() == PyExc_KeyboardInterrupt) + quit_flag = 1; goto done; + } if (! PyList_Check (pp_list)) goto done; @@ -141,8 +149,11 @@ if (! gdbpy_is_string (result)) { *out_value = convert_value_from_python (result); - if (PyErr_Occurred ()) + if (PyErr_Occurred ()) { + if (PyErr_Occurred() == PyExc_KeyboardInterrupt) + quit_flag = 1; *out_value = NULL; + } Py_DECREF (result); result = NULL; } === modified file 'gdb/python/python.c' --- gdb/python/python.c 2009-10-14 22:46:40 +0000 +++ gdb/python/python.c 2009-10-15 04:22:35 +0000 @@ -69,6 +69,60 @@ struct gdbarch *python_gdbarch; const struct language_defn *python_language; +#include "event-loop.h" + +extern void* sigint_token; +static void* py_sigint_token = 0; +static void* old_sigint_token = 0; +static int old_immediate_quit; + +static int +py_checksignals(void* arg) +{ + return PyErr_CheckSignals(); +} + +static void +async_pyinterrupt (gdb_client_data arg) +{ + PyErr_SetInterrupt(); + Py_AddPendingCall (py_checksignals, NULL); +} + + +static void* +set_pyinterrupt() +{ + void* oldtoken = sigint_token; + old_sigint_token = oldtoken; + if (py_sigint_token == 0) + py_sigint_token = create_async_signal_handler (async_pyinterrupt, NULL); + sigint_token = py_sigint_token; + if (quit_flag) { + async_pyinterrupt (NULL); + quit_flag = 0; + } + old_immediate_quit = immediate_quit; + immediate_quit = 1; + return oldtoken; +} + +void +restore_pyinterrupt (void* token) +{ + if (!token) { + if (old_sigint_token) { + sigint_token = old_sigint_token; + immediate_quit = old_immediate_quit; + } + } + else + sigint_token = token; + old_sigint_token = 0; + if (PyOS_InterruptOccurred()) + quit_flag = 1; +} + /* Restore global language and architecture and Python GIL state when leaving the Python interpreter. */ @@ -77,6 +131,8 @@ PyGILState_STATE state; struct gdbarch *gdbarch; const struct language_defn *language; + void* old_token; + int old_immediate; }; static void @@ -86,6 +142,10 @@ PyGILState_Release (env->state); python_gdbarch = env->gdbarch; python_language = env->language; + if (env->old_token) { + restore_pyinterrupt (env->old_token); + immediate_quit = env->old_immediate; + } xfree (env); } @@ -101,6 +161,8 @@ env->state = PyGILState_Ensure (); env->gdbarch = python_gdbarch; env->language = python_language; + env->old_immediate = immediate_quit; + env->old_token = set_pyinterrupt(); python_gdbarch = gdbarch; python_language = language; @@ -171,17 +233,18 @@ python_command (char *arg, int from_tty) { struct cleanup *cleanup; - cleanup = ensure_python_env (get_current_arch (), current_language); while (arg && *arg && isspace (*arg)) ++arg; if (arg && *arg) { + cleanup = ensure_python_env (get_current_arch (), current_language); if (PyRun_SimpleString (arg)) { gdbpy_print_stack (); error (_("Error while executing Python code.")); } + do_cleanups (cleanup); } else { @@ -190,7 +253,6 @@ execute_control_command_untraced (l); } - do_cleanups (cleanup); } @@ -311,8 +373,10 @@ TRY_CATCH (except, RETURN_MASK_ALL) { + restore_pyinterrupt (0); execute_command (arg, from_tty); } + set_pyinterrupt(); GDB_PY_HANDLE_EXCEPTION (except); /* Do any commands attached to breakpoint we stopped at. */ @@ -382,8 +446,10 @@ TRY_CATCH (except, RETURN_MASK_ALL) { + restore_pyinterrupt (0); execute_command (arg, from_tty); } + set_pyinterrupt(); ui_out_redirect (uiout, 0); uiout = old_uiout; gdb_stdout = old_stdout; @@ -414,8 +480,10 @@ TRY_CATCH (except, RETURN_MASK_ALL) { + restore_pyinterrupt (0); result = parse_and_eval (expr_str); } + set_pyinterrupt(); GDB_PY_HANDLE_EXCEPTION (except); return value_to_value_object (result); @@ -452,6 +519,9 @@ void gdbpy_print_stack (void) { + if (PyErr_Occurred() == PyExc_KeyboardInterrupt) + quit_flag = 1; + if (gdbpy_should_print_stack) PyErr_Print (); else @@ -473,8 +543,11 @@ return NULL; TRY_CATCH (e, RETURN_MASK_QUIT) { + restore_pyinterrupt (0); + quit_flag = 0; line = gdb_readline_wrapper ((char*)prompt_str); } + set_pyinterrupt(); if (e.reason < 0) { PyErr_SetNone (PyExc_KeyboardInterrupt); return NULL;