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