gdb stub breakpoints support
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 26 Jul 2003 12:06:08 +0000 (12:06 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 26 Jul 2003 12:06:08 +0000 (12:06 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@332 c046a42c-6fe2-441c-8c8c-71466251a162

cpu-all.h
cpu-exec.c
cpu-i386.h
exec.c
exec.h
gdbstub.c
op-i386.c
translate-arm.c
translate-i386.c
translate.c
vl.c

index d61ad77..787a054 100644 (file)
--- 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 */
index ef33aaa..908f161 100644 (file)
@@ -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 */
index e6318fb..82cdffc 100644 (file)
 
 #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 e7f5081..fc0a0cf 100644 (file)
--- 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 5ae28ef..9489c47 100644 (file)
--- 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);
index 2d1f478..5fce5d8 100644 (file)
--- 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';
index be8b5a1..661d45b 100644 (file)
--- 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;
index c9759f8..bc8be85 100644 (file)
@@ -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)
index 871d997..1c051f9 100644 (file)
@@ -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)
index 68c7622..e9055c0 100644 (file)
@@ -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 bb15ac4..9f76ac0 100644 (file)
--- 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)