aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbserver/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/gdbserver/server.c')
-rw-r--r--gdb/gdbserver/server.c154
1 files changed, 154 insertions, 0 deletions
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 852a0bd..6993ae3 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -314,6 +314,153 @@ monitor_show_help (void)
monitor_output (" Quit GDBserver\n");
}
+/* Subroutine of handle_search_memory to simplify it. */
+
+static int
+handle_search_memory_1 (CORE_ADDR start_addr, CORE_ADDR search_space_len,
+ gdb_byte *pattern, unsigned pattern_len,
+ gdb_byte *search_buf,
+ unsigned chunk_size, unsigned search_buf_size,
+ CORE_ADDR *found_addrp)
+{
+ /* Prime the search buffer. */
+
+ if (read_inferior_memory (start_addr, search_buf, search_buf_size) != 0)
+ {
+ warning ("unable to access target memory at 0x%lx, halting search",
+ (long) 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 = (search_space_len < search_buf_size
+ ? search_space_len
+ : search_buf_size);
+
+ found_ptr = memmem (search_buf, nr_search_bytes, pattern, pattern_len);
+
+ if (found_ptr != NULL)
+ {
+ CORE_ADDR found_addr = start_addr + (found_ptr - search_buf);
+ *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 + keep_len;
+ int nr_to_read;
+
+ /* Copy the trailing part of the previous iteration to the front
+ of the buffer for the next iteration. */
+ memcpy (search_buf, search_buf + chunk_size, keep_len);
+
+ nr_to_read = (search_space_len - keep_len < chunk_size
+ ? search_space_len - keep_len
+ : chunk_size);
+
+ if (read_inferior_memory (read_addr, search_buf + keep_len,
+ nr_to_read) != 0)
+ {
+ warning ("unable to access target memory at 0x%lx, halting search",
+ (long) read_addr);
+ return -1;
+ }
+
+ start_addr += chunk_size;
+ }
+ }
+
+ /* Not found. */
+
+ return 0;
+}
+
+/* Handle qSearch:memory packets. */
+
+static void
+handle_search_memory (char *own_buf, int packet_len)
+{
+ CORE_ADDR start_addr;
+ CORE_ADDR search_space_len;
+ gdb_byte *pattern;
+ unsigned int pattern_len;
+ /* NOTE: also defined in find.c testcase. */
+#define SEARCH_CHUNK_SIZE 16000
+ const unsigned chunk_size = SEARCH_CHUNK_SIZE;
+ /* Buffer to hold memory contents for searching. */
+ gdb_byte *search_buf;
+ unsigned search_buf_size;
+ int found;
+ CORE_ADDR found_addr;
+ int cmd_name_len = sizeof ("qSearch:memory:") - 1;
+
+ pattern = malloc (packet_len);
+ if (pattern == NULL)
+ {
+ error ("unable to allocate memory to perform the search");
+ strcpy (own_buf, "E00");
+ return;
+ }
+ if (decode_search_memory_packet (own_buf + cmd_name_len,
+ packet_len - cmd_name_len,
+ &start_addr, &search_space_len,
+ pattern, &pattern_len) < 0)
+ {
+ free (pattern);
+ error ("error in parsing qSearch:memory packet");
+ strcpy (own_buf, "E00");
+ return;
+ }
+
+ 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;
+
+ search_buf = malloc (search_buf_size);
+ if (search_buf == NULL)
+ {
+ free (pattern);
+ error ("unable to allocate memory to perform the search");
+ strcpy (own_buf, "E00");
+ return;
+ }
+
+ found = handle_search_memory_1 (start_addr, search_space_len,
+ pattern, pattern_len,
+ search_buf, chunk_size, search_buf_size,
+ &found_addr);
+
+ if (found > 0)
+ sprintf (own_buf, "1,%lx", (long) found_addr);
+ else if (found == 0)
+ strcpy (own_buf, "0");
+ else
+ strcpy (own_buf, "E00");
+
+ free (search_buf);
+ free (pattern);
+}
+
#define require_running(BUF) \
if (!target_running ()) \
{ \
@@ -731,6 +878,13 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
return;
}
+ if (strncmp ("qSearch:memory:", own_buf, sizeof ("qSearch:memory:") - 1) == 0)
+ {
+ require_running (own_buf);
+ handle_search_memory (own_buf, packet_len);
+ return;
+ }
+
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;