From patchwork Thu Feb 21 14:02:51 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anna Neiman X-Patchwork-Id: 222290 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 60AE92C008D for ; Fri, 22 Feb 2013 01:04:16 +1100 (EST) Received: from localhost ([::1]:39911 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U8Wkw-00041S-Hx for incoming@patchwork.ozlabs.org; Thu, 21 Feb 2013 09:04:14 -0500 Received: from eggs.gnu.org ([208.118.235.92]:56727) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U8WkS-0003yB-Ak for qemu-devel@nongnu.org; Thu, 21 Feb 2013 09:04:01 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1U8WkE-0003fM-Eb for qemu-devel@nongnu.org; Thu, 21 Feb 2013 09:03:44 -0500 Received: from relay1.mentorg.com ([192.94.38.131]:47712) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U8WkD-0003f7-VR for qemu-devel@nongnu.org; Thu, 21 Feb 2013 09:03:30 -0500 Received: from svr-orw-exc-10.mgc.mentorg.com ([147.34.98.58]) by relay1.mentorg.com with esmtp id 1U8WkA-0005Mw-Dl from Anna_Neiman@mentor.com ; Thu, 21 Feb 2013 06:03:26 -0800 Received: from ish-aneiman-ub.isr.mentorg.com ([137.202.52.61]) by SVR-ORW-EXC-10.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.4675); Thu, 21 Feb 2013 06:03:25 -0800 From: Anna Neiman To: qemu-devel@nongnu.org Date: Thu, 21 Feb 2013 16:02:51 +0200 Message-Id: <1361455371-31255-1-git-send-email-anna_neiman@mentor.com> X-Mailer: git-send-email 1.7.9.5 X-OriginalArrivalTime: 21 Feb 2013 14:03:26.0179 (UTC) FILETIME=[37DF5B30:01CE103C] X-detected-operating-system: by eggs.gnu.org: Windows NT kernel [generic] [fuzzy] X-Received-From: 192.94.38.131 Cc: Peter Maydell , Anthony Liguori , Amir Schriber , Paul Brook , Anna Neiman , Alex Rozenman Subject: [Qemu-devel] [PATCH 24028/24028] Evaluate breakpoint condition on target.Mechanism: translate gdb bytecode to TCG code and add to the translation block. Most of code is located in the new file translate-gdbagent.*. OPC_MAX_SIZE - size of translation buffer - was increased X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Signed-off-by: Anna Neiman --- Makefile.target | 2 +- cpu-exec.c | 19 +- exec.c | 17 +- gdbstub.c | 63 ++- include/exec/cpu-all.h | 1 + include/exec/cpu-defs.h | 24 ++ include/exec/exec-all.h | 2 +- target-alpha/translate.c | 2 +- target-arm/translate.c | 31 +- target-cris/translate.c | 2 +- target-i386/helper.c | 2 +- target-i386/translate.c | 2 +- target-lm32/translate.c | 2 +- target-m68k/translate.c | 2 +- target-microblaze/translate.c | 2 +- target-mips/translate.c | 2 +- target-openrisc/translate.c | 2 +- target-ppc/translate.c | 2 +- target-s390x/translate.c | 2 +- target-sh4/translate.c | 2 +- target-sparc/translate.c | 3 +- target-unicore32/translate.c | 2 +- target-xtensa/translate.c | 2 +- tcg/tcg-op.h | 10 + tcg/tcg.h | 6 + translate-all.c | 7 + translate-all.h | 2 + translate-gdbagent.c | 922 +++++++++++++++++++++++++++++++++++++++++ translate-gdbagent.h | 49 +++ 29 files changed, 1155 insertions(+), 31 deletions(-) create mode 100644 translate-gdbagent.c create mode 100644 translate-gdbagent.h diff --git a/Makefile.target b/Makefile.target index 760da1e..ed31f24 100644 --- a/Makefile.target +++ b/Makefile.target @@ -66,7 +66,7 @@ all: $(PROGS) stap ######################################################### # cpu emulator library -obj-y = exec.o translate-all.o cpu-exec.o +obj-y = exec.o translate-all.o translate-gdbagent.o cpu-exec.o obj-y += tcg/tcg.o tcg/optimize.o obj-$(CONFIG_TCG_INTERPRETER) += tci.o obj-$(CONFIG_TCG_INTERPRETER) += disas/tci.o diff --git a/cpu-exec.c b/cpu-exec.c index ff9a884..9347791 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -52,7 +52,8 @@ void cpu_resume_from_signal(CPUArchState *env, void *puc) /* Execute the code without caching the generated code. An interpreter could be used if available. */ static void cpu_exec_nocache(CPUArchState *env, int max_cycles, - TranslationBlock *orig_tb) + TranslationBlock *orig_tb, + int prev_rw_debug_flag) { tcg_target_ulong next_tb; TranslationBlock *tb; @@ -66,8 +67,10 @@ static void cpu_exec_nocache(CPUArchState *env, int max_cycles, max_cycles); env->current_tb = tb; /* execute the generated code */ + env->qemu_rw_debug_flag = 0; next_tb = tcg_qemu_tb_exec(env, tb->tc_ptr); env->current_tb = NULL; + env->qemu_rw_debug_flag = prev_rw_debug_flag; if ((next_tb & 3) == 2) { /* Restore PC. This may happen if async event occurs before @@ -184,6 +187,7 @@ int cpu_exec(CPUArchState *env) TranslationBlock *tb; uint8_t *tc_ptr; tcg_target_ulong next_tb; + int prev_rw_debug_flag = env->qemu_rw_debug_flag; if (env->halted) { if (!cpu_has_work(cpu)) { @@ -348,7 +352,10 @@ int cpu_exec(CPUArchState *env) } #elif defined(TARGET_PPC) if ((interrupt_request & CPU_INTERRUPT_RESET)) { + int saved_debug_flag = env->qemu_rw_debug_flag; + env->qemu_rw_debug_flag = 0; cpu_reset(cpu); + env->qemu_rw_debug_flag = saved_debug_flag; } if (interrupt_request & CPU_INTERRUPT_HARD) { ppc_hw_interrupt(env); @@ -594,7 +601,13 @@ int cpu_exec(CPUArchState *env) if (likely(!env->exit_request)) { tc_ptr = tb->tc_ptr; /* execute the generated code */ + + prev_rw_debug_flag = env->qemu_rw_debug_flag; + env->qemu_rw_debug_flag = 0; + next_tb = tcg_qemu_tb_exec(env, tc_ptr); + env->qemu_rw_debug_flag = prev_rw_debug_flag; + if ((next_tb & 3) == 2) { /* Instruction counter expired. */ int insns_left; @@ -615,7 +628,8 @@ int cpu_exec(CPUArchState *env) } else { if (insns_left > 0) { /* Execute remaining instructions. */ - cpu_exec_nocache(env, insns_left, tb); + cpu_exec_nocache(env, insns_left, tb, + prev_rw_debug_flag); } env->exception_index = EXCP_INTERRUPT; next_tb = 0; @@ -631,6 +645,7 @@ int cpu_exec(CPUArchState *env) /* Reload env after longjmp - the compiler may have smashed all * local variables as longjmp is marked 'noreturn'. */ env = cpu_single_env; + env->qemu_rw_debug_flag = prev_rw_debug_flag; } } /* for(;;) */ diff --git a/exec.c b/exec.c index b85508b..d96815b 100644 --- a/exec.c +++ b/exec.c @@ -295,6 +295,7 @@ void cpu_exec_init(CPUArchState *env) register_savevm(NULL, "cpu", cpu_index, CPU_SAVE_VERSION, cpu_save, cpu_load, env); #endif + env->qemu_rw_debug_flag = 1; } #if defined(TARGET_HAS_ICE) @@ -398,6 +399,7 @@ void cpu_watchpoint_remove_all(CPUArchState *env, int mask) /* Add a breakpoint. */ int cpu_breakpoint_insert(CPUArchState *env, target_ulong pc, int flags, + long cond_len, uint8_t *cond_exp, CPUBreakpoint **breakpoint) { #if defined(TARGET_HAS_ICE) @@ -407,6 +409,13 @@ int cpu_breakpoint_insert(CPUArchState *env, target_ulong pc, int flags, bp->pc = pc; bp->flags = flags; + bp->cond_len = cond_len; + if (cond_exp == NULL || cond_len == 0) { + bp->cond_exp = NULL; + } else { + bp->cond_exp = g_malloc(sizeof(uint8_t) * cond_len); + memcpy(bp->cond_exp, cond_exp, sizeof(uint8_t) * cond_len); + } /* keep all GDB-injected breakpoints in front */ if (flags & BP_GDB) @@ -450,6 +459,11 @@ void cpu_breakpoint_remove_by_ref(CPUArchState *env, CPUBreakpoint *breakpoint) breakpoint_invalidate(env, breakpoint->pc); + if (breakpoint->cond_len != 0 && breakpoint->cond_exp != NULL) { + g_free(breakpoint->cond_exp); + } + + g_free(breakpoint); #endif } @@ -549,7 +563,8 @@ CPUArchState *cpu_copy(CPUArchState *env) QTAILQ_INIT(&env->watchpoints); #if defined(TARGET_HAS_ICE) QTAILQ_FOREACH(bp, &env->breakpoints, entry) { - cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL); + cpu_breakpoint_insert(new_env, bp->pc, bp->flags, + bp->cond_len, bp->cond_exp, NULL); } QTAILQ_FOREACH(wp, &env->watchpoints, entry) { cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1, diff --git a/gdbstub.c b/gdbstub.c index 6cd26f1..c709154 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -42,6 +42,8 @@ #include "sysemu/kvm.h" #include "qemu/bitops.h" +#include "translate-gdbagent.h" + #ifndef TARGET_CPU_MEMORY_RW_DEBUG static inline int target_memory_rw_debug(CPUArchState *env, target_ulong addr, uint8_t *buf, int len, int is_write) @@ -1941,7 +1943,8 @@ static const int xlat_gdb_type[] = { }; #endif -static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type) +static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type, + long cond_len, uint8_t *cond_exp) { CPUArchState *env; int err = 0; @@ -1953,7 +1956,8 @@ static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type) case GDB_BREAKPOINT_SW: case GDB_BREAKPOINT_HW: for (env = first_cpu; env != NULL; env = env->next_cpu) { - err = cpu_breakpoint_insert(env, addr, BP_GDB, NULL); + err = cpu_breakpoint_insert(env, addr, BP_GDB, + cond_len, cond_exp, NULL); if (err) break; } @@ -2087,6 +2091,10 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) uint8_t *registers; target_ulong addr, len; + uint8_t *bp_cond_expr = NULL; + int bp_cond_len = 0; + int i = 0 ; + #ifdef DEBUG_GDB printf("command='%s'\n", line_buf); #endif @@ -2308,16 +2316,57 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) if (*p == ',') p++; len = strtoull(p, (char **)&p, 16); - if (ch == 'Z') - res = gdb_breakpoint_insert(addr, len, type); - else + while (isspace(*p)) { + p++; + } + if (ch == 'Z' && *p == ';') { + p++; + while (isspace(*p)) { + p++; + } + if (*p == 'X') { + p++; + bp_cond_len = strtoul(p, (char **)&p, 16); + if (*p == ',') { + p++; + } + if (bp_cond_len > 0) { + int bp_cond_size = sizeof(uint8_t) * bp_cond_len; + bp_cond_expr = (uint8_t *)g_malloc(bp_cond_size); + memset(bp_cond_expr, 0, bp_cond_size); + + for (i = 0 ; i < bp_cond_len ; i++) { + if (!isxdigit(*p) || !isxdigit(*(p + 1))) { + bp_cond_len = 0 ; + g_free(bp_cond_expr); + bp_cond_expr = NULL; + perror("Error in breakpoint condition"); + } else { + hextomem(bp_cond_expr+i, p, 1); + p += 2; + } + } + } +#ifdef DEBUG_GDB + bp_agent_dump_bytecode(bp_cond_len, bp_cond_expr); +#endif + } + } + if (ch == 'Z') { + res = gdb_breakpoint_insert(addr, len, type, + bp_cond_len, bp_cond_expr); + } else { res = gdb_breakpoint_remove(addr, len, type); + } if (res >= 0) put_packet(s, "OK"); else if (res == -ENOSYS) put_packet(s, ""); else put_packet(s, "E22"); + if (bp_cond_expr != NULL) { + g_free(bp_cond_expr); + } break; case 'H': type = *p++; @@ -2442,6 +2491,10 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) #endif /* !CONFIG_USER_ONLY */ if (strncmp(p, "Supported", 9) == 0) { snprintf(buf, sizeof(buf), "PacketSize=%x", MAX_PACKET_LENGTH); + + /* conditional breakpoint evaluation on target*/ + pstrcat(buf, sizeof(buf), ";ConditionalBreakpoints+"); + #ifdef GDB_CORE_XML pstrcat(buf, sizeof(buf), ";qXfer:features:read+"); #endif diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 249e046..383c4c1 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -448,6 +448,7 @@ void cpu_exit(CPUArchState *s); #define BP_CPU 0x20 int cpu_breakpoint_insert(CPUArchState *env, target_ulong pc, int flags, + long cond_len, uint8_t *cond_exp, CPUBreakpoint **breakpoint); int cpu_breakpoint_remove(CPUArchState *env, target_ulong pc, int flags); void cpu_breakpoint_remove_by_ref(CPUArchState *env, CPUBreakpoint *breakpoint); diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index 2911b9f..a1bbde3 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -137,9 +137,13 @@ typedef struct icount_decr_u16 { typedef struct CPUBreakpoint { target_ulong pc; int flags; /* BP_* */ + int cond_len; + uint8_t *cond_exp; QTAILQ_ENTRY(CPUBreakpoint) entry; } CPUBreakpoint; +int bp_has_cond(CPUBreakpoint *bp); + typedef struct CPUWatchpoint { target_ulong vaddr; target_ulong len_mask; @@ -147,6 +151,21 @@ typedef struct CPUWatchpoint { QTAILQ_ENTRY(CPUWatchpoint) entry; } CPUWatchpoint; + +#if TARGET_LONG_SIZE == 4 +typedef float target_double; +#else /* TARGET_LONG_SIZE == 8 */ +typedef double target_double; +#endif + +typedef union BPAgentStackElementType { + target_long l; + target_double d; +} BPAgentStackElementType; + + +#define BP_AGENT_MAX_COND_SIZE 1024 + #define CPU_TEMP_BUF_NLONGS 128 #define CPU_COMMON \ struct TranslationBlock *current_tb; /* currently executing TB */ \ @@ -196,6 +215,11 @@ typedef struct CPUWatchpoint { /* user data */ \ void *opaque; \ \ + BPAgentStackElementType bp_agent_stack[BP_AGENT_MAX_COND_SIZE]; \ + BPAgentStackElementType *bp_agent_stack_current; \ + /*bp_agent_stack_current is the current location in bp_agent_stack */ \ + int bp_agent_error; /* error in evaluation - ex., divide by zero*/ \ + int qemu_rw_debug_flag; \ const char *cpu_model_str; #endif diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index f685c28..afe4701 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -59,7 +59,7 @@ typedef struct TranslationBlock TranslationBlock; * and up to 4 + N parameters on 64-bit archs * (N = number of input arguments + output arguments). */ #define MAX_OPC_PARAM (4 + (MAX_OPC_PARAM_PER_ARG * MAX_OPC_PARAM_ARGS)) -#define OPC_BUF_SIZE 640 +#define OPC_BUF_SIZE 2560 #define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR) /* Maximum size a TCG op can expand to. This is complicated because a diff --git a/target-alpha/translate.c b/target-alpha/translate.c index f687b95..b5d6e0c 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -72,7 +72,7 @@ typedef enum { } ExitStatus; /* global register indexes */ -static TCGv_ptr cpu_env; +TCGv_ptr cpu_env; static TCGv cpu_ir[31]; static TCGv cpu_fir[31]; static TCGv cpu_pc; diff --git a/target-arm/translate.c b/target-arm/translate.c index a8893f7..d1d8f7d 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -32,6 +32,7 @@ #include "helper.h" #define GEN_HELPER 1 #include "helper.h" +#include "translate-gdbagent.h" #define ENABLE_ARCH_4T arm_feature(env, ARM_FEATURE_V4T) #define ENABLE_ARCH_5 arm_feature(env, ARM_FEATURE_V5) @@ -81,7 +82,7 @@ static uint32_t gen_opc_condexec_bits[OPC_BUF_SIZE]; #define DISAS_WFI 4 #define DISAS_SWI 5 -static TCGv_ptr cpu_env; +TCGv_ptr cpu_env; /* We reuse the same 64-bit temporaries for efficiency. */ static TCGv_i64 cpu_V0, cpu_V1, cpu_M0; static TCGv_i32 cpu_R[16]; @@ -153,6 +154,11 @@ static inline void store_cpu_offset(TCGv var, int offset) tcg_temp_free_i32(var); } +void cpu_get_reg_var_arm(TCGv var, int reg) +{ + tcg_gen_mov_i32(var, cpu_R[reg]); +} + #define store_cpu_field(var, name) \ store_cpu_offset(var, offsetof(CPUARMState, name)) @@ -9827,11 +9833,24 @@ static inline void gen_intermediate_code_internal(CPUARMState *env, if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { QTAILQ_FOREACH(bp, &env->breakpoints, entry) { if (bp->pc == dc->pc) { - gen_exception_insn(dc, 0, EXCP_DEBUG); - /* Advance PC so that clearing the breakpoint will - invalidate this TB. */ - dc->pc += 2; - goto done_generating; + if (bp_has_cond(bp)) { + int bp_condlabel = gen_new_label(); + int res = tcg_gen_bp_cond + (env, &tcg_ctx, bp, bp_condlabel); + /* tcg_gen_bp_cond can return 0 + in case internal error, + in particular gen_opc_buf overload */ + gen_exception(EXCP_DEBUG); + if (res) { + gen_set_label(bp_condlabel); + } + } else { + gen_exception_insn(dc, 0, EXCP_DEBUG); + /* Advance PC so that clearing the breakpoint will + invalidate this TB. */ + dc->pc += 2; + goto done_generating; + } break; } } diff --git a/target-cris/translate.c b/target-cris/translate.c index 09e6011..077f714 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -55,7 +55,7 @@ #define CC_MASK_NZVC 0xf #define CC_MASK_RNZV 0x10e -static TCGv_ptr cpu_env; +TCGv_ptr cpu_env; static TCGv cpu_R[16]; static TCGv cpu_PR[16]; static TCGv cc_x; diff --git a/target-i386/helper.c b/target-i386/helper.c index d1cb4e2..e23b2f4 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -973,7 +973,7 @@ void hw_breakpoint_insert(CPUX86State *env, int index) switch (hw_breakpoint_type(env->dr[7], index)) { case DR7_TYPE_BP_INST: if (hw_breakpoint_enabled(env->dr[7], index)) { - err = cpu_breakpoint_insert(env, env->dr[index], BP_CPU, + err = cpu_breakpoint_insert(env, env->dr[index], BP_CPU, 0, NULL, &env->cpu_breakpoint[index]); } break; diff --git a/target-i386/translate.c b/target-i386/translate.c index 112c310..760b206 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -50,7 +50,7 @@ //#define MACRO_TEST 1 /* global register indexes */ -static TCGv_ptr cpu_env; +TCGv_ptr cpu_env; static TCGv cpu_A0, cpu_cc_src, cpu_cc_dst, cpu_cc_tmp; static TCGv_i32 cpu_cc_op; static TCGv cpu_regs[CPU_NB_REGS]; diff --git a/target-lm32/translate.c b/target-lm32/translate.c index 6b87340..7f4bc7d 100644 --- a/target-lm32/translate.c +++ b/target-lm32/translate.c @@ -39,7 +39,7 @@ #define MEM_INDEX 0 -static TCGv_ptr cpu_env; +TCGv_ptr cpu_env; static TCGv cpu_R[32]; static TCGv cpu_pc; static TCGv cpu_ie; diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 3f1478c..07647d3 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -42,7 +42,7 @@ #undef DEFO64 #undef DEFF64 -static TCGv_ptr cpu_env; +TCGv_ptr cpu_env; static char cpu_reg_names[3*8*3 + 5*4]; static TCGv cpu_dregs[8]; diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index 58ce712..d0b92db 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -42,7 +42,7 @@ (((src) >> start) & ((1 << (end - start + 1)) - 1)) static TCGv env_debug; -static TCGv_ptr cpu_env; +TCGv_ptr cpu_env; static TCGv cpu_R[32]; static TCGv cpu_SR[18]; static TCGv env_imm; diff --git a/target-mips/translate.c b/target-mips/translate.c index 3b77b53..2e20707 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1006,7 +1006,7 @@ enum { }; /* global register indices */ -static TCGv_ptr cpu_env; +TCGv_ptr cpu_env; static TCGv cpu_gpr[32], cpu_PC; static TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC], cpu_ACX[MIPS_DSP_ACC]; static TCGv cpu_dspctrl, btarget, bcond; diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c index 1e1b30c..32e5e08 100644 --- a/target-openrisc/translate.c +++ b/target-openrisc/translate.c @@ -49,7 +49,7 @@ typedef struct DisasContext { uint32_t delayed_branch; } DisasContext; -static TCGv_ptr cpu_env; +TCGv_ptr cpu_env; static TCGv cpu_sr; static TCGv cpu_R[32]; static TCGv cpu_pc; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 2ac5794..24ce440 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -44,7 +44,7 @@ /* Code translation helpers */ /* global register indexes */ -static TCGv_ptr cpu_env; +TCGv_ptr cpu_env; static char cpu_reg_names[10*3 + 22*4 /* GPR */ #if !defined(TARGET_PPC64) + 10*4 + 22*5 /* SPE GPRh */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index a57296c..3bdfc28 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -35,7 +35,7 @@ #include "qemu/host-utils.h" /* global register indexes */ -static TCGv_ptr cpu_env; +TCGv_ptr cpu_env; #include "exec/gen-icount.h" #include "helper.h" diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 260aaab..9ee093c 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -57,7 +57,7 @@ enum { }; /* global register indexes */ -static TCGv_ptr cpu_env; +TCGv_ptr cpu_env; static TCGv cpu_gregs[24]; static TCGv cpu_pc, cpu_sr, cpu_ssr, cpu_spc, cpu_gbr; static TCGv cpu_vbr, cpu_sgr, cpu_dbr, cpu_mach, cpu_macl; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index ca75e1a..de4eaad 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -39,7 +39,8 @@ according to jump_pc[T2] */ /* global register indexes */ -static TCGv_ptr cpu_env, cpu_regwptr; +TCGv_ptr cpu_env; +static TCGv_ptr cpu_regwptr; static TCGv cpu_cc_src, cpu_cc_src2, cpu_cc_dst; static TCGv_i32 cpu_cc_op; static TCGv_i32 cpu_psr; diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c index f4498bc..32c2172 100644 --- a/target-unicore32/translate.c +++ b/target-unicore32/translate.c @@ -48,7 +48,7 @@ typedef struct DisasContext { conditional executions state has been updated. */ #define DISAS_SYSCALL 5 -static TCGv_ptr cpu_env; +TCGv_ptr cpu_env; static TCGv_i32 cpu_R[32]; /* FIXME: These should be removed. */ diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index 7029ac4..dad1f7a 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -69,7 +69,7 @@ typedef struct DisasContext { unsigned cpenable; } DisasContext; -static TCGv_ptr cpu_env; +TCGv_ptr cpu_env; static TCGv_i32 cpu_pc; static TCGv_i32 cpu_R[16]; static TCGv_i32 cpu_FR[16]; diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 91c9d80..03f66e9 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -21,6 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + + +#ifndef __TCG_OP_H__ +#define __TCG_OP_H__ #include "tcg.h" int gen_new_label(void); @@ -2718,6 +2722,8 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index) TCGV_PTR_TO_NAT(B)) #define tcg_gen_addi_ptr(R, A, B) tcg_gen_addi_i32(TCGV_PTR_TO_NAT(R), \ TCGV_PTR_TO_NAT(A), (B)) +#define tcg_gen_subi_ptr(R, A, B) tcg_gen_subi_i32(TCGV_PTR_TO_NAT(R), \ + TCGV_PTR_TO_NAT(A), (B)) #define tcg_gen_ext_i32_ptr(R, A) tcg_gen_mov_i32(TCGV_PTR_TO_NAT(R), (A)) #else /* TCG_TARGET_REG_BITS == 32 */ #define tcg_gen_add_ptr(R, A, B) tcg_gen_add_i64(TCGV_PTR_TO_NAT(R), \ @@ -2725,5 +2731,9 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index) TCGV_PTR_TO_NAT(B)) #define tcg_gen_addi_ptr(R, A, B) tcg_gen_addi_i64(TCGV_PTR_TO_NAT(R), \ TCGV_PTR_TO_NAT(A), (B)) +#define tcg_gen_subi_ptr(R, A, B) tcg_gen_subi_i64(TCGV_PTR_TO_NAT(R), \ + TCGV_PTR_TO_NAT(A), (B)) #define tcg_gen_ext_i32_ptr(R, A) tcg_gen_ext_i32_i64(TCGV_PTR_TO_NAT(R), (A)) #endif /* TCG_TARGET_REG_BITS != 32 */ + +#endif /* __TCG_OP_H__ */ diff --git a/tcg/tcg.h b/tcg/tcg.h index 51c8176..8158e3c 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -21,6 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + +#ifndef __TCG_H__ +#define __TCG_H__ + #include "qemu-common.h" /* Target word size (must be identical to pointer size). */ @@ -682,3 +686,5 @@ void tcg_register_jit(void *buf, size_t buf_size); /* Generate TB finalization at the end of block */ void tcg_out_tb_finalize(TCGContext *s); #endif + +#endif /* __TCG_H__*/ diff --git a/translate-all.c b/translate-all.c index efeb247..5f10984 100644 --- a/translate-all.c +++ b/translate-all.c @@ -59,6 +59,7 @@ #include "exec/cputlb.h" #include "translate-all.h" +#include "translate-gdbagent.h" //#define DEBUG_TB_INVALIDATE //#define DEBUG_FLUSH @@ -150,6 +151,8 @@ int cpu_gen_code(CPUArchState *env, TranslationBlock *tb, int *gen_code_size_ptr exceptions */ ti = profile_getclock(); #endif + bp_agent_init(); + tcg_func_start(s); gen_intermediate_code(env, tb); @@ -199,6 +202,7 @@ static int cpu_restore_state_from_tb(TranslationBlock *tb, CPUArchState *env, TCGContext *s = &tcg_ctx; int j; uintptr_t tc_ptr; + int prev_rw_debug_flag; #ifdef CONFIG_PROFILER int64_t ti; #endif @@ -208,7 +212,10 @@ static int cpu_restore_state_from_tb(TranslationBlock *tb, CPUArchState *env, #endif tcg_func_start(s); + prev_rw_debug_flag = env->qemu_rw_debug_flag; + env->qemu_rw_debug_flag = 1; gen_intermediate_code_pc(env, tb); + env->qemu_rw_debug_flag = prev_rw_debug_flag; if (use_icount) { /* Reset the cycle counter to the start of the block. */ diff --git a/translate-all.h b/translate-all.h index b181fb4..5e883b1 100644 --- a/translate-all.h +++ b/translate-all.h @@ -31,4 +31,6 @@ void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len); void cpu_unlink_tb(CPUArchState *env); void tb_check_watchpoint(CPUArchState *env); +extern TCGv_ptr cpu_env; + #endif /* TRANSLATE_ALL_H */ diff --git a/translate-gdbagent.c b/translate-gdbagent.c new file mode 100644 index 0000000..e868ced --- /dev/null +++ b/translate-gdbagent.c @@ -0,0 +1,922 @@ +/* + * Translation GDB bytecode to TCG. + * Used for evaluation breakpoint condition on host. + * + * Copyright (c) 2013 Anna Neiman + * Copyright (c) 2012 Mentor Graphics Corp. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#define NO_CPU_IO_DEFS +#include "cpu.h" +#include "exec/exec-all.h" +#include "translate-gdbagent.h" +#include "translate-all.h" + +#if defined(TARGET_HAS_ICE) + +static TCGv_ptr bp_agent_stack_current_tcg ; +static TCGv qemu_rw_debug_flag_tcg ; +static TCGv bp_agent_error_tcg ; + +typedef void(*CPUGetRegVarFuncType)(TCGv var, int reg); + +/* function for retrieve register contents - platform depend*/ +static CPUGetRegVarFuncType cpu_get_reg_var_func; + + +static int inited; + +void bp_agent_init(void) +{ + if (!inited) { + inited = 1; + bp_agent_stack_current_tcg = + tcg_global_mem_new_ptr(TCG_AREG0, + offsetof(CPUArchState, bp_agent_stack_current), + "bp_agent_stack_current"); + qemu_rw_debug_flag_tcg = + tcg_global_mem_new(TCG_AREG0, + offsetof(CPUArchState, qemu_rw_debug_flag), + "qemu_rw_debug_flag"); + bp_agent_error_tcg = + tcg_global_mem_new(TCG_AREG0, + offsetof(CPUArchState, bp_agent_error), + "bp_agent_error"); + } +#if defined(TARGET_ARM) + cpu_get_reg_var_func = cpu_get_reg_var_arm; +#else + cpu_get_reg_var_func = 0; +#endif +} +static void bp_agent_init_local(CPUArchState *env, int len) +{ + if (len > BP_AGENT_MAX_COND_SIZE) { + fprintf(stderr, + "GDB agent: Condition length more then %d is unsupported.\n", + BP_AGENT_MAX_COND_SIZE); + } + + tcg_gen_addi_ptr(bp_agent_stack_current_tcg, cpu_env, + offsetof(CPUArchState, bp_agent_stack)); + tcg_gen_movi_tl(qemu_rw_debug_flag_tcg, 1); +} + +static void increment_stack_ptr(CPUArchState *env) +{ + tcg_gen_addi_ptr(bp_agent_stack_current_tcg, + bp_agent_stack_current_tcg, + TARGET_LONG_SIZE); + +} +static void decrement_stack_ptr(CPUArchState *env) +{ + tcg_gen_subi_ptr(bp_agent_stack_current_tcg, + bp_agent_stack_current_tcg, + TARGET_LONG_SIZE); +} + +static int check_max_instr_num(TCGContext *s, int labels_num) +{ + return ((s->gen_opc_ptr - s->gen_opc_buf) <= + (OPC_MAX_SIZE - 20 - labels_num)) ; +} + +static int bp_agent_stack_set_const(CPUArchState *env, target_long tmp) +{ + TCGv tmp2 = tcg_temp_new(); + tcg_gen_movi_tl(tmp2, tmp); + tcg_gen_st_tl(tmp2, bp_agent_stack_current_tcg, 0); + + tcg_temp_free(tmp2); + return 1; +} +static int bp_agent_stack_push_const(CPUArchState *env, target_long tmp) +{ + bp_agent_stack_set_const(env, tmp); + + increment_stack_ptr(env); + return 1; +} +static int bp_agent_stack_push(CPUArchState *env, TCGv tmp) +{ + tcg_gen_st_tl(tmp, bp_agent_stack_current_tcg, 0); + + increment_stack_ptr(env); + return 1; +} + +static int bp_agent_stack_pop(CPUArchState *env, TCGv tmp) +{ + decrement_stack_ptr(env); + tcg_gen_ld_tl(tmp, bp_agent_stack_current_tcg, 0); + return 1; +} + +static int bp_agent_brcond_top(CPUArchState *env, int condlabel) +{ + TCGv tmp = tcg_temp_local_new(); + int loc_err_label = gen_new_label(); + + bp_agent_stack_pop(env, tmp); + tcg_gen_movi_tl(qemu_rw_debug_flag_tcg, 0); + + /* if error - evaluate on host */ + tcg_gen_brcondi_tl(TCG_COND_NE, bp_agent_error_tcg, 0, loc_err_label); + + tcg_gen_brcondi_tl(TCG_COND_EQ, tmp, 0, condlabel); + + gen_set_label(loc_err_label); + + tcg_temp_free(tmp); + + return 1; +} + +typedef enum { + BYTECODE_FLOAT = 0x01, + BYTECODE_ADD = 0x02, + BYTECODE_SUB = 0x03, + BYTECODE_MUL = 0x04, + BYTECODE_DIV_SIGNED = 0x05, + BYTECODE_DIV_UNSIGNED = 0x06, + BYTECODE_REM_SIGNED = 0x07, + BYTECODE_REM_UNSIGNED = 0x08, + BYTECODE_LSH = 0x09, + BYTECODE_RSH_SIGNED = 0x0a, + BYTECODE_RSH_UNSIGNED = 0x0b, + BYTECODE_TRACE = 0x0c, + BYTECODE_TRACE_QUICK = 0x0d, + BYTECODE_LOG_NOT = 0x0e, + BYTECODE_BIT_AND = 0x0f, + BYTECODE_BIT_OR = 0x10, + BYTECODE_BIT_XOR = 0x11, + BYTECODE_BIT_NOT = 0x12, + BYTECODE_EQUAL = 0x13, + BYTECODE_LESS_SIGNED = 0x14, + BYTECODE_LESS_UNSIGNED = 0x15, + BYTECODE_EXT = 0x16, + BYTECODE_REF8 = 0x17, + BYTECODE_REF16 = 0x18, + BYTECODE_REF32 = 0x19, + BYTECODE_REF64 = 0x1a, + BYTECODE_REF_FLOAT = 0x1b, + BYTECODE_REF_DOUBLE = 0x1c, + BYTECODE_REF_LONG_DOUBLE = 0x1d, + BYTECODE_L_TO_D = 0x1e, + BYTECODE_D_TO_L = 0x1f, + BYTECODE_IF_GOTO = 0x20, + BYTECODE_GOTO = 0x21, + BYTECODE_CONST8 = 0x22, + BYTECODE_CONST16 = 0x23, + BYTECODE_CONST32 = 0x24, + BYTECODE_CONST64 = 0x25, + BYTECODE_REG = 0x26, + BYTECODE_END = 0x27, + BYTECODE_DUP = 0x28, + BYTECODE_POP = 0x29, + BYTECODE_ZERO_EXT = 0x2a, + BYTECODE_SWAP = 0x2b, + BYTECODE_TRACE16 = 0x30 +} BytecodeCommandsType; + +static const char *bytecode_commands_names[] = { + "", /*0x00*/ + "float", /*0x01*/ + "add", /*0x02*/ + "sub", /*0x03*/ + "mul", /*0x04*/ + "div_signed", /*0x05*/ + "div_unsigned", /*0x06*/ + "rem_signed", /*0x07*/ + "rem_unsigned", /*0x08*/ + "lsh", /*0x09*/ + "rsh_signed", /*0x0a*/ + "rsh_unsigned", /*0x0b*/ + "trace", /*0x0c*/ + "trace_quick", /*0x0d*/ + "log_not", /*0x0e*/ + "bit_and", /*0x0f*/ + "bit_or", /*0x10*/ + "bit_xor", /*0x11*/ + "bit_not ", /*0x12*/ + "equal", /*0x13*/ + "less_signed", /*0x14*/ + "less_unsigned", /*0x15*/ + "ext", /*0x16*/ + "ref8", /*0x17*/ + "ref16", /*0x18*/ + "ref32", /*0x19*/ + "ref64", /*0x1a*/ + "ref_float", /*0x1b*/ + "ref_double", /*0x1c*/ + "ref_long_double", /*0x1d*/ + "l_to_d", /*0x1e*/ + "d_to_l", /*0x1f*/ + "if_goto", /*0x20*/ + "goto", /*0x21*/ + "const8", /*0x22*/ + "const16", /*0x23*/ + "const32", /*0x24*/ + "const64", /*0x25*/ + "reg", /*0x26*/ + "end", /*0x27*/ + "dup", /*0x28*/ + "pop", /*0x29*/ + "zero_ext", /*0x2a*/ + "swap", /*0x2b*/ + "", /*0x2c*/ + "", /*0x2d*/ + "", /*0x2e*/ + "", /*0x2f*/ + "trace16" /*0x30*/ +}; + +static target_long bp_agent_get_arg(const uint8_t *cond_exp, + int *bp_agent_instr_cnt, int num_bytes) +{ + target_long res = 0 ; + int ind = *bp_agent_instr_cnt; + switch (num_bytes) { + case 1: + ind++; + res = cond_exp[ind]; + break; + case 2: + { + uint16_t val; + ind++; + val = (cond_exp[ind] << 8) + cond_exp[ind+1]; + ind++; + bswap16(val); + res = val; + } + break; + case 8: + { +#if TARGET_LONG_SIZE == 8 + uint64_t val = 0; + int i = 0; + for (i = 0; i < 8; i++) { + ind++; + val = val + cond_exp[ind]; + val = val << 8; + } + bswap64(val); + res = val; +#else + fprintf(stderr, + "GDB agent: const 64 is not supported for 32 bit target architecture.\n"); +#endif + break; + } + case 4: + default: + { + uint32_t val; + ind++; + val = + (cond_exp[ind] << 24) + (cond_exp[ind+1] << 16) + + (cond_exp[ind+2] << 8) + cond_exp[ind+3]; + ind += 3; + bswap32(val); + res = val; + } + break; + } + *bp_agent_instr_cnt = ind; + return res; +} +typedef int(*PrintFuncType)(const char *, ...) + __attribute__((__format__(__printf__, 1, 2))); + +static int bp_agent_pass_bytecode(int cond_len, const uint8_t *cond_exp, + int *label_tab, PrintFuncType prnt) +/* returns number of labels */ +{ + int ret = 0 ; + int i = 0 ; + target_long val = 0; + for (i = 0 ; i < cond_len; i++) { + BytecodeCommandsType command_type = (BytecodeCommandsType)(cond_exp[i]); + switch (command_type) { + case BYTECODE_FLOAT: /*0x01*/ + case BYTECODE_REF_FLOAT: /*0x1b */ + case BYTECODE_REF_DOUBLE: /*0x1c */ + case BYTECODE_REF_LONG_DOUBLE: /*0x1d */ + case BYTECODE_L_TO_D: /*0x1e*/ + case BYTECODE_D_TO_L: /*0x1f*/ + case BYTECODE_TRACE: /*0x0c*/ + if (prnt) { + prnt("\n\t%s", + bytecode_commands_names[(int)command_type]); + } + break; + case BYTECODE_TRACE_QUICK: /*0x0d*/ + val = bp_agent_get_arg(cond_exp, &i, 1); + if (prnt) { + prnt("\n\t%s %x", + bytecode_commands_names[(int)command_type], + (unsigned int)val); + } + break; + case BYTECODE_TRACE16: /*0x30*/ + val = bp_agent_get_arg(cond_exp, &i, 2); + if (prnt) { + prnt("\n\t%s %x", + bytecode_commands_names[(int)command_type], + (unsigned int)val); + } + break; + case BYTECODE_END: /*0x27*/ + case BYTECODE_DUP: /*0x28*/ + case BYTECODE_POP: /*0x29*/ + case BYTECODE_SWAP: /*0x2b */ + case BYTECODE_REF8: /*0x17*/ + case BYTECODE_REF16: /*0x18 */ + case BYTECODE_REF64: /*0x1a */ + case BYTECODE_REF32: /*0x19*/ + if (prnt) { + prnt("\n\t%s", + bytecode_commands_names[(int)command_type]); + } + break; + case BYTECODE_IF_GOTO: /*0x20*/ + case BYTECODE_GOTO: /*0x21*/ + val = bp_agent_get_arg(cond_exp, &i, 2); + if (prnt) { + prnt("\n\t%s %x", + bytecode_commands_names[(int)command_type], + (unsigned int)val); + } + if (label_tab != NULL && label_tab[val] == -1) { + label_tab[val] = gen_new_label(); + ret++; + } + break; + case BYTECODE_CONST8: /*0x22*/ + val = bp_agent_get_arg(cond_exp, &i, 1); + if (prnt) { + prnt("\n\t%s %x", + bytecode_commands_names[(int)command_type], + (unsigned int)val); + } + break; + case BYTECODE_CONST16: /*0x23*/ + val = bp_agent_get_arg(cond_exp, &i, 2); + if (prnt) { + prnt("\n\t%s %x", + bytecode_commands_names[(int)command_type], + (unsigned int)val); + } + break; + case BYTECODE_CONST64: /*0x25*/ + val = bp_agent_get_arg(cond_exp, &i, 8); +#if TARGET_LONG_SIZE == 8 + if (prnt) { + prnt("\n\t%s %llx", + bytecode_commands_names[(int)command_type], + (unsigned long long)val); + } +#endif + break; + case BYTECODE_CONST32: /*0x24*/ + val = bp_agent_get_arg(cond_exp, &i, 4); + if (prnt) { + prnt("\n\t%s %lx", + bytecode_commands_names[(int)command_type], + (unsigned long)val); + } + break; + case BYTECODE_REG: /*0x26*/ + val = bp_agent_get_arg(cond_exp, &i, 2); + if (prnt) { + prnt("\n\t%s %x", + bytecode_commands_names[(int)command_type], + (unsigned int)val); + } + break; + + case BYTECODE_LOG_NOT:/*0x0e*/ + case BYTECODE_BIT_NOT: /*0x12*/ + if (prnt) { + prnt("\n\t%s", + bytecode_commands_names[(int)command_type]); + } + break; + case BYTECODE_EXT: /*0x16*/ + val = bp_agent_get_arg(cond_exp, &i, 1); + if (prnt) { + prnt("\n\text %x", (unsigned int) val); + } + break; + case BYTECODE_ZERO_EXT: /*0x2a */ + val = bp_agent_get_arg(cond_exp, &i, 1); + if (prnt) { + prnt("\n\t%s %x", + bytecode_commands_names[(int)command_type], + (unsigned int)val); + } + break; + case BYTECODE_ADD: /*0x02*/ + case BYTECODE_SUB: /*0x03*/ + case BYTECODE_MUL: /*0x04*/ + case BYTECODE_DIV_SIGNED: /*0x05*/ + case BYTECODE_DIV_UNSIGNED: /*0x06*/ + case BYTECODE_REM_SIGNED: /*0x07*/ + case BYTECODE_REM_UNSIGNED: /*0x08*/ + case BYTECODE_LSH: /*0x09*/ + case BYTECODE_RSH_SIGNED: /*0x0a*/ + case BYTECODE_RSH_UNSIGNED: /*0x0b*/ + case BYTECODE_BIT_AND: /*0x0f*/ + case BYTECODE_BIT_OR: /*0x10*/ + case BYTECODE_BIT_XOR: /*0x11*/ + case BYTECODE_EQUAL: /*0x13*/ + case BYTECODE_LESS_SIGNED: /*0x14*/ + case BYTECODE_LESS_UNSIGNED: /*0x15*/ + if (prnt) { + prnt("\n\t%s", + bytecode_commands_names[(int)command_type]); + } + break; + default: + break; + } + } + return ret; +} +void bp_agent_dump_bytecode(int cond_len, const uint8_t *cond_exp) +/*called from gdbstub in debug mode */ +{ + printf("\nBytecode :"); + bp_agent_pass_bytecode(cond_len, cond_exp, NULL, printf); + printf("\nEnd of Bytecode :"); +} +static int bp_agent_tcg_gen(CPUArchState *env, TCGContext *s, + int cond_len, const uint8_t *cond_exp) +{ + int i = 0 ; + target_long val = 0 ; + + int ret = 1 ; + int labels_num = 0 ; + + + int *label_tab = (int *)g_malloc(sizeof(int) * cond_len); + for (i = 0; i < cond_len ; i++) { + label_tab[i] = -1; /* real label value can be 0*/ + } + + labels_num = bp_agent_pass_bytecode(cond_len, cond_exp, label_tab, NULL); + for (i = 0; + (i < cond_len) && (ret == 1) && check_max_instr_num(s, labels_num); + i++) { + BytecodeCommandsType command_type = (BytecodeCommandsType)(cond_exp[i]); + if (label_tab[i] != -1) { + gen_set_label(label_tab[i]); + labels_num--; + } + switch (command_type) { + case BYTECODE_FLOAT: /*0x01 */ + case BYTECODE_REF_FLOAT: /*0x1b */ + case BYTECODE_REF_DOUBLE: /*0x1c */ + case BYTECODE_REF_LONG_DOUBLE: /*0x1d */ + case BYTECODE_L_TO_D: /*0x1e */ + case BYTECODE_D_TO_L: /*0x1f */ + printf("\n Command is not implemented in BP agent"); + break; + case BYTECODE_TRACE: /*0x0c not need for bp condition */ + break; + case BYTECODE_TRACE_QUICK: /*0x0d not need for bp condition */ + val = bp_agent_get_arg(cond_exp, &i, 1); + break; + case BYTECODE_TRACE16: /*0x30 not need for bp condition */ + val = bp_agent_get_arg(cond_exp, &i, 2); + break; + case BYTECODE_END: /*0x27 */ + i = cond_len; + break; + case BYTECODE_DUP: /*0x28*/ + { + TCGv tmp1 = tcg_temp_new(); + ret = bp_agent_stack_pop(env, tmp1); + if (ret) { + ret = bp_agent_stack_push(env, tmp1); + } + if (ret) { + ret = bp_agent_stack_push(env, tmp1); + } + tcg_temp_free(tmp1); + } + break; + case BYTECODE_POP: /*0x29*/ + decrement_stack_ptr(env); + break; + case BYTECODE_SWAP: /*0x2b*/ + { + TCGv tmp1 = tcg_temp_new(); + TCGv tmp2 = tcg_temp_new(); + ret = bp_agent_stack_pop(env, tmp1); + if (ret) { + ret = bp_agent_stack_pop(env, tmp2); + } + if (ret) { + ret = bp_agent_stack_push(env, tmp1); + } + if (ret) { + ret = bp_agent_stack_push(env, tmp2); + } + tcg_temp_free(tmp1); + tcg_temp_free(tmp2); + } + break; + case BYTECODE_REF8: /*0x17*/ + case BYTECODE_REF16: /*0x18*/ + case BYTECODE_REF64: /*0x1a*/ + case BYTECODE_REF32: /*0x19*/ + { + TCGv tmp1 = tcg_temp_new(); + TCGv tmp2 = tcg_temp_new(); + ret = bp_agent_stack_pop(env, tmp1); + if (ret) { + switch (command_type) { + case BYTECODE_REF8: /*0x17*/ + tcg_gen_qemu_ld8u(tmp2, tmp1, 0); + break; + case BYTECODE_REF16: /*0x18*/ + tcg_gen_qemu_ld16u(tmp2, tmp1, 0); + break; + case BYTECODE_REF64: /*0x1a*/ +#if TARGET_LONG_SIZE == 8 + tcg_gen_qemu_ld64(tmp2, tmp1, 0); +#else + tcg_gen_qemu_ld32u(tmp2, tmp1, 0); +#endif + break; + case BYTECODE_REF32: /*0x19*/ + tcg_gen_qemu_ld32u(tmp2, tmp1, 0); + break; + default: + break; + } + } + if (ret) { + ret = bp_agent_stack_push(env, tmp2); + } + tcg_temp_free(tmp1); + tcg_temp_free(tmp2); + } + break; + case BYTECODE_IF_GOTO: /*0x20*/ + { + TCGv tmp1 = tcg_temp_new(); + val = bp_agent_get_arg(cond_exp, &i, 2); + ret = bp_agent_stack_pop(env, tmp1); + if (ret) { + tcg_gen_brcondi_tl(TCG_COND_NE, tmp1, 0, label_tab[val]); + } + tcg_temp_free(tmp1); + } + break; + case BYTECODE_GOTO: /*0x21*/ + val = bp_agent_get_arg(cond_exp, &i, 2); + tcg_gen_br(label_tab[val]); + break; + case BYTECODE_CONST8: /*0x22*/ + val = bp_agent_get_arg(cond_exp, &i, 1); + ret = bp_agent_stack_push_const(env, val); + break; + case BYTECODE_CONST16: /*0x23*/ + val = bp_agent_get_arg(cond_exp, &i, 2) ; + ret = bp_agent_stack_push_const(env, val); + break; + case BYTECODE_CONST64: /*0x25*/ + val = bp_agent_get_arg(cond_exp, &i, 8); +#if TARGET_LONG_SIZE == 8 + ret = bp_agent_stack_push_const(env, val); +#endif + break; + case BYTECODE_CONST32: /*0x24*/ + val = bp_agent_get_arg(cond_exp, &i, 4); + ret = bp_agent_stack_push_const(env, val); + break; + case BYTECODE_REG: /*0x26*/ + { + TCGv tmp1 = tcg_temp_new(); + val = bp_agent_get_arg(cond_exp, &i, 2) ; + cpu_get_reg_var_func(tmp1, val); + ret = bp_agent_stack_push(env, tmp1); + tcg_temp_free(tmp1); + } + break; + case BYTECODE_LOG_NOT:/*0x0e*/ + { + TCGv tmp1 = tcg_temp_new(); + TCGv tmp = tcg_temp_local_new(); + + ret = bp_agent_stack_pop(env, tmp1); + if (!ret) { + tcg_temp_free(tmp1); + tcg_temp_free(tmp); + break; + } + tcg_gen_setcondi_tl(TCG_COND_EQ, tmp, tmp1, 0); + + ret = bp_agent_stack_push(env, tmp); + tcg_temp_free(tmp1); + tcg_temp_free(tmp); + } + break; + case BYTECODE_BIT_NOT: /*0x12*/ + { + TCGv tmp1 = tcg_temp_new(); + ret = bp_agent_stack_pop(env, tmp1); + if (ret) { + tcg_gen_not_tl(tmp1, tmp1); + ret = bp_agent_stack_push(env, tmp1); + } + tcg_temp_free(tmp1); + } + break; + case BYTECODE_EXT: /*0x16*/ + case BYTECODE_ZERO_EXT: /*0x2a*/ + val = bp_agent_get_arg(cond_exp, &i, 1) ; + if (val != 8 && val != 16 && val != 32) { + fprintf(stderr, + "\n GDB agent: non-aligned bit extension is not supported."); + } else { + TCGv tmp = tcg_temp_new(); + ret = bp_agent_stack_pop(env, tmp); + if (!ret) { + tcg_temp_free(tmp); + break; + } + switch (val) { + case 8: + if (command_type == BYTECODE_EXT) { + tcg_gen_ext8s_tl(tmp, tmp); + } else { + tcg_gen_ext8u_tl(tmp, tmp); + } + break; + case 16: + if (command_type == BYTECODE_EXT) { + tcg_gen_ext16s_tl(tmp, tmp); + } else { + tcg_gen_ext16u_tl(tmp, tmp); + } + break; + case 32: + if (command_type == BYTECODE_EXT) { + tcg_gen_ext32s_tl(tmp, tmp); + } else { + tcg_gen_ext32u_tl(tmp, tmp); + } + break; + } + ret = bp_agent_stack_push(env, tmp); + tcg_temp_free(tmp); + } + break; + case BYTECODE_SUB: /*0x03*/ + case BYTECODE_ADD: /*0x02*/ + case BYTECODE_MUL: /*0x04*/ + case BYTECODE_DIV_SIGNED: /*0x05*/ + case BYTECODE_REM_SIGNED: /*0x07*/ + case BYTECODE_REM_UNSIGNED: /*0x08*/ + case BYTECODE_BIT_AND: /*0x0f*/ + case BYTECODE_BIT_OR: /*0x10*/ + case BYTECODE_BIT_XOR: /*0x11*/ + case BYTECODE_LSH: /*0x09*/ + case BYTECODE_RSH_SIGNED: /*0x0a*/ + case BYTECODE_RSH_UNSIGNED: /*0x0b*/ + { + int is_divide_command = + (command_type == BYTECODE_DIV_SIGNED || + command_type == BYTECODE_DIV_UNSIGNED || + command_type == BYTECODE_REM_SIGNED || + command_type == BYTECODE_REM_UNSIGNED); + int my_div_label1 = -1; + int my_div_label2 = -1; + TCGv tmp1 = (is_divide_command ? + tcg_temp_local_new() : tcg_temp_new()); + TCGv tmp2 = (is_divide_command ? + tcg_temp_local_new() : tcg_temp_new()); + ret = bp_agent_stack_pop(env, tmp1); + if (!ret) { + tcg_temp_free(tmp1); + tcg_temp_free(tmp2); + break; + } + if (is_divide_command) { /* check for divide by zero*/ + my_div_label1 = gen_new_label(); + my_div_label2 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_NE, tmp1, 0, + my_div_label1); + tcg_gen_movi_tl(bp_agent_error_tcg , 1); + tcg_gen_br(my_div_label2); + gen_set_label(my_div_label1); + } + ret = bp_agent_stack_pop(env, tmp2); + if (!ret) { + tcg_temp_free(tmp1); + tcg_temp_free(tmp2); + break; + } + switch (command_type) { + case BYTECODE_ADD: + tcg_gen_add_tl(tmp2, tmp2, tmp1); + break; + case BYTECODE_SUB: + tcg_gen_sub_tl(tmp2, tmp2, tmp1); + break; + case BYTECODE_MUL: + tcg_gen_mul_tl(tmp2, tmp2, tmp1); + break; + case BYTECODE_DIV_SIGNED: + tcg_gen_div_tl(tmp2, tmp2, tmp1); + break; + case BYTECODE_DIV_UNSIGNED: + tcg_gen_divu_tl(tmp2, tmp2, tmp1); + break; + case BYTECODE_REM_SIGNED: + tcg_gen_rem_tl(tmp2, tmp2, tmp1); + break; + case BYTECODE_REM_UNSIGNED: + tcg_gen_remu_tl(tmp2, tmp2, tmp1); + break; + case BYTECODE_BIT_AND: + tcg_gen_and_tl(tmp2, tmp2, tmp1); + break; + case BYTECODE_BIT_OR: + tcg_gen_or_tl(tmp2, tmp2, tmp1); + break; + case BYTECODE_BIT_XOR: + tcg_gen_xor_tl(tmp2, tmp2, tmp1); + break; + case BYTECODE_LSH: + tcg_gen_shl_tl(tmp2, tmp2, tmp1); + break; + case BYTECODE_RSH_SIGNED: + tcg_gen_sar_tl(tmp2, tmp2, tmp1); + break; + case BYTECODE_RSH_UNSIGNED: + tcg_gen_shr_tl(tmp2, tmp2, tmp1); + break; + default: + break; + } + ret = bp_agent_stack_push(env, tmp2); + if (is_divide_command) { + gen_set_label(my_div_label2); + } + tcg_temp_free(tmp1); + tcg_temp_free(tmp2); + } + break; + case BYTECODE_EQUAL: /*0x13*/ + case BYTECODE_LESS_UNSIGNED: /*0x15*/ + case BYTECODE_LESS_SIGNED: /*0x14*/ + { + TCGv tmp1 = tcg_temp_new(); + TCGv tmp2 = tcg_temp_new(); + TCGv tmp = tcg_temp_local_new(); + + ret = bp_agent_stack_pop(env, tmp1); + if (!ret) { + tcg_temp_free(tmp1); + tcg_temp_free(tmp2); + tcg_temp_free(tmp); + break; + } + ret = bp_agent_stack_pop(env, tmp2); + if (!ret) { + tcg_temp_free(tmp1); + tcg_temp_free(tmp2); + tcg_temp_free(tmp); + break; + } + TCGCond cond ; + switch (command_type) { + case BYTECODE_EQUAL: + cond = TCG_COND_EQ; + break; + case BYTECODE_LESS_UNSIGNED: + cond = TCG_COND_LTU; + break; + case BYTECODE_LESS_SIGNED: + cond = TCG_COND_LT; + break; + default: + break; + } + tcg_gen_setcond_tl(cond, tmp, tmp, tmp1); + ret = bp_agent_stack_push(env, tmp); + + tcg_temp_free(tmp1); + tcg_temp_free(tmp2); + tcg_temp_free(tmp); + } + break; + default: + break; + } + } + /*for case error , ex.buffer overloading - + need to set labels anyway in order to avoid segmentation fault */ + while (i < cond_len && labels_num > 0) { + if (label_tab[i] != -1) { + gen_set_label(label_tab[i]); + labels_num--; + } + i++; + } + g_free(label_tab); + return ret; +} + +#define MSG_PRFX "qemu note: " +#define GDB_AG_TRANS "GDB agent expression translation" +#define COND_EXP "Conditional expression" +#define NOT_SUPPORT "is not supported" + +#define ERR_OS "%s%s target evaluation %s for the current platform.\n" +#define ERR_BIG "%sError in %s: %s is too big and will be evaluated on host.\n" +#define ERR_INTERN "%sInternal error in %s - %s will be evaluated on host.\n" + +int tcg_gen_bp_cond(CPUArchState *env, + TCGContext *s, + CPUBreakpoint *bp, + int condlabel) +/* returns 1 if OK, 0 in case error */ +{ + int res = 1; + if (!bp_has_cond(bp)) { + return 0; + } + if (cpu_get_reg_var_func == NULL) { + fprintf(stderr, ERR_OS, MSG_PRFX, COND_EXP, NOT_SUPPORT); + return 0; + } + if (bp->cond_len > BP_AGENT_MAX_COND_SIZE) { + fprintf(stderr, ERR_BIG, MSG_PRFX, GDB_AG_TRANS, COND_EXP); + return 0; + } + bp_agent_init_local(env, bp->cond_len); + res = bp_agent_tcg_gen(env, s, bp->cond_len, bp->cond_exp); + if (!res || !check_max_instr_num(s, 0)) { + if (!check_max_instr_num(s, 0)) { + fprintf(stderr, ERR_BIG, MSG_PRFX, GDB_AG_TRANS, COND_EXP); + } else { + fprintf(stderr, ERR_INTERN, MSG_PRFX, GDB_AG_TRANS, COND_EXP); + } + return 0; + } else { + bp_agent_brcond_top(env, condlabel); + return 1; + } +} + +#else +int tcg_gen_bp_cond(CPUArchState *env, + TCGContext *s, + CPUBreakpoint *bp, + int condlabel) +{ + return 1; +} +void bp_agent_init(void) +{ +} +#endif +int bp_has_cond(CPUBreakpoint *bp) +{ + return (bp != NULL && bp->cond_exp != NULL && bp->cond_len != 0); +} diff --git a/translate-gdbagent.h b/translate-gdbagent.h new file mode 100644 index 0000000..de1f7fc --- /dev/null +++ b/translate-gdbagent.h @@ -0,0 +1,49 @@ + +/* + * Translation GDB bytecode to TCG. + * Used for evaluation breakpoint condition on host. + * + * Copyright (c) 2013 Anna Neiman + * Copyright (c) 2012 Mentor Graphics Corp. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __TRANSLATE_GDBAGENT_H__ +#define __TRANSLATE_GDBAGENT_H__ + +#include "tcg-op.h" + +struct TCGContext; +int tcg_gen_bp_cond(CPUArchState *env, + struct TCGContext *s, + CPUBreakpoint *bp, + int condlabel); + +extern void cpu_get_reg_var(TCGv var, int reg); + +void bp_agent_dump_bytecode(int cond_len, const uint8_t *cond_exp); + +void bp_agent_init(void); + +#if defined(TARGET_ARM) +extern void cpu_get_reg_var_arm(TCGv var, int reg); +#endif + +#endif