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,7 +1076,7 @@ static void tb_reset_jump_recursive(TranslationBlock *tb) | ||
| 1076 | tb_reset_jump_recursive2(tb, 1); | 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 | static void breakpoint_invalidate(CPUState *env, target_ulong pc) | 1080 | static void breakpoint_invalidate(CPUState *env, target_ulong pc) |
| 1081 | { | 1081 | { |
| 1082 | target_ulong phys_addr; | 1082 | target_ulong phys_addr; |
| @@ -1090,7 +1090,7 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc) | @@ -1090,7 +1090,7 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc) | ||
| 1090 | breakpoint is reached */ | 1090 | breakpoint is reached */ |
| 1091 | int cpu_breakpoint_insert(CPUState *env, target_ulong pc) | 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 | int i; | 1094 | int i; |
| 1095 | 1095 | ||
| 1096 | for(i = 0; i < env->nb_breakpoints; i++) { | 1096 | for(i = 0; i < env->nb_breakpoints; i++) { |
| @@ -1112,7 +1112,7 @@ int cpu_breakpoint_insert(CPUState *env, target_ulong pc) | @@ -1112,7 +1112,7 @@ int cpu_breakpoint_insert(CPUState *env, target_ulong pc) | ||
| 1112 | /* remove a breakpoint */ | 1112 | /* remove a breakpoint */ |
| 1113 | int cpu_breakpoint_remove(CPUState *env, target_ulong pc) | 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 | int i; | 1116 | int i; |
| 1117 | for(i = 0; i < env->nb_breakpoints; i++) { | 1117 | for(i = 0; i < env->nb_breakpoints; i++) { |
| 1118 | if (env->breakpoints[i] == pc) | 1118 | if (env->breakpoints[i] == pc) |
| @@ -1120,9 +1120,9 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc) | @@ -1120,9 +1120,9 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc) | ||
| 1120 | } | 1120 | } |
| 1121 | return -1; | 1121 | return -1; |
| 1122 | found: | 1122 | found: |
| 1123 | - memmove(&env->breakpoints[i], &env->breakpoints[i + 1], | ||
| 1124 | - (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0])); | ||
| 1125 | env->nb_breakpoints--; | 1123 | env->nb_breakpoints--; |
| 1124 | + if (i < env->nb_breakpoints) | ||
| 1125 | + env->breakpoints[i] = env->breakpoints[env->nb_breakpoints]; | ||
| 1126 | 1126 | ||
| 1127 | breakpoint_invalidate(env, pc); | 1127 | breakpoint_invalidate(env, pc); |
| 1128 | return 0; | 1128 | return 0; |
| @@ -1135,7 +1135,7 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc) | @@ -1135,7 +1135,7 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc) | ||
| 1135 | CPU loop after each instruction */ | 1135 | CPU loop after each instruction */ |
| 1136 | void cpu_single_step(CPUState *env, int enabled) | 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 | if (env->singlestep_enabled != enabled) { | 1139 | if (env->singlestep_enabled != enabled) { |
| 1140 | env->singlestep_enabled = enabled; | 1140 | env->singlestep_enabled = enabled; |
| 1141 | /* must flush all the translated code to avoid inconsistancies */ | 1141 | /* must flush all the translated code to avoid inconsistancies */ |
gdbstub.c
| @@ -17,7 +17,18 @@ | @@ -17,7 +17,18 @@ | ||
| 17 | * License along with this library; if not, write to the Free Software | 17 | * License along with this library; if not, write to the Free Software |
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 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 | #include "vl.h" | 30 | #include "vl.h" |
| 31 | +#endif | ||
| 21 | 32 | ||
| 22 | #include <sys/socket.h> | 33 | #include <sys/socket.h> |
| 23 | #include <netinet/in.h> | 34 | #include <netinet/in.h> |
| @@ -31,9 +42,10 @@ enum RSState { | @@ -31,9 +42,10 @@ enum RSState { | ||
| 31 | RS_GETLINE, | 42 | RS_GETLINE, |
| 32 | RS_CHKSUM1, | 43 | RS_CHKSUM1, |
| 33 | RS_CHKSUM2, | 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 | typedef struct GDBState { | 50 | typedef struct GDBState { |
| 39 | enum RSState state; | 51 | enum RSState state; |
| @@ -43,6 +55,11 @@ typedef struct GDBState { | @@ -43,6 +55,11 @@ typedef struct GDBState { | ||
| 43 | int line_csum; | 55 | int line_csum; |
| 44 | } GDBState; | 56 | } GDBState; |
| 45 | 57 | ||
| 58 | +#ifdef CONFIG_USER_ONLY | ||
| 59 | +/* XXX: remove this hack. */ | ||
| 60 | +static GDBState gdbserver_state; | ||
| 61 | +#endif | ||
| 62 | + | ||
| 46 | static int get_char(GDBState *s) | 63 | static int get_char(GDBState *s) |
| 47 | { | 64 | { |
| 48 | uint8_t ch; | 65 | uint8_t ch; |
| @@ -330,8 +347,47 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) | @@ -330,8 +347,47 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) | ||
| 330 | env->npc = tswapl(registers[69]); | 347 | env->npc = tswapl(registers[69]); |
| 331 | env->fsr = tswapl(registers[70]); | 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 | static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) | 391 | static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) |
| 336 | { | 392 | { |
| 337 | return 0; | 393 | return 0; |
| @@ -343,10 +399,8 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) | @@ -343,10 +399,8 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) | ||
| 343 | 399 | ||
| 344 | #endif | 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 | const char *p; | 404 | const char *p; |
| 351 | int ch, reg_size, type; | 405 | int ch, reg_size, type; |
| 352 | char buf[4096]; | 406 | char buf[4096]; |
| @@ -361,6 +415,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) | @@ -361,6 +415,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) | ||
| 361 | ch = *p++; | 415 | ch = *p++; |
| 362 | switch(ch) { | 416 | switch(ch) { |
| 363 | case '?': | 417 | case '?': |
| 418 | + /* TODO: Make this return the correct value for user-mode. */ | ||
| 364 | snprintf(buf, sizeof(buf), "S%02x", SIGTRAP); | 419 | snprintf(buf, sizeof(buf), "S%02x", SIGTRAP); |
| 365 | put_packet(s, buf); | 420 | put_packet(s, buf); |
| 366 | break; | 421 | break; |
| @@ -376,8 +431,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) | @@ -376,8 +431,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) | ||
| 376 | env->npc = addr + 4; | 431 | env->npc = addr + 4; |
| 377 | #endif | 432 | #endif |
| 378 | } | 433 | } |
| 379 | - vm_start(); | ||
| 380 | - break; | 434 | + return RS_CONTINUE; |
| 381 | case 's': | 435 | case 's': |
| 382 | if (*p != '\0') { | 436 | if (*p != '\0') { |
| 383 | addr = strtoul(p, (char **)&p, 16); | 437 | addr = strtoul(p, (char **)&p, 16); |
| @@ -391,8 +445,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) | @@ -391,8 +445,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) | ||
| 391 | #endif | 445 | #endif |
| 392 | } | 446 | } |
| 393 | cpu_single_step(env, 1); | 447 | cpu_single_step(env, 1); |
| 394 | - vm_start(); | ||
| 395 | - break; | 448 | + return RS_CONTINUE; |
| 396 | case 'g': | 449 | case 'g': |
| 397 | reg_size = cpu_gdb_read_registers(env, mem_buf); | 450 | reg_size = cpu_gdb_read_registers(env, mem_buf); |
| 398 | memtohex(buf, mem_buf, reg_size); | 451 | memtohex(buf, mem_buf, reg_size); |
| @@ -472,6 +525,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) | @@ -472,6 +525,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) | ||
| 472 | 525 | ||
| 473 | extern void tb_flush(CPUState *env); | 526 | extern void tb_flush(CPUState *env); |
| 474 | 527 | ||
| 528 | +#ifndef CONFIG_USER_ONLY | ||
| 475 | static void gdb_vm_stopped(void *opaque, int reason) | 529 | static void gdb_vm_stopped(void *opaque, int reason) |
| 476 | { | 530 | { |
| 477 | GDBState *s = opaque; | 531 | GDBState *s = opaque; |
| @@ -490,17 +544,20 @@ static void gdb_vm_stopped(void *opaque, int reason) | @@ -490,17 +544,20 @@ static void gdb_vm_stopped(void *opaque, int reason) | ||
| 490 | snprintf(buf, sizeof(buf), "S%02x", ret); | 544 | snprintf(buf, sizeof(buf), "S%02x", ret); |
| 491 | put_packet(s, buf); | 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 | int i, csum; | 551 | int i, csum; |
| 497 | char reply[1]; | 552 | char reply[1]; |
| 498 | 553 | ||
| 554 | +#ifndef CONFIG_USER_ONLY | ||
| 499 | if (vm_running) { | 555 | if (vm_running) { |
| 500 | /* when the CPU is running, we cannot do anything except stop | 556 | /* when the CPU is running, we cannot do anything except stop |
| 501 | it when receiving a char */ | 557 | it when receiving a char */ |
| 502 | vm_stop(EXCP_INTERRUPT); | 558 | vm_stop(EXCP_INTERRUPT); |
| 503 | } else { | 559 | } else { |
| 560 | +#endif | ||
| 504 | switch(s->state) { | 561 | switch(s->state) { |
| 505 | case RS_IDLE: | 562 | case RS_IDLE: |
| 506 | if (ch == '$') { | 563 | if (ch == '$') { |
| @@ -535,13 +592,67 @@ static void gdb_read_byte(GDBState *s, int ch) | @@ -535,13 +592,67 @@ static void gdb_read_byte(GDBState *s, int ch) | ||
| 535 | } else { | 592 | } else { |
| 536 | reply[0] = '+'; | 593 | reply[0] = '+'; |
| 537 | put_buffer(s, reply, 1); | 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 | break; | 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 | static int gdb_can_read(void *opaque) | 656 | static int gdb_can_read(void *opaque) |
| 546 | { | 657 | { |
| 547 | return 256; | 658 | return 256; |
| @@ -559,10 +670,12 @@ static void gdb_read(void *opaque, const uint8_t *buf, int size) | @@ -559,10 +670,12 @@ static void gdb_read(void *opaque, const uint8_t *buf, int size) | ||
| 559 | vm_start(); | 670 | vm_start(); |
| 560 | } else { | 671 | } else { |
| 561 | for(i = 0; i < size; i++) | 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 | static void gdb_accept(void *opaque, const uint8_t *buf, int size) | 679 | static void gdb_accept(void *opaque, const uint8_t *buf, int size) |
| 567 | { | 680 | { |
| 568 | GDBState *s; | 681 | GDBState *s; |
| @@ -585,15 +698,21 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size) | @@ -585,15 +698,21 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size) | ||
| 585 | val = 1; | 698 | val = 1; |
| 586 | setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); | 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 | s = qemu_mallocz(sizeof(GDBState)); | 705 | s = qemu_mallocz(sizeof(GDBState)); |
| 589 | if (!s) { | 706 | if (!s) { |
| 590 | close(fd); | 707 | close(fd); |
| 591 | return; | 708 | return; |
| 592 | } | 709 | } |
| 710 | +#endif | ||
| 593 | s->fd = fd; | 711 | s->fd = fd; |
| 594 | 712 | ||
| 595 | fcntl(fd, F_SETFL, O_NONBLOCK); | 713 | fcntl(fd, F_SETFL, O_NONBLOCK); |
| 596 | 714 | ||
| 715 | +#ifndef CONFIG_USER_ONLY | ||
| 597 | /* stop the VM */ | 716 | /* stop the VM */ |
| 598 | vm_stop(EXCP_INTERRUPT); | 717 | vm_stop(EXCP_INTERRUPT); |
| 599 | 718 | ||
| @@ -601,6 +720,7 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size) | @@ -601,6 +720,7 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size) | ||
| 601 | qemu_add_fd_read_handler(s->fd, gdb_can_read, gdb_read, s); | 720 | qemu_add_fd_read_handler(s->fd, gdb_can_read, gdb_read, s); |
| 602 | /* when the VM is stopped, the following callback is called */ | 721 | /* when the VM is stopped, the following callback is called */ |
| 603 | qemu_add_vm_stop_handler(gdb_vm_stopped, s); | 722 | qemu_add_vm_stop_handler(gdb_vm_stopped, s); |
| 723 | +#endif | ||
| 604 | } | 724 | } |
| 605 | 725 | ||
| 606 | static int gdbserver_open(int port) | 726 | static int gdbserver_open(int port) |
| @@ -631,7 +751,9 @@ static int gdbserver_open(int port) | @@ -631,7 +751,9 @@ static int gdbserver_open(int port) | ||
| 631 | perror("listen"); | 751 | perror("listen"); |
| 632 | return -1; | 752 | return -1; |
| 633 | } | 753 | } |
| 754 | +#ifndef CONFIG_USER_ONLY | ||
| 634 | fcntl(fd, F_SETFL, O_NONBLOCK); | 755 | fcntl(fd, F_SETFL, O_NONBLOCK); |
| 756 | +#endif | ||
| 635 | return fd; | 757 | return fd; |
| 636 | } | 758 | } |
| 637 | 759 | ||
| @@ -641,6 +763,10 @@ int gdbserver_start(int port) | @@ -641,6 +763,10 @@ int gdbserver_start(int port) | ||
| 641 | if (gdbserver_fd < 0) | 763 | if (gdbserver_fd < 0) |
| 642 | return -1; | 764 | return -1; |
| 643 | /* accept connections */ | 765 | /* accept connections */ |
| 766 | +#ifdef CONFIG_USER_ONLY | ||
| 767 | + gdb_accept (NULL, NULL, 0); | ||
| 768 | +#else | ||
| 644 | qemu_add_fd_read_handler(gdbserver_fd, NULL, gdb_accept, NULL); | 769 | qemu_add_fd_read_handler(gdbserver_fd, NULL, gdb_accept, NULL); |
| 770 | +#endif | ||
| 645 | return 0; | 771 | return 0; |
| 646 | } | 772 | } |
gdbstub.h
0 โ 100644
linux-user/main.c
| @@ -278,6 +278,20 @@ void cpu_loop(CPUX86State *env) | @@ -278,6 +278,20 @@ void cpu_loop(CPUX86State *env) | ||
| 278 | case EXCP_INTERRUPT: | 278 | case EXCP_INTERRUPT: |
| 279 | /* just indicate that signals should be handled asap */ | 279 | /* just indicate that signals should be handled asap */ |
| 280 | break; | 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 | default: | 295 | default: |
| 282 | pc = env->segs[R_CS].base + env->eip; | 296 | pc = env->segs[R_CS].base + env->eip; |
| 283 | fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", | 297 | fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", |
| @@ -379,6 +393,20 @@ void cpu_loop(CPUARMState *env) | @@ -379,6 +393,20 @@ void cpu_loop(CPUARMState *env) | ||
| 379 | queue_signal(info.si_signo, &info); | 393 | queue_signal(info.si_signo, &info); |
| 380 | } | 394 | } |
| 381 | break; | 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 | default: | 410 | default: |
| 383 | error: | 411 | error: |
| 384 | fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", | 412 | fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", |
| @@ -529,6 +557,20 @@ void cpu_loop (CPUSPARCState *env) | @@ -529,6 +557,20 @@ void cpu_loop (CPUSPARCState *env) | ||
| 529 | break; | 557 | break; |
| 530 | case 0x100: // XXX, why do we get these? | 558 | case 0x100: // XXX, why do we get these? |
| 531 | break; | 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 | default: | 574 | default: |
| 533 | printf ("Unhandled trap: 0x%x\n", trapnr); | 575 | printf ("Unhandled trap: 0x%x\n", trapnr); |
| 534 | cpu_dump_state(env, stderr, fprintf, 0); | 576 | cpu_dump_state(env, stderr, fprintf, 0); |
| @@ -911,8 +953,20 @@ void cpu_loop(CPUPPCState *env) | @@ -911,8 +953,20 @@ void cpu_loop(CPUPPCState *env) | ||
| 911 | case EXCP_INTERRUPT: | 953 | case EXCP_INTERRUPT: |
| 912 | /* Don't know why this should ever happen... */ | 954 | /* Don't know why this should ever happen... */ |
| 913 | break; | 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 | default: | 970 | default: |
| 917 | fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", | 971 | fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", |
| 918 | trapnr); | 972 | trapnr); |
| @@ -930,10 +984,11 @@ void cpu_loop(CPUPPCState *env) | @@ -930,10 +984,11 @@ void cpu_loop(CPUPPCState *env) | ||
| 930 | void usage(void) | 984 | void usage(void) |
| 931 | { | 985 | { |
| 932 | printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n" | 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 | "Linux CPU emulator (compiled for %s emulation)\n" | 988 | "Linux CPU emulator (compiled for %s emulation)\n" |
| 935 | "\n" | 989 | "\n" |
| 936 | "-h print this help\n" | 990 | "-h print this help\n" |
| 991 | + "-g wait gdb connection to port %d\n" | ||
| 937 | "-L path set the elf interpreter prefix (default=%s)\n" | 992 | "-L path set the elf interpreter prefix (default=%s)\n" |
| 938 | "-s size set the stack size in bytes (default=%ld)\n" | 993 | "-s size set the stack size in bytes (default=%ld)\n" |
| 939 | "\n" | 994 | "\n" |
| @@ -944,6 +999,7 @@ void usage(void) | @@ -944,6 +999,7 @@ void usage(void) | ||
| 944 | "-d options activate log (logfile=%s)\n" | 999 | "-d options activate log (logfile=%s)\n" |
| 945 | "-p pagesize set the host page size to 'pagesize'\n", | 1000 | "-p pagesize set the host page size to 'pagesize'\n", |
| 946 | TARGET_ARCH, | 1001 | TARGET_ARCH, |
| 1002 | + DEFAULT_GDBSTUB_PORT, | ||
| 947 | interp_prefix, | 1003 | interp_prefix, |
| 948 | x86_stack_size, | 1004 | x86_stack_size, |
| 949 | DEBUG_LOGFILE); | 1005 | DEBUG_LOGFILE); |
| @@ -967,6 +1023,7 @@ int main(int argc, char **argv) | @@ -967,6 +1023,7 @@ int main(int argc, char **argv) | ||
| 967 | CPUState *env; | 1023 | CPUState *env; |
| 968 | int optind; | 1024 | int optind; |
| 969 | const char *r; | 1025 | const char *r; |
| 1026 | + int use_gdbstub = 0; | ||
| 970 | 1027 | ||
| 971 | if (argc <= 1) | 1028 | if (argc <= 1) |
| 972 | usage(); | 1029 | usage(); |
| @@ -1020,6 +1077,8 @@ int main(int argc, char **argv) | @@ -1020,6 +1077,8 @@ int main(int argc, char **argv) | ||
| 1020 | fprintf(stderr, "page size must be a power of two\n"); | 1077 | fprintf(stderr, "page size must be a power of two\n"); |
| 1021 | exit(1); | 1078 | exit(1); |
| 1022 | } | 1079 | } |
| 1080 | + } else if (!strcmp(r, "g")) { | ||
| 1081 | + use_gdbstub = 1; | ||
| 1023 | } else | 1082 | } else |
| 1024 | #ifdef USE_CODE_COPY | 1083 | #ifdef USE_CODE_COPY |
| 1025 | if (!strcmp(r, "no-code-copy")) { | 1084 | if (!strcmp(r, "no-code-copy")) { |
| @@ -1176,6 +1235,10 @@ int main(int argc, char **argv) | @@ -1176,6 +1235,10 @@ int main(int argc, char **argv) | ||
| 1176 | #error unsupported target CPU | 1235 | #error unsupported target CPU |
| 1177 | #endif | 1236 | #endif |
| 1178 | 1237 | ||
| 1238 | + if (use_gdbstub) { | ||
| 1239 | + gdbserver_start (DEFAULT_GDBSTUB_PORT); | ||
| 1240 | + gdb_handlesig(env, 0); | ||
| 1241 | + } | ||
| 1179 | cpu_loop(env); | 1242 | cpu_loop(env); |
| 1180 | /* never exits */ | 1243 | /* never exits */ |
| 1181 | return 0; | 1244 | return 0; |
linux-user/qemu.h
| @@ -9,6 +9,7 @@ | @@ -9,6 +9,7 @@ | ||
| 9 | 9 | ||
| 10 | #include "cpu.h" | 10 | #include "cpu.h" |
| 11 | #include "syscall.h" | 11 | #include "syscall.h" |
| 12 | +#include "gdbstub.h" | ||
| 12 | 13 | ||
| 13 | /* This struct is used to hold certain information about the image. | 14 | /* This struct is used to hold certain information about the image. |
| 14 | * Basically, it replicates in user space what would be certain | 15 | * Basically, it replicates in user space what would be certain |
linux-user/signal.c
| @@ -1675,6 +1675,12 @@ void process_pending_signals(void *cpu_env) | @@ -1675,6 +1675,12 @@ void process_pending_signals(void *cpu_env) | ||
| 1675 | k->first = q->next; | 1675 | k->first = q->next; |
| 1676 | if (!k->first) | 1676 | if (!k->first) |
| 1677 | k->pending = 0; | 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 | handler = k->sa._sa_handler; | 1685 | handler = k->sa._sa_handler; |
| 1680 | if (handler == TARGET_SIG_DFL) { | 1686 | if (handler == TARGET_SIG_DFL) { |
target-arm/cpu.h
| @@ -26,6 +26,8 @@ | @@ -26,6 +26,8 @@ | ||
| 26 | 26 | ||
| 27 | #include "softfloat.h" | 27 | #include "softfloat.h" |
| 28 | 28 | ||
| 29 | +#define TARGET_HAS_ICE 1 | ||
| 30 | + | ||
| 29 | #define EXCP_UDEF 1 /* undefined instruction */ | 31 | #define EXCP_UDEF 1 /* undefined instruction */ |
| 30 | #define EXCP_SWI 2 /* software interrupt */ | 32 | #define EXCP_SWI 2 /* software interrupt */ |
| 31 | #define EXCP_PREFETCH_ABORT 3 | 33 | #define EXCP_PREFETCH_ABORT 3 |
| @@ -62,6 +64,11 @@ typedef struct CPUARMState { | @@ -62,6 +64,11 @@ typedef struct CPUARMState { | ||
| 62 | int user_mode_only; | 64 | int user_mode_only; |
| 63 | uint32_t address; | 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 | /* in order to avoid passing too many arguments to the memory | 72 | /* in order to avoid passing too many arguments to the memory |
| 66 | write helpers, we store some rarely used information in the CPU | 73 | write helpers, we store some rarely used information in the CPU |
| 67 | context) */ | 74 | context) */ |
target-arm/op.c
| @@ -858,6 +858,12 @@ void OPPROTO op_undef_insn(void) | @@ -858,6 +858,12 @@ void OPPROTO op_undef_insn(void) | ||
| 858 | cpu_loop_exit(); | 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 | /* VFP support. We follow the convention used for VFP instrunctions: | 867 | /* VFP support. We follow the convention used for VFP instrunctions: |
| 862 | Single precition routines have a "s" suffix, double precision a | 868 | Single precition routines have a "s" suffix, double precision a |
| 863 | "d" suffix. */ | 869 | "d" suffix. */ |
target-arm/translate.c
| @@ -2026,6 +2026,17 @@ static inline int gen_intermediate_code_internal(CPUState *env, | @@ -2026,6 +2026,17 @@ static inline int gen_intermediate_code_internal(CPUState *env, | ||
| 2026 | dc->pc = pc_start; | 2026 | dc->pc = pc_start; |
| 2027 | lj = -1; | 2027 | lj = -1; |
| 2028 | do { | 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 | if (search_pc) { | 2040 | if (search_pc) { |
| 2030 | j = gen_opc_ptr - gen_opc_buf; | 2041 | j = gen_opc_ptr - gen_opc_buf; |
| 2031 | if (lj < j) { | 2042 | if (lj < j) { |
| @@ -2040,7 +2051,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, | @@ -2040,7 +2051,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, | ||
| 2040 | disas_thumb_insn(dc); | 2051 | disas_thumb_insn(dc); |
| 2041 | else | 2052 | else |
| 2042 | disas_arm_insn(env, dc); | 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 | (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); | 2056 | (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); |
| 2045 | switch(dc->is_jmp) { | 2057 | switch(dc->is_jmp) { |
| 2046 | case DISAS_JUMP_NEXT: | 2058 | case DISAS_JUMP_NEXT: |
target-i386/cpu.h
| @@ -34,6 +34,8 @@ | @@ -34,6 +34,8 @@ | ||
| 34 | close to the modifying instruction */ | 34 | close to the modifying instruction */ |
| 35 | #define TARGET_HAS_PRECISE_SMC | 35 | #define TARGET_HAS_PRECISE_SMC |
| 36 | 36 | ||
| 37 | +#define TARGET_HAS_ICE 1 | ||
| 38 | + | ||
| 37 | #include "cpu-defs.h" | 39 | #include "cpu-defs.h" |
| 38 | 40 | ||
| 39 | #include "softfloat.h" | 41 | #include "softfloat.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,6 +71,7 @@ static inline char *realpath(const char *path, char *resolved_path) | ||
| 71 | #else | 71 | #else |
| 72 | 72 | ||
| 73 | #include "cpu.h" | 73 | #include "cpu.h" |
| 74 | +#include "gdbstub.h" | ||
| 74 | 75 | ||
| 75 | #endif /* !defined(QEMU_TOOL) */ | 76 | #endif /* !defined(QEMU_TOOL) */ |
| 76 | 77 | ||
| @@ -829,10 +830,4 @@ const char *readline_get_history(unsigned int index); | @@ -829,10 +830,4 @@ const char *readline_get_history(unsigned int index); | ||
| 829 | void readline_start(const char *prompt, int is_password, | 830 | void readline_start(const char *prompt, int is_password, |
| 830 | ReadLineFunc *readline_func, void *opaque); | 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 | #endif /* VL_H */ | 833 | #endif /* VL_H */ |