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]

[python] Implement gdb.search_memory.


Hi,

This patch implents gdb.search_memory, exposing the functionality of the
'find' CLI command. Just pushed it to the branch.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


gdb/
2009-02-20  Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* findcmd.c (put_bits): Remove static attribute.
	(allocate_pattern_buffer): New function, factored out of
	parse_find_args.
	(increase_pattern_buffer): Likewise.
	(search_memory): Likewise
	(parse_find_args): Use allocate_pattern_buffer and
	increase_pattern_buffer.
	(find_command): Use search_memory.
	* python/python-internal.h (gdbpy_is_value_object): Add prototype.
	(get_addr_from_python): Likewise.
	* python/python-utils.c (get_addr_from_python): New function.
	* python/python-value.c (builtin_type_upylong): New define.
	(convert_value_from_python): If an overflow occurs when converting
	to long long, try to convert as unsigned.
	(gdbpy_is_value_object): New function.
	* python/python.c (add_value_pattern): New function.
	(add_pattern_element): Likewise.
	(get_search_pattern): Likewise.
	(gdbpy_search_memory): Likewise.
	(GdbMethods): Add `search_memory' entry.
	* target.h (allocate_pattern_buffer): Add prototype.
	(increase_pattern_buffer): Likewise.
	(search_memory): Likewise.
	(put_bits): Likewise.
	* value.c (pack_unsigned_long): New function.
	(value_from_ulongest): Likewise.
	(value.h): Add prototype.

gdb/testsuite/
2009-02-20  Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* gdb.python/find.exp: New file.
	* gdb.python/find.c: New file.

gdb/doc/

2009-02-20  Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* gdb.texinfo (Basic Python): Document `gdb.search_memory'
---
 gdb/doc/gdb.texinfo               |   17 +++
 gdb/findcmd.c                     |  111 +++++++++++++-----
 gdb/python/python-internal.h      |    4 +
 gdb/python/python-utils.c         |   46 +++++++
 gdb/python/python-value.c         |   41 ++++++-
 gdb/python/python.c               |  238 +++++++++++++++++++++++++++++++++++++
 gdb/target.h                      |   14 ++
 gdb/testsuite/gdb.python/find.c   |   64 ++++++++++
 gdb/testsuite/gdb.python/find.exp |  186 +++++++++++++++++++++++++++++
 gdb/value.c                       |   48 ++++++++
 gdb/value.h                       |    1 +
 11 files changed, 740 insertions(+), 30 deletions(-)
 create mode 100644 gdb/testsuite/gdb.python/find.c
 create mode 100644 gdb/testsuite/gdb.python/find.exp

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 4408635..91114a1 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18280,6 +18280,23 @@ protocol, i.e., a string, an array or the object returned from
 @var{length} determines the number of bytes from @var{buffer} to be written.
 @end defun
 
+@findex gdb.search_memory
+@defun search_memory @var{address} @var{length} @var{pattern} @r{[}@var{size}@r{]} @r{[}@var{max_count}@r{]}
+Search a region of the inferior memory starting at @var{address} with the given
+@var{length}.  @var{pattern} can be a string, a byte array, a buffer object,
+a number, a @code{gdb.Value} object (@pxref{Values From Inferior}) or a list
+or tuple with elements in any combination of those types.  If @var{size} is
+given and is non-zero, it specifies the size in bytes of a Python scalar or
+@code{gdb.Value} in the search pattern.  If @var{size} is zero or not specified,
+ it is taken from the value's type in the current language.
+This is useful when one wants to specify the search
+pattern as a mixture of types.
+Note that this means, for example, that in the case of C-like languages
+a search for an untyped 0x42 will search for @samp{(int) 0x42}
+which is typically four bytes.  @var{max_count} is the highest number of matches
+to search for.
+@end defun
+
 @node Exception Handling
 @subsubsection Exception Handling
 @cindex python exceptions
diff --git a/gdb/findcmd.c b/gdb/findcmd.c
index 4e7fa09..f912dcf 100644
--- a/gdb/findcmd.c
+++ b/gdb/findcmd.c
@@ -26,7 +26,7 @@
 
 /* Copied from bfd_put_bits.  */
 
-static void
+void
 put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p)
 {
   int i;
@@ -44,6 +44,41 @@ put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p)
     }
 }
 
