mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/stsquad/tags/pull-tcg-plugins-281019-4' into staging
TCG Plugins initial implementation - use --enable-plugins @ configure - low impact introspection (-plugin empty.so to measure overhead) - plugins cannot alter guest state - example plugins included in source tree (tests/plugins) - -d plugin to enable plugin output in logs - check-tcg runs extra tests when plugins enabled - documentation in docs/devel/plugins.rst # gpg: Signature made Mon 28 Oct 2019 15:13:23 GMT # 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-tcg-plugins-281019-4: (57 commits) travis.yml: enable linux-gcc-debug-tcg cache MAINTAINERS: add me for the TCG plugins code scripts/checkpatch.pl: don't complain about (foo, /* empty */) .travis.yml: add --enable-plugins tests include/exec: wrap cpu_ldst.h in CONFIG_TCG accel/stubs: reduce headers from tcg-stub tests/plugin: add hotpages to analyse memory access patterns tests/plugin: add instruction execution breakdown tests/plugin: add a hotblocks plugin tests/tcg: enable plugin testing tests/tcg: drop test-i386-fprem from TESTS when not SLOW tests/tcg: move "virtual" tests to EXTRA_TESTS tests/tcg: set QEMU_OPTS for all cris runs tests/tcg/Makefile.target: fix path to config-host.mak tests/plugin: add sample plugins linux-user: support -plugin option vl: support -plugin option plugin: add qemu_plugin_outs helper plugin: add qemu_plugin_insn_disas helper plugin: expand the plugin_init function to include an info block ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+18
-3
@@ -135,7 +135,7 @@ matrix:
|
||||
# TCG debug can be run just on its own and is mostly agnostic to user/softmmu distinctions
|
||||
- env:
|
||||
- CONFIG="--enable-debug-tcg --disable-system"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
|
||||
- env:
|
||||
@@ -336,14 +336,29 @@ matrix:
|
||||
- env:
|
||||
- CONFIG="--disable-system --enable-debug-tcg"
|
||||
- TEST_CMD="make -j3 check-tcg V=1"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
|
||||
# Run check-tcg against linux-user (with plugins)
|
||||
# we skip sparc64-linux-user until it has been fixed somewhat
|
||||
- env:
|
||||
- CONFIG="--disable-system --enable-plugins --enable-debug-tcg --target-list-exclude=sparc64-linux-user"
|
||||
- TEST_CMD="make -j3 check-tcg V=1"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
|
||||
# Run check-tcg against softmmu targets
|
||||
- env:
|
||||
- CONFIG="--enable-debug-tcg --target-list=xtensa-softmmu,arm-softmmu,aarch64-softmmu,alpha-softmmu"
|
||||
- TEST_CMD="make -j3 check-tcg V=1"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
|
||||
# Run check-tcg against softmmu targets (with plugins)
|
||||
- env:
|
||||
- CONFIG="--enable-plugins --enable-debug-tcg --target-list=xtensa-softmmu,arm-softmmu,aarch64-softmmu,alpha-softmmu"
|
||||
- TEST_CMD="make -j3 check-tcg V=1"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
|
||||
# Release builds
|
||||
|
||||
@@ -2360,6 +2360,12 @@ M: Richard Henderson <rth@twiddle.net>
|
||||
S: Maintained
|
||||
F: tcg/
|
||||
|
||||
TCG Plugins
|
||||
M: Alex Bennée <alex.bennee@linaro.org>
|
||||
S: Maintained
|
||||
F: plugins/
|
||||
F: tests/plugin
|
||||
|
||||
AArch64 TCG target
|
||||
M: Claudio Fontana <claudio.fontana@huawei.com>
|
||||
M: Claudio Fontana <claudio.fontana@gmail.com>
|
||||
|
||||
@@ -74,6 +74,12 @@ CONFIG_ALL=y
|
||||
config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION
|
||||
@echo $@ is out-of-date, running configure
|
||||
@./config.status
|
||||
|
||||
# Force configure to re-run if the API symbols are updated
|
||||
ifeq ($(CONFIG_PLUGIN),y)
|
||||
config-host.mak: $(SRC_PATH)/plugins/qemu-plugins.symbols
|
||||
endif
|
||||
|
||||
else
|
||||
config-host.mak:
|
||||
ifneq ($(filter-out $(UNCHECKED_GOALS),$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail))
|
||||
@@ -737,6 +743,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
|
||||
@@ -853,7 +860,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),)
|
||||
@@ -915,6 +926,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 \
|
||||
|
||||
@@ -119,6 +119,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
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "exec/exec-all.h"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
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
|
||||
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)
|
||||
{
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, 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)
|
||||
{
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info);
|
||||
}
|
||||
+58
-36
@@ -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
|
||||
@@ -59,26 +60,6 @@
|
||||
# define ABI_TYPE uint32_t
|
||||
#endif
|
||||
|
||||
#define ATOMIC_TRACE_RMW do { \
|
||||
uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false); \
|
||||
\
|
||||
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 { \
|
||||
uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false); \
|
||||
\
|
||||
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); \
|
||||
\
|
||||
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 +79,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 +99,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 +114,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 +130,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 +147,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 +183,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 +195,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 +233,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 +254,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 +270,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 +289,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 +307,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 +341,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 +353,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 +381,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
|
||||
|
||||
@@ -238,8 +238,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);
|
||||
@@ -253,7 +251,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);
|
||||
@@ -271,9 +268,10 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
assert_no_pages_locked();
|
||||
qemu_plugin_disable_mem_helpers(cpu);
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -704,6 +702,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();
|
||||
}
|
||||
|
||||
|
||||
+59
-1
@@ -34,6 +34,9 @@
|
||||
#include "qemu/atomic.h"
|
||||
#include "qemu/atomic128.h"
|
||||
#include "translate-all.h"
|
||||
#ifdef CONFIG_PLUGIN
|
||||
#include "qemu/plugin-memory.h"
|
||||
#endif
|
||||
|
||||
/* DEBUG defines, enable DEBUG_TLB_LOG to log to the CPU_LOG_MMU target */
|
||||
/* #define DEBUG_TLB */
|
||||
@@ -1051,7 +1054,8 @@ static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index,
|
||||
* NOTE: This function will trigger an exception if the page is
|
||||
* not executable.
|
||||
*/
|
||||
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);
|
||||
@@ -1077,13 +1081,24 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr)
|
||||
|
||||
if (unlikely(entry->addr_code & TLB_MMIO)) {
|
||||
/* The 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);
|
||||
}
|
||||
|
||||
static void notdirty_write(CPUState *cpu, vaddr mem_vaddr, unsigned size,
|
||||
CPUIOTLBEntry *iotlbentry, uintptr_t retaddr)
|
||||
{
|
||||
@@ -1235,6 +1250,45 @@ 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.
|
||||
*
|
||||
* This should never fail as the memory access being instrumented
|
||||
* should have just filled the TLB.
|
||||
*/
|
||||
|
||||
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);
|
||||
uintptr_t index = tlb_index(env, mmu_idx, addr);
|
||||
target_ulong tlb_addr = is_store ? tlb_addr_write(tlbe) : tlbe->addr_read;
|
||||
|
||||
if (likely(tlb_hit(tlb_addr, addr))) {
|
||||
/* We must have an iotlb entry for MMIO */
|
||||
if (tlb_addr & TLB_MMIO) {
|
||||
CPUIOTLBEntry *iotlbentry;
|
||||
iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index];
|
||||
data->is_io = true;
|
||||
data->v.io.section = iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs);
|
||||
data->v.io.offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr;
|
||||
} else {
|
||||
data->is_io = false;
|
||||
data->v.ram.hostaddr = addr + tlbe->addend;
|
||||
}
|
||||
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,
|
||||
@@ -1811,6 +1865,9 @@ void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
#define ATOMIC_MMU_DECLS
|
||||
#define ATOMIC_MMU_LOOKUP atomic_mmu_lookup(env, addr, oi, retaddr)
|
||||
#define ATOMIC_MMU_CLEANUP
|
||||
#define ATOMIC_MMU_IDX get_mmuidx(oi)
|
||||
|
||||
#include "atomic_common.inc.c"
|
||||
|
||||
#define DATA_SIZE 1
|
||||
#include "atomic_template.h"
|
||||
@@ -1853,6 +1910,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. */
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -1214,6 +1214,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.
|
||||
@@ -1221,6 +1223,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();
|
||||
@@ -1245,14 +1248,22 @@ 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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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))) {
|
||||
@@ -99,6 +107,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) {
|
||||
@@ -111,6 +127,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;
|
||||
|
||||
@@ -751,10 +751,13 @@ 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 MMU_USER_IDX
|
||||
|
||||
#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"
|
||||
|
||||
|
||||
+18
-6
@@ -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);
|
||||
|
||||
@@ -332,6 +334,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 */
|
||||
@@ -402,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;
|
||||
@@ -420,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);
|
||||
|
||||
@@ -430,6 +436,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 */
|
||||
@@ -477,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;
|
||||
@@ -495,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);
|
||||
|
||||
@@ -505,6 +515,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 */
|
||||
@@ -552,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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -501,6 +502,7 @@ libxml2=""
|
||||
debug_mutex="no"
|
||||
libpmem=""
|
||||
default_devices="yes"
|
||||
plugins="no"
|
||||
|
||||
supported_cpu="no"
|
||||
supported_os="no"
|
||||
@@ -1532,6 +1534,10 @@ for opt do
|
||||
;;
|
||||
--disable-xkbcommon) xkbcommon=no
|
||||
;;
|
||||
--enable-plugins) plugins="yes"
|
||||
;;
|
||||
--disable-plugins) plugins="no"
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: unknown option $opt"
|
||||
echo "Try '$0 --help' for more information"
|
||||
@@ -1713,6 +1719,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:
|
||||
@@ -3644,6 +3652,9 @@ 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"
|
||||
fi
|
||||
|
||||
# This workaround is required due to a bug in pkg-config file for glib as it
|
||||
# doesn't define GLIB_STATIC_COMPILATION for pkg-config --static
|
||||
@@ -5494,6 +5505,61 @@ if compile_prog "" "" ; then
|
||||
atomic64=yes
|
||||
fi
|
||||
|
||||
#########################################
|
||||
# See if --dynamic-list is supported by the linker
|
||||
ld_dynamic_list="no"
|
||||
if test "$static" = "no" ; then
|
||||
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
|
||||
|
||||
if compile_prog "" "-Wl,--dynamic-list=$TMPTXT" ; then
|
||||
ld_dynamic_list="yes"
|
||||
fi
|
||||
fi
|
||||
|
||||
#########################################
|
||||
# See if -exported_symbols_list is supported by the linker
|
||||
|
||||
ld_exported_symbols_list="no"
|
||||
if test "$static" = "no" ; then
|
||||
cat > $TMPTXT <<EOF
|
||||
_foo
|
||||
EOF
|
||||
|
||||
if compile_prog "" "-Wl,-exported_symbols_list,$TMPTXT" ; then
|
||||
ld_exported_symbols_list="yes"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$plugins" = "yes" &&
|
||||
test "$ld_dynamic_list" = "no" &&
|
||||
test "$ld_exported_symbols_list" = "no" ; then
|
||||
error_exit \
|
||||
"Plugin support requires dynamic linking and 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. You can't build with --static."
|
||||
fi
|
||||
|
||||
########################################
|
||||
# See if 16-byte vector operations are supported.
|
||||
# Even without a vector unit the compiler may expand these.
|
||||
@@ -6491,6 +6557,7 @@ echo "capstone $capstone"
|
||||
echo "libpmem support $libpmem"
|
||||
echo "libudev $libudev"
|
||||
echo "default devices $default_devices"
|
||||
echo "plugin support $plugins"
|
||||
|
||||
if test "$supported_cpu" = "no"; then
|
||||
echo
|
||||
@@ -7328,6 +7395,27 @@ 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"
|
||||
# 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
|
||||
QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
|
||||
elif test "$ARCH" = "sparc64" ; then
|
||||
@@ -7874,6 +7962,7 @@ DIRS="$DIRS roms/seabios roms/vgabios"
|
||||
LINKS="Makefile"
|
||||
LINKS="$LINKS tests/tcg/lm32/Makefile po/Makefile"
|
||||
LINKS="$LINKS tests/tcg/Makefile.target tests/fp/Makefile"
|
||||
LINKS="$LINKS tests/plugin/Makefile"
|
||||
LINKS="$LINKS pc-bios/optionrom/Makefile pc-bios/keymaps"
|
||||
LINKS="$LINKS pc-bios/s390-ccw/Makefile"
|
||||
LINKS="$LINKS roms/seabios/Makefile roms/vgabios/Makefile"
|
||||
|
||||
@@ -200,11 +200,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);
|
||||
|
||||
@@ -45,6 +45,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"
|
||||
@@ -1264,9 +1265,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. */
|
||||
|
||||
@@ -418,6 +418,7 @@ static bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count)
|
||||
# define cap_disas_target(i, p, s) false
|
||||
# define cap_disas_host(i, p, s) false
|
||||
# define cap_disas_monitor(i, p, c) false
|
||||
# define cap_disas_plugin(i, p, c) false
|
||||
#endif /* CONFIG_CAPSTONE */
|
||||
|
||||
/* Disassemble this for me please... (debugging). */
|
||||
@@ -475,6 +476,115 @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code,
|
||||
}
|
||||
}
|
||||
|
||||
static __thread 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_vprintf(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 */
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_CAPSTONE
|
||||
/* Disassemble a single instruction directly into plugin output */
|
||||
static
|
||||
bool cap_disas_plugin(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;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We should only be dissembling one instruction at a time here. If
|
||||
* there is left over it usually indicates the front end has read more
|
||||
* bytes than it needed.
|
||||
*/
|
||||
char *plugin_disas(CPUState *cpu, uint64_t addr, size_t size)
|
||||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
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 && cap_disas_plugin(&s.info, addr, size)) {
|
||||
return g_strdup(ds->str);
|
||||
}
|
||||
|
||||
if (s.info.print_insn == NULL) {
|
||||
s.info.print_insn = print_insn_od_target;
|
||||
}
|
||||
|
||||
count = s.info.print_insn(addr, &s.info);
|
||||
|
||||
/* The decoder probably read more than it needed it's not critical */
|
||||
if (count < size) {
|
||||
warn_report("%s: %zu bytes left over", __func__, size - count);
|
||||
}
|
||||
|
||||
return g_strdup(ds->str);
|
||||
}
|
||||
|
||||
/* Disassemble this for me please... (debugging). */
|
||||
void disas(FILE *out, void *code, unsigned long size)
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user