get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/1882117/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 1882117,
    "url": "http://patchwork.ozlabs.org/api/patches/1882117/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20240103173349.398526-41-alex.bennee@linaro.org/",
    "project": {
        "id": 14,
        "url": "http://patchwork.ozlabs.org/api/projects/14/?format=api",
        "name": "QEMU Development",
        "link_name": "qemu-devel",
        "list_id": "qemu-devel.nongnu.org",
        "list_email": "qemu-devel@nongnu.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20240103173349.398526-41-alex.bennee@linaro.org>",
    "list_archive_url": null,
    "date": "2024-01-03T17:33:46",
    "name": "[v2,40/43] contrib/plugins: extend execlog to track register changes",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "8c04b8daf590eaa93aadfb41a2d6ce479dc97402",
    "submitter": {
        "id": 39532,
        "url": "http://patchwork.ozlabs.org/api/people/39532/?format=api",
        "name": "Alex Bennée",
        "email": "alex.bennee@linaro.org"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20240103173349.398526-41-alex.bennee@linaro.org/mbox/",
    "series": [
        {
            "id": 388742,
            "url": "http://patchwork.ozlabs.org/api/series/388742/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=388742",
            "date": "2024-01-03T17:33:08",
            "name": "testing and plugin updates for 9.0 (pre-PR)",
            "version": 2,
            "mbox": "http://patchwork.ozlabs.org/series/388742/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/1882117/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/1882117/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256\n header.s=google header.b=Dmj9yqBH;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)"
        ],
        "Received": [
            "from lists.gnu.org (lists.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4T4xqf6nBTz1ydb\n\tfor <incoming@patchwork.ozlabs.org>; Thu,  4 Jan 2024 04:42:06 +1100 (AEDT)",
            "from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1rL5DX-0007yt-D9; Wed, 03 Jan 2024 12:39:47 -0500",
            "from eggs.gnu.org ([2001:470:142:3::10])\n by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <alex.bennee@linaro.org>)\n id 1rL5DV-0007uN-KP\n for qemu-devel@nongnu.org; Wed, 03 Jan 2024 12:39:45 -0500",
            "from mail-wr1-x42c.google.com ([2a00:1450:4864:20::42c])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)\n (Exim 4.90_1) (envelope-from <alex.bennee@linaro.org>)\n id 1rL5D4-0000nJ-29\n for qemu-devel@nongnu.org; Wed, 03 Jan 2024 12:39:45 -0500",
            "by mail-wr1-x42c.google.com with SMTP id\n ffacd0b85a97d-32f8441dfb5so10215749f8f.0\n for <qemu-devel@nongnu.org>; Wed, 03 Jan 2024 09:39:17 -0800 (PST)",
            "from draig.lan ([85.9.250.243]) by smtp.gmail.com with ESMTPSA id\n a16-20020a056000101000b003366a9cb0d1sm31080983wrx.92.2024.01.03.09.39.09\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Wed, 03 Jan 2024 09:39:13 -0800 (PST)",
            "from draig.lan (localhost [IPv6:::1])\n by draig.lan (Postfix) with ESMTP id 6B2135F9D5;\n Wed,  3 Jan 2024 17:33:53 +0000 (GMT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=linaro.org; s=google; t=1704303556; x=1704908356; darn=nongnu.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=6qYxYpnr0vzCXiIKNDoO95XioKhgHwYSQEn7vMTXP0k=;\n b=Dmj9yqBH0R9BNNEJZQN+FNhibX59WBNR3Code1eBTJenUa25jXSHbtf/Mf0IKX8MZe\n 6XCrym3EOptamH3G/VRfvXTab4yOa7VfOiXHr2c4D86w/Dk19JaYmvLP5DkFpdlfUcBd\n n5zQxqRocv+qN4aStvKE8zYkwPUe5zUueok/eZB4lKjPDGSvLFnyUQSXYhoKlivHHA3Y\n zLBt0Arf3oDaXQMU3/8DkBk624NJzpje9MfCfhPvvp3cCcMX2DTZ0kKtiipMNFsR232F\n tl4q5leS2u6C2kEDIuTDbmYVR04GPG0bXNy9IAoXKc3eLbdH75SJXNqgQChsM1dmRDOM\n dxvw==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1704303556; x=1704908356;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc\n :subject:date:message-id:reply-to;\n bh=6qYxYpnr0vzCXiIKNDoO95XioKhgHwYSQEn7vMTXP0k=;\n b=KiPtBdpRKp3+Q04iYjl98o2I1A8Q+UvBXVbgdHwAjaN7fPV3kxttUZuH0D9a5rQpCi\n OZH8lRqLLlGF5YhWEybJqYnIeqcyTZ/qC1AIXHHh0Xk9RYIOQxSPU+AlFEgDBT+Atz+r\n HMGGAkVbNTE6LidZlcGEpao2fHvawB3TyV6D019NyiGHOJbxFaHcTZXWm70QDIAhb30p\n DmFG8Pn7ATamWMHeqwDNnIMq0hVnPVlL+Bj5tY8/NSbBhx4nRuSZAi6d63y3mgC7JqQV\n BxsrAsHnhMZ5+ehfz9ThrB7RU7Ek7FQiFFyNiv1db8A/OCqMTtrXIzju5op2KLzyXDb2\n 5asw==",
        "X-Gm-Message-State": "AOJu0Yx9xvjnrjKWIbutZPdJ785TITLTcaa7mx4TZXTeSdehL7B+s7F8\n OPxhTcHABALb6YF3FrP0OpS+T/+2y1914A==",
        "X-Google-Smtp-Source": "\n AGHT+IFirHy9EDbCpJhUcCOWZ36HyZDOq8CLVldsPYnvJBVFXEf2kuTpqZW9jVagG31llrW0iPzfwg==",
        "X-Received": "by 2002:adf:e747:0:b0:336:6722:19f with SMTP id\n c7-20020adfe747000000b003366722019fmr10341379wrn.29.1704303556598;\n Wed, 03 Jan 2024 09:39:16 -0800 (PST)",
        "From": "=?utf-8?q?Alex_Benn=C3=A9e?= <alex.bennee@linaro.org>",
        "To": "qemu-devel@nongnu.org",
        "Cc": "qemu-s390x@nongnu.org, qemu-ppc@nongnu.org,\n Richard Henderson <richard.henderson@linaro.org>,\n Song Gao <gaosong@loongson.cn>,\n =?utf-8?q?Marc-Andr=C3=A9_Lureau?= <marcandre.lureau@redhat.com>,\n David Hildenbrand <david@redhat.com>, Aurelien Jarno <aurelien@aurel32.net>,\n Yoshinori Sato <ysato@users.sourceforge.jp>,\n Yanan Wang <wangyanan55@huawei.com>, Bin Meng <bin.meng@windriver.com>,\n Laurent Vivier <lvivier@redhat.com>, Michael Rolnik <mrolnik@gmail.com>,\n Alexandre Iooss <erdnaxe@crans.org>, David Woodhouse <dwmw2@infradead.org>,\n Laurent Vivier <laurent@vivier.eu>, Paolo Bonzini <pbonzini@redhat.com>,\n Brian Cain <bcain@quicinc.com>,\n Daniel Henrique Barboza <danielhb413@gmail.com>,\n Beraldo Leal <bleal@redhat.com>, Paul Durrant <paul@xen.org>,\n Mahmoud Mandour <ma.mandourr@gmail.com>, Thomas Huth <thuth@redhat.com>,\n Liu Zhiwei <zhiwei_liu@linux.alibaba.com>, Cleber Rosa <crosa@redhat.com>,\n kvm@vger.kernel.org, Peter Maydell <peter.maydell@linaro.org>,\n Wainer dos Santos Moschetta <wainersm@redhat.com>, =?utf-8?q?Alex_Benn?=\n\t=?utf-8?q?=C3=A9e?= <alex.bennee@linaro.org>, qemu-arm@nongnu.org,\n Weiwei Li <liwei1518@gmail.com>,\n =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= <philmd@linaro.org>,\n John Snow <jsnow@redhat.com>,\n Daniel Henrique Barboza <dbarboza@ventanamicro.com>,\n Nicholas Piggin <npiggin@gmail.com>, Palmer Dabbelt <palmer@dabbelt.com>,\n Marcel Apfelbaum <marcel.apfelbaum@gmail.com>,\n Ilya Leoshkevich <iii@linux.ibm.com>,\n =?utf-8?q?C=C3=A9dric_Le_Goater?= <clg@kaod.org>,\n \"Edgar E. Iglesias\" <edgar.iglesias@gmail.com>,\n Eduardo Habkost <eduardo@habkost.net>,\n Pierrick Bouvier <pierrick.bouvier@linaro.org>, qemu-riscv@nongnu.org,\n Alistair Francis <alistair.francis@wdc.com>,\n Akihiko Odaki <akihiko.odaki@daynix.com>",
        "Subject": "[PATCH v2 40/43] contrib/plugins: extend execlog to track register\n changes",
        "Date": "Wed,  3 Jan 2024 17:33:46 +0000",
        "Message-Id": "<20240103173349.398526-41-alex.bennee@linaro.org>",
        "X-Mailer": "git-send-email 2.39.2",
        "In-Reply-To": "<20240103173349.398526-1-alex.bennee@linaro.org>",
        "References": "<20240103173349.398526-1-alex.bennee@linaro.org>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=UTF-8",
        "Content-Transfer-Encoding": "8bit",
        "Received-SPF": "pass client-ip=2a00:1450:4864:20::42c;\n envelope-from=alex.bennee@linaro.org; helo=mail-wr1-x42c.google.com",
        "X-Spam_score_int": "-20",
        "X-Spam_score": "-2.1",
        "X-Spam_bar": "--",
        "X-Spam_report": "(-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,\n DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001,\n T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no",
        "X-Spam_action": "no action",
        "X-BeenThere": "qemu-devel@nongnu.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "<qemu-devel.nongnu.org>",
        "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.nongnu.org/archive/html/qemu-devel>",
        "List-Post": "<mailto:qemu-devel@nongnu.org>",
        "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>",
        "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>",
        "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org",
        "Sender": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org"
    },
    "content": "With the new plugin register API we can now track changes to register\nvalues. Currently the implementation is fairly dumb which will slow\ndown if a large number of register values are being tracked. This\ncould be improved by only instrumenting instructions which mention\nregisters we are interested in tracking.\n\nExample usage:\n\n  ./qemu-aarch64 -D plugin.log -d plugin \\\n     -cpu max,sve256=on \\\n     -plugin contrib/plugins/libexeclog.so,reg=sp,reg=z\\* \\\n     ./tests/tcg/aarch64-linux-user/sha512-sve\n\nwill display in the execlog any changes to the stack pointer (sp) and\nthe SVE Z registers.\n\nSigned-off-by: Alex Bennée <alex.bennee@linaro.org>\nCc: Akihiko Odaki <akihiko.odaki@daynix.com>\nBased-On: <20231025093128.33116-19-akihiko.odaki@daynix.com>\n\n---\nv3\n  - prefix 0x to register value\nv2\n  - we now do the glob-like search in the plugin itself.\n  - fix some erroneous cpus->cpu\n\nvAJB:\n\nChanges for the new API with a simpler glob based \"reg\" specifier\nwhich can be specified multiple times.\n---\n docs/devel/tcg-plugins.rst |   9 +-\n contrib/plugins/execlog.c  | 189 ++++++++++++++++++++++++++++---------\n 2 files changed, 153 insertions(+), 45 deletions(-)",
    "diff": "diff --git a/docs/devel/tcg-plugins.rst b/docs/devel/tcg-plugins.rst\nindex 81dcd43a612..3a0962723d7 100644\n--- a/docs/devel/tcg-plugins.rst\n+++ b/docs/devel/tcg-plugins.rst\n@@ -497,6 +497,14 @@ arguments if required::\n   $ qemu-system-arm $(QEMU_ARGS) \\\n     -plugin ./contrib/plugins/libexeclog.so,ifilter=st1w,afilter=0x40001808 -d plugin\n \n+This plugin can also dump registers when they change value. Specify the name of the\n+registers with multiple ``reg`` options. You can also use glob style matching if you wish::\n+\n+  $ qemu-system-arm $(QEMU_ARGS) \\\n+    -plugin ./contrib/plugins/libexeclog.so,reg=\\*_el2,reg=sp -d plugin\n+\n+Be aware that each additional register to check will slow down execution quite considerably.\n+\n - contrib/plugins/cache.c\n \n Cache modelling plugin that measures the performance of a given L1 cache\n@@ -583,4 +591,3 @@ The following API is generated from the inline documentation in\n include the full kernel-doc annotations.\n \n .. kernel-doc:: include/qemu/qemu-plugin.h\n-\ndiff --git a/contrib/plugins/execlog.c b/contrib/plugins/execlog.c\nindex f262e5555eb..c20e88a6941 100644\n--- a/contrib/plugins/execlog.c\n+++ b/contrib/plugins/execlog.c\n@@ -1,7 +1,7 @@\n /*\n  * Copyright (C) 2021, Alexandre Iooss <erdnaxe@crans.org>\n  *\n- * Log instruction execution with memory access.\n+ * Log instruction execution with memory access and register changes\n  *\n  * License: GNU GPL, version 2 or later.\n  *   See the COPYING file in the top-level directory.\n@@ -15,30 +15,29 @@\n \n #include <qemu-plugin.h>\n \n+typedef struct {\n+    struct qemu_plugin_register *handle;\n+    GByteArray *last;\n+    GByteArray *new;\n+    const char *name;\n+} Register;\n+\n+typedef struct CPU {\n+    /* Store last executed instruction on each vCPU as a GString */\n+    GString *last_exec;\n+    /* Ptr array of Register */\n+    GPtrArray *registers;\n+} CPU;\n+\n QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;\n \n-/* Store last executed instruction on each vCPU as a GString */\n-static GPtrArray *last_exec;\n+static CPU *cpus;\n+static int num_cpus;\n static GRWLock expand_array_lock;\n \n static GPtrArray *imatches;\n static GArray *amatches;\n-\n-/*\n- * Expand last_exec array.\n- *\n- * As we could have multiple threads trying to do this we need to\n- * serialise the expansion under a lock.\n- */\n-static void expand_last_exec(int cpu_index)\n-{\n-    g_rw_lock_writer_lock(&expand_array_lock);\n-    while (cpu_index >= last_exec->len) {\n-        GString *s = g_string_new(NULL);\n-        g_ptr_array_add(last_exec, s);\n-    }\n-    g_rw_lock_writer_unlock(&expand_array_lock);\n-}\n+static GPtrArray *rmatches;\n \n /**\n  * Add memory read or write information to current instruction log\n@@ -50,8 +49,8 @@ static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t info,\n \n     /* Find vCPU in array */\n     g_rw_lock_reader_lock(&expand_array_lock);\n-    g_assert(cpu_index < last_exec->len);\n-    s = g_ptr_array_index(last_exec, cpu_index);\n+    g_assert(cpu_index < num_cpus);\n+    s = cpus[cpu_index].last_exec;\n     g_rw_lock_reader_unlock(&expand_array_lock);\n \n     /* Indicate type of memory access */\n@@ -77,28 +76,46 @@ static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t info,\n  */\n static void vcpu_insn_exec(unsigned int cpu_index, void *udata)\n {\n-    GString *s;\n+    CPU *cpu;\n \n-    /* Find or create vCPU in array */\n     g_rw_lock_reader_lock(&expand_array_lock);\n-    if (cpu_index >= last_exec->len) {\n-        g_rw_lock_reader_unlock(&expand_array_lock);\n-        expand_last_exec(cpu_index);\n-        g_rw_lock_reader_lock(&expand_array_lock);\n-    }\n-    s = g_ptr_array_index(last_exec, cpu_index);\n+    g_assert(cpu_index < num_cpus);\n+    cpu = &cpus[cpu_index];\n     g_rw_lock_reader_unlock(&expand_array_lock);\n \n     /* Print previous instruction in cache */\n-    if (s->len) {\n-        qemu_plugin_outs(s->str);\n+    if (cpu->last_exec->len) {\n+        if (cpu->registers) {\n+            for (int n = 0; n < cpu->registers->len; n++) {\n+                Register *reg = cpu->registers->pdata[n];\n+                int sz;\n+\n+                g_byte_array_set_size(reg->new, 0);\n+                sz = qemu_plugin_read_register(cpu_index, reg->handle, reg->new);\n+                g_assert(sz == reg->last->len);\n+\n+                if (memcmp(reg->last->data, reg->new->data, sz)) {\n+                    GByteArray *temp = reg->last;\n+                    g_string_append_printf(cpu->last_exec, \", %s -> 0x\", reg->name);\n+                    /* TODO: handle BE properly */\n+                    for (int i = sz; i >= 0; i--) {\n+                        g_string_append_printf(cpu->last_exec, \"%02x\",\n+                                               reg->new->data[i]);\n+                    }\n+                    reg->last = reg->new;\n+                    reg->new = temp;\n+                }\n+            }\n+        }\n+\n+        qemu_plugin_outs(cpu->last_exec->str);\n         qemu_plugin_outs(\"\\n\");\n     }\n \n     /* Store new instruction in cache */\n     /* vcpu_mem will add memory access information to last_exec */\n-    g_string_printf(s, \"%u, \", cpu_index);\n-    g_string_append(s, (char *)udata);\n+    g_string_printf(cpus[cpu_index].last_exec, \"%u, \", cpu_index);\n+    g_string_append(cpus[cpu_index].last_exec, (char *)udata);\n }\n \n /**\n@@ -167,8 +184,10 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)\n                                              QEMU_PLUGIN_MEM_RW, NULL);\n \n             /* Register callback on instruction */\n-            qemu_plugin_register_vcpu_insn_exec_cb(insn, vcpu_insn_exec,\n-                                                   QEMU_PLUGIN_CB_NO_REGS, output);\n+            qemu_plugin_register_vcpu_insn_exec_cb(\n+                insn, vcpu_insn_exec,\n+                rmatches ? QEMU_PLUGIN_CB_R_REGS : QEMU_PLUGIN_CB_NO_REGS,\n+                output);\n \n             /* reset skip */\n             skip = (imatches || amatches);\n@@ -177,17 +196,86 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)\n     }\n }\n \n+static Register *init_vcpu_register(int vcpu_index,\n+                                    qemu_plugin_reg_descriptor *desc)\n+{\n+    Register *reg = g_new0(Register, 1);\n+    int r;\n+\n+    reg->handle = desc->handle;\n+    reg->name = g_strdup(desc->name);\n+    reg->last = g_byte_array_new();\n+    reg->new = g_byte_array_new();\n+\n+    /* read the initial value */\n+    r = qemu_plugin_read_register(vcpu_index, reg->handle, reg->last);\n+    g_assert(r > 0);\n+    return reg;\n+}\n+\n+static registers_init(int vcpu_index)\n+{\n+    GPtrArray *registers = g_ptr_array_new();\n+    g_autoptr(GArray) reg_list = qemu_plugin_get_registers(vcpu_index);\n+\n+    if (reg_list && reg_list->len) {\n+        /*\n+         * Go through each register in the complete list and\n+         * see if we want to track it.\n+         */\n+        for (int r = 0; r < reg_list->len; r++) {\n+            qemu_plugin_reg_descriptor *rd = &g_array_index(\n+                reg_list, qemu_plugin_reg_descriptor, r);\n+            for (int p = 0; p < rmatches->len; p++) {\n+                g_autoptr(GPatternSpec) pat = g_pattern_spec_new(rmatches->pdata[p]);\n+                if (g_pattern_match_string(pat, rd->name)) {\n+                    Register *reg = init_vcpu_register(vcpu_index, rd);\n+                    g_ptr_array_add(registers, reg);\n+                }\n+            }\n+        }\n+    }\n+    cpus[num_cpus].registers = registers;\n+}\n+\n+/*\n+ * Initialise a new vcpu/thread with:\n+ *   - last_exec tracking data\n+ *   - list of tracked registers\n+ *   - initial value of registers\n+ *\n+ * As we could have multiple threads trying to do this we need to\n+ * serialise the expansion under a lock.\n+ */\n+static void vcpu_init(qemu_plugin_id_t id, unsigned int vcpu_index)\n+{\n+    g_rw_lock_writer_lock(&expand_array_lock);\n+\n+    if (vcpu_index >= num_cpus) {\n+        cpus = g_realloc_n(cpus, vcpu_index + 1, sizeof(*cpus));\n+        while (vcpu_index >= num_cpus) {\n+            cpus[num_cpus].last_exec = g_string_new(NULL);\n+\n+            /* Any registers to track? */\n+            if (rmatches && rmatches->len) {\n+                registers_init(vcpu_index);\n+            }\n+            num_cpus++;\n+        }\n+    }\n+\n+    g_rw_lock_writer_unlock(&expand_array_lock);\n+}\n+\n /**\n  * On plugin exit, print last instruction in cache\n  */\n static void plugin_exit(qemu_plugin_id_t id, void *p)\n {\n     guint i;\n-    GString *s;\n-    for (i = 0; i < last_exec->len; i++) {\n-        s = g_ptr_array_index(last_exec, i);\n-        if (s->str) {\n-            qemu_plugin_outs(s->str);\n+    for (i = 0; i < num_cpus; i++) {\n+        if (cpus[i].last_exec->str) {\n+            qemu_plugin_outs(cpus[i].last_exec->str);\n             qemu_plugin_outs(\"\\n\");\n         }\n     }\n@@ -212,6 +300,18 @@ static void parse_vaddr_match(char *match)\n     g_array_append_val(amatches, v);\n }\n \n+/*\n+ * We have to wait until vCPUs are started before we can check the\n+ * patterns find anything.\n+ */\n+static void add_regpat(char *regpat)\n+{\n+    if (!rmatches) {\n+        rmatches = g_ptr_array_new();\n+    }\n+    g_ptr_array_add(rmatches, g_strdup(regpat));\n+}\n+\n /**\n  * Install the plugin\n  */\n@@ -224,9 +324,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,\n      * we don't know the size before emulation.\n      */\n     if (info->system_emulation) {\n-        last_exec = g_ptr_array_sized_new(info->system.max_vcpus);\n-    } else {\n-        last_exec = g_ptr_array_new();\n+        cpus = g_new(CPU, info->system.max_vcpus);\n     }\n \n     for (int i = 0; i < argc; i++) {\n@@ -236,13 +334,16 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,\n             parse_insn_match(tokens[1]);\n         } else if (g_strcmp0(tokens[0], \"afilter\") == 0) {\n             parse_vaddr_match(tokens[1]);\n+        } else if (g_strcmp0(tokens[0], \"reg\") == 0) {\n+            add_regpat(tokens[1]);\n         } else {\n             fprintf(stderr, \"option parsing failed: %s\\n\", opt);\n             return -1;\n         }\n     }\n \n-    /* Register translation block and exit callbacks */\n+    /* Register init, translation block and exit callbacks */\n+    qemu_plugin_register_vcpu_init_cb(id, vcpu_init);\n     qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);\n     qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);\n \n",
    "prefixes": [
        "v2",
        "40/43"
    ]
}