From patchwork Tue Feb 26 13:51:56 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anna Neiman X-Patchwork-Id: 223223 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 2F59B2C02AD for ; Wed, 27 Feb 2013 00:52:27 +1100 (EST) Received: from localhost ([::1]:48560 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UAKxF-0002v8-Bb for incoming@patchwork.ozlabs.org; Tue, 26 Feb 2013 08:52:25 -0500 Received: from eggs.gnu.org ([208.118.235.92]:56859) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UAKwq-0002tT-AH for qemu-devel@nongnu.org; Tue, 26 Feb 2013 08:52:10 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UAKwk-0006UN-0C for qemu-devel@nongnu.org; Tue, 26 Feb 2013 08:52:00 -0500 Received: from relay1.mentorg.com ([192.94.38.131]:44370) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UAKwj-0006UA-J3 for qemu-devel@nongnu.org; Tue, 26 Feb 2013 08:51:53 -0500 Received: from svr-orw-exc-10.mgc.mentorg.com ([147.34.98.58]) by relay1.mentorg.com with esmtp id 1UAKwi-0001dQ-Sn from Anna_Neiman@mentor.com ; Tue, 26 Feb 2013 05:51:52 -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); Tue, 26 Feb 2013 05:51:52 -0800 From: Anna Neiman To: qemu-devel@nongnu.org Date: Tue, 26 Feb 2013 15:51:56 +0200 Message-Id: <1361886716-10965-1-git-send-email-anna_neiman@mentor.com> X-Mailer: git-send-email 1.7.9.5 X-OriginalArrivalTime: 26 Feb 2013 13:51:52.0850 (UTC) FILETIME=[6EAE7F20:01CE1428] 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 , Paul Brook , Amir Schreiber , Anna Neiman , Alex Rozenman Subject: [Qemu-devel] [PATCH] PATCH2 - evaluate breakpoint condition on target - functionality core ( without usage yet ) - translate gdb bytecode to TCG code for add to the translation block 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 +- translate-gdbagent.c | 919 ++++++++++++++++++++++++++++++++++++++++++++++++++ translate-gdbagent.h | 55 +++ 3 files changed, 975 insertions(+), 1 deletion(-) create mode 100644 translate-gdbagent.c create mode 100644 translate-gdbagent.h diff --git a/Makefile.target b/Makefile.target index ca657b3..e2df631 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/translate-gdbagent.c b/translate-gdbagent.c new file mode 100644 index 0000000..d959a47 --- /dev/null +++ b/translate-gdbagent.c @@ -0,0 +1,919 @@ +/* + * 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" +#include "qemu/error-report.h" + +#if defined(TARGET_HAS_ICE) + +static TCGv_ptr bp_agent_stack_current_tcg ; +static TCGv bp_agent_error_tcg ; + + +/* functions for retrieve register contents - platform depend +should be initialized inside gen_intermediate_code_internal +for each supported platform*/ +CPUGetRegVarFuncType cpu_get_reg_var_func; +CPUSetVarToEnvPtrFuncType cpu_set_var_to_env_ptr_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"); + bp_agent_error_tcg = + tcg_global_mem_new(TCG_AREG0, + offsetof(CPUArchState, bp_agent_error), + "bp_agent_error"); + } +} +static void bp_agent_init_local(CPUArchState *env, int len) +{ + if (len > BP_AGENT_MAX_STACK_SIZE) { + fprintf(stderr, + "GDB agent: Condition length more then %d is unsupported.\n", + BP_AGENT_MAX_STACK_SIZE); + } + + cpu_set_var_to_env_ptr_func ( bp_agent_stack_current_tcg, offsetof(CPUArchState, bp_agent_stack)); +} + +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); + + /* 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++; + bswap32(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: /* shouldn't occur*/ + { + 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*/ + { + val = bp_agent_get_arg(cond_exp, &i, 2) ; + if ( val < 0 || val >= 15 ) { + ret = 0; + } else { + TCGv tmp1 = tcg_temp_new(); + 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, tmp2, 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. + For example, it can be situation when goto operator + to the label "x" was generated, + but the error occured before generation label "x" itself*/ + 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 || cpu_set_var_to_env_ptr_func == NULL) { + error_report(ERR_OS, MSG_PRFX, COND_EXP, NOT_SUPPORT); + return 0; + } + if (bp->cond_len > BP_AGENT_MAX_STACK_SIZE) { + error_report(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)) { + error_report(ERR_BIG, MSG_PRFX, GDB_AG_TRANS, COND_EXP); + } else { + error_report(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..76db4d2 --- /dev/null +++ b/translate-gdbagent.h @@ -0,0 +1,55 @@ + +/* + * 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); + +typedef void(*CPUGetRegVarFuncType)(TCGv var, int reg); +typedef void(*CPUSetVarToEnvPtrFuncType) + (TCGv_ptr var_ptr, int offset); + +/* functions for retrieve register contents - platform depend +should be initialized inside gen_intermediate_code_internal +for each supported platform*/ +extern CPUGetRegVarFuncType cpu_get_reg_var_func; +extern CPUSetVarToEnvPtrFuncType cpu_set_var_to_env_ptr_func; + +#endif