From 799fa30a6e3cfb21d6b46b33d4e8a12cac439ac4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Nov 2025 12:49:46 +0100 Subject: [PATCH 01/10] ioapic: fix typo in irqfd check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not registering the IEC notifier results in a regression with interrupt remapping when running a VM configured with an intel-iommu device and an assigned PCI VF. At boot, Linux complains with : [ 15.416794] __common_interrupt: 2.37 No irq handler for vector Reported-by: Cédric Le Goater Analyzed-by: Magnus Kulke Signed-off-by: Paolo Bonzini --- hw/intc/ioapic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c index e431d00311..38e4384648 100644 --- a/hw/intc/ioapic.c +++ b/hw/intc/ioapic.c @@ -216,7 +216,7 @@ static void ioapic_update_kvm_routes(IOAPICCommonState *s) #endif } -#ifdef ACCEL_KERNEL_GSI_IRQFD_POSSIBLE +#ifdef ACCEL_GSI_IRQFD_POSSIBLE static void ioapic_iec_notifier(void *private, bool global, uint32_t index, uint32_t mask) { @@ -434,7 +434,7 @@ static const MemoryRegionOps ioapic_io_ops = { static void ioapic_machine_done_notify(Notifier *notifier, void *data) { -#ifdef ACCEL_KERNEL_GSI_IRQFD_POSSIBLE +#ifdef ACCEL_GSI_IRQFD_POSSIBLE IOAPICCommonState *s = container_of(notifier, IOAPICCommonState, machine_done); From 46b06eaeb48d82ec231e9a09ce032ab1d5df8d33 Mon Sep 17 00:00:00 2001 From: Nguyen Dinh Phi Date: Fri, 14 Nov 2025 16:29:15 +0800 Subject: [PATCH 02/10] target/i386: emulate: Make sure fetch_instruction exist before calling it Currently, this function is only available in MSHV. If a different accelerator is used, and the code jumps to this section, a segfault will occur. (I ran into this with HVF) Signed-off-by: Nguyen Dinh Phi Link: https://lore.kernel.org/r/20251114082915.71884-2-phind.uet@gmail.com Signed-off-by: Paolo Bonzini --- target/i386/emulate/x86_decode.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target/i386/emulate/x86_decode.c b/target/i386/emulate/x86_decode.c index 97bd6f1a3b..d037ed1142 100644 --- a/target/i386/emulate/x86_decode.c +++ b/target/i386/emulate/x86_decode.c @@ -77,7 +77,11 @@ static inline uint64_t decode_bytes(CPUX86State *env, struct x86_decode *decode, memcpy(&val, decode->stream->bytes + decode->len, size); } else { target_ulong va = linear_rip(env_cpu(env), env->eip) + decode->len; - emul_ops->fetch_instruction(env_cpu(env), &val, va, size); + if (emul_ops->fetch_instruction) { + emul_ops->fetch_instruction(env_cpu(env), &val, va, size); + } else { + emul_ops->read_mem(env_cpu(env), &val, va, size); + } } decode->len += size; From ebd9ea2947d88f237e20333fe547ca8817d0b0ee Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 14 Nov 2025 17:54:17 +0000 Subject: [PATCH 03/10] target/i386: Mark VPERMILPS as not valid with prefix 0 There are a small set of binary SSE insns which have no MMX equivalent, which we create the gen functions for with the BINARY_INT_SSE() macro. This forwards to gen_binary_int_sse() with a NULL pointer for 'mmx'. For almost all of these insns we correctly mark them in the decode table as not permitting a zero prefix byte; however we got this wrong for VPERMILPS, with the result that a bogus instruction would get through the decode checks and end up in gen_binary_int_sse() trying to call a NULL pointer. Correct the decode table entry for VPERMILPS so that we get the expected #UD exception. In the x86 SDM, table A-4 "Three-byte Opcode Map: 08H-FFH (First Two Bytes are 0F 38H)" confirms that there is no pfx 0 version of VPERMILPS. Cc: qemu-stable@nongnu.org Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3199 Signed-off-by: Peter Maydell Link: https://lore.kernel.org/r/20251114175417.2794804-1-peter.maydell@linaro.org Signed-off-by: Paolo Bonzini --- target/i386/tcg/decode-new.c.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc index f4192f1006..805cfd08e8 100644 --- a/target/i386/tcg/decode-new.c.inc +++ b/target/i386/tcg/decode-new.c.inc @@ -643,7 +643,7 @@ static const X86OpEntry opcodes_0F38_00toEF[240] = { [0x0a] = X86_OP_ENTRY3(PSIGND, V,x, H,x, W,x, vex4 cpuid(SSSE3) mmx avx2_256 p_00_66), [0x0b] = X86_OP_ENTRY3(PMULHRSW, V,x, H,x, W,x, vex4 cpuid(SSSE3) mmx avx2_256 p_00_66), /* Listed incorrectly as type 4 */ - [0x0c] = X86_OP_ENTRY3(VPERMILPS, V,x, H,x, W,x, vex6 chk(W0) cpuid(AVX) p_00_66), + [0x0c] = X86_OP_ENTRY3(VPERMILPS, V,x, H,x, W,x, vex6 chk(W0) cpuid(AVX) p_66), [0x0d] = X86_OP_ENTRY3(VPERMILPD, V,x, H,x, W,x, vex6 chk(W0) cpuid(AVX) p_66), [0x0e] = X86_OP_ENTRY3(VTESTPS, None,None, V,x, W,x, vex6 chk(W0) cpuid(AVX) p_66), [0x0f] = X86_OP_ENTRY3(VTESTPD, None,None, V,x, W,x, vex6 chk(W0) cpuid(AVX) p_66), From ebb46ba6a4a20d393a6889c21e8a80dabab4cc8e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 15 Nov 2025 00:57:52 +0100 Subject: [PATCH 04/10] target/i386/tcg: validate segment registers Correctly reject invalid segment registers, including CS when used as the destination of a MOV. Ignore the REX prefix as well. Fixes: 5e9e21bcc4d ("target/i386: move 60-BF opcodes to new decoder", 2024-05-07) Cc: qemu-stable@nongnu.org Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3195 Signed-off-by: Paolo Bonzini --- target/i386/tcg/decode-new.c.inc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc index 805cfd08e8..0f8c5d1693 100644 --- a/target/i386/tcg/decode-new.c.inc +++ b/target/i386/tcg/decode-new.c.inc @@ -2059,7 +2059,12 @@ static bool decode_op(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, case X86_TYPE_S: /* reg selects a segment register */ op->unit = X86_OP_SEG; - goto get_reg; + op->n = (get_modrm(s, env) >> 3) & 7; + /* Values outside [CDEFGS]S, as well as storing to CS, are invalid. */ + if (op->n >= 6 || (op->n == R_CS && op == &decode->op[0])) { + return false; + } + break; case X86_TYPE_P: op->unit = X86_OP_MMX; From 9c3afb9d9b92d166d227b43d890c6a8ad33a928d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 15 Nov 2025 01:04:18 +0100 Subject: [PATCH 05/10] target/i386: svm: fix sign extension of exit code The exit_code parameter of cpu_vmexit is declared as uint32_t, but exit codes are 64 bits wide according to the AMD SVM specification. And because uint32_t is unsigned, this causes exit codes to be zero-extended, for example writing SVM_EXIT_ERR as 0xffff_ffff instead of the expected 0xffff_ffff_ffff_ffff. Cc: qemu-stable@nongnu.org Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2977 Signed-off-by: Paolo Bonzini --- target/i386/tcg/helper-tcg.h | 2 +- target/i386/tcg/system/svm_helper.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h index be011b06b7..e41cbda407 100644 --- a/target/i386/tcg/helper-tcg.h +++ b/target/i386/tcg/helper-tcg.h @@ -99,7 +99,7 @@ void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask); /* system/svm_helper.c */ #ifndef CONFIG_USER_ONLY -G_NORETURN void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, +G_NORETURN void cpu_vmexit(CPUX86State *nenv, uint64_t exit_code, uint64_t exit_info_1, uintptr_t retaddr); void do_vmexit(CPUX86State *env); #endif diff --git a/target/i386/tcg/system/svm_helper.c b/target/i386/tcg/system/svm_helper.c index 505788b0e2..4b86796518 100644 --- a/target/i386/tcg/system/svm_helper.c +++ b/target/i386/tcg/system/svm_helper.c @@ -128,7 +128,7 @@ static inline bool virtual_gif_enabled(CPUX86State *env) return false; } -static inline bool virtual_vm_load_save_enabled(CPUX86State *env, uint32_t exit_code, uintptr_t retaddr) +static inline bool virtual_vm_load_save_enabled(CPUX86State *env, uint64_t exit_code, uintptr_t retaddr) { uint64_t lbr_ctl; @@ -723,7 +723,7 @@ void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param, } } -void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1, +void cpu_vmexit(CPUX86State *env, uint64_t exit_code, uint64_t exit_info_1, uintptr_t retaddr) { CPUState *cs = env_cpu(env); @@ -732,7 +732,7 @@ void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1, qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n", - exit_code, exit_info_1, + (uint32_t)exit_code, exit_info_1, x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)), env->eip); From 106d766c9d5b549bc9780d2d2c519aa2bbebc89a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 15 Nov 2025 01:58:57 +0100 Subject: [PATCH 06/10] target/i386: fix stack size when delivering real mode interrupts The stack can be 32-bit even in real mode, and in this case the stack pointer must be updated in its entirety rather than just the bottom 16 bits. The same is true of real mode IRET, for which there was even a comment suggesting the right thing to do. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1506 Signed-off-by: Paolo Bonzini --- target/i386/tcg/seg_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index 667b1c3869..227336c4ef 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -1161,7 +1161,7 @@ static void do_interrupt_real(CPUX86State *env, int intno, int is_int, sa.env = env; sa.ra = 0; sa.sp = env->regs[R_ESP]; - sa.sp_mask = 0xffff; + sa.sp_mask = get_sp_mask(env->segs[R_SS].flags); sa.ss_base = env->segs[R_SS].base; sa.mmu_index = x86_mmu_index_pl(env, 0); @@ -1964,7 +1964,7 @@ void helper_iret_real(CPUX86State *env, int shift) sa.env = env; sa.ra = GETPC(); sa.mmu_index = x86_mmu_index_pl(env, 0); - sa.sp_mask = 0xffff; /* XXXX: use SS segment size? */ + sa.sp_mask = get_sp_mask(env->segs[R_SS].flags); sa.sp = env->regs[R_ESP]; sa.ss_base = env->segs[R_SS].base; From 50797af6e8ed8b7d3921413d6879cac772ded956 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 Nov 2025 16:48:09 +0100 Subject: [PATCH 07/10] mtest2make: cleanup mtest-suites variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the "--suite" argument from the .*.mtest-suites variables, and add it only when actually computing the arguments to "meson test". This makes it possible to set ninja-cmd-goals from the set of suites, instead of doing it via many different .ninja-goals.* variables. Reviewed-by: Alex Bennée Tested-by: Alex Bennée Signed-off-by: Paolo Bonzini --- Makefile | 4 +++- scripts/mtest2make.py | 40 +++++++++++++++++++--------------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 74c2da2037..9fb55dcf33 100644 --- a/Makefile +++ b/Makefile @@ -96,6 +96,8 @@ meson.stamp: config-host.mak # 3. ensure meson-generated build files are up-to-date +ninja-cmd-goals = + ifneq ($(NINJA),) Makefile.ninja: build.ninja $(quiet-@){ \ @@ -150,7 +152,7 @@ NINJAFLAGS = \ $(or $(filter -l% -j%, $(MAKEFLAGS)), \ $(if $(filter --jobserver-auth=%, $(MAKEFLAGS)),, -j1))) \ -d keepdepfile -ninja-cmd-goals = $(or $(MAKECMDGOALS), all) +ninja-cmd-goals += $(or $(MAKECMDGOALS), all) ninja-cmd-goals += $(foreach g, $(MAKECMDGOALS), $(.ninja-goals.$g)) makefile-targets := build.ninja ctags TAGS cscope dist clean diff --git a/scripts/mtest2make.py b/scripts/mtest2make.py index 2ef375fc6f..d7c514243a 100644 --- a/scripts/mtest2make.py +++ b/scripts/mtest2make.py @@ -8,24 +8,23 @@ from collections import defaultdict import itertools import json import os -import shlex import sys class Suite(object): def __init__(self): self.deps = set() - self.speeds = ['quick'] + self.speeds = [] def names(self, base): - return [base if speed == 'quick' else f'{base}-{speed}' for speed in self.speeds] + return [f'{base}-{speed}' for speed in self.speeds] -print(''' +print(r''' SPEED = quick -.speed.quick = $(foreach s,$(sort $(filter-out %-slow %-thorough, $1)), --suite $s) -.speed.slow = $(foreach s,$(sort $(filter-out %-thorough, $1)), --suite $s) -.speed.thorough = $(foreach s,$(sort $1), --suite $s) +.speed.quick = $(sort $(filter-out %-slow %-thorough, $1)) +.speed.slow = $(sort $(filter-out %-thorough, $1)) +.speed.thorough = $(sort $1) TIMEOUT_MULTIPLIER ?= 1 .mtestargs = --no-rebuild -t $(TIMEOUT_MULTIPLIER) @@ -34,8 +33,10 @@ ifneq ($(SPEED), quick) endif .mtestargs += $(subst -j,--num-processes , $(filter-out -j, $(lastword -j1 $(filter -j%, $(MAKEFLAGS))))) -.check.mtestargs = $(MTESTARGS) $(.mtestargs) $(if $(V),--verbose,--print-errorlogs) -.bench.mtestargs = $(MTESTARGS) $(.mtestargs) --benchmark --verbose''') +.check.mtestargs = $(MTESTARGS) $(.mtestargs) $(if $(V),--verbose,--print-errorlogs) \ + $(foreach s, $(sort $(.check.mtest-suites)), --suite $s) +.bench.mtestargs = $(MTESTARGS) $(.mtestargs) --benchmark --verbose \ + $(foreach s, $(sort $(.bench.mtest-suites)), --suite $s)''') introspect = json.load(sys.stdin) @@ -72,29 +73,26 @@ def emit_prolog(suites, prefix): print(f'all-{prefix}-targets = {all_targets}') print(f'all-{prefix}-xml = {all_xml}') print(f'.PHONY: {prefix} do-meson-{prefix} {prefix}-report.junit.xml $(all-{prefix}-targets) $(all-{prefix}-xml)') - print(f'ifeq ($(filter {prefix}, $(MAKECMDGOALS)),)') - print(f'.{prefix}.mtestargs += $(call .speed.$(SPEED), $(.{prefix}.mtest-suites))') - print(f'endif') + print(f'ninja-cmd-goals += $(foreach s, $(.{prefix}.mtest-suites), $(.{prefix}-$s.deps))') print(f'{prefix}-build: run-ninja') print(f'{prefix} $(all-{prefix}-targets): do-meson-{prefix}') print(f'do-meson-{prefix}: run-ninja; $(if $(MAKE.n),,+)$(MESON) test $(.{prefix}.mtestargs)') print(f'{prefix}-report.junit.xml $(all-{prefix}-xml): {prefix}-report%.junit.xml: run-ninja') print(f'\t$(MAKE) {prefix}$* MTESTARGS="$(MTESTARGS) --logbase {prefix}-report$*" && ln -f meson-logs/$@ .') -def emit_suite_deps(name, suite, prefix): +def emit_suite(name, suite, prefix): deps = ' '.join(suite.deps) - targets = [f'{prefix}-{name}', f'{prefix}-report-{name}.junit.xml', f'{prefix}', f'{prefix}-report.junit.xml', - f'{prefix}-build'] print() print(f'.{prefix}-{name}.deps = {deps}') - for t in targets: - print(f'.ninja-goals.{t} += $(.{prefix}-{name}.deps)') + print(f'.ninja-goals.check-build += $(.{prefix}-{name}.deps)') -def emit_suite(name, suite, prefix): - emit_suite_deps(name, suite, prefix) - targets = f'{prefix}-{name} {prefix}-report-{name}.junit.xml {prefix} {prefix}-report.junit.xml' + names = ' '.join(suite.names(name)) + targets = f'{prefix}-{name} {prefix}-report-{name}.junit.xml' + if not name.endswith('-slow') and not name.endswith('-thorough'): + targets += f' {prefix} {prefix}-report.junit.xml' print(f'ifneq ($(filter {targets}, $(MAKECMDGOALS)),)') - print(f'.{prefix}.mtest-suites += ' + ' '.join(suite.names(name))) + # for the "base" suite possibly add FOO-slow and FOO-thorough + print(f".{prefix}.mtest-suites += {name} $(call .speed.$(SPEED), {names})") print(f'endif') targets = {t['id']: [os.path.relpath(f) for f in t['filename']] From b1085f87ef868e1153591c6e596b0e2b03b0e066 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 Nov 2025 16:51:17 +0100 Subject: [PATCH 08/10] mtest2make: add dependencies to the "speed-qualified" suite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thorough tests may have more dependencies than faster ones. Dependencies are now looked up based on the suites being executed, not on the suites passed as goals to the makefile. Therefore, it is possible to limit dependencies to the speeds that need them. Reviewed-by: Alex Bennée Tested-by: Alex Bennée Signed-off-by: Paolo Bonzini --- scripts/mtest2make.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mtest2make.py b/scripts/mtest2make.py index d7c514243a..38512046d9 100644 --- a/scripts/mtest2make.py +++ b/scripts/mtest2make.py @@ -58,13 +58,13 @@ def process_tests(test, targets, suites): s = s.split(':')[1] if s == 'slow' or s == 'thorough': continue + suites[s].deps.update(deps) if s.endswith('-slow'): s = s[:-5] suites[s].speeds.append('slow') if s.endswith('-thorough'): s = s[:-9] suites[s].speeds.append('thorough') - suites[s].deps.update(deps) def emit_prolog(suites, prefix): all_targets = ' '.join((f'{prefix}-{k}' for k in suites.keys())) From 5f9d28a2f8d3d42bf17643e62064100d977f9f7b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Nov 2025 00:26:28 +0100 Subject: [PATCH 09/10] mtest2make: do not repeat the same speed over and over MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are just two of them (slow and thorough; quick is simply the default). Avoid repeating them for as many times as there are tests. Reviewed-by: Alex Bennée Tested-by: Alex Bennée Signed-off-by: Paolo Bonzini --- scripts/mtest2make.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/mtest2make.py b/scripts/mtest2make.py index 38512046d9..4b252defc3 100644 --- a/scripts/mtest2make.py +++ b/scripts/mtest2make.py @@ -13,7 +13,7 @@ import sys class Suite(object): def __init__(self): self.deps = set() - self.speeds = [] + self.speeds = set() def names(self, base): return [f'{base}-{speed}' for speed in self.speeds] @@ -61,10 +61,10 @@ def process_tests(test, targets, suites): suites[s].deps.update(deps) if s.endswith('-slow'): s = s[:-5] - suites[s].speeds.append('slow') + suites[s].speeds.add('slow') if s.endswith('-thorough'): s = s[:-9] - suites[s].speeds.append('thorough') + suites[s].speeds.add('thorough') def emit_prolog(suites, prefix): all_targets = ' '.join((f'{prefix}-{k}' for k in suites.keys())) From 58f88d0bf7c4c0676b54f97ba91eecccbca968c9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Nov 2025 14:53:32 +0100 Subject: [PATCH 10/10] replay: add tracing events The replay subsystem does not provide any way to see what's going on and how the replay events interleave with other things happening in QEMU. Add trace events to improve debuggability; to avoid having too many events reimplement all functions in terms of (non-traced) replay_getc and replay_putc and add a single trace event for each datum that is extracted or written. Signed-off-by: Paolo Bonzini --- meson.build | 1 + replay/replay-internal.c | 70 ++++++++++++++++++++++++++++++---------- replay/trace-events | 12 +++++++ replay/trace.h | 1 + 4 files changed, 67 insertions(+), 17 deletions(-) create mode 100644 replay/trace-events create mode 100644 replay/trace.h diff --git a/meson.build b/meson.build index df4460035c..95fcec9ba1 100644 --- a/meson.build +++ b/meson.build @@ -3678,6 +3678,7 @@ if have_system 'hw/gpio', 'migration', 'net', + 'replay', 'system', 'ui', 'hw/remote', diff --git a/replay/replay-internal.c b/replay/replay-internal.c index c2a7200339..4839f2b632 100644 --- a/replay/replay-internal.c +++ b/replay/replay-internal.c @@ -15,6 +15,7 @@ #include "replay-internal.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" +#include "trace.h" /* Mutex to protect reading and writing events to the log. data_kind and has_unread_data are also protected @@ -44,7 +45,7 @@ static void replay_read_error(void) exit(1); } -void replay_put_byte(uint8_t byte) +static void replay_putc(uint8_t byte) { if (replay_file) { if (putc(byte, replay_file) == EOF) { @@ -53,29 +54,45 @@ void replay_put_byte(uint8_t byte) } } +void replay_put_byte(uint8_t byte) +{ + trace_replay_put_byte(byte); + replay_putc(byte); +} + void replay_put_event(uint8_t event) { + trace_replay_put_event(event); assert(event < EVENT_COUNT); - replay_put_byte(event); + replay_putc(event); } void replay_put_word(uint16_t word) { - replay_put_byte(word >> 8); - replay_put_byte(word); + trace_replay_put_word(word); + replay_putc(word >> 8); + replay_putc(word); } void replay_put_dword(uint32_t dword) { - replay_put_word(dword >> 16); - replay_put_word(dword); + int i; + + trace_replay_put_dword(dword); + for (i = 24; i >= 0; i -= 8) { + replay_putc(dword >> i); + } } void replay_put_qword(int64_t qword) { - replay_put_dword(qword >> 32); - replay_put_dword(qword); + int i; + + trace_replay_put_qword(qword); + for (i = 56; i >= 0; i -= 8) { + replay_putc(qword >> i); + } } void replay_put_array(const uint8_t *buf, size_t size) @@ -88,7 +105,7 @@ void replay_put_array(const uint8_t *buf, size_t size) } } -uint8_t replay_get_byte(void) +static uint8_t replay_getc(void) { uint8_t byte = 0; if (replay_file) { @@ -101,36 +118,52 @@ uint8_t replay_get_byte(void) return byte; } +uint8_t replay_get_byte(void) +{ + uint8_t byte = replay_getc(); + trace_replay_get_byte(byte); + return byte; +} + uint16_t replay_get_word(void) { uint16_t word = 0; if (replay_file) { - word = replay_get_byte(); - word = (word << 8) + replay_get_byte(); + word = replay_getc(); + word = (word << 8) + replay_getc(); } + trace_replay_get_word(word); return word; } uint32_t replay_get_dword(void) { uint32_t dword = 0; + int i; + if (replay_file) { - dword = replay_get_word(); - dword = (dword << 16) + replay_get_word(); + for (i = 24; i >= 0; i -= 8) { + dword |= replay_getc() << i; + } } + trace_replay_get_dword(dword); return dword; } int64_t replay_get_qword(void) { - int64_t qword = 0; + uint64_t qword = 0; + int i; + if (replay_file) { - qword = replay_get_dword(); - qword = (qword << 32) + replay_get_dword(); + for (i = 56; i >= 0; i -= 8) { + qword |= (uint64_t)replay_getc() << i; + } } + trace_replay_get_qword(qword); return qword; } @@ -172,10 +205,12 @@ void replay_check_error(void) void replay_fetch_data_kind(void) { + trace_replay_fetch_data_kind(); if (replay_file) { if (!replay_state.has_unread_data) { - replay_state.data_kind = replay_get_byte(); + replay_state.data_kind = replay_getc(); replay_state.current_event++; + trace_replay_get_event(replay_state.current_event, replay_state.data_kind); if (replay_state.data_kind == EVENT_INSTRUCTION) { replay_state.instruction_count = replay_get_dword(); } @@ -246,6 +281,7 @@ void replay_advance_current_icount(uint64_t current_icount) int diff = (int)(current_icount - replay_state.current_icount); /* Time can only go forward */ + trace_replay_advance_current_icount(replay_state.current_icount, diff); assert(diff >= 0); if (replay_mode == REPLAY_MODE_RECORD) { diff --git a/replay/trace-events b/replay/trace-events new file mode 100644 index 0000000000..e9c887a6c5 --- /dev/null +++ b/replay/trace-events @@ -0,0 +1,12 @@ +replay_put_byte(uint8_t event) "%02x" +replay_put_event(uint8_t event) "%02x" +replay_put_word(uint16_t event) "%04x" +replay_put_dword(uint32_t event) "%08x" +replay_put_qword(uint64_t event) "%016" PRIx64 +replay_get_byte(uint8_t byte) "%02x" +replay_get_word(uint16_t word) "%04x" +replay_get_dword(uint32_t dword) "%08x" +replay_get_qword(uint64_t qword) "%016" PRIx64 +replay_fetch_data_kind(void) "" +replay_get_event(uint32_t current, uint8_t data) "#%u data=%02x" +replay_advance_current_icount(uint64_t current_icount, int diff) "current=%" PRIu64 " diff=%d" diff --git a/replay/trace.h b/replay/trace.h new file mode 100644 index 0000000000..39ff481742 --- /dev/null +++ b/replay/trace.h @@ -0,0 +1 @@ +#include "trace/trace-replay.h"