/* Python interface to inferiors.
- Copyright (C) 2009-2017 Free Software Foundation, Inc.
+ Copyright (C) 2009-2020 Free Software Foundation, Inc.
This file is part of GDB.
#include "gdbthread.h"
#include "inferior.h"
#include "objfiles.h"
-#include "observer.h"
+#include "observable.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;
};
-typedef struct
+struct inferior_object
{
PyObject_HEAD
/* Number of threads in the list. */
int nthreads;
-} inferior_object;
+};
extern PyTypeObject inferior_object_type
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("inferior_object");
if (!gdb_python_initialized)
return;
- if (!find_thread_ptid (inferior_ptid))
- return;
+ if (inferior_ptid == null_ptid)
+ return;
stop_signal = inferior_thread ()->suspend.stop_signal;
return;
gdbpy_enter enter_py (objfile != NULL
- ? get_objfile_arch (objfile)
+ ? objfile->arch ()
: target_gdbarch (),
current_language);
representing INFERIOR. If the object has already been created,
return it and increment the reference count, otherwise, create it.
Return NULL on failure. */
-PyObject *
+
+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;
inf_obj->nthreads = 0;
+ /* 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);
-
}
- else
- Py_INCREF ((PyObject *)inf_obj);
- return (PyObject *) inf_obj;
+ /* We are returning a new reference. */
+ gdb_assert (inf_obj != nullptr);
+ return gdbpy_ref<inferior_object>::new_reference (inf_obj);
}
-/* Finds the Python Inferior object for the given PID. Returns a
- reference, or NULL if PID does not match any inferior object. */
-
-PyObject *
-find_inferior_object (int pid)
+/* Called when a new inferior is created. Notifies any Python event
+ listeners. */
+static void
+python_new_inferior (struct inferior *inf)
{
- struct inferior *inf = find_inferior_pid (pid);
+ if (!gdb_python_initialized)
+ return;
- if (inf)
- return inferior_to_inferior_object (inf);
+ gdbpy_enter enter_py (python_gdbarch, python_language);
- return NULL;
+ if (evregpy_no_listeners_p (gdb_py_events.new_inferior))
+ return;
+
+ gdbpy_ref<inferior_object> inf_obj = inferior_to_inferior_object (inf);
+ if (inf_obj == NULL)
+ {
+ gdbpy_print_stack ();
+ return;
+ }
+
+ gdbpy_ref<> event = create_event_object (&new_inferior_event_object_type);
+ if (event == NULL
+ || evpy_add_attribute (event.get (), "inferior",
+ (PyObject *) inf_obj.get ()) < 0
+ || evpy_emit_event (event.get (), gdb_py_events.new_inferior) < 0)
+ gdbpy_print_stack ();
}
-thread_object *
-find_thread_object (ptid_t ptid)
+/* Called when an inferior is removed. Notifies any Python event
+ listeners. */
+static void
+python_inferior_deleted (struct inferior *inf)
{
- int pid;
- struct threadlist_entry *thread;
+ if (!gdb_python_initialized)
+ return;
- pid = ptid_get_pid (ptid);
- if (pid == 0)
- return NULL;
+ gdbpy_enter enter_py (python_gdbarch, python_language);
+
+ if (evregpy_no_listeners_p (gdb_py_events.inferior_deleted))
+ return;
+
+ gdbpy_ref<inferior_object> inf_obj = inferior_to_inferior_object (inf);
+ if (inf_obj == NULL)
+ {
+ gdbpy_print_stack ();
+ return;
+ }
- gdbpy_ref inf_obj (find_inferior_object (pid));
+ gdbpy_ref<> event = create_event_object (&inferior_deleted_event_object_type);
+ if (event == NULL
+ || evpy_add_attribute (event.get (), "inferior",
+ (PyObject *) inf_obj.get ()) < 0
+ || evpy_emit_event (event.get (), gdb_py_events.inferior_deleted) < 0)
+ gdbpy_print_stack ();
+}
+
+gdbpy_ref<>
+thread_to_thread_object (thread_info *thr)
+{
+ gdbpy_ref<inferior_object> inf_obj = inferior_to_inferior_object (thr->inf);
if (inf_obj == NULL)
return NULL;
- for (thread = ((inferior_object *)(inf_obj.get ()))->threads; thread;
+ for (threadlist_entry *thread = inf_obj->threads;
+ thread != NULL;
thread = thread->next)
- if (ptid_equal (thread->thread_obj->thread->ptid, ptid))
- return thread->thread_obj;
+ if (thread->thread_obj->thread == thr)
+ return gdbpy_ref<>::new_reference ((PyObject *) thread->thread_obj.get ());
+ PyErr_SetString (PyExc_SystemError,
+ _("could not find gdb thread object"));
return NULL;
}
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;
inf_obj->nthreads++;
+
+ if (evregpy_no_listeners_p (gdb_py_events.new_thread))
+ return;
+
+ gdbpy_ref<> event = create_thread_event_object (&new_thread_event_object_type,
+ (PyObject *) inf_obj);
+ if (event == NULL
+ || evpy_emit_event (event.get (), gdb_py_events.new_thread) < 0)
+ gdbpy_print_stack ();
}
static void
delete_thread_object (struct thread_info *tp, int ignore)
{
- inferior_object *inf_obj;
struct threadlist_entry **entry, *tmp;
if (!gdb_python_initialized)
gdbpy_enter enter_py (python_gdbarch, python_language);
- inf_obj
- = (inferior_object *) find_inferior_object (ptid_get_pid (tp->ptid));
- if (!inf_obj)
+ gdbpy_ref<inferior_object> inf_obj = inferior_to_inferior_object (tp->inf);
+ if (inf_obj == NULL)
return;
/* Find thread entry in its inferior's thread_list. */
break;
if (!*entry)
- {
- Py_DECREF (inf_obj);
- return;
- }
+ return;
tmp = *entry;
tmp->thread_obj->thread = NULL;
*entry = (*entry)->next;
inf_obj->nthreads--;
- Py_DECREF (tmp->thread_obj);
- Py_DECREF (inf_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;
Py_RETURN_FALSE;
}
-static int
-build_inferior_list (struct inferior *inf, void *arg)
+/* Getter of gdb.Inferior.progspace. */
+
+static PyObject *
+infpy_get_progspace (PyObject *self, void *closure)
{
- PyObject *list = (PyObject *) arg;
- gdbpy_ref inferior (inferior_to_inferior_object (inf));
+ inferior_object *inf = (inferior_object *) self;
- if (inferior == NULL)
- return 0;
+ INFPY_REQUIRE_VALID (inf);
+
+ program_space *pspace = inf->inferior->pspace;
+ gdb_assert (pspace != nullptr);
- return PyList_Append (list, inferior.get ()) ? 1 : 0;
+ return pspace_to_pspace_object (pspace).release ();
}
/* Implementation of gdb.inferiors () -> (gdb.Inferior, ...).
PyObject *
gdbpy_inferiors (PyObject *unused, PyObject *unused2)
{
- gdbpy_ref list (PyList_New (0));
+ gdbpy_ref<> list (PyList_New (0));
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 ());
}
infpy_read_memory (PyObject *self, PyObject *args, PyObject *kw)
{
CORE_ADDR addr, length;
- gdb_byte *buffer = NULL;
- membuf_object *membuf_obj;
+ gdb::unique_xmalloc_ptr<gdb_byte> buffer;
PyObject *addr_obj, *length_obj, *result;
- static char *keywords[] = { "address", "length", NULL };
+ static const char *keywords[] = { "address", "length", NULL };
- if (! PyArg_ParseTupleAndKeywords (args, kw, "OO", keywords,
- &addr_obj, &length_obj))
+ if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "OO", keywords,
+ &addr_obj, &length_obj))
return NULL;
if (get_addr_from_python (addr_obj, &addr) < 0
|| get_addr_from_python (length_obj, &length) < 0)
return NULL;
- TRY
+ try
{
- buffer = (gdb_byte *) xmalloc (length);
+ buffer.reset ((gdb_byte *) xmalloc (length));
- read_memory (addr, buffer, length);
+ read_memory (addr, buffer.get (), length);
}
- CATCH (except, RETURN_MASK_ALL)
+ catch (const gdb_exception &except)
{
- xfree (buffer);
GDB_PY_HANDLE_EXCEPTION (except);
}
- END_CATCH
- membuf_obj = PyObject_New (membuf_object, &membuf_object_type);
+ gdbpy_ref<membuf_object> membuf_obj (PyObject_New (membuf_object,
+ &membuf_object_type));
if (membuf_obj == NULL)
- {
- xfree (buffer);
- return NULL;
- }
+ return NULL;
- membuf_obj->buffer = buffer;
+ membuf_obj->buffer = buffer.release ();
membuf_obj->addr = addr;
membuf_obj->length = length;
#ifdef IS_PY3K
- result = PyMemoryView_FromObject ((PyObject *) membuf_obj);
+ result = PyMemoryView_FromObject ((PyObject *) membuf_obj.get ());
#else
- result = PyBuffer_FromReadWriteObject ((PyObject *) membuf_obj, 0,
+ result = PyBuffer_FromReadWriteObject ((PyObject *) membuf_obj.get (), 0,
Py_END_OF_BUFFER);
#endif
- Py_DECREF (membuf_obj);
return result;
}
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 char *keywords[] = { "address", "buffer", "length", NULL };
-#ifdef IS_PY3K
+ static const char *keywords[] = { "address", "buffer", "length", NULL };
Py_buffer pybuf;
- if (! PyArg_ParseTupleAndKeywords (args, kw, "Os*|O", keywords,
- &addr_obj, &pybuf,
- &length_obj))
+ 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 (! 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. */
ret = PyBuffer_FillInfo (buf, self, membuf_obj->buffer,
membuf_obj->length, 0,
PyBUF_CONTIG);
- buf->format = "c";
+
+ /* Despite the documentation saying this field is a "const char *",
+ in Python 3.4 at least, it's really a "char *". */
+ buf->format = (char *) "c";
return ret;
}
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 char *keywords[] = { "address", "length", "pattern", NULL };
+ static const char *keywords[] = { "address", "length", "pattern", NULL };
PyObject *start_addr_obj, *length_obj;
Py_ssize_t pattern_size;
const gdb_byte *buffer;
CORE_ADDR found_addr;
int found = 0;
-#ifdef IS_PY3K
Py_buffer pybuf;
- if (! PyArg_ParseTupleAndKeywords (args, kw, "OOs*", keywords,
- &start_addr_obj, &length_obj,
- &pybuf))
+ if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "OOs*", keywords,
+ &start_addr_obj, &length_obj,
+ &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 (! 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);
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_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[] = { "handle", NULL };
+
+ INFPY_REQUIRE_VALID (inf_obj);
+
+ if (! gdb_PyArg_ParseTupleAndKeywords (args, kw, "O", keywords, &handle_obj))
+ return NULL;
+
+ 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' must be a thread handle object."));
+
+ return NULL;
+ }
+
+ try
+ {
+ struct thread_info *thread_info;
+
+ 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 (const gdb_exception &except)
+ {
+ GDB_PY_HANDLE_EXCEPTION (except);
+ }
+
+ Py_RETURN_NONE;
+}
+
+/* Implementation of gdb.Inferior.architecture. */
+
+static PyObject *
+infpy_architecture (PyObject *self, PyObject *args)
+{
+ inferior_object *inf = (inferior_object *) self;
+
+ INFPY_REQUIRE_VALID (inf);
+
+ return gdbarch_to_arch_object (inf->inferior->gdbarch);
+}
+
+/* Implement repr() for gdb.Inferior. */
+
+static PyObject *
+infpy_repr (PyObject *obj)
+{
+ inferior_object *self = (inferior_object *) obj;
+ inferior *inf = self->inferior;
+
+ if (inf == nullptr)
+ return PyString_FromString ("<gdb.Inferior (invalid)>");
+
+ return PyString_FromFormat ("<gdb.Inferior num=%d, pid=%d>",
+ inf->num, inf->pid);
+}
+
+
static void
infpy_dealloc (PyObject *obj)
{
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)
{
- 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;
-
- Py_DECREF ((PyObject *) inf_obj);
}
/* Implementation of gdb.selected_inferior() -> gdb.Inferior.
PyObject *
gdbpy_selected_inferior (PyObject *self, PyObject *args)
{
- return inferior_to_inferior_object (current_inferior ());
+ return ((PyObject *)
+ inferior_to_inferior_object (current_inferior ()).release ());
}
int
infpy_inf_data_key =
register_inferior_data_with_cleanup (NULL, py_free_inferior);
- observer_attach_new_thread (add_thread_object);
- observer_attach_thread_exit (delete_thread_object);
- observer_attach_normal_stop (python_on_normal_stop);
- observer_attach_target_resumed (python_on_resume);
- observer_attach_inferior_call_pre (python_on_inferior_call_pre);
- observer_attach_inferior_call_post (python_on_inferior_call_post);
- observer_attach_memory_changed (python_on_memory_change);
- observer_attach_register_changed (python_on_register_change);
- observer_attach_inferior_exit (python_inferior_exit);
- observer_attach_new_objfile (python_new_objfile);
+ 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);
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 PyGetSetDef inferior_object_getset[] =
+static gdb_PyGetSetDef inferior_object_getset[] =
{
{ "num", infpy_get_num, NULL, "ID of inferior, 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,
"True if the inferior was created using 'attach'.", NULL },
+ { "progspace", infpy_get_progspace, NULL, "Program space of this inferior" },
{ 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\
+Return architecture of this inferior." },
{ NULL }
};
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
- 0, /* tp_repr */
+ infpy_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
#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 */