Fix device introspection regressions
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWF8SNAAoJEDhwtADrkYZTSaUQAJdIB2CiO6COT0T36ZNU/yi8 wkFdmBt6Ejks1v8OBhoz+NEwMomj55uyeG+ck4BfvNAZJqpYPSKeZdviu/U/UDHw BJmUBk5beMcTay66DhQ+0bASfn+3nldM6vXExZEsxi43dLAxyksOd6WZ7L3LieDI V7mXJ02y/E8tcwuQqiAutU4N/6JlF2PIJpPgDZaPEJIFbW/LBBUoFneYmK4Mv8sZ SMjgEulE4JZ/WDeZJYxwWHmNFzrUgTwikq2ydPxawBK6zkoC3JdlkjHdOKWhkQfV tMbnRjHmlN9uO3zoF/aIZgFVy4pbnb+f4bnWPqLG55U5z8WXmXao8LlThlzkRdjw xrqW8yvwMk1owRLlhjxVR4iyxTXPnp/S76QlEVJbokGFW/MhWhctQoIH0C2lfcgG t0A642Xy6NXy+vZqJLJxzigBGn8zT98BXfKptWLHr9aun2U5Vpou0ylf5nsiojL+ 5HR+bB4J/ZVbxIW1OIJqR/cnSKzZqSLCqBB3jnCP60dIgaD7/JeUSz91AFZDPRcb PmGsSCa1rjPC66R/QmxYwZ3YGuz0imKWDALqkudsNJnklBVMLxfC+Gp5Sg4D475K qzwgRAcXv9wsSPumwoxaQBZxHd4Xuj91e7QmMO+z1un6oOb07fh2Wt5Ib/UoqYM7 +Ry+yGwO5sRkwZhxdaxM =QXLe -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/armbru/tags/pull-monitor-2015-10-09' into staging Fix device introspection regressions # gpg: Signature made Fri 09 Oct 2015 14:43:41 BST using RSA key ID EB918653 # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" * remotes/armbru/tags/pull-monitor-2015-10-09: Revert "qdev: Use qdev_get_device_class() for -device <type>,help" qdev: Protect device-list-properties against broken devices qmp: Fix device-list-properties not to crash for abstract device device-introspect-test: New, covering device introspection libqtest: New hmp() & friends libqtest: Clean up unused QTestState member sigact_old tests: Fix how qom-test is run macio: move DBDMA_init from instance_init to realize hw: do not pass NULL to memory_region_init from instance_init memory: allow destroying a non-empty MemoryRegion virtio-input: Fix device introspection on non-Linux hosts update-linux-headers: Rename SW_MAX to SW_MAX_ Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
7684922390
@ -103,6 +103,12 @@ static void aw_a10_class_init(ObjectClass *oc, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = aw_a10_realize;
|
||||
|
||||
/*
|
||||
* Reason: creates an ARM CPU, thus use after free(), see
|
||||
* arm_cpu_class_init()
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo aw_a10_type_info = {
|
||||
|
@ -97,6 +97,12 @@ static void digic_class_init(ObjectClass *oc, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = digic_realize;
|
||||
|
||||
/*
|
||||
* Reason: creates an ARM CPU, thus use after free(), see
|
||||
* arm_cpu_class_init()
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo digic_type_info = {
|
||||
|
@ -284,6 +284,12 @@ static void fsl_imx25_class_init(ObjectClass *oc, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = fsl_imx25_realize;
|
||||
|
||||
/*
|
||||
* Reason: creates an ARM CPU, thus use after free(), see
|
||||
* arm_cpu_class_init()
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo fsl_imx25_type_info = {
|
||||
|
@ -258,6 +258,12 @@ static void fsl_imx31_class_init(ObjectClass *oc, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = fsl_imx31_realize;
|
||||
|
||||
/*
|
||||
* Reason: creates an ARM CPU, thus use after free(), see
|
||||
* arm_cpu_class_init()
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo fsl_imx31_type_info = {
|
||||
|
@ -1958,7 +1958,7 @@ static void pxa2xx_fir_instance_init(Object *obj)
|
||||
PXA2xxFIrState *s = PXA2XX_FIR(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &pxa2xx_fir_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &pxa2xx_fir_ops, s,
|
||||
"pxa2xx-fir", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
@ -271,6 +271,12 @@ static void xlnx_zynqmp_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
dc->props = xlnx_zynqmp_props;
|
||||
dc->realize = xlnx_zynqmp_realize;
|
||||
|
||||
/*
|
||||
* Reason: creates an ARM CPU, thus use after free(), see
|
||||
* arm_cpu_class_init()
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo xlnx_zynqmp_type_info = {
|
||||
|
@ -280,12 +280,12 @@ static void cg3_initfn(Object *obj)
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
CG3State *s = CG3(obj);
|
||||
|
||||
memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE,
|
||||
memory_region_init_ram(&s->rom, obj, "cg3.prom", FCODE_MAX_ROM_SIZE,
|
||||
&error_fatal);
|
||||
memory_region_set_readonly(&s->rom, true);
|
||||
sysbus_init_mmio(sbd, &s->rom);
|
||||
|
||||
memory_region_init_io(&s->reg, NULL, &cg3_reg_ops, s, "cg3.reg",
|
||||
memory_region_init_io(&s->reg, obj, &cg3_reg_ops, s, "cg3.reg",
|
||||
CG3_REG_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->reg);
|
||||
}
|
||||
|
@ -944,7 +944,7 @@ static void tcx_initfn(Object *obj)
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
TCXState *s = TCX(obj);
|
||||
|
||||
memory_region_init_ram(&s->rom, NULL, "tcx.prom", FCODE_MAX_ROM_SIZE,
|
||||
memory_region_init_ram(&s->rom, OBJECT(s), "tcx.prom", FCODE_MAX_ROM_SIZE,
|
||||
&error_fatal);
|
||||
memory_region_set_readonly(&s->rom, true);
|
||||
sysbus_init_mmio(sbd, &s->rom);
|
||||
|
@ -8,9 +8,9 @@ common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o
|
||||
common-obj-$(CONFIG_TSC2005) += tsc2005.o
|
||||
common-obj-$(CONFIG_VMMOUSE) += vmmouse.o
|
||||
|
||||
ifeq ($(CONFIG_LINUX),y)
|
||||
common-obj-$(CONFIG_VIRTIO) += virtio-input.o
|
||||
common-obj-$(CONFIG_VIRTIO) += virtio-input-hid.o
|
||||
ifeq ($(CONFIG_LINUX),y)
|
||||
common-obj-$(CONFIG_VIRTIO) += virtio-input-host.o
|
||||
endif
|
||||
|
||||
|
@ -79,7 +79,7 @@ static void intdbg_control_init(Object *obj)
|
||||
SysBusDevice *sd = SYS_BUS_DEVICE(obj);
|
||||
IntegratorDebugState *s = INTEGRATOR_DEBUG(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &intdbg_control_ops,
|
||||
memory_region_init_io(&s->iomem, obj, &intdbg_control_ops,
|
||||
NULL, "dbg-leds", 0x1000000);
|
||||
sysbus_init_mmio(sd, &s->iomem);
|
||||
}
|
||||
|
@ -713,7 +713,7 @@ static void cuda_initfn(Object *obj)
|
||||
CUDAState *s = CUDA(obj);
|
||||
int i;
|
||||
|
||||
memory_region_init_io(&s->mem, NULL, &cuda_ops, s, "cuda", 0x2000);
|
||||
memory_region_init_io(&s->mem, obj, &cuda_ops, s, "cuda", 0x2000);
|
||||
sysbus_init_mmio(d, &s->mem);
|
||||
sysbus_init_irq(d, &s->irq);
|
||||
|
||||
|
@ -105,10 +105,10 @@ static void macio_escc_legacy_setup(MacIOState *macio_state)
|
||||
0xF0, 0xE0,
|
||||
};
|
||||
|
||||
memory_region_init(escc_legacy, NULL, "escc-legacy", 256);
|
||||
memory_region_init(escc_legacy, OBJECT(macio_state), "escc-legacy", 256);
|
||||
for (i = 0; i < ARRAY_SIZE(maps); i += 2) {
|
||||
MemoryRegion *port = g_new(MemoryRegion, 1);
|
||||
memory_region_init_alias(port, NULL, "escc-legacy-port",
|
||||
memory_region_init_alias(port, OBJECT(macio_state), "escc-legacy-port",
|
||||
macio_state->escc_mem, maps[i+1], 0x2);
|
||||
memory_region_add_subregion(escc_legacy, maps[i], port);
|
||||
}
|
||||
@ -131,6 +131,10 @@ static void macio_common_realize(PCIDevice *d, Error **errp)
|
||||
MacIOState *s = MACIO(d);
|
||||
SysBusDevice *sysbus_dev;
|
||||
Error *err = NULL;
|
||||
MemoryRegion *dbdma_mem;
|
||||
|
||||
s->dbdma = DBDMA_init(&dbdma_mem);
|
||||
memory_region_add_subregion(&s->bar, 0x08000, dbdma_mem);
|
||||
|
||||
object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err);
|
||||
if (err) {
|
||||
@ -328,16 +332,12 @@ static void macio_newworld_init(Object *obj)
|
||||
static void macio_instance_init(Object *obj)
|
||||
{
|
||||
MacIOState *s = MACIO(obj);
|
||||
MemoryRegion *dbdma_mem;
|
||||
|
||||
memory_region_init(&s->bar, NULL, "macio", 0x80000);
|
||||
memory_region_init(&s->bar, obj, "macio", 0x80000);
|
||||
|
||||
object_initialize(&s->cuda, sizeof(s->cuda), TYPE_CUDA);
|
||||
qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default());
|
||||
object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL);
|
||||
|
||||
s->dbdma = DBDMA_init(&dbdma_mem);
|
||||
memory_region_add_subregion(&s->bar, 0x08000, dbdma_mem);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_macio_oldworld = {
|
||||
|
@ -500,6 +500,8 @@ static void pci_vpb_class_init(ObjectClass *klass, void *data)
|
||||
dc->reset = pci_vpb_reset;
|
||||
dc->vmsd = &pci_vpb_vmstate;
|
||||
dc->props = pci_vpb_properties;
|
||||
/* Reason: object_unref() hangs */
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo pci_vpb_info = {
|
||||
@ -521,10 +523,19 @@ static void pci_realview_init(Object *obj)
|
||||
s->mem_win_size[2] = 0x08000000;
|
||||
}
|
||||
|
||||
static void pci_realview_class_init(ObjectClass *class, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(class);
|
||||
|
||||
/* Reason: object_unref() hangs */
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo pci_realview_info = {
|
||||
.name = "realview_pci",
|
||||
.parent = TYPE_VERSATILE_PCI,
|
||||
.instance_init = pci_realview_init,
|
||||
.class_init = pci_realview_class_init,
|
||||
};
|
||||
|
||||
static void versatile_pci_register_types(void)
|
||||
|
@ -163,7 +163,7 @@ static void pxa2xx_pcmcia_initfn(Object *obj)
|
||||
sysbus_init_mmio(sbd, &s->container_mem);
|
||||
|
||||
/* Socket I/O Memory Space */
|
||||
memory_region_init_io(&s->iomem, NULL, &pxa2xx_pcmcia_io_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &pxa2xx_pcmcia_io_ops, s,
|
||||
"pxa2xx-pcmcia-io", 0x04000000);
|
||||
memory_region_add_subregion(&s->container_mem, 0x00000000,
|
||||
&s->iomem);
|
||||
@ -171,13 +171,13 @@ static void pxa2xx_pcmcia_initfn(Object *obj)
|
||||
/* Then next 64 MB is reserved */
|
||||
|
||||
/* Socket Attribute Memory Space */
|
||||
memory_region_init_io(&s->attr_iomem, NULL, &pxa2xx_pcmcia_attr_ops, s,
|
||||
memory_region_init_io(&s->attr_iomem, obj, &pxa2xx_pcmcia_attr_ops, s,
|
||||
"pxa2xx-pcmcia-attribute", 0x04000000);
|
||||
memory_region_add_subregion(&s->container_mem, 0x08000000,
|
||||
&s->attr_iomem);
|
||||
|
||||
/* Socket Common Memory Space */
|
||||
memory_region_init_io(&s->common_iomem, NULL, &pxa2xx_pcmcia_common_ops, s,
|
||||
memory_region_init_io(&s->common_iomem, obj, &pxa2xx_pcmcia_common_ops, s,
|
||||
"pxa2xx-pcmcia-common", 0x04000000);
|
||||
memory_region_add_subregion(&s->container_mem, 0x0c000000,
|
||||
&s->common_iomem);
|
||||
|
@ -2134,14 +2134,6 @@ static void virtio_tablet_initfn(Object *obj)
|
||||
TYPE_VIRTIO_TABLET);
|
||||
}
|
||||
|
||||
static void virtio_host_initfn(Object *obj)
|
||||
{
|
||||
VirtIOInputHostPCI *dev = VIRTIO_INPUT_HOST_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_INPUT_HOST);
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_input_pci_info = {
|
||||
.name = TYPE_VIRTIO_INPUT_PCI,
|
||||
.parent = TYPE_VIRTIO_PCI,
|
||||
@ -2180,12 +2172,22 @@ static const TypeInfo virtio_tablet_pci_info = {
|
||||
.instance_init = virtio_tablet_initfn,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_LINUX
|
||||
static void virtio_host_initfn(Object *obj)
|
||||
{
|
||||
VirtIOInputHostPCI *dev = VIRTIO_INPUT_HOST_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_INPUT_HOST);
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_host_pci_info = {
|
||||
.name = TYPE_VIRTIO_INPUT_HOST_PCI,
|
||||
.parent = TYPE_VIRTIO_INPUT_PCI,
|
||||
.instance_size = sizeof(VirtIOInputHostPCI),
|
||||
.instance_init = virtio_host_initfn,
|
||||
};
|
||||
#endif
|
||||
|
||||
/* virtio-pci-bus */
|
||||
|
||||
@ -2233,7 +2235,9 @@ static void virtio_pci_register_types(void)
|
||||
type_register_static(&virtio_keyboard_pci_info);
|
||||
type_register_static(&virtio_mouse_pci_info);
|
||||
type_register_static(&virtio_tablet_pci_info);
|
||||
#ifdef CONFIG_LINUX
|
||||
type_register_static(&virtio_host_pci_info);
|
||||
#endif
|
||||
type_register_static(&virtio_pci_bus_info);
|
||||
type_register_static(&virtio_pci_info);
|
||||
#ifdef CONFIG_VIRTFS
|
||||
|
@ -267,6 +267,8 @@ struct VirtIOInputHIDPCI {
|
||||
VirtIOInputHID vdev;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_LINUX
|
||||
|
||||
#define TYPE_VIRTIO_INPUT_HOST_PCI "virtio-input-host-pci"
|
||||
#define VIRTIO_INPUT_HOST_PCI(obj) \
|
||||
OBJECT_CHECK(VirtIOInputHostPCI, (obj), TYPE_VIRTIO_INPUT_HOST_PCI)
|
||||
@ -276,6 +278,8 @@ struct VirtIOInputHostPCI {
|
||||
VirtIOInputHost vdev;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* virtio-gpu-pci: This extends VirtioPCIProxy.
|
||||
*/
|
||||
|
@ -114,6 +114,19 @@ typedef struct DeviceClass {
|
||||
* TODO remove once we're there
|
||||
*/
|
||||
bool cannot_instantiate_with_device_add_yet;
|
||||
/*
|
||||
* Does this device model survive object_unref(object_new(TNAME))?
|
||||
* All device models should, and this flag shouldn't exist. Some
|
||||
* devices crash in object_new(), some crash or hang in
|
||||
* object_unref(). Makes introspecting properties with
|
||||
* qmp_device_list_properties() dangerous. Bad, because it's used
|
||||
* by -device FOO,help. This flag serves to protect that code.
|
||||
* It should never be set without a comment explaining why it is
|
||||
* set.
|
||||
* TODO remove once we're there
|
||||
*/
|
||||
bool cannot_destroy_with_object_finalize_yet;
|
||||
|
||||
bool hotpluggable;
|
||||
|
||||
/* callbacks */
|
||||
|
@ -887,8 +887,8 @@ struct input_keymap_entry {
|
||||
#define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */
|
||||
#define SW_LINEIN_INSERT 0x0d /* set = inserted */
|
||||
#define SW_MUTE_DEVICE 0x0e /* set = device disabled */
|
||||
#define SW_MAX 0x0f
|
||||
#define SW_CNT (SW_MAX+1)
|
||||
#define SW_MAX_ 0x0f
|
||||
#define SW_CNT (SW_MAX_+1)
|
||||
|
||||
/*
|
||||
* Misc events
|
||||
|
17
memory.c
17
memory.c
@ -1304,7 +1304,22 @@ static void memory_region_finalize(Object *obj)
|
||||
{
|
||||
MemoryRegion *mr = MEMORY_REGION(obj);
|
||||
|
||||
assert(QTAILQ_EMPTY(&mr->subregions));
|
||||
assert(!mr->container);
|
||||
|
||||
/* We know the region is not visible in any address space (it
|
||||
* does not have a container and cannot be a root either because
|
||||
* it has no references, so we can blindly clear mr->enabled.
|
||||
* memory_region_set_enabled instead could trigger a transaction
|
||||
* and cause an infinite loop.
|
||||
*/
|
||||
mr->enabled = false;
|
||||
memory_region_transaction_begin();
|
||||
while (!QTAILQ_EMPTY(&mr->subregions)) {
|
||||
MemoryRegion *subregion = QTAILQ_FIRST(&mr->subregions);
|
||||
memory_region_del_subregion(mr, subregion);
|
||||
}
|
||||
memory_region_transaction_commit();
|
||||
|
||||
mr->destructor(mr);
|
||||
memory_region_clear_coalescing(mr);
|
||||
g_free((char *)mr->name);
|
||||
|
@ -237,9 +237,12 @@ int qdev_device_help(QemuOpts *opts)
|
||||
return 0;
|
||||
}
|
||||
|
||||
qdev_get_device_class(&driver, &local_err);
|
||||
if (local_err) {
|
||||
goto error;
|
||||
if (!object_class_by_name(driver)) {
|
||||
const char *typename = find_typename_by_alias(driver);
|
||||
|
||||
if (typename) {
|
||||
driver = typename;
|
||||
}
|
||||
}
|
||||
|
||||
prop_list = qmp_device_list_properties(driver, &local_err);
|
||||
|
11
qmp.c
11
qmp.c
@ -515,6 +515,17 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (object_class_is_abstract(klass)) {
|
||||
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "name",
|
||||
"non-abstract device type");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (DEVICE_CLASS(klass)->cannot_destroy_with_object_finalize_yet) {
|
||||
error_setg(errp, "Can't list properties of device '%s'", typename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
obj = object_new(typename);
|
||||
|
||||
QTAILQ_FOREACH(prop, &obj->properties, node) {
|
||||
|
@ -53,6 +53,7 @@ cp_portable() {
|
||||
-e 's/__attribute__((packed))/QEMU_PACKED/' \
|
||||
-e 's/__inline__/inline/' \
|
||||
-e '/sys\/ioctl.h/d' \
|
||||
-e 's/SW_MAX/SW_MAX_/' \
|
||||
"$f" > "$to/$header";
|
||||
}
|
||||
|
||||
|
@ -298,6 +298,13 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data)
|
||||
dc->vmsd = &vmstate_alpha_cpu;
|
||||
#endif
|
||||
cc->gdb_num_core_regs = 67;
|
||||
|
||||
/*
|
||||
* Reason: alpha_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo alpha_cpu_type_info = {
|
||||
|
@ -1427,6 +1427,17 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->debug_excp_handler = arm_debug_excp_handler;
|
||||
|
||||
cc->disas_set_info = arm_disas_set_info;
|
||||
|
||||
/*
|
||||
* Reason: arm_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*
|
||||
* Once this is fixed, the devices that create ARM CPUs should be
|
||||
* updated not to set cannot_destroy_with_object_finalize_yet,
|
||||
* unless they still screw up something else.
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static void cpu_register(const ARMCPUInfo *info)
|
||||
|
@ -309,6 +309,13 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->gdb_stop_before_watchpoint = true;
|
||||
|
||||
cc->disas_set_info = cris_disas_set_info;
|
||||
|
||||
/*
|
||||
* Reason: cris_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo cris_cpu_type_info = {
|
||||
|
@ -1453,6 +1453,8 @@ static void host_x86_cpu_class_init(ObjectClass *oc, void *data)
|
||||
*/
|
||||
|
||||
dc->props = host_x86_cpu_properties;
|
||||
/* Reason: host_x86_cpu_initfn() dies when !kvm_enabled() */
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static void host_x86_cpu_initfn(Object *obj)
|
||||
@ -3190,6 +3192,12 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
|
||||
#endif
|
||||
cc->cpu_exec_enter = x86_cpu_exec_enter;
|
||||
cc->cpu_exec_exit = x86_cpu_exec_exit;
|
||||
|
||||
/*
|
||||
* Reason: x86_cpu_initfn() calls cpu_exec_init(), which saves the
|
||||
* object in cpus -> dangling pointer after final object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo x86_cpu_type_info = {
|
||||
|
@ -275,6 +275,13 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->gdb_num_core_regs = 32 + 7;
|
||||
cc->gdb_stop_before_watchpoint = true;
|
||||
cc->debug_excp_handler = lm32_debug_excp_handler;
|
||||
|
||||
/*
|
||||
* Reason: lm32_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static void lm32_register_cpu_type(const LM32CPUInfo *info)
|
||||
|
@ -212,6 +212,13 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data)
|
||||
dc->vmsd = &vmstate_m68k_cpu;
|
||||
cc->gdb_num_core_regs = 18;
|
||||
cc->gdb_core_xml_file = "cf-core.xml";
|
||||
|
||||
/*
|
||||
* Reason: m68k_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static void register_cpu_type(const M68kCPUInfo *info)
|
||||
|
@ -264,6 +264,12 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->gdb_num_core_regs = 32 + 5;
|
||||
|
||||
cc->disas_set_info = mb_disas_set_info;
|
||||
|
||||
/*
|
||||
* Reason: mb_cpu_initfn() calls cpu_exec_init(), which saves the
|
||||
* object in cpus -> dangling pointer after final object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo mb_cpu_type_info = {
|
||||
|
@ -153,6 +153,13 @@ static void mips_cpu_class_init(ObjectClass *c, void *data)
|
||||
|
||||
cc->gdb_num_core_regs = 73;
|
||||
cc->gdb_stop_before_watchpoint = true;
|
||||
|
||||
/*
|
||||
* Reason: mips_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo mips_cpu_type_info = {
|
||||
|
@ -114,6 +114,13 @@ static void moxie_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->get_phys_page_debug = moxie_cpu_get_phys_page_debug;
|
||||
cc->vmsd = &vmstate_moxie_cpu;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Reason: moxie_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static void moxielite_initfn(Object *obj)
|
||||
|
@ -177,6 +177,13 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data)
|
||||
dc->vmsd = &vmstate_openrisc_cpu;
|
||||
#endif
|
||||
cc->gdb_num_core_regs = 32 + 3;
|
||||
|
||||
/*
|
||||
* Reason: openrisc_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static void cpu_register(const OpenRISCCPUInfo *info)
|
||||
|
@ -2192,6 +2192,7 @@ static void kvmppc_host_cpu_initfn(Object *obj)
|
||||
|
||||
static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
|
||||
uint32_t vmx = kvmppc_get_vmx();
|
||||
uint32_t dfp = kvmppc_get_dfp();
|
||||
@ -2218,6 +2219,9 @@ static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data)
|
||||
if (icache_size != -1) {
|
||||
pcc->l1_icache_size = icache_size;
|
||||
}
|
||||
|
||||
/* Reason: kvmppc_host_cpu_initfn() dies when !kvm_enabled() */
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
bool kvmppc_has_cap_epr(void)
|
||||
|
@ -353,6 +353,13 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
|
||||
#endif
|
||||
cc->gdb_num_core_regs = S390_NUM_CORE_REGS;
|
||||
cc->gdb_core_xml_file = "s390x-core64.xml";
|
||||
|
||||
/*
|
||||
* Reason: s390_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo s390_cpu_type_info = {
|
||||
|
@ -290,6 +290,13 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data)
|
||||
#endif
|
||||
dc->vmsd = &vmstate_sh_cpu;
|
||||
cc->gdb_num_core_regs = 59;
|
||||
|
||||
/*
|
||||
* Reason: superh_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo superh_cpu_type_info = {
|
||||
|
@ -854,6 +854,13 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data)
|
||||
#else
|
||||
cc->gdb_num_core_regs = 72;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Reason: sparc_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo sparc_cpu_type_info = {
|
||||
|
@ -159,6 +159,13 @@ static void tilegx_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->set_pc = tilegx_cpu_set_pc;
|
||||
cc->handle_mmu_fault = tilegx_cpu_handle_mmu_fault;
|
||||
cc->gdb_num_core_regs = 0;
|
||||
|
||||
/*
|
||||
* Reason: tilegx_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo tilegx_cpu_type_info = {
|
||||
|
@ -170,6 +170,12 @@ static void tricore_cpu_class_init(ObjectClass *c, void *data)
|
||||
cc->set_pc = tricore_cpu_set_pc;
|
||||
cc->synchronize_from_tb = tricore_cpu_synchronize_from_tb;
|
||||
|
||||
/*
|
||||
* Reason: tricore_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static void cpu_register(const TriCoreCPUInfo *info)
|
||||
|
@ -155,6 +155,13 @@ static void uc32_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->get_phys_page_debug = uc32_cpu_get_phys_page_debug;
|
||||
#endif
|
||||
dc->vmsd = &vmstate_uc32_cpu;
|
||||
|
||||
/*
|
||||
* Reason: uc32_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static void uc32_register_cpu_type(const UniCore32CPUInfo *info)
|
||||
|
@ -155,6 +155,13 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
|
||||
#endif
|
||||
cc->debug_excp_handler = xtensa_breakpoint_handler;
|
||||
dc->vmsd = &vmstate_xtensa_cpu;
|
||||
|
||||
/*
|
||||
* Reason: xtensa_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo xtensa_cpu_type_info = {
|
||||
|
@ -86,6 +86,9 @@ check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
|
||||
# All QTests for now are POSIX-only, but the dependencies are
|
||||
# really in libqtest, not in the testcases themselves.
|
||||
|
||||
check-qtest-generic-y = tests/device-introspect-test$(EXESUF)
|
||||
gcov-files-generic-y = qdev-monitor.c qmp.c
|
||||
|
||||
gcov-files-ipack-y += hw/ipack/ipack.c
|
||||
check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF)
|
||||
gcov-files-ipack-y += hw/char/ipoctal232.c
|
||||
@ -218,10 +221,7 @@ gcov-files-ppc64-y += ppc64-softmmu/hw/ppc/spapr_pci.c
|
||||
check-qtest-microblazeel-y = $(check-qtest-microblaze-y)
|
||||
check-qtest-xtensaeb-y = $(check-qtest-xtensa-y)
|
||||
|
||||
# qom-test works for all sysemu architectures:
|
||||
$(foreach target,$(SYSEMU_TARGET_LIST), \
|
||||
$(if $(findstring tests/qom-test$(EXESUF), $(check-qtest-$(target)-y)),, \
|
||||
$(eval check-qtest-$(target)-y += tests/qom-test$(EXESUF))))
|
||||
check-qtest-generic-y += tests/qom-test$(EXESUF)
|
||||
|
||||
check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
|
||||
comments.json empty.json enum-empty.json enum-missing-data.json \
|
||||
@ -384,6 +384,7 @@ libqos-imx-obj-y = $(libqos-obj-y) tests/libqos/i2c-imx.o
|
||||
libqos-usb-obj-y = $(libqos-pc-obj-y) tests/libqos/usb.o
|
||||
libqos-virtio-obj-y = $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o tests/libqos/malloc-generic.o
|
||||
|
||||
tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o
|
||||
tests/rtc-test$(EXESUF): tests/rtc-test.o
|
||||
tests/m48t59-test$(EXESUF): tests/m48t59-test.o
|
||||
tests/endianness-test$(EXESUF): tests/endianness-test.o
|
||||
@ -448,8 +449,11 @@ CFLAGS += $(TEST_CFLAGS)
|
||||
|
||||
TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))
|
||||
ifeq ($(CONFIG_POSIX),y)
|
||||
QTEST_TARGETS=$(foreach TARGET,$(TARGETS), $(if $(check-qtest-$(TARGET)-y), $(TARGET),))
|
||||
QTEST_TARGETS = $(TARGETS)
|
||||
check-qtest-y=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y))
|
||||
check-qtest-y += $(check-qtest-generic-y)
|
||||
else
|
||||
QTEST_TARGETS =
|
||||
endif
|
||||
|
||||
qtest-obj-y = tests/libqtest.o $(test-util-obj-y)
|
||||
@ -487,8 +491,8 @@ $(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: $(check-qtest-y)
|
||||
$(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \
|
||||
QTEST_QEMU_IMG=qemu-img$(EXESUF) \
|
||||
MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$((RANDOM % 255 + 1))} \
|
||||
gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y),"GTESTER $@")
|
||||
$(if $(CONFIG_GCOV),@for f in $(gcov-files-$*-y); do \
|
||||
gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y) $(check-qtest-generic-y),"GTESTER $@")
|
||||
$(if $(CONFIG_GCOV),@for f in $(gcov-files-$*-y) $(gcov-files-generic-y); do \
|
||||
echo Gcov report for $$f:;\
|
||||
$(GCOV) $(GCOV_OPTIONS) $$f -o `dirname $$f`; \
|
||||
done,)
|
||||
@ -499,7 +503,7 @@ $(patsubst %, check-%, $(check-unit-y)): check-%: %
|
||||
$(call quiet-command, \
|
||||
MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$((RANDOM % 255 + 1))} \
|
||||
gtester $(GTESTER_OPTIONS) -m=$(SPEED) $*,"GTESTER $*")
|
||||
$(if $(CONFIG_GCOV),@for f in $(gcov-files-$(subst tests/,,$*)-y); do \
|
||||
$(if $(CONFIG_GCOV),@for f in $(gcov-files-$(subst tests/,,$*)-y) $(gcov-files-generic-y); do \
|
||||
echo Gcov report for $$f:;\
|
||||
$(GCOV) $(GCOV_OPTIONS) $$f -o `dirname $$f`; \
|
||||
done,)
|
||||
|
124
tests/device-introspect-test.c
Normal file
124
tests/device-introspect-test.c
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Device introspection test cases
|
||||
*
|
||||
* Copyright (c) 2015 Red Hat Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Markus Armbruster <armbru@redhat.com>,
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Covers QMP device-list-properties and HMP device_add help. We
|
||||
* currently don't check that their output makes sense, only that QEMU
|
||||
* survives. Useful since we've had an astounding number of crash
|
||||
* bugs around here.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdarg.h>
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "libqtest.h"
|
||||
|
||||
const char common_args[] = "-nodefaults -machine none";
|
||||
|
||||
static QList *device_type_list(bool abstract)
|
||||
{
|
||||
QDict *resp;
|
||||
QList *ret;
|
||||
|
||||
resp = qmp("{'execute': 'qom-list-types',"
|
||||
" 'arguments': {'implements': 'device', 'abstract': %i}}",
|
||||
abstract);
|
||||
g_assert(qdict_haskey(resp, "return"));
|
||||
ret = qdict_get_qlist(resp, "return");
|
||||
QINCREF(ret);
|
||||
QDECREF(resp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void test_one_device(const char *type)
|
||||
{
|
||||
QDict *resp;
|
||||
char *help, *qom_tree;
|
||||
|
||||
resp = qmp("{'execute': 'device-list-properties',"
|
||||
" 'arguments': {'typename': %s}}",
|
||||
type);
|
||||
QDECREF(resp);
|
||||
|
||||
help = hmp("device_add \"%s,help\"", type);
|
||||
g_free(help);
|
||||
|
||||
/*
|
||||
* Some devices leave dangling pointers in QOM behind.
|
||||
* "info qom-tree" has a good chance at crashing then
|
||||
*/
|
||||
qom_tree = hmp("info qom-tree");
|
||||
g_free(qom_tree);
|
||||
}
|
||||
|
||||
static void test_device_intro_list(void)
|
||||
{
|
||||
QList *types;
|
||||
char *help;
|
||||
|
||||
qtest_start(common_args);
|
||||
|
||||
types = device_type_list(true);
|
||||
QDECREF(types);
|
||||
|
||||
help = hmp("device_add help");
|
||||
g_free(help);
|
||||
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
static void test_device_intro_none(void)
|
||||
{
|
||||
qtest_start(common_args);
|
||||
test_one_device("nonexistent");
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
static void test_device_intro_abstract(void)
|
||||
{
|
||||
qtest_start(common_args);
|
||||
test_one_device("device");
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
static void test_device_intro_concrete(void)
|
||||
{
|
||||
QList *types;
|
||||
QListEntry *entry;
|
||||
const char *type;
|
||||
|
||||
qtest_start(common_args);
|
||||
types = device_type_list(false);
|
||||
|
||||
QLIST_FOREACH_ENTRY(types, entry) {
|
||||
type = qdict_get_try_str(qobject_to_qdict(qlist_entry_obj(entry)),
|
||||
"name");
|
||||
g_assert(type);
|
||||
test_one_device(type);
|
||||
}
|
||||
|
||||
QDECREF(types);
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
qtest_add_func("device/introspect/list", test_device_intro_list);
|
||||
qtest_add_func("device/introspect/none", test_device_intro_none);
|
||||
qtest_add_func("device/introspect/abstract", test_device_intro_abstract);
|
||||
qtest_add_func("device/introspect/concrete", test_device_intro_concrete);
|
||||
|
||||
return g_test_run();
|
||||
}
|
@ -16,28 +16,18 @@
|
||||
|
||||
static void drive_add(void)
|
||||
{
|
||||
QDict *response;
|
||||
char *resp = hmp("drive_add 0 if=none,id=drive0");
|
||||
|
||||
response = qmp("{'execute': 'human-monitor-command',"
|
||||
" 'arguments': {"
|
||||
" 'command-line': 'drive_add 0 if=none,id=drive0'"
|
||||
"}}");
|
||||
g_assert(response);
|
||||
g_assert_cmpstr(qdict_get_try_str(response, "return"), ==, "OK\r\n");
|
||||
QDECREF(response);
|
||||
g_assert_cmpstr(resp, ==, "OK\r\n");
|
||||
g_free(resp);
|
||||
}
|
||||
|
||||
static void drive_del(void)
|
||||
{
|
||||
QDict *response;
|
||||
char *resp = hmp("drive_del drive0");
|
||||
|
||||
response = qmp("{'execute': 'human-monitor-command',"
|
||||
" 'arguments': {"
|
||||
" 'command-line': 'drive_del drive0'"
|
||||
"}}");
|
||||
g_assert(response);
|
||||
g_assert_cmpstr(qdict_get_try_str(response, "return"), ==, "");
|
||||
QDECREF(response);
|
||||
g_assert_cmpstr(resp, ==, "");
|
||||
g_free(resp);
|
||||
}
|
||||
|
||||
static void device_del(void)
|
||||
|
@ -510,9 +510,7 @@ static void test_flush(void)
|
||||
tmp_path);
|
||||
|
||||
/* Delay the completion of the flush request until we explicitly do it */
|
||||
qmp_discard_response("{'execute':'human-monitor-command', 'arguments': {"
|
||||
" 'command-line':"
|
||||
" 'qemu-io ide0-hd0 \"break flush_to_os A\"'} }");
|
||||
g_free(hmp("qemu-io ide0-hd0 \"break flush_to_os A\""));
|
||||
|
||||
/* FLUSH CACHE command on device 0*/
|
||||
outb(IDE_BASE + reg_device, 0);
|
||||
@ -524,9 +522,7 @@ static void test_flush(void)
|
||||
assert_bit_clear(data, DF | ERR | DRQ);
|
||||
|
||||
/* Complete the command */
|
||||
qmp_discard_response("{'execute':'human-monitor-command', 'arguments': {"
|
||||
" 'command-line':"
|
||||
" 'qemu-io ide0-hd0 \"resume A\"'} }");
|
||||
g_free(hmp("qemu-io ide0-hd0 \"resume A\""));
|
||||
|
||||
/* Check registers */
|
||||
data = inb(IDE_BASE + reg_device);
|
||||
|
@ -46,7 +46,6 @@ struct QTestState
|
||||
bool irq_level[MAX_IRQ];
|
||||
GString *rx;
|
||||
pid_t qemu_pid; /* our child QEMU process */
|
||||
struct sigaction sigact_old; /* restored on exit */
|
||||
};
|
||||
|
||||
static GList *qtest_instances;
|
||||
@ -484,6 +483,33 @@ void qtest_qmp_eventwait(QTestState *s, const char *event)
|
||||
}
|
||||
}
|
||||
|
||||
char *qtest_hmpv(QTestState *s, const char *fmt, va_list ap)
|
||||
{
|
||||
char *cmd;
|
||||
QDict *resp;
|
||||
char *ret;
|
||||
|
||||
cmd = g_strdup_vprintf(fmt, ap);
|
||||
resp = qtest_qmp(s, "{'execute': 'human-monitor-command',"
|
||||
" 'arguments': {'command-line': %s}}",
|
||||
cmd);
|
||||
ret = g_strdup(qdict_get_try_str(resp, "return"));
|
||||
g_assert(ret);
|
||||
QDECREF(resp);
|
||||
g_free(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *qtest_hmp(QTestState *s, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *ret;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = qtest_hmpv(s, fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *qtest_get_arch(void)
|
||||
{
|
||||
@ -775,6 +801,16 @@ void qmp_discard_response(const char *fmt, ...)
|
||||
qtest_qmpv_discard_response(global_qtest, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
char *hmp(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *ret;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = qtest_hmpv(global_qtest, fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool qtest_big_endian(void)
|
||||
{
|
||||
|
@ -119,6 +119,29 @@ QDict *qtest_qmp_receive(QTestState *s);
|
||||
*/
|
||||
void qtest_qmp_eventwait(QTestState *s, const char *event);
|
||||
|
||||
/**
|
||||
* qtest_hmpv:
|
||||
* @s: #QTestState instance to operate on.
|
||||
* @fmt...: HMP command to send to QEMU
|
||||
*
|
||||
* Send HMP command to QEMU via QMP's human-monitor-command.
|
||||
*
|
||||
* Returns: the command's output. The caller should g_free() it.
|
||||
*/
|
||||
char *qtest_hmp(QTestState *s, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* qtest_hmpv:
|
||||
* @s: #QTestState instance to operate on.
|
||||
* @fmt: HMP command to send to QEMU
|
||||
* @ap: HMP command arguments
|
||||
*
|
||||
* Send HMP command to QEMU via QMP's human-monitor-command.
|
||||
*
|
||||
* Returns: the command's output. The caller should g_free() it.
|
||||
*/
|
||||
char *qtest_hmpv(QTestState *s, const char *fmt, va_list ap);
|
||||
|
||||
/**
|
||||
* qtest_get_irq:
|
||||
* @s: #QTestState instance to operate on.
|
||||
@ -498,6 +521,16 @@ static inline void qmp_eventwait(const char *event)
|
||||
return qtest_qmp_eventwait(global_qtest, event);
|
||||
}
|
||||
|
||||
/**
|
||||
* hmp:
|
||||
* @fmt...: HMP command to send to QEMU
|
||||
*
|
||||
* Send HMP command to QEMU via QMP's human-monitor-command.
|
||||
*
|
||||
* Returns: the command's output. The caller should g_free() it.
|
||||
*/
|
||||
char *hmp(const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* get_irq:
|
||||
* @num: Interrupt to observe.
|
||||
|
Loading…
Reference in New Issue
Block a user