gdb: use caller objfile in dwarf_evaluate_loc_desc::push_dwarf_reg_entry_value
[deliverable/binutils-gdb.git] / gdb / python / py-inferior.c
index ba81177b867194966b60e31b293fc1c60f85e496..b9268c11d4385b6eeef25aa0e92222c796ed30eb 100644 (file)
@@ -1,6 +1,6 @@
 /* Python interface to inferiors.
 
-   Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 2009-2020 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 "exceptions.h"
 #include "gdbcore.h"
 #include "gdbthread.h"
 #include "inferior.h"
-#include "observer.h"
+#include "objfiles.h"
+#include "observable.h"
 #include "python-internal.h"
 #include "arch-utils.h"
 #include "language.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
 
@@ -45,9 +54,10 @@ typedef struct
 
   /* Number of threads in the list.  */
   int nthreads;
-} inferior_object;
+};
 
-static PyTypeObject inferior_object_type;
+extern PyTypeObject inferior_object_type
+    CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("inferior_object");
 
 static const struct inferior_data *infpy_inf_data_key;
 
@@ -60,7 +70,8 @@ typedef struct {
   CORE_ADDR length;
 } membuf_object;
 
-static PyTypeObject membuf_object_type;
+extern PyTypeObject membuf_object_type
+    CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("membuf_object");
 
 /* Require that INFERIOR be a valid inferior ID.  */
 #define INFPY_REQUIRE_VALID(Inferior)                          \
@@ -73,117 +84,284 @@ static PyTypeObject membuf_object_type;
       }                                                                \
   } while (0)
 
