From 5389aa19033153c09556d1362a8b8a56abccb8f5 Mon Sep 17 00:00:00 2001 From: Vladimir Chtchetkine Date: Tue, 16 Feb 2010 10:38:35 -0800 Subject: Merge memory checking from sandbox Change-id: Ibce845d0 --- tcg/tcg.c | 161 +++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 97 insertions(+), 64 deletions(-) (limited to 'tcg') diff --git a/tcg/tcg.c b/tcg/tcg.c index 5d18842..c63168b 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -57,7 +57,7 @@ #include "tcg-op.h" #include "elf.h" -static void patch_reloc(uint8_t *code_ptr, int type, +static void patch_reloc(uint8_t *code_ptr, int type, tcg_target_long value, tcg_target_long addend); static TCGOpDef tcg_op_defs[] = { @@ -75,6 +75,16 @@ static TCGRegSet tcg_target_call_clobber_regs; uint16_t *gen_opc_ptr; TCGArg *gen_opparam_ptr; +#ifdef CONFIG_MEMCHECK +/* + * Memchecker addition in this module is intended to build a map that matches + * translated PC to a guest PC. Map is built in tcg_gen_code_common routine, + * and is saved into temporary gen_opc_tpc2gpc_ptr array, that later will be + * copied into the TranslationBlock that represents the translated code. + */ +#include "memcheck/memcheck_api.h" +#endif // CONFIG_MEMCHECK + static inline void tcg_out8(TCGContext *s, uint8_t v) { *s->code_ptr++ = v; @@ -94,7 +104,7 @@ static inline void tcg_out32(TCGContext *s, uint32_t v) /* label relocation processing */ -void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, +void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, int label_index, long addend) { TCGLabel *l; @@ -103,7 +113,7 @@ void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, l = &s->labels[label_index]; if (l->has_value) { /* FIXME: This may break relocations on RISC targets that - modify instruction fields in place. The caller may not have + modify instruction fields in place. The caller may not have written the initial value. */ patch_reloc(code_ptr, type, l->u.value, addend); } else { @@ -117,7 +127,7 @@ void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, } } -static void tcg_out_label(TCGContext *s, int label_index, +static void tcg_out_label(TCGContext *s, int label_index, tcg_target_long value) { TCGLabel *l; @@ -157,7 +167,7 @@ void *tcg_malloc_internal(TCGContext *s, int size) { TCGPool *p; int pool_size; - + if (size > TCG_POOL_CHUNK_SIZE) { /* big malloc: insert a new pool (XXX: could optimize) */ p = qemu_malloc(sizeof(TCGPool) + size); @@ -180,7 +190,7 @@ void *tcg_malloc_internal(TCGContext *s, int size) p = qemu_malloc(sizeof(TCGPool) + pool_size); p->size = pool_size; p->next = NULL; - if (s->pool_current) + if (s->pool_current) s->pool_current->next = p; else s->pool_first = p; @@ -211,7 +221,7 @@ void tcg_context_init(TCGContext *s) memset(s, 0, sizeof(*s)); s->temps = s->static_temps; s->nb_globals = 0; - + /* Count total number of arguments and allocate the corresponding space */ total_args = 0; @@ -232,14 +242,14 @@ void tcg_context_init(TCGContext *s) sorted_args += n; args_ct += n; } - + tcg_target_init(s); /* init global prologue and epilogue */ s->code_buf = code_gen_prologue; s->code_ptr = s->code_buf; tcg_target_qemu_prologue(s); - flush_icache_range((unsigned long)s->code_buf, + flush_icache_range((unsigned long)s->code_buf, (unsigned long)s->code_ptr); } @@ -697,7 +707,7 @@ static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size, if (idx < s->nb_globals) { pstrcpy(buf, buf_size, ts->name); } else { - if (ts->temp_local) + if (ts->temp_local) snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); else snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); @@ -735,7 +745,7 @@ static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val) tcg_target_ulong v; if (unlikely(!s->helpers_sorted)) { - qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo), + qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo), helper_cmp); s->helpers_sorted = 1; } @@ -794,7 +804,7 @@ void tcg_dump_ops(TCGContext *s, FILE *outfile) #else pc = args[0]; #endif - if (!first_insn) + if (!first_insn) fprintf(outfile, "\n"); fprintf(outfile, " ---- 0x%" PRIx64, pc); first_insn = 0; @@ -834,7 +844,7 @@ void tcg_dump_ops(TCGContext *s, FILE *outfile) tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + i])); } } - } else if (c == INDEX_op_movi_i32 + } else if (c == INDEX_op_movi_i32 #if TCG_TARGET_REG_BITS == 64 || c == INDEX_op_movi_i64 #endif @@ -845,7 +855,7 @@ void tcg_dump_ops(TCGContext *s, FILE *outfile) nb_oargs = def->nb_oargs; nb_iargs = def->nb_iargs; nb_cargs = def->nb_cargs; - fprintf(outfile, " %s %s,$", def->name, + fprintf(outfile, " %s %s,$", def->name, tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0])); val = args[1]; th = tcg_find_helper(s, val); @@ -869,7 +879,7 @@ void tcg_dump_ops(TCGContext *s, FILE *outfile) nb_iargs = def->nb_iargs; nb_cargs = def->nb_cargs; } - + k = 0; for(i = 0; i < nb_oargs; i++) { if (k != 0) @@ -1026,7 +1036,7 @@ void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs) #ifdef USE_LIVENESS_ANALYSIS /* set a nop for an operation using 'nb_args' */ -static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, +static inline void tcg_set_nop(TCGContext *s, uint16_t *opc_ptr, TCGArg *args, int nb_args) { if (nb_args == 0) { @@ -1090,7 +1100,7 @@ static void tcg_liveness_analysis(TCGContext *s) /* XXX: make it really dynamic */ s->op_dead_iargs = tcg_malloc(OPC_BUF_SIZE * sizeof(uint16_t)); - + dead_temps = tcg_malloc(s->nb_temps); memset(dead_temps, 1, s->nb_temps); @@ -1119,7 +1129,7 @@ static void tcg_liveness_analysis(TCGContext *s) if (!dead_temps[arg]) goto do_not_remove_call; } - tcg_set_nop(s, gen_opc_buf + op_index, + tcg_set_nop(s, gen_opc_buf + op_index, args - 1, nb_args); } else { do_not_remove_call: @@ -1129,7 +1139,7 @@ static void tcg_liveness_analysis(TCGContext *s) arg = args[i]; dead_temps[arg] = 1; } - + if (!(call_flags & TCG_CALL_CONST)) { /* globals are live (they may be used by the call) */ memset(dead_temps, 0, s->nb_globals); @@ -1269,8 +1279,8 @@ static void dump_regs(TCGContext *s) for(i = 0; i < TCG_TARGET_NB_REGS; i++) { if (s->reg_to_temp[i] >= 0) { - printf("%s: %s\n", - tcg_target_reg_names[i], + printf("%s: %s\n", + tcg_target_reg_names[i], tcg_get_arg_str_idx(s, buf, sizeof(buf), s->reg_to_temp[i])); } } @@ -1288,7 +1298,7 @@ static void check_regs(TCGContext *s) ts = &s->temps[k]; if (ts->val_type != TEMP_VAL_REG || ts->reg != reg) { - printf("Inconsistency for register %s:\n", + printf("Inconsistency for register %s:\n", tcg_target_reg_names[reg]); goto fail; } @@ -1299,7 +1309,7 @@ static void check_regs(TCGContext *s) if (ts->val_type == TEMP_VAL_REG && !ts->fixed_reg && s->reg_to_temp[ts->reg] != k) { - printf("Inconsistency for temp %s:\n", + printf("Inconsistency for temp %s:\n", tcg_get_arg_str_idx(s, buf, sizeof(buf), k)); fail: printf("reg state:\n"); @@ -1334,7 +1344,7 @@ static void tcg_reg_free(TCGContext *s, int reg) ts = &s->temps[temp]; assert(ts->val_type == TEMP_VAL_REG); if (!ts->mem_coherent) { - if (!ts->mem_allocated) + if (!ts->mem_allocated) temp_allocate_frame(s, temp); tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset); } @@ -1387,9 +1397,9 @@ static void temp_save(TCGContext *s, int temp, TCGRegSet allocated_regs) ts->val_type = TEMP_VAL_MEM; break; case TEMP_VAL_CONST: - reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], + reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], allocated_regs); - if (!ts->mem_allocated) + if (!ts->mem_allocated) temp_allocate_frame(s, temp); tcg_out_movi(s, ts->type, reg, ts->val); tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset); @@ -1519,7 +1529,7 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, ots->mem_coherent = 0; } -static void tcg_reg_alloc_op(TCGContext *s, +static void tcg_reg_alloc_op(TCGContext *s, const TCGOpDef *def, int opc, const TCGArg *args, unsigned int dead_iargs) @@ -1536,11 +1546,11 @@ static void tcg_reg_alloc_op(TCGContext *s, nb_iargs = def->nb_iargs; /* copy constants */ - memcpy(new_args + nb_oargs + nb_iargs, - args + nb_oargs + nb_iargs, + memcpy(new_args + nb_oargs + nb_iargs, + args + nb_oargs + nb_iargs, sizeof(TCGArg) * def->nb_cargs); - /* satisfy input constraints */ + /* satisfy input constraints */ tcg_regset_set(allocated_regs, s->reserved_regs); for(k = 0; k < nb_iargs; k++) { i = def->sorted_args[nb_oargs + k]; @@ -1581,7 +1591,7 @@ static void tcg_reg_alloc_op(TCGContext *s, /* if the input is aliased to an output and if it is not dead after the instruction, we must allocate a new register and move it */ - if (!IS_DEAD_IARG(i - nb_oargs)) + if (!IS_DEAD_IARG(i - nb_oargs)) goto allocate_in_reg; } } @@ -1590,7 +1600,7 @@ static void tcg_reg_alloc_op(TCGContext *s, /* nothing to do : the constraint is satisfied */ } else { allocate_in_reg: - /* allocate a new register matching the constraint + /* allocate a new register matching the constraint and move the temporary register into it */ reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); tcg_out_mov(s, reg, ts->reg); @@ -1600,7 +1610,7 @@ static void tcg_reg_alloc_op(TCGContext *s, tcg_regset_set_reg(allocated_regs, reg); iarg_end: ; } - + if (def->flags & TCG_OPF_BB_END) { tcg_reg_alloc_bb_end(s, allocated_regs); } else { @@ -1616,9 +1626,9 @@ static void tcg_reg_alloc_op(TCGContext *s, } } } - + if (def->flags & TCG_OPF_CALL_CLOBBER) { - /* XXX: permit generic clobber register list ? */ + /* XXX: permit generic clobber register list ? */ for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) { tcg_reg_free(s, reg); @@ -1626,12 +1636,12 @@ static void tcg_reg_alloc_op(TCGContext *s, } /* XXX: for load/store we could do that only for the slow path (i.e. when a memory callback is called) */ - + /* store globals and free associated registers (we assume the insn can modify any global. */ save_globals(s, allocated_regs); } - + /* satisfy the output constraints */ tcg_regset_set(allocated_regs, s->reserved_regs); for(k = 0; k < nb_oargs; k++) { @@ -1659,7 +1669,7 @@ static void tcg_reg_alloc_op(TCGContext *s, ts->reg = reg; /* temp value is modified, so the value kept in memory is potentially not the same */ - ts->mem_coherent = 0; + ts->mem_coherent = 0; s->reg_to_temp[reg] = arg; } oarg_end: @@ -1669,7 +1679,7 @@ static void tcg_reg_alloc_op(TCGContext *s, /* emit instruction */ tcg_out_op(s, opc, new_args, const_args); - + /* move the outputs in the correct register if needed */ for(i = 0; i < nb_oargs; i++) { ts = &s->temps[args[i]]; @@ -1713,7 +1723,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, /* assign stack slots first */ /* XXX: preallocate call stack */ call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long); - call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & + call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & ~(TCG_TARGET_STACK_ALIGN - 1); allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); if (allocate_args) { @@ -1731,13 +1741,13 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, if (ts->val_type == TEMP_VAL_REG) { tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset); } else if (ts->val_type == TEMP_VAL_MEM) { - reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], + reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], s->reserved_regs); /* XXX: not correct if reading values from the stack */ tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); tcg_out_st(s, ts->type, reg, TCG_REG_CALL_STACK, stack_offset); } else if (ts->val_type == TEMP_VAL_CONST) { - reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], + reg = tcg_reg_alloc(s, tcg_target_available_regs[ts->type], s->reserved_regs); /* XXX: sign extend may be needed on some targets */ tcg_out_movi(s, ts->type, reg, ts->val); @@ -1750,7 +1760,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, stack_offset += sizeof(tcg_target_long); #endif } - + /* assign input registers */ tcg_regset_set(allocated_regs, s->reserved_regs); for(i = 0; i < nb_regs; i++) { @@ -1774,7 +1784,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, tcg_regset_set_reg(allocated_regs, reg); } } - + /* assign function address */ func_arg = args[nb_oargs + nb_iargs - 1]; arg_ct = &def->args_ct[0]; @@ -1807,8 +1817,8 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, } else { tcg_abort(); } - - + + /* mark dead temporaries and free the associated registers */ for(i = 0; i < nb_iargs; i++) { arg = args[nb_oargs + i]; @@ -1821,14 +1831,14 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, } } } - + /* clobber call registers */ for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) { if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) { tcg_reg_free(s, reg); } } - + /* store globals and free associated registers (we assume the call can modify any global. */ if (!(flags & TCG_CALL_CONST)) { @@ -1836,7 +1846,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, } tcg_out_op(s, opc, &func_arg, &const_func_arg); - + if (allocate_args) { tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size)); } @@ -1856,11 +1866,11 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, s->reg_to_temp[ts->reg] = -1; ts->val_type = TEMP_VAL_REG; ts->reg = reg; - ts->mem_coherent = 0; + ts->mem_coherent = 0; s->reg_to_temp[reg] = arg; } } - + return nb_iargs + nb_oargs + def->nb_cargs + 1; } @@ -1888,6 +1898,9 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, const TCGOpDef *def; unsigned int dead_iargs; const TCGArg *args; +#ifdef CONFIG_MEMCHECK + unsigned int tpc2gpc_index = 0; +#endif // CONFIG_MEMCHECK #ifdef DEBUG_DISAS if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) { @@ -1921,7 +1934,27 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, args = gen_opparam_buf; op_index = 0; +#ifdef CONFIG_MEMCHECK + gen_opc_tpc2gpc_pairs = 0; +#endif // CONFIG_MEMCHECK + for(;;) { +#ifdef CONFIG_MEMCHECK + /* On condition that memcheck is enabled, and operation index reached + * new operation in the guest code, save (pc_tb, pc_guest) pair into + * gen_opc_tpc2gpc array. Note that we do that only on condition that + * search_pc is < 0. This way we make sure that this is "normal" + * translation, called from tcg_gen_code, and not from + * tcg_gen_code_search_pc. */ + if (memcheck_enabled && search_pc < 0 && + gen_opc_instr_start[op_index]) { + gen_opc_tpc2gpc_ptr[tpc2gpc_index] = (target_ulong)s->code_ptr; + tpc2gpc_index++; + gen_opc_tpc2gpc_ptr[tpc2gpc_index] = gen_opc_pc[op_index]; + tpc2gpc_index++; + gen_opc_tpc2gpc_pairs++; + } +#endif // CONFIG_MEMCHECK opc = gen_opc_buf[op_index]; #ifdef CONFIG_PROFILER tcg_table_op_count[opc]++; @@ -2027,7 +2060,7 @@ int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf) tcg_gen_code_common(s, gen_code_buf, -1); /* flush instruction cache */ - flush_icache_range((unsigned long)gen_code_buf, + flush_icache_range((unsigned long)gen_code_buf, (unsigned long)s->code_ptr); return s->code_ptr - gen_code_buf; } @@ -2051,33 +2084,33 @@ void tcg_dump_info(FILE *f, tot = s->interm_time + s->code_time; cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n", tot, tot / 2.4e9); - cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n", - s->tb_count, + cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n", + s->tb_count, s->tb_count1 - s->tb_count, s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0); - cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n", + cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n", s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max); cpu_fprintf(f, "deleted ops/TB %0.2f\n", - s->tb_count ? + s->tb_count ? (double)s->del_op_count / s->tb_count : 0); cpu_fprintf(f, "avg temps/TB %0.2f max=%d\n", - s->tb_count ? + s->tb_count ? (double)s->temp_count / s->tb_count : 0, s->temp_count_max); - - cpu_fprintf(f, "cycles/op %0.1f\n", + + cpu_fprintf(f, "cycles/op %0.1f\n", s->op_count ? (double)tot / s->op_count : 0); - cpu_fprintf(f, "cycles/in byte %0.1f\n", + cpu_fprintf(f, "cycles/in byte %0.1f\n", s->code_in_len ? (double)tot / s->code_in_len : 0); - cpu_fprintf(f, "cycles/out byte %0.1f\n", + cpu_fprintf(f, "cycles/out byte %0.1f\n", s->code_out_len ? (double)tot / s->code_out_len : 0); if (tot == 0) tot = 1; - cpu_fprintf(f, " gen_interm time %0.1f%%\n", + cpu_fprintf(f, " gen_interm time %0.1f%%\n", (double)s->interm_time / tot * 100.0); - cpu_fprintf(f, " gen_code time %0.1f%%\n", + cpu_fprintf(f, " gen_code time %0.1f%%\n", (double)s->code_time / tot * 100.0); - cpu_fprintf(f, "liveness/code time %0.1f%%\n", + cpu_fprintf(f, "liveness/code time %0.1f%%\n", (double)s->la_time / (s->code_time ? s->code_time : 1) * 100.0); cpu_fprintf(f, "cpu_restore count %" PRId64 "\n", s->restore_count); -- cgit v1.1