Message ID | 1426071808-2513-1-git-send-email-hw.claudio@gmail.com |
---|---|
State | New |
Headers | show |
On 2015/3/11 19:03, hw.claudio@gmail.com wrote: > From: Claudio Fontana <claudio.fontana@huawei.com> > > 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 <claudio.fontana@huawei.com> > --- > hmp-commands.hx | 28 ++++++++++++ > monitor.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 167 insertions(+) > Hi, Claudio checkpatch.pl reports some warnings. Regards, -Gonglei > Please note that this has been only loosely tested with LE host / LE guest, > more testing needed for heterogeneous host/target, and for matches overlapping > chunks. > > Of course it is possible to dump the guest memory and then use other tools > to look for the needed data. Personally I found it handy to have this available > in qemu, I wonder whether it can be handy in general. > > Ciao, > > Claudio > > 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..60a2e0d 100644 > --- a/monitor.c > +++ b/monitor.c > @@ -1208,6 +1208,123 @@ 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; /* needle to search in the haystack */ > + const char *format_str; /* numeric input format string */ > + > +#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 */ > + char value_raw[8]; /* numeric input converted to raw data */ > + 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;) { > + if (!(match = memmem(mark, todo, needle, wsize))) { > + 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 +1449,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"); >
On 11 March 2015 at 12:27, Gonglei <arei.gonglei@huawei.com> wrote: > On 2015/3/11 19:03, hw.claudio@gmail.com wrote: >> From: Claudio Fontana <claudio.fontana@huawei.com> >> >> 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 <claudio.fontana@huawei.com> >> --- >> hmp-commands.hx | 28 ++++++++++++ >> monitor.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 167 insertions(+) >> > Hi, Claudio > checkpatch.pl reports some warnings. Right, I'll get rid of those -tx Claudio > > Regards, > -Gonglei >> Please note that this has been only loosely tested with LE host / LE guest, >> more testing needed for heterogeneous host/target, and for matches overlapping >> chunks. >> >> Of course it is possible to dump the guest memory and then use other tools >> to look for the needed data. Personally I found it handy to have this available >> in qemu, I wonder whether it can be handy in general. >> >> Ciao, >> >> Claudio >> >> 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..60a2e0d 100644 >> --- a/monitor.c >> +++ b/monitor.c >> @@ -1208,6 +1208,123 @@ 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; /* needle to search in the haystack */ >> + const char *format_str; /* numeric input format string */ >> + >> +#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 */ >> + char value_raw[8]; /* numeric input converted to raw data */ >> + 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;) { >> + if (!(match = memmem(mark, todo, needle, wsize))) { >> + 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 +1449,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"); >> > >
This series failed Patchew automatic testing. Find the log fragments below (grepped lines around keywords "error" and "warning"), or open the following URL to see the full log: http://qemu.patchew.org/testing/log/<1426071808-2513-1-git-send-email-hw.claudio@gmail.com> ----------8<--------- Checking if the code is already merged ...No. === Writing patches === 0001-monitor--add-memory-search-commands-s--sp.patch 0001-monitor--add-memory-search-commands-s--sp.email === Applying patches === Applying: monitor: add memory search commands s, sp === Starting docker === Copying test script "/home/patchew/tests/qemu-devel.sh" Starting docker... docker run --net=none -v /var/tmp/patchew-tester/tmp0FIf3M:/var/tmp/patchew-test patchew:fedora-20 timeout 3600 /var/tmp/patchew-test/qemu-devel.sh /var/tmp/patchew-test *** Testing 'coding style check' *** Checking 0001-monitor--add-memory-search-commands-s--sp.patch command failed with exit code 0 $@ WARNING: braces {} are necessary for all arms of this statement #89: FILE: monitor.c:1213: + if (is_physical) [...] + else [...] WARNING: braces {} are necessary for all arms of this statement #160: FILE: monitor.c:1284: + if (is_physical) [...] + else [...] ERROR: do not use assignment in if condition #185: FILE: monitor.c:1309: + if (!(match = memmem(mark, todo, needle, wsize))) { total: 1 errors, 2 warnings, 185 lines checked 0001-monitor--add-memory-search-commands-s--sp.patch has style problems, please review. If any of these errors are false positives report them to the maintainer, see CHECKPATCH in MAINTAINERS. *** Testing 'configure' *** Install prefix /usr/local BIOS directory /usr/local/share/qemu binary directory /usr/local/bin library directory /usr/local/lib module directory /usr/local/lib/qemu libexec directory /usr/local/libexec include directory /usr/local/include config directory /usr/local/etc local state directory /usr/local/var Manual directory /usr/local/share/man ELF interp prefix /usr/gnemul/qemu-%M Source path /var/tmp/patchew-test/git C compiler cc Host C compiler cc C++ compiler c++ Objective-C compiler cc -- CC qobject/qerror.o GEN trace/generated-events.c CC trace/control.o CC trace/qmp.o CC util/osdep.o CC util/cutils.o CC util/unicode.o CC util/qemu-timer-common.o CC util/oslib-posix.o CC util/qemu-thread-posix.o CC util/event_notifier-posix.o CC util/qemu-openpty.o CC util/envlist.o CC util/path.o CC util/module.o CC util/bitmap.o CC util/bitops.o CC util/hbitmap.o CC util/fifo8.o CC util/acl.o CC util/error.o CC util/qemu-error.o CC util/compatfd.o CC util/id.o CC util/iov.o CC util/aes.o CC util/qemu-config.o CC util/qemu-sockets.o CC util/uri.o CC util/notify.o CC util/qemu-option.o CC util/qemu-progress.o CC util/hexdump.o CC util/crc32c.o CC util/throttle.o CC util/getauxval.o CC util/readline.o CC util/rfifolock.o CC util/rcu.o CC stubs/arch-query-cpu-def.o CC stubs/bdrv-commit-all.o CC stubs/chr-baum-init.o CC stubs/chr-msmouse.o CC stubs/chr-testdev.o CC stubs/clock-warp.o CC stubs/cpu-get-clock.o CC stubs/cpu-get-icount.o CC stubs/dump.o CC stubs/fdset-add-fd.o CC stubs/fdset-find-fd.o CC stubs/fdset-get-fd.o CC stubs/fdset-remove-fd.o CC stubs/gdbstub.o CC stubs/get-fd.o CC stubs/get-next-serial.o CC stubs/get-vm-name.o CC stubs/iothread-lock.o CC stubs/is-daemonized.o CC stubs/machine-init-done.o CC stubs/migr-blocker.o CC stubs/mon-is-qmp.o CC stubs/mon-printf.o CC stubs/mon-set-error.o CC stubs/monitor-init.o CC stubs/notify-event.o CC stubs/qtest.o CC stubs/reset.o CC stubs/runstate-check.o CC stubs/set-fd-handler.o CC stubs/slirp.o CC stubs/sysbus.o CC stubs/uuid.o CC stubs/vc-init.o CC stubs/vm-stop.o CC stubs/vmstate.o CC stubs/cpus.o CC stubs/kvm.o CC stubs/qmp_pc_dimm_device_list.o CC qemu-nbd.o CC async.o CC thread-pool.o CC nbd.o CC block.o -- GEN x86_64-softmmu/hmp-commands.h GEN x86_64-softmmu/qmp-commands-old.h GEN x86_64-softmmu/config-target.h CC x86_64-softmmu/exec.o CC x86_64-softmmu/translate-all.o CC x86_64-softmmu/cpu-exec.o CC x86_64-softmmu/tcg/tcg.o CC x86_64-softmmu/tcg/tcg-op.o CC x86_64-softmmu/tcg/optimize.o CC x86_64-softmmu/fpu/softfloat.o CC x86_64-softmmu/disas.o CC x86_64-softmmu/arch_init.o CC x86_64-softmmu/cpus.o CC x86_64-softmmu/monitor.o CC x86_64-softmmu/gdbstub.o CC x86_64-softmmu/balloon.o CC x86_64-softmmu/ioport.o CC x86_64-softmmu/numa.o CC x86_64-softmmu/qtest.o /var/tmp/patchew-test/git/monitor.c: In function 'memory_search': /var/tmp/patchew-test/git/monitor.c:1309:16: error: 'needle' may be used uninitialized in this function [-Werror=maybe-uninitialized] if (!(match = memmem(mark, todo, needle, wsize))) { ^ cc1: all warnings being treated as errors make[1]: *** [monitor.o] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [subdir-x86_64-softmmu] Error 2 Test failed.
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..60a2e0d 100644 --- a/monitor.c +++ b/monitor.c @@ -1208,6 +1208,123 @@ 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; /* needle to search in the haystack */ + const char *format_str; /* numeric input format string */ + +#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 */ + char value_raw[8]; /* numeric input converted to raw data */ + 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;) { + if (!(match = memmem(mark, todo, needle, wsize))) { + 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 +1449,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");