diff --git a/cpu-all.h b/cpu-all.h index d61ad77341..787a054a48 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -313,9 +313,12 @@ extern CPUState *cpu_single_env; #define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */ void cpu_interrupt(CPUState *s, int mask); +int cpu_breakpoint_insert(CPUState *env, uint32_t pc); +int cpu_breakpoint_remove(CPUState *env, uint32_t pc); + /* gdb stub API */ extern int gdbstub_fd; CPUState *cpu_gdbstub_get_env(void *opaque); -int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port); +int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port); #endif /* CPU_ALL_H */ diff --git a/cpu-exec.c b/cpu-exec.c index ef33aaa3e0..908f161840 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -280,7 +280,7 @@ int cpu_exec(CPUState *env1) tb->tc_ptr = tc_ptr; tb->cs_base = (unsigned long)cs_base; tb->flags = flags; - ret = cpu_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size); + ret = cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size); #if defined(TARGET_I386) /* XXX: suppress that, this is incorrect */ /* if invalid instruction, signal it */ diff --git a/cpu-i386.h b/cpu-i386.h index e6318fb7f2..82cdffc25e 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -155,6 +155,9 @@ #define EXCP_INTERRUPT 256 /* async interruption */ #define EXCP_HLT 257 /* hlt instruction reached */ +#define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */ + +#define MAX_BREAKPOINTS 32 enum { CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ @@ -270,6 +273,9 @@ typedef struct CPUX86State { uint32_t dr[8]; /* debug registers */ int interrupt_request; int user_mode_only; /* user mode only simulation */ + + uint32_t breakpoints[MAX_BREAKPOINTS]; + int nb_breakpoints; /* user data */ void *opaque; diff --git a/exec.c b/exec.c index e7f5081d0b..fc0a0cf7af 100644 --- a/exec.c +++ b/exec.c @@ -617,6 +617,48 @@ static void tb_reset_jump_recursive(TranslationBlock *tb) tb_reset_jump_recursive2(tb, 1); } +/* add a breakpoint */ +int cpu_breakpoint_insert(CPUState *env, uint32_t pc) +{ +#if defined(TARGET_I386) + int i; + + for(i = 0; i < env->nb_breakpoints; i++) { + if (env->breakpoints[i] == pc) + return 0; + } + + if (env->nb_breakpoints >= MAX_BREAKPOINTS) + return -1; + env->breakpoints[env->nb_breakpoints++] = pc; + tb_invalidate_page(pc); + return 0; +#else + return -1; +#endif +} + +/* remove a breakpoint */ +int cpu_breakpoint_remove(CPUState *env, uint32_t pc) +{ +#if defined(TARGET_I386) + int i; + for(i = 0; i < env->nb_breakpoints; i++) { + if (env->breakpoints[i] == pc) + goto found; + } + return -1; + found: + memmove(&env->breakpoints[i], &env->breakpoints[i + 1], + (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0])); + env->nb_breakpoints--; + tb_invalidate_page(pc); + return 0; +#else + return -1; +#endif +} + /* mask must never be zero */ void cpu_interrupt(CPUState *env, int mask) { diff --git a/exec.h b/exec.h index 5ae28ef9b1..9489c47773 100644 --- a/exec.h +++ b/exec.h @@ -58,10 +58,10 @@ extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; extern FILE *logfile; extern int loglevel; -int gen_intermediate_code(struct TranslationBlock *tb); -int gen_intermediate_code_pc(struct TranslationBlock *tb); +int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb); +int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb); void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf); -int cpu_gen_code(struct TranslationBlock *tb, +int cpu_gen_code(CPUState *env, struct TranslationBlock *tb, int max_code_size, int *gen_code_size_ptr); int cpu_restore_state(struct TranslationBlock *tb, CPUState *env, unsigned long searched_pc); diff --git a/gdbstub.c b/gdbstub.c index 2d1f4784a5..5fce5d8831 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -37,7 +37,7 @@ #include "thunk.h" #include "exec.h" -//#define DEBUG_GDB +#define DEBUG_GDB int gdbstub_fd = -1; @@ -283,11 +283,11 @@ static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write) } /* port = 0 means default port */ -int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port) +int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) { CPUState *env; const char *p; - int ret, ch, nb_regs, i; + int ret, ch, nb_regs, i, type; char buf[4096]; uint8_t mem_buf[2000]; uint32_t *registers; @@ -309,8 +309,19 @@ int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port) put_packet(buf); break; case 'c': - main_loop(opaque); - snprintf(buf, sizeof(buf), "S%02x", 0); + if (*p != '\0') { + addr = strtoul(p, (char **)&p, 16); + env = cpu_gdbstub_get_env(opaque); +#if defined(TARGET_I386) + env->eip = addr; +#endif + } + ret = main_loop(opaque); + if (ret == EXCP_DEBUG) + ret = SIGTRAP; + else + ret = 0; + snprintf(buf, sizeof(buf), "S%02x", ret); put_packet(buf); break; case 'g': @@ -379,6 +390,40 @@ int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port) else put_packet("OK"); break; + case 'Z': + type = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + addr = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + len = strtoul(p, (char **)&p, 16); + if (type == 0 || type == 1) { + env = cpu_gdbstub_get_env(opaque); + if (cpu_breakpoint_insert(env, addr) < 0) + goto breakpoint_error; + put_packet("OK"); + } else { + breakpoint_error: + put_packet("ENN"); + } + break; + case 'z': + type = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + addr = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + len = strtoul(p, (char **)&p, 16); + if (type == 0 || type == 1) { + env = cpu_gdbstub_get_env(opaque); + cpu_breakpoint_remove(env, addr); + put_packet("OK"); + } else { + goto breakpoint_error; + } + break; default: /* put empty packet */ buf[0] = '\0'; diff --git a/op-i386.c b/op-i386.c index be8b5a113d..661d45bf44 100644 --- a/op-i386.c +++ b/op-i386.c @@ -471,6 +471,12 @@ void OPPROTO op_hlt(void) cpu_loop_exit(); } +void OPPROTO op_debug(void) +{ + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(); +} + void OPPROTO op_raise_interrupt(void) { int intno; diff --git a/translate-arm.c b/translate-arm.c index c9759f81b7..bc8be855fb 100644 --- a/translate-arm.c +++ b/translate-arm.c @@ -786,7 +786,9 @@ static void disas_arm_insn(DisasContext *s) /* generate intermediate code in gen_opc_buf and gen_opparam_buf for basic block 'tb'. If search_pc is TRUE, also generate PC information for each intermediate instruction. */ -static inline int gen_intermediate_code_internal(TranslationBlock *tb, int search_pc) +static inline int gen_intermediate_code_internal(CPUState *env, + TranslationBlock *tb, + int search_pc) { DisasContext dc1, *dc = &dc1; uint16_t *gen_opc_end; @@ -853,14 +855,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc return 0; } -int gen_intermediate_code(TranslationBlock *tb) +int gen_intermediate_code(CPUState *env, TranslationBlock *tb) { - return gen_intermediate_code_internal(tb, 0); + return gen_intermediate_code_internal(env, tb, 0); } -int gen_intermediate_code_pc(TranslationBlock *tb) +int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) { - return gen_intermediate_code_internal(tb, 1); + return gen_intermediate_code_internal(env, tb, 1); } CPUARMState *cpu_arm_init(void) diff --git a/translate-i386.c b/translate-i386.c index 871d997414..1c051f9956 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -1463,6 +1463,15 @@ static void gen_interrupt(DisasContext *s, int intno, s->is_jmp = 1; } +static void gen_debug(DisasContext *s, unsigned int cur_eip) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(cur_eip); + gen_op_debug(); + s->is_jmp = 1; +} + /* generate a jump to eip. No segment change must happen before as a direct call to the next block may occur */ static void gen_jmp(DisasContext *s, unsigned int eip) @@ -4080,7 +4089,9 @@ static void optimize_flags(uint16_t *opc_buf, int opc_buf_len) /* generate intermediate code in gen_opc_buf and gen_opparam_buf for basic block 'tb'. If search_pc is TRUE, also generate PC information for each intermediate instruction. */ -static inline int gen_intermediate_code_internal(TranslationBlock *tb, int search_pc) +static inline int gen_intermediate_code_internal(CPUState *env, + TranslationBlock *tb, + int search_pc) { DisasContext dc1, *dc = &dc1; uint8_t *pc_ptr; @@ -4116,6 +4127,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc pc_ptr = pc_start; lj = -1; do { + if (env->nb_breakpoints > 0) { + for(j = 0; j < env->nb_breakpoints; j++) { + if (env->breakpoints[j] == (unsigned long)pc_ptr) { + gen_debug(dc, pc_ptr - dc->cs_base); + goto the_end; + } + } + } if (search_pc) { j = gen_opc_ptr - gen_opc_buf; if (lj < j) { @@ -4160,6 +4179,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc if (dc->tf) { gen_op_raise_exception(EXCP01_SSTP); } + the_end: if (dc->is_jmp != DISAS_TB_JUMP) { /* indicate that the hash table must be used to find the next TB */ gen_op_movl_T0_0(); @@ -4202,14 +4222,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc return 0; } -int gen_intermediate_code(TranslationBlock *tb) +int gen_intermediate_code(CPUState *env, TranslationBlock *tb) { - return gen_intermediate_code_internal(tb, 0); + return gen_intermediate_code_internal(env, tb, 0); } -int gen_intermediate_code_pc(TranslationBlock *tb) +int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) { - return gen_intermediate_code_internal(tb, 1); + return gen_intermediate_code_internal(env, tb, 1); } CPUX86State *cpu_x86_init(void) diff --git a/translate.c b/translate.c index 68c76224a3..e9055c0dd1 100644 --- a/translate.c +++ b/translate.c @@ -107,13 +107,13 @@ void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) '*gen_code_size_ptr' contains the size of the generated code (host code). */ -int cpu_gen_code(TranslationBlock *tb, +int cpu_gen_code(CPUState *env, TranslationBlock *tb, int max_code_size, int *gen_code_size_ptr) { uint8_t *gen_code_buf; int gen_code_size; - if (gen_intermediate_code(tb) < 0) + if (gen_intermediate_code(env, tb) < 0) return -1; /* generate machine code */ @@ -154,7 +154,7 @@ int cpu_restore_state(TranslationBlock *tb, unsigned long tc_ptr; uint16_t *opc_ptr; - if (gen_intermediate_code_pc(tb) < 0) + if (gen_intermediate_code_pc(env, tb) < 0) return -1; /* find opc index corresponding to search_pc */ diff --git a/vl.c b/vl.c index bb15ac4a91..9f76ac0044 100644 --- a/vl.c +++ b/vl.c @@ -2540,7 +2540,7 @@ CPUState *cpu_gdbstub_get_env(void *opaque) return global_env; } -void main_loop(void *opaque) +int main_loop(void *opaque) { struct pollfd ufds[2], *pf, *serial_ufd, *net_ufd, *gdb_ufd; int ret, n, timeout; @@ -2552,7 +2552,8 @@ void main_loop(void *opaque) ret = cpu_x86_exec(env); if (reset_requested) break; - + if (ret == EXCP_DEBUG) + return EXCP_DEBUG; /* if hlt instruction, we wait until the next IRQ */ if (ret == EXCP_HLT) timeout = 10; @@ -2618,6 +2619,7 @@ void main_loop(void *opaque) timer_irq_pending = 0; } } + return EXCP_INTERRUPT; } void help(void)