qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH  v4 00/54] plugins for TCG
@ 2019-07-31 16:06 Alex Bennée
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 01/54] target/arm: handle M-profile semihosting at translate time Alex Bennée
                   ` (56 more replies)
  0 siblings, 57 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: bobby.prani, cota, Alex Bennée, aaron

Hi,

This is the latest iteration of the plugins series. The main changes
from the last version are:

  - dropped passing of haddr to plugins

This makes the code for handling the plugins less invasive in the
softmmu path at the cost of offloading processing to the plugin if it
wants the value. We rely on the fact that the TLB is per vCPU so a
helper can just trigger a re-query of the TLB to get the final
address.

Part of that change involved embedding the MMU index in the meminfo
field for tracing. I see there are some other patches on the list for
messing with TCGMemOp so there might be a clash coming up.

  - translator_ld goes direct to softmmu/user functions

I also mark the [SOFTMMU_]CODE_ACCESS helpers as deprecated. There is
more work to be done to clean up all the current uses of code access
helpers but ideally the only thing that should be peaking at code is
the translator loop itself. However a bunch of helpers have taken to
using code loading functions to peak at the instruction just executed
to figure out what to do. Once those have been fixed then we can
remove those helpers.

Other more minor fixes can be found documented bellow the --- in the
individual patches.

This series also includes the semihosting patches as they are a
pre-requisite for the translator_ld patches for ARM.

Once the tree opens up for development again I hope to get the
semihosting and trivial clean-up patches merged quickly so the patch
count for the plugins patches proper can be reduced a bit.

The following patches need review
  patch 0004/target arm remove run time semihosting checks.patch
  patch 0005/includes remove stale smp max _cpus externs.patch
  patch 0007/trace add mmu_index to mem_info.patch
  patch 0011/docs devel add plugins.rst design document.patch
  patch 0012/configure add enable plugins MOVE TO END.patch
  patch 0015/plugin add implementation of the api.patch
  patch 0024/plugins implement helpers for resolving hwaddr.patch
  patch 0047/tests tcg enable plugin testing.patch
  patch 0048/tests plugin add a hotblocks plugin.patch
  patch 0050/tests plugin add instruction execution breakdown.patch
  patch 0051/tests plugin add hotpages plugin to breakdown mem.patch
  patch 0053/include exec wrap cpu_ldst.h in CONFIG_TCG.patch

Alex Bennée (18):
  target/arm: handle M-profile semihosting at translate time
  target/arm: handle A-profile T32 semihosting at translate time
  target/arm: handle A-profile A32 semihosting at translate time
  target/arm: remove run time semihosting checks
  includes: remove stale [smp|max]_cpus externs
  trace: add mmu_index to mem_info
  docs/devel: add plugins.rst design document
  configure: add --enable-plugins (MOVE TO END)
  plugin: add implementation of the api
  plugins: implement helpers for resolving hwaddr
  tests/tcg: enable plugin testing
  tests/plugin: add a hotblocks plugin
  plugin: add qemu_plugin_insn_disas helper
  tests/plugin: add instruction execution breakdown
  tests/plugin: add hotpages plugin to breakdown memory access patterns
  accel/stubs: reduce headers from tcg-stub
  include/exec: wrap cpu_ldst.h in CONFIG_TCG
  include/exec/cpu-defs.h: fix typo

Emilio G. Cota (34):
  trace: expand mem_info:size_shift to 4 bits
  tcg/README: fix typo s/afterwise/afterwards/
  cpu: introduce cpu_in_exclusive_context()
  translate-all: use cpu_in_exclusive_work_context() in tb_flush
  plugin: add user-facing API
  plugin: add core code
  queue: add QTAILQ_REMOVE_SEVERAL
  cputlb: document get_page_addr_code
  cputlb: introduce get_page_addr_code_hostp
  tcg: add tcg_gen_st_ptr
  plugin-gen: add module for TCG-related code
  atomic_template: fix indentation in GEN_ATOMIC_HELPER
  atomic_template: add inline trace/plugin helpers
  tcg: let plugins instrument virtual memory accesses
  translate-all: notify plugin code of tb_flush
  *-user: notify plugin of exit
  *-user: plugin syscalls
  cpu: hook plugin vcpu events
  plugin-gen: add plugin_insn_append
  translator: add translator_ld{ub,sw,uw,l,q}
  target/arm: fetch code with translator_ld
  target/ppc: fetch code with translator_ld
  target/sh4: fetch code with translator_ld
  target/i386: fetch code with translator_ld
  target/hppa: fetch code with translator_ld
  target/m68k: fetch code with translator_ld
  target/alpha: fetch code with translator_ld
  target/riscv: fetch code with translator_ld
  target/sparc: fetch code with translator_ld
  target/xtensa: fetch code with translator_ld
  target/openrisc: fetch code with translator_ld
  translator: inject instrumentation from plugins
  plugin: add API symbols to qemu-plugins.symbols
  tests/plugin: add sample plugins

Lluís Vilanova (2):
  vl: support -plugin option
  linux-user: support -plugin option

 Makefile                                  |  10 +-
 Makefile.target                           |   2 +
 accel/stubs/tcg-stub.c                    |   3 -
 accel/tcg/Makefile.objs                   |   1 +
 accel/tcg/atomic_common.inc.c             |  54 ++
 accel/tcg/atomic_template.h               |  96 ++-
 accel/tcg/cpu-exec.c                      |   8 +-
 accel/tcg/cputlb.c                        |  69 +-
 accel/tcg/plugin-gen.c                    | 977 ++++++++++++++++++++++
 accel/tcg/plugin-helpers.h                |   5 +
 accel/tcg/translate-all.c                 |  15 +-
 accel/tcg/translator.c                    |  20 +
 accel/tcg/user-exec.c                     |   3 +
 bsd-user/syscall.c                        |  24 +-
 configure                                 |  86 +-
 cpus-common.c                             |   4 +
 cpus.c                                    |  10 +
 disas.c                                   | 103 +++
 docs/devel/index.rst                      |   1 +
 docs/devel/plugins.rst                    | 107 +++
 exec.c                                    |   2 +
 include/disas/disas.h                     |   2 +
 include/exec/cpu-defs.h                   |   3 +-
 include/exec/cpu_ldst.h                   |  11 +
 include/exec/cpu_ldst_template.h          |  37 +-
 include/exec/cpu_ldst_useronly_template.h |  29 +-
 include/exec/exec-all.h                   |  81 +-
 include/exec/helper-gen.h                 |   1 +
 include/exec/helper-proto.h               |   1 +
 include/exec/helper-tcg.h                 |   1 +
 include/exec/plugin-gen.h                 |  71 ++
 include/exec/translator.h                 |  58 +-
 include/qemu/bswap.h                      |   5 +
 include/qemu/plugin.h                     | 261 ++++++
 include/qemu/qemu-plugin.h                | 360 ++++++++
 include/qemu/queue.h                      |  10 +
 include/qom/cpu.h                         |  19 +
 include/sysemu/sysemu.h                   |   2 -
 include/user/syscall-trace.h              |  40 +
 linux-user/exit.c                         |   1 +
 linux-user/main.c                         |  18 +
 linux-user/syscall.c                      |   7 +-
 plugins/.gitignore                        |   2 +
 plugins/Makefile.objs                     |  21 +
 plugins/api.c                             | 338 ++++++++
 plugins/core.c                            | 499 +++++++++++
 plugins/loader.c                          | 353 ++++++++
 plugins/plugin.h                          |  95 +++
 plugins/qemu-plugins.symbols              |  39 +
 qemu-options.hx                           |  17 +
 qom/cpu.c                                 |   2 +
 scripts/tracetool/transform.py            |   1 +
 target/alpha/translate.c                  |   2 +-
 target/arm/arm_ldst.h                     |  15 +-
 target/arm/helper.c                       |  90 +-
 target/arm/m_helper.c                     |  18 +-
 target/arm/translate.c                    |  64 +-
 target/hppa/translate.c                   |   2 +-
 target/i386/translate.c                   |  10 +-
 target/m68k/translate.c                   |   2 +-
 target/openrisc/translate.c               |   2 +-
 target/ppc/translate.c                    |   8 +-
 target/riscv/translate.c                  |   2 +-
 target/sh4/translate.c                    |   4 +-
 target/sparc/translate.c                  |   2 +-
 target/xtensa/translate.c                 |   4 +-
 tcg/README                                |   2 +-
 tcg/tcg-op.c                              |  40 +-
 tcg/tcg-op.h                              |  16 +
 tcg/tcg-opc.h                             |   3 +
 tcg/tcg.c                                 |  22 +
 tcg/tcg.h                                 |  23 +
 tests/Makefile.include                    |  10 +-
 tests/plugin/Makefile                     |  31 +
 tests/plugin/bb.c                         |  65 ++
 tests/plugin/empty.c                      |  29 +
 tests/plugin/hotblocks.c                  | 146 ++++
 tests/plugin/hotpages.c                   | 179 ++++
 tests/plugin/howvec.c                     | 301 +++++++
 tests/plugin/insn.c                       |  62 ++
 tests/plugin/mem.c                        |  96 +++
 tests/tcg/Makefile                        |  34 +
 tests/tcg/arm/Makefile.softmmu-target     |   1 +
 trace-events                              |   8 +-
 trace/mem-internal.h                      |  31 +-
 trace/mem.h                               |   7 +-
 vl.c                                      |  11 +
 87 files changed, 5067 insertions(+), 260 deletions(-)
 create mode 100644 accel/tcg/atomic_common.inc.c
 create mode 100644 accel/tcg/plugin-gen.c
 create mode 100644 accel/tcg/plugin-helpers.h
 create mode 100644 docs/devel/plugins.rst
 create mode 100644 include/exec/plugin-gen.h
 create mode 100644 include/qemu/plugin.h
 create mode 100644 include/qemu/qemu-plugin.h
 create mode 100644 include/user/syscall-trace.h
 create mode 100644 plugins/.gitignore
 create mode 100644 plugins/Makefile.objs
 create mode 100644 plugins/api.c
 create mode 100644 plugins/core.c
 create mode 100644 plugins/loader.c
 create mode 100644 plugins/plugin.h
 create mode 100644 plugins/qemu-plugins.symbols
 create mode 100644 tests/plugin/Makefile
 create mode 100644 tests/plugin/bb.c
 create mode 100644 tests/plugin/empty.c
 create mode 100644 tests/plugin/hotblocks.c
 create mode 100644 tests/plugin/hotpages.c
 create mode 100644 tests/plugin/howvec.c
 create mode 100644 tests/plugin/insn.c
 create mode 100644 tests/plugin/mem.c

-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 01/54] target/arm: handle M-profile semihosting at translate time
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 02/54] target/arm: handle A-profile T32 " Alex Bennée
                   ` (55 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Richard Henderson, aaron, cota,
	open list:ARM TCG CPUs, bobby.prani, Alex Bennée

We do this for other semihosting calls so we might as well do it for
M-profile as well.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/m_helper.c  | 18 ++++++------------
 target/arm/translate.c | 20 +++++++++++++++++++-
 2 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c
index 84609f446e6..129d52a56bf 100644
--- a/target/arm/m_helper.c
+++ b/target/arm/m_helper.c
@@ -2113,19 +2113,13 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
             break;
         }
         break;
+    case EXCP_SEMIHOST:
+        qemu_log_mask(CPU_LOG_INT,
+                      "...handling as semihosting call 0x%x\n",
+                      env->regs[0]);
+        env->regs[0] = do_arm_semihosting(env);
+        return;
     case EXCP_BKPT:
-        if (semihosting_enabled()) {
-            int nr;
-            nr = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env)) & 0xff;
-            if (nr == 0xab) {
-                env->regs[15] += 2;
-                qemu_log_mask(CPU_LOG_INT,
-                              "...handling as semihosting call 0x%x\n",
-                              env->regs[0]);
-                env->regs[0] = do_arm_semihosting(env);
-                return;
-            }
-        }
         armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false);
         break;
     case EXCP_IRQ:
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 7853462b21b..0b02c520395 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -10976,6 +10976,24 @@ illegal_op:
                        default_exception_el(s));
 }
 
+/*
+ * Thumb BKPT. On M-profile CPUs this may be a semihosting call which
+ * we can process much the same way as gen_hlt() above.
+ */
+static inline void gen_thumb_bkpt(DisasContext *s, int imm8)
+{
+    if (arm_dc_feature(s, ARM_FEATURE_M) &&
+        semihosting_enabled() &&
+#ifndef CONFIG_USER_ONLY
+        s->current_el != 0 &&
+#endif
+        (imm8 == 0xab)) {
+        gen_exception_internal_insn(s, 0, EXCP_SEMIHOST);
+        return;
+    }
+    gen_exception_bkpt_insn(s, 2, syn_aa32_bkpt(imm8, true));
+}
+
 static void disas_thumb_insn(DisasContext *s, uint32_t insn)
 {
     uint32_t val, op, rm, rn, rd, shift, cond;
@@ -11611,7 +11629,7 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn)
         {
             int imm8 = extract32(insn, 0, 8);
             ARCH(5);
-            gen_exception_bkpt_insn(s, 2, syn_aa32_bkpt(imm8, true));
+            gen_thumb_bkpt(s, imm8);
             break;
         }
 
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 02/54] target/arm: handle A-profile T32 semihosting at translate time
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 01/54] target/arm: handle M-profile semihosting at translate time Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 03/54] target/arm: handle A-profile A32 " Alex Bennée
                   ` (54 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Richard Henderson, aaron, cota,
	open list:ARM TCG CPUs, bobby.prani, Alex Bennée

As for the other semihosting calls we can resolve this at translate
time.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/translate.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/target/arm/translate.c b/target/arm/translate.c
index 0b02c520395..662d6f49115 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -10994,6 +10994,24 @@ static inline void gen_thumb_bkpt(DisasContext *s, int imm8)
     gen_exception_bkpt_insn(s, 2, syn_aa32_bkpt(imm8, true));
 }
 
+/*
+ * Thumb SWI. On A-profile CPUs this may be a semihosting call.
+ */
+static inline void gen_thumb_swi(DisasContext *s, int imm8)
+{
+    if (semihosting_enabled() &&
+#ifndef CONFIG_USER_ONLY
+        s->current_el != 0 &&
+#endif
+        (imm8 == 0xab)) {
+        gen_exception_internal_insn(s, 0, EXCP_SEMIHOST);
+        return;
+    }
+    gen_set_pc_im(s, s->pc);
+    s->svc_imm = imm8;
+    s->base.is_jmp = DISAS_SWI;
+}
+
 static void disas_thumb_insn(DisasContext *s, uint32_t insn)
 {
     uint32_t val, op, rm, rn, rd, shift, cond;
@@ -11758,10 +11776,8 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn)
             goto undef;
 
         if (cond == 0xf) {
-            /* swi */
-            gen_set_pc_im(s, s->pc);
-            s->svc_imm = extract32(insn, 0, 8);
-            s->base.is_jmp = DISAS_SWI;
+            /* swi/svc  */
+            gen_thumb_swi(s, extract32(insn, 0, 8));
             break;
         }
         /* generate a conditional jump to next instruction */
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 03/54] target/arm: handle A-profile A32 semihosting at translate time
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 01/54] target/arm: handle M-profile semihosting at translate time Alex Bennée
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 02/54] target/arm: handle A-profile T32 " Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 04/54] target/arm: remove run time semihosting checks Alex Bennée
                   ` (53 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Richard Henderson, aaron, cota,
	open list:ARM TCG CPUs, bobby.prani, Alex Bennée

As for the other semihosting calls we can resolve this at translate
time.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/translate.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/target/arm/translate.c b/target/arm/translate.c
index 662d6f49115..4cb0e6fd835 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -7698,6 +7698,22 @@ static void arm_skip_unless(DisasContext *s, uint32_t cond)
     arm_gen_test_cc(cond ^ 1, s->condlabel);
 }
 
+static inline void gen_arm_swi(DisasContext *s, int imm24)
+{
+    if (semihosting_enabled() &&
+#ifndef CONFIG_USER_ONLY
+        s->current_el != 0 &&
+#endif
+        (imm24 == 0x123456)) {
+        gen_exception_internal_insn(s, 0, EXCP_SEMIHOST);
+        return;
+    }
+
+    gen_set_pc_im(s, s->pc);
+    s->svc_imm = imm24;
+    s->base.is_jmp = DISAS_SWI;
+}
+
 static void disas_arm_insn(DisasContext *s, unsigned int insn)
 {
     unsigned int cond, val, op1, i, shift, rm, rs, rn, rd, sh;
@@ -9248,9 +9264,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
             break;
         case 0xf:
             /* swi */
-            gen_set_pc_im(s, s->pc);
-            s->svc_imm = extract32(insn, 0, 24);
-            s->base.is_jmp = DISAS_SWI;
+            gen_arm_swi(s, extract32(insn, 0, 24));
             break;
         default:
         illegal_op:
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 04/54] target/arm: remove run time semihosting checks
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (2 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 03/54] target/arm: handle A-profile A32 " Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 13:27   ` Aaron Lindsay OS via Qemu-devel
  2019-08-01 14:53   ` Richard Henderson
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 05/54] includes: remove stale [smp|max]_cpus externs Alex Bennée
                   ` (52 subsequent siblings)
  56 siblings, 2 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, aaron, cota, open list:ARM TCG CPUs, bobby.prani,
	Alex Bennée

Now we do all our checking and use a common EXCP_SEMIHOST for
semihosting operations we can make helper code a lot simpler.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v2
  - fix re-base conflicts
  - hoist EXCP_SEMIHOST check
  - comment cleanups
---
 target/arm/helper.c | 90 +++++++++------------------------------------
 1 file changed, 18 insertions(+), 72 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index b74c23a9bc0..c5b90a83d36 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -8259,86 +8259,30 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
                   new_el, env->pc, pstate_read(env));
 }
 
-static inline bool check_for_semihosting(CPUState *cs)
+/*
+ * Do semihosting call and set the appropriate return value. All the
+ * permission and validity checks have been done at translate time.
+ *
+ * We only see semihosting exceptions in TCG only as they are not
+ * trapped to the hypervisor in KVM.
+ */
+static void handle_semihosting(CPUState *cs)
 {
 #ifdef CONFIG_TCG
-    /* Check whether this exception is a semihosting call; if so
-     * then handle it and return true; otherwise return false.
-     */
     ARMCPU *cpu = ARM_CPU(cs);
     CPUARMState *env = &cpu->env;
 
     if (is_a64(env)) {
-        if (cs->exception_index == EXCP_SEMIHOST) {
-            /* This is always the 64-bit semihosting exception.
-             * The "is this usermode" and "is semihosting enabled"
-             * checks have been done at translate time.
-             */
-            qemu_log_mask(CPU_LOG_INT,
-                          "...handling as semihosting call 0x%" PRIx64 "\n",
-                          env->xregs[0]);
-            env->xregs[0] = do_arm_semihosting(env);
-            return true;
-        }
-        return false;
+        qemu_log_mask(CPU_LOG_INT,
+                      "...handling as semihosting call 0x%" PRIx64 "\n",
+                      env->xregs[0]);
+        env->xregs[0] = do_arm_semihosting(env);
     } else {
-        uint32_t imm;
-
-        /* Only intercept calls from privileged modes, to provide some
-         * semblance of security.
-         */
-        if (cs->exception_index != EXCP_SEMIHOST &&
-            (!semihosting_enabled() ||
-             ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR))) {
-            return false;
-        }
-
-        switch (cs->exception_index) {
-        case EXCP_SEMIHOST:
-            /* This is always a semihosting call; the "is this usermode"
-             * and "is semihosting enabled" checks have been done at
-             * translate time.
-             */
-            break;
-        case EXCP_SWI:
-            /* Check for semihosting interrupt.  */
-            if (env->thumb) {
-                imm = arm_lduw_code(env, env->regs[15] - 2, arm_sctlr_b(env))
-                    & 0xff;
-                if (imm == 0xab) {
-                    break;
-                }
-            } else {
-                imm = arm_ldl_code(env, env->regs[15] - 4, arm_sctlr_b(env))
-                    & 0xffffff;
-                if (imm == 0x123456) {
-                    break;
-                }
-            }
-            return false;
-        case EXCP_BKPT:
-            /* See if this is a semihosting syscall.  */
-            if (env->thumb) {
-                imm = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env))
-                    & 0xff;
-                if (imm == 0xab) {
-                    env->regs[15] += 2;
-                    break;
-                }
-            }
-            return false;
-        default:
-            return false;
-        }
-
         qemu_log_mask(CPU_LOG_INT,
                       "...handling as semihosting call 0x%x\n",
                       env->regs[0]);
         env->regs[0] = do_arm_semihosting(env);
-        return true;
     }
-#else
-    return false;
 #endif
 }
 
@@ -8371,11 +8315,13 @@ void arm_cpu_do_interrupt(CPUState *cs)
         return;
     }
 
-    /* Semihosting semantics depend on the register width of the
-     * code that caused the exception, not the target exception level,
-     * so must be handled here.
+    /*
+     * Semihosting semantics depend on the register width of the code
+     * that caused the exception, not the target exception level, so
+     * must be handled here.
      */
-    if (check_for_semihosting(cs)) {
+    if (cs->exception_index == EXCP_SEMIHOST) {
+        handle_semihosting(cs);
         return;
     }
 
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 05/54] includes: remove stale [smp|max]_cpus externs
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (3 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 04/54] target/arm: remove run time semihosting checks Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 14:54   ` Richard Henderson
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 06/54] trace: expand mem_info:size_shift to 4 bits Alex Bennée
                   ` (51 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: bobby.prani, cota, Alex Bennée, aaron, Like Xu

Commit a5e0b3311 removed these in favour of querying machine
properties. Remove the extern declarations as well.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Cc: Like Xu <like.xu@linux.intel.com>
Message-Id: <20190711130546.18578-1-alex.bennee@linaro.org>
---
 include/sysemu/sysemu.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 984c439ac96..e70edf7c1cf 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -103,8 +103,6 @@ extern const char *keyboard_layout;
 extern int win2k_install_hack;
 extern int alt_grab;
 extern int ctrl_grab;
-extern int smp_cpus;
-extern unsigned int max_cpus;
 extern int cursor_hide;
 extern int graphic_rotate;
 extern int no_quit;
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 06/54] trace: expand mem_info:size_shift to 4 bits
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (4 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 05/54] includes: remove stale [smp|max]_cpus externs Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 15:01   ` Richard Henderson
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 07/54] trace: add mmu_index to mem_info Alex Bennée
                   ` (50 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: bobby.prani, cota, Alex Bennée, aaron, Stefan Hajnoczi

From: "Emilio G. Cota" <cota@braap.org>

This will allow us to trace 32k-long memory accesses (although our
maximum is something like 256 bytes at the moment).

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Emilio G. Cota <cota@braap.org>
[AJB: expanded to 3->4 bits]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 trace-events | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/trace-events b/trace-events
index aeea3c2bdbf..63bb192ade6 100644
--- a/trace-events
+++ b/trace-events
@@ -149,7 +149,7 @@ vcpu guest_cpu_reset(void)
 # Access information can be parsed as:
 #
 # struct mem_info {
-#     uint8_t size_shift : 2; /* interpreted as "1 << size_shift" bytes */
+#     uint8_t size_shift : 4; /* interpreted as "1 << size_shift" bytes */
 #     bool    sign_extend: 1; /* sign-extended */
 #     uint8_t endianness : 1; /* 0: little, 1: big */
 #     bool    store      : 1; /* wheter it's a store operation */
-- 
2.20.1



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

* [Qemu-devel] [PATCH  v4 07/54] trace: add mmu_index to mem_info
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (5 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 06/54] trace: expand mem_info:size_shift to 4 bits Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 15:17   ` Richard Henderson
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 08/54] tcg/README: fix typo s/afterwise/afterwards/ Alex Bennée
                   ` (49 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Riku Voipio, aaron, cota, Stefan Hajnoczi, Paolo Bonzini,
	bobby.prani, Alex Bennée, Richard Henderson

We are going to re-use mem_info later for plugins and will need to
track the mmu_idx for softmmu code.

[TODO: convert everything to use TCGMemOpIdx?]

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 accel/tcg/atomic_template.h               |  6 ++---
 accel/tcg/cputlb.c                        |  2 ++
 accel/tcg/user-exec.c                     |  1 +
 include/exec/cpu_ldst_template.h          | 15 +++++------
 include/exec/cpu_ldst_useronly_template.h |  6 ++---
 scripts/tracetool/transform.py            |  1 +
 tcg/tcg-op.c                              |  8 +++---
 trace-events                              |  6 +++--
 trace/mem-internal.h                      | 31 ++++++++++++++++-------
 trace/mem.h                               |  7 ++---
 10 files changed, 50 insertions(+), 33 deletions(-)

diff --git a/accel/tcg/atomic_template.h b/accel/tcg/atomic_template.h
index 5aaf1862539..313a4c7ed97 100644
--- a/accel/tcg/atomic_template.h
+++ b/accel/tcg/atomic_template.h
@@ -60,7 +60,7 @@
 #endif
 
 #define ATOMIC_TRACE_RMW do {                                           \
-        uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false); \
+        uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false, ATOMIC_MMU_IDX); \
                                                                         \
         trace_guest_mem_before_exec(env_cpu(env), addr, info);      \
         trace_guest_mem_before_exec(env_cpu(env), addr,             \
@@ -68,13 +68,13 @@
     } while (0)
 
 #define ATOMIC_TRACE_LD do {                                            \
-        uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false); \
+        uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false, ATOMIC_MMU_IDX); \
                                                                         \
         trace_guest_mem_before_exec(env_cpu(env), addr, info);      \
     } while (0)
 
 # define ATOMIC_TRACE_ST do {                                           \
-        uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, true); \
+        uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, true, ATOMIC_MMU_IDX); \
                                                                         \
         trace_guest_mem_before_exec(env_cpu(env), addr, info);      \
     } while (0)
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index bb9897b25a3..bffdb251580 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1692,6 +1692,7 @@ void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
             memory_notdirty_write_complete(&ndi);       \
         }                                               \
     } while (0)
+#define ATOMIC_MMU_IDX oi
 
 #define DATA_SIZE 1
 #include "atomic_template.h"
@@ -1734,6 +1735,7 @@ void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
 #define DATA_SIZE 8
 #include "atomic_template.h"
 #endif
+#undef ATOMIC_MMU_IDX
 
 /* Code access functions.  */
 
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index 897d1571c4a..bff1934cf1b 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -719,6 +719,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
 #define ATOMIC_MMU_DECLS do {} while (0)
 #define ATOMIC_MMU_LOOKUP  atomic_mmu_lookup(env, addr, DATA_SIZE, GETPC())
 #define ATOMIC_MMU_CLEANUP do { clear_helper_retaddr(); } while (0)
+#define ATOMIC_MMU_IDX 0
 
 #define ATOMIC_NAME(X)   HELPER(glue(glue(atomic_ ## X, SUFFIX), END))
 #define EXTRA_ARGS
diff --git a/include/exec/cpu_ldst_template.h b/include/exec/cpu_ldst_template.h
index af7e0b49f2d..5750a26b9ec 100644
--- a/include/exec/cpu_ldst_template.h
+++ b/include/exec/cpu_ldst_template.h
@@ -84,17 +84,16 @@ glue(glue(glue(cpu_ld, USUFFIX), MEMSUFFIX), _ra)(CPUArchState *env,
     CPUTLBEntry *entry;
     RES_TYPE res;
     target_ulong addr;
-    int mmu_idx;
+    int mmu_idx = CPU_MMU_INDEX;
     TCGMemOpIdx oi;
 
 #if !defined(SOFTMMU_CODE_ACCESS)
     trace_guest_mem_before_exec(
         env_cpu(env), ptr,
-        trace_mem_build_info(SHIFT, false, MO_TE, false));
+        trace_mem_build_info(SHIFT, false, MO_TE, false, mmu_idx));
 #endif
 
     addr = ptr;
-    mmu_idx = CPU_MMU_INDEX;
     entry = tlb_entry(env, mmu_idx, addr);
     if (unlikely(entry->ADDR_READ !=
                  (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
@@ -123,17 +122,16 @@ glue(glue(glue(cpu_lds, SUFFIX), MEMSUFFIX), _ra)(CPUArchState *env,
     CPUTLBEntry *entry;
     int res;
     target_ulong addr;
-    int mmu_idx;
+    int mmu_idx = CPU_MMU_INDEX;
     TCGMemOpIdx oi;
 
 #if !defined(SOFTMMU_CODE_ACCESS)
     trace_guest_mem_before_exec(
         env_cpu(env), ptr,
-        trace_mem_build_info(SHIFT, true, MO_TE, false));
+        trace_mem_build_info(SHIFT, true, MO_TE, false, mmu_idx));
 #endif
 
     addr = ptr;
-    mmu_idx = CPU_MMU_INDEX;
     entry = tlb_entry(env, mmu_idx, addr);
     if (unlikely(entry->ADDR_READ !=
                  (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
@@ -165,17 +163,16 @@ glue(glue(glue(cpu_st, SUFFIX), MEMSUFFIX), _ra)(CPUArchState *env,
 {
     CPUTLBEntry *entry;
     target_ulong addr;
-    int mmu_idx;
+    int mmu_idx = CPU_MMU_INDEX;
     TCGMemOpIdx oi;
 
 #if !defined(SOFTMMU_CODE_ACCESS)
     trace_guest_mem_before_exec(
         env_cpu(env), ptr,
-        trace_mem_build_info(SHIFT, false, MO_TE, true));
+        trace_mem_build_info(SHIFT, false, MO_TE, true, mmu_idx));
 #endif
 
     addr = ptr;
-    mmu_idx = CPU_MMU_INDEX;
     entry = tlb_entry(env, mmu_idx, addr);
     if (unlikely(tlb_addr_write(entry) !=
                  (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
diff --git a/include/exec/cpu_ldst_useronly_template.h b/include/exec/cpu_ldst_useronly_template.h
index 2378f2958c9..8f7f117ad44 100644
--- a/include/exec/cpu_ldst_useronly_template.h
+++ b/include/exec/cpu_ldst_useronly_template.h
@@ -73,7 +73,7 @@ glue(glue(cpu_ld, USUFFIX), MEMSUFFIX)(CPUArchState *env, abi_ptr ptr)
 #else
     trace_guest_mem_before_exec(
         env_cpu(env), ptr,
-        trace_mem_build_info(SHIFT, false, MO_TE, false));
+        trace_mem_build_info(SHIFT, false, MO_TE, false, 0));
     return glue(glue(ld, USUFFIX), _p)(g2h(ptr));
 #endif
 }
@@ -105,7 +105,7 @@ glue(glue(cpu_lds, SUFFIX), MEMSUFFIX)(CPUArchState *env, abi_ptr ptr)
 #else
     trace_guest_mem_before_exec(
         env_cpu(env), ptr,
-        trace_mem_build_info(SHIFT, true, MO_TE, false));
+        trace_mem_build_info(SHIFT, true, MO_TE, false, 0));
     return glue(glue(lds, SUFFIX), _p)(g2h(ptr));
 #endif
 }
@@ -132,7 +132,7 @@ glue(glue(cpu_st, SUFFIX), MEMSUFFIX)(CPUArchState *env, abi_ptr ptr,
 {
     trace_guest_mem_before_exec(
         env_cpu(env), ptr,
-        trace_mem_build_info(SHIFT, false, MO_TE, true));
+        trace_mem_build_info(SHIFT, false, MO_TE, true, 0));
     glue(glue(st, SUFFIX), _p)(g2h(ptr), v);
 }
 
diff --git a/scripts/tracetool/transform.py b/scripts/tracetool/transform.py
index e18b05315ef..2ca9286046d 100644
--- a/scripts/tracetool/transform.py
+++ b/scripts/tracetool/transform.py
@@ -83,6 +83,7 @@ TCG_2_HOST = {
 
 HOST_2_TCG_COMPAT = {
     "uint8_t": "uint32_t",
+    "uint16_t": "uint32_t",
     }
 
 
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
index 587d0922384..38e62dcba97 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -2795,7 +2795,7 @@ void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
     tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
     memop = tcg_canonicalize_memop(memop, 0, 0);
     trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
-                               addr, trace_mem_get_info(memop, 0));
+                               addr, trace_mem_get_info(memop, idx, 0));
 
     orig_memop = memop;
     if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) {
@@ -2832,7 +2832,7 @@ void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
     tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
     memop = tcg_canonicalize_memop(memop, 0, 1);
     trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
-                               addr, trace_mem_get_info(memop, 1));
+                               addr, trace_mem_get_info(memop, idx, 1));
 
     if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) {
         swap = tcg_temp_new_i32();
@@ -2875,7 +2875,7 @@ void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
     tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
     memop = tcg_canonicalize_memop(memop, 1, 0);
     trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
-                               addr, trace_mem_get_info(memop, 0));
+                               addr, trace_mem_get_info(memop, idx, 0));
 
     orig_memop = memop;
     if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) {
@@ -2923,7 +2923,7 @@ void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
     tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
     memop = tcg_canonicalize_memop(memop, 1, 1);
     trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
-                               addr, trace_mem_get_info(memop, 1));
+                               addr, trace_mem_get_info(memop, idx, 1));
 
     if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) {
         swap = tcg_temp_new_i64();
diff --git a/trace-events b/trace-events
index 63bb192ade6..9f15a0c1fe6 100644
--- a/trace-events
+++ b/trace-events
@@ -152,12 +152,14 @@ vcpu guest_cpu_reset(void)
 #     uint8_t size_shift : 4; /* interpreted as "1 << size_shift" bytes */
 #     bool    sign_extend: 1; /* sign-extended */
 #     uint8_t endianness : 1; /* 0: little, 1: big */
-#     bool    store      : 1; /* wheter it's a store operation */
+#     bool    store      : 1; /* whether it is a store operation */
+#             pad        : 1;
+#     uint8_t mmuidx     : 4; /* mmuidx (softmmu only)  */
 # };
 #
 # Mode: user, softmmu
 # Targets: TCG(all)
-vcpu tcg guest_mem_before(TCGv vaddr, uint8_t info) "info=%d", "vaddr=0x%016"PRIx64" info=%d"
+vcpu tcg guest_mem_before(TCGv vaddr, uint16_t info) "info=%d", "vaddr=0x%016"PRIx64" info=%d"
 
 # linux-user/syscall.c
 # bsd-user/syscall.c
diff --git a/trace/mem-internal.h b/trace/mem-internal.h
index f6efaf6d6b7..35da998c16b 100644
--- a/trace/mem-internal.h
+++ b/trace/mem-internal.h
@@ -14,11 +14,13 @@
 #define TRACE_MEM_SE (1ULL << 3)    /* sign extended (y/n) */
 #define TRACE_MEM_BE (1ULL << 4)    /* big endian (y/n) */
 #define TRACE_MEM_ST (1ULL << 5)    /* store (y/n) */
+#define TRACE_MEM_MMU_SHIFT 8       /* mmu idx */
 
-static inline uint8_t trace_mem_build_info(
-    int size_shift, bool sign_extend, TCGMemOp endianness, bool store)
+static inline uint16_t trace_mem_build_info(
+    int size_shift, bool sign_extend, TCGMemOp endianness,
+    bool store, unsigned int mmu_idx)
 {
-    uint8_t res;
+    uint16_t res;
 
     res = size_shift & TRACE_MEM_SZ_SHIFT_MASK;
     if (sign_extend) {
@@ -30,25 +32,36 @@ static inline uint8_t trace_mem_build_info(
     if (store) {
         res |= TRACE_MEM_ST;
     }
+#ifdef CONFIG_SOFTMMU
+    res |= mmu_idx << TRACE_MEM_MMU_SHIFT;
+#endif
     return res;
 }
 
-static inline uint8_t trace_mem_get_info(TCGMemOp op, bool store)
+static inline uint16_t trace_mem_get_info(TCGMemOp op,
+                                          unsigned int mmu_idx,
+                                          bool store)
 {
     return trace_mem_build_info(op & MO_SIZE, !!(op & MO_SIGN),
-                                op & MO_BSWAP, store);
+                                op & MO_BSWAP, store,
+                                mmu_idx);
 }
 
+/* Used by the atomic helpers */
 static inline
-uint8_t trace_mem_build_info_no_se_be(int size_shift, bool store)
+uint16_t trace_mem_build_info_no_se_be(int size_shift, bool store,
+                                       TCGMemOpIdx oi)
 {
-    return trace_mem_build_info(size_shift, false, MO_BE, store);
+    return trace_mem_build_info(size_shift, false, MO_BE, store,
+                                get_mmuidx(oi));
 }
 
 static inline
-uint8_t trace_mem_build_info_no_se_le(int size_shift, bool store)
+uint16_t trace_mem_build_info_no_se_le(int size_shift, bool store,
+                                       TCGMemOpIdx oi)
 {
-    return trace_mem_build_info(size_shift, false, MO_LE, store);
+    return trace_mem_build_info(size_shift, false, MO_LE, store,
+                                get_mmuidx(oi));
 }
 
 #endif /* TRACE__MEM_INTERNAL_H */
diff --git a/trace/mem.h b/trace/mem.h
index 2b58196e536..0f9cd4862ac 100644
--- a/trace/mem.h
+++ b/trace/mem.h
@@ -18,15 +18,16 @@
  *
  * Return a value for the 'info' argument in guest memory access traces.
  */
-static uint8_t trace_mem_get_info(TCGMemOp op, bool store);
+static uint16_t trace_mem_get_info(TCGMemOp op, unsigned int mmu_idx, bool store);
 
 /**
  * trace_mem_build_info:
  *
  * Return a value for the 'info' argument in guest memory access traces.
  */
-static uint8_t trace_mem_build_info(int size_shift, bool sign_extend,
-                                    TCGMemOp endianness, bool store);
+static uint16_t trace_mem_build_info(int size_shift, bool sign_extend,
+                                     TCGMemOp endianness, bool store,
+                                     unsigned int mmuidx);
 
 
 #include "trace/mem-internal.h"
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 08/54] tcg/README: fix typo s/afterwise/afterwards/
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (6 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 07/54] trace: add mmu_index to mem_info Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 09/54] cpu: introduce cpu_in_exclusive_context() Alex Bennée
                   ` (48 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Richard Henderson, aaron, cota, bobby.prani, Alex Bennée,
	Richard Henderson

From: "Emilio G. Cota" <cota@braap.org>

Afterwise is "wise after the fact", as in "hindsight".
Here we meant "afterwards" (as in "subsequently"). Fix it.

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tcg/README | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tcg/README b/tcg/README
index 21fcdf737ff..ef9be5ba90e 100644
--- a/tcg/README
+++ b/tcg/README
@@ -101,7 +101,7 @@ This can be overridden using the following function modifiers:
   canonical locations before calling the helper.
 - TCG_CALL_NO_WRITE_GLOBALS means that the helper does not modify any globals.
   They will only be saved to their canonical location before calling helpers,
-  but they won't be reloaded afterwise.
+  but they won't be reloaded afterwards.
 - TCG_CALL_NO_SIDE_EFFECTS means that the call to the function is removed if
   the return value is not used.
 
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 09/54] cpu: introduce cpu_in_exclusive_context()
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (7 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 08/54] tcg/README: fix typo s/afterwise/afterwards/ Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 15:23   ` Richard Henderson
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 10/54] translate-all: use cpu_in_exclusive_work_context() in tb_flush Alex Bennée
                   ` (47 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, aaron, cota, Paolo Bonzini, bobby.prani,
	Alex Bennée, Richard Henderson

From: "Emilio G. Cota" <cota@braap.org>

Suggested-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Emilio G. Cota <cota@braap.org>
[AJB: moved inside start/end_exclusive fns + cleanup]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v4
  - -> cpu_in_exclusive_context
  - moved inside start/end exclusive
  - fixed up cpu_exec_step_atomic
---
 accel/tcg/cpu-exec.c |  5 +----
 cpus-common.c        |  4 ++++
 include/qom/cpu.h    | 13 +++++++++++++
 3 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 6c85c3ee1e9..ab9dfd4f908 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -239,8 +239,6 @@ void cpu_exec_step_atomic(CPUState *cpu)
     uint32_t flags;
     uint32_t cflags = 1;
     uint32_t cf_mask = cflags & CF_HASH_MASK;
-    /* volatile because we modify it between setjmp and longjmp */
-    volatile bool in_exclusive_region = false;
 
     if (sigsetjmp(cpu->jmp_env, 0) == 0) {
         tb = tb_lookup__cpu_state(cpu, &pc, &cs_base, &flags, cf_mask);
@@ -254,7 +252,6 @@ void cpu_exec_step_atomic(CPUState *cpu)
 
         /* Since we got here, we know that parallel_cpus must be true.  */
         parallel_cpus = false;
-        in_exclusive_region = true;
         cc->cpu_exec_enter(cpu);
         /* execute the generated code */
         trace_exec_tb(tb, pc);
@@ -274,7 +271,7 @@ void cpu_exec_step_atomic(CPUState *cpu)
         assert_no_pages_locked();
     }
 
-    if (in_exclusive_region) {
+    if (cpu_in_exclusive_context(cpu)) {
         /* We might longjump out of either the codegen or the
          * execution, so must make sure we only end the exclusive
          * region if we started it.
diff --git a/cpus-common.c b/cpus-common.c
index 3ca58c64e80..e87400834be 100644
--- a/cpus-common.c
+++ b/cpus-common.c
@@ -208,11 +208,15 @@ void start_exclusive(void)
      * section until end_exclusive resets pending_cpus to 0.
      */
     qemu_mutex_unlock(&qemu_cpu_list_lock);
+
+    current_cpu->in_exclusive_context = true;
 }
 
 /* Finish an exclusive operation.  */
 void end_exclusive(void)
 {
+    current_cpu->in_exclusive_context = false;
+
     qemu_mutex_lock(&qemu_cpu_list_lock);
     atomic_set(&pending_cpus, 0);
     qemu_cond_broadcast(&exclusive_resume);
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 5ee0046b629..65a0926c49a 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -373,6 +373,7 @@ struct CPUState {
     bool unplug;
     bool crash_occurred;
     bool exit_request;
+    bool in_exclusive_context;
     uint32_t cflags_next_tb;
     /* updates protected by BQL */
     uint32_t interrupt_request;
@@ -785,6 +786,18 @@ void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data)
  */
 void async_safe_run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data);
 
+/**
+ * cpu_in_exclusive_context()
+ * @cpu: The vCPU to check
+ *
+ * Returns true if @cpu is an exclusive context, for example running
+ * something which has previously been queued via async_safe_run_on_cpu().
+ */
+static inline bool cpu_in_exclusive_context(const CPUState *cpu)
+{
+    return cpu->in_exclusive_context;
+}
+
 /**
  * qemu_get_cpu:
  * @index: The CPUState@cpu_index value of the CPU to obtain.
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 10/54] translate-all: use cpu_in_exclusive_work_context() in tb_flush
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (8 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 09/54] cpu: introduce cpu_in_exclusive_context() Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 15:25   ` Richard Henderson
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 11/54] docs/devel: add plugins.rst design document Alex Bennée
                   ` (46 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: aaron, cota, Paolo Bonzini, bobby.prani, Alex Bennée,
	Richard Henderson

From: "Emilio G. Cota" <cota@braap.org>

tb_flush will be called by the plugin module from a safe
work environment. Prepare for that.

Suggested-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Emilio G. Cota <cota@braap.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 accel/tcg/translate-all.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 5d1e08b1699..9c5c60ed964 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -1268,8 +1268,13 @@ void tb_flush(CPUState *cpu)
 {
     if (tcg_enabled()) {
         unsigned tb_flush_count = atomic_mb_read(&tb_ctx.tb_flush_count);
-        async_safe_run_on_cpu(cpu, do_tb_flush,
-                              RUN_ON_CPU_HOST_INT(tb_flush_count));
+
+        if (cpu_in_exclusive_context(cpu)) {
+            do_tb_flush(cpu, RUN_ON_CPU_HOST_INT(tb_flush_count));
+        } else {
+            async_safe_run_on_cpu(cpu, do_tb_flush,
+                                  RUN_ON_CPU_HOST_INT(tb_flush_count));
+        }
     }
 }
 
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 11/54] docs/devel: add plugins.rst design document
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (9 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 10/54] translate-all: use cpu_in_exclusive_work_context() in tb_flush Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 15:31   ` Richard Henderson
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 12/54] configure: add --enable-plugins (MOVE TO END) Alex Bennée
                   ` (45 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: bobby.prani, cota, Alex Bennée, aaron

This is mostly extracted from Emilio's more verbose commit comments
with some additional verbiage from me.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v4
  - some rewording and tweaks
  - made non-atomicity of inline ops more explicit
  - expanded description of plugin unload
---
 docs/devel/index.rst   |   1 +
 docs/devel/plugins.rst | 107 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 108 insertions(+)
 create mode 100644 docs/devel/plugins.rst

diff --git a/docs/devel/index.rst b/docs/devel/index.rst
index 1ec61fcfed9..2ff058bae38 100644
--- a/docs/devel/index.rst
+++ b/docs/devel/index.rst
@@ -22,3 +22,4 @@ Contents:
    decodetree
    secure-coding-practices
    tcg
+   plugins
diff --git a/docs/devel/plugins.rst b/docs/devel/plugins.rst
new file mode 100644
index 00000000000..0a31227b613
--- /dev/null
+++ b/docs/devel/plugins.rst
@@ -0,0 +1,107 @@
+..
+   Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
+   Copyright (c) 2019, Linaro Limited
+   Written by Emilio Cota and Alex Bennée
+
+================
+QEMU TCG Plugins
+================
+
+QEMU TCG plugins provide a way for users to run experiments taking
+advantage of the total system control emulation can have over a guest.
+It provides a mechanism for plugins to subscribe to events during
+translation and execution and optionally callback into the plugin
+during these events.
+
+API Stability
+=============
+
+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.
+
+Exposure of QEMU internals
+--------------------------
+
+The plugin architecture actively avoids leaking implementation details
+about how QEMU's translation works to the plugins. While there are
+conceptions such as translation time and translation blocks the
+details are opaque to plugins. The plugin is able to query select
+details of instructions and system configuration only through the
+exported *qemu_plugin* functions. The types used to describe
+instructions and events are opaque to the plugins themselves.
+
+Usage
+=====
+
+The QEMU binary needs to be compiled for plugin support:
+
+::
+    configure --enable-plugins
+
+Once built a program can be run with multiple plugins loaded each with
+their own arguments:
+
+::
+    $QEMU $OTHER_QEMU_ARGS \
+      -plugin tests/plugin/libhowvec.so,arg=inline,arg=hint \
+      -plugin tests/plugin/libhotblocks.so
+
+Arguments are plugin specific and can be used to modify their
+behaviour. In this case the howvec plugin is being asked to use inline
+ops to count and break down the hint instructions by type.
+
+Plugin Life cycle
+=================
+
+First the plugin is loaded and the public qemu_plugin_install function
+is called. The plugin will then register callbacks for various plugin
+events. Generally plugins will register a handler for the *atexit*
+if they want to dump a summary of collected information once the
+program/system has finished running.
+
+When a registered event occurs the plugin callback is invoked. The
+callbacks may provide additional information. In the case of a
+translation event the plugin has an option to enumerate the
+instructions in a block of instructions and optionally register
+callbacks to some or all instructions when they are executed.
+
+There is also a facility to add an inline event where code to
+increment a counter can be directly inlined with the translation.
+Currently only a simple increment is supported. This is not atomic so
+can miss counts. If you want absolute precision you should use a
+callback which can then ensure atomicity itself.
+
+Finally when QEMU exits all the registered *atexit* callbacks are
+invoked.
+
+Internals
+=========
+
+Locking
+-------
+
+We have to ensure we cannot deadlock, particularly under MTTCG. For
+this we acquire a lock when called from plugin code. We also keep the
+list of callbacks under RCU so that we do not have to hold the lock
+when calling the callbacks. This is also for performance, since some
+callbacks (e.g. memory access callbacks) might be called very
+frequently.
+
+  * A consequence of this is that we keep our own list of CPUs, so that
+    we do not have to worry about locking order wrt cpu_list_lock.
+  * Use a recursive lock, since we can get registration calls from
+    callbacks.
+
+As a result registering/unregistering callbacks is "slow", since it
+takes a lock. But this is very infrequent; we want performance when
+calling (or not calling) callbacks, not when registering them. Using
+RCU is great for this.
+
+We support the uninstallation of a plugin at any time (e.g. from
+plugin callbacks). This allows plugins to remove themselves if they no
+longer want to instrument the code. This operation is asynchronous
+which means callbacks may still occur after the uninstall operation is
+requested. The plugin isn't completely uninstalled until the safe work
+has executed while all vCPUs are quiescent.
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 12/54] configure: add --enable-plugins (MOVE TO END)
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (10 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 11/54] docs/devel: add plugins.rst design document Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 15:33   ` Richard Henderson
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 13/54] plugin: add user-facing API Alex Bennée
                   ` (44 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: bobby.prani, cota, Alex Bennée, aaron

This adds the basic boilerplate feature enable option for the build.
We shall expand it later.

XXX: currently this patch is included at the start of development to
aid with incremental building. It should be moved to the end once the
plugins are feature complete.

[AJB: split from larger patch]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 configure | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/configure b/configure
index 714e7fb6a1f..dbc78f21b0c 100755
--- a/configure
+++ b/configure
@@ -499,6 +499,7 @@ docker="no"
 debug_mutex="no"
 libpmem=""
 default_devices="yes"
+plugins="no"
 
 # cross compilers defaults, can be overridden with --cross-cc-ARCH
 cross_cc_aarch64="aarch64-linux-gnu-gcc"
@@ -1543,6 +1544,10 @@ for opt do
   ;;
   --disable-libpmem) libpmem=no
   ;;
+  --enable-plugins) plugins="yes"
+  ;;
+  --disable-plugins) plugins="no"
+  ;;
   *)
       echo "ERROR: unknown option $opt"
       echo "Try '$0 --help' for more information"
@@ -1740,6 +1745,8 @@ Advanced options (experts only):
   --enable-profiler        profiler support
   --enable-debug-stack-usage
                            track the maximum stack usage of stacks created by qemu_alloc_stack
+  --enable-plugins
+                           enable plugins via shared library loading
 
 Optional features, enabled with --enable-FEATURE and
 disabled with --disable-FEATURE, default is enabled if available:
@@ -6481,6 +6488,7 @@ echo "docker            $docker"
 echo "libpmem support   $libpmem"
 echo "libudev           $libudev"
 echo "default devices   $default_devices"
+echo "plugin support    $plugins"
 
 if test "$supported_cpu" = "no"; then
     echo
@@ -7307,6 +7315,11 @@ if test "$sheepdog" = "yes" ; then
   echo "CONFIG_SHEEPDOG=y" >> $config_host_mak
 fi
 
+if test "$plugins" = "yes" ; then
+    echo "CONFIG_PLUGIN=y" >> $config_host_mak
+    LIBS="-ldl $LIBS"
+fi
+
 if test "$tcg_interpreter" = "yes"; then
   QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
 elif test "$ARCH" = "sparc64" ; then
-- 
2.20.1



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

* [Qemu-devel] [PATCH  v4 13/54] plugin: add user-facing API
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (11 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 12/54] configure: add --enable-plugins (MOVE TO END) Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 15:39   ` Richard Henderson
  2019-08-02 18:25   ` Aaron Lindsay OS via Qemu-devel
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 14/54] plugin: add core code Alex Bennée
                   ` (43 subsequent siblings)
  56 siblings, 2 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: bobby.prani, cota, Alex Bennée, aaron

From: "Emilio G. Cota" <cota@braap.org>

Add the API first to ease review.

Signed-off-by: Emilio G. Cota <cota@braap.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v3
  - merge in changes to plugin install/reset/uninstall
  - split api file
v4
  - s/is/it/
  - more docstrings
  - remove qemu_plugin_register_vcpu_mem_haddr_cb and related bits
  - add qemu_plugin_get_hwaddr and related bits
  - drop vcpu_index from tb_trans_cb_t
---
 include/qemu/qemu-plugin.h | 351 +++++++++++++++++++++++++++++++++++++
 1 file changed, 351 insertions(+)
 create mode 100644 include/qemu/qemu-plugin.h

diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
new file mode 100644
index 00000000000..d9c1ca3b4cf
--- /dev/null
+++ b/include/qemu/qemu-plugin.h
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
+ * Copyright (C) 2019, Linaro
+ *
+ * License: GNU GPL, version 2 or later.
+ *   See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef QEMU_PLUGIN_API_H
+#define QEMU_PLUGIN_API_H
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+/*
+ * For best performance, build the plugin with -fvisibility=hidden so that
+ * QEMU_PLUGIN_LOCAL is implicit. Then, just mark qemu_plugin_install with
+ * QEMU_PLUGIN_EXPORT. For more info, see
+ *   https://gcc.gnu.org/wiki/Visibility
+ */
+#if defined _WIN32 || defined __CYGWIN__
+  #ifdef BUILDING_DLL
+    #define QEMU_PLUGIN_EXPORT __declspec(dllexport)
+  #else
+    #define QEMU_PLUGIN_EXPORT __declspec(dllimport)
+  #endif
+  #define QEMU_PLUGIN_LOCAL
+#else
+  #if __GNUC__ >= 4
+    #define QEMU_PLUGIN_EXPORT __attribute__((visibility("default")))
+    #define QEMU_PLUGIN_LOCAL  __attribute__((visibility("hidden")))
+  #else
+    #define QEMU_PLUGIN_EXPORT
+    #define QEMU_PLUGIN_LOCAL
+  #endif
+#endif
+
+typedef uint64_t qemu_plugin_id_t;
+
+/**
+ * qemu_plugin_install() - Install a plugin
+ * @id: this plugin's opaque ID
+ * @argc: number of arguments
+ * @argv: array of arguments (@argc elements)
+ *
+ * All plugins must export this symbol.
+ *
+ * Note: Calling qemu_plugin_uninstall() from this function is a bug. To raise
+ * an error during install, return !0.
+ *
+ * Note: @argv remains valid throughout the lifetime of the loaded plugin.
+ */
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, int argc,
+                                           char **argv);
+
+/*
+ * Prototypes for the various callback styles we will be registering
+ * in the following functions.
+ */
+typedef void (*qemu_plugin_simple_cb_t)(qemu_plugin_id_t id);
+
+typedef void (*qemu_plugin_udata_cb_t)(qemu_plugin_id_t id, void *userdata);
+
+typedef void (*qemu_plugin_vcpu_simple_cb_t)(qemu_plugin_id_t id,
+                                             unsigned int vcpu_index);
+
+typedef void (*qemu_plugin_vcpu_udata_cb_t)(unsigned int vcpu_index,
+                                            void *userdata);
+
+/**
+ * qemu_plugin_uninstall() - Uninstall a plugin
+ * @id: this plugin's opaque ID
+ * @cb: callback to be called once the plugin has been removed
+ *
+ * Do NOT assume that the plugin has been uninstalled once this function
+ * returns. Plugins are uninstalled asynchronously, and therefore the given
+ * plugin receives callbacks until @cb is called.
+ *
+ * Note: Calling this function from qemu_plugin_install() is a bug.
+ */
+void qemu_plugin_uninstall(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb);
+
+/**
+ * qemu_plugin_reset() - Reset a plugin
+ * @id: this plugin's opaque ID
+ * @cb: callback to be called once the plugin has been reset
+ *
+ * Unregisters all callbacks for the plugin given by @id.
+ *
+ * Do NOT assume that the plugin has been reset once this function returns.
+ * Plugins are reset asynchronously, and therefore the given plugin receives
+ * callbacks until @cb is called.
+ */
+void qemu_plugin_reset(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb);
+
+/**
+ * qemu_plugin_register_vcpu_init_cb() - register a vCPU initialization callback
+ * @id: plugin ID
+ * @cb: callback function
+ *
+ * The @cb function is called every time a vCPU is initialized.
+ *
+ * See also: qemu_plugin_register_vcpu_exit_cb()
+ */
+void qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id,
+                                       qemu_plugin_vcpu_simple_cb_t cb);
+
+/**
+ * qemu_plugin_register_vcpu_exit_cb() - register a vCPU exit callback
+ * @id: plugin ID
+ * @cb: callback function
+ *
+ * The @cb function is called every time a vCPU exits.
+ *
+ * See also: qemu_plugin_register_vcpu_init_cb()
+ */
+void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,
+                                       qemu_plugin_vcpu_simple_cb_t cb);
+
+/**
+ * qemu_plugin_register_vcpu_idle_cb() - register a vCPU idle callback
+ * @id: plugin ID
+ * @cb: callback function
+ *
+ * The @cb function is called every time a vCPU idles.
+ */
+void qemu_plugin_register_vcpu_idle_cb(qemu_plugin_id_t id,
+                                       qemu_plugin_vcpu_simple_cb_t cb);
+
+/**
+ * qemu_plugin_register_vcpu_resume_cb() - register a vCPU resume callback
+ * @id: plugin ID
+ * @cb: callback function
+ *
+ * The @cb function is called every time a vCPU resumes execution.
+ */
+void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
+                                         qemu_plugin_vcpu_simple_cb_t cb);
+
+/*
+ * Opaque types that the plugin is given during the translation and
+ * instrumentation phase.
+ */
+struct qemu_plugin_tb;
+struct qemu_plugin_insn;
+
+enum qemu_plugin_cb_flags {
+    QEMU_PLUGIN_CB_NO_REGS, /* callback does not access the CPU's regs */
+    QEMU_PLUGIN_CB_R_REGS,  /* callback reads the CPU's regs */
+    QEMU_PLUGIN_CB_RW_REGS, /* callback reads and writes the CPU's regs */
+};
+
+enum qemu_plugin_mem_rw {
+    QEMU_PLUGIN_MEM_R = 1,
+    QEMU_PLUGIN_MEM_W,
+    QEMU_PLUGIN_MEM_RW,
+};
+
+/**
+ * qemu_plugin_register_vcpu_tb_trans_cb() - register a translate cb
+ * @id: plugin ID
+ * @cb: callback function
+ *
+ * The @cb function is called every time a translation occurs. The @cb
+ * function is passed an opaque qemu_plugin_type which it can query
+ * for additional information including the list of translated
+ * instructions. At this point the plugin can register further
+ * callbacks to be triggered when the block or individual instruction
+ * executes.
+ */
+typedef void (*qemu_plugin_vcpu_tb_trans_cb_t)(qemu_plugin_id_t id,
+                                               struct qemu_plugin_tb *tb);
+
+void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
+                                           qemu_plugin_vcpu_tb_trans_cb_t cb);
+
+/**
+ * qemu_plugin_register_vcpu_tb_trans_exec_cb() - register execution callback
+ * @tb: the opaque qemu_plugin_tb handle for the translation
+ * @cb: callback function
+ * @flags: does the plugin read or write the CPU's registers?
+ * @userdata: any plugin data to pass to the @cb?
+ *
+ * The @cb function is called every time a translated unit executes.
+ */
+void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
+                                          qemu_plugin_vcpu_udata_cb_t cb,
+                                          enum qemu_plugin_cb_flags flags,
+                                          void *userdata);
+
+enum qemu_plugin_op {
+    QEMU_PLUGIN_INLINE_ADD_U64,
+};
+
+/**
+ * qemu_plugin_register_vcpu_tb_trans_exec_inline() - execution inline op
+ * @tb: the opaque qemu_plugin_tb handle for the translation
+ * @op: the type of qemu_plugin_op (e.g. ADD_U64)
+ * @ptr: the target memory location for the op
+ * @imm: the op data (e.g. 1)
+ *
+ * Insert an inline op to every time a translated unit executes.
+ * Useful if you just want to increment a single counter somewhere in
+ * memory.
+ */
+void qemu_plugin_register_vcpu_tb_exec_inline(struct qemu_plugin_tb *tb,
+                                              enum qemu_plugin_op op,
+                                              void *ptr, uint64_t imm);
+
+/**
+ * qemu_plugin_register_vcpu_insn_exec_cb() - register insn execution cb
+ * @insn: the opaque qemu_plugin_insn handle for an instruction
+ * @cb: callback function
+ * @flags: does the plugin read or write the CPU's registers?
+ * @userdata: any plugin data to pass to the @cb?
+ *
+ * The @cb function is called every time an instruction is executed
+ */
+void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
+                                            qemu_plugin_vcpu_udata_cb_t cb,
+                                            enum qemu_plugin_cb_flags flags,
+                                            void *userdata);
+
+/**
+ * qemu_plugin_register_vcpu_insn_exec_inline() - insn execution inline op
+ * @insn: the opaque qemu_plugin_insn handle for an instruction
+ * @cb: callback function
+ * @op: the type of qemu_plugin_op (e.g. ADD_U64)
+ * @ptr: the target memory location for the op
+ * @imm: the op data (e.g. 1)
+ *
+ * Insert an inline op to every time an instruction executes. Useful
+ * if you just want to increment a single counter somewhere in memory.
+ */
+void qemu_plugin_register_vcpu_insn_exec_inline(struct qemu_plugin_insn *insn,
+                                                enum qemu_plugin_op op,
+                                                void *ptr, uint64_t imm);
+
+/*
+ * Helpers to query information about the instructions in a block
+ */
+size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb);
+
+uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb);
+
+struct qemu_plugin_insn *
+qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx);
+
+const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn);
+
+size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn);
+
+uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn);
+void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn);
+
+/*
+ * Memory Instrumentation
+ *
+ * The anonymous qemu_plugin_meminfo_t and qemu_plugin_hwaddr types
+ * can be used in queries to QEMU to get more information about a
+ * given memory access.
+ */
+typedef uint32_t qemu_plugin_meminfo_t;
+struct qemu_plugin_hwaddr;
+
+/* meminfo queries */
+unsigned int qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info);
+bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info);
+bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info);
+bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info);
+
+/*
+ * qemu_plugin_get_hwaddr():
+ * @vaddr: the virtual address of the memory operation
+ *
+ * For system emulation returns a qemu_plugin_hwaddr handle to query
+ * details about the actual physical address backing the virtual
+ * address. For linux-user guests it just returns NULL.
+ *
+ * This handle is *only* valid for the duration of the callback. Any
+ * information about the handle should be recovered before the
+ * callback returns.
+ */
+struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
+                                                  uint64_t vaddr);
+
+bool qemu_plugin_hwaddr_is_io(struct qemu_plugin_hwaddr *hwaddr);
+uint64_t qemu_plugin_hwaddr_to_raddr(const struct qemu_plugin_hwaddr *haddr);
+
+typedef void
+(*qemu_plugin_vcpu_mem_cb_t)(unsigned int vcpu_index,
+                             qemu_plugin_meminfo_t info, uint64_t vaddr,
+                             void *userdata);
+
+void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
+                                      qemu_plugin_vcpu_mem_cb_t cb,
+                                      enum qemu_plugin_cb_flags flags,
+                                      enum qemu_plugin_mem_rw rw,
+                                      void *userdata);
+
+void qemu_plugin_register_vcpu_mem_inline(struct qemu_plugin_insn *insn,
+                                          enum qemu_plugin_mem_rw rw,
+                                          enum qemu_plugin_op op, void *ptr,
+                                          uint64_t imm);
+
+
+
+typedef void
+(*qemu_plugin_vcpu_syscall_cb_t)(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,
+                                 uint64_t a6, uint64_t a7, uint64_t a8);
+
+void qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id,
+                                          qemu_plugin_vcpu_syscall_cb_t cb);
+
+typedef void
+(*qemu_plugin_vcpu_syscall_ret_cb_t)(qemu_plugin_id_t id, unsigned int vcpu_idx,
+                                     int64_t num, int64_t ret);
+
+void
+qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
+                                         qemu_plugin_vcpu_syscall_ret_cb_t cb);
+
+
+/**
+ * qemu_plugin_vcpu_for_each() - iterate over the existing vCPU
+ * @id: plugin ID
+ * @cb: callback function
+ *
+ * The @cb function is called once for each existing vCPU.
+ *
+ * See also: qemu_plugin_register_vcpu_init_cb()
+ */
+void qemu_plugin_vcpu_for_each(qemu_plugin_id_t id,
+                               qemu_plugin_vcpu_simple_cb_t cb);
+
+void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
+                                   qemu_plugin_simple_cb_t cb);
+
+void qemu_plugin_register_atexit_cb(qemu_plugin_id_t id,
+                                    qemu_plugin_udata_cb_t cb, void *userdata);
+
+/* returns -1 in user-mode */
+int qemu_plugin_n_vcpus(void);
+
+/* returns -1 in user-mode */
+int qemu_plugin_n_max_vcpus(void);
+
+#endif /* QEMU_PLUGIN_API_H */
-- 
2.20.1



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

* [Qemu-devel] [PATCH  v4 14/54] plugin: add core code
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (12 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 13/54] plugin: add user-facing API Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 15:58   ` Richard Henderson
  2019-09-12  9:17   ` Daniel P. Berrangé
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 15/54] plugin: add implementation of the api Alex Bennée
                   ` (42 subsequent siblings)
  56 siblings, 2 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: Eduardo Habkost, aaron, cota, bobby.prani, Alex Bennée

From: "Emilio G. Cota" <cota@braap.org>

Signed-off-by: Emilio G. Cota <cota@braap.org>
[AJB: moved directory and merged various fixes]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v3
  - moved to plugins/
  - merged
    plugin: remove uninstall_cb_t and just use simple_cb_t
    plugin: handle uninstall when !current_cpu
    plugin: introduce qemu_plugin_reset
  - split into core/loader
  - use GArray/GByteArray/GPtrArray instead of homegrown funcs
v4
  - document QEMU_PLUGIN_EV_MAX
  - move qemu_plugin_ram_addr_from_host to api
  - drop vcpu_index from trans cb
  - s/plugin_dyn_cb_type/plugin_dyn_cb_subtype/ in qemu_plugin_dyn_cb
  - remove haddr from memory hooks
  - checkpatch fixes
---
 Makefile              |   9 +-
 Makefile.target       |   2 +
 include/qemu/plugin.h | 255 +++++++++++++++++++++
 include/qom/cpu.h     |   6 +
 plugins/Makefile.objs |   6 +
 plugins/core.c        | 499 ++++++++++++++++++++++++++++++++++++++++++
 plugins/loader.c      | 353 ++++++++++++++++++++++++++++++
 plugins/plugin.h      |  95 ++++++++
 8 files changed, 1224 insertions(+), 1 deletion(-)
 create mode 100644 include/qemu/plugin.h
 create mode 100644 plugins/Makefile.objs
 create mode 100644 plugins/core.c
 create mode 100644 plugins/loader.c
 create mode 100644 plugins/plugin.h

diff --git a/Makefile b/Makefile
index cfab1561b9c..ed4bb87f224 100644
--- a/Makefile
+++ b/Makefile
@@ -841,7 +841,11 @@ endif
 
 ICON_SIZES=16x16 24x24 32x32 48x48 64x64 128x128 256x256 512x512
 
-install: all $(if $(BUILD_DOCS),install-doc) install-datadir install-localstatedir \
+install-includedir:
+	$(INSTALL_DIR) "$(DESTDIR)$(includedir)"
+
+install: all $(if $(BUILD_DOCS),install-doc) \
+	install-datadir install-localstatedir install-includedir \
 	$(if $(INSTALL_BLOBS),$(edk2-decompressed)) \
 	recurse-install
 ifneq ($(TOOLS),)
@@ -903,6 +907,9 @@ endif
 		"$(DESTDIR)$(qemu_desktopdir)/qemu.desktop"
 ifdef CONFIG_GTK
 	$(MAKE) -C po $@
+endif
+ifeq ($(CONFIG_PLUGIN),y)
+	$(INSTALL_DATA) $(SRC_PATH)/include/qemu/qemu-plugin.h "$(DESTDIR)$(includedir)/qemu-plugin.h"
 endif
 	$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/keymaps"
 	set -e; for x in $(KEYMAPS); do \
diff --git a/Makefile.target b/Makefile.target
index 933b27453a1..1c73028d17a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -122,6 +122,8 @@ obj-y += disas.o
 obj-$(call notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o
 LIBS := $(libs_cpu) $(LIBS)
 
+obj-$(CONFIG_PLUGIN) += plugins/
+
 #########################################################
 # Linux user emulator target
 
diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
new file mode 100644
index 00000000000..3c46a241669
--- /dev/null
+++ b/include/qemu/plugin.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
+ *
+ * License: GNU GPL, version 2 or later.
+ *   See the COPYING file in the top-level directory.
+ */
+#ifndef QEMU_PLUGIN_H
+#define QEMU_PLUGIN_H
+
+#include "qemu/config-file.h"
+#include "qemu/qemu-plugin.h"
+#include "qemu/error-report.h"
+#include "qemu/queue.h"
+#include "qemu/option.h"
+
+/*
+ * Option parsing/processing.
+ * Note that we can load an arbitrary number of plugins.
+ */
+struct qemu_plugin_desc;
+typedef QTAILQ_HEAD(, qemu_plugin_desc) QemuPluginList;
+
+#ifdef CONFIG_PLUGIN
+extern QemuOptsList qemu_plugin_opts;
+
+static inline void qemu_plugin_add_opts(void)
+{
+    qemu_add_opts(&qemu_plugin_opts);
+}
+
+void qemu_plugin_opt_parse(const char *optarg, QemuPluginList *head);
+int qemu_plugin_load_list(QemuPluginList *head);
+#else /* !CONFIG_PLUGIN */
+static inline void qemu_plugin_add_opts(void)
+{ }
+
+static inline void qemu_plugin_opt_parse(const char *optarg,
+                                         QemuPluginList *head)
+{
+    error_report("plugin interface not enabled in this build");
+    exit(1);
+}
+
+static inline int qemu_plugin_load_list(QemuPluginList *head)
+{
+    return 0;
+}
+#endif /* !CONFIG_PLUGIN */
+
+/*
+ * Events that plugins can subscribe to.
+ */
+enum qemu_plugin_event {
+    QEMU_PLUGIN_EV_VCPU_INIT,
+    QEMU_PLUGIN_EV_VCPU_EXIT,
+    QEMU_PLUGIN_EV_VCPU_TB_TRANS,
+    QEMU_PLUGIN_EV_VCPU_IDLE,
+    QEMU_PLUGIN_EV_VCPU_RESUME,
+    QEMU_PLUGIN_EV_VCPU_SYSCALL,
+    QEMU_PLUGIN_EV_VCPU_SYSCALL_RET,
+    QEMU_PLUGIN_EV_FLUSH,
+    QEMU_PLUGIN_EV_ATEXIT,
+    QEMU_PLUGIN_EV_MAX, /* total number of plugin events we support */
+};
+
+union qemu_plugin_cb_sig {
+    qemu_plugin_simple_cb_t          simple;
+    qemu_plugin_udata_cb_t           udata;
+    qemu_plugin_vcpu_simple_cb_t     vcpu_simple;
+    qemu_plugin_vcpu_udata_cb_t      vcpu_udata;
+    qemu_plugin_vcpu_tb_trans_cb_t   vcpu_tb_trans;
+    qemu_plugin_vcpu_mem_cb_t        vcpu_mem;
+    qemu_plugin_vcpu_syscall_cb_t    vcpu_syscall;
+    qemu_plugin_vcpu_syscall_ret_cb_t vcpu_syscall_ret;
+    void *generic;
+};
+
+enum plugin_dyn_cb_type {
+    PLUGIN_CB_INSN,
+    PLUGIN_CB_MEM,
+    PLUGIN_N_CB_TYPES,
+};
+
+enum plugin_dyn_cb_subtype {
+    PLUGIN_CB_REGULAR,
+    PLUGIN_CB_INLINE,
+    PLUGIN_N_CB_SUBTYPES,
+};
+
+/*
+ * A dynamic callback has an insertion point that is determined at run-time.
+ * Usually the insertion point is somewhere in the code cache; think for
+ * instance of a callback to be called upon the execution of a particular TB.
+ */
+struct qemu_plugin_dyn_cb {
+    union qemu_plugin_cb_sig f;
+    void *userp;
+    unsigned tcg_flags;
+    enum plugin_dyn_cb_subtype type;
+    /* @rw applies to mem callbacks only (both regular and inline) */
+    enum qemu_plugin_mem_rw rw;
+    /* fields specific to each dyn_cb type go here */
+    union {
+        struct {
+            enum qemu_plugin_op op;
+            uint64_t imm;
+        } inline_insn;
+    };
+};
+
+struct qemu_plugin_insn {
+    GByteArray *data;
+    uint64_t vaddr;
+    void *haddr;
+    GArray *cbs[PLUGIN_N_CB_TYPES][PLUGIN_N_CB_SUBTYPES];
+    bool calls_helpers;
+    bool mem_helper;
+};
+
+/*
+ * qemu_plugin_insn allocate and cleanup functions. We don't expect to
+ * cleanup many of these structures. They are reused for each fresh
+ * translation.
+ */
+
+static inline void qemu_plugin_insn_cleanup_fn(gpointer data)
+{
+    struct qemu_plugin_insn *insn = (struct qemu_plugin_insn *) data;
+    g_byte_array_free(insn->data, true);
+}
+
+static inline struct qemu_plugin_insn * qemu_plugin_insn_alloc(void)
+{
+    int i, j;
+    struct qemu_plugin_insn *insn = g_new0(struct qemu_plugin_insn, 1);
+    insn->data = g_byte_array_sized_new(4);
+
+    for (i = 0; i < PLUGIN_N_CB_TYPES; i++) {
+        for (j = 0; j < PLUGIN_N_CB_SUBTYPES; j++) {
+            insn->cbs[i][j] = g_array_new(false, false,
+                                          sizeof(struct qemu_plugin_dyn_cb));
+        }
+    }
+    return insn;
+}
+
+struct qemu_plugin_tb {
+    GPtrArray *insns;
+    size_t n;
+    uint64_t vaddr;
+    uint64_t vaddr2;
+    void *haddr1;
+    void *haddr2;
+    GArray *cbs[PLUGIN_N_CB_SUBTYPES];
+};
+
+/**
+ * qemu_plugin_tb_insn_get(): get next plugin record for translation.
+ *
+ */
+static inline
+struct qemu_plugin_insn *qemu_plugin_tb_insn_get(struct qemu_plugin_tb *tb)
+{
+    struct qemu_plugin_insn *insn;
+    int i, j;
+
+    if (unlikely(tb->n == tb->insns->len)) {
+        struct qemu_plugin_insn *new_insn = qemu_plugin_insn_alloc();
+        g_ptr_array_add(tb->insns, new_insn);
+    }
+    insn = g_ptr_array_index(tb->insns, tb->n++);
+    g_byte_array_set_size(insn->data, 0);
+    insn->calls_helpers = false;
+    insn->mem_helper = false;
+
+    for (i = 0; i < PLUGIN_N_CB_TYPES; i++) {
+        for (j = 0; j < PLUGIN_N_CB_SUBTYPES; j++) {
+            g_array_set_size(insn->cbs[i][j], 0);
+        }
+    }
+
+    return insn;
+}
+
+#ifdef CONFIG_PLUGIN
+
+void qemu_plugin_vcpu_init_hook(CPUState *cpu);
+void qemu_plugin_vcpu_exit_hook(CPUState *cpu);
+void qemu_plugin_tb_trans_cb(CPUState *cpu, struct qemu_plugin_tb *tb);
+void qemu_plugin_vcpu_idle_cb(CPUState *cpu);
+void qemu_plugin_vcpu_resume_cb(CPUState *cpu);
+void
+qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1,
+                         uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5,
+                         uint64_t a6, uint64_t a7, uint64_t a8);
+void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret);
+
+void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr, uint32_t meminfo);
+
+void qemu_plugin_flush_cb(void);
+
+void qemu_plugin_atexit_cb(void);
+
+void qemu_plugin_add_dyn_cb_arr(GArray *arr);
+
+void qemu_plugin_disable_mem_helpers(CPUState *cpu);
+
+#else /* !CONFIG_PLUGIN */
+
+static inline void qemu_plugin_vcpu_init_hook(CPUState *cpu)
+{ }
+
+static inline void qemu_plugin_vcpu_exit_hook(CPUState *cpu)
+{ }
+
+static inline void qemu_plugin_tb_trans_cb(CPUState *cpu,
+                                           struct qemu_plugin_tb *tb)
+{ }
+
+static inline void qemu_plugin_vcpu_idle_cb(CPUState *cpu)
+{ }
+
+static inline void qemu_plugin_vcpu_resume_cb(CPUState *cpu)
+{ }
+
+static inline void
+qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1, uint64_t a2,
+                         uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6,
+                         uint64_t a7, uint64_t a8)
+{ }
+
+static inline
+void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret)
+{ }
+
+static inline void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
+                                           uint32_t meminfo)
+{ }
+
+static inline void qemu_plugin_flush_cb(void)
+{ }
+
+static inline void qemu_plugin_atexit_cb(void)
+{ }
+
+static inline
+void qemu_plugin_add_dyn_cb_arr(GArray *arr)
+{ }
+
+static inline void qemu_plugin_disable_mem_helpers(CPUState *cpu)
+{ }
+
+#endif /* !CONFIG_PLUGIN */
+
+#endif /* QEMU_PLUGIN_H */
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 65a0926c49a..7a71d0017fa 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -29,6 +29,7 @@
 #include "qemu/rcu_queue.h"
 #include "qemu/queue.h"
 #include "qemu/thread.h"
+#include "qemu/plugin.h"
 
 typedef int (*WriteCoreDumpFunction)(const void *buf, size_t size,
                                      void *opaque);
@@ -345,6 +346,7 @@ struct qemu_work_item;
  * @trace_dstate_delayed: Delayed changes to trace_dstate (includes all changes
  *                        to @trace_dstate).
  * @trace_dstate: Dynamic tracing state of events for this vCPU (bitmask).
+ * @plugin_mask: Plugin event bitmap. Modified only via async work.
  * @ignore_memory_transaction_failures: Cached copy of the MachineState
  *    flag of the same name: allows the board to suppress calling of the
  *    CPU do_transaction_failed hook function.
@@ -430,6 +432,10 @@ struct CPUState {
     DECLARE_BITMAP(trace_dstate_delayed, CPU_TRACE_DSTATE_MAX_EVENTS);
     DECLARE_BITMAP(trace_dstate, CPU_TRACE_DSTATE_MAX_EVENTS);
 
+    DECLARE_BITMAP(plugin_mask, QEMU_PLUGIN_EV_MAX);
+
+    GArray *plugin_mem_cbs;
+
     /* TODO Move common fields from CPUArchState here. */
     int cpu_index;
     int cluster_index;
diff --git a/plugins/Makefile.objs b/plugins/Makefile.objs
new file mode 100644
index 00000000000..58940335bca
--- /dev/null
+++ b/plugins/Makefile.objs
@@ -0,0 +1,6 @@
+#
+# Plugin Support
+#
+
+obj-y += loader.o
+obj-y += core.o
diff --git a/plugins/core.c b/plugins/core.c
new file mode 100644
index 00000000000..28616b724ee
--- /dev/null
+++ b/plugins/core.c
@@ -0,0 +1,499 @@
+/*
+ * plugin.c - QEMU Plugin interface
+ *
+ * Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
+ *
+ * License: GNU GPL, version 2 or later.
+ *   See the COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/config-file.h"
+#include "qapi/error.h"
+#include "qemu/option.h"
+#include "qemu/rcu_queue.h"
+#include "qemu/xxhash.h"
+#include "qemu/rcu.h"
+#include "qom/cpu.h"
+#include "exec/cpu-common.h"
+#include <dlfcn.h>
+
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "exec/helper-proto.h"
+#include "sysemu/sysemu.h"
+#include "tcg/tcg.h"
+#include "tcg/tcg-op.h"
+#include "trace/mem-internal.h" /* mem_info macros */
+#include "plugin.h"
+
+struct qemu_plugin_cb {
+    struct qemu_plugin_ctx *ctx;
+    union qemu_plugin_cb_sig f;
+    void *udata;
+    QLIST_ENTRY(qemu_plugin_cb) entry;
+};
+
+QLIST_HEAD(qemu_plugin_cb_head, qemu_plugin_cb);
+
+struct qemu_plugin_state plugin;
+
+struct qemu_plugin_ctx *plugin_id_to_ctx_locked(qemu_plugin_id_t id)
+{
+    struct qemu_plugin_ctx *ctx;
+    qemu_plugin_id_t *id_p;
+
+    id_p = g_hash_table_lookup(plugin.id_ht, &id);
+    ctx = container_of(id_p, struct qemu_plugin_ctx, id);
+    if (ctx == NULL) {
+        error_report("plugin: invalid plugin id %" PRIu64, id);
+        abort();
+    }
+    return ctx;
+}
+
+static void plugin_cpu_update__async(CPUState *cpu, run_on_cpu_data data)
+{
+    bitmap_copy(cpu->plugin_mask, &data.host_ulong, QEMU_PLUGIN_EV_MAX);
+    cpu_tb_jmp_cache_clear(cpu);
+}
+
+static void plugin_cpu_update__locked(gpointer k, gpointer v, gpointer udata)
+{
+    CPUState *cpu = container_of(k, CPUState, cpu_index);
+    run_on_cpu_data mask = RUN_ON_CPU_HOST_ULONG(*plugin.mask);
+
+    if (cpu->created) {
+        async_run_on_cpu(cpu, plugin_cpu_update__async, mask);
+    } else {
+        plugin_cpu_update__async(cpu, mask);
+    }
+}
+
+void plugin_unregister_cb__locked(struct qemu_plugin_ctx *ctx,
+                                  enum qemu_plugin_event ev)
+{
+    struct qemu_plugin_cb *cb = ctx->callbacks[ev];
+
+    if (cb == NULL) {
+        return;
+    }
+    QLIST_REMOVE_RCU(cb, entry);
+    g_free(cb);
+    ctx->callbacks[ev] = NULL;
+    if (QLIST_EMPTY_RCU(&plugin.cb_lists[ev])) {
+        clear_bit(ev, plugin.mask);
+        g_hash_table_foreach(plugin.cpu_ht, plugin_cpu_update__locked, NULL);
+    }
+}
+
+static void plugin_vcpu_cb__simple(CPUState *cpu, enum qemu_plugin_event ev)
+{
+    struct qemu_plugin_cb *cb, *next;
+
+    switch (ev) {
+    case QEMU_PLUGIN_EV_VCPU_INIT:
+    case QEMU_PLUGIN_EV_VCPU_EXIT:
+    case QEMU_PLUGIN_EV_VCPU_IDLE:
+    case QEMU_PLUGIN_EV_VCPU_RESUME:
+        /* iterate safely; plugins might uninstall themselves at any time */
+        QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
+            qemu_plugin_vcpu_simple_cb_t func = cb->f.vcpu_simple;
+
+            func(cb->ctx->id, cpu->cpu_index);
+        }
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static void plugin_cb__simple(enum qemu_plugin_event ev)
+{
+    struct qemu_plugin_cb *cb, *next;
+
+    switch (ev) {
+    case QEMU_PLUGIN_EV_FLUSH:
+        QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
+            qemu_plugin_simple_cb_t func = cb->f.simple;
+
+            func(cb->ctx->id);
+        }
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static void plugin_cb__udata(enum qemu_plugin_event ev)
+{
+    struct qemu_plugin_cb *cb, *next;
+
+    switch (ev) {
+    case QEMU_PLUGIN_EV_ATEXIT:
+        QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
+            qemu_plugin_udata_cb_t func = cb->f.udata;
+
+            func(cb->ctx->id, cb->udata);
+        }
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static void
+do_plugin_register_cb(qemu_plugin_id_t id, enum qemu_plugin_event ev,
+                      void *func, void *udata)
+{
+    struct qemu_plugin_ctx *ctx;
+
+    qemu_rec_mutex_lock(&plugin.lock);
+    ctx = plugin_id_to_ctx_locked(id);
+    /* if the plugin is on its way out, ignore this request */
+    if (unlikely(ctx->uninstalling)) {
+        goto out_unlock;
+    }
+    if (func) {
+        struct qemu_plugin_cb *cb = ctx->callbacks[ev];
+
+        if (cb) {
+            cb->f.generic = func;
+            cb->udata = udata;
+        } else {
+            cb = g_new(struct qemu_plugin_cb, 1);
+            cb->ctx = ctx;
+            cb->f.generic = func;
+            cb->udata = udata;
+            ctx->callbacks[ev] = cb;
+            QLIST_INSERT_HEAD_RCU(&plugin.cb_lists[ev], cb, entry);
+            if (!test_bit(ev, plugin.mask)) {
+                set_bit(ev, plugin.mask);
+                g_hash_table_foreach(plugin.cpu_ht, plugin_cpu_update__locked,
+                                     NULL);
+            }
+        }
+    } else {
+        plugin_unregister_cb__locked(ctx, ev);
+    }
+ out_unlock:
+    qemu_rec_mutex_unlock(&plugin.lock);
+}
+
+void plugin_register_cb(qemu_plugin_id_t id, enum qemu_plugin_event ev,
+                        void *func)
+{
+    do_plugin_register_cb(id, ev, func, NULL);
+}
+
+void
+plugin_register_cb_udata(qemu_plugin_id_t id, enum qemu_plugin_event ev,
+                         void *func, void *udata)
+{
+    do_plugin_register_cb(id, ev, func, udata);
+}
+
+void qemu_plugin_vcpu_init_hook(CPUState *cpu)
+{
+    bool success;
+
+    qemu_rec_mutex_lock(&plugin.lock);
+    plugin_cpu_update__locked(&cpu->cpu_index, NULL, NULL);
+    success = g_hash_table_insert(plugin.cpu_ht, &cpu->cpu_index,
+                                  &cpu->cpu_index);
+    g_assert(success);
+    qemu_rec_mutex_unlock(&plugin.lock);
+
+    plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_INIT);
+}
+
+void qemu_plugin_vcpu_exit_hook(CPUState *cpu)
+{
+    bool success;
+
+    plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_EXIT);
+
+    qemu_rec_mutex_lock(&plugin.lock);
+    success = g_hash_table_remove(plugin.cpu_ht, &cpu->cpu_index);
+    g_assert(success);
+    qemu_rec_mutex_unlock(&plugin.lock);
+}
+
+struct plugin_for_each_args {
+    struct qemu_plugin_ctx *ctx;
+    qemu_plugin_vcpu_simple_cb_t cb;
+};
+
+static void plugin_vcpu_for_each(gpointer k, gpointer v, gpointer udata)
+{
+    struct plugin_for_each_args *args = udata;
+    int cpu_index = *(int *)k;
+
+    args->cb(args->ctx->id, cpu_index);
+}
+
+void qemu_plugin_vcpu_for_each(qemu_plugin_id_t id,
+                               qemu_plugin_vcpu_simple_cb_t cb)
+{
+    struct plugin_for_each_args args;
+
+    if (cb == NULL) {
+        return;
+    }
+    qemu_rec_mutex_lock(&plugin.lock);
+    args.ctx = plugin_id_to_ctx_locked(id);
+    args.cb = cb;
+    g_hash_table_foreach(plugin.cpu_ht, plugin_vcpu_for_each, &args);
+    qemu_rec_mutex_unlock(&plugin.lock);
+}
+
+/* Allocate and return a callback record */
+static struct qemu_plugin_dyn_cb *plugin_get_dyn_cb(GArray **arr)
+{
+    GArray *cbs = *arr;
+
+    if (!cbs) {
+        cbs = g_array_sized_new(false, false, sizeof(struct qemu_plugin_dyn_cb), 1);
+        *arr = cbs;
+    }
+
+    g_array_set_size(cbs, cbs->len + 1);
+    return &g_array_index(cbs, struct qemu_plugin_dyn_cb, cbs->len - 1);
+}
+
+void plugin_register_inline_op(GArray **arr,
+                               enum qemu_plugin_mem_rw rw,
+                               enum qemu_plugin_op op, void *ptr,
+                               uint64_t imm)
+{
+    struct qemu_plugin_dyn_cb *dyn_cb;
+
+    dyn_cb = plugin_get_dyn_cb(arr);
+    dyn_cb->userp = ptr;
+    dyn_cb->type = PLUGIN_CB_INLINE;
+    dyn_cb->rw = rw;
+    dyn_cb->inline_insn.op = op;
+    dyn_cb->inline_insn.imm = imm;
+}
+
+static inline uint32_t cb_to_tcg_flags(enum qemu_plugin_cb_flags flags)
+{
+    uint32_t ret;
+
+    switch (flags) {
+    case QEMU_PLUGIN_CB_RW_REGS:
+        ret = 0;
+    case QEMU_PLUGIN_CB_R_REGS:
+        ret = TCG_CALL_NO_WG;
+        break;
+    case QEMU_PLUGIN_CB_NO_REGS:
+    default:
+        ret = TCG_CALL_NO_RWG;
+    }
+    return ret;
+}
+
+inline void
+plugin_register_dyn_cb__udata(GArray **arr,
+                              qemu_plugin_vcpu_udata_cb_t cb,
+                              enum qemu_plugin_cb_flags flags, void *udata)
+{
+    struct qemu_plugin_dyn_cb *dyn_cb = plugin_get_dyn_cb(arr);
+
+    dyn_cb->userp = udata;
+    dyn_cb->tcg_flags = cb_to_tcg_flags(flags);
+    dyn_cb->f.vcpu_udata = cb;
+    dyn_cb->type = PLUGIN_CB_REGULAR;
+}
+
+void plugin_register_vcpu_mem_cb(GArray **arr,
+                                 void *cb,
+                                 enum qemu_plugin_cb_flags flags,
+                                 enum qemu_plugin_mem_rw rw,
+                                 void *udata)
+{
+    struct qemu_plugin_dyn_cb *dyn_cb;
+
+    dyn_cb = plugin_get_dyn_cb(arr);
+    dyn_cb->userp = udata;
+    dyn_cb->tcg_flags = cb_to_tcg_flags(flags);
+    dyn_cb->type = PLUGIN_CB_REGULAR;
+    dyn_cb->rw = rw;
+    dyn_cb->f.generic = cb;
+}
+
+void qemu_plugin_tb_trans_cb(CPUState *cpu, struct qemu_plugin_tb *tb)
+{
+    struct qemu_plugin_cb *cb, *next;
+    enum qemu_plugin_event ev = QEMU_PLUGIN_EV_VCPU_TB_TRANS;
+
+    /* no plugin_mask check here; caller should have checked */
+
+    QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
+        qemu_plugin_vcpu_tb_trans_cb_t func = cb->f.vcpu_tb_trans;
+
+        func(cb->ctx->id, tb);
+    }
+}
+
+void
+qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1, uint64_t a2,
+                         uint64_t a3, uint64_t a4, uint64_t a5,
+                         uint64_t a6, uint64_t a7, uint64_t a8)
+{
+    struct qemu_plugin_cb *cb, *next;
+    enum qemu_plugin_event ev = QEMU_PLUGIN_EV_VCPU_SYSCALL;
+
+    if (!test_bit(ev, cpu->plugin_mask)) {
+        return;
+    }
+
+    QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
+        qemu_plugin_vcpu_syscall_cb_t func = cb->f.vcpu_syscall;
+
+        func(cb->ctx->id, cpu->cpu_index, num, a1, a2, a3, a4, a5, a6, a7, a8);
+    }
+}
+
+void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret)
+{
+    struct qemu_plugin_cb *cb, *next;
+    enum qemu_plugin_event ev = QEMU_PLUGIN_EV_VCPU_SYSCALL_RET;
+
+    if (!test_bit(ev, cpu->plugin_mask)) {
+        return;
+    }
+
+    QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
+        qemu_plugin_vcpu_syscall_ret_cb_t func = cb->f.vcpu_syscall_ret;
+
+        func(cb->ctx->id, cpu->cpu_index, num, ret);
+    }
+}
+
+void qemu_plugin_vcpu_idle_cb(CPUState *cpu)
+{
+    plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_IDLE);
+}
+
+void qemu_plugin_vcpu_resume_cb(CPUState *cpu)
+{
+    plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_RESUME);
+}
+
+void qemu_plugin_register_vcpu_idle_cb(qemu_plugin_id_t id,
+                                       qemu_plugin_vcpu_simple_cb_t cb)
+{
+    plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_IDLE, cb);
+}
+
+void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
+                                         qemu_plugin_vcpu_simple_cb_t cb)
+{
+    plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_RESUME, cb);
+}
+
+void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
+                                   qemu_plugin_simple_cb_t cb)
+{
+    plugin_register_cb(id, QEMU_PLUGIN_EV_FLUSH, cb);
+}
+
+static bool free_dyn_cb_arr(void *p, uint32_t h, void *userp)
+{
+    g_array_free((GArray *) p, true);
+    return true;
+}
+
+void qemu_plugin_flush_cb(void)
+{
+    qht_iter_remove(&plugin.dyn_cb_arr_ht, free_dyn_cb_arr, NULL);
+    qht_reset(&plugin.dyn_cb_arr_ht);
+
+    plugin_cb__simple(QEMU_PLUGIN_EV_FLUSH);
+}
+
+void exec_inline_op(struct qemu_plugin_dyn_cb *cb)
+{
+    uint64_t *val = cb->userp;
+
+    switch (cb->inline_insn.op) {
+    case QEMU_PLUGIN_INLINE_ADD_U64:
+        *val += cb->inline_insn.imm;
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr, uint32_t info)
+{
+    GArray *arr = cpu->plugin_mem_cbs;
+    size_t i;
+
+    if (arr == NULL) {
+        return;
+    }
+    for (i = 0; i < arr->len; i++) {
+        struct qemu_plugin_dyn_cb *cb =
+            &g_array_index(arr, struct qemu_plugin_dyn_cb, i);
+        int w = !!(info & TRACE_MEM_ST) + 1;
+
+        if (!(w & cb->rw)) {
+                break;
+        }
+        switch (cb->type) {
+        case PLUGIN_CB_REGULAR:
+            cb->f.vcpu_mem(cpu->cpu_index, info, vaddr, cb->userp);
+            break;
+        case PLUGIN_CB_INLINE:
+            exec_inline_op(cb);
+            break;
+        default:
+            g_assert_not_reached();
+        }
+    }
+}
+
+void qemu_plugin_atexit_cb(void)
+{
+    plugin_cb__udata(QEMU_PLUGIN_EV_ATEXIT);
+}
+
+void qemu_plugin_register_atexit_cb(qemu_plugin_id_t id,
+                                    qemu_plugin_udata_cb_t cb,
+                                    void *udata)
+{
+    plugin_register_cb_udata(id, QEMU_PLUGIN_EV_ATEXIT, cb, udata);
+}
+
+/*
+ * Call this function after longjmp'ing to the main loop. It's possible that the
+ * last instruction of a TB might have used helpers, and therefore the
+ * "disable" instruction will never execute because it ended up as dead code.
+ */
+void qemu_plugin_disable_mem_helpers(CPUState *cpu)
+{
+    cpu->plugin_mem_cbs = NULL;
+}
+
+static bool plugin_dyn_cb_arr_cmp(const void *ap, const void *bp)
+{
+    return ap == bp;
+}
+
+static void __attribute__((__constructor__)) plugin_init(void)
+{
+    int i;
+
+    for (i = 0; i < QEMU_PLUGIN_EV_MAX; i++) {
+        QLIST_INIT(&plugin.cb_lists[i]);
+    }
+    qemu_rec_mutex_init(&plugin.lock);
+    plugin.id_ht = g_hash_table_new(g_int64_hash, g_int64_equal);
+    plugin.cpu_ht = g_hash_table_new(g_int_hash, g_int_equal);
+    QTAILQ_INIT(&plugin.ctxs);
+    qht_init(&plugin.dyn_cb_arr_ht, plugin_dyn_cb_arr_cmp, 16,
+             QHT_MODE_AUTO_RESIZE);
+    atexit(qemu_plugin_atexit_cb);
+}
diff --git a/plugins/loader.c b/plugins/loader.c
new file mode 100644
index 00000000000..bd77e88ede0
--- /dev/null
+++ b/plugins/loader.c
@@ -0,0 +1,353 @@
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/config-file.h"
+#include "qapi/error.h"
+#include "qemu/option.h"
+#include "qemu/rcu_queue.h"
+#include "qemu/qht.h"
+#include "qemu/bitmap.h"
+#include "qemu/xxhash.h"
+#include "qemu/plugin.h"
+#include "qom/cpu.h"
+#include <dlfcn.h>
+#include "cpu.h"
+#include "exec/exec-all.h"
+
+#include "plugin.h"
+
+/*
+ * For convenience we use a bitmap for plugin.mask, but really all we need is a
+ * u32, which is what we store in TranslationBlock.
+ */
+QEMU_BUILD_BUG_ON(QEMU_PLUGIN_EV_MAX > 32);
+
+struct qemu_plugin_desc {
+    char *path;
+    char **argv;
+    QTAILQ_ENTRY(qemu_plugin_desc) entry;
+    int argc;
+};
+
+struct qemu_plugin_parse_arg {
+    QemuPluginList *head;
+    struct qemu_plugin_desc *curr;
+};
+
+QemuOptsList qemu_plugin_opts = {
+    .name = "plugin",
+    .implied_opt_name = "file",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_plugin_opts.head),
+    .desc = {
+        /* do our own parsing to support multiple plugins */
+        { /* end of list */ }
+    },
+};
+
+typedef int (*qemu_plugin_install_func_t)(qemu_plugin_id_t, int, char **);
+
+extern struct qemu_plugin_state plugin;
+
+void qemu_plugin_add_dyn_cb_arr(GArray *arr)
+{
+    uint32_t hash = qemu_xxhash2((uint64_t)(uintptr_t)arr);
+    bool inserted;
+
+    inserted = qht_insert(&plugin.dyn_cb_arr_ht, arr, hash, NULL);
+    g_assert(inserted);
+}
+
+static struct qemu_plugin_desc *plugin_find_desc(QemuPluginList *head,
+                                                 const char *path)
+{
+    struct qemu_plugin_desc *desc;
+
+    QTAILQ_FOREACH(desc, head, entry) {
+        if (strcmp(desc->path, path) == 0) {
+            return desc;
+        }
+    }
+    return NULL;
+}
+
+static int plugin_add(void *opaque, const char *name, const char *value,
+                      Error **errp)
+{
+    struct qemu_plugin_parse_arg *arg = opaque;
+    struct qemu_plugin_desc *p;
+
+    if (strcmp(name, "file") == 0) {
+        if (strcmp(value, "") == 0) {
+            error_setg(errp, "requires a non-empty argument");
+            return 1;
+        }
+        p = plugin_find_desc(arg->head, value);
+        if (p == NULL) {
+            p = g_new0(struct qemu_plugin_desc, 1);
+            p->path = g_strdup(value);
+            QTAILQ_INSERT_TAIL(arg->head, p, entry);
+        }
+        arg->curr = p;
+    } else if (strcmp(name, "arg") == 0) {
+        if (arg->curr == NULL) {
+            error_setg(errp, "missing earlier '-plugin file=' option");
+            return 1;
+        }
+        p = arg->curr;
+        p->argc++;
+        p->argv = g_realloc_n(p->argv, p->argc, sizeof(char *));
+        p->argv[p->argc - 1] = g_strdup(value);
+    } else {
+        error_setg(errp, "-plugin: unexpected parameter '%s'; ignored", name);
+    }
+    return 0;
+}
+
+void qemu_plugin_opt_parse(const char *optarg, QemuPluginList *head)
+{
+    struct qemu_plugin_parse_arg arg;
+    QemuOpts *opts;
+
+    opts = qemu_opts_parse_noisily(qemu_find_opts("plugin"), optarg, true);
+    if (opts == NULL) {
+        exit(1);
+    }
+    arg.head = head;
+    arg.curr = NULL;
+    qemu_opt_foreach(opts, plugin_add, &arg, &error_fatal);
+    qemu_opts_del(opts);
+}
+
+/*
+ * From: https://en.wikipedia.org/wiki/Xorshift
+ * This is faster than rand_r(), and gives us a wider range (RAND_MAX is only
+ * guaranteed to be >= INT_MAX).
+ */
+static uint64_t xorshift64star(uint64_t x)
+{
+    x ^= x >> 12; /* a */
+    x ^= x << 25; /* b */
+    x ^= x >> 27; /* c */
+    return x * UINT64_C(2685821657736338717);
+}
+
+static int plugin_load(struct qemu_plugin_desc *desc)
+{
+    qemu_plugin_install_func_t install;
+    struct qemu_plugin_ctx *ctx;
+    char *err;
+    int rc;
+
+    ctx = qemu_memalign(qemu_dcache_linesize, sizeof(*ctx));
+    memset(ctx, 0, sizeof(*ctx));
+    ctx->desc = desc;
+
+    ctx->handle = dlopen(desc->path, RTLD_NOW);
+    if (ctx->handle == NULL) {
+        error_report("%s: %s", __func__, dlerror());
+        goto err_dlopen;
+    }
+
+    /* clear any previous dlerror, call dlsym, then check dlerror */
+    dlerror();
+    install = dlsym(ctx->handle, "qemu_plugin_install");
+    err = dlerror();
+    if (err) {
+        error_report("%s: %s", __func__, err);
+        goto err_symbol;
+    }
+    /* symbol was found; it could be NULL though */
+    if (install == NULL) {
+        error_report("%s: %s: qemu_plugin_install is NULL",
+                     __func__, desc->path);
+        goto err_symbol;
+    }
+
+    qemu_rec_mutex_lock(&plugin.lock);
+
+    /* find an unused random id with &ctx as the seed */
+    ctx->id = (uint64_t)(uintptr_t)ctx;
+    for (;;) {
+        void *existing;
+
+        ctx->id = xorshift64star(ctx->id);
+        existing = g_hash_table_lookup(plugin.id_ht, &ctx->id);
+        if (likely(existing == NULL)) {
+            bool success;
+
+            success = g_hash_table_insert(plugin.id_ht, &ctx->id, &ctx->id);
+            g_assert(success);
+            break;
+        }
+    }
+    QTAILQ_INSERT_TAIL(&plugin.ctxs, ctx, entry);
+    ctx->installing = true;
+    rc = install(ctx->id, desc->argc, desc->argv);
+    ctx->installing = false;
+    if (rc) {
+        error_report("%s: qemu_plugin_install returned error code %d",
+                     __func__, rc);
+        /*
+         * we cannot rely on the plugin doing its own cleanup, so
+         * call a full uninstall if the plugin did not yet call it.
+         */
+        /* if (!ctx->uninstalling) { */
+        /*     qemu_plugin_uninstall(ctx->id, NULL); */
+        /* } */
+    }
+
+    qemu_rec_mutex_unlock(&plugin.lock);
+    return rc;
+
+ err_symbol:
+    if (dlclose(ctx->handle)) {
+        warn_report("%s: %s", __func__, dlerror());
+    }
+ err_dlopen:
+    qemu_vfree(ctx);
+    return 1;
+}
+
+/* call after having removed @desc from the list */
+static void plugin_desc_free(struct qemu_plugin_desc *desc)
+{
+    int i;
+
+    for (i = 0; i < desc->argc; i++) {
+        g_free(desc->argv[i]);
+    }
+    g_free(desc->argv);
+    g_free(desc->path);
+    g_free(desc);
+}
+
+/**
+ * qemu_plugin_load_list - load a list of plugins
+ * @head: head of the list of descriptors of the plugins to be loaded
+ *
+ * Returns 0 if all plugins in the list are installed, !0 otherwise.
+ *
+ * Note: the descriptor of each successfully installed plugin is removed
+ * from the list given by @head.
+ */
+int qemu_plugin_load_list(QemuPluginList *head)
+{
+    struct qemu_plugin_desc *desc, *next;
+
+    QTAILQ_FOREACH_SAFE(desc, head, entry, next) {
+        int err;
+
+        err = plugin_load(desc);
+        if (err) {
+            return err;
+        }
+        QTAILQ_REMOVE(head, desc, entry);
+    }
+    return 0;
+}
+
+struct qemu_plugin_reset_data {
+    struct qemu_plugin_ctx *ctx;
+    qemu_plugin_simple_cb_t cb;
+    bool reset;
+};
+
+static void plugin_reset_destroy__locked(struct qemu_plugin_reset_data *data)
+{
+    struct qemu_plugin_ctx *ctx = data->ctx;
+    enum qemu_plugin_event ev;
+    bool success;
+
+    /*
+     * After updating the subscription lists there is no need to wait for an RCU
+     * grace period to elapse, because right now we either are in a "safe async"
+     * work environment (i.e. all vCPUs are asleep), or no vCPUs have yet been
+     * created.
+     */
+    for (ev = 0; ev < QEMU_PLUGIN_EV_MAX; ev++) {
+        plugin_unregister_cb__locked(ctx, ev);
+    }
+
+    if (data->reset) {
+        g_assert(ctx->resetting);
+        if (data->cb) {
+            data->cb(ctx->id);
+        }
+        ctx->resetting = false;
+        g_free(data);
+        return;
+    }
+
+    g_assert(ctx->uninstalling);
+    /* we cannot dlclose if we are going to return to plugin code */
+    if (ctx->installing) {
+        error_report("Calling qemu_plugin_uninstall from the install function "
+                     "is a bug. Instead, return !0 from the install function.");
+        abort();
+    }
+
+    success = g_hash_table_remove(plugin.id_ht, &ctx->id);
+    g_assert(success);
+    QTAILQ_REMOVE(&plugin.ctxs, ctx, entry);
+    if (data->cb) {
+        data->cb(ctx->id);
+    }
+    if (dlclose(ctx->handle)) {
+        warn_report("%s: %s", __func__, dlerror());
+    }
+    plugin_desc_free(ctx->desc);
+    qemu_vfree(ctx);
+    g_free(data);
+}
+
+static void plugin_reset_destroy(struct qemu_plugin_reset_data *data)
+{
+    qemu_rec_mutex_lock(&plugin.lock);
+    plugin_reset_destroy__locked(data);
+    qemu_rec_mutex_lock(&plugin.lock);
+}
+
+static void plugin_flush_destroy(CPUState *cpu, run_on_cpu_data arg)
+{
+    struct qemu_plugin_reset_data *data = arg.host_ptr;
+
+    g_assert(cpu_in_exclusive_context(cpu));
+    tb_flush(cpu);
+    plugin_reset_destroy(data);
+}
+
+void plugin_reset_uninstall(qemu_plugin_id_t id,
+                            qemu_plugin_simple_cb_t cb,
+                            bool reset)
+{
+    struct qemu_plugin_reset_data *data;
+    struct qemu_plugin_ctx *ctx;
+
+    qemu_rec_mutex_lock(&plugin.lock);
+    ctx = plugin_id_to_ctx_locked(id);
+    if (ctx->uninstalling || (reset && ctx->resetting)) {
+        qemu_rec_mutex_unlock(&plugin.lock);
+        return;
+    }
+    ctx->resetting = reset;
+    ctx->uninstalling = !reset;
+    qemu_rec_mutex_unlock(&plugin.lock);
+
+    data = g_new(struct qemu_plugin_reset_data, 1);
+    data->ctx = ctx;
+    data->cb = cb;
+    data->reset = reset;
+    /*
+     * Only flush the code cache if the vCPUs have been created. If so,
+     * current_cpu must be non-NULL.
+     */
+    if (current_cpu) {
+        async_safe_run_on_cpu(current_cpu, plugin_flush_destroy,
+                              RUN_ON_CPU_HOST_PTR(data));
+    } else {
+        /*
+         * If current_cpu isn't set, then we don't have yet any vCPU threads
+         * and we therefore can remove the callbacks synchronously.
+         */
+        plugin_reset_destroy(data);
+    }
+}
diff --git a/plugins/plugin.h b/plugins/plugin.h
new file mode 100644
index 00000000000..641f006dd76
--- /dev/null
+++ b/plugins/plugin.h
@@ -0,0 +1,95 @@
+/*
+ * Plugin Shared Internal Functions
+ *
+ * Copyright (C) 2019, Linaro
+ *
+ * License: GNU GPL, version 2 or later.
+ *   See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef _PLUGIN_INTERNAL_H_
+#define _PLUGIN_INTERNAL_H_
+
+/* global state */
+struct qemu_plugin_state {
+    QTAILQ_HEAD(, qemu_plugin_ctx) ctxs;
+    QLIST_HEAD(, qemu_plugin_cb) cb_lists[QEMU_PLUGIN_EV_MAX];
+    /*
+     * Use the HT as a hash map by inserting k == v, which saves memory as
+     * documented by GLib. The parent struct is obtained with container_of().
+     */
+    GHashTable *id_ht;
+    /*
+     * Use the HT as a hash map. Note that we could use a list here,
+     * but with the HT we avoid adding a field to CPUState.
+     */
+    GHashTable *cpu_ht;
+    DECLARE_BITMAP(mask, QEMU_PLUGIN_EV_MAX);
+    /*
+     * @lock protects the struct as well as ctx->uninstalling.
+     * The lock must be acquired by all API ops.
+     * The lock is recursive, which greatly simplifies things, e.g.
+     * callback registration from qemu_plugin_vcpu_for_each().
+     */
+    QemuRecMutex lock;
+    /*
+     * HT of callbacks invoked from helpers. All entries are freed when
+     * the code cache is flushed.
+     */
+    struct qht dyn_cb_arr_ht;
+};
+
+
+struct qemu_plugin_ctx {
+    void *handle; /* dlopen */
+    qemu_plugin_id_t id;
+    struct qemu_plugin_cb *callbacks[QEMU_PLUGIN_EV_MAX];
+    QTAILQ_ENTRY(qemu_plugin_ctx) entry;
+    /*
+     * keep a reference to @desc until uninstall, so that plugins do not have
+     * to strdup plugin args.
+     */
+    struct qemu_plugin_desc *desc;
+    bool installing;
+    bool uninstalling;
+    bool resetting;
+};
+
+struct qemu_plugin_ctx *plugin_id_to_ctx_locked(qemu_plugin_id_t id);
+
+void plugin_register_inline_op(GArray **arr,
+                               enum qemu_plugin_mem_rw rw,
+                               enum qemu_plugin_op op, void *ptr,
+                               uint64_t imm);
+
+void plugin_reset_uninstall(qemu_plugin_id_t id,
+                            qemu_plugin_simple_cb_t cb,
+                            bool reset);
+
+void plugin_register_cb(qemu_plugin_id_t id, enum qemu_plugin_event ev,
+                        void *func);
+
+void plugin_unregister_cb__locked(struct qemu_plugin_ctx *ctx,
+                                  enum qemu_plugin_event ev);
+
+void
+plugin_register_cb_udata(qemu_plugin_id_t id, enum qemu_plugin_event ev,
+                         void *func, void *udata);
+
+void
+plugin_register_dyn_cb__udata(GArray **arr,
+                              qemu_plugin_vcpu_udata_cb_t cb,
+                              enum qemu_plugin_cb_flags flags, void *udata);
+
+
+void plugin_register_vcpu_mem_cb(GArray **arr,
+                                 void *cb,
+                                 enum qemu_plugin_cb_flags flags,
+                                 enum qemu_plugin_mem_rw rw,
+                                 void *udata);
+
+void exec_inline_op(struct qemu_plugin_dyn_cb *cb);
+
+#endif /* _PLUGIN_INTERNAL_H_ */
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 15/54] plugin: add implementation of the api
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (13 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 14/54] plugin: add core code Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 16:14   ` Richard Henderson
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 16/54] queue: add QTAILQ_REMOVE_SEVERAL Alex Bennée
                   ` (41 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: bobby.prani, cota, Alex Bennée, aaron

[AJB: split from the core code commit]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v4
   - add qemu_plugin_ram_addr_from_host
   - remove _haddr api calls
---
 plugins/Makefile.objs |   1 +
 plugins/api.c         | 299 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 300 insertions(+)
 create mode 100644 plugins/api.c

diff --git a/plugins/Makefile.objs b/plugins/Makefile.objs
index 58940335bca..95baabf3d2f 100644
--- a/plugins/Makefile.objs
+++ b/plugins/Makefile.objs
@@ -4,3 +4,4 @@
 
 obj-y += loader.o
 obj-y += core.o
+obj-y += api.o
diff --git a/plugins/api.c b/plugins/api.c
new file mode 100644
index 00000000000..586bb8789f1
--- /dev/null
+++ b/plugins/api.c
@@ -0,0 +1,299 @@
+/*
+ * QEMU Plugin API
+ *
+ * This provides the API that is available to the plugins to interact
+ * with QEMU. We have to be careful not to expose internal details of
+ * how QEMU works so we abstract out things like translation and
+ * instructions to anonymous data types:
+ *
+ *  qemu_plugin_tb
+ *  qemu_plugin_insn
+ *
+ * Which can then be passed back into the API to do additional things.
+ * As such all the public functions in here are exported in
+ * qemu-plugin.h.
+ *
+ * The general life-cycle of a plugin is:
+ *
+ *  - plugin is loaded, public qemu_plugin_install called
+ *    - the install func registers callbacks for events
+ *    - usually an atexit_cb is registered to dump info at the end
+ *  - when a registered event occurs the plugin is called
+ *     - some events pass additional info
+ *     - during translation the plugin can decide to instrument any
+ *       instruction
+ *  - when QEMU exits all the registered atexit callbacks are called
+ *
+ * Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
+ * Copyright (C) 2019, Linaro
+ *
+ * License: GNU GPL, version 2 or later.
+ *   See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/plugin.h"
+#include "cpu.h"
+#include "sysemu/sysemu.h"
+#include "tcg/tcg.h"
+#include "trace/mem-internal.h" /* mem_info macros */
+#include "plugin.h"
+#ifndef CONFIG_USER_ONLY
+#include "hw/boards.h"
+#endif
+
+/* Uninstall and Reset handlers */
+
+void qemu_plugin_uninstall(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb)
+{
+    plugin_reset_uninstall(id, cb, false);
+}
+
+void qemu_plugin_reset(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb)
+{
+    plugin_reset_uninstall(id, cb, true);
+}
+
+/*
+ * Plugin Register Functions
+ *
+ * This allows the plugin to register callbacks for various events
+ * during the translation.
+ */
+
+void qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id,
+                                       qemu_plugin_vcpu_simple_cb_t cb)
+{
+    plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_INIT, cb);
+}
+
+void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,
+                                       qemu_plugin_vcpu_simple_cb_t cb)
+{
+    plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_EXIT, cb);
+}
+
+void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
+                                          qemu_plugin_vcpu_udata_cb_t cb,
+                                          enum qemu_plugin_cb_flags flags,
+                                          void *udata)
+{
+    plugin_register_dyn_cb__udata(&tb->cbs[PLUGIN_CB_REGULAR],
+                                  cb, flags, udata);
+}
+
+void qemu_plugin_register_vcpu_tb_exec_inline(struct qemu_plugin_tb *tb,
+                                              enum qemu_plugin_op op,
+                                              void *ptr, uint64_t imm)
+{
+    plugin_register_inline_op(&tb->cbs[PLUGIN_CB_INLINE], 0, op, ptr, imm);
+}
+
+void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
+                                            qemu_plugin_vcpu_udata_cb_t cb,
+                                            enum qemu_plugin_cb_flags flags,
+                                            void *udata)
+{
+    plugin_register_dyn_cb__udata(&insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR],
+        cb, flags, udata);
+}
+
+void qemu_plugin_register_vcpu_insn_exec_inline(struct qemu_plugin_insn *insn,
+                                                enum qemu_plugin_op op,
+                                                void *ptr, uint64_t imm)
+{
+    plugin_register_inline_op(&insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE],
+                              0, op, ptr, imm);
+}
+
+
+
+void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
+                                      qemu_plugin_vcpu_mem_cb_t cb,
+                                      enum qemu_plugin_cb_flags flags,
+                                      enum qemu_plugin_mem_rw rw,
+                                      void *udata)
+{
+    plugin_register_vcpu_mem_cb(&insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR],
+                                cb, flags, rw, udata);
+}
+
+void qemu_plugin_register_vcpu_mem_inline(struct qemu_plugin_insn *insn,
+                                          enum qemu_plugin_mem_rw rw,
+                                          enum qemu_plugin_op op, void *ptr,
+                                          uint64_t imm)
+{
+    plugin_register_inline_op(&insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE],
+        rw, op, ptr, imm);
+}
+
+void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
+                                           qemu_plugin_vcpu_tb_trans_cb_t cb)
+{
+    plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_TB_TRANS, cb);
+}
+
+void qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id,
+                                          qemu_plugin_vcpu_syscall_cb_t cb)
+{
+    plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL, cb);
+}
+
+void
+qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
+                                         qemu_plugin_vcpu_syscall_ret_cb_t cb)
+{
+    plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL_RET, cb);
+}
+
+/*
+ * Plugin Queries
+ *
+ * These are queries that the plugin can make to gauge information
+ * from our opaque data types. We do not want to leak internal details
+ * here just information useful to the plugin.
+ */
+
+/*
+ * Translation block information:
+ *
+ * A plugin can query the virtual address of the start of the block
+ * and the number of instructions in it. It can also get access to
+ * each translated instruction.
+ */
+
+size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb)
+{
+    return tb->n;
+}
+
+uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb)
+{
+    return tb->vaddr;
+}
+
+struct qemu_plugin_insn *
+qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx)
+{
+    if (unlikely(idx >= tb->n)) {
+        return NULL;
+    }
+    return g_ptr_array_index(tb->insns, idx);
+}
+
+/*
+ * Instruction information
+ *
+ * These queries allow the plugin to retrieve information about each
+ * instruction being translated.
+ */
+
+const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn)
+{
+    return insn->data->data;
+}
+
+size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn)
+{
+    return insn->data->len;
+}
+
+uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn)
+{
+    return insn->vaddr;
+}
+
+void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn)
+{
+    return insn->haddr;
+}
+
+/*
+ * The memory queries allow the plugin to query information about a
+ * memory access.
+ */
+
+unsigned qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info)
+{
+    return info & TRACE_MEM_SZ_SHIFT_MASK;
+}
+
+bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info)
+{
+    return !!(info & TRACE_MEM_SE);
+}
+
+bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info)
+{
+    return !!(info & TRACE_MEM_BE);
+}
+
+bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info)
+{
+    return !!(info & TRACE_MEM_ST);
+}
+
+/*
+ * Virtual Memory queries
+ */
+
+struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
+                                                  uint64_t vaddr)
+{
+    return NULL;
+}
+
+bool qemu_plugin_hwaddr_is_io(struct qemu_plugin_hwaddr *hwaddr)
+{
+    return false;
+}
+
+uint64_t qemu_plugin_hwaddr_to_raddr(const struct qemu_plugin_hwaddr *haddr)
+{
+#if 0 /* XXX FIXME should be SOFTMMU */
+    ram_addr_t ram_addr;
+
+    g_assert(haddr);
+    ram_addr = qemu_ram_addr_from_host(haddr);
+    if (ram_addr == RAM_ADDR_INVALID) {
+        error_report("Bad ram pointer %p", haddr);
+        abort();
+    }
+    return ram_addr;
+#else
+    return 0;
+#endif
+}
+
+/*
+ * Queries to the number and potential maximum number of vCPUs there
+ * will be. This helps the plugin dimension per-vcpu arrays.
+ */
+
+#ifndef CONFIG_USER_ONLY
+static MachineState * get_ms(void)
+{
+    return MACHINE(qdev_get_machine());
+}
+#endif
+
+int qemu_plugin_n_vcpus(void)
+{
+#ifdef CONFIG_USER_ONLY
+    return -1;
+#else
+    return get_ms()->smp.cpus;
+#endif
+}
+
+int qemu_plugin_n_max_vcpus(void)
+{
+#ifdef CONFIG_USER_ONLY
+    return -1;
+#else
+    return get_ms()->smp.max_cpus;
+#endif
+}
-- 
2.20.1



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

* [Qemu-devel] [PATCH  v4 16/54] queue: add QTAILQ_REMOVE_SEVERAL
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (14 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 15/54] plugin: add implementation of the api Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 16:16   ` Richard Henderson
  2019-08-01 16:16   ` Richard Henderson
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 17/54] cputlb: document get_page_addr_code Alex Bennée
                   ` (40 subsequent siblings)
  56 siblings, 2 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: bobby.prani, cota, Alex Bennée, aaron

From: "Emilio G. Cota" <cota@braap.org>

This is faster than removing elements one by one.

Will gain a user soon.

Signed-off-by: Emilio G. Cota <cota@braap.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/qemu/queue.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/include/qemu/queue.h b/include/qemu/queue.h
index 0379bd8fdbb..66e834dad11 100644
--- a/include/qemu/queue.h
+++ b/include/qemu/queue.h
@@ -422,6 +422,16 @@ union {                                                                 \
         (elm)->field.tqe_circ.tql_prev = NULL;                          \
 } while (/*CONSTCOND*/0)
 
+/* remove @left, @right and all elements in between from @head */
+#define QTAILQ_REMOVE_SEVERAL(head, left, right, field) do {            \
+        if (((right)->field.tqe_next) != NULL)                          \
+            (right)->field.tqe_next->field.tqe_circ.tql_prev =          \
+                (left)->field.tqe_circ.tql_prev;                        \
+        else                                                            \
+            (head)->tqh_circ.tql_prev = (left)->field.tqe_circ.tql_prev; \
+        (left)->field.tqe_circ.tql_prev->tql_next = (right)->field.tqe_next; \
+    } while (/*CONSTCOND*/0)
+
 #define QTAILQ_FOREACH(var, head, field)                                \
         for ((var) = ((head)->tqh_first);                               \
                 (var);                                                  \
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 17/54] cputlb: document get_page_addr_code
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (15 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 16/54] queue: add QTAILQ_REMOVE_SEVERAL Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 17:08   ` Richard Henderson
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 18/54] cputlb: introduce get_page_addr_code_hostp Alex Bennée
                   ` (39 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: aaron, cota, Paolo Bonzini, bobby.prani, Alex Bennée,
	Richard Henderson

From: "Emilio G. Cota" <cota@braap.org>

Suggested-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Emilio G. Cota <cota@braap.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 accel/tcg/cputlb.c      |  5 -----
 include/exec/exec-all.h | 24 +++++++++++++++++++++---
 2 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index bffdb251580..a01e04c5416 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1015,11 +1015,6 @@ static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index,
   victim_tlb_hit(env, mmu_idx, index, offsetof(CPUTLBEntry, TY), \
                  (ADDR) & TARGET_PAGE_MASK)
 
-/* NOTE: this function can trigger an exception */
-/* NOTE2: the returned address is not exactly the physical address: it
- * is actually a ram_addr_t (in system mode; the user mode emulation
- * version of this function returns a guest virtual address).
- */
 tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr)
 {
     uintptr_t mmu_idx = cpu_mmu_index(env, true);
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 16034ee651e..8b1c3d5b9db 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -480,7 +480,15 @@ void mmap_lock(void);
 void mmap_unlock(void);
 bool have_mmap_lock(void);
 
-static inline tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
+/**
+ * get_page_addr_code() - user-mode version
+ * @env: CPUArchState
+ * @addr: guest virtual address of guest code
+ *
+ * Returns @addr.
+ */
+static inline tb_page_addr_t get_page_addr_code(CPUArchState *env,
+                                                target_ulong addr)
 {
     return addr;
 }
@@ -488,8 +496,18 @@ static inline tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong
 static inline void mmap_lock(void) {}
 static inline void mmap_unlock(void) {}
 
-/* cputlb.c */
-tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr);
+/**
+ * get_page_addr_code() - full-system version
+ * @env: CPUArchState
+ * @addr: guest virtual address of guest code
+ *
+ * If we cannot translate and execute from the entire RAM page, or if
+ * the region is not backed by RAM, returns -1. Otherwise, returns the
+ * ram_addr_t corresponding to the guest code at @addr.
+ *
+ * Note: this function can trigger an exception.
+ */
+tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr);
 
 void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length);
 void tlb_set_dirty(CPUState *cpu, target_ulong vaddr);
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 18/54] cputlb: introduce get_page_addr_code_hostp
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (16 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 17/54] cputlb: document get_page_addr_code Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 17:10   ` Richard Henderson
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 19/54] tcg: add tcg_gen_st_ptr Alex Bennée
                   ` (38 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: aaron, cota, Paolo Bonzini, bobby.prani, Alex Bennée,
	Richard Henderson

From: "Emilio G. Cota" <cota@braap.org>

This will be used by plugins to get the host address
of instructions.

Signed-off-by: Emilio G. Cota <cota@braap.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 accel/tcg/cputlb.c      | 14 +++++++++++++-
 include/exec/exec-all.h | 38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index a01e04c5416..21ba71ea9dd 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1015,7 +1015,8 @@ static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index,
   victim_tlb_hit(env, mmu_idx, index, offsetof(CPUTLBEntry, TY), \
                  (ADDR) & TARGET_PAGE_MASK)
 
-tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr)
+tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, target_ulong addr,
+                                        void **hostp)
 {
     uintptr_t mmu_idx = cpu_mmu_index(env, true);
     uintptr_t index = tlb_index(env, mmu_idx, addr);
@@ -1040,13 +1041,24 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr)
          *    than a target page, so we must redo the MMU check every insn
          *  - TLB_MMIO: region is not backed by RAM
          */
+        if (hostp) {
+            *hostp = NULL;
+        }
         return -1;
     }
 
     p = (void *)((uintptr_t)addr + entry->addend);
+    if (hostp) {
+        *hostp = p;
+    }
     return qemu_ram_addr_from_host_nofail(p);
 }
 
+tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr)
+{
+    return get_page_addr_code_hostp(env, addr, NULL);
+}
+
 /* Probe for whether the specified guest write access is permitted.
  * If it is not permitted then an exception will be taken in the same
  * way as if this were a real write access (and we will not return).
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 8b1c3d5b9db..90045e77c1f 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -21,6 +21,7 @@
 #define EXEC_ALL_H
 
 #include "exec/tb-context.h"
+#include "exec/cpu_ldst.h"
 #include "sysemu/cpus.h"
 
 /* allow to see translation results - the slowdown should be negligible, so we leave it */
@@ -492,6 +493,26 @@ static inline tb_page_addr_t get_page_addr_code(CPUArchState *env,
 {
     return addr;
 }
+
+/**
+ * get_page_addr_code_hostp() - user-mode version
+ * @env: CPUArchState
+ * @addr: guest virtual address of guest code
+ *
+ * Returns @addr.
+ *
+ * If @hostp is non-NULL, sets *@hostp to the host address where @addr's content
+ * is kept.
+ */
+static inline tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env,
+                                                      target_ulong addr,
+                                                      void **hostp)
+{
+    if (hostp) {
+        *hostp = g2h(addr);
+    }
+    return addr;
+}
 #else
 static inline void mmap_lock(void) {}
 static inline void mmap_unlock(void) {}
@@ -509,6 +530,23 @@ static inline void mmap_unlock(void) {}
  */
 tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr);
 
+/**
+ * get_page_addr_code_hostp() - full-system version
+ * @env: CPUArchState
+ * @addr: guest virtual address of guest code
+ *
+ * See get_page_addr_code() (full-system version) for documentation on the
+ * return value.
+ *
+ * Sets *@hostp (when @hostp is non-NULL) as follows.
+ * If the return value is -1, sets *@hostp to NULL. Otherwise, sets *@hostp
+ * to the host address where @addr's content is kept.
+ *
+ * Note: this function can trigger an exception.
+ */
+tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, target_ulong addr,
+                                        void **hostp);
+
 void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length);
 void tlb_set_dirty(CPUState *cpu, target_ulong vaddr);
 
-- 
2.20.1



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

* [Qemu-devel] [PATCH  v4 19/54] tcg: add tcg_gen_st_ptr
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (17 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 18/54] cputlb: introduce get_page_addr_code_hostp Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 20/54] plugin-gen: add module for TCG-related code Alex Bennée
                   ` (37 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Richard Henderson, aaron, cota, bobby.prani, Alex Bennée,
	Richard Henderson

From: "Emilio G. Cota" <cota@braap.org>

Will gain a user soon.

Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tcg/tcg-op.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index 2d4dd5cd7de..698f3111eb2 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -1249,6 +1249,11 @@ static inline void tcg_gen_ld_ptr(TCGv_ptr r, TCGv_ptr a, intptr_t o)
     glue(tcg_gen_ld_,PTR)((NAT)r, a, o);
 }
 
+static inline void tcg_gen_st_ptr(TCGv_ptr r, TCGv_ptr a, intptr_t o)
+{
+    glue(tcg_gen_st_, PTR)((NAT)r, a, o);
+}
+
 static inline void tcg_gen_discard_ptr(TCGv_ptr a)
 {
     glue(tcg_gen_discard_,PTR)((NAT)a);
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 20/54] plugin-gen: add module for TCG-related code
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (18 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 19/54] tcg: add tcg_gen_st_ptr Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 21/54] atomic_template: fix indentation in GEN_ATOMIC_HELPER Alex Bennée
                   ` (36 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: aaron, cota, Paolo Bonzini, bobby.prani, Alex Bennée,
	Richard Henderson

From: "Emilio G. Cota" <cota@braap.org>

We first inject empty instrumentation from translator_loop.
After translation, we go through the plugins to see what
they want to register for, filling in the empty instrumentation.
If if turns out that some instrumentation remains unused, we
remove it.

This approach supports the following features:

- Inlining TCG code for simple operations. Note that we do not
  export TCG ops to plugins. Instead, we give them a C API to
  insert inlined ops. So far we only support adding an immediate
  to a u64, e.g. to count events.

- "Direct" callbacks. These are callbacks that do not go via
  a helper. Instead, the helper is defined at run-time, so that
  the plugin code is directly called from TCG. This makes direct
  callbacks as efficient as possible; they are therefore used
  for very frequent events, e.g. memory callbacks.

- Passing the host address to memory callbacks. Most of this
  is implemented in a later patch though.

- Instrumentation of memory accesses performed from helpers.
  See the corresponding comment, as well as a later patch.

Signed-off-by: Emilio G. Cota <cota@braap.org>
[AJB: add alloc_tcg_plugin_context, use glib, rm hwaddr]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v3
  - introduce alloc_tcg_plugin_context
  - allocate GPtrArray for tracking insns
v4
  - remove hwaddr variants of callbacks
  - pass full 32bit meminfo
  - remove now unused code
  - move plugin_gen_from into .c file
---
 accel/tcg/Makefile.objs     |   1 +
 accel/tcg/plugin-gen.c      | 977 ++++++++++++++++++++++++++++++++++++
 accel/tcg/plugin-helpers.h  |   5 +
 include/exec/helper-gen.h   |   1 +
 include/exec/helper-proto.h |   1 +
 include/exec/helper-tcg.h   |   1 +
 include/exec/plugin-gen.h   |  57 +++
 tcg/tcg-op.h                |  11 +
 tcg/tcg-opc.h               |   3 +
 tcg/tcg.c                   |  22 +
 tcg/tcg.h                   |  20 +
 11 files changed, 1099 insertions(+)
 create mode 100644 accel/tcg/plugin-gen.c
 create mode 100644 accel/tcg/plugin-helpers.h
 create mode 100644 include/exec/plugin-gen.h

diff --git a/accel/tcg/Makefile.objs b/accel/tcg/Makefile.objs
index d381a02f347..a92f2c454b9 100644
--- a/accel/tcg/Makefile.objs
+++ b/accel/tcg/Makefile.objs
@@ -6,3 +6,4 @@ obj-y += translator.o
 
 obj-$(CONFIG_USER_ONLY) += user-exec.o
 obj-$(call lnot,$(CONFIG_SOFTMMU)) += user-exec-stub.o
+obj-$(CONFIG_PLUGIN) += plugin-gen.o
diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
new file mode 100644
index 00000000000..f93ee85d83a
--- /dev/null
+++ b/accel/tcg/plugin-gen.c
@@ -0,0 +1,977 @@
+/*
+ * plugin-gen.c - TCG-related bits of plugin infrastructure
+ *
+ * Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
+ * License: GNU GPL, version 2 or later.
+ *   See the COPYING file in the top-level directory.
+ *
+ * We support instrumentation at an instruction granularity. That is,
+ * if a plugin wants to instrument the memory accesses performed by a
+ * particular instruction, it can just do that instead of instrumenting
+ * all memory accesses. Thus, in order to do this we first have to
+ * translate a TB, so that plugins can decide what/where to instrument.
+ *
+ * Injecting the desired instrumentation could be done with a second
+ * translation pass that combined the instrumentation requests, but that
+ * would be ugly and inefficient since we would decode the guest code twice.
+ * Instead, during TB translation we add "empty" instrumentation calls for all
+ * possible instrumentation events, and then once we collect the instrumentation
+ * requests from plugins, we either "fill in" those empty events or remove them
+ * if they have no requests.
+ *
+ * When "filling in" an event we first copy the empty callback's TCG ops. This
+ * might seem unnecessary, but it is done to support an arbitrary number
+ * of callbacks per event. Take for example a regular instruction callback.
+ * We first generate a callback to an empty helper function. Then, if two
+ * plugins register one callback each for this instruction, we make two copies
+ * of the TCG ops generated for the empty callback, substituting the function
+ * pointer that points to the empty helper function with the plugins' desired
+ * callback functions. After that we remove the empty callback's ops.
+ *
+ * Note that the location in TCGOp.args[] of the pointer to a helper function
+ * varies across different guest and host architectures. Instead of duplicating
+ * the logic that figures this out, we rely on the fact that the empty
+ * callbacks point to empty functions that are unique pointers in the program.
+ * Thus, to find the right location we just have to look for a match in
+ * TCGOp.args[]. This is the main reason why we first copy an empty callback's
+ * TCG ops and then fill them in; regardless of whether we have one or many
+ * callbacks for that event, the logic to add all of them is the same.
+ *
+ * When generating more than one callback per event, we make a small
+ * optimization to avoid generating redundant operations. For instance, for the
+ * second and all subsequent callbacks of an event, we do not need to reload the
+ * CPU's index into a TCG temp, since the first callback did it already.
+ */
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "tcg/tcg.h"
+#include "tcg/tcg-op.h"
+#include "trace/mem.h"
+#include "exec/exec-all.h"
+#include "exec/plugin-gen.h"
+#include "exec/translator.h"
+
+#ifdef CONFIG_SOFTMMU
+# define CONFIG_SOFTMMU_GATE 1
+#else
+# define CONFIG_SOFTMMU_GATE 0
+#endif
+
+/*
+ * plugin_cb_start TCG op args[]:
+ * 0: enum plugin_gen_from
+ * 1: enum plugin_gen_cb
+ * 2: set to 1 for mem callback that is a write, 0 otherwise.
+ */
+
+enum plugin_gen_from {
+    PLUGIN_GEN_FROM_TB,
+    PLUGIN_GEN_FROM_INSN,
+    PLUGIN_GEN_FROM_MEM,
+    PLUGIN_GEN_AFTER_INSN,
+    PLUGIN_GEN_N_FROMS,
+};
+
+enum plugin_gen_cb {
+    PLUGIN_GEN_CB_UDATA,
+    PLUGIN_GEN_CB_INLINE,
+    PLUGIN_GEN_CB_MEM,
+    PLUGIN_GEN_ENABLE_MEM_HELPER,
+    PLUGIN_GEN_DISABLE_MEM_HELPER,
+    PLUGIN_GEN_N_CBS,
+};
+
+/*
+ * These helpers are stubs that get dynamically switched out for calls
+ * direct to the plugin if they are subscribed to.
+ */
+void HELPER(plugin_vcpu_udata_cb)(uint32_t cpu_index, void *udata)
+{ }
+
+void HELPER(plugin_vcpu_mem_cb)(unsigned int vcpu_index,
+                                qemu_plugin_meminfo_t info, uint64_t vaddr,
+                                void *userdata)
+{ }
+
+static void do_gen_mem_cb(TCGv vaddr, uint32_t info)
+{
+    TCGv_i32 cpu_index = tcg_temp_new_i32();
+    TCGv_i32 meminfo = tcg_const_i32(info);
+    TCGv_i64 vaddr64 = tcg_temp_new_i64();
+    TCGv_ptr udata = tcg_const_ptr(NULL);
+
+    tcg_gen_ld_i32(cpu_index, cpu_env,
+                   -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
+    tcg_gen_extu_tl_i64(vaddr64, vaddr);
+
+    gen_helper_plugin_vcpu_mem_cb(cpu_index, meminfo, vaddr64, udata);
+
+    tcg_temp_free_ptr(udata);
+    tcg_temp_free_i64(vaddr64);
+    tcg_temp_free_i32(meminfo);
+    tcg_temp_free_i32(cpu_index);
+}
+
+static void gen_empty_udata_cb(void)
+{
+    TCGv_i32 cpu_index = tcg_temp_new_i32();
+    TCGv_ptr udata = tcg_const_ptr(NULL); /* will be overwritten later */
+
+    tcg_gen_ld_i32(cpu_index, cpu_env,
+                   -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
+    gen_helper_plugin_vcpu_udata_cb(cpu_index, udata);
+
+    tcg_temp_free_ptr(udata);
+    tcg_temp_free_i32(cpu_index);
+}
+
+/*
+ * For now we only support addi_i64.
+ * When we support more ops, we can generate one empty inline cb for each.
+ */
+static void gen_empty_inline_cb(void)
+{
+    TCGv_i64 val = tcg_temp_new_i64();
+    TCGv_ptr ptr = tcg_const_ptr(NULL); /* overwritten later */
+
+    tcg_gen_ld_i64(val, ptr, 0);
+    /* pass an immediate != 0 so that it doesn't get optimized away */
+    tcg_gen_addi_i64(val, val, 0xdeadface);
+    tcg_gen_st_i64(val, ptr, 0);
+    tcg_temp_free_ptr(ptr);
+    tcg_temp_free_i64(val);
+}
+
+static void gen_empty_mem_cb(TCGv addr, uint32_t info)
+{
+    do_gen_mem_cb(addr, info);
+}
+
+/*
+ * Share the same function for enable/disable. When enabling, the NULL
+ * pointer will be overwritten later.
+ */
+static void gen_empty_mem_helper(void)
+{
+    TCGv_ptr ptr;
+
+    ptr = tcg_const_ptr(NULL);
+    tcg_gen_st_ptr(ptr, cpu_env, offsetof(CPUState, plugin_mem_cbs));
+    tcg_temp_free_ptr(ptr);
+}
+
+static inline
+void gen_plugin_cb_start(enum plugin_gen_from from,
+                         enum plugin_gen_cb type, unsigned wr)
+{
+    TCGOp *op;
+
+    tcg_gen_plugin_cb_start(from, type, wr);
+    op = tcg_last_op();
+    QSIMPLEQ_INSERT_TAIL(&tcg_ctx->plugin_ops, op, plugin_link);
+}
+
+static void gen_wrapped(enum plugin_gen_from from,
+                        enum plugin_gen_cb type, void (*func)(void))
+{
+    gen_plugin_cb_start(from, type, 0);
+    func();
+    tcg_gen_plugin_cb_end();
+}
+
+static inline void plugin_gen_empty_callback(enum plugin_gen_from from)
+{
+    switch (from) {
+    case PLUGIN_GEN_AFTER_INSN:
+        gen_wrapped(from, PLUGIN_GEN_DISABLE_MEM_HELPER,
+                    gen_empty_mem_helper);
+        break;
+    case PLUGIN_GEN_FROM_INSN:
+        /*
+         * Note: plugin_gen_inject() relies on ENABLE_MEM_HELPER being
+         * the first callback of an instruction
+         */
+        gen_wrapped(from, PLUGIN_GEN_ENABLE_MEM_HELPER,
+                    gen_empty_mem_helper);
+        /* fall through */
+    case PLUGIN_GEN_FROM_TB:
+        gen_wrapped(from, PLUGIN_GEN_CB_UDATA, gen_empty_udata_cb);
+        gen_wrapped(from, PLUGIN_GEN_CB_INLINE, gen_empty_inline_cb);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+union mem_gen_fn {
+    void (*mem_fn)(TCGv, uint32_t);
+    void (*inline_fn)(void);
+};
+
+static void gen_mem_wrapped(enum plugin_gen_cb type,
+                            const union mem_gen_fn *f, TCGv addr,
+                            uint32_t info, bool is_mem)
+{
+    int wr = !!(info & TRACE_MEM_ST);
+
+    gen_plugin_cb_start(PLUGIN_GEN_FROM_MEM, type, wr);
+    if (is_mem) {
+        f->mem_fn(addr, info);
+    } else {
+        f->inline_fn();
+    }
+    tcg_gen_plugin_cb_end();
+}
+
+void plugin_gen_empty_mem_callback(TCGv addr, uint32_t info)
+{
+    union mem_gen_fn fn;
+
+    fn.mem_fn = gen_empty_mem_cb;
+    gen_mem_wrapped(PLUGIN_GEN_CB_MEM, &fn, addr, info, true);
+
+    fn.inline_fn = gen_empty_inline_cb;
+    gen_mem_wrapped(PLUGIN_GEN_CB_INLINE, &fn, 0, info, false);
+}
+
+static TCGOp *find_op(TCGOp *op, TCGOpcode opc)
+{
+    while (op) {
+        if (op->opc == opc) {
+            return op;
+        }
+        op = QTAILQ_NEXT(op, link);
+    }
+    return NULL;
+}
+
+static TCGOp *rm_ops_range(TCGOp *begin, TCGOp *end)
+{
+    TCGOp *ret = QTAILQ_NEXT(end, link);
+
+    QTAILQ_REMOVE_SEVERAL(&tcg_ctx->ops, begin, end, link);
+    return ret;
+}
+
+/* remove all ops until (and including) plugin_cb_end */
+static TCGOp *rm_ops(TCGOp *op)
+{
+    TCGOp *end_op = find_op(op, INDEX_op_plugin_cb_end);
+
+    tcg_debug_assert(end_op);
+    return rm_ops_range(op, end_op);
+}
+
+static TCGOp *copy_op_nocheck(TCGOp **begin_op, TCGOp *op)
+{
+    *begin_op = QTAILQ_NEXT(*begin_op, link);
+    tcg_debug_assert(*begin_op);
+    op = tcg_op_insert_after(tcg_ctx, op, (*begin_op)->opc);
+    memcpy(op->args, (*begin_op)->args, sizeof(op->args));
+    return op;
+}
+
+static TCGOp *copy_op(TCGOp **begin_op, TCGOp *op, TCGOpcode opc)
+{
+    op = copy_op_nocheck(begin_op, op);
+    tcg_debug_assert((*begin_op)->opc == opc);
+    return op;
+}
+
+static TCGOp *copy_extu_i32_i64(TCGOp **begin_op, TCGOp *op)
+{
+    if (TCG_TARGET_REG_BITS == 32) {
+        /* mov_i32 */
+        op = copy_op(begin_op, op, INDEX_op_mov_i32);
+        /* movi_i32 */
+        op = copy_op(begin_op, op, INDEX_op_movi_i32);
+    } else {
+        /* extu_i32_i64 */
+        op = copy_op(begin_op, op, INDEX_op_extu_i32_i64);
+    }
+    return op;
+}
+
+static TCGOp *copy_mov_i64(TCGOp **begin_op, TCGOp *op)
+{
+    if (TCG_TARGET_REG_BITS == 32) {
+        /* 2x mov_i32 */
+        op = copy_op(begin_op, op, INDEX_op_mov_i32);
+        op = copy_op(begin_op, op, INDEX_op_mov_i32);
+    } else {
+        /* mov_i64 */
+        op = copy_op(begin_op, op, INDEX_op_mov_i64);
+    }
+    return op;
+}
+
+static TCGOp *copy_movi_i64(TCGOp **begin_op, TCGOp *op, uint64_t v)
+{
+    if (TCG_TARGET_REG_BITS == 32) {
+        /* 2x movi_i32 */
+        op = copy_op(begin_op, op, INDEX_op_movi_i32);
+        op->args[1] = v;
+
+        op = copy_op(begin_op, op, INDEX_op_movi_i32);
+        op->args[1] = v >> 32;
+    } else {
+        /* movi_i64 */
+        op = copy_op(begin_op, op, INDEX_op_movi_i64);
+        op->args[1] = v;
+    }
+    return op;
+}
+
+static TCGOp *copy_const_ptr(TCGOp **begin_op, TCGOp *op, void *ptr)
+{
+    if (UINTPTR_MAX == UINT32_MAX) {
+        /* movi_i32 */
+        op = copy_op(begin_op, op, INDEX_op_movi_i32);
+        op->args[1] = (uintptr_t)ptr;
+    } else {
+        /* movi_i64 */
+        op = copy_movi_i64(begin_op, op, (uint64_t)(uintptr_t)ptr);
+    }
+    return op;
+}
+
+static TCGOp *copy_const_i64(TCGOp **begin_op, TCGOp *op, uint64_t v)
+{
+    return copy_movi_i64(begin_op, op, v);
+}
+
+static TCGOp *copy_extu_tl_i64(TCGOp **begin_op, TCGOp *op)
+{
+    if (TARGET_LONG_BITS == 32) {
+        /* extu_i32_i64 */
+        op = copy_extu_i32_i64(begin_op, op);
+    } else {
+        /* mov_i64 */
+        op = copy_mov_i64(begin_op, op);
+    }
+    return op;
+}
+
+static TCGOp *copy_ld_i64(TCGOp **begin_op, TCGOp *op)
+{
+    if (TCG_TARGET_REG_BITS == 32) {
+        /* 2x ld_i32 */
+        op = copy_op(begin_op, op, INDEX_op_ld_i32);
+        op = copy_op(begin_op, op, INDEX_op_ld_i32);
+    } else {
+        /* ld_i64 */
+        op = copy_op(begin_op, op, INDEX_op_ld_i64);
+    }
+    return op;
+}
+
+#if 0 /* XXX: no longer needed? */
+static TCGOp *copy_ld_ptr(TCGOp **begin_op, TCGOp *op)
+{
+    if (UINTPTR_MAX == UINT32_MAX) {
+        /* ld_i32 */
+        op = copy_op(begin_op, op, INDEX_op_ld_i32);
+    } else {
+        /* ld_i64 */
+        op = copy_ld_i64(begin_op, op);
+    }
+    return op;
+}
+
+static TCGOp *skip_ld_i64(TCGOp *begin_op)
+{
+    TCGOp *op;
+
+    if (TCG_TARGET_REG_BITS == 32) {
+        /* 2x ld_i32 */
+        op = QTAILQ_NEXT(begin_op, link);
+        tcg_debug_assert(op->opc == INDEX_op_ld_i32);
+        op = QTAILQ_NEXT(op, link);
+        tcg_debug_assert(op->opc == INDEX_op_ld_i32);
+    } else {
+        /* ld_i64 */
+        op = QTAILQ_NEXT(begin_op, link);
+        tcg_debug_assert(op->opc == INDEX_op_ld_i64);
+    }
+    return op;
+}
+
+static TCGOp *skip_ld_ptr(TCGOp *begin_op)
+{
+    TCGOp *op;
+
+    if (UINTPTR_MAX == UINT32_MAX) {
+        /* ld_i32 */
+        op = QTAILQ_NEXT(begin_op, link);
+        tcg_debug_assert(op->opc == INDEX_op_ld_i32);
+    } else {
+        /* ld_i64 */
+        op = skip_ld_i64(begin_op);
+    }
+    return op;
+}
+#endif
+
+static TCGOp *copy_st_i64(TCGOp **begin_op, TCGOp *op)
+{
+    if (TCG_TARGET_REG_BITS == 32) {
+        /* 2x st_i32 */
+        op = copy_op(begin_op, op, INDEX_op_st_i32);
+        op = copy_op(begin_op, op, INDEX_op_st_i32);
+    } else {
+        /* st_i64 */
+        op = copy_op(begin_op, op, INDEX_op_st_i64);
+    }
+    return op;
+}
+
+static TCGOp *copy_add_i64(TCGOp **begin_op, TCGOp *op)
+{
+    if (TCG_TARGET_REG_BITS == 32) {
+        /* all 32-bit backends must implement add2_i32 */
+        g_assert(TCG_TARGET_HAS_add2_i32);
+        op = copy_op(begin_op, op, INDEX_op_add2_i32);
+    } else {
+        op = copy_op(begin_op, op, INDEX_op_add_i64);
+    }
+    return op;
+}
+
+static TCGOp *copy_st_ptr(TCGOp **begin_op, TCGOp *op)
+{
+    if (UINTPTR_MAX == UINT32_MAX) {
+        /* st_i32 */
+        op = copy_op(begin_op, op, INDEX_op_st_i32);
+    } else {
+        /* st_i64 */
+        op = copy_st_i64(begin_op, op);
+    }
+    return op;
+}
+
+static TCGOp *copy_call(TCGOp **begin_op, TCGOp *op, void *empty_func,
+                        void *func, unsigned tcg_flags, int *cb_idx)
+{
+    /* copy all ops until the call */
+    do {
+        op = copy_op_nocheck(begin_op, op);
+    } while (op->opc != INDEX_op_call);
+
+    /* fill in the op call */
+    op->param1 = (*begin_op)->param1;
+    op->param2 = (*begin_op)->param2;
+    tcg_debug_assert(op->life == 0);
+    if (*cb_idx == -1) {
+        int i;
+
+        /*
+         * Instead of working out the position of the callback in args[], just
+         * look for @empty_func, since it should be a unique pointer.
+         */
+        for (i = 0; i < MAX_OPC_PARAM_ARGS; i++) {
+            if ((uintptr_t)(*begin_op)->args[i] == (uintptr_t)empty_func) {
+                *cb_idx = i;
+                break;
+            }
+        }
+        tcg_debug_assert(i < MAX_OPC_PARAM_ARGS);
+    }
+    op->args[*cb_idx] = (uintptr_t)func;
+    op->args[*cb_idx + 1] = tcg_flags;
+
+    return op;
+}
+
+static TCGOp *append_udata_cb(const struct qemu_plugin_dyn_cb *cb,
+                              TCGOp *begin_op, TCGOp *op, int *cb_idx)
+{
+    /* const_ptr */
+    op = copy_const_ptr(&begin_op, op, cb->userp);
+
+    /* copy the ld_i32, but note that we only have to copy it once */
+    begin_op = QTAILQ_NEXT(begin_op, link);
+    tcg_debug_assert(begin_op && begin_op->opc == INDEX_op_ld_i32);
+    if (*cb_idx == -1) {
+        op = tcg_op_insert_after(tcg_ctx, op, INDEX_op_ld_i32);
+        memcpy(op->args, begin_op->args, sizeof(op->args));
+    }
+
+    /* call */
+    op = copy_call(&begin_op, op, HELPER(plugin_vcpu_udata_cb),
+                   cb->f.vcpu_udata, cb->tcg_flags, cb_idx);
+
+    return op;
+}
+
+static TCGOp *append_inline_cb(const struct qemu_plugin_dyn_cb *cb,
+                               TCGOp *begin_op, TCGOp *op,
+                               int *unused)
+{
+    /* const_ptr */
+    op = copy_const_ptr(&begin_op, op, cb->userp);
+
+    /* ld_i64 */
+    op = copy_ld_i64(&begin_op, op);
+
+    /* const_i64 */
+    op = copy_const_i64(&begin_op, op, cb->inline_insn.imm);
+
+    /* add_i64 */
+    op = copy_add_i64(&begin_op, op);
+
+    /* st_i64 */
+    op = copy_st_i64(&begin_op, op);
+
+    return op;
+}
+
+static TCGOp *append_mem_cb(const struct qemu_plugin_dyn_cb *cb,
+                            TCGOp *begin_op, TCGOp *op, int *cb_idx)
+{
+    enum plugin_gen_cb type = begin_op->args[1];
+
+    tcg_debug_assert(type == PLUGIN_GEN_CB_MEM);
+
+    /* const_i32 == movi_i32 ("info", so it remains as is) */
+    op = copy_op(&begin_op, op, INDEX_op_movi_i32);
+
+    /* const_ptr */
+    op = copy_const_ptr(&begin_op, op, cb->userp);
+
+    /* copy the ld_i32, but note that we only have to copy it once */
+    begin_op = QTAILQ_NEXT(begin_op, link);
+    tcg_debug_assert(begin_op && begin_op->opc == INDEX_op_ld_i32);
+    if (*cb_idx == -1) {
+        op = tcg_op_insert_after(tcg_ctx, op, INDEX_op_ld_i32);
+        memcpy(op->args, begin_op->args, sizeof(op->args));
+    }
+
+    /* extu_tl_i64 */
+    op = copy_extu_tl_i64(&begin_op, op);
+
+    if (type == PLUGIN_GEN_CB_MEM) {
+        /* call */
+        op = copy_call(&begin_op, op, HELPER(plugin_vcpu_mem_cb),
+                       cb->f.vcpu_udata, cb->tcg_flags, cb_idx);
+    }
+
+    return op;
+}
+
+typedef TCGOp *(*inject_fn)(const struct qemu_plugin_dyn_cb *cb,
+                            TCGOp *begin_op, TCGOp *op, int *intp);
+typedef bool (*op_ok_fn)(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb);
+
+static bool op_ok(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb)
+{
+    return true;
+}
+
+static bool op_rw(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb)
+{
+    int w;
+
+    w = op->args[2];
+    return !!(cb->rw & (w + 1));
+}
+
+static inline
+void inject_cb_type(const GArray *cbs, TCGOp *begin_op, inject_fn inject,
+                    op_ok_fn ok)
+{
+    TCGOp *end_op;
+    TCGOp *op;
+    int cb_idx = -1;
+    int i;
+
+    if (!cbs || cbs->len == 0) {
+        rm_ops(begin_op);
+        return;
+    }
+
+    end_op = find_op(begin_op, INDEX_op_plugin_cb_end);
+    tcg_debug_assert(end_op);
+
+    op = end_op;
+    for (i = 0; i < cbs->len; i++) {
+        struct qemu_plugin_dyn_cb *cb =
+            &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
+
+        if (!ok(begin_op, cb)) {
+            continue;
+        }
+        op = inject(cb, begin_op, op, &cb_idx);
+    }
+    rm_ops_range(begin_op, end_op);
+}
+
+static void
+inject_udata_cb(const GArray *cbs, TCGOp *begin_op)
+{
+    inject_cb_type(cbs, begin_op, append_udata_cb, op_ok);
+}
+
+static void
+inject_inline_cb(const GArray *cbs, TCGOp *begin_op, op_ok_fn ok)
+{
+    inject_cb_type(cbs, begin_op, append_inline_cb, ok);
+}
+
+static void
+inject_mem_cb(const GArray *cbs, TCGOp *begin_op)
+{
+    inject_cb_type(cbs, begin_op, append_mem_cb, op_rw);
+}
+
+/* we could change the ops in place, but we can reuse more code by copying */
+static void inject_mem_helper(TCGOp *begin_op, GArray *arr)
+{
+    TCGOp *orig_op = begin_op;
+    TCGOp *end_op;
+    TCGOp *op;
+
+    end_op = find_op(begin_op, INDEX_op_plugin_cb_end);
+    tcg_debug_assert(end_op);
+
+    /* const ptr */
+    op = copy_const_ptr(&begin_op, end_op, arr);
+
+    /* st_ptr */
+    op = copy_st_ptr(&begin_op, op);
+
+    rm_ops_range(orig_op, end_op);
+}
+
+/*
+ * Tracking memory accesses performed from helpers requires extra work.
+ * If an instruction is emulated with helpers, we do two things:
+ * (1) copy the CB descriptors, and keep track of it so that they can be
+ * freed later on, and (2) point CPUState.plugin_mem_cbs to the descriptors, so
+ * that we can read them at run-time (i.e. when the helper executes).
+ * This run-time access is performed from qemu_plugin_vcpu_mem_cb.
+ *
+ * Note that plugin_gen_disable_mem_helpers undoes (2). Since it
+ * is possible that the code we generate after the instruction is
+ * dead, we also add checks before generating tb_exit etc.
+ */
+static void inject_mem_enable_helper(struct qemu_plugin_insn *plugin_insn,
+                                     TCGOp *begin_op)
+{
+    GArray *cbs[2];
+    GArray *arr;
+    size_t n_cbs, i;
+
+    cbs[0] = plugin_insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR];
+    cbs[1] = plugin_insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE];
+
+    n_cbs = 0;
+    for (i = 0; i < ARRAY_SIZE(cbs); i++) {
+        n_cbs += cbs[i]->len;
+    }
+
+    plugin_insn->mem_helper = plugin_insn->calls_helpers && n_cbs;
+    if (likely(!plugin_insn->mem_helper)) {
+        rm_ops(begin_op);
+        return;
+    }
+
+    arr = g_array_sized_new(false, false,
+                            sizeof(struct qemu_plugin_dyn_cb), n_cbs);
+
+    for (i = 0; i < ARRAY_SIZE(cbs); i++) {
+        g_array_append_vals(arr, cbs[i]->data, cbs[i]->len);
+    }
+
+    qemu_plugin_add_dyn_cb_arr(arr);
+    inject_mem_helper(begin_op, arr);
+}
+
+static void inject_mem_disable_helper(struct qemu_plugin_insn *plugin_insn,
+                                      TCGOp *begin_op)
+{
+    if (likely(!plugin_insn->mem_helper)) {
+        rm_ops(begin_op);
+        return;
+    }
+    inject_mem_helper(begin_op, NULL);
+}
+
+/* called before finishing a TB with exit_tb, goto_tb or goto_ptr */
+void plugin_gen_disable_mem_helpers(void)
+{
+    TCGv_ptr ptr;
+
+    if (likely(tcg_ctx->plugin_insn == NULL ||
+               !tcg_ctx->plugin_insn->mem_helper)) {
+        return;
+    }
+    ptr = tcg_const_ptr(NULL);
+    tcg_gen_st_ptr(ptr, cpu_env, offsetof(CPUState, plugin_mem_cbs));
+    tcg_temp_free_ptr(ptr);
+    tcg_ctx->plugin_insn->mem_helper = false;
+}
+
+static void plugin_gen_tb_udata(const struct qemu_plugin_tb *ptb,
+                                TCGOp *begin_op)
+{
+    inject_udata_cb(ptb->cbs[PLUGIN_CB_REGULAR], begin_op);
+}
+
+static void plugin_gen_tb_inline(const struct qemu_plugin_tb *ptb,
+                                 TCGOp *begin_op)
+{
+    inject_inline_cb(ptb->cbs[PLUGIN_CB_INLINE], begin_op, op_ok);
+}
+
+static void plugin_gen_insn_udata(const struct qemu_plugin_tb *ptb,
+                                  TCGOp *begin_op, int insn_idx)
+{
+    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
+
+    inject_udata_cb(insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR], begin_op);
+}
+
+static void plugin_gen_insn_inline(const struct qemu_plugin_tb *ptb,
+                                   TCGOp *begin_op, int insn_idx)
+{
+    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
+    inject_inline_cb(insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE],
+                     begin_op, op_ok);
+}
+
+static void plugin_gen_mem_regular(const struct qemu_plugin_tb *ptb,
+                                   TCGOp *begin_op, int insn_idx)
+{
+    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
+    inject_mem_cb(insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR], begin_op);
+}
+
+static void plugin_gen_mem_inline(const struct qemu_plugin_tb *ptb,
+                                  TCGOp *begin_op, int insn_idx)
+{
+    const GArray *cbs;
+    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
+
+    cbs = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE];
+    inject_inline_cb(cbs, begin_op, op_rw);
+}
+
+static void plugin_gen_enable_mem_helper(const struct qemu_plugin_tb *ptb,
+                                         TCGOp *begin_op, int insn_idx)
+{
+    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
+    inject_mem_enable_helper(insn, begin_op);
+}
+
+static void plugin_gen_disable_mem_helper(const struct qemu_plugin_tb *ptb,
+                                          TCGOp *begin_op, int insn_idx)
+{
+    struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
+    inject_mem_disable_helper(insn, begin_op);
+}
+
+static void plugin_inject_cb(const struct qemu_plugin_tb *ptb, TCGOp *begin_op,
+                             int insn_idx)
+{
+    enum plugin_gen_from from = begin_op->args[0];
+    enum plugin_gen_cb type = begin_op->args[1];
+
+    switch (from) {
+    case PLUGIN_GEN_FROM_TB:
+        switch (type) {
+        case PLUGIN_GEN_CB_UDATA:
+            plugin_gen_tb_udata(ptb, begin_op);
+            return;
+        case PLUGIN_GEN_CB_INLINE:
+            plugin_gen_tb_inline(ptb, begin_op);
+            return;
+        default:
+            g_assert_not_reached();
+        }
+    case PLUGIN_GEN_FROM_INSN:
+        switch (type) {
+        case PLUGIN_GEN_CB_UDATA:
+            plugin_gen_insn_udata(ptb, begin_op, insn_idx);
+            return;
+        case PLUGIN_GEN_CB_INLINE:
+            plugin_gen_insn_inline(ptb, begin_op, insn_idx);
+            return;
+        case PLUGIN_GEN_ENABLE_MEM_HELPER:
+            plugin_gen_enable_mem_helper(ptb, begin_op, insn_idx);
+            return;
+        default:
+            g_assert_not_reached();
+        }
+    case PLUGIN_GEN_FROM_MEM:
+        switch (type) {
+        case PLUGIN_GEN_CB_MEM:
+            plugin_gen_mem_regular(ptb, begin_op, insn_idx);
+            return;
+        case PLUGIN_GEN_CB_INLINE:
+            plugin_gen_mem_inline(ptb, begin_op, insn_idx);
+            return;
+        default:
+            g_assert_not_reached();
+        }
+    case PLUGIN_GEN_AFTER_INSN:
+        switch (type) {
+        case PLUGIN_GEN_DISABLE_MEM_HELPER:
+            plugin_gen_disable_mem_helper(ptb, begin_op, insn_idx);
+            return;
+        default:
+            g_assert_not_reached();
+        }
+    default:
+        g_assert_not_reached();
+    }
+}
+
+/* #define DEBUG_PLUGIN_GEN_OPS */
+static void pr_ops(void)
+{
+#ifdef DEBUG_PLUGIN_GEN_OPS
+    TCGOp *op;
+    int i = 0;
+
+    QTAILQ_FOREACH(op, &tcg_ctx->ops, link) {
+        const char *name = "";
+        const char *type = "";
+
+        if (op->opc == INDEX_op_plugin_cb_start) {
+            switch (op->args[0]) {
+            case PLUGIN_GEN_FROM_TB:
+                name = "tb";
+                break;
+            case PLUGIN_GEN_FROM_INSN:
+                name = "insn";
+                break;
+            case PLUGIN_GEN_FROM_MEM:
+                name = "mem";
+                break;
+            case PLUGIN_GEN_AFTER_INSN:
+                name = "after insn";
+                break;
+            default:
+                break;
+            }
+            switch (op->args[1]) {
+            case PLUGIN_GEN_CB_UDATA:
+                type = "udata";
+                break;
+            case PLUGIN_GEN_CB_INLINE:
+                type = "inline";
+                break;
+            case PLUGIN_GEN_CB_MEM:
+                type = "mem";
+                break;
+            case PLUGIN_GEN_ENABLE_MEM_HELPER:
+                type = "enable mem helper";
+                break;
+            case PLUGIN_GEN_DISABLE_MEM_HELPER:
+                type = "disable mem helper";
+                break;
+            default:
+                break;
+            }
+        }
+        printf("op[%2i]: %s %s %s\n", i, tcg_op_defs[op->opc].name, name, type);
+        i++;
+    }
+#endif
+}
+
+static void plugin_gen_inject(const struct qemu_plugin_tb *plugin_tb)
+{
+    TCGOp *op;
+    int insn_idx;
+
+    pr_ops();
+    insn_idx = -1;
+    QSIMPLEQ_FOREACH(op, &tcg_ctx->plugin_ops, plugin_link) {
+        enum plugin_gen_from from = op->args[0];
+        enum plugin_gen_cb type = op->args[1];
+
+        tcg_debug_assert(op->opc == INDEX_op_plugin_cb_start);
+        /* ENABLE_MEM_HELPER is the first callback of an instruction */
+        if (from == PLUGIN_GEN_FROM_INSN &&
+            type == PLUGIN_GEN_ENABLE_MEM_HELPER) {
+            insn_idx++;
+        }
+        plugin_inject_cb(plugin_tb, op, insn_idx);
+    }
+    pr_ops();
+}
+
+bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb)
+{
+    struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
+    bool ret = false;
+
+    if (test_bit(QEMU_PLUGIN_EV_VCPU_TB_TRANS, cpu->plugin_mask)) {
+        ret = true;
+
+        QSIMPLEQ_INIT(&tcg_ctx->plugin_ops);
+        ptb->vaddr = tb->pc;
+        ptb->vaddr2 = -1;
+        get_page_addr_code_hostp(cpu->env_ptr, tb->pc, &ptb->haddr1);
+        ptb->haddr2 = NULL;
+
+        plugin_gen_empty_callback(PLUGIN_GEN_FROM_TB);
+    }
+    return ret;
+}
+
+void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
+{
+    struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
+    struct qemu_plugin_insn *pinsn;
+
+    pinsn = qemu_plugin_tb_insn_get(ptb);
+    tcg_ctx->plugin_insn = pinsn;
+    pinsn->vaddr = db->pc_next;
+    plugin_gen_empty_callback(PLUGIN_GEN_FROM_INSN);
+
+    /*
+     * Detect page crossing to get the new host address.
+     * Note that we skip this when haddr1 == NULL, e.g. when we're
+     * fetching instructions from a region not backed by RAM.
+     */
+    if (likely(ptb->haddr1 != NULL && ptb->vaddr2 == -1) &&
+        unlikely((db->pc_next & TARGET_PAGE_MASK) !=
+                 (db->pc_first & TARGET_PAGE_MASK))) {
+        get_page_addr_code_hostp(cpu->env_ptr, db->pc_next,
+                                 &ptb->haddr2);
+        ptb->vaddr2 = db->pc_next;
+    }
+    if (likely(ptb->vaddr2 == -1)) {
+        pinsn->haddr = ptb->haddr1 + pinsn->vaddr - ptb->vaddr;
+    } else {
+        pinsn->haddr = ptb->haddr2 + pinsn->vaddr - ptb->vaddr2;
+    }
+}
+
+void plugin_gen_insn_end(void)
+{
+    plugin_gen_empty_callback(PLUGIN_GEN_AFTER_INSN);
+}
+
+void plugin_gen_tb_end(CPUState *cpu)
+{
+    struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
+    int i;
+
+    /* collect instrumentation requests */
+    qemu_plugin_tb_trans_cb(cpu, ptb);
+
+    /* inject the instrumentation at the appropriate places */
+    plugin_gen_inject(ptb);
+
+    /* clean up */
+    for (i = 0; i < PLUGIN_N_CB_SUBTYPES; i++) {
+        if (ptb->cbs[i]) {
+            g_array_set_size(ptb->cbs[i], 0);
+        }
+    }
+    ptb->n = 0;
+    tcg_ctx->plugin_insn = NULL;
+}
diff --git a/accel/tcg/plugin-helpers.h b/accel/tcg/plugin-helpers.h
new file mode 100644
index 00000000000..1916ee79206
--- /dev/null
+++ b/accel/tcg/plugin-helpers.h
@@ -0,0 +1,5 @@
+#ifdef CONFIG_PLUGIN
+/* Note: no TCG flags because those are overwritten later */
+DEF_HELPER_2(plugin_vcpu_udata_cb, void, i32, ptr)
+DEF_HELPER_4(plugin_vcpu_mem_cb, void, i32, i32, i64, ptr)
+#endif
diff --git a/include/exec/helper-gen.h b/include/exec/helper-gen.h
index 22381a17088..236ff405243 100644
--- a/include/exec/helper-gen.h
+++ b/include/exec/helper-gen.h
@@ -70,6 +70,7 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret)          \
 #include "trace/generated-helpers.h"
 #include "trace/generated-helpers-wrappers.h"
 #include "tcg-runtime.h"
+#include "plugin-helpers.h"
 
 #undef DEF_HELPER_FLAGS_0
 #undef DEF_HELPER_FLAGS_1
diff --git a/include/exec/helper-proto.h b/include/exec/helper-proto.h
index 74943edb13a..1c4ba9bc788 100644
--- a/include/exec/helper-proto.h
+++ b/include/exec/helper-proto.h
@@ -33,6 +33,7 @@ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
 #include "helper.h"
 #include "trace/generated-helpers.h"
 #include "tcg-runtime.h"
+#include "plugin-helpers.h"
 
 #undef DEF_HELPER_FLAGS_0
 #undef DEF_HELPER_FLAGS_1
diff --git a/include/exec/helper-tcg.h b/include/exec/helper-tcg.h
index 268e0f804be..573c2ce2e98 100644
--- a/include/exec/helper-tcg.h
+++ b/include/exec/helper-tcg.h
@@ -55,6 +55,7 @@
 #include "helper.h"
 #include "trace/generated-helpers.h"
 #include "tcg-runtime.h"
+#include "plugin-helpers.h"
 
 #undef str
 #undef DEF_HELPER_FLAGS_0
diff --git a/include/exec/plugin-gen.h b/include/exec/plugin-gen.h
new file mode 100644
index 00000000000..de519883b16
--- /dev/null
+++ b/include/exec/plugin-gen.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
+ *
+ * License: GNU GPL, version 2 or later.
+ *   See the COPYING file in the top-level directory.
+ *
+ * plugin-gen.h - TCG-dependent definitions for generating plugin code
+ *
+ * This header should be included only from plugin.c and C files that emit
+ * TCG code.
+ */
+#ifndef QEMU_PLUGIN_GEN_H
+#define QEMU_PLUGIN_GEN_H
+
+#include "qemu/plugin.h"
+#include "tcg/tcg.h"
+
+struct DisasContextBase;
+
+#ifdef CONFIG_PLUGIN
+
+bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb);
+void plugin_gen_tb_end(CPUState *cpu);
+void plugin_gen_insn_start(CPUState *cpu, const struct DisasContextBase *db);
+void plugin_gen_insn_end(void);
+
+void plugin_gen_disable_mem_helpers(void);
+void plugin_gen_empty_mem_callback(TCGv addr, uint32_t info);
+
+#else /* !CONFIG_PLUGIN */
+
+static inline
+bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb)
+{
+    return false;
+}
+
+static inline
+void plugin_gen_insn_start(CPUState *cpu, const struct DisasContextBase *db)
+{ }
+
+static inline void plugin_gen_insn_end(void)
+{ }
+
+static inline void plugin_gen_tb_end(CPUState *cpu)
+{ }
+
+static inline void plugin_gen_disable_mem_helpers(void)
+{ }
+
+static inline void plugin_gen_empty_mem_callback(TCGv addr, uint32_t info)
+{ }
+
+#endif /* CONFIG_PLUGIN */
+
+#endif /* QEMU_PLUGIN_GEN_H */
+
diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index 698f3111eb2..edf12de1f31 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -833,6 +833,17 @@ void tcg_gen_goto_tb(unsigned idx);
  */
 void tcg_gen_lookup_and_goto_ptr(void);
 
+static inline void tcg_gen_plugin_cb_start(unsigned from, unsigned type,
+                                           unsigned wr)
+{
+    tcg_gen_op3(INDEX_op_plugin_cb_start, from, type, wr);
+}
+
+static inline void tcg_gen_plugin_cb_end(void)
+{
+    tcg_emit_op(INDEX_op_plugin_cb_end);
+}
+
 #if TARGET_LONG_BITS == 32
 #define tcg_temp_new() tcg_temp_new_i32()
 #define tcg_global_reg_new tcg_global_reg_new_i32
diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h
index 242d608e6db..9288a049468 100644
--- a/tcg/tcg-opc.h
+++ b/tcg/tcg-opc.h
@@ -198,6 +198,9 @@ DEF(goto_tb, 0, 0, 1, TCG_OPF_BB_EXIT | TCG_OPF_BB_END)
 DEF(goto_ptr, 0, 1, 0,
     TCG_OPF_BB_EXIT | TCG_OPF_BB_END | IMPL(TCG_TARGET_HAS_goto_ptr))
 
+DEF(plugin_cb_start, 0, 0, 3, TCG_OPF_NOT_PRESENT)
+DEF(plugin_cb_end, 0, 0, 0, TCG_OPF_NOT_PRESENT)
+
 DEF(qemu_ld_i32, 1, TLADDR_ARGS, 1,
     TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
 DEF(qemu_st_i32, 0, TLADDR_ARGS + 1, 1,
diff --git a/tcg/tcg.c b/tcg/tcg.c
index be2c33c400c..516128dc21a 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -737,6 +737,15 @@ void tcg_region_init(void)
 #endif
 }
 
+static void alloc_tcg_plugin_context(TCGContext *s)
+{
+#ifdef CONFIG_PLUGIN
+    s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
+    s->plugin_tb->insns =
+        g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
+#endif
+}
+
 /*
  * All TCG threads except the parent (i.e. the one that called tcg_context_init
  * and registered the target's TCG globals) must register with this function
@@ -781,6 +790,10 @@ void tcg_register_thread(void)
     g_assert(n < ms->smp.max_cpus);
     atomic_set(&tcg_ctxs[n], s);
 
+    if (n > 0) {
+        alloc_tcg_plugin_context(s);
+    }
+
     tcg_ctx = s;
     qemu_mutex_lock(&region.lock);
     err = tcg_region_initial_alloc__locked(tcg_ctx);
@@ -977,6 +990,8 @@ void tcg_context_init(TCGContext *s)
         indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
     }
 
+    alloc_tcg_plugin_context(s);
+
     tcg_ctx = s;
     /*
      * In user-mode we simply share the init context among threads, since we
@@ -1682,6 +1697,13 @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args)
     flags = info->flags;
     sizemask = info->sizemask;
 
+#ifdef CONFIG_PLUGIN
+    /* detect non-plugin helpers */
+    if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) {
+        tcg_ctx->plugin_insn->calls_helpers = true;
+    }
+#endif
+
 #if defined(__sparc__) && !defined(__arch64__) \
     && !defined(CONFIG_TCG_INTERPRETER)
     /* We have 64-bit values in one register, but need to pass as two
diff --git a/tcg/tcg.h b/tcg/tcg.h
index b411e17a28f..2385e758e55 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -625,6 +625,9 @@ typedef struct TCGOp {
 
     /* Next and previous opcodes.  */
     QTAILQ_ENTRY(TCGOp) link;
+#ifdef CONFIG_PLUGIN
+    QSIMPLEQ_ENTRY(TCGOp) plugin_link;
+#endif
 
     /* Arguments for the opcode.  */
     TCGArg args[MAX_OPC_PARAM];
@@ -726,6 +729,23 @@ struct TCGContext {
 
     TCGLabel *exitreq_label;
 
+#ifdef CONFIG_PLUGIN
+    /*
+     * We keep one plugin_tb struct per TCGContext. Note that on every TB
+     * translation we clear but do not free its contents; this way we
+     * avoid a lot of malloc/free churn, since after a few TB's it's
+     * unlikely that we'll need to allocate either more instructions or more
+     * space for instructions (for variable-instruction-length ISAs).
+     */
+    struct qemu_plugin_tb *plugin_tb;
+
+    /* descriptor of the instruction being translated */
+    struct qemu_plugin_insn *plugin_insn;
+
+    /* list to quickly access the injected ops */
+    QSIMPLEQ_HEAD(, TCGOp) plugin_ops;
+#endif
+
     TCGTempSet free_temps[TCG_TYPE_COUNT * 2];
     TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */
 
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 21/54] atomic_template: fix indentation in GEN_ATOMIC_HELPER
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (19 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 20/54] plugin-gen: add module for TCG-related code Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 22/54] atomic_template: add inline trace/plugin helpers Alex Bennée
                   ` (35 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Richard Henderson, aaron, cota, Paolo Bonzini, bobby.prani,
	Alex Bennée, Richard Henderson

From: "Emilio G. Cota" <cota@braap.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 accel/tcg/atomic_template.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/accel/tcg/atomic_template.h b/accel/tcg/atomic_template.h
index 313a4c7ed97..53899bbbc21 100644
--- a/accel/tcg/atomic_template.h
+++ b/accel/tcg/atomic_template.h
@@ -284,7 +284,7 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
 
 #define GEN_ATOMIC_HELPER(X)                                        \
 ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
-                 ABI_TYPE val EXTRA_ARGS)                           \
+                        ABI_TYPE val EXTRA_ARGS)                    \
 {                                                                   \
     ATOMIC_MMU_DECLS;                                               \
     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                           \
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 22/54] atomic_template: add inline trace/plugin helpers
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (20 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 21/54] atomic_template: fix indentation in GEN_ATOMIC_HELPER Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 18:23   ` Richard Henderson
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 23/54] tcg: let plugins instrument virtual memory accesses Alex Bennée
                   ` (34 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Riku Voipio, aaron, cota, Paolo Bonzini, bobby.prani,
	Alex Bennée, Richard Henderson

From: "Emilio G. Cota" <cota@braap.org>

In preparation for plugin support.

Signed-off-by: Emilio G. Cota <cota@braap.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v4
  - move common stuff to atomic_common.inc.c
  - fix ups for widened uint16_t info
  - drop haddr in helpers
  - fix wide lines
---
 accel/tcg/atomic_common.inc.c | 50 +++++++++++++++++++
 accel/tcg/atomic_template.h   | 93 +++++++++++++++++++++--------------
 accel/tcg/cputlb.c            |  2 +
 accel/tcg/user-exec.c         |  2 +
 4 files changed, 111 insertions(+), 36 deletions(-)
 create mode 100644 accel/tcg/atomic_common.inc.c

diff --git a/accel/tcg/atomic_common.inc.c b/accel/tcg/atomic_common.inc.c
new file mode 100644
index 00000000000..a86098fb2de
--- /dev/null
+++ b/accel/tcg/atomic_common.inc.c
@@ -0,0 +1,50 @@
+/*
+ * Common Atomic Helper Functions
+ *
+ * This file should be included before the various instantiations of
+ * the atomic_template.h helpers.
+ *
+ * Copyright (c) 2019 Linaro
+ * Written by Alex Bennée <alex.bennee@linaro.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+static inline
+void atomic_trace_rmw_pre(CPUArchState *env, target_ulong addr, uint16_t info)
+{
+    CPUState *cpu = env_cpu(env);
+
+    trace_guest_mem_before_exec(cpu, addr, info);
+    trace_guest_mem_before_exec(cpu, addr, info | TRACE_MEM_ST);
+}
+
+static inline void
+atomic_trace_rmw_post(CPUArchState *env, target_ulong addr, uint16_t info)
+{
+}
+
+static inline
+void atomic_trace_ld_pre(CPUArchState *env, target_ulong addr, uint16_t info)
+{
+    trace_guest_mem_before_exec(env_cpu(env), addr, info);
+}
+
+static inline
+void atomic_trace_ld_post(CPUArchState *env, target_ulong addr, uint16_t info)
+{
+}
+
+static inline
+void atomic_trace_st_pre(CPUArchState *env, target_ulong addr, uint16_t info)
+{
+    trace_guest_mem_before_exec(env_cpu(env), addr, info);
+}
+
+static inline
+void atomic_trace_st_post(CPUArchState *env, target_ulong addr, uint16_t info)
+{
+}
diff --git a/accel/tcg/atomic_template.h b/accel/tcg/atomic_template.h
index 53899bbbc21..34f891d4a62 100644
--- a/accel/tcg/atomic_template.h
+++ b/accel/tcg/atomic_template.h
@@ -59,26 +59,6 @@
 # define ABI_TYPE  uint32_t
 #endif
 
-#define ATOMIC_TRACE_RMW do {                                           \
-        uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false, ATOMIC_MMU_IDX); \
-                                                                        \
-        trace_guest_mem_before_exec(env_cpu(env), addr, info);      \
-        trace_guest_mem_before_exec(env_cpu(env), addr,             \
-                                    info | TRACE_MEM_ST);               \
-    } while (0)
-
-#define ATOMIC_TRACE_LD do {                                            \
-        uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false, ATOMIC_MMU_IDX); \
-                                                                        \
-        trace_guest_mem_before_exec(env_cpu(env), addr, info);      \
-    } while (0)
-
-# define ATOMIC_TRACE_ST do {                                           \
-        uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, true, ATOMIC_MMU_IDX); \
-                                                                        \
-        trace_guest_mem_before_exec(env_cpu(env), addr, info);      \
-    } while (0)
-
 /* Define host-endian atomic operations.  Note that END is used within
    the ATOMIC_NAME macro, and redefined below.  */
 #if DATA_SIZE == 1
@@ -98,14 +78,17 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
     ATOMIC_MMU_DECLS;
     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
     DATA_TYPE ret;
+    uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false,
+                                                           ATOMIC_MMU_IDX);
 
-    ATOMIC_TRACE_RMW;
+    atomic_trace_rmw_pre(env, addr, info);
 #if DATA_SIZE == 16
     ret = atomic16_cmpxchg(haddr, cmpv, newv);
 #else
     ret = atomic_cmpxchg__nocheck(haddr, cmpv, newv);
 #endif
     ATOMIC_MMU_CLEANUP;
+    atomic_trace_rmw_post(env, addr, info);
     return ret;
 }
 
@@ -115,10 +98,13 @@ ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
 {
     ATOMIC_MMU_DECLS;
     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
+    uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false,
+                                                           ATOMIC_MMU_IDX);
 
-    ATOMIC_TRACE_LD;
+    atomic_trace_ld_pre(env, addr, info);
     val = atomic16_read(haddr);
     ATOMIC_MMU_CLEANUP;
+    atomic_trace_ld_post(env, addr, info);
     return val;
 }
 
@@ -127,10 +113,13 @@ void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
 {
     ATOMIC_MMU_DECLS;
     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
+    uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, true,
+                                                          ATOMIC_MMU_IDX);
 
-    ATOMIC_TRACE_ST;
+    atomic_trace_st_pre(env, addr, info);
     atomic16_set(haddr, val);
     ATOMIC_MMU_CLEANUP;
+    atomic_trace_st_post(env, addr, info);
 }
 #endif
 #else
@@ -140,10 +129,13 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
     ATOMIC_MMU_DECLS;
     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
     DATA_TYPE ret;
+    uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false,
+                                                          ATOMIC_MMU_IDX);
 
-    ATOMIC_TRACE_RMW;
+    atomic_trace_rmw_pre(env, addr, info);
     ret = atomic_xchg__nocheck(haddr, val);
     ATOMIC_MMU_CLEANUP;
+    atomic_trace_rmw_post(env, addr, info);
     return ret;
 }
 
@@ -154,10 +146,14 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
     ATOMIC_MMU_DECLS;                                               \
     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                           \
     DATA_TYPE ret;                                                  \
+    uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,   \
+                                                           false,   \
+                                                           ATOMIC_MMU_IDX); \
                                                                     \
-    ATOMIC_TRACE_RMW;                                               \
+    atomic_trace_rmw_pre(env, addr, info);                          \
     ret = atomic_##X(haddr, val);                                   \
     ATOMIC_MMU_CLEANUP;                                             \
+    atomic_trace_rmw_post(env, addr, info);                         \
     return ret;                                                     \
 }
 
@@ -186,8 +182,11 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
     ATOMIC_MMU_DECLS;                                               \
     XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                          \
     XDATA_TYPE cmp, old, new, val = xval;                           \
+    uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,   \
+                                                           false,   \
+                                                           ATOMIC_MMU_IDX); \
                                                                     \
-    ATOMIC_TRACE_RMW;                                               \
+    atomic_trace_rmw_pre(env, addr, info);                          \
     smp_mb();                                                       \
     cmp = atomic_read__nocheck(haddr);                              \
     do {                                                            \
@@ -195,6 +194,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
         cmp = atomic_cmpxchg__nocheck(haddr, old, new);             \
     } while (cmp != old);                                           \
     ATOMIC_MMU_CLEANUP;                                             \
+    atomic_trace_rmw_post(env, addr, info);                         \
     return RET;                                                     \
 }
 
@@ -232,14 +232,18 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
     ATOMIC_MMU_DECLS;
     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
     DATA_TYPE ret;
+    uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
+                                                           false,
+                                                           ATOMIC_MMU_IDX);
 
-    ATOMIC_TRACE_RMW;
+    atomic_trace_rmw_pre(env, addr, info);
 #if DATA_SIZE == 16
     ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
 #else
     ret = atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
 #endif
     ATOMIC_MMU_CLEANUP;
+    atomic_trace_rmw_post(env, addr, info);
     return BSWAP(ret);
 }
 
@@ -249,10 +253,14 @@ ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
 {
     ATOMIC_MMU_DECLS;
     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
+    uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
+                                                           false,
+                                                           ATOMIC_MMU_IDX);
 
-    ATOMIC_TRACE_LD;
+    atomic_trace_ld_pre(env, addr, info);
     val = atomic16_read(haddr);
     ATOMIC_MMU_CLEANUP;
+    atomic_trace_ld_post(env, addr, info);
     return BSWAP(val);
 }
 
@@ -261,11 +269,16 @@ void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
 {
     ATOMIC_MMU_DECLS;
     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
+    uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
+                                                           true,
+                                                           ATOMIC_MMU_IDX);
 
-    ATOMIC_TRACE_ST;
+    val = BSWAP(val);
+    atomic_trace_st_pre(env, addr, info);
     val = BSWAP(val);
     atomic16_set(haddr, val);
     ATOMIC_MMU_CLEANUP;
+    atomic_trace_st_post(env, addr, info);
 }
 #endif
 #else
@@ -275,10 +288,14 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
     ATOMIC_MMU_DECLS;
     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
     ABI_TYPE ret;
+    uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
+                                                           false,
+                                                           ATOMIC_MMU_IDX);
 
-    ATOMIC_TRACE_RMW;
+    atomic_trace_rmw_pre(env, addr, info);
     ret = atomic_xchg__nocheck(haddr, BSWAP(val));
     ATOMIC_MMU_CLEANUP;
+    atomic_trace_rmw_post(env, addr, info);
     return BSWAP(ret);
 }
 
@@ -289,10 +306,14 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
     ATOMIC_MMU_DECLS;                                               \
     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                           \
     DATA_TYPE ret;                                                  \
+    uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,   \
+                                                           false,   \
+                                                           ATOMIC_MMU_IDX); \
                                                                     \
-    ATOMIC_TRACE_RMW;                                               \
+    atomic_trace_rmw_pre(env, addr, info);                          \
     ret = atomic_##X(haddr, BSWAP(val));                            \
     ATOMIC_MMU_CLEANUP;                                             \
+    atomic_trace_rmw_post(env, addr, info);                         \
     return BSWAP(ret);                                              \
 }
 
@@ -319,8 +340,11 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
     ATOMIC_MMU_DECLS;                                               \
     XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                          \
     XDATA_TYPE ldo, ldn, old, new, val = xval;                      \
+    uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,   \
+                                                           false,   \
+                                                           ATOMIC_MMU_IDX); \
                                                                     \
-    ATOMIC_TRACE_RMW;                                               \
+    atomic_trace_rmw_pre(env, addr, info);                          \
     smp_mb();                                                       \
     ldn = atomic_read__nocheck(haddr);                              \
     do {                                                            \
@@ -328,6 +352,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
         ldn = atomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new));      \
     } while (ldo != ldn);                                           \
     ATOMIC_MMU_CLEANUP;                                             \
+    atomic_trace_rmw_post(env, addr, info);                         \
     return RET;                                                     \
 }
 
@@ -355,10 +380,6 @@ GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new)
 #undef MEND
 #endif /* DATA_SIZE > 1 */
 
-#undef ATOMIC_TRACE_ST
-#undef ATOMIC_TRACE_LD
-#undef ATOMIC_TRACE_RMW
-
 #undef BSWAP
 #undef ABI_TYPE
 #undef DATA_TYPE
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index 21ba71ea9dd..e4ac06041a2 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1701,6 +1701,8 @@ void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
     } while (0)
 #define ATOMIC_MMU_IDX oi
 
+#include "atomic_common.inc.c"
+
 #define DATA_SIZE 1
 #include "atomic_template.h"
 
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index bff1934cf1b..1c8aee943dc 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -724,6 +724,8 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
 #define ATOMIC_NAME(X)   HELPER(glue(glue(atomic_ ## X, SUFFIX), END))
 #define EXTRA_ARGS
 
+#include "atomic_common.inc.c"
+
 #define DATA_SIZE 1
 #include "atomic_template.h"
 
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 23/54] tcg: let plugins instrument virtual memory accesses
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (21 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 22/54] atomic_template: add inline trace/plugin helpers Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 18:29   ` Richard Henderson
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 24/54] plugins: implement helpers for resolving hwaddr Alex Bennée
                   ` (33 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: aaron, cota, Paolo Bonzini, bobby.prani, Alex Bennée,
	Richard Henderson

From: "Emilio G. Cota" <cota@braap.org>

To capture all memory accesses we need hook into all the various
helper functions that are involved in memory operations as well as the
injected inline helper calls. A later commit will allow us to resolve
the actual guest HW addresses by replaying the lookup.

Signed-off-by: Emilio G. Cota <cota@braap.org>
[AJB: drop haddr handling, just deal in vaddr]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v3
  - fixes for cpu_neg()
v4
  - rebase fixups, moved cpu_neg() fixes down the stack
  - drop haddr support - will be restored with later helper
  - reword commit
---
 accel/tcg/atomic_common.inc.c             |  4 +++
 accel/tcg/atomic_template.h               |  1 +
 accel/tcg/cpu-exec.c                      |  3 ++
 accel/tcg/cputlb.c                        | 14 ++++----
 include/exec/cpu-defs.h                   |  1 +
 include/exec/cpu_ldst_template.h          | 28 +++++++++-------
 include/exec/cpu_ldst_useronly_template.h | 29 ++++++++--------
 tcg/tcg-op.c                              | 40 ++++++++++++++++++-----
 tcg/tcg.h                                 |  1 +
 9 files changed, 79 insertions(+), 42 deletions(-)

diff --git a/accel/tcg/atomic_common.inc.c b/accel/tcg/atomic_common.inc.c
index a86098fb2de..344525b0bb3 100644
--- a/accel/tcg/atomic_common.inc.c
+++ b/accel/tcg/atomic_common.inc.c
@@ -25,6 +25,8 @@ void atomic_trace_rmw_pre(CPUArchState *env, target_ulong addr, uint16_t info)
 static inline void
 atomic_trace_rmw_post(CPUArchState *env, target_ulong addr, uint16_t info)
 {
+    qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info);
+    qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info | TRACE_MEM_ST);
 }
 
 static inline
@@ -36,6 +38,7 @@ void atomic_trace_ld_pre(CPUArchState *env, target_ulong addr, uint16_t info)
 static inline
 void atomic_trace_ld_post(CPUArchState *env, target_ulong addr, uint16_t info)
 {
+    qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info);
 }
 
 static inline
@@ -47,4 +50,5 @@ void atomic_trace_st_pre(CPUArchState *env, target_ulong addr, uint16_t info)
 static inline
 void atomic_trace_st_post(CPUArchState *env, target_ulong addr, uint16_t info)
 {
+    qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info);
 }
diff --git a/accel/tcg/atomic_template.h b/accel/tcg/atomic_template.h
index 34f891d4a62..4f209c8e18c 100644
--- a/accel/tcg/atomic_template.h
+++ b/accel/tcg/atomic_template.h
@@ -18,6 +18,7 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "qemu/plugin.h"
 #include "trace/mem.h"
 
 #if DATA_SIZE == 16
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index ab9dfd4f908..81be72a373d 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -269,6 +269,7 @@ void cpu_exec_step_atomic(CPUState *cpu)
             qemu_mutex_unlock_iothread();
         }
         assert_no_pages_locked();
+        qemu_plugin_disable_mem_helpers(cpu);
     }
 
     if (cpu_in_exclusive_context(cpu)) {
@@ -702,6 +703,8 @@ int cpu_exec(CPUState *cpu)
         if (qemu_mutex_iothread_locked()) {
             qemu_mutex_unlock_iothread();
         }
+        qemu_plugin_disable_mem_helpers(cpu);
+
         assert_no_pages_locked();
     }
 
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index e4ac06041a2..f7c0290639c 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -881,7 +881,7 @@ static void tlb_fill(CPUState *cpu, target_ulong addr, int size,
 
 static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
                          int mmu_idx, target_ulong addr, uintptr_t retaddr,
-                         MMUAccessType access_type, int size)
+                         TCGMemOp mo, MMUAccessType access_type, int size)
 {
     CPUState *cpu = env_cpu(env);
     hwaddr mr_offset;
@@ -925,7 +925,7 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
 
 static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
                       int mmu_idx, uint64_t val, target_ulong addr,
-                      uintptr_t retaddr, int size)
+                      uintptr_t retaddr, TCGMemOp mo, int size)
 {
     CPUState *cpu = env_cpu(env);
     hwaddr mr_offset;
@@ -1264,7 +1264,8 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
         offsetof(CPUTLBEntry, addr_code) : offsetof(CPUTLBEntry, addr_read);
     const MMUAccessType access_type =
         code_read ? MMU_INST_FETCH : MMU_DATA_LOAD;
-    unsigned a_bits = get_alignment_bits(get_memop(oi));
+    TCGMemOp mo = get_memop(oi);
+    unsigned a_bits = get_alignment_bits(mo);
     void *haddr;
     uint64_t res;
 
@@ -1313,7 +1314,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
         }
 
         res = io_readx(env, &env_tlb(env)->d[mmu_idx].iotlb[index],
-                       mmu_idx, addr, retaddr, access_type, size);
+                       mmu_idx, addr, retaddr, mo, access_type, size);
         return handle_bswap(res, size, big_endian);
     }
 
@@ -1513,7 +1514,8 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
     CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
     target_ulong tlb_addr = tlb_addr_write(entry);
     const size_t tlb_off = offsetof(CPUTLBEntry, addr_write);
-    unsigned a_bits = get_alignment_bits(get_memop(oi));
+    TCGMemOp mo = get_memop(oi);
+    unsigned a_bits = get_alignment_bits(mo);
     void *haddr;
 
     /* Handle CPU specific unaligned behaviour */
@@ -1562,7 +1564,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
 
         io_writex(env, &env_tlb(env)->d[mmu_idx].iotlb[index], mmu_idx,
                   handle_bswap(val, size, big_endian),
-                  addr, retaddr, size);
+                  addr, retaddr, mo, size);
         return;
     }
 
diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h
index 9bc713a70b2..31deca369ea 100644
--- a/include/exec/cpu-defs.h
+++ b/include/exec/cpu-defs.h
@@ -215,6 +215,7 @@ typedef struct CPUTLBCommon {
  * Since this is placed within CPUNegativeOffsetState, the smallest
  * negative offsets are at the end of the struct.
  */
+
 typedef struct CPUTLB {
     CPUTLBCommon c;
     CPUTLBDesc d[NB_MMU_MODES];
diff --git a/include/exec/cpu_ldst_template.h b/include/exec/cpu_ldst_template.h
index 5750a26b9ec..6f0d3407979 100644
--- a/include/exec/cpu_ldst_template.h
+++ b/include/exec/cpu_ldst_template.h
@@ -28,6 +28,7 @@
 #include "trace-root.h"
 #endif
 
+#include "qemu/plugin.h"
 #include "trace/mem.h"
 
 #if DATA_SIZE == 8
@@ -86,11 +87,9 @@ glue(glue(glue(cpu_ld, USUFFIX), MEMSUFFIX), _ra)(CPUArchState *env,
     target_ulong addr;
     int mmu_idx = CPU_MMU_INDEX;
     TCGMemOpIdx oi;
-
 #if !defined(SOFTMMU_CODE_ACCESS)
-    trace_guest_mem_before_exec(
-        env_cpu(env), ptr,
-        trace_mem_build_info(SHIFT, false, MO_TE, false, mmu_idx));
+    uint16_t meminfo = trace_mem_build_info(SHIFT, false, MO_TE, false, mmu_idx);
+    trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
 #endif
 
     addr = ptr;
@@ -104,6 +103,9 @@ glue(glue(glue(cpu_ld, USUFFIX), MEMSUFFIX), _ra)(CPUArchState *env,
         uintptr_t hostaddr = addr + entry->addend;
         res = glue(glue(ld, USUFFIX), _p)((uint8_t *)hostaddr);
     }
+#ifndef SOFTMMU_CODE_ACCESS
+    qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
+#endif
     return res;
 }
 
@@ -124,11 +126,9 @@ glue(glue(glue(cpu_lds, SUFFIX), MEMSUFFIX), _ra)(CPUArchState *env,
     target_ulong addr;
     int mmu_idx = CPU_MMU_INDEX;
     TCGMemOpIdx oi;
-
 #if !defined(SOFTMMU_CODE_ACCESS)
-    trace_guest_mem_before_exec(
-        env_cpu(env), ptr,
-        trace_mem_build_info(SHIFT, true, MO_TE, false, mmu_idx));
+    uint16_t meminfo = trace_mem_build_info(SHIFT, true, MO_TE, false, mmu_idx);
+    trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
 #endif
 
     addr = ptr;
@@ -142,6 +142,9 @@ glue(glue(glue(cpu_lds, SUFFIX), MEMSUFFIX), _ra)(CPUArchState *env,
         uintptr_t hostaddr = addr + entry->addend;
         res = glue(glue(lds, SUFFIX), _p)((uint8_t *)hostaddr);
     }
+#ifndef SOFTMMU_CODE_ACCESS
+    qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
+#endif
     return res;
 }
 
@@ -165,11 +168,9 @@ glue(glue(glue(cpu_st, SUFFIX), MEMSUFFIX), _ra)(CPUArchState *env,
     target_ulong addr;
     int mmu_idx = CPU_MMU_INDEX;
     TCGMemOpIdx oi;
-
 #if !defined(SOFTMMU_CODE_ACCESS)
-    trace_guest_mem_before_exec(
-        env_cpu(env), ptr,
-        trace_mem_build_info(SHIFT, false, MO_TE, true, mmu_idx));
+    uint16_t meminfo = trace_mem_build_info(SHIFT, false, MO_TE, true, mmu_idx);
+    trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
 #endif
 
     addr = ptr;
@@ -183,6 +184,9 @@ glue(glue(glue(cpu_st, SUFFIX), MEMSUFFIX), _ra)(CPUArchState *env,
         uintptr_t hostaddr = addr + entry->addend;
         glue(glue(st, SUFFIX), _p)((uint8_t *)hostaddr, v);
     }
+#ifndef SOFTMMU_CODE_ACCESS
+    qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
+#endif
 }
 
 static inline void
diff --git a/include/exec/cpu_ldst_useronly_template.h b/include/exec/cpu_ldst_useronly_template.h
index 8f7f117ad44..5cd0fa3b99d 100644
--- a/include/exec/cpu_ldst_useronly_template.h
+++ b/include/exec/cpu_ldst_useronly_template.h
@@ -64,18 +64,17 @@
 static inline RES_TYPE
 glue(glue(cpu_ld, USUFFIX), MEMSUFFIX)(CPUArchState *env, abi_ptr ptr)
 {
-#ifdef CODE_ACCESS
     RES_TYPE ret;
+#ifdef CODE_ACCESS
     set_helper_retaddr(1);
     ret = glue(glue(ld, USUFFIX), _p)(g2h(ptr));
     clear_helper_retaddr();
-    return ret;
 #else
-    trace_guest_mem_before_exec(
-        env_cpu(env), ptr,
-        trace_mem_build_info(SHIFT, false, MO_TE, false, 0));
-    return glue(glue(ld, USUFFIX), _p)(g2h(ptr));
+    uint16_t meminfo = trace_mem_build_info(SHIFT, false, MO_TE, false, 0);
+    trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
+    ret = glue(glue(ld, USUFFIX), _p)(g2h(ptr));
 #endif
+    return ret;
 }
 
 #ifndef CODE_ACCESS
@@ -96,18 +95,18 @@ glue(glue(glue(cpu_ld, USUFFIX), MEMSUFFIX), _ra)(CPUArchState *env,
 static inline int
 glue(glue(cpu_lds, SUFFIX), MEMSUFFIX)(CPUArchState *env, abi_ptr ptr)
 {
-#ifdef CODE_ACCESS
     int ret;
+#ifdef CODE_ACCESS
     set_helper_retaddr(1);
     ret = glue(glue(lds, SUFFIX), _p)(g2h(ptr));
     clear_helper_retaddr();
-    return ret;
 #else
-    trace_guest_mem_before_exec(
-        env_cpu(env), ptr,
-        trace_mem_build_info(SHIFT, true, MO_TE, false, 0));
-    return glue(glue(lds, SUFFIX), _p)(g2h(ptr));
+    uint16_t meminfo = trace_mem_build_info(SHIFT, true, MO_TE, false, 0);
+    trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
+    ret = glue(glue(lds, SUFFIX), _p)(g2h(ptr));
+    qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
 #endif
+    return ret;
 }
 
 #ifndef CODE_ACCESS
@@ -130,10 +129,10 @@ static inline void
 glue(glue(cpu_st, SUFFIX), MEMSUFFIX)(CPUArchState *env, abi_ptr ptr,
                                       RES_TYPE v)
 {
-    trace_guest_mem_before_exec(
-        env_cpu(env), ptr,
-        trace_mem_build_info(SHIFT, false, MO_TE, true, 0));
+    uint16_t meminfo = trace_mem_build_info(SHIFT, false, MO_TE, true, 0);
+    trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
     glue(glue(st, SUFFIX), _p)(g2h(ptr), v);
+    qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
 }
 
 static inline void
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
index 38e62dcba97..b60b42e6410 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -30,6 +30,7 @@
 #include "tcg-mo.h"
 #include "trace-tcg.h"
 #include "trace/mem.h"
+#include "exec/plugin-gen.h"
 
 /* Reduce the number of ifdefs below.  This assumes that all uses of
    TCGV_HIGH and TCGV_LOW are properly protected by a conditional that
@@ -2684,6 +2685,7 @@ void tcg_gen_exit_tb(TranslationBlock *tb, unsigned idx)
         tcg_debug_assert(idx == TB_EXIT_REQUESTED);
     }
 
+    plugin_gen_disable_mem_helpers();
     tcg_gen_op1i(INDEX_op_exit_tb, val);
 }
 
@@ -2696,6 +2698,7 @@ void tcg_gen_goto_tb(unsigned idx)
     tcg_debug_assert((tcg_ctx->goto_tb_issue_mask & (1 << idx)) == 0);
     tcg_ctx->goto_tb_issue_mask |= 1 << idx;
 #endif
+    plugin_gen_disable_mem_helpers();
     /* When not chaining, we simply fall through to the "fallback" exit.  */
     if (!qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) {
         tcg_gen_op1i(INDEX_op_goto_tb, idx);
@@ -2705,7 +2708,10 @@ void tcg_gen_goto_tb(unsigned idx)
 void tcg_gen_lookup_and_goto_ptr(void)
 {
     if (TCG_TARGET_HAS_goto_ptr && !qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) {
-        TCGv_ptr ptr = tcg_temp_new_ptr();
+        TCGv_ptr ptr;
+
+        plugin_gen_disable_mem_helpers();
+        ptr = tcg_temp_new_ptr();
         gen_helper_lookup_tb_ptr(ptr, cpu_env);
         tcg_gen_op1i(INDEX_op_goto_ptr, tcgv_ptr_arg(ptr));
         tcg_temp_free_ptr(ptr);
@@ -2788,14 +2794,24 @@ static void tcg_gen_req_mo(TCGBar type)
     }
 }
 
+static inline void plugin_gen_mem_callbacks(TCGv vaddr, uint16_t info)
+{
+#ifdef CONFIG_PLUGIN
+    if (tcg_ctx->plugin_insn == NULL) {
+        return;
+    }
+    plugin_gen_empty_mem_callback(vaddr, info);
+#endif
+}
+
 void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
 {
     TCGMemOp orig_memop;
+    uint16_t info = trace_mem_get_info(memop, idx, 0);
 
     tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
     memop = tcg_canonicalize_memop(memop, 0, 0);
-    trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
-                               addr, trace_mem_get_info(memop, idx, 0));
+    trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env, addr, info);
 
     orig_memop = memop;
     if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) {
@@ -2807,6 +2823,7 @@ void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
     }
 
     gen_ldst_i32(INDEX_op_qemu_ld_i32, val, addr, memop, idx);
+    plugin_gen_mem_callbacks(addr, info);
 
     if ((orig_memop ^ memop) & MO_BSWAP) {
         switch (orig_memop & MO_SIZE) {
@@ -2828,11 +2845,11 @@ void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
 void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
 {
     TCGv_i32 swap = NULL;
+    uint16_t info = trace_mem_get_info(memop, idx, 1);
 
     tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
     memop = tcg_canonicalize_memop(memop, 0, 1);
-    trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
-                               addr, trace_mem_get_info(memop, idx, 1));
+    trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env, addr, info);
 
     if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) {
         swap = tcg_temp_new_i32();
@@ -2852,6 +2869,7 @@ void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
     }
 
     gen_ldst_i32(INDEX_op_qemu_st_i32, val, addr, memop, idx);
+    plugin_gen_mem_callbacks(addr, info);
 
     if (swap) {
         tcg_temp_free_i32(swap);
@@ -2861,6 +2879,7 @@ void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
 void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
 {
     TCGMemOp orig_memop;
+    uint16_t info;
 
     if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
         tcg_gen_qemu_ld_i32(TCGV_LOW(val), addr, idx, memop);
@@ -2874,8 +2893,8 @@ void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
 
     tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
     memop = tcg_canonicalize_memop(memop, 1, 0);
-    trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
-                               addr, trace_mem_get_info(memop, idx, 0));
+    info = trace_mem_get_info(memop, idx, 0);
+    trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env, addr, info);
 
     orig_memop = memop;
     if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) {
@@ -2887,6 +2906,7 @@ void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
     }
 
     gen_ldst_i64(INDEX_op_qemu_ld_i64, val, addr, memop, idx);
+    plugin_gen_mem_callbacks(addr, info);
 
     if ((orig_memop ^ memop) & MO_BSWAP) {
         switch (orig_memop & MO_SIZE) {
@@ -2914,6 +2934,7 @@ void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
 void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
 {
     TCGv_i64 swap = NULL;
+    uint16_t info;
 
     if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
         tcg_gen_qemu_st_i32(TCGV_LOW(val), addr, idx, memop);
@@ -2922,8 +2943,8 @@ void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
 
     tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
     memop = tcg_canonicalize_memop(memop, 1, 1);
-    trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
-                               addr, trace_mem_get_info(memop, idx, 1));
+    info = trace_mem_get_info(memop, idx, 1);
+    trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env, addr, info);
 
     if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) {
         swap = tcg_temp_new_i64();
@@ -2947,6 +2968,7 @@ void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
     }
 
     gen_ldst_i64(INDEX_op_qemu_st_i64, val, addr, memop, idx);
+    plugin_gen_mem_callbacks(addr, info);
 
     if (swap) {
         tcg_temp_free_i64(swap);
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 2385e758e55..93f52f4ca93 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -28,6 +28,7 @@
 #include "cpu.h"
 #include "exec/tb-context.h"
 #include "qemu/bitops.h"
+#include "qemu/plugin.h"
 #include "qemu/queue.h"
 #include "tcg-mo.h"
 #include "tcg-target.h"
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 24/54] plugins: implement helpers for resolving hwaddr
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (22 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 23/54] tcg: let plugins instrument virtual memory accesses Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 14:14   ` Aaron Lindsay OS via Qemu-devel
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 25/54] translate-all: notify plugin code of tb_flush Alex Bennée
                   ` (32 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: aaron, cota, Paolo Bonzini, bobby.prani, Alex Bennée,
	Richard Henderson

We need to keep a local per-cpu copy of the data as other threads may
be running. We use a automatically growing array and re-use the space
for subsequent queries.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 accel/tcg/cputlb.c      | 32 ++++++++++++++++++++++++++
 include/exec/exec-all.h | 17 ++++++++++++++
 include/qemu/plugin.h   |  6 +++++
 plugins/api.c           | 50 +++++++++++++++++++++++++++++++++--------
 4 files changed, 96 insertions(+), 9 deletions(-)

diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index f7c0290639c..f37e89c806d 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1130,6 +1130,38 @@ void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr,
     return (void *)((uintptr_t)addr + entry->addend);
 }
 
+
+#ifdef CONFIG_PLUGIN
+/*
+ * Perform a TLB lookup and populate the qemu_plugin_hwaddr structure.
+ * This should be a hot path as we will have just looked this path up
+ * in the softmmu lookup code (or helper). We don't handle re-fills or
+ * checking the victim table. This is purely informational.
+ */
+
+bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx,
+                       bool is_store, struct qemu_plugin_hwaddr *data)
+{
+    CPUArchState *env = cpu->env_ptr;
+    CPUTLBEntry *tlbe = tlb_entry(env, mmu_idx, addr);
+    target_ulong tlb_addr = is_store ? tlb_addr_write(tlbe) : tlbe->addr_read;
+
+    if (tlb_hit(tlb_addr, addr)) {
+        if (tlb_addr & TLB_MMIO) {
+            data->hostaddr = 0;
+            data->is_io = true;
+            /* XXX: lookup device */
+        } else {
+            data->hostaddr = addr + tlbe->addend;
+            data->is_io = false;
+        }
+        return true;
+    }
+    return false;
+}
+
+#endif
+
 /* Probe for a read-modify-write atomic operation.  Do not allow unaligned
  * operations, or io operations to proceed.  Return the host address.  */
 static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 90045e77c1f..c42626e35b1 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -262,6 +262,17 @@ void tlb_set_page(CPUState *cpu, target_ulong vaddr,
                   int mmu_idx, target_ulong size);
 void probe_write(CPUArchState *env, target_ulong addr, int size, int mmu_idx,
                  uintptr_t retaddr);
+
+/**
+ * tlb_plugin_lookup: query last TLB lookup
+ * @cpu: cpu environment
+ *
+ * This function can be used directly after a memory operation to
+ * query information about the access. It is used by the plugin
+ * infrastructure to expose more information about the address.
+ */
+bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx,
+                       bool is_store, struct qemu_plugin_hwaddr *data);
 #else
 static inline void tlb_init(CPUState *cpu)
 {
@@ -311,6 +322,12 @@ static inline void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu,
                                                        uint16_t idxmap)
 {
 }
+static inline bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr,
+                                     int mmu_idx, bool is_store,
+                                     struct qemu_plugin_hwaddr *data)
+{
+    return false;
+}
 #endif
 
 #define CODE_GEN_ALIGN           16 /* must be >= of the size of a icache line */
diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
index 3c46a241669..657345df60c 100644
--- a/include/qemu/plugin.h
+++ b/include/qemu/plugin.h
@@ -182,6 +182,12 @@ struct qemu_plugin_insn *qemu_plugin_tb_insn_get(struct qemu_plugin_tb *tb)
     return insn;
 }
 
+struct qemu_plugin_hwaddr {
+    uint64_t hostaddr;
+    bool is_io;
+};
+
+
 #ifdef CONFIG_PLUGIN
 
 void qemu_plugin_vcpu_init_hook(CPUState *cpu);
diff --git a/plugins/api.c b/plugins/api.c
index 586bb8789f1..4b3ac9e31fb 100644
--- a/plugins/api.c
+++ b/plugins/api.c
@@ -39,7 +39,7 @@
 #include "cpu.h"
 #include "sysemu/sysemu.h"
 #include "tcg/tcg.h"
-#include "trace/mem-internal.h" /* mem_info macros */
+#include "exec/exec-all.h"
 #include "plugin.h"
 #ifndef CONFIG_USER_ONLY
 #include "hw/boards.h"
@@ -240,11 +240,42 @@ bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info)
  * Virtual Memory queries
  */
 
+#ifdef CONFIG_SOFTMMU
+static GArray *hwaddr_refs;
+
+struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
+                                                  uint64_t vaddr)
+{
+    CPUState *cpu = current_cpu;
+    unsigned int mmu_idx = info >> TRACE_MEM_MMU_SHIFT;
+    struct qemu_plugin_hwaddr *hwaddr;
+
+    /* Ensure we have memory allocated for this work */
+    if (!hwaddr_refs) {
+        hwaddr_refs = g_array_sized_new(false, true,
+                                        sizeof(struct qemu_plugin_hwaddr),
+                                        cpu->cpu_index + 1);
+    } else if (cpu->cpu_index >= hwaddr_refs->len) {
+        hwaddr_refs = g_array_set_size(hwaddr_refs, cpu->cpu_index + 1);
+    }
+
+    hwaddr = &g_array_index(hwaddr_refs, struct qemu_plugin_hwaddr,
+                            cpu->cpu_index);
+
+    if (!tlb_plugin_lookup(cpu, vaddr, mmu_idx,
+                           info & TRACE_MEM_ST, hwaddr)) {
+        return NULL;
+    }
+
+    return hwaddr;
+}
+#else
 struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
                                                   uint64_t vaddr)
 {
     return NULL;
 }
+#endif
 
 bool qemu_plugin_hwaddr_is_io(struct qemu_plugin_hwaddr *hwaddr)
 {
@@ -253,14 +284,15 @@ bool qemu_plugin_hwaddr_is_io(struct qemu_plugin_hwaddr *hwaddr)
 
 uint64_t qemu_plugin_hwaddr_to_raddr(const struct qemu_plugin_hwaddr *haddr)
 {
-#if 0 /* XXX FIXME should be SOFTMMU */
-    ram_addr_t ram_addr;
-
-    g_assert(haddr);
-    ram_addr = qemu_ram_addr_from_host(haddr);
-    if (ram_addr == RAM_ADDR_INVALID) {
-        error_report("Bad ram pointer %p", haddr);
-        abort();
+#ifdef CONFIG_SOFTMMU
+    ram_addr_t ram_addr = 0;
+
+    if (haddr && !haddr->is_io) {
+        ram_addr = qemu_ram_addr_from_host((void *) haddr->hostaddr);
+        if (ram_addr == RAM_ADDR_INVALID) {
+            error_report("Bad ram pointer %"PRIx64"", haddr->hostaddr);
+            abort();
+        }
     }
     return ram_addr;
 #else
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 25/54] translate-all: notify plugin code of tb_flush
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (23 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 24/54] plugins: implement helpers for resolving hwaddr Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 26/54] *-user: notify plugin of exit Alex Bennée
                   ` (31 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Richard Henderson, aaron, cota, Paolo Bonzini, bobby.prani,
	Alex Bennée, Richard Henderson

From: "Emilio G. Cota" <cota@braap.org>

Plugins might allocate per-TB data that then they get passed each
time a TB is executed (via the *userdata pointer).

Notify plugin code every time a code cache flush occurs, so
that plugins can then reclaim the memory of the per-TB data.

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 accel/tcg/translate-all.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 9c5c60ed964..7379df8f19c 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -1231,6 +1231,8 @@ static gboolean tb_host_size_iter(gpointer key, gpointer value, gpointer data)
 /* flush all the translation blocks */
 static void do_tb_flush(CPUState *cpu, run_on_cpu_data tb_flush_count)
 {
+    bool did_flush = false;
+
     mmap_lock();
     /* If it is already been done on request of another CPU,
      * just retry.
@@ -1238,6 +1240,7 @@ static void do_tb_flush(CPUState *cpu, run_on_cpu_data tb_flush_count)
     if (tb_ctx.tb_flush_count != tb_flush_count.host_int) {
         goto done;
     }
+    did_flush = true;
 
     if (DEBUG_TB_FLUSH_GATE) {
         size_t nb_tbs = tcg_nb_tbs();
@@ -1262,6 +1265,9 @@ static void do_tb_flush(CPUState *cpu, run_on_cpu_data tb_flush_count)
 
 done:
     mmap_unlock();
+    if (did_flush) {
+        qemu_plugin_flush_cb();
+    }
 }
 
 void tb_flush(CPUState *cpu)
-- 
2.20.1



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

* [Qemu-devel] [PATCH  v4 26/54] *-user: notify plugin of exit
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (24 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 25/54] translate-all: notify plugin code of tb_flush Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 27/54] *-user: plugin syscalls Alex Bennée
                   ` (30 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Riku Voipio, Richard Henderson, Laurent Vivier, aaron, cota,
	bobby.prani, Alex Bennée

From: "Emilio G. Cota" <cota@braap.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 bsd-user/syscall.c | 3 +++
 linux-user/exit.c  | 1 +
 2 files changed, 4 insertions(+)

diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 1ee6195d9ff..84a983a9a12 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -332,6 +332,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         _mcleanup();
 #endif
         gdb_exit(cpu_env, arg1);
+        qemu_plugin_atexit_cb();
         /* XXX: should free thread stack and CPU env */
         _exit(arg1);
         ret = 0; /* avoid warning */
@@ -430,6 +431,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
         _mcleanup();
 #endif
         gdb_exit(cpu_env, arg1);
+        qemu_plugin_atexit_cb();
         /* XXX: should free thread stack and CPU env */
         _exit(arg1);
         ret = 0; /* avoid warning */
@@ -505,6 +507,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
         _mcleanup();
 #endif
         gdb_exit(cpu_env, arg1);
+        qemu_plugin_atexit_cb();
         /* XXX: should free thread stack and CPU env */
         _exit(arg1);
         ret = 0; /* avoid warning */
diff --git a/linux-user/exit.c b/linux-user/exit.c
index bdda7205532..a362ef67d2c 100644
--- a/linux-user/exit.c
+++ b/linux-user/exit.c
@@ -35,4 +35,5 @@ void preexit_cleanup(CPUArchState *env, int code)
         __gcov_dump();
 #endif
         gdb_exit(env, code);
+        qemu_plugin_atexit_cb();
 }
-- 
2.20.1



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

* [Qemu-devel] [PATCH  v4 27/54] *-user: plugin syscalls
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (25 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 26/54] *-user: notify plugin of exit Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 28/54] cpu: hook plugin vcpu events Alex Bennée
                   ` (29 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Riku Voipio, Richard Henderson, Laurent Vivier, aaron, cota,
	bobby.prani, Alex Bennée

From: "Emilio G. Cota" <cota@braap.org>

To avoid too much duplication add a wrapper that the existing trace
and the new plugin calls can live in. We could move the -strace code
here as well but that is left for a future series as the code is
subtly different between the bsd and linux.

Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
[AJB: wrap in syscall-trace.h, expand commit msg]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 bsd-user/syscall.c           | 21 +++++++++++++------
 include/user/syscall-trace.h | 40 ++++++++++++++++++++++++++++++++++++
 linux-user/syscall.c         |  7 ++++---
 3 files changed, 59 insertions(+), 9 deletions(-)
 create mode 100644 include/user/syscall-trace.h

diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 84a983a9a12..0d45b654bb3 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -26,6 +26,7 @@
 
 #include "qemu.h"
 #include "qemu-common.h"
+#include "user/syscall-trace.h"
 
 //#define DEBUG
 
@@ -322,7 +323,8 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
 #ifdef DEBUG
     gemu_log("freebsd syscall %d\n", num);
 #endif
-    trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+    record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
+
     if(do_strace)
         print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
 
@@ -403,7 +405,8 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
 #endif
     if (do_strace)
         print_freebsd_syscall_ret(num, ret);
-    trace_guest_user_syscall_ret(cpu, num, ret);
+
+    record_syscall_return(cpu, num, ret);
     return ret;
  efault:
     ret = -TARGET_EFAULT;
@@ -421,7 +424,9 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
 #ifdef DEBUG
     gemu_log("netbsd syscall %d\n", num);
 #endif
-    trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
+
+    record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
+
     if(do_strace)
         print_netbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
 
@@ -479,7 +484,8 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
 #endif
     if (do_strace)
         print_netbsd_syscall_ret(num, ret);
-    trace_guest_user_syscall_ret(cpu, num, ret);
+
+    record_syscall_return(cpu, num, ret);
     return ret;
  efault:
     ret = -TARGET_EFAULT;
@@ -497,7 +503,9 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
 #ifdef DEBUG
     gemu_log("openbsd syscall %d\n", num);
 #endif
-    trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
+
+    record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
+
     if(do_strace)
         print_openbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
 
@@ -555,7 +563,8 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
 #endif
     if (do_strace)
         print_openbsd_syscall_ret(num, ret);
-    trace_guest_user_syscall_ret(cpu, num, ret);
+
+    record_syscall_return(cpu, num, ret);
     return ret;
  efault:
     ret = -TARGET_EFAULT;
diff --git a/include/user/syscall-trace.h b/include/user/syscall-trace.h
new file mode 100644
index 00000000000..9e604736433
--- /dev/null
+++ b/include/user/syscall-trace.h
@@ -0,0 +1,40 @@
+/*
+ * Common System Call Tracing Wrappers for *-user
+ *
+ * Copyright (c) 2019 Linaro
+ * Written by Alex Bennée <alex.bennee@linaro.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef _SYSCALL_TRACE_H_
+#define _SYSCALL_TRACE_H_
+
+/*
+ * These helpers just provide a common place for the various
+ * subsystems that want to track syscalls to put their hooks in. We
+ * could potentially unify the -strace code here as well.
+ */
+
+static inline void record_syscall_start(void *cpu, int num,
+                                        abi_long arg1, abi_long arg2,
+                                        abi_long arg3, abi_long arg4,
+                                        abi_long arg5, abi_long arg6,
+                                        abi_long arg7, abi_long arg8)
+{
+    trace_guest_user_syscall(cpu, num,
+                             arg1, arg2, arg3, arg4,
+                             arg5, arg6, arg7, arg8);
+    qemu_plugin_vcpu_syscall(cpu, num,
+                             arg1, arg2, arg3, arg4,
+                             arg5, arg6, arg7, arg8);
+}
+
+static inline void record_syscall_return(void *cpu, int num, abi_long ret)
+{
+    trace_guest_user_syscall_ret(cpu, num, ret);
+    qemu_plugin_vcpu_syscall_ret(cpu, num, ret);
+}
+
+
+#endif /* _SYSCALL_TRACE_H_ */
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 8367cb138df..9132f6d2663 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -109,6 +109,7 @@
 
 #include "qemu.h"
 #include "qemu/guest-random.h"
+#include "user/syscall-trace.h"
 #include "qapi/error.h"
 #include "fd-trans.h"
 
@@ -11968,8 +11969,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
     }
 #endif
 
-    trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4,
-                             arg5, arg6, arg7, arg8);
+    record_syscall_start(cpu, num, arg1,
+                         arg2, arg3, arg4, arg5, arg6, arg7, arg8);
 
     if (unlikely(do_strace)) {
         print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
@@ -11981,6 +11982,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                           arg5, arg6, arg7, arg8);
     }
 
-    trace_guest_user_syscall_ret(cpu, num, ret);
+    record_syscall_return(cpu, num, ret);
     return ret;
 }
-- 
2.20.1



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

* [Qemu-devel] [PATCH  v4 28/54] cpu: hook plugin vcpu events
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (26 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 27/54] *-user: plugin syscalls Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 29/54] plugin-gen: add plugin_insn_append Alex Bennée
                   ` (28 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Richard Henderson, aaron, cota, Paolo Bonzini,
	bobby.prani, Alex Bennée, Richard Henderson

From: "Emilio G. Cota" <cota@braap.org>

Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 cpus.c    | 10 ++++++++++
 exec.c    |  2 ++
 qom/cpu.c |  2 ++
 3 files changed, 14 insertions(+)

diff --git a/cpus.c b/cpus.c
index 927a00aa90b..cef94560e31 100644
--- a/cpus.c
+++ b/cpus.c
@@ -44,6 +44,7 @@
 #include "exec/exec-all.h"
 
 #include "qemu/thread.h"
+#include "qemu/plugin.h"
 #include "sysemu/cpus.h"
 #include "sysemu/qtest.h"
 #include "qemu/main-loop.h"
@@ -1241,9 +1242,18 @@ static void qemu_tcg_rr_wait_io_event(void)
 
 static void qemu_wait_io_event(CPUState *cpu)
 {
+    bool slept = false;
+
     while (cpu_thread_is_idle(cpu)) {
+        if (!slept) {
+            slept = true;
+            qemu_plugin_vcpu_idle_cb(cpu);
+        }
         qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex);
     }
+    if (slept) {
+        qemu_plugin_vcpu_resume_cb(cpu);
+    }
 
 #ifdef _WIN32
     /* Eat dummy APC queued by qemu_cpu_kick_thread.  */
diff --git a/exec.c b/exec.c
index 3e78de3b8f8..65374d0bdc8 100644
--- a/exec.c
+++ b/exec.c
@@ -974,6 +974,8 @@ void cpu_exec_realizefn(CPUState *cpu, Error **errp)
     }
     tlb_init(cpu);
 
+    qemu_plugin_vcpu_init_hook(cpu);
+
 #ifndef CONFIG_USER_ONLY
     if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
         vmstate_register(NULL, cpu->cpu_index, &vmstate_cpu_common, cpu);
diff --git a/qom/cpu.c b/qom/cpu.c
index f376f782d83..90ebb214bb2 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -33,6 +33,7 @@
 #include "hw/boards.h"
 #include "hw/qdev-properties.h"
 #include "trace-root.h"
+#include "qemu/plugin.h"
 
 CPUInterruptHandler cpu_interrupt_handler;
 
@@ -354,6 +355,7 @@ static void cpu_common_unrealizefn(DeviceState *dev, Error **errp)
     CPUState *cpu = CPU(dev);
     /* NOTE: latest generic point before the cpu is fully unrealized */
     trace_fini_vcpu(cpu);
+    qemu_plugin_vcpu_exit_hook(cpu);
     cpu_exec_unrealizefn(cpu);
 }
 
-- 
2.20.1



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

* [Qemu-devel] [PATCH  v4 29/54] plugin-gen: add plugin_insn_append
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (27 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 28/54] cpu: hook plugin vcpu events Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 18:39   ` Richard Henderson
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 30/54] translator: add translator_ld{ub, sw, uw, l, q} Alex Bennée
                   ` (27 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: bobby.prani, cota, Alex Bennée, aaron

From: "Emilio G. Cota" <cota@braap.org>

By adding it to plugin-gen's header file, we can export is as
an inline, since tcg.h is included in the header (we need tcg_ctx).

Signed-off-by: Emilio G. Cota <cota@braap.org>
[AJB: use g_byte_array]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v3
  - use g_byte_array
---
 include/exec/plugin-gen.h | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/include/exec/plugin-gen.h b/include/exec/plugin-gen.h
index de519883b16..4834a9e2f40 100644
--- a/include/exec/plugin-gen.h
+++ b/include/exec/plugin-gen.h
@@ -27,6 +27,17 @@ void plugin_gen_insn_end(void);
 void plugin_gen_disable_mem_helpers(void);
 void plugin_gen_empty_mem_callback(TCGv addr, uint32_t info);
 
+static inline void plugin_insn_append(const void *from, size_t size)
+{
+    struct qemu_plugin_insn *insn = tcg_ctx->plugin_insn;
+
+    if (insn == NULL) {
+        return;
+    }
+
+    insn->data = g_byte_array_append(insn->data, from, size);
+}
+
 #else /* !CONFIG_PLUGIN */
 
 static inline
@@ -51,6 +62,9 @@ static inline void plugin_gen_disable_mem_helpers(void)
 static inline void plugin_gen_empty_mem_callback(TCGv addr, uint32_t info)
 { }
 
+static inline void plugin_insn_append(const void *from, size_t size)
+{ }
+
 #endif /* CONFIG_PLUGIN */
 
 #endif /* QEMU_PLUGIN_GEN_H */
-- 
2.20.1



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

* [Qemu-devel] [PATCH  v4 30/54] translator: add translator_ld{ub, sw, uw, l, q}
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (28 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 29/54] plugin-gen: add plugin_insn_append Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 19:24   ` Richard Henderson
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 31/54] target/arm: fetch code with translator_ld Alex Bennée
                   ` (26 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Richard Henderson, aaron, cota, Paolo Bonzini, bobby.prani,
	Alex Bennée, Richard Henderson

From: "Emilio G. Cota" <cota@braap.org>

Suggested-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Emilio G. Cota <cota@braap.org>
[AJB: directly plumb into softmmu/user helpers]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v4
  - don't use the cpu_ldst helpers, plumb directly into the lower
  level
  - mark the CODE_ACCESS/SOFTMMU_CODE_ACCESS as deprecated
---
 include/exec/cpu_ldst.h   | 11 ++++++++
 include/exec/translator.h | 58 ++++++++++++++++++++++++++++++++++++++-
 include/qemu/bswap.h      |  5 ++++
 tcg/tcg.h                 |  2 ++
 4 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h
index 9151fdb042c..fd499f7e2ff 100644
--- a/include/exec/cpu_ldst.h
+++ b/include/exec/cpu_ldst.h
@@ -129,6 +129,11 @@ static inline void clear_helper_retaddr(void)
 #include "exec/cpu_ldst_useronly_template.h"
 #undef MEMSUFFIX
 
+/*
+ * Code access is deprecated in favour of translator_ld* functions
+ * (see translator.h). However there are still users that need to
+ * converted so for now these stay.
+ */
 #define MEMSUFFIX _code
 #define CODE_ACCESS
 #define DATA_SIZE 1
@@ -427,6 +432,12 @@ static inline CPUTLBEntry *tlb_entry(CPUArchState *env, uintptr_t mmu_idx,
 #undef CPU_MMU_INDEX
 #undef MEMSUFFIX
 
+/*
+ * Code access is deprecated in favour of translator_ld* functions
+ * (see translator.h). However there are still users that need to
+ * converted so for now these stay.
+ */
+
 #define CPU_MMU_INDEX (cpu_mmu_index(env, true))
 #define MEMSUFFIX _code
 #define SOFTMMU_CODE_ACCESS
diff --git a/include/exec/translator.h b/include/exec/translator.h
index 180c51d5092..30b1a594fc1 100644
--- a/include/exec/translator.h
+++ b/include/exec/translator.h
@@ -19,7 +19,10 @@
  */
 
 
+#include "qemu/bswap.h"
 #include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "exec/plugin-gen.h"
 #include "tcg/tcg.h"
 
 
@@ -142,4 +145,57 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
 
 void translator_loop_temp_check(DisasContextBase *db);
 
-#endif /* EXEC__TRANSLATOR_H */
+/*
+ * Translator Load Functions
+ *
+ * These are intended to replace the old cpu_ld*_code functions and
+ * are mandatory for front-ends that have been migrated to the common
+ * translator_loop. These functions are only intended to be called
+ * from the translation stage and should not be called from helper
+ * functions. Those functions should be converted to encode the
+ * relevant at translation time.
+ */
+
+#ifdef CONFIG_USER_ONLY
+
+#define DO_LOAD(type, name, shift)               \
+    set_helper_retaddr(1);                       \
+    ret = name ## _p(g2h(pc));                   \
+    clear_helper_retaddr();
+
+#else
+
+#define DO_LOAD(type, name, shift)                   \
+    int mmu_idx = cpu_mmu_index(env, true);          \
+    TCGMemOpIdx oi = make_memop_idx(shift, mmu_idx); \
+    ret = helper_ret_ ## name ## _cmmu(env, pc, oi, 0);
+
+#endif
+
+#define GEN_TRANSLATOR_LD(fullname, name, type, shift, swap_fn)         \
+    static inline type                                                  \
+    fullname ## _swap(CPUArchState *env, abi_ptr pc, bool do_swap)      \
+    {                                                                   \
+        type ret;                                                       \
+        DO_LOAD(type, name, shift)                                      \
+                                                                        \
+        if (do_swap) {                                                  \
+            ret = swap_fn(ret);                                         \
+        }                                                               \
+        plugin_insn_append(&ret, sizeof(ret));                          \
+        return ret;                                                     \
+    }                                                                   \
+                                                                        \
+    static inline type fullname(CPUArchState *env, abi_ptr pc)          \
+    {                                                                   \
+        return fullname ## _swap(env, pc, false);                       \
+    }
+
+GEN_TRANSLATOR_LD(translator_ldub, ldb, uint8_t, 1, /* no swap needed */)
+GEN_TRANSLATOR_LD(translator_ldsw, lduw, int16_t, 2, bswap16)
+GEN_TRANSLATOR_LD(translator_lduw, lduw, uint16_t, 2, bswap16)
+GEN_TRANSLATOR_LD(translator_ldl, ldl, uint32_t, 3, bswap32)
+GEN_TRANSLATOR_LD(translator_ldq, ldq, uint64_t, 4, bswap64)
+#undef GEN_TRANSLATOR_LD
+
+#endif  /* EXEC__TRANSLATOR_H */
diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h
index 2a9f3fe783e..4f707278740 100644
--- a/include/qemu/bswap.h
+++ b/include/qemu/bswap.h
@@ -306,6 +306,11 @@ static inline int ldub_p(const void *ptr)
     return *(uint8_t *)ptr;
 }
 
+static inline int ldb_p(const void *ptr)
+{
+    return ldub_p(ptr);
+}
+
 static inline int ldsb_p(const void *ptr)
 {
     return *(int8_t *)ptr;
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 93f52f4ca93..c918fdd87c4 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -1404,6 +1404,7 @@ uint64_t helper_be_ldq_cmmu(CPUArchState *env, target_ulong addr,
 # define helper_ret_stl_mmu   helper_be_stl_mmu
 # define helper_ret_stq_mmu   helper_be_stq_mmu
 # define helper_ret_ldw_cmmu  helper_be_ldw_cmmu
+# define helper_ret_lduw_cmmu helper_be_ldw_cmmu
 # define helper_ret_ldl_cmmu  helper_be_ldl_cmmu
 # define helper_ret_ldq_cmmu  helper_be_ldq_cmmu
 #else
@@ -1417,6 +1418,7 @@ uint64_t helper_be_ldq_cmmu(CPUArchState *env, target_ulong addr,
 # define helper_ret_stl_mmu   helper_le_stl_mmu
 # define helper_ret_stq_mmu   helper_le_stq_mmu
 # define helper_ret_ldw_cmmu  helper_le_ldw_cmmu
+# define helper_ret_lduw_cmmu helper_le_ldw_cmmu
 # define helper_ret_ldl_cmmu  helper_le_ldl_cmmu
 # define helper_ret_ldq_cmmu  helper_le_ldq_cmmu
 #endif
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 31/54] target/arm: fetch code with translator_ld
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (29 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 30/54] translator: add translator_ld{ub, sw, uw, l, q} Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-08-01 19:26   ` Richard Henderson
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 32/54] target/ppc: " Alex Bennée
                   ` (25 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, aaron, cota, open list:ARM TCG CPUs, bobby.prani,
	Alex Bennée

From: "Emilio G. Cota" <cota@braap.org>

Now the arm_ld*_code functions are only used at translate time we can
just pass down to translator_ld functions.

Signed-off-by: Emilio G. Cota <cota@braap.org>
[AJB: convert from plugin_insn_append to translator_ld]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v4
  - use translator_ld like the rest of them
---
 target/arm/arm_ldst.h | 15 +++------------
 1 file changed, 3 insertions(+), 12 deletions(-)

diff --git a/target/arm/arm_ldst.h b/target/arm/arm_ldst.h
index 5e0ac8bef06..45edb108f6a 100644
--- a/target/arm/arm_ldst.h
+++ b/target/arm/arm_ldst.h
@@ -20,25 +20,20 @@
 #ifndef ARM_LDST_H
 #define ARM_LDST_H
 
-#include "exec/cpu_ldst.h"
+#include "exec/translator.h"
 #include "qemu/bswap.h"
 
 /* Load an instruction and return it in the standard little-endian order */
 static inline uint32_t arm_ldl_code(CPUARMState *env, target_ulong addr,
                                     bool sctlr_b)
 {
-    uint32_t insn = cpu_ldl_code(env, addr);
-    if (bswap_code(sctlr_b)) {
-        return bswap32(insn);
-    }
-    return insn;
+    return translator_ldl_swap(env, addr, bswap_code(sctlr_b));
 }
 
 /* Ditto, for a halfword (Thumb) instruction */
 static inline uint16_t arm_lduw_code(CPUARMState *env, target_ulong addr,
                                      bool sctlr_b)
 {
-    uint16_t insn;
 #ifndef CONFIG_USER_ONLY
     /* In big-endian (BE32) mode, adjacent Thumb instructions have been swapped
        within each word.  Undo that now.  */
@@ -46,11 +41,7 @@ static inline uint16_t arm_lduw_code(CPUARMState *env, target_ulong addr,
         addr ^= 2;
     }
 #endif
-    insn = cpu_lduw_code(env, addr);
-    if (bswap_code(sctlr_b)) {
-        return bswap16(insn);
-    }
-    return insn;
+    return translator_lduw_swap(env, addr, bswap_code(sctlr_b));
 }
 
 #endif
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 32/54] target/ppc: fetch code with translator_ld
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (30 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 31/54] target/arm: fetch code with translator_ld Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 33/54] target/sh4: " Alex Bennée
                   ` (24 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Richard Henderson, aaron, cota, open list:PowerPC TCG CPUs,
	bobby.prani, Alex Bennée, David Gibson

From: "Emilio G. Cota" <cota@braap.org>

Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Acked-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/ppc/translate.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 4a5de280365..a27b5659f46 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -7864,11 +7864,9 @@ static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
     LOG_DISAS("nip=" TARGET_FMT_lx " super=%d ir=%d\n",
               ctx->base.pc_next, ctx->mem_idx, (int)msr_ir);
 
-    if (unlikely(need_byteswap(ctx))) {
-        ctx->opcode = bswap32(cpu_ldl_code(env, ctx->base.pc_next));
-    } else {
-        ctx->opcode = cpu_ldl_code(env, ctx->base.pc_next);
-    }
+    ctx->opcode = translator_ldl_swap(env, ctx->base.pc_next,
+                                      need_byteswap(ctx));
+
     LOG_DISAS("translate opcode %08x (%02x %02x %02x %02x) (%s)\n",
               ctx->opcode, opc1(ctx->opcode), opc2(ctx->opcode),
               opc3(ctx->opcode), opc4(ctx->opcode),
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 33/54] target/sh4: fetch code with translator_ld
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (31 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 32/54] target/ppc: " Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 34/54] target/i386: " Alex Bennée
                   ` (23 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Richard Henderson, aaron, cota, bobby.prani, Alex Bennée,
	Aurelien Jarno

From: "Emilio G. Cota" <cota@braap.org>

There is a small wrinkle with the gUSA instruction. The translator
effectively treats a (known) gUSA sequence as a single instruction.
For the purposes of the plugin we end up with a long multi-instruction
qemu_plugin_insn.

If the known sequence isn't detected we shall never run this
translation anyway.

Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/sh4/translate.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/sh4/translate.c b/target/sh4/translate.c
index 5a7d8c45355..922785e225e 100644
--- a/target/sh4/translate.c
+++ b/target/sh4/translate.c
@@ -1917,7 +1917,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env)
 
     /* Read all of the insns for the region.  */
     for (i = 0; i < max_insns; ++i) {
-        insns[i] = cpu_lduw_code(env, pc + i * 2);
+        insns[i] = translator_lduw(env, pc + i * 2);
     }
 
     ld_adr = ld_dst = ld_mop = -1;
@@ -2332,7 +2332,7 @@ static void sh4_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
     }
 #endif
 
-    ctx->opcode = cpu_lduw_code(env, ctx->base.pc_next);
+    ctx->opcode = translator_lduw(env, ctx->base.pc_next);
     decode_opc(ctx);
     ctx->base.pc_next += 2;
 }
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 34/54] target/i386: fetch code with translator_ld
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (32 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 33/54] target/sh4: " Alex Bennée
@ 2019-07-31 16:06 ` Alex Bennée
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 35/54] target/hppa: " Alex Bennée
                   ` (22 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Richard Henderson, aaron, cota, Paolo Bonzini,
	bobby.prani, Alex Bennée, Richard Henderson

From: "Emilio G. Cota" <cota@braap.org>

Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/i386/translate.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/target/i386/translate.c b/target/i386/translate.c
index 03150a86e23..bf4cd875aba 100644
--- a/target/i386/translate.c
+++ b/target/i386/translate.c
@@ -1925,28 +1925,28 @@ static uint64_t advance_pc(CPUX86State *env, DisasContext *s, int num_bytes)
 
 static inline uint8_t x86_ldub_code(CPUX86State *env, DisasContext *s)
 {
-    return cpu_ldub_code(env, advance_pc(env, s, 1));
+    return translator_ldub(env, advance_pc(env, s, 1));
 }
 
 static inline int16_t x86_ldsw_code(CPUX86State *env, DisasContext *s)
 {
-    return cpu_ldsw_code(env, advance_pc(env, s, 2));
+    return translator_ldsw(env, advance_pc(env, s, 2));
 }
 
 static inline uint16_t x86_lduw_code(CPUX86State *env, DisasContext *s)
 {
-    return cpu_lduw_code(env, advance_pc(env, s, 2));
+    return translator_lduw(env, advance_pc(env, s, 2));
 }
 
 static inline uint32_t x86_ldl_code(CPUX86State *env, DisasContext *s)
 {
-    return cpu_ldl_code(env, advance_pc(env, s, 4));
+    return translator_ldl(env, advance_pc(env, s, 4));
 }
 
 #ifdef TARGET_X86_64
 static inline uint64_t x86_ldq_code(CPUX86State *env, DisasContext *s)
 {
-    return cpu_ldq_code(env, advance_pc(env, s, 8));
+    return translator_ldq(env, advance_pc(env, s, 8));
 }
 #endif
 
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 35/54] target/hppa: fetch code with translator_ld
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (33 preceding siblings ...)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 34/54] target/i386: " Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 36/54] target/m68k: " Alex Bennée
                   ` (21 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: Richard Henderson, aaron, cota, bobby.prani, Alex Bennée,
	Richard Henderson

From: "Emilio G. Cota" <cota@braap.org>

Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/hppa/translate.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index 188fe688cbe..36a784e2932 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -4217,7 +4217,7 @@ static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
     {
         /* Always fetch the insn, even if nullified, so that we check
            the page permissions for execute.  */
-        uint32_t insn = cpu_ldl_code(env, ctx->base.pc_next);
+        uint32_t insn = translator_ldl(env, ctx->base.pc_next);
 
         /* Set up the IA queue for the next insn.
            This will be overwritten by a branch.  */
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 36/54] target/m68k: fetch code with translator_ld
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (34 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 35/54] target/hppa: " Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 37/54] target/alpha: " Alex Bennée
                   ` (20 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: Richard Henderson, Laurent Vivier, aaron, cota, bobby.prani,
	Alex Bennée

From: "Emilio G. Cota" <cota@braap.org>

Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/m68k/translate.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 60bcfb7bd0c..92785befaac 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -384,7 +384,7 @@ static TCGv gen_ldst(DisasContext *s, int opsize, TCGv addr, TCGv val,
 static inline uint16_t read_im16(CPUM68KState *env, DisasContext *s)
 {
     uint16_t im;
-    im = cpu_lduw_code(env, s->pc);
+    im = translator_lduw(env, s->pc);
     s->pc += 2;
     return im;
 }
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 37/54] target/alpha: fetch code with translator_ld
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (35 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 36/54] target/m68k: " Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 38/54] target/riscv: " Alex Bennée
                   ` (19 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: Richard Henderson, aaron, cota, bobby.prani, Alex Bennée,
	Richard Henderson

From: "Emilio G. Cota" <cota@braap.org>

Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/alpha/translate.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/alpha/translate.c b/target/alpha/translate.c
index 2c9cccf6c1b..daf1e05cba6 100644
--- a/target/alpha/translate.c
+++ b/target/alpha/translate.c
@@ -2989,7 +2989,7 @@ static void alpha_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
 {
     DisasContext *ctx = container_of(dcbase, DisasContext, base);
     CPUAlphaState *env = cpu->env_ptr;
-    uint32_t insn = cpu_ldl_code(env, ctx->base.pc_next);
+    uint32_t insn = translator_ldl(env, ctx->base.pc_next);
 
     ctx->base.pc_next += 4;
     ctx->base.is_jmp = translate_one(ctx, insn);
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 38/54] target/riscv: fetch code with translator_ld
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (36 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 37/54] target/alpha: " Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 39/54] target/sparc: " Alex Bennée
                   ` (18 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: open list:RISC-V TCG CPUs, Sagar Karandikar, Bastian Koppelmann,
	Palmer Dabbelt, Richard Henderson, aaron, cota, Alistair Francis,
	bobby.prani, Alex Bennée

From: "Emilio G. Cota" <cota@braap.org>

Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/riscv/translate.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 8d6ab732588..73cea63e4a2 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -796,7 +796,7 @@ static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
     DisasContext *ctx = container_of(dcbase, DisasContext, base);
     CPURISCVState *env = cpu->env_ptr;
 
-    ctx->opcode = cpu_ldl_code(env, ctx->base.pc_next);
+    ctx->opcode = translator_ldl(env, ctx->base.pc_next);
     decode_opc(ctx);
     ctx->base.pc_next = ctx->pc_succ_insn;
 
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 39/54] target/sparc: fetch code with translator_ld
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (37 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 38/54] target/riscv: " Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 40/54] target/xtensa: " Alex Bennée
                   ` (17 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: Richard Henderson, Mark Cave-Ayland, aaron, cota, bobby.prani,
	Alex Bennée, Artyom Tarasenko

From: "Emilio G. Cota" <cota@braap.org>

Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/sparc/translate.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 091bab53af3..c91ff118099 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -5900,7 +5900,7 @@ static void sparc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
     CPUSPARCState *env = cs->env_ptr;
     unsigned int insn;
 
-    insn = cpu_ldl_code(env, dc->pc);
+    insn = translator_ldl(env, dc->pc);
     dc->base.pc_next += 4;
     disas_sparc_insn(dc, insn);
 
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 40/54] target/xtensa: fetch code with translator_ld
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (38 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 39/54] target/sparc: " Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 41/54] target/openrisc: " Alex Bennée
                   ` (16 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: Richard Henderson, Max Filippov, aaron, cota, bobby.prani,
	Alex Bennée

From: "Emilio G. Cota" <cota@braap.org>

Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/xtensa/translate.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
index 6f1da878752..cb849ae2d9b 100644
--- a/target/xtensa/translate.c
+++ b/target/xtensa/translate.c
@@ -863,7 +863,7 @@ static int arg_copy_compare(const void *a, const void *b)
 static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
 {
     xtensa_isa isa = dc->config->isa;
-    unsigned char b[MAX_INSN_LENGTH] = {cpu_ldub_code(env, dc->pc)};
+    unsigned char b[MAX_INSN_LENGTH] = {translator_ldub(env, dc->pc)};
     unsigned len = xtensa_op0_insn_len(dc, b[0]);
     xtensa_format fmt;
     int slot, slots;
@@ -887,7 +887,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
 
     dc->base.pc_next = dc->pc + len;
     for (i = 1; i < len; ++i) {
-        b[i] = cpu_ldub_code(env, dc->pc + i);
+        b[i] = translator_ldub(env, dc->pc + i);
     }
     xtensa_insnbuf_from_chars(isa, dc->insnbuf, b, len);
     fmt = xtensa_format_decode(isa, dc->insnbuf);
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 41/54] target/openrisc: fetch code with translator_ld
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (39 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 40/54] target/xtensa: " Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 42/54] translator: inject instrumentation from plugins Alex Bennée
                   ` (15 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: Richard Henderson, aaron, cota, Stafford Horne, Alex Bennée,
	bobby.prani

From: "Emilio G. Cota" <cota@braap.org>

Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/openrisc/translate.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
index 4360ce40452..7df4c68d158 100644
--- a/target/openrisc/translate.c
+++ b/target/openrisc/translate.c
@@ -1305,7 +1305,7 @@ static void openrisc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
 {
     DisasContext *dc = container_of(dcbase, DisasContext, base);
     OpenRISCCPU *cpu = OPENRISC_CPU(cs);
-    uint32_t insn = cpu_ldl_code(&cpu->env, dc->base.pc_next);
+    uint32_t insn = translator_ldl(&cpu->env, dc->base.pc_next);
 
     if (!decode(dc, insn)) {
         gen_illegal_exception(dc);
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 42/54] translator: inject instrumentation from plugins
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (40 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 41/54] target/openrisc: " Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-08-01 19:35   ` Richard Henderson
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 43/54] plugin: add API symbols to qemu-plugins.symbols Alex Bennée
                   ` (14 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: aaron, cota, Paolo Bonzini, bobby.prani, Alex Bennée,
	Richard Henderson

From: "Emilio G. Cota" <cota@braap.org>

Signed-off-by: Emilio G. Cota <cota@braap.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v4
  - note we can't inject instrumentation if ! DISAS_NEXT
---
 accel/tcg/translator.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
index 9226a348a39..4e30772f8cb 100644
--- a/accel/tcg/translator.c
+++ b/accel/tcg/translator.c
@@ -16,6 +16,7 @@
 #include "exec/gen-icount.h"
 #include "exec/log.h"
 #include "exec/translator.h"
+#include "exec/plugin-gen.h"
 
 /* Pairs with tcg_clear_temp_count.
    To be called by #TranslatorOps.{translate_insn,tb_stop} if
@@ -34,6 +35,7 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
                      CPUState *cpu, TranslationBlock *tb, int max_insns)
 {
     int bp_insn = 0;
+    bool plugin_enabled;
 
     /* Initialize DisasContext */
     db->tb = tb;
@@ -55,11 +57,17 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
     ops->tb_start(db, cpu);
     tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
 
+    plugin_enabled = plugin_gen_tb_start(cpu, tb);
+
     while (true) {
         db->num_insns++;
         ops->insn_start(db, cpu);
         tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
 
+        if (plugin_enabled) {
+            plugin_gen_insn_start(cpu, db);
+        }
+
         /* Pass breakpoint hits to target for further processing */
         if (!db->singlestep_enabled
             && unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
@@ -100,6 +108,14 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
             break;
         }
 
+        /*
+         * We can't instrument after instructions that change control
+         * flow although this only really affects post-load operations.
+         */
+        if (plugin_enabled) {
+            plugin_gen_insn_end();
+        }
+
         /* Stop translation if the output buffer is full,
            or we have executed all of the allowed instructions.  */
         if (tcg_op_buf_full() || db->num_insns >= db->max_insns) {
@@ -112,6 +128,10 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
     ops->tb_stop(db, cpu);
     gen_tb_end(db->tb, db->num_insns - bp_insn);
 
+    if (plugin_enabled) {
+        plugin_gen_tb_end(cpu);
+    }
+
     /* The disas_log hook may use these values rather than recompute.  */
     db->tb->size = db->pc_next - db->pc_first;
     db->tb->icount = db->num_insns;
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 43/54] plugin: add API symbols to qemu-plugins.symbols
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (41 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 42/54] translator: inject instrumentation from plugins Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-08-01 19:42   ` Richard Henderson
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 44/54] vl: support -plugin option Alex Bennée
                   ` (13 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: bobby.prani, cota, Alex Bennée, aaron

From: "Emilio G. Cota" <cota@braap.org>

Signed-off-by: Emilio G. Cota <cota@braap.org>
[AJB: moved into plugins]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v3
  - moved to plugins/
  - include qemu_plugin_reset
---
 Makefile                     |  1 +
 configure                    | 69 ++++++++++++++++++++++++++++++++++++
 plugins/.gitignore           |  2 ++
 plugins/Makefile.objs        | 14 ++++++++
 plugins/qemu-plugins.symbols | 38 ++++++++++++++++++++
 5 files changed, 124 insertions(+)
 create mode 100644 plugins/.gitignore
 create mode 100644 plugins/qemu-plugins.symbols

diff --git a/Makefile b/Makefile
index ed4bb87f224..485e4bb2e85 100644
--- a/Makefile
+++ b/Makefile
@@ -726,6 +726,7 @@ distclean: clean
 	rm -f qemu-doc.fn qemu-doc.fns qemu-doc.info qemu-doc.ky qemu-doc.kys
 	rm -f qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp
 	rm -f qemu-doc.vr qemu-doc.txt
+	rm -f qemu-plugins-ld.symbols qemu-plugins-ld64.symbols
 	rm -f config.log
 	rm -f linux-headers/asm
 	rm -f docs/version.texi
diff --git a/configure b/configure
index dbc78f21b0c..7f6a1556fe2 100755
--- a/configure
+++ b/configure
@@ -30,6 +30,7 @@ TMPO="${TMPDIR1}/${TMPB}.o"
 TMPCXX="${TMPDIR1}/${TMPB}.cxx"
 TMPE="${TMPDIR1}/${TMPB}.exe"
 TMPMO="${TMPDIR1}/${TMPB}.mo"
+TMPTXT="${TMPDIR1}/${TMPB}.txt"
 
 rm -f config.log
 
@@ -5498,6 +5499,58 @@ if compile_prog "" "" ; then
   atomic64=yes
 fi
 
+#########################################
+# See if --dynamic-list is supported by the linker
+
+cat > $TMPTXT <<EOF
+{
+  foo;
+};
+EOF
+
+cat > $TMPC <<EOF
+#include <stdio.h>
+void foo(void);
+
+void foo(void)
+{
+  printf("foo\n");
+}
+
+int main(void)
+{
+  foo();
+  return 0;
+}
+EOF
+
+ld_dynamic_list="no"
+if compile_prog "" "-Wl,--dynamic-list=$TMPTXT" ; then
+  ld_dynamic_list="yes"
+fi
+
+#########################################
+# See if -exported_symbols_list is supported by the linker
+
+cat > $TMPTXT <<EOF
+  _foo
+EOF
+
+ld_exported_symbols_list="no"
+if compile_prog "" "-Wl,-exported_symbols_list,$TMPTXT" ; then
+  ld_exported_symbols_list="yes"
+fi
+
+if  test "$plugins" = "yes" &&
+    test "$ld_dynamic_list" = "no" &&
+    test "$ld_exported_symbols_list" = "no" ; then
+  error_exit \
+      "Plugin support requires specifying a set of symbols that " \
+      "are exported to plugins. Unfortunately your linker doesn't " \
+      "support the flag (--dynamic-list or -exported_symbols_list) used " \
+      "for this purpose."
+fi
+
 ########################################
 # See if 16-byte vector operations are supported.
 # Even without a vector unit the compiler may expand these.
@@ -7318,6 +7371,22 @@ fi
 if test "$plugins" = "yes" ; then
     echo "CONFIG_PLUGIN=y" >> $config_host_mak
     LIBS="-ldl $LIBS"
+    # Copy the export object list to the build dir
+    if test "$ld_dynamic_list" = "yes" ; then
+	echo "CONFIG_HAS_LD_DYNAMIC_LIST=yes" >> $config_host_mak
+	ld_symbols=qemu-plugins-ld.symbols
+	cp "$source_path/plugins/qemu-plugins.symbols" $ld_symbols
+    elif test "$ld_exported_symbols_list" = "yes" ; then
+	echo "CONFIG_HAS_LD_EXPORTED_SYMBOLS_LIST=yes" >> $config_host_mak
+	ld64_symbols=qemu-plugins-ld64.symbols
+	echo "# Automatically generated by configure - do not modify" > $ld64_symbols
+	grep 'qemu_' "$source_path/plugins/qemu-plugins.symbols" | sed 's/;//g' | \
+	    sed -E 's/^[[:space:]]*(.*)/_\1/' >> $ld64_symbols
+    else
+	error_exit \
+	    "If \$plugins=yes, either \$ld_dynamic_list or " \
+	    "\$ld_exported_symbols_list should have been set to 'yes'."
+    fi
 fi
 
 if test "$tcg_interpreter" = "yes"; then
diff --git a/plugins/.gitignore b/plugins/.gitignore
new file mode 100644
index 00000000000..7b8aaa1f109
--- /dev/null
+++ b/plugins/.gitignore
@@ -0,0 +1,2 @@
+qemu-plugins-ld.symbols
+qemu-plugins-ld64.symbols
diff --git a/plugins/Makefile.objs b/plugins/Makefile.objs
index 95baabf3d2f..6f14d91ccb9 100644
--- a/plugins/Makefile.objs
+++ b/plugins/Makefile.objs
@@ -5,3 +5,17 @@
 obj-y += loader.o
 obj-y += core.o
 obj-y += api.o
+
+# Abuse -libs suffix to only link with --dynamic-list/-exported_symbols_list
+# when the final binary includes the plugin object.
+#
+# Note that simply setting LDFLAGS is not enough: we build binaries that
+# never link plugin.o, and the linker might fail (at least ld64 does)
+# if the symbols in the list are not in the output binary.
+ifdef CONFIG_HAS_LD_DYNAMIC_LIST
+api.o-libs := -Wl,--dynamic-list=$(BUILD_DIR)/qemu-plugins-ld.symbols
+else
+ifdef CONFIG_HAS_LD_EXPORTED_SYMBOLS_LIST
+api.o-libs := -Wl,-exported_symbols_list,$(BUILD_DIR)/qemu-plugins-ld64.symbols
+endif
+endif
diff --git a/plugins/qemu-plugins.symbols b/plugins/qemu-plugins.symbols
new file mode 100644
index 00000000000..40c0d1abd2f
--- /dev/null
+++ b/plugins/qemu-plugins.symbols
@@ -0,0 +1,38 @@
+{
+  qemu_plugin_uninstall;
+  qemu_plugin_reset;
+  qemu_plugin_register_vcpu_init_cb;
+  qemu_plugin_register_vcpu_exit_cb;
+  qemu_plugin_register_vcpu_idle_cb;
+  qemu_plugin_register_vcpu_resume_cb;
+  qemu_plugin_register_vcpu_insn_exec_cb;
+  qemu_plugin_register_vcpu_insn_exec_inline;
+  qemu_plugin_register_vcpu_mem_cb;
+  qemu_plugin_register_vcpu_mem_haddr_cb;
+  qemu_plugin_register_vcpu_mem_inline;
+  qemu_plugin_ram_addr_from_host;
+  qemu_plugin_register_vcpu_tb_trans_cb;
+  qemu_plugin_register_vcpu_tb_exec_cb;
+  qemu_plugin_register_vcpu_tb_exec_inline;
+  qemu_plugin_register_flush_cb;
+  qemu_plugin_register_vcpu_syscall_cb;
+  qemu_plugin_register_vcpu_syscall_ret_cb;
+  qemu_plugin_register_atexit_cb;
+  qemu_plugin_tb_n_insns;
+  qemu_plugin_tb_get_insn;
+  qemu_plugin_tb_vaddr;
+  qemu_plugin_insn_data;
+  qemu_plugin_insn_size;
+  qemu_plugin_insn_vaddr;
+  qemu_plugin_insn_haddr;
+  qemu_plugin_mem_size_shift;
+  qemu_plugin_mem_is_sign_extended;
+  qemu_plugin_mem_is_big_endian;
+  qemu_plugin_mem_is_store;
+  qemu_plugin_get_hwaddr;
+  qemu_plugin_hwaddr_is_io;
+  qemu_plugin_hwaddr_to_raddr;
+  qemu_plugin_vcpu_for_each;
+  qemu_plugin_n_vcpus;
+  qemu_plugin_n_max_vcpus;
+};
-- 
2.20.1



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

* [Qemu-devel] [PATCH  v4 44/54] vl: support -plugin option
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (42 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 43/54] plugin: add API symbols to qemu-plugins.symbols Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 45/54] linux-user: " Alex Bennée
                   ` (12 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: Richard Henderson, aaron, cota, Paolo Bonzini, bobby.prani,
	Alex Bennée, Lluís Vilanova

From: Lluís Vilanova <vilanova@ac.upc.edu>

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
[ cota: s/instrument/plugin ]
Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 qemu-options.hx | 17 +++++++++++++++++
 vl.c            | 11 +++++++++++
 2 files changed, 28 insertions(+)

diff --git a/qemu-options.hx b/qemu-options.hx
index 9621e934c0b..7b438f61734 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -4131,6 +4131,23 @@ HXCOMM HX does not support conditional compilation of text.
 @findex -trace
 @include qemu-option-trace.texi
 ETEXI
+DEF("plugin", HAS_ARG, QEMU_OPTION_plugin,
+    "-plugin [file=]<file>[,arg=<string>]\n"
+    "                load a plugin\n",
+    QEMU_ARCH_ALL)
+STEXI
+@item -plugin file=@var{file}[,arg=@var{string}]
+@findex -plugin
+
+Load a plugin.
+
+@table @option
+@item file=@var{file}
+Load the given plugin from a shared library file.
+@item arg=@var{string}
+Argument string passed to the plugin. (Can be given multiple times.)
+@end table
+ETEXI
 
 HXCOMM Internal use
 DEF("qtest", HAS_ARG, QEMU_OPTION_qtest, "", QEMU_ARCH_ALL)
diff --git a/vl.c b/vl.c
index b426b321346..bb62989f776 100644
--- a/vl.c
+++ b/vl.c
@@ -109,6 +109,7 @@ int main(int argc, char **argv)
 
 #include "trace-root.h"
 #include "trace/control.h"
+#include "qemu/plugin.h"
 #include "qemu/queue.h"
 #include "sysemu/arch_init.h"
 
@@ -2889,6 +2890,7 @@ int main(int argc, char **argv, char **envp)
     bool list_data_dirs = false;
     char *dir, **dirs;
     BlockdevOptionsQueue bdo_queue = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue);
+    QemuPluginList plugin_list = QTAILQ_HEAD_INITIALIZER(plugin_list);
 
     os_set_line_buffering();
 
@@ -2919,6 +2921,7 @@ int main(int argc, char **argv, char **envp)
     qemu_add_opts(&qemu_global_opts);
     qemu_add_opts(&qemu_mon_opts);
     qemu_add_opts(&qemu_trace_opts);
+    qemu_plugin_add_opts();
     qemu_add_opts(&qemu_option_rom_opts);
     qemu_add_opts(&qemu_machine_opts);
     qemu_add_opts(&qemu_accel_opts);
@@ -3697,6 +3700,9 @@ int main(int argc, char **argv, char **envp)
                 g_free(trace_file);
                 trace_file = trace_opt_parse(optarg);
                 break;
+            case QEMU_OPTION_plugin:
+                qemu_plugin_opt_parse(optarg, &plugin_list);
+                break;
             case QEMU_OPTION_readconfig:
                 {
                     int ret = qemu_read_config_file(optarg);
@@ -4010,6 +4016,11 @@ int main(int argc, char **argv, char **envp)
                                machine_class->default_machine_opts, 0);
     }
 
+    /* process plugin before CPUs are created, but once -smp has been parsed */
+    if (qemu_plugin_load_list(&plugin_list)) {
+        exit(1);
+    }
+
     qemu_opts_foreach(qemu_find_opts("device"),
                       default_driver_check, NULL, NULL);
     qemu_opts_foreach(qemu_find_opts("global"),
-- 
2.20.1



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

* [Qemu-devel] [PATCH  v4 45/54] linux-user: support -plugin option
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (43 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 44/54] vl: support -plugin option Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 46/54] tests/plugin: add sample plugins Alex Bennée
                   ` (11 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: Riku Voipio, Richard Henderson, Laurent Vivier, aaron, cota,
	bobby.prani, Alex Bennée, Lluís Vilanova

From: Lluís Vilanova <vilanova@ac.upc.edu>

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
[ cota: s/instrument/plugin ]
Signed-off-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 linux-user/main.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/linux-user/main.c b/linux-user/main.c
index 8ffc5251955..42daa47dd3c 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -33,6 +33,7 @@
 #include "qemu/error-report.h"
 #include "qemu/help_option.h"
 #include "qemu/module.h"
+#include "qemu/plugin.h"
 #include "cpu.h"
 #include "exec/exec-all.h"
 #include "tcg.h"
@@ -392,6 +393,15 @@ static void handle_arg_trace(const char *arg)
     trace_file = trace_opt_parse(arg);
 }
 
+static QemuPluginList plugins = QTAILQ_HEAD_INITIALIZER(plugins);
+
+#ifdef CONFIG_PLUGIN
+static void handle_arg_plugin(const char *arg)
+{
+    qemu_plugin_opt_parse(arg, &plugins);
+}
+#endif
+
 struct qemu_argument {
     const char *argv;
     const char *env;
@@ -443,6 +453,10 @@ static const struct qemu_argument arg_table[] = {
      "",           "Seed for pseudo-random number generator"},
     {"trace",      "QEMU_TRACE",       true,  handle_arg_trace,
      "",           "[[enable=]<pattern>][,events=<file>][,file=<file>]"},
+#ifdef CONFIG_PLUGIN
+    {"plugin",     "QEMU_PLUGIN",      true,  handle_arg_plugin,
+     "",           "[file=]<file>[,arg=<string>]"},
+#endif
     {"version",    "QEMU_VERSION",     false, handle_arg_version,
      "",           "display version information and exit"},
     {NULL, NULL, false, NULL, NULL, NULL}
@@ -633,6 +647,7 @@ int main(int argc, char **argv, char **envp)
     cpu_model = NULL;
 
     qemu_add_opts(&qemu_trace_opts);
+    qemu_plugin_add_opts();
 
     optind = parse_args(argc, argv);
 
@@ -640,6 +655,9 @@ int main(int argc, char **argv, char **envp)
         exit(1);
     }
     trace_init_file(trace_file);
+    if (qemu_plugin_load_list(&plugins)) {
+        exit(1);
+    }
 
     /* Zero out regs */
     memset(regs, 0, sizeof(struct target_pt_regs));
-- 
2.20.1



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

* [Qemu-devel] [PATCH  v4 46/54] tests/plugin: add sample plugins
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (44 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 45/54] linux-user: " Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 47/54] tests/tcg: enable plugin testing Alex Bennée
                   ` (10 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: bobby.prani, cota, Alex Bennée, aaron

From: "Emilio G. Cota" <cota@braap.org>

Pass arguments with -plugin=libfoo.so,arg=bar,arg=baz

Signed-off-by: Emilio G. Cota <cota@braap.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v4
   - tweaks for hwaddr API
---
 configure             |  4 +-
 tests/plugin/Makefile | 28 +++++++++++++
 tests/plugin/bb.c     | 65 +++++++++++++++++++++++++++++
 tests/plugin/empty.c  | 29 +++++++++++++
 tests/plugin/insn.c   | 62 ++++++++++++++++++++++++++++
 tests/plugin/mem.c    | 96 +++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 282 insertions(+), 2 deletions(-)
 create mode 100644 tests/plugin/Makefile
 create mode 100644 tests/plugin/bb.c
 create mode 100644 tests/plugin/empty.c
 create mode 100644 tests/plugin/insn.c
 create mode 100644 tests/plugin/mem.c

diff --git a/configure b/configure
index 7f6a1556fe2..26afcc6061b 100755
--- a/configure
+++ b/configure
@@ -8006,14 +8006,14 @@ fi
 # tests might fail. Prefer to keep the relevant files in their own
 # directory and symlink the directory instead.
 DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests tests/vm"
-DIRS="$DIRS tests/fp tests/qgraph"
+DIRS="$DIRS tests/fp tests/qgraph tests/plugin"
 DIRS="$DIRS docs docs/interop fsdev scsi"
 DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw"
 DIRS="$DIRS roms/seabios roms/vgabios"
 LINKS="Makefile tests/tcg/Makefile"
 LINKS="$LINKS tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit"
 LINKS="$LINKS tests/tcg/lm32/Makefile tests/tcg/xtensa/Makefile po/Makefile"
-LINKS="$LINKS tests/fp/Makefile"
+LINKS="$LINKS tests/fp/Makefile tests/plugin/Makefile"
 LINKS="$LINKS pc-bios/optionrom/Makefile pc-bios/keymaps"
 LINKS="$LINKS pc-bios/spapr-rtas/Makefile"
 LINKS="$LINKS pc-bios/s390-ccw/Makefile"
diff --git a/tests/plugin/Makefile b/tests/plugin/Makefile
new file mode 100644
index 00000000000..f9a3546ea32
--- /dev/null
+++ b/tests/plugin/Makefile
@@ -0,0 +1,28 @@
+BUILD_DIR := $(CURDIR)/../..
+
+include $(BUILD_DIR)/config-host.mak
+include $(SRC_PATH)/rules.mak
+
+$(call set-vpath, $(SRC_PATH)/tests/plugin)
+
+NAMES :=
+NAMES += bb
+NAMES += empty
+NAMES += insn
+NAMES += mem
+
+SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES)))
+
+QEMU_CFLAGS += -fPIC
+QEMU_CFLAGS += -I$(SRC_PATH)/include/qemu
+
+all: $(SONAMES)
+
+lib%.so: %.o
+	$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDLIBS)
+
+clean:
+	rm -f *.o *.so *.d
+	rm -Rf .libs
+
+.PHONY: all clean
diff --git a/tests/plugin/bb.c b/tests/plugin/bb.c
new file mode 100644
index 00000000000..93d25de3639
--- /dev/null
+++ b/tests/plugin/bb.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
+ *
+ * License: GNU GPL, version 2 or later.
+ *   See the COPYING file in the top-level directory.
+ */
+#include <inttypes.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <qemu-plugin.h>
+
+static uint64_t bb_count;
+static uint64_t insn_count;
+static int stdout_fd;
+static bool do_inline;
+
+static void plugin_exit(qemu_plugin_id_t id, void *p)
+{
+    dprintf(stdout_fd, "bb's: %" PRIu64", insns: %" PRIu64 "\n",
+            bb_count, insn_count);
+}
+
+static void vcpu_tb_exec(unsigned int cpu_index, void *udata)
+{
+    unsigned long n_insns = (unsigned long)udata;
+
+    insn_count += n_insns;
+    bb_count++;
+}
+
+static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
+{
+    unsigned long n_insns = qemu_plugin_tb_n_insns(tb);
+
+    if (do_inline) {
+        qemu_plugin_register_vcpu_tb_exec_inline(tb, QEMU_PLUGIN_INLINE_ADD_U64,
+                                                 &bb_count, 1);
+        qemu_plugin_register_vcpu_tb_exec_inline(tb, QEMU_PLUGIN_INLINE_ADD_U64,
+                                                 &insn_count, n_insns);
+    } else {
+        qemu_plugin_register_vcpu_tb_exec_cb(tb, vcpu_tb_exec,
+                                             QEMU_PLUGIN_CB_NO_REGS,
+                                             (void *)n_insns);
+    }
+}
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, int argc,
+                                           char **argv)
+{
+    if (argc && strcmp(argv[0], "inline") == 0) {
+        do_inline = true;
+    }
+
+    /* to be used when in the exit hook */
+    stdout_fd = dup(STDOUT_FILENO);
+    assert(stdout_fd);
+
+    qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
+    qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
+    return 0;
+}
diff --git a/tests/plugin/empty.c b/tests/plugin/empty.c
new file mode 100644
index 00000000000..b141ddd0df4
--- /dev/null
+++ b/tests/plugin/empty.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
+ *
+ * License: GNU GPL, version 2 or later.
+ *   See the COPYING file in the top-level directory.
+ */
+#include <inttypes.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <qemu-plugin.h>
+
+/*
+ * Empty TB translation callback.
+ * This allows us to measure the overhead of injecting and then
+ * removing empty instrumentation.
+ */
+static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
+{ }
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, int argc,
+                                           char **argv)
+{
+    qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
+    return 0;
+}
diff --git a/tests/plugin/insn.c b/tests/plugin/insn.c
new file mode 100644
index 00000000000..3000ab4b731
--- /dev/null
+++ b/tests/plugin/insn.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
+ *
+ * License: GNU GPL, version 2 or later.
+ *   See the COPYING file in the top-level directory.
+ */
+#include <inttypes.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <qemu-plugin.h>
+
+static int stdout_fd;
+static uint64_t insn_count;
+static bool do_inline;
+
+static void vcpu_insn_exec_before(unsigned int cpu_index, void *udata)
+{
+    insn_count++;
+}
+
+static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
+{
+    size_t n = qemu_plugin_tb_n_insns(tb);
+    size_t i;
+
+    for (i = 0; i < n; i++) {
+        struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
+
+        if (do_inline) {
+            qemu_plugin_register_vcpu_insn_exec_inline(
+                insn, QEMU_PLUGIN_INLINE_ADD_U64, &insn_count, 1);
+        } else {
+            qemu_plugin_register_vcpu_insn_exec_cb(
+                insn, vcpu_insn_exec_before, QEMU_PLUGIN_CB_NO_REGS, NULL);
+        }
+    }
+}
+
+static void plugin_exit(qemu_plugin_id_t id, void *p)
+{
+    dprintf(stdout_fd, "insns: %" PRIu64 "\n", insn_count);
+}
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, int argc,
+                                           char **argv)
+{
+    if (argc && !strcmp(argv[0], "inline")) {
+        do_inline = true;
+    }
+
+    /* to be used when in the exit hook */
+    stdout_fd = dup(STDOUT_FILENO);
+    assert(stdout_fd);
+
+    qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
+    qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
+    return 0;
+}
diff --git a/tests/plugin/mem.c b/tests/plugin/mem.c
new file mode 100644
index 00000000000..e5490f4a99d
--- /dev/null
+++ b/tests/plugin/mem.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
+ *
+ * License: GNU GPL, version 2 or later.
+ *   See the COPYING file in the top-level directory.
+ */
+#include <inttypes.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <qemu-plugin.h>
+
+static uint64_t mem_count;
+static uint64_t io_count;
+static int stdout_fd;
+static bool do_inline;
+static bool do_haddr;
+static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW;
+
+static void plugin_exit(qemu_plugin_id_t id, void *p)
+{
+    dprintf(stdout_fd, "mem accesses: %" PRIu64 "\n", mem_count);
+    if (do_haddr) {
+        dprintf(stdout_fd, "io accesses: %" PRIu64 "\n", mem_count);
+    }
+}
+
+static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t meminfo,
+                     uint64_t vaddr, void *udata)
+{
+    if (do_haddr) {
+        struct qemu_plugin_hwaddr *hwaddr;
+        hwaddr = qemu_plugin_get_hwaddr(meminfo, vaddr);
+        if (qemu_plugin_hwaddr_is_io(hwaddr)) {
+            io_count++;
+        } else {
+            mem_count++;
+        }
+    } else {
+        mem_count++;
+    }
+}
+
+static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
+{
+    size_t n = qemu_plugin_tb_n_insns(tb);
+    size_t i;
+
+    for (i = 0; i < n; i++) {
+        struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
+
+        if (do_inline) {
+            qemu_plugin_register_vcpu_mem_inline(insn, rw,
+                                                 QEMU_PLUGIN_INLINE_ADD_U64,
+                                                 &mem_count, 1);
+        } else {
+            qemu_plugin_register_vcpu_mem_cb(insn, vcpu_mem,
+                                             QEMU_PLUGIN_CB_NO_REGS,
+                                             rw, NULL);
+        }
+    }
+}
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, int argc,
+                                           char **argv)
+{
+    if (argc) {
+        if (argc >= 3) {
+            if (!strcmp(argv[2], "haddr")) {
+                do_haddr = true;
+            }
+        }
+        if (argc >= 2) {
+            const char *str = argv[1];
+
+            if (!strcmp(str, "r")) {
+                rw = QEMU_PLUGIN_MEM_R;
+            } else if (!strcmp(str, "w")) {
+                rw = QEMU_PLUGIN_MEM_W;
+            }
+        }
+        if (!strcmp(argv[0], "inline")) {
+            do_inline = true;
+        }
+    }
+    /* plugin_exit might write to stdout after stdout has been closed */
+    stdout_fd = dup(STDOUT_FILENO);
+    assert(stdout_fd);
+
+    qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
+    qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
+    return 0;
+}
-- 
2.20.1



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

* [Qemu-devel] [PATCH  v4 47/54] tests/tcg: enable plugin testing
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (45 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 46/54] tests/plugin: add sample plugins Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 48/54] tests/plugin: add a hotblocks plugin Alex Bennée
                   ` (9 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Philippe Mathieu-Daudé,
	aaron, cota, open list:ARM TCG CPUs, bobby.prani,
	Alex Bennée

If CONFIG_PLUGINS is enabled then lets enable testing for all our TCG
targets. This is a simple smoke test that ensure we don't crash or
otherwise barf out by running each plugin against each test.

There is a minor knock on effect for additional runners which need
specialised QEMU_OPTS which will also need to declare a plugin version
of the runner. If this gets onerous we might need to add another
helper.

Checking the results of the plugins is left for a later exercise.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/Makefile.include                | 10 +++++++-
 tests/tcg/Makefile                    | 34 +++++++++++++++++++++++++++
 tests/tcg/arm/Makefile.softmmu-target |  1 +
 3 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index fd7fdb86586..0611aede077 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -1052,6 +1052,14 @@ check-softfloat:
 		"SKIPPED for non-TCG builds")
 endif
 
+# Plugins
+ifeq ($(CONFIG_PLUGIN),y)
+plugins:
+	$(call quiet-command,\
+		$(MAKE) $(SUBDIR_MAKEFLAGS) -C tests/plugin V="$(V)", \
+		"BUILD", "plugins")
+endif
+
 # Per guest TCG tests
 
 BUILD_TCG_TARGET_RULES=$(patsubst %,build-tcg-tests-%, $(TARGET_DIRS))
@@ -1066,7 +1074,7 @@ $(foreach PROBE_TARGET,$(TARGET_DIRS), 				\
 		$(eval build-tcg-tests-$(PROBE_TARGET): $(DOCKER_PREREQ))))
 endif
 
-build-tcg-tests-%:
+build-tcg-tests-%: $(if $(CONFIG_PLUGIN),plugins)
 	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" \
 		SKIP_DOCKER_BUILD=1 TARGET_DIR="$*/" guest-tests, \
 		"BUILD", "TCG tests for $*")
diff --git a/tests/tcg/Makefile b/tests/tcg/Makefile
index 9f567686240..8341a5345bc 100644
--- a/tests/tcg/Makefile
+++ b/tests/tcg/Makefile
@@ -120,11 +120,37 @@ all: $(TESTS)
 #
 
 RUN_TESTS=$(patsubst %,run-%, $(TESTS))
+
+# If plugins exist also include those in the tests
+ifeq ($(CONFIG_PLUGIN),y)
+PLUGIN_DIR=../../tests/plugin
+VPATH+=$(PLUGIN_DIR)
+PLUGINS=$(notdir $(wildcard $(PLUGIN_DIR)/*.so))
+
+# We need to ensure expand the run-plugin-TEST-with-PLUGIN
+# pre-requistes manually here as we can't use stems to handle it. We
+# also add some special helpers the run-plugin- rules can use bellow.
+
+$(foreach p,$(PLUGINS), \
+	$(foreach t,$(TESTS),\
+		$(eval run-plugin-$(t)-with-$(p): $t $p) \
+		$(eval RUN_TESTS+=run-plugin-$(t)-with-$(p))))
+endif
+
+strip-plugin = $(wordlist 1, 1, $(subst -with-, ,$1))
+extract-plugin = $(wordlist 2, 2, $(subst -with-, ,$1))
+
 RUN_TESTS+=$(EXTRA_RUNS)
 
 ifdef CONFIG_USER_ONLY
 run-%: %
 	$(call run-test, $<, $(QEMU) $(QEMU_OPTS) $<, "$< on $(TARGET_NAME)")
+
+run-plugin-%:
+	$(call run-test, $@, $(QEMU) $(QEMU_OPTS) \
+		-plugin $(PLUGIN_DIR)/$(call extract-plugin,$@) \
+		 $(call strip-plugin,$<), \
+	"$< on $(TARGET_NAME)")
 else
 run-%: %
 	$(call run-test, $<, \
@@ -132,6 +158,14 @@ run-%: %
 		  -chardev file$(COMMA)path=$<.out$(COMMA)id=output \
 	   	  $(QEMU_OPTS) $<, \
 	  "$< on $(TARGET_NAME)")
+
+run-plugin-%:
+	$(call run-test, $@, \
+	  $(QEMU) -monitor none -display none \
+		  -chardev file$(COMMA)path=$@.out$(COMMA)id=output \
+	   	  -plugin $(PLUGIN_DIR)/$(call extract-plugin,$@) \
+	   	  $(QEMU_OPTS) $(call strip-plugin,$<), \
+	  "$< on $(TARGET_NAME)")
 endif
 
 gdb-%: %
diff --git a/tests/tcg/arm/Makefile.softmmu-target b/tests/tcg/arm/Makefile.softmmu-target
index 49d48d8a1c3..cd628306b3e 100644
--- a/tests/tcg/arm/Makefile.softmmu-target
+++ b/tests/tcg/arm/Makefile.softmmu-target
@@ -25,5 +25,6 @@ LDFLAGS+=-nostdlib -N -static
 test-armv6m-undef: EXTRA_CFLAGS+=-mcpu=cortex-m0
 
 run-test-armv6m-undef: QEMU_OPTS+=-semihosting -M microbit -kernel
+run-plugin-test-armv6m-undef-%: QEMU_OPTS+=-semihosting -M microbit -kernel
 
 endif
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 48/54] tests/plugin: add a hotblocks plugin
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (46 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 47/54] tests/tcg: enable plugin testing Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 49/54] plugin: add qemu_plugin_insn_disas helper Alex Bennée
                   ` (8 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: bobby.prani, cota, Alex Bennée, aaron

This is a simple plugin to track which translation blocks are call
most often. As we don't have a view of the internals of TCG we can
only work by the address of the start of the block so we also need to
tracks how often the address is translated.

As there will be multiple blocks starting at the same address. We can
try and work around this by futzing the value to feed to the hash with
the insn count.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/plugin/Makefile    |   1 +
 tests/plugin/hotblocks.c | 146 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 147 insertions(+)
 create mode 100644 tests/plugin/hotblocks.c

diff --git a/tests/plugin/Makefile b/tests/plugin/Makefile
index f9a3546ea32..e74940eaac5 100644
--- a/tests/plugin/Makefile
+++ b/tests/plugin/Makefile
@@ -10,6 +10,7 @@ NAMES += bb
 NAMES += empty
 NAMES += insn
 NAMES += mem
+NAMES += hotblocks
 
 SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES)))
 
diff --git a/tests/plugin/hotblocks.c b/tests/plugin/hotblocks.c
new file mode 100644
index 00000000000..3654afbc887
--- /dev/null
+++ b/tests/plugin/hotblocks.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2019, Alex Bennée <alex.bennee@linaro.org>
+ *
+ * License: GNU GPL, version 2 or later.
+ *   See the COPYING file in the top-level directory.
+ */
+#include <inttypes.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <glib.h>
+
+#include <qemu-plugin.h>
+
+static bool do_inline;
+static int stdout_fd;
+
+/* Plugins need to take care of their own locking */
+static GMutex lock;
+static GHashTable *hotblocks;
+static guint64 limit = 20;
+
+/*
+ * Counting Structure
+ *
+ * The internals of the TCG are not exposed to plugins so we can only
+ * get the starting PC for each block. We cheat this slightly by
+ * xor'ing the number of instructions to the hash to help
+ * differentiate.
+ */
+typedef struct {
+    uint64_t start_addr;
+    uint64_t exec_count;
+    int      trans_count;
+    unsigned long insns;
+} ExecCount;
+
+static gint cmp_exec_count(gconstpointer a, gconstpointer b)
+{
+    ExecCount *ea = (ExecCount *) a;
+    ExecCount *eb = (ExecCount *) b;
+    return ea->exec_count > eb->exec_count ? -1 : 1;
+}
+
+static void plugin_exit(qemu_plugin_id_t id, void *p)
+{
+    GString *report = g_string_new("collected ");
+    GList *counts, *it;
+    int i;
+
+    g_mutex_lock(&lock);
+    g_string_append_printf(report, "%d entries in the hash table\n",
+                           g_hash_table_size(hotblocks));
+    counts = g_hash_table_get_values(hotblocks);
+    it = g_list_sort(counts, cmp_exec_count);
+
+    g_string_append_printf(report, "pc, tcount, icount, ecount\n");
+
+    for (i = 0; i < limit && it->next; i++, it = it->next) {
+        ExecCount *rec = (ExecCount *) it->data;
+        g_string_append_printf(report, "%#016"PRIx64", %d, %ld, %"PRId64"\n",
+                               rec->start_addr, rec->trans_count,
+                               rec->insns, rec->exec_count);
+    }
+
+    g_mutex_unlock(&lock);
+    g_list_free(it);
+
+    dprintf(stdout_fd, "%s", report->str);
+    g_string_free(report, true);
+}
+
+static void plugin_init(void)
+{
+    hotblocks = g_hash_table_new(NULL, g_direct_equal);
+}
+
+static void vcpu_tb_exec(unsigned int cpu_index, void *udata)
+{
+    ExecCount *cnt;
+    uint64_t hash = (uint64_t) udata;
+
+    g_mutex_lock(&lock);
+    cnt = (ExecCount *) g_hash_table_lookup(hotblocks, (gconstpointer) hash);
+    /* should always succeed */
+    g_assert(cnt);
+    cnt->exec_count++;
+    g_mutex_unlock(&lock);
+}
+
+/*
+ * When do_inline we ask the plugin to increment the counter for us.
+ * Otherwise a helper is inserted which calls the vcpu_tb_exec
+ * callback.
+ */
+static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
+{
+    ExecCount *cnt;
+    uint64_t pc = qemu_plugin_tb_vaddr(tb);
+    unsigned long insns = qemu_plugin_tb_n_insns(tb);
+    uint64_t hash = pc ^ insns;
+
+    g_mutex_lock(&lock);
+    cnt = (ExecCount *) g_hash_table_lookup(hotblocks, (gconstpointer) hash);
+    if (cnt) {
+        cnt->trans_count++;
+    } else {
+        cnt = g_new0(ExecCount, 1);
+        cnt->start_addr = pc;
+        cnt->trans_count = 1;
+        cnt->insns = insns;
+        g_hash_table_insert(hotblocks, (gpointer) hash, (gpointer) cnt);
+    }
+
+    g_mutex_unlock(&lock);
+
+    if (do_inline) {
+        qemu_plugin_register_vcpu_tb_exec_inline(tb, QEMU_PLUGIN_INLINE_ADD_U64,
+                                                 &cnt->exec_count, 1);
+    } else {
+        qemu_plugin_register_vcpu_tb_exec_cb(tb, vcpu_tb_exec,
+                                             QEMU_PLUGIN_CB_NO_REGS,
+                                             (void *)hash);
+    }
+}
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, int argc,
+                                           char **argv)
+{
+    if (argc && strcmp(argv[0], "inline") == 0) {
+        do_inline = true;
+    }
+
+    /* to be used when in the exit hook */
+    stdout_fd = dup(STDOUT_FILENO);
+    assert(stdout_fd);
+
+    plugin_init();
+
+    qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
+    qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
+    return 0;
+}
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 49/54] plugin: add qemu_plugin_insn_disas helper
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (47 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 48/54] tests/plugin: add a hotblocks plugin Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 50/54] tests/plugin: add instruction execution breakdown Alex Bennée
                   ` (7 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Richard Henderson, bobby.prani, cota, Alex Bennée, aaron

Give the plugins access to the QEMU dissasembler so they don't have to
re-invent the wheel.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 disas.c                      | 103 +++++++++++++++++++++++++++++++++++
 include/disas/disas.h        |   2 +
 include/qemu/qemu-plugin.h   |   9 +++
 plugins/api.c                |   7 +++
 plugins/qemu-plugins.symbols |   1 +
 5 files changed, 122 insertions(+)

diff --git a/disas.c b/disas.c
index 3e2bfa572b1..4b127369c36 100644
--- a/disas.c
+++ b/disas.c
@@ -475,6 +475,109 @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code,
     }
 }
 
+static GString plugin_disas_output;
+
+static int plugin_printf(FILE *stream, const char *fmt, ...)
+{
+    va_list va;
+    GString *s = &plugin_disas_output;
+    int initial_len = s->len;
+
+    va_start(va, fmt);
+    g_string_append_printf(s, fmt, va);
+    va_end(va);
+
+    return s->len - initial_len;
+}
+
+static void plugin_print_address(bfd_vma addr, struct disassemble_info *info)
+{
+    /* does nothing */
+}
+
+/* Disassemble a single instruction directly into plugin output */
+static
+bool plugin_cap_disas_insn(disassemble_info *info, uint64_t pc, size_t size)
+{
+    uint8_t cap_buf[1024];
+    csh handle;
+    cs_insn *insn;
+    size_t csize = 0;
+    int count;
+    GString *s = &plugin_disas_output;
+
+    if (cap_disas_start(info, &handle) != CS_ERR_OK) {
+        return false;
+    }
+    insn = cap_insn;
+
+    size_t tsize = MIN(sizeof(cap_buf) - csize, size);
+    const uint8_t *cbuf = cap_buf;
+    target_read_memory(pc, cap_buf, tsize, info);
+
+    count = cs_disasm(handle, cbuf, size, 0, 1, &insn);
+
+    if (count) {
+        g_string_printf(s, "%s %s", insn->mnemonic, insn->op_str);
+    } else {
+        g_string_printf(s, "cs_disasm failed");
+    }
+
+    cs_close(&handle);
+    return true;
+}
+
+char * plugin_disas(CPUState *cpu, uint64_t addr, size_t size)
+{
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+    target_ulong pc;
+    int count;
+    CPUDebug s;
+    GString *ds = g_string_set_size(&plugin_disas_output, 0);
+
+    g_assert(ds == &plugin_disas_output);
+
+    INIT_DISASSEMBLE_INFO(s.info, NULL, plugin_printf);
+
+    s.cpu = cpu;
+    s.info.read_memory_func = target_read_memory;
+    s.info.buffer_vma = addr;
+    s.info.buffer_length = size;
+    s.info.print_address_func = plugin_print_address;
+    s.info.cap_arch = -1;
+    s.info.cap_mode = 0;
+    s.info.cap_insn_unit = 4;
+    s.info.cap_insn_split = 4;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    s.info.endian = BFD_ENDIAN_BIG;
+#else
+    s.info.endian = BFD_ENDIAN_LITTLE;
+#endif
+
+    if (cc->disas_set_info) {
+        cc->disas_set_info(cpu, &s.info);
+    }
+
+    if (s.info.cap_arch >= 0 && plugin_cap_disas_insn(&s.info, addr, size)) {
+        return g_strdup(ds->str);
+    }
+
+    if (s.info.print_insn == NULL) {
+        s.info.print_insn = print_insn_od_target;
+    }
+
+    for (pc = addr; size > 0; pc += count, size -= count) {
+        count = s.info.print_insn(pc, &s.info);
+        if (count < 0) {
+            break;
+        }
+        g_assert(size >= count);
+    }
+
+    return g_strdup(ds->str);
+}
+
 /* Disassemble this for me please... (debugging). */
 void disas(FILE *out, void *code, unsigned long size)
 {
diff --git a/include/disas/disas.h b/include/disas/disas.h
index 15da511f49c..119df9e9bdf 100644
--- a/include/disas/disas.h
+++ b/include/disas/disas.h
@@ -13,6 +13,8 @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code,
 void monitor_disas(Monitor *mon, CPUState *cpu,
                    target_ulong pc, int nb_insn, int is_physical);
 
+char * plugin_disas(CPUState *cpu, uint64_t addr, size_t size);
+
 /* Look up symbol for debugging purpose.  Returns "" if unknown. */
 const char *lookup_symbol(target_ulong orig_addr);
 #endif
diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
index d9c1ca3b4cf..8b403dd6157 100644
--- a/include/qemu/qemu-plugin.h
+++ b/include/qemu/qemu-plugin.h
@@ -324,6 +324,15 @@ qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
                                          qemu_plugin_vcpu_syscall_ret_cb_t cb);
 
 
+/**
+ * qemu_plugin_insn_disas() - return disassembly string for instruction
+ * @insn: instruction reference
+ *
+ * Returns an allocated string containing the disassembly
+ */
+
+char * qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn);
+
 /**
  * qemu_plugin_vcpu_for_each() - iterate over the existing vCPU
  * @id: plugin ID
diff --git a/plugins/api.c b/plugins/api.c
index 4b3ac9e31fb..5a0bed1b1e0 100644
--- a/plugins/api.c
+++ b/plugins/api.c
@@ -40,6 +40,7 @@
 #include "sysemu/sysemu.h"
 #include "tcg/tcg.h"
 #include "exec/exec-all.h"
+#include "disas/disas.h"
 #include "plugin.h"
 #ifndef CONFIG_USER_ONLY
 #include "hw/boards.h"
@@ -211,6 +212,12 @@ void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn)
     return insn->haddr;
 }
 
+char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn)
+{
+    CPUState *cpu = current_cpu;
+    return plugin_disas(cpu, insn->vaddr, insn->data->len);
+}
+
 /*
  * The memory queries allow the plugin to query information about a
  * memory access.
diff --git a/plugins/qemu-plugins.symbols b/plugins/qemu-plugins.symbols
index 40c0d1abd2f..267ec381b4a 100644
--- a/plugins/qemu-plugins.symbols
+++ b/plugins/qemu-plugins.symbols
@@ -25,6 +25,7 @@
   qemu_plugin_insn_size;
   qemu_plugin_insn_vaddr;
   qemu_plugin_insn_haddr;
+  qemu_plugin_insn_disas;
   qemu_plugin_mem_size_shift;
   qemu_plugin_mem_is_sign_extended;
   qemu_plugin_mem_is_big_endian;
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 50/54] tests/plugin: add instruction execution breakdown
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (48 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 49/54] plugin: add qemu_plugin_insn_disas helper Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-08-01 14:31   ` Aaron Lindsay OS via Qemu-devel
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 51/54] tests/plugin: add hotpages plugin to breakdown memory access patterns Alex Bennée
                   ` (6 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: bobby.prani, cota, Alex Bennée, aaron

This gives a break down of instruction classes and individual
instruction types.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/plugin/Makefile |   1 +
 tests/plugin/howvec.c | 301 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 302 insertions(+)
 create mode 100644 tests/plugin/howvec.c

diff --git a/tests/plugin/Makefile b/tests/plugin/Makefile
index e74940eaac5..3656429d46b 100644
--- a/tests/plugin/Makefile
+++ b/tests/plugin/Makefile
@@ -11,6 +11,7 @@ NAMES += empty
 NAMES += insn
 NAMES += mem
 NAMES += hotblocks
+NAMES += howvec
 
 SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES)))
 
diff --git a/tests/plugin/howvec.c b/tests/plugin/howvec.c
new file mode 100644
index 00000000000..accf8611ff4
--- /dev/null
+++ b/tests/plugin/howvec.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2019, Alex Bennée <alex.bennee@linaro.org>
+ *
+ * How vectorised is this code?
+ *
+ * Attempt to measure the amount of vectorisation that has been done
+ * on some code by counting classes of instruction. This is very much
+ * ARM specific.
+ *
+ * License: GNU GPL, version 2 or later.
+ *   See the COPYING file in the top-level directory.
+ */
+#include <inttypes.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <glib.h>
+
+#include <qemu-plugin.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+typedef enum {
+    COUNT_CLASS,
+    COUNT_INDIVIDUAL,
+    COUNT_NONE
+} CountType;
+
+static int limit = 50;
+static int stdout_fd;
+static bool do_inline;
+static bool verbose;
+
+static GMutex lock;
+static GHashTable *insns;
+
+typedef struct {
+    const char *class;
+    const char *opt;
+    uint32_t mask;
+    uint32_t pattern;
+    CountType what;
+    uint64_t count;
+} InsnClassExecCount;
+
+typedef struct {
+    char *insn;
+    uint32_t opcode;
+    uint64_t count;
+    InsnClassExecCount *class;
+} InsnExecCount;
+
+/*
+ * Matchers for classes of instructions, order is important.
+ *
+ * Your most precise match must be before looser matches. If no match
+ * is found in the table we can create an individual entry.
+ */
+InsnClassExecCount insn_classes[] = {
+    /* "Reserved"" */
+    { "  UDEF",              "udef",   0xffff0000, 0x00000000, COUNT_NONE},
+    { "  SVE",               "sve",    0x1e000000, 0x04000000, COUNT_CLASS},
+    { "Reserved",            "res",    0x1e000000, 0x00000000, COUNT_CLASS},
+    /* Data Processing Immediate */
+    { "  PCrel addr",        "pcrel",  0x1f000000, 0x10000000, COUNT_CLASS},
+    { "  Add/Sub (imm,tags)","asit",   0x1f800000, 0x11800000, COUNT_CLASS},
+    { "  Add/Sub (imm)",     "asi",    0x1f000000, 0x11000000, COUNT_CLASS},
+    { "  Logical (imm)",     "logi",   0x1f800000, 0x12000000, COUNT_CLASS},
+    { "  Move Wide (imm)",   "movwi",  0x1f800000, 0x12800000, COUNT_CLASS},
+    { "  Bitfield",          "bitf",   0x1f800000, 0x13000000, COUNT_CLASS},
+    { "  Extract",           "extr",   0x1f800000, 0x13800000, COUNT_CLASS},
+    { "Data Proc Imm",       "dpri",   0x1c000000, 0x10000000, COUNT_CLASS},
+    /* Branches */
+    { "  Cond Branch (imm)", "cndb",   0xfe000000, 0x54000000, COUNT_CLASS},
+    { "  Exception Gen",     "excp",   0xff000000, 0xd4000000, COUNT_CLASS},
+    { "    NOP",             "nop",    0xffffffff, 0xd503201f, COUNT_NONE},
+    { "  Hints",             "hint",   0xfffff000, 0xd5032000, COUNT_CLASS},
+    { "  Barriers",          "barr",   0xfffff000, 0xd5033000, COUNT_CLASS},
+    { "  PSTATE",            "psta",   0xfff8f000, 0xd5004000, COUNT_CLASS},
+    { "  System Insn",       "sins",   0xffd80000, 0xd5080000, COUNT_CLASS},
+    { "  System Reg",        "sreg",   0xffd00000, 0xd5100000, COUNT_CLASS},
+    { "  Branch (reg)",      "breg",   0xfe000000, 0xd6000000, COUNT_CLASS},
+    { "  Branch (imm)",      "bimm",   0x7c000000, 0x14000000, COUNT_CLASS},
+    { "  Cmp & Branch",      "cmpb",   0x7e000000, 0x34000000, COUNT_CLASS},
+    { "  Tst & Branch",      "tstb",   0x7e000000, 0x36000000, COUNT_CLASS},
+    { "Branches",            "branch", 0x1c000000, 0x14000000, COUNT_CLASS},
+    /* Loads and Stores */
+    { "  AdvSimd ldstmult",  "advlsm", 0xbfbf0000, 0x0c000000, COUNT_CLASS},
+    { "  AdvSimd ldstmult++","advlsmp",0xbfb00000, 0x0c800000, COUNT_CLASS},
+    { "  AdvSimd ldst",      "advlss", 0xbf9f0000, 0x0d000000, COUNT_CLASS},
+    { "  AdvSimd ldst++",    "advlssp",0xbf800000, 0x0d800000, COUNT_CLASS},
+    { "  ldst excl",         "ldstx",  0x3f000000, 0x08000000, COUNT_CLASS},
+    { "    Prefetch",        "prfm",   0xff000000, 0xd8000000, COUNT_CLASS},
+    { "  Load Reg (lit)",    "ldlit",  0x1b000000, 0x18000000, COUNT_CLASS},
+    { "  ldst noalloc pair", "ldstnap",0x3b800000, 0x28000000, COUNT_CLASS},
+    { "  ldst pair",         "ldstp",  0x38000000, 0x28000000, COUNT_CLASS},
+    { "  ldst reg",          "ldstr",  0x3b200000, 0x38000000, COUNT_CLASS},
+    { "  Atomic ldst",       "atomic", 0x3b200c00, 0x38200000, COUNT_CLASS},
+    { "  ldst reg (reg off)","ldstro", 0x3b200b00, 0x38200800, COUNT_CLASS},
+    { "  ldst reg (pac)",    "ldstpa", 0x3b200200, 0x38200800, COUNT_CLASS},
+    { "  ldst reg (imm)",    "ldsti",  0x3b000000, 0x39000000, COUNT_CLASS},
+    { "Loads & Stores",      "ldst",   0x0a000000, 0x08000000, COUNT_CLASS},
+    /* Data Processing Register */
+    { "Data Proc Reg",       "dprr",   0x0e000000, 0x0a000000, COUNT_CLASS},
+    /* Scalar FP */
+    { "Scalar FP ",          "fpsimd", 0x0e000000, 0x0e000000, COUNT_CLASS},
+    /* Unclassified */
+    { "Unclassified",        "unclas", 0x00000000, 0x00000000, COUNT_CLASS}
+};
+
+static gint cmp_exec_count(gconstpointer a, gconstpointer b)
+{
+    InsnExecCount *ea = (InsnExecCount *) a;
+    InsnExecCount *eb = (InsnExecCount *) b;
+    return ea->count > eb->count ? -1 : 1;
+}
+
+static void plugin_exit(qemu_plugin_id_t id, void *p)
+{
+    GString *report = g_string_new("Instruction Classes:\n");
+    int i;
+    GList *counts;
+
+    for (i = 0; i < ARRAY_SIZE(insn_classes); i++) {
+        switch (insn_classes[i].what) {
+        case COUNT_CLASS:
+            if (insn_classes[i].count || verbose) {
+                g_string_append_printf(report, "Class: %-24s\t(%ld hits)\n",
+                                       insn_classes[i].class,
+                                       insn_classes[i].count);
+            }
+            break;
+        case COUNT_INDIVIDUAL:
+            g_string_append_printf(report, "Class: %-24s\tcounted individually\n",
+                                   insn_classes[i].class);
+            break;
+        case COUNT_NONE:
+            g_string_append_printf(report, "Class: %-24s\tnot counted\n",
+                                   insn_classes[i].class);
+            break;
+        default:
+            break;
+        }
+    }
+
+    counts = g_hash_table_get_values(insns);
+    if (counts && g_list_next(counts)) {
+        GList *it;
+
+        g_string_append_printf(report,"Individual Instructions:\n");
+
+        it = g_list_sort(counts, cmp_exec_count);
+
+        for (i = 0; i < limit && it->next; i++, it = it->next) {
+            InsnExecCount *rec = (InsnExecCount *) it->data;
+            g_string_append_printf(report, "Instr: %-24s\t(%ld hits)\t(op=%#08x/%s)\n",
+                                   rec->insn,
+                                   rec->count,
+                                   rec->opcode,
+                                   rec->class ?
+                                   rec->class->class : "un-categorised");
+        }
+        g_list_free(it);
+    }
+
+    dprintf(stdout_fd, "%s", report->str);
+    g_string_free(report, true);
+}
+
+static void plugin_init(void)
+{
+    insns = g_hash_table_new(NULL, g_direct_equal);
+}
+
+static void vcpu_insn_exec_before(unsigned int cpu_index, void *udata)
+{
+    uint64_t *count = (uint64_t *) udata;
+    (*count)++;
+}
+
+static uint64_t * find_counter(struct qemu_plugin_insn *insn)
+{
+    int i;
+    uint64_t *cnt = NULL;
+    uint32_t opcode;
+    InsnClassExecCount *class = NULL;
+
+    /* we expect all instructions to by 32 bits for ARM */
+    g_assert(qemu_plugin_insn_size(insn) == 4);
+    opcode = *((uint32_t *)qemu_plugin_insn_data(insn));
+
+    for (i = 0; !cnt && i < ARRAY_SIZE(insn_classes); i++) {
+        uint32_t masked_bits = opcode & insn_classes[i].mask;
+        if (masked_bits == insn_classes[i].pattern) {
+            class = &insn_classes[i];
+            break;
+        }
+    }
+
+    g_assert(class);
+
+    switch (class->what) {
+    case COUNT_NONE:
+        return NULL;
+    case COUNT_CLASS:
+        return &class->count;
+    case COUNT_INDIVIDUAL:
+    {
+        InsnExecCount *icount;
+
+        g_mutex_lock(&lock);
+        icount = (InsnExecCount *) g_hash_table_lookup(insns,
+                                                       GUINT_TO_POINTER(opcode));
+
+        if (!icount) {
+            icount = g_new0(InsnExecCount, 1);
+            icount->opcode = opcode;
+            icount->insn = qemu_plugin_insn_disas(insn);
+            icount->class = class;
+
+            if (verbose) {
+                dprintf(stdout_fd, "adding for %s (%#08x @ %#20lx from %s)\n",
+                        icount->insn, opcode, qemu_plugin_insn_vaddr(insn),
+                        class->class);
+            }
+            g_hash_table_insert(insns, GUINT_TO_POINTER(opcode),
+                                (gpointer) icount);
+        }
+        g_mutex_unlock(&lock);
+
+        return &icount->count;
+    }
+    default:
+        g_assert_not_reached();
+    }
+
+    return NULL;
+}
+
+static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
+{
+    size_t n = qemu_plugin_tb_n_insns(tb);
+    size_t i;
+
+    for (i = 0; i < n; i++) {
+        uint64_t *cnt;
+        struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
+        cnt = find_counter(insn);
+
+        if (cnt) {
+            if (do_inline) {
+                qemu_plugin_register_vcpu_insn_exec_inline(
+                    insn, QEMU_PLUGIN_INLINE_ADD_U64, cnt, 1);
+            } else {
+                qemu_plugin_register_vcpu_insn_exec_cb(
+                    insn, vcpu_insn_exec_before, QEMU_PLUGIN_CB_NO_REGS, cnt);
+            }
+        }
+    }
+}
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, int argc,
+                                           char **argv)
+{
+    int i;
+
+    for (i = 0; i < argc; i++) {
+        char *p = argv[i];
+        if (strcmp(p, "inline") == 0) {
+            do_inline = true;
+        } else if (strcmp(p, "verbose") == 0) {
+            verbose = true;
+        } else {
+            int j;
+            CountType type = COUNT_INDIVIDUAL;
+            if (*p == '!') {
+                type = COUNT_NONE;
+                p++;
+            }
+            for (j = 0; j < ARRAY_SIZE(insn_classes); j++) {
+                if (strcmp(p, insn_classes[j].opt) == 0) {
+                    insn_classes[j].what = type;
+                    break;
+                }
+            }
+        }
+    }
+
+    /* to be used when in the exit hook */
+    stdout_fd = dup(STDOUT_FILENO);
+    assert(stdout_fd);
+
+    plugin_init();
+
+    qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
+    qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
+    return 0;
+}
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 51/54] tests/plugin: add hotpages plugin to breakdown memory access patterns
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (49 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 50/54] tests/plugin: add instruction execution breakdown Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 52/54] accel/stubs: reduce headers from tcg-stub Alex Bennée
                   ` (5 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: bobby.prani, cota, Alex Bennée, aaron

This plugin gives a break down of access patterns grouped into pages.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v4
   - tweaks for new hwaddr api
   - add sorting and pagesize selection args
---
 tests/plugin/Makefile   |   1 +
 tests/plugin/hotpages.c | 179 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 180 insertions(+)
 create mode 100644 tests/plugin/hotpages.c

diff --git a/tests/plugin/Makefile b/tests/plugin/Makefile
index 3656429d46b..75467b6db85 100644
--- a/tests/plugin/Makefile
+++ b/tests/plugin/Makefile
@@ -12,6 +12,7 @@ NAMES += insn
 NAMES += mem
 NAMES += hotblocks
 NAMES += howvec
+NAMES += hotpages
 
 SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES)))
 
diff --git a/tests/plugin/hotpages.c b/tests/plugin/hotpages.c
new file mode 100644
index 00000000000..13ce8ffeb8b
--- /dev/null
+++ b/tests/plugin/hotpages.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2019, Alex Bennée <alex.bennee@linaro.org>
+ *
+ * Hot Pages - show which pages saw the most memory accesses.
+ *
+ * License: GNU GPL, version 2 or later.
+ *   See the COPYING file in the top-level directory.
+ */
+
+#include <inttypes.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <glib.h>
+
+#include <qemu-plugin.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+static uint64_t page_size = 4096;
+static uint64_t page_mask;
+static int stdout_fd;
+static int limit = 50;
+static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW;
+
+enum sort_type {
+    SORT_RW = 0,
+    SORT_R,
+    SORT_W
+};
+
+static int sort_by = SORT_RW;
+
+typedef struct {
+    uint64_t page_address;
+    int cpu_read;
+    int cpu_write;
+    uint64_t reads;
+    uint64_t writes;
+} PageCounters;
+
+static GMutex lock;
+static GHashTable *pages;
+
+static gint cmp_access_count(gconstpointer a, gconstpointer b)
+{
+    PageCounters *ea = (PageCounters *) a;
+    PageCounters *eb = (PageCounters *) b;
+    int r;
+    switch (sort_by) {
+    case SORT_RW:
+        r = (ea->reads + ea->writes) > (eb->reads + eb->writes) ? -1 : 1;
+        break;
+    case SORT_R:
+        r = ea->reads > eb->reads ? -1 : 1;
+        break;
+    case SORT_W:
+        r = ea->writes > eb->writes ? -1 : 1;
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    return r;
+}
+
+
+static void plugin_exit(qemu_plugin_id_t id, void *p)
+{
+    GString *report = g_string_new("Addr, RCPUs, Reads, WCPUs, Writes\n");
+    int i;
+    GList *counts;
+
+    counts = g_hash_table_get_values(pages);
+    if (counts && g_list_next(counts)) {
+        GList *it;
+
+        it = g_list_sort(counts, cmp_access_count);
+
+        for (i = 0; i < limit && it->next; i++, it = it->next) {
+            PageCounters *rec = (PageCounters *) it->data;
+            g_string_append_printf(report,
+                                   "%#016"PRIx64", 0x%04x, %"PRId64
+                                   ", 0x%04x, %"PRId64"\n",
+                                   rec->page_address,
+                                   rec->cpu_read, rec->reads,
+                                   rec->cpu_write, rec->writes);
+        }
+        g_list_free(it);
+    }
+
+    dprintf(stdout_fd, "%s", report->str);
+    g_string_free(report, true);
+}
+
+static void plugin_init(void)
+{
+    page_mask = (page_size - 1);
+    pages = g_hash_table_new(NULL, g_direct_equal);
+}
+
+static void vcpu_haddr(unsigned int cpu_index, qemu_plugin_meminfo_t meminfo,
+                       uint64_t vaddr, void *udata)
+{
+    struct qemu_plugin_hwaddr *hwaddr = qemu_plugin_get_hwaddr(meminfo, vaddr);
+    uint64_t page;
+    PageCounters *count;
+
+    /* We only get a hwaddr for system emulation */
+    if (hwaddr) {
+        page = (uint64_t) qemu_plugin_hwaddr_to_raddr(hwaddr);
+    } else {
+        page = vaddr;
+    }
+    page &= ~page_mask;
+
+    g_mutex_lock(&lock);
+    count = (PageCounters *) g_hash_table_lookup(pages, GUINT_TO_POINTER(page));
+
+    if (!count) {
+        count = g_new0(PageCounters, 1);
+        count->page_address = page;
+        g_hash_table_insert(pages, GUINT_TO_POINTER(page), (gpointer) count);
+    }
+    if (qemu_plugin_mem_is_store(meminfo)) {
+        count->writes++;
+        count->cpu_write |= (1 << cpu_index);
+    } else {
+        count->reads++;
+        count->cpu_read |= (1 << cpu_index);
+    }
+
+    g_mutex_unlock(&lock);
+}
+
+static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
+{
+    size_t n = qemu_plugin_tb_n_insns(tb);
+    size_t i;
+
+    for (i = 0; i < n; i++) {
+        struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
+        qemu_plugin_register_vcpu_mem_cb(insn, vcpu_haddr,
+                                         QEMU_PLUGIN_CB_NO_REGS,
+                                         rw, NULL);
+    }
+}
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, int argc,
+                                           char **argv)
+{
+    int i;
+
+    /* to be used when in the exit hook */
+    stdout_fd = dup(STDOUT_FILENO);
+    assert(stdout_fd);
+
+    for (i = 0; i < argc; i++) {
+        char *opt = argv[i];
+        if (g_strcmp0(opt, "reads") == 0) {
+            sort_by = SORT_R;
+        } else if (g_strcmp0(opt, "writes") == 0) {
+            sort_by = SORT_W;
+        } else if (g_str_has_prefix(opt, "pagesize=")) {
+            page_size = g_ascii_strtoull(opt + 9, NULL, 10);
+        } else {
+            dprintf(stdout_fd, "option parsing failed: %s\n", opt);
+            return -1;
+        }
+    }
+
+    plugin_init();
+
+    qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
+    qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
+    return 0;
+}
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 52/54] accel/stubs: reduce headers from tcg-stub
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (50 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 51/54] tests/plugin: add hotpages plugin to breakdown memory access patterns Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 53/54] include/exec: wrap cpu_ldst.h in CONFIG_TCG Alex Bennée
                   ` (4 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: Richard Henderson, aaron, cota, Paolo Bonzini, bobby.prani,
	Alex Bennée, Richard Henderson

We don't need much for these. However I do wonder why these aren't
just null inlines in exec-all.h

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 accel/stubs/tcg-stub.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/accel/stubs/tcg-stub.c b/accel/stubs/tcg-stub.c
index 76ae461749e..431ec7d7e6c 100644
--- a/accel/stubs/tcg-stub.c
+++ b/accel/stubs/tcg-stub.c
@@ -11,10 +11,7 @@
  */
 
 #include "qemu/osdep.h"
-#include "qemu-common.h"
 #include "cpu.h"
-#include "tcg/tcg.h"
-#include "exec/cpu-common.h"
 #include "exec/exec-all.h"
 
 void tb_flush(CPUState *cpu)
-- 
2.20.1



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

* [Qemu-devel] [PATCH v4 53/54] include/exec: wrap cpu_ldst.h in CONFIG_TCG
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (51 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 52/54] accel/stubs: reduce headers from tcg-stub Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-08-01 19:51   ` Richard Henderson
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 54/54] include/exec/cpu-defs.h: fix typo Alex Bennée
                   ` (3 subsequent siblings)
  56 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: aaron, cota, Paolo Bonzini, bobby.prani, Alex Bennée,
	Richard Henderson

This gets around a build problem with --disable-tcg.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/exec/exec-all.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index c42626e35b1..e6b9b460c81 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -21,7 +21,9 @@
 #define EXEC_ALL_H
 
 #include "exec/tb-context.h"
+#ifdef CONFIG_TCG
 #include "exec/cpu_ldst.h"
+#endif
 #include "sysemu/cpus.h"
 
 /* allow to see translation results - the slowdown should be negligible, so we leave it */
-- 
2.20.1



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

* [Qemu-devel] [PATCH  v4 54/54] include/exec/cpu-defs.h: fix typo
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (52 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 53/54] include/exec: wrap cpu_ldst.h in CONFIG_TCG Alex Bennée
@ 2019-07-31 16:07 ` Alex Bennée
  2019-07-31 17:00 ` [Qemu-devel] [PATCH v4 00/54] plugins for TCG no-reply
                   ` (2 subsequent siblings)
  56 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-07-31 16:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: Richard Henderson, aaron, cota, Paolo Bonzini, bobby.prani,
	Alex Bennée, Richard Henderson

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/exec/cpu-defs.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h
index 31deca369ea..355fa817a93 100644
--- a/include/exec/cpu-defs.h
+++ b/include/exec/cpu-defs.h
@@ -233,7 +233,7 @@ typedef struct CPUTLB { } CPUTLB;
 #endif  /* !CONFIG_USER_ONLY && CONFIG_TCG */
 
 /*
- * This structure must be placed in ArchCPU immedately
+ * This structure must be placed in ArchCPU immediately
  * before CPUArchState, as a field named "neg".
  */
 typedef struct CPUNegativeOffsetState {
-- 
2.20.1



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

* Re: [Qemu-devel] [PATCH  v4 00/54] plugins for TCG
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (53 preceding siblings ...)
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 54/54] include/exec/cpu-defs.h: fix typo Alex Bennée
@ 2019-07-31 17:00 ` no-reply
  2019-08-01  4:19 ` Markus Armbruster
  2019-08-01 14:20 ` [Qemu-devel] [PATCH v4 00/54] plugins for TCG no-reply
  56 siblings, 0 replies; 107+ messages in thread
From: no-reply @ 2019-07-31 17:00 UTC (permalink / raw)
  To: alex.bennee; +Cc: bobby.prani, cota, alex.bennee, qemu-devel, aaron

Patchew URL: https://patchew.org/QEMU/20190731160719.11396-1-alex.bennee@linaro.org/



Hi,

This series seems to have some coding style problems. See output below for
more information:

Type: series
Subject: [Qemu-devel] [PATCH  v4 00/54] plugins for TCG
Message-id: 20190731160719.11396-1-alex.bennee@linaro.org

=== TEST SCRIPT BEGIN ===
#!/bin/bash
git rev-parse base > /dev/null || exit 0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
./scripts/checkpatch.pl --mailback base..
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
From https://github.com/patchew-project/qemu
 - [tag update]      patchew/20190731075652.17053-1-thuth@redhat.com -> patchew/20190731075652.17053-1-thuth@redhat.com
 * [new tag]         patchew/20190731160719.11396-1-alex.bennee@linaro.org -> patchew/20190731160719.11396-1-alex.bennee@linaro.org
Submodule 'capstone' (https://git.qemu.org/git/capstone.git) registered for path 'capstone'
Submodule 'dtc' (https://git.qemu.org/git/dtc.git) registered for path 'dtc'
Submodule 'roms/QemuMacDrivers' (https://git.qemu.org/git/QemuMacDrivers.git) registered for path 'roms/QemuMacDrivers'
Submodule 'roms/SLOF' (https://git.qemu.org/git/SLOF.git) registered for path 'roms/SLOF'
Submodule 'roms/edk2' (https://git.qemu.org/git/edk2.git) registered for path 'roms/edk2'
Submodule 'roms/ipxe' (https://git.qemu.org/git/ipxe.git) registered for path 'roms/ipxe'
Submodule 'roms/openbios' (https://git.qemu.org/git/openbios.git) registered for path 'roms/openbios'
Submodule 'roms/openhackware' (https://git.qemu.org/git/openhackware.git) registered for path 'roms/openhackware'
Submodule 'roms/opensbi' (https://git.qemu.org/git/opensbi.git) registered for path 'roms/opensbi'
Submodule 'roms/qemu-palcode' (https://git.qemu.org/git/qemu-palcode.git) registered for path 'roms/qemu-palcode'
Submodule 'roms/seabios' (https://git.qemu.org/git/seabios.git/) registered for path 'roms/seabios'
Submodule 'roms/seabios-hppa' (https://git.qemu.org/git/seabios-hppa.git) registered for path 'roms/seabios-hppa'
Submodule 'roms/sgabios' (https://git.qemu.org/git/sgabios.git) registered for path 'roms/sgabios'
Submodule 'roms/skiboot' (https://git.qemu.org/git/skiboot.git) registered for path 'roms/skiboot'
Submodule 'roms/u-boot' (https://git.qemu.org/git/u-boot.git) registered for path 'roms/u-boot'
Submodule 'roms/u-boot-sam460ex' (https://git.qemu.org/git/u-boot-sam460ex.git) registered for path 'roms/u-boot-sam460ex'
Submodule 'slirp' (https://git.qemu.org/git/libslirp.git) registered for path 'slirp'
Submodule 'tests/fp/berkeley-softfloat-3' (https://git.qemu.org/git/berkeley-softfloat-3.git) registered for path 'tests/fp/berkeley-softfloat-3'
Submodule 'tests/fp/berkeley-testfloat-3' (https://git.qemu.org/git/berkeley-testfloat-3.git) registered for path 'tests/fp/berkeley-testfloat-3'
Submodule 'ui/keycodemapdb' (https://git.qemu.org/git/keycodemapdb.git) registered for path 'ui/keycodemapdb'
Cloning into 'capstone'...
Submodule path 'capstone': checked out '22ead3e0bfdb87516656453336160e0a37b066bf'
Cloning into 'dtc'...
Submodule path 'dtc': checked out '88f18909db731a627456f26d779445f84e449536'
Cloning into 'roms/QemuMacDrivers'...
Submodule path 'roms/QemuMacDrivers': checked out '90c488d5f4a407342247b9ea869df1c2d9c8e266'
Cloning into 'roms/SLOF'...
Submodule path 'roms/SLOF': checked out 'ba1ab360eebe6338bb8d7d83a9220ccf7e213af3'
Cloning into 'roms/edk2'...
Submodule path 'roms/edk2': checked out '20d2e5a125e34fc8501026613a71549b2a1a3e54'
Submodule 'SoftFloat' (https://github.com/ucb-bar/berkeley-softfloat-3.git) registered for path 'ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3'
Submodule 'CryptoPkg/Library/OpensslLib/openssl' (https://github.com/openssl/openssl) registered for path 'CryptoPkg/Library/OpensslLib/openssl'
Cloning into 'ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3'...
Submodule path 'roms/edk2/ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3': checked out 'b64af41c3276f97f0e181920400ee056b9c88037'
Cloning into 'CryptoPkg/Library/OpensslLib/openssl'...
Submodule path 'roms/edk2/CryptoPkg/Library/OpensslLib/openssl': checked out '50eaac9f3337667259de725451f201e784599687'
Submodule 'boringssl' (https://boringssl.googlesource.com/boringssl) registered for path 'boringssl'
Submodule 'krb5' (https://github.com/krb5/krb5) registered for path 'krb5'
Submodule 'pyca.cryptography' (https://github.com/pyca/cryptography.git) registered for path 'pyca-cryptography'
Cloning into 'boringssl'...
Submodule path 'roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl': checked out '2070f8ad9151dc8f3a73bffaa146b5e6937a583f'
Cloning into 'krb5'...
Submodule path 'roms/edk2/CryptoPkg/Library/OpensslLib/openssl/krb5': checked out 'b9ad6c49505c96a088326b62a52568e3484f2168'
Cloning into 'pyca-cryptography'...
Submodule path 'roms/edk2/CryptoPkg/Library/OpensslLib/openssl/pyca-cryptography': checked out '09403100de2f6f1cdd0d484dcb8e620f1c335c8f'
Cloning into 'roms/ipxe'...
Submodule path 'roms/ipxe': checked out 'de4565cbe76ea9f7913a01f331be3ee901bb6e17'
Cloning into 'roms/openbios'...
Submodule path 'roms/openbios': checked out 'c79e0ecb84f4f1ee3f73f521622e264edd1bf174'
Cloning into 'roms/openhackware'...
Submodule path 'roms/openhackware': checked out 'c559da7c8eec5e45ef1f67978827af6f0b9546f5'
Cloning into 'roms/opensbi'...
Submodule path 'roms/opensbi': checked out 'ce228ee0919deb9957192d723eecc8aaae2697c6'
Cloning into 'roms/qemu-palcode'...
Submodule path 'roms/qemu-palcode': checked out 'bf0e13698872450164fa7040da36a95d2d4b326f'
Cloning into 'roms/seabios'...
Submodule path 'roms/seabios': checked out 'a5cab58e9a3fb6e168aba919c5669bea406573b4'
Cloning into 'roms/seabios-hppa'...
Submodule path 'roms/seabios-hppa': checked out '0f4fe84658165e96ce35870fd19fc634e182e77b'
Cloning into 'roms/sgabios'...
Submodule path 'roms/sgabios': checked out 'cbaee52287e5f32373181cff50a00b6c4ac9015a'
Cloning into 'roms/skiboot'...
Submodule path 'roms/skiboot': checked out '261ca8e779e5138869a45f174caa49be6a274501'
Cloning into 'roms/u-boot'...
Submodule path 'roms/u-boot': checked out 'd3689267f92c5956e09cc7d1baa4700141662bff'
Cloning into 'roms/u-boot-sam460ex'...
Submodule path 'roms/u-boot-sam460ex': checked out '60b3916f33e617a815973c5a6df77055b2e3a588'
Cloning into 'slirp'...
Submodule path 'slirp': checked out 'f0da6726207b740f6101028b2992f918477a4b08'
Cloning into 'tests/fp/berkeley-softfloat-3'...
Submodule path 'tests/fp/berkeley-softfloat-3': checked out 'b64af41c3276f97f0e181920400ee056b9c88037'
Cloning into 'tests/fp/berkeley-testfloat-3'...
Submodule path 'tests/fp/berkeley-testfloat-3': checked out '5a59dcec19327396a011a17fd924aed4fec416b3'
Cloning into 'ui/keycodemapdb'...
Submodule path 'ui/keycodemapdb': checked out '6b3d716e2b6472eb7189d3220552280ef3d832ce'
Switched to a new branch 'test'
4618434 include/exec/cpu-defs.h: fix typo
d260302 include/exec: wrap cpu_ldst.h in CONFIG_TCG
4a08e81 accel/stubs: reduce headers from tcg-stub
dc047a8 tests/plugin: add hotpages plugin to breakdown memory access patterns
0031177 tests/plugin: add instruction execution breakdown
bd83073 plugin: add qemu_plugin_insn_disas helper
719f27a tests/plugin: add a hotblocks plugin
0c2193f tests/tcg: enable plugin testing
4fda032 tests/plugin: add sample plugins
fd7f586 linux-user: support -plugin option
b484c3f vl: support -plugin option
720fb2d plugin: add API symbols to qemu-plugins.symbols
75048c5 translator: inject instrumentation from plugins
90d92af target/openrisc: fetch code with translator_ld
bf3c443 target/xtensa: fetch code with translator_ld
1b3b92b target/sparc: fetch code with translator_ld
f41eb29 target/riscv: fetch code with translator_ld
35e338c target/alpha: fetch code with translator_ld
9014aab target/m68k: fetch code with translator_ld
604625d target/hppa: fetch code with translator_ld
f86b279 target/i386: fetch code with translator_ld
5bfcc20 target/sh4: fetch code with translator_ld
65656f9 target/ppc: fetch code with translator_ld
1338aac target/arm: fetch code with translator_ld
6ad7980 translator: add translator_ld{ub, sw, uw, l, q}
123a7b0 plugin-gen: add plugin_insn_append
2fc0fb1 cpu: hook plugin vcpu events
2ad986c *-user: plugin syscalls
12cf148 *-user: notify plugin of exit
5ef3c3d translate-all: notify plugin code of tb_flush
ceffbf5 plugins: implement helpers for resolving hwaddr
bfd0bef tcg: let plugins instrument virtual memory accesses
8c70962 atomic_template: add inline trace/plugin helpers
b6d0321 atomic_template: fix indentation in GEN_ATOMIC_HELPER
59e11a6 plugin-gen: add module for TCG-related code
b7ff8fb tcg: add tcg_gen_st_ptr
57dce44 cputlb: introduce get_page_addr_code_hostp
c21fd8d cputlb: document get_page_addr_code
0156ea7 queue: add QTAILQ_REMOVE_SEVERAL
98bb420 plugin: add implementation of the api
90dff04 plugin: add core code
dfc8157 plugin: add user-facing API
c508aec configure: add --enable-plugins (MOVE TO END)
efd9ca8 docs/devel: add plugins.rst design document
7e445c2 translate-all: use cpu_in_exclusive_work_context() in tb_flush
e3927dd cpu: introduce cpu_in_exclusive_context()
2c1c22b tcg/README: fix typo s/afterwise/afterwards/
0082b05 trace: add mmu_index to mem_info
43a9cd6 trace: expand mem_info:size_shift to 4 bits
92f8098 includes: remove stale [smp|max]_cpus externs
b12d00f target/arm: remove run time semihosting checks
3964cfe target/arm: handle A-profile A32 semihosting at translate time
354ccbf target/arm: handle A-profile T32 semihosting at translate time
c736511 target/arm: handle M-profile semihosting at translate time

=== OUTPUT BEGIN ===
1/54 Checking commit c736511afb73 (target/arm: handle M-profile semihosting at translate time)
2/54 Checking commit 354ccbf7836a (target/arm: handle A-profile T32 semihosting at translate time)
3/54 Checking commit 3964cfed151e (target/arm: handle A-profile A32 semihosting at translate time)
4/54 Checking commit b12d00f866ff (target/arm: remove run time semihosting checks)
5/54 Checking commit 92f80985c6b7 (includes: remove stale [smp|max]_cpus externs)
6/54 Checking commit 43a9cd64afe9 (trace: expand mem_info:size_shift to 4 bits)
7/54 Checking commit 0082b05e9d82 (trace: add mmu_index to mem_info)
ERROR: line over 90 characters
#24: FILE: accel/tcg/atomic_template.h:63:
+        uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false, ATOMIC_MMU_IDX); \

ERROR: line over 90 characters
#33: FILE: accel/tcg/atomic_template.h:71:
+        uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false, ATOMIC_MMU_IDX); \

ERROR: line over 90 characters
#40: FILE: accel/tcg/atomic_template.h:77:
+        uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, true, ATOMIC_MMU_IDX); \

WARNING: line over 80 characters
#321: FILE: trace/mem.h:21:
+static uint16_t trace_mem_get_info(TCGMemOp op, unsigned int mmu_idx, bool store);

total: 3 errors, 1 warnings, 261 lines checked

Patch 7/54 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

8/54 Checking commit 2c1c22bc16e9 (tcg/README: fix typo s/afterwise/afterwards/)
9/54 Checking commit e3927dda7720 (cpu: introduce cpu_in_exclusive_context())
10/54 Checking commit 7e445c2738b4 (translate-all: use cpu_in_exclusive_work_context() in tb_flush)
11/54 Checking commit efd9ca87d2ad (docs/devel: add plugins.rst design document)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#24: 
new file mode 100644

total: 0 errors, 1 warnings, 111 lines checked

Patch 11/54 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
12/54 Checking commit c508aec11118 (configure: add --enable-plugins (MOVE TO END))
13/54 Checking commit dfc81576c19a (plugin: add user-facing API)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#15: 
new file mode 100644

WARNING: architecture specific defines should be avoided
#41: FILE: include/qemu/qemu-plugin.h:22:
+#if defined _WIN32 || defined __CYGWIN__

WARNING: architecture specific defines should be avoided
#49: FILE: include/qemu/qemu-plugin.h:30:
+  #if __GNUC__ >= 4

total: 0 errors, 3 warnings, 351 lines checked

Patch 13/54 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
14/54 Checking commit 90dff041feaf (plugin: add core code)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#54: 
new file mode 100644

ERROR: "foo * bar" should be "foo *bar"
#190: FILE: include/qemu/plugin.h:132:
+static inline struct qemu_plugin_insn * qemu_plugin_insn_alloc(void)

ERROR: named QLIST_HEAD should be typedefed separately
#399: FILE: plugins/core.c:37:
+QLIST_HEAD(qemu_plugin_cb_head, qemu_plugin_cb);

WARNING: line over 80 characters
#618: FILE: plugins/core.c:256:
+        cbs = g_array_sized_new(false, false, sizeof(struct qemu_plugin_dyn_cb), 1);

WARNING: Block comments use a leading /* on a separate line
#909: FILE: plugins/loader.c:42:
+        { /* end of list */ }

ERROR: externs should be avoided in .c files
#915: FILE: plugins/loader.c:48:
+extern struct qemu_plugin_state plugin;

total: 3 errors, 3 warnings, 1261 lines checked

Patch 14/54 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

15/54 Checking commit 98bb4205f8d1 (plugin: add implementation of the api)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#22: 
new file mode 100644

ERROR: if this code is redundant consider removing it
#282: FILE: plugins/api.c:256:
+#if 0 /* XXX FIXME should be SOFTMMU */

ERROR: "foo * bar" should be "foo *bar"
#303: FILE: plugins/api.c:277:
+static MachineState * get_ms(void)

total: 2 errors, 1 warnings, 303 lines checked

Patch 15/54 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

16/54 Checking commit 0156ea779e67 (queue: add QTAILQ_REMOVE_SEVERAL)
WARNING: Block comments use a leading /* on a separate line
#31: FILE: include/qemu/queue.h:433:
+    } while (/*CONSTCOND*/0)

total: 0 errors, 1 warnings, 16 lines checked

Patch 16/54 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
17/54 Checking commit c21fd8dfb8e0 (cputlb: document get_page_addr_code)
18/54 Checking commit 57dce445a292 (cputlb: introduce get_page_addr_code_hostp)
19/54 Checking commit b7ff8fb737a6 (tcg: add tcg_gen_st_ptr)
20/54 Checking commit 59e11a6c6781 (plugin-gen: add module for TCG-related code)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#48: 
new file mode 100644

ERROR: if this code is redundant consider removing it
#420: FILE: accel/tcg/plugin-gen.c:368:
+#if 0 /* XXX: no longer needed? */

total: 1 errors, 1 warnings, 1168 lines checked

Patch 20/54 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

21/54 Checking commit b6d032138a56 (atomic_template: fix indentation in GEN_ATOMIC_HELPER)
22/54 Checking commit 8c70962547d5 (atomic_template: add inline trace/plugin helpers)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#15: 
new file mode 100644

total: 0 errors, 1 warnings, 296 lines checked

Patch 22/54 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
23/54 Checking commit bfd0bef6abd9 (tcg: let plugins instrument virtual memory accesses)
WARNING: line over 80 characters
#171: FILE: include/exec/cpu_ldst_template.h:91:
+    uint16_t meminfo = trace_mem_build_info(SHIFT, false, MO_TE, false, mmu_idx);

total: 0 errors, 1 warnings, 372 lines checked

Patch 23/54 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
24/54 Checking commit ceffbf57661b (plugins: implement helpers for resolving hwaddr)
25/54 Checking commit 5ef3c3d45dd0 (translate-all: notify plugin code of tb_flush)
26/54 Checking commit 12cf1480ae24 (*-user: notify plugin of exit)
27/54 Checking commit 2ad986cc69bd (*-user: plugin syscalls)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#93: 
new file mode 100644

total: 0 errors, 1 warnings, 127 lines checked

Patch 27/54 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
28/54 Checking commit 2fc0fb11c7c5 (cpu: hook plugin vcpu events)
29/54 Checking commit 123a7b0c3078 (plugin-gen: add plugin_insn_append)
30/54 Checking commit 6ad7980f6247 (translator: add translator_ld{ub, sw, uw, l, q})
ERROR: Macros with multiple statements should be enclosed in a do - while loop
#76: FILE: include/exec/translator.h:161:
+#define DO_LOAD(type, name, shift)               \
+    set_helper_retaddr(1);                       \
+    ret = name ## _p(g2h(pc));                   \
+    clear_helper_retaddr();

WARNING: Block comments use a leading /* on a separate line
#109: FILE: include/exec/translator.h:194:
+GEN_TRANSLATOR_LD(translator_ldub, ldb, uint8_t, 1, /* no swap needed */)

total: 1 errors, 1 warnings, 116 lines checked

Patch 30/54 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

31/54 Checking commit 1338aac82722 (target/arm: fetch code with translator_ld)
32/54 Checking commit 65656f9c3eea (target/ppc: fetch code with translator_ld)
33/54 Checking commit 5bfcc20d11c6 (target/sh4: fetch code with translator_ld)
34/54 Checking commit f86b27916216 (target/i386: fetch code with translator_ld)
35/54 Checking commit 604625d4780e (target/hppa: fetch code with translator_ld)
36/54 Checking commit 9014aab24680 (target/m68k: fetch code with translator_ld)
37/54 Checking commit 35e338c60b8f (target/alpha: fetch code with translator_ld)
38/54 Checking commit f41eb298b626 (target/riscv: fetch code with translator_ld)
39/54 Checking commit 1b3b92b10053 (target/sparc: fetch code with translator_ld)
40/54 Checking commit bf3c443ec239 (target/xtensa: fetch code with translator_ld)
41/54 Checking commit 90d92af84114 (target/openrisc: fetch code with translator_ld)
42/54 Checking commit 75048c56cd83 (translator: inject instrumentation from plugins)
43/54 Checking commit 720fb2d03f34 (plugin: add API symbols to qemu-plugins.symbols)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#120: 
new file mode 100644

total: 0 errors, 1 warnings, 151 lines checked

Patch 43/54 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
44/54 Checking commit b484c3fd133c (vl: support -plugin option)
45/54 Checking commit fd7f58630fad (linux-user: support -plugin option)
46/54 Checking commit 4fda03223154 (tests/plugin: add sample plugins)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#36: 
new file mode 100644

total: 0 errors, 1 warnings, 296 lines checked

Patch 46/54 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
47/54 Checking commit 0c2193fd7aa2 (tests/tcg: enable plugin testing)
48/54 Checking commit 719f27a8e85d (tests/plugin: add a hotblocks plugin)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#32: 
new file mode 100644

total: 0 errors, 1 warnings, 153 lines checked

Patch 48/54 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
49/54 Checking commit bd8307360460 (plugin: add qemu_plugin_insn_disas helper)
ERROR: "foo * bar" should be "foo *bar"
#74: FILE: disas.c:530:
+char * plugin_disas(CPUState *cpu, uint64_t addr, size_t size)

ERROR: "foo * bar" should be "foo *bar"
#136: FILE: include/disas/disas.h:16:
+char * plugin_disas(CPUState *cpu, uint64_t addr, size_t size);

ERROR: "foo * bar" should be "foo *bar"
#155: FILE: include/qemu/qemu-plugin.h:334:
+char * qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn);

total: 3 errors, 0 warnings, 158 lines checked

Patch 49/54 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

50/54 Checking commit 0031177b24bf (tests/plugin: add instruction execution breakdown)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#26: 
new file mode 100644

ERROR: space required after that ',' (ctx:VxV)
#99: FILE: tests/plugin/howvec.c:69:
+    { "  Add/Sub (imm,tags)","asit",   0x1f800000, 0x11800000, COUNT_CLASS},
                             ^

ERROR: space required after that ',' (ctx:VxV)
#122: FILE: tests/plugin/howvec.c:92:
+    { "  AdvSimd ldstmult++","advlsmp",0xbfb00000, 0x0c800000, COUNT_CLASS},
                             ^

ERROR: space required after that ',' (ctx:VxV)
#122: FILE: tests/plugin/howvec.c:92:
+    { "  AdvSimd ldstmult++","advlsmp",0xbfb00000, 0x0c800000, COUNT_CLASS},
                                       ^

ERROR: space required after that ',' (ctx:VxV)
#124: FILE: tests/plugin/howvec.c:94:
+    { "  AdvSimd ldst++",    "advlssp",0xbf800000, 0x0d800000, COUNT_CLASS},
                                       ^

ERROR: space required after that ',' (ctx:VxV)
#128: FILE: tests/plugin/howvec.c:98:
+    { "  ldst noalloc pair", "ldstnap",0x3b800000, 0x28000000, COUNT_CLASS},
                                       ^

ERROR: space required after that ',' (ctx:VxV)
#132: FILE: tests/plugin/howvec.c:102:
+    { "  ldst reg (reg off)","ldstro", 0x3b200b00, 0x38200800, COUNT_CLASS},
                             ^

WARNING: line over 80 characters
#167: FILE: tests/plugin/howvec.c:137:
+            g_string_append_printf(report, "Class: %-24s\tcounted individually\n",

ERROR: space required after that ',' (ctx:VxV)
#183: FILE: tests/plugin/howvec.c:153:
+        g_string_append_printf(report,"Individual Instructions:\n");
                                      ^

WARNING: line over 80 characters
#189: FILE: tests/plugin/howvec.c:159:
+            g_string_append_printf(report, "Instr: %-24s\t(%ld hits)\t(op=%#08x/%s)\n",

ERROR: "foo * bar" should be "foo *bar"
#214: FILE: tests/plugin/howvec.c:184:
+static uint64_t * find_counter(struct qemu_plugin_insn *insn)

WARNING: line over 80 characters
#246: FILE: tests/plugin/howvec.c:216:
+                                                       GUINT_TO_POINTER(opcode));

total: 8 errors, 4 warnings, 308 lines checked

Patch 50/54 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

51/54 Checking commit dc047a82f004 (tests/plugin: add hotpages plugin to breakdown memory access patterns)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#26: 
new file mode 100644

total: 0 errors, 1 warnings, 186 lines checked

Patch 51/54 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
52/54 Checking commit 4a08e81629be (accel/stubs: reduce headers from tcg-stub)
53/54 Checking commit d260302d62f5 (include/exec: wrap cpu_ldst.h in CONFIG_TCG)
54/54 Checking commit 4618434e2366 (include/exec/cpu-defs.h: fix typo)
=== OUTPUT END ===

Test command exited with code: 1


The full log is available at
http://patchew.org/logs/20190731160719.11396-1-alex.bennee@linaro.org/testing.checkpatch/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

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

* Re: [Qemu-devel] [PATCH  v4 00/54] plugins for TCG
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (54 preceding siblings ...)
  2019-07-31 17:00 ` [Qemu-devel] [PATCH v4 00/54] plugins for TCG no-reply
@ 2019-08-01  4:19 ` Markus Armbruster
  2019-09-06 19:52   ` Alex Bennée
  2019-08-01 14:20 ` [Qemu-devel] [PATCH v4 00/54] plugins for TCG no-reply
  56 siblings, 1 reply; 107+ messages in thread
From: Markus Armbruster @ 2019-08-01  4:19 UTC (permalink / raw)
  To: Alex Bennée; +Cc: bobby.prani, cota, qemu-devel, aaron

Alex Bennée <alex.bennee@linaro.org> writes:

> Hi,
>
> This is the latest iteration of the plugins series. The main changes
> from the last version are:
>
>   - dropped passing of haddr to plugins
>
> This makes the code for handling the plugins less invasive in the
> softmmu path at the cost of offloading processing to the plugin if it
> wants the value. We rely on the fact that the TLB is per vCPU so a
> helper can just trigger a re-query of the TLB to get the final
> address.
>
> Part of that change involved embedding the MMU index in the meminfo
> field for tracing. I see there are some other patches on the list for
> messing with TCGMemOp so there might be a clash coming up.
>
>   - translator_ld goes direct to softmmu/user functions
>
> I also mark the [SOFTMMU_]CODE_ACCESS helpers as deprecated. There is
> more work to be done to clean up all the current uses of code access
> helpers but ideally the only thing that should be peaking at code is
> the translator loop itself. However a bunch of helpers have taken to
> using code loading functions to peak at the instruction just executed
> to figure out what to do. Once those have been fixed then we can
> remove those helpers.
>
> Other more minor fixes can be found documented bellow the --- in the
> individual patches.
>
> This series also includes the semihosting patches as they are a
> pre-requisite for the translator_ld patches for ARM.
>
> Once the tree opens up for development again I hope to get the
> semihosting and trivial clean-up patches merged quickly so the patch
> count for the plugins patches proper can be reduced a bit.

Next time, please explain briefly what TCG plugins are about right in
your cover letter.  I had to go hunting for this.  Found "[PATCH v4
11/54] docs/devel: add plugins.rst design document".

Please advise why TCG plugins don't undermine the GPL.  Any proposal to
add a plugin interface needs to do that.


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

* Re: [Qemu-devel] [PATCH v4 04/54] target/arm: remove run time semihosting checks
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 04/54] target/arm: remove run time semihosting checks Alex Bennée
@ 2019-08-01 13:27   ` Aaron Lindsay OS via Qemu-devel
  2019-08-01 13:36     ` Peter Maydell
  2019-08-01 14:53   ` Richard Henderson
  1 sibling, 1 reply; 107+ messages in thread
From: Aaron Lindsay OS via Qemu-devel @ 2019-08-01 13:27 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Peter Maydell, bobby.prani, cota, qemu-devel, open list:ARM TCG CPUs

On Jul 31 17:06, Alex Bennée wrote:
> Now we do all our checking and use a common EXCP_SEMIHOST for
> semihosting operations we can make helper code a lot simpler.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> 
> ---
> v2
>   - fix re-base conflicts
>   - hoist EXCP_SEMIHOST check
>   - comment cleanups
> ---
>  target/arm/helper.c | 90 +++++++++------------------------------------
>  1 file changed, 18 insertions(+), 72 deletions(-)
> 
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index b74c23a9bc0..c5b90a83d36 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -8259,86 +8259,30 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
>                    new_el, env->pc, pstate_read(env));
>  }
>  
> -static inline bool check_for_semihosting(CPUState *cs)
> +/*
> + * Do semihosting call and set the appropriate return value. All the
> + * permission and validity checks have been done at translate time.
> + *
> + * We only see semihosting exceptions in TCG only as they are not
> + * trapped to the hypervisor in KVM.
> + */
> +static void handle_semihosting(CPUState *cs)
>  {
>  #ifdef CONFIG_TCG
> -    /* Check whether this exception is a semihosting call; if so
> -     * then handle it and return true; otherwise return false.
> -     */
>      ARMCPU *cpu = ARM_CPU(cs);
>      CPUARMState *env = &cpu->env;
>  
>      if (is_a64(env)) {
> -        if (cs->exception_index == EXCP_SEMIHOST) {
> -            /* This is always the 64-bit semihosting exception.
> -             * The "is this usermode" and "is semihosting enabled"
> -             * checks have been done at translate time.
> -             */
> -            qemu_log_mask(CPU_LOG_INT,
> -                          "...handling as semihosting call 0x%" PRIx64 "\n",
> -                          env->xregs[0]);
> -            env->xregs[0] = do_arm_semihosting(env);
> -            return true;
> -        }
> -        return false;
> +        qemu_log_mask(CPU_LOG_INT,
> +                      "...handling as semihosting call 0x%" PRIx64 "\n",
> +                      env->xregs[0]);
> +        env->xregs[0] = do_arm_semihosting(env);
>      } else {
> -        uint32_t imm;
> -
> -        /* Only intercept calls from privileged modes, to provide some
> -         * semblance of security.
> -         */
> -        if (cs->exception_index != EXCP_SEMIHOST &&
> -            (!semihosting_enabled() ||
> -             ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR))) {
> -            return false;
> -        }
> -
> -        switch (cs->exception_index) {
> -        case EXCP_SEMIHOST:
> -            /* This is always a semihosting call; the "is this usermode"
> -             * and "is semihosting enabled" checks have been done at
> -             * translate time.
> -             */
> -            break;
> -        case EXCP_SWI:
> -            /* Check for semihosting interrupt.  */
> -            if (env->thumb) {
> -                imm = arm_lduw_code(env, env->regs[15] - 2, arm_sctlr_b(env))
> -                    & 0xff;
> -                if (imm == 0xab) {
> -                    break;
> -                }
> -            } else {
> -                imm = arm_ldl_code(env, env->regs[15] - 4, arm_sctlr_b(env))
> -                    & 0xffffff;
> -                if (imm == 0x123456) {
> -                    break;
> -                }
> -            }
> -            return false;
> -        case EXCP_BKPT:
> -            /* See if this is a semihosting syscall.  */
> -            if (env->thumb) {
> -                imm = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env))
> -                    & 0xff;
> -                if (imm == 0xab) {
> -                    env->regs[15] += 2;
> -                    break;
> -                }
> -            }
> -            return false;
> -        default:
> -            return false;
> -        }
> -
>          qemu_log_mask(CPU_LOG_INT,
>                        "...handling as semihosting call 0x%x\n",
>                        env->regs[0]);
>          env->regs[0] = do_arm_semihosting(env);
> -        return true;
>      }
> -#else
> -    return false;
>  #endif
>  }
>  
> @@ -8371,11 +8315,13 @@ void arm_cpu_do_interrupt(CPUState *cs)
>          return;
>      }
>  
> -    /* Semihosting semantics depend on the register width of the
> -     * code that caused the exception, not the target exception level,
> -     * so must be handled here.
> +    /*
> +     * Semihosting semantics depend on the register width of the code
> +     * that caused the exception, not the target exception level, so
> +     * must be handled here.
>       */
> -    if (check_for_semihosting(cs)) {
> +    if (cs->exception_index == EXCP_SEMIHOST) {
> +        handle_semihosting(cs);
>          return;
>      }

Previously, this code would never return here if CONFIG_TCG was not
defined because check_for_semihosting() always returned false in that
case. Is it now true that `cs->exception_index` will never hold a value
of EXCP_SEMIHOST if CONFIG_TCG is not defined (or that it is otherwise
correct to return here in that case where it wasn't previously)?

-Aaron


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

* Re: [Qemu-devel] [PATCH v4 04/54] target/arm: remove run time semihosting checks
  2019-08-01 13:27   ` Aaron Lindsay OS via Qemu-devel
@ 2019-08-01 13:36     ` Peter Maydell
  0 siblings, 0 replies; 107+ messages in thread
From: Peter Maydell @ 2019-08-01 13:36 UTC (permalink / raw)
  To: Aaron Lindsay OS
  Cc: bobby.prani, cota, Alex Bennée, qemu-devel, open list:ARM TCG CPUs

On Thu, 1 Aug 2019 at 14:27, Aaron Lindsay OS
<aaron@os.amperecomputing.com> wrote:
>
> On Jul 31 17:06, Alex Bennée wrote:

> > @@ -8371,11 +8315,13 @@ void arm_cpu_do_interrupt(CPUState *cs)
> >          return;
> >      }
> >
> > -    /* Semihosting semantics depend on the register width of the
> > -     * code that caused the exception, not the target exception level,
> > -     * so must be handled here.
> > +    /*
> > +     * Semihosting semantics depend on the register width of the code
> > +     * that caused the exception, not the target exception level, so
> > +     * must be handled here.
> >       */
> > -    if (check_for_semihosting(cs)) {
> > +    if (cs->exception_index == EXCP_SEMIHOST) {
> > +        handle_semihosting(cs);
> >          return;
> >      }
>
> Previously, this code would never return here if CONFIG_TCG was not
> defined because check_for_semihosting() always returned false in that
> case. Is it now true that `cs->exception_index` will never hold a value
> of EXCP_SEMIHOST if CONFIG_TCG is not defined (or that it is otherwise
> correct to return here in that case where it wasn't previously)?

It's always true that cs->exception_index can't be EXCP_SEMIHOST
here if we're not using TCG, because the only way you can get into
this function other than by using TCG is the call in
kvm_arm_handle_debug(), which sets exception_index beforehand.
More generally, we only call this function in non-TCG if we're
trying to manually configure the CPU state to simulate a guest
exception entry, and that will always be done by setting up the
exception_index to the kind of exception we're simulating before
the call. EXCP_SEMIHOST isn't a real exception so that should never
happen (you could argue that we should assert, I suppose).

thanks
-- PMM


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

* Re: [Qemu-devel] [PATCH v4 24/54] plugins: implement helpers for resolving hwaddr
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 24/54] plugins: implement helpers for resolving hwaddr Alex Bennée
@ 2019-08-01 14:14   ` Aaron Lindsay OS via Qemu-devel
  2019-08-01 18:37     ` Richard Henderson
  2019-10-09 17:45     ` Alex Bennée
  0 siblings, 2 replies; 107+ messages in thread
From: Aaron Lindsay OS via Qemu-devel @ 2019-08-01 14:14 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Paolo Bonzini, bobby.prani, cota, qemu-devel, Richard Henderson

On Jul 31 17:06, Alex Bennée wrote:
> We need to keep a local per-cpu copy of the data as other threads may
> be running. We use a automatically growing array and re-use the space
> for subsequent queries.

[...]

> +bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx,
> +                       bool is_store, struct qemu_plugin_hwaddr *data)
> +{
> +    CPUArchState *env = cpu->env_ptr;
> +    CPUTLBEntry *tlbe = tlb_entry(env, mmu_idx, addr);
> +    target_ulong tlb_addr = is_store ? tlb_addr_write(tlbe) : tlbe->addr_read;
> +
> +    if (tlb_hit(tlb_addr, addr)) {
> +        if (tlb_addr & TLB_MMIO) {
> +            data->hostaddr = 0;
> +            data->is_io = true;
> +            /* XXX: lookup device */
> +        } else {
> +            data->hostaddr = addr + tlbe->addend;
> +            data->is_io = false;
> +        }
> +        return true;
> +    }
> +    return false;
> +}

In what cases do you expect tlb_hit() should not evaluate to true here?
Will returns of false only be in error cases, or do you expect it can
occur during normal operation? In particular, I'm interested in ensuring
this is as reliable as possible, since some plugins may require physical
addresses.

> +struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
> +                                                  uint64_t vaddr)
> +{
> +    CPUState *cpu = current_cpu;
> +    unsigned int mmu_idx = info >> TRACE_MEM_MMU_SHIFT;
> +    struct qemu_plugin_hwaddr *hwaddr;
> +
> +    /* Ensure we have memory allocated for this work */
> +    if (!hwaddr_refs) {
> +        hwaddr_refs = g_array_sized_new(false, true,
> +                                        sizeof(struct qemu_plugin_hwaddr),
> +                                        cpu->cpu_index + 1);
> +    } else if (cpu->cpu_index >= hwaddr_refs->len) {
> +        hwaddr_refs = g_array_set_size(hwaddr_refs, cpu->cpu_index + 1);
> +    }

Are there one or more race conditions with the allocations here? If so,
could they be solved by doing the allocations at plugin initialization
and when the number of online cpu's changes, instead of lazily?

>  uint64_t qemu_plugin_hwaddr_to_raddr(const struct qemu_plugin_hwaddr *haddr)

I was at first confused about the utility of this function until I
(re-?)discovered you had to convert first to hwaddr and then raddr to
get a "true" physical address. Perhaps that could be added to a comment
here or in the API definition in the main plugin header file.

-Aaron


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

* Re: [Qemu-devel] [PATCH  v4 00/54] plugins for TCG
  2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
                   ` (55 preceding siblings ...)
  2019-08-01  4:19 ` Markus Armbruster
@ 2019-08-01 14:20 ` no-reply
  56 siblings, 0 replies; 107+ messages in thread
From: no-reply @ 2019-08-01 14:20 UTC (permalink / raw)
  To: alex.bennee; +Cc: bobby.prani, cota, alex.bennee, qemu-devel, aaron

Patchew URL: https://patchew.org/QEMU/20190731160719.11396-1-alex.bennee@linaro.org/



Hi,

This series failed the asan build test. Please find the testing commands and
their output below. If you have Docker installed, you can probably reproduce it
locally.

=== TEST SCRIPT BEGIN ===
#!/bin/bash
make docker-image-fedora V=1 NETWORK=1
time make docker-test-debug@fedora TARGET_LIST=x86_64-softmmu J=14 NETWORK=1
=== TEST SCRIPT END ===

  CC      x86_64-softmmu/cpus.o
  CC      x86_64-softmmu/gdbstub.o
  CC      x86_64-softmmu/balloon.o
/tmp/qemu-test/src/disas.c:503:5: error: use of undeclared identifier 'csh'
    csh handle;
    ^
/tmp/qemu-test/src/disas.c:504:5: error: use of undeclared identifier 'cs_insn'
    cs_insn *insn;
    ^
/tmp/qemu-test/src/disas.c:504:14: error: use of undeclared identifier 'insn'; did you mean 'info'?
    cs_insn *insn;
             ^~~~
             info
/tmp/qemu-test/src/disas.c:500:46: note: 'info' declared here
bool plugin_cap_disas_insn(disassemble_info *info, uint64_t pc, size_t size)
                                             ^
/tmp/qemu-test/src/disas.c:509:9: error: implicit declaration of function 'cap_disas_start' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    if (cap_disas_start(info, &handle) != CS_ERR_OK) {
        ^
/tmp/qemu-test/src/disas.c:509:9: error: this function declaration is not a prototype [-Werror,-Wstrict-prototypes]
/tmp/qemu-test/src/disas.c:509:32: error: use of undeclared identifier 'handle'
    if (cap_disas_start(info, &handle) != CS_ERR_OK) {
                               ^
/tmp/qemu-test/src/disas.c:509:43: error: use of undeclared identifier 'CS_ERR_OK'
    if (cap_disas_start(info, &handle) != CS_ERR_OK) {
                                          ^
/tmp/qemu-test/src/disas.c:512:5: error: use of undeclared identifier 'insn'
    insn = cap_insn;
    ^
/tmp/qemu-test/src/disas.c:512:12: error: use of undeclared identifier 'cap_insn'
    insn = cap_insn;
           ^
/tmp/qemu-test/src/disas.c:518:13: error: implicit declaration of function 'cs_disasm' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    count = cs_disasm(handle, cbuf, size, 0, 1, &insn);
            ^
/tmp/qemu-test/src/disas.c:518:13: error: this function declaration is not a prototype [-Werror,-Wstrict-prototypes]
/tmp/qemu-test/src/disas.c:518:23: error: use of undeclared identifier 'handle'
    count = cs_disasm(handle, cbuf, size, 0, 1, &insn);
                      ^
/tmp/qemu-test/src/disas.c:518:50: error: use of undeclared identifier 'insn'
    count = cs_disasm(handle, cbuf, size, 0, 1, &insn);
                                                 ^
/tmp/qemu-test/src/disas.c:521:37: error: use of undeclared identifier 'insn'
        g_string_printf(s, "%s %s", insn->mnemonic, insn->op_str);
                                    ^
/tmp/qemu-test/src/disas.c:521:53: error: use of undeclared identifier 'insn'
        g_string_printf(s, "%s %s", insn->mnemonic, insn->op_str);
                                                    ^
/tmp/qemu-test/src/disas.c:526:5: error: implicit declaration of function 'cs_close' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    cs_close(&handle);
    ^
/tmp/qemu-test/src/disas.c:526:5: error: this function declaration is not a prototype [-Werror,-Wstrict-prototypes]
/tmp/qemu-test/src/disas.c:526:15: error: use of undeclared identifier 'handle'
    cs_close(&handle);
              ^
18 errors generated.


The full log is available at
http://patchew.org/logs/20190731160719.11396-1-alex.bennee@linaro.org/testing.asan/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

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

* Re: [Qemu-devel] [PATCH v4 50/54] tests/plugin: add instruction execution breakdown
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 50/54] tests/plugin: add instruction execution breakdown Alex Bennée
@ 2019-08-01 14:31   ` Aaron Lindsay OS via Qemu-devel
  2019-10-09 18:49     ` Alex Bennée
  0 siblings, 1 reply; 107+ messages in thread
From: Aaron Lindsay OS via Qemu-devel @ 2019-08-01 14:31 UTC (permalink / raw)
  To: Alex Bennée; +Cc: bobby.prani, cota, qemu-devel

On Jul 31 17:07, Alex Bennée wrote:
> + * Attempt to measure the amount of vectorisation that has been done
> + * on some code by counting classes of instruction. This is very much
> + * ARM specific.

I suspect some of my plugins will also be architecture-specific. Does it
make sense to have a plugin specify to QEMU which architectures or
running modes (i.e. softmmu vs. linux user) it supports? Or
alternatively to have QEMU expose this information to the plugin so that
it can cleanly exit if its needs are not met?

-Aaron


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

* Re: [Qemu-devel] [PATCH v4 04/54] target/arm: remove run time semihosting checks
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 04/54] target/arm: remove run time semihosting checks Alex Bennée
  2019-08-01 13:27   ` Aaron Lindsay OS via Qemu-devel
@ 2019-08-01 14:53   ` Richard Henderson
  1 sibling, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 14:53 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Peter Maydell, aaron, cota, bobby.prani, open list:ARM TCG CPUs

On 7/31/19 9:06 AM, Alex Bennée wrote:
> -static inline bool check_for_semihosting(CPUState *cs)
> +/*
> + * Do semihosting call and set the appropriate return value. All the
> + * permission and validity checks have been done at translate time.
> + *
> + * We only see semihosting exceptions in TCG only as they are not
> + * trapped to the hypervisor in KVM.
> + */
> +static void handle_semihosting(CPUState *cs)
>  {
>  #ifdef CONFIG_TCG

Let's move the ifdef outside the function...

> -    if (check_for_semihosting(cs)) {
> +    if (cs->exception_index == EXCP_SEMIHOST) {
> +        handle_semihosting(cs);
>          return;
>      }

... and put another one here.

Peter described how we can't get EXCP_SEMIHOST here from kvm, and suggested an
assert.  Well, the assert is already present just below:

    assert(!excp_is_internal(cs->exception_index));

All we need to do is not return early beforehand.


r~


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

* Re: [Qemu-devel] [PATCH v4 05/54] includes: remove stale [smp|max]_cpus externs
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 05/54] includes: remove stale [smp|max]_cpus externs Alex Bennée
@ 2019-08-01 14:54   ` Richard Henderson
  0 siblings, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 14:54 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel; +Cc: bobby.prani, cota, aaron, Like Xu

On 7/31/19 9:06 AM, Alex Bennée wrote:
> Commit a5e0b3311 removed these in favour of querying machine
> properties. Remove the extern declarations as well.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> Cc: Like Xu <like.xu@linux.intel.com>
> Message-Id: <20190711130546.18578-1-alex.bennee@linaro.org>
> ---
>  include/sysemu/sysemu.h | 2 --
>  1 file changed, 2 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


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

* Re: [Qemu-devel] [PATCH v4 06/54] trace: expand mem_info:size_shift to 4 bits
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 06/54] trace: expand mem_info:size_shift to 4 bits Alex Bennée
@ 2019-08-01 15:01   ` Richard Henderson
  0 siblings, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 15:01 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel; +Cc: bobby.prani, cota, aaron, Stefan Hajnoczi

On 7/31/19 9:06 AM, Alex Bennée wrote:
> From: "Emilio G. Cota" <cota@braap.org>
> 
> This will allow us to trace 32k-long memory accesses (although our
> maximum is something like 256 bytes at the moment).
> 
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Signed-off-by: Emilio G. Cota <cota@braap.org>
> [AJB: expanded to 3->4 bits]
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  trace-events | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/trace-events b/trace-events
> index aeea3c2bdbf..63bb192ade6 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -149,7 +149,7 @@ vcpu guest_cpu_reset(void)
>  # Access information can be parsed as:
>  #
>  # struct mem_info {
> -#     uint8_t size_shift : 2; /* interpreted as "1 << size_shift" bytes */
> +#     uint8_t size_shift : 4; /* interpreted as "1 << size_shift" bytes */
>  #     bool    sign_extend: 1; /* sign-extended */
>  #     uint8_t endianness : 1; /* 0: little, 1: big */
>  #     bool    store      : 1; /* wheter it's a store operation */
> 

Adjusting the comment doesn't do anything, and neither the before or the after
match the actual code:

#define TRACE_MEM_SZ_SHIFT_MASK 0x7 /* size shift mask */

Is this a victim of a rebase, with the changes to trace/mem-internal.h moved to
a different patch?


r~


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

* Re: [Qemu-devel] [PATCH v4 07/54] trace: add mmu_index to mem_info
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 07/54] trace: add mmu_index to mem_info Alex Bennée
@ 2019-08-01 15:17   ` Richard Henderson
  0 siblings, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 15:17 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Riku Voipio, aaron, cota, Stefan Hajnoczi, Paolo Bonzini,
	bobby.prani, Richard Henderson

On 7/31/19 9:06 AM, Alex Bennée wrote:
> We are going to re-use mem_info later for plugins and will need to
> track the mmu_idx for softmmu code.
> 
> [TODO: convert everything to use TCGMemOpIdx?]

Probably easier.  At the moment,

> +#define ATOMIC_MMU_IDX oi

this is mis-named.  It works because

>  static inline
> -uint8_t trace_mem_build_info_no_se_le(int size_shift, bool store)
> +uint16_t trace_mem_build_info_no_se_le(int size_shift, bool store,
> +                                       TCGMemOpIdx oi)
>  {
> -    return trace_mem_build_info(size_shift, false, MO_LE, store);
> +    return trace_mem_build_info(size_shift, false, MO_LE, store,
> +                                get_mmuidx(oi));
>  }

you're also inconsistent about the arguments between user-only and softmmu.

Without doing everything, maybe just use

#define ATOMIC_MMU_IDX   get_mmuidx(oi)

?

r~


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

* Re: [Qemu-devel] [PATCH v4 09/54] cpu: introduce cpu_in_exclusive_context()
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 09/54] cpu: introduce cpu_in_exclusive_context() Alex Bennée
@ 2019-08-01 15:23   ` Richard Henderson
  0 siblings, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 15:23 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Eduardo Habkost, aaron, cota, Paolo Bonzini, bobby.prani,
	Richard Henderson

On 7/31/19 9:06 AM, Alex Bennée wrote:
> From: "Emilio G. Cota" <cota@braap.org>
> 
> Suggested-by: Alex Bennée <alex.bennee@linaro.org>
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Signed-off-by: Emilio G. Cota <cota@braap.org>
> [AJB: moved inside start/end_exclusive fns + cleanup]
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> 
> ---
> v4
>   - -> cpu_in_exclusive_context
>   - moved inside start/end exclusive
>   - fixed up cpu_exec_step_atomic
> ---
>  accel/tcg/cpu-exec.c |  5 +----
>  cpus-common.c        |  4 ++++
>  include/qom/cpu.h    | 13 +++++++++++++
>  3 files changed, 18 insertions(+), 4 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~



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

* Re: [Qemu-devel] [PATCH v4 10/54] translate-all: use cpu_in_exclusive_work_context() in tb_flush
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 10/54] translate-all: use cpu_in_exclusive_work_context() in tb_flush Alex Bennée
@ 2019-08-01 15:25   ` Richard Henderson
  0 siblings, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 15:25 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Paolo Bonzini, aaron, cota, bobby.prani, Richard Henderson

On 7/31/19 9:06 AM, Alex Bennée wrote:
> From: "Emilio G. Cota" <cota@braap.org>
> 
> tb_flush will be called by the plugin module from a safe
> work environment. Prepare for that.
> 
> Suggested-by: Alex Bennée <alex.bennee@linaro.org>
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Signed-off-by: Emilio G. Cota <cota@braap.org>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  accel/tcg/translate-all.c | 9 +++++++--
>  1 file changed, 7 insertions(+), 2 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~



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

* Re: [Qemu-devel] [PATCH v4 11/54] docs/devel: add plugins.rst design document
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 11/54] docs/devel: add plugins.rst design document Alex Bennée
@ 2019-08-01 15:31   ` Richard Henderson
  0 siblings, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 15:31 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel; +Cc: bobby.prani, cota, aaron

On 7/31/19 9:06 AM, Alex Bennée wrote:
> This is mostly extracted from Emilio's more verbose commit comments
> with some additional verbiage from me.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> 
> ---
> v4
>   - some rewording and tweaks
>   - made non-atomicity of inline ops more explicit
>   - expanded description of plugin unload
> ---
>  docs/devel/index.rst   |   1 +
>  docs/devel/plugins.rst | 107 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 108 insertions(+)
>  create mode 100644 docs/devel/plugins.rst

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~



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

* Re: [Qemu-devel] [PATCH v4 12/54] configure: add --enable-plugins (MOVE TO END)
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 12/54] configure: add --enable-plugins (MOVE TO END) Alex Bennée
@ 2019-08-01 15:33   ` Richard Henderson
  0 siblings, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 15:33 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel; +Cc: bobby.prani, cota, aaron

On 7/31/19 9:06 AM, Alex Bennée wrote:
> This adds the basic boilerplate feature enable option for the build.
> We shall expand it later.
> 
> XXX: currently this patch is included at the start of development to
> aid with incremental building. It should be moved to the end once the
> plugins are feature complete.
> 
> [AJB: split from larger patch]
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  configure | 13 +++++++++++++
>  1 file changed, 13 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~



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

* Re: [Qemu-devel] [PATCH v4 13/54] plugin: add user-facing API
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 13/54] plugin: add user-facing API Alex Bennée
@ 2019-08-01 15:39   ` Richard Henderson
  2019-08-02 18:25   ` Aaron Lindsay OS via Qemu-devel
  1 sibling, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 15:39 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel; +Cc: bobby.prani, cota, aaron

On 7/31/19 9:06 AM, Alex Bennée wrote:
> From: "Emilio G. Cota" <cota@braap.org>
> 
> Add the API first to ease review.
> 
> Signed-off-by: Emilio G. Cota <cota@braap.org>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> 
> ---
> v3
>   - merge in changes to plugin install/reset/uninstall
>   - split api file
> v4
>   - s/is/it/
>   - more docstrings
>   - remove qemu_plugin_register_vcpu_mem_haddr_cb and related bits
>   - add qemu_plugin_get_hwaddr and related bits
>   - drop vcpu_index from tb_trans_cb_t
> ---
>  include/qemu/qemu-plugin.h | 351 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 351 insertions(+)
>  create mode 100644 include/qemu/qemu-plugin.h

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~



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

* Re: [Qemu-devel] [PATCH v4 14/54] plugin: add core code
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 14/54] plugin: add core code Alex Bennée
@ 2019-08-01 15:58   ` Richard Henderson
  2019-09-12  9:17   ` Daniel P. Berrangé
  1 sibling, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 15:58 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel; +Cc: aaron, cota, Eduardo Habkost, bobby.prani

On 7/31/19 9:06 AM, Alex Bennée wrote:
> +static inline struct qemu_plugin_insn * qemu_plugin_insn_alloc(void)
> +{
> +    int i, j;
> +    struct qemu_plugin_insn *insn = g_new0(struct qemu_plugin_insn, 1);
> +    insn->data = g_byte_array_sized_new(4);
> +
> +    for (i = 0; i < PLUGIN_N_CB_TYPES; i++) {
> +        for (j = 0; j < PLUGIN_N_CB_SUBTYPES; j++) {
> +            insn->cbs[i][j] = g_array_new(false, false,
> +                                          sizeof(struct qemu_plugin_dyn_cb));
> +        }
> +    }
> +    return insn;
> +}
> +
> +struct qemu_plugin_tb {
> +    GPtrArray *insns;
> +    size_t n;
> +    uint64_t vaddr;
> +    uint64_t vaddr2;
> +    void *haddr1;
> +    void *haddr2;
> +    GArray *cbs[PLUGIN_N_CB_SUBTYPES];
> +};
> +
> +/**
> + * qemu_plugin_tb_insn_get(): get next plugin record for translation.
> + *
> + */
> +static inline
> +struct qemu_plugin_insn *qemu_plugin_tb_insn_get(struct qemu_plugin_tb *tb)
> +{
> +    struct qemu_plugin_insn *insn;
> +    int i, j;
> +
> +    if (unlikely(tb->n == tb->insns->len)) {
> +        struct qemu_plugin_insn *new_insn = qemu_plugin_insn_alloc();
> +        g_ptr_array_add(tb->insns, new_insn);
> +    }
> +    insn = g_ptr_array_index(tb->insns, tb->n++);
> +    g_byte_array_set_size(insn->data, 0);
> +    insn->calls_helpers = false;
> +    insn->mem_helper = false;
> +
> +    for (i = 0; i < PLUGIN_N_CB_TYPES; i++) {
> +        for (j = 0; j < PLUGIN_N_CB_SUBTYPES; j++) {
> +            g_array_set_size(insn->cbs[i][j], 0);
> +        }
> +    }
> +
> +    return insn;
> +}

Why are these inlines in the header?
They seem to be used only once in patch 20.
It seems like these should be local to plugin-gen.c.

Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


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

* Re: [Qemu-devel] [PATCH v4 15/54] plugin: add implementation of the api
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 15/54] plugin: add implementation of the api Alex Bennée
@ 2019-08-01 16:14   ` Richard Henderson
  0 siblings, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 16:14 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel; +Cc: bobby.prani, cota, aaron

On 7/31/19 9:06 AM, Alex Bennée wrote:
> +uint64_t qemu_plugin_hwaddr_to_raddr(const struct qemu_plugin_hwaddr *haddr)
> +{
> +#if 0 /* XXX FIXME should be SOFTMMU */
> +    ram_addr_t ram_addr;
> +
> +    g_assert(haddr);
> +    ram_addr = qemu_ram_addr_from_host(haddr);
> +    if (ram_addr == RAM_ADDR_INVALID) {
> +        error_report("Bad ram pointer %p", haddr);
> +        abort();
> +    }
> +    return ram_addr;
> +#else
> +    return 0;
> +#endif
> +}

What would a plugin do with an raddr?  This seems like a qemu internal thing,
and not really related to anything that the plugin could match up to the hw.

Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


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

* Re: [Qemu-devel] [PATCH v4 16/54] queue: add QTAILQ_REMOVE_SEVERAL
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 16/54] queue: add QTAILQ_REMOVE_SEVERAL Alex Bennée
@ 2019-08-01 16:16   ` Richard Henderson
  2019-08-01 16:16   ` Richard Henderson
  1 sibling, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 16:16 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel; +Cc: bobby.prani, cota, aaron

On 7/31/19 9:06 AM, Alex Bennée wrote:
> From: "Emilio G. Cota" <cota@braap.org>
> 
> This is faster than removing elements one by one.
> 
> Will gain a user soon.
> 
> Signed-off-by: Emilio G. Cota <cota@braap.org>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  include/qemu/queue.h | 10 ++++++++++
>  1 file changed, 10 insertions(+)



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

* Re: [Qemu-devel] [PATCH v4 16/54] queue: add QTAILQ_REMOVE_SEVERAL
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 16/54] queue: add QTAILQ_REMOVE_SEVERAL Alex Bennée
  2019-08-01 16:16   ` Richard Henderson
@ 2019-08-01 16:16   ` Richard Henderson
  1 sibling, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 16:16 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel; +Cc: bobby.prani, cota, aaron

On 7/31/19 9:06 AM, Alex Bennée wrote:
> From: "Emilio G. Cota" <cota@braap.org>
> 
> This is faster than removing elements one by one.
> 
> Will gain a user soon.
> 
> Signed-off-by: Emilio G. Cota <cota@braap.org>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  include/qemu/queue.h | 10 ++++++++++
>  1 file changed, 10 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


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

* Re: [Qemu-devel] [PATCH v4 17/54] cputlb: document get_page_addr_code
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 17/54] cputlb: document get_page_addr_code Alex Bennée
@ 2019-08-01 17:08   ` Richard Henderson
  0 siblings, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 17:08 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Paolo Bonzini, aaron, cota, bobby.prani, Richard Henderson

On 7/31/19 9:06 AM, Alex Bennée wrote:
> From: "Emilio G. Cota" <cota@braap.org>
> 
> Suggested-by: Alex Bennée <alex.bennee@linaro.org>
> Signed-off-by: Emilio G. Cota <cota@braap.org>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  accel/tcg/cputlb.c      |  5 -----
>  include/exec/exec-all.h | 24 +++++++++++++++++++++---
>  2 files changed, 21 insertions(+), 8 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


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

* Re: [Qemu-devel] [PATCH v4 18/54] cputlb: introduce get_page_addr_code_hostp
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 18/54] cputlb: introduce get_page_addr_code_hostp Alex Bennée
@ 2019-08-01 17:10   ` Richard Henderson
  0 siblings, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 17:10 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Paolo Bonzini, aaron, cota, bobby.prani, Richard Henderson

On 7/31/19 9:06 AM, Alex Bennée wrote:
> From: "Emilio G. Cota" <cota@braap.org>
> 
> This will be used by plugins to get the host address
> of instructions.
> 
> Signed-off-by: Emilio G. Cota <cota@braap.org>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  accel/tcg/cputlb.c      | 14 +++++++++++++-
>  include/exec/exec-all.h | 38 ++++++++++++++++++++++++++++++++++++++
>  2 files changed, 51 insertions(+), 1 deletion(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


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

* Re: [Qemu-devel] [PATCH v4 22/54] atomic_template: add inline trace/plugin helpers
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 22/54] atomic_template: add inline trace/plugin helpers Alex Bennée
@ 2019-08-01 18:23   ` Richard Henderson
  0 siblings, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 18:23 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Riku Voipio, aaron, cota, Paolo Bonzini, bobby.prani, Richard Henderson

On 7/31/19 9:06 AM, Alex Bennée wrote:
> From: "Emilio G. Cota" <cota@braap.org>
> 
> In preparation for plugin support.
> 
> Signed-off-by: Emilio G. Cota <cota@braap.org>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> 
> ---
> v4
>   - move common stuff to atomic_common.inc.c
>   - fix ups for widened uint16_t info
>   - drop haddr in helpers
>   - fix wide lines
> ---
>  accel/tcg/atomic_common.inc.c | 50 +++++++++++++++++++
>  accel/tcg/atomic_template.h   | 93 +++++++++++++++++++++--------------
>  accel/tcg/cputlb.c            |  2 +
>  accel/tcg/user-exec.c         |  2 +
>  4 files changed, 111 insertions(+), 36 deletions(-)
>  create mode 100644 accel/tcg/atomic_common.inc.c

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~



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

* Re: [Qemu-devel] [PATCH v4 23/54] tcg: let plugins instrument virtual memory accesses
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 23/54] tcg: let plugins instrument virtual memory accesses Alex Bennée
@ 2019-08-01 18:29   ` Richard Henderson
  0 siblings, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 18:29 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Paolo Bonzini, aaron, cota, bobby.prani, Richard Henderson

On 7/31/19 9:06 AM, Alex Bennée wrote:
> From: "Emilio G. Cota" <cota@braap.org>
> 
> To capture all memory accesses we need hook into all the various
> helper functions that are involved in memory operations as well as the
> injected inline helper calls. A later commit will allow us to resolve
> the actual guest HW addresses by replaying the lookup.
> 
> Signed-off-by: Emilio G. Cota <cota@braap.org>
> [AJB: drop haddr handling, just deal in vaddr]
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> 
> ---
> v3
>   - fixes for cpu_neg()
> v4
>   - rebase fixups, moved cpu_neg() fixes down the stack
>   - drop haddr support - will be restored with later helper
>   - reword commit
> ---
>  accel/tcg/atomic_common.inc.c             |  4 +++
>  accel/tcg/atomic_template.h               |  1 +
>  accel/tcg/cpu-exec.c                      |  3 ++
>  accel/tcg/cputlb.c                        | 14 ++++----
>  include/exec/cpu-defs.h                   |  1 +
>  include/exec/cpu_ldst_template.h          | 28 +++++++++-------
>  include/exec/cpu_ldst_useronly_template.h | 29 ++++++++--------
>  tcg/tcg-op.c                              | 40 ++++++++++++++++++-----
>  tcg/tcg.h                                 |  1 +
>  9 files changed, 79 insertions(+), 42 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~



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

* Re: [Qemu-devel] [PATCH v4 24/54] plugins: implement helpers for resolving hwaddr
  2019-08-01 14:14   ` Aaron Lindsay OS via Qemu-devel
@ 2019-08-01 18:37     ` Richard Henderson
  2019-10-09 17:45     ` Alex Bennée
  1 sibling, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 18:37 UTC (permalink / raw)
  To: Aaron Lindsay OS, Alex Bennée
  Cc: Paolo Bonzini, bobby.prani, cota, qemu-devel, Richard Henderson

On 8/1/19 7:14 AM, Aaron Lindsay OS via Qemu-devel wrote:
> On Jul 31 17:06, Alex Bennée wrote:
>> We need to keep a local per-cpu copy of the data as other threads may
>> be running. We use a automatically growing array and re-use the space
>> for subsequent queries.
> 
> [...]
> 
>> +bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx,
>> +                       bool is_store, struct qemu_plugin_hwaddr *data)
>> +{
>> +    CPUArchState *env = cpu->env_ptr;
>> +    CPUTLBEntry *tlbe = tlb_entry(env, mmu_idx, addr);
>> +    target_ulong tlb_addr = is_store ? tlb_addr_write(tlbe) : tlbe->addr_read;
>> +
>> +    if (tlb_hit(tlb_addr, addr)) {
>> +        if (tlb_addr & TLB_MMIO) {
>> +            data->hostaddr = 0;
>> +            data->is_io = true;
>> +            /* XXX: lookup device */
>> +        } else {
>> +            data->hostaddr = addr + tlbe->addend;
>> +            data->is_io = false;
>> +        }
>> +        return true;
>> +    }
>> +    return false;
>> +}
> 
> In what cases do you expect tlb_hit() should not evaluate to true here?
> Will returns of false only be in error cases, or do you expect it can
> occur during normal operation? In particular, I'm interested in ensuring
> this is as reliable as possible, since some plugins may require physical
> addresses.

I have the same question.  Given the access has just succeeded, it would seem
to be that the tlb entry *must* hit.  No victim tlb check or anything.


r~


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

* Re: [Qemu-devel] [PATCH v4 29/54] plugin-gen: add plugin_insn_append
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 29/54] plugin-gen: add plugin_insn_append Alex Bennée
@ 2019-08-01 18:39   ` Richard Henderson
  0 siblings, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 18:39 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel; +Cc: bobby.prani, cota, aaron

On 7/31/19 9:06 AM, Alex Bennée wrote:
> From: "Emilio G. Cota" <cota@braap.org>
> 
> By adding it to plugin-gen's header file, we can export is as
> an inline, since tcg.h is included in the header (we need tcg_ctx).
> 
> Signed-off-by: Emilio G. Cota <cota@braap.org>
> [AJB: use g_byte_array]
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> 
> ---
> v3
>   - use g_byte_array
> ---
>  include/exec/plugin-gen.h | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~



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

* Re: [Qemu-devel] [PATCH v4 30/54] translator: add translator_ld{ub, sw, uw, l, q}
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 30/54] translator: add translator_ld{ub, sw, uw, l, q} Alex Bennée
@ 2019-08-01 19:24   ` Richard Henderson
  0 siblings, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 19:24 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Paolo Bonzini, bobby.prani, cota, aaron, Richard Henderson

On 7/31/19 9:06 AM, Alex Bennée wrote:
> +#ifdef CONFIG_USER_ONLY
> +
> +#define DO_LOAD(type, name, shift)               \
> +    set_helper_retaddr(1);                       \
> +    ret = name ## _p(g2h(pc));                   \
> +    clear_helper_retaddr();
> +
> +#else
> +
> +#define DO_LOAD(type, name, shift)                   \
> +    int mmu_idx = cpu_mmu_index(env, true);          \
> +    TCGMemOpIdx oi = make_memop_idx(shift, mmu_idx); \
> +    ret = helper_ret_ ## name ## _cmmu(env, pc, oi, 0);

Why are you only using the out-of-line slowpath functions?
Seems like the rest of the fastpath should be included too.


r~


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

* Re: [Qemu-devel] [PATCH v4 31/54] target/arm: fetch code with translator_ld
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 31/54] target/arm: fetch code with translator_ld Alex Bennée
@ 2019-08-01 19:26   ` Richard Henderson
  0 siblings, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 19:26 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Peter Maydell, aaron, cota, bobby.prani, open list:ARM TCG CPUs

On 7/31/19 9:06 AM, Alex Bennée wrote:
> From: "Emilio G. Cota" <cota@braap.org>
> 
> Now the arm_ld*_code functions are only used at translate time we can
> just pass down to translator_ld functions.
> 
> Signed-off-by: Emilio G. Cota <cota@braap.org>
> [AJB: convert from plugin_insn_append to translator_ld]
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> 
> ---
> v4
>   - use translator_ld like the rest of them
> ---
>  target/arm/arm_ldst.h | 15 +++------------
>  1 file changed, 3 insertions(+), 12 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~



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

* Re: [Qemu-devel] [PATCH v4 42/54] translator: inject instrumentation from plugins
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 42/54] translator: inject instrumentation from plugins Alex Bennée
@ 2019-08-01 19:35   ` Richard Henderson
  0 siblings, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 19:35 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Paolo Bonzini, aaron, cota, bobby.prani, Richard Henderson

On 7/31/19 9:07 AM, Alex Bennée wrote:
> From: "Emilio G. Cota" <cota@braap.org>
> 
> Signed-off-by: Emilio G. Cota <cota@braap.org>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> 
> ---
> v4
>   - note we can't inject instrumentation if ! DISAS_NEXT
> ---
>  accel/tcg/translator.c | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~



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

* Re: [Qemu-devel] [PATCH v4 43/54] plugin: add API symbols to qemu-plugins.symbols
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 43/54] plugin: add API symbols to qemu-plugins.symbols Alex Bennée
@ 2019-08-01 19:42   ` Richard Henderson
  2019-10-11 16:46     ` Alex Bennée
  0 siblings, 1 reply; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 19:42 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel; +Cc: bobby.prani, cota, aaron

On 7/31/19 9:07 AM, Alex Bennée wrote:
> +#########################################
> +# See if --dynamic-list is supported by the linker
> +
> +cat > $TMPTXT <<EOF
> +{
> +  foo;
> +};
> +EOF
> +
> +cat > $TMPC <<EOF
> +#include <stdio.h>
> +void foo(void);
> +
> +void foo(void)
> +{
> +  printf("foo\n");
> +}
> +
> +int main(void)
> +{
> +  foo();
> +  return 0;
> +}
> +EOF
> +
> +ld_dynamic_list="no"
> +if compile_prog "" "-Wl,--dynamic-list=$TMPTXT" ; then
> +  ld_dynamic_list="yes"
> +fi
> +
> +#########################################
> +# See if -exported_symbols_list is supported by the linker
> +
> +cat > $TMPTXT <<EOF
> +  _foo
> +EOF
> +
> +ld_exported_symbols_list="no"
> +if compile_prog "" "-Wl,-exported_symbols_list,$TMPTXT" ; then
> +  ld_exported_symbols_list="yes"
> +fi
> +
> +if  test "$plugins" = "yes" &&
> +    test "$ld_dynamic_list" = "no" &&
> +    test "$ld_exported_symbols_list" = "no" ; then
> +  error_exit \
> +      "Plugin support requires specifying a set of symbols that " \
> +      "are exported to plugins. Unfortunately your linker doesn't " \
> +      "support the flag (--dynamic-list or -exported_symbols_list) used " \
> +      "for this purpose."
> +fi
> +
>  ########################################
>  # See if 16-byte vector operations are supported.
>  # Even without a vector unit the compiler may expand these.
> @@ -7318,6 +7371,22 @@ fi
>  if test "$plugins" = "yes" ; then
>      echo "CONFIG_PLUGIN=y" >> $config_host_mak
>      LIBS="-ldl $LIBS"
> +    # Copy the export object list to the build dir
> +    if test "$ld_dynamic_list" = "yes" ; then
> +	echo "CONFIG_HAS_LD_DYNAMIC_LIST=yes" >> $config_host_mak
> +	ld_symbols=qemu-plugins-ld.symbols
> +	cp "$source_path/plugins/qemu-plugins.symbols" $ld_symbols
> +    elif test "$ld_exported_symbols_list" = "yes" ; then
> +	echo "CONFIG_HAS_LD_EXPORTED_SYMBOLS_LIST=yes" >> $config_host_mak
> +	ld64_symbols=qemu-plugins-ld64.symbols
> +	echo "# Automatically generated by configure - do not modify" > $ld64_symbols
> +	grep 'qemu_' "$source_path/plugins/qemu-plugins.symbols" | sed 's/;//g' | \
> +	    sed -E 's/^[[:space:]]*(.*)/_\1/' >> $ld64_symbols
> +    else
> +	error_exit \
> +	    "If \$plugins=yes, either \$ld_dynamic_list or " \
> +	    "\$ld_exported_symbols_list should have been set to 'yes'."
> +    fi
>  fi
>  

How much of this should be skipped if --enable-static?
Or perhaps just dependent on --enable-plugins and let
that switch detect the conflict?


r~



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

* Re: [Qemu-devel] [PATCH v4 53/54] include/exec: wrap cpu_ldst.h in CONFIG_TCG
  2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 53/54] include/exec: wrap cpu_ldst.h in CONFIG_TCG Alex Bennée
@ 2019-08-01 19:51   ` Richard Henderson
  0 siblings, 0 replies; 107+ messages in thread
From: Richard Henderson @ 2019-08-01 19:51 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Paolo Bonzini, aaron, cota, bobby.prani, Richard Henderson

On 7/31/19 9:07 AM, Alex Bennée wrote:
> This gets around a build problem with --disable-tcg.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  include/exec/exec-all.h | 2 ++
>  1 file changed, 2 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~



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

* Re: [Qemu-devel] [PATCH  v4 13/54] plugin: add user-facing API
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 13/54] plugin: add user-facing API Alex Bennée
  2019-08-01 15:39   ` Richard Henderson
@ 2019-08-02 18:25   ` Aaron Lindsay OS via Qemu-devel
  2019-09-06 19:31     ` Alex Bennée
  1 sibling, 1 reply; 107+ messages in thread
From: Aaron Lindsay OS via Qemu-devel @ 2019-08-02 18:25 UTC (permalink / raw)
  To: Alex Bennée; +Cc: bobby.prani, cota, qemu-devel

One thing I would find useful is the ability to access register values
during an execution-time callback. I think the easiest way to do that
generically would be to expose them via the gdb functionality (like
Pavel's earlier patchset did [1]), though that (currently) limits you to
the general-purpose registers. Ideally it would be nice be able to
access other registers (i.e. floating-point, or maybe even system
registers), though those are more difficult to do generically.

Perhaps if we added some sort of architectural-support checking for
individual plugins like I mentioned in another response to this
patchset, we could allow some limited architecture-specific
functionality in this vein? I confess I haven't thought through all the
ramifications of that yet, though. 

-Aaron

[1] - See qemulib_read_register() at
      https://patchwork.ozlabs.org/patch/925393/


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

* Re: [Qemu-devel] [PATCH  v4 13/54] plugin: add user-facing API
  2019-08-02 18:25   ` Aaron Lindsay OS via Qemu-devel
@ 2019-09-06 19:31     ` Alex Bennée
  2019-09-10 16:24       ` Aaron Lindsay OS via Qemu-devel
  0 siblings, 1 reply; 107+ messages in thread
From: Alex Bennée @ 2019-09-06 19:31 UTC (permalink / raw)
  To: Aaron Lindsay OS; +Cc: bobby.prani, cota, qemu-devel


Aaron Lindsay OS <aaron@os.amperecomputing.com> writes:

> One thing I would find useful is the ability to access register values
> during an execution-time callback. I think the easiest way to do that
> generically would be to expose them via the gdb functionality (like
> Pavel's earlier patchset did [1]), though that (currently) limits you to
> the general-purpose registers. Ideally it would be nice be able to
> access other registers (i.e. floating-point, or maybe even system
> registers), though those are more difficult to do generically.

ARM already has system register support via the gdbstub XML interface so
it's certainly doable. The trick is how we do that in a probable way
without leaking the gdb remote protocol into plugins (which is just very
ugly).

> Perhaps if we added some sort of architectural-support checking for
> individual plugins like I mentioned in another response to this
> patchset, we could allow some limited architecture-specific
> functionality in this vein? I confess I haven't thought through all the
> ramifications of that yet, though.

I was wondering if exposing the Elf Type would be enough? It's portable
enough that plugins should be able to work with it without defining our
own architecture enumeration.

>
> -Aaron
>
> [1] - See qemulib_read_register() at
>       https://patchwork.ozlabs.org/patch/925393/


--
Alex Bennée


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

* Re: [Qemu-devel] [PATCH  v4 00/54] plugins for TCG
  2019-08-01  4:19 ` Markus Armbruster
@ 2019-09-06 19:52   ` Alex Bennée
  2019-09-10 16:16     ` Aaron Lindsay OS via Qemu-devel
                       ` (2 more replies)
  0 siblings, 3 replies; 107+ messages in thread
From: Alex Bennée @ 2019-09-06 19:52 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: bobby.prani, cota, qemu-devel, aaron


Markus Armbruster <armbru@redhat.com> writes:

> Alex Bennée <alex.bennee@linaro.org> writes:
>
>> Hi,
>>
>> This is the latest iteration of the plugins series. The main changes
>> from the last version are:
>>
>>   - dropped passing of haddr to plugins
>>
>> This makes the code for handling the plugins less invasive in the
>> softmmu path at the cost of offloading processing to the plugin if it
>> wants the value. We rely on the fact that the TLB is per vCPU so a
>> helper can just trigger a re-query of the TLB to get the final
>> address.
>>
>> Part of that change involved embedding the MMU index in the meminfo
>> field for tracing. I see there are some other patches on the list for
>> messing with TCGMemOp so there might be a clash coming up.
>>
>>   - translator_ld goes direct to softmmu/user functions
>>
>> I also mark the [SOFTMMU_]CODE_ACCESS helpers as deprecated. There is
>> more work to be done to clean up all the current uses of code access
>> helpers but ideally the only thing that should be peaking at code is
>> the translator loop itself. However a bunch of helpers have taken to
>> using code loading functions to peak at the instruction just executed
>> to figure out what to do. Once those have been fixed then we can
>> remove those helpers.
>>
>> Other more minor fixes can be found documented bellow the --- in the
>> individual patches.
>>
>> This series also includes the semihosting patches as they are a
>> pre-requisite for the translator_ld patches for ARM.
>>
>> Once the tree opens up for development again I hope to get the
>> semihosting and trivial clean-up patches merged quickly so the patch
>> count for the plugins patches proper can be reduced a bit.
>
> Next time, please explain briefly what TCG plugins are about right in
> your cover letter.  I had to go hunting for this.  Found "[PATCH v4
> 11/54] docs/devel: add plugins.rst design document".

I'll provide a better overview in my next cover letter.

> Please advise why TCG plugins don't undermine the GPL.  Any proposal to
> add a plugin interface needs to do that.

I'm not sure what we can say about this apart from "ask your lawyer".
I'm certainly not proposing we add any sort of language about what
should and shouldn't be allowed to use the plugin interface. I find it
hard to see how anyone could argue code written to interface with the
plugin API couldn't be considered a derived work.

There are two use cases I have in mind:

The first is FLOSS developers writing interesting tools that can take
advantage of QEMU's control of the system to do experiments that are
tricky with other setups (Valgrind is limited to same-arch, Dynamo/Pin
are user-space only). I want these experiments to be easy to do without
having to keep hacking and re-hacking QEMU's core code. I would hope
QEMU developers would up-stream theirs into the QEMU source tree but I
can imagine academics will have open source code that will only ever sit
in their paper's repository.

The other is users who currently maintain hacked up internal copies of
QEMU as a test bed for whatever piece of silicon they are brewing behind
closed doors. This code would never be distributed (hence never be a GPL
issue) and is generally kept private because it's IP sensitive
(e.g: experimenting with different cache models). If we can provide an
interface that allows them to keep their experiments private and
separate from changes to the core code then maybe apart from making
their lives a bit easier we will see some non-IP sensitive contributions
come back to the upstream. I live in hope ;-)

--
Alex Bennée


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

* Re: [Qemu-devel] [PATCH  v4 00/54] plugins for TCG
  2019-09-06 19:52   ` Alex Bennée
@ 2019-09-10 16:16     ` Aaron Lindsay OS via Qemu-devel
  2019-09-10 17:37       ` Alex Bennée
  2019-09-10 16:34     ` Peter Maydell
  2019-09-12  6:46     ` [Qemu-devel] TCG plugins and the GPL (was: [PATCH v4 00/54] plugins for TCG) Markus Armbruster
  2 siblings, 1 reply; 107+ messages in thread
From: Aaron Lindsay OS via Qemu-devel @ 2019-09-10 16:16 UTC (permalink / raw)
  To: Alex Bennée; +Cc: bobby.prani, cota, Markus Armbruster, qemu-devel

On Sep 06 20:52, Alex Bennée wrote:
> 
> Markus Armbruster <armbru@redhat.com> writes:
> > Please advise why TCG plugins don't undermine the GPL.  Any proposal to
> > add a plugin interface needs to do that.
> 
> I'm not sure what we can say about this apart from "ask your lawyer".
> I'm certainly not proposing we add any sort of language about what
> should and shouldn't be allowed to use the plugin interface. I find it
> hard to see how anyone could argue code written to interface with the
> plugin API couldn't be considered a derived work.

I am not a lawyer, but I would not have expected software merely using a
well-defined API to be considered a derivative work of the software
defining it. Unless, of course, it is a derivative work of another
plugin using the same interface in a way that is not necessitated by the
structure of the API.

What's your reasoning for why it would be a derivative work? Is your
belief that the plugin API is complex enough that anything using it has
to be a derivative work, or something else?

That said, I'm not sure I understand in what way adding a plugin
interface would undermine the GPL, so maybe I'm missing the point.

-Aaron


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

* Re: [Qemu-devel] [PATCH  v4 13/54] plugin: add user-facing API
  2019-09-06 19:31     ` Alex Bennée
@ 2019-09-10 16:24       ` Aaron Lindsay OS via Qemu-devel
  2019-09-10 17:41         ` Alex Bennée
  0 siblings, 1 reply; 107+ messages in thread
From: Aaron Lindsay OS via Qemu-devel @ 2019-09-10 16:24 UTC (permalink / raw)
  To: Alex Bennée; +Cc: bobby.prani, cota, qemu-devel

On Sep 06 20:31, Alex Bennée wrote:
> Aaron Lindsay OS <aaron@os.amperecomputing.com> writes:
> 
> > One thing I would find useful is the ability to access register values
> > during an execution-time callback. I think the easiest way to do that
> > generically would be to expose them via the gdb functionality (like
> > Pavel's earlier patchset did [1]), though that (currently) limits you to
> > the general-purpose registers. Ideally it would be nice be able to
> > access other registers (i.e. floating-point, or maybe even system
> > registers), though those are more difficult to do generically.
> 
> ARM already has system register support via the gdbstub XML interface so
> it's certainly doable. The trick is how we do that in a probable way
> without leaking the gdb remote protocol into plugins (which is just very
> ugly).

What do you mean by "in a probable way"?

I agree that simply exposing the gdb interface does not seem like a
clean solution.

> > Perhaps if we added some sort of architectural-support checking for
> > individual plugins like I mentioned in another response to this
> > patchset, we could allow some limited architecture-specific
> > functionality in this vein? I confess I haven't thought through all the
> > ramifications of that yet, though.
> 
> I was wondering if exposing the Elf Type would be enough? It's portable
> enough that plugins should be able to work with it without defining our
> own architecture enumeration.

I can't think of a reason that wouldn't work, assuming you're referring
to exposing a value corresponding to the `e_machine` ELF header.

-Aaron


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

* Re: [Qemu-devel] [PATCH v4 00/54] plugins for TCG
  2019-09-06 19:52   ` Alex Bennée
  2019-09-10 16:16     ` Aaron Lindsay OS via Qemu-devel
@ 2019-09-10 16:34     ` Peter Maydell
  2019-09-12  6:46     ` [Qemu-devel] TCG plugins and the GPL (was: [PATCH v4 00/54] plugins for TCG) Markus Armbruster
  2 siblings, 0 replies; 107+ messages in thread
From: Peter Maydell @ 2019-09-10 16:34 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Aaron Lindsay, Pranith Kumar, Emilio G. Cota, Markus Armbruster,
	QEMU Developers

On Fri, 6 Sep 2019 at 20:53, Alex Bennée <alex.bennee@linaro.org> wrote:
> Markus Armbruster <armbru@redhat.com> writes:
>
> > Please advise why TCG plugins don't undermine the GPL.  Any proposal to
> > add a plugin interface needs to do that.
>
> I'm not sure what we can say about this apart from "ask your lawyer".

I suspect the underlying confusion here is "the term 'plugin'
has a very wide scope and you and Markus are probably not on
the same page about what this API/ABI is actually doing".

Specifically, this is not the 'plugin ABI that lets you write
device models out of tree' that is sometimes mooted, and the ABI
does not (unless it's changed since I last looked) expose arbitrary
bits of QEMU internals to the plugin or let plugins make calls to
random QEMU functions. It's a very limited scope ABI that allows
QEMU users to write code that can do useful introspection on what
running guest code is doing without having to modify QEMU itself
in non-sustainable non-upstreamable ways.
[If it doesn't have that kind of protection against misuse
then we should add it.]

More generally, your cover letter really needs to be much
more descriptive about what we're trying to do here, and
what the purpose, limitations, etc are here. If you say
"plugins" without giving any detail then you're going to
trigger a lot of (reasonable) reactions from people who
associate that word with a much more generalized "provide
arbitrary bits of QEMU functionality as 3rd-party blobs"
concept...

thanks
-- PMM


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

* Re: [Qemu-devel] [PATCH  v4 00/54] plugins for TCG
  2019-09-10 16:16     ` Aaron Lindsay OS via Qemu-devel
@ 2019-09-10 17:37       ` Alex Bennée
  0 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-09-10 17:37 UTC (permalink / raw)
  To: Aaron Lindsay OS; +Cc: bobby.prani, cota, Markus Armbruster, qemu-devel


Aaron Lindsay OS <aaron@os.amperecomputing.com> writes:

> On Sep 06 20:52, Alex Bennée wrote:
>>
>> Markus Armbruster <armbru@redhat.com> writes:
>> > Please advise why TCG plugins don't undermine the GPL.  Any proposal to
>> > add a plugin interface needs to do that.
>>
>> I'm not sure what we can say about this apart from "ask your lawyer".
>> I'm certainly not proposing we add any sort of language about what
>> should and shouldn't be allowed to use the plugin interface. I find it
>> hard to see how anyone could argue code written to interface with the
>> plugin API couldn't be considered a derived work.
>
> I am not a lawyer, but I would not have expected software merely using a
> well-defined API to be considered a derivative work of the software
> defining it. Unless, of course, it is a derivative work of another
> plugin using the same interface in a way that is not necessitated by the
> structure of the API.
>
> What's your reasoning for why it would be a derivative work? Is your
> belief that the plugin API is complex enough that anything using it has
> to be a derivative work, or something else?

Well it's derivative if the code couldn't have been written on it's own
- so is "derived" from a design in GPL code. The endless arguments about
derivation w.r.t the nvidia kernel drivers hinge on the fact the drivers
are multi-OS and shimmed to into the kernel - not explicitly written for
Linux. However no one really knows where the line is because it's the
courts that will ultimately decide.

OTOH the kernel has explicit language about the syscall layer:

   NOTE! This copyright does *not* cover user programs that use kernel
 services by normal system calls - this is merely considered normal use
 of the kernel, and does *not* fall under the heading of "derived work".

Anyway I don't really care either way and don't intend to become an arm
chair lawyer as the arguments can become rather circular and tedious. We
might want to make an explicit statement in the QEMU tree about
reserving the right to change the API in the future and the best way to
keep plugins in sync is to have them in the upstream source tree.

> That said, I'm not sure I understand in what way adding a plugin
> interface would undermine the GPL, so maybe I'm missing the point.

I suspect there is a similar concern as GCC had when they were asked to
expose their IR to tools. They were explicitly concerned that people
would ship proprietary compilers consisting of a GPL GCC shell with all
the clever optimisations in proprietary plugins that glued the front and
backends together. I don't think this is a problem for QEMU because at
the moment plugins can't be used to improve code generation - just
observe it. You could theoretically implement device models this way but
there are definitely easier more efficient ways of doing it - as shown
by other 3rd party forks of QEMU.

As I mentioned in the other message I'm sure there will be proprietary
- or rather secret behind closed doors plugins but I don't view them any
differently to all the various secret and external forks of the main
QEMU source.

>
> -Aaron


--
Alex Bennée


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

* Re: [Qemu-devel] [PATCH  v4 13/54] plugin: add user-facing API
  2019-09-10 16:24       ` Aaron Lindsay OS via Qemu-devel
@ 2019-09-10 17:41         ` Alex Bennée
  0 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-09-10 17:41 UTC (permalink / raw)
  To: Aaron Lindsay OS; +Cc: bobby.prani, cota, qemu-devel


Aaron Lindsay OS <aaron@os.amperecomputing.com> writes:

> On Sep 06 20:31, Alex Bennée wrote:
>> Aaron Lindsay OS <aaron@os.amperecomputing.com> writes:
>>
>> > One thing I would find useful is the ability to access register values
>> > during an execution-time callback. I think the easiest way to do that
>> > generically would be to expose them via the gdb functionality (like
>> > Pavel's earlier patchset did [1]), though that (currently) limits you to
>> > the general-purpose registers. Ideally it would be nice be able to
>> > access other registers (i.e. floating-point, or maybe even system
>> > registers), though those are more difficult to do generically.
>>
>> ARM already has system register support via the gdbstub XML interface so
>> it's certainly doable. The trick is how we do that in a probable way
>> without leaking the gdb remote protocol into plugins (which is just very
>> ugly).
>
> What do you mean by "in a probable way"?
>
> I agree that simply exposing the gdb interface does not seem like a
> clean solution.

That was a typo - portable was what I was aiming for. The problem with
the gdb interface is how you tie register id's to something useful
rather than having to encode the arbitrary gdb register enumeration into
your plugins.

>
>> > Perhaps if we added some sort of architectural-support checking for
>> > individual plugins like I mentioned in another response to this
>> > patchset, we could allow some limited architecture-specific
>> > functionality in this vein? I confess I haven't thought through all the
>> > ramifications of that yet, though.
>>
>> I was wondering if exposing the Elf Type would be enough? It's portable
>> enough that plugins should be able to work with it without defining our
>> own architecture enumeration.
>
> I can't think of a reason that wouldn't work, assuming you're referring
> to exposing a value corresponding to the `e_machine` ELF header.

Yes exactly that - I started but uncovered some hideousness in our
current Elf support so there will be a short diversion to re-factor that
into something a bit more usable across the code base.

>
> -Aaron


--
Alex Bennée


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

* [Qemu-devel] TCG plugins and the GPL (was: [PATCH v4 00/54] plugins for TCG)
  2019-09-06 19:52   ` Alex Bennée
  2019-09-10 16:16     ` Aaron Lindsay OS via Qemu-devel
  2019-09-10 16:34     ` Peter Maydell
@ 2019-09-12  6:46     ` Markus Armbruster
  2019-09-12  9:03       ` Alex Bennée
  2 siblings, 1 reply; 107+ messages in thread
From: Markus Armbruster @ 2019-09-12  6:46 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Peter Maydell, qemu-devel, aaron, cota, Stefan Hajnoczi, bobby.prani

Alex Bennée <alex.bennee@linaro.org> writes:

> Markus Armbruster <armbru@redhat.com> writes:
[...]
>> Please advise why TCG plugins don't undermine the GPL.  Any proposal to
>> add a plugin interface needs to do that.
>
> I'm not sure what we can say about this apart from "ask your lawyer".

I'm not asking for a legal argument, I'm asking for a pragmatic one.

> I'm certainly not proposing we add any sort of language about what
> should and shouldn't be allowed to use the plugin interface. I find it
> hard to see how anyone could argue code written to interface with the
> plugin API couldn't be considered a derived work.

What makes that so?  Is writing a plugin without linking with QEMU code
impractical?

> There are two use cases I have in mind:
>
> The first is FLOSS developers writing interesting tools that can take
> advantage of QEMU's control of the system to do experiments that are
> tricky with other setups (Valgrind is limited to same-arch, Dynamo/Pin
> are user-space only). I want these experiments to be easy to do without
> having to keep hacking and re-hacking QEMU's core code. I would hope
> QEMU developers would up-stream theirs into the QEMU source tree but I
> can imagine academics will have open source code that will only ever sit
> in their paper's repository.

GPL'ed code that's not for upstream is 100% legitimate.

> The other is users who currently maintain hacked up internal copies of
> QEMU as a test bed for whatever piece of silicon they are brewing behind
> closed doors. This code would never be distributed (hence never be a GPL
> issue)

Correct.  We can't force anybody to distribute, and that's only proper.

>        and is generally kept private because it's IP sensitive
> (e.g: experimenting with different cache models). If we can provide an
> interface that allows them to keep their experiments private and
> separate from changes to the core code then maybe apart from making
> their lives a bit easier we will see some non-IP sensitive contributions
> come back to the upstream. I live in hope ;-)

I'm concerned about a third case: imlementing stuff as a plugin so you
can distribute it with a GPL-incompatible license.  Particularly
pernicious when that stuff could be useful upstream.

Are there any technical difficulties that could make distributing a
plugins in binary form impractical?


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

* Re: [Qemu-devel] TCG plugins and the GPL (was: [PATCH v4 00/54] plugins for TCG)
  2019-09-12  6:46     ` [Qemu-devel] TCG plugins and the GPL (was: [PATCH v4 00/54] plugins for TCG) Markus Armbruster
@ 2019-09-12  9:03       ` Alex Bennée
  2019-09-12  9:21         ` Peter Maydell
  2019-09-12  9:32         ` Daniel P. Berrangé
  0 siblings, 2 replies; 107+ messages in thread
From: Alex Bennée @ 2019-09-12  9:03 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Peter Maydell, qemu-devel, aaron, cota, Stefan Hajnoczi, bobby.prani


Markus Armbruster <armbru@redhat.com> writes:

> Alex Bennée <alex.bennee@linaro.org> writes:
>
>> Markus Armbruster <armbru@redhat.com> writes:
> [...]
>>> Please advise why TCG plugins don't undermine the GPL.  Any proposal to
>>> add a plugin interface needs to do that.
>>
>> I'm not sure what we can say about this apart from "ask your lawyer".
>
> I'm not asking for a legal argument, I'm asking for a pragmatic one.
>
>> I'm certainly not proposing we add any sort of language about what
>> should and shouldn't be allowed to use the plugin interface. I find it
>> hard to see how anyone could argue code written to interface with the
>> plugin API couldn't be considered a derived work.
>
> What makes that so?  Is writing a plugin without linking with QEMU code
> impractical?

The way a plugin works is by linking. The plugin itself would be useless
unless combined with the QEMU code to do its thing. It is a more
intimate binding than an IPC interface using some sort of protocol. The
argument goes that pretty much any kernel module is derived code - but
again it has never really been litigated in the courts which would be
the people to set the precedent.

>
>> There are two use cases I have in mind:
>>
>> The first is FLOSS developers writing interesting tools that can take
>> advantage of QEMU's control of the system to do experiments that are
>> tricky with other setups (Valgrind is limited to same-arch, Dynamo/Pin
>> are user-space only). I want these experiments to be easy to do without
>> having to keep hacking and re-hacking QEMU's core code. I would hope
>> QEMU developers would up-stream theirs into the QEMU source tree but I
>> can imagine academics will have open source code that will only ever sit
>> in their paper's repository.
>
> GPL'ed code that's not for upstream is 100% legitimate.
>
>> The other is users who currently maintain hacked up internal copies of
>> QEMU as a test bed for whatever piece of silicon they are brewing behind
>> closed doors. This code would never be distributed (hence never be a GPL
>> issue)
>
> Correct.  We can't force anybody to distribute, and that's only proper.
>
>>        and is generally kept private because it's IP sensitive
>> (e.g: experimenting with different cache models). If we can provide an
>> interface that allows them to keep their experiments private and
>> separate from changes to the core code then maybe apart from making
>> their lives a bit easier we will see some non-IP sensitive contributions
>> come back to the upstream. I live in hope ;-)
>
> I'm concerned about a third case: imlementing stuff as a plugin so you
> can distribute it with a GPL-incompatible license.  Particularly
> pernicious when that stuff could be useful upstream.

If someone were to do that it would depend on a copyright holder (i.e.
one of us) being willing to challenge that licensing. AIUI GCC used
additional language in the runtime exception clause:

  https://www.gnu.org/licenses/gcc-exception-3.1.html

which only allows use of the runtime exception if the code has gone
through GPL compatible code:

  A Compilation Process is "Eligible" if it is done using GCC, alone or
  with other GPL-compatible software, or if it is done without using any
  work based on GCC. For example, using non-GPL-compatible Software to
  optimize any GCC intermediate representations would not qualify as an
  Eligible Compilation Process.

> Are there any technical difficulties that could make distributing a
> plugins in binary form impractical?

Well the first thing will be we are not intending to offer a guaranteed
ABI. While we don't want to be changing it at a whim there shouldn't be
an expectation that the plugin interface will maintain backwards
compatibility (unlike the command line interface ;-). There should be an
expectation that plugins will likely need to be rebuilt against the
current source tree from time to time.

We could implement a more technical measure analogous to the kernels
module signing that would require the plugin to be rebuilt with
reference to the current QEMU source tree although that will be a pain
even for internally distributed blobs. I'm loathed to implement such a
system from v1 though given the problem of publicly distributed binary
blobs is currently only a theoretical problem.

--
Alex Bennée


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

* Re: [Qemu-devel] [PATCH  v4 14/54] plugin: add core code
  2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 14/54] plugin: add core code Alex Bennée
  2019-08-01 15:58   ` Richard Henderson
@ 2019-09-12  9:17   ` Daniel P. Berrangé
  1 sibling, 0 replies; 107+ messages in thread
From: Daniel P. Berrangé @ 2019-09-12  9:17 UTC (permalink / raw)
  To: Alex Bennée; +Cc: aaron, cota, qemu-devel, bobby.prani, Eduardo Habkost

On Wed, Jul 31, 2019 at 05:06:39PM +0100, Alex Bennée wrote:
> From: "Emilio G. Cota" <cota@braap.org>
> 
> Signed-off-by: Emilio G. Cota <cota@braap.org>
> [AJB: moved directory and merged various fixes]
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>


> +static int plugin_load(struct qemu_plugin_desc *desc)
> +{
> +    qemu_plugin_install_func_t install;
> +    struct qemu_plugin_ctx *ctx;
> +    char *err;
> +    int rc;
> +
> +    ctx = qemu_memalign(qemu_dcache_linesize, sizeof(*ctx));
> +    memset(ctx, 0, sizeof(*ctx));
> +    ctx->desc = desc;
> +
> +    ctx->handle = dlopen(desc->path, RTLD_NOW);
> +    if (ctx->handle == NULL) {
> +        error_report("%s: %s", __func__, dlerror());
> +        goto err_dlopen;
> +    }
> +
> +    /* clear any previous dlerror, call dlsym, then check dlerror */
> +    dlerror();
> +    install = dlsym(ctx->handle, "qemu_plugin_install");

If you use 'GModule' instead of dlopen, then we get portability to
many more platforms, including ablity to load DLLs on Windows:

  https://developer.gnome.org/glib/stable/glib-Dynamic-Loading-of-Modules.html



Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


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

* Re: [Qemu-devel] TCG plugins and the GPL (was: [PATCH v4 00/54] plugins for TCG)
  2019-09-12  9:03       ` Alex Bennée
@ 2019-09-12  9:21         ` Peter Maydell
  2019-09-12 10:07           ` Alex Bennée
  2019-09-12  9:32         ` Daniel P. Berrangé
  1 sibling, 1 reply; 107+ messages in thread
From: Peter Maydell @ 2019-09-12  9:21 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Markus Armbruster, QEMU Developers, Aaron Lindsay,
	Emilio G. Cota, Stefan Hajnoczi, Pranith Kumar

On Thu, 12 Sep 2019 at 10:03, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> Well the first thing will be we are not intending to offer a guaranteed
> ABI. While we don't want to be changing it at a whim there shouldn't be
> an expectation that the plugin interface will maintain backwards
> compatibility (unlike the command line interface ;-). There should be an
> expectation that plugins will likely need to be rebuilt against the
> current source tree from time to time.

Wait, what? From my perspective the whole point of the plugin
interface is that it should be stable, in that at least there's
a good chance that a plugin you built will work against multiple
versions of QEMU, and if it doesn't then it should fail with
a reasonable error message telling you to update. I'm not
sure we should be landing the plugins infrastructure if we
don't have that much stability.

thanks
-- PMM


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

* Re: [Qemu-devel] TCG plugins and the GPL (was: [PATCH v4 00/54] plugins for TCG)
  2019-09-12  9:03       ` Alex Bennée
  2019-09-12  9:21         ` Peter Maydell
@ 2019-09-12  9:32         ` Daniel P. Berrangé
  1 sibling, 0 replies; 107+ messages in thread
From: Daniel P. Berrangé @ 2019-09-12  9:32 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Peter Maydell, Markus Armbruster, qemu-devel, aaron, cota,
	Stefan Hajnoczi, bobby.prani

On Thu, Sep 12, 2019 at 10:03:48AM +0100, Alex Bennée wrote:
> 
> Markus Armbruster <armbru@redhat.com> writes:
> 
> > Alex Bennée <alex.bennee@linaro.org> writes:
> >
> >> Markus Armbruster <armbru@redhat.com> writes:
> > [...]
> >>> Please advise why TCG plugins don't undermine the GPL.  Any proposal to
> >>> add a plugin interface needs to do that.
> >>
> >> I'm not sure what we can say about this apart from "ask your lawyer".
> >
> > I'm not asking for a legal argument, I'm asking for a pragmatic one.
> >
> >> I'm certainly not proposing we add any sort of language about what
> >> should and shouldn't be allowed to use the plugin interface. I find it
> >> hard to see how anyone could argue code written to interface with the
> >> plugin API couldn't be considered a derived work.
> >
> > What makes that so?  Is writing a plugin without linking with QEMU code
> > impractical?
> 
> The way a plugin works is by linking. The plugin itself would be useless
> unless combined with the QEMU code to do its thing. It is a more
> intimate binding than an IPC interface using some sort of protocol. The
> argument goes that pretty much any kernel module is derived code - but
> again it has never really been litigated in the courts which would be
> the people to set the precedent.

Part of the problem with the kernel is the historical precedent they
had set. The issue of GPL compliance only become prominent much later
after (closed source) loadable modules were already widely in use. They
tried to lock the door after the horse had already bolted by adding
EXPORT_SYMBOL_GPL.

We can avoid this trapped by clearly documenting our license expectations
from the very start. ie state that we consider any plugins to be derived
works and to be bound by the terms of the GPL. This doesn't mean the
plugins themselves have to be GPL, but they have to be under terms that
allow relicensing to the GPL, in order to be license compatible. 

We could even go as far as having the plugin registration API require
that the plugin explicitly declare its license and we can log this
license at time of loading. If people use a non-GPL compatible license
it will be clearly visible as non-compatible, or if they lie and pretend
to be GPL then they would be willfully violating.

> >> There are two use cases I have in mind:
> >>
> >> The first is FLOSS developers writing interesting tools that can take
> >> advantage of QEMU's control of the system to do experiments that are
> >> tricky with other setups (Valgrind is limited to same-arch, Dynamo/Pin
> >> are user-space only). I want these experiments to be easy to do without
> >> having to keep hacking and re-hacking QEMU's core code. I would hope
> >> QEMU developers would up-stream theirs into the QEMU source tree but I
> >> can imagine academics will have open source code that will only ever sit
> >> in their paper's repository.
> >
> > GPL'ed code that's not for upstream is 100% legitimate.

Yep, the code only has to be provided to the people who receive the
plugin binary. Those people can't be prevented from redistributing
it further though.

> >> The other is users who currently maintain hacked up internal copies of
> >> QEMU as a test bed for whatever piece of silicon they are brewing behind
> >> closed doors. This code would never be distributed (hence never be a GPL
> >> issue)
> >
> > Correct.  We can't force anybody to distribute, and that's only proper.
> >

> > Are there any technical difficulties that could make distributing a
> > plugins in binary form impractical?
> 
> Well the first thing will be we are not intending to offer a guaranteed
> ABI. While we don't want to be changing it at a whim there shouldn't be
> an expectation that the plugin interface will maintain backwards
> compatibility (unlike the command line interface ;-). There should be an
> expectation that plugins will likely need to be rebuilt against the
> current source tree from time to time.
> 
> We could implement a more technical measure analogous to the kernels
> module signing that would require the plugin to be rebuilt with
> reference to the current QEMU source tree although that will be a pain
> even for internally distributed blobs. I'm loathed to implement such a
> system from v1 though given the problem of publicly distributed binary
> blobs is currently only a theoretical problem.

The problem with waiting for a problem to arise is that you have set a
precedent that its ok. We are in a stronger enforcement position if we
can set expectations accurately from day one, avoiding the trap the
kernel had which needed to try to enforce after the fact.

So from that POV, I'd be strongly in favour of technical measures that
force the plugin to be rebuilt against each new QEMU version.

This doesn't need to be module signing - it could be as simple as
requiring the plugin to export a symbol "module_version" which must
exactly match the QEMU version, or refuse to load it. If we want to
be even more strict we could generate a random hash in each QEMU
rebuild, which is the similar level of strictness to kernel signing

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


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

* Re: [Qemu-devel] TCG plugins and the GPL (was: [PATCH v4 00/54] plugins for TCG)
  2019-09-12  9:21         ` Peter Maydell
@ 2019-09-12 10:07           ` Alex Bennée
  2019-09-12 10:16             ` Daniel P. Berrangé
  2019-09-12 10:18             ` Peter Maydell
  0 siblings, 2 replies; 107+ messages in thread
From: Alex Bennée @ 2019-09-12 10:07 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Markus Armbruster, QEMU Developers, Aaron Lindsay,
	Emilio G. Cota, Stefan Hajnoczi, Pranith Kumar


Peter Maydell <peter.maydell@linaro.org> writes:

> On Thu, 12 Sep 2019 at 10:03, Alex Bennée <alex.bennee@linaro.org> wrote:
>>
>> Well the first thing will be we are not intending to offer a guaranteed
>> ABI. While we don't want to be changing it at a whim there shouldn't be
>> an expectation that the plugin interface will maintain backwards
>> compatibility (unlike the command line interface ;-). There should be an
>> expectation that plugins will likely need to be rebuilt against the
>> current source tree from time to time.
>
> Wait, what? From my perspective the whole point of the plugin
> interface is that it should be stable, in that at least there's
> a good chance that a plugin you built will work against multiple
> versions of QEMU, and if it doesn't then it should fail with
> a reasonable error message telling you to update. I'm not
> sure we should be landing the plugins infrastructure if we
> don't have that much stability.

There is a big fat blurry line between "set in stone" and "not requiring
you to re-engineer the plugin every QEMU release". I'm saying we should
reserve the right to extend and change the plugin API as required but
the expectation would be the plugins will continue to work the same way
but maybe with tweaks to the API hooks to support additional features.

It's also a pretty young interface so I would expect some evolution once
it is released into the field.

One problem with the anti-license circumvention measures being suggested
is it will mean having to recompile plugins for any given release. This
isn't a problem for plugins we write but it does add an extra step for
out of tree plugins. Maybe being forced to re-compile (but not change
the source) is a hurdle we are willing to accept?

--
Alex Bennée


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

* Re: [Qemu-devel] TCG plugins and the GPL (was: [PATCH v4 00/54] plugins for TCG)
  2019-09-12 10:07           ` Alex Bennée
@ 2019-09-12 10:16             ` Daniel P. Berrangé
  2019-09-12 10:21               ` Peter Maydell
  2019-09-12 10:18             ` Peter Maydell
  1 sibling, 1 reply; 107+ messages in thread
From: Daniel P. Berrangé @ 2019-09-12 10:16 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Peter Maydell, Markus Armbruster, QEMU Developers, Aaron Lindsay,
	Emilio G. Cota, Stefan Hajnoczi, Pranith Kumar

On Thu, Sep 12, 2019 at 11:07:07AM +0100, Alex Bennée wrote:
> 
> Peter Maydell <peter.maydell@linaro.org> writes:
> 
> > On Thu, 12 Sep 2019 at 10:03, Alex Bennée <alex.bennee@linaro.org> wrote:
> >>
> >> Well the first thing will be we are not intending to offer a guaranteed
> >> ABI. While we don't want to be changing it at a whim there shouldn't be
> >> an expectation that the plugin interface will maintain backwards
> >> compatibility (unlike the command line interface ;-). There should be an
> >> expectation that plugins will likely need to be rebuilt against the
> >> current source tree from time to time.
> >
> > Wait, what? From my perspective the whole point of the plugin
> > interface is that it should be stable, in that at least there's
> > a good chance that a plugin you built will work against multiple
> > versions of QEMU, and if it doesn't then it should fail with
> > a reasonable error message telling you to update. I'm not
> > sure we should be landing the plugins infrastructure if we
> > don't have that much stability.
> 
> There is a big fat blurry line between "set in stone" and "not requiring
> you to re-engineer the plugin every QEMU release". I'm saying we should
> reserve the right to extend and change the plugin API as required but
> the expectation would be the plugins will continue to work the same way
> but maybe with tweaks to the API hooks to support additional features.
> 
> It's also a pretty young interface so I would expect some evolution once
> it is released into the field.
> 
> One problem with the anti-license circumvention measures being suggested
> is it will mean having to recompile plugins for any given release. This
> isn't a problem for plugins we write but it does add an extra step for
> out of tree plugins. Maybe being forced to re-compile (but not change
> the source) is a hurdle we are willing to accept?

I can understand & totally support not wishing to break the compilation
of plugins for every release, by having a reasonably stable API.

I think forcing recompile for each release is reasonable protection
to make it less atttractive to create license violating closed source
plugins.

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


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

* Re: [Qemu-devel] TCG plugins and the GPL (was: [PATCH v4 00/54] plugins for TCG)
  2019-09-12 10:07           ` Alex Bennée
  2019-09-12 10:16             ` Daniel P. Berrangé
@ 2019-09-12 10:18             ` Peter Maydell
  2019-09-12 10:35               ` Alex Bennée
  1 sibling, 1 reply; 107+ messages in thread
From: Peter Maydell @ 2019-09-12 10:18 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Markus Armbruster, QEMU Developers, Aaron Lindsay,
	Emilio G. Cota, Stefan Hajnoczi, Pranith Kumar

On Thu, 12 Sep 2019 at 11:07, Alex Bennée <alex.bennee@linaro.org> wrote:
> Peter Maydell <peter.maydell@linaro.org> writes:
> > Wait, what? From my perspective the whole point of the plugin
> > interface is that it should be stable, in that at least there's
> > a good chance that a plugin you built will work against multiple
> > versions of QEMU, and if it doesn't then it should fail with
> > a reasonable error message telling you to update. I'm not
> > sure we should be landing the plugins infrastructure if we
> > don't have that much stability.
>
> There is a big fat blurry line between "set in stone" and "not requiring
> you to re-engineer the plugin every QEMU release". I'm saying we should
> reserve the right to extend and change the plugin API as required but
> the expectation would be the plugins will continue to work the same way
> but maybe with tweaks to the API hooks to support additional features.
>
> It's also a pretty young interface so I would expect some evolution once
> it is released into the field.

Sure. But I think we should document that we at least intend to
have some approximation to a compatability/deprecation policy
here, and some mechanisms for versioning so you get a helpful
error rather than weird misbehaviour if your plugin is too old.

> One problem with the anti-license circumvention measures being suggested
> is it will mean having to recompile plugins for any given release.

Why should we do this? I think this is making life hard for our
users for no good reason. We *do* have this check for modules,
because a module is just a random .so that can do anything in
QEMU. I thought we had the TCG-plugin interface much more locked
down than that?

thanks
-- PMM


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

* Re: [Qemu-devel] TCG plugins and the GPL (was: [PATCH v4 00/54] plugins for TCG)
  2019-09-12 10:16             ` Daniel P. Berrangé
@ 2019-09-12 10:21               ` Peter Maydell
  0 siblings, 0 replies; 107+ messages in thread
From: Peter Maydell @ 2019-09-12 10:21 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: Markus Armbruster, QEMU Developers, Aaron Lindsay,
	Emilio G. Cota, Stefan Hajnoczi, Pranith Kumar, Alex Bennée

On Thu, 12 Sep 2019 at 11:17, Daniel P. Berrangé <berrange@redhat.com> wrote:
> I think forcing recompile for each release is reasonable protection
> to make it less atttractive to create license violating closed source
> plugins.

I'm just not sure that a plugin that, for instance, does
"whenever the guest makes a memory access print the address
and data", is in any reasonable sense a derived work of QEMU
that it makes sense to extend the GPL to. We're providing
a convenient introspection interface here, similar to but
different from the way gdbstub lets you introspect guest
binary behaviour, not an arbitrary mechanism for extending
QEMU itself.

thanks
-- PMM


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

* Re: [Qemu-devel] TCG plugins and the GPL (was: [PATCH v4 00/54] plugins for TCG)
  2019-09-12 10:18             ` Peter Maydell
@ 2019-09-12 10:35               ` Alex Bennée
  0 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-09-12 10:35 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Markus Armbruster, QEMU Developers, Aaron Lindsay,
	Emilio G. Cota, Stefan Hajnoczi, Pranith Kumar


Peter Maydell <peter.maydell@linaro.org> writes:

> On Thu, 12 Sep 2019 at 11:07, Alex Bennée <alex.bennee@linaro.org> wrote:
>> Peter Maydell <peter.maydell@linaro.org> writes:
>> > Wait, what? From my perspective the whole point of the plugin
>> > interface is that it should be stable, in that at least there's
>> > a good chance that a plugin you built will work against multiple
>> > versions of QEMU, and if it doesn't then it should fail with
>> > a reasonable error message telling you to update. I'm not
>> > sure we should be landing the plugins infrastructure if we
>> > don't have that much stability.
>>
>> There is a big fat blurry line between "set in stone" and "not requiring
>> you to re-engineer the plugin every QEMU release". I'm saying we should
>> reserve the right to extend and change the plugin API as required but
>> the expectation would be the plugins will continue to work the same way
>> but maybe with tweaks to the API hooks to support additional features.
>>
>> It's also a pretty young interface so I would expect some evolution once
>> it is released into the field.
>
> Sure. But I think we should document that we at least intend to
> have some approximation to a compatability/deprecation policy
> here, and some mechanisms for versioning so you get a helpful
> error rather than weird misbehaviour if your plugin is too old.
>
>> One problem with the anti-license circumvention measures being suggested
>> is it will mean having to recompile plugins for any given release.
>
> Why should we do this? I think this is making life hard for our
> users for no good reason. We *do* have this check for modules,
> because a module is just a random .so that can do anything in
> QEMU. I thought we had the TCG-plugin interface much more locked
> down than that?

It is, there are only a few set calls the plugin can make into QEMU,
mostly to register callbacks to events. Currently it can examine the
state of the system (again through the API) but can't change it's
behaviour (although a register access interface has been requested
although I'd initially intended to make it read only).

>
> thanks
> -- PMM


--
Alex Bennée


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

* Re: [PATCH v4 24/54] plugins: implement helpers for resolving hwaddr
  2019-08-01 14:14   ` Aaron Lindsay OS via Qemu-devel
  2019-08-01 18:37     ` Richard Henderson
@ 2019-10-09 17:45     ` Alex Bennée
  1 sibling, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-10-09 17:45 UTC (permalink / raw)
  To: Aaron Lindsay OS
  Cc: Paolo Bonzini, bobby.prani, cota, qemu-devel, Richard Henderson


Aaron Lindsay OS <aaron@os.amperecomputing.com> writes:

> On Jul 31 17:06, Alex Bennée wrote:
>> We need to keep a local per-cpu copy of the data as other threads may
>> be running. We use a automatically growing array and re-use the space
>> for subsequent queries.
>
> [...]
>
>> +bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx,
>> +                       bool is_store, struct qemu_plugin_hwaddr *data)
>> +{
>> +    CPUArchState *env = cpu->env_ptr;
>> +    CPUTLBEntry *tlbe = tlb_entry(env, mmu_idx, addr);
>> +    target_ulong tlb_addr = is_store ? tlb_addr_write(tlbe) : tlbe->addr_read;
>> +
>> +    if (tlb_hit(tlb_addr, addr)) {
>> +        if (tlb_addr & TLB_MMIO) {
>> +            data->hostaddr = 0;
>> +            data->is_io = true;
>> +            /* XXX: lookup device */
>> +        } else {
>> +            data->hostaddr = addr + tlbe->addend;
>> +            data->is_io = false;
>> +        }
>> +        return true;
>> +    }
>> +    return false;
>> +}
>
> In what cases do you expect tlb_hit() should not evaluate to true here?
> Will returns of false only be in error cases, or do you expect it can
> occur during normal operation? In particular, I'm interested in ensuring
> this is as reliable as possible, since some plugins may require physical
> addresses.

Only if the API is misused and a call made outside of the hooked memory
operation. An assert would be too strong as the plugin could then bring
down QEMU - I guess we could use some sort of error_report...

>
>> +struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
>> +                                                  uint64_t vaddr)
>> +{
>> +    CPUState *cpu = current_cpu;
>> +    unsigned int mmu_idx = info >> TRACE_MEM_MMU_SHIFT;
>> +    struct qemu_plugin_hwaddr *hwaddr;
>> +
>> +    /* Ensure we have memory allocated for this work */
>> +    if (!hwaddr_refs) {
>> +        hwaddr_refs = g_array_sized_new(false, true,
>> +                                        sizeof(struct qemu_plugin_hwaddr),
>> +                                        cpu->cpu_index + 1);
>> +    } else if (cpu->cpu_index >= hwaddr_refs->len) {
>> +        hwaddr_refs = g_array_set_size(hwaddr_refs, cpu->cpu_index + 1);
>> +    }
>
> Are there one or more race conditions with the allocations here? If so,
> could they be solved by doing the allocations at plugin initialization
> and when the number of online cpu's changes, instead of lazily?

It might be easier to just keep a __thread local array here and let TLS
deal with it.

--
Alex Bennée


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

* Re: [PATCH  v4 50/54] tests/plugin: add instruction execution breakdown
  2019-08-01 14:31   ` Aaron Lindsay OS via Qemu-devel
@ 2019-10-09 18:49     ` Alex Bennée
  0 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-10-09 18:49 UTC (permalink / raw)
  To: Aaron Lindsay OS; +Cc: bobby.prani, cota, qemu-devel


Aaron Lindsay OS <aaron@os.amperecomputing.com> writes:

> On Jul 31 17:07, Alex Bennée wrote:
>> + * Attempt to measure the amount of vectorisation that has been done
>> + * on some code by counting classes of instruction. This is very much
>> + * ARM specific.
>
> I suspect some of my plugins will also be architecture-specific. Does it
> make sense to have a plugin specify to QEMU which architectures or
> running modes (i.e. softmmu vs. linux user) it supports? Or
> alternatively to have QEMU expose this information to the plugin so that
> it can cleanly exit if its needs are not met?

I've exposed an information block with the qemu type in it as a string.
This allows the plugin to take appropriate action.

>
> -Aaron


--
Alex Bennée


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

* Re: [Qemu-devel] [PATCH v4 43/54] plugin: add API symbols to qemu-plugins.symbols
  2019-08-01 19:42   ` Richard Henderson
@ 2019-10-11 16:46     ` Alex Bennée
  0 siblings, 0 replies; 107+ messages in thread
From: Alex Bennée @ 2019-10-11 16:46 UTC (permalink / raw)
  To: Richard Henderson; +Cc: bobby.prani, cota, qemu-devel, aaron


Richard Henderson <richard.henderson@linaro.org> writes:

> On 7/31/19 9:07 AM, Alex Bennée wrote:
>> +#########################################
>> +# See if --dynamic-list is supported by the linker
>> +
>> +cat > $TMPTXT <<EOF
>> +{
>> +  foo;
>> +};
>> +EOF
>> +
>> +cat > $TMPC <<EOF
>> +#include <stdio.h>
>> +void foo(void);
>> +
>> +void foo(void)
>> +{
>> +  printf("foo\n");
>> +}
>> +
>> +int main(void)
>> +{
>> +  foo();
>> +  return 0;
>> +}
>> +EOF
>> +
>> +ld_dynamic_list="no"
>> +if compile_prog "" "-Wl,--dynamic-list=$TMPTXT" ; then
>> +  ld_dynamic_list="yes"
>> +fi
>> +
>> +#########################################
>> +# See if -exported_symbols_list is supported by the linker
>> +
>> +cat > $TMPTXT <<EOF
>> +  _foo
>> +EOF
>> +
>> +ld_exported_symbols_list="no"
>> +if compile_prog "" "-Wl,-exported_symbols_list,$TMPTXT" ; then
>> +  ld_exported_symbols_list="yes"
>> +fi
>> +
>> +if  test "$plugins" = "yes" &&
>> +    test "$ld_dynamic_list" = "no" &&
>> +    test "$ld_exported_symbols_list" = "no" ; then
>> +  error_exit \
>> +      "Plugin support requires specifying a set of symbols that " \
>> +      "are exported to plugins. Unfortunately your linker doesn't " \
>> +      "support the flag (--dynamic-list or -exported_symbols_list) used " \
>> +      "for this purpose."
>> +fi
>> +
>>  ########################################
>>  # See if 16-byte vector operations are supported.
>>  # Even without a vector unit the compiler may expand these.
>> @@ -7318,6 +7371,22 @@ fi
>>  if test "$plugins" = "yes" ; then
>>      echo "CONFIG_PLUGIN=y" >> $config_host_mak
>>      LIBS="-ldl $LIBS"
>> +    # Copy the export object list to the build dir
>> +    if test "$ld_dynamic_list" = "yes" ; then
>> +	echo "CONFIG_HAS_LD_DYNAMIC_LIST=yes" >> $config_host_mak
>> +	ld_symbols=qemu-plugins-ld.symbols
>> +	cp "$source_path/plugins/qemu-plugins.symbols" $ld_symbols
>> +    elif test "$ld_exported_symbols_list" = "yes" ; then
>> +	echo "CONFIG_HAS_LD_EXPORTED_SYMBOLS_LIST=yes" >> $config_host_mak
>> +	ld64_symbols=qemu-plugins-ld64.symbols
>> +	echo "# Automatically generated by configure - do not modify" > $ld64_symbols
>> +	grep 'qemu_' "$source_path/plugins/qemu-plugins.symbols" | sed 's/;//g' | \
>> +	    sed -E 's/^[[:space:]]*(.*)/_\1/' >> $ld64_symbols
>> +    else
>> +	error_exit \
>> +	    "If \$plugins=yes, either \$ld_dynamic_list or " \
>> +	    "\$ld_exported_symbols_list should have been set to 'yes'."
>> +    fi
>>  fi
>>
>
> How much of this should be skipped if --enable-static?
> Or perhaps just dependent on --enable-plugins and let
> that switch detect the conflict?

I've gated the ld_dynamic_list checks on if test "$static" = "no" so it
errors out quickly if you try and build with --static --enable-plugins.


>
>
> r~


--
Alex Bennée


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

end of thread, other threads:[~2019-10-11 18:46 UTC | newest]

Thread overview: 107+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-31 16:06 [Qemu-devel] [PATCH v4 00/54] plugins for TCG Alex Bennée
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 01/54] target/arm: handle M-profile semihosting at translate time Alex Bennée
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 02/54] target/arm: handle A-profile T32 " Alex Bennée
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 03/54] target/arm: handle A-profile A32 " Alex Bennée
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 04/54] target/arm: remove run time semihosting checks Alex Bennée
2019-08-01 13:27   ` Aaron Lindsay OS via Qemu-devel
2019-08-01 13:36     ` Peter Maydell
2019-08-01 14:53   ` Richard Henderson
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 05/54] includes: remove stale [smp|max]_cpus externs Alex Bennée
2019-08-01 14:54   ` Richard Henderson
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 06/54] trace: expand mem_info:size_shift to 4 bits Alex Bennée
2019-08-01 15:01   ` Richard Henderson
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 07/54] trace: add mmu_index to mem_info Alex Bennée
2019-08-01 15:17   ` Richard Henderson
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 08/54] tcg/README: fix typo s/afterwise/afterwards/ Alex Bennée
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 09/54] cpu: introduce cpu_in_exclusive_context() Alex Bennée
2019-08-01 15:23   ` Richard Henderson
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 10/54] translate-all: use cpu_in_exclusive_work_context() in tb_flush Alex Bennée
2019-08-01 15:25   ` Richard Henderson
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 11/54] docs/devel: add plugins.rst design document Alex Bennée
2019-08-01 15:31   ` Richard Henderson
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 12/54] configure: add --enable-plugins (MOVE TO END) Alex Bennée
2019-08-01 15:33   ` Richard Henderson
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 13/54] plugin: add user-facing API Alex Bennée
2019-08-01 15:39   ` Richard Henderson
2019-08-02 18:25   ` Aaron Lindsay OS via Qemu-devel
2019-09-06 19:31     ` Alex Bennée
2019-09-10 16:24       ` Aaron Lindsay OS via Qemu-devel
2019-09-10 17:41         ` Alex Bennée
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 14/54] plugin: add core code Alex Bennée
2019-08-01 15:58   ` Richard Henderson
2019-09-12  9:17   ` Daniel P. Berrangé
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 15/54] plugin: add implementation of the api Alex Bennée
2019-08-01 16:14   ` Richard Henderson
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 16/54] queue: add QTAILQ_REMOVE_SEVERAL Alex Bennée
2019-08-01 16:16   ` Richard Henderson
2019-08-01 16:16   ` Richard Henderson
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 17/54] cputlb: document get_page_addr_code Alex Bennée
2019-08-01 17:08   ` Richard Henderson
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 18/54] cputlb: introduce get_page_addr_code_hostp Alex Bennée
2019-08-01 17:10   ` Richard Henderson
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 19/54] tcg: add tcg_gen_st_ptr Alex Bennée
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 20/54] plugin-gen: add module for TCG-related code Alex Bennée
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 21/54] atomic_template: fix indentation in GEN_ATOMIC_HELPER Alex Bennée
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 22/54] atomic_template: add inline trace/plugin helpers Alex Bennée
2019-08-01 18:23   ` Richard Henderson
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 23/54] tcg: let plugins instrument virtual memory accesses Alex Bennée
2019-08-01 18:29   ` Richard Henderson
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 24/54] plugins: implement helpers for resolving hwaddr Alex Bennée
2019-08-01 14:14   ` Aaron Lindsay OS via Qemu-devel
2019-08-01 18:37     ` Richard Henderson
2019-10-09 17:45     ` Alex Bennée
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 25/54] translate-all: notify plugin code of tb_flush Alex Bennée
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 26/54] *-user: notify plugin of exit Alex Bennée
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 27/54] *-user: plugin syscalls Alex Bennée
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 28/54] cpu: hook plugin vcpu events Alex Bennée
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 29/54] plugin-gen: add plugin_insn_append Alex Bennée
2019-08-01 18:39   ` Richard Henderson
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 30/54] translator: add translator_ld{ub, sw, uw, l, q} Alex Bennée
2019-08-01 19:24   ` Richard Henderson
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 31/54] target/arm: fetch code with translator_ld Alex Bennée
2019-08-01 19:26   ` Richard Henderson
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 32/54] target/ppc: " Alex Bennée
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 33/54] target/sh4: " Alex Bennée
2019-07-31 16:06 ` [Qemu-devel] [PATCH v4 34/54] target/i386: " Alex Bennée
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 35/54] target/hppa: " Alex Bennée
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 36/54] target/m68k: " Alex Bennée
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 37/54] target/alpha: " Alex Bennée
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 38/54] target/riscv: " Alex Bennée
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 39/54] target/sparc: " Alex Bennée
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 40/54] target/xtensa: " Alex Bennée
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 41/54] target/openrisc: " Alex Bennée
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 42/54] translator: inject instrumentation from plugins Alex Bennée
2019-08-01 19:35   ` Richard Henderson
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 43/54] plugin: add API symbols to qemu-plugins.symbols Alex Bennée
2019-08-01 19:42   ` Richard Henderson
2019-10-11 16:46     ` Alex Bennée
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 44/54] vl: support -plugin option Alex Bennée
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 45/54] linux-user: " Alex Bennée
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 46/54] tests/plugin: add sample plugins Alex Bennée
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 47/54] tests/tcg: enable plugin testing Alex Bennée
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 48/54] tests/plugin: add a hotblocks plugin Alex Bennée
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 49/54] plugin: add qemu_plugin_insn_disas helper Alex Bennée
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 50/54] tests/plugin: add instruction execution breakdown Alex Bennée
2019-08-01 14:31   ` Aaron Lindsay OS via Qemu-devel
2019-10-09 18:49     ` Alex Bennée
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 51/54] tests/plugin: add hotpages plugin to breakdown memory access patterns Alex Bennée
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 52/54] accel/stubs: reduce headers from tcg-stub Alex Bennée
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 53/54] include/exec: wrap cpu_ldst.h in CONFIG_TCG Alex Bennée
2019-08-01 19:51   ` Richard Henderson
2019-07-31 16:07 ` [Qemu-devel] [PATCH v4 54/54] include/exec/cpu-defs.h: fix typo Alex Bennée
2019-07-31 17:00 ` [Qemu-devel] [PATCH v4 00/54] plugins for TCG no-reply
2019-08-01  4:19 ` Markus Armbruster
2019-09-06 19:52   ` Alex Bennée
2019-09-10 16:16     ` Aaron Lindsay OS via Qemu-devel
2019-09-10 17:37       ` Alex Bennée
2019-09-10 16:34     ` Peter Maydell
2019-09-12  6:46     ` [Qemu-devel] TCG plugins and the GPL (was: [PATCH v4 00/54] plugins for TCG) Markus Armbruster
2019-09-12  9:03       ` Alex Bennée
2019-09-12  9:21         ` Peter Maydell
2019-09-12 10:07           ` Alex Bennée
2019-09-12 10:16             ` Daniel P. Berrangé
2019-09-12 10:21               ` Peter Maydell
2019-09-12 10:18             ` Peter Maydell
2019-09-12 10:35               ` Alex Bennée
2019-09-12  9:32         ` Daniel P. Berrangé
2019-08-01 14:20 ` [Qemu-devel] [PATCH v4 00/54] plugins for TCG no-reply

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).