gdb stub breakpoints support

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@332 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2003-07-26 12:06:08 +00:00
parent d6b4936796
commit 4c3a88a284
11 changed files with 151 additions and 25 deletions

View File

@ -313,9 +313,12 @@ extern CPUState *cpu_single_env;
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */ #define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
void cpu_interrupt(CPUState *s, int mask); 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 */ /* gdb stub API */
extern int gdbstub_fd; extern int gdbstub_fd;
CPUState *cpu_gdbstub_get_env(void *opaque); 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 */ #endif /* CPU_ALL_H */

View File

@ -280,7 +280,7 @@ int cpu_exec(CPUState *env1)
tb->tc_ptr = tc_ptr; tb->tc_ptr = tc_ptr;
tb->cs_base = (unsigned long)cs_base; tb->cs_base = (unsigned long)cs_base;
tb->flags = flags; 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) #if defined(TARGET_I386)
/* XXX: suppress that, this is incorrect */ /* XXX: suppress that, this is incorrect */
/* if invalid instruction, signal it */ /* if invalid instruction, signal it */

View File

@ -155,6 +155,9 @@
#define EXCP_INTERRUPT 256 /* async interruption */ #define EXCP_INTERRUPT 256 /* async interruption */
#define EXCP_HLT 257 /* hlt instruction reached */ #define EXCP_HLT 257 /* hlt instruction reached */
#define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */
#define MAX_BREAKPOINTS 32
enum { enum {
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
@ -271,6 +274,9 @@ typedef struct CPUX86State {
int interrupt_request; int interrupt_request;
int user_mode_only; /* user mode only simulation */ int user_mode_only; /* user mode only simulation */
uint32_t breakpoints[MAX_BREAKPOINTS];
int nb_breakpoints;
/* user data */ /* user data */
void *opaque; void *opaque;
} CPUX86State; } CPUX86State;

42
exec.c
View File

@ -617,6 +617,48 @@ static void tb_reset_jump_recursive(TranslationBlock *tb)
tb_reset_jump_recursive2(tb, 1); 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 */ /* mask must never be zero */
void cpu_interrupt(CPUState *env, int mask) void cpu_interrupt(CPUState *env, int mask)
{ {

6
exec.h
View File

@ -58,10 +58,10 @@ extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
extern FILE *logfile; extern FILE *logfile;
extern int loglevel; extern int loglevel;
int gen_intermediate_code(struct TranslationBlock *tb); int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
int gen_intermediate_code_pc(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); 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 max_code_size, int *gen_code_size_ptr);
int cpu_restore_state(struct TranslationBlock *tb, int cpu_restore_state(struct TranslationBlock *tb,
CPUState *env, unsigned long searched_pc); CPUState *env, unsigned long searched_pc);

View File

@ -37,7 +37,7 @@
#include "thunk.h" #include "thunk.h"
#include "exec.h" #include "exec.h"
//#define DEBUG_GDB #define DEBUG_GDB
int gdbstub_fd = -1; 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 */ /* 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; CPUState *env;
const char *p; const char *p;
int ret, ch, nb_regs, i; int ret, ch, nb_regs, i, type;
char buf[4096]; char buf[4096];
uint8_t mem_buf[2000]; uint8_t mem_buf[2000];
uint32_t *registers; uint32_t *registers;
@ -309,8 +309,19 @@ int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port)
put_packet(buf); put_packet(buf);
break; break;
case 'c': case 'c':
main_loop(opaque); if (*p != '\0') {
snprintf(buf, sizeof(buf), "S%02x", 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); put_packet(buf);
break; break;
case 'g': case 'g':
@ -379,6 +390,40 @@ int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port)
else else
put_packet("OK"); put_packet("OK");
break; 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: default:
/* put empty packet */ /* put empty packet */
buf[0] = '\0'; buf[0] = '\0';

View File

@ -471,6 +471,12 @@ void OPPROTO op_hlt(void)
cpu_loop_exit(); cpu_loop_exit();
} }
void OPPROTO op_debug(void)
{
env->exception_index = EXCP_DEBUG;
cpu_loop_exit();
}
void OPPROTO op_raise_interrupt(void) void OPPROTO op_raise_interrupt(void)
{ {
int intno; int intno;

View File

@ -786,7 +786,9 @@ static void disas_arm_insn(DisasContext *s)
/* generate intermediate code in gen_opc_buf and gen_opparam_buf for /* generate intermediate code in gen_opc_buf and gen_opparam_buf for
basic block 'tb'. If search_pc is TRUE, also generate PC basic block 'tb'. If search_pc is TRUE, also generate PC
information for each intermediate instruction. */ 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; DisasContext dc1, *dc = &dc1;
uint16_t *gen_opc_end; uint16_t *gen_opc_end;
@ -853,14 +855,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc
return 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);
} }
CPUARMState *cpu_arm_init(void) CPUARMState *cpu_arm_init(void)

