Expose an internal API to QEMU to find groups of registers. It returns a list containing the details required to called gdb_read_register().
Based-on: <20231025093128.33116-15-akihiko.od...@daynix.com> Cc: Akihiko Odaki <akihiko.od...@daynix.com> Signed-off-by: Alex Bennée <alex.ben...@linaro.org> --- vAJB: This principle difference is the find registers is a single call which can return a) multiple registers and b) is agnostic to the gdb feature. This is because I haven't so far found any duplicate registers in the system so I thing the regname by itself should be enough. However I do expose the gdb feature name in case the caller wants to do some additional filtering. --- include/exec/gdbstub.h | 47 +++++++++++++++++++++++++++++++++ gdbstub/gdbstub.c | 59 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index da9ddfe54c..b201eb4b84 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -111,6 +111,53 @@ void gdb_feature_builder_end(const GDBFeatureBuilder *builder); */ const GDBFeature *gdb_find_static_feature(const char *xmlname); +/** + * gdb_find_feature() - Find a feature associated with a CPU. + * @cpu: The CPU associated with the feature. + * @name: The feature's name. + * + * Return: The feature's number. + */ +int gdb_find_feature(CPUState *cpu, const char *name); + +/** + * gdb_find_feature_register() - Find a register associated with a CPU. + * @cpu: The CPU associated with the register. + * @feature: The feature's number returned by gdb_find_feature(). + * @name: The register's name. + * + * Return: The register's number. + */ +int gdb_find_feature_register(CPUState *cpu, int feature, const char *name); + +/** + * gdb_read_register() - Read a register associated with a CPU. + * @cpu: The CPU associated with the register. + * @buf: The buffer that the read register will be appended to. + * @reg: The register's number returned by gdb_find_feature_register(). + * + * Return: The number of read bytes. + */ +int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); + +/** + * typedef GDBRegDesc - a register description from gdbstub + */ +typedef struct { + int gdb_reg; + const char *name; + const char *feature_name; +} GDBRegDesc; + +/** + * gdb_find_registers() - Return list of registers matching pattern + * @cpu: The CPU being searched + * @reg_pattern: the pattern being searched for + * + * Returns a GArray of GDBRegDesc, caller frees + */ +GArray *gdb_find_registers(CPUState *cpu, const char *reg_pattern); + void gdb_set_stop_cpu(CPUState *cpu); /* in gdbstub-xml.c, generated by scripts/feature_to_c.py */ diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 7d7d887817..45882d1a6f 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -490,7 +490,64 @@ const GDBFeature *gdb_find_static_feature(const char *xmlname) g_assert_not_reached(); } -static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg) +int gdb_find_feature(CPUState *cpu, const char *name) +{ + GDBRegisterState *r; + + for (guint i = 0; i < cpu->gdb_regs->len; i++) { + r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i); + if (!strcmp(name, r->feature->name)) { + return i; + } + } + + return -1; +} + +int gdb_find_feature_register(CPUState *cpu, int feature, const char *name) +{ + GDBRegisterState *r; + + r = &g_array_index(cpu->gdb_regs, GDBRegisterState, feature); + + for (int i = 0; i < r->feature->num_regs; i++) { + if (r->feature->regs[i] && !strcmp(name, r->feature->regs[i])) { + return r->base_reg + i; + } + } + + return -1; +} + +GArray *gdb_find_registers(CPUState *cpu, const char *reg_pattern) +{ + g_autoptr(GPatternSpec) pat = g_pattern_spec_new(reg_pattern); + GArray *results = g_array_new(true, true, sizeof(GDBRegDesc)); + + /* registers are only available once the CPU is initialised */ + if (!cpu->gdb_regs) { + return results; + } + + for (int f = 0; f < cpu->gdb_regs->len; f++) { + GDBRegisterState *r = &g_array_index(cpu->gdb_regs, GDBRegisterState, f); + for (int i = 0; i < r->feature->num_regs; i++) { + const char *name = r->feature->regs[i]; + if (name && g_pattern_match_string(pat, name)) { + GDBRegDesc desc = { + r->base_reg + i, + name, + r->feature->name + }; + g_array_append_val(results, desc); + } + } + } + + return results; +} + +int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg) { CPUClass *cc = CPU_GET_CLASS(cpu); GDBRegisterState *r; -- 2.39.2