mirror of https://github.com/xemu-project/xemu.git
gdbstub: Simplify XML lookup
Now we know all instances of GDBFeature that is used in CPU so we can traverse them to find XML. This removes the need for a CPU-specific lookup function for dynamic XMLs. Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20231213-gdb-v17-7-777047380591@daynix.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20240227144335.1196131-12-alex.bennee@linaro.org>
This commit is contained in:
parent
66260159a7
commit
ee59fa1dd5
|
@ -352,6 +352,7 @@ static const char *get_feature_xml(const char *p, const char **newp,
|
||||||
{
|
{
|
||||||
CPUState *cpu = gdb_get_first_cpu_in_process(process);
|
CPUState *cpu = gdb_get_first_cpu_in_process(process);
|
||||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||||
|
GDBRegisterState *r;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -365,7 +366,6 @@ static const char *get_feature_xml(const char *p, const char **newp,
|
||||||
/* Is it the main target xml? */
|
/* Is it the main target xml? */
|
||||||
if (strncmp(p, "target.xml", len) == 0) {
|
if (strncmp(p, "target.xml", len) == 0) {
|
||||||
if (!process->target_xml) {
|
if (!process->target_xml) {
|
||||||
GDBRegisterState *r;
|
|
||||||
g_autoptr(GPtrArray) xml = g_ptr_array_new_with_free_func(g_free);
|
g_autoptr(GPtrArray) xml = g_ptr_array_new_with_free_func(g_free);
|
||||||
|
|
||||||
g_ptr_array_add(
|
g_ptr_array_add(
|
||||||
|
@ -380,18 +380,12 @@ static const char *get_feature_xml(const char *p, const char **newp,
|
||||||
g_markup_printf_escaped("<architecture>%s</architecture>",
|
g_markup_printf_escaped("<architecture>%s</architecture>",
|
||||||
cc->gdb_arch_name(cpu)));
|
cc->gdb_arch_name(cpu)));
|
||||||
}
|
}
|
||||||
g_ptr_array_add(
|
for (guint i = 0; i < cpu->gdb_regs->len; i++) {
|
||||||
xml,
|
r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
|
||||||
g_markup_printf_escaped("<xi:include href=\"%s\"/>",
|
g_ptr_array_add(
|
||||||
cc->gdb_core_xml_file));
|
xml,
|
||||||
if (cpu->gdb_regs) {
|
g_markup_printf_escaped("<xi:include href=\"%s\"/>",
|
||||||
for (guint i = 0; i < cpu->gdb_regs->len; i++) {
|
r->feature->xmlname));
|
||||||
r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
|
|
||||||
g_ptr_array_add(
|
|
||||||
xml,
|
|
||||||
g_markup_printf_escaped("<xi:include href=\"%s\"/>",
|
|
||||||
r->feature->xmlname));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
g_ptr_array_add(xml, g_strdup("</target>"));
|
g_ptr_array_add(xml, g_strdup("</target>"));
|
||||||
g_ptr_array_add(xml, NULL);
|
g_ptr_array_add(xml, NULL);
|
||||||
|
@ -400,20 +394,11 @@ static const char *get_feature_xml(const char *p, const char **newp,
|
||||||
}
|
}
|
||||||
return process->target_xml;
|
return process->target_xml;
|
||||||
}
|
}
|
||||||
/* Is it dynamically generated by the target? */
|
/* Is it one of the features? */
|
||||||
if (cc->gdb_get_dynamic_xml) {
|
for (guint i = 0; i < cpu->gdb_regs->len; i++) {
|
||||||
g_autofree char *xmlname = g_strndup(p, len);
|
r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
|
||||||
const char *xml = cc->gdb_get_dynamic_xml(cpu, xmlname);
|
if (strncmp(p, r->feature->xmlname, len) == 0) {
|
||||||
if (xml) {
|
return r->feature->xml;
|
||||||
return xml;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Is it one of the encoded gdb-xml/ files? */
|
|
||||||
for (int i = 0; gdb_static_features[i].xmlname; i++) {
|
|
||||||
const char *name = gdb_static_features[i].xmlname;
|
|
||||||
if ((strncmp(name, p, len) == 0) &&
|
|
||||||
strlen(name) == len) {
|
|
||||||
return gdb_static_features[i].xml;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,12 +493,10 @@ static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
|
||||||
return cc->gdb_read_register(cpu, buf, reg);
|
return cc->gdb_read_register(cpu, buf, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpu->gdb_regs) {
|
for (guint i = 0; i < cpu->gdb_regs->len; i++) {
|
||||||
for (guint i = 0; i < cpu->gdb_regs->len; i++) {
|
r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
|
||||||
r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
|
if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
|
||||||
if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
|
return r->get_reg(cpu, buf, reg - r->base_reg);
|
||||||
return r->get_reg(cpu, buf, reg - r->base_reg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -528,51 +511,70 @@ static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
|
||||||
return cc->gdb_write_register(cpu, mem_buf, reg);
|
return cc->gdb_write_register(cpu, mem_buf, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpu->gdb_regs) {
|
for (guint i = 0; i < cpu->gdb_regs->len; i++) {
|
||||||
for (guint i = 0; i < cpu->gdb_regs->len; i++) {
|
r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
|
||||||
r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
|
if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
|
||||||
if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
|
return r->set_reg(cpu, mem_buf, reg - r->base_reg);
|
||||||
return r->set_reg(cpu, mem_buf, reg - r->base_reg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gdb_register_feature(CPUState *cpu, int base_reg,
|
||||||
|
gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
|
||||||
|
const GDBFeature *feature)
|
||||||
|
{
|
||||||
|
GDBRegisterState s = {
|
||||||
|
.base_reg = base_reg,
|
||||||
|
.get_reg = get_reg,
|
||||||
|
.set_reg = set_reg,
|
||||||
|
.feature = feature
|
||||||
|
};
|
||||||
|
|
||||||
|
g_array_append_val(cpu->gdb_regs, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_init_cpu(CPUState *cpu)
|
||||||
|
{
|
||||||
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||||
|
const GDBFeature *feature;
|
||||||
|
|
||||||
|
cpu->gdb_regs = g_array_new(false, false, sizeof(GDBRegisterState));
|
||||||
|
|
||||||
|
if (cc->gdb_core_xml_file) {
|
||||||
|
feature = gdb_find_static_feature(cc->gdb_core_xml_file);
|
||||||
|
gdb_register_feature(cpu, 0,
|
||||||
|
cc->gdb_read_register, cc->gdb_write_register,
|
||||||
|
feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs;
|
||||||
|
}
|
||||||
|
|
||||||
void gdb_register_coprocessor(CPUState *cpu,
|
void gdb_register_coprocessor(CPUState *cpu,
|
||||||
gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
|
gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
|
||||||
const GDBFeature *feature, int g_pos)
|
const GDBFeature *feature, int g_pos)
|
||||||
{
|
{
|
||||||
GDBRegisterState *s;
|
GDBRegisterState *s;
|
||||||
guint i;
|
guint i;
|
||||||
|
int base_reg = cpu->gdb_num_regs;
|
||||||
|
|
||||||
if (cpu->gdb_regs) {
|
for (i = 0; i < cpu->gdb_regs->len; i++) {
|
||||||
for (i = 0; i < cpu->gdb_regs->len; i++) {
|
/* Check for duplicates. */
|
||||||
/* Check for duplicates. */
|
s = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
|
||||||
s = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
|
if (s->feature == feature) {
|
||||||
if (s->feature == feature) {
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
cpu->gdb_regs = g_array_new(false, false, sizeof(GDBRegisterState));
|
|
||||||
i = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_array_set_size(cpu->gdb_regs, i + 1);
|
gdb_register_feature(cpu, base_reg, get_reg, set_reg, feature);
|
||||||
s = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
|
|
||||||
s->base_reg = cpu->gdb_num_regs;
|
|
||||||
s->get_reg = get_reg;
|
|
||||||
s->set_reg = set_reg;
|
|
||||||
s->feature = feature;
|
|
||||||
|
|
||||||
/* Add to end of list. */
|
/* Add to end of list. */
|
||||||
cpu->gdb_num_regs += feature->num_regs;
|
cpu->gdb_num_regs += feature->num_regs;
|
||||||
if (g_pos) {
|
if (g_pos) {
|
||||||
if (g_pos != s->base_reg) {
|
if (g_pos != base_reg) {
|
||||||
error_report("Error: Bad gdb register numbering for '%s', "
|
error_report("Error: Bad gdb register numbering for '%s', "
|
||||||
"expected %d got %d", feature->xml,
|
"expected %d got %d", feature->xml, g_pos, base_reg);
|
||||||
g_pos, s->base_reg);
|
|
||||||
} else {
|
} else {
|
||||||
cpu->gdb_num_g_regs = cpu->gdb_num_regs;
|
cpu->gdb_num_g_regs = cpu->gdb_num_regs;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
#include "exec/log.h"
|
#include "exec/log.h"
|
||||||
#include "exec/cpu-common.h"
|
#include "exec/cpu-common.h"
|
||||||
|
#include "exec/gdbstub.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "qemu/qemu-print.h"
|
#include "qemu/qemu-print.h"
|
||||||
#include "sysemu/tcg.h"
|
#include "sysemu/tcg.h"
|
||||||
|
@ -240,11 +241,10 @@ static void cpu_common_unrealizefn(DeviceState *dev)
|
||||||
static void cpu_common_initfn(Object *obj)
|
static void cpu_common_initfn(Object *obj)
|
||||||
{
|
{
|
||||||
CPUState *cpu = CPU(obj);
|
CPUState *cpu = CPU(obj);
|
||||||
CPUClass *cc = CPU_GET_CLASS(obj);
|
|
||||||
|
|
||||||
|
gdb_init_cpu(cpu);
|
||||||
cpu->cpu_index = UNASSIGNED_CPU_INDEX;
|
cpu->cpu_index = UNASSIGNED_CPU_INDEX;
|
||||||
cpu->cluster_index = UNASSIGNED_CLUSTER_INDEX;
|
cpu->cluster_index = UNASSIGNED_CLUSTER_INDEX;
|
||||||
cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs;
|
|
||||||
/* user-mode doesn't have configurable SMP topology */
|
/* user-mode doesn't have configurable SMP topology */
|
||||||
/* the default value is changed by qemu_init_vcpu() for system-mode */
|
/* the default value is changed by qemu_init_vcpu() for system-mode */
|
||||||
cpu->nr_cores = 1;
|
cpu->nr_cores = 1;
|
||||||
|
@ -264,6 +264,7 @@ static void cpu_common_finalize(Object *obj)
|
||||||
{
|
{
|
||||||
CPUState *cpu = CPU(obj);
|
CPUState *cpu = CPU(obj);
|
||||||
|
|
||||||
|
g_array_free(cpu->gdb_regs, TRUE);
|
||||||
qemu_lockcnt_destroy(&cpu->in_ioctl_lock);
|
qemu_lockcnt_destroy(&cpu->in_ioctl_lock);
|
||||||
qemu_mutex_destroy(&cpu->work_mutex);
|
qemu_mutex_destroy(&cpu->work_mutex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,12 @@ typedef struct GDBFeatureBuilder {
|
||||||
typedef int (*gdb_get_reg_cb)(CPUState *cpu, GByteArray *buf, int reg);
|
typedef int (*gdb_get_reg_cb)(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
typedef int (*gdb_set_reg_cb)(CPUState *cpu, uint8_t *buf, int reg);
|
typedef int (*gdb_set_reg_cb)(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gdb_init_cpu(): Initialize the CPU for gdbstub.
|
||||||
|
* @cpu: The CPU to be initialized.
|
||||||
|
*/
|
||||||
|
void gdb_init_cpu(CPUState *cpu);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gdb_register_coprocessor() - register a supplemental set of registers
|
* gdb_register_coprocessor() - register a supplemental set of registers
|
||||||
* @cpu - the CPU associated with registers
|
* @cpu - the CPU associated with registers
|
||||||
|
|
Loading…
Reference in New Issue