Home | History | Annotate | Line # | Download | only in gdb
findcmd.c revision 1.1.1.5
      1 /* The find command.
      2 
      3    Copyright (C) 2008-2019 Free Software Foundation, Inc.
      4 
      5    This file is part of GDB.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19 
     20 #include "defs.h"
     21 #include "arch-utils.h"
     22 #include <ctype.h>
     23 #include "gdbcmd.h"
     24 #include "value.h"
     25 #include "target.h"
     26 #include "cli/cli-utils.h"
     27 #include <algorithm>
     28 #include "common/byte-vector.h"
     29 
     30 /* Copied from bfd_put_bits.  */
     31 
     32 static void
     33 put_bits (bfd_uint64_t data, gdb::byte_vector &buf, int bits, bfd_boolean big_p)
     34 {
     35   int i;
     36   int bytes;
     37 
     38   gdb_assert (bits % 8 == 0);
     39 
     40   bytes = bits / 8;
     41   size_t last = buf.size ();
     42   buf.resize (last + bytes);
     43   for (i = 0; i < bytes; i++)
     44     {
     45       int index = big_p ? bytes - i - 1 : i;
     46 
     47       buf[last + index] = data & 0xff;
     48       data >>= 8;
     49     }
     50 }
     51 
     52 /* Subroutine of find_command to simplify it.
     53    Parse the arguments of the "find" command.  */
     54 
     55 static gdb::byte_vector
     56 parse_find_args (const char *args, ULONGEST *max_countp,
     57 		 CORE_ADDR *start_addrp, ULONGEST *search_space_lenp,
     58 		 bfd_boolean big_p)
     59 {
     60   /* Default to using the specified type.  */
     61   char size = '\0';
     62   ULONGEST max_count = ~(ULONGEST) 0;
     63   /* Buffer to hold the search pattern.  */
     64   gdb::byte_vector pattern_buf;
     65   CORE_ADDR start_addr;
     66   ULONGEST search_space_len;
     67   const char *s = args;
     68   struct value *v;
     69 
     70   if (args == NULL)
     71     error (_("Missing search parameters."));
     72 
     73   /* Get search granularity and/or max count if specified.
     74      They may be specified in either order, together or separately.  */
     75 
     76   while (*s == '/')
     77     {
     78       ++s;
     79 
     80       while (*s != '\0' && *s != '/' && !isspace (*s))
     81 	{
     82 	  if (isdigit (*s))
     83 	    {
     84 	      max_count = atoi (s);
     85 	      while (isdigit (*s))
     86 		++s;
     87 	      continue;
     88 	    }
     89 
     90 	  switch (*s)
     91 	    {
     92 	    case 'b':
     93 	    case 'h':
     94 	    case 'w':
     95 	    case 'g':
     96 	      size = *s++;
     97 	      break;
     98 	    default:
     99 	      error (_("Invalid size granularity."));
    100 	    }
    101 	}
    102 
    103       s = skip_spaces (s);
    104     }
    105 
    106   /* Get the search range.  */
    107 
    108   v = parse_to_comma_and_eval (&s);
    109   start_addr = value_as_address (v);
    110 
    111   if (*s == ',')
    112     ++s;
    113   s = skip_spaces (s);
    114 
    115   if (*s == '+')
    116     {
    117       LONGEST len;
    118 
    119       ++s;
    120       v = parse_to_comma_and_eval (&s);
    121       len = value_as_long (v);
    122       if (len == 0)
    123 	{
    124 	  printf_filtered (_("Empty search range.\n"));
    125 	  return pattern_buf;
    126 	}
    127       if (len < 0)
    128 	error (_("Invalid length."));
    129       /* Watch for overflows.  */
    130       if (len > CORE_ADDR_MAX
    131 	  || (start_addr + len - 1) < start_addr)
    132 	error (_("Search space too large."));
    133       search_space_len = len;
    134     }
    135   else
    136     {
    137       CORE_ADDR end_addr;
    138 
    139       v = parse_to_comma_and_eval (&s);
    140       end_addr = value_as_address (v);
    141       if (start_addr > end_addr)
    142 	error (_("Invalid search space, end precedes start."));
    143       search_space_len = end_addr - start_addr + 1;
    144       /* We don't support searching all of memory
    145 	 (i.e. start=0, end = 0xff..ff).
    146 	 Bail to avoid overflows later on.  */
    147       if (search_space_len == 0)
    148 	error (_("Overflow in address range "
    149 		 "computation, choose smaller range."));
    150     }
    151 
    152   if (*s == ',')
    153     ++s;
    154 
    155   /* Fetch the search string.  */
    156 
    157   while (*s != '\0')
    158     {
    159       LONGEST x;
    160       struct type *t;
    161 
    162       s = skip_spaces (s);
    163 
    164       v = parse_to_comma_and_eval (&s);
    165       t = value_type (v);
    166 
    167       if (size != '\0')
    168 	{
    169 	  x = value_as_long (v);
    170 	  switch (size)
    171 	    {
    172 	    case 'b':
    173 	      pattern_buf.push_back (x);
    174 	      break;
    175 	    case 'h':
    176 	      put_bits (x, pattern_buf, 16, big_p);
    177 	      break;
    178 	    case 'w':
    179 	      put_bits (x, pattern_buf, 32, big_p);
    180 	      break;
    181 	    case 'g':
    182 	      put_bits (x, pattern_buf, 64, big_p);
    183 	      break;
    184 	    }
    185 	}
    186       else
    187 	{
    188 	  const gdb_byte *contents = value_contents (v);
    189 	  pattern_buf.insert (pattern_buf.end (), contents,
    190 			      contents + TYPE_LENGTH (t));
    191 	}
    192 
    193       if (*s == ',')
    194 	++s;
    195       s = skip_spaces (s);
    196     }
    197 
    198   if (pattern_buf.empty ())
    199     error (_("Missing search pattern."));
    200 
    201   if (search_space_len < pattern_buf.size ())
    202     error (_("Search space too small to contain pattern."));
    203 
    204   *max_countp = max_count;
    205   *start_addrp = start_addr;
    206   *search_space_lenp = search_space_len;
    207 
    208   return pattern_buf;
    209 }
    210 
    211 static void
    212 find_command (const char *args, int from_tty)
    213 {
    214   struct gdbarch *gdbarch = get_current_arch ();
    215   bfd_boolean big_p = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG;
    216   /* Command line parameters.
    217      These are initialized to avoid uninitialized warnings from -Wall.  */
    218   ULONGEST max_count = 0;
    219   CORE_ADDR start_addr = 0;
    220   ULONGEST search_space_len = 0;
    221   /* End of command line parameters.  */
    222   unsigned int found_count;
    223   CORE_ADDR last_found_addr;
    224 
    225   gdb::byte_vector pattern_buf = parse_find_args (args, &max_count,
    226 						  &start_addr,
    227 						  &search_space_len,
    228 						  big_p);
    229 
    230   /* Perform the search.  */
    231 
    232   found_count = 0;
    233   last_found_addr = 0;
    234 
    235   while (search_space_len >= pattern_buf.size ()
    236 	 && found_count < max_count)
    237     {
    238       /* Offset from start of this iteration to the next iteration.  */
    239       ULONGEST next_iter_incr;
    240       CORE_ADDR found_addr;
    241       int found = target_search_memory (start_addr, search_space_len,
    242 					pattern_buf.data (),
    243 					pattern_buf.size (),
    244 					&found_addr);
    245 
    246       if (found <= 0)
    247 	break;
    248 
    249       print_address (gdbarch, found_addr, gdb_stdout);
    250       printf_filtered ("\n");
    251       ++found_count;
    252       last_found_addr = found_addr;
    253 
    254       /* Begin next iteration at one byte past this match.  */
    255       next_iter_incr = (found_addr - start_addr) + 1;
    256 
    257       /* For robustness, we don't let search_space_len go -ve here.  */
    258       if (search_space_len >= next_iter_incr)
    259 	search_space_len -= next_iter_incr;
    260       else
    261 	search_space_len = 0;
    262       start_addr += next_iter_incr;
    263     }
    264 
    265   /* Record and print the results.  */
    266 
    267   set_internalvar_integer (lookup_internalvar ("numfound"), found_count);
    268   if (found_count > 0)
    269     {
    270       struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
    271 
    272       set_internalvar (lookup_internalvar ("_"),
    273 		       value_from_pointer (ptr_type, last_found_addr));
    274     }
    275 
    276   if (found_count == 0)
    277     printf_filtered ("Pattern not found.\n");
    278   else
    279     printf_filtered ("%d pattern%s found.\n", found_count,
    280 		     found_count > 1 ? "s" : "");
    281 }
    282 
    283 void
    284 _initialize_mem_search (void)
    285 {
    286   add_cmd ("find", class_vars, find_command, _("\
    287 Search memory for a sequence of bytes.\n\
    288 Usage:\nfind \
    289 [/SIZE-CHAR] [/MAX-COUNT] START-ADDRESS, END-ADDRESS, EXPR1 [, EXPR2 ...]\n\
    290 find [/SIZE-CHAR] [/MAX-COUNT] START-ADDRESS, +LENGTH, EXPR1 [, EXPR2 ...]\n\
    291 SIZE-CHAR is one of b,h,w,g for 8,16,32,64 bit values respectively,\n\
    292 and if not specified the size is taken from the type of the expression\n\
    293 in the current language.\n\
    294 Note that this means for example that in the case of C-like languages\n\
    295 a search for an untyped 0x42 will search for \"(int) 0x42\"\n\
    296 which is typically four bytes, and a search for a string \"hello\" will\n\
    297 include the trailing '\\0'.  The null terminator can be removed from\n\
    298 searching by using casts, e.g.: {char[5]}\"hello\".\n\
    299 \n\
    300 The address of the last match is stored as the value of \"$_\".\n\
    301 Convenience variable \"$numfound\" is set to the number of matches."),
    302 	   &cmdlist);
    303 }
    304