From patchwork Fri Apr 24 12:39:48 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Claudio Fontana X-Patchwork-Id: 464205 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id D6A2A14011B for ; Fri, 24 Apr 2015 22:39:25 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="verification failed; unprotected key" header.d=gmail.com header.i=@gmail.com header.b=YlBzPEeP; dkim-adsp=none (unprotected policy); dkim-atps=neutral Received: from localhost ([::1]:44696 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YlctA-0000uW-4J for incoming@patchwork.ozlabs.org; Fri, 24 Apr 2015 08:39:24 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:56628) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Ylcsp-0000U3-0w for qemu-devel@nongnu.org; Fri, 24 Apr 2015 08:39:04 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Ylcsl-0001ye-PH for qemu-devel@nongnu.org; Fri, 24 Apr 2015 08:39:02 -0400 Received: from mail-wg0-x236.google.com ([2a00:1450:400c:c00::236]:35727) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Ylcsl-0001yZ-Ee for qemu-devel@nongnu.org; Fri, 24 Apr 2015 08:38:59 -0400 Received: by wgyo15 with SMTP id o15so49172111wgy.2 for ; Fri, 24 Apr 2015 05:38:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=8RvYJfBJB2ri1xJt3kvOZDVBmDJ8uGkuSeIi2IKTxC8=; b=YlBzPEePHETr4fK3FKD6GZRyThwo6pehcufFpCiOpQoltshxdB58Ikog1Jw9AIKT5S rLrnDLz9yDeeZI/mOurjpJaDs+raFpvuaKVG2+IhpHDROA9q/NbBUtUlGCIRpYFmFczW G3mNtwxOPhfiXcCknYk61+EvI27uvPGLbPEVqFBzxB14CcgDgBnBtmmlDNsMt78QbG+g gy+xuuGxhbjKf3qo4qisjmBQZkAkdvBy19djilS0+G8T/qI0ZDZ2KwB2jVG01axguRo5 ndQtTJwTaJNYYfYZajxkFPRXPudpBsD48LlAyW20HOr9WXBc0USi3rbI9vUhAN/W3+SH aSmQ== X-Received: by 10.195.18.103 with SMTP id gl7mr15157852wjd.34.1429879138494; Fri, 24 Apr 2015 05:38:58 -0700 (PDT) Received: from moosach.csi ([217.111.50.162]) by mx.google.com with ESMTPSA id kc4sm16746268wjc.2.2015.04.24.05.38.56 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 24 Apr 2015 05:38:57 -0700 (PDT) From: hw.claudio@gmail.com To: Luiz Capitulino Date: Fri, 24 Apr 2015 14:39:48 +0200 Message-Id: <1429879188-28888-1-git-send-email-hw.claudio@gmail.com> X-Mailer: git-send-email 1.8.5.3 X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:400c:c00::236 Cc: Paolo Bonzini , Gonglei , Claudio Fontana , qemu-devel@nongnu.org, Peter Maydell Subject: [Qemu-devel] [RFC v4] 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 --- hmp-commands.hx | 28 ++++++++++++ monitor.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+) changes from v3: initialize pointer variable to NULL to finally get rid of spurious warning changes from v2: move code to try to address spurious warning changes from v1: make checkpatch happy by adding braces here and there. diff --git a/hmp-commands.hx b/hmp-commands.hx index d5022d8..2bf5737 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -432,6 +432,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 c86a89e..b648dd2 100644 --- a/monitor.c +++ b/monitor.c @@ -1208,6 +1208,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) { @@ -1332,6 +1450,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");