mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-03 07:43:54 -06:00
Maintainer updates for testing, gdbstub, semihosting, plugins
- bump python in *BSD images via libvirt-ci - remove old unused Leon3 Avocado test - re-factor gdb command extension - add stoptrigger plugin to contrib - ensure plugin mem callbacks properly sized - reduce check-tcg noise of inline plugin test - fix register dumping in execlog plugin - restrict semihosting to TCG builds - fix regex in MTE test -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmae5OcACgkQ+9DbCVqe KkR8cgf/eM2Sm7EG7zIQ8SbY53DS07ls6uT7Mfn4374GEmj4Cy1I+WNoLGM5vq1r qWAC9q2LgJVMQoWJA6Fi3SCKiylBp3/jIdJ7CWN5qj/NmePHSV3EisQXf2qOWWL9 qOX2hJI7IIYNI2v3IvCzN/fB8F8U60iXERFHRypBH2p6Mz+EGMC3CEhesOEUta6o 2IMkRW8MoDv9x4B+FnNYav6CfqZjhRenu1CGgVGvWYRds2QDVNB/14kOunmBuwSs gPb7AhhnpobDYVxMarlJNPMbOdFjtDkYCajCNW7ffLcl+OjhoVR6cJcFpbOMv4kZ 8Nok8aDjUDWwUbmU0rBynca+1k8OTg== =TjRc -----END PGP SIGNATURE----- Merge tag 'pull-maintainer-9.1-rc0-230724-1' of https://gitlab.com/stsquad/qemu into staging Maintainer updates for testing, gdbstub, semihosting, plugins - bump python in *BSD images via libvirt-ci - remove old unused Leon3 Avocado test - re-factor gdb command extension - add stoptrigger plugin to contrib - ensure plugin mem callbacks properly sized - reduce check-tcg noise of inline plugin test - fix register dumping in execlog plugin - restrict semihosting to TCG builds - fix regex in MTE test # -----BEGIN PGP SIGNATURE----- # # iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmae5OcACgkQ+9DbCVqe # KkR8cgf/eM2Sm7EG7zIQ8SbY53DS07ls6uT7Mfn4374GEmj4Cy1I+WNoLGM5vq1r # qWAC9q2LgJVMQoWJA6Fi3SCKiylBp3/jIdJ7CWN5qj/NmePHSV3EisQXf2qOWWL9 # qOX2hJI7IIYNI2v3IvCzN/fB8F8U60iXERFHRypBH2p6Mz+EGMC3CEhesOEUta6o # 2IMkRW8MoDv9x4B+FnNYav6CfqZjhRenu1CGgVGvWYRds2QDVNB/14kOunmBuwSs # gPb7AhhnpobDYVxMarlJNPMbOdFjtDkYCajCNW7ffLcl+OjhoVR6cJcFpbOMv4kZ # 8Nok8aDjUDWwUbmU0rBynca+1k8OTg== # =TjRc # -----END PGP SIGNATURE----- # gpg: Signature made Tue 23 Jul 2024 09:01:59 AM AEST # gpg: using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44 # gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" [full] * tag 'pull-maintainer-9.1-rc0-230724-1' of https://gitlab.com/stsquad/qemu: tests/tcg/aarch64: Fix test-mte.py semihosting: Restrict to TCG target/xtensa: Restrict semihosting to TCG target/riscv: Restrict semihosting to TCG target/mips: Restrict semihosting to TCG target/m68k: Restrict semihosting to TCG target/mips: Add semihosting stub target/m68k: Add semihosting stub semihosting: Include missing 'gdbstub/syscalls.h' header plugins/execlog.c: correct dump of registers values tests/plugins: use qemu_plugin_outs for inline stats plugins: fix mem callback array size plugins/stoptrigger: TCG plugin to stop execution under conditions gdbstub: Re-factor gdb command extensions tests/avocado: Remove non-working sparc leon3 test testing: bump to latest libvirt-ci Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
26b09663a9
27 changed files with 370 additions and 170 deletions
|
@ -11,6 +11,6 @@ MAKE='/usr/local/bin/gmake'
|
||||||
NINJA='/usr/local/bin/ninja'
|
NINJA='/usr/local/bin/ninja'
|
||||||
PACKAGING_COMMAND='pkg'
|
PACKAGING_COMMAND='pkg'
|
||||||
PIP3='/usr/local/bin/pip-3.8'
|
PIP3='/usr/local/bin/pip-3.8'
|
||||||
PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson mtools ncurses nettle ninja opencv pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-tomli py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio socat spice-protocol tesseract usbredir virglrenderer vte3 xorriso zstd'
|
PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson mtools ncurses nettle ninja opencv pixman pkgconf png py311-numpy py311-pillow py311-pip py311-sphinx py311-sphinx_rtd_theme py311-tomli py311-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio socat spice-protocol tesseract usbredir virglrenderer vte3 xorriso zstd'
|
||||||
PYPI_PKGS=''
|
PYPI_PKGS=''
|
||||||
PYTHON='/usr/local/bin/python3'
|
PYTHON='/usr/local/bin/python3'
|
||||||
|
|
|
@ -1727,7 +1727,6 @@ S: Maintained
|
||||||
F: hw/sparc/leon3.c
|
F: hw/sparc/leon3.c
|
||||||
F: hw/*/grlib*
|
F: hw/*/grlib*
|
||||||
F: include/hw/*/grlib*
|
F: include/hw/*/grlib*
|
||||||
F: tests/avocado/machine_sparc_leon3.py
|
|
||||||
|
|
||||||
S390 Machines
|
S390 Machines
|
||||||
-------------
|
-------------
|
||||||
|
|
|
@ -85,8 +85,7 @@ static void gen_enable_mem_helper(struct qemu_plugin_tb *ptb,
|
||||||
len = insn->mem_cbs->len;
|
len = insn->mem_cbs->len;
|
||||||
arr = g_array_sized_new(false, false,
|
arr = g_array_sized_new(false, false,
|
||||||
sizeof(struct qemu_plugin_dyn_cb), len);
|
sizeof(struct qemu_plugin_dyn_cb), len);
|
||||||
memcpy(arr->data, insn->mem_cbs->data,
|
g_array_append_vals(arr, insn->mem_cbs->data, len);
|
||||||
len * sizeof(struct qemu_plugin_dyn_cb));
|
|
||||||
qemu_plugin_add_dyn_cb_arr(arr);
|
qemu_plugin_add_dyn_cb_arr(arr);
|
||||||
|
|
||||||
tcg_gen_st_ptr(tcg_constant_ptr((intptr_t)arr), tcg_env,
|
tcg_gen_st_ptr(tcg_constant_ptr((intptr_t)arr), tcg_env,
|
||||||
|
|
|
@ -28,6 +28,7 @@ NAMES += hwprofile
|
||||||
NAMES += cache
|
NAMES += cache
|
||||||
NAMES += drcov
|
NAMES += drcov
|
||||||
NAMES += ips
|
NAMES += ips
|
||||||
|
NAMES += stoptrigger
|
||||||
|
|
||||||
ifeq ($(CONFIG_WIN32),y)
|
ifeq ($(CONFIG_WIN32),y)
|
||||||
SO_SUFFIX := .dll
|
SO_SUFFIX := .dll
|
||||||
|
|
|
@ -101,7 +101,7 @@ static void insn_check_regs(CPU *cpu)
|
||||||
GByteArray *temp = reg->last;
|
GByteArray *temp = reg->last;
|
||||||
g_string_append_printf(cpu->last_exec, ", %s -> 0x", reg->name);
|
g_string_append_printf(cpu->last_exec, ", %s -> 0x", reg->name);
|
||||||
/* TODO: handle BE properly */
|
/* TODO: handle BE properly */
|
||||||
for (int i = sz; i >= 0; i--) {
|
for (int i = sz - 1; i >= 0; i--) {
|
||||||
g_string_append_printf(cpu->last_exec, "%02x",
|
g_string_append_printf(cpu->last_exec, "%02x",
|
||||||
reg->new->data[i]);
|
reg->new->data[i]);
|
||||||
}
|
}
|
||||||
|
|
151
contrib/plugins/stoptrigger.c
Normal file
151
contrib/plugins/stoptrigger.c
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024, Simon Hamelin <simon.hamelin@grenoble-inp.org>
|
||||||
|
*
|
||||||
|
* Stop execution once a given address is reached or if the
|
||||||
|
* count of executed instructions reached a specified limit
|
||||||
|
*
|
||||||
|
* License: GNU GPL, version 2 or later.
|
||||||
|
* See the COPYING file in the top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <glib.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <qemu-plugin.h>
|
||||||
|
|
||||||
|
QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
|
||||||
|
|
||||||
|
/* Scoreboard to track executed instructions count */
|
||||||
|
typedef struct {
|
||||||
|
uint64_t insn_count;
|
||||||
|
} InstructionsCount;
|
||||||
|
static struct qemu_plugin_scoreboard *insn_count_sb;
|
||||||
|
static qemu_plugin_u64 insn_count;
|
||||||
|
|
||||||
|
static uint64_t icount;
|
||||||
|
static int icount_exit_code;
|
||||||
|
|
||||||
|
static bool exit_on_icount;
|
||||||
|
static bool exit_on_address;
|
||||||
|
|
||||||
|
/* Map trigger addresses to exit code */
|
||||||
|
static GHashTable *addrs_ht;
|
||||||
|
|
||||||
|
static void exit_emulation(int return_code, char *message)
|
||||||
|
{
|
||||||
|
qemu_plugin_outs(message);
|
||||||
|
g_free(message);
|
||||||
|
exit(return_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exit_icount_reached(unsigned int cpu_index, void *udata)
|
||||||
|
{
|
||||||
|
uint64_t insn_vaddr = GPOINTER_TO_UINT(udata);
|
||||||
|
char *msg = g_strdup_printf("icount reached at 0x%" PRIx64 ", exiting\n",
|
||||||
|
insn_vaddr);
|
||||||
|
|
||||||
|
exit_emulation(icount_exit_code, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exit_address_reached(unsigned int cpu_index, void *udata)
|
||||||
|
{
|
||||||
|
uint64_t insn_vaddr = GPOINTER_TO_UINT(udata);
|
||||||
|
char *msg = g_strdup_printf("0x%" PRIx64 " reached, exiting\n", insn_vaddr);
|
||||||
|
int exit_code;
|
||||||
|
|
||||||
|
exit_code = GPOINTER_TO_INT(
|
||||||
|
g_hash_table_lookup(addrs_ht, GUINT_TO_POINTER(insn_vaddr)));
|
||||||
|
|
||||||
|
exit_emulation(exit_code, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
|
||||||
|
{
|
||||||
|
size_t tb_n = qemu_plugin_tb_n_insns(tb);
|
||||||
|
for (size_t i = 0; i < tb_n; i++) {
|
||||||
|
struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
|
||||||
|
gpointer insn_vaddr = GUINT_TO_POINTER(qemu_plugin_insn_vaddr(insn));
|
||||||
|
|
||||||
|
if (exit_on_icount) {
|
||||||
|
/* Increment and check scoreboard for each instruction */
|
||||||
|
qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(
|
||||||
|
insn, QEMU_PLUGIN_INLINE_ADD_U64, insn_count, 1);
|
||||||
|
qemu_plugin_register_vcpu_insn_exec_cond_cb(
|
||||||
|
insn, exit_icount_reached, QEMU_PLUGIN_CB_NO_REGS,
|
||||||
|
QEMU_PLUGIN_COND_EQ, insn_count, icount + 1, insn_vaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exit_on_address) {
|
||||||
|
if (g_hash_table_contains(addrs_ht, insn_vaddr)) {
|
||||||
|
/* Exit triggered by address */
|
||||||
|
qemu_plugin_register_vcpu_insn_exec_cb(
|
||||||
|
insn, exit_address_reached, QEMU_PLUGIN_CB_NO_REGS,
|
||||||
|
insn_vaddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void plugin_exit(qemu_plugin_id_t id, void *p)
|
||||||
|
{
|
||||||
|
g_hash_table_destroy(addrs_ht);
|
||||||
|
qemu_plugin_scoreboard_free(insn_count_sb);
|
||||||
|
}
|
||||||
|
|
||||||
|
QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
||||||
|
const qemu_info_t *info, int argc,
|
||||||
|
char **argv)
|
||||||
|
{
|
||||||
|
addrs_ht = g_hash_table_new(NULL, g_direct_equal);
|
||||||
|
|
||||||
|
insn_count_sb = qemu_plugin_scoreboard_new(sizeof(InstructionsCount));
|
||||||
|
insn_count = qemu_plugin_scoreboard_u64_in_struct(
|
||||||
|
insn_count_sb, InstructionsCount, insn_count);
|
||||||
|
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
char *opt = argv[i];
|
||||||
|
g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
|
||||||
|
if (g_strcmp0(tokens[0], "icount") == 0) {
|
||||||
|
g_auto(GStrv) icount_tokens = g_strsplit(tokens[1], ":", 2);
|
||||||
|
icount = g_ascii_strtoull(icount_tokens[0], NULL, 0);
|
||||||
|
if (icount < 1 || g_strrstr(icount_tokens[0], "-") != NULL) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"icount parsing failed: '%s' must be a positive "
|
||||||
|
"integer\n",
|
||||||
|
icount_tokens[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (icount_tokens[1]) {
|
||||||
|
icount_exit_code = g_ascii_strtoull(icount_tokens[1], NULL, 0);
|
||||||
|
}
|
||||||
|
exit_on_icount = true;
|
||||||
|
} else if (g_strcmp0(tokens[0], "addr") == 0) {
|
||||||
|
g_auto(GStrv) addr_tokens = g_strsplit(tokens[1], ":", 2);
|
||||||
|
uint64_t exit_addr = g_ascii_strtoull(addr_tokens[0], NULL, 0);
|
||||||
|
int exit_code = 0;
|
||||||
|
if (addr_tokens[1]) {
|
||||||
|
exit_code = g_ascii_strtoull(addr_tokens[1], NULL, 0);
|
||||||
|
}
|
||||||
|
g_hash_table_insert(addrs_ht, GUINT_TO_POINTER(exit_addr),
|
||||||
|
GINT_TO_POINTER(exit_code));
|
||||||
|
exit_on_address = true;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "option parsing failed: %s\n", opt);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!exit_on_icount && !exit_on_address) {
|
||||||
|
fprintf(stderr, "'icount' or 'addr' argument missing\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register translation block and exit callbacks */
|
||||||
|
qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
|
||||||
|
qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -642,6 +642,28 @@ The plugin has a number of arguments, all of them are optional:
|
||||||
configuration arguments implies ``l2=on``.
|
configuration arguments implies ``l2=on``.
|
||||||
(default: N = 2097152 (2MB), B = 64, A = 16)
|
(default: N = 2097152 (2MB), B = 64, A = 16)
|
||||||
|
|
||||||
|
- contrib/plugins/stoptrigger.c
|
||||||
|
|
||||||
|
The stoptrigger plugin allows to setup triggers to stop emulation.
|
||||||
|
It can be used for research purposes to launch some code and precisely stop it
|
||||||
|
and understand where its execution flow went.
|
||||||
|
|
||||||
|
Two types of triggers can be configured: a count of instructions to stop at,
|
||||||
|
or an address to stop at. Multiple triggers can be set at once.
|
||||||
|
|
||||||
|
By default, QEMU will exit with return code 0. A custom return code can be
|
||||||
|
configured for each trigger using ``:CODE`` syntax.
|
||||||
|
|
||||||
|
For example, to stop at the 20-th instruction with return code 41, at address
|
||||||
|
0xd4 with return code 0 or at address 0xd8 with return code 42::
|
||||||
|
|
||||||
|
$ qemu-system-aarch64 $(QEMU_ARGS) \
|
||||||
|
-plugin ./contrib/plugins/libstoptrigger.so,icount=20:41,addr=0xd4,addr=0xd8:42 -d plugin
|
||||||
|
|
||||||
|
The plugin will log the reason of exit, for example::
|
||||||
|
|
||||||
|
0xd4 reached, exiting
|
||||||
|
|
||||||
Plugin API
|
Plugin API
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
|
|
@ -1614,18 +1614,21 @@ static void handle_query_thread_extra(GArray *params, void *user_ctx)
|
||||||
gdb_put_strbuf();
|
gdb_put_strbuf();
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *extended_qsupported_features;
|
|
||||||
void gdb_extend_qsupported_features(char *qsupported_features)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We don't support different sets of CPU gdb features on different CPUs yet
|
|
||||||
* so assert the feature strings are the same on all CPUs, or is set only
|
|
||||||
* once (1 CPU).
|
|
||||||
*/
|
|
||||||
g_assert(extended_qsupported_features == NULL ||
|
|
||||||
g_strcmp0(extended_qsupported_features, qsupported_features) == 0);
|
|
||||||
|
|
||||||
extended_qsupported_features = qsupported_features;
|
static char **extra_query_flags;
|
||||||
|
|
||||||
|
void gdb_extend_qsupported_features(char *qflags)
|
||||||
|
{
|
||||||
|
if (!extra_query_flags) {
|
||||||
|
extra_query_flags = g_new0(char *, 2);
|
||||||
|
extra_query_flags[0] = g_strdup(qflags);
|
||||||
|
} else if (!g_strv_contains((const gchar * const *) extra_query_flags,
|
||||||
|
qflags)) {
|
||||||
|
int len = g_strv_length(extra_query_flags);
|
||||||
|
extra_query_flags = g_realloc_n(extra_query_flags, len + 2,
|
||||||
|
sizeof(char *));
|
||||||
|
extra_query_flags[len] = g_strdup(qflags);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_query_supported(GArray *params, void *user_ctx)
|
static void handle_query_supported(GArray *params, void *user_ctx)
|
||||||
|
@ -1668,8 +1671,11 @@ static void handle_query_supported(GArray *params, void *user_ctx)
|
||||||
|
|
||||||
g_string_append(gdbserver_state.str_buf, ";vContSupported+;multiprocess+");
|
g_string_append(gdbserver_state.str_buf, ";vContSupported+;multiprocess+");
|
||||||
|
|
||||||
if (extended_qsupported_features) {
|
if (extra_query_flags) {
|
||||||
g_string_append(gdbserver_state.str_buf, extended_qsupported_features);
|
int extras = g_strv_length(extra_query_flags);
|
||||||
|
for (int i = 0; i < extras; i++) {
|
||||||
|
g_string_append(gdbserver_state.str_buf, extra_query_flags[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gdb_put_strbuf();
|
gdb_put_strbuf();
|
||||||
|
@ -1753,39 +1759,58 @@ static const GdbCmdParseEntry gdb_gen_query_set_common_table[] = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Compares if a set of command parsers is equal to another set of parsers. */
|
/**
|
||||||
static bool cmp_cmds(GdbCmdParseEntry *c, GdbCmdParseEntry *d, int size)
|
* extend_table() - extend one of the command tables
|
||||||
|
* @table: the command table to extend (or NULL)
|
||||||
|
* @extensions: a list of GdbCmdParseEntry pointers
|
||||||
|
*
|
||||||
|
* The entries themselves should be pointers to static const
|
||||||
|
* GdbCmdParseEntry entries. If the entry is already in the table we
|
||||||
|
* skip adding it again.
|
||||||
|
*
|
||||||
|
* Returns (a potentially freshly allocated) GPtrArray of GdbCmdParseEntry
|
||||||
|
*/
|
||||||
|
static GPtrArray *extend_table(GPtrArray *table, GPtrArray *extensions)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < size; i++) {
|
if (!table) {
|
||||||
if (!(c[i].handler == d[i].handler &&
|
table = g_ptr_array_new();
|
||||||
g_strcmp0(c[i].cmd, d[i].cmd) == 0 &&
|
}
|
||||||
c[i].cmd_startswith == d[i].cmd_startswith &&
|
|
||||||
g_strcmp0(c[i].schema, d[i].schema) == 0)) {
|
|
||||||
|
|
||||||
/* Sets are different. */
|
for (int i = 0; i < extensions->len; i++) {
|
||||||
return false;
|
gpointer entry = g_ptr_array_index(extensions, i);
|
||||||
|
if (!g_ptr_array_find(table, entry, NULL)) {
|
||||||
|
g_ptr_array_add(table, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sets are equal, i.e. contain the same command parsers. */
|
return table;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GdbCmdParseEntry *extended_query_table;
|
/**
|
||||||
static int extended_query_table_size;
|
* process_extended_table() - run through an extended command table
|
||||||
void gdb_extend_query_table(GdbCmdParseEntry *table, int size)
|
* @table: the command table to check
|
||||||
|
* @data: parameters
|
||||||
|
*
|
||||||
|
* returns true if the command was found and executed
|
||||||
|
*/
|
||||||
|
static bool process_extended_table(GPtrArray *table, const char *data)
|
||||||
{
|
{
|
||||||
/*
|
for (int i = 0; i < table->len; i++) {
|
||||||
* We don't support different sets of CPU gdb features on different CPUs yet
|
const GdbCmdParseEntry *entry = g_ptr_array_index(table, i);
|
||||||
* so assert query table is the same on all CPUs, or is set only once
|
if (process_string_cmd(data, entry, 1)) {
|
||||||
* (1 CPU).
|
return true;
|
||||||
*/
|
}
|
||||||
g_assert(extended_query_table == NULL ||
|
}
|
||||||
(extended_query_table_size == size &&
|
return false;
|
||||||
cmp_cmds(extended_query_table, table, size)));
|
}
|
||||||
|
|
||||||
extended_query_table = table;
|
|
||||||
extended_query_table_size = size;
|
/* Ptr to GdbCmdParseEntry */
|
||||||
|
static GPtrArray *extended_query_table;
|
||||||
|
|
||||||
|
void gdb_extend_query_table(GPtrArray *new_queries)
|
||||||
|
{
|
||||||
|
extended_query_table = extend_table(extended_query_table, new_queries);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const GdbCmdParseEntry gdb_gen_query_table[] = {
|
static const GdbCmdParseEntry gdb_gen_query_table[] = {
|
||||||
|
@ -1880,20 +1905,12 @@ static const GdbCmdParseEntry gdb_gen_query_table[] = {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static GdbCmdParseEntry *extended_set_table;
|
/* Ptr to GdbCmdParseEntry */
|
||||||
static int extended_set_table_size;
|
static GPtrArray *extended_set_table;
|
||||||
void gdb_extend_set_table(GdbCmdParseEntry *table, int size)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We don't support different sets of CPU gdb features on different CPUs yet
|
|
||||||
* so assert set table is the same on all CPUs, or is set only once (1 CPU).
|
|
||||||
*/
|
|
||||||
g_assert(extended_set_table == NULL ||
|
|
||||||
(extended_set_table_size == size &&
|
|
||||||
cmp_cmds(extended_set_table, table, size)));
|
|
||||||
|
|
||||||
extended_set_table = table;
|
void gdb_extend_set_table(GPtrArray *new_set)
|
||||||
extended_set_table_size = size;
|
{
|
||||||
|
extended_set_table = extend_table(extended_set_table, new_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const GdbCmdParseEntry gdb_gen_set_table[] = {
|
static const GdbCmdParseEntry gdb_gen_set_table[] = {
|
||||||
|
@ -1924,26 +1941,28 @@ static const GdbCmdParseEntry gdb_gen_set_table[] = {
|
||||||
|
|
||||||
static void handle_gen_query(GArray *params, void *user_ctx)
|
static void handle_gen_query(GArray *params, void *user_ctx)
|
||||||
{
|
{
|
||||||
|
const char *data;
|
||||||
|
|
||||||
if (!params->len) {
|
if (!params->len) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process_string_cmd(gdb_get_cmd_param(params, 0)->data,
|
data = gdb_get_cmd_param(params, 0)->data;
|
||||||
|
|
||||||
|
if (process_string_cmd(data,
|
||||||
gdb_gen_query_set_common_table,
|
gdb_gen_query_set_common_table,
|
||||||
ARRAY_SIZE(gdb_gen_query_set_common_table))) {
|
ARRAY_SIZE(gdb_gen_query_set_common_table))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process_string_cmd(gdb_get_cmd_param(params, 0)->data,
|
if (process_string_cmd(data,
|
||||||
gdb_gen_query_table,
|
gdb_gen_query_table,
|
||||||
ARRAY_SIZE(gdb_gen_query_table))) {
|
ARRAY_SIZE(gdb_gen_query_table))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extended_query_table &&
|
if (extended_query_table &&
|
||||||
process_string_cmd(gdb_get_cmd_param(params, 0)->data,
|
process_extended_table(extended_query_table, data)) {
|
||||||
extended_query_table,
|
|
||||||
extended_query_table_size)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1953,26 +1972,28 @@ static void handle_gen_query(GArray *params, void *user_ctx)
|
||||||
|
|
||||||
static void handle_gen_set(GArray *params, void *user_ctx)
|
static void handle_gen_set(GArray *params, void *user_ctx)
|
||||||
{
|
{
|
||||||
|
const char *data;
|
||||||
|
|
||||||
if (!params->len) {
|
if (!params->len) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process_string_cmd(gdb_get_cmd_param(params, 0)->data,
|
data = gdb_get_cmd_param(params, 0)->data;
|
||||||
|
|
||||||
|
if (process_string_cmd(data,
|
||||||
gdb_gen_query_set_common_table,
|
gdb_gen_query_set_common_table,
|
||||||
ARRAY_SIZE(gdb_gen_query_set_common_table))) {
|
ARRAY_SIZE(gdb_gen_query_set_common_table))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process_string_cmd(gdb_get_cmd_param(params, 0)->data,
|
if (process_string_cmd(data,
|
||||||
gdb_gen_set_table,
|
gdb_gen_set_table,
|
||||||
ARRAY_SIZE(gdb_gen_set_table))) {
|
ARRAY_SIZE(gdb_gen_set_table))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extended_set_table &&
|
if (extended_set_table &&
|
||||||
process_string_cmd(gdb_get_cmd_param(params, 0)->data,
|
process_extended_table(extended_set_table, data)) {
|
||||||
extended_set_table,
|
|
||||||
extended_set_table_size)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,23 +74,28 @@ int gdb_put_packet(const char *buf);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gdb_extend_query_table() - Extend query table.
|
* gdb_extend_query_table() - Extend query table.
|
||||||
* @table: The table with the additional query packet handlers.
|
* @table: GPtrArray of GdbCmdParseEntry entries.
|
||||||
* @size: The number of handlers to be added.
|
*
|
||||||
|
* The caller should free @table afterwards
|
||||||
*/
|
*/
|
||||||
void gdb_extend_query_table(GdbCmdParseEntry *table, int size);
|
void gdb_extend_query_table(GPtrArray *table);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gdb_extend_set_table() - Extend set table.
|
* gdb_extend_set_table() - Extend set table.
|
||||||
* @table: The table with the additional set packet handlers.
|
* @table: GPtrArray of GdbCmdParseEntry entries.
|
||||||
* @size: The number of handlers to be added.
|
*
|
||||||
|
* The caller should free @table afterwards
|
||||||
*/
|
*/
|
||||||
void gdb_extend_set_table(GdbCmdParseEntry *table, int size);
|
void gdb_extend_set_table(GPtrArray *table);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gdb_extend_qsupported_features() - Extend the qSupported features string.
|
* gdb_extend_qsupported_features() - Extend the qSupported features string.
|
||||||
* @qsupported_features: The additional qSupported feature(s) string. The string
|
* @qsupported_features: The additional qSupported feature(s) string. The string
|
||||||
* should start with a semicolon and, if there are more than one feature, the
|
* should start with a semicolon and, if there are more than one feature, the
|
||||||
* features should be separate by a semiocolon.
|
* features should be separate by a semicolon.
|
||||||
|
*
|
||||||
|
* The caller should free @qsupported_features afterwards if
|
||||||
|
* dynamically allocated.
|
||||||
*/
|
*/
|
||||||
void gdb_extend_qsupported_features(char *qsupported_features);
|
void gdb_extend_qsupported_features(char *qsupported_features);
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#ifndef SEMIHOSTING_SYSCALLS_H
|
#ifndef SEMIHOSTING_SYSCALLS_H
|
||||||
#define SEMIHOSTING_SYSCALLS_H
|
#define SEMIHOSTING_SYSCALLS_H
|
||||||
|
|
||||||
|
#include "gdbstub/syscalls.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Argument loading from the guest is performed by the caller;
|
* Argument loading from the guest is performed by the caller;
|
||||||
* results are returned via the 'complete' callback.
|
* results are returned via the 'complete' callback.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
config SEMIHOSTING
|
config SEMIHOSTING
|
||||||
bool
|
bool
|
||||||
|
depends on TCG
|
||||||
|
|
||||||
config ARM_COMPATIBLE_SEMIHOSTING
|
config ARM_COMPATIBLE_SEMIHOSTING
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -477,11 +477,9 @@ static GDBFeature *arm_gen_dynamic_m_secextreg_feature(CPUState *cs,
|
||||||
|
|
||||||
void arm_cpu_register_gdb_commands(ARMCPU *cpu)
|
void arm_cpu_register_gdb_commands(ARMCPU *cpu)
|
||||||
{
|
{
|
||||||
GArray *query_table =
|
g_autoptr(GPtrArray) query_table = g_ptr_array_new();
|
||||||
g_array_new(FALSE, FALSE, sizeof(GdbCmdParseEntry));
|
g_autoptr(GPtrArray) set_table = g_ptr_array_new();
|
||||||
GArray *set_table =
|
g_autoptr(GString) qsupported_features = g_string_new(NULL);
|
||||||
g_array_new(FALSE, FALSE, sizeof(GdbCmdParseEntry));
|
|
||||||
GString *qsupported_features = g_string_new(NULL);
|
|
||||||
|
|
||||||
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
|
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
|
||||||
#ifdef TARGET_AARCH64
|
#ifdef TARGET_AARCH64
|
||||||
|
@ -492,16 +490,12 @@ void arm_cpu_register_gdb_commands(ARMCPU *cpu)
|
||||||
|
|
||||||
/* Set arch-specific handlers for 'q' commands. */
|
/* Set arch-specific handlers for 'q' commands. */
|
||||||
if (query_table->len) {
|
if (query_table->len) {
|
||||||
gdb_extend_query_table(&g_array_index(query_table,
|
gdb_extend_query_table(query_table);
|
||||||
GdbCmdParseEntry, 0),
|
|
||||||
query_table->len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set arch-specific handlers for 'Q' commands. */
|
/* Set arch-specific handlers for 'Q' commands. */
|
||||||
if (set_table->len) {
|
if (set_table->len) {
|
||||||
gdb_extend_set_table(&g_array_index(set_table,
|
gdb_extend_set_table(set_table);
|
||||||
GdbCmdParseEntry, 0),
|
|
||||||
set_table->len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set arch-specific qSupported feature. */
|
/* Set arch-specific qSupported feature. */
|
||||||
|
|
|
@ -564,7 +564,7 @@ enum Command {
|
||||||
NUM_CMDS
|
NUM_CMDS
|
||||||
};
|
};
|
||||||
|
|
||||||
static GdbCmdParseEntry cmd_handler_table[NUM_CMDS] = {
|
static const GdbCmdParseEntry cmd_handler_table[NUM_CMDS] = {
|
||||||
[qMemTags] = {
|
[qMemTags] = {
|
||||||
.handler = handle_q_memtag,
|
.handler = handle_q_memtag,
|
||||||
.cmd_startswith = true,
|
.cmd_startswith = true,
|
||||||
|
@ -590,17 +590,16 @@ static GdbCmdParseEntry cmd_handler_table[NUM_CMDS] = {
|
||||||
#endif /* CONFIG_USER_ONLY */
|
#endif /* CONFIG_USER_ONLY */
|
||||||
|
|
||||||
void aarch64_cpu_register_gdb_commands(ARMCPU *cpu, GString *qsupported,
|
void aarch64_cpu_register_gdb_commands(ARMCPU *cpu, GString *qsupported,
|
||||||
GArray *qtable, GArray *stable)
|
GPtrArray *qtable, GPtrArray *stable)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
/* MTE */
|
/* MTE */
|
||||||
if (cpu_isar_feature(aa64_mte, cpu)) {
|
if (cpu_isar_feature(aa64_mte, cpu)) {
|
||||||
g_string_append(qsupported, ";memory-tagging+");
|
g_string_append(qsupported, ";memory-tagging+");
|
||||||
|
|
||||||
g_array_append_val(qtable, cmd_handler_table[qMemTags]);
|
g_ptr_array_add(qtable, (gpointer) &cmd_handler_table[qMemTags]);
|
||||||
g_array_append_val(qtable, cmd_handler_table[qIsAddressTagged]);
|
g_ptr_array_add(qtable, (gpointer) &cmd_handler_table[qIsAddressTagged]);
|
||||||
|
g_ptr_array_add(stable, (gpointer) &cmd_handler_table[QMemTags]);
|
||||||
g_array_append_val(stable, cmd_handler_table[QMemTags]);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -359,8 +359,8 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu);
|
||||||
void arm_translate_init(void);
|
void arm_translate_init(void);
|
||||||
|
|
||||||
void arm_cpu_register_gdb_commands(ARMCPU *cpu);
|
void arm_cpu_register_gdb_commands(ARMCPU *cpu);
|
||||||
void aarch64_cpu_register_gdb_commands(ARMCPU *cpu, GString *, GArray *,
|
void aarch64_cpu_register_gdb_commands(ARMCPU *cpu, GString *,
|
||||||
GArray *);
|
GPtrArray *, GPtrArray *);
|
||||||
|
|
||||||
void arm_restore_state_to_opc(CPUState *cs,
|
void arm_restore_state_to_opc(CPUState *cs,
|
||||||
const TranslationBlock *tb,
|
const TranslationBlock *tb,
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
config M68K
|
config M68K
|
||||||
bool
|
bool
|
||||||
select SEMIHOSTING
|
imply SEMIHOSTING if TCG
|
||||||
|
|
|
@ -11,9 +11,12 @@ m68k_ss.add(files(
|
||||||
|
|
||||||
m68k_system_ss = ss.source_set()
|
m68k_system_ss = ss.source_set()
|
||||||
m68k_system_ss.add(files(
|
m68k_system_ss.add(files(
|
||||||
'm68k-semi.c',
|
|
||||||
'monitor.c'
|
'monitor.c'
|
||||||
))
|
))
|
||||||
|
m68k_system_ss.add(when: ['CONFIG_SEMIHOSTING'],
|
||||||
|
if_true: files('m68k-semi.c'),
|
||||||
|
if_false: files('semihosting-stub.c')
|
||||||
|
)
|
||||||
|
|
||||||
target_arch += {'m68k': m68k_ss}
|
target_arch += {'m68k': m68k_ss}
|
||||||
target_system_arch += {'m68k': m68k_system_ss}
|
target_system_arch += {'m68k': m68k_system_ss}
|
||||||
|
|
15
target/m68k/semihosting-stub.c
Normal file
15
target/m68k/semihosting-stub.c
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* m68k/ColdFire semihosting stub
|
||||||
|
*
|
||||||
|
* SPDX-FileContributor: Philippe Mathieu-Daudé <philmd@linaro.org>
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linaro Ltd.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "cpu.h"
|
||||||
|
|
||||||
|
void do_m68k_semihosting(CPUM68KState *env, int nr)
|
||||||
|
{
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
config MIPS
|
config MIPS
|
||||||
bool
|
bool
|
||||||
select SEMIHOSTING
|
imply SEMIHOSTING if TCG
|
||||||
|
|
||||||
config MIPS64
|
config MIPS64
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
mips_system_ss.add(files(
|
mips_system_ss.add(files(
|
||||||
'cp0_helper.c',
|
'cp0_helper.c',
|
||||||
'mips-semi.c',
|
|
||||||
'special_helper.c',
|
'special_helper.c',
|
||||||
'tlb_helper.c',
|
'tlb_helper.c',
|
||||||
))
|
))
|
||||||
|
mips_system_ss.add(when: ['CONFIG_SEMIHOSTING'],
|
||||||
|
if_true: files('mips-semi.c'),
|
||||||
|
if_false: files('semihosting-stub.c')
|
||||||
|
)
|
||||||
mips_system_ss.add(when: 'TARGET_MIPS64', if_true: files(
|
mips_system_ss.add(when: 'TARGET_MIPS64', if_true: files(
|
||||||
'lcsr_helper.c',
|
'lcsr_helper.c',
|
||||||
))
|
))
|
||||||
|
|
15
target/mips/tcg/sysemu/semihosting-stub.c
Normal file
15
target/mips/tcg/sysemu/semihosting-stub.c
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* MIPS semihosting stub
|
||||||
|
*
|
||||||
|
* SPDX-FileContributor: Philippe Mathieu-Daudé <philmd@linaro.org>
|
||||||
|
* SPDX-FileCopyrightText: 2024 Linaro Ltd.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
void mips_semihosting(CPUMIPSState *env)
|
||||||
|
{
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
config RISCV32
|
config RISCV32
|
||||||
bool
|
bool
|
||||||
select ARM_COMPATIBLE_SEMIHOSTING # for do_common_semihosting()
|
imply ARM_COMPATIBLE_SEMIHOSTING if TCG
|
||||||
select DEVICE_TREE # needed by boot.c
|
select DEVICE_TREE # needed by boot.c
|
||||||
|
|
||||||
config RISCV64
|
config RISCV64
|
||||||
bool
|
bool
|
||||||
select ARM_COMPATIBLE_SEMIHOSTING # for do_common_semihosting()
|
imply ARM_COMPATIBLE_SEMIHOSTING if TCG
|
||||||
select DEVICE_TREE # needed by boot.c
|
select DEVICE_TREE # needed by boot.c
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
config XTENSA
|
config XTENSA
|
||||||
bool
|
bool
|
||||||
select SEMIHOSTING
|
imply SEMIHOSTING if TCG
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
# Functional test that boots a Leon3 machine and checks its serial console.
|
|
||||||
#
|
|
||||||
# Copyright (c) Philippe Mathieu-Daudé <f4bug@amsat.org>
|
|
||||||
#
|
|
||||||
# This work is licensed under the terms of the GNU GPL, version 2 or
|
|
||||||
# later. See the COPYING file in the top-level directory.
|
|
||||||
|
|
||||||
from avocado_qemu import QemuSystemTest
|
|
||||||
from avocado_qemu import wait_for_console_pattern
|
|
||||||
from avocado import skip
|
|
||||||
|
|
||||||
|
|
||||||
class Leon3Machine(QemuSystemTest):
|
|
||||||
|
|
||||||
timeout = 60
|
|
||||||
|
|
||||||
@skip("Test currently broken")
|
|
||||||
# A Window Underflow exception occurs before booting the kernel,
|
|
||||||
# and QEMU exit calling cpu_abort(), which makes this test to fail.
|
|
||||||
def test_leon3_helenos_uimage(self):
|
|
||||||
"""
|
|
||||||
:avocado: tags=arch:sparc
|
|
||||||
:avocado: tags=machine:leon3_generic
|
|
||||||
:avocado: tags=binfmt:uimage
|
|
||||||
"""
|
|
||||||
kernel_url = ('http://www.helenos.org/releases/'
|
|
||||||
'HelenOS-0.6.0-sparc32-leon3.bin')
|
|
||||||
kernel_hash = 'a88c9cfdb8430c66650e5290a08765f9bf049a30'
|
|
||||||
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
|
|
||||||
|
|
||||||
self.vm.set_console()
|
|
||||||
self.vm.add_args('-kernel', kernel_path)
|
|
||||||
|
|
||||||
self.vm.launch()
|
|
||||||
|
|
||||||
wait_for_console_pattern(self, 'Copyright (c) 2001-2014 HelenOS project')
|
|
||||||
wait_for_console_pattern(self, 'Booting the kernel ...')
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0e9490cebc726ef772b6c9e27dac32e7ae99f9b2
|
Subproject commit 789b4601bce4e01f43fdb6ad4ce5ab4e46674440
|
|
@ -71,10 +71,12 @@ static void stats_insn(void)
|
||||||
const uint64_t cond_track_left = qemu_plugin_u64_sum(insn_cond_track_count);
|
const uint64_t cond_track_left = qemu_plugin_u64_sum(insn_cond_track_count);
|
||||||
const uint64_t conditional =
|
const uint64_t conditional =
|
||||||
cond_num_trigger * cond_trigger_limit + cond_track_left;
|
cond_num_trigger * cond_trigger_limit + cond_track_left;
|
||||||
printf("insn: %" PRIu64 "\n", expected);
|
g_autoptr(GString) stats = g_string_new("");
|
||||||
printf("insn: %" PRIu64 " (per vcpu)\n", per_vcpu);
|
g_string_append_printf(stats, "insn: %" PRIu64 "\n", expected);
|
||||||
printf("insn: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu);
|
g_string_append_printf(stats, "insn: %" PRIu64 " (per vcpu)\n", per_vcpu);
|
||||||
printf("insn: %" PRIu64 " (cond cb)\n", conditional);
|
g_string_append_printf(stats, "insn: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu);
|
||||||
|
g_string_append_printf(stats, "insn: %" PRIu64 " (cond cb)\n", conditional);
|
||||||
|
qemu_plugin_outs(stats->str);
|
||||||
g_assert(expected > 0);
|
g_assert(expected > 0);
|
||||||
g_assert(per_vcpu == expected);
|
g_assert(per_vcpu == expected);
|
||||||
g_assert(inl_per_vcpu == expected);
|
g_assert(inl_per_vcpu == expected);
|
||||||
|
@ -91,10 +93,12 @@ static void stats_tb(void)
|
||||||
const uint64_t cond_track_left = qemu_plugin_u64_sum(tb_cond_track_count);
|
const uint64_t cond_track_left = qemu_plugin_u64_sum(tb_cond_track_count);
|
||||||
const uint64_t conditional =
|
const uint64_t conditional =
|
||||||
cond_num_trigger * cond_trigger_limit + cond_track_left;
|
cond_num_trigger * cond_trigger_limit + cond_track_left;
|
||||||
printf("tb: %" PRIu64 "\n", expected);
|
g_autoptr(GString) stats = g_string_new("");
|
||||||
printf("tb: %" PRIu64 " (per vcpu)\n", per_vcpu);
|
g_string_append_printf(stats, "tb: %" PRIu64 "\n", expected);
|
||||||
printf("tb: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu);
|
g_string_append_printf(stats, "tb: %" PRIu64 " (per vcpu)\n", per_vcpu);
|
||||||
printf("tb: %" PRIu64 " (conditional cb)\n", conditional);
|
g_string_append_printf(stats, "tb: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu);
|
||||||
|
g_string_append_printf(stats, "tb: %" PRIu64 " (conditional cb)\n", conditional);
|
||||||
|
qemu_plugin_outs(stats->str);
|
||||||
g_assert(expected > 0);
|
g_assert(expected > 0);
|
||||||
g_assert(per_vcpu == expected);
|
g_assert(per_vcpu == expected);
|
||||||
g_assert(inl_per_vcpu == expected);
|
g_assert(inl_per_vcpu == expected);
|
||||||
|
@ -107,9 +111,11 @@ static void stats_mem(void)
|
||||||
const uint64_t per_vcpu = qemu_plugin_u64_sum(count_mem);
|
const uint64_t per_vcpu = qemu_plugin_u64_sum(count_mem);
|
||||||
const uint64_t inl_per_vcpu =
|
const uint64_t inl_per_vcpu =
|
||||||
qemu_plugin_u64_sum(count_mem_inline);
|
qemu_plugin_u64_sum(count_mem_inline);
|
||||||
printf("mem: %" PRIu64 "\n", expected);
|
g_autoptr(GString) stats = g_string_new("");
|
||||||
printf("mem: %" PRIu64 " (per vcpu)\n", per_vcpu);
|
g_string_append_printf(stats, "mem: %" PRIu64 "\n", expected);
|
||||||
printf("mem: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu);
|
g_string_append_printf(stats, "mem: %" PRIu64 " (per vcpu)\n", per_vcpu);
|
||||||
|
g_string_append_printf(stats, "mem: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu);
|
||||||
|
qemu_plugin_outs(stats->str);
|
||||||
g_assert(expected > 0);
|
g_assert(expected > 0);
|
||||||
g_assert(per_vcpu == expected);
|
g_assert(per_vcpu == expected);
|
||||||
g_assert(inl_per_vcpu == expected);
|
g_assert(inl_per_vcpu == expected);
|
||||||
|
@ -118,6 +124,7 @@ static void stats_mem(void)
|
||||||
static void plugin_exit(qemu_plugin_id_t id, void *udata)
|
static void plugin_exit(qemu_plugin_id_t id, void *udata)
|
||||||
{
|
{
|
||||||
const unsigned int num_cpus = qemu_plugin_num_vcpus();
|
const unsigned int num_cpus = qemu_plugin_num_vcpus();
|
||||||
|
g_autoptr(GString) stats = g_string_new("");
|
||||||
g_assert(num_cpus == max_cpu_index + 1);
|
g_assert(num_cpus == max_cpu_index + 1);
|
||||||
|
|
||||||
for (int i = 0; i < num_cpus ; ++i) {
|
for (int i = 0; i < num_cpus ; ++i) {
|
||||||
|
@ -135,20 +142,21 @@ static void plugin_exit(qemu_plugin_id_t id, void *udata)
|
||||||
qemu_plugin_u64_get(insn_cond_num_trigger, i);
|
qemu_plugin_u64_get(insn_cond_num_trigger, i);
|
||||||
const uint64_t insn_cond_left =
|
const uint64_t insn_cond_left =
|
||||||
qemu_plugin_u64_get(insn_cond_track_count, i);
|
qemu_plugin_u64_get(insn_cond_track_count, i);
|
||||||
printf("cpu %d: tb (%" PRIu64 ", %" PRIu64
|
g_string_printf(stats, "cpu %d: tb (%" PRIu64 ", %" PRIu64
|
||||||
", %" PRIu64 " * %" PRIu64 " + %" PRIu64
|
", %" PRIu64 " * %" PRIu64 " + %" PRIu64
|
||||||
") | "
|
") | "
|
||||||
"insn (%" PRIu64 ", %" PRIu64
|
"insn (%" PRIu64 ", %" PRIu64
|
||||||
", %" PRIu64 " * %" PRIu64 " + %" PRIu64
|
", %" PRIu64 " * %" PRIu64 " + %" PRIu64
|
||||||
") | "
|
") | "
|
||||||
"mem (%" PRIu64 ", %" PRIu64 ")"
|
"mem (%" PRIu64 ", %" PRIu64 ")"
|
||||||
"\n",
|
"\n",
|
||||||
i,
|
i,
|
||||||
tb, tb_inline,
|
tb, tb_inline,
|
||||||
tb_cond_trigger, cond_trigger_limit, tb_cond_left,
|
tb_cond_trigger, cond_trigger_limit, tb_cond_left,
|
||||||
insn, insn_inline,
|
insn, insn_inline,
|
||||||
insn_cond_trigger, cond_trigger_limit, insn_cond_left,
|
insn_cond_trigger, cond_trigger_limit, insn_cond_left,
|
||||||
mem, mem_inline);
|
mem, mem_inline);
|
||||||
|
qemu_plugin_outs(stats->str);
|
||||||
g_assert(tb == tb_inline);
|
g_assert(tb == tb_inline);
|
||||||
g_assert(insn == insn_inline);
|
g_assert(insn == insn_inline);
|
||||||
g_assert(mem == mem_inline);
|
g_assert(mem == mem_inline);
|
||||||
|
|
|
@ -18,7 +18,7 @@ import re
|
||||||
from test_gdbstub import main, report
|
from test_gdbstub import main, report
|
||||||
|
|
||||||
|
|
||||||
PATTERN_0 = "Memory tags for address 0x[0-9a-f]+ match \(0x[0-9a-f]+\)."
|
PATTERN_0 = "Memory tags for address 0x[0-9a-f]+ match \\(0x[0-9a-f]+\\)."
|
||||||
PATTERN_1 = ".*(0x[0-9a-f]+)"
|
PATTERN_1 = ".*(0x[0-9a-f]+)"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -51,13 +51,13 @@
|
||||||
"pixman",
|
"pixman",
|
||||||
"pkgconf",
|
"pkgconf",
|
||||||
"png",
|
"png",
|
||||||
"py39-numpy",
|
"py311-numpy",
|
||||||
"py39-pillow",
|
"py311-pillow",
|
||||||
"py39-pip",
|
"py311-pip",
|
||||||
"py39-sphinx",
|
"py311-sphinx",
|
||||||
"py39-sphinx_rtd_theme",
|
"py311-sphinx_rtd_theme",
|
||||||
"py39-tomli",
|
"py311-tomli",
|
||||||
"py39-yaml",
|
"py311-yaml",
|
||||||
"python3",
|
"python3",
|
||||||
"rpm2cpio",
|
"rpm2cpio",
|
||||||
"sdl2",
|
"sdl2",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue