This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [python][patch] Inferior and Thread information support.


On 06/18/2010 07:04 PM, Tom Tromey wrote:
>>>>>> "Phil" == Phil Muldoon <pmuldoon@redhat.com> writes:
> 
> Phil> +int
> Phil> +search_memory (CORE_ADDR *start_addr, ULONGEST *search_space_len,
> Phil> +	       const char *pattern_buf, ULONGEST pattern_len,
> Phil> +	       CORE_ADDR *found_addr)
> 
> I think if you remove the max_count parameter then you won't need this
> at all, you can just call target_search_memory directly.

OK.

> struct inferior now has a "user-data" API, like objfiles do.
> See register_inferior_data and register_inferior_data_with_cleanup.
> 
> I think this means that we can attach the Python objects directly to the
> struct inferior, rather than keeping an external list.

I've done this.  Threads do not have the same registry mechanism yet, so
I've had to keep the old observer mechanism there.  But inferiors use
the new registry cleanup.

I've also simplified the search_memory api as requested.  We now take
an address, a length and a buffer only.  We now only return the first
match found in the buffer. (and let the user do the iteration in the
scripting side).

Latest patch attached. WDYT?

Cheers

Phil

--

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 5cb02d8..6dbb284 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -275,6 +275,8 @@ SUBDIR_PYTHON_OBS = \
 	py-cmd.o \
 	py-frame.o \
 	py-function.o \
+	py-inferior.o \
+	py-infthread.o \
 	py-lazy-string.o \
 	py-objfile.o \
 	py-param.o \
@@ -293,6 +295,8 @@ SUBDIR_PYTHON_SRCS = \
 	python/py-cmd.c \
 	python/py-frame.c \
 	python/py-function.c \
+	python/py-inferior.c \
+	python/py-infthread.c \
 	python/py-lazy-string.c \
 	python/py-objfile.c \
 	python/py-param.c \
@@ -2018,6 +2022,14 @@ py-function.o: $(srcdir)/python/py-function.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-function.c
 	$(POSTCOMPILE)
 
+py-inferior.o: $(srcdir)/python/py-inferior.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-inferior.c
+	$(POSTCOMPILE)
+
+py-infthread.o: $(srcdir)/python/py-infthread.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-infthread.c
+	$(POSTCOMPILE)
+
 py-lazy-string.o: $(srcdir)/python/py-lazy-string.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-lazy-string.c
 	$(POSTCOMPILE)
diff --git a/gdb/NEWS b/gdb/NEWS
index af65274..d28bae4 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -100,9 +100,9 @@ is now deprecated.
 * Python scripting
 
 ** The GDB Python API now has access to breakpoints, symbols, symbol
-   tables, program spaces, and frame's code blocks.  Additionally, GDB
-   Parameters can now be created from the API, and manipulated via
-   set/show in the CLI.
+   tables, program spaces, inferiors, threads and frame's code blocks.
+   Additionally, GDB Parameters can now be created from the API, and
+   manipulated via set/show in the CLI.
 
 ** New functions gdb.target_charset, gdb.target_wide_charset,
    gdb.progspaces, gdb.current_progspace, and gdb.string_to_argv.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 463030f..553516d 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -20170,6 +20170,8 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
 * Pretty Printing API::         Pretty-printing values.
 * Selecting Pretty-Printers::   How GDB chooses a pretty-printer.
 * Disabling Pretty-Printers::   Disabling broken printers.
+* Inferiors In Python::         Python representation of inferiors (processes)
+* Threads In Python::           Accessing inferior threads from Python.
 * Commands In Python::          Implementing new commands in Python.
 * Parameters In Python::        Adding new @value{GDBN} parameters.
 * Functions In Python::         Writing new convenience functions.
@@ -20986,6 +20988,137 @@ attribute to the registered function or callable object.  If this attribute
 is present and its value is @code{False}, the printer is disabled, otherwise
 the printer is enabled.
 
+@node Inferiors In Python
+@subsubsection Inferiors In Python
+@cindex inferiors in python
+
+@findex gdb.Inferior
+Programs which are being run under @value{GDBN} are called inferiors
+(@pxref{Inferiors and Programs}).  Python scripts can access
+information about and manipulate inferiors controlled by @value{GDBN}
+via objects of the @code{gdb.Inferior} class.
+
+The following inferior-related functions are available in the @code{gdb}
+module:
+
+@defun inferiors
+Return a tuple containing all inferior objects.
+@end defun
+
+A @code{gdb.Inferior} object has the following attributes:
+
+@table @code
+@defivar Inferior num
+ID of inferior, as assigned by GDB.
+@end defivar
+
+@defivar Inferior pid
+Process ID of the inferior, as assigned by the underlying operating
+system.
+@end defivar
+
+@defivar Inferior was_attached
+Boolean signaling whether the inferior was created using `attach', or
+started by @value{GDBN} itself.
+@end defivar
+@end table
+
+A @code{gdb.Inferior} object has the following methods:
+
+@table @code
+@defmethod Inferior threads
+This method returns a tuple holding all the threads which are valid
+when it is called.  If there are no valid threads, the method will
+return an empty tuple.
+@end defmethod
+
+@findex gdb.read_memory
+@defmethod Inferior read_memory address length
+Read @var{length} bytes of memory from the inferior, starting at
+@var{address}.  Returns a buffer object, which behaves much like an array
+or a string.  It can be modified and given to the @code{gdb.write_memory}
+function.
+@end defmethod
+
+@findex gdb.write_memory
+@defmethod Inferior write_memory address buffer @r{[}length@r{]}
+Write the contents of @var{buffer} to the inferior, starting at
+@var{address}.  The @var{buffer} parameter must be a Python object
+which supports the buffer protocol, i.e., a string, an array or the
+object returned from @code{gdb.read_memory}.  If given, @var{length}
+determines the number of bytes from @var{buffer} to be written.
+@end defmethod
+
+@findex gdb.search_memory
+@defmethod Inferior search_memory address length pattern
+Search a region of the inferior memory starting at @var{address} with
+the given @var{length} using the search pattern supplied in
+@var{pattern}.  The @var{pattern} parameter must be a Python object
+which supports the buffer protocol, i.e., a string, an array or the
+object returned from @code{gdb.read_memory}.  Returns a Python @code{Long}
+containing the address where the pattern was found, or @code{None} if
+the pattern could not be found.
+@end defmethod
+@end table
+
+@node Threads In Python
+@subsubsection Threads In Python
+@cindex threads in python
+
+@findex gdb.InferiorThread
+Python scripts can access information about, and manipulate inferior threads
+controlled by @value{GDBN}, via objects of the @code{gdb.InferiorThread} class.
+
+The following thread-related functions are available in the @code{gdb}
+module:
+
+@findex gdb.selected_thread
+@defun selected_thread
+This function returns the thread object for the selected thread.  If there
+is no selected thread, this will return @code{None}.
+@end defun
+
+A @code{gdb.InferiorThread} object has the following attributes:
+
+@table @code
+@defivar InferiorThread num
+ID of the thread, as assigned by GDB.
+@end defivar
+
+@defivar InferiorThread ptid
+ID of the thread, as assigned by the operating system.  This attribute is a
+tuple containing three integers.  The first is the Process ID (PID); the second
+is the Lightweight Process ID (LWPID), and the third is the Thread ID (TID).
+Either the LWPID or TID may be 0, which indicates that the operating system
+does not  use that identifier.
+@end defivar
+@end table
+
+A @code{gdb.InferiorThread} object has the following methods:
+
+@table @code
+@defmethod InferiorThread newest_frame
+Return the newest frame thread's stack.
+@end defmethod
+
+@defmethod InferiorThread switch
+This changes @value{GDBN}'s currently selected thread to the one represented
+by this object.
+@end defmethod
+
+@defmethod InferiorThread is_stopped
+Return a Boolean indicating whether the thread is stopped.
+@end defmethod
+
+@defmethod InferiorThread is_running
+Return a Boolean indicating whether the thread is running.
+@end defmethod
+
+@defmethod InferiorThread is_exited
+Return a Boolean indicating whether the thread is exited.
+@end defmethod
+@end table
+
 @node Commands In Python
 @subsubsection Commands In Python
 
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 6e9e5d3..a7df810 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -265,7 +265,7 @@ frapy_function (PyObject *self, PyObject *args)
 /* Convert a frame_info struct to a Python Frame object.
    Sets a Python exception and returns NULL on error.  */
 
-static frame_object *
+PyObject *
 frame_info_to_frame_object (struct frame_info *frame)
 {
   frame_object *frame_obj;
@@ -296,7 +296,7 @@ frame_info_to_frame_object (struct frame_info *frame)
 
   frame_obj->gdbarch = get_frame_arch (frame);
 
-  return frame_obj;
+  return (PyObject *) frame_obj;
 }
 
 /* Implementation of gdb.Frame.older (self) -> gdb.Frame.
@@ -497,7 +497,7 @@ PyObject *
 gdbpy_selected_frame (PyObject *self, PyObject *args)
 {
   struct frame_info *frame;
-  frame_object *frame_obj = NULL;   /* Initialize to appease gcc warning.  */
+  PyObject *frame_obj = NULL;   /* Initialize to appease gcc warning.  */
   volatile struct gdb_exception except;
 
   TRY_CATCH (except, RETURN_MASK_ALL)
@@ -507,7 +507,7 @@ gdbpy_selected_frame (PyObject *self, PyObject *args)
     }
   GDB_PY_HANDLE_EXCEPTION (except);
 
-  return (PyObject *) frame_obj;
+  return frame_obj;
 }
 
 /* Implementation of gdb.stop_reason_string (Integer) -> String.
diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c
new file mode 100644
index 0000000..113e8ef
--- /dev/null
+++ b/gdb/python/py-inferior.c
@@ -0,0 +1,732 @@
+/* Python interface to inferiors.
+
+   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   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 "python-internal.h"
+#include "arch-utils.h"
+#include "language.h"
+
+struct threadlist_entry {
+  thread_object *thread_obj;
+  struct threadlist_entry *next;
+};
+
+typedef struct
+{
+  PyObject_HEAD
+
+  /* The inferior we represent.  */
+  struct inferior *inferior;
+
+  /* thread_object instances under this inferior.  This list owns a
+     reference to each object it contains.  */
+  struct threadlist_entry *threads;
+
+  /* Number of threads in the list.  */
+  int nthreads;
+} inferior_object;
+
+static PyTypeObject inferior_object_type;
+
+static const struct inferior_data *infpy_inf_data_key;
+
+typedef struct {
+  PyObject_HEAD
+  void *buffer;
+
+  /* These are kept just for mbpy_str.  */
+  CORE_ADDR addr;
+  CORE_ADDR length;
+} membuf_object;
+
+static PyTypeObject membuf_object_type;
+
+/* Require that INFERIOR be a valid inferior ID.  */
+#define INFPY_REQUIRE_VALID(Inferior)				\
+  do {								\
+    if (!Inferior->inferior)					\
+      {								\
+	PyErr_SetString (PyExc_RuntimeError,			\
+			 _("Inferior no longer exists."));	\
+	return NULL;						\
+      }								\
+  } while (0)
+
+
+
+/* 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 *
+inferior_to_inferior_object (struct inferior *inferior)
+{
+  inferior_object *inf_obj;
+
+  inf_obj = 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;
+	}
+
+      inf_obj->inferior = inferior;
+      inf_obj->threads = NULL;
+      inf_obj->nthreads = 0;
+
+      set_inferior_data (inferior, infpy_inf_data_key, inf_obj);
+
+      do_cleanups (cleanup);
+    }
+  else
+    Py_INCREF (inf_obj);
+
+  return (PyObject *) inf_obj;
+}
+
+/* Finds the Python Inferior object for the given PID.  */
+PyObject *
+find_inferior_object (int pid)
+{
+  struct inflist_entry *p;
+  struct inferior *inf = find_inferior_pid (pid);
+
+  if (inf)
+    return inferior_to_inferior_object (inf);
+
+  return NULL;
+}
+
+thread_object *
+find_thread_object (ptid_t ptid)
+{
+  int pid;
+  struct threadlist_entry *thread;
+  PyObject *inf_obj;
+
+  pid = PIDGET (ptid);
+  inf_obj = find_inferior_object (pid);
+
+  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;
+
+  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);
+
+  thread_obj = create_thread_object (tp);
+  if (!thread_obj)
+    {
+      warning (_("Cannot create Python InferiorThread object."));
+      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->next = inf_obj->threads;
+
+  inf_obj->threads = entry;
+  inf_obj->nthreads++;
+
+  do_cleanups (cleanup);
+}
+
+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)
+    return;
+
+  /* Find thread entry in its inferior's thread_list.  */
+  for (entry = &inf_obj->threads; *entry != NULL; entry =
+	 &(*entry)->next)
+    if ((*entry)->thread_obj->thread == tp)
+      break;
+
+  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);
+}
+
+static PyObject *
+infpy_threads (PyObject *self, PyObject *args)
+{
+  int i;
+  struct threadlist_entry *entry;
+  inferior_object *inf_obj = (inferior_object *) self;
+  PyObject *tuple;
+
+  INFPY_REQUIRE_VALID (inf_obj);
+
+  tuple = PyTuple_New (inf_obj->nthreads);
+  if (!tuple)
+    return NULL;
+
+  /* The list is in reverse order of thread age (i.e., newest comes
+     first).  */
+  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);
+    }
+
+  return tuple;
+}
+
+static PyObject *
+infpy_get_num (PyObject *self, void *closure)
+{
+  inferior_object *inf = (inferior_object *) self;
+
+  INFPY_REQUIRE_VALID (inf);
+
+  return PyLong_FromLong (inf->inferior->num);
+}
+
+static PyObject *
+infpy_get_pid (PyObject *self, void *closure)
+{
+  inferior_object *inf = (inferior_object *) self;
+
+  INFPY_REQUIRE_VALID (inf);
+
+  return PyLong_FromLong (inf->inferior->pid);
+}
+
+static PyObject *
+infpy_get_was_attached (PyObject *self, void *closure)
+{
+  inferior_object *inf = (inferior_object *) self;
+  INFPY_REQUIRE_VALID (inf);
+  if (inf->inferior->attach_flag)
+    Py_RETURN_TRUE;
+  Py_RETURN_FALSE;
+}
+
+
+
+static int
+build_inferior_list (struct inferior *inf, void *arg)
+{
+  PyObject *list = arg;
+  PyObject *inferior = inferior_to_inferior_object (inf);
+  PyList_Append (list, inferior);
+
+  return 0;
+}
+
+/* Implementation of gdb.inferiors () -> (gdb.Inferior, ...).
+   Returns a tuple of all inferiors.  */
+PyObject *
+gdbpy_inferiors (PyObject *unused, PyObject *unused2)
+{
+  int i = 0;
+  PyObject *list, *inferior;
+  struct inferior *inf;
+
+  list = PyList_New (0);
+  if (!list)
+    return NULL;
+
+  iterate_over_inferiors (build_inferior_list, list);
+
+  return PyList_AsTuple (list);
+}
+
+
+
+/* Membuf and memory manipulation.  */
+
+/* Implementation of gdb.read_memory (address, length).
+   Returns a Python buffer object with LENGTH bytes of the inferior's
+   memory at ADDRESS.  Both arguments are integers.  */
+static PyObject *
+infpy_read_memory (PyObject *self, PyObject *args)
+{
+  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;
+
+  if (! PyArg_ParseTuple (args, "OO", &addr_obj, &length_obj))
+    return NULL;
+
+  cleanups = make_cleanup (null_cleanup, NULL);
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      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);
+
+      read_memory (addr, buffer, length);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  if (error)
+    {
+      do_cleanups (cleanups);
+      return NULL;
+    }
+
+  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);
+
+  membuf_obj->buffer = buffer;
+  membuf_obj->addr = addr;
+  membuf_obj->length = length;
+
+  return PyBuffer_FromReadWriteObject ((PyObject *) membuf_obj, 0,
+				       Py_END_OF_BUFFER);
+}
+
+/* Implementation of gdb.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
+   provided.  The function returns nothing.  */
+static PyObject *
+infpy_write_memory (PyObject *self, PyObject *args)
+{
+  int buf_len, error = 0;
+  const char *buffer;
+  CORE_ADDR addr, length;
+  PyObject *addr_obj, *length_obj = NULL;
+  volatile struct gdb_exception except;
+
+  if (! PyArg_ParseTuple (args, "Os#|O", &addr_obj, &buffer, &buf_len,
+			  &length_obj))
+    return NULL;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      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);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  if (error)
+    return NULL;
+
+  Py_RETURN_NONE;
+}
+
+/* Destructor of Membuf objects.  */
+static void
+mbpy_dealloc (PyObject *self)
+{
+  xfree (((membuf_object *) self)->buffer);
+  self->ob_type->tp_free (self);
+}
+
+/* Return a description of the Membuf object.  */
+static PyObject *
+mbpy_str (PyObject *self)
+{
+  membuf_object *membuf_obj = (membuf_object *) self;
+
+  return PyString_FromFormat (_("Memory buffer for address %s, \
+which is %s bytes long."),
+			      paddress (python_gdbarch, membuf_obj->addr),
+			      pulongest (membuf_obj->length));
+}
+
+static Py_ssize_t
+get_read_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr)
+{
+  membuf_object *membuf_obj = (membuf_object *) self;
+
+  if (segment)
+    {
+      PyErr_SetString (PyExc_SystemError,
+		       _("The memory buffer supports only one segment."));
+      return -1;
+    }
+
+  *ptrptr = membuf_obj->buffer;
+
+  return membuf_obj->length;
+}
+
+static Py_ssize_t
+get_write_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr)
+{
+  return get_read_buffer (self, segment, ptrptr);
+}
+
+static Py_ssize_t
+get_seg_count (PyObject *self, Py_ssize_t *lenp)
+{
+  if (lenp)
+    *lenp = ((membuf_object *) self)->length;
+
+  return 1;
+}
+
+static Py_ssize_t
+get_char_buffer (PyObject *self, Py_ssize_t segment, char **ptrptr)
+{
+  void *ptr = NULL;
+  Py_ssize_t ret;
+
+  ret = get_read_buffer (self, segment, &ptr);
+  *ptrptr = (char *) ptr;
+
+  return ret;
+}
+
+/* Implementation of
+   gdb.search_memory (address, length, pattern).  ADDRESS is the
+   address to start the search.  LENGTH specifies the scope of the
+   search from ADDRESS.  PATTERN is the pattern to search for (and
+   must be a Python object supporting the buffer protocol).
+   Returns a Python Long object holding the address where the pattern
+   was located, or if the pattern was not found, returns None.  */
+static PyObject *
+infpy_search_memory (PyObject *self, PyObject *args, PyObject *kw)
+{
+  CORE_ADDR start_addr, length;
+  static char *keywords[] = { "address", "length", "pattern", NULL };
+  PyObject *pattern, *start_addr_obj, *length_obj;
+  volatile struct gdb_exception except;
+  Py_ssize_t pattern_size;
+  const void *buffer;
+  CORE_ADDR found_addr;
+  int found = 0;
+
+  if (! PyArg_ParseTupleAndKeywords (args, kw, "OOO", keywords,
+				     &start_addr_obj, &length_obj,
+				     &pattern))
+    return NULL;
+
+  if (get_addr_from_python (start_addr_obj, &start_addr)
+      && get_addr_from_python (length_obj, &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;
+	}
+    }
+  else
+    {
+      PyErr_SetString (PyExc_RuntimeError,
+		       _("Cannot get search address/range from Python."));
+
+      return NULL;
+    }
+
+  if (!PyObject_CheckReadBuffer (pattern))
+    {
+      PyErr_SetString (PyExc_RuntimeError,
+		       _("The pattern is not a Python buffer."));
+
+      return NULL;
+    }
+
+  if (PyObject_AsReadBuffer (pattern, &buffer, &pattern_size) == -1)
+    return NULL;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      found = target_search_memory (start_addr, length,
+				    buffer, pattern_size,
+				    &found_addr);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  if (found)
+    return PyLong_FromLong (found_addr);
+  else
+    Py_RETURN_NONE;
+}
+
+
+
+/* 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);
+
+  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);
+    }
+
+  inf_obj->nthreads = 0;
+
+  Py_DECREF ((PyObject *) inf_obj);
+  do_cleanups (cleanup);
+}
+
+void
+gdbpy_initialize_inferior (void)
+{
+  if (PyType_Ready (&inferior_object_type) < 0)
+    return;
+
+  Py_INCREF (&inferior_object_type);
+  PyModule_AddObject (gdb_module, "Inferior",
+		      (PyObject *) &inferior_object_type);
+
+  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);
+
+  if (PyType_Ready (&membuf_object_type) < 0)
+    return;
+
+  Py_INCREF (&membuf_object_type);
+  PyModule_AddObject (gdb_module, "Membuf", (PyObject *)
+		      &membuf_object_type);
+}
+
+
+
+static 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 },
+  { NULL }
+};
+
+static PyMethodDef inferior_object_methods[] =
+{
+  { "threads", infpy_threads, METH_NOARGS,
+    "Return all the threads of this inferior." },
+  { "read_memory", infpy_read_memory, METH_VARARGS,
+    "read_memory (address, length) -> buffer\n\
+Return a buffer object for reading from the inferior's memory." },
+  { "write_memory", infpy_write_memory, METH_VARARGS,
+    "write_memory (address, buffer [, length])\n\
+Write the given buffer object to the inferior's memory." },
+  { "search_memory", (PyCFunction) infpy_search_memory,
+    METH_VARARGS | METH_KEYWORDS,
+    "search_memory (address, length, pattern) -> long\n\
+Return a long with the address of a match, or None." },
+
+  { NULL }
+};
+
+static PyTypeObject inferior_object_type =
+{
+  PyObject_HEAD_INIT (NULL)
+  0,				  /* ob_size */
+  "gdb.Inferior",		  /* tp_name */
+  sizeof (inferior_object),	  /* tp_basicsize */
+  0,				  /* tp_itemsize */
+  0,				  /* tp_dealloc */
+  0,				  /* tp_print */
+  0,				  /* tp_getattr */
+  0,				  /* tp_setattr */
+  0,				  /* tp_compare */
+  0,				  /* tp_repr */
+  0,				  /* tp_as_number */
+  0,				  /* tp_as_sequence */
+  0,				  /* tp_as_mapping */
+  0,				  /* tp_hash  */
+  0,				  /* tp_call */
+  0,				  /* tp_str */
+  0,				  /* tp_getattro */
+  0,				  /* tp_setattro */
+  0,				  /* tp_as_buffer */
+  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER,  /* tp_flags */
+  "GDB inferior object",	  /* tp_doc */
+  0,				  /* tp_traverse */
+  0,				  /* tp_clear */
+  0,				  /* tp_richcompare */
+  0,				  /* tp_weaklistoffset */
+  0,				  /* tp_iter */
+  0,				  /* tp_iternext */
+  inferior_object_methods,	  /* tp_methods */
+  0,				  /* tp_members */
+  inferior_object_getset,	  /* tp_getset */
+  0,				  /* tp_base */
+  0,				  /* tp_dict */
+  0,				  /* tp_descr_get */
+  0,				  /* tp_descr_set */
+  0,				  /* tp_dictoffset */
+  0,				  /* tp_init */
+  0				  /* tp_alloc */
+};
+
+
+
+/* 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
+};
+
+static PyTypeObject membuf_object_type = {
+  PyObject_HEAD_INIT (NULL)
+  0,				  /*ob_size*/
+  "gdb.Membuf",			  /*tp_name*/
+  sizeof (membuf_object),	  /*tp_basicsize*/
+  0,				  /*tp_itemsize*/
+  mbpy_dealloc,			  /*tp_dealloc*/
+  0,				  /*tp_print*/
+  0,				  /*tp_getattr*/
+  0,				  /*tp_setattr*/
+  0,				  /*tp_compare*/
+  0,				  /*tp_repr*/
+  0,				  /*tp_as_number*/
+  0,				  /*tp_as_sequence*/
+  0,				  /*tp_as_mapping*/
+  0,				  /*tp_hash */
+  0,				  /*tp_call*/
+  mbpy_str,			  /*tp_str*/
+  0,				  /*tp_getattro*/
+  0,				  /*tp_setattro*/
+  &buffer_procs,		  /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT,		  /*tp_flags*/
+  "GDB memory buffer object", 	  /*tp_doc*/
+  0,				  /* tp_traverse */
+  0,				  /* tp_clear */
+  0,				  /* tp_richcompare */
+  0,				  /* tp_weaklistoffset */
+  0,				  /* tp_iter */
+  0,				  /* tp_iternext */
+  0,				  /* tp_methods */
+  0,				  /* tp_members */
+  0,				  /* tp_getset */
+  0,				  /* tp_base */
+  0,				  /* tp_dict */
+  0,				  /* tp_descr_get */
+  0,				  /* tp_descr_set */
+  0,				  /* tp_dictoffset */
+  0,				  /* tp_init */
+  0,				  /* tp_alloc */
+  PyType_GenericNew		  /* tp_new */
+};
diff --git a/gdb/python/py-infthread.c b/gdb/python/py-infthread.c
new file mode 100644
index 0000000..dfeb285
--- /dev/null
+++ b/gdb/python/py-infthread.c
@@ -0,0 +1,303 @@
+/* Python interface to inferior threads.
+
+   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "exceptions.h"
+#include "gdbthread.h"
+#include "inferior.h"
+#include "python-internal.h"
+
+static PyTypeObject thread_object_type;
+
+/* Require that INFERIOR be a valid inferior ID.  */
+#define THPY_REQUIRE_VALID(Thread)				\
+  do {								\
+    if (!Thread->thread)					\
+      {								\
+	PyErr_SetString (PyExc_RuntimeError,			\
+			 _("Thread no longer exists."));	\
+	return NULL;						\
+      }								\
+  } while (0)
+
+
+
+thread_object *
+create_thread_object (struct thread_info *tp)
+{
+  thread_object *thread_obj;
+
+  thread_obj = PyObject_New (thread_object, &thread_object_type);
+  if (!thread_obj)
+    return NULL;
+
+  thread_obj->thread = tp;
+  thread_obj->inf_obj = find_inferior_object (PIDGET (tp->ptid));
+  Py_INCREF (thread_obj->inf_obj);
+
+  return thread_obj;
+}
+
+
+
+static void
+thpy_dealloc (PyObject *self)
+{
+  Py_DECREF (((thread_object *) self)->inf_obj);
+  self->ob_type->tp_free (self);
+}
+
+static PyObject *
+thpy_get_num (PyObject *self, void *closure)
+{
+  thread_object *thread_obj = (thread_object *) self;
+
+  THPY_REQUIRE_VALID (thread_obj);
+
+  return PyLong_FromLong (thread_obj->thread->num);
+}
+
+/* Getter for InferiorThread.ptid  -> (pid, lwp, tid).
+   Returns a tuple with the thread's ptid components.  */
+static PyObject *
+thpy_get_ptid (PyObject *self, void *closure)
+{
+  int pid;
+  long tid, lwp;
+  thread_object *thread_obj = (thread_object *) self;
+  PyObject *ret;
+
+  THPY_REQUIRE_VALID (thread_obj);
+
+  ret = PyTuple_New (3);
+  if (!ret)
+    return NULL;
+
+  pid = ptid_get_pid (thread_obj->thread->ptid);
+  lwp = ptid_get_lwp (thread_obj->thread->ptid);
+  tid = ptid_get_tid (thread_obj->thread->ptid);
+
+  PyTuple_SET_ITEM (ret, 0, PyInt_FromLong (pid));
+  PyTuple_SET_ITEM (ret, 1, PyInt_FromLong (lwp));
+  PyTuple_SET_ITEM (ret, 2, PyInt_FromLong (tid));
+
+  return ret;
+}
+
+
+
+/* Implementation of InferiorThread.newest_frame () -> gdb.Frame.
+   Returns the newest frame object.  */
+PyObject *
+thpy_newest_frame (PyObject *self, PyObject *args)
+{
+  struct frame_info *frame;
+  PyObject *frame_obj = NULL;   /* Initialize to appease gcc warning.  */
+  thread_object *thread_obj = (thread_object *) self;
+  struct cleanup *cleanup;
+  volatile struct gdb_exception except;
+
+  THPY_REQUIRE_VALID (thread_obj);
+
+  cleanup = make_cleanup_restore_current_thread ();
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      switch_to_thread (thread_obj->thread->ptid);
+
+      frame = get_current_frame ();
+      frame_obj = frame_info_to_frame_object (frame);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  do_cleanups (cleanup);
+
+  return frame_obj;
+}
+
+/* Implementation of InferiorThread.switch ().
+   Makes this the GDB selected thread.  */
+static PyObject *
+thpy_switch (PyObject *self, PyObject *args)
+{
+  thread_object *thread_obj = (thread_object *) self;
+  struct cleanup *cleanup;
+  volatile struct gdb_exception except;
+
+  THPY_REQUIRE_VALID (thread_obj);
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      switch_to_thread (thread_obj->thread->ptid);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  Py_RETURN_NONE;
+}
+
+/* Implementation of InferiorThread.is_stopped () -> Boolean.
+   Return whether the thread is stopped.  */
+static PyObject *
+thpy_is_stopped (PyObject *self, PyObject *args)
+{
+  thread_object *thread_obj = (thread_object *) self;
+
+  THPY_REQUIRE_VALID (thread_obj);
+
+  if (is_stopped (thread_obj->thread->ptid))
+    Py_RETURN_TRUE;
+
+  Py_RETURN_FALSE;
+}
+
+/* Implementation of InferiorThread.is_running () -> Boolean.
+   Return whether the thread is running.  */
+static PyObject *
+thpy_is_running (PyObject *self, PyObject *args)
+{
+  thread_object *thread_obj = (thread_object *) self;
+
+  THPY_REQUIRE_VALID (thread_obj);
+
+  if (is_running (thread_obj->thread->ptid))
+    Py_RETURN_TRUE;
+
+  Py_RETURN_FALSE;
+}
+
+/* Implementation of InferiorThread.is_exited () -> Boolean.
+   Return whether the thread is exited.  */
+static PyObject *
+thpy_is_exited (PyObject *self, PyObject *args)
+{
+  thread_object *thread_obj = (thread_object *) self;
+
+  THPY_REQUIRE_VALID (thread_obj);
+
+  if (is_exited (thread_obj->thread->ptid))
+    Py_RETURN_TRUE;
+
+  Py_RETURN_FALSE;
+}
+
+
+
+/* Implementation of gdb.selected_thread () -> gdb.InferiorThread.
+   Returns the selected thread object.  */
+PyObject *
+gdbpy_selected_thread (PyObject *self, PyObject *args)
+{
+  PyObject *thread_obj;
+
+  thread_obj = (PyObject *) find_thread_object (inferior_ptid);
+  if (thread_obj)
+    {
+      Py_INCREF (thread_obj);
+      return thread_obj;
+    }
+
+  Py_RETURN_NONE;
+}
+
+
+
+void
+gdbpy_initialize_thread (void)
+{
+  if (PyType_Ready (&thread_object_type) < 0)
+    return;
+
+  Py_INCREF (&thread_object_type);
+  PyModule_AddObject (gdb_module, "InferiorThread",
+		      (PyObject *) &thread_object_type);
+}
+
+
+
+static PyGetSetDef thread_object_getset[] =
+{
+  { "num", thpy_get_num, NULL, "ID of the thread, as assigned by GDB.", NULL },
+  { "ptid", thpy_get_ptid, NULL, "ID of the thread, as assigned by the OS.",
+    NULL },
+
+  { NULL }
+};
+
+static PyMethodDef thread_object_methods[] =
+{
+  { "newest_frame", thpy_newest_frame, METH_NOARGS,
+    "newest_frame () -> gdb.Frame\n\
+Return the newest frame in the thread." },
+  { "switch", thpy_switch, METH_NOARGS,
+    "switch ()\n\
+Makes this the GDB selected thread." },
+  { "is_stopped", thpy_is_stopped, METH_NOARGS,
+    "is_stopped () -> Boolean\n\
+Return whether the thread is stopped." },
+  { "is_running", thpy_is_running, METH_NOARGS,
+    "is_running () -> Boolean\n\
+Return whether the thread is running." },
+  { "is_exited", thpy_is_exited, METH_NOARGS,
+    "is_exited () -> Boolean\n\
+Return whether the thread is exited." },
+
+  { NULL }
+};
+
+static PyTypeObject thread_object_type =
+{
+  PyObject_HEAD_INIT (NULL)
+  0,				  /*ob_size*/
+  "gdb.InferiorThread",		  /*tp_name*/
+  sizeof (thread_object),	  /*tp_basicsize*/
+  0,				  /*tp_itemsize*/
+  thpy_dealloc,			  /*tp_dealloc*/
+  0,				  /*tp_print*/
+  0,				  /*tp_getattr*/
+  0,				  /*tp_setattr*/
+  0,				  /*tp_compare*/
+  0,				  /*tp_repr*/
+  0,				  /*tp_as_number*/
+  0,				  /*tp_as_sequence*/
+  0,				  /*tp_as_mapping*/
+  0,				  /*tp_hash */
+  0,				  /*tp_call*/
+  0,				  /*tp_str*/
+  0,				  /*tp_getattro*/
+  0,				  /*tp_setattro*/
+  0,				  /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER,  /*tp_flags*/
+  "GDB thread object",		  /* tp_doc */
+  0,				  /* tp_traverse */
+  0,				  /* tp_clear */
+  0,				  /* tp_richcompare */
+  0,				  /* tp_weaklistoffset */
+  0,				  /* tp_iter */
+  0,				  /* tp_iternext */
+  thread_object_methods,	  /* tp_methods */
+  0,				  /* tp_members */
+  thread_object_getset,		  /* tp_getset */
+  0,				  /* tp_base */
+  0,				  /* tp_dict */
+  0,				  /* tp_descr_get */
+  0,				  /* tp_descr_set */
+  0,				  /* tp_dictoffset */
+  0,				  /* tp_init */
+  0				  /* tp_alloc */
+};
diff --git a/gdb/python/py-utils.c b/gdb/python/py-utils.c
index 944e6b4..90609fa 100644
--- a/gdb/python/py-utils.c
+++ b/gdb/python/py-utils.c
@@ -19,6 +19,7 @@
 
 #include "defs.h"
 #include "charset.h"
+#include "value.h"
 #include "python-internal.h"
 
 
@@ -272,3 +273,51 @@ gdbpy_exception_to_string (PyObject *ptype, PyObject *pvalue)
 
   return str;
 }
+
+/* Converts OBJ to a CORE_ADDR value.
+
+   Returns 1 on success or 0 on failure, with a Python exception set.  This
+   function can also throw GDB exceptions.
+*/
+
+int
+get_addr_from_python (PyObject *obj, CORE_ADDR *addr)
+{
+  if (gdbpy_is_value_object (obj))
+    *addr = value_as_address (value_object_to_value (obj));
+  else if (PyLong_Check (obj))
+    {
+      /* Assume CORE_ADDR corresponds to unsigned long.  */
+      *addr = PyLong_AsUnsignedLong (obj);
+      if (PyErr_Occurred () != NULL)
+	return 0;
+    }
+  else if (PyInt_Check (obj))
+    {
+      long val;
+
+      /* Assume CORE_ADDR corresponds to unsigned long.  */
+      val = PyInt_AsLong (obj);
+
+      if (val >= 0)
+	*addr = val;
+      else
+      {
+	/* If no error ocurred, VAL is indeed negative.  */
+	if (PyErr_Occurred () != NULL)
+	  return 0;
+
+	PyErr_SetString (PyExc_ValueError,
+			 _("Supplied address is negative."));
+	return 0;
+      }
+    }
+  else
+    {
+      PyErr_SetString (PyExc_TypeError,
+		       _("Invalid type for address."));
+      return 0;
+    }
+
+  return 1;
+}
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
index eb20de8..2024021 100644
--- a/gdb/python/py-value.c
+++ b/gdb/python/py-value.c
@@ -43,6 +43,10 @@
 /* Python's long type corresponds to C's long long type.  */
 #define builtin_type_pylong builtin_type (python_gdbarch)->builtin_long_long
 
+/* Python's long type corresponds to C's long long type.  Unsigned version.  */
+#define builtin_type_upylong builtin_type \
+  (python_gdbarch)->builtin_unsigned_long_long
+
 #define builtin_type_pybool \
   language_bool_type (python_language, python_gdbarch)
 
@@ -961,7 +965,34 @@ convert_value_from_python (PyObject *obj)
 	{
 	  LONGEST l = PyLong_AsLongLong (obj);
 
-	  if (! PyErr_Occurred ())
+	  if (PyErr_Occurred ())
+	    {
+	      /* If the error was an overflow, we can try converting to
+	         ULONGEST instead.  */
+	      if (PyErr_ExceptionMatches (PyExc_OverflowError))
+		{
+		  PyObject *etype, *evalue, *etraceback, *zero;
+
+		  PyErr_Fetch (&etype, &evalue, &etraceback);
+		  zero = PyInt_FromLong (0);
+
+		  /* Check whether obj is positive.  */
+		  if (PyObject_RichCompareBool (obj, zero, Py_GT) > 0)
+		    {
+		      ULONGEST ul;
+
+		      ul = PyLong_AsUnsignedLongLong (obj);
+		      if (! PyErr_Occurred ())
+			value = value_from_ulongest (builtin_type_upylong, ul);
+		    }
+		  else
+		    /* There's nothing we can do.  */
+		    PyErr_Restore (etype, evalue, etraceback);
+
+		  Py_DECREF (zero);
+		}
+	    }
+	  else
 	    value = value_from_longest (builtin_type_pylong, l);
 	}
       else if (PyFloat_Check (obj))
@@ -1028,6 +1059,14 @@ gdbpy_history (PyObject *self, PyObject *args)
   return value_to_value_object (res_val);
 }
 
+/* Returns 1 in OBJ is a gdb.Value object, 0 otherwise.  */
+
+int
+gdbpy_is_value_object (PyObject *obj)
+{
+  return PyObject_TypeCheck (obj, &value_object_type);
+}
+
 void
 gdbpy_initialize_values (void)
 {
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 5bd2a4b..daaed2c 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -80,6 +80,17 @@ extern PyTypeObject value_object_type;
 extern PyTypeObject block_object_type;
 extern PyTypeObject symbol_object_type;
 
+typedef struct
+{
+  PyObject_HEAD
+
+  /* The thread we represent.  */
+  struct thread_info *thread;
+
+  /* The Inferior object to which this thread belongs.  */
+  PyObject *inf_obj;
+} thread_object;
+
 extern struct cmd_list_element *set_python_list;
 extern struct cmd_list_element *show_python_list;
 
@@ -92,6 +103,8 @@ PyObject *gdbpy_block_for_pc (PyObject *self, PyObject *args);
 PyObject *gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw);
 PyObject *gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
 					   const char *encoding, struct type *type);
+PyObject *gdbpy_inferiors (PyObject *unused, PyObject *unused2);
+PyObject *gdbpy_selected_thread (PyObject *self, PyObject *args);
 PyObject *gdbpy_string_to_argv (PyObject *self, PyObject *args);
 PyObject *gdbpy_get_hook_function (const char *);
 PyObject *gdbpy_parameter (PyObject *self, PyObject *args);
@@ -106,6 +119,7 @@ PyObject *symbol_to_symbol_object (struct symbol *sym);
 PyObject *block_to_block_object (struct block *block, struct objfile *objfile);
 PyObject *value_to_value_object (struct value *v);
 PyObject *type_to_type_object (struct type *);
+PyObject *frame_info_to_frame_object (struct frame_info *frame);
 
 PyObject *pspace_to_pspace_object (struct program_space *);
 PyObject *pspy_get_printers (PyObject *, void *);
@@ -113,6 +127,10 @@ PyObject *pspy_get_printers (PyObject *, void *);
 PyObject *objfile_to_objfile_object (struct objfile *);
 PyObject *objfpy_get_printers (PyObject *, void *);
 
+thread_object *create_thread_object (struct thread_info *tp);
+thread_object *find_thread_object (ptid_t ptid);
+PyObject *find_inferior_object (int pid);
+
 struct block *block_object_to_block (PyObject *obj);
 struct symbol *symbol_object_to_symbol (PyObject *obj);
 struct value *value_object_to_value (PyObject *self);
@@ -136,6 +154,8 @@ void gdbpy_initialize_objfile (void);
 void gdbpy_initialize_breakpoints (void);
 void gdbpy_initialize_lazy_string (void);
 void gdbpy_initialize_parameters (void);
+void gdbpy_initialize_thread (void);
+void gdbpy_initialize_inferior (void);
 
 struct cleanup *make_cleanup_py_decref (PyObject *py);
 
@@ -188,6 +208,8 @@ gdb_byte *gdbpy_extract_lazy_string (PyObject *string,
 				     struct type **str_type, 
 				     long *length, char **encoding);
 
+int gdbpy_is_value_object (PyObject *obj);
+
 /* Note that these are declared here, and not in python.h with the
    other pretty-printer functions, because they refer to PyObject.  */
 PyObject *apply_varobj_pretty_printer (PyObject *print_obj,
@@ -204,4 +226,6 @@ extern PyObject *gdbpy_enabled_cst;
 
 extern PyObject *gdbpy_gdberror_exc;
 
+int get_addr_from_python (PyObject *obj, CORE_ADDR *addr);
+
 #endif /* GDB_PYTHON_INTERNAL_H */
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 31880c1..77aed6e 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -686,6 +686,8 @@ Enables or disables printing of Python stack traces."),
   gdbpy_initialize_objfile ();
   gdbpy_initialize_breakpoints ();
   gdbpy_initialize_lazy_string ();
+  gdbpy_initialize_thread ();
+  gdbpy_initialize_inferior ();
 
   PyRun_SimpleString ("import gdb");
   PyRun_SimpleString ("gdb.pretty_printers = []");
@@ -799,7 +801,12 @@ Arguments are separate by spaces and may be quoted."
     "Write a string using gdb's filtered stream." },
   { "flush", gdbpy_flush, METH_NOARGS,
     "Flush gdb's filtered stdout stream." },
-
+  { "selected_thread", gdbpy_selected_thread, METH_NOARGS,
+    "selected_thread () -> gdb.InferiorThread.\n\
+Return the selected thread object." },
+  { "inferiors", gdbpy_inferiors, METH_NOARGS,
+    "inferiors () -> (gdb.Inferior, ...).\n\
+Return a tuple containing all inferiors." },
   {NULL, NULL, 0, NULL}
 };
 
diff --git a/gdb/testsuite/gdb.python/Makefile.in b/gdb/testsuite/gdb.python/Makefile.in
index c6a2678..660941d 100644
--- a/gdb/testsuite/gdb.python/Makefile.in
+++ b/gdb/testsuite/gdb.python/Makefile.in
@@ -2,7 +2,7 @@ VPATH = @srcdir@
 srcdir = @srcdir@
 
 EXECUTABLES = py-type py-value py-prettyprint py-template py-block \
-		py-symbol py-mi py-breakpoint
+		py-symbol py-mi py-breakpoint py-inferior py-infthread
 
 all info install-info dvi install uninstall installcheck check:
 	@echo "Nothing to be done for $@..."
diff --git a/gdb/testsuite/gdb.python/py-inferior.c b/gdb/testsuite/gdb.python/py-inferior.c
new file mode 100644
index 0000000..0b48299
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-inferior.c
@@ -0,0 +1,49 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#define CHUNK_SIZE 16000 /* same as findcmd.c's */
+#define BUF_SIZE (2 * CHUNK_SIZE) /* at least two chunks */
+
+static int8_t int8_search_buf[100];
+static int16_t int16_search_buf[100];
+static int32_t int32_search_buf[100];
+static int64_t int64_search_buf[100];
+
+static char *search_buf;
+static int search_buf_size;
+
+static int x;
+
+
+int f2 (int a)
+{
+  char *str = "hello, testsuite";
+
+  puts (str);	/* Break here.  */
+
+  return ++a;
+}
+
+int f1 (int a, int b)
+{
+  return f2(a) + b;
+}
+
+static void
+init_bufs ()
+{
+  search_buf_size = BUF_SIZE;
+  search_buf = malloc (search_buf_size);
+  if (search_buf == NULL)
+    exit (1);
+  memset (search_buf, 'x', search_buf_size);
+}
+
+int main (int argc, char *argv[])
+{
+  init_bufs ();
+
+  return f1 (1, 2);
+}
diff --git a/gdb/testsuite/gdb.python/py-inferior.exp b/gdb/testsuite/gdb.python/py-inferior.exp
new file mode 100644
index 0000000..309ae8c
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-inferior.exp
@@ -0,0 +1,191 @@
+# Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite.  It tests the mechanism
+# exposing inferiors to Python.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+# Run a command in GDB, and report a failure if a Python exception is thrown.
+# If report_pass is true, report a pass if no exception is thrown.
+proc gdb_py_test_silent_cmd {cmd name report_pass} {
+    global gdb_prompt
+
+  gdb_test_multiple $cmd $name {
+      -re "Traceback.*$gdb_prompt $"  { fail $name }
+      -re "$gdb_prompt $"	      { if $report_pass { pass $name } }
+  }
+}
+
+set testfile "py-inferior"
+set srcfile ${testfile}.c
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
+    return -1
+}
+
+# Start with a fresh gdb.
+clean_restart ${testfile}
+
+# Skip all tests if Python scripting is not enabled.
+if { [skip_python_tests] } { continue }
+
+# The following tests require execution.
+
+if ![runto_main] then {
+    fail "Can't run to main"
+    return 0
+}
+
+runto [gdb_get_line_number "Break here."]
+
+# Test basic gdb.Inferior attributes and methods.
+
+gdb_py_test_silent_cmd "python inferiors = gdb.inferiors ()" "get inferiors list" 1
+gdb_test "python print inferiors" "\\(<gdb.Inferior object at 0x\[\[:xdigit:\]\]+>,\\)" "verify inferiors list"
+gdb_py_test_silent_cmd "python i0 = inferiors\[0\]" "get first inferior" 0
+
+gdb_test "python print 'result =', i0 == inferiors\[0\]" " = True" "test equality comparison (true)"
+gdb_test "python print 'result =', i0.num" " = \[0-9\]+" "test Inferior.num"
+gdb_test "python print 'result =', i0.pid" " = \[0-9\]+" "test Inferior.pid"
+gdb_test "python print 'result =', i0.was_attached" " = False" "test Inferior.was_attached"
+gdb_test "python print i0.threads ()" "\\(<gdb.InferiorThread object at 0x\[\[:xdigit:\]\]+>,\\)" "test Inferior.threads"
+
+# Test memory read and write operations.
+
+gdb_py_test_silent_cmd "python addr = gdb.selected_frame ().read_var ('str')" \
+  "read str address" 0
+gdb_py_test_silent_cmd "python str = gdb.inferiors()\[0\].read_memory (addr, 5)" \
+  "read str contents" 1
+gdb_py_test_silent_cmd "python str\[1\] = 'a'" "change str" 0
+gdb_py_test_silent_cmd "python gdb.inferiors()\[0\].write_memory (addr, str)" \
+  "write str" 1
+gdb_test "print str" " = 0x\[\[:xdigit:\]\]+ \"hallo, testsuite\"" \
+  "ensure str was changed in the inferior"
+
+# Test memory search.
+
+set hex_number {0x[0-9a-fA-F][0-9a-fA-F]*}
+set dec_number {[0-9]+}
+set history_prefix {[$][0-9]* = }
+set newline {[\r\n]+}
+set pattern_not_found "${newline}.None"
+set one_pattern_found "${newline}.${dec_number}"
+
+# Test string pattern.
+
+gdb_test "set *(int32_t*) &int8_search_buf\[10\] = 0x61616161" "" ""
+gdb_test "py search_buf = gdb.selected_frame ().read_var ('int8_search_buf')" "" ""
+gdb_test "py start_addr = search_buf.address" "" ""
+gdb_test "py length = search_buf.type.sizeof" "" ""
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, 'aaa')" \
+  "${one_pattern_found}" "find string pattern"
+
+# Test not finding pattern because search range too small, with
+# potential find at the edge of the range.
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, 10+3, 'aaaa')" \
+  "${pattern_not_found}" "pattern not found at end of range"
+
+# Increase the search range by 1 and we should find the pattern.
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, 10+3+1, 'aaa')" \
+  "${one_pattern_found}" "pattern found at end of range"
+
+# Import struct to pack the following patterns.
+gdb_test "py from struct import *" "" ""
+
+# Test 16-bit pattern.
+
+gdb_test "set int16_search_buf\[10\] = 0x1234" "" ""
+gdb_test "py search_buf = gdb.selected_frame ().read_var ('int16_search_buf')" "" ""
+gdb_test "py start_addr = search_buf.address" "" ""
+gdb_test "py length = search_buf.type.sizeof" "" ""
+gdb_test "py pattern = pack('H',0x1234)" "" \
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, pattern)" \
+  "${one_pattern_found}" "find 16-bit pattern, with value pattern"
+
+# Test 32-bit pattern.
+
+gdb_test "set int32_search_buf\[10\] = 0x12345678" "" ""
+gdb_test "py search_buf = gdb.selected_frame ().read_var ('int32_search_buf')" "" ""
+gdb_test "py start_addr = search_buf.address" "" ""
+gdb_test "py length = search_buf.type.sizeof" "" ""
+gdb_test "py pattern = pack('I',0x12345678)" "" \
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, pattern)" \
+  "${one_pattern_found}" "find 32-bit pattern, with python pattern"
+
+# Test 64-bit pattern.
+
+gdb_test "set int64_search_buf\[10\] = 0xfedcba9876543210LL" "" ""
+gdb_test "py search_buf = gdb.selected_frame ().read_var ('int64_search_buf')" "" ""
+gdb_test "py start_addr = search_buf.address" "" ""
+gdb_test "py length = search_buf.type.sizeof" "" ""
+gdb_test "py pattern = pack('Q', 0xfedcba9876543210)" "" ""
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, pattern)" \
+  "${one_pattern_found}" "find 64-bit pattern, with value pattern"
+
+# Test mixed-sized patterns.
+
+gdb_test "set *(int8_t*) &search_buf\[10\] = 0x62" "" ""
+gdb_test "set *(int16_t*) &search_buf\[11\] = 0x6363" "" ""
+gdb_test "set *(int32_t*) &search_buf\[13\] = 0x64646464" "" ""
+gdb_test "py search_buf = gdb.selected_frame ().read_var ('search_buf')" "" ""
+gdb_test "py start_addr = search_buf\[0\].address" "" ""
+gdb_test "py pattern1 = pack('B', 0x62)" "" ""
+gdb_test "py pattern2 = pack('H', 0x6363)" "" ""
+gdb_test "py pattern3 = pack('I', 0x64646464)" "" ""
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, 100, pattern1)" \
+    "${one_pattern_found}" "find mixed-sized pattern"
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, 100, pattern2)" \
+    "${one_pattern_found}" "find mixed-sized pattern"
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, 100, pattern3)" \
+    "${one_pattern_found}" "find mixed-sized pattern"
+
+# Test search spanning a large range, in the particular case of native
+# targets, test the search spanning multiple chunks.
+# Remote targets may implement the search differently.
+
+set CHUNK_SIZE 16000 ;
+
+gdb_test "set *(int32_t*) &search_buf\[0*${CHUNK_SIZE}+100\] = 0x12345678" "" ""
+gdb_test "set *(int32_t*) &search_buf\[1*${CHUNK_SIZE}+100\] = 0x12345678" "" ""
+gdb_test "py start_addr = gdb.selected_frame ().read_var ('search_buf')" "" ""
+gdb_test "py length = gdb.selected_frame ().read_var ('search_buf_size')" "" ""
+gdb_test "py pattern = pack('I', 0x12345678)" "" ""
+gdb_test "py first = gdb.inferiors()\[0\].search_memory (start_addr,length, pattern)" "" ""
+gdb_test "py print first" "${one_pattern_found}" "search spanning large range 1st result"
+gdb_test "py start_addr = first + 1"
+gdb_test "py second = gdb.inferiors()\[0\].search_memory (start_addr, length, pattern)" "" ""
+gdb_test "py print second" "${one_pattern_found}" "search spanning large range 2nd result"
+gdb_test "py start_addr = second + 1"
+gdb_test "py third = gdb.inferiors()\[0\].search_memory (start_addr, length, pattern)" "" ""
+gdb_test "py print third" "${pattern_not_found}" "search spanning large range 3rd result"
+
+# For native targets, test a pattern straddling a chunk boundary.
+
+if [isnative] {
+    gdb_test "set *(int32_t*) &search_buf\[${CHUNK_SIZE}-1\] = 0xfdb97531" "" ""
+    gdb_test "py pattern = pack('I', 0xfdb97531)" "" ""
+    gdb_test "py start_addr = gdb.selected_frame ().read_var ('search_buf')" "" ""
+    gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, pattern)" \
+      "${one_pattern_found}" "find pattern straddling chunk boundary"
+}
diff --git a/gdb/testsuite/gdb.python/py-infthread.c b/gdb/testsuite/gdb.python/py-infthread.c
new file mode 100644
index 0000000..22eb9f2
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-infthread.c
@@ -0,0 +1,14 @@
+int f2 (int a)
+{
+  return ++a;
+}
+
+int f1 (int a, int b)
+{
+  return f2(a) + b;
+}
+
+int main (int argc, char *argv[])
+{
+  return f1 (1, 2);
+}
diff --git a/gdb/testsuite/gdb.python/py-infthread.exp b/gdb/testsuite/gdb.python/py-infthread.exp
new file mode 100644
index 0000000..a25d0b5
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-infthread.exp
@@ -0,0 +1,53 @@
+# Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite.  It tests the mechanism
+# exposing inferior threads to Python.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+set testfile "py-infthread"
+set srcfile ${testfile}.c
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
+    return -1
+}
+
+# Start with a fresh gdb.
+clean_restart ${testfile}
+
+# Skip all tests if Python scripting is not enabled.
+if { [skip_python_tests] } { continue }
+
+# The following tests require execution.
+
+if ![runto_main] then {
+    fail "Can't run to main"
+    return 0
+}
+
+runto [gdb_get_line_number "Break here."]
+
+# Test basic gdb.Inferior attributes and methods.
+
+gdb_py_test_silent_cmd "python t0 = gdb.selected_thread ()" "test gdb.selected_thread" 1
+gdb_test "python print t0" "\\<gdb.InferiorThread object at 0x\[\[:xdigit:\]\]+>" "verify InferiorThread object"
+gdb_test "python print 'result =', t0.num" " = \[0-9\]+" "test Inferior.num"
+gdb_test "python print 'result =', t0.ptid" " = \\(\[0-9\]+, \[0-9\]+, \[0-9\]+\\)" "test InferiorThread.ptid"
+
+gdb_test "python print 'result =', t0.is_stopped ()" " = True" "test InferiorThread.is_stopped"
+gdb_test "python print 'result =', t0.is_running ()" " = False" "test InferiorThread.is_running"
+gdb_test "python print 'result =', t0.is_exited ()" " = False" "test InferiorThread.is_exited"
diff --git a/gdb/value.c b/gdb/value.c
index 5e0e8d8..8812fe1 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2244,6 +2244,43 @@ pack_long (gdb_byte *buf, struct type *type, LONGEST num)
 }
 
 
+/* Pack NUM into BUF using a target format of TYPE.  */
+
+void
+pack_unsigned_long (gdb_byte *buf, struct type *type, ULONGEST num)
+{
+  int len;
+  enum bfd_endian byte_order;
+
+  type = check_typedef (type);
+  len = TYPE_LENGTH (type);
+  byte_order = gdbarch_byte_order (get_type_arch (type));
+
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_INT:
+    case TYPE_CODE_CHAR:
+    case TYPE_CODE_ENUM:
+    case TYPE_CODE_FLAGS:
+    case TYPE_CODE_BOOL:
+    case TYPE_CODE_RANGE:
+    case TYPE_CODE_MEMBERPTR:
+      store_unsigned_integer (buf, len, byte_order, num);
+      break;
+
+    case TYPE_CODE_REF:
+    case TYPE_CODE_PTR:
+      store_typed_address (buf, type, (CORE_ADDR) num);
+      break;
+
+    default:
+      error (_("\
+Unexpected type (%d) encountered for unsigned integer constant."),
+	     TYPE_CODE (type));
+    }
+}
+
+
 /* Convert C numbers into newly allocated values.  */
 
 struct value *
@@ -2256,6 +2293,19 @@ value_from_longest (struct type *type, LONGEST num)
 }
 
 
+/* Convert C unsigned numbers into newly allocated values.  */
+
+struct value *
+value_from_ulongest (struct type *type, ULONGEST num)
+{
+  struct value *val = allocate_value (type);
+
+  pack_unsigned_long (value_contents_raw (val), type, num);
+
+  return val;
+}
+
+
 /* Create a value representing a pointer of type TYPE to the address
    ADDR.  */
 struct value *
diff --git a/gdb/value.h b/gdb/value.h
index c3dfb17..474e661 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -366,6 +366,7 @@ extern LONGEST unpack_field_as_long (struct type *type,
 extern void pack_long (gdb_byte *buf, struct type *type, LONGEST num);
 
 extern struct value *value_from_longest (struct type *type, LONGEST num);
+extern struct value *value_from_ulongest (struct type *type, ULONGEST num);
 extern struct value *value_from_pointer (struct type *type, CORE_ADDR addr);
 extern struct value *value_from_double (struct type *type, DOUBLEST num);
 extern struct value *value_from_decfloat (struct type *type,


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]