mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-31 05:51:53 -06:00
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:
parent
97836ceed3
commit
ccfcaba6fd
4 changed files with 496 additions and 0 deletions
96
gdbstub.c
96
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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue