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