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 */ | ... | ... |