qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/2] plugins: add plugin API to read guest memory
@ 2024-08-27  2:18 Rowan Hart
  2024-08-27  2:18 ` [PATCH v2 1/2] " Rowan Hart
  2024-08-27  2:18 ` [PATCH v2 2/2] plugins: add option to dump write argument to syscall plugin Rowan Hart
  0 siblings, 2 replies; 5+ messages in thread
From: Rowan Hart @ 2024-08-27  2:18 UTC (permalink / raw)
  To: qemu-devel
  Cc: Pierrick Bouvier, Mahmoud Mandour, Alexandre Iooss,
	Alex Bennée, Rowan Hart

This patch adds one API function to the QEMU plugin API

bool qemu_plugin_read_memory_vaddr(vaddr, GByteArray *, size_t);

The API allows reading memory from an arbitrary guest virtual
address, which is useful for many things but the motivating examples
are:

* Virtual Machine Introspection (VMI)
* Accurate and easier execution trace extraction
* Debugging and logging tools

An example of its use is added to the existing syscalls plugin,
which now has an option to hexdump the buf argument to any write(2)
syscalls which occur.

Rowan Hart (2):
  plugins: add plugin API to read guest memory
  plugins: add option to dump write argument to syscall plugin

 docs/about/emulation.rst     |  14 ++++-
 include/qemu/qemu-plugin.h   |  32 +++++++++-
 plugins/api.c                |  20 ++++++
 plugins/qemu-plugins.symbols |   1 +
 tests/tcg/plugins/syscall.c  | 117 +++++++++++++++++++++++++++++++++++
 5 files changed, 182 insertions(+), 2 deletions(-)

-- 
2.46.0



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v2 1/2] plugins: add plugin API to read guest memory
  2024-08-27  2:18 [PATCH v2 0/2] plugins: add plugin API to read guest memory Rowan Hart
