aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2024-05-15 11:46:36 +0200
committerRichard Henderson <richard.henderson@linaro.org>2024-05-15 11:46:36 +0200
commit2b01688380103acc2a9cd197b964d643fceba2a9 (patch)
tree42f662fdef3d1faa54d262bc1e784088d85548ab
parent265aad58e9cab31d0e69c374ec2efcede7fa8881 (diff)
parentc9290dfebfdba5c13baa5e1f10e13a1c876b0643 (diff)
Merge tag 'pull-tcg-20240515' of https://gitlab.com/rth7680/qemu into staging
tcg/loongarch64: Fill out tcg_out_{ld,st} for vector regs accel/tcg: Improve disassembly for target and plugin # -----BEGIN PGP SIGNATURE----- # # iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmZEXT0dHHJpY2hhcmQu # aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV/FbQf+P3ppcAA+5smxaQyi # dsfCJaGOMqRTWYuSmNsJ7AlxQobxLKVsJrAHraNU1AnDfwKrX3XXJcU4Gwt0eQyN # lGiF/24KLElvb+w6fkjuLdK+DbGWTrNabXJAnBw1h21x+go0mvVCVSuQQw7a/RDS # btPnGkmoi0H340JC1MVSDRgFkB3RV0kOMXGGm70S+mw0WhjVgdInhLv0jjnj2QFM # tYzJ5g+00v0HPo8Lun5kRSaI7EGG7J/XfGa71WHIHrB0o7FAzslap4fGTcfOB+7a # f2jTGErezJQj1pvJLvFTNX4YQ02ORnDKsz4EC0G9QU8rk+S1bD2vTVoi5IY5ayfJ # oqxyRw== # =Q16M # -----END PGP SIGNATURE----- # gpg: Signature made Wed 15 May 2024 08:59:09 AM CEST # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [ultimate] * tag 'pull-tcg-20240515' of https://gitlab.com/rth7680/qemu: (34 commits) tcg/loongarch64: Fill out tcg_out_{ld,st} for vector regs accel/tcg: Remove cpu_ldsb_code / cpu_ldsw_code target/s390x: Use translator_lduw in get_next_pc target/xtensa: Use translator_ldub in xtensa_insn_len target/rx: Use translator_ld* target/riscv: Use translator_ld* for everything target/cris: Use cris_fetch in translate_v10.c.inc target/cris: Use translator_ld* in cris_fetch target/avr: Use translator_lduw target/i386: Use translator_ldub for everything target/microblaze: Use translator_ldl target/hexagon: Use translator_ldl in pkt_crosses_page target/s390x: Disassemble EXECUTEd instructions target/s390x: Fix translator_fake_ld length accel/tcg: Introduce translator_fake_ld disas: Use translator_st to get disassembly data disas: Split disas.c accel/tcg: Return bool from TranslatorOps.disas_log accel/tcg: Provide default implementation of disas_log plugins: Merge alloc_tcg_plugin_context into plugin_gen_tb_start ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
-rw-r--r--accel/tcg/plugin-gen.c63
-rw-r--r--accel/tcg/translator.c307
-rw-r--r--contrib/plugins/execlog.c5
-rw-r--r--contrib/plugins/howvec.c4
-rw-r--r--disas/disas-common.c104
-rw-r--r--disas/disas-host.c129
-rw-r--r--disas/disas-internal.h4
-rw-r--r--disas/disas-mon.c15
-rw-r--r--disas/disas-target.c99
-rw-r--r--disas/disas.c338
-rw-r--r--disas/meson.build8
-rw-r--r--disas/objdump.c37
-rw-r--r--include/disas/disas.h9
-rw-r--r--include/exec/cpu_ldst.h10
-rw-r--r--include/exec/plugin-gen.h7
-rw-r--r--include/exec/translator.h74
-rw-r--r--include/qemu/plugin.h22
-rw-r--r--include/qemu/qemu-plugin.h15
-rw-r--r--include/qemu/typedefs.h1
-rw-r--r--include/tcg/tcg.h1
-rw-r--r--plugins/api.c57
-rw-r--r--target/alpha/translate.c9
-rw-r--r--target/arm/tcg/translate-a64.c11
-rw-r--r--target/arm/tcg/translate.c12
-rw-r--r--target/avr/translate.c11
-rw-r--r--target/cris/translate.c37
-rw-r--r--target/cris/translate_v10.c.inc30
-rw-r--r--target/hexagon/translate.c11
-rw-r--r--target/hppa/translate.c21
-rw-r--r--target/i386/tcg/translate.c19
-rw-r--r--target/loongarch/tcg/translate.c8
-rw-r--r--target/m68k/translate.c9
-rw-r--r--target/microblaze/translate.c11
-rw-r--r--target/mips/tcg/translate.c9
-rw-r--r--target/openrisc/translate.c11
-rw-r--r--target/ppc/translate.c9
-rw-r--r--target/riscv/translate.c24
-rw-r--r--target/rx/translate.c35
-rw-r--r--target/s390x/tcg/translate.c26
-rw-r--r--target/sh4/translate.c9
-rw-r--r--target/sparc/translate.c9
-rw-r--r--target/tricore/translate.c9
-rw-r--r--target/xtensa/translate.c12
-rw-r--r--tcg/loongarch64/tcg-target.c.inc103
-rw-r--r--tcg/tcg.c12
45 files changed, 887 insertions, 879 deletions
diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index 49f5d1c2e4..54b08ffc9e 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -188,7 +188,7 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
int insn_idx = -1;
if (unlikely(qemu_loglevel_mask(LOG_TB_OP_PLUGIN)
- && qemu_log_in_addr_range(plugin_tb->vaddr))) {
+ && qemu_log_in_addr_range(tcg_ctx->plugin_db->pc_first))) {
FILE *logfile = qemu_log_trylock();
if (logfile) {
fprintf(logfile, "OP before plugin injection:\n");
@@ -303,35 +303,34 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
}
}
-bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db,
- bool mem_only)
+bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db)
{
- bool ret = false;
+ struct qemu_plugin_tb *ptb;
- if (test_bit(QEMU_PLUGIN_EV_VCPU_TB_TRANS, cpu->plugin_state->event_mask)) {
- struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
+ if (!test_bit(QEMU_PLUGIN_EV_VCPU_TB_TRANS,
+ cpu->plugin_state->event_mask)) {
+ return false;
+ }
+
+ tcg_ctx->plugin_db = db;
+ tcg_ctx->plugin_insn = NULL;
+ ptb = tcg_ctx->plugin_tb;
- /* reset callbacks */
+ if (ptb) {
+ /* Reset callbacks */
if (ptb->cbs) {
g_array_set_size(ptb->cbs, 0);
}
ptb->n = 0;
-
- ret = true;
-
- ptb->vaddr = db->pc_first;
- ptb->vaddr2 = -1;
- ptb->haddr1 = db->host_addr[0];
- ptb->haddr2 = NULL;
- ptb->mem_only = mem_only;
ptb->mem_helper = false;
-
- tcg_gen_plugin_cb(PLUGIN_GEN_FROM_TB);
+ } else {
+ ptb = g_new0(struct qemu_plugin_tb, 1);
+ tcg_ctx->plugin_tb = ptb;
+ ptb->insns = g_ptr_array_new();
}
- tcg_ctx->plugin_insn = NULL;
-
- return ret;
+ tcg_gen_plugin_cb(PLUGIN_GEN_FROM_TB);
+ return true;
}
void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
@@ -345,11 +344,9 @@ void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
ptb->n = n;
if (n <= ptb->insns->len) {
insn = g_ptr_array_index(ptb->insns, n - 1);
- g_byte_array_set_size(insn->data, 0);
} else {
assert(n - 1 == ptb->insns->len);
insn = g_new0(struct qemu_plugin_insn, 1);
- insn->data = g_byte_array_sized_new(4);
g_ptr_array_add(ptb->insns, insn);
}
@@ -366,28 +363,16 @@ void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
pc = db->pc_next;
insn->vaddr = pc;
- /*
- * Detect page crossing to get the new host address.
- * Note that we skip this when haddr1 == NULL, e.g. when we're
- * fetching instructions from a region not backed by RAM.
- */
- if (ptb->haddr1 == NULL) {
- insn->haddr = NULL;
- } else if (is_same_page(db, db->pc_next)) {
- insn->haddr = ptb->haddr1 + pc - ptb->vaddr;
- } else {
- if (ptb->vaddr2 == -1) {
- ptb->vaddr2 = TARGET_PAGE_ALIGN(db->pc_first);
- get_page_addr_code_hostp(cpu_env(cpu), ptb->vaddr2, &ptb->haddr2);
- }
- insn->haddr = ptb->haddr2 + pc - ptb->vaddr2;
- }
-
tcg_gen_plugin_cb(PLUGIN_GEN_FROM_INSN);
}
void plugin_gen_insn_end(void)
{
+ const DisasContextBase *db = tcg_ctx->plugin_db;
+ struct qemu_plugin_insn *pinsn = tcg_ctx->plugin_insn;
+
+ pinsn->len = db->fake_insn ? db->record_len : db->pc_next - pinsn->vaddr;
+
tcg_gen_plugin_cb(PLUGIN_GEN_AFTER_INSN);
}
diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
index 6832e55135..c56967eecd 100644
--- a/accel/tcg/translator.c
+++ b/accel/tcg/translator.c
@@ -14,8 +14,10 @@
#include "exec/translator.h"
#include "exec/cpu_ldst.h"
#include "exec/plugin-gen.h"
+#include "exec/cpu_ldst.h"
#include "tcg/tcg-op-common.h"
#include "internal-target.h"
+#include "disas/disas.h"
static void set_can_do_io(DisasContextBase *db, bool val)
{
@@ -129,8 +131,11 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
db->max_insns = *max_insns;
db->singlestep_enabled = cflags & CF_SINGLE_STEP;
db->insn_start = NULL;
+ db->fake_insn = false;
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 */
@@ -140,7 +145,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
ops->tb_start(db, cpu);
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
- plugin_enabled = plugin_gen_tb_start(cpu, db, cflags & CF_MEMI_ONLY);
+ plugin_enabled = plugin_gen_tb_start(cpu, db);
db->plugin_enabled = plugin_enabled;
while (true) {
@@ -222,159 +227,249 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
FILE *logfile = qemu_log_trylock();
if (logfile) {
fprintf(logfile, "----------------\n");
- ops->disas_log(db, cpu, logfile);
+
+ if (!ops->disas_log ||
+ !ops->disas_log(db, cpu, logfile)) {
+ fprintf(logfile, "IN: %s\n", lookup_symbol(db->pc_first));
+ target_disas(logfile, cpu, db);
+ }
fprintf(logfile, "\n");
qemu_log_unlock(logfile);
}
}
}
-static void *translator_access(CPUArchState *env, DisasContextBase *db,
- vaddr pc, size_t len)
+static bool translator_ld(CPUArchState *env, DisasContextBase *db,
+ void *dest, vaddr pc, size_t len)
{
+ TranslationBlock *tb = db->tb;
+ vaddr last = pc + len - 1;
void *host;
- vaddr base, end;
- TranslationBlock *tb;
-
- tb = db->tb;
+ vaddr base;
/* Use slow path if first page is MMIO. */
if (unlikely(tb_page_addr0(tb) == -1)) {
- return NULL;
+ /* We capped translation with first page MMIO in tb_gen_code. */
+ tcg_debug_assert(db->max_insns == 1);
+ return false;
}
- end = pc + len - 1;
- if (likely(is_same_page(db, end))) {
- host = db->host_addr[0];
- base = db->pc_first;
- } else {
- host = db->host_addr[1];
- base = TARGET_PAGE_ALIGN(db->pc_first);
- if (host == NULL) {
- tb_page_addr_t page0, old_page1, new_page1;
-
- new_page1 = get_page_addr_code_hostp(env, base, &db->host_addr[1]);
-
- /*
- * If the second page is MMIO, treat as if the first page
- * was MMIO as well, so that we do not cache the TB.
- */
- if (unlikely(new_page1 == -1)) {
- tb_unlock_pages(tb);
- tb_set_page_addr0(tb, -1);
- return NULL;
- }
+ host = db->host_addr[0];
+ base = db->pc_first;
- /*
- * If this is not the first time around, and page1 matches,
- * then we already have the page locked. Alternately, we're
- * not doing anything to prevent the PTE from changing, so
- * we might wind up with a different page, requiring us to
- * re-do the locking.
- */
- old_page1 = tb_page_addr1(tb);
- if (likely(new_page1 != old_page1)) {
- page0 = tb_page_addr0(tb);
- if (unlikely(old_page1 != -1)) {
- tb_unlock_page1(page0, old_page1);
- }
- tb_set_page_addr1(tb, new_page1);
- tb_lock_page1(page0, new_page1);
- }
- host = db->host_addr[1];
+ if (likely(((base ^ last) & TARGET_PAGE_MASK) == 0)) {
+ /* Entire read is from the first page. */
+ memcpy(dest, host + (pc - base), len);
+ return true;
+ }
+
+ if (unlikely(((base ^ pc) & TARGET_PAGE_MASK) == 0)) {
+ /* Read begins on the first page and extends to the second. */
+ size_t len0 = -(pc | TARGET_PAGE_MASK);
+ memcpy(dest, host + (pc - base), len0);
+ pc += len0;
+ dest += len0;
+ len -= len0;
+ }
+
+ /*
+ * The read must conclude on the second page and not extend to a third.
+ *
+ * TODO: We could allow the two pages to be virtually discontiguous,
+ * since we already allow the two pages to be physically discontiguous.
+ * The only reasonable use case would be executing an insn at the end
+ * of the address space wrapping around to the beginning. For that,
+ * we would need to know the current width of the address space.
+ * In the meantime, assert.
+ */
+ base = (base & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+ assert(((base ^ pc) & TARGET_PAGE_MASK) == 0);
+ assert(((base ^ last) & TARGET_PAGE_MASK) == 0);
+ host = db->host_addr[1];
+
+ if (host == NULL) {
+ tb_page_addr_t page0, old_page1, new_page1;
+
+ new_page1 = get_page_addr_code_hostp(env, base, &db->host_addr[1]);
+
+ /*
+ * If the second page is MMIO, treat as if the first page
+ * was MMIO as well, so that we do not cache the TB.
+ */
+ if (unlikely(new_page1 == -1)) {
+ tb_unlock_pages(tb);
+ tb_set_page_addr0(tb, -1);
+ /* Require that this be the final insn. */
+ db->max_insns = db->num_insns;
+ return false;
}
- /* Use slow path when crossing pages. */
- if (is_same_page(db, pc)) {
- return NULL;
+ /*
+ * If this is not the first time around, and page1 matches,
+ * then we already have the page locked. Alternately, we're
+ * not doing anything to prevent the PTE from changing, so
+ * we might wind up with a different page, requiring us to
+ * re-do the locking.
+ */
+ old_page1 = tb_page_addr1(tb);
+ if (likely(new_page1 != old_page1)) {
+ page0 = tb_page_addr0(tb);
+ if (unlikely(old_page1 != -1)) {
+ tb_unlock_page1(page0, old_page1);
+ }
+ tb_set_page_addr1(tb, new_page1);
+ tb_lock_page1(page0, new_page1);
}
+ host = db->host_addr[1];
}
- tcg_debug_assert(pc >= base);
- return host + (pc - base);
+ memcpy(dest, host + (pc - base), len);
+ return true;
}
-static void plugin_insn_append(abi_ptr pc, const void *from, size_t size)
+static void record_save(DisasContextBase *db, vaddr pc,
+ const void *from, int size)
{
-#ifdef CONFIG_PLUGIN
- struct qemu_plugin_insn *insn = tcg_ctx->plugin_insn;
- abi_ptr off;
+ int offset;
- if (insn == NULL) {
+ /* Do not record probes before the start of TB. */
+ if (pc < db->pc_first) {
return;
}
- off = pc - insn->vaddr;
- if (off < insn->data->len) {
- g_byte_array_set_size(insn->data, off);
- } else if (off > insn->data->len) {
- /* we have an unexpected gap */
- g_assert_not_reached();
+
+ /*
+ * 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);
+}
+
+size_t translator_st_len(const DisasContextBase *db)
+{
+ return db->fake_insn ? db->record_len : db->tb->size;
+}
+
+bool translator_st(const DisasContextBase *db, void *dest,
+ vaddr addr, size_t len)
+{
+ size_t offset, offset_end;
+
+ if (addr < db->pc_first) {
+ return false;
+ }
+ offset = addr - db->pc_first;
+ offset_end = offset + len;
+ if (offset_end > translator_st_len(db)) {
+ return false;
+ }
+
+ if (!db->fake_insn) {
+ size_t offset_page1 = -(db->pc_first | TARGET_PAGE_MASK);
+
+ /* Get all the bytes from the first page. */
+ if (db->host_addr[0]) {
+ if (offset_end <= offset_page1) {
+ memcpy(dest, db->host_addr[0] + offset, len);
+ return true;
+ }
+ if (offset < offset_page1) {
+ size_t len0 = offset_page1 - offset;
+ memcpy(dest, db->host_addr[0] + offset, len0);
+ offset += len0;
+ dest += len0;
+ }
+ }
+
+ /* Get any bytes from the second page. */
+ if (db->host_addr[1] && offset >= offset_page1) {
+ memcpy(dest, db->host_addr[1] + (offset - offset_page1),
+ offset_end - offset);
+ return true;
+ }
}
- insn->data = g_byte_array_append(insn->data, from, size);
-#endif
+ /* Else get recorded bytes. */
+ if (db->record_len != 0 &&
+ offset >= db->record_start &&
+ offset_end <= db->record_start + db->record_len) {
+ memcpy(dest, db->record + (offset - db->record_start),
+ offset_end - offset);
+ return true;
+ }
+ return false;
}
-uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, abi_ptr pc)
+uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, vaddr pc)
{
- uint8_t ret;
- void *p = translator_access(env, db, pc, sizeof(ret));
+ uint8_t raw;
- if (p) {
- plugin_insn_append(pc, p, sizeof(ret));
- return ldub_p(p);
+ if (!translator_ld(env, db, &raw, pc, sizeof(raw))) {
+ raw = cpu_ldub_code(env, pc);
+ record_save(db, pc, &raw, sizeof(raw));
}
- ret = cpu_ldub_code(env, pc);
- plugin_insn_append(pc, &ret, sizeof(ret));
- return ret;
+ return raw;
}
-uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, abi_ptr pc)
+uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, vaddr pc)
{
- uint16_t ret, plug;
- void *p = translator_access(env, db, pc, sizeof(ret));
+ uint16_t raw, tgt;
- if (p) {
- plugin_insn_append(pc, p, sizeof(ret));
- return lduw_p(p);
+ if (translator_ld(env, db, &raw, pc, sizeof(raw))) {
+ tgt = tswap16(raw);
+ } else {
+ tgt = cpu_lduw_code(env, pc);
+ raw = tswap16(tgt);
+ record_save(db, pc, &raw, sizeof(raw));
}
- ret = cpu_lduw_code(env, pc);
- plug = tswap16(ret);
- plugin_insn_append(pc, &plug, sizeof(ret));
- return ret;
+ return tgt;
}
-uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, abi_ptr pc)
+uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, vaddr pc)
{
- uint32_t ret, plug;
- void *p = translator_access(env, db, pc, sizeof(ret));
+ uint32_t raw, tgt;
- if (p) {
- plugin_insn_append(pc, p, sizeof(ret));
- return ldl_p(p);
+ if (translator_ld(env, db, &raw, pc, sizeof(raw))) {
+ tgt = tswap32(raw);
+ } else {
+ tgt = cpu_ldl_code(env, pc);
+ raw = tswap32(tgt);
+ record_save(db, pc, &raw, sizeof(raw));
}
- ret = cpu_ldl_code(env, pc);
- plug = tswap32(ret);
- plugin_insn_append(pc, &plug, sizeof(ret));
- return ret;
+ return tgt;
}
-uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, abi_ptr pc)
+uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, vaddr pc)
{
- uint64_t ret, plug;
- void *p = translator_access(env, db, pc, sizeof(ret));
+ uint64_t raw, tgt;
- if (p) {
- plugin_insn_append(pc, p, sizeof(ret));
- return ldq_p(p);
+ if (translator_ld(env, db, &raw, pc, sizeof(raw))) {
+ tgt = tswap64(raw);
+ } else {
+ tgt = cpu_ldq_code(env, pc);
+ raw = tswap64(tgt);
+ record_save(db, pc, &raw, sizeof(raw));
}
- ret = cpu_ldq_code(env, pc);
- plug = tswap64(ret);
- plugin_insn_append(pc, &plug, sizeof(ret));
- return ret;
+ return tgt;
}
-void translator_fake_ldb(uint8_t insn8, abi_ptr pc)
+void translator_fake_ld(DisasContextBase *db, const void *data, size_t len)
{
- plugin_insn_append(pc, &insn8, sizeof(insn8));
+ db->fake_insn = true;
+ record_save(db, db->pc_first, data, len);
}
diff --git a/contrib/plugins/execlog.c b/contrib/plugins/execlog.c
index fab18113d4..371db97eb1 100644
--- a/contrib/plugins/execlog.c
+++ b/contrib/plugins/execlog.c
@@ -258,8 +258,9 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
NULL);
}
} else {
- uint32_t insn_opcode;
- insn_opcode = *((uint32_t *)qemu_plugin_insn_data(insn));
+ uint32_t insn_opcode = 0;
+ qemu_plugin_insn_data(insn, &insn_opcode, sizeof(insn_opcode));
+
char *output = g_strdup_printf("0x%"PRIx64", 0x%"PRIx32", \"%s\"",
insn_vaddr, insn_opcode, insn_disas);
diff --git a/contrib/plugins/howvec.c b/contrib/plugins/howvec.c
index 94bbc53820..9be67f7453 100644
--- a/contrib/plugins/howvec.c
+++ b/contrib/plugins/howvec.c
@@ -252,7 +252,7 @@ static struct qemu_plugin_scoreboard *find_counter(
{
int i;
uint64_t *cnt = NULL;
- uint32_t opcode;
+ uint32_t opcode = 0;
InsnClassExecCount *class = NULL;
/*
@@ -261,7 +261,7 @@ static struct qemu_plugin_scoreboard *find_counter(
* They would probably benefit from a more tailored plugin.
* However we can fall back to individual instruction counting.
*/
- opcode = *((uint32_t *)qemu_plugin_insn_data(insn));
+ qemu_plugin_insn_data(insn, &opcode, sizeof(opcode));
for (i = 0; !cnt && i < class_table_sz; i++) {
class = &class_table[i];
diff --git a/disas/disas-common.c b/disas/disas-common.c
new file mode 100644
index 0000000000..de61f6d8a1
--- /dev/null
+++ b/disas/disas-common.c
@@ -0,0 +1,104 @@
+/*
+ * Common routines for disassembly.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "disas/disas.h"
+#include "disas/capstone.h"
+#include "hw/core/cpu.h"
+#include "exec/tswap.h"
+#include "disas-internal.h"
+
+
+/* Filled in by elfload.c. Simplistic, but will do for now. */
+struct syminfo *syminfos = NULL;
+
+/*
+ * Print an error message. We can assume that this is in response to
+ * an error return from {host,target}_read_memory.
+ */
+static void perror_memory(int status, bfd_vma memaddr,
+ struct disassemble_info *info)
+{
+ if (status != EIO) {
+ /* Can't happen. */
+ info->fprintf_func(info->stream, "Unknown error %d\n", status);
+ } else {
+ /* Address between memaddr and memaddr + len was out of bounds. */
+ info->fprintf_func(info->stream,
+ "Address 0x%" PRIx64 " is out of bounds.\n",
+ memaddr);
+ }
+}
+
+/* Print address in hex. */
+static void print_address(bfd_vma addr, struct disassemble_info *info)
+{
+ info->fprintf_func(info->stream, "0x%" PRIx64, addr);
+}
+
+/* Stub prevents some fruitless earching in optabs disassemblers. */
+static int symbol_at_address(bfd_vma addr, struct disassemble_info *info)
+{
+ return 1;
+}
+
+void disas_initialize_debug(CPUDebug *s)
+{
+ memset(s, 0, sizeof(*s));
+ s->info.arch = bfd_arch_unknown;
+ s->info.cap_arch = -1;
+ s->info.cap_insn_unit = 4;
+ s->info.cap_insn_split = 4;
+ s->info.memory_error_func = perror_memory;
+ s->info.symbol_at_address_func = symbol_at_address;
+}
+
+void disas_initialize_debug_target(CPUDebug *s, CPUState *cpu)
+{
+ disas_initialize_debug(s);
+
+ s->cpu = cpu;
+ s->info.print_address_func = print_address;
+ if (target_words_bigendian()) {
+ s->info.endian = BFD_ENDIAN_BIG;
+ } else {
+ s->info.endian = BFD_ENDIAN_LITTLE;
+ }
+
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ if (cc->disas_set_info) {
+ cc->disas_set_info(cpu, &s->info);
+ }
+}
+
+int disas_gstring_printf(FILE *stream, const char *fmt, ...)
+{
+ /* We abuse the FILE parameter to pass a GString. */
+ GString *s = (GString *)stream;
+ int initial_len = s->len;
+ va_list va;
+
+ va_start(va, fmt);
+ g_string_append_vprintf(s, fmt, va);
+ va_end(va);
+
+ return s->len - initial_len;
+}
+
+/* Look up symbol for debugging purpose. Returns "" if unknown. */
+const char *lookup_symbol(uint64_t orig_addr)
+{
+ const char *symbol = "";
+ struct syminfo *s;
+
+ for (s = syminfos; s; s = s->next) {
+ symbol = s->lookup_symbol(s, orig_addr);
+ if (symbol[0] != '\0') {
+ break;
+ }
+ }
+
+ return symbol;
+}
diff --git a/disas/disas-host.c b/disas/disas-host.c
new file mode 100644
index 0000000000..8146fafe80
--- /dev/null
+++ b/disas/disas-host.c
@@ -0,0 +1,129 @@
+/*
+ * Routines for host instruction disassembly.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "disas/disas.h"
+#include "disas/capstone.h"
+#include "disas-internal.h"
+
+
+/*
+ * Get LENGTH bytes from info's buffer, at host address memaddr.
+ * Transfer them to myaddr.
+ */
+static int host_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
+ struct disassemble_info *info)
+{
+ if (memaddr < info->buffer_vma
+ || memaddr + length > info->buffer_vma + info->buffer_length) {
+ /* Out of bounds. Use EIO because GDB uses it. */
+ return EIO;
+ }
+ memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
+ return 0;
+}
+
+/* Print address in hex, truncated to the width of a host virtual address. */
+static void host_print_address(bfd_vma addr, struct disassemble_info *info)
+{
+ info->fprintf_func(info->stream, "0x%" PRIxPTR, (uintptr_t)addr);
+}
+
+static void initialize_debug_host(CPUDebug *s)
+{
+ disas_initialize_debug(s);
+
+ s->info.read_memory_func = host_read_memory;
+ s->info.print_address_func = host_print_address;
+#if HOST_BIG_ENDIAN
+ s->info.endian = BFD_ENDIAN_BIG;
+#else
+ s->info.endian = BFD_ENDIAN_LITTLE;
+#endif
+#if defined(CONFIG_TCG_INTERPRETER)
+ s->info.print_insn = print_insn_tci;
+#elif defined(__i386__)
+ s->info.mach = bfd_mach_i386_i386;
+ s->info.cap_arch = CS_ARCH_X86;
+ s->info.cap_mode = CS_MODE_32;
+ s->info.cap_insn_unit = 1;
+ s->info.cap_insn_split = 8;
+#elif defined(__x86_64__)
+ s->info.mach = bfd_mach_x86_64;
+ s->info.cap_arch = CS_ARCH_X86;
+ s->info.cap_mode = CS_MODE_64;
+ s->info.cap_insn_unit = 1;
+ s->info.cap_insn_split = 8;
+#elif defined(_ARCH_PPC)
+ s->info.cap_arch = CS_ARCH_PPC;
+# ifdef _ARCH_PPC64
+ s->info.cap_mode = CS_MODE_64;
+# endif
+#elif defined(__riscv)
+#if defined(_ILP32) || (__riscv_xlen == 32)
+ s->info.print_insn = print_insn_riscv32;
+#elif defined(_LP64)
+ s->info.print_insn = print_insn_riscv64;
+#else
+#error unsupported RISC-V ABI
+#endif
+#elif defined(__aarch64__)
+ s->info.cap_arch = CS_ARCH_ARM64;
+#elif defined(__alpha__)
+ s->info.print_insn = print_insn_alpha;
+#elif defined(__sparc__)
+ s->info.print_insn = print_insn_sparc;
+ s->info.mach = bfd_mach_sparc_v9b;
+#elif defined(__arm__)
+ /* TCG only generates code for arm mode. */
+ s->info.cap_arch = CS_ARCH_ARM;
+#elif defined(__MIPSEB__)
+ s->info.print_insn = print_insn_big_mips;
+#elif defined(__MIPSEL__)
+ s->info.print_insn = print_insn_little_mips;
+#elif defined(__m68k__)
+ s->info.print_insn = print_insn_m68k;
+#elif defined(__s390__)
+ s->info.cap_arch = CS_ARCH_SYSZ;
+ s->info.cap_insn_unit = 2;
+ s->info.cap_insn_split = 6;
+#elif defined(__hppa__)
+ s->info.print_insn = print_insn_hppa;
+#elif defined(__loongarch__)
+ s->info.print_insn = print_insn_loongarch;
+#endif
+}
+
+/* Disassemble this for me please... (debugging). */
+void disas(FILE *out, const void *code, size_t size)
+{
+ uintptr_t pc;
+ int count;
+ CPUDebug s;
+
+ initialize_debug_host(&s);
+ s.info.fprintf_func = fprintf;
+ s.info.stream = out;
+ s.info.buffer = code;
+ s.info.buffer_vma = (uintptr_t)code;
+ s.info.buffer_length = size;
+ s.info.show_opcodes = true;
+
+ if (s.info.cap_arch >= 0 && cap_disas_host(&s.info, code, size)) {
+ return;
+ }
+
+ if (s.info.print_insn == NULL) {
+ s.info.print_insn = print_insn_od_host;
+ }
+ for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
+ fprintf(out, "0x%08" PRIxPTR ": ", pc);
+ count = s.info.print_insn(pc, &s.info);
+ fprintf(out, "\n");
+ if (count < 0) {
+ break;
+ }
+ }
+}
diff --git a/disas/disas-internal.h b/disas/disas-internal.h
index 84a01f126f..ed32e704cc 100644
--- a/disas/disas-internal.h
+++ b/disas/disas-internal.h
@@ -14,8 +14,12 @@ typedef struct CPUDebug {
CPUState *cpu;
} CPUDebug;
+void disas_initialize_debug(CPUDebug *s);
void disas_initialize_debug_target(CPUDebug *s, CPUState *cpu);
int disas_gstring_printf(FILE *stream, const char *fmt, ...)
G_GNUC_PRINTF(2, 3);
+int print_insn_od_host(bfd_vma pc, disassemble_info *info);
+int print_insn_od_target(bfd_vma pc, disassemble_info *info);
+
#endif
diff --git a/disas/disas-mon.c b/disas/disas-mon.c
index 5d6d9aa02d..37bf16ac79 100644
--- a/disas/disas-mon.c
+++ b/disas/disas-mon.c
@@ -11,6 +11,19 @@
#include "hw/core/cpu.h"
#include "monitor/monitor.h"
+/*
+ * Get LENGTH bytes from info's buffer, at target address memaddr.
+ * Transfer them to myaddr.
+ */
+static int
+virtual_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
+ struct disassemble_info *info)
+{
+ CPUDebug *s = container_of(info, CPUDebug, info);
+ int r = cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0);
+ return r ? EIO : 0;
+}
+
static int
physical_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
struct disassemble_info *info)
@@ -38,6 +51,8 @@ void monitor_disas(Monitor *mon, CPUState *cpu, uint64_t pc,
if (is_physical) {
s.info.read_memory_func = physical_read_memory;
+ } else {
+ s.info.read_memory_func = virtual_read_memory;
}
s.info.buffer_vma = pc;
diff --git a/disas/disas-target.c b/disas/disas-target.c
new file mode 100644
index 0000000000..48f3a365dc
--- /dev/null
+++ b/disas/disas-target.c
@@ -0,0 +1,99 @@
+/*
+ * Routines for target instruction disassembly.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "disas/disas.h"
+#include "disas/capstone.h"
+#include "exec/translator.h"
+#include "disas-internal.h"
+
+
+static int translator_read_memory(bfd_vma memaddr, bfd_byte *myaddr,
+ int length, struct disassemble_info *info)
+{
+ const DisasContextBase *db = info->application_data;
+ return translator_st(db, myaddr, memaddr, length) ? 0 : EIO;
+}
+
+void target_disas(FILE *out, CPUState *cpu, const struct DisasContextBase *db)
+{
+ uint64_t code = db->pc_first;
+ size_t size = translator_st_len(db);
+ uint64_t pc;
+ int count;
+ CPUDebug s;
+
+ disas_initialize_debug_target(&s, cpu);
+ s.info.read_memory_func = translator_read_memory;
+ s.info.application_data = (void *)db;
+ s.info.fprintf_func = fprintf;
+ s.info.stream = out;
+ s.info.buffer_vma = code;
+ s.info.buffer_length = size;
+ s.info.show_opcodes = true;
+
+ if (s.info.cap_arch >= 0 && cap_disas_target(&s.info, code, size)) {
+ return;
+ }
+
+ if (s.info.print_insn == NULL) {
+ s.info.print_insn = print_insn_od_target;
+ }
+
+ for (pc = code; size > 0; pc += count, size -= count) {
+ fprintf(out, "0x%08" PRIx64 ": ", pc);
+ count = s.info.print_insn(pc, &s.info);
+ fprintf(out, "\n");
+ if (count < 0) {
+ break;
+ }
+ if (size < count) {
+ fprintf(out,
+ "Disassembler disagrees with translator over instruction "
+ "decoding\n"
+ "Please report this to qemu-devel@nongnu.org\n");
+ break;
+ }
+ }
+}
+
+#ifdef CONFIG_PLUGIN
+static void plugin_print_address(bfd_vma addr, struct disassemble_info *info)
+{
+ /* does nothing */
+}
+
+/*
+ * We should only be dissembling one instruction at a time here. If
+ * there is left over it usually indicates the front end has read more
+ * bytes than it needed.
+ */
+char *plugin_disas(CPUState *cpu, const DisasContextBase *db,
+ uint64_t addr, size_t size)
+{
+ CPUDebug s;
+ GString *ds = g_string_new(NULL);
+
+ disas_initialize_debug_target(&s, cpu);
+ s.info.read_memory_func = translator_read_memory;
+ s.info.application_data = (void *)db;
+ s.info.fprintf_func = disas_gstring_printf;
+ s.info.stream = (FILE *)ds; /* abuse this slot */
+ s.info.buffer_vma = addr;
+ s.info.buffer_length = size;
+ s.info.print_address_func = plugin_print_address;
+
+ if (s.info.cap_arch >= 0 && cap_disas_plugin(&s.info, addr, size)) {
+ ; /* done */
+ } else if (s.info.print_insn) {
+ s.info.print_insn(addr, &s.info);
+ } else {
+ ; /* cannot disassemble -- return empty string */
+ }
+
+ /* Return the buffer, freeing the GString container. */
+ return g_string_free(ds, false);
+}
+#endif /* CONFIG_PLUGIN */
diff --git a/disas/disas.c b/disas/disas.c
deleted file mode 100644
index ec14715ecd..0000000000
--- a/disas/disas.c
+++ /dev/null
@@ -1,338 +0,0 @@
-/* General "disassemble this chunk" code. Used for debugging. */
-#include "qemu/osdep.h"
-#include "disas/disas-internal.h"
-#include "elf.h"
-#include "qemu/qemu-print.h"
-#include "disas/disas.h"
-#include "disas/capstone.h"
-#include "hw/core/cpu.h"
-#include "exec/tswap.h"
-#include "exec/memory.h"
-
-/* Filled in by elfload.c. Simplistic, but will do for now. */
-struct syminfo *syminfos = NULL;
-
-/*
- * Get LENGTH bytes from info's buffer, at host address memaddr.
- * Transfer them to myaddr.
- */
-static int host_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
- struct disassemble_info *info)
-{
- if (memaddr < info->buffer_vma
- || memaddr + length > info->buffer_vma + info->buffer_length) {
- /* Out of bounds. Use EIO because GDB uses it. */
- return EIO;
- }
- memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
- return 0;
-}
-
-/*
- * Get LENGTH bytes from info's buffer, at target address memaddr.
- * Transfer them to myaddr.
- */
-static int target_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
- struct disassemble_info *info)
-{
- CPUDebug *s = container_of(info, CPUDebug, info);
- int r = cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0);
- return r ? EIO : 0;
-}
-
-/*
- * Print an error message. We can assume that this is in response to
- * an error return from {host,target}_read_memory.
- */
-static void perror_memory(int status, bfd_vma memaddr,
- struct disassemble_info *info)
-{
- if (status != EIO) {
- /* Can't happen. */
- info->fprintf_func(info->stream, "Unknown error %d\n", status);
- } else {
- /* Address between memaddr and memaddr + len was out of bounds. */
- info->fprintf_func(info->stream,
- "Address 0x%" PRIx64 " is out of bounds.\n",
- memaddr);
- }
-}
-
-/* Print address in hex. */
-static void print_address(bfd_vma addr, struct disassemble_info *info)
-{
- info->fprintf_func(info->stream, "0x%" PRIx64, addr);
-}
-
-/* Print address in hex, truncated to the width of a host virtual address. */
-static void host_print_address(bfd_vma addr, struct disassemble_info *info)
-{
- print_address((uintptr_t)addr, info);
-}
-
-/* Stub prevents some fruitless earching in optabs disassemblers. */
-static int symbol_at_address(bfd_vma addr, struct disassemble_info *info)
-{
- return 1;
-}
-
-static int print_insn_objdump(bfd_vma pc, disassemble_info *info,
- const char *prefix)
-{
- int i, n = info->buffer_length;
- g_autofree uint8_t *buf = g_malloc(n);
-
- if (info->read_memory_func(pc, buf, n, info) == 0) {
- for (i = 0; i < n; ++i) {
- if (i % 32 == 0) {
- info->fprintf_func(info->stream, "\n%s: ", prefix);
- }
- info->fprintf_func(info->stream, "%02x", buf[i]);
- }
- } else {
- info->fprintf_func(info->stream, "unable to read memory");
- }
- return n;
-}
-
-static int print_insn_od_host(bfd_vma pc, disassemble_info *info)
-{
- return print_insn_objdump(pc, info, "OBJD-H");
-}
-
-static int print_insn_od_target(bfd_vma pc, disassemble_info *info)
-{
- return print_insn_objdump(pc, info, "OBJD-T");
-}
-
-static void initialize_debug(CPUDebug *s)
-{
- memset(s, 0, sizeof(*s));
- s->info.arch = bfd_arch_unknown;
- s->info.cap_arch = -1;
- s->info.cap_insn_unit = 4;
- s->info.cap_insn_split = 4;
- s->info.memory_error_func = perror_memory;
- s->info.symbol_at_address_func = symbol_at_address;
-}
-
-void disas_initialize_debug_target(CPUDebug *s, CPUState *cpu)
-{
- initialize_debug(s);
-
- s->cpu = cpu;
- s->info.read_memory_func = target_read_memory;
- s->info.print_address_func = print_address;
- if (target_words_bigendian()) {
- s->info.endian = BFD_ENDIAN_BIG;
- } else {
- s->info.endian = BFD_ENDIAN_LITTLE;
- }
-
- CPUClass *cc = CPU_GET_CLASS(cpu);
- if (cc->disas_set_info) {
- cc->disas_set_info(cpu, &s->info);
- }
-}
-
-static void initialize_debug_host(CPUDebug *s)
-{
- initialize_debug(s);
-
- s->info.read_memory_func = host_read_memory;
- s->info.print_address_func = host_print_address;
-#if HOST_BIG_ENDIAN
- s->info.endian = BFD_ENDIAN_BIG;
-#else
- s->info.endian = BFD_ENDIAN_LITTLE;
-#endif
-#if defined(CONFIG_TCG_INTERPRETER)
- s->info.print_insn = print_insn_tci;
-#elif defined(__i386__)
- s->info.mach = bfd_mach_i386_i386;
- s->info.cap_arch = CS_ARCH_X86;
- s->info.cap_mode = CS_MODE_32;
- s->info.cap_insn_unit = 1;
- s->info.cap_insn_split = 8;
-#elif defined(__x86_64__)
- s->info.mach = bfd_mach_x86_64;
- s->info.cap_arch = CS_ARCH_X86;
- s->info.cap_mode = CS_MODE_64;
- s->info.cap_insn_unit = 1;
- s->info.cap_insn_split = 8;
-#elif defined(_ARCH_PPC)
- s->info.cap_arch = CS_ARCH_PPC;
-# ifdef _ARCH_PPC64
- s->info.cap_mode = CS_MODE_64;
-# endif
-#elif defined(__riscv)
-#if defined(_ILP32) || (__riscv_xlen == 32)
- s->info.print_insn = print_insn_riscv32;
-#elif defined(_LP64)
- s->info.print_insn = print_insn_riscv64;
-#else
-#error unsupported RISC-V ABI
-#endif
-#elif defined(__aarch64__)
- s->info.cap_arch = CS_ARCH_ARM64;
-#elif defined(__alpha__)
- s->info.print_insn = print_insn_alpha;
-#elif defined(__sparc__)
- s->info.print_insn = print_insn_sparc;
- s->info.mach = bfd_mach_sparc_v9b;
-#elif defined(__arm__)
- /* TCG only generates code for arm mode. */
- s->info.cap_arch = CS_ARCH_ARM;
-#elif defined(__MIPSEB__)
- s->info.print_insn = print_insn_big_mips;
-#elif defined(__MIPSEL__)
- s->info.print_insn = print_insn_little_mips;
-#elif defined(__m68k__)
- s->info.print_insn = print_insn_m68k;
-#elif defined(__s390__)
- s->info.cap_arch = CS_ARCH_SYSZ;
- s->info.cap_insn_unit = 2;
- s->info.cap_insn_split = 6;
-#elif defined(__hppa__)
- s->info.print_insn = print_insn_hppa;
-#elif defined(__loongarch__)
- s->info.print_insn = print_insn_loongarch;
-#endif
-}
-
-/* Disassemble this for me please... (debugging). */
-void target_disas(FILE *out, CPUState *cpu, uint64_t code, size_t size)
-{
- uint64_t pc;
- int count;
- CPUDebug s;
-
- disas_initialize_debug_target(&s, cpu);
- s.info.fprintf_func = fprintf;
- s.info.stream = out;
- s.info.buffer_vma = code;
- s.info.buffer_length = size;
- s.info.show_opcodes = true;
-
- if (s.info.cap_arch >= 0 && cap_disas_target(&s.info, code, size)) {
- return;
- }
-
- if (s.info.print_insn == NULL) {
- s.info.print_insn = print_insn_od_target;
- }
-
- for (pc = code; size > 0; pc += count, size -= count) {
- fprintf(out, "0x%08" PRIx64 ": ", pc);
- count = s.info.print_insn(pc, &s.info);
- fprintf(out, "\n");
- if (count < 0) {
- break;
- }
- if (size < count) {
- fprintf(out,
- "Disassembler disagrees with translator over instruction "
- "decoding\n"
- "Please report this to qemu-devel@nongnu.org\n");
- break;
- }
- }
-}
-
-int disas_gstring_printf(FILE *stream, const char *fmt, ...)
-{
- /* We abuse the FILE parameter to pass a GString. */
- GString *s = (GString *)stream;
- int initial_len = s->len;
- va_list va;
-
- va_start(va, fmt);
- g_string_append_vprintf(s, fmt, va);
- va_end(va);
-
- return s->len - initial_len;
-}
-
-static void plugin_print_address(bfd_vma addr, struct disassemble_info *info)
-{
- /* does nothing */
-}
-
-
-/*
- * We should only be dissembling one instruction at a time here. If
- * there is left over it usually indicates the front end has read more
- * bytes than it needed.
- */
-char *plugin_disas(CPUState *cpu, uint64_t addr, size_t size)
-{
- CPUDebug s;
- GString *ds = g_string_new(NULL);
-
- disas_initialize_debug_target(&s, cpu);
- s.info.fprintf_func = disas_gstring_printf;
- s.info.stream = (FILE *)ds; /* abuse this slot */
- s.info.buffer_vma = addr;
- s.info.buffer_length = size;
- s.info.print_address_func = plugin_print_address;
-
- if (s.info.cap_arch >= 0 && cap_disas_plugin(&s.info, addr, size)) {
- ; /* done */
- } else if (s.info.print_insn) {
- s.info.print_insn(addr, &s.info);
- } else {
- ; /* cannot disassemble -- return empty string */
- }
-
- /* Return the buffer, freeing the GString container. */
- return g_string_free(ds, false);
-}
-
-/* Disassemble this for me please... (debugging). */
-void disas(FILE *out, const void *code, size_t size)
-{
- uintptr_t pc;
- int count;
- CPUDebug s;
-
- initialize_debug_host(&s);
- s.info.fprintf_func = fprintf;
- s.info.stream = out;
- s.info.buffer = code;
- s.info.buffer_vma = (uintptr_t)code;
- s.info.buffer_length = size;
- s.info.show_opcodes = true;
-
- if (s.info.cap_arch >= 0 && cap_disas_host(&s.info, code, size)) {
- return;
- }
-
- if (s.info.print_insn == NULL) {
- s.info.print_insn = print_insn_od_host;
- }
- for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
- fprintf(out, "0x%08" PRIxPTR ": ", pc);
- count = s.info.print_insn(pc, &s.info);
- fprintf(out, "\n");
- if (count < 0) {
- break;
- }
- }
-
-}
-
-/* Look up symbol for debugging purpose. Returns "" if unknown. */
-const char *lookup_symbol(uint64_t orig_addr)
-{
- const char *symbol = "";
- struct syminfo *s;
-
- for (s = syminfos; s; s = s->next) {
- symbol = s->lookup_symbol(s, orig_addr);
- if (symbol[0] != '\0') {
- break;
- }
- }
-
- return symbol;
-}
diff --git a/disas/meson.build b/disas/meson.build
index 5c8073beb3..20d6aef9a7 100644
--- a/disas/meson.build
+++ b/disas/meson.build
@@ -14,7 +14,11 @@ common_ss.add(when: 'CONFIG_SH4_DIS', if_true: files('sh4.c'))
common_ss.add(when: 'CONFIG_SPARC_DIS', if_true: files('sparc.c'))
common_ss.add(when: 'CONFIG_XTENSA_DIS', if_true: files('xtensa.c'))
common_ss.add(when: capstone, if_true: [files('capstone.c'), capstone])
-common_ss.add(files('disas.c'))
-
+common_ss.add(when: 'CONFIG_TCG', if_true: files(
+ 'disas-host.c',
+ 'disas-target.c',
+ 'objdump.c'
+))
+common_ss.add(files('disas-common.c'))
system_ss.add(files('disas-mon.c'))
specific_ss.add(capstone)
diff --git a/disas/objdump.c b/disas/objdump.c
new file mode 100644
index 0000000000..9859f23419
--- /dev/null
+++ b/disas/objdump.c
@@ -0,0 +1,37 @@
+/*
+ * Dump disassembly as text, for processing by scripts/disas-objdump.pl.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "disas-internal.h"
+
+
+static int print_insn_objdump(bfd_vma pc, disassemble_info *info,
+ const char *prefix)
+{
+ int i, n = info->buffer_length;
+ g_autofree uint8_t *buf = g_malloc(n);
+
+ if (info->read_memory_func(pc, buf, n, info) == 0) {
+ for (i = 0; i < n; ++i) {
+ if (i % 32 == 0) {
+ info->fprintf_func(info->stream, "\n%s: ", prefix);
+ }
+ info->fprintf_func(info->stream, "%02x", buf[i]);
+ }
+ } else {
+ info->fprintf_func(info->stream, "unable to read memory");
+ }
+ return n;
+}
+
+int print_insn_od_host(bfd_vma pc, disassemble_info *info)
+{
+ return print_insn_objdump(pc, info, "OBJD-H");
+}
+
+int print_insn_od_target(bfd_vma pc, disassemble_info *info)
+{
+ return print_insn_objdump(pc, info, "OBJD-T");
+}
diff --git a/include/disas/disas.h b/include/disas/disas.h
index 176775eff7..c702b1effc 100644
--- a/include/disas/disas.h
+++ b/include/disas/disas.h
@@ -2,13 +2,18 @@
#define QEMU_DISAS_H
/* Disassemble this for me please... (debugging). */
+#ifdef CONFIG_TCG
void disas(FILE *out, const void *code, size_t size);
-void target_disas(FILE *out, CPUState *cpu, uint64_t code, size_t size);
+void target_disas(FILE *out, CPUState *cpu, const DisasContextBase *db);
+#endif
void monitor_disas(Monitor *mon, CPUState *cpu, uint64_t pc,
int nb_insn, bool is_physical);
-char *plugin_disas(CPUState *cpu, uint64_t addr, size_t size);
+#ifdef CONFIG_PLUGIN
+char *plugin_disas(CPUState *cpu, const DisasContextBase *db,
+ uint64_t addr, size_t size);
+#endif
/* Look up symbol for debugging purpose. Returns "" if unknown. */
const char *lookup_symbol(uint64_t orig_addr);
diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h
index 11ba3778ba..71009f84f5 100644
--- a/include/exec/cpu_ldst.h
+++ b/include/exec/cpu_ldst.h
@@ -355,16 +355,6 @@ uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr addr);
uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr addr);
uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr);
-static inline int cpu_ldsb_code(CPUArchState *env, abi_ptr addr)
-{
- return (int8_t)cpu_ldub_code(env, addr);
-}
-
-static inline int cpu_ldsw_code(CPUArchState *env, abi_ptr addr)
-{
- return (int16_t)cpu_lduw_code(env, addr);
-}
-
/**
* tlb_vaddr_to_host:
* @env: CPUArchState
diff --git a/include/exec/plugin-gen.h b/include/exec/plugin-gen.h
index f333f33198..cbb2ca2131 100644
--- a/include/exec/plugin-gen.h
+++ b/include/exec/plugin-gen.h
@@ -18,8 +18,7 @@ struct DisasContextBase;
#ifdef CONFIG_PLUGIN
-bool plugin_gen_tb_start(CPUState *cpu, const struct DisasContextBase *db,
- bool supress);
+bool plugin_gen_tb_start(CPUState *cpu, const struct DisasContextBase *db);
void plugin_gen_tb_end(CPUState *cpu, size_t num_insns);
void plugin_gen_insn_start(CPUState *cpu, const struct DisasContextBase *db);
void plugin_gen_insn_end(void);
@@ -28,8 +27,8 @@ void plugin_gen_disable_mem_helpers(void);
#else /* !CONFIG_PLUGIN */
-static inline bool
-plugin_gen_tb_start(CPUState *cpu, const struct DisasContextBase *db, bool sup)
+static inline
+bool plugin_gen_tb_start(CPUState *cpu, const struct DisasContextBase *db)
{
return false;
}
diff --git a/include/exec/translator.h b/include/exec/translator.h
index 6cd937ac5c..25004dfb76 100644
--- a/include/exec/translator.h
+++ b/include/exec/translator.h
@@ -19,10 +19,7 @@
*/
#include "qemu/bswap.h"
-#include "exec/cpu-common.h"
-#include "exec/cpu-defs.h"
-#include "exec/abi_ptr.h"
-#include "cpu.h"
+#include "exec/vaddr.h"
/**
* gen_intermediate_code
@@ -75,14 +72,14 @@ typedef enum DisasJumpType {
* @num_insns: Number of translated instructions (including current).
* @max_insns: Maximum number of instructions to be translated in this TB.
* @singlestep_enabled: "Hardware" single stepping enabled.
- * @saved_can_do_io: Known value of cpu->neg.can_do_io, or -1 for unknown.
* @plugin_enabled: TCG plugin enabled in this TB.
+ * @fake_insn: True if translator_fake_ldb used.
* @insn_start: The last op emitted by the insn_start hook,
* which is expected to be INDEX_op_insn_start.
*
* Architecture-agnostic disassembly context.
*/
-typedef struct DisasContextBase {
+struct DisasContextBase {
TranslationBlock *tb;
vaddr pc_first;
vaddr pc_next;
@@ -91,9 +88,22 @@ typedef struct DisasContextBase {
int max_insns;
bool singlestep_enabled;
bool plugin_enabled;
+ bool fake_insn;
struct TCGOp *insn_start;
void *host_addr[2];
-} DisasContextBase;
+
+ /*
+ * 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];
+};
/**
* TranslatorOps:
@@ -125,7 +135,7 @@ typedef struct TranslatorOps {
void (*insn_start)(DisasContextBase *db, CPUState *cpu);
void (*translate_insn)(DisasContextBase *db, CPUState *cpu);
void (*tb_stop)(DisasContextBase *db, CPUState *cpu);
- void (*disas_log)(const DisasContextBase *db, CPUState *cpu, FILE *f);
+ bool (*disas_log)(const DisasContextBase *db, CPUState *cpu, FILE *f);
} TranslatorOps;
/**
@@ -185,14 +195,14 @@ bool translator_io_start(DisasContextBase *db);
* the relevant information at translation time.
*/
-uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, abi_ptr pc);
-uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, abi_ptr pc);
-uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, abi_ptr pc);
-uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, abi_ptr pc);
+uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, vaddr pc);
+uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, vaddr pc);
+uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, vaddr pc);
+uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, vaddr pc);
static inline uint16_t
translator_lduw_swap(CPUArchState *env, DisasContextBase *db,
- abi_ptr pc, bool do_swap)
+ vaddr pc, bool do_swap)
{
uint16_t ret = translator_lduw(env, db, pc);
if (do_swap) {
@@ -203,7 +213,7 @@ translator_lduw_swap(CPUArchState *env, DisasContextBase *db,
static inline uint32_t
translator_ldl_swap(CPUArchState *env, DisasContextBase *db,
- abi_ptr pc, bool do_swap)
+ vaddr pc, bool do_swap)
{
uint32_t ret = translator_ldl(env, db, pc);
if (do_swap) {
@@ -214,7 +224,7 @@ translator_ldl_swap(CPUArchState *env, DisasContextBase *db,
static inline uint64_t
translator_ldq_swap(CPUArchState *env, DisasContextBase *db,
- abi_ptr pc, bool do_swap)
+ vaddr pc, bool do_swap)
{
uint64_t ret = translator_ldq(env, db, pc);
if (do_swap) {
@@ -224,17 +234,42 @@ translator_ldq_swap(CPUArchState *env, DisasContextBase *db,
}
/**
- * translator_fake_ldb - fake instruction load
- * @insn8: byte of instruction
- * @pc: program counter of instruction
+ * translator_fake_ld - fake instruction load
+ * @db: Disassembly context
+ * @data: bytes of instruction
+ * @len: number of bytes
*
* This is a special case helper used where the instruction we are
* about to translate comes from somewhere else (e.g. being
* re-synthesised for s390x "ex"). It ensures we update other areas of
* the translator with details of the executed instruction.
*/
-void translator_fake_ldb(uint8_t insn8, abi_ptr pc);
+void translator_fake_ld(DisasContextBase *db, const void *data, size_t len);
+
+/**
+ * translator_st
+ * @db: disassembly context
+ * @dest: address to copy into
+ * @addr: virtual address within TB
+ * @len: length
+ *
+ * Copy @len bytes from @addr into @dest.
+ * All bytes must have been read during translation.
+ * Return true on success or false on failure.
+ */
+bool translator_st(const DisasContextBase *db, void *dest,
+ vaddr addr, size_t len);
+
+/**
+ * translator_st_len
+ * @db: disassembly context
+ *
+ * Return the number of bytes available to copy from the
+ * current translation block with translator_st.
+ */
+size_t translator_st_len(const DisasContextBase *db);
+#ifdef COMPILING_PER_TARGET
/*
* Return whether addr is on the same page as where disassembly started.
* Translators can use this to enforce the rule that only single-insn
@@ -244,5 +279,6 @@ static inline bool is_same_page(const DisasContextBase *db, vaddr addr)
{
return ((addr ^ db->pc_first) & TARGET_PAGE_MASK) == 0;
}
+#endif
#endif /* EXEC__TRANSLATOR_H */
diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
index b535bfd5de..7fda6ef126 100644
--- a/include/qemu/plugin.h
+++ b/include/qemu/plugin.h
@@ -98,17 +98,14 @@ struct qemu_plugin_dyn_cb {
/* Internal context for instrumenting an instruction */
struct qemu_plugin_insn {
- GByteArray *data;
uint64_t vaddr;
- void *haddr;
GArray *insn_cbs;
GArray *mem_cbs;
+ uint8_t len;
bool calls_helpers;
/* if set, the instruction calls helpers that might access guest memory */
bool mem_helper;
-
- bool mem_only;
};
/* A scoreboard is an array of values, indexed by vcpu_index */
@@ -117,27 +114,10 @@ struct qemu_plugin_scoreboard {
QLIST_ENTRY(qemu_plugin_scoreboard) entry;
};
-/*
- * qemu_plugin_insn allocate and cleanup functions. We don't expect to
- * cleanup many of these structures. They are reused for each fresh
- * translation.
- */
-
-static inline void qemu_plugin_insn_cleanup_fn(gpointer data)
-{
- struct qemu_plugin_insn *insn = (struct qemu_plugin_insn *) data;
- g_byte_array_free(insn->data, true);
-}
-
/* Internal context for this TranslationBlock */
struct qemu_plugin_tb {
GPtrArray *insns;
size_t n;
- uint64_t vaddr;
- uint64_t vaddr2;
- void *haddr1;
- void *haddr2;
- bool mem_only;
/* if set, the TB calls helpers that might access guest memory */
bool mem_helper;
diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
index 4fc6c3739b..5f36c2d1ac 100644
--- a/include/qemu/qemu-plugin.h
+++ b/include/qemu/qemu-plugin.h
@@ -61,7 +61,7 @@ typedef uint64_t qemu_plugin_id_t;
extern QEMU_PLUGIN_EXPORT int qemu_plugin_version;
-#define QEMU_PLUGIN_VERSION 2
+#define QEMU_PLUGIN_VERSION 3
/**
* struct qemu_info_t - system information for plugins
@@ -394,17 +394,16 @@ struct qemu_plugin_insn *
qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx);
/**
- * qemu_plugin_insn_data() - return ptr to instruction data
+ * qemu_plugin_insn_data() - copy instruction data
* @insn: opaque instruction handle from qemu_plugin_tb_get_insn()
+ * @dest: destination into which data is copied
+ * @len: length of dest
*
- * Note: data is only valid for duration of callback. See
- * qemu_plugin_insn_size() to calculate size of stream.
- *
- * Returns: pointer to a stream of bytes containing the value of this
- * instructions opcode.
+ * Returns the number of bytes copied, minimum of @len and insn size.
*/
QEMU_PLUGIN_API
-const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn);
+size_t qemu_plugin_insn_data(const struct qemu_plugin_insn *insn,
+ void *dest, size_t len);
/**
* qemu_plugin_insn_size() - return size of instruction
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index b47e7179e2..9d222dc376 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -42,6 +42,7 @@ typedef struct CPUPluginState CPUPluginState;
typedef struct CPUState CPUState;
typedef struct DeviceState DeviceState;
typedef struct DirtyBitmapSnapshot DirtyBitmapSnapshot;
+typedef struct DisasContextBase DisasContextBase;
typedef struct DisplayChangeListener DisplayChangeListener;
typedef struct DriveInfo DriveInfo;
typedef struct DumpState DumpState;
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index 135e36d729..2a1c080bab 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -537,6 +537,7 @@ struct TCGContext {
* space for instructions (for variable-instruction-length ISAs).
*/
struct qemu_plugin_tb *plugin_tb;
+ const struct DisasContextBase *plugin_db;
/* descriptor of the instruction being translated */
struct qemu_plugin_insn *plugin_insn;
diff --git a/plugins/api.c b/plugins/api.c
index 2144da1fe8..b04c5e1928 100644
--- a/plugins/api.c
+++ b/plugins/api.c
@@ -42,6 +42,7 @@
#include "tcg/tcg.h"
#include "exec/exec-all.h"
#include "exec/gdbstub.h"
+#include "exec/translator.h"
#include "disas/disas.h"
#include "plugin.h"
#ifndef CONFIG_USER_ONLY
@@ -86,12 +87,17 @@ void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,
plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_EXIT, cb);
}
+static bool tb_is_mem_only(void)
+{
+ return tb_cflags(tcg_ctx->gen_tb) & CF_MEMI_ONLY;
+}
+
void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
qemu_plugin_vcpu_udata_cb_t cb,
enum qemu_plugin_cb_flags flags,
void *udata)
{
- if (!tb->mem_only) {
+ if (!tb_is_mem_only()) {
plugin_register_dyn_cb__udata(&tb->cbs, cb, flags, udata);
}
}
@@ -102,7 +108,7 @@ void qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(
qemu_plugin_u64 entry,
uint64_t imm)
{
- if (!tb->mem_only) {
+ if (!tb_is_mem_only()) {
plugin_register_inline_op_on_entry(&tb->cbs, 0, op, entry, imm);
}
}
@@ -112,7 +118,7 @@ void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
enum qemu_plugin_cb_flags flags,
void *udata)
{
- if (!insn->mem_only) {
+ if (!tb_is_mem_only()) {
plugin_register_dyn_cb__udata(&insn->insn_cbs, cb, flags, udata);
}
}
@@ -123,7 +129,7 @@ void qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(
qemu_plugin_u64 entry,
uint64_t imm)
{
- if (!insn->mem_only) {
+ if (!tb_is_mem_only()) {
plugin_register_inline_op_on_entry(&insn->insn_cbs, 0, op, entry, imm);
}
}
@@ -194,7 +200,8 @@ size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb)
uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb)
{
- return tb->vaddr;
+ const DisasContextBase *db = tcg_ctx->plugin_db;
+ return db->pc_first;
}
struct qemu_plugin_insn *
@@ -205,7 +212,6 @@ qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx)
return NULL;
}
insn = g_ptr_array_index(tb->insns, idx);
- insn->mem_only = tb->mem_only;
return insn;
}
@@ -216,14 +222,18 @@ qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx)
* instruction being translated.
*/
-const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn)
+size_t qemu_plugin_insn_data(const struct qemu_plugin_insn *insn,
+ void *dest, size_t len)
{
- return insn->data->data;
+ const DisasContextBase *db = tcg_ctx->plugin_db;
+
+ len = MIN(len, insn->len);
+ return translator_st(db, dest, insn->vaddr, len) ? len : 0;
}
size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn)
{
- return insn->data->len;
+ return insn->len;
}
uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn)
@@ -233,13 +243,36 @@ uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn)
void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn)
{
- return insn->haddr;
+ const DisasContextBase *db = tcg_ctx->plugin_db;
+ vaddr page0_last = db->pc_first | ~TARGET_PAGE_MASK;
+
+ if (db->fake_insn) {
+ return NULL;
+ }
+
+ /*
+ * ??? The return value is not intended for use of host memory,
+ * but as a proxy for address space and physical address.
+ * Thus we are only interested in the first byte and do not
+ * care about spanning pages.
+ */
+ if (insn->vaddr <= page0_last) {
+ if (db->host_addr[0] == NULL) {
+ return NULL;
+ }
+ return db->host_addr[0] + insn->vaddr - db->pc_first;
+ } else {
+ if (db->host_addr[1] == NULL) {
+ return NULL;
+ }
+ return db->host_addr[1] + insn->vaddr - (page0_last + 1);
+ }
}
char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn)
{
- CPUState *cpu = current_cpu;
- return plugin_disas(cpu, insn->vaddr, insn->data->len);
+ return plugin_disas(tcg_ctx->cpu, tcg_ctx->plugin_db,
+ insn->vaddr, insn->len);
}
const char *qemu_plugin_insn_symbol(const struct qemu_plugin_insn *insn)
diff --git a/target/alpha/translate.c b/target/alpha/translate.c
index db847e7a23..fb6cac4b53 100644
--- a/target/alpha/translate.c
+++ b/target/alpha/translate.c
@@ -20,7 +20,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "sysemu/cpus.h"
-#include "disas/disas.h"
#include "qemu/host-utils.h"
#include "exec/exec-all.h"
#include "tcg/tcg-op.h"
@@ -2947,20 +2946,12 @@ static void alpha_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
}
}
-static void alpha_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cpu, FILE *logfile)
-{
- fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
- target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
-}
-
static const TranslatorOps alpha_tr_ops = {
.init_disas_context = alpha_tr_init_disas_context,
.tb_start = alpha_tr_tb_start,
.insn_start = alpha_tr_insn_start,
.translate_insn = alpha_tr_translate_insn,
.tb_stop = alpha_tr_tb_stop,
- .disas_log = alpha_tr_disas_log,
};
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 976094a5c8..4126aaa27e 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -22,7 +22,6 @@
#include "translate.h"
#include "translate-a64.h"
#include "qemu/log.h"
-#include "disas/disas.h"
#include "arm_ldst.h"
#include "semihosting/semihost.h"
#include "cpregs.h"
@@ -14382,20 +14381,10 @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
}
}
-static void aarch64_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cpu, FILE *logfile)
-{
- DisasContext *dc = container_of(dcbase, DisasContext, base);
-
- fprintf(logfile, "IN: %s\n", lookup_symbol(dc->base.pc_first));
- target_disas(logfile, cpu, dc->base.pc_first, dc->base.tb->size);
-}
-
const TranslatorOps aarch64_translator_ops = {
.init_disas_context = aarch64_tr_init_disas_context,
.tb_start = aarch64_tr_tb_start,
.insn_start = aarch64_tr_insn_start,
.translate_insn = aarch64_tr_translate_insn,
.tb_stop = aarch64_tr_tb_stop,
- .disas_log = aarch64_tr_disas_log,
};
diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c
index dc49a8d806..d605e10f11 100644
--- a/target/arm/tcg/translate.c
+++ b/target/arm/tcg/translate.c
@@ -23,7 +23,6 @@
#include "translate.h"
#include "translate-a32.h"
#include "qemu/log.h"
-#include "disas/disas.h"
#include "arm_ldst.h"
#include "semihosting/semihost.h"
#include "cpregs.h"
@@ -9663,22 +9662,12 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
}
}
-static void arm_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cpu, FILE *logfile)
-{
- DisasContext *dc = container_of(dcbase, DisasContext, base);
-
- fprintf(logfile, "IN: %s\n", lookup_symbol(dc->base.pc_first));
- target_disas(logfile, cpu, dc->base.pc_first, dc->base.tb->size);
-}
-
static const TranslatorOps arm_translator_ops = {
.init_disas_context = arm_tr_init_disas_context,
.tb_start = arm_tr_tb_start,
.insn_start = arm_tr_insn_start,
.translate_insn = arm_tr_translate_insn,
.tb_stop = arm_tr_tb_stop,
- .disas_log = arm_tr_disas_log,
};
static const TranslatorOps thumb_translator_ops = {
@@ -9687,7 +9676,6 @@ static const TranslatorOps thumb_translator_ops = {
.insn_start = arm_tr_insn_start,
.translate_insn = thumb_tr_translate_insn,
.tb_stop = arm_tr_tb_stop,
- .disas_log = arm_tr_disas_log,
};
/* generate intermediate code for basic block 'tb'. */
diff --git a/target/avr/translate.c b/target/avr/translate.c
index 87e2bd5ef1..2d51892115 100644
--- a/target/avr/translate.c
+++ b/target/avr/translate.c
@@ -24,7 +24,6 @@
#include "cpu.h"
#include "exec/exec-all.h"
#include "tcg/tcg-op.h"
-#include "exec/cpu_ldst.h"
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
#include "exec/log.h"
@@ -173,7 +172,7 @@ static int to_regs_00_30_by_two(DisasContext *ctx, int indx)
static uint16_t next_word(DisasContext *ctx)
{
- return cpu_lduw_code(ctx->env, ctx->npc++ * 2);
+ return translator_lduw(ctx->env, &ctx->base, ctx->npc++ * 2);
}
static int append_16(DisasContext *ctx, int x)
@@ -2787,20 +2786,12 @@ static void avr_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
}
}
-static void avr_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cs, FILE *logfile)
-{
- fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
- target_disas(logfile, cs, dcbase->pc_first, dcbase->tb->size);
-}
-
static const TranslatorOps avr_tr_ops = {
.init_disas_context = avr_tr_init_disas_context,
.tb_start = avr_tr_tb_start,
.insn_start = avr_tr_insn_start,
.translate_insn = avr_tr_translate_insn,
.tb_stop = avr_tr_tb_stop,
- .disas_log = avr_tr_disas_log,
};
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
diff --git a/target/cris/translate.c b/target/cris/translate.c
index b3a4d61d0a..a30c67eb07 100644
--- a/target/cris/translate.c
+++ b/target/cris/translate.c
@@ -25,12 +25,10 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "disas/disas.h"
#include "exec/exec-all.h"
#include "tcg/tcg-op.h"
#include "exec/helper-proto.h"
#include "mmu.h"
-#include "exec/cpu_ldst.h"
#include "exec/translator.h"
#include "crisv32-decode.h"
#include "qemu/qemu-print.h"
@@ -223,37 +221,28 @@ static int sign_extend(unsigned int val, unsigned int width)
}
static int cris_fetch(CPUCRISState *env, DisasContext *dc, uint32_t addr,
- unsigned int size, unsigned int sign)
+ unsigned int size, bool sign)
{
int r;
switch (size) {
case 4:
- {
- r = cpu_ldl_code(env, addr);
+ r = translator_ldl(env, &dc->base, addr);
break;
- }
case 2:
- {
+ r = translator_lduw(env, &dc->base, addr);
if (sign) {
- r = cpu_ldsw_code(env, addr);
- } else {
- r = cpu_lduw_code(env, addr);
+ r = (int16_t)r;
}
break;
- }
case 1:
- {
+ r = translator_ldub(env, &dc->base, addr);
if (sign) {
- r = cpu_ldsb_code(env, addr);
- } else {
- r = cpu_ldub_code(env, addr);
+ r = (int8_t)r;
}
break;
- }
default:
- cpu_abort(CPU(dc->cpu), "Invalid fetch size %d\n", size);
- break;
+ g_assert_not_reached();
}
return r;
}
@@ -2869,7 +2858,7 @@ static unsigned int crisv32_decoder(CPUCRISState *env, DisasContext *dc)
int i;
/* Load a halfword onto the instruction register. */
- dc->ir = cris_fetch(env, dc, dc->pc, 2, 0);
+ dc->ir = cris_fetch(env, dc, dc->pc, 2, 0);
/* Now decode it. */
dc->opcode = EXTRACT_FIELD(dc->ir, 4, 11);
@@ -3148,22 +3137,12 @@ static void cris_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
}
}
-static void cris_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cpu, FILE *logfile)
-{
- if (!DISAS_CRIS) {
- fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
- target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
- }
-}
-
static const TranslatorOps cris_tr_ops = {
.init_disas_context = cris_tr_init_disas_context,
.tb_start = cris_tr_tb_start,
.insn_start = cris_tr_insn_start,
.translate_insn = cris_tr_translate_insn,
.tb_stop = cris_tr_tb_stop,
- .disas_log = cris_tr_disas_log,
};
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
diff --git a/target/cris/translate_v10.c.inc b/target/cris/translate_v10.c.inc
index 73fc27c15d..c15ff47505 100644
--- a/target/cris/translate_v10.c.inc
+++ b/target/cris/translate_v10.c.inc
@@ -165,20 +165,7 @@ static int dec10_prep_move_m(CPUCRISState *env, DisasContext *dc,
/* Load [$rs] onto T1. */
if (is_imm) {
- if (memsize != 4) {
- if (s_ext) {
- if (memsize == 1)
- imm = cpu_ldsb_code(env, dc->pc + 2);
- else
- imm = cpu_ldsw_code(env, dc->pc + 2);
- } else {
- if (memsize == 1)
- imm = cpu_ldub_code(env, dc->pc + 2);
- else
- imm = cpu_lduw_code(env, dc->pc + 2);
- }
- } else
- imm = cpu_ldl_code(env, dc->pc + 2);
+ imm = cris_fetch(env, dc, dc->pc + 2, memsize, s_ext);
tcg_gen_movi_tl(dst, imm);
@@ -929,10 +916,11 @@ static int dec10_dip(CPUCRISState *env, DisasContext *dc)
LOG_DIS("dip pc=%x opcode=%d r%d r%d\n",
dc->pc, dc->opcode, dc->src, dc->dst);
if (dc->src == 15) {
- imm = cpu_ldl_code(env, dc->pc + 2);
+ imm = cris_fetch(env, dc, dc->pc + 2, 4, 0);
tcg_gen_movi_tl(cpu_PR[PR_PREFIX], imm);
- if (dc->postinc)
+ if (dc->postinc) {
insn_len += 4;
+ }
tcg_gen_addi_tl(cpu_R[15], cpu_R[15], insn_len - 2);
} else {
gen_load(dc, cpu_PR[PR_PREFIX], cpu_R[dc->src], 4, 0);
@@ -1095,10 +1083,10 @@ static unsigned int dec10_ind(CPUCRISState *env, DisasContext *dc)
if (dc->src == 15) {
LOG_DIS("jump.%d %d r%d r%d direct\n", size,
dc->opcode, dc->src, dc->dst);
- imm = cpu_ldl_code(env, dc->pc + 2);
- if (dc->mode == CRISV10_MODE_AUTOINC)
+ imm = cris_fetch(env, dc, dc->pc + 2, size, 0);
+ if (dc->mode == CRISV10_MODE_AUTOINC) {
insn_len += size;
-
+ }
c = tcg_constant_tl(dc->pc + insn_len);
t_gen_mov_preg_TN(dc, dc->dst, c);
dc->jmp_pc = imm;
@@ -1164,7 +1152,7 @@ static unsigned int dec10_ind(CPUCRISState *env, DisasContext *dc)
case CRISV10_IND_BCC_M:
cris_cc_mask(dc, 0);
- simm = cpu_ldsw_code(env, dc->pc + 2);
+ simm = cris_fetch(env, dc, dc->pc + 2, 2, 1);
simm += 4;
LOG_DIS("bcc_m: b%s %x\n", cc_name(dc->cond), dc->pc + simm);
@@ -1185,7 +1173,7 @@ static unsigned int crisv10_decoder(CPUCRISState *env, DisasContext *dc)
unsigned int insn_len = 2;
/* Load a halfword onto the instruction register. */
- dc->ir = cpu_lduw_code(env, dc->pc);
+ dc->ir = cris_fetch(env, dc, dc->pc, 2, 0);
/* Now decode it. */
dc->opcode = EXTRACT_FIELD(dc->ir, 6, 9);
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 0904dc2d38..4b1bee3c6d 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -1022,7 +1022,7 @@ static bool pkt_crosses_page(CPUHexagonState *env, DisasContext *ctx)
int nwords;
for (nwords = 0; !found_end && nwords < PACKET_WORDS_MAX; nwords++) {
- uint32_t word = cpu_ldl_code(env,
+ uint32_t word = translator_ldl(env, &ctx->base,
ctx->base.pc_next + nwords * sizeof(uint32_t));
found_end = is_packet_end(word);
}
@@ -1075,21 +1075,12 @@ static void hexagon_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
}
}
-static void hexagon_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cpu, FILE *logfile)
-{
- fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
- target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
-}
-
-
static const TranslatorOps hexagon_tr_ops = {
.init_disas_context = hexagon_tr_init_disas_context,
.tb_start = hexagon_tr_tb_start,
.insn_start = hexagon_tr_insn_start,
.translate_insn = hexagon_tr_translate_packet,
.tb_stop = hexagon_tr_tb_stop,
- .disas_log = hexagon_tr_disas_log,
};
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index 6d45611888..7287e1debf 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -19,7 +19,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "disas/disas.h"
#include "qemu/host-utils.h"
#include "exec/exec-all.h"
#include "exec/page-protection.h"
@@ -4816,31 +4815,29 @@ static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
}
}
-static void hppa_tr_disas_log(const DisasContextBase *dcbase,
+#ifdef CONFIG_USER_ONLY
+static bool hppa_tr_disas_log(const DisasContextBase *dcbase,
CPUState *cs, FILE *logfile)
{
target_ulong pc = dcbase->pc_first;
-#ifdef CONFIG_USER_ONLY
switch (pc) {
case 0x00:
fprintf(logfile, "IN:\n0x00000000: (null)\n");
- return;
+ return true;
case 0xb0:
fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n");
- return;
+ return true;
case 0xe0:
fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n");
- return;
+ return true;
case 0x100:
fprintf(logfile, "IN:\n0x00000100: syscall\n");
- return;
+ return true;
}
-#endif
-
- fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
- target_disas(logfile, cs, pc, dcbase->tb->size);
+ return false;
}
+#endif
static const TranslatorOps hppa_tr_ops = {
.init_disas_context = hppa_tr_init_disas_context,
@@ -4848,7 +4845,9 @@ static const TranslatorOps hppa_tr_ops = {
.insn_start = hppa_tr_insn_start,
.translate_insn = hppa_tr_translate_insn,
.tb_stop = hppa_tr_tb_stop,
+#ifdef CONFIG_USER_ONLY
.disas_log = hppa_tr_disas_log,
+#endif
};
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index de87775016..76be742580 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -20,11 +20,9 @@
#include "qemu/host-utils.h"
#include "cpu.h"
-#include "disas/disas.h"
#include "exec/exec-all.h"
#include "tcg/tcg-op.h"
#include "tcg/tcg-op-gvec.h"
-#include "exec/cpu_ldst.h"
#include "exec/translator.h"
#include "fpu/softfloat.h"
@@ -1580,9 +1578,8 @@ static uint64_t advance_pc(CPUX86State *env, DisasContext *s, int num_bytes)
* This can happen even if the operand is only one byte long!
*/
if (((s->pc - 1) ^ (pc - 1)) & TARGET_PAGE_MASK) {
- volatile uint8_t unused =
- cpu_ldub_code(env, (s->pc - 1) & TARGET_PAGE_MASK);
- (void) unused;
+ (void)translator_ldub(env, &s->base,
+ (s->pc - 1) & TARGET_PAGE_MASK);
}
siglongjmp(s->jmpbuf, 1);
}
@@ -2178,7 +2175,7 @@ static void gen_unknown_opcode(CPUX86State *env, DisasContext *s)
fprintf(logfile, "ILLOPC: " TARGET_FMT_lx ":", pc);
for (; pc < end; ++pc) {
- fprintf(logfile, " %02x", cpu_ldub_code(env, pc));
+ fprintf(logfile, " %02x", translator_ldub(env, &s->base, pc));
}
fprintf(logfile, "\n");
qemu_log_unlock(logfile);
@@ -4798,22 +4795,12 @@ static void i386_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
}
}
-static void i386_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cpu, FILE *logfile)
-{
- DisasContext *dc = container_of(dcbase, DisasContext, base);
-
- fprintf(logfile, "IN: %s\n", lookup_symbol(dc->base.pc_first));
- target_disas(logfile, cpu, dc->base.pc_first, dc->base.tb->size);
-}
-
static const TranslatorOps i386_tr_ops = {
.init_disas_context = i386_tr_init_disas_context,
.tb_start = i386_tr_tb_start,
.insn_start = i386_tr_insn_start,
.translate_insn = i386_tr_translate_insn,
.tb_stop = i386_tr_tb_stop,
- .disas_log = i386_tr_disas_log,
};
/* generate intermediate code for basic block 'tb'. */
diff --git a/target/loongarch/tcg/translate.c b/target/loongarch/tcg/translate.c
index 7567712655..1fca4afc73 100644
--- a/target/loongarch/tcg/translate.c
+++ b/target/loongarch/tcg/translate.c
@@ -325,20 +325,12 @@ static void loongarch_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
}
}
-static void loongarch_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cpu, FILE *logfile)
-{
- qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
- target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
-}
-
static const TranslatorOps loongarch_tr_ops = {
.init_disas_context = loongarch_tr_init_disas_context,
.tb_start = loongarch_tr_tb_start,
.insn_start = loongarch_tr_insn_start,
.translate_insn = loongarch_tr_translate_insn,
.tb_stop = loongarch_tr_tb_stop,
- .disas_log = loongarch_tr_disas_log,
};
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 169927552a..445966fb6a 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -20,7 +20,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "disas/disas.h"
#include "exec/exec-all.h"
#include "tcg/tcg-op.h"
#include "qemu/log.h"
@@ -6105,20 +6104,12 @@ static void m68k_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
}
}
-static void m68k_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cpu, FILE *logfile)
-{
- fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
- target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
-}
-
static const TranslatorOps m68k_tr_ops = {
.init_disas_context = m68k_tr_init_disas_context,
.tb_start = m68k_tr_tb_start,
.insn_start = m68k_tr_insn_start,
.translate_insn = m68k_tr_translate_insn,
.tb_stop = m68k_tr_tb_stop,
- .disas_log = m68k_tr_disas_log,
};
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c
index 6d89c1a175..4beaf69e76 100644
--- a/target/microblaze/translate.c
+++ b/target/microblaze/translate.c
@@ -20,7 +20,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "disas/disas.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
#include "tcg/tcg-op.h"
@@ -1637,7 +1636,7 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
dc->tb_flags_to_set = 0;
- ir = cpu_ldl_code(cpu_env(cs), dc->base.pc_next);
+ ir = translator_ldl(cpu_env(cs), &dc->base, dc->base.pc_next);
if (!decode(dc, ir)) {
trap_illegal(dc, true);
}
@@ -1771,20 +1770,12 @@ static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
}
}
-static void mb_tr_disas_log(const DisasContextBase *dcb,
- CPUState *cs, FILE *logfile)
-{
- fprintf(logfile, "IN: %s\n", lookup_symbol(dcb->pc_first));
- target_disas(logfile, cs, dcb->pc_first, dcb->tb->size);
-}
-
static const TranslatorOps mb_tr_ops = {
.init_disas_context = mb_tr_init_disas_context,
.tb_start = mb_tr_tb_start,
.insn_start = mb_tr_insn_start,
.translate_insn = mb_tr_translate_insn,
.tb_stop = mb_tr_tb_stop,
- .disas_log = mb_tr_disas_log,
};
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c
index 06c108cc9c..333469b268 100644
--- a/target/mips/tcg/translate.c
+++ b/target/mips/tcg/translate.c
@@ -29,7 +29,6 @@
#include "exec/translation-block.h"
#include "semihosting/semihost.h"
#include "trace.h"
-#include "disas/disas.h"
#include "fpu_helper.h"
#define HELPER_H "helper.h"
@@ -15475,20 +15474,12 @@ static void mips_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
}
}
-static void mips_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cs, FILE *logfile)
-{
- fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
- target_disas(logfile, cs, dcbase->pc_first, dcbase->tb->size);
-}
-
static const TranslatorOps mips_tr_ops = {
.init_disas_context = mips_tr_init_disas_context,
.tb_start = mips_tr_tb_start,
.insn_start = mips_tr_insn_start,
.translate_insn = mips_tr_translate_insn,
.tb_stop = mips_tr_tb_stop,
- .disas_log = mips_tr_disas_log,
};
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
index 23fff46084..ca566847cb 100644
--- a/target/openrisc/translate.c
+++ b/target/openrisc/translate.c
@@ -21,7 +21,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "exec/exec-all.h"
-#include "disas/disas.h"
#include "tcg/tcg-op.h"
#include "qemu/log.h"
#include "qemu/bitops.h"
@@ -1638,22 +1637,12 @@ static void openrisc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
}
}
-static void openrisc_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cs, FILE *logfile)
-{
- DisasContext *s = container_of(dcbase, DisasContext, base);
-
- fprintf(logfile, "IN: %s\n", lookup_symbol(s->base.pc_first));
- target_disas(logfile, cs, s->base.pc_first, s->base.tb->size);
-}
-
static const TranslatorOps openrisc_tr_ops = {
.init_disas_context = openrisc_tr_init_disas_context,
.tb_start = openrisc_tr_tb_start,
.insn_start = openrisc_tr_insn_start,
.translate_insn = openrisc_tr_translate_insn,
.tb_stop = openrisc_tr_tb_stop,
- .disas_log = openrisc_tr_disas_log,
};
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 93ffec787c..49dee6cab0 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -21,7 +21,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
-#include "disas/disas.h"
#include "exec/exec-all.h"
#include "tcg/tcg-op.h"
#include "tcg/tcg-op-gvec.h"
@@ -7405,20 +7404,12 @@ static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
}
}
-static void ppc_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cs, FILE *logfile)
-{
- fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
- target_disas(logfile, cs, dcbase->pc_first, dcbase->tb->size);
-}
-
static const TranslatorOps ppc_tr_ops = {
.init_disas_context = ppc_tr_init_disas_context,
.tb_start = ppc_tr_tb_start,
.insn_start = ppc_tr_insn_start,
.translate_insn = ppc_tr_translate_insn,
.tb_stop = ppc_tr_tb_stop,
- .disas_log = ppc_tr_disas_log,
};
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 9ff09ebdb6..2c27fd4ce1 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -20,8 +20,6 @@
#include "qemu/log.h"
#include "cpu.h"
#include "tcg/tcg-op.h"
-#include "disas/disas.h"
-#include "exec/cpu_ldst.h"
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
@@ -1083,7 +1081,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
CPUState *cpu = ctx->cs;
CPURISCVState *env = cpu_env(cpu);
- return cpu_ldl_code(env, pc);
+ return translator_ldl(env, &ctx->base, pc);
}
/* Include insn module translation function */
@@ -1244,7 +1242,8 @@ static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
unsigned page_ofs = ctx->base.pc_next & ~TARGET_PAGE_MASK;
if (page_ofs > TARGET_PAGE_SIZE - MAX_INSN_LEN) {
- uint16_t next_insn = cpu_lduw_code(env, ctx->base.pc_next);
+ uint16_t next_insn =
+ translator_lduw(env, &ctx->base, ctx->base.pc_next);
int len = insn_len(next_insn);
if (!is_same_page(&ctx->base, ctx->base.pc_next + len - 1)) {
@@ -1270,29 +1269,12 @@ static void riscv_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
}
}
-static void riscv_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cpu, FILE *logfile)
-{
-#ifndef CONFIG_USER_ONLY
- RISCVCPU *rvcpu = RISCV_CPU(cpu);
- CPURISCVState *env = &rvcpu->env;
-#endif
-
- fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
-#ifndef CONFIG_USER_ONLY
- fprintf(logfile, "Priv: "TARGET_FMT_ld"; Virt: %d\n",
- env->priv, env->virt_enabled);
-#endif
- target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
-}
-
static const TranslatorOps riscv_tr_ops = {
.init_disas_context = riscv_tr_init_disas_context,
.tb_start = riscv_tr_tb_start,
.insn_start = riscv_tr_insn_start,
.translate_insn = riscv_tr_translate_insn,
.tb_stop = riscv_tr_tb_stop,
- .disas_log = riscv_tr_disas_log,
};
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
diff --git a/target/rx/translate.c b/target/rx/translate.c
index f6e9e0ec90..9b81cf20b3 100644
--- a/target/rx/translate.c
+++ b/target/rx/translate.c
@@ -22,7 +22,6 @@
#include "cpu.h"
#include "exec/exec-all.h"
#include "tcg/tcg-op.h"
-#include "exec/cpu_ldst.h"
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
#include "exec/translator.h"
@@ -75,10 +74,10 @@ static TCGv_i64 cpu_acc;
/* decoder helper */
static uint32_t decode_load_bytes(DisasContext *ctx, uint32_t insn,
- int i, int n)
+ int i, int n)
{
while (++i <= n) {
- uint8_t b = cpu_ldub_code(ctx->env, ctx->base.pc_next++);
+ uint8_t b = translator_ldub(ctx->env, &ctx->base, ctx->base.pc_next++);
insn |= b << (32 - i * 8);
}
return insn;
@@ -90,22 +89,24 @@ static uint32_t li(DisasContext *ctx, int sz)
CPURXState *env = ctx->env;
addr = ctx->base.pc_next;
- tcg_debug_assert(sz < 4);
switch (sz) {
case 1:
ctx->base.pc_next += 1;
- return cpu_ldsb_code(env, addr);
+ return (int8_t)translator_ldub(env, &ctx->base, addr);
case 2:
ctx->base.pc_next += 2;
- return cpu_ldsw_code(env, addr);
+ return (int16_t)translator_lduw(env, &ctx->base, addr);
case 3:
ctx->base.pc_next += 3;
- tmp = cpu_ldsb_code(env, addr + 2) << 16;
- tmp |= cpu_lduw_code(env, addr) & 0xffff;
+ tmp = (int8_t)translator_ldub(env, &ctx->base, addr + 2);
+ tmp <<= 16;
+ tmp |= translator_lduw(env, &ctx->base, addr);
return tmp;
case 0:
ctx->base.pc_next += 4;
- return cpu_ldl_code(env, addr);
+ return translator_ldl(env, &ctx->base, addr);
+ default:
+ g_assert_not_reached();
}
return 0;
}
@@ -190,22 +191,22 @@ static inline TCGv rx_index_addr(DisasContext *ctx, TCGv mem,
{
uint32_t dsp;
- tcg_debug_assert(ld < 3);
switch (ld) {
case 0:
return cpu_regs[reg];
case 1:
- dsp = cpu_ldub_code(ctx->env, ctx->base.pc_next) << size;
+ dsp = translator_ldub(ctx->env, &ctx->base, ctx->base.pc_next) << size;
tcg_gen_addi_i32(mem, cpu_regs[reg], dsp);
ctx->base.pc_next += 1;
return mem;
case 2:
- dsp = cpu_lduw_code(ctx->env, ctx->base.pc_next) << size;
+ dsp = translator_lduw(ctx->env, &ctx->base, ctx->base.pc_next) << size;
tcg_gen_addi_i32(mem, cpu_regs[reg], dsp);
ctx->base.pc_next += 2;
return mem;
+ default:
+ g_assert_not_reached();
}
- return NULL;
}
static inline MemOp mi_to_mop(unsigned mi)
@@ -2247,20 +2248,12 @@ static void rx_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
}
}
-static void rx_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cs, FILE *logfile)
-{
- fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
- target_disas(logfile, cs, dcbase->pc_first, dcbase->tb->size);
-}
-
static const TranslatorOps rx_tr_ops = {
.init_disas_context = rx_tr_init_disas_context,
.tb_start = rx_tr_tb_start,
.insn_start = rx_tr_insn_start,
.translate_insn = rx_tr_translate_insn,
.tb_stop = rx_tr_tb_stop,
- .disas_log = rx_tr_disas_log,
};
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
index 90a74ee795..ebd96abe6c 100644
--- a/target/s390x/tcg/translate.c
+++ b/target/s390x/tcg/translate.c
@@ -31,13 +31,11 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "s390x-internal.h"
-#include "disas/disas.h"
#include "exec/exec-all.h"
#include "tcg/tcg-op.h"
#include "tcg/tcg-op-gvec.h"
#include "qemu/log.h"
#include "qemu/host-utils.h"
-#include "exec/cpu_ldst.h"
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
@@ -6192,6 +6190,8 @@ static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s)
const DisasInsn *info;
if (unlikely(s->ex_value)) {
+ uint64_t be_insn;
+
/* Drop the EX data now, so that it's clear on exception paths. */
tcg_gen_st_i64(tcg_constant_i64(0), tcg_env,
offsetof(CPUS390XState, ex_value));
@@ -6199,13 +6199,11 @@ static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s)
/* Extract the values saved by EXECUTE. */
insn = s->ex_value & 0xffffffffffff0000ull;
ilen = s->ex_value & 0xf;
+ op = insn >> 56;
/* Register insn bytes with translator so plugins work. */
- for (int i = 0; i < ilen; i++) {
- uint8_t byte = extract64(insn, 56 - (i * 8), 8);
- translator_fake_ldb(byte, pc + i);
- }
- op = insn >> 56;
+ be_insn = cpu_to_be64(insn);
+ translator_fake_ld(&s->base, &be_insn, get_ilen(op));
} else {
insn = ld_code2(env, s, pc);
op = (insn >> 8) & 0xff;
@@ -6472,7 +6470,7 @@ static void s390x_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
static target_ulong get_next_pc(CPUS390XState *env, DisasContext *s,
uint64_t pc)
{
- uint64_t insn = cpu_lduw_code(env, pc);
+ uint64_t insn = translator_lduw(env, &s->base, pc);
return pc + get_ilen((insn >> 8) & 0xff);
}
@@ -6520,18 +6518,18 @@ static void s390x_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
}
}
-static void s390x_tr_disas_log(const DisasContextBase *dcbase,
+static bool s390x_tr_disas_log(const DisasContextBase *dcbase,
CPUState *cs, FILE *logfile)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
if (unlikely(dc->ex_value)) {
- /* ??? Unfortunately target_disas can't use host memory. */
- fprintf(logfile, "IN: EXECUTE %016" PRIx64, dc->ex_value);
- } else {
- fprintf(logfile, "IN: %s\n", lookup_symbol(dc->base.pc_first));
- target_disas(logfile, cs, dc->base.pc_first, dc->base.tb->size);
+ /* The ex_value has been recorded with translator_fake_ld. */
+ fprintf(logfile, "IN: EXECUTE\n");
+ target_disas(logfile, cs, &dc->base);
+ return true;
}
+ return false;
}
static const TranslatorOps s390x_tr_ops = {
diff --git a/target/sh4/translate.c b/target/sh4/translate.c
index b3282f3ac7..53b092175d 100644
--- a/target/sh4/translate.c
+++ b/target/sh4/translate.c
@@ -19,7 +19,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "disas/disas.h"
#include "exec/exec-all.h"
#include "tcg/tcg-op.h"
#include "exec/helper-proto.h"
@@ -2310,20 +2309,12 @@ static void sh4_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
}
}
-static void sh4_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cs, FILE *logfile)
-{
- fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
- target_disas(logfile, cs, dcbase->pc_first, dcbase->tb->size);
-}
-
static const TranslatorOps sh4_tr_ops = {
.init_disas_context = sh4_tr_init_disas_context,
.tb_start = sh4_tr_tb_start,
.insn_start = sh4_tr_insn_start,
.translate_insn = sh4_tr_translate_insn,
.tb_stop = sh4_tr_tb_stop,
- .disas_log = sh4_tr_disas_log,
};
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 99c6f3cc72..dca072888a 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -21,7 +21,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "disas/disas.h"
#include "exec/helper-proto.h"
#include "exec/exec-all.h"
#include "tcg/tcg-op.h"
@@ -5149,20 +5148,12 @@ static void sparc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
}
}
-static void sparc_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cpu, FILE *logfile)
-{
- fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
- target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
-}
-
static const TranslatorOps sparc_tr_ops = {
.init_disas_context = sparc_tr_init_disas_context,
.tb_start = sparc_tr_tb_start,
.insn_start = sparc_tr_insn_start,
.translate_insn = sparc_tr_translate_insn,
.tb_stop = sparc_tr_tb_stop,
- .disas_log = sparc_tr_disas_log,
};
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
diff --git a/target/tricore/translate.c b/target/tricore/translate.c
index c45e1d992e..a46a03e1fd 100644
--- a/target/tricore/translate.c
+++ b/target/tricore/translate.c
@@ -20,7 +20,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "disas/disas.h"
#include "exec/exec-all.h"
#include "tcg/tcg-op.h"
#include "exec/cpu_ldst.h"
@@ -8453,20 +8452,12 @@ static void tricore_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
}
}
-static void tricore_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cpu, FILE *logfile)
-{
- fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
- target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
-}
-
static const TranslatorOps tricore_tr_ops = {
.init_disas_context = tricore_tr_init_disas_context,
.tb_start = tricore_tr_tb_start,
.insn_start = tricore_tr_insn_start,
.translate_insn = tricore_tr_translate_insn,
.tb_stop = tricore_tr_tb_stop,
- .disas_log = tricore_tr_disas_log,
};
diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
index b206d57fc4..75b7bfda4c 100644
--- a/target/xtensa/translate.c
+++ b/target/xtensa/translate.c
@@ -32,11 +32,9 @@
#include "cpu.h"
#include "exec/exec-all.h"
-#include "disas/disas.h"
#include "tcg/tcg-op.h"
#include "qemu/log.h"
#include "qemu/qemu-print.h"
-#include "exec/cpu_ldst.h"
#include "semihosting/semihost.h"
#include "exec/translator.h"
@@ -1119,7 +1117,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
static inline unsigned xtensa_insn_len(CPUXtensaState *env, DisasContext *dc)
{
- uint8_t b0 = cpu_ldub_code(env, dc->pc);
+ uint8_t b0 = translator_ldub(env, &dc->base, dc->pc);
return xtensa_op0_insn_len(dc, b0);
}
@@ -1221,20 +1219,12 @@ static void xtensa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
}
}
-static void xtensa_tr_disas_log(const DisasContextBase *dcbase,
- CPUState *cpu, FILE *logfile)
-{
- fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
- target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
-}
-
static const TranslatorOps xtensa_translator_ops = {
.init_disas_context = xtensa_tr_init_disas_context,
.tb_start = xtensa_tr_tb_start,
.insn_start = xtensa_tr_insn_start,
.translate_insn = xtensa_tr_translate_insn,
.tb_stop = xtensa_tr_tb_stop,
- .disas_log = xtensa_tr_disas_log,
};
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc
index 69c5b8ac4f..06ca1ab11c 100644
--- a/tcg/loongarch64/tcg-target.c.inc
+++ b/tcg/loongarch64/tcg-target.c.inc
@@ -808,18 +808,88 @@ static void tcg_out_ldst(TCGContext *s, LoongArchInsn opc, TCGReg data,
}
}
-static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg,
- TCGReg arg1, intptr_t arg2)
+static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg dest,
+ TCGReg base, intptr_t offset)
{
- bool is_32bit = type == TCG_TYPE_I32;
- tcg_out_ldst(s, is_32bit ? OPC_LD_W : OPC_LD_D, arg, arg1, arg2);
+ switch (type) {
+ case TCG_TYPE_I32:
+ if (dest < TCG_REG_V0) {
+ tcg_out_ldst(s, OPC_LD_W, dest, base, offset);
+ } else {
+ tcg_out_dupm_vec(s, TCG_TYPE_I128, MO_32, dest, base, offset);
+ }
+ break;
+ case TCG_TYPE_I64:
+ if (dest < TCG_REG_V0) {
+ tcg_out_ldst(s, OPC_LD_D, dest, base, offset);
+ } else {
+ tcg_out_dupm_vec(s, TCG_TYPE_I128, MO_64, dest, base, offset);
+ }
+ break;
+ case TCG_TYPE_V128:
+ if (-0x800 <= offset && offset <= 0x7ff) {
+ tcg_out_opc_vld(s, dest, base, offset);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP0, offset);
+ tcg_out_opc_vldx(s, dest, base, TCG_REG_TMP0);
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
}
-static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
- TCGReg arg1, intptr_t arg2)
+static void tcg_out_st(TCGContext *s, TCGType type, TCGReg src,
+ TCGReg base, intptr_t offset)
{
- bool is_32bit = type == TCG_TYPE_I32;
- tcg_out_ldst(s, is_32bit ? OPC_ST_W : OPC_ST_D, arg, arg1, arg2);
+ switch (type) {
+ case TCG_TYPE_I32:
+ if (src < TCG_REG_V0) {
+ tcg_out_ldst(s, OPC_ST_W, src, base, offset);
+ } else {
+ /* TODO: Could use fst_s, fstx_s */
+ if (offset < -0x100 || offset > 0xff || (offset & 3)) {
+ if (-0x800 <= offset && offset <= 0x7ff) {
+ tcg_out_opc_addi_d(s, TCG_REG_TMP0, base, offset);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP0, offset);
+ tcg_out_opc_add_d(s, TCG_REG_TMP0, TCG_REG_TMP0, base);
+ }
+ base = TCG_REG_TMP0;
+ offset = 0;
+ }
+ tcg_out_opc_vstelm_w(s, src, base, offset, 0);
+ }
+ break;
+ case TCG_TYPE_I64:
+ if (src < TCG_REG_V0) {
+ tcg_out_ldst(s, OPC_ST_D, src, base, offset);
+ } else {
+ /* TODO: Could use fst_d, fstx_d */
+ if (offset < -0x100 || offset > 0xff || (offset & 7)) {
+ if (-0x800 <= offset && offset <= 0x7ff) {
+ tcg_out_opc_addi_d(s, TCG_REG_TMP0, base, offset);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP0, offset);
+ tcg_out_opc_add_d(s, TCG_REG_TMP0, TCG_REG_TMP0, base);
+ }
+ base = TCG_REG_TMP0;
+ offset = 0;
+ }
+ tcg_out_opc_vstelm_d(s, src, base, offset, 0);
+ }
+ break;
+ case TCG_TYPE_V128:
+ if (-0x800 <= offset && offset <= 0x7ff) {
+ tcg_out_opc_vst(s, src, base, offset);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP0, offset);
+ tcg_out_opc_vstx(s, src, base, TCG_REG_TMP0);
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
}
static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
@@ -1740,7 +1810,6 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
{
TCGType type = vecl + TCG_TYPE_V64;
TCGArg a0, a1, a2, a3;
- TCGReg temp = TCG_REG_TMP0;
TCGReg temp_vec = TCG_VEC_TMP0;
static const LoongArchInsn cmp_vec_insn[16][4] = {
@@ -1820,22 +1889,10 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
switch (opc) {
case INDEX_op_st_vec:
- /* Try to fit vst imm */
- if (-0x800 <= a2 && a2 <= 0x7ff) {
- tcg_out_opc_vst(s, a0, a1, a2);
- } else {
- tcg_out_movi(s, TCG_TYPE_I64, temp, a2);
- tcg_out_opc_vstx(s, a0, a1, temp);
- }
+ tcg_out_st(s, type, a0, a1, a2);
break;
case INDEX_op_ld_vec:
- /* Try to fit vld imm */
- if (-0x800 <= a2 && a2 <= 0x7ff) {
- tcg_out_opc_vld(s, a0, a1, a2);
- } else {
- tcg_out_movi(s, TCG_TYPE_I64, temp, a2);
- tcg_out_opc_vldx(s, a0, a1, temp);
- }
+ tcg_out_ld(s, type, a0, a1, a2);
break;
case INDEX_op_and_vec:
tcg_out_opc_vand_v(s, a0, a1, a2);
diff --git a/tcg/tcg.c b/tcg/tcg.c
index d827c6d431..34e3056380 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -761,15 +761,6 @@ QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) -
< MIN_TLB_MASK_TABLE_OFS);
#endif
-static void alloc_tcg_plugin_context(TCGContext *s)
-{
-#ifdef CONFIG_PLUGIN
- s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
- s->plugin_tb->insns =
- g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
-#endif
-}
-
/*
* All TCG threads except the parent (i.e. the one that called tcg_context_init
* and registered the target's TCG globals) must register with this function
@@ -814,7 +805,6 @@ void tcg_register_thread(void)
qatomic_set(&tcg_ctxs[n], s);
if (n > 0) {
- alloc_tcg_plugin_context(s);
tcg_region_initial_alloc(s);
}
@@ -1361,8 +1351,6 @@ static void tcg_context_init(unsigned max_cpus)
indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
}
- alloc_tcg_plugin_context(s);
-
tcg_ctx = s;
/*
* In user-mode we simply share the init context among threads, since we