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) | ... | ... |