* [PATCH RESEND v5 00/26] plugins: Allow to read registers
@ 2023-08-18 3:36 Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 01/26] contrib/plugins: Use GRWLock in execlog Akihiko Odaki
` (25 more replies)
0 siblings, 26 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki
I and other people in the University of Tokyo, where I research processor
design, found TCG plugins are very useful for processor design exploration.
The feature we find missing is the capability to read registers from
plugins. In this series, I propose to add such a capability by reusing
gdbstub code.
The reuse of gdbstub code ensures the long-term stability of the TCG plugin
interface for register access without incurring a burden to maintain yet
another interface for register access.
This process to add TCG plugin involves four major changes. The first one
is to add GDBFeature structure that represents a GDB feature, which usually
includes registers. GDBFeature can be generated from static XML files or
dynamically generated by architecture-specific code. In fact, this is a
refactoring independent of the feature this series adds, and potentially
it's benefitial even without the plugin feature. The plugin feature will
utilize this new structure to describe registers exposed to plugins.
The second one is to make gdb_read_register/gdb_write_register usable
outside of gdbstub context.
The third one is to actually make registers readable for plugins.
The last one is to allow to implement a QEMU plugin in C++. A plugin that
I'll describe later is written in C++.
The below is a summary of patches:
Patch 01 fixes a bug in execlog plugin.
Patch [02, 16] introduce GDBFeature.
Patch 17 adds information useful for plugins to GDBFeature.
Patch [18, 21] make registers readable outside of gdbstub context.
Patch [22, 24] add the feature to read registers from plugins.
Patch [25, 26] make it possible to write plugins in C++.
The execlog plugin will have new options to demonstrate the new feature.
I also have a plugin that uses this new feature to generate execution
traces for Sniper processor simulator, which is available at:
https://github.com/shioya-lab/sniper/tree/akihikodaki/bb
V4 -> V5:
Corrected g_rw_lock_writer_lock() call. (Richard Henderson)
Replaced abort() with g_assert_not_reached(). (Richard Henderson)
Fixed CSR name leak in target/riscv. (Richard Henderson)
Removed gdb_has_xml variable.
V3 -> V4:
Added execlog changes I forgot to include in the last version.
V2 -> V3:
Added patch "hw/core/cpu: Return static value with gdb_arch_name()".
Added patch "gdbstub: Dynamically allocate target.xml buffer".
(Alex Bennée)
Added patch "gdbstub: Introduce GDBFeatureBuilder". (Alex Bennée)
Dropped Reviewed-by tags for "target/*: Use GDBFeature for dynamic XML".
Changed gdb_find_static_feature() to abort on failure. (Alex Bennée)
Changed the execlog plugin to log the register value only when changed.
(Alex Bennée)
Dropped 0x prefixes for register value logs for conciseness.
V1 -> V2:
Added SPDX-License-Identifier: GPL-2.0-or-later. (Philippe Mathieu-Daudé)
Split long lines. (Philippe Mathieu-Daudé)
Renamed gdb_features to gdb_static_features (Philippe Mathieu-Daudé)
Dropped RFC.
Akihiko Odaki (26):
contrib/plugins: Use GRWLock in execlog
gdbstub: Introduce GDBFeature structure
gdbstub: Add num_regs member to GDBFeature
gdbstub: Introduce gdb_find_static_feature()
target/arm: Move the reference to arm-core.xml
hw/core/cpu: Replace gdb_core_xml_file with gdb_core_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
hw/core/cpu: Return static value with gdb_arch_name()
gdbstub: Dynamically allocate target.xml buffer
gdbstub: Simplify XML lookup
hw/core/cpu: Remove gdb_get_dynamic_xml member
gdbstub: Add members to identify registers to GDBFeature
target/arm: Remove references to gdb_has_xml
target/ppc: Remove references to gdb_has_xml
gdbstub: Remove gdb_has_xml variable
gdbstub: Expose functions to read registers
cpu: Call plugin hooks only when ready
plugins: Allow to read registers
contrib/plugins: Allow to log registers
plugins: Support C++
contrib/plugins: Add cc plugin
MAINTAINERS | 2 +-
docs/devel/tcg-plugins.rst | 18 +++-
configure | 15 ++-
meson.build | 2 +-
gdbstub/internals.h | 2 +-
include/exec/gdbstub.h | 51 +++++++--
include/hw/core/cpu.h | 11 +-
include/qemu/qemu-plugin.h | 69 +++++++++++-
target/arm/cpu.h | 26 ++---
target/arm/internals.h | 2 +-
target/ppc/cpu-qom.h | 3 +-
target/ppc/cpu.h | 3 +-
target/ppc/internal.h | 2 +-
target/riscv/cpu.h | 4 +-
target/s390x/cpu.h | 2 -
contrib/plugins/execlog.c | 150 ++++++++++++++++++++------
cpu.c | 11 --
gdbstub/gdbstub.c | 198 +++++++++++++++++++++++-----------
gdbstub/softmmu.c | 3 +-
gdbstub/user.c | 1 -
hw/core/cpu-common.c | 10 ++
plugins/api.c | 40 +++++++
stubs/gdbstub.c | 6 +-
target/arm/cpu.c | 12 +--
target/arm/cpu64.c | 8 +-
target/arm/gdbstub.c | 202 +++++++++++++----------------------
target/arm/gdbstub64.c | 90 +++++++---------
target/arm/tcg/cpu32.c | 3 +-
target/avr/cpu.c | 4 +-
target/hexagon/cpu.c | 5 +-
target/i386/cpu.c | 13 ++-
target/loongarch/cpu.c | 8 +-
target/loongarch/gdbstub.c | 2 +-
target/m68k/cpu.c | 7 +-
target/m68k/helper.c | 6 +-
target/microblaze/cpu.c | 9 +-
target/ppc/cpu_init.c | 9 +-
target/ppc/gdbstub.c | 80 ++++----------
target/riscv/cpu.c | 27 ++---
target/riscv/gdbstub.c | 89 +++++++--------
target/rx/cpu.c | 4 +-
target/s390x/cpu.c | 8 +-
target/s390x/gdbstub.c | 28 ++---
target/tricore/cpu.c | 4 +-
contrib/plugins/Makefile | 5 +
contrib/plugins/cc.cc | 17 +++
plugins/qemu-plugins.symbols | 2 +
scripts/feature_to_c.py | 102 ++++++++++++++++++
scripts/feature_to_c.sh | 69 ------------
tests/tcg/Makefile.target | 3 +
50 files changed, 825 insertions(+), 622 deletions(-)
create mode 100644 contrib/plugins/cc.cc
create mode 100755 scripts/feature_to_c.py
delete mode 100644 scripts/feature_to_c.sh
--
2.41.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 01/26] contrib/plugins: Use GRWLock in execlog
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 02/26] gdbstub: Introduce GDBFeature structure Akihiko Odaki
` (24 subsequent siblings)
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Alexandre Iooss, Mahmoud Mandour
execlog had the following comment:
> As we could have multiple threads trying to do this we need to
> serialise the expansion under a lock. Threads accessing already
> created entries can continue without issue even if the ptr array
> gets reallocated during resize.
However, when the ptr array gets reallocated, the other threads may have
a stale reference to the old buffer. This results in use-after-free.
Use GRWLock to properly fix this issue.
Fixes: 3d7caf145e ("contrib/plugins: add execlog to log instruction execution and memory access")
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
---
contrib/plugins/execlog.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/contrib/plugins/execlog.c b/contrib/plugins/execlog.c
index 7129d526f8..82dc2f584e 100644
--- a/contrib/plugins/execlog.c
+++ b/contrib/plugins/execlog.c
@@ -19,7 +19,7 @@ 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 GMutex expand_array_lock;
+static GRWLock expand_array_lock;
static GPtrArray *imatches;
static GArray *amatches;
@@ -28,18 +28,16 @@ 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. Threads accessing already
- * created entries can continue without issue even if the ptr array
- * gets reallocated during resize.
+ * serialise the expansion under a lock.
*/
static void expand_last_exec(int cpu_index)
{
- g_mutex_lock(&expand_array_lock);
+ 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_mutex_unlock(&expand_array_lock);
+ g_rw_lock_writer_unlock(&expand_array_lock);
}
/**
@@ -51,8 +49,10 @@ static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t info,
GString *s;
/* 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_rw_lock_reader_unlock(&expand_array_lock);
/* Indicate type of memory access */
if (qemu_plugin_mem_is_store(info)) {
@@ -80,10 +80,14 @@ static void vcpu_insn_exec(unsigned int cpu_index, void *udata)
GString *s;
/* 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_rw_lock_reader_unlock(&expand_array_lock);
/* Print previous instruction in cache */
if (s->len) {
--
2.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 02/26] gdbstub: Introduce GDBFeature structure
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 01/26] contrib/plugins: Use GRWLock in execlog Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 03/26] gdbstub: Add num_regs member to GDBFeature Akihiko Odaki
` (23 subsequent siblings)
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Philippe Mathieu-Daudé, Richard Henderson,
Paolo Bonzini, Marc-André Lureau, Daniel P. Berrangé,
Thomas Huth, John Snow, Cleber Rosa
Before this change, the information from a XML file was stored in an
array that is not descriptive. Introduce a dedicated structure type to
make it easier to understand and to extend with more fields.
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>
---
MAINTAINERS | 2 +-
meson.build | 2 +-
include/exec/gdbstub.h | 9 ++++--
gdbstub/gdbstub.c | 4 +--
stubs/gdbstub.c | 6 ++--
scripts/feature_to_c.py | 48 ++++++++++++++++++++++++++++
scripts/feature_to_c.sh | 69 -----------------------------------------
7 files changed, 62 insertions(+), 78 deletions(-)
create mode 100755 scripts/feature_to_c.py
delete mode 100644 scripts/feature_to_c.sh
diff --git a/MAINTAINERS b/MAINTAINERS
index 12e59b6b27..514ac74101 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2826,7 +2826,7 @@ F: include/exec/gdbstub.h
F: include/gdbstub/*
F: gdb-xml/
F: tests/tcg/multiarch/gdbstub/
-F: scripts/feature_to_c.sh
+F: scripts/feature_to_c.py
F: scripts/probe-gdb-support.py
Memory API
diff --git a/meson.build b/meson.build
index 98e68ef0b1..5c633f7e01 100644
--- a/meson.build
+++ b/meson.build
@@ -3683,7 +3683,7 @@ common_all = static_library('common',
dependencies: common_all.dependencies(),
name_suffix: 'fa')
-feature_to_c = find_program('scripts/feature_to_c.sh')
+feature_to_c = find_program('scripts/feature_to_c.py')
if targetos == 'darwin'
entitlement = find_program('scripts/entitlement.sh')
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 7d743fe1e9..3f08093321 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -10,6 +10,11 @@
#define GDB_WATCHPOINT_READ 3
#define GDB_WATCHPOINT_ACCESS 4
+typedef struct GDBFeature {
+ const char *xmlname;
+ const char *xml;
+} GDBFeature;
+
/* Get or set a register. Returns the size of the register. */
typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg);
@@ -38,7 +43,7 @@ void gdb_set_stop_cpu(CPUState *cpu);
*/
extern bool gdb_has_xml;
-/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */
-extern const char *const xml_builtin[][2];
+/* in gdbstub-xml.c, generated by scripts/feature_to_c.py */
+extern const GDBFeature gdb_static_features[];
#endif
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index 6911b73c07..2772f07bbe 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -407,11 +407,11 @@ static const char *get_feature_xml(const char *p, const char **newp,
}
}
for (i = 0; ; i++) {
- name = xml_builtin[i][0];
+ name = gdb_static_features[i].xmlname;
if (!name || (strncmp(name, p, len) == 0 && strlen(name) == len))
break;
}
- return name ? xml_builtin[i][1] : NULL;
+ return name ? gdb_static_features[i].xml : NULL;
}
static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
diff --git a/stubs/gdbstub.c b/stubs/gdbstub.c
index 2b7aee50d3..580e20702b 100644
--- a/stubs/gdbstub.c
+++ b/stubs/gdbstub.c
@@ -1,6 +1,6 @@
#include "qemu/osdep.h"
-#include "exec/gdbstub.h" /* xml_builtin */
+#include "exec/gdbstub.h" /* gdb_static_features */
-const char *const xml_builtin[][2] = {
- { NULL, NULL }
+const GDBFeature gdb_static_features[] = {
+ { NULL }
};
diff --git a/scripts/feature_to_c.py b/scripts/feature_to_c.py
new file mode 100755
index 0000000000..bcbcb83beb
--- /dev/null
+++ b/scripts/feature_to_c.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os, sys
+
+def writeliteral(indent, bytes):
+ sys.stdout.write(' ' * indent)
+ sys.stdout.write('"')
+ quoted = True
+
+ for c in bytes:
+ if not quoted:
+ sys.stdout.write('\n')
+ sys.stdout.write(' ' * indent)
+ sys.stdout.write('"')
+ quoted = True
+
+ if c == b'"'[0]:
+ sys.stdout.write('\\"')
+ elif c == b'\\'[0]:
+ sys.stdout.write('\\\\')
+ elif c == b'\n'[0]:
+ sys.stdout.write('\\n"')
+ quoted = False
+ elif c >= 32 and c < 127:
+ sys.stdout.write(c.to_bytes(1, 'big').decode())
+ else:
+ sys.stdout.write(f'\{c:03o}')
+
+ if quoted:
+ sys.stdout.write('"')
+
+sys.stdout.write('#include "qemu/osdep.h"\n' \
+ '#include "exec/gdbstub.h"\n' \
+ '\n'
+ 'const GDBFeature gdb_static_features[] = {\n')
+
+for input in sys.argv[1:]:
+ with open(input, 'rb') as file:
+ read = file.read()
+
+ 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(' { NULL }\n};\n')
diff --git a/scripts/feature_to_c.sh b/scripts/feature_to_c.sh
deleted file mode 100644
index c1f67c8f6a..0000000000
--- a/scripts/feature_to_c.sh
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/bin/sh
-
-# Convert text files to compilable C arrays.
-#
-# Copyright (C) 2007 Free Software Foundation, Inc.
-#
-# This file is part of GDB.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, see <http://www.gnu.org/licenses/>.
-
-if test -z "$1"; then
- echo "Usage: $0 INPUTFILE..."
- exit 1
-fi
-
-for input; do
- arrayname=xml_feature_$(echo $input | sed 's,.*/,,; s/[-.]/_/g')
-
- ${AWK:-awk} 'BEGIN { n = 0
- printf "#include \"qemu/osdep.h\"\n"
- print "static const char '$arrayname'[] = {"
- for (i = 0; i < 255; i++)
- _ord_[sprintf("%c", i)] = i
- } {
- split($0, line, "");
- printf " "
- for (i = 1; i <= length($0); i++) {
- c = line[i]
- if (c == "'\''") {
- printf "'\''\\'\'''\'', "
- } else if (c == "\\") {
- printf "'\''\\\\'\'', "
- } else if (_ord_[c] >= 32 && _ord_[c] < 127) {
- printf "'\''%s'\'', ", c
- } else {
- printf "'\''\\%03o'\'', ", _ord_[c]
- }
- if (i % 10 == 0)
- printf "\n "
- }
- printf "'\''\\n'\'', \n"
- } END {
- print " 0 };"
- }' < $input
-done
-
-echo
-echo '#include "exec/gdbstub.h"'
-echo "const char *const xml_builtin[][2] = {"
-
-for input; do
- basename=$(echo $input | sed 's,.*/,,')
- arrayname=xml_feature_$(echo $input | sed 's,.*/,,; s/[-.]/_/g')
- echo " { \"$basename\", $arrayname },"
-done
-
-echo " { (char *)0, (char *)0 }"
-echo "};"
--
2.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 03/26] gdbstub: Add num_regs member to GDBFeature
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 01/26] contrib/plugins: Use GRWLock in execlog Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 02/26] gdbstub: Introduce GDBFeature structure Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 04/26] gdbstub: Introduce gdb_find_static_feature() Akihiko Odaki
` (22 subsequent siblings)
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Philippe Mathieu-Daudé, John Snow,
Cleber Rosa
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>
---
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 3f08093321..9b484d7eef 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 100755
--- 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.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 04/26] gdbstub: Introduce gdb_find_static_feature()
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (2 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 03/26] gdbstub: Add num_regs member to GDBFeature Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 05/26] target/arm: Move the reference to arm-core.xml Akihiko Odaki
` (21 subsequent siblings)
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Philippe Mathieu-Daudé, Richard Henderson
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>
---
include/exec/gdbstub.h | 2 ++
gdbstub/gdbstub.c | 13 +++++++++++++
2 files changed, 15 insertions(+)
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 9b484d7eef..d0dcc99ed4 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -34,6 +34,8 @@ void gdb_register_coprocessor(CPUState *cpu,
*/
int gdbserver_start(const char *port_or_device);
+const GDBFeature *gdb_find_static_feature(const char *xmlname);
+
void gdb_set_stop_cpu(CPUState *cpu);
/**
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index 2772f07bbe..f0ba9efaff 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -414,6 +414,19 @@ static const char *get_feature_xml(const char *p, const char **newp,
return name ? gdb_static_features[i].xml : 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.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 05/26] target/arm: Move the reference to arm-core.xml
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (3 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 04/26] gdbstub: Introduce gdb_find_static_feature() Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 06/26] hw/core/cpu: Replace gdb_core_xml_file with gdb_core_feature Akihiko Odaki
` (20 subsequent siblings)
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Richard Henderson, Peter Maydell,
open list:ARM TCG CPUs
Some subclasses overwrite gdb_core_xml_file member but others don't.
Always initialize the member in the subclasses for consistency.
This especially helps for AArch64; in a following change, the file
specified by gdb_core_xml_file is always looked up even if it's going to
be overwritten later. Looking up arm-core.xml results in an error as
it will not be embedded in the AArch64 build.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
target/arm/cpu.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 93c28d50e5..d71a162070 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2354,7 +2354,6 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
cc->sysemu_ops = &arm_sysemu_ops;
#endif
cc->gdb_num_core_regs = 26;
- cc->gdb_core_xml_file = "arm-core.xml";
cc->gdb_arch_name = arm_gdb_arch_name;
cc->gdb_get_dynamic_xml = arm_gdb_get_dynamic_xml;
cc->gdb_stop_before_watchpoint = true;
@@ -2376,8 +2375,10 @@ static void arm_cpu_instance_init(Object *obj)
static void cpu_register_class_init(ObjectClass *oc, void *data)
{
ARMCPUClass *acc = ARM_CPU_CLASS(oc);
+ CPUClass *cc = CPU_CLASS(acc);
acc->info = data;
+ cc->gdb_core_xml_file = "arm-core.xml";
}
void arm_cpu_register(const ARMCPUInfo *info)
--
2.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 06/26] hw/core/cpu: Replace gdb_core_xml_file with gdb_core_feature
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (4 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 05/26] target/arm: Move the reference to arm-core.xml Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 07/26] gdbstub: Introduce GDBFeatureBuilder Akihiko Odaki
` (19 subsequent siblings)
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Philippe Mathieu-Daudé, Eduardo Habkost,
Marcel Apfelbaum, Yanan Wang, Peter Maydell, Michael Rolnik,
Brian Cain, Song Gao, Xiaojuan Yang, Laurent Vivier,
Edgar E. Iglesias, Daniel Henrique Barboza, Cédric Le Goater,
David Gibson, Greg Kurz, Nicholas Piggin, Palmer Dabbelt,
Alistair Francis, Bin Meng, Weiwei Li, Liu Zhiwei, Yoshinori Sato,
Thomas Huth, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, open list:ARM TCG CPUs,
open list:PowerPC TCG CPUs, open list:RISC-V TCG CPUs,
open list:S390 general arch...
This is a tree-wide change to replace gdb_core_xml_file, the path to
GDB XML file with gdb_core_feature, the pointer to GDBFeature. This
also replaces the values assigned to gdb_num_core_regs with the
num_regs member of GDBFeature where applicable to remove magic numbers.
A following change will utilize additional information provided by
GDBFeature to simplify XML file lookup.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
include/hw/core/cpu.h | 5 +++--
target/s390x/cpu.h | 2 --
gdbstub/gdbstub.c | 6 +++---
target/arm/cpu.c | 4 ++--
target/arm/cpu64.c | 4 ++--
target/arm/tcg/cpu32.c | 3 ++-
target/avr/cpu.c | 4 ++--
target/hexagon/cpu.c | 2 +-
target/i386/cpu.c | 7 +++----
target/loongarch/cpu.c | 4 ++--
target/m68k/cpu.c | 7 ++++---
target/microblaze/cpu.c | 4 ++--
target/ppc/cpu_init.c | 4 ++--
target/riscv/cpu.c | 7 ++++---
target/rx/cpu.c | 4 ++--
target/s390x/cpu.c | 4 ++--
16 files changed, 36 insertions(+), 35 deletions(-)
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index fdcbe87352..84219c1885 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -23,6 +23,7 @@
#include "hw/qdev-core.h"
#include "disas/dis-asm.h"
#include "exec/cpu-common.h"
+#include "exec/gdbstub.h"
#include "exec/hwaddr.h"
#include "exec/memattrs.h"
#include "qapi/qapi-types-run-state.h"
@@ -127,7 +128,7 @@ struct SysemuCPUOps;
* 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_core_xml_file: File name for core registers GDB XML description.
+ * @gdb_core_feature: GDB core feature description.
* @gdb_stop_before_watchpoint: Indicates whether GDB expects the CPU to stop
* before the insn which triggers a watchpoint rather than after it.
* @gdb_arch_name: Optional callback that returns the architecture name known
@@ -163,7 +164,7 @@ struct CPUClass {
int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg);
vaddr (*gdb_adjust_breakpoint)(CPUState *cpu, vaddr addr);
- const char *gdb_core_xml_file;
+ const GDBFeature *gdb_core_feature;
gchar * (*gdb_arch_name)(CPUState *cpu);
const char * (*gdb_get_dynamic_xml)(CPUState *cpu, const char *xmlname);
diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
index eb5b65b7d3..c5bac3230c 100644
--- a/target/s390x/cpu.h
+++ b/target/s390x/cpu.h
@@ -451,8 +451,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 f0ba9efaff..94f218039b 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -386,7 +386,7 @@ static const char *get_feature_xml(const char *p, const char **newp,
g_free(arch);
}
pstrcat(buf, buf_sz, "<xi:include href=\"");
- pstrcat(buf, buf_sz, cc->gdb_core_xml_file);
+ pstrcat(buf, buf_sz, cc->gdb_core_feature->xmlname);
pstrcat(buf, buf_sz, "\"/>");
for (r = cpu->gdb_regs; r; r = r->next) {
pstrcat(buf, buf_sz, "<xi:include href=\"");
@@ -1506,7 +1506,7 @@ static void handle_query_supported(GArray *params, void *user_ctx)
g_string_printf(gdbserver_state.str_buf, "PacketSize=%x", MAX_PACKET_LENGTH);
cc = CPU_GET_CLASS(first_cpu);
- if (cc->gdb_core_xml_file) {
+ if (cc->gdb_core_feature) {
g_string_append(gdbserver_state.str_buf, ";qXfer:features:read+");
}
@@ -1548,7 +1548,7 @@ static void handle_query_xfer_features(GArray *params, void *user_ctx)
process = gdb_get_cpu_process(gdbserver_state.g_cpu);
cc = CPU_GET_CLASS(gdbserver_state.g_cpu);
- if (!cc->gdb_core_xml_file) {
+ if (!cc->gdb_core_feature) {
gdb_put_packet("");
return;
}
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index d71a162070..a206ab6b1b 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2353,7 +2353,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;
@@ -2378,7 +2377,8 @@ static void cpu_register_class_init(ObjectClass *oc, void *data)
CPUClass *cc = CPU_CLASS(acc);
acc->info = data;
- cc->gdb_core_xml_file = "arm-core.xml";
+ cc->gdb_core_feature = gdb_find_static_feature("arm-core.xml");
+ cc->gdb_num_core_regs = cc->gdb_core_feature->num_regs;
}
void arm_cpu_register(const ARMCPUInfo *info)
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 96158093cc..9c2a226159 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -754,8 +754,8 @@ 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_core_feature = gdb_find_static_feature("aarch64-core.xml");
+ cc->gdb_num_core_regs = cc->gdb_core_feature->num_regs;
cc->gdb_arch_name = aarch64_gdb_arch_name;
object_class_property_add_bool(oc, "aarch64", aarch64_cpu_get_aarch64,
diff --git a/target/arm/tcg/cpu32.c b/target/arm/tcg/cpu32.c
index 47d2e8e781..49a823ad58 100644
--- a/target/arm/tcg/cpu32.c
+++ b/target/arm/tcg/cpu32.c
@@ -1040,7 +1040,8 @@ static void arm_v7m_class_init(ObjectClass *oc, void *data)
acc->info = data;
cc->tcg_ops = &arm_v7m_tcg_ops;
- cc->gdb_core_xml_file = "arm-m-profile.xml";
+ cc->gdb_core_feature = gdb_find_static_feature("arm-m-profile.xml");
+ cc->gdb_num_core_regs = cc->gdb_core_feature->num_regs;
}
#ifndef TARGET_AARCH64
diff --git a/target/avr/cpu.c b/target/avr/cpu.c
index 8f741f258c..217adc64cb 100644
--- a/target/avr/cpu.c
+++ b/target/avr/cpu.c
@@ -246,8 +246,8 @@ 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->gdb_core_feature = gdb_find_static_feature("avr-cpu.xml");
+ cc->gdb_num_core_regs = cc->gdb_core_feature->num_regs;
cc->tcg_ops = &avr_tcg_ops;
}
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index f155936289..b54162cbeb 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -391,7 +391,7 @@ static void hexagon_cpu_class_init(ObjectClass *c, void *data)
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->gdb_core_feature = gdb_find_static_feature("hexagon-core.xml");
cc->disas_set_info = hexagon_cpu_disas_set_info;
cc->tcg_ops = &hexagon_tcg_ops;
}
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 97ad229d8b..069410985f 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -7963,12 +7963,11 @@ 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;
+ cc->gdb_core_feature = gdb_find_static_feature("i386-64bit.xml");
#else
- cc->gdb_core_xml_file = "i386-32bit.xml";
- cc->gdb_num_core_regs = 50;
+ cc->gdb_core_feature = gdb_find_static_feature("i386-32bit.xml");
#endif
+ cc->gdb_num_core_regs = cc->gdb_core_feature->num_regs;
cc->disas_set_info = x86_disas_set_info;
dc->user_creatable = true;
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index ad93ecac92..b204cb279d 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -722,8 +722,8 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data)
cc->gdb_read_register = loongarch_cpu_gdb_read_register;
cc->gdb_write_register = loongarch_cpu_gdb_write_register;
cc->disas_set_info = loongarch_cpu_disas_set_info;
- cc->gdb_num_core_regs = 35;
- cc->gdb_core_xml_file = "loongarch-base64.xml";
+ cc->gdb_core_feature = gdb_find_static_feature("loongarch-base64.xml");
+ cc->gdb_num_core_regs = cc->gdb_core_feature->num_regs;
cc->gdb_stop_before_watchpoint = true;
cc->gdb_arch_name = loongarch_gdb_arch_name;
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
index 70d58471dc..2bd7238aa8 100644
--- a/target/m68k/cpu.c
+++ b/target/m68k/cpu.c
@@ -572,7 +572,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;
}
@@ -580,7 +579,8 @@ static void m68k_cpu_class_init_cf_core(ObjectClass *c, void *data)
{
CPUClass *cc = CPU_CLASS(c);
- cc->gdb_core_xml_file = "cf-core.xml";
+ cc->gdb_core_feature = gdb_find_static_feature("cf-core.xml");
+ cc->gdb_num_core_regs = cc->gdb_core_feature->num_regs;
}
#define DEFINE_M68K_CPU_TYPE_CF(model) \
@@ -595,7 +595,8 @@ static void m68k_cpu_class_init_m68k_core(ObjectClass *c, void *data)
{
CPUClass *cc = CPU_CLASS(c);
- cc->gdb_core_xml_file = "m68k-core.xml";
+ cc->gdb_core_feature = gdb_find_static_feature("m68k-core.xml");
+ cc->gdb_num_core_regs = cc->gdb_core_feature->num_regs;
}
#define DEFINE_M68K_CPU_TYPE_M68K(model) \
diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c
index 03c2c4db1f..47f37c2519 100644
--- a/target/microblaze/cpu.c
+++ b/target/microblaze/cpu.c
@@ -428,8 +428,8 @@ 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->gdb_core_feature = gdb_find_static_feature("microblaze-core.xml");
+ cc->gdb_num_core_regs = cc->gdb_core_feature->num_regs;
cc->disas_set_info = mb_disas_set_info;
cc->tcg_ops = &mb_tcg_ops;
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 02b7aad9b0..eb56226865 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -7381,9 +7381,9 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
cc->gdb_arch_name = ppc_gdb_arch_name;
#if defined(TARGET_PPC64)
- cc->gdb_core_xml_file = "power64-core.xml";
+ cc->gdb_core_feature = gdb_find_static_feature("power64-core.xml");
#else
- cc->gdb_core_xml_file = "power-core.xml";
+ cc->gdb_core_feature = gdb_find_static_feature("power-core.xml");
#endif
cc->disas_set_info = ppc_disas_set_info;
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 6b93b04453..36de35270d 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1031,11 +1031,11 @@ static void riscv_cpu_validate_misa_mxl(RISCVCPU *cpu, Error **errp)
#ifdef TARGET_RISCV64
case MXL_RV64:
case MXL_RV128:
- cc->gdb_core_xml_file = "riscv-64bit-cpu.xml";
+ cc->gdb_core_feature = gdb_find_static_feature("riscv-64bit-cpu.xml");
break;
#endif
case MXL_RV32:
- cc->gdb_core_xml_file = "riscv-32bit-cpu.xml";
+ cc->gdb_core_feature = gdb_find_static_feature("riscv-32bit-cpu.xml");
break;
default:
g_assert_not_reached();
@@ -1045,6 +1045,8 @@ static void riscv_cpu_validate_misa_mxl(RISCVCPU *cpu, Error **errp)
error_setg(errp, "misa_mxl_max must be equal to misa_mxl");
return;
}
+
+ cc->gdb_num_core_regs = cc->gdb_core_feature->num_regs;
}
/*
@@ -2138,7 +2140,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 157e57da0f..b139265728 100644
--- a/target/rx/cpu.c
+++ b/target/rx/cpu.c
@@ -239,8 +239,8 @@ 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->gdb_core_feature = gdb_find_static_feature("rx-core.xml");
+ cc->gdb_num_core_regs = cc->gdb_core_feature->num_regs;
cc->tcg_ops = &rx_tcg_ops;
}
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index df167493c3..2a2ff8cbdc 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -348,8 +348,8 @@ 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_core_feature = gdb_find_static_feature("s390x-core64.xml");
+ cc->gdb_num_core_regs = cc->gdb_core_feature->num_regs;
cc->gdb_arch_name = s390_gdb_arch_name;
s390_cpu_model_class_register_props(oc);
--
2.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 07/26] gdbstub: Introduce GDBFeatureBuilder
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (5 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 06/26] hw/core/cpu: Replace gdb_core_xml_file with gdb_core_feature Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 08/26] target/arm: Use GDBFeature for dynamic XML Akihiko Odaki
` (18 subsequent siblings)
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Richard Henderson, Philippe Mathieu-Daudé
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>
---
include/exec/gdbstub.h | 20 ++++++++++++++
gdbstub/gdbstub.c | 59 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 79 insertions(+)
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index d0dcc99ed4..1f4608d4f9 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -16,6 +16,11 @@ typedef struct GDBFeature {
int num_regs;
} GDBFeature;
+typedef struct GDBFeatureBuilder {
+ GDBFeature *feature;
+ GPtrArray *xml;
+} GDBFeatureBuilder;
+
/* Get or set a register. Returns the size of the register. */
typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg);
@@ -34,6 +39,21 @@ void gdb_register_coprocessor(CPUState *cpu,
*/
int gdbserver_start(const char *port_or_device);
+void gdb_feature_builder_init(GDBFeatureBuilder *builder, GDBFeature *feature,
+ const char *name, const char *xmlname);
+
+void gdb_feature_builder_append_tag(const GDBFeatureBuilder *builder,
+ const char *format, ...)
+ G_GNUC_PRINTF(2, 3);
+
+void gdb_feature_builder_append_reg(const GDBFeatureBuilder *builder,
+ const char *name,
+ int bitsize,
+ const char *type,
+ const char *group);
+
+void gdb_feature_builder_end(const GDBFeatureBuilder *builder);
+
const GDBFeature *gdb_find_static_feature(const char *xmlname);
void gdb_set_stop_cpu(CPUState *cpu);
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index 94f218039b..909e3cd655 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -414,6 +414,65 @@ static const char *get_feature_xml(const char *p, const char **newp,
return name ? gdb_static_features[i].xml : NULL;
}
+void gdb_feature_builder_init(GDBFeatureBuilder *builder, GDBFeature *feature,
+ const char *name, const char *xmlname)
+{
+ char *header = g_markup_printf_escaped(
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
+ "<feature name=\"%s\">",
+ name);
+
+ builder->feature = feature;
+ builder->xml = g_ptr_array_new();
+ g_ptr_array_add(builder->xml, header);
+ 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,
+ const char *type,
+ const char *group)
+{
+ if (group) {
+ gdb_feature_builder_append_tag(
+ builder,
+ "<reg name=\"%s\" bitsize=\"%d\" type=\"%s\" group=\"%s\"/>",
+ name, bitsize, type, group);
+ } else {
+ gdb_feature_builder_append_tag(
+ builder, "<reg name=\"%s\" bitsize=\"%d\" type=\"%s\"/>",
+ name, bitsize, type);
+ }
+
+ builder->feature->num_regs++;
+}
+
+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.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 08/26] target/arm: Use GDBFeature for dynamic XML
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (6 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 07/26] gdbstub: Introduce GDBFeatureBuilder Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 09/26] target/ppc: " Akihiko Odaki
` (17 subsequent siblings)
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Richard Henderson, Peter Maydell,
open list:ARM TCG CPUs
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>
---
target/arm/cpu.h | 20 +++---
target/arm/internals.h | 2 +-
target/arm/gdbstub.c | 134 ++++++++++++++++++-----------------------
target/arm/gdbstub64.c | 90 ++++++++++++---------------
4 files changed, 108 insertions(+), 138 deletions(-)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 88e5accda6..d6c2378d05 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -136,23 +136,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 {
@@ -881,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 0f01bc32a8..ca20e4fd1e 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1388,7 +1388,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 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 f421c5d041..daa68ead66 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -25,11 +25,10 @@
#include "internals.h"
#include "cpregs.h"
-typedef struct RegisterSysregXmlParam {
+typedef struct RegisterSysregFeatureParam {
CPUState *cs;
- GString *s;
- int n;
-} RegisterSysregXmlParam;
+ GDBFeatureBuilder builder;
+} RegisterSysregFeatureParam;
/* Old gdb always expect FPA registers. Newer (xml-aware) gdb only expect
whatever the target description contains. Due to a historical mishap
@@ -243,7 +242,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)) {
@@ -260,34 +259,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)
{
- 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++;
+ dyn_feature->data.cpregs.keys[dyn_feature->desc.num_regs] = ri_key;
+
+ gdb_feature_builder_append_reg(builder, ri->name, bitsize,
+ "int", "cp_regs");
}
-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);
}
} else {
if (ri->state == ARM_CP_STATE_AA32) {
@@ -296,32 +293,31 @@ 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);
} 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);
}
}
}
}
}
-static int arm_gen_dynamic_sysreg_xml(CPUState *cs, int base_reg)
+static GDBFeature *arm_gen_dynamic_sysreg_feature(CPUState *cs)
{
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");
+ 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
@@ -413,31 +409,26 @@ 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)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
- GString *s = g_string_new(NULL);
- int base_reg = orig_base_reg;
+ GDBFeatureBuilder builder;
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");
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,
+ "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
@@ -455,31 +446,26 @@ 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)
{
ARMCPU *cpu = ARM_CPU(cs);
- GString *s = g_string_new(NULL);
- int base_reg = orig_base_reg;
+ GDBFeatureBuilder builder;
+ char *name;
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");
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, "int", NULL);
+ name = g_strconcat(m_sysreg_def[i].name, "_s", NULL);
+ gdb_feature_builder_append_reg(&builder, name, 32, "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 */
@@ -489,14 +475,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;
@@ -514,7 +500,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)->num_regs;
gdb_register_coprocessor(cs, aarch64_gdb_get_sve_reg,
aarch64_gdb_set_sve_reg, nreg,
"sve-registers.xml", 0);
@@ -560,20 +546,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)->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)->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)->num_regs,
"arm-m-secext.xml", 0);
}
#endif
diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c
index d7b79a6589..632ac2a520 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,72 @@ 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)
{
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 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");
/* 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, "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, "int", "float");
+ gdb_feature_builder_append_reg(&builder, "fpcr", 32, "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,
+ "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,
+ "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, "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.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 09/26] target/ppc: Use GDBFeature for dynamic XML
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (7 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 08/26] target/arm: Use GDBFeature for dynamic XML Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 10/26] target/riscv: " Akihiko Odaki
` (16 subsequent siblings)
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Richard Henderson, Daniel Henrique Barboza,
Cédric Le Goater, David Gibson, Greg Kurz, Nicholas Piggin,
open list:PowerPC TCG CPUs
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>
---
target/ppc/cpu-qom.h | 3 +--
target/ppc/cpu.h | 2 +-
target/ppc/cpu_init.c | 2 +-
target/ppc/gdbstub.c | 45 ++++++++++++++-----------------------------
4 files changed, 17 insertions(+), 35 deletions(-)
diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h
index be33786bd8..633fb402b5 100644
--- a/target/ppc/cpu-qom.h
+++ b/target/ppc/cpu-qom.h
@@ -186,8 +186,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 25fac9577a..5f251bdffe 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1381,7 +1381,7 @@ 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);
+void ppc_gdb_gen_spr_feature(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 eb56226865..938cd2b7e1 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6673,7 +6673,7 @@ static void init_ppc_proc(PowerPCCPU *cpu)
(*pcc->init_proc)(env);
#if !defined(CONFIG_USER_ONLY)
- ppc_gdb_gen_spr_xml(cpu);
+ ppc_gdb_gen_spr_feature(cpu);
#endif
/* MSR bits & flags consistency checks */
diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c
index ca39efdc35..0ef484dbee 100644
--- a/target/ppc/gdbstub.c
+++ b/target/ppc/gdbstub.c
@@ -318,15 +318,21 @@ 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)
+void ppc_gdb_gen_spr_feature(PowerPCCPU *cpu)
{
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
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");
+
for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) {
ppc_spr_t *spr = &env->spr_cb[i];
@@ -344,35 +350,12 @@ 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, "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)
@@ -380,7 +363,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;
}
@@ -618,6 +601,6 @@ void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *pcc)
}
#ifndef CONFIG_USER_ONLY
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.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 10/26] target/riscv: Use GDBFeature for dynamic XML
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (8 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 09/26] target/ppc: " Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 11/26] gdbstub: Use GDBFeature for gdb_register_coprocessor Akihiko Odaki
` (15 subsequent siblings)
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Palmer Dabbelt, Alistair Francis, Bin Meng,
Weiwei Li, Daniel Henrique Barboza, Liu Zhiwei,
open list:RISC-V TCG CPUs
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>
---
target/riscv/cpu.h | 4 +--
target/riscv/cpu.c | 4 +--
target/riscv/gdbstub.c | 77 ++++++++++++++++++------------------------
3 files changed, 37 insertions(+), 48 deletions(-)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 6ea22e0eea..f67751d5b7 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -391,8 +391,8 @@ struct ArchCPU {
CPUNegativeOffsetState neg;
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 36de35270d..ceca40cdd9 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1962,9 +1962,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..cdae406751 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)
{
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,8 @@ 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");
for (i = 0; i < CSR_TABLE_SIZE; i++) {
if (env->priv_ver < csr_ops[i].min_priv_ver) {
@@ -240,72 +240,63 @@ 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,
+ "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)
{
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");
/* 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, "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 +311,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)->num_regs,
"riscv-vector.xml", 0);
}
switch (env->misa_mxl_max) {
@@ -343,9 +333,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)->num_regs,
"riscv-csr.xml", 0);
}
}
--
2.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 11/26] gdbstub: Use GDBFeature for gdb_register_coprocessor
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (9 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 10/26] target/riscv: " Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 12/26] gdbstub: Use GDBFeature for GDBRegisterState Akihiko Odaki
` (14 subsequent siblings)
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Philippe Mathieu-Daudé, Peter Maydell,
Brian Cain, Song Gao, Xiaojuan Yang, Laurent Vivier,
Edgar E. Iglesias, Daniel Henrique Barboza, Cédric Le Goater,
David Gibson, Greg Kurz, Nicholas Piggin, Palmer Dabbelt,
Alistair Francis, Bin Meng, Weiwei Li, Liu Zhiwei, Thomas Huth,
Richard Henderson, David Hildenbrand, Ilya Leoshkevich,
open list:ARM TCG CPUs, open list:PowerPC TCG CPUs,
open list:RISC-V TCG CPUs, open list:S390 general arch...
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>
---
include/exec/gdbstub.h | 2 +-
gdbstub/gdbstub.c | 13 +++++++------
target/arm/gdbstub.c | 34 ++++++++++++++++++----------------
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 | 18 ++++++++++--------
target/s390x/gdbstub.c | 28 +++++++---------------------
10 files changed, 57 insertions(+), 65 deletions(-)
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 1f4608d4f9..572abada63 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -27,7 +27,7 @@ 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);
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 909e3cd655..b62002bc34 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -530,7 +530,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;
GDBRegisterState **p;
@@ -538,25 +538,26 @@ void gdb_register_coprocessor(CPUState *cpu,
p = &cpu->gdb_regs;
while (*p) {
/* Check for duplicates. */
- if (strcmp((*p)->xml, xml) == 0)
+ if (strcmp((*p)->xml, feature->xmlname) == 0)
return;
p = &(*p)->next;
}
s = g_new0(GDBRegisterState, 1);
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;
*p = s;
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 daa68ead66..791784dffe 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -500,14 +500,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)->num_regs;
+ GDBFeature *feature = arm_gen_dynamic_svereg_feature(cs);
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
@@ -518,19 +518,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)) {
/*
@@ -538,29 +541,28 @@ 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)->num_regs,
- "system-registers.xml", 0);
+ arm_gen_dynamic_sysreg_feature(cs), 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)->num_regs,
- "arm-m-system.xml", 0);
+ arm_gen_dynamic_m_systemreg_feature(cs), 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)->num_regs,
- "arm-m-secext.xml", 0);
+ arm_gen_dynamic_m_secextreg_feature(cs), 0);
}
#endif
}
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index b54162cbeb..6732efc5de 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 0752fff924..2886b106bb 100644
--- a/target/loongarch/gdbstub.c
+++ b/target/loongarch/gdbstub.c
@@ -101,5 +101,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 47f37c2519..c804622ab9 100644
--- a/target/microblaze/cpu.c
+++ b/target/microblaze/cpu.c
@@ -298,8 +298,9 @@ static void mb_cpu_initfn(Object *obj)
cpu_set_cpustate_pointers(cpu);
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 0ef484dbee..70cac919e0 100644
--- a/target/ppc/gdbstub.c
+++ b/target/ppc/gdbstub.c
@@ -585,22 +585,23 @@ 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_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 cdae406751..d4f9eb1516 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -305,28 +305,31 @@ 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)->num_regs,
- "riscv-vector.xml", 0);
+ ricsv_gen_dynamic_vector_feature(cs), 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();
@@ -334,7 +337,6 @@ 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)->num_regs,
- "riscv-csr.xml", 0);
+ riscv_gen_dynamic_csr_feature(cs), 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.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 12/26] gdbstub: Use GDBFeature for GDBRegisterState
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (10 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 11/26] gdbstub: Use GDBFeature for gdb_register_coprocessor Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-30 14:59 ` Alex Bennée
2023-08-18 3:36 ` [PATCH RESEND v5 13/26] hw/core/cpu: Return static value with gdb_arch_name() Akihiko Odaki
` (13 subsequent siblings)
25 siblings, 1 reply; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Philippe Mathieu-Daudé
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>
---
gdbstub/gdbstub.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index b62002bc34..ee6b8b98c8 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;
struct GDBRegisterState *next;
} GDBRegisterState;
@@ -390,7 +389,7 @@ static const char *get_feature_xml(const char *p, const char **newp,
pstrcat(buf, buf_sz, "\"/>");
for (r = cpu->gdb_regs; r; r = r->next) {
pstrcat(buf, buf_sz, "<xi:include href=\"");
- pstrcat(buf, buf_sz, r->xml);
+ pstrcat(buf, buf_sz, r->feature->xmlname);
pstrcat(buf, buf_sz, "\"/>");
}
pstrcat(buf, buf_sz, "</target>");
@@ -497,7 +496,7 @@ static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
}
for (r = cpu->gdb_regs; r; r = r->next) {
- 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);
}
}
@@ -515,7 +514,7 @@ static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
}
for (r = cpu->gdb_regs; r; r = r->next) {
- 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);
}
}
@@ -538,17 +537,16 @@ void gdb_register_coprocessor(CPUState *cpu,
p = &cpu->gdb_regs;
while (*p) {
/* Check for duplicates. */
- if (strcmp((*p)->xml, feature->xmlname) == 0)
+ if ((*p)->feature == feature)
return;
p = &(*p)->next;
}
s = g_new0(GDBRegisterState, 1);
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.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 13/26] hw/core/cpu: Return static value with gdb_arch_name()
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (11 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 12/26] gdbstub: Use GDBFeature for GDBRegisterState Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-30 15:00 ` Alex Bennée
2023-08-18 3:36 ` [PATCH RESEND v5 14/26] gdbstub: Dynamically allocate target.xml buffer Akihiko Odaki
` (12 subsequent siblings)
25 siblings, 1 reply; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Philippe Mathieu-Daudé, Eduardo Habkost,
Marcel Apfelbaum, Yanan Wang, Peter Maydell, Song Gao,
Xiaojuan Yang, Daniel Henrique Barboza, Cédric Le Goater,
David Gibson, Greg Kurz, Nicholas Piggin, Palmer Dabbelt,
Alistair Francis, Bin Meng, Weiwei Li, Liu Zhiwei,
Richard Henderson, David Hildenbrand, Ilya Leoshkevich,
Thomas Huth, Bastian Koppelmann, open list:ARM TCG CPUs,
open list:PowerPC TCG CPUs, open list:RISC-V TCG CPUs,
open list:S390 TCG CPUs
All implementations of gdb_arch_name() returns dynamic duplicates of
static strings. It's also unlikely that there will be an implementation
of gdb_arch_name() that returns a truly dynamic value due to the nature
of the function returning a well-known identifiers. Qualify the value
gdb_arch_name() with const and make all of its implementations return
static strings.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
include/hw/core/cpu.h | 2 +-
target/ppc/internal.h | 2 +-
gdbstub/gdbstub.c | 4 +---
target/arm/cpu.c | 6 +++---
target/arm/cpu64.c | 4 ++--
target/i386/cpu.c | 6 +++---
target/loongarch/cpu.c | 4 ++--
target/ppc/gdbstub.c | 6 +++---
target/riscv/cpu.c | 6 +++---
target/s390x/cpu.c | 4 ++--
target/tricore/cpu.c | 4 ++--
11 files changed, 23 insertions(+), 25 deletions(-)
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index 84219c1885..09f1aca624 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -165,7 +165,7 @@ struct CPUClass {
vaddr (*gdb_adjust_breakpoint)(CPUState *cpu, vaddr addr);
const GDBFeature *gdb_core_feature;
- gchar * (*gdb_arch_name)(CPUState *cpu);
+ 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/ppc/internal.h b/target/ppc/internal.h
index 57acb3212c..974b37aa60 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -221,7 +221,7 @@ void destroy_ppc_opcodes(PowerPCCPU *cpu);
/* gdbstub.c */
void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *ppc);
-gchar *ppc_gdb_arch_name(CPUState *cs);
+const gchar *ppc_gdb_arch_name(CPUState *cs);
/**
* prot_for_access_type:
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index ee6b8b98c8..5656a44970 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -378,11 +378,9 @@ static const char *get_feature_xml(const char *p, const char **newp,
"<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
"<target>");
if (cc->gdb_arch_name) {
- gchar *arch = cc->gdb_arch_name(cpu);
pstrcat(buf, buf_sz, "<architecture>");
- pstrcat(buf, buf_sz, arch);
+ pstrcat(buf, buf_sz, cc->gdb_arch_name(cpu));
pstrcat(buf, buf_sz, "</architecture>");
- g_free(arch);
}
pstrcat(buf, buf_sz, "<xi:include href=\"");
pstrcat(buf, buf_sz, cc->gdb_core_feature->xmlname);
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index a206ab6b1b..5f07133419 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2281,15 +2281,15 @@ static Property arm_cpu_properties[] = {
DEFINE_PROP_END_OF_LIST()
};
-static gchar *arm_gdb_arch_name(CPUState *cs)
+static const gchar *arm_gdb_arch_name(CPUState *cs)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
- return g_strdup("iwmmxt");
+ return "iwmmxt";
}
- return g_strdup("arm");
+ return "arm";
}
#ifndef CONFIG_USER_ONLY
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 9c2a226159..65f84bfb18 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -743,9 +743,9 @@ static void aarch64_cpu_finalizefn(Object *obj)
{
}
-static gchar *aarch64_gdb_arch_name(CPUState *cs)
+static const gchar *aarch64_gdb_arch_name(CPUState *cs)
{
- return g_strdup("aarch64");
+ return "aarch64";
}
static void aarch64_cpu_class_init(ObjectClass *oc, void *data)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 069410985f..c1a7667f4a 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -5910,12 +5910,12 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model)
memset(&env->user_features, 0, sizeof(env->user_features));
}
-static gchar *x86_gdb_arch_name(CPUState *cs)
+static const gchar *x86_gdb_arch_name(CPUState *cs)
{
#ifdef TARGET_X86_64
- return g_strdup("i386:x86-64");
+ return "i386:x86-64";
#else
- return g_strdup("i386");
+ return "i386";
#endif
}
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index b204cb279d..6c76d14e43 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -692,9 +692,9 @@ static const struct SysemuCPUOps loongarch_sysemu_ops = {
};
#endif
-static gchar *loongarch_gdb_arch_name(CPUState *cs)
+static const gchar *loongarch_gdb_arch_name(CPUState *cs)
{
- return g_strdup("loongarch64");
+ return "loongarch64";
}
static void loongarch_cpu_class_init(ObjectClass *c, void *data)
diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c
index 70cac919e0..dbdee7d56e 100644
--- a/target/ppc/gdbstub.c
+++ b/target/ppc/gdbstub.c
@@ -572,12 +572,12 @@ static int gdb_set_vsx_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
return 0;
}
-gchar *ppc_gdb_arch_name(CPUState *cs)
+const gchar *ppc_gdb_arch_name(CPUState *cs)
{
#if defined(TARGET_PPC64)
- return g_strdup("powerpc:common64");
+ return "powerpc:common64";
#else
- return g_strdup("powerpc:common");
+ return "powerpc:common";
#endif
}
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index ceca40cdd9..86a477bfc0 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1941,17 +1941,17 @@ static Property riscv_cpu_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
-static gchar *riscv_gdb_arch_name(CPUState *cs)
+static const gchar *riscv_gdb_arch_name(CPUState *cs)
{
RISCVCPU *cpu = RISCV_CPU(cs);
CPURISCVState *env = &cpu->env;
switch (riscv_cpu_mxl(env)) {
case MXL_RV32:
- return g_strdup("riscv:rv32");
+ return "riscv:rv32";
case MXL_RV64:
case MXL_RV128:
- return g_strdup("riscv:rv64");
+ return "riscv:rv64";
default:
g_assert_not_reached();
}
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index 2a2ff8cbdc..ca356c2b86 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -284,9 +284,9 @@ static void s390_cpu_initfn(Object *obj)
#endif
}
-static gchar *s390_gdb_arch_name(CPUState *cs)
+static const gchar *s390_gdb_arch_name(CPUState *cs)
{
- return g_strdup("s390:64-bit");
+ return "s390:64-bit";
}
static Property s390x_cpu_properties[] = {
diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c
index 133a9ac70e..44e3ba6f0e 100644
--- a/target/tricore/cpu.c
+++ b/target/tricore/cpu.c
@@ -29,9 +29,9 @@ static inline void set_feature(CPUTriCoreState *env, int feature)
env->features |= 1ULL << feature;
}
-static gchar *tricore_gdb_arch_name(CPUState *cs)
+static const gchar *tricore_gdb_arch_name(CPUState *cs)
{
- return g_strdup("tricore");
+ return "tricore";
}
static void tricore_cpu_set_pc(CPUState *cs, vaddr value)
--
2.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 14/26] gdbstub: Dynamically allocate target.xml buffer
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (12 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 13/26] hw/core/cpu: Return static value with gdb_arch_name() Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 15/26] gdbstub: Simplify XML lookup Akihiko Odaki
` (11 subsequent siblings)
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Philippe Mathieu-Daudé
There is no guarantee that target.xml fits in 1024 bytes, and the fixed
buffer length requires tedious buffer overflow check. Dynamically
allocate the target.xml buffer to resolve these problems.
Suggested-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
gdbstub/internals.h | 2 +-
gdbstub/gdbstub.c | 44 ++++++++++++++++++++++++--------------------
gdbstub/softmmu.c | 2 +-
3 files changed, 26 insertions(+), 22 deletions(-)
diff --git a/gdbstub/internals.h b/gdbstub/internals.h
index f2b46cce41..4876ebd74f 100644
--- a/gdbstub/internals.h
+++ b/gdbstub/internals.h
@@ -33,7 +33,7 @@ typedef struct GDBProcess {
uint32_t pid;
bool attached;
- char target_xml[1024];
+ char *target_xml;
} GDBProcess;
enum RSState {
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index 5656a44970..031ad89c7d 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -366,33 +366,37 @@ static const char *get_feature_xml(const char *p, const char **newp,
name = NULL;
if (strncmp(p, "target.xml", len) == 0) {
- char *buf = process->target_xml;
- const size_t buf_sz = sizeof(process->target_xml);
-
/* Generate the XML description for this CPU. */
- if (!buf[0]) {
+ if (!process->target_xml) {
+ g_autoptr(GPtrArray) a = g_ptr_array_new_with_free_func(g_free);
GDBRegisterState *r;
- pstrcat(buf, buf_sz,
- "<?xml version=\"1.0\"?>"
- "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
- "<target>");
+ g_ptr_array_add(
+ a,
+ g_strdup("<?xml version=\"1.0\"?>"
+ "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
+ "<target>"));
if (cc->gdb_arch_name) {
- pstrcat(buf, buf_sz, "<architecture>");
- pstrcat(buf, buf_sz, cc->gdb_arch_name(cpu));
- pstrcat(buf, buf_sz, "</architecture>");
+ g_ptr_array_add(
+ a,
+ g_markup_printf_escaped("<architecture>%s</architecture>",
+ cc->gdb_arch_name(cpu)));
}
- pstrcat(buf, buf_sz, "<xi:include href=\"");
- pstrcat(buf, buf_sz, cc->gdb_core_feature->xmlname);
- pstrcat(buf, buf_sz, "\"/>");
+ g_ptr_array_add(
+ a,
+ g_markup_printf_escaped("<xi:include href=\"%s\"/>",
+ cc->gdb_core_feature->xmlname));
for (r = cpu->gdb_regs; r; r = r->next) {
- pstrcat(buf, buf_sz, "<xi:include href=\"");
- pstrcat(buf, buf_sz, r->feature->xmlname);
- pstrcat(buf, buf_sz, "\"/>");
+ g_ptr_array_add(
+ a,
+ g_markup_printf_escaped("<xi:include href=\"%s\"/>",
+ r->feature->xmlname));
}
- pstrcat(buf, buf_sz, "</target>");
+ g_ptr_array_add(a, g_strdup("</target>"));
+ g_ptr_array_add(a, NULL);
+ process->target_xml = g_strjoinv(NULL, (void *)a->pdata);
}
- return buf;
+ return process->target_xml;
}
if (cc->gdb_get_dynamic_xml) {
char *xmlname = g_strndup(p, len);
@@ -2270,6 +2274,6 @@ void gdb_create_default_process(GDBState *s)
process = &s->processes[s->process_num - 1];
process->pid = pid;
process->attached = false;
- process->target_xml[0] = '\0';
+ process->target_xml = NULL;
}
diff --git a/gdbstub/softmmu.c b/gdbstub/softmmu.c
index f509b7285d..5282324764 100644
--- a/gdbstub/softmmu.c
+++ b/gdbstub/softmmu.c
@@ -293,7 +293,7 @@ static int find_cpu_clusters(Object *child, void *opaque)
assert(cluster->cluster_id != UINT32_MAX);
process->pid = cluster->cluster_id + 1;
process->attached = false;
- process->target_xml[0] = '\0';
+ process->target_xml = NULL;
return 0;
}
--
2.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 15/26] gdbstub: Simplify XML lookup
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (13 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 14/26] gdbstub: Dynamically allocate target.xml buffer Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 16/26] hw/core/cpu: Remove gdb_get_dynamic_xml member Akihiko Odaki
` (10 subsequent siblings)
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Philippe Mathieu-Daudé
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>
---
gdbstub/gdbstub.c | 24 ++++++++----------------
1 file changed, 8 insertions(+), 16 deletions(-)
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index 031ad89c7d..4648a56088 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -354,8 +354,7 @@ static const char *get_feature_xml(const char *p, const char **newp,
GDBProcess *process)
{
size_t len;
- int i;
- const char *name;
+ GDBRegisterState *r;
CPUState *cpu = gdb_get_first_cpu_in_process(process);
CPUClass *cc = CPU_GET_CLASS(cpu);
@@ -364,7 +363,6 @@ static const char *get_feature_xml(const char *p, const char **newp,
len++;
*newp = p + len;
- name = NULL;
if (strncmp(p, "target.xml", len) == 0) {
/* Generate the XML description for this CPU. */
if (!process->target_xml) {
@@ -398,21 +396,15 @@ static const char *get_feature_xml(const char *p, const char **newp,
}
return process->target_xml;
}
- if (cc->gdb_get_dynamic_xml) {
- char *xmlname = g_strndup(p, len);
- const char *xml = cc->gdb_get_dynamic_xml(cpu, xmlname);
-
- g_free(xmlname);
- if (xml) {
- return xml;
- }
+ if (strncmp(p, cc->gdb_core_feature->xmlname, len) == 0) {
+ return cc->gdb_core_feature->xml;
}
- for (i = 0; ; i++) {
- name = gdb_static_features[i].xmlname;
- if (!name || (strncmp(name, p, len) == 0 && strlen(name) == len))
- break;
+ for (r = cpu->gdb_regs; r; r = r->next) {
+ if (strncmp(p, r->feature->xmlname, len) == 0) {
+ return r->feature->xml;
+ }
}
- return name ? gdb_static_features[i].xml : NULL;
+ return NULL;
}
void gdb_feature_builder_init(GDBFeatureBuilder *builder, GDBFeature *feature,
--
2.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 16/26] hw/core/cpu: Remove gdb_get_dynamic_xml member
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (14 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 15/26] gdbstub: Simplify XML lookup Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 17/26] gdbstub: Add members to identify registers to GDBFeature Akihiko Odaki
` (9 subsequent siblings)
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Eduardo Habkost, Marcel Apfelbaum,
Philippe Mathieu-Daudé, Yanan Wang, Peter Maydell,
Daniel Henrique Barboza, Cédric Le Goater, David Gibson,
Greg Kurz, Nicholas Piggin, Palmer Dabbelt, Alistair Francis,
Bin Meng, Weiwei Li, Liu Zhiwei, open list:ARM TCG CPUs,
open list:PowerPC TCG CPUs, open list:RISC-V TCG CPUs
This function is no longer used.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
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 09f1aca624..8fc9a1a140 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -133,9 +133,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.
@@ -166,7 +163,6 @@ struct CPUClass {
const GDBFeature *gdb_core_feature;
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 d6c2378d05..09bf82034d 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1131,12 +1131,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 5f251bdffe..3dc6e545e3 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1382,7 +1382,6 @@ 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_feature(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,
int cpuid, DumpState *s);
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 5f07133419..f26c0ded18 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2354,7 +2354,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 791784dffe..fc5ed89e80 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -470,24 +470,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 938cd2b7e1..a3153c4e9f 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -7370,9 +7370,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 dbdee7d56e..c86b7055ca 100644
--- a/target/ppc/gdbstub.c
+++ b/target/ppc/gdbstub.c
@@ -357,16 +357,6 @@ void ppc_gdb_gen_spr_feature(PowerPCCPU *cpu)
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 86a477bfc0..e12b6ef7f6 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1957,19 +1957,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)
{
@@ -2147,7 +2134,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;
cc->tcg_ops = &riscv_tcg_ops;
object_class_property_add(c, "mvendorid", "uint32", cpu_get_mvendorid,
--
2.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 17/26] gdbstub: Add members to identify registers to GDBFeature
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (15 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 16/26] hw/core/cpu: Remove gdb_get_dynamic_xml member Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 18/26] target/arm: Remove references to gdb_has_xml Akihiko Odaki
` (8 subsequent siblings)
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Philippe Mathieu-Daudé, John Snow,
Cleber Rosa, Peter Maydell, Palmer Dabbelt, Alistair Francis,
Bin Meng, Weiwei Li, Daniel Henrique Barboza, Liu Zhiwei,
open list:ARM TCG CPUs, open list:RISC-V TCG CPUs
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>
---
include/exec/gdbstub.h | 3 +++
gdbstub/gdbstub.c | 8 ++++++--
target/arm/gdbstub.c | 2 +-
target/riscv/gdbstub.c | 4 +---
scripts/feature_to_c.py | 14 +++++++++++++-
5 files changed, 24 insertions(+), 7 deletions(-)
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 572abada63..f3f2c40b1a 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;
} GDBFeatureBuilder;
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index 4648a56088..e52a739491 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -418,9 +418,10 @@ void gdb_feature_builder_init(GDBFeatureBuilder *builder, GDBFeature *feature,
builder->feature = feature;
builder->xml = g_ptr_array_new();
+ builder->regs = g_ptr_array_new();
g_ptr_array_add(builder->xml, header);
feature->xmlname = xmlname;
- feature->num_regs = 0;
+ feature->name = name;
}
void gdb_feature_builder_append_tag(const GDBFeatureBuilder *builder,
@@ -449,7 +450,7 @@ void gdb_feature_builder_append_reg(const GDBFeatureBuilder *builder,
name, bitsize, type);
}
- builder->feature->num_regs++;
+ g_ptr_array_add(builder->regs, (void *)name);
}
void gdb_feature_builder_end(const GDBFeatureBuilder *builder)
@@ -464,6 +465,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/arm/gdbstub.c b/target/arm/gdbstub.c
index fc5ed89e80..dbc396a88b 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -264,7 +264,7 @@ static void arm_gen_one_feature_sysreg(GDBFeatureBuilder *builder,
ARMCPRegInfo *ri, uint32_t ri_key,
int bitsize)
{
- dyn_feature->data.cpregs.keys[dyn_feature->desc.num_regs] = ri_key;
+ dyn_feature->data.cpregs.keys[builder->regs->len] = ri_key;
gdb_feature_builder_append_reg(builder, ri->name, bitsize,
"int", "cp_regs");
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
index d4f9eb1516..a2ec9a3701 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -240,11 +240,9 @@ static GDBFeature *riscv_gen_dynamic_csr_feature(CPUState *cs)
}
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,
diff --git a/scripts/feature_to_c.py b/scripts/feature_to_c.py
index e04d6b2df7..807af0e685 100755
--- 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.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 18/26] target/arm: Remove references to gdb_has_xml
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (16 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 17/26] gdbstub: Add members to identify registers to GDBFeature Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-30 15:02 ` Alex Bennée
2023-08-18 3:36 ` [PATCH RESEND v5 19/26] target/ppc: " Akihiko Odaki
` (7 subsequent siblings)
25 siblings, 1 reply; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Peter Maydell, open list:ARM TCG CPUs
GDB has XML support since 6.7 which was released in 2007.
It's time to remove support for old GDB versions without XML support.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
target/arm/gdbstub.c | 32 ++------------------------------
1 file changed, 2 insertions(+), 30 deletions(-)
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index dbc396a88b..4cccaa42e0 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -45,21 +45,7 @@ int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
/* Core integer register. */
return gdb_get_reg32(mem_buf, env->regs[n]);
}
- if (n < 24) {
- /* FPA registers. */
- if (gdb_has_xml) {
- return 0;
- }
- return gdb_get_zeroes(mem_buf, 12);
- }
- switch (n) {
- case 24:
- /* FPA status register. */
- if (gdb_has_xml) {
- return 0;
- }
- return gdb_get_reg32(mem_buf, 0);
- case 25:
+ if (n == 25) {
/* CPSR, or XPSR for M-profile */
if (arm_feature(env, ARM_FEATURE_M)) {
return gdb_get_reg32(mem_buf, xpsr_read(env));
@@ -99,21 +85,7 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
env->regs[n] = tmp;
return 4;
}
- if (n < 24) { /* 16-23 */
- /* FPA registers (ignored). */
- if (gdb_has_xml) {
- return 0;
- }
- return 12;
- }
- switch (n) {
- case 24:
- /* FPA status register (ignored). */
- if (gdb_has_xml) {
- return 0;
- }
- return 4;
- case 25:
+ if (n == 25) {
/* CPSR, or XPSR for M-profile */
if (arm_feature(env, ARM_FEATURE_M)) {
/*
--
2.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 19/26] target/ppc: Remove references to gdb_has_xml
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (17 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 18/26] target/arm: Remove references to gdb_has_xml Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-25 9:40 ` Nicholas Piggin
2023-08-18 3:36 ` [PATCH RESEND v5 20/26] gdbstub: Remove gdb_has_xml variable Akihiko Odaki
` (6 subsequent siblings)
25 siblings, 1 reply; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Daniel Henrique Barboza, Cédric Le Goater,
David Gibson, Greg Kurz, Nicholas Piggin,
open list:PowerPC TCG CPUs
GDB has XML support since 6.7 which was released in 2007.
It's time to remove support for old GDB versions without XML support.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
target/ppc/gdbstub.c | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c
index c86b7055ca..7e3b67a234 100644
--- a/target/ppc/gdbstub.c
+++ b/target/ppc/gdbstub.c
@@ -54,12 +54,6 @@ static int ppc_gdb_register_len(int n)
case 0 ... 31:
/* gprs */
return sizeof(target_ulong);
- case 32 ... 63:
- /* fprs */
- if (gdb_has_xml) {
- return 0;
- }
- return 8;
case 66:
/* cr */
case 69:
@@ -74,12 +68,6 @@ static int ppc_gdb_register_len(int n)
case 68:
/* ctr */
return sizeof(target_ulong);
- case 70:
- /* fpscr */
- if (gdb_has_xml) {
- return 0;
- }
- return sizeof(target_ulong);
default:
return 0;
}
--
2.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 20/26] gdbstub: Remove gdb_has_xml variable
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (18 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 19/26] target/ppc: " Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-30 15:02 ` Alex Bennée
2023-08-18 3:36 ` [PATCH RESEND v5 21/26] gdbstub: Expose functions to read registers Akihiko Odaki
` (5 subsequent siblings)
25 siblings, 1 reply; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Philippe Mathieu-Daudé
GDB has XML support since 6.7 which was released in 2007.
It's time to remove support for old GDB versions without XML support.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
include/exec/gdbstub.h | 8 --------
gdbstub/gdbstub.c | 13 -------------
gdbstub/softmmu.c | 1 -
gdbstub/user.c | 1 -
4 files changed, 23 deletions(-)
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index f3f2c40b1a..5cba2933d2 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -61,14 +61,6 @@ const GDBFeature *gdb_find_static_feature(const char *xmlname);
void gdb_set_stop_cpu(CPUState *cpu);
-/**
- * gdb_has_xml:
- * This is an ugly hack to cope with both new and old gdb.
- * If gdb sends qXfer:features:read then assume we're talking to a newish
- * gdb that understands target descriptions.
- */
-extern bool gdb_has_xml;
-
/* in gdbstub-xml.c, generated by scripts/feature_to_c.py */
extern const GDBFeature gdb_static_features[];
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index e52a739491..55819f4aba 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -74,8 +74,6 @@ void gdb_init_gdbserver_state(void)
gdbserver_state.sstep_flags &= gdbserver_state.supported_sstep_flags;
}
-bool gdb_has_xml;
-
/* writes 2*len+1 bytes in buf */
void gdb_memtohex(GString *buf, const uint8_t *mem, int len)
{
@@ -1121,11 +1119,6 @@ static void handle_set_reg(GArray *params, void *user_ctx)
{
int reg_size;
- if (!gdb_has_xml) {
- gdb_put_packet("");
- return;
- }
-
if (params->len != 2) {
gdb_put_packet("E22");
return;
@@ -1142,11 +1135,6 @@ static void handle_get_reg(GArray *params, void *user_ctx)
{
int reg_size;
- if (!gdb_has_xml) {
- gdb_put_packet("");
- return;
- }
-
if (!params->len) {
gdb_put_packet("E14");
return;
@@ -1609,7 +1597,6 @@ static void handle_query_xfer_features(GArray *params, void *user_ctx)
return;
}
- gdb_has_xml = true;
p = get_param(params, 0)->data;
xml = get_feature_xml(p, &p, process);
if (!xml) {
diff --git a/gdbstub/softmmu.c b/gdbstub/softmmu.c
index 5282324764..42645d2220 100644
--- a/gdbstub/softmmu.c
+++ b/gdbstub/softmmu.c
@@ -97,7 +97,6 @@ static void gdb_chr_event(void *opaque, QEMUChrEvent event)
vm_stop(RUN_STATE_PAUSED);
replay_gdb_attached();
- gdb_has_xml = false;
break;
default:
break;
diff --git a/gdbstub/user.c b/gdbstub/user.c
index 5b375be1d9..7ab6e5d975 100644
--- a/gdbstub/user.c
+++ b/gdbstub/user.c
@@ -198,7 +198,6 @@ static void gdb_accept_init(int fd)
gdbserver_state.c_cpu = gdb_first_attached_cpu();
gdbserver_state.g_cpu = gdbserver_state.c_cpu;
gdbserver_user_state.fd = fd;
- gdb_has_xml = false;
}
static bool gdb_accept_socket(int gdb_fd)
--
2.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 21/26] gdbstub: Expose functions to read registers
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (19 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 20/26] gdbstub: Remove gdb_has_xml variable Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 22/26] cpu: Call plugin hooks only when ready Akihiko Odaki
` (4 subsequent siblings)
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Philippe Mathieu-Daudé
gdb_foreach_feature() enumerates features that are useful to identify
registers. gdb_read_register() actually reads registers.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
include/exec/gdbstub.h | 6 ++++++
gdbstub/gdbstub.c | 20 +++++++++++++++++++-
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 5cba2933d2..1208fafa33 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -59,6 +59,12 @@ void gdb_feature_builder_end(const GDBFeatureBuilder *builder);
const GDBFeature *gdb_find_static_feature(const char *xmlname);
+void gdb_foreach_feature(CPUState *cpu,
+ void (* callback)(void *, const GDBFeature *, int),
+ void *opaque);
+
+int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
+
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 55819f4aba..41fad40b6c 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -481,7 +481,25 @@ const GDBFeature *gdb_find_static_feature(const char *xmlname)
g_assert_not_reached();
}
-static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
+void gdb_foreach_feature(CPUState *cpu,
+ void (* callback)(void *, const GDBFeature *, int),
+ void *opaque)
+{
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ GDBRegisterState *r;
+
+ if (!cc->gdb_core_feature) {
+ return;
+ }
+
+ callback(opaque, cc->gdb_core_feature, 0);
+
+ for (r = cpu->gdb_regs; r; r = r->next) {
+ callback(opaque, r->feature, r->base_reg);
+ }
+}
+
+int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
CPUArchState *env = cpu->env_ptr;
--
2.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 22/26] cpu: Call plugin hooks only when ready
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (20 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 21/26] gdbstub: Expose functions to read registers Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-30 15:04 ` Alex Bennée
2023-08-18 3:36 ` [PATCH RESEND v5 23/26] plugins: Allow to read registers Akihiko Odaki
` (3 subsequent siblings)
25 siblings, 1 reply; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Eduardo Habkost, Marcel Apfelbaum,
Philippe Mathieu-Daudé, Yanan Wang
The initialization and exit hooks will not affect the state of vCPU,
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>
---
cpu.c | 11 -----------
hw/core/cpu-common.c | 10 ++++++++++
2 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/cpu.c b/cpu.c
index 1c948d1161..2552c85249 100644
--- a/cpu.c
+++ b/cpu.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;
@@ -148,11 +147,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);
@@ -179,11 +173,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 ced66c2b34..be1544687e 100644
--- a/hw/core/cpu-common.c
+++ b/hw/core/cpu-common.c
@@ -209,6 +209,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 */
}
@@ -216,6 +221,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.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 23/26] plugins: Allow to read registers
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (21 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 22/26] cpu: Call plugin hooks only when ready Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 24/26] contrib/plugins: Allow to log registers Akihiko Odaki
` (2 subsequent siblings)
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Alexandre Iooss, Mahmoud Mandour
It is based on GDB protocol to ensure interface stability.
The timing of the vcpu init hook is also changed so that the hook will
get called after GDB features are initialized.
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1706
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
include/qemu/qemu-plugin.h | 65 ++++++++++++++++++++++++++++++++++--
plugins/api.c | 40 ++++++++++++++++++++++
plugins/qemu-plugins.symbols | 2 ++
3 files changed, 104 insertions(+), 3 deletions(-)
diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
index 50a9957279..214b12bfd6 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>
@@ -51,7 +52,7 @@ typedef uint64_t qemu_plugin_id_t;
extern QEMU_PLUGIN_EXPORT int qemu_plugin_version;
-#define QEMU_PLUGIN_VERSION 1
+#define QEMU_PLUGIN_VERSION 2
/**
* struct qemu_info_t - system information for plugins
@@ -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,62 @@ uint64_t qemu_plugin_end_code(void);
*/
uint64_t qemu_plugin_entry_code(void);
+/**
+ * struct qemu_plugin_register_file_t - register information
+ *
+ * This structure identifies registers. The identifiers included in this
+ * structure are identical with names used in GDB's standard target features
+ * with some extensions. For details, see:
+ * https://sourceware.org/gdb/onlinedocs/gdb/Standard-Target-Features.html
+ *
+ * A register is uniquely identified with the combination of a feature name
+ * and a register name or a register number. It is recommended to derive
+ * register numbers from feature names and register names each time a new vcpu
+ * starts.
+ *
+ * To derive the register number from a feature name and a register name,
+ * first look up qemu_plugin_register_file_t with the feature name, and then
+ * look up the register name in its @regs. The sum of the @base_reg and the
+ * index in the @reg is the register number.
+ *
+ * Note that @regs may have holes; some elements of @regs may be NULL.
+ */
+typedef struct qemu_plugin_register_file_t {
+ /** @name: feature name */
+ const char *name;
+ /** @regs: register names */
+ const char * const *regs;
+ /** @base_reg: the base identified number */
+ int base_reg;
+ /** @num_regs: the number of elements in @regs */
+ int num_regs;
+} qemu_plugin_register_file_t;
+
+/**
+ * qemu_plugin_get_register_files() - returns register information
+ *
+ * @vcpu_index: the index of the vcpu context
+ * @size: the pointer to the variable to hold the number of returned elements
+ *
+ * Returns an array of qemu_plugin_register_file_t. The user should g_free()
+ * the array once no longer needed.
+ */
+qemu_plugin_register_file_t *
+qemu_plugin_get_register_files(unsigned int vcpu_index, int *size);
+
+/**
+ * qemu_plugin_read_register() - read register
+ *
+ * @buf: the byte array to append the read register content to.
+ * @reg: the register identifier determined with
+ * qemu_plugin_get_register_files().
+ *
+ * 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.
+ */
+int qemu_plugin_read_register(GByteArray *buf, int reg);
+
#endif /* QEMU_QEMU_PLUGIN_H */
diff --git a/plugins/api.c b/plugins/api.c
index 2078b16edb..e1b22c98f5 100644
--- a/plugins/api.c
+++ b/plugins/api.c
@@ -35,6 +35,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
#include "qemu/plugin.h"
#include "qemu/log.h"
#include "tcg/tcg.h"
@@ -442,3 +443,42 @@ uint64_t qemu_plugin_entry_code(void)
#endif
return entry;
}
+
+static void count_gdb_feature(void *opaque, const GDBFeature *feature,
+ int base_reg)
+{
+ (*(int *)opaque)++;
+}
+
+static void map_gdb_feature(void *opaque, const GDBFeature *feature,
+ int base_reg)
+{
+ qemu_plugin_register_file_t **cursor = opaque;
+ (*cursor)->name = feature->name;
+ (*cursor)->regs = feature->regs;
+ (*cursor)->base_reg = base_reg;
+ (*cursor)->num_regs = feature->num_regs;
+ (*cursor)++;
+}
+
+qemu_plugin_register_file_t *
+qemu_plugin_get_register_files(unsigned int vcpu_index, int *size)
+{
+ QEMU_IOTHREAD_LOCK_GUARD();
+
+ *size = 0;
+ gdb_foreach_feature(qemu_get_cpu(vcpu_index), count_gdb_feature, size);
+
+ qemu_plugin_register_file_t *files =
+ g_new(qemu_plugin_register_file_t, *size);
+
+ qemu_plugin_register_file_t *cursor = files;
+ gdb_foreach_feature(qemu_get_cpu(vcpu_index), map_gdb_feature, &cursor);
+
+ return files;
+}
+
+int qemu_plugin_read_register(GByteArray *buf, int reg)
+{
+ return gdb_read_register(current_cpu, buf, reg);
+}
diff --git a/plugins/qemu-plugins.symbols b/plugins/qemu-plugins.symbols
index 71f6c90549..4ed9e70e47 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_get_register_files;
+ qemu_plugin_read_register;
};
--
2.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 24/26] contrib/plugins: Allow to log registers
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (22 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 23/26] plugins: Allow to read registers Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-30 15:08 ` Alex Bennée
2023-08-18 3:36 ` [PATCH RESEND v5 25/26] plugins: Support C++ Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 26/26] contrib/plugins: Add cc plugin Akihiko Odaki
25 siblings, 1 reply; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Alexandre Iooss, Mahmoud Mandour,
Richard Henderson, Paolo Bonzini
This demonstrates how a register can be read from a plugin.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
docs/devel/tcg-plugins.rst | 10 ++-
contrib/plugins/execlog.c | 140 ++++++++++++++++++++++++++++---------
2 files changed, 117 insertions(+), 33 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..aa05840fd0 100644
--- a/contrib/plugins/execlog.c
+++ b/contrib/plugins/execlog.c
@@ -15,27 +15,43 @@
#include <qemu-plugin.h>
+typedef struct CPU {
+ /* Store last executed instruction on each vCPU as a GString */
+ GString *last_exec;
+ GByteArray *reg_history[2];
+
+ int reg;
+} 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;
+static char *rfile_name;
+static char *reg_name;
+
/*
- * Expand last_exec array.
+ * Expand cpu 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)
+static void expand_cpu(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);
+ if (cpu_index >= num_cpus) {
+ cpus = g_realloc_n(cpus, cpu_index + 1, sizeof(*cpus));
+ while (cpu_index >= num_cpus) {
+ cpus[num_cpus].last_exec = g_string_new(NULL);
+ cpus[num_cpus].reg_history[0] = g_byte_array_new();
+ cpus[num_cpus].reg_history[1] = g_byte_array_new();
+ num_cpus++;
+ }
}
g_rw_lock_writer_unlock(&expand_array_lock);
}
@@ -50,8 +66,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 +93,42 @@ 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;
+ int n;
+ int i;
- /* 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_rw_lock_reader_unlock(&expand_array_lock);
/* Print previous instruction in cache */
- if (s->len) {
- qemu_plugin_outs(s->str);
+ if (cpus[cpu_index].last_exec->len) {
+ if (cpus[cpu_index].reg >= 0) {
+ GByteArray *current = cpus[cpu_index].reg_history[0];
+ GByteArray *last = cpus[cpu_index].reg_history[1];
+
+ g_byte_array_set_size(current, 0);
+ n = qemu_plugin_read_register(current, cpus[cpu_index].reg);
+
+ if (n != last->len || memcmp(current->data, last->data, n)) {
+ g_string_append(cpus[cpu_index].last_exec, ", reg,");
+ for (i = 0; i < n; i++) {
+ g_string_append_printf(cpus[cpu_index].last_exec, " %02x",
+ current->data[i]);
+ }
+ }
+
+ cpus[cpu_index].reg_history[0] = last;
+ cpus[cpu_index].reg_history[1] = current;
+ }
+
+ 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);
+
+ g_rw_lock_reader_unlock(&expand_array_lock);
}
/**
@@ -167,8 +197,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,
+ rfile_name ? QEMU_PLUGIN_CB_R_REGS : QEMU_PLUGIN_CB_NO_REGS,
+ output);
/* reset skip */
skip = (imatches || amatches);
@@ -177,17 +209,53 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
}
}
+static void vcpu_init(qemu_plugin_id_t id, unsigned int vcpu_index)
+{
+ int reg = 0;
+ bool found = false;
+
+ expand_cpu(vcpu_index);
+
+ if (rfile_name) {
+ int i;
+ int j;
+ int n;
+
+ qemu_plugin_register_file_t *rfiles =
+ qemu_plugin_get_register_files(vcpu_index, &n);
+
+ for (i = 0; i < n; i++) {
+ if (g_strcmp0(rfiles[i].name, rfile_name) == 0) {
+ for (j = 0; j < rfiles[i].num_regs; j++) {
+ if (g_strcmp0(rfiles[i].regs[j], reg_name) == 0) {
+ reg += j;
+ found = true;
+ break;
+ }
+ }
+ break;
+ }
+
+ reg += rfiles[i].num_regs;
+ }
+
+ g_free(rfiles);
+ }
+
+ g_rw_lock_writer_lock(&expand_array_lock);
+ cpus[vcpu_index].reg = found ? reg : -1;
+ 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");
}
}
@@ -224,9 +292,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 +302,23 @@ 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], "rfile") == 0) {
+ rfile_name = g_strdup(tokens[1]);
+ } else if (g_strcmp0(tokens[0], "reg") == 0) {
+ reg_name = g_strdup(tokens[1]);
} else {
fprintf(stderr, "option parsing failed: %s\n", opt);
return -1;
}
}
+ if ((!rfile_name) != (!reg_name)) {
+ fputs("file and reg need to be set at the same time\n", stderr);
+ return -1;
+ }
+
/* Register 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.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 25/26] plugins: Support C++
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (23 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 24/26] contrib/plugins: Allow to log registers Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 26/26] contrib/plugins: Add cc plugin Akihiko Odaki
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki
Make qemu-plugin.h consumable for C++ platform.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
include/qemu/qemu-plugin.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
index 214b12bfd6..8637e3d8cf 100644
--- a/include/qemu/qemu-plugin.h
+++ b/include/qemu/qemu-plugin.h
@@ -16,6 +16,8 @@
#include <stdbool.h>
#include <stddef.h>
+G_BEGIN_DECLS
+
/*
* For best performance, build the plugin with -fvisibility=hidden so that
* QEMU_PLUGIN_LOCAL is implicit. Then, just mark qemu_plugin_install with
@@ -723,4 +725,6 @@ qemu_plugin_get_register_files(unsigned int vcpu_index, int *size);
*/
int qemu_plugin_read_register(GByteArray *buf, int reg);
+G_END_DECLS
+
#endif /* QEMU_QEMU_PLUGIN_H */
--
2.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH RESEND v5 26/26] contrib/plugins: Add cc plugin
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
` (24 preceding siblings ...)
2023-08-18 3:36 ` [PATCH RESEND v5 25/26] plugins: Support C++ Akihiko Odaki
@ 2023-08-18 3:36 ` Akihiko Odaki
25 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-18 3:36 UTC (permalink / raw)
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Akihiko Odaki, Paolo Bonzini, Thomas Huth, Alexandre Iooss,
Mahmoud Mandour, Richard Henderson, Philippe Mathieu-Daudé
This demonstrates how to write a plugin in C++.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
docs/devel/tcg-plugins.rst | 8 ++++++++
configure | 15 ++++++++++++---
contrib/plugins/Makefile | 5 +++++
contrib/plugins/cc.cc | 17 +++++++++++++++++
tests/tcg/Makefile.target | 3 +++
5 files changed, 45 insertions(+), 3 deletions(-)
create mode 100644 contrib/plugins/cc.cc
diff --git a/docs/devel/tcg-plugins.rst b/docs/devel/tcg-plugins.rst
index c9f8b27590..0a11f8036c 100644
--- a/docs/devel/tcg-plugins.rst
+++ b/docs/devel/tcg-plugins.rst
@@ -584,6 +584,14 @@ The plugin has a number of arguments, all of them are optional:
configuration arguments implies ``l2=on``.
(default: N = 2097152 (2MB), B = 64, A = 16)
+- contrib/plugins/cc.cc
+
+cc plugin demonstrates how to write a plugin in C++. It simply outputs
+"hello, world" to the plugin log::
+
+ $ qemu-system-arm $(QEMU_ARGS) \
+ -plugin ./contrib/plugins/libcc.so -d plugin
+
API
---
diff --git a/configure b/configure
index 26ec5e4f54..0065b0dfe0 100755
--- a/configure
+++ b/configure
@@ -293,10 +293,18 @@ else
cc="${CC-${cross_prefix}gcc}"
fi
-if test -z "${CXX}${cross_prefix}"; then
- cxx="c++"
+if test -n "${CXX+x}"; then
+ cxx="$CXX"
else
- cxx="${CXX-${cross_prefix}g++}"
+ if test -n "${cross_prefix}"; then
+ cxx="${cross_prefix}g++"
+ else
+ cxx="c++"
+ fi
+
+ if ! has "$cxx"; then
+ cxx=
+ fi
fi
# Preferred ObjC compiler:
@@ -1702,6 +1710,7 @@ echo "MESON=$meson" >> $config_host_mak
echo "NINJA=$ninja" >> $config_host_mak
echo "PKG_CONFIG=${pkg_config}" >> $config_host_mak
echo "CC=$cc" >> $config_host_mak
+echo "CXX=$cxx" >> $config_host_mak
echo "EXESUF=$EXESUF" >> $config_host_mak
# use included Linux headers
diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile
index b2b9db9f51..93d86b3d07 100644
--- a/contrib/plugins/Makefile
+++ b/contrib/plugins/Makefile
@@ -21,6 +21,9 @@ NAMES += lockstep
NAMES += hwprofile
NAMES += cache
NAMES += drcov
+ifneq ($(CXX),)
+NAMES += cc
+endif
SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES)))
@@ -31,6 +34,8 @@ CFLAGS += -fPIC -Wall
CFLAGS += $(if $(CONFIG_DEBUG_TCG), -ggdb -O0)
CFLAGS += -I$(SRC_PATH)/include/qemu
+CXXFLAGS := $(CFLAGS)
+
all: $(SONAMES)
%.o: %.c
diff --git a/contrib/plugins/cc.cc b/contrib/plugins/cc.cc
new file mode 100644
index 0000000000..83a5528db0
--- /dev/null
+++ b/contrib/plugins/cc.cc
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <qemu-plugin.h>
+
+extern "C" {
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
+ const qemu_info_t *info, int argc,
+ char **argv)
+{
+ qemu_plugin_outs("hello, world\n");
+ return 0;
+}
+
+};
diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target
index 462289f47c..3d7837d3b8 100644
--- a/tests/tcg/Makefile.target
+++ b/tests/tcg/Makefile.target
@@ -149,6 +149,9 @@ PLUGIN_SRC=$(SRC_PATH)/tests/plugin
PLUGIN_LIB=../../plugin
VPATH+=$(PLUGIN_LIB)
PLUGINS=$(patsubst %.c, lib%.so, $(notdir $(wildcard $(PLUGIN_SRC)/*.c)))
+ifneq ($(CXX),)
+PLUGINS+=$(patsubst %.cc, lib%.so, $(notdir $(wildcard $(PLUGIN_SRC)/*.cc)))
+endif
# We need to ensure expand the run-plugin-TEST-with-PLUGIN
# pre-requistes manually here as we can't use stems to handle it. We
--
2.41.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* Re: [PATCH RESEND v5 19/26] target/ppc: Remove references to gdb_has_xml
2023-08-18 3:36 ` [PATCH RESEND v5 19/26] target/ppc: " Akihiko Odaki
@ 2023-08-25 9:40 ` Nicholas Piggin
0 siblings, 0 replies; 38+ messages in thread
From: Nicholas Piggin @ 2023-08-25 9:40 UTC (permalink / raw)
To: Akihiko Odaki
Cc: Alex Bennée, Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Daniel Henrique Barboza, Cédric Le Goater, David Gibson,
Greg Kurz, open list:PowerPC TCG CPUs
On Fri Aug 18, 2023 at 1:36 PM AEST, Akihiko Odaki wrote:
> GDB has XML support since 6.7 which was released in 2007.
> It's time to remove support for old GDB versions without XML support.
These 3 patches might be better to go ahead in a preparation series
with "remove support for gdb 6.7" in the subject so people don't
miss it. You could put a minimum version in docs/system/gdb.rst
too.
For the ppc part,
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
>
> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> ---
> target/ppc/gdbstub.c | 12 ------------
> 1 file changed, 12 deletions(-)
>
> diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c
> index c86b7055ca..7e3b67a234 100644
> --- a/target/ppc/gdbstub.c
> +++ b/target/ppc/gdbstub.c
> @@ -54,12 +54,6 @@ static int ppc_gdb_register_len(int n)
> case 0 ... 31:
> /* gprs */
> return sizeof(target_ulong);
> - case 32 ... 63:
> - /* fprs */
> - if (gdb_has_xml) {
> - return 0;
> - }
> - return 8;
> case 66:
> /* cr */
> case 69:
> @@ -74,12 +68,6 @@ static int ppc_gdb_register_len(int n)
> case 68:
> /* ctr */
> return sizeof(target_ulong);
> - case 70:
> - /* fpscr */
> - if (gdb_has_xml) {
> - return 0;
> - }
> - return sizeof(target_ulong);
> default:
> return 0;
> }
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH RESEND v5 12/26] gdbstub: Use GDBFeature for GDBRegisterState
2023-08-18 3:36 ` [PATCH RESEND v5 12/26] gdbstub: Use GDBFeature for GDBRegisterState Akihiko Odaki
@ 2023-08-30 14:59 ` Alex Bennée
0 siblings, 0 replies; 38+ messages in thread
From: Alex Bennée @ 2023-08-30 14:59 UTC (permalink / raw)
To: Akihiko Odaki
Cc: Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Philippe Mathieu-Daudé
Akihiko Odaki <akihiko.odaki@daynix.com> writes:
> 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>
> ---
> gdbstub/gdbstub.c | 14 ++++++--------
> 1 file changed, 6 insertions(+), 8 deletions(-)
>
> diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
> index b62002bc34..ee6b8b98c8 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;
> struct GDBRegisterState *next;
> } GDBRegisterState;
>
> @@ -390,7 +389,7 @@ static const char *get_feature_xml(const char *p, const char **newp,
> pstrcat(buf, buf_sz, "\"/>");
> for (r = cpu->gdb_regs; r; r = r->next) {
> pstrcat(buf, buf_sz, "<xi:include href=\"");
> - pstrcat(buf, buf_sz, r->xml);
> + pstrcat(buf, buf_sz, r->feature->xmlname);
> pstrcat(buf, buf_sz, "\"/>");
> }
I should note I've done some cleaning up of the XML code in the gdbstub
so you'll probably want to re-base once the PR has gone in.
> pstrcat(buf, buf_sz, "</target>");
> @@ -497,7 +496,7 @@ static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
> }
>
> for (r = cpu->gdb_regs; r; r = r->next) {
> - 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);
> }
> }
> @@ -515,7 +514,7 @@ static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
> }
>
> for (r = cpu->gdb_regs; r; r = r->next) {
> - 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);
> }
> }
> @@ -538,17 +537,16 @@ void gdb_register_coprocessor(CPUState *cpu,
> p = &cpu->gdb_regs;
> while (*p) {
> /* Check for duplicates. */
> - if (strcmp((*p)->xml, feature->xmlname) == 0)
> + if ((*p)->feature == feature)
> return;
> p = &(*p)->next;
> }
>
> s = g_new0(GDBRegisterState, 1);
> 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;
Otherwise:
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH RESEND v5 13/26] hw/core/cpu: Return static value with gdb_arch_name()
2023-08-18 3:36 ` [PATCH RESEND v5 13/26] hw/core/cpu: Return static value with gdb_arch_name() Akihiko Odaki
@ 2023-08-30 15:00 ` Alex Bennée
0 siblings, 0 replies; 38+ messages in thread
From: Alex Bennée @ 2023-08-30 15:00 UTC (permalink / raw)
To: Akihiko Odaki
Cc: Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Philippe Mathieu-Daudé, Eduardo Habkost, Marcel Apfelbaum,
Yanan Wang, Peter Maydell, Song Gao, Xiaojuan Yang,
Daniel Henrique Barboza, Cédric Le Goater, David Gibson,
Greg Kurz, Nicholas Piggin, Palmer Dabbelt, Alistair Francis,
Bin Meng, Weiwei Li, Liu Zhiwei, Richard Henderson,
David Hildenbrand, Ilya Leoshkevich, Thomas Huth,
Bastian Koppelmann, open list:ARM TCG CPUs,
open list:PowerPC TCG CPUs, open list:RISC-V TCG CPUs,
open list:S390 TCG CPUs
Akihiko Odaki <akihiko.odaki@daynix.com> writes:
> All implementations of gdb_arch_name() returns dynamic duplicates of
> static strings. It's also unlikely that there will be an implementation
> of gdb_arch_name() that returns a truly dynamic value due to the nature
> of the function returning a well-known identifiers. Qualify the value
> gdb_arch_name() with const and make all of its implementations return
> static strings.
>
> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH RESEND v5 18/26] target/arm: Remove references to gdb_has_xml
2023-08-18 3:36 ` [PATCH RESEND v5 18/26] target/arm: Remove references to gdb_has_xml Akihiko Odaki
@ 2023-08-30 15:02 ` Alex Bennée
0 siblings, 0 replies; 38+ messages in thread
From: Alex Bennée @ 2023-08-30 15:02 UTC (permalink / raw)
To: Akihiko Odaki
Cc: Mikhail Tyutin, Aleksandr Anenkov, qemu-devel, Peter Maydell,
open list:ARM TCG CPUs
Akihiko Odaki <akihiko.odaki@daynix.com> writes:
> GDB has XML support since 6.7 which was released in 2007.
> It's time to remove support for old GDB versions without XML support.
>
> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Acked-by: Alex Bennée <alex.bennee@linaro.org>
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH RESEND v5 20/26] gdbstub: Remove gdb_has_xml variable
2023-08-18 3:36 ` [PATCH RESEND v5 20/26] gdbstub: Remove gdb_has_xml variable Akihiko Odaki
@ 2023-08-30 15:02 ` Alex Bennée
2023-08-30 20:24 ` Akihiko Odaki
0 siblings, 1 reply; 38+ messages in thread
From: Alex Bennée @ 2023-08-30 15:02 UTC (permalink / raw)
To: Akihiko Odaki
Cc: Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Philippe Mathieu-Daudé
Akihiko Odaki <akihiko.odaki@daynix.com> writes:
> GDB has XML support since 6.7 which was released in 2007.
> It's time to remove support for old GDB versions without XML support.
>
> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
In principle I'm fine with this but should we not catch GDB's which
don't send qXfer:features:read earlier?
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH RESEND v5 22/26] cpu: Call plugin hooks only when ready
2023-08-18 3:36 ` [PATCH RESEND v5 22/26] cpu: Call plugin hooks only when ready Akihiko Odaki
@ 2023-08-30 15:04 ` Alex Bennée
0 siblings, 0 replies; 38+ messages in thread
From: Alex Bennée @ 2023-08-30 15:04 UTC (permalink / raw)
To: Akihiko Odaki
Cc: Mikhail Tyutin, Aleksandr Anenkov, qemu-devel, Eduardo Habkost,
Marcel Apfelbaum, Philippe Mathieu-Daudé, Yanan Wang
Akihiko Odaki <akihiko.odaki@daynix.com> writes:
> The initialization and exit hooks will not affect the state of vCPU,
> 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>
Acked-by: Alex Bennée <alex.bennee@linaro.org>
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH RESEND v5 24/26] contrib/plugins: Allow to log registers
2023-08-18 3:36 ` [PATCH RESEND v5 24/26] contrib/plugins: Allow to log registers Akihiko Odaki
@ 2023-08-30 15:08 ` Alex Bennée
2023-08-30 20:53 ` Akihiko Odaki
0 siblings, 1 reply; 38+ messages in thread
From: Alex Bennée @ 2023-08-30 15:08 UTC (permalink / raw)
To: Akihiko Odaki
Cc: Mikhail Tyutin, Aleksandr Anenkov, qemu-devel, Alexandre Iooss,
Mahmoud Mandour, Richard Henderson, Paolo Bonzini
Akihiko Odaki <akihiko.odaki@daynix.com> writes:
> This demonstrates how a register can be read from a plugin.
>
> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> ---
> docs/devel/tcg-plugins.rst | 10 ++-
> contrib/plugins/execlog.c | 140 ++++++++++++++++++++++++++++---------
> 2 files changed, 117 insertions(+), 33 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..aa05840fd0 100644
> --- a/contrib/plugins/execlog.c
> +++ b/contrib/plugins/execlog.c
> @@ -15,27 +15,43 @@
>
> #include <qemu-plugin.h>
>
> +typedef struct CPU {
> + /* Store last executed instruction on each vCPU as a GString */
> + GString *last_exec;
> + GByteArray *reg_history[2];
> +
> + int reg;
> +} CPU;
> +
> QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
>
<snip>
>
> /* 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);
> +
> + g_rw_lock_reader_unlock(&expand_array_lock);
> }
>
> /**
> @@ -167,8 +197,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,
> + rfile_name ? QEMU_PLUGIN_CB_R_REGS : QEMU_PLUGIN_CB_NO_REGS,
> + output);
>
> /* reset skip */
> skip = (imatches || amatches);
> @@ -177,17 +209,53 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
> }
> }
>
> +static void vcpu_init(qemu_plugin_id_t id, unsigned int vcpu_index)
> +{
> + int reg = 0;
> + bool found = false;
> +
> + expand_cpu(vcpu_index);
> +
> + if (rfile_name) {
> + int i;
> + int j;
> + int n;
> +
> + qemu_plugin_register_file_t *rfiles =
> + qemu_plugin_get_register_files(vcpu_index, &n);
> +
> + for (i = 0; i < n; i++) {
> + if (g_strcmp0(rfiles[i].name, rfile_name) == 0) {
> + for (j = 0; j < rfiles[i].num_regs; j++) {
> + if (g_strcmp0(rfiles[i].regs[j], reg_name) == 0) {
> + reg += j;
> + found = true;
> + break;
> + }
> + }
> + break;
> + }
> +
> + reg += rfiles[i].num_regs;
> + }
> +
> + g_free(rfiles);
> + }
This makes me question the value of exposing the register file directly
to the plugin. I would much rather have a lookup utility function with
an optional tag. Something like:
plugin_reg_t qemu_plugin_find_register(const char *name, const char *tag);
And make tag optional. I think in the general case "name" should be enough.
> +
> + g_rw_lock_writer_lock(&expand_array_lock);
> + cpus[vcpu_index].reg = found ? reg : -1;
> + 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");
> }
> }
> @@ -224,9 +292,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 +302,23 @@ 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], "rfile") == 0) {
> + rfile_name = g_strdup(tokens[1]);
> + } else if (g_strcmp0(tokens[0], "reg") == 0) {
> + reg_name = g_strdup(tokens[1]);
And then instead of having the rfile/reg distinction support a command
line like:
qemu-aarch64 -plugin contrib/plugins/libexeclog.so,reg=sp,reg=x1,reg=sve:p1
so if the user specifies a reg of the form TAG:REG we can pass that as
the option tag string. It also avoids exposing all the details of gdb to
plugins while still allowing the utility function to search by rname
internally (even if only a substring match?),
> } else {
> fprintf(stderr, "option parsing failed: %s\n", opt);
> return -1;
> }
> }
>
> + if ((!rfile_name) != (!reg_name)) {
> + fputs("file and reg need to be set at the same time\n", stderr);
> + return -1;
> + }
> +
> /* Register 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);
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH RESEND v5 20/26] gdbstub: Remove gdb_has_xml variable
2023-08-30 15:02 ` Alex Bennée
@ 2023-08-30 20:24 ` Akihiko Odaki
0 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-30 20:24 UTC (permalink / raw)
To: Alex Bennée
Cc: Mikhail Tyutin, Aleksandr Anenkov, qemu-devel,
Philippe Mathieu-Daudé
On 2023/08/31 0:02, Alex Bennée wrote:
>
> Akihiko Odaki <akihiko.odaki@daynix.com> writes:
>
>> GDB has XML support since 6.7 which was released in 2007.
>> It's time to remove support for old GDB versions without XML support.
>>
>> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
>
> In principle I'm fine with this but should we not catch GDB's which
> don't send qXfer:features:read earlier?
>
I don't think so. qXfer:features:read was introduced very long ago so
practically such a condition should only happen with a failing GDB.
There is nothing special for qXfer:features:read that differentiates
from many other possible GDB failures that we do not catch.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH RESEND v5 24/26] contrib/plugins: Allow to log registers
2023-08-30 15:08 ` Alex Bennée
@ 2023-08-30 20:53 ` Akihiko Odaki
2023-09-04 15:30 ` Alex Bennée
0 siblings, 1 reply; 38+ messages in thread
From: Akihiko Odaki @ 2023-08-30 20:53 UTC (permalink / raw)
To: Alex Bennée
Cc: Mikhail Tyutin, Aleksandr Anenkov, qemu-devel, Alexandre Iooss,
Mahmoud Mandour, Richard Henderson, Paolo Bonzini
On 2023/08/31 0:08, Alex Bennée wrote:
>
> Akihiko Odaki <akihiko.odaki@daynix.com> writes:
>
>> This demonstrates how a register can be read from a plugin.
>>
>> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
>> ---
>> docs/devel/tcg-plugins.rst | 10 ++-
>> contrib/plugins/execlog.c | 140 ++++++++++++++++++++++++++++---------
>> 2 files changed, 117 insertions(+), 33 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..aa05840fd0 100644
>> --- a/contrib/plugins/execlog.c
>> +++ b/contrib/plugins/execlog.c
>> @@ -15,27 +15,43 @@
>>
>> #include <qemu-plugin.h>
>>
>> +typedef struct CPU {
>> + /* Store last executed instruction on each vCPU as a GString */
>> + GString *last_exec;
>> + GByteArray *reg_history[2];
>> +
>> + int reg;
>> +} CPU;
>> +
>> QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
>>
> <snip>
>>
>> /* 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);
>> +
>> + g_rw_lock_reader_unlock(&expand_array_lock);
>> }
>>
>> /**
>> @@ -167,8 +197,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,
>> + rfile_name ? QEMU_PLUGIN_CB_R_REGS : QEMU_PLUGIN_CB_NO_REGS,
>> + output);
>>
>> /* reset skip */
>> skip = (imatches || amatches);
>> @@ -177,17 +209,53 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
>> }
>> }
>>
>> +static void vcpu_init(qemu_plugin_id_t id, unsigned int vcpu_index)
>> +{
>> + int reg = 0;
>> + bool found = false;
>> +
>> + expand_cpu(vcpu_index);
>> +
>> + if (rfile_name) {
>> + int i;
>> + int j;
>> + int n;
>> +
>> + qemu_plugin_register_file_t *rfiles =
>> + qemu_plugin_get_register_files(vcpu_index, &n);
>> +
>> + for (i = 0; i < n; i++) {
>> + if (g_strcmp0(rfiles[i].name, rfile_name) == 0) {
>> + for (j = 0; j < rfiles[i].num_regs; j++) {
>> + if (g_strcmp0(rfiles[i].regs[j], reg_name) == 0) {
>> + reg += j;
>> + found = true;
>> + break;
>> + }
>> + }
>> + break;
>> + }
>> +
>> + reg += rfiles[i].num_regs;
>> + }
>> +
>> + g_free(rfiles);
>> + }
>
> This makes me question the value of exposing the register file directly
> to the plugin. I would much rather have a lookup utility function with
> an optional tag. Something like:
>
> plugin_reg_t qemu_plugin_find_register(const char *name, const char *tag);
>
> And make tag optional. I think in the general case "name" should be enough.
I have explained the reason why I introduced register file abstraction
instead of adding a function to look up a register for an earlier
version of this series:
> I added a function that returns all register information instead of a
> function that looks up a register so that a plugin can enumerate
> registers. Such capability is useful for a plugin that dumps all
> registers or a plugin that simulates processor (such a plugin may want
> to warn if there are unknown registers).
How would you define name and tag? They are something we currently do
not have, and I'm trying to add new types of identifiers since such
identifiers will be needed to be defined for different architectures and
require documentation and extra work to avoid name conflicts and ensure
interface stability.
>
>> +
>> + g_rw_lock_writer_lock(&expand_array_lock);
>> + cpus[vcpu_index].reg = found ? reg : -1;
>> + 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");
>> }
>> }
>> @@ -224,9 +292,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 +302,23 @@ 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], "rfile") == 0) {
>> + rfile_name = g_strdup(tokens[1]);
>> + } else if (g_strcmp0(tokens[0], "reg") == 0) {
>> + reg_name = g_strdup(tokens[1]);
>
> And then instead of having the rfile/reg distinction support a command
> line like:
>
> qemu-aarch64 -plugin contrib/plugins/libexeclog.so,reg=sp,reg=x1,reg=sve:p1
>
> so if the user specifies a reg of the form TAG:REG we can pass that as
> the option tag string. It also avoids exposing all the details of gdb to
> plugins while still allowing the utility function to search by rname
> internally (even if only a substring match?),
That implicitly assumes TAG does not contain a colon. I'm avoiding to
make such an implicit assumption because it is a reference for plugin
writers who may create out-of-tree plugins. We should retrain ourselves
to tell the plugin writers not to make such an assumption that may not
hold in the future version of QEMU.
I consider a substring match harmful for a similar reason. There is no
guarantee that a future version of QEMU will not introduce a new
register that match with the existing substring and break interface
stability.
It is not necessary that identifiers are consistent with ones GDB use.
What matters here is that the identifiers are documented, stable and
immune from conflicts.
>
>
>> } else {
>> fprintf(stderr, "option parsing failed: %s\n", opt);
>> return -1;
>> }
>> }
>>
>> + if ((!rfile_name) != (!reg_name)) {
>> + fputs("file and reg need to be set at the same time\n", stderr);
>> + return -1;
>> + }
>> +
>> /* Register 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);
>
>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH RESEND v5 24/26] contrib/plugins: Allow to log registers
2023-08-30 20:53 ` Akihiko Odaki
@ 2023-09-04 15:30 ` Alex Bennée
2023-09-05 6:51 ` Akihiko Odaki
0 siblings, 1 reply; 38+ messages in thread
From: Alex Bennée @ 2023-09-04 15:30 UTC (permalink / raw)
To: Akihiko Odaki
Cc: Mikhail Tyutin, Aleksandr Anenkov, qemu-devel, Alexandre Iooss,
Mahmoud Mandour, Richard Henderson, Paolo Bonzini
Akihiko Odaki <akihiko.odaki@daynix.com> writes:
> On 2023/08/31 0:08, Alex Bennée wrote:
>> Akihiko Odaki <akihiko.odaki@daynix.com> writes:
>>
>>> This demonstrates how a register can be read from a plugin.
>>>
>>> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
>>> ---
>>> docs/devel/tcg-plugins.rst | 10 ++-
>>> contrib/plugins/execlog.c | 140 ++++++++++++++++++++++++++++---------
>>> 2 files changed, 117 insertions(+), 33 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..aa05840fd0 100644
>>> --- a/contrib/plugins/execlog.c
>>> +++ b/contrib/plugins/execlog.c
>>> @@ -15,27 +15,43 @@
>>> #include <qemu-plugin.h>
>>> +typedef struct CPU {
>>> + /* Store last executed instruction on each vCPU as a GString */
>>> + GString *last_exec;
>>> + GByteArray *reg_history[2];
>>> +
>>> + int reg;
>>> +} CPU;
>>> +
>>> QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
>>>
>> <snip>
>>> /* 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);
>>> +
>>> + g_rw_lock_reader_unlock(&expand_array_lock);
>>> }
>>> /**
>>> @@ -167,8 +197,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,
>>> + rfile_name ? QEMU_PLUGIN_CB_R_REGS : QEMU_PLUGIN_CB_NO_REGS,
>>> + output);
>>> /* reset skip */
>>> skip = (imatches || amatches);
>>> @@ -177,17 +209,53 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
>>> }
>>> }
>>> +static void vcpu_init(qemu_plugin_id_t id, unsigned int
>>> vcpu_index)
>>> +{
>>> + int reg = 0;
>>> + bool found = false;
>>> +
>>> + expand_cpu(vcpu_index);
>>> +
>>> + if (rfile_name) {
>>> + int i;
>>> + int j;
>>> + int n;
>>> +
>>> + qemu_plugin_register_file_t *rfiles =
>>> + qemu_plugin_get_register_files(vcpu_index, &n);
>>> +
>>> + for (i = 0; i < n; i++) {
>>> + if (g_strcmp0(rfiles[i].name, rfile_name) == 0) {
>>> + for (j = 0; j < rfiles[i].num_regs; j++) {
>>> + if (g_strcmp0(rfiles[i].regs[j], reg_name) == 0) {
>>> + reg += j;
>>> + found = true;
>>> + break;
>>> + }
>>> + }
>>> + break;
>>> + }
>>> +
>>> + reg += rfiles[i].num_regs;
>>> + }
>>> +
>>> + g_free(rfiles);
>>> + }
>> This makes me question the value of exposing the register file
>> directly
>> to the plugin. I would much rather have a lookup utility function with
>> an optional tag. Something like:
>> plugin_reg_t qemu_plugin_find_register(const char *name, const
>> char *tag);
>> And make tag optional. I think in the general case "name" should be
>> enough.
>
> I have explained the reason why I introduced register file abstraction
> instead of adding a function to look up a register for an earlier
> version of this series:
>> I added a function that returns all register information instead of a
>> function that looks up a register so that a plugin can enumerate
>> registers. Such capability is useful for a plugin that dumps all
>> registers or a plugin that simulates processor (such a plugin may want
>> to warn if there are unknown registers).
Fair enough. However I think a simple search interface will also be
useful for the more common case.
> How would you define name and tag? They are something we currently do
> not have, and I'm trying to add new types of identifiers since such
> identifiers will be needed to be defined for different architectures
> and require documentation and extra work to avoid name conflicts and
> ensure interface stability.
The name would be the register name which AFAICT are unique across the
system. If you have examples of clashes I'm curious as to what they are.
I'm still conflicted about baking gdb-isms into this ABI because they
aren't as stable as they could be either. Either way we do state:
This is a new feature for QEMU and it does allow people to develop
out-of-tree plugins that can be dynamically linked into a running QEMU
process. However the project reserves the right to change or break the
API should it need to do so. The best way to avoid this is to submit
your plugin upstream so they can be updated if/when the API changes.
So I'm not overly concerned about formalising a stable ABI for now.
>
>>
>>> +
>>> + g_rw_lock_writer_lock(&expand_array_lock);
>>> + cpus[vcpu_index].reg = found ? reg : -1;
>>> + 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");
>>> }
>>> }
>>> @@ -224,9 +292,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 +302,23 @@ 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], "rfile") == 0) {
>>> + rfile_name = g_strdup(tokens[1]);
>>> + } else if (g_strcmp0(tokens[0], "reg") == 0) {
>>> + reg_name = g_strdup(tokens[1]);
>> And then instead of having the rfile/reg distinction support a
>> command
>> line like:
>> qemu-aarch64 -plugin
>> contrib/plugins/libexeclog.so,reg=sp,reg=x1,reg=sve:p1
>> so if the user specifies a reg of the form TAG:REG we can pass that
>> as
>> the option tag string. It also avoids exposing all the details of gdb to
>> plugins while still allowing the utility function to search by rname
>> internally (even if only a substring match?),
>
> That implicitly assumes TAG does not contain a colon. I'm avoiding to
> make such an implicit assumption because it is a reference for plugin
> writers who may create out-of-tree plugins. We should retrain
> ourselves to tell the plugin writers not to make such an assumption
> that may not hold in the future version of QEMU.
>
> I consider a substring match harmful for a similar reason. There is no
> guarantee that a future version of QEMU will not introduce a new
> register that match with the existing substring and break interface
> stability.
>
> It is not necessary that identifiers are consistent with ones GDB use.
> What matters here is that the identifiers are documented, stable and
> immune from conflicts.
We've a couple of cases of GDB having to issue new XML interface names
to handle cases where the previous definition missed important bits.
Hence my unease at exposing them to the plugin interface.
The plugin interface shouldn't (yet?) be regarded as a stable interface
(c.f. above).
>
>>
>>> } else {
>>> fprintf(stderr, "option parsing failed: %s\n", opt);
>>> return -1;
>>> }
>>> }
>>> + if ((!rfile_name) != (!reg_name)) {
>>> + fputs("file and reg need to be set at the same time\n", stderr);
>>> + return -1;
>>> + }
>>> +
>>> /* Register 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);
>>
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH RESEND v5 24/26] contrib/plugins: Allow to log registers
2023-09-04 15:30 ` Alex Bennée
@ 2023-09-05 6:51 ` Akihiko Odaki
0 siblings, 0 replies; 38+ messages in thread
From: Akihiko Odaki @ 2023-09-05 6:51 UTC (permalink / raw)
To: Alex Bennée
Cc: Mikhail Tyutin, Aleksandr Anenkov, qemu-devel, Alexandre Iooss,
Mahmoud Mandour, Richard Henderson, Paolo Bonzini
On 2023/09/05 0:30, Alex Bennée wrote:
>
> Akihiko Odaki <akihiko.odaki@daynix.com> writes:
>
>> On 2023/08/31 0:08, Alex Bennée wrote:
>>> Akihiko Odaki <akihiko.odaki@daynix.com> writes:
>>>
>>>> This demonstrates how a register can be read from a plugin.
>>>>
>>>> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
>>>> ---
>>>> docs/devel/tcg-plugins.rst | 10 ++-
>>>> contrib/plugins/execlog.c | 140 ++++++++++++++++++++++++++++---------
>>>> 2 files changed, 117 insertions(+), 33 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..aa05840fd0 100644
>>>> --- a/contrib/plugins/execlog.c
>>>> +++ b/contrib/plugins/execlog.c
>>>> @@ -15,27 +15,43 @@
>>>> #include <qemu-plugin.h>
>>>> +typedef struct CPU {
>>>> + /* Store last executed instruction on each vCPU as a GString */
>>>> + GString *last_exec;
>>>> + GByteArray *reg_history[2];
>>>> +
>>>> + int reg;
>>>> +} CPU;
>>>> +
>>>> QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
>>>>
>>> <snip>
>>>> /* 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);
>>>> +
>>>> + g_rw_lock_reader_unlock(&expand_array_lock);
>>>> }
>>>> /**
>>>> @@ -167,8 +197,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,
>>>> + rfile_name ? QEMU_PLUGIN_CB_R_REGS : QEMU_PLUGIN_CB_NO_REGS,
>>>> + output);
>>>> /* reset skip */
>>>> skip = (imatches || amatches);
>>>> @@ -177,17 +209,53 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
>>>> }
>>>> }
>>>> +static void vcpu_init(qemu_plugin_id_t id, unsigned int
>>>> vcpu_index)
>>>> +{
>>>> + int reg = 0;
>>>> + bool found = false;
>>>> +
>>>> + expand_cpu(vcpu_index);
>>>> +
>>>> + if (rfile_name) {
>>>> + int i;
>>>> + int j;
>>>> + int n;
>>>> +
>>>> + qemu_plugin_register_file_t *rfiles =
>>>> + qemu_plugin_get_register_files(vcpu_index, &n);
>>>> +
>>>> + for (i = 0; i < n; i++) {
>>>> + if (g_strcmp0(rfiles[i].name, rfile_name) == 0) {
>>>> + for (j = 0; j < rfiles[i].num_regs; j++) {
>>>> + if (g_strcmp0(rfiles[i].regs[j], reg_name) == 0) {
>>>> + reg += j;
>>>> + found = true;
>>>> + break;
>>>> + }
>>>> + }
>>>> + break;
>>>> + }
>>>> +
>>>> + reg += rfiles[i].num_regs;
>>>> + }
>>>> +
>>>> + g_free(rfiles);
>>>> + }
>>> This makes me question the value of exposing the register file
>>> directly
>>> to the plugin. I would much rather have a lookup utility function with
>>> an optional tag. Something like:
>>> plugin_reg_t qemu_plugin_find_register(const char *name, const
>>> char *tag);
>>> And make tag optional. I think in the general case "name" should be
>>> enough.
>>
>> I have explained the reason why I introduced register file abstraction
>> instead of adding a function to look up a register for an earlier
>> version of this series:
>>> I added a function that returns all register information instead of a
>>> function that looks up a register so that a plugin can enumerate
>>> registers. Such capability is useful for a plugin that dumps all
>>> registers or a plugin that simulates processor (such a plugin may want
>>> to warn if there are unknown registers).
>
> Fair enough. However I think a simple search interface will also be
> useful for the more common case.
I'll add one in a future version.
>
>> How would you define name and tag? They are something we currently do
>> not have, and I'm trying to add new types of identifiers since such
>> identifiers will be needed to be defined for different architectures
>> and require documentation and extra work to avoid name conflicts and
>> ensure interface stability.
>
> The name would be the register name which AFAICT are unique across the
> system. If you have examples of clashes I'm curious as to what they are.
Here I'm talking about creating and maintaining a set of identifiers
independent of GDB. I'm suggesting to reuse the identifiers GDB use
since they are already designed so that there are no clashes.
> I'm still conflicted about baking gdb-isms into this ABI because they
> aren't as stable as they could be either. Either way we do state:
>
> This is a new feature for QEMU and it does allow people to develop
> out-of-tree plugins that can be dynamically linked into a running QEMU
> process. However the project reserves the right to change or break the
> API should it need to do so. The best way to avoid this is to submit
> your plugin upstream so they can be updated if/when the API changes.
>
> So I'm not overly concerned about formalising a stable ABI for now.
>
>>
>>>
>>>> +
>>>> + g_rw_lock_writer_lock(&expand_array_lock);
>>>> + cpus[vcpu_index].reg = found ? reg : -1;
>>>> + 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");
>>>> }
>>>> }
>>>> @@ -224,9 +292,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 +302,23 @@ 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], "rfile") == 0) {
>>>> + rfile_name = g_strdup(tokens[1]);
>>>> + } else if (g_strcmp0(tokens[0], "reg") == 0) {
>>>> + reg_name = g_strdup(tokens[1]);
>>> And then instead of having the rfile/reg distinction support a
>>> command
>>> line like:
>>> qemu-aarch64 -plugin
>>> contrib/plugins/libexeclog.so,reg=sp,reg=x1,reg=sve:p1
>>> so if the user specifies a reg of the form TAG:REG we can pass that
>>> as
>>> the option tag string. It also avoids exposing all the details of gdb to
>>> plugins while still allowing the utility function to search by rname
>>> internally (even if only a substring match?),
>>
>> That implicitly assumes TAG does not contain a colon. I'm avoiding to
>> make such an implicit assumption because it is a reference for plugin
>> writers who may create out-of-tree plugins. We should retrain
>> ourselves to tell the plugin writers not to make such an assumption
>> that may not hold in the future version of QEMU.
>>
>> I consider a substring match harmful for a similar reason. There is no
>> guarantee that a future version of QEMU will not introduce a new
>> register that match with the existing substring and break interface
>> stability.
>>
>> It is not necessary that identifiers are consistent with ones GDB use.
>> What matters here is that the identifiers are documented, stable and
>> immune from conflicts.
>
> We've a couple of cases of GDB having to issue new XML interface names
> to handle cases where the previous definition missed important bits.
> Hence my unease at exposing them to the plugin interface.
Why you had to issue new feature names when adding missing definitions?
I expect the reasoning for changing GDB interface names should also
apply for TCG plugins: when not changing interface names will break GDB,
it should be also likely to break TCG plugins using the affected features.
I consider names used in GDB stable. GDB versions will break if they are
not.
>
> The plugin interface shouldn't (yet?) be regarded as a stable interface
> (c.f. above).
The plugin interface has been for almost 5 years. If it is not stable
yet, when it will be? In any case, the interface stability should be
considered as an eventual goal; otherwise the existing infrastructure
for plugin API versioning will make no sense.
^ permalink raw reply [flat|nested] 38+ messages in thread
end of thread, other threads:[~2023-09-05 6:51 UTC | newest]
Thread overview: 38+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-08-18 3:36 [PATCH RESEND v5 00/26] plugins: Allow to read registers Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 01/26] contrib/plugins: Use GRWLock in execlog Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 02/26] gdbstub: Introduce GDBFeature structure Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 03/26] gdbstub: Add num_regs member to GDBFeature Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 04/26] gdbstub: Introduce gdb_find_static_feature() Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 05/26] target/arm: Move the reference to arm-core.xml Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 06/26] hw/core/cpu: Replace gdb_core_xml_file with gdb_core_feature Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 07/26] gdbstub: Introduce GDBFeatureBuilder Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 08/26] target/arm: Use GDBFeature for dynamic XML Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 09/26] target/ppc: " Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 10/26] target/riscv: " Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 11/26] gdbstub: Use GDBFeature for gdb_register_coprocessor Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 12/26] gdbstub: Use GDBFeature for GDBRegisterState Akihiko Odaki
2023-08-30 14:59 ` Alex Bennée
2023-08-18 3:36 ` [PATCH RESEND v5 13/26] hw/core/cpu: Return static value with gdb_arch_name() Akihiko Odaki
2023-08-30 15:00 ` Alex Bennée
2023-08-18 3:36 ` [PATCH RESEND v5 14/26] gdbstub: Dynamically allocate target.xml buffer Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 15/26] gdbstub: Simplify XML lookup Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 16/26] hw/core/cpu: Remove gdb_get_dynamic_xml member Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 17/26] gdbstub: Add members to identify registers to GDBFeature Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 18/26] target/arm: Remove references to gdb_has_xml Akihiko Odaki
2023-08-30 15:02 ` Alex Bennée
2023-08-18 3:36 ` [PATCH RESEND v5 19/26] target/ppc: " Akihiko Odaki
2023-08-25 9:40 ` Nicholas Piggin
2023-08-18 3:36 ` [PATCH RESEND v5 20/26] gdbstub: Remove gdb_has_xml variable Akihiko Odaki
2023-08-30 15:02 ` Alex Bennée
2023-08-30 20:24 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 21/26] gdbstub: Expose functions to read registers Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 22/26] cpu: Call plugin hooks only when ready Akihiko Odaki
2023-08-30 15:04 ` Alex Bennée
2023-08-18 3:36 ` [PATCH RESEND v5 23/26] plugins: Allow to read registers Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 24/26] contrib/plugins: Allow to log registers Akihiko Odaki
2023-08-30 15:08 ` Alex Bennée
2023-08-30 20:53 ` Akihiko Odaki
2023-09-04 15:30 ` Alex Bennée
2023-09-05 6:51 ` Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 25/26] plugins: Support C++ Akihiko Odaki
2023-08-18 3:36 ` [PATCH RESEND v5 26/26] contrib/plugins: Add cc plugin Akihiko Odaki
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).