#include "qemu_socket.h"
#include "kvm.h"
+#ifndef TARGET_CPU_MEMORY_RW_DEBUG
+static inline int target_memory_rw_debug(CPUState *env, target_ulong addr,
+ uint8_t *buf, int len, int is_write)
+{
+ return cpu_memory_rw_debug(env, addr, buf, len, is_write);
+}
+#else
+/* target_memory_rw_debug() defined in cpu.h */
+#endif
enum {
GDB_SIGNAL_0 = 0,
}
}
#else
- qemu_chr_write(s->chr, buf, len);
+ qemu_chr_fe_write(s->chr, buf, len);
#endif
}
{
if (gdb_has_xml)
return 0;
- GET_REG32(0); /* fpscr */
+ GET_REG32(env->fpscr);
}
}
}
#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
if (n < 64) {
/* fprs */
- GET_REG32(*((uint32_t *)&env->fpr[n - 32]));
+ if (n & 1) {
+ GET_REG32(env->fpr[(n - 32) / 2].l.lower);
+ } else {
+ GET_REG32(env->fpr[(n - 32) / 2].l.upper);
+ }
}
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
switch (n) {
#else
if (n < 64) {
/* f0-f31 */
- GET_REG32(*((uint32_t *)&env->fpr[n - 32]));
+ if (n & 1) {
+ GET_REG32(env->fpr[(n - 32) / 2].l.lower);
+ } else {
+ GET_REG32(env->fpr[(n - 32) / 2].l.upper);
+ }
}
if (n < 80) {
/* f32-f62 (double width, even numbers only) */
- uint64_t val;
-
- val = (uint64_t)*((uint32_t *)&env->fpr[(n - 64) * 2 + 32]) << 32;
- val |= *((uint32_t *)&env->fpr[(n - 64) * 2 + 33]);
- GET_REG64(val);
+ GET_REG64(env->fpr[(n - 32) / 2].ll);
}
switch (n) {
case 80: GET_REGL(env->pc);
#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
else if (n < 64) {
/* fprs */
- *((uint32_t *)&env->fpr[n - 32]) = tmp;
+ /* f0-f31 */
+ if (n & 1) {
+ env->fpr[(n - 32) / 2].l.lower = tmp;
+ } else {
+ env->fpr[(n - 32) / 2].l.upper = tmp;
+ }
} else {
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
switch (n) {
#else
else if (n < 64) {
/* f0-f31 */
- env->fpr[n] = ldfl_p(mem_buf);
+ tmp = ldl_p(mem_buf);
+ if (n & 1) {
+ env->fpr[(n - 32) / 2].l.lower = tmp;
+ } else {
+ env->fpr[(n - 32) / 2].l.upper = tmp;
+ }
return 4;
} else if (n < 80) {
/* f32-f62 (double width, even numbers only) */
- *((uint32_t *)&env->fpr[(n - 64) * 2 + 32]) = tmp >> 32;
- *((uint32_t *)&env->fpr[(n - 64) * 2 + 33]) = tmp;
+ env->fpr[(n - 32) / 2].ll = tmp;
} else {
switch (n) {
case 80: env->pc = tmp; break;
}
return 4;
}
+#elif defined(TARGET_XTENSA)
+
+/* Use num_core_regs to see only non-privileged registers in an unmodified gdb.
+ * Use num_regs to see all registers. gdb modification is required for that:
+ * reset bit 0 in the 'flags' field of the registers definitions in the
+ * gdb/xtensa-config.c inside gdb source tree or inside gdb overlay.
+ */
+#define NUM_CORE_REGS (env->config->gdb_regmap.num_regs)
+#define num_g_regs NUM_CORE_REGS
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+ const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
+
+ if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
+ return 0;
+ }
+
+ switch (reg->type) {
+ case 9: /*pc*/
+ GET_REG32(env->pc);
+ break;
+
+ case 1: /*ar*/
+ xtensa_sync_phys_from_window(env);
+ GET_REG32(env->phys_regs[(reg->targno & 0xff) % env->config->nareg]);
+ break;
+
+ case 2: /*SR*/
+ GET_REG32(env->sregs[reg->targno & 0xff]);
+ break;
+
+ case 3: /*UR*/
+ GET_REG32(env->uregs[reg->targno & 0xff]);
+ break;
+
+ case 8: /*a*/
+ GET_REG32(env->regs[reg->targno & 0x0f]);
+ break;
+
+ default:
+ qemu_log("%s from reg %d of unsupported type %d\n",
+ __func__, n, reg->type);
+ return 0;
+ }
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+ uint32_t tmp;
+ const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
+
+ if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
+ return 0;
+ }
+
+ tmp = ldl_p(mem_buf);
+
+ switch (reg->type) {
+ case 9: /*pc*/
+ env->pc = tmp;
+ break;
+
+ case 1: /*ar*/
+ env->phys_regs[(reg->targno & 0xff) % env->config->nareg] = tmp;
+ xtensa_sync_window_from_phys(env);
+ break;
+
+ case 2: /*SR*/
+ env->sregs[reg->targno & 0xff] = tmp;
+ break;
+
+ case 3: /*UR*/
+ env->uregs[reg->targno & 0xff] = tmp;
+ break;
+
+ case 8: /*a*/
+ env->regs[reg->targno & 0x0f] = tmp;
+ break;
+
+ default:
+ qemu_log("%s to reg %d of unsupported type %d\n",
+ __func__, n, reg->type);
+ return 0;
+ }
+
+ return 4;
+}
#else
#define NUM_CORE_REGS 0
#endif
+#if !defined(TARGET_XTENSA)
static int num_g_regs = NUM_CORE_REGS;
+#endif
#ifdef GDB_CORE_XML
/* Encode data using the encoding for 'x' packets. */
return 0;
}
+#if !defined(TARGET_XTENSA)
/* Register a supplemental set of CPU registers. If g_pos is nonzero it
specifies the first register number and these registers are included in
a standard "g" packet. Direction is relative to gdb, i.e. get_reg is
GDBRegisterState **p;
static int last_reg = NUM_CORE_REGS;
- s = (GDBRegisterState *)qemu_mallocz(sizeof(GDBRegisterState));
- s->base_reg = last_reg;
- s->num_regs = num_regs;
- s->get_reg = get_reg;
- s->set_reg = set_reg;
- s->xml = xml;
p = &env->gdb_regs;
while (*p) {
/* Check for duplicates. */
return;
p = &(*p)->next;
}
+
+ s = g_new0(GDBRegisterState, 1);
+ s->base_reg = last_reg;
+ s->num_regs = num_regs;
+ s->get_reg = get_reg;
+ s->set_reg = set_reg;
+ s->xml = xml;
+
/* Add to end of list. */
last_reg += num_regs;
*p = s;
}
}
}
+#endif
#ifndef CONFIG_USER_ONLY
static const int xlat_gdb_type[] = {
s->c_cpu->psw.addr = pc;
#elif defined (TARGET_LM32)
s->c_cpu->pc = pc;
+#elif defined(TARGET_XTENSA)
+ s->c_cpu->pc = pc;
#endif
}
break;
case 'g':
cpu_synchronize_state(s->g_cpu);
+ env = s->g_cpu;
len = 0;
for (addr = 0; addr < num_g_regs; addr++) {
reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr);
break;
case 'G':
cpu_synchronize_state(s->g_cpu);
+ env = s->g_cpu;
registers = mem_buf;
len = strlen(p) / 2;
hextomem((uint8_t *)registers, p, len);
if (*p == ',')
p++;
len = strtoull(p, NULL, 16);
- if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) {
+ if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) {
put_packet (s, "E14");
} else {
memtohex(buf, mem_buf, len);
if (*p == ':')
p++;
hextomem(mem_buf, p, len);
- if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 1) != 0)
+ if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 1) != 0) {
put_packet(s, "E14");
- else
+ } else {
put_packet(s, "OK");
+ }
break;
case 'p':
/* Older gdb are really dumb, and don't use 'g' if 'p' is avaialable.
hextomem(mem_buf, p + 5, len);
len = len / 2;
mem_buf[len++] = 0;
- qemu_chr_read(s->mon_chr, mem_buf, len);
+ qemu_chr_be_write(s->mon_chr, mem_buf, len);
put_packet(s, "OK");
break;
}
}
#ifndef CONFIG_USER_ONLY
-static void gdb_vm_state_change(void *opaque, int running, int reason)
+static void gdb_vm_state_change(void *opaque, int running, RunState state)
{
GDBState *s = gdbserver_state;
CPUState *env = s->c_cpu;
if (running || s->state == RS_INACTIVE || s->state == RS_SYSCALL) {
return;
}
- switch (reason) {
- case VMSTOP_DEBUG:
+ switch (state) {
+ case RUN_STATE_DEBUG:
if (env->watchpoint_hit) {
switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) {
case BP_MEM_READ:
tb_flush(env);
ret = GDB_SIGNAL_TRAP;
break;
- case VMSTOP_USER:
+ case RUN_STATE_PAUSED:
ret = GDB_SIGNAL_INT;
break;
- case VMSTOP_SHUTDOWN:
+ case RUN_STATE_SHUTDOWN:
ret = GDB_SIGNAL_QUIT;
break;
- case VMSTOP_DISKFULL:
+ case RUN_STATE_IO_ERROR:
ret = GDB_SIGNAL_IO;
break;
- case VMSTOP_WATCHDOG:
+ case RUN_STATE_WATCHDOG:
ret = GDB_SIGNAL_ALRM;
break;
- case VMSTOP_PANIC:
+ case RUN_STATE_INTERNAL_ERROR:
ret = GDB_SIGNAL_ABRT;
break;
- case VMSTOP_SAVEVM:
- case VMSTOP_LOADVM:
+ case RUN_STATE_SAVE_VM:
+ case RUN_STATE_RESTORE_VM:
return;
- case VMSTOP_MIGRATE:
+ case RUN_STATE_FINISH_MIGRATE:
ret = GDB_SIGNAL_XCPU;
break;
default:
gdb_current_syscall_cb = cb;
s->state = RS_SYSCALL;
#ifndef CONFIG_USER_ONLY
- vm_stop(VMSTOP_DEBUG);
+ vm_stop(RUN_STATE_DEBUG);
#endif
s->state = RS_IDLE;
va_start(va, fmt);
if (ch != '$')
return;
}
- if (vm_running) {
+ if (runstate_is_running()) {
/* when the CPU is running, we cannot do anything except stop
it when receiving a char */
- vm_stop(VMSTOP_USER);
+ vm_stop(RUN_STATE_PAUSED);
} else
#endif
{
#ifndef CONFIG_USER_ONLY
if (s->chr) {
- qemu_chr_close(s->chr);
+ qemu_chr_delete(s->chr);
}
#endif
}
}
else if (n == 0 || errno != EAGAIN)
{
- /* XXX: Connection closed. Should probably wait for annother
+ /* XXX: Connection closed. Should probably wait for another
connection before continuing. */
return sig;
}
val = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
- s = qemu_mallocz(sizeof(GDBState));
+ s = g_malloc0(sizeof(GDBState));
s->c_cpu = first_cpu;
s->g_cpu = first_cpu;
s->fd = fd;
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
if (ret < 0) {
perror("bind");
+ close(fd);
return -1;
}
ret = listen(fd, 0);
if (ret < 0) {
perror("listen");
+ close(fd);
return -1;
}
return fd;
{
switch (event) {
case CHR_EVENT_OPENED:
- vm_stop(VMSTOP_USER);
+ vm_stop(RUN_STATE_PAUSED);
gdb_has_xml = 0;
break;
default:
#ifndef _WIN32
static void gdb_sigterm_handler(int signal)
{
- if (vm_running) {
- vm_stop(VMSTOP_USER);
+ if (runstate_is_running()) {
+ vm_stop(RUN_STATE_PAUSED);
}
}
#endif
sigaction(SIGINT, &act, NULL);
}
#endif
- chr = qemu_chr_open("gdb", device, NULL);
+ chr = qemu_chr_new("gdb", device, NULL);
if (!chr)
return -1;
s = gdbserver_state;
if (!s) {
- s = qemu_mallocz(sizeof(GDBState));
+ s = g_malloc0(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 = g_malloc0(sizeof(*mon_chr));
mon_chr->chr_write = gdb_monitor_write;
monitor_init(mon_chr, 0);
} else {
if (s->chr)
- qemu_chr_close(s->chr);
+ qemu_chr_delete(s->chr);
mon_chr = s->mon_chr;
memset(s, 0, sizeof(GDBState));
}