1 /* Readline support for Python.
2 
3    Copyright (C) 2012-2024 Free Software Foundation, Inc.
4 
5    This file is part of GDB.
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19 
20 #include "python-internal.h"
21 #include "top.h"
22 #include "cli/cli-utils.h"
23 
24 /* Readline function suitable for PyOS_ReadlineFunctionPointer, which
25    is used for Python's interactive parser and raw_input.  In both
26    cases, sys_stdin and sys_stdout are always stdin and stdout
27    respectively, as far as I can tell; they are ignored and
28    command_line_input is used instead.  */
29 
30 static char *
gdbpy_readline_wrapper(FILE * sys_stdin,FILE * sys_stdout,const char * prompt)31 gdbpy_readline_wrapper (FILE *sys_stdin, FILE *sys_stdout,
32 #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 4
33                               const char *prompt)
34 #else
35                               char *prompt)
36 #endif
37 {
38   int n;
39   const char *p = NULL;
40   std::string buffer;
41   char *q;
42 
43   try
44     {
45       p = command_line_input (buffer, prompt, "python");
46     }
47   /* Handle errors by raising Python exceptions.  */
48   catch (const gdb_exception_forced_quit &e)
49     {
50       quit_force (NULL, 0);
51     }
52   catch (const gdb_exception &except)
53     {
54       /* Detect user interrupt (Ctrl-C).  */
55       if (except.reason == RETURN_QUIT)
56           return NULL;
57 
58 
59       /* This readline callback is called without the GIL held.  */
60       gdbpy_gil gil;
61 
62       gdbpy_convert_exception (except);
63       return NULL;
64     }
65 
66   /* Detect EOF (Ctrl-D).  */
67   if (p == NULL)
68     {
69       q = (char *) PyMem_RawMalloc (1);
70       if (q != NULL)
71           q[0] = '\0';
72       return q;
73     }
74 
75   n = strlen (p);
76 
77   /* Copy the line to Python and return.  */
78   q = (char *) PyMem_RawMalloc (n + 2);
79   if (q != NULL)
80     {
81       strcpy (q, p);
82       q[n] = '\n';
83       q[n + 1] = '\0';
84     }
85   return q;
86 }
87 
88 /* Initialize Python readline support.  */
89 
90 static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_gdb_readline(void)91 gdbpy_initialize_gdb_readline (void)
92 {
93   /* Python's readline module conflicts with GDB's use of readline
94      since readline is not reentrant.  Ideally, a reentrant wrapper to
95      GDB's readline should be implemented to replace Python's readline
96      and prevent conflicts.  For now, this file implements a
97      sys.meta_path finder that simply fails to import the readline
98      module.  */
99   if (PyRun_SimpleString ("\
100 import sys\n\
101 \n\
102 class GdbRemoveReadlineFinder:\n\
103   def find_module(self, fullname, path=None):\n\
104     if fullname == 'readline' and path is None:\n\
105       return self\n\
106     return None\n\
107 \n\
108   def load_module(self, fullname):\n\
109     raise ImportError('readline module disabled under GDB')\n\
110 \n\
111 sys.meta_path.append(GdbRemoveReadlineFinder())\n\
112 ") == 0)
113     PyOS_ReadlineFunctionPointer = gdbpy_readline_wrapper;
114 
115   return 0;
116 }
117 
118 GDBPY_INITIALIZE_FILE (gdbpy_initialize_gdb_readline);
119