mirror of https://github.com/xemu-project/xemu.git
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;
|
||||
|
||||
if (unlikely(qemu_loglevel_mask(LOG_TB_OP_PLUGIN)
|
||||
&& qemu_log_in_addr_range(plugin_tb->vaddr))) {
|
||||
&& qemu_log_in_addr_range(tcg_ctx->plugin_db->pc_first))) {
|
||||
FILE *logfile = qemu_log_trylock();
|
||||
if (logfile) {
|
||||
fprintf(logfile, "OP before plugin injection:\n");
|
||||
|
@ -303,35 +303,34 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
|
|||
}
|
||||
}
|
||||
|
||||
bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db,
|
||||
bool mem_only)
|
||||
bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db)
|
||||
{
|
||||
bool ret = false;
|
||||
struct qemu_plugin_tb *ptb;
|
||||
|
||||
if (test_bit(QEMU_PLUGIN_EV_VCPU_TB_TRANS, cpu->plugin_state->event_mask)) {
|
||||
struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
|
||||
if (!test_bit(QEMU_PLUGIN_EV_VCPU_TB_TRANS,
|
||||
cpu->plugin_state->event_mask)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* reset callbacks */
|
||||
tcg_ctx->plugin_db = db;
|
||||
tcg_ctx->plugin_insn = NULL;
|
||||
ptb = tcg_ctx->plugin_tb;
|
||||
|
||||
if (ptb) {
|
||||
/* Reset callbacks */
|
||||
if (ptb->cbs) {
|
||||
g_array_set_size(ptb->cbs, 0);
|
||||
}
|
||||
ptb->n = 0;
|
||||
|
||||
ret = true;
|
||||
|
||||
ptb->vaddr = db->pc_first;
|
||||
ptb->vaddr2 = -1;
|
||||
ptb->haddr1 = db->host_addr[0];
|
||||
ptb->haddr2 = NULL;
|
||||
ptb->mem_only = mem_only;
|
||||
ptb->mem_helper = false;
|
||||
|
||||
tcg_gen_plugin_cb(PLUGIN_GEN_FROM_TB);
|
||||
} else {
|
||||
ptb = g_new0(struct qemu_plugin_tb, 1);
|
||||
tcg_ctx->plugin_tb = ptb;
|
||||
ptb->insns = g_ptr_array_new();
|
||||
}
|
||||
|
||||
tcg_ctx->plugin_insn = NULL;
|
||||
|
||||
return ret;
|
||||
tcg_gen_plugin_cb(PLUGIN_GEN_FROM_TB);
|
||||
return true;
|
||||
}
|
||||
|
||||
void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
|
||||
|
@ -345,11 +344,9 @@ void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
|
|||
ptb->n = n;
|
||||
if (n <= ptb->insns->len) {
|
||||
insn = g_ptr_array_index(ptb->insns, n - 1);
|
||||
g_byte_array_set_size(insn->data, 0);
|
||||
} else {
|
||||
assert(n - 1 == ptb->insns->len);
|
||||
insn = g_new0(struct qemu_plugin_insn, 1);
|
||||
insn->data = g_byte_array_sized_new(4);
|
||||
g_ptr_array_add(ptb->insns, insn);
|
||||
}
|
||||
|
||||
|
@ -366,28 +363,16 @@ void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
|
|||
pc = db->pc_next;
|
||||
insn->vaddr = pc;
|
||||
|
||||
/*
|
||||
* Detect page crossing to get the new host address.
|
||||
* Note that we skip this when haddr1 == NULL, e.g. when we're
|
||||
* fetching instructions from a region not backed by RAM.
|
||||
*/
|
||||
if (ptb->haddr1 == NULL) {
|
||||
insn->haddr = NULL;
|
||||
} else if (is_same_page(db, db->pc_next)) {
|
||||
insn->haddr = ptb->haddr1 + pc - ptb->vaddr;
|
||||
} else {
|
||||
if (ptb->vaddr2 == -1) {
|
||||
ptb->vaddr2 = TARGET_PAGE_ALIGN(db->pc_first);
|
||||
get_page_addr_code_hostp(cpu_env(cpu), ptb->vaddr2, &ptb->haddr2);
|
||||
}
|
||||
insn->haddr = ptb->haddr2 + pc - ptb->vaddr2;
|
||||
}
|
||||
|
||||
tcg_gen_plugin_cb(PLUGIN_GEN_FROM_INSN);
|
||||
}
|
||||
|
||||
void plugin_gen_insn_end(void)
|
||||
{
|
||||
const DisasContextBase *db = tcg_ctx->plugin_db;
|
||||
struct qemu_plugin_insn *pinsn = tcg_ctx->plugin_insn;
|
||||
|
||||
pinsn->len = db->fake_insn ? db->record_len : db->pc_next - pinsn->vaddr;
|
||||
|
||||
tcg_gen_plugin_cb(PLUGIN_GEN_AFTER_INSN);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,10 @@
|
|||
#include "exec/translator.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/plugin-gen.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "tcg/tcg-op-common.h"
|
||||
#include "internal-target.h"
|
||||
#include "disas/disas.h"
|
||||
|
||||
static void set_can_do_io(DisasContextBase *db, bool val)
|
||||
{
|
||||
|
@ -129,8 +131,11 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
|||
db->max_insns = *max_insns;
|
||||
db->singlestep_enabled = cflags & CF_SINGLE_STEP;
|
||||
db->insn_start = NULL;
|
||||
db->fake_insn = false;
|
||||
db->host_addr[0] = host_pc;
|
||||
db->host_addr[1] = NULL;
|
||||
db->record_start = 0;
|
||||
db->record_len = 0;
|
||||
|
||||
ops->init_disas_context(db, cpu);
|
||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
||||
|
@ -140,7 +145,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
|||
ops->tb_start(db, cpu);
|
||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
||||
|
||||
plugin_enabled = plugin_gen_tb_start(cpu, db, cflags & CF_MEMI_ONLY);
|
||||
plugin_enabled = plugin_gen_tb_start(cpu, db);
|
||||
db->plugin_enabled = plugin_enabled;
|
||||
|
||||
while (true) {
|
||||
|
@ -222,159 +227,249 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
|||
FILE *logfile = qemu_log_trylock();
|
||||
if (logfile) {
|
||||
fprintf(logfile, "----------------\n");
|
||||
ops->disas_log(db, cpu, logfile);
|
||||
|
||||
if (!ops->disas_log ||
|
||||
!ops->disas_log(db, cpu, logfile)) {
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(db->pc_first));
|
||||
target_disas(logfile, cpu, db);
|
||||
}
|
||||
fprintf(logfile, "\n");
|
||||
qemu_log_unlock(logfile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void *translator_access(CPUArchState *env, DisasContextBase *db,
|
||||
vaddr pc, size_t len)
|
||||
static bool translator_ld(CPUArchState *env, DisasContextBase *db,
|
||||
void *dest, vaddr pc, size_t len)
|
||||
{
|
||||
TranslationBlock *tb = db->tb;
|
||||
vaddr last = pc + len - 1;
|
||||
void *host;
|
||||
vaddr base, end;
|
||||
TranslationBlock *tb;
|
||||
|
||||
tb = db->tb;
|
||||
vaddr base;
|
||||
|
||||
/* Use slow path if first page is MMIO. */
|
||||
if (unlikely(tb_page_addr0(tb) == -1)) {
|
||||
return NULL;
|
||||
/* We capped translation with first page MMIO in tb_gen_code. */
|
||||
tcg_debug_assert(db->max_insns == 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
end = pc + len - 1;
|
||||
if (likely(is_same_page(db, end))) {
|
||||
host = db->host_addr[0];
|
||||
base = db->pc_first;
|
||||
} else {
|
||||
host = db->host_addr[0];
|
||||
base = db->pc_first;
|
||||
|
||||
if (likely(((base ^ last) & TARGET_PAGE_MASK) == 0)) {
|
||||
/* Entire read is from the first page. */
|
||||
memcpy(dest, host + (pc - base), len);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (unlikely(((base ^ pc) & TARGET_PAGE_MASK) == 0)) {
|
||||
/* Read begins on the first page and extends to the second. */
|
||||
size_t len0 = -(pc | TARGET_PAGE_MASK);
|
||||
memcpy(dest, host + (pc - base), len0);
|
||||
pc += len0;
|
||||
dest += len0;
|
||||
len -= len0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The read must conclude on the second page and not extend to a third.
|
||||
*
|
||||
* TODO: We could allow the two pages to be virtually discontiguous,
|
||||
* since we already allow the two pages to be physically discontiguous.
|
||||
* The only reasonable use case would be executing an insn at the end
|
||||
* of the address space wrapping around to the beginning. For that,
|
||||
* we would need to know the current width of the address space.
|
||||
* In the meantime, assert.
|
||||
*/
|
||||
base = (base & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
|
||||
assert(((base ^ pc) & TARGET_PAGE_MASK) == 0);
|
||||
assert(((base ^ last) & TARGET_PAGE_MASK) == 0);
|
||||
host = db->host_addr[1];
|
||||
|
||||
if (host == NULL) {
|
||||
tb_page_addr_t page0, old_page1, new_page1;
|
||||
|
||||
new_page1 = get_page_addr_code_hostp(env, base, &db->host_addr[1]);
|
||||
|
||||
/*
|
||||
* If the second page is MMIO, treat as if the first page
|
||||
* was MMIO as well, so that we do not cache the TB.
|
||||
*/
|
||||
if (unlikely(new_page1 == -1)) {
|
||||
tb_unlock_pages(tb);
|
||||
tb_set_page_addr0(tb, -1);
|
||||
/* Require that this be the final insn. */
|
||||
db->max_insns = db->num_insns;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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];
|
||||
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);
|
||||
return host + (pc - base);
|
||||
memcpy(dest, host + (pc - base), len);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void plugin_insn_append(abi_ptr pc, const void *from, size_t size)
|
||||
static void record_save(DisasContextBase *db, vaddr pc,
|
||||
const void *from, int size)
|
||||
{
|
||||
#ifdef CONFIG_PLUGIN
|
||||
struct qemu_plugin_insn *insn = tcg_ctx->plugin_insn;
|
||||
abi_ptr off;
|
||||
int offset;
|
||||
|
||||
if (insn == NULL) {
|
||||
/* Do not record probes before the start of TB. */
|
||||
if (pc < db->pc_first) {
|
||||
return;
|
||||
}
|
||||
off = pc - insn->vaddr;
|
||||
if (off < insn->data->len) {
|
||||
g_byte_array_set_size(insn->data, off);
|
||||
} else if (off > insn->data->len) {
|
||||
/* we have an unexpected gap */
|
||||
g_assert_not_reached();
|
||||
|
||||
/*
|
||||
* In translator_access, we verified that pc is within 2 pages
|
||||
* of pc_first, thus this will never overflow.
|
||||
*/
|
||||
offset = pc - db->pc_first;
|
||||
|
||||
/*
|
||||
* Either the first or second page may be I/O. If it is the second,
|
||||
* then the first byte we need to record will be at a non-zero offset.
|
||||
* In either case, we should not need to record but a single insn.
|
||||
*/
|
||||
if (db->record_len == 0) {
|
||||
db->record_start = offset;
|
||||
db->record_len = size;
|
||||
} else {
|
||||
assert(offset == db->record_start + db->record_len);
|
||||
assert(db->record_len + size <= sizeof(db->record));
|
||||
db->record_len += size;
|
||||
}
|
||||
|
||||
insn->data = g_byte_array_append(insn->data, from, size);
|
||||
#endif
|
||||
memcpy(db->record + (offset - db->record_start), from, size);
|
||||
}
|
||||
|
||||
uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, abi_ptr pc)
|
||||
size_t translator_st_len(const DisasContextBase *db)
|
||||
{
|
||||
uint8_t ret;
|
||||
void *p = translator_access(env, db, pc, sizeof(ret));
|
||||
return db->fake_insn ? db->record_len : db->tb->size;
|
||||
}
|
||||
|
||||
if (p) {
|
||||
plugin_insn_append(pc, p, sizeof(ret));
|
||||
return ldub_p(p);
|
||||
bool translator_st(const DisasContextBase *db, void *dest,
|
||||
vaddr addr, size_t len)
|
||||
{
|
||||
size_t offset, offset_end;
|
||||
|
||||
if (addr < db->pc_first) {
|
||||
return false;
|
||||
}
|
||||
ret = cpu_ldub_code(env, pc);
|
||||
plugin_insn_append(pc, &ret, sizeof(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
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);
|
||||
offset = addr - db->pc_first;
|
||||
offset_end = offset + len;
|
||||
if (offset_end > translator_st_len(db)) {
|
||||
return false;
|
||||
}
|
||||
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)
|
||||
{
|
||||
uint32_t ret, plug;
|
||||
void *p = translator_access(env, db, pc, sizeof(ret));
|
||||
if (!db->fake_insn) {
|
||||
size_t offset_page1 = -(db->pc_first | TARGET_PAGE_MASK);
|
||||
|
||||
if (p) {
|
||||
plugin_insn_append(pc, p, sizeof(ret));
|
||||
return ldl_p(p);
|
||||
/* Get all the bytes from the first page. */
|
||||
if (db->host_addr[0]) {
|
||||
if (offset_end <= offset_page1) {
|
||||
memcpy(dest, db->host_addr[0] + offset, len);
|
||||
return true;
|
||||
}
|
||||
if (offset < offset_page1) {
|
||||
size_t len0 = offset_page1 - offset;
|
||||
memcpy(dest, db->host_addr[0] + offset, len0);
|
||||
offset += len0;
|
||||
dest += len0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get any bytes from the second page. */
|
||||
if (db->host_addr[1] && offset >= offset_page1) {
|
||||
memcpy(dest, db->host_addr[1] + (offset - offset_page1),
|
||||
offset_end - offset);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
uint64_t ret, plug;
|
||||
void *p = translator_access(env, db, pc, sizeof(ret));
|
||||
|
||||
if (p) {
|
||||
plugin_insn_append(pc, p, sizeof(ret));
|
||||
return ldq_p(p);
|
||||
/* Else get recorded bytes. */
|
||||
if (db->record_len != 0 &&
|
||||
offset >= db->record_start &&
|
||||
offset_end <= db->record_start + db->record_len) {
|
||||
memcpy(dest, db->record + (offset - db->record_start),
|
||||
offset_end - offset);
|
||||
return true;
|
||||
}
|
||||
ret = cpu_ldq_code(env, pc);
|
||||
plug = tswap64(ret);
|
||||
plugin_insn_append(pc, &plug, sizeof(ret));
|
||||
return ret;
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
uint32_t insn_opcode;
|
||||
insn_opcode = *((uint32_t *)qemu_plugin_insn_data(insn));
|
||||
uint32_t insn_opcode = 0;
|
||||
qemu_plugin_insn_data(insn, &insn_opcode, sizeof(insn_opcode));
|
||||
|
||||
char *output = g_strdup_printf("0x%"PRIx64", 0x%"PRIx32", \"%s\"",
|
||||
insn_vaddr, insn_opcode, insn_disas);
|
||||
|
||||
|
|
|
@ -252,7 +252,7 @@ static struct qemu_plugin_scoreboard *find_counter(
|
|||
{
|
||||
int i;
|
||||
uint64_t *cnt = NULL;
|
||||
uint32_t opcode;
|
||||
uint32_t opcode = 0;
|
||||
InsnClassExecCount *class = NULL;
|
||||
|
||||
/*
|
||||
|
@ -261,7 +261,7 @@ static struct qemu_plugin_scoreboard *find_counter(
|
|||
* They would probably benefit from a more tailored plugin.
|
||||
* However we can fall back to individual instruction counting.
|
||||
*/
|
||||
opcode = *((uint32_t *)qemu_plugin_insn_data(insn));
|
||||
qemu_plugin_insn_data(insn, &opcode, sizeof(opcode));
|
||||
|
||||
for (i = 0; !cnt && i < class_table_sz; i++) {
|
||||
class = &class_table[i];
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
} CPUDebug;
|
||||
|
||||
void disas_initialize_debug(CPUDebug *s);
|
||||
void disas_initialize_debug_target(CPUDebug *s, CPUState *cpu);
|
||||
int disas_gstring_printf(FILE *stream, const char *fmt, ...)
|
||||
G_GNUC_PRINTF(2, 3);
|
||||
|
||||
int print_insn_od_host(bfd_vma pc, disassemble_info *info);
|
||||
int print_insn_od_target(bfd_vma pc, disassemble_info *info);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,6 +11,19 @@
|
|||
#include "hw/core/cpu.h"
|
||||
#include "monitor/monitor.h"
|
||||
|
||||
/*
|
||||
* Get LENGTH bytes from info's buffer, at target address memaddr.
|
||||
* Transfer them to myaddr.
|
||||
*/
|
||||
static int
|
||||
virtual_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
|
||||
struct disassemble_info *info)
|
||||
{
|
||||
CPUDebug *s = container_of(info, CPUDebug, info);
|
||||
int r = cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0);
|
||||
return r ? EIO : 0;
|
||||
}
|
||||
|
||||
static int
|
||||
physical_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
|
||||
struct disassemble_info *info)
|
||||
|
@ -38,6 +51,8 @@ void monitor_disas(Monitor *mon, CPUState *cpu, uint64_t pc,
|
|||
|
||||
if (is_physical) {
|
||||
s.info.read_memory_func = physical_read_memory;
|
||||
} else {
|
||||
s.info.read_memory_func = virtual_read_memory;
|
||||
}
|
||||
s.info.buffer_vma = pc;
|
||||
|
||||
|
|
|
@ -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_XTENSA_DIS', if_true: files('xtensa.c'))
|
||||
common_ss.add(when: capstone, if_true: [files('capstone.c'), capstone])
|
||||
common_ss.add(files('disas.c'))
|
||||
|
||||
common_ss.add(when: 'CONFIG_TCG', if_true: files(
|
||||
'disas-host.c',
|
||||
'disas-target.c',
|
||||
'objdump.c'
|
||||
))
|
||||
common_ss.add(files('disas-common.c'))
|
||||
system_ss.add(files('disas-mon.c'))
|
||||
specific_ss.add(capstone)
|
||||
|
|
|
@ -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
|
||||
|
||||
/* Disassemble this for me please... (debugging). */
|
||||
#ifdef CONFIG_TCG
|
||||
void disas(FILE *out, const void *code, size_t size);
|
||||
void target_disas(FILE *out, CPUState *cpu, uint64_t code, size_t size);
|
||||
void target_disas(FILE *out, CPUState *cpu, const DisasContextBase *db);
|
||||
#endif
|
||||
|
||||
void monitor_disas(Monitor *mon, CPUState *cpu, uint64_t pc,
|
||||
int nb_insn, bool is_physical);
|
||||
|
||||
char *plugin_disas(CPUState *cpu, uint64_t addr, size_t size);
|
||||
#ifdef CONFIG_PLUGIN
|
||||
char *plugin_disas(CPUState *cpu, const DisasContextBase *db,
|
||||
uint64_t addr, size_t size);
|
||||
#endif
|
||||
|
||||
/* Look up symbol for debugging purpose. Returns "" if unknown. */
|
||||
const char *lookup_symbol(uint64_t orig_addr);
|
||||
|
|
|
@ -355,16 +355,6 @@ uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr addr);
|
|||
uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr addr);
|
||||
uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr);
|
||||
|
||||
static inline int cpu_ldsb_code(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return (int8_t)cpu_ldub_code(env, addr);
|
||||
}
|
||||
|
||||
static inline int cpu_ldsw_code(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return (int16_t)cpu_lduw_code(env, addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* tlb_vaddr_to_host:
|
||||
* @env: CPUArchState
|
||||
|
|
|
@ -18,8 +18,7 @@ struct DisasContextBase;
|
|||
|
||||
#ifdef CONFIG_PLUGIN
|
||||
|
||||
bool plugin_gen_tb_start(CPUState *cpu, const struct DisasContextBase *db,
|
||||
bool supress);
|
||||
bool plugin_gen_tb_start(CPUState *cpu, const struct DisasContextBase *db);
|
||||
void plugin_gen_tb_end(CPUState *cpu, size_t num_insns);
|
||||
void plugin_gen_insn_start(CPUState *cpu, const struct DisasContextBase *db);
|
||||
void plugin_gen_insn_end(void);
|
||||
|
@ -28,8 +27,8 @@ void plugin_gen_disable_mem_helpers(void);
|
|||
|
||||
#else /* !CONFIG_PLUGIN */
|
||||
|
||||
static inline bool
|
||||
plugin_gen_tb_start(CPUState *cpu, const struct DisasContextBase *db, bool sup)
|
||||
static inline
|
||||
bool plugin_gen_tb_start(CPUState *cpu, const struct DisasContextBase *db)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -19,10 +19,7 @@
|
|||
*/
|
||||
|
||||
#include "qemu/bswap.h"
|
||||
#include "exec/cpu-common.h"
|
||||
#include "exec/cpu-defs.h"
|
||||
#include "exec/abi_ptr.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/vaddr.h"
|
||||
|
||||
/**
|
||||
* gen_intermediate_code
|
||||
|
@ -75,14 +72,14 @@ typedef enum DisasJumpType {
|
|||
* @num_insns: Number of translated instructions (including current).
|
||||
* @max_insns: Maximum number of instructions to be translated in this TB.
|
||||
* @singlestep_enabled: "Hardware" single stepping enabled.
|
||||
* @saved_can_do_io: Known value of cpu->neg.can_do_io, or -1 for unknown.
|
||||
* @plugin_enabled: TCG plugin enabled in this TB.
|
||||
* @fake_insn: True if translator_fake_ldb used.
|
||||
* @insn_start: The last op emitted by the insn_start hook,
|
||||
* which is expected to be INDEX_op_insn_start.
|
||||
*
|
||||
* Architecture-agnostic disassembly context.
|
||||
*/
|
||||
typedef struct DisasContextBase {
|
||||
struct DisasContextBase {
|
||||
TranslationBlock *tb;
|
||||
vaddr pc_first;
|
||||
vaddr pc_next;
|
||||
|
@ -91,9 +88,22 @@ typedef struct DisasContextBase {
|
|||
int max_insns;
|
||||
bool singlestep_enabled;
|
||||
bool plugin_enabled;
|
||||
bool fake_insn;
|
||||
struct TCGOp *insn_start;
|
||||
void *host_addr[2];
|
||||
} DisasContextBase;
|
||||
|
||||
/*
|
||||
* Record insn data that we cannot read directly from host memory.
|
||||
* There are only two reasons we cannot use host memory:
|
||||
* (1) We are executing from I/O,
|
||||
* (2) We are executing a synthetic instruction (s390x EX).
|
||||
* In both cases we need record exactly one instruction,
|
||||
* and thus the maximum amount of data we record is limited.
|
||||
*/
|
||||
int record_start;
|
||||
int record_len;
|
||||
uint8_t record[32];
|
||||
};
|
||||
|
||||
/**
|
||||
* TranslatorOps:
|
||||
|
@ -125,7 +135,7 @@ typedef struct TranslatorOps {
|
|||
void (*insn_start)(DisasContextBase *db, CPUState *cpu);
|
||||
void (*translate_insn)(DisasContextBase *db, CPUState *cpu);
|
||||
void (*tb_stop)(DisasContextBase *db, CPUState *cpu);
|
||||
void (*disas_log)(const DisasContextBase *db, CPUState *cpu, FILE *f);
|
||||
bool (*disas_log)(const DisasContextBase *db, CPUState *cpu, FILE *f);
|
||||
} TranslatorOps;
|
||||
|
||||
/**
|
||||
|
@ -185,14 +195,14 @@ bool translator_io_start(DisasContextBase *db);
|
|||
* the relevant information at translation time.
|
||||
*/
|
||||
|
||||
uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, abi_ptr pc);
|
||||
uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, abi_ptr pc);
|
||||
uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, abi_ptr pc);
|
||||
uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, abi_ptr pc);
|
||||
uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, vaddr pc);
|
||||
uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, vaddr pc);
|
||||
uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, vaddr pc);
|
||||
uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, vaddr pc);
|
||||
|
||||
static inline uint16_t
|
||||
translator_lduw_swap(CPUArchState *env, DisasContextBase *db,
|
||||
abi_ptr pc, bool do_swap)
|
||||
vaddr pc, bool do_swap)
|
||||
{
|
||||
uint16_t ret = translator_lduw(env, db, pc);
|
||||
if (do_swap) {
|
||||
|
@ -203,7 +213,7 @@ translator_lduw_swap(CPUArchState *env, DisasContextBase *db,
|
|||
|
||||
static inline uint32_t
|
||||
translator_ldl_swap(CPUArchState *env, DisasContextBase *db,
|
||||
abi_ptr pc, bool do_swap)
|
||||
vaddr pc, bool do_swap)
|
||||
{
|
||||
uint32_t ret = translator_ldl(env, db, pc);
|
||||
if (do_swap) {
|
||||
|
@ -214,7 +224,7 @@ translator_ldl_swap(CPUArchState *env, DisasContextBase *db,
|
|||
|
||||
static inline uint64_t
|
||||
translator_ldq_swap(CPUArchState *env, DisasContextBase *db,
|
||||
abi_ptr pc, bool do_swap)
|
||||
vaddr pc, bool do_swap)
|
||||
{
|
||||
uint64_t ret = translator_ldq(env, db, pc);
|
||||
if (do_swap) {
|
||||
|
@ -224,17 +234,42 @@ translator_ldq_swap(CPUArchState *env, DisasContextBase *db,
|
|||
}
|
||||
|
||||
/**
|
||||
* translator_fake_ldb - fake instruction load
|
||||
* @insn8: byte of instruction
|
||||
* @pc: program counter of instruction
|
||||
* translator_fake_ld - fake instruction load
|
||||
* @db: Disassembly context
|
||||
* @data: bytes of instruction
|
||||
* @len: number of bytes
|
||||
*
|
||||
* This is a special case helper used where the instruction we are
|
||||
* about to translate comes from somewhere else (e.g. being
|
||||
* re-synthesised for s390x "ex"). It ensures we update other areas of
|
||||
* the translator with details of the executed instruction.
|
||||
*/
|
||||
void translator_fake_ldb(uint8_t insn8, abi_ptr pc);
|
||||
void translator_fake_ld(DisasContextBase *db, const void *data, size_t len);
|
||||
|
||||
/**
|
||||
* translator_st
|
||||
* @db: disassembly context
|
||||
* @dest: address to copy into
|
||||
* @addr: virtual address within TB
|
||||
* @len: length
|
||||
*
|
||||
* Copy @len bytes from @addr into @dest.
|
||||
* All bytes must have been read during translation.
|
||||
* Return true on success or false on failure.
|
||||
*/
|
||||
bool translator_st(const DisasContextBase *db, void *dest,
|
||||
vaddr addr, size_t len);
|
||||
|
||||
/**
|
||||
* translator_st_len
|
||||
* @db: disassembly context
|
||||
*
|
||||
* Return the number of bytes available to copy from the
|
||||
* current translation block with translator_st.
|
||||
*/
|
||||
size_t translator_st_len(const DisasContextBase *db);
|
||||
|
||||
#ifdef COMPILING_PER_TARGET
|
||||
/*
|
||||
* Return whether addr is on the same page as where disassembly started.
|
||||
* Translators can use this to enforce the rule that only single-insn
|
||||
|
@ -244,5 +279,6 @@ static inline bool is_same_page(const DisasContextBase *db, vaddr addr)
|
|||
{
|
||||
return ((addr ^ db->pc_first) & TARGET_PAGE_MASK) == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* EXEC__TRANSLATOR_H */
|
||||
|
|
|
@ -98,17 +98,14 @@ struct qemu_plugin_dyn_cb {
|
|||
|
||||
/* Internal context for instrumenting an instruction */
|
||||
struct qemu_plugin_insn {
|
||||
GByteArray *data;
|
||||
uint64_t vaddr;
|
||||
void *haddr;
|
||||
GArray *insn_cbs;
|
||||
GArray *mem_cbs;
|
||||
uint8_t len;
|
||||
bool calls_helpers;
|
||||
|
||||
/* if set, the instruction calls helpers that might access guest memory */
|
||||
bool mem_helper;
|
||||
|
||||
bool mem_only;
|
||||
};
|
||||
|
||||
/* A scoreboard is an array of values, indexed by vcpu_index */
|
||||
|
@ -117,27 +114,10 @@ struct qemu_plugin_scoreboard {
|
|||
QLIST_ENTRY(qemu_plugin_scoreboard) entry;
|
||||
};
|
||||
|
||||
/*
|
||||
* qemu_plugin_insn allocate and cleanup functions. We don't expect to
|
||||
* cleanup many of these structures. They are reused for each fresh
|
||||
* translation.
|
||||
*/
|
||||
|
||||
static inline void qemu_plugin_insn_cleanup_fn(gpointer data)
|
||||
{
|
||||
struct qemu_plugin_insn *insn = (struct qemu_plugin_insn *) data;
|
||||
g_byte_array_free(insn->data, true);
|
||||
}
|
||||
|
||||
/* Internal context for this TranslationBlock */
|
||||
struct qemu_plugin_tb {
|
||||
GPtrArray *insns;
|
||||
size_t n;
|
||||
uint64_t vaddr;
|
||||
uint64_t vaddr2;
|
||||
void *haddr1;
|
||||
void *haddr2;
|
||||
bool mem_only;
|
||||
|
||||
/* if set, the TB calls helpers that might access guest memory */
|
||||
bool mem_helper;
|
||||
|
|
|
@ -61,7 +61,7 @@ typedef uint64_t qemu_plugin_id_t;
|
|||
|
||||
extern QEMU_PLUGIN_EXPORT int qemu_plugin_version;
|
||||
|
||||
#define QEMU_PLUGIN_VERSION 2
|
||||
#define QEMU_PLUGIN_VERSION 3
|
||||
|
||||
/**
|
||||
* struct qemu_info_t - system information for plugins
|
||||
|
@ -394,17 +394,16 @@ struct qemu_plugin_insn *
|
|||
qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx);
|
||||
|
||||
/**
|
||||
* qemu_plugin_insn_data() - return ptr to instruction data
|
||||
* qemu_plugin_insn_data() - copy instruction data
|
||||
* @insn: opaque instruction handle from qemu_plugin_tb_get_insn()
|
||||
* @dest: destination into which data is copied
|
||||
* @len: length of dest
|
||||
*
|
||||
* Note: data is only valid for duration of callback. See
|
||||
* qemu_plugin_insn_size() to calculate size of stream.
|
||||
*
|
||||
* Returns: pointer to a stream of bytes containing the value of this
|
||||
* instructions opcode.
|
||||
* Returns the number of bytes copied, minimum of @len and insn size.
|
||||
*/
|
||||
QEMU_PLUGIN_API
|
||||
const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn);
|
||||
size_t qemu_plugin_insn_data(const struct qemu_plugin_insn *insn,
|
||||
void *dest, size_t len);
|
||||
|
||||
/**
|
||||
* qemu_plugin_insn_size() - return size of instruction
|
||||
|
|
|
@ -42,6 +42,7 @@ typedef struct CPUPluginState CPUPluginState;
|
|||
typedef struct CPUState CPUState;
|
||||
typedef struct DeviceState DeviceState;
|
||||
typedef struct DirtyBitmapSnapshot DirtyBitmapSnapshot;
|
||||
typedef struct DisasContextBase DisasContextBase;
|
||||
typedef struct DisplayChangeListener DisplayChangeListener;
|
||||
typedef struct DriveInfo DriveInfo;
|
||||
typedef struct DumpState DumpState;
|
||||
|
|
|
@ -537,6 +537,7 @@ struct TCGContext {
|
|||
* space for instructions (for variable-instruction-length ISAs).
|
||||
*/
|
||||
struct qemu_plugin_tb *plugin_tb;
|
||||
const struct DisasContextBase *plugin_db;
|
||||
|
||||
/* descriptor of the instruction being translated */
|
||||
struct qemu_plugin_insn *plugin_insn;
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "tcg/tcg.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/gdbstub.h"
|
||||
#include "exec/translator.h"
|
||||
#include "disas/disas.h"
|
||||
#include "plugin.h"
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
@ -86,12 +87,17 @@ void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,
|
|||
plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_EXIT, cb);
|
||||
}
|
||||
|
||||
static bool tb_is_mem_only(void)
|
||||
{
|
||||
return tb_cflags(tcg_ctx->gen_tb) & CF_MEMI_ONLY;
|
||||
}
|
||||
|
||||
void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
|
||||
qemu_plugin_vcpu_udata_cb_t cb,
|
||||
enum qemu_plugin_cb_flags flags,
|
||||
void *udata)
|
||||
{
|
||||
if (!tb->mem_only) {
|
||||
if (!tb_is_mem_only()) {
|
||||
plugin_register_dyn_cb__udata(&tb->cbs, cb, flags, udata);
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +108,7 @@ void qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(
|
|||
qemu_plugin_u64 entry,
|
||||
uint64_t imm)
|
||||
{
|
||||
if (!tb->mem_only) {
|
||||
if (!tb_is_mem_only()) {
|
||||
plugin_register_inline_op_on_entry(&tb->cbs, 0, op, entry, imm);
|
||||
}
|
||||
}
|
||||
|
@ -112,7 +118,7 @@ void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
|
|||
enum qemu_plugin_cb_flags flags,
|
||||
void *udata)
|
||||
{
|
||||
if (!insn->mem_only) {
|
||||
if (!tb_is_mem_only()) {
|
||||
plugin_register_dyn_cb__udata(&insn->insn_cbs, cb, flags, udata);
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +129,7 @@ void qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(
|
|||
qemu_plugin_u64 entry,
|
||||
uint64_t imm)
|
||||
{
|
||||
if (!insn->mem_only) {
|
||||
if (!tb_is_mem_only()) {
|
||||
plugin_register_inline_op_on_entry(&insn->insn_cbs, 0, op, entry, imm);
|
||||
}
|
||||
}
|
||||
|
@ -194,7 +200,8 @@ size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb)
|
|||
|
||||
uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb)
|
||||
{
|
||||
return tb->vaddr;
|
||||
const DisasContextBase *db = tcg_ctx->plugin_db;
|
||||
return db->pc_first;
|
||||
}
|
||||
|
||||
struct qemu_plugin_insn *
|
||||
|
@ -205,7 +212,6 @@ qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx)
|
|||
return NULL;
|
||||
}
|
||||
insn = g_ptr_array_index(tb->insns, idx);
|
||||
insn->mem_only = tb->mem_only;
|
||||
return insn;
|
||||
}
|
||||
|
||||
|
@ -216,14 +222,18 @@ qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx)
|
|||
* instruction being translated.
|
||||
*/
|
||||
|
||||
const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn)
|
||||
size_t qemu_plugin_insn_data(const struct qemu_plugin_insn *insn,
|
||||
void *dest, size_t len)
|
||||
{
|
||||
return insn->data->data;
|
||||
const DisasContextBase *db = tcg_ctx->plugin_db;
|
||||
|
||||
len = MIN(len, insn->len);
|
||||
return translator_st(db, dest, insn->vaddr, len) ? len : 0;
|
||||
}
|
||||
|
||||
size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn)
|
||||
{
|
||||
return insn->data->len;
|
||||
return insn->len;
|
||||
}
|
||||
|
||||
uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn)
|
||||
|
@ -233,13 +243,36 @@ uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn)
|
|||
|
||||
void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn)
|
||||
{
|
||||
return insn->haddr;
|
||||
const DisasContextBase *db = tcg_ctx->plugin_db;
|
||||
vaddr page0_last = db->pc_first | ~TARGET_PAGE_MASK;
|
||||
|
||||
if (db->fake_insn) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ??? The return value is not intended for use of host memory,
|
||||
* but as a proxy for address space and physical address.
|
||||
* Thus we are only interested in the first byte and do not
|
||||
* care about spanning pages.
|
||||
*/
|
||||
if (insn->vaddr <= page0_last) {
|
||||
if (db->host_addr[0] == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return db->host_addr[0] + insn->vaddr - db->pc_first;
|
||||
} else {
|
||||
if (db->host_addr[1] == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return db->host_addr[1] + insn->vaddr - (page0_last + 1);
|
||||
}
|
||||
}
|
||||
|
||||
char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn)
|
||||
{
|
||||
CPUState *cpu = current_cpu;
|
||||
return plugin_disas(cpu, insn->vaddr, insn->data->len);
|
||||
return plugin_disas(tcg_ctx->cpu, tcg_ctx->plugin_db,
|
||||
insn->vaddr, insn->len);
|
||||
}
|
||||
|
||||
const char *qemu_plugin_insn_symbol(const struct qemu_plugin_insn *insn)
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "disas/disas.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
|
@ -2947,20 +2946,12 @@ static void alpha_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
static void alpha_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cpu, FILE *logfile)
|
||||
{
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
|
||||
target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps alpha_tr_ops = {
|
||||
.init_disas_context = alpha_tr_init_disas_context,
|
||||
.tb_start = alpha_tr_tb_start,
|
||||
.insn_start = alpha_tr_insn_start,
|
||||
.translate_insn = alpha_tr_translate_insn,
|
||||
.tb_stop = alpha_tr_tb_stop,
|
||||
.disas_log = alpha_tr_disas_log,
|
||||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "translate.h"
|
||||
#include "translate-a64.h"
|
||||
#include "qemu/log.h"
|
||||
#include "disas/disas.h"
|
||||
#include "arm_ldst.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "cpregs.h"
|
||||
|
@ -14382,20 +14381,10 @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
static void aarch64_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cpu, FILE *logfile)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dc->base.pc_first));
|
||||
target_disas(logfile, cpu, dc->base.pc_first, dc->base.tb->size);
|
||||
}
|
||||
|
||||
const TranslatorOps aarch64_translator_ops = {
|
||||
.init_disas_context = aarch64_tr_init_disas_context,
|
||||
.tb_start = aarch64_tr_tb_start,
|
||||
.insn_start = aarch64_tr_insn_start,
|
||||
.translate_insn = aarch64_tr_translate_insn,
|
||||
.tb_stop = aarch64_tr_tb_stop,
|
||||
.disas_log = aarch64_tr_disas_log,
|
||||
};
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include "translate.h"
|
||||
#include "translate-a32.h"
|
||||
#include "qemu/log.h"
|
||||
#include "disas/disas.h"
|
||||
#include "arm_ldst.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "cpregs.h"
|
||||
|
@ -9663,22 +9662,12 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
static void arm_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cpu, FILE *logfile)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dc->base.pc_first));
|
||||
target_disas(logfile, cpu, dc->base.pc_first, dc->base.tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps arm_translator_ops = {
|
||||
.init_disas_context = arm_tr_init_disas_context,
|
||||
.tb_start = arm_tr_tb_start,
|
||||
.insn_start = arm_tr_insn_start,
|
||||
.translate_insn = arm_tr_translate_insn,
|
||||
.tb_stop = arm_tr_tb_stop,
|
||||
.disas_log = arm_tr_disas_log,
|
||||
};
|
||||
|
||||
static const TranslatorOps thumb_translator_ops = {
|
||||
|
@ -9687,7 +9676,6 @@ static const TranslatorOps thumb_translator_ops = {
|
|||
.insn_start = arm_tr_insn_start,
|
||||
.translate_insn = thumb_tr_translate_insn,
|
||||
.tb_stop = arm_tr_tb_stop,
|
||||
.disas_log = arm_tr_disas_log,
|
||||
};
|
||||
|
||||
/* generate intermediate code for basic block 'tb'. */
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/helper-gen.h"
|
||||
#include "exec/log.h"
|
||||
|
@ -173,7 +172,7 @@ static int to_regs_00_30_by_two(DisasContext *ctx, int indx)
|
|||
|
||||
static uint16_t next_word(DisasContext *ctx)
|
||||
{
|
||||
return cpu_lduw_code(ctx->env, ctx->npc++ * 2);
|
||||
return translator_lduw(ctx->env, &ctx->base, ctx->npc++ * 2);
|
||||
}
|
||||
|
||||
static int append_16(DisasContext *ctx, int x)
|
||||
|
@ -2787,20 +2786,12 @@ static void avr_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
|
|||
}
|
||||
}
|
||||
|
||||
static void avr_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cs, FILE *logfile)
|
||||
{
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
|
||||
target_disas(logfile, cs, dcbase->pc_first, dcbase->tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps avr_tr_ops = {
|
||||
.init_disas_context = avr_tr_init_disas_context,
|
||||
.tb_start = avr_tr_tb_start,
|
||||
.insn_start = avr_tr_insn_start,
|
||||
.translate_insn = avr_tr_translate_insn,
|
||||
.tb_stop = avr_tr_tb_stop,
|
||||
.disas_log = avr_tr_disas_log,
|
||||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
|
|
|
@ -25,12 +25,10 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "mmu.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/translator.h"
|
||||
#include "crisv32-decode.h"
|
||||
#include "qemu/qemu-print.h"
|
||||
|
@ -223,37 +221,28 @@ static int sign_extend(unsigned int val, unsigned int width)
|
|||
}
|
||||
|
||||
static int cris_fetch(CPUCRISState *env, DisasContext *dc, uint32_t addr,
|
||||
unsigned int size, unsigned int sign)
|
||||
unsigned int size, bool sign)
|
||||
{
|
||||
int r;
|
||||
|
||||
switch (size) {
|
||||
case 4:
|
||||
{
|
||||
r = cpu_ldl_code(env, addr);
|
||||
r = translator_ldl(env, &dc->base, addr);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
r = translator_lduw(env, &dc->base, addr);
|
||||
if (sign) {
|
||||
r = cpu_ldsw_code(env, addr);
|
||||
} else {
|
||||
r = cpu_lduw_code(env, addr);
|
||||
r = (int16_t)r;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
r = translator_ldub(env, &dc->base, addr);
|
||||
if (sign) {
|
||||
r = cpu_ldsb_code(env, addr);
|
||||
} else {
|
||||
r = cpu_ldub_code(env, addr);
|
||||
r = (int8_t)r;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
cpu_abort(CPU(dc->cpu), "Invalid fetch size %d\n", size);
|
||||
break;
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
@ -2869,7 +2858,7 @@ static unsigned int crisv32_decoder(CPUCRISState *env, DisasContext *dc)
|
|||
int i;
|
||||
|
||||
/* Load a halfword onto the instruction register. */
|
||||
dc->ir = cris_fetch(env, dc, dc->pc, 2, 0);
|
||||
dc->ir = cris_fetch(env, dc, dc->pc, 2, 0);
|
||||
|
||||
/* Now decode it. */
|
||||
dc->opcode = EXTRACT_FIELD(dc->ir, 4, 11);
|
||||
|
@ -3148,22 +3137,12 @@ static void cris_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
static void cris_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cpu, FILE *logfile)
|
||||
{
|
||||
if (!DISAS_CRIS) {
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
|
||||
target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
|
||||
}
|
||||
}
|
||||
|
||||
static const TranslatorOps cris_tr_ops = {
|
||||
.init_disas_context = cris_tr_init_disas_context,
|
||||
.tb_start = cris_tr_tb_start,
|
||||
.insn_start = cris_tr_insn_start,
|
||||
.translate_insn = cris_tr_translate_insn,
|
||||
.tb_stop = cris_tr_tb_stop,
|
||||
.disas_log = cris_tr_disas_log,
|
||||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
|
|
|
@ -165,20 +165,7 @@ static int dec10_prep_move_m(CPUCRISState *env, DisasContext *dc,
|
|||
|
||||
/* Load [$rs] onto T1. */
|
||||
if (is_imm) {
|
||||
if (memsize != 4) {
|
||||
if (s_ext) {
|
||||
if (memsize == 1)
|
||||
imm = cpu_ldsb_code(env, dc->pc + 2);
|
||||
else
|
||||
imm = cpu_ldsw_code(env, dc->pc + 2);
|
||||
} else {
|
||||
if (memsize == 1)
|
||||
imm = cpu_ldub_code(env, dc->pc + 2);
|
||||
else
|
||||
imm = cpu_lduw_code(env, dc->pc + 2);
|
||||
}
|
||||
} else
|
||||
imm = cpu_ldl_code(env, dc->pc + 2);
|
||||
imm = cris_fetch(env, dc, dc->pc + 2, memsize, s_ext);
|
||||
|
||||
tcg_gen_movi_tl(dst, imm);
|
||||
|
||||
|
@ -929,10 +916,11 @@ static int dec10_dip(CPUCRISState *env, DisasContext *dc)
|
|||
LOG_DIS("dip pc=%x opcode=%d r%d r%d\n",
|
||||
dc->pc, dc->opcode, dc->src, dc->dst);
|
||||
if (dc->src == 15) {
|
||||
imm = cpu_ldl_code(env, dc->pc + 2);
|
||||
imm = cris_fetch(env, dc, dc->pc + 2, 4, 0);
|
||||
tcg_gen_movi_tl(cpu_PR[PR_PREFIX], imm);
|
||||
if (dc->postinc)
|
||||
if (dc->postinc) {
|
||||
insn_len += 4;
|
||||
}
|
||||
tcg_gen_addi_tl(cpu_R[15], cpu_R[15], insn_len - 2);
|
||||
} else {
|
||||
gen_load(dc, cpu_PR[PR_PREFIX], cpu_R[dc->src], 4, 0);
|
||||
|
@ -1095,10 +1083,10 @@ static unsigned int dec10_ind(CPUCRISState *env, DisasContext *dc)
|
|||
if (dc->src == 15) {
|
||||
LOG_DIS("jump.%d %d r%d r%d direct\n", size,
|
||||
dc->opcode, dc->src, dc->dst);
|
||||
imm = cpu_ldl_code(env, dc->pc + 2);
|
||||
if (dc->mode == CRISV10_MODE_AUTOINC)
|
||||
imm = cris_fetch(env, dc, dc->pc + 2, size, 0);
|
||||
if (dc->mode == CRISV10_MODE_AUTOINC) {
|
||||
insn_len += size;
|
||||
|
||||
}
|
||||
c = tcg_constant_tl(dc->pc + insn_len);
|
||||
t_gen_mov_preg_TN(dc, dc->dst, c);
|
||||
dc->jmp_pc = imm;
|
||||
|
@ -1164,7 +1152,7 @@ static unsigned int dec10_ind(CPUCRISState *env, DisasContext *dc)
|
|||
case CRISV10_IND_BCC_M:
|
||||
|
||||
cris_cc_mask(dc, 0);
|
||||
simm = cpu_ldsw_code(env, dc->pc + 2);
|
||||
simm = cris_fetch(env, dc, dc->pc + 2, 2, 1);
|
||||
simm += 4;
|
||||
|
||||
LOG_DIS("bcc_m: b%s %x\n", cc_name(dc->cond), dc->pc + simm);
|
||||
|
@ -1185,7 +1173,7 @@ static unsigned int crisv10_decoder(CPUCRISState *env, DisasContext *dc)
|
|||
unsigned int insn_len = 2;
|
||||
|
||||
/* Load a halfword onto the instruction register. */
|
||||
dc->ir = cpu_lduw_code(env, dc->pc);
|
||||
dc->ir = cris_fetch(env, dc, dc->pc, 2, 0);
|
||||
|
||||
/* Now decode it. */
|
||||
dc->opcode = EXTRACT_FIELD(dc->ir, 6, 9);
|
||||
|
|
|
@ -1022,7 +1022,7 @@ static bool pkt_crosses_page(CPUHexagonState *env, DisasContext *ctx)
|
|||
int nwords;
|
||||
|
||||
for (nwords = 0; !found_end && nwords < PACKET_WORDS_MAX; nwords++) {
|
||||
uint32_t word = cpu_ldl_code(env,
|
||||
uint32_t word = translator_ldl(env, &ctx->base,
|
||||
ctx->base.pc_next + nwords * sizeof(uint32_t));
|
||||
found_end = is_packet_end(word);
|
||||
}
|
||||
|
@ -1075,21 +1075,12 @@ static void hexagon_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
static void hexagon_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cpu, FILE *logfile)
|
||||
{
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
|
||||
target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
|
||||
}
|
||||
|
||||
|
||||
static const TranslatorOps hexagon_tr_ops = {
|
||||
.init_disas_context = hexagon_tr_init_disas_context,
|
||||
.tb_start = hexagon_tr_tb_start,
|
||||
.insn_start = hexagon_tr_insn_start,
|
||||
.translate_insn = hexagon_tr_translate_packet,
|
||||
.tb_stop = hexagon_tr_tb_stop,
|
||||
.disas_log = hexagon_tr_disas_log,
|
||||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "disas/disas.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/page-protection.h"
|
||||
|
@ -4816,31 +4815,29 @@ static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
|
|||
}
|
||||
}
|
||||
|
||||
static void hppa_tr_disas_log(const DisasContextBase *dcbase,
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
static bool hppa_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cs, FILE *logfile)
|
||||
{
|
||||
target_ulong pc = dcbase->pc_first;
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
switch (pc) {
|
||||
case 0x00:
|
||||
fprintf(logfile, "IN:\n0x00000000: (null)\n");
|
||||
return;
|
||||
return true;
|
||||
case 0xb0:
|
||||
fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n");
|
||||
return;
|
||||
return true;
|
||||
case 0xe0:
|
||||
fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n");
|
||||
return;
|
||||
return true;
|
||||
case 0x100:
|
||||
fprintf(logfile, "IN:\n0x00000100: syscall\n");
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
|
||||
target_disas(logfile, cs, pc, dcbase->tb->size);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const TranslatorOps hppa_tr_ops = {
|
||||
.init_disas_context = hppa_tr_init_disas_context,
|
||||
|
@ -4848,7 +4845,9 @@ static const TranslatorOps hppa_tr_ops = {
|
|||
.insn_start = hppa_tr_insn_start,
|
||||
.translate_insn = hppa_tr_translate_insn,
|
||||
.tb_stop = hppa_tr_tb_stop,
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
.disas_log = hppa_tr_disas_log,
|
||||
#endif
|
||||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
|
|
|
@ -20,11 +20,9 @@
|
|||
|
||||
#include "qemu/host-utils.h"
|
||||
#include "cpu.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "tcg/tcg-op-gvec.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/translator.h"
|
||||
#include "fpu/softfloat.h"
|
||||
|
||||
|
@ -1580,9 +1578,8 @@ static uint64_t advance_pc(CPUX86State *env, DisasContext *s, int num_bytes)
|
|||
* This can happen even if the operand is only one byte long!
|
||||
*/
|
||||
if (((s->pc - 1) ^ (pc - 1)) & TARGET_PAGE_MASK) {
|
||||
volatile uint8_t unused =
|
||||
cpu_ldub_code(env, (s->pc - 1) & TARGET_PAGE_MASK);
|
||||
(void) unused;
|
||||
(void)translator_ldub(env, &s->base,
|
||||
(s->pc - 1) & TARGET_PAGE_MASK);
|
||||
}
|
||||
siglongjmp(s->jmpbuf, 1);
|
||||
}
|
||||
|
@ -2178,7 +2175,7 @@ static void gen_unknown_opcode(CPUX86State *env, DisasContext *s)
|
|||
|
||||
fprintf(logfile, "ILLOPC: " TARGET_FMT_lx ":", pc);
|
||||
for (; pc < end; ++pc) {
|
||||
fprintf(logfile, " %02x", cpu_ldub_code(env, pc));
|
||||
fprintf(logfile, " %02x", translator_ldub(env, &s->base, pc));
|
||||
}
|
||||
fprintf(logfile, "\n");
|
||||
qemu_log_unlock(logfile);
|
||||
|
@ -4798,22 +4795,12 @@ static void i386_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
static void i386_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cpu, FILE *logfile)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dc->base.pc_first));
|
||||
target_disas(logfile, cpu, dc->base.pc_first, dc->base.tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps i386_tr_ops = {
|
||||
.init_disas_context = i386_tr_init_disas_context,
|
||||
.tb_start = i386_tr_tb_start,
|
||||
.insn_start = i386_tr_insn_start,
|
||||
.translate_insn = i386_tr_translate_insn,
|
||||
.tb_stop = i386_tr_tb_stop,
|
||||
.disas_log = i386_tr_disas_log,
|
||||
};
|
||||
|
||||
/* generate intermediate code for basic block 'tb'. */
|
||||
|
|
|
@ -325,20 +325,12 @@ static void loongarch_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
|
|||
}
|
||||
}
|
||||
|
||||
static void loongarch_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cpu, FILE *logfile)
|
||||
{
|
||||
qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
|
||||
target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps loongarch_tr_ops = {
|
||||
.init_disas_context = loongarch_tr_init_disas_context,
|
||||
.tb_start = loongarch_tr_tb_start,
|
||||
.insn_start = loongarch_tr_insn_start,
|
||||
.translate_insn = loongarch_tr_translate_insn,
|
||||
.tb_stop = loongarch_tr_tb_stop,
|
||||
.disas_log = loongarch_tr_disas_log,
|
||||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "qemu/log.h"
|
||||
|
@ -6105,20 +6104,12 @@ static void m68k_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
static void m68k_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cpu, FILE *logfile)
|
||||
{
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
|
||||
target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps m68k_tr_ops = {
|
||||
.init_disas_context = m68k_tr_init_disas_context,
|
||||
.tb_start = m68k_tr_tb_start,
|
||||
.insn_start = m68k_tr_insn_start,
|
||||
.translate_insn = m68k_tr_translate_insn,
|
||||
.tb_stop = m68k_tr_tb_stop,
|
||||
.disas_log = m68k_tr_disas_log,
|
||||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
|
@ -1637,7 +1636,7 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
|
|||
|
||||
dc->tb_flags_to_set = 0;
|
||||
|
||||
ir = cpu_ldl_code(cpu_env(cs), dc->base.pc_next);
|
||||
ir = translator_ldl(cpu_env(cs), &dc->base, dc->base.pc_next);
|
||||
if (!decode(dc, ir)) {
|
||||
trap_illegal(dc, true);
|
||||
}
|
||||
|
@ -1771,20 +1770,12 @@ static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
|
|||
}
|
||||
}
|
||||
|
||||
static void mb_tr_disas_log(const DisasContextBase *dcb,
|
||||
CPUState *cs, FILE *logfile)
|
||||
{
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dcb->pc_first));
|
||||
target_disas(logfile, cs, dcb->pc_first, dcb->tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps mb_tr_ops = {
|
||||
.init_disas_context = mb_tr_init_disas_context,
|
||||
.tb_start = mb_tr_tb_start,
|
||||
.insn_start = mb_tr_insn_start,
|
||||
.translate_insn = mb_tr_translate_insn,
|
||||
.tb_stop = mb_tr_tb_stop,
|
||||
.disas_log = mb_tr_disas_log,
|
||||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include "exec/translation-block.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "trace.h"
|
||||
#include "disas/disas.h"
|
||||
#include "fpu_helper.h"
|
||||
|
||||
#define HELPER_H "helper.h"
|
||||
|
@ -15475,20 +15474,12 @@ static void mips_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
|
|||
}
|
||||
}
|
||||
|
||||
static void mips_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cs, FILE *logfile)
|
||||
{
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
|
||||
target_disas(logfile, cs, dcbase->pc_first, dcbase->tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps mips_tr_ops = {
|
||||
.init_disas_context = mips_tr_init_disas_context,
|
||||
.tb_start = mips_tr_tb_start,
|
||||
.insn_start = mips_tr_insn_start,
|
||||
.translate_insn = mips_tr_translate_insn,
|
||||
.tb_stop = mips_tr_tb_stop,
|
||||
.disas_log = mips_tr_disas_log,
|
||||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "disas/disas.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/bitops.h"
|
||||
|
@ -1638,22 +1637,12 @@ static void openrisc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
|
|||
}
|
||||
}
|
||||
|
||||
static void openrisc_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cs, FILE *logfile)
|
||||
{
|
||||
DisasContext *s = container_of(dcbase, DisasContext, base);
|
||||
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(s->base.pc_first));
|
||||
target_disas(logfile, cs, s->base.pc_first, s->base.tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps openrisc_tr_ops = {
|
||||
.init_disas_context = openrisc_tr_init_disas_context,
|
||||
.tb_start = openrisc_tr_tb_start,
|
||||
.insn_start = openrisc_tr_insn_start,
|
||||
.translate_insn = openrisc_tr_translate_insn,
|
||||
.tb_stop = openrisc_tr_tb_stop,
|
||||
.disas_log = openrisc_tr_disas_log,
|
||||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "internal.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "tcg/tcg-op-gvec.h"
|
||||
|
@ -7405,20 +7404,12 @@ static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
|
|||
}
|
||||
}
|
||||
|
||||
static void ppc_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cs, FILE *logfile)
|
||||
{
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
|
||||
target_disas(logfile, cs, dcbase->pc_first, dcbase->tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps ppc_tr_ops = {
|
||||
.init_disas_context = ppc_tr_init_disas_context,
|
||||
.tb_start = ppc_tr_tb_start,
|
||||
.insn_start = ppc_tr_insn_start,
|
||||
.translate_insn = ppc_tr_translate_insn,
|
||||
.tb_stop = ppc_tr_tb_stop,
|
||||
.disas_log = ppc_tr_disas_log,
|
||||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
#include "qemu/log.h"
|
||||
#include "cpu.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/helper-gen.h"
|
||||
|
@ -1083,7 +1081,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
|
|||
CPUState *cpu = ctx->cs;
|
||||
CPURISCVState *env = cpu_env(cpu);
|
||||
|
||||
return cpu_ldl_code(env, pc);
|
||||
return translator_ldl(env, &ctx->base, pc);
|
||||
}
|
||||
|
||||
/* Include insn module translation function */
|
||||
|
@ -1244,7 +1242,8 @@ static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
|||
unsigned page_ofs = ctx->base.pc_next & ~TARGET_PAGE_MASK;
|
||||
|
||||
if (page_ofs > TARGET_PAGE_SIZE - MAX_INSN_LEN) {
|
||||
uint16_t next_insn = cpu_lduw_code(env, ctx->base.pc_next);
|
||||
uint16_t next_insn =
|
||||
translator_lduw(env, &ctx->base, ctx->base.pc_next);
|
||||
int len = insn_len(next_insn);
|
||||
|
||||
if (!is_same_page(&ctx->base, ctx->base.pc_next + len - 1)) {
|
||||
|
@ -1270,29 +1269,12 @@ static void riscv_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
static void riscv_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cpu, FILE *logfile)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
RISCVCPU *rvcpu = RISCV_CPU(cpu);
|
||||
CPURISCVState *env = &rvcpu->env;
|
||||
#endif
|
||||
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
fprintf(logfile, "Priv: "TARGET_FMT_ld"; Virt: %d\n",
|
||||
env->priv, env->virt_enabled);
|
||||
#endif
|
||||
target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps riscv_tr_ops = {
|
||||
.init_disas_context = riscv_tr_init_disas_context,
|
||||
.tb_start = riscv_tr_tb_start,
|
||||
.insn_start = riscv_tr_insn_start,
|
||||
.translate_insn = riscv_tr_translate_insn,
|
||||
.tb_stop = riscv_tr_tb_stop,
|
||||
.disas_log = riscv_tr_disas_log,
|
||||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/helper-gen.h"
|
||||
#include "exec/translator.h"
|
||||
|
@ -75,10 +74,10 @@ static TCGv_i64 cpu_acc;
|
|||
|
||||
/* decoder helper */
|
||||
static uint32_t decode_load_bytes(DisasContext *ctx, uint32_t insn,
|
||||
int i, int n)
|
||||
int i, int n)
|
||||
{
|
||||
while (++i <= n) {
|
||||
uint8_t b = cpu_ldub_code(ctx->env, ctx->base.pc_next++);
|
||||
uint8_t b = translator_ldub(ctx->env, &ctx->base, ctx->base.pc_next++);
|
||||
insn |= b << (32 - i * 8);
|
||||
}
|
||||
return insn;
|
||||
|
@ -90,22 +89,24 @@ static uint32_t li(DisasContext *ctx, int sz)
|
|||
CPURXState *env = ctx->env;
|
||||
addr = ctx->base.pc_next;
|
||||
|
||||
tcg_debug_assert(sz < 4);
|
||||
switch (sz) {
|
||||
case 1:
|
||||
ctx->base.pc_next += 1;
|
||||
return cpu_ldsb_code(env, addr);
|
||||
return (int8_t)translator_ldub(env, &ctx->base, addr);
|
||||
case 2:
|
||||
ctx->base.pc_next += 2;
|
||||
return cpu_ldsw_code(env, addr);
|
||||
return (int16_t)translator_lduw(env, &ctx->base, addr);
|
||||
case 3:
|
||||
ctx->base.pc_next += 3;
|
||||
tmp = cpu_ldsb_code(env, addr + 2) << 16;
|
||||
tmp |= cpu_lduw_code(env, addr) & 0xffff;
|
||||
tmp = (int8_t)translator_ldub(env, &ctx->base, addr + 2);
|
||||
tmp <<= 16;
|
||||
tmp |= translator_lduw(env, &ctx->base, addr);
|
||||
return tmp;
|
||||
case 0:
|
||||
ctx->base.pc_next += 4;
|
||||
return cpu_ldl_code(env, addr);
|
||||
return translator_ldl(env, &ctx->base, addr);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -190,22 +191,22 @@ static inline TCGv rx_index_addr(DisasContext *ctx, TCGv mem,
|
|||
{
|
||||
uint32_t dsp;
|
||||
|
||||
tcg_debug_assert(ld < 3);
|
||||
switch (ld) {
|
||||
case 0:
|
||||
return cpu_regs[reg];
|
||||
case 1:
|
||||
dsp = cpu_ldub_code(ctx->env, ctx->base.pc_next) << size;
|
||||
dsp = translator_ldub(ctx->env, &ctx->base, ctx->base.pc_next) << size;
|
||||
tcg_gen_addi_i32(mem, cpu_regs[reg], dsp);
|
||||
ctx->base.pc_next += 1;
|
||||
return mem;
|
||||
case 2:
|
||||
dsp = cpu_lduw_code(ctx->env, ctx->base.pc_next) << size;
|
||||
dsp = translator_lduw(ctx->env, &ctx->base, ctx->base.pc_next) << size;
|
||||
tcg_gen_addi_i32(mem, cpu_regs[reg], dsp);
|
||||
ctx->base.pc_next += 2;
|
||||
return mem;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline MemOp mi_to_mop(unsigned mi)
|
||||
|
@ -2247,20 +2248,12 @@ static void rx_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
|
|||
}
|
||||
}
|
||||
|
||||
static void rx_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cs, FILE *logfile)
|
||||
{
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
|
||||
target_disas(logfile, cs, dcbase->pc_first, dcbase->tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps rx_tr_ops = {
|
||||
.init_disas_context = rx_tr_init_disas_context,
|
||||
.tb_start = rx_tr_tb_start,
|
||||
.insn_start = rx_tr_insn_start,
|
||||
.translate_insn = rx_tr_translate_insn,
|
||||
.tb_stop = rx_tr_tb_stop,
|
||||
.disas_log = rx_tr_disas_log,
|
||||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
|
|
|
@ -31,13 +31,11 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "s390x-internal.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "tcg/tcg-op-gvec.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/helper-gen.h"
|
||||
|
||||
|
@ -6192,6 +6190,8 @@ static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s)
|
|||
const DisasInsn *info;
|
||||
|
||||
if (unlikely(s->ex_value)) {
|
||||
uint64_t be_insn;
|
||||
|
||||
/* Drop the EX data now, so that it's clear on exception paths. */
|
||||
tcg_gen_st_i64(tcg_constant_i64(0), tcg_env,
|
||||
offsetof(CPUS390XState, ex_value));
|
||||
|
@ -6199,13 +6199,11 @@ static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s)
|
|||
/* Extract the values saved by EXECUTE. */
|
||||
insn = s->ex_value & 0xffffffffffff0000ull;
|
||||
ilen = s->ex_value & 0xf;
|
||||
op = insn >> 56;
|
||||
|
||||
/* Register insn bytes with translator so plugins work. */
|
||||
for (int i = 0; i < ilen; i++) {
|
||||
uint8_t byte = extract64(insn, 56 - (i * 8), 8);
|
||||
translator_fake_ldb(byte, pc + i);
|
||||
}
|
||||
op = insn >> 56;
|
||||
be_insn = cpu_to_be64(insn);
|
||||
translator_fake_ld(&s->base, &be_insn, get_ilen(op));
|
||||
} else {
|
||||
insn = ld_code2(env, s, pc);
|
||||
op = (insn >> 8) & 0xff;
|
||||
|
@ -6472,7 +6470,7 @@ static void s390x_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
|
|||
static target_ulong get_next_pc(CPUS390XState *env, DisasContext *s,
|
||||
uint64_t pc)
|
||||
{
|
||||
uint64_t insn = cpu_lduw_code(env, pc);
|
||||
uint64_t insn = translator_lduw(env, &s->base, pc);
|
||||
|
||||
return pc + get_ilen((insn >> 8) & 0xff);
|
||||
}
|
||||
|
@ -6520,18 +6518,18 @@ static void s390x_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
|
|||
}
|
||||
}
|
||||
|
||||
static void s390x_tr_disas_log(const DisasContextBase *dcbase,
|
||||
static bool s390x_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cs, FILE *logfile)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
if (unlikely(dc->ex_value)) {
|
||||
/* ??? Unfortunately target_disas can't use host memory. */
|
||||
fprintf(logfile, "IN: EXECUTE %016" PRIx64, dc->ex_value);
|
||||
} else {
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dc->base.pc_first));
|
||||
target_disas(logfile, cs, dc->base.pc_first, dc->base.tb->size);
|
||||
/* The ex_value has been recorded with translator_fake_ld. */
|
||||
fprintf(logfile, "IN: EXECUTE\n");
|
||||
target_disas(logfile, cs, &dc->base);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const TranslatorOps s390x_tr_ops = {
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "exec/helper-proto.h"
|
||||
|
@ -2310,20 +2309,12 @@ static void sh4_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
|
|||
}
|
||||
}
|
||||
|
||||
static void sh4_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cs, FILE *logfile)
|
||||
{
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
|
||||
target_disas(logfile, cs, dcbase->pc_first, dcbase->tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps sh4_tr_ops = {
|
||||
.init_disas_context = sh4_tr_init_disas_context,
|
||||
.tb_start = sh4_tr_tb_start,
|
||||
.insn_start = sh4_tr_insn_start,
|
||||
.translate_insn = sh4_tr_translate_insn,
|
||||
.tb_stop = sh4_tr_tb_stop,
|
||||
.disas_log = sh4_tr_disas_log,
|
||||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "qemu/osdep.h"
|
||||
|
||||
#include "cpu.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
|
@ -5149,20 +5148,12 @@ static void sparc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
|
|||
}
|
||||
}
|
||||
|
||||
static void sparc_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cpu, FILE *logfile)
|
||||
{
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
|
||||
target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps sparc_tr_ops = {
|
||||
.init_disas_context = sparc_tr_init_disas_context,
|
||||
.tb_start = sparc_tr_tb_start,
|
||||
.insn_start = sparc_tr_insn_start,
|
||||
.translate_insn = sparc_tr_translate_insn,
|
||||
.tb_stop = sparc_tr_tb_stop,
|
||||
.disas_log = sparc_tr_disas_log,
|
||||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
|
@ -8453,20 +8452,12 @@ static void tricore_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
static void tricore_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cpu, FILE *logfile)
|
||||
{
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
|
||||
target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps tricore_tr_ops = {
|
||||
.init_disas_context = tricore_tr_init_disas_context,
|
||||
.tb_start = tricore_tr_tb_start,
|
||||
.insn_start = tricore_tr_insn_start,
|
||||
.translate_insn = tricore_tr_translate_insn,
|
||||
.tb_stop = tricore_tr_tb_stop,
|
||||
.disas_log = tricore_tr_disas_log,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -32,11 +32,9 @@
|
|||
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "disas/disas.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/qemu-print.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "exec/translator.h"
|
||||
|
||||
|
@ -1119,7 +1117,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
|
|||
|
||||
static inline unsigned xtensa_insn_len(CPUXtensaState *env, DisasContext *dc)
|
||||
{
|
||||
uint8_t b0 = cpu_ldub_code(env, dc->pc);
|
||||
uint8_t b0 = translator_ldub(env, &dc->base, dc->pc);
|
||||
return xtensa_op0_insn_len(dc, b0);
|
||||
}
|
||||
|
||||
|
@ -1221,20 +1219,12 @@ static void xtensa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
static void xtensa_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cpu, FILE *logfile)
|
||||
{
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
|
||||
target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps xtensa_translator_ops = {
|
||||
.init_disas_context = xtensa_tr_init_disas_context,
|
||||
.tb_start = xtensa_tr_tb_start,
|
||||
.insn_start = xtensa_tr_insn_start,
|
||||
.translate_insn = xtensa_tr_translate_insn,
|
||||
.tb_stop = xtensa_tr_tb_stop,
|
||||
.disas_log = xtensa_tr_disas_log,
|
||||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||
|
|
|
@ -808,18 +808,88 @@ static void tcg_out_ldst(TCGContext *s, LoongArchInsn opc, TCGReg data,
|
|||
}
|
||||
}
|
||||
|
||||
static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg,
|
||||
TCGReg arg1, intptr_t arg2)
|
||||
static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg dest,
|
||||
TCGReg base, intptr_t offset)
|
||||
{
|
||||
bool is_32bit = type == TCG_TYPE_I32;
|
||||
tcg_out_ldst(s, is_32bit ? OPC_LD_W : OPC_LD_D, arg, arg1, arg2);
|
||||
switch (type) {
|
||||
case TCG_TYPE_I32:
|
||||
if (dest < TCG_REG_V0) {
|
||||
tcg_out_ldst(s, OPC_LD_W, dest, base, offset);
|
||||
} else {
|
||||
tcg_out_dupm_vec(s, TCG_TYPE_I128, MO_32, dest, base, offset);
|
||||
}
|
||||
break;
|
||||
case TCG_TYPE_I64:
|
||||
if (dest < TCG_REG_V0) {
|
||||
tcg_out_ldst(s, OPC_LD_D, dest, base, offset);
|
||||
} else {
|
||||
tcg_out_dupm_vec(s, TCG_TYPE_I128, MO_64, dest, base, offset);
|
||||
}
|
||||
break;
|
||||
case TCG_TYPE_V128:
|
||||
if (-0x800 <= offset && offset <= 0x7ff) {
|
||||
tcg_out_opc_vld(s, dest, base, offset);
|
||||
} else {
|
||||
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP0, offset);
|
||||
tcg_out_opc_vldx(s, dest, base, TCG_REG_TMP0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
|
||||
TCGReg arg1, intptr_t arg2)
|
||||
static void tcg_out_st(TCGContext *s, TCGType type, TCGReg src,
|
||||
TCGReg base, intptr_t offset)
|
||||
{
|
||||
bool is_32bit = type == TCG_TYPE_I32;
|
||||
tcg_out_ldst(s, is_32bit ? OPC_ST_W : OPC_ST_D, arg, arg1, arg2);
|
||||
switch (type) {
|
||||
case TCG_TYPE_I32:
|
||||
if (src < TCG_REG_V0) {
|
||||
tcg_out_ldst(s, OPC_ST_W, src, base, offset);
|
||||
} else {
|
||||
/* TODO: Could use fst_s, fstx_s */
|
||||
if (offset < -0x100 || offset > 0xff || (offset & 3)) {
|
||||
if (-0x800 <= offset && offset <= 0x7ff) {
|
||||
tcg_out_opc_addi_d(s, TCG_REG_TMP0, base, offset);
|
||||
} else {
|
||||
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP0, offset);
|
||||
tcg_out_opc_add_d(s, TCG_REG_TMP0, TCG_REG_TMP0, base);
|
||||
}
|
||||
base = TCG_REG_TMP0;
|
||||
offset = 0;
|
||||
}
|
||||
tcg_out_opc_vstelm_w(s, src, base, offset, 0);
|
||||
}
|
||||
break;
|
||||
case TCG_TYPE_I64:
|
||||
if (src < TCG_REG_V0) {
|
||||
tcg_out_ldst(s, OPC_ST_D, src, base, offset);
|
||||
} else {
|
||||
/* TODO: Could use fst_d, fstx_d */
|
||||
if (offset < -0x100 || offset > 0xff || (offset & 7)) {
|
||||
if (-0x800 <= offset && offset <= 0x7ff) {
|
||||
tcg_out_opc_addi_d(s, TCG_REG_TMP0, base, offset);
|
||||
} else {
|
||||
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP0, offset);
|
||||
tcg_out_opc_add_d(s, TCG_REG_TMP0, TCG_REG_TMP0, base);
|
||||
}
|
||||
base = TCG_REG_TMP0;
|
||||
offset = 0;
|
||||
}
|
||||
tcg_out_opc_vstelm_d(s, src, base, offset, 0);
|
||||
}
|
||||
break;
|
||||
case TCG_TYPE_V128:
|
||||
if (-0x800 <= offset && offset <= 0x7ff) {
|
||||
tcg_out_opc_vst(s, src, base, offset);
|
||||
} else {
|
||||
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP0, offset);
|
||||
tcg_out_opc_vstx(s, src, base, TCG_REG_TMP0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
|
||||
|
@ -1740,7 +1810,6 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
|
|||
{
|
||||
TCGType type = vecl + TCG_TYPE_V64;
|
||||
TCGArg a0, a1, a2, a3;
|
||||
TCGReg temp = TCG_REG_TMP0;
|
||||
TCGReg temp_vec = TCG_VEC_TMP0;
|
||||
|
||||
static const LoongArchInsn cmp_vec_insn[16][4] = {
|
||||
|
@ -1820,22 +1889,10 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
|
|||
|
||||
switch (opc) {
|
||||
case INDEX_op_st_vec:
|
||||
/* Try to fit vst imm */
|
||||
if (-0x800 <= a2 && a2 <= 0x7ff) {
|
||||
tcg_out_opc_vst(s, a0, a1, a2);
|
||||
} else {
|
||||
tcg_out_movi(s, TCG_TYPE_I64, temp, a2);
|
||||
tcg_out_opc_vstx(s, a0, a1, temp);
|
||||
}
|
||||
tcg_out_st(s, type, a0, a1, a2);
|
||||
break;
|
||||
case INDEX_op_ld_vec:
|
||||
/* Try to fit vld imm */
|
||||
if (-0x800 <= a2 && a2 <= 0x7ff) {
|
||||
tcg_out_opc_vld(s, a0, a1, a2);
|
||||
} else {
|
||||
tcg_out_movi(s, TCG_TYPE_I64, temp, a2);
|
||||
tcg_out_opc_vldx(s, a0, a1, temp);
|
||||
}
|
||||
tcg_out_ld(s, type, a0, a1, a2);
|
||||
break;
|
||||
case INDEX_op_and_vec:
|
||||
tcg_out_opc_vand_v(s, a0, a1, a2);
|
||||
|
|
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);
|
||||
#endif
|
||||
|
||||
static void alloc_tcg_plugin_context(TCGContext *s)
|
||||
{
|
||||
#ifdef CONFIG_PLUGIN
|
||||
s->plugin_tb = g_new0(struct qemu_plugin_tb, 1);
|
||||
s->plugin_tb->insns =
|
||||
g_ptr_array_new_with_free_func(qemu_plugin_insn_cleanup_fn);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* All TCG threads except the parent (i.e. the one that called tcg_context_init
|
||||
* and registered the target's TCG globals) must register with this function
|
||||
|
@ -814,7 +805,6 @@ void tcg_register_thread(void)
|
|||
qatomic_set(&tcg_ctxs[n], s);
|
||||
|
||||
if (n > 0) {
|
||||
alloc_tcg_plugin_context(s);
|
||||
tcg_region_initial_alloc(s);
|
||||
}
|
||||
|
||||
|
@ -1361,8 +1351,6 @@ static void tcg_context_init(unsigned max_cpus)
|
|||
indirect_reg_alloc_order[i] = tcg_target_reg_alloc_order[i];
|
||||
}
|
||||
|
||||
alloc_tcg_plugin_context(s);
|
||||
|
||||
tcg_ctx = s;
|
||||
/*
|
||||
* In user-mode we simply share the init context among threads, since we
|
||||
|
|
Loading…
Reference in New Issue