xref: /dflybsd-src/contrib/gdb-7/gdb/findcmd.c (revision a45ae5f869d9cfcb3e41dbab486e10bfa9e336bf)
15796c8dcSSimon Schubert /* The find command.
25796c8dcSSimon Schubert 
3*a45ae5f8SJohn Marino    Copyright (C) 2008-2012 Free Software Foundation, Inc.
45796c8dcSSimon Schubert 
55796c8dcSSimon Schubert    This file is part of GDB.
65796c8dcSSimon Schubert 
75796c8dcSSimon Schubert    This program is free software; you can redistribute it and/or modify
85796c8dcSSimon Schubert    it under the terms of the GNU General Public License as published by
95796c8dcSSimon Schubert    the Free Software Foundation; either version 3 of the License, or
105796c8dcSSimon Schubert    (at your option) any later version.
115796c8dcSSimon Schubert 
125796c8dcSSimon Schubert    This program is distributed in the hope that it will be useful,
135796c8dcSSimon Schubert    but WITHOUT ANY WARRANTY; without even the implied warranty of
145796c8dcSSimon Schubert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
155796c8dcSSimon Schubert    GNU General Public License for more details.
165796c8dcSSimon Schubert 
175796c8dcSSimon Schubert    You should have received a copy of the GNU General Public License
185796c8dcSSimon Schubert    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
195796c8dcSSimon Schubert 
205796c8dcSSimon Schubert #include "defs.h"
215796c8dcSSimon Schubert #include "arch-utils.h"
225796c8dcSSimon Schubert #include <ctype.h>
235796c8dcSSimon Schubert #include "gdb_string.h"
245796c8dcSSimon Schubert #include "gdbcmd.h"
255796c8dcSSimon Schubert #include "value.h"
265796c8dcSSimon Schubert #include "target.h"
275796c8dcSSimon Schubert 
285796c8dcSSimon Schubert /* Copied from bfd_put_bits.  */
295796c8dcSSimon Schubert 
305796c8dcSSimon Schubert static void
315796c8dcSSimon Schubert put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p)
325796c8dcSSimon Schubert {
335796c8dcSSimon Schubert   int i;
345796c8dcSSimon Schubert   int bytes;
355796c8dcSSimon Schubert 
365796c8dcSSimon Schubert   gdb_assert (bits % 8 == 0);
375796c8dcSSimon Schubert 
385796c8dcSSimon Schubert   bytes = bits / 8;
395796c8dcSSimon Schubert   for (i = 0; i < bytes; i++)
405796c8dcSSimon Schubert     {
415796c8dcSSimon Schubert       int index = big_p ? bytes - i - 1 : i;
425796c8dcSSimon Schubert 
435796c8dcSSimon Schubert       buf[index] = data & 0xff;
445796c8dcSSimon Schubert       data >>= 8;
455796c8dcSSimon Schubert     }
465796c8dcSSimon Schubert }
475796c8dcSSimon Schubert 
485796c8dcSSimon Schubert /* Subroutine of find_command to simplify it.
495796c8dcSSimon Schubert    Parse the arguments of the "find" command.  */
505796c8dcSSimon Schubert 
515796c8dcSSimon Schubert static void
525796c8dcSSimon Schubert parse_find_args (char *args, ULONGEST *max_countp,
535796c8dcSSimon Schubert 		 char **pattern_bufp, ULONGEST *pattern_lenp,
545796c8dcSSimon Schubert 		 CORE_ADDR *start_addrp, ULONGEST *search_space_lenp,
555796c8dcSSimon Schubert 		 bfd_boolean big_p)
565796c8dcSSimon Schubert {
575796c8dcSSimon Schubert   /* Default to using the specified type.  */
585796c8dcSSimon Schubert   char size = '\0';
595796c8dcSSimon Schubert   ULONGEST max_count = ~(ULONGEST) 0;
605796c8dcSSimon Schubert   /* Buffer to hold the search pattern.  */
615796c8dcSSimon Schubert   char *pattern_buf;
625796c8dcSSimon Schubert   /* Current size of search pattern buffer.
635796c8dcSSimon Schubert      We realloc space as needed.  */
645796c8dcSSimon Schubert #define INITIAL_PATTERN_BUF_SIZE 100
655796c8dcSSimon Schubert   ULONGEST pattern_buf_size = INITIAL_PATTERN_BUF_SIZE;
665796c8dcSSimon Schubert   /* Pointer to one past the last in-use part of pattern_buf.  */
675796c8dcSSimon Schubert   char *pattern_buf_end;
685796c8dcSSimon Schubert   ULONGEST pattern_len;
695796c8dcSSimon Schubert   CORE_ADDR start_addr;
705796c8dcSSimon Schubert   ULONGEST search_space_len;
715796c8dcSSimon Schubert   char *s = args;
725796c8dcSSimon Schubert   struct cleanup *old_cleanups;
735796c8dcSSimon Schubert   struct value *v;
745796c8dcSSimon Schubert 
755796c8dcSSimon Schubert   if (args == NULL)
765796c8dcSSimon Schubert     error (_("Missing search parameters."));
775796c8dcSSimon Schubert 
785796c8dcSSimon Schubert   pattern_buf = xmalloc (pattern_buf_size);
795796c8dcSSimon Schubert   pattern_buf_end = pattern_buf;
805796c8dcSSimon Schubert   old_cleanups = make_cleanup (free_current_contents, &pattern_buf);
815796c8dcSSimon Schubert 
825796c8dcSSimon Schubert   /* Get search granularity and/or max count if specified.
835796c8dcSSimon Schubert      They may be specified in either order, together or separately.  */
845796c8dcSSimon Schubert 
855796c8dcSSimon Schubert   while (*s == '/')
865796c8dcSSimon Schubert     {
875796c8dcSSimon Schubert       ++s;
885796c8dcSSimon Schubert 
895796c8dcSSimon Schubert       while (*s != '\0' && *s != '/' && !isspace (*s))
905796c8dcSSimon Schubert 	{
915796c8dcSSimon Schubert 	  if (isdigit (*s))
925796c8dcSSimon Schubert 	    {
935796c8dcSSimon Schubert 	      max_count = atoi (s);
945796c8dcSSimon Schubert 	      while (isdigit (*s))
955796c8dcSSimon Schubert 		++s;
965796c8dcSSimon Schubert 	      continue;
975796c8dcSSimon Schubert 	    }
985796c8dcSSimon Schubert 
995796c8dcSSimon Schubert 	  switch (*s)
1005796c8dcSSimon Schubert 	    {
1015796c8dcSSimon Schubert 	    case 'b':
1025796c8dcSSimon Schubert 	    case 'h':
1035796c8dcSSimon Schubert 	    case 'w':
1045796c8dcSSimon Schubert 	    case 'g':
1055796c8dcSSimon Schubert 	      size = *s++;
1065796c8dcSSimon Schubert 	      break;
1075796c8dcSSimon Schubert 	    default:
1085796c8dcSSimon Schubert 	      error (_("Invalid size granularity."));
1095796c8dcSSimon Schubert 	    }
1105796c8dcSSimon Schubert 	}
1115796c8dcSSimon Schubert 
1125796c8dcSSimon Schubert       while (isspace (*s))
1135796c8dcSSimon Schubert 	++s;
1145796c8dcSSimon Schubert     }
1155796c8dcSSimon Schubert 
1165796c8dcSSimon Schubert   /* Get the search range.  */
1175796c8dcSSimon Schubert 
1185796c8dcSSimon Schubert   v = parse_to_comma_and_eval (&s);
1195796c8dcSSimon Schubert   start_addr = value_as_address (v);
1205796c8dcSSimon Schubert 
1215796c8dcSSimon Schubert   if (*s == ',')
1225796c8dcSSimon Schubert     ++s;
1235796c8dcSSimon Schubert   while (isspace (*s))
1245796c8dcSSimon Schubert     ++s;
1255796c8dcSSimon Schubert 
1265796c8dcSSimon Schubert   if (*s == '+')
1275796c8dcSSimon Schubert     {
1285796c8dcSSimon Schubert       LONGEST len;
129cf7f2e2dSJohn Marino 
1305796c8dcSSimon Schubert       ++s;
1315796c8dcSSimon Schubert       v = parse_to_comma_and_eval (&s);
1325796c8dcSSimon Schubert       len = value_as_long (v);
1335796c8dcSSimon Schubert       if (len == 0)
1345796c8dcSSimon Schubert 	{
135*a45ae5f8SJohn Marino 	  do_cleanups (old_cleanups);
1365796c8dcSSimon Schubert 	  printf_filtered (_("Empty search range.\n"));
1375796c8dcSSimon Schubert 	  return;
1385796c8dcSSimon Schubert 	}
1395796c8dcSSimon Schubert       if (len < 0)
1405796c8dcSSimon Schubert 	error (_("Invalid length."));
1415796c8dcSSimon Schubert       /* Watch for overflows.  */
1425796c8dcSSimon Schubert       if (len > CORE_ADDR_MAX
1435796c8dcSSimon Schubert 	  || (start_addr + len - 1) < start_addr)
1445796c8dcSSimon Schubert 	error (_("Search space too large."));
1455796c8dcSSimon Schubert       search_space_len = len;
1465796c8dcSSimon Schubert     }
1475796c8dcSSimon Schubert   else
1485796c8dcSSimon Schubert     {
1495796c8dcSSimon Schubert       CORE_ADDR end_addr;
150cf7f2e2dSJohn Marino 
1515796c8dcSSimon Schubert       v = parse_to_comma_and_eval (&s);
1525796c8dcSSimon Schubert       end_addr = value_as_address (v);
1535796c8dcSSimon Schubert       if (start_addr > end_addr)
154*a45ae5f8SJohn Marino 	error (_("Invalid search space, end precedes start."));
1555796c8dcSSimon Schubert       search_space_len = end_addr - start_addr + 1;
1565796c8dcSSimon Schubert       /* We don't support searching all of memory
1575796c8dcSSimon Schubert 	 (i.e. start=0, end = 0xff..ff).
1585796c8dcSSimon Schubert 	 Bail to avoid overflows later on.  */
1595796c8dcSSimon Schubert       if (search_space_len == 0)
160c50c785cSJohn Marino 	error (_("Overflow in address range "
161c50c785cSJohn Marino 		 "computation, choose smaller range."));
1625796c8dcSSimon Schubert     }
1635796c8dcSSimon Schubert 
1645796c8dcSSimon Schubert   if (*s == ',')
1655796c8dcSSimon Schubert     ++s;
1665796c8dcSSimon Schubert 
1675796c8dcSSimon Schubert   /* Fetch the search string.  */
1685796c8dcSSimon Schubert 
1695796c8dcSSimon Schubert   while (*s != '\0')
1705796c8dcSSimon Schubert     {
1715796c8dcSSimon Schubert       LONGEST x;
1725796c8dcSSimon Schubert       int val_bytes;
1735796c8dcSSimon Schubert 
1745796c8dcSSimon Schubert       while (isspace (*s))
1755796c8dcSSimon Schubert 	++s;
1765796c8dcSSimon Schubert 
1775796c8dcSSimon Schubert       v = parse_to_comma_and_eval (&s);
1785796c8dcSSimon Schubert       val_bytes = TYPE_LENGTH (value_type (v));
1795796c8dcSSimon Schubert 
1805796c8dcSSimon Schubert       /* Keep it simple and assume size == 'g' when watching for when we
1815796c8dcSSimon Schubert 	 need to grow the pattern buf.  */
1825796c8dcSSimon Schubert       if ((pattern_buf_end - pattern_buf + max (val_bytes, sizeof (int64_t)))
1835796c8dcSSimon Schubert 	  > pattern_buf_size)
1845796c8dcSSimon Schubert 	{
1855796c8dcSSimon Schubert 	  size_t current_offset = pattern_buf_end - pattern_buf;
186cf7f2e2dSJohn Marino 
1875796c8dcSSimon Schubert 	  pattern_buf_size *= 2;
1885796c8dcSSimon Schubert 	  pattern_buf = xrealloc (pattern_buf, pattern_buf_size);
1895796c8dcSSimon Schubert 	  pattern_buf_end = pattern_buf + current_offset;
1905796c8dcSSimon Schubert 	}
1915796c8dcSSimon Schubert 
1925796c8dcSSimon Schubert       if (size != '\0')
1935796c8dcSSimon Schubert 	{
1945796c8dcSSimon Schubert 	  x = value_as_long (v);
1955796c8dcSSimon Schubert 	  switch (size)
1965796c8dcSSimon Schubert 	    {
1975796c8dcSSimon Schubert 	    case 'b':
1985796c8dcSSimon Schubert 	      *pattern_buf_end++ = x;
1995796c8dcSSimon Schubert 	      break;
2005796c8dcSSimon Schubert 	    case 'h':
2015796c8dcSSimon Schubert 	      put_bits (x, pattern_buf_end, 16, big_p);
2025796c8dcSSimon Schubert 	      pattern_buf_end += sizeof (int16_t);
2035796c8dcSSimon Schubert 	      break;
2045796c8dcSSimon Schubert 	    case 'w':
2055796c8dcSSimon Schubert 	      put_bits (x, pattern_buf_end, 32, big_p);
2065796c8dcSSimon Schubert 	      pattern_buf_end += sizeof (int32_t);
2075796c8dcSSimon Schubert 	      break;
2085796c8dcSSimon Schubert 	    case 'g':
2095796c8dcSSimon Schubert 	      put_bits (x, pattern_buf_end, 64, big_p);
2105796c8dcSSimon Schubert 	      pattern_buf_end += sizeof (int64_t);
2115796c8dcSSimon Schubert 	      break;
2125796c8dcSSimon Schubert 	    }
2135796c8dcSSimon Schubert 	}
2145796c8dcSSimon Schubert       else
2155796c8dcSSimon Schubert 	{
216cf7f2e2dSJohn Marino 	  memcpy (pattern_buf_end, value_contents (v), val_bytes);
2175796c8dcSSimon Schubert 	  pattern_buf_end += val_bytes;
2185796c8dcSSimon Schubert 	}
2195796c8dcSSimon Schubert 
2205796c8dcSSimon Schubert       if (*s == ',')
2215796c8dcSSimon Schubert 	++s;
2225796c8dcSSimon Schubert       while (isspace (*s))
2235796c8dcSSimon Schubert 	++s;
2245796c8dcSSimon Schubert     }
2255796c8dcSSimon Schubert 
2265796c8dcSSimon Schubert   if (pattern_buf_end == pattern_buf)
2275796c8dcSSimon Schubert     error (_("Missing search pattern."));
2285796c8dcSSimon Schubert 
2295796c8dcSSimon Schubert   pattern_len = pattern_buf_end - pattern_buf;
2305796c8dcSSimon Schubert 
2315796c8dcSSimon Schubert   if (search_space_len < pattern_len)
2325796c8dcSSimon Schubert     error (_("Search space too small to contain pattern."));
2335796c8dcSSimon Schubert 
2345796c8dcSSimon Schubert   *max_countp = max_count;
2355796c8dcSSimon Schubert   *pattern_bufp = pattern_buf;
2365796c8dcSSimon Schubert   *pattern_lenp = pattern_len;
2375796c8dcSSimon Schubert   *start_addrp = start_addr;
2385796c8dcSSimon Schubert   *search_space_lenp = search_space_len;
2395796c8dcSSimon Schubert 
2405796c8dcSSimon Schubert   /* We successfully parsed the arguments, leave the freeing of PATTERN_BUF
2415796c8dcSSimon Schubert      to the caller now.  */
2425796c8dcSSimon Schubert   discard_cleanups (old_cleanups);
2435796c8dcSSimon Schubert }
2445796c8dcSSimon Schubert 
2455796c8dcSSimon Schubert static void
2465796c8dcSSimon Schubert find_command (char *args, int from_tty)
2475796c8dcSSimon Schubert {
2485796c8dcSSimon Schubert   struct gdbarch *gdbarch = get_current_arch ();
2495796c8dcSSimon Schubert   bfd_boolean big_p = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG;
2505796c8dcSSimon Schubert   /* Command line parameters.
2515796c8dcSSimon Schubert      These are initialized to avoid uninitialized warnings from -Wall.  */
2525796c8dcSSimon Schubert   ULONGEST max_count = 0;
2535796c8dcSSimon Schubert   char *pattern_buf = 0;
2545796c8dcSSimon Schubert   ULONGEST pattern_len = 0;
2555796c8dcSSimon Schubert   CORE_ADDR start_addr = 0;
2565796c8dcSSimon Schubert   ULONGEST search_space_len = 0;
2575796c8dcSSimon Schubert   /* End of command line parameters.  */
2585796c8dcSSimon Schubert   unsigned int found_count;
2595796c8dcSSimon Schubert   CORE_ADDR last_found_addr;
2605796c8dcSSimon Schubert   struct cleanup *old_cleanups;
2615796c8dcSSimon Schubert 
2625796c8dcSSimon Schubert   parse_find_args (args, &max_count, &pattern_buf, &pattern_len,
2635796c8dcSSimon Schubert 		   &start_addr, &search_space_len, big_p);
2645796c8dcSSimon Schubert 
2655796c8dcSSimon Schubert   old_cleanups = make_cleanup (free_current_contents, &pattern_buf);
2665796c8dcSSimon Schubert 
2675796c8dcSSimon Schubert   /* Perform the search.  */
2685796c8dcSSimon Schubert 
2695796c8dcSSimon Schubert   found_count = 0;
2705796c8dcSSimon Schubert   last_found_addr = 0;
2715796c8dcSSimon Schubert 
2725796c8dcSSimon Schubert   while (search_space_len >= pattern_len
2735796c8dcSSimon Schubert 	 && found_count < max_count)
2745796c8dcSSimon Schubert     {
2755796c8dcSSimon Schubert       /* Offset from start of this iteration to the next iteration.  */
2765796c8dcSSimon Schubert       ULONGEST next_iter_incr;
2775796c8dcSSimon Schubert       CORE_ADDR found_addr;
2785796c8dcSSimon Schubert       int found = target_search_memory (start_addr, search_space_len,
2795796c8dcSSimon Schubert 					pattern_buf, pattern_len, &found_addr);
2805796c8dcSSimon Schubert 
2815796c8dcSSimon Schubert       if (found <= 0)
2825796c8dcSSimon Schubert 	break;
2835796c8dcSSimon Schubert 
2845796c8dcSSimon Schubert       print_address (gdbarch, found_addr, gdb_stdout);
2855796c8dcSSimon Schubert       printf_filtered ("\n");
2865796c8dcSSimon Schubert       ++found_count;
2875796c8dcSSimon Schubert       last_found_addr = found_addr;
2885796c8dcSSimon Schubert 
2895796c8dcSSimon Schubert       /* Begin next iteration at one byte past this match.  */
2905796c8dcSSimon Schubert       next_iter_incr = (found_addr - start_addr) + 1;
2915796c8dcSSimon Schubert 
2925796c8dcSSimon Schubert       /* For robustness, we don't let search_space_len go -ve here.  */
2935796c8dcSSimon Schubert       if (search_space_len >= next_iter_incr)
2945796c8dcSSimon Schubert 	search_space_len -= next_iter_incr;
2955796c8dcSSimon Schubert       else
2965796c8dcSSimon Schubert 	search_space_len = 0;
2975796c8dcSSimon Schubert       start_addr += next_iter_incr;
2985796c8dcSSimon Schubert     }
2995796c8dcSSimon Schubert 
3005796c8dcSSimon Schubert   /* Record and print the results.  */
3015796c8dcSSimon Schubert 
3025796c8dcSSimon Schubert   set_internalvar_integer (lookup_internalvar ("numfound"), found_count);
3035796c8dcSSimon Schubert   if (found_count > 0)
3045796c8dcSSimon Schubert     {
3055796c8dcSSimon Schubert       struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
306cf7f2e2dSJohn Marino 
3075796c8dcSSimon Schubert       set_internalvar (lookup_internalvar ("_"),
3085796c8dcSSimon Schubert 		       value_from_pointer (ptr_type, last_found_addr));
3095796c8dcSSimon Schubert     }
3105796c8dcSSimon Schubert 
3115796c8dcSSimon Schubert   if (found_count == 0)
3125796c8dcSSimon Schubert     printf_filtered ("Pattern not found.\n");
3135796c8dcSSimon Schubert   else
3145796c8dcSSimon Schubert     printf_filtered ("%d pattern%s found.\n", found_count,
3155796c8dcSSimon Schubert 		     found_count > 1 ? "s" : "");
3165796c8dcSSimon Schubert 
3175796c8dcSSimon Schubert   do_cleanups (old_cleanups);
3185796c8dcSSimon Schubert }
3195796c8dcSSimon Schubert 
3205796c8dcSSimon Schubert /* Provide a prototype to silence -Wmissing-prototypes.  */
3215796c8dcSSimon Schubert extern initialize_file_ftype _initialize_mem_search;
3225796c8dcSSimon Schubert 
3235796c8dcSSimon Schubert void
3245796c8dcSSimon Schubert _initialize_mem_search (void)
3255796c8dcSSimon Schubert {
3265796c8dcSSimon Schubert   add_cmd ("find", class_vars, find_command, _("\
3275796c8dcSSimon Schubert Search memory for a sequence of bytes.\n\
328c50c785cSJohn Marino Usage:\nfind \
329c50c785cSJohn Marino [/size-char] [/max-count] start-address, end-address, expr1 [, expr2 ...]\n\
3305796c8dcSSimon Schubert find [/size-char] [/max-count] start-address, +length, expr1 [, expr2 ...]\n\
3315796c8dcSSimon Schubert size-char is one of b,h,w,g for 8,16,32,64 bit values respectively,\n\
3325796c8dcSSimon Schubert and if not specified the size is taken from the type of the expression\n\
3335796c8dcSSimon Schubert in the current language.\n\
3345796c8dcSSimon Schubert Note that this means for example that in the case of C-like languages\n\
3355796c8dcSSimon Schubert a search for an untyped 0x42 will search for \"(int) 0x42\"\n\
3365796c8dcSSimon Schubert which is typically four bytes.\n\
3375796c8dcSSimon Schubert \n\
3385796c8dcSSimon Schubert The address of the last match is stored as the value of \"$_\".\n\
3395796c8dcSSimon Schubert Convenience variable \"$numfound\" is set to the number of matches."),
3405796c8dcSSimon Schubert 	   &cmdlist);
3415796c8dcSSimon Schubert }
342