-/* Return a borrowed reference to the Python object of type Inferior
+static void
+python_on_normal_stop (struct bpstats *bs, int print_frame)
+{
+  enum gdb_signal stop_signal;
+
+  if (!gdb_python_initialized)
+    return;
+
+  if (inferior_ptid == null_ptid)
+    return;
+
+  stop_signal = inferior_thread ()->suspend.stop_signal;
+
+  gdbpy_enter enter_py (get_current_arch (), current_language);
+
+  if (emit_stop_event (bs, stop_signal) < 0)
+    gdbpy_print_stack ();
+}
+
+static void
+python_on_resume (ptid_t ptid)
+{
+  if (!gdb_python_initialized)
+    return;
+
+  gdbpy_enter enter_py (target_gdbarch (), current_language);
+
+  if (emit_continue_event (ptid) < 0)
+    gdbpy_print_stack ();
+}
+
+/* Callback, registered as an observer, that notifies Python listeners
+   when an inferior function call is about to be made. */
+
+static void
+python_on_inferior_call_pre (ptid_t thread, CORE_ADDR address)
+{
+  gdbpy_enter enter_py (target_gdbarch (), current_language);
+
+  if (emit_inferior_call_event (INFERIOR_CALL_PRE, thread, address) < 0)
+    gdbpy_print_stack ();
+}
+
+/* Callback, registered as an observer, that notifies Python listeners
+   when an inferior function call has completed. */
+
+static void
+python_on_inferior_call_post (ptid_t thread, CORE_ADDR address)
+{
+  gdbpy_enter enter_py (target_gdbarch (), current_language);
+
+  if (emit_inferior_call_event (INFERIOR_CALL_POST, thread, address) < 0)
+    gdbpy_print_stack ();
+}
+
+/* Callback, registered as an observer, that notifies Python listeners
+   when a part of memory has been modified by user action (eg via a
+   'set' command). */
+
+static void
+python_on_memory_change (struct inferior *inferior, CORE_ADDR addr, ssize_t len, const bfd_byte *data)
+{
+  gdbpy_enter enter_py (target_gdbarch (), current_language);
+
+  if (emit_memory_changed_event (addr, len) < 0)
+    gdbpy_print_stack ();
+}
+
+/* Callback, registered as an observer, that notifies Python listeners
+   when a register has been modified by user action (eg via a 'set'
+   command). */
+
+static void
+python_on_register_change (struct frame_info *frame, int regnum)
+{
+  gdbpy_enter enter_py (target_gdbarch (), current_language);
+
+  if (emit_register_changed_event (frame, regnum) < 0)
+    gdbpy_print_stack ();
+}
+
+static void
+python_inferior_exit (struct inferior *inf)
+{
+  const LONGEST *exit_code = NULL;
+
+  if (!gdb_python_initialized)
+    return;
+
+  gdbpy_enter enter_py (target_gdbarch (), current_language);
+
+  if (inf->has_exit_code)
+    exit_code = &inf->exit_code;
+
+  if (emit_exited_event (exit_code, inf) < 0)
+    gdbpy_print_stack ();
+}
+
+/* Callback used to notify Python listeners about new objfiles loaded in the
+   inferior.  OBJFILE may be NULL which means that the objfile list has been
+   cleared (emptied).  */
+
+static void
+python_new_objfile (struct objfile *objfile)
+{
+  if (!gdb_python_initialized)
+    return;
+
+  gdbpy_enter enter_py (objfile != NULL
+                       ? objfile->arch ()
+                       : target_gdbarch (),
+                       current_language);
+
+  if (objfile == NULL)
+    {
+      if (emit_clear_objfiles_event () < 0)
+       gdbpy_print_stack ();
+    }
+  else
+    {
+      if (emit_new_objfile_event (objfile) < 0)
+       gdbpy_print_stack ();
+    }
+}
+
+/* Return a reference to the Python object of type Inferior
    representing INFERIOR.  If the object has already been created,
-   return it,  otherwise, create it.  Return NULL on failure.  */
-PyObject *
+   return it and increment the reference count,  otherwise, create it.
+   Return NULL on failure.  */
+
+gdbpy_ref<inferior_object>
 inferior_to_inferior_object (struct inferior *inferior)
 {
   inferior_object *inf_obj;
 
-  inf_obj = inferior_data (inferior, infpy_inf_data_key);
+  inf_obj = (inferior_object *) inferior_data (inferior, infpy_inf_data_key);
   if (!inf_obj)
     {
-      struct cleanup *cleanup;
-      cleanup = ensure_python_env (python_gdbarch, python_language);
-
       inf_obj = PyObject_New (inferior_object, &inferior_object_type);
       if (!inf_obj)
-       {
-         do_cleanups (cleanup);
-         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);
-
-      do_cleanups (cleanup);
     }
 
-  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
-   borrowed reference, or NULL if PID does not match any inferior
-   obect.
-  */
-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 inflist_entry *p;
-  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;
-  PyObject *inf_obj;
+  if (!gdb_python_initialized)
+    return;
 
-  pid = PIDGET (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;
+    }
 
-  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;
 
-  if (inf_obj)
-    for (thread = ((inferior_object *)inf_obj)->threads; thread;
-        thread = thread->next)
-      if (ptid_equal (thread->thread_obj->thread->ptid, ptid))
-       return thread->thread_obj;
+  for (threadlist_entry *thread = inf_obj->threads;
+       thread != NULL;
+       thread = thread->next)
+    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)
 {
-  struct cleanup *cleanup;
-  thread_object *thread_obj;
   inferior_object *inf_obj;
   struct threadlist_entry *entry;
 
-  cleanup = ensure_python_env (python_gdbarch, python_language);
+  if (!gdb_python_initialized)
+    return;
+
+  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 ();
-      do_cleanups (cleanup);
       return;
     }
 
   inf_obj = (inferior_object *) thread_obj->inf_obj;
 
