This is the mail archive of the archer@sourceware.org mailing list for the Archer 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]

Add gdb.read_memory, gdb.write_memory and gdb.Membuf.


Hi,

One thing which has been in the back of my mind for the Python support
in GDB is a way to read and write from/to the inferior memory. This
patch addresses that.

It's very simple: gdb.read_memory takes an address and a length and
reads the bytes from the inferior, placing them in a Python buffer
object. gdb.write_memory takes an address and a Python object supporting
the buffer protocol[0] (i.e., the object from read_memory, an array or a
string) and writes it to the inferior memory.

An excerpt from the documentation:

"Python objects implemented in C can export a group of functions called
the âbuffer interface.â These functions can be used by an object to
expose its data in a raw, byte-oriented format. Clients of the object
can use the buffer interface to access the object data directly, without
needing to copy it first."

Sounds like Python's buffer mechanism is made for exactly this kind of
use. Here's an example:

(gdb) p argv[0]
$2 = 0xbffff37a "/tmp/hello"
(gdb) py b = gdb.read_memory(0xbffff37a, 10)
(gdb) py print b
/tmp/hello
(gdb) py b[6] = 'a'
(gdb) py print b
/tmp/hallo
(gdb) py gdb.write_memory(0xbffff37a, b)
(gdb) print argv[0]
$3 = 0xbffff37a "/tmp/hallo"

It's possible to do more advanced byte manipulation using the struct
module[1].

The only drawback is that the buffer interface was changed in
Python 3.0, so GDB will have to be changed to support the new version of
Python. I had a cursory look at the changes, and it seems it wouldn't be
hard to support it. Most changes are additions to the interface, and the
spirit and base of it remains the same. There's more info at the "What's
new in Python 2.6" article[2], and details in PEP-3118[3].

Refs:
[0] - http://docs.python.org/c-api/buffer.html
[1] - http://docs.python.org/library/struct.html
[2] - http://docs.python.org/dev/3.0/whatsnew/2.6.html#pep-3118
[3] - http://www.python.org/dev/peps/pep-3118/
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center



2008-12-29  Thiago Jung Bauermann  <bauerman@br.ibm.com>
 
 gdb/
	* Makefile.in (SUBDIR_PYTHON_OBS): Add python-membuf.o.
	(SUBDIR_PYTHON_SRCS): Add python-membuf.c.
	(python-membuf.o): New target.
	* python/python-internal.h (gdbpy_read_memory,
	gdbpy_write_memory, gdbpy_initialize_membuf): New prototypes.
	* python/python-membuf.c: New file.
	* python/python.c (_initialize_python): Call
	gdbpy_initialize_membuf.
	(GdbMethods): Add entries for `read_memory' and `write_memory'.

gdb/doc/
	* gdb.texinfo (Basic Python): Document gdb.read_memory and
	gdb.write_memory.

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 836e2ba..050411a 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -279,6 +279,7 @@ SUBDIR_PYTHON_OBS = \
 	python-frame.o \
 	python-function.o \
 	python-hooks.o \
+	python-membuf.o \
 	python-objfile.o \
 	python-param.o \
 	python-symbol.o \
@@ -294,6 +295,7 @@ SUBDIR_PYTHON_SRCS = \
 	python/python-frame.c \
 	python/python-function.c \
 	python/python-hooks.c \
+	python/python-membuf.c \
 	python/python-objfile.c \
 	python/python-param.c \
 	python/python-symbol.c \
@@ -1891,6 +1893,10 @@ python-hooks.o: $(srcdir)/python/python-hooks.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-hooks.c
 	$(POSTCOMPILE)
 
+python-membuf.o: $(srcdir)/python/python-membuf.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-membuf.c
+	$(POSTCOMPILE)
+
 python-objfile.o: $(srcdir)/python/python-objfile.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-objfile.c
 	$(POSTCOMPILE)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 620d093..b8c6b9c 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18179,6 +18179,21 @@ frames, as expressed by the given @var{reason} code (an integer, see the
 @xref{Frames In Python,,Acessing inferior stack frames from Python}.)
 @end defun
 
