/* General python/gdb code
- Copyright (C) 2008-2020 Free Software Foundation, Inc.
+ Copyright (C) 2008-2021 Free Software Foundation, Inc.
This file is part of GDB.
#include "objfiles.h"
#include "value.h"
#include "language.h"
-#include "event-loop.h"
+#include "gdbsupport/event-loop.h"
#include "readline/tilde.h"
#include "python.h"
#include "extension-priv.h"
extern PyMethodDef python_GdbMethods[];
-#ifdef IS_PY3K
-extern struct PyModuleDef python_GdbModuleDef;
-#endif
-
PyObject *gdb_module;
PyObject *gdb_python_module;
static script_sourcer_func gdbpy_source_script;
static objfile_script_sourcer_func gdbpy_source_objfile_script;
static objfile_script_executor_func gdbpy_execute_objfile_script;
-static void gdbpy_finish_initialization
- (const struct extension_language_defn *);
+static void gdbpy_initialize (const struct extension_language_defn *);
static int gdbpy_initialized (const struct extension_language_defn *);
static void gdbpy_eval_from_control_command
(const struct extension_language_defn *, struct command_line *cmd);
static int gdbpy_check_quit_flag (const struct extension_language_defn *);
static enum ext_lang_rc gdbpy_before_prompt_hook
(const struct extension_language_defn *, const char *current_gdb_prompt);
+static gdb::optional<std::string> gdbpy_colorize
+ (const std::string &filename, const std::string &contents);
/* The interface between gdb proper and loading of python scripts. */
const struct extension_language_ops python_extension_ops =
{
- gdbpy_finish_initialization,
+ gdbpy_initialize,
gdbpy_initialized,
gdbpy_eval_from_control_command,
gdbpy_before_prompt_hook,
gdbpy_get_matching_xmethod_workers,
+
+ gdbpy_colorize,
};
/* Architecture and language to be used in callbacks from
PyGILState_Release (m_state);
}
+/* A helper class to save and restore the GIL, but without touching
+ the other globals that are handled by gdbpy_enter. */
+
+class gdbpy_gil
+{
+public:
+
+ gdbpy_gil ()
+ : m_state (PyGILState_Ensure ())
+ {
+ }
+
+ ~gdbpy_gil ()
+ {
+ PyGILState_Release (m_state);
+ }
+
+ DISABLE_COPY_AND_ASSIGN (gdbpy_gil);
+
+private:
+
+ PyGILState_STATE m_state;
+};
+
/* Set the quit flag. */
static void
static int
gdbpy_check_quit_flag (const struct extension_language_defn *extlang)
{
+ if (!gdb_python_initialized)
+ return 0;
+
+ gdbpy_gil gil;
return PyOS_InterruptOccurred ();
}
if (return_value == nullptr)
{
/* Use PyErr_PrintEx instead of gdbpy_print_stack to better match the
- behavior of the non-Windows codepath. */
+ behavior of the non-Windows codepath. */
PyErr_PrintEx(0);
}
/* Fall through. */
case var_zinteger:
case var_zuinteger_unlimited:
- return PyLong_FromLong (* (int *) var);
+ return gdb_py_object_from_longest (* (int *) var).release ();
case var_uinteger:
{
if (val == UINT_MAX)
Py_RETURN_NONE;
- return PyLong_FromUnsignedLong (val);
+ return gdb_py_object_from_ulongest (val).release ();
}
case var_zuinteger:
{
unsigned int val = * (unsigned int *) var;
- return PyLong_FromUnsignedLong (val);
+ return gdb_py_object_from_ulongest (val).release ();
}
}
}
catch (const gdb_exception &except)
{
+ /* If an exception occurred then we won't hit normal_stop (), or have
+ an exception reach the top level of the event loop, which are the
+ two usual places in which stdin would be re-enabled. So, before we
+ convert the exception and continue back in Python, we should
+ re-enable stdin here. */
+ async_enable_stdin ();
GDB_PY_HANDLE_EXCEPTION (except);
}
/* Posting and handling events. */
-/* A helper class to save and restore the GIL, but without touching
- the other globals that are handled by gdbpy_enter. */
-
-class gdbpy_gil
-{
-public:
-
- gdbpy_gil ()
- : m_state (PyGILState_Ensure ())
- {
- }
-
- ~gdbpy_gil ()
- {
- PyGILState_Release (m_state);
- }
-
- DISABLE_COPY_AND_ASSIGN (gdbpy_gil);
-
-private:
-
- PyGILState_STATE m_state;
-};
-
/* A single event. */
struct gdbpy_event
{
{
}
- gdbpy_event (gdbpy_event &&other)
+ gdbpy_event (gdbpy_event &&other) noexcept
: m_func (other.m_func)
{
other.m_func = nullptr;
return EXT_LANG_RC_NOP;
}
+/* This is the extension_language_ops.colorize "method". */
+
+static gdb::optional<std::string>
+gdbpy_colorize (const std::string &filename, const std::string &contents)
+{
+ if (!gdb_python_initialized)
+ return {};
+
+ gdbpy_enter enter_py (get_current_arch (), current_language);
+
+ if (gdb_python_module == nullptr
+ || !PyObject_HasAttrString (gdb_python_module, "colorize"))
+ return {};
+
+ gdbpy_ref<> hook (PyObject_GetAttrString (gdb_python_module, "colorize"));
+ if (hook == nullptr)
+ {
+ gdbpy_print_stack ();
+ return {};
+ }
+
+ if (!PyCallable_Check (hook.get ()))
+ return {};
+
+ gdbpy_ref<> fname_arg (PyString_FromString (filename.c_str ()));
+ if (fname_arg == nullptr)
+ {
+ gdbpy_print_stack ();
+ return {};
+ }
+ gdbpy_ref<> contents_arg (PyString_FromString (contents.c_str ()));
+ if (contents_arg == nullptr)
+ {
+ gdbpy_print_stack ();
+ return {};
+ }
+
+ gdbpy_ref<> result (PyObject_CallFunctionObjArgs (hook.get (),
+ fname_arg.get (),
+ contents_arg.get (),
+ nullptr));
+ if (result == nullptr)
+ {
+ gdbpy_print_stack ();
+ return {};
+ }
+
+ if (!gdbpy_is_string (result.get ()))
+ return {};
+
+ gdbpy_ref<> unic = python_string_to_unicode (result.get ());
+ if (unic == nullptr)
+ {
+ gdbpy_print_stack ();
+ return {};
+ }
+ gdbpy_ref<> host_str (PyUnicode_AsEncodedString (unic.get (),
+ host_charset (),
+ nullptr));
+ if (host_str == nullptr)
+ {
+ gdbpy_print_stack ();
+ return {};
+ }
+
+ return std::string (PyBytes_AsString (host_str.get ()));
+}
+
\f
/* Printing. */
try
{
switch (stream_type)
- {
- case 1:
- {
+ {
+ case 1:
+ {
fprintf_filtered (gdb_stderr, "%s", arg);
break;
- }
- case 2:
- {
+ }
+ case 2:
+ {
fprintf_filtered (gdb_stdlog, "%s", arg);
break;
- }
- default:
- fprintf_filtered (gdb_stdout, "%s", arg);
- }
+ }
+ default:
+ fprintf_filtered (gdb_stdout, "%s", arg);
+ }
}
catch (const gdb_exception &except)
{
PyErr_Clear ();
}
else
- fprintf_filtered (gdb_stderr, "Python Exception %s %s: \n",
+ fprintf_filtered (gdb_stderr, "Python Exception %s: %s\n",
type.get (), msg.get ());
}
catch (const gdb_exception &except)
static PyObject *
gdbpy_progspaces (PyObject *unused1, PyObject *unused2)
{
- struct program_space *ps;
-
gdbpy_ref<> list (PyList_New (0));
if (list == NULL)
return NULL;
- ALL_PSPACES (ps)
- {
- gdbpy_ref<> item = pspace_to_pspace_object (ps);
+ for (struct program_space *ps : program_spaces)
+ {
+ gdbpy_ref<> item = pspace_to_pspace_object (ps);
- if (item == NULL || PyList_Append (list.get (), item.get ()) == -1)
- return NULL;
- }
+ if (item == NULL || PyList_Append (list.get (), item.get ()) == -1)
+ return NULL;
+ }
return list.release ();
}
if (!gdb_python_initialized)
return;
- gdbpy_enter enter_py (get_objfile_arch (objfile), current_language);
- gdbpy_current_objfile = objfile;
+ gdbpy_enter enter_py (objfile->arch (), current_language);
+ scoped_restore restire_current_objfile
+ = make_scoped_restore (&gdbpy_current_objfile, objfile);
python_run_simple_file (file, filename);
-
- gdbpy_current_objfile = NULL;
}
/* Set the current objfile to OBJFILE and then execute SCRIPT
if (!gdb_python_initialized)
return;
- gdbpy_enter enter_py (get_objfile_arch (objfile), current_language);
- gdbpy_current_objfile = objfile;
+ gdbpy_enter enter_py (objfile->arch (), current_language);
+ scoped_restore restire_current_objfile
+ = make_scoped_restore (&gdbpy_current_objfile, objfile);
PyRun_SimpleString (script);
-
- gdbpy_current_objfile = NULL;
}
/* Return the current Objfile, or None if there isn't one. */
#endif /* HAVE_PYTHON */
-\f
+/* When this is turned on before Python is initialised then Python will
+ ignore any environment variables related to Python. This is equivalent
+ to passing `-E' to the python program. */
+static bool python_ignore_environment = false;
-/* Lists for 'set python' commands. */
+/* Implement 'show python ignore-environment'. */
-static struct cmd_list_element *user_set_python_list;
-static struct cmd_list_element *user_show_python_list;
+static void
+show_python_ignore_environment (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("Python's ignore-environment setting is %s.\n"),
+ value);
+}
-/* Function for use by 'set python' prefix command. */
+/* Implement 'set python ignore-environment'. This sets Python's internal
+ flag no matter when the command is issued, however, if this is used
+ after Py_Initialize has been called then most of the environment will
+ already have been read. */
static void
-user_set_python (const char *args, int from_tty)
+set_python_ignore_environment (const char *args, int from_tty,
+ struct cmd_list_element *c)
{
- help_list (user_set_python_list, "set python ", all_commands,
- gdb_stdout);
+#ifdef HAVE_PYTHON
+ Py_IgnoreEnvironmentFlag = python_ignore_environment ? 1 : 0;
+#endif
}
-/* Function for use by 'show python' prefix command. */
+/* When this is turned on before Python is initialised then Python will
+ not write `.pyc' files on import of a module. */
+static enum auto_boolean python_dont_write_bytecode = AUTO_BOOLEAN_AUTO;
+
+/* Implement 'show python dont-write-bytecode'. */
static void
-user_show_python (const char *args, int from_tty)
+show_python_dont_write_bytecode (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
{
- cmd_show_list (user_show_python_list, from_tty, "");
+ if (python_dont_write_bytecode == AUTO_BOOLEAN_AUTO)
+ {
+ const char *auto_string
+ = (python_ignore_environment
+ || getenv ("PYTHONDONTWRITEBYTECODE") == nullptr) ? "off" : "on";
+
+ fprintf_filtered (file,
+ _("Python's dont-write-bytecode setting is %s (currently %s).\n"),
+ value, auto_string);
+ }
+ else
+ fprintf_filtered (file, _("Python's dont-write-bytecode setting is %s.\n"),
+ value);
+}
+
+/* Implement 'set python dont-write-bytecode'. This sets Python's internal
+ flag no matter when the command is issued, however, if this is used
+ after Py_Initialize has been called then many modules could already
+ have been imported and their byte code written out. */
+
+static void
+set_python_dont_write_bytecode (const char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+#ifdef HAVE_PYTHON
+ if (python_dont_write_bytecode == AUTO_BOOLEAN_AUTO)
+ Py_DontWriteBytecodeFlag
+ = (!python_ignore_environment
+ && getenv ("PYTHONDONTWRITEBYTECODE") != nullptr) ? 1 : 0;
+ else
+ Py_DontWriteBytecodeFlag
+ = python_dont_write_bytecode == AUTO_BOOLEAN_TRUE ? 1 : 0;
+#endif /* HAVE_PYTHON */
}
+\f
+
+/* Lists for 'set python' commands. */
+
+static struct cmd_list_element *user_set_python_list;
+static struct cmd_list_element *user_show_python_list;
+
/* Initialize the Python code. */
#ifdef HAVE_PYTHON
Py_Finalize ();
+ gdb_python_initialized = false;
restore_active_ext_lang (previous_active);
}
#ifdef IS_PY3K
+static struct PyModuleDef python_GdbModuleDef =
+{
+ PyModuleDef_HEAD_INIT,
+ "_gdb",
+ NULL,
+ -1,
+ python_GdbMethods,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
/* This is called via the PyImport_AppendInittab mechanism called
during initialization, to make the built-in _gdb module known to
Python. */
static bool
do_start_initialization ()
{
-#ifdef IS_PY3K
- size_t progsize, count;
- /* Python documentation indicates that the memory given
- to Py_SetProgramName cannot be freed. However, it seems that
- at least Python 3.7.4 Py_SetProgramName takes a copy of the
- given program_name. Making progname_copy static and not release
- the memory avoids a leak report for Python versions that duplicate
- program_name, and respect the requirement of Py_SetProgramName
- for Python versions that do not duplicate program_name. */
- static wchar_t *progname_copy;
-#endif
-
#ifdef WITH_PYTHON_PATH
/* Work around problem where python gets confused about where it is,
and then can't find its libraries, etc.
(concat (ldirname (python_libdir.c_str ()).c_str (), SLASH_STRING, "bin",
SLASH_STRING, "python", (char *) NULL));
#ifdef IS_PY3K
+ /* Python documentation indicates that the memory given
+ to Py_SetProgramName cannot be freed. However, it seems that
+ at least Python 3.7.4 Py_SetProgramName takes a copy of the
+ given program_name. Making progname_copy static and not release
+ the memory avoids a leak report for Python versions that duplicate
+ program_name, and respect the requirement of Py_SetProgramName
+ for Python versions that do not duplicate program_name. */
+ static wchar_t *progname_copy;
+
std::string oldloc = setlocale (LC_ALL, NULL);
setlocale (LC_ALL, "");
- progsize = strlen (progname.get ());
- progname_copy = (wchar_t *) xmalloc ((progsize + 1) * sizeof (wchar_t));
- if (!progname_copy)
- {
- fprintf (stderr, "out of memory\n");
- return false;
- }
- count = mbstowcs (progname_copy, progname.get (), progsize + 1);
+ size_t progsize = strlen (progname.get ());
+ progname_copy = XNEWVEC (wchar_t, progsize + 1);
+ size_t count = mbstowcs (progname_copy, progname.get (), progsize + 1);
if (count == (size_t) -1)
{
fprintf (stderr, "Could not convert python path to string\n");
#endif
Py_Initialize ();
+#if PY_VERSION_HEX < 0x03090000
+ /* PyEval_InitThreads became deprecated in Python 3.9 and will
+ be removed in Python 3.11. Prior to Python 3.7, this call was
+ required to initialize the GIL. */
PyEval_InitThreads ();
+#endif
#ifdef IS_PY3K
gdb_module = PyImport_ImportModule ("_gdb");
|| gdbpy_initialize_py_events () < 0
|| gdbpy_initialize_event () < 0
|| gdbpy_initialize_arch () < 0
+ || gdbpy_initialize_registers () < 0
|| gdbpy_initialize_xmethods () < 0
- || gdbpy_initialize_unwind () < 0)
+ || gdbpy_initialize_unwind () < 0
+ || gdbpy_initialize_tui () < 0)
return false;
#define GDB_PY_DEFINE_EVENT_TYPE(name, py_name, doc, base) \
return false;
/* Release the GIL while gdb runs. */
- PyThreadState_Swap (NULL);
- PyEval_ReleaseLock ();
+ PyEval_SaveThread ();
make_final_cleanup (finalize_python, NULL);
add_com_alias ("py", "python", class_obscure, 1);
/* Add set/show python print-stack. */
- add_prefix_cmd ("python", no_class, user_show_python,
- _("Prefix command for python preference settings."),
- &user_show_python_list, "show python ", 0,
- &showlist);
+ add_basic_prefix_cmd ("python", no_class,
+ _("Prefix command for python preference settings."),
+ &user_show_python_list, "show python ", 0,
+ &showlist);
- add_prefix_cmd ("python", no_class, user_set_python,
- _("Prefix command for python preference settings."),
- &user_set_python_list, "set python ", 0,
- &setlist);
+ add_show_prefix_cmd ("python", no_class,
+ _("Prefix command for python preference settings."),
+ &user_set_python_list, "set python ", 0,
+ &setlist);
add_setshow_enum_cmd ("print-stack", no_class, python_excp_enums,
&gdbpy_should_print_stack, _("\
&user_set_python_list,
&user_show_python_list);
-#ifdef HAVE_PYTHON
- if (!do_start_initialization () && PyErr_Occurred ())
- gdbpy_print_stack ();
-#endif /* HAVE_PYTHON */
+ add_setshow_boolean_cmd ("ignore-environment", no_class,
+ &python_ignore_environment, _("\
+Set whether the Python interpreter should ignore environment variables."), _(" \
+Show whether the Python interpreter showlist ignore environment variables."), _(" \
+When enabled GDB's Python interpreter will ignore any Python related\n \
+flags in the environment. This is equivalent to passing `-E' to a\n \
+python executable."),
+ set_python_ignore_environment,
+ show_python_ignore_environment,
+ &user_set_python_list,
+ &user_show_python_list);
+
+ add_setshow_auto_boolean_cmd ("dont-write-bytecode", no_class,
+ &python_dont_write_bytecode, _("\
+Set whether the Python interpreter should ignore environment variables."), _(" \
+Show whether the Python interpreter showlist ignore environment variables."), _(" \
+When enabled GDB's Python interpreter will ignore any Python related\n \
+flags in the environment. This is equivalent to passing `-E' to a\n \
+python executable."),
+ set_python_dont_write_bytecode,
+ show_python_dont_write_bytecode,
+ &user_set_python_list,
+ &user_show_python_list);
}
#ifdef HAVE_PYTHON
-/* Helper function for gdbpy_finish_initialization. This does the
- work and then returns false if an error has occurred and must be
- displayed, or true on success. */
+/* Helper function for gdbpy_initialize. This does the work and then
+ returns false if an error has occurred and must be displayed, or true on
+ success. */
static bool
-do_finish_initialization (const struct extension_language_defn *extlang)
+do_initialize (const struct extension_language_defn *extlang)
{
PyObject *m;
PyObject *sys_path;
return gdb_pymodule_addobject (m, "gdb", gdb_python_module) >= 0;
}
-/* Perform the remaining python initializations.
- These must be done after GDB is at least mostly initialized.
- E.g., The "info pretty-printer" command needs the "info" prefix
- command installed.
- This is the extension_language_ops.finish_initialization "method". */
+/* Perform Python initialization. This will be called after GDB has
+ performed all of its own initialization. This is the
+ extension_language_ops.initialize "method". */
static void
-gdbpy_finish_initialization (const struct extension_language_defn *extlang)
+gdbpy_initialize (const struct extension_language_defn *extlang)
{
+ if (!do_start_initialization () && PyErr_Occurred ())
+ gdbpy_print_stack ();
+
gdbpy_enter enter_py (get_current_arch (), current_language);
- if (!do_finish_initialization (extlang))
+ if (!do_initialize (extlang))
{
gdbpy_print_stack ();
warning (_("internal error: Unhandled Python exception"));
return gdb_python_initialized;
}
-#endif /* HAVE_PYTHON */
-
-\f
-
-#ifdef HAVE_PYTHON
-
PyMethodDef python_GdbMethods[] =
{
{ "history", gdbpy_history, METH_VARARGS,
"convenience_variable (NAME, VALUE) -> None.\n\
Set the value of the convenience variable $NAME." },
- {NULL, NULL, 0, NULL}
-};
+#ifdef TUI
+ { "register_window_type", (PyCFunction) gdbpy_register_tui_window,
+ METH_VARARGS | METH_KEYWORDS,
+ "register_window_type (NAME, CONSTRUCSTOR) -> None\n\
+Register a TUI window constructor." },
+#endif /* TUI */
-#ifdef IS_PY3K
-struct PyModuleDef python_GdbModuleDef =
-{
- PyModuleDef_HEAD_INIT,
- "_gdb",
- NULL,
- -1,
- python_GdbMethods,
- NULL,
- NULL,
- NULL,
- NULL
+ {NULL, NULL, 0, NULL}
};
-#endif
/* Define all the event objects. */
#define GDB_PY_DEFINE_EVENT_TYPE(name, py_name, doc, base) \
PyTypeObject name##_event_object_type \
- CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("event_object") \
+ CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("event_object") \
= { \
PyVarObject_HEAD_INIT (NULL, 0) \
"gdb." py_name, /* tp_name */ \