aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-07-26 12:06:08 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-07-26 12:06:08 +0000
commit4c3a88a284b288e0ed3c097de7fc07111d848003 (patch)
tree8f4a8190c97d326f26b4e7d603ac8f98c50e8706
parentd6b4936796b37f629879de69d847c5cdc4892157 (diff)
gdb stub breakpoints support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@332 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r--cpu-all.h5
-rw-r--r--cpu-exec.c2
-rw-r--r--cpu-i386.h6
-rw-r--r--exec.c42
-rw-r--r--exec.h6
-rw-r--r--gdbstub.c55
-rw-r--r--op-i386.c6
-rw-r--r--translate-arm.c12
-rw-r--r--translate-i386.c30
-rw-r--r--translate.c6
-rw-r--r--vl.c6
11 files changed, 151 insertions, 25 deletions
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)