12345c77cSMichael Roth /* 22345c77cSMichael Roth * Core Definitions for QAPI Visitor Classes 32345c77cSMichael Roth * 47c91aabdSEric Blake * Copyright (C) 2012-2016 Red Hat, Inc. 52345c77cSMichael Roth * Copyright IBM, Corp. 2011 62345c77cSMichael Roth * 72345c77cSMichael Roth * Authors: 82345c77cSMichael Roth * Anthony Liguori <aliguori@us.ibm.com> 92345c77cSMichael Roth * 102345c77cSMichael Roth * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 112345c77cSMichael Roth * See the COPYING.LIB file in the top-level directory. 122345c77cSMichael Roth * 132345c77cSMichael Roth */ 142345c77cSMichael Roth 15cbf21151SPeter Maydell #include "qemu/osdep.h" 16da34e65cSMarkus Armbruster #include "qapi/error.h" 17*113e47aeSMarkus Armbruster #include "qapi/util.h" 1879ee7df8SPaolo Bonzini #include "qemu-common.h" 1969dd62dfSKevin Wolf #include "qapi/qmp/qobject.h" 207b1b5d19SPaolo Bonzini #include "qapi/qmp/qerror.h" 217b1b5d19SPaolo Bonzini #include "qapi/visitor.h" 227b1b5d19SPaolo Bonzini #include "qapi/visitor-impl.h" 23ebfd93b6SDaniel P. Berrange #include "trace.h" 242345c77cSMichael Roth 253b098d56SEric Blake void visit_complete(Visitor *v, void *opaque) 263b098d56SEric Blake { 273b098d56SEric Blake assert(v->type != VISITOR_OUTPUT || v->complete); 28ebfd93b6SDaniel P. Berrange trace_visit_complete(v, opaque); 293b098d56SEric Blake if (v->complete) { 303b098d56SEric Blake v->complete(v, opaque); 313b098d56SEric Blake } 323b098d56SEric Blake } 333b098d56SEric Blake 342c0ef9f4SEric Blake void visit_free(Visitor *v) 352c0ef9f4SEric Blake { 36ebfd93b6SDaniel P. Berrange trace_visit_free(v); 372c0ef9f4SEric Blake if (v) { 382c0ef9f4SEric Blake v->free(v); 392c0ef9f4SEric Blake } 402c0ef9f4SEric Blake } 412c0ef9f4SEric Blake 4251e72bc1SEric Blake void visit_start_struct(Visitor *v, const char *name, void **obj, 43337283dfSEric Blake size_t size, Error **errp) 442345c77cSMichael Roth { 45e58d695eSEric Blake Error *err = NULL; 46e58d695eSEric Blake 47ebfd93b6SDaniel P. Berrange trace_visit_start_struct(v, name, obj, size); 48adfb264cSEric Blake if (obj) { 49adfb264cSEric Blake assert(size); 50a15fcc3cSEric Blake assert(!(v->type & VISITOR_OUTPUT) || *obj); 51adfb264cSEric Blake } 52e58d695eSEric Blake v->start_struct(v, name, obj, size, &err); 53a15fcc3cSEric Blake if (obj && (v->type & VISITOR_INPUT)) { 54e58d695eSEric Blake assert(!err != !*obj); 55e58d695eSEric Blake } 56e58d695eSEric Blake error_propagate(errp, err); 572345c77cSMichael Roth } 582345c77cSMichael Roth 5915c2f669SEric Blake void visit_check_struct(Visitor *v, Error **errp) 602345c77cSMichael Roth { 61ebfd93b6SDaniel P. Berrange trace_visit_check_struct(v); 6215c2f669SEric Blake if (v->check_struct) { 6315c2f669SEric Blake v->check_struct(v, errp); 6415c2f669SEric Blake } 6515c2f669SEric Blake } 6615c2f669SEric Blake 671158bb2aSEric Blake void visit_end_struct(Visitor *v, void **obj) 6815c2f669SEric Blake { 69ebfd93b6SDaniel P. Berrange trace_visit_end_struct(v, obj); 701158bb2aSEric Blake v->end_struct(v, obj); 712345c77cSMichael Roth } 722345c77cSMichael Roth 73d9f62ddeSEric Blake void visit_start_list(Visitor *v, const char *name, GenericList **list, 74d9f62ddeSEric Blake size_t size, Error **errp) 752345c77cSMichael Roth { 76d9f62ddeSEric Blake Error *err = NULL; 77d9f62ddeSEric Blake 78d9f62ddeSEric Blake assert(!list || size >= sizeof(GenericList)); 79ebfd93b6SDaniel P. Berrange trace_visit_start_list(v, name, list, size); 80d9f62ddeSEric Blake v->start_list(v, name, list, size, &err); 81a15fcc3cSEric Blake if (list && (v->type & VISITOR_INPUT)) { 82d9f62ddeSEric Blake assert(!(err && *list)); 83d9f62ddeSEric Blake } 84d9f62ddeSEric Blake error_propagate(errp, err); 852345c77cSMichael Roth } 862345c77cSMichael Roth 87d9f62ddeSEric Blake GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size) 882345c77cSMichael Roth { 89d9f62ddeSEric Blake assert(tail && size >= sizeof(GenericList)); 90ebfd93b6SDaniel P. Berrange trace_visit_next_list(v, tail, size); 91d9f62ddeSEric Blake return v->next_list(v, tail, size); 922345c77cSMichael Roth } 932345c77cSMichael Roth 94a4a1c70dSMarkus Armbruster void visit_check_list(Visitor *v, Error **errp) 95a4a1c70dSMarkus Armbruster { 96a4a1c70dSMarkus Armbruster trace_visit_check_list(v); 97a4a1c70dSMarkus Armbruster if (v->check_list) { 98a4a1c70dSMarkus Armbruster v->check_list(v, errp); 99a4a1c70dSMarkus Armbruster } 100a4a1c70dSMarkus Armbruster } 101a4a1c70dSMarkus Armbruster 1021158bb2aSEric Blake void visit_end_list(Visitor *v, void **obj) 1032345c77cSMichael Roth { 104ebfd93b6SDaniel P. Berrange trace_visit_end_list(v, obj); 1051158bb2aSEric Blake v->end_list(v, obj); 1062345c77cSMichael Roth } 1072345c77cSMichael Roth 108dbf11922SEric Blake void visit_start_alternate(Visitor *v, const char *name, 109dbf11922SEric Blake GenericAlternate **obj, size_t size, 11060390d2dSMarc-André Lureau Error **errp) 111dbf11922SEric Blake { 112e58d695eSEric Blake Error *err = NULL; 113e58d695eSEric Blake 114dbf11922SEric Blake assert(obj && size >= sizeof(GenericAlternate)); 115a15fcc3cSEric Blake assert(!(v->type & VISITOR_OUTPUT) || *obj); 11660390d2dSMarc-André Lureau trace_visit_start_alternate(v, name, obj, size); 117dbf11922SEric Blake if (v->start_alternate) { 11860390d2dSMarc-André Lureau v->start_alternate(v, name, obj, size, &err); 119dbf11922SEric Blake } 120a15fcc3cSEric Blake if (v->type & VISITOR_INPUT) { 121e58d695eSEric Blake assert(v->start_alternate && !err != !*obj); 122e58d695eSEric Blake } 123e58d695eSEric Blake error_propagate(errp, err); 124dbf11922SEric Blake } 125dbf11922SEric Blake 1261158bb2aSEric Blake void visit_end_alternate(Visitor *v, void **obj) 127dbf11922SEric Blake { 128ebfd93b6SDaniel P. Berrange trace_visit_end_alternate(v, obj); 129dbf11922SEric Blake if (v->end_alternate) { 1301158bb2aSEric Blake v->end_alternate(v, obj); 131dbf11922SEric Blake } 132dbf11922SEric Blake } 133dbf11922SEric Blake 13451e72bc1SEric Blake bool visit_optional(Visitor *v, const char *name, bool *present) 1352345c77cSMichael Roth { 136ebfd93b6SDaniel P. Berrange trace_visit_optional(v, name, present); 137297a3646SMarkus Armbruster if (v->optional) { 1380b2a0d6bSEric Blake v->optional(v, name, present); 1392345c77cSMichael Roth } 14029637a6eSEric Blake return *present; 1412345c77cSMichael Roth } 1422345c77cSMichael Roth 14368ab47e4SEric Blake bool visit_is_input(Visitor *v) 14468ab47e4SEric Blake { 14568ab47e4SEric Blake return v->type == VISITOR_INPUT; 14668ab47e4SEric Blake } 14768ab47e4SEric Blake 14851e72bc1SEric Blake void visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp) 1492345c77cSMichael Roth { 150adfb264cSEric Blake assert(obj); 151ebfd93b6SDaniel P. Berrange trace_visit_type_int(v, name, obj); 1520b2a0d6bSEric Blake v->type_int64(v, name, obj, errp); 1532345c77cSMichael Roth } 1542345c77cSMichael Roth 15504e070d2SEric Blake static void visit_type_uintN(Visitor *v, uint64_t *obj, const char *name, 15604e070d2SEric Blake uint64_t max, const char *type, Error **errp) 15704e070d2SEric Blake { 15804e070d2SEric Blake Error *err = NULL; 15904e070d2SEric Blake uint64_t value = *obj; 16004e070d2SEric Blake 1610b2a0d6bSEric Blake v->type_uint64(v, name, &value, &err); 16204e070d2SEric Blake if (err) { 16304e070d2SEric Blake error_propagate(errp, err); 16404e070d2SEric Blake } else if (value > max) { 16504e070d2SEric Blake error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 16604e070d2SEric Blake name ? name : "null", type); 16704e070d2SEric Blake } else { 16804e070d2SEric Blake *obj = value; 16904e070d2SEric Blake } 17004e070d2SEric Blake } 17104e070d2SEric Blake 17251e72bc1SEric Blake void visit_type_uint8(Visitor *v, const char *name, uint8_t *obj, 17351e72bc1SEric Blake Error **errp) 1744e27e819SMichael Roth { 175ebfd93b6SDaniel P. Berrange uint64_t value; 176ebfd93b6SDaniel P. Berrange 177ebfd93b6SDaniel P. Berrange trace_visit_type_uint8(v, name, obj); 178ebfd93b6SDaniel P. Berrange value = *obj; 17904e070d2SEric Blake visit_type_uintN(v, &value, name, UINT8_MAX, "uint8_t", errp); 1804e27e819SMichael Roth *obj = value; 1814e27e819SMichael Roth } 1824e27e819SMichael Roth 18351e72bc1SEric Blake void visit_type_uint16(Visitor *v, const char *name, uint16_t *obj, 18404e070d2SEric Blake Error **errp) 1854e27e819SMichael Roth { 186ebfd93b6SDaniel P. Berrange uint64_t value; 187ebfd93b6SDaniel P. Berrange 188ebfd93b6SDaniel P. Berrange trace_visit_type_uint16(v, name, obj); 189ebfd93b6SDaniel P. Berrange value = *obj; 19004e070d2SEric Blake visit_type_uintN(v, &value, name, UINT16_MAX, "uint16_t", errp); 1914e27e819SMichael Roth *obj = value; 1924e27e819SMichael Roth } 1934e27e819SMichael Roth 19451e72bc1SEric Blake void visit_type_uint32(Visitor *v, const char *name, uint32_t *obj, 19504e070d2SEric Blake Error **errp) 1964e27e819SMichael Roth { 197ebfd93b6SDaniel P. Berrange uint64_t value; 198ebfd93b6SDaniel P. Berrange 199ebfd93b6SDaniel P. Berrange trace_visit_type_uint32(v, name, obj); 200ebfd93b6SDaniel P. Berrange value = *obj; 20104e070d2SEric Blake visit_type_uintN(v, &value, name, UINT32_MAX, "uint32_t", errp); 2024e27e819SMichael Roth *obj = value; 2034e27e819SMichael Roth } 2044e27e819SMichael Roth 20551e72bc1SEric Blake void visit_type_uint64(Visitor *v, const char *name, uint64_t *obj, 20604e070d2SEric Blake Error **errp) 2074e27e819SMichael Roth { 208adfb264cSEric Blake assert(obj); 209ebfd93b6SDaniel P. Berrange trace_visit_type_uint64(v, name, obj); 2100b2a0d6bSEric Blake v->type_uint64(v, name, obj, errp); 2114e27e819SMichael Roth } 2124e27e819SMichael Roth 21304e070d2SEric Blake static void visit_type_intN(Visitor *v, int64_t *obj, const char *name, 21404e070d2SEric Blake int64_t min, int64_t max, const char *type, 21504e070d2SEric Blake Error **errp) 2164e27e819SMichael Roth { 21704e070d2SEric Blake Error *err = NULL; 21804e070d2SEric Blake int64_t value = *obj; 219297a3646SMarkus Armbruster 2200b2a0d6bSEric Blake v->type_int64(v, name, &value, &err); 22104e070d2SEric Blake if (err) { 22204e070d2SEric Blake error_propagate(errp, err); 22304e070d2SEric Blake } else if (value < min || value > max) { 224c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 22504e070d2SEric Blake name ? name : "null", type); 22604e070d2SEric Blake } else { 2274e27e819SMichael Roth *obj = value; 2284e27e819SMichael Roth } 2294e27e819SMichael Roth } 2304e27e819SMichael Roth 23151e72bc1SEric Blake void visit_type_int8(Visitor *v, const char *name, int8_t *obj, Error **errp) 23204e070d2SEric Blake { 233ebfd93b6SDaniel P. Berrange int64_t value; 234ebfd93b6SDaniel P. Berrange 235ebfd93b6SDaniel P. Berrange trace_visit_type_int8(v, name, obj); 236ebfd93b6SDaniel P. Berrange value = *obj; 23704e070d2SEric Blake visit_type_intN(v, &value, name, INT8_MIN, INT8_MAX, "int8_t", errp); 23804e070d2SEric Blake *obj = value; 23904e070d2SEric Blake } 24004e070d2SEric Blake 24151e72bc1SEric Blake void visit_type_int16(Visitor *v, const char *name, int16_t *obj, 24251e72bc1SEric Blake Error **errp) 2434e27e819SMichael Roth { 244ebfd93b6SDaniel P. Berrange int64_t value; 245ebfd93b6SDaniel P. Berrange 246ebfd93b6SDaniel P. Berrange trace_visit_type_int16(v, name, obj); 247ebfd93b6SDaniel P. Berrange value = *obj; 24804e070d2SEric Blake visit_type_intN(v, &value, name, INT16_MIN, INT16_MAX, "int16_t", errp); 2494e27e819SMichael Roth *obj = value; 2504e27e819SMichael Roth } 2514e27e819SMichael Roth 25251e72bc1SEric Blake void visit_type_int32(Visitor *v, const char *name, int32_t *obj, 25351e72bc1SEric Blake Error **errp) 2544e27e819SMichael Roth { 255ebfd93b6SDaniel P. Berrange int64_t value; 256ebfd93b6SDaniel P. Berrange 257ebfd93b6SDaniel P. Berrange trace_visit_type_int32(v, name, obj); 258ebfd93b6SDaniel P. Berrange value = *obj; 25904e070d2SEric Blake visit_type_intN(v, &value, name, INT32_MIN, INT32_MAX, "int32_t", errp); 2604e27e819SMichael Roth *obj = value; 2614e27e819SMichael Roth } 2624e27e819SMichael Roth 26351e72bc1SEric Blake void visit_type_int64(Visitor *v, const char *name, int64_t *obj, 26451e72bc1SEric Blake Error **errp) 2654e27e819SMichael Roth { 266adfb264cSEric Blake assert(obj); 267ebfd93b6SDaniel P. Berrange trace_visit_type_int64(v, name, obj); 2680b2a0d6bSEric Blake v->type_int64(v, name, obj, errp); 2694e27e819SMichael Roth } 2704e27e819SMichael Roth 27151e72bc1SEric Blake void visit_type_size(Visitor *v, const char *name, uint64_t *obj, 27251e72bc1SEric Blake Error **errp) 273092705d4SLaszlo Ersek { 274adfb264cSEric Blake assert(obj); 275ebfd93b6SDaniel P. Berrange trace_visit_type_size(v, name, obj); 276b8877962SVasilis Liaskovitis if (v->type_size) { 2770b2a0d6bSEric Blake v->type_size(v, name, obj, errp); 278b8877962SVasilis Liaskovitis } else { 2790b2a0d6bSEric Blake v->type_uint64(v, name, obj, errp); 280b8877962SVasilis Liaskovitis } 281092705d4SLaszlo Ersek } 282092705d4SLaszlo Ersek 28351e72bc1SEric Blake void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) 2842345c77cSMichael Roth { 285adfb264cSEric Blake assert(obj); 286ebfd93b6SDaniel P. Berrange trace_visit_type_bool(v, name, obj); 2870b2a0d6bSEric Blake v->type_bool(v, name, obj, errp); 2882345c77cSMichael Roth } 2892345c77cSMichael Roth 29051e72bc1SEric Blake void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp) 2912345c77cSMichael Roth { 292e58d695eSEric Blake Error *err = NULL; 293e58d695eSEric Blake 294e58d695eSEric Blake assert(obj); 295adfb264cSEric Blake /* TODO: Fix callers to not pass NULL when they mean "", so that we 296adfb264cSEric Blake * can enable: 297a15fcc3cSEric Blake assert(!(v->type & VISITOR_OUTPUT) || *obj); 298adfb264cSEric Blake */ 299ebfd93b6SDaniel P. Berrange trace_visit_type_str(v, name, obj); 300e58d695eSEric Blake v->type_str(v, name, obj, &err); 301a15fcc3cSEric Blake if (v->type & VISITOR_INPUT) { 302e58d695eSEric Blake assert(!err != !*obj); 303e58d695eSEric Blake } 304e58d695eSEric Blake error_propagate(errp, err); 3052345c77cSMichael Roth } 3062345c77cSMichael Roth 30751e72bc1SEric Blake void visit_type_number(Visitor *v, const char *name, double *obj, 30851e72bc1SEric Blake Error **errp) 3092345c77cSMichael Roth { 310adfb264cSEric Blake assert(obj); 311ebfd93b6SDaniel P. Berrange trace_visit_type_number(v, name, obj); 3120b2a0d6bSEric Blake v->type_number(v, name, obj, errp); 3132345c77cSMichael Roth } 3140f71a1e0SPaolo Bonzini 31551e72bc1SEric Blake void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp) 31628770e05SMarkus Armbruster { 317e58d695eSEric Blake Error *err = NULL; 318e58d695eSEric Blake 319e58d695eSEric Blake assert(obj); 320adfb264cSEric Blake assert(v->type != VISITOR_OUTPUT || *obj); 321ebfd93b6SDaniel P. Berrange trace_visit_type_any(v, name, obj); 322e58d695eSEric Blake v->type_any(v, name, obj, &err); 323e58d695eSEric Blake if (v->type == VISITOR_INPUT) { 324e58d695eSEric Blake assert(!err != !*obj); 325e58d695eSEric Blake } 326e58d695eSEric Blake error_propagate(errp, err); 32728770e05SMarkus Armbruster } 32828770e05SMarkus Armbruster 329d2f95f4dSMarkus Armbruster void visit_type_null(Visitor *v, const char *name, QNull **obj, 330d2f95f4dSMarkus Armbruster Error **errp) 3313bc97fd5SEric Blake { 332d2f95f4dSMarkus Armbruster trace_visit_type_null(v, name, obj); 333d2f95f4dSMarkus Armbruster v->type_null(v, name, obj, errp); 3343bc97fd5SEric Blake } 3353bc97fd5SEric Blake 336983f52d4SEric Blake static void output_type_enum(Visitor *v, const char *name, int *obj, 337337283dfSEric Blake const char *const strings[], Error **errp) 3380f71a1e0SPaolo Bonzini { 3390f71a1e0SPaolo Bonzini int i = 0; 3400f71a1e0SPaolo Bonzini int value = *obj; 3410f71a1e0SPaolo Bonzini char *enum_str; 3420f71a1e0SPaolo Bonzini 3430f71a1e0SPaolo Bonzini while (strings[i++] != NULL); 3440f71a1e0SPaolo Bonzini if (value < 0 || value >= i - 1) { 345c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER, name ? name : "null"); 3460f71a1e0SPaolo Bonzini return; 3470f71a1e0SPaolo Bonzini } 3480f71a1e0SPaolo Bonzini 3490f71a1e0SPaolo Bonzini enum_str = (char *)strings[value]; 35051e72bc1SEric Blake visit_type_str(v, name, &enum_str, errp); 3510f71a1e0SPaolo Bonzini } 3520f71a1e0SPaolo Bonzini 353983f52d4SEric Blake static void input_type_enum(Visitor *v, const char *name, int *obj, 354337283dfSEric Blake const char *const strings[], Error **errp) 3550f71a1e0SPaolo Bonzini { 356297a3646SMarkus Armbruster Error *local_err = NULL; 357*113e47aeSMarkus Armbruster int64_t value; 3580f71a1e0SPaolo Bonzini char *enum_str; 3590f71a1e0SPaolo Bonzini 36051e72bc1SEric Blake visit_type_str(v, name, &enum_str, &local_err); 361297a3646SMarkus Armbruster if (local_err) { 362297a3646SMarkus Armbruster error_propagate(errp, local_err); 3630f71a1e0SPaolo Bonzini return; 3640f71a1e0SPaolo Bonzini } 3650f71a1e0SPaolo Bonzini 366*113e47aeSMarkus Armbruster value = qapi_enum_parse(strings, enum_str, -1, NULL); 367*113e47aeSMarkus Armbruster if (value < 0) { 368c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER, enum_str); 3690f71a1e0SPaolo Bonzini g_free(enum_str); 3700f71a1e0SPaolo Bonzini return; 3710f71a1e0SPaolo Bonzini } 3720f71a1e0SPaolo Bonzini 3730f71a1e0SPaolo Bonzini g_free(enum_str); 3740f71a1e0SPaolo Bonzini *obj = value; 3750f71a1e0SPaolo Bonzini } 376983f52d4SEric Blake 377983f52d4SEric Blake void visit_type_enum(Visitor *v, const char *name, int *obj, 378983f52d4SEric Blake const char *const strings[], Error **errp) 379983f52d4SEric Blake { 380adfb264cSEric Blake assert(obj && strings); 3816514532fSStefan Hajnoczi trace_visit_type_enum(v, name, obj); 382a15fcc3cSEric Blake switch (v->type) { 383a15fcc3cSEric Blake case VISITOR_INPUT: 384983f52d4SEric Blake input_type_enum(v, name, obj, strings, errp); 385a15fcc3cSEric Blake break; 386a15fcc3cSEric Blake case VISITOR_OUTPUT: 387983f52d4SEric Blake output_type_enum(v, name, obj, strings, errp); 388a15fcc3cSEric Blake break; 389a15fcc3cSEric Blake case VISITOR_CLONE: 390a15fcc3cSEric Blake /* nothing further to do, scalar value was already copied by 391a15fcc3cSEric Blake * g_memdup() during visit_start_*() */ 392a15fcc3cSEric Blake break; 393a15fcc3cSEric Blake case VISITOR_DEALLOC: 394a15fcc3cSEric Blake /* nothing to deallocate for a scalar */ 395a15fcc3cSEric Blake break; 396983f52d4SEric Blake } 397983f52d4SEric Blake } 398