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/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.
This commit is contained in:
parent
7010a0c901
commit
08388c79d5
16 changed files with 1204 additions and 3 deletions
|
@ -1,3 +1,22 @@
|
||||||
|
2008-05-09 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.
|
||||||
|
|
||||||
2008-05-09 Eli Zaretskii <eliz@gnu.org>
|
2008-05-09 Eli Zaretskii <eliz@gnu.org>
|
||||||
|
|
||||||
* thread.c (_initialize_thread): Don't use commas and periods in
|
* thread.c (_initialize_thread): Don't use commas and periods in
|
||||||
|
|
|
@ -609,9 +609,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c \
|
||||||
dbxread.c demangle.c dictionary.c disasm.c doublest.c dummy-frame.c \
|
dbxread.c demangle.c dictionary.c disasm.c doublest.c dummy-frame.c \
|
||||||
dwarf2expr.c dwarf2loc.c dwarf2read.c dwarf2-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 \
|
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 \
|
f-exp.y f-lang.c f-typeprint.c f-valprint.c findcmd.c findvar.c \
|
||||||
frame-base.c \
|
frame.c frame-base.c frame-unwind.c \
|
||||||
frame-unwind.c \
|
|
||||||
gdbarch.c arch-utils.c gdbtypes.c gnu-v2-abi.c gnu-v3-abi.c \
|
gdbarch.c arch-utils.c gdbtypes.c gnu-v2-abi.c gnu-v3-abi.c \
|
||||||
inf-loop.c \
|
inf-loop.c \
|
||||||
infcall.c \
|
infcall.c \
|
||||||
|
@ -1061,6 +1060,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
|
||||||
event-loop.o event-top.o inf-loop.o completer.o \
|
event-loop.o event-top.o inf-loop.o completer.o \
|
||||||
gdbarch.o arch-utils.o gdbtypes.o osabi.o copying.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 \
|
memattr.o mem-break.o target.o parse.o language.o buildsym.o \
|
||||||
|
findcmd.o \
|
||||||
std-regs.o \
|
std-regs.o \
|
||||||
signals.o \
|
signals.o \
|
||||||
gdb-events.o \
|
gdb-events.o \
|
||||||
|
@ -2136,6 +2136,8 @@ fbsd-nat.o: fbsd-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) $(regcache_h) \
|
||||||
f-exp.o: f-exp.c $(defs_h) $(gdb_string_h) $(expression_h) $(value_h) \
|
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) \
|
$(parser_defs_h) $(language_h) $(f_lang_h) $(bfd_h) $(symfile_h) \
|
||||||
$(objfiles_h) $(block_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) \
|
findvar.o: findvar.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(frame_h) \
|
||||||
$(value_h) $(gdbcore_h) $(inferior_h) $(target_h) $(gdb_string_h) \
|
$(value_h) $(gdbcore_h) $(inferior_h) $(target_h) $(gdb_string_h) \
|
||||||
$(gdb_assert_h) $(floatformat_h) $(symfile_h) $(regcache_h) \
|
$(gdb_assert_h) $(floatformat_h) $(symfile_h) $(regcache_h) \
|
||||||
|
|
9
gdb/NEWS
9
gdb/NEWS
|
@ -3,6 +3,11 @@
|
||||||
|
|
||||||
*** Changes since GDB 6.8
|
*** Changes since GDB 6.8
|
||||||
|
|
||||||
|
* New remote packets
|
||||||
|
|
||||||
|
qSearch:memory:
|
||||||
|
Search memory for a sequence of bytes.
|
||||||
|
|
||||||
* The "disassemble" command now supports an optional /m modifier to print mixed
|
* The "disassemble" command now supports an optional /m modifier to print mixed
|
||||||
source+assembly.
|
source+assembly.
|
||||||
|
|
||||||
|
@ -35,6 +40,10 @@ have also been fixed.
|
||||||
|
|
||||||
* New commands
|
* New commands
|
||||||
|
|
||||||
|
find [/size-char] [/max-count] start-address, end-address|+search-space-size,
|
||||||
|
val1 [, val2, ...]
|
||||||
|
Search memory for a sequence of bytes.
|
||||||
|
|
||||||
set debug timetstamp
|
set debug timetstamp
|
||||||
show debug timestamp
|
show debug timestamp
|
||||||
Display timestamps with GDB debugging output.
|
Display timestamps with GDB debugging output.
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
2008-05-09 Doug Evans <dje@google.com>
|
||||||
|
|
||||||
|
* doc/gdb.texinfo: Document "find" command, qSearch:memory packet.
|
||||||
|
|
||||||
2008-05-05 Doug Evans <dje@google.com>
|
2008-05-05 Doug Evans <dje@google.com>
|
||||||
|
|
||||||
* gdb.texinfo (disassemble): Document /m modifier.
|
* gdb.texinfo (disassemble): Document /m modifier.
|
||||||
|
|
|
@ -5590,6 +5590,7 @@ Table}.
|
||||||
* Character Sets:: Debugging programs that use a different
|
* Character Sets:: Debugging programs that use a different
|
||||||
character set than GDB does
|
character set than GDB does
|
||||||
* Caching Remote Data:: Data caching for remote targets
|
* Caching Remote Data:: Data caching for remote targets
|
||||||
|
* Searching Memory:: Searching memory for a sequence of bytes
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node Expressions
|
@node Expressions
|
||||||
|
@ -7653,6 +7654,104 @@ state (dirty, bad, ok, etc.). This command is useful for debugging
|
||||||
the data cache operation.
|
the data cache operation.
|
||||||
@end table
|
@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@t{++}
|
||||||
|
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 @samp{(int) 0x42}
|
||||||
|
which is typically four bytes.
|
||||||
|
|
||||||
|
@item @var{n}, maximum number of finds
|
||||||
|
The maximum number of matches to print. The default is to print all finds.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
You can use strings as 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 @code{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
|
||||||
|
|
||||||
|
@noindent
|
||||||
|
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
|
@node Macros
|
||||||
@chapter C Preprocessor Macros
|
@chapter C Preprocessor Macros
|
||||||
|
@ -13496,6 +13595,10 @@ are:
|
||||||
@tab @code{qGetTLSAddr}
|
@tab @code{qGetTLSAddr}
|
||||||
@tab Displaying @code{__thread} variables
|
@tab Displaying @code{__thread} variables
|
||||||
|
|
||||||
|
@item @code{search-memory}
|
||||||
|
@tab @code{qSearch:memory}
|
||||||
|
@tab @code{find}
|
||||||
|
|
||||||
@item @code{supported-packets}
|
@item @code{supported-packets}
|
||||||
@tab @code{qSupported}
|
@tab @code{qSupported}
|
||||||
@tab Remote communications parameters
|
@tab Remote communications parameters
|
||||||
|
@ -24606,6 +24709,26 @@ command by a @samp{,}, not a @samp{:}, contrary to the naming
|
||||||
conventions above. Please don't use this packet as a model for new
|
conventions above. Please don't use this packet as a model for new
|
||||||
packets.)
|
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{]}
|
@item qSupported @r{[}:@var{gdbfeature} @r{[};@var{gdbfeature}@r{]}@dots{} @r{]}
|
||||||
@cindex supported packets, remote query
|
@cindex supported packets, remote query
|
||||||
@cindex features of the remote protocol
|
@cindex features of the remote protocol
|
||||||
|
|
331
gdb/findcmd.c
Normal file
331
gdb/findcmd.c
Normal file
|
@ -0,0 +1,331 @@
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
|
@ -1,3 +1,11 @@
|
||||||
|
2008-05-09 Doug Evans <dje@google.com>
|
||||||
|
|
||||||
|
* 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.
|
||||||
|
|
||||||
2008-05-08 Ulrich Weigand <uweigand@de.ibm.com>
|
2008-05-08 Ulrich Weigand <uweigand@de.ibm.com>
|
||||||
|
|
||||||
* regcache.c (registers_length): Remove.
|
* regcache.c (registers_length): Remove.
|
||||||
|
|
|
@ -1080,6 +1080,24 @@ decode_xfer_write (char *buf, int packet_len, char **annex, CORE_ADDR *offset,
|
||||||
return 0;
|
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.
|
/* 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. */
|
Returns 1 if the symbol is found, 0 if it is not, -1 on error. */
|
||||||
|
|
||||||
|
|
|
@ -314,6 +314,153 @@ monitor_show_help (void)
|
||||||
monitor_output (" Quit GDBserver\n");
|
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) \
|
#define require_running(BUF) \
|
||||||
if (!target_running ()) \
|
if (!target_running ()) \
|
||||||
{ \
|
{ \
|
||||||
|
@ -731,6 +878,13 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||||
return;
|
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
|
/* Otherwise we didn't know what packet it was. Say we didn't
|
||||||
understand it. */
|
understand it. */
|
||||||
own_buf[0] = 0;
|
own_buf[0] = 0;
|
||||||
|
|
|
@ -195,6 +195,10 @@ int decode_X_packet (char *from, int packet_len, CORE_ADDR * mem_addr_ptr,
|
||||||
int decode_xfer_write (char *buf, int packet_len, char **annex,
|
int decode_xfer_write (char *buf, int packet_len, char **annex,
|
||||||
CORE_ADDR *offset, unsigned int *len,
|
CORE_ADDR *offset, unsigned int *len,
|
||||||
unsigned char *data);
|
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 unhexify (char *bin, const char *hex, int count);
|
||||||
int hexify (char *hex, const char *bin, int count);
|
int hexify (char *hex, const char *bin, int count);
|
||||||
|
|
93
gdb/remote.c
93
gdb/remote.c
|
@ -935,6 +935,7 @@ enum {
|
||||||
PACKET_qGetTLSAddr,
|
PACKET_qGetTLSAddr,
|
||||||
PACKET_qSupported,
|
PACKET_qSupported,
|
||||||
PACKET_QPassSignals,
|
PACKET_QPassSignals,
|
||||||
|
PACKET_qSearch_memory,
|
||||||
PACKET_vAttach,
|
PACKET_vAttach,
|
||||||
PACKET_vRun,
|
PACKET_vRun,
|
||||||
PACKET_MAX
|
PACKET_MAX
|
||||||
|
@ -6195,6 +6196,93 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
|
||||||
return strlen ((char *) readbuf);
|
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
|
static void
|
||||||
remote_rcmd (char *command,
|
remote_rcmd (char *command,
|
||||||
struct ui_file *outbuf)
|
struct ui_file *outbuf)
|
||||||
|
@ -7256,6 +7344,7 @@ Specify the serial device it is connected to\n\
|
||||||
remote_ops.to_flash_erase = remote_flash_erase;
|
remote_ops.to_flash_erase = remote_flash_erase;
|
||||||
remote_ops.to_flash_done = remote_flash_done;
|
remote_ops.to_flash_done = remote_flash_done;
|
||||||
remote_ops.to_read_description = remote_read_description;
|
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_can_async_p = remote_return_zero;
|
||||||
remote_ops.to_is_async_p = remote_return_zero;
|
remote_ops.to_is_async_p = remote_return_zero;
|
||||||
}
|
}
|
||||||
|
@ -7403,6 +7492,7 @@ Specify the serial device it is connected to (e.g. /dev/ttya).";
|
||||||
remote_async_ops.to_flash_erase = remote_flash_erase;
|
remote_async_ops.to_flash_erase = remote_flash_erase;
|
||||||
remote_async_ops.to_flash_done = remote_flash_done;
|
remote_async_ops.to_flash_done = remote_flash_done;
|
||||||
remote_async_ops.to_read_description = remote_read_description;
|
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
|
/* Set up the async extended remote vector by making a copy of the standard
|
||||||
|
@ -7669,6 +7759,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
|
||||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_qSupported],
|
add_packet_config_cmd (&remote_protocol_packets[PACKET_qSupported],
|
||||||
"qSupported", "supported-packets", 0);
|
"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],
|
add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_open],
|
||||||
"vFile:open", "hostio-open", 0);
|
"vFile:open", "hostio-open", 0);
|
||||||
|
|
||||||
|
|
152
gdb/target.c
152
gdb/target.c
|
@ -476,6 +476,7 @@ update_current_target (void)
|
||||||
INHERIT (to_make_corefile_notes, t);
|
INHERIT (to_make_corefile_notes, t);
|
||||||
INHERIT (to_get_thread_local_address, t);
|
INHERIT (to_get_thread_local_address, t);
|
||||||
/* Do not inherit to_read_description. */
|
/* Do not inherit to_read_description. */
|
||||||
|
/* Do not inherit to_search_memory. */
|
||||||
INHERIT (to_magic, t);
|
INHERIT (to_magic, t);
|
||||||
/* Do not inherit to_memory_map. */
|
/* Do not inherit to_memory_map. */
|
||||||
/* Do not inherit to_flash_erase. */
|
/* Do not inherit to_flash_erase. */
|
||||||
|
@ -1760,6 +1761,157 @@ target_read_description (struct target_ops *target)
|
||||||
return NULL;
|
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
|
/* Look through the currently pushed targets. If none of them will
|
||||||
be able to restart the currently running process, issue an error
|
be able to restart the currently running process, issue an error
|
||||||
message. */
|
message. */
|
||||||
|
|
26
gdb/target.h
26
gdb/target.h
|
@ -505,6 +505,17 @@ struct target_ops
|
||||||
int (*to_auxv_parse) (struct target_ops *ops, gdb_byte **readptr,
|
int (*to_auxv_parse) (struct target_ops *ops, gdb_byte **readptr,
|
||||||
gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp);
|
gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp);
|
||||||
|
|
||||||
|
/* 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;
|
int to_magic;
|
||||||
/* Need sub-structure for target machine related rather than comm related?
|
/* Need sub-structure for target machine related rather than comm related?
|
||||||
*/
|
*/
|
||||||
|
@ -1102,6 +1113,21 @@ extern int target_stopped_data_address_p (struct target_ops *);
|
||||||
|
|
||||||
extern const struct target_desc *target_read_description (struct target_ops *);
|
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. */
|
/* Command logging facility. */
|
||||||
|
|
||||||
#define target_log_command(p) \
|
#define target_log_command(p) \
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
2008-05-09 Doug Evans <dje@google.com>
|
||||||
|
|
||||||
|
* testsuite/gdb.base/find.exp: New file.
|
||||||
|
* testsuite/gdb.base/find.c: New file.
|
||||||
|
|
||||||
2008-05-08 Daniel Jacobowitz <dan@codesourcery.com>
|
2008-05-08 Daniel Jacobowitz <dan@codesourcery.com>
|
||||||
|
|
||||||
* gdb.base/commands.exp (watchpoint_command_test): Handle
|
* gdb.base/commands.exp (watchpoint_command_test): Handle
|
||||||
|
|
62
gdb/testsuite/gdb.base/find.c
Normal file
62
gdb/testsuite/gdb.base/find.c
Normal file
|
@ -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;
|
||||||
|
}
|
191
gdb/testsuite/gdb.base/find.exp
Normal file
191
gdb/testsuite/gdb.base/find.exp
Normal file
|
@ -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"
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue