From: "Alex Bennée" <alex.bennee@linaro.org>
To: "Marc-André Lureau" <marcandre.lureau@redhat.com>
Cc: qemu-devel@nongnu.org,
"Dr. David Alan Gilbert" <dave@treblig.org>,
"Philippe Mathieu-Daudé" <philmd@oss.qualcomm.com>,
"Zhao Liu" <zhao1.liu@intel.com>,
"Peter Maydell" <peter.maydell@linaro.org>,
"Chinmay Rath" <rathc@linux.ibm.com>,
"Nicholas Piggin" <npiggin@gmail.com>,
"Glenn Miles" <milesg@linux.ibm.com>,
"Harsh Prateek Bora" <harshpb@linux.ibm.com>,
"Palmer Dabbelt" <palmer@dabbelt.com>,
"Alistair Francis" <alistair.francis@wdc.com>,
"Weiwei Li" <liwei1518@gmail.com>,
"Daniel Henrique Barboza" <daniel.barboza@oss.qualcomm.com>,
"Liu Zhiwei" <zhiwei_liu@linux.alibaba.com>,
"Chao Liu" <chao.liu@processmission.com>,
"Max Filippov" <jcmvbkbc@gmail.com>,
qemu-arm@nongnu.org, qemu-ppc@nongnu.org, qemu-riscv@nongnu.org,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Laurent Vivier" <laurent@vivier.eu>,
"Mark Cave-Ayland" <mark.cave-ayland@ilande.co.uk>,
"Artyom Tarasenko" <atar4qemu@gmail.com>,
"Helge Deller" <deller@gmx.de>,
"Pierrick Bouvier" <pierrick.bouvier@oss.qualcomm.com>,
"Warner Losh" <imp@bsdimp.com>, "Kyle Evans" <kevans@freebsd.org>
Subject: Re: [PATCH v2 04/10] gdbstub: add gdb_register_internal_coprocessor()
Date: Tue, 13 Oct 2026 09:42:57 +0100 [thread overview]
Message-ID: <87ik36gfe6.fsf@draig.linaro.org> (raw)
In-Reply-To: <20261013-query-reg-v2-4-6f95a2e139a9@redhat.com> ("Marc-André Lureau"'s message of "Tue, 13 Oct 2026 00:34:07 +0400")
Marc-André Lureau <marcandre.lureau@redhat.com> writes:
> Add support for registering coprocessor features that are only visible
> to QEMU's internal APIs (HMP monitor $register expressions, plugins) but
> hidden from GDB's target description XML.
>
> When a feature is registered as internal:
> - It is excluded from the target.xml sent to GDB
> - Its XML is not served via qXfer:features:read
> - 'p'/'P' packets for internal register numbers return E14
>
> This is useful for exposing system registers to the HMP monitor without
> affecting GDB's register namespace. Exposing aliases or synthetic
> registers through GDB's target description can cause problems: name
> collisions with GDB's pseudo-registers, independent register caching,
> and missing DWARF unwind rules.
Hmm are they *that* useful for HMP then?
The front-ends do limit what they export to gdb (see for example
ARM_CP_NO_GDB) generally because reading them causes side-effects. Those
restrictions are also a reason to limit them from the HMP interface.
>
> Internal features must be registered after all GDB-visible features to
> keep remote register numbering consistent. This ordering is enforced
> with an assertion.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> gdbstub/gdbstub.c | 71 ++++++++++++++++++++++++++++++++++++++++++++------
> include/exec/gdbstub.h | 21 +++++++++++++++
> 2 files changed, 84 insertions(+), 8 deletions(-)
>
> diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
> index 912e31b66744..ac0f76d62333 100644
> --- a/gdbstub/gdbstub.c
> +++ b/gdbstub/gdbstub.c
> @@ -54,6 +54,7 @@ typedef struct GDBRegisterState {
> gdb_get_reg_cb get_reg;
> gdb_set_reg_cb set_reg;
> const GDBFeature *feature;
> + bool internal; /* hidden from GDB, accessible via API/monitor */
> } GDBRegisterState;
>
> GDBState gdbserver_state;
> @@ -385,6 +386,11 @@ static const char *get_feature_xml(const char *p, const char **newp,
> }
> for (guint i = 0; i < cpu->gdb_regs->len; i++) {
> r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
> + /* The core target.xml feature must never be internal. */
> + g_assert(i > 0 || !r->internal);
> + if (r->internal) {
> + continue;
> + }
> g_ptr_array_add(
> xml,
> g_markup_printf_escaped("<xi:include href=\"%s\"/>",
> @@ -400,6 +406,9 @@ static const char *get_feature_xml(const char *p, const char **newp,
> /* Is it one of the features? */
> for (guint i = 0; i < cpu->gdb_regs->len; i++) {
> r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
> + if (r->internal) {
> + continue;
> + }
> if (strncmp(p, r->feature->xmlname, len) == 0) {
> return r->feature->xml;
> }
> @@ -563,13 +572,14 @@ int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
>
> 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)
> + const GDBFeature *feature, bool internal)
> {
> GDBRegisterState s = {
> .base_reg = base_reg,
> .get_reg = get_reg,
> .set_reg = set_reg,
> - .feature = feature
> + .feature = feature,
> + .internal = internal
> };
>
> trace_gdbxml_register_feature(feature->name, feature->xmlname,
> @@ -605,7 +615,7 @@ void gdb_init_cpu(CPUState *cpu)
> assert(feature->base_reg == 0);
> gdb_register_feature(cpu, 0,
> cc->gdb_read_register, cc->gdb_write_register,
> - feature);
> + feature, false);
> cpu->gdb_next_base_reg = cpu->gdb_num_g_regs = feature->num_regs;
> } else {
> cpu->gdb_next_base_reg = cpu->gdb_num_g_regs = cc->gdb_num_core_regs;
> @@ -616,20 +626,26 @@ void gdb_init_cpu(CPUState *cpu)
> cc->gdb_num_core_regs);
> }
>
> -void gdb_register_coprocessor(CPUState *cpu,
> - gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
> - const GDBFeature *feature)
> +static void do_gdb_register_coprocessor(CPUState *cpu,
> + gdb_get_reg_cb get_reg,
> + gdb_set_reg_cb set_reg,
> + const GDBFeature *feature,
> + bool internal)
> {
> GDBRegisterState *s;
> guint i;
> int base_reg = cpu->gdb_next_base_reg;
>
> for (i = 0; i < cpu->gdb_regs->len; i++) {
> - /* Check for duplicates. */
> s = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
> + /* Check for duplicates. */
> if (s->feature == feature) {
> return;
> }
> + /* GDB-visible features must not follow internal ones. */
> + if (!internal) {
> + g_assert(!s->internal);
> + }
> }
>
> if (base_reg < feature->base_reg) {
> @@ -637,12 +653,27 @@ void gdb_register_coprocessor(CPUState *cpu,
> feature->base_reg);
> base_reg = feature->base_reg;
> }
> - gdb_register_feature(cpu, base_reg, get_reg, set_reg, feature);
> + gdb_register_feature(cpu, base_reg, get_reg, set_reg, feature, internal);
>
> /* Add to end of list. */
> cpu->gdb_next_base_reg = base_reg + feature->num_regs;
> }
>
> +void gdb_register_coprocessor(CPUState *cpu,
> + gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
> + const GDBFeature *feature)
> +{
> + do_gdb_register_coprocessor(cpu, get_reg, set_reg, feature, false);
> +}
> +
> +void gdb_register_internal_coprocessor(CPUState *cpu,
> + gdb_get_reg_cb get_reg,
> + gdb_set_reg_cb set_reg,
> + const GDBFeature *feature)
> +{
> + do_gdb_register_coprocessor(cpu, get_reg, set_reg, feature, true);
> +}
> +
> void gdb_unregister_coprocessor_all(CPUState *cpu)
> {
> /*
> @@ -1223,6 +1254,18 @@ static void handle_remove_bp(GArray *params, void *user_ctx)
> * the remote gdb to fallback to older methods.
> */
>
> +static bool gdb_register_is_internal(CPUState *cpu, int reg)
> +{
> + for (guint i = 0; i < cpu->gdb_regs->len; i++) {
> + GDBRegisterState *r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
> +
> + if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
> + return r->internal;
> + }
> + }
> + return false;
> +}
> +
> static void handle_set_reg(GArray *params, void *user_ctx)
> {
> int reg_size;
> @@ -1232,6 +1275,12 @@ static void handle_set_reg(GArray *params, void *user_ctx)
> return;
> }
>
> + if (gdb_register_is_internal(gdbserver_state.g_cpu,
> + gdb_get_cmd_param(params, 0)->val_ull)) {
> + gdb_put_packet("E14");
> + return;
> + }
> +
> reg_size = strlen(gdb_get_cmd_param(params, 1)->data) / 2;
> gdb_hextomem(gdbserver_state.mem_buf, gdb_get_cmd_param(params, 1)->data, reg_size);
> gdb_write_register(gdbserver_state.g_cpu, gdbserver_state.mem_buf->data,
> @@ -1248,6 +1297,12 @@ static void handle_get_reg(GArray *params, void *user_ctx)
> return;
> }
>
> + if (gdb_register_is_internal(gdbserver_state.g_cpu,
> + gdb_get_cmd_param(params, 0)->val_ull)) {
> + gdb_put_packet("E14");
> + return;
> + }
> +
> reg_size = gdb_read_register(gdbserver_state.g_cpu,
> gdbserver_state.mem_buf,
> gdb_get_cmd_param(params, 0)->val_ull);
> diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
> index 75eb4d9c365e..1bc778324758 100644
> --- a/include/exec/gdbstub.h
> +++ b/include/exec/gdbstub.h
> @@ -40,6 +40,27 @@ void gdb_register_coprocessor(CPUState *cpu,
> gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
> const GDBFeature *feature);
>
> +/**
> + * gdb_register_internal_coprocessor() - register internal registers
> + *
> + * Like gdb_register_coprocessor(), but the feature is NOT exposed to
> + * GDB via the target description XML. The registers are only
> + * accessible through QEMU's internal APIs (HMP monitor ``$register``
> + * expressions via gdb_get_register_list()).
> + *
> + * Internal features must be registered after all GDB-visible features
> + * to avoid register numbering mismatches with GDB.
> + *
> + * @cpu - the CPU associated with registers
> + * @get_reg - get function
> + * @set_reg - set function
> + * @feature - the GDBFeature describing the registers
> + */
> +void gdb_register_internal_coprocessor(CPUState *cpu,
> + gdb_get_reg_cb get_reg,
> + gdb_set_reg_cb set_reg,
> + const GDBFeature *feature);
> +
> /**
> * gdb_unregister_coprocessor_all() - unregisters supplemental set of registers
> * @cpu - the CPU associated with registers
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
next prev parent reply other threads:[~2026-10-13 8:51 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-12 20:34 [PATCH v2 00/10] monitor/hmp: replace MonitorDef with GDB registers Marc-André Lureau
2026-10-12 20:34 ` [PATCH v2 01/10] hmp: don't crash on invalid register Marc-André Lureau
2026-10-12 20:34 ` [PATCH v2 02/10] gdbstub: fix next register base after register gaps Marc-André Lureau
2026-10-12 20:34 ` [PATCH v2 03/10] gdbstub: set feature->base_reg for dynamic features Marc-André Lureau
2026-10-12 20:34 ` [PATCH v2 04/10] gdbstub: add gdb_register_internal_coprocessor() Marc-André Lureau
2026-10-13 8:42 ` Alex Bennée [this message]
2026-10-13 13:00 ` Marc-André Lureau
2026-10-13 13:26 ` Peter Maydell
2026-10-13 14:34 ` Dr. David Alan Gilbert
2026-10-12 20:34 ` [PATCH v2 05/10] target/i386: expose segment limits via GDB Marc-André Lureau
2026-10-12 20:34 ` [PATCH v2 06/10] target/m68k: expose system registers " Marc-André Lureau
2026-10-12 20:34 ` [PATCH v2 07/10] target/sparc64: " Marc-André Lureau
2026-10-13 6:57 ` Philippe Mathieu-Daudé
2026-10-12 20:34 ` [PATCH v2 08/10] target/riscv: bypass smstateen check in debugger mode Marc-André Lureau
2026-10-12 20:34 ` [PATCH v2 09/10] target/riscv: expose register aliases via GDB Marc-André Lureau
2026-10-12 20:34 ` [PATCH v2 10/10] monitor/hmp: remove legacy MonitorDef infrastructure Marc-André Lureau
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87ik36gfe6.fsf@draig.linaro.org \
--to=alex.bennee@linaro.org \
--cc=alistair.francis@wdc.com \
--cc=atar4qemu@gmail.com \
--cc=chao.liu@processmission.com \
--cc=daniel.barboza@oss.qualcomm.com \
--cc=dave@treblig.org \
--cc=deller@gmx.de \
--cc=harshpb@linux.ibm.com \
--cc=imp@bsdimp.com \
--cc=jcmvbkbc@gmail.com \
--cc=kevans@freebsd.org \
--cc=laurent@vivier.eu \
--cc=liwei1518@gmail.com \
--cc=marcandre.lureau@redhat.com \
--cc=mark.cave-ayland@ilande.co.uk \
--cc=milesg@linux.ibm.com \
--cc=npiggin@gmail.com \
--cc=palmer@dabbelt.com \
--cc=pbonzini@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=philmd@oss.qualcomm.com \
--cc=pierrick.bouvier@oss.qualcomm.com \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=qemu-ppc@nongnu.org \
--cc=qemu-riscv@nongnu.org \
--cc=rathc@linux.ibm.com \
--cc=zhao1.liu@intel.com \
--cc=zhiwei_liu@linux.alibaba.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.