-  entry = xmalloc (sizeof (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++;
 
-  do_cleanups (cleanup);
+  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)
 {
-  struct cleanup *cleanup;
-  inferior_object *inf_obj;
-  thread_object *thread_obj;
   struct threadlist_entry **entry, *tmp;
 
-  inf_obj = (inferior_object *) find_inferior_object (PIDGET(tp->ptid));
-  if (!inf_obj)
+  if (!gdb_python_initialized)
+    return;
+
+  gdbpy_enter enter_py (python_gdbarch, python_language);
+
+  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.  */
@@ -195,18 +373,13 @@ delete_thread_object (struct thread_info *tp, int ignore)
   if (!*entry)
     return;
 
-  cleanup = ensure_python_env (python_gdbarch, python_language);
-
   tmp = *entry;
   tmp->thread_obj->thread = NULL;
 
   *entry = (*entry)->next;
   inf_obj->nthreads--;
 
-  Py_DECREF (tmp->thread_obj);
-  xfree (tmp);
-
-  do_cleanups (cleanup);
+  delete tmp;
 }
 
 static PyObject *
@@ -219,6 +392,15 @@ infpy_threads (PyObject *self, PyObject *args)
 
   INFPY_REQUIRE_VALID (inf_obj);
 
+  try
+    {
+      update_thread_list ();
+    }
+  catch (const gdb_exception &except)
+    {
+      GDB_PY_HANDLE_EXCEPTION (except);
+    }
+
   tuple = PyTuple_New (inf_obj->nthreads);
   if (!tuple)
     return NULL;
@@ -226,8 +408,9 @@ infpy_threads (PyObject *self, PyObject *args)
   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;
@@ -264,14 +447,19 @@ infpy_get_was_attached (PyObject *self, void *closure)
   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 = arg;
-  PyObject *inferior = inferior_to_inferior_object (inf);
+  inferior_object *inf = (inferior_object *) self;
+
+  INFPY_REQUIRE_VALID (inf);
+
+  program_space *pspace = inf->inferior->pspace;
+  gdb_assert (pspace != nullptr);
 
-  PyList_Append (list, inferior);
-  return 0;
+  return pspace_to_pspace_object (pspace).release ();
 }
 
 /* Implementation of gdb.inferiors () -> (gdb.Inferior, ...).
@@ -279,89 +467,77 @@ build_inferior_list (struct inferior *inf, void *arg)
 PyObject *
 gdbpy_inferiors (PyObject *unused, PyObject *unused2)
 {
-  int i = 0;
-  PyObject *list, *inferior;
-  struct inferior *inf;
-
-  list = PyList_New (0);
-  if (!list)
+  gdbpy_ref<> list (PyList_New (0));
+  if (list == NULL)
     return NULL;
 
-  iterate_over_inferiors (build_inferior_list, list);
+  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);
+  return PyList_AsTuple (list.get ());
 }
 
 /* Membuf and memory manipulation.  */
 
-/* Implementation of gdb.read_memory (address, length).
+/* Implementation of Inferior.read_memory (address, length).
    Returns a Python buffer object with LENGTH bytes of the inferior's
    memory at ADDRESS.  Both arguments are integers.  Returns NULL on error,
    with a python exception set.  */
 static PyObject *
 infpy_read_memory (PyObject *self, PyObject *args, PyObject *kw)
 {
-  int error = 0;
   CORE_ADDR addr, length;
-  void *buffer = NULL;
-  membuf_object *membuf_obj;
-  PyObject *addr_obj, *length_obj;
-  struct cleanup *cleanups;
-  volatile struct gdb_exception except;
-  static char *keywords[] = { "address", "length", NULL };
-
-  if (! PyArg_ParseTupleAndKeywords (args, kw, "OO", keywords,
-                                    &addr_obj, &length_obj))
+  gdb::unique_xmalloc_ptr<gdb_byte> buffer;
+  PyObject *addr_obj, *length_obj, *result;
+  static const char *keywords[] = { "address", "length", NULL };
+
+  if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "OO", keywords,
+                                       &addr_obj, &length_obj))
     return NULL;
 
-  cleanups = make_cleanup (null_cleanup, NULL);
+  if (get_addr_from_python (addr_obj, &addr) < 0
+      || get_addr_from_python (length_obj, &length) < 0)
+    return NULL;
 
-  TRY_CATCH (except, RETURN_MASK_ALL)
+  try
     {
-      if (!get_addr_from_python (addr_obj, &addr)
-         || !get_addr_from_python (length_obj, &length))
-       {
-         error = 1;
-         break;
-       }
-
-      buffer = xmalloc (length);
-      make_cleanup (xfree, buffer);
+      buffer.reset ((gdb_byte *) xmalloc (length));
 
-      read_memory (addr, buffer, length);
+      read_memory (addr, buffer.get (), length);
     }
-  if (except.reason < 0)
+  catch (const gdb_exception &except)
     {
-      do_cleanups (cleanups);
       GDB_PY_HANDLE_EXCEPTION (except);
     }
 
