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


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

Re: RFC: new command to search memory


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 (&current_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 (&current_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"
> +}
>
>
>


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