diff options
author | Avi Kivity <avi@redhat.com> | 2009-12-07 10:46:09 +0200 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-12-07 10:46:09 +0200 |
commit | 989e2cd2f9db2edcd347c380dddfeb5b64327b76 (patch) | |
tree | f803f84b6d6393b6869b36c07bbe3760e7676fe5 | |
parent | Fix mismerge in cpu_post_load (diff) | |
parent | monitor: QError support (diff) | |
download | qemu-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-- | Makefile | 6 | ||||
-rw-r--r-- | check-qstring.c | 31 | ||||
-rwxr-xr-x | configure | 41 | ||||
-rw-r--r-- | hw/acpi.c | 2 | ||||
-rw-r--r-- | hw/apb_pci.c | 22 | ||||
-rw-r--r-- | hw/baum.c | 8 | ||||
-rw-r--r-- | hw/bt-l2cap.c | 2 | ||||
-rw-r--r-- | hw/i2c.c | 6 | ||||
-rw-r--r-- | hw/nand.c | 4 | ||||
-rw-r--r-- | hw/nseries.c | 2 | ||||
-rw-r--r-- | hw/parallel.c | 2 | ||||
-rw-r--r-- | hw/pci.c | 26 | ||||
-rw-r--r-- | hw/pci.h | 1 | ||||
-rw-r--r-- | hw/rtl8139.c | 4 | ||||
-rw-r--r-- | hw/scsi-generic.c | 4 | ||||
-rw-r--r-- | hw/serial.c | 2 | ||||
-rw-r--r-- | hw/vga-pci.c | 6 | ||||
-rw-r--r-- | hw/xen_backend.c | 2 | ||||
-rw-r--r-- | monitor.c | 43 | ||||
-rw-r--r-- | qerror.c | 260 | ||||
-rw-r--r-- | qerror.h | 42 | ||||
-rw-r--r-- | qjson.c | 23 | ||||
-rw-r--r-- | qjson.h | 2 | ||||
-rw-r--r-- | qobject.h | 1 | ||||
-rw-r--r-- | qstring.c | 48 | ||||
-rw-r--r-- | qstring.h | 4 | ||||
-rw-r--r-- | sysemu.h | 7 |
27 files changed, 520 insertions, 81 deletions
@@ -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; @@ -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 @@ -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; } @@ -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) @@ -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) @@ -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), @@ -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; @@ -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) @@ -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 */ @@ -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 = ≈ - - 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; } @@ -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); @@ -43,6 +43,7 @@ typedef enum { QTYPE_QLIST, QTYPE_QFLOAT, QTYPE_QBOOL, + QTYPE_QERROR, } qtype_code; struct QObject; @@ -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 */ @@ -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 */ @@ -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 */ |