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 */
|
#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 */
|
||||||
|
@ -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 */
|
||||||
|
@ -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
42
exec.c
@ -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
6
exec.h
@ -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);
|
||||||
|
55
gdbstub.c
55
gdbstub.c
@ -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';
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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
6
vl.c
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user