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>
This commit is contained in:
Max Filippov 2011-09-06 03:55:52 +04:00 committed by Blue Swirl
parent 97836ceed3
commit ccfcaba6fd
4 changed files with 496 additions and 0 deletions

View file

@ -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);