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>
master
Richard Henderson 2024-05-15 11:46:36 +02:00
commit 2b01688380
45 changed files with 899 additions and 891 deletions

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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];

104
disas/disas-common.c Normal file
View File

@ -0,0 +1,104 @@
/*
* Common routines for disassembly.
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "disas/disas.h"
#include "disas/capstone.h"
#include "hw/core/cpu.h"
#include "exec/tswap.h"
#include "disas-internal.h"
/* Filled in by elfload.c. Simplistic, but will do for now. */
struct syminfo *syminfos = NULL;
/*
* Print an error message. We can assume that this is in response to
* an error return from {host,target}_read_memory.
*/
static void perror_memory(int status, bfd_vma memaddr,
struct disassemble_info *info)
{
if (status != EIO) {
/* Can't happen. */
info->fprintf_func(info->stream, "Unknown error %d\n", status);
} else {
/* Address between memaddr and memaddr + len was out of bounds. */
info->fprintf_func(info->stream,
"Address 0x%" PRIx64 " is out of bounds.\n",
memaddr);
}
}
/* Print address in hex. */
static void print_address(bfd_vma addr, struct disassemble_info *info)
{
info->fprintf_func(info->stream, "0x%" PRIx64, addr);
}
/* Stub prevents some fruitless earching in optabs disassemblers. */
static int symbol_at_address(bfd_vma addr, struct disassemble_info *info)
{
return 1;
}
void disas_initialize_debug(CPUDebug *s)
{
memset(s, 0, sizeof(*s));
s->info.arch = bfd_arch_unknown;
s->info.cap_arch = -1;
s->info.cap_insn_unit = 4;
s->info.cap_insn_split = 4;
s->info.memory_error_func = perror_memory;
s->info.symbol_at_address_func = symbol_at_address;
}
void disas_initialize_debug_target(CPUDebug *s, CPUState *cpu)
{
disas_initialize_debug(s);
s->cpu = cpu;
s->info.print_address_func = print_address;
if (target_words_bigendian()) {
s->info.endian = BFD_ENDIAN_BIG;
} else {
s->info.endian = BFD_ENDIAN_LITTLE;
}
CPUClass *cc = CPU_GET_CLASS(cpu);
if (cc->disas_set_info) {
cc->disas_set_info(cpu, &s->info);
}
}
int disas_gstring_printf(FILE *stream, const char *fmt, ...)
{
/* We abuse the FILE parameter to pass a GString. */
GString *s = (GString *)stream;
int initial_len = s->len;
va_list va;
va_start(va, fmt);
g_string_append_vprintf(s, fmt, va);
va_end(va);
return s->len - initial_len;
}
/* Look up symbol for debugging purpose. Returns "" if unknown. */
const char *lookup_symbol(uint64_t orig_addr)
{
const char *symbol = "";
struct syminfo *s;
for (s = syminfos; s; s = s->next) {
symbol = s->lookup_symbol(s, orig_addr);
if (symbol[0] != '\0') {
break;
}
}
return symbol;
}

129
disas/disas-host.c Normal file
View File

@ -0,0 +1,129 @@
/*
* Routines for host instruction disassembly.
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "disas/disas.h"
#include "disas/capstone.h"
#include "disas-internal.h"
/*
* Get LENGTH bytes from info's buffer, at host address memaddr.
* Transfer them to myaddr.
*/
static int host_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
struct disassemble_info *info)
{
if (memaddr < info->buffer_vma
|| memaddr + length > info->buffer_vma + info->buffer_length) {
/* Out of bounds. Use EIO because GDB uses it. */
return EIO;
}
memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
return 0;
}
/* Print address in hex, truncated to the width of a host virtual address. */
static void host_print_address(bfd_vma addr, struct disassemble_info *info)
{
info->fprintf_func(info->stream, "0x%" PRIxPTR, (uintptr_t)addr);
}
static void initialize_debug_host(CPUDebug *s)
{
disas_initialize_debug(s);
s->info.read_memory_func = host_read_memory;
s->info.print_address_func = host_print_address;
#if HOST_BIG_ENDIAN
s->info.endian = BFD_ENDIAN_BIG;
#else
s->info.endian = BFD_ENDIAN_LITTLE;
#endif
#if defined(CONFIG_TCG_INTERPRETER)
s->info.print_insn = print_insn_tci;
#elif defined(__i386__)
s->info.mach = bfd_mach_i386_i386;
s->info.cap_arch = CS_ARCH_X86;
s->info.cap_mode = CS_MODE_32;
s->info.cap_insn_unit = 1;
s->info.cap_insn_split = 8;
#elif defined(__x86_64__)
s->info.mach = bfd_mach_x86_64;
s->info.cap_arch = CS_ARCH_X86;
s->info.cap_mode = CS_MODE_64;
s->info.cap_insn_unit = 1;
s->info.cap_insn_split = 8;
#elif defined(_ARCH_PPC)
s->info.cap_arch = CS_ARCH_PPC;
# ifdef _ARCH_PPC64
s->info.cap_mode = CS_MODE_64;
# endif
#elif defined(__riscv)
#if defined(_ILP32) || (__riscv_xlen == 32)
s->info.print_insn = print_insn_riscv32;
#elif defined(_LP64)
s->info.print_insn = print_insn_riscv64;
#else
#error unsupported RISC-V ABI
#endif
#elif defined(__aarch64__)
s->info.cap_arch = CS_ARCH_ARM64;
#elif defined(__alpha__)
s->info.print_insn = print_insn_alpha;
#elif defined(__sparc__)
s->info.print_insn = print_insn_sparc;
s->info.mach = bfd_mach_sparc_v9b;
#elif defined(__arm__)
/* TCG only generates code for arm mode. */
s->info.cap_arch = CS_ARCH_ARM;
#elif defined(__MIPSEB__)
s->info.print_insn = print_insn_big_mips;
#elif defined(__MIPSEL__)
s->info.print_insn = print_insn_little_mips;
#elif defined(__m68k__)
s->info.print_insn = print_insn_m68k;
#elif defined(__s390__)
s->info.cap_arch = CS_ARCH_SYSZ;
s->info.cap_insn_unit = 2;
s->info.cap_insn_split = 6;
#elif defined(__hppa__)
s->info.print_insn = print_insn_hppa;
#elif defined(__loongarch__)
s->info.print_insn = print_insn_loongarch;
#endif
}
/* Disassemble this for me please... (debugging). */
void disas(FILE *out, const void *code, size_t size)
{
uintptr_t pc;
int count;
CPUDebug s;
initialize_debug_host(&s);
s.info.fprintf_func = fprintf;
s.info.stream = out;
s.info.buffer = code;
s.info.buffer_vma = (uintptr_t)code;
s.info.buffer_length = size;
s.info.show_opcodes = true;
if (s.info.cap_arch >= 0 && cap_disas_host(&s.info, code, size)) {
return;
}
if (s.info.print_insn == NULL) {
s.info.print_insn = print_insn_od_host;
}
for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
fprintf(out, "0x%08" PRIxPTR ": ", pc);
count = s.info.print_insn(pc, &s.info);
fprintf(out, "\n");
if (count < 0) {
break;
}
}
}

View File

@ -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

View File

@ -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;

99
disas/disas-target.c Normal file
View File

@ -0,0 +1,99 @@
/*
* Routines for target instruction disassembly.
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "disas/disas.h"
#include "disas/capstone.h"
#include "exec/translator.h"
#include "disas-internal.h"
static int translator_read_memory(bfd_vma memaddr, bfd_byte *myaddr,
int length, struct disassemble_info *info)
{
const DisasContextBase *db = info->application_data;
return translator_st(db, myaddr, memaddr, length) ? 0 : EIO;
}
void target_disas(FILE *out, CPUState *cpu, const struct DisasContextBase *db)
{
uint64_t code = db->pc_first;
size_t size = translator_st_len(db);
uint64_t pc;
int count;
CPUDebug s;
disas_initialize_debug_target(&s, cpu);
s.info.read_memory_func = translator_read_memory;
s.info.application_data = (void *)db;
s.info.fprintf_func = fprintf;
s.info.stream = out;
s.info.buffer_vma = code;
s.info.buffer_length = size;
s.info.show_opcodes = true;
if (s.info.cap_arch >= 0 && cap_disas_target(&s.info, code, size)) {
return;
}
if (s.info.print_insn == NULL) {
s.info.print_insn = print_insn_od_target;
}
for (pc = code; size > 0; pc += count, size -= count) {
fprintf(out, "0x%08" PRIx64 ": ", pc);
count = s.info.print_insn(pc, &s.info);
fprintf(out, "\n");
if (count < 0) {
break;
}
if (size < count) {
fprintf(out,
"Disassembler disagrees with translator over instruction "
"decoding\n"
"Please report this to qemu-devel@nongnu.org\n");
break;
}
}
}
#ifdef CONFIG_PLUGIN
static void plugin_print_address(bfd_vma addr, struct disassemble_info *info)
{
/* does nothing */
}
/*
* We should only be dissembling one instruction at a time here. If
* there is left over it usually indicates the front end has read more
* bytes than it needed.
*/
char *plugin_disas(CPUState *cpu, const DisasContextBase *db,
uint64_t addr, size_t size)
{
CPUDebug s;
GString *ds = g_string_new(NULL);
disas_initialize_debug_target(&s, cpu);
s.info.read_memory_func = translator_read_memory;
s.info.application_data = (void *)db;
s.info.fprintf_func = disas_gstring_printf;
s.info.stream = (FILE *)ds; /* abuse this slot */
s.info.buffer_vma = addr;
s.info.buffer_length = size;
s.info.print_address_func = plugin_print_address;
if (s.info.cap_arch >= 0 && cap_disas_plugin(&s.info, addr, size)) {
; /* done */
} else if (s.info.print_insn) {
s.info.print_insn(addr, &s.info);
} else {
; /* cannot disassemble -- return empty string */
}
/* Return the buffer, freeing the GString container. */
return g_string_free(ds, false);
}
#endif /* CONFIG_PLUGIN */

View File

@ -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;
}

View File

@ -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)

37
disas/objdump.c Normal file
View File

@ -0,0 +1,37 @@
/*
* Dump disassembly as text, for processing by scripts/disas-objdump.pl.
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "disas-internal.h"
static int print_insn_objdump(bfd_vma pc, disassemble_info *info,
const char *prefix)
{
int i, n = info->buffer_length;
g_autofree uint8_t *buf = g_malloc(n);
if (info->read_memory_func(pc, buf, n, info) == 0) {
for (i = 0; i < n; ++i) {
if (i % 32 == 0) {
info->fprintf_func(info->stream, "\n%s: ", prefix);
}
info->fprintf_func(info->stream, "%02x", buf[i]);
}
} else {
info->fprintf_func(info->stream, "unable to read memory");
}
return n;
}
int print_insn_od_host(bfd_vma pc, disassemble_info *info)
{
return print_insn_objdump(pc, info, "OBJD-H");
}
int print_insn_od_target(bfd_vma pc, disassemble_info *info)
{
return print_insn_objdump(pc, info, "OBJD-T");
}

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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,

View File

@ -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,
};

View File

@ -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'. */

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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'. */

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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 = {

View File

@ -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,

View File

@ -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,

View File

@ -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,
};

View File

@ -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,

View File

@ -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);

View File

@ -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