mirror of https://github.com/xemu-project/xemu.git
Final test, gdbstub, plugin and gitdm updates for 8.2
- fix duplicate register in arm xml - hide various duplicate system registers from gdbstub - add new gdb register test to the CI (skipping s390x/ppc64 for now) - introduce GDBFeatureBuilder - move plugin initialisation to after vCPU init completes - enable building TCG plugins on Windows platform - various gitdm updates - some mailmap fixes - disable testing for nios2 signals which have regressed -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmVLpk4ACgkQ+9DbCVqe KkT7Zwf+LgNS2T8Gd6UBMk50Zwew3DSzK3HRRkAlxSV9vN9TCprnVDGJn7ObRpfq QCwiTmh20JRPFFBEsPGy/ozNPZsuWbt1/vyh3fnU4KD3aMySuyc/Hb9/mONPC9VE zh1mUxLCx10uwG5qF8jupIp22BQYD7B9i4YSF1gAUGsQNU7BPvcBDeDzyhCItJen 73oG9RQm7vDbjTOcGDkAMAG8iwLt07oMgFrDSgD8x7RWOxG8aiM3ninAW6S5GcO3 s49t0rTqJIu+pOncYYzmPvFxyZ/6W82tsJYtfxlVML02qj24HOmLWywRWgL5b10y TyXsDba3Ru8ez/kEaVVX6u9N1G/Ktg== =or8W -----END PGP SIGNATURE----- Merge tag 'pull-halloween-omnibus-081123-1' of https://gitlab.com/stsquad/qemu into staging Final test, gdbstub, plugin and gitdm updates for 8.2 - fix duplicate register in arm xml - hide various duplicate system registers from gdbstub - add new gdb register test to the CI (skipping s390x/ppc64 for now) - introduce GDBFeatureBuilder - move plugin initialisation to after vCPU init completes - enable building TCG plugins on Windows platform - various gitdm updates - some mailmap fixes - disable testing for nios2 signals which have regressed # -----BEGIN PGP SIGNATURE----- # # iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmVLpk4ACgkQ+9DbCVqe # KkT7Zwf+LgNS2T8Gd6UBMk50Zwew3DSzK3HRRkAlxSV9vN9TCprnVDGJn7ObRpfq # QCwiTmh20JRPFFBEsPGy/ozNPZsuWbt1/vyh3fnU4KD3aMySuyc/Hb9/mONPC9VE # zh1mUxLCx10uwG5qF8jupIp22BQYD7B9i4YSF1gAUGsQNU7BPvcBDeDzyhCItJen # 73oG9RQm7vDbjTOcGDkAMAG8iwLt07oMgFrDSgD8x7RWOxG8aiM3ninAW6S5GcO3 # s49t0rTqJIu+pOncYYzmPvFxyZ/6W82tsJYtfxlVML02qj24HOmLWywRWgL5b10y # TyXsDba3Ru8ez/kEaVVX6u9N1G/Ktg== # =or8W # -----END PGP SIGNATURE----- # gpg: Signature made Wed 08 Nov 2023 23:16:30 HKT # gpg: using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44 # gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 6685 AE99 E751 67BC AFC8 DF35 FBD0 DB09 5A9E 2A44 * tag 'pull-halloween-omnibus-081123-1' of https://gitlab.com/stsquad/qemu: (23 commits) Revert "tests/tcg/nios2: Re-enable linux-user tests" mailmap: fixup some more corrupted author fields contrib/gitdm: add Daynix to domain-map contrib/gitdm: map HiSilicon to Huawei contrib/gitdm: add domain-map for Cestc contrib/gitdm: Add Rivos Inc to the domain map plugins: allow plugins to be enabled on windows gitlab: add dlltool to Windows CI plugins: disable lockstep plugin on windows plugins: make test/example plugins work on windows plugins: add dllexport and dllimport to api funcs configure: tell meson and contrib_plugins about DLLTOOL cpu: Call plugin hooks only when ready gdbstub: Introduce GDBFeatureBuilder gdbstub: Introduce gdb_find_static_feature() gdbstub: Add num_regs member to GDBFeature tests/avocado: update the tcg_plugins test tests/tcg: add an explicit gdbstub register tester target/arm: hide aliased MIDR from gdbstub target/arm: hide all versions of DBGD[RS]AR from gdbstub ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
9a4750143c
|
@ -165,7 +165,7 @@ cross-win32-system:
|
||||||
job: win32-fedora-cross-container
|
job: win32-fedora-cross-container
|
||||||
variables:
|
variables:
|
||||||
IMAGE: fedora-win32-cross
|
IMAGE: fedora-win32-cross
|
||||||
EXTRA_CONFIGURE_OPTS: --enable-fdt=internal
|
EXTRA_CONFIGURE_OPTS: --enable-fdt=internal --disable-plugins
|
||||||
CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu m68k-softmmu
|
CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu m68k-softmmu
|
||||||
microblazeel-softmmu mips64el-softmmu nios2-softmmu
|
microblazeel-softmmu mips64el-softmmu nios2-softmmu
|
||||||
artifacts:
|
artifacts:
|
||||||
|
@ -179,7 +179,7 @@ cross-win64-system:
|
||||||
job: win64-fedora-cross-container
|
job: win64-fedora-cross-container
|
||||||
variables:
|
variables:
|
||||||
IMAGE: fedora-win64-cross
|
IMAGE: fedora-win64-cross
|
||||||
EXTRA_CONFIGURE_OPTS: --enable-fdt=internal
|
EXTRA_CONFIGURE_OPTS: --enable-fdt=internal --disable-plugins
|
||||||
CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu
|
CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu
|
||||||
m68k-softmmu microblazeel-softmmu nios2-softmmu
|
m68k-softmmu microblazeel-softmmu nios2-softmmu
|
||||||
or1k-softmmu rx-softmmu sh4eb-softmmu sparc64-softmmu
|
or1k-softmmu rx-softmmu sh4eb-softmmu sparc64-softmmu
|
||||||
|
|
|
@ -72,6 +72,7 @@
|
||||||
- .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed
|
- .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed
|
||||||
bison diffutils flex
|
bison diffutils flex
|
||||||
git grep make sed
|
git grep make sed
|
||||||
|
$MINGW_TARGET-binutils
|
||||||
$MINGW_TARGET-capstone
|
$MINGW_TARGET-capstone
|
||||||
$MINGW_TARGET-ccache
|
$MINGW_TARGET-ccache
|
||||||
$MINGW_TARGET-curl
|
$MINGW_TARGET-curl
|
||||||
|
|
2
.mailmap
2
.mailmap
|
@ -30,10 +30,12 @@ malc <av1474@comtv.ru> malc <malc@c046a42c-6fe2-441c-8c8c-71466251a162>
|
||||||
# Corrupted Author fields
|
# Corrupted Author fields
|
||||||
Aaron Larson <alarson@ddci.com> alarson@ddci.com
|
Aaron Larson <alarson@ddci.com> alarson@ddci.com
|
||||||
Andreas Färber <andreas.faerber@web.de> Andreas Färber <andreas.faerber>
|
Andreas Färber <andreas.faerber@web.de> Andreas Färber <andreas.faerber>
|
||||||
|
fanwenjie <fanwj@mail.ustc.edu.cn> fanwj@mail.ustc.edu.cn <fanwj@mail.ustc.edu.cn>
|
||||||
Jason Wang <jasowang@redhat.com> Jason Wang <jasowang>
|
Jason Wang <jasowang@redhat.com> Jason Wang <jasowang>
|
||||||
Marek Dolata <mkdolata@us.ibm.com> mkdolata@us.ibm.com <mkdolata@us.ibm.com>
|
Marek Dolata <mkdolata@us.ibm.com> mkdolata@us.ibm.com <mkdolata@us.ibm.com>
|
||||||
Michael Ellerman <mpe@ellerman.id.au> michael@ozlabs.org <michael@ozlabs.org>
|
Michael Ellerman <mpe@ellerman.id.au> michael@ozlabs.org <michael@ozlabs.org>
|
||||||
Nick Hudson <hnick@vmware.com> hnick@vmware.com <hnick@vmware.com>
|
Nick Hudson <hnick@vmware.com> hnick@vmware.com <hnick@vmware.com>
|
||||||
|
Timothée Cocault <timothee.cocault@gmail.com> timothee.cocault@gmail.com <timothee.cocault@gmail.com>
|
||||||
|
|
||||||
# There is also a:
|
# There is also a:
|
||||||
# (no author) <(no author)@c046a42c-6fe2-441c-8c8c-71466251a162>
|
# (no author) <(no author)@c046a42c-6fe2-441c-8c8c-71466251a162>
|
||||||
|
|
|
@ -2942,7 +2942,7 @@ F: gdbstub/*
|
||||||
F: include/exec/gdbstub.h
|
F: include/exec/gdbstub.h
|
||||||
F: include/gdbstub/*
|
F: include/gdbstub/*
|
||||||
F: gdb-xml/
|
F: gdb-xml/
|
||||||
F: tests/tcg/multiarch/gdbstub/
|
F: tests/tcg/multiarch/gdbstub/*
|
||||||
F: scripts/feature_to_c.py
|
F: scripts/feature_to_c.py
|
||||||
F: scripts/probe-gdb-support.py
|
F: scripts/probe-gdb-support.py
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
# Default configuration for loongarch64-linux-user
|
# Default configuration for loongarch64-linux-user
|
||||||
TARGET_ARCH=loongarch64
|
TARGET_ARCH=loongarch64
|
||||||
TARGET_BASE_ARCH=loongarch
|
TARGET_BASE_ARCH=loongarch
|
||||||
|
TARGET_XML_FILES=gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml
|
||||||
|
|
|
@ -309,6 +309,7 @@ fi
|
||||||
ar="${AR-${cross_prefix}ar}"
|
ar="${AR-${cross_prefix}ar}"
|
||||||
as="${AS-${cross_prefix}as}"
|
as="${AS-${cross_prefix}as}"
|
||||||
ccas="${CCAS-$cc}"
|
ccas="${CCAS-$cc}"
|
||||||
|
dlltool="${DLLTOOL-${cross_prefix}dlltool}"
|
||||||
objcopy="${OBJCOPY-${cross_prefix}objcopy}"
|
objcopy="${OBJCOPY-${cross_prefix}objcopy}"
|
||||||
ld="${LD-${cross_prefix}ld}"
|
ld="${LD-${cross_prefix}ld}"
|
||||||
ranlib="${RANLIB-${cross_prefix}ranlib}"
|
ranlib="${RANLIB-${cross_prefix}ranlib}"
|
||||||
|
@ -1010,9 +1011,9 @@ if test "$targetos" = "bogus"; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# test for any invalid configuration combinations
|
# test for any invalid configuration combinations
|
||||||
if test "$targetos" = "windows"; then
|
if test "$targetos" = "windows" && ! has "$dlltool"; then
|
||||||
if test "$plugins" = "yes"; then
|
if test "$plugins" = "yes"; then
|
||||||
error_exit "TCG plugins not currently supported on Windows platforms"
|
error_exit "TCG plugins requires dlltool to build on Windows platforms"
|
||||||
fi
|
fi
|
||||||
plugins="no"
|
plugins="no"
|
||||||
fi
|
fi
|
||||||
|
@ -1659,9 +1660,15 @@ echo "SRC_PATH=$source_path/contrib/plugins" >> contrib/plugins/$config_host_mak
|
||||||
echo "PKG_CONFIG=${pkg_config}" >> contrib/plugins/$config_host_mak
|
echo "PKG_CONFIG=${pkg_config}" >> contrib/plugins/$config_host_mak
|
||||||
echo "CC=$cc $CPU_CFLAGS" >> contrib/plugins/$config_host_mak
|
echo "CC=$cc $CPU_CFLAGS" >> contrib/plugins/$config_host_mak
|
||||||
echo "CFLAGS=${CFLAGS-$default_cflags} $EXTRA_CFLAGS" >> contrib/plugins/$config_host_mak
|
echo "CFLAGS=${CFLAGS-$default_cflags} $EXTRA_CFLAGS" >> contrib/plugins/$config_host_mak
|
||||||
|
if test "$targetos" = windows; then
|
||||||
|
echo "DLLTOOL=$dlltool" >> contrib/plugins/$config_host_mak
|
||||||
|
fi
|
||||||
if test "$targetos" = darwin; then
|
if test "$targetos" = darwin; then
|
||||||
echo "CONFIG_DARWIN=y" >> contrib/plugins/$config_host_mak
|
echo "CONFIG_DARWIN=y" >> contrib/plugins/$config_host_mak
|
||||||
fi
|
fi
|
||||||
|
if test "$targetos" = windows; then
|
||||||
|
echo "CONFIG_WIN32=y" >> contrib/plugins/$config_host_mak
|
||||||
|
fi
|
||||||
|
|
||||||
# tests/tcg configuration
|
# tests/tcg configuration
|
||||||
(config_host_mak=tests/tcg/config-host.mak
|
(config_host_mak=tests/tcg/config-host.mak
|
||||||
|
@ -1764,6 +1771,7 @@ if test "$skip_meson" = no; then
|
||||||
test -n "$cxx" && echo "cpp = [$(meson_quote $cxx $CPU_CFLAGS)]" >> $cross
|
test -n "$cxx" && echo "cpp = [$(meson_quote $cxx $CPU_CFLAGS)]" >> $cross
|
||||||
test -n "$objcc" && echo "objc = [$(meson_quote $objcc $CPU_CFLAGS)]" >> $cross
|
test -n "$objcc" && echo "objc = [$(meson_quote $objcc $CPU_CFLAGS)]" >> $cross
|
||||||
echo "ar = [$(meson_quote $ar)]" >> $cross
|
echo "ar = [$(meson_quote $ar)]" >> $cross
|
||||||
|
echo "dlltool = [$(meson_quote $dlltool)]" >> $cross
|
||||||
echo "nm = [$(meson_quote $nm)]" >> $cross
|
echo "nm = [$(meson_quote $nm)]" >> $cross
|
||||||
echo "pkgconfig = [$(meson_quote $pkg_config)]" >> $cross
|
echo "pkgconfig = [$(meson_quote $pkg_config)]" >> $cross
|
||||||
echo "pkg-config = [$(meson_quote $pkg_config)]" >> $cross
|
echo "pkg-config = [$(meson_quote $pkg_config)]" >> $cross
|
||||||
|
@ -1869,6 +1877,7 @@ preserve_env CC
|
||||||
preserve_env CFLAGS
|
preserve_env CFLAGS
|
||||||
preserve_env CXX
|
preserve_env CXX
|
||||||
preserve_env CXXFLAGS
|
preserve_env CXXFLAGS
|
||||||
|
preserve_env DLLTOOL
|
||||||
preserve_env LD
|
preserve_env LD
|
||||||
preserve_env LDFLAGS
|
preserve_env LDFLAGS
|
||||||
preserve_env LD_LIBRARY_PATH
|
preserve_env LD_LIBRARY_PATH
|
||||||
|
|
|
@ -12,15 +12,18 @@ amd.com AMD
|
||||||
aspeedtech.com ASPEED Technology Inc.
|
aspeedtech.com ASPEED Technology Inc.
|
||||||
baidu.com Baidu
|
baidu.com Baidu
|
||||||
bytedance.com ByteDance
|
bytedance.com ByteDance
|
||||||
|
cestc.cn Cestc
|
||||||
cmss.chinamobile.com China Mobile
|
cmss.chinamobile.com China Mobile
|
||||||
citrix.com Citrix
|
citrix.com Citrix
|
||||||
crudebyte.com Crudebyte
|
crudebyte.com Crudebyte
|
||||||
chinatelecom.cn China Telecom
|
chinatelecom.cn China Telecom
|
||||||
|
daynix.com Daynix
|
||||||
eldorado.org.br Instituto de Pesquisas Eldorado
|
eldorado.org.br Instituto de Pesquisas Eldorado
|
||||||
fb.com Facebook
|
fb.com Facebook
|
||||||
fujitsu.com Fujitsu
|
fujitsu.com Fujitsu
|
||||||
google.com Google
|
google.com Google
|
||||||
greensocs.com GreenSocs
|
greensocs.com GreenSocs
|
||||||
|
hisilicon.com Huawei
|
||||||
huawei.com Huawei
|
huawei.com Huawei
|
||||||
ibm.com IBM
|
ibm.com IBM
|
||||||
igalia.com Igalia
|
igalia.com Igalia
|
||||||
|
@ -38,6 +41,7 @@ proxmox.com Proxmox
|
||||||
quicinc.com Qualcomm Innovation Center
|
quicinc.com Qualcomm Innovation Center
|
||||||
redhat.com Red Hat
|
redhat.com Red Hat
|
||||||
rev.ng rev.ng Labs
|
rev.ng rev.ng Labs
|
||||||
|
rivosinc.com Rivos Inc
|
||||||
rt-rk.com RT-RK
|
rt-rk.com RT-RK
|
||||||
samsung.com Samsung
|
samsung.com Samsung
|
||||||
siemens.com Siemens
|
siemens.com Siemens
|
||||||
|
|
|
@ -17,12 +17,25 @@ NAMES += execlog
|
||||||
NAMES += hotblocks
|
NAMES += hotblocks
|
||||||
NAMES += hotpages
|
NAMES += hotpages
|
||||||
NAMES += howvec
|
NAMES += howvec
|
||||||
|
|
||||||
|
# The lockstep example communicates using unix sockets,
|
||||||
|
# and can't be easily made to work on windows.
|
||||||
|
ifneq ($(CONFIG_WIN32),y)
|
||||||
NAMES += lockstep
|
NAMES += lockstep
|
||||||
|
endif
|
||||||
|
|
||||||
NAMES += hwprofile
|
NAMES += hwprofile
|
||||||
NAMES += cache
|
NAMES += cache
|
||||||
NAMES += drcov
|
NAMES += drcov
|
||||||
|
|
||||||
SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES)))
|
ifeq ($(CONFIG_WIN32),y)
|
||||||
|
SO_SUFFIX := .dll
|
||||||
|
LDLIBS += $(shell $(PKG_CONFIG) --libs glib-2.0)
|
||||||
|
else
|
||||||
|
SO_SUFFIX := .so
|
||||||
|
endif
|
||||||
|
|
||||||
|
SONAMES := $(addsuffix $(SO_SUFFIX),$(addprefix lib,$(NAMES)))
|
||||||
|
|
||||||
# The main QEMU uses Glib extensively so it's perfectly fine to use it
|
# The main QEMU uses Glib extensively so it's perfectly fine to use it
|
||||||
# in plugins (which many example do).
|
# in plugins (which many example do).
|
||||||
|
@ -35,15 +48,20 @@ all: $(SONAMES)
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(CC) $(CFLAGS) $(PLUGIN_CFLAGS) -c -o $@ $<
|
$(CC) $(CFLAGS) $(PLUGIN_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
lib%.so: %.o
|
ifeq ($(CONFIG_WIN32),y)
|
||||||
ifeq ($(CONFIG_DARWIN),y)
|
lib%$(SO_SUFFIX): %.o win32_linker.o ../../plugins/qemu_plugin_api.lib
|
||||||
|
$(CC) -shared -o $@ $^ $(LDLIBS)
|
||||||
|
else ifeq ($(CONFIG_DARWIN),y)
|
||||||
|
lib%$(SO_SUFFIX): %.o
|
||||||
$(CC) -bundle -Wl,-undefined,dynamic_lookup -o $@ $^ $(LDLIBS)
|
$(CC) -bundle -Wl,-undefined,dynamic_lookup -o $@ $^ $(LDLIBS)
|
||||||
else
|
else
|
||||||
|
lib%$(SO_SUFFIX): %.o
|
||||||
$(CC) -shared -o $@ $^ $(LDLIBS)
|
$(CC) -shared -o $@ $^ $(LDLIBS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o *.so *.d
|
rm -f *.o *$(SO_SUFFIX) *.d
|
||||||
rm -Rf .libs
|
rm -Rf .libs
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023, Greg Manning <gmanning@rapitasystems.com>
|
||||||
|
*
|
||||||
|
* This hook, __pfnDliFailureHook2, is documented in the microsoft documentation here:
|
||||||
|
* https://learn.microsoft.com/en-us/cpp/build/reference/error-handling-and-notification
|
||||||
|
* It gets called when a delay-loaded DLL encounters various errors.
|
||||||
|
* We handle the specific case of a DLL looking for a "qemu.exe",
|
||||||
|
* and give it the running executable (regardless of what it is named).
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
||||||
|
* See the COPYING.LIB file in the top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <delayimp.h>
|
||||||
|
|
||||||
|
FARPROC WINAPI dll_failure_hook(unsigned dliNotify, PDelayLoadInfo pdli);
|
||||||
|
|
||||||
|
|
||||||
|
PfnDliHook __pfnDliFailureHook2 = dll_failure_hook;
|
||||||
|
|
||||||
|
FARPROC WINAPI dll_failure_hook(unsigned dliNotify, PDelayLoadInfo pdli) {
|
||||||
|
if (dliNotify == dliFailLoadLib) {
|
||||||
|
/* If the failing request was for qemu.exe, ... */
|
||||||
|
if (strcmp(pdli->szDll, "qemu.exe") == 0) {
|
||||||
|
/* Then pass back a pointer to the top level module. */
|
||||||
|
HMODULE top = GetModuleHandle(NULL);
|
||||||
|
return (FARPROC) top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Otherwise we can't do anything special. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
11
cpu-target.c
11
cpu-target.c
|
@ -42,7 +42,6 @@
|
||||||
#include "hw/core/accel-cpu.h"
|
#include "hw/core/accel-cpu.h"
|
||||||
#include "trace/trace-root.h"
|
#include "trace/trace-root.h"
|
||||||
#include "qemu/accel.h"
|
#include "qemu/accel.h"
|
||||||
#include "qemu/plugin.h"
|
|
||||||
|
|
||||||
uintptr_t qemu_host_page_size;
|
uintptr_t qemu_host_page_size;
|
||||||
intptr_t qemu_host_page_mask;
|
intptr_t qemu_host_page_mask;
|
||||||
|
@ -143,11 +142,6 @@ bool cpu_exec_realizefn(CPUState *cpu, Error **errp)
|
||||||
/* Wait until cpu initialization complete before exposing cpu. */
|
/* Wait until cpu initialization complete before exposing cpu. */
|
||||||
cpu_list_add(cpu);
|
cpu_list_add(cpu);
|
||||||
|
|
||||||
/* Plugin initialization must wait until cpu_index assigned. */
|
|
||||||
if (tcg_enabled()) {
|
|
||||||
qemu_plugin_vcpu_init_hook(cpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
assert(qdev_get_vmsd(DEVICE(cpu)) == NULL ||
|
assert(qdev_get_vmsd(DEVICE(cpu)) == NULL ||
|
||||||
qdev_get_vmsd(DEVICE(cpu))->unmigratable);
|
qdev_get_vmsd(DEVICE(cpu))->unmigratable);
|
||||||
|
@ -176,11 +170,6 @@ void cpu_exec_unrealizefn(CPUState *cpu)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Call the plugin hook before clearing cpu->cpu_index in cpu_list_remove */
|
|
||||||
if (tcg_enabled()) {
|
|
||||||
qemu_plugin_vcpu_exit_hook(cpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
cpu_list_remove(cpu);
|
cpu_list_remove(cpu);
|
||||||
/*
|
/*
|
||||||
* Now that the vCPU has been removed from the RCU list, we can call
|
* Now that the vCPU has been removed from the RCU list, we can call
|
||||||
|
|
|
@ -76,7 +76,7 @@
|
||||||
<reg name="q8" bitsize="128" type="neon_q"/>
|
<reg name="q8" bitsize="128" type="neon_q"/>
|
||||||
<reg name="q9" bitsize="128" type="neon_q"/>
|
<reg name="q9" bitsize="128" type="neon_q"/>
|
||||||
<reg name="q10" bitsize="128" type="neon_q"/>
|
<reg name="q10" bitsize="128" type="neon_q"/>
|
||||||
<reg name="q10" bitsize="128" type="neon_q"/>
|
<reg name="q11" bitsize="128" type="neon_q"/>
|
||||||
<reg name="q12" bitsize="128" type="neon_q"/>
|
<reg name="q12" bitsize="128" type="neon_q"/>
|
||||||
<reg name="q13" bitsize="128" type="neon_q"/>
|
<reg name="q13" bitsize="128" type="neon_q"/>
|
||||||
<reg name="q14" bitsize="128" type="neon_q"/>
|
<reg name="q14" bitsize="128" type="neon_q"/>
|
||||||
|
|
|
@ -422,6 +422,84 @@ static const char *get_feature_xml(const char *p, const char **newp,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gdb_feature_builder_init(GDBFeatureBuilder *builder, GDBFeature *feature,
|
||||||
|
const char *name, const char *xmlname,
|
||||||
|
int base_reg)
|
||||||
|
{
|
||||||
|
char *header = g_markup_printf_escaped(
|
||||||
|
"<?xml version=\"1.0\"?>"
|
||||||
|
"<!DOCTYPE feature SYSTEM \"gdb-target.dtd\">"
|
||||||
|
"<feature name=\"%s\">",
|
||||||
|
name);
|
||||||
|
|
||||||
|
builder->feature = feature;
|
||||||
|
builder->xml = g_ptr_array_new();
|
||||||
|
g_ptr_array_add(builder->xml, header);
|
||||||
|
builder->base_reg = base_reg;
|
||||||
|
feature->xmlname = xmlname;
|
||||||
|
feature->num_regs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_feature_builder_append_tag(const GDBFeatureBuilder *builder,
|
||||||
|
const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
g_ptr_array_add(builder->xml, g_markup_vprintf_escaped(format, ap));
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_feature_builder_append_reg(const GDBFeatureBuilder *builder,
|
||||||
|
const char *name,
|
||||||
|
int bitsize,
|
||||||
|
int regnum,
|
||||||
|
const char *type,
|
||||||
|
const char *group)
|
||||||
|
{
|
||||||
|
if (builder->feature->num_regs < regnum) {
|
||||||
|
builder->feature->num_regs = regnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group) {
|
||||||
|
gdb_feature_builder_append_tag(
|
||||||
|
builder,
|
||||||
|
"<reg name=\"%s\" bitsize=\"%d\" regnum=\"%d\" type=\"%s\" group=\"%s\"/>",
|
||||||
|
name, bitsize, builder->base_reg + regnum, type, group);
|
||||||
|
} else {
|
||||||
|
gdb_feature_builder_append_tag(
|
||||||
|
builder,
|
||||||
|
"<reg name=\"%s\" bitsize=\"%d\" regnum=\"%d\" type=\"%s\"/>",
|
||||||
|
name, bitsize, builder->base_reg + regnum, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_feature_builder_end(const GDBFeatureBuilder *builder)
|
||||||
|
{
|
||||||
|
g_ptr_array_add(builder->xml, (void *)"</feature>");
|
||||||
|
g_ptr_array_add(builder->xml, NULL);
|
||||||
|
|
||||||
|
builder->feature->xml = g_strjoinv(NULL, (void *)builder->xml->pdata);
|
||||||
|
|
||||||
|
for (guint i = 0; i < builder->xml->len - 2; i++) {
|
||||||
|
g_free(g_ptr_array_index(builder->xml, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ptr_array_free(builder->xml, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
const GDBFeature *gdb_find_static_feature(const char *xmlname)
|
||||||
|
{
|
||||||
|
const GDBFeature *feature;
|
||||||
|
|
||||||
|
for (feature = gdb_static_features; feature->xmlname; feature++) {
|
||||||
|
if (!strcmp(feature->xmlname, xmlname)) {
|
||||||
|
return feature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
|
static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
|
||||||
{
|
{
|
||||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||||
|
|
|
@ -214,6 +214,11 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp)
|
||||||
cpu_resume(cpu);
|
cpu_resume(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Plugin initialization must wait until the cpu is fully realized. */
|
||||||
|
if (tcg_enabled()) {
|
||||||
|
qemu_plugin_vcpu_init_hook(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
/* NOTE: latest generic point where the cpu is fully realized */
|
/* NOTE: latest generic point where the cpu is fully realized */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,6 +226,11 @@ static void cpu_common_unrealizefn(DeviceState *dev)
|
||||||
{
|
{
|
||||||
CPUState *cpu = CPU(dev);
|
CPUState *cpu = CPU(dev);
|
||||||
|
|
||||||
|
/* Call the plugin hook before clearing the cpu is fully unrealized */
|
||||||
|
if (tcg_enabled()) {
|
||||||
|
qemu_plugin_vcpu_exit_hook(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
/* NOTE: latest generic point before the cpu is fully unrealized */
|
/* NOTE: latest generic point before the cpu is fully unrealized */
|
||||||
cpu_exec_unrealizefn(cpu);
|
cpu_exec_unrealizefn(cpu);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,15 @@
|
||||||
typedef struct GDBFeature {
|
typedef struct GDBFeature {
|
||||||
const char *xmlname;
|
const char *xmlname;
|
||||||
const char *xml;
|
const char *xml;
|
||||||
|
int num_regs;
|
||||||
} GDBFeature;
|
} GDBFeature;
|
||||||
|
|
||||||
|
typedef struct GDBFeatureBuilder {
|
||||||
|
GDBFeature *feature;
|
||||||
|
GPtrArray *xml;
|
||||||
|
int base_reg;
|
||||||
|
} GDBFeatureBuilder;
|
||||||
|
|
||||||
|
|
||||||
/* Get or set a register. Returns the size of the register. */
|
/* Get or set a register. Returns the size of the register. */
|
||||||
typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg);
|
typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg);
|
||||||
|
@ -43,6 +50,58 @@ void gdb_register_coprocessor(CPUState *cpu,
|
||||||
*/
|
*/
|
||||||
int gdbserver_start(const char *port_or_device);
|
int gdbserver_start(const char *port_or_device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gdb_feature_builder_init() - Initialize GDBFeatureBuilder.
|
||||||
|
* @builder: The builder to be initialized.
|
||||||
|
* @feature: The feature to be filled.
|
||||||
|
* @name: The name of the feature.
|
||||||
|
* @xmlname: The name of the XML.
|
||||||
|
* @base_reg: The base number of the register ID.
|
||||||
|
*/
|
||||||
|
void gdb_feature_builder_init(GDBFeatureBuilder *builder, GDBFeature *feature,
|
||||||
|
const char *name, const char *xmlname,
|
||||||
|
int base_reg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gdb_feature_builder_append_tag() - Append a tag.
|
||||||
|
* @builder: The builder.
|
||||||
|
* @format: The format of the tag.
|
||||||
|
* @...: The values to be formatted.
|
||||||
|
*/
|
||||||
|
void G_GNUC_PRINTF(2, 3)
|
||||||
|
gdb_feature_builder_append_tag(const GDBFeatureBuilder *builder,
|
||||||
|
const char *format, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gdb_feature_builder_append_reg() - Append a register.
|
||||||
|
* @builder: The builder.
|
||||||
|
* @name: The register's name; it must be unique within a CPU.
|
||||||
|
* @bitsize: The register's size, in bits.
|
||||||
|
* @regnum: The offset of the register's number in the feature.
|
||||||
|
* @type: The type of the register.
|
||||||
|
* @group: The register group to which this register belongs; it can be NULL.
|
||||||
|
*/
|
||||||
|
void gdb_feature_builder_append_reg(const GDBFeatureBuilder *builder,
|
||||||
|
const char *name,
|
||||||
|
int bitsize,
|
||||||
|
int regnum,
|
||||||
|
const char *type,
|
||||||
|
const char *group);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gdb_feature_builder_end() - End building GDBFeature.
|
||||||
|
* @builder: The builder.
|
||||||
|
*/
|
||||||
|
void gdb_feature_builder_end(const GDBFeatureBuilder *builder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gdb_find_static_feature() - Find a static feature.
|
||||||
|
* @xmlname: The name of the XML.
|
||||||
|
*
|
||||||
|
* Return: The static feature.
|
||||||
|
*/
|
||||||
|
const GDBFeature *gdb_find_static_feature(const char *xmlname);
|
||||||
|
|
||||||
void gdb_set_stop_cpu(CPUState *cpu);
|
void gdb_set_stop_cpu(CPUState *cpu);
|
||||||
|
|
||||||
/* in gdbstub-xml.c, generated by scripts/feature_to_c.py */
|
/* in gdbstub-xml.c, generated by scripts/feature_to_c.py */
|
||||||
|
|
|
@ -22,15 +22,18 @@
|
||||||
* https://gcc.gnu.org/wiki/Visibility
|
* https://gcc.gnu.org/wiki/Visibility
|
||||||
*/
|
*/
|
||||||
#if defined _WIN32 || defined __CYGWIN__
|
#if defined _WIN32 || defined __CYGWIN__
|
||||||
#ifdef BUILDING_DLL
|
#ifdef CONFIG_PLUGIN
|
||||||
#define QEMU_PLUGIN_EXPORT __declspec(dllexport)
|
|
||||||
#else
|
|
||||||
#define QEMU_PLUGIN_EXPORT __declspec(dllimport)
|
#define QEMU_PLUGIN_EXPORT __declspec(dllimport)
|
||||||
|
#define QEMU_PLUGIN_API __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define QEMU_PLUGIN_EXPORT __declspec(dllexport)
|
||||||
|
#define QEMU_PLUGIN_API __declspec(dllimport)
|
||||||
#endif
|
#endif
|
||||||
#define QEMU_PLUGIN_LOCAL
|
#define QEMU_PLUGIN_LOCAL
|
||||||
#else
|
#else
|
||||||
#define QEMU_PLUGIN_EXPORT __attribute__((visibility("default")))
|
#define QEMU_PLUGIN_EXPORT __attribute__((visibility("default")))
|
||||||
#define QEMU_PLUGIN_LOCAL __attribute__((visibility("hidden")))
|
#define QEMU_PLUGIN_LOCAL __attribute__((visibility("hidden")))
|
||||||
|
#define QEMU_PLUGIN_API
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -147,6 +150,7 @@ typedef void (*qemu_plugin_vcpu_udata_cb_t)(unsigned int vcpu_index,
|
||||||
*
|
*
|
||||||
* Note: Calling this function from qemu_plugin_install() is a bug.
|
* Note: Calling this function from qemu_plugin_install() is a bug.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void qemu_plugin_uninstall(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb);
|
void qemu_plugin_uninstall(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -160,6 +164,7 @@ void qemu_plugin_uninstall(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb);
|
||||||
* Plugins are reset asynchronously, and therefore the given plugin receives
|
* Plugins are reset asynchronously, and therefore the given plugin receives
|
||||||
* callbacks until @cb is called.
|
* callbacks until @cb is called.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void qemu_plugin_reset(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb);
|
void qemu_plugin_reset(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -171,6 +176,7 @@ void qemu_plugin_reset(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb);
|
||||||
*
|
*
|
||||||
* See also: qemu_plugin_register_vcpu_exit_cb()
|
* See also: qemu_plugin_register_vcpu_exit_cb()
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id,
|
void qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id,
|
||||||
qemu_plugin_vcpu_simple_cb_t cb);
|
qemu_plugin_vcpu_simple_cb_t cb);
|
||||||
|
|
||||||
|
@ -183,6 +189,7 @@ void qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id,
|
||||||
*
|
*
|
||||||
* See also: qemu_plugin_register_vcpu_init_cb()
|
* See also: qemu_plugin_register_vcpu_init_cb()
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,
|
void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,
|
||||||
qemu_plugin_vcpu_simple_cb_t cb);
|
qemu_plugin_vcpu_simple_cb_t cb);
|
||||||
|
|
||||||
|
@ -193,6 +200,7 @@ void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,
|
||||||
*
|
*
|
||||||
* The @cb function is called every time a vCPU idles.
|
* The @cb function is called every time a vCPU idles.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void qemu_plugin_register_vcpu_idle_cb(qemu_plugin_id_t id,
|
void qemu_plugin_register_vcpu_idle_cb(qemu_plugin_id_t id,
|
||||||
qemu_plugin_vcpu_simple_cb_t cb);
|
qemu_plugin_vcpu_simple_cb_t cb);
|
||||||
|
|
||||||
|
@ -203,6 +211,7 @@ void qemu_plugin_register_vcpu_idle_cb(qemu_plugin_id_t id,
|
||||||
*
|
*
|
||||||
* The @cb function is called every time a vCPU resumes execution.
|
* The @cb function is called every time a vCPU resumes execution.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
|
void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
|
||||||
qemu_plugin_vcpu_simple_cb_t cb);
|
qemu_plugin_vcpu_simple_cb_t cb);
|
||||||
|
|
||||||
|
@ -253,6 +262,7 @@ typedef void (*qemu_plugin_vcpu_tb_trans_cb_t)(qemu_plugin_id_t id,
|
||||||
* callbacks to be triggered when the block or individual instruction
|
* callbacks to be triggered when the block or individual instruction
|
||||||
* executes.
|
* executes.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
|
void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
|
||||||
qemu_plugin_vcpu_tb_trans_cb_t cb);
|
qemu_plugin_vcpu_tb_trans_cb_t cb);
|
||||||
|
|
||||||
|
@ -265,6 +275,7 @@ void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
|
||||||
*
|
*
|
||||||
* The @cb function is called every time a translated unit executes.
|
* The @cb function is called every time a translated unit executes.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
|
void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
|
||||||
qemu_plugin_vcpu_udata_cb_t cb,
|
qemu_plugin_vcpu_udata_cb_t cb,
|
||||||
enum qemu_plugin_cb_flags flags,
|
enum qemu_plugin_cb_flags flags,
|
||||||
|
@ -296,6 +307,7 @@ enum qemu_plugin_op {
|
||||||
* Note: ops are not atomic so in multi-threaded/multi-smp situations
|
* Note: ops are not atomic so in multi-threaded/multi-smp situations
|
||||||
* you will get inexact results.
|
* you will get inexact results.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void qemu_plugin_register_vcpu_tb_exec_inline(struct qemu_plugin_tb *tb,
|
void qemu_plugin_register_vcpu_tb_exec_inline(struct qemu_plugin_tb *tb,
|
||||||
enum qemu_plugin_op op,
|
enum qemu_plugin_op op,
|
||||||
void *ptr, uint64_t imm);
|
void *ptr, uint64_t imm);
|
||||||
|
@ -309,6 +321,7 @@ void qemu_plugin_register_vcpu_tb_exec_inline(struct qemu_plugin_tb *tb,
|
||||||
*
|
*
|
||||||
* The @cb function is called every time an instruction is executed
|
* The @cb function is called every time an instruction is executed
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
|
void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
|
||||||
qemu_plugin_vcpu_udata_cb_t cb,
|
qemu_plugin_vcpu_udata_cb_t cb,
|
||||||
enum qemu_plugin_cb_flags flags,
|
enum qemu_plugin_cb_flags flags,
|
||||||
|
@ -324,6 +337,7 @@ void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
|
||||||
* Insert an inline op to every time an instruction executes. Useful
|
* Insert an inline op to every time an instruction executes. Useful
|
||||||
* if you just want to increment a single counter somewhere in memory.
|
* if you just want to increment a single counter somewhere in memory.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void qemu_plugin_register_vcpu_insn_exec_inline(struct qemu_plugin_insn *insn,
|
void qemu_plugin_register_vcpu_insn_exec_inline(struct qemu_plugin_insn *insn,
|
||||||
enum qemu_plugin_op op,
|
enum qemu_plugin_op op,
|
||||||
void *ptr, uint64_t imm);
|
void *ptr, uint64_t imm);
|
||||||
|
@ -334,6 +348,7 @@ void qemu_plugin_register_vcpu_insn_exec_inline(struct qemu_plugin_insn *insn,
|
||||||
*
|
*
|
||||||
* Returns: number of instructions in this block
|
* Returns: number of instructions in this block
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb);
|
size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -342,6 +357,7 @@ size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb);
|
||||||
*
|
*
|
||||||
* Returns: virtual address of block start
|
* Returns: virtual address of block start
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb);
|
uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -355,6 +371,7 @@ uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb);
|
||||||
*
|
*
|
||||||
* Returns: opaque handle to instruction
|
* Returns: opaque handle to instruction
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
struct qemu_plugin_insn *
|
struct qemu_plugin_insn *
|
||||||
qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx);
|
qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx);
|
||||||
|
|
||||||
|
@ -368,6 +385,7 @@ qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx);
|
||||||
* Returns: pointer to a stream of bytes containing the value of this
|
* Returns: pointer to a stream of bytes containing the value of this
|
||||||
* instructions opcode.
|
* instructions opcode.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn);
|
const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -376,6 +394,7 @@ const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn);
|
||||||
*
|
*
|
||||||
* Returns: size of instruction in bytes
|
* Returns: size of instruction in bytes
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn);
|
size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -384,6 +403,7 @@ size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn);
|
||||||
*
|
*
|
||||||
* Returns: virtual address of instruction
|
* Returns: virtual address of instruction
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn);
|
uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -392,6 +412,7 @@ uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn);
|
||||||
*
|
*
|
||||||
* Returns: hardware (physical) target address of instruction
|
* Returns: hardware (physical) target address of instruction
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn);
|
void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -410,6 +431,7 @@ struct qemu_plugin_hwaddr;
|
||||||
*
|
*
|
||||||
* Returns: size of access in ^2 (0=byte, 1=16bit, 2=32bit etc...)
|
* Returns: size of access in ^2 (0=byte, 1=16bit, 2=32bit etc...)
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
unsigned int qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info);
|
unsigned int qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info);
|
||||||
/**
|
/**
|
||||||
* qemu_plugin_mem_is_sign_extended() - was the access sign extended
|
* qemu_plugin_mem_is_sign_extended() - was the access sign extended
|
||||||
|
@ -417,6 +439,7 @@ unsigned int qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info);
|
||||||
*
|
*
|
||||||
* Returns: true if it was, otherwise false
|
* Returns: true if it was, otherwise false
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info);
|
bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info);
|
||||||
/**
|
/**
|
||||||
* qemu_plugin_mem_is_big_endian() - was the access big endian
|
* qemu_plugin_mem_is_big_endian() - was the access big endian
|
||||||
|
@ -424,6 +447,7 @@ bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info);
|
||||||
*
|
*
|
||||||
* Returns: true if it was, otherwise false
|
* Returns: true if it was, otherwise false
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info);
|
bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info);
|
||||||
/**
|
/**
|
||||||
* qemu_plugin_mem_is_store() - was the access a store
|
* qemu_plugin_mem_is_store() - was the access a store
|
||||||
|
@ -431,6 +455,7 @@ bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info);
|
||||||
*
|
*
|
||||||
* Returns: true if it was, otherwise false
|
* Returns: true if it was, otherwise false
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info);
|
bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -446,6 +471,7 @@ bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info);
|
||||||
* information about the handle should be recovered before the
|
* information about the handle should be recovered before the
|
||||||
* callback returns.
|
* callback returns.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
|
struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
|
||||||
uint64_t vaddr);
|
uint64_t vaddr);
|
||||||
|
|
||||||
|
@ -462,6 +488,7 @@ struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
|
||||||
* Returns true if the handle's memory operation is to memory-mapped IO, or
|
* Returns true if the handle's memory operation is to memory-mapped IO, or
|
||||||
* false if it is to RAM
|
* false if it is to RAM
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
bool qemu_plugin_hwaddr_is_io(const struct qemu_plugin_hwaddr *haddr);
|
bool qemu_plugin_hwaddr_is_io(const struct qemu_plugin_hwaddr *haddr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -473,12 +500,14 @@ bool qemu_plugin_hwaddr_is_io(const struct qemu_plugin_hwaddr *haddr);
|
||||||
* Note that the returned physical address may not be unique if you are dealing
|
* Note that the returned physical address may not be unique if you are dealing
|
||||||
* with multiple address spaces.
|
* with multiple address spaces.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
uint64_t qemu_plugin_hwaddr_phys_addr(const struct qemu_plugin_hwaddr *haddr);
|
uint64_t qemu_plugin_hwaddr_phys_addr(const struct qemu_plugin_hwaddr *haddr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns a string representing the device. The string is valid for
|
* Returns a string representing the device. The string is valid for
|
||||||
* the lifetime of the plugin.
|
* the lifetime of the plugin.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
const char *qemu_plugin_hwaddr_device_name(const struct qemu_plugin_hwaddr *h);
|
const char *qemu_plugin_hwaddr_device_name(const struct qemu_plugin_hwaddr *h);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -513,6 +542,7 @@ typedef void (*qemu_plugin_vcpu_mem_cb_t) (unsigned int vcpu_index,
|
||||||
* callback so the plugin is responsible for ensuring it doesn't get
|
* callback so the plugin is responsible for ensuring it doesn't get
|
||||||
* confused by making appropriate use of locking if required.
|
* confused by making appropriate use of locking if required.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
|
void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
|
||||||
qemu_plugin_vcpu_mem_cb_t cb,
|
qemu_plugin_vcpu_mem_cb_t cb,
|
||||||
enum qemu_plugin_cb_flags flags,
|
enum qemu_plugin_cb_flags flags,
|
||||||
|
@ -531,6 +561,7 @@ void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
|
||||||
* instruction. This provides for a lightweight but not thread-safe
|
* instruction. This provides for a lightweight but not thread-safe
|
||||||
* way of counting the number of operations done.
|
* way of counting the number of operations done.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void qemu_plugin_register_vcpu_mem_inline(struct qemu_plugin_insn *insn,
|
void qemu_plugin_register_vcpu_mem_inline(struct qemu_plugin_insn *insn,
|
||||||
enum qemu_plugin_mem_rw rw,
|
enum qemu_plugin_mem_rw rw,
|
||||||
enum qemu_plugin_op op, void *ptr,
|
enum qemu_plugin_op op, void *ptr,
|
||||||
|
@ -544,6 +575,7 @@ typedef void
|
||||||
uint64_t a3, uint64_t a4, uint64_t a5,
|
uint64_t a3, uint64_t a4, uint64_t a5,
|
||||||
uint64_t a6, uint64_t a7, uint64_t a8);
|
uint64_t a6, uint64_t a7, uint64_t a8);
|
||||||
|
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id,
|
void qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id,
|
||||||
qemu_plugin_vcpu_syscall_cb_t cb);
|
qemu_plugin_vcpu_syscall_cb_t cb);
|
||||||
|
|
||||||
|
@ -551,6 +583,7 @@ typedef void
|
||||||
(*qemu_plugin_vcpu_syscall_ret_cb_t)(qemu_plugin_id_t id, unsigned int vcpu_idx,
|
(*qemu_plugin_vcpu_syscall_ret_cb_t)(qemu_plugin_id_t id, unsigned int vcpu_idx,
|
||||||
int64_t num, int64_t ret);
|
int64_t num, int64_t ret);
|
||||||
|
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void
|
void
|
||||||
qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
|
qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
|
||||||
qemu_plugin_vcpu_syscall_ret_cb_t cb);
|
qemu_plugin_vcpu_syscall_ret_cb_t cb);
|
||||||
|
@ -563,6 +596,7 @@ qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
|
||||||
* Returns an allocated string containing the disassembly
|
* Returns an allocated string containing the disassembly
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
QEMU_PLUGIN_API
|
||||||
char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn);
|
char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -572,6 +606,7 @@ char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn);
|
||||||
* Return a static string referring to the symbol. This is dependent
|
* Return a static string referring to the symbol. This is dependent
|
||||||
* on the binary QEMU is running having provided a symbol table.
|
* on the binary QEMU is running having provided a symbol table.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
const char *qemu_plugin_insn_symbol(const struct qemu_plugin_insn *insn);
|
const char *qemu_plugin_insn_symbol(const struct qemu_plugin_insn *insn);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -583,9 +618,11 @@ const char *qemu_plugin_insn_symbol(const struct qemu_plugin_insn *insn);
|
||||||
*
|
*
|
||||||
* See also: qemu_plugin_register_vcpu_init_cb()
|
* See also: qemu_plugin_register_vcpu_init_cb()
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void qemu_plugin_vcpu_for_each(qemu_plugin_id_t id,
|
void qemu_plugin_vcpu_for_each(qemu_plugin_id_t id,
|
||||||
qemu_plugin_vcpu_simple_cb_t cb);
|
qemu_plugin_vcpu_simple_cb_t cb);
|
||||||
|
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
|
void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
|
||||||
qemu_plugin_simple_cb_t cb);
|
qemu_plugin_simple_cb_t cb);
|
||||||
|
|
||||||
|
@ -602,6 +639,7 @@ void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
|
||||||
* In user-mode it is possible a few un-instrumented instructions from
|
* In user-mode it is possible a few un-instrumented instructions from
|
||||||
* child threads may run before the host kernel reaps the threads.
|
* child threads may run before the host kernel reaps the threads.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void qemu_plugin_register_atexit_cb(qemu_plugin_id_t id,
|
void qemu_plugin_register_atexit_cb(qemu_plugin_id_t id,
|
||||||
qemu_plugin_udata_cb_t cb, void *userdata);
|
qemu_plugin_udata_cb_t cb, void *userdata);
|
||||||
|
|
||||||
|
@ -615,6 +653,7 @@ int qemu_plugin_n_max_vcpus(void);
|
||||||
* qemu_plugin_outs() - output string via QEMU's logging system
|
* qemu_plugin_outs() - output string via QEMU's logging system
|
||||||
* @string: a string
|
* @string: a string
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
void qemu_plugin_outs(const char *string);
|
void qemu_plugin_outs(const char *string);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -628,6 +667,7 @@ void qemu_plugin_outs(const char *string);
|
||||||
* returns true if the combination @name=@val parses correctly to a boolean
|
* returns true if the combination @name=@val parses correctly to a boolean
|
||||||
* argument, and false otherwise
|
* argument, and false otherwise
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
bool qemu_plugin_bool_parse(const char *name, const char *val, bool *ret);
|
bool qemu_plugin_bool_parse(const char *name, const char *val, bool *ret);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -638,6 +678,7 @@ bool qemu_plugin_bool_parse(const char *name, const char *val, bool *ret);
|
||||||
* return NULL. The user should g_free() the string once no longer
|
* return NULL. The user should g_free() the string once no longer
|
||||||
* needed.
|
* needed.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
const char *qemu_plugin_path_to_binary(void);
|
const char *qemu_plugin_path_to_binary(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -646,6 +687,7 @@ const char *qemu_plugin_path_to_binary(void);
|
||||||
* Returns the nominal start address of the main text segment in
|
* Returns the nominal start address of the main text segment in
|
||||||
* user-mode. Currently returns 0 for system emulation.
|
* user-mode. Currently returns 0 for system emulation.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
uint64_t qemu_plugin_start_code(void);
|
uint64_t qemu_plugin_start_code(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -654,6 +696,7 @@ uint64_t qemu_plugin_start_code(void);
|
||||||
* Returns the nominal end address of the main text segment in
|
* Returns the nominal end address of the main text segment in
|
||||||
* user-mode. Currently returns 0 for system emulation.
|
* user-mode. Currently returns 0 for system emulation.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
uint64_t qemu_plugin_end_code(void);
|
uint64_t qemu_plugin_end_code(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -662,6 +705,7 @@ uint64_t qemu_plugin_end_code(void);
|
||||||
* Returns the nominal entry address of the main text segment in
|
* Returns the nominal entry address of the main text segment in
|
||||||
* user-mode. Currently returns 0 for system emulation.
|
* user-mode. Currently returns 0 for system emulation.
|
||||||
*/
|
*/
|
||||||
|
QEMU_PLUGIN_API
|
||||||
uint64_t qemu_plugin_entry_code(void);
|
uint64_t qemu_plugin_entry_code(void);
|
||||||
|
|
||||||
#endif /* QEMU_QEMU_PLUGIN_H */
|
#endif /* QEMU_QEMU_PLUGIN_H */
|
||||||
|
|
|
@ -3944,6 +3944,11 @@ endforeach
|
||||||
|
|
||||||
if get_option('plugins')
|
if get_option('plugins')
|
||||||
install_headers('include/qemu/qemu-plugin.h')
|
install_headers('include/qemu/qemu-plugin.h')
|
||||||
|
if targetos == 'windows'
|
||||||
|
# On windows, we want to deliver the qemu_plugin_api.lib file in the qemu installer,
|
||||||
|
# so that plugin authors can compile against it.
|
||||||
|
install_data(win32_qemu_plugin_api_lib, install_dir: 'lib')
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
subdir('qga')
|
subdir('qga')
|
||||||
|
|
|
@ -14,6 +14,25 @@ if not enable_modules
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if get_option('plugins')
|
if get_option('plugins')
|
||||||
|
if targetos == 'windows'
|
||||||
|
dlltool = find_program('dlltool', required: true)
|
||||||
|
|
||||||
|
# Generate a .lib file for plugins to link against.
|
||||||
|
# First, create a .def file listing all the symbols a plugin should expect to have
|
||||||
|
# available in qemu
|
||||||
|
win32_plugin_def = configure_file(
|
||||||
|
input: files('qemu-plugins.symbols'),
|
||||||
|
output: 'qemu_plugin_api.def',
|
||||||
|
capture: true,
|
||||||
|
command: ['sed', '-e', '0,/^/s//EXPORTS/; s/[{};]//g', '@INPUT@'])
|
||||||
|
# then use dlltool to assemble a delaylib.
|
||||||
|
win32_qemu_plugin_api_lib = configure_file(
|
||||||
|
input: win32_plugin_def,
|
||||||
|
output: 'qemu_plugin_api.lib',
|
||||||
|
command: [dlltool, '--input-def', '@INPUT@',
|
||||||
|
'--output-delaylib', '@OUTPUT@', '--dllname', 'qemu.exe']
|
||||||
|
)
|
||||||
|
endif
|
||||||
specific_ss.add(files(
|
specific_ss.add(files(
|
||||||
'loader.c',
|
'loader.c',
|
||||||
'core.c',
|
'core.c',
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
import os, sys
|
import os, sys, xml.etree.ElementTree
|
||||||
|
|
||||||
def writeliteral(indent, bytes):
|
def writeliteral(indent, bytes):
|
||||||
sys.stdout.write(' ' * indent)
|
sys.stdout.write(' ' * indent)
|
||||||
|
@ -39,10 +39,52 @@ for input in sys.argv[1:]:
|
||||||
with open(input, 'rb') as file:
|
with open(input, 'rb') as file:
|
||||||
read = file.read()
|
read = file.read()
|
||||||
|
|
||||||
|
parser = xml.etree.ElementTree.XMLPullParser(['start', 'end'])
|
||||||
|
parser.feed(read)
|
||||||
|
events = parser.read_events()
|
||||||
|
event, element = next(events)
|
||||||
|
if event != 'start':
|
||||||
|
sys.stderr.write(f'unexpected event: {event}\n')
|
||||||
|
exit(1)
|
||||||
|
if element.tag != 'feature':
|
||||||
|
sys.stderr.write(f'unexpected start tag: {element.tag}\n')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
regnum = 0
|
||||||
|
regnums = []
|
||||||
|
tags = ['feature']
|
||||||
|
for event, element in events:
|
||||||
|
if event == 'end':
|
||||||
|
if element.tag != tags[len(tags) - 1]:
|
||||||
|
sys.stderr.write(f'unexpected end tag: {element.tag}\n')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
tags.pop()
|
||||||
|
if element.tag == 'feature':
|
||||||
|
break
|
||||||
|
elif event == 'start':
|
||||||
|
if len(tags) < 2 and element.tag == 'reg':
|
||||||
|
if 'regnum' in element.attrib:
|
||||||
|
regnum = int(element.attrib['regnum'])
|
||||||
|
|
||||||
|
regnums.append(regnum)
|
||||||
|
regnum += 1
|
||||||
|
|
||||||
|
tags.append(element.tag)
|
||||||
|
else:
|
||||||
|
raise Exception(f'unexpected event: {event}\n')
|
||||||
|
|
||||||
|
if len(tags):
|
||||||
|
sys.stderr.write('unterminated feature tag\n')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
base_reg = min(regnums)
|
||||||
|
num_regs = max(regnums) - base_reg + 1 if len(regnums) else 0
|
||||||
|
|
||||||
sys.stdout.write(' {\n')
|
sys.stdout.write(' {\n')
|
||||||
writeliteral(8, bytes(os.path.basename(input), 'utf-8'))
|
writeliteral(8, bytes(os.path.basename(input), 'utf-8'))
|
||||||
sys.stdout.write(',\n')
|
sys.stdout.write(',\n')
|
||||||
writeliteral(8, read)
|
writeliteral(8, read)
|
||||||
sys.stdout.write('\n },\n')
|
sys.stdout.write(f',\n {num_regs},\n }},\n')
|
||||||
|
|
||||||
sys.stdout.write(' { NULL }\n};\n')
|
sys.stdout.write(' { NULL }\n};\n')
|
||||||
|
|
|
@ -937,14 +937,14 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
|
||||||
*/
|
*/
|
||||||
{ .name = "DBGDRAR", .cp = 14, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
|
{ .name = "DBGDRAR", .cp = 14, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
|
||||||
.access = PL0_R, .accessfn = access_tdra,
|
.access = PL0_R, .accessfn = access_tdra,
|
||||||
.type = ARM_CP_CONST, .resetvalue = 0 },
|
.type = ARM_CP_CONST | ARM_CP_NO_GDB, .resetvalue = 0 },
|
||||||
{ .name = "MDRAR_EL1", .state = ARM_CP_STATE_AA64,
|
{ .name = "MDRAR_EL1", .state = ARM_CP_STATE_AA64,
|
||||||
.opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 0,
|
.opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 0,
|
||||||
.access = PL1_R, .accessfn = access_tdra,
|
.access = PL1_R, .accessfn = access_tdra,
|
||||||
.type = ARM_CP_CONST, .resetvalue = 0 },
|
.type = ARM_CP_CONST, .resetvalue = 0 },
|
||||||
{ .name = "DBGDSAR", .cp = 14, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
|
{ .name = "DBGDSAR", .cp = 14, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
|
||||||
.access = PL0_R, .accessfn = access_tdra,
|
.access = PL0_R, .accessfn = access_tdra,
|
||||||
.type = ARM_CP_CONST, .resetvalue = 0 },
|
.type = ARM_CP_CONST | ARM_CP_NO_GDB, .resetvalue = 0 },
|
||||||
/* Monitor debug system control register; the 32-bit alias is DBGDSCRext. */
|
/* Monitor debug system control register; the 32-bit alias is DBGDSCRext. */
|
||||||
{ .name = "MDSCR_EL1", .state = ARM_CP_STATE_BOTH,
|
{ .name = "MDSCR_EL1", .state = ARM_CP_STATE_BOTH,
|
||||||
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2,
|
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2,
|
||||||
|
@ -1065,9 +1065,11 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
|
||||||
static const ARMCPRegInfo debug_lpae_cp_reginfo[] = {
|
static const ARMCPRegInfo debug_lpae_cp_reginfo[] = {
|
||||||
/* 64 bit access versions of the (dummy) debug registers */
|
/* 64 bit access versions of the (dummy) debug registers */
|
||||||
{ .name = "DBGDRAR", .cp = 14, .crm = 1, .opc1 = 0,
|
{ .name = "DBGDRAR", .cp = 14, .crm = 1, .opc1 = 0,
|
||||||
.access = PL0_R, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 },
|
.access = PL0_R, .type = ARM_CP_CONST | ARM_CP_64BIT | ARM_CP_NO_GDB,
|
||||||
|
.resetvalue = 0 },
|
||||||
{ .name = "DBGDSAR", .cp = 14, .crm = 2, .opc1 = 0,
|
{ .name = "DBGDSAR", .cp = 14, .crm = 2, .opc1 = 0,
|
||||||
.access = PL0_R, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 },
|
.access = PL0_R, .type = ARM_CP_CONST | ARM_CP_64BIT | ARM_CP_NO_GDB,
|
||||||
|
.resetvalue = 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void dbgwvr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
static void dbgwvr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
|
|
@ -3722,20 +3722,6 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const ARMCPRegInfo vapa_cp_reginfo[] = {
|
|
||||||
{ .name = "PAR", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0,
|
|
||||||
.access = PL1_RW, .resetvalue = 0,
|
|
||||||
.bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.par_s),
|
|
||||||
offsetoflow32(CPUARMState, cp15.par_ns) },
|
|
||||||
.writefn = par_write },
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
|
||||||
/* This underdecoding is safe because the reginfo is NO_RAW. */
|
|
||||||
{ .name = "ATS", .cp = 15, .crn = 7, .crm = 8, .opc1 = 0, .opc2 = CP_ANY,
|
|
||||||
.access = PL1_W, .accessfn = ats_access,
|
|
||||||
.writefn = ats_write, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC },
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Return basic MPU access permission bits. */
|
/* Return basic MPU access permission bits. */
|
||||||
static uint32_t simple_mpu_ap_bits(uint32_t val)
|
static uint32_t simple_mpu_ap_bits(uint32_t val)
|
||||||
{
|
{
|
||||||
|
@ -8904,6 +8890,27 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||||
define_arm_cp_regs(cpu, generic_timer_cp_reginfo);
|
define_arm_cp_regs(cpu, generic_timer_cp_reginfo);
|
||||||
}
|
}
|
||||||
if (arm_feature(env, ARM_FEATURE_VAPA)) {
|
if (arm_feature(env, ARM_FEATURE_VAPA)) {
|
||||||
|
ARMCPRegInfo vapa_cp_reginfo[] = {
|
||||||
|
{ .name = "PAR", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0,
|
||||||
|
.access = PL1_RW, .resetvalue = 0,
|
||||||
|
.bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.par_s),
|
||||||
|
offsetoflow32(CPUARMState, cp15.par_ns) },
|
||||||
|
.writefn = par_write},
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
/* This underdecoding is safe because the reginfo is NO_RAW. */
|
||||||
|
{ .name = "ATS", .cp = 15, .crn = 7, .crm = 8, .opc1 = 0, .opc2 = CP_ANY,
|
||||||
|
.access = PL1_W, .accessfn = ats_access,
|
||||||
|
.writefn = ats_write, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC },
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When LPAE exists this 32-bit PAR register is an alias of the
|
||||||
|
* 64-bit AArch32 PAR register defined in lpae_cp_reginfo[]
|
||||||
|
*/
|
||||||
|
if (arm_feature(env, ARM_FEATURE_LPAE)) {
|
||||||
|
vapa_cp_reginfo[0].type = ARM_CP_ALIAS | ARM_CP_NO_GDB;
|
||||||
|
}
|
||||||
define_arm_cp_regs(cpu, vapa_cp_reginfo);
|
define_arm_cp_regs(cpu, vapa_cp_reginfo);
|
||||||
}
|
}
|
||||||
if (arm_feature(env, ARM_FEATURE_CACHE_TEST_CLEAN)) {
|
if (arm_feature(env, ARM_FEATURE_CACHE_TEST_CLEAN)) {
|
||||||
|
@ -8993,7 +9000,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||||
.type = ARM_CP_CONST, .resetvalue = cpu->revidr },
|
.type = ARM_CP_CONST, .resetvalue = cpu->revidr },
|
||||||
};
|
};
|
||||||
ARMCPRegInfo id_v8_midr_alias_cp_reginfo = {
|
ARMCPRegInfo id_v8_midr_alias_cp_reginfo = {
|
||||||
.name = "MIDR", .type = ARM_CP_ALIAS | ARM_CP_CONST,
|
.name = "MIDR", .type = ARM_CP_ALIAS | ARM_CP_CONST | ARM_CP_NO_GDB,
|
||||||
.cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 4,
|
.cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 4,
|
||||||
.access = PL1_R, .resetvalue = cpu->midr
|
.access = PL1_R, .resetvalue = cpu->midr
|
||||||
};
|
};
|
||||||
|
|
|
@ -54,13 +54,11 @@ class PluginKernelBase(LinuxKernelTest):
|
||||||
class PluginKernelNormal(PluginKernelBase):
|
class PluginKernelNormal(PluginKernelBase):
|
||||||
|
|
||||||
def _grab_aarch64_kernel(self):
|
def _grab_aarch64_kernel(self):
|
||||||
kernel_url = ('http://security.debian.org/'
|
kernel_url = ('https://storage.tuxboot.com/20230331/arm64/Image')
|
||||||
'debian-security/pool/updates/main/l/linux-signed-arm64/'
|
kernel_sha256 = 'ce95a7101a5fecebe0fe630deee6bd97b32ba41bc8754090e9ad8961ea8674c7'
|
||||||
'linux-image-4.19.0-12-arm64_4.19.152-1_arm64.deb')
|
kernel_path = self.fetch_asset(kernel_url,
|
||||||
kernel_sha1 = '2036c2792f80ac9c4ccaae742b2e0a28385b6010'
|
asset_hash=kernel_sha256,
|
||||||
kernel_deb = self.fetch_asset(kernel_url, asset_hash=kernel_sha1)
|
algorithm = "sha256")
|
||||||
kernel_path = self.extract_from_deb(kernel_deb,
|
|
||||||
"/boot/vmlinuz-4.19.0-12-arm64")
|
|
||||||
return kernel_path
|
return kernel_path
|
||||||
|
|
||||||
def test_aarch64_virt_insn(self):
|
def test_aarch64_virt_insn(self):
|
||||||
|
@ -88,6 +86,10 @@ class PluginKernelNormal(PluginKernelBase):
|
||||||
m = re.search(br"insns: (?P<count>\d+)", s)
|
m = re.search(br"insns: (?P<count>\d+)", s)
|
||||||
if "count" not in m.groupdict():
|
if "count" not in m.groupdict():
|
||||||
self.fail("Failed to find instruction count")
|
self.fail("Failed to find instruction count")
|
||||||
|
else:
|
||||||
|
count = int(m.group("count"))
|
||||||
|
self.log.info(f"Counted: {count} instructions")
|
||||||
|
|
||||||
|
|
||||||
def test_aarch64_virt_insn_icount(self):
|
def test_aarch64_virt_insn_icount(self):
|
||||||
"""
|
"""
|
||||||
|
@ -111,9 +113,13 @@ class PluginKernelNormal(PluginKernelBase):
|
||||||
|
|
||||||
with plugin_log as lf, \
|
with plugin_log as lf, \
|
||||||
mmap.mmap(lf.fileno(), 0, access=mmap.ACCESS_READ) as s:
|
mmap.mmap(lf.fileno(), 0, access=mmap.ACCESS_READ) as s:
|
||||||
m = re.search(br"detected repeat execution @ (?P<addr>0x[0-9A-Fa-f]+)", s)
|
|
||||||
if m is not None and "addr" in m.groupdict():
|
m = re.search(br"insns: (?P<count>\d+)", s)
|
||||||
self.fail("detected repeated instructions")
|
if "count" not in m.groupdict():
|
||||||
|
self.fail("Failed to find instruction count")
|
||||||
|
else:
|
||||||
|
count = int(m.group("count"))
|
||||||
|
self.log.info(f"Counted: {count} instructions")
|
||||||
|
|
||||||
def test_aarch64_virt_mem_icount(self):
|
def test_aarch64_virt_mem_icount(self):
|
||||||
"""
|
"""
|
||||||
|
@ -145,3 +151,5 @@ class PluginKernelNormal(PluginKernelBase):
|
||||||
callback = int(m[1])
|
callback = int(m[1])
|
||||||
if inline != callback:
|
if inline != callback:
|
||||||
self.fail("mismatched access counts")
|
self.fail("mismatched access counts")
|
||||||
|
else:
|
||||||
|
self.log.info(f"Counted {inline} memory accesses")
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
t = []
|
t = []
|
||||||
if get_option('plugins')
|
if get_option('plugins')
|
||||||
foreach i : ['bb', 'empty', 'insn', 'mem', 'syscall']
|
foreach i : ['bb', 'empty', 'insn', 'mem', 'syscall']
|
||||||
t += shared_module(i, files(i + '.c'),
|
if targetos == 'windows'
|
||||||
include_directories: '../../include/qemu',
|
t += shared_module(i, files(i + '.c') + '../../contrib/plugins/win32_linker.c',
|
||||||
dependencies: glib)
|
include_directories: '../../include/qemu',
|
||||||
|
objects: [win32_qemu_plugin_api_lib],
|
||||||
|
dependencies: glib)
|
||||||
|
|
||||||
|
else
|
||||||
|
t += shared_module(i, files(i + '.c'),
|
||||||
|
include_directories: '../../include/qemu',
|
||||||
|
dependencies: glib)
|
||||||
|
endif
|
||||||
endforeach
|
endforeach
|
||||||
endif
|
endif
|
||||||
if t.length() > 0
|
if t.length() > 0
|
||||||
|
|
|
@ -93,12 +93,21 @@ run-gdbstub-thread-breakpoint: testthread
|
||||||
--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
|
--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
|
||||||
--bin $< --test $(MULTIARCH_SRC)/gdbstub/test-thread-breakpoint.py, \
|
--bin $< --test $(MULTIARCH_SRC)/gdbstub/test-thread-breakpoint.py, \
|
||||||
hitting a breakpoint on non-main thread)
|
hitting a breakpoint on non-main thread)
|
||||||
|
|
||||||
|
run-gdbstub-registers: sha512
|
||||||
|
$(call run-test, $@, $(GDB_SCRIPT) \
|
||||||
|
--gdb $(GDB) \
|
||||||
|
--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
|
||||||
|
--bin $< --test $(MULTIARCH_SRC)/gdbstub/registers.py, \
|
||||||
|
checking register enumeration)
|
||||||
|
|
||||||
else
|
else
|
||||||
run-gdbstub-%:
|
run-gdbstub-%:
|
||||||
$(call skip-test, "gdbstub test $*", "need working gdb with $(patsubst -%,,$(TARGET_NAME)) support")
|
$(call skip-test, "gdbstub test $*", "need working gdb with $(patsubst -%,,$(TARGET_NAME)) support")
|
||||||
endif
|
endif
|
||||||
EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read \
|
EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read \
|
||||||
run-gdbstub-proc-mappings run-gdbstub-thread-breakpoint
|
run-gdbstub-proc-mappings run-gdbstub-thread-breakpoint \
|
||||||
|
run-gdbstub-registers
|
||||||
|
|
||||||
# ARM Compatible Semi Hosting Tests
|
# ARM Compatible Semi Hosting Tests
|
||||||
#
|
#
|
||||||
|
|
|
@ -0,0 +1,197 @@
|
||||||
|
# Exercise the register functionality by exhaustively iterating
|
||||||
|
# through all supported registers on the system.
|
||||||
|
#
|
||||||
|
# This is launched via tests/guest-debug/run-test.py but you can also
|
||||||
|
# call it directly if using it for debugging/introspection:
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
import sys
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
initial_vlen = 0
|
||||||
|
failcount = 0
|
||||||
|
|
||||||
|
def report(cond, msg):
|
||||||
|
"Report success/fail of test."
|
||||||
|
if cond:
|
||||||
|
print("PASS: %s" % (msg))
|
||||||
|
else:
|
||||||
|
print("FAIL: %s" % (msg))
|
||||||
|
global failcount
|
||||||
|
failcount += 1
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_xml_regmap():
|
||||||
|
"""
|
||||||
|
Iterate through the XML descriptions and validate.
|
||||||
|
|
||||||
|
We check for any duplicate registers and report them. Return a
|
||||||
|
reg_map hash containing the names, regnums and initial values of
|
||||||
|
all registers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# First check the XML descriptions we have sent. Most arches
|
||||||
|
# support XML but a few of the ancient ones don't in which case we
|
||||||
|
# need to gracefully fail.
|
||||||
|
|
||||||
|
try:
|
||||||
|
xml = gdb.execute("maint print xml-tdesc", False, True)
|
||||||
|
except (gdb.error):
|
||||||
|
print("SKIP: target does not support XML")
|
||||||
|
return None
|
||||||
|
|
||||||
|
total_regs = 0
|
||||||
|
reg_map = {}
|
||||||
|
frame = gdb.selected_frame()
|
||||||
|
|
||||||
|
tree = ET.fromstring(xml)
|
||||||
|
for f in tree.findall("feature"):
|
||||||
|
name = f.attrib["name"]
|
||||||
|
regs = f.findall("reg")
|
||||||
|
|
||||||
|
total = len(regs)
|
||||||
|
total_regs += total
|
||||||
|
base = int(regs[0].attrib["regnum"])
|
||||||
|
top = int(regs[-1].attrib["regnum"])
|
||||||
|
|
||||||
|
print(f"feature: {name} has {total} registers from {base} to {top}")
|
||||||
|
|
||||||
|
for r in regs:
|
||||||
|
name = r.attrib["name"]
|
||||||
|
regnum = int(r.attrib["regnum"])
|
||||||
|
try:
|
||||||
|
value = frame.read_register(name)
|
||||||
|
except ValueError:
|
||||||
|
report(False, f"failed to read reg: {name}")
|
||||||
|
|
||||||
|
entry = { "name": name, "initial": value, "regnum": regnum }
|
||||||
|
|
||||||
|
if name in reg_map:
|
||||||
|
report(False, f"duplicate register {entry} vs {reg_map[name]}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
reg_map[name] = entry
|
||||||
|
|
||||||
|
# Validate we match
|
||||||
|
report(total_regs == len(reg_map.keys()),
|
||||||
|
f"counted all {total_regs} registers in XML")
|
||||||
|
|
||||||
|
return reg_map
|
||||||
|
|
||||||
|
def crosscheck_remote_xml(reg_map):
|
||||||
|
"""
|
||||||
|
Cross-check the list of remote-registers with the XML info.
|
||||||
|
"""
|
||||||
|
|
||||||
|
remote = gdb.execute("maint print remote-registers", False, True)
|
||||||
|
r_regs = remote.split("\n")
|
||||||
|
|
||||||
|
total_regs = len(reg_map.keys())
|
||||||
|
total_r_regs = 0
|
||||||
|
|
||||||
|
for r in r_regs:
|
||||||
|
fields = r.split()
|
||||||
|
# Some of the registers reported here are "pseudo" registers that
|
||||||
|
# gdb invents based on actual registers so we need to filter them
|
||||||
|
# out.
|
||||||
|
if len(fields) == 8:
|
||||||
|
r_name = fields[0]
|
||||||
|
r_regnum = int(fields[6])
|
||||||
|
|
||||||
|
# check in the XML
|
||||||
|
try:
|
||||||
|
x_reg = reg_map[r_name]
|
||||||
|
except KeyError:
|
||||||
|
report(False, f"{r_name} not in XML description")
|
||||||
|
continue
|
||||||
|
|
||||||
|
x_reg["seen"] = True
|
||||||
|
x_regnum = x_reg["regnum"]
|
||||||
|
if r_regnum != x_regnum:
|
||||||
|
report(False, f"{r_name} {r_regnum} == {x_regnum} (xml)")
|
||||||
|
else:
|
||||||
|
total_r_regs += 1
|
||||||
|
|
||||||
|
# Just print a mismatch in totals as gdb will filter out 64 bit
|
||||||
|
# registers on a 32 bit machine. Also print what is missing to
|
||||||
|
# help with debug.
|
||||||
|
if total_regs != total_r_regs:
|
||||||
|
print(f"xml-tdesc has ({total_regs}) registers")
|
||||||
|
print(f"remote-registers has ({total_r_regs}) registers")
|
||||||
|
|
||||||
|
for x_key in reg_map.keys():
|
||||||
|
x_reg = reg_map[x_key]
|
||||||
|
if "seen" not in x_reg:
|
||||||
|
print(f"{x_reg} wasn't seen in remote-registers")
|
||||||
|
|
||||||
|
def complete_and_diff(reg_map):
|
||||||
|
"""
|
||||||
|
Let the program run to (almost) completion and then iterate
|
||||||
|
through all the registers we know about and report which ones have
|
||||||
|
changed.
|
||||||
|
"""
|
||||||
|
# Let the program get to the end and we can check what changed
|
||||||
|
b = gdb.Breakpoint("_exit")
|
||||||
|
if b.pending: # workaround Microblaze weirdness
|
||||||
|
b.delete()
|
||||||
|
gdb.Breakpoint("_Exit")
|
||||||
|
|
||||||
|
gdb.execute("continue")
|
||||||
|
|
||||||
|
frame = gdb.selected_frame()
|
||||||
|
changed = 0
|
||||||
|
|
||||||
|
for e in reg_map.values():
|
||||||
|
name = e["name"]
|
||||||
|
old_val = e["initial"]
|
||||||
|
|
||||||
|
try:
|
||||||
|
new_val = frame.read_register(name)
|
||||||
|
except:
|
||||||
|
report(False, f"failed to read {name} at end of run")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if new_val != old_val:
|
||||||
|
print(f"{name} changes from {old_val} to {new_val}")
|
||||||
|
changed += 1
|
||||||
|
|
||||||
|
# as long as something changed we can be confident its working
|
||||||
|
report(changed > 0, f"{changed} registers were changed")
|
||||||
|
|
||||||
|
|
||||||
|
def run_test():
|
||||||
|
"Run through the tests"
|
||||||
|
|
||||||
|
reg_map = fetch_xml_regmap()
|
||||||
|
|
||||||
|
if reg_map is not None:
|
||||||
|
crosscheck_remote_xml(reg_map)
|
||||||
|
complete_and_diff(reg_map)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# This runs as the script it sourced (via -x, via run-test.py)
|
||||||
|
#
|
||||||
|
try:
|
||||||
|
inferior = gdb.selected_inferior()
|
||||||
|
arch = inferior.architecture()
|
||||||
|
print("ATTACHED: %s" % arch.name())
|
||||||
|
except (gdb.error, AttributeError):
|
||||||
|
print("SKIPPING (not connected)", file=sys.stderr)
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
if gdb.parse_and_eval('$pc') == 0:
|
||||||
|
print("SKIP: PC not set")
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
try:
|
||||||
|
run_test()
|
||||||
|
except (gdb.error):
|
||||||
|
print ("GDB Exception: %s" % (sys.exc_info()[0]))
|
||||||
|
failcount += 1
|
||||||
|
pass
|
||||||
|
|
||||||
|
print("All tests complete: %d failures" % failcount)
|
||||||
|
exit(failcount)
|
|
@ -48,9 +48,20 @@ run-gdbstub-untimely-packet: hello
|
||||||
$(call quiet-command, \
|
$(call quiet-command, \
|
||||||
(! grep -Fq 'Packet instead of Ack, ignoring it' untimely-packet.gdb.err), \
|
(! grep -Fq 'Packet instead of Ack, ignoring it' untimely-packet.gdb.err), \
|
||||||
"GREP", file untimely-packet.gdb.err)
|
"GREP", file untimely-packet.gdb.err)
|
||||||
|
|
||||||
|
run-gdbstub-registers: memory
|
||||||
|
$(call run-test, $@, $(GDB_SCRIPT) \
|
||||||
|
--gdb $(GDB) \
|
||||||
|
--qemu $(QEMU) \
|
||||||
|
--output $<.registers.gdb.out \
|
||||||
|
--qargs \
|
||||||
|
"-monitor none -display none -chardev file$(COMMA)path=$<.out$(COMMA)id=output $(QEMU_OPTS)" \
|
||||||
|
--bin $< --test $(MULTIARCH_SRC)/gdbstub/registers.py, \
|
||||||
|
softmmu gdbstub support)
|
||||||
else
|
else
|
||||||
run-gdbstub-%:
|
run-gdbstub-%:
|
||||||
$(call skip-test, "gdbstub test $*", "need working gdb with $(patsubst -%,,$(TARGET_NAME)) support")
|
$(call skip-test, "gdbstub test $*", "need working gdb with $(patsubst -%,,$(TARGET_NAME)) support")
|
||||||
endif
|
endif
|
||||||
|
|
||||||
MULTIARCH_RUNS += run-gdbstub-memory run-gdbstub-interrupt run-gdbstub-untimely-packet
|
MULTIARCH_RUNS += run-gdbstub-memory run-gdbstub-interrupt \
|
||||||
|
run-gdbstub-untimely-packet run-gdbstub-registers
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
# nios2 specific test tweaks
|
||||||
|
|
||||||
|
# Currently nios2 signal handling is broken
|
||||||
|
run-signals: signals
|
||||||
|
$(call skip-test, $<, "BROKEN")
|
||||||
|
run-plugin-signals-with-%:
|
||||||
|
$(call skip-test, $<, "BROKEN")
|
||||||
|
run-linux-test: linux-test
|
||||||
|
$(call skip-test, $<, "BROKEN")
|
||||||
|
run-plugin-linux-test-with-%:
|
||||||
|
$(call skip-test, $<, "BROKEN")
|
|
@ -38,4 +38,11 @@ PPC64_TESTS += signal_save_restore_xer
|
||||||
PPC64_TESTS += xxspltw
|
PPC64_TESTS += xxspltw
|
||||||
PPC64_TESTS += test-aes
|
PPC64_TESTS += test-aes
|
||||||
|
|
||||||
|
ifneq ($(GDB),)
|
||||||
|
# Skip for now until vsx registers sorted out
|
||||||
|
run-gdbstub-registers:
|
||||||
|
$(call skip-test, $<, "BROKEN reading VSX registers")
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
TESTS += $(PPC64_TESTS)
|
TESTS += $(PPC64_TESTS)
|
||||||
|
|
|
@ -103,6 +103,10 @@ run-gdbstub-svc: hello-s390x-asm
|
||||||
--bin $< --test $(S390X_SRC)/gdbstub/test-svc.py, \
|
--bin $< --test $(S390X_SRC)/gdbstub/test-svc.py, \
|
||||||
single-stepping svc)
|
single-stepping svc)
|
||||||
|
|
||||||
|
# Skip for now until vx registers sorted out
|
||||||
|
run-gdbstub-registers:
|
||||||
|
$(call skip-test, $<, "BROKEN reading VX registers")
|
||||||
|
|
||||||
EXTRA_RUNS += run-gdbstub-signals-s390x run-gdbstub-svc
|
EXTRA_RUNS += run-gdbstub-signals-s390x run-gdbstub-svc
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue