aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.include9
-rw-r--r--tests/docker/dockerfiles/fedora.docker2
-rw-r--r--tests/docker/dockerfiles/ubuntu2004.docker65
-rwxr-xr-xtests/docker/test-tsan44
-rw-r--r--tests/plugin/Makefile1
-rw-r--r--tests/plugin/lockstep.c340
-rw-r--r--tests/qtest/Makefile.include7
-rw-r--r--tests/tcg/Makefile.target12
-rw-r--r--tests/tcg/aarch64/Makefile.target5
-rw-r--r--tests/tcg/arm/Makefile.target2
-rw-r--r--tests/tcg/i386/Makefile.target1
-rw-r--r--tests/tsan/blacklist.tsan10
-rw-r--r--tests/tsan/suppressions.tsan14
13 files changed, 499 insertions, 13 deletions
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 5607c7290d..3f4448a20b 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -55,7 +55,6 @@ SYSEMU_TARGET_LIST := $(subst -softmmu.mak,,$(notdir \
check-unit-y += tests/check-qdict$(EXESUF)
check-unit-y += tests/check-block-qdict$(EXESUF)
-check-unit-$(CONFIG_SOFTMMU) += tests/test-char$(EXESUF)
check-unit-y += tests/check-qnum$(EXESUF)
check-unit-y += tests/check-qstring$(EXESUF)
check-unit-y += tests/check-qlist$(EXESUF)
@@ -108,7 +107,6 @@ check-unit-y += tests/test-qht$(EXESUF)
check-unit-y += tests/test-qht-par$(EXESUF)
check-unit-y += tests/test-bitops$(EXESUF)
check-unit-y += tests/test-bitcnt$(EXESUF)
-check-unit-$(CONFIG_SOFTMMU) += tests/test-qdev-global-props$(EXESUF)
check-unit-y += tests/check-qom-interface$(EXESUF)
check-unit-y += tests/check-qom-proplist$(EXESUF)
check-unit-y += tests/test-qemu-opts$(EXESUF)
@@ -123,9 +121,16 @@ check-speed-$(CONFIG_BLOCK) += tests/benchmark-crypto-cipher$(EXESUF)
check-unit-$(CONFIG_BLOCK) += tests/test-crypto-secret$(EXESUF)
check-unit-$(call land,$(CONFIG_BLOCK),$(CONFIG_GNUTLS)) += tests/test-crypto-tlscredsx509$(EXESUF)
check-unit-$(call land,$(CONFIG_BLOCK),$(CONFIG_GNUTLS)) += tests/test-crypto-tlssession$(EXESUF)
+ifndef CONFIG_TSAN
+# Some tests: test-char, test-qdev-global-props, and test-qga,
+# are not runnable under TSan due to a known issue.
+# https://github.com/google/sanitizers/issues/1116
+check-unit-$(CONFIG_SOFTMMU) += tests/test-char$(EXESUF)
+check-unit-$(CONFIG_SOFTMMU) += tests/test-qdev-global-props$(EXESUF)
ifneq (,$(findstring qemu-ga,$(TOOLS)))
check-unit-$(call land,$(CONFIG_LINUX),$(CONFIG_VIRTIO_SERIAL)) += tests/test-qga$(EXESUF)
endif
+endif
check-unit-$(CONFIG_SOFTMMU) += tests/test-timed-average$(EXESUF)
check-unit-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_INOTIFY1)) += tests/test-util-filemonitor$(EXESUF)
check-unit-$(CONFIG_SOFTMMU) += tests/test-util-sockets$(EXESUF)
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index 92b6e11c8a..798ddd2c3e 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -1,4 +1,4 @@
-FROM fedora:30
+FROM fedora:32
# Please keep this list sorted alphabetically
ENV PACKAGES \
diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker
new file mode 100644
index 0000000000..6050ce7e8a
--- /dev/null
+++ b/tests/docker/dockerfiles/ubuntu2004.docker
@@ -0,0 +1,65 @@
+FROM ubuntu:20.04
+ENV PACKAGES flex bison \
+ ccache \
+ clang-10\
+ gcc \
+ gettext \
+ git \
+ glusterfs-common \
+ libaio-dev \
+ libattr1-dev \
+ libbrlapi-dev \
+ libbz2-dev \
+ libcacard-dev \
+ libcap-ng-dev \
+ libcurl4-gnutls-dev \
+ libdrm-dev \
+ libepoxy-dev \
+ libfdt-dev \
+ libgbm-dev \
+ libgtk-3-dev \
+ libibverbs-dev \
+ libiscsi-dev \
+ libjemalloc-dev \
+ libjpeg-turbo8-dev \
+ liblzo2-dev \
+ libncurses5-dev \
+ libncursesw5-dev \
+ libnfs-dev \
+ libnss3-dev \
+ libnuma-dev \
+ libpixman-1-dev \
+ librados-dev \
+ librbd-dev \
+ librdmacm-dev \
+ libsasl2-dev \
+ libsdl2-dev \
+ libseccomp-dev \
+ libsnappy-dev \
+ libspice-protocol-dev \
+ libspice-server-dev \
+ libssh-dev \
+ libusb-1.0-0-dev \
+ libusbredirhost-dev \
+ libvdeplug-dev \
+ libvte-2.91-dev \
+ libxen-dev \
+ libzstd-dev \
+ make \
+ python3-yaml \
+ python3-sphinx \
+ sparse \
+ texinfo \
+ xfslibs-dev\
+ vim
+RUN apt-get update && \
+ DEBIAN_FRONTEND=noninteractive apt-get -y install $PACKAGES
+RUN dpkg -l $PACKAGES | sort > /packages.txt
+ENV FEATURES clang tsan pyyaml sdl2
+
+# https://bugs.launchpad.net/qemu/+bug/1838763
+ENV QEMU_CONFIGURE_OPTS --disable-libssh
+
+# Apply patch https://reviews.llvm.org/D75820
+# This is required for TSan in clang-10 to compile with QEMU.
+RUN sed -i 's/^const/static const/g' /usr/lib/llvm-10/lib/clang/10.0.0/include/sanitizer/tsan_interface.h
diff --git a/tests/docker/test-tsan b/tests/docker/test-tsan
new file mode 100755
index 0000000000..eb40ac45b7
--- /dev/null
+++ b/tests/docker/test-tsan
@@ -0,0 +1,44 @@
+#!/bin/bash -e
+#
+# This test will use TSan as part of a build and a make check.
+#
+# Copyright (c) 2020 Linaro
+# Copyright (c) 2016 Red Hat Inc.
+#
+# Authors:
+# Robert Foley <robert.foley@linaro.org>
+# Originally based on test-quick from Fam Zheng <famz@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2
+# or (at your option) any later version. See the COPYING file in
+# the top-level directory.
+
+. common.rc
+
+setup_tsan()
+{
+ requires clang tsan
+ tsan_log_dir="/tmp/qemu-test/build/tsan"
+ mkdir -p $tsan_log_dir > /dev/null || true
+ EXTRA_CONFIGURE_OPTS="${EXTRA_CONFIGURE_OPTS} --enable-tsan \
+ --cc=clang-10 --cxx=clang++-10 \
+ --disable-werror --extra-cflags=-O0"
+ # detect deadlocks is false currently simply because
+ # TSan crashes immediately with deadlock detector enabled.
+ # We have maxed out the history size to get the best chance of finding
+ # warnings during testing.
+ # Note, to get TSan to fail on warning, use exitcode=66 below.
+ tsan_opts="suppressions=/tmp/qemu-test/src/tests/tsan/suppressions.tsan\
+ detect_deadlocks=false history_size=7\
+ halt_on_error=0 exitcode=0 verbose=5\
+ log_path=$tsan_log_dir/tsan_warning"
+ export TSAN_OPTIONS="$tsan_opts"
+}
+
+cd "$BUILD_DIR"
+
+TARGET_LIST=${TARGET_LIST:-$DEF_TARGET_LIST} \
+setup_tsan
+build_qemu
+check_qemu
+install_qemu
diff --git a/tests/plugin/Makefile b/tests/plugin/Makefile
index 75467b6db8..b3250e2504 100644
--- a/tests/plugin/Makefile
+++ b/tests/plugin/Makefile
@@ -13,6 +13,7 @@ NAMES += mem
NAMES += hotblocks
NAMES += howvec
NAMES += hotpages
+NAMES += lockstep
SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES)))
diff --git a/tests/plugin/lockstep.c b/tests/plugin/lockstep.c
new file mode 100644
index 0000000000..a696673dff
--- /dev/null
+++ b/tests/plugin/lockstep.c
@@ -0,0 +1,340 @@
+/*
+ * Lockstep Execution Plugin
+ *
+ * Allows you to execute two QEMU instances in lockstep and report
+ * when their execution diverges. This is mainly useful for developers
+ * who want to see where a change to TCG code generation has
+ * introduced a subtle and hard to find bug.
+ *
+ * Caveats:
+ * - single-threaded linux-user apps only with non-deterministic syscalls
+ * - no MTTCG enabled system emulation (icount may help)
+ *
+ * While icount makes things more deterministic it doesn't mean a
+ * particular run may execute the exact same sequence of blocks. An
+ * asynchronous event (for example X11 graphics update) may cause a
+ * block to end early and a new partial block to start. This means
+ * serial only test cases are a better bet. -d nochain may also help.
+ *
+ * This code is not thread safe!
+ *
+ * Copyright (c) 2020 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <glib.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <qemu-plugin.h>
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+
+/* saved so we can uninstall later */
+static qemu_plugin_id_t our_id;
+
+static unsigned long bb_count;
+static unsigned long insn_count;
+
+/* Information about a translated block */
+typedef struct {
+ uint64_t pc;
+ uint64_t insns;
+} BlockInfo;
+
+/* Information about an execution state in the log */
+typedef struct {
+ BlockInfo *block;
+ unsigned long insn_count;
+ unsigned long block_count;
+} ExecInfo;
+
+/* The execution state we compare */
+typedef struct {
+ uint64_t pc;
+ unsigned long insn_count;
+} ExecState;
+
+typedef struct {
+ GSList *log_pos;
+ int distance;
+} DivergeState;
+
+/* list of translated block info */
+static GSList *blocks;
+
+/* execution log and points of divergence */
+static GSList *log, *divergence_log;
+
+static int socket_fd;
+static char *path_to_unlink;
+
+static bool verbose;
+
+static void plugin_cleanup(qemu_plugin_id_t id)
+{
+ /* Free our block data */
+ g_slist_free_full(blocks, &g_free);
+ g_slist_free_full(log, &g_free);
+ g_slist_free(divergence_log);
+
+ close(socket_fd);
+ if (path_to_unlink) {
+ unlink(path_to_unlink);
+ }
+}
+
+static void plugin_exit(qemu_plugin_id_t id, void *p)
+{
+ g_autoptr(GString) out = g_string_new("No divergence :-)\n");
+ g_string_append_printf(out, "Executed %ld/%d blocks\n",
+ bb_count, g_slist_length(log));
+ g_string_append_printf(out, "Executed ~%ld instructions\n", insn_count);
+ qemu_plugin_outs(out->str);
+
+ plugin_cleanup(id);
+}
+
+static void report_divergance(ExecState *us, ExecState *them)
+{
+ DivergeState divrec = { log, 0 };
+ g_autoptr(GString) out = g_string_new("");
+ bool diverged = false;
+
+ /*
+ * If we have diverged before did we get back on track or are we
+ * totally loosing it?
+ */
+ if (divergence_log) {
+ DivergeState *last = (DivergeState *) divergence_log->data;
+ GSList *entry;
+
+ for (entry = log; g_slist_next(entry); entry = g_slist_next(entry)) {
+ if (entry == last->log_pos) {
+ break;
+ }
+ divrec.distance++;
+ }
+
+ /*
+ * If the last two records are so close it is likely we will
+ * not recover synchronisation with the other end.
+ */
+ if (divrec.distance == 1 && last->distance == 1) {
+ diverged = true;
+ }
+ }
+ divergence_log = g_slist_prepend(divergence_log,
+ g_memdup(&divrec, sizeof(divrec)));
+
+ /* Output short log entry of going out of sync... */
+ if (verbose || divrec.distance == 1 || diverged) {
+ g_string_printf(out, "@ %#016lx vs %#016lx (%d/%d since last)\n",
+ us->pc, them->pc, g_slist_length(divergence_log),
+ divrec.distance);
+ qemu_plugin_outs(out->str);
+ }
+
+ if (diverged) {
+ int i;
+ GSList *entry;
+
+ g_string_printf(out, "Δ insn_count @ %#016lx (%ld) vs %#016lx (%ld)\n",
+ us->pc, us->insn_count, them->pc, them->insn_count);
+
+ for (entry = log, i = 0;
+ g_slist_next(entry) && i < 5;
+ entry = g_slist_next(entry), i++) {
+ ExecInfo *prev = (ExecInfo *) entry->data;
+ g_string_append_printf(out,
+ " previously @ %#016lx/%ld (%ld insns)\n",
+ prev->block->pc, prev->block->insns,
+ prev->insn_count);
+ }
+ qemu_plugin_outs(out->str);
+ qemu_plugin_outs("too much divergence... giving up.");
+ qemu_plugin_uninstall(our_id, plugin_cleanup);
+ }
+}
+
+static void vcpu_tb_exec(unsigned int cpu_index, void *udata)
+{
+ BlockInfo *bi = (BlockInfo *) udata;
+ ExecState us, them;
+ ssize_t bytes;
+ ExecInfo *exec;
+
+ us.pc = bi->pc;
+ us.insn_count = insn_count;
+
+ /*
+ * Write our current position to the other end. If we fail the
+ * other end has probably died and we should shut down gracefully.
+ */
+ bytes = write(socket_fd, &us, sizeof(ExecState));
+ if (bytes < sizeof(ExecState)) {
+ qemu_plugin_outs(bytes < 0 ?
+ "problem writing to socket" :
+ "wrote less than expected to socket");
+ qemu_plugin_uninstall(our_id, plugin_cleanup);
+ return;
+ }
+
+ /*
+ * Now read where our peer has reached. Again a failure probably
+ * indicates the other end died and we should close down cleanly.
+ */
+ bytes = read(socket_fd, &them, sizeof(ExecState));
+ if (bytes < sizeof(ExecState)) {
+ qemu_plugin_outs(bytes < 0 ?
+ "problem reading from socket" :
+ "read less than expected");
+ qemu_plugin_uninstall(our_id, plugin_cleanup);
+ return;
+ }
+
+ /*
+ * Compare and report if we have diverged.
+ */
+ if (us.pc != them.pc) {
+ report_divergance(&us, &them);
+ }
+
+ /*
+ * Assume this block will execute fully and record it
+ * in the execution log.
+ */
+ insn_count += bi->insns;
+ bb_count++;
+ exec = g_new0(ExecInfo, 1);
+ exec->block = bi;
+ exec->insn_count = insn_count;
+ exec->block_count = bb_count;
+ log = g_slist_prepend(log, exec);
+}
+
+static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
+{
+ BlockInfo *bi = g_new0(BlockInfo, 1);
+ bi->pc = qemu_plugin_tb_vaddr(tb);
+ bi->insns = qemu_plugin_tb_n_insns(tb);
+
+ /* save a reference so we can free later */
+ blocks = g_slist_prepend(blocks, bi);
+ qemu_plugin_register_vcpu_tb_exec_cb(tb, vcpu_tb_exec,
+ QEMU_PLUGIN_CB_NO_REGS, (void *)bi);
+}
+
+
+/*
+ * Instead of encoding master/slave status into what is essentially
+ * two peers we shall just take the simple approach of checking for
+ * the existence of the pipe and assuming if it's not there we are the
+ * first process.
+ */
+static bool setup_socket(const char *path)
+{
+ struct sockaddr_un sockaddr;
+ int fd;
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) {
+ perror("create socket");
+ return false;
+ }
+
+ sockaddr.sun_family = AF_UNIX;
+ g_strlcpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1);
+ if (bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) {
+ perror("bind socket");
+ close(fd);
+ return false;
+ }
+
+ /* remember to clean-up */
+ path_to_unlink = g_strdup(path);
+
+ if (listen(fd, 1) < 0) {
+ perror("listen socket");
+ close(fd);
+ return false;
+ }
+
+ socket_fd = accept(fd, NULL, NULL);
+ if (socket_fd < 0 && errno != EINTR) {
+ perror("accept socket");
+ return false;
+ }
+
+ qemu_plugin_outs("setup_socket::ready\n");
+
+ return true;
+}
+
+static bool connect_socket(const char *path)
+{
+ int fd;
+ struct sockaddr_un sockaddr;
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) {
+ perror("create socket");
+ return false;
+ }
+
+ sockaddr.sun_family = AF_UNIX;
+ g_strlcpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1);
+
+ if (connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) {
+ perror("failed to connect");
+ return false;
+ }
+
+ qemu_plugin_outs("connect_socket::ready\n");
+
+ socket_fd = fd;
+ return true;
+}
+
+static bool setup_unix_socket(const char *path)
+{
+ if (g_file_test(path, G_FILE_TEST_EXISTS)) {
+ return connect_socket(path);
+ } else {
+ return setup_socket(path);
+ }
+}
+
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
+ const qemu_info_t *info,
+ int argc, char **argv)
+{
+ int i;
+
+ if (!argc || !argv[0]) {
+ qemu_plugin_outs("Need a socket path to talk to other instance.");
+ return -1;
+ }
+
+ 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.");
+ return -1;
+ }
+ }
+
+ our_id = id;
+
+ 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/qtest/Makefile.include b/tests/qtest/Makefile.include
index 5023fa413d..98af2c2d93 100644
--- a/tests/qtest/Makefile.include
+++ b/tests/qtest/Makefile.include
@@ -314,12 +314,15 @@ tests/qtest/tpm-tis-device-test$(EXESUF): tests/qtest/tpm-tis-device-test.o test
# QTest rules
TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))
+QTEST_TARGETS =
+# The qtests are not runnable (yet) under TSan due to a known issue.
+# https://github.com/google/sanitizers/issues/1116
+ifndef CONFIG_TSAN
ifeq ($(CONFIG_POSIX),y)
QTEST_TARGETS = $(TARGETS)
check-qtest-y=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y:%=tests/qtest/%$(EXESUF)))
check-qtest-y += $(check-qtest-generic-y:%=tests/qtest/%$(EXESUF))
-else
-QTEST_TARGETS =
+endif
endif
qtest-obj-y = tests/qtest/libqtest.o $(test-util-obj-y)
diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target
index b3cff3cad1..4b2b696fce 100644
--- a/tests/tcg/Makefile.target
+++ b/tests/tcg/Makefile.target
@@ -126,9 +126,11 @@ RUN_TESTS=$(patsubst %,run-%, $(TESTS))
# If plugins exist also include those in the tests
ifeq ($(CONFIG_PLUGIN),y)
-PLUGIN_DIR=../../plugin
-VPATH+=$(PLUGIN_DIR)
-PLUGINS=$(notdir $(wildcard $(PLUGIN_DIR)/*.so))
+PLUGIN_SRC=$(SRC_PATH)/tests/plugin
+PLUGIN_LIB=../../plugin
+VPATH+=$(PLUGIN_LIB)
+PLUGINS=$(filter-out liblockstep.so,\
+ $(patsubst %.c, lib%.so, $(notdir $(wildcard $(PLUGIN_SRC)/*.c))))
# 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
@@ -152,7 +154,7 @@ run-%: %
run-plugin-%:
$(call run-test, $@, $(QEMU) $(QEMU_OPTS) \
- -plugin $(PLUGIN_DIR)/$(call extract-plugin,$@) \
+ -plugin $(PLUGIN_LIB)/$(call extract-plugin,$@) \
-d plugin -D $*.pout \
$(call strip-plugin,$<), \
"$* on $(TARGET_NAME)")
@@ -168,7 +170,7 @@ run-plugin-%:
$(call run-test, $@, \
$(QEMU) -monitor none -display none \
-chardev file$(COMMA)path=$@.out$(COMMA)id=output \
- -plugin $(PLUGIN_DIR)/$(call extract-plugin,$@) \
+ -plugin $(PLUGIN_LIB)/$(call extract-plugin,$@) \
-d plugin -D $*.pout \
$(QEMU_OPTS) $(call strip-plugin,$<), \
"$* on $(TARGET_NAME)")
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
index 312f36cde5..b617f2ac7e 100644
--- a/tests/tcg/aarch64/Makefile.target
+++ b/tests/tcg/aarch64/Makefile.target
@@ -20,8 +20,9 @@ run-fcvt: fcvt
# Pauth Tests
ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_ARMV8_3),)
AARCH64_TESTS += pauth-1 pauth-2 pauth-4
-run-pauth-%: QEMU_OPTS += -cpu max
pauth-%: CFLAGS += -march=armv8.3-a
+run-pauth-%: QEMU_OPTS += -cpu max
+run-plugin-pauth-%: QEMU_OPTS += -cpu max
endif
# Semihosting smoke test for linux-user
@@ -31,7 +32,7 @@ run-semihosting: semihosting
run-plugin-semihosting-with-%:
$(call run-test, $@, $(QEMU) $(QEMU_OPTS) \
- -plugin $(PLUGIN_DIR)/$(call extract-plugin,$@) \
+ -plugin $(PLUGIN_LIB)/$(call extract-plugin,$@) \
$(call strip-plugin,$<) 2> $<.err, \
"$< on $(TARGET_NAME) with $*")
diff --git a/tests/tcg/arm/Makefile.target b/tests/tcg/arm/Makefile.target
index 3da09a38be..ec95156562 100644
--- a/tests/tcg/arm/Makefile.target
+++ b/tests/tcg/arm/Makefile.target
@@ -45,7 +45,7 @@ run-semihosting-arm: semihosting-arm
run-plugin-semihosting-with-%:
$(call run-test, $@, $(QEMU) $(QEMU_OPTS) \
- -plugin $(PLUGIN_DIR)/$(call extract-plugin,$@) \
+ -plugin $(PLUGIN_LIB)/$(call extract-plugin,$@) \
$(call strip-plugin,$<) 2> $<.err, \
"$< on $(TARGET_NAME) with $*")
diff --git a/tests/tcg/i386/Makefile.target b/tests/tcg/i386/Makefile.target
index 53efec0668..1a6463a7dc 100644
--- a/tests/tcg/i386/Makefile.target
+++ b/tests/tcg/i386/Makefile.target
@@ -12,6 +12,7 @@ X86_64_TESTS:=$(filter test-i386-ssse3, $(ALL_X86_TESTS))
test-i386-pcmpistri: CFLAGS += -msse4.2
run-test-i386-pcmpistri: QEMU_OPTS += -cpu max
+run-plugin-test-i386-pcmpistri-%: QEMU_OPTS += -cpu max
#
# hello-i386 is a barebones app
diff --git a/tests/tsan/blacklist.tsan b/tests/tsan/blacklist.tsan
new file mode 100644
index 0000000000..75e444f5dc
--- /dev/null
+++ b/tests/tsan/blacklist.tsan
@@ -0,0 +1,10 @@
+# This is an example blacklist.
+# To enable use of the blacklist add this to configure:
+# "--extra-cflags=-fsanitize-blacklist=<src path>/tests/tsan/blacklist.tsan"
+# The eventual goal would be to fix these warnings.
+
+# TSan is not happy about setting/getting of dirty bits,
+# for example, cpu_physical_memory_set_dirty_range,
+# and cpu_physical_memory_get_dirty.
+src:bitops.c
+src:bitmap.c
diff --git a/tests/tsan/suppressions.tsan b/tests/tsan/suppressions.tsan
new file mode 100644
index 0000000000..73414b9ebd
--- /dev/null
+++ b/tests/tsan/suppressions.tsan
@@ -0,0 +1,14 @@
+# This is the set of runtime suppressions of TSan warnings.
+# The goal would be to have here only items we do not
+# plan to fix, and to explain why for each item.
+
+# TSan reports a double lock on RECURSIVE mutexes.
+# Since the recursive lock is intentional, we choose to ignore it.
+mutex:aio_context_acquire
+mutex:pthread_mutex_lock
+
+# TSan reports a race betwen pthread_mutex_init() and
+# pthread_mutex_lock(). Since this is outside of QEMU,
+# we choose to ignore it.
+race:pthread_mutex_init
+race:pthread_mutex_lock