Commit 4c3a88a284b288e0ed3c097de7fc07111d848003
1 parent
d6b49367
gdb stub breakpoints support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@332 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
11 changed files
with
151 additions
and
25 deletions
cpu-all.h
... | ... | @@ -313,9 +313,12 @@ extern CPUState *cpu_single_env; |
313 | 313 | #define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */ |
314 | 314 | void cpu_interrupt(CPUState *s, int mask); |
315 | 315 | |
316 | +int cpu_breakpoint_insert(CPUState *env, uint32_t pc); | |
317 | +int cpu_breakpoint_remove(CPUState *env, uint32_t pc); | |
318 | + | |
316 | 319 | /* gdb stub API */ |
317 | 320 | extern int gdbstub_fd; |
318 | 321 | CPUState *cpu_gdbstub_get_env(void *opaque); |
319 | -int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port); | |
322 | +int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port); | |
320 | 323 | |
321 | 324 | #endif /* CPU_ALL_H */ | ... | ... |
cpu-exec.c
... | ... | @@ -280,7 +280,7 @@ int cpu_exec(CPUState *env1) |
280 | 280 | tb->tc_ptr = tc_ptr; |
281 | 281 | tb->cs_base = (unsigned long)cs_base; |
282 | 282 | tb->flags = flags; |
283 | - ret = cpu_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size); | |
283 | + ret = cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size); | |
284 | 284 | #if defined(TARGET_I386) |
285 | 285 | /* XXX: suppress that, this is incorrect */ |
286 | 286 | /* if invalid instruction, signal it */ | ... | ... |
cpu-i386.h
... | ... | @@ -155,6 +155,9 @@ |
155 | 155 | |
156 | 156 | #define EXCP_INTERRUPT 256 /* async interruption */ |
157 | 157 | #define EXCP_HLT 257 /* hlt instruction reached */ |
158 | +#define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */ | |
159 | + | |
160 | +#define MAX_BREAKPOINTS 32 | |
158 | 161 | |
159 | 162 | enum { |
160 | 163 | CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ |
... | ... | @@ -270,6 +273,9 @@ typedef struct CPUX86State { |
270 | 273 | uint32_t dr[8]; /* debug registers */ |
271 | 274 | int interrupt_request; |
272 | 275 | int user_mode_only; /* user mode only simulation */ |
276 | + | |
277 | + uint32_t breakpoints[MAX_BREAKPOINTS]; | |
278 | + int nb_breakpoints; | |
273 | 279 | |
274 | 280 | /* user data */ |
275 | 281 | void *opaque; | ... | ... |
exec.c
... | ... | @@ -617,6 +617,48 @@ static void tb_reset_jump_recursive(TranslationBlock *tb) |
617 | 617 | tb_reset_jump_recursive2(tb, 1); |
618 | 618 | } |
619 | 619 | |
620 | +/* add a breakpoint */ | |
621 | +int cpu_breakpoint_insert(CPUState *env, uint32_t pc) | |
622 | +{ | |
623 | +#if defined(TARGET_I386) | |
624 | + int i; | |
625 | + | |
626 | + for(i = 0; i < env->nb_breakpoints; i++) { | |
627 | + if (env->breakpoints[i] == pc) | |
628 | + return 0; | |
629 | + } | |
630 | + | |
631 | + if (env->nb_breakpoints >= MAX_BREAKPOINTS) | |
632 | + return -1; | |
633 | + env->breakpoints[env->nb_breakpoints++] = pc; | |
634 | + tb_invalidate_page(pc); | |
635 | + return 0; | |
636 | +#else | |
637 | + return -1; | |
638 | +#endif | |
639 | +} | |
640 | + | |
641 | +/* remove a breakpoint */ | |
642 | +int cpu_breakpoint_remove(CPUState *env, uint32_t pc) | |
643 | +{ | |
644 | +#if defined(TARGET_I386) | |
645 | + int i; | |
646 | + for(i = 0; i < env->nb_breakpoints; i++) { | |
647 | + if (env->breakpoints[i] == pc) | |
648 | + goto found; | |
649 | + } | |
650 | + return -1; | |
651 | + found: | |
652 | + memmove(&env->breakpoints[i], &env->breakpoints[i + 1], | |
653 | + (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0])); | |
654 | + env->nb_breakpoints--; | |
655 | + tb_invalidate_page(pc); | |
656 | + return 0; | |
657 | +#else | |
658 | + return -1; | |
659 | +#endif | |
660 | +} | |
661 | + | |
620 | 662 | /* mask must never be zero */ |
621 | 663 | void cpu_interrupt(CPUState *env, int mask) |
622 | 664 | { | ... | ... |
exec.h
... | ... | @@ -58,10 +58,10 @@ extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; |
58 | 58 | extern FILE *logfile; |
59 | 59 | extern int loglevel; |
60 | 60 | |
61 | -int gen_intermediate_code(struct TranslationBlock *tb); | |
62 | -int gen_intermediate_code_pc(struct TranslationBlock *tb); | |
61 | +int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb); | |
62 | +int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb); | |
63 | 63 | void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf); |
64 | -int cpu_gen_code(struct TranslationBlock *tb, | |
64 | +int cpu_gen_code(CPUState *env, struct TranslationBlock *tb, | |
65 | 65 | int max_code_size, int *gen_code_size_ptr); |
66 | 66 | int cpu_restore_state(struct TranslationBlock *tb, |
67 | 67 | CPUState *env, unsigned long searched_pc); | ... | ... |
gdbstub.c
... | ... | @@ -37,7 +37,7 @@ |
37 | 37 | #include "thunk.h" |
38 | 38 | #include "exec.h" |
39 | 39 | |
40 | -//#define DEBUG_GDB | |
40 | +#define DEBUG_GDB | |
41 | 41 | |
42 | 42 | int gdbstub_fd = -1; |
43 | 43 | |
... | ... | @@ -283,11 +283,11 @@ static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write) |
283 | 283 | } |
284 | 284 | |
285 | 285 | /* port = 0 means default port */ |
286 | -int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port) | |
286 | +int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) | |
287 | 287 | { |
288 | 288 | CPUState *env; |
289 | 289 | const char *p; |
290 | - int ret, ch, nb_regs, i; | |
290 | + int ret, ch, nb_regs, i, type; | |
291 | 291 | char buf[4096]; |
292 | 292 | uint8_t mem_buf[2000]; |
293 | 293 | uint32_t *registers; |
... | ... | @@ -309,8 +309,19 @@ int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port) |
309 | 309 | put_packet(buf); |
310 | 310 | break; |
311 | 311 | case 'c': |
312 | - main_loop(opaque); | |
313 | - snprintf(buf, sizeof(buf), "S%02x", 0); | |
312 | + if (*p != '\0') { | |
313 | + addr = strtoul(p, (char **)&p, 16); | |
314 | + env = cpu_gdbstub_get_env(opaque); | |
315 | +#if defined(TARGET_I386) | |
316 | + env->eip = addr; | |
317 | +#endif | |
318 | + } | |
319 | + ret = main_loop(opaque); | |
320 | + if (ret == EXCP_DEBUG) | |
321 | + ret = SIGTRAP; | |
322 | + else | |
323 | + ret = 0; | |
324 | + snprintf(buf, sizeof(buf), "S%02x", ret); | |
314 | 325 | put_packet(buf); |
315 | 326 | break; |
316 | 327 | case 'g': |
... | ... | @@ -379,6 +390,40 @@ int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port) |
379 | 390 | else |
380 | 391 | put_packet("OK"); |
381 | 392 | break; |
393 | + case 'Z': | |
394 | + type = strtoul(p, (char **)&p, 16); | |
395 | + if (*p == ',') | |
396 | + p++; | |
397 | + addr = strtoul(p, (char **)&p, 16); | |
398 | + if (*p == ',') | |
399 | + p++; | |
400 | + len = strtoul(p, (char **)&p, 16); | |
401 | + if (type == 0 || type == 1) { | |
402 | + env = cpu_gdbstub_get_env(opaque); | |
403 | + if (cpu_breakpoint_insert(env, addr) < 0) | |
404 | + goto breakpoint_error; | |
405 | + put_packet("OK"); | |
406 | + } else { | |
407 | + breakpoint_error: | |
408 | + put_packet("ENN"); | |
409 | + } | |
410 | + break; | |
411 | + case 'z': | |
412 | + type = strtoul(p, (char **)&p, 16); | |
413 | + if (*p == ',') | |
414 | + p++; | |
415 | + addr = strtoul(p, (char **)&p, 16); | |
416 | + if (*p == ',') | |
417 | + p++; | |
418 | + len = strtoul(p, (char **)&p, 16); | |
419 | + if (type == 0 || type == 1) { | |
420 | + env = cpu_gdbstub_get_env(opaque); | |
421 | + cpu_breakpoint_remove(env, addr); | |
422 | + put_packet("OK"); | |
423 | + } else { | |
424 | + goto breakpoint_error; | |
425 | + } | |
426 | + break; | |
382 | 427 | default: |
383 | 428 | /* put empty packet */ |
384 | 429 | buf[0] = '\0'; | ... | ... |
op-i386.c
translate-arm.c
... | ... | @@ -786,7 +786,9 @@ static void disas_arm_insn(DisasContext *s) |
786 | 786 | /* generate intermediate code in gen_opc_buf and gen_opparam_buf for |
787 | 787 | basic block 'tb'. If search_pc is TRUE, also generate PC |
788 | 788 | information for each intermediate instruction. */ |
789 | -static inline int gen_intermediate_code_internal(TranslationBlock *tb, int search_pc) | |
789 | +static inline int gen_intermediate_code_internal(CPUState *env, | |
790 | + TranslationBlock *tb, | |
791 | + int search_pc) | |
790 | 792 | { |
791 | 793 | DisasContext dc1, *dc = &dc1; |
792 | 794 | uint16_t *gen_opc_end; |
... | ... | @@ -853,14 +855,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc |
853 | 855 | return 0; |
854 | 856 | } |
855 | 857 | |
856 | -int gen_intermediate_code(TranslationBlock *tb) | |
858 | +int gen_intermediate_code(CPUState *env, TranslationBlock *tb) | |
857 | 859 | { |
858 | - return gen_intermediate_code_internal(tb, 0); | |
860 | + return gen_intermediate_code_internal(env, tb, 0); | |
859 | 861 | } |
860 | 862 | |
861 | -int gen_intermediate_code_pc(TranslationBlock *tb) | |
863 | +int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) | |
862 | 864 | { |
863 | - return gen_intermediate_code_internal(tb, 1); | |
865 | + return gen_intermediate_code_internal(env, tb, 1); | |
864 | 866 | } |
865 | 867 | |
866 | 868 | CPUARMState *cpu_arm_init(void) | ... | ... |
translate-i386.c
... | ... | @@ -1463,6 +1463,15 @@ static void gen_interrupt(DisasContext *s, int intno, |
1463 | 1463 | s->is_jmp = 1; |
1464 | 1464 | } |
1465 | 1465 | |
1466 | +static void gen_debug(DisasContext *s, unsigned int cur_eip) | |
1467 | +{ | |
1468 | + if (s->cc_op != CC_OP_DYNAMIC) | |
1469 | + gen_op_set_cc_op(s->cc_op); | |
1470 | + gen_op_jmp_im(cur_eip); | |
1471 | + gen_op_debug(); | |
1472 | + s->is_jmp = 1; | |
1473 | +} | |
1474 | + | |
1466 | 1475 | /* generate a jump to eip. No segment change must happen before as a |
1467 | 1476 | direct call to the next block may occur */ |
1468 | 1477 | 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) |
4080 | 4089 | /* generate intermediate code in gen_opc_buf and gen_opparam_buf for |
4081 | 4090 | basic block 'tb'. If search_pc is TRUE, also generate PC |
4082 | 4091 | information for each intermediate instruction. */ |
4083 | -static inline int gen_intermediate_code_internal(TranslationBlock *tb, int search_pc) | |
4092 | +static inline int gen_intermediate_code_internal(CPUState *env, | |
4093 | + TranslationBlock *tb, | |
4094 | + int search_pc) | |
4084 | 4095 | { |
4085 | 4096 | DisasContext dc1, *dc = &dc1; |
4086 | 4097 | uint8_t *pc_ptr; |
... | ... | @@ -4116,6 +4127,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc |
4116 | 4127 | pc_ptr = pc_start; |
4117 | 4128 | lj = -1; |
4118 | 4129 | do { |
4130 | + if (env->nb_breakpoints > 0) { | |
4131 | + for(j = 0; j < env->nb_breakpoints; j++) { | |
4132 | + if (env->breakpoints[j] == (unsigned long)pc_ptr) { | |
4133 | + gen_debug(dc, pc_ptr - dc->cs_base); | |
4134 | + goto the_end; | |
4135 | + } | |
4136 | + } | |
4137 | + } | |
4119 | 4138 | if (search_pc) { |
4120 | 4139 | j = gen_opc_ptr - gen_opc_buf; |
4121 | 4140 | if (lj < j) { |
... | ... | @@ -4160,6 +4179,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc |
4160 | 4179 | if (dc->tf) { |
4161 | 4180 | gen_op_raise_exception(EXCP01_SSTP); |
4162 | 4181 | } |
4182 | + the_end: | |
4163 | 4183 | if (dc->is_jmp != DISAS_TB_JUMP) { |
4164 | 4184 | /* indicate that the hash table must be used to find the next TB */ |
4165 | 4185 | gen_op_movl_T0_0(); |
... | ... | @@ -4202,14 +4222,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc |
4202 | 4222 | return 0; |
4203 | 4223 | } |
4204 | 4224 | |
4205 | -int gen_intermediate_code(TranslationBlock *tb) | |
4225 | +int gen_intermediate_code(CPUState *env, TranslationBlock *tb) | |
4206 | 4226 | { |
4207 | - return gen_intermediate_code_internal(tb, 0); | |
4227 | + return gen_intermediate_code_internal(env, tb, 0); | |
4208 | 4228 | } |
4209 | 4229 | |
4210 | -int gen_intermediate_code_pc(TranslationBlock *tb) | |
4230 | +int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) | |
4211 | 4231 | { |
4212 | - return gen_intermediate_code_internal(tb, 1); | |
4232 | + return gen_intermediate_code_internal(env, tb, 1); | |
4213 | 4233 | } |
4214 | 4234 | |
4215 | 4235 | CPUX86State *cpu_x86_init(void) | ... | ... |
translate.c
... | ... | @@ -107,13 +107,13 @@ void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) |
107 | 107 | '*gen_code_size_ptr' contains the size of the generated code (host |
108 | 108 | code). |
109 | 109 | */ |
110 | -int cpu_gen_code(TranslationBlock *tb, | |
110 | +int cpu_gen_code(CPUState *env, TranslationBlock *tb, | |
111 | 111 | int max_code_size, int *gen_code_size_ptr) |
112 | 112 | { |
113 | 113 | uint8_t *gen_code_buf; |
114 | 114 | int gen_code_size; |
115 | 115 | |
116 | - if (gen_intermediate_code(tb) < 0) | |
116 | + if (gen_intermediate_code(env, tb) < 0) | |
117 | 117 | return -1; |
118 | 118 | |
119 | 119 | /* generate machine code */ |
... | ... | @@ -154,7 +154,7 @@ int cpu_restore_state(TranslationBlock *tb, |
154 | 154 | unsigned long tc_ptr; |
155 | 155 | uint16_t *opc_ptr; |
156 | 156 | |
157 | - if (gen_intermediate_code_pc(tb) < 0) | |
157 | + if (gen_intermediate_code_pc(env, tb) < 0) | |
158 | 158 | return -1; |
159 | 159 | |
160 | 160 | /* find opc index corresponding to search_pc */ | ... | ... |
vl.c
... | ... | @@ -2540,7 +2540,7 @@ CPUState *cpu_gdbstub_get_env(void *opaque) |
2540 | 2540 | return global_env; |
2541 | 2541 | } |
2542 | 2542 | |
2543 | -void main_loop(void *opaque) | |
2543 | +int main_loop(void *opaque) | |
2544 | 2544 | { |
2545 | 2545 | struct pollfd ufds[2], *pf, *serial_ufd, *net_ufd, *gdb_ufd; |
2546 | 2546 | int ret, n, timeout; |
... | ... | @@ -2552,7 +2552,8 @@ void main_loop(void *opaque) |
2552 | 2552 | ret = cpu_x86_exec(env); |
2553 | 2553 | if (reset_requested) |
2554 | 2554 | break; |
2555 | - | |
2555 | + if (ret == EXCP_DEBUG) | |
2556 | + return EXCP_DEBUG; | |
2556 | 2557 | /* if hlt instruction, we wait until the next IRQ */ |
2557 | 2558 | if (ret == EXCP_HLT) |
2558 | 2559 | timeout = 10; |
... | ... | @@ -2618,6 +2619,7 @@ void main_loop(void *opaque) |
2618 | 2619 | timer_irq_pending = 0; |
2619 | 2620 | } |
2620 | 2621 | } |
2622 | + return EXCP_INTERRUPT; | |
2621 | 2623 | } |
2622 | 2624 | |
2623 | 2625 | void help(void) | ... | ... |