@ 2024-08-27  2:18 ` Rowan Hart
  2024-08-27 15:59   ` Pierrick Bouvier
  2024-08-27  2:18 ` [PATCH v2 2/2] plugins: add option to dump write argument to syscall plugin Rowan Hart
  1 sibling, 1 reply; 5+ messages in thread
From: Rowan Hart @ 2024-08-27  2:18 UTC (permalink / raw)
  To: qemu-devel
  Cc: Pierrick Bouvier, Mahmoud Mandour, Alexandre Iooss,
	Alex Bennée, Rowan Hart

Signed-off-by: Rowan Hart <rowanbhart@gmail.com>
---
 include/qemu/qemu-plugin.h   | 32 +++++++++++++++++++++++++++++++-
 plugins/api.c                | 20 ++++++++++++++++++++
 plugins/qemu-plugins.symbols |  1 +
 3 files changed, 52 insertions(+), 1 deletion(-)

diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
index c71c705b69..10f9db8cdc 100644
--- a/include/qemu/qemu-plugin.h
+++ b/include/qemu/qemu-plugin.h
@@ -57,11 +57,19 @@ typedef uint64_t qemu_plugin_id_t;
  * - Remove qemu_plugin_register_vcpu_{tb, insn, mem}_exec_inline.
  *   Those functions are replaced by *_per_vcpu variants, which guarantee
  *   thread-safety for operations.
+ *
+ * version 3:
+ * - modified arguments and return value of qemu_plugin_insn_data to copy
+ *   the data into a user-provided buffer instead of returning a pointer
+ *   to the data.
+ *
+ * version 4:
+ * - added qemu_plugin_read_memory_vaddr
  */
 
 extern QEMU_PLUGIN_EXPORT int qemu_plugin_version;
 
-#define QEMU_PLUGIN_VERSION 3
+#define QEMU_PLUGIN_VERSION 4
 
 /**
  * struct qemu_info_t - system information for plugins
@@ -852,6 +860,28 @@ typedef struct {
 QEMU_PLUGIN_API
 GArray *qemu_plugin_get_registers(void);
 
+/**
+ * qemu_plugin_read_memory_vaddr() - read from memory using a virtual address
+ *
+ * @addr: A virtual address to read from
+ * @data: A byte array to store data into
+ * @len: The number of bytes to read, starting from @addr
+
+ * @len bytes of data is read starting at @addr and stored into @data. If @data
+ * is not large enough to hold @len bytes, it will be expanded to the necessary
+ * size, reallocating if necessary. @len must be greater than 0.
+ *
+ * This function does not ensure writes are flushed prior to reading, so
+ * callers should take care when calling this function in plugin callbacks to
+ * avoid attempting to read data which may not yet be written and should use
+ * the memory callback API instead.
+ *
+ * Returns true on success and false on failure.
+ */
+QEMU_PLUGIN_API
+bool qemu_plugin_read_memory_vaddr(uint64_t addr,
+                                          GByteArray *data, size_t len);
+
 /**
  * qemu_plugin_read_register() - read register for current vCPU
  *
diff --git a/plugins/api.c b/plugins/api.c
index 2ff13d09de..cb7d818918 100644
--- a/plugins/api.c
+++ b/plugins/api.c
@@ -527,6 +527,26 @@ GArray *qemu_plugin_get_registers(void)
     return create_register_handles(regs);
 }
 
+bool qemu_plugin_read_memory_vaddr(vaddr addr, GByteArray *data, size_t len)
+{
+    g_assert(current_cpu);
+
+    if (len == 0) {
+        return false;
+    }
+
+    g_byte_array_set_size(data, len);
+
+    int result = cpu_memory_rw_debug(current_cpu, addr, data->data,
+                                data->len, 0);
+
+    if (result < 0) {
+        return false;
+    }
+
+    return true;
+}
+
 int qemu_plugin_read_register(struct qemu_plugin_register *reg, GByteArray *buf)
 {
     g_assert(current_cpu);
diff --git a/plugins/qemu-plugins.symbols b/plugins/qemu-plugins.symbols
index ca773d8d9f..3ad479a924 100644
--- a/plugins/qemu-plugins.symbols
+++ b/plugins/qemu-plugins.symbols
@@ -20,6 +20,7 @@
   qemu_plugin_num_vcpus;
   qemu_plugin_outs;
   qemu_plugin_path_to_binary;
+  qemu_plugin_read_memory_vaddr;
   qemu_plugin_read_register;
   qemu_plugin_register_atexit_cb;
   qemu_plugin_register_flush_cb;
-- 
2.46.0



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v2 2/2] plugins: add option to dump write argument to syscall plugin
  2024-08-27  2:18 [PATCH v2 0/2] plugins: add plugin API to read guest memory Rowan Hart
  2024-08-27  2:18 ` [PATCH v2 1/2] " Rowan Hart
@ 2024-08-27  2:18 ` Rowan Hart
  2024-08-27 16:01   ` Pierrick Bouvier
  1 sibling, 1 reply; 5+ messages in thread
From: Rowan Hart @ 2024-08-27  2:18 UTC (permalink / raw)
  To: qemu-devel
  Cc: Pierrick Bouvier, Mahmoud Mandour, Alexandre Iooss,
	Alex Bennée, Rowan Hart

Signed-off-by: Rowan Hart <rowanbhart@gmail.com>
---
 docs/about/emulation.rst    |  14 ++++-
 tests/tcg/plugins/syscall.c | 117 ++++++++++++++++++++++++++++++++++++
 2 files changed, 130 insertions(+), 1 deletion(-)

diff --git a/docs/about/emulation.rst b/docs/about/emulation.rst
index eea1261baa..e85d494ff0 100644
--- a/docs/about/emulation.rst
+++ b/docs/about/emulation.rst
@@ -388,6 +388,19 @@ run::
   160          1      0
   135          1      0
 
