mirror of
https://github.com/qemu/qemu.git
synced 2025-08-16 23:02:44 +00:00
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----- 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>
This commit is contained in:
commit
2b01688380
@ -188,7 +188,7 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
|
|||||||
int insn_idx = -1;
|
int insn_idx = -1;
|
||||||
|
|
||||||
if (unlikely(qemu_loglevel_mask(LOG_TB_OP_PLUGIN)
|
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();
|
FILE *logfile = qemu_log_trylock();
|
||||||
if (logfile) {
|
if (logfile) {
|
||||||
fprintf(logfile, "OP before plugin injection:\n");
|
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 plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db)
|
||||||
bool mem_only)
|
|
||||||
{
|
{
|
||||||
bool ret = false;
|
struct qemu_plugin_tb *ptb;
|
||||||
|
|
||||||
if (test_bit(QEMU_PLUGIN_EV_VCPU_TB_TRANS, cpu->plugin_state->event_mask)) {
|
if (!test_bit(QEMU_PLUGIN_EV_VCPU_TB_TRANS,
|
||||||
struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
|
cpu->plugin_state->event_mask)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* reset callbacks */
|
tcg_ctx->plugin_db = db;
|
||||||
|
tcg_ctx->plugin_insn = NULL;
|
||||||
|
ptb = tcg_ctx->plugin_tb;
|
||||||
|
|
||||||
|
if (ptb) {
|
||||||
|
/* Reset callbacks */
|
||||||
if (ptb->cbs) {
|
if (ptb->cbs) {
|
||||||
g_array_set_size(ptb->cbs, 0);
|
g_array_set_size(ptb->cbs, 0);
|
||||||
}
|
}
|
||||||
ptb->n = 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;
|
ptb->mem_helper = false;
|
||||||
|
} else {
|
||||||
tcg_gen_plugin_cb(PLUGIN_GEN_FROM_TB);
|
ptb = g_new0(struct qemu_plugin_tb, 1);
|
||||||
|
tcg_ctx->plugin_tb = ptb;
|
||||||
|
ptb->insns = g_ptr_array_new();
|
||||||
}
|
}
|
||||||
|
|
||||||
tcg_ctx->plugin_insn = NULL;
|
tcg_gen_plugin_cb(PLUGIN_GEN_FROM_TB);
|
||||||
|
return true;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
|
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;
|
ptb->n = n;
|
||||||
if (n <= ptb->insns->len) {
|
if (n <= ptb->insns->len) {
|
||||||
insn = g_ptr_array_index(ptb->insns, n - 1);
|
insn = g_ptr_array_index(ptb->insns, n - 1);
|
||||||
g_byte_array_set_size(insn->data, 0);
|
|
||||||
} else {
|
} else {
|
||||||
assert(n - 1 == ptb->insns->len);
|
assert(n - 1 == ptb->insns->len);
|
||||||
insn = g_new0(struct qemu_plugin_insn, 1);
|
insn = g_new0(struct qemu_plugin_insn, 1);
|
||||||
insn->data = g_byte_array_sized_new(4);
|
|
||||||
g_ptr_array_add(ptb->insns, insn);
|
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;
|
pc = db->pc_next;
|
||||||
insn->vaddr = pc;
|
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);
|
tcg_gen_plugin_cb(PLUGIN_GEN_FROM_INSN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void plugin_gen_insn_end(void)
|
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);
|
tcg_gen_plugin_cb(PLUGIN_GEN_AFTER_INSN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,8 +14,10 @@
|
|||||||
#include "exec/translator.h"
|
#include "exec/translator.h"
|
||||||
#include "exec/cpu_ldst.h"
|
#include "exec/cpu_ldst.h"
|
||||||
#include "exec/plugin-gen.h"
|
#include "exec/plugin-gen.h"
|
||||||
|
#include "exec/cpu_ldst.h"
|
||||||
#include "tcg/tcg-op-common.h"
|
#include "tcg/tcg-op-common.h"
|
||||||
#include "internal-target.h"
|
#include "internal-target.h"
|
||||||
|
#include "disas/disas.h"
|
||||||
|
|
||||||
static void set_can_do_io(DisasContextBase *db, bool val)
|
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->max_insns = *max_insns;
|
||||||
db->singlestep_enabled = cflags & CF_SINGLE_STEP;
|
db->singlestep_enabled = cflags & CF_SINGLE_STEP;
|
||||||
db->insn_start = NULL;
|
db->insn_start = NULL;
|
||||||
|
db->fake_insn = false;
|
||||||
db->host_addr[0] = host_pc;
|
db->host_addr[0] = host_pc;
|
||||||
db->host_addr[1] = NULL;
|
db->host_addr[1] = NULL;
|
||||||
|
db->record_start = 0;
|
||||||
|
db->record_len = 0;
|
||||||
|
|
||||||
ops->init_disas_context(db, cpu);
|
ops->init_disas_context(db, cpu);
|
||||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
||||||
@ -140,7 +145,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
|||||||
ops->tb_start(db, cpu);
|
ops->tb_start(db, cpu);
|
||||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
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;
|
db->plugin_enabled = plugin_enabled;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -222,159 +227,249 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
|||||||
FILE *logfile = qemu_log_trylock();
|
FILE *logfile = qemu_log_trylock();
|
||||||
if (logfile) {
|
if (logfile) {
|
||||||
fprintf(logfile, "----------------\n");
|
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");
|
fprintf(logfile, "\n");
|
||||||
qemu_log_unlock(logfile);
|
qemu_log_unlock(logfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *translator_access(CPUArchState *env, DisasContextBase *db,
|
static bool translator_ld(CPUArchState *env, DisasContextBase *db,
|
||||||
vaddr pc, size_t len)
|
void *dest, vaddr pc, size_t len)
|
||||||
{
|
{
|
||||||
|
TranslationBlock *tb = db->tb;
|
||||||
|
vaddr last = pc + len - 1;
|
||||||
void *host;
|
void *host;
|
||||||
vaddr base, end;
|
vaddr base;
|
||||||
TranslationBlock *tb;
|
|
||||||
|
|
||||||
tb = db->tb;
|
|
||||||
|
|
||||||
/* Use slow path if first page is MMIO. */
|
/* Use slow path if first page is MMIO. */
|
||||||
if (unlikely(tb_page_addr0(tb) == -1)) {
|
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;
|
host = db->host_addr[0];
|
||||||
if (likely(is_same_page(db, end))) {
|
base = db->pc_first;
|
||||||
host = db->host_addr[0];
|
|
||||||
base = db->pc_first;
|
if (likely(((base ^ last) & TARGET_PAGE_MASK) == 0)) {
|
||||||
} else {
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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];
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Use slow path when crossing pages. */
|
|
||||||
if (is_same_page(db, pc)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tcg_debug_assert(pc >= base);
|
memcpy(dest, host + (pc - base), len);
|
||||||
return host + (pc - base);
|
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
|
int offset;
|
||||||
struct qemu_plugin_insn *insn = tcg_ctx->plugin_insn;
|
|
||||||
abi_ptr off;
|
|
||||||
|
|
||||||
if (insn == NULL) {
|
/* Do not record probes before the start of TB. */
|
||||||
|
if (pc < db->pc_first) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
off = pc - insn->vaddr;
|
|
||||||
if (off < insn->data->len) {
|
/*
|
||||||
g_byte_array_set_size(insn->data, off);
|
* In translator_access, we verified that pc is within 2 pages
|
||||||
} else if (off > insn->data->len) {
|
* of pc_first, thus this will never overflow.
|
||||||
/* we have an unexpected gap */
|
*/
|
||||||
g_assert_not_reached();
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
insn->data = g_byte_array_append(insn->data, from, size);
|
memcpy(db->record + (offset - db->record_start), from, size);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, abi_ptr pc)
|
size_t translator_st_len(const DisasContextBase *db)
|
||||||
{
|
{
|
||||||
uint8_t ret;
|
return db->fake_insn ? db->record_len : db->tb->size;
|
||||||
void *p = translator_access(env, db, pc, sizeof(ret));
|
}
|
||||||
|
|
||||||
if (p) {
|
bool translator_st(const DisasContextBase *db, void *dest,
|
||||||
plugin_insn_append(pc, p, sizeof(ret));
|
vaddr addr, size_t len)
|
||||||
return ldub_p(p);
|
{
|
||||||
|
size_t offset, offset_end;
|
||||||
|
|
||||||
|
if (addr < db->pc_first) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
ret = cpu_ldub_code(env, pc);
|
offset = addr - db->pc_first;
|
||||||
plugin_insn_append(pc, &ret, sizeof(ret));
|
offset_end = offset + len;
|
||||||
return ret;
|
if (offset_end > translator_st_len(db)) {
|
||||||
}
|
return false;
|
||||||
|
|
||||||
uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, abi_ptr pc)
|
|
||||||
{
|
|
||||||
uint16_t ret, plug;
|
|
||||||
void *p = translator_access(env, db, pc, sizeof(ret));
|
|
||||||
|
|
||||||
if (p) {
|
|
||||||
plugin_insn_append(pc, p, sizeof(ret));
|
|
||||||
return lduw_p(p);
|
|
||||||
}
|
}
|
||||||
ret = cpu_lduw_code(env, pc);
|
|
||||||
plug = tswap16(ret);
|
|
||||||
plugin_insn_append(pc, &plug, sizeof(ret));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, abi_ptr pc)
|
if (!db->fake_insn) {
|
||||||
{
|
size_t offset_page1 = -(db->pc_first | TARGET_PAGE_MASK);
|
||||||
uint32_t ret, plug;
|
|
||||||
void *p = translator_access(env, db, pc, sizeof(ret));
|
|
||||||
|
|
||||||
if (p) {
|
/* Get all the bytes from the first page. */
|
||||||
plugin_insn_append(pc, p, sizeof(ret));
|
if (db->host_addr[0]) {
|
||||||
return ldl_p(p);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ret = cpu_ldl_code(env, pc);
|
|
||||||
plug = tswap32(ret);
|
|
||||||
plugin_insn_append(pc, &plug, sizeof(ret));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, abi_ptr pc)
|
/* Else get recorded bytes. */
|
||||||
{
|
if (db->record_len != 0 &&
|
||||||
uint64_t ret, plug;
|
offset >= db->record_start &&
|
||||||
void *p = translator_access(env, db, pc, sizeof(ret));
|
offset_end <= db->record_start + db->record_len) {
|
||||||
|
memcpy(dest, db->record + (offset - db->record_start),
|
||||||
if (p) {
|
offset_end - offset);
|
||||||
plugin_insn_append(pc, p, sizeof(ret));
|
return true;
|
||||||
return ldq_p(p);
|
|
||||||
}
|
}
|
||||||
ret = cpu_ldq_code(env, pc);
|
return false;
|
||||||
plug = tswap64(ret);
|
|
||||||
plugin_insn_append(pc, &plug, sizeof(ret));
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void translator_fake_ldb(uint8_t insn8, abi_ptr pc)
|
uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, vaddr pc)
|
||||||
{
|
{
|
||||||
plugin_insn_append(pc, &insn8, sizeof(insn8));
|
uint8_t raw;
|
||||||
|
|
||||||
|
if (!translator_ld(env, db, &raw, pc, sizeof(raw))) {
|
||||||
|
raw = cpu_ldub_code(env, pc);
|
||||||
|
record_save(db, pc, &raw, sizeof(raw));
|
||||||
|
}
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, vaddr pc)
|
||||||
|
{
|
||||||
|
uint16_t raw, tgt;
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
return tgt;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, vaddr pc)
|
||||||
|
{
|
||||||
|
uint32_t raw, tgt;
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
return tgt;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, vaddr pc)
|
||||||
|
{
|
||||||
|
uint64_t raw, tgt;
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
return tgt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void translator_fake_ld(DisasContextBase *db, const void *data, size_t len)
|
||||||
|
{
|
||||||
|
db->fake_insn = true;
|
||||||
|
record_save(db, db->pc_first, data, len);
|
||||||
}
|
}
|
||||||
|
@ -258,8 +258,9 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
|
|||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uint32_t insn_opcode;
|
uint32_t insn_opcode = 0;
|
||||||
insn_opcode = *((uint32_t *)qemu_plugin_insn_data(insn));
|
qemu_plugin_insn_data(insn, &insn_opcode, sizeof(insn_opcode));
|
||||||
|
|
||||||
char *output = g_strdup_printf("0x%"PRIx64", 0x%"PRIx32", \"%s\"",
|
char *output = g_strdup_printf("0x%"PRIx64", 0x%"PRIx32", \"%s\"",
|
||||||
insn_vaddr, insn_opcode, insn_disas);
|
insn_vaddr, insn_opcode, insn_disas);
|
||||||
|
|
||||||
|
@ -252,7 +252,7 @@ static struct qemu_plugin_scoreboard *find_counter(
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
uint64_t *cnt = NULL;
|
uint64_t *cnt = NULL;
|
||||||
uint32_t opcode;
|
uint32_t opcode = 0;
|
||||||
InsnClassExecCount *class = NULL;
|
InsnClassExecCount *class = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -261,7 +261,7 @@ static struct qemu_plugin_scoreboard *find_counter(
|
|||||||
* They would probably benefit from a more tailored plugin.
|
* They would probably benefit from a more tailored plugin.
|
||||||
* However we can fall back to individual instruction counting.
|
* 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++) {
|
for (i = 0; !cnt && i < class_table_sz; i++) {
|
||||||
class = &class_table[i];
|
class = &class_table[i];
|
||||||
|
104
disas/disas-common.c
Normal file
104
disas/disas-common.c
Normal file
@ -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;
|
||||||
|
}
|
129
disas/disas-host.c
Normal file
129
disas/disas-host.c
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,8 +14,12 @@ typedef struct CPUDebug {
|
|||||||
CPUState *cpu;
|
CPUState *cpu;
|
||||||
} CPUDebug;
|
} CPUDebug;
|
||||||
|
|
||||||
|
void disas_initialize_debug(CPUDebug *s);
|
||||||
void disas_initialize_debug_target(CPUDebug *s, CPUState *cpu);
|
void disas_initialize_debug_target(CPUDebug *s, CPUState *cpu);
|
||||||
int disas_gstring_printf(FILE *stream, const char *fmt, ...)
|
int disas_gstring_printf(FILE *stream, const char *fmt, ...)
|
||||||
G_GNUC_PRINTF(2, 3);
|
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
|
#endif
|
||||||
|
@ -11,6 +11,19 @@
|
|||||||
#include "hw/core/cpu.h"
|
#include "hw/core/cpu.h"
|
||||||
#include "monitor/monitor.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
|
static int
|
||||||
physical_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
|
physical_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
|
||||||
struct disassemble_info *info)
|
struct disassemble_info *info)
|
||||||
@ -38,6 +51,8 @@ void monitor_disas(Monitor *mon, CPUState *cpu, uint64_t pc,
|
|||||||
|
|
||||||
if (is_physical) {
|
if (is_physical) {
|
||||||
s.info.read_memory_func = physical_read_memory;
|
s.info.read_memory_func = physical_read_memory;
|
||||||
|
} else {
|
||||||
|
s.info.read_memory_func = virtual_read_memory;
|
||||||
}
|
}
|
||||||
s.info.buffer_vma = pc;
|
s.info.buffer_vma = pc;
|
||||||
|
|
||||||
|
99
disas/disas-target.c
Normal file
99
disas/disas-target.c
Normal file
@ -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 */
|
338
disas/disas.c
338
disas/disas.c
@ -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;
|
|
||||||
}
|
|
@ -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_SPARC_DIS', if_true: files('sparc.c'))
|
||||||
common_ss.add(when: 'CONFIG_XTENSA_DIS', if_true: files('xtensa.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(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'))
|
system_ss.add(files('disas-mon.c'))
|
||||||
specific_ss.add(capstone)
|
specific_ss.add(capstone)
|
||||||
|
37
disas/objdump.c
Normal file
37
disas/objdump.c
Normal file
@ -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");
|
||||||
|
}
|
@ -2,13 +2,18 @@
|
|||||||
#define QEMU_DISAS_H
|
#define QEMU_DISAS_H
|
||||||
|
|
||||||
/* Disassemble this for me please... (debugging). */
|
/* Disassemble this for me please... (debugging). */
|
||||||
|
#ifdef CONFIG_TCG
|
||||||
void disas(FILE *out, const void *code, size_t size);
|
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,
|
void monitor_disas(Monitor *mon, CPUState *cpu, uint64_t pc,
|
||||||
int nb_insn, bool is_physical);
|
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. */
|
/* Look up symbol for debugging purpose. Returns "" if unknown. */
|
||||||
const char *lookup_symbol(uint64_t orig_addr);
|
const char *lookup_symbol(uint64_t orig_addr);
|
||||||
|
@ -355,16 +355,6 @@ uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr addr);
|
|||||||
uint32_t cpu_ldl_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);
|
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:
|
* tlb_vaddr_to_host:
|
||||||
* @env: CPUArchState
|
* @env: CPUArchState
|
||||||
|
@ -18,8 +18,7 @@ struct DisasContextBase;
|
|||||||
|
|
||||||
#ifdef CONFIG_PLUGIN
|
#ifdef CONFIG_PLUGIN
|
||||||
|
|
||||||
bool plugin_gen_tb_start(CPUState *cpu, const struct DisasContextBase *db,
|
bool plugin_gen_tb_start(CPUState *cpu, const struct DisasContextBase *db);
|
||||||
bool supress);
|
|
||||||
void plugin_gen_tb_end(CPUState *cpu, size_t num_insns);
|
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_start(CPUState *cpu, const struct DisasContextBase *db);
|
||||||
void plugin_gen_insn_end(void);
|
void plugin_gen_insn_end(void);
|
||||||
@ -28,8 +27,8 @@ void plugin_gen_disable_mem_helpers(void);
|
|||||||
|
|
||||||
#else /* !CONFIG_PLUGIN */
|
#else /* !CONFIG_PLUGIN */
|
||||||
|
|
||||||
static inline bool
|
static inline
|
||||||
plugin_gen_tb_start(CPUState *cpu, const struct DisasContextBase *db, bool sup)
|
bool plugin_gen_tb_start(CPUState *cpu, const struct DisasContextBase *db)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/bswap.h"
|
#include "qemu/bswap.h"
|
||||||
#include "exec/cpu-common.h"
|
#include "exec/vaddr.h"
|
||||||
#include "exec/cpu-defs.h"
|
|
||||||
#include "exec/abi_ptr.h"
|
|
||||||
#include "cpu.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gen_intermediate_code
|
* gen_intermediate_code
|
||||||
@ -75,14 +72,14 @@ typedef enum DisasJumpType {
|
|||||||
* @num_insns: Number of translated instructions (including current).
|
* @num_insns: Number of translated instructions (including current).
|
||||||
* @max_insns: Maximum number of instructions to be translated in this TB.
|
* @max_insns: Maximum number of instructions to be translated in this TB.
|
||||||
* @singlestep_enabled: "Hardware" single stepping enabled.
|
* @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.
|
* @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,
|
* @insn_start: The last op emitted by the insn_start hook,
|
||||||
* which is expected to be INDEX_op_insn_start.
|
* which is expected to be INDEX_op_insn_start.
|
||||||
*
|
*
|
||||||
* Architecture-agnostic disassembly context.
|
* Architecture-agnostic disassembly context.
|
||||||
*/
|
*/
|
||||||
typedef struct DisasContextBase {
|
struct DisasContextBase {
|
||||||
TranslationBlock *tb;
|
TranslationBlock *tb;
|
||||||
vaddr pc_first;
|
vaddr pc_first;
|
||||||
vaddr pc_next;
|
vaddr pc_next;
|
||||||
@ -91,9 +88,22 @@ typedef struct DisasContextBase {
|
|||||||
int max_insns;
|
int max_insns;
|
||||||
bool singlestep_enabled;
|
bool singlestep_enabled;
|
||||||
bool plugin_enabled;
|
bool plugin_enabled;
|
||||||
|
bool fake_insn;
|
||||||
struct TCGOp *insn_start;
|
struct TCGOp *insn_start;
|
||||||
void *host_addr[2];
|
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:
|
* TranslatorOps:
|
||||||
@ -125,7 +135,7 @@ typedef struct TranslatorOps {
|
|||||||
void (*insn_start)(DisasContextBase *db, CPUState *cpu);
|
void (*insn_start)(DisasContextBase *db, CPUState *cpu);
|
||||||
void (*translate_insn)(DisasContextBase *db, CPUState *cpu);
|
void (*translate_insn)(DisasContextBase *db, CPUState *cpu);
|
||||||
void (*tb_stop)(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;
|
} TranslatorOps;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -185,14 +195,14 @@ bool translator_io_start(DisasContextBase *db);
|
|||||||
* the relevant information at translation time.
|
* the relevant information at translation time.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint8_t translator_ldub(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, abi_ptr pc);
|
uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, vaddr pc);
|
||||||
uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, abi_ptr pc);
|
uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, vaddr pc);
|
||||||
uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, abi_ptr pc);
|
uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, vaddr pc);
|
||||||
|
|
||||||
static inline uint16_t
|
static inline uint16_t
|
||||||
translator_lduw_swap(CPUArchState *env, DisasContextBase *db,
|
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);
|
uint16_t ret = translator_lduw(env, db, pc);
|
||||||
if (do_swap) {
|
if (do_swap) {
|
||||||
@ -203,7 +213,7 @@ translator_lduw_swap(CPUArchState *env, DisasContextBase *db,
|
|||||||
|
|
||||||
static inline uint32_t
|
static inline uint32_t
|
||||||
translator_ldl_swap(CPUArchState *env, DisasContextBase *db,
|
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);
|
uint32_t ret = translator_ldl(env, db, pc);
|
||||||
if (do_swap) {
|
if (do_swap) {
|
||||||
@ -214,7 +224,7 @@ translator_ldl_swap(CPUArchState *env, DisasContextBase *db,
|
|||||||
|
|
||||||
static inline uint64_t
|
static inline uint64_t
|
||||||
translator_ldq_swap(CPUArchState *env, DisasContextBase *db,
|
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);
|
uint64_t ret = translator_ldq(env, db, pc);
|
||||||
if (do_swap) {
|
if (do_swap) {
|
||||||
@ -224,17 +234,42 @@ translator_ldq_swap(CPUArchState *env, DisasContextBase *db,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* translator_fake_ldb - fake instruction load
|
* translator_fake_ld - fake instruction load
|
||||||
* @insn8: byte of instruction
|
* @db: Disassembly context
|
||||||
* @pc: program counter of instruction
|
* @data: bytes of instruction
|
||||||
|
* @len: number of bytes
|
||||||
*
|
*
|
||||||
* This is a special case helper used where the instruction we are
|
* This is a special case helper used where the instruction we are
|
||||||
* about to translate comes from somewhere else (e.g. being
|
* about to translate comes from somewhere else (e.g. being
|
||||||
* re-synthesised for s390x "ex"). It ensures we update other areas of
|
* re-synthesised for s390x "ex"). It ensures we update other areas of
|
||||||
* the translator with details of the executed instruction.
|
* 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.
|
* Return whether addr is on the same page as where disassembly started.
|
||||||
* Translators can use this to enforce the rule that only single-insn
|
* 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;
|
return ((addr ^ db->pc_first) & TARGET_PAGE_MASK) == 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* EXEC__TRANSLATOR_H */
|
#endif /* EXEC__TRANSLATOR_H */
|
||||||
|
@ -98,17 +98,14 @@ struct qemu_plugin_dyn_cb {
|
|||||||
|
|
||||||
/* Internal context for instrumenting an instruction */
|
/* Internal context for instrumenting an instruction */
|
||||||
struct qemu_plugin_insn {
|
struct qemu_plugin_insn {
|
||||||
GByteArray *data;
|
|
||||||
uint64_t vaddr;
|
uint64_t vaddr;
|
||||||
void *haddr;
|
|
||||||
GArray *insn_cbs;
|
GArray *insn_cbs;
|
||||||
GArray *mem_cbs;
|
GArray *mem_cbs;
|
||||||
|
uint8_t len;
|
||||||
bool calls_helpers;
|
bool calls_helpers;
|
||||||
|
|
||||||
/* if set, the instruction calls helpers that might access guest memory */
|
/* if set, the instruction calls helpers that might access guest memory */
|
||||||
bool mem_helper;
|
bool mem_helper;
|
||||||
|
|
||||||
bool mem_only;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* A scoreboard is an array of values, indexed by vcpu_index */
|
/* 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;
|
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 */
|
/* Internal context for this TranslationBlock */
|
||||||
struct qemu_plugin_tb {
|
struct qemu_plugin_tb {
|
||||||
GPtrArray *insns;
|
GPtrArray *insns;
|
||||||
size_t n;
|
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 */
|
/* if set, the TB calls helpers that might access guest memory */
|
||||||
bool mem_helper;
|
bool mem_helper;
|
||||||
|
@ -61,7 +61,7 @@ typedef uint64_t qemu_plugin_id_t;
|
|||||||
|
|
||||||
extern QEMU_PLUGIN_EXPORT int qemu_plugin_version;
|
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
|
* 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_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()
|
* @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
|
* Returns the number of bytes copied, minimum of @len and insn size.
|
||||||
* qemu_plugin_insn_size() to calculate size of stream.
|
|
||||||
*
|
|
||||||
* Returns: pointer to a stream of bytes containing the value of this
|
|
||||||
* instructions opcode.
|
|
||||||
*/
|
*/
|
||||||
QEMU_PLUGIN_API
|
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
|
* qemu_plugin_insn_size() - return size of instruction
|
||||||
|
@ -42,6 +42,7 @@ typedef struct CPUPluginState CPUPluginState;
|
|||||||
typedef struct CPUState CPUState;
|
typedef struct CPUState CPUState;
|
||||||
typedef struct DeviceState DeviceState;
|
typedef struct DeviceState DeviceState;
|
||||||
typedef struct DirtyBitmapSnapshot DirtyBitmapSnapshot;
|
typedef struct DirtyBitmapSnapshot DirtyBitmapSnapshot;
|
||||||
|
typedef struct DisasContextBase DisasContextBase;
|
||||||
typedef struct DisplayChangeListener DisplayChangeListener;
|
typedef struct DisplayChangeListener DisplayChangeListener;
|
||||||
typedef struct DriveInfo DriveInfo;
|
typedef struct DriveInfo DriveInfo;
|
||||||
typedef struct DumpState DumpState;
|
typedef struct DumpState DumpState;
|
||||||
|
@ -537,6 +537,7 @@ struct TCGContext {
|
|||||||
* space for instructions (for variable-instruction-length ISAs).
|
* space for instructions (for variable-instruction-length ISAs).
|
||||||
*/
|
*/
|
||||||
struct qemu_plugin_tb *plugin_tb;
|
struct qemu_plugin_tb *plugin_tb;
|
||||||
|
const struct DisasContextBase *plugin_db;
|
||||||
|
|
||||||
/* descriptor of the instruction being translated */
|
/* descriptor of the instruction being translated */
|
||||||
struct qemu_plugin_insn *plugin_insn;
|
struct qemu_plugin_insn *plugin_insn;
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include "tcg/tcg.h"
|
#include "tcg/tcg.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
|
#include "exec/translator.h"
|
||||||
#include "disas/disas.h"
|
#include "disas/disas.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#ifndef CONFIG_USER_ONLY
|
#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);
|
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,
|
void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
|
||||||
qemu_plugin_vcpu_udata_cb_t cb,
|
qemu_plugin_vcpu_udata_cb_t cb,
|
||||||
enum qemu_plugin_cb_flags flags,
|
enum qemu_plugin_cb_flags flags,
|
||||||
void *udata)
|
void *udata)
|
||||||
{
|
{
|
||||||
if (!tb->mem_only) {
|
if (!tb_is_mem_only()) {
|
||||||
plugin_register_dyn_cb__udata(&tb->cbs, cb, flags, udata);
|
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,
|
qemu_plugin_u64 entry,
|
||||||
uint64_t imm)
|
uint64_t imm)
|
||||||
{
|
{
|
||||||
if (!tb->mem_only) {
|
if (!tb_is_mem_only()) {
|
||||||
plugin_register_inline_op_on_entry(&tb->cbs, 0, op, entry, imm);
|
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,
|
enum qemu_plugin_cb_flags flags,
|
||||||
void *udata)
|
void *udata)
|
||||||
{
|
{
|
||||||
if (!insn->mem_only) {
|
if (!tb_is_mem_only()) {
|
||||||
plugin_register_dyn_cb__udata(&insn->insn_cbs, cb, flags, udata);
|
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,
|
qemu_plugin_u64 entry,
|
||||||
uint64_t imm)
|
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);
|
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)
|
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 *
|
struct qemu_plugin_insn *
|
||||||
@ -205,7 +212,6 @@ qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
insn = g_ptr_array_index(tb->insns, idx);
|
insn = g_ptr_array_index(tb->insns, idx);
|
||||||
insn->mem_only = tb->mem_only;
|
|
||||||
return insn;
|
return insn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,14 +222,18 @@ qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx)
|
|||||||
* instruction being translated.
|
* 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)
|
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)
|
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)
|
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)
|
char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn)
|
||||||
{
|
{
|
||||||
CPUState *cpu = current_cpu;
|
return plugin_disas(tcg_ctx->cpu, tcg_ctx->plugin_db,
|
||||||
return plugin_disas(cpu, insn->vaddr, insn->data->len);
|
insn->vaddr, insn->len);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *qemu_plugin_insn_symbol(const struct qemu_plugin_insn *insn)
|
const char *qemu_plugin_insn_symbol(const struct qemu_plugin_insn *insn)
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "sysemu/cpus.h"
|
#include "sysemu/cpus.h"
|
||||||
#include "disas/disas.h"
|
|
||||||
#include "qemu/host-utils.h"
|
#include "qemu/host-utils.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "tcg/tcg-op.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 = {
|
static const TranslatorOps alpha_tr_ops = {
|
||||||
.init_disas_context = alpha_tr_init_disas_context,
|
.init_disas_context = alpha_tr_init_disas_context,
|
||||||
.tb_start = alpha_tr_tb_start,
|
.tb_start = alpha_tr_tb_start,
|
||||||
.insn_start = alpha_tr_insn_start,
|
.insn_start = alpha_tr_insn_start,
|
||||||
.translate_insn = alpha_tr_translate_insn,
|
.translate_insn = alpha_tr_translate_insn,
|
||||||
.tb_stop = alpha_tr_tb_stop,
|
.tb_stop = alpha_tr_tb_stop,
|
||||||
.disas_log = alpha_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
#include "translate.h"
|
#include "translate.h"
|
||||||
#include "translate-a64.h"
|
#include "translate-a64.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "disas/disas.h"
|
|
||||||
#include "arm_ldst.h"
|
#include "arm_ldst.h"
|
||||||
#include "semihosting/semihost.h"
|
#include "semihosting/semihost.h"
|
||||||
#include "cpregs.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 = {
|
const TranslatorOps aarch64_translator_ops = {
|
||||||
.init_disas_context = aarch64_tr_init_disas_context,
|
.init_disas_context = aarch64_tr_init_disas_context,
|
||||||
.tb_start = aarch64_tr_tb_start,
|
.tb_start = aarch64_tr_tb_start,
|
||||||
.insn_start = aarch64_tr_insn_start,
|
.insn_start = aarch64_tr_insn_start,
|
||||||
.translate_insn = aarch64_tr_translate_insn,
|
.translate_insn = aarch64_tr_translate_insn,
|
||||||
.tb_stop = aarch64_tr_tb_stop,
|
.tb_stop = aarch64_tr_tb_stop,
|
||||||
.disas_log = aarch64_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "translate.h"
|
#include "translate.h"
|
||||||
#include "translate-a32.h"
|
#include "translate-a32.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "disas/disas.h"
|
|
||||||
#include "arm_ldst.h"
|
#include "arm_ldst.h"
|
||||||
#include "semihosting/semihost.h"
|
#include "semihosting/semihost.h"
|
||||||
#include "cpregs.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 = {
|
static const TranslatorOps arm_translator_ops = {
|
||||||
.init_disas_context = arm_tr_init_disas_context,
|
.init_disas_context = arm_tr_init_disas_context,
|
||||||
.tb_start = arm_tr_tb_start,
|
.tb_start = arm_tr_tb_start,
|
||||||
.insn_start = arm_tr_insn_start,
|
.insn_start = arm_tr_insn_start,
|
||||||
.translate_insn = arm_tr_translate_insn,
|
.translate_insn = arm_tr_translate_insn,
|
||||||
.tb_stop = arm_tr_tb_stop,
|
.tb_stop = arm_tr_tb_stop,
|
||||||
.disas_log = arm_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const TranslatorOps thumb_translator_ops = {
|
static const TranslatorOps thumb_translator_ops = {
|
||||||
@ -9687,7 +9676,6 @@ static const TranslatorOps thumb_translator_ops = {
|
|||||||
.insn_start = arm_tr_insn_start,
|
.insn_start = arm_tr_insn_start,
|
||||||
.translate_insn = thumb_tr_translate_insn,
|
.translate_insn = thumb_tr_translate_insn,
|
||||||
.tb_stop = arm_tr_tb_stop,
|
.tb_stop = arm_tr_tb_stop,
|
||||||
.disas_log = arm_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* generate intermediate code for basic block 'tb'. */
|
/* generate intermediate code for basic block 'tb'. */
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "tcg/tcg-op.h"
|
#include "tcg/tcg-op.h"
|
||||||
#include "exec/cpu_ldst.h"
|
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
#include "exec/helper-gen.h"
|
#include "exec/helper-gen.h"
|
||||||
#include "exec/log.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)
|
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)
|
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 = {
|
static const TranslatorOps avr_tr_ops = {
|
||||||
.init_disas_context = avr_tr_init_disas_context,
|
.init_disas_context = avr_tr_init_disas_context,
|
||||||
.tb_start = avr_tr_tb_start,
|
.tb_start = avr_tr_tb_start,
|
||||||
.insn_start = avr_tr_insn_start,
|
.insn_start = avr_tr_insn_start,
|
||||||
.translate_insn = avr_tr_translate_insn,
|
.translate_insn = avr_tr_translate_insn,
|
||||||
.tb_stop = avr_tr_tb_stop,
|
.tb_stop = avr_tr_tb_stop,
|
||||||
.disas_log = avr_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||||
|
@ -25,12 +25,10 @@
|
|||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "disas/disas.h"
|
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "tcg/tcg-op.h"
|
#include "tcg/tcg-op.h"
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
#include "mmu.h"
|
#include "mmu.h"
|
||||||
#include "exec/cpu_ldst.h"
|
|
||||||
#include "exec/translator.h"
|
#include "exec/translator.h"
|
||||||
#include "crisv32-decode.h"
|
#include "crisv32-decode.h"
|
||||||
#include "qemu/qemu-print.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,
|
static int cris_fetch(CPUCRISState *env, DisasContext *dc, uint32_t addr,
|
||||||
unsigned int size, unsigned int sign)
|
unsigned int size, bool sign)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 4:
|
case 4:
|
||||||
{
|
r = translator_ldl(env, &dc->base, addr);
|
||||||
r = cpu_ldl_code(env, addr);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case 2:
|
case 2:
|
||||||
{
|
r = translator_lduw(env, &dc->base, addr);
|
||||||
if (sign) {
|
if (sign) {
|
||||||
r = cpu_ldsw_code(env, addr);
|
r = (int16_t)r;
|
||||||
} else {
|
|
||||||
r = cpu_lduw_code(env, addr);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case 1:
|
case 1:
|
||||||
{
|
r = translator_ldub(env, &dc->base, addr);
|
||||||
if (sign) {
|
if (sign) {
|
||||||
r = cpu_ldsb_code(env, addr);
|
r = (int8_t)r;
|
||||||
} else {
|
|
||||||
r = cpu_ldub_code(env, addr);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
cpu_abort(CPU(dc->cpu), "Invalid fetch size %d\n", size);
|
g_assert_not_reached();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -2869,7 +2858,7 @@ static unsigned int crisv32_decoder(CPUCRISState *env, DisasContext *dc)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Load a halfword onto the instruction register. */
|
/* 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. */
|
/* Now decode it. */
|
||||||
dc->opcode = EXTRACT_FIELD(dc->ir, 4, 11);
|
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 = {
|
static const TranslatorOps cris_tr_ops = {
|
||||||
.init_disas_context = cris_tr_init_disas_context,
|
.init_disas_context = cris_tr_init_disas_context,
|
||||||
.tb_start = cris_tr_tb_start,
|
.tb_start = cris_tr_tb_start,
|
||||||
.insn_start = cris_tr_insn_start,
|
.insn_start = cris_tr_insn_start,
|
||||||
.translate_insn = cris_tr_translate_insn,
|
.translate_insn = cris_tr_translate_insn,
|
||||||
.tb_stop = cris_tr_tb_stop,
|
.tb_stop = cris_tr_tb_stop,
|
||||||
.disas_log = cris_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||||
|
@ -165,20 +165,7 @@ static int dec10_prep_move_m(CPUCRISState *env, DisasContext *dc,
|
|||||||
|
|
||||||
/* Load [$rs] onto T1. */
|
/* Load [$rs] onto T1. */
|
||||||
if (is_imm) {
|
if (is_imm) {
|
||||||
if (memsize != 4) {
|
imm = cris_fetch(env, dc, dc->pc + 2, memsize, s_ext);
|
||||||
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);
|
|
||||||
|
|
||||||
tcg_gen_movi_tl(dst, imm);
|
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",
|
LOG_DIS("dip pc=%x opcode=%d r%d r%d\n",
|
||||||
dc->pc, dc->opcode, dc->src, dc->dst);
|
dc->pc, dc->opcode, dc->src, dc->dst);
|
||||||
if (dc->src == 15) {
|
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);
|
tcg_gen_movi_tl(cpu_PR[PR_PREFIX], imm);
|
||||||
if (dc->postinc)
|
if (dc->postinc) {
|
||||||
insn_len += 4;
|
insn_len += 4;
|
||||||
|
}
|
||||||
tcg_gen_addi_tl(cpu_R[15], cpu_R[15], insn_len - 2);
|
tcg_gen_addi_tl(cpu_R[15], cpu_R[15], insn_len - 2);
|
||||||
} else {
|
} else {
|
||||||
gen_load(dc, cpu_PR[PR_PREFIX], cpu_R[dc->src], 4, 0);
|
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) {
|
if (dc->src == 15) {
|
||||||
LOG_DIS("jump.%d %d r%d r%d direct\n", size,
|
LOG_DIS("jump.%d %d r%d r%d direct\n", size,
|
||||||
dc->opcode, dc->src, dc->dst);
|
dc->opcode, dc->src, dc->dst);
|
||||||
imm = cpu_ldl_code(env, dc->pc + 2);
|
imm = cris_fetch(env, dc, dc->pc + 2, size, 0);
|
||||||
if (dc->mode == CRISV10_MODE_AUTOINC)
|
if (dc->mode == CRISV10_MODE_AUTOINC) {
|
||||||
insn_len += size;
|
insn_len += size;
|
||||||
|
}
|
||||||
c = tcg_constant_tl(dc->pc + insn_len);
|
c = tcg_constant_tl(dc->pc + insn_len);
|
||||||
t_gen_mov_preg_TN(dc, dc->dst, c);
|
t_gen_mov_preg_TN(dc, dc->dst, c);
|
||||||
dc->jmp_pc = imm;
|
dc->jmp_pc = imm;
|
||||||
@ -1164,7 +1152,7 @@ static unsigned int dec10_ind(CPUCRISState *env, DisasContext *dc)
|
|||||||
case CRISV10_IND_BCC_M:
|
case CRISV10_IND_BCC_M:
|
||||||
|
|
||||||
cris_cc_mask(dc, 0);
|
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;
|
simm += 4;
|
||||||
|
|
||||||
LOG_DIS("bcc_m: b%s %x\n", cc_name(dc->cond), dc->pc + simm);
|
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;
|
unsigned int insn_len = 2;
|
||||||
|
|
||||||
/* Load a halfword onto the instruction register. */
|
/* 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. */
|
/* Now decode it. */
|
||||||
dc->opcode = EXTRACT_FIELD(dc->ir, 6, 9);
|
dc->opcode = EXTRACT_FIELD(dc->ir, 6, 9);
|
||||||
|
@ -1022,7 +1022,7 @@ static bool pkt_crosses_page(CPUHexagonState *env, DisasContext *ctx)
|
|||||||
int nwords;
|
int nwords;
|
||||||
|
|
||||||
for (nwords = 0; !found_end && nwords < PACKET_WORDS_MAX; 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));
|
ctx->base.pc_next + nwords * sizeof(uint32_t));
|
||||||
found_end = is_packet_end(word);
|
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 = {
|
static const TranslatorOps hexagon_tr_ops = {
|
||||||
.init_disas_context = hexagon_tr_init_disas_context,
|
.init_disas_context = hexagon_tr_init_disas_context,
|
||||||
.tb_start = hexagon_tr_tb_start,
|
.tb_start = hexagon_tr_tb_start,
|
||||||
.insn_start = hexagon_tr_insn_start,
|
.insn_start = hexagon_tr_insn_start,
|
||||||
.translate_insn = hexagon_tr_translate_packet,
|
.translate_insn = hexagon_tr_translate_packet,
|
||||||
.tb_stop = hexagon_tr_tb_stop,
|
.tb_stop = hexagon_tr_tb_stop,
|
||||||
.disas_log = hexagon_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "disas/disas.h"
|
|
||||||
#include "qemu/host-utils.h"
|
#include "qemu/host-utils.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "exec/page-protection.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)
|
CPUState *cs, FILE *logfile)
|
||||||
{
|
{
|
||||||
target_ulong pc = dcbase->pc_first;
|
target_ulong pc = dcbase->pc_first;
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
|
||||||
switch (pc) {
|
switch (pc) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
fprintf(logfile, "IN:\n0x00000000: (null)\n");
|
fprintf(logfile, "IN:\n0x00000000: (null)\n");
|
||||||
return;
|
return true;
|
||||||
case 0xb0:
|
case 0xb0:
|
||||||
fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n");
|
fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n");
|
||||||
return;
|
return true;
|
||||||
case 0xe0:
|
case 0xe0:
|
||||||
fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n");
|
fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n");
|
||||||
return;
|
return true;
|
||||||
case 0x100:
|
case 0x100:
|
||||||
fprintf(logfile, "IN:\n0x00000100: syscall\n");
|
fprintf(logfile, "IN:\n0x00000100: syscall\n");
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
return false;
|
||||||
|
|
||||||
fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
|
|
||||||
target_disas(logfile, cs, pc, dcbase->tb->size);
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static const TranslatorOps hppa_tr_ops = {
|
static const TranslatorOps hppa_tr_ops = {
|
||||||
.init_disas_context = hppa_tr_init_disas_context,
|
.init_disas_context = hppa_tr_init_disas_context,
|
||||||
@ -4848,7 +4845,9 @@ static const TranslatorOps hppa_tr_ops = {
|
|||||||
.insn_start = hppa_tr_insn_start,
|
.insn_start = hppa_tr_insn_start,
|
||||||
.translate_insn = hppa_tr_translate_insn,
|
.translate_insn = hppa_tr_translate_insn,
|
||||||
.tb_stop = hppa_tr_tb_stop,
|
.tb_stop = hppa_tr_tb_stop,
|
||||||
|
#ifdef CONFIG_USER_ONLY
|
||||||
.disas_log = hppa_tr_disas_log,
|
.disas_log = hppa_tr_disas_log,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||||
|
@ -20,11 +20,9 @@
|
|||||||
|
|
||||||
#include "qemu/host-utils.h"
|
#include "qemu/host-utils.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "disas/disas.h"
|
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "tcg/tcg-op.h"
|
#include "tcg/tcg-op.h"
|
||||||
#include "tcg/tcg-op-gvec.h"
|
#include "tcg/tcg-op-gvec.h"
|
||||||
#include "exec/cpu_ldst.h"
|
|
||||||
#include "exec/translator.h"
|
#include "exec/translator.h"
|
||||||
#include "fpu/softfloat.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!
|
* This can happen even if the operand is only one byte long!
|
||||||
*/
|
*/
|
||||||
if (((s->pc - 1) ^ (pc - 1)) & TARGET_PAGE_MASK) {
|
if (((s->pc - 1) ^ (pc - 1)) & TARGET_PAGE_MASK) {
|
||||||
volatile uint8_t unused =
|
(void)translator_ldub(env, &s->base,
|
||||||
cpu_ldub_code(env, (s->pc - 1) & TARGET_PAGE_MASK);
|
(s->pc - 1) & TARGET_PAGE_MASK);
|
||||||
(void) unused;
|
|
||||||
}
|
}
|
||||||
siglongjmp(s->jmpbuf, 1);
|
siglongjmp(s->jmpbuf, 1);
|
||||||
}
|
}
|
||||||
@ -2178,7 +2175,7 @@ static void gen_unknown_opcode(CPUX86State *env, DisasContext *s)
|
|||||||
|
|
||||||
fprintf(logfile, "ILLOPC: " TARGET_FMT_lx ":", pc);
|
fprintf(logfile, "ILLOPC: " TARGET_FMT_lx ":", pc);
|
||||||
for (; pc < end; ++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");
|
fprintf(logfile, "\n");
|
||||||
qemu_log_unlock(logfile);
|
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 = {
|
static const TranslatorOps i386_tr_ops = {
|
||||||
.init_disas_context = i386_tr_init_disas_context,
|
.init_disas_context = i386_tr_init_disas_context,
|
||||||
.tb_start = i386_tr_tb_start,
|
.tb_start = i386_tr_tb_start,
|
||||||
.insn_start = i386_tr_insn_start,
|
.insn_start = i386_tr_insn_start,
|
||||||
.translate_insn = i386_tr_translate_insn,
|
.translate_insn = i386_tr_translate_insn,
|
||||||
.tb_stop = i386_tr_tb_stop,
|
.tb_stop = i386_tr_tb_stop,
|
||||||
.disas_log = i386_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* generate intermediate code for basic block 'tb'. */
|
/* generate intermediate code for basic block 'tb'. */
|
||||||
|
@ -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 = {
|
static const TranslatorOps loongarch_tr_ops = {
|
||||||
.init_disas_context = loongarch_tr_init_disas_context,
|
.init_disas_context = loongarch_tr_init_disas_context,
|
||||||
.tb_start = loongarch_tr_tb_start,
|
.tb_start = loongarch_tr_tb_start,
|
||||||
.insn_start = loongarch_tr_insn_start,
|
.insn_start = loongarch_tr_insn_start,
|
||||||
.translate_insn = loongarch_tr_translate_insn,
|
.translate_insn = loongarch_tr_translate_insn,
|
||||||
.tb_stop = loongarch_tr_tb_stop,
|
.tb_stop = loongarch_tr_tb_stop,
|
||||||
.disas_log = loongarch_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "disas/disas.h"
|
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "tcg/tcg-op.h"
|
#include "tcg/tcg-op.h"
|
||||||
#include "qemu/log.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 = {
|
static const TranslatorOps m68k_tr_ops = {
|
||||||
.init_disas_context = m68k_tr_init_disas_context,
|
.init_disas_context = m68k_tr_init_disas_context,
|
||||||
.tb_start = m68k_tr_tb_start,
|
.tb_start = m68k_tr_tb_start,
|
||||||
.insn_start = m68k_tr_insn_start,
|
.insn_start = m68k_tr_insn_start,
|
||||||
.translate_insn = m68k_tr_translate_insn,
|
.translate_insn = m68k_tr_translate_insn,
|
||||||
.tb_stop = m68k_tr_tb_stop,
|
.tb_stop = m68k_tr_tb_stop,
|
||||||
.disas_log = m68k_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "disas/disas.h"
|
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "exec/cpu_ldst.h"
|
#include "exec/cpu_ldst.h"
|
||||||
#include "tcg/tcg-op.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;
|
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)) {
|
if (!decode(dc, ir)) {
|
||||||
trap_illegal(dc, true);
|
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 = {
|
static const TranslatorOps mb_tr_ops = {
|
||||||
.init_disas_context = mb_tr_init_disas_context,
|
.init_disas_context = mb_tr_init_disas_context,
|
||||||
.tb_start = mb_tr_tb_start,
|
.tb_start = mb_tr_tb_start,
|
||||||
.insn_start = mb_tr_insn_start,
|
.insn_start = mb_tr_insn_start,
|
||||||
.translate_insn = mb_tr_translate_insn,
|
.translate_insn = mb_tr_translate_insn,
|
||||||
.tb_stop = mb_tr_tb_stop,
|
.tb_stop = mb_tr_tb_stop,
|
||||||
.disas_log = mb_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||||
|
@ -29,7 +29,6 @@
|
|||||||
#include "exec/translation-block.h"
|
#include "exec/translation-block.h"
|
||||||
#include "semihosting/semihost.h"
|
#include "semihosting/semihost.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "disas/disas.h"
|
|
||||||
#include "fpu_helper.h"
|
#include "fpu_helper.h"
|
||||||
|
|
||||||
#define HELPER_H "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 = {
|
static const TranslatorOps mips_tr_ops = {
|
||||||
.init_disas_context = mips_tr_init_disas_context,
|
.init_disas_context = mips_tr_init_disas_context,
|
||||||
.tb_start = mips_tr_tb_start,
|
.tb_start = mips_tr_tb_start,
|
||||||
.insn_start = mips_tr_insn_start,
|
.insn_start = mips_tr_insn_start,
|
||||||
.translate_insn = mips_tr_translate_insn,
|
.translate_insn = mips_tr_translate_insn,
|
||||||
.tb_stop = mips_tr_tb_stop,
|
.tb_stop = mips_tr_tb_stop,
|
||||||
.disas_log = mips_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "disas/disas.h"
|
|
||||||
#include "tcg/tcg-op.h"
|
#include "tcg/tcg-op.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "qemu/bitops.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 = {
|
static const TranslatorOps openrisc_tr_ops = {
|
||||||
.init_disas_context = openrisc_tr_init_disas_context,
|
.init_disas_context = openrisc_tr_init_disas_context,
|
||||||
.tb_start = openrisc_tr_tb_start,
|
.tb_start = openrisc_tr_tb_start,
|
||||||
.insn_start = openrisc_tr_insn_start,
|
.insn_start = openrisc_tr_insn_start,
|
||||||
.translate_insn = openrisc_tr_translate_insn,
|
.translate_insn = openrisc_tr_translate_insn,
|
||||||
.tb_stop = openrisc_tr_tb_stop,
|
.tb_stop = openrisc_tr_tb_stop,
|
||||||
.disas_log = openrisc_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "disas/disas.h"
|
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "tcg/tcg-op.h"
|
#include "tcg/tcg-op.h"
|
||||||
#include "tcg/tcg-op-gvec.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 = {
|
static const TranslatorOps ppc_tr_ops = {
|
||||||
.init_disas_context = ppc_tr_init_disas_context,
|
.init_disas_context = ppc_tr_init_disas_context,
|
||||||
.tb_start = ppc_tr_tb_start,
|
.tb_start = ppc_tr_tb_start,
|
||||||
.insn_start = ppc_tr_insn_start,
|
.insn_start = ppc_tr_insn_start,
|
||||||
.translate_insn = ppc_tr_translate_insn,
|
.translate_insn = ppc_tr_translate_insn,
|
||||||
.tb_stop = ppc_tr_tb_stop,
|
.tb_stop = ppc_tr_tb_stop,
|
||||||
.disas_log = ppc_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||||
|
@ -20,8 +20,6 @@
|
|||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "tcg/tcg-op.h"
|
#include "tcg/tcg-op.h"
|
||||||
#include "disas/disas.h"
|
|
||||||
#include "exec/cpu_ldst.h"
|
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
#include "exec/helper-gen.h"
|
#include "exec/helper-gen.h"
|
||||||
@ -1083,7 +1081,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
|
|||||||
CPUState *cpu = ctx->cs;
|
CPUState *cpu = ctx->cs;
|
||||||
CPURISCVState *env = cpu_env(cpu);
|
CPURISCVState *env = cpu_env(cpu);
|
||||||
|
|
||||||
return cpu_ldl_code(env, pc);
|
return translator_ldl(env, &ctx->base, pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Include insn module translation function */
|
/* 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;
|
unsigned page_ofs = ctx->base.pc_next & ~TARGET_PAGE_MASK;
|
||||||
|
|
||||||
if (page_ofs > TARGET_PAGE_SIZE - MAX_INSN_LEN) {
|
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);
|
int len = insn_len(next_insn);
|
||||||
|
|
||||||
if (!is_same_page(&ctx->base, ctx->base.pc_next + len - 1)) {
|
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 = {
|
static const TranslatorOps riscv_tr_ops = {
|
||||||
.init_disas_context = riscv_tr_init_disas_context,
|
.init_disas_context = riscv_tr_init_disas_context,
|
||||||
.tb_start = riscv_tr_tb_start,
|
.tb_start = riscv_tr_tb_start,
|
||||||
.insn_start = riscv_tr_insn_start,
|
.insn_start = riscv_tr_insn_start,
|
||||||
.translate_insn = riscv_tr_translate_insn,
|
.translate_insn = riscv_tr_translate_insn,
|
||||||
.tb_stop = riscv_tr_tb_stop,
|
.tb_stop = riscv_tr_tb_stop,
|
||||||
.disas_log = riscv_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "tcg/tcg-op.h"
|
#include "tcg/tcg-op.h"
|
||||||
#include "exec/cpu_ldst.h"
|
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
#include "exec/helper-gen.h"
|
#include "exec/helper-gen.h"
|
||||||
#include "exec/translator.h"
|
#include "exec/translator.h"
|
||||||
@ -75,10 +74,10 @@ static TCGv_i64 cpu_acc;
|
|||||||
|
|
||||||
/* decoder helper */
|
/* decoder helper */
|
||||||
static uint32_t decode_load_bytes(DisasContext *ctx, uint32_t insn,
|
static uint32_t decode_load_bytes(DisasContext *ctx, uint32_t insn,
|
||||||
int i, int n)
|
int i, int n)
|
||||||
{
|
{
|
||||||
while (++i <= 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);
|
insn |= b << (32 - i * 8);
|
||||||
}
|
}
|
||||||
return insn;
|
return insn;
|
||||||
@ -90,22 +89,24 @@ static uint32_t li(DisasContext *ctx, int sz)
|
|||||||
CPURXState *env = ctx->env;
|
CPURXState *env = ctx->env;
|
||||||
addr = ctx->base.pc_next;
|
addr = ctx->base.pc_next;
|
||||||
|
|
||||||
tcg_debug_assert(sz < 4);
|
|
||||||
switch (sz) {
|
switch (sz) {
|
||||||
case 1:
|
case 1:
|
||||||
ctx->base.pc_next += 1;
|
ctx->base.pc_next += 1;
|
||||||
return cpu_ldsb_code(env, addr);
|
return (int8_t)translator_ldub(env, &ctx->base, addr);
|
||||||
case 2:
|
case 2:
|
||||||
ctx->base.pc_next += 2;
|
ctx->base.pc_next += 2;
|
||||||
return cpu_ldsw_code(env, addr);
|
return (int16_t)translator_lduw(env, &ctx->base, addr);
|
||||||
case 3:
|
case 3:
|
||||||
ctx->base.pc_next += 3;
|
ctx->base.pc_next += 3;
|
||||||
tmp = cpu_ldsb_code(env, addr + 2) << 16;
|
tmp = (int8_t)translator_ldub(env, &ctx->base, addr + 2);
|
||||||
tmp |= cpu_lduw_code(env, addr) & 0xffff;
|
tmp <<= 16;
|
||||||
|
tmp |= translator_lduw(env, &ctx->base, addr);
|
||||||
return tmp;
|
return tmp;
|
||||||
case 0:
|
case 0:
|
||||||
ctx->base.pc_next += 4;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -190,22 +191,22 @@ static inline TCGv rx_index_addr(DisasContext *ctx, TCGv mem,
|
|||||||
{
|
{
|
||||||
uint32_t dsp;
|
uint32_t dsp;
|
||||||
|
|
||||||
tcg_debug_assert(ld < 3);
|
|
||||||
switch (ld) {
|
switch (ld) {
|
||||||
case 0:
|
case 0:
|
||||||
return cpu_regs[reg];
|
return cpu_regs[reg];
|
||||||
case 1:
|
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);
|
tcg_gen_addi_i32(mem, cpu_regs[reg], dsp);
|
||||||
ctx->base.pc_next += 1;
|
ctx->base.pc_next += 1;
|
||||||
return mem;
|
return mem;
|
||||||
case 2:
|
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);
|
tcg_gen_addi_i32(mem, cpu_regs[reg], dsp);
|
||||||
ctx->base.pc_next += 2;
|
ctx->base.pc_next += 2;
|
||||||
return mem;
|
return mem;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline MemOp mi_to_mop(unsigned mi)
|
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 = {
|
static const TranslatorOps rx_tr_ops = {
|
||||||
.init_disas_context = rx_tr_init_disas_context,
|
.init_disas_context = rx_tr_init_disas_context,
|
||||||
.tb_start = rx_tr_tb_start,
|
.tb_start = rx_tr_tb_start,
|
||||||
.insn_start = rx_tr_insn_start,
|
.insn_start = rx_tr_insn_start,
|
||||||
.translate_insn = rx_tr_translate_insn,
|
.translate_insn = rx_tr_translate_insn,
|
||||||
.tb_stop = rx_tr_tb_stop,
|
.tb_stop = rx_tr_tb_stop,
|
||||||
.disas_log = rx_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||||
|
@ -31,13 +31,11 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "s390x-internal.h"
|
#include "s390x-internal.h"
|
||||||
#include "disas/disas.h"
|
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "tcg/tcg-op.h"
|
#include "tcg/tcg-op.h"
|
||||||
#include "tcg/tcg-op-gvec.h"
|
#include "tcg/tcg-op-gvec.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "qemu/host-utils.h"
|
#include "qemu/host-utils.h"
|
||||||
#include "exec/cpu_ldst.h"
|
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
#include "exec/helper-gen.h"
|
#include "exec/helper-gen.h"
|
||||||
|
|
||||||
@ -6192,6 +6190,8 @@ static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s)
|
|||||||
const DisasInsn *info;
|
const DisasInsn *info;
|
||||||
|
|
||||||
if (unlikely(s->ex_value)) {
|
if (unlikely(s->ex_value)) {
|
||||||
|
uint64_t be_insn;
|
||||||
|
|
||||||
/* Drop the EX data now, so that it's clear on exception paths. */
|
/* Drop the EX data now, so that it's clear on exception paths. */
|
||||||
tcg_gen_st_i64(tcg_constant_i64(0), tcg_env,
|
tcg_gen_st_i64(tcg_constant_i64(0), tcg_env,
|
||||||
offsetof(CPUS390XState, ex_value));
|
offsetof(CPUS390XState, ex_value));
|
||||||
@ -6199,13 +6199,11 @@ static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s)
|
|||||||
/* Extract the values saved by EXECUTE. */
|
/* Extract the values saved by EXECUTE. */
|
||||||
insn = s->ex_value & 0xffffffffffff0000ull;
|
insn = s->ex_value & 0xffffffffffff0000ull;
|
||||||
ilen = s->ex_value & 0xf;
|
ilen = s->ex_value & 0xf;
|
||||||
|
op = insn >> 56;
|
||||||
|
|
||||||
/* Register insn bytes with translator so plugins work. */
|
/* Register insn bytes with translator so plugins work. */
|
||||||
for (int i = 0; i < ilen; i++) {
|
be_insn = cpu_to_be64(insn);
|
||||||
uint8_t byte = extract64(insn, 56 - (i * 8), 8);
|
translator_fake_ld(&s->base, &be_insn, get_ilen(op));
|
||||||
translator_fake_ldb(byte, pc + i);
|
|
||||||
}
|
|
||||||
op = insn >> 56;
|
|
||||||
} else {
|
} else {
|
||||||
insn = ld_code2(env, s, pc);
|
insn = ld_code2(env, s, pc);
|
||||||
op = (insn >> 8) & 0xff;
|
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,
|
static target_ulong get_next_pc(CPUS390XState *env, DisasContext *s,
|
||||||
uint64_t pc)
|
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);
|
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)
|
CPUState *cs, FILE *logfile)
|
||||||
{
|
{
|
||||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||||
|
|
||||||
if (unlikely(dc->ex_value)) {
|
if (unlikely(dc->ex_value)) {
|
||||||
/* ??? Unfortunately target_disas can't use host memory. */
|
/* The ex_value has been recorded with translator_fake_ld. */
|
||||||
fprintf(logfile, "IN: EXECUTE %016" PRIx64, dc->ex_value);
|
fprintf(logfile, "IN: EXECUTE\n");
|
||||||
} else {
|
target_disas(logfile, cs, &dc->base);
|
||||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dc->base.pc_first));
|
return true;
|
||||||
target_disas(logfile, cs, dc->base.pc_first, dc->base.tb->size);
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TranslatorOps s390x_tr_ops = {
|
static const TranslatorOps s390x_tr_ops = {
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "disas/disas.h"
|
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "tcg/tcg-op.h"
|
#include "tcg/tcg-op.h"
|
||||||
#include "exec/helper-proto.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 = {
|
static const TranslatorOps sh4_tr_ops = {
|
||||||
.init_disas_context = sh4_tr_init_disas_context,
|
.init_disas_context = sh4_tr_init_disas_context,
|
||||||
.tb_start = sh4_tr_tb_start,
|
.tb_start = sh4_tr_tb_start,
|
||||||
.insn_start = sh4_tr_insn_start,
|
.insn_start = sh4_tr_insn_start,
|
||||||
.translate_insn = sh4_tr_translate_insn,
|
.translate_insn = sh4_tr_translate_insn,
|
||||||
.tb_stop = sh4_tr_tb_stop,
|
.tb_stop = sh4_tr_tb_stop,
|
||||||
.disas_log = sh4_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "disas/disas.h"
|
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "tcg/tcg-op.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 = {
|
static const TranslatorOps sparc_tr_ops = {
|
||||||
.init_disas_context = sparc_tr_init_disas_context,
|
.init_disas_context = sparc_tr_init_disas_context,
|
||||||
.tb_start = sparc_tr_tb_start,
|
.tb_start = sparc_tr_tb_start,
|
||||||
.insn_start = sparc_tr_insn_start,
|
.insn_start = sparc_tr_insn_start,
|
||||||
.translate_insn = sparc_tr_translate_insn,
|
.translate_insn = sparc_tr_translate_insn,
|
||||||
.tb_stop = sparc_tr_tb_stop,
|
.tb_stop = sparc_tr_tb_stop,
|
||||||
.disas_log = sparc_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "disas/disas.h"
|
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "tcg/tcg-op.h"
|
#include "tcg/tcg-op.h"
|
||||||
#include "exec/cpu_ldst.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 = {
|
static const TranslatorOps tricore_tr_ops = {
|
||||||
.init_disas_context = tricore_tr_init_disas_context,
|
.init_disas_context = tricore_tr_init_disas_context,
|
||||||
.tb_start = tricore_tr_tb_start,
|
.tb_start = tricore_tr_tb_start,
|
||||||
.insn_start = tricore_tr_insn_start,
|
.insn_start = tricore_tr_insn_start,
|
||||||
.translate_insn = tricore_tr_translate_insn,
|
.translate_insn = tricore_tr_translate_insn,
|
||||||
.tb_stop = tricore_tr_tb_stop,
|
.tb_stop = tricore_tr_tb_stop,
|
||||||
.disas_log = tricore_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,11 +32,9 @@
|
|||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "disas/disas.h"
|
|
||||||
#include "tcg/tcg-op.h"
|
#include "tcg/tcg-op.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "qemu/qemu-print.h"
|
#include "qemu/qemu-print.h"
|
||||||
#include "exec/cpu_ldst.h"
|
|
||||||
#include "semihosting/semihost.h"
|
#include "semihosting/semihost.h"
|
||||||
#include "exec/translator.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)
|
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);
|
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 = {
|
static const TranslatorOps xtensa_translator_ops = {
|
||||||
.init_disas_context = xtensa_tr_init_disas_context,
|
.init_disas_context = xtensa_tr_init_disas_context,
|
||||||
.tb_start = xtensa_tr_tb_start,
|
.tb_start = xtensa_tr_tb_start,
|
||||||
.insn_start = xtensa_tr_insn_start,
|
.insn_start = xtensa_tr_insn_start,
|
||||||
.translate_insn = xtensa_tr_translate_insn,
|
.translate_insn = xtensa_tr_translate_insn,
|
||||||
.tb_stop = xtensa_tr_tb_stop,
|
.tb_stop = xtensa_tr_tb_stop,
|
||||||
.disas_log = xtensa_tr_disas_log,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||||
|
@ -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,
|
static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg dest,
|
||||||
TCGReg arg1, intptr_t arg2)
|
TCGReg base, intptr_t offset)
|
||||||
{
|
{
|
||||||
bool is_32bit = type == TCG_TYPE_I32;
|
switch (type) {
|
||||||
tcg_out_ldst(s, is_32bit ? OPC_LD_W : OPC_LD_D, arg, arg1, arg2);
|
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,
|
static void tcg_out_st(TCGContext *s, TCGType type, TCGReg src,
|
||||||
TCGReg arg1, intptr_t arg2)
|
TCGReg base, intptr_t offset)
|
||||||
{
|
{
|
||||||
bool is_32bit = type == TCG_TYPE_I32;
|
switch (type) {
|
||||||
tcg_out_ldst(s, is_32bit ? OPC_ST_W : OPC_ST_D, arg, arg1, arg2);
|
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,
|
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;
|
TCGType type = vecl + TCG_TYPE_V64;
|
||||||
TCGArg a0, a1, a2, a3;
|
TCGArg a0, a1, a2, a3;
|
||||||
TCGReg temp = TCG_REG_TMP0;
|
|
||||||
TCGReg temp_vec = TCG_VEC_TMP0;
|
TCGReg temp_vec = TCG_VEC_TMP0;
|
||||||
|
|
||||||
static const LoongArchInsn cmp_vec_insn[16][4] = {
|
static const LoongArchInsn cmp_vec_insn[16][4] = {
|
||||||
@ -1820,22 +1889,10 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
|
|||||||
|
|
||||||
switch (opc) {
|
switch (opc) {
|
||||||
case INDEX_op_st_vec:
|
case INDEX_op_st_vec:
|
||||||
/* Try to fit vst imm */
|
tcg_out_st(s, type, a0, a1, a2);
|
||||||
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);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case INDEX_op_ld_vec:
|
case INDEX_op_ld_vec:
|
||||||
/* Try to fit vld imm */
|
tcg_out_ld(s, type, a0, a1, a2);
|
||||||
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);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case INDEX_op_and_vec:
|
case INDEX_op_and_vec:
|
||||||
tcg_out_opc_vand_v(s, a0, a1, a2);
|
tcg_out_opc_vand_v(s, a0, a1, a2);
|
||||||
|
12
tcg/tcg.c
12
tcg/tcg.c
@ -761,15 +761,6 @@ QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) -
|
|||||||
< MIN_TLB_MASK_TABLE_OFS);
|
< MIN_TLB_MASK_TABLE_OFS);
|
||||||
#endif
|
#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
|
* 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
|
* 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);
|
qatomic_set(&tcg_ctxs[n], s);
|
||||||
|
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
alloc_tcg_plugin_context(s);
|
|
||||||
tcg_region_initial_alloc(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];
|
indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
alloc_tcg_plugin_context(s);
|
|
||||||
|
|
||||||
tcg_ctx = s;
|
tcg_ctx = s;
|
||||||
/*
|
/*
|
||||||
* In user-mode we simply share the init context among threads, since we
|
* In user-mode we simply share the init context among threads, since we
|
||||||
|
Loading…
Reference in New Issue
Block a user