xref: /openbmc/qemu/tests/qtest/fuzz/qos_fuzz.c (revision d89b64beea65f77c21a553cb54cb97b75c53dc21)
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