From patchwork Fri May 8 13:34:02 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luiz Capitulino X-Patchwork-Id: 470053 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 936F6140281 for ; Fri, 8 May 2015 23:39:02 +1000 (AEST) Received: from localhost ([::1]:55880 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YqiUW-0000cM-RL for incoming@patchwork.ozlabs.org; Fri, 08 May 2015 09:39:00 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41784) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YqiPz-0000jm-4P for qemu-devel@nongnu.org; Fri, 08 May 2015 09:34:23 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YqiPv-0002PD-Ur for qemu-devel@nongnu.org; Fri, 08 May 2015 09:34:19 -0400 Received: from mx1.redhat.com ([209.132.183.28]:55956) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YqiPv-0002P3-MO for qemu-devel@nongnu.org; Fri, 08 May 2015 09:34:15 -0400 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (Postfix) with ESMTPS id 3D403C1F03; Fri, 8 May 2015 13:34:15 +0000 (UTC) Received: from localhost (ovpn-113-30.phx2.redhat.com [10.3.113.30]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t48DYEJS019005; Fri, 8 May 2015 09:34:14 -0400 From: Luiz Capitulino To: peter.maydell@linaro.org Date: Fri, 8 May 2015 09:34:02 -0400 Message-Id: <1431092051-31046-2-git-send-email-lcapitulino@redhat.com> In-Reply-To: <1431092051-31046-1-git-send-email-lcapitulino@redhat.com> References: <1431092051-31046-1-git-send-email-lcapitulino@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: qemu-devel@nongnu.org Subject: [Qemu-devel] [PULL 01/10] monitor: add memory search commands s, sp X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Claudio Fontana usage is similar to the commands x, xp. Example with string: looking for "ELF" header in memory: (qemu) s/1000000cb 0x40001000 "ELF" searching memory area [0000000040001000-00000000400f5240] 0000000040090001 (qemu) x/20b 0x40090000 0000000040090000: '\x7f' 'E' 'L' 'F' '\x02' '\x01' '\x01' '\x03' 0000000040090008: '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' '\x00' 0000000040090010: '\x02' '\x00' '\xb7' '\x00' Example with value: looking for 64bit variable value 0x990088 (qemu) s/1000000xg 0xffff900042000000 0x990088 searching memory area [ffff900042000000-ffff9000427a1200] ffff9000424b3000 ffff9000424c1000 Signed-off-by: Claudio Fontana Signed-off-by: Luiz Capitulino --- hmp-commands.hx | 28 ++++++++++++ monitor.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+) diff --git a/hmp-commands.hx b/hmp-commands.hx index e864a6c..badf1f5 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -430,6 +430,34 @@ Start gdbserver session (default @var{port}=1234) ETEXI { + .name = "s", + .args_type = "fmt:/,addr:l,data:s", + .params = "/fmt addr data", + .help = "search virtual memory starting at 'addr' for 'data'", + .mhandler.cmd = hmp_memory_search, + }, + +STEXI +@item s/fmt @var{addr} @var{data} +@findex s +Virtual memory search starting at @var{addr} for data described by @var{data}. +ETEXI + + { + .name = "sp", + .args_type = "fmt:/,addr:l,data:s", + .params = "/fmt addr data", + .help = "search physical memory starting at 'addr' for 'data'", + .mhandler.cmd = hmp_physical_memory_search, + }, + +STEXI +@item sp/fmt @var{addr} @var{data} +@findex sp +Physical memory search starting at @var{addr} for data described by @var{data}. +ETEXI + + { .name = "x", .args_type = "fmt:/,addr:l", .params = "/fmt addr", diff --git a/monitor.c b/monitor.c index 3952d64..9611d4f 100644 --- a/monitor.c +++ b/monitor.c @@ -1205,6 +1205,124 @@ static void monitor_printc(Monitor *mon, int c) monitor_printf(mon, "'"); } +static void monitor_print_addr(Monitor *mon, hwaddr addr, bool is_physical) +{ + if (is_physical) { + monitor_printf(mon, TARGET_FMT_plx "\n", addr); + } else { + monitor_printf(mon, TARGET_FMT_lx "\n", (target_ulong)addr); + } +} + +/* simple memory search for a byte sequence. The sequence is generated from + * a numeric value to look for in guest memory, or from a string. + */ +static void memory_search(Monitor *mon, int count, int format, int wsize, + hwaddr addr, const char *data_str, bool is_physical) +{ + int pos, len; /* pos in the search area, len of area */ + char *hay; /* buffer for haystack */ + int hay_size; /* haystack size. Needle size is wsize. */ + const char *needle = NULL; /* needle to search in the haystack */ + const char *format_str; /* numeric input format string */ + char value_raw[8]; /* numeric input converted to raw data */ +#define MONITOR_S_CHUNK_SIZE 16000 + + len = wsize * count; + if (len < 1) { + monitor_printf(mon, "invalid search area length.\n"); + return; + } + switch (format) { + case 'i': + monitor_printf(mon, "format '%c' not supported.\n", format); + return; + case 'c': + needle = data_str; + wsize = strlen(data_str); + if (wsize > MONITOR_S_CHUNK_SIZE) { + monitor_printf(mon, "search string too long [max %d].\n", + MONITOR_S_CHUNK_SIZE); + return; + } + break; + case 'o': + format_str = "%" SCNo64; + break; + default: + case 'x': + format_str = "%" SCNx64; + break; + case 'u': + format_str = "%" SCNu64; + break; + case 'd': + format_str = "%" SCNd64; + break; + } + if (format != 'c') { + uint64_t value; /* numeric input value */ + void *from = &value; + if (sscanf(data_str, format_str, &value) != 1) { + monitor_printf(mon, "could not parse search string " + "\"%s\" as format '%c'.\n", data_str, format); + return; + } +#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) + value = bswap64(value); +#endif +#if defined(TARGET_WORDS_BIGENDIAN) + from += 8 - wsize; +#endif + memcpy(value_raw, from, wsize); + needle = value_raw; + } + monitor_printf(mon, "searching memory area "); + if (is_physical) { + monitor_printf(mon, "[" TARGET_FMT_plx "-" TARGET_FMT_plx "]\n", + addr, addr + len); + } else { + monitor_printf(mon, "[" TARGET_FMT_lx "-" TARGET_FMT_lx "]\n", + (target_ulong)addr, (target_ulong)addr + len); + } + hay_size = len < MONITOR_S_CHUNK_SIZE ? len : MONITOR_S_CHUNK_SIZE; + hay = g_malloc0(hay_size); + + for (pos = 0; pos < len;) { + char *mark, *match; /* mark new starting position, eventual match */ + int l, todo; /* total length to be processed in current chunk */ + l = len - pos; + if (l > hay_size) { + l = hay_size; + } + if (is_physical) { + cpu_physical_memory_read(addr, hay, l); + } else if (cpu_memory_rw_debug(ENV_GET_CPU(mon_get_cpu()), addr, + (uint8_t *)hay, l, 0) < 0) { + monitor_printf(mon, " Cannot access memory\n"); + break; + } + for (mark = hay, todo = l; todo >= wsize;) { + match = memmem(mark, todo, needle, wsize); + if (!match) { + break; + } + monitor_print_addr(mon, addr + (match - hay), is_physical); + mark = match + 1; + todo = mark - hay; + } + if (pos + l < len) { + /* catch potential matches across chunks. */ + pos += l - (wsize - 1); + addr += l - (wsize - 1); + } else { + pos += l; + addr += l; + } + } + g_free(hay); +} + static void memory_dump(Monitor *mon, int count, int format, int wsize, hwaddr addr, int is_physical) { @@ -1329,6 +1447,28 @@ static void memory_dump(Monitor *mon, int count, int format, int wsize, } } +static void hmp_memory_search(Monitor *mon, const QDict *qdict) +{ + int count = qdict_get_int(qdict, "count"); + int format = qdict_get_int(qdict, "format"); + int size = qdict_get_int(qdict, "size"); + target_long addr = qdict_get_int(qdict, "addr"); + const char *data_str = qdict_get_str(qdict, "data"); + + memory_search(mon, count, format, size, addr, data_str, false); +} + +static void hmp_physical_memory_search(Monitor *mon, const QDict *qdict) +{ + int count = qdict_get_int(qdict, "count"); + int format = qdict_get_int(qdict, "format"); + int size = qdict_get_int(qdict, "size"); + hwaddr addr = qdict_get_int(qdict, "addr"); + const char *data_str = qdict_get_str(qdict, "data"); + + memory_search(mon, count, format, size, addr, data_str, true); +} + static void hmp_memory_dump(Monitor *mon, const QDict *qdict) { int count = qdict_get_int(qdict, "count");