* [PATCH 00/29] gdbstub and plugin read register and windows support
@ 2023-11-03 19:59 Alex Bennée
2023-11-03 19:59 ` [PATCH 01/29] default-configs: Add TARGET_XML_FILES definition Alex Bennée
` (28 more replies)
0 siblings, 29 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik
Here are my final updates for the 8.2 cycle which I can hopefully
merge if we get enough review. Aside from the usual tweaks and fixes
there are two new features:
TCG Plugin Register Access
This is based on Akihiko's previously posted series with some changes
by myself. I wasn't keen on the plugin facing API so I've re-written
it to use an opaque handle and hide the gdb details from the plugin. I
think this allows for potential future improvements as well as being
ready for up-coming heterogeneous support. The new API allowed for
making the execlog register tracking a bit more flexible and able to
track multiple registers.
Windows Support
This fairly late breaking patch finally adds support for Windows to
the TCG plugins subsystem. I'm pretty pleased with Greg's approach
which improves on previous attempts by avoiding re-implementing a
linker for POSIX targets. I don't have access to Windows though so I'm
calling on Windows users to test the solution.
The following patches still need review:
contrib/plugins: extend execlog to track register changes
plugins: add an API to read registers
gdbstub: expose api to find registers
tests/avocado: update the tcg_plugins test
tests/tcg: add an explicit gdbstub register tester
target/arm: hide aliased MIDR from gdbstub
target/arm: hide all versions of DBGD[RS]AR from gdbstub
target/arm: hide the 32bit version of PAR from gdbstub
gdb-xml: fix duplicate register in arm-neon.xml
Akihiko Odaki (16):
default-configs: Add TARGET_XML_FILES definition
gdbstub: Add num_regs member to GDBFeature
gdbstub: Introduce gdb_find_static_feature()
gdbstub: Introduce GDBFeatureBuilder
target/arm: Use GDBFeature for dynamic XML
target/ppc: Use GDBFeature for dynamic XML
target/riscv: Use GDBFeature for dynamic XML
gdbstub: Use GDBFeature for gdb_register_coprocessor
gdbstub: Use GDBFeature for GDBRegisterState
gdbstub: Change gdb_get_reg_cb and gdb_set_reg_cb
gdbstub: Simplify XML lookup
gdbstub: Infer number of core registers from XML
hw/core/cpu: Remove gdb_get_dynamic_xml member
gdbstub: Add members to identify registers to GDBFeature
cpu: Call plugin hooks only when ready
plugins: Use different helpers when reading registers
Alex Bennée (9):
gdb-xml: fix duplicate register in arm-neon.xml
target/arm: hide the 32bit version of PAR from gdbstub
target/arm: hide all versions of DBGD[RS]AR from gdbstub
target/arm: hide aliased MIDR from gdbstub
tests/tcg: add an explicit gdbstub register tester
tests/avocado: update the tcg_plugins test
gdbstub: expose api to find registers
plugins: add an API to read registers
contrib/plugins: extend execlog to track register changes
Greg Manning (4):
plugins: add dllexport and dllimport to api funcs
plugins: make test/example plugins work on windows
plugins: disable lockstep plugin on windows
plugins: allow plugins to be enabled on windows
docs/devel/tcg-plugins.rst | 10 +-
configure | 9 +-
configs/targets/loongarch64-linux-user.mak | 1 +
meson.build | 5 +
accel/tcg/plugin-helpers.h | 3 +-
include/exec/gdbstub.h | 121 +++++++-
include/hw/core/cpu.h | 7 +-
include/qemu/plugin.h | 1 +
include/qemu/qemu-plugin.h | 104 ++++++-
target/arm/cpu.h | 27 +-
target/arm/internals.h | 14 +-
target/hexagon/internal.h | 4 +-
target/microblaze/cpu.h | 4 +-
target/ppc/cpu-qom.h | 4 +-
target/ppc/cpu.h | 2 -
target/riscv/cpu.h | 5 +-
target/s390x/cpu.h | 2 -
accel/tcg/plugin-gen.c | 43 ++-
contrib/plugins/execlog.c | 180 +++++++++---
contrib/plugins/win32_linker.c | 34 +++
cpu-target.c | 11 -
gdbstub/gdbstub.c | 273 +++++++++++++-----
hw/core/cpu-common.c | 15 +-
plugins/api.c | 114 +++++++-
target/arm/cpu.c | 2 -
target/arm/cpu64.c | 1 -
target/arm/debug_helper.c | 8 +-
target/arm/gdbstub.c | 230 +++++++--------
target/arm/gdbstub64.c | 122 ++++----
target/arm/helper.c | 4 +-
target/avr/cpu.c | 1 -
target/hexagon/cpu.c | 4 +-
target/hexagon/gdbstub.c | 10 +-
target/i386/cpu.c | 2 -
target/loongarch/cpu.c | 2 -
target/loongarch/gdbstub.c | 13 +-
target/m68k/cpu.c | 1 -
target/m68k/helper.c | 26 +-
target/microblaze/cpu.c | 6 +-
target/microblaze/gdbstub.c | 9 +-
target/ppc/cpu_init.c | 7 -
target/ppc/gdbstub.c | 114 ++++----
target/riscv/cpu.c | 15 -
target/riscv/gdbstub.c | 139 +++++----
target/rx/cpu.c | 1 -
target/s390x/cpu.c | 1 -
target/s390x/gdbstub.c | 105 ++++---
contrib/plugins/Makefile | 26 +-
gdb-xml/arm-neon.xml | 2 +-
plugins/meson.build | 17 ++
plugins/qemu-plugins.symbols | 2 +
scripts/feature_to_c.py | 58 +++-
tests/avocado/tcg_plugins.py | 28 +-
tests/plugin/meson.build | 14 +-
tests/tcg/multiarch/Makefile.target | 11 +-
tests/tcg/multiarch/gdbstub/registers.py | 188 ++++++++++++
.../multiarch/system/Makefile.softmmu-target | 13 +-
57 files changed, 1577 insertions(+), 598 deletions(-)
create mode 100644 contrib/plugins/win32_linker.c
create mode 100644 tests/tcg/multiarch/gdbstub/registers.py
--
2.39.2
^ permalink raw reply [flat|nested] 46+ messages in thread
* [PATCH 01/29] default-configs: Add TARGET_XML_FILES definition
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-05 20:55 ` Richard Henderson
2023-11-03 19:59 ` [PATCH 02/29] gdb-xml: fix duplicate register in arm-neon.xml Alex Bennée
` (27 subsequent siblings)
28 siblings, 1 reply; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
From: Akihiko Odaki <akihiko.odaki@daynix.com>
loongarch64-linux-user has references to XML files so include them.
Fixes: d32688ecdb ("default-configs: Add loongarch linux-user support")
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Message-Id: <20231030054834.39145-6-akihiko.odaki@daynix.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
configs/targets/loongarch64-linux-user.mak | 1 +
1 file changed, 1 insertion(+)
diff --git a/configs/targets/loongarch64-linux-user.mak b/configs/targets/loongarch64-linux-user.mak
index 7d1b964020..43b8a2160f 100644
--- a/configs/targets/loongarch64-linux-user.mak
+++ b/configs/targets/loongarch64-linux-user.mak
@@ -1,3 +1,4 @@
# Default configuration for loongarch64-linux-user
TARGET_ARCH=loongarch64
TARGET_BASE_ARCH=loongarch
+TARGET_XML_FILES=gdb-xml/loongarch-base32.xml gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 02/29] gdb-xml: fix duplicate register in arm-neon.xml
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
2023-11-03 19:59 ` [PATCH 01/29] default-configs: Add TARGET_XML_FILES definition Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-05 20:45 ` Richard Henderson
2023-11-03 19:59 ` [PATCH 03/29] target/arm: hide the 32bit version of PAR from gdbstub Alex Bennée
` (26 subsequent siblings)
28 siblings, 1 reply; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
gdb-xml/arm-neon.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gdb-xml/arm-neon.xml b/gdb-xml/arm-neon.xml
index 9dce0a996f..d61f6b8549 100644
--- a/gdb-xml/arm-neon.xml
+++ b/gdb-xml/arm-neon.xml
@@ -76,7 +76,7 @@
<reg name="q8" bitsize="128" type="neon_q"/>
<reg name="q9" bitsize="128" type="neon_q"/>
<reg name="q10" bitsize="128" type="neon_q"/>
- <reg name="q10" bitsize="128" type="neon_q"/>
+ <reg name="q11" bitsize="128" type="neon_q"/>
<reg name="q12" bitsize="128" type="neon_q"/>
<reg name="q13" bitsize="128" type="neon_q"/>
<reg name="q14" bitsize="128" type="neon_q"/>
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 03/29] target/arm: hide the 32bit version of PAR from gdbstub
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
2023-11-03 19:59 ` [PATCH 01/29] default-configs: Add TARGET_XML_FILES definition Alex Bennée
2023-11-03 19:59 ` [PATCH 02/29] gdb-xml: fix duplicate register in arm-neon.xml Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 04/29] target/arm: hide all versions of DBGD[RS]AR " Alex Bennée
` (25 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik
This is a slightly hacky way to avoid duplicate PAR's in the system
register XML we send to gdb which causes an alias. However the other
alternative would be to post process ARMCPRegInfo once all registers
have been defined looking for textual duplicates. And that seems like
overkill.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
target/arm/helper.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 5dc0d20a84..104f9378b4 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -3727,7 +3727,7 @@ static const ARMCPRegInfo vapa_cp_reginfo[] = {
.access = PL1_RW, .resetvalue = 0,
.bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.par_s),
offsetoflow32(CPUARMState, cp15.par_ns) },
- .writefn = par_write },
+ .writefn = par_write, .type = ARM_CP_NO_GDB },
#ifndef CONFIG_USER_ONLY
/* This underdecoding is safe because the reginfo is NO_RAW. */
{ .name = "ATS", .cp = 15, .crn = 7, .crm = 8, .opc1 = 0, .opc2 = CP_ANY,
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 04/29] target/arm: hide all versions of DBGD[RS]AR from gdbstub
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (2 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 03/29] target/arm: hide the 32bit version of PAR from gdbstub Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 05/29] target/arm: hide aliased MIDR " Alex Bennée
` (24 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik
This avoids two duplicates being presented to gdbstub. As the
registers are RAZ anyway it is unlikely their value would be of use to
someone using gdbstub anyway.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
target/arm/debug_helper.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c
index 79a3659c0c..dc783adba5 100644
--- a/target/arm/debug_helper.c
+++ b/target/arm/debug_helper.c
@@ -937,14 +937,14 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
*/
{ .name = "DBGDRAR", .cp = 14, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
.access = PL0_R, .accessfn = access_tdra,
- .type = ARM_CP_CONST, .resetvalue = 0 },
+ .type = ARM_CP_CONST | ARM_CP_NO_GDB, .resetvalue = 0 },
{ .name = "MDRAR_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 0,
.access = PL1_R, .accessfn = access_tdra,
.type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "DBGDSAR", .cp = 14, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
.access = PL0_R, .accessfn = access_tdra,
- .type = ARM_CP_CONST, .resetvalue = 0 },
+ .type = ARM_CP_CONST | ARM_CP_NO_GDB, .resetvalue = 0 },
/* Monitor debug system control register; the 32-bit alias is DBGDSCRext. */
{ .name = "MDSCR_EL1", .state = ARM_CP_STATE_BOTH,
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2,
@@ -1065,9 +1065,9 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
static const ARMCPRegInfo debug_lpae_cp_reginfo[] = {
/* 64 bit access versions of the (dummy) debug registers */
{ .name = "DBGDRAR", .cp = 14, .crm = 1, .opc1 = 0,
- .access = PL0_R, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 },
+ .access = PL0_R, .type = ARM_CP_CONST | ARM_CP_64BIT | ARM_CP_NO_GDB, .resetvalue = 0 },
{ .name = "DBGDSAR", .cp = 14, .crm = 2, .opc1 = 0,
- .access = PL0_R, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 },
+ .access = PL0_R, .type = ARM_CP_CONST | ARM_CP_64BIT | ARM_CP_NO_GDB, .resetvalue = 0 },
};
static void dbgwvr_write(CPUARMState *env, const ARMCPRegInfo *ri,
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 05/29] target/arm: hide aliased MIDR from gdbstub
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (3 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 04/29] target/arm: hide all versions of DBGD[RS]AR " Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 06/29] tests/tcg: add an explicit gdbstub register tester Alex Bennée
` (23 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik
This is just a constant alias register with the same value as the
"other" MIDR so it serves no purpose being presented to gdbstub.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
target/arm/helper.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 104f9378b4..a681bcba62 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -8993,7 +8993,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
.type = ARM_CP_CONST, .resetvalue = cpu->revidr },
};
ARMCPRegInfo id_v8_midr_alias_cp_reginfo = {
- .name = "MIDR", .type = ARM_CP_ALIAS | ARM_CP_CONST,
+ .name = "MIDR", .type = ARM_CP_ALIAS | ARM_CP_CONST | ARM_CP_NO_GDB,
.cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 4,
.access = PL1_R, .resetvalue = cpu->midr
};
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 06/29] tests/tcg: add an explicit gdbstub register tester
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (4 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 05/29] target/arm: hide aliased MIDR " Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-05 12:17 ` Akihiko Odaki
2023-11-03 19:59 ` [PATCH 07/29] tests/avocado: update the tcg_plugins test Alex Bennée
` (22 subsequent siblings)
28 siblings, 1 reply; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki, Luis Machado
We already do a couple of "info registers" for specific tests but this
is a more comprehensive multiarch test. It also has some output
helpful for debugging the gdbstub by showing which XML features are
advertised and what the underlying register numbers are.
My initial motivation was to see if there are any duplicate register
names exposed via the gdbstub while I was reviewing the proposed
register interface for TCG plugins.
Mismatches between the xml and remote-desc are reported for debugging
but do not fail the test.
Cc: Akihiko Odaki <akihiko.odaki@daynix.com>
Cc: Luis Machado <luis.machado@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20231012170426.1335442-1-alex.bennee@linaro.org>
---
v2
- remove python2 compat bits
- add SPDX header, clean up comment lines
- fix duplicate check
- use field 6 (Rmt Nr) instead of field 1 (Nr) for cross-check
- more useful output on finding a duplicates and missing regs
- handle non-XML targets cleanly
---
tests/tcg/multiarch/Makefile.target | 11 +-
tests/tcg/multiarch/gdbstub/registers.py | 188 ++++++++++++++++++
.../multiarch/system/Makefile.softmmu-target | 13 +-
3 files changed, 210 insertions(+), 2 deletions(-)
create mode 100644 tests/tcg/multiarch/gdbstub/registers.py
diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target
index f3bfaf1a22..d31ba8d6ae 100644
--- a/tests/tcg/multiarch/Makefile.target
+++ b/tests/tcg/multiarch/Makefile.target
@@ -93,12 +93,21 @@ run-gdbstub-thread-breakpoint: testthread
--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
--bin $< --test $(MULTIARCH_SRC)/gdbstub/test-thread-breakpoint.py, \
hitting a breakpoint on non-main thread)
+
+run-gdbstub-registers: sha512
+ $(call run-test, $@, $(GDB_SCRIPT) \
+ --gdb $(GDB) \
+ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
+ --bin $< --test $(MULTIARCH_SRC)/gdbstub/registers.py, \
+ checking register enumeration)
+
else
run-gdbstub-%:
$(call skip-test, "gdbstub test $*", "need working gdb with $(patsubst -%,,$(TARGET_NAME)) support")
endif
EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read \
- run-gdbstub-proc-mappings run-gdbstub-thread-breakpoint
+ run-gdbstub-proc-mappings run-gdbstub-thread-breakpoint \
+ run-gdbstub-registers
# ARM Compatible Semi Hosting Tests
#
diff --git a/tests/tcg/multiarch/gdbstub/registers.py b/tests/tcg/multiarch/gdbstub/registers.py
new file mode 100644
index 0000000000..2aa0c30165
--- /dev/null
+++ b/tests/tcg/multiarch/gdbstub/registers.py
@@ -0,0 +1,188 @@
+# Exercise the register functionality by exhaustively iterating
+# through all supported registers on the system.
+#
+# This is launched via tests/guest-debug/run-test.py but you can also
+# call it directly if using it for debugging/introspection:
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import gdb
+import sys
+import xml.etree.ElementTree as ET
+
+initial_vlen = 0
+failcount = 0
+
+def report(cond, msg):
+ "Report success/fail of test."
+ if cond:
+ print("PASS: %s" % (msg))
+ else:
+ print("FAIL: %s" % (msg))
+ global failcount
+ failcount += 1
+
+
+def fetch_xml_regmap():
+ """
+ Iterate through the XML descriptions and validate.
+
+ We check for any duplicate registers and report them. Return a
+ reg_map hash containing the names, regnums and initial values of
+ all registers.
+ """
+
+ # First check the XML descriptions we have sent. Most arches
+ # support XML but a few of the ancient ones don't in which case we
+ # need to gracefully fail.
+
+ try:
+ xml = gdb.execute("maint print xml-tdesc", False, True)
+ except (gdb.error):
+ print("SKIP: target does not support XML")
+ return None
+
+ total_regs = 0
+ reg_map = {}
+ frame = gdb.selected_frame()
+
+ tree = ET.fromstring(xml)
+ for f in tree.findall("feature"):
+ name = f.attrib["name"]
+ regs = f.findall("reg")
+
+ total = len(regs)
+ total_regs += total
+ base = int(regs[0].attrib["regnum"])
+ top = int(regs[-1].attrib["regnum"])
+
+ print(f"feature: {name} has {total} registers from {base} to {top}")
+
+ for r in regs:
+ name = r.attrib["name"]
+ regnum = int(r.attrib["regnum"])
+ value = frame.read_register(name).__str__()
+ entry = { "name": name, "initial": value, "regnum": regnum }
+
+ if name in reg_map:
+ report(False, f"duplicate register {entry} vs {reg_map[name]}")
+ continue
+
+ reg_map[name] = entry
+
+ # Validate we match
+ report(total_regs == len(reg_map.keys()),
+ f"counted all {total_regs} registers in XML")
+
+ return reg_map
+
+def crosscheck_remote_xml(reg_map):
+ """
+ Cross-check the list of remote-registers with the XML info.
+ """
+
+ remote = gdb.execute("maint print remote-registers", False, True)
+ r_regs = remote.split("\n")
+
+ total_regs = len(reg_map.keys())
+ total_r_regs = 0
+
+ for r in r_regs:
+ fields = r.split()
+ # Some of the registers reported here are "pseudo" registers that
+ # gdb invents based on actual registers so we need to filter them
+ # out.
+ if len(fields) == 8:
+ r_name = fields[0]
+ r_regnum = int(fields[6])
+
+ # check in the XML
+ try:
+ x_reg = reg_map[r_name]
+ x_reg["seen"] = True
+ except KeyError:
+ report(False, "{r_name} not in XML description")
+ continue
+
+ x_regnum = x_reg["regnum"]
+ if r_regnum != x_regnum:
+ report(False, f"{r_name} {r_regnum} == {x_regnum} (xml)")
+ else:
+ total_r_regs += 1
+
+ # Just print a mismatch in totals as gdb will filter out 64 bit
+ # registers on a 32 bit machine. Also print what is missing to
+ # help with debug.
+ if total_regs != total_r_regs:
+ print(f"xml-tdesc ({total_regs}) and remote-registers ({total_r_regs}) do not agree")
+
+ for x_key in reg_map.keys():
+ x_reg = reg_map[x_key]
+ if "seen" not in x_reg:
+ print(f"{x_reg} wasn't seen in remote-registers")
+
+def complete_and_diff(reg_map):
+ """
+ Let the program run to (almost) completion and then iterate
+ through all the registers we know about and report which ones have
+ changed.
+ """
+ # Let the program get to the end and we can check what changed
+ gdb.Breakpoint("_exit")
+ gdb.execute("continue")
+
+ frame = gdb.selected_frame()
+ changed = 0
+
+ for e in reg_map.values():
+ name = e["name"]
+ old_val = e["initial"]
+
+ try:
+ new_val = frame.read_register(name).__str__()
+ except:
+ report(False, f"failed to read {name} at end of run")
+ continue
+
+ if new_val != old_val:
+ print(f"{name} changes from {old_val} to {new_val}")
+ changed += 1
+
+ # as long as something changed we can be confident its working
+ report(changed > 0, f"{changed} registers were changed")
+
+
+def run_test():
+ "Run through the tests"
+
+ reg_map = fetch_xml_regmap()
+
+ if reg_map is not None:
+ crosscheck_remote_xml(reg_map)
+ complete_and_diff(reg_map)
+
+
+#
+# This runs as the script it sourced (via -x, via run-test.py)
+#
+try:
+ inferior = gdb.selected_inferior()
+ arch = inferior.architecture()
+ print("ATTACHED: %s" % arch.name())
+except (gdb.error, AttributeError):
+ print("SKIPPING (not connected)", file=sys.stderr)
+ exit(0)
+
+if gdb.parse_and_eval('$pc') == 0:
+ print("SKIP: PC not set")
+ exit(0)
+
+try:
+ run_test()
+except (gdb.error):
+ print ("GDB Exception: %s" % (sys.exc_info()[0]))
+ failcount += 1
+ pass
+
+print("All tests complete: %d failures" % failcount)
+exit(failcount)
diff --git a/tests/tcg/multiarch/system/Makefile.softmmu-target b/tests/tcg/multiarch/system/Makefile.softmmu-target
index dee4f58dea..32dc0f9830 100644
--- a/tests/tcg/multiarch/system/Makefile.softmmu-target
+++ b/tests/tcg/multiarch/system/Makefile.softmmu-target
@@ -48,9 +48,20 @@ run-gdbstub-untimely-packet: hello
$(call quiet-command, \
(! grep -Fq 'Packet instead of Ack, ignoring it' untimely-packet.gdb.err), \
"GREP", file untimely-packet.gdb.err)
+
+run-gdbstub-registers: memory
+ $(call run-test, $@, $(GDB_SCRIPT) \
+ --gdb $(GDB) \
+ --qemu $(QEMU) \
+ --output $<.registers.gdb.out \
+ --qargs \
+ "-monitor none -display none -chardev file$(COMMA)path=$<.out$(COMMA)id=output $(QEMU_OPTS)" \
+ --bin $< --test $(MULTIARCH_SRC)/gdbstub/registers.py, \
+ softmmu gdbstub support)
else
run-gdbstub-%:
$(call skip-test, "gdbstub test $*", "need working gdb with $(patsubst -%,,$(TARGET_NAME)) support")
endif
-MULTIARCH_RUNS += run-gdbstub-memory run-gdbstub-interrupt run-gdbstub-untimely-packet
+MULTIARCH_RUNS += run-gdbstub-memory run-gdbstub-interrupt \
+ run-gdbstub-untimely-packet run-gdbstub-registers
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 07/29] tests/avocado: update the tcg_plugins test
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (5 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 06/29] tests/tcg: add an explicit gdbstub register tester Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 08/29] gdbstub: Add num_regs member to GDBFeature Alex Bennée
` (21 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik
There are a number of things that are broken on the test currently so
lets fix that up:
- replace retired Debian kernel for tuxrun_baseline one
- remove "detected repeat instructions test" since ea185a55
- log total counted instructions/memory accesses
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
tests/avocado/tcg_plugins.py | 28 ++++++++++++++++++----------
1 file changed, 18 insertions(+), 10 deletions(-)
diff --git a/tests/avocado/tcg_plugins.py b/tests/avocado/tcg_plugins.py
index 642d2e49e3..15fd87b2c1 100644
--- a/tests/avocado/tcg_plugins.py
+++ b/tests/avocado/tcg_plugins.py
@@ -54,13 +54,11 @@ def run_vm(self, kernel_path, kernel_command_line,
class PluginKernelNormal(PluginKernelBase):
def _grab_aarch64_kernel(self):
- kernel_url = ('http://security.debian.org/'
- 'debian-security/pool/updates/main/l/linux-signed-arm64/'
- 'linux-image-4.19.0-12-arm64_4.19.152-1_arm64.deb')
- kernel_sha1 = '2036c2792f80ac9c4ccaae742b2e0a28385b6010'
- kernel_deb = self.fetch_asset(kernel_url, asset_hash=kernel_sha1)
- kernel_path = self.extract_from_deb(kernel_deb,
- "/boot/vmlinuz-4.19.0-12-arm64")
+ kernel_url = ('https://storage.tuxboot.com/20230331/arm64/Image')
+ kernel_sha256 = 'ce95a7101a5fecebe0fe630deee6bd97b32ba41bc8754090e9ad8961ea8674c7'
+ kernel_path = self.fetch_asset(kernel_url,
+ asset_hash=kernel_sha256,
+ algorithm = "sha256")
return kernel_path
def test_aarch64_virt_insn(self):
@@ -88,6 +86,10 @@ def test_aarch64_virt_insn(self):
m = re.search(br"insns: (?P<count>\d+)", s)
if "count" not in m.groupdict():
self.fail("Failed to find instruction count")
+ else:
+ count = int(m.group("count"))
+ self.log.info(f"Counted: {count} instructions")
+
def test_aarch64_virt_insn_icount(self):
"""
@@ -111,9 +113,13 @@ def test_aarch64_virt_insn_icount(self):
with plugin_log as lf, \
mmap.mmap(lf.fileno(), 0, access=mmap.ACCESS_READ) as s:
- m = re.search(br"detected repeat execution @ (?P<addr>0x[0-9A-Fa-f]+)", s)
- if m is not None and "addr" in m.groupdict():
- self.fail("detected repeated instructions")
+
+ m = re.search(br"insns: (?P<count>\d+)", s)
+ if "count" not in m.groupdict():
+ self.fail("Failed to find instruction count")
+ else:
+ count = int(m.group("count"))
+ self.log.info(f"Counted: {count} instructions")
def test_aarch64_virt_mem_icount(self):
"""
@@ -145,3 +151,5 @@ def test_aarch64_virt_mem_icount(self):
callback = int(m[1])
if inline != callback:
self.fail("mismatched access counts")
+ else:
+ self.log.info(f"Counted {inline} memory accesses")
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 08/29] gdbstub: Add num_regs member to GDBFeature
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (6 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 07/29] tests/avocado: update the tcg_plugins test Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 09/29] gdbstub: Introduce gdb_find_static_feature() Alex Bennée
` (20 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
From: Akihiko Odaki <akihiko.odaki@daynix.com>
Currently the number of registers exposed to GDB is written as magic
numbers in code. Derive the number of registers GDB actually see from
XML files to replace the magic numbers in code later.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20231025093128.33116-2-akihiko.odaki@daynix.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
include/exec/gdbstub.h | 1 +
scripts/feature_to_c.py | 46 +++++++++++++++++++++++++++++++++++++++--
2 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 1a01c35f8e..a43aa34dad 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -13,6 +13,7 @@
typedef struct GDBFeature {
const char *xmlname;
const char *xml;
+ int num_regs;
} GDBFeature;
diff --git a/scripts/feature_to_c.py b/scripts/feature_to_c.py
index bcbcb83beb..e04d6b2df7 100644
--- a/scripts/feature_to_c.py
+++ b/scripts/feature_to_c.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-import os, sys
+import os, sys, xml.etree.ElementTree
def writeliteral(indent, bytes):
sys.stdout.write(' ' * indent)
@@ -39,10 +39,52 @@ def writeliteral(indent, bytes):
with open(input, 'rb') as file:
read = file.read()
+ parser = xml.etree.ElementTree.XMLPullParser(['start', 'end'])
+ parser.feed(read)
+ events = parser.read_events()
+ event, element = next(events)
+ if event != 'start':
+ sys.stderr.write(f'unexpected event: {event}\n')
+ exit(1)
+ if element.tag != 'feature':
+ sys.stderr.write(f'unexpected start tag: {element.tag}\n')
+ exit(1)
+
+ regnum = 0
+ regnums = []
+ tags = ['feature']
+ for event, element in events:
+ if event == 'end':
+ if element.tag != tags[len(tags) - 1]:
+ sys.stderr.write(f'unexpected end tag: {element.tag}\n')
+ exit(1)
+
+ tags.pop()
+ if element.tag == 'feature':
+ break
+ elif event == 'start':
+ if len(tags) < 2 and element.tag == 'reg':
+ if 'regnum' in element.attrib:
+ regnum = int(element.attrib['regnum'])
+
+ regnums.append(regnum)
+ regnum += 1
+
+ tags.append(element.tag)
+ else:
+ raise Exception(f'unexpected event: {event}\n')
+
+ if len(tags):
+ sys.stderr.write('unterminated feature tag\n')
+ exit(1)
+
+ base_reg = min(regnums)
+ num_regs = max(regnums) - base_reg + 1 if len(regnums) else 0
+
sys.stdout.write(' {\n')
writeliteral(8, bytes(os.path.basename(input), 'utf-8'))
sys.stdout.write(',\n')
writeliteral(8, read)
- sys.stdout.write('\n },\n')
+ sys.stdout.write(f',\n {num_regs},\n }},\n')
sys.stdout.write(' { NULL }\n};\n')
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 09/29] gdbstub: Introduce gdb_find_static_feature()
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (7 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 08/29] gdbstub: Add num_regs member to GDBFeature Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 10/29] gdbstub: Introduce GDBFeatureBuilder Alex Bennée
` (19 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
From: Akihiko Odaki <akihiko.odaki@daynix.com>
This function is useful to determine the number of registers exposed to
GDB from the XML name.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20231025093128.33116-3-akihiko.odaki@daynix.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
include/exec/gdbstub.h | 8 ++++++++
gdbstub/gdbstub.c | 13 +++++++++++++
2 files changed, 21 insertions(+)
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index a43aa34dad..7fe00506c7 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -44,6 +44,14 @@ void gdb_register_coprocessor(CPUState *cpu,
*/
int gdbserver_start(const char *port_or_device);
+/**
+ * gdb_find_static_feature() - Find a static feature.
+ * @xmlname: The name of the XML.
+ *
+ * Return: The static feature.
+ */
+const GDBFeature *gdb_find_static_feature(const char *xmlname);
+
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 29540a0284..ae24c4848f 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -422,6 +422,19 @@ static const char *get_feature_xml(const char *p, const char **newp,
return NULL;
}
+const GDBFeature *gdb_find_static_feature(const char *xmlname)
+{
+ const GDBFeature *feature;
+
+ for (feature = gdb_static_features; feature->xmlname; feature++) {
+ if (!strcmp(feature->xmlname, xmlname)) {
+ return feature;
+ }
+ }
+
+ g_assert_not_reached();
+}
+
static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 10/29] gdbstub: Introduce GDBFeatureBuilder
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (8 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 09/29] gdbstub: Introduce gdb_find_static_feature() Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 11/29] target/arm: Use GDBFeature for dynamic XML Alex Bennée
` (18 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
From: Akihiko Odaki <akihiko.odaki@daynix.com>
GDBFeatureBuilder unifies the logic to generate dynamic GDBFeature.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20231025093128.33116-4-akihiko.odaki@daynix.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
include/exec/gdbstub.h | 50 ++++++++++++++++++++++++++++++++
gdbstub/gdbstub.c | 65 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 115 insertions(+)
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 7fe00506c7..d8a3c56fa2 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -16,6 +16,12 @@ typedef struct GDBFeature {
int num_regs;
} GDBFeature;
+typedef struct GDBFeatureBuilder {
+ GDBFeature *feature;
+ GPtrArray *xml;
+ int base_reg;
+} GDBFeatureBuilder;
+
/* Get or set a register. Returns the size of the register. */
typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg);
@@ -44,6 +50,50 @@ void gdb_register_coprocessor(CPUState *cpu,
*/
int gdbserver_start(const char *port_or_device);
+/**
+ * gdb_feature_builder_init() - Initialize GDBFeatureBuilder.
+ * @builder: The builder to be initialized.
+ * @feature: The feature to be filled.
+ * @name: The name of the feature.
+ * @xmlname: The name of the XML.
+ * @base_reg: The base number of the register ID.
+ */
+void gdb_feature_builder_init(GDBFeatureBuilder *builder, GDBFeature *feature,
+ const char *name, const char *xmlname,
+ int base_reg);
+
+/**
+ * gdb_feature_builder_append_tag() - Append a tag.
+ * @builder: The builder.
+ * @format: The format of the tag.
+ * @...: The values to be formatted.
+ */
+void G_GNUC_PRINTF(2, 3)
+gdb_feature_builder_append_tag(const GDBFeatureBuilder *builder,
+ const char *format, ...);
+
+/**
+ * gdb_feature_builder_append_reg() - Append a register.
+ * @builder: The builder.
+ * @name: The register's name; it must be unique within a CPU.
+ * @bitsize: The register's size, in bits.
+ * @regnum: The offset of the register's number in the feature.
+ * @type: The type of the register.
+ * @group: The register group to which this register belongs; it can be NULL.
+ */
+void gdb_feature_builder_append_reg(const GDBFeatureBuilder *builder,
+ const char *name,
+ int bitsize,
+ int regnum,
+ const char *type,
+ const char *group);
+
+/**
+ * gdb_feature_builder_end() - End building GDBFeature.
+ * @builder: The builder.
+ */
+void gdb_feature_builder_end(const GDBFeatureBuilder *builder);
+
/**
* gdb_find_static_feature() - Find a static feature.
* @xmlname: The name of the XML.
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index ae24c4848f..ebb912da1b 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -422,6 +422,71 @@ static const char *get_feature_xml(const char *p, const char **newp,
return NULL;
}
+void gdb_feature_builder_init(GDBFeatureBuilder *builder, GDBFeature *feature,
+ const char *name, const char *xmlname,
+ int base_reg)
+{
+ char *header = g_markup_printf_escaped(
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE feature SYSTEM \"gdb-target.dtd\">"
+ "<feature name=\"%s\">",
+ name);
+
+ builder->feature = feature;
+ builder->xml = g_ptr_array_new();
+ g_ptr_array_add(builder->xml, header);
+ builder->base_reg = base_reg;
+ feature->xmlname = xmlname;
+ feature->num_regs = 0;
+}
+
+void gdb_feature_builder_append_tag(const GDBFeatureBuilder *builder,
+ const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ g_ptr_array_add(builder->xml, g_markup_vprintf_escaped(format, ap));
+ va_end(ap);
+}
+
+void gdb_feature_builder_append_reg(const GDBFeatureBuilder *builder,
+ const char *name,
+ int bitsize,
+ int regnum,
+ const char *type,
+ const char *group)
+{
+ if (builder->feature->num_regs < regnum) {
+ builder->feature->num_regs = regnum;
+ }
+
+ if (group) {
+ gdb_feature_builder_append_tag(
+ builder,
+ "<reg name=\"%s\" bitsize=\"%d\" regnum=\"%d\" type=\"%s\" group=\"%s\"/>",
+ name, bitsize, builder->base_reg + regnum, type, group);
+ } else {
+ gdb_feature_builder_append_tag(
+ builder,
+ "<reg name=\"%s\" bitsize=\"%d\" regnum=\"%d\" type=\"%s\"/>",
+ name, bitsize, builder->base_reg + regnum, type);
+ }
+}
+
+void gdb_feature_builder_end(const GDBFeatureBuilder *builder)
+{
+ g_ptr_array_add(builder->xml, (void *)"</feature>");
+ g_ptr_array_add(builder->xml, NULL);
+
+ builder->feature->xml = g_strjoinv(NULL, (void *)builder->xml->pdata);
+
+ for (guint i = 0; i < builder->xml->len - 2; i++) {
+ g_free(g_ptr_array_index(builder->xml, i));
+ }
+
+ g_ptr_array_free(builder->xml, TRUE);
+}
+
const GDBFeature *gdb_find_static_feature(const char *xmlname)
{
const GDBFeature *feature;
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 11/29] target/arm: Use GDBFeature for dynamic XML
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (9 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 10/29] gdbstub: Introduce GDBFeatureBuilder Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 12/29] target/ppc: " Alex Bennée
` (17 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
From: Akihiko Odaki <akihiko.odaki@daynix.com>
In preparation for a change to use GDBFeature as a parameter of
gdb_register_coprocessor(), convert the internal representation of
dynamic feature from plain XML to GDBFeature.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20231025093128.33116-5-akihiko.odaki@daynix.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
target/arm/cpu.h | 21 +++---
target/arm/internals.h | 2 +-
target/arm/gdbstub.c | 142 ++++++++++++++++++++---------------------
target/arm/gdbstub64.c | 95 +++++++++++++--------------
4 files changed, 123 insertions(+), 137 deletions(-)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index d51dfe48db..2549681367 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -25,6 +25,7 @@
#include "hw/registerfields.h"
#include "cpu-qom.h"
#include "exec/cpu-defs.h"
+#include "exec/gdbstub.h"
#include "qapi/qapi-types-common.h"
/* ARM processors have a weak memory model */
@@ -136,23 +137,21 @@ enum {
*/
/**
- * DynamicGDBXMLInfo:
- * @desc: Contains the XML descriptions.
- * @num: Number of the registers in this XML seen by GDB.
+ * DynamicGDBFeatureInfo:
+ * @desc: Contains the feature descriptions.
* @data: A union with data specific to the set of registers
* @cpregs_keys: Array that contains the corresponding Key of
* a given cpreg with the same order of the cpreg
* in the XML description.
*/
-typedef struct DynamicGDBXMLInfo {
- char *desc;
- int num;
+typedef struct DynamicGDBFeatureInfo {
+ GDBFeature desc;
union {
struct {
uint32_t *keys;
} cpregs;
} data;
-} DynamicGDBXMLInfo;
+} DynamicGDBFeatureInfo;
/* CPU state for each instance of a generic timer (in cp15 c14) */
typedef struct ARMGenericTimer {
@@ -880,10 +879,10 @@ struct ArchCPU {
uint64_t *cpreg_vmstate_values;
int32_t cpreg_vmstate_array_len;
- DynamicGDBXMLInfo dyn_sysreg_xml;
- DynamicGDBXMLInfo dyn_svereg_xml;
- DynamicGDBXMLInfo dyn_m_systemreg_xml;
- DynamicGDBXMLInfo dyn_m_secextreg_xml;
+ DynamicGDBFeatureInfo dyn_sysreg_feature;
+ DynamicGDBFeatureInfo dyn_svereg_feature;
+ DynamicGDBFeatureInfo dyn_m_systemreg_feature;
+ DynamicGDBFeatureInfo dyn_m_secextreg_feature;
/* Timers used by the generic (architected) timer */
QEMUTimer *gt_timer[NUM_GTIMERS];
diff --git a/target/arm/internals.h b/target/arm/internals.h
index c837506e44..989416e613 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1440,7 +1440,7 @@ static inline uint64_t pmu_counter_mask(CPUARMState *env)
}
#ifdef TARGET_AARCH64
-int arm_gen_dynamic_svereg_xml(CPUState *cpu, int base_reg);
+GDBFeature *arm_gen_dynamic_svereg_feature(CPUState *cpu, int base_reg);
int aarch64_gdb_get_sve_reg(CPUARMState *env, GByteArray *buf, int reg);
int aarch64_gdb_set_sve_reg(CPUARMState *env, uint8_t *buf, int reg);
int aarch64_gdb_get_fpu_reg(CPUARMState *env, GByteArray *buf, int reg);
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index 28f546a5ff..5949adfb31 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -26,11 +26,11 @@
#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
@@ -216,7 +216,7 @@ static int arm_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg)
const ARMCPRegInfo *ri;
uint32_t key;
- key = cpu->dyn_sysreg_xml.data.cpregs.keys[reg];
+ 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)) {
@@ -233,34 +233,32 @@ static int arm_gdb_set_sysreg(CPUARMState *env, uint8_t *buf, int reg)
return 0;
}
-static void arm_gen_one_xml_sysreg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml,
+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 = (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(¶m->builder, dyn_feature,
+ ri, ri_key, 64, param->n++);
}
} else {
if (ri->state == ARM_CP_STATE_AA32) {
@@ -269,32 +267,32 @@ 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(¶m->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(¶m->builder, dyn_feature,
+ ri, ri_key, 32, param->n++);
}
}
}
}
}
-static 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, ¶m);
- 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(¶m.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, ¶m);
+ gdb_feature_builder_end(¶m.builder);
+ return &cpu->dyn_sysreg_feature.desc;
}
#ifdef CONFIG_TCG
@@ -386,31 +384,29 @@ static int arm_gdb_set_m_systemreg(CPUARMState *env, uint8_t *buf, int reg)
return 0; /* TODO */
}
-static int arm_gen_dynamic_m_systemreg_xml(CPUState *cs, int orig_base_reg)
+static GDBFeature *arm_gen_dynamic_m_systemreg_feature(CPUState *cs,
+ int base_reg)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
- GString *s = g_string_new(NULL);
- int base_reg = orig_base_reg;
+ GDBFeatureBuilder builder;
+ int reg = 0;
int i;
- 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.arm.m-system\">\n");
+ 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)) {
- g_string_append_printf(s,
- "<reg name=\"%s\" bitsize=\"32\" regnum=\"%d\"/>\n",
- m_sysreg_def[i].name, base_reg++);
+ gdb_feature_builder_append_reg(&builder, m_sysreg_def[i].name, 32,
+ reg++, "int", NULL);
}
}
- g_string_append_printf(s, "</feature>");
- cpu->dyn_m_systemreg_xml.desc = g_string_free(s, false);
- cpu->dyn_m_systemreg_xml.num = base_reg - orig_base_reg;
+ gdb_feature_builder_end(&builder);
- return cpu->dyn_m_systemreg_xml.num;
+ return &cpu->dyn_m_systemreg_feature.desc;
}
#ifndef CONFIG_USER_ONLY
@@ -428,31 +424,31 @@ static int arm_gdb_set_m_secextreg(CPUARMState *env, uint8_t *buf, int reg)
return 0; /* TODO */
}
-static int arm_gen_dynamic_m_secextreg_xml(CPUState *cs, int orig_base_reg)
+static GDBFeature *arm_gen_dynamic_m_secextreg_feature(CPUState *cs,
+ int base_reg)
{
ARMCPU *cpu = ARM_CPU(cs);
- GString *s = g_string_new(NULL);
- int base_reg = orig_base_reg;
+ GDBFeatureBuilder builder;
+ char *name;
+ int reg = 0;
int i;
- 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.arm.secext\">\n");
+ 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++) {
- g_string_append_printf(s,
- "<reg name=\"%s_ns\" bitsize=\"32\" regnum=\"%d\"/>\n",
- m_sysreg_def[i].name, base_reg++);
- g_string_append_printf(s,
- "<reg name=\"%s_s\" bitsize=\"32\" regnum=\"%d\"/>\n",
- m_sysreg_def[i].name, base_reg++);
+ 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);
}
- g_string_append_printf(s, "</feature>");
- cpu->dyn_m_secextreg_xml.desc = g_string_free(s, false);
- cpu->dyn_m_secextreg_xml.num = base_reg - orig_base_reg;
+ gdb_feature_builder_end(&builder);
- return cpu->dyn_m_secextreg_xml.num;
+ return &cpu->dyn_m_secextreg_feature.desc;
}
#endif
#endif /* CONFIG_TCG */
@@ -462,14 +458,14 @@ const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
ARMCPU *cpu = ARM_CPU(cs);
if (strcmp(xmlname, "system-registers.xml") == 0) {
- return cpu->dyn_sysreg_xml.desc;
+ return cpu->dyn_sysreg_feature.desc.xml;
} else if (strcmp(xmlname, "sve-registers.xml") == 0) {
- return cpu->dyn_svereg_xml.desc;
+ return cpu->dyn_svereg_feature.desc.xml;
} else if (strcmp(xmlname, "arm-m-system.xml") == 0) {
- return cpu->dyn_m_systemreg_xml.desc;
+ return cpu->dyn_m_systemreg_feature.desc.xml;
#ifndef CONFIG_USER_ONLY
} else if (strcmp(xmlname, "arm-m-secext.xml") == 0) {
- return cpu->dyn_m_secextreg_xml.desc;
+ return cpu->dyn_m_secextreg_feature.desc.xml;
#endif
}
return NULL;
@@ -487,7 +483,7 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
*/
#ifdef TARGET_AARCH64
if (isar_feature_aa64_sve(&cpu->isar)) {
- int nreg = arm_gen_dynamic_svereg_xml(cs, cs->gdb_num_regs);
+ int nreg = arm_gen_dynamic_svereg_feature(cs, cs->gdb_num_regs)->num_regs;
gdb_register_coprocessor(cs, aarch64_gdb_get_sve_reg,
aarch64_gdb_set_sve_reg, nreg,
"sve-registers.xml", 0);
@@ -533,20 +529,20 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
1, "arm-m-profile-mve.xml", 0);
}
gdb_register_coprocessor(cs, arm_gdb_get_sysreg, arm_gdb_set_sysreg,
- arm_gen_dynamic_sysreg_xml(cs, cs->gdb_num_regs),
+ arm_gen_dynamic_sysreg_feature(cs, cs->gdb_num_regs)->num_regs,
"system-registers.xml", 0);
#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_xml(cs, cs->gdb_num_regs),
+ arm_gen_dynamic_m_systemreg_feature(cs, cs->gdb_num_regs)->num_regs,
"arm-m-system.xml", 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_xml(cs, cs->gdb_num_regs),
+ arm_gen_dynamic_m_secextreg_feature(cs, cs->gdb_num_regs)->num_regs,
"arm-m-secext.xml", 0);
}
#endif
diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c
index d7b79a6589..5286d5c604 100644
--- a/target/arm/gdbstub64.c
+++ b/target/arm/gdbstub64.c
@@ -247,7 +247,7 @@ int aarch64_gdb_set_pauth_reg(CPUARMState *env, uint8_t *buf, int reg)
return 0;
}
-static void output_vector_union_type(GString *s, int reg_width,
+static void output_vector_union_type(GDBFeatureBuilder *builder, int reg_width,
const char *name)
{
struct TypeSize {
@@ -282,10 +282,10 @@ static void output_vector_union_type(GString *s, int reg_width,
/* First define types and totals in a whole VL */
for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
- g_string_append_printf(s,
- "<vector id=\"%s%c%c\" type=\"%s\" count=\"%d\"/>",
- name, vec_lanes[i].sz, vec_lanes[i].suffix,
- vec_lanes[i].gdb_type, reg_width / vec_lanes[i].size);
+ gdb_feature_builder_append_tag(
+ builder, "<vector id=\"%s%c%c\" type=\"%s\" count=\"%d\"/>",
+ name, vec_lanes[i].sz, vec_lanes[i].suffix,
+ vec_lanes[i].gdb_type, reg_width / vec_lanes[i].size);
}
/*
@@ -296,86 +296,77 @@ static void output_vector_union_type(GString *s, int reg_width,
for (i = 0; i < ARRAY_SIZE(suf); i++) {
int bits = 8 << i;
- g_string_append_printf(s, "<union id=\"%sn%c\">", name, suf[i]);
+ gdb_feature_builder_append_tag(builder, "<union id=\"%sn%c\">",
+ name, 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=\"%s%c%c\"/>",
- vec_lanes[j].suffix, name,
- vec_lanes[j].sz, vec_lanes[j].suffix);
+ gdb_feature_builder_append_tag(
+ builder, "<field name=\"%c\" type=\"%s%c%c\"/>",
+ vec_lanes[j].suffix, name,
+ vec_lanes[j].sz, vec_lanes[j].suffix);
}
}
- g_string_append(s, "</union>");
+ gdb_feature_builder_append_tag(builder, "</union>");
}
/* And now the final union of unions */
- g_string_append_printf(s, "<union id=\"%s\">", name);
+ gdb_feature_builder_append_tag(builder, "<union id=\"%s\">", name);
for (i = ARRAY_SIZE(suf) - 1; i >= 0; i--) {
- g_string_append_printf(s, "<field name=\"%c\" type=\"%sn%c\"/>",
- suf[i], name, suf[i]);
+ gdb_feature_builder_append_tag(builder,
+ "<field name=\"%c\" type=\"%sn%c\"/>",
+ suf[i], name, suf[i]);
}
- g_string_append(s, "</union>");
+ gdb_feature_builder_append_tag(builder, "</union>");
}
-int arm_gen_dynamic_svereg_xml(CPUState *cs, int orig_base_reg)
+GDBFeature *arm_gen_dynamic_svereg_feature(CPUState *cs, int base_reg)
{
ARMCPU *cpu = ARM_CPU(cs);
- GString *s = g_string_new(NULL);
- DynamicGDBXMLInfo *info = &cpu->dyn_svereg_xml;
int reg_width = cpu->sve_max_vq * 128;
int pred_width = cpu->sve_max_vq * 16;
- int base_reg = orig_base_reg;
+ GDBFeatureBuilder builder;
+ char *name;
+ int reg = 0;
int i;
- 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\">");
+ gdb_feature_builder_init(&builder, &cpu->dyn_svereg_feature.desc,
+ "org.gnu.gdb.aarch64.sve", "sve-registers.xml",
+ base_reg);
/* Create the vector union type. */
- output_vector_union_type(s, reg_width, "svev");
+ output_vector_union_type(&builder, reg_width, "svev");
/* Create the predicate vector type. */
- g_string_append_printf(s,
- "<vector id=\"svep\" type=\"uint8\" count=\"%d\"/>",
- pred_width / 8);
+ gdb_feature_builder_append_tag(
+ &builder, "<vector id=\"svep\" type=\"uint8\" count=\"%d\"/>",
+ pred_width / 8);
/* Define the vector registers. */
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++);
+ name = g_strdup_printf("z%d", i);
+ gdb_feature_builder_append_reg(&builder, name, reg_width, reg++,
+ "svev", NULL);
}
/* 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++);
+ gdb_feature_builder_append_reg(&builder, "fpsr", 32, reg++,
+ "int", "float");
+ gdb_feature_builder_append_reg(&builder, "fpcr", 32, reg++,
+ "int", "float");
/* Define the predicate registers. */
for (i = 0; i < 16; i++) {
- g_string_append_printf(s,
- "<reg name=\"p%d\" bitsize=\"%d\""
- " regnum=\"%d\" type=\"svep\"/>",
- i, pred_width, base_reg++);
+ name = g_strdup_printf("p%d", i);
+ gdb_feature_builder_append_reg(&builder, name, pred_width, reg++,
+ "svep", NULL);
}
- g_string_append_printf(s,
- "<reg name=\"ffr\" bitsize=\"%d\""
- " regnum=\"%d\" group=\"vector\""
- " type=\"svep\"/>",
- pred_width, base_reg++);
+ gdb_feature_builder_append_reg(&builder, "ffr", pred_width, reg++,
+ "svep", "vector");
/* Define the vector length pseudo-register. */
- g_string_append_printf(s,
- "<reg name=\"vg\" bitsize=\"64\""
- " regnum=\"%d\" type=\"int\"/>",
- base_reg++);
+ gdb_feature_builder_append_reg(&builder, "vg", 64, reg++, "int", NULL);
- g_string_append_printf(s, "</feature>");
+ gdb_feature_builder_end(&builder);
- info->desc = g_string_free(s, false);
- info->num = base_reg - orig_base_reg;
- return info->num;
+ return &cpu->dyn_svereg_feature.desc;
}
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 12/29] target/ppc: Use GDBFeature for dynamic XML
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (10 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 11/29] target/arm: Use GDBFeature for dynamic XML Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 13/29] target/riscv: " Alex Bennée
` (16 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
From: Akihiko Odaki <akihiko.odaki@daynix.com>
In preparation for a change to use GDBFeature as a parameter of
gdb_register_coprocessor(), convert the internal representation of
dynamic feature from plain XML to GDBFeature.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20231025093128.33116-6-akihiko.odaki@daynix.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
target/ppc/cpu-qom.h | 4 ++--
target/ppc/cpu.h | 1 -
target/ppc/cpu_init.c | 4 ----
target/ppc/gdbstub.c | 51 ++++++++++++++++---------------------------
4 files changed, 21 insertions(+), 39 deletions(-)
diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h
index be33786bd8..8d5ebba5d3 100644
--- a/target/ppc/cpu-qom.h
+++ b/target/ppc/cpu-qom.h
@@ -20,6 +20,7 @@
#ifndef QEMU_PPC_CPU_QOM_H
#define QEMU_PPC_CPU_QOM_H
+#include "exec/gdbstub.h"
#include "hw/core/cpu.h"
#include "qom/object.h"
@@ -186,8 +187,7 @@ struct PowerPCCPUClass {
int bfd_mach;
uint32_t l1_dcache_size, l1_icache_size;
#ifndef CONFIG_USER_ONLY
- unsigned int gdb_num_sprs;
- const char *gdb_spr_xml;
+ GDBFeature gdb_spr;
#endif
const PPCHash64Options *hash64_opts;
struct ppc_radix_page_info *radix_page_info;
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 30392ebeee..848062bc9f 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1384,7 +1384,6 @@ int ppc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
int ppc_cpu_gdb_write_register_apple(CPUState *cpu, uint8_t *buf, int reg);
#ifndef CONFIG_USER_ONLY
hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-void ppc_gdb_gen_spr_xml(PowerPCCPU *cpu);
const char *ppc_gdb_get_dynamic_xml(CPUState *cs, const char *xml_name);
#endif
int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 40fe14a6c2..a0178c3ce8 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6682,10 +6682,6 @@ static void init_ppc_proc(PowerPCCPU *cpu)
/* PowerPC implementation specific initialisations (SPRs, timers, ...) */
(*pcc->init_proc)(env);
-#if !defined(CONFIG_USER_ONLY)
- ppc_gdb_gen_spr_xml(cpu);
-#endif
-
/* MSR bits & flags consistency checks */
if (env->msr_mask & (1 << 25)) {
switch (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE)) {
diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c
index ec5731e5d6..e3be3dbd10 100644
--- a/target/ppc/gdbstub.c
+++ b/target/ppc/gdbstub.c
@@ -300,15 +300,23 @@ int ppc_cpu_gdb_write_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
}
#ifndef CONFIG_USER_ONLY
-void ppc_gdb_gen_spr_xml(PowerPCCPU *cpu)
+static void gdb_gen_spr_feature(CPUState *cs)
{
- PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
- GString *xml;
- char *spr_name;
+ GDBFeatureBuilder builder;
unsigned int num_regs = 0;
int i;
+ if (pcc->gdb_spr.xml) {
+ return;
+ }
+
+ gdb_feature_builder_init(&builder, &pcc->gdb_spr,
+ "org.qemu.power.spr", "power-spr.xml",
+ cs->gdb_num_regs);
+
for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) {
ppc_spr_t *spr = &env->spr_cb[i];
@@ -326,35 +334,13 @@ void ppc_gdb_gen_spr_xml(PowerPCCPU *cpu)
*/
spr->gdb_id = num_regs;
num_regs++;
- }
-
- if (pcc->gdb_spr_xml) {
- return;
- }
- xml = g_string_new("<?xml version=\"1.0\"?>");
- g_string_append(xml, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
- g_string_append(xml, "<feature name=\"org.qemu.power.spr\">");
-
- for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) {
- ppc_spr_t *spr = &env->spr_cb[i];
-
- if (!spr->name) {
- continue;
- }
-
- spr_name = g_ascii_strdown(spr->name, -1);
- g_string_append_printf(xml, "<reg name=\"%s\"", spr_name);
- g_free(spr_name);
-
- g_string_append_printf(xml, " bitsize=\"%d\"", TARGET_LONG_BITS);
- g_string_append(xml, " group=\"spr\"/>");
+ gdb_feature_builder_append_reg(&builder, g_ascii_strdown(spr->name, -1),
+ TARGET_LONG_BITS, num_regs,
+ "int", "spr");
}
- g_string_append(xml, "</feature>");
-
- pcc->gdb_num_sprs = num_regs;
- pcc->gdb_spr_xml = g_string_free(xml, false);
+ gdb_feature_builder_end(&builder);
}
const char *ppc_gdb_get_dynamic_xml(CPUState *cs, const char *xml_name)
@@ -362,7 +348,7 @@ const char *ppc_gdb_get_dynamic_xml(CPUState *cs, const char *xml_name)
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
if (strcmp(xml_name, "power-spr.xml") == 0) {
- return pcc->gdb_spr_xml;
+ return pcc->gdb_spr.xml;
}
return NULL;
}
@@ -599,7 +585,8 @@ void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *pcc)
32, "power-vsx.xml", 0);
}
#ifndef CONFIG_USER_ONLY
+ gdb_gen_spr_feature(cs);
gdb_register_coprocessor(cs, gdb_get_spr_reg, gdb_set_spr_reg,
- pcc->gdb_num_sprs, "power-spr.xml", 0);
+ pcc->gdb_spr.num_regs, "power-spr.xml", 0);
#endif
}
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 13/29] target/riscv: Use GDBFeature for dynamic XML
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (11 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 12/29] target/ppc: " Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-06 9:32 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 14/29] gdbstub: Use GDBFeature for gdb_register_coprocessor Alex Bennée
` (15 subsequent siblings)
28 siblings, 1 reply; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
From: Akihiko Odaki <akihiko.odaki@daynix.com>
In preparation for a change to use GDBFeature as a parameter of
gdb_register_coprocessor(), convert the internal representation of
dynamic feature from plain XML to GDBFeature.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Message-Id: <20231025093128.33116-7-akihiko.odaki@daynix.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
target/riscv/cpu.h | 5 +--
target/riscv/cpu.c | 4 +--
target/riscv/gdbstub.c | 79 +++++++++++++++++++-----------------------
3 files changed, 40 insertions(+), 48 deletions(-)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index f8ffa5ee38..73ec1d3b79 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -24,6 +24,7 @@
#include "hw/registerfields.h"
#include "hw/qdev-properties.h"
#include "exec/cpu-defs.h"
+#include "exec/gdbstub.h"
#include "qemu/cpu-float.h"
#include "qom/object.h"
#include "qemu/int128.h"
@@ -395,8 +396,8 @@ struct ArchCPU {
CPURISCVState env;
- char *dyn_csr_xml;
- char *dyn_vreg_xml;
+ GDBFeature dyn_csr_feature;
+ GDBFeature dyn_vreg_feature;
/* Configuration Settings */
RISCVCPUConfig cfg;
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index ac4a6c7eec..5200fba9b9 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1421,9 +1421,9 @@ static const char *riscv_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
RISCVCPU *cpu = RISCV_CPU(cs);
if (strcmp(xmlname, "riscv-csr.xml") == 0) {
- return cpu->dyn_csr_xml;
+ return cpu->dyn_csr_feature.xml;
} else if (strcmp(xmlname, "riscv-vector.xml") == 0) {
- return cpu->dyn_vreg_xml;
+ return cpu->dyn_vreg_feature.xml;
}
return NULL;
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
index 524bede865..a3ac0212d1 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -212,12 +212,13 @@ static int riscv_gdb_set_virtual(CPURISCVState *cs, uint8_t *mem_buf, int n)
return 0;
}
-static int riscv_gen_dynamic_csr_xml(CPUState *cs, int base_reg)
+static GDBFeature *riscv_gen_dynamic_csr_feature(CPUState *cs, int base_reg)
{
RISCVCPU *cpu = RISCV_CPU(cs);
CPURISCVState *env = &cpu->env;
- GString *s = g_string_new(NULL);
+ GDBFeatureBuilder builder;
riscv_csr_predicate_fn predicate;
+ const char *name;
int bitsize = 16 << env->misa_mxl_max;
int i;
@@ -230,9 +231,9 @@ static int riscv_gen_dynamic_csr_xml(CPUState *cs, int base_reg)
bitsize = 64;
}
- g_string_printf(s, "<?xml version=\"1.0\"?>");
- g_string_append_printf(s, "<!DOCTYPE feature SYSTEM \"gdb-target.dtd\">");
- g_string_append_printf(s, "<feature name=\"org.gnu.gdb.riscv.csr\">");
+ gdb_feature_builder_init(&builder, &cpu->dyn_csr_feature,
+ "org.gnu.gdb.riscv.csr", "riscv-csr.xml",
+ base_reg);
for (i = 0; i < CSR_TABLE_SIZE; i++) {
if (env->priv_ver < csr_ops[i].min_priv_ver) {
@@ -240,72 +241,64 @@ static int riscv_gen_dynamic_csr_xml(CPUState *cs, int base_reg)
}
predicate = csr_ops[i].predicate;
if (predicate && (predicate(env, i) == RISCV_EXCP_NONE)) {
- if (csr_ops[i].name) {
- g_string_append_printf(s, "<reg name=\"%s\"", csr_ops[i].name);
- } else {
- g_string_append_printf(s, "<reg name=\"csr%03x\"", i);
+ g_autofree char *dynamic_name = NULL;
+ name = csr_ops[i].name;
+ if (!name) {
+ dynamic_name = g_strdup_printf("csr%03x", i);
+ name = dynamic_name;
}
- g_string_append_printf(s, " bitsize=\"%d\"", bitsize);
- g_string_append_printf(s, " regnum=\"%d\"/>", base_reg + i);
+
+ gdb_feature_builder_append_reg(&builder, name, bitsize, i,
+ "int", NULL);
}
}
- g_string_append_printf(s, "</feature>");
-
- cpu->dyn_csr_xml = g_string_free(s, false);
+ gdb_feature_builder_end(&builder);
#if !defined(CONFIG_USER_ONLY)
env->debugger = false;
#endif
- return CSR_TABLE_SIZE;
+ return &cpu->dyn_csr_feature;
}
-static int ricsv_gen_dynamic_vector_xml(CPUState *cs, int base_reg)
+static GDBFeature *ricsv_gen_dynamic_vector_feature(CPUState *cs, int base_reg)
{
RISCVCPU *cpu = RISCV_CPU(cs);
- GString *s = g_string_new(NULL);
- g_autoptr(GString) ts = g_string_new("");
+ GDBFeatureBuilder builder;
int reg_width = cpu->cfg.vlen;
- int num_regs = 0;
int i;
- 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.riscv.vector\">");
+ gdb_feature_builder_init(&builder, &cpu->dyn_vreg_feature,
+ "org.gnu.gdb.riscv.vector", "riscv-vector.xml",
+ base_reg);
/* 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, "%s", vec_lanes[i].id);
- g_string_append_printf(s,
- "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>",
- ts->str, vec_lanes[i].gdb_type, count);
+ gdb_feature_builder_append_tag(
+ &builder, "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>",
+ vec_lanes[i].id, vec_lanes[i].gdb_type, count);
}
/* Define unions */
- g_string_append_printf(s, "<union id=\"riscv_vector\">");
+ gdb_feature_builder_append_tag(&builder, "<union id=\"riscv_vector\">");
for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
- g_string_append_printf(s, "<field name=\"%c\" type=\"%s\"/>",
- vec_lanes[i].suffix,
- vec_lanes[i].id);
+ gdb_feature_builder_append_tag(&builder,
+ "<field name=\"%c\" type=\"%s\"/>",
+ vec_lanes[i].suffix, vec_lanes[i].id);
}
- g_string_append(s, "</union>");
+ gdb_feature_builder_append_tag(&builder, "</union>");
/* Define vector registers */
for (i = 0; i < 32; i++) {
- g_string_append_printf(s,
- "<reg name=\"v%d\" bitsize=\"%d\""
- " regnum=\"%d\" group=\"vector\""
- " type=\"riscv_vector\"/>",
- i, reg_width, base_reg++);
- num_regs++;
+ gdb_feature_builder_append_reg(&builder, g_strdup_printf("v%d", i),
+ reg_width, i, "riscv_vector", "vector");
}
- g_string_append_printf(s, "</feature>");
+ gdb_feature_builder_end(&builder);
- cpu->dyn_vreg_xml = g_string_free(s, false);
- return num_regs;
+ return &cpu->dyn_vreg_feature;
}
void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
@@ -320,10 +313,9 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
32, "riscv-32bit-fpu.xml", 0);
}
if (env->misa_ext & RVV) {
- int base_reg = cs->gdb_num_regs;
gdb_register_coprocessor(cs, riscv_gdb_get_vector,
riscv_gdb_set_vector,
- ricsv_gen_dynamic_vector_xml(cs, base_reg),
+ ricsv_gen_dynamic_vector_feature(cs, cs->gdb_num_regs)->num_regs,
"riscv-vector.xml", 0);
}
switch (env->misa_mxl_max) {
@@ -343,9 +335,8 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
}
if (cpu->cfg.ext_icsr) {
- int base_reg = cs->gdb_num_regs;
gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
- riscv_gen_dynamic_csr_xml(cs, base_reg),
+ riscv_gen_dynamic_csr_feature(cs, cs->gdb_num_regs)->num_regs,
"riscv-csr.xml", 0);
}
}
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 14/29] gdbstub: Use GDBFeature for gdb_register_coprocessor
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (12 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 13/29] target/riscv: " Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 15/29] gdbstub: Use GDBFeature for GDBRegisterState Alex Bennée
` (14 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
From: Akihiko Odaki <akihiko.odaki@daynix.com>
This is a tree-wide change to introduce GDBFeature parameter to
gdb_register_coprocessor(). The new parameter just replaces num_regs
and xml parameters for now. GDBFeature will be utilized to simplify XML
lookup in a following change.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Acked-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20231025093128.33116-8-akihiko.odaki@daynix.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
include/exec/gdbstub.h | 2 +-
gdbstub/gdbstub.c | 13 +++++++------
target/arm/gdbstub.c | 35 +++++++++++++++++++----------------
target/hexagon/cpu.c | 3 +--
target/loongarch/gdbstub.c | 2 +-
target/m68k/helper.c | 6 +++---
target/microblaze/cpu.c | 5 +++--
target/ppc/gdbstub.c | 11 ++++++-----
target/riscv/gdbstub.c | 20 ++++++++++++--------
target/s390x/gdbstub.c | 28 +++++++---------------------
10 files changed, 60 insertions(+), 65 deletions(-)
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index d8a3c56fa2..ac6fce99a6 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -38,7 +38,7 @@ typedef int (*gdb_set_reg_cb)(CPUArchState *env, uint8_t *buf, int reg);
*/
void gdb_register_coprocessor(CPUState *cpu,
gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
- int num_regs, const char *xml, int g_pos);
+ const GDBFeature *feature, int g_pos);
/**
* gdbserver_start: start the gdb server
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index ebb912da1b..67c6fd2609 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -544,7 +544,7 @@ static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
void gdb_register_coprocessor(CPUState *cpu,
gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
- int num_regs, const char *xml, int g_pos)
+ const GDBFeature *feature, int g_pos)
{
GDBRegisterState *s;
guint i;
@@ -553,7 +553,7 @@ void gdb_register_coprocessor(CPUState *cpu,
for (i = 0; i < cpu->gdb_regs->len; i++) {
/* Check for duplicates. */
s = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
- if (strcmp(s->xml, xml) == 0) {
+ if (strcmp(s->xml, feature->xmlname) == 0) {
return;
}
}
@@ -565,17 +565,18 @@ void gdb_register_coprocessor(CPUState *cpu,
g_array_set_size(cpu->gdb_regs, i + 1);
s = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
s->base_reg = cpu->gdb_num_regs;
- s->num_regs = num_regs;
+ s->num_regs = feature->num_regs;
s->get_reg = get_reg;
s->set_reg = set_reg;
- s->xml = xml;
+ s->xml = feature->xml;
/* Add to end of list. */
- cpu->gdb_num_regs += num_regs;
+ cpu->gdb_num_regs += feature->num_regs;
if (g_pos) {
if (g_pos != s->base_reg) {
error_report("Error: Bad gdb register numbering for '%s', "
- "expected %d got %d", xml, g_pos, s->base_reg);
+ "expected %d got %d", feature->xml,
+ g_pos, s->base_reg);
} else {
cpu->gdb_num_g_regs = cpu->gdb_num_regs;
}
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index 5949adfb31..f2b201d312 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -483,14 +483,14 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
*/
#ifdef TARGET_AARCH64
if (isar_feature_aa64_sve(&cpu->isar)) {
- int nreg = arm_gen_dynamic_svereg_feature(cs, cs->gdb_num_regs)->num_regs;
+ 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, nreg,
- "sve-registers.xml", 0);
+ aarch64_gdb_set_sve_reg, feature, 0);
} else {
gdb_register_coprocessor(cs, aarch64_gdb_get_fpu_reg,
aarch64_gdb_set_fpu_reg,
- 34, "aarch64-fpu.xml", 0);
+ gdb_find_static_feature("aarch64-fpu.xml"),
+ 0);
}
/*
* Note that we report pauth information via the feature name
@@ -501,19 +501,22 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
if (isar_feature_aa64_pauth(&cpu->isar)) {
gdb_register_coprocessor(cs, aarch64_gdb_get_pauth_reg,
aarch64_gdb_set_pauth_reg,
- 4, "aarch64-pauth.xml", 0);
+ 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,
- 49, "arm-neon.xml", 0);
+ 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,
- 33, "arm-vfp3.xml", 0);
+ 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,
- 17, "arm-vfp.xml", 0);
+ gdb_find_static_feature("arm-vfp.xml"), 0);
}
if (!arm_feature(env, ARM_FEATURE_M)) {
/*
@@ -521,29 +524,29 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
* expose to gdb.
*/
gdb_register_coprocessor(cs, vfp_gdb_get_sysreg, vfp_gdb_set_sysreg,
- 2, "arm-vfp-sysregs.xml", 0);
+ 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,
- 1, "arm-m-profile-mve.xml", 0);
+ 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)->num_regs,
- "system-registers.xml", 0);
+ arm_gen_dynamic_sysreg_feature(cs, cs->gdb_num_regs),
+ 0);
#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)->num_regs,
- "arm-m-system.xml", 0);
+ 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)->num_regs,
- "arm-m-secext.xml", 0);
+ arm_gen_dynamic_m_secextreg_feature(cs, cs->gdb_num_regs), 0);
}
#endif
}
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 1adc11b713..60d52e1e9d 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -342,8 +342,7 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp)
gdb_register_coprocessor(cs, hexagon_hvx_gdb_read_register,
hexagon_hvx_gdb_write_register,
- NUM_VREGS + NUM_QREGS,
- "hexagon-hvx.xml", 0);
+ gdb_find_static_feature("hexagon-hvx.xml"), 0);
qemu_init_vcpu(cs);
cpu_reset(cs);
diff --git a/target/loongarch/gdbstub.c b/target/loongarch/gdbstub.c
index 5fc2f19e96..843a869450 100644
--- a/target/loongarch/gdbstub.c
+++ b/target/loongarch/gdbstub.c
@@ -118,5 +118,5 @@ static int loongarch_gdb_set_fpu(CPULoongArchState *env,
void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs)
{
gdb_register_coprocessor(cs, loongarch_gdb_get_fpu, loongarch_gdb_set_fpu,
- 41, "loongarch-fpu.xml", 0);
+ gdb_find_static_feature("loongarch-fpu.xml"), 0);
}
diff --git a/target/m68k/helper.c b/target/m68k/helper.c
index 0a1544cd68..675f2dcd5a 100644
--- a/target/m68k/helper.c
+++ b/target/m68k/helper.c
@@ -152,10 +152,10 @@ void m68k_cpu_init_gdb(M68kCPU *cpu)
if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
gdb_register_coprocessor(cs, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg,
- 11, "cf-fp.xml", 18);
+ gdb_find_static_feature("cf-fp.xml"), 18);
} else if (m68k_feature(env, M68K_FEATURE_FPU)) {
- gdb_register_coprocessor(cs, m68k_fpu_gdb_get_reg,
- m68k_fpu_gdb_set_reg, 11, "m68k-fp.xml", 18);
+ gdb_register_coprocessor(cs, m68k_fpu_gdb_get_reg, m68k_fpu_gdb_set_reg,
+ gdb_find_static_feature("m68k-fp.xml"), 18);
}
/* TODO: Add [E]MAC registers. */
}
diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c
index bbb3335cad..1998f69828 100644
--- a/target/microblaze/cpu.c
+++ b/target/microblaze/cpu.c
@@ -297,8 +297,9 @@ static void mb_cpu_initfn(Object *obj)
CPUMBState *env = &cpu->env;
gdb_register_coprocessor(CPU(cpu), mb_cpu_gdb_read_stack_protect,
- mb_cpu_gdb_write_stack_protect, 2,
- "microblaze-stack-protect.xml", 0);
+ mb_cpu_gdb_write_stack_protect,
+ gdb_find_static_feature("microblaze-stack-protect.xml"),
+ 0);
set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c
index e3be3dbd10..09b852464f 100644
--- a/target/ppc/gdbstub.c
+++ b/target/ppc/gdbstub.c
@@ -570,23 +570,24 @@ void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *pcc)
{
if (pcc->insns_flags & PPC_FLOAT) {
gdb_register_coprocessor(cs, gdb_get_float_reg, gdb_set_float_reg,
- 33, "power-fpu.xml", 0);
+ gdb_find_static_feature("power-fpu.xml"), 0);
}
if (pcc->insns_flags & PPC_ALTIVEC) {
gdb_register_coprocessor(cs, gdb_get_avr_reg, gdb_set_avr_reg,
- 34, "power-altivec.xml", 0);
+ gdb_find_static_feature("power-altivec.xml"),
+ 0);
}
if (pcc->insns_flags & PPC_SPE) {
gdb_register_coprocessor(cs, gdb_get_spe_reg, gdb_set_spe_reg,
- 34, "power-spe.xml", 0);
+ gdb_find_static_feature("power-spe.xml"), 0);
}
if (pcc->insns_flags2 & PPC2_VSX) {
gdb_register_coprocessor(cs, gdb_get_vsx_reg, gdb_set_vsx_reg,
- 32, "power-vsx.xml", 0);
+ gdb_find_static_feature("power-vsx.xml"), 0);
}
#ifndef CONFIG_USER_ONLY
gdb_gen_spr_feature(cs);
gdb_register_coprocessor(cs, gdb_get_spr_reg, gdb_set_spr_reg,
- pcc->gdb_spr.num_regs, "power-spr.xml", 0);
+ &pcc->gdb_spr, 0);
#endif
}
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
index a3ac0212d1..df2e6335b5 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -307,28 +307,32 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
CPURISCVState *env = &cpu->env;
if (env->misa_ext & RVD) {
gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
- 32, "riscv-64bit-fpu.xml", 0);
+ gdb_find_static_feature("riscv-64bit-fpu.xml"),
+ 0);
} else if (env->misa_ext & RVF) {
gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
- 32, "riscv-32bit-fpu.xml", 0);
+ gdb_find_static_feature("riscv-32bit-fpu.xml"),
+ 0);
}
if (env->misa_ext & RVV) {
gdb_register_coprocessor(cs, riscv_gdb_get_vector,
riscv_gdb_set_vector,
- ricsv_gen_dynamic_vector_feature(cs, cs->gdb_num_regs)->num_regs,
- "riscv-vector.xml", 0);
+ ricsv_gen_dynamic_vector_feature(cs, cs->gdb_num_regs),
+ 0);
}
switch (env->misa_mxl_max) {
case MXL_RV32:
gdb_register_coprocessor(cs, riscv_gdb_get_virtual,
riscv_gdb_set_virtual,
- 1, "riscv-32bit-virtual.xml", 0);
+ gdb_find_static_feature("riscv-32bit-virtual.xml"),
+ 0);
break;
case MXL_RV64:
case MXL_RV128:
gdb_register_coprocessor(cs, riscv_gdb_get_virtual,
riscv_gdb_set_virtual,
- 1, "riscv-64bit-virtual.xml", 0);
+ gdb_find_static_feature("riscv-64bit-virtual.xml"),
+ 0);
break;
default:
g_assert_not_reached();
@@ -336,7 +340,7 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
if (cpu->cfg.ext_icsr) {
gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
- riscv_gen_dynamic_csr_feature(cs, cs->gdb_num_regs)->num_regs,
- "riscv-csr.xml", 0);
+ riscv_gen_dynamic_csr_feature(cs, cs->gdb_num_regs),
+ 0);
}
}
diff --git a/target/s390x/gdbstub.c b/target/s390x/gdbstub.c
index 6fbfd41bc8..02c388dc32 100644
--- a/target/s390x/gdbstub.c
+++ b/target/s390x/gdbstub.c
@@ -69,8 +69,6 @@ int s390_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
/* the values represent the positions in s390-acr.xml */
#define S390_A0_REGNUM 0
#define S390_A15_REGNUM 15
-/* total number of registers in s390-acr.xml */
-#define S390_NUM_AC_REGS 16
static int cpu_read_ac_reg(CPUS390XState *env, GByteArray *buf, int n)
{
@@ -98,8 +96,6 @@ static int cpu_write_ac_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
#define S390_FPC_REGNUM 0
#define S390_F0_REGNUM 1
#define S390_F15_REGNUM 16
-/* total number of registers in s390-fpr.xml */
-#define S390_NUM_FP_REGS 17
static int cpu_read_fp_reg(CPUS390XState *env, GByteArray *buf, int n)
{
@@ -132,8 +128,6 @@ static int cpu_write_fp_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
#define S390_V15L_REGNUM 15
#define S390_V16_REGNUM 16
#define S390_V31_REGNUM 31
-/* total number of registers in s390-vx.xml */
-#define S390_NUM_VREGS 32
static int cpu_read_vreg(CPUS390XState *env, GByteArray *buf, int n)
{
@@ -172,8 +166,6 @@ static int cpu_write_vreg(CPUS390XState *env, uint8_t *mem_buf, int n)
/* the values represent the positions in s390-cr.xml */
#define S390_C0_REGNUM 0
#define S390_C15_REGNUM 15
-/* total number of registers in s390-cr.xml */
-#define S390_NUM_C_REGS 16
#ifndef CONFIG_USER_ONLY
static int cpu_read_c_reg(CPUS390XState *env, GByteArray *buf, int n)
@@ -206,8 +198,6 @@ static int cpu_write_c_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
#define S390_VIRT_CPUTM_REGNUM 1
#define S390_VIRT_BEA_REGNUM 2
#define S390_VIRT_PREFIX_REGNUM 3
-/* total number of registers in s390-virt.xml */
-#define S390_NUM_VIRT_REGS 4
static int cpu_read_virt_reg(CPUS390XState *env, GByteArray *mem_buf, int n)
{
@@ -254,8 +244,6 @@ static int cpu_write_virt_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
#define S390_VIRT_KVM_PFT_REGNUM 1
#define S390_VIRT_KVM_PFS_REGNUM 2
#define S390_VIRT_KVM_PFC_REGNUM 3
-/* total number of registers in s390-virt-kvm.xml */
-#define S390_NUM_VIRT_KVM_REGS 4
static int cpu_read_virt_kvm_reg(CPUS390XState *env, GByteArray *mem_buf, int n)
{
@@ -303,8 +291,6 @@ static int cpu_write_virt_kvm_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
#define S390_GS_GSD_REGNUM 1
#define S390_GS_GSSM_REGNUM 2
#define S390_GS_GSEPLA_REGNUM 3
-/* total number of registers in s390-gs.xml */
-#define S390_NUM_GS_REGS 4
static int cpu_read_gs_reg(CPUS390XState *env, GByteArray *buf, int n)
{
@@ -322,33 +308,33 @@ void s390_cpu_gdb_init(CPUState *cs)
{
gdb_register_coprocessor(cs, cpu_read_ac_reg,
cpu_write_ac_reg,
- S390_NUM_AC_REGS, "s390-acr.xml", 0);
+ gdb_find_static_feature("s390-acr.xml"), 0);
gdb_register_coprocessor(cs, cpu_read_fp_reg,
cpu_write_fp_reg,
- S390_NUM_FP_REGS, "s390-fpr.xml", 0);
+ gdb_find_static_feature("s390-fpr.xml"), 0);
gdb_register_coprocessor(cs, cpu_read_vreg,
cpu_write_vreg,
- S390_NUM_VREGS, "s390-vx.xml", 0);
+ gdb_find_static_feature("s390-vx.xml"), 0);
gdb_register_coprocessor(cs, cpu_read_gs_reg,
cpu_write_gs_reg,
- S390_NUM_GS_REGS, "s390-gs.xml", 0);
+ gdb_find_static_feature("s390-gs.xml"), 0);
#ifndef CONFIG_USER_ONLY
gdb_register_coprocessor(cs, cpu_read_c_reg,
cpu_write_c_reg,
- S390_NUM_C_REGS, "s390-cr.xml", 0);
+ gdb_find_static_feature("s390-cr.xml"), 0);
gdb_register_coprocessor(cs, cpu_read_virt_reg,
cpu_write_virt_reg,
- S390_NUM_VIRT_REGS, "s390-virt.xml", 0);
+ gdb_find_static_feature("s390-virt.xml"), 0);
if (kvm_enabled()) {
gdb_register_coprocessor(cs, cpu_read_virt_kvm_reg,
cpu_write_virt_kvm_reg,
- S390_NUM_VIRT_KVM_REGS, "s390-virt-kvm.xml",
+ gdb_find_static_feature("s390-virt-kvm.xml"),
0);
}
#endif
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 15/29] gdbstub: Use GDBFeature for GDBRegisterState
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (13 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 14/29] gdbstub: Use GDBFeature for gdb_register_coprocessor Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 16/29] gdbstub: Change gdb_get_reg_cb and gdb_set_reg_cb Alex Bennée
` (13 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
From: Akihiko Odaki <akihiko.odaki@daynix.com>
Simplify GDBRegisterState by replacing num_regs and xml members with
one member that points to GDBFeature.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20231025093128.33116-9-akihiko.odaki@daynix.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
gdbstub/gdbstub.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index 67c6fd2609..ebabbc00f6 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -47,10 +47,9 @@
typedef struct GDBRegisterState {
int base_reg;
- int num_regs;
gdb_get_reg_cb get_reg;
gdb_set_reg_cb set_reg;
- const char *xml;
+ const GDBFeature *feature;
} GDBRegisterState;
GDBState gdbserver_state;
@@ -391,7 +390,7 @@ static const char *get_feature_xml(const char *p, const char **newp,
g_ptr_array_add(
xml,
g_markup_printf_escaped("<xi:include href=\"%s\"/>",
- r->xml));
+ r->feature->xmlname));
}
}
g_ptr_array_add(xml, g_strdup("</target>"));
@@ -513,7 +512,7 @@ static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
if (cpu->gdb_regs) {
for (guint i = 0; i < cpu->gdb_regs->len; i++) {
r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
- if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
+ if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
return r->get_reg(env, buf, reg - r->base_reg);
}
}
@@ -534,7 +533,7 @@ static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
if (cpu->gdb_regs) {
for (guint i = 0; i < cpu->gdb_regs->len; i++) {
r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
- if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
+ if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
return r->set_reg(env, mem_buf, reg - r->base_reg);
}
}
@@ -553,7 +552,7 @@ void gdb_register_coprocessor(CPUState *cpu,
for (i = 0; i < cpu->gdb_regs->len; i++) {
/* Check for duplicates. */
s = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
- if (strcmp(s->xml, feature->xmlname) == 0) {
+ if (s->feature == feature) {
return;
}
}
@@ -565,10 +564,9 @@ void gdb_register_coprocessor(CPUState *cpu,
g_array_set_size(cpu->gdb_regs, i + 1);
s = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
s->base_reg = cpu->gdb_num_regs;
- s->num_regs = feature->num_regs;
s->get_reg = get_reg;
s->set_reg = set_reg;
- s->xml = feature->xml;
+ s->feature = feature;
/* Add to end of list. */
cpu->gdb_num_regs += feature->num_regs;
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 16/29] gdbstub: Change gdb_get_reg_cb and gdb_set_reg_cb
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (14 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 15/29] gdbstub: Use GDBFeature for GDBRegisterState Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 17/29] gdbstub: Simplify XML lookup Alex Bennée
` (12 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
From: Akihiko Odaki <akihiko.odaki@daynix.com>
Align the parameters of gdb_get_reg_cb and gdb_set_reg_cb with the
gdb_read_register and gdb_write_register members of CPUClass to allow
to unify the logic to access registers of the core and coprocessors
in the future.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20231025093128.33116-10-akihiko.odaki@daynix.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
include/exec/gdbstub.h | 4 +-
target/arm/internals.h | 12 +++---
target/hexagon/internal.h | 4 +-
target/microblaze/cpu.h | 4 +-
gdbstub/gdbstub.c | 6 +--
target/arm/gdbstub.c | 51 ++++++++++++++++--------
target/arm/gdbstub64.c | 27 +++++++++----
target/hexagon/gdbstub.c | 10 ++++-
target/loongarch/gdbstub.c | 11 ++++--
target/m68k/helper.c | 20 ++++++++--
target/microblaze/gdbstub.c | 9 ++++-
target/ppc/gdbstub.c | 46 +++++++++++++++++-----
target/riscv/gdbstub.c | 46 ++++++++++++++++------
target/s390x/gdbstub.c | 77 ++++++++++++++++++++++++++++---------
14 files changed, 236 insertions(+), 91 deletions(-)
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index ac6fce99a6..bcaab1bc75 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -24,8 +24,8 @@ typedef struct GDBFeatureBuilder {
/* Get or set a register. Returns the size of the register. */
-typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg);
-typedef int (*gdb_set_reg_cb)(CPUArchState *env, uint8_t *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);
/**
* gdb_register_coprocessor() - register a supplemental set of registers
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 989416e613..4ef5137967 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1441,12 +1441,12 @@ static inline uint64_t pmu_counter_mask(CPUARMState *env)
#ifdef TARGET_AARCH64
GDBFeature *arm_gen_dynamic_svereg_feature(CPUState *cpu, int base_reg);
-int aarch64_gdb_get_sve_reg(CPUARMState *env, GByteArray *buf, int reg);
-int aarch64_gdb_set_sve_reg(CPUARMState *env, uint8_t *buf, int reg);
-int aarch64_gdb_get_fpu_reg(CPUARMState *env, GByteArray *buf, int reg);
-int aarch64_gdb_set_fpu_reg(CPUARMState *env, uint8_t *buf, int reg);
-int aarch64_gdb_get_pauth_reg(CPUARMState *env, GByteArray *buf, int reg);
-int aarch64_gdb_set_pauth_reg(CPUARMState *env, uint8_t *buf, int reg);
+int aarch64_gdb_get_sve_reg(CPUState *cs, GByteArray *buf, int reg);
+int aarch64_gdb_set_sve_reg(CPUState *cs, uint8_t *buf, int reg);
+int aarch64_gdb_get_fpu_reg(CPUState *cs, GByteArray *buf, int reg);
+int aarch64_gdb_set_fpu_reg(CPUState *cs, uint8_t *buf, int reg);
+int aarch64_gdb_get_pauth_reg(CPUState *cs, GByteArray *buf, int reg);
+int aarch64_gdb_set_pauth_reg(CPUState *cs, uint8_t *buf, int reg);
void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp);
void arm_cpu_sme_finalize(ARMCPU *cpu, Error **errp);
void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp);
diff --git a/target/hexagon/internal.h b/target/hexagon/internal.h
index d732b6bb3c..beb08cb7e3 100644
--- a/target/hexagon/internal.h
+++ b/target/hexagon/internal.h
@@ -33,8 +33,8 @@
int hexagon_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int hexagon_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
-int hexagon_hvx_gdb_read_register(CPUHexagonState *env, GByteArray *mem_buf, int n);
-int hexagon_hvx_gdb_write_register(CPUHexagonState *env, uint8_t *mem_buf, int n);
+int hexagon_hvx_gdb_read_register(CPUState *env, GByteArray *mem_buf, int n);
+int hexagon_hvx_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n);
void hexagon_debug_vreg(CPUHexagonState *env, int regnum);
void hexagon_debug_qreg(CPUHexagonState *env, int regnum);
diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h
index e43c49d4af..c14b3357b7 100644
--- a/target/microblaze/cpu.h
+++ b/target/microblaze/cpu.h
@@ -370,8 +370,8 @@ G_NORETURN void mb_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
void mb_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
int mb_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int mb_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
-int mb_cpu_gdb_read_stack_protect(CPUArchState *cpu, GByteArray *buf, int reg);
-int mb_cpu_gdb_write_stack_protect(CPUArchState *cpu, uint8_t *buf, int reg);
+int mb_cpu_gdb_read_stack_protect(CPUState *cs, GByteArray *buf, int reg);
+int mb_cpu_gdb_write_stack_protect(CPUState *cs, uint8_t *buf, int reg);
static inline uint32_t mb_cpu_read_msr(const CPUMBState *env)
{
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index ebabbc00f6..4809c90c4a 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -502,7 +502,6 @@ const GDBFeature *gdb_find_static_feature(const char *xmlname)
static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
- CPUArchState *env = cpu_env(cpu);
GDBRegisterState *r;
if (reg < cc->gdb_num_core_regs) {
@@ -513,7 +512,7 @@ static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
for (guint i = 0; i < cpu->gdb_regs->len; i++) {
r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
- return r->get_reg(env, buf, reg - r->base_reg);
+ return r->get_reg(cpu, buf, reg - r->base_reg);
}
}
}
@@ -523,7 +522,6 @@ static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
- CPUArchState *env = cpu_env(cpu);
GDBRegisterState *r;
if (reg < cc->gdb_num_core_regs) {
@@ -534,7 +532,7 @@ static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
for (guint i = 0; i < cpu->gdb_regs->len; i++) {
r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
- return r->set_reg(env, mem_buf, reg - r->base_reg);
+ return r->set_reg(cpu, mem_buf, reg - r->base_reg);
}
}
}
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index f2b201d312..059d84f98e 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -106,9 +106,10 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
return 0;
}
-static int vfp_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg)
+static int vfp_gdb_get_reg(CPUState *cs, GByteArray *buf, int reg)
{
- ARMCPU *cpu = env_archcpu(env);
+ 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. */
@@ -130,9 +131,10 @@ static int vfp_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg)
return 0;
}
-static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
+static int vfp_gdb_set_reg(CPUState *cs, uint8_t *buf, int reg)
{
- ARMCPU *cpu = env_archcpu(env);
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16;
if (reg < nregs) {
@@ -156,8 +158,11 @@ static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
return 0;
}
-static int vfp_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg)
+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]);
@@ -167,8 +172,11 @@ static int vfp_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg)
return 0;
}
-static int vfp_gdb_set_sysreg(CPUARMState *env, uint8_t *buf, int reg)
+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);
@@ -180,8 +188,11 @@ static int vfp_gdb_set_sysreg(CPUARMState *env, uint8_t *buf, int reg)
return 0;
}
-static int mve_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg)
+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);
@@ -190,8 +201,11 @@ static int mve_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg)
}
}
-static int mve_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
+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);
@@ -210,9 +224,10 @@ static int mve_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
* We return the number of bytes copied
*/
-static int arm_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg)
+static int arm_gdb_get_sysreg(CPUState *cs, GByteArray *buf, int reg)
{
- ARMCPU *cpu = env_archcpu(env);
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
const ARMCPRegInfo *ri;
uint32_t key;
@@ -228,7 +243,7 @@ static int arm_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg)
return 0;
}
-static int arm_gdb_set_sysreg(CPUARMState *env, uint8_t *buf, int reg)
+static int arm_gdb_set_sysreg(CPUState *cs, uint8_t *buf, int reg)
{
return 0;
}
@@ -367,8 +382,11 @@ static int m_sysreg_get(CPUARMState *env, GByteArray *buf,
return gdb_get_reg32(buf, *ptr);
}
-static int arm_gdb_get_m_systemreg(CPUARMState *env, GByteArray *buf, int reg)
+static int arm_gdb_get_m_systemreg(CPUState *cs, GByteArray *buf, int reg)
{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
/*
* Here, we emulate MRS instruction, where CONTROL has a mix of
* banked and non-banked bits.
@@ -379,7 +397,7 @@ static int arm_gdb_get_m_systemreg(CPUARMState *env, GByteArray *buf, int reg)
return m_sysreg_get(env, buf, reg, env->v7m.secure);
}
-static int arm_gdb_set_m_systemreg(CPUARMState *env, uint8_t *buf, int reg)
+static int arm_gdb_set_m_systemreg(CPUState *cs, uint8_t *buf, int reg)
{
return 0; /* TODO */
}
@@ -414,12 +432,15 @@ static GDBFeature *arm_gen_dynamic_m_systemreg_feature(CPUState *cs,
* 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(CPUARMState *env, GByteArray *buf, int reg)
+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(CPUARMState *env, uint8_t *buf, int reg)
+static int arm_gdb_set_m_secextreg(CPUState *cs, uint8_t *buf, int reg)
{
return 0; /* TODO */
}
diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c
index 5286d5c604..caa31ff3fa 100644
--- a/target/arm/gdbstub64.c
+++ b/target/arm/gdbstub64.c
@@ -72,8 +72,11 @@ int aarch64_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
return 0;
}
-int aarch64_gdb_get_fpu_reg(CPUARMState *env, GByteArray *buf, int reg)
+int aarch64_gdb_get_fpu_reg(CPUState *cs, GByteArray *buf, int reg)
{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
switch (reg) {
case 0 ... 31:
{
@@ -92,8 +95,11 @@ int aarch64_gdb_get_fpu_reg(CPUARMState *env, GByteArray *buf, int reg)
}
}
-int aarch64_gdb_set_fpu_reg(CPUARMState *env, uint8_t *buf, int reg)
+int aarch64_gdb_set_fpu_reg(CPUState *cs, uint8_t *buf, int reg)
{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
switch (reg) {
case 0 ... 31:
/* 128 bit FP register */
@@ -116,9 +122,10 @@ int aarch64_gdb_set_fpu_reg(CPUARMState *env, uint8_t *buf, int reg)
}
}
-int aarch64_gdb_get_sve_reg(CPUARMState *env, GByteArray *buf, int reg)
+int aarch64_gdb_get_sve_reg(CPUState *cs, GByteArray *buf, int reg)
{
- ARMCPU *cpu = env_archcpu(env);
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
switch (reg) {
/* The first 32 registers are the zregs */
@@ -164,9 +171,10 @@ int aarch64_gdb_get_sve_reg(CPUARMState *env, GByteArray *buf, int reg)
return 0;
}
-int aarch64_gdb_set_sve_reg(CPUARMState *env, uint8_t *buf, int reg)
+int aarch64_gdb_set_sve_reg(CPUState *cs, uint8_t *buf, int reg)
{
- ARMCPU *cpu = env_archcpu(env);
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
/* The first 32 registers are the zregs */
switch (reg) {
@@ -210,8 +218,11 @@ int aarch64_gdb_set_sve_reg(CPUARMState *env, uint8_t *buf, int reg)
return 0;
}
-int aarch64_gdb_get_pauth_reg(CPUARMState *env, GByteArray *buf, int reg)
+int aarch64_gdb_get_pauth_reg(CPUState *cs, GByteArray *buf, int reg)
{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
switch (reg) {
case 0: /* pauth_dmask */
case 1: /* pauth_cmask */
@@ -241,7 +252,7 @@ int aarch64_gdb_get_pauth_reg(CPUARMState *env, GByteArray *buf, int reg)
}
}
-int aarch64_gdb_set_pauth_reg(CPUARMState *env, uint8_t *buf, int reg)
+int aarch64_gdb_set_pauth_reg(CPUState *cs, uint8_t *buf, int reg)
{
/* All pseudo registers are read-only. */
return 0;
diff --git a/target/hexagon/gdbstub.c b/target/hexagon/gdbstub.c
index 54d37e006e..6007e6462b 100644
--- a/target/hexagon/gdbstub.c
+++ b/target/hexagon/gdbstub.c
@@ -81,8 +81,11 @@ static int gdb_get_qreg(CPUHexagonState *env, GByteArray *mem_buf, int n)
return total;
}
-int hexagon_hvx_gdb_read_register(CPUHexagonState *env, GByteArray *mem_buf, int n)
+int hexagon_hvx_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
+ HexagonCPU *cpu = HEXAGON_CPU(cs);
+ CPUHexagonState *env = &cpu->env;
+
if (n < NUM_VREGS) {
return gdb_get_vreg(env, mem_buf, n);
}
@@ -115,8 +118,11 @@ static int gdb_put_qreg(CPUHexagonState *env, uint8_t *mem_buf, int n)
return MAX_VEC_SIZE_BYTES / 8;
}
-int hexagon_hvx_gdb_write_register(CPUHexagonState *env, uint8_t *mem_buf, int n)
+int hexagon_hvx_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
+ HexagonCPU *cpu = HEXAGON_CPU(cs);
+ CPUHexagonState *env = &cpu->env;
+
if (n < NUM_VREGS) {
return gdb_put_vreg(env, mem_buf, n);
}
diff --git a/target/loongarch/gdbstub.c b/target/loongarch/gdbstub.c
index 843a869450..22c6889011 100644
--- a/target/loongarch/gdbstub.c
+++ b/target/loongarch/gdbstub.c
@@ -84,9 +84,11 @@ int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
return length;
}
-static int loongarch_gdb_get_fpu(CPULoongArchState *env,
- GByteArray *mem_buf, int n)
+static int loongarch_gdb_get_fpu(CPUState *cs, GByteArray *mem_buf, int n)
{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+
if (0 <= n && n < 32) {
return gdb_get_reg64(mem_buf, env->fpr[n].vreg.D(0));
} else if (32 <= n && n < 40) {
@@ -97,9 +99,10 @@ static int loongarch_gdb_get_fpu(CPULoongArchState *env,
return 0;
}
-static int loongarch_gdb_set_fpu(CPULoongArchState *env,
- uint8_t *mem_buf, int n)
+static int loongarch_gdb_set_fpu(CPUState *cs, uint8_t *mem_buf, int n)
{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
int length = 0;
if (0 <= n && n < 32) {
diff --git a/target/m68k/helper.c b/target/m68k/helper.c
index 675f2dcd5a..a5ee4d87e3 100644
--- a/target/m68k/helper.c
+++ b/target/m68k/helper.c
@@ -69,8 +69,11 @@ void m68k_cpu_list(void)
g_slist_free(list);
}
-static int cf_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n)
+static int cf_fpu_gdb_get_reg(CPUState *cs, GByteArray *mem_buf, int n)
{
+ M68kCPU *cpu = M68K_CPU(cs);
+ CPUM68KState *env = &cpu->env;
+
if (n < 8) {
float_status s;
return gdb_get_reg64(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
@@ -86,8 +89,11 @@ static int cf_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n)
return 0;
}
-static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
+static int cf_fpu_gdb_set_reg(CPUState *cs, uint8_t *mem_buf, int n)
{
+ M68kCPU *cpu = M68K_CPU(cs);
+ CPUM68KState *env = &cpu->env;
+
if (n < 8) {
float_status s;
env->fregs[n].d = float64_to_floatx80(ldq_p(mem_buf), &s);
@@ -106,8 +112,11 @@ static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
return 0;
}
-static int m68k_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n)
+static int m68k_fpu_gdb_get_reg(CPUState *cs, GByteArray *mem_buf, int n)
{
+ M68kCPU *cpu = M68K_CPU(cs);
+ CPUM68KState *env = &cpu->env;
+
if (n < 8) {
int len = gdb_get_reg16(mem_buf, env->fregs[n].l.upper);
len += gdb_get_reg16(mem_buf, 0);
@@ -125,8 +134,11 @@ static int m68k_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n)
return 0;
}
-static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
+static int m68k_fpu_gdb_set_reg(CPUState *cs, uint8_t *mem_buf, int n)
{
+ M68kCPU *cpu = M68K_CPU(cs);
+ CPUM68KState *env = &cpu->env;
+
if (n < 8) {
env->fregs[n].l.upper = lduw_be_p(mem_buf);
env->fregs[n].l.lower = ldq_be_p(mem_buf + 4);
diff --git a/target/microblaze/gdbstub.c b/target/microblaze/gdbstub.c
index 29ac6e9c0f..6ffc5ad075 100644
--- a/target/microblaze/gdbstub.c
+++ b/target/microblaze/gdbstub.c
@@ -94,8 +94,10 @@ int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
return gdb_get_reg32(mem_buf, val);
}
-int mb_cpu_gdb_read_stack_protect(CPUMBState *env, GByteArray *mem_buf, int n)
+int mb_cpu_gdb_read_stack_protect(CPUState *cs, GByteArray *mem_buf, int n)
{
+ MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
+ CPUMBState *env = &cpu->env;
uint32_t val;
switch (n) {
@@ -153,8 +155,11 @@ int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
return 4;
}
-int mb_cpu_gdb_write_stack_protect(CPUMBState *env, uint8_t *mem_buf, int n)
+int mb_cpu_gdb_write_stack_protect(CPUState *cs, uint8_t *mem_buf, int n)
{
+ MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
+ CPUMBState *env = &cpu->env;
+
switch (n) {
case GDB_SP_SHL:
env->slr = ldl_p(mem_buf);
diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c
index 09b852464f..8ca37b6bf9 100644
--- a/target/ppc/gdbstub.c
+++ b/target/ppc/gdbstub.c
@@ -369,8 +369,10 @@ static int gdb_find_spr_idx(CPUPPCState *env, int n)
return -1;
}
-static int gdb_get_spr_reg(CPUPPCState *env, GByteArray *buf, int n)
+static int gdb_get_spr_reg(CPUState *cs, GByteArray *buf, int n)
{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
int reg;
int len;
@@ -385,8 +387,10 @@ static int gdb_get_spr_reg(CPUPPCState *env, GByteArray *buf, int n)
return len;
}
-static int gdb_set_spr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_set_spr_reg(CPUState *cs, uint8_t *mem_buf, int n)
{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
int reg;
int len;
@@ -403,8 +407,10 @@ static int gdb_set_spr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
}
#endif
-static int gdb_get_float_reg(CPUPPCState *env, GByteArray *buf, int n)
+static int gdb_get_float_reg(CPUState *cs, GByteArray *buf, int n)
{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
uint8_t *mem_buf;
if (n < 32) {
gdb_get_reg64(buf, *cpu_fpr_ptr(env, n));
@@ -421,8 +427,11 @@ static int gdb_get_float_reg(CPUPPCState *env, GByteArray *buf, int n)
return 0;
}
-static int gdb_set_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_set_float_reg(CPUState *cs, uint8_t *mem_buf, int n)
{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+
if (n < 32) {
ppc_maybe_bswap_register(env, mem_buf, 8);
*cpu_fpr_ptr(env, n) = ldq_p(mem_buf);
@@ -436,8 +445,10 @@ static int gdb_set_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
return 0;
}
-static int gdb_get_avr_reg(CPUPPCState *env, GByteArray *buf, int n)
+static int gdb_get_avr_reg(CPUState *cs, GByteArray *buf, int n)
{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
uint8_t *mem_buf;
if (n < 32) {
@@ -462,8 +473,11 @@ static int gdb_get_avr_reg(CPUPPCState *env, GByteArray *buf, int n)
return 0;
}
-static int gdb_set_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_set_avr_reg(CPUState *cs, uint8_t *mem_buf, int n)
{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+
if (n < 32) {
ppc_avr_t *avr = cpu_avr_ptr(env, n);
ppc_maybe_bswap_register(env, mem_buf, 16);
@@ -484,8 +498,11 @@ static int gdb_set_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
return 0;
}
-static int gdb_get_spe_reg(CPUPPCState *env, GByteArray *buf, int n)
+static int gdb_get_spe_reg(CPUState *cs, GByteArray *buf, int n)
{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+
if (n < 32) {
#if defined(TARGET_PPC64)
gdb_get_reg32(buf, env->gpr[n] >> 32);
@@ -508,8 +525,11 @@ static int gdb_get_spe_reg(CPUPPCState *env, GByteArray *buf, int n)
return 0;
}
-static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_set_spe_reg(CPUState *cs, uint8_t *mem_buf, int n)
{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+
if (n < 32) {
#if defined(TARGET_PPC64)
target_ulong lo = (uint32_t)env->gpr[n];
@@ -537,8 +557,11 @@ static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
return 0;
}
-static int gdb_get_vsx_reg(CPUPPCState *env, GByteArray *buf, int n)
+static int gdb_get_vsx_reg(CPUState *cs, GByteArray *buf, int n)
{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+
if (n < 32) {
gdb_get_reg64(buf, *cpu_vsrl_ptr(env, n));
ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 8), 8);
@@ -547,8 +570,11 @@ static int gdb_get_vsx_reg(CPUPPCState *env, GByteArray *buf, int n)
return 0;
}
-static int gdb_set_vsx_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_set_vsx_reg(CPUState *cs, uint8_t *mem_buf, int n)
{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+
if (n < 32) {
ppc_maybe_bswap_register(env, mem_buf, 8);
*cpu_vsrl_ptr(env, n) = ldq_p(mem_buf);
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
index df2e6335b5..9553ad62a3 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -106,8 +106,11 @@ int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
return length;
}
-static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n)
+static int riscv_gdb_get_fpu(CPUState *cs, GByteArray *buf, int n)
{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+
if (n < 32) {
if (env->misa_ext & RVD) {
return gdb_get_reg64(buf, env->fpr[n]);
@@ -119,8 +122,11 @@ static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n)
return 0;
}
-static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
+static int riscv_gdb_set_fpu(CPUState *cs, uint8_t *mem_buf, int n)
{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+
if (n < 32) {
env->fpr[n] = ldq_p(mem_buf); /* always 64-bit */
return sizeof(uint64_t);
@@ -128,8 +134,10 @@ static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
return 0;
}
-static int riscv_gdb_get_vector(CPURISCVState *env, GByteArray *buf, int n)
+static int riscv_gdb_get_vector(CPUState *cs, GByteArray *buf, int n)
{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
uint16_t vlenb = riscv_cpu_cfg(env)->vlen >> 3;
if (n < 32) {
int i;
@@ -144,8 +152,10 @@ static int riscv_gdb_get_vector(CPURISCVState *env, GByteArray *buf, int n)
return 0;
}
-static int riscv_gdb_set_vector(CPURISCVState *env, uint8_t *mem_buf, int n)
+static int riscv_gdb_set_vector(CPUState *cs, uint8_t *mem_buf, int n)
{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
uint16_t vlenb = riscv_cpu_cfg(env)->vlen >> 3;
if (n < 32) {
int i;
@@ -158,8 +168,11 @@ static int riscv_gdb_set_vector(CPURISCVState *env, uint8_t *mem_buf, int n)
return 0;
}
-static int riscv_gdb_get_csr(CPURISCVState *env, GByteArray *buf, int n)
+static int riscv_gdb_get_csr(CPUState *cs, GByteArray *buf, int n)
{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+
if (n < CSR_TABLE_SIZE) {
target_ulong val = 0;
int result;
@@ -172,8 +185,11 @@ static int riscv_gdb_get_csr(CPURISCVState *env, GByteArray *buf, int n)
return 0;
}
-static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
+static int riscv_gdb_set_csr(CPUState *cs, uint8_t *mem_buf, int n)
{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+
if (n < CSR_TABLE_SIZE) {
target_ulong val = ldtul_p(mem_buf);
int result;
@@ -186,25 +202,31 @@ static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
return 0;
}
-static int riscv_gdb_get_virtual(CPURISCVState *cs, GByteArray *buf, int n)
+static int riscv_gdb_get_virtual(CPUState *cs, GByteArray *buf, int n)
{
if (n == 0) {
#ifdef CONFIG_USER_ONLY
return gdb_get_regl(buf, 0);
#else
- return gdb_get_regl(buf, cs->priv);
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+
+ return gdb_get_regl(buf, env->priv);
#endif
}
return 0;
}
-static int riscv_gdb_set_virtual(CPURISCVState *cs, uint8_t *mem_buf, int n)
+static int riscv_gdb_set_virtual(CPUState *cs, uint8_t *mem_buf, int n)
{
if (n == 0) {
#ifndef CONFIG_USER_ONLY
- cs->priv = ldtul_p(mem_buf) & 0x3;
- if (cs->priv == PRV_RESERVED) {
- cs->priv = PRV_S;
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+
+ env->priv = ldtul_p(mem_buf) & 0x3;
+ if (env->priv == PRV_RESERVED) {
+ env->priv = PRV_S;
}
#endif
return sizeof(target_ulong);
diff --git a/target/s390x/gdbstub.c b/target/s390x/gdbstub.c
index 02c388dc32..c1e7c59b82 100644
--- a/target/s390x/gdbstub.c
+++ b/target/s390x/gdbstub.c
@@ -70,8 +70,11 @@ int s390_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
#define S390_A0_REGNUM 0
#define S390_A15_REGNUM 15
-static int cpu_read_ac_reg(CPUS390XState *env, GByteArray *buf, int n)
+static int cpu_read_ac_reg(CPUState *cs, GByteArray *buf, int n)
{
+ S390CPU *cpu = S390_CPU(cs);
+ CPUS390XState *env = &cpu->env;
+
switch (n) {
case S390_A0_REGNUM ... S390_A15_REGNUM:
return gdb_get_reg32(buf, env->aregs[n]);
@@ -80,8 +83,11 @@ static int cpu_read_ac_reg(CPUS390XState *env, GByteArray *buf, int n)
}
}
-static int cpu_write_ac_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_write_ac_reg(CPUState *cs, uint8_t *mem_buf, int n)
{
+ S390CPU *cpu = S390_CPU(cs);
+ CPUS390XState *env = &cpu->env;
+
switch (n) {
case S390_A0_REGNUM ... S390_A15_REGNUM:
env->aregs[n] = ldl_p(mem_buf);
@@ -97,8 +103,11 @@ static int cpu_write_ac_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
#define S390_F0_REGNUM 1
#define S390_F15_REGNUM 16
-static int cpu_read_fp_reg(CPUS390XState *env, GByteArray *buf, int n)
+static int cpu_read_fp_reg(CPUState *cs, GByteArray *buf, int n)
{
+ S390CPU *cpu = S390_CPU(cs);
+ CPUS390XState *env = &cpu->env;
+
switch (n) {
case S390_FPC_REGNUM:
return gdb_get_reg32(buf, env->fpc);
@@ -109,8 +118,11 @@ static int cpu_read_fp_reg(CPUS390XState *env, GByteArray *buf, int n)
}
}
-static int cpu_write_fp_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_write_fp_reg(CPUState *cs, uint8_t *mem_buf, int n)
{
+ S390CPU *cpu = S390_CPU(cs);
+ CPUS390XState *env = &cpu->env;
+
switch (n) {
case S390_FPC_REGNUM:
env->fpc = ldl_p(mem_buf);
@@ -129,8 +141,10 @@ static int cpu_write_fp_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
#define S390_V16_REGNUM 16
#define S390_V31_REGNUM 31
-static int cpu_read_vreg(CPUS390XState *env, GByteArray *buf, int n)
+static int cpu_read_vreg(CPUState *cs, GByteArray *buf, int n)
{
+ S390CPU *cpu = S390_CPU(cs);
+ CPUS390XState *env = &cpu->env;
int ret;
switch (n) {
@@ -148,8 +162,11 @@ static int cpu_read_vreg(CPUS390XState *env, GByteArray *buf, int n)
return ret;
}
-static int cpu_write_vreg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_write_vreg(CPUState *cs, uint8_t *mem_buf, int n)
{
+ S390CPU *cpu = S390_CPU(cs);
+ CPUS390XState *env = &cpu->env;
+
switch (n) {
case S390_V0L_REGNUM ... S390_V15L_REGNUM:
env->vregs[n][1] = ldtul_p(mem_buf + 8);
@@ -168,8 +185,11 @@ static int cpu_write_vreg(CPUS390XState *env, uint8_t *mem_buf, int n)
#define S390_C15_REGNUM 15
#ifndef CONFIG_USER_ONLY
-static int cpu_read_c_reg(CPUS390XState *env, GByteArray *buf, int n)
+static int cpu_read_c_reg(CPUState *cs, GByteArray *buf, int n)
{
+ S390CPU *cpu = S390_CPU(cs);
+ CPUS390XState *env = &cpu->env;
+
switch (n) {
case S390_C0_REGNUM ... S390_C15_REGNUM:
return gdb_get_regl(buf, env->cregs[n]);
@@ -178,8 +198,11 @@ static int cpu_read_c_reg(CPUS390XState *env, GByteArray *buf, int n)
}
}
-static int cpu_write_c_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_write_c_reg(CPUState *cs, uint8_t *mem_buf, int n)
{
+ S390CPU *cpu = S390_CPU(cs);
+ CPUS390XState *env = &cpu->env;
+
switch (n) {
case S390_C0_REGNUM ... S390_C15_REGNUM:
env->cregs[n] = ldtul_p(mem_buf);
@@ -199,8 +222,11 @@ static int cpu_write_c_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
#define S390_VIRT_BEA_REGNUM 2
#define S390_VIRT_PREFIX_REGNUM 3
-static int cpu_read_virt_reg(CPUS390XState *env, GByteArray *mem_buf, int n)
+static int cpu_read_virt_reg(CPUState *cs, GByteArray *mem_buf, int n)
{
+ S390CPU *cpu = S390_CPU(cs);
+ CPUS390XState *env = &cpu->env;
+
switch (n) {
case S390_VIRT_CKC_REGNUM:
return gdb_get_regl(mem_buf, env->ckc);
@@ -215,24 +241,27 @@ static int cpu_read_virt_reg(CPUS390XState *env, GByteArray *mem_buf, int n)
}
}
-static int cpu_write_virt_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_write_virt_reg(CPUState *cs, uint8_t *mem_buf, int n)
{
+ S390CPU *cpu = S390_CPU(cs);
+ CPUS390XState *env = &cpu->env;
+
switch (n) {
case S390_VIRT_CKC_REGNUM:
env->ckc = ldtul_p(mem_buf);
- cpu_synchronize_post_init(env_cpu(env));
+ cpu_synchronize_post_init(cs);
return 8;
case S390_VIRT_CPUTM_REGNUM:
env->cputm = ldtul_p(mem_buf);
- cpu_synchronize_post_init(env_cpu(env));
+ cpu_synchronize_post_init(cs);
return 8;
case S390_VIRT_BEA_REGNUM:
env->gbea = ldtul_p(mem_buf);
- cpu_synchronize_post_init(env_cpu(env));
+ cpu_synchronize_post_init(cs);
return 8;
case S390_VIRT_PREFIX_REGNUM:
env->psa = ldtul_p(mem_buf);
- cpu_synchronize_post_init(env_cpu(env));
+ cpu_synchronize_post_init(cs);
return 8;
default:
return 0;
@@ -245,8 +274,11 @@ static int cpu_write_virt_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
#define S390_VIRT_KVM_PFS_REGNUM 2
#define S390_VIRT_KVM_PFC_REGNUM 3
-static int cpu_read_virt_kvm_reg(CPUS390XState *env, GByteArray *mem_buf, int n)
+static int cpu_read_virt_kvm_reg(CPUState *cs, GByteArray *mem_buf, int n)
{
+ S390CPU *cpu = S390_CPU(cs);
+ CPUS390XState *env = &cpu->env;
+
switch (n) {
case S390_VIRT_KVM_PP_REGNUM:
return gdb_get_regl(mem_buf, env->pp);
@@ -261,8 +293,11 @@ static int cpu_read_virt_kvm_reg(CPUS390XState *env, GByteArray *mem_buf, int n)
}
}
-static int cpu_write_virt_kvm_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_write_virt_kvm_reg(CPUState *cs, uint8_t *mem_buf, int n)
{
+ S390CPU *cpu = S390_CPU(cs);
+ CPUS390XState *env = &cpu->env;
+
switch (n) {
case S390_VIRT_KVM_PP_REGNUM:
env->pp = ldtul_p(mem_buf);
@@ -292,13 +327,19 @@ static int cpu_write_virt_kvm_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
#define S390_GS_GSSM_REGNUM 2
#define S390_GS_GSEPLA_REGNUM 3
-static int cpu_read_gs_reg(CPUS390XState *env, GByteArray *buf, int n)
+static int cpu_read_gs_reg(CPUState *cs, GByteArray *buf, int n)
{
+ S390CPU *cpu = S390_CPU(cs);
+ CPUS390XState *env = &cpu->env;
+
return gdb_get_regl(buf, env->gscb[n]);
}
-static int cpu_write_gs_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_write_gs_reg(CPUState *cs, uint8_t *mem_buf, int n)
{
+ S390CPU *cpu = S390_CPU(cs);
+ CPUS390XState *env = &cpu->env;
+
env->gscb[n] = ldtul_p(mem_buf);
cpu_synchronize_post_init(env_cpu(env));
return 8;
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 17/29] gdbstub: Simplify XML lookup
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (15 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 16/29] gdbstub: Change gdb_get_reg_cb and gdb_set_reg_cb Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-07 8:46 ` Frédéric Pétrot
2023-11-03 19:59 ` [PATCH 18/29] gdbstub: Infer number of core registers from XML Alex Bennée
` (11 subsequent siblings)
28 siblings, 1 reply; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
From: Akihiko Odaki <akihiko.odaki@daynix.com>
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: <20231025093128.33116-11-akihiko.odaki@daynix.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
include/exec/gdbstub.h | 6 +++
gdbstub/gdbstub.c | 118 +++++++++++++++++++++--------------------
hw/core/cpu-common.c | 5 +-
3 files changed, 69 insertions(+), 60 deletions(-)
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index bcaab1bc75..82a8afa237 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -27,6 +27,12 @@ typedef struct GDBFeatureBuilder {
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);
+/**
+ * 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
* @cpu - the CPU associated with registers
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index 4809c90c4a..5ecd1f23e6 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -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);
CPUClass *cc = CPU_GET_CLASS(cpu);
+ GDBRegisterState *r;
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? */
if (strncmp(p, "target.xml", len) == 0) {
if (!process->target_xml) {
- GDBRegisterState *r;
g_autoptr(GPtrArray) xml = g_ptr_array_new_with_free_func(g_free);
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>",
cc->gdb_arch_name(cpu)));
}
- g_ptr_array_add(
- xml,
- g_markup_printf_escaped("<xi:include href=\"%s\"/>",
- cc->gdb_core_xml_file));
- if (cpu->gdb_regs) {
- for (guint i = 0; i < cpu->gdb_regs->len; i++) {
- 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));
- }
+ for (guint i = 0; i < cpu->gdb_regs->len; i++) {
+ 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, NULL);
@@ -400,20 +394,11 @@ static const char *get_feature_xml(const char *p, const char **newp,
}
return process->target_xml;
}
- /* Is it dynamically generated by the target? */
- if (cc->gdb_get_dynamic_xml) {
- g_autofree char *xmlname = g_strndup(p, len);
- const char *xml = cc->gdb_get_dynamic_xml(cpu, xmlname);
- if (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;
+ /* 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 (strncmp(p, r->feature->xmlname, len) == 0) {
+ return r->feature->xml;
}
}
@@ -508,12 +493,10 @@ static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
return cc->gdb_read_register(cpu, buf, reg);
}
- if (cpu->gdb_regs) {
- for (guint i = 0; i < cpu->gdb_regs->len; i++) {
- r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
- if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
- return r->get_reg(cpu, buf, reg - r->base_reg);
- }
+ for (guint i = 0; i < cpu->gdb_regs->len; i++) {
+ r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
+ if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
+ return r->get_reg(cpu, buf, reg - r->base_reg);
}
}
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);
}
- if (cpu->gdb_regs) {
- for (guint i = 0; i < cpu->gdb_regs->len; i++) {
- r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
- if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
- return r->set_reg(cpu, mem_buf, reg - r->base_reg);
- }
+ for (guint i = 0; i < cpu->gdb_regs->len; i++) {
+ r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
+ 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 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,
gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
const GDBFeature *feature, int g_pos)
{
GDBRegisterState *s;
guint i;
+ int base_reg = cpu->gdb_num_regs;
- if (cpu->gdb_regs) {
- for (i = 0; i < cpu->gdb_regs->len; i++) {
- /* Check for duplicates. */
- s = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
- if (s->feature == feature) {
- return;
- }
+ for (i = 0; i < cpu->gdb_regs->len; i++) {
+ /* Check for duplicates. */
+ s = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
+ if (s->feature == feature) {
+ return;
}
- } else {
- cpu->gdb_regs = g_array_new(false, false, sizeof(GDBRegisterState));
- i = 0;
}
- g_array_set_size(cpu->gdb_regs, i + 1);
- 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;
+ gdb_register_feature(cpu, base_reg, get_reg, set_reg, feature);
/* Add to end of list. */
cpu->gdb_num_regs += feature->num_regs;
if (g_pos) {
- if (g_pos != s->base_reg) {
+ if (g_pos != base_reg) {
error_report("Error: Bad gdb register numbering for '%s', "
- "expected %d got %d", feature->xml,
- g_pos, s->base_reg);
+ "expected %d got %d", feature->xml, g_pos, base_reg);
} else {
cpu->gdb_num_g_regs = cpu->gdb_num_regs;
}
diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c
index bab8942c30..2a2a6eb3eb 100644
--- a/hw/core/cpu-common.c
+++ b/hw/core/cpu-common.c
@@ -27,6 +27,7 @@
#include "qemu/main-loop.h"
#include "exec/log.h"
#include "exec/cpu-common.h"
+#include "exec/gdbstub.h"
#include "qemu/error-report.h"
#include "qemu/qemu-print.h"
#include "sysemu/tcg.h"
@@ -223,11 +224,10 @@ static void cpu_common_unrealizefn(DeviceState *dev)
static void cpu_common_initfn(Object *obj)
{
CPUState *cpu = CPU(obj);
- CPUClass *cc = CPU_GET_CLASS(obj);
+ gdb_init_cpu(cpu);
cpu->cpu_index = UNASSIGNED_CPU_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 */
/* the default value is changed by qemu_init_vcpu() for system-mode */
cpu->nr_cores = 1;
@@ -247,6 +247,7 @@ static void cpu_common_finalize(Object *obj)
{
CPUState *cpu = CPU(obj);
+ g_array_free(cpu->gdb_regs, TRUE);
qemu_lockcnt_destroy(&cpu->in_ioctl_lock);
qemu_mutex_destroy(&cpu->work_mutex);
}
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 18/29] gdbstub: Infer number of core registers from XML
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (16 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 17/29] gdbstub: Simplify XML lookup Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 19/29] hw/core/cpu: Remove gdb_get_dynamic_xml member Alex Bennée
` (10 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
From: Akihiko Odaki <akihiko.odaki@daynix.com>
GDBFeature has the num_regs member so use it where applicable to
remove magic numbers.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Message-Id: <20231025093128.33116-12-akihiko.odaki@daynix.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
include/hw/core/cpu.h | 3 ++-
target/s390x/cpu.h | 2 --
gdbstub/gdbstub.c | 5 ++++-
target/arm/cpu.c | 1 -
target/arm/cpu64.c | 1 -
target/avr/cpu.c | 1 -
target/hexagon/cpu.c | 1 -
target/i386/cpu.c | 2 --
target/loongarch/cpu.c | 2 --
target/m68k/cpu.c | 1 -
target/microblaze/cpu.c | 1 -
target/riscv/cpu.c | 1 -
target/rx/cpu.c | 1 -
target/s390x/cpu.c | 1 -
14 files changed, 6 insertions(+), 17 deletions(-)
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index 18593db5b2..9a771d682f 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -127,7 +127,8 @@ struct SysemuCPUOps;
* @gdb_adjust_breakpoint: Callback for adjusting the address of a
* breakpoint. Used by AVR to handle a gdb mis-feature with
* its Harvard architecture split code and data.
- * @gdb_num_core_regs: Number of core registers accessible to GDB.
+ * @gdb_num_core_regs: Number of core registers accessible to GDB or 0 to infer
+ * from @gdb_core_xml_file.
* @gdb_core_xml_file: File name for core registers GDB XML description.
* @gdb_stop_before_watchpoint: Indicates whether GDB expects the CPU to stop
* before the insn which triggers a watchpoint rather than after it.
diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
index 40c5cedd0e..12939bc562 100644
--- a/target/s390x/cpu.h
+++ b/target/s390x/cpu.h
@@ -458,8 +458,6 @@ static inline void cpu_get_tb_cpu_state(CPUS390XState *env, vaddr *pc,
#define S390_R13_REGNUM 15
#define S390_R14_REGNUM 16
#define S390_R15_REGNUM 17
-/* Total Core Registers. */
-#define S390_NUM_CORE_REGS 18
static inline void setcc(S390CPU *cpu, uint64_t cc)
{
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index 5ecd1f23e6..af63b5d159 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -546,9 +546,12 @@ void gdb_init_cpu(CPUState *cpu)
gdb_register_feature(cpu, 0,
cc->gdb_read_register, cc->gdb_write_register,
feature);
+ cpu->gdb_num_regs = cpu->gdb_num_g_regs = feature->num_regs;
}
- cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs;
+ if (cc->gdb_num_core_regs) {
+ cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs;
+ }
}
void gdb_register_coprocessor(CPUState *cpu,
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index df6496b019..a18b832c9a 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2489,7 +2489,6 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
#ifndef CONFIG_USER_ONLY
cc->sysemu_ops = &arm_sysemu_ops;
#endif
- cc->gdb_num_core_regs = 26;
cc->gdb_arch_name = arm_gdb_arch_name;
cc->gdb_get_dynamic_xml = arm_gdb_get_dynamic_xml;
cc->gdb_stop_before_watchpoint = true;
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 1e9c6c85ae..8a5bad54cf 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -793,7 +793,6 @@ static void aarch64_cpu_class_init(ObjectClass *oc, void *data)
cc->gdb_read_register = aarch64_cpu_gdb_read_register;
cc->gdb_write_register = aarch64_cpu_gdb_write_register;
- cc->gdb_num_core_regs = 34;
cc->gdb_core_xml_file = "aarch64-core.xml";
cc->gdb_arch_name = aarch64_gdb_arch_name;
diff --git a/target/avr/cpu.c b/target/avr/cpu.c
index 14d8b9d1f0..01adfb5089 100644
--- a/target/avr/cpu.c
+++ b/target/avr/cpu.c
@@ -244,7 +244,6 @@ static void avr_cpu_class_init(ObjectClass *oc, void *data)
cc->gdb_read_register = avr_cpu_gdb_read_register;
cc->gdb_write_register = avr_cpu_gdb_write_register;
cc->gdb_adjust_breakpoint = avr_cpu_gdb_adjust_breakpoint;
- cc->gdb_num_core_regs = 35;
cc->gdb_core_xml_file = "avr-cpu.xml";
cc->tcg_ops = &avr_tcg_ops;
}
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 60d52e1e9d..7c1426f70c 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -385,7 +385,6 @@ static void hexagon_cpu_class_init(ObjectClass *c, void *data)
cc->get_pc = hexagon_cpu_get_pc;
cc->gdb_read_register = hexagon_gdb_read_register;
cc->gdb_write_register = hexagon_gdb_write_register;
- cc->gdb_num_core_regs = TOTAL_PER_THREAD_REGS;
cc->gdb_stop_before_watchpoint = true;
cc->gdb_core_xml_file = "hexagon-core.xml";
cc->disas_set_info = hexagon_cpu_disas_set_info;
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index fc8484cb5e..6af6013d2d 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -7969,10 +7969,8 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
cc->gdb_arch_name = x86_gdb_arch_name;
#ifdef TARGET_X86_64
cc->gdb_core_xml_file = "i386-64bit.xml";
- cc->gdb_num_core_regs = 66;
#else
cc->gdb_core_xml_file = "i386-32bit.xml";
- cc->gdb_num_core_regs = 50;
#endif
cc->disas_set_info = x86_disas_set_info;
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index ef1bf89dac..1b25920895 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -775,7 +775,6 @@ static void loongarch32_cpu_class_init(ObjectClass *c, void *data)
{
CPUClass *cc = CPU_CLASS(c);
- cc->gdb_num_core_regs = 35;
cc->gdb_core_xml_file = "loongarch-base32.xml";
cc->gdb_arch_name = loongarch32_gdb_arch_name;
}
@@ -789,7 +788,6 @@ static void loongarch64_cpu_class_init(ObjectClass *c, void *data)
{
CPUClass *cc = CPU_CLASS(c);
- cc->gdb_num_core_regs = 35;
cc->gdb_core_xml_file = "loongarch-base64.xml";
cc->gdb_arch_name = loongarch64_gdb_arch_name;
}
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
index 538d9473c2..5fdbe5602b 100644
--- a/target/m68k/cpu.c
+++ b/target/m68k/cpu.c
@@ -565,7 +565,6 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data)
#endif
cc->disas_set_info = m68k_cpu_disas_set_info;
- cc->gdb_num_core_regs = 18;
cc->tcg_ops = &m68k_tcg_ops;
}
diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c
index 1998f69828..9d3fbfe159 100644
--- a/target/microblaze/cpu.c
+++ b/target/microblaze/cpu.c
@@ -428,7 +428,6 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data)
cc->sysemu_ops = &mb_sysemu_ops;
#endif
device_class_set_props(dc, mb_properties);
- cc->gdb_num_core_regs = 32 + 25;
cc->gdb_core_xml_file = "microblaze-core.xml";
cc->disas_set_info = mb_disas_set_info;
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 5200fba9b9..00518df497 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1575,7 +1575,6 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
cc->get_pc = riscv_cpu_get_pc;
cc->gdb_read_register = riscv_cpu_gdb_read_register;
cc->gdb_write_register = riscv_cpu_gdb_write_register;
- cc->gdb_num_core_regs = 33;
cc->gdb_stop_before_watchpoint = true;
cc->disas_set_info = riscv_cpu_disas_set_info;
#ifndef CONFIG_USER_ONLY
diff --git a/target/rx/cpu.c b/target/rx/cpu.c
index 4d0d3a0c8c..7b9e46d1bc 100644
--- a/target/rx/cpu.c
+++ b/target/rx/cpu.c
@@ -235,7 +235,6 @@ static void rx_cpu_class_init(ObjectClass *klass, void *data)
cc->gdb_write_register = rx_cpu_gdb_write_register;
cc->disas_set_info = rx_cpu_disas_set_info;
- cc->gdb_num_core_regs = 26;
cc->gdb_core_xml_file = "rx-core.xml";
cc->tcg_ops = &rx_tcg_ops;
}
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index 6acfa1c91b..6fba949729 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -362,7 +362,6 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
s390_cpu_class_init_sysemu(cc);
#endif
cc->disas_set_info = s390_cpu_disas_set_info;
- cc->gdb_num_core_regs = S390_NUM_CORE_REGS;
cc->gdb_core_xml_file = "s390x-core64.xml";
cc->gdb_arch_name = s390_gdb_arch_name;
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 19/29] hw/core/cpu: Remove gdb_get_dynamic_xml member
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (17 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 18/29] gdbstub: Infer number of core registers from XML Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 20/29] gdbstub: Add members to identify registers to GDBFeature Alex Bennée
` (9 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
From: Akihiko Odaki <akihiko.odaki@daynix.com>
This function is no longer used.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20231025093128.33116-13-akihiko.odaki@daynix.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
include/hw/core/cpu.h | 4 ----
target/arm/cpu.h | 6 ------
target/ppc/cpu.h | 1 -
target/arm/cpu.c | 1 -
target/arm/gdbstub.c | 18 ------------------
target/ppc/cpu_init.c | 3 ---
target/ppc/gdbstub.c | 10 ----------
target/riscv/cpu.c | 14 --------------
8 files changed, 57 deletions(-)
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index 9a771d682f..e4d28e09e8 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -134,9 +134,6 @@ struct SysemuCPUOps;
* before the insn which triggers a watchpoint rather than after it.
* @gdb_arch_name: Optional callback that returns the architecture name known
* to GDB. The caller must free the returned string with g_free.
- * @gdb_get_dynamic_xml: Callback to return dynamically generated XML for the
- * gdb stub. Returns a pointer to the XML contents for the specified XML file
- * or NULL if the CPU doesn't have a dynamically generated content for it.
* @disas_set_info: Setup architecture specific components of disassembly info
* @adjust_watchpoint_address: Perform a target-specific adjustment to an
* address before attempting to match it against watchpoints.
@@ -167,7 +164,6 @@ struct CPUClass {
const char *gdb_core_xml_file;
const gchar * (*gdb_arch_name)(CPUState *cpu);
- const char * (*gdb_get_dynamic_xml)(CPUState *cpu, const char *xmlname);
void (*disas_set_info)(CPUState *cpu, disassemble_info *info);
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 2549681367..ad0940dc57 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1137,12 +1137,6 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
int arm_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
-/* Returns the dynamically generated XML for the gdb stub.
- * Returns a pointer to the XML contents for the specified XML file or NULL
- * if the XML name doesn't match the predefined one.
- */
-const char *arm_gdb_get_dynamic_xml(CPUState *cpu, const char *xmlname);
-
int arm_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
int cpuid, DumpState *s);
int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 848062bc9f..650e6ece70 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1384,7 +1384,6 @@ int ppc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
int ppc_cpu_gdb_write_register_apple(CPUState *cpu, uint8_t *buf, int reg);
#ifndef CONFIG_USER_ONLY
hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-const char *ppc_gdb_get_dynamic_xml(CPUState *cs, const char *xml_name);
#endif
int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
int cpuid, DumpState *s);
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index a18b832c9a..9de8dd7599 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2490,7 +2490,6 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
cc->sysemu_ops = &arm_sysemu_ops;
#endif
cc->gdb_arch_name = arm_gdb_arch_name;
- cc->gdb_get_dynamic_xml = arm_gdb_get_dynamic_xml;
cc->gdb_stop_before_watchpoint = true;
cc->disas_set_info = arm_disas_set_info;
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index 059d84f98e..a3bb73cfa7 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -474,24 +474,6 @@ static GDBFeature *arm_gen_dynamic_m_secextreg_feature(CPUState *cs,
#endif
#endif /* CONFIG_TCG */
-const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
-{
- ARMCPU *cpu = ARM_CPU(cs);
-
- if (strcmp(xmlname, "system-registers.xml") == 0) {
- return cpu->dyn_sysreg_feature.desc.xml;
- } else if (strcmp(xmlname, "sve-registers.xml") == 0) {
- return cpu->dyn_svereg_feature.desc.xml;
- } else if (strcmp(xmlname, "arm-m-system.xml") == 0) {
- return cpu->dyn_m_systemreg_feature.desc.xml;
-#ifndef CONFIG_USER_ONLY
- } else if (strcmp(xmlname, "arm-m-secext.xml") == 0) {
- return cpu->dyn_m_secextreg_feature.desc.xml;
-#endif
- }
- return NULL;
-}
-
void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
{
CPUState *cs = CPU(cpu);
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index a0178c3ce8..909d753b02 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -7380,9 +7380,6 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
#endif
cc->gdb_num_core_regs = 71;
-#ifndef CONFIG_USER_ONLY
- cc->gdb_get_dynamic_xml = ppc_gdb_get_dynamic_xml;
-#endif
#ifdef USE_APPLE_GDB
cc->gdb_read_register = ppc_cpu_gdb_read_register_apple;
cc->gdb_write_register = ppc_cpu_gdb_write_register_apple;
diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c
index 8ca37b6bf9..f47878a67b 100644
--- a/target/ppc/gdbstub.c
+++ b/target/ppc/gdbstub.c
@@ -342,16 +342,6 @@ static void gdb_gen_spr_feature(CPUState *cs)
gdb_feature_builder_end(&builder);
}
-
-const char *ppc_gdb_get_dynamic_xml(CPUState *cs, const char *xml_name)
-{
- PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
-
- if (strcmp(xml_name, "power-spr.xml") == 0) {
- return pcc->gdb_spr.xml;
- }
- return NULL;
-}
#endif
#if !defined(CONFIG_USER_ONLY)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 00518df497..aee422c497 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1416,19 +1416,6 @@ static const gchar *riscv_gdb_arch_name(CPUState *cs)
}
}
-static const char *riscv_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
-{
- RISCVCPU *cpu = RISCV_CPU(cs);
-
- if (strcmp(xmlname, "riscv-csr.xml") == 0) {
- return cpu->dyn_csr_feature.xml;
- } else if (strcmp(xmlname, "riscv-vector.xml") == 0) {
- return cpu->dyn_vreg_feature.xml;
- }
-
- return NULL;
-}
-
#ifndef CONFIG_USER_ONLY
static int64_t riscv_get_arch_id(CPUState *cs)
{
@@ -1582,7 +1569,6 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
cc->get_arch_id = riscv_get_arch_id;
#endif
cc->gdb_arch_name = riscv_gdb_arch_name;
- cc->gdb_get_dynamic_xml = riscv_gdb_get_dynamic_xml;
object_class_property_add(c, "mvendorid", "uint32", cpu_get_mvendorid,
cpu_set_mvendorid, NULL, NULL);
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 20/29] gdbstub: Add members to identify registers to GDBFeature
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (18 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 19/29] hw/core/cpu: Remove gdb_get_dynamic_xml member Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 21/29] gdbstub: expose api to find registers Alex Bennée
` (8 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
From: Akihiko Odaki <akihiko.odaki@daynix.com>
These members will be used to help plugins to identify registers.
The added members in instances of GDBFeature dynamically generated by
CPUs will be filled in later changes.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Message-Id: <20231025093128.33116-14-akihiko.odaki@daynix.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
include/exec/gdbstub.h | 3 +++
gdbstub/gdbstub.c | 12 +++++++++---
target/riscv/gdbstub.c | 4 +---
scripts/feature_to_c.py | 14 +++++++++++++-
4 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 82a8afa237..da9ddfe54c 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -13,12 +13,15 @@
typedef struct GDBFeature {
const char *xmlname;
const char *xml;
+ const char *name;
+ const char * const *regs;
int num_regs;
} GDBFeature;
typedef struct GDBFeatureBuilder {
GDBFeature *feature;
GPtrArray *xml;
+ GPtrArray *regs;
int base_reg;
} GDBFeatureBuilder;
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index af63b5d159..7d7d887817 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -419,9 +419,10 @@ void gdb_feature_builder_init(GDBFeatureBuilder *builder, GDBFeature *feature,
builder->feature = feature;
builder->xml = g_ptr_array_new();
g_ptr_array_add(builder->xml, header);
+ builder->regs = g_ptr_array_new();
builder->base_reg = base_reg;
feature->xmlname = xmlname;
- feature->num_regs = 0;
+ feature->name = name;
}
void gdb_feature_builder_append_tag(const GDBFeatureBuilder *builder,
@@ -440,10 +441,12 @@ void gdb_feature_builder_append_reg(const GDBFeatureBuilder *builder,
const char *type,
const char *group)
{
- if (builder->feature->num_regs < regnum) {
- builder->feature->num_regs = regnum;
+ if (builder->regs->len <= regnum) {
+ g_ptr_array_set_size(builder->regs, regnum + 1);
}
+ builder->regs->pdata[regnum] = (gpointer *)name;
+
if (group) {
gdb_feature_builder_append_tag(
builder,
@@ -469,6 +472,9 @@ void gdb_feature_builder_end(const GDBFeatureBuilder *builder)
}
g_ptr_array_free(builder->xml, TRUE);
+
+ builder->feature->num_regs = builder->regs->len;
+ builder->feature->regs = (void *)g_ptr_array_free(builder->regs, FALSE);
}
const GDBFeature *gdb_find_static_feature(const char *xmlname)
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
index 9553ad62a3..fce87a16c2 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -263,11 +263,9 @@ static GDBFeature *riscv_gen_dynamic_csr_feature(CPUState *cs, int base_reg)
}
predicate = csr_ops[i].predicate;
if (predicate && (predicate(env, i) == RISCV_EXCP_NONE)) {
- g_autofree char *dynamic_name = NULL;
name = csr_ops[i].name;
if (!name) {
- dynamic_name = g_strdup_printf("csr%03x", i);
- name = dynamic_name;
+ name = g_strdup_printf("csr%03x", i);
}
gdb_feature_builder_append_reg(&builder, name, bitsize, i,
diff --git a/scripts/feature_to_c.py b/scripts/feature_to_c.py
index e04d6b2df7..807af0e685 100644
--- a/scripts/feature_to_c.py
+++ b/scripts/feature_to_c.py
@@ -50,7 +50,9 @@ def writeliteral(indent, bytes):
sys.stderr.write(f'unexpected start tag: {element.tag}\n')
exit(1)
+ feature_name = element.attrib['name']
regnum = 0
+ regnames = []
regnums = []
tags = ['feature']
for event, element in events:
@@ -67,6 +69,7 @@ def writeliteral(indent, bytes):
if 'regnum' in element.attrib:
regnum = int(element.attrib['regnum'])
+ regnames.append(element.attrib['name'])
regnums.append(regnum)
regnum += 1
@@ -85,6 +88,15 @@ def writeliteral(indent, bytes):
writeliteral(8, bytes(os.path.basename(input), 'utf-8'))
sys.stdout.write(',\n')
writeliteral(8, read)
- sys.stdout.write(f',\n {num_regs},\n }},\n')
+ sys.stdout.write(',\n')
+ writeliteral(8, bytes(feature_name, 'utf-8'))
+ sys.stdout.write(',\n (const char * const []) {\n')
+
+ for index, regname in enumerate(regnames):
+ sys.stdout.write(f' [{regnums[index] - base_reg}] =\n')
+ writeliteral(16, bytes(regname, 'utf-8'))
+ sys.stdout.write(',\n')
+
+ sys.stdout.write(f' }},\n {num_regs},\n }},\n')
sys.stdout.write(' { NULL }\n};\n')
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 21/29] gdbstub: expose api to find registers
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (19 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 20/29] gdbstub: Add members to identify registers to GDBFeature Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 22/29] cpu: Call plugin hooks only when ready Alex Bennée
` (7 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
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.odaki@daynix.com>
Cc: Akihiko Odaki <akihiko.odaki@daynix.com>
Signed-off-by: Alex Bennée <alex.bennee@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
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 22/29] cpu: Call plugin hooks only when ready
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (20 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 21/29] gdbstub: expose api to find registers Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 23/29] plugins: Use different helpers when reading registers Alex Bennée
` (6 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
From: Akihiko Odaki <akihiko.odaki@daynix.com>
The initialization and exit hooks will not affect the state of vCPU
outside TCG context, but they may depend on the state of vCPU.
Therefore, it's better to call plugin hooks after the vCPU state is
fully initialized and before it gets uninitialized.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20231025093128.33116-16-akihiko.odaki@daynix.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
cpu-target.c | 11 -----------
hw/core/cpu-common.c | 10 ++++++++++
2 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/cpu-target.c b/cpu-target.c
index 79363ae370..00cd7f4d69 100644
--- a/cpu-target.c
+++ b/cpu-target.c
@@ -42,7 +42,6 @@
#include "hw/core/accel-cpu.h"
#include "trace/trace-root.h"
#include "qemu/accel.h"
-#include "qemu/plugin.h"
uintptr_t qemu_host_page_size;
intptr_t qemu_host_page_mask;
@@ -143,11 +142,6 @@ void cpu_exec_realizefn(CPUState *cpu, Error **errp)
/* Wait until cpu initialization complete before exposing cpu. */
cpu_list_add(cpu);
- /* Plugin initialization must wait until cpu_index assigned. */
- if (tcg_enabled()) {
- qemu_plugin_vcpu_init_hook(cpu);
- }
-
#ifdef CONFIG_USER_ONLY
assert(qdev_get_vmsd(DEVICE(cpu)) == NULL ||
qdev_get_vmsd(DEVICE(cpu))->unmigratable);
@@ -174,11 +168,6 @@ void cpu_exec_unrealizefn(CPUState *cpu)
}
#endif
- /* Call the plugin hook before clearing cpu->cpu_index in cpu_list_remove */
- if (tcg_enabled()) {
- qemu_plugin_vcpu_exit_hook(cpu);
- }
-
cpu_list_remove(cpu);
/*
* Now that the vCPU has been removed from the RCU list, we can call
diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c
index 2a2a6eb3eb..409397e2b5 100644
--- a/hw/core/cpu-common.c
+++ b/hw/core/cpu-common.c
@@ -210,6 +210,11 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp)
cpu_resume(cpu);
}
+ /* Plugin initialization must wait until the cpu is fully realized. */
+ if (tcg_enabled()) {
+ qemu_plugin_vcpu_init_hook(cpu);
+ }
+
/* NOTE: latest generic point where the cpu is fully realized */
}
@@ -217,6 +222,11 @@ static void cpu_common_unrealizefn(DeviceState *dev)
{
CPUState *cpu = CPU(dev);
+ /* Call the plugin hook before clearing the cpu is fully unrealized */
+ if (tcg_enabled()) {
+ qemu_plugin_vcpu_exit_hook(cpu);
+ }
+
/* NOTE: latest generic point before the cpu is fully unrealized */
cpu_exec_unrealizefn(cpu);
}
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 23/29] plugins: Use different helpers when reading registers
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (21 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 22/29] cpu: Call plugin hooks only when ready Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-07 3:13 ` Richard Henderson
2023-11-03 19:59 ` [PATCH 24/29] plugins: add an API to read registers Alex Bennée
` (5 subsequent siblings)
28 siblings, 1 reply; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
From: Akihiko Odaki <akihiko.odaki@daynix.com>
This avoids optimizations incompatible when reading registers.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Message-Id: <20231025093128.33116-17-akihiko.odaki@daynix.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
accel/tcg/plugin-helpers.h | 3 ++-
include/qemu/plugin.h | 1 +
accel/tcg/plugin-gen.c | 43 ++++++++++++++++++++++++++++++++++----
plugins/api.c | 12 +++++++++--
4 files changed, 52 insertions(+), 7 deletions(-)
diff --git a/accel/tcg/plugin-helpers.h b/accel/tcg/plugin-helpers.h
index 8e685e0654..11796436f3 100644
--- a/accel/tcg/plugin-helpers.h
+++ b/accel/tcg/plugin-helpers.h
@@ -1,4 +1,5 @@
#ifdef CONFIG_PLUGIN
-DEF_HELPER_FLAGS_2(plugin_vcpu_udata_cb, TCG_CALL_NO_RWG | TCG_CALL_PLUGIN, void, i32, ptr)
+DEF_HELPER_FLAGS_2(plugin_vcpu_udata_cb_no_wg, TCG_CALL_NO_WG | TCG_CALL_PLUGIN, void, i32, ptr)
+DEF_HELPER_FLAGS_2(plugin_vcpu_udata_cb_no_rwg, TCG_CALL_NO_RWG | TCG_CALL_PLUGIN, void, i32, ptr)
DEF_HELPER_FLAGS_4(plugin_vcpu_mem_cb, TCG_CALL_NO_RWG | TCG_CALL_PLUGIN, void, i32, i32, i64, ptr)
#endif
diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
index 7fdc3a4849..b0c5ac6829 100644
--- a/include/qemu/plugin.h
+++ b/include/qemu/plugin.h
@@ -73,6 +73,7 @@ enum plugin_dyn_cb_type {
enum plugin_dyn_cb_subtype {
PLUGIN_CB_REGULAR,
+ PLUGIN_CB_REGULAR_R,
PLUGIN_CB_INLINE,
PLUGIN_N_CB_SUBTYPES,
};
diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index 78b331b251..b37ce7683e 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -79,6 +79,7 @@ enum plugin_gen_from {
enum plugin_gen_cb {
PLUGIN_GEN_CB_UDATA,
+ PLUGIN_GEN_CB_UDATA_R,
PLUGIN_GEN_CB_INLINE,
PLUGIN_GEN_CB_MEM,
PLUGIN_GEN_ENABLE_MEM_HELPER,
@@ -90,7 +91,10 @@ enum plugin_gen_cb {
* These helpers are stubs that get dynamically switched out for calls
* direct to the plugin if they are subscribed to.
*/
-void HELPER(plugin_vcpu_udata_cb)(uint32_t cpu_index, void *udata)
+void HELPER(plugin_vcpu_udata_cb_no_wg)(uint32_t cpu_index, void *udata)
+{ }
+
+void HELPER(plugin_vcpu_udata_cb_no_rwg)(uint32_t cpu_index, void *udata)
{ }
void HELPER(plugin_vcpu_mem_cb)(unsigned int vcpu_index,
@@ -98,7 +102,7 @@ void HELPER(plugin_vcpu_mem_cb)(unsigned int vcpu_index,
void *userdata)
{ }
-static void gen_empty_udata_cb(void)
+static void gen_empty_udata_cb(void (*gen_helper)(TCGv_i32, TCGv_ptr))
{
TCGv_i32 cpu_index = tcg_temp_ebb_new_i32();
TCGv_ptr udata = tcg_temp_ebb_new_ptr();
@@ -106,12 +110,22 @@ static void gen_empty_udata_cb(void)
tcg_gen_movi_ptr(udata, 0);
tcg_gen_ld_i32(cpu_index, tcg_env,
-offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
- gen_helper_plugin_vcpu_udata_cb(cpu_index, udata);
+ gen_helper(cpu_index, udata);
tcg_temp_free_ptr(udata);
tcg_temp_free_i32(cpu_index);
}
+static void gen_empty_udata_cb_no_wg(void)
+{
+ gen_empty_udata_cb(gen_helper_plugin_vcpu_udata_cb_no_wg);
+}
+
+static void gen_empty_udata_cb_no_rwg(void)
+{
+ gen_empty_udata_cb(gen_helper_plugin_vcpu_udata_cb_no_rwg);
+}
+
/*
* For now we only support addi_i64.
* When we support more ops, we can generate one empty inline cb for each.
@@ -192,7 +206,8 @@ static void plugin_gen_empty_callback(enum plugin_gen_from from)
gen_empty_mem_helper);
/* fall through */
case PLUGIN_GEN_FROM_TB:
- gen_wrapped(from, PLUGIN_GEN_CB_UDATA, gen_empty_udata_cb);
+ gen_wrapped(from, PLUGIN_GEN_CB_UDATA, gen_empty_udata_cb_no_rwg);
+ gen_wrapped(from, PLUGIN_GEN_CB_UDATA_R, gen_empty_udata_cb_no_wg);
gen_wrapped(from, PLUGIN_GEN_CB_INLINE, gen_empty_inline_cb);
break;
default:
@@ -588,6 +603,12 @@ static void plugin_gen_tb_udata(const struct qemu_plugin_tb *ptb,
inject_udata_cb(ptb->cbs[PLUGIN_CB_REGULAR], begin_op);
}
+static void plugin_gen_tb_udata_r(const struct qemu_plugin_tb *ptb,
+ TCGOp *begin_op)
+{
+ inject_udata_cb(ptb->cbs[PLUGIN_CB_REGULAR_R], begin_op);
+}
+
static void plugin_gen_tb_inline(const struct qemu_plugin_tb *ptb,
TCGOp *begin_op)
{
@@ -602,6 +623,14 @@ static void plugin_gen_insn_udata(const struct qemu_plugin_tb *ptb,
inject_udata_cb(insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR], begin_op);
}
+static void plugin_gen_insn_udata_r(const struct qemu_plugin_tb *ptb,
+ TCGOp *begin_op, int insn_idx)
+{
+ struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
+
+ inject_udata_cb(insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR_R], begin_op);
+}
+
static void plugin_gen_insn_inline(const struct qemu_plugin_tb *ptb,
TCGOp *begin_op, int insn_idx)
{
@@ -721,6 +750,9 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
case PLUGIN_GEN_CB_UDATA:
plugin_gen_tb_udata(plugin_tb, op);
break;
+ case PLUGIN_GEN_CB_UDATA_R:
+ plugin_gen_tb_udata_r(plugin_tb, op);
+ break;
case PLUGIN_GEN_CB_INLINE:
plugin_gen_tb_inline(plugin_tb, op);
break;
@@ -737,6 +769,9 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
case PLUGIN_GEN_CB_UDATA:
plugin_gen_insn_udata(plugin_tb, op, insn_idx);
break;
+ case PLUGIN_GEN_CB_UDATA_R:
+ plugin_gen_insn_udata_r(plugin_tb, op, insn_idx);
+ break;
case PLUGIN_GEN_CB_INLINE:
plugin_gen_insn_inline(plugin_tb, op, insn_idx);
break;
diff --git a/plugins/api.c b/plugins/api.c
index 5521b0ad36..ac39cdea0b 100644
--- a/plugins/api.c
+++ b/plugins/api.c
@@ -89,7 +89,11 @@ void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
void *udata)
{
if (!tb->mem_only) {
- plugin_register_dyn_cb__udata(&tb->cbs[PLUGIN_CB_REGULAR],
+ int index = flags == QEMU_PLUGIN_CB_R_REGS ||
+ flags == QEMU_PLUGIN_CB_RW_REGS ?
+ PLUGIN_CB_REGULAR_R : PLUGIN_CB_REGULAR;
+
+ plugin_register_dyn_cb__udata(&tb->cbs[index],
cb, flags, udata);
}
}
@@ -109,7 +113,11 @@ void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
void *udata)
{
if (!insn->mem_only) {
- plugin_register_dyn_cb__udata(&insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR],
+ int index = flags == QEMU_PLUGIN_CB_R_REGS ||
+ flags == QEMU_PLUGIN_CB_RW_REGS ?
+ PLUGIN_CB_REGULAR_R : PLUGIN_CB_REGULAR;
+
+ plugin_register_dyn_cb__udata(&insn->cbs[PLUGIN_CB_INSN][index],
cb, flags, udata);
}
}
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 24/29] plugins: add an API to read registers
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (22 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 23/29] plugins: Use different helpers when reading registers Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-05 12:40 ` Akihiko Odaki
2023-11-03 19:59 ` [PATCH 25/29] contrib/plugins: extend execlog to track register changes Alex Bennée
` (4 subsequent siblings)
28 siblings, 1 reply; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
We can only request a list of registers once the vCPU has been
initialised so the user needs to use either call the find function on
vCPU initialisation or during the translation phase. We don't expose
the reg number to the plugin instead hiding it behind an opaque
handle. This allows for a bit of future proofing should the internals
need to be changed while also being hashed against the CPUClass so we
can handle different register sets per-vCPU in hetrogenous situations.
Having an internal state within the plugins also allows us to expand
the interface in future (for example providing callbacks on register
change if the translator can track changes).
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1706
Cc: Akihiko Odaki <akihiko.odaki@daynix.com>
Based-on: <20231025093128.33116-18-akihiko.odaki@daynix.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
vAJB:
The main difference to Akikio's version is hiding the gdb register
detail from the plugin for the reasons described above.
---
include/qemu/qemu-plugin.h | 52 +++++++++++++++++-
plugins/api.c | 102 +++++++++++++++++++++++++++++++++++
plugins/qemu-plugins.symbols | 2 +
3 files changed, 154 insertions(+), 2 deletions(-)
diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
index 50a9957279..e5c16df5ca 100644
--- a/include/qemu/qemu-plugin.h
+++ b/include/qemu/qemu-plugin.h
@@ -11,6 +11,7 @@
#ifndef QEMU_QEMU_PLUGIN_H
#define QEMU_QEMU_PLUGIN_H
+#include <glib.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stddef.h>
@@ -218,8 +219,8 @@ struct qemu_plugin_insn;
* @QEMU_PLUGIN_CB_R_REGS: callback reads the CPU's regs
* @QEMU_PLUGIN_CB_RW_REGS: callback reads and writes the CPU's regs
*
- * Note: currently unused, plugins cannot read or change system
- * register state.
+ * Note: currently QEMU_PLUGIN_CB_RW_REGS is unused, plugins cannot change
+ * system register state.
*/
enum qemu_plugin_cb_flags {
QEMU_PLUGIN_CB_NO_REGS,
@@ -664,4 +665,51 @@ uint64_t qemu_plugin_end_code(void);
*/
uint64_t qemu_plugin_entry_code(void);
+/** struct qemu_plugin_register - Opaque handle for a translated instruction */
+struct qemu_plugin_register;
+
+/**
+ * typedef qemu_plugin_reg_descriptor - register descriptions
+ *
+ * @name: register name
+ * @handle: opaque handle for retrieving value with qemu_plugin_read_register
+ * @feature: optional feature descriptor, can be NULL
+ */
+typedef struct {
+ char name[32];
+ struct qemu_plugin_register *handle;
+ const char *feature;
+} qemu_plugin_reg_descriptor;
+
+/**
+ * qemu_plugin_find_registers() - return register list
+ * @vcpu_index: vcpu to query
+ * @reg_pattern: register name pattern
+ *
+ * Returns a GArray of qemu_plugin_reg_descriptor or NULL. Caller
+ * frees. As the register set of a given vCPU is only available once
+ * the vCPU is initialised if you want to monitor registers from the
+ * start you should call this from a qemu_plugin_register_vcpu_init_cb()
+ * callback.
+ */
+GArray * qemu_plugin_find_registers(unsigned int vcpu_index, const char *reg_pattern);
+
+/**
+ * qemu_plugin_read_register() - read register
+ *
+ * @vcpu: vcpu index
+ * @handle: a @qemu_plugin_reg_handle handle
+ * @buf: A GByteArray for the data owned by the plugin
+ *
+ * This function is only available in a context that register read access is
+ * explicitly requested.
+ *
+ * Returns the size of the read register. The content of @buf is in target byte
+ * order. On failure returns -1
+ */
+int qemu_plugin_read_register(unsigned int vcpu,
+ struct qemu_plugin_register *handle,
+ GByteArray *buf);
+
+
#endif /* QEMU_QEMU_PLUGIN_H */
diff --git a/plugins/api.c b/plugins/api.c
index ac39cdea0b..2644af5bb3 100644
--- a/plugins/api.c
+++ b/plugins/api.c
@@ -8,6 +8,7 @@
*
* qemu_plugin_tb
* qemu_plugin_insn
+ * qemu_plugin_register
*
* Which can then be passed back into the API to do additional things.
* As such all the public functions in here are exported in
@@ -35,10 +36,12 @@
*/
#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
#include "qemu/plugin.h"
#include "qemu/log.h"
#include "tcg/tcg.h"
#include "exec/exec-all.h"
+#include "exec/gdbstub.h"
#include "exec/ram_addr.h"
#include "disas/disas.h"
#include "plugin.h"
@@ -435,3 +438,102 @@ uint64_t qemu_plugin_entry_code(void)
#endif
return entry;
}
+
+/*
+ * Register handles
+ *
+ * The plugin infrastructure keeps hold of these internal data
+ * structures which are presented to plugins as opaque handles. They
+ * are global to the system and therefor additions to the hash table
+ * must be protected by the @reg_handle_lock.
+ *
+ * In order to future proof for up-coming heterogeneous work we want
+ * different entries for each CPU type while sharing them in the
+ * common case of multiple cores of the same type.
+ */
+
+static QemuMutex reg_handle_lock;
+
+struct qemu_plugin_register {
+ const char *name;
+ int gdb_reg_num;
+};
+
+static GHashTable *reg_handles; /* hash table of PluginReg */
+
+/* Generate a stable key - would xxhash be overkill? */
+static gpointer cpu_plus_reg_to_key(CPUState *cs, int gdb_regnum)
+{
+ uintptr_t key = (uintptr_t) cs->cc;
+ key ^= gdb_regnum;
+ return GUINT_TO_POINTER(key);
+}
+
+/*
+ * Create register handles.
+ *
+ * We need to create a handle for each register so the plugin
+ * infrastructure can call gdbstub to read a register. We also
+ * construct a result array with those handles and some ancillary data
+ * the plugin might find useful.
+ */
+
+static GArray * create_register_handles(CPUState *cs, GArray *gdbstub_regs) {
+ GArray *find_data = g_array_new(true, true, sizeof(qemu_plugin_reg_descriptor));
+
+ WITH_QEMU_LOCK_GUARD(®_handle_lock) {
+
+ if (!reg_handles) {
+ reg_handles = g_hash_table_new(g_direct_hash, g_direct_equal);
+ }
+
+ for (int i=0; i < gdbstub_regs->len; i++) {
+ GDBRegDesc *grd = &g_array_index(gdbstub_regs, GDBRegDesc, i);
+ gpointer key = cpu_plus_reg_to_key(cs, grd->gdb_reg);
+ struct qemu_plugin_register *val = g_hash_table_lookup(reg_handles, key);
+
+ /* Doesn't exist, create one */
+ if (!val) {
+ val = g_new0(struct qemu_plugin_register, 1);
+ val->gdb_reg_num = grd->gdb_reg;
+ val->name = grd->name;
+
+ g_hash_table_insert(reg_handles, key, val);
+ }
+
+ /* Create a record for the plugin */
+ qemu_plugin_reg_descriptor desc = {
+ .handle = val,
+ .feature = g_intern_string(grd->feature_name)
+ };
+ g_strlcpy(desc.name, val->name, sizeof(desc.name));
+ g_array_append_val(find_data, desc);
+ }
+ }
+
+ return find_data;
+}
+
+GArray * qemu_plugin_find_registers(unsigned int vcpu, const char *reg_pattern)
+{
+ CPUState *cs = qemu_get_cpu(vcpu);
+ if (cs) {
+ g_autoptr(GArray) regs = gdb_find_registers(cs, reg_pattern);
+ return regs->len ? create_register_handles(cs, regs) : NULL;
+ } else {
+ return NULL;
+ }
+}
+
+int qemu_plugin_read_register(unsigned int vcpu, struct qemu_plugin_register *reg, GByteArray *buf)
+{
+ CPUState *cs = qemu_get_cpu(vcpu);
+ /* assert with debugging on? */
+ return gdb_read_register(cs, buf, reg->gdb_reg_num);
+}
+
+static void __attribute__((__constructor__)) qemu_api_init(void)
+{
+ qemu_mutex_init(®_handle_lock);
+
+}
diff --git a/plugins/qemu-plugins.symbols b/plugins/qemu-plugins.symbols
index 71f6c90549..86928f5f50 100644
--- a/plugins/qemu-plugins.symbols
+++ b/plugins/qemu-plugins.symbols
@@ -42,4 +42,6 @@
qemu_plugin_tb_vaddr;
qemu_plugin_uninstall;
qemu_plugin_vcpu_for_each;
+ qemu_plugin_find_registers;
+ qemu_plugin_read_register;
};
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 25/29] contrib/plugins: extend execlog to track register changes
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (23 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 24/29] plugins: add an API to read registers Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-06 15:30 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 26/29] plugins: add dllexport and dllimport to api funcs Alex Bennée
` (3 subsequent siblings)
28 siblings, 1 reply; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Akihiko Odaki
With the new plugin register API we can now track changes to register
values. Currently the implementation is fairly dumb which will slow
down if a large number of register values are being tracked. This
could be improved by only instrumenting instructions which mention
registers we are interested in tracking.
Example usage:
./qemu-aarch64 -D plugin.log -d plugin \
-cpu max,sve256=on \
-plugin contrib/plugins/libexeclog.so,reg=sp,reg=z\* \
./tests/tcg/aarch64-linux-user/sha512-sve
will display in the execlog any changes to the stack pointer (sp) and
the SVE Z registers.
Cc: Akihiko Odaki <akihiko.odaki@daynix.com>
Based-On: <20231025093128.33116-19-akihiko.odaki@daynix.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
vAJB:
Changes for the new API with a simpler glob based "reg" specifier
which can be specified multiple times.
---
docs/devel/tcg-plugins.rst | 10 ++-
contrib/plugins/execlog.c | 180 ++++++++++++++++++++++++++++---------
2 files changed, 145 insertions(+), 45 deletions(-)
diff --git a/docs/devel/tcg-plugins.rst b/docs/devel/tcg-plugins.rst
index 81dcd43a61..c9f8b27590 100644
--- a/docs/devel/tcg-plugins.rst
+++ b/docs/devel/tcg-plugins.rst
@@ -497,6 +497,15 @@ arguments if required::
$ qemu-system-arm $(QEMU_ARGS) \
-plugin ./contrib/plugins/libexeclog.so,ifilter=st1w,afilter=0x40001808 -d plugin
+This plugin can also dump a specified register. The specification of register
+follows `GDB standard target features <https://sourceware.org/gdb/onlinedocs/gdb/Standard-Target-Features.html>`__.
+
+Specify the name of the feature that contains the register and the name of the
+register with ``rfile`` and ``reg`` options, respectively::
+
+ $ qemu-system-arm $(QEMU_ARGS) \
+ -plugin ./contrib/plugins/libexeclog.so,rfile=org.gnu.gdb.arm.core,reg=sp -d plugin
+
- contrib/plugins/cache.c
Cache modelling plugin that measures the performance of a given L1 cache
@@ -583,4 +592,3 @@ The following API is generated from the inline documentation in
include the full kernel-doc annotations.
.. kernel-doc:: include/qemu/qemu-plugin.h
-
diff --git a/contrib/plugins/execlog.c b/contrib/plugins/execlog.c
index 82dc2f584e..dcee04fc37 100644
--- a/contrib/plugins/execlog.c
+++ b/contrib/plugins/execlog.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2021, Alexandre Iooss <erdnaxe@crans.org>
*
- * Log instruction execution with memory access.
+ * Log instruction execution with memory access and register changes
*
* License: GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
@@ -15,30 +15,29 @@
#include <qemu-plugin.h>
+typedef struct {
+ struct qemu_plugin_register *handle;
+ GByteArray *last;
+ GByteArray *new;
+ const char *name;
+} Register;
+
+typedef struct CPU {
+ /* Store last executed instruction on each vCPU as a GString */
+ GString *last_exec;
+ /* Ptr array of Register */
+ GPtrArray *registers;
+} CPU;
+
QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
-/* Store last executed instruction on each vCPU as a GString */
-static GPtrArray *last_exec;
+static CPU *cpus;
+static int num_cpus;
static GRWLock expand_array_lock;
static GPtrArray *imatches;
static GArray *amatches;
-
-/*
- * Expand last_exec array.
- *
- * As we could have multiple threads trying to do this we need to
- * serialise the expansion under a lock.
- */
-static void expand_last_exec(int cpu_index)
-{
- g_rw_lock_writer_lock(&expand_array_lock);
- while (cpu_index >= last_exec->len) {
- GString *s = g_string_new(NULL);
- g_ptr_array_add(last_exec, s);
- }
- g_rw_lock_writer_unlock(&expand_array_lock);
-}
+static GPtrArray *rmatches;
/**
* Add memory read or write information to current instruction log
@@ -50,8 +49,8 @@ static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t info,
/* Find vCPU in array */
g_rw_lock_reader_lock(&expand_array_lock);
- g_assert(cpu_index < last_exec->len);
- s = g_ptr_array_index(last_exec, cpu_index);
+ g_assert(cpu_index < num_cpus);
+ s = cpus[cpu_index].last_exec;
g_rw_lock_reader_unlock(&expand_array_lock);
/* Indicate type of memory access */
@@ -77,28 +76,46 @@ static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t info,
*/
static void vcpu_insn_exec(unsigned int cpu_index, void *udata)
{
- GString *s;
+ CPU *cpu;
- /* Find or create vCPU in array */
g_rw_lock_reader_lock(&expand_array_lock);
- if (cpu_index >= last_exec->len) {
- g_rw_lock_reader_unlock(&expand_array_lock);
- expand_last_exec(cpu_index);
- g_rw_lock_reader_lock(&expand_array_lock);
- }
- s = g_ptr_array_index(last_exec, cpu_index);
+ g_assert(cpu_index < num_cpus);
+ cpu = &cpus[cpu_index];
g_rw_lock_reader_unlock(&expand_array_lock);
/* Print previous instruction in cache */
- if (s->len) {
- qemu_plugin_outs(s->str);
+ if (cpus->last_exec->len) {
+ if (cpus->registers) {
+ for (int n = 0; n < cpu->registers->len; n++) {
+ Register *reg = cpu->registers->pdata[n];
+ int sz;
+
+ g_byte_array_set_size(reg->new, 0);
+ sz = qemu_plugin_read_register(cpu_index, reg->handle, reg->new);
+ g_assert(sz == reg->last->len);
+
+ if (memcmp(reg->last->data, reg->new->data, sz)) {
+ GByteArray *temp = reg->last;
+ g_string_append_printf(cpu->last_exec, ", %s -> ", reg->name);
+ /* TODO: handle BE properly */
+ for (int i = sz; i >= 0; i--) {
+ g_string_append_printf(cpu->last_exec, "%02x",
+ reg->new->data[i]);
+ }
+ reg->last = reg->new;
+ reg->new = temp;
+ }
+ }
+ }
+
+ qemu_plugin_outs(cpus[cpu_index].last_exec->str);
qemu_plugin_outs("\n");
}
/* Store new instruction in cache */
/* vcpu_mem will add memory access information to last_exec */
- g_string_printf(s, "%u, ", cpu_index);
- g_string_append(s, (char *)udata);
+ g_string_printf(cpus[cpu_index].last_exec, "%u, ", cpu_index);
+ g_string_append(cpus[cpu_index].last_exec, (char *)udata);
}
/**
@@ -167,8 +184,10 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
QEMU_PLUGIN_MEM_RW, NULL);
/* Register callback on instruction */
- qemu_plugin_register_vcpu_insn_exec_cb(insn, vcpu_insn_exec,
- QEMU_PLUGIN_CB_NO_REGS, output);
+ qemu_plugin_register_vcpu_insn_exec_cb(
+ insn, vcpu_insn_exec,
+ rmatches ? QEMU_PLUGIN_CB_R_REGS : QEMU_PLUGIN_CB_NO_REGS,
+ output);
/* reset skip */
skip = (imatches || amatches);
@@ -177,17 +196,77 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
}
}
+static Register *init_vcpu_register(int vcpu_index,
+ qemu_plugin_reg_descriptor *desc)
+{
+ Register *reg = g_new0(Register, 1);
+ int r;
+
+ reg->handle = desc->handle;
+ reg->name = g_strdup(desc->name);
+ reg->last = g_byte_array_new();
+ reg->new = g_byte_array_new();
+
+ /* read the initial value */
+ r = qemu_plugin_read_register(vcpu_index, reg->handle, reg->last);
+ g_assert(r > 0);
+ return reg;
+}
+
+/*
+ * Initialise a new vcpu/thread with:
+ * - last_exec tracking data
+ * - list of tracked registers
+ * - initial value of registers
+ *
+ * As we could have multiple threads trying to do this we need to
+ * serialise the expansion under a lock.
+ */
+static void vcpu_init(qemu_plugin_id_t id, unsigned int vcpu_index)
+{
+ g_rw_lock_writer_lock(&expand_array_lock);
+
+ if (vcpu_index >= num_cpus) {
+ cpus = g_realloc_n(cpus, vcpu_index + 1, sizeof(*cpus));
+ while (vcpu_index >= num_cpus) {
+ cpus[num_cpus].last_exec = g_string_new(NULL);
+
+ /* Any registers to track? */
+ if (rmatches && rmatches->len) {
+ GPtrArray *registers = g_ptr_array_new();
+
+ /* For each pattern add the register definitions */
+ for (int p = 0; p < rmatches->len; p++) {
+ g_autoptr(GArray) reg_list =
+ qemu_plugin_find_registers(vcpu_index, rmatches->pdata[p]);
+ if (reg_list && reg_list->len) {
+ for (int r = 0; r < reg_list->len; r++) {
+ Register *reg =
+ init_vcpu_register(vcpu_index,
+ &g_array_index(reg_list,
+ qemu_plugin_reg_descriptor, r));
+ g_ptr_array_add(registers, reg);
+ }
+ }
+ }
+ cpus[num_cpus].registers = registers;
+ }
+ num_cpus++;
+ }
+ }
+
+ g_rw_lock_writer_unlock(&expand_array_lock);
+}
+
/**
* On plugin exit, print last instruction in cache
*/
static void plugin_exit(qemu_plugin_id_t id, void *p)
{
guint i;
- GString *s;
- for (i = 0; i < last_exec->len; i++) {
- s = g_ptr_array_index(last_exec, i);
- if (s->str) {
- qemu_plugin_outs(s->str);
+ for (i = 0; i < num_cpus; i++) {
+ if (cpus[i].last_exec->str) {
+ qemu_plugin_outs(cpus[i].last_exec->str);
qemu_plugin_outs("\n");
}
}
@@ -212,6 +291,18 @@ static void parse_vaddr_match(char *match)
g_array_append_val(amatches, v);
}
+/*
+ * We have to wait until vCPUs are started before we can check the
+ * patterns find anything.
+ */
+static void add_regpat(char *regpat)
+{
+ if (!rmatches) {
+ rmatches = g_ptr_array_new();
+ }
+ g_ptr_array_add(rmatches, g_strdup(regpat));
+}
+
/**
* Install the plugin
*/
@@ -224,9 +315,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
* we don't know the size before emulation.
*/
if (info->system_emulation) {
- last_exec = g_ptr_array_sized_new(info->system.max_vcpus);
- } else {
- last_exec = g_ptr_array_new();
+ cpus = g_new(CPU, info->system.max_vcpus);
}
for (int i = 0; i < argc; i++) {
@@ -236,13 +325,16 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
parse_insn_match(tokens[1]);
} else if (g_strcmp0(tokens[0], "afilter") == 0) {
parse_vaddr_match(tokens[1]);
+ } else if (g_strcmp0(tokens[0], "reg") == 0) {
+ add_regpat(tokens[1]);
} else {
fprintf(stderr, "option parsing failed: %s\n", opt);
return -1;
}
}
- /* Register translation block and exit callbacks */
+ /* Register init, translation block and exit callbacks */
+ qemu_plugin_register_vcpu_init_cb(id, vcpu_init);
qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 26/29] plugins: add dllexport and dllimport to api funcs
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (24 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 25/29] contrib/plugins: extend execlog to track register changes Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 27/29] plugins: make test/example plugins work on windows Alex Bennée
` (2 subsequent siblings)
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Greg Manning
From: Greg Manning <gmanning@rapitasystems.com>
In qemu-plugin.h, mark all API functions as __declspec(dllexport) when
compiling the executables, and as __declspec(dllimport) when being used
to compile plugins against.
Signed-off-by: Greg Manning <gmanning@rapitasystems.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20231102172053.17692-2-gmanning@rapitasystems.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
include/qemu/qemu-plugin.h | 52 +++++++++++++++++++++++++++++++++++---
1 file changed, 49 insertions(+), 3 deletions(-)
diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
index e5c16df5ca..785315c06d 100644
--- a/include/qemu/qemu-plugin.h
+++ b/include/qemu/qemu-plugin.h
@@ -23,15 +23,18 @@
* https://gcc.gnu.org/wiki/Visibility
*/
#if defined _WIN32 || defined __CYGWIN__
- #ifdef BUILDING_DLL
- #define QEMU_PLUGIN_EXPORT __declspec(dllexport)
- #else
+ #ifdef CONFIG_PLUGIN
#define QEMU_PLUGIN_EXPORT __declspec(dllimport)
+ #define QEMU_PLUGIN_API __declspec(dllexport)
+ #else
+ #define QEMU_PLUGIN_EXPORT __declspec(dllexport)
+ #define QEMU_PLUGIN_API __declspec(dllimport)
#endif
#define QEMU_PLUGIN_LOCAL
#else
#define QEMU_PLUGIN_EXPORT __attribute__((visibility("default")))
#define QEMU_PLUGIN_LOCAL __attribute__((visibility("hidden")))
+ #define QEMU_PLUGIN_API
#endif
/**
@@ -148,6 +151,7 @@ typedef void (*qemu_plugin_vcpu_udata_cb_t)(unsigned int vcpu_index,
*
* Note: Calling this function from qemu_plugin_install() is a bug.
*/
+QEMU_PLUGIN_API
void qemu_plugin_uninstall(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb);
/**
@@ -161,6 +165,7 @@ void qemu_plugin_uninstall(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb);
* Plugins are reset asynchronously, and therefore the given plugin receives
* callbacks until @cb is called.
*/
+QEMU_PLUGIN_API
void qemu_plugin_reset(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb);
/**
@@ -172,6 +177,7 @@ void qemu_plugin_reset(qemu_plugin_id_t id, qemu_plugin_simple_cb_t cb);
*
* See also: qemu_plugin_register_vcpu_exit_cb()
*/
+QEMU_PLUGIN_API
void qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id,
qemu_plugin_vcpu_simple_cb_t cb);
@@ -184,6 +190,7 @@ void qemu_plugin_register_vcpu_init_cb(qemu_plugin_id_t id,
*
* See also: qemu_plugin_register_vcpu_init_cb()
*/
+QEMU_PLUGIN_API
void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,
qemu_plugin_vcpu_simple_cb_t cb);
@@ -194,6 +201,7 @@ void qemu_plugin_register_vcpu_exit_cb(qemu_plugin_id_t id,
*
* The @cb function is called every time a vCPU idles.
*/
+QEMU_PLUGIN_API
void qemu_plugin_register_vcpu_idle_cb(qemu_plugin_id_t id,
qemu_plugin_vcpu_simple_cb_t cb);
@@ -204,6 +212,7 @@ void qemu_plugin_register_vcpu_idle_cb(qemu_plugin_id_t id,
*
* The @cb function is called every time a vCPU resumes execution.
*/
+QEMU_PLUGIN_API
void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
qemu_plugin_vcpu_simple_cb_t cb);
@@ -254,6 +263,7 @@ typedef void (*qemu_plugin_vcpu_tb_trans_cb_t)(qemu_plugin_id_t id,
* callbacks to be triggered when the block or individual instruction
* executes.
*/
+QEMU_PLUGIN_API
void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
qemu_plugin_vcpu_tb_trans_cb_t cb);
@@ -266,6 +276,7 @@ void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
*
* The @cb function is called every time a translated unit executes.
*/
+QEMU_PLUGIN_API
void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
qemu_plugin_vcpu_udata_cb_t cb,
enum qemu_plugin_cb_flags flags,
@@ -297,6 +308,7 @@ enum qemu_plugin_op {
* Note: ops are not atomic so in multi-threaded/multi-smp situations
* you will get inexact results.
*/
+QEMU_PLUGIN_API
void qemu_plugin_register_vcpu_tb_exec_inline(struct qemu_plugin_tb *tb,
enum qemu_plugin_op op,
void *ptr, uint64_t imm);
@@ -310,6 +322,7 @@ void qemu_plugin_register_vcpu_tb_exec_inline(struct qemu_plugin_tb *tb,
*
* The @cb function is called every time an instruction is executed
*/
+QEMU_PLUGIN_API
void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
qemu_plugin_vcpu_udata_cb_t cb,
enum qemu_plugin_cb_flags flags,
@@ -325,6 +338,7 @@ void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
* Insert an inline op to every time an instruction executes. Useful
* if you just want to increment a single counter somewhere in memory.
*/
+QEMU_PLUGIN_API
void qemu_plugin_register_vcpu_insn_exec_inline(struct qemu_plugin_insn *insn,
enum qemu_plugin_op op,
void *ptr, uint64_t imm);
@@ -335,6 +349,7 @@ void qemu_plugin_register_vcpu_insn_exec_inline(struct qemu_plugin_insn *insn,
*
* Returns: number of instructions in this block
*/
+QEMU_PLUGIN_API
size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb);
/**
@@ -343,6 +358,7 @@ size_t qemu_plugin_tb_n_insns(const struct qemu_plugin_tb *tb);
*
* Returns: virtual address of block start
*/
+QEMU_PLUGIN_API
uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb);
/**
@@ -356,6 +372,7 @@ uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb);
*
* Returns: opaque handle to instruction
*/
+QEMU_PLUGIN_API
struct qemu_plugin_insn *
qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx);
@@ -369,6 +386,7 @@ qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx);
* Returns: pointer to a stream of bytes containing the value of this
* instructions opcode.
*/
+QEMU_PLUGIN_API
const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn);
/**
@@ -377,6 +395,7 @@ const void *qemu_plugin_insn_data(const struct qemu_plugin_insn *insn);
*
* Returns: size of instruction in bytes
*/
+QEMU_PLUGIN_API
size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn);
/**
@@ -385,6 +404,7 @@ size_t qemu_plugin_insn_size(const struct qemu_plugin_insn *insn);
*
* Returns: virtual address of instruction
*/
+QEMU_PLUGIN_API
uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn);
/**
@@ -393,6 +413,7 @@ uint64_t qemu_plugin_insn_vaddr(const struct qemu_plugin_insn *insn);
*
* Returns: hardware (physical) target address of instruction
*/
+QEMU_PLUGIN_API
void *qemu_plugin_insn_haddr(const struct qemu_plugin_insn *insn);
/**
@@ -411,6 +432,7 @@ struct qemu_plugin_hwaddr;
*
* Returns: size of access in ^2 (0=byte, 1=16bit, 2=32bit etc...)
*/
+QEMU_PLUGIN_API
unsigned int qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info);
/**
* qemu_plugin_mem_is_sign_extended() - was the access sign extended
@@ -418,6 +440,7 @@ unsigned int qemu_plugin_mem_size_shift(qemu_plugin_meminfo_t info);
*
* Returns: true if it was, otherwise false
*/
+QEMU_PLUGIN_API
bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info);
/**
* qemu_plugin_mem_is_big_endian() - was the access big endian
@@ -425,6 +448,7 @@ bool qemu_plugin_mem_is_sign_extended(qemu_plugin_meminfo_t info);
*
* Returns: true if it was, otherwise false
*/
+QEMU_PLUGIN_API
bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info);
/**
* qemu_plugin_mem_is_store() - was the access a store
@@ -432,6 +456,7 @@ bool qemu_plugin_mem_is_big_endian(qemu_plugin_meminfo_t info);
*
* Returns: true if it was, otherwise false
*/
+QEMU_PLUGIN_API
bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info);
/**
@@ -447,6 +472,7 @@ bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info);
* information about the handle should be recovered before the
* callback returns.
*/
+QEMU_PLUGIN_API
struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
uint64_t vaddr);
@@ -463,6 +489,7 @@ struct qemu_plugin_hwaddr *qemu_plugin_get_hwaddr(qemu_plugin_meminfo_t info,
* Returns true if the handle's memory operation is to memory-mapped IO, or
* false if it is to RAM
*/
+QEMU_PLUGIN_API
bool qemu_plugin_hwaddr_is_io(const struct qemu_plugin_hwaddr *haddr);
/**
@@ -474,12 +501,14 @@ bool qemu_plugin_hwaddr_is_io(const struct qemu_plugin_hwaddr *haddr);
* Note that the returned physical address may not be unique if you are dealing
* with multiple address spaces.
*/
+QEMU_PLUGIN_API
uint64_t qemu_plugin_hwaddr_phys_addr(const struct qemu_plugin_hwaddr *haddr);
/*
* Returns a string representing the device. The string is valid for
* the lifetime of the plugin.
*/
+QEMU_PLUGIN_API
const char *qemu_plugin_hwaddr_device_name(const struct qemu_plugin_hwaddr *h);
/**
@@ -514,6 +543,7 @@ typedef void (*qemu_plugin_vcpu_mem_cb_t) (unsigned int vcpu_index,
* callback so the plugin is responsible for ensuring it doesn't get
* confused by making appropriate use of locking if required.
*/
+QEMU_PLUGIN_API
void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
qemu_plugin_vcpu_mem_cb_t cb,
enum qemu_plugin_cb_flags flags,
@@ -532,6 +562,7 @@ void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
* instruction. This provides for a lightweight but not thread-safe
* way of counting the number of operations done.
*/
+QEMU_PLUGIN_API
void qemu_plugin_register_vcpu_mem_inline(struct qemu_plugin_insn *insn,
enum qemu_plugin_mem_rw rw,
enum qemu_plugin_op op, void *ptr,
@@ -545,6 +576,7 @@ typedef void
uint64_t a3, uint64_t a4, uint64_t a5,
uint64_t a6, uint64_t a7, uint64_t a8);
+QEMU_PLUGIN_API
void qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id,
qemu_plugin_vcpu_syscall_cb_t cb);
@@ -552,6 +584,7 @@ typedef void
(*qemu_plugin_vcpu_syscall_ret_cb_t)(qemu_plugin_id_t id, unsigned int vcpu_idx,
int64_t num, int64_t ret);
+QEMU_PLUGIN_API
void
qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
qemu_plugin_vcpu_syscall_ret_cb_t cb);
@@ -564,6 +597,7 @@ qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
* Returns an allocated string containing the disassembly
*/
+QEMU_PLUGIN_API
char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn);
/**
@@ -573,6 +607,7 @@ char *qemu_plugin_insn_disas(const struct qemu_plugin_insn *insn);
* Return a static string referring to the symbol. This is dependent
* on the binary QEMU is running having provided a symbol table.
*/
+QEMU_PLUGIN_API
const char *qemu_plugin_insn_symbol(const struct qemu_plugin_insn *insn);
/**
@@ -584,9 +619,11 @@ const char *qemu_plugin_insn_symbol(const struct qemu_plugin_insn *insn);
*
* See also: qemu_plugin_register_vcpu_init_cb()
*/
+QEMU_PLUGIN_API
void qemu_plugin_vcpu_for_each(qemu_plugin_id_t id,
qemu_plugin_vcpu_simple_cb_t cb);
+QEMU_PLUGIN_API
void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
qemu_plugin_simple_cb_t cb);
@@ -603,6 +640,7 @@ void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
* In user-mode it is possible a few un-instrumented instructions from
* child threads may run before the host kernel reaps the threads.
*/
+QEMU_PLUGIN_API
void qemu_plugin_register_atexit_cb(qemu_plugin_id_t id,
qemu_plugin_udata_cb_t cb, void *userdata);
@@ -616,6 +654,7 @@ int qemu_plugin_n_max_vcpus(void);
* qemu_plugin_outs() - output string via QEMU's logging system
* @string: a string
*/
+QEMU_PLUGIN_API
void qemu_plugin_outs(const char *string);
/**
@@ -629,6 +668,7 @@ void qemu_plugin_outs(const char *string);
* returns true if the combination @name=@val parses correctly to a boolean
* argument, and false otherwise
*/
+QEMU_PLUGIN_API
bool qemu_plugin_bool_parse(const char *name, const char *val, bool *ret);
/**
@@ -639,6 +679,7 @@ bool qemu_plugin_bool_parse(const char *name, const char *val, bool *ret);
* return NULL. The user should g_free() the string once no longer
* needed.
*/
+QEMU_PLUGIN_API
const char *qemu_plugin_path_to_binary(void);
/**
@@ -647,6 +688,7 @@ const char *qemu_plugin_path_to_binary(void);
* Returns the nominal start address of the main text segment in
* user-mode. Currently returns 0 for system emulation.
*/
+QEMU_PLUGIN_API
uint64_t qemu_plugin_start_code(void);
/**
@@ -655,6 +697,7 @@ uint64_t qemu_plugin_start_code(void);
* Returns the nominal end address of the main text segment in
* user-mode. Currently returns 0 for system emulation.
*/
+QEMU_PLUGIN_API
uint64_t qemu_plugin_end_code(void);
/**
@@ -663,6 +706,7 @@ uint64_t qemu_plugin_end_code(void);
* Returns the nominal entry address of the main text segment in
* user-mode. Currently returns 0 for system emulation.
*/
+QEMU_PLUGIN_API
uint64_t qemu_plugin_entry_code(void);
/** struct qemu_plugin_register - Opaque handle for a translated instruction */
@@ -692,6 +736,7 @@ typedef struct {
* start you should call this from a qemu_plugin_register_vcpu_init_cb()
* callback.
*/
+QEMU_PLUGIN_API
GArray * qemu_plugin_find_registers(unsigned int vcpu_index, const char *reg_pattern);
/**
@@ -707,6 +752,7 @@ GArray * qemu_plugin_find_registers(unsigned int vcpu_index, const char *reg_pat
* Returns the size of the read register. The content of @buf is in target byte
* order. On failure returns -1
*/
+QEMU_PLUGIN_API
int qemu_plugin_read_register(unsigned int vcpu,
struct qemu_plugin_register *handle,
GByteArray *buf);
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 27/29] plugins: make test/example plugins work on windows
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (25 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 26/29] plugins: add dllexport and dllimport to api funcs Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-04 9:14 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 28/29] plugins: disable lockstep plugin " Alex Bennée
2023-11-03 19:59 ` [PATCH 29/29] plugins: allow plugins to be enabled " Alex Bennée
28 siblings, 1 reply; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Greg Manning
From: Greg Manning <gmanning@rapitasystems.com>
Generate a qemu_plugin_api.lib delay import lib on windows, for
windows qemu plugins to link against.
Implement an example dll load fail hook to link up the API functions
correctly when a plugin is loaded on windows.
Update the build scripts for the test and example plugins to use these
things.
Signed-off-by: Greg Manning <gmanning@rapitasystems.com>
Acked-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20231102172053.17692-3-gmanning@rapitasystems.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
configure | 3 +++
contrib/plugins/win32_linker.c | 34 ++++++++++++++++++++++++++++++++++
contrib/plugins/Makefile | 20 ++++++++++++++++----
plugins/meson.build | 17 +++++++++++++++++
tests/plugin/meson.build | 14 +++++++++++---
5 files changed, 81 insertions(+), 7 deletions(-)
create mode 100644 contrib/plugins/win32_linker.c
diff --git a/configure b/configure
index f1456f6123..04f2cdd166 100755
--- a/configure
+++ b/configure
@@ -1662,6 +1662,9 @@ echo "CFLAGS=${CFLAGS-$default_cflags} $EXTRA_CFLAGS" >> contrib/plugins/$config
if test "$targetos" = darwin; then
echo "CONFIG_DARWIN=y" >> contrib/plugins/$config_host_mak
fi
+if test "$targetos" = windows; then
+ echo "CONFIG_WIN32=y" >> contrib/plugins/$config_host_mak
+fi
# tests/tcg configuration
(config_host_mak=tests/tcg/config-host.mak
diff --git a/contrib/plugins/win32_linker.c b/contrib/plugins/win32_linker.c
new file mode 100644
index 0000000000..50797d616e
--- /dev/null
+++ b/contrib/plugins/win32_linker.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023, Greg Manning <gmanning@rapitasystems.com>
+ *
+ * This hook, __pfnDliFailureHook2, is documented in the microsoft documentation here:
+ * https://learn.microsoft.com/en-us/cpp/build/reference/error-handling-and-notification
+ * It gets called when a delay-loaded DLL encounters various errors.
+ * We handle the specific case of a DLL looking for a "qemu.exe",
+ * and give it the running executable (regardless of what it is named).
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include <Windows.h>
+#include <delayimp.h>
+
+FARPROC WINAPI dll_failure_hook(unsigned dliNotify, PDelayLoadInfo pdli);
+
+
+PfnDliHook __pfnDliFailureHook2 = dll_failure_hook;
+
+FARPROC WINAPI dll_failure_hook(unsigned dliNotify, PDelayLoadInfo pdli) {
+ if (dliNotify == dliFailLoadLib) {
+ /* If the failing request was for qemu.exe, ... */
+ if (strcmp(pdli->szDll, "qemu.exe") == 0) {
+ /* Then pass back a pointer to the top level module. */
+ HMODULE top = GetModuleHandle(NULL);
+ return (FARPROC) top;
+ }
+ }
+ /* Otherwise we can't do anything special. */
+ return 0;
+}
+
diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile
index 8ba78c7a32..751fa38619 100644
--- a/contrib/plugins/Makefile
+++ b/contrib/plugins/Makefile
@@ -22,7 +22,14 @@ NAMES += hwprofile
NAMES += cache
NAMES += drcov
-SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES)))
+ifeq ($(CONFIG_WIN32),y)
+SO_SUFFIX := .dll
+LDLIBS += $(shell $(PKG_CONFIG) --libs glib-2.0)
+else
+SO_SUFFIX := .so
+endif
+
+SONAMES := $(addsuffix $(SO_SUFFIX),$(addprefix lib,$(NAMES)))
# The main QEMU uses Glib extensively so it's perfectly fine to use it
# in plugins (which many example do).
@@ -35,15 +42,20 @@ all: $(SONAMES)
%.o: %.c
$(CC) $(CFLAGS) $(PLUGIN_CFLAGS) -c -o $@ $<
-lib%.so: %.o
-ifeq ($(CONFIG_DARWIN),y)
+ifeq ($(CONFIG_WIN32),y)
+lib%$(SO_SUFFIX): %.o win32_linker.o ../../plugins/qemu_plugin_api.lib
+ $(CC) -shared -o $@ $^ $(LDLIBS)
+else ifeq ($(CONFIG_DARWIN),y)
+lib%$(SO_SUFFIX): %.o
$(CC) -bundle -Wl,-undefined,dynamic_lookup -o $@ $^ $(LDLIBS)
else
+lib%$(SO_SUFFIX): %.o
$(CC) -shared -o $@ $^ $(LDLIBS)
endif
+
clean:
- rm -f *.o *.so *.d
+ rm -f *.o *$(SO_SUFFIX) *.d
rm -Rf .libs
.PHONY: all clean
diff --git a/plugins/meson.build b/plugins/meson.build
index 71ed996ed3..8ed9fa270c 100644
--- a/plugins/meson.build
+++ b/plugins/meson.build
@@ -14,6 +14,23 @@ if not enable_modules
endif
if get_option('plugins')
+ if targetos == 'windows'
+ # Generate a .lib file for plugins to link against.
+ # First, create a .def file listing all the symbols a plugin should expect to have
+ # available in qemu
+ win32_plugin_def = configure_file(
+ input: files('qemu-plugins.symbols'),
+ output: 'qemu_plugin_api.def',
+ capture: true,
+ command: ['sed', '-e', '0,/^/s//EXPORTS/; s/[{};]//g', '@INPUT@'])
+ # then use dlltool to assemble a delaylib.
+ win32_qemu_plugin_api_lib = configure_file(
+ input: win32_plugin_def,
+ output: 'qemu_plugin_api.lib',
+ command: ['dlltool', '--input-def', '@INPUT@',
+ '--output-delaylib', '@OUTPUT@', '--dllname', 'qemu.exe']
+ )
+ endif
specific_ss.add(files(
'loader.c',
'core.c',
diff --git a/tests/plugin/meson.build b/tests/plugin/meson.build
index 322cafcdf6..528bb9d86c 100644
--- a/tests/plugin/meson.build
+++ b/tests/plugin/meson.build
@@ -1,9 +1,17 @@
t = []
if get_option('plugins')
foreach i : ['bb', 'empty', 'insn', 'mem', 'syscall']
- t += shared_module(i, files(i + '.c'),
- include_directories: '../../include/qemu',
- dependencies: glib)
+ if targetos == 'windows'
+ t += shared_module(i, files(i + '.c') + '../../contrib/plugins/win32_linker.c',
+ include_directories: '../../include/qemu',
+ objects: [win32_qemu_plugin_api_lib],
+ dependencies: glib)
+
+ else
+ t += shared_module(i, files(i + '.c'),
+ include_directories: '../../include/qemu',
+ dependencies: glib)
+ endif
endforeach
endif
if t.length() > 0
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 28/29] plugins: disable lockstep plugin on windows
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (26 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 27/29] plugins: make test/example plugins work on windows Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 29/29] plugins: allow plugins to be enabled " Alex Bennée
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Greg Manning
From: Greg Manning <gmanning@rapitasystems.com>
The lockstep plugin uses unix sockets and would require a different
communication mechanism to work on Windows.
Signed-off-by: Greg Manning <gmanning@rapitasystems.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20231102172053.17692-4-gmanning@rapitasystems.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
contrib/plugins/Makefile | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile
index 751fa38619..1783750cf6 100644
--- a/contrib/plugins/Makefile
+++ b/contrib/plugins/Makefile
@@ -17,7 +17,13 @@ NAMES += execlog
NAMES += hotblocks
NAMES += hotpages
NAMES += howvec
+
+# The lockstep example communicates using unix sockets,
+# and can't be easily made to work on windows.
+ifneq ($(CONFIG_WIN32),y)
NAMES += lockstep
+endif
+
NAMES += hwprofile
NAMES += cache
NAMES += drcov
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH 29/29] plugins: allow plugins to be enabled on windows
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
` (27 preceding siblings ...)
2023-11-03 19:59 ` [PATCH 28/29] plugins: disable lockstep plugin " Alex Bennée
@ 2023-11-03 19:59 ` Alex Bennée
28 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-03 19:59 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Alex Bennée, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik,
Greg Manning
From: Greg Manning <gmanning@rapitasystems.com>
allow plugins to be enabled in the configure script on windows. Also,
add the qemu_plugin_api.lib to the installer.
Signed-off-by: Greg Manning <gmanning@rapitasystems.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20231102172053.17692-5-gmanning@rapitasystems.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
configure | 6 ------
meson.build | 5 +++++
2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/configure b/configure
index 04f2cdd166..1129e6dd94 100755
--- a/configure
+++ b/configure
@@ -1010,12 +1010,6 @@ if test "$targetos" = "bogus"; then
fi
# test for any invalid configuration combinations
-if test "$targetos" = "windows"; then
- if test "$plugins" = "yes"; then
- error_exit "TCG plugins not currently supported on Windows platforms"
- fi
- plugins="no"
-fi
if test "$tcg" = "disabled" ; then
if test "$plugins" = "yes"; then
error_exit "Can't enable plugins on non-TCG builds"
diff --git a/meson.build b/meson.build
index dcef8b1e79..b855224acc 100644
--- a/meson.build
+++ b/meson.build
@@ -3904,6 +3904,11 @@ endforeach
if get_option('plugins')
install_headers('include/qemu/qemu-plugin.h')
+ if targetos == 'windows'
+ # On windows, we want to deliver the qemu_plugin_api.lib file in the qemu installer,
+ # so that plugin authors can compile against it.
+ install_data(win32_qemu_plugin_api_lib, install_dir: 'lib')
+ endif
endif
subdir('qga')
--
2.39.2
^ permalink raw reply related [flat|nested] 46+ messages in thread
* Re: [PATCH 27/29] plugins: make test/example plugins work on windows
2023-11-03 19:59 ` [PATCH 27/29] plugins: make test/example plugins work on windows Alex Bennée
@ 2023-11-04 9:14 ` Alex Bennée
0 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-04 9:14 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Cédric Le Goater, Paolo Bonzini,
David Hildenbrand, Brian Cain, qemu-ppc, Palmer Dabbelt,
qemu-riscv, Eduardo Habkost, Philippe Mathieu-Daudé,
Alistair Francis, Liu Zhiwei, Cleber Rosa, qemu-s390x,
Laurent Vivier, Yoshinori Sato, Nicholas Piggin, Thomas Huth,
John Snow, Alexandre Iooss, Daniel P. Berrangé,
Mahmoud Mandour, Daniel Henrique Barboza, Bin Meng, Beraldo Leal,
Richard Henderson, Michael Rolnik, Greg Manning
=?UTF-8?q?Alex=20Benn=C3=A9e?= <alex.bennee@linaro.org> writes:
> From: Greg Manning <gmanning@rapitasystems.com>
>
> Generate a qemu_plugin_api.lib delay import lib on windows, for
> windows qemu plugins to link against.
>
> Implement an example dll load fail hook to link up the API functions
> correctly when a plugin is loaded on windows.
>
> Update the build scripts for the test and example plugins to use these
> things.
>
> Signed-off-by: Greg Manning <gmanning@rapitasystems.com>
> Acked-by: Alex Benn.©e <alex.bennee@linaro.org>
> Message-Id: <20231102172053.17692-3-gmanning@rapitasystems.com>
> Signed-off-by: Alex Benn.©e <alex.bennee@linaro.org>
> ---
> configure | 3 +++
> contrib/plugins/win32_linker.c | 34 ++++++++++++++++++++++++++++++++++
> contrib/plugins/Makefile | 20 ++++++++++++++++----
> plugins/meson.build | 17 +++++++++++++++++
> tests/plugin/meson.build | 14 +++++++++++---
> 5 files changed, 81 insertions(+), 7 deletions(-)
> create mode 100644 contrib/plugins/win32_linker.c
>
>
> if get_option('plugins')
> + if targetos == 'windows'
> + # Generate a .lib file for plugins to link against.
> + # First, create a .def file listing all the symbols a plugin should expect to have
> + # available in qemu
> + win32_plugin_def = configure_file(
> + input: files('qemu-plugins.symbols'),
> + output: 'qemu_plugin_api.def',
> + capture: true,
> + command: ['sed', '-e', '0,/^/s//EXPORTS/; s/[{};]//g', '@INPUT@'])
> + # then use dlltool to assemble a delaylib.
> + win32_qemu_plugin_api_lib = configure_file(
> + input: win32_plugin_def,
> + output: 'qemu_plugin_api.lib',
> + command: ['dlltool', '--input-def', '@INPUT@',
> + '--output-delaylib', '@OUTPUT@', '--dllname',
> 'qemu.exe']
We need to ensure we have dlltool available before enabling plugins for
windows otherwise we fail here. Also we need to update the windows
images to include it.
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [PATCH 06/29] tests/tcg: add an explicit gdbstub register tester
2023-11-03 19:59 ` [PATCH 06/29] tests/tcg: add an explicit gdbstub register tester Alex Bennée
@ 2023-11-05 12:17 ` Akihiko Odaki
0 siblings, 0 replies; 46+ messages in thread
From: Akihiko Odaki @ 2023-11-05 12:17 UTC (permalink / raw)
To: Alex Bennée, qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Cédric Le Goater, Paolo Bonzini,
David Hildenbrand, Brian Cain, qemu-ppc, Palmer Dabbelt,
qemu-riscv, Eduardo Habkost, Philippe Mathieu-Daudé,
Alistair Francis, Liu Zhiwei, Cleber Rosa, qemu-s390x,
Laurent Vivier, Yoshinori Sato, Nicholas Piggin, Thomas Huth,
John Snow, Alexandre Iooss, Daniel P. Berrangé,
Mahmoud Mandour, Daniel Henrique Barboza, Bin Meng, Beraldo Leal,
Richard Henderson, Michael Rolnik, Luis Machado
On 2023/11/04 4:59, Alex Bennée wrote:
> We already do a couple of "info registers" for specific tests but this
> is a more comprehensive multiarch test. It also has some output
> helpful for debugging the gdbstub by showing which XML features are
> advertised and what the underlying register numbers are.
>
> My initial motivation was to see if there are any duplicate register
> names exposed via the gdbstub while I was reviewing the proposed
> register interface for TCG plugins.
>
> Mismatches between the xml and remote-desc are reported for debugging
> but do not fail the test.
>
> Cc: Akihiko Odaki <akihiko.odaki@daynix.com>
> Cc: Luis Machado <luis.machado@linaro.org>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> Message-Id: <20231012170426.1335442-1-alex.bennee@linaro.org>
>
> ---
> v2
> - remove python2 compat bits
> - add SPDX header, clean up comment lines
> - fix duplicate check
> - use field 6 (Rmt Nr) instead of field 1 (Nr) for cross-check
> - more useful output on finding a duplicates and missing regs
> - handle non-XML targets cleanly
> ---
> tests/tcg/multiarch/Makefile.target | 11 +-
> tests/tcg/multiarch/gdbstub/registers.py | 188 ++++++++++++++++++
> .../multiarch/system/Makefile.softmmu-target | 13 +-
> 3 files changed, 210 insertions(+), 2 deletions(-)
> create mode 100644 tests/tcg/multiarch/gdbstub/registers.py
>
> diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target
> index f3bfaf1a22..d31ba8d6ae 100644
> --- a/tests/tcg/multiarch/Makefile.target
> +++ b/tests/tcg/multiarch/Makefile.target
> @@ -93,12 +93,21 @@ run-gdbstub-thread-breakpoint: testthread
> --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
> --bin $< --test $(MULTIARCH_SRC)/gdbstub/test-thread-breakpoint.py, \
> hitting a breakpoint on non-main thread)
> +
> +run-gdbstub-registers: sha512
> + $(call run-test, $@, $(GDB_SCRIPT) \
> + --gdb $(GDB) \
> + --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
> + --bin $< --test $(MULTIARCH_SRC)/gdbstub/registers.py, \
> + checking register enumeration)
> +
> else
> run-gdbstub-%:
> $(call skip-test, "gdbstub test $*", "need working gdb with $(patsubst -%,,$(TARGET_NAME)) support")
> endif
> EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read \
> - run-gdbstub-proc-mappings run-gdbstub-thread-breakpoint
> + run-gdbstub-proc-mappings run-gdbstub-thread-breakpoint \
> + run-gdbstub-registers
>
> # ARM Compatible Semi Hosting Tests
> #
> diff --git a/tests/tcg/multiarch/gdbstub/registers.py b/tests/tcg/multiarch/gdbstub/registers.py
> new file mode 100644
> index 0000000000..2aa0c30165
> --- /dev/null
> +++ b/tests/tcg/multiarch/gdbstub/registers.py
> @@ -0,0 +1,188 @@
> +# Exercise the register functionality by exhaustively iterating
> +# through all supported registers on the system.
> +#
> +# This is launched via tests/guest-debug/run-test.py but you can also
> +# call it directly if using it for debugging/introspection:
> +#
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +
> +import gdb
> +import sys
> +import xml.etree.ElementTree as ET
> +
> +initial_vlen = 0
This seems unused.
> +failcount = 0
> +
> +def report(cond, msg):
> + "Report success/fail of test."
> + if cond:
> + print("PASS: %s" % (msg))
> + else:
> + print("FAIL: %s" % (msg))
> + global failcount
> + failcount += 1
I suggest using unittest to remove this boilerplate.
> +
> +
> +def fetch_xml_regmap():
> + """
> + Iterate through the XML descriptions and validate.
> +
> + We check for any duplicate registers and report them. Return a
> + reg_map hash containing the names, regnums and initial values of
> + all registers.
> + """
> +
> + # First check the XML descriptions we have sent. Most arches
> + # support XML but a few of the ancient ones don't in which case we
> + # need to gracefully fail.
> +
> + try:
> + xml = gdb.execute("maint print xml-tdesc", False, True)
> + except (gdb.error):
> + print("SKIP: target does not support XML")
> + return None
> +
> + total_regs = 0
> + reg_map = {}
> + frame = gdb.selected_frame()
> +
> + tree = ET.fromstring(xml)
> + for f in tree.findall("feature"):
> + name = f.attrib["name"]
> + regs = f.findall("reg")
> +
> + total = len(regs)
> + total_regs += total
> + base = int(regs[0].attrib["regnum"])
> + top = int(regs[-1].attrib["regnum"])
> +
> + print(f"feature: {name} has {total} registers from {base} to {top}")
> +
> + for r in regs:
> + name = r.attrib["name"]
> + regnum = int(r.attrib["regnum"])
> + value = frame.read_register(name).__str__()
Does it really need conversion to string?
> + entry = { "name": name, "initial": value, "regnum": regnum }
> +
> + if name in reg_map:
> + report(False, f"duplicate register {entry} vs {reg_map[name]}")
> + continue
> +
> + reg_map[name] = entry
> +
> + # Validate we match
> + report(total_regs == len(reg_map.keys()),
> + f"counted all {total_regs} registers in XML")
> +
> + return reg_map
> +
> +def crosscheck_remote_xml(reg_map):
> + """
> + Cross-check the list of remote-registers with the XML info.
> + """
> +
> + remote = gdb.execute("maint print remote-registers", False, True)
> + r_regs = remote.split("\n")
> +
> + total_regs = len(reg_map.keys())
> + total_r_regs = 0
> +
> + for r in r_regs:
> + fields = r.split()
> + # Some of the registers reported here are "pseudo" registers that
> + # gdb invents based on actual registers so we need to filter them
> + # out.
> + if len(fields) == 8:
> + r_name = fields[0]
> + r_regnum = int(fields[6])
> +
> + # check in the XML
> + try:
> + x_reg = reg_map[r_name]
> + x_reg["seen"] = True
Place x_reg["seen"] out of this try block.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [PATCH 24/29] plugins: add an API to read registers
2023-11-03 19:59 ` [PATCH 24/29] plugins: add an API to read registers Alex Bennée
@ 2023-11-05 12:40 ` Akihiko Odaki
[not found] ` <87il6fdyaq.fsf@draig.linaro.org>
0 siblings, 1 reply; 46+ messages in thread
From: Akihiko Odaki @ 2023-11-05 12:40 UTC (permalink / raw)
To: Alex Bennée, qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Cédric Le Goater, Paolo Bonzini,
David Hildenbrand, Brian Cain, qemu-ppc, Palmer Dabbelt,
qemu-riscv, Eduardo Habkost, Philippe Mathieu-Daudé,
Alistair Francis, Liu Zhiwei, Cleber Rosa, qemu-s390x,
Laurent Vivier, Yoshinori Sato, Nicholas Piggin, Thomas Huth,
John Snow, Alexandre Iooss, Daniel P. Berrangé,
Mahmoud Mandour, Daniel Henrique Barboza, Bin Meng, Beraldo Leal,
Richard Henderson, Michael Rolnik
On 2023/11/04 4:59, Alex Bennée wrote:
> We can only request a list of registers once the vCPU has been
> initialised so the user needs to use either call the find function on
> vCPU initialisation or during the translation phase. We don't expose
> the reg number to the plugin instead hiding it behind an opaque
> handle. This allows for a bit of future proofing should the internals
> need to be changed while also being hashed against the CPUClass so we
> can handle different register sets per-vCPU in hetrogenous situations.
>
> Having an internal state within the plugins also allows us to expand
> the interface in future (for example providing callbacks on register
> change if the translator can track changes).
>
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1706
> Cc: Akihiko Odaki <akihiko.odaki@daynix.com>
> Based-on: <20231025093128.33116-18-akihiko.odaki@daynix.com>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>
> ---
> vAJB:
>
> The main difference to Akikio's version is hiding the gdb register
> detail from the plugin for the reasons described above.
> ---
> include/qemu/qemu-plugin.h | 52 +++++++++++++++++-
> plugins/api.c | 102 +++++++++++++++++++++++++++++++++++
> plugins/qemu-plugins.symbols | 2 +
> 3 files changed, 154 insertions(+), 2 deletions(-)
>
> diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
> index 50a9957279..e5c16df5ca 100644
> --- a/include/qemu/qemu-plugin.h
> +++ b/include/qemu/qemu-plugin.h
> @@ -11,6 +11,7 @@
> #ifndef QEMU_QEMU_PLUGIN_H
> #define QEMU_QEMU_PLUGIN_H
>
> +#include <glib.h>
> #include <inttypes.h>
> #include <stdbool.h>
> #include <stddef.h>
> @@ -218,8 +219,8 @@ struct qemu_plugin_insn;
> * @QEMU_PLUGIN_CB_R_REGS: callback reads the CPU's regs
> * @QEMU_PLUGIN_CB_RW_REGS: callback reads and writes the CPU's regs
> *
> - * Note: currently unused, plugins cannot read or change system
> - * register state.
> + * Note: currently QEMU_PLUGIN_CB_RW_REGS is unused, plugins cannot change
> + * system register state.
> */
> enum qemu_plugin_cb_flags {
> QEMU_PLUGIN_CB_NO_REGS,
> @@ -664,4 +665,51 @@ uint64_t qemu_plugin_end_code(void);
> */
> uint64_t qemu_plugin_entry_code(void);
>
> +/** struct qemu_plugin_register - Opaque handle for a translated instruction */
> +struct qemu_plugin_register;
> +
> +/**
> + * typedef qemu_plugin_reg_descriptor - register descriptions
> + *
> + * @name: register name
> + * @handle: opaque handle for retrieving value with qemu_plugin_read_register
> + * @feature: optional feature descriptor, can be NULL
> + */
> +typedef struct {
> + char name[32];
> + struct qemu_plugin_register *handle;
> + const char *feature;
> +} qemu_plugin_reg_descriptor;
> +
> +/**
> + * qemu_plugin_find_registers() - return register list
> + * @vcpu_index: vcpu to query
> + * @reg_pattern: register name pattern
> + *
> + * Returns a GArray of qemu_plugin_reg_descriptor or NULL. Caller
> + * frees. As the register set of a given vCPU is only available once
> + * the vCPU is initialised if you want to monitor registers from the
> + * start you should call this from a qemu_plugin_register_vcpu_init_cb()
> + * callback.
> + */
> +GArray * qemu_plugin_find_registers(unsigned int vcpu_index, const char *reg_pattern);
A pattern may be convenient for humans but not for machine. My
motivation to introduce the feature is to generate traces consumable by
trace-based simulators. Such a plugin needs an exact match of registers.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [PATCH 02/29] gdb-xml: fix duplicate register in arm-neon.xml
2023-11-03 19:59 ` [PATCH 02/29] gdb-xml: fix duplicate register in arm-neon.xml Alex Bennée
@ 2023-11-05 20:45 ` Richard Henderson
0 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2023-11-05 20:45 UTC (permalink / raw)
To: Alex Bennée, qemu-devel
On 11/3/23 12:59, Alex Bennée wrote:
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
> gdb-xml/arm-neon.xml | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/gdb-xml/arm-neon.xml b/gdb-xml/arm-neon.xml
> index 9dce0a996f..d61f6b8549 100644
> --- a/gdb-xml/arm-neon.xml
> +++ b/gdb-xml/arm-neon.xml
> @@ -76,7 +76,7 @@
> <reg name="q8" bitsize="128" type="neon_q"/>
> <reg name="q9" bitsize="128" type="neon_q"/>
> <reg name="q10" bitsize="128" type="neon_q"/>
> - <reg name="q10" bitsize="128" type="neon_q"/>
> + <reg name="q11" bitsize="128" type="neon_q"/>
> <reg name="q12" bitsize="128" type="neon_q"/>
> <reg name="q13" bitsize="128" type="neon_q"/>
> <reg name="q14" bitsize="128" type="neon_q"/>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [PATCH 01/29] default-configs: Add TARGET_XML_FILES definition
2023-11-03 19:59 ` [PATCH 01/29] default-configs: Add TARGET_XML_FILES definition Alex Bennée
@ 2023-11-05 20:55 ` Richard Henderson
2023-11-06 15:44 ` Alex Bennée
0 siblings, 1 reply; 46+ messages in thread
From: Richard Henderson @ 2023-11-05 20:55 UTC (permalink / raw)
To: Alex Bennée, qemu-devel; +Cc: Song Gao
On 11/3/23 12:59, Alex Bennée wrote:
> From: Akihiko Odaki <akihiko.odaki@daynix.com>
>
> loongarch64-linux-user has references to XML files so include them.
>
> Fixes: d32688ecdb ("default-configs: Add loongarch linux-user support")
> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> Message-Id: <20231030054834.39145-6-akihiko.odaki@daynix.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
> ---
> configs/targets/loongarch64-linux-user.mak | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/configs/targets/loongarch64-linux-user.mak b/configs/targets/loongarch64-linux-user.mak
> index 7d1b964020..43b8a2160f 100644
> --- a/configs/targets/loongarch64-linux-user.mak
> +++ b/configs/targets/loongarch64-linux-user.mak
> @@ -1,3 +1,4 @@
> # Default configuration for loongarch64-linux-user
> TARGET_ARCH=loongarch64
> TARGET_BASE_ARCH=loongarch
> +TARGET_XML_FILES=gdb-xml/loongarch-base32.xml gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml
The qemu-loongarch64 binary emulates loongarch64 only, not loongarch32. The inclusion of
loongarch-base32.xml here is not relevant.
That said, we don't exclude TYPE_LOONGARCH32_CPU or -cpu la132 from CONFIG_USER_ONLY,
which is a separate mistake.
r~
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [PATCH 13/29] target/riscv: Use GDBFeature for dynamic XML
2023-11-03 19:59 ` [PATCH 13/29] target/riscv: " Alex Bennée
@ 2023-11-06 9:32 ` Alex Bennée
2023-11-06 15:35 ` Alex Bennée
0 siblings, 1 reply; 46+ messages in thread
From: Alex Bennée @ 2023-11-06 9:32 UTC (permalink / raw)
To: qemu-devel, Akihiko Odaki
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Cédric Le Goater, Paolo Bonzini,
David Hildenbrand, Brian Cain, qemu-ppc, Palmer Dabbelt,
qemu-riscv, Eduardo Habkost, Philippe Mathieu-Daudé,
Alistair Francis, Liu Zhiwei, Cleber Rosa, qemu-s390x,
Laurent Vivier, Yoshinori Sato, Nicholas Piggin, Thomas Huth,
John Snow, Alexandre Iooss, Daniel P. Berrangé,
Mahmoud Mandour, Daniel Henrique Barboza, Bin Meng, Beraldo Leal,
Richard Henderson, Michael Rolnik, Akihiko Odaki
Alex Bennée <alex.bennee@linaro.org> writes:
> From: Akihiko Odaki <akihiko.odaki@daynix.com>
>
> In preparation for a change to use GDBFeature as a parameter of
> gdb_register_coprocessor(), convert the internal representation of
> dynamic feature from plain XML to GDBFeature.
>
> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> Message-Id: <20231025093128.33116-7-akihiko.odaki@daynix.com>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
I bisected the following failure:
./qemu-riscv64 -g 1234 ./tests/tcg/riscv64-linux-user/sha512
and:
gdb-multiarch ./tests/tcg/riscv64-linux-user/sha512 -ex "target remote localhost:1234" -x ../../tests/tcg/multiarch/gdbstub/registers.py
gives:
warning: Architecture rejected target-supplied description
Ignoring packet error, continuing...
Ignoring packet error, continuing...
Ignoring packet error, continuing...
Ignoring packet error, continuing...
> ---
> target/riscv/cpu.h | 5 +--
> target/riscv/cpu.c | 4 +--
> target/riscv/gdbstub.c | 79 +++++++++++++++++++-----------------------
> 3 files changed, 40 insertions(+), 48 deletions(-)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index f8ffa5ee38..73ec1d3b79 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -24,6 +24,7 @@
> #include "hw/registerfields.h"
> #include "hw/qdev-properties.h"
> #include "exec/cpu-defs.h"
> +#include "exec/gdbstub.h"
> #include "qemu/cpu-float.h"
> #include "qom/object.h"
> #include "qemu/int128.h"
> @@ -395,8 +396,8 @@ struct ArchCPU {
>
> CPURISCVState env;
>
> - char *dyn_csr_xml;
> - char *dyn_vreg_xml;
> + GDBFeature dyn_csr_feature;
> + GDBFeature dyn_vreg_feature;
>
> /* Configuration Settings */
> RISCVCPUConfig cfg;
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index ac4a6c7eec..5200fba9b9 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -1421,9 +1421,9 @@ static const char *riscv_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
> RISCVCPU *cpu = RISCV_CPU(cs);
>
> if (strcmp(xmlname, "riscv-csr.xml") == 0) {
> - return cpu->dyn_csr_xml;
> + return cpu->dyn_csr_feature.xml;
> } else if (strcmp(xmlname, "riscv-vector.xml") == 0) {
> - return cpu->dyn_vreg_xml;
> + return cpu->dyn_vreg_feature.xml;
> }
>
> return NULL;
> diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
> index 524bede865..a3ac0212d1 100644
> --- a/target/riscv/gdbstub.c
> +++ b/target/riscv/gdbstub.c
> @@ -212,12 +212,13 @@ static int riscv_gdb_set_virtual(CPURISCVState *cs, uint8_t *mem_buf, int n)
> return 0;
> }
>
> -static int riscv_gen_dynamic_csr_xml(CPUState *cs, int base_reg)
> +static GDBFeature *riscv_gen_dynamic_csr_feature(CPUState *cs, int base_reg)
> {
> RISCVCPU *cpu = RISCV_CPU(cs);
> CPURISCVState *env = &cpu->env;
> - GString *s = g_string_new(NULL);
> + GDBFeatureBuilder builder;
> riscv_csr_predicate_fn predicate;
> + const char *name;
> int bitsize = 16 << env->misa_mxl_max;
> int i;
>
> @@ -230,9 +231,9 @@ static int riscv_gen_dynamic_csr_xml(CPUState *cs, int base_reg)
> bitsize = 64;
> }
>
> - g_string_printf(s, "<?xml version=\"1.0\"?>");
> - g_string_append_printf(s, "<!DOCTYPE feature SYSTEM \"gdb-target.dtd\">");
> - g_string_append_printf(s, "<feature name=\"org.gnu.gdb.riscv.csr\">");
> + gdb_feature_builder_init(&builder, &cpu->dyn_csr_feature,
> + "org.gnu.gdb.riscv.csr", "riscv-csr.xml",
> + base_reg);
>
> for (i = 0; i < CSR_TABLE_SIZE; i++) {
> if (env->priv_ver < csr_ops[i].min_priv_ver) {
> @@ -240,72 +241,64 @@ static int riscv_gen_dynamic_csr_xml(CPUState *cs, int base_reg)
> }
> predicate = csr_ops[i].predicate;
> if (predicate && (predicate(env, i) == RISCV_EXCP_NONE)) {
> - if (csr_ops[i].name) {
> - g_string_append_printf(s, "<reg name=\"%s\"", csr_ops[i].name);
> - } else {
> - g_string_append_printf(s, "<reg name=\"csr%03x\"", i);
> + g_autofree char *dynamic_name = NULL;
> + name = csr_ops[i].name;
> + if (!name) {
> + dynamic_name = g_strdup_printf("csr%03x", i);
> + name = dynamic_name;
> }
> - g_string_append_printf(s, " bitsize=\"%d\"", bitsize);
> - g_string_append_printf(s, " regnum=\"%d\"/>", base_reg + i);
> +
> + gdb_feature_builder_append_reg(&builder, name, bitsize, i,
> + "int", NULL);
> }
> }
>
> - g_string_append_printf(s, "</feature>");
> -
> - cpu->dyn_csr_xml = g_string_free(s, false);
> + gdb_feature_builder_end(&builder);
>
> #if !defined(CONFIG_USER_ONLY)
> env->debugger = false;
> #endif
>
> - return CSR_TABLE_SIZE;
> + return &cpu->dyn_csr_feature;
> }
>
> -static int ricsv_gen_dynamic_vector_xml(CPUState *cs, int base_reg)
> +static GDBFeature *ricsv_gen_dynamic_vector_feature(CPUState *cs, int base_reg)
> {
> RISCVCPU *cpu = RISCV_CPU(cs);
> - GString *s = g_string_new(NULL);
> - g_autoptr(GString) ts = g_string_new("");
> + GDBFeatureBuilder builder;
> int reg_width = cpu->cfg.vlen;
> - int num_regs = 0;
> int i;
>
> - 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.riscv.vector\">");
> + gdb_feature_builder_init(&builder, &cpu->dyn_vreg_feature,
> + "org.gnu.gdb.riscv.vector", "riscv-vector.xml",
> + base_reg);
>
> /* 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, "%s", vec_lanes[i].id);
> - g_string_append_printf(s,
> - "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>",
> - ts->str, vec_lanes[i].gdb_type, count);
> + gdb_feature_builder_append_tag(
> + &builder, "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>",
> + vec_lanes[i].id, vec_lanes[i].gdb_type, count);
> }
>
> /* Define unions */
> - g_string_append_printf(s, "<union id=\"riscv_vector\">");
> + gdb_feature_builder_append_tag(&builder, "<union id=\"riscv_vector\">");
> for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
> - g_string_append_printf(s, "<field name=\"%c\" type=\"%s\"/>",
> - vec_lanes[i].suffix,
> - vec_lanes[i].id);
> + gdb_feature_builder_append_tag(&builder,
> + "<field name=\"%c\" type=\"%s\"/>",
> + vec_lanes[i].suffix, vec_lanes[i].id);
> }
> - g_string_append(s, "</union>");
> + gdb_feature_builder_append_tag(&builder, "</union>");
>
> /* Define vector registers */
> for (i = 0; i < 32; i++) {
> - g_string_append_printf(s,
> - "<reg name=\"v%d\" bitsize=\"%d\""
> - " regnum=\"%d\" group=\"vector\""
> - " type=\"riscv_vector\"/>",
> - i, reg_width, base_reg++);
> - num_regs++;
> + gdb_feature_builder_append_reg(&builder, g_strdup_printf("v%d", i),
> + reg_width, i, "riscv_vector", "vector");
> }
>
> - g_string_append_printf(s, "</feature>");
> + gdb_feature_builder_end(&builder);
>
> - cpu->dyn_vreg_xml = g_string_free(s, false);
> - return num_regs;
> + return &cpu->dyn_vreg_feature;
> }
>
> void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
> @@ -320,10 +313,9 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
> 32, "riscv-32bit-fpu.xml", 0);
> }
> if (env->misa_ext & RVV) {
> - int base_reg = cs->gdb_num_regs;
> gdb_register_coprocessor(cs, riscv_gdb_get_vector,
> riscv_gdb_set_vector,
> - ricsv_gen_dynamic_vector_xml(cs, base_reg),
> + ricsv_gen_dynamic_vector_feature(cs, cs->gdb_num_regs)->num_regs,
> "riscv-vector.xml", 0);
> }
> switch (env->misa_mxl_max) {
> @@ -343,9 +335,8 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
> }
>
> if (cpu->cfg.ext_icsr) {
> - int base_reg = cs->gdb_num_regs;
> gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
> - riscv_gen_dynamic_csr_xml(cs, base_reg),
> + riscv_gen_dynamic_csr_feature(cs, cs->gdb_num_regs)->num_regs,
> "riscv-csr.xml", 0);
> }
> }
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [PATCH 24/29] plugins: add an API to read registers
[not found] ` <333fbdf6-9f5b-41c3-99ce-8808c542d485@daynix.com>
@ 2023-11-06 11:40 ` Alex Bennée
2023-11-07 6:56 ` Akihiko Odaki
0 siblings, 1 reply; 46+ messages in thread
From: Alex Bennée @ 2023-11-06 11:40 UTC (permalink / raw)
To: Akihiko Odaki; +Cc: QEMU Developers
Akihiko Odaki <akihiko.odaki@daynix.com> writes:
(re-adding qemu-devel which my mail client dropped a few messages ago, sorry)
> On 2023/11/06 19:46, Alex Bennée wrote:
>> Akihiko Odaki <akihiko.odaki@daynix.com> writes:
>>
>>> On 2023/11/06 18:30, Alex Bennée wrote:
>>>> Akihiko Odaki <akihiko.odaki@daynix.com> writes:
>>>>
>>>>> On 2023/11/04 4:59, Alex Bennée wrote:
>>>>>> We can only request a list of registers once the vCPU has been
>>>>>> initialised so the user needs to use either call the find function on
>>>>>> vCPU initialisation or during the translation phase. We don't expose
>>>>>> the reg number to the plugin instead hiding it behind an opaque
>>>>>> handle. This allows for a bit of future proofing should the internals
>>>>>> need to be changed while also being hashed against the CPUClass so we
>>>>>> can handle different register sets per-vCPU in hetrogenous situations.
>>>>>> Having an internal state within the plugins also allows us to expand
>>>>>> the interface in future (for example providing callbacks on register
>>>>>> change if the translator can track changes).
>>>>>> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1706
>>>>>> Cc: Akihiko Odaki <akihiko.odaki@daynix.com>
>>>>>> Based-on: <20231025093128.33116-18-akihiko.odaki@daynix.com>
>>>>>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>>>>>> +struct qemu_plugin_register;
>>>>>> +
>>>>>> +/**
>>>>>> + * typedef qemu_plugin_reg_descriptor - register descriptions
>>>>>> + *
>>>>>> + * @name: register name
>>>>>> + * @handle: opaque handle for retrieving value with qemu_plugin_read_register
>>>>>> + * @feature: optional feature descriptor, can be NULL
>>>>>> + */
>>>>>> +typedef struct {
>>>>>> + char name[32];
>>>>>> + struct qemu_plugin_register *handle;
>>>>>> + const char *feature;
>>>>>> +} qemu_plugin_reg_descriptor;
>>>>>> +
>>>>>> +/**
>>>>>> + * qemu_plugin_find_registers() - return register list
>>>>>> + * @vcpu_index: vcpu to query
>>>>>> + * @reg_pattern: register name pattern
>>>>>> + *
>>>>>> + * Returns a GArray of qemu_plugin_reg_descriptor or NULL. Caller
>>>>>> + * frees. As the register set of a given vCPU is only available once
>>>>>> + * the vCPU is initialised if you want to monitor registers from the
>>>>>> + * start you should call this from a qemu_plugin_register_vcpu_init_cb()
>>>>>> + * callback.
>>>>>> + */
>>>>>> +GArray * qemu_plugin_find_registers(unsigned int vcpu_index, const char *reg_pattern);
>>>>>
>>>>> A pattern may be convenient for humans but not for machine. My
>>>>> motivation to introduce the feature is to generate traces consumable
>>>>> by trace-based simulators. Such a plugin needs an exact match of
>>>>> registers.
>>>> That's true - but we don't have any such users in the code base.
>>>> However
>>>> for exact matches the details are in qemu_plugin_reg_descriptor so you
>>>> can always filter there if you want.
>>>
>>> I designed the feature to read registers for users outside of the code
>>> base so the code base has no practical user.
>>> I added the feature to log register values to execlog but it's only
>>> for demonstration and it is useless for practical use;
>> I wouldn't say its useless - and it is important to have in-tree
>> code to
>> exercise the various parts of the API we expose.
>
> I mean it is useless except for demonstration. Having some code for
> demonstration is good but we shouldn't overfit the API to it.
>
>> To be clear is your objection just to the way
>> qemu_plugin_find_registers() works or the whole concept of using a
>> handle instead of the register number? I'm certainly open to better ways
>> of doing the former but as explained in the commit I think the handle
>> based approach is a more hygienic interface that gives us scope to
>> improve it going forward.
>
> Yes, my major concern is that the pattern matching.
OK. Another potential consumer I thought about during implementing the
internal API was HMP which would also benefit from a more human wildcard
type search. So I think the resolution of this is having two APIs, one
returning a list of qemu_plugin_reg_descriptor and one returning a
single descriptor only with an exact match.
I thought exposing features and registers in two calls was a bit clunky
though so how about:
struct qemu_plugin_reg_descriptor *
qemu_plugin_find_register(unsigned int vcpu_index,
const char *name,
const char *gdb_feature);
which will only reply on an exact match (although I still think
register names are unique enough you can get away without gdb_feature).
> I'm fine with the use of a pointer instead of the register number. A
> pointer is indeed more random for each run so it will prevent the user
> from hardcoding it.
>
>> As we are so close to soft-freeze I suggest I re-spin the series to
>> include 1-12/29 and the windows bits and we can work on a better API for
>> the 9.0 release.
>
> I'm not in haste either and fine to delay it for the 9.0 release.
OK I'll get as much as I can merged now and leave the final API bits for
when the tree opens up. I don't suppose you have any idea why:
target/riscv: Use GDBFeature for dynamic XML
caused a regression? The XML generated looks identical but the
communication diverges with the riscv-csr response:
gdbstub_io_command Received: qXfer:features:read:riscv-csr.xm gdbstub_io_command Received: qXfer:features:read:riscv-csr.xm
gdbstub_io_binaryreply 0x0000: 6c 3c 3f 78 6d 6c 20 76 65 7 gdbstub_io_binaryreply 0x0000: 6c 3c 3f 78 6d 6c 20 76 65 7
gdbstub_io_binaryreply 0x0010: 31 2e 30 22 3f 3e 3c 21 44 4 gdbstub_io_binaryreply 0x0010: 31 2e 30 22 3f 3e 3c 21 44 4
gdbstub_io_binaryreply 0x0020: 66 65 61 74 75 72 65 20 53 5 gdbstub_io_binaryreply 0x0020: 66 65 61 74 75 72 65 20 53 5
gdbstub_io_binaryreply 0x0030: 67 64 62 2d 74 61 72 67 65 7 gdbstub_io_binaryreply 0x0030: 67 64 62 2d 74 61 72 67 65 7
gdbstub_io_binaryreply 0x0040: 3c 66 65 61 74 75 72 65 20 6 gdbstub_io_binaryreply 0x0040: 3c 66 65 61 74 75 72 65 20 6
gdbstub_io_binaryreply 0x0050: 72 67 2e 67 6e 75 2e 67 64 6 gdbstub_io_binaryreply 0x0050: 72 67 2e 67 6e 75 2e 67 64 6
gdbstub_io_binaryreply 0x0060: 2e 63 73 72 22 3e 3c 72 65 6 gdbstub_io_binaryreply 0x0060: 2e 63 73 72 22 3e 3c 72 65 6
gdbstub_io_binaryreply 0x0070: 22 66 66 6c 61 67 73 22 20 6 gdbstub_io_binaryreply 0x0070: 22 66 66 6c 61 67 73 22 20 6
gdbstub_io_binaryreply 0x0080: 3d 22 36 34 22 20 72 65 67 6 gdbstub_io_binaryreply 0x0080: 3d 22 36 34 22 20 72 65 67 6
gdbstub_io_binaryreply 0x0090: 22 2f 3e 3c 72 65 67 20 6e 6 | gdbstub_io_binaryreply 0x0090: 22 20 74 79 70 65 3d 22 69 6
gdbstub_io_binaryreply 0x00a0: 6d 22 20 62 69 74 73 69 7a 6 | gdbstub_io_binaryreply 0x00a0: 65 67 20 6e 61 6d 65 3d 22 6
gdbstub_io_binaryreply 0x00b0: 72 65 67 6e 75 6d 3d 22 36 3 | gdbstub_io_binaryreply 0x00b0: 74 73 69 7a 65 3d 22 36 34 2
gdbstub_io_binaryreply 0x00c0: 67 20 6e 61 6d 65 3d 22 66 6 | gdbstub_io_binaryreply 0x00c0: 6d 3d 22 36 38 22 20 74 79 7
gdbstub_io_binaryreply 0x00d0: 74 73 69 7a 65 3d 22 36 34 2 | gdbstub_io_binaryreply 0x00d0: 22 2f 3e 3c 72 65 67 20 6e 6
gdbstub_io_binaryreply 0x00e0: 6d 3d 22 36 39 22 2f 3e 3c 7 | gdbstub_io_binaryreply 0x00e0: 73 72 22 20 62 69 74 73 69 7
gdbstub_io_binaryreply 0x00f0: 65 3d 22 63 79 63 6c 65 22 2 | gdbstub_io_binaryreply 0x00f0: 20 72 65 67 6e 75 6d 3d 22 3
gdbstub_io_binaryreply 0x0100: 65 3d 22 36 34 22 20 72 65 6 | gdbstub_io_binaryreply 0x0100: 65 3d 22 69 6e 74 22 2f 3e 3
gdbstub_io_binaryreply 0x0110: 31 33 38 22 2f 3e 3c 72 65 6 | gdbstub_io_binaryreply 0x0110: 6d 65 3d 22 63 79 63 6c 65 2
gdbstub_io_binaryreply 0x0120: 22 74 69 6d 65 22 20 62 69 7 | gdbstub_io_binaryreply 0x0120: 7a 65 3d 22 36 34 22 20 72 6
gdbstub_io_binaryreply 0x0130: 36 34 22 20 72 65 67 6e 75 6 | gdbstub_io_binaryreply 0x0130: 33 31 33 38 22 20 74 79 70 6
gdbstub_io_binaryreply 0x0140: 22 2f 3e 3c 72 65 67 20 6e 6 | gdbstub_io_binaryreply 0x0140: 2f 3e 3c 72 65 67 20 6e 61 6
gdbstub_io_binaryreply 0x0150: 73 74 72 65 74 22 20 62 69 7 | gdbstub_io_binaryreply 0x0150: 65 22 20 62 69 74 73 69 7a 6
gdbstub_io_binaryreply 0x0160: 36 34 22 20 72 65 67 6e 75 6 | gdbstub_io_binaryreply 0x0160: 72 65 67 6e 75 6d 3d 22 33 3
gdbstub_io_binaryreply 0x0170: 22 2f 3e 3c 2f 66 65 61 74 7 | gdbstub_io_binaryreply 0x0170: 70 65 3d 22 69 6e 74 22 2f 3
> gdbstub_io_binaryreply 0x0180: 61 6d 65 3d 22 69 6e 73 74 7
> gdbstub_io_binaryreply 0x0190: 74 73 69 7a 65 3d 22 36 34 2
> gdbstub_io_binaryreply 0x01a0: 6d 3d 22 33 31 34 30 22 20 7
> gdbstub_io_binaryreply 0x01b0: 6e 74 22 2f 3e 3c 2f 66 65 6
gdbstub_io_command Received: qTStatus gdbstub_io_command Received: qTStatus
gdbstub_io_reply Sent: gdbstub_io_reply Sent:
gdbstub_io_command Received: ? gdbstub_io_command Received: ?
gdbstub_io_reply Sent: T05thread:p2003b4.2003b4; | gdbstub_io_reply Sent: T05thread:p2011b6.2011b6;
Was this the reason for the misa_max cleanups?
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [PATCH 25/29] contrib/plugins: extend execlog to track register changes
2023-11-03 19:59 ` [PATCH 25/29] contrib/plugins: extend execlog to track register changes Alex Bennée
@ 2023-11-06 15:30 ` Alex Bennée
0 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-06 15:30 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Cédric Le Goater, Paolo Bonzini,
David Hildenbrand, Brian Cain, qemu-ppc, Palmer Dabbelt,
qemu-riscv, Eduardo Habkost, Philippe Mathieu-Daudé,
Alistair Francis, Liu Zhiwei, Cleber Rosa, qemu-s390x,
Laurent Vivier, Yoshinori Sato, Nicholas Piggin, Thomas Huth,
John Snow, Alexandre Iooss, Daniel P. Berrangé,
Mahmoud Mandour, Daniel Henrique Barboza, Bin Meng, Beraldo Leal,
Richard Henderson, Michael Rolnik, Akihiko Odaki
Alex Bennée <alex.bennee@linaro.org> writes:
> With the new plugin register API we can now track changes to register
> values. Currently the implementation is fairly dumb which will slow
> down if a large number of register values are being tracked. This
> could be improved by only instrumenting instructions which mention
> registers we are interested in tracking.
>
> Example usage:
>
> ./qemu-aarch64 -D plugin.log -d plugin \
> -cpu max,sve256=on \
> -plugin contrib/plugins/libexeclog.so,reg=sp,reg=z\* \
> ./tests/tcg/aarch64-linux-user/sha512-sve
>
> will display in the execlog any changes to the stack pointer (sp) and
> the SVE Z registers.
>
> Cc: Akihiko Odaki <akihiko.odaki@daynix.com>
> Based-On: <20231025093128.33116-19-akihiko.odaki@daynix.com>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>
> ---
> vAJB:
>
> Changes for the new API with a simpler glob based "reg" specifier
> which can be specified multiple times.
> +/*
> + * Initialise a new vcpu/thread with:
> + * - last_exec tracking data
> + * - list of tracked registers
> + * - initial value of registers
> + *
> + * As we could have multiple threads trying to do this we need to
> + * serialise the expansion under a lock.
> + */
> +static void vcpu_init(qemu_plugin_id_t id, unsigned int vcpu_index)
> +{
> + g_rw_lock_writer_lock(&expand_array_lock);
> +
> + if (vcpu_index >= num_cpus) {
> + cpus = g_realloc_n(cpus, vcpu_index + 1, sizeof(*cpus));
> + while (vcpu_index >= num_cpus) {
> + cpus[num_cpus].last_exec = g_string_new(NULL);
> +
> + /* Any registers to track? */
> + if (rmatches && rmatches->len) {
> + GPtrArray *registers = g_ptr_array_new();
> +
> + /* For each pattern add the register definitions */
> + for (int p = 0; p < rmatches->len; p++) {
> + g_autoptr(GArray) reg_list =
> + qemu_plugin_find_registers(vcpu_index, rmatches->pdata[p]);
> + if (reg_list && reg_list->len) {
> + for (int r = 0; r < reg_list->len; r++) {
> + Register *reg =
> + init_vcpu_register(vcpu_index,
> + &g_array_index(reg_list,
> + qemu_plugin_reg_descriptor, r));
> + g_ptr_array_add(registers, reg);
> + }
> + }
> + }
> + cpus[num_cpus].registers = registers;
Note to self:
modified contrib/plugins/execlog.c
@@ -250,6 +250,8 @@ static void vcpu_init(qemu_plugin_id_t id, unsigned int vcpu_index)
}
}
cpus[num_cpus].registers = registers;
+ } else {
+ cpus[num_cpus].registers = NULL;
}
num_cpus++;
}
> + }
> + num_cpus++;
> + }
> + }
> +
> + g_rw_lock_writer_unlock(&expand_array_lock);
> +}
> +
> /**
> * On plugin exit, print last instruction in cache
> */
> static void plugin_exit(qemu_plugin_id_t id, void *p)
> {
> guint i;
> - GString *s;
> - for (i = 0; i < last_exec->len; i++) {
> - s = g_ptr_array_index(last_exec, i);
> - if (s->str) {
> - qemu_plugin_outs(s->str);
> + for (i = 0; i < num_cpus; i++) {
> + if (cpus[i].last_exec->str) {
> + qemu_plugin_outs(cpus[i].last_exec->str);
> qemu_plugin_outs("\n");
> }
> }
> @@ -212,6 +291,18 @@ static void parse_vaddr_match(char *match)
> g_array_append_val(amatches, v);
> }
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [PATCH 13/29] target/riscv: Use GDBFeature for dynamic XML
2023-11-06 9:32 ` Alex Bennée
@ 2023-11-06 15:35 ` Alex Bennée
0 siblings, 0 replies; 46+ messages in thread
From: Alex Bennée @ 2023-11-06 15:35 UTC (permalink / raw)
To: qemu-devel
Cc: Akihiko Odaki, Peter Maydell, Edgar E. Iglesias, Song Gao,
qemu-arm, Marc-André Lureau, Wainer dos Santos Moschetta,
Weiwei Li, Marcel Apfelbaum, Ilya Leoshkevich,
Daniel Henrique Barboza, Yanan Wang, Cédric Le Goater,
Paolo Bonzini, David Hildenbrand, Brian Cain, qemu-ppc,
Palmer Dabbelt, qemu-riscv, Eduardo Habkost,
Philippe Mathieu-Daudé, Alistair Francis, Liu Zhiwei,
Cleber Rosa, qemu-s390x, Laurent Vivier, Yoshinori Sato,
Nicholas Piggin, Thomas Huth, John Snow, Alexandre Iooss,
Daniel P. Berrangé, Mahmoud Mandour, Daniel Henrique Barboza,
Bin Meng, Beraldo Leal, Richard Henderson, Michael Rolnik
Alex Bennée <alex.bennee@linaro.org> writes:
> Alex Bennée <alex.bennee@linaro.org> writes:
>
>> From: Akihiko Odaki <akihiko.odaki@daynix.com>
>>
>> In preparation for a change to use GDBFeature as a parameter of
>> gdb_register_coprocessor(), convert the internal representation of
>> dynamic feature from plain XML to GDBFeature.
>>
>> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
>> Message-Id: <20231025093128.33116-7-akihiko.odaki@daynix.com>
>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>
> I bisected the following failure:
>
> ./qemu-riscv64 -g 1234 ./tests/tcg/riscv64-linux-user/sha512
>
> and:
>
> gdb-multiarch ./tests/tcg/riscv64-linux-user/sha512 -ex "target remote localhost:1234" -x ../../tests/tcg/multiarch/gdbstub/registers.py
>
> gives:
>
> warning: Architecture rejected target-supplied description
> Ignoring packet error, continuing...
> Ignoring packet error, continuing...
> Ignoring packet error, continuing...
> Ignoring packet error, continuing...
I don't know if the discontinuous register numbering could be the
problem:
<feature name="org.gnu.gdb.riscv.csr">
<reg name="fflags" bitsize="64" type="int" regnum="67"/>
<reg name="frm" bitsize="64" type="int" regnum="68"/>
<reg name="fcsr" bitsize="64" type="int" regnum="69"/>
<reg name="cycle" bitsize="64" type="int" regnum="3138"/>
<reg name="time" bitsize="64" type="int" regnum="3139"/>
<reg name="instret" bitsize="64" type="int" regnum="3140"/>
</feature>
?
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [PATCH 01/29] default-configs: Add TARGET_XML_FILES definition
2023-11-05 20:55 ` Richard Henderson
@ 2023-11-06 15:44 ` Alex Bennée
2023-11-06 23:22 ` Richard Henderson
0 siblings, 1 reply; 46+ messages in thread
From: Alex Bennée @ 2023-11-06 15:44 UTC (permalink / raw)
To: Richard Henderson; +Cc: qemu-devel, Song Gao
Richard Henderson <richard.henderson@linaro.org> writes:
> On 11/3/23 12:59, Alex Bennée wrote:
>> From: Akihiko Odaki <akihiko.odaki@daynix.com>
>> loongarch64-linux-user has references to XML files so include them.
>> Fixes: d32688ecdb ("default-configs: Add loongarch linux-user
>> support")
>> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
>> Message-Id: <20231030054834.39145-6-akihiko.odaki@daynix.com>
>> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
>> ---
>> configs/targets/loongarch64-linux-user.mak | 1 +
>> 1 file changed, 1 insertion(+)
>> diff --git a/configs/targets/loongarch64-linux-user.mak
>> b/configs/targets/loongarch64-linux-user.mak
>> index 7d1b964020..43b8a2160f 100644
>> --- a/configs/targets/loongarch64-linux-user.mak
>> +++ b/configs/targets/loongarch64-linux-user.mak
>> @@ -1,3 +1,4 @@
>> # Default configuration for loongarch64-linux-user
>> TARGET_ARCH=loongarch64
>> TARGET_BASE_ARCH=loongarch
>> +TARGET_XML_FILES=gdb-xml/loongarch-base32.xml gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml
>
>
> The qemu-loongarch64 binary emulates loongarch64 only, not
> loongarch32. The inclusion of loongarch-base32.xml here is not
> relevant.
Does the system binary emulate both?
> That said, we don't exclude TYPE_LOONGARCH32_CPU or -cpu la132 from
> CONFIG_USER_ONLY, which is a separate mistake.
Where should that be done?
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [PATCH 01/29] default-configs: Add TARGET_XML_FILES definition
2023-11-06 15:44 ` Alex Bennée
@ 2023-11-06 23:22 ` Richard Henderson
0 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2023-11-06 23:22 UTC (permalink / raw)
To: Alex Bennée; +Cc: qemu-devel, Song Gao
On 11/6/23 07:44, Alex Bennée wrote:
>>> +TARGET_XML_FILES=gdb-xml/loongarch-base32.xml gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml
>>
>>
>> The qemu-loongarch64 binary emulates loongarch64 only, not
>> loongarch32. The inclusion of loongarch-base32.xml here is not
>> relevant.
>
> Does the system binary emulate both?
Yes.
Technically, the user-only binary will emulate the 32-bit cpu just fine. But much like
aarch64, there is no ilp32 kernel abi for loongarch.
>> That said, we don't exclude TYPE_LOONGARCH32_CPU or -cpu la132 from
>> CONFIG_USER_ONLY, which is a separate mistake.
>
> Where should that be done?
Probably target/loongarch/cpu.c, by omitting TYPE_LOONGARCH32_CPU and "la132".
r~
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [PATCH 23/29] plugins: Use different helpers when reading registers
2023-11-03 19:59 ` [PATCH 23/29] plugins: Use different helpers when reading registers Alex Bennée
@ 2023-11-07 3:13 ` Richard Henderson
0 siblings, 0 replies; 46+ messages in thread
From: Richard Henderson @ 2023-11-07 3:13 UTC (permalink / raw)
To: Alex Bennée, qemu-devel
On 11/3/23 12:59, Alex Bennée wrote:
> --- a/plugins/api.c
> +++ b/plugins/api.c
> @@ -89,7 +89,11 @@ void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
> void *udata)
> {
> if (!tb->mem_only) {
> - plugin_register_dyn_cb__udata(&tb->cbs[PLUGIN_CB_REGULAR],
> + int index = flags == QEMU_PLUGIN_CB_R_REGS ||
> + flags == QEMU_PLUGIN_CB_RW_REGS ?
> + PLUGIN_CB_REGULAR_R : PLUGIN_CB_REGULAR;
> +
I'd really rather you reject QEMU_PLUGIN_CB_RW_REGS entirely, rather than implement it
with incorrect semantics.
Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> + plugin_register_dyn_cb__udata(&tb->cbs[index],
> cb, flags, udata);
> }
> }
> @@ -109,7 +113,11 @@ void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
> void *udata)
> {
> if (!insn->mem_only) {
> - plugin_register_dyn_cb__udata(&insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR],
> + int index = flags == QEMU_PLUGIN_CB_R_REGS ||
> + flags == QEMU_PLUGIN_CB_RW_REGS ?
> + PLUGIN_CB_REGULAR_R : PLUGIN_CB_REGULAR;
> +
> + plugin_register_dyn_cb__udata(&insn->cbs[PLUGIN_CB_INSN][index],
> cb, flags, udata);
> }
> }
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [PATCH 24/29] plugins: add an API to read registers
2023-11-06 11:40 ` Alex Bennée
@ 2023-11-07 6:56 ` Akihiko Odaki
0 siblings, 0 replies; 46+ messages in thread
From: Akihiko Odaki @ 2023-11-07 6:56 UTC (permalink / raw)
To: Alex Bennée; +Cc: QEMU Developers
On 2023/11/06 20:40, Alex Bennée wrote:
> Akihiko Odaki <akihiko.odaki@daynix.com> writes:
>
> (re-adding qemu-devel which my mail client dropped a few messages ago, sorry)
>
>> On 2023/11/06 19:46, Alex Bennée wrote:
>>> Akihiko Odaki <akihiko.odaki@daynix.com> writes:
>>>
>>>> On 2023/11/06 18:30, Alex Bennée wrote:
>>>>> Akihiko Odaki <akihiko.odaki@daynix.com> writes:
>>>>>
>>>>>> On 2023/11/04 4:59, Alex Bennée wrote:
>>>>>>> We can only request a list of registers once the vCPU has been
>>>>>>> initialised so the user needs to use either call the find function on
>>>>>>> vCPU initialisation or during the translation phase. We don't expose
>>>>>>> the reg number to the plugin instead hiding it behind an opaque
>>>>>>> handle. This allows for a bit of future proofing should the internals
>>>>>>> need to be changed while also being hashed against the CPUClass so we
>>>>>>> can handle different register sets per-vCPU in hetrogenous situations.
>>>>>>> Having an internal state within the plugins also allows us to expand
>>>>>>> the interface in future (for example providing callbacks on register
>>>>>>> change if the translator can track changes).
>>>>>>> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1706
>>>>>>> Cc: Akihiko Odaki <akihiko.odaki@daynix.com>
>>>>>>> Based-on: <20231025093128.33116-18-akihiko.odaki@daynix.com>
>>>>>>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>>>>>>> +struct qemu_plugin_register;
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * typedef qemu_plugin_reg_descriptor - register descriptions
>>>>>>> + *
>>>>>>> + * @name: register name
>>>>>>> + * @handle: opaque handle for retrieving value with qemu_plugin_read_register
>>>>>>> + * @feature: optional feature descriptor, can be NULL
>>>>>>> + */
>>>>>>> +typedef struct {
>>>>>>> + char name[32];
>>>>>>> + struct qemu_plugin_register *handle;
>>>>>>> + const char *feature;
>>>>>>> +} qemu_plugin_reg_descriptor;
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * qemu_plugin_find_registers() - return register list
>>>>>>> + * @vcpu_index: vcpu to query
>>>>>>> + * @reg_pattern: register name pattern
>>>>>>> + *
>>>>>>> + * Returns a GArray of qemu_plugin_reg_descriptor or NULL. Caller
>>>>>>> + * frees. As the register set of a given vCPU is only available once
>>>>>>> + * the vCPU is initialised if you want to monitor registers from the
>>>>>>> + * start you should call this from a qemu_plugin_register_vcpu_init_cb()
>>>>>>> + * callback.
>>>>>>> + */
>>>>>>> +GArray * qemu_plugin_find_registers(unsigned int vcpu_index, const char *reg_pattern);
>>>>>>
>>>>>> A pattern may be convenient for humans but not for machine. My
>>>>>> motivation to introduce the feature is to generate traces consumable
>>>>>> by trace-based simulators. Such a plugin needs an exact match of
>>>>>> registers.
>>>>> That's true - but we don't have any such users in the code base.
>>>>> However
>>>>> for exact matches the details are in qemu_plugin_reg_descriptor so you
>>>>> can always filter there if you want.
>>>>
>>>> I designed the feature to read registers for users outside of the code
>>>> base so the code base has no practical user.
>>>> I added the feature to log register values to execlog but it's only
>>>> for demonstration and it is useless for practical use;
>>> I wouldn't say its useless - and it is important to have in-tree
>>> code to
>>> exercise the various parts of the API we expose.
>>
>> I mean it is useless except for demonstration. Having some code for
>> demonstration is good but we shouldn't overfit the API to it.
>>
>>> To be clear is your objection just to the way
>>> qemu_plugin_find_registers() works or the whole concept of using a
>>> handle instead of the register number? I'm certainly open to better ways
>>> of doing the former but as explained in the commit I think the handle
>>> based approach is a more hygienic interface that gives us scope to
>>> improve it going forward.
>>
>> Yes, my major concern is that the pattern matching.
>
> OK. Another potential consumer I thought about during implementing the
> internal API was HMP which would also benefit from a more human wildcard
> type search. So I think the resolution of this is having two APIs, one
> returning a list of qemu_plugin_reg_descriptor and one returning a
> single descriptor only with an exact match.
I don't think qemu_plugin_find_registers() is so versetile that it
should be a public API. What is appropriate as a user interface depends
more on the context.
For HMP, it may be better to implement command completion instead of
having a wildcard. Some may want regular expressions instead of GLib
patterns. Some may want POSIX-compliant glob instead of GLib-specific
pattern match (the quirks of GLib pattern is documented at
https://gitlab.gnome.org/GNOME/glib/-/blob/2.78.1/glib/gpattern.c#L33).
I think it's better to expose an array of register names and let the
plugin do the pattern match in a way appropriate for the specific use case.
>
> I thought exposing features and registers in two calls was a bit clunky
> though so how about:
>
> struct qemu_plugin_reg_descriptor *
> qemu_plugin_find_register(unsigned int vcpu_index,
> const char *name,
> const char *gdb_feature);
>
> which will only reply on an exact match (although I still think
> register names are unique enough you can get away without gdb_feature).
>
>> I'm fine with the use of a pointer instead of the register number. A
>> pointer is indeed more random for each run so it will prevent the user
>> from hardcoding it.
>>
>>> As we are so close to soft-freeze I suggest I re-spin the series to
>>> include 1-12/29 and the windows bits and we can work on a better API for
>>> the 9.0 release.
>>
>> I'm not in haste either and fine to delay it for the 9.0 release.
>
> OK I'll get as much as I can merged now and leave the final API bits for
> when the tree opens up. I don't suppose you have any idea why:
>
> target/riscv: Use GDBFeature for dynamic XML
>
> caused a regression? The XML generated looks identical but the
> communication diverges with the riscv-csr response:
>
> gdbstub_io_command Received: qXfer:features:read:riscv-csr.xm gdbstub_io_command Received: qXfer:features:read:riscv-csr.xm
> gdbstub_io_binaryreply 0x0000: 6c 3c 3f 78 6d 6c 20 76 65 7 gdbstub_io_binaryreply 0x0000: 6c 3c 3f 78 6d 6c 20 76 65 7
> gdbstub_io_binaryreply 0x0010: 31 2e 30 22 3f 3e 3c 21 44 4 gdbstub_io_binaryreply 0x0010: 31 2e 30 22 3f 3e 3c 21 44 4
> gdbstub_io_binaryreply 0x0020: 66 65 61 74 75 72 65 20 53 5 gdbstub_io_binaryreply 0x0020: 66 65 61 74 75 72 65 20 53 5
> gdbstub_io_binaryreply 0x0030: 67 64 62 2d 74 61 72 67 65 7 gdbstub_io_binaryreply 0x0030: 67 64 62 2d 74 61 72 67 65 7
> gdbstub_io_binaryreply 0x0040: 3c 66 65 61 74 75 72 65 20 6 gdbstub_io_binaryreply 0x0040: 3c 66 65 61 74 75 72 65 20 6
> gdbstub_io_binaryreply 0x0050: 72 67 2e 67 6e 75 2e 67 64 6 gdbstub_io_binaryreply 0x0050: 72 67 2e 67 6e 75 2e 67 64 6
> gdbstub_io_binaryreply 0x0060: 2e 63 73 72 22 3e 3c 72 65 6 gdbstub_io_binaryreply 0x0060: 2e 63 73 72 22 3e 3c 72 65 6
> gdbstub_io_binaryreply 0x0070: 22 66 66 6c 61 67 73 22 20 6 gdbstub_io_binaryreply 0x0070: 22 66 66 6c 61 67 73 22 20 6
> gdbstub_io_binaryreply 0x0080: 3d 22 36 34 22 20 72 65 67 6 gdbstub_io_binaryreply 0x0080: 3d 22 36 34 22 20 72 65 67 6
> gdbstub_io_binaryreply 0x0090: 22 2f 3e 3c 72 65 67 20 6e 6 | gdbstub_io_binaryreply 0x0090: 22 20 74 79 70 65 3d 22 69 6
> gdbstub_io_binaryreply 0x00a0: 6d 22 20 62 69 74 73 69 7a 6 | gdbstub_io_binaryreply 0x00a0: 65 67 20 6e 61 6d 65 3d 22 6
> gdbstub_io_binaryreply 0x00b0: 72 65 67 6e 75 6d 3d 22 36 3 | gdbstub_io_binaryreply 0x00b0: 74 73 69 7a 65 3d 22 36 34 2
> gdbstub_io_binaryreply 0x00c0: 67 20 6e 61 6d 65 3d 22 66 6 | gdbstub_io_binaryreply 0x00c0: 6d 3d 22 36 38 22 20 74 79 7
> gdbstub_io_binaryreply 0x00d0: 74 73 69 7a 65 3d 22 36 34 2 | gdbstub_io_binaryreply 0x00d0: 22 2f 3e 3c 72 65 67 20 6e 6
> gdbstub_io_binaryreply 0x00e0: 6d 3d 22 36 39 22 2f 3e 3c 7 | gdbstub_io_binaryreply 0x00e0: 73 72 22 20 62 69 74 73 69 7
> gdbstub_io_binaryreply 0x00f0: 65 3d 22 63 79 63 6c 65 22 2 | gdbstub_io_binaryreply 0x00f0: 20 72 65 67 6e 75 6d 3d 22 3
> gdbstub_io_binaryreply 0x0100: 65 3d 22 36 34 22 20 72 65 6 | gdbstub_io_binaryreply 0x0100: 65 3d 22 69 6e 74 22 2f 3e 3
> gdbstub_io_binaryreply 0x0110: 31 33 38 22 2f 3e 3c 72 65 6 | gdbstub_io_binaryreply 0x0110: 6d 65 3d 22 63 79 63 6c 65 2
> gdbstub_io_binaryreply 0x0120: 22 74 69 6d 65 22 20 62 69 7 | gdbstub_io_binaryreply 0x0120: 7a 65 3d 22 36 34 22 20 72 6
> gdbstub_io_binaryreply 0x0130: 36 34 22 20 72 65 67 6e 75 6 | gdbstub_io_binaryreply 0x0130: 33 31 33 38 22 20 74 79 70 6
> gdbstub_io_binaryreply 0x0140: 22 2f 3e 3c 72 65 67 20 6e 6 | gdbstub_io_binaryreply 0x0140: 2f 3e 3c 72 65 67 20 6e 61 6
> gdbstub_io_binaryreply 0x0150: 73 74 72 65 74 22 20 62 69 7 | gdbstub_io_binaryreply 0x0150: 65 22 20 62 69 74 73 69 7a 6
> gdbstub_io_binaryreply 0x0160: 36 34 22 20 72 65 67 6e 75 6 | gdbstub_io_binaryreply 0x0160: 72 65 67 6e 75 6d 3d 22 33 3
> gdbstub_io_binaryreply 0x0170: 22 2f 3e 3c 2f 66 65 61 74 7 | gdbstub_io_binaryreply 0x0170: 70 65 3d 22 69 6e 74 22 2f 3
> > gdbstub_io_binaryreply 0x0180: 61 6d 65 3d 22 69 6e 73 74 7
> > gdbstub_io_binaryreply 0x0190: 74 73 69 7a 65 3d 22 36 34 2
> > gdbstub_io_binaryreply 0x01a0: 6d 3d 22 33 31 34 30 22 20 7
> > gdbstub_io_binaryreply 0x01b0: 6e 74 22 2f 3e 3c 2f 66 65 6
> gdbstub_io_command Received: qTStatus gdbstub_io_command Received: qTStatus
> gdbstub_io_reply Sent: gdbstub_io_reply Sent:
> gdbstub_io_command Received: ? gdbstub_io_command Received: ?
> gdbstub_io_reply Sent: T05thread:p2003b4.2003b4; | gdbstub_io_reply Sent: T05thread:p2011b6.2011b6;
>
> Was this the reason for the misa_max cleanups?
The misa_max cleanups are needed for "gdbstub: Simplify XML lookup", not
for "target/riscv: Use GDBFeature for dynamic XML".
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [PATCH 17/29] gdbstub: Simplify XML lookup
2023-11-03 19:59 ` [PATCH 17/29] gdbstub: Simplify XML lookup Alex Bennée
@ 2023-11-07 8:46 ` Frédéric Pétrot
2023-11-07 10:31 ` Alex Bennée
0 siblings, 1 reply; 46+ messages in thread
From: Frédéric Pétrot @ 2023-11-07 8:46 UTC (permalink / raw)
To: Alex Bennée, qemu-devel
Cc: Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Cédric Le Goater, Paolo Bonzini,
David Hildenbrand, Brian Cain, qemu-ppc, Palmer Dabbelt,
qemu-riscv, Eduardo Habkost, Philippe Mathieu-Daudé,
Alistair Francis, Liu Zhiwei, Cleber Rosa, qemu-s390x,
Laurent Vivier, Yoshinori Sato, Nicholas Piggin, Thomas Huth,
John Snow, Alexandre Iooss, Daniel P. Berrangé,
Mahmoud Mandour, Daniel Henrique Barboza, Bin Meng, Beraldo Leal,
Richard Henderson, Michael Rolnik, Akihiko Odaki
Hello Alex and Akihiko,
this patch introduces a regression for riscv.
When connecting to gdb, gdb issues the infamous "Architecture rejected
target-supplied description" warning.
As this patch touches "common" QEMU files (not riscv ones that I am
a bit more familiar with and am able to test), I will probably not
be able to come out with a proper patch, so I leave it to you guys.
Fixing this might also fix an other issue with selecting registers on
QEMU command line when using Alex "new" execlog: for riscv there is no
match on the general purpose registers that are given in
gdb-xml/riscv-64bit-cpu.xml.
And by the way thanks for this very useful feature!
Frédéric
Le 03/11/2023 à 20:59, Alex Bennée a écrit :
> From: Akihiko Odaki <akihiko.odaki@daynix.com>
>
> 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: <20231025093128.33116-11-akihiko.odaki@daynix.com>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
> include/exec/gdbstub.h | 6 +++
> gdbstub/gdbstub.c | 118 +++++++++++++++++++++--------------------
> hw/core/cpu-common.c | 5 +-
> 3 files changed, 69 insertions(+), 60 deletions(-)
>
> diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
> index bcaab1bc75..82a8afa237 100644
> --- a/include/exec/gdbstub.h
> +++ b/include/exec/gdbstub.h
> @@ -27,6 +27,12 @@ typedef struct GDBFeatureBuilder {
> 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);
>
> +/**
> + * 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
> * @cpu - the CPU associated with registers
> diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
> index 4809c90c4a..5ecd1f23e6 100644
> --- a/gdbstub/gdbstub.c
> +++ b/gdbstub/gdbstub.c
> @@ -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);
> CPUClass *cc = CPU_GET_CLASS(cpu);
> + GDBRegisterState *r;
> 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? */
> if (strncmp(p, "target.xml", len) == 0) {
> if (!process->target_xml) {
> - GDBRegisterState *r;
> g_autoptr(GPtrArray) xml = g_ptr_array_new_with_free_func(g_free);
>
> 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>",
> cc->gdb_arch_name(cpu)));
> }
> - g_ptr_array_add(
> - xml,
> - g_markup_printf_escaped("<xi:include href=\"%s\"/>",
> - cc->gdb_core_xml_file));
> - if (cpu->gdb_regs) {
> - for (guint i = 0; i < cpu->gdb_regs->len; i++) {
> - 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));
> - }
> + for (guint i = 0; i < cpu->gdb_regs->len; i++) {
> + 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, NULL);
> @@ -400,20 +394,11 @@ static const char *get_feature_xml(const char *p, const char **newp,
> }
> return process->target_xml;
> }
> - /* Is it dynamically generated by the target? */
> - if (cc->gdb_get_dynamic_xml) {
> - g_autofree char *xmlname = g_strndup(p, len);
> - const char *xml = cc->gdb_get_dynamic_xml(cpu, xmlname);
> - if (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;
> + /* 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 (strncmp(p, r->feature->xmlname, len) == 0) {
> + return r->feature->xml;
> }
> }
>
> @@ -508,12 +493,10 @@ static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
> return cc->gdb_read_register(cpu, buf, reg);
> }
>
> - if (cpu->gdb_regs) {
> - for (guint i = 0; i < cpu->gdb_regs->len; i++) {
> - r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
> - if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
> - return r->get_reg(cpu, buf, reg - r->base_reg);
> - }
> + for (guint i = 0; i < cpu->gdb_regs->len; i++) {
> + r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
> + if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
> + return r->get_reg(cpu, buf, reg - r->base_reg);
> }
> }
> 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);
> }
>
> - if (cpu->gdb_regs) {
> - for (guint i = 0; i < cpu->gdb_regs->len; i++) {
> - r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
> - if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
> - return r->set_reg(cpu, mem_buf, reg - r->base_reg);
> - }
> + for (guint i = 0; i < cpu->gdb_regs->len; i++) {
> + r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
> + 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 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,
> gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
> const GDBFeature *feature, int g_pos)
> {
> GDBRegisterState *s;
> guint i;
> + int base_reg = cpu->gdb_num_regs;
>
> - if (cpu->gdb_regs) {
> - for (i = 0; i < cpu->gdb_regs->len; i++) {
> - /* Check for duplicates. */
> - s = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
> - if (s->feature == feature) {
> - return;
> - }
> + for (i = 0; i < cpu->gdb_regs->len; i++) {
> + /* Check for duplicates. */
> + s = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
> + if (s->feature == feature) {
> + return;
> }
> - } else {
> - cpu->gdb_regs = g_array_new(false, false, sizeof(GDBRegisterState));
> - i = 0;
> }
>
> - g_array_set_size(cpu->gdb_regs, i + 1);
> - 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;
> + gdb_register_feature(cpu, base_reg, get_reg, set_reg, feature);
>
> /* Add to end of list. */
> cpu->gdb_num_regs += feature->num_regs;
> if (g_pos) {
> - if (g_pos != s->base_reg) {
> + if (g_pos != base_reg) {
> error_report("Error: Bad gdb register numbering for '%s', "
> - "expected %d got %d", feature->xml,
> - g_pos, s->base_reg);
> + "expected %d got %d", feature->xml, g_pos, base_reg);
> } else {
> cpu->gdb_num_g_regs = cpu->gdb_num_regs;
> }
> diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c
> index bab8942c30..2a2a6eb3eb 100644
> --- a/hw/core/cpu-common.c
> +++ b/hw/core/cpu-common.c
> @@ -27,6 +27,7 @@
> #include "qemu/main-loop.h"
> #include "exec/log.h"
> #include "exec/cpu-common.h"
> +#include "exec/gdbstub.h"
> #include "qemu/error-report.h"
> #include "qemu/qemu-print.h"
> #include "sysemu/tcg.h"
> @@ -223,11 +224,10 @@ static void cpu_common_unrealizefn(DeviceState *dev)
> static void cpu_common_initfn(Object *obj)
> {
> CPUState *cpu = CPU(obj);
> - CPUClass *cc = CPU_GET_CLASS(obj);
>
> + gdb_init_cpu(cpu);
> cpu->cpu_index = UNASSIGNED_CPU_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 */
> /* the default value is changed by qemu_init_vcpu() for system-mode */
> cpu->nr_cores = 1;
> @@ -247,6 +247,7 @@ static void cpu_common_finalize(Object *obj)
> {
> CPUState *cpu = CPU(obj);
>
> + g_array_free(cpu->gdb_regs, TRUE);
> qemu_lockcnt_destroy(&cpu->in_ioctl_lock);
> qemu_mutex_destroy(&cpu->work_mutex);
> }
--
+---------------------------------------------------------------------------+
| Frédéric Pétrot, Pr. Grenoble INP-Ensimag/TIMA |
| Mob/Pho: +33 6 74 57 99 65/+33 4 76 57 48 70 Ad augusta per angusta |
| http://tima.univ-grenoble-alpes.fr frederic.petrot@univ-grenoble-alpes.fr |
+---------------------------------------------------------------------------+
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [PATCH 17/29] gdbstub: Simplify XML lookup
2023-11-07 8:46 ` Frédéric Pétrot
@ 2023-11-07 10:31 ` Alex Bennée
2023-11-07 11:46 ` Frédéric Pétrot
0 siblings, 1 reply; 46+ messages in thread
From: Alex Bennée @ 2023-11-07 10:31 UTC (permalink / raw)
To: Frédéric Pétrot
Cc: qemu-devel, Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Cédric Le Goater, Paolo Bonzini,
David Hildenbrand, Brian Cain, qemu-ppc, Palmer Dabbelt,
qemu-riscv, Eduardo Habkost, Philippe Mathieu-Daudé,
Alistair Francis, Liu Zhiwei, Cleber Rosa, qemu-s390x,
Laurent Vivier, Yoshinori Sato, Nicholas Piggin, Thomas Huth,
John Snow, Alexandre Iooss, Daniel P. Berrangé,
Mahmoud Mandour, Daniel Henrique Barboza, Bin Meng, Beraldo Leal,
Richard Henderson, Michael Rolnik, Akihiko Odaki
Frédéric Pétrot <frederic.petrot@univ-grenoble-alpes.fr> writes:
> Hello Alex and Akihiko,
>
> this patch introduces a regression for riscv.
> When connecting to gdb, gdb issues the infamous "Architecture rejected
> target-supplied description" warning.
I tracked it down to 13/29 when bisecting which I dropped from:
Message-Id: <20231106185112.2755262-1-alex.bennee@linaro.org>
Date: Mon, 6 Nov 2023 18:50:50 +0000
Subject: [PATCH 00/22] Maintainer updates for 8.2 (gdbstub, tests, plugins) pre-PR
From: =?UTF-8?q?Alex=20Benn=C3=A9e?= <alex.bennee@linaro.org>
So if you can check that series doesn't regress RiscV (it passes the
tests) then we can at least get some of the stuff merged during freeze.
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [PATCH 17/29] gdbstub: Simplify XML lookup
2023-11-07 10:31 ` Alex Bennée
@ 2023-11-07 11:46 ` Frédéric Pétrot
0 siblings, 0 replies; 46+ messages in thread
From: Frédéric Pétrot @ 2023-11-07 11:46 UTC (permalink / raw)
To: Alex Bennée
Cc: qemu-devel, Peter Maydell, Edgar E. Iglesias, Song Gao, qemu-arm,
Marc-André Lureau, Wainer dos Santos Moschetta, Weiwei Li,
Marcel Apfelbaum, Ilya Leoshkevich, Daniel Henrique Barboza,
Yanan Wang, Cédric Le Goater, Paolo Bonzini,
David Hildenbrand, Brian Cain, qemu-ppc, Palmer Dabbelt,
qemu-riscv, Eduardo Habkost, Philippe Mathieu-Daudé,
Alistair Francis, Liu Zhiwei, Cleber Rosa, qemu-s390x,
Laurent Vivier, Yoshinori Sato, Nicholas Piggin, Thomas Huth,
John Snow, Alexandre Iooss, Daniel P. Berrangé,
Mahmoud Mandour, Daniel Henrique Barboza, Bin Meng, Beraldo Leal,
Richard Henderson, Michael Rolnik, Akihiko Odaki
Le 07/11/2023 à 11:31, Alex Bennée a écrit :
> Frédéric Pétrot <frederic.petrot@univ-grenoble-alpes.fr> writes:
>
>> Hello Alex and Akihiko,
>>
>> this patch introduces a regression for riscv.
>> When connecting to gdb, gdb issues the infamous "Architecture rejected
>> target-supplied description" warning.
>
> I tracked it down to 13/29 when bisecting which I dropped from:
>
> Message-Id: <20231106185112.2755262-1-alex.bennee@linaro.org>
> Date: Mon, 6 Nov 2023 18:50:50 +0000
> Subject: [PATCH 00/22] Maintainer updates for 8.2 (gdbstub, tests, plugins) pre-PR
> From: =?UTF-8?q?Alex=20Benn=C3=A9e?= <alex.bennee@linaro.org>
>
> So if you can check that series doesn't regress RiscV (it passes the
> tests) then we can at least get some of the stuff merged during freeze.
I do confirm that this fixes the issue with gdb, thanks !
--
+---------------------------------------------------------------------------+
| Frédéric Pétrot, Pr. Grenoble INP-Ensimag/TIMA |
| Mob/Pho: +33 6 74 57 99 65/+33 4 76 57 48 70 Ad augusta per angusta |
| http://tima.univ-grenoble-alpes.fr frederic.petrot@univ-grenoble-alpes.fr |
+---------------------------------------------------------------------------+
^ permalink raw reply [flat|nested] 46+ messages in thread
end of thread, other threads:[~2023-11-07 11:45 UTC | newest]
Thread overview: 46+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-11-03 19:59 [PATCH 00/29] gdbstub and plugin read register and windows support Alex Bennée
2023-11-03 19:59 ` [PATCH 01/29] default-configs: Add TARGET_XML_FILES definition Alex Bennée
2023-11-05 20:55 ` Richard Henderson
2023-11-06 15:44 ` Alex Bennée
2023-11-06 23:22 ` Richard Henderson
2023-11-03 19:59 ` [PATCH 02/29] gdb-xml: fix duplicate register in arm-neon.xml Alex Bennée
2023-11-05 20:45 ` Richard Henderson
2023-11-03 19:59 ` [PATCH 03/29] target/arm: hide the 32bit version of PAR from gdbstub Alex Bennée
2023-11-03 19:59 ` [PATCH 04/29] target/arm: hide all versions of DBGD[RS]AR " Alex Bennée
2023-11-03 19:59 ` [PATCH 05/29] target/arm: hide aliased MIDR " Alex Bennée
2023-11-03 19:59 ` [PATCH 06/29] tests/tcg: add an explicit gdbstub register tester Alex Bennée
2023-11-05 12:17 ` Akihiko Odaki
2023-11-03 19:59 ` [PATCH 07/29] tests/avocado: update the tcg_plugins test Alex Bennée
2023-11-03 19:59 ` [PATCH 08/29] gdbstub: Add num_regs member to GDBFeature Alex Bennée
2023-11-03 19:59 ` [PATCH 09/29] gdbstub: Introduce gdb_find_static_feature() Alex Bennée
2023-11-03 19:59 ` [PATCH 10/29] gdbstub: Introduce GDBFeatureBuilder Alex Bennée
2023-11-03 19:59 ` [PATCH 11/29] target/arm: Use GDBFeature for dynamic XML Alex Bennée
2023-11-03 19:59 ` [PATCH 12/29] target/ppc: " Alex Bennée
2023-11-03 19:59 ` [PATCH 13/29] target/riscv: " Alex Bennée
2023-11-06 9:32 ` Alex Bennée
2023-11-06 15:35 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 14/29] gdbstub: Use GDBFeature for gdb_register_coprocessor Alex Bennée
2023-11-03 19:59 ` [PATCH 15/29] gdbstub: Use GDBFeature for GDBRegisterState Alex Bennée
2023-11-03 19:59 ` [PATCH 16/29] gdbstub: Change gdb_get_reg_cb and gdb_set_reg_cb Alex Bennée
2023-11-03 19:59 ` [PATCH 17/29] gdbstub: Simplify XML lookup Alex Bennée
2023-11-07 8:46 ` Frédéric Pétrot
2023-11-07 10:31 ` Alex Bennée
2023-11-07 11:46 ` Frédéric Pétrot
2023-11-03 19:59 ` [PATCH 18/29] gdbstub: Infer number of core registers from XML Alex Bennée
2023-11-03 19:59 ` [PATCH 19/29] hw/core/cpu: Remove gdb_get_dynamic_xml member Alex Bennée
2023-11-03 19:59 ` [PATCH 20/29] gdbstub: Add members to identify registers to GDBFeature Alex Bennée
2023-11-03 19:59 ` [PATCH 21/29] gdbstub: expose api to find registers Alex Bennée
2023-11-03 19:59 ` [PATCH 22/29] cpu: Call plugin hooks only when ready Alex Bennée
2023-11-03 19:59 ` [PATCH 23/29] plugins: Use different helpers when reading registers Alex Bennée
2023-11-07 3:13 ` Richard Henderson
2023-11-03 19:59 ` [PATCH 24/29] plugins: add an API to read registers Alex Bennée
2023-11-05 12:40 ` Akihiko Odaki
[not found] ` <87il6fdyaq.fsf@draig.linaro.org>
[not found] ` <94da2184-2586-458e-9362-fa913ca68fb5@daynix.com>
[not found] ` <874jhzdur3.fsf@draig.linaro.org>
[not found] ` <333fbdf6-9f5b-41c3-99ce-8808c542d485@daynix.com>
2023-11-06 11:40 ` Alex Bennée
2023-11-07 6:56 ` Akihiko Odaki
2023-11-03 19:59 ` [PATCH 25/29] contrib/plugins: extend execlog to track register changes Alex Bennée
2023-11-06 15:30 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 26/29] plugins: add dllexport and dllimport to api funcs Alex Bennée
2023-11-03 19:59 ` [PATCH 27/29] plugins: make test/example plugins work on windows Alex Bennée
2023-11-04 9:14 ` Alex Bennée
2023-11-03 19:59 ` [PATCH 28/29] plugins: disable lockstep plugin " Alex Bennée
2023-11-03 19:59 ` [PATCH 29/29] plugins: allow plugins to be enabled " Alex Bennée
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).