[PATCH] new MI command for pattern filling of memory regions

Giuseppe MONTALTO
2012-05-09T16:18:56Z

Hi all,

it's the first time I attempt a contribution to gdb, so feel free to ask for
details and, please, let me know if I'm doing anything wrong!

Short:
the proposed enhancement is about memory filling.

Rationale:
Filling a memory region with a pattern of bytes so far, can only be done by
sending a potentially high number of repeated commands to gdb (depending on
the size of the region that we need to fill).
If gdb is controlled through a GUI (e.g. Eclipse/CDT), this may cause the UI
to freeze for a quite long time.
This is especially true when you're debugging a remote target, due to the
amount of generated network traffic.

Solution:
Implement an MI command that allows filling, with a specific pattern of bytes,
an arbitrarily sized memory region.

The proposed patch is here below, also including the related test script.

Regards,
Giuseppe Montalto

From 9a168d60e69ce7618ab74591f230172554e4bc0b Mon Sep 17 00:00:00 2001
From: Giuseppe Montalto <giusepe.montalto@st.com>
Date: Wed, 9 May 2012 16:53:28 +0200
Subject: [PATCH] implemented a new MI command - data-fill-memory-bytes

---
gdb/ChangeLog | 8 +++
gdb/mi/mi-cmds.c | 1 +
gdb/mi/mi-cmds.h | 1 +
gdb/mi/mi-main.c | 73 +++++++++++++++++++++++++++++
gdb/testsuite/ChangeLog | 4 ++
gdb/testsuite/gdb.mi/mi-fill-memory.exp | 76 +++++++++++++++++++++++++++++++
6 files changed, 163 insertions(+), 0 deletions(-)
create mode 100644 gdb/testsuite/gdb.mi/mi-fill-memory.exp

diff --git gdb/ChangeLog gdb/ChangeLog
index 309473e..fe335bb 100644
--- gdb/ChangeLog
+++ gdb/ChangeLog
@@ -1,3 +1,11 @@
+2012-05-09 Giuseppe Montalto <giuseppe.montalto@st.com>
+
+ * mi/mi-cmds.h (mi_cmd_data_fill_memory_bytes): New Declaration
+ * mi/mi-cmds.c (data-fill-memory-bytes): New member in struct
+ mi_cmd mi_cmds
+ * mi/mi-main.c (mi_cmd_data_fill_memory_bytes): new Function
+ implementation
+
2012-05-09 Pedro Alves <palves@redhat.com>

* target.c (set_maintenance_target_async_permitted): Rename to ...
diff --git gdb/mi/mi-cmds.c gdb/mi/mi-cmds.c
index 9152489..020a483 100644
--- gdb/mi/mi-cmds.c
+++ gdb/mi/mi-cmds.c
@@ -47,6 +47,7 @@ struct mi_cmd mi_cmds[] =
{ "break-watch", { NULL, 0 }, mi_cmd_break_watch},
{ "data-disassemble", { NULL, 0 }, mi_cmd_disassemble},
{ "data-evaluate-expression", { NULL, 0 }, mi_cmd_data_evaluate_expression},
+ { "data-fill-memory-bytes", {NULL, 0}, mi_cmd_data_fill_memory_bytes},
{ "data-list-changed-registers", { NULL, 0 },
mi_cmd_data_list_changed_registers},
{ "data-list-register-names", { NULL, 0 }, mi_cmd_data_list_register_names},
diff --git gdb/mi/mi-cmds.h gdb/mi/mi-cmds.h
index c8465f0..7a8756b 100644
--- gdb/mi/mi-cmds.h
+++ gdb/mi/mi-cmds.h
@@ -45,6 +45,7 @@ extern mi_cmd_argv_ftype mi_cmd_break_passcount;
extern mi_cmd_argv_ftype mi_cmd_break_watch;
extern mi_cmd_argv_ftype mi_cmd_disassemble;
extern mi_cmd_argv_ftype mi_cmd_data_evaluate_expression;
+extern mi_cmd_argv_ftype mi_cmd_data_fill_memory_bytes;
extern mi_cmd_argv_ftype mi_cmd_data_list_register_names;
extern mi_cmd_argv_ftype mi_cmd_data_list_register_values;
extern mi_cmd_argv_ftype mi_cmd_data_list_changed_registers;
diff --git gdb/mi/mi-main.c gdb/mi/mi-main.c
index 90fb624..5d94333 100644
--- gdb/mi/mi-main.c
+++ gdb/mi/mi-main.c
@@ -1693,6 +1693,79 @@ mi_cmd_data_write_memory_bytes (char *command, char **argv, int argc)
do_cleanups (back_to);
}

