qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio
at master 355 lines 10 kB view raw
1#include "qemu/osdep.h" 2#include "qapi/qmp/qdict.h" 3#include "qapi/qmp/qjson.h" 4#include "qapi/qmp/qnum.h" 5#include "qapi/qmp/qstring.h" 6#include "qapi/error.h" 7#include "qapi/qobject-input-visitor.h" 8#include "tests/test-qapi-types.h" 9#include "tests/test-qapi-visit.h" 10#include "test-qapi-commands.h" 11#include "test-qapi-init-commands.h" 12 13static QmpCommandList qmp_commands; 14 15#if defined(TEST_IF_STRUCT) && defined(TEST_IF_CMD) 16UserDefThree *qmp_TestIfCmd(TestIfStruct *foo, Error **errp) 17{ 18 return NULL; 19} 20#endif 21 22UserDefThree *qmp_TestCmdReturnDefThree(Error **errp) 23{ 24 return NULL; 25} 26 27void qmp_user_def_cmd(Error **errp) 28{ 29} 30 31void qmp_test_flags_command(Error **errp) 32{ 33} 34 35void qmp_cmd_success_response(Error **errp) 36{ 37} 38 39Empty2 *qmp_user_def_cmd0(Error **errp) 40{ 41 return g_new0(Empty2, 1); 42} 43 44void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp) 45{ 46} 47 48void qmp_test_features0(FeatureStruct0 *fs0, FeatureStruct1 *fs1, 49 FeatureStruct2 *fs2, FeatureStruct3 *fs3, 50 FeatureStruct4 *fs4, CondFeatureStruct1 *cfs1, 51 CondFeatureStruct2 *cfs2, CondFeatureStruct3 *cfs3, 52 Error **errp) 53{ 54} 55 56void qmp_test_command_features1(Error **errp) 57{ 58} 59 60void qmp_test_command_features3(Error **errp) 61{ 62} 63 64void qmp_test_command_cond_features1(Error **errp) 65{ 66} 67 68void qmp_test_command_cond_features2(Error **errp) 69{ 70} 71 72void qmp_test_command_cond_features3(Error **errp) 73{ 74} 75 76UserDefTwo *qmp_user_def_cmd2(UserDefOne *ud1a, 77 bool has_udb1, UserDefOne *ud1b, 78 Error **errp) 79{ 80 UserDefTwo *ret; 81 UserDefOne *ud1c = g_malloc0(sizeof(UserDefOne)); 82 UserDefOne *ud1d = g_malloc0(sizeof(UserDefOne)); 83 84 ud1c->string = strdup(ud1a->string); 85 ud1c->integer = ud1a->integer; 86 ud1d->string = strdup(has_udb1 ? ud1b->string : "blah0"); 87 ud1d->integer = has_udb1 ? ud1b->integer : 0; 88 89 ret = g_new0(UserDefTwo, 1); 90 ret->string0 = strdup("blah1"); 91 ret->dict1 = g_new0(UserDefTwoDict, 1); 92 ret->dict1->string1 = strdup("blah2"); 93 ret->dict1->dict2 = g_new0(UserDefTwoDictDict, 1); 94 ret->dict1->dict2->userdef = ud1c; 95 ret->dict1->dict2->string = strdup("blah3"); 96 ret->dict1->dict3 = g_new0(UserDefTwoDictDict, 1); 97 ret->dict1->has_dict3 = true; 98 ret->dict1->dict3->userdef = ud1d; 99 ret->dict1->dict3->string = strdup("blah4"); 100 101 return ret; 102} 103 104int64_t qmp_guest_get_time(int64_t a, bool has_b, int64_t b, Error **errp) 105{ 106 return a + (has_b ? b : 0); 107} 108 109QObject *qmp_guest_sync(QObject *arg, Error **errp) 110{ 111 return arg; 112} 113 114void qmp_boxed_struct(UserDefZero *arg, Error **errp) 115{ 116} 117 118void qmp_boxed_union(UserDefListUnion *arg, Error **errp) 119{ 120} 121 122void qmp_boxed_empty(Empty1 *arg, Error **errp) 123{ 124} 125 126__org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a, 127 __org_qemu_x_StructList *b, 128 __org_qemu_x_Union2 *c, 129 __org_qemu_x_Alt *d, 130 Error **errp) 131{ 132 __org_qemu_x_Union1 *ret = g_new0(__org_qemu_x_Union1, 1); 133 134 ret->type = ORG_QEMU_X_UNION1_KIND___ORG_QEMU_X_BRANCH; 135 ret->u.__org_qemu_x_branch.data = strdup("blah1"); 136 137 /* Also test that 'wchar-t' was munged to 'q_wchar_t' */ 138 if (b && b->value && !b->value->has_q_wchar_t) { 139 b->value->q_wchar_t = 1; 140 } 141 return ret; 142} 143 144 145static QObject *do_qmp_dispatch(bool allow_oob, const char *template, ...) 146{ 147 va_list ap; 148 QDict *req, *resp; 149 QObject *ret; 150 151 va_start(ap, template); 152 req = qdict_from_vjsonf_nofail(template, ap); 153 va_end(ap); 154 155 resp = qmp_dispatch(&qmp_commands, QOBJECT(req), allow_oob); 156 g_assert(resp); 157 ret = qdict_get(resp, "return"); 158 g_assert(ret); 159 g_assert(qdict_size(resp) == 1); 160 161 qobject_ref(ret); 162 qobject_unref(resp); 163 qobject_unref(req); 164 return ret; 165} 166 167static void do_qmp_dispatch_error(bool allow_oob, ErrorClass cls, 168 const char *template, ...) 169{ 170 va_list ap; 171 QDict *req, *resp; 172 QDict *error; 173 174 va_start(ap, template); 175 req = qdict_from_vjsonf_nofail(template, ap); 176 va_end(ap); 177 178 resp = qmp_dispatch(&qmp_commands, QOBJECT(req), allow_oob); 179 g_assert(resp); 180 error = qdict_get_qdict(resp, "error"); 181 g_assert(error); 182 g_assert_cmpstr(qdict_get_try_str(error, "class"), 183 ==, QapiErrorClass_str(cls)); 184 g_assert(qdict_get_try_str(error, "desc")); 185 g_assert(qdict_size(error) == 2); 186 g_assert(qdict_size(resp) == 1); 187 188 qobject_unref(resp); 189 qobject_unref(req); 190} 191 192/* test commands with no input and no return value */ 193static void test_dispatch_cmd(void) 194{ 195 QDict *ret; 196 197 ret = qobject_to(QDict, 198 do_qmp_dispatch(false, 199 "{ 'execute': 'user_def_cmd' }")); 200 assert(ret && qdict_size(ret) == 0); 201 qobject_unref(ret); 202} 203 204static void test_dispatch_cmd_oob(void) 205{ 206 QDict *ret; 207 208 ret = qobject_to(QDict, 209 do_qmp_dispatch(true, 210 "{ 'exec-oob': 'test-flags-command' }")); 211 assert(ret && qdict_size(ret) == 0); 212 qobject_unref(ret); 213} 214 215/* test commands that return an error due to invalid parameters */ 216static void test_dispatch_cmd_failure(void) 217{ 218 /* missing arguments */ 219 do_qmp_dispatch_error(false, ERROR_CLASS_GENERIC_ERROR, 220 "{ 'execute': 'user_def_cmd2' }"); 221 222 /* extra arguments */ 223 do_qmp_dispatch_error(false, ERROR_CLASS_GENERIC_ERROR, 224 "{ 'execute': 'user_def_cmd'," 225 " 'arguments': { 'a': 66 } }"); 226} 227 228static void test_dispatch_cmd_success_response(void) 229{ 230 QDict *req = qdict_new(); 231 QDict *resp; 232 233 qdict_put_str(req, "execute", "cmd-success-response"); 234 resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false); 235 g_assert_null(resp); 236 qobject_unref(req); 237} 238 239/* test commands that involve both input parameters and return values */ 240static void test_dispatch_cmd_io(void) 241{ 242 QDict *ret, *ret_dict, *ret_dict_dict, *ret_dict_dict_userdef; 243 QDict *ret_dict_dict2, *ret_dict_dict2_userdef; 244 QNum *ret3; 245 int64_t val; 246 247 ret = qobject_to(QDict, do_qmp_dispatch(false, 248 "{ 'execute': 'user_def_cmd2', 'arguments': {" 249 " 'ud1a': { 'integer': 42, 'string': 'hello' }," 250 " 'ud1b': { 'integer': 422, 'string': 'hello2' } } }")); 251 252 assert(!strcmp(qdict_get_str(ret, "string0"), "blah1")); 253 ret_dict = qdict_get_qdict(ret, "dict1"); 254 assert(!strcmp(qdict_get_str(ret_dict, "string1"), "blah2")); 255 ret_dict_dict = qdict_get_qdict(ret_dict, "dict2"); 256 ret_dict_dict_userdef = qdict_get_qdict(ret_dict_dict, "userdef"); 257 assert(qdict_get_int(ret_dict_dict_userdef, "integer") == 42); 258 assert(!strcmp(qdict_get_str(ret_dict_dict_userdef, "string"), "hello")); 259 assert(!strcmp(qdict_get_str(ret_dict_dict, "string"), "blah3")); 260 ret_dict_dict2 = qdict_get_qdict(ret_dict, "dict3"); 261 ret_dict_dict2_userdef = qdict_get_qdict(ret_dict_dict2, "userdef"); 262 assert(qdict_get_int(ret_dict_dict2_userdef, "integer") == 422); 263 assert(!strcmp(qdict_get_str(ret_dict_dict2_userdef, "string"), "hello2")); 264 assert(!strcmp(qdict_get_str(ret_dict_dict2, "string"), "blah4")); 265 qobject_unref(ret); 266 267 ret3 = qobject_to(QNum, do_qmp_dispatch(false, 268 "{ 'execute': 'guest-get-time', 'arguments': { 'a': 66 } }")); 269 g_assert(qnum_get_try_int(ret3, &val)); 270 g_assert_cmpint(val, ==, 66); 271 qobject_unref(ret3); 272} 273 274/* test generated dealloc functions for generated types */ 275static void test_dealloc_types(void) 276{ 277 UserDefOne *ud1test, *ud1a, *ud1b; 278 UserDefOneList *ud1list; 279 280 ud1test = g_malloc0(sizeof(UserDefOne)); 281 ud1test->integer = 42; 282 ud1test->string = g_strdup("hi there 42"); 283 284 qapi_free_UserDefOne(ud1test); 285 286 ud1a = g_malloc0(sizeof(UserDefOne)); 287 ud1a->integer = 43; 288 ud1a->string = g_strdup("hi there 43"); 289 290 ud1b = g_malloc0(sizeof(UserDefOne)); 291 ud1b->integer = 44; 292 ud1b->string = g_strdup("hi there 44"); 293 294 ud1list = g_malloc0(sizeof(UserDefOneList)); 295 ud1list->value = ud1a; 296 ud1list->next = g_malloc0(sizeof(UserDefOneList)); 297 ud1list->next->value = ud1b; 298 299 qapi_free_UserDefOneList(ud1list); 300} 301 302/* test generated deallocation on an object whose construction was prematurely 303 * terminated due to an error */ 304static void test_dealloc_partial(void) 305{ 306 static const char text[] = "don't leak me"; 307 308 UserDefTwo *ud2 = NULL; 309 Error *err = NULL; 310 311 /* create partial object */ 312 { 313 QDict *ud2_dict; 314 Visitor *v; 315 316 ud2_dict = qdict_new(); 317 qdict_put_str(ud2_dict, "string0", text); 318 319 v = qobject_input_visitor_new(QOBJECT(ud2_dict)); 320 visit_type_UserDefTwo(v, NULL, &ud2, &err); 321 visit_free(v); 322 qobject_unref(ud2_dict); 323 } 324 325 /* verify that visit_type_XXX() cleans up properly on error */ 326 error_free_or_abort(&err); 327 assert(!ud2); 328 329 /* Manually create a partial object, leaving ud2->dict1 at NULL */ 330 ud2 = g_new0(UserDefTwo, 1); 331 ud2->string0 = g_strdup(text); 332 333 /* tear down partial object */ 334 qapi_free_UserDefTwo(ud2); 335} 336 337 338int main(int argc, char **argv) 339{ 340 g_test_init(&argc, &argv, NULL); 341 342 g_test_add_func("/qmp/dispatch_cmd", test_dispatch_cmd); 343 g_test_add_func("/qmp/dispatch_cmd_oob", test_dispatch_cmd_oob); 344 g_test_add_func("/qmp/dispatch_cmd_failure", test_dispatch_cmd_failure); 345 g_test_add_func("/qmp/dispatch_cmd_io", test_dispatch_cmd_io); 346 g_test_add_func("/qmp/dispatch_cmd_success_response", 347 test_dispatch_cmd_success_response); 348 g_test_add_func("/qmp/dealloc_types", test_dealloc_types); 349 g_test_add_func("/qmp/dealloc_partial", test_dealloc_partial); 350 351 test_qmp_init_marshal(&qmp_commands); 352 g_test_run(); 353 354 return 0; 355}