1275ab39dSAlexander Bulekov /*
2275ab39dSAlexander Bulekov * QOS-assisted fuzzing helpers
3275ab39dSAlexander Bulekov *
4275ab39dSAlexander Bulekov * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
5275ab39dSAlexander Bulekov *
6275ab39dSAlexander Bulekov * This library is free software; you can redistribute it and/or
7275ab39dSAlexander Bulekov * modify it under the terms of the GNU Lesser General Public
8dc0ad02dSThomas Huth * License version 2.1 as published by the Free Software Foundation.
9275ab39dSAlexander Bulekov *
10275ab39dSAlexander Bulekov * This library is distributed in the hope that it will be useful,
11275ab39dSAlexander Bulekov * but WITHOUT ANY WARRANTY; without even the implied warranty of
12275ab39dSAlexander Bulekov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13275ab39dSAlexander Bulekov * Lesser General Public License for more details.
14275ab39dSAlexander Bulekov *
15275ab39dSAlexander Bulekov * You should have received a copy of the GNU Lesser General Public
16275ab39dSAlexander Bulekov * License along with this library; if not, see <http://www.gnu.org/licenses/>
17275ab39dSAlexander Bulekov */
18275ab39dSAlexander Bulekov
19275ab39dSAlexander Bulekov #include "qemu/osdep.h"
20275ab39dSAlexander Bulekov #include "qemu/units.h"
21275ab39dSAlexander Bulekov #include "qapi/error.h"
22275ab39dSAlexander Bulekov #include "exec/memory.h"
23275ab39dSAlexander Bulekov #include "qemu/main-loop.h"
24275ab39dSAlexander Bulekov
25907b5105SMarc-André Lureau #include "tests/qtest/libqtest.h"
26b243c73cSXuzhou Cheng #include "tests/qtest/libqos/libqos-malloc.h"
27275ab39dSAlexander Bulekov #include "tests/qtest/libqos/qgraph.h"
28275ab39dSAlexander Bulekov #include "tests/qtest/libqos/qgraph_internal.h"
29275ab39dSAlexander Bulekov #include "tests/qtest/libqos/qos_external.h"
30275ab39dSAlexander Bulekov
31275ab39dSAlexander Bulekov #include "fuzz.h"
32275ab39dSAlexander Bulekov #include "qos_fuzz.h"
33275ab39dSAlexander Bulekov
34275ab39dSAlexander Bulekov #include "qapi/qapi-commands-machine.h"
35275ab39dSAlexander Bulekov #include "qapi/qapi-commands-qom.h"
36275ab39dSAlexander Bulekov
37275ab39dSAlexander Bulekov
38275ab39dSAlexander Bulekov void *fuzz_qos_obj;
39275ab39dSAlexander Bulekov QGuestAllocator *fuzz_qos_alloc;
40275ab39dSAlexander Bulekov
41275ab39dSAlexander Bulekov static const char *fuzz_target_name;
42275ab39dSAlexander Bulekov static char **fuzz_path_vec;
43275ab39dSAlexander Bulekov
qos_set_machines_devices_available(void)44275ab39dSAlexander Bulekov static void qos_set_machines_devices_available(void)
45275ab39dSAlexander Bulekov {
46a56f3cdbSMarkus Armbruster MachineInfoList *mach_info;
47a56f3cdbSMarkus Armbruster ObjectTypeInfoList *type_info;
48275ab39dSAlexander Bulekov
49236e9397SMaksim Davydov mach_info = qmp_query_machines(false, false, &error_abort);
50a56f3cdbSMarkus Armbruster machines_apply_to_node(mach_info);
51a56f3cdbSMarkus Armbruster qapi_free_MachineInfoList(mach_info);
52275ab39dSAlexander Bulekov
53047f2ca1SMarkus Armbruster type_info = qmp_qom_list_types("device", true, true, &error_abort);
54a56f3cdbSMarkus Armbruster types_apply_to_node(type_info);
55a56f3cdbSMarkus Armbruster qapi_free_ObjectTypeInfoList(type_info);
56275ab39dSAlexander Bulekov }
57275ab39dSAlexander Bulekov
58275ab39dSAlexander Bulekov static char **current_path;
59275ab39dSAlexander Bulekov
qos_allocate_objects(QTestState * qts,QGuestAllocator ** p_alloc)60275ab39dSAlexander Bulekov void *qos_allocate_objects(QTestState *qts, QGuestAllocator **p_alloc)
61275ab39dSAlexander Bulekov {
62275ab39dSAlexander Bulekov return allocate_objects(qts, current_path + 1, p_alloc);
63275ab39dSAlexander Bulekov }
64275ab39dSAlexander Bulekov
qos_build_main_args(void)65f5ec79f5SAlexander Bulekov static GString *qos_build_main_args(void)
66275ab39dSAlexander Bulekov {
67275ab39dSAlexander Bulekov char **path = fuzz_path_vec;
68275ab39dSAlexander Bulekov QOSGraphNode *test_node;
69c59c582dSAlexChen GString *cmd_line;
70275ab39dSAlexander Bulekov void *test_arg;
71275ab39dSAlexander Bulekov
72275ab39dSAlexander Bulekov if (!path) {
73275ab39dSAlexander Bulekov fprintf(stderr, "QOS Path not found\n");
74275ab39dSAlexander Bulekov abort();
75275ab39dSAlexander Bulekov }
76275ab39dSAlexander Bulekov
77275ab39dSAlexander Bulekov /* Before test */
78c59c582dSAlexChen cmd_line = g_string_new(path[0]);
79275ab39dSAlexander Bulekov current_path = path;
80275ab39dSAlexander Bulekov test_node = qos_graph_get_node(path[(g_strv_length(path) - 1)]);
81275ab39dSAlexander Bulekov test_arg = test_node->u.test.arg;
82275ab39dSAlexander Bulekov if (test_node->u.test.before) {
83275ab39dSAlexander Bulekov test_arg = test_node->u.test.before(cmd_line, test_arg);
84275ab39dSAlexander Bulekov }
85275ab39dSAlexander Bulekov /* Prepend the arguments that we need */
86275ab39dSAlexander Bulekov g_string_prepend(cmd_line,
87275ab39dSAlexander Bulekov TARGET_NAME " -display none -machine accel=qtest -m 64 ");
88f5ec79f5SAlexander Bulekov return cmd_line;
89275ab39dSAlexander Bulekov }
90275ab39dSAlexander Bulekov
91275ab39dSAlexander Bulekov /*
92275ab39dSAlexander Bulekov * This function is largely a copy of qos-test.c:walk_path. Since walk_path
93275ab39dSAlexander Bulekov * is itself a callback, its a little annoying to add another argument/layer of
94275ab39dSAlexander Bulekov * indirection
95275ab39dSAlexander Bulekov */
walk_path(QOSGraphNode * orig_path,int len)96275ab39dSAlexander Bulekov static void walk_path(QOSGraphNode *orig_path, int len)
97275ab39dSAlexander Bulekov {
98275ab39dSAlexander Bulekov QOSGraphNode *path;
99275ab39dSAlexander Bulekov QOSGraphEdge *edge;
100275ab39dSAlexander Bulekov
1013fc92f87SAlexander Bulekov /*
1023fc92f87SAlexander Bulekov * etype set to QEDGE_CONSUMED_BY so that machine can add to the command
1033fc92f87SAlexander Bulekov * line
1043fc92f87SAlexander Bulekov */
105275ab39dSAlexander Bulekov QOSEdgeType etype = QEDGE_CONSUMED_BY;
106275ab39dSAlexander Bulekov
107275ab39dSAlexander Bulekov /* twice QOS_PATH_MAX_ELEMENT_SIZE since each edge can have its arg */
108275ab39dSAlexander Bulekov char **path_vec = g_new0(char *, (QOS_PATH_MAX_ELEMENT_SIZE * 2));
109275ab39dSAlexander Bulekov int path_vec_size = 0;
110275ab39dSAlexander Bulekov
111275ab39dSAlexander Bulekov char *after_cmd, *before_cmd, *after_device;
112275ab39dSAlexander Bulekov GString *after_device_str = g_string_new("");
113275ab39dSAlexander Bulekov char *node_name = orig_path->name, *path_str;
114275ab39dSAlexander Bulekov
115275ab39dSAlexander Bulekov GString *cmd_line = g_string_new("");
116275ab39dSAlexander Bulekov GString *cmd_line2 = g_string_new("");
117275ab39dSAlexander Bulekov
118275ab39dSAlexander Bulekov path = qos_graph_get_node(node_name); /* root */
119275ab39dSAlexander Bulekov node_name = qos_graph_edge_get_dest(path->path_edge); /* machine name */
120275ab39dSAlexander Bulekov
121275ab39dSAlexander Bulekov path_vec[path_vec_size++] = node_name;
122275ab39dSAlexander Bulekov path_vec[path_vec_size++] = qos_get_machine_type(node_name);
123275ab39dSAlexander Bulekov
124275ab39dSAlexander Bulekov for (;;) {
125275ab39dSAlexander Bulekov path = qos_graph_get_node(node_name);
126275ab39dSAlexander Bulekov if (!path->path_edge) {
127275ab39dSAlexander Bulekov break;
128275ab39dSAlexander Bulekov }
129275ab39dSAlexander Bulekov
130275ab39dSAlexander Bulekov node_name = qos_graph_edge_get_dest(path->path_edge);
131275ab39dSAlexander Bulekov
132275ab39dSAlexander Bulekov /* append node command line + previous edge command line */
133275ab39dSAlexander Bulekov if (path->command_line && etype == QEDGE_CONSUMED_BY) {
134275ab39dSAlexander Bulekov g_string_append(cmd_line, path->command_line);
135275ab39dSAlexander Bulekov g_string_append(cmd_line, after_device_str->str);
136275ab39dSAlexander Bulekov g_string_truncate(after_device_str, 0);
137275ab39dSAlexander Bulekov }
138275ab39dSAlexander Bulekov
139275ab39dSAlexander Bulekov path_vec[path_vec_size++] = qos_graph_edge_get_name(path->path_edge);
140275ab39dSAlexander Bulekov /* detect if edge has command line args */
141275ab39dSAlexander Bulekov after_cmd = qos_graph_edge_get_after_cmd_line(path->path_edge);
142275ab39dSAlexander Bulekov after_device = qos_graph_edge_get_extra_device_opts(path->path_edge);
143275ab39dSAlexander Bulekov before_cmd = qos_graph_edge_get_before_cmd_line(path->path_edge);
144275ab39dSAlexander Bulekov edge = qos_graph_get_edge(path->name, node_name);
145275ab39dSAlexander Bulekov etype = qos_graph_edge_get_type(edge);
146275ab39dSAlexander Bulekov
147275ab39dSAlexander Bulekov if (before_cmd) {
148275ab39dSAlexander Bulekov g_string_append(cmd_line, before_cmd);
149275ab39dSAlexander Bulekov }
150275ab39dSAlexander Bulekov if (after_cmd) {
151275ab39dSAlexander Bulekov g_string_append(cmd_line2, after_cmd);
152275ab39dSAlexander Bulekov }
153275ab39dSAlexander Bulekov if (after_device) {
154275ab39dSAlexander Bulekov g_string_append(after_device_str, after_device);
155275ab39dSAlexander Bulekov }
156275ab39dSAlexander Bulekov }
157275ab39dSAlexander Bulekov
158275ab39dSAlexander Bulekov path_vec[path_vec_size++] = NULL;
159275ab39dSAlexander Bulekov g_string_append(cmd_line, after_device_str->str);
160275ab39dSAlexander Bulekov g_string_free(after_device_str, true);
161275ab39dSAlexander Bulekov
162275ab39dSAlexander Bulekov g_string_append(cmd_line, cmd_line2->str);
163275ab39dSAlexander Bulekov g_string_free(cmd_line2, true);
164275ab39dSAlexander Bulekov
165275ab39dSAlexander Bulekov /*
166275ab39dSAlexander Bulekov * here position 0 has <arch>/<machine>, position 1 has <machine>.
167275ab39dSAlexander Bulekov * The path must not have the <arch>, qtest_add_data_func adds it.
168275ab39dSAlexander Bulekov */
169275ab39dSAlexander Bulekov path_str = g_strjoinv("/", path_vec + 1);
170275ab39dSAlexander Bulekov
171275ab39dSAlexander Bulekov /* Check that this is the test we care about: */
172275ab39dSAlexander Bulekov char *test_name = strrchr(path_str, '/') + 1;
173275ab39dSAlexander Bulekov if (strcmp(test_name, fuzz_target_name) == 0) {
174275ab39dSAlexander Bulekov /*
175275ab39dSAlexander Bulekov * put arch/machine in position 1 so run_one_test can do its work
176275ab39dSAlexander Bulekov * and add the command line at position 0.
177275ab39dSAlexander Bulekov */
178275ab39dSAlexander Bulekov path_vec[1] = path_vec[0];
179275ab39dSAlexander Bulekov path_vec[0] = g_string_free(cmd_line, false);
180275ab39dSAlexander Bulekov
181275ab39dSAlexander Bulekov fuzz_path_vec = path_vec;
182275ab39dSAlexander Bulekov } else {
183*7c66540dSDmitry Frolov g_string_free(cmd_line, true);
184275ab39dSAlexander Bulekov g_free(path_vec);
185275ab39dSAlexander Bulekov }
186275ab39dSAlexander Bulekov
187275ab39dSAlexander Bulekov g_free(path_str);
188275ab39dSAlexander Bulekov }
189275ab39dSAlexander Bulekov
qos_get_cmdline(FuzzTarget * t)190f5ec79f5SAlexander Bulekov static GString *qos_get_cmdline(FuzzTarget *t)
191275ab39dSAlexander Bulekov {
192275ab39dSAlexander Bulekov /*
193275ab39dSAlexander Bulekov * Set a global variable that we use to identify the qos_path for our
194275ab39dSAlexander Bulekov * fuzz_target
195275ab39dSAlexander Bulekov */
196275ab39dSAlexander Bulekov fuzz_target_name = t->name;
197275ab39dSAlexander Bulekov qos_set_machines_devices_available();
198275ab39dSAlexander Bulekov qos_graph_foreach_test_path(walk_path);
199275ab39dSAlexander Bulekov return qos_build_main_args();
200275ab39dSAlexander Bulekov }
201275ab39dSAlexander Bulekov
fuzz_add_qos_target(FuzzTarget * fuzz_opts,const char * interface,QOSGraphTestOptions * opts)202275ab39dSAlexander Bulekov void fuzz_add_qos_target(
203275ab39dSAlexander Bulekov FuzzTarget *fuzz_opts,
204275ab39dSAlexander Bulekov const char *interface,
205275ab39dSAlexander Bulekov QOSGraphTestOptions *opts
206275ab39dSAlexander Bulekov )
207275ab39dSAlexander Bulekov {
208275ab39dSAlexander Bulekov qos_add_test(fuzz_opts->name, interface, NULL, opts);
209275ab39dSAlexander Bulekov fuzz_opts->get_init_cmdline = qos_get_cmdline;
210275ab39dSAlexander Bulekov fuzz_add_target(fuzz_opts);
211275ab39dSAlexander Bulekov }
212275ab39dSAlexander Bulekov
qos_init_path(QTestState * s)213275ab39dSAlexander Bulekov void qos_init_path(QTestState *s)
214275ab39dSAlexander Bulekov {
215275ab39dSAlexander Bulekov fuzz_qos_obj = qos_allocate_objects(s , &fuzz_qos_alloc);
216275ab39dSAlexander Bulekov }
217