/* Target memory searching Copyright (C) 2020-2023 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 . */ #include "gdbsupport/common-defs.h" #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 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; }