aboutsummaryrefslogtreecommitdiff
path: root/accel/tcg
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2024-04-02 19:46:33 -1000
committerRichard Henderson <richard.henderson@linaro.org>2024-05-15 08:54:32 +0200
commitba3fb2a735963cf3988ef9476d134a8418baa436 (patch)
tree4bd315a692a8f8a12b575c19a598d247ed88f8df /accel/tcg
parentddfa9f11766c532209d4ce848c12761d28730338 (diff)
downloadqemu-ba3fb2a735963cf3988ef9476d134a8418baa436.zip
qemu-ba3fb2a735963cf3988ef9476d134a8418baa436.tar.gz
qemu-ba3fb2a735963cf3988ef9476d134a8418baa436.tar.bz2
accel/tcg: Record mmio bytes during translation
This will be able to replace plugin_insn_append, and will be usable for disassembly. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'accel/tcg')
-rw-r--r--accel/tcg/translator.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
index 18138c6..86a1fe1 100644
--- a/accel/tcg/translator.c
+++ b/accel/tcg/translator.c
@@ -132,6 +132,8 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
db->insn_start = NULL;
db->host_addr[0] = host_pc;
db->host_addr[1] = NULL;
+ db->record_start = 0;
+ db->record_len = 0;
ops->init_disas_context(db, cpu);
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
@@ -318,6 +320,39 @@ static bool translator_ld(CPUArchState *env, DisasContextBase *db,
return true;
}
+static void record_save(DisasContextBase *db, vaddr pc,
+ const void *from, int size)
+{
+ int offset;
+
+ /* Do not record probes before the start of TB. */
+ if (pc < db->pc_first) {
+ return;
+ }
+
+ /*
+ * In translator_access, we verified that pc is within 2 pages
+ * of pc_first, thus this will never overflow.
+ */
+ offset = pc - db->pc_first;
+
+ /*
+ * Either the first or second page may be I/O. If it is the second,
+ * then the first byte we need to record will be at a non-zero offset.
+ * In either case, we should not need to record but a single insn.
+ */
+ if (db->record_len == 0) {
+ db->record_start = offset;
+ db->record_len = size;
+ } else {
+ assert(offset == db->record_start + db->record_len);
+ assert(db->record_len + size <= sizeof(db->record));
+ db->record_len += size;
+ }
+
+ memcpy(db->record + (offset - db->record_start), from, size);
+}
+
static void plugin_insn_append(vaddr pc, const void *from, size_t size)
{
#ifdef CONFIG_PLUGIN
@@ -345,6 +380,7 @@ uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, vaddr pc)
if (!translator_ld(env, db, &raw, pc, sizeof(raw))) {
raw = cpu_ldub_code(env, pc);
+ record_save(db, pc, &raw, sizeof(raw));
}
plugin_insn_append(pc, &raw, sizeof(raw));
return raw;
@@ -359,6 +395,7 @@ uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, vaddr pc)
} else {
tgt = cpu_lduw_code(env, pc);
raw = tswap16(tgt);
+ record_save(db, pc, &raw, sizeof(raw));
}
plugin_insn_append(pc, &raw, sizeof(raw));
return tgt;
@@ -373,6 +410,7 @@ uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, vaddr pc)
} else {
tgt = cpu_ldl_code(env, pc);
raw = tswap32(tgt);
+ record_save(db, pc, &raw, sizeof(raw));
}
plugin_insn_append(pc, &raw, sizeof(raw));
return tgt;
@@ -387,6 +425,7 @@ uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, vaddr pc)
} else {
tgt = cpu_ldq_code(env, pc);
raw = tswap64(tgt);
+ record_save(db, pc, &raw, sizeof(raw));
}
plugin_insn_append(pc, &raw, sizeof(raw));
return tgt;
@@ -394,5 +433,7 @@ uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, vaddr pc)
void translator_fake_ldb(DisasContextBase *db, vaddr pc, uint8_t insn8)
{
+ assert(pc >= db->pc_first);
+ record_save(db, pc, &insn8, sizeof(insn8));
plugin_insn_append(pc, &insn8, sizeof(insn8));
}