/* Python interface to inferiors.
- Copyright (C) 2009-2018 Free Software Foundation, Inc.
+ Copyright (C) 2009-2021 Free Software Foundation, Inc.
This file is part of GDB.
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
+#include "auto-load.h"
#include "gdbcore.h"
#include "gdbthread.h"
#include "inferior.h"
#include "python-internal.h"
#include "arch-utils.h"
#include "language.h"
-#include "gdb_signals.h"
+#include "gdbsupport/gdb_signals.h"
#include "py-event.h"
#include "py-stopevent.h"
-struct threadlist_entry {
- thread_object *thread_obj;
+struct threadlist_entry
+{
+ threadlist_entry (gdbpy_ref<thread_object> &&ref)
+ : thread_obj (std::move (ref))
+ {
+ }
+
+ gdbpy_ref<thread_object> thread_obj;
struct threadlist_entry *next;
};
static const struct inferior_data *infpy_inf_data_key;
-typedef struct {
+struct membuf_object {
PyObject_HEAD
void *buffer;
/* These are kept just for mbpy_str. */
CORE_ADDR addr;
CORE_ADDR length;
-} membuf_object;
+};
extern PyTypeObject membuf_object_type
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("membuf_object");
return;
gdbpy_enter enter_py (objfile != NULL
- ? get_objfile_arch (objfile)
+ ? objfile->arch ()
: target_gdbarch (),
current_language);
return it and increment the reference count, otherwise, create it.
Return NULL on failure. */
-inferior_object *
+gdbpy_ref<inferior_object>
inferior_to_inferior_object (struct inferior *inferior)
{
inferior_object *inf_obj;
{
inf_obj = PyObject_New (inferior_object, &inferior_object_type);
if (!inf_obj)
- return NULL;
+ return NULL;
inf_obj->inferior = inferior;
inf_obj->threads = NULL;
/* PyObject_New initializes the new object with a refcount of 1. This
counts for the reference we are keeping in the inferior data. */
set_inferior_data (inferior, infpy_inf_data_key, inf_obj);
-
}
/* We are returning a new reference. */
- Py_INCREF ((PyObject *)inf_obj);
-
- return inf_obj;
+ gdb_assert (inf_obj != nullptr);
+ return gdbpy_ref<inferior_object>::new_reference (inf_obj);
}
/* Called when a new inferior is created. Notifies any Python event
if (evregpy_no_listeners_p (gdb_py_events.new_inferior))
return;
- gdbpy_ref<inferior_object> inf_obj (inferior_to_inferior_object (inf));
+ gdbpy_ref<inferior_object> inf_obj = inferior_to_inferior_object (inf);
if (inf_obj == NULL)
{
gdbpy_print_stack ();
if (evregpy_no_listeners_p (gdb_py_events.inferior_deleted))
return;
- gdbpy_ref<inferior_object> inf_obj (inferior_to_inferior_object (inf));
+ gdbpy_ref<inferior_object> inf_obj = inferior_to_inferior_object (inf);
if (inf_obj == NULL)
{
gdbpy_print_stack ();
gdbpy_ref<>
thread_to_thread_object (thread_info *thr)
{
- gdbpy_ref<inferior_object> inf_obj (inferior_to_inferior_object (thr->inf));
+ gdbpy_ref<inferior_object> inf_obj = inferior_to_inferior_object (thr->inf);
if (inf_obj == NULL)
return NULL;
thread != NULL;
thread = thread->next)
if (thread->thread_obj->thread == thr)
- return gdbpy_ref<>::new_reference ((PyObject *) thread->thread_obj);
+ return gdbpy_ref<>::new_reference ((PyObject *) thread->thread_obj.get ());
PyErr_SetString (PyExc_SystemError,
_("could not find gdb thread object"));
static void
add_thread_object (struct thread_info *tp)
{
- thread_object *thread_obj;
inferior_object *inf_obj;
struct threadlist_entry *entry;
gdbpy_enter enter_py (python_gdbarch, python_language);
- thread_obj = create_thread_object (tp);
- if (!thread_obj)
+ gdbpy_ref<thread_object> thread_obj = create_thread_object (tp);
+ if (thread_obj == NULL)
{
gdbpy_print_stack ();
return;
inf_obj = (inferior_object *) thread_obj->inf_obj;
- entry = XNEW (struct threadlist_entry);
- entry->thread_obj = thread_obj;
+ entry = new threadlist_entry (std::move (thread_obj));
entry->next = inf_obj->threads;
inf_obj->threads = entry;
return;
gdbpy_ref<> event = create_thread_event_object (&new_thread_event_object_type,
- (PyObject *) thread_obj);
+ (PyObject *) inf_obj);
if (event == NULL
|| evpy_emit_event (event.get (), gdb_py_events.new_thread) < 0)
gdbpy_print_stack ();
gdbpy_enter enter_py (python_gdbarch, python_language);
- gdbpy_ref<inferior_object> inf_obj
- ((inferior_object *) inferior_to_inferior_object (tp->inf));
+ gdbpy_ref<inferior_object> inf_obj = inferior_to_inferior_object (tp->inf);
if (inf_obj == NULL)
return;
*entry = (*entry)->next;
inf_obj->nthreads--;
- Py_DECREF (tmp->thread_obj);
- xfree (tmp);
+ delete tmp;
}
static PyObject *
INFPY_REQUIRE_VALID (inf_obj);
- TRY
+ try
{
update_thread_list ();
}
- CATCH (except, RETURN_MASK_ALL)
+ catch (const gdb_exception &except)
{
GDB_PY_HANDLE_EXCEPTION (except);
}
- END_CATCH
tuple = PyTuple_New (inf_obj->nthreads);
if (!tuple)
for (i = 0, entry = inf_obj->threads; i < inf_obj->nthreads;
i++, entry = entry->next)
{
- Py_INCREF (entry->thread_obj);
- PyTuple_SET_ITEM (tuple, i, (PyObject *) entry->thread_obj);
+ PyObject *thr = (PyObject *) entry->thread_obj.get ();
+ Py_INCREF (thr);
+ PyTuple_SET_ITEM (tuple, i, thr);
}
return tuple;
INFPY_REQUIRE_VALID (inf);
- return PyLong_FromLong (inf->inferior->num);
+ return gdb_py_object_from_longest (inf->inferior->num).release ();
+}
+
+/* Return the connection number of the given inferior, or None if a
+ connection does not exist. */
+
+static PyObject *
+infpy_get_connection_num (PyObject *self, void *closure)
+{
+ inferior_object *inf = (inferior_object *) self;
+
+ INFPY_REQUIRE_VALID (inf);
+
+ process_stratum_target *target = inf->inferior->process_target ();
+ if (target == nullptr)
+ Py_RETURN_NONE;
+
+ return PyLong_FromLong (target->connection_number);
}
static PyObject *
INFPY_REQUIRE_VALID (inf);
- return PyLong_FromLong (inf->inferior->pid);
+ return gdb_py_object_from_longest (inf->inferior->pid).release ();
}
static PyObject *
return pspace_to_pspace_object (pspace).release ();
}
-static int
-build_inferior_list (struct inferior *inf, void *arg)
-{
- PyObject *list = (PyObject *) arg;
- gdbpy_ref<inferior_object> inferior (inferior_to_inferior_object (inf));
-
- if (inferior == NULL)
- return 0;
-
- return PyList_Append (list, (PyObject *) inferior.get ()) ? 1 : 0;
-}
-
/* Implementation of gdb.inferiors () -> (gdb.Inferior, ...).
Returns a tuple of all inferiors. */
PyObject *
if (list == NULL)
return NULL;
- if (iterate_over_inferiors (build_inferior_list, list.get ()))
- return NULL;
+ for (inferior *inf : all_inferiors ())
+ {
+ gdbpy_ref<inferior_object> inferior = inferior_to_inferior_object (inf);
+
+ if (inferior == NULL)
+ continue;
+
+ if (PyList_Append (list.get (), (PyObject *) inferior.get ()) != 0)
+ return NULL;
+ }
return PyList_AsTuple (list.get ());
}
|| get_addr_from_python (length_obj, &length) < 0)
return NULL;
- TRY
+ try
{
buffer.reset ((gdb_byte *) xmalloc (length));
read_memory (addr, buffer.get (), length);
}
- CATCH (except, RETURN_MASK_ALL)
+ catch (const gdb_exception &except)
{
GDB_PY_HANDLE_EXCEPTION (except);
}
- END_CATCH
gdbpy_ref<membuf_object> membuf_obj (PyObject_New (membuf_object,
&membuf_object_type));
static PyObject *
infpy_write_memory (PyObject *self, PyObject *args, PyObject *kw)
{
- struct gdb_exception except = exception_none;
+ struct gdb_exception except;
Py_ssize_t buf_len;
const gdb_byte *buffer;
CORE_ADDR addr, length;
PyObject *addr_obj, *length_obj = NULL;
static const char *keywords[] = { "address", "buffer", "length", NULL };
-#ifdef IS_PY3K
Py_buffer pybuf;
if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "Os*|O", keywords,
&addr_obj, &pybuf, &length_obj))
return NULL;
+ Py_buffer_up buffer_up (&pybuf);
buffer = (const gdb_byte *) pybuf.buf;
buf_len = pybuf.len;
-#else
- if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "Os#|O", keywords,
- &addr_obj, &buffer, &buf_len,
- &length_obj))
- return NULL;
-
- buffer = (const gdb_byte *) buffer;
-#endif
if (get_addr_from_python (addr_obj, &addr) < 0)
- goto fail;
+ return nullptr;
if (!length_obj)
length = buf_len;
else if (get_addr_from_python (length_obj, &length) < 0)
- goto fail;
+ return nullptr;
- TRY
+ try
{
write_memory_with_notification (addr, buffer, length);
}
- CATCH (ex, RETURN_MASK_ALL)
+ catch (gdb_exception &ex)
{
- except = ex;
+ except = std::move (ex);
}
- END_CATCH
-#ifdef IS_PY3K
- PyBuffer_Release (&pybuf);
-#endif
GDB_PY_HANDLE_EXCEPTION (except);
Py_RETURN_NONE;
-
- fail:
-#ifdef IS_PY3K
- PyBuffer_Release (&pybuf);
-#endif
- return NULL;
}
/* Destructor of Membuf objects. */
static PyObject *
infpy_search_memory (PyObject *self, PyObject *args, PyObject *kw)
{
- struct gdb_exception except = exception_none;
+ struct gdb_exception except;
CORE_ADDR start_addr, length;
static const char *keywords[] = { "address", "length", "pattern", NULL };
PyObject *start_addr_obj, *length_obj;
const gdb_byte *buffer;
CORE_ADDR found_addr;
int found = 0;
-#ifdef IS_PY3K
Py_buffer pybuf;
if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "OOs*", keywords,
&pybuf))
return NULL;
+ Py_buffer_up buffer_up (&pybuf);
buffer = (const gdb_byte *) pybuf.buf;
pattern_size = pybuf.len;
-#else
- PyObject *pattern;
- const void *vbuffer;
-
- if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "OOO", keywords,
- &start_addr_obj, &length_obj,
- &pattern))
- return NULL;
-
- if (!PyObject_CheckReadBuffer (pattern))
- {
- PyErr_SetString (PyExc_RuntimeError,
- _("The pattern is not a Python buffer."));
-
- return NULL;
- }
-
- if (PyObject_AsReadBuffer (pattern, &vbuffer, &pattern_size) == -1)
- return NULL;
-
- buffer = (const gdb_byte *) vbuffer;
-#endif
if (get_addr_from_python (start_addr_obj, &start_addr) < 0)
- goto fail;
+ return nullptr;
if (get_addr_from_python (length_obj, &length) < 0)
- goto fail;
+ return nullptr;
if (!length)
{
PyErr_SetString (PyExc_ValueError,
_("Search range is empty."));
- goto fail;
+ return nullptr;
}
/* Watch for overflows. */
else if (length > CORE_ADDR_MAX
{
PyErr_SetString (PyExc_ValueError,
_("The search range is too large."));
- goto fail;
+ return nullptr;
}
- TRY
+ try
{
found = target_search_memory (start_addr, length,
buffer, pattern_size,
&found_addr);
}
- CATCH (ex, RETURN_MASK_ALL)
+ catch (gdb_exception &ex)
{
- except = ex;
+ except = std::move (ex);
}
- END_CATCH
-#ifdef IS_PY3K
- PyBuffer_Release (&pybuf);
-#endif
GDB_PY_HANDLE_EXCEPTION (except);
if (found)
- return PyLong_FromLong (found_addr);
+ return gdb_py_object_from_ulongest (found_addr).release ();
else
Py_RETURN_NONE;
-
- fail:
-#ifdef IS_PY3K
- PyBuffer_Release (&pybuf);
-#endif
- return NULL;
}
/* Implementation of gdb.Inferior.is_valid (self) -> Boolean.
Py_RETURN_TRUE;
}
-/* Implementation of gdb.Inferior.thread_from_thread_handle (self, handle)
- -> gdb.InferiorThread. */
+/* Implementation of gdb.Inferior.thread_from_handle (self, handle)
+ -> gdb.InferiorThread. */
static PyObject *
infpy_thread_from_thread_handle (PyObject *self, PyObject *args, PyObject *kw)
{
PyObject *handle_obj;
inferior_object *inf_obj = (inferior_object *) self;
- static const char *keywords[] = { "thread_handle", NULL };
+ static const char *keywords[] = { "handle", NULL };
INFPY_REQUIRE_VALID (inf_obj);
if (! gdb_PyArg_ParseTupleAndKeywords (args, kw, "O", keywords, &handle_obj))
return NULL;
- if (!gdbpy_is_value_object (handle_obj))
+ const gdb_byte *bytes;
+ size_t bytes_len;
+ Py_buffer_up buffer_up;
+ Py_buffer py_buf;
+
+ if (PyObject_CheckBuffer (handle_obj)
+ && PyObject_GetBuffer (handle_obj, &py_buf, PyBUF_SIMPLE) == 0)
+ {
+ buffer_up.reset (&py_buf);
+ bytes = (const gdb_byte *) py_buf.buf;
+ bytes_len = py_buf.len;
+ }
+ else if (gdbpy_is_value_object (handle_obj))
+ {
+ struct value *val = value_object_to_value (handle_obj);
+ bytes = value_contents_all (val);
+ bytes_len = TYPE_LENGTH (value_type (val));
+ }
+ else
{
PyErr_SetString (PyExc_TypeError,
- _("Argument 'handle_obj' must be a thread handle object."));
+ _("Argument 'handle' must be a thread handle object."));
return NULL;
}
- TRY
+ try
{
struct thread_info *thread_info;
- struct value *val = value_object_to_value (handle_obj);
- thread_info = find_thread_by_handle (val, inf_obj->inferior);
+ thread_info = find_thread_by_handle
+ (gdb::array_view<const gdb_byte> (bytes, bytes_len),
+ inf_obj->inferior);
if (thread_info != NULL)
return thread_to_thread_object (thread_info).release ();
}
- CATCH (except, RETURN_MASK_ALL)
+ catch (const gdb_exception &except)
{
GDB_PY_HANDLE_EXCEPTION (except);
}
- END_CATCH
Py_RETURN_NONE;
}
return;
set_inferior_data (inf, infpy_inf_data_key, NULL);
+ Py_TYPE (obj)->tp_free (obj);
}
/* Clear the INFERIOR pointer in an Inferior object and clear the
static void
py_free_inferior (struct inferior *inf, void *datum)
{
- gdbpy_ref<inferior_object> inf_obj ((inferior_object *) datum);
struct threadlist_entry *th_entry, *th_tmp;
if (!gdb_python_initialized)
return;
gdbpy_enter enter_py (python_gdbarch, python_language);
+ gdbpy_ref<inferior_object> inf_obj ((inferior_object *) datum);
inf_obj->inferior = NULL;
/* Deallocate threads list. */
for (th_entry = inf_obj->threads; th_entry != NULL;)
{
- Py_DECREF (th_entry->thread_obj);
-
th_tmp = th_entry;
th_entry = th_entry->next;
- xfree (th_tmp);
+ delete th_tmp;
}
inf_obj->nthreads = 0;
PyObject *
gdbpy_selected_inferior (PyObject *self, PyObject *args)
{
- return (PyObject *) inferior_to_inferior_object (current_inferior ());
+ return ((PyObject *)
+ inferior_to_inferior_object (current_inferior ()).release ());
+}
+
+void _initialize_py_inferior ();
+void
+_initialize_py_inferior ()
+{
+ infpy_inf_data_key =
+ register_inferior_data_with_cleanup (NULL, py_free_inferior);
}
int
(PyObject *) &inferior_object_type) < 0)
return -1;
- infpy_inf_data_key =
- register_inferior_data_with_cleanup (NULL, py_free_inferior);
-
- gdb::observers::new_thread.attach (add_thread_object);
- gdb::observers::thread_exit.attach (delete_thread_object);
- gdb::observers::normal_stop.attach (python_on_normal_stop);
- gdb::observers::target_resumed.attach (python_on_resume);
- gdb::observers::inferior_call_pre.attach (python_on_inferior_call_pre);
- gdb::observers::inferior_call_post.attach (python_on_inferior_call_post);
- gdb::observers::memory_changed.attach (python_on_memory_change);
- gdb::observers::register_changed.attach (python_on_register_change);
- gdb::observers::inferior_exit.attach (python_inferior_exit);
- gdb::observers::new_objfile.attach (python_new_objfile);
- gdb::observers::inferior_added.attach (python_new_inferior);
- gdb::observers::inferior_removed.attach (python_inferior_deleted);
+ gdb::observers::new_thread.attach (add_thread_object, "py-inferior");
+ gdb::observers::thread_exit.attach (delete_thread_object, "py-inferior");
+ gdb::observers::normal_stop.attach (python_on_normal_stop, "py-inferior");
+ gdb::observers::target_resumed.attach (python_on_resume, "py-inferior");
+ gdb::observers::inferior_call_pre.attach (python_on_inferior_call_pre,
+ "py-inferior");
+ gdb::observers::inferior_call_post.attach (python_on_inferior_call_post,
+ "py-inferior");
+ gdb::observers::memory_changed.attach (python_on_memory_change,
+ "py-inferior");
+ gdb::observers::register_changed.attach (python_on_register_change,
+ "py-inferior");
+ gdb::observers::inferior_exit.attach (python_inferior_exit, "py-inferior");
+ /* Need to run after auto-load's new_objfile observer, so that
+ auto-loaded pretty-printers are available. */
+ gdb::observers::new_objfile.attach
+ (python_new_objfile, "py-inferior",
+ { &auto_load_new_objfile_observer_token });
+ gdb::observers::inferior_added.attach (python_new_inferior, "py-inferior");
+ gdb::observers::inferior_removed.attach (python_inferior_deleted,
+ "py-inferior");
membuf_object_type.tp_new = PyType_GenericNew;
if (PyType_Ready (&membuf_object_type) < 0)
return -1;
- return gdb_pymodule_addobject (gdb_module, "Membuf", (PyObject *)
- &membuf_object_type);
+ return gdb_pymodule_addobject (gdb_module, "Membuf",
+ (PyObject *) &membuf_object_type);
}
static gdb_PyGetSetDef inferior_object_getset[] =
{
{ "num", infpy_get_num, NULL, "ID of inferior, as assigned by GDB.", NULL },
+ { "connection_num", infpy_get_connection_num, NULL,
+ "ID of inferior's connection, as assigned by GDB.", NULL },
{ "pid", infpy_get_pid, NULL, "PID of inferior, as assigned by the OS.",
NULL },
{ "was_attached", infpy_get_was_attached, NULL,
METH_VARARGS | METH_KEYWORDS,
"search_memory (address, length, pattern) -> long\n\
Return a long with the address of a match, or None." },
+ /* thread_from_thread_handle is deprecated. */
{ "thread_from_thread_handle", (PyCFunction) infpy_thread_from_thread_handle,
METH_VARARGS | METH_KEYWORDS,
"thread_from_thread_handle (handle) -> gdb.InferiorThread.\n\
+Return thread object corresponding to thread handle.\n\
+This method is deprecated - use thread_from_handle instead." },
+ { "thread_from_handle", (PyCFunction) infpy_thread_from_thread_handle,
+ METH_VARARGS | METH_KEYWORDS,
+ "thread_from_handle (handle) -> gdb.InferiorThread.\n\
Return thread object corresponding to thread handle." },
{ "architecture", (PyCFunction) infpy_architecture, METH_NOARGS,
"architecture () -> gdb.Architecture\n\
#else
-/* Python doesn't provide a decent way to get compatibility here. */
-#if HAVE_LIBPYTHON2_4
-#define CHARBUFFERPROC_NAME getcharbufferproc
-#else
-#define CHARBUFFERPROC_NAME charbufferproc
-#endif
-
static PyBufferProcs buffer_procs = {
get_read_buffer,
get_write_buffer,
get_seg_count,
- /* The cast here works around a difference between Python 2.4 and
- Python 2.5. */
- (CHARBUFFERPROC_NAME) get_char_buffer
+ get_char_buffer
};
#endif /* IS_PY3K */