This is the mail archive of the
archer@sourceware.org
mailing list for the Archer project.
[python] Implement gdb.search_memory.
- From: Thiago Jung Bauermann <bauerman at br dot ibm dot com>
- To: archer ml <archer at sourceware dot org>
- Date: Fri, 20 Feb 2009 19:03:31 -0300
- Subject: [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