Commit 1fddef4b1ba3bf14d36472475019a4a6acd4d976
1 parent
6e4255f6
gdb support for user mode (Paul Brook)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1367 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
14 changed files
with
265 additions
and
29 deletions
Makefile.target
exec.c
... | ... | @@ -1076,7 +1076,7 @@ static void tb_reset_jump_recursive(TranslationBlock *tb) |
1076 | 1076 | tb_reset_jump_recursive2(tb, 1); |
1077 | 1077 | } |
1078 | 1078 | |
1079 | -#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC) | |
1079 | +#if defined(TARGET_HAS_ICE) | |
1080 | 1080 | static void breakpoint_invalidate(CPUState *env, target_ulong pc) |
1081 | 1081 | { |
1082 | 1082 | target_ulong phys_addr; |
... | ... | @@ -1090,7 +1090,7 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc) |
1090 | 1090 | breakpoint is reached */ |
1091 | 1091 | int cpu_breakpoint_insert(CPUState *env, target_ulong pc) |
1092 | 1092 | { |
1093 | -#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC) | |
1093 | +#if defined(TARGET_HAS_ICE) | |
1094 | 1094 | int i; |
1095 | 1095 | |
1096 | 1096 | for(i = 0; i < env->nb_breakpoints; i++) { |
... | ... | @@ -1112,7 +1112,7 @@ int cpu_breakpoint_insert(CPUState *env, target_ulong pc) |
1112 | 1112 | /* remove a breakpoint */ |
1113 | 1113 | int cpu_breakpoint_remove(CPUState *env, target_ulong pc) |
1114 | 1114 | { |
1115 | -#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC) | |
1115 | +#if defined(TARGET_HAS_ICE) | |
1116 | 1116 | int i; |
1117 | 1117 | for(i = 0; i < env->nb_breakpoints; i++) { |
1118 | 1118 | if (env->breakpoints[i] == pc) |
... | ... | @@ -1120,9 +1120,9 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc) |
1120 | 1120 | } |
1121 | 1121 | return -1; |
1122 | 1122 | found: |
1123 | - memmove(&env->breakpoints[i], &env->breakpoints[i + 1], | |
1124 | - (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0])); | |
1125 | 1123 | env->nb_breakpoints--; |
1124 | + if (i < env->nb_breakpoints) | |
1125 | + env->breakpoints[i] = env->breakpoints[env->nb_breakpoints]; | |
1126 | 1126 | |
1127 | 1127 | breakpoint_invalidate(env, pc); |
1128 | 1128 | return 0; |
... | ... | @@ -1135,7 +1135,7 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc) |
1135 | 1135 | CPU loop after each instruction */ |
1136 | 1136 | void cpu_single_step(CPUState *env, int enabled) |
1137 | 1137 | { |
1138 | -#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC) | |
1138 | +#if defined(TARGET_HAS_ICE) | |
1139 | 1139 | if (env->singlestep_enabled != enabled) { |
1140 | 1140 | env->singlestep_enabled = enabled; |
1141 | 1141 | /* must flush all the translated code to avoid inconsistancies */ | ... | ... |
gdbstub.c
... | ... | @@ -17,7 +17,18 @@ |
17 | 17 | * License along with this library; if not, write to the Free Software |
18 | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | 19 | */ |
20 | +#ifdef CONFIG_USER_ONLY | |
21 | +#include <stdlib.h> | |
22 | +#include <stdio.h> | |
23 | +#include <stdarg.h> | |
24 | +#include <string.h> | |
25 | +#include <errno.h> | |
26 | +#include <unistd.h> | |
27 | + | |
28 | +#include "qemu.h" | |
29 | +#else | |
20 | 30 | #include "vl.h" |
31 | +#endif | |
21 | 32 | |
22 | 33 | #include <sys/socket.h> |
23 | 34 | #include <netinet/in.h> |
... | ... | @@ -31,9 +42,10 @@ enum RSState { |
31 | 42 | RS_GETLINE, |
32 | 43 | RS_CHKSUM1, |
33 | 44 | RS_CHKSUM2, |
45 | + RS_CONTINUE | |
34 | 46 | }; |
35 | - | |
36 | -static int gdbserver_fd; | |
47 | +/* XXX: This is not thread safe. Do we care? */ | |
48 | +static int gdbserver_fd = -1; | |
37 | 49 | |
38 | 50 | typedef struct GDBState { |
39 | 51 | enum RSState state; |
... | ... | @@ -43,6 +55,11 @@ typedef struct GDBState { |
43 | 55 | int line_csum; |
44 | 56 | } GDBState; |
45 | 57 | |
58 | +#ifdef CONFIG_USER_ONLY | |
59 | +/* XXX: remove this hack. */ | |
60 | +static GDBState gdbserver_state; | |
61 | +#endif | |
62 | + | |
46 | 63 | static int get_char(GDBState *s) |
47 | 64 | { |
48 | 65 | uint8_t ch; |
... | ... | @@ -330,8 +347,47 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) |
330 | 347 | env->npc = tswapl(registers[69]); |
331 | 348 | env->fsr = tswapl(registers[70]); |
332 | 349 | } |
333 | -#else | |
350 | +#elif defined (TARGET_ARM) | |
351 | +static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) | |
352 | +{ | |
353 | + int i; | |
354 | + uint8_t *ptr; | |
355 | + | |
356 | + ptr = mem_buf; | |
357 | + /* 16 core integer registers (4 bytes each). */ | |
358 | + for (i = 0; i < 16; i++) | |
359 | + { | |
360 | + *(uint32_t *)ptr = tswapl(env->regs[i]); | |
361 | + ptr += 4; | |
362 | + } | |
363 | + /* 8 FPA registers (12 bytes each), FPS (4 bytes). | |
364 | + Not yet implemented. */ | |
365 | + memset (ptr, 0, 8 * 12 + 4); | |
366 | + ptr += 8 * 12 + 4; | |
367 | + /* CPSR (4 bytes). */ | |
368 | + *(uint32_t *)ptr = tswapl (env->cpsr); | |
369 | + ptr += 4; | |
370 | + | |
371 | + return ptr - mem_buf; | |
372 | +} | |
334 | 373 | |
374 | +static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) | |
375 | +{ | |
376 | + int i; | |
377 | + uint8_t *ptr; | |
378 | + | |
379 | + ptr = mem_buf; | |
380 | + /* Core integer registers. */ | |
381 | + for (i = 0; i < 16; i++) | |
382 | + { | |
383 | + env->regs[i] = tswapl(*(uint32_t *)ptr); | |
384 | + ptr += 4; | |
385 | + } | |
386 | + /* Ignore FPA regs and scr. */ | |
387 | + ptr += 8 * 12 + 4; | |
388 | + env->cpsr = tswapl(*(uint32_t *)ptr); | |
389 | +} | |
390 | +#else | |
335 | 391 | static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) |
336 | 392 | { |
337 | 393 | return 0; |
... | ... | @@ -343,10 +399,8 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) |
343 | 399 | |
344 | 400 | #endif |
345 | 401 | |
346 | -/* port = 0 means default port */ | |
347 | -static int gdb_handle_packet(GDBState *s, const char *line_buf) | |
402 | +static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) | |
348 | 403 | { |
349 | - CPUState *env = cpu_single_env; | |
350 | 404 | const char *p; |
351 | 405 | int ch, reg_size, type; |
352 | 406 | char buf[4096]; |
... | ... | @@ -361,6 +415,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) |
361 | 415 | ch = *p++; |
362 | 416 | switch(ch) { |
363 | 417 | case '?': |
418 | + /* TODO: Make this return the correct value for user-mode. */ | |
364 | 419 | snprintf(buf, sizeof(buf), "S%02x", SIGTRAP); |
365 | 420 | put_packet(s, buf); |
366 | 421 | break; |
... | ... | @@ -376,8 +431,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) |
376 | 431 | env->npc = addr + 4; |
377 | 432 | #endif |
378 | 433 | } |
379 | - vm_start(); | |
380 | - break; | |
434 | + return RS_CONTINUE; | |
381 | 435 | case 's': |
382 | 436 | if (*p != '\0') { |
383 | 437 | addr = strtoul(p, (char **)&p, 16); |
... | ... | @@ -391,8 +445,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) |
391 | 445 | #endif |
392 | 446 | } |
393 | 447 | cpu_single_step(env, 1); |
394 | - vm_start(); | |
395 | - break; | |
448 | + return RS_CONTINUE; | |
396 | 449 | case 'g': |
397 | 450 | reg_size = cpu_gdb_read_registers(env, mem_buf); |
398 | 451 | memtohex(buf, mem_buf, reg_size); |
... | ... | @@ -472,6 +525,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) |
472 | 525 | |
473 | 526 | extern void tb_flush(CPUState *env); |
474 | 527 | |
528 | +#ifndef CONFIG_USER_ONLY | |
475 | 529 | static void gdb_vm_stopped(void *opaque, int reason) |
476 | 530 | { |
477 | 531 | GDBState *s = opaque; |
... | ... | @@ -490,17 +544,20 @@ static void gdb_vm_stopped(void *opaque, int reason) |
490 | 544 | snprintf(buf, sizeof(buf), "S%02x", ret); |
491 | 545 | put_packet(s, buf); |
492 | 546 | } |
547 | +#endif | |
493 | 548 | |
494 | -static void gdb_read_byte(GDBState *s, int ch) | |
549 | +static void gdb_read_byte(GDBState *s, CPUState *env, int ch) | |
495 | 550 | { |
496 | 551 | int i, csum; |
497 | 552 | char reply[1]; |
498 | 553 | |
554 | +#ifndef CONFIG_USER_ONLY | |
499 | 555 | if (vm_running) { |
500 | 556 | /* when the CPU is running, we cannot do anything except stop |
501 | 557 | it when receiving a char */ |
502 | 558 | vm_stop(EXCP_INTERRUPT); |
503 | 559 | } else { |
560 | +#endif | |
504 | 561 | switch(s->state) { |
505 | 562 | case RS_IDLE: |
506 | 563 | if (ch == '$') { |
... | ... | @@ -535,13 +592,67 @@ static void gdb_read_byte(GDBState *s, int ch) |
535 | 592 | } else { |
536 | 593 | reply[0] = '+'; |
537 | 594 | put_buffer(s, reply, 1); |
538 | - s->state = gdb_handle_packet(s, s->line_buf); | |
595 | + s->state = gdb_handle_packet(s, env, s->line_buf); | |
539 | 596 | } |
540 | 597 | break; |
598 | + case RS_CONTINUE: | |
599 | +#ifndef CONFIG_USER_ONLY | |
600 | + vm_start(); | |
601 | + s->state = RS_IDLE; | |
602 | +#endif | |
603 | + break; | |
541 | 604 | } |
605 | +#ifndef CONFIG_USER_ONLY | |
542 | 606 | } |
607 | +#endif | |
543 | 608 | } |
544 | 609 | |
610 | +#ifdef CONFIG_USER_ONLY | |
611 | +int | |
612 | +gdb_handlesig (CPUState *env, int sig) | |
613 | +{ | |
614 | + GDBState *s; | |
615 | + char buf[256]; | |
616 | + int n; | |
617 | + | |
618 | + if (gdbserver_fd < 0) | |
619 | + return sig; | |
620 | + | |
621 | + s = &gdbserver_state; | |
622 | + | |
623 | + /* disable single step if it was enabled */ | |
624 | + cpu_single_step(env, 0); | |
625 | + tb_flush(env); | |
626 | + | |
627 | + if (sig != 0) | |
628 | + { | |
629 | + snprintf(buf, sizeof(buf), "S%02x", sig); | |
630 | + put_packet(s, buf); | |
631 | + } | |
632 | + | |
633 | + /* TODO: How do we terminate this loop? */ | |
634 | + sig = 0; | |
635 | + s->state = RS_IDLE; | |
636 | + while (s->state != RS_CONTINUE) | |
637 | + { | |
638 | + n = read (s->fd, buf, 256); | |
639 | + if (n > 0) | |
640 | + { | |
641 | + int i; | |
642 | + | |
643 | + for (i = 0; i < n; i++) | |
644 | + gdb_read_byte (s, env, buf[i]); | |
645 | + } | |
646 | + else if (n == 0 || errno != EAGAIN) | |
647 | + { | |
648 | + /* XXX: Connection closed. Should probably wait for annother | |
649 | + connection before continuing. */ | |
650 | + return sig; | |
651 | + } | |
652 | + } | |
653 | + return sig; | |
654 | +} | |
655 | +#else | |
545 | 656 | static int gdb_can_read(void *opaque) |
546 | 657 | { |
547 | 658 | return 256; |
... | ... | @@ -559,10 +670,12 @@ static void gdb_read(void *opaque, const uint8_t *buf, int size) |
559 | 670 | vm_start(); |
560 | 671 | } else { |
561 | 672 | for(i = 0; i < size; i++) |
562 | - gdb_read_byte(s, buf[i]); | |
673 | + gdb_read_byte(s, cpu_single_env, buf[i]); | |
563 | 674 | } |
564 | 675 | } |
565 | 676 | |
677 | +#endif | |
678 | + | |
566 | 679 | static void gdb_accept(void *opaque, const uint8_t *buf, int size) |
567 | 680 | { |
568 | 681 | GDBState *s; |
... | ... | @@ -585,15 +698,21 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size) |
585 | 698 | val = 1; |
586 | 699 | setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); |
587 | 700 | |
701 | +#ifdef CONFIG_USER_ONLY | |
702 | + s = &gdbserver_state; | |
703 | + memset (s, 0, sizeof (GDBState)); | |
704 | +#else | |
588 | 705 | s = qemu_mallocz(sizeof(GDBState)); |
589 | 706 | if (!s) { |
590 | 707 | close(fd); |
591 | 708 | return; |
592 | 709 | } |
710 | +#endif | |
593 | 711 | s->fd = fd; |
594 | 712 | |
595 | 713 | fcntl(fd, F_SETFL, O_NONBLOCK); |
596 | 714 | |
715 | +#ifndef CONFIG_USER_ONLY | |
597 | 716 | /* stop the VM */ |
598 | 717 | vm_stop(EXCP_INTERRUPT); |
599 | 718 | |
... | ... | @@ -601,6 +720,7 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size) |
601 | 720 | qemu_add_fd_read_handler(s->fd, gdb_can_read, gdb_read, s); |
602 | 721 | /* when the VM is stopped, the following callback is called */ |
603 | 722 | qemu_add_vm_stop_handler(gdb_vm_stopped, s); |
723 | +#endif | |
604 | 724 | } |
605 | 725 | |
606 | 726 | static int gdbserver_open(int port) |
... | ... | @@ -631,7 +751,9 @@ static int gdbserver_open(int port) |
631 | 751 | perror("listen"); |
632 | 752 | return -1; |
633 | 753 | } |
754 | +#ifndef CONFIG_USER_ONLY | |
634 | 755 | fcntl(fd, F_SETFL, O_NONBLOCK); |
756 | +#endif | |
635 | 757 | return fd; |
636 | 758 | } |
637 | 759 | |
... | ... | @@ -641,6 +763,10 @@ int gdbserver_start(int port) |
641 | 763 | if (gdbserver_fd < 0) |
642 | 764 | return -1; |
643 | 765 | /* accept connections */ |
766 | +#ifdef CONFIG_USER_ONLY | |
767 | + gdb_accept (NULL, NULL, 0); | |
768 | +#else | |
644 | 769 | qemu_add_fd_read_handler(gdbserver_fd, NULL, gdb_accept, NULL); |
770 | +#endif | |
645 | 771 | return 0; |
646 | 772 | } | ... | ... |
gdbstub.h
0 โ 100644
linux-user/main.c
... | ... | @@ -278,6 +278,20 @@ void cpu_loop(CPUX86State *env) |
278 | 278 | case EXCP_INTERRUPT: |
279 | 279 | /* just indicate that signals should be handled asap */ |
280 | 280 | break; |
281 | + case EXCP_DEBUG: | |
282 | + { | |
283 | + int sig; | |
284 | + | |
285 | + sig = gdb_handlesig (env, TARGET_SIGTRAP); | |
286 | + if (sig) | |
287 | + { | |
288 | + info.si_signo = sig; | |
289 | + info.si_errno = 0; | |
290 | + info.si_code = TARGET_TRAP_BRKPT; | |
291 | + queue_signal(info.si_signo, &info); | |
292 | + } | |
293 | + } | |
294 | + break; | |
281 | 295 | default: |
282 | 296 | pc = env->segs[R_CS].base + env->eip; |
283 | 297 | fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", |
... | ... | @@ -379,6 +393,20 @@ void cpu_loop(CPUARMState *env) |
379 | 393 | queue_signal(info.si_signo, &info); |
380 | 394 | } |
381 | 395 | break; |
396 | + case EXCP_DEBUG: | |
397 | + { | |
398 | + int sig; | |
399 | + | |
400 | + sig = gdb_handlesig (env, TARGET_SIGTRAP); | |
401 | + if (sig) | |
402 | + { | |
403 | + info.si_signo = sig; | |
404 | + info.si_errno = 0; | |
405 | + info.si_code = TARGET_TRAP_BRKPT; | |
406 | + queue_signal(info.si_signo, &info); | |
407 | + } | |
408 | + } | |
409 | + break; | |
382 | 410 | default: |
383 | 411 | error: |
384 | 412 | fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", |
... | ... | @@ -529,6 +557,20 @@ void cpu_loop (CPUSPARCState *env) |
529 | 557 | break; |
530 | 558 | case 0x100: // XXX, why do we get these? |
531 | 559 | break; |
560 | + case EXCP_DEBUG: | |
561 | + { | |
562 | + int sig; | |
563 | + | |
564 | + sig = gdb_handlesig (env, TARGET_SIGTRAP); | |
565 | + if (sig) | |
566 | + { | |
567 | + info.si_signo = sig; | |
568 | + info.si_errno = 0; | |
569 | + info.si_code = TARGET_TRAP_BRKPT; | |
570 | + queue_signal(info.si_signo, &info); | |
571 | + } | |
572 | + } | |
573 | + break; | |
532 | 574 | default: |
533 | 575 | printf ("Unhandled trap: 0x%x\n", trapnr); |
534 | 576 | cpu_dump_state(env, stderr, fprintf, 0); |
... | ... | @@ -911,8 +953,20 @@ void cpu_loop(CPUPPCState *env) |
911 | 953 | case EXCP_INTERRUPT: |
912 | 954 | /* Don't know why this should ever happen... */ |
913 | 955 | break; |
914 | - case EXCP_DEBUG: | |
915 | - break; | |
956 | + case EXCP_DEBUG: | |
957 | + { | |
958 | + int sig; | |
959 | + | |
960 | + sig = gdb_handlesig (env, TARGET_SIGTRAP); | |
961 | + if (sig) | |
962 | + { | |
963 | + info.si_signo = sig; | |
964 | + info.si_errno = 0; | |
965 | + info.si_code = TARGET_TRAP_BRKPT; | |
966 | + queue_signal(info.si_signo, &info); | |
967 | + } | |
968 | + } | |
969 | + break; | |
916 | 970 | default: |
917 | 971 | fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", |
918 | 972 | trapnr); |
... | ... | @@ -930,10 +984,11 @@ void cpu_loop(CPUPPCState *env) |
930 | 984 | void usage(void) |
931 | 985 | { |
932 | 986 | printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n" |
933 | - "usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n" | |
987 | + "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] program [arguments...]\n" | |
934 | 988 | "Linux CPU emulator (compiled for %s emulation)\n" |
935 | 989 | "\n" |
936 | 990 | "-h print this help\n" |
991 | + "-g wait gdb connection to port %d\n" | |
937 | 992 | "-L path set the elf interpreter prefix (default=%s)\n" |
938 | 993 | "-s size set the stack size in bytes (default=%ld)\n" |
939 | 994 | "\n" |
... | ... | @@ -944,6 +999,7 @@ void usage(void) |
944 | 999 | "-d options activate log (logfile=%s)\n" |
945 | 1000 | "-p pagesize set the host page size to 'pagesize'\n", |
946 | 1001 | TARGET_ARCH, |
1002 | + DEFAULT_GDBSTUB_PORT, | |
947 | 1003 | interp_prefix, |
948 | 1004 | x86_stack_size, |
949 | 1005 | DEBUG_LOGFILE); |
... | ... | @@ -967,6 +1023,7 @@ int main(int argc, char **argv) |
967 | 1023 | CPUState *env; |
968 | 1024 | int optind; |
969 | 1025 | const char *r; |
1026 | + int use_gdbstub = 0; | |
970 | 1027 | |
971 | 1028 | if (argc <= 1) |
972 | 1029 | usage(); |
... | ... | @@ -1020,6 +1077,8 @@ int main(int argc, char **argv) |
1020 | 1077 | fprintf(stderr, "page size must be a power of two\n"); |
1021 | 1078 | exit(1); |
1022 | 1079 | } |
1080 | + } else if (!strcmp(r, "g")) { | |
1081 | + use_gdbstub = 1; | |
1023 | 1082 | } else |
1024 | 1083 | #ifdef USE_CODE_COPY |
1025 | 1084 | if (!strcmp(r, "no-code-copy")) { |
... | ... | @@ -1176,6 +1235,10 @@ int main(int argc, char **argv) |
1176 | 1235 | #error unsupported target CPU |
1177 | 1236 | #endif |
1178 | 1237 | |
1238 | + if (use_gdbstub) { | |
1239 | + gdbserver_start (DEFAULT_GDBSTUB_PORT); | |
1240 | + gdb_handlesig(env, 0); | |
1241 | + } | |
1179 | 1242 | cpu_loop(env); |
1180 | 1243 | /* never exits */ |
1181 | 1244 | return 0; | ... | ... |
linux-user/qemu.h
linux-user/signal.c
... | ... | @@ -1675,6 +1675,12 @@ void process_pending_signals(void *cpu_env) |
1675 | 1675 | k->first = q->next; |
1676 | 1676 | if (!k->first) |
1677 | 1677 | k->pending = 0; |
1678 | + | |
1679 | + sig = gdb_handlesig (cpu_env, sig); | |
1680 | + if (!sig) { | |
1681 | + fprintf (stderr, "Lost signal\n"); | |
1682 | + abort(); | |
1683 | + } | |
1678 | 1684 | |
1679 | 1685 | handler = k->sa._sa_handler; |
1680 | 1686 | if (handler == TARGET_SIG_DFL) { | ... | ... |
target-arm/cpu.h
... | ... | @@ -26,6 +26,8 @@ |
26 | 26 | |
27 | 27 | #include "softfloat.h" |
28 | 28 | |
29 | +#define TARGET_HAS_ICE 1 | |
30 | + | |
29 | 31 | #define EXCP_UDEF 1 /* undefined instruction */ |
30 | 32 | #define EXCP_SWI 2 /* software interrupt */ |
31 | 33 | #define EXCP_PREFETCH_ABORT 3 |
... | ... | @@ -62,6 +64,11 @@ typedef struct CPUARMState { |
62 | 64 | int user_mode_only; |
63 | 65 | uint32_t address; |
64 | 66 | |
67 | + /* ICE debug support. */ | |
68 | + target_ulong breakpoints[MAX_BREAKPOINTS]; | |
69 | + int nb_breakpoints; | |
70 | + int singlestep_enabled; | |
71 | + | |
65 | 72 | /* in order to avoid passing too many arguments to the memory |
66 | 73 | write helpers, we store some rarely used information in the CPU |
67 | 74 | context) */ | ... | ... |
target-arm/op.c
... | ... | @@ -858,6 +858,12 @@ void OPPROTO op_undef_insn(void) |
858 | 858 | cpu_loop_exit(); |
859 | 859 | } |
860 | 860 | |
861 | +void OPPROTO op_debug(void) | |
862 | +{ | |
863 | + env->exception_index = EXCP_DEBUG; | |
864 | + cpu_loop_exit(); | |
865 | +} | |
866 | + | |
861 | 867 | /* VFP support. We follow the convention used for VFP instrunctions: |
862 | 868 | Single precition routines have a "s" suffix, double precision a |
863 | 869 | "d" suffix. */ | ... | ... |
target-arm/translate.c
... | ... | @@ -2026,6 +2026,17 @@ static inline int gen_intermediate_code_internal(CPUState *env, |
2026 | 2026 | dc->pc = pc_start; |
2027 | 2027 | lj = -1; |
2028 | 2028 | do { |
2029 | + if (env->nb_breakpoints > 0) { | |
2030 | + for(j = 0; j < env->nb_breakpoints; j++) { | |
2031 | + if (env->breakpoints[j] == dc->pc) { | |
2032 | + gen_op_movl_T0_im((long)dc->pc); | |
2033 | + gen_op_movl_reg_TN[0][15](); | |
2034 | + gen_op_debug(); | |
2035 | + dc->is_jmp = DISAS_JUMP; | |
2036 | + break; | |
2037 | + } | |
2038 | + } | |
2039 | + } | |
2029 | 2040 | if (search_pc) { |
2030 | 2041 | j = gen_opc_ptr - gen_opc_buf; |
2031 | 2042 | if (lj < j) { |
... | ... | @@ -2040,7 +2051,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, |
2040 | 2051 | disas_thumb_insn(dc); |
2041 | 2052 | else |
2042 | 2053 | disas_arm_insn(env, dc); |
2043 | - } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && | |
2054 | + } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && | |
2055 | + !env->singlestep_enabled && | |
2044 | 2056 | (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); |
2045 | 2057 | switch(dc->is_jmp) { |
2046 | 2058 | case DISAS_JUMP_NEXT: | ... | ... |
target-i386/cpu.h
target-ppc/cpu.h
target-sparc/cpu.h
vl.h
... | ... | @@ -71,6 +71,7 @@ static inline char *realpath(const char *path, char *resolved_path) |
71 | 71 | #else |
72 | 72 | |
73 | 73 | #include "cpu.h" |
74 | +#include "gdbstub.h" | |
74 | 75 | |
75 | 76 | #endif /* !defined(QEMU_TOOL) */ |
76 | 77 | |
... | ... | @@ -829,10 +830,4 @@ const char *readline_get_history(unsigned int index); |
829 | 830 | void readline_start(const char *prompt, int is_password, |
830 | 831 | ReadLineFunc *readline_func, void *opaque); |
831 | 832 | |
832 | -/* gdbstub.c */ | |
833 | - | |
834 | -#define DEFAULT_GDBSTUB_PORT 1234 | |
835 | - | |
836 | -int gdbserver_start(int port); | |
837 | - | |
838 | 833 | #endif /* VL_H */ | ... | ... |