+/* Allocates a buffer in *PATTERN_BUF, with a hard-coded initial size which
+   will be returned in *PATTERN_BUF_SIZE. *PATTERN_BUF_END points to the same
+   place as *PATTERN_BUF, indicating that the buffer is initially empty.  */
+
+void
+allocate_pattern_buffer (char **pattern_buf, char **pattern_buf_end,
+			 ULONGEST *pattern_buf_size)
+{
+#define INITIAL_PATTERN_BUF_SIZE 100
+  *pattern_buf_size = INITIAL_PATTERN_BUF_SIZE;
+  *pattern_buf = xmalloc (*pattern_buf_size);
+  *pattern_buf_end = *pattern_buf;
+}
+
+/* Grows *PATTERN_BUF by a factor of two if it's not large enough to hold
+   VAL_BYTES more bytes  or a 64-bit value, whichever is larger.
+   *PATTERN_BUF_END is updated as necessary.  */
+
+void
+increase_pattern_buffer (char **pattern_buf, char **pattern_buf_end,
+			 ULONGEST *pattern_buf_size, int val_bytes)
+{
+    /* Keep it simple and assume size == 'g' when watching for when we
+       need to grow the pattern buf.  */
+    if ((*pattern_buf_end - *pattern_buf + max (val_bytes, sizeof (int64_t)))
+	> *pattern_buf_size)
+      {
+	size_t current_offset = *pattern_buf_end - *pattern_buf;
+
+	*pattern_buf_size *= 2;
+	*pattern_buf = xrealloc (*pattern_buf, *pattern_buf_size);
+	*pattern_buf_end = *pattern_buf + current_offset;
+      }
+}
+
 /* Subroutine of find_command to simplify it.
    Parse the arguments of the "find" command.  */
 