+/* DATA-MEMORY-FILL-RAW:
+
+ ADDR: start address
+ COUNT: number of bytes to be filled (decimal integer)
+ DATA: string of bytes to write from that address. (1,2,4 or 8 bytes) */
+void
+mi_cmd_data_fill_memory_bytes (char *command, char **argv, int argc)
+{
+ CORE_ADDR addr;
+ char *cdata;
+ gdb_byte *data;
+ int len, r, i, steps;
+ long int count, j;
+ struct cleanup *back_to;
+
+ if (argc != 3)
+ error (_("Usage: ADDR COUNT DATA."));
+
+ /* read parameters */
+ addr = parse_and_eval_address (argv[0]);
+ /* COUNT is supposed to be a decimal integer*/
+ count = strtol(argv[1], NULL, 10);
+ cdata = argv[2];
+
+ /* calculate and allocate a memory buffer for DATA parameter */
+ len = strlen (cdata);
+
+ if ( len != 2 && len != 4 && len != 8 && len != 16 )
+ error (_("DATA must be 2, 4, 8 or 16 characters."));
+
+ len = len/2;
+
+ if ( (long int)len < count )
+ {
+ /* pattern is made of less bytes than count:
+ repeat pattern to fill memory */
+ data = xmalloc (count/len);
+ back_to = make_cleanup (xfree, data);
+
+ steps = count/len;
+ for (j = 0; j < steps; j++)
+ {
+ for (i = 0; i < len; ++i)
+ {
+ int x;
+ sscanf (cdata + i * 2, "%02x", &x);
+ data[i + j * len] = (gdb_byte)x;
+ }
+ }
+ }
+ else
+ {
+ /* pattern is longer than (or equal to) count:
+ just copy len bytes */
+ data = xmalloc (len);
+ back_to = make_cleanup (xfree, data);
+
+ for (i = 0; i < len; ++i)
+ {
+ int x;
+ sscanf (cdata + i * 2, "%02x", &x);
+ data[i] = (gdb_byte)x;
+ }
+ }
+
+ r = target_write_memory (addr, data, count);
+
+ if (r != 0)
+ error (_("Could not fill memory range with supplied pattern"));
+
+ do_cleanups (back_to);
+}
+
void
mi_cmd_enable_timings (char *command, char **argv, int argc)
{
diff --git gdb/testsuite/ChangeLog gdb/testsuite/ChangeLog
index 43549bf..a49274f 100644
--- gdb/testsuite/ChangeLog
+++ gdb/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2012-05-09 Giuseppe Montalto <giuseppe.montalto@st.com>
+
+ * gdb.mi/mi-fill-memory.exp: New test.
+
2012-05-08 Maciej W. Rozycki <macro@codesourcery.com>

* gdb.mi/mi-var-display.exp: Check for the existence of $fp
diff --git gdb/testsuite/gdb.mi/mi-fill-memory.exp gdb/testsuite/gdb.mi/mi-fill-memory.exp
new file mode 100644
index 0000000..40147e5
--- /dev/null
+++ gdb/testsuite/gdb.mi/mi-fill-memory.exp
@@ -0,0 +1,76 @@
+# Copyright (C) 2012 Free Software Foundation, Inc.
+# Copyright (C) 2012 STMicroelectronics
+
+# 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 <http://www.gnu.org/licenses/>.
+
+#
+# test basic Machine interface (MI) operations
+#
+# Verify that, using the MI, we can load a program and do
+# other basic things that are used by all test files through mi_gdb_exit,
+# mi_gdb_start, mi_delete_breakpoints, mi_gdb_reinitialize_dir and
+# mi_gdb_load, so we can safely use those.
+#
+# The goal is not to test gdb functionality, which is done by other tests,
+# but the command syntax and correct output response to MI operations.
+#
+# added for testing the -data-fill-memory-bytes MI command
+#
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+gdb_exit
+if [mi_gdb_start] {
+ continue
+}
+
+set testfile "mi-read-memory"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-DFAKEARGV}] != "" } {
+ untested mi-read-memory.exp
+ return -1
+}
+
+
+mi_run_to_main
+mi_next_to "main" "" "mi-read-memory.c" "20" "next at main"
+
+mi_gdb_test "1-data-fill-memory-bytes" \
+ "1\\^error,msg=\"Usage: ADDR COUNT DATA\.\""\
+ "no arguments"
+
+mi_gdb_test "2-data-fill-memory-bytes 8" \
+ "2\\^error,msg=\"Usage: ADDR COUNT DATA\.\""\
+ "two arguments missing"
+
+mi_gdb_test "3-data-fill-memory-bytes 8 ab"\
+ "3\\^error,msg=\"Usage: ADDR COUNT DATA\.\""\
+ "one argument missing"
+
+mi_gdb_test "4-data-fill-memory-bytes \$pc 8 abc"\
+ "4\\^error,msg=\"DATA must be 2, 4, 8 or 16 characters\.\""\
+ "wrong data length"
+
+mi_gdb_test "5-data-fill-memory-bytes \$pc 8 ab"\
+ "5\\\^done" \
+ "memory successfully filled"
+
+mi_gdb_test "6-interpreter-exec console \"x \$pc\"" \
+ ".*0xabababab.*" \
+ "pattern correctly read from memory"
+
+mi_gdb_exit
+return 0
--
1.7.4.msysgit.0