qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Akihiko Odaki <akihiko.odaki@daynix.com>
To: "Alex Bennée" <alex.bennee@linaro.org>
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: Tue, 5 Sep 2023 15:51:04 +0900	[thread overview]
Message-ID: <fadd59c2-bd09-4195-be39-78b1f48e948e@daynix.com> (raw)
In-Reply-To: <877cp6hrpq.fsf@linaro.org>

On 2023/09/05 0:30, Alex Bennée wrote:
> 
> Akihiko Odaki <akihiko.odaki@daynix.com> writes:
> 
>> On 2023/08/31 0:08, Alex Bennée wrote:
>>> 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.
>>
>> I have explained the reason why I introduced register file abstraction
>> instead of adding a function to look up a register for an earlier
>> version of this series:
>>> I added a function that returns all register information instead of a
>>> function that looks up a register so that a plugin can enumerate
>>> registers. Such capability is useful for a plugin that dumps all
>>> registers or a plugin that simulates processor (such a plugin may want
>>> to warn if there are unknown registers).
> 
> Fair enough. However I think a simple search interface will also be
> useful for the more common case.

I'll add one in a future version.

> 
>> How would you define name and tag? They are something we currently do
>> not have, and I'm trying to add new types of identifiers since such
>> identifiers will be needed to be defined for different architectures
>> and require documentation and extra work to avoid name conflicts and
>> ensure interface stability.
> 
> The name would be the register name which AFAICT are unique across the
> system. If you have examples of clashes I'm curious as to what they are.

Here I'm talking about creating and maintaining a set of identifiers 
independent of GDB. I'm suggesting to reuse the identifiers GDB use 
since they are already designed so that there are no clashes.

> I'm still conflicted about baking gdb-isms into this ABI because they
> aren't as stable as they could be either. Either way we do state:
> 
>    This is a new feature for QEMU and it does allow people to develop
>    out-of-tree plugins that can be dynamically linked into a running QEMU
>    process. However the project reserves the right to change or break the
>    API should it need to do so. The best way to avoid this is to submit
>    your plugin upstream so they can be updated if/when the API changes.
> 
> So I'm not overly concerned about formalising a stable ABI for now.
> 
>>
>>>
>>>> +
>>>> +    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?),
>>
>> That implicitly assumes TAG does not contain a colon. I'm avoiding to
>> make such an implicit assumption because it is a reference for plugin
>> writers who may create out-of-tree plugins. We should retrain
>> ourselves to tell the plugin writers not to make such an assumption
>> that may not hold in the future version of QEMU.
>>
>> I consider a substring match harmful for a similar reason. There is no
>> guarantee that a future version of QEMU will not introduce a new
>> register that match with the existing substring and break interface
>> stability.
>>
>> It is not necessary that identifiers are consistent with ones GDB use.
>> What matters here is that the identifiers are documented, stable and
>> immune from conflicts.
> 
> We've a couple of cases of GDB having to issue new XML interface names
> to handle cases where the previous definition missed important bits.
> Hence my unease at exposing them to the plugin interface.

Why you had to issue new feature names when adding missing definitions? 
I expect the reasoning for changing GDB interface names should also 
apply for TCG plugins: when not changing interface names will break GDB, 
it should be also likely to break TCG plugins using the affected features.

I consider names used in GDB stable. GDB versions will break if they are 
not.

> 
> The plugin interface shouldn't (yet?) be regarded as a stable interface
> (c.f. above).
The plugin interface has been for almost 5 years. If it is not stable 
yet, when it will be? In any case, the interface stability should be 
considered as an eventual goal; otherwise the existing infrastructure 
for plugin API versioning will make no sense.


  reply	other threads:[~2023-09-05  6:51 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
2023-08-30 20:53     ` Akihiko Odaki
2023-09-04 15:30       ` Alex Bennée
2023-09-05  6:51         ` Akihiko Odaki [this message]
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=fadd59c2-bd09-4195-be39-78b1f48e948e@daynix.com \
    --to=akihiko.odaki@daynix.com \
    --cc=a.anenkov@yadro.com \
    --cc=alex.bennee@linaro.org \
    --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 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).