Commit 34865134335df669132f9c2ed12d1e0be361f30f
1 parent
0806e3f6
log activation from gdb - gdb single step support for x86 - stop timer when cpu is being debugged
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@402 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
5 changed files
with
125 additions
and
24 deletions
cpu-all.h
... | ... | @@ -377,6 +377,10 @@ int cpu_breakpoint_insert(CPUState *env, uint32_t pc); |
377 | 377 | int cpu_breakpoint_remove(CPUState *env, uint32_t pc); |
378 | 378 | void cpu_single_step(CPUState *env, int enabled); |
379 | 379 | |
380 | +#define CPU_LOG_ALL 1 | |
381 | +void cpu_set_log(int log_flags); | |
382 | +void cpu_set_log_filename(const char *filename); | |
383 | + | |
380 | 384 | /* memory API */ |
381 | 385 | |
382 | 386 | typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value); | ... | ... |
exec.c
... | ... | @@ -78,6 +78,11 @@ CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; |
78 | 78 | CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; |
79 | 79 | static int io_mem_nb; |
80 | 80 | |
81 | +/* log support */ | |
82 | +char *logfilename = "/tmp/qemu.log"; | |
83 | +FILE *logfile; | |
84 | +int loglevel; | |
85 | + | |
81 | 86 | static void page_init(void) |
82 | 87 | { |
83 | 88 | /* NOTE: we can always suppose that host_page_size >= |
... | ... | @@ -676,6 +681,24 @@ void cpu_single_step(CPUState *env, int enabled) |
676 | 681 | #endif |
677 | 682 | } |
678 | 683 | |
684 | +/* enable or disable low levels log */ | |
685 | +void cpu_set_log(int log_flags) | |
686 | +{ | |
687 | + loglevel = log_flags; | |
688 | + if (loglevel && !logfile) { | |
689 | + logfile = fopen(logfilename, "w"); | |
690 | + if (!logfile) { | |
691 | + perror(logfilename); | |
692 | + _exit(1); | |
693 | + } | |
694 | + setvbuf(logfile, NULL, _IOLBF, 0); | |
695 | + } | |
696 | +} | |
697 | + | |
698 | +void cpu_set_log_filename(const char *filename) | |
699 | +{ | |
700 | + logfilename = strdup(filename); | |
701 | +} | |
679 | 702 | |
680 | 703 | /* mask must never be zero */ |
681 | 704 | void cpu_interrupt(CPUState *env, int mask) | ... | ... |
gdbstub.c
... | ... | @@ -437,7 +437,24 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) |
437 | 437 | goto breakpoint_error; |
438 | 438 | } |
439 | 439 | break; |
440 | + case 'Q': | |
441 | + if (!strncmp(p, "Tinit", 5)) { | |
442 | + /* init traces */ | |
443 | + put_packet("OK"); | |
444 | + } else if (!strncmp(p, "TStart", 6)) { | |
445 | + /* start log (gdb 'tstart' command) */ | |
446 | + cpu_set_log(CPU_LOG_ALL); | |
447 | + put_packet("OK"); | |
448 | + } else if (!strncmp(p, "TStop", 5)) { | |
449 | + /* stop log (gdb 'tstop' command) */ | |
450 | + cpu_set_log(0); | |
451 | + put_packet("OK"); | |
452 | + } else { | |
453 | + goto unknown_command; | |
454 | + } | |
455 | + break; | |
440 | 456 | default: |
457 | + unknown_command: | |
441 | 458 | /* put empty packet */ |
442 | 459 | buf[0] = '\0'; |
443 | 460 | put_packet(buf); | ... | ... |
target-i386/translate.c
... | ... | @@ -60,6 +60,7 @@ typedef struct DisasContext { |
60 | 60 | int cpl; |
61 | 61 | int iopl; |
62 | 62 | int tf; /* TF cpu flag */ |
63 | + int singlestep_enabled; /* "hardware" single step enabled */ | |
63 | 64 | int jmp_opt; /* use direct block chaining for direct jumps */ |
64 | 65 | int mem_index; /* select memory access functions */ |
65 | 66 | struct TranslationBlock *tb; |
... | ... | @@ -1712,7 +1713,9 @@ static void gen_eob(DisasContext *s) |
1712 | 1713 | { |
1713 | 1714 | if (s->cc_op != CC_OP_DYNAMIC) |
1714 | 1715 | gen_op_set_cc_op(s->cc_op); |
1715 | - if (s->tf) { | |
1716 | + if (s->singlestep_enabled) { | |
1717 | + gen_op_debug(); | |
1718 | + } else if (s->tf) { | |
1716 | 1719 | gen_op_raise_exception(EXCP01_SSTP); |
1717 | 1720 | } else { |
1718 | 1721 | gen_op_movl_T0_0(); |
... | ... | @@ -4368,6 +4371,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, |
4368 | 4371 | dc->cpl = (flags >> HF_CPL_SHIFT) & 3; |
4369 | 4372 | dc->iopl = (flags >> IOPL_SHIFT) & 3; |
4370 | 4373 | dc->tf = (flags >> TF_SHIFT) & 1; |
4374 | + dc->singlestep_enabled = env->singlestep_enabled; | |
4371 | 4375 | dc->cc_op = CC_OP_DYNAMIC; |
4372 | 4376 | dc->cs_base = cs_base; |
4373 | 4377 | dc->tb = tb; |
... | ... | @@ -4425,7 +4429,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, |
4425 | 4429 | break; |
4426 | 4430 | /* if single step mode, we generate only one instruction and |
4427 | 4431 | generate an exception */ |
4428 | - if (dc->tf) { | |
4432 | + if (dc->tf || dc->singlestep_enabled) { | |
4429 | 4433 | gen_op_jmp_im(pc_ptr - dc->cs_base); |
4430 | 4434 | gen_eob(dc); |
4431 | 4435 | break; | ... | ... |
vl.c
... | ... | @@ -50,7 +50,6 @@ |
50 | 50 | |
51 | 51 | #include "vl.h" |
52 | 52 | |
53 | -#define DEBUG_LOGFILE "/tmp/vl.log" | |
54 | 53 | #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" |
55 | 54 | #define BIOS_FILENAME "bios.bin" |
56 | 55 | #define VGABIOS_FILENAME "vgabios.bin" |
... | ... | @@ -209,8 +208,6 @@ static const char *bios_dir = CONFIG_QEMU_SHAREDIR; |
209 | 208 | char phys_ram_file[1024]; |
210 | 209 | CPUX86State *global_env; |
211 | 210 | CPUX86State *cpu_single_env; |
212 | -FILE *logfile = NULL; | |
213 | -int loglevel; | |
214 | 211 | IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; |
215 | 212 | IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; |
216 | 213 | BlockDriverState *bs_table[MAX_DISKS]; |
... | ... | @@ -832,20 +829,76 @@ int speaker_data_on; |
832 | 829 | int dummy_refresh_clock; |
833 | 830 | int pit_min_timer_count = 0; |
834 | 831 | |
835 | -int64_t get_clock(void) | |
832 | + | |
833 | +#if defined(__powerpc__) | |
834 | + | |
835 | +static inline uint32_t get_tbl(void) | |
836 | 836 | { |
837 | - struct timeval tv; | |
838 | - gettimeofday(&tv, NULL); | |
839 | - return tv.tv_sec * 1000000LL + tv.tv_usec; | |
837 | + uint32_t tbl; | |
838 | + asm volatile("mftb %0" : "=r" (tbl)); | |
839 | + return tbl; | |
840 | 840 | } |
841 | 841 | |
842 | -int64_t cpu_get_ticks(void) | |
842 | +static inline uint32_t get_tbu(void) | |
843 | +{ | |
844 | + uint32_t tbl; | |
845 | + asm volatile("mftbu %0" : "=r" (tbl)); | |
846 | + return tbl; | |
847 | +} | |
848 | + | |
849 | +int64_t cpu_get_real_ticks(void) | |
850 | +{ | |
851 | + uint32_t l, h, h1; | |
852 | + /* NOTE: we test if wrapping has occurred */ | |
853 | + do { | |
854 | + h = get_tbu(); | |
855 | + l = get_tbl(); | |
856 | + h1 = get_tbu(); | |
857 | + } while (h != h1); | |
858 | + return ((int64_t)h << 32) | l; | |
859 | +} | |
860 | + | |
861 | +#elif defined(__i386__) | |
862 | + | |
863 | +int64_t cpu_get_real_ticks(void) | |
843 | 864 | { |
844 | 865 | int64_t val; |
845 | 866 | asm("rdtsc" : "=A" (val)); |
846 | 867 | return val; |
847 | 868 | } |
848 | 869 | |
870 | +#else | |
871 | +#error unsupported CPU | |
872 | +#endif | |
873 | + | |
874 | +static int64_t cpu_ticks_offset; | |
875 | +static int64_t cpu_ticks_last; | |
876 | + | |
877 | +int64_t cpu_get_ticks(void) | |
878 | +{ | |
879 | + return cpu_get_real_ticks() + cpu_ticks_offset; | |
880 | +} | |
881 | + | |
882 | +/* enable cpu_get_ticks() */ | |
883 | +void cpu_enable_ticks(void) | |
884 | +{ | |
885 | + cpu_ticks_offset = cpu_ticks_last - cpu_get_real_ticks(); | |
886 | +} | |
887 | + | |
888 | +/* disable cpu_get_ticks() : the clock is stopped. You must not call | |
889 | + cpu_get_ticks() after that. */ | |
890 | +void cpu_disable_ticks(void) | |
891 | +{ | |
892 | + cpu_ticks_last = cpu_get_ticks(); | |
893 | +} | |
894 | + | |
895 | +int64_t get_clock(void) | |
896 | +{ | |
897 | + struct timeval tv; | |
898 | + gettimeofday(&tv, NULL); | |
899 | + return tv.tv_sec * 1000000LL + tv.tv_usec; | |
900 | +} | |
901 | + | |
849 | 902 | void cpu_calibrate_ticks(void) |
850 | 903 | { |
851 | 904 | int64_t usec, ticks; |
... | ... | @@ -3297,12 +3350,17 @@ int main_loop(void *opaque) |
3297 | 3350 | } |
3298 | 3351 | |
3299 | 3352 | serial_ok = 1; |
3353 | + cpu_enable_ticks(); | |
3300 | 3354 | for(;;) { |
3301 | 3355 | ret = cpu_x86_exec(env); |
3302 | - if (reset_requested) | |
3356 | + if (reset_requested) { | |
3357 | + ret = EXCP_INTERRUPT; | |
3303 | 3358 | break; |
3304 | - if (ret == EXCP_DEBUG) | |
3305 | - return EXCP_DEBUG; | |
3359 | + } | |
3360 | + if (ret == EXCP_DEBUG) { | |
3361 | + ret = EXCP_DEBUG; | |
3362 | + break; | |
3363 | + } | |
3306 | 3364 | /* if hlt instruction, we wait until the next IRQ */ |
3307 | 3365 | if (ret == EXCP_HLT) |
3308 | 3366 | timeout = 10; |
... | ... | @@ -3359,8 +3417,10 @@ int main_loop(void *opaque) |
3359 | 3417 | uint8_t buf[1]; |
3360 | 3418 | /* stop emulation if requested by gdb */ |
3361 | 3419 | n = read(gdbstub_fd, buf, 1); |
3362 | - if (n == 1) | |
3420 | + if (n == 1) { | |
3421 | + ret = EXCP_INTERRUPT; | |
3363 | 3422 | break; |
3423 | + } | |
3364 | 3424 | } |
3365 | 3425 | } |
3366 | 3426 | |
... | ... | @@ -3377,7 +3437,8 @@ int main_loop(void *opaque) |
3377 | 3437 | gui_refresh_pending = 0; |
3378 | 3438 | } |
3379 | 3439 | } |
3380 | - return EXCP_INTERRUPT; | |
3440 | + cpu_disable_ticks(); | |
3441 | + return ret; | |
3381 | 3442 | } |
3382 | 3443 | |
3383 | 3444 | void help(void) |
... | ... | @@ -3535,7 +3596,7 @@ int main(int argc, char **argv) |
3535 | 3596 | } |
3536 | 3597 | break; |
3537 | 3598 | case 'd': |
3538 | - loglevel = 1; | |
3599 | + cpu_set_log(CPU_LOG_ALL); | |
3539 | 3600 | break; |
3540 | 3601 | case 'n': |
3541 | 3602 | pstrcpy(network_script, sizeof(network_script), optarg); |
... | ... | @@ -3563,14 +3624,6 @@ int main(int argc, char **argv) |
3563 | 3624 | |
3564 | 3625 | /* init debug */ |
3565 | 3626 | setvbuf(stdout, NULL, _IOLBF, 0); |
3566 | - if (loglevel) { | |
3567 | - logfile = fopen(DEBUG_LOGFILE, "w"); | |
3568 | - if (!logfile) { | |
3569 | - perror(DEBUG_LOGFILE); | |
3570 | - _exit(1); | |
3571 | - } | |
3572 | - setvbuf(logfile, NULL, _IOLBF, 0); | |
3573 | - } | |
3574 | 3627 | |
3575 | 3628 | /* init network tun interface */ |
3576 | 3629 | if (net_fd < 0) | ... | ... |