aboutsummaryrefslogtreecommitdiff
path: root/target/arm/gdbstub.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/arm/gdbstub.c')
-rw-r--r--target/arm/gdbstub.c600
1 files changed, 418 insertions, 182 deletions
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index 826601b341..a3bb73cfa7 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -20,12 +20,17 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "exec/gdbstub.h"
+#include "gdbstub/helpers.h"
+#include "sysemu/tcg.h"
+#include "internals.h"
+#include "cpu-features.h"
+#include "cpregs.h"
-typedef struct RegisterSysregXmlParam {
+typedef struct RegisterSysregFeatureParam {
CPUState *cs;
- GString *s;
+ GDBFeatureBuilder builder;
int n;
-} RegisterSysregXmlParam;
+} RegisterSysregFeatureParam;
/* Old gdb always expect FPA registers. Newer (xml-aware) gdb only expect
whatever the target description contains. Due to a historical mishap
@@ -42,21 +47,7 @@ int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
/* Core integer register. */
return gdb_get_reg32(mem_buf, env->regs[n]);
}
- if (n < 24) {
- /* FPA registers. */
- if (gdb_has_xml) {
- return 0;
- }
- return gdb_get_zeroes(mem_buf, 12);
- }
- switch (n) {
- case 24:
- /* FPA status register. */
- if (gdb_has_xml) {
- return 0;
- }
- return gdb_get_reg32(mem_buf, 0);
- case 25:
+ if (n == 25) {
/* CPSR, or XPSR for M-profile */
if (arm_feature(env, ARM_FEATURE_M)) {
return gdb_get_reg32(mem_buf, xpsr_read(env));
@@ -76,8 +67,13 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
tmp = ldl_p(mem_buf);
- /* Mask out low bit of PC to workaround gdb bugs. This will probably
- cause problems if we ever implement the Jazelle DBX extensions. */
+ /*
+ * Mask out low bits of PC to workaround gdb bugs.
+ * This avoids an assert in thumb_tr_translate_insn, because it is
+ * architecturally impossible to misalign the pc.
+ * This will probably cause problems if we ever implement the
+ * Jazelle DBX extensions.
+ */
if (n == 15) {
tmp &= ~1;
}
@@ -91,27 +87,13 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
env->regs[n] = tmp;
return 4;
}
- if (n < 24) { /* 16-23 */
- /* FPA registers (ignored). */
- if (gdb_has_xml) {
- return 0;
- }
- return 12;
- }
- switch (n) {
- case 24:
- /* FPA status register (ignored). */
- if (gdb_has_xml) {
- return 0;
- }
- return 4;
- case 25:
+ if (n == 25) {
/* CPSR, or XPSR for M-profile */
if (arm_feature(env, ARM_FEATURE_M)) {
/*
* Don't allow writing to XPSR.Exception as it can cause
* a transition into or out of handler mode (it's not
- * writeable via the MSR insn so this is a reasonable
+ * writable via the MSR insn so this is a reasonable
* restriction). Other fields are safe to update.
*/
xpsr_write(env, tmp, ~XPSR_EXCP);
@@ -124,34 +106,174 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
return 0;
}
-static void arm_gen_one_xml_sysreg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml,
+static int vfp_gdb_get_reg(CPUState *cs, GByteArray *buf, int reg)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16;
+
+ /* VFP data registers are always little-endian. */
+ if (reg < nregs) {
+ return gdb_get_reg64(buf, *aa32_vfp_dreg(env, reg));
+ }
+ if (arm_feature(env, ARM_FEATURE_NEON)) {
+ /* Aliases for Q regs. */
+ nregs += 16;
+ if (reg < nregs) {
+ uint64_t *q = aa32_vfp_qreg(env, reg - 32);
+ return gdb_get_reg128(buf, q[0], q[1]);
+ }
+ }
+ switch (reg - nregs) {
+ case 0:
+ return gdb_get_reg32(buf, vfp_get_fpscr(env));
+ }
+ return 0;
+}
+
+static int vfp_gdb_set_reg(CPUState *cs, uint8_t *buf, int reg)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16;
+
+ if (reg < nregs) {
+ *aa32_vfp_dreg(env, reg) = ldq_le_p(buf);
+ return 8;
+ }
+ if (arm_feature(env, ARM_FEATURE_NEON)) {
+ nregs += 16;
+ if (reg < nregs) {
+ uint64_t *q = aa32_vfp_qreg(env, reg - 32);
+ q[0] = ldq_le_p(buf);
+ q[1] = ldq_le_p(buf + 8);
+ return 16;
+ }
+ }
+ switch (reg - nregs) {
+ case 0:
+ vfp_set_fpscr(env, ldl_p(buf));
+ return 4;
+ }
+ return 0;
+}
+
+static int vfp_gdb_get_sysreg(CPUState *cs, GByteArray *buf, int reg)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
+ switch (reg) {
+ case 0:
+ return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPSID]);
+ case 1:
+ return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPEXC]);
+ }
+ return 0;
+}
+
+static int vfp_gdb_set_sysreg(CPUState *cs, uint8_t *buf, int reg)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
+ switch (reg) {
+ case 0:
+ env->vfp.xregs[ARM_VFP_FPSID] = ldl_p(buf);
+ return 4;
+ case 1:
+ env->vfp.xregs[ARM_VFP_FPEXC] = ldl_p(buf) & (1 << 30);
+ return 4;
+ }
+ return 0;
+}
+
+static int mve_gdb_get_reg(CPUState *cs, GByteArray *buf, int reg)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
+ switch (reg) {
+ case 0:
+ return gdb_get_reg32(buf, env->v7m.vpr);
+ default:
+ return 0;
+ }
+}
+
+static int mve_gdb_set_reg(CPUState *cs, uint8_t *buf, int reg)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
+ switch (reg) {
+ case 0:
+ env->v7m.vpr = ldl_p(buf);
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * arm_get/set_gdb_*: get/set a gdb register
+ * @env: the CPU state
+ * @buf: a buffer to copy to/from
+ * @reg: register number (offset from start of group)
+ *
+ * We return the number of bytes copied
+ */
+
+static int arm_gdb_get_sysreg(CPUState *cs, GByteArray *buf, int reg)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ const ARMCPRegInfo *ri;
+ uint32_t key;
+
+ key = cpu->dyn_sysreg_feature.data.cpregs.keys[reg];
+ ri = get_arm_cp_reginfo(cpu->cp_regs, key);
+ if (ri) {
+ if (cpreg_field_is_64bit(ri)) {
+ return gdb_get_reg64(buf, (uint64_t)read_raw_cp_reg(env, ri));
+ } else {
+ return gdb_get_reg32(buf, (uint32_t)read_raw_cp_reg(env, ri));
+ }
+ }
+ return 0;
+}
+
+static int arm_gdb_set_sysreg(CPUState *cs, uint8_t *buf, int reg)
+{
+ return 0;
+}
+
+static void arm_gen_one_feature_sysreg(GDBFeatureBuilder *builder,
+ DynamicGDBFeatureInfo *dyn_feature,
ARMCPRegInfo *ri, uint32_t ri_key,
- int bitsize, int regnum)
+ int bitsize, int n)
{
- g_string_append_printf(s, "<reg name=\"%s\"", ri->name);
- g_string_append_printf(s, " bitsize=\"%d\"", bitsize);
- g_string_append_printf(s, " regnum=\"%d\"", regnum);
- g_string_append_printf(s, " group=\"cp_regs\"/>");
- dyn_xml->data.cpregs.keys[dyn_xml->num] = ri_key;
- dyn_xml->num++;
+ gdb_feature_builder_append_reg(builder, ri->name, bitsize, n,
+ "int", "cp_regs");
+
+ dyn_feature->data.cpregs.keys[n] = ri_key;
}
-static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
- gpointer p)
+static void arm_register_sysreg_for_feature(gpointer key, gpointer value,
+ gpointer p)
{
- uint32_t ri_key = *(uint32_t *)key;
+ uint32_t ri_key = (uintptr_t)key;
ARMCPRegInfo *ri = value;
- RegisterSysregXmlParam *param = (RegisterSysregXmlParam *)p;
- GString *s = param->s;
+ RegisterSysregFeatureParam *param = p;
ARMCPU *cpu = ARM_CPU(param->cs);
CPUARMState *env = &cpu->env;
- DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_sysreg_xml;
+ DynamicGDBFeatureInfo *dyn_feature = &cpu->dyn_sysreg_feature;
if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_NO_GDB))) {
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
if (ri->state == ARM_CP_STATE_AA64) {
- arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64,
- param->n++);
+ arm_gen_one_feature_sysreg(&param->builder, dyn_feature,
+ ri, ri_key, 64, param->n++);
}
} else {
if (ri->state == ARM_CP_STATE_AA32) {
@@ -160,162 +282,276 @@ static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
return;
}
if (ri->type & ARM_CP_64BIT) {
- arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64,
- param->n++);
+ arm_gen_one_feature_sysreg(&param->builder, dyn_feature,
+ ri, ri_key, 64, param->n++);
} else {
- arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 32,
- param->n++);
+ arm_gen_one_feature_sysreg(&param->builder, dyn_feature,
+ ri, ri_key, 32, param->n++);
}
}
}
}
}
-int arm_gen_dynamic_sysreg_xml(CPUState *cs, int base_reg)
+static GDBFeature *arm_gen_dynamic_sysreg_feature(CPUState *cs, int base_reg)
{
ARMCPU *cpu = ARM_CPU(cs);
- GString *s = g_string_new(NULL);
- RegisterSysregXmlParam param = {cs, s, base_reg};
-
- cpu->dyn_sysreg_xml.num = 0;
- cpu->dyn_sysreg_xml.data.cpregs.keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs));
- g_string_printf(s, "<?xml version=\"1.0\"?>");
- g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
- g_string_append_printf(s, "<feature name=\"org.qemu.gdb.arm.sys.regs\">");
- g_hash_table_foreach(cpu->cp_regs, arm_register_sysreg_for_xml, &param);
- g_string_append_printf(s, "</feature>");
- cpu->dyn_sysreg_xml.desc = g_string_free(s, false);
- return cpu->dyn_sysreg_xml.num;
+ RegisterSysregFeatureParam param = {cs};
+ gsize num_regs = g_hash_table_size(cpu->cp_regs);
+
+ gdb_feature_builder_init(&param.builder,
+ &cpu->dyn_sysreg_feature.desc,
+ "org.qemu.gdb.arm.sys.regs",
+ "system-registers.xml",
+ base_reg);
+ cpu->dyn_sysreg_feature.data.cpregs.keys = g_new(uint32_t, num_regs);
+ g_hash_table_foreach(cpu->cp_regs, arm_register_sysreg_for_feature, &param);
+ gdb_feature_builder_end(&param.builder);
+ return &cpu->dyn_sysreg_feature.desc;
}
-struct TypeSize {
- const char *gdb_type;
- int size;
- const char sz, suffix;
-};
+#ifdef CONFIG_TCG
+typedef enum {
+ M_SYSREG_MSP,
+ M_SYSREG_PSP,
+ M_SYSREG_PRIMASK,
+ M_SYSREG_CONTROL,
+ M_SYSREG_BASEPRI,
+ M_SYSREG_FAULTMASK,
+ M_SYSREG_MSPLIM,
+ M_SYSREG_PSPLIM,
+} MProfileSysreg;
-static const struct TypeSize vec_lanes[] = {
- /* quads */
- { "uint128", 128, 'q', 'u' },
- { "int128", 128, 'q', 's' },
- /* 64 bit */
- { "ieee_double", 64, 'd', 'f' },
- { "uint64", 64, 'd', 'u' },
- { "int64", 64, 'd', 's' },
- /* 32 bit */
- { "ieee_single", 32, 's', 'f' },
- { "uint32", 32, 's', 'u' },
- { "int32", 32, 's', 's' },
- /* 16 bit */
- { "ieee_half", 16, 'h', 'f' },
- { "uint16", 16, 'h', 'u' },
- { "int16", 16, 'h', 's' },
- /* bytes */
- { "uint8", 8, 'b', 'u' },
- { "int8", 8, 'b', 's' },
+static const struct {
+ const char *name;
+ int feature;
+} m_sysreg_def[] = {
+ [M_SYSREG_MSP] = { "msp", ARM_FEATURE_M },
+ [M_SYSREG_PSP] = { "psp", ARM_FEATURE_M },
+ [M_SYSREG_PRIMASK] = { "primask", ARM_FEATURE_M },
+ [M_SYSREG_CONTROL] = { "control", ARM_FEATURE_M },
+ [M_SYSREG_BASEPRI] = { "basepri", ARM_FEATURE_M_MAIN },
+ [M_SYSREG_FAULTMASK] = { "faultmask", ARM_FEATURE_M_MAIN },
+ [M_SYSREG_MSPLIM] = { "msplim", ARM_FEATURE_V8 },
+ [M_SYSREG_PSPLIM] = { "psplim", ARM_FEATURE_V8 },
};
+static uint32_t *m_sysreg_ptr(CPUARMState *env, MProfileSysreg reg, bool sec)
+{
+ uint32_t *ptr;
-int arm_gen_dynamic_svereg_xml(CPUState *cs, int base_reg)
+ switch (reg) {
+ case M_SYSREG_MSP:
+ ptr = arm_v7m_get_sp_ptr(env, sec, false, true);
+ break;
+ case M_SYSREG_PSP:
+ ptr = arm_v7m_get_sp_ptr(env, sec, true, true);
+ break;
+ case M_SYSREG_MSPLIM:
+ ptr = &env->v7m.msplim[sec];
+ break;
+ case M_SYSREG_PSPLIM:
+ ptr = &env->v7m.psplim[sec];
+ break;
+ case M_SYSREG_PRIMASK:
+ ptr = &env->v7m.primask[sec];
+ break;
+ case M_SYSREG_BASEPRI:
+ ptr = &env->v7m.basepri[sec];
+ break;
+ case M_SYSREG_FAULTMASK:
+ ptr = &env->v7m.faultmask[sec];
+ break;
+ case M_SYSREG_CONTROL:
+ ptr = &env->v7m.control[sec];
+ break;
+ default:
+ return NULL;
+ }
+ return arm_feature(env, m_sysreg_def[reg].feature) ? ptr : NULL;
+}
+
+static int m_sysreg_get(CPUARMState *env, GByteArray *buf,
+ MProfileSysreg reg, bool secure)
{
- ARMCPU *cpu = ARM_CPU(cs);
- GString *s = g_string_new(NULL);
- DynamicGDBXMLInfo *info = &cpu->dyn_svereg_xml;
- g_autoptr(GString) ts = g_string_new("");
- int i, j, bits, reg_width = (cpu->sve_max_vq * 128);
- info->num = 0;
- g_string_printf(s, "<?xml version=\"1.0\"?>");
- g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
- g_string_append_printf(s, "<feature name=\"org.gnu.gdb.aarch64.sve\">");
-
- /* First define types and totals in a whole VL */
- for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
- int count = reg_width / vec_lanes[i].size;
- g_string_printf(ts, "svev%c%c", vec_lanes[i].sz, vec_lanes[i].suffix);
- g_string_append_printf(s,
- "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>",
- ts->str, vec_lanes[i].gdb_type, count);
+ uint32_t *ptr = m_sysreg_ptr(env, reg, secure);
+
+ if (ptr == NULL) {
+ return 0;
}
+ return gdb_get_reg32(buf, *ptr);
+}
+
+static int arm_gdb_get_m_systemreg(CPUState *cs, GByteArray *buf, int reg)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
/*
- * Now define a union for each size group containing unsigned and
- * signed and potentially float versions of each size from 128 to
- * 8 bits.
+ * Here, we emulate MRS instruction, where CONTROL has a mix of
+ * banked and non-banked bits.
*/
- for (bits = 128, i = 0; bits >= 8; bits /= 2, i++) {
- const char suf[] = { 'q', 'd', 's', 'h', 'b' };
- g_string_append_printf(s, "<union id=\"svevn%c\">", suf[i]);
- for (j = 0; j < ARRAY_SIZE(vec_lanes); j++) {
- if (vec_lanes[j].size == bits) {
- g_string_append_printf(s, "<field name=\"%c\" type=\"svev%c%c\"/>",
- vec_lanes[j].suffix,
- vec_lanes[j].sz, vec_lanes[j].suffix);
- }
- }
- g_string_append(s, "</union>");
+ if (reg == M_SYSREG_CONTROL) {
+ return gdb_get_reg32(buf, arm_v7m_mrs_control(env, env->v7m.secure));
}
- /* And now the final union of unions */
- g_string_append(s, "<union id=\"svev\">");
- for (bits = 128, i = 0; bits >= 8; bits /= 2, i++) {
- const char suf[] = { 'q', 'd', 's', 'h', 'b' };
- g_string_append_printf(s, "<field name=\"%c\" type=\"svevn%c\"/>",
- suf[i], suf[i]);
- }
- g_string_append(s, "</union>");
-
- /* Finally the sve prefix type */
- g_string_append_printf(s,
- "<vector id=\"svep\" type=\"uint8\" count=\"%d\"/>",
- reg_width / 8);
-
- /* Then define each register in parts for each vq */
- for (i = 0; i < 32; i++) {
- g_string_append_printf(s,
- "<reg name=\"z%d\" bitsize=\"%d\""
- " regnum=\"%d\" type=\"svev\"/>",
- i, reg_width, base_reg++);
- info->num++;
- }
- /* fpscr & status registers */
- g_string_append_printf(s, "<reg name=\"fpsr\" bitsize=\"32\""
- " regnum=\"%d\" group=\"float\""
- " type=\"int\"/>", base_reg++);
- g_string_append_printf(s, "<reg name=\"fpcr\" bitsize=\"32\""
- " regnum=\"%d\" group=\"float\""
- " type=\"int\"/>", base_reg++);
- info->num += 2;
-
- for (i = 0; i < 16; i++) {
- g_string_append_printf(s,
- "<reg name=\"p%d\" bitsize=\"%d\""
- " regnum=\"%d\" type=\"svep\"/>",
- i, cpu->sve_max_vq * 16, base_reg++);
- info->num++;
+ return m_sysreg_get(env, buf, reg, env->v7m.secure);
+}
+
+static int arm_gdb_set_m_systemreg(CPUState *cs, uint8_t *buf, int reg)
+{
+ return 0; /* TODO */
+}
+
+static GDBFeature *arm_gen_dynamic_m_systemreg_feature(CPUState *cs,
+ int base_reg)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ GDBFeatureBuilder builder;
+ int reg = 0;
+ int i;
+
+ gdb_feature_builder_init(&builder, &cpu->dyn_m_systemreg_feature.desc,
+ "org.gnu.gdb.arm.m-system", "arm-m-system.xml",
+ base_reg);
+
+ for (i = 0; i < ARRAY_SIZE(m_sysreg_def); i++) {
+ if (arm_feature(env, m_sysreg_def[i].feature)) {
+ gdb_feature_builder_append_reg(&builder, m_sysreg_def[i].name, 32,
+ reg++, "int", NULL);
+ }
}
- g_string_append_printf(s,
- "<reg name=\"ffr\" bitsize=\"%d\""
- " regnum=\"%d\" group=\"vector\""
- " type=\"svep\"/>",
- cpu->sve_max_vq * 16, base_reg++);
- g_string_append_printf(s,
- "<reg name=\"vg\" bitsize=\"64\""
- " regnum=\"%d\" type=\"int\"/>",
- base_reg++);
- info->num += 2;
- g_string_append_printf(s, "</feature>");
- cpu->dyn_svereg_xml.desc = g_string_free(s, false);
-
- return cpu->dyn_svereg_xml.num;
+
+ gdb_feature_builder_end(&builder);
+
+ return &cpu->dyn_m_systemreg_feature.desc;
+}
+
+#ifndef CONFIG_USER_ONLY
+/*
+ * For user-only, we see the non-secure registers via m_systemreg above.
+ * For secext, encode the non-secure view as even and secure view as odd.
+ */
+static int arm_gdb_get_m_secextreg(CPUState *cs, GByteArray *buf, int reg)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
+ return m_sysreg_get(env, buf, reg >> 1, reg & 1);
}
+static int arm_gdb_set_m_secextreg(CPUState *cs, uint8_t *buf, int reg)
+{
+ return 0; /* TODO */
+}
-const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
+static GDBFeature *arm_gen_dynamic_m_secextreg_feature(CPUState *cs,
+ int base_reg)
{
ARMCPU *cpu = ARM_CPU(cs);
+ GDBFeatureBuilder builder;
+ char *name;
+ int reg = 0;
+ int i;
+
+ gdb_feature_builder_init(&builder, &cpu->dyn_m_secextreg_feature.desc,
+ "org.gnu.gdb.arm.secext", "arm-m-secext.xml",
+ base_reg);
+
+ for (i = 0; i < ARRAY_SIZE(m_sysreg_def); i++) {
+ name = g_strconcat(m_sysreg_def[i].name, "_ns", NULL);
+ gdb_feature_builder_append_reg(&builder, name, 32, reg++,
+ "int", NULL);
+ name = g_strconcat(m_sysreg_def[i].name, "_s", NULL);
+ gdb_feature_builder_append_reg(&builder, name, 32, reg++,
+ "int", NULL);
+ }
+
+ gdb_feature_builder_end(&builder);
+
+ return &cpu->dyn_m_secextreg_feature.desc;
+}
+#endif
+#endif /* CONFIG_TCG */
+
+void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
+{
+ CPUState *cs = CPU(cpu);
+ CPUARMState *env = &cpu->env;
+
+ if (arm_feature(env, ARM_FEATURE_AARCH64)) {
+ /*
+ * The lower part of each SVE register aliases to the FPU
+ * registers so we don't need to include both.
+ */
+#ifdef TARGET_AARCH64
+ if (isar_feature_aa64_sve(&cpu->isar)) {
+ GDBFeature *feature = arm_gen_dynamic_svereg_feature(cs, cs->gdb_num_regs);
+ gdb_register_coprocessor(cs, aarch64_gdb_get_sve_reg,
+ aarch64_gdb_set_sve_reg, feature, 0);
+ } else {
+ gdb_register_coprocessor(cs, aarch64_gdb_get_fpu_reg,
+ aarch64_gdb_set_fpu_reg,
+ gdb_find_static_feature("aarch64-fpu.xml"),
+ 0);
+ }
+ /*
+ * Note that we report pauth information via the feature name
+ * org.gnu.gdb.aarch64.pauth_v2, not org.gnu.gdb.aarch64.pauth.
+ * GDB versions 9 through 12 have a bug where they will crash
+ * if they see the latter XML from QEMU.
+ */
+ if (isar_feature_aa64_pauth(&cpu->isar)) {
+ gdb_register_coprocessor(cs, aarch64_gdb_get_pauth_reg,
+ aarch64_gdb_set_pauth_reg,
+ gdb_find_static_feature("aarch64-pauth.xml"),
+ 0);
+ }
+#endif
+ } else {
+ if (arm_feature(env, ARM_FEATURE_NEON)) {
+ gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
+ gdb_find_static_feature("arm-neon.xml"),
+ 0);
+ } else if (cpu_isar_feature(aa32_simd_r32, cpu)) {
+ gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
+ gdb_find_static_feature("arm-vfp3.xml"),
+ 0);
+ } else if (cpu_isar_feature(aa32_vfp_simd, cpu)) {
+ gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
+ gdb_find_static_feature("arm-vfp.xml"), 0);
+ }
+ if (!arm_feature(env, ARM_FEATURE_M)) {
+ /*
+ * A and R profile have FP sysregs FPEXC and FPSID that we
+ * expose to gdb.
+ */
+ gdb_register_coprocessor(cs, vfp_gdb_get_sysreg, vfp_gdb_set_sysreg,
+ gdb_find_static_feature("arm-vfp-sysregs.xml"),
+ 0);
+ }
+ }
+ if (cpu_isar_feature(aa32_mve, cpu) && tcg_enabled()) {
+ gdb_register_coprocessor(cs, mve_gdb_get_reg, mve_gdb_set_reg,
+ gdb_find_static_feature("arm-m-profile-mve.xml"),
+ 0);
+ }
+ gdb_register_coprocessor(cs, arm_gdb_get_sysreg, arm_gdb_set_sysreg,
+ arm_gen_dynamic_sysreg_feature(cs, cs->gdb_num_regs),
+ 0);
- if (strcmp(xmlname, "system-registers.xml") == 0) {
- return cpu->dyn_sysreg_xml.desc;
- } else if (strcmp(xmlname, "sve-registers.xml") == 0) {
- return cpu->dyn_svereg_xml.desc;
+#ifdef CONFIG_TCG
+ if (arm_feature(env, ARM_FEATURE_M) && tcg_enabled()) {
+ gdb_register_coprocessor(cs,
+ arm_gdb_get_m_systemreg, arm_gdb_set_m_systemreg,
+ arm_gen_dynamic_m_systemreg_feature(cs, cs->gdb_num_regs), 0);
+#ifndef CONFIG_USER_ONLY
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
+ gdb_register_coprocessor(cs,
+ arm_gdb_get_m_secextreg, arm_gdb_set_m_secextreg,
+ arm_gen_dynamic_m_secextreg_feature(cs, cs->gdb_num_regs), 0);
+ }
+#endif
}
- return NULL;
+#endif /* CONFIG_TCG */
}