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
@ -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>
|
||||
|
||||
* 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 \
|
||||
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 \
|
||||
@ -1061,6 +1060,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
|
||||
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 \
|
||||
@ -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) \
|
||||
$(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) \
|
||||
|
9
gdb/NEWS
9
gdb/NEWS
@ -3,6 +3,11 @@
|
||||
|
||||
*** 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
|
||||
source+assembly.
|
||||
|
||||
@ -35,6 +40,10 @@ have also been fixed.
|
||||
|
||||
* 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
|
||||
show debug timestamp
|
||||
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>
|
||||
|
||||
* gdb.texinfo (disassemble): Document /m modifier.
|
||||
|
@ -5590,6 +5590,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
|
||||
@ -7653,6 +7654,104 @@ state (dirty, bad, ok, etc.). This command is useful for debugging
|
||||
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@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
|
||||
@chapter C Preprocessor Macros
|
||||
@ -13496,6 +13595,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
|
||||
@ -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
|
||||
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
|
||||
|
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>
|
||||
|
||||
* regcache.c (registers_length): Remove.
|
||||
|
@ -1080,6 +1080,24 @@ decode_xfer_write (char *buf, int packet_len, char **annex, CORE_ADDR *offset,
|
||||
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. */
|
||||
|
||||
|
@ -314,6 +314,153 @@ 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 +878,13 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||
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;
|
||||
|
@ -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,
|
||||
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);
|
||||
|
93
gdb/remote.c
93
gdb/remote.c
@ -935,6 +935,7 @@ enum {
|
||||
PACKET_qGetTLSAddr,
|
||||
PACKET_qSupported,
|
||||
PACKET_QPassSignals,
|
||||
PACKET_qSearch_memory,
|
||||
PACKET_vAttach,
|
||||
PACKET_vRun,
|
||||
PACKET_MAX
|
||||
@ -6195,6 +6196,93 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
|
||||
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)
|
||||
@ -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_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;
|
||||
}
|
||||
@ -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_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
|
||||
@ -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],
|
||||
"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);
|
||||
|
||||
|
152
gdb/target.c
152
gdb/target.c
@ -476,6 +476,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. */
|
||||
@ -1760,6 +1761,157 @@ target_read_description (struct target_ops *target)
|
||||
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. */
|
||||
|
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,
|
||||
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;
|
||||
/* 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 *);
|
||||
|
||||
/* 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) \
|
||||
|
@ -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>
|
||||
|
||||
* 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…
x
Reference in New Issue
Block a user