+@findex gdb.read_memory
+@defun read_memory @var{address} @var{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 defun
+
+@findex gdb.write_memory
+@defun write_memory @var{address} @var{buffer} @r{[}@var{length}@r{]}
+Write the contents of @var{buffer} (a Python object which supports the buffer
+protocol, i.e., a string, an array or the object returned from
+@code{gdb.read_memory}) to the inferior, starting at @var{address}.  If given,
+@var{length} determines the number of bytes from @var{buffer} to be written.
+@end defun
+
 @node Exception Handling
 @subsubsection Exception Handling
 @cindex python exceptions
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 8b85ec0..6510a6a 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -78,6 +78,8 @@ PyObject *gdbpy_frame_stop_reason_string (PyObject *, PyObject *);
 PyObject *gdbpy_lookup_symbol (PyObject *self, PyObject *args);
 PyObject *gdbpy_selected_frame (PyObject *self, PyObject *args);
 PyObject *gdbpy_block_for_pc (PyObject *self, PyObject *args);
+PyObject *gdbpy_read_memory (PyObject *self, PyObject *args);
+PyObject *gdbpy_write_memory (PyObject *self, PyObject *args);
 
 PyObject *symtab_and_line_to_sal_object (struct symtab_and_line sal);
 PyObject *symtab_to_symtab_object (struct symtab *symtab);
@@ -108,6 +110,7 @@ void gdbpy_initialize_blocks (void);
 void gdbpy_initialize_functions (void);
 void gdbpy_initialize_objfile (void);
 void gdbpy_initialize_parameters (void);
+void gdbpy_initialize_membuf (void);
 
 struct cleanup *make_cleanup_py_decref (PyObject *py);
 struct cleanup *make_cleanup_py_restore_gil (PyGILState_STATE *state);
diff --git a/gdb/python/python-membuf.c b/gdb/python/python-membuf.c
new file mode 100644
index 0000000..b1fc491
--- /dev/null
+++ b/gdb/python/python-membuf.c
@@ -0,0 +1,214 @@
+/* Python interface to the inferior memory.
+
+   Copyright (C) 2008 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 "python-internal.h"
+
+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;
+
+/* 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.  */
+
+PyObject *
+gdbpy_read_memory (PyObject *self, PyObject *args)
+{
+  CORE_ADDR addr, length;
+  void *buffer;
+  membuf_object *membuf_obj;
+  struct cleanup *cleanups;
+  volatile struct gdb_exception except;
+
+  /* Assume CORE_ADDR corresponds to unsigned long.  */
+  if (! PyArg_ParseTuple (args, "kk", &addr, &length))
+    return NULL;
+
+  buffer = xmalloc (length);
+  cleanups = make_cleanup (xfree, buffer);
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      read_memory (addr, buffer, length);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  discard_cleanups (cleanups);
+
+  membuf_obj = PyObject_New (membuf_object, &membuf_object_type);
+  if (membuf_obj == NULL)
+    {
+      xfree (buffer);
+      PyErr_SetString (PyExc_MemoryError,
+		       "Could not allocate memory buffer object.");
+      return NULL;
+    }
+
+  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.  */
+
+PyObject *
+gdbpy_write_memory (PyObject *self, PyObject *args)
+{
+  int buf_len;
+  const char *buffer;
+  long length = -1;
+  CORE_ADDR addr;
+  membuf_object *membuf_obj;
+  struct cleanup *cleanups;
+  volatile struct gdb_exception except;
+
+  /* Assume CORE_ADDR corresponds to unsigned long.  */
+  if (! PyArg_ParseTuple (args, "ks#|l", &addr, &buffer, &buf_len, &length))
+    return NULL;
+
+  if (length == -1)
+    length = buf_len;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      write_memory (addr, buffer, length);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  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 %p, %u bytes long",
+			      (void *) membuf_obj->addr,
+			      (unsigned int) membuf_obj->length);
+}
+
+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;
+}
+
+Py_ssize_t
+get_write_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr)
+{
+  return get_read_buffer (self, segment, ptrptr);
+}
+
+Py_ssize_t
+get_seg_count (PyObject *self, Py_ssize_t *lenp)
+{
+  if (lenp)
+    *lenp = ((membuf_object *) self)->length;
+
+  return 1;
+}
+
+Py_ssize_t
+get_char_buffer (PyObject *self, Py_ssize_t segment, char **ptrptr)
+{
+  return get_char_buffer (self, segment, ptrptr);
+}
+
+static PyBufferProcs buffer_procs = {
+  get_read_buffer,
+  get_write_buffer,
+  get_seg_count,
+  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*/
+};
+
+void
+gdbpy_initialize_membuf (void)
+{
+  membuf_object_type.tp_new = PyType_GenericNew;
+  if (PyType_Ready (&membuf_object_type) < 0)
+    return;
+
+  Py_INCREF (&membuf_object_type);
+  PyModule_AddObject (gdb_module, "Membuf", (PyObject *) &membuf_object_type);
+}
diff --git a/gdb/python/python.c b/gdb/python/python.c
index e19928a..6fa0856 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1462,8 +1462,8 @@ Enables or disables auto-loading of Python code when an object is opened."),
   gdbpy_initialize_types ();
   gdbpy_initialize_parameters ();
   gdbpy_initialize_objfile ();
-
   gdbpy_initialize_events ();
+  gdbpy_initialize_membuf ();
 
   PyRun_SimpleString ("import gdb");
   PyRun_SimpleString ("gdb.pretty_printers = {}");
@@ -1580,6 +1580,13 @@ Note: may later change to return an object." },
   { "post_event", gdbpy_post_event, METH_VARARGS,
     "Post an event into gdb's event loop." },
 
+  { "read_memory", gdbpy_read_memory, METH_VARARGS,
+    "read_memory (address, length) -> buffer\n\
+Return a buffer object for reading from the inferior's memory." },
+  { "write_memory", gdbpy_write_memory, METH_VARARGS,
+    "write_memory (address, buffer [, length])\n\
+Write the given buffer object to the inferior's memory." },
+
   { "write", gdbpy_write, METH_VARARGS,
     "Write a string using gdb's filtered stream." },
   { "flush", gdbpy_flush, METH_NOARGS,



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