View File

@ -1463,6 +1463,15 @@ static void gen_interrupt(DisasContext *s, int intno,
s->is_jmp = 1; 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 /* generate a jump to eip. No segment change must happen before as a
direct call to the next block may occur */ direct call to the next block may occur */
static void gen_jmp(DisasContext *s, unsigned int eip) 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 /* generate intermediate code in gen_opc_buf and gen_opparam_buf for
basic block 'tb'. If search_pc is TRUE, also generate PC basic block 'tb'. If search_pc is TRUE, also generate PC
information for each intermediate instruction. */ 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; DisasContext dc1, *dc = &dc1;
uint8_t *pc_ptr; uint8_t *pc_ptr;
@ -4116,6 +4127,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc
pc_ptr = pc_start; pc_ptr = pc_start;
lj = -1; lj = -1;
do { 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) { if (search_pc) {
j = gen_opc_ptr - gen_opc_buf; j = gen_opc_ptr - gen_opc_buf;
if (lj < j) { if (lj < j) {
@ -4160,6 +4179,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc
if (dc->tf) { if (dc->tf) {
gen_op_raise_exception(EXCP01_SSTP); gen_op_raise_exception(EXCP01_SSTP);
} }
the_end:
if (dc->is_jmp != DISAS_TB_JUMP) { if (dc->is_jmp != DISAS_TB_JUMP) {
/* indicate that the hash table must be used to find the next TB */ /* indicate that the hash table must be used to find the next TB */
gen_op_movl_T0_0(); gen_op_movl_T0_0();
@ -4202,14 +4222,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc
return 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) CPUX86State *cpu_x86_init(void)

View 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 '*gen_code_size_ptr' contains the size of the generated code (host
code). code).
*/ */
int cpu_gen_code(TranslationBlock *tb, int cpu_gen_code(CPUState *env, TranslationBlock *tb,
int max_code_size, int *gen_code_size_ptr) int max_code_size, int *gen_code_size_ptr)
{ {
uint8_t *gen_code_buf; uint8_t *gen_code_buf;
int gen_code_size; int gen_code_size;
if (gen_intermediate_code(tb) < 0) if (gen_intermediate_code(env, tb) < 0)
return -1; return -1;
/* generate machine code */ /* generate machine code */
@ -154,7 +154,7 @@ int cpu_restore_state(TranslationBlock *tb,
unsigned long tc_ptr; unsigned long tc_ptr;
uint16_t *opc_ptr; uint16_t *opc_ptr;
if (gen_intermediate_code_pc(tb) < 0) if (gen_intermediate_code_pc(env, tb) < 0)
return -1; return -1;
/* find opc index corresponding to search_pc */ /* find opc index corresponding to search_pc */

6
vl.c
View File

@ -2540,7 +2540,7 @@ CPUState *cpu_gdbstub_get_env(void *opaque)
return global_env; return global_env;
} }
void main_loop(void *opaque) int main_loop(void *opaque)
{ {
struct pollfd ufds[2], *pf, *serial_ufd, *net_ufd, *gdb_ufd; struct pollfd ufds[2], *pf, *serial_ufd, *net_ufd, *gdb_ufd;
int ret, n, timeout; int ret, n, timeout;
@ -2552,7 +2552,8 @@ void main_loop(void *opaque)
ret = cpu_x86_exec(env); ret = cpu_x86_exec(env);
if (reset_requested) if (reset_requested)
break; break;
if (ret == EXCP_DEBUG)
return EXCP_DEBUG;
/* if hlt instruction, we wait until the next IRQ */ /* if hlt instruction, we wait until the next IRQ */
if (ret == EXCP_HLT) if (ret == EXCP_HLT)
timeout = 10; timeout = 10;
@ -2618,6 +2619,7 @@ void main_loop(void *opaque)
timer_irq_pending = 0; timer_irq_pending = 0;
} }
} }
return EXCP_INTERRUPT;
} }
void help(void) void help(void)