+Behaviour can be tweaked with the following arguments:
+
+.. list-table:: Syscall plugin arguments
+  :widths: 20 80
+  :header-rows: 1
+
+  * - Option
+    - Description
+  * - print=true|false
+    - Print the number of times each syscall is called
+  * - log_writes=true|false
+    - Log the buffer of each write syscall in hexdump format
+
 Test inline operations
 ......................
 
@@ -777,4 +790,3 @@ Other emulation features
 When running system emulation you can also enable deterministic
 execution which allows for repeatable record/replay debugging. See
 :ref:`Record/Replay<replay>` for more details.
-
diff --git a/tests/tcg/plugins/syscall.c b/tests/tcg/plugins/syscall.c
index 72e1a5bf90..7c92f798b5 100644
--- a/tests/tcg/plugins/syscall.c
+++ b/tests/tcg/plugins/syscall.c
@@ -22,8 +22,57 @@ typedef struct {
     int64_t errors;
 } SyscallStats;
 
+struct SyscallInfo {
+    const char *name;
+    int64_t write_sysno;
+};
+
+const struct SyscallInfo arch_syscall_info[] = {
+    { "aarch64", 64 },
+    { "aarch64_be", 64 },
+    { "alpha", 4 },
+    { "arm", 4 },
+    { "armeb", 4 },
+    { "avr", -1 },
+    { "cris", -1 },
+    { "hexagon", 64 },
+    { "hppa", -1 },
+    { "i386", 4 },
+    { "loongarch64", -1 },
+    { "m68k", 4 },
+    { "microblaze", 4 },
+    { "microblazeel", 4 },
+    { "mips", 1 },
+    { "mips64", 1 },
+    { "mips64el", 1 },
+    { "mipsel", 1 },
+    { "mipsn32", 1 },
+    { "mipsn32el", 1 },
+    { "or1k", -1 },
+    { "ppc", 4 },
+    { "ppc64", 4 },
+    { "ppc64le", 4 },
+    { "riscv32", 64 },
+    { "riscv64", 64 },
+    { "rx", -1 },
+    { "s390x", -1 },
+    { "sh4", -1 },
+    { "sh4eb", -1 },
+    { "sparc", 4 },
+    { "sparc32plus", 4 },
+    { "sparc64", 4 },
+    { "tricore", -1 },
+    { "x86_64", 1 },
+    { "xtensa", 13 },
+    { "xtensaeb", 13 },
+    { NULL, -1 },
+};
+
 static GMutex lock;
 static GHashTable *statistics;
+static GByteArray *memory_buffer;
+static bool do_log_writes;
+static int64_t write_sysno = -1;
 
 static SyscallStats *get_or_create_entry(int64_t num)
 {
@@ -39,6 +88,44 @@ static SyscallStats *get_or_create_entry(int64_t num)
     return entry;
 }
 
+/*
+ * Hex-dump a GByteArray to the QEMU plugin output in the format:
+ * 61 63 63 65 6c 09 09 20 20 20 66 70 75 09 09 09  | accel.....fpu...
+ * 20 6d 6f 64 75 6c 65 2d 63 6f 6d 6d 6f 6e 2e 63  | .module-common.c
+ */
+static void hexdump(const GByteArray *data)
+{
+    g_autoptr(GString) out = g_string_new("");
+
+    for (guint index = 0; index < data->len; index += 16) {
+        for (guint col = 0; col < 16; col++) {
+            if (index + col < data->len) {
+                g_string_append_printf(out, "%02x ", data->data[index + col]);
+            } else {
+                g_string_append(out, "   ");
+            }
+        }
+
+        g_string_append(out, " | ");
+
+        for (guint col = 0; col < 16; col++) {
+            if (index + col >= data->len) {
+                break;
+            }
+
+            if (g_ascii_isgraph(data->data[index + col])) {
+                g_string_append_printf(out, "%c", data->data[index + col]);
+            } else {
+                g_string_append(out, ".");
+            }
+        }
+
+        g_string_append(out, "\n");
+    }
+
+    qemu_plugin_outs(out->str);
+}
+
 static void vcpu_syscall(qemu_plugin_id_t id, unsigned int vcpu_index,
                          int64_t num, uint64_t a1, uint64_t a2,
                          uint64_t a3, uint64_t a4, uint64_t a5,
@@ -54,6 +141,14 @@ static void vcpu_syscall(qemu_plugin_id_t id, unsigned int vcpu_index,
         g_autofree gchar *out = g_strdup_printf("syscall #%" PRIi64 "\n", num);
         qemu_plugin_outs(out);
     }
+
+    if (do_log_writes && num == write_sysno) {
+        if (qemu_plugin_read_memory_vaddr(a2, memory_buffer, a3)) {
+            hexdump(memory_buffer);
+        } else {
+            fprintf(stderr, "Error reading memory from vaddr %lu\n", a2);
+        }
+    }
 }
 
 static void vcpu_syscall_ret(qemu_plugin_id_t id, unsigned int vcpu_idx,
@@ -127,6 +222,10 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
             if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_print)) {
                 fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
             }
