diff options
author | Doug Evans <dje@google.com> | 2008-05-09 17:02:03 +0000 |
---|---|---|
committer | Doug Evans <dje@google.com> | 2008-05-09 17:02:03 +0000 |
commit | 08388c79d5a8553465b2de881bed15766837735c (patch) | |
tree | 1c0af907d5caa5836541d62803dd1775c683913c /gdb/findcmd.c | |
parent | 7010a0c9019a68999ca6e43b4eec8b28d0907cbc (diff) | |
download | gdb-08388c79d5a8553465b2de881bed15766837735c.zip gdb-08388c79d5a8553465b2de881bed15766837735c.tar.gz gdb-08388c79d5a8553465b2de881bed15766837735c.tar.bz2 |
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.
Diffstat (limited to 'gdb/findcmd.c')
-rw-r--r-- | gdb/findcmd.c | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/gdb/findcmd.c b/gdb/findcmd.c new file mode 100644 index 0000000..dfb746b --- /dev/null +++ b/gdb/findcmd.c @@ -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); +} |