aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2009-12-07 10:46:09 +0200
committerAvi Kivity <avi@redhat.com>2009-12-07 10:46:09 +0200
commit989e2cd2f9db2edcd347c380dddfeb5b64327b76 (patch)
treef803f84b6d6393b6869b36c07bbe3760e7676fe5
parentFix mismerge in cpu_post_load (diff)
parentmonitor: QError support (diff)
downloadqemu-kvm-989e2cd2f9db2edcd347c380dddfeb5b64327b76.tar.gz
qemu-kvm-989e2cd2f9db2edcd347c380dddfeb5b64327b76.tar.bz2
qemu-kvm-989e2cd2f9db2edcd347c380dddfeb5b64327b76.zip
Merge commit '8204a9180c5f456d30cbd29fddf734e97f7c74fa' into upstream-merge
* commit '8204a9180c5f456d30cbd29fddf734e97f7c74fa': (22 commits) monitor: QError support Introduce QError utests: Add qstring_from_substr() unit-test utests: Add qstring_append_chr() unit-test QString: Introduce qstring_from_substr() QString: Introduce qstring_append_int() QString: Introduce qstring_append_chr() QJSON: Introduce qobject_from_jsonv() fix I2C slave addressing Fix qdev property type definition for isa serial/parallel devices Fix qemu_malloc/qemu_free use in rtl8139.c Fix free use in xen_backend.c Fix qemu_free use in scsi-generic.c Fix qemu_free use in nseries.c Fix qemu_free use in bt-l2cap.c Fix qemu_free use in nand.c Fix qemu_free use in baum.c Fix qemu_free use in acpi.c pci: move apb specific stuff to apb_pci.c configure: use correct cflags in compiler checks ... Conflicts: monitor.c Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--Makefile6
-rw-r--r--check-qstring.c31
-rwxr-xr-xconfigure41
-rw-r--r--hw/acpi.c2
-rw-r--r--hw/apb_pci.c22
-rw-r--r--hw/baum.c8
-rw-r--r--hw/bt-l2cap.c2
-rw-r--r--hw/i2c.c6
-rw-r--r--hw/nand.c4
-rw-r--r--hw/nseries.c2
-rw-r--r--hw/parallel.c2
-rw-r--r--hw/pci.c26
-rw-r--r--hw/pci.h1
-rw-r--r--hw/rtl8139.c4
-rw-r--r--hw/scsi-generic.c4
-rw-r--r--hw/serial.c2
-rw-r--r--hw/vga-pci.c6
-rw-r--r--hw/xen_backend.c2
-rw-r--r--monitor.c43
-rw-r--r--qerror.c260
-rw-r--r--qerror.h42
-rw-r--r--qjson.c23
-rw-r--r--qjson.h2
-rw-r--r--qobject.h1
-rw-r--r--qstring.c48
-rw-r--r--qstring.h4
-rw-r--r--sysemu.h7
27 files changed, 520 insertions, 81 deletions
diff --git a/Makefile b/Makefile
index 6641f7363..4829ab7c1 100644
--- a/Makefile
+++ b/Makefile
@@ -162,7 +162,7 @@ obj-y += qemu-char.o aio.o savevm.o
obj-y += msmouse.o ps2.o
obj-y += qdev.o qdev-properties.o
obj-y += qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o json-lexer.o
-obj-y += json-streamer.o json-parser.o qjson.o
+obj-y += json-streamer.o json-parser.o qjson.o qerror.o
obj-y += qemu-config.o block-migration.o
obj-$(CONFIG_BRLAPI) += baum.o
@@ -237,14 +237,12 @@ libqemu_common.a: $(obj-y)
######################################################################
-qemu-img.o: config-host.h qemu-img-cmds.h
+qemu-img.o: qemu-img-cmds.h
qemu-img$(EXESUF): qemu-img.o qemu-tool.o $(block-obj-y)
qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o $(block-obj-y)
-qemu-io.o: config-host.h
-
qemu-io$(EXESUF): qemu-io.o qemu-tool.o cmd.o $(block-obj-y)
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
diff --git a/check-qstring.c b/check-qstring.c
index ea4dfd03c..c308a63ea 100644
--- a/check-qstring.c
+++ b/check-qstring.c
@@ -55,6 +55,35 @@ START_TEST(qstring_get_str_test)
}
END_TEST
+START_TEST(qstring_append_chr_test)
+{
+ int i;
+ QString *qstring;
+ const char *str = "qstring append char unit-test";
+
+ qstring = qstring_new();
+
+ for (i = 0; str[i]; i++)
+ qstring_append_chr(qstring, str[i]);
+
+ fail_unless(strcmp(str, qstring_get_str(qstring)) == 0);
+ QDECREF(qstring);
+}
+END_TEST
+
+START_TEST(qstring_from_substr_test)
+{
+ QString *qs;
+
+ qs = qstring_from_substr("virtualization", 3, 9);
+ fail_unless(qs != NULL);
+ fail_unless(strcmp(qstring_get_str(qs), "tualiza") == 0);
+
+ QDECREF(qs);
+}
+END_TEST
+
+
START_TEST(qobject_to_qstring_test)
{
QString *qstring;
@@ -78,6 +107,8 @@ static Suite *qstring_suite(void)
tcase_add_test(qstring_public_tcase, qstring_from_str_test);
tcase_add_test(qstring_public_tcase, qstring_destroy_test);
tcase_add_test(qstring_public_tcase, qstring_get_str_test);
+ tcase_add_test(qstring_public_tcase, qstring_append_chr_test);
+ tcase_add_test(qstring_public_tcase, qstring_from_substr_test);
tcase_add_test(qstring_public_tcase, qobject_to_qstring_test);
return s;
diff --git a/configure b/configure
index f8a68cb9b..d5f53f8b7 100755
--- a/configure
+++ b/configure
@@ -91,6 +91,26 @@ ar="${cross_prefix}${ar}"
objcopy="${cross_prefix}${objcopy}"
ld="${cross_prefix}${ld}"
+# default flags for all hosts
+QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS"
+CFLAGS="-g $CFLAGS"
+QEMU_CFLAGS="-Wall -Wundef -Wendif-labels -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
+QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
+QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
+QEMU_CFLAGS="-U_FORTIFY_SOURCE $QEMU_CFLAGS"
+QEMU_CFLAGS="-I. -I\$(SRC_PATH) $QEMU_CFLAGS"
+LDFLAGS="-g $LDFLAGS"
+
+gcc_flags="-Wold-style-declaration -Wold-style-definition"
+cat > $TMPC << EOF
+int main(void) { }
+EOF
+for flag in $gcc_flags; do
+ if compile_prog "$QEMU_CFLAGS" "$flag" ; then
+ QEMU_CFLAGS="$flag $QEMU_CFLAGS"
+ fi
+done
+
# check that the C compiler works.
cat > $TMPC <<EOF
int main(void) {}
@@ -1734,7 +1754,7 @@ int main(void)
return 0;
}
EOF
-if compile_prog "" "" ; then
+if compile_prog "$ARCH_CFLAGS" "" ; then
fallocate=yes
fi
@@ -1882,28 +1902,9 @@ fi
# End of CC checks
# After here, no more $cc or $ld runs
-# default flags for all hosts
-QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS"
-CFLAGS="-g $CFLAGS"
if test "$debug" = "no" ; then
CFLAGS="-O2 $CFLAGS"
fi
-QEMU_CFLAGS="-Wall -Wundef -Wendif-labels -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
-QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
-QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
-QEMU_CFLAGS="-U_FORTIFY_SOURCE $QEMU_CFLAGS"
-QEMU_CFLAGS="-I. -I\$(SRC_PATH) $QEMU_CFLAGS"
-LDFLAGS="-g $LDFLAGS"
-
-gcc_flags="-Wold-style-declaration -Wold-style-definition"
-cat > $TMPC << EOF
-int main(void) { }
-EOF
-for flag in $gcc_flags; do
- if compile_prog "$QEMU_CFLAGS" "$flag" ; then
- QEMU_CFLAGS="$flag $QEMU_CFLAGS"
- fi
-done
# Consult white-list to determine whether to enable werror
# by default. Only enable by default for git builds
diff --git a/hw/acpi.c b/hw/acpi.c
index ffe447ce3..ec049a2e8 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -989,7 +989,7 @@ int acpi_table_add(const char *t)
return 0;
out:
if (acpi_tables) {
- free(acpi_tables);
+ qemu_free(acpi_tables);
acpi_tables = NULL;
}
return -1;
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index f2ed136fd..fe8faa6d0 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -182,6 +182,25 @@ static void pci_apb_set_irq(void *opaque, int irq_num, int level)
qemu_set_irq(pic[irq_num], level);
}
+static void apb_pci_bridge_init(PCIBus *b)
+{
+ PCIDevice *dev = pci_bridge_get_device(b);
+
+ /*
+ * command register:
+ * According to PCI bridge spec, after reset
+ * bus master bit is off
+ * memory space enable bit is off
+ * According to manual (805-1251.pdf).
+ * the reset value should be zero unless the boot pin is tied high
+ * (which is true) and thus it should be PCI_COMMAND_MEMORY.
+ */
+ pci_set_word(dev->config + PCI_COMMAND,
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ dev->config[PCI_LATENCY_TIMER] = 0x10;
+ dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION;
+}
+
PCIBus *pci_apb_init(target_phys_addr_t special_base,
target_phys_addr_t mem_base,
qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
@@ -212,10 +231,13 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
pci_apb_map_irq,
"Advanced PCI Bus secondary bridge 1");
+ apb_pci_bridge_init(*bus2);
+
*bus3 = pci_bridge_init(d->host_state.bus, PCI_DEVFN(1, 1),
PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
pci_apb_map_irq,
"Advanced PCI Bus secondary bridge 2");
+ apb_pci_bridge_init(*bus3);
return d->host_state.bus;
}
diff --git a/hw/baum.c b/hw/baum.c
index fa356ec48..18633f484 100644
--- a/hw/baum.c
+++ b/hw/baum.c
@@ -559,7 +559,7 @@ static void baum_chr_read(void *opaque)
if (ret == -1 && (brlapi_errno != BRLAPI_ERROR_LIBCERR || errno != EINTR)) {
brlapi_perror("baum: brlapi_readKey");
brlapi__closeConnection(baum->brlapi);
- free(baum->brlapi);
+ qemu_free(baum->brlapi);
baum->brlapi = NULL;
}
}
@@ -622,8 +622,8 @@ fail:
qemu_free_timer(baum->cellCount_timer);
brlapi__closeConnection(handle);
fail_handle:
- free(handle);
- free(chr);
- free(baum);
+ qemu_free(handle);
+ qemu_free(chr);
+ qemu_free(baum);
return NULL;
}
diff --git a/hw/bt-l2cap.c b/hw/bt-l2cap.c
index 4697f529d..70d731e61 100644
--- a/hw/bt-l2cap.c
+++ b/hw/bt-l2cap.c
@@ -1218,7 +1218,7 @@ static void l2cap_teardown(struct l2cap_instance_s *l2cap, int send_disconnect)
for (cid = L2CAP_CID_ALLOC; cid < L2CAP_CID_MAX; cid ++)
if (l2cap->cid[cid]) {
l2cap->cid[cid]->params.close(l2cap->cid[cid]->params.opaque);
- free(l2cap->cid[cid]);
+ qemu_free(l2cap->cid[cid]);
}
if (l2cap->role)
diff --git a/hw/i2c.c b/hw/i2c.c
index 5c291ce0a..bee8e88c6 100644
--- a/hw/i2c.c
+++ b/hw/i2c.c
@@ -85,9 +85,11 @@ int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
i2c_slave *slave = NULL;
QLIST_FOREACH(qdev, &bus->qbus.children, sibling) {
- slave = I2C_SLAVE_FROM_QDEV(qdev);
- if (slave->address == address)
+ i2c_slave *candidate = I2C_SLAVE_FROM_QDEV(qdev);
+ if (candidate->address == address) {
+ slave = candidate;
break;
+ }
}
if (!slave)
diff --git a/hw/nand.c b/hw/nand.c
index 37fd5243f..838f8bc89 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -507,9 +507,9 @@ void nand_done(NANDFlashState *s)
}
if (!s->bdrv || s->mem_oob)
- free(s->storage);
+ qemu_free(s->storage);
- free(s);
+ qemu_free(s);
}
#else
diff --git a/hw/nseries.c b/hw/nseries.c
index 79f7387ff..0273eeea3 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -711,7 +711,7 @@ static void n800_dss_init(struct rfbi_chip_s *chip)
fb_blank = memset(qemu_malloc(800 * 480 * 2), 0xff, 800 * 480 * 2);
/* Display Memory Data Port */
chip->block(chip->opaque, 1, fb_blank, 800 * 480 * 2, 800);
- free(fb_blank);
+ qemu_free(fb_blank);
}
static void n8x0_dss_setup(struct n800_s *s)
diff --git a/hw/parallel.c b/hw/parallel.c
index 5ae8348da..12693d40d 100644
--- a/hw/parallel.c
+++ b/hw/parallel.c
@@ -587,7 +587,7 @@ static ISADeviceInfo parallel_isa_info = {
.qdev.size = sizeof(ISAParallelState),
.init = parallel_isa_initfn,
.qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("index", ISAParallelState, index, -1),
+ DEFINE_PROP_UINT32("index", ISAParallelState, index, -1),
DEFINE_PROP_HEX32("iobase", ISAParallelState, iobase, -1),
DEFINE_PROP_UINT32("irq", ISAParallelState, isairq, 7),
DEFINE_PROP_CHR("chardev", ISAParallelState, state.chr),
diff --git a/hw/pci.c b/hw/pci.c
index 5422725f4..245b1386b 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1333,29 +1333,10 @@ static int pci_bridge_initfn(PCIDevice *dev)
pci_config_set_vendor_id(s->dev.config, s->vid);
pci_config_set_device_id(s->dev.config, s->did);
- /* TODO: intial value
- * command register:
- * According to PCI bridge spec, after reset
- * bus master bit is off
- * memory space enable bit is off
- * According to manual (805-1251.pdf).(See abp_pbi.c for its links.)
- * the reset value should be zero unless the boot pin is tied high
- * (which is tru) and thus it should be PCI_COMMAND_MEMORY.
- *
- * For now, don't touch the value.
- * Later command register will be set to zero and apb_pci.c will
- * override the value.
- * Same for latency timer, and multi function bit of header type.
- */
- pci_set_word(dev->config + PCI_COMMAND,
- PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
-
pci_set_word(dev->config + PCI_STATUS,
PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
- dev->config[PCI_LATENCY_TIMER] = 0x10;
- dev->config[PCI_HEADER_TYPE] =
- PCI_HEADER_TYPE_MULTI_FUNCTION | PCI_HEADER_TYPE_BRIDGE;
+ dev->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_BRIDGE;
pci_set_word(dev->config + PCI_SEC_STATUS,
PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
return 0;
@@ -1385,6 +1366,11 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
return &s->bus;
}
+PCIDevice *pci_bridge_get_device(PCIBus *bus)
+{
+ return bus->parent_dev;
+}
+
static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
{
PCIDevice *pci_dev = (PCIDevice *)qdev;
diff --git a/hw/pci.h b/hw/pci.h
index 75f239bf8..4739e0147 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -354,6 +354,7 @@ int pci_parse_host_devaddr(const char *addr, int *busp,
void pci_info(Monitor *mon);
PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
pci_map_irq_fn map_irq, const char *name);
+PCIDevice *pci_bridge_get_device(PCIBus *bus);
static inline void
pci_set_byte(uint8_t *config, uint8_t val)
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index c166db074..be47f61c2 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -1985,7 +1985,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
if (!s->cplus_txbuffer)
{
s->cplus_txbuffer_len = CP_TX_BUFFER_SIZE;
- s->cplus_txbuffer = malloc(s->cplus_txbuffer_len);
+ s->cplus_txbuffer = qemu_malloc(s->cplus_txbuffer_len);
s->cplus_txbuffer_offset = 0;
DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer allocated space %d\n", s->cplus_txbuffer_len));
@@ -2300,7 +2300,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
}
else
{
- free(saved_buffer);
+ qemu_free(saved_buffer);
}
}
else
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 92ef7716b..cf56ea0f2 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -561,7 +561,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
if (len == 0) {
if (r->buf != NULL)
- free(r->buf);
+ qemu_free(r->buf);
r->buflen = 0;
r->buf = NULL;
ret = execute_command(s->dinfo->bdrv, r, SG_DXFER_NONE, scsi_command_complete);
@@ -574,7 +574,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
if (r->buflen != len) {
if (r->buf != NULL)
- free(r->buf);
+ qemu_free(r->buf);
r->buf = qemu_malloc(len);
r->buflen = len;
}
diff --git a/hw/serial.c b/hw/serial.c
index 006326056..e7538ac8c 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -900,7 +900,7 @@ static ISADeviceInfo serial_isa_info = {
.qdev.size = sizeof(ISASerialState),
.init = serial_isa_initfn,
.qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("index", ISASerialState, index, -1),
+ DEFINE_PROP_UINT32("index", ISASerialState, index, -1),
DEFINE_PROP_HEX32("iobase", ISASerialState, iobase, -1),
DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1),
DEFINE_PROP_CHR("chardev", ISASerialState, state.chr),
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index 5dae62508..d0a781822 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -109,6 +109,12 @@ static int pci_vga_initfn(PCIDevice *dev)
PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
}
+#ifdef CONFIG_BOCHS_VBE
+ /* XXX: use optimized standard vga accesses */
+ cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+ VGA_RAM_SIZE, s->vram_offset);
+#endif
+
/* ROM BIOS */
rom_add_vga(VGABIOS_FILENAME);
return 0;
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
index 658ea8d1d..a2e408fa0 100644
--- a/hw/xen_backend.c
+++ b/hw/xen_backend.c
@@ -594,7 +594,7 @@ static void xenstore_update(void *unused)
xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
cleanup:
- qemu_free(vec);
+ free(vec);
}
static void xen_be_evtchn_event(void *opaque)
diff --git a/monitor.c b/monitor.c
index e161f7d17..5288c9ddb 100644
--- a/monitor.c
+++ b/monitor.c
@@ -49,6 +49,7 @@
#include "qlist.h"
#include "qdict.h"
#include "qstring.h"
+#include "qerror.h"
#include "exec-all.h"
#include "qemu-kvm.h"
@@ -106,6 +107,7 @@ struct Monitor {
CPUState *mon_cpu;
BlockDriverCompletionFunc *password_completion_cb;
void *password_opaque;
+ QError *error;
QLIST_HEAD(,mon_fd_t) fds;
QLIST_ENTRY(Monitor) entry;
};
@@ -227,6 +229,11 @@ static inline int monitor_handler_ported(const mon_cmd_t *cmd)
return cmd->user_print != NULL;
}
+static inline int monitor_has_error(const Monitor *mon)
+{
+ return mon->error != NULL;
+}
+
static void monitor_print_qobject(Monitor *mon, const QObject *data)
{
switch (qobject_type(data)) {
@@ -3200,6 +3207,13 @@ fail:
return NULL;
}
+static void monitor_print_error(Monitor *mon)
+{
+ qerror_print(mon->error);
+ QDECREF(mon->error);
+ mon->error = NULL;
+}
+
static void monitor_handle_command(Monitor *mon, const char *cmdline)
{
QDict *qdict;
@@ -3225,7 +3239,10 @@ static void monitor_handle_command(Monitor *mon, const char *cmdline)
cmd->mhandler.cmd(mon, qdict);
}
- qemu_errors_to_previous();
+ if (monitor_has_error(mon))
+ monitor_print_error(mon);
+
+ qemu_errors_to_previous();
out:
QDECREF(qdict);
@@ -3676,3 +3693,27 @@ void qemu_error(const char *fmt, ...)
break;
}
}
+
+void qemu_error_internal(const char *file, int linenr, const char *func,
+ const char *fmt, ...)
+{
+ va_list va;
+ QError *qerror;
+
+ assert(qemu_error_sink != NULL);
+
+ va_start(va, fmt);
+ qerror = qerror_from_info(file, linenr, func, fmt, &va);
+ va_end(va);
+
+ switch (qemu_error_sink->dest) {
+ case ERR_SINK_FILE:
+ qerror_print(qerror);
+ QDECREF(qerror);
+ break;
+ case ERR_SINK_MONITOR:
+ assert(qemu_error_sink->mon->error == NULL);
+ qemu_error_sink->mon->error = qerror;
+ break;
+ }
+}
diff --git a/qerror.c b/qerror.c
new file mode 100644
index 000000000..10b0939f6
--- /dev/null
+++ b/qerror.c
@@ -0,0 +1,260 @@
+/*
+ * QError: QEMU Error data-type.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+#include "qjson.h"
+#include "qerror.h"
+#include "qstring.h"
+#include "sysemu.h"
+#include "qemu-common.h"
+
+static void qerror_destroy_obj(QObject *obj);
+
+static const QType qerror_type = {
+ .code = QTYPE_QERROR,
+ .destroy = qerror_destroy_obj,
+};
+
+/**
+ * The 'desc' parameter is a printf-like string, the format of the format
+ * string is:
+ *
+ * %(KEY)
+ *
+ * Where KEY is a QDict key, which has to be passed to qerror_from_info().
+ *
+ * Example:
+ *
+ * "foo error on device: %(device) slot: %(slot_nr)"
+ *
+ * A single percent sign can be printed if followed by a second one,
+ * for example:
+ *
+ * "running out of foo: %(foo)%%"
+ */
+const QErrorStringTable qerror_table[] = {
+ {}
+};
+
+/**
+ * qerror_new(): Create a new QError
+ *
+ * Return strong reference.
+ */
+QError *qerror_new(void)
+{
+ QError *qerr;
+
+ qerr = qemu_mallocz(sizeof(*qerr));
+ QOBJECT_INIT(qerr, &qerror_type);
+
+ return qerr;
+}
+
+static void qerror_abort(const QError *qerr, const char *fmt, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "qerror: bad call in function '%s':\n", qerr->func);
+ fprintf(stderr, "qerror: -> ");
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ fprintf(stderr, "\nqerror: call at %s:%d\n", qerr->file, qerr->linenr);
+ abort();
+}
+
+static void qerror_set_data(QError *qerr, const char *fmt, va_list *va)
+{
+ QObject *obj;
+
+ obj = qobject_from_jsonv(fmt, va);
+ if (!obj) {
+ qerror_abort(qerr, "invalid format '%s'", fmt);
+ }
+ if (qobject_type(obj) != QTYPE_QDICT) {
+ qerror_abort(qerr, "error format is not a QDict '%s'", fmt);
+ }
+
+ qerr->error = qobject_to_qdict(obj);
+
+ obj = qdict_get(qerr->error, "class");
+ if (!obj) {
+ qerror_abort(qerr, "missing 'class' key in '%s'", fmt);
+ }
+ if (qobject_type(obj) != QTYPE_QSTRING) {
+ qerror_abort(qerr, "'class' key value should be a QString");
+ }
+
+ obj = qdict_get(qerr->error, "data");
+ if (!obj) {
+ qerror_abort(qerr, "missing 'data' key in '%s'", fmt);
+ }
+ if (qobject_type(obj) != QTYPE_QDICT) {
+ qerror_abort(qerr, "'data' key value should be a QDICT");
+ }
+}
+
+static void qerror_set_desc(QError *qerr, const char *fmt)
+{
+ int i;
+
+ // FIXME: inefficient loop
+
+ for (i = 0; qerror_table[i].error_fmt; i++) {
+ if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
+ qerr->entry = &qerror_table[i];
+ return;
+ }
+ }
+
+ qerror_abort(qerr, "error format '%s' not found", fmt);
+}
+
+/**
+ * qerror_from_info(): Create a new QError from error information
+ *
+ * The information consists of:
+ *
+ * - file the file name of where the error occurred
+ * - linenr the line number of where the error occurred
+ * - func the function name of where the error occurred
+ * - fmt JSON printf-like dictionary, there must exist keys 'class' and
+ * 'data'
+ * - va va_list of all arguments specified by fmt
+ *
+ * Return strong reference.
+ */
+QError *qerror_from_info(const char *file, int linenr, const char *func,
+ const char *fmt, va_list *va)
+{
+ QError *qerr;
+
+ qerr = qerror_new();
+ qerr->linenr = linenr;
+ qerr->file = file;
+ qerr->func = func;
+
+ if (!fmt) {
+ qerror_abort(qerr, "QDict not specified");
+ }
+
+ qerror_set_data(qerr, fmt, va);
+ qerror_set_desc(qerr, fmt);
+
+ return qerr;
+}
+
+static void parse_error(const QError *qerror, int c)
+{
+ qerror_abort(qerror, "expected '%c' in '%s'", c, qerror->entry->desc);
+}
+
+static const char *append_field(QString *outstr, const QError *qerror,
+ const char *start)
+{
+ QObject *obj;
+ QDict *qdict;
+ QString *key_qs;
+ const char *end, *key;
+
+ if (*start != '%')
+ parse_error(qerror, '%');
+ start++;
+ if (*start != '(')
+ parse_error(qerror, '(');
+ start++;
+
+ end = strchr(start, ')');
+ if (!end)
+ parse_error(qerror, ')');
+
+ key_qs = qstring_from_substr(start, 0, end - start - 1);
+ key = qstring_get_str(key_qs);
+
+ qdict = qobject_to_qdict(qdict_get(qerror->error, "data"));
+ obj = qdict_get(qdict, key);
+ if (!obj) {
+ qerror_abort(qerror, "key '%s' not found in QDict", key);
+ }
+
+ switch (qobject_type(obj)) {
+ case QTYPE_QSTRING:
+ qstring_append(outstr, qdict_get_str(qdict, key));
+ break;
+ case QTYPE_QINT:
+ qstring_append_int(outstr, qdict_get_int(qdict, key));
+ break;
+ default:
+ qerror_abort(qerror, "invalid type '%c'", qobject_type(obj));
+ }
+
+ QDECREF(key_qs);
+ return ++end;
+}
+
+/**
+ * qerror_print(): Print QError data
+ *
+ * This function will print the member 'desc' of the specified QError object,
+ * it uses qemu_error() for this, so that the output is routed to the right
+ * place (ie. stderr or Monitor's device).
+ */
+void qerror_print(const QError *qerror)
+{
+ const char *p;
+ QString *qstring;
+
+ assert(qerror->entry != NULL);
+
+ qstring = qstring_new();
+
+ for (p = qerror->entry->desc; *p != '\0';) {
+ if (*p != '%') {
+ qstring_append_chr(qstring, *p++);
+ } else if (*(p + 1) == '%') {
+ qstring_append_chr(qstring, '%');
+ p += 2;
+ } else {
+ p = append_field(qstring, qerror, p);
+ }
+ }
+
+ qemu_error("%s\n", qstring_get_str(qstring));
+ QDECREF(qstring);
+}
+
+/**
+ * qobject_to_qerror(): Convert a QObject into a QError
+ */
+QError *qobject_to_qerror(const QObject *obj)
+{
+ if (qobject_type(obj) != QTYPE_QERROR) {
+ return NULL;
+ }
+
+ return container_of(obj, QError, base);
+}
+
+/**
+ * qerror_destroy_obj(): Free all memory allocated by a QError
+ */
+static void qerror_destroy_obj(QObject *obj)
+{
+ QError *qerr;
+
+ assert(obj != NULL);
+ qerr = qobject_to_qerror(obj);
+
+ QDECREF(qerr->error);
+ qemu_free(qerr);
+}
diff --git a/qerror.h b/qerror.h
new file mode 100644
index 000000000..01703ee2b
--- /dev/null
+++ b/qerror.h
@@ -0,0 +1,42 @@
+/*
+ * QError header file.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+#ifndef QERROR_H
+#define QERROR_H
+
+#include "qdict.h"
+#include <stdarg.h>
+
+typedef struct QErrorStringTable {
+ const char *desc;
+ const char *error_fmt;
+} QErrorStringTable;
+
+typedef struct QError {
+ QObject_HEAD;
+ QDict *error;
+ int linenr;
+ const char *file;
+ const char *func;
+ const QErrorStringTable *entry;
+} QError;
+
+QError *qerror_new(void);
+QError *qerror_from_info(const char *file, int linenr, const char *func,
+ const char *fmt, va_list *va);
+void qerror_print(const QError *qerror);
+QError *qobject_to_qerror(const QObject *obj);
+
+/*
+ * QError class list
+ */
+
+#endif /* QERROR_H */
diff --git a/qjson.c b/qjson.c
index 7270909af..60c904d3f 100644
--- a/qjson.c
+++ b/qjson.c
@@ -34,10 +34,12 @@ static void parse_json(JSONMessageParser *parser, QList *tokens)
s->result = json_parser_parse(tokens, s->ap);
}
-QObject *qobject_from_json(const char *string)
+QObject *qobject_from_jsonv(const char *string, va_list *ap)
{
JSONParsingState state = {};
+ state.ap = ap;
+
json_message_parser_init(&state.parser, parse_json);
json_message_parser_feed(&state.parser, string, strlen(string));
json_message_parser_flush(&state.parser);
@@ -46,22 +48,21 @@ QObject *qobject_from_json(const char *string)
return state.result;
}
+QObject *qobject_from_json(const char *string)
+{
+ return qobject_from_jsonv(string, NULL);
+}
+
QObject *qobject_from_jsonf(const char *string, ...)
{
- JSONParsingState state = {};
+ QObject *obj;
va_list ap;
va_start(ap, string);
- state.ap = &ap;
-
- json_message_parser_init(&state.parser, parse_json);
- json_message_parser_feed(&state.parser, string, strlen(string));
- json_message_parser_flush(&state.parser);
- json_message_parser_destroy(&state.parser);
-
+ obj = qobject_from_jsonv(string, &ap);
va_end(ap);
- return state.result;
+ return obj;
}
typedef struct ToJsonIterState
@@ -223,6 +224,8 @@ static void to_json(const QObject *obj, QString *str)
}
break;
}
+ case QTYPE_QERROR:
+ /* XXX: should QError be emitted? */
case QTYPE_NONE:
break;
}
diff --git a/qjson.h b/qjson.h
index 7fce742c4..7afec2eec 100644
--- a/qjson.h
+++ b/qjson.h
@@ -14,12 +14,14 @@
#ifndef QJSON_H
#define QJSON_H
+#include <stdarg.h>
#include "qobject.h"
#include "qstring.h"
QObject *qobject_from_json(const char *string);
QObject *qobject_from_jsonf(const char *string, ...)
__attribute__((__format__ (__printf__, 1, 2)));
+QObject *qobject_from_jsonv(const char *string, va_list *ap);
QString *qobject_to_json(const QObject *obj);
diff --git a/qobject.h b/qobject.h
index 2270ec1d7..07de211ef 100644
--- a/qobject.h
+++ b/qobject.h
@@ -43,6 +43,7 @@ typedef enum {
QTYPE_QLIST,
QTYPE_QFLOAT,
QTYPE_QBOOL,
+ QTYPE_QERROR,
} qtype_code;
struct QObject;
diff --git a/qstring.c b/qstring.c
index 441a9e6ef..740a1067d 100644
--- a/qstring.c
+++ b/qstring.c
@@ -31,21 +31,21 @@ QString *qstring_new(void)
}
/**
- * qstring_from_str(): Create a new QString from a regular C string
+ * qstring_from_substr(): Create a new QString from a C string substring
*
- * Return strong reference.
+ * Return string reference
*/
-QString *qstring_from_str(const char *str)
+QString *qstring_from_substr(const char *str, int start, int end)
{
QString *qstring;
qstring = qemu_malloc(sizeof(*qstring));
- qstring->length = strlen(str);
+ qstring->length = end - start + 1;
qstring->capacity = qstring->length;
qstring->string = qemu_malloc(qstring->capacity + 1);
- memcpy(qstring->string, str, qstring->length);
+ memcpy(qstring->string, str + start, qstring->length);
qstring->string[qstring->length] = 0;
QOBJECT_INIT(qstring, &qstring_type);
@@ -53,24 +53,56 @@ QString *qstring_from_str(const char *str)
return qstring;
}
-/* qstring_append(): Append a C string to a QString
+/**
+ * qstring_from_str(): Create a new QString from a regular C string
+ *
+ * Return strong reference.
*/
-void qstring_append(QString *qstring, const char *str)
+QString *qstring_from_str(const char *str)
{
- size_t len = strlen(str);
+ return qstring_from_substr(str, 0, strlen(str) - 1);
+}
+static void capacity_increase(QString *qstring, size_t len)
+{
if (qstring->capacity < (qstring->length + len)) {
qstring->capacity += len;
qstring->capacity *= 2; /* use exponential growth */
qstring->string = qemu_realloc(qstring->string, qstring->capacity + 1);
}
+}
+
+/* qstring_append(): Append a C string to a QString
+ */
+void qstring_append(QString *qstring, const char *str)
+{
+ size_t len = strlen(str);
+ capacity_increase(qstring, len);
memcpy(qstring->string + qstring->length, str, len);
qstring->length += len;
qstring->string[qstring->length] = 0;
}
+void qstring_append_int(QString *qstring, int64_t value)
+{
+ char num[32];
+
+ snprintf(num, sizeof(num), "%" PRId64, value);
+ qstring_append(qstring, num);
+}
+
+/**
+ * qstring_append_chr(): Append a C char to a QString
+ */
+void qstring_append_chr(QString *qstring, int c)
+{
+ capacity_increase(qstring, 1);
+ qstring->string[qstring->length++] = c;
+ qstring->string[qstring->length] = 0;
+}
+
/**
* qobject_to_qstring(): Convert a QObject to a QString
*/
diff --git a/qstring.h b/qstring.h
index 65905d457..6aaa7d5c8 100644
--- a/qstring.h
+++ b/qstring.h
@@ -1,6 +1,7 @@
#ifndef QSTRING_H
#define QSTRING_H
+#include <stdint.h>
#include "qobject.h"
typedef struct QString {
@@ -12,8 +13,11 @@ typedef struct QString {
QString *qstring_new(void);
QString *qstring_from_str(const char *str);
+QString *qstring_from_substr(const char *str, int start, int end);
const char *qstring_get_str(const QString *qstring);
+void qstring_append_int(QString *qstring, int64_t value);
void qstring_append(QString *qstring, const char *str);
+void qstring_append_chr(QString *qstring, int c);
QString *qobject_to_qstring(const QObject *obj);
#endif /* QSTRING_H */
diff --git a/sysemu.h b/sysemu.h
index 4f662260d..532117cd5 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -7,6 +7,7 @@
#include "qemu-queue.h"
#include "qemu-timer.h"
#include "qdict.h"
+#include "qerror.h"
#ifdef _WIN32
#include <windows.h>
@@ -72,6 +73,12 @@ void qemu_errors_to_file(FILE *fp);
void qemu_errors_to_mon(Monitor *mon);
void qemu_errors_to_previous(void);
void qemu_error(const char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
+void qemu_error_internal(const char *file, int linenr, const char *func,
+ const char *fmt, ...)
+ __attribute__ ((format(printf, 4, 5)));
+
+#define qemu_error_new(fmt, ...) \
+ qemu_error_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__)
#ifdef _WIN32
/* Polling handling */