...
...
19
to using upstream QEMU for these tasks which have historically
19
to using upstream QEMU for these tasks which have historically
20
required maintaining a QEMU fork downstream (like QEMUAFL
20
required maintaining a QEMU fork downstream (like QEMUAFL
21
https://github.com/AFLplusplus/qemuafl), which is tedious, error
21
https://github.com/AFLplusplus/qemuafl), which is tedious, error
22
prone, and results in users missing out on enhancements to QEMU.
22
prone, and results in users missing out on enhancements to QEMU.
23
23
24
novafacing (2):
24
A test is provided, compile:
25
26
gcc -o tests/tcg/x86_64/inject-target tests/tcg/x86_64/inject-target.c
27
28
And run:
29
30
./build/qemu-x86_64 -d plugin --plugin build/tests/tcg/plugins/libinject.so tests/tcg/x86_64/inject-target
31
32
Hopefully after a number of tries, the inject plugin will inject the right
33
value into the target program, leading to a victory message. This plugin
34
handles simple "hypercalls", only one of which is implemented and injects
35
data into guest memory.
36
37
novafacing (3):
25
Expose gdb_write_register function to consumers of gdbstub
38
Expose gdb_write_register function to consumers of gdbstub
26
Add plugin API functions for register R/W, hwaddr R/W, vaddr W
39
Add plugin API functions for register R/W, hwaddr R/W, vaddr W
40
Add inject plugin and x86_64 target for the inject plugin
27
41
28
gdbstub/gdbstub.c | 2 +-
42
gdbstub/gdbstub.c | 2 +-
29
include/exec/gdbstub.h | 14 +++++
43
include/exec/gdbstub.h | 14 +++
30
include/qemu/qemu-plugin.h | 116 +++++++++++++++++++++++++++++++++----
44
include/qemu/qemu-plugin.h | 116 +++++++++++++++--
31
plugins/api.c | 66 ++++++++++++++++++++-
45
plugins/api.c | 66 +++++++++-
32
4 files changed, 183 insertions(+), 15 deletions(-)
46
tests/tcg/plugins/inject.c | 206 +++++++++++++++++++++++++++++++
47
tests/tcg/plugins/meson.build | 2 +-
48
tests/tcg/x86_64/Makefile.target | 1 +
49
tests/tcg/x86_64/inject-target.c | 27 ++++
50
8 files changed, 418 insertions(+), 16 deletions(-)
51
create mode 100644 tests/tcg/plugins/inject.c
52
create mode 100644 tests/tcg/x86_64/inject-target.c
33
53
34
--
54
--
35
2.46.1
55
2.46.1
diff view generated by jsdifflib
1
From: novafacing <rowanbhart@gmail.com>
1
From: novafacing <rowanbhart@gmail.com>
2
2
3
---
3
---
4
gdbstub/gdbstub.c | 2 +-
4
gdbstub/gdbstub.c | 2 +-
5
include/exec/gdbstub.h | 14 ++++++++++++++
5
include/exec/gdbstub.h | 14 ++++++++++++++
6
2 files changed, 15 insertions(+), 1 deletion(-)
6
2 files changed, 15 insertions(+), 1 deletion(-)
7
7
8
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
8
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
9
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
10
--- a/gdbstub/gdbstub.c
10
--- a/gdbstub/gdbstub.c
11
+++ b/gdbstub/gdbstub.c
11
+++ b/gdbstub/gdbstub.c
12
@@ -XXX,XX +XXX,XX @@ int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
12
@@ -XXX,XX +XXX,XX @@ int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
13
return 0;
13
return 0;
14
}
14
}
15
15
16
-static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
16
-static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
17
+int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
17
+int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
18
{
18
{
19
CPUClass *cc = CPU_GET_CLASS(cpu);
19
CPUClass *cc = CPU_GET_CLASS(cpu);
20
GDBRegisterState *r;
20
GDBRegisterState *r;
21
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
21
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
22
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
23
--- a/include/exec/gdbstub.h
23
--- a/include/exec/gdbstub.h
24
+++ b/include/exec/gdbstub.h
24
+++ b/include/exec/gdbstub.h
25
@@ -XXX,XX +XXX,XX @@ const GDBFeature *gdb_find_static_feature(const char *xmlname);
25
@@ -XXX,XX +XXX,XX @@ const GDBFeature *gdb_find_static_feature(const char *xmlname);
26
*/
26
*/
27
int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
27
int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
28
28
29
+/**
29
+/**
30
+ * gdb_write_register() - Write a register associated with a CPU.
30
+ * gdb_write_register() - Write a register associated with a CPU.
31
+ * @cpu: The CPU associated with the register.
31
+ * @cpu: The CPU associated with the register.
32
+ * @buf: The buffer that the register contents will be set to.
32
+ * @buf: The buffer that the register contents will be set to.
33
+ * @reg: The register's number returned by gdb_find_feature_register().
33
+ * @reg: The register's number returned by gdb_find_feature_register().
34
+ *
34
+ *
35
+ * The size of @buf must be at least the size of the register being
35
+ * The size of @buf must be at least the size of the register being
36
+ * written.
36
+ * written.
37
+ *
37
+ *
38
+ * Return: The number of written bytes, or 0 if an error occurred (for
38
+ * Return: The number of written bytes, or 0 if an error occurred (for
39
+ * example, an unknown register was provided).
39
+ * example, an unknown register was provided).
40
+ */
40
+ */
41
+int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg);
41
+int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg);
42
+
42
+
43
/**
43
/**
44
* typedef GDBRegDesc - a register description from gdbstub
44
* typedef GDBRegDesc - a register description from gdbstub
45
*/
45
*/
46
--
46
--
47
2.46.1
47
2.46.1
diff view generated by jsdifflib
1
From: novafacing <rowanbhart@gmail.com>
1
From: novafacing <rowanbhart@gmail.com>
2
2
3
---
3
---
4
include/qemu/qemu-plugin.h | 116 +++++++++++++++++++++++++++++++++----
4
include/qemu/qemu-plugin.h | 116 +++++++++++++++++++++++++++++++++----
5
plugins/api.c | 66 ++++++++++++++++++++-
5
plugins/api.c | 66 ++++++++++++++++++++-
6
2 files changed, 168 insertions(+), 14 deletions(-)
6
2 files changed, 168 insertions(+), 14 deletions(-)
7
7
8
diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
8
diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
9
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
10
--- a/include/qemu/qemu-plugin.h
10
--- a/include/qemu/qemu-plugin.h
11
+++ b/include/qemu/qemu-plugin.h
11
+++ b/include/qemu/qemu-plugin.h
12
@@ -XXX,XX +XXX,XX @@ typedef uint64_t qemu_plugin_id_t;
12
@@ -XXX,XX +XXX,XX @@ typedef uint64_t qemu_plugin_id_t;
13
*
13
*
14
* version 4:
14
* version 4:
15
* - added qemu_plugin_read_memory_vaddr
15
* - added qemu_plugin_read_memory_vaddr
16
+ *
16
+ *
17
+ * version 5:
17
+ * version 5:
18
+ * - added qemu_plugin_write_memory_vaddr
18
+ * - added qemu_plugin_write_memory_vaddr
19
+ * - added qemu_plugin_read_memory_hwaddr
19
+ * - added qemu_plugin_read_memory_hwaddr
20
+ * - added qemu_plugin_write_memory_hwaddr
20
+ * - added qemu_plugin_write_memory_hwaddr
21
+ * - added qemu_plugin_write_register
21
+ * - added qemu_plugin_write_register
22
+ *
22
+ *
23
*/
23
*/
24
24
25
extern QEMU_PLUGIN_EXPORT int qemu_plugin_version;
25
extern QEMU_PLUGIN_EXPORT int qemu_plugin_version;
26
26
27
-#define QEMU_PLUGIN_VERSION 4
27
-#define QEMU_PLUGIN_VERSION 4
28
+#define QEMU_PLUGIN_VERSION 5
28
+#define QEMU_PLUGIN_VERSION 5
29
29
30
/**
30
/**
31
* struct qemu_info_t - system information for plugins
31
* struct qemu_info_t - system information for plugins
32
@@ -XXX,XX +XXX,XX @@ typedef struct {
32
@@ -XXX,XX +XXX,XX @@ typedef struct {
33
* @QEMU_PLUGIN_CB_R_REGS: callback reads the CPU's regs
33
* @QEMU_PLUGIN_CB_R_REGS: callback reads the CPU's regs
34
* @QEMU_PLUGIN_CB_RW_REGS: callback reads and writes the CPU's regs
34
* @QEMU_PLUGIN_CB_RW_REGS: callback reads and writes the CPU's regs
35
*
35
*
36
- * Note: currently QEMU_PLUGIN_CB_RW_REGS is unused, plugins cannot change
36
- * Note: currently QEMU_PLUGIN_CB_RW_REGS is unused, plugins cannot change
37
- * system register state.
37
- * system register state.
38
*/
38
*/
39
enum qemu_plugin_cb_flags {
39
enum qemu_plugin_cb_flags {
40
QEMU_PLUGIN_CB_NO_REGS,
40
QEMU_PLUGIN_CB_NO_REGS,
41
@@ -XXX,XX +XXX,XX @@ typedef struct {
41
@@ -XXX,XX +XXX,XX @@ typedef struct {
42
QEMU_PLUGIN_API
42
QEMU_PLUGIN_API
43
GArray *qemu_plugin_get_registers(void);
43
GArray *qemu_plugin_get_registers(void);
44
44
45
+/**
45
+/**
46
+ * qemu_plugin_read_register() - read register for current vCPU
46
+ * qemu_plugin_read_register() - read register for current vCPU
47
+ *
47
+ *
48
+ * @handle: a @qemu_plugin_reg_handle handle
48
+ * @handle: a @qemu_plugin_reg_handle handle
49
+ * @buf: A GByteArray for the data owned by the plugin
49
+ * @buf: A GByteArray for the data owned by the plugin
50
+ *
50
+ *
51
+ * This function is only available in a context that register read access is
51
+ * This function is only available in a context that register read access is
52
+ * explicitly requested via the QEMU_PLUGIN_CB_R_REGS flag.
52
+ * explicitly requested via the QEMU_PLUGIN_CB_R_REGS flag.
53
+ *
53
+ *
54
+ * Returns the size of the read register. The content of @buf is in target byte
54
+ * Returns the size of the read register. The content of @buf is in target byte
55
+ * order. On failure returns -1.
55
+ * order. On failure returns -1.
56
+ */
56
+ */
57
+QEMU_PLUGIN_API
57
+QEMU_PLUGIN_API
58
+int qemu_plugin_read_register(struct qemu_plugin_register *handle,
58
+int qemu_plugin_read_register(struct qemu_plugin_register *handle,
59
+ GByteArray *buf);
59
+ GByteArray *buf);
60
+
60
+
61
+/**
61
+/**
62
+ * qemu_plugin_write_register() - write register for current vCPU
62
+ * qemu_plugin_write_register() - write register for current vCPU
63
+ *
63
+ *
64
+ * @handle: a @qemu_plugin_reg_handle handle
64
+ * @handle: a @qemu_plugin_reg_handle handle
65
+ * @buf: A GByteArray for the data owned by the plugin
65
+ * @buf: A GByteArray for the data owned by the plugin
66
+ *
66
+ *
67
+ * This function is only available in a context that register write access is
67
+ * This function is only available in a context that register write access is
68
+ * explicitly requested via the QEMU_PLUGIN_CB_W_REGS flag.
68
+ * explicitly requested via the QEMU_PLUGIN_CB_W_REGS flag.
69
+ *
69
+ *
70
+ * The size of @buf must be at least the size of the requested register.
70
+ * The size of @buf must be at least the size of the requested register.
71
+ * Attempting to write a register with @buf smaller than the register size
71
+ * Attempting to write a register with @buf smaller than the register size
72
+ * will result in a crash or other undesired behavior.
72
+ * will result in a crash or other undesired behavior.
73
+ *
73
+ *
74
+ * Returns the number of bytes written. On failure returns 0.
74
+ * Returns the number of bytes written. On failure returns 0.
75
+ */
75
+ */
76
+QEMU_PLUGIN_API
76
+QEMU_PLUGIN_API
77
+int qemu_plugin_write_register(struct qemu_plugin_register *handle,
77
+int qemu_plugin_write_register(struct qemu_plugin_register *handle,
78
+ GByteArray *buf);
78
+ GByteArray *buf);
79
+
79
+
80
/**
80
/**
81
* qemu_plugin_read_memory_vaddr() - read from memory using a virtual address
81
* qemu_plugin_read_memory_vaddr() - read from memory using a virtual address
82
*
82
*
83
@@ -XXX,XX +XXX,XX @@ bool qemu_plugin_read_memory_vaddr(uint64_t addr,
83
@@ -XXX,XX +XXX,XX @@ bool qemu_plugin_read_memory_vaddr(uint64_t addr,
84
GByteArray *data, size_t len);
84
GByteArray *data, size_t len);
85
85
86
/**
86
/**
87
- * qemu_plugin_read_register() - read register for current vCPU
87
- * qemu_plugin_read_register() - read register for current vCPU
88
+ * qemu_plugin_write_memory_vaddr() - write to memory using a virtual address
88
+ * qemu_plugin_write_memory_vaddr() - write to memory using a virtual address
89
*
89
*
90
- * @handle: a @qemu_plugin_reg_handle handle
90
- * @handle: a @qemu_plugin_reg_handle handle
91
- * @buf: A GByteArray for the data owned by the plugin
91
- * @buf: A GByteArray for the data owned by the plugin
92
+ * @addr: A virtual address to write to
92
+ * @addr: A virtual address to write to
93
+ * @data: A byte array containing the data to write
93
+ * @data: A byte array containing the data to write
94
*
94
*
95
- * This function is only available in a context that register read access is
95
- * This function is only available in a context that register read access is
96
- * explicitly requested via the QEMU_PLUGIN_CB_R_REGS flag.
96
- * explicitly requested via the QEMU_PLUGIN_CB_R_REGS flag.
97
+ * The contents of @data will be written to memory starting at the virtual
97
+ * The contents of @data will be written to memory starting at the virtual
98
+ * address @addr.
98
+ * address @addr.
99
*
99
*
100
- * Returns the size of the read register. The content of @buf is in target byte
100
- * Returns the size of the read register. The content of @buf is in target byte
101
- * order. On failure returns -1.
101
- * order. On failure returns -1.
102
+ * This function does not guarantee consistency of writes, nor does it ensure
102
+ * This function does not guarantee consistency of writes, nor does it ensure
103
+ * that pending writes are flushed either before or after the write takes
103
+ * that pending writes are flushed either before or after the write takes
104
+ * place, so callers should take care when calling this function in plugin
104
+ * place, so callers should take care when calling this function in plugin
105
+ * callbacks to avoid depending on the existence of data written using this
105
+ * callbacks to avoid depending on the existence of data written using this
106
+ * function which may be overwritten afterward.
106
+ * function which may be overwritten afterward.
107
+ *
107
+ *
108
+ * Returns true on success and false on failure.
108
+ * Returns true on success and false on failure.
109
*/
109
*/
110
QEMU_PLUGIN_API
110
QEMU_PLUGIN_API
111
-int qemu_plugin_read_register(struct qemu_plugin_register *handle,
111
-int qemu_plugin_read_register(struct qemu_plugin_register *handle,
112
- GByteArray *buf);
112
- GByteArray *buf);
113
+bool qemu_plugin_write_memory_vaddr(uint64_t addr,
113
+bool qemu_plugin_write_memory_vaddr(uint64_t addr,
114
+ GByteArray *data);
114
+ GByteArray *data);
115
+
115
+
116
+/**
116
+/**
117
+ * qemu_plugin_read_memory_vaddr() - read from memory using a hardware address
117
+ * qemu_plugin_read_memory_vaddr() - read from memory using a hardware address
118
+ *
118
+ *
119
+ * @addr: A virtual address to read from
119
+ * @addr: A virtual address to read from
120
+ * @data: A byte array to store data into
120
+ * @data: A byte array to store data into
121
+ * @len: The number of bytes to read, starting from @addr
121
+ * @len: The number of bytes to read, starting from @addr
122
+ *
122
+ *
123
+ * @len bytes of data is read starting at @addr and stored into @data. If @data
123
+ * @len bytes of data is read starting at @addr and stored into @data. If @data
124
+ * is not large enough to hold @len bytes, it will be expanded to the necessary
124
+ * is not large enough to hold @len bytes, it will be expanded to the necessary
125
+ * size, reallocating if necessary. @len must be greater than 0.
125
+ * size, reallocating if necessary. @len must be greater than 0.
126
+ *
126
+ *
127
+ * This function does not ensure writes are flushed prior to reading, so
127
+ * This function does not ensure writes are flushed prior to reading, so
128
+ * callers should take care when calling this function in plugin callbacks to
128
+ * callers should take care when calling this function in plugin callbacks to
129
+ * avoid attempting to read data which may not yet be written and should use
129
+ * avoid attempting to read data which may not yet be written and should use
130
+ * the memory callback API instead.
130
+ * the memory callback API instead.
131
+ *
131
+ *
132
+ * This function is only valid for softmmu targets.
132
+ * This function is only valid for softmmu targets.
133
+ *
133
+ *
134
+ * Returns true on success and false on failure.
134
+ * Returns true on success and false on failure.
135
+ */
135
+ */
136
+QEMU_PLUGIN_API
136
+QEMU_PLUGIN_API
137
+bool qemu_plugin_read_memory_hwaddr(uint64_t addr,
137
+bool qemu_plugin_read_memory_hwaddr(uint64_t addr,
138
+ GByteArray *data, size_t len);
138
+ GByteArray *data, size_t len);
139
+
139
+
140
+/**
140
+/**
141
+ * qemu_plugin_write_memory_vaddr() - write to memory using a hardware address
141
+ * qemu_plugin_write_memory_vaddr() - write to memory using a hardware address
142
+ *
142
+ *
143
+ * @addr: A virtual address to write to
143
+ * @addr: A virtual address to write to
144
+ * @data: A byte array containing the data to write
144
+ * @data: A byte array containing the data to write
145
+ *
145
+ *
146
+ * The contents of @data will be written to memory starting at the hardware
146
+ * The contents of @data will be written to memory starting at the hardware
147
+ * address @addr.
147
+ * address @addr.
148
+ *
148
+ *
149
+ * This function does not guarantee consistency of writes, nor does it ensure
149
+ * This function does not guarantee consistency of writes, nor does it ensure
150
+ * that pending writes are flushed either before or after the write takes
150
+ * that pending writes are flushed either before or after the write takes
151
+ * place, so callers should take care when calling this function in plugin
151
+ * place, so callers should take care when calling this function in plugin
152
+ * callbacks to avoid depending on the existence of data written using this
152
+ * callbacks to avoid depending on the existence of data written using this
153
+ * function which may be overwritten afterward.
153
+ * function which may be overwritten afterward.
154
+ *
154
+ *
155
+ * This function is only valid for softmmu targets.
155
+ * This function is only valid for softmmu targets.
156
+ *
156
+ *
157
+ * Returns true on success and false on failure.
157
+ * Returns true on success and false on failure.
158
+ */
158
+ */
159
+QEMU_PLUGIN_API
159
+QEMU_PLUGIN_API
160
+bool qemu_plugin_write_memory_hwaddr(uint64_t addr,
160
+bool qemu_plugin_write_memory_hwaddr(uint64_t addr,
161
+ GByteArray *data);
161
+ GByteArray *data);
162
162
163
/**
163
/**
164
* qemu_plugin_scoreboard_new() - alloc a new scoreboard
164
* qemu_plugin_scoreboard_new() - alloc a new scoreboard
165
diff --git a/plugins/api.c b/plugins/api.c
165
diff --git a/plugins/api.c b/plugins/api.c
166
index XXXXXXX..XXXXXXX 100644
166
index XXXXXXX..XXXXXXX 100644
167
--- a/plugins/api.c
167
--- a/plugins/api.c
168
+++ b/plugins/api.c
168
+++ b/plugins/api.c
169
@@ -XXX,XX +XXX,XX @@ GArray *qemu_plugin_get_registers(void)
169
@@ -XXX,XX +XXX,XX @@ GArray *qemu_plugin_get_registers(void)
170
return create_register_handles(regs);
170
return create_register_handles(regs);
171
}
171
}
172
172
173
+int qemu_plugin_read_register(struct qemu_plugin_register *reg, GByteArray *buf)
173
+int qemu_plugin_read_register(struct qemu_plugin_register *reg, GByteArray *buf)
174
+{
174
+{
175
+ g_assert(current_cpu);
175
+ g_assert(current_cpu);
176
+
176
+
177
+ return gdb_read_register(current_cpu, buf, GPOINTER_TO_INT(reg) - 1);
177
+ return gdb_read_register(current_cpu, buf, GPOINTER_TO_INT(reg) - 1);
178
+}
178
+}
179
+
179
+
180
+int qemu_plugin_write_register(struct qemu_plugin_register *reg, GByteArray *buf)
180
+int qemu_plugin_write_register(struct qemu_plugin_register *reg, GByteArray *buf)
181
+{
181
+{
182
+ g_assert(current_cpu);
182
+ g_assert(current_cpu);
183
+
183
+
184
+ if (buf->len == 0) {
184
+ if (buf->len == 0) {
185
+ return 0;
185
+ return 0;
186
+ }
186
+ }
187
+
187
+
188
+ return gdb_write_register(current_cpu, buf->data, GPOINTER_TO_INT(reg) - 1);
188
+ return gdb_write_register(current_cpu, buf->data, GPOINTER_TO_INT(reg) - 1);
189
+}
189
+}
190
+
190
+
191
bool qemu_plugin_read_memory_vaddr(vaddr addr, GByteArray *data, size_t len)
191
bool qemu_plugin_read_memory_vaddr(vaddr addr, GByteArray *data, size_t len)
192
{
192
{
193
g_assert(current_cpu);
193
g_assert(current_cpu);
194
@@ -XXX,XX +XXX,XX @@ bool qemu_plugin_read_memory_vaddr(vaddr addr, GByteArray *data, size_t len)
194
@@ -XXX,XX +XXX,XX @@ bool qemu_plugin_read_memory_vaddr(vaddr addr, GByteArray *data, size_t len)
195
return true;
195
return true;
196
}
196
}
197
197
198
-int qemu_plugin_read_register(struct qemu_plugin_register *reg, GByteArray *buf)
198
-int qemu_plugin_read_register(struct qemu_plugin_register *reg, GByteArray *buf)
199
+bool qemu_plugin_write_memory_vaddr(vaddr addr, GByteArray *data)
199
+bool qemu_plugin_write_memory_vaddr(vaddr addr, GByteArray *data)
200
{
200
{
201
g_assert(current_cpu);
201
g_assert(current_cpu);
202
202
203
- return gdb_read_register(current_cpu, buf, GPOINTER_TO_INT(reg) - 1);
203
- return gdb_read_register(current_cpu, buf, GPOINTER_TO_INT(reg) - 1);
204
+ if (data->len == 0) {
204
+ if (data->len == 0) {
205
+ return false;
205
+ return false;
206
+ }
206
+ }
207
+
207
+
208
+ int result = cpu_memory_rw_debug(current_cpu, addr, data->data,
208
+ int result = cpu_memory_rw_debug(current_cpu, addr, data->data,
209
+ data->len, true);
209
+ data->len, true);
210
+
210
+
211
+ if (result < 0) {
211
+ if (result < 0) {
212
+ return false;
212
+ return false;
213
+ }
213
+ }
214
+
214
+
215
+ return true;
215
+ return true;
216
+}
216
+}
217
+
217
+
218
+bool qemu_plugin_read_memory_hwaddr(hwaddr addr, GByteArray *data, size_t len)
218
+bool qemu_plugin_read_memory_hwaddr(hwaddr addr, GByteArray *data, size_t len)
219
+{
219
+{
220
+#ifdef CONFIG_SOFTMMU
220
+#ifdef CONFIG_SOFTMMU
221
+ if (len == 0) {
221
+ if (len == 0) {
222
+ return false;
222
+ return false;
223
+ }
223
+ }
224
+
224
+
225
+ g_byte_array_set_size(data, len);
225
+ g_byte_array_set_size(data, len);
226
+
226
+
227
+ cpu_physical_memory_rw(addr, data->data, data->len, false);
227
+ cpu_physical_memory_rw(addr, data->data, data->len, false);
228
+
228
+
229
+ return true;
229
+ return true;
230
+#else
230
+#else
231
+ return false;
231
+ return false;
232
+#endif
232
+#endif
233
}
233
}
234
234
235
+bool qemu_plugin_write_memory_hwaddr(hwaddr addr, GByteArray *data)
235
+bool qemu_plugin_write_memory_hwaddr(hwaddr addr, GByteArray *data)
236
+{
236
+{
237
+#ifdef CONFIG_SOFTMMU
237
+#ifdef CONFIG_SOFTMMU
238
+ if (data->len == 0) {
238
+ if (data->len == 0) {
239
+ return false;
239
+ return false;
240
+ }
240
+ }
241
+
241
+
242
+ cpu_physical_memory_rw(addr, data->data, data->len, true);
242
+ cpu_physical_memory_rw(addr, data->data, data->len, true);
243
+
243
+
244
+ return true;
244
+ return true;
245
+#else
245
+#else
246
+ return false;
246
+ return false;
247
+#endif
247
+#endif
248
+}
248
+}
249
+
249
+
250
+
250
+
251
struct qemu_plugin_scoreboard *qemu_plugin_scoreboard_new(size_t element_size)
251
struct qemu_plugin_scoreboard *qemu_plugin_scoreboard_new(size_t element_size)
252
{
252
{
253
return plugin_scoreboard_new(element_size);
253
return plugin_scoreboard_new(element_size);
254
--
254
--
255
2.46.1
255
2.46.1
diff view generated by jsdifflib
New patch
1
From: novafacing <rowanbhart@gmail.com>
1
2
3
---
4
tests/tcg/plugins/inject.c | 206 +++++++++++++++++++++++++++++++
5
tests/tcg/plugins/meson.build | 2 +-
6
tests/tcg/x86_64/Makefile.target | 1 +
7
tests/tcg/x86_64/inject-target.c | 27 ++++
8
4 files changed, 235 insertions(+), 1 deletion(-)
9
create mode 100644 tests/tcg/plugins/inject.c
10
create mode 100644 tests/tcg/x86_64/inject-target.c
11
12
diff --git a/tests/tcg/plugins/inject.c b/tests/tcg/plugins/inject.c
13
new file mode 100644
14
index XXXXXXX..XXXXXXX
15
--- /dev/null
16
+++ b/tests/tcg/plugins/inject.c
17
@@ -XXX,XX +XXX,XX @@
18
+/*
19
+ * Copyright (C) 2024, Rowan Hart <rowanbhart@gmail.com>
20
+ *
21
+ * License: GNU GPL, version 2 or later.
22
+ * See the COPYING file in the top-level directory.
23
+ */
24
+#include "glib.h"
25
+#include <assert.h>
26
+#include <inttypes.h>
27
+#include <stdio.h>
28
+#include <stdlib.h>
29
+#include <string.h>
30
+#include <unistd.h>
31
+
32
+#include <qemu-plugin.h>
33
+
34
+/*
35
+ * Specifies a Hypercall for an architecture:
36
+ *
37
+ * - Architecture name
38
+ * - Whether it is enabled
39
+ * - The hypercall instruction
40
+ * - The register names to pass the hypercall # and args
41
+ */
42
+struct HypercallSpec {
43
+ const char *name;
44
+ const bool enabled;
45
+ const char *hypercall;
46
+ const bool little_endian;
47
+ const char *num_reg;
48
+ const char *arg0_reg;
49
+ const char *arg1_reg;
50
+};
51
+
52
+static const struct HypercallSpec *hypercall_spec;
53
+
54
+static const struct HypercallSpec hypercall_specs[] = {
55
+ { "aarch64", false, NULL, true, 0, 0, 0 },
56
+ { "aarch64_be", false, NULL, false, 0, 0, 0 },
57
+ { "alpha", false, NULL, true, 0, 0, 0 },
58
+ { "arm", false, NULL, true, 0, 0, 0 },
59
+ { "armeb", false, NULL, false, 0, 0, 0 },
60
+ { "avr", false, NULL, true, 0, 0, 0 },
61
+ { "hexagon", false, NULL, true, 0, 0, 0 },
62
+ { "hppa", false, NULL, false, 0, 0, 0 },
63
+ { "i386", false, NULL, true, 0, 0, 0 },
64
+ { "loongarch64", false, NULL, true, 0, 0, 0 },
65
+ { "m68k", false, NULL, false, 0, 0, 0 },
66
+ { "microblaze", false, NULL, false, 0, 0, 0 },
67
+ { "microblazeel", false, NULL, true, 0, 0, 0 },
68
+ { "mips", false, NULL, false, 0, 0, 0 },
69
+ { "mips64", false, NULL, false, 0, 0, 0 },
70
+ { "mips64el", false, NULL, true, 0, 0, 0 },
71
+ { "mipsel", false, NULL, true, 0, 0, 0 },
72
+ { "mipsn32", false, NULL, false, 0, 0, 0 },
73
+ { "mipsn32el", false, NULL, true, 0, 0, 0 },
74
+ { "or1k", false, NULL, false, 0, 0, 0 },
75
+ { "ppc", false, NULL, false, 0, 0, 0 },
76
+ { "ppc64", false, NULL, false, 0, 0, 0 },
77
+ { "ppc64le", false, NULL, true, 0, 0, 0 },
78
+ { "riscv32", false, NULL, true, 0, 0, 0 },
79
+ { "riscv64", false, NULL, true, 0, 0, 0 },
80
+ { "rx", false, NULL, true, 0, 0, 0 },
81
+ { "s390x", false, NULL, false, 0, 0, 0 },
82
+ { "sh4", false, NULL, true, 0, 0, 0 },
83
+ { "sh4eb", false, NULL, false, 0, 0, 0 },
84
+ { "sparc", false, NULL, false, 0, 0, 0 },
85
+ { "sparc32plus", false, NULL, false, 0, 0, 0 },
86
+ { "sparc64", false, NULL, false, 0, 0, 0 },
87
+ { "tricore", false, NULL, true, 0, 0, 0 },
88
+ { "x86_64", true, "\x0f\xa2", true, "rax", "rdi", "rsi" },
89
+ { "xtensa", false, NULL, true, 0, 0, 0 },
90
+ { "xtensaeb", false, NULL, false, 0, 0, 0 },
91
+ { NULL, false, NULL, false, 0, 0, 0 },
92
+};
93
+
94
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
95
+
96
+/*
97
+ * Returns a handle to a register with a given name, or NULL if there is no
98
+ * such register.
99
+ */
100
+static struct qemu_plugin_register *get_register(const char *name)
101
+{
102
+ GArray *registers = qemu_plugin_get_registers();
103
+
104
+ struct qemu_plugin_register *handle = NULL;
105
+
106
+ qemu_plugin_reg_descriptor *reg_descriptors =
107
+ (qemu_plugin_reg_descriptor *)registers->data;
108
+
109
+ for (size_t i = 0; i < registers->len; i++) {
110
+ if (!strcmp(reg_descriptors[i].name, name)) {
111
+ handle = reg_descriptors[i].handle;
112
+ }
113
+ }
114
+
115
+ g_array_free(registers, true);
116
+
117
+ return handle;
118
+}
119
+
120
+/*
121
+ * Transforms a byte array with at most 8 entries into a uint64_t
122
+ * depending on the target machine's endianness.
123
+ */
124
+static uint64_t byte_array_to_uint64(GByteArray *buf)
125
+{
126
+ uint64_t value = 0;
127
+ if (hypercall_spec->little_endian) {
128
+ for (int i = 0; i < buf->len && i < sizeof(uint64_t); i++) {
129
+ value |= ((uint64_t)buf->data[i]) << (i * 8);
130
+ }
131
+ } else {
132
+ for (int i = 0; i < buf->len && i < sizeof(uint64_t); i++) {
133
+ value |= ((uint64_t)buf->data[i]) << ((buf->len - 1 - i) * 8);
134
+ }
135
+ }
136
+ return value;
137
+}
138
+
139
+/*
140
+ * Handle a "hyperacll" instruction, which has some special meaning for this
141
+ * plugin.
142
+ */
143
+static void hypercall(unsigned int vcpu_index, void *userdata)
144
+{
145
+ uint64_t num = 0, arg0 = 0, arg1 = 0;
146
+ GByteArray *buf = g_byte_array_new();
147
+ qemu_plugin_read_register(get_register(hypercall_spec->num_reg), buf);
148
+ num = byte_array_to_uint64(buf);
149
+
150
+ g_byte_array_set_size(buf, 0);
151
+ qemu_plugin_read_register(get_register(hypercall_spec->arg0_reg), buf);
152
+ arg0 = byte_array_to_uint64(buf);
153
+
154
+ g_byte_array_set_size(buf, 0);
155
+ qemu_plugin_read_register(get_register(hypercall_spec->arg1_reg), buf);
156
+ arg1 = byte_array_to_uint64(buf);
157
+
158
+ switch (num) {
159
+ /*
160
+ * The write hypercall (#0x13371337) tells the plugin to write random bytes
161
+ * of a given size into the memory of the emulated system at a particular
162
+ * vaddr
163
+ */
164
+ case 0x13371337: {
165
+ GByteArray *data = g_byte_array_new();
166
+ g_byte_array_set_size(data, arg1);
167
+ for (uint64_t i = 0; i < arg1; i++) {
168
+ data->data[i] = (uint8_t)g_random_int();
169
+ }
170
+ qemu_plugin_write_memory_vaddr(arg0, data);
171
+ break;
172
+ }
173
+ default:
174
+ break;
175
+ }
176
+
177
+ g_byte_array_free(buf, TRUE);
178
+}
179
+
180
+/*
181
+ * Callback on translation of a translation block.
182
+ */
183
+static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
184
+{
185
+ for (size_t i = 0; i < qemu_plugin_tb_n_insns(tb); i++) {
186
+ struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
187
+ GByteArray *insn_data = g_byte_array_new();
188
+ size_t insn_len = qemu_plugin_insn_size(insn);
189
+ g_byte_array_set_size(insn_data, insn_len);
190
+ qemu_plugin_insn_data(insn, insn_data->data, insn_data->len);
191
+ if (!memcmp(insn_data->data, hypercall_spec->hypercall, insn_data->len)) {
192
+ qemu_plugin_register_vcpu_insn_exec_cb(insn, hypercall,
193
+ QEMU_PLUGIN_CB_R_REGS, NULL);
194
+ }
195
+ g_byte_array_free(insn_data, true);
196
+ }
197
+}
198
+
199
+
200
+/*
201
+ * Called when the plugin is installed
202
+ */
203
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
204
+ const qemu_info_t *info, int argc,
205
+ char **argv)
206
+{
207
+ hypercall_spec = &hypercall_specs[0];
208
+ while (hypercall_spec->name != NULL) {
209
+ if (!strcmp(hypercall_spec->name, info->target_name)) {
210
+ break;
211
+ }
212
+ hypercall_spec++;
213
+ }
214
+
215
+ if (hypercall_spec->name == NULL) {
216
+ qemu_plugin_outs("Error: no hypercall spec.");
217
+ return -1;
218
+ }
219
+
220
+ qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
221
+
222
+ return 0;
223
+}
224
diff --git a/tests/tcg/plugins/meson.build b/tests/tcg/plugins/meson.build
225
index XXXXXXX..XXXXXXX 100644
226
--- a/tests/tcg/plugins/meson.build
227
+++ b/tests/tcg/plugins/meson.build
228
@@ -XXX,XX +XXX,XX @@
229
t = []
230
if get_option('plugins')
231
- foreach i : ['bb', 'empty', 'inline', 'insn', 'mem', 'syscall']
232
+ foreach i : ['bb', 'empty', 'inline', 'insn', 'mem', 'syscall', 'inject']
233
if host_os == 'windows'
234
t += shared_module(i, files(i + '.c') + '../../../contrib/plugins/win32_linker.c',
235
include_directories: '../../../include/qemu',
236
diff --git a/tests/tcg/x86_64/Makefile.target b/tests/tcg/x86_64/Makefile.target
237
index XXXXXXX..XXXXXXX 100644
238
--- a/tests/tcg/x86_64/Makefile.target
239
+++ b/tests/tcg/x86_64/Makefile.target
240
@@ -XXX,XX +XXX,XX @@ X86_64_TESTS += adox
241
X86_64_TESTS += test-1648
242
X86_64_TESTS += test-2175
243
X86_64_TESTS += cross-modifying-code
244
+X86_64_TESTS += inject-target
245
TESTS=$(MULTIARCH_TESTS) $(X86_64_TESTS) test-x86_64
246
else
247
TESTS=$(MULTIARCH_TESTS)
248
diff --git a/tests/tcg/x86_64/inject-target.c b/tests/tcg/x86_64/inject-target.c
249
new file mode 100644
250
index XXXXXXX..XXXXXXX
251
--- /dev/null
252
+++ b/tests/tcg/x86_64/inject-target.c
253
@@ -XXX,XX +XXX,XX @@
254
+#include <stddef.h>
255
+#include <stdint.h>
256
+#include <stdio.h>
257
+
258
+#define hypercall(num, arg0, arg1) \
259
+ unsigned int _a __attribute__((unused)) = 0; \
260
+ unsigned int _b __attribute__((unused)) = 0; \
261
+ unsigned int _c __attribute__((unused)) = 0; \
262
+ unsigned int _d __attribute__((unused)) = 0; \
263
+ __asm__ __volatile__("cpuid\n\t" \
264
+ : "=a"(_a), "=b"(_b), "=c"(_c), "=d"(_d) \
265
+ : "a"(num), "D"(arg0), "S"(arg1));
266
+
267
+int main(void)
268
+{
269
+ uint16_t value;
270
+
271
+ for (size_t i = 0; i < 1000000; i++) {
272
+ hypercall(0x13371337, &value, sizeof(value));
273
+ if (value == 0x1337) {
274
+ printf("Victory!\n");
275
+ return 0;
276
+ }
277
+ }
278
+ return 1;
279
+}
280
+
281
--
282
2.46.1
diff view generated by jsdifflib