Skip to content

Commit

Permalink
tests: add plugin asserting correctness of discon event's to_pc
Browse files Browse the repository at this point in the history
We recently introduced plugin API for the registration of callbacks for
discontinuity events, specifically for interrupts, exceptions and host
call events. The callback receives, among other information, the VCPU
index and the PC after the event. This change introduces a test plugin
asserting that particular behaviour.
  • Loading branch information
neithernut authored and pbo-linaro committed Dec 4, 2024
1 parent 8745434 commit 815b198
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 1 deletion.
95 changes: 95 additions & 0 deletions tests/tcg/plugins/discons.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright (C) 2024, Julian Ganz <[email protected]>
*
* License: GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include <stdio.h>

#include <qemu-plugin.h>

QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;

struct cpu_state {
uint64_t next_pc;
bool has_next;
};

static struct qemu_plugin_scoreboard *states;

static bool abort_on_mismatch;

static void vcpu_discon(qemu_plugin_id_t id, unsigned int vcpu_index,
enum qemu_plugin_discon_type type, uint64_t from_pc,
uint64_t to_pc)
{
struct cpu_state *state = qemu_plugin_scoreboard_find(states, vcpu_index);
state->next_pc = to_pc;
state->has_next = true;
}

static void insn_exec(unsigned int vcpu_index, void *userdata)
{
struct cpu_state *state = qemu_plugin_scoreboard_find(states, vcpu_index);
uint64_t pc = (uint64_t) userdata;
GString* report;

if (state->has_next) {
if (state->next_pc != pc) {
report = g_string_new("Trap target PC mismatch\n");
g_string_append_printf(report,
"Expected: %"PRIx64"\nEncountered: %"
PRIx64"\n",
state->next_pc, pc);
qemu_plugin_outs(report->str);
if (abort_on_mismatch) {
g_abort();
}
g_string_free(report, true);
}
state->has_next = false;
}
}

static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
{
size_t i;
size_t n_insns = qemu_plugin_tb_n_insns(tb);

for (i = 0; i < n_insns; i++) {
struct qemu_plugin_insn * insn = qemu_plugin_tb_get_insn(tb, i);
uint64_t pc = qemu_plugin_insn_vaddr(insn);
qemu_plugin_register_vcpu_insn_exec_cb(insn, insn_exec,
QEMU_PLUGIN_CB_NO_REGS,
(void*) pc);
}
}

QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
const qemu_info_t *info,
int argc, char **argv)
{
int i;

for (i = 0; i < argc; i++) {
char *opt = argv[i];
g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
if (g_strcmp0(tokens[0], "abort") == 0) {
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &abort_on_mismatch)) {
fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
return -1;
}
} else {
fprintf(stderr, "option parsing failed: %s\n", opt);
return -1;
}
}

states = qemu_plugin_scoreboard_new(sizeof(struct cpu_state));

qemu_plugin_register_vcpu_discon_cb(id, QEMU_PLUGIN_DISCON_ALL,
vcpu_discon);
qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);

return 0;
}
2 changes: 1 addition & 1 deletion tests/tcg/plugins/meson.build
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
t = []
if get_option('plugins')
foreach i : ['bb', 'empty', 'inline', 'insn', 'mem', 'syscall']
foreach i : ['bb', 'discons', 'empty', 'inline', 'insn', 'mem', 'syscall']
if host_os == 'windows'
t += shared_module(i, files(i + '.c') + '../../../contrib/plugins/win32_linker.c',
include_directories: '../../../include/qemu',
Expand Down

0 comments on commit 815b198

Please sign in to comment.