All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Alex Bennée" <alex.bennee@linaro.org>
To: Akihiko Odaki <akihiko.odaki@daynix.com>
Cc: Mikhail Tyutin <m.tyutin@yadro.com>,
	Aleksandr Anenkov <a.anenkov@yadro.com>,
	qemu-devel@nongnu.org, Alexandre Iooss <erdnaxe@crans.org>,
	Mahmoud Mandour <ma.mandourr@gmail.com>,
	Richard Henderson <richard.henderson@linaro.org>,
	Paolo Bonzini <pbonzini@redhat.com>
Subject: Re: [PATCH RESEND v5 24/26] contrib/plugins: Allow to log registers
Date: Wed, 30 Aug 2023 16:08:11 +0100	[thread overview]
Message-ID: <87a5u8r2a9.fsf@linaro.org> (raw)
In-Reply-To: <20230818033648.8326-25-akihiko.odaki@daynix.com>


Akihiko Odaki <akihiko.odaki@daynix.com> writes:

> This demonstrates how a register can be read from a plugin.
>
> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> ---
>  docs/devel/tcg-plugins.rst |  10 ++-
>  contrib/plugins/execlog.c  | 140 ++++++++++++++++++++++++++++---------
>  2 files changed, 117 insertions(+), 33 deletions(-)
>
> diff --git a/docs/devel/tcg-plugins.rst b/docs/devel/tcg-plugins.rst
> index 81dcd43a61..c9f8b27590 100644
> --- a/docs/devel/tcg-plugins.rst
> +++ b/docs/devel/tcg-plugins.rst
> @@ -497,6 +497,15 @@ arguments if required::
>    $ qemu-system-arm $(QEMU_ARGS) \
>      -plugin ./contrib/plugins/libexeclog.so,ifilter=st1w,afilter=0x40001808 -d plugin
>  
> +This plugin can also dump a specified register. The specification of register
> +follows `GDB standard target features <https://sourceware.org/gdb/onlinedocs/gdb/Standard-Target-Features.html>`__.
> +
> +Specify the name of the feature that contains the register and the name of the
> +register with ``rfile`` and ``reg`` options, respectively::
> +
> +  $ qemu-system-arm $(QEMU_ARGS) \
> +    -plugin ./contrib/plugins/libexeclog.so,rfile=org.gnu.gdb.arm.core,reg=sp -d plugin
> +
>  - contrib/plugins/cache.c
>  
>  Cache modelling plugin that measures the performance of a given L1 cache
> @@ -583,4 +592,3 @@ The following API is generated from the inline documentation in
>  include the full kernel-doc annotations.
>  
>  .. kernel-doc:: include/qemu/qemu-plugin.h
> -
> diff --git a/contrib/plugins/execlog.c b/contrib/plugins/execlog.c
> index 82dc2f584e..aa05840fd0 100644
> --- a/contrib/plugins/execlog.c
> +++ b/contrib/plugins/execlog.c
> @@ -15,27 +15,43 @@
>  
>  #include <qemu-plugin.h>
>  
> +typedef struct CPU {
> +    /* Store last executed instruction on each vCPU as a GString */
> +    GString *last_exec;
> +    GByteArray *reg_history[2];
> +
> +    int reg;
> +} CPU;
> +
>  QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
>  
<snip>
>  
>      /* Store new instruction in cache */
>      /* vcpu_mem will add memory access information to last_exec */
> -    g_string_printf(s, "%u, ", cpu_index);
> -    g_string_append(s, (char *)udata);
> +    g_string_printf(cpus[cpu_index].last_exec, "%u, ", cpu_index);
> +    g_string_append(cpus[cpu_index].last_exec, (char *)udata);
> +
> +    g_rw_lock_reader_unlock(&expand_array_lock);
>  }
>  
>  /**
> @@ -167,8 +197,10 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
>                                               QEMU_PLUGIN_MEM_RW, NULL);
>  
>              /* Register callback on instruction */
> -            qemu_plugin_register_vcpu_insn_exec_cb(insn, vcpu_insn_exec,
> -                                                   QEMU_PLUGIN_CB_NO_REGS, output);
> +            qemu_plugin_register_vcpu_insn_exec_cb(
> +                insn, vcpu_insn_exec,
> +                rfile_name ? QEMU_PLUGIN_CB_R_REGS : QEMU_PLUGIN_CB_NO_REGS,
> +                output);
>  
>              /* reset skip */
>              skip = (imatches || amatches);
> @@ -177,17 +209,53 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
>      }
>  }
>  
> +static void vcpu_init(qemu_plugin_id_t id, unsigned int vcpu_index)
> +{
> +    int reg = 0;
> +    bool found = false;
> +
> +    expand_cpu(vcpu_index);
> +
> +    if (rfile_name) {
> +        int i;
> +        int j;
> +        int n;
> +
> +        qemu_plugin_register_file_t *rfiles =
> +            qemu_plugin_get_register_files(vcpu_index, &n);
> +
> +        for (i = 0; i < n; i++) {
> +            if (g_strcmp0(rfiles[i].name, rfile_name) == 0) {
> +                for (j = 0; j < rfiles[i].num_regs; j++) {
> +                    if (g_strcmp0(rfiles[i].regs[j], reg_name) == 0) {
> +                        reg += j;
> +                        found = true;
> +                        break;
> +                    }
> +                }
> +                break;
> +            }
> +
> +            reg += rfiles[i].num_regs;
> +        }
> +
> +        g_free(rfiles);
> +    }

This makes me question the value of exposing the register file directly
to the plugin. I would much rather have a lookup utility function with
an optional tag. Something like:

  plugin_reg_t qemu_plugin_find_register(const char *name, const char *tag);

And make tag optional. I think in the general case "name" should be enough.

> +
> +    g_rw_lock_writer_lock(&expand_array_lock);
> +    cpus[vcpu_index].reg = found ? reg : -1;
> +    g_rw_lock_writer_unlock(&expand_array_lock);
> +}
> +
>  /**
>   * On plugin exit, print last instruction in cache
>   */
>  static void plugin_exit(qemu_plugin_id_t id, void *p)
>  {
>      guint i;
> -    GString *s;
> -    for (i = 0; i < last_exec->len; i++) {
> -        s = g_ptr_array_index(last_exec, i);
> -        if (s->str) {
> -            qemu_plugin_outs(s->str);
> +    for (i = 0; i < num_cpus; i++) {
> +        if (cpus[i].last_exec->str) {
> +            qemu_plugin_outs(cpus[i].last_exec->str);
>              qemu_plugin_outs("\n");
>          }
>      }
> @@ -224,9 +292,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
>       * we don't know the size before emulation.
>       */
>      if (info->system_emulation) {
> -        last_exec = g_ptr_array_sized_new(info->system.max_vcpus);
> -    } else {
> -        last_exec = g_ptr_array_new();
> +        cpus = g_new(CPU, info->system.max_vcpus);
>      }
>  
>      for (int i = 0; i < argc; i++) {
> @@ -236,13 +302,23 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
>              parse_insn_match(tokens[1]);
>          } else if (g_strcmp0(tokens[0], "afilter") == 0) {
>              parse_vaddr_match(tokens[1]);
> +        } else if (g_strcmp0(tokens[0], "rfile") == 0) {
> +            rfile_name = g_strdup(tokens[1]);
> +        } else if (g_strcmp0(tokens[0], "reg") == 0) {
> +            reg_name = g_strdup(tokens[1]);

And then instead of having the rfile/reg distinction support a command
line like:

  qemu-aarch64 -plugin contrib/plugins/libexeclog.so,reg=sp,reg=x1,reg=sve:p1

so if the user specifies a reg of the form TAG:REG we can pass that as
the option tag string. It also avoids exposing all the details of gdb to
plugins while still allowing the utility function to search by rname
internally (even if only a substring match?),


>          } else {
>              fprintf(stderr, "option parsing failed: %s\n", opt);
>              return -1;
>          }
>      }
>  
> +    if ((!rfile_name) != (!reg_name)) {
> +        fputs("file and reg need to be set at the same time\n", stderr);
> +        return -1;
> +    }
> +
>      /* Register translation block and exit callbacks */
> +    qemu_plugin_register_vcpu_init_cb(id, vcpu_init);
>      qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
>      qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);


-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


  reply	other threads:[~2023-08-30 15:14 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-18  3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 01/26] contrib/plugins: Use GRWLock in execlog Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 02/26] gdbstub: Introduce GDBFeature structure Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 03/26] gdbstub: Add num_regs member to GDBFeature Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 04/26] gdbstub: Introduce gdb_find_static_feature() Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 05/26] target/arm: Move the reference to arm-core.xml Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 06/26] hw/core/cpu: Replace gdb_core_xml_file with gdb_core_feature Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 07/26] gdbstub: Introduce GDBFeatureBuilder Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 08/26] target/arm: Use GDBFeature for dynamic XML Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 09/26] target/ppc: " Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 10/26] target/riscv: " Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 11/26] gdbstub: Use GDBFeature for gdb_register_coprocessor Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 12/26] gdbstub: Use GDBFeature for GDBRegisterState Akihiko Odaki
2023-08-30 14:59   ` Alex Bennée
2023-08-18  3:36 ` [PATCH RESEND v5 13/26] hw/core/cpu: Return static value with gdb_arch_name() Akihiko Odaki
2023-08-30 15:00   ` Alex Bennée
2023-08-18  3:36 ` [PATCH RESEND v5 14/26] gdbstub: Dynamically allocate target.xml buffer Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 15/26] gdbstub: Simplify XML lookup Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 16/26] hw/core/cpu: Remove gdb_get_dynamic_xml member Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 17/26] gdbstub: Add members to identify registers to GDBFeature Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 18/26] target/arm: Remove references to gdb_has_xml Akihiko Odaki
2023-08-30 15:02   ` Alex Bennée
2023-08-18  3:36 ` [PATCH RESEND v5 19/26] target/ppc: " Akihiko Odaki
2023-08-25  9:40   ` Nicholas Piggin
2023-08-18  3:36 ` [PATCH RESEND v5 20/26] gdbstub: Remove gdb_has_xml variable Akihiko Odaki
2023-08-30 15:02   ` Alex Bennée
2023-08-30 20:24     ` Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 21/26] gdbstub: Expose functions to read registers Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 22/26] cpu: Call plugin hooks only when ready Akihiko Odaki
2023-08-30 15:04   ` Alex Bennée
2023-08-18  3:36 ` [PATCH RESEND v5 23/26] plugins: Allow to read registers Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 24/26] contrib/plugins: Allow to log registers Akihiko Odaki
2023-08-30 15:08   ` Alex Bennée [this message]
2023-08-30 20:53     ` Akihiko Odaki
2023-09-04 15:30       ` Alex Bennée
2023-09-05  6:51         ` Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 25/26] plugins: Support C++ Akihiko Odaki
2023-08-18  3:36 ` [PATCH RESEND v5 26/26] contrib/plugins: Add cc plugin Akihiko Odaki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87a5u8r2a9.fsf@linaro.org \
    --to=alex.bennee@linaro.org \
    --cc=a.anenkov@yadro.com \
    --cc=akihiko.odaki@daynix.com \
    --cc=erdnaxe@crans.org \
    --cc=m.tyutin@yadro.com \
    --cc=ma.mandourr@gmail.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=richard.henderson@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.