-  if (error)
-    {
-      do_cleanups (cleanups);
-      return NULL;
-    }
-
-  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)
-    {
-      PyErr_SetString (PyExc_MemoryError,
-                      _("Could not allocate memory buffer object."));
-      do_cleanups (cleanups);
-      return NULL;
-    }
-
-  discard_cleanups (cleanups);
+    return NULL;
 
-  membuf_obj->buffer = buffer;
+  membuf_obj->buffer = buffer.release ();
   membuf_obj->addr = addr;
   membuf_obj->length = length;
 
-  return PyBuffer_FromReadWriteObject ((PyObject *) membuf_obj, 0,
-                                      Py_END_OF_BUFFER);
+#ifdef IS_PY3K
+  result = PyMemoryView_FromObject ((PyObject *) membuf_obj.get ());
+#else
+  result = PyBuffer_FromReadWriteObject ((PyObject *) membuf_obj.get (), 0,
+                                        Py_END_OF_BUFFER);
+#endif
+
+  return result;
 }
 
-/* Implementation of gdb.write_memory (address, buffer [, length]).
+/* Implementation of Inferior.write_memory (address, buffer [, length]).
    Writes the contents of BUFFER (a Python object supporting the read
    buffer protocol) at ADDRESS in the inferior's memory.  Write LENGTH
    bytes from BUFFER, or its entire contents if the argument is not
@@ -370,40 +546,40 @@ infpy_read_memory (PyObject *self, PyObject *args, PyObject *kw)
 static PyObject *
 infpy_write_memory (PyObject *self, PyObject *args, PyObject *kw)
 {
-  int buf_len, error = 0;
-  const char *buffer;
+  struct gdb_exception except;
+  Py_ssize_t buf_len;
+  const gdb_byte *buffer;
   CORE_ADDR addr, length;
   PyObject *addr_obj, *length_obj = NULL;
-  volatile struct gdb_exception except;
-  static char *keywords[] = { "address", "buffer", "length", NULL };
+  static const char *keywords[] = { "address", "buffer", "length", NULL };
+  Py_buffer pybuf;
 
-
-  if (! PyArg_ParseTupleAndKeywords (args, kw, "Os#|O", keywords,
-                                    &addr_obj, &buffer, &buf_len,
-                                    &length_obj))
+  if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "Os*|O", keywords,
+                                       &addr_obj, &pybuf, &length_obj))
     return NULL;
 
-  TRY_CATCH (except, RETURN_MASK_ALL)
+  Py_buffer_up buffer_up (&pybuf);
+  buffer = (const gdb_byte *) pybuf.buf;
+  buf_len = pybuf.len;
+
+  if (get_addr_from_python (addr_obj, &addr) < 0)
+    return nullptr;
+
+  if (!length_obj)
+    length = buf_len;
+  else if (get_addr_from_python (length_obj, &length) < 0)
+    return nullptr;
+
+  try
     {
-      if (!get_addr_from_python (addr_obj, &addr))
-       {
-         error = 1;
-         break;
-       }
-
-      if (!length_obj)
-       length = buf_len;
-      else if (!get_addr_from_python (length_obj, &length))
-       {
-         error = 1;
-         break;
-       }
-      write_memory (addr, buffer, length);
+      write_memory_with_notification (addr, buffer, length);
+    }
+  catch (gdb_exception &ex)
+    {
+      except = std::move (ex);
     }
-  GDB_PY_HANDLE_EXCEPTION (except);
 
-  if (error)
-    return NULL;
+  GDB_PY_HANDLE_EXCEPTION (except);
 
   Py_RETURN_NONE;
 }
@@ -413,7 +589,7 @@ static void
 mbpy_dealloc (PyObject *self)
 {
   xfree (((membuf_object *) self)->buffer);
-  self->ob_type->tp_free (self);
+  Py_TYPE (self)->tp_free (self);
 }
 
 /* Return a description of the Membuf object.  */
@@ -428,6 +604,27 @@ which is %s bytes long."),
                              pulongest (membuf_obj->length));
 }
 
