#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 */
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 */
#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 */
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;
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)
{
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);
#include "thunk.h"
#include "exec.h"
-//#define DEBUG_GDB
+#define DEBUG_GDB
int gdbstub_fd = -1;
}
/* 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;
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':
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';
cpu_loop_exit();
}
+void OPPROTO op_debug(void)
+{
+ env->exception_index = EXCP_DEBUG;
+ cpu_loop_exit();
+}
+
void OPPROTO op_raise_interrupt(void)
{
int intno;
/* 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;
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)
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)
/* 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;
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) {
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();
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)
'*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 */
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 */
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;
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;
timer_irq_pending = 0;
}
}
+ return EXCP_INTERRUPT;
}
void help(void)