+        } else if (g_strcmp0(tokens[0], "log_writes") == 0) {
+            if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_log_writes)) {
+                fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
+            }
         } else {
             fprintf(stderr, "unsupported argument: %s\n", argv[i]);
             return -1;
@@ -137,6 +236,24 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
         statistics = g_hash_table_new_full(NULL, g_direct_equal, NULL, g_free);
     }
 
+    if (do_log_writes) {
+        for (const struct SyscallInfo *syscall_info = arch_syscall_info;
+            syscall_info->name != NULL; syscall_info++) {
+
+            if (g_strcmp0(syscall_info->name, info->target_name) == 0) {
+                write_sysno = syscall_info->write_sysno;
+                break;
+            }
+        }
+
+        if (write_sysno == -1) {
+            fprintf(stderr, "write syscall number not found\n");
+            return -1;
+        }
+
+        memory_buffer = g_byte_array_new();
+    }
+
     qemu_plugin_register_vcpu_syscall_cb(id, vcpu_syscall);
     qemu_plugin_register_vcpu_syscall_ret_cb(id, vcpu_syscall_ret);
     qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
-- 
2.46.0



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v2 1/2] plugins: add plugin API to read guest memory
  2024-08-27  2:18 ` [PATCH v2 1/2] " Rowan Hart
@ 2024-08-27 15:59   ` Pierrick Bouvier
  0 siblings, 0 replies; 5+ messages in thread
From: Pierrick Bouvier @ 2024-08-27 15:59 UTC (permalink / raw)
  To: Rowan Hart, qemu-devel; +Cc: Mahmoud Mandour, Alexandre Iooss, Alex Bennée

