From: scott snyder <snyder@fnal.gov>
To: Tom Tromey <tromey@redhat.com>,
Marcelo Taube <mail.marcelo.taube@gmail.com>,
gdb@sourceware.org
Subject: Re: Some feedback about the python scripting feature
Date: Fri, 13 Nov 2009 21:37:00 -0000 [thread overview]
Message-ID: <200911122107.nACL7DiB032152@d0mino02.fnal.gov> (raw)
In-Reply-To: <20091110153803.GA26779@caradoc.them.org>
>From: Daniel Jacobowitz <drow@false.org>
> 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 <ctype.h>
@@ -459,6 +460,37 @@
\f
+/* 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);
+}
+
+\f
+
/* 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);
}
\f
@@ -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;
prev parent reply other threads:[~2009-11-12 21:07 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <4AF898F3.50908@gmail.com>
2009-11-10 8:06 ` Marcelo Taube
2009-11-10 15:12 ` Phil Muldoon
2009-11-10 15:38 ` Tom Tromey
2009-11-10 16:53 ` Daniel Jacobowitz
2009-11-10 20:49 ` Marcelo Taube
2009-11-11 2:00 ` Daniel Jacobowitz
2009-11-13 21:37 ` scott snyder [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200911122107.nACL7DiB032152@d0mino02.fnal.gov \
--to=snyder@fnal.gov \
--cc=gdb@sourceware.org \
--cc=mail.marcelo.taube@gmail.com \
--cc=tromey@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox