diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2021-09-03 14:23:36 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2021-09-03 14:23:36 +0100 |
commit | 9c03aa87e52567f6c9a7bf456e5dd94dc84088de (patch) | |
tree | d3c63b25ddaf5a1f6268bc40c81c9abff8df611e | |
parent | 8880cc4362fde4ecdac0b2092318893118206fcf (diff) | |
parent | a35af836d103f781d2fea437129732c16ba64b25 (diff) | |
download | qemu-9c03aa87e52567f6c9a7bf456e5dd94dc84088de.zip qemu-9c03aa87e52567f6c9a7bf456e5dd94dc84088de.tar.gz qemu-9c03aa87e52567f6c9a7bf456e5dd94dc84088de.tar.bz2 |
Merge remote-tracking branch 'remotes/stsquad/tags/pull-for-6.2-020921-1' into staging
Testing and plugin updates:
- fix typo in execlog plugin
- clean-up and document gitlab FOO_RUNNER_AVAILABLE vars
- fix plugin build issue on OSX and modules
- add multi-core support to cache modelling plugin
- clean-ups for plugin arg=FOO handling
# gpg: Signature made Thu 02 Sep 2021 11:33:02 BST
# gpg: using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44
# gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" [full]
# Primary key fingerprint: 6685 AE99 E751 67BC AFC8 DF35 FBD0 DB09 5A9E 2A44
* remotes/stsquad/tags/pull-for-6.2-020921-1: (22 commits)
docs/devel: be consistent about example plugin names
docs/deprecated: deprecate passing plugin args through `arg=`
tests/plugins/syscalls: adhere to new arg-passing scheme
tests/plugins/mem: introduce "track" arg and make args not positional
tests/plugins/insn: made arg inline not positional and parse it as bool
tests/plugins/bb: adapt to the new arg passing scheme
docs/tcg-plugins: new passing parameters scheme for cache docs
plugins/howvec: adapting to the new argument passing scheme
plugins/hwprofile: adapt to the new plugin arguments scheme
plugins/lockstep: make socket path not positional & parse bool arg
plugins/hotblocks: Added correct boolean argument parsing
plugins/hotpages: introduce sortby arg and parsed bool args correctly
plugins/api: added a boolean parsing plugin api
plugins: allow plugin arguments to be passed directly
docs/devel/tcg-plugins: added cores arg to cache plugin
plugins: sort exported symbol list
plugins/cache: supported multicore cache modelling
plugins: do not limit exported symbols if modules are active
gitlab-ci: Fix ..._RUNNER_AVAILABLE variables and document them
gitlab-ci: Remove superfluous "dnf install" statement
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | .gitlab-ci.d/buildtest.yml | 99 | ||||
-rw-r--r-- | .gitlab-ci.d/custom-runners.yml | 12 | ||||
-rwxr-xr-x | configure | 5 | ||||
-rw-r--r-- | contrib/plugins/cache.c | 176 | ||||
-rw-r--r-- | contrib/plugins/execlog.c | 2 | ||||
-rw-r--r-- | contrib/plugins/hotblocks.c | 14 | ||||
-rw-r--r-- | contrib/plugins/hotpages.c | 30 | ||||
-rw-r--r-- | contrib/plugins/howvec.c | 27 | ||||
-rw-r--r-- | contrib/plugins/hwprofile.c | 39 | ||||
-rw-r--r-- | contrib/plugins/lockstep.c | 31 | ||||
-rw-r--r-- | docs/about/deprecated.rst | 12 | ||||
-rw-r--r-- | docs/devel/ci-jobs.rst | 11 | ||||
-rw-r--r-- | docs/devel/tcg-plugins.rst | 68 | ||||
-rw-r--r-- | include/qemu/qemu-plugin.h | 13 | ||||
-rw-r--r-- | linux-user/main.c | 2 | ||||
-rw-r--r-- | plugins/api.c | 5 | ||||
-rw-r--r-- | plugins/loader.c | 24 | ||||
-rw-r--r-- | plugins/meson.build | 14 | ||||
-rw-r--r-- | plugins/qemu-plugins.symbols | 49 | ||||
-rw-r--r-- | qemu-options.hx | 9 | ||||
-rw-r--r-- | tests/plugin/bb.c | 15 | ||||
-rw-r--r-- | tests/plugin/insn.c | 14 | ||||
-rw-r--r-- | tests/plugin/mem.c | 47 | ||||
-rw-r--r-- | tests/plugin/syscall.c | 23 | ||||
-rw-r--r-- | tests/tcg/i386/Makefile.softmmu-target | 2 | ||||
-rw-r--r-- | tests/tcg/i386/Makefile.target | 2 | ||||
-rw-r--r-- | tests/tcg/x86_64/Makefile.softmmu-target | 2 |
27 files changed, 467 insertions, 280 deletions
diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index e74998e..be4d90c 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -202,85 +202,6 @@ acceptance-system-opensuse: MAKE_CHECK_ARGS: check-acceptance -build-disabled: - extends: .native_build_job_template - needs: - job: amd64-fedora-container - variables: - IMAGE: fedora - CONFIGURE_ARGS: - --disable-attr - --disable-auth-pam - --disable-avx2 - --disable-bochs - --disable-brlapi - --disable-bzip2 - --disable-cap-ng - --disable-capstone - --disable-cloop - --disable-coroutine-pool - --disable-curl - --disable-curses - --disable-dmg - --disable-docs - --disable-gcrypt - --disable-glusterfs - --disable-gnutls - --disable-gtk - --disable-guest-agent - --disable-iconv - --disable-keyring - --disable-kvm - --disable-libiscsi - --disable-libpmem - --disable-libssh - --disable-libudev - --disable-libusb - --disable-libxml2 - --disable-linux-aio - --disable-live-block-migration - --disable-lzo - --disable-malloc-trim - --disable-mpath - --disable-nettle - --disable-numa - --disable-opengl - --disable-parallels - --disable-pie - --disable-qcow1 - --disable-qed - --disable-qom-cast-debug - --disable-rbd - --disable-rdma - --disable-replication - --disable-sdl - --disable-seccomp - --disable-slirp - --disable-smartcard - --disable-snappy - --disable-sparse - --disable-spice - --disable-strip - --disable-tpm - --disable-usb-redir - --disable-vdi - --disable-vhost-crypto - --disable-vhost-net - --disable-vhost-scsi - --disable-vhost-kernel - --disable-vhost-user - --disable-vhost-vdpa - --disable-vhost-vsock - --disable-virglrenderer - --disable-vnc - --disable-vte - --disable-vvfat - --disable-xen - --disable-zstd - TARGETS: arm-softmmu i386-softmmu ppc64-softmmu mips64-softmmu - s390x-softmmu i386-linux-user - MAKE_CHECK_ARGS: check-qtest SPEED=slow - # This jobs explicitly disable TCG (--disable-tcg), KVM is detected by # the configure script. The container doesn't contain Xen headers so # Xen accelerator is not detected / selected. As result it build the @@ -649,20 +570,26 @@ build-without-default-devices: build-without-default-features: extends: .native_build_job_template needs: - job: amd64-debian-container + job: amd64-fedora-container variables: - IMAGE: debian-amd64 - CONFIGURE_ARGS: --without-default-features --disable-user - --target-list-exclude=arm-softmmu,i386-softmmu,mipsel-softmmu,mips64-softmmu,ppc-softmmu - MAKE_CHECK_ARGS: check-unit + IMAGE: fedora + CONFIGURE_ARGS: + --without-default-features + --disable-capstone + --disable-fdt + --disable-pie + --disable-qom-cast-debug + --disable-slirp + --disable-strip + TARGETS: avr-softmmu i386-softmmu mips64-softmmu s390x-softmmu sh4-softmmu + sparc64-softmmu hexagon-linux-user i386-linux-user s390x-linux-user + MAKE_CHECK_ARGS: check-unit check-qtest SPEED=slow build-libvhost-user: stage: build image: $CI_REGISTRY_IMAGE/qemu/fedora:latest needs: job: amd64-fedora-container - before_script: - - dnf install -y meson ninja-build script: - mkdir subprojects/libvhost-user/build - cd subprojects/libvhost-user/build diff --git a/.gitlab-ci.d/custom-runners.yml b/.gitlab-ci.d/custom-runners.yml index 564b945..0d3e4a7 100644 --- a/.gitlab-ci.d/custom-runners.yml +++ b/.gitlab-ci.d/custom-runners.yml @@ -137,7 +137,7 @@ ubuntu-20.04-aarch64-all-linux-static: - aarch64 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' - - if: "$S390X_RUNNER_AVAILABLE" + - if: "$AARCH64_RUNNER_AVAILABLE" script: # --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763 # --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages @@ -157,7 +157,7 @@ ubuntu-20.04-aarch64-all: - aarch64 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' - - if: "$S390X_RUNNER_AVAILABLE" + - if: "$AARCH64_RUNNER_AVAILABLE" script: - mkdir build - cd build @@ -174,7 +174,7 @@ ubuntu-20.04-aarch64-alldbg: - aarch64 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' - - if: "$S390X_RUNNER_AVAILABLE" + - if: "$AARCH64_RUNNER_AVAILABLE" script: - mkdir build - cd build @@ -193,7 +193,7 @@ ubuntu-20.04-aarch64-clang: rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' when: manual - - if: "$S390X_RUNNER_AVAILABLE" + - if: "$AARCH64_RUNNER_AVAILABLE" when: manual script: - mkdir build @@ -211,7 +211,7 @@ ubuntu-20.04-aarch64-tci: - aarch64 rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' - - if: "$S390X_RUNNER_AVAILABLE" + - if: "$AARCH64_RUNNER_AVAILABLE" script: - mkdir build - cd build @@ -228,7 +228,7 @@ ubuntu-20.04-aarch64-notcg: rules: - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/' when: manual - - if: "$S390X_RUNNER_AVAILABLE" + - if: "$AARCH64_RUNNER_AVAILABLE" when: manual script: - mkdir build @@ -3187,9 +3187,8 @@ glib_req_ver=2.56 glib_modules=gthread-2.0 if test "$modules" = yes; then glib_modules="$glib_modules gmodule-export-2.0" -fi -if test "$plugins" = "yes"; then - glib_modules="$glib_modules gmodule-2.0" +elif test "$plugins" = "yes"; then + glib_modules="$glib_modules gmodule-no-export-2.0" fi for i in $glib_modules; do diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c index 066ea6d..a1e03ca 100644 --- a/contrib/plugins/cache.c +++ b/contrib/plugins/cache.c @@ -17,18 +17,12 @@ static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW; static GHashTable *miss_ht; -static GMutex mtx; +static GMutex hashtable_lock; static GRand *rng; static int limit; static bool sys; -static uint64_t dmem_accesses; -static uint64_t dmisses; - -static uint64_t imem_accesses; -static uint64_t imisses; - enum EvictionPolicy { LRU, FIFO, @@ -80,6 +74,8 @@ typedef struct { int blksize_shift; uint64_t set_mask; uint64_t tag_mask; + uint64_t accesses; + uint64_t misses; } Cache; typedef struct { @@ -96,7 +92,16 @@ void (*update_miss)(Cache *cache, int set, int blk); void (*metadata_init)(Cache *cache); void (*metadata_destroy)(Cache *cache); -Cache *dcache, *icache; +static int cores; +static Cache **dcaches, **icaches; + +static GMutex *dcache_locks; +static GMutex *icache_locks; + +static uint64_t all_dmem_accesses; +static uint64_t all_imem_accesses; +static uint64_t all_imisses; +static uint64_t all_dmisses; static int pow_of_two(int num) { @@ -233,20 +238,24 @@ static bool bad_cache_params(int blksize, int assoc, int cachesize) static Cache *cache_init(int blksize, int assoc, int cachesize) { - if (bad_cache_params(blksize, assoc, cachesize)) { - return NULL; - } - Cache *cache; int i; uint64_t blk_mask; + /* + * This function shall not be called directly, and hence expects suitable + * parameters. + */ + g_assert(!bad_cache_params(blksize, assoc, cachesize)); + cache = g_new(Cache, 1); cache->assoc = assoc; cache->cachesize = cachesize; cache->num_sets = cachesize / (blksize * assoc); cache->sets = g_new(CacheSet, cache->num_sets); cache->blksize_shift = pow_of_two(blksize); + cache->accesses = 0; + cache->misses = 0; for (i = 0; i < cache->num_sets; i++) { cache->sets[i].blocks = g_new0(CacheBlock, assoc); @@ -263,6 +272,24 @@ static Cache *cache_init(int blksize, int assoc, int cachesize) return cache; } +static Cache **caches_init(int blksize, int assoc, int cachesize) +{ + Cache **caches; + int i; + + if (bad_cache_params(blksize, assoc, cachesize)) { + return NULL; + } + + caches = g_new(Cache *, cores); + + for (i = 0; i < cores; i++) { + caches[i] = cache_init(blksize, assoc, cachesize); + } + + return caches; +} + static int get_invalid_block(Cache *cache, uint64_t set) { int i; @@ -353,6 +380,7 @@ static void vcpu_mem_access(unsigned int vcpu_index, qemu_plugin_meminfo_t info, { uint64_t effective_addr; struct qemu_plugin_hwaddr *hwaddr; + int cache_idx; InsnData *insn; hwaddr = qemu_plugin_get_hwaddr(info, vaddr); @@ -361,32 +389,35 @@ static void vcpu_mem_access(unsigned int vcpu_index, qemu_plugin_meminfo_t info, } effective_addr = hwaddr ? qemu_plugin_hwaddr_phys_addr(hwaddr) : vaddr; + cache_idx = vcpu_index % cores; - g_mutex_lock(&mtx); - if (!access_cache(dcache, effective_addr)) { + g_mutex_lock(&dcache_locks[cache_idx]); + if (!access_cache(dcaches[cache_idx], effective_addr)) { insn = (InsnData *) userdata; - insn->dmisses++; - dmisses++; + __atomic_fetch_add(&insn->dmisses, 1, __ATOMIC_SEQ_CST); + dcaches[cache_idx]->misses++; } - dmem_accesses++; - g_mutex_unlock(&mtx); + dcaches[cache_idx]->accesses++; + g_mutex_unlock(&dcache_locks[cache_idx]); } static void vcpu_insn_exec(unsigned int vcpu_index, void *userdata) { uint64_t insn_addr; InsnData *insn; + int cache_idx; - g_mutex_lock(&mtx); insn_addr = ((InsnData *) userdata)->addr; - if (!access_cache(icache, insn_addr)) { + cache_idx = vcpu_index % cores; + g_mutex_lock(&icache_locks[cache_idx]); + if (!access_cache(icaches[cache_idx], insn_addr)) { insn = (InsnData *) userdata; - insn->imisses++; - imisses++; + __atomic_fetch_add(&insn->imisses, 1, __ATOMIC_SEQ_CST); + icaches[cache_idx]->misses++; } - imem_accesses++; - g_mutex_unlock(&mtx); + icaches[cache_idx]->accesses++; + g_mutex_unlock(&icache_locks[cache_idx]); } static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) @@ -411,7 +442,7 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) * new entries for those instructions. Instead, we fetch the same * entry from the hash table and register it for the callback again. */ - g_mutex_lock(&mtx); + g_mutex_lock(&hashtable_lock); data = g_hash_table_lookup(miss_ht, GUINT_TO_POINTER(effective_addr)); if (data == NULL) { data = g_new0(InsnData, 1); @@ -421,7 +452,7 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) g_hash_table_insert(miss_ht, GUINT_TO_POINTER(effective_addr), (gpointer) data); } - g_mutex_unlock(&mtx); + g_mutex_unlock(&hashtable_lock); qemu_plugin_register_vcpu_mem_cb(insn, vcpu_mem_access, QEMU_PLUGIN_CB_NO_REGS, @@ -453,6 +484,15 @@ static void cache_free(Cache *cache) g_free(cache); } +static void caches_free(Cache **caches) +{ + int i; + + for (i = 0; i < cores; i++) { + cache_free(caches[i]); + } +} + static int dcmp(gconstpointer a, gconstpointer b) { InsnData *insn_a = (InsnData *) a; @@ -461,6 +501,37 @@ static int dcmp(gconstpointer a, gconstpointer b) return insn_a->dmisses < insn_b->dmisses ? 1 : -1; } +static void append_stats_line(GString *line, uint64_t daccess, uint64_t dmisses, + uint64_t iaccess, uint64_t imisses) +{ + double dmiss_rate, imiss_rate; + + dmiss_rate = ((double) dmisses) / (daccess) * 100.0; + imiss_rate = ((double) imisses) / (iaccess) * 100.0; + + g_string_append_printf(line, "%-14lu %-12lu %9.4lf%% %-14lu %-12lu" + " %9.4lf%%\n", + daccess, + dmisses, + daccess ? dmiss_rate : 0.0, + iaccess, + imisses, + iaccess ? imiss_rate : 0.0); +} + +static void sum_stats(void) +{ + int i; + + g_assert(cores > 1); + for (i = 0; i < cores; i++) { + all_imisses += icaches[i]->misses; + all_dmisses += dcaches[i]->misses; + all_imem_accesses += icaches[i]->accesses; + all_dmem_accesses += dcaches[i]->accesses; + } +} + static int icmp(gconstpointer a, gconstpointer b) { InsnData *insn_a = (InsnData *) a; @@ -471,19 +542,29 @@ static int icmp(gconstpointer a, gconstpointer b) static void log_stats(void) { - g_autoptr(GString) rep = g_string_new(""); - g_string_append_printf(rep, - "Data accesses: %lu, Misses: %lu\nMiss rate: %lf%%\n\n", - dmem_accesses, - dmisses, - ((double) dmisses / (double) dmem_accesses) * 100.0); - - g_string_append_printf(rep, - "Instruction accesses: %lu, Misses: %lu\nMiss rate: %lf%%\n\n", - imem_accesses, - imisses, - ((double) imisses / (double) imem_accesses) * 100.0); + int i; + Cache *icache, *dcache; + + g_autoptr(GString) rep = g_string_new("core #, data accesses, data misses," + " dmiss rate, insn accesses," + " insn misses, imiss rate\n"); + + for (i = 0; i < cores; i++) { + g_string_append_printf(rep, "%-8d", i); + dcache = dcaches[i]; + icache = icaches[i]; + append_stats_line(rep, dcache->accesses, dcache->misses, + icache->accesses, icache->misses); + } + + if (cores > 1) { + sum_stats(); + g_string_append_printf(rep, "%-8s", "sum"); + append_stats_line(rep, all_dmem_accesses, all_dmisses, + all_imem_accesses, all_imisses); + } + g_string_append(rep, "\n"); qemu_plugin_outs(rep->str); } @@ -530,8 +611,8 @@ static void plugin_exit(qemu_plugin_id_t id, void *p) log_stats(); log_top_insns(); - cache_free(dcache); - cache_free(icache); + caches_free(dcaches); + caches_free(icaches); g_hash_table_destroy(miss_ht); } @@ -579,6 +660,8 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, policy = LRU; + cores = sys ? qemu_plugin_n_vcpus() : 1; + for (i = 0; i < argc; i++) { char *opt = argv[i]; if (g_str_has_prefix(opt, "iblksize=")) { @@ -595,6 +678,8 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, dcachesize = g_ascii_strtoll(opt + 11, NULL, 10); } else if (g_str_has_prefix(opt, "limit=")) { limit = g_ascii_strtoll(opt + 6, NULL, 10); + } else if (g_str_has_prefix(opt, "cores=")) { + cores = g_ascii_strtoll(opt + 6, NULL, 10); } else if (g_str_has_prefix(opt, "evict=")) { gchar *p = opt + 6; if (g_strcmp0(p, "rand") == 0) { @@ -615,22 +700,25 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, policy_init(); - dcache = cache_init(dblksize, dassoc, dcachesize); - if (!dcache) { + dcaches = caches_init(dblksize, dassoc, dcachesize); + if (!dcaches) { const char *err = cache_config_error(dblksize, dassoc, dcachesize); fprintf(stderr, "dcache cannot be constructed from given parameters\n"); fprintf(stderr, "%s\n", err); return -1; } - icache = cache_init(iblksize, iassoc, icachesize); - if (!icache) { + icaches = caches_init(iblksize, iassoc, icachesize); + if (!icaches) { const char *err = cache_config_error(iblksize, iassoc, icachesize); fprintf(stderr, "icache cannot be constructed from given parameters\n"); fprintf(stderr, "%s\n", err); return -1; } + dcache_locks = g_new0(GMutex, cores); + icache_locks = g_new0(GMutex, cores); + qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); qemu_plugin_register_atexit_cb(id, plugin_exit, NULL); diff --git a/contrib/plugins/execlog.c b/contrib/plugins/execlog.c index 2de9f0d..a5275dc 100644 --- a/contrib/plugins/execlog.c +++ b/contrib/plugins/execlog.c @@ -67,7 +67,7 @@ static void vcpu_insn_exec(unsigned int cpu_index, void *udata) /* Print previous instruction in cache */ if (s->len) { qemu_plugin_outs(s->str); - qemu_plugin_outs("s\n"); + qemu_plugin_outs("\n"); } /* Store new instruction in cache */ diff --git a/contrib/plugins/hotblocks.c b/contrib/plugins/hotblocks.c index 4b08340..062200a 100644 --- a/contrib/plugins/hotblocks.c +++ b/contrib/plugins/hotblocks.c @@ -133,8 +133,18 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, int argc, char **argv) { - if (argc && strcmp(argv[0], "inline") == 0) { - do_inline = true; + for (int i = 0; i < argc; i++) { + char *opt = argv[i]; + g_autofree char **tokens = g_strsplit(opt, "=", 2); + if (g_strcmp0(tokens[0], "inline") == 0) { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) { + fprintf(stderr, "boolean argument parsing failed: %s\n", opt); + return -1; + } + } else { + fprintf(stderr, "option parsing failed: %s\n", opt); + return -1; + } } plugin_init(); diff --git a/contrib/plugins/hotpages.c b/contrib/plugins/hotpages.c index bf53267..0d12910 100644 --- a/contrib/plugins/hotpages.c +++ b/contrib/plugins/hotpages.c @@ -169,16 +169,26 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, 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_strcmp0(opt, "address") == 0) { - sort_by = SORT_A; - } else if (g_strcmp0(opt, "io") == 0) { - track_io = true; - } else if (g_str_has_prefix(opt, "pagesize=")) { - page_size = g_ascii_strtoull(opt + 9, NULL, 10); + g_autofree char **tokens = g_strsplit(opt, "=", -1); + + if (g_strcmp0(tokens[0], "sortby") == 0) { + if (g_strcmp0(tokens[1], "reads") == 0) { + sort_by = SORT_R; + } else if (g_strcmp0(tokens[1], "writes") == 0) { + sort_by = SORT_W; + } else if (g_strcmp0(tokens[1], "address") == 0) { + sort_by = SORT_A; + } else { + fprintf(stderr, "invalid value to sortby: %s\n", tokens[1]); + return -1; + } + } else if (g_strcmp0(tokens[0], "io") == 0) { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &track_io)) { + fprintf(stderr, "boolean argument parsing failed: %s\n", opt); + return -1; + } + } else if (g_strcmp0(tokens[0], "pagesize") == 0) { + page_size = g_ascii_strtoull(tokens[1], NULL, 10); } else { fprintf(stderr, "option parsing failed: %s\n", opt); return -1; diff --git a/contrib/plugins/howvec.c b/contrib/plugins/howvec.c index 600f7fa..4a5ec3d 100644 --- a/contrib/plugins/howvec.c +++ b/contrib/plugins/howvec.c @@ -333,23 +333,34 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, 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 { + g_autofree char **tokens = g_strsplit(p, "=", -1); + if (g_strcmp0(tokens[0], "inline") == 0) { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) { + fprintf(stderr, "boolean argument parsing failed: %s\n", p); + return -1; + } + } else if (g_strcmp0(tokens[0], "verbose") == 0) { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &verbose)) { + fprintf(stderr, "boolean argument parsing failed: %s\n", p); + return -1; + } + } else if (g_strcmp0(tokens[0], "count") == 0) { + char *value = tokens[1]; int j; CountType type = COUNT_INDIVIDUAL; - if (*p == '!') { + if (*value == '!') { type = COUNT_NONE; - p++; + value++; } for (j = 0; j < class_table_sz; j++) { - if (strcmp(p, class_table[j].opt) == 0) { + if (strcmp(value, class_table[j].opt) == 0) { class_table[j].what = type; break; } } + } else { + fprintf(stderr, "option parsing failed: %s\n", p); + return -1; } } diff --git a/contrib/plugins/hwprofile.c b/contrib/plugins/hwprofile.c index faf216a..691d4ed 100644 --- a/contrib/plugins/hwprofile.c +++ b/contrib/plugins/hwprofile.c @@ -259,27 +259,42 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, int argc, char **argv) { int i; + g_autoptr(GString) matches_raw = g_string_new(""); for (i = 0; i < argc; i++) { char *opt = argv[i]; - if (g_strcmp0(opt, "read") == 0) { - rw = QEMU_PLUGIN_MEM_R; - } else if (g_strcmp0(opt, "write") == 0) { - rw = QEMU_PLUGIN_MEM_W; - } else if (g_strcmp0(opt, "pattern") == 0) { - pattern = true; - } else if (g_strcmp0(opt, "source") == 0) { - source = true; - } else if (g_str_has_prefix(opt, "match")) { - gchar **parts = g_strsplit(opt, "=", 2); + g_autofree char **tokens = g_strsplit(opt, "=", 2); + + if (g_strcmp0(tokens[0], "track") == 0) { + if (g_strcmp0(tokens[1], "read") == 0) { + rw = QEMU_PLUGIN_MEM_R; + } else if (g_strcmp0(tokens[1], "write") == 0) { + rw = QEMU_PLUGIN_MEM_W; + } else { + fprintf(stderr, "invalid value for track: %s\n", tokens[1]); + return -1; + } + } else if (g_strcmp0(tokens[0], "pattern") == 0) { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &pattern)) { + fprintf(stderr, "boolean argument parsing failed: %s\n", opt); + return -1; + } + } else if (g_strcmp0(tokens[0], "source") == 0) { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &source)) { + fprintf(stderr, "boolean argument parsing failed: %s\n", opt); + return -1; + } + } else if (g_strcmp0(tokens[0], "match") == 0) { check_match = true; - matches = g_strsplit(parts[1], ",", -1); - g_strfreev(parts); + g_string_append_printf(matches_raw, "%s,", tokens[1]); } else { fprintf(stderr, "option parsing failed: %s\n", opt); return -1; } } + if (check_match) { + matches = g_strsplit(matches_raw->str, ",", -1); + } if (source && pattern) { fprintf(stderr, "can only currently track either source or pattern.\n"); diff --git a/contrib/plugins/lockstep.c b/contrib/plugins/lockstep.c index 7fd35eb..a41ffe8 100644 --- a/contrib/plugins/lockstep.c +++ b/contrib/plugins/lockstep.c @@ -319,22 +319,35 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, int argc, char **argv) { int i; - - if (!argc || !argv[0]) { - qemu_plugin_outs("Need a socket path to talk to other instance."); - return -1; - } + g_autofree char *sock_path = NULL; for (i = 0; i < argc; i++) { char *p = argv[i]; - if (strcmp(p, "verbose") == 0) { - verbose = true; - } else if (!setup_unix_socket(argv[0])) { - qemu_plugin_outs("Failed to setup socket for communications."); + g_autofree char **tokens = g_strsplit(p, "=", 2); + + if (g_strcmp0(tokens[0], "verbose") == 0) { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &verbose)) { + fprintf(stderr, "boolean argument parsing failed: %s\n", p); + return -1; + } + } else if (g_strcmp0(tokens[0], "sockpath") == 0) { + sock_path = tokens[1]; + } else { + fprintf(stderr, "option parsing failed: %s\n", p); return -1; } } + if (sock_path == NULL) { + fprintf(stderr, "Need a socket path to talk to other instance.\n"); + return -1; + } + + if (!setup_unix_socket(sock_path)) { + fprintf(stderr, "Failed to setup socket for communications.\n"); + return -1; + } + our_id = id; qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 1e1a5e9..6e88a84 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -139,6 +139,18 @@ The ``-no-quit`` is a synonym for ``-display ...,window-close=off`` which should be used instead. +Plugin argument passing through ``arg=<string>`` (since 6.1) +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Passing TCG plugins arguments through ``arg=`` is redundant is makes the +command-line less readable, especially when the argument itself consist of a +name and a value, e.g. ``-plugin plugin_name,arg="arg_name=arg_value"``. +Therefore, the usage of ``arg`` is redundant. Single-word arguments are treated +as short-form boolean values, and passed to plugins as ``arg_name=on``. +However, short-form booleans are deprecated and full explicit ``arg_name=on`` +form is preferred. + + QEMU Machine Protocol (QMP) commands ------------------------------------ diff --git a/docs/devel/ci-jobs.rst b/docs/devel/ci-jobs.rst index 9cd9819..277975e 100644 --- a/docs/devel/ci-jobs.rst +++ b/docs/devel/ci-jobs.rst @@ -38,3 +38,14 @@ these artifacts are not already cached, downloading them make the jobs reach the timeout limit). Set this variable to have the tests using the Avocado framework run automatically. +AARCH64_RUNNER_AVAILABLE +~~~~~~~~~~~~~~~~~~~~~~~~ +If you've got access to an aarch64 host that can be used as a gitlab-CI +runner, you can set this variable to enable the tests that require this +kind of host. The runner should be tagged with "aarch64". + +S390X_RUNNER_AVAILABLE +~~~~~~~~~~~~~~~~~~~~~~ +If you've got access to an IBM Z host that can be used as a gitlab-CI +runner, you can set this variable to enable the tests that require this +kind of host. The runner should be tagged with "s390x". diff --git a/docs/devel/tcg-plugins.rst b/docs/devel/tcg-plugins.rst index 047bf4a..dac5101 100644 --- a/docs/devel/tcg-plugins.rst +++ b/docs/devel/tcg-plugins.rst @@ -80,7 +80,7 @@ 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/libhowvec.so,inline=on,count=hint \ -plugin tests/plugin/libhotblocks.so Arguments are plugin specific and can be used to modify their @@ -193,17 +193,32 @@ Similar to hotblocks but this time tracks memory accesses:: 0x0000000048b000, 0x0001, 130594, 0x0001, 355 0x0000000048a000, 0x0001, 1826, 0x0001, 11 +The hotpages plugin can be configured using the following arguments: + + * sortby=reads|writes|address + + Log the data sorted by either the number of reads, the number of writes, or + memory address. (Default: entries are sorted by the sum of reads and writes) + + * io=on + + Track IO addresses. Only relevant to full system emulation. (Default: off) + + * pagesize=N + + The page size used. (Default: N = 4096) + - contrib/plugins/howvec.c This is an instruction classifier so can be used to count different types of instructions. It has a number of options to refine which get -counted. You can give an argument for a class of instructions to break -it down fully, so for example to see all the system registers -accesses:: +counted. You can give a value to the `count` argument for a class of +instructions to break it down fully, so for example to see all the system +registers accesses:: ./aarch64-softmmu/qemu-system-aarch64 $(QEMU_ARGS) \ -append "root=/dev/sda2 systemd.unit=benchmark.service" \ - -smp 4 -plugin ./contrib/plugins/libhowvec.so,arg=sreg -d plugin + -smp 4 -plugin ./contrib/plugins/libhowvec.so,count=sreg -d plugin which will lead to a sorted list after the class breakdown:: @@ -271,7 +286,7 @@ communicate over:: ./sparc-softmmu/qemu-system-sparc -monitor none -parallel none \ -net none -M SS-20 -m 256 -kernel day11/zImage.elf \ - -plugin ./contrib/plugins/liblockstep.so,arg=lockstep-sparc.sock \ + -plugin ./contrib/plugins/liblockstep.so,sockpath=lockstep-sparc.sock \ -d plugin,nochain which will eventually report:: @@ -286,27 +301,27 @@ which will eventually report:: previously @ 0x000000ffd08098/5 (809900593 insns) previously @ 0x000000ffd080c0/1 (809900588 insns) -- contrib/plugins/hwprofile +- contrib/plugins/hwprofile.c The hwprofile tool can only be used with system emulation and allows the user to see what hardware is accessed how often. It has a number of options: - * arg=read or arg=write + * track=read or track=write By default the plugin tracks both reads and writes. You can use one of these options to limit the tracking to just one class of accesses. - * arg=source + * source Will include a detailed break down of what the guest PC that made the - access was. Not compatible with arg=pattern. Example output:: + access was. Not compatible with the pattern option. Example output:: cirrus-low-memory @ 0xfffffd00000a0000 pc:fffffc0000005cdc, 1, 256 pc:fffffc0000005ce8, 1, 256 pc:fffffc0000005cec, 1, 256 - * arg=pattern + * pattern Instead break down the accesses based on the offset into the HW region. This can be useful for seeing the most used registers of a @@ -345,7 +360,7 @@ which will output an execution trace following this structure:: 0, 0xd34, 0xf9c8f000, "bl #0x10c8" 0, 0x10c8, 0xfff96c43, "ldr r3, [r0, #0x44]", load, 0x200000e4, RAM -- contrib/plugins/cache +- contrib/plugins/cache.c Cache modelling plugin that measures the performance of a given cache configuration when a given working set is run:: @@ -355,11 +370,8 @@ configuration when a given working set is run:: will report the following:: - Data accesses: 996479, Misses: 507 - Miss rate: 0.050879% - - Instruction accesses: 2641737, Misses: 18617 - Miss rate: 0.704726% + core #, data accesses, data misses, dmiss rate, insn accesses, insn misses, imiss rate + 0 996695 508 0.0510% 2642799 18617 0.7044% address, data misses, instruction 0x424f1e (_int_malloc), 109, movq %rax, 8(%rcx) @@ -377,29 +389,35 @@ will report the following:: The plugin has a number of arguments, all of them are optional: - * arg="limit=N" + * limit=N Print top N icache and dcache thrashing instructions along with their address, number of misses, and its disassembly. (default: 32) - * arg="icachesize=N" - * arg="iblksize=B" - * arg="iassoc=A" + * icachesize=N + * iblksize=B + * iassoc=A Instruction cache configuration arguments. They specify the cache size, block size, and associativity of the instruction cache, respectively. (default: N = 16384, B = 64, A = 8) - * arg="dcachesize=N" - * arg="dblksize=B" - * arg="dassoc=A" + * dcachesize=N + * dblksize=B + * dassoc=A Data cache configuration arguments. They specify the cache size, block size, and associativity of the data cache, respectively. (default: N = 16384, B = 64, A = 8) - * arg="evict=POLICY" + * evict=POLICY Sets the eviction policy to POLICY. Available policies are: :code:`lru`, :code:`fifo`, and :code:`rand`. The plugin will use the specified policy for both instruction and data caches. (default: POLICY = :code:`lru`) + + * cores=N + + Sets the number of cores for which we maintain separate icache and dcache. + (default: for linux-user, N = 1, for full system emulation: N = cores + available to guest) diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h index e6e815a..5f10172 100644 --- a/include/qemu/qemu-plugin.h +++ b/include/qemu/qemu-plugin.h @@ -577,4 +577,17 @@ int qemu_plugin_n_max_vcpus(void); */ void qemu_plugin_outs(const char *string); +/** + * qemu_plugin_bool_parse() - parses a boolean argument in the form of + * "<argname>=[on|yes|true|off|no|false]" + * + * @name: argument name, the part before the equals sign + * @val: argument value, what's after the equals sign + * @ret: output return value + * + * returns true if the combination @name=@val parses correctly to a boolean + * argument, and false otherwise + */ +bool qemu_plugin_bool_parse(const char *name, const char *val, bool *ret); + #endif /* QEMU_PLUGIN_API_H */ diff --git a/linux-user/main.c b/linux-user/main.c index 37ed50d..a609456 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -463,7 +463,7 @@ static const struct qemu_argument arg_table[] = { "", "[[enable=]<pattern>][,events=<file>][,file=<file>]"}, #ifdef CONFIG_PLUGIN {"plugin", "QEMU_PLUGIN", true, handle_arg_plugin, - "", "[file=]<file>[,arg=<string>]"}, + "", "[file=]<file>[,<argname>=<argvalue>]"}, #endif {"version", "QEMU_VERSION", false, handle_arg_version, "", "display version information and exit"}, diff --git a/plugins/api.c b/plugins/api.c index 2d521e6..acff9ce 100644 --- a/plugins/api.c +++ b/plugins/api.c @@ -383,3 +383,8 @@ void qemu_plugin_outs(const char *string) { qemu_log_mask(CPU_LOG_PLUGIN, "%s", string); } + +bool qemu_plugin_bool_parse(const char *name, const char *value, bool *ret) +{ + return name && value && qapi_bool_parse(name, value, ret, NULL); +} diff --git a/plugins/loader.c b/plugins/loader.c index 05df403..a4ec281 100644 --- a/plugins/loader.c +++ b/plugins/loader.c @@ -94,6 +94,8 @@ static int plugin_add(void *opaque, const char *name, const char *value, { struct qemu_plugin_parse_arg *arg = opaque; struct qemu_plugin_desc *p; + bool is_on; + char *fullarg; if (strcmp(name, "file") == 0) { if (strcmp(value, "") == 0) { @@ -107,18 +109,32 @@ static int plugin_add(void *opaque, const char *name, const char *value, QTAILQ_INSERT_TAIL(arg->head, p, entry); } arg->curr = p; - } else if (strcmp(name, "arg") == 0) { + } else { if (arg->curr == NULL) { error_setg(errp, "missing earlier '-plugin file=' option"); return 1; } + + if (g_strcmp0(name, "arg") == 0 && + !qapi_bool_parse(name, value, &is_on, NULL)) { + if (strchr(value, '=') == NULL) { + /* Will treat arg="argname" as "argname=on" */ + fullarg = g_strdup_printf("%s=%s", value, "on"); + } else { + fullarg = g_strdup_printf("%s", value); + } + warn_report("using 'arg=%s' is deprecated", value); + error_printf("Please use '%s' directly\n", fullarg); + } else { + fullarg = g_strdup_printf("%s=%s", name, value); + } + 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); + p->argv[p->argc - 1] = fullarg; } + return 0; } diff --git a/plugins/meson.build b/plugins/meson.build index e777230..bfd5c98 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -1,9 +1,11 @@ -if 'CONFIG_HAS_LD_DYNAMIC_LIST' in config_host - plugin_ldflags = ['-Wl,--dynamic-list=' + (meson.build_root() / 'qemu-plugins-ld.symbols')] -elif 'CONFIG_HAS_LD_EXPORTED_SYMBOLS_LIST' in config_host - plugin_ldflags = ['-Wl,-exported_symbols_list,' + (meson.build_root() / 'qemu-plugins-ld64.symbols')] -else - plugin_ldflags = [] +plugin_ldflags = [] +# Modules need more symbols than just those in plugins/qemu-plugins.symbols +if not enable_modules + if 'CONFIG_HAS_LD_DYNAMIC_LIST' in config_host + plugin_ldflags = ['-Wl,--dynamic-list=' + (meson.build_root() / 'qemu-plugins-ld.symbols')] + elif 'CONFIG_HAS_LD_EXPORTED_SYMBOLS_LIST' in config_host + plugin_ldflags = ['-Wl,-exported_symbols_list,' + (meson.build_root() / 'qemu-plugins-ld64.symbols')] + endif endif specific_ss.add(when: 'CONFIG_PLUGIN', if_true: [files( diff --git a/plugins/qemu-plugins.symbols b/plugins/qemu-plugins.symbols index 40b4ff3..67b309e 100644 --- a/plugins/qemu-plugins.symbols +++ b/plugins/qemu-plugins.symbols @@ -1,37 +1,38 @@ { - qemu_plugin_uninstall; - qemu_plugin_reset; - qemu_plugin_register_vcpu_init_cb; + qemu_plugin_bool_parse; + qemu_plugin_get_hwaddr; + qemu_plugin_hwaddr_is_io; + qemu_plugin_insn_data; + qemu_plugin_insn_disas; + qemu_plugin_insn_haddr; + qemu_plugin_insn_size; + qemu_plugin_insn_vaddr; + qemu_plugin_mem_is_big_endian; + qemu_plugin_mem_is_sign_extended; + qemu_plugin_mem_is_store; + qemu_plugin_mem_size_shift; + qemu_plugin_n_max_vcpus; + qemu_plugin_n_vcpus; + qemu_plugin_outs; + qemu_plugin_register_atexit_cb; + qemu_plugin_register_flush_cb; qemu_plugin_register_vcpu_exit_cb; qemu_plugin_register_vcpu_idle_cb; - qemu_plugin_register_vcpu_resume_cb; + qemu_plugin_register_vcpu_init_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_inline; - 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_resume_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_register_vcpu_tb_exec_cb; + qemu_plugin_register_vcpu_tb_exec_inline; + qemu_plugin_register_vcpu_tb_trans_cb; + qemu_plugin_reset; qemu_plugin_tb_get_insn; + qemu_plugin_tb_n_insns; qemu_plugin_tb_vaddr; - qemu_plugin_insn_data; - 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; - qemu_plugin_mem_is_store; - qemu_plugin_get_hwaddr; - qemu_plugin_hwaddr_is_io; + qemu_plugin_uninstall; qemu_plugin_vcpu_for_each; - qemu_plugin_n_vcpus; - qemu_plugin_n_max_vcpus; - qemu_plugin_outs; }; diff --git a/qemu-options.hx b/qemu-options.hx index 83aa59a..4a9ee72 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4532,19 +4532,18 @@ SRST ERST DEF("plugin", HAS_ARG, QEMU_OPTION_plugin, - "-plugin [file=]<file>[,arg=<string>]\n" + "-plugin [file=]<file>[,<argname>=<argvalue>]\n" " load a plugin\n", QEMU_ARCH_ALL) SRST -``-plugin file=file[,arg=string]`` +``-plugin file=file[,argname=argvalue]`` Load a plugin. ``file=file`` Load the given plugin from a shared library file. - ``arg=string`` - Argument string passed to the plugin. (Can be given multiple - times.) + ``argname=argvalue`` + Argument passed to the plugin. (Can be given multiple times.) ERST HXCOMM Internal use diff --git a/tests/plugin/bb.c b/tests/plugin/bb.c index de09bdd..7d470a1 100644 --- a/tests/plugin/bb.c +++ b/tests/plugin/bb.c @@ -104,10 +104,17 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, for (i = 0; i < argc; i++) { char *opt = argv[i]; - if (g_strcmp0(opt, "inline") == 0) { - do_inline = true; - } else if (g_strcmp0(opt, "idle") == 0) { - idle_report = true; + g_autofree char **tokens = g_strsplit(opt, "=", 2); + if (g_strcmp0(tokens[0], "inline") == 0) { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) { + fprintf(stderr, "boolean argument parsing failed: %s\n", opt); + return -1; + } + } else if (g_strcmp0(tokens[0], "idle") == 0) { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &idle_report)) { + fprintf(stderr, "boolean argument parsing failed: %s\n", opt); + return -1; + } } else { fprintf(stderr, "option parsing failed: %s\n", opt); return -1; diff --git a/tests/plugin/insn.c b/tests/plugin/insn.c index c253980..0f6a193 100644 --- a/tests/plugin/insn.c +++ b/tests/plugin/insn.c @@ -62,8 +62,18 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, int argc, char **argv) { - if (argc && !strcmp(argv[0], "inline")) { - do_inline = true; + for (int i = 0; i < argc; i++) { + char *opt = argv[i]; + g_autofree char **tokens = g_strsplit(opt, "=", 2); + if (g_strcmp0(tokens[0], "inline") == 0) { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) { + fprintf(stderr, "boolean argument parsing failed: %s\n", opt); + return -1; + } + } else { + fprintf(stderr, "option parsing failed: %s\n", opt); + return -1; + } } qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); diff --git a/tests/plugin/mem.c b/tests/plugin/mem.c index afd1d27..4570f7d 100644 --- a/tests/plugin/mem.c +++ b/tests/plugin/mem.c @@ -80,29 +80,40 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, 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")) { + for (int i = 0; i < argc; i++) { + char *opt = argv[i]; + g_autofree char **tokens = g_strsplit(opt, "=", 2); + + if (g_strcmp0(tokens[0], "haddr") == 0) { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_haddr)) { + fprintf(stderr, "boolean argument parsing failed: %s\n", opt); + return -1; + } + } else if (g_strcmp0(tokens[0], "track") == 0) { + if (g_strcmp0(tokens[1], "r") == 0) { rw = QEMU_PLUGIN_MEM_R; - } else if (!strcmp(str, "w")) { + } else if (g_strcmp0(tokens[1], "w") == 0) { rw = QEMU_PLUGIN_MEM_W; + } else if (g_strcmp0(tokens[1], "rw") == 0) { + rw = QEMU_PLUGIN_MEM_RW; + } else { + fprintf(stderr, "invaild value for argument track: %s\n", opt); + return -1; + } + } else if (g_strcmp0(tokens[0], "inline") == 0) { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) { + fprintf(stderr, "boolean argument parsing failed: %s\n", opt); + return -1; + } + } else if (g_strcmp0(tokens[0], "callback") == 0) { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_callback)) { + fprintf(stderr, "boolean argument parsing failed: %s\n", opt); + return -1; } - } - if (!strcmp(argv[0], "inline")) { - do_inline = true; - do_callback = false; - } else if (!strcmp(argv[0], "both")) { - do_inline = true; - do_callback = true; } else { - do_callback = true; + fprintf(stderr, "option parsing failed: %s\n", opt); + return -1; } } diff --git a/tests/plugin/syscall.c b/tests/plugin/syscall.c index 6dd7109..484b48d 100644 --- a/tests/plugin/syscall.c +++ b/tests/plugin/syscall.c @@ -119,17 +119,26 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, int argc, char **argv) { - if (argc == 0) { - statistics = g_hash_table_new_full(NULL, g_direct_equal, NULL, g_free); - } else { - for (int i = 0; i < argc; i++) { - if (g_strcmp0(argv[i], "print") != 0) { - fprintf(stderr, "unsupported argument: %s\n", argv[i]); - return -1; + bool do_print = false; + + for (int i = 0; i < argc; i++) { + char *opt = argv[i]; + g_autofree char **tokens = g_strsplit(opt, "=", 2); + + if (g_strcmp0(tokens[0], "print") == 0) { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_print)) { + fprintf(stderr, "boolean argument parsing failed: %s\n", opt); } + } else { + fprintf(stderr, "unsupported argument: %s\n", argv[i]); + return -1; } } + if (!do_print) { + statistics = g_hash_table_new_full(NULL, g_direct_equal, NULL, g_free); + } + qemu_plugin_register_vcpu_syscall_cb(id, vcpu_syscall); qemu_plugin_register_vcpu_syscall_ret_cb(id, vcpu_syscall_ret); qemu_plugin_register_atexit_cb(id, plugin_exit, NULL); diff --git a/tests/tcg/i386/Makefile.softmmu-target b/tests/tcg/i386/Makefile.softmmu-target index fa9b1b9..9b9038d 100644 --- a/tests/tcg/i386/Makefile.softmmu-target +++ b/tests/tcg/i386/Makefile.softmmu-target @@ -38,7 +38,7 @@ run-plugin-%-with-libinsn.so: $(call run-test, $@, \ $(QEMU) -monitor none -display none \ -chardev file$(COMMA)path=$@.out$(COMMA)id=output \ - -plugin ../../plugin/libinsn.so$(COMMA)arg=inline \ + -plugin ../../plugin/libinsn.so$(COMMA)inline=on \ -d plugin -D $*-with-libinsn.so.pout \ $(QEMU_OPTS) $*, \ "$* on $(TARGET_NAME)") diff --git a/tests/tcg/i386/Makefile.target b/tests/tcg/i386/Makefile.target index b0a2128..a053ca3 100644 --- a/tests/tcg/i386/Makefile.target +++ b/tests/tcg/i386/Makefile.target @@ -61,7 +61,7 @@ endif # non-inline runs will trigger the duplicate instruction heuristics in libinsn.so run-plugin-%-with-libinsn.so: $(call run-test, $@, $(QEMU) $(QEMU_OPTS) \ - -plugin ../../plugin/libinsn.so$(COMMA)arg=inline \ + -plugin ../../plugin/libinsn.so$(COMMA)inline=on \ -d plugin -D $*-with-libinsn.so.pout $*, \ "$* (inline) on $(TARGET_NAME)") diff --git a/tests/tcg/x86_64/Makefile.softmmu-target b/tests/tcg/x86_64/Makefile.softmmu-target index 9896319..2afa329 100644 --- a/tests/tcg/x86_64/Makefile.softmmu-target +++ b/tests/tcg/x86_64/Makefile.softmmu-target @@ -38,7 +38,7 @@ run-plugin-%-with-libinsn.so: $(call run-test, $@, \ $(QEMU) -monitor none -display none \ -chardev file$(COMMA)path=$@.out$(COMMA)id=output \ - -plugin ../../plugin/libinsn.so$(COMMA)arg=inline \ + -plugin ../../plugin/libinsn.so$(COMMA)inline=on \ -d plugin -D $*-with-libinsn.so.pout \ $(QEMU_OPTS) $*, \ "$* on $(TARGET_NAME)") |