On 8/26/24 19:18, Rowan Hart wrote:
> Signed-off-by: Rowan Hart <rowanbhart@gmail.com>
> ---
>   include/qemu/qemu-plugin.h   | 32 +++++++++++++++++++++++++++++++-
>   plugins/api.c                | 20 ++++++++++++++++++++
>   plugins/qemu-plugins.symbols |  1 +
>   3 files changed, 52 insertions(+), 1 deletion(-)
> 
> diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
> index c71c705b69..10f9db8cdc 100644
> --- a/include/qemu/qemu-plugin.h
> +++ b/include/qemu/qemu-plugin.h
> @@ -57,11 +57,19 @@ typedef uint64_t qemu_plugin_id_t;
>    * - Remove qemu_plugin_register_vcpu_{tb, insn, mem}_exec_inline.
>    *   Those functions are replaced by *_per_vcpu variants, which guarantee
>    *   thread-safety for operations.
> + *
> + * version 3:
> + * - modified arguments and return value of qemu_plugin_insn_data to copy
> + *   the data into a user-provided buffer instead of returning a pointer
> + *   to the data.
> + *
> + * version 4:
> + * - added qemu_plugin_read_memory_vaddr
>    */
>   
>   extern QEMU_PLUGIN_EXPORT int qemu_plugin_version;
>   
> -#define QEMU_PLUGIN_VERSION 3
> +#define QEMU_PLUGIN_VERSION 4
>   
>   /**
>    * struct qemu_info_t - system information for plugins
> @@ -852,6 +860,28 @@ typedef struct {
>   QEMU_PLUGIN_API
>   GArray *qemu_plugin_get_registers(void);
>   
> +/**
> + * qemu_plugin_read_memory_vaddr() - read from memory using a virtual address
> + *
> + * @addr: A virtual address to read from
> + * @data: A byte array to store data into
> + * @len: The number of bytes to read, starting from @addr
> +

Missing '*' on this line, generating an error when building doc.

> + * @len bytes of data is read starting at @addr and stored into @data. If @data
> + * is not large enough to hold @len bytes, it will be expanded to the necessary
> + * size, reallocating if necessary. @len must be greater than 0.
> + *
> + * This function does not ensure writes are flushed prior to reading, so
> + * callers should take care when calling this function in plugin callbacks to
> + * avoid attempting to read data which may not yet be written and should use
> + * the memory callback API instead.
> + *
> + * Returns true on success and false on failure.
> + */
> +QEMU_PLUGIN_API
> +bool qemu_plugin_read_memory_vaddr(uint64_t addr,
> +                                          GByteArray *data, size_t len);
> +
>   /**
>    * qemu_plugin_read_register() - read register for current vCPU
>    *
> diff --git a/plugins/api.c b/plugins/api.c
> index 2ff13d09de..cb7d818918 100644
> --- a/plugins/api.c
> +++ b/plugins/api.c
> @@ -527,6 +527,26 @@ GArray *qemu_plugin_get_registers(void)
>       return create_register_handles(regs);
>   }
>   
> +bool qemu_plugin_read_memory_vaddr(vaddr addr, GByteArray *data, size_t len)
> +{
> +    g_assert(current_cpu);
> +
> +    if (len == 0) {
> +        return false;
> +    }
> +
> +    g_byte_array_set_size(data, len);
> +
> +    int result = cpu_memory_rw_debug(current_cpu, addr, data->data,
> +                                data->len, 0);
> +
> +    if (result < 0) {
> +        return false;
> +    }
> +
> +    return true;
> +}
> +
>   int qemu_plugin_read_register(struct qemu_plugin_register *reg, GByteArray *buf)
>   {
>       g_assert(current_cpu);
> diff --git a/plugins/qemu-plugins.symbols b/plugins/qemu-plugins.symbols
> index ca773d8d9f..3ad479a924 100644
> --- a/plugins/qemu-plugins.symbols
> +++ b/plugins/qemu-plugins.symbols
> @@ -20,6 +20,7 @@
>     qemu_plugin_num_vcpus;
>     qemu_plugin_outs;
>     qemu_plugin_path_to_binary;
> +  qemu_plugin_read_memory_vaddr;
>     qemu_plugin_read_register;
>     qemu_plugin_register_atexit_cb;
>     qemu_plugin_register_flush_cb;

Otherwise,
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>

@Rowan, for v3, you can add this "Reviewed-by: ..." line in your commit 
message, so it shows it was reviewed.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v2 2/2] plugins: add option to dump write argument to syscall plugin
  2024-08-27  2:18 ` [PATCH v2 2/2] plugins: add option to dump write argument to syscall plugin Rowan Hart
@ 2024-08-27 16:01   ` Pierrick Bouvier
  0 siblings, 0 replies; 5+ messages in thread
From: Pierrick Bouvier @ 2024-08-27 16:01 UTC (permalink / raw)
  To: Rowan Hart, qemu-devel; +Cc: Mahmoud Mandour, Alexandre Iooss, Alex Bennée

On 8/26/24 19:18, Rowan Hart wrote:
> Signed-off-by: Rowan Hart <rowanbhart@gmail.com>
> ---
>   docs/about/emulation.rst    |  14 ++++-
>   tests/tcg/plugins/syscall.c | 117 ++++++++++++++++++++++++++++++++++++
>   2 files changed, 130 insertions(+), 1 deletion(-)
> 
> diff --git a/docs/about/emulation.rst b/docs/about/emulation.rst
> index eea1261baa..e85d494ff0 100644
> --- a/docs/about/emulation.rst
> +++ b/docs/about/emulation.rst
> @@ -388,6 +388,19 @@ run::
>     160          1      0
>     135          1      0
>   
> +Behaviour can be tweaked with the following arguments:
> +
> +.. list-table:: Syscall plugin arguments
> +  :widths: 20 80
> +  :header-rows: 1
> +
> +  * - Option
> +    - Description
> +  * - print=true|false
> +    - Print the number of times each syscall is called
> +  * - log_writes=true|false
> +    - Log the buffer of each write syscall in hexdump format
> +
>   Test inline operations
>   ......................
>   
> @@ -777,4 +790,3 @@ Other emulation features
>   When running system emulation you can also enable deterministic
>   execution which allows for repeatable record/replay debugging. See
>   :ref:`Record/Replay<replay>` for more details.
> -
> diff --git a/tests/tcg/plugins/syscall.c b/tests/tcg/plugins/syscall.c
> index 72e1a5bf90..7c92f798b5 100644
> --- a/tests/tcg/plugins/syscall.c
> +++ b/tests/tcg/plugins/syscall.c
> @@ -22,8 +22,57 @@ typedef struct {
>       int64_t errors;
>   } SyscallStats;
>   
> +struct SyscallInfo {
> +    const char *name;
> +    int64_t write_sysno;
> +};
> +
> +const struct SyscallInfo arch_syscall_info[] = {
> +    { "aarch64", 64 },
> +    { "aarch64_be", 64 },
> +    { "alpha", 4 },
> +    { "arm", 4 },
> +    { "armeb", 4 },
> +    { "avr", -1 },
> +    { "cris", -1 },
> +    { "hexagon", 64 },
> +    { "hppa", -1 },
> +    { "i386", 4 },
> +    { "loongarch64", -1 },
> +    { "m68k", 4 },
> +    { "microblaze", 4 },
> +    { "microblazeel", 4 },
> +    { "mips", 1 },
> +    { "mips64", 1 },
> +    { "mips64el", 1 },
> +    { "mipsel", 1 },
> +    { "mipsn32", 1 },
> +    { "mipsn32el", 1 },
> +    { "or1k", -1 },
> +    { "ppc", 4 },
> +    { "ppc64", 4 },
> +    { "ppc64le", 4 },
> +    { "riscv32", 64 },
> +    { "riscv64", 64 },
> +    { "rx", -1 },
> +    { "s390x", -1 },
> +    { "sh4", -1 },
> +    { "sh4eb", -1 },
> +    { "sparc", 4 },
> +    { "sparc32plus", 4 },
> +    { "sparc64", 4 },
> +    { "tricore", -1 },
> +    { "x86_64", 1 },
> +    { "xtensa", 13 },
> +    { "xtensaeb", 13 },
> +    { NULL, -1 },
> +};
> +
>   static GMutex lock;
>   static GHashTable *statistics;
> +static GByteArray *memory_buffer;
> +static bool do_log_writes;
> +static int64_t write_sysno = -1;
>   
>   static SyscallStats *get_or_create_entry(int64_t num)
>   {
> @@ -39,6 +88,44 @@ static SyscallStats *get_or_create_entry(int64_t num)
>       return entry;
>   }
>   
> +/*
> + * Hex-dump a GByteArray to the QEMU plugin output in the format:
> + * 61 63 63 65 6c 09 09 20 20 20 66 70 75 09 09 09  | accel.....fpu...
> + * 20 6d 6f 64 75 6c 65 2d 63 6f 6d 6d 6f 6e 2e 63  | .module-common.c
> + */
> +static void hexdump(const GByteArray *data)
> +{
> +    g_autoptr(GString) out = g_string_new("");
> +
> +    for (guint index = 0; index < data->len; index += 16) {
> +        for (guint col = 0; col < 16; col++) {
> +            if (index + col < data->len) {
> +                g_string_append_printf(out, "%02x ", data->data[index + col]);
> +            } else {
> +                g_string_append(out, "   ");
> +            }
> +        }
> +
> +        g_string_append(out, " | ");
> +
> +        for (guint col = 0; col < 16; col++) {
> +            if (index + col >= data->len) {
> +                break;
> +            }
> +
> +            if (g_ascii_isgraph(data->data[index + col])) {
> +                g_string_append_printf(out, "%c", data->data[index + col]);
> +            } else {
> +                g_string_append(out, ".");
> +            }
> +        }
> +
> +        g_string_append(out, "\n");
> +    }
> +
> +    qemu_plugin_outs(out->str);
> +}
> +
>   static void vcpu_syscall(qemu_plugin_id_t id, unsigned int vcpu_index,
>                            int64_t num, uint64_t a1, uint64_t a2,
>                            uint64_t a3, uint64_t a4, uint64_t a5,
> @@ -54,6 +141,14 @@ static void vcpu_syscall(qemu_plugin_id_t id, unsigned int vcpu_index,
>           g_autofree gchar *out = g_strdup_printf("syscall #%" PRIi64 "\n", num);
>           qemu_plugin_outs(out);
>       }
> +
> +    if (do_log_writes && num == write_sysno) {
> +        if (qemu_plugin_read_memory_vaddr(a2, memory_buffer, a3)) {
> +            hexdump(memory_buffer);
> +        } else {
> +            fprintf(stderr, "Error reading memory from vaddr %lu\n", a2);
> +        }
> +    }
>   }
>   
>   static void vcpu_syscall_ret(qemu_plugin_id_t id, unsigned int vcpu_idx,
> @@ -127,6 +222,10 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
>               if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_print)) {
>                   fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
>               }
> +        } else if (g_strcmp0(tokens[0], "log_writes") == 0) {
> +            if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_log_writes)) {
> +                fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
> +            }
>           } else {
>               fprintf(stderr, "unsupported argument: %s\n", argv[i]);
>               return -1;
> @@ -137,6 +236,24 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
>           statistics = g_hash_table_new_full(NULL, g_direct_equal, NULL, g_free);
>       }
>   
> +    if (do_log_writes) {
> +        for (const struct SyscallInfo *syscall_info = arch_syscall_info;
> +            syscall_info->name != NULL; syscall_info++) {
> +
> +            if (g_strcmp0(syscall_info->name, info->target_name) == 0) {
> +                write_sysno = syscall_info->write_sysno;
> +                break;
> +            }
> +        }
> +
> +        if (write_sysno == -1) {
> +            fprintf(stderr, "write syscall number not found\n");
> +            return -1;
> +        }
> +
> +        memory_buffer = g_byte_array_new();
> +    }
> +
>       qemu_plugin_register_vcpu_syscall_cb(id, vcpu_syscall);
>       qemu_plugin_register_vcpu_syscall_ret_cb(id, vcpu_syscall_ret);
>       qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);

Works as expected.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Tested-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2024-08-27 16:01 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-27  2:18 [PATCH v2 0/2] plugins: add plugin API to read guest memory Rowan Hart
2024-08-27  2:18 ` [PATCH v2 1/2] " Rowan Hart
2024-08-27 15:59   ` Pierrick Bouvier
2024-08-27  2:18 ` [PATCH v2 2/2] plugins: add option to dump write argument to syscall plugin Rowan Hart
2024-08-27 16:01   ` Pierrick Bouvier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).