mirror of https://github.com/xemu-project/xemu.git
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>
This commit is contained in:
parent
ddfa9f1176
commit
ba3fb2a735
|
@ -132,6 +132,8 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||||
db->insn_start = NULL;
|
db->insn_start = NULL;
|
||||||
db->host_addr[0] = host_pc;
|
db->host_addr[0] = host_pc;
|
||||||
db->host_addr[1] = NULL;
|
db->host_addr[1] = NULL;
|
||||||
|
db->record_start = 0;
|
||||||
|
db->record_len = 0;
|
||||||
|
|
||||||
ops->init_disas_context(db, cpu);
|
ops->init_disas_context(db, cpu);
|
||||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
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;
|
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)
|
static void plugin_insn_append(vaddr pc, const void *from, size_t size)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_PLUGIN
|
#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))) {
|
if (!translator_ld(env, db, &raw, pc, sizeof(raw))) {
|
||||||
raw = cpu_ldub_code(env, pc);
|
raw = cpu_ldub_code(env, pc);
|
||||||
|
record_save(db, pc, &raw, sizeof(raw));
|
||||||
}
|
}
|
||||||
plugin_insn_append(pc, &raw, sizeof(raw));
|
plugin_insn_append(pc, &raw, sizeof(raw));
|
||||||
return raw;
|
return raw;
|
||||||
|
@ -359,6 +395,7 @@ uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, vaddr pc)
|
||||||
} else {
|
} else {
|
||||||
tgt = cpu_lduw_code(env, pc);
|
tgt = cpu_lduw_code(env, pc);
|
||||||
raw = tswap16(tgt);
|
raw = tswap16(tgt);
|
||||||
|
record_save(db, pc, &raw, sizeof(raw));
|
||||||
}
|
}
|
||||||
plugin_insn_append(pc, &raw, sizeof(raw));
|
plugin_insn_append(pc, &raw, sizeof(raw));
|
||||||
return tgt;
|
return tgt;
|
||||||
|
@ -373,6 +410,7 @@ uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, vaddr pc)
|
||||||
} else {
|
} else {
|
||||||
tgt = cpu_ldl_code(env, pc);
|
tgt = cpu_ldl_code(env, pc);
|
||||||
raw = tswap32(tgt);
|
raw = tswap32(tgt);
|
||||||
|
record_save(db, pc, &raw, sizeof(raw));
|
||||||
}
|
}
|
||||||
plugin_insn_append(pc, &raw, sizeof(raw));
|
plugin_insn_append(pc, &raw, sizeof(raw));
|
||||||
return tgt;
|
return tgt;
|
||||||
|
@ -387,6 +425,7 @@ uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, vaddr pc)
|
||||||
} else {
|
} else {
|
||||||
tgt = cpu_ldq_code(env, pc);
|
tgt = cpu_ldq_code(env, pc);
|
||||||
raw = tswap64(tgt);
|
raw = tswap64(tgt);
|
||||||
|
record_save(db, pc, &raw, sizeof(raw));
|
||||||
}
|
}
|
||||||
plugin_insn_append(pc, &raw, sizeof(raw));
|
plugin_insn_append(pc, &raw, sizeof(raw));
|
||||||
return tgt;
|
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)
|
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));
|
plugin_insn_append(pc, &insn8, sizeof(insn8));
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,6 +90,18 @@ typedef struct DisasContextBase {
|
||||||
bool plugin_enabled;
|
bool plugin_enabled;
|
||||||
struct TCGOp *insn_start;
|
struct TCGOp *insn_start;
|
||||||
void *host_addr[2];
|
void *host_addr[2];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Record insn data that we cannot read directly from host memory.
|
||||||
|
* There are only two reasons we cannot use host memory:
|
||||||
|
* (1) We are executing from I/O,
|
||||||
|
* (2) We are executing a synthetic instruction (s390x EX).
|
||||||
|
* In both cases we need record exactly one instruction,
|
||||||
|
* and thus the maximum amount of data we record is limited.
|
||||||
|
*/
|
||||||
|
int record_start;
|
||||||
|
int record_len;
|
||||||
|
uint8_t record[32];
|
||||||
} DisasContextBase;
|
} DisasContextBase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue