/* General python/gdb code
- Copyright (C) 2008-2019 Free Software Foundation, Inc.
+ Copyright (C) 2008-2020 Free Software Foundation, Inc.
This file is part of GDB.
#include "objfiles.h"
#include "value.h"
#include "language.h"
-#include "event-loop.h"
-#include "serial.h"
+#include "gdbsupport/event-loop.h"
#include "readline/tilde.h"
#include "python.h"
#include "extension-priv.h"
#include "cli/cli-utils.h"
#include <ctype.h>
#include "location.h"
-#include "ser-event.h"
+#include "run-on-main-thread.h"
/* Declared constants and enum for python stack printing. */
static const char python_excp_none[] = "none";
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. */
gdbpy_before_prompt_hook,
gdbpy_get_matching_xmethod_workers,
+
+ gdbpy_colorize,
};
/* Architecture and language to be used in callbacks from
m_error->restore ();
- PyGILState_Release (m_state);
python_gdbarch = m_gdbarch;
python_language = m_language;
restore_active_ext_lang (m_previous_active);
+ 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);
}
static PyObject *
gdbpy_rbreak (PyObject *self, PyObject *args, PyObject *kw)
{
- /* A simple type to ensure clean up of a vector of allocated strings
- when a C interface demands a const char *array[] type
- interface. */
- struct symtab_list_type
- {
- ~symtab_list_type ()
- {
- for (const char *elem: vec)
- xfree ((void *) elem);
- }
- std::vector<const char *> vec;
- };
-
char *regex = NULL;
std::vector<symbol_search> symbols;
unsigned long count = 0;
unsigned int throttle = 0;
static const char *keywords[] = {"regex","minsyms", "throttle",
"symtabs", NULL};
- symtab_list_type symtab_paths;
if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s|O!IO", keywords,
®ex, &PyBool_Type,
minsyms_p = cmp;
}
+ global_symbol_searcher spec (FUNCTIONS_DOMAIN, regex);
+ SCOPE_EXIT {
+ for (const char *elem : spec.filenames)
+ xfree ((void *) elem);
+ };
+
/* The "symtabs" keyword is any Python iterable object that returns
a gdb.Symtab on each iteration. If specified, iterate through
the provided gdb.Symtabs and extract their full path. As
/* Make sure there is a definite place to store the value of
filename before it is released. */
- symtab_paths.vec.push_back (nullptr);
- symtab_paths.vec.back () = filename.release ();
+ spec.filenames.push_back (nullptr);
+ spec.filenames.back () = filename.release ();
}
}
- if (symtab_list)
- {
- const char **files = symtab_paths.vec.data ();
-
- symbols = search_symbols (regex, FUNCTIONS_DOMAIN, NULL,
- symtab_paths.vec.size (), files, false);
- }
- else
- symbols = search_symbols (regex, FUNCTIONS_DOMAIN, NULL, 0, NULL, false);
+ /* The search spec. */
+ symbols = spec.search ();
/* Count the number of symbols (both symbols and optionally minimal
symbols) so we can correctly check the throttle limit. */
symbol_name = fullname;
symbol_name += ":";
- symbol_name += SYMBOL_LINKAGE_NAME (p.symbol);
+ symbol_name += p.symbol->linkage_name ();
}
else
symbol_name = p.msymbol.minsym->linkage_name ();
if (! PyArg_ParseTuple (args, "|s", &arg))
return NULL;
+ /* Treat a string consisting of just whitespace the same as
+ NULL. */
+ if (arg != NULL)
+ {
+ arg = skip_spaces (arg);
+ if (*arg == '\0')
+ arg = NULL;
+ }
+
if (arg != NULL)
location = string_to_event_location_basic (&arg, python_language,
symbol_name_match_type::WILD);
/* A single event. */
struct gdbpy_event
{
- /* The Python event. This is just a callable object. */
- PyObject *event;
- /* The next event. */
- struct gdbpy_event *next;
-};
+ gdbpy_event (gdbpy_ref<> &&func)
+ : m_func (func.release ())
+ {
+ }
-/* All pending events. */
-static struct gdbpy_event *gdbpy_event_list;
-/* The final link of the event list. */
-static struct gdbpy_event **gdbpy_event_list_end;
+ gdbpy_event (gdbpy_event &&other) noexcept
+ : m_func (other.m_func)
+ {
+ other.m_func = nullptr;
+ }
-/* So that we can wake up the main thread even when it is blocked in
- poll(). */
-static struct serial_event *gdbpy_serial_event;
+ gdbpy_event (const gdbpy_event &other)
+ : m_func (other.m_func)
+ {
+ gdbpy_gil gil;
+ Py_XINCREF (m_func);
+ }
-/* The file handler callback. This reads from the internal pipe, and
- then processes the Python event queue. This will always be run in
- the main gdb thread. */
+ ~gdbpy_event ()
+ {
+ gdbpy_gil gil;
+ Py_XDECREF (m_func);
+ }
-static void
-gdbpy_run_events (int error, gdb_client_data client_data)
-{
- gdbpy_enter enter_py (get_current_arch (), current_language);
+ gdbpy_event &operator= (const gdbpy_event &other) = delete;
- /* Clear the event fd. Do this before flushing the events list, so
- that any new event post afterwards is sure to re-awake the event
- loop. */
- serial_event_clear (gdbpy_serial_event);
+ void operator() ()
+ {
+ gdbpy_enter enter_py (get_current_arch (), current_language);
- while (gdbpy_event_list)
- {
- /* Dispatching the event might push a new element onto the event
- loop, so we update here "atomically enough". */
- struct gdbpy_event *item = gdbpy_event_list;
- gdbpy_event_list = gdbpy_event_list->next;
- if (gdbpy_event_list == NULL)
- gdbpy_event_list_end = &gdbpy_event_list;
-
- gdbpy_ref<> call_result (PyObject_CallObject (item->event, NULL));
- if (call_result == NULL)
- gdbpy_print_stack ();
+ gdbpy_ref<> call_result (PyObject_CallObject (m_func, NULL));
+ if (call_result == NULL)
+ gdbpy_print_stack ();
+ }
- Py_DECREF (item->event);
- xfree (item);
- }
-}
+private:
+
+ /* The Python event. This is just a callable object. Note that
+ this is not a gdbpy_ref<>, because we have to take particular
+ care to only destroy the reference when holding the GIL. */
+ PyObject *m_func;
+};
/* Submit an event to the gdb thread. */
static PyObject *
gdbpy_post_event (PyObject *self, PyObject *args)
{
- struct gdbpy_event *event;
PyObject *func;
- int wakeup;
if (!PyArg_ParseTuple (args, "O", &func))
return NULL;
return NULL;
}
- Py_INCREF (func);
-
- /* From here until the end of the function, we have the GIL, so we
- can operate on our global data structures without worrying. */
- wakeup = gdbpy_event_list == NULL;
-
- event = XNEW (struct gdbpy_event);
- event->event = func;
- event->next = NULL;
- *gdbpy_event_list_end = event;
- gdbpy_event_list_end = &event->next;
-
- /* Wake up gdb when needed. */
- if (wakeup)
- serial_event_set (gdbpy_serial_event);
+ gdbpy_ref<> func_ref = gdbpy_ref<>::new_reference (func);
+ gdbpy_event event (std::move (func_ref));
+ run_on_main_thread (event);
Py_RETURN_NONE;
}
-/* Initialize the Python event handler. */
-static int
-gdbpy_initialize_events (void)
-{
- gdbpy_event_list_end = &gdbpy_event_list;
-
- gdbpy_serial_event = make_serial_event ();
- add_file_handler (serial_event_fd (gdbpy_serial_event),
- gdbpy_run_events, NULL);
-
- return 0;
-}
-
\f
/* This is the extension_language_ops.before_prompt "method". */
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)
{
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_enter enter_py (objfile->arch (), current_language);
gdbpy_current_objfile = objfile;
python_run_simple_file (file, filename);
if (!gdb_python_initialized)
return;
- gdbpy_enter enter_py (get_objfile_arch (objfile), current_language);
+ gdbpy_enter enter_py (objfile->arch (), current_language);
gdbpy_current_objfile = objfile;
PyRun_SimpleString (script);
static struct cmd_list_element *user_set_python_list;
static struct cmd_list_element *user_show_python_list;
-/* Function for use by 'set python' prefix command. */
-
-static void
-user_set_python (const char *args, int from_tty)
-{
- help_list (user_set_python_list, "set python ", all_commands,
- gdb_stdout);
-}
-
-/* Function for use by 'show python' prefix command. */
-
-static void
-user_show_python (const char *args, int from_tty)
-{
- cmd_show_list (user_show_python_list, from_tty, "");
-}
-
/* Initialize the Python code. */
#ifdef HAVE_PYTHON
Py_Finalize ();
+ gdb_python_initialized = false;
restore_active_ext_lang (previous_active);
}
/* This is called via the PyImport_AppendInittab mechanism called
during initialization, to make the built-in _gdb module known to
Python. */
+PyMODINIT_FUNC init__gdb_module (void);
PyMODINIT_FUNC
init__gdb_module (void)
{
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;
- }
+ progname_copy = XNEWVEC (wchar_t, progsize + 1);
count = mbstowcs (progname_copy, progname.get (), progsize + 1);
if (count == (size_t) -1)
{
#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_linetable () < 0
|| gdbpy_initialize_thread () < 0
|| gdbpy_initialize_inferior () < 0
- || gdbpy_initialize_events () < 0
|| gdbpy_initialize_eventregistry () < 0
|| 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);
/* See python.h. */
cmd_list_element *python_cmd_element = nullptr;
+void _initialize_python ();
void
-_initialize_python (void)
+_initialize_python ()
{
add_com ("python-interactive", class_obscure,
python_interactive_command,
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, _("\
"convenience_variable (NAME, VALUE) -> None.\n\
Set the value of the convenience variable $NAME." },
+#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 */
+
{NULL, NULL, 0, NULL}
};
/* 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 */ \