Enable readline in Python in a GDB-specific way and block the
authorYit Phang Khoo <khooyp@sourceware.org>
Wed, 22 Aug 2012 21:04:55 +0000 (21:04 +0000)
committerYit Phang Khoo <khooyp@sourceware.org>
Wed, 22 Aug 2012 21:04:55 +0000 (21:04 +0000)
standard Python readline module to prevent conflicts with GDB.
* Makefile.in (SUBDIR_PYTHON_OBS): Add py-gdb-readline.o.
(SUBDIR_PYTHON_SRCS): Add python/py-gdb-readline.c.
(py-gdb-readline.o): Add rule to compile python/py-gdb-readline.c.
* python/py-gdb-readline.c: New file.
* python/python-internal.h (gdbpy_initialize_gdb_readline): New
prototype.
* python/python.c (_initialize_python): Call
gdbpy_initialize_gdb_readline.

gdb/ChangeLog
gdb/Makefile.in
gdb/python/py-gdb-readline.c [new file with mode: 0644]
gdb/python/python-internal.h
gdb/python/python.c

index ac628ce..cb69076 100644 (file)
@@ -1,3 +1,16 @@
+2012-08-22  Khoo Yit Phang <khooyp@cs.umd.edu>
+
+       Enable readline in Python in a GDB-specific way and block the
+       standard Python readline module to prevent conflicts with GDB.
+       * Makefile.in (SUBDIR_PYTHON_OBS): Add py-gdb-readline.o.
+       (SUBDIR_PYTHON_SRCS): Add python/py-gdb-readline.c.
+       (py-gdb-readline.o): Add rule to compile python/py-gdb-readline.c.
+       * python/py-gdb-readline.c: New file.
+       * python/python-internal.h (gdbpy_initialize_gdb_readline): New
+       prototype.
+       * python/python.c (_initialize_python): Call
+       gdbpy_initialize_gdb_readline.
+
 2012-08-22  Keith Seitz  <keiths@redhat.com>
 
        * defs.h: Include build-gnulib/config.h
index bb1f0bc..5d5574e 100644 (file)
@@ -280,6 +280,7 @@ SUBDIR_PYTHON_OBS = \
        py-finishbreakpoint.o \
        py-frame.o \
        py-function.o \
+       py-gdb-readline.o \
        py-inferior.o \
        py-infthread.o \
        py-lazy-string.o \
@@ -312,6 +313,7 @@ SUBDIR_PYTHON_SRCS = \
        python/py-finishbreakpoint.c \
        python/py-frame.c \
        python/py-function.c \
+       python/py-gdb-readline.c \
        python/py-inferior.c \
        python/py-infthread.c \
        python/py-lazy-string.c \
@@ -2083,6 +2085,10 @@ py-function.o: $(srcdir)/python/py-function.c
        $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-function.c
        $(POSTCOMPILE)
 
+py-gdb-readline.o: $(srcdir)/python/py-gdb-readline.c
+       $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-gdb-readline.c
+       $(POSTCOMPILE)
+
 py-inferior.o: $(srcdir)/python/py-inferior.c
        $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-inferior.c
        $(POSTCOMPILE)
diff --git a/gdb/python/py-gdb-readline.c b/gdb/python/py-gdb-readline.c
new file mode 100644 (file)
index 0000000..b5e0705
--- /dev/null
@@ -0,0 +1,113 @@
+/* Readline support for Python.
+
+   Copyright (C) 2012 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#include "defs.h"
+#include "python-internal.h"
+#include "exceptions.h"
+#include "top.h"
+#include "cli/cli-utils.h"
+#include "gdb_string.h"
+
+#include <stddef.h>
+
+/* Readline function suitable for PyOS_ReadlineFunctionPointer, which
+   is used for Python's interactive parser and raw_input.  In both
+   cases, sys_stdin and sys_stdout are always stdin and stdout
+   respectively, as far as I can tell; they are ignored and
+   command_line_input is used instead.  */
+
+static char *
+gdbpy_readline_wrapper (FILE *sys_stdin, FILE *sys_stdout,
+                       char *prompt)
+{
+  int n;
+  char *p = NULL, *p_start, *p_end, *q;
+  volatile struct gdb_exception except;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    p = command_line_input (prompt, 0, "python");
+
+  /* Detect user interrupt (Ctrl-C).  */
+  if (except.reason == RETURN_QUIT)
+    return NULL;
+
+  /* Handle errors by raising Python exceptions.  */
+  if (except.reason < 0)
+    {
+      /* The thread state is nulled during gdbpy_readline_wrapper,
+        with the original value saved in the following undocumented
+        variable (see Python's Parser/myreadline.c and
+        Modules/readline.c).  */
+      PyEval_RestoreThread (_PyOS_ReadlineTState);
+      gdbpy_convert_exception (except);
+      PyEval_SaveThread ();
+      return NULL;
+    }
+
+  /* Detect EOF (Ctrl-D).  */
+  if (p == NULL)
+    {
+      q = PyMem_Malloc (1);
+      if (q != NULL)
+       q[0] = '\0';
+      return q;
+    }
+
+  n = strlen (p);
+
+  /* Copy the line to Python and return.  */
+  q = PyMem_Malloc (n + 2);
+  if (q != NULL)
+    {
+      strncpy (q, p, n);
+      q[n] = '\n';
+      q[n + 1] = '\0';
+    }
+  return q;
+}
+
+/* Initialize Python readline support.  */
+
+void
+gdbpy_initialize_gdb_readline (void)
+{
+  /* Python's readline module conflicts with GDB's use of readline
+     since readline is not reentrant.  Ideally, a reentrant wrapper to
+     GDB's readline should be implemented to replace Python's readline
+     and prevent conflicts.  For now, this file implements a
+     sys.meta_path finder that simply fails to import the readline
+     module.  */
+  PyRun_SimpleString ("\
+import sys\n\
+\n\
+class GdbRemoveReadlineFinder:\n\
+  def find_module(self, fullname, path=None):\n\
+    if fullname == 'readline' and path is None:\n\
+      return self\n\
+    return None\n\
+\n\
+  def load_module(self, fullname):\n\
+    raise ImportError('readline module disabled under GDB')\n\
+\n\
+sys.meta_path.append(GdbRemoveReadlineFinder())\n\
+");
+
+  PyOS_ReadlineFunctionPointer = gdbpy_readline_wrapper;
+}
+
index bae61c2..aa3678b 100644 (file)
@@ -232,6 +232,7 @@ struct symtab *symtab_object_to_symtab (PyObject *obj);
 struct symtab_and_line *sal_object_to_symtab_and_line (PyObject *obj);
 struct frame_info *frame_object_to_frame_info (PyObject *frame_obj);
 
+void gdbpy_initialize_gdb_readline (void);
 void gdbpy_initialize_auto_load (void);
 void gdbpy_initialize_values (void);
 void gdbpy_initialize_frames (void);
index ad735ce..1e59d1e 100644 (file)
@@ -1389,6 +1389,7 @@ message == an error message without a stack will be printed."),
   gdbpy_gdberror_exc = PyErr_NewException ("gdb.GdbError", NULL, NULL);
   PyModule_AddObject (gdb_module, "GdbError", gdbpy_gdberror_exc);
 
+  gdbpy_initialize_gdb_readline ();
   gdbpy_initialize_auto_load ();
   gdbpy_initialize_values ();
   gdbpy_initialize_frames ();