@@ -59,8 +94,7 @@ parse_find_args (char *args, ULONGEST *max_countp,
   char *pattern_buf;
   /* Current size of search pattern buffer.
      We realloc space as needed.  */
-#define INITIAL_PATTERN_BUF_SIZE 100
-  ULONGEST pattern_buf_size = INITIAL_PATTERN_BUF_SIZE;
+  ULONGEST pattern_buf_size;
   /* Pointer to one past the last in-use part of pattern_buf.  */
   char *pattern_buf_end;
   ULONGEST pattern_len;
@@ -74,8 +108,7 @@ parse_find_args (char *args, ULONGEST *max_countp,
   if (args == NULL)
     error (_("Missing search parameters."));
 
-  pattern_buf = xmalloc (pattern_buf_size);
-  pattern_buf_end = pattern_buf;
+  allocate_pattern_buffer (&pattern_buf, &pattern_buf_end, &pattern_buf_size);
   old_cleanups = make_cleanup (free_current_contents, &pattern_buf);
 
   /* Get search granularity and/or max count if specified.
@@ -172,16 +205,8 @@ parse_find_args (char *args, ULONGEST *max_countp,
       v = parse_to_comma_and_eval (&s);
       val_bytes = TYPE_LENGTH (value_type (v));
 
-      /* Keep it simple and assume size == 'g' when watching for when we
-	 need to grow the pattern buf.  */
-      if ((pattern_buf_end - pattern_buf + max (val_bytes, sizeof (int64_t)))
-	  > pattern_buf_size)
-	{
-	  size_t current_offset = pattern_buf_end - pattern_buf;
-	  pattern_buf_size *= 2;
-	  pattern_buf = xrealloc (pattern_buf, pattern_buf_size);
-	  pattern_buf_end = pattern_buf + current_offset;
-	}
+      increase_pattern_buffer (&pattern_buf, &pattern_buf_end,
+			       &pattern_buf_size, val_bytes);
 
       if (size != '\0')
 	{
@@ -236,6 +261,45 @@ parse_find_args (char *args, ULONGEST *max_countp,
   discard_cleanups (old_cleanups);
 }
 
+/* Drives target_search_memory to sweep through the specified search space,
+   possibly in several iterations (with one call to this function for each
+   iteration).  *START_ADDR is the address where the search starts, and is
+   updated to the next starting address to continue the search.
+   *SEARCH_SPACE_LEN is the amount of bytes which will be searched, and is
+   updated for the next iteration. PATTERN_BUF holds the pattern to be searched
+   for, PATTERN_LEN is the size of the pattern in bytes.  If a match is found,
+   it's address is put in *FOUND_ADDR.
+
+   Returns 1 if found, 0 if not found, and -1 if there was an error requiring
+   halting of the search (e.g. memory read error).  */
+
+int
+search_memory (CORE_ADDR *start_addr, ULONGEST *search_space_len,
+	       const char *pattern_buf, ULONGEST pattern_len,
+	       CORE_ADDR *found_addr)
+{
+  /* Offset from start of this iteration to the next iteration.  */
+  ULONGEST next_iter_incr;
+  int found;
+    
+  found = target_search_memory (*start_addr, *search_space_len,
+				pattern_buf, pattern_len, found_addr);
+  if (found <= 0)
+    return found;
+
+  /* Begin next iteration at one byte past this match.  */
+  next_iter_incr = (*found_addr - *start_addr) + 1;
+
+  /* For robustness, we don't let search_space_len go -ve here.  */
+  if (*search_space_len >= next_iter_incr)
+    *search_space_len -= next_iter_incr;
+  else
+    *search_space_len = 0;
+  *start_addr += next_iter_incr;
+
+  return found;
+}
+
 static void
 find_command (char *args, int from_tty)
 {
@@ -264,12 +328,11 @@ find_command (char *args, int from_tty)
   while (search_space_len >= pattern_len
 	 && found_count < max_count)
     {
-      /* Offset from start of this iteration to the next iteration.  */
-      ULONGEST next_iter_incr;
       CORE_ADDR found_addr;
-      int found = target_search_memory (start_addr, search_space_len,
-					pattern_buf, pattern_len, &found_addr);
+      int found;
 
+      found = search_memory (&start_addr, &search_space_len, pattern_buf,
+			     pattern_len, &found_addr);
       if (found <= 0)
 	break;
 
@@ -277,16 +340,6 @@ find_command (char *args, int from_tty)
       printf_filtered ("\n");
       ++found_count;
       last_found_addr = found_addr;
-
-      /* Begin next iteration at one byte past this match.  */
-      next_iter_incr = (found_addr - start_addr) + 1;
-
-      /* For robustness, we don't let search_space_len go -ve here.  */
-      if (search_space_len >= next_iter_incr)
-	search_space_len -= next_iter_incr;
-      else
-	search_space_len = 0;
-      start_addr += next_iter_incr;
     }
 
   /* Record and print the results.  */
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index afdf821..0608330 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -157,6 +157,8 @@ char *python_string_to_host_string (PyObject *obj);
 PyObject *target_string_to_unicode (const gdb_byte *str, int length);
 int gdbpy_is_string (PyObject *obj);
 
+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.  */
 char *apply_varobj_pretty_printer (PyObject *print_obj, struct value *value,
@@ -170,4 +172,6 @@ extern PyObject *gdbpy_to_string_cst;
 extern PyObject *gdbpy_display_hint_cst;
 extern PyObject *gdbpy_doc_cst;
 
+int get_addr_from_python (PyObject *obj, CORE_ADDR *addr);
+
 #endif /* GDB_PYTHON_INTERNAL_H */
diff --git a/gdb/python/python-utils.c b/gdb/python/python-utils.c
index 1e6d952..c6c305f 100644
--- a/gdb/python/python-utils.c
+++ b/gdb/python/python-utils.c
@@ -19,6 +19,7 @@
 
 #include "defs.h"
 #include "charset.h"
+#include "value.h"
 #include "python-internal.h"
 

@@ -181,3 +182,48 @@ gdbpy_is_string (PyObject *obj)
 {
   return PyString_Check (obj) || PyUnicode_Check (obj);
 }
+
+/* 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, "negative address");
+	return 0;
+      }
+    }
+  else
+    {
+      PyErr_SetString (PyExc_TypeError, "invalid type for address");
+      return 0;
+    }
+
+  return 1;
+}
diff --git a/gdb/python/python-value.c b/gdb/python/python-value.c
index 55361d6..ca29f46 100644
--- a/gdb/python/python-value.c
+++ b/gdb/python/python-value.c
@@ -52,6 +52,10 @@ struct value *values_in_python = NULL;
 /* Python's long type corresponds to C's long long type.  */
 #define builtin_type_pylong builtin_type (current_gdbarch)->builtin_long_long
 
+/* Python's long type corresponds to C's long long type.  Unsigned version.  */
+#define builtin_type_upylong builtin_type \
+  (current_gdbarch)->builtin_unsigned_long_long
+
 #define builtin_type_pybool \
   language_bool_type (current_language, current_gdbarch)
 
@@ -798,7 +802,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))
@@ -857,6 +888,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.c b/gdb/python/python.c
index 8677da6..5836a15 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -326,6 +326,241 @@ gdbpy_find_pc_function (PyObject *self, PyObject *args)
   Py_RETURN_NONE;
 }
 
+/* Adds GDB value V to the pattern buffer in *PATTERN_BUF.  If SIZE is not zero,
+   it specifies the number of bytes from V to copy to *PATTERN_BUF.  The
+   function increases the size of *PATTERN_BUF as necessary, adjusting
+   *PATTERN_BUF_END and *PATTERN_BUF_SIZE in the process.  */
+
+static void
+add_value_pattern (struct value *v, int size, char **pattern_buf,
+		   char **pattern_buf_end, ULONGEST *pattern_buf_size)
+{
+  int val_bytes;
+
+  if (size)
+    {
+      LONGEST x = value_as_long (v);
+
+      if (size == 1)
+	*(*pattern_buf_end)++ = x;
+      else
+	{
+	  put_bits (x, *pattern_buf_end, size * 8,
+		    gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG);
+	  *pattern_buf_end += size;
+	}
+    }
+  else
+   {
+     val_bytes = TYPE_LENGTH (value_type (v));
+
+     increase_pattern_buffer (pattern_buf, pattern_buf_end,
+			      pattern_buf_size, val_bytes);
+
+     memcpy (*pattern_buf_end, value_contents_raw (v), val_bytes);
+     *pattern_buf_end += val_bytes;
+   }
+}
+
+/* This function does the actual work of constructing the pattern buffer from
+   OBJ.  If OBJ is an object which implements the read buffer protocol (such
+   as a string, a byte array or gdb.Membuf), then its contents are directly
+   copied to *PATTERN_BUF.  If it is a list, then this function is recursively
+   called for each of its elements.  If OBJ is an object which can be converted
+   to a GDB value, then the contents of the value are copied to PATTERN_BUF.
+   If SIZE is different than zero, then it limits the number of bytes which
+   are copied to the buffer in case OBJ is converted to a GDB value.  That
+   means that SIZE influences only Python scalars and gdb.Value objects.
+   The function increases the size of *PATTERN_BUF as necessary, adjusting
+   *PATTERN_BUF_END and *PATTERN_BUF_SIZE in the process.
+
+   Returns 1 on success or 0 on failure, with a Python exception set.  This
+   function can also throw GDB exceptions.  */
+
+static int
+add_pattern_element (PyObject *obj, int size, char **pattern_buf,
+		     char **pattern_buf_end, ULONGEST *pattern_buf_size)
+{
+  if (PyObject_CheckReadBuffer (obj))
+    {
+      /* Handle string, Unicode string, byte array, gdb.Membuf and any other
+         object implementing the buffer protocol.  The SIZE parameter is
+	 ignored in this case.  */
+
+      int val_bytes;
+      const void *buffer;
+
+      if (PyObject_AsReadBuffer (obj, &buffer, &val_bytes) == -1)
+	return 0;
+
+      increase_pattern_buffer (pattern_buf, pattern_buf_end,
+			       pattern_buf_size, val_bytes);
+
+      memcpy (*pattern_buf_end, buffer, val_bytes);
+      *pattern_buf_end += val_bytes;
+    }
+  else if (gdbpy_is_value_object (obj))
+    add_value_pattern (value_object_to_value (obj), size, pattern_buf,
+		       pattern_buf_end, pattern_buf_size);
+  else if (PySequence_Check (obj))
+    {
+      /* Handle lists and tuples.  */
+
+      Py_ssize_t i, num_objs;
+
+      num_objs = PySequence_Size (obj);
+      for (i = 0; i < num_objs; i++)
+	if (!add_pattern_element (PySequence_GetItem (obj, i), size,
+				  pattern_buf, pattern_buf_end,
+				  pattern_buf_size))
+	  return 0;
+    }
+  else
+    {
+      /* See if we can convert from a Python object to a GDB value.  */
+
+      struct value *v = convert_value_from_python (obj);
+
+      if (v)
+	add_value_pattern (v, size, pattern_buf, pattern_buf_end,
+			   pattern_buf_size);
+      else
+	return 0;
+    }
+
+  return 1;
+}
+
+/* Constructs the search pattern from OBJ, putting it in *PATTERN_BUFP, and its
+   size in *PATTERN_LENP.  See the function add_pattern_element to learn how
+   the search pattern is obtained from OBJ.
+
+   Returns 1 on success or 0 on failure, with a Python exception set.  This
+   function can also throw GDB exceptions.  */
+
+static int
+get_search_pattern (PyObject *obj, int size, char **pattern_bufp,
+		    ULONGEST *pattern_lenp)
+{
+  /* Buffer to hold the search pattern.  */
+  char *pattern_buf;
+  /* Current size of search pattern buffer.
+     We realloc space as needed.  */
+  ULONGEST pattern_buf_size;
+  /* Pointer to one past the last in-use part of pattern_buf.  */
+  char *pattern_buf_end;
+  struct cleanup *old_cleanups;
+
+  allocate_pattern_buffer (&pattern_buf, &pattern_buf_end, &pattern_buf_size);
+  old_cleanups = make_cleanup (free_current_contents, &pattern_buf);
+
+  if (!add_pattern_element (obj, size, &pattern_buf, &pattern_buf_end,
+			    &pattern_buf_size))
+    {
+      do_cleanups (old_cleanups);
+
+      return 0;
+    }
+
+  *pattern_bufp = pattern_buf;
+  *pattern_lenp = pattern_buf_end - pattern_buf;
+
+  discard_cleanups (old_cleanups);
+
+  return 1;
+}
+
+/* Implementation of
+   gdb.search_memory (start_address, length, pattern|list
+		      [, size] [, max_count]).
+   The third argument may be either a pattern, or a list or tupple of patterns
+   to be searched.  Size is the size in bytes of each search query value, either
+   1, 2, 4 or 8.  Returns a list of the addresses where matches were found.  */
+
+PyObject *
+gdbpy_search_memory (PyObject *self, PyObject *args)
+{
+  int size = 0;
+  long length;
+  unsigned int found_count = 0;
+  long max_count = 0;
+  CORE_ADDR start_addr;
+  char *pattern_buf;
+  ULONGEST pattern_len, search_space_len;
+  PyObject *pattern, *list = NULL, *start_addr_obj;
+  struct cleanup *cleanups = NULL;
+  volatile struct gdb_exception except;
+
+  /* Assume CORE_ADDR corresponds to unsigned long.  */
+  if (! PyArg_ParseTuple (args, "OlO|il", &start_addr_obj, &length, &pattern,
+			  &size, &max_count))
+    return NULL;
+
+  if (!max_count)
+    max_count = LONG_MAX;
+
+  if (!length)
+    {
+      PyErr_SetString (PyExc_ValueError, "empty search range");
+      return NULL;
+    }
+  else if (length < 0)
+    {
+      PyErr_SetString (PyExc_ValueError, "invalid search range");
+      return NULL;
+    }
+  else
+    {
+      /* Watch for overflows.  */
+      if (length > CORE_ADDR_MAX
+	  || (start_addr + length - 1) < start_addr)
+	{
+	  PyErr_SetString (PyExc_ValueError, "search range too large");
+	  return NULL;
+	}
+
+      search_space_len = length;
+    }
+
+  if (size != 0 && size != 1 && size != 2 && size != 4 && size != 8)
+    {
+      PyErr_SetString (PyExc_ValueError, "invalid pattern size");
+      return NULL;
+    }
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      if (get_addr_from_python (start_addr_obj, &start_addr))
+	{
+	  if (get_search_pattern (pattern, size, &pattern_buf, &pattern_len))
+	    {
+	      cleanups = make_cleanup (xfree, pattern_buf);
+	      list = PyList_New (0);
+
+	      while (search_space_len >= pattern_len && found_count < max_count)
+		{
+		  CORE_ADDR found_addr;
+		  int found;
+
+		  found = search_memory (&start_addr, &search_space_len,
+					 pattern_buf, pattern_len, &found_addr);
+		  if (found <= 0)
+		    break;
+
+		  PyList_Append (list, PyLong_FromUnsignedLong (found_addr));
+		  ++found_count;
+		}
+	    }
+	}
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  if (cleanups)
+    do_cleanups (cleanups);
+
+  return list;
+}
+
 /* A Python function which is a wrapper for decode_line_1.  */
 
 static PyObject *
@@ -1686,6 +1921,9 @@ 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." },
+  { "search_memory", gdbpy_search_memory, METH_VARARGS,
+    "search_memory (start_address, length, pattern|list [, size] [, max_count]) -> list\n\
+Return a list with the addresses where matches were found." },
 
   { "write", gdbpy_write, METH_VARARGS,
     "Write a string using gdb's filtered stream." },
diff --git a/gdb/target.h b/gdb/target.h
index caf6384..ee87c17 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1167,6 +1167,20 @@ extern int target_search_memory (CORE_ADDR start_addr,
                                  ULONGEST pattern_len,
                                  CORE_ADDR *found_addrp);
 
+/* Utility functions which can be used by search_memory implementations.  */
+
+void allocate_pattern_buffer (char **pattern_bufp, char **pattern_buf_end,
+			      ULONGEST *pattern_buf_size);
+
+void increase_pattern_buffer (char **pattern_bufp, char **pattern_buf_end,
+			      ULONGEST *pattern_buf_size, int val_bytes);
+
+int search_memory (CORE_ADDR *start_addr, ULONGEST *search_space_len,
+		   const char *pattern_buf, ULONGEST pattern_len,
+		   CORE_ADDR *found_addr);
+
+void put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p);
+
 /* Command logging facility.  */
 
 #define target_log_command(p)						\
diff --git a/gdb/testsuite/gdb.python/find.c b/gdb/testsuite/gdb.python/find.c
new file mode 100644
index 0000000..35ddd8c
--- /dev/null
+++ b/gdb/testsuite/gdb.python/find.c
@@ -0,0 +1,64 @@
+/* Testcase for the search_memory Python function.
+   This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2009 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/>.
+
+   Please email any bugs, comments, and/or additions to this file to:
+   bug-gdb@gnu.org  */
+
+/* Based on the gdb.base/find.c testcase.  */
+
+#include <stdlib.h>
+#include <stdint.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;
+
+static void
+stop_here ()
+{
+  x = 1; // stop here
+}
+
+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 ()
+{
+  init_bufs ();
+
+  stop_here ();
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.python/find.exp b/gdb/testsuite/gdb.python/find.exp
new file mode 100644
index 0000000..30afe41
--- /dev/null
+++ b/gdb/testsuite/gdb.python/find.exp
@@ -0,0 +1,186 @@
+# Copyright 2008, 2009 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 tests the search_memory Python function.
+# Based on the gdb.base/find.exp testcase.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}...
+# Run a test named NAME, consisting of multiple lines of input.
+# After each input line INPUT, search for result line RESULT.
+# Succeed if all results are seen; fail otherwise.
+proc gdb_py_test_multiple {name args} {
+    global gdb_prompt
+    foreach {input result} $args {
+	if {[gdb_test_multiple $input "$name - $input" {
+	    -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" {
+		pass "$name - $input"
+	    }
+	}]} {
+	    return 1
+	}
+    }
+    return 0
+}
+
+set testfile "find"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug nowarnings}] != "" } {
+    untested find.exp
+    return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+gdb_test_multiple "python print 'hello, world!'" "verify python support" {
+    -re "not supported.*$gdb_prompt $"	{
+      unsupported "python support is disabled"
+      return -1
+    }
+    -re "$gdb_prompt $"	{}
+}
+
+gdb_test "break $srcfile:stop_here" \
+    "Breakpoint.*at.* file .*$srcfile, line.*" \
+    "breakpoint function in file"
+
+gdb_run_cmd
+gdb_expect {
+    -re "Breakpoint \[0-9\]+,.*stop_here.* at .*$srcfile:.*$gdb_prompt $" {
+	pass "run until function breakpoint"
+    }
+    -re "$gdb_prompt $" {
+	fail "run until function breakpoint"
+    }
+    timeout {
+	fail "run until function breakpoint (timeout)"
+    }
+}
+
+# We've now got the target program in a state where we can test "find".
+
+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}.]"
+set one_pattern_found "${newline}.${dec_number}L]"
+set two_patterns_found "${newline}.${dec_number}L, ${dec_number}L]"
+
+# Test string pattern.
+
+gdb_test "set *(int32_t*) &int8_search_buf\[10\] = 0x61616161" "" ""
+gdb_test "py start_addr = gdb.parse_and_eval ('&int8_search_buf\[0\]')" "" ""
+gdb_test "py length = gdb.parse_and_eval ('sizeof (int8_search_buf)')" "" ""
+
+gdb_test "py print gdb.search_memory (start_addr, length, 'aaa')" \
+  "${two_patterns_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.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.search_memory (start_addr, 10+3+1, \['a', 'a', 'a', 'a'\])" \
+  "${one_pattern_found}" "pattern found at end of range"
+
+# Test max-count with size-char.
+
+gdb_test "py print gdb.search_memory (start_addr, length, \[0x61, 0x61\], 1, 1)" \
+  "\[\\r\\n\].${dec_number}L]" "size = 1, max_count = 1"
+
+# Test 16-bit pattern.
+
+gdb_test "set int16_search_buf\[10\] = 0x1234" "" ""
+gdb_test "py start_addr = gdb.parse_and_eval ('&int16_search_buf\[0\]')" "" ""
+gdb_test "py length = gdb.parse_and_eval ('sizeof (int16_search_buf)')" "" ""
+gdb_test "py pattern = gdb.parse_and_eval ('(int16_t) 0x1234')" "" ""
+
+gdb_test "py print gdb.search_memory (start_addr, length, 0x1234, 2)" \
+  "${one_pattern_found}" "find 16-bit pattern, with python pattern"
+
+gdb_test "py print gdb.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 start_addr = gdb.parse_and_eval ('&int32_search_buf\[0\]')" "" ""
+gdb_test "py length = gdb.parse_and_eval ('sizeof (int32_search_buf)')" "" ""
+gdb_test "py pattern = gdb.parse_and_eval ('(int32_t) 0x12345678')" "" ""
+
+gdb_test "py print gdb.search_memory (start_addr, length, 0x12345678, 4)" \
+  "${one_pattern_found}" "find 32-bit pattern, with python pattern"
+gdb_test "py print gdb.search_memory (start_addr, length, pattern)" \
+  "${one_pattern_found}" "find 32-bit pattern, with value pattern"
+
+# Test 64-bit pattern.
+
+gdb_test "set int64_search_buf\[10\] = 0xfedcba9876543210LL" "" ""
+gdb_test "py start_addr = gdb.parse_and_eval ('&int64_search_buf\[0\]')" "" ""
+gdb_test "py length = gdb.parse_and_eval ('sizeof (int64_search_buf)')" "" ""
+gdb_test "py pattern = gdb.parse_and_eval ('(int64_t) 0xfedcba9876543210LL')" "" ""
+
+gdb_test "py print gdb.search_memory (start_addr, length, 0xfedcba9876543210, 8)" \
+  "${one_pattern_found}" "find 64-bit pattern, with python pattern"
+gdb_test "py print gdb.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 start_addr = gdb.parse_and_eval ('&search_buf\[0\]')" "" ""
+gdb_test "py pattern1 = gdb.parse_and_eval ('(int8_t) 0x62')" "" ""
+gdb_test "py pattern2 = gdb.parse_and_eval ('(int16_t) 0x6363')" "" ""
+gdb_test "py pattern3 = gdb.parse_and_eval ('(int32_t) 0x64646464')" "" ""
+
+gdb_test "py print gdb.search_memory (start_addr, 100, \[pattern1, pattern2, 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.parse_and_eval ('search_buf')" "" ""
+gdb_test "py length = gdb.parse_and_eval ('search_buf_size')" "" ""
+
+gdb_test "py print gdb.search_memory (start_addr, length, 0x12345678, 4)" \
+  "${two_patterns_found}" "search spanning large range"
+
+# 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 print gdb.search_memory (start_addr, length, 0xfdb97531, 4)" \
+      "${one_pattern_found}" "find pattern straddling chunk boundary"
+}
diff --git a/gdb/value.c b/gdb/value.c
index 7c66922..ac55685 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1783,6 +1783,41 @@ 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;
+
+  type = check_typedef (type);
+  len = TYPE_LENGTH (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, 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 *
@@ -1796,6 +1831,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 1caf0c8..c8a4489 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -287,6 +287,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,
-- 
1.5.6.5


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