@@ -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
@@ -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(;;) */
@@ -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,
@@ -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
@@ -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);
@@ -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
@@ -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
@@ -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;
@@ -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;
}
}
@@ -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;
@@ -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;
@@ -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];
@@ -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;
@@ -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];
@@ -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;
@@ -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;
@@ -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;
@@ -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 */
@@ -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"
@@ -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;
@@ -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;
@@ -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. */
@@ -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];
@@ -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__ */
@@ -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__*/
@@ -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. */
@@ -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 */
new file mode 100644
@@ -0,0 +1,922 @@
+/*
+ * Translation GDB bytecode to TCG.
+ * Used for evaluation breakpoint condition on host.
+ *
+ * Copyright (c) 2013 Anna Neiman <anna_neiman@mentor.com>
+ * 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 <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#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);
+}
new file mode 100644
@@ -0,0 +1,49 @@
+
+/*
+ * Translation GDB bytecode to TCG.
+ * Used for evaluation breakpoint condition on host.
+ *
+ * Copyright (c) 2013 Anna Neiman <anna_neiman@mentor.com>
+ * 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
Signed-off-by: Anna Neiman <anna_neiman@mentor.com> --- 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