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:
parent
d6b4936796
commit
4c3a88a284
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
@ -271,6 +274,9 @@ typedef struct CPUX86State {
|
||||
int interrupt_request;
|
||||
int user_mode_only; /* user mode only simulation */
|
||||
|
||||
uint32_t breakpoints[MAX_BREAKPOINTS];
|
||||
int nb_breakpoints;
|
||||
|
||||
/* user data */
|
||||
void *opaque;
|
||||
} CPUX86State;
|
||||
|
42
exec.c
42
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)
|
||||
{
|
||||
|
6
exec.h
6
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);
|
||||
|
55
gdbstub.c
55
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';
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
6
vl.c
6
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)
|
||||
|
Loading…
Reference in New Issue
Block a user