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: "Paolo Bonzini" <pbonzini@redhat.com>,
	"Thomas Huth" <thuth@redhat.com>,
	"Alexandre Iooss" <erdnaxe@crans.org>,
	"Mahmoud Mandour" <ma.mandourr@gmail.com>,
	"Eduardo Habkost" <eduardo@habkost.net>,
	"Marcel Apfelbaum" <marcel.apfelbaum@gmail.com>,
	"Philippe Mathieu-Daudé" <philmd@linaro.org>,
	"Yanan Wang" <wangyanan55@huawei.com>,
	"Richard Henderson" <richard.henderson@linaro.org>,
	"Marc-André Lureau" <marcandre.lureau@redhat.com>,
	"Daniel P. Berrangé" <berrange@redhat.com>,
	"John Snow" <jsnow@redhat.com>, "Cleber Rosa" <crosa@redhat.com>,
	"Peter Maydell" <peter.maydell@linaro.org>,
	"Michael Rolnik" <mrolnik@gmail.com>,
	"Edgar E. Iglesias" <edgar.iglesias@gmail.com>,
	"Brian Cain" <bcain@quicinc.com>,
	"Song Gao" <gaosong@loongson.cn>,
	"Xiaojuan Yang" <yangxiaojuan@loongson.cn>,
	"Laurent Vivier" <laurent@vivier.eu>,
	"Aurelien Jarno" <aurelien@aurel32.net>,
	"Jiaxun Yang" <jiaxun.yang@flygoat.com>,
	"Aleksandar Rikalo" <aleksandar.rikalo@syrmia.com>,
	"Chris Wulff" <crwulff@gmail.com>, "Marek Vasut" <marex@denx.de>,
	"Stafford Horne" <shorne@gmail.com>,
	"Daniel Henrique Barboza" <danielhb413@gmail.com>,
	"Cédric Le Goater" <clg@kaod.org>,
	"David Gibson" <david@gibson.dropbear.id.au>,
	"Greg Kurz" <groug@kaod.org>,
	"Nicholas Piggin" <npiggin@gmail.com>,
	"Palmer Dabbelt" <palmer@dabbelt.com>,
	"Alistair Francis" <alistair.francis@wdc.com>,
	"Bin Meng" <bin.meng@windriver.com>,
	"Weiwei Li" <liweiwei@iscas.ac.cn>,
	"Liu Zhiwei" <zhiwei_liu@linux.alibaba.com>,
	"Yoshinori Sato" <ysato@users.sourceforge.jp>,
	"David Hildenbrand" <david@redhat.com>,
	"Ilya Leoshkevich" <iii@linux.ibm.com>,
	"Mark Cave-Ayland" <mark.cave-ayland@ilande.co.uk>,
	"Artyom Tarasenko" <atar4qemu@gmail.com>,
	"Bastian Koppelmann" <kbastian@mail.uni-paderborn.de>,
	"Max Filippov" <jcmvbkbc@gmail.com>,
	qemu-devel@nongnu.org, qemu-arm@nongnu.org, qemu-ppc@nongnu.org,
	qemu-riscv@nongnu.org, qemu-s390x@nongnu.org
Subject: Re: [RFC PATCH 22/24] contrib/plugins: Allow to log registers
Date: Wed, 16 Aug 2023 23:59:00 +0900	[thread overview]
Message-ID: <1e71e3fe-8d34-4a66-aba6-aa0f569fbda2@daynix.com> (raw)
In-Reply-To: <87ttt1ps02.fsf@linaro.org>

On 2023/08/15 0:21, Alex Bennée wrote:
> 
> Akihiko Odaki <akihiko.odaki@daynix.com> writes:
> 
>> This demonstrates how a register can be read from a plugin.
> 
> I think it would be a little more useful as a demo if it tracked changes
> to the register state rather than dumping it for every line executed.
> 
>>
>> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
>> ---
>>   docs/devel/tcg-plugins.rst |  10 ++-
>>   contrib/plugins/execlog.c  | 130 ++++++++++++++++++++++++++++---------
>>   2 files changed, 108 insertions(+), 32 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 ce67acf145..031ad67fbb 100644
>> --- a/contrib/plugins/execlog.c
>> +++ b/contrib/plugins/execlog.c
>> @@ -15,27 +15,42 @@
>>   
>>   #include <qemu-plugin.h>
>>   
>> +typedef struct CPU {
>> +    /* Store last executed instruction on each vCPU as a GString */
>> +    GString *last_exec;
>> +    GByteArray *reg_buf;
>> +
>> +    int reg;
>> +} CPU;
>> +
>>   QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
>>   
>> -/* Store last executed instruction on each vCPU as a GString */
>> -static GPtrArray *last_exec;
>> +static CPU *cpus;
>> +static int num_cpus;
>>   static GRWLock expand_array_lock;
>>   
>>   static GPtrArray *imatches;
>>   static GArray *amatches;
>>   
>> +static char *rfile_name;
>> +static char *reg_name;
>> +
>>   /*
>> - * Expand last_exec array.
>> + * Expand cpu array.
>>    *
>>    * As we could have multiple threads trying to do this we need to
>>    * serialise the expansion under a lock.
>>    */
>> -static void expand_last_exec(int cpu_index)
>> +static void expand_cpu(int cpu_index)
>>   {
>> -    g_rw_lock_writer_unlock(&expand_array_lock);
>> -    while (cpu_index >= last_exec->len) {
>> -        GString *s = g_string_new(NULL);
>> -        g_ptr_array_add(last_exec, s);
>> +    g_rw_lock_writer_lock(&expand_array_lock);
>> +    if (cpu_index >= num_cpus) {
>> +        cpus = g_realloc_n(cpus, cpu_index + 1, sizeof(*cpus));
>> +        while (cpu_index >= num_cpus) {
>> +            cpus[num_cpus].last_exec = g_string_new(NULL);
>> +            cpus[num_cpus].reg_buf = g_byte_array_new();
>> +            num_cpus++;
>> +        }
>>       }
>>       g_rw_lock_writer_unlock(&expand_array_lock);
>>   }
>> @@ -50,8 +65,8 @@ static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t info,
>>   
>>       /* Find vCPU in array */
>>       g_rw_lock_reader_lock(&expand_array_lock);
>> -    g_assert(cpu_index < last_exec->len);
>> -    s = g_ptr_array_index(last_exec, cpu_index);
>> +    g_assert(cpu_index < num_cpus);
>> +    s = cpus[cpu_index].last_exec;
>>       g_rw_lock_reader_unlock(&expand_array_lock);
>>   
>>       /* Indicate type of memory access */
>> @@ -77,28 +92,35 @@ static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t info,
>>    */
>>   static void vcpu_insn_exec(unsigned int cpu_index, void *udata)
>>   {
>> -    GString *s;
>> +    CPU cpu;
>> +    int n;
>> +    int i;
>>   
>>       /* Find or create vCPU in array */
>>       g_rw_lock_reader_lock(&expand_array_lock);
>> -    if (cpu_index >= last_exec->len) {
>> -        g_rw_lock_reader_unlock(&expand_array_lock);
>> -        expand_last_exec(cpu_index);
>> -        g_rw_lock_reader_lock(&expand_array_lock);
>> -    }
>> -    s = g_ptr_array_index(last_exec, cpu_index);
>> +    cpu = cpus[cpu_index];
>>       g_rw_lock_reader_unlock(&expand_array_lock);
>>   
>>       /* Print previous instruction in cache */
>> -    if (s->len) {
>> -        qemu_plugin_outs(s->str);
>> +    if (cpu.last_exec->len) {
>> +        qemu_plugin_outs(cpu.last_exec->str);
>>           qemu_plugin_outs("\n");
>>       }
>>   
>>       /* 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(cpu.last_exec, "%u, ", cpu_index);
>> +    g_string_append(cpu.last_exec, (char *)udata);
>> +
>> +    if (cpu.reg >= 0) {
>> +        g_string_append(cpu.last_exec, ", reg,");
>> +        n = qemu_plugin_read_register(cpu.reg_buf, cpu.reg);
>> +        for (i = 0; i < n; i++) {
>> +            g_string_append_printf(cpu.last_exec, " 0x%02X",
>> +                                   cpu.reg_buf->data[i]);
>> +        }
> 
> so instead of:
> 
>    0, 0x4001b4, 0xd10043ff, "sub sp, sp, #0x10", reg, 0x70 0xFF 0x7F 0x00 0x00 0x40 0x00 0x00
> 
> we could aim for something like:
> 
>    0, 0x4001b4, 0xd10043ff, "sub sp, sp, #0x10", sp => 0x70ff7f0000400000

I changed this plugin so that it only emits register values when changed 
in v4 (I noticed I sent a wrong patch in v3), but it's not readable as 
much as your suggestion. It now emits like:

0, 0x4001b4, 0xd10043ff, "sub sp, sp, #0x10", reg, 70 ff 7f 00 00 40 00 00

This is because it's following the current CSV-like format of execlog 
output.

It will not also emit the value like 0x70ff7f0000400000 since the plugin 
does not know how the bytes should be interpreted. In fact, in this case 
I think it is in little endian and should be written as 0x4000007fff70. 
However the plugin does not have such knowledge.

> 
> 
>> +        g_byte_array_set_size(cpu.reg_buf, 0);
>> +    }
>>   }
>>   
>>   /**
>> @@ -167,8 +189,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 +201,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);
>> +    }
>> +
>> +    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 +284,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 +294,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]);
>>           } 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);
> 
> 


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

Thread overview: 61+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-07-31  8:43 [RFC PATCH 00/24] plugins: Allow to read registers Akihiko Odaki
2023-07-31  8:43 ` [RFC PATCH 01/24] contrib/plugins: Use GRWLock in execlog Akihiko Odaki
2023-08-14 10:48   ` Alex Bennée
2023-07-31  8:43 ` [RFC PATCH 02/24] gdbstub: Introduce GDBFeature structure Akihiko Odaki
2023-07-31 13:34   ` Philippe Mathieu-Daudé
2023-07-31 13:51   ` Philippe Mathieu-Daudé
2023-08-14 11:33   ` Alex Bennée
2023-07-31  8:43 ` [RFC PATCH 03/24] gdbstub: Add num_regs member to GDBFeature Akihiko Odaki
2023-07-31 13:35   ` Philippe Mathieu-Daudé
2023-08-14 11:44   ` Alex Bennée
2023-07-31  8:43 ` [RFC PATCH 04/24] gdbstub: Introduce gdb_find_static_feature() Akihiko Odaki
2023-07-31 13:52   ` Philippe Mathieu-Daudé
2023-08-14 11:56   ` Alex Bennée
2023-07-31  8:43 ` [RFC PATCH 05/24] target/arm: Move the reference to arm-core.xml Akihiko Odaki
2023-07-31  8:43 ` [RFC PATCH 06/24] hw/core/cpu: Replace gdb_core_xml_file with gdb_core_feature Akihiko Odaki
2023-07-31 13:27   ` Philippe Mathieu-Daudé
2023-07-31 13:37     ` Akihiko Odaki
2023-08-14 11:59   ` Alex Bennée
2023-08-16 13:47     ` Akihiko Odaki
2023-08-16 15:00       ` Alex Bennée
2023-08-16 15:10         ` Akihiko Odaki
2023-08-14 13:19   ` Alex Bennée
2023-07-31  8:43 ` [RFC PATCH 07/24] target/arm: Use GDBFeature for dynamic XML Akihiko Odaki
2023-07-31 13:44   ` Philippe Mathieu-Daudé
2023-07-31 14:00     ` Akihiko Odaki
2023-08-14 13:01   ` Alex Bennée
2023-07-31  8:43 ` [RFC PATCH 08/24] target/ppc: " Akihiko Odaki
2023-07-31 13:45   ` Philippe Mathieu-Daudé
2023-07-31  8:43 ` [RFC PATCH 09/24] target/riscv: " Akihiko Odaki
2023-07-31 13:46   ` Philippe Mathieu-Daudé
2023-07-31  8:43 ` [RFC PATCH 10/24] gdbstub: Use GDBFeature for gdb_register_coprocessor Akihiko Odaki
2023-08-14 13:13   ` Alex Bennée
2023-07-31  8:43 ` [RFC PATCH 11/24] gdbstub: Use GDBFeature for GDBRegisterState Akihiko Odaki
2023-07-31  8:43 ` [RFC PATCH 12/24] gdbstub: Simplify XML lookup Akihiko Odaki
2023-08-14 13:27   ` Alex Bennée
2023-08-16 13:51     ` Akihiko Odaki
2023-07-31  8:43 ` [RFC PATCH 13/24] hw/core/cpu: Remove gdb_get_dynamic_xml member Akihiko Odaki
2023-08-14 13:29   ` Alex Bennée
2023-07-31  8:43 ` [RFC PATCH 14/24] gdbstub: Add members to identify registers to GDBFeature Akihiko Odaki
2023-08-14 13:30   ` Alex Bennée
2023-07-31  8:43 ` [RFC PATCH 15/24] target/arm: Fill new members of GDBFeature Akihiko Odaki
2023-08-14 14:56   ` Alex Bennée
2023-08-16 14:23     ` Akihiko Odaki
2023-08-16 15:03       ` Alex Bennée
2023-08-16 15:11         ` Akihiko Odaki
2023-07-31  8:43 ` [RFC PATCH 16/24] target/ppc: " Akihiko Odaki
2023-07-31  8:43 ` [RFC PATCH 17/24] target/riscv: " Akihiko Odaki
2023-07-31  8:43 ` [RFC PATCH 18/24] hw/core/cpu: Add a parameter to gdb_read_register/gdb_write_register Akihiko Odaki
2023-07-31  8:43 ` [RFC PATCH 19/24] gdbstub: Hide gdb_has_xml Akihiko Odaki
2023-07-31  8:43 ` [RFC PATCH 20/24] gdbstub: Expose functions to read registers Akihiko Odaki
2023-07-31  8:43 ` [RFC PATCH 21/24] plugins: Allow " Akihiko Odaki
2023-08-14 15:05   ` Alex Bennée
2023-08-16 14:38     ` Akihiko Odaki
2023-07-31  8:43 ` [RFC PATCH 22/24] contrib/plugins: Allow to log registers Akihiko Odaki
2023-08-14 15:21   ` Alex Bennée
2023-08-16 14:59     ` Akihiko Odaki [this message]
2023-07-31  8:43 ` [RFC PATCH 23/24] plugins: Support C++ Akihiko Odaki
2023-07-31  8:43 ` [RFC PATCH 24/24] contrib/plugins: Add cc plugin Akihiko Odaki
2023-08-14 15:23   ` Alex Bennée
2023-08-16 15:04     ` Akihiko Odaki
2023-08-14 15:27 ` [RFC PATCH 00/24] plugins: Allow to read registers Alex Bennée

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=1e71e3fe-8d34-4a66-aba6-aa0f569fbda2@daynix.com \
    --to=akihiko.odaki@daynix.com \
    --cc=aleksandar.rikalo@syrmia.com \
    --cc=alex.bennee@linaro.org \
    --cc=alistair.francis@wdc.com \
    --cc=atar4qemu@gmail.com \
    --cc=aurelien@aurel32.net \
    --cc=bcain@quicinc.com \
    --cc=berrange@redhat.com \
    --cc=bin.meng@windriver.com \
    --cc=clg@kaod.org \
    --cc=crosa@redhat.com \
    --cc=crwulff@gmail.com \
    --cc=danielhb413@gmail.com \
    --cc=david@gibson.dropbear.id.au \
    --cc=david@redhat.com \
    --cc=edgar.iglesias@gmail.com \
    --cc=eduardo@habkost.net \
    --cc=erdnaxe@crans.org \
    --cc=gaosong@loongson.cn \
    --cc=groug@kaod.org \
    --cc=iii@linux.ibm.com \
    --cc=jcmvbkbc@gmail.com \
    --cc=jiaxun.yang@flygoat.com \
    --cc=jsnow@redhat.com \
    --cc=kbastian@mail.uni-paderborn.de \
    --cc=laurent@vivier.eu \
    --cc=liweiwei@iscas.ac.cn \
    --cc=ma.mandourr@gmail.com \
    --cc=marcandre.lureau@redhat.com \
    --cc=marcel.apfelbaum@gmail.com \
    --cc=marex@denx.de \
    --cc=mark.cave-ayland@ilande.co.uk \
    --cc=mrolnik@gmail.com \
    --cc=npiggin@gmail.com \
    --cc=palmer@dabbelt.com \
    --cc=pbonzini@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=philmd@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-ppc@nongnu.org \
    --cc=qemu-riscv@nongnu.org \
    --cc=qemu-s390x@nongnu.org \
    --cc=richard.henderson@linaro.org \
    --cc=shorne@gmail.com \
    --cc=thuth@redhat.com \
    --cc=wangyanan55@huawei.com \
    --cc=yangxiaojuan@loongson.cn \
    --cc=ysato@users.sourceforge.jp \
    --cc=zhiwei_liu@linux.alibaba.com \
    /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).