aboutsummaryrefslogtreecommitdiffstats
path: root/gdbstub.c
diff options
context:
space:
mode:
authorMax Filippov <jcmvbkbc@gmail.com>2011-09-06 03:55:52 +0400
committerBlue Swirl <blauwirbel@gmail.com>2011-09-10 16:57:40 +0000
commitccfcaba6fd9f69a9322af1911302e71127bee1e0 (patch)
treef68ec83f8fae54bf2dd78565966d58af6f3cf008 /gdbstub.c
parent97836ceed39bb1be9a72c9d7c122657d569731d9 (diff)
target-xtensa: add gdb support
Specific xtensa processor overlay for GDB contains register map in the gdb/xtensa-config.c. This description is used by the GDB to e.g. parse 'g' response packets and it may be reused in the qemu's gdbstub (only XTREG definitions for non-pseudoregisters are needed). Currently mainline GDB does not support operations with privileged SRs (see http://sourceware.org/ml/gdb/2011-07/msg00075.html). This support may be enabled, see NUM_CORE_REGS comment in the gdbstub.c Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Diffstat (limited to 'gdbstub.c')
-rw-r--r--gdbstub.c96
1 files changed, 96 insertions, 0 deletions
diff --git a/gdbstub.c b/gdbstub.c
index 3b87c2734..933088578 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1541,6 +1541,94 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
}
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
@@ -1557,7 +1645,9 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
#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. */
@@ -1654,6 +1744,7 @@ static int gdb_write_register(CPUState *env, uint8_t *mem_buf, int reg)
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
@@ -1693,6 +1784,7 @@ void gdb_register_coprocessor(CPUState * env,
}
}
}
+#endif
#ifndef CONFIG_USER_ONLY
static const int xlat_gdb_type[] = {
@@ -1818,6 +1910,8 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
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
}
@@ -1988,6 +2082,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
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);
@@ -1998,6 +2093,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
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);