#define MAX_PACKET_LENGTH 4096
#include "qemu_socket.h"
+#include "kvm.h"
enum {
} GDBRegisterState;
enum RSState {
+ RS_INACTIVE,
RS_IDLE,
RS_GETLINE,
RS_CHKSUM1,
static gdb_syscall_complete_cb gdb_current_syscall_cb;
-enum {
+static enum {
GDB_SYS_UNKNOWN,
GDB_SYS_ENABLED,
GDB_SYS_DISABLED,
return 4;
}
+#elif defined (TARGET_MICROBLAZE)
+
+#define NUM_CORE_REGS (32 + 5)
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+ if (n < 32) {
+ GET_REG32(env->regs[n]);
+ } else {
+ GET_REG32(env->sregs[n - 32]);
+ }
+ return 0;
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+ uint32_t tmp;
+
+ if (n > NUM_CORE_REGS)
+ return 0;
+
+ tmp = ldl_p(mem_buf);
+
+ if (n < 32) {
+ env->regs[n] = tmp;
+ } else {
+ env->sregs[n - 32] = tmp;
+ }
+ return 4;
+}
#elif defined (TARGET_CRIS)
#define NUM_CORE_REGS 49
GDB_CORE_XML);
for (r = first_cpu->gdb_regs; r; r = r->next) {
- strcat(target_xml, "<xi:include href=\"");
- strcat(target_xml, r->xml);
- strcat(target_xml, "\"/>");
+ pstrcat(target_xml, sizeof(target_xml), "<xi:include href=\"");
+ pstrcat(target_xml, sizeof(target_xml), r->xml);
+ pstrcat(target_xml, sizeof(target_xml), "\"/>");
}
- strcat(target_xml, "</target>");
+ pstrcat(target_xml, sizeof(target_xml), "</target>");
}
return target_xml;
}
}
}
-/* 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
}
}
+static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
+{
+#if defined(TARGET_I386)
+ s->c_cpu->eip = pc;
+ cpu_synchronize_state(s->c_cpu, 1);
+#elif defined (TARGET_PPC)
+ s->c_cpu->nip = pc;
+#elif defined (TARGET_SPARC)
+ s->c_cpu->pc = pc;
+ s->c_cpu->npc = pc + 4;
+#elif defined (TARGET_ARM)
+ s->c_cpu->regs[15] = pc;
+#elif defined (TARGET_SH4)
+ s->c_cpu->pc = pc;
+#elif defined (TARGET_MIPS)
+ s->c_cpu->active_tc.PC = pc;
+#elif defined (TARGET_MICROBLAZE)
+ s->c_cpu->sregs[SR_PC] = pc;
+#elif defined (TARGET_CRIS)
+ s->c_cpu->pc = pc;
+#elif defined (TARGET_ALPHA)
+ s->c_cpu->pc = pc;
+#endif
+}
+
+static inline int gdb_id(CPUState *env)
+{
+#if defined(CONFIG_USER_ONLY) && defined(USE_NPTL)
+ return env->host_tid;
+#else
+ return env->cpu_index + 1;
+#endif
+}
+
+static CPUState *find_cpu(uint32_t thread_id)
+{
+ CPUState *env;
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ if (gdb_id(env) == thread_id) {
+ return env;
+ }
+ }
+
+ return NULL;
+}
+
static int gdb_handle_packet(GDBState *s, const char *line_buf)
{
CPUState *env;
const char *p;
- int ch, reg_size, type, res, thread;
+ uint32_t thread;
+ int ch, reg_size, type, res;
char buf[MAX_PACKET_LENGTH];
uint8_t mem_buf[MAX_PACKET_LENGTH];
uint8_t *registers;
case '?':
/* TODO: Make this return the correct value for user-mode. */
snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP,
- s->c_cpu->cpu_index+1);
+ gdb_id(s->c_cpu));
put_packet(s, buf);
/* Remove all the breakpoints when this query is issued,
* because gdb is doing and initial connect and the state
case 'c':
if (*p != '\0') {
addr = strtoull(p, (char **)&p, 16);
-#if defined(TARGET_I386)
- s->c_cpu->eip = addr;
-#elif defined (TARGET_PPC)
- s->c_cpu->nip = addr;
-#elif defined (TARGET_SPARC)
- s->c_cpu->pc = addr;
- s->c_cpu->npc = addr + 4;
-#elif defined (TARGET_ARM)
- s->c_cpu->regs[15] = addr;
-#elif defined (TARGET_SH4)
- s->c_cpu->pc = addr;
-#elif defined (TARGET_MIPS)
- 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
+ gdb_set_cpu_pc(s, addr);
}
s->signal = 0;
gdb_continue(s);
case 's':
if (*p != '\0') {
addr = strtoull(p, (char **)&p, 16);
-#if defined(TARGET_I386)
- s->c_cpu->eip = addr;
-#elif defined (TARGET_PPC)
- s->c_cpu->nip = addr;
-#elif defined (TARGET_SPARC)
- s->c_cpu->pc = addr;
- s->c_cpu->npc = addr + 4;
-#elif defined (TARGET_ARM)
- s->c_cpu->regs[15] = addr;
-#elif defined (TARGET_SH4)
- s->c_cpu->pc = addr;
-#elif defined (TARGET_MIPS)
- 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
+ gdb_set_cpu_pc(s, addr);
}
cpu_single_step(s->c_cpu, sstep_flags);
gdb_continue(s);
}
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':
put_packet(s, "OK");
break;
}
- for (env = first_cpu; env != NULL; env = env->next_cpu)
- if (env->cpu_index + 1 == thread)
- break;
+ env = find_cpu(thread);
if (env == NULL) {
put_packet(s, "E22");
break;
break;
case 'T':
thread = strtoull(p, (char **)&p, 16);
-#ifndef CONFIG_USER_ONLY
- if (thread > 0 && thread < smp_cpus + 1)
-#else
- if (thread == 1)
-#endif
- put_packet(s, "OK");
- else
+ env = find_cpu(thread);
+
+ if (env != NULL) {
+ put_packet(s, "OK");
+ } else {
put_packet(s, "E22");
+ }
break;
case 'q':
case 'Q':
} else if (strcmp(p,"sThreadInfo") == 0) {
report_cpuinfo:
if (s->query_cpu) {
- snprintf(buf, sizeof(buf), "m%x", s->query_cpu->cpu_index+1);
+ snprintf(buf, sizeof(buf), "m%x", gdb_id(s->query_cpu));
put_packet(s, buf);
s->query_cpu = s->query_cpu->next_cpu;
} else
break;
} else if (strncmp(p,"ThreadExtraInfo,", 16) == 0) {
thread = strtoull(p+16, (char **)&p, 16);
- for (env = first_cpu; env != NULL; env = env->next_cpu)
- if (env->cpu_index + 1 == thread) {
- len = snprintf((char *)mem_buf, sizeof(mem_buf),
- "CPU#%d [%s]", env->cpu_index,
- env->halted ? "halted " : "running");
- memtohex(buf, mem_buf, len);
- put_packet(s, buf);
- break;
- }
+ env = find_cpu(thread);
+ if (env != NULL) {
+ cpu_synchronize_state(env, 0);
+ len = snprintf((char *)mem_buf, sizeof(mem_buf),
+ "CPU#%d [%s]", env->cpu_index,
+ env->halted ? "halted " : "running");
+ memtohex(buf, mem_buf, len);
+ put_packet(s, buf);
+ }
break;
}
#ifdef CONFIG_USER_ONLY
if (strncmp(p, "Supported", 9) == 0) {
snprintf(buf, sizeof(buf), "PacketSize=%x", MAX_PACKET_LENGTH);
#ifdef GDB_CORE_XML
- strcat(buf, ";qXfer:features:read+");
+ pstrcat(buf, sizeof(buf), ";qXfer:features:read+");
#endif
put_packet(s, buf);
break;
int ret;
if (running || (reason != EXCP_DEBUG && reason != EXCP_INTERRUPT) ||
- s->state == RS_SYSCALL)
+ 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 ";",
- GDB_SIGNAL_TRAP, env->cpu_index+1, type,
+ GDB_SIGNAL_TRAP, gdb_id(env), type,
env->watchpoint_hit->vaddr);
put_packet(s, buf);
env->watchpoint_hit = NULL;
} else {
ret = GDB_SIGNAL_INT;
}
- snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, env->cpu_index+1);
+ snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, gdb_id(env));
put_packet(s, buf);
}
#endif
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
s = qemu_mallocz(sizeof(GDBState));
-
- memset (s, 0, sizeof (GDBState));
s->c_cpu = first_cpu;
s->g_cpu = first_cpu;
s->fd = fd;
return len;
}
-int gdbserver_start(const char *port)
+#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_port_name[128];
- int port_num;
- char *p;
- CharDriverState *chr;
+ char gdbstub_device_name[128];
+ CharDriverState *chr = NULL;
+ CharDriverState *mon_chr;
- if (!port || !*port)
- return -1;
+ 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;
- 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;
+ 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);
}
- chr = qemu_chr_open("gdb", port, NULL);
- if (!chr)
- return -1;
+ s = gdbserver_state;
+ if (!s) {
+ s = qemu_mallocz(sizeof(GDBState));
+ gdbserver_state = s;
- s = qemu_mallocz(sizeof(GDBState));
+ 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_change_state_handler(gdb_vm_state_change, NULL);
-
- /* Initialize a monitor terminal for gdb */
- s->mon_chr = qemu_mallocz(sizeof(*s->mon_chr));
- s->mon_chr->chr_write = gdb_monitor_write;
- monitor_init(s->mon_chr, 0);
+ s->state = chr ? RS_IDLE : RS_INACTIVE;
+ s->mon_chr = mon_chr;
return 0;
}