*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
*/
#include "config.h"
#include "qemu-common.h"
#include "qemu.h"
#else
+#include "monitor.h"
#include "qemu-char.h"
#include "sysemu.h"
#include "gdbstub.h"
#define MAX_PACKET_LENGTH 4096
#include "qemu_socket.h"
-#ifdef _WIN32
-/* XXX: these constants may be independent of the host ones even for Unix */
-#ifndef SIGTRAP
-#define SIGTRAP 5
+#include "kvm.h"
+
+
+enum {
+ GDB_SIGNAL_0 = 0,
+ GDB_SIGNAL_INT = 2,
+ GDB_SIGNAL_TRAP = 5,
+ GDB_SIGNAL_UNKNOWN = 143
+};
+
+#ifdef CONFIG_USER_ONLY
+
+/* Map target signal numbers to GDB protocol signal numbers and vice
+ * versa. For user emulation's currently supported systems, we can
+ * assume most signals are defined.
+ */
+
+static int gdb_signal_table[] = {
+ 0,
+ TARGET_SIGHUP,
+ TARGET_SIGINT,
+ TARGET_SIGQUIT,
+ TARGET_SIGILL,
+ TARGET_SIGTRAP,
+ TARGET_SIGABRT,
+ -1, /* SIGEMT */
+ TARGET_SIGFPE,
+ TARGET_SIGKILL,
+ TARGET_SIGBUS,
+ TARGET_SIGSEGV,
+ TARGET_SIGSYS,
+ TARGET_SIGPIPE,
+ TARGET_SIGALRM,
+ TARGET_SIGTERM,
+ TARGET_SIGURG,
+ TARGET_SIGSTOP,
+ TARGET_SIGTSTP,
+ TARGET_SIGCONT,
+ TARGET_SIGCHLD,
+ TARGET_SIGTTIN,
+ TARGET_SIGTTOU,
+ TARGET_SIGIO,
+ TARGET_SIGXCPU,
+ TARGET_SIGXFSZ,
+ TARGET_SIGVTALRM,
+ TARGET_SIGPROF,
+ TARGET_SIGWINCH,
+ -1, /* SIGLOST */
+ TARGET_SIGUSR1,
+ TARGET_SIGUSR2,
+#ifdef TARGET_SIGPWR
+ TARGET_SIGPWR,
+#else
+ -1,
#endif
-#ifndef SIGINT
-#define SIGINT 2
+ -1, /* SIGPOLL */
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+#ifdef __SIGRTMIN
+ __SIGRTMIN + 1,
+ __SIGRTMIN + 2,
+ __SIGRTMIN + 3,
+ __SIGRTMIN + 4,
+ __SIGRTMIN + 5,
+ __SIGRTMIN + 6,
+ __SIGRTMIN + 7,
+ __SIGRTMIN + 8,
+ __SIGRTMIN + 9,
+ __SIGRTMIN + 10,
+ __SIGRTMIN + 11,
+ __SIGRTMIN + 12,
+ __SIGRTMIN + 13,
+ __SIGRTMIN + 14,
+ __SIGRTMIN + 15,
+ __SIGRTMIN + 16,
+ __SIGRTMIN + 17,
+ __SIGRTMIN + 18,
+ __SIGRTMIN + 19,
+ __SIGRTMIN + 20,
+ __SIGRTMIN + 21,
+ __SIGRTMIN + 22,
+ __SIGRTMIN + 23,
+ __SIGRTMIN + 24,
+ __SIGRTMIN + 25,
+ __SIGRTMIN + 26,
+ __SIGRTMIN + 27,
+ __SIGRTMIN + 28,
+ __SIGRTMIN + 29,
+ __SIGRTMIN + 30,
+ __SIGRTMIN + 31,
+ -1, /* SIGCANCEL */
+ __SIGRTMIN,
+ __SIGRTMIN + 32,
+ __SIGRTMIN + 33,
+ __SIGRTMIN + 34,
+ __SIGRTMIN + 35,
+ __SIGRTMIN + 36,
+ __SIGRTMIN + 37,
+ __SIGRTMIN + 38,
+ __SIGRTMIN + 39,
+ __SIGRTMIN + 40,
+ __SIGRTMIN + 41,
+ __SIGRTMIN + 42,
+ __SIGRTMIN + 43,
+ __SIGRTMIN + 44,
+ __SIGRTMIN + 45,
+ __SIGRTMIN + 46,
+ __SIGRTMIN + 47,
+ __SIGRTMIN + 48,
+ __SIGRTMIN + 49,
+ __SIGRTMIN + 50,
+ __SIGRTMIN + 51,
+ __SIGRTMIN + 52,
+ __SIGRTMIN + 53,
+ __SIGRTMIN + 54,
+ __SIGRTMIN + 55,
+ __SIGRTMIN + 56,
+ __SIGRTMIN + 57,
+ __SIGRTMIN + 58,
+ __SIGRTMIN + 59,
+ __SIGRTMIN + 60,
+ __SIGRTMIN + 61,
+ __SIGRTMIN + 62,
+ __SIGRTMIN + 63,
+ __SIGRTMIN + 64,
+ __SIGRTMIN + 65,
+ __SIGRTMIN + 66,
+ __SIGRTMIN + 67,
+ __SIGRTMIN + 68,
+ __SIGRTMIN + 69,
+ __SIGRTMIN + 70,
+ __SIGRTMIN + 71,
+ __SIGRTMIN + 72,
+ __SIGRTMIN + 73,
+ __SIGRTMIN + 74,
+ __SIGRTMIN + 75,
+ __SIGRTMIN + 76,
+ __SIGRTMIN + 77,
+ __SIGRTMIN + 78,
+ __SIGRTMIN + 79,
+ __SIGRTMIN + 80,
+ __SIGRTMIN + 81,
+ __SIGRTMIN + 82,
+ __SIGRTMIN + 83,
+ __SIGRTMIN + 84,
+ __SIGRTMIN + 85,
+ __SIGRTMIN + 86,
+ __SIGRTMIN + 87,
+ __SIGRTMIN + 88,
+ __SIGRTMIN + 89,
+ __SIGRTMIN + 90,
+ __SIGRTMIN + 91,
+ __SIGRTMIN + 92,
+ __SIGRTMIN + 93,
+ __SIGRTMIN + 94,
+ __SIGRTMIN + 95,
+ -1, /* SIGINFO */
+ -1, /* UNKNOWN */
+ -1, /* DEFAULT */
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1
#endif
+};
#else
-#include <signal.h>
+/* In system mode we only need SIGINT and SIGTRAP; other signals
+ are not yet supported. */
+
+enum {
+ TARGET_SIGINT = 2,
+ TARGET_SIGTRAP = 5
+};
+
+static int gdb_signal_table[] = {
+ -1,
+ -1,
+ TARGET_SIGINT,
+ -1,
+ -1,
+ TARGET_SIGTRAP
+};
+#endif
+
+#ifdef CONFIG_USER_ONLY
+static int target_signal_to_gdb (int sig)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE (gdb_signal_table); i++)
+ if (gdb_signal_table[i] == sig)
+ return i;
+ return GDB_SIGNAL_UNKNOWN;
+}
#endif
+static int gdb_signal_to_target (int sig)
+{
+ if (sig < ARRAY_SIZE (gdb_signal_table))
+ return gdb_signal_table[sig];
+ else
+ return -1;
+}
+
//#define DEBUG_GDB
typedef struct GDBRegisterState {
} GDBRegisterState;
enum RSState {
+ RS_INACTIVE,
RS_IDLE,
RS_GETLINE,
RS_CHKSUM1,
int running_state;
#else
CharDriverState *chr;
+ CharDriverState *mon_chr;
#endif
} GDBState;
#elif defined (TARGET_PPC)
+/* Old gdb always expects FP registers. Newer (xml-aware) gdb only
+ expects whatever the target description contains. Due to a
+ historical mishap the FP registers appear in between core integer
+ regs and PC, MSR, CR, and so forth. We hack round this by giving the
+ FP regs zero size when talking to a newer gdb. */
#define NUM_CORE_REGS 71
+#if defined (TARGET_PPC64)
+#define GDB_CORE_XML "power64-core.xml"
+#else
+#define GDB_CORE_XML "power-core.xml"
+#endif
static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
{
GET_REGL(env->gpr[n]);
} else if (n < 64) {
/* fprs */
+ if (gdb_has_xml)
+ return 0;
stfq_p(mem_buf, env->fpr[n-32]);
return 8;
} else {
case 67: GET_REGL(env->lr);
case 68: GET_REGL(env->ctr);
case 69: GET_REGL(env->xer);
- case 70: GET_REG32(0); /* fpscr */
+ case 70:
+ {
+ if (gdb_has_xml)
+ return 0;
+ GET_REG32(0); /* fpscr */
+ }
}
}
return 0;
return sizeof(target_ulong);
} else if (n < 64) {
/* fprs */
+ if (gdb_has_xml)
+ return 0;
env->fpr[n-32] = ldfq_p(mem_buf);
return 8;
} else {
return sizeof(target_ulong);
case 70:
/* fpscr */
+ if (gdb_has_xml)
+ return 0;
return 4;
}
}
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
#define NUM_CORE_REGS 86
#else
-#define NUM_CORE_REGS 73
+#define NUM_CORE_REGS 72
#endif
#ifdef TARGET_ABI32
case 69: GET_REGA(env->npc);
case 70: GET_REGA(env->fsr);
case 71: GET_REGA(0); /* csr */
- case 72: GET_REGA(0);
+ default: GET_REGA(0);
}
#else
if (n < 64) {
return 4;
}
+#elif defined (TARGET_ALPHA)
+
+#define NUM_CORE_REGS 65
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+ if (n < 31) {
+ GET_REGL(env->ir[n]);
+ }
+ else if (n == 31) {
+ GET_REGL(0);
+ }
+ else if (n<63) {
+ uint64_t val;
+
+ val=*((uint64_t *)&env->fir[n-32]);
+ GET_REGL(val);
+ }
+ else if (n==63) {
+ GET_REGL(env->fpcr);
+ }
+ else if (n==64) {
+ GET_REGL(env->pc);
+ }
+ else {
+ GET_REGL(0);
+ }
+
+ return 0;
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+ target_ulong tmp;
+ tmp = ldtul_p(mem_buf);
+
+ if (n < 31) {
+ env->ir[n] = tmp;
+ }
+
+ if (n > 31 && n < 63) {
+ env->fir[n - 32] = ldfl_p(mem_buf);
+ }
+
+ if (n == 64 ) {
+ env->pc=tmp;
+ }
+
+ return 8;
+}
#else
#define NUM_CORE_REGS 0
}
}
-/* GDB breakpoint/watchpoint types */
-#define GDB_BREAKPOINT_SW 0
-#define GDB_BREAKPOINT_HW 1
-#define GDB_WATCHPOINT_WRITE 2
-#define GDB_WATCHPOINT_READ 3
-#define GDB_WATCHPOINT_ACCESS 4
-
#ifndef CONFIG_USER_ONLY
static const int xlat_gdb_type[] = {
[GDB_WATCHPOINT_WRITE] = BP_GDB | BP_MEM_WRITE,
CPUState *env;
int err = 0;
+ if (kvm_enabled())
+ return kvm_insert_breakpoint(gdbserver_state->c_cpu, addr, len, type);
+
switch (type) {
case GDB_BREAKPOINT_SW:
case GDB_BREAKPOINT_HW:
CPUState *env;
int err = 0;
+ if (kvm_enabled())
+ return kvm_remove_breakpoint(gdbserver_state->c_cpu, addr, len, type);
+
switch (type) {
case GDB_BREAKPOINT_SW:
case GDB_BREAKPOINT_HW:
{
CPUState *env;
+ if (kvm_enabled()) {
+ kvm_remove_all_breakpoints(gdbserver_state->c_cpu);
+ return;
+ }
+
for (env = first_cpu; env != NULL; env = env->next_cpu) {
cpu_breakpoint_remove_all(env, BP_GDB);
#ifndef CONFIG_USER_ONLY
switch(ch) {
case '?':
/* TODO: Make this return the correct value for user-mode. */
- snprintf(buf, sizeof(buf), "T%02xthread:%02x;", SIGTRAP,
+ snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP,
s->c_cpu->cpu_index+1);
put_packet(s, buf);
/* Remove all the breakpoints when this query is issued,
addr = strtoull(p, (char **)&p, 16);
#if defined(TARGET_I386)
s->c_cpu->eip = addr;
+ cpu_synchronize_state(s->c_cpu, 1);
#elif defined (TARGET_PPC)
s->c_cpu->nip = addr;
#elif defined (TARGET_SPARC)
s->c_cpu->active_tc.PC = addr;
#elif defined (TARGET_CRIS)
s->c_cpu->pc = addr;
+#elif defined (TARGET_ALPHA)
+ s->c_cpu->pc = addr;
#endif
}
+ s->signal = 0;
gdb_continue(s);
return RS_IDLE;
case 'C':
- s->signal = strtoul(p, (char **)&p, 16);
+ s->signal = gdb_signal_to_target (strtoul(p, (char **)&p, 16));
+ if (s->signal == -1)
+ s->signal = 0;
gdb_continue(s);
return RS_IDLE;
case 'k':
addr = strtoull(p, (char **)&p, 16);
#if defined(TARGET_I386)
s->c_cpu->eip = addr;
+ cpu_synchronize_state(s->c_cpu, 1);
#elif defined (TARGET_PPC)
s->c_cpu->nip = addr;
#elif defined (TARGET_SPARC)
s->c_cpu->active_tc.PC = addr;
#elif defined (TARGET_CRIS)
s->c_cpu->pc = addr;
+#elif defined (TARGET_ALPHA)
+ s->c_cpu->pc = addr;
#endif
}
cpu_single_step(s->c_cpu, sstep_flags);
}
break;
case 'g':
+ cpu_synchronize_state(s->g_cpu, 0);
len = 0;
for (addr = 0; addr < num_g_regs; addr++) {
reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr);
len -= reg_size;
registers += reg_size;
}
+ cpu_synchronize_state(s->g_cpu, 1);
put_packet(s, "OK");
break;
case 'm':
thread = strtoull(p+16, (char **)&p, 16);
for (env = first_cpu; env != NULL; env = env->next_cpu)
if (env->cpu_index + 1 == thread) {
+ cpu_synchronize_state(env, 0);
len = snprintf((char *)mem_buf, sizeof(mem_buf),
"CPU#%d [%s]", env->cpu_index,
env->halted ? "halted " : "running");
}
break;
}
-#ifdef CONFIG_LINUX_USER
+#ifdef CONFIG_USER_ONLY
else if (strncmp(p, "Offsets", 7) == 0) {
TaskState *ts = s->c_cpu->opaque;
put_packet(s, buf);
break;
}
-#endif
+#else /* !CONFIG_USER_ONLY */
+ else if (strncmp(p, "Rcmd,", 5) == 0) {
+ int len = strlen(p + 5);
+
+ if ((len % 2) != 0) {
+ put_packet(s, "E01");
+ break;
+ }
+ hextomem(mem_buf, p + 5, len);
+ len = len / 2;
+ mem_buf[len++] = 0;
+ qemu_chr_read(s->mon_chr, mem_buf, len);
+ put_packet(s, "OK");
+ break;
+ }
+#endif /* !CONFIG_USER_ONLY */
if (strncmp(p, "Supported", 9) == 0) {
snprintf(buf, sizeof(buf), "PacketSize=%x", MAX_PACKET_LENGTH);
#ifdef GDB_CORE_XML
}
#ifndef CONFIG_USER_ONLY
-static void gdb_vm_stopped(void *opaque, int reason)
+static void gdb_vm_state_change(void *opaque, int running, int reason)
{
GDBState *s = gdbserver_state;
CPUState *env = s->c_cpu;
const char *type;
int ret;
- if (s->state == RS_SYSCALL)
+ if (running || (reason != EXCP_DEBUG && reason != EXCP_INTERRUPT) ||
+ s->state == RS_INACTIVE || s->state == RS_SYSCALL)
return;
/* disable single step if it was enable */
}
snprintf(buf, sizeof(buf),
"T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";",
- SIGTRAP, env->cpu_index+1, type,
+ GDB_SIGNAL_TRAP, env->cpu_index+1, type,
env->watchpoint_hit->vaddr);
put_packet(s, buf);
env->watchpoint_hit = NULL;
return;
}
tb_flush(env);
- ret = SIGTRAP;
- } else if (reason == EXCP_INTERRUPT) {
- ret = SIGINT;
+ ret = GDB_SIGNAL_TRAP;
} else {
- ret = 0;
+ ret = GDB_SIGNAL_INT;
}
snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, env->cpu_index+1);
put_packet(s, buf);
#ifdef CONFIG_USER_ONLY
gdb_handlesig(s->c_cpu, 0);
#else
- cpu_interrupt(s->c_cpu, CPU_INTERRUPT_EXIT);
+ cpu_exit(s->c_cpu);
#endif
}
}
#ifdef CONFIG_USER_ONLY
+int
+gdb_queuesig (void)
+{
+ GDBState *s;
+
+ s = gdbserver_state;
+
+ if (gdbserver_fd < 0 || s->fd < 0)
+ return 0;
+ else
+ return 1;
+}
+
int
gdb_handlesig (CPUState *env, int sig)
{
if (sig != 0)
{
- snprintf(buf, sizeof(buf), "S%02x", sig);
+ snprintf(buf, sizeof(buf), "S%02x", target_signal_to_gdb (sig));
put_packet(s, buf);
}
/* put_packet() might have detected that the peer terminated the
put_packet(s, buf);
}
+/* Tell the remote gdb that the process has exited due to SIG. */
+void gdb_signalled(CPUState *env, int sig)
+{
+ GDBState *s;
+ char buf[4];
+
+ s = gdbserver_state;
+ if (gdbserver_fd < 0 || s->fd < 0)
+ return;
+
+ snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb (sig));
+ put_packet(s, buf);
+}
static void gdb_accept(void)
{
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
s = qemu_mallocz(sizeof(GDBState));
- if (!s) {
- errno = ENOMEM;
- perror("accept");
- return;
- }
-
- memset (s, 0, sizeof (GDBState));
s->c_cpu = first_cpu;
s->g_cpu = first_cpu;
s->fd = fd;
gdb_accept();
return 0;
}
+
+/* Disable gdb stub for child processes. */
+void gdbserver_fork(CPUState *env)
+{
+ GDBState *s = gdbserver_state;
+ if (gdbserver_fd < 0 || s->fd < 0)
+ return;
+ close(s->fd);
+ s->fd = -1;
+ cpu_breakpoint_remove_all(env, BP_GDB);
+ cpu_watchpoint_remove_all(env, BP_GDB);
+}
#else
static int gdb_chr_can_receive(void *opaque)
{
}
}
-int gdbserver_start(const char *port)
+static void gdb_monitor_output(GDBState *s, const char *msg, int len)
{
- GDBState *s;
- char gdbstub_port_name[128];
- int port_num;
- char *p;
- CharDriverState *chr;
+ char buf[MAX_PACKET_LENGTH];
- if (!port || !*port)
- return -1;
+ buf[0] = 'O';
+ if (len > (MAX_PACKET_LENGTH/2) - 1)
+ len = (MAX_PACKET_LENGTH/2) - 1;
+ memtohex(buf + 1, (uint8_t *)msg, len);
+ put_packet(s, buf);
+}
+
+static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+ const char *p = (const char *)buf;
+ int max_sz;
- port_num = strtol(port, &p, 10);
- if (*p == 0) {
- /* A numeric value is interpreted as a port number. */
- snprintf(gdbstub_port_name, sizeof(gdbstub_port_name),
- "tcp::%d,nowait,nodelay,server", port_num);
- port = gdbstub_port_name;
+ max_sz = (sizeof(gdbserver_state->last_packet) - 2) / 2;
+ for (;;) {
+ if (len <= max_sz) {
+ gdb_monitor_output(gdbserver_state, p, len);
+ break;
+ }
+ gdb_monitor_output(gdbserver_state, p, max_sz);
+ p += max_sz;
+ len -= max_sz;
}
+ return len;
+}
- chr = qemu_chr_open("gdb", port);
- if (!chr)
+#ifndef _WIN32
+static void gdb_sigterm_handler(int signal)
+{
+ if (vm_running)
+ vm_stop(EXCP_INTERRUPT);
+}
+#endif
+
+int gdbserver_start(const char *device)
+{
+ GDBState *s;
+ char gdbstub_device_name[128];
+ CharDriverState *chr = NULL;
+ CharDriverState *mon_chr;
+
+ if (!device)
return -1;
+ if (strcmp(device, "none") != 0) {
+ if (strstart(device, "tcp:", NULL)) {
+ /* enforce required TCP attributes */
+ snprintf(gdbstub_device_name, sizeof(gdbstub_device_name),
+ "%s,nowait,nodelay,server", device);
+ device = gdbstub_device_name;
+ }
+#ifndef _WIN32
+ else if (strcmp(device, "stdio") == 0) {
+ struct sigaction act;
- s = qemu_mallocz(sizeof(GDBState));
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = gdb_sigterm_handler;
+ sigaction(SIGINT, &act, NULL);
+ }
+#endif
+ chr = qemu_chr_open("gdb", device, NULL);
+ if (!chr)
+ return -1;
+
+ qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive,
+ gdb_chr_event, NULL);
+ }
+
+ s = gdbserver_state;
if (!s) {
- return -1;
+ s = qemu_mallocz(sizeof(GDBState));
+ gdbserver_state = s;
+
+ qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
+
+ /* Initialize a monitor terminal for gdb */
+ mon_chr = qemu_mallocz(sizeof(*mon_chr));
+ mon_chr->chr_write = gdb_monitor_write;
+ monitor_init(mon_chr, 0);
+ } else {
+ if (s->chr)
+ qemu_chr_close(s->chr);
+ mon_chr = s->mon_chr;
+ memset(s, 0, sizeof(GDBState));
}
s->c_cpu = first_cpu;
s->g_cpu = first_cpu;
s->chr = chr;
- gdbserver_state = s;
- qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive,
- gdb_chr_event, NULL);
- qemu_add_vm_stop_handler(gdb_vm_stopped, NULL);
+ s->state = chr ? RS_IDLE : RS_INACTIVE;
+ s->mon_chr = mon_chr;
+
return 0;
}
#endif