| /* Target memory searching | 
 |  | 
 |    Copyright (C) 2020-2025 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 "gdbsupport/search.h" | 
 | #include "gdbsupport/byte-vector.h" | 
 |  | 
 | /* 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 | 
 |   (gdb::function_view<target_read_memory_ftype> read_memory, | 
 |    CORE_ADDR start_addr, ULONGEST search_space_len, | 
 |    const gdb_byte *pattern, ULONGEST pattern_len, | 
 |    CORE_ADDR *found_addrp) | 
 | { | 
 |   const unsigned chunk_size = SEARCH_CHUNK_SIZE; | 
 |   /* Buffer to hold memory contents for searching.  */ | 
 |   unsigned search_buf_size; | 
 |  | 
 |   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; | 
 |  | 
 |   gdb::byte_vector search_buf (search_buf_size); | 
 |  | 
 |   /* Prime the search buffer.  */ | 
 |  | 
 |   if (!read_memory (start_addr, search_buf.data (), search_buf_size)) | 
 |     { | 
 |       warning (_("Unable to access %s bytes of target " | 
 | 		 "memory at %s, halting search."), | 
 | 	       pulongest (search_buf_size), hex_string (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 | 
 | 	= std::min (search_space_len, (ULONGEST) search_buf_size); | 
 |  | 
 |       found_ptr = (gdb_byte *) memmem (search_buf.data (), nr_search_bytes, | 
 | 				       pattern, pattern_len); | 
 |  | 
 |       if (found_ptr != NULL) | 
 | 	{ | 
 | 	  CORE_ADDR found_addr = start_addr + (found_ptr - search_buf.data ()); | 
 |  | 
 | 	  *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 + chunk_size + 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); | 
 | 	  if (keep_len > 0) | 
 | 	    memcpy (&search_buf[0], &search_buf[chunk_size], keep_len); | 
 |  | 
 | 	  nr_to_read = std::min (search_space_len - keep_len, | 
 | 				 (ULONGEST) chunk_size); | 
 |  | 
 | 	  if (!read_memory (read_addr, &search_buf[keep_len], nr_to_read)) | 
 | 	    { | 
 | 	      warning (_("Unable to access %s bytes of target " | 
 | 			 "memory at %s, halting search."), | 
 | 		       plongest (nr_to_read), | 
 | 		       hex_string (read_addr)); | 
 | 	      return -1; | 
 | 	    } | 
 |  | 
 | 	  start_addr += chunk_size; | 
 | 	} | 
 |     } | 
 |  | 
 |   /* Not found.  */ | 
 |  | 
 |   return 0; | 
 | } |