diff options
| -rw-r--r-- | MAINTAINERS | 1 | ||||
| -rw-r--r-- | Makefile | 26 | ||||
| -rw-r--r-- | Makefile.target | 11 | ||||
| -rw-r--r-- | backends/hostmem-file.c | 6 | ||||
| -rw-r--r-- | backends/hostmem.c | 8 | ||||
| -rw-r--r-- | docs/devel/tracing.txt | 4 | ||||
| -rw-r--r-- | hw/core/machine.c | 3 | ||||
| -rw-r--r-- | hw/display/qxl.c | 14 | ||||
| -rw-r--r-- | hw/display/trace-events | 2 | ||||
| -rw-r--r-- | hw/gpio/trace-events | 2 | ||||
| -rw-r--r-- | hw/i386/pc.c | 9 | ||||
| -rw-r--r-- | hw/usb/combined-packet.c | 4 | ||||
| -rw-r--r-- | hw/usb/dev-hid.c | 26 | ||||
| -rw-r--r-- | hw/usb/dev-mtp.c | 168 | ||||
| -rw-r--r-- | hw/usb/hcd-ehci-pci.c | 4 | ||||
| -rw-r--r-- | hw/usb/hcd-ehci-sysbus.c | 4 | ||||
| -rw-r--r-- | hw/usb/hcd-ehci.c | 5 | ||||
| -rw-r--r-- | hw/usb/hcd-ehci.h | 4 | ||||
| -rw-r--r-- | hw/usb/hcd-xhci.c | 22 | ||||
| -rw-r--r-- | hw/usb/hcd-xhci.h | 1 | ||||
| -rw-r--r-- | hw/vfio/pci.c | 2 | ||||
| -rw-r--r-- | hw/vfio/trace-events | 2 | ||||
| -rw-r--r-- | numa.c | 1 | ||||
| -rwxr-xr-x | scripts/qemu-trace-stap | 175 | ||||
| -rw-r--r-- | scripts/qemu-trace-stap.texi | 140 | ||||
| -rw-r--r-- | scripts/tracetool/__init__.py | 6 | ||||
| -rw-r--r-- | scripts/tracetool/format/log_stap.py | 127 | ||||
| -rw-r--r-- | target/i386/cpu.c | 10 | ||||
| -rw-r--r-- | trace-events | 4 | ||||
| -rw-r--r-- | vl.c | 7 |
30 files changed, 683 insertions, 115 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index b334b53979..234e5c413b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2011,6 +2011,7 @@ F: trace-events F: qemu-option-trace.texi F: scripts/tracetool.py F: scripts/tracetool/ +F: scripts/qemu-trace-stap* F: docs/devel/tracing.txt T: git https://github.com/stefanha/qemu.git tracing diff --git a/Makefile b/Makefile index de898eab62..1278a3eb52 100644 --- a/Makefile +++ b/Makefile @@ -145,7 +145,7 @@ tracetool-y += $(shell find $(SRC_PATH)/scripts/tracetool -name "*.py") %/trace.h: %/trace.h-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ -%/trace.h-timestamp: $(SRC_PATH)/%/trace-events $(tracetool-y) +%/trace.h-timestamp: $(SRC_PATH)/%/trace-events $(tracetool-y) $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ --group=$(call trace-group-name,$@) \ --format=h \ @@ -154,7 +154,7 @@ tracetool-y += $(shell find $(SRC_PATH)/scripts/tracetool -name "*.py") %/trace.c: %/trace.c-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ -%/trace.c-timestamp: $(SRC_PATH)/%/trace-events $(tracetool-y) +%/trace.c-timestamp: $(SRC_PATH)/%/trace-events $(tracetool-y) $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ --group=$(call trace-group-name,$@) \ --format=c \ @@ -163,7 +163,7 @@ tracetool-y += $(shell find $(SRC_PATH)/scripts/tracetool -name "*.py") %/trace-ust.h: %/trace-ust.h-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ -%/trace-ust.h-timestamp: $(SRC_PATH)/%/trace-events $(tracetool-y) +%/trace-ust.h-timestamp: $(SRC_PATH)/%/trace-events $(tracetool-y) $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ --group=$(call trace-group-name,$@) \ --format=ust-events-h \ @@ -187,7 +187,7 @@ tracetool-y += $(shell find $(SRC_PATH)/scripts/tracetool -name "*.py") trace-root.h: trace-root.h-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ -trace-root.h-timestamp: $(SRC_PATH)/trace-events $(tracetool-y) +trace-root.h-timestamp: $(SRC_PATH)/trace-events $(tracetool-y) $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ --group=root \ --format=h \ @@ -196,7 +196,7 @@ trace-root.h-timestamp: $(SRC_PATH)/trace-events $(tracetool-y) trace-root.c: trace-root.c-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ -trace-root.c-timestamp: $(SRC_PATH)/trace-events $(tracetool-y) +trace-root.c-timestamp: $(SRC_PATH)/trace-events $(tracetool-y) $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ --group=root \ --format=c \ @@ -205,7 +205,7 @@ trace-root.c-timestamp: $(SRC_PATH)/trace-events $(tracetool-y) trace-ust-root.h: trace-ust-root.h-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ -trace-ust-root.h-timestamp: $(SRC_PATH)/trace-events $(tracetool-y) +trace-ust-root.h-timestamp: $(SRC_PATH)/trace-events $(tracetool-y) $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ --group=root \ --format=ust-events-h \ @@ -214,7 +214,7 @@ trace-ust-root.h-timestamp: $(SRC_PATH)/trace-events $(tracetool-y) trace-ust-all.h: trace-ust-all.h-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ -trace-ust-all.h-timestamp: $(trace-events-files) $(tracetool-y) +trace-ust-all.h-timestamp: $(trace-events-files) $(tracetool-y) $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ --group=all \ --format=ust-events-h \ @@ -223,7 +223,7 @@ trace-ust-all.h-timestamp: $(trace-events-files) $(tracetool-y) trace-ust-all.c: trace-ust-all.c-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ -trace-ust-all.c-timestamp: $(trace-events-files) $(tracetool-y) +trace-ust-all.c-timestamp: $(trace-events-files) $(tracetool-y) $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ --group=all \ --format=ust-events-c \ @@ -305,6 +305,9 @@ DOCS+=docs/qemu-cpu-models.7 ifdef CONFIG_VIRTFS DOCS+=fsdev/virtfs-proxy-helper.1 endif +ifdef CONFIG_TRACE_SYSTEMTAP +DOCS+=scripts/qemu-trace-stap.1 +endif else DOCS= endif @@ -699,6 +702,9 @@ ifneq ($(TOOLS),) $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8" $(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8" endif +ifdef CONFIG_TRACE_SYSTEMTAP + $(INSTALL_DATA) scripts/qemu-trace-stap.1 "$(DESTDIR)$(mandir)/man1" +endif ifneq (,$(findstring qemu-ga,$(TOOLS))) $(INSTALL_DATA) qemu-ga.8 "$(DESTDIR)$(mandir)/man8" $(INSTALL_DATA) docs/interop/qemu-ga-ref.html "$(DESTDIR)$(qemu_docdir)" @@ -738,6 +744,9 @@ endif ifneq ($(HELPERS-y),) $(call install-prog,$(HELPERS-y),$(DESTDIR)$(libexecdir)) endif +ifdef CONFIG_TRACE_SYSTEMTAP + $(INSTALL_PROG) "scripts/qemu-trace-stap" $(DESTDIR)$(bindir) +endif ifneq ($(BLOBS),) set -e; for x in $(BLOBS); do \ $(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \ @@ -852,6 +861,7 @@ qemu-nbd.8: qemu-nbd.texi qemu-option-trace.texi qemu-ga.8: qemu-ga.texi docs/qemu-block-drivers.7: docs/qemu-block-drivers.texi docs/qemu-cpu-models.7: docs/qemu-cpu-models.texi +scripts/qemu-trace-stap.1: scripts/qemu-trace-stap.texi html: qemu-doc.html docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html info: qemu-doc.info docs/interop/qemu-qmp-ref.info docs/interop/qemu-ga-ref.info diff --git a/Makefile.target b/Makefile.target index 39f72e81be..401dc1ea6f 100644 --- a/Makefile.target +++ b/Makefile.target @@ -45,7 +45,7 @@ config-target.h: config-target.h-timestamp config-target.h-timestamp: config-target.mak ifdef CONFIG_TRACE_SYSTEMTAP -stap: $(QEMU_PROG).stp-installed $(QEMU_PROG).stp $(QEMU_PROG)-simpletrace.stp +stap: $(QEMU_PROG).stp-installed $(QEMU_PROG).stp $(QEMU_PROG)-simpletrace.stp $(QEMU_PROG)-log.stp ifdef CONFIG_USER_ONLY TARGET_TYPE=user @@ -84,6 +84,14 @@ $(QEMU_PROG)-simpletrace.stp: $(BUILD_DIR)/trace-events-all $(tracetool-y) --probe-prefix=qemu.$(TARGET_TYPE).$(TARGET_NAME) \ $< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG)-simpletrace.stp") +$(QEMU_PROG)-log.stp: $(BUILD_DIR)/trace-events-all $(tracetool-y) + $(call quiet-command,$(TRACETOOL) \ + --group=all \ + --format=log-stap \ + --backends=$(TRACE_BACKENDS) \ + --probe-prefix=qemu.$(TARGET_TYPE).$(TARGET_NAME) \ + $< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG)-log.stp") + else stap: endif @@ -227,6 +235,7 @@ ifdef CONFIG_TRACE_SYSTEMTAP $(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset" $(INSTALL_DATA) $(QEMU_PROG).stp-installed "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset/$(QEMU_PROG).stp" $(INSTALL_DATA) $(QEMU_PROG)-simpletrace.stp "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset/$(QEMU_PROG)-simpletrace.stp" + $(INSTALL_DATA) $(QEMU_PROG)-log.stp "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset/$(QEMU_PROG)-log.stp" endif GENERATED_FILES += config-target.h diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c index 7a34e25c43..ba601ce940 100644 --- a/backends/hostmem-file.c +++ b/backends/hostmem-file.c @@ -82,7 +82,8 @@ static void set_mem_path(Object *o, const char *str, Error **errp) HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); if (host_memory_backend_mr_inited(backend)) { - error_setg(errp, "cannot change property value"); + error_setg(errp, "cannot change property 'mem-path' of %s", + object_get_typename(o)); return; } g_free(fb->mem_path); @@ -120,7 +121,8 @@ static void file_memory_backend_set_align(Object *o, Visitor *v, uint64_t val; if (host_memory_backend_mr_inited(backend)) { - error_setg(&local_err, "cannot change property value"); + error_setg(&local_err, "cannot change property '%s' of %s", + name, object_get_typename(o)); goto out; } diff --git a/backends/hostmem.c b/backends/hostmem.c index 0c8ef17653..87b19d2111 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -57,7 +57,8 @@ host_memory_backend_set_size(Object *obj, Visitor *v, const char *name, uint64_t value; if (host_memory_backend_mr_inited(backend)) { - error_setg(&local_err, "cannot change property value"); + error_setg(&local_err, "cannot change property %s of %s ", + name, object_get_typename(obj)); goto out; } @@ -66,8 +67,9 @@ host_memory_backend_set_size(Object *obj, Visitor *v, const char *name, goto out; } if (!value) { - error_setg(&local_err, "Property '%s.%s' doesn't take value '%" - PRIu64 "'", object_get_typename(obj), name, value); + error_setg(&local_err, + "property '%s' of %s doesn't take value '%" PRIu64 "'", + name, object_get_typename(obj), value); goto out; } backend->size = value; diff --git a/docs/devel/tracing.txt b/docs/devel/tracing.txt index bc52f12485..056aa56496 100644 --- a/docs/devel/tracing.txt +++ b/docs/devel/tracing.txt @@ -317,6 +317,10 @@ probes: --target-name x86_64 \ <trace-events-all >qemu.stp +To facilitate simple usage of systemtap where there merely needs to be printf +logging of certain probes, a helper script "qemu-trace-stap" is provided. +Consult its manual page for guidance on its usage. + == Trace event properties == Each event in the "trace-events-all" file can be prefixed with a space-separated diff --git a/hw/core/machine.c b/hw/core/machine.c index 2629515363..077fbd182a 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -30,6 +30,9 @@ GlobalProperty hw_compat_3_1[] = { { "memory-backend-memfd", "x-use-canonical-path-for-ramblock-id", "true" }, { "tpm-crb", "ppi", "false" }, { "tpm-tis", "ppi", "false" }, + { "usb-kbd", "serial", "42" }, + { "usb-mouse", "serial", "42" }, + { "usb-kbd", "serial", "42" }, }; const size_t hw_compat_3_1_len = G_N_ELEMENTS(hw_compat_3_1); diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 8e9a65e75b..da8fd5a40a 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -1763,10 +1763,16 @@ async_common: qxl_set_mode(d, val, 0); break; case QXL_IO_LOG: - trace_qxl_io_log(d->id, d->ram->log_buf); - if (d->guestdebug) { - fprintf(stderr, "qxl/guest-%d: %" PRId64 ": %s", d->id, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), d->ram->log_buf); + if (TRACE_QXL_IO_LOG_ENABLED || d->guestdebug) { + /* We cannot trust the guest to NUL terminate d->ram->log_buf */ + char *log_buf = g_strndup((const char *)d->ram->log_buf, + sizeof(d->ram->log_buf)); + trace_qxl_io_log(d->id, log_buf); + if (d->guestdebug) { + fprintf(stderr, "qxl/guest-%d: %" PRId64 ": %s", d->id, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), log_buf); + } + g_free(log_buf); } break; case QXL_IO_RESET: diff --git a/hw/display/trace-events b/hw/display/trace-events index 5a48c6cb6a..387c6b8931 100644 --- a/hw/display/trace-events +++ b/hw/display/trace-events @@ -72,7 +72,7 @@ qxl_interface_update_area_complete_rest(int qid, uint32_t num_updated_rects) "%d qxl_interface_update_area_complete_overflow(int qid, int max) "%d max=%d" qxl_interface_update_area_complete_schedule_bh(int qid, uint32_t num_dirty) "%d #dirty=%d" qxl_io_destroy_primary_ignored(int qid, const char *mode) "%d %s" -qxl_io_log(int qid, const uint8_t *log_buf) "%d %s" +qxl_io_log(int qid, const char *log_buf) "%d %s" qxl_io_read_unexpected(int qid) "%d" qxl_io_unexpected_vga_mode(int qid, uint64_t addr, uint64_t val, const char *desc) "%d 0x%"PRIx64"=%"PRIu64" (%s)" qxl_io_write(int qid, const char *mode, uint64_t addr, const char *aname, uint64_t val, unsigned size, int async) "%d %s addr=%"PRIu64 " (%s) val=%"PRIu64" size=%u async=%d" diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events index cb41a89756..5d4dd200c2 100644 --- a/hw/gpio/trace-events +++ b/hw/gpio/trace-events @@ -4,4 +4,4 @@ nrf51_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64 nrf51_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64 nrf51_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64 -nrf51_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64 \ No newline at end of file +nrf51_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64 diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 747548b7aa..1690b1935f 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -114,7 +114,15 @@ GlobalProperty pc_compat_3_1[] = { { "intel-iommu", "dma-drain", "off" }, { "Opteron_G3" "-" TYPE_X86_CPU, "rdtscp", "off" }, { "Opteron_G4" "-" TYPE_X86_CPU, "rdtscp", "off" }, + { "Opteron_G4" "-" TYPE_X86_CPU, "npt", "off" }, + { "Opteron_G4" "-" TYPE_X86_CPU, "nrip-save", "off" }, { "Opteron_G5" "-" TYPE_X86_CPU, "rdtscp", "off" }, + { "Opteron_G5" "-" TYPE_X86_CPU, "npt", "off" }, + { "Opteron_G5" "-" TYPE_X86_CPU, "nrip-save", "off" }, + { "EPYC" "-" TYPE_X86_CPU, "npt", "off" }, + { "EPYC" "-" TYPE_X86_CPU, "nrip-save", "off" }, + { "EPYC-IBPB" "-" TYPE_X86_CPU, "npt", "off" }, + { "EPYC-IBPB" "-" TYPE_X86_CPU, "nrip-save", "off" }, { "Skylake-Client" "-" TYPE_X86_CPU, "mpx", "on" }, { "Skylake-Client-IBRS" "-" TYPE_X86_CPU, "mpx", "on" }, { "Skylake-Server" "-" TYPE_X86_CPU, "mpx", "on" }, @@ -122,6 +130,7 @@ GlobalProperty pc_compat_3_1[] = { { "Cascadelake-Server" "-" TYPE_X86_CPU, "mpx", "on" }, { "Icelake-Client" "-" TYPE_X86_CPU, "mpx", "on" }, { "Icelake-Server" "-" TYPE_X86_CPU, "mpx", "on" }, + { "Cascadelake-Server" "-" TYPE_X86_CPU, "stepping", "5" }, }; const size_t pc_compat_3_1_len = G_N_ELEMENTS(pc_compat_3_1); diff --git a/hw/usb/combined-packet.c b/hw/usb/combined-packet.c index fc98383d30..37b23e20ef 100644 --- a/hw/usb/combined-packet.c +++ b/hw/usb/combined-packet.c @@ -9,14 +9,14 @@ * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 2 of the License, or(at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "qemu/osdep.h" diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index 90cd745f06..f9ea3033a1 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -61,10 +61,13 @@ enum { STR_PRODUCT_MOUSE, STR_PRODUCT_TABLET, STR_PRODUCT_KEYBOARD, - STR_SERIALNUMBER, + STR_SERIAL_COMPAT, STR_CONFIG_MOUSE, STR_CONFIG_TABLET, STR_CONFIG_KEYBOARD, + STR_SERIAL_MOUSE, + STR_SERIAL_TABLET, + STR_SERIAL_KEYBOARD, }; static const USBDescStrings desc_strings = { @@ -72,10 +75,13 @@ static const USBDescStrings desc_strings = { [STR_PRODUCT_MOUSE] = "QEMU USB Mouse", [STR_PRODUCT_TABLET] = "QEMU USB Tablet", [STR_PRODUCT_KEYBOARD] = "QEMU USB Keyboard", - [STR_SERIALNUMBER] = "42", /* == remote wakeup works */ + [STR_SERIAL_COMPAT] = "42", [STR_CONFIG_MOUSE] = "HID Mouse", [STR_CONFIG_TABLET] = "HID Tablet", [STR_CONFIG_KEYBOARD] = "HID Keyboard", + [STR_SERIAL_MOUSE] = "89126", + [STR_SERIAL_TABLET] = "28754", + [STR_SERIAL_KEYBOARD] = "68284", }; static const USBDescIface desc_iface_mouse = { @@ -375,7 +381,7 @@ static const USBDesc desc_mouse = { .bcdDevice = 0, .iManufacturer = STR_MANUFACTURER, .iProduct = STR_PRODUCT_MOUSE, - .iSerialNumber = STR_SERIALNUMBER, + .iSerialNumber = STR_SERIAL_MOUSE, }, .full = &desc_device_mouse, .str = desc_strings, @@ -389,7 +395,7 @@ static const USBDesc desc_mouse2 = { .bcdDevice = 0, .iManufacturer = STR_MANUFACTURER, .iProduct = STR_PRODUCT_MOUSE, - .iSerialNumber = STR_SERIALNUMBER, + .iSerialNumber = STR_SERIAL_MOUSE, }, .full = &desc_device_mouse, .high = &desc_device_mouse2, @@ -404,7 +410,7 @@ static const USBDesc desc_tablet = { .bcdDevice = 0, .iManufacturer = STR_MANUFACTURER, .iProduct = STR_PRODUCT_TABLET, - .iSerialNumber = STR_SERIALNUMBER, + .iSerialNumber = STR_SERIAL_TABLET, }, .full = &desc_device_tablet, .str = desc_strings, @@ -418,7 +424,7 @@ static const USBDesc desc_tablet2 = { .bcdDevice = 0, .iManufacturer = STR_MANUFACTURER, .iProduct = STR_PRODUCT_TABLET, - .iSerialNumber = STR_SERIALNUMBER, + .iSerialNumber = STR_SERIAL_TABLET, }, .full = &desc_device_tablet, .high = &desc_device_tablet2, @@ -433,7 +439,7 @@ static const USBDesc desc_keyboard = { .bcdDevice = 0, .iManufacturer = STR_MANUFACTURER, .iProduct = STR_PRODUCT_KEYBOARD, - .iSerialNumber = STR_SERIALNUMBER, + .iSerialNumber = STR_SERIAL_KEYBOARD, }, .full = &desc_device_keyboard, .str = desc_strings, @@ -447,7 +453,7 @@ static const USBDesc desc_keyboard2 = { .bcdDevice = 0, .iManufacturer = STR_MANUFACTURER, .iProduct = STR_PRODUCT_KEYBOARD, - .iSerialNumber = STR_SERIALNUMBER, + .iSerialNumber = STR_SERIAL_KEYBOARD, }, .full = &desc_device_keyboard, .high = &desc_device_keyboard2, @@ -718,9 +724,7 @@ static void usb_hid_initfn(USBDevice *dev, int kind, return; } - if (dev->serial) { - usb_desc_set_string(dev, STR_SERIALNUMBER, dev->serial); - } + usb_desc_create_serial(dev); usb_desc_init(dev); us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); hid_init(&us->hid, kind, usb_hid_changed); diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 68c5eb8eaa..f1d20fa1b9 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -25,6 +25,7 @@ #include "trace.h" #include "hw/usb.h" #include "desc.h" +#include "qemu/units.h" /* ----------------------------------------------------------------------- */ @@ -35,6 +36,13 @@ enum mtp_container_type { TYPE_EVENT = 4, }; +/* MTP write stage, for internal use only */ +enum mtp_write_status { + WRITE_START = 1, + WRITE_CONTINUE = 2, + WRITE_END = 3, +}; + enum mtp_code { /* command codes */ CMD_GET_DEVICE_INFO = 0x1001, @@ -152,8 +160,10 @@ struct MTPData { bool first; /* Used for >4G file sizes */ bool pending; - uint64_t cached_length; int fd; + uint8_t write_status; + /* Internal pointer per every MTP_WRITE_BUF_SZ */ + uint64_t data_offset; }; struct MTPObject { @@ -244,6 +254,7 @@ typedef struct { #define MTP_MANUFACTURER "QEMU" #define MTP_PRODUCT "QEMU filesharing" +#define MTP_WRITE_BUF_SZ (512 * KiB) enum { STR_MANUFACTURER = 1, @@ -666,6 +677,7 @@ static void usb_mtp_object_readdir(MTPState *s, MTPObject *o) } dir = fdopendir(fd); if (!dir) { + close(fd); return; } #ifdef CONFIG_INOTIFY1 @@ -1618,21 +1630,28 @@ static char *utf16_to_str(uint8_t len, uint16_t *arr) } /* Wrapper around write, returns 0 on failure */ -static uint64_t write_retry(int fd, void *buf, uint64_t size) +static uint64_t write_retry(int fd, void *buf, uint64_t size, off_t offset) { - uint64_t bytes_left = size, ret; + uint64_t ret = 0; - while (bytes_left > 0) { - ret = write(fd, buf, bytes_left); - if ((ret == -1) && (errno != EINTR || errno != EAGAIN || - errno != EWOULDBLOCK)) { - break; - } - bytes_left -= ret; - buf += ret; + if (lseek(fd, offset, SEEK_SET) < 0) { + goto done; } - return size - bytes_left; + ret = qemu_write_full(fd, buf, size); + +done: + return ret; +} + +static void usb_mtp_update_object(MTPObject *parent, char *name) +{ + MTPObject *o = + usb_mtp_object_lookup_name(parent, name, strlen(name)); + + if (o) { + lstat(o->path, &o->stat); + } } static void usb_mtp_write_data(MTPState *s) @@ -1646,48 +1665,56 @@ static void usb_mtp_write_data(MTPState *s) assert(d != NULL); - if (parent == NULL || !s->write_pending) { - usb_mtp_queue_result(s, RES_INVALID_OBJECTINFO, d->trans, - 0, 0, 0, 0); + switch (d->write_status) { + case WRITE_START: + if (!parent || !s->write_pending) { + usb_mtp_queue_result(s, RES_INVALID_OBJECTINFO, d->trans, + 0, 0, 0, 0); return; - } - - if (s->dataset.filename) { - path = g_strdup_printf("%s/%s", parent->path, s->dataset.filename); - if (s->dataset.format == FMT_ASSOCIATION) { - d->fd = mkdir(path, mask); - goto free; - } - if ((s->dataset.size != 0xFFFFFFFF) && (s->dataset.size < d->length)) { - usb_mtp_queue_result(s, RES_STORE_FULL, d->trans, - 0, 0, 0, 0); - goto done; - } - d->fd = open(path, O_CREAT | O_WRONLY | O_CLOEXEC | O_NOFOLLOW, mask); - if (d->fd == -1) { - usb_mtp_queue_result(s, RES_STORE_FULL, d->trans, - 0, 0, 0, 0); - goto done; } - /* - * Return success if initiator sent 0 sized data - */ - if (!s->dataset.size) { - goto success; - } + if (s->dataset.filename) { + path = g_strdup_printf("%s/%s", parent->path, s->dataset.filename); + if (s->dataset.format == FMT_ASSOCIATION) { + d->fd = mkdir(path, mask); + goto free; + } + d->fd = open(path, O_CREAT | O_WRONLY | + O_CLOEXEC | O_NOFOLLOW, mask); + if (d->fd == -1) { + usb_mtp_queue_result(s, RES_STORE_FULL, d->trans, + 0, 0, 0, 0); + goto done; + } - rc = write_retry(d->fd, d->data, d->offset); - if (rc != d->offset) { + /* Return success if initiator sent 0 sized data */ + if (!s->dataset.size) { + goto success; + } + if (d->length != MTP_WRITE_BUF_SZ && !d->pending) { + d->write_status = WRITE_END; + } + } + /* fall through */ + case WRITE_CONTINUE: + case WRITE_END: + rc = write_retry(d->fd, d->data, d->data_offset, + d->offset - d->data_offset); + if (rc != d->data_offset) { usb_mtp_queue_result(s, RES_STORE_FULL, d->trans, 0, 0, 0, 0); goto done; + } + if (d->write_status != WRITE_END) { + return; + } else { + /* Only for < 4G file sizes */ + if (s->dataset.size != 0xFFFFFFFF && d->offset != s->dataset.size) { + usb_mtp_queue_result(s, RES_INCOMPLETE_TRANSFER, d->trans, + 0, 0, 0, 0); + goto done; } - /* Only for < 4G file sizes */ - if (s->dataset.size != 0xFFFFFFFF && rc != s->dataset.size) { - usb_mtp_queue_result(s, RES_INCOMPLETE_TRANSFER, d->trans, - 0, 0, 0, 0); - goto done; + usb_mtp_update_object(parent, s->dataset.filename); } } @@ -1776,37 +1803,43 @@ static void usb_mtp_get_data(MTPState *s, mtp_container *container, total_len = cpu_to_le32(container->length) - sizeof(mtp_container); /* Length of data in this packet */ data_len -= sizeof(mtp_container); - usb_mtp_realloc(d, total_len); - d->length += total_len; + if (total_len < MTP_WRITE_BUF_SZ) { + usb_mtp_realloc(d, total_len); + d->length += total_len; + } else { + usb_mtp_realloc(d, MTP_WRITE_BUF_SZ - sizeof(mtp_container)); + d->length += MTP_WRITE_BUF_SZ - sizeof(mtp_container); + } d->offset = 0; - d->cached_length = total_len; d->first = false; d->pending = false; + d->data_offset = 0; + d->write_status = WRITE_START; } if (d->pending) { - usb_mtp_realloc(d, d->cached_length); - d->length += d->cached_length; + memset(d->data, 0, d->length); + if (d->length != MTP_WRITE_BUF_SZ) { + usb_mtp_realloc(d, MTP_WRITE_BUF_SZ - d->length); + d->length += (MTP_WRITE_BUF_SZ - d->length); + } d->pending = false; + d->write_status = WRITE_CONTINUE; + d->data_offset = 0; } - if (d->length - d->offset > data_len) { + if (d->length - d->data_offset > data_len) { dlen = data_len; } else { - dlen = d->length - d->offset; - /* Check for cached data for large files */ - if ((s->dataset.size == 0xFFFFFFFF) && (dlen < p->iov.size)) { - usb_mtp_realloc(d, p->iov.size - dlen); - d->length += p->iov.size - dlen; - dlen = p->iov.size; - } + dlen = d->length - d->data_offset; } switch (d->code) { case CMD_SEND_OBJECT_INFO: - usb_packet_copy(p, d->data + d->offset, dlen); + usb_packet_copy(p, d->data + d->data_offset, dlen); d->offset += dlen; - if (d->offset == d->length) { + d->data_offset += dlen; + if (d->data_offset == d->length) { /* The operation might have already failed */ if (!s->result) { usb_mtp_write_metadata(s, dlen); @@ -1817,19 +1850,26 @@ static void usb_mtp_get_data(MTPState *s, mtp_container *container, } break; case CMD_SEND_OBJECT: - usb_packet_copy(p, d->data + d->offset, dlen); + usb_packet_copy(p, d->data + d->data_offset, dlen); d->offset += dlen; + d->data_offset += dlen; if ((p->iov.size % 64) || !p->iov.size) { assert((s->dataset.size == 0xFFFFFFFF) || - (s->dataset.size == d->length)); + (s->dataset.size == d->offset)); + if (d->length == MTP_WRITE_BUF_SZ) { + d->write_status = WRITE_END; + } else { + d->write_status = WRITE_START; + } usb_mtp_write_data(s); usb_mtp_data_free(s->data_out); s->data_out = NULL; return; } - if (d->offset == d->length) { + if (d->data_offset == d->length) { d->pending = true; + usb_mtp_write_data(s); } break; default: diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c index 69abbf7b7b..38b24b160a 100644 --- a/hw/usb/hcd-ehci-pci.c +++ b/hw/usb/hcd-ehci-pci.c @@ -4,14 +4,14 @@ * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 2 of the License, or(at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, see <http://www.gnu.org/licenses/>. */ diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c index 331faf8bc3..9f7f128f19 100644 --- a/hw/usb/hcd-ehci-sysbus.c +++ b/hw/usb/hcd-ehci-sysbus.c @@ -4,14 +4,14 @@ * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 2 of the License, or(at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, see <http://www.gnu.org/licenses/>. */ diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index e233681962..9b132cb0d3 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -12,18 +12,17 @@ * Niels de Vos. David S. Ahern continued working on it. Kevin Wolf, * Jan Kiszka and Vincent Palatin contributed bugfixes. * - * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 2 of the License, or(at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, see <http://www.gnu.org/licenses/>. */ diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index d6601706ee..fedf82c611 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -4,14 +4,14 @@ * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 2 of the License, or(at your option) any later version. + * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, see <http://www.gnu.org/licenses/>. */ diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 8f1a01a405..19c64f7ff4 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -1571,6 +1571,11 @@ static void xhci_stall_ep(XHCITransfer *xfer) uint32_t err; XHCIStreamContext *sctx; + if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) { + /* never halt isoch endpoints, 4.10.2 */ + return; + } + if (epctx->nr_pstreams) { sctx = xhci_find_stream(epctx, xfer->streamid, &err); if (sctx == NULL) { @@ -1944,6 +1949,16 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) while (1) { length = xhci_ring_chain_length(xhci, ring); if (length <= 0) { + if (epctx->type == ET_ISO_OUT || epctx->type == ET_ISO_IN) { + /* 4.10.3.1 */ + XHCIEvent ev = { ER_TRANSFER }; + ev.ccode = epctx->type == ET_ISO_IN ? + CC_RING_OVERRUN : CC_RING_UNDERRUN; + ev.slotid = epctx->slotid; + ev.epid = epctx->epid; + ev.ptr = epctx->ring.dequeue; + xhci_event(xhci, &ev, xhci->slots[epctx->slotid-1].intr); + } break; } xfer = xhci_ep_alloc_xfer(epctx, length); @@ -2023,6 +2038,7 @@ static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid) xhci->slots[slotid-1].enabled = 0; xhci->slots[slotid-1].addressed = 0; xhci->slots[slotid-1].uport = NULL; + xhci->slots[slotid-1].intr = 0; return CC_SUCCESS; } @@ -2122,6 +2138,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, slot = &xhci->slots[slotid-1]; slot->uport = uport; slot->ctx = octx; + slot->intr = get_field(slot_ctx[2], TRB_INTR); /* Make sure device is in USB_STATE_DEFAULT state */ usb_device_reset(dev); @@ -2295,8 +2312,9 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid, slot_ctx[1] &= ~0xFFFF; /* max exit latency */ slot_ctx[1] |= islot_ctx[1] & 0xFFFF; - slot_ctx[2] &= ~0xFF00000; /* interrupter target */ - slot_ctx[2] |= islot_ctx[2] & 0xFF000000; + /* update interrupter target field */ + xhci->slots[slotid-1].intr = get_field(islot_ctx[2], TRB_INTR); + set_field(&slot_ctx[2], xhci->slots[slotid-1].intr, TRB_INTR); DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n", slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]); diff --git a/hw/usb/hcd-xhci.h b/hw/usb/hcd-xhci.h index fc36a4c787..240caa4e51 100644 --- a/hw/usb/hcd-xhci.h +++ b/hw/usb/hcd-xhci.h @@ -140,6 +140,7 @@ typedef struct XHCIPort { typedef struct XHCISlot { bool enabled; bool addressed; + uint16_t intr; dma_addr_t ctx; USBPort *uport; XHCIEPContext *eps[31]; diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index c0cb1ec289..dd12f36391 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -2581,7 +2581,7 @@ static void vfio_populate_device(VFIOPCIDevice *vdev, Error **errp) ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info); if (ret) { /* This can fail for an old kernel or legacy PCI dev */ - trace_vfio_populate_device_get_irq_info_failure(); + trace_vfio_populate_device_get_irq_info_failure(strerror(errno)); } else if (irq_info.count == 1) { vdev->pci_aer = true; } else { diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index a85e8662ea..f41ca96160 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -37,7 +37,7 @@ vfio_pci_hot_reset_has_dep_devices(const char *name) "%s: hot reset dependent de vfio_pci_hot_reset_dep_devices(int domain, int bus, int slot, int function, int group_id) "\t%04x:%02x:%02x.%x group %d" vfio_pci_hot_reset_result(const char *name, const char *result) "%s hot reset: %s" vfio_populate_device_config(const char *name, unsigned long size, unsigned long offset, unsigned long flags) "Device %s config:\n size: 0x%lx, offset: 0x%lx, flags: 0x%lx" -vfio_populate_device_get_irq_info_failure(void) "VFIO_DEVICE_GET_IRQ_INFO failure: %m" +vfio_populate_device_get_irq_info_failure(const char *errstr) "VFIO_DEVICE_GET_IRQ_INFO failure: %s" vfio_realize(const char *name, int group_id) " (%s) group %d" vfio_mdev(const char *name, bool is_mdev) " (%s) is_mdev %d" vfio_add_ext_cap_dropped(const char *name, uint16_t cap, uint16_t offset) "%s 0x%x@0x%x" diff --git a/numa.c b/numa.c index 50ec016013..3875e1efda 100644 --- a/numa.c +++ b/numa.c @@ -533,6 +533,7 @@ void memory_region_allocate_system_memory(MemoryRegion *mr, Object *owner, error_report("memory backend %s is used multiple times. Each " "-numa option must use a different memdev value.", path); + g_free(path); exit(1); } diff --git a/scripts/qemu-trace-stap b/scripts/qemu-trace-stap new file mode 100755 index 0000000000..91d1051cdc --- /dev/null +++ b/scripts/qemu-trace-stap @@ -0,0 +1,175 @@ +#!/usr/bin/python +# -*- python -*- +# +# Copyright (C) 2019 Red Hat, Inc +# +# QEMU SystemTap Trace Tool +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +import argparse +import copy +import os.path +import re +import subprocess +import sys + + +def probe_prefix(binary): + dirname, filename = os.path.split(binary) + return re.sub("-", ".", filename) + ".log" + + +def which(binary): + for path in os.environ["PATH"].split(os.pathsep): + if os.path.exists(os.path.join(path, binary)): + return os.path.join(path, binary) + + print("Unable to find '%s' in $PATH" % binary) + sys.exit(1) + + +def tapset_dir(binary): + dirname, filename = os.path.split(binary) + if dirname == '': + thisfile = which(binary) + else: + thisfile = os.path.realpath(binary) + if not os.path.exists(thisfile): + print("Unable to find '%s'" % thisfile) + sys.exit(1) + + basedir = os.path.split(thisfile)[0] + tapset = os.path.join(basedir, "..", "share", "systemtap", "tapset") + return os.path.realpath(tapset) + + +def tapset_env(tapset_dir): + tenv = copy.copy(os.environ) + tenv["SYSTEMTAP_TAPSET"] = tapset_dir + return tenv + +def cmd_run(args): + prefix = probe_prefix(args.binary) + tapsets = tapset_dir(args.binary) + + if args.verbose: + print("Using tapset dir '%s' for binary '%s'" % (tapsets, args.binary)) + + probes = [] + for probe in args.probes: + probes.append("probe %s.%s {}" % (prefix, probe)) + if len(probes) == 0: + print("At least one probe pattern must be specified") + sys.exit(1) + + script = " ".join(probes) + if args.verbose: + print("Compiling script '%s'" % script) + script = """probe begin { print("Running script, <Ctrl>-c to quit\\n") } """ + script + + # We request an 8MB buffer, since the stap default 1MB buffer + # can be easily overflowed by frequently firing QEMU traces + stapargs = ["stap", "-s", "8"] + if args.pid is not None: + stapargs.extend(["-x", args.pid]) + stapargs.extend(["-e", script]) + subprocess.call(stapargs, env=tapset_env(tapsets)) + + +def cmd_list(args): + tapsets = tapset_dir(args.binary) + + if args.verbose: + print("Using tapset dir '%s' for binary '%s'" % (tapsets, args.binary)) + + def print_probes(verbose, name): + prefix = probe_prefix(args.binary) + offset = len(prefix) + 1 + script = prefix + "." + name + + if verbose: + print("Listing probes with name '%s'" % script) + proc = subprocess.Popen(["stap", "-l", script], + stdout=subprocess.PIPE, env=tapset_env(tapsets)) + out, err = proc.communicate() + if proc.returncode != 0: + print("No probes found, are the tapsets installed in %s" % tapset_dir(args.binary)) + sys.exit(1) + + for line in out.splitlines(): + if line.startswith(prefix): + print("%s" % line[offset:]) + + if len(args.probes) == 0: + print_probes(args.verbose, "*") + else: + for probe in args.probes: + print_probes(args.verbose, probe) + + +def main(): + parser = argparse.ArgumentParser(description="QEMU SystemTap trace tool") + parser.add_argument("-v", "--verbose", help="Print verbose progress info", + action='store_true') + + subparser = parser.add_subparsers(help="commands") + subparser.required = True + subparser.dest = "command" + + runparser = subparser.add_parser("run", help="Run a trace session", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" + +To watch all trace points on the qemu-system-x86_64 binary: + + %(argv0)s run qemu-system-x86_64 + +To only watch the trace points matching the qio* and qcrypto* patterns + + %(argv0)s run qemu-system-x86_64 'qio*' 'qcrypto*' +""" % {"argv0": sys.argv[0]}) + runparser.set_defaults(func=cmd_run) + runparser.add_argument("--pid", "-p", dest="pid", + help="Restrict tracing to a specific process ID") + runparser.add_argument("binary", help="QEMU system or user emulator binary") + runparser.add_argument("probes", help="Probe names or wildcards", + nargs=argparse.REMAINDER) + + listparser = subparser.add_parser("list", help="List probe points", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" + +To list all trace points on the qemu-system-x86_64 binary: + + %(argv0)s list qemu-system-x86_64 + +To only list the trace points matching the qio* and qcrypto* patterns + + %(argv0)s list qemu-system-x86_64 'qio*' 'qcrypto*' +""" % {"argv0": sys.argv[0]}) + listparser.set_defaults(func=cmd_list) + listparser.add_argument("binary", help="QEMU system or user emulator binary") + listparser.add_argument("probes", help="Probe names or wildcards", + nargs=argparse.REMAINDER) + + args = parser.parse_args() + + args.func(args) + sys.exit(0) + +if __name__ == '__main__': + main() diff --git a/scripts/qemu-trace-stap.texi b/scripts/qemu-trace-stap.texi new file mode 100644 index 0000000000..07bb9eb94e --- /dev/null +++ b/scripts/qemu-trace-stap.texi @@ -0,0 +1,140 @@ +@example +@c man begin SYNOPSIS +@command{qemu-trace-stap} @var{GLOBAL-OPTIONS} @var{COMMAND} @var{COMMAND-OPTIONS} @var{ARGS...} +@c man end +@end example + +@c man begin DESCRIPTION + +The @command{qemu-trace-stap} program facilitates tracing of the execution +of QEMU emulators using SystemTap. + +It is required to have the SystemTap runtime environment installed to use +this program, since it is a wrapper around execution of the @command{stap} +program. + +@c man end + +@c man begin OPTIONS + +The following global options may be used regardless of which command +is executed: + +@table @option +@item @var{--verbose}, @var{-v} + +Display verbose information about command execution. + +@end table + +The following commands are valid: + +@table @option + +@item @var{list} @var{BINARY} @var{PATTERN...} + +List all the probe names provided by @var{BINARY} that match +@var{PATTERN}. + +If @var{BINARY} is not an absolute path, it will be located by searching +the directories listed in the @code{$PATH} environment variable. + +@var{PATTERN} is a plain string that is used to filter the results of +this command. It may optionally contain a @code{*} wildcard to facilitate +matching multiple probes without listing each one explicitly. Multiple +@var{PATTERN} arguments may be given, causing listing of probes that match +any of the listed names. If no @var{PATTERN} is given, the all possible +probes will be listed. + +For example, to list all probes available in the @command{qemu-system-x86_64} +binary: + +@example +$ qemu-trace-stap list qemu-system-x86_64 +@end example + +To filter the list to only cover probes related to QEMU's cryptographic +subsystem, in a binary outside @code{$PATH} + +@example +$ qemu-trace-stap list /opt/qemu/4.0.0/bin/qemu-system-x86_64 'qcrypto*' +@end example + + +@item @var{run} @var{OPTIONS} @var{BINARY} @var{PATTERN...} + +Run a trace session, printing formatted output any time a process that is +executing @var{BINARY} triggers a probe matching @var{PATTERN}. + +If @var{BINARY} is not an absolute path, it will be located by searching +the directories listed in the @code{$PATH} environment variable. + +@var{PATTERN} is a plain string that matches a probe name shown by the +@var{list} command. It may optionally contain a @code{*} wildcard to +facilitate matching multiple probes without listing each one explicitly. +Multiple @var{PATTERN} arguments may be given, causing all matching probes +to be monitored. At least one @var{PATTERN} is required, since stap is not +capable of tracing all known QEMU probes concurrently without overflowing +its trace buffer. + +Invocation of this command does not need to be synchronized with +invocation of the QEMU process(es). It will match probes on all +existing running processes and all future launched processes, +unless told to only monitor a specific process. + +Valid command specific options are: + +@table @option +@item @var{--pid=PID}, @var{-p PID} + +Restrict the tracing session so that it only triggers for the process +identified by @code{PID}. + +@end table + +For example, to monitor all processes executing @command{qemu-system-x86_64} +as found on $PATH, displaying all I/O related probes: + +@example +$ qemu-trace-stap run qemu-system-x86_64 'qio*' +@end example + +To monitor only the QEMU process with PID 1732 + +@example +$ qemu-trace-stap run --pid=1732 qemu-system-x86_64 'qio*' +@end example + +To monitor QEMU processes running an alternative binary outside of +@code{$PATH}, displaying verbose information about setup of the +tracing environment: + +@example +$ qemu-trace-stap -v run /opt/qemu/4.0.0/qemu-system-x86_64 'qio*' +@end example + +@end table + +@c man end + +@ignore + +@setfilename qemu-trace-stap +@settitle QEMU SystemTap trace tool + +@c man begin LICENSE + +Copyright (C) 2019 Red Hat, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +@c man end + +@c man begin SEEALSO +qemu(1), stap(1) +@c man end + +@end ignore diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py index 0e3c9e146c..6fca674936 100644 --- a/scripts/tracetool/__init__.py +++ b/scripts/tracetool/__init__.py @@ -274,6 +274,10 @@ class Event(object): props = groups["props"].split() fmt = groups["fmt"] fmt_trans = groups["fmt_trans"] + if fmt.find("%m") != -1 or fmt_trans.find("%m") != -1: + raise ValueError("Event format '%m' is forbidden, pass the error " + "as an explicit trace argument") + if len(fmt_trans) > 0: fmt = [fmt_trans, fmt] args = Arguments.build(groups["args"]) @@ -350,6 +354,8 @@ def read_events(fobj, fname): events = [] for lineno, line in enumerate(fobj, 1): + if line[-1] != '\n': + raise ValueError("%s does not end with a new line" % fname) if not line.strip(): continue if line.lstrip().startswith('#'): diff --git a/scripts/tracetool/format/log_stap.py b/scripts/tracetool/format/log_stap.py new file mode 100644 index 0000000000..3ccbc09d61 --- /dev/null +++ b/scripts/tracetool/format/log_stap.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Generate .stp file that printfs log messages (DTrace with SystemTAP only). +""" + +__author__ = "Daniel P. Berrange <berrange@redhat.com>" +__copyright__ = "Copyright (C) 2014-2019, Red Hat, Inc." +__license__ = "GPL version 2 or (at your option) any later version" + +__maintainer__ = "Daniel Berrange" +__email__ = "berrange@redhat.com" + +import re + +from tracetool import out +from tracetool.backend.dtrace import binary, probeprefix +from tracetool.backend.simple import is_string +from tracetool.format.stap import stap_escape + +def global_var_name(name): + return probeprefix().replace(".", "_") + "_" + name + +STATE_SKIP = 0 +STATE_LITERAL = 1 +STATE_MACRO = 2 + +def c_macro_to_format(macro): + if macro.startswith("PRI"): + return macro[3] + + if macro == "TARGET_FMT_plx": + return "%016x" + + raise Exception("Unhandled macro '%s'" % macro) + +def c_fmt_to_stap(fmt): + state = 0 + bits = [] + literal = "" + macro = "" + escape = 0; + for i in range(len(fmt)): + if fmt[i] == '\\': + if escape: + escape = 0 + else: + escape = 1 + if state != STATE_LITERAL: + raise Exception("Unexpected escape outside string literal") + literal = literal + fmt[i] + elif fmt[i] == '"' and not escape: + if state == STATE_LITERAL: + state = STATE_SKIP + bits.append(literal) + literal = "" + else: + if state == STATE_MACRO: + bits.append(c_macro_to_format(macro)) + state = STATE_LITERAL + elif fmt[i] == ' ' or fmt[i] == '\t': + if state == STATE_MACRO: + bits.append(c_macro_to_format(macro)) + macro = "" + state = STATE_SKIP + elif state == STATE_LITERAL: + literal = literal + fmt[i] + else: + escape = 0 + if state == STATE_SKIP: + state = STATE_MACRO + + if state == STATE_LITERAL: + literal = literal + fmt[i] + else: + macro = macro + fmt[i] + + if state == STATE_MACRO: + bits.append(c_macro_to_format(macro)) + elif state == STATE_LITERAL: + bits.append(literal) + + fmt = re.sub("%(\d*)z(x|u|d)", "%\\1\\2", "".join(bits)) + return fmt + +def generate(events, backend, group): + out('/* This file is autogenerated by tracetool, do not edit. */', + '') + + for event_id, e in enumerate(events): + if 'disable' in e.properties: + continue + + out('probe %(probeprefix)s.log.%(name)s = %(probeprefix)s.%(name)s ?', + '{', + probeprefix=probeprefix(), + name=e.name) + + # Get references to userspace strings + for type_, name in e.args: + name = stap_escape(name) + if is_string(type_): + out(' try {', + ' arg%(name)s_str = %(name)s ? ' + + 'user_string_n(%(name)s, 512) : "<null>"', + ' } catch {}', + name=name) + + # Determine systemtap's view of variable names + fields = ["pid()", "gettimeofday_ns()"] + for type_, name in e.args: + name = stap_escape(name) + if is_string(type_): + fields.append("arg" + name + "_str") + else: + fields.append(name) + + # Emit the entire record in a single SystemTap printf() + arg_str = ', '.join(arg for arg in fields) + fmt_str = "%d@%d " + e.name + " " + c_fmt_to_stap(e.fmt) + "\\n" + out(' printf("%(fmt_str)s", %(arg_str)s)', + fmt_str=fmt_str, arg_str=arg_str) + + out('}') + + out() diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 2f5412592d..7483daef58 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -2503,7 +2503,7 @@ static X86CPUDefinition builtin_x86_defs[] = { .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 85, - .stepping = 5, + .stepping = 6, .features[FEAT_1_EDX] = CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | @@ -2801,6 +2801,8 @@ static X86CPUDefinition builtin_x86_defs[] = { CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM, + .features[FEAT_SVM] = + CPUID_SVM_NPT | CPUID_SVM_NRIPSAVE, /* no xsaveopt! */ .xlevel = 0x8000001A, .model_id = "AMD Opteron 62xx class CPU", @@ -2831,6 +2833,8 @@ static X86CPUDefinition builtin_x86_defs[] = { CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM, + .features[FEAT_SVM] = + CPUID_SVM_NPT | CPUID_SVM_NRIPSAVE, /* no xsaveopt! */ .xlevel = 0x8000001A, .model_id = "AMD Opteron 63xx class CPU", @@ -2877,6 +2881,8 @@ static X86CPUDefinition builtin_x86_defs[] = { CPUID_XSAVE_XGETBV1, .features[FEAT_6_EAX] = CPUID_6_EAX_ARAT, + .features[FEAT_SVM] = + CPUID_SVM_NPT | CPUID_SVM_NRIPSAVE, .xlevel = 0x8000001E, .model_id = "AMD EPYC Processor", .cache_info = &epyc_cache_info, @@ -2925,6 +2931,8 @@ static X86CPUDefinition builtin_x86_defs[] = { CPUID_XSAVE_XGETBV1, .features[FEAT_6_EAX] = CPUID_6_EAX_ARAT, + .features[FEAT_SVM] = + CPUID_SVM_NPT | CPUID_SVM_NRIPSAVE, .xlevel = 0x8000001E, .model_id = "AMD EPYC Processor (with IBPB)", .cache_info = &epyc_cache_info, diff --git a/trace-events b/trace-events index 4fd2cb4b97..e66afc59e9 100644 --- a/trace-events +++ b/trace-events @@ -34,9 +34,9 @@ cpu_out(unsigned int addr, char size, unsigned int val) "addr 0x%x(%c) value %u" balloon_event(void *opaque, unsigned long addr) "opaque %p addr %lu" # vl.c -vm_state_notify(int running, int reason) "running %d reason %d" +vm_state_notify(int running, int reason, const char *reason_str) "running %d reason %d (%s)" load_file(const char *name, const char *path) "name %s location %s" -runstate_set(int new_state) "new state %d" +runstate_set(int current_state, const char *current_state_str, int new_state, const char *new_state_str) "current_run_state %d (%s) new_state %d (%s)" system_wakeup_request(int reason) "reason=%d" qemu_system_shutdown_request(int reason) "reason=%d" qemu_system_powerdown_request(void) "" diff --git a/vl.c b/vl.c index bc9fbec654..9cf0fbe0b8 100644 --- a/vl.c +++ b/vl.c @@ -731,6 +731,9 @@ void runstate_set(RunState new_state) { assert(new_state < RUN_STATE__MAX); + trace_runstate_set(current_run_state, RunState_str(current_run_state), + new_state, RunState_str(current_run_state)); + if (current_run_state == new_state) { return; } @@ -741,7 +744,7 @@ void runstate_set(RunState new_state) RunState_str(new_state)); abort(); } - trace_runstate_set(new_state); + current_run_state = new_state; } @@ -1554,7 +1557,7 @@ void vm_state_notify(int running, RunState state) { VMChangeStateEntry *e, *next; - trace_vm_state_notify(running, state); + trace_vm_state_notify(running, state, RunState_str(state)); QLIST_FOREACH_SAFE(e, &vm_change_state_head, entries, next) { e->cb(e->opaque, running, state); |