* RFC: new command to search memory
@ 2008-01-15 22:15 Doug Evans
2008-01-28 18:15 ` Doug Evans
0 siblings, 1 reply; 5+ messages in thread
From: Doug Evans @ 2008-01-15 22:15 UTC (permalink / raw)
To: gdb-patches, pkoning
ref: http://sourceware.org/ml/gdb/2007-12/msg00161.html
I had some time so as an exercise I came up with this.
The basic syntax I came up with is:
find [/size] [/max_count] start_addr, @len, val1 [, val2, ...]
find [/size] [/max_count] start_addr, end_addr, val1 [, val2, ...]
Examples:
void
hello ()
{
static char hello[] = "hello-hello";
static struct { char c; short s; int i; } __attribute__ ((packed)) mixed
= { 'c', 0x1234, 0x87654321 };
printf ("%s\n", hello);
}
(gdb) find &hello[0], @sizeof(hello), "hello"
0x601048 <hello.1628>
0x60104e <hello.1628+6>
2 patterns found
(gdb) find &mixed, @sizeof(mixed), (char) 'c', (short) 0x1234, (int) 0x87654321
0x601054 <mixed.1633>
1 pattern found
(gdb) print $numfound
$1 = 1
(gdb) print $_
$2 = (void *) 0x601054
Instead of linking with libiberty I just put a copy of lmemmem.c in
with gdbserver.
I realize the libiberty mods need to go through gcc-patches.
I'll forward that part of this patch on if/when appropriate.
2008-01-15 Doug Evans <dje@sebabeach.org>
* include/libiberty.h: (lmemmem): Declare.
* libiberty/Makefile.in (CFILES): Add lmemmem.c.
(REQUIRED_OFILES): Add lmemmem.o.
(lmemmem.o): New rule.
* libiberty/configure.ac (funcs): Add memmem.
(AC_CHECK_FUNCS): Add memmem.
* libiberty/config.in: Regenerate.
* libiberty/configure: Regenerate.
* libiberty/lmemmem.c: New file.
New "find" command.
* gdb/Makefile.in (SFILES): Add findcmd.c.
(COMMON_OBJS): Add findcmd.o.
(findcmd.o): New rule.
* gdb/findcmd.c: New file.
* gdb/target.h (target_ops): New member to_search_memory.
(simple_search_memory): Declare.
(target_search_memory): Declare.
* gdb/target.c (simple_search_memory): New fn.
(default_search_memory): New fn.
(debug_to_search_memory): New fn.
(target_search_memory): New fn.
(update_current_target): Set to_search_memory.
(setup_target_debug): Set to_search_memory.
* gdb/remote.c (PACKET_qSearch_memory): New packet kind.
(remote_protocol_features): Add qSearch:memory.
(remote_search_memory): New fn.
(init_remote_ops): Init to_search_memory.
(init_extended_remote_ops): Ditto.
(_initialize_remote): Add qSearch:memory packet config command.
* gdbserver/configure.ac: Check for memmem.
* gdbserver/configure: Regenerate.
* gdbserver/config.in: Regenerate.
* gdbserver/Makefile.in (SFILES): Add lmemmem.c.
(OBS): Add lmemmem.o.
(lmemmem.o): New rule.
* gdbserver/server.h (decode_search_memory_packet): Declare.
(lmemmem): Declare.
* gdbserver/remote-utils.c (decode_search_memory_packet): New fn.
* gdbserver/server.c (handle_search_memory_1): New fn.
(handle_search_memory): New fn.
(handle_query): Process qSearch:memory packets.
* gdbserver/lmemmem.c: New file.
* doc/gdb.texinfo: Document "find" command, qSearch:memory packet.
* testsuite/gdb.base/find.exp: New file.
* testsuite/gdb.base/find.c: New file.
Index: include/libiberty.h
===================================================================
RCS file: /cvs/src/src/include/libiberty.h,v
retrieving revision 1.57
diff -u -p -u -p -r1.57 libiberty.h
--- ./include/libiberty.h 6 Sep 2007 17:22:36 -0000 1.57
+++ ./include/libiberty.h 15 Jan 2008 21:53:23 -0000
@@ -1,6 +1,6 @@
/* Function declarations for libiberty.
- Copyright 2001, 2002, 2005, 2007 Free Software Foundation, Inc.
+ Copyright 2001, 2002, 2005, 2007, 2008 Free Software Foundation, Inc.
Note - certain prototypes declared in this header file are for
functions whoes implementation copyright does not belong to the
@@ -166,6 +166,10 @@ extern char *libiberty_concat_ptr;
(libiberty_concat_ptr = (char *) alloca (concat_length ACONCAT_PARAMS + 1), \
concat_copy2 ACONCAT_PARAMS)
+/* A well-defined memmem () that is always compiled in. */
+
+extern void * lmemmem (const void *, size_t, const void *, size_t);
+
/* Check whether two file descriptors refer to the same file. */
extern int fdmatch (int fd1, int fd2);
Index: libiberty/Makefile.in
===================================================================
RCS file: /cvs/src/src/libiberty/Makefile.in,v
retrieving revision 1.89
diff -u -p -u -p -r1.89 Makefile.in
--- ./libiberty/Makefile.in 25 Jul 2007 06:36:27 -0000 1.89
+++ ./libiberty/Makefile.in 15 Jan 2008 21:53:23 -0000
@@ -2,7 +2,7 @@
# Originally written by K. Richard Pixley <rich@cygnus.com>.
#
# Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-# 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software
+# 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software
# Foundation
#
# This file is part of the libiberty library.
@@ -133,6 +133,7 @@ CFILES = alloca.c argv.c asprintf.c atex
hashtab.c hex.c \
index.c insque.c \
lbasename.c \
+ lmemmem.c \
lrealpath.c \
make-relative-prefix.c \
make-temp-file.c md5.c memchr.c memcmp.c memcpy.c memmove.c \
@@ -164,7 +165,7 @@ REQUIRED_OFILES = ./regex.o ./cplus-dem.
./fnmatch.o ./fopen_unlocked.o \
./getopt.o ./getopt1.o ./getpwd.o ./getruntime.o \
./hashtab.o ./hex.o \
- ./lbasename.o ./lrealpath.o \
+ ./lbasename.o ./lmemmem.o ./lrealpath.o \
./make-relative-prefix.o ./make-temp-file.o \
./objalloc.o ./obstack.o \
./partition.o ./pexecute.o ./physmem.o \
@@ -748,6 +749,12 @@ $(CONFIGURED_OFILES): stamp-picdir
else true; fi
$(COMPILE.c) $(srcdir)/lbasename.c $(OUTPUT_OPTION)
+./lmemmem.o: $(srcdir)/lmemmem.c stamp-h
+ if [ x"$(PICFLAG)" != x ]; then \
+ $(COMPILE.c) $(PICFLAG) $(srcdir)/lmemmem.c -o pic/$@; \
+ else true; fi
+ $(COMPILE.c) $(srcdir)/lmemmem.c $(OUTPUT_OPTION)
+
./lrealpath.o: $(srcdir)/lrealpath.c stamp-h $(INCDIR)/ansidecl.h \
$(INCDIR)/libiberty.h
if [ x"$(PICFLAG)" != x ]; then \
Index: libiberty/config.in
===================================================================
RCS file: /cvs/src/src/libiberty/config.in,v
retrieving revision 1.38
diff -u -p -u -p -r1.38 config.in
--- ./libiberty/config.in 22 Jul 2005 03:16:32 -0000 1.38
+++ ./libiberty/config.in 15 Jan 2008 21:53:23 -0000
@@ -139,6 +139,9 @@
/* Define to 1 if you have the `memcpy' function. */
#undef HAVE_MEMCPY
+/* Define to 1 if you have the `memmem' function. */
+#undef HAVE_MEMMEM
+
/* Define to 1 if you have the `memmove' function. */
#undef HAVE_MEMMOVE
Index: libiberty/configure
===================================================================
RCS file: /cvs/src/src/libiberty/configure,v
retrieving revision 1.89
diff -u -p -u -p -r1.89 configure
--- ./libiberty/configure 17 Jul 2007 18:05:02 -0000 1.89
+++ ./libiberty/configure 15 Jan 2008 21:53:23 -0000
@@ -5137,7 +5137,7 @@ if test "x" = "y"; then
for ac_func in asprintf atexit basename bcmp bcopy bsearch bzero calloc clock \
getcwd getpagesize gettimeofday index insque mkstemps memchr memcmp memcpy \
- memmove mempcpy memset putenv random rename rindex sigsetmask \
+ memmem memmove mempcpy memset putenv random rename rindex sigsetmask \
strcasecmp setenv stpcpy stpncpy strchr strdup strncasecmp strndup strrchr strstr \
strtod strtol strtoul strverscmp tmpnam vasprintf vfprintf vprintf \
vsprintf waitpid getrusage on_exit psignal strerror strsignal \
Index: libiberty/configure.ac
===================================================================
RCS file: /cvs/src/src/libiberty/configure.ac,v
retrieving revision 1.37
diff -u -p -u -p -r1.37 configure.ac
--- ./libiberty/configure.ac 17 Jul 2007 18:05:02 -0000 1.37
+++ ./libiberty/configure.ac 15 Jan 2008 21:53:23 -0000
@@ -362,7 +362,7 @@ checkfuncs="$checkfuncs getsysinfo table
if test "x" = "y"; then
AC_CHECK_FUNCS(asprintf atexit basename bcmp bcopy bsearch bzero calloc clock \
getcwd getpagesize gettimeofday index insque mkstemps memchr memcmp memcpy \
- memmove mempcpy memset putenv random rename rindex sigsetmask \
+ memmem memmove mempcpy memset putenv random rename rindex sigsetmask \
strcasecmp setenv stpcpy stpncpy strchr strdup strncasecmp strndup strrchr strstr \
strtod strtol strtoul strverscmp tmpnam vasprintf vfprintf vprintf \
vsprintf waitpid getrusage on_exit psignal strerror strsignal \
Index: libiberty/lmemmem.c
===================================================================
RCS file: libiberty/lmemmem.c
diff -N libiberty/lmemmem.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ./libiberty/lmemmem.c 15 Jan 2008 21:53:23 -0000
@@ -0,0 +1,52 @@
+/* lmemmem -- search for a sequence of bytes
+ This function is in the public domain. */
+
+/*
+
+@deftypefn Supplemental void *lmemmem (const void *@var{haystack}, size_t @var{haystacklen},
+ const void *@var{needle}, size_t @var{needlelen})
+
+Search the area of memory at @var{haystack} for the bytes at @var{needle},
+and return the first occurrence.
+Returns a pointer to the beginning of the string or NULL if not found.
+
+@end deftypefn
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <sys/types.h> /* size_t */
+#include "libiberty.h"
+
+void*
+lmemmem (const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen)
+{
+#ifdef HAVE_MEMMEM
+ return memmem (haystack, haystacklen, needle, needlelen);
+#else
+ size_t i,j;
+ const char *h = (const char *) haystack;
+ const char *n = (const char *) needle;
+
+ if (needlelen > haystacklen)
+ return NULL;
+ if (needlelen == 0)
+ return (void *) haystack; /* this is what glibc memmem does */
+
+ for (i = 0; i <= haystacklen - needlelen; ++i)
+ {
+ for (j = 0; j < needlelen; ++j)
+ {
+ if (h[i + j] != n[j])
+ break;
+ }
+ if (j == needlelen)
+ return (void*) (h + i);
+ }
+
+ return NULL;
+#endif
+}
Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.974
diff -u -p -u -p -r1.974 Makefile.in
--- ./gdb/Makefile.in 11 Jan 2008 13:34:14 -0000 1.974
+++ ./gdb/Makefile.in 15 Jan 2008 21:53:23 -0000
@@ -599,9 +599,8 @@ SFILES = ada-exp.y ada-lang.c ada-typepr
dbxread.c demangle.c dictionary.c disasm.c doublest.c dummy-frame.c \
dwarf2expr.c dwarf2loc.c dwarf2read.c dwarf2-frame.c \
elfread.c environ.c eval.c event-loop.c event-top.c expprint.c \
- f-exp.y f-lang.c f-typeprint.c f-valprint.c findvar.c frame.c \
- frame-base.c \
- frame-unwind.c \
+ f-exp.y f-lang.c f-typeprint.c f-valprint.c findvar.c findcmd.c \
+ frame.c frame-base.c frame-unwind.c \
gdbarch.c arch-utils.c gdbtypes.c gnu-v2-abi.c gnu-v3-abi.c \
inf-loop.c \
infcall.c \
@@ -1042,6 +1041,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $
event-loop.o event-top.o inf-loop.o completer.o \
gdbarch.o arch-utils.o gdbtypes.o osabi.o copying.o \
memattr.o mem-break.o target.o parse.o language.o buildsym.o \
+ findcmd.o \
std-regs.o \
signals.o \
gdb-events.o \
@@ -2097,6 +2097,7 @@ fbsd-nat.o: fbsd-nat.c $(defs_h) $(gdbco
f-exp.o: f-exp.c $(defs_h) $(gdb_string_h) $(expression_h) $(value_h) \
$(parser_defs_h) $(language_h) $(f_lang_h) $(bfd_h) $(symfile_h) \
$(objfiles_h) $(block_h)
+findcmd.o: findcmd.c $(defs_h) $(gdbcmd_h) $(value_h) $(target_h)
findvar.o: findvar.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(frame_h) \
$(value_h) $(gdbcore_h) $(inferior_h) $(target_h) $(gdb_string_h) \
$(gdb_assert_h) $(floatformat_h) $(symfile_h) $(regcache_h) \
Index: gdb/NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.251
diff -u -p -u -p -r1.251 NEWS
--- ./gdb/NEWS 5 Jan 2008 21:50:43 -0000 1.251
+++ ./gdb/NEWS 15 Jan 2008 21:53:23 -0000
@@ -3,6 +3,17 @@
*** Changes since GDB 6.7
+* New command
+
+find [/size-char] [/max-count] start-address, end-address|@search-space-size,
+ val1 [, val2, ...]
+ Search memory for a sequence of bytes.
+
+* New remote packet
+
+qSearch:memory:
+ Search memory for a sequence of bytes.
+
* Change in command line behavior -- corefiles vs. process ids.
When the '-p NUMBER' or '--pid NUMBER' options are used, and
Index: gdb/findcmd.c
===================================================================
RCS file: gdb/findcmd.c
diff -N gdb/findcmd.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ./gdb/findcmd.c 15 Jan 2008 21:53:24 -0000
@@ -0,0 +1,401 @@
+/* The find command.
+
+ 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 <ctype.h>
+#include "gdb_string.h"
+#include "gdbcmd.h"
+#include "value.h"
+#include "target.h"
+
+static void
+put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p);
+
+static int
+parse_search_string (char **strp, char **parsed_stringp);
+
+/* Copied from bfd_put_bits. */
+
+static void
+put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p)
+{
+ int i;
+ int bytes;
+
+ gdb_assert (bits % 8 == 0);
+
+ bytes = bits / 8;
+ for (i = 0; i < bytes; i++)
+ {
+ int index = big_p ? bytes - i - 1 : i;
+
+ buf[index] = data & 0xff;
+ data >>= 8;
+ }
+}
+
+/* Parse a C/C++ string.
+ *STRP does not contain any embedded nulls.
+ *STRP points to the leading double quote (").
+ The result is the length of the string, and
+ *PARSED_STRINGP contains the parsed string, malloc'd, and
+ *STRP is updated to point to one past the trailing double quote.
+ We need to return the length in case the result has embedded nulls.
+ If there is an error while parsing the string, error() is called
+ so we don't return. */
+
+static int
+parse_search_string (char **strp, char **parsed_stringp)
+{
+ char *start = *strp;
+ char *s = start;
+ char *result_string = xmalloc (strlen (start));
+ char *r = result_string;
+ int len = 0;
+
+ gdb_assert (*s == '"');
+ ++s;
+
+ while (*s != '\0' && *s != '"')
+ {
+ if (*s == '\\')
+ {
+ int c;
+ ++s;
+ c = parse_escape (&s);
+ if (c >= 0)
+ {
+ *r++ = c;
+ ++len;
+ }
+ }
+ else if (*s == '"')
+ {
+ break;
+ }
+ else
+ {
+ *r++ = *s++;
+ ++len;
+ }
+ }
+
+ if (*s != '"')
+ error ("missing trailing double-quote(\") in string");
+ ++s;
+
+ *strp = s;
+ *parsed_stringp = result_string;
+ return len;
+}
+
+static void
+find_command (char *args, int from_tty)
+{
+ /* default to using the specified type */
+ char size = '\0';
+ ULONGEST max_count = ~(ULONGEST) 0;
+ CORE_ADDR start_addr;
+ ULONGEST search_space_len;
+ struct value *v;
+ char *s = args;
+ /* Buffer to hold the search pattern. */
+ 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;
+ /* Pointer to one past the last in-use part of pattern_buf. */
+ char *pattern_buf_end;
+ /* Length of the pattern. */
+ ULONGEST pattern_len;
+ /* Buffer to hold memory contents for searching. */
+ char *search_buf;
+ ULONGEST search_buf_size;
+ /* Where in search_buf to begin searching. */
+ char *search_buf_start;
+ struct cleanup *old_cleanups;
+ unsigned int found_count;
+ CORE_ADDR last_found_addr;
+ enum bfd_endian endian = gdbarch_byte_order (current_gdbarch);
+ /* If endian is unknown use big endian.
+ ??? Is there an established convention for what to pick? */
+ bfd_boolean big_p = endian != BFD_ENDIAN_LITTLE;
+
+ if (args == NULL)
+ error (_("missing search parameters"));
+
+ pattern_buf = xmalloc (pattern_buf_size);
+ pattern_buf_end = pattern_buf;
+ old_cleanups = make_cleanup (free_current_contents, &pattern_buf);
+
+ /* Get search granularity and/or max count if specified. */
+
+ while (*s == '/')
+ {
+ ++s;
+
+ if (isdigit (*s))
+ {
+ /* copied from decode_format */
+ max_count = atoi (s);
+ while (isdigit (*s))
+ ++s;
+ if (*s != '\0' && !isspace (*s))
+ error (_("invalid max-count"));
+ }
+ else
+ {
+ switch (*s)
+ {
+ case 'b':
+ case 'h':
+ case 'w':
+ case 'g':
+ size = *s++;
+ break;
+ default:
+ error (_("invalid size granularity"));
+ }
+ if (*s != '\0' && !isspace (*s))
+ error (_("invalid size granularity"));
+ }
+
+ while (isspace (*s))
+ ++s;
+ }
+
+ /* Get the search range. */
+
+ v = parse_to_comma_and_eval (&s);
+ start_addr = value_as_address (v);
+
+ if (*s == ',')
+ ++s;
+ while (isspace (*s))
+ ++s;
+
+ if (*s == '@')
+ {
+ LONGEST len;
+ ++s;
+ v = parse_to_comma_and_eval (&s);
+ len = value_as_long (v);
+ if (len == 0)
+ {
+ printf_filtered (_("empty search range\n"));
+ return;
+ }
+ if (len < 0)
+ error (_("invalid length"));
+ /* Watch for overflows. */
+ if (len > CORE_ADDR_MAX
+ || (start_addr + len - 1) < start_addr)
+ error (_("search space too large"));
+ search_space_len = len;
+ }
+ else
+ {
+ CORE_ADDR end_addr;
+ v = parse_to_comma_and_eval (&s);
+ end_addr = value_as_address (v);
+ if (start_addr > end_addr)
+ error (_("invalid search space, end preceeds start"));
+ search_space_len = end_addr - start_addr + 1;
+ /* We don't support searching all of memory
+ (i.e. start=0, end = 0xff..ff).
+ Bail to avoid overflows later on. */
+ if (search_space_len == 0)
+ error (_("overflow in address range computation, choose smaller range"));
+ }
+
+ if (*s == ',')
+ ++s;
+
+ /* Fetch the search string. */
+
+ while (*s != '\0')
+ {
+ LONGEST x;
+
+ /* If we see a string, parse it ourselves rather than the normal
+ handling of downloading it to target memory. */
+
+ while (isspace (*s))
+ ++s;
+
+ if (*s == '"')
+ {
+ char *str;
+ int len = parse_search_string (&s, &str);
+
+ if ((pattern_buf_end - pattern_buf + len)
+ > pattern_buf_size)
+ {
+ size_t current_offset = pattern_buf_end - pattern_buf;
+ pattern_buf_size += len * 2; /* kiss */
+ pattern_buf = xrealloc (pattern_buf, pattern_buf_size);
+ pattern_buf_end = pattern_buf + current_offset;
+ }
+
+ memcpy (pattern_buf_end, str, len);
+ pattern_buf_end += len;
+
+ free (str);
+
+ /* Leave the pointer at the next comma, like the `else' clause
+ will do. */
+ while (isspace (*s))
+ ++s;
+
+ if (*s != '\0' && *s != ',')
+ error ("comma expected between expressions");
+ }
+ else /* Not a string, parse the expression the normal way. */
+ {
+ int val_bytes;
+
+ /* ??? Need to prevent (char*) "foo", it downloads string to target
+ and we don't want that. */
+ 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;
+ }
+
+ if (size != '\0')
+ {
+ x = value_as_long (v);
+ switch (size)
+ {
+ case 'b':
+ *pattern_buf_end++ = x;
+ break;
+ case 'h':
+ put_bits (x, pattern_buf_end, 16, big_p);
+ pattern_buf_end += sizeof (int16_t);
+ break;
+ case 'w':
+ put_bits (x, pattern_buf_end, 32, big_p);
+ pattern_buf_end += sizeof (int32_t);
+ break;
+ case 'g':
+ put_bits (x, pattern_buf_end, 64, big_p);
+ pattern_buf_end += sizeof (int64_t);
+ break;
+ }
+ }
+ else
+ {
+ memcpy (pattern_buf_end, value_contents_raw (v), val_bytes);
+ pattern_buf_end += val_bytes;
+ }
+ }
+
+ if (*s == ',')
+ ++s;
+ while (isspace (*s))
+ ++s;
+ }
+
+ if (pattern_buf_end == pattern_buf)
+ error (_("missing search pattern"));
+
+ pattern_len = pattern_buf_end - pattern_buf;
+
+ if (search_space_len < pattern_len)
+ error (_("search space too small to contain pattern"));
+
+ /* Perform the search. */
+
+ found_count = 0;
+ last_found_addr = 0;
+
+ 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);
+
+ if (found <= 0)
+ break;
+
+ print_address (found_addr, gdb_stdout);
+ 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. */
+
+ set_internalvar (lookup_internalvar ("numfound"),
+ value_from_longest (builtin_type_int,
+ (LONGEST) found_count));
+ if (found_count > 0)
+ {
+ set_internalvar (lookup_internalvar ("_"),
+ value_from_pointer (builtin_type_void_data_ptr,
+ last_found_addr));
+ }
+
+ if (found_count == 0)
+ printf_filtered ("pattern not found\n");
+ else
+ printf_filtered ("%d pattern%s found\n", found_count,
+ found_count > 1 ? "s" : "");
+
+ do_cleanups (old_cleanups);
+}
+
+void
+_initialize_mem_search (void)
+{
+ add_cmd ("find", class_vars, find_command, _("\
+Search memory for a sequence of bytes.\n\
+Usage:\n\
+find [/size-char] [/max-count] start-address, end-address, expr1 [, expr2 ...]\n\
+find [/size-char] [/max-count] start-address, @length, expr1 [, expr2 ...]\n\
+size-char is one of b,h,w,g for 8,16,32,64 bit values respectively,\n\
+and if not specified the size is taken from the type of the expression.\n\
+\n\
+The address of the last match is stored as the value of \"$_\".\n\
+Convenience variable \"$numfound\" is set to the number of matches."),
+ &cmdlist);
+}
Index: gdb/remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.275
diff -u -p -u -p -r1.275 remote.c
--- ./gdb/remote.c 1 Jan 2008 22:53:12 -0000 1.275
+++ ./gdb/remote.c 15 Jan 2008 21:53:24 -0000
@@ -920,6 +920,7 @@ enum {
PACKET_qGetTLSAddr,
PACKET_qSupported,
PACKET_QPassSignals,
+ PACKET_qSearch_memory,
PACKET_MAX
};
@@ -2402,6 +2403,8 @@ static struct protocol_feature remote_pr
PACKET_qXfer_spu_write },
{ "QPassSignals", PACKET_DISABLE, remote_supported_packet,
PACKET_QPassSignals },
+ { "qSearch:memory", PACKET_DISABLE, remote_supported_packet,
+ PACKET_qSearch_memory },
};
static void
@@ -5909,6 +5912,81 @@ remote_xfer_partial (struct target_ops *
return strlen ((char *) readbuf);
}
+static int
+remote_search_memory (CORE_ADDR start_addr, ULONGEST search_space_len,
+ const gdb_byte *pattern, ULONGEST pattern_len,
+ CORE_ADDR *found_addrp)
+{
+ struct remote_state *rs = get_remote_state ();
+ int max_size = get_memory_write_packet_size ();
+ struct packet_config *packet =
+ &remote_protocol_packets[PACKET_qSearch_memory];
+ /* number of packet bytes used to encode the pattern,
+ this could be more than PATTERN_LEN due to escape characters */
+ int escaped_pattern_len;
+ /* amount of pattern that was encodable in the packet */
+ int used_pattern_len;
+ int i;
+ int found;
+ ULONGEST found_addr;
+
+ /* Don't go to the target if we don't have to.
+ This is done after checking packet->support to avoid the possibility that
+ a success for this edge case means the facility works in general. */
+ if (pattern_len > search_space_len)
+ return 0;
+ if (pattern_len == 0)
+ {
+ *found_addrp = start_addr;
+ return 1;
+ }
+
+ if (packet->support == PACKET_DISABLE)
+ {
+ /* Target doesn't provided special support, fall back and use the
+ standard support (copy memory and do the search here). */
+ return simple_search_memory (¤t_target,
+ start_addr, search_space_len,
+ pattern, pattern_len, found_addrp);
+ }
+
+ /* Insert header. */
+ i = snprintf (rs->buf, max_size,
+ "qSearch:memory:%s;%s;",
+ paddr_nz (start_addr),
+ phex_nz (search_space_len, sizeof (search_space_len)));
+ max_size -= (i + 1);
+
+ /* Escape as much data as fits into rs->buf. */
+ escaped_pattern_len =
+ remote_escape_output (pattern, pattern_len, (rs->buf + i),
+ &used_pattern_len, max_size);
+
+ /* Bail if the pattern is too large. */
+ if (used_pattern_len != pattern_len)
+ error ("pattern is too large to transmit to remote target");
+
+ if (putpkt_binary (rs->buf, i + escaped_pattern_len) < 0
+ || getpkt_sane (&rs->buf, &rs->buf_size, 0) < 0
+ || packet_ok (rs->buf, packet) != PACKET_OK)
+ return -1;
+
+ if (rs->buf[0] == '0')
+ found = 0;
+ else if (rs->buf[0] == '1')
+ {
+ found = 1;
+ if (rs->buf[1] != ',')
+ error (_("unknown qSearch:memory reply: %s"), rs->buf);
+ unpack_varlen_hex (rs->buf + 2, &found_addr);
+ *found_addrp = found_addr;
+ }
+ else
+ error (_("unknown qSearch:memory reply: %s"), rs->buf);
+
+ return found;
+}
+
static void
remote_rcmd (char *command,
struct ui_file *outbuf)
@@ -6964,6 +7042,7 @@ Specify the serial device it is connecte
remote_ops.to_flash_erase = remote_flash_erase;
remote_ops.to_flash_done = remote_flash_done;
remote_ops.to_read_description = remote_read_description;
+ remote_ops.to_search_memory = remote_search_memory;
}
/* Set up the extended remote vector by making a copy of the standard
@@ -7097,6 +7176,7 @@ Specify the serial device it is connecte
remote_async_ops.to_flash_erase = remote_flash_erase;
remote_async_ops.to_flash_done = remote_flash_done;
remote_async_ops.to_read_description = remote_read_description;
+ remote_async_ops.to_search_memory = remote_search_memory;
}
/* Set up the async extended remote vector by making a copy of the standard
@@ -7355,6 +7435,9 @@ Show the maximum size of the address (in
add_packet_config_cmd (&remote_protocol_packets[PACKET_qSupported],
"qSupported", "supported-packets", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_qSearch_memory],
+ "qSearch:memory", "search-memory", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_open],
"vFile:open", "hostio-open", 0);
Index: gdb/target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.153
diff -u -p -u -p -r1.153 target.c
--- ./gdb/target.c 11 Jan 2008 00:12:43 -0000 1.153
+++ ./gdb/target.c 15 Jan 2008 21:53:24 -0000
@@ -88,6 +88,11 @@ static LONGEST target_xfer_partial (stru
void *readbuf, const void *writebuf,
ULONGEST offset, LONGEST len);
+static int
+default_search_memory (CORE_ADDR start_addr, ULONGEST search_space_len,
+ const gdb_byte *pattern, ULONGEST pattern_len,
+ CORE_ADDR *found_addrp);
+
static void init_dummy_target (void);
static struct target_ops debug_target;
@@ -160,6 +165,12 @@ static int debug_to_thread_alive (ptid_t
static void debug_to_stop (void);
+static int debug_to_search_memory (CORE_ADDR start_addr,
+ ULONGEST search_space_len,
+ const gdb_byte *pattern,
+ ULONGEST pattern_len,
+ CORE_ADDR *found_addrp);
+
/* NOTE: cagney/2004-09-29: Many targets reference this variable in
wierd and mysterious ways. Putting the variable here lets those
wierd and mysterious ways keep building while they are being
@@ -464,6 +475,7 @@ update_current_target (void)
INHERIT (to_make_corefile_notes, t);
INHERIT (to_get_thread_local_address, t);
/* Do not inherit to_read_description. */
+ INHERIT (to_search_memory, t);
INHERIT (to_magic, t);
/* Do not inherit to_memory_map. */
/* Do not inherit to_flash_erase. */
@@ -636,6 +648,8 @@ update_current_target (void)
(void (*) (void (*) (enum inferior_event_type, void*), void*))
tcomplain);
current_target.to_read_description = NULL;
+ de_fault (to_search_memory, default_search_memory);
+
#undef de_fault
/* Finally, position the target-stack beneath the squashed
@@ -1723,6 +1737,139 @@ target_read_description (struct target_o
return NULL;
}
+/* Utility to implement a basic search of memory. */
+
+int
+simple_search_memory (struct target_ops* ops,
+ CORE_ADDR start_addr, ULONGEST search_space_len,
+ const gdb_byte *pattern, ULONGEST pattern_len,
+ CORE_ADDR *found_addrp)
+{
+ /* ??? tunable?
+ NOTE: also defined in find.c testcase. */
+#define SEARCH_CHUNK_SIZE 16000
+ const unsigned chunk_size = SEARCH_CHUNK_SIZE;
+ /* Buffer to hold memory contents for searching. */
+ gdb_byte *search_buf;
+ unsigned search_buf_size;
+ struct cleanup *old_cleanups;
+
+ search_buf_size = chunk_size + pattern_len - 1;
+
+ /* No point in trying to allocate a buffer larger than the search space. */
+ if (search_space_len < search_buf_size)
+ search_buf_size = search_space_len;
+
+ search_buf = malloc (search_buf_size);
+ if (search_buf == NULL)
+ error (_("unable to allocate memory to perform the search"));
+ old_cleanups = make_cleanup (free_current_contents, &search_buf);
+
+ /* Prime the search buffer. */
+
+ if (target_read (ops, TARGET_OBJECT_MEMORY, NULL,
+ search_buf, start_addr, search_buf_size) != search_buf_size)
+ {
+ warning (_("unable to access target memory at %s, halting search"),
+ hex_string (start_addr));
+ do_cleanups (old_cleanups);
+ return -1;
+ }
+
+ /* Perform the search.
+
+ The loop is kept simple by allocating [N + pattern-length - 1] bytes.
+ When we've scanned N bytes we copy the trailing bytes to the start and
+ read in another N bytes. */
+
+ while (search_space_len >= pattern_len)
+ {
+ gdb_byte *found_ptr;
+ unsigned nr_search_bytes = min (search_space_len, search_buf_size);
+
+ found_ptr = lmemmem (search_buf, nr_search_bytes,
+ pattern, pattern_len);
+
+ if (found_ptr != NULL)
+ {
+ CORE_ADDR found_addr = start_addr + (found_ptr - search_buf);
+ *found_addrp = found_addr;
+ do_cleanups (old_cleanups);
+ return 1;
+ }
+
+ /* Not found in this chunk, skip to next chunk. */
+
+ /* Don't let search_space_len wrap here, it's unsigned. */
+ if (search_space_len >= chunk_size)
+ search_space_len -= chunk_size;
+ else
+ search_space_len = 0;
+
+ if (search_space_len >= pattern_len)
+ {
+ unsigned keep_len = search_buf_size - chunk_size;
+ CORE_ADDR read_addr = start_addr + keep_len;
+ int nr_to_read;
+
+ /* Copy the trailing part of the previous iteration to the front
+ of the buffer for the next iteration. */
+ gdb_assert (keep_len == pattern_len - 1);
+ memcpy (search_buf, search_buf + chunk_size, keep_len);
+
+ nr_to_read = min (search_space_len - keep_len, chunk_size);
+
+ if (target_read (ops, TARGET_OBJECT_MEMORY, NULL,
+ search_buf + keep_len, read_addr,
+ nr_to_read) != nr_to_read)
+ {
+ warning (_("unable to access target memory at %s, halting search"),
+ hex_string (read_addr));
+ do_cleanups (old_cleanups);
+ return -1;
+ }
+
+ start_addr += chunk_size;
+ }
+ }
+
+ /* Not found. */
+
+ do_cleanups (old_cleanups);
+ return 0;
+}
+
+/* The default implementation of to_search_memory. */
+
+static int
+default_search_memory (CORE_ADDR start_addr, ULONGEST search_space_len,
+ const gdb_byte *pattern, ULONGEST pattern_len,
+ CORE_ADDR *found_addrp)
+{
+ return simple_search_memory (¤t_target, start_addr, search_space_len,
+ pattern, pattern_len, found_addrp);
+}
+
+/* Search SEARCH_SPACE_LEN bytes beginning at START_ADDR for the
+ sequence of bytes in PATTERN with length PATTERN_LEN.
+
+ The result is 1 if found, 0 if not found, and -1 if there was an error
+ requiring halting of the search (e.g. memory read error).
+ If the pattern is found the address is recorded in FOUND_ADDRP.
+
+ NOTE: May wish to give target ability to maintain state across successive
+ calls within one search request. Left for later. */
+
+int
+target_search_memory (CORE_ADDR start_addr, ULONGEST search_space_len,
+ const gdb_byte *pattern, ULONGEST pattern_len,
+ CORE_ADDR *found_addrp)
+{
+ return current_target.to_search_memory (start_addr, search_space_len,
+ pattern, pattern_len,
+ found_addrp);
+}
+
/* Look through the list of possible targets for a target that can
execute a run or attach command without any other data. This is
used to locate the default process stratum.
@@ -2677,6 +2824,19 @@ debug_to_pid_to_exec_file (int pid)
return exec_file;
}
+static int
+debug_to_search_memory (CORE_ADDR start_addr, ULONGEST search_space_len,
+ const gdb_byte *pattern, ULONGEST pattern_len,
+ CORE_ADDR *found_addrp)
+{
+ int found = debug_target.to_search_memory (start_addr, search_space_len,
+ pattern, pattern_len,
+ found_addrp);
+ fprintf_unfiltered (gdb_stdlog, "target_search_memory (%s, ...) = %d\n",
+ hex_string (start_addr), found);
+ return found;
+}
+
static void
setup_target_debug (void)
{
@@ -2732,6 +2892,7 @@ setup_target_debug (void)
current_target.to_stop = debug_to_stop;
current_target.to_rcmd = debug_to_rcmd;
current_target.to_pid_to_exec_file = debug_to_pid_to_exec_file;
+ current_target.to_search_memory = debug_to_search_memory;
}
\f
Index: gdb/target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.109
diff -u -p -u -p -r1.109 target.h
--- ./gdb/target.h 1 Jan 2008 22:53:13 -0000 1.109
+++ ./gdb/target.h 15 Jan 2008 21:53:24 -0000
@@ -500,6 +500,16 @@ struct target_ops
was available. */
const struct target_desc *(*to_read_description) (struct target_ops *ops);
+ /* Search SEARCH_SPACE_LEN bytes beginning at START_ADDR for the
+ sequence of bytes in PATTERN with length PATTERN_LEN.
+
+ The result is 1 if found, 0 if not found, and -1 if there was an error
+ requiring halting of the search (e.g. memory read error).
+ If the pattern is found the address is recorded in FOUND_ADDRP. */
+ int (*to_search_memory) (CORE_ADDR start_addr, ULONGEST search_space_len,
+ const gdb_byte *pattern, ULONGEST pattern_len,
+ CORE_ADDR *found_addrp);
+
int to_magic;
/* Need sub-structure for target machine related rather than comm related?
*/
@@ -1107,6 +1117,19 @@ extern int target_stopped_data_address_p
extern const struct target_desc *target_read_description (struct target_ops *);
+/* Utility implementation of searching memory. */
+extern int
+simple_search_memory (struct target_ops* ops,
+ CORE_ADDR start_addr, ULONGEST search_space_len,
+ const gdb_byte *pattern, ULONGEST pattern_len,
+ CORE_ADDR *found_addrp);
+
+/* Main entry point for searching memory. */
+extern int
+target_search_memory (CORE_ADDR start_addr, ULONGEST search_space_len,
+ const gdb_byte *pattern, ULONGEST pattern_len,
+ CORE_ADDR *found_addrp);
+
/* Command logging facility. */
#define target_log_command(p) \
Index: gdb/doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.457
diff -u -p -u -p -r1.457 gdb.texinfo
--- ./gdb/doc/gdb.texinfo 12 Jan 2008 08:36:09 -0000 1.457
+++ ./gdb/doc/gdb.texinfo 15 Jan 2008 21:53:25 -0000
@@ -5491,6 +5491,7 @@ Table}.
* Character Sets:: Debugging programs that use a different
character set than GDB does
* Caching Remote Data:: Data caching for remote targets
+* Searching Memory:: Searching memory for a sequence of bytes
@end menu
@node Expressions
@@ -7469,6 +7470,73 @@ state (dirty, bad, ok, etc.). This comm
the data cache operation.
@end table
+@node Searching Memory
+@section Search Memory
+@cindex searching memory
+
+Memory can be searched for a particular sequence of bytes with the
+@code{find} command.
+
+@table @code
+
+@kindex find
+@item find @r{[}/@var{size}@r{]} @r{[}/@var{max_count}@r{]} @var{start_addr}, @@@var{len}, @var{val1} @r{[}, @var{val2}, ...@r{]}
+@itemx find @r{[}/@var{size}@r{]} @r{[}/@var{max_count}@r{]} @var{start_addr}, @var{end_addr}, @var{val1} @r{[}, @var{val2}, ...@r{]}
+Search memory for the sequence of bytes specified by @var{val1}, @var{val2}, etc.
+The search begins at address @var{start_addr} and continues for either
+@var{len} bytes or through to @var{end_addr} inclusive.
+
+@var{size} specifies how to interpret the search pattern and is
+'b' for 8-bit values, 'h' for 16-bit values, 'w' for 32-bit values,
+and 'g' for 64-bit values. If the value size is not explicitly
+specified, it is taken from the value's type. The latter is useful
+when one wants to specify the search pattern as a mixture of types.
+
+@var{max_count} specifies the maximum number of finds to print.
+The default is to print all finds.
+
+@var{size} and @var{max_count} may be specified in either order.
+
+Strings may be specified for search values, quote them normally.
+The string value is copied into the search pattern byte by byte,
+regardless of the endianness of the target and the size specification.
+@end table
+
+The address of each match found is printed as well as a count of the
+number of matches found.
+
+The address of the last value found is stored in convenience variable
+@samp{$numfound}.
+A count of the number of matches is stored in @samp{$_}.
+
+For example, if stopped at the printf in this function
+
+@smallexample
+void
+hello ()
+@{
+ static char hello[] = "hello-hello";
+ static struct @{ char c; short s; int i; @} __attribute__ ((packed)) mixed
+ = @{ 'c', 0x1234, 0x87654321 @};
+ printf ("%s\n", hello);
+@}
+@end smallexample
+
+You get during debugging
+
+@smallexample
+(gdb) find &hello[0], @@sizeof(hello), "hello"
+0x601048 <hello.1628>
+0x60104e <hello.1628+6>
+2 patterns found
+(gdb) find &mixed, @@sizeof(mixed), (char) 'c', (short) 0x1234, (int) 0x87654321
+0x601054 <mixed.1633>
+1 pattern found
+(gdb) print $numfound
+$1 = 1
+(gdb) print $_
+$2 = (void *) 0x601054
+@end smallexample
@node Macros
@chapter C Preprocessor Macros
@@ -13205,6 +13273,10 @@ are:
@tab @code{qGetTLSAddr}
@tab Displaying @code{__thread} variables
+@item @code{search-memory}
+@tab @code{qSearch:memory}
+@tab @code{find}
+
@item @code{supported-packets}
@tab @code{qSupported}
@tab Remote communications parameters
@@ -24151,6 +24223,26 @@ command by a @samp{,}, not a @samp{:}, c
conventions above. Please don't use this packet as a model for new
packets.)
+@item qSearch:memory:@var{address};@var{length};@var{search-pattern}
+@cindex search memory
+@cindex @samp{qSearch:memory} packet
+@anchor{qSearch memory}
+Search LENGTH bytes at ADDRESS for SEARCH-PATTERN.
+ADDRESS and LENGTH are encoded in hex.
+SEARCH-PATTERN is a sequence of bytes, hex encoded.
+
+Reply:
+@table @samp
+@item 0
+The pattern was not found.
+@item 1,address
+The pattern was found at ADDRESS.
+@item E @var{NN}
+A badly formed request or an error was encountered while searching memory.
+@item
+An empty reply indicates that @samp{qSearch:memory} is not recognized.
+@end table
+
@item qSupported @r{[}:@var{gdbfeature} @r{[};@var{gdbfeature}@r{]}@dots{} @r{]}
@cindex supported packets, remote query
@cindex features of the remote protocol
@@ -24292,6 +24384,11 @@ These are the currently defined stub fea
@tab @samp{-}
@tab Yes
+@item @samp{qSearch:memory}
+@tab No
+@tab @samp{-}
+@tab Yes
+
@end multitable
These are the currently defined stub features, in more detail:
@@ -24336,6 +24433,10 @@ The remote stub understands the @samp{qX
The remote stub understands the @samp{QPassSignals} packet
(@pxref{QPassSignals}).
+@item qSearch:memory
+The remote stub understands the @samp{qSearch:memory} packet
+(@pxref{qSearch memory}).
+
@end table
@item qSymbol::
Index: gdb/gdbserver/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/Makefile.in,v
retrieving revision 1.52
diff -u -p -u -p -r1.52 Makefile.in
--- ./gdb/gdbserver/Makefile.in 1 Jan 2008 22:53:14 -0000 1.52
+++ ./gdb/gdbserver/Makefile.in 15 Jan 2008 21:53:25 -0000
@@ -122,6 +122,7 @@ SFILES= $(srcdir)/gdbreplay.c $(srcdir)/
$(srcdir)/thread-db.c $(srcdir)/utils.c \
$(srcdir)/linux-arm-low.c $(srcdir)/linux-cris-low.c \
$(srcdir)/linux-crisv32-low.c $(srcdir)/linux-i386-low.c \
+ $(srcdir)/lmemmem.c \
$(srcdir)/i387-fp.c \
$(srcdir)/linux-ia64-low.c $(srcdir)/linux-low.c \
$(srcdir)/linux-m32r-low.c \
@@ -139,7 +140,7 @@ TAGFILES = $(SOURCES) ${HFILES} ${ALLPAR
OBS = inferiors.o regcache.o remote-utils.o server.o signals.o target.o \
utils.o version.o \
- mem-break.o hostio.o \
+ mem-break.o hostio.o lmemmem.o \
$(XML_BUILTIN) \
$(DEPFILES)
GDBSERVER_LIBS = @GDBSERVER_LIBS@
@@ -291,6 +292,8 @@ utils.o: utils.c $(server_h)
signals.o: ../signals/signals.c $(server_h)
$(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $< -DGDBSERVER
+lmemmem.o: lmemmem.c $(server_h)
+
i387-fp.o: i387-fp.c $(server_h)
linux_low_h = $(srcdir)/linux-low.h
Index: gdb/gdbserver/config.in
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/config.in,v
retrieving revision 1.20
diff -u -p -u -p -r1.20 config.in
--- ./gdb/gdbserver/config.in 16 Dec 2007 21:50:05 -0000 1.20
+++ ./gdb/gdbserver/config.in 15 Jan 2008 21:53:25 -0000
@@ -41,6 +41,9 @@
/* Define to 1 if you have the <malloc.h> header file. */
#undef HAVE_MALLOC_H
+/* Define to 1 if you have the `memmem' function. */
+#undef HAVE_MEMMEM
+
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
Index: gdb/gdbserver/configure
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/configure,v
retrieving revision 1.31
diff -u -p -u -p -r1.31 configure
--- ./gdb/gdbserver/configure 16 Dec 2007 21:50:05 -0000 1.31
+++ ./gdb/gdbserver/configure 15 Jan 2008 21:53:25 -0000
@@ -3101,7 +3101,7 @@ done
-for ac_func in pread pwrite pread64
+for ac_func in memmem pread pwrite pread64
do
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
echo "$as_me:$LINENO: checking for $ac_func" >&5
Index: gdb/gdbserver/configure.ac
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/configure.ac,v
retrieving revision 1.19
diff -u -p -u -p -r1.19 configure.ac
--- ./gdb/gdbserver/configure.ac 16 Dec 2007 21:50:05 -0000 1.19
+++ ./gdb/gdbserver/configure.ac 15 Jan 2008 21:53:25 -0000
@@ -41,7 +41,7 @@ AC_CHECK_HEADERS(sgtty.h termio.h termio
errno.h fcntl.h signal.h sys/file.h malloc.h dnl
sys/ioctl.h netinet/in.h sys/socket.h netdb.h dnl
netinet/tcp.h arpa/inet.h sys/wait.h)
-AC_CHECK_FUNCS(pread pwrite pread64)
+AC_CHECK_FUNCS(memmem pread pwrite pread64)
have_errno=no
AC_MSG_CHECKING(for errno)
Index: gdb/gdbserver/lmemmem.c
===================================================================
RCS file: gdb/gdbserver/lmemmem.c
diff -N gdb/gdbserver/lmemmem.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ./gdb/gdbserver/lmemmem.c 15 Jan 2008 21:53:25 -0000
@@ -0,0 +1,43 @@
+/* lmemmem -- search for a sequence of bytes
+ This function is in the public domain. */
+
+#include "config.h"
+#include <stdlib.h>
+
+#ifdef HAVE_STRING_H
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE /* memmem */
+#endif
+#include <string.h>
+#endif
+
+void*
+lmemmem (const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen)
+{
+#ifdef HAVE_MEMMEM
+ return memmem (haystack, haystacklen, needle, needlelen);
+#else
+ size_t i,j;
+ const char *h = (const char *) haystack;
+ const char *n = (const char *) needle;
+
+ if (needlelen > haystacklen)
+ return NULL;
+ if (needlelen == 0)
+ return (void *) haystack; /* this is what glibc memmem does */
+
+ for (i = 0; i <= haystacklen - needlelen; ++i)
+ {
+ for (j = 0; j < needlelen; ++j)
+ {
+ if (h[i + j] != n[j])
+ break;
+ }
+ if (j == needlelen)
+ return (void*) (h + i);
+ }
+
+ return NULL;
+#endif
+}
Index: gdb/gdbserver/remote-utils.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/remote-utils.c,v
retrieving revision 1.53
diff -u -p -u -p -r1.53 remote-utils.c
--- ./gdb/gdbserver/remote-utils.c 1 Jan 2008 22:53:14 -0000 1.53
+++ ./gdb/gdbserver/remote-utils.c 15 Jan 2008 21:53:25 -0000
@@ -1080,6 +1080,24 @@ decode_xfer_write (char *buf, int packet
return 0;
}
+/* Decode the parameters of a qSearch:memory packet. */
+
+int
+decode_search_memory_packet (const char *buf, int packet_len,
+ CORE_ADDR *start_addrp,
+ CORE_ADDR *search_space_lenp,
+ gdb_byte *pattern, unsigned int *pattern_lenp)
+{
+ const char *p = buf;
+
+ p = decode_address_to_semicolon (start_addrp, p);
+ p = decode_address_to_semicolon (search_space_lenp, p);
+ packet_len -= p - buf;
+ *pattern_lenp = remote_unescape_input ((const gdb_byte *) p, packet_len,
+ pattern, packet_len);
+ return 0;
+}
+
/* Ask GDB for the address of NAME, and return it in ADDRP if found.
Returns 1 if the symbol is found, 0 if it is not, -1 on error. */
Index: gdb/gdbserver/server.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
retrieving revision 1.62
diff -u -p -u -p -r1.62 server.c
--- ./gdb/gdbserver/server.c 1 Jan 2008 22:53:14 -0000 1.62
+++ ./gdb/gdbserver/server.c 15 Jan 2008 21:53:25 -0000
@@ -254,6 +254,157 @@ monitor_show_help (void)
monitor_output (" Enable remote protocol debugging messages\n");
}
+/* Subroutine of handle_search_memory to simplify it. */
+/* ??? Copied from simple_search_memory. Combine? */
+
+static int
+handle_search_memory_1 (CORE_ADDR start_addr, CORE_ADDR search_space_len,
+ gdb_byte *pattern, unsigned pattern_len,
+ gdb_byte *search_buf,
+ unsigned chunk_size, unsigned search_buf_size,
+ CORE_ADDR *found_addrp)
+{
+ /* Prime the search buffer. */
+
+ if (read_inferior_memory (start_addr, search_buf, search_buf_size) != 0)
+ {
+ warning ("unable to access target memory at 0x%lx, halting search",
+ (long) start_addr);
+ return -1;
+ }
+
+ /* Perform the search.
+
+ The loop is kept simple by allocating [N + pattern-length - 1] bytes.
+ When we've scanned N bytes we copy the trailing bytes to the start and
+ read in another N bytes. */
+
+ while (search_space_len >= pattern_len)
+ {
+ gdb_byte *found_ptr;
+ unsigned nr_search_bytes = (search_space_len < search_buf_size
+ ? search_space_len
+ : search_buf_size);
+
+ found_ptr = lmemmem (search_buf, nr_search_bytes,
+ pattern, pattern_len);
+
+ if (found_ptr != NULL)
+ {
+ CORE_ADDR found_addr = start_addr + (found_ptr - search_buf);
+ *found_addrp = found_addr;
+ return 1;
+ }
+
+ /* Not found in this chunk, skip to next chunk. */
+
+ /* Don't let search_space_len wrap here, it's unsigned. */
+ if (search_space_len >= chunk_size)
+ search_space_len -= chunk_size;
+ else
+ search_space_len = 0;
+
+ if (search_space_len >= pattern_len)
+ {
+ unsigned keep_len = search_buf_size - chunk_size;
+ CORE_ADDR read_addr = start_addr + keep_len;
+ int nr_to_read;
+
+ /* Copy the trailing part of the previous iteration to the front
+ of the buffer for the next iteration. */
+ memcpy (search_buf, search_buf + chunk_size, keep_len);
+
+ nr_to_read = (search_space_len - keep_len < chunk_size
+ ? search_space_len - keep_len
+ : chunk_size);
+
+ if (read_inferior_memory (read_addr, search_buf + keep_len,
+ nr_to_read) != 0)
+ {
+ warning ("unable to access target memory at 0x%lx, halting search",
+ (long) read_addr);
+ return -1;
+ }
+
+ start_addr += chunk_size;
+ }
+ }
+
+ /* Not found. */
+
+ return 0;
+}
+
+/* Handle qSearch:memory packets. */
+/* ??? Copied from simple_search_memory. Combine? */
+
+static void
+handle_search_memory (char *own_buf, int packet_len)
+{
+ CORE_ADDR start_addr;
+ CORE_ADDR search_space_len;
+ gdb_byte *pattern;
+ unsigned int pattern_len;
+ /* ??? tunable?
+ NOTE: also defined in find.c testcase. */
+#define SEARCH_CHUNK_SIZE 16000
+ const unsigned chunk_size = SEARCH_CHUNK_SIZE;
+ /* Buffer to hold memory contents for searching. */
+ gdb_byte *search_buf;
+ unsigned search_buf_size;
+ int found;
+ CORE_ADDR found_addr;
+ int cmd_name_len = sizeof ("qSearch:memory:") - 1;
+
+ pattern = malloc (packet_len);
+ if (pattern == NULL)
+ {
+ error ("unable to allocate memory to perform the search");
+ strcpy (own_buf, "E00");
+ return;
+ }
+ if (decode_search_memory_packet (own_buf + cmd_name_len,
+ packet_len - cmd_name_len,
+ &start_addr, &search_space_len,
+ pattern, &pattern_len) < 0)
+ {
+ free (pattern);
+ error ("error in parsing qSearch:memory packet");
+ strcpy (own_buf, "E00");
+ return;
+ }
+
+ search_buf_size = chunk_size + pattern_len - 1;
+
+ /* No point in trying to allocate a buffer larger than the search space. */
+ if (search_space_len < search_buf_size)
+ search_buf_size = search_space_len;
+
+ search_buf = malloc (search_buf_size);
+ if (search_buf == NULL)
+ {
+ free (pattern);
+ error ("unable to allocate memory to perform the search");
+ strcpy (own_buf, "E00");
+ return;
+ }
+
+ found = handle_search_memory_1 (start_addr, search_space_len,
+ pattern, pattern_len,
+ search_buf, chunk_size, search_buf_size,
+ &found_addr);
+
+ if (found > 0)
+ sprintf (own_buf, "1,%lx", (long) found_addr);
+ else if (found == 0)
+ strcpy (own_buf, "0");
+ else
+ strcpy (own_buf, "E00");
+
+ free (search_buf);
+ free (pattern);
+}
+
/* Handle all of the extended 'q' packets. */
void
handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
@@ -533,6 +684,10 @@ handle_query (char *own_buf, int packet_
supports qXfer:libraries:read, so always report it. */
strcat (own_buf, ";qXfer:libraries:read+");
+ /* Do the searching here, so we don't have to send memory back to gdb
+ to be searched. */
+ strcat (own_buf, ";qSearch:memory+");
+
if (the_target->read_auxv != NULL)
strcat (own_buf, ";qXfer:auxv:read+");
@@ -653,6 +808,12 @@ handle_query (char *own_buf, int packet_
return;
}
+ if (strncmp ("qSearch:memory:", own_buf, sizeof ("qSearch:memory:") - 1) == 0)
+ {
+ handle_search_memory (own_buf, packet_len);
+ return;
+ }
+
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
Index: gdb/gdbserver/server.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.h,v
retrieving revision 1.39
diff -u -p -u -p -r1.39 server.h
--- ./gdb/gdbserver/server.h 1 Jan 2008 22:53:14 -0000 1.39
+++ ./gdb/gdbserver/server.h 15 Jan 2008 21:53:25 -0000
@@ -192,6 +192,10 @@ int decode_X_packet (char *from, int pac
int decode_xfer_write (char *buf, int packet_len, char **annex,
CORE_ADDR *offset, unsigned int *len,
unsigned char *data);
+int decode_search_memory_packet (const char *buf, int packet_len,
+ CORE_ADDR *start_addrp,
+ CORE_ADDR *search_space_lenp,
+ gdb_byte *pattern, unsigned int *pattern_lenp);
int unhexify (char *bin, const char *hex, int count);
int hexify (char *hex, const char *bin, int count);
@@ -218,6 +222,10 @@ void error (const char *string,...) ATTR
void fatal (const char *string,...) ATTR_NORETURN ATTR_FORMAT (printf, 1, 2);
void warning (const char *string,...) ATTR_FORMAT (printf, 1, 2);
+/* Functions from lmemmem.c */
+
+void *lmemmem (const void *, size_t, const void *, size_t);
+
/* Functions from the register cache definition. */
void init_registers (void);
Index: gdb/testsuite/gdb.base/find.c
===================================================================
RCS file: gdb/testsuite/gdb.base/find.c
diff -N gdb/testsuite/gdb.base/find.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ./gdb/testsuite/gdb.base/find.c 15 Jan 2008 21:53:25 -0000
@@ -0,0 +1,62 @@
+/* Testcase for the find command.
+ This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2008 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 */
+
+#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;
+}
Index: gdb/testsuite/gdb.base/find.exp
===================================================================
RCS file: gdb/testsuite/gdb.base/find.exp
diff -N gdb/testsuite/gdb.base/find.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ./gdb/testsuite/gdb.base/find.exp 15 Jan 2008 21:53:25 -0000
@@ -0,0 +1,165 @@
+# Copyright 2008 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@prep.ai.mit.edu
+
+# This tests the find command.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+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 "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 history_prefix {[$][0-9]* = }
+set newline {[\r\n]*}
+set one_pattern_found "${newline}1 pattern found"
+set two_patterns_found "${newline}2 patterns found"
+
+# Test string pattern.
+
+gdb_test "set *(int32_t*) &int8_search_buf\[10\] = 0x61616161" "" ""
+
+gdb_test "find &int8_search_buf\[0\], @sizeof(int8_search_buf), \"aaa\"" \
+ "${hex_number}.*<int8_search_buf\\+10>${newline}${hex_number}.*<int8_search_buf\\+11>${two_patterns_found}" \
+ "find string pattern"
+
+# Test max-count, and $numfound.
+
+gdb_test "find /1 &int8_search_buf\[0\], @sizeof(int8_search_buf), \"aaa\"" \
+ "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
+ "max-count first"
+
+gdb_test "print \$numfound" \
+ "${history_prefix}1" \
+ "numfound"
+
+# Test max-count with size-char.
+# They can be specified in either order.
+
+gdb_test "find /1 /b &int8_search_buf\[0\], @sizeof(int8_search_buf), 0x61, 0x61, 0x61" \
+ "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
+ "max-count first"
+
+gdb_test "find /b /1 &int8_search_buf\[0\], @sizeof(int8_search_buf), 0x61, 0x61, 0x61" \
+ "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
+ "max-count second"
+
+# Test specifying end address.
+
+gdb_test "find /b &int8_search_buf\[0\], &int8_search_buf\[0\]+sizeof(int8_search_buf), 0x61, 0x61, 0x61, 0x61" \
+ "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
+ "find byte pattern with end address"
+
+# Test 16-bit pattern.
+
+gdb_test "set int16_search_buf\[10\] = 0x1234" "" ""
+
+gdb_test "find /h &int16_search_buf\[0\], @sizeof(int16_search_buf), 0x1234" \
+ "${hex_number}.*<int16_search_buf\\+20>${one_pattern_found}" \
+ "find 16-bit pattern"
+
+gdb_test "find &int16_search_buf\[0\], @sizeof(int16_search_buf), (int16_t) 0x1234" \
+ "${hex_number}.*<int16_search_buf\\+20>${one_pattern_found}" \
+ "find 16-bit pattern"
+
+# Test 32-bit pattern.
+
+gdb_test "set int32_search_buf\[10\] = 0x12345678" "" ""
+
+gdb_test "find &int32_search_buf\[0\], @sizeof(int32_search_buf), (int32_t) 0x12345678" \
+ "${hex_number}.*<int32_search_buf\\+40>${one_pattern_found}" \
+ "find 32-bit pattern"
+
+gdb_test "find /w &int32_search_buf\[0\], @sizeof(int32_search_buf), 0x12345678" \
+ "${hex_number}.*<int32_search_buf\\+40>${one_pattern_found}" \
+ "find 32-bit pattern"
+
+# Test 64-bit pattern.
+
+gdb_test "set int64_search_buf\[10\] = 0xfedcba9876543210LL" "" ""
+
+gdb_test "find &int64_search_buf\[0\], @sizeof(int64_search_buf), (int64_t) 0xfedcba9876543210LL" \
+ "${hex_number}.*<int64_search_buf\\+80>${one_pattern_found}" \
+ "find 64-bit pattern"
+
+gdb_test "find /g &int64_search_buf\[0\], @sizeof(int64_search_buf), 0xfedcba9876543210LL" \
+ "${hex_number}.*<int64_search_buf\\+80>${one_pattern_found}" \
+ "find 64-bit 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 "find &search_buf\[0\], @search_buf_size, (int8_t) 0x62, (int16_t) 0x6363, (int32_t) 0x64646464" \
+ "${hex_number}${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 ;# see findcmd.c
+
+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 "find /w search_buf, @search_buf_size, 0x12345678" \
+ "${hex_number}${newline}${hex_number}${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 "find /w search_buf, @search_buf_size, 0xfdb97531" \
+ "${hex_number}${one_pattern_found}" \
+ "find pattern straddling chunk boundary"
+}
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: RFC: new command to search memory
2008-01-15 22:15 RFC: new command to search memory Doug Evans
@ 2008-01-28 18:15 ` Doug Evans
2008-01-28 20:26 ` Eli Zaretskii
0 siblings, 1 reply; 5+ messages in thread
From: Doug Evans @ 2008-01-28 18:15 UTC (permalink / raw)
To: gdb-patches, pkoning
Ping ...
On Jan 15, 2008 2:14 PM, Doug Evans <dje@google.com> wrote:
> ref: http://sourceware.org/ml/gdb/2007-12/msg00161.html
> I had some time so as an exercise I came up with this.
> The basic syntax I came up with is:
>
> find [/size] [/max_count] start_addr, @len, val1 [, val2, ...]
> find [/size] [/max_count] start_addr, end_addr, val1 [, val2, ...]
>
> Examples:
>
> void
> hello ()
> {
> static char hello[] = "hello-hello";
> static struct { char c; short s; int i; } __attribute__ ((packed)) mixed
> = { 'c', 0x1234, 0x87654321 };
> printf ("%s\n", hello);
> }
>
> (gdb) find &hello[0], @sizeof(hello), "hello"
> 0x601048 <hello.1628>
> 0x60104e <hello.1628+6>
> 2 patterns found
> (gdb) find &mixed, @sizeof(mixed), (char) 'c', (short) 0x1234, (int) 0x87654321
> 0x601054 <mixed.1633>
> 1 pattern found
> (gdb) print $numfound
> $1 = 1
> (gdb) print $_
> $2 = (void *) 0x601054
>
> Instead of linking with libiberty I just put a copy of lmemmem.c in
> with gdbserver.
>
> I realize the libiberty mods need to go through gcc-patches.
> I'll forward that part of this patch on if/when appropriate.
>
> 2008-01-15 Doug Evans <dje@sebabeach.org>
>
> * include/libiberty.h: (lmemmem): Declare.
>
> * libiberty/Makefile.in (CFILES): Add lmemmem.c.
> (REQUIRED_OFILES): Add lmemmem.o.
> (lmemmem.o): New rule.
> * libiberty/configure.ac (funcs): Add memmem.
> (AC_CHECK_FUNCS): Add memmem.
> * libiberty/config.in: Regenerate.
> * libiberty/configure: Regenerate.
> * libiberty/lmemmem.c: New file.
>
> New "find" command.
> * gdb/Makefile.in (SFILES): Add findcmd.c.
> (COMMON_OBJS): Add findcmd.o.
> (findcmd.o): New rule.
> * gdb/findcmd.c: New file.
> * gdb/target.h (target_ops): New member to_search_memory.
> (simple_search_memory): Declare.
> (target_search_memory): Declare.
> * gdb/target.c (simple_search_memory): New fn.
> (default_search_memory): New fn.
> (debug_to_search_memory): New fn.
> (target_search_memory): New fn.
> (update_current_target): Set to_search_memory.
> (setup_target_debug): Set to_search_memory.
> * gdb/remote.c (PACKET_qSearch_memory): New packet kind.
> (remote_protocol_features): Add qSearch:memory.
> (remote_search_memory): New fn.
> (init_remote_ops): Init to_search_memory.
> (init_extended_remote_ops): Ditto.
> (_initialize_remote): Add qSearch:memory packet config command.
> * gdbserver/configure.ac: Check for memmem.
> * gdbserver/configure: Regenerate.
> * gdbserver/config.in: Regenerate.
> * gdbserver/Makefile.in (SFILES): Add lmemmem.c.
> (OBS): Add lmemmem.o.
> (lmemmem.o): New rule.
> * gdbserver/server.h (decode_search_memory_packet): Declare.
> (lmemmem): Declare.
> * gdbserver/remote-utils.c (decode_search_memory_packet): New fn.
> * gdbserver/server.c (handle_search_memory_1): New fn.
> (handle_search_memory): New fn.
> (handle_query): Process qSearch:memory packets.
> * gdbserver/lmemmem.c: New file.
> * doc/gdb.texinfo: Document "find" command, qSearch:memory packet.
> * testsuite/gdb.base/find.exp: New file.
> * testsuite/gdb.base/find.c: New file.
>
> Index: include/libiberty.h
> ===================================================================
> RCS file: /cvs/src/src/include/libiberty.h,v
> retrieving revision 1.57
> diff -u -p -u -p -r1.57 libiberty.h
> --- ./include/libiberty.h 6 Sep 2007 17:22:36 -0000 1.57
> +++ ./include/libiberty.h 15 Jan 2008 21:53:23 -0000
> @@ -1,6 +1,6 @@
> /* Function declarations for libiberty.
>
> - Copyright 2001, 2002, 2005, 2007 Free Software Foundation, Inc.
> + Copyright 2001, 2002, 2005, 2007, 2008 Free Software Foundation, Inc.
>
> Note - certain prototypes declared in this header file are for
> functions whoes implementation copyright does not belong to the
> @@ -166,6 +166,10 @@ extern char *libiberty_concat_ptr;
> (libiberty_concat_ptr = (char *) alloca (concat_length ACONCAT_PARAMS + 1), \
> concat_copy2 ACONCAT_PARAMS)
>
> +/* A well-defined memmem () that is always compiled in. */
> +
> +extern void * lmemmem (const void *, size_t, const void *, size_t);
> +
> /* Check whether two file descriptors refer to the same file. */
>
> extern int fdmatch (int fd1, int fd2);
> Index: libiberty/Makefile.in
> ===================================================================
> RCS file: /cvs/src/src/libiberty/Makefile.in,v
> retrieving revision 1.89
> diff -u -p -u -p -r1.89 Makefile.in
> --- ./libiberty/Makefile.in 25 Jul 2007 06:36:27 -0000 1.89
> +++ ./libiberty/Makefile.in 15 Jan 2008 21:53:23 -0000
> @@ -2,7 +2,7 @@
> # Originally written by K. Richard Pixley <rich@cygnus.com>.
> #
> # Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
> -# 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software
> +# 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software
> # Foundation
> #
> # This file is part of the libiberty library.
> @@ -133,6 +133,7 @@ CFILES = alloca.c argv.c asprintf.c atex
> hashtab.c hex.c \
> index.c insque.c \
> lbasename.c \
> + lmemmem.c \
> lrealpath.c \
> make-relative-prefix.c \
> make-temp-file.c md5.c memchr.c memcmp.c memcpy.c memmove.c \
> @@ -164,7 +165,7 @@ REQUIRED_OFILES = ./regex.o ./cplus-dem.
> ./fnmatch.o ./fopen_unlocked.o \
> ./getopt.o ./getopt1.o ./getpwd.o ./getruntime.o \
> ./hashtab.o ./hex.o \
> - ./lbasename.o ./lrealpath.o \
> + ./lbasename.o ./lmemmem.o ./lrealpath.o \
> ./make-relative-prefix.o ./make-temp-file.o \
> ./objalloc.o ./obstack.o \
> ./partition.o ./pexecute.o ./physmem.o \
> @@ -748,6 +749,12 @@ $(CONFIGURED_OFILES): stamp-picdir
> else true; fi
> $(COMPILE.c) $(srcdir)/lbasename.c $(OUTPUT_OPTION)
>
> +./lmemmem.o: $(srcdir)/lmemmem.c stamp-h
> + if [ x"$(PICFLAG)" != x ]; then \
> + $(COMPILE.c) $(PICFLAG) $(srcdir)/lmemmem.c -o pic/$@; \
> + else true; fi
> + $(COMPILE.c) $(srcdir)/lmemmem.c $(OUTPUT_OPTION)
> +
> ./lrealpath.o: $(srcdir)/lrealpath.c stamp-h $(INCDIR)/ansidecl.h \
> $(INCDIR)/libiberty.h
> if [ x"$(PICFLAG)" != x ]; then \
> Index: libiberty/config.in
> ===================================================================
> RCS file: /cvs/src/src/libiberty/config.in,v
> retrieving revision 1.38
> diff -u -p -u -p -r1.38 config.in
> --- ./libiberty/config.in 22 Jul 2005 03:16:32 -0000 1.38
> +++ ./libiberty/config.in 15 Jan 2008 21:53:23 -0000
> @@ -139,6 +139,9 @@
> /* Define to 1 if you have the `memcpy' function. */
> #undef HAVE_MEMCPY
>
> +/* Define to 1 if you have the `memmem' function. */
> +#undef HAVE_MEMMEM
> +
> /* Define to 1 if you have the `memmove' function. */
> #undef HAVE_MEMMOVE
>
> Index: libiberty/configure
> ===================================================================
> RCS file: /cvs/src/src/libiberty/configure,v
> retrieving revision 1.89
> diff -u -p -u -p -r1.89 configure
> --- ./libiberty/configure 17 Jul 2007 18:05:02 -0000 1.89
> +++ ./libiberty/configure 15 Jan 2008 21:53:23 -0000
> @@ -5137,7 +5137,7 @@ if test "x" = "y"; then
>
> for ac_func in asprintf atexit basename bcmp bcopy bsearch bzero calloc clock \
> getcwd getpagesize gettimeofday index insque mkstemps memchr memcmp memcpy \
> - memmove mempcpy memset putenv random rename rindex sigsetmask \
> + memmem memmove mempcpy memset putenv random rename rindex sigsetmask \
> strcasecmp setenv stpcpy stpncpy strchr strdup strncasecmp strndup strrchr strstr \
> strtod strtol strtoul strverscmp tmpnam vasprintf vfprintf vprintf \
> vsprintf waitpid getrusage on_exit psignal strerror strsignal \
> Index: libiberty/configure.ac
> ===================================================================
> RCS file: /cvs/src/src/libiberty/configure.ac,v
> retrieving revision 1.37
> diff -u -p -u -p -r1.37 configure.ac
> --- ./libiberty/configure.ac 17 Jul 2007 18:05:02 -0000 1.37
> +++ ./libiberty/configure.ac 15 Jan 2008 21:53:23 -0000
> @@ -362,7 +362,7 @@ checkfuncs="$checkfuncs getsysinfo table
> if test "x" = "y"; then
> AC_CHECK_FUNCS(asprintf atexit basename bcmp bcopy bsearch bzero calloc clock \
> getcwd getpagesize gettimeofday index insque mkstemps memchr memcmp memcpy \
> - memmove mempcpy memset putenv random rename rindex sigsetmask \
> + memmem memmove mempcpy memset putenv random rename rindex sigsetmask \
> strcasecmp setenv stpcpy stpncpy strchr strdup strncasecmp strndup strrchr strstr \
> strtod strtol strtoul strverscmp tmpnam vasprintf vfprintf vprintf \
> vsprintf waitpid getrusage on_exit psignal strerror strsignal \
> Index: libiberty/lmemmem.c
> ===================================================================
> RCS file: libiberty/lmemmem.c
> diff -N libiberty/lmemmem.c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ ./libiberty/lmemmem.c 15 Jan 2008 21:53:23 -0000
> @@ -0,0 +1,52 @@
> +/* lmemmem -- search for a sequence of bytes
> + This function is in the public domain. */
> +
> +/*
> +
> +@deftypefn Supplemental void *lmemmem (const void *@var{haystack}, size_t @var{haystacklen},
> + const void *@var{needle}, size_t @var{needlelen})
> +
> +Search the area of memory at @var{haystack} for the bytes at @var{needle},
> +and return the first occurrence.
> +Returns a pointer to the beginning of the string or NULL if not found.
> +
> +@end deftypefn
> +
> +*/
> +
> +#ifdef HAVE_CONFIG_H
> +#include "config.h"
> +#endif
> +#include <sys/types.h> /* size_t */
> +#include "libiberty.h"
> +
> +void*
> +lmemmem (const void *haystack, size_t haystacklen,
> + const void *needle, size_t needlelen)
> +{
> +#ifdef HAVE_MEMMEM
> + return memmem (haystack, haystacklen, needle, needlelen);
> +#else
> + size_t i,j;
> + const char *h = (const char *) haystack;
> + const char *n = (const char *) needle;
> +
> + if (needlelen > haystacklen)
> + return NULL;
> + if (needlelen == 0)
> + return (void *) haystack; /* this is what glibc memmem does */
> +
> + for (i = 0; i <= haystacklen - needlelen; ++i)
> + {
> + for (j = 0; j < needlelen; ++j)
> + {
> + if (h[i + j] != n[j])
> + break;
> + }
> + if (j == needlelen)
> + return (void*) (h + i);
> + }
> +
> + return NULL;
> +#endif
> +}
> Index: gdb/Makefile.in
> ===================================================================
> RCS file: /cvs/src/src/gdb/Makefile.in,v
> retrieving revision 1.974
> diff -u -p -u -p -r1.974 Makefile.in
> --- ./gdb/Makefile.in 11 Jan 2008 13:34:14 -0000 1.974
> +++ ./gdb/Makefile.in 15 Jan 2008 21:53:23 -0000
> @@ -599,9 +599,8 @@ SFILES = ada-exp.y ada-lang.c ada-typepr
> dbxread.c demangle.c dictionary.c disasm.c doublest.c dummy-frame.c \
> dwarf2expr.c dwarf2loc.c dwarf2read.c dwarf2-frame.c \
> elfread.c environ.c eval.c event-loop.c event-top.c expprint.c \
> - f-exp.y f-lang.c f-typeprint.c f-valprint.c findvar.c frame.c \
> - frame-base.c \
> - frame-unwind.c \
> + f-exp.y f-lang.c f-typeprint.c f-valprint.c findvar.c findcmd.c \
> + frame.c frame-base.c frame-unwind.c \
> gdbarch.c arch-utils.c gdbtypes.c gnu-v2-abi.c gnu-v3-abi.c \
> inf-loop.c \
> infcall.c \
> @@ -1042,6 +1041,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $
> event-loop.o event-top.o inf-loop.o completer.o \
> gdbarch.o arch-utils.o gdbtypes.o osabi.o copying.o \
> memattr.o mem-break.o target.o parse.o language.o buildsym.o \
> + findcmd.o \
> std-regs.o \
> signals.o \
> gdb-events.o \
> @@ -2097,6 +2097,7 @@ fbsd-nat.o: fbsd-nat.c $(defs_h) $(gdbco
> f-exp.o: f-exp.c $(defs_h) $(gdb_string_h) $(expression_h) $(value_h) \
> $(parser_defs_h) $(language_h) $(f_lang_h) $(bfd_h) $(symfile_h) \
> $(objfiles_h) $(block_h)
> +findcmd.o: findcmd.c $(defs_h) $(gdbcmd_h) $(value_h) $(target_h)
> findvar.o: findvar.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(frame_h) \
> $(value_h) $(gdbcore_h) $(inferior_h) $(target_h) $(gdb_string_h) \
> $(gdb_assert_h) $(floatformat_h) $(symfile_h) $(regcache_h) \
> Index: gdb/NEWS
> ===================================================================
> RCS file: /cvs/src/src/gdb/NEWS,v
> retrieving revision 1.251
> diff -u -p -u -p -r1.251 NEWS
> --- ./gdb/NEWS 5 Jan 2008 21:50:43 -0000 1.251
> +++ ./gdb/NEWS 15 Jan 2008 21:53:23 -0000
> @@ -3,6 +3,17 @@
>
> *** Changes since GDB 6.7
>
> +* New command
> +
> +find [/size-char] [/max-count] start-address, end-address|@search-space-size,
> + val1 [, val2, ...]
> + Search memory for a sequence of bytes.
> +
> +* New remote packet
> +
> +qSearch:memory:
> + Search memory for a sequence of bytes.
> +
> * Change in command line behavior -- corefiles vs. process ids.
>
> When the '-p NUMBER' or '--pid NUMBER' options are used, and
> Index: gdb/findcmd.c
> ===================================================================
> RCS file: gdb/findcmd.c
> diff -N gdb/findcmd.c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ ./gdb/findcmd.c 15 Jan 2008 21:53:24 -0000
> @@ -0,0 +1,401 @@
> +/* The find command.
> +
> + 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 <ctype.h>
> +#include "gdb_string.h"
> +#include "gdbcmd.h"
> +#include "value.h"
> +#include "target.h"
> +
> +static void
> +put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p);
> +
> +static int
> +parse_search_string (char **strp, char **parsed_stringp);
> +
> +/* Copied from bfd_put_bits. */
> +
> +static void
> +put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p)
> +{
> + int i;
> + int bytes;
> +
> + gdb_assert (bits % 8 == 0);
> +
> + bytes = bits / 8;
> + for (i = 0; i < bytes; i++)
> + {
> + int index = big_p ? bytes - i - 1 : i;
> +
> + buf[index] = data & 0xff;
> + data >>= 8;
> + }
> +}
> +
> +/* Parse a C/C++ string.
> + *STRP does not contain any embedded nulls.
> + *STRP points to the leading double quote (").
> + The result is the length of the string, and
> + *PARSED_STRINGP contains the parsed string, malloc'd, and
> + *STRP is updated to point to one past the trailing double quote.
> + We need to return the length in case the result has embedded nulls.
> + If there is an error while parsing the string, error() is called
> + so we don't return. */
> +
> +static int
> +parse_search_string (char **strp, char **parsed_stringp)
> +{
> + char *start = *strp;
> + char *s = start;
> + char *result_string = xmalloc (strlen (start));
> + char *r = result_string;
> + int len = 0;
> +
> + gdb_assert (*s == '"');
> + ++s;
> +
> + while (*s != '\0' && *s != '"')
> + {
> + if (*s == '\\')
> + {
> + int c;
> + ++s;
> + c = parse_escape (&s);
> + if (c >= 0)
> + {
> + *r++ = c;
> + ++len;
> + }
> + }
> + else if (*s == '"')
> + {
> + break;
> + }
> + else
> + {
> + *r++ = *s++;
> + ++len;
> + }
> + }
> +
> + if (*s != '"')
> + error ("missing trailing double-quote(\") in string");
> + ++s;
> +
> + *strp = s;
> + *parsed_stringp = result_string;
> + return len;
> +}
> +
> +static void
> +find_command (char *args, int from_tty)
> +{
> + /* default to using the specified type */
> + char size = '\0';
> + ULONGEST max_count = ~(ULONGEST) 0;
> + CORE_ADDR start_addr;
> + ULONGEST search_space_len;
> + struct value *v;
> + char *s = args;
> + /* Buffer to hold the search pattern. */
> + 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;
> + /* Pointer to one past the last in-use part of pattern_buf. */
> + char *pattern_buf_end;
> + /* Length of the pattern. */
> + ULONGEST pattern_len;
> + /* Buffer to hold memory contents for searching. */
> + char *search_buf;
> + ULONGEST search_buf_size;
> + /* Where in search_buf to begin searching. */
> + char *search_buf_start;
> + struct cleanup *old_cleanups;
> + unsigned int found_count;
> + CORE_ADDR last_found_addr;
> + enum bfd_endian endian = gdbarch_byte_order (current_gdbarch);
> + /* If endian is unknown use big endian.
> + ??? Is there an established convention for what to pick? */
> + bfd_boolean big_p = endian != BFD_ENDIAN_LITTLE;
> +
> + if (args == NULL)
> + error (_("missing search parameters"));
> +
> + pattern_buf = xmalloc (pattern_buf_size);
> + pattern_buf_end = pattern_buf;
> + old_cleanups = make_cleanup (free_current_contents, &pattern_buf);
> +
> + /* Get search granularity and/or max count if specified. */
> +
> + while (*s == '/')
> + {
> + ++s;
> +
> + if (isdigit (*s))
> + {
> + /* copied from decode_format */
> + max_count = atoi (s);
> + while (isdigit (*s))
> + ++s;
> + if (*s != '\0' && !isspace (*s))
> + error (_("invalid max-count"));
> + }
> + else
> + {
> + switch (*s)
> + {
> + case 'b':
> + case 'h':
> + case 'w':
> + case 'g':
> + size = *s++;
> + break;
> + default:
> + error (_("invalid size granularity"));
> + }
> + if (*s != '\0' && !isspace (*s))
> + error (_("invalid size granularity"));
> + }
> +
> + while (isspace (*s))
> + ++s;
> + }
> +
> + /* Get the search range. */
> +
> + v = parse_to_comma_and_eval (&s);
> + start_addr = value_as_address (v);
> +
> + if (*s == ',')
> + ++s;
> + while (isspace (*s))
> + ++s;
> +
> + if (*s == '@')
> + {
> + LONGEST len;
> + ++s;
> + v = parse_to_comma_and_eval (&s);
> + len = value_as_long (v);
> + if (len == 0)
> + {
> + printf_filtered (_("empty search range\n"));
> + return;
> + }
> + if (len < 0)
> + error (_("invalid length"));
> + /* Watch for overflows. */
> + if (len > CORE_ADDR_MAX
> + || (start_addr + len - 1) < start_addr)
> + error (_("search space too large"));
> + search_space_len = len;
> + }
> + else
> + {
> + CORE_ADDR end_addr;
> + v = parse_to_comma_and_eval (&s);
> + end_addr = value_as_address (v);
> + if (start_addr > end_addr)
> + error (_("invalid search space, end preceeds start"));
> + search_space_len = end_addr - start_addr + 1;
> + /* We don't support searching all of memory
> + (i.e. start=0, end = 0xff..ff).
> + Bail to avoid overflows later on. */
> + if (search_space_len == 0)
> + error (_("overflow in address range computation, choose smaller range"));
> + }
> +
> + if (*s == ',')
> + ++s;
> +
> + /* Fetch the search string. */
> +
> + while (*s != '\0')
> + {
> + LONGEST x;
> +
> + /* If we see a string, parse it ourselves rather than the normal
> + handling of downloading it to target memory. */
> +
> + while (isspace (*s))
> + ++s;
> +
> + if (*s == '"')
> + {
> + char *str;
> + int len = parse_search_string (&s, &str);
> +
> + if ((pattern_buf_end - pattern_buf + len)
> + > pattern_buf_size)
> + {
> + size_t current_offset = pattern_buf_end - pattern_buf;
> + pattern_buf_size += len * 2; /* kiss */
> + pattern_buf = xrealloc (pattern_buf, pattern_buf_size);
> + pattern_buf_end = pattern_buf + current_offset;
> + }
> +
> + memcpy (pattern_buf_end, str, len);
> + pattern_buf_end += len;
> +
> + free (str);
> +
> + /* Leave the pointer at the next comma, like the `else' clause
> + will do. */
> + while (isspace (*s))
> + ++s;
> +
> + if (*s != '\0' && *s != ',')
> + error ("comma expected between expressions");
> + }
> + else /* Not a string, parse the expression the normal way. */
> + {
> + int val_bytes;
> +
> + /* ??? Need to prevent (char*) "foo", it downloads string to target
> + and we don't want that. */
> + 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;
> + }
> +
> + if (size != '\0')
> + {
> + x = value_as_long (v);
> + switch (size)
> + {
> + case 'b':
> + *pattern_buf_end++ = x;
> + break;
> + case 'h':
> + put_bits (x, pattern_buf_end, 16, big_p);
> + pattern_buf_end += sizeof (int16_t);
> + break;
> + case 'w':
> + put_bits (x, pattern_buf_end, 32, big_p);
> + pattern_buf_end += sizeof (int32_t);
> + break;
> + case 'g':
> + put_bits (x, pattern_buf_end, 64, big_p);
> + pattern_buf_end += sizeof (int64_t);
> + break;
> + }
> + }
> + else
> + {
> + memcpy (pattern_buf_end, value_contents_raw (v), val_bytes);
> + pattern_buf_end += val_bytes;
> + }
> + }
> +
> + if (*s == ',')
> + ++s;
> + while (isspace (*s))
> + ++s;
> + }
> +
> + if (pattern_buf_end == pattern_buf)
> + error (_("missing search pattern"));
> +
> + pattern_len = pattern_buf_end - pattern_buf;
> +
> + if (search_space_len < pattern_len)
> + error (_("search space too small to contain pattern"));
> +
> + /* Perform the search. */
> +
> + found_count = 0;
> + last_found_addr = 0;
> +
> + 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);
> +
> + if (found <= 0)
> + break;
> +
> + print_address (found_addr, gdb_stdout);
> + 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. */
> +
> + set_internalvar (lookup_internalvar ("numfound"),
> + value_from_longest (builtin_type_int,
> + (LONGEST) found_count));
> + if (found_count > 0)
> + {
> + set_internalvar (lookup_internalvar ("_"),
> + value_from_pointer (builtin_type_void_data_ptr,
> + last_found_addr));
> + }
> +
> + if (found_count == 0)
> + printf_filtered ("pattern not found\n");
> + else
> + printf_filtered ("%d pattern%s found\n", found_count,
> + found_count > 1 ? "s" : "");
> +
> + do_cleanups (old_cleanups);
> +}
> +
> +void
> +_initialize_mem_search (void)
> +{
> + add_cmd ("find", class_vars, find_command, _("\
> +Search memory for a sequence of bytes.\n\
> +Usage:\n\
> +find [/size-char] [/max-count] start-address, end-address, expr1 [, expr2 ...]\n\
> +find [/size-char] [/max-count] start-address, @length, expr1 [, expr2 ...]\n\
> +size-char is one of b,h,w,g for 8,16,32,64 bit values respectively,\n\
> +and if not specified the size is taken from the type of the expression.\n\
> +\n\
> +The address of the last match is stored as the value of \"$_\".\n\
> +Convenience variable \"$numfound\" is set to the number of matches."),
> + &cmdlist);
> +}
> Index: gdb/remote.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/remote.c,v
> retrieving revision 1.275
> diff -u -p -u -p -r1.275 remote.c
> --- ./gdb/remote.c 1 Jan 2008 22:53:12 -0000 1.275
> +++ ./gdb/remote.c 15 Jan 2008 21:53:24 -0000
> @@ -920,6 +920,7 @@ enum {
> PACKET_qGetTLSAddr,
> PACKET_qSupported,
> PACKET_QPassSignals,
> + PACKET_qSearch_memory,
> PACKET_MAX
> };
>
> @@ -2402,6 +2403,8 @@ static struct protocol_feature remote_pr
> PACKET_qXfer_spu_write },
> { "QPassSignals", PACKET_DISABLE, remote_supported_packet,
> PACKET_QPassSignals },
> + { "qSearch:memory", PACKET_DISABLE, remote_supported_packet,
> + PACKET_qSearch_memory },
> };
>
> static void
> @@ -5909,6 +5912,81 @@ remote_xfer_partial (struct target_ops *
> return strlen ((char *) readbuf);
> }
>
> +static int
> +remote_search_memory (CORE_ADDR start_addr, ULONGEST search_space_len,
> + const gdb_byte *pattern, ULONGEST pattern_len,
> + CORE_ADDR *found_addrp)
> +{
> + struct remote_state *rs = get_remote_state ();
> + int max_size = get_memory_write_packet_size ();
> + struct packet_config *packet =
> + &remote_protocol_packets[PACKET_qSearch_memory];
> + /* number of packet bytes used to encode the pattern,
> + this could be more than PATTERN_LEN due to escape characters */
> + int escaped_pattern_len;
> + /* amount of pattern that was encodable in the packet */
> + int used_pattern_len;
> + int i;
> + int found;
> + ULONGEST found_addr;
> +
> + /* Don't go to the target if we don't have to.
> + This is done after checking packet->support to avoid the possibility that
> + a success for this edge case means the facility works in general. */
> + if (pattern_len > search_space_len)
> + return 0;
> + if (pattern_len == 0)
> + {
> + *found_addrp = start_addr;
> + return 1;
> + }
> +
> + if (packet->support == PACKET_DISABLE)
> + {
> + /* Target doesn't provided special support, fall back and use the
> + standard support (copy memory and do the search here). */
> + return simple_search_memory (¤t_target,
> + start_addr, search_space_len,
> + pattern, pattern_len, found_addrp);
> + }
> +
> + /* Insert header. */
> + i = snprintf (rs->buf, max_size,
> + "qSearch:memory:%s;%s;",
> + paddr_nz (start_addr),
> + phex_nz (search_space_len, sizeof (search_space_len)));
> + max_size -= (i + 1);
> +
> + /* Escape as much data as fits into rs->buf. */
> + escaped_pattern_len =
> + remote_escape_output (pattern, pattern_len, (rs->buf + i),
> + &used_pattern_len, max_size);
> +
> + /* Bail if the pattern is too large. */
> + if (used_pattern_len != pattern_len)
> + error ("pattern is too large to transmit to remote target");
> +
> + if (putpkt_binary (rs->buf, i + escaped_pattern_len) < 0
> + || getpkt_sane (&rs->buf, &rs->buf_size, 0) < 0
> + || packet_ok (rs->buf, packet) != PACKET_OK)
> + return -1;
> +
> + if (rs->buf[0] == '0')
> + found = 0;
> + else if (rs->buf[0] == '1')
> + {
> + found = 1;
> + if (rs->buf[1] != ',')
> + error (_("unknown qSearch:memory reply: %s"), rs->buf);
> + unpack_varlen_hex (rs->buf + 2, &found_addr);
> + *found_addrp = found_addr;
> + }
> + else
> + error (_("unknown qSearch:memory reply: %s"), rs->buf);
> +
> + return found;
> +}
> +
> static void
> remote_rcmd (char *command,
> struct ui_file *outbuf)
> @@ -6964,6 +7042,7 @@ Specify the serial device it is connecte
> remote_ops.to_flash_erase = remote_flash_erase;
> remote_ops.to_flash_done = remote_flash_done;
> remote_ops.to_read_description = remote_read_description;
> + remote_ops.to_search_memory = remote_search_memory;
> }
>
> /* Set up the extended remote vector by making a copy of the standard
> @@ -7097,6 +7176,7 @@ Specify the serial device it is connecte
> remote_async_ops.to_flash_erase = remote_flash_erase;
> remote_async_ops.to_flash_done = remote_flash_done;
> remote_async_ops.to_read_description = remote_read_description;
> + remote_async_ops.to_search_memory = remote_search_memory;
> }
>
> /* Set up the async extended remote vector by making a copy of the standard
> @@ -7355,6 +7435,9 @@ Show the maximum size of the address (in
> add_packet_config_cmd (&remote_protocol_packets[PACKET_qSupported],
> "qSupported", "supported-packets", 0);
>
> + add_packet_config_cmd (&remote_protocol_packets[PACKET_qSearch_memory],
> + "qSearch:memory", "search-memory", 0);
> +
> add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_open],
> "vFile:open", "hostio-open", 0);
>
> Index: gdb/target.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/target.c,v
> retrieving revision 1.153
> diff -u -p -u -p -r1.153 target.c
> --- ./gdb/target.c 11 Jan 2008 00:12:43 -0000 1.153
> +++ ./gdb/target.c 15 Jan 2008 21:53:24 -0000
> @@ -88,6 +88,11 @@ static LONGEST target_xfer_partial (stru
> void *readbuf, const void *writebuf,
> ULONGEST offset, LONGEST len);
>
> +static int
> +default_search_memory (CORE_ADDR start_addr, ULONGEST search_space_len,
> + const gdb_byte *pattern, ULONGEST pattern_len,
> + CORE_ADDR *found_addrp);
> +
> static void init_dummy_target (void);
>
> static struct target_ops debug_target;
> @@ -160,6 +165,12 @@ static int debug_to_thread_alive (ptid_t
>
> static void debug_to_stop (void);
>
> +static int debug_to_search_memory (CORE_ADDR start_addr,
> + ULONGEST search_space_len,
> + const gdb_byte *pattern,
> + ULONGEST pattern_len,
> + CORE_ADDR *found_addrp);
> +
> /* NOTE: cagney/2004-09-29: Many targets reference this variable in
> wierd and mysterious ways. Putting the variable here lets those
> wierd and mysterious ways keep building while they are being
> @@ -464,6 +475,7 @@ update_current_target (void)
> INHERIT (to_make_corefile_notes, t);
> INHERIT (to_get_thread_local_address, t);
> /* Do not inherit to_read_description. */
> + INHERIT (to_search_memory, t);
> INHERIT (to_magic, t);
> /* Do not inherit to_memory_map. */
> /* Do not inherit to_flash_erase. */
> @@ -636,6 +648,8 @@ update_current_target (void)
> (void (*) (void (*) (enum inferior_event_type, void*), void*))
> tcomplain);
> current_target.to_read_description = NULL;
> + de_fault (to_search_memory, default_search_memory);
> +
> #undef de_fault
>
> /* Finally, position the target-stack beneath the squashed
> @@ -1723,6 +1737,139 @@ target_read_description (struct target_o
> return NULL;
> }
>
> +/* Utility to implement a basic search of memory. */
> +
> +int
> +simple_search_memory (struct target_ops* ops,
> + CORE_ADDR start_addr, ULONGEST search_space_len,
> + const gdb_byte *pattern, ULONGEST pattern_len,
> + CORE_ADDR *found_addrp)
> +{
> + /* ??? tunable?
> + NOTE: also defined in find.c testcase. */
> +#define SEARCH_CHUNK_SIZE 16000
> + const unsigned chunk_size = SEARCH_CHUNK_SIZE;
> + /* Buffer to hold memory contents for searching. */
> + gdb_byte *search_buf;
> + unsigned search_buf_size;
> + struct cleanup *old_cleanups;
> +
> + search_buf_size = chunk_size + pattern_len - 1;
> +
> + /* No point in trying to allocate a buffer larger than the search space. */
> + if (search_space_len < search_buf_size)
> + search_buf_size = search_space_len;
> +
> + search_buf = malloc (search_buf_size);
> + if (search_buf == NULL)
> + error (_("unable to allocate memory to perform the search"));
> + old_cleanups = make_cleanup (free_current_contents, &search_buf);
> +
> + /* Prime the search buffer. */
> +
> + if (target_read (ops, TARGET_OBJECT_MEMORY, NULL,
> + search_buf, start_addr, search_buf_size) != search_buf_size)
> + {
> + warning (_("unable to access target memory at %s, halting search"),
> + hex_string (start_addr));
> + do_cleanups (old_cleanups);
> + return -1;
> + }
> +
> + /* Perform the search.
> +
> + The loop is kept simple by allocating [N + pattern-length - 1] bytes.
> + When we've scanned N bytes we copy the trailing bytes to the start and
> + read in another N bytes. */
> +
> + while (search_space_len >= pattern_len)
> + {
> + gdb_byte *found_ptr;
> + unsigned nr_search_bytes = min (search_space_len, search_buf_size);
> +
> + found_ptr = lmemmem (search_buf, nr_search_bytes,
> + pattern, pattern_len);
> +
> + if (found_ptr != NULL)
> + {
> + CORE_ADDR found_addr = start_addr + (found_ptr - search_buf);
> + *found_addrp = found_addr;
> + do_cleanups (old_cleanups);
> + return 1;
> + }
> +
> + /* Not found in this chunk, skip to next chunk. */
> +
> + /* Don't let search_space_len wrap here, it's unsigned. */
> + if (search_space_len >= chunk_size)
> + search_space_len -= chunk_size;
> + else
> + search_space_len = 0;
> +
> + if (search_space_len >= pattern_len)
> + {
> + unsigned keep_len = search_buf_size - chunk_size;
> + CORE_ADDR read_addr = start_addr + keep_len;
> + int nr_to_read;
> +
> + /* Copy the trailing part of the previous iteration to the front
> + of the buffer for the next iteration. */
> + gdb_assert (keep_len == pattern_len - 1);
> + memcpy (search_buf, search_buf + chunk_size, keep_len);
> +
> + nr_to_read = min (search_space_len - keep_len, chunk_size);
> +
> + if (target_read (ops, TARGET_OBJECT_MEMORY, NULL,
> + search_buf + keep_len, read_addr,
> + nr_to_read) != nr_to_read)
> + {
> + warning (_("unable to access target memory at %s, halting search"),
> + hex_string (read_addr));
> + do_cleanups (old_cleanups);
> + return -1;
> + }
> +
> + start_addr += chunk_size;
> + }
> + }
> +
> + /* Not found. */
> +
> + do_cleanups (old_cleanups);
> + return 0;
> +}
> +
> +/* The default implementation of to_search_memory. */
> +
> +static int
> +default_search_memory (CORE_ADDR start_addr, ULONGEST search_space_len,
> + const gdb_byte *pattern, ULONGEST pattern_len,
> + CORE_ADDR *found_addrp)
> +{
> + return simple_search_memory (¤t_target, start_addr, search_space_len,
> + pattern, pattern_len, found_addrp);
> +}
> +
> +/* Search SEARCH_SPACE_LEN bytes beginning at START_ADDR for the
> + sequence of bytes in PATTERN with length PATTERN_LEN.
> +
> + The result is 1 if found, 0 if not found, and -1 if there was an error
> + requiring halting of the search (e.g. memory read error).
> + If the pattern is found the address is recorded in FOUND_ADDRP.
> +
> + NOTE: May wish to give target ability to maintain state across successive
> + calls within one search request. Left for later. */
> +
> +int
> +target_search_memory (CORE_ADDR start_addr, ULONGEST search_space_len,
> + const gdb_byte *pattern, ULONGEST pattern_len,
> + CORE_ADDR *found_addrp)
> +{
> + return current_target.to_search_memory (start_addr, search_space_len,
> + pattern, pattern_len,
> + found_addrp);
> +}
> +
> /* Look through the list of possible targets for a target that can
> execute a run or attach command without any other data. This is
> used to locate the default process stratum.
> @@ -2677,6 +2824,19 @@ debug_to_pid_to_exec_file (int pid)
> return exec_file;
> }
>
> +static int
> +debug_to_search_memory (CORE_ADDR start_addr, ULONGEST search_space_len,
> + const gdb_byte *pattern, ULONGEST pattern_len,
> + CORE_ADDR *found_addrp)
> +{
> + int found = debug_target.to_search_memory (start_addr, search_space_len,
> + pattern, pattern_len,
> + found_addrp);
> + fprintf_unfiltered (gdb_stdlog, "target_search_memory (%s, ...) = %d\n",
> + hex_string (start_addr), found);
> + return found;
> +}
> +
> static void
> setup_target_debug (void)
> {
> @@ -2732,6 +2892,7 @@ setup_target_debug (void)
> current_target.to_stop = debug_to_stop;
> current_target.to_rcmd = debug_to_rcmd;
> current_target.to_pid_to_exec_file = debug_to_pid_to_exec_file;
> + current_target.to_search_memory = debug_to_search_memory;
> }
>
>
> Index: gdb/target.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/target.h,v
> retrieving revision 1.109
> diff -u -p -u -p -r1.109 target.h
> --- ./gdb/target.h 1 Jan 2008 22:53:13 -0000 1.109
> +++ ./gdb/target.h 15 Jan 2008 21:53:24 -0000
> @@ -500,6 +500,16 @@ struct target_ops
> was available. */
> const struct target_desc *(*to_read_description) (struct target_ops *ops);
>
> + /* Search SEARCH_SPACE_LEN bytes beginning at START_ADDR for the
> + sequence of bytes in PATTERN with length PATTERN_LEN.
> +
> + The result is 1 if found, 0 if not found, and -1 if there was an error
> + requiring halting of the search (e.g. memory read error).
> + If the pattern is found the address is recorded in FOUND_ADDRP. */
> + int (*to_search_memory) (CORE_ADDR start_addr, ULONGEST search_space_len,
> + const gdb_byte *pattern, ULONGEST pattern_len,
> + CORE_ADDR *found_addrp);
> +
> int to_magic;
> /* Need sub-structure for target machine related rather than comm related?
> */
> @@ -1107,6 +1117,19 @@ extern int target_stopped_data_address_p
>
> extern const struct target_desc *target_read_description (struct target_ops *);
>
> +/* Utility implementation of searching memory. */
> +extern int
> +simple_search_memory (struct target_ops* ops,
> + CORE_ADDR start_addr, ULONGEST search_space_len,
> + const gdb_byte *pattern, ULONGEST pattern_len,
> + CORE_ADDR *found_addrp);
> +
> +/* Main entry point for searching memory. */
> +extern int
> +target_search_memory (CORE_ADDR start_addr, ULONGEST search_space_len,
> + const gdb_byte *pattern, ULONGEST pattern_len,
> + CORE_ADDR *found_addrp);
> +
> /* Command logging facility. */
>
> #define target_log_command(p) \
> Index: gdb/doc/gdb.texinfo
> ===================================================================
> RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
> retrieving revision 1.457
> diff -u -p -u -p -r1.457 gdb.texinfo
> --- ./gdb/doc/gdb.texinfo 12 Jan 2008 08:36:09 -0000 1.457
> +++ ./gdb/doc/gdb.texinfo 15 Jan 2008 21:53:25 -0000
> @@ -5491,6 +5491,7 @@ Table}.
> * Character Sets:: Debugging programs that use a different
> character set than GDB does
> * Caching Remote Data:: Data caching for remote targets
> +* Searching Memory:: Searching memory for a sequence of bytes
> @end menu
>
> @node Expressions
> @@ -7469,6 +7470,73 @@ state (dirty, bad, ok, etc.). This comm
> the data cache operation.
> @end table
>
> +@node Searching Memory
> +@section Search Memory
> +@cindex searching memory
> +
> +Memory can be searched for a particular sequence of bytes with the
> +@code{find} command.
> +
> +@table @code
> +
> +@kindex find
> +@item find @r{[}/@var{size}@r{]} @r{[}/@var{max_count}@r{]} @var{start_addr}, @@@var{len}, @var{val1} @r{[}, @var{val2}, ...@r{]}
> +@itemx find @r{[}/@var{size}@r{]} @r{[}/@var{max_count}@r{]} @var{start_addr}, @var{end_addr}, @var{val1} @r{[}, @var{val2}, ...@r{]}
> +Search memory for the sequence of bytes specified by @var{val1}, @var{val2}, etc.
> +The search begins at address @var{start_addr} and continues for either
> +@var{len} bytes or through to @var{end_addr} inclusive.
> +
> +@var{size} specifies how to interpret the search pattern and is
> +'b' for 8-bit values, 'h' for 16-bit values, 'w' for 32-bit values,
> +and 'g' for 64-bit values. If the value size is not explicitly
> +specified, it is taken from the value's type. The latter is useful
> +when one wants to specify the search pattern as a mixture of types.
> +
> +@var{max_count} specifies the maximum number of finds to print.
> +The default is to print all finds.
> +
> +@var{size} and @var{max_count} may be specified in either order.
> +
> +Strings may be specified for search values, quote them normally.
> +The string value is copied into the search pattern byte by byte,
> +regardless of the endianness of the target and the size specification.
> +@end table
> +
> +The address of each match found is printed as well as a count of the
> +number of matches found.
> +
> +The address of the last value found is stored in convenience variable
> +@samp{$numfound}.
> +A count of the number of matches is stored in @samp{$_}.
> +
> +For example, if stopped at the printf in this function
> +
> +@smallexample
> +void
> +hello ()
> +@{
> + static char hello[] = "hello-hello";
> + static struct @{ char c; short s; int i; @} __attribute__ ((packed)) mixed
> + = @{ 'c', 0x1234, 0x87654321 @};
> + printf ("%s\n", hello);
> +@}
> +@end smallexample
> +
> +You get during debugging
> +
> +@smallexample
> +(gdb) find &hello[0], @@sizeof(hello), "hello"
> +0x601048 <hello.1628>
> +0x60104e <hello.1628+6>
> +2 patterns found
> +(gdb) find &mixed, @@sizeof(mixed), (char) 'c', (short) 0x1234, (int) 0x87654321
> +0x601054 <mixed.1633>
> +1 pattern found
> +(gdb) print $numfound
> +$1 = 1
> +(gdb) print $_
> +$2 = (void *) 0x601054
> +@end smallexample
>
> @node Macros
> @chapter C Preprocessor Macros
> @@ -13205,6 +13273,10 @@ are:
> @tab @code{qGetTLSAddr}
> @tab Displaying @code{__thread} variables
>
> +@item @code{search-memory}
> +@tab @code{qSearch:memory}
> +@tab @code{find}
> +
> @item @code{supported-packets}
> @tab @code{qSupported}
> @tab Remote communications parameters
> @@ -24151,6 +24223,26 @@ command by a @samp{,}, not a @samp{:}, c
> conventions above. Please don't use this packet as a model for new
> packets.)
>
> +@item qSearch:memory:@var{address};@var{length};@var{search-pattern}
> +@cindex search memory
> +@cindex @samp{qSearch:memory} packet
> +@anchor{qSearch memory}
> +Search LENGTH bytes at ADDRESS for SEARCH-PATTERN.
> +ADDRESS and LENGTH are encoded in hex.
> +SEARCH-PATTERN is a sequence of bytes, hex encoded.
> +
> +Reply:
> +@table @samp
> +@item 0
> +The pattern was not found.
> +@item 1,address
> +The pattern was found at ADDRESS.
> +@item E @var{NN}
> +A badly formed request or an error was encountered while searching memory.
> +@item
> +An empty reply indicates that @samp{qSearch:memory} is not recognized.
> +@end table
> +
> @item qSupported @r{[}:@var{gdbfeature} @r{[};@var{gdbfeature}@r{]}@dots{} @r{]}
> @cindex supported packets, remote query
> @cindex features of the remote protocol
> @@ -24292,6 +24384,11 @@ These are the currently defined stub fea
> @tab @samp{-}
> @tab Yes
>
> +@item @samp{qSearch:memory}
> +@tab No
> +@tab @samp{-}
> +@tab Yes
> +
> @end multitable
>
> These are the currently defined stub features, in more detail:
> @@ -24336,6 +24433,10 @@ The remote stub understands the @samp{qX
> The remote stub understands the @samp{QPassSignals} packet
> (@pxref{QPassSignals}).
>
> +@item qSearch:memory
> +The remote stub understands the @samp{qSearch:memory} packet
> +(@pxref{qSearch memory}).
> +
> @end table
>
> @item qSymbol::
> Index: gdb/gdbserver/Makefile.in
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/Makefile.in,v
> retrieving revision 1.52
> diff -u -p -u -p -r1.52 Makefile.in
> --- ./gdb/gdbserver/Makefile.in 1 Jan 2008 22:53:14 -0000 1.52
> +++ ./gdb/gdbserver/Makefile.in 15 Jan 2008 21:53:25 -0000
> @@ -122,6 +122,7 @@ SFILES= $(srcdir)/gdbreplay.c $(srcdir)/
> $(srcdir)/thread-db.c $(srcdir)/utils.c \
> $(srcdir)/linux-arm-low.c $(srcdir)/linux-cris-low.c \
> $(srcdir)/linux-crisv32-low.c $(srcdir)/linux-i386-low.c \
> + $(srcdir)/lmemmem.c \
> $(srcdir)/i387-fp.c \
> $(srcdir)/linux-ia64-low.c $(srcdir)/linux-low.c \
> $(srcdir)/linux-m32r-low.c \
> @@ -139,7 +140,7 @@ TAGFILES = $(SOURCES) ${HFILES} ${ALLPAR
>
> OBS = inferiors.o regcache.o remote-utils.o server.o signals.o target.o \
> utils.o version.o \
> - mem-break.o hostio.o \
> + mem-break.o hostio.o lmemmem.o \
> $(XML_BUILTIN) \
> $(DEPFILES)
> GDBSERVER_LIBS = @GDBSERVER_LIBS@
> @@ -291,6 +292,8 @@ utils.o: utils.c $(server_h)
> signals.o: ../signals/signals.c $(server_h)
> $(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $< -DGDBSERVER
>
> +lmemmem.o: lmemmem.c $(server_h)
> +
> i387-fp.o: i387-fp.c $(server_h)
>
> linux_low_h = $(srcdir)/linux-low.h
> Index: gdb/gdbserver/config.in
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/config.in,v
> retrieving revision 1.20
> diff -u -p -u -p -r1.20 config.in
> --- ./gdb/gdbserver/config.in 16 Dec 2007 21:50:05 -0000 1.20
> +++ ./gdb/gdbserver/config.in 15 Jan 2008 21:53:25 -0000
> @@ -41,6 +41,9 @@
> /* Define to 1 if you have the <malloc.h> header file. */
> #undef HAVE_MALLOC_H
>
> +/* Define to 1 if you have the `memmem' function. */
> +#undef HAVE_MEMMEM
> +
> /* Define to 1 if you have the <memory.h> header file. */
> #undef HAVE_MEMORY_H
>
> Index: gdb/gdbserver/configure
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/configure,v
> retrieving revision 1.31
> diff -u -p -u -p -r1.31 configure
> --- ./gdb/gdbserver/configure 16 Dec 2007 21:50:05 -0000 1.31
> +++ ./gdb/gdbserver/configure 15 Jan 2008 21:53:25 -0000
> @@ -3101,7 +3101,7 @@ done
>
>
>
> -for ac_func in pread pwrite pread64
> +for ac_func in memmem pread pwrite pread64
> do
> as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
> echo "$as_me:$LINENO: checking for $ac_func" >&5
> Index: gdb/gdbserver/configure.ac
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/configure.ac,v
> retrieving revision 1.19
> diff -u -p -u -p -r1.19 configure.ac
> --- ./gdb/gdbserver/configure.ac 16 Dec 2007 21:50:05 -0000 1.19
> +++ ./gdb/gdbserver/configure.ac 15 Jan 2008 21:53:25 -0000
> @@ -41,7 +41,7 @@ AC_CHECK_HEADERS(sgtty.h termio.h termio
> errno.h fcntl.h signal.h sys/file.h malloc.h dnl
> sys/ioctl.h netinet/in.h sys/socket.h netdb.h dnl
> netinet/tcp.h arpa/inet.h sys/wait.h)
> -AC_CHECK_FUNCS(pread pwrite pread64)
> +AC_CHECK_FUNCS(memmem pread pwrite pread64)
>
> have_errno=no
> AC_MSG_CHECKING(for errno)
> Index: gdb/gdbserver/lmemmem.c
> ===================================================================
> RCS file: gdb/gdbserver/lmemmem.c
> diff -N gdb/gdbserver/lmemmem.c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ ./gdb/gdbserver/lmemmem.c 15 Jan 2008 21:53:25 -0000
> @@ -0,0 +1,43 @@
> +/* lmemmem -- search for a sequence of bytes
> + This function is in the public domain. */
> +
> +#include "config.h"
> +#include <stdlib.h>
> +
> +#ifdef HAVE_STRING_H
> +#ifndef _GNU_SOURCE
> +#define _GNU_SOURCE /* memmem */
> +#endif
> +#include <string.h>
> +#endif
> +
> +void*
> +lmemmem (const void *haystack, size_t haystacklen,
> + const void *needle, size_t needlelen)
> +{
> +#ifdef HAVE_MEMMEM
> + return memmem (haystack, haystacklen, needle, needlelen);
> +#else
> + size_t i,j;
> + const char *h = (const char *) haystack;
> + const char *n = (const char *) needle;
> +
> + if (needlelen > haystacklen)
> + return NULL;
> + if (needlelen == 0)
> + return (void *) haystack; /* this is what glibc memmem does */
> +
> + for (i = 0; i <= haystacklen - needlelen; ++i)
> + {
> + for (j = 0; j < needlelen; ++j)
> + {
> + if (h[i + j] != n[j])
> + break;
> + }
> + if (j == needlelen)
> + return (void*) (h + i);
> + }
> +
> + return NULL;
> +#endif
> +}
> Index: gdb/gdbserver/remote-utils.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/remote-utils.c,v
> retrieving revision 1.53
> diff -u -p -u -p -r1.53 remote-utils.c
> --- ./gdb/gdbserver/remote-utils.c 1 Jan 2008 22:53:14 -0000 1.53
> +++ ./gdb/gdbserver/remote-utils.c 15 Jan 2008 21:53:25 -0000
> @@ -1080,6 +1080,24 @@ decode_xfer_write (char *buf, int packet
> return 0;
> }
>
> +/* Decode the parameters of a qSearch:memory packet. */
> +
> +int
> +decode_search_memory_packet (const char *buf, int packet_len,
> + CORE_ADDR *start_addrp,
> + CORE_ADDR *search_space_lenp,
> + gdb_byte *pattern, unsigned int *pattern_lenp)
> +{
> + const char *p = buf;
> +
> + p = decode_address_to_semicolon (start_addrp, p);
> + p = decode_address_to_semicolon (search_space_lenp, p);
> + packet_len -= p - buf;
> + *pattern_lenp = remote_unescape_input ((const gdb_byte *) p, packet_len,
> + pattern, packet_len);
> + return 0;
> +}
> +
> /* Ask GDB for the address of NAME, and return it in ADDRP if found.
> Returns 1 if the symbol is found, 0 if it is not, -1 on error. */
>
> Index: gdb/gdbserver/server.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
> retrieving revision 1.62
> diff -u -p -u -p -r1.62 server.c
> --- ./gdb/gdbserver/server.c 1 Jan 2008 22:53:14 -0000 1.62
> +++ ./gdb/gdbserver/server.c 15 Jan 2008 21:53:25 -0000
> @@ -254,6 +254,157 @@ monitor_show_help (void)
> monitor_output (" Enable remote protocol debugging messages\n");
> }
>
> +/* Subroutine of handle_search_memory to simplify it. */
> +/* ??? Copied from simple_search_memory. Combine? */
> +
> +static int
> +handle_search_memory_1 (CORE_ADDR start_addr, CORE_ADDR search_space_len,
> + gdb_byte *pattern, unsigned pattern_len,
> + gdb_byte *search_buf,
> + unsigned chunk_size, unsigned search_buf_size,
> + CORE_ADDR *found_addrp)
> +{
> + /* Prime the search buffer. */
> +
> + if (read_inferior_memory (start_addr, search_buf, search_buf_size) != 0)
> + {
> + warning ("unable to access target memory at 0x%lx, halting search",
> + (long) start_addr);
> + return -1;
> + }
> +
> + /* Perform the search.
> +
> + The loop is kept simple by allocating [N + pattern-length - 1] bytes.
> + When we've scanned N bytes we copy the trailing bytes to the start and
> + read in another N bytes. */
> +
> + while (search_space_len >= pattern_len)
> + {
> + gdb_byte *found_ptr;
> + unsigned nr_search_bytes = (search_space_len < search_buf_size
> + ? search_space_len
> + : search_buf_size);
> +
> + found_ptr = lmemmem (search_buf, nr_search_bytes,
> + pattern, pattern_len);
> +
> + if (found_ptr != NULL)
> + {
> + CORE_ADDR found_addr = start_addr + (found_ptr - search_buf);
> + *found_addrp = found_addr;
> + return 1;
> + }
> +
> + /* Not found in this chunk, skip to next chunk. */
> +
> + /* Don't let search_space_len wrap here, it's unsigned. */
> + if (search_space_len >= chunk_size)
> + search_space_len -= chunk_size;
> + else
> + search_space_len = 0;
> +
> + if (search_space_len >= pattern_len)
> + {
> + unsigned keep_len = search_buf_size - chunk_size;
> + CORE_ADDR read_addr = start_addr + keep_len;
> + int nr_to_read;
> +
> + /* Copy the trailing part of the previous iteration to the front
> + of the buffer for the next iteration. */
> + memcpy (search_buf, search_buf + chunk_size, keep_len);
> +
> + nr_to_read = (search_space_len - keep_len < chunk_size
> + ? search_space_len - keep_len
> + : chunk_size);
> +
> + if (read_inferior_memory (read_addr, search_buf + keep_len,
> + nr_to_read) != 0)
> + {
> + warning ("unable to access target memory at 0x%lx, halting search",
> + (long) read_addr);
> + return -1;
> + }
> +
> + start_addr += chunk_size;
> + }
> + }
> +
> + /* Not found. */
> +
> + return 0;
> +}
> +
> +/* Handle qSearch:memory packets. */
> +/* ??? Copied from simple_search_memory. Combine? */
> +
> +static void
> +handle_search_memory (char *own_buf, int packet_len)
> +{
> + CORE_ADDR start_addr;
> + CORE_ADDR search_space_len;
> + gdb_byte *pattern;
> + unsigned int pattern_len;
> + /* ??? tunable?
> + NOTE: also defined in find.c testcase. */
> +#define SEARCH_CHUNK_SIZE 16000
> + const unsigned chunk_size = SEARCH_CHUNK_SIZE;
> + /* Buffer to hold memory contents for searching. */
> + gdb_byte *search_buf;
> + unsigned search_buf_size;
> + int found;
> + CORE_ADDR found_addr;
> + int cmd_name_len = sizeof ("qSearch:memory:") - 1;
> +
> + pattern = malloc (packet_len);
> + if (pattern == NULL)
> + {
> + error ("unable to allocate memory to perform the search");
> + strcpy (own_buf, "E00");
> + return;
> + }
> + if (decode_search_memory_packet (own_buf + cmd_name_len,
> + packet_len - cmd_name_len,
> + &start_addr, &search_space_len,
> + pattern, &pattern_len) < 0)
> + {
> + free (pattern);
> + error ("error in parsing qSearch:memory packet");
> + strcpy (own_buf, "E00");
> + return;
> + }
> +
> + search_buf_size = chunk_size + pattern_len - 1;
> +
> + /* No point in trying to allocate a buffer larger than the search space. */
> + if (search_space_len < search_buf_size)
> + search_buf_size = search_space_len;
> +
> + search_buf = malloc (search_buf_size);
> + if (search_buf == NULL)
> + {
> + free (pattern);
> + error ("unable to allocate memory to perform the search");
> + strcpy (own_buf, "E00");
> + return;
> + }
> +
> + found = handle_search_memory_1 (start_addr, search_space_len,
> + pattern, pattern_len,
> + search_buf, chunk_size, search_buf_size,
> + &found_addr);
> +
> + if (found > 0)
> + sprintf (own_buf, "1,%lx", (long) found_addr);
> + else if (found == 0)
> + strcpy (own_buf, "0");
> + else
> + strcpy (own_buf, "E00");
> +
> + free (search_buf);
> + free (pattern);
> +}
> +
> /* Handle all of the extended 'q' packets. */
> void
> handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
> @@ -533,6 +684,10 @@ handle_query (char *own_buf, int packet_
> supports qXfer:libraries:read, so always report it. */
> strcat (own_buf, ";qXfer:libraries:read+");
>
> + /* Do the searching here, so we don't have to send memory back to gdb
> + to be searched. */
> + strcat (own_buf, ";qSearch:memory+");
> +
> if (the_target->read_auxv != NULL)
> strcat (own_buf, ";qXfer:auxv:read+");
>
> @@ -653,6 +808,12 @@ handle_query (char *own_buf, int packet_
> return;
> }
>
> + if (strncmp ("qSearch:memory:", own_buf, sizeof ("qSearch:memory:") - 1) == 0)
> + {
> + handle_search_memory (own_buf, packet_len);
> + return;
> + }
> +
> /* Otherwise we didn't know what packet it was. Say we didn't
> understand it. */
> own_buf[0] = 0;
> Index: gdb/gdbserver/server.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/server.h,v
> retrieving revision 1.39
> diff -u -p -u -p -r1.39 server.h
> --- ./gdb/gdbserver/server.h 1 Jan 2008 22:53:14 -0000 1.39
> +++ ./gdb/gdbserver/server.h 15 Jan 2008 21:53:25 -0000
> @@ -192,6 +192,10 @@ int decode_X_packet (char *from, int pac
> int decode_xfer_write (char *buf, int packet_len, char **annex,
> CORE_ADDR *offset, unsigned int *len,
> unsigned char *data);
> +int decode_search_memory_packet (const char *buf, int packet_len,
> + CORE_ADDR *start_addrp,
> + CORE_ADDR *search_space_lenp,
> + gdb_byte *pattern, unsigned int *pattern_lenp);
>
> int unhexify (char *bin, const char *hex, int count);
> int hexify (char *hex, const char *bin, int count);
> @@ -218,6 +222,10 @@ void error (const char *string,...) ATTR
> void fatal (const char *string,...) ATTR_NORETURN ATTR_FORMAT (printf, 1, 2);
> void warning (const char *string,...) ATTR_FORMAT (printf, 1, 2);
>
> +/* Functions from lmemmem.c */
> +
> +void *lmemmem (const void *, size_t, const void *, size_t);
> +
> /* Functions from the register cache definition. */
>
> void init_registers (void);
> Index: gdb/testsuite/gdb.base/find.c
> ===================================================================
> RCS file: gdb/testsuite/gdb.base/find.c
> diff -N gdb/testsuite/gdb.base/find.c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ ./gdb/testsuite/gdb.base/find.c 15 Jan 2008 21:53:25 -0000
> @@ -0,0 +1,62 @@
> +/* Testcase for the find command.
> + This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2008 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 */
> +
> +#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;
> +}
> Index: gdb/testsuite/gdb.base/find.exp
> ===================================================================
> RCS file: gdb/testsuite/gdb.base/find.exp
> diff -N gdb/testsuite/gdb.base/find.exp
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ ./gdb/testsuite/gdb.base/find.exp 15 Jan 2008 21:53:25 -0000
> @@ -0,0 +1,165 @@
> +# Copyright 2008 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@prep.ai.mit.edu
> +
> +# This tests the find command.
> +
> +if $tracelevel then {
> + strace $tracelevel
> +}
> +
> +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 "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 history_prefix {[$][0-9]* = }
> +set newline {[\r\n]*}
> +set one_pattern_found "${newline}1 pattern found"
> +set two_patterns_found "${newline}2 patterns found"
> +
> +# Test string pattern.
> +
> +gdb_test "set *(int32_t*) &int8_search_buf\[10\] = 0x61616161" "" ""
> +
> +gdb_test "find &int8_search_buf\[0\], @sizeof(int8_search_buf), \"aaa\"" \
> + "${hex_number}.*<int8_search_buf\\+10>${newline}${hex_number}.*<int8_search_buf\\+11>${two_patterns_found}" \
> + "find string pattern"
> +
> +# Test max-count, and $numfound.
> +
> +gdb_test "find /1 &int8_search_buf\[0\], @sizeof(int8_search_buf), \"aaa\"" \
> + "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
> + "max-count first"
> +
> +gdb_test "print \$numfound" \
> + "${history_prefix}1" \
> + "numfound"
> +
> +# Test max-count with size-char.
> +# They can be specified in either order.
> +
> +gdb_test "find /1 /b &int8_search_buf\[0\], @sizeof(int8_search_buf), 0x61, 0x61, 0x61" \
> + "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
> + "max-count first"
> +
> +gdb_test "find /b /1 &int8_search_buf\[0\], @sizeof(int8_search_buf), 0x61, 0x61, 0x61" \
> + "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
> + "max-count second"
> +
> +# Test specifying end address.
> +
> +gdb_test "find /b &int8_search_buf\[0\], &int8_search_buf\[0\]+sizeof(int8_search_buf), 0x61, 0x61, 0x61, 0x61" \
> + "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
> + "find byte pattern with end address"
> +
> +# Test 16-bit pattern.
> +
> +gdb_test "set int16_search_buf\[10\] = 0x1234" "" ""
> +
> +gdb_test "find /h &int16_search_buf\[0\], @sizeof(int16_search_buf), 0x1234" \
> + "${hex_number}.*<int16_search_buf\\+20>${one_pattern_found}" \
> + "find 16-bit pattern"
> +
> +gdb_test "find &int16_search_buf\[0\], @sizeof(int16_search_buf), (int16_t) 0x1234" \
> + "${hex_number}.*<int16_search_buf\\+20>${one_pattern_found}" \
> + "find 16-bit pattern"
> +
> +# Test 32-bit pattern.
> +
> +gdb_test "set int32_search_buf\[10\] = 0x12345678" "" ""
> +
> +gdb_test "find &int32_search_buf\[0\], @sizeof(int32_search_buf), (int32_t) 0x12345678" \
> + "${hex_number}.*<int32_search_buf\\+40>${one_pattern_found}" \
> + "find 32-bit pattern"
> +
> +gdb_test "find /w &int32_search_buf\[0\], @sizeof(int32_search_buf), 0x12345678" \
> + "${hex_number}.*<int32_search_buf\\+40>${one_pattern_found}" \
> + "find 32-bit pattern"
> +
> +# Test 64-bit pattern.
> +
> +gdb_test "set int64_search_buf\[10\] = 0xfedcba9876543210LL" "" ""
> +
> +gdb_test "find &int64_search_buf\[0\], @sizeof(int64_search_buf), (int64_t) 0xfedcba9876543210LL" \
> + "${hex_number}.*<int64_search_buf\\+80>${one_pattern_found}" \
> + "find 64-bit pattern"
> +
> +gdb_test "find /g &int64_search_buf\[0\], @sizeof(int64_search_buf), 0xfedcba9876543210LL" \
> + "${hex_number}.*<int64_search_buf\\+80>${one_pattern_found}" \
> + "find 64-bit 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 "find &search_buf\[0\], @search_buf_size, (int8_t) 0x62, (int16_t) 0x6363, (int32_t) 0x64646464" \
> + "${hex_number}${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 ;# see findcmd.c
> +
> +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 "find /w search_buf, @search_buf_size, 0x12345678" \
> + "${hex_number}${newline}${hex_number}${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 "find /w search_buf, @search_buf_size, 0xfdb97531" \
> + "${hex_number}${one_pattern_found}" \
> + "find pattern straddling chunk boundary"
> +}
>
>
>
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: RFC: new command to search memory
2008-01-28 18:15 ` Doug Evans
@ 2008-01-28 20:26 ` Eli Zaretskii
2008-01-30 18:10 ` Doug Evans
0 siblings, 1 reply; 5+ messages in thread
From: Eli Zaretskii @ 2008-01-28 20:26 UTC (permalink / raw)
To: Doug Evans; +Cc: gdb-patches, pkoning
> Date: Mon, 28 Jan 2008 10:10:44 -0800
> From: "Doug Evans" <dje@google.com>
>
> Ping ...
Sorry, I managed to miss this somehow.
The patch for the manual is approved (assuming the code patch will be
approved), except for the following gotchas:
> +@table @code
> +
> +@kindex find
> +@item find @r{[}/@var{size}@r{]} @r{[}/@var{max_count}@r{]} @var{start_addr}, @@@var{len}, @var{val1} @r{[}, @var{val2}, ...@r{]}
> +@itemx find @r{[}/@var{size}@r{]} @r{[}/@var{max_count}@r{]} @var{start_addr}, @var{end_addr}, @var{val1} @r{[}, @var{val2}, ...@r{]}
These two lines are two long, and since they are in @code, TeX will
not wrap them, and they will overflow the page margins in print. So
please make them shorter somehow. Here's one idea:
@item find @r{[}/@var{options} @var{where} @dots{}
and then describe ``options'' and ``where'' separately.
Also, please use @dots{} instead of literal "...", the former looks
better in print.
> +@var{size} specifies how to interpret the search pattern and is
> +'b' for 8-bit values, 'h' for 16-bit values, 'w' for 32-bit values,
Please use @samp{b}, @samp{h} etc.
> +Strings may be specified for search values, quote them normally.
Is this language-dependent? If not, then ``normally'' doesn't really
cut it; please describe specifically how to quote.
> +The string value is copied into the search pattern byte by byte,
> +regardless of the endianness of the target and the size specification.
This begs the question: what about non-printable characters? are they
supported, and if so, how?
> +The address of the last value found is stored in convenience variable
> +@samp{$numfound}.
> +A count of the number of matches is stored in @samp{$_}.
Your example has this the other way around (and so does the code,
IIUC):
> +(gdb) find &mixed, @@sizeof(mixed), (char) 'c', (short) 0x1234, (int) 0x87654321
> +0x601054 <mixed.1633>
> +1 pattern found
> +(gdb) print $numfound
> +$1 = 1
> +(gdb) print $_
> +$2 = (void *) 0x601054
> +@end smallexample
> +@item qSearch:memory:@var{address};@var{length};@var{search-pattern}
> +@cindex search memory
You already have "@cindex searching memory" where you describe `find',
so this almost identical index entry in a totally different place
would be confusing: the reader will not know which entry is relevant
for them. I suggest this instead:
@cindex searching memory, in remote debugging
> +@cindex @samp{qSearch:memory} packet
> +@anchor{qSearch memory}
> +Search LENGTH bytes at ADDRESS for SEARCH-PATTERN.
> +ADDRESS and LENGTH are encoded in hex.
> +SEARCH-PATTERN is a sequence of bytes, hex encoded.
> +
> +Reply:
> +@table @samp
> +@item 0
> +The pattern was not found.
> +@item 1,address
> +The pattern was found at ADDRESS.
This should use @var{length}, @var{address}, instead of LENGTH,
ADDRESS, etc.: in lower-case and in @var.
> Index: gdb/NEWS
> ===================================================================
> RCS file: /cvs/src/src/gdb/NEWS,v
> retrieving revision 1.251
> diff -u -p -u -p -r1.251 NEWS
> --- ./gdb/NEWS 5 Jan 2008 21:50:43 -0000 1.251
> +++ ./gdb/NEWS 15 Jan 2008 21:53:23 -0000
> @@ -3,6 +3,17 @@
>
> *** Changes since GDB 6.7
>
> +* New command
> +
> +find [/size-char] [/max-count] start-address, end-address|@search-space-size,
> + val1 [, val2, ...]
> + Search memory for a sequence of bytes.
> +
> +* New remote packet
> +
> +qSearch:memory:
> + Search memory for a sequence of bytes.
> +
> * Change in command line behavior -- corefiles vs. process ids.
This is also fine.
Thanks.
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: RFC: new command to search memory
2008-01-28 20:26 ` Eli Zaretskii
@ 2008-01-30 18:10 ` Doug Evans
2008-01-30 18:33 ` Eli Zaretskii
0 siblings, 1 reply; 5+ messages in thread
From: Doug Evans @ 2008-01-30 18:10 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches, pkoning
On Jan 28, 2008 11:58 AM, Eli Zaretskii <eliz@gnu.org> wrote:
> > +@table @code
> > +
> > +@kindex find
> > +@item find @r{[}/@var{size}@r{]} @r{[}/@var{max_count}@r{]} @var{start_addr}, @@@var{len}, @var{val1} @r{[}, @var{val2}, ...@r{]}
> > +@itemx find @r{[}/@var{size}@r{]} @r{[}/@var{max_count}@r{]} @var{start_addr}, @var{end_addr}, @var{val1} @r{[}, @var{val2}, ...@r{]}
>
> These two lines are two long, and since they are in @code, TeX will
> not wrap them, and they will overflow the page margins in print. So
> please make them shorter somehow. Here's one idea:
>
> @item find @r{[}/@var{options} @var{where} @dots{}
>
> and then describe ``options'' and ``where'' separately.
>
> Also, please use @dots{} instead of literal "...", the former looks
> better in print.
>
> > +@var{size} specifies how to interpret the search pattern and is
> > +'b' for 8-bit values, 'h' for 16-bit values, 'w' for 32-bit values,
>
> Please use @samp{b}, @samp{h} etc.
Righto.
> +Strings may be specified for search values, quote them normally.
>
> Is this language-dependent? If not, then ``normally'' doesn't really
> cut it; please describe specifically how to quote.
The string is not language dependent. I guess it could be, but I'm
not sure there's sufficient value here. Consider the printf command.
One thing that might be useful is to merge the respective string
parsing in each command (assuming they take equivalent strings).
> > +The string value is copied into the search pattern byte by byte,
> > +regardless of the endianness of the target and the size specification.
>
> This begs the question: what about non-printable characters? are they
> supported, and if so, how?
The string parser uses parse_escape so they can be embedded in the
string. One can also do it this way:
find /b mumble, "search string ", 1, 127, 253, " with embedded
non-printable characters"
find mumble, "search string ", (char) 1, (char) 127, (char) 253, "with
embedded non-printable characters"
I can update the docs on what the string may contain.
> > +The address of the last value found is stored in convenience variable
> > +@samp{$numfound}.
> > +A count of the number of matches is stored in @samp{$_}.
>
> Your example has this the other way around (and so does the code,
> IIUC):
Oops, thanks for catching that.
> > +@item qSearch:memory:@var{address};@var{length};@var{search-pattern}
> > +@cindex search memory
>
> You already have "@cindex searching memory" where you describe `find',
> so this almost identical index entry in a totally different place
> would be confusing: the reader will not know which entry is relevant
> for them. I suggest this instead:
>
> @cindex searching memory, in remote debugging
>
> > +@cindex @samp{qSearch:memory} packet
> > +@anchor{qSearch memory}
> > +Search LENGTH bytes at ADDRESS for SEARCH-PATTERN.
> > +ADDRESS and LENGTH are encoded in hex.
> > +SEARCH-PATTERN is a sequence of bytes, hex encoded.
> > +
> > +Reply:
> > +@table @samp
> > +@item 0
> > +The pattern was not found.
> > +@item 1,address
> > +The pattern was found at ADDRESS.
>
> This should use @var{length}, @var{address}, instead of LENGTH,
> ADDRESS, etc.: in lower-case and in @var.
Righto.
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: RFC: new command to search memory
2008-01-30 18:10 ` Doug Evans
@ 2008-01-30 18:33 ` Eli Zaretskii
0 siblings, 0 replies; 5+ messages in thread
From: Eli Zaretskii @ 2008-01-30 18:33 UTC (permalink / raw)
To: Doug Evans; +Cc: gdb-patches, pkoning
> Date: Wed, 30 Jan 2008 10:06:02 -0800
> From: "Doug Evans" <dje@google.com>
> Cc: gdb-patches@sourceware.org, pkoning@equallogic.com
>
> > +Strings may be specified for search values, quote them normally.
> >
> > Is this language-dependent? If not, then ``normally'' doesn't really
> > cut it; please describe specifically how to quote.
>
>
> The string is not language dependent. I guess it could be, but I'm
> not sure there's sufficient value here.
I'm not saying that it should, just that if it's something specific to
GDB, the manual should spell it out.
> I can update the docs on what the string may contain.
Yes, please.
Thanks.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2008-01-30 18:27 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-01-15 22:15 RFC: new command to search memory Doug Evans
2008-01-28 18:15 ` Doug Evans
2008-01-28 20:26 ` Eli Zaretskii
2008-01-30 18:10 ` Doug Evans
2008-01-30 18:33 ` Eli Zaretskii
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox