@samitouri / QOSamiQemu / commits / 42cc2028a4

monitor/hmp: Handle gdb-xml exposed registers via gdb_get_register()

Implement the gdb_get_register() helper and call it before the regular get_monitor_def() one. Registers is exposed via the GDB XML files will be directly handled, possibily allowing new registers added to XML files to be automatically accessible in QEMU monitor. All targets having GDB XML files can now be used within the monitor. For example with Loongarch, before: $ qemu-system-loongarch64 -M virt -S -monitor stdio QEMU 10.2.0 monitor - type 'help' for more information (qemu) info registers CPU#0 PC=000000001c000000 FCSR0 0x00000000 ... (qemu) p/x $pc unknown register Try "help p" for more information (qemu) and after: $ ./qemu-system-loongarch64 -M virt -S -monitor stdio QEMU 10.2.50 monitor - type 'help' for more information (qemu) p/x $pc 0x1c000000 (qemu) Similarly RISC-V: QEMU 10.2.0 monitor - type 'help' for more information (qemu) p/x $pc unknown register Try "help p" for more information VS QEMU 10.2.50 monitor - type 'help' for more information (qemu) p/x $pc 0x1000 (qemu) Reviewed-by: Dr. David Alan Gilbert <dave@treblig.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20260219191955.83815-17-philmd@linaro.org>

Philippe Mathieu-Daudé committed Feb 19, 2026 at 20:19 UTC 42cc2028a435c5775c42491d10068b85822ba81a
1 file changed +46 -3
monitor/hmp.c
+46 -3
@@ -27,14 +27,18 @@
27 #include "hw/core/qdev.h"
28 #include "monitor-internal.h"
29 #include "monitor/hmp.h"
30 +#include "monitor/hmp-target.h"
31 #include "qobject/qdict.h"
32 #include "qobject/qnum.h"
33 +#include "qemu/bswap.h"
34 #include "qemu/config-file.h"
35 #include "qemu/ctype.h"
36 #include "qemu/cutils.h"
37 #include "qemu/log.h"
38 #include "qemu/option.h"
39 +#include "qemu/target-info.h"
40 #include "qemu/units.h"
41 +#include "exec/gdbstub.h"
42 #include "system/block-backend.h"
43 #include "trace.h"
44
@@ -306,6 +310,46 @@ void hmp_help_cmd(Monitor *mon, const char *name)
310 free_cmdline_args(args, nb_args);
311 }
312
313 +/*
314 + * Set @pval to the value in the register identified by @name.
315 + * return %true if the register is found, %false otherwise.
316 + */
317 +static bool gdb_get_register(Monitor *mon, int64_t *pval, const char *name)
318 +{
319 + g_autoptr(GArray) regs = NULL;
320 + CPUState *cs = mon_get_cpu(mon);
321 +
322 + if (cs == NULL) {
323 + return false;
324 + }
325 +
326 + regs = gdb_get_register_list(cs);
327 +
328 + for (int i = 0; i < regs->len; i++) {
329 + GDBRegDesc *reg = &g_array_index(regs, GDBRegDesc, i);
330 + g_autoptr(GByteArray) buf = NULL;
331 + int reg_size;
332 +
333 + if (!reg->name || g_strcmp0(name, reg->name)) {
334 + continue;
335 + }
336 +
337 + buf = g_byte_array_new();
338 + reg_size = gdb_read_register(cs, buf, reg->gdb_reg);
339 + if (reg_size > sizeof(*pval)) {
340 + return false;
341 + }
342 +
343 + if (target_big_endian()) {
344 + *pval = ldn_be_p(buf->data, reg_size);
345 + } else {
346 + *pval = ldn_le_p(buf->data, reg_size);
347 + }
348 + return true;
349 + }
350 + return false;
351 +}
352 +
353 /*******************************************************************/
354
355 static const char *pch;
@@ -338,7 +382,6 @@ static int64_t expr_unary(Monitor *mon)
382 {
383 int64_t n;
384 char *p;
341 - int ret;
385
386 switch (*pch) {
387 case '+':
@@ -393,8 +436,8 @@ static int64_t expr_unary(Monitor *mon)
436 pch++;
437 }
438 *q = 0;
396 - ret = get_monitor_def(mon, &reg, buf);
397 - if (ret < 0) {
439 + if (!gdb_get_register(mon, &reg, buf)
440 + && get_monitor_def(mon, &reg, buf) < 0) {
441 expr_error(mon, "unknown register");
442 }
443 n = reg;