+#ifdef IS_PY3K
+
+static int
+get_buffer (PyObject *self, Py_buffer *buf, int flags)
+{
+  membuf_object *membuf_obj = (membuf_object *) self;
+  int ret;
+
+  ret = PyBuffer_FillInfo (buf, self, membuf_obj->buffer,
+                          membuf_obj->length, 0,
+                          PyBUF_CONTIG);
+
+  /* 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;
+}
+
+#else
+
 static Py_ssize_t
 get_read_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr)
 {
@@ -472,6 +669,8 @@ get_char_buffer (PyObject *self, Py_ssize_t segment, char **ptrptr)
   return ret;
 }
 
+#endif /* IS_PY3K */
+
 /* Implementation of
    gdb.search_memory (address, length, pattern).  ADDRESS is the
    address to start the search.  LENGTH specifies the scope of the
@@ -483,59 +682,57 @@ get_char_buffer (PyObject *self, Py_ssize_t segment, char **ptrptr)
 static PyObject *
 infpy_search_memory (PyObject *self, PyObject *args, PyObject *kw)
 {
+  struct gdb_exception except;
   CORE_ADDR start_addr, length;
-  static char *keywords[] = { "address", "length", "pattern", NULL };
-  PyObject *pattern, *start_addr_obj, *length_obj;
-  volatile struct gdb_exception except;
+  static const char *keywords[] = { "address", "length", "pattern", NULL };
+  PyObject *start_addr_obj, *length_obj;
   Py_ssize_t pattern_size;
-  const void *buffer;
+  const gdb_byte *buffer;
   CORE_ADDR found_addr;
   int found = 0;
+  Py_buffer pybuf;
 
-  if (! PyArg_ParseTupleAndKeywords (args, kw, "OOO", keywords,
-                                    &start_addr_obj, &length_obj,
-                                    &pattern))
+  if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "OOs*", keywords,
+                                       &start_addr_obj, &length_obj,
+                                       &pybuf))
     return NULL;
 
-  if (get_addr_from_python (start_addr_obj, &start_addr)
-      && get_addr_from_python (length_obj, &length))
+  Py_buffer_up buffer_up (&pybuf);
+  buffer = (const gdb_byte *) pybuf.buf;
+  pattern_size = pybuf.len;
+
+  if (get_addr_from_python (start_addr_obj, &start_addr) < 0)
+    return nullptr;
+
+  if (get_addr_from_python (length_obj, &length) < 0)
+    return nullptr;
+
+  if (!length)
     {
-      if (!length)
-       {
-         PyErr_SetString (PyExc_ValueError,
-                          _("Search range is empty."));
-         return NULL;
-       }
-      /* Watch for overflows.  */
-      else if (length > CORE_ADDR_MAX
-              || (start_addr + length - 1) < start_addr)
-       {
-         PyErr_SetString (PyExc_ValueError,
-                          _("The search range is too large."));
-
-         return NULL;
-       }
+      PyErr_SetString (PyExc_ValueError,
+                      _("Search range is empty."));
+      return nullptr;
     }
-  else
-    return NULL;
-
-  if (!PyObject_CheckReadBuffer (pattern))
+  /* Watch for overflows.  */
+  else if (length > CORE_ADDR_MAX
+          || (start_addr + length - 1) < start_addr)
     {
-      PyErr_SetString (PyExc_RuntimeError,
-                      _("The pattern is not a Python buffer."));
-
-      return NULL;
+      PyErr_SetString (PyExc_ValueError,
+                      _("The search range is too large."));
+      return nullptr;
     }
 
-  if (PyObject_AsReadBuffer (pattern, &buffer, &pattern_size) == -1)
-    return NULL;
-
-  TRY_CATCH (except, RETURN_MASK_ALL)
+  try
     {
       found = target_search_memory (start_addr, length,
                                    buffer, pattern_size,
                                    &found_addr);
     }
+  catch (gdb_exception &ex)
+    {
+      except = std::move (ex);
+    }
+
   GDB_PY_HANDLE_EXCEPTION (except);
 
   if (found)
@@ -544,73 +741,206 @@ infpy_search_memory (PyObject *self, PyObject *args, PyObject *kw)
     Py_RETURN_NONE;
 }
 
+/* Implementation of gdb.Inferior.is_valid (self) -> Boolean.
+   Returns True if this inferior object still exists in GDB.  */
+
+static PyObject *
+infpy_is_valid (PyObject *self, PyObject *args)
+{
+  inferior_object *inf = (inferior_object *) self;
+
+  if (! inf->inferior)
+    Py_RETURN_FALSE;
+
+  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)
+{
+  inferior_object *inf_obj = (inferior_object *) obj;
+  struct inferior *inf = inf_obj->inferior;
+
+  if (! inf)
+    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
    thread list.  */
 static void
 py_free_inferior (struct inferior *inf, void *datum)
 {
-
-  struct cleanup *cleanup;
-  inferior_object *inf_obj = datum;
   struct threadlist_entry *th_entry, *th_tmp;
 
-  cleanup = ensure_python_env (python_gdbarch, python_language);
+  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;
+}
+
+/* Implementation of gdb.selected_inferior() -> gdb.Inferior.
+   Returns the current inferior object.  */
 
-  Py_DECREF ((PyObject *) inf_obj);
-  do_cleanups (cleanup);
+PyObject *
+gdbpy_selected_inferior (PyObject *self, PyObject *args)
+{
+  return ((PyObject *)
+         inferior_to_inferior_object (current_inferior ()).release ());
 }
 
-void
+int
 gdbpy_initialize_inferior (void)
 {
   if (PyType_Ready (&inferior_object_type) < 0)
-    return;
+    return -1;
 
-  Py_INCREF (&inferior_object_type);
-  PyModule_AddObject (gdb_module, "Inferior",
-                     (PyObject *) &inferior_object_type);
+  if (gdb_pymodule_addobject (gdb_module, "Inferior",
+                             (PyObject *) &inferior_object_type) < 0)
+    return -1;
 
   infpy_inf_data_key =
-    register_inferior_data_with_cleanup (py_free_inferior);
-
-  observer_attach_new_thread (add_thread_object);
-  observer_attach_thread_exit (delete_thread_object);
-
+    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);
+
+  membuf_object_type.tp_new = PyType_GenericNew;
   if (PyType_Ready (&membuf_object_type) < 0)
-    return;
+    return -1;
 
-  Py_INCREF (&membuf_object_type);
-  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 }
 };
 
 static PyMethodDef inferior_object_methods[] =
 {
+  { "is_valid", infpy_is_valid, METH_NOARGS,
+    "is_valid () -> Boolean.\n\
+Return true if this inferior is valid, false if not." },
   { "threads", infpy_threads, METH_NOARGS,
     "Return all the threads of this inferior." },
   { "read_memory", (PyCFunction) infpy_read_memory,
@@ -625,22 +955,34 @@ Write the given buffer object to the inferior's memory." },
     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 }
 };
 
-static PyTypeObject inferior_object_type =
+PyTypeObject inferior_object_type =
 {
-  PyObject_HEAD_INIT (NULL)
-  0,                             /* ob_size */
+  PyVarObject_HEAD_INIT (NULL, 0)
   "gdb.Inferior",                /* tp_name */
   sizeof (inferior_object),      /* tp_basicsize */
   0,                             /* tp_itemsize */
-  0,                             /* tp_dealloc */
+  infpy_dealloc,                 /* tp_dealloc */
   0,                             /* tp_print */
   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 */
@@ -670,25 +1012,25 @@ static PyTypeObject inferior_object_type =
   0                              /* tp_alloc */
 };
 
-/* Python doesn't provide a decent way to get compatibility here.  */
-#if HAVE_LIBPYTHON2_4
-#define CHARBUFFERPROC_NAME getcharbufferproc
+#ifdef IS_PY3K
+
+static PyBufferProcs buffer_procs =
+{
+  get_buffer
+};
+
 #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 */
 
-static PyTypeObject membuf_object_type = {
-  PyObject_HEAD_INIT (NULL)
-  0,                             /*ob_size*/
+PyTypeObject membuf_object_type = {
+  PyVarObject_HEAD_INIT (NULL, 0)
   "gdb.Membuf",                          /*tp_name*/
   sizeof (membuf_object),        /*tp_basicsize*/
   0,                             /*tp_itemsize*/
@@ -725,5 +1067,4 @@ static PyTypeObject membuf_object_type = {
   0,                             /* tp_dictoffset */
   0,                             /* tp_init */
   0,                             /* tp_alloc */
-  PyType_GenericNew              /* tp_new */
 };
This page took 0.036959 seconds and 4 git commands to generate.