* [RFA] new command to search memory
@ 2008-02-14 2:20 Doug Evans
2008-02-14 19:54 ` Eli Zaretskii
2008-02-26 2:31 ` Daniel Jacobowitz
0 siblings, 2 replies; 21+ messages in thread
From: Doug Evans @ 2008-02-14 2:20 UTC (permalink / raw)
To: gdb-patches, pkoning
I didn't get a response to the non-doc portions of this patch.
[Eli, thanks for the doc review, I made the suggested changes,
though I went a different route in shortening the length of the
line specifying the find command syntax. The end result is still
rather short.]
The libiberty patches need to go through gcc-patches, but I'm guessing
there's no point in bothering them until this patch is approved
at least in principal.
What can I do to help make progress here?
2008-02-13 Doug Evans <dje@google.com>
* 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 14 Feb 2008 02:03:40 -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 14 Feb 2008 02:03:40 -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 14 Feb 2008 02:03:40 -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 14 Feb 2008 02:03:40 -0000
@@ -5062,6 +5062,7 @@ vars="sys_errlist sys_nerr sys_siglist"
checkfuncs="getrusage on_exit psignal strerror strsignal sysconf times sbrk gettimeofday"
checkfuncs="$checkfuncs realpath canonicalize_file_name pstat_getstatic pstat_getdynamic sysmp"
checkfuncs="$checkfuncs getsysinfo table sysctl wait3 wait4 __fsetlocking"
+checkfuncs="$checkfuncs memmem"
# These are neither executed nor required, but they help keep
# autoheader happy without adding a bunch of text to acconfig.h.
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 14 Feb 2008 02:03:41 -0000
@@ -356,6 +356,7 @@ vars="sys_errlist sys_nerr sys_siglist"
checkfuncs="getrusage on_exit psignal strerror strsignal sysconf times sbrk gettimeofday"
checkfuncs="$checkfuncs realpath canonicalize_file_name pstat_getstatic pstat_getdynamic sysmp"
checkfuncs="$checkfuncs getsysinfo table sysctl wait3 wait4 __fsetlocking"
+checkfuncs="$checkfuncs memmem"
# These are neither executed nor required, but they help keep
# autoheader happy without adding a bunch of text to acconfig.h.
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 14 Feb 2008 02:03:41 -0000
@@ -0,0 +1,58 @@
+/* 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
+#ifdef HAVE_STRING_H
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE /* memmem */
+#endif
+#include <string.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.982
diff -u -p -u -p -r1.982 Makefile.in
--- gdb/Makefile.in 11 Feb 2008 21:58:41 -0000 1.982
+++ gdb/Makefile.in 14 Feb 2008 02:03:41 -0000
@@ -600,9 +600,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 \
@@ -1043,6 +1042,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 \
@@ -2101,6 +2101,8 @@ 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) $(gdb_string_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.257
diff -u -p -u -p -r1.257 NEWS
--- gdb/NEWS 11 Feb 2008 21:58:41 -0000 1.257
+++ gdb/NEWS 14 Feb 2008 02:03:41 -0000
@@ -64,6 +64,10 @@ stored in two consecutive float register
* New commands
+find [/size-char] [/max-count] start-address, end-address|@search-space-size,
+ val1 [, val2, ...]
+ Search memory for a sequence of bytes.
+
set print frame-arguments (all|scalars|none)
show print frame-arguments
The value of this variable can be changed to control which argument
@@ -83,6 +87,9 @@ remote delete
* New remote packets
+qSearch:memory:
+ Search memory for a sequence of bytes.
+
vFile:open:
vFile:close:
vFile:pread:
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 14 Feb 2008 02:03:41 -0000
@@ -0,0 +1,399 @@
+/* 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.
+ They may be specified in either order, together or separately. */
+
+ while (*s == '/')
+ {
+ ++s;
+
+ while (*s != '\0' && *s != '/' && !isspace (*s))
+ {
+ if (isdigit (*s))
+ {
+ max_count = atoi (s);
+ while (isdigit (*s))
+ ++s;
+ continue;
+ }
+
+ switch (*s)
+ {
+ case 'b':
+ case 'h':
+ case 'w':
+ case 'g':
+ size = *s++;
+ break;
+ default:
+ 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.278
diff -u -p -u -p -r1.278 remote.c
--- gdb/remote.c 30 Jan 2008 00:51:49 -0000 1.278
+++ gdb/remote.c 14 Feb 2008 02:03:41 -0000
@@ -933,6 +933,7 @@ enum {
PACKET_qGetTLSAddr,
PACKET_qSupported,
PACKET_QPassSignals,
+ PACKET_qSearch_memory,
PACKET_vAttach,
PACKET_vRun,
PACKET_MAX
@@ -2459,6 +2460,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
@@ -6198,6 +6201,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)
@@ -7253,6 +7331,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
@@ -7388,6 +7467,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
@@ -7648,6 +7728,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.154
diff -u -p -u -p -r1.154 target.c
--- gdb/target.c 25 Jan 2008 00:09:49 -0000 1.154
+++ gdb/target.c 14 Feb 2008 02:03:41 -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 14 Feb 2008 02:03:42 -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.467
diff -u -p -u -p -r1.467 gdb.texinfo
--- gdb/doc/gdb.texinfo 3 Feb 2008 18:55:27 -0000 1.467
+++ gdb/doc/gdb.texinfo 14 Feb 2008 02:03:43 -0000
@@ -5543,6 +5543,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
@@ -7521,6 +7522,90 @@ 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{sn}@r{]} @var{start_addr}, @@@var{len}, @var{val1} @r{[}, @var{val2}, @dots{}@r{]}
+@itemx find @r{[}/@var{sn}@r{]} @var{start_addr}, @var{end_addr}, @var{val1} @r{[}, @var{val2}, @dots{}@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.
+@end table
+
+@var{s} and @var{n} are optional parameters.
+They may be specified in either order, apart or together.
+
+@table @r
+@item @var{s}, search query size
+The size of each search query value.
+
+@table @code
+@item b
+Bytes.
+@item h
+Halfwords (two bytes).
+@item w
+Words (four bytes).
+@item g
+Giant words (eight bytes).
+@end table
+
+If the value size is not specified, it is taken from the
+value's type. This is useful when one wants to specify the search
+pattern as a mixture of types.
+
+@item @var{n}, maximum number of finds
+The maximum number of finds to print. The default is to print all finds.
+@end table
+
+Strings may be specified for search values, quote them with double-quotes
+(@code{"}). The string value is copied into the search pattern byte by byte,
+regardless of the endianness of the target and the size specification.
+
+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{$_}.
+A count of the number of matches is stored in @samp{$numfound}.
+
+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 /b1 &hello[0], @@sizeof(hello), 'h', 0x65, 'l'
+0x601048 <hello.1628>
+1 pattern 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
@@ -13332,6 +13417,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
@@ -24330,6 +24419,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 searching memory, in remote debugging
+@cindex @samp{qSearch:memory} packet
+@anchor{qSearch memory}
+Search @var{length} bytes at @var{address} for @var{search-pattern}.
+@var{address} and @var{length} are encoded in hex.
+@var{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 @var{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
@@ -24471,6 +24580,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:
@@ -24515,6 +24629,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.54
diff -u -p -u -p -r1.54 Makefile.in
--- gdb/gdbserver/Makefile.in 11 Feb 2008 22:00:31 -0000 1.54
+++ gdb/gdbserver/Makefile.in 14 Feb 2008 02:03:43 -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 \
@@ -141,7 +142,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@
@@ -294,6 +295,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 14 Feb 2008 02:03:43 -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.32
diff -u -p -u -p -r1.32 configure
--- gdb/gdbserver/configure 1 Feb 2008 00:08:25 -0000 1.32
+++ gdb/gdbserver/configure 14 Feb 2008 02:03:43 -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.20
diff -u -p -u -p -r1.20 configure.ac
--- gdb/gdbserver/configure.ac 1 Feb 2008 00:08:25 -0000 1.20
+++ gdb/gdbserver/configure.ac 14 Feb 2008 02:03:43 -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 14 Feb 2008 02:03:43 -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.54
diff -u -p -u -p -r1.54 remote-utils.c
--- gdb/gdbserver/remote-utils.c 30 Jan 2008 00:51:50 -0000 1.54
+++ gdb/gdbserver/remote-utils.c 14 Feb 2008 02:03:43 -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.63
diff -u -p -u -p -r1.63 server.c
--- gdb/gdbserver/server.c 30 Jan 2008 00:51:50 -0000 1.63
+++ gdb/gdbserver/server.c 14 Feb 2008 02:03:43 -0000
@@ -270,6 +270,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);
+}
+
#define require_running(BUF) \
if (!target_running ()) \
{ \
@@ -568,6 +719,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+");
@@ -692,6 +847,13 @@ handle_query (char *own_buf, int packet_
return;
}
+ if (strncmp ("qSearch:memory:", own_buf, sizeof ("qSearch:memory:") - 1) == 0)
+ {
+ require_running (own_buf);
+ 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.40
diff -u -p -u -p -r1.40 server.h
--- gdb/gdbserver/server.h 1 Feb 2008 00:08:25 -0000 1.40
+++ gdb/gdbserver/server.h 14 Feb 2008 02:03:44 -0000
@@ -195,6 +195,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);
@@ -221,6 +225,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 14 Feb 2008 02:03:47 -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 14 Feb 2008 02:03:47 -0000
@@ -0,0 +1,191 @@
+# 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 pattern_not_found "${newline}pattern not found"
+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 not finding pattern because search range too small, with
+# potential find at the edge of the range.
+
+gdb_test "find &int8_search_buf\[0\], @10+3, \"aaaa\"" \
+ "${pattern_not_found}" \
+ "pattern not found at end of range"
+
+# Increase the search range by 1 and we should find the pattern.
+
+gdb_test "find &int8_search_buf\[0\], @10+3+1, \"aaaa\"" \
+ "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
+ "pattern found at end of range"
+
+# 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"
+
+gdb_test "print \$_" \
+ "${history_prefix}.*${hex_number}" \
+ "\$_"
+
+gdb_test "print \$numfound" \
+ "${history_prefix}1" \
+ "\$numfound"
+
+# Test max-count with size-char.
+# They can be specified in either order.
+
+gdb_test "find /1b &int8_search_buf\[0\], @sizeof(int8_search_buf), 0x61, 0x61, 0x61" \
+ "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
+ "size,max-count, /1b"
+
+gdb_test "find /b1 &int8_search_buf\[0\], @sizeof(int8_search_buf), 0x61, 0x61, 0x61" \
+ "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
+ "size,max-count, /b1"
+
+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}" \
+ "size,max-count, /b/1"
+
+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}" \
+ "size,max-count, /1/b"
+
+# 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\], @100, (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] 21+ messages in thread
* Re: [RFA] new command to search memory
2008-02-14 2:20 [RFA] new command to search memory Doug Evans
@ 2008-02-14 19:54 ` Eli Zaretskii
2008-02-14 22:52 ` Doug Evans
2008-02-26 2:31 ` Daniel Jacobowitz
1 sibling, 1 reply; 21+ messages in thread
From: Eli Zaretskii @ 2008-02-14 19:54 UTC (permalink / raw)
To: Doug Evans; +Cc: gdb-patches, pkoning
> Date: Wed, 13 Feb 2008 18:19:15 -0800 (PST)
> From: dje@google.com (Doug Evans)
>
> I didn't get a response to the non-doc portions of this patch.
> [Eli, thanks for the doc review, I made the suggested changes,
> though I went a different route in shortening the length of the
> line specifying the find command syntax. The end result is still
> rather short.]
You mean, rather long...
The patch is okay with me, but could you (or someone else) please see
whether these two long lines
> +@item find @r{[}/@var{sn}@r{]} @var{start_addr}, @@@var{len}, @var{val1} @r{[}, @var{val2}, @dots{}@r{]}
> +@itemx find @r{[}/@var{sn}@r{]} @var{start_addr}, @var{end_addr}, @var{val1} @r{[}, @var{val2}, @dots{}@r{]}
survive the typesetting for the printed manual (either by TeX or
pdftex) without overflowing the page margin? I'm afraid they will
overflow, since the items of this table are typeset with @code, and
@code specifies a chunk of monospaced font that cannot be broken
between lines.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [RFA] new command to search memory
2008-02-14 19:54 ` Eli Zaretskii
@ 2008-02-14 22:52 ` Doug Evans
2008-02-15 8:28 ` Eli Zaretskii
0 siblings, 1 reply; 21+ messages in thread
From: Doug Evans @ 2008-02-14 22:52 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
On Thu, Feb 14, 2008 at 11:53 AM, Eli Zaretskii <eliz@gnu.org> wrote:
> > Date: Wed, 13 Feb 2008 18:19:15 -0800 (PST)
> > From: dje@google.com (Doug Evans)
>
> >
> > I didn't get a response to the non-doc portions of this patch.
> > [Eli, thanks for the doc review, I made the suggested changes,
> > though I went a different route in shortening the length of the
> > line specifying the find command syntax. The end result is still
> > rather short.]
>
> You mean, rather long...
>
> The patch is okay with me, but could you (or someone else) please see
> whether these two long lines
>
>
> > +@item find @r{[}/@var{sn}@r{]} @var{start_addr}, @@@var{len}, @var{val1} @r{[}, @var{val2}, @dots{}@r{]}
> > +@itemx find @r{[}/@var{sn}@r{]} @var{start_addr}, @var{end_addr}, @var{val1} @r{[}, @var{val2}, @dots{}@r{]}
>
> survive the typesetting for the printed manual (either by TeX or
> pdftex) without overflowing the page margin? I'm afraid they will
> overflow, since the items of this table are typeset with @code, and
> @code specifies a chunk of monospaced font that cannot be broken
> between lines.
Is looking at gdb.pdf (created with cd doc && make gdb.pdf) sufficient?
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [RFA] new command to search memory
2008-02-14 22:52 ` Doug Evans
@ 2008-02-15 8:28 ` Eli Zaretskii
2008-02-16 5:39 ` Doug Evans
0 siblings, 1 reply; 21+ messages in thread
From: Eli Zaretskii @ 2008-02-15 8:28 UTC (permalink / raw)
To: Doug Evans; +Cc: gdb-patches
> Date: Thu, 14 Feb 2008 14:51:40 -0800
> From: "Doug Evans" <dje@google.com>
> Cc: gdb-patches@sourceware.org
>
> On Thu, Feb 14, 2008 at 11:53 AM, Eli Zaretskii <eliz@gnu.org> wrote:
> > > Date: Wed, 13 Feb 2008 18:19:15 -0800 (PST)
> > > From: dje@google.com (Doug Evans)
> >
> > >
> > > I didn't get a response to the non-doc portions of this patch.
> > > [Eli, thanks for the doc review, I made the suggested changes,
> > > though I went a different route in shortening the length of the
> > > line specifying the find command syntax. The end result is still
> > > rather short.]
> >
> > You mean, rather long...
> >
> > The patch is okay with me, but could you (or someone else) please see
> > whether these two long lines
> >
> >
> > > +@item find @r{[}/@var{sn}@r{]} @var{start_addr}, @@@var{len}, @var{val1} @r{[}, @var{val2}, @dots{}@r{]}
> > > +@itemx find @r{[}/@var{sn}@r{]} @var{start_addr}, @var{end_addr}, @var{val1} @r{[}, @var{val2}, @dots{}@r{]}
> >
> > survive the typesetting for the printed manual (either by TeX or
> > pdftex) without overflowing the page margin? I'm afraid they will
> > overflow, since the items of this table are typeset with @code, and
> > @code specifies a chunk of monospaced font that cannot be broken
> > between lines.
>
> Is looking at gdb.pdf (created with cd doc && make gdb.pdf) sufficient?
Yes, thanks.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [RFA] new command to search memory
2008-02-15 8:28 ` Eli Zaretskii
@ 2008-02-16 5:39 ` Doug Evans
2008-02-16 13:33 ` Eli Zaretskii
0 siblings, 1 reply; 21+ messages in thread
From: Doug Evans @ 2008-02-16 5:39 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
On Feb 15, 2008 12:27 AM, Eli Zaretskii <eliz@gnu.org> wrote:
> > Is looking at gdb.pdf (created with cd doc && make gdb.pdf) sufficient?
>
> Yes, thanks.
Hi. I sent you a screenshot of the relevant page in gdb.pdf created
with @smallbook.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [RFA] new command to search memory
2008-02-16 5:39 ` Doug Evans
@ 2008-02-16 13:33 ` Eli Zaretskii
0 siblings, 0 replies; 21+ messages in thread
From: Eli Zaretskii @ 2008-02-16 13:33 UTC (permalink / raw)
To: Doug Evans; +Cc: gdb-patches
> Date: Fri, 15 Feb 2008 21:38:56 -0800
> From: "Doug Evans" <dje@google.com>
> Cc: gdb-patches@sourceware.org
>
> On Feb 15, 2008 12:27 AM, Eli Zaretskii <eliz@gnu.org> wrote:
> > > Is looking at gdb.pdf (created with cd doc && make gdb.pdf) sufficient?
> >
> > Yes, thanks.
>
> Hi. I sent you a screenshot of the relevant page in gdb.pdf created
> with @smallbook.
Thanks, it typesetted just fine.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [RFA] new command to search memory
2008-02-14 2:20 [RFA] new command to search memory Doug Evans
2008-02-14 19:54 ` Eli Zaretskii
@ 2008-02-26 2:31 ` Daniel Jacobowitz
2008-02-29 3:13 ` Doug Evans
2008-04-09 21:06 ` Doug Evans
1 sibling, 2 replies; 21+ messages in thread
From: Daniel Jacobowitz @ 2008-02-26 2:31 UTC (permalink / raw)
To: Doug Evans; +Cc: gdb-patches, pkoning
On Wed, Feb 13, 2008 at 06:19:15PM -0800, Doug Evans wrote:
> I didn't get a response to the non-doc portions of this patch.
Sorry for the delay on this, Doug. To be honest, I was hoping someone
else would comment on the interface. I think it's a bit confusing and
also somewhat inconsistent among GDB commands. But we do need the
feature, and you've obviously spent a while thinking about it, and
you're the one who did all the work, and the GDB CLI commands are
plenty inconsistent already. So I'll just get used to it :-)
The find command looks like:
find [/[s][n]] START_ADDR, [@LEN | END_ADDR], VAL [, VAL]...
Stopping values at a comma is not much like other GDB commands.
On the other hand, there's priort art (the printf command), and
there's parser support (parse_to_comma_and_eval, which you used
and I totally did not know was there before today), and the parsing is
reasonably intuitive. So we've got commas.
The slashed arguments work analagously to x and display, which is
nice. Should the default count should be one instead of infinity?
I suppose having it default to infinity is nice, since we don't
have to invent a syntax for infinity that way.
What do you think of "+" instead of "@" to distinguish lengths? "find
&hello[0] +0x100".
And for the search string, I guess the main reason that you didn't
use the normal language parsers was to avoid the malloc call:
> + /* If we see a string, parse it ourselves rather than the normal
> + handling of downloading it to target memory. */
Can we use the language parsers, for consistency with other GDB
commands, if we fix this? Which I happen to have a patch for. I'll
dust it off and post it. Then, someday, we can get wchar_t strings
here for free (I hope).
After that, we can (and should IMO) document in the manual that all
of the arguments to find are source language expressions.
I noticed that the current command is implemented all in one function,
which goes from a CLI string to output. I'm sure we'll want a GDB/MI
command for this, so it would be helpful if it was broken out into
two functions. OTOH that's easy to do later so don't worry about it,
let's get it in the CLI first.
I don't have a ton to say about the code itself, except that you
forgot to format some of your comments as sentences. Similarly
for error messages, though I can't remember what our convention
is for that; Eli may know better.
find_command is big, and might benefit from a couple of smaller
documented functions. The list of local variables is a full page.
> +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);
Prototypes shouldn't have the function name in the first column, but
fortunately you don't even need these.
default_search_memory was similar, and some of the others in headers.
> + /* If endian is unknown use big endian.
> + ??? Is there an established convention for what to pick? */
> + bfd_boolean big_p = endian != BFD_ENDIAN_LITTLE;
GDB should handle this elsewhere; if you get BFD_ENDIAN_UNKNOWN here
we have bigger problems. So doing it this way is fine.
> + /* 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. */
done before, you mean?
qSearch:memory does not need to be advertised for qSupported. The
rule of thumb is that things which are used to implement a user
command don't need to be, since there's no big penalty if we try them
and are told they are not supported - we'll just try another approach
and next time we'll know. That means you need to handle
PACKET_DISABLE twice, before and after sending the packet.
> @@ -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. */
I suggest doing this as a do-not-inherit, like the other new methods.
Maybe someday we'll eliminate the older style entirely.
> @@ -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,
"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
I don't think it needs to be tunable. The value doesn't matter much,
since you truncate to the size of the search space.
> +/* 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);
> +}
Please pass target_ops to to_search_memory. That lets you combine
default_search_memory and simple_search_memory, and it also lets
targets get at their own state (e.g. if the remote target needs to
know whether it's an extended target or not).
> +
> +/* 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. */
Isn't there only one call per search request now? I don't think this
is necessary.
> +If the value size is not specified, it is taken from the
> +value's type. This is useful when one wants to specify the search
> +pattern as a mixture of types.
IMO this will confuse users for constants, which have type int (or
sometimes long), so could you add a word about that? Otherwise
someone will type "find &hello[0], @100, 0x65, 0x66" and be confused
by the lack of matches.
> Index: gdb/gdbserver/server.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
> retrieving revision 1.63
> diff -u -p -u -p -r1.63 server.c
> --- gdb/gdbserver/server.c 30 Jan 2008 00:51:50 -0000 1.63
> +++ gdb/gdbserver/server.c 14 Feb 2008 02:03:43 -0000
> @@ -270,6 +270,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? */
GDB and gdbserver? No, I don't think it's a good idea any more. I
used to, but they're just not laid out right.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [RFA] new command to search memory
2008-02-26 2:31 ` Daniel Jacobowitz
@ 2008-02-29 3:13 ` Doug Evans
2008-02-29 3:58 ` Daniel Jacobowitz
2008-04-09 21:06 ` Doug Evans
1 sibling, 1 reply; 21+ messages in thread
From: Doug Evans @ 2008-02-29 3:13 UTC (permalink / raw)
To: gdb-patches
Thanks for the review.
On Mon, Feb 25, 2008 at 6:23 PM, Daniel Jacobowitz <drow@false.org> wrote:
>
> The find command looks like:
>
> find [/[s][n]] START_ADDR, [@LEN | END_ADDR], VAL [, VAL]...
>
> Stopping values at a comma is not much like other GDB commands.
> On the other hand, there's priort art (the printf command), and
> there's parser support (parse_to_comma_and_eval, which you used
> and I totally did not know was there before today), and the parsing is
> reasonably intuitive. So we've got commas.
There aren't many commands that take multiple expressions as
arguments. One needs a useful way to separate them.
> The slashed arguments work analagously to x and display, which is
> nice. Should the default count should be one instead of infinity?
> I suppose having it default to infinity is nice, since we don't
> have to invent a syntax for infinity that way.
/u or some such for "unlimited" would work I guess. I can change the
default if that's preferable.
> What do you think of "+" instead of "@" to distinguish lengths? "find
> &hello[0] +0x100".
I picked "@" because it's used, for example, in "p foo[0]@10". It's
not identical, but it seemed similar enough. "+" works too.
> And for the search string, I guess the main reason that you didn't
> use the normal language parsers was to avoid the malloc call:
>
>
> > + /* If we see a string, parse it ourselves rather than the normal
> > + handling of downloading it to target memory. */
Ya, but for completeness sake it's not just the malloc call, it's the
whole shebang. I can understand why in
(gdb) p strcmp (foo, "bar")
one wants to download "bar" to the target before calling strcmp, but
find's needs are different.
> Can we use the language parsers, for consistency with other GDB
> commands, if we fix this? Which I happen to have a patch for. I'll
> dust it off and post it. Then, someday, we can get wchar_t strings
> here for free (I hope).
Sure.
> I noticed that the current command is implemented all in one function,
> which goes from a CLI string to output. I'm sure we'll want a GDB/MI
> command for this, so it would be helpful if it was broken out into
> two functions. OTOH that's easy to do later so don't worry about it,
> let's get it in the CLI first.
ok.
> qSearch:memory does not need to be advertised for qSupported. The
> rule of thumb is that things which are used to implement a user
> command don't need to be, since there's no big penalty if we try them
> and are told they are not supported - we'll just try another approach
> and next time we'll know. That means you need to handle
> PACKET_DISABLE twice, before and after sending the packet.
I found a use for the option that goes with qSupported both for
testing and analysis. Maybe users would also find use for the choice,
but it can be tossed.
> > @@ -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. */
>
> I suggest doing this as a do-not-inherit, like the other new methods.
> Maybe someday we'll eliminate the older style entirely.
ok.
> > @@ -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,
>
> "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
>
> I don't think it needs to be tunable. The value doesn't matter much,
> since you truncate to the size of the search space.
ok.
> > +/* 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);
> > +}
>
> Please pass target_ops to to_search_memory. That lets you combine
> default_search_memory and simple_search_memory, and it also lets
> targets get at their own state (e.g. if the remote target needs to
> know whether it's an extended target or not).
ok.
> > +
> > +/* 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. */
>
> Isn't there only one call per search request now? I don't think this
> is necessary.
ok.
> > +If the value size is not specified, it is taken from the
> > +value's type. This is useful when one wants to specify the search
> > +pattern as a mixture of types.
>
> IMO this will confuse users for constants, which have type int (or
> sometimes long), so could you add a word about that? Otherwise
> someone will type "find &hello[0], @100, 0x65, 0x66" and be confused
> by the lack of matches.
Or one could default to something else, bytes or ints or some such,
and have a /t option or some such that says to use the type of the
object.
> > Index: gdb/gdbserver/server.c
> > ===================================================================
> > RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
> > retrieving revision 1.63
> > diff -u -p -u -p -r1.63 server.c
> > --- gdb/gdbserver/server.c 30 Jan 2008 00:51:50 -0000 1.63
> > +++ gdb/gdbserver/server.c 14 Feb 2008 02:03:43 -0000
> > @@ -270,6 +270,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? */
>
> GDB and gdbserver? No, I don't think it's a good idea any more. I
> used to, but they're just not laid out right.
ok.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [RFA] new command to search memory
2008-02-29 3:13 ` Doug Evans
@ 2008-02-29 3:58 ` Daniel Jacobowitz
2008-04-17 2:59 ` Doug Evans
0 siblings, 1 reply; 21+ messages in thread
From: Daniel Jacobowitz @ 2008-02-29 3:58 UTC (permalink / raw)
To: Doug Evans; +Cc: gdb-patches
On Thu, Feb 28, 2008 at 06:44:00PM -0800, Doug Evans wrote:
> > The slashed arguments work analagously to x and display, which is
> > nice. Should the default count should be one instead of infinity?
> > I suppose having it default to infinity is nice, since we don't
> > have to invent a syntax for infinity that way.
>
> /u or some such for "unlimited" would work I guess. I can change the
> default if that's preferable.
I think it's fine the way you've got it.
> > What do you think of "+" instead of "@" to distinguish lengths? "find
> > &hello[0] +0x100".
>
> I picked "@" because it's used, for example, in "p foo[0]@10". It's
> not identical, but it seemed similar enough. "+" works too.
I'd prefer +, if that works for you.
> Ya, but for completeness sake it's not just the malloc call, it's the
> whole shebang. I can understand why in
>
> (gdb) p strcmp (foo, "bar")
>
> one wants to download "bar" to the target before calling strcmp, but
> find's needs are different.
Right. I've got a patch to cover the downloading. I didn't get it
posted yet but it hasn't dropped off my list for this week either.
> > qSearch:memory does not need to be advertised for qSupported. The
> > rule of thumb is that things which are used to implement a user
> > command don't need to be, since there's no big penalty if we try them
> > and are told they are not supported - we'll just try another approach
> > and next time we'll know. That means you need to handle
> > PACKET_DISABLE twice, before and after sending the packet.
>
> I found a use for the option that goes with qSupported both for
> testing and analysis. Maybe users would also find use for the choice,
> but it can be tossed.
The option isn't actually linked to qSupported; you can add just the
option, and it will default to auto.
> > > +If the value size is not specified, it is taken from the
> > > +value's type. This is useful when one wants to specify the search
> > > +pattern as a mixture of types.
> >
> > IMO this will confuse users for constants, which have type int (or
> > sometimes long), so could you add a word about that? Otherwise
> > someone will type "find &hello[0], @100, 0x65, 0x66" and be confused
> > by the lack of matches.
>
> Or one could default to something else, bytes or ints or some such,
> and have a /t option or some such that says to use the type of the
> object.
Either way; I've no preference. The way you've got it seems fine if
we can clarify the description.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [RFA] new command to search memory
2008-02-26 2:31 ` Daniel Jacobowitz
2008-02-29 3:13 ` Doug Evans
@ 2008-04-09 21:06 ` Doug Evans
2008-05-02 15:37 ` Daniel Jacobowitz
1 sibling, 1 reply; 21+ messages in thread
From: Doug Evans @ 2008-04-09 21:06 UTC (permalink / raw)
To: gdb-patches
On Mon, Feb 25, 2008 at 7:23 PM, Daniel Jacobowitz <drow@false.org> wrote:
> And for the search string, I guess the main reason that you didn't
> use the normal language parsers was to avoid the malloc call:
>
>
> > + /* If we see a string, parse it ourselves rather than the normal
> > + handling of downloading it to target memory. */
>
> Can we use the language parsers, for consistency with other GDB
> commands, if we fix this? Which I happen to have a patch for. I'll
> dust it off and post it. Then, someday, we can get wchar_t strings
> here for free (I hope).
>
> After that, we can (and should IMO) document in the manual that all
> of the arguments to find are source language expressions.
If I want to search for 'h', 'e', 'l', 'l', 'o' I won't be able to
use "hello" because that will now include the trailing nul. Often one
will want the trailing nul, but it does make searching for substrings
kinda hard. [For completeness' sake, one could change the definition
of what "hello" means in this context, and if one wants the trailing
nul, one has to explicitly specify it, e.g. "hello\0". It's
C-specific though, and the find command is presumably not supposed to
know the user is thinking in C - that's the whole point. I don't have
an opinion either way.]
Any suggestions or preferences for whether and how to make searching
for substrings not excessively clumsy?
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [RFA] new command to search memory
2008-02-29 3:58 ` Daniel Jacobowitz
@ 2008-04-17 2:59 ` Doug Evans
2008-04-28 18:37 ` Fwd: " Doug Evans
2008-05-02 15:19 ` Daniel Jacobowitz
0 siblings, 2 replies; 21+ messages in thread
From: Doug Evans @ 2008-04-17 2:59 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 612 bytes --]
Here's the revised "find" patch. It includes all requested changes to date.
Could someone look at target.c:target_search_memory and make sure it's
DTRT regarding handling targetdebug and falling back on a default?
Given that we're not using inheritance here, the current code seems
like the right way to go, but ...
Ok to check in?
There's still an outstanding issue of supporting this in gdbmi. I
split find_command into two parts so adding this to gdbmi should be
more straightforward.
And there's also an outstanding issue of if/how to support substring searches.
Both of these issues can wait I gather.
[-- Attachment #2: gdb-080416-findcmd-6.patch.txt --]
[-- Type: text/plain, Size: 47716 bytes --]
2008-04-16 Doug Evans <dje@google.com>
New "find" command.
* NEWS: Document find command and qSearch:memory packet.
* Makefile.in (SFILES): Add findcmd.c.
(COMMON_OBJS): Add findcmd.o.
(findcmd.o): New rule.
* findcmd.c: New file.
* target.h (target_ops): New member to_search_memory.
(simple_search_memory): Declare.
(target_search_memory): Declare.
* target.c (simple_search_memory): New fn.
(target_search_memory): New fn.
* remote.c (PACKET_qSearch_memory): New packet kind.
(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/Makefile.in (INCGNULIB): New variable.
(INCLUDE_CFLAGS): Add $(INCGNULIB).
(OBS): Add memmem.o.
* gdbserver/server.h (decode_search_memory_packet): 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.
* doc/gdb.texinfo: Document "find" command, qSearch:memory packet.
* testsuite/gdb.base/find.exp: New file.
* testsuite/gdb.base/find.c: New file.
Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.1000
diff -u -p -u -p -r1.1000 Makefile.in
--- Makefile.in 14 Apr 2008 19:47:29 -0000 1.1000
+++ Makefile.in 17 Apr 2008 02:35:23 -0000
@@ -608,9 +608,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 findcmd.c findvar.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 \
@@ -1052,6 +1051,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 \
@@ -2124,6 +2124,8 @@ 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) $(gdb_string_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: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.264
diff -u -p -u -p -r1.264 NEWS
--- NEWS 4 Apr 2008 15:51:15 -0000 1.264
+++ NEWS 17 Apr 2008 02:35:23 -0000
@@ -3,8 +3,13 @@
*** Changes since GDB 6.8
+* New remote packets
+
+qSearch:memory:
+ Search memory for a sequence of bytes.
+
* Watchpoints can now be set on unreadable memory locations, e.g. addresses
-which will be allocated using malloc later in program execution.
+ which will be allocated using malloc later in program execution.
* The qXfer:libraries:read remote procotol packet now allows passing a
list of section offsets.
@@ -30,6 +35,10 @@ show multiple-symbols
The value of this variable can be changed to adjust the debugger behavior
when an expression or a breakpoint location contains an ambiguous symbol
name (an overloaded function name, for instance).
+
+find [/size-char] [/max-count] start-address, end-address|@search-space-size,
+ val1 [, val2, ...]
+ Search memory for a sequence of bytes.
*** Changes in GDB 6.8
Index: findcmd.c
===================================================================
RCS file: findcmd.c
diff -N findcmd.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ findcmd.c 17 Apr 2008 02:35:23 -0000
@@ -0,0 +1,334 @@
+/* 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"
+
+/* 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;
+ }
+}
+
+/* Subroutine of find_command to simplify it.
+ Parse the arguments of the "find" command. */
+
+static void
+parse_find_args (char *args, ULONGEST *max_countp,
+ char **pattern_bufp, ULONGEST *pattern_lenp,
+ CORE_ADDR *start_addrp, ULONGEST *search_space_lenp)
+{
+ /* Default to using the specified type. */
+ char size = '\0';
+ ULONGEST max_count = ~(ULONGEST) 0;
+ /* 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;
+ ULONGEST pattern_len;
+ CORE_ADDR start_addr;
+ ULONGEST search_space_len;
+ char *s = args;
+ bfd_boolean big_p = gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG;
+ struct cleanup *old_cleanups;
+ struct value *v;
+
+ 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.
+ They may be specified in either order, together or separately. */
+
+ while (*s == '/')
+ {
+ ++s;
+
+ while (*s != '\0' && *s != '/' && !isspace (*s))
+ {
+ if (isdigit (*s))
+ {
+ max_count = atoi (s);
+ while (isdigit (*s))
+ ++s;
+ continue;
+ }
+
+ switch (*s)
+ {
+ case 'b':
+ case 'h':
+ case 'w':
+ case 'g':
+ size = *s++;
+ break;
+ default:
+ 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;
+ int val_bytes;
+
+ /* If we see a string, parse it ourselves rather than the normal
+ handling of downloading it to target memory. */
+
+ while (isspace (*s))
+ ++s;
+
+ 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"));
+
+ *max_countp = max_count;
+ *pattern_bufp = pattern_buf;
+ *pattern_lenp = pattern_len;
+ *start_addrp = start_addr;
+ *search_space_lenp = search_space_len;
+
+ /* We successfully parsed the arguments, leave the freeing of PATTERN_BUF
+ to the caller now. */
+ discard_cleanups (old_cleanups);
+}
+
+static void
+find_command (char *args, int from_tty)
+{
+ /* Command line parameters.
+ These are initialized to avoid uninitialized warnings from -Wall. */
+ ULONGEST max_count = 0;
+ char *pattern_buf = 0;
+ ULONGEST pattern_len = 0;
+ CORE_ADDR start_addr = 0;
+ ULONGEST search_space_len = 0;
+ /* End of command line parameters. */
+ unsigned int found_count;
+ CORE_ADDR last_found_addr;
+ struct cleanup *old_cleanups;
+
+ parse_find_args (args, &max_count, &pattern_buf, &pattern_len,
+ &start_addr, &search_space_len);
+
+ old_cleanups = make_cleanup (free_current_contents, &pattern_buf);
+
+ /* 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\
+in the current language.\n\
+Note that this means for example that in the case of C-like languages\n\
+a search for an untyped 0x42 will search for \"(int) 0x42\"\n\
+which is typically four bytes.\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: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.286
diff -u -p -u -p -r1.286 remote.c
--- remote.c 21 Mar 2008 17:09:35 -0000 1.286
+++ remote.c 17 Apr 2008 02:35:24 -0000
@@ -935,6 +935,7 @@ enum {
PACKET_qGetTLSAddr,
PACKET_qSupported,
PACKET_QPassSignals,
+ PACKET_qSearch_memory,
PACKET_vAttach,
PACKET_vRun,
PACKET_MAX
@@ -6176,6 +6177,93 @@ remote_xfer_partial (struct target_ops *
return strlen ((char *) readbuf);
}
+static int
+remote_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)
+{
+ 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 before 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 we already know the packet isn't supported, fall back to the simple
+ way of searching memory. */
+
+ 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 (ops, 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)
+ {
+ /* The request may not have worked because the command is not
+ supported. If so, fall back to the simple way. */
+ if (packet->support == PACKET_DISABLE)
+ {
+ return simple_search_memory (ops, start_addr, search_space_len,
+ pattern, pattern_len, found_addrp);
+ }
+ 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)
@@ -7237,6 +7325,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;
remote_ops.to_can_async_p = remote_return_zero;
remote_ops.to_is_async_p = remote_return_zero;
}
@@ -7384,6 +7473,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
@@ -7650,6 +7740,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: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.159
diff -u -p -u -p -r1.159 target.c
--- target.c 28 Mar 2008 16:37:08 -0000 1.159
+++ target.c 17 Apr 2008 02:35:24 -0000
@@ -469,6 +469,7 @@ update_current_target (void)
INHERIT (to_make_corefile_notes, t);
INHERIT (to_get_thread_local_address, t);
/* Do not inherit to_read_description. */
+ /* Do not inherit to_search_memory. */
INHERIT (to_magic, t);
/* Do not inherit to_memory_map. */
/* Do not inherit to_flash_erase. */
@@ -1743,6 +1744,157 @@ target_read_description (struct target_o
return NULL;
}
+/* The default implementation of to_search_memory.
+ This implements a basic search of memory, reading target memory and
+ performing the search here (as opposed to performing the search in on the
+ target side with, for example, gdbserver). */
+
+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)
+{
+ /* 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 = memmem (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;
+}
+
+/* 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
+target_search_memory (CORE_ADDR start_addr, ULONGEST search_space_len,
+ const gdb_byte *pattern, ULONGEST pattern_len,
+ CORE_ADDR *found_addrp)
+{
+ struct target_ops *t;
+ int found;
+
+ /* We don't use INHERIT to set current_target.to_search_memory,
+ so we have to scan the target stack and handle targetdebug
+ ourselves. */
+
+ if (targetdebug)
+ fprintf_unfiltered (gdb_stdlog, "target_search_memory (%s, ...)\n",
+ hex_string (start_addr));
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_search_memory != NULL)
+ break;
+
+ if (t != NULL)
+ {
+ found = t->to_search_memory (t, start_addr, search_space_len,
+ pattern, pattern_len, found_addrp);
+ }
+ else
+ {
+ /* If a special version of to_search_memory isn't available, use the
+ simple version. */
+ found = simple_search_memory (¤t_target,
+ start_addr, search_space_len,
+ pattern, pattern_len, found_addrp);
+ }
+
+ if (targetdebug)
+ fprintf_unfiltered (gdb_stdlog, " = %d\n", found);
+
+ return found;
+}
+
/* Look through the currently pushed targets. If none of them will
be able to restart the currently running process, issue an error
message. */
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.116
diff -u -p -u -p -r1.116 target.h
--- target.h 8 Apr 2008 17:02:23 -0000 1.116
+++ target.h 17 Apr 2008 02:35:24 -0000
@@ -497,6 +497,17 @@ 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) (struct target_ops *ops,
+ 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?
*/
@@ -1095,6 +1106,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: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.481
diff -u -p -u -p -r1.481 gdb.texinfo
--- doc/gdb.texinfo 16 Apr 2008 13:14:18 -0000 1.481
+++ doc/gdb.texinfo 17 Apr 2008 02:35:24 -0000
@@ -5534,6 +5534,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
@@ -7597,6 +7598,101 @@ 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{sn}@r{]} @var{start_addr}, +@var{len}, @var{val1} @r{[}, @var{val2}, @dots{}@r{]}
+@itemx find @r{[}/@var{sn}@r{]} @var{start_addr}, @var{end_addr}, @var{val1} @r{[}, @var{val2}, @dots{}@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.
+@end table
+
+@var{s} and @var{n} are optional parameters.
+They may be specified in either order, apart or together.
+
+@table @r
+@item @var{s}, search query size
+The size of each search query value.
+
+@table @code
+@item b
+Bytes.
+@item h
+Halfwords (two bytes).
+@item w
+Words (four bytes).
+@item g
+Giant words (eight bytes).
+@end table
+
+All values are interpreted in the current language.
+This means, for example, that if the current source language is C/C++
+then searching for the string "hello" includes the trailing '\0'.
+
+If the value size is not specified, it is taken from the
+value's type in the current language.
+This is useful when one wants to specify the search
+pattern as a mixture of types.
+Note that this means, for example, that in the case of C-like languages
+a search for an untyped 0x42 will search for "(int) 0x42"
+which is typically four bytes.
+
+@item @var{n}, maximum number of finds
+The maximum number of finds to print. The default is to print all finds.
+@end table
+
+Strings may be specified for search values, quote them with double-quotes
+(@code{"}). The string value is copied into the search pattern byte by byte,
+regardless of the endianness of the target and the size specification.
+
+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{$_}.
+A count of the number of matches is stored in @samp{$numfound}.
+
+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"
+0x804956d <hello.1620+6>
+1 pattern found
+(gdb) find &hello[0], +sizeof(hello), 'h', 'e', 'l', 'l', 'o'
+0x8049567 <hello.1620>
+0x804956d <hello.1620+6>
+2 patterns found
+(gdb) find /b1 &hello[0], +sizeof(hello), 'h', 0x65, 'l'
+0x8049567 <hello.1620>
+1 pattern found
+(gdb) find &mixed, +sizeof(mixed), (char) 'c', (short) 0x1234, (int) 0x87654321
+0x8049560 <mixed.1625>
+1 pattern found
+(gdb) print $numfound
+$1 = 1
+(gdb) print $_
+$2 = (void *) 0x8049560
+@end smallexample
@node Macros
@chapter C Preprocessor Macros
@@ -13434,6 +13530,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
@@ -24465,6 +24565,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 searching memory, in remote debugging
+@cindex @samp{qSearch:memory} packet
+@anchor{qSearch memory}
+Search @var{length} bytes at @var{address} for @var{search-pattern}.
+@var{address} and @var{length} are encoded in hex.
+@var{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 @var{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
Index: gdbserver/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/Makefile.in,v
retrieving revision 1.57
diff -u -p -u -p -r1.57 Makefile.in
--- gdbserver/Makefile.in 14 Apr 2008 18:04:00 -0000 1.57
+++ gdbserver/Makefile.in 17 Apr 2008 02:35:24 -0000
@@ -81,11 +81,15 @@ BFD_CFLAGS = -I$(BFD_DIR) -I$(BFD_SRC)
READLINE_DIR = ${srcdir}/../readline
READLINE_DEP = $$(READLINE_DIR)
+# gnulib
+INCGNULIB = -I$(srcdir)/../gnulib -I../gnulib
+
# All the includes used for CFLAGS and for lint.
# -I. for config files.
# -I${srcdir} for our headers.
# -I$(srcdir)/../regformats for regdef.h.
-INCLUDE_CFLAGS = -I. -I${srcdir} -I$(srcdir)/../regformats -I$(INCLUDE_DIR)
+INCLUDE_CFLAGS = -I. -I${srcdir} -I$(srcdir)/../regformats -I$(INCLUDE_DIR) \
+ $(INCGNULIB)
# M{H,T}_CFLAGS, if defined, has host- and target-dependent CFLAGS
# from the config/ directory.
@@ -143,7 +147,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 memmem.o hostio.o \
$(XML_BUILTIN) \
$(DEPFILES) $(LIBOBJS)
GDBSERVER_LIBS = @GDBSERVER_LIBS@
Index: gdbserver/remote-utils.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/remote-utils.c,v
retrieving revision 1.54
diff -u -p -u -p -r1.54 remote-utils.c
--- gdbserver/remote-utils.c 30 Jan 2008 00:51:50 -0000 1.54
+++ gdbserver/remote-utils.c 17 Apr 2008 02:35:24 -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: gdbserver/server.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
retrieving revision 1.70
diff -u -p -u -p -r1.70 server.c
--- gdbserver/server.c 4 Apr 2008 19:19:11 -0000 1.70
+++ gdbserver/server.c 17 Apr 2008 02:35:24 -0000
@@ -314,6 +314,154 @@ monitor_show_help (void)
monitor_output (" Quit GDBserver\n");
}
+/* Subroutine of handle_search_memory to simplify it. */
+
+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 = memmem (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. */
+
+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;
+ /* 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);
+}
+
#define require_running(BUF) \
if (!target_running ()) \
{ \
@@ -731,6 +879,13 @@ handle_query (char *own_buf, int packet_
return;
}
+ if (strncmp ("qSearch:memory:", own_buf, sizeof ("qSearch:memory:") - 1) == 0)
+ {
+ require_running (own_buf);
+ 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: gdbserver/server.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.h,v
retrieving revision 1.41
diff -u -p -u -p -r1.41 server.h
--- gdbserver/server.h 27 Feb 2008 03:27:40 -0000 1.41
+++ gdbserver/server.h 17 Apr 2008 02:35:24 -0000
@@ -195,6 +195,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);
Index: testsuite/gdb.base/find.c
===================================================================
RCS file: testsuite/gdb.base/find.c
diff -N testsuite/gdb.base/find.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/find.c 17 Apr 2008 02:35: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: testsuite/gdb.base/find.exp
===================================================================
RCS file: testsuite/gdb.base/find.exp
diff -N testsuite/gdb.base/find.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/find.exp 17 Apr 2008 02:35:25 -0000
@@ -0,0 +1,191 @@
+# 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 pattern_not_found "${newline}pattern not found"
+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), 'a', 'a', 'a'" \
+ "${hex_number}.*<int8_search_buf\\+10>${newline}${hex_number}.*<int8_search_buf\\+11>${two_patterns_found}" \
+ "find string pattern"
+
+# Test not finding pattern because search range too small, with
+# potential find at the edge of the range.
+
+gdb_test "find &int8_search_buf\[0\], +10+3, \"aaaa\"" \
+ "${pattern_not_found}" \
+ "pattern not found at end of range"
+
+# Increase the search range by 1 and we should find the pattern.
+
+gdb_test "find &int8_search_buf\[0\], +10+3+1, 'a', 'a', 'a', 'a'" \
+ "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
+ "pattern found at end of range"
+
+# Test max-count, $_ and $numfound.
+
+gdb_test "find /1 &int8_search_buf\[0\], +sizeof(int8_search_buf), 'a', 'a', 'a'" \
+ "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
+ "max-count"
+
+gdb_test "print \$_" \
+ "${history_prefix}.*${hex_number}" \
+ "\$_"
+
+gdb_test "print \$numfound" \
+ "${history_prefix}1" \
+ "\$numfound"
+
+# Test max-count with size-char.
+# They can be specified in either order.
+
+gdb_test "find /1b &int8_search_buf\[0\], +sizeof(int8_search_buf), 0x61, 0x61, 0x61" \
+ "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
+ "size,max-count, /1b"
+
+gdb_test "find /b1 &int8_search_buf\[0\], +sizeof(int8_search_buf), 0x61, 0x61, 0x61" \
+ "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
+ "size,max-count, /b1"
+
+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}" \
+ "size,max-count, /b/1"
+
+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}" \
+ "size,max-count, /1/b"
+
+# 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\], +100, (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] 21+ messages in thread
* Fwd: [RFA] new command to search memory
2008-04-17 2:59 ` Doug Evans
@ 2008-04-28 18:37 ` Doug Evans
2008-04-29 0:40 ` Eli Zaretskii
2008-05-02 15:19 ` Daniel Jacobowitz
1 sibling, 1 reply; 21+ messages in thread
From: Doug Evans @ 2008-04-28 18:37 UTC (permalink / raw)
To: GDB Patches
[-- Attachment #1: Type: text/plain, Size: 819 bytes --]
Ping.
---------- Forwarded message ----------
From: Doug Evans <dje@google.com>
Date: Wed, Apr 16, 2008 at 7:46 PM
Subject: Re: [RFA] new command to search memory
To: gdb-patches@sourceware.org
Here's the revised "find" patch. It includes all requested changes to date.
Could someone look at target.c:target_search_memory and make sure it's
DTRT regarding handling targetdebug and falling back on a default?
Given that we're not using inheritance here, the current code seems
like the right way to go, but ...
Ok to check in?
There's still an outstanding issue of supporting this in gdbmi. I
split find_command into two parts so adding this to gdbmi should be
more straightforward.
And there's also an outstanding issue of if/how to support substring searches.
Both of these issues can wait I gather.
[-- Attachment #2: gdb-080416-findcmd-6.patch.txt --]
[-- Type: text/plain, Size: 47716 bytes --]
2008-04-16 Doug Evans <dje@google.com>
New "find" command.
* NEWS: Document find command and qSearch:memory packet.
* Makefile.in (SFILES): Add findcmd.c.
(COMMON_OBJS): Add findcmd.o.
(findcmd.o): New rule.
* findcmd.c: New file.
* target.h (target_ops): New member to_search_memory.
(simple_search_memory): Declare.
(target_search_memory): Declare.
* target.c (simple_search_memory): New fn.
(target_search_memory): New fn.
* remote.c (PACKET_qSearch_memory): New packet kind.
(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/Makefile.in (INCGNULIB): New variable.
(INCLUDE_CFLAGS): Add $(INCGNULIB).
(OBS): Add memmem.o.
* gdbserver/server.h (decode_search_memory_packet): 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.
* doc/gdb.texinfo: Document "find" command, qSearch:memory packet.
* testsuite/gdb.base/find.exp: New file.
* testsuite/gdb.base/find.c: New file.
Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.1000
diff -u -p -u -p -r1.1000 Makefile.in
--- Makefile.in 14 Apr 2008 19:47:29 -0000 1.1000
+++ Makefile.in 17 Apr 2008 02:35:23 -0000
@@ -608,9 +608,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 findcmd.c findvar.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 \
@@ -1052,6 +1051,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 \
@@ -2124,6 +2124,8 @@ 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) $(gdb_string_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: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.264
diff -u -p -u -p -r1.264 NEWS
--- NEWS 4 Apr 2008 15:51:15 -0000 1.264
+++ NEWS 17 Apr 2008 02:35:23 -0000
@@ -3,8 +3,13 @@
*** Changes since GDB 6.8
+* New remote packets
+
+qSearch:memory:
+ Search memory for a sequence of bytes.
+
* Watchpoints can now be set on unreadable memory locations, e.g. addresses
-which will be allocated using malloc later in program execution.
+ which will be allocated using malloc later in program execution.
* The qXfer:libraries:read remote procotol packet now allows passing a
list of section offsets.
@@ -30,6 +35,10 @@ show multiple-symbols
The value of this variable can be changed to adjust the debugger behavior
when an expression or a breakpoint location contains an ambiguous symbol
name (an overloaded function name, for instance).
+
+find [/size-char] [/max-count] start-address, end-address|@search-space-size,
+ val1 [, val2, ...]
+ Search memory for a sequence of bytes.
*** Changes in GDB 6.8
Index: findcmd.c
===================================================================
RCS file: findcmd.c
diff -N findcmd.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ findcmd.c 17 Apr 2008 02:35:23 -0000
@@ -0,0 +1,334 @@
+/* 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"
+
+/* 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;
+ }
+}
+
+/* Subroutine of find_command to simplify it.
+ Parse the arguments of the "find" command. */
+
+static void
+parse_find_args (char *args, ULONGEST *max_countp,
+ char **pattern_bufp, ULONGEST *pattern_lenp,
+ CORE_ADDR *start_addrp, ULONGEST *search_space_lenp)
+{
+ /* Default to using the specified type. */
+ char size = '\0';
+ ULONGEST max_count = ~(ULONGEST) 0;
+ /* 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;
+ ULONGEST pattern_len;
+ CORE_ADDR start_addr;
+ ULONGEST search_space_len;
+ char *s = args;
+ bfd_boolean big_p = gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG;
+ struct cleanup *old_cleanups;
+ struct value *v;
+
+ 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.
+ They may be specified in either order, together or separately. */
+
+ while (*s == '/')
+ {
+ ++s;
+
+ while (*s != '\0' && *s != '/' && !isspace (*s))
+ {
+ if (isdigit (*s))
+ {
+ max_count = atoi (s);
+ while (isdigit (*s))
+ ++s;
+ continue;
+ }
+
+ switch (*s)
+ {
+ case 'b':
+ case 'h':
+ case 'w':
+ case 'g':
+ size = *s++;
+ break;
+ default:
+ 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;
+ int val_bytes;
+
+ /* If we see a string, parse it ourselves rather than the normal
+ handling of downloading it to target memory. */
+
+ while (isspace (*s))
+ ++s;
+
+ 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"));
+
+ *max_countp = max_count;
+ *pattern_bufp = pattern_buf;
+ *pattern_lenp = pattern_len;
+ *start_addrp = start_addr;
+ *search_space_lenp = search_space_len;
+
+ /* We successfully parsed the arguments, leave the freeing of PATTERN_BUF
+ to the caller now. */
+ discard_cleanups (old_cleanups);
+}
+
+static void
+find_command (char *args, int from_tty)
+{
+ /* Command line parameters.
+ These are initialized to avoid uninitialized warnings from -Wall. */
+ ULONGEST max_count = 0;
+ char *pattern_buf = 0;
+ ULONGEST pattern_len = 0;
+ CORE_ADDR start_addr = 0;
+ ULONGEST search_space_len = 0;
+ /* End of command line parameters. */
+ unsigned int found_count;
+ CORE_ADDR last_found_addr;
+ struct cleanup *old_cleanups;
+
+ parse_find_args (args, &max_count, &pattern_buf, &pattern_len,
+ &start_addr, &search_space_len);
+
+ old_cleanups = make_cleanup (free_current_contents, &pattern_buf);
+
+ /* 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\
+in the current language.\n\
+Note that this means for example that in the case of C-like languages\n\
+a search for an untyped 0x42 will search for \"(int) 0x42\"\n\
+which is typically four bytes.\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: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.286
diff -u -p -u -p -r1.286 remote.c
--- remote.c 21 Mar 2008 17:09:35 -0000 1.286
+++ remote.c 17 Apr 2008 02:35:24 -0000
@@ -935,6 +935,7 @@ enum {
PACKET_qGetTLSAddr,
PACKET_qSupported,
PACKET_QPassSignals,
+ PACKET_qSearch_memory,
PACKET_vAttach,
PACKET_vRun,
PACKET_MAX
@@ -6176,6 +6177,93 @@ remote_xfer_partial (struct target_ops *
return strlen ((char *) readbuf);
}
+static int
+remote_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)
+{
+ 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 before 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 we already know the packet isn't supported, fall back to the simple
+ way of searching memory. */
+
+ 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 (ops, 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)
+ {
+ /* The request may not have worked because the command is not
+ supported. If so, fall back to the simple way. */
+ if (packet->support == PACKET_DISABLE)
+ {
+ return simple_search_memory (ops, start_addr, search_space_len,
+ pattern, pattern_len, found_addrp);
+ }
+ 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)
@@ -7237,6 +7325,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;
remote_ops.to_can_async_p = remote_return_zero;
remote_ops.to_is_async_p = remote_return_zero;
}
@@ -7384,6 +7473,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
@@ -7650,6 +7740,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: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.159
diff -u -p -u -p -r1.159 target.c
--- target.c 28 Mar 2008 16:37:08 -0000 1.159
+++ target.c 17 Apr 2008 02:35:24 -0000
@@ -469,6 +469,7 @@ update_current_target (void)
INHERIT (to_make_corefile_notes, t);
INHERIT (to_get_thread_local_address, t);
/* Do not inherit to_read_description. */
+ /* Do not inherit to_search_memory. */
INHERIT (to_magic, t);
/* Do not inherit to_memory_map. */
/* Do not inherit to_flash_erase. */
@@ -1743,6 +1744,157 @@ target_read_description (struct target_o
return NULL;
}
+/* The default implementation of to_search_memory.
+ This implements a basic search of memory, reading target memory and
+ performing the search here (as opposed to performing the search in on the
+ target side with, for example, gdbserver). */
+
+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)
+{
+ /* 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 = memmem (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;
+}
+
+/* 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
+target_search_memory (CORE_ADDR start_addr, ULONGEST search_space_len,
+ const gdb_byte *pattern, ULONGEST pattern_len,
+ CORE_ADDR *found_addrp)
+{
+ struct target_ops *t;
+ int found;
+
+ /* We don't use INHERIT to set current_target.to_search_memory,
+ so we have to scan the target stack and handle targetdebug
+ ourselves. */
+
+ if (targetdebug)
+ fprintf_unfiltered (gdb_stdlog, "target_search_memory (%s, ...)\n",
+ hex_string (start_addr));
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_search_memory != NULL)
+ break;
+
+ if (t != NULL)
+ {
+ found = t->to_search_memory (t, start_addr, search_space_len,
+ pattern, pattern_len, found_addrp);
+ }
+ else
+ {
+ /* If a special version of to_search_memory isn't available, use the
+ simple version. */
+ found = simple_search_memory (¤t_target,
+ start_addr, search_space_len,
+ pattern, pattern_len, found_addrp);
+ }
+
+ if (targetdebug)
+ fprintf_unfiltered (gdb_stdlog, " = %d\n", found);
+
+ return found;
+}
+
/* Look through the currently pushed targets. If none of them will
be able to restart the currently running process, issue an error
message. */
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.116
diff -u -p -u -p -r1.116 target.h
--- target.h 8 Apr 2008 17:02:23 -0000 1.116
+++ target.h 17 Apr 2008 02:35:24 -0000
@@ -497,6 +497,17 @@ 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) (struct target_ops *ops,
+ 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?
*/
@@ -1095,6 +1106,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: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.481
diff -u -p -u -p -r1.481 gdb.texinfo
--- doc/gdb.texinfo 16 Apr 2008 13:14:18 -0000 1.481
+++ doc/gdb.texinfo 17 Apr 2008 02:35:24 -0000
@@ -5534,6 +5534,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
@@ -7597,6 +7598,101 @@ 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{sn}@r{]} @var{start_addr}, +@var{len}, @var{val1} @r{[}, @var{val2}, @dots{}@r{]}
+@itemx find @r{[}/@var{sn}@r{]} @var{start_addr}, @var{end_addr}, @var{val1} @r{[}, @var{val2}, @dots{}@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.
+@end table
+
+@var{s} and @var{n} are optional parameters.
+They may be specified in either order, apart or together.
+
+@table @r
+@item @var{s}, search query size
+The size of each search query value.
+
+@table @code
+@item b
+Bytes.
+@item h
+Halfwords (two bytes).
+@item w
+Words (four bytes).
+@item g
+Giant words (eight bytes).
+@end table
+
+All values are interpreted in the current language.
+This means, for example, that if the current source language is C/C++
+then searching for the string "hello" includes the trailing '\0'.
+
+If the value size is not specified, it is taken from the
+value's type in the current language.
+This is useful when one wants to specify the search
+pattern as a mixture of types.
+Note that this means, for example, that in the case of C-like languages
+a search for an untyped 0x42 will search for "(int) 0x42"
+which is typically four bytes.
+
+@item @var{n}, maximum number of finds
+The maximum number of finds to print. The default is to print all finds.
+@end table
+
+Strings may be specified for search values, quote them with double-quotes
+(@code{"}). The string value is copied into the search pattern byte by byte,
+regardless of the endianness of the target and the size specification.
+
+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{$_}.
+A count of the number of matches is stored in @samp{$numfound}.
+
+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"
+0x804956d <hello.1620+6>
+1 pattern found
+(gdb) find &hello[0], +sizeof(hello), 'h', 'e', 'l', 'l', 'o'
+0x8049567 <hello.1620>
+0x804956d <hello.1620+6>
+2 patterns found
+(gdb) find /b1 &hello[0], +sizeof(hello), 'h', 0x65, 'l'
+0x8049567 <hello.1620>
+1 pattern found
+(gdb) find &mixed, +sizeof(mixed), (char) 'c', (short) 0x1234, (int) 0x87654321
+0x8049560 <mixed.1625>
+1 pattern found
+(gdb) print $numfound
+$1 = 1
+(gdb) print $_
+$2 = (void *) 0x8049560
+@end smallexample
@node Macros
@chapter C Preprocessor Macros
@@ -13434,6 +13530,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
@@ -24465,6 +24565,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 searching memory, in remote debugging
+@cindex @samp{qSearch:memory} packet
+@anchor{qSearch memory}
+Search @var{length} bytes at @var{address} for @var{search-pattern}.
+@var{address} and @var{length} are encoded in hex.
+@var{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 @var{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
Index: gdbserver/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/Makefile.in,v
retrieving revision 1.57
diff -u -p -u -p -r1.57 Makefile.in
--- gdbserver/Makefile.in 14 Apr 2008 18:04:00 -0000 1.57
+++ gdbserver/Makefile.in 17 Apr 2008 02:35:24 -0000
@@ -81,11 +81,15 @@ BFD_CFLAGS = -I$(BFD_DIR) -I$(BFD_SRC)
READLINE_DIR = ${srcdir}/../readline
READLINE_DEP = $$(READLINE_DIR)
+# gnulib
+INCGNULIB = -I$(srcdir)/../gnulib -I../gnulib
+
# All the includes used for CFLAGS and for lint.
# -I. for config files.
# -I${srcdir} for our headers.
# -I$(srcdir)/../regformats for regdef.h.
-INCLUDE_CFLAGS = -I. -I${srcdir} -I$(srcdir)/../regformats -I$(INCLUDE_DIR)
+INCLUDE_CFLAGS = -I. -I${srcdir} -I$(srcdir)/../regformats -I$(INCLUDE_DIR) \
+ $(INCGNULIB)
# M{H,T}_CFLAGS, if defined, has host- and target-dependent CFLAGS
# from the config/ directory.
@@ -143,7 +147,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 memmem.o hostio.o \
$(XML_BUILTIN) \
$(DEPFILES) $(LIBOBJS)
GDBSERVER_LIBS = @GDBSERVER_LIBS@
Index: gdbserver/remote-utils.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/remote-utils.c,v
retrieving revision 1.54
diff -u -p -u -p -r1.54 remote-utils.c
--- gdbserver/remote-utils.c 30 Jan 2008 00:51:50 -0000 1.54
+++ gdbserver/remote-utils.c 17 Apr 2008 02:35:24 -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: gdbserver/server.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
retrieving revision 1.70
diff -u -p -u -p -r1.70 server.c
--- gdbserver/server.c 4 Apr 2008 19:19:11 -0000 1.70
+++ gdbserver/server.c 17 Apr 2008 02:35:24 -0000
@@ -314,6 +314,154 @@ monitor_show_help (void)
monitor_output (" Quit GDBserver\n");
}
+/* Subroutine of handle_search_memory to simplify it. */
+
+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 = memmem (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. */
+
+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;
+ /* 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);
+}
+
#define require_running(BUF) \
if (!target_running ()) \
{ \
@@ -731,6 +879,13 @@ handle_query (char *own_buf, int packet_
return;
}
+ if (strncmp ("qSearch:memory:", own_buf, sizeof ("qSearch:memory:") - 1) == 0)
+ {
+ require_running (own_buf);
+ 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: gdbserver/server.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.h,v
retrieving revision 1.41
diff -u -p -u -p -r1.41 server.h
--- gdbserver/server.h 27 Feb 2008 03:27:40 -0000 1.41
+++ gdbserver/server.h 17 Apr 2008 02:35:24 -0000
@@ -195,6 +195,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);
Index: testsuite/gdb.base/find.c
===================================================================
RCS file: testsuite/gdb.base/find.c
diff -N testsuite/gdb.base/find.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/find.c 17 Apr 2008 02:35: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: testsuite/gdb.base/find.exp
===================================================================
RCS file: testsuite/gdb.base/find.exp
diff -N testsuite/gdb.base/find.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/find.exp 17 Apr 2008 02:35:25 -0000
@@ -0,0 +1,191 @@
+# 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 pattern_not_found "${newline}pattern not found"
+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), 'a', 'a', 'a'" \
+ "${hex_number}.*<int8_search_buf\\+10>${newline}${hex_number}.*<int8_search_buf\\+11>${two_patterns_found}" \
+ "find string pattern"
+
+# Test not finding pattern because search range too small, with
+# potential find at the edge of the range.
+
+gdb_test "find &int8_search_buf\[0\], +10+3, \"aaaa\"" \
+ "${pattern_not_found}" \
+ "pattern not found at end of range"
+
+# Increase the search range by 1 and we should find the pattern.
+
+gdb_test "find &int8_search_buf\[0\], +10+3+1, 'a', 'a', 'a', 'a'" \
+ "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
+ "pattern found at end of range"
+
+# Test max-count, $_ and $numfound.
+
+gdb_test "find /1 &int8_search_buf\[0\], +sizeof(int8_search_buf), 'a', 'a', 'a'" \
+ "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
+ "max-count"
+
+gdb_test "print \$_" \
+ "${history_prefix}.*${hex_number}" \
+ "\$_"
+
+gdb_test "print \$numfound" \
+ "${history_prefix}1" \
+ "\$numfound"
+
+# Test max-count with size-char.
+# They can be specified in either order.
+
+gdb_test "find /1b &int8_search_buf\[0\], +sizeof(int8_search_buf), 0x61, 0x61, 0x61" \
+ "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
+ "size,max-count, /1b"
+
+gdb_test "find /b1 &int8_search_buf\[0\], +sizeof(int8_search_buf), 0x61, 0x61, 0x61" \
+ "${hex_number}.*<int8_search_buf\\+10>${one_pattern_found}" \
+ "size,max-count, /b1"
+
+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}" \
+ "size,max-count, /b/1"
+
+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}" \
+ "size,max-count, /1/b"
+
+# 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\], +100, (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] 21+ messages in thread
* Re: Fwd: [RFA] new command to search memory
2008-04-28 18:37 ` Fwd: " Doug Evans
@ 2008-04-29 0:40 ` Eli Zaretskii
2008-05-09 6:46 ` Doug Evans
0 siblings, 1 reply; 21+ messages in thread
From: Eli Zaretskii @ 2008-04-29 0:40 UTC (permalink / raw)
To: Doug Evans; +Cc: gdb-patches
> Date: Mon, 28 Apr 2008 07:06:51 -0700
> From: "Doug Evans" <dje@google.com>
>
> --- NEWS 4 Apr 2008 15:51:15 -0000 1.264
> +++ NEWS 17 Apr 2008 02:35:23 -0000
This part is okay, thanks.
> + printf_filtered (_("empty search range\n"));
Do we want to capitalize the messages (here and elsewhere in your
patch)?
> --- doc/gdb.texinfo 16 Apr 2008 13:14:18 -0000 1.481
> +++ doc/gdb.texinfo 17 Apr 2008 02:35:24 -0000
This part is also okay, but I have a few comments/corrections.
> +@table @code
> +@item b
> +Bytes.
> +@item h
> +Halfwords (two bytes).
> +@item w
> +Words (four bytes).
> +@item g
> +Giant words (eight bytes).
> +@end table
In this table, the text under @item's are not complete sentences, so
it's better to start them with a lowercase letter and not end them
with a period.
> +This means, for example, that if the current source language is C/C++
Please use C@t{++} for "C++", it looks better in print.
> +then searching for the string "hello" includes the trailing '\0'.
Please quote text ``like this'', rather than "like this", it looks
better in print (and will be translated into "like this" in the
on-line manual).
> +Note that this means, for example, that in the case of C-like languages
> +a search for an untyped 0x42 will search for "(int) 0x42"
Please use @samp{(int) 0x42}, to force use of typeface appropriate for
program symbols.
> +@item @var{n}, maximum number of finds
> +The maximum number of finds to print. The default is to print all finds.
I think "matches" is a better word than "finds".
> +Strings may be specified for search values, quote them with double-quotes
It's better to avoid passive tense. For example:
You can use strings as search values. Quote them with double-quotes
(@code{"}).
> +For example, if stopped at the printf in this function:
"printf" should be in @code.
> +@smallexample
> +void
> +hello ()
> +@{
> + static char hello[] = "hello-hello";
> + static struct @{ char c; short s; int i; @} __attribute__ ((packed)) mixed
This last line is too long for a @smallexample. Please break it into
two shorter lines.
> +You get during debugging:
This is a continuation of the sentence broken by @smallexample. So
you should begin it with a lower-case `y', and you should put
@noindent (on a line of itself) immediately before it, to prevent
indentation that is typically output at the beginning of a paragraph.
Other than that, your changes for the documentation are okay with me.
Thanks!
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [RFA] new command to search memory
2008-04-17 2:59 ` Doug Evans
2008-04-28 18:37 ` Fwd: " Doug Evans
@ 2008-05-02 15:19 ` Daniel Jacobowitz
2008-05-09 6:35 ` Doug Evans
2008-05-09 20:16 ` Doug Evans
1 sibling, 2 replies; 21+ messages in thread
From: Daniel Jacobowitz @ 2008-05-02 15:19 UTC (permalink / raw)
To: Doug Evans; +Cc: gdb-patches
On Wed, Apr 16, 2008 at 07:46:48PM -0700, Doug Evans wrote:
> Here's the revised "find" patch. It includes all requested changes to date.
>
> Could someone look at target.c:target_search_memory and make sure it's
> DTRT regarding handling targetdebug and falling back on a default?
> Given that we're not using inheritance here, the current code seems
> like the right way to go, but ...
Yes, that looks right.
> * Watchpoints can now be set on unreadable memory locations, e.g. addresses
> -which will be allocated using malloc later in program execution.
> + which will be allocated using malloc later in program execution.
I always get confused about this but current style for NEWS puts
continuation lines up against the left margin.
> + /* If we see a string, parse it ourselves rather than the normal
> + handling of downloading it to target memory. */
This comment is stale I think?
> +/* 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);
> +
Function names only go against the left margin at the definition.
> Index: gdbserver/Makefile.in
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/Makefile.in,v
> retrieving revision 1.57
> diff -u -p -u -p -r1.57 Makefile.in
> --- gdbserver/Makefile.in 14 Apr 2008 18:04:00 -0000 1.57
> +++ gdbserver/Makefile.in 17 Apr 2008 02:35:24 -0000
> @@ -81,11 +81,15 @@ BFD_CFLAGS = -I$(BFD_DIR) -I$(BFD_SRC)
> READLINE_DIR = ${srcdir}/../readline
> READLINE_DEP = $$(READLINE_DIR)
>
> +# gnulib
> +INCGNULIB = -I$(srcdir)/../gnulib -I../gnulib
> +
> # All the includes used for CFLAGS and for lint.
> # -I. for config files.
> # -I${srcdir} for our headers.
> # -I$(srcdir)/../regformats for regdef.h.
> -INCLUDE_CFLAGS = -I. -I${srcdir} -I$(srcdir)/../regformats -I$(INCLUDE_DIR)
> +INCLUDE_CFLAGS = -I. -I${srcdir} -I$(srcdir)/../regformats -I$(INCLUDE_DIR) \
> + $(INCGNULIB)
>
> # M{H,T}_CFLAGS, if defined, has host- and target-dependent CFLAGS
> # from the config/ directory.
> @@ -143,7 +147,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 memmem.o hostio.o \
> $(XML_BUILTIN) \
> $(DEPFILES) $(LIBOBJS)
> GDBSERVER_LIBS = @GDBSERVER_LIBS@
The gdbserver configure script should already be taking care of all
these. In particular we don't want to reference ../gnulib in the
objdir since it won't exist if you're just building gdbserver. And I
know it will add memmem.o, I tested that.
Does that leave just the declaration? You can stick it somewhere in
gdbserver instead of bringing in all the replacement gnulib headers.
And you were still talking with Eli about docs. But other than that
I'm happy with this version. Thanks for your patience.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [RFA] new command to search memory
2008-04-09 21:06 ` Doug Evans
@ 2008-05-02 15:37 ` Daniel Jacobowitz
0 siblings, 0 replies; 21+ messages in thread
From: Daniel Jacobowitz @ 2008-05-02 15:37 UTC (permalink / raw)
To: Doug Evans; +Cc: gdb-patches
On Wed, Apr 09, 2008 at 01:37:26PM -0700, Doug Evans wrote:
> If I want to search for 'h', 'e', 'l', 'l', 'o' I won't be able to
> use "hello" because that will now include the trailing nul. Often one
> will want the trailing nul, but it does make searching for substrings
> kinda hard. [For completeness' sake, one could change the definition
> of what "hello" means in this context, and if one wants the trailing
> nul, one has to explicitly specify it, e.g. "hello\0". It's
> C-specific though, and the find command is presumably not supposed to
> know the user is thinking in C - that's the whole point. I don't have
> an opinion either way.]
>
> Any suggestions or preferences for whether and how to make searching
> for substrings not excessively clumsy?
I think that "hello" should be five characters, for this purpose.
There's some support for that in C; it's a valid initializer for
either char[5] or char[6] (C99 6.7.8#15).
Would it help if "hello" reached this point as a TYPE_CODE_STRING
but {'a', 'b', '\0'} was TYPE_CODE_ARRAY, so that we could reliably
detect strings? I don't think it's a big deal since people will
normally leave off the braces for the array here anyway.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [RFA] new command to search memory
2008-05-02 15:19 ` Daniel Jacobowitz
@ 2008-05-09 6:35 ` Doug Evans
2008-05-09 7:33 ` Daniel Jacobowitz
2008-05-09 20:16 ` Doug Evans
1 sibling, 1 reply; 21+ messages in thread
From: Doug Evans @ 2008-05-09 6:35 UTC (permalink / raw)
To: gdb-patches
On Fri, May 2, 2008 at 8:17 AM, Daniel Jacobowitz <drow@false.org> wrote:
>> Index: gdbserver/Makefile.in
>> ===================================================================
>> RCS file: /cvs/src/src/gdb/gdbserver/Makefile.in,v
>> retrieving revision 1.57
>> diff -u -p -u -p -r1.57 Makefile.in
>> --- gdbserver/Makefile.in 14 Apr 2008 18:04:00 -0000 1.57
>> +++ gdbserver/Makefile.in 17 Apr 2008 02:35:24 -0000
>> @@ -81,11 +81,15 @@ BFD_CFLAGS = -I$(BFD_DIR) -I$(BFD_SRC)
>> READLINE_DIR = ${srcdir}/../readline
>> READLINE_DEP = $$(READLINE_DIR)
>>
>> +# gnulib
>> +INCGNULIB = -I$(srcdir)/../gnulib -I../gnulib
>> +
>> # All the includes used for CFLAGS and for lint.
>> # -I. for config files.
>> # -I${srcdir} for our headers.
>> # -I$(srcdir)/../regformats for regdef.h.
>> -INCLUDE_CFLAGS = -I. -I${srcdir} -I$(srcdir)/../regformats -I$(INCLUDE_DIR)
>> +INCLUDE_CFLAGS = -I. -I${srcdir} -I$(srcdir)/../regformats -I$(INCLUDE_DIR) \
>> + $(INCGNULIB)
>>
>> # M{H,T}_CFLAGS, if defined, has host- and target-dependent CFLAGS
>> # from the config/ directory.
>> @@ -143,7 +147,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 memmem.o hostio.o \
>> $(XML_BUILTIN) \
>> $(DEPFILES) $(LIBOBJS)
>> GDBSERVER_LIBS = @GDBSERVER_LIBS@
>
> The gdbserver configure script should already be taking care of all
> these. In particular we don't want to reference ../gnulib in the
> objdir since it won't exist if you're just building gdbserver. And I
> know it will add memmem.o, I tested that.
I thought gnulib/memmem.o was always going to be used. We started
down this path because, in part, libc's memmem is O(n^2).
configure ...
checking for memmem... yes
after making gdbserver ...
$ nm gdbserver | grep memmem
U memmem@@GLIBC_2.0
> Does that leave just the declaration? You can stick it somewhere in
> gdbserver instead of bringing in all the replacement gnulib headers.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: Fwd: [RFA] new command to search memory
2008-04-29 0:40 ` Eli Zaretskii
@ 2008-05-09 6:46 ` Doug Evans
2008-05-09 14:35 ` Eli Zaretskii
0 siblings, 1 reply; 21+ messages in thread
From: Doug Evans @ 2008-05-09 6:46 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
On Mon, Apr 28, 2008 at 11:52 AM, Eli Zaretskii <eliz@gnu.org> wrote:
>> --- doc/gdb.texinfo 16 Apr 2008 13:14:18 -0000 1.481
>> +++ doc/gdb.texinfo 17 Apr 2008 02:35:24 -0000
>
> This part is also okay, but I have a few comments/corrections.
>
>> +@table @code
>> +@item b
>> +Bytes.
>> +@item h
>> +Halfwords (two bytes).
>> +@item w
>> +Words (four bytes).
>> +@item g
>> +Giant words (eight bytes).
>> +@end table
>
> In this table, the text under @item's are not complete sentences, so
> it's better to start them with a lowercase letter and not end them
> with a period.
Cut-n-paste-n-tweak from @section Examining memory.
I can fix that too if you like (in a separate patch of course).
I'll make the other corrections. Thanks.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [RFA] new command to search memory
2008-05-09 6:35 ` Doug Evans
@ 2008-05-09 7:33 ` Daniel Jacobowitz
0 siblings, 0 replies; 21+ messages in thread
From: Daniel Jacobowitz @ 2008-05-09 7:33 UTC (permalink / raw)
To: Doug Evans; +Cc: gdb-patches
On Thu, May 08, 2008 at 07:51:29PM -0700, Doug Evans wrote:
> I thought gnulib/memmem.o was always going to be used. We started
> down this path because, in part, libc's memmem is O(n^2).
>
> configure ...
> checking for memmem... yes
>
> after making gdbserver ...
> $ nm gdbserver | grep memmem
> U memmem@@GLIBC_2.0
It was deliberate, since gdbserver is supposed to be small rather than
fast. If you feel strongly about it we can rip out the configure bits
easily enough.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: Fwd: [RFA] new command to search memory
2008-05-09 6:46 ` Doug Evans
@ 2008-05-09 14:35 ` Eli Zaretskii
0 siblings, 0 replies; 21+ messages in thread
From: Eli Zaretskii @ 2008-05-09 14:35 UTC (permalink / raw)
To: Doug Evans; +Cc: gdb-patches
> Date: Thu, 8 May 2008 20:07:51 -0700
> From: "Doug Evans" <dje@google.com>
> Cc: gdb-patches@sourceware.org
>
> >> +@table @code
> >> +@item b
> >> +Bytes.
> >> +@item h
> >> +Halfwords (two bytes).
> >> +@item w
> >> +Words (four bytes).
> >> +@item g
> >> +Giant words (eight bytes).
> >> +@end table
> >
> > In this table, the text under @item's are not complete sentences, so
> > it's better to start them with a lowercase letter and not end them
> > with a period.
>
> Cut-n-paste-n-tweak from @section Examining memory.
> I can fix that too if you like (in a separate patch of course).
Yes, please. Thanks.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [RFA] new command to search memory
2008-05-02 15:19 ` Daniel Jacobowitz
2008-05-09 6:35 ` Doug Evans
@ 2008-05-09 20:16 ` Doug Evans
2008-05-09 20:18 ` Daniel Jacobowitz
1 sibling, 1 reply; 21+ messages in thread
From: Doug Evans @ 2008-05-09 20:16 UTC (permalink / raw)
To: Daniel Jacobowitz, Eli Zaretskii; +Cc: GDB Patches
I've checked the patch in with the requested corrections.
Thanks for the reviews and help with gnulib.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [RFA] new command to search memory
2008-05-09 20:16 ` Doug Evans
@ 2008-05-09 20:18 ` Daniel Jacobowitz
0 siblings, 0 replies; 21+ messages in thread
From: Daniel Jacobowitz @ 2008-05-09 20:18 UTC (permalink / raw)
To: Doug Evans; +Cc: Eli Zaretskii, GDB Patches
On Fri, May 09, 2008 at 10:05:42AM -0700, Doug Evans wrote:
> I've checked the patch in with the requested corrections.
Thanks! I'm glad GDB finally has this.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2008-05-09 17:07 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-02-14 2:20 [RFA] new command to search memory Doug Evans
2008-02-14 19:54 ` Eli Zaretskii
2008-02-14 22:52 ` Doug Evans
2008-02-15 8:28 ` Eli Zaretskii
2008-02-16 5:39 ` Doug Evans
2008-02-16 13:33 ` Eli Zaretskii
2008-02-26 2:31 ` Daniel Jacobowitz
2008-02-29 3:13 ` Doug Evans
2008-02-29 3:58 ` Daniel Jacobowitz
2008-04-17 2:59 ` Doug Evans
2008-04-28 18:37 ` Fwd: " Doug Evans
2008-04-29 0:40 ` Eli Zaretskii
2008-05-09 6:46 ` Doug Evans
2008-05-09 14:35 ` Eli Zaretskii
2008-05-02 15:19 ` Daniel Jacobowitz
2008-05-09 6:35 ` Doug Evans
2008-05-09 7:33 ` Daniel Jacobowitz
2008-05-09 20:16 ` Doug Evans
2008-05-09 20:18 ` Daniel Jacobowitz
2008-04-09 21:06 ` Doug Evans
2008-05-02 15:37 ` Daniel Jacobowitz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox