diff --git a/linux-user/sh4/trace_info.h b/linux-user/sh4/trace_info.h new file mode 100644 index 0000000000000..e32f8a07f63d1 --- /dev/null +++ b/linux-user/sh4/trace_info.h @@ -0,0 +1,6 @@ +#pragma once + +#include "frame_arch.h" + +const uint64_t frame_arch = frame_arch_sh; +const uint64_t frame_mach = frame_mach_sh4; diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c index b26524429c0dd..699ddd4fe596d 100644 --- a/qobject/block-qdict.c +++ b/qobject/block-qdict.c @@ -222,7 +222,7 @@ void qdict_array_split(QDict *src, QList **dst) *dst = qlist_new(); for (i = 0; i < UINT_MAX; i++) { - QObject *subqobj; + QObject *subqobj = NULL; bool is_subqdict; QDict *subqdict = NULL; char indexstr[32], prefix[32]; diff --git a/target/sh4/helper.h b/target/sh4/helper.h index 8d792f6b5538d..cb274a0c38e3c 100644 --- a/target/sh4/helper.h +++ b/target/sh4/helper.h @@ -41,3 +41,12 @@ DEF_HELPER_FLAGS_2(ftrc_FT, TCG_CALL_NO_WG, i32, env, f32) DEF_HELPER_FLAGS_2(ftrc_DT, TCG_CALL_NO_WG, i32, env, f64) DEF_HELPER_3(fipr, void, env, i32, i32) DEF_HELPER_2(ftrv, void, env, i32) + +#ifdef HAS_TRACEWRAP +DEF_HELPER_1(trace_newframe, void, i32) +DEF_HELPER_2(trace_endframe, void, env, i32) +DEF_HELPER_2(trace_load_reg, void, i32, i32) +DEF_HELPER_2(trace_store_reg, void, i32, i32) +DEF_HELPER_3(trace_load_mem, void, i32, i32, i32) +DEF_HELPER_3(trace_store_mem, void, i32, i32, i32) +#endif /* HAS_TRACEWRAP */ diff --git a/target/sh4/meson.build b/target/sh4/meson.build index 56a57576da76b..1f02c289a01d8 100644 --- a/target/sh4/meson.build +++ b/target/sh4/meson.build @@ -7,6 +7,10 @@ sh4_ss.add(files( 'translate.c', )) +if get_option('tracewrap') + sh4_ss.add(files('trace_helper.c')) +endif + sh4_softmmu_ss = ss.source_set() sh4_softmmu_ss.add(files('monitor.c')) diff --git a/target/sh4/trace_helper.c b/target/sh4/trace_helper.c new file mode 100644 index 0000000000000..a619bc926ddc0 --- /dev/null +++ b/target/sh4/trace_helper.c @@ -0,0 +1,117 @@ +#include "tracewrap.h" +#include "cpu.h" +#include "qemu/log.h" +#include "exec/helper-proto.h" +#include "exec/memop.h" +#include "qemu/log.h" + +const char *regs[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r0b", "r1b", "r2b", "r3b", "r4b", "r5b", "r6b", "r7b", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "sr", + "gbr", "ssr", "spc", "sgr", "dbr", "vbr", "mach", "macl", "pr" +}; +static const int reg_max = sizeof(regs) / sizeof(regs[0]); + +void HELPER(trace_newframe)(target_ulong pc) +{ + qemu_trace_newframe(pc, 0); +} + +void HELPER(trace_endframe)(CPUSH4State *env, target_ulong old_pc) +{ + qemu_trace_endframe(env, old_pc, 32); +} + +OperandInfo * load_store_reg(uint32_t reg, uint32_t val, int ls) +{ + RegOperand * ro = g_new(RegOperand,1); + reg_operand__init(ro); + ro->name = g_strdup(reg < reg_max ? regs[reg] : "UNKNOWN"); + + OperandInfoSpecific *ois = g_new(OperandInfoSpecific,1); + operand_info_specific__init(ois); + ois->reg_operand = ro; + OperandUsage *ou = g_new(OperandUsage,1); + operand_usage__init(ou); + if (ls == 0) + { + ou->read = 1; + } else { + ou->written = 1; + } + OperandInfo *oi = g_new(OperandInfo,1); + operand_info__init(oi); + oi->bit_length = 0; + oi->operand_info_specific = ois; + oi->operand_usage = ou; + oi->value.len = 4; + oi->value.data = g_malloc(oi->value.len); + memcpy(oi->value.data, &val, 4); + return oi; +} + +void HELPER(trace_load_reg)(uint32_t reg, uint32_t val) +{ + qemu_log("This register (r%d) was read. Value 0x%x\n", reg, val); + + //r0 always reads 0 + OperandInfo *oi = load_store_reg(reg, (reg != 0) ? val : 0, 0); + + qemu_trace_add_operand(oi, 0x1); +} + +void HELPER(trace_store_reg)(uint32_t reg, uint32_t val) +{ + qemu_log("This register (r%d) was written. Value: 0x%x\n", reg, val); + + OperandInfo *oi = load_store_reg(reg, val, 1); + + qemu_trace_add_operand(oi, 0x2); +} + +OperandInfo *load_store_mem(uint64_t addr, int ls, const void *data, size_t data_size) { + MemOperand * mo = g_new(MemOperand, 1); + mem_operand__init(mo); + + mo->address = addr; + + OperandInfoSpecific *ois = g_new(OperandInfoSpecific, 1); + operand_info_specific__init(ois); + ois->mem_operand = mo; + + OperandUsage *ou = g_new(OperandUsage, 1); + operand_usage__init(ou); + if (ls == 0) { + ou->read = 1; + } else { + ou->written = 1; + } + OperandInfo *oi = g_new(OperandInfo, 1); + operand_info__init(oi); + oi->bit_length = data_size * 8; + oi->operand_info_specific = ois; + oi->operand_usage = ou; + oi->value.len = data_size; + oi->value.data = g_malloc(oi->value.len); + #ifdef BSWAP_NEEDED + memcpy_rev(oi->value.data, data, data_size); + #else + memcpy(oi->value.data, data, data_size); + #endif + return oi; +} + +void HELPER(trace_load_mem)(uint32_t addr, uint32_t val, uint32_t op) +{ + qemu_log("LOAD at 0x%lx size: %d data: 0x%lx\n", (unsigned long) addr, memop_size(op), (unsigned long) val); + OperandInfo *oi = load_store_mem(addr, 0, &val, memop_size(op)); + qemu_trace_add_operand(oi, 0x1); +} + +void HELPER(trace_store_mem)(uint32_t addr, uint32_t val, uint32_t op) +{ + qemu_log("STORE at 0x%lx size: %d data: 0x%lx\n", (unsigned long) addr, memop_size(op), (unsigned long) val); + OperandInfo *oi = load_store_mem(addr, 1, &val, memop_size(op)); + qemu_trace_add_operand(oi, 0x2); +} diff --git a/target/sh4/translate.c b/target/sh4/translate.c index ce5d674a520e7..0aff9da2172e6 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -185,6 +185,66 @@ void superh_cpu_dump_state(CPUState *cs, FILE *f, int flags) } } +#ifdef HAS_TRACEWRAP +static void gen_trace_load_reg(uint32_t reg, TCGv var) +{ + TCGv_i32 t = tcg_const_i32(reg); + gen_helper_trace_load_reg(t, var); + tcg_temp_free_i32(t); +} + +static void gen_trace_store_reg(uint32_t reg, TCGv var) +{ + TCGv_i32 t = tcg_const_i32(reg); + gen_helper_trace_store_reg(t, var); + tcg_temp_free_i32(t); +} + +static inline void gen_trace_newframe(uint32_t pc) +{ + TCGv_i32 tmp0 = tcg_temp_new_i32(); + tcg_gen_movi_i32(tmp0, pc); + gen_helper_trace_newframe(tmp0); + tcg_temp_free_i32(tmp0); +} + +static inline void gen_trace_endframe(uint32_t pc) +{ + TCGv_i32 tmp0 = tcg_temp_new_i32(); + tcg_gen_movi_i32(tmp0, pc); + gen_helper_trace_endframe(cpu_env, tmp0); + tcg_temp_free_i32(tmp0); +} +#endif /* HAS_TRACEWRAP */ + +static inline void log_load_gpr(uint32_t rx, TCGv var) { + #ifdef HAS_TRACEWRAP + gen_trace_load_reg(rx, var); + #endif +} + +static inline void log_store_gpr(uint32_t rx, TCGv var) { + #ifdef HAS_TRACEWRAP + gen_trace_store_reg(rx, var); + #endif +} + +static inline void log_load_mem(TCGv addr, TCGv val, MemOp op) { + #ifdef HAS_TRACEWRAP + TCGv_i32 o = tcg_const_i32(op); + gen_helper_trace_load_mem(addr, val, o); + tcg_temp_free_i32(o); + #endif +} + +static inline void log_store_mem(TCGv addr, TCGv val, MemOp op) { + #ifdef HAS_TRACEWRAP + TCGv_i32 o = tcg_const_i32(op); + gen_helper_trace_store_mem(addr, val, o); + tcg_temp_free_i32(o); + #endif +} + static void gen_read_sr(TCGv dst) { TCGv t0 = tcg_temp_new(); @@ -238,6 +298,9 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) tcg_gen_goto_tb(n); tcg_gen_movi_i32(cpu_pc, dest); tcg_gen_exit_tb(ctx->base.tb, n); + #ifdef HAS_TRACEWRAP + gen_trace_endframe(dest); + #endif } else { tcg_gen_movi_i32(cpu_pc, dest); if (use_exit_tb(ctx)) { @@ -529,8 +592,9 @@ static void _decode_opc(DisasContext * ctx) return; case 0xd000: /* mov.l @(disp,PC),Rn */ { - TCGv addr = tcg_const_i32((ctx->base.pc_next + 4 + B7_0 * 4) & ~3); - tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL); + TCGv addr = tcg_const_i32((ctx->base.pc_next + 4 + B7_0 * 4) & ~3); + tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL); + log_load_mem(addr, REG(B11_8), MO_TESL); tcg_temp_free(addr); } return; @@ -552,7 +616,7 @@ static void _decode_opc(DisasContext * ctx) switch (ctx->opcode & 0xf00f) { case 0x6003: /* mov Rm,Rn */ - tcg_gen_mov_i32(REG(B11_8), REG(B7_4)); + tcg_gen_mov_i32(REG(B11_8), REG(B7_4)); return; case 0x2000: /* mov.b Rm,@Rn */ tcg_gen_qemu_st_i32(REG(B7_4), REG(B11_8), ctx->memidx, MO_UB); @@ -659,8 +723,8 @@ static void _decode_opc(DisasContext * ctx) { TCGv addr = tcg_temp_new(); tcg_gen_add_i32(addr, REG(B7_4), REG(0)); - tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL); - tcg_temp_free(addr); + tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL); + tcg_temp_free(addr); } return; case 0x6008: /* swap.b Rm,Rn */ @@ -2303,9 +2367,18 @@ static void sh4_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) } #endif +#ifdef HAS_TRACEWRAP + gen_trace_newframe(ctx->base.pc_next); +#endif + ctx->opcode = translator_lduw(env, &ctx->base, ctx->base.pc_next); decode_opc(ctx); ctx->base.pc_next += 2; + +#ifdef HAS_TRACEWRAP + gen_trace_endframe(ctx->base.pc_next); +#endif + } static void sh4_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) @@ -2326,6 +2399,9 @@ static void sh4_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) case DISAS_TOO_MANY: gen_save_cpu_state(ctx, false); gen_goto_tb(ctx, 0, ctx->base.pc_next); + #ifdef HAS_TRACEWRAP + gen_trace_endframe(ctx->base.pc_next); + #endif break; case DISAS_NORETURN: break;