* [Qemu-devel] [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel @ 2016-09-05 18:56 Lluís Vilanova 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 1/6] hypertrace: Add documentation Lluís Vilanova ` (6 more replies) 0 siblings, 7 replies; 14+ messages in thread From: Lluís Vilanova @ 2016-09-05 18:56 UTC (permalink / raw) To: qemu-devel Cc: Daniel P Berrange, Luiz Capitulino, Eric Blake, Stefan Hajnoczi The hypertrace channel allows guest code to emit events in QEMU (the host) using its tracing infrastructure (see "docs/trace.txt"). This works in both 'system' and 'user' modes, is architecture-agnostic and introduces minimal noise on the guest. See first commit for a full description, use-cases and an example. Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> --- Changes in v2 ============= * Remove unnecessary casts for g2h() [Eric Blake]. * Use perror() [Eric Blake]. * Avoid expansions in application example [Eric Blake]. * Add copyright in document "hypertrace.txt" [Eric Blake]. * Make the user-mode hypertrace invocations thread-safe [Stefan Hajnoczi]. * Split dynamic hypertrace configuration into a separate "config" channel. Changes in v3 ============= * Fix calculation of arguments. * Rebase on e00da55 Lluís Vilanova (6): hypertrace: Add documentation hypertrace: Add tracing event "guest_hypertrace" hypertrace: [*-user] Add QEMU-side proxy to "guest_hypertrace" event hypertrace: [softmmu] Add QEMU-side proxy to "guest_hypertrace" event hypertrace: Add guest-side user-level library hypertrace: Add guest-side Linux module Makefile | 8 Makefile.objs | 6 bsd-user/main.c | 16 + bsd-user/mmap.c | 15 + bsd-user/syscall.c | 31 +- configure | 40 ++ docs/hypertrace.txt | 227 +++++++++++++ docs/tracing.txt | 3 hypertrace/Makefile.objs | 21 + hypertrace/common.c | 26 ++ hypertrace/common.h | 24 + hypertrace/guest/linux-module/Kbuild.in | 7 hypertrace/guest/linux-module/Makefile | 23 + .../include/linux/qemu-hypertrace-internal.h | 46 +++ .../linux-module/include/linux/qemu-hypertrace.h | 73 ++++ hypertrace/guest/linux-module/qemu-hypertrace.c | 146 +++++++++ hypertrace/guest/user/Makefile | 30 ++ hypertrace/guest/user/common.c | 301 ++++++++++++++++++ hypertrace/guest/user/qemu-hypertrace.h | 80 +++++ hypertrace/softmmu.c | 235 ++++++++++++++ hypertrace/user.c | 339 ++++++++++++++++++++ hypertrace/user.h | 61 ++++ include/hw/pci/pci.h | 2 include/qom/cpu.h | 4 linux-user/main.c | 19 + linux-user/mmap.c | 17 + linux-user/qemu.h | 3 linux-user/syscall.c | 31 +- trace/Makefile.objs | 2 29 files changed, 1809 insertions(+), 27 deletions(-) create mode 100644 docs/hypertrace.txt create mode 100644 hypertrace/Makefile.objs create mode 100644 hypertrace/common.c create mode 100644 hypertrace/common.h create mode 100644 hypertrace/guest/linux-module/Kbuild.in create mode 100644 hypertrace/guest/linux-module/Makefile create mode 100644 hypertrace/guest/linux-module/include/linux/qemu-hypertrace-internal.h create mode 100644 hypertrace/guest/linux-module/include/linux/qemu-hypertrace.h create mode 100644 hypertrace/guest/linux-module/qemu-hypertrace.c create mode 100644 hypertrace/guest/user/Makefile create mode 100644 hypertrace/guest/user/common.c create mode 100644 hypertrace/guest/user/qemu-hypertrace.h create mode 100644 hypertrace/softmmu.c create mode 100644 hypertrace/user.c create mode 100644 hypertrace/user.h To: qemu-devel@nongnu.org Cc: Stefan Hajnoczi <stefanha@redhat.com> Cc: Eric Blake <eblake@redhat.com> Cc: Luiz Capitulino <lcapitulino@redhat.com> Cc: Daniel P Berrange <berrange@redhat.com> ^ permalink raw reply [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v2 1/6] hypertrace: Add documentation 2016-09-05 18:56 [Qemu-devel] [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel Lluís Vilanova @ 2016-09-05 18:56 ` Lluís Vilanova 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 2/6] hypertrace: Add tracing event "guest_hypertrace" Lluís Vilanova ` (5 subsequent siblings) 6 siblings, 0 replies; 14+ messages in thread From: Lluís Vilanova @ 2016-09-05 18:56 UTC (permalink / raw) To: qemu-devel Cc: Daniel P Berrange, Luiz Capitulino, Eric Blake, Stefan Hajnoczi Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> --- docs/hypertrace.txt | 227 +++++++++++++++++++++++++++++++++++++++++++++++++++ docs/tracing.txt | 3 + 2 files changed, 230 insertions(+) create mode 100644 docs/hypertrace.txt diff --git a/docs/hypertrace.txt b/docs/hypertrace.txt new file mode 100644 index 0000000..f061036 --- /dev/null +++ b/docs/hypertrace.txt @@ -0,0 +1,227 @@ += Hypertrace channel = + +Copyright (C) 2016 Lluís Vilanova <vilanova@ac.upc.edu> + +This work is licensed under the terms of the GNU GPL, version 2 or later. +See the COPYING file in the top-level directory. + + +The hypertrace channel allows guest code to emit events in QEMU (the host) using +its tracing infrastructure (see "docs/trace.txt"). This works in both 'system' +and 'user' modes. Therefore, hypertrace is to tracing what hypercalls are to +system calls. + +The hypertrace channel can be used for various purposes: + +* The example below shows how to use this on your guest applications to identify + regions of interest where you want to selectively enable certain tracing + events, without paying the price of tracing them outside the interest + regions. + +* You can also invoke hypertrace in your guest code to time the performance of + new TCG optimizations. Each hypertrace event comes with a host timestamp, + making it easy to compare execution times of interesting guest code regions. + +* Calls to hypertrace can also be added along traces generated in the guest to + more easily correlate and merge guest and host traces. + +Hypertrace highlights: + +* Works with 'system' and 'user' mode. + +* Minimal setup for the guest; QEMU provides support guest code libraries to + make 'system' mode with Linux and 'user' mode work out of the box. + +* Independent of guest architecture; the guest code uses accesses to special + memory regions, as opposed to redefining instruction semantics. + +* Negligible guest overhead; emitting a hypertrace event requires a single guest + memory access, making it as unobtrusive as possible. + +Warning: The hypertrace channel in 'system' mode is presented as a PCI device, +and thus will only be available on systems with support for PCI. You can get the +list of guests with PCI support with 'grep pci.mak default-configs/*'. + + +== Quick guide == + +This shows an example of using the hypertrace channel to trace events only in a +region of the guest code, which is identified by calls to the hypertrace +channel. + +We are going to trace memory accesses to disk using QEMU's "log" backend, and +will use QEMU's "dtrace" (SystemTap) backend to control when we want to trace +them. Tracing is done with "log" because it is more efficient than using +"dtrace" in high-volume events like memory accesses. The first time the guest +code invokes the hypertrace channel, we will start tracing the +"guest_mem_before_exec" event, and then will disable it the second time around. + +1. Set the tracing backends and number of arguments for the hypertrace events: + + mkdir /tmp/qemu-build + cd /tmp/qemu-build + /path/to/qemu-source/configure \ + --enable-trace-backends=dtrace,log \ + --with-hypertrace-args=1 \ + --prefix=/tmp/qemu-install + make -j install + +2. Enable the "guest_mem_before_exec" event: + + sed -i -e 's/disable vcpu tcg guest_mem_before/vcpu tcg guest_mem_before/g' /path/to/qemu-source/trace-events + +3. Compile the guest support code: + + make -C /tmp/qemu-build/x86_64-linux-user/hypertrace/guest/user + make -C /tmp/qemu-build/x86_64-softmmu/hypertrace/guest/user + make -C /tmp/qemu-build/x86_64-softmmu/hypertrace/guest/linux-module + + If you need to cross-compile the guest library, set the 'CC' variable: + + make -C /tmp/qemu-build/mipsel-linux-user/hypertrace/guest/user CC=mipsel-gnu-linux-gcc + +3. Create a guest application using "qemu-hypertrace.h" to interact with the + hypertrace channel: + + cat > /tmp/my-hypertrace.c <<\EOF + #include <stdio.h> + #include <errno.h> + #include <stdlib.h> + #include <string.h> + #include <qemu-hypertrace.h> + + + int main(int argc, char **argv) + { + char *base = NULL; + if (argc > 1) { + base = argv[1]; + } + + /* In 'user' mode this path must be the same we will use to start QEMU. */ + if (qemu_hypertrace_init(base) != 0) { + perror("error: qemu_hypertrace_init"); + abort(); + } + + /* Set additional event arguments */ + uint64_t client = 0; + uint64_t *data = qemu_hypertrace_data(client); + data[0] = 0xbabe; + data[1] = 0xdead; + data[2] = 0xbeef; + + /* Emit 1st event */ + qemu_hypertrace(client, 0xcafe); + + /* Computation in between */ + printf("Some computation...\n"); + + /* Emit 2nd event */ + qemu_hypertrace(client, 0xcafe); + } + EOF + + gcc -o /tmp/my-hypertrace-user /tmp/my-hypertrace.c \ + /tmp/qemu-build/x86_64-linux-user/hypertrace/guest/user/libqemu-hypertrace-guest.a \ + -I/tmp/qemu-install/include -lpthread + + gcc -o /tmp/my-hypertrace-softmmu /tmp/my-hypertrace.c \ + /tmp/qemu-build/x86_64-softmmu/hypertrace/guest/user/libqemu-hypertrace-guest.a \ + -I/tmp/qemu-install/include -lpthread + +4. Create a SystemTap script to control event tracing: + + cat > /tmp/my-hypertrace-script.stp <<\EOF + #!/usr/bin/env stap + + global hypercount + + %{ + #include <linux/delay.h> + %} + + function enable_mem:long() + %{ + char *argv[4] = {"/bin/sh", "-c", "echo 'trace-event guest_mem_before_exec on' | telnet localhost 1234", NULL}; + printk(KERN_ERR "enable\n"); + call_usermodehelper(argv[0], argv, NULL, UMH_WAIT_EXEC); + /* Wait for changes to apply */ + msleep(1000); + printk(KERN_ERR "enabled\n"); + STAP_RETURN(0); + %} + + function disable_mem:long() + %{ + char *argv[4] = {"/bin/sh", "-c", "echo 'trace-event guest_mem_before_exec off' | telnet localhost 1234", NULL}; + printk(KERN_ERR "disable\n"); + call_usermodehelper(argv[0], argv, NULL, UMH_WAIT_EXEC); + msleep(1000); + printk(KERN_ERR "disabled\n"); + STAP_RETURN(0); + %} + + probe process("./install/vanilla/bin/qemu-*").mark("guest_hypertrace") + { + hypercount++ + printf("guest_hypertrace: %x\n", $arg1) + if (hypercount == 1) { + enable_mem() + } else if (hypercount == 2) { + disable_mem() + exit() + } + } + EOF + +4. Run a guest system with access to QEMU's hypertrace: + + stap -g /tmp/my-hypertrace-script.stp + /tmp/qemu-install/x86_64-softmmu/qemu-system-x86_64 \ + -device hypertrace \ + -monitor tcp:localhost:1234,server,nowait \ + -trace enable=guest_hypertrace -D /dev/stdout \ + ...' + + And inside the VM: + + sudo /tmp/my-hypertrace-softmmu + + The result will be something like this: + + VNC server running on ::1:5900 + 23071@1473096085.744211:guest_hypertrace cpu=0x5602e1f49c10 arg1=0x000000000000cafe arg2=0x000000000000babe arg3=0x000000000000dead arg4=0x000000000000beef + 23071@1473096085.745763:guest_mem_before_trans cpu=0x5602e1f49c10 info=19 + 23071@1473096085.745907:guest_mem_before_trans cpu=0x5602e1f49c10 info=3 + 23071@1473096085.752368:guest_mem_before_trans cpu=0x5602e1f49c10 info=3 + 23071@1473096085.752384:guest_mem_before_trans cpu=0x5602e1f49c10 info=19 + 23071@1473096086.756117:guest_hypertrace cpu=0x5602e1f49c10 arg1=0x000000000000cafe arg2=0x000000000000babe arg3=0x000000000000dead arg4=0x000000000000beef + +Similarly, you can enable hypertrace when running standalone guest applications: + + /tmp/qemu-install/bin/qemu-x86_64 \ + -hypertrace /tmp/hypertrace \ + -trace enable=guest* -D /dev/stdout \ + /tmp/my-hypertrace-user /tmp/hypertrace + +You can also use hypertrace inside the Linux's kernel code with the provided +guest module (see "/tmp/qemu-install/include/linux/qemu-hypertrace.h"): + + sudo insmod /tmp/qemu-build/x86_64-softmmu/hypertrace/guest/linux-module/qemu-hypertrace.ko + + +== Details == + +To make it more efficient in terms of guest and host time, hypertrace provides +two different memory areas (channels). + +The control channel is used by the guest to tell QEMU that new data is ready to +be processed in the data channel. Writes to the control channel are intercepted +by QEMU, which emits the "hypertrace" tracing event. + +The data channel is a regular memory buffer used by the guest to write +additional event arguments before raising the event through the control channel. + +Both channels accept different "per-client offsets" to enable multiple guest +threads or CPUs to use the hypertrace channel without having to synchronize. diff --git a/docs/tracing.txt b/docs/tracing.txt index 29f2f9a..f312596 100644 --- a/docs/tracing.txt +++ b/docs/tracing.txt @@ -5,6 +5,9 @@ This document describes the tracing infrastructure in QEMU and how to use it for debugging, profiling, and observing execution. +See "docs/hypertrace.txt" to correlate guest tracing events with those in the +QEMU host. + == Quickstart == 1. Build with the 'simple' trace backend: ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v2 2/6] hypertrace: Add tracing event "guest_hypertrace" 2016-09-05 18:56 [Qemu-devel] [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel Lluís Vilanova 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 1/6] hypertrace: Add documentation Lluís Vilanova @ 2016-09-05 18:56 ` Lluís Vilanova 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 3/6] hypertrace: [*-user] Add QEMU-side proxy to "guest_hypertrace" event Lluís Vilanova ` (4 subsequent siblings) 6 siblings, 0 replies; 14+ messages in thread From: Lluís Vilanova @ 2016-09-05 18:56 UTC (permalink / raw) To: qemu-devel Cc: Daniel P Berrange, Luiz Capitulino, Eric Blake, Stefan Hajnoczi Generates the "guest_hypertrace" event with a user-configurable number of arguments. Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> --- Makefile.objs | 2 ++ configure | 34 ++++++++++++++++++++++++++++++++++ trace/Makefile.objs | 2 +- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/Makefile.objs b/Makefile.objs index 6d5ddcf..3db04b9 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -159,3 +159,5 @@ trace-events-y += target-s390x/trace-events trace-events-y += target-ppc/trace-events trace-events-y += qom/trace-events trace-events-y += linux-user/trace-events + +trace-events-gen-y = hypertrace/trace-events diff --git a/configure b/configure index 4b808f9..d7ec31f 100755 --- a/configure +++ b/configure @@ -273,6 +273,7 @@ pie="" qom_cast_debug="yes" trace_backends="log" trace_file="trace" +hypertrace="1" spice="" rbd="" smartcard="" @@ -782,6 +783,8 @@ for opt do ;; --with-trace-file=*) trace_file="$optarg" ;; + --with-hypertrace-args=*) hypertrace="$optarg" + ;; --enable-gprof) gprof="yes" ;; --enable-gcov) gcov="yes" @@ -1300,6 +1303,8 @@ Advanced options (experts only): Available backends: $($python $source_path/scripts/tracetool.py --list-backends) --with-trace-file=NAME Full PATH,NAME of file to store traces Default:trace-<pid> + --with-hypertrace-args=NUMBER + number of hypertrace arguments (default: $hypertrace) --disable-slirp disable SLIRP userspace network connectivity --enable-tcg-interpreter enable TCG with bytecode interpreter (TCI) --oss-lib path to OSS library @@ -4201,6 +4206,16 @@ if test "$?" -ne 0 ; then fi ########################################## +# check hypertrace arguments +case "$hypertrace" in + ''|*[!0-9]*) error_exit "invalid number of hypertrace arguments" ;; + *) ;; +esac +if test $hypertrace = 0; then + error_exit "hypertrace arguments must be greater than zero" +fi + +########################################## # For 'ust' backend, test if ust headers are present if have_backend "ust"; then cat > $TMPC << EOF @@ -4875,6 +4890,7 @@ echo "Trace backends $trace_backends" if have_backend "simple"; then echo "Trace output file $trace_file-<pid>" fi +echo "Hypertrace arguments $hypertrace" echo "spice support $spice $(echo_version $spice $spice_protocol_version/$spice_server_version)" echo "rbd support $rbd" echo "xfsctl support $xfs" @@ -5503,6 +5519,24 @@ else fi QEMU_INCLUDES="-I\$(SRC_PATH)/tcg $QEMU_INCLUDES" +# hypertrace +echo "CONFIG_HYPERTRACE_ARGS=$hypertrace" >> $config_host_mak +hypertrace_events=hypertrace/trace-events +mkdir -p $(dirname $hypertrace_events) +echo "# See docs/trace-events.txt for syntax documentation." >$hypertrace_events +echo -n 'vcpu guest_hypertrace(' >>$hypertrace_events +for i in `seq $hypertrace`; do + if test $i != 1; then + echo -n ", " >>$hypertrace_events + fi + echo -n "uint64_t arg$i" >>$hypertrace_events +done +echo -n ') ' >>$hypertrace_events +for i in `seq $hypertrace`; do + echo -n "\" arg$i=0x%016\"PRIx64" >>$hypertrace_events +done +echo >>$hypertrace_events + echo "TOOLS=$tools" >> $config_host_mak echo "ROMS=$roms" >> $config_host_mak echo "MAKE=$make" >> $config_host_mak diff --git a/trace/Makefile.objs b/trace/Makefile.objs index 4d91b3b..b71ec54 100644 --- a/trace/Makefile.objs +++ b/trace/Makefile.objs @@ -8,7 +8,7 @@ tracetool-y = $(SRC_PATH)/scripts/tracetool.py tracetool-y += $(shell find $(SRC_PATH)/scripts/tracetool -name "*.py") -$(BUILD_DIR)/trace-events-all: $(trace-events-y:%=$(SRC_PATH)/%) +$(BUILD_DIR)/trace-events-all: $(trace-events-y:%=$(SRC_PATH)/%) $(trace-events-gen-y:%=$(BUILD_DIR)/%) $(call quiet-command,cat $^ > $@) ###################################################################### ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v2 3/6] hypertrace: [*-user] Add QEMU-side proxy to "guest_hypertrace" event 2016-09-05 18:56 [Qemu-devel] [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel Lluís Vilanova 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 1/6] hypertrace: Add documentation Lluís Vilanova 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 2/6] hypertrace: Add tracing event "guest_hypertrace" Lluís Vilanova @ 2016-09-05 18:56 ` Lluís Vilanova 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 4/6] hypertrace: [softmmu] " Lluís Vilanova ` (3 subsequent siblings) 6 siblings, 0 replies; 14+ messages in thread From: Lluís Vilanova @ 2016-09-05 18:56 UTC (permalink / raw) To: qemu-devel Cc: Daniel P Berrange, Luiz Capitulino, Eric Blake, Stefan Hajnoczi, Riku Voipio QEMU detects when the guest uses 'mmap' on hypertrace's control channel file, and then uses 'mprotect' to detect accesses to it, which are used to trigger tracing event "guest_hypertrace". Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> --- Makefile.objs | 4 + bsd-user/main.c | 16 ++ bsd-user/mmap.c | 15 ++ bsd-user/syscall.c | 31 +++- hypertrace/Makefile.objs | 18 ++ hypertrace/common.c | 26 ++++ hypertrace/common.h | 24 +++ hypertrace/user.c | 339 ++++++++++++++++++++++++++++++++++++++++++++++ hypertrace/user.h | 61 ++++++++ include/qom/cpu.h | 4 + linux-user/main.c | 19 +++ linux-user/mmap.c | 17 ++ linux-user/qemu.h | 3 linux-user/syscall.c | 31 +++- 14 files changed, 583 insertions(+), 25 deletions(-) create mode 100644 hypertrace/Makefile.objs create mode 100644 hypertrace/common.c create mode 100644 hypertrace/common.h create mode 100644 hypertrace/user.c create mode 100644 hypertrace/user.h diff --git a/Makefile.objs b/Makefile.objs index 3db04b9..56b41c7 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -104,6 +104,10 @@ util-obj-y += trace/ target-obj-y += trace/ ###################################################################### +# hypertrace +target-obj-y += hypertrace/ + +###################################################################### # guest agent # FIXME: a few definitions from qapi-types.o/qapi-visit.o are needed diff --git a/bsd-user/main.c b/bsd-user/main.c index 0fb08e4..0d0a850 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -31,9 +31,12 @@ #include "tcg.h" #include "qemu/timer.h" #include "qemu/envlist.h" +#include "qemu/error-report.h" #include "exec/log.h" #include "trace/control.h" #include "glib-compat.h" +#include "hypertrace/user.h" + int singlestep; unsigned long mmap_min_addr; @@ -694,6 +697,8 @@ static void usage(void) "-strace log system calls\n" "-trace [[enable=]<pattern>][,events=<file>][,file=<file>]\n" " specify tracing options\n" + "-hypertrace [[base=]<path>][,max-clients=<uint>]\n" + " specify hypertrace options\n" "\n" "Environment variables:\n" "QEMU_STRACE Print system calls and arguments similar to the\n" @@ -744,6 +749,8 @@ int main(int argc, char **argv) envlist_t *envlist = NULL; char *trace_file = NULL; bsd_type = target_openbsd; + char *hypertrace_base = NULL; + unsigned int hypertrace_max_clients = 0; if (argc <= 1) usage(); @@ -763,6 +770,7 @@ int main(int argc, char **argv) cpu_model = NULL; qemu_add_opts(&qemu_trace_opts); + qemu_add_opts(&qemu_hypertrace_opts); optind = 1; for (;;) { @@ -853,6 +861,9 @@ int main(int argc, char **argv) } else if (!strcmp(r, "trace")) { g_free(trace_file); trace_file = trace_opt_parse(optarg); + } else if (!strcmp(r, "hypertrace")) { + g_free(hypertrace_file); + hypertrace_opt_parse(optarg, &hypertrace_base, &hypertrace_max_clients); } else { usage(); } @@ -987,6 +998,11 @@ int main(int argc, char **argv) target_set_brk(info->brk); syscall_init(); signal_init(); + if (atexit(hypertrace_fini) != 0) { + fprintf(stderr, "error: atexit: %s\n", strerror(errno)); + abort(); + } + hypertrace_init(hypertrace_base, hypertrace_size); /* Now that we've loaded the binary, GUEST_BASE is fixed. Delay generating the prologue until now so that the prologue can take diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c index 610f91b..d8ffc1e 100644 --- a/bsd-user/mmap.c +++ b/bsd-user/mmap.c @@ -21,6 +21,7 @@ #include "qemu.h" #include "qemu-common.h" #include "bsd-mman.h" +#include "hypertrace/user.h" //#define DEBUG_MMAP @@ -251,10 +252,17 @@ static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) return addr; } -/* NOTE: all the constants are the HOST ones */ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, int flags, int fd, abi_ulong offset) { + return target_mmap_cpu(start, len, prot, flags, fd, offset, NULL); +} + +/* NOTE: all the constants are the HOST ones */ +abi_long target_mmap_cpu(abi_ulong start, abi_ulong len, int prot, + int flags, int fd, abi_ulong offset, + CPUState *cpu) +{ abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; unsigned long host_start; @@ -296,6 +304,10 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, goto the_end; real_start = start & qemu_host_page_mask; + if (!hypertrace_guest_mmap_check(fd, len, offset)) { + goto fail; + } + if (!(flags & MAP_FIXED)) { abi_ulong mmap_start; void *p; @@ -407,6 +419,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, } } the_end1: + hypertrace_guest_mmap_apply(fd, g2h(start), cpu); page_set_flags(start, start + len, prot | PAGE_VALID); the_end: #ifdef DEBUG_MMAP diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c index 66492aa..d354e7f 100644 --- a/bsd-user/syscall.c +++ b/bsd-user/syscall.c @@ -26,6 +26,7 @@ #include "qemu.h" #include "qemu-common.h" +#include "hypertrace/user.h" //#define DEBUG @@ -332,6 +333,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, _mcleanup(); #endif gdb_exit(cpu_env, arg1); + hypertrace_fini(); /* XXX: should free thread stack and CPU env */ _exit(arg1); ret = 0; /* avoid warning */ @@ -369,10 +371,11 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(p, arg1, 0); break; case TARGET_FREEBSD_NR_mmap: - ret = get_errno(target_mmap(arg1, arg2, arg3, - target_to_host_bitmask(arg4, mmap_flags_tbl), - arg5, - arg6)); + ret = get_errno(target_mmap_cpu(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), + arg5, + arg6, + cpu)); break; case TARGET_FREEBSD_NR_mprotect: ret = get_errno(target_mprotect(arg1, arg2, arg3)); @@ -430,6 +433,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1, _mcleanup(); #endif gdb_exit(cpu_env, arg1); + hypertrace_fini(); /* XXX: should free thread stack and CPU env */ _exit(arg1); ret = 0; /* avoid warning */ @@ -455,10 +459,11 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(p, arg1, 0); break; case TARGET_NETBSD_NR_mmap: - ret = get_errno(target_mmap(arg1, arg2, arg3, - target_to_host_bitmask(arg4, mmap_flags_tbl), - arg5, - arg6)); + ret = get_errno(target_mmap_cpu(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), + arg5, + arg6, + cpu)); break; case TARGET_NETBSD_NR_mprotect: ret = get_errno(target_mprotect(arg1, arg2, arg3)); @@ -505,6 +510,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1, _mcleanup(); #endif gdb_exit(cpu_env, arg1); + hypertrace_fini(); /* XXX: should free thread stack and CPU env */ _exit(arg1); ret = 0; /* avoid warning */ @@ -530,10 +536,11 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(p, arg1, 0); break; case TARGET_OPENBSD_NR_mmap: - ret = get_errno(target_mmap(arg1, arg2, arg3, - target_to_host_bitmask(arg4, mmap_flags_tbl), - arg5, - arg6)); + ret = get_errno(target_mmap_cpu(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), + arg5, + arg6, + cpu)); break; case TARGET_OPENBSD_NR_mprotect: ret = get_errno(target_mprotect(arg1, arg2, arg3)); diff --git a/hypertrace/Makefile.objs b/hypertrace/Makefile.objs new file mode 100644 index 0000000..24e8fb4 --- /dev/null +++ b/hypertrace/Makefile.objs @@ -0,0 +1,18 @@ +# -*- mode: makefile -*- + +target-obj-$(CONFIG_USER_ONLY) += user.o +target-obj-y += common.o + +$(obj)/user.o: $(obj)/emit.c + +$(obj)/emit.c: $(obj)/emit.c-timestamp $(BUILD_DIR)/config-host.mak + @cmp $< $@ >/dev/null 2>&1 || cp $< $@ +$(obj)/emit.c-timestamp: $(BUILD_DIR)/config-host.mak + @echo "static void hypertrace_emit(CPUState *cpu, uint64_t arg1, uint64_t *data)" >$@ + @echo "{" >>$@ + @echo -n " trace_guest_hypertrace(cpu, arg1" >>$@ + @for i in `seq $$(( $(CONFIG_HYPERTRACE_ARGS) - 1 ))`; do \ + echo -n ", data[$$i-1]" >>$@; \ + done + @echo ");" >>$@ + @echo "}" >>$@ diff --git a/hypertrace/common.c b/hypertrace/common.c new file mode 100644 index 0000000..baca098 --- /dev/null +++ b/hypertrace/common.c @@ -0,0 +1,26 @@ +/* + * QEMU-side management of hypertrace in user-level emulation. + * + * Copyright (C) 2016 Lluís Vilanova <vilanova@ac.upc.edu> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "cpu.h" +#include "hypertrace/common.h" +#include "qemu/osdep.h" + +void hypertrace_init_config(struct hypertrace_config *config, + unsigned int max_clients) +{ + config->max_clients = max_clients; + config->client_args = CONFIG_HYPERTRACE_ARGS; + config->client_data_size = config->client_args * sizeof(uint64_t); + config->control_size = QEMU_ALIGN_UP( + config->max_clients * sizeof(uint64_t), TARGET_PAGE_SIZE); + config->data_size = QEMU_ALIGN_UP( + config->max_clients * config->client_data_size, TARGET_PAGE_SIZE); +} diff --git a/hypertrace/common.h b/hypertrace/common.h new file mode 100644 index 0000000..dfce161 --- /dev/null +++ b/hypertrace/common.h @@ -0,0 +1,24 @@ +/* + * QEMU-side management of hypertrace in user-level emulation. + * + * Copyright (C) 2016 Lluís Vilanova <vilanova@ac.upc.edu> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#if !defined(__KERNEL__) +#include <stdint.h> +#endif + +struct hypertrace_config +{ + uint64_t max_clients; + uint64_t client_args; + uint64_t client_data_size; + uint64_t control_size; + uint64_t data_size; +}; + +void hypertrace_init_config(struct hypertrace_config *config, + unsigned int max_clients); diff --git a/hypertrace/user.c b/hypertrace/user.c new file mode 100644 index 0000000..0e07283 --- /dev/null +++ b/hypertrace/user.c @@ -0,0 +1,339 @@ +/* + * QEMU-side management of hypertrace in user-level emulation. + * + * Copyright (C) 2016 Lluís Vilanova <vilanova@ac.upc.edu> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +/* + * Implementation details + * ====================== + * + * There are 3 channels, each a regular file in the host system, and mmap'ed by + * the guest application. + * + * - Configuration channel: Exposes configuration parameters. Mapped once and + * directly readable. + * + * - Data channel: Lets guests write argument values. Each guest thread should + * use a different offset to avoid concurrency problems. Mapped once and + * directly accessible. + * + * - Control channel: Triggers the hypertrace event on a write, providing the + * first argument. Offset in the control channel sets the offset in the data + * channel. Mapped once per thread, using two pages to reliably detect + * accesses and their written value through a SEGV handler. + */ + +#include <assert.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <sys/mman.h> + +#include "qemu/osdep.h" +#include "cpu.h" + +#include "hypertrace/common.h" +#include "hypertrace/user.h" +#include "qemu/config-file.h" +#include "qemu/error-report.h" +#include "trace.h" + + +static struct hypertrace_config config; +static char *config_path = NULL; +static int config_fd = -1; +static uint64_t *qemu_config = NULL; + +static char *data_path = NULL; +static int data_fd = -1; +static uint64_t *qemu_data = NULL; + +static char *control_path = NULL; +static int control_fd = -1; +static uint64_t *qemu_control = NULL; +static struct stat control_fd_stat; + +struct sigaction segv_next; +static void segv_handler(int signum, siginfo_t *siginfo, void *sigctxt); + + +QemuOptsList qemu_hypertrace_opts = { + .name = "hypertrace", + .implied_opt_name = "path", + .head = QTAILQ_HEAD_INITIALIZER(qemu_hypertrace_opts.head), + .desc = { + { + .name = "path", + .type = QEMU_OPT_STRING, + }, + { + .name = "max-clients", + .type = QEMU_OPT_NUMBER, + .def_value_str = "1", + }, + { /* end of list */ } + }, +}; + +void hypertrace_opt_parse(const char *optarg, char **base, unsigned int *max_clients_) +{ + int max_clients; + QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("hypertrace"), + optarg, true); + if (!opts) { + exit(1); + } + if (qemu_opt_get(opts, "path")) { + *base = g_strdup(qemu_opt_get(opts, "path")); + } else { + *base = NULL; + } + max_clients = qemu_opt_get_number(opts, "pages", 1); + if (max_clients <= 0) { + error_report("Parameter 'max-clients' expects a positive number"); + exit(EXIT_FAILURE); + } + *max_clients_ = max_clients; +} + +static void init_channel(const char *base, const char *suffix, size_t size, + char ** path, int *fd, uint64_t **addr) +{ + *path = g_malloc(strlen(base) + strlen(suffix) + 1); + sprintf(*path, "%s%s", base, suffix); + + *fd = open(*path, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR); + if (*fd == -1) { + error_report("error: open(%s): %s", *path, strerror(errno)); + abort(); + } + + off_t lres = lseek(*fd, size - 1, SEEK_SET); + if (lres == (off_t)-1) { + error_report("error: lseek(%s): %s", *path, strerror(errno)); + abort(); + } + + char tmp; + ssize_t wres = write(*fd, &tmp, 1); + if (wres == -1) { + error_report("error: write(%s): %s", *path, strerror(errno)); + abort(); + } + + if (addr) { + *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0); + if (*addr == MAP_FAILED) { + error_report("error: mmap(%s): %s", *path, strerror(errno)); + abort(); + } + } +} + +static void fini_handler(int signum, siginfo_t *siginfo, void *sigctxt) +{ + hypertrace_fini(); +} + +void hypertrace_init(const char *base, unsigned int max_clients) +{ + struct sigaction sigint; + struct hypertrace_config *pconfig; + + if (base == NULL) { + return; + } + + memset(&sigint, 0, sizeof(sigint)); + sigint.sa_sigaction = fini_handler; + sigint.sa_flags = SA_SIGINFO | SA_RESTART; + if (sigaction(SIGINT, &sigint, NULL) != 0) { + error_report("error: sigaction(SIGINT): %s", strerror(errno)); + abort(); + } + if (sigaction(SIGABRT, &sigint, NULL) != 0) { + error_report("error: sigaction(SIGABRT): %s", strerror(errno)); + abort(); + } + + hypertrace_init_config(&config, max_clients); + /* We need twice the space for the double-fault protocol */ + config.control_size *= 2; + + init_channel(base, "-config", TARGET_PAGE_SIZE, &config_path, &config_fd, &qemu_config); + pconfig = (struct hypertrace_config*)qemu_config; + pconfig->max_clients = tswap64(config.max_clients); + pconfig->client_args = tswap64(config.client_args); + pconfig->client_data_size = tswap64(config.client_data_size); + pconfig->control_size = tswap64(config.control_size); + pconfig->data_size = tswap64(config.data_size); + + init_channel(base, "-data", config.data_size, &data_path, &data_fd, &qemu_data); + if (fstat(data_fd, &control_fd_stat) == -1) { + error_report("error: fstat(hypertrace_control): %s", strerror(errno)); + abort(); + } + printf("data: dev=%ld ino=%ld ptr=%p\n", + control_fd_stat.st_dev, control_fd_stat.st_ino, qemu_data); + + init_channel(base, "-control", config.control_size, &control_path, &control_fd, &qemu_control); + + if (fstat(control_fd, &control_fd_stat) == -1) { + error_report("error: fstat(hypertrace_control): %s", strerror(errno)); + abort(); + } + printf("control: dev=%ld ino=%ld ptr=%p\n", + control_fd_stat.st_dev, control_fd_stat.st_ino, qemu_control); + + struct sigaction segv; + memset(&segv, 0, sizeof(segv)); + segv.sa_sigaction = segv_handler; + segv.sa_flags = SA_SIGINFO | SA_RESTART; + sigemptyset(&segv.sa_mask); + + if (sigaction(SIGSEGV, &segv, &segv_next) != 0) { + error_report("error: sigaction(SIGSEGV): %s", strerror(errno)); + abort(); + } +} + + +static void fini_channel(int *fd, char **path) +{ + if (*fd != -1) { + if (close(*fd) == -1) { + error_report("error: close: %s", strerror(errno)); + abort(); + } + if (unlink(*path) == -1) { + error_report("error: unlink(%s): %s", *path, strerror(errno)); + abort(); + } + *fd = -1; + } + if (*path != NULL) { + g_free(*path); + *path = NULL; + } +} + +void hypertrace_fini(void) +{ + static bool atexit_in = false; + if (atexit_in) { + return; + } + atexit_in = true; + + if (sigaction(SIGSEGV, &segv_next, NULL) != 0) { + error_report("error: sigaction(SIGSEGV): %s", strerror(errno)); + abort(); + } + fini_channel(&config_fd, &config_path); + fini_channel(&data_fd, &data_path); + fini_channel(&control_fd, &control_path); +} + + +bool hypertrace_guest_mmap_check(int fd, unsigned long len, unsigned long offset) +{ + struct stat s; + if (fstat(fd, &s) < 0) { + return true; + } + + if (s.st_dev != control_fd_stat.st_dev || + s.st_ino != control_fd_stat.st_ino) { + return true; + } + + return len == (config.control_size) && offset == 0; +} + +void hypertrace_guest_mmap_apply(int fd, void *qemu_addr, CPUState *vcpu) +{ + struct stat s; + + if (vcpu == NULL) { + return; + } + + if (fstat(fd, &s) != 0) { + return; + } + + if (s.st_dev != control_fd_stat.st_dev || + s.st_ino != control_fd_stat.st_ino) { + return; + } + + /* it's an mmap of the control channel; split it in two and mprotect it to + * detect writes (cmd is written once on each part) + */ + printf("cpu->hypertrace_control=%p %lu %lu\n", qemu_addr, s.st_dev, s.st_ino); + vcpu->hypertrace_control = qemu_addr; + if (mprotect(vcpu->hypertrace_control, config.control_size / 2, PROT_READ) == -1) { + error_report("error: mprotect(hypertrace_control): %s", strerror(errno)); + abort(); + } +} + +static void swap_control(void *from, void *to) +{ + printf("mprotect: RW %p %lu\n", from, config.control_size / 2); + if (mprotect(from, config.control_size / 2, PROT_READ | PROT_WRITE) == -1) { + error_report("error: mprotect(from): %s", strerror(errno)); + abort(); + } + printf("mprotect: R %p %lu\n", to, config.control_size / 2); + if (mprotect(to, config.control_size / 2, PROT_READ) == -1) { + error_report("error: mprotect(to): %s", strerror(errno)); + abort(); + } +} + +#include "hypertrace/emit.c" + +static void segv_handler(int signum, siginfo_t *siginfo, void *sigctxt) +{ + CPUState *vcpu = current_cpu; + void *control_0 = vcpu->hypertrace_control; + void *control_1 = vcpu->hypertrace_control + config.control_size / 2; + void *control_2 = control_1 + config.control_size / 2; + + if (control_0 <= siginfo->si_addr && siginfo->si_addr < control_1) { + + /* 1st fault (guest will write cmd) */ + printf("SEGV 1\n"); + assert(((unsigned long)siginfo->si_addr % sizeof(uint64_t)) == 0); + swap_control(control_0, control_1); + printf("SEGV 1!\n"); + + } else if (control_1 <= siginfo->si_addr && siginfo->si_addr < control_2) { + size_t client = (siginfo->si_addr - control_1) / sizeof(uint64_t); + uint64_t vcontrol = ((uint64_t*)control_0)[client]; + uint64_t *data_ptr = &qemu_data[client * config.client_data_size]; + + /* 2nd fault (invoke) */ + printf("SEGV 2\n"); + assert(((unsigned long)siginfo->si_addr % sizeof(uint64_t)) == 0); + hypertrace_emit(current_cpu, vcontrol, data_ptr); + swap_control(control_1, control_0); + printf("SEGV 2!\n"); + + } else { + /* proxy to next handler */ + printf("SEGV ?\n"); + if (segv_next.sa_sigaction != NULL) { + segv_next.sa_sigaction(signum, siginfo, sigctxt); + } else if (segv_next.sa_handler != NULL) { + segv_next.sa_handler(signum); + } + printf("SEGV ?!\n"); + } +} diff --git a/hypertrace/user.h b/hypertrace/user.h new file mode 100644 index 0000000..9c1f44b --- /dev/null +++ b/hypertrace/user.h @@ -0,0 +1,61 @@ +/* + * QEMU-side management of hypertrace in user-level emulation. + * + * Copyright (C) 2016 Lluís Vilanova <vilanova@ac.upc.edu> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <stdint.h> +#include <sys/types.h> + + +/** + * Definition of QEMU options describing hypertrace subsystem configuration + */ +extern QemuOptsList qemu_hypertrace_opts; + +/** + * hypertrace_opt_parse: + * @optarg: Input arguments. + * @base: Output base path for the hypertrace channel files. + * @max_clients: Output maximum number of concurrent clients. + * + * Parse the commandline arguments for hypertrace. + */ +void hypertrace_opt_parse(const char *optarg, char **base, unsigned int *max_clients); + +/** + * hypertrace_init: + * @base: Base path for the hypertrace channel files. + * @max_clients: Maximum number of concurrent clients. + * + * Initialize the backing files for the hypertrace channel. + */ +void hypertrace_init(const char *base, unsigned int max_clients); + +/** + * hypertrace_guest_mmap_check: + * + * Verify argument validity when mapping the control channel. + * + * Precondition: defined(CONFIG_USER_ONLY) + */ +bool hypertrace_guest_mmap_check(int fd, unsigned long len, unsigned long offset); + +/** + * hypertrace_guest_mmap_apply: + * + * Configure initial mprotect if mapping the control channel. + * + * Precondition: defined(CONFIG_USER_ONLY) + */ +void hypertrace_guest_mmap_apply(int fd, void *qemu_addr, CPUState *vcpu); + +/** + * hypertrace_fini: + * + * Remove the backing files for the hypertrace channel. + */ +void hypertrace_fini(void); diff --git a/include/qom/cpu.h b/include/qom/cpu.h index ce0c406..c83570a 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -283,6 +283,7 @@ struct qemu_work_item { * @work_mutex: Lock to prevent multiple access to queued_work_*. * @queued_work_first: First asynchronous work pending. * @trace_dstate: Dynamic tracing state of events for this vCPU (bitmask). + * @hypertrace_control: Per-vCPU address of the hypertrace control channel. * * State of one CPU core or thread. */ @@ -353,6 +354,9 @@ struct CPUState { /* Used for events with 'vcpu' and *without* the 'disabled' properties */ DECLARE_BITMAP(trace_dstate, TRACE_VCPU_EVENT_COUNT); + /* Only used when defined(CONFIG_USER_ONLY) */ + void *hypertrace_control; + /* TODO Move common fields from CPUArchState here. */ int cpu_index; /* used by alpha TCG */ uint32_t halted; /* used by alpha, cris, ppc TCG */ diff --git a/linux-user/main.c b/linux-user/main.c index f2f4d2f..5316a25 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -32,10 +32,12 @@ #include "tcg.h" #include "qemu/timer.h" #include "qemu/envlist.h" +#include "qemu/error-report.h" #include "elf.h" #include "exec/log.h" #include "trace/control.h" #include "glib-compat.h" +#include "hypertrace/user.h" char *exec_path; @@ -4011,6 +4013,14 @@ static void handle_arg_trace(const char *arg) trace_file = trace_opt_parse(arg); } +static char *hypertrace_base; +static unsigned int hypertrace_max_clients; +static void handle_arg_hypertrace(const char *arg) +{ + g_free(hypertrace_base); + hypertrace_opt_parse(arg, &hypertrace_base, &hypertrace_max_clients); +} + struct qemu_argument { const char *argv; const char *env; @@ -4060,6 +4070,8 @@ static const struct qemu_argument arg_table[] = { "", "Seed for pseudo-random number generator"}, {"trace", "QEMU_TRACE", true, handle_arg_trace, "", "[[enable=]<pattern>][,events=<file>][,file=<file>]"}, + {"hypertrace", "QEMU_HYPERTRACE", true, handle_arg_hypertrace, + "", "[[base=]<path>][,max-clients=<uint>]"}, {"version", "QEMU_VERSION", false, handle_arg_version, "", "display version information and exit"}, {NULL, NULL, false, NULL, NULL, NULL} @@ -4250,6 +4262,7 @@ int main(int argc, char **argv, char **envp) srand(time(NULL)); qemu_add_opts(&qemu_trace_opts); + qemu_add_opts(&qemu_hypertrace_opts); optind = parse_args(argc, argv); @@ -4448,6 +4461,12 @@ int main(int argc, char **argv, char **envp) syscall_init(); signal_init(); + if (atexit(hypertrace_fini)) { + fprintf(stderr, "error: atexit: %s\n", strerror(errno)); + abort(); + } + hypertrace_init(hypertrace_base, hypertrace_max_clients); + /* Now that we've loaded the binary, GUEST_BASE is fixed. Delay generating the prologue until now so that the prologue can take the real value of GUEST_BASE into account. */ diff --git a/linux-user/mmap.c b/linux-user/mmap.c index c4371d9..cfb159c 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -23,6 +23,7 @@ #include "qemu.h" #include "qemu-common.h" #include "translate-all.h" +#include "hypertrace/user.h" //#define DEBUG_MMAP @@ -357,10 +358,18 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) } } -/* NOTE: all the constants are the HOST ones */ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, int flags, int fd, abi_ulong offset) { + return target_mmap_cpu(start, len, prot, flags, fd, offset, NULL); +} + + +/* NOTE: all the constants are the HOST ones */ +abi_long target_mmap_cpu(abi_ulong start, abi_ulong len, int prot, + int flags, int fd, abi_ulong offset, + CPUState *cpu) +{ abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; mmap_lock(); @@ -442,6 +451,10 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, } } + if (!hypertrace_guest_mmap_check(fd, len, offset)) { + goto fail; + } + if (!(flags & MAP_FIXED)) { unsigned long host_start; void *p; @@ -553,6 +566,8 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, } } the_end1: + printf("mmap "TARGET_ABI_FMT_lx" "TARGET_ABI_FMT_lu"\n", start, len); + hypertrace_guest_mmap_apply(fd, g2h(start), cpu); page_set_flags(start, start + len, prot | PAGE_VALID); the_end: #ifdef DEBUG_MMAP diff --git a/linux-user/qemu.h b/linux-user/qemu.h index bef465d..968a6b4 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -411,6 +411,9 @@ void sparc64_get_context(CPUSPARCState *env); int target_mprotect(abi_ulong start, abi_ulong len, int prot); abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, int flags, int fd, abi_ulong offset); +abi_long target_mmap_cpu(abi_ulong start, abi_ulong len, int prot, + int flags, int fd, abi_ulong offset, + CPUState *cpu); int target_munmap(abi_ulong start, abi_ulong len); abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, abi_ulong new_size, unsigned long flags, diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ca06943..3e8d8fd 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -111,6 +111,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include "uname.h" #include "qemu.h" +#include "hypertrace/user.h" #define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \ CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID) @@ -7372,6 +7373,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, _mcleanup(); #endif gdb_exit(cpu_env, arg1); + hypertrace_fini(); _exit(arg1); ret = 0; /* avoid warning */ break; @@ -8824,15 +8826,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, v5 = tswapal(v[4]); v6 = tswapal(v[5]); unlock_user(v, arg1, 0); - ret = get_errno(target_mmap(v1, v2, v3, - target_to_host_bitmask(v4, mmap_flags_tbl), - v5, v6)); + ret = get_errno(target_mmap_cpu( + v1, v2, v3, + target_to_host_bitmask(v4, mmap_flags_tbl), + v5, v6, + cpu)); } #else - ret = get_errno(target_mmap(arg1, arg2, arg3, - target_to_host_bitmask(arg4, mmap_flags_tbl), - arg5, - arg6)); + ret = get_errno(target_mmap_cpu( + arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), + arg5, + arg6, + cpu)); #endif break; #endif @@ -8841,10 +8847,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifndef MMAP_SHIFT #define MMAP_SHIFT 12 #endif - ret = get_errno(target_mmap(arg1, arg2, arg3, - target_to_host_bitmask(arg4, mmap_flags_tbl), - arg5, - arg6 << MMAP_SHIFT)); + ret = get_errno(target_mmap_cpu( + arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), + arg5, + arg6 << MMAP_SHIFT, + cpu)); break; #endif case TARGET_NR_munmap: @@ -9377,6 +9385,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, _mcleanup(); #endif gdb_exit(cpu_env, arg1); + hypertrace_fini(); ret = get_errno(exit_group(arg1)); break; #endif ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v2 4/6] hypertrace: [softmmu] Add QEMU-side proxy to "guest_hypertrace" event 2016-09-05 18:56 [Qemu-devel] [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel Lluís Vilanova ` (2 preceding siblings ...) 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 3/6] hypertrace: [*-user] Add QEMU-side proxy to "guest_hypertrace" event Lluís Vilanova @ 2016-09-05 18:56 ` Lluís Vilanova 2016-09-06 1:43 ` Michael S. Tsirkin 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 5/6] hypertrace: Add guest-side user-level library Lluís Vilanova ` (2 subsequent siblings) 6 siblings, 1 reply; 14+ messages in thread From: Lluís Vilanova @ 2016-09-05 18:56 UTC (permalink / raw) To: qemu-devel Cc: Daniel P Berrange, Luiz Capitulino, Eric Blake, Stefan Hajnoczi, Michael S. Tsirkin, Marcel Apfelbaum Uses a virtual device to trigger the hypertrace channel event. Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> --- hypertrace/Makefile.objs | 5 + hypertrace/softmmu.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++ include/hw/pci/pci.h | 2 3 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 hypertrace/softmmu.c diff --git a/hypertrace/Makefile.objs b/hypertrace/Makefile.objs index 24e8fb4..0025207 100644 --- a/hypertrace/Makefile.objs +++ b/hypertrace/Makefile.objs @@ -1,9 +1,12 @@ # -*- mode: makefile -*- target-obj-$(CONFIG_USER_ONLY) += user.o +ifdef CONFIG_PCI +target-obj-$(CONFIG_SOFTMMU) += softmmu.o +endif target-obj-y += common.o -$(obj)/user.o: $(obj)/emit.c +$(obj)/user.o $(obj)/softmmu.o: $(obj)/emit.c $(obj)/emit.c: $(obj)/emit.c-timestamp $(BUILD_DIR)/config-host.mak @cmp $< $@ >/dev/null 2>&1 || cp $< $@ diff --git a/hypertrace/softmmu.c b/hypertrace/softmmu.c new file mode 100644 index 0000000..ca4d1ad --- /dev/null +++ b/hypertrace/softmmu.c @@ -0,0 +1,235 @@ +/* + * QEMU-side management of hypertrace in softmmu emulation. + * + * Copyright (C) 2016 Lluís Vilanova <vilanova@ac.upc.edu> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +/* + * Implementation details + * ====================== + * + * There are 3 channels, each a BAR of a virtual device that can be used through + * MMIO. + * + * + * - Configuration channel: Exposes configuration parameters. + * + * - Data channel: Lets guests write argument values. Each guest client should + * use a different offset to avoid concurrency problems. + * + * - Control channel: Triggers the hypertrace event on a write, providing the + * first argument. Offset in the control channel sets the offset in the data + * channel. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/ram_addr.h" +#include "hypertrace/common.h" +#include "hw/pci/pci.h" +#include "migration/migration.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "trace.h" + + +#define PAGE_SIZE TARGET_PAGE_SIZE + + +typedef struct HypertraceState +{ + PCIDevice dev; + + uint64_t max_clients; + struct hypertrace_config hconfig; + + MemoryRegion config; + void *config_ptr; + MemoryRegion data; + void *data_ptr; + MemoryRegion control; + void *control_ptr; + + Error *migration_blocker; +} HypertraceState; + + +static uint64_t hypertrace_control_io_read(void *opaque, hwaddr addr, + unsigned size) +{ + uint64_t res; + HypertraceState *s = opaque; + char *mem = &((char*)s->control_ptr)[addr]; + + switch (size) { + case 1: + { + res = ((uint8_t*)mem)[0]; + break; + } + case 2: + { + res = ((uint16_t*)mem)[0]; + break; + } + case 4: + { + res = ((uint32_t*)mem)[0]; + break; + } + case 8: + { + res = ((uint64_t*)mem)[0]; + break; + } + default: + error_report("error: hypertrace: Unexpected read of size %d\n", size); + } + + return res; +} + +#include "hypertrace/emit.c" + +static void hypertrace_control_io_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + HypertraceState *s = opaque; + char *mem = &((char*)s->control_ptr)[addr]; + + switch (size) { + case 1: + { + uint8_t *res = (uint8_t*)mem; + *res = (uint8_t)data; + break; + } + case 2: + { + uint16_t *res = (uint16_t*)mem; + *res = (uint16_t)data; + break; + } + case 4: + { + uint32_t *res = (uint32_t*)mem; + *res = (uint32_t)data; + break; + } + case 8: + { + uint64_t *res = (uint64_t*)mem; + *res = (uint64_t)data; + break; + } + default: + error_report("error: hypertrace: Unexpected write of size %d\n", size); + } + + if ((addr + size) % sizeof(uint64_t) == 0) { + uint64_t client = addr / sizeof(uint64_t); + uint64_t vcontrol = ((uint64_t*)s->control_ptr)[client]; + uint64_t *data_ptr = (uint64_t*)s->data_ptr; + data_ptr = &data_ptr[client * s->hconfig.client_data_size]; + hypertrace_emit(current_cpu, vcontrol, data_ptr); + } +} + +static const MemoryRegionOps hypertrace_control_ops = { + .read = &hypertrace_control_io_read, + .write = &hypertrace_control_io_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + + +static void hypertrace_realize(PCIDevice *dev, Error **errp) +{ + struct hypertrace_config *config; + HypertraceState *s = DO_UPCAST(HypertraceState, dev, dev); + Error *err = NULL; + + if (s->max_clients < 1) { + error_setg(errp, "hypertrace: must have at least one client\n"); + return; + } + + hypertrace_init_config(&s->hconfig, s->max_clients); + + error_setg(&s->migration_blocker, "The 'hypertrace' device cannot be migrated"); + migrate_add_blocker(s->migration_blocker); + + pci_set_word(s->dev.config + PCI_COMMAND, + PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + + /* config channel */ + memory_region_init_ram(&s->config, OBJECT(s), "hypertrace.config", + TARGET_PAGE_SIZE, &err); + if (err) { + error_propagate(errp, err); + return; + } + pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->config); + s->config_ptr = qemu_map_ram_ptr(s->config.ram_block, 0); + config = s->config_ptr; + config->max_clients = tswap64(s->hconfig.max_clients); + config->client_args = tswap64(s->hconfig.client_args); + config->client_data_size = tswap64(s->hconfig.client_data_size); + config->control_size = tswap64(s->hconfig.control_size); + config->data_size = tswap64(s->hconfig.data_size); + + /* data channel */ + memory_region_init_ram(&s->data, OBJECT(s), "hypertrace.data", + s->hconfig.data_size, &err); + if (err) { + error_propagate(errp, err); + return; + } + pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->data); + s->data_ptr = qemu_map_ram_ptr(s->data.ram_block, 0); + + /* control channel */ + memory_region_init_io(&s->control, OBJECT(s), &hypertrace_control_ops, s, + "hypertrace.control", s->hconfig.control_size); + pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->control); + s->control_ptr = qemu_map_ram_ptr(s->control.ram_block, 0); +} + + +static Property hypertrace_properties[] = { + DEFINE_PROP_UINT64("max-clients", HypertraceState, max_clients, 1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void hypertrace_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->realize = hypertrace_realize; + k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + k->device_id = PCI_DEVICE_ID_HYPERTRACE; + k->class_id = PCI_CLASS_MEMORY_RAM; + dc->desc = "Hypertrace communication channel", + dc->props = hypertrace_properties; +} + +static TypeInfo hypertrace_info = { + .name = "hypertrace", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(HypertraceState), + .class_init = hypertrace_class_init, +}; + +static void hypertrace_register_types(void) +{ + type_register_static(&hypertrace_info); +} + +type_init(hypertrace_register_types) diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 929ec2f..8973f57 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -80,6 +80,8 @@ #define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 #define PCI_DEVICE_ID_VIRTIO_9P 0x1009 +#define PCI_DEVICE_ID_HYPERTRACE 0x10f0 + #define PCI_VENDOR_ID_REDHAT 0x1b36 #define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001 #define PCI_DEVICE_ID_REDHAT_SERIAL 0x0002 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH v2 4/6] hypertrace: [softmmu] Add QEMU-side proxy to "guest_hypertrace" event 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 4/6] hypertrace: [softmmu] " Lluís Vilanova @ 2016-09-06 1:43 ` Michael S. Tsirkin 2016-09-09 13:19 ` Lluís Vilanova 2016-09-14 14:37 ` Stefan Hajnoczi 0 siblings, 2 replies; 14+ messages in thread From: Michael S. Tsirkin @ 2016-09-06 1:43 UTC (permalink / raw) To: Lluís Vilanova Cc: qemu-devel, Daniel P Berrange, Luiz Capitulino, Eric Blake, Stefan Hajnoczi, Marcel Apfelbaum On Mon, Sep 05, 2016 at 08:56:44PM +0200, Lluís Vilanova wrote: > diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h > index 929ec2f..8973f57 100644 > --- a/include/hw/pci/pci.h > +++ b/include/hw/pci/pci.h > @@ -80,6 +80,8 @@ > #define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 > #define PCI_DEVICE_ID_VIRTIO_9P 0x1009 > > +#define PCI_DEVICE_ID_HYPERTRACE 0x10f0 > + > #define PCI_VENDOR_ID_REDHAT 0x1b36 > #define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001 > #define PCI_DEVICE_ID_REDHAT_SERIAL 0x0002 There's no need to add IDs to this header. We should probably drop the ones we currently have in pci.h, too. -- MST ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH v2 4/6] hypertrace: [softmmu] Add QEMU-side proxy to "guest_hypertrace" event 2016-09-06 1:43 ` Michael S. Tsirkin @ 2016-09-09 13:19 ` Lluís Vilanova 2016-09-14 14:37 ` Stefan Hajnoczi 1 sibling, 0 replies; 14+ messages in thread From: Lluís Vilanova @ 2016-09-09 13:19 UTC (permalink / raw) To: Michael S. Tsirkin Cc: qemu-devel, Luiz Capitulino, Stefan Hajnoczi, Marcel Apfelbaum Michael S Tsirkin writes: > On Mon, Sep 05, 2016 at 08:56:44PM +0200, Lluís Vilanova wrote: >> diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h >> index 929ec2f..8973f57 100644 >> --- a/include/hw/pci/pci.h >> +++ b/include/hw/pci/pci.h >> @@ -80,6 +80,8 @@ >> #define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 >> #define PCI_DEVICE_ID_VIRTIO_9P 0x1009 >> >> +#define PCI_DEVICE_ID_HYPERTRACE 0x10f0 >> + >> #define PCI_VENDOR_ID_REDHAT 0x1b36 >> #define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001 >> #define PCI_DEVICE_ID_REDHAT_SERIAL 0x0002 > There's no need to add IDs to this header. > We should probably drop the ones we currently have in pci.h, too. You mean these should simply be a define inside each device's code? Thanks, Lluis ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH v2 4/6] hypertrace: [softmmu] Add QEMU-side proxy to "guest_hypertrace" event 2016-09-06 1:43 ` Michael S. Tsirkin 2016-09-09 13:19 ` Lluís Vilanova @ 2016-09-14 14:37 ` Stefan Hajnoczi 1 sibling, 0 replies; 14+ messages in thread From: Stefan Hajnoczi @ 2016-09-14 14:37 UTC (permalink / raw) To: Michael S. Tsirkin Cc: Lluís Vilanova, qemu-devel, Daniel P Berrange, Luiz Capitulino, Eric Blake, Marcel Apfelbaum [-- Attachment #1: Type: text/plain, Size: 1011 bytes --] On Tue, Sep 06, 2016 at 04:43:00AM +0300, Michael S. Tsirkin wrote: > On Mon, Sep 05, 2016 at 08:56:44PM +0200, Lluís Vilanova wrote: > > diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h > > index 929ec2f..8973f57 100644 > > --- a/include/hw/pci/pci.h > > +++ b/include/hw/pci/pci.h > > @@ -80,6 +80,8 @@ > > #define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 > > #define PCI_DEVICE_ID_VIRTIO_9P 0x1009 > > > > +#define PCI_DEVICE_ID_HYPERTRACE 0x10f0 > > + > > #define PCI_VENDOR_ID_REDHAT 0x1b36 > > #define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001 > > #define PCI_DEVICE_ID_REDHAT_SERIAL 0x0002 > > > There's no need to add IDs to this header. > We should probably drop the ones we currently have in pci.h, too. Defining the PCI IDs in public headers gives libqos test cases access to them. If they are scoped to only be available in device emulation code then the test cases need to duplicate them, which is undesirable IMO. Stefan [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 455 bytes --] ^ permalink raw reply [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v2 5/6] hypertrace: Add guest-side user-level library 2016-09-05 18:56 [Qemu-devel] [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel Lluís Vilanova ` (3 preceding siblings ...) 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 4/6] hypertrace: [softmmu] " Lluís Vilanova @ 2016-09-05 18:56 ` Lluís Vilanova 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 6/6] hypertrace: Add guest-side Linux module Lluís Vilanova 2016-09-05 19:23 ` [Qemu-devel] [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel no-reply 6 siblings, 0 replies; 14+ messages in thread From: Lluís Vilanova @ 2016-09-05 18:56 UTC (permalink / raw) To: qemu-devel Cc: Daniel P Berrange, Luiz Capitulino, Eric Blake, Stefan Hajnoczi Provides guest library "libqemu-hypertrace-guest.a" to abstract access to the hypertrace channel. Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> --- Makefile | 6 + configure | 2 hypertrace/guest/user/Makefile | 30 +++ hypertrace/guest/user/common.c | 301 +++++++++++++++++++++++++++++++ hypertrace/guest/user/qemu-hypertrace.h | 80 ++++++++ 5 files changed, 418 insertions(+), 1 deletion(-) create mode 100644 hypertrace/guest/user/Makefile create mode 100644 hypertrace/guest/user/common.c create mode 100644 hypertrace/guest/user/qemu-hypertrace.h diff --git a/Makefile b/Makefile index 50b4b3a..8fb469b 100644 --- a/Makefile +++ b/Makefile @@ -460,9 +460,13 @@ ifneq (,$(findstring qemu-ga,$(TOOLS))) endif endif +install-hypertrace: + $(INSTALL_DIR) "$(DESTDIR)$(includedir)" + $(INSTALL_DATA) "$(SRC_PATH)/hypertrace/guest/user/qemu-hypertrace.h" "$(DESTDIR)$(includedir)/" + install: all $(if $(BUILD_DOCS),install-doc) \ -install-datadir install-localstatedir +install-datadir install-localstatedir install-hypertrace ifneq ($(TOOLS),) $(call install-prog,$(subst qemu-ga,qemu-ga$(EXESUF),$(TOOLS)),$(DESTDIR)$(bindir)) endif diff --git a/configure b/configure index d7ec31f..ad83fff 100755 --- a/configure +++ b/configure @@ -5793,6 +5793,8 @@ if [ "$TARGET_BASE_ARCH" = "" ]; then fi symlink "$source_path/Makefile.target" "$target_dir/Makefile" +mkdir -p $target_dir/hypertrace/guest/user +symlink $source_path/hypertrace/guest/user/Makefile $target_dir/hypertrace/guest/user/Makefile upper() { echo "$@"| LC_ALL=C tr '[a-z]' '[A-Z]' diff --git a/hypertrace/guest/user/Makefile b/hypertrace/guest/user/Makefile new file mode 100644 index 0000000..85d0839 --- /dev/null +++ b/hypertrace/guest/user/Makefile @@ -0,0 +1,30 @@ +include ../../../../config-host.mak +include ../../../config-target.mak +include $(SRC_PATH)/rules.mak + +vpath % $(SRC_PATH)/hypertrace/guest/user + +# do not use QEMU's per-host cflags when building guest code +QEMU_CFLAGS = -Werror -Wall + +QEMU_CFLAGS += $(GLIB_CFLAGS) +QEMU_CFLAGS += -I$(SRC_PATH)/include +QEMU_CFLAGS += -I../../../../linux-headers +QEMU_CFLAGS += -I../../../../ +QEMU_CFLAGS += -I../../../ + +ifdef CONFIG_SOFTMMU +QEMU_CFLAGS += -DNEED_CPU_H +QEMU_CFLAGS += -I$(SRC_PATH)/target-$(TARGET_BASE_ARCH) +endif + +QEMU_CFLAGS += -g -O2 + +obj-y = common.o + +libqemu-hypertrace-guest.a: $(obj-y) + +all: libqemu-hypertrace-guest.a + +clean: + rm -f $(obj-y) libqemu-hypertrace-guest.a diff --git a/hypertrace/guest/user/common.c b/hypertrace/guest/user/common.c new file mode 100644 index 0000000..cf14386 --- /dev/null +++ b/hypertrace/guest/user/common.c @@ -0,0 +1,301 @@ +/* + * Guest-side management of hypertrace. + * + * Copyright (C) 2016 Lluís Vilanova <vilanova@ac.upc.edu> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu-hypertrace.h" + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <pthread.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <stdbool.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <glob.h> + +#include "config-host.h" +#include "config-target.h" +#if defined(CONFIG_SOFTMMU) +#include "qemu/osdep.h" +#include "hw/pci/pci.h" +#endif +#include "hypertrace/common.h" + +static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER; + +static char *config_path = NULL; +static int config_fd = -1; +static uint64_t *config_addr = NULL; +static struct hypertrace_config *config = NULL; + + +static char *data_path = NULL; +static int data_fd = -1; +static uint64_t *data_addr = NULL; + +static char *control_path = NULL; +static int control_fd = -1; +#if defined(CONFIG_USER_ONLY) +static __thread uint64_t *control_addr = NULL; +static __thread uint64_t *control_addr_1 = NULL; +#else +static uint64_t *control_addr = NULL; +#endif + + +static int init_channel_file(const char *base, const char *suffix, size_t size, + char ** path, int *fd, uint64_t **addr, bool write) +{ + int prot; + + *path = malloc(strlen(base) + strlen(suffix) + 1); + sprintf(*path, "%s%s", base, suffix); + + prot = O_RDONLY; + if (write) { + prot = O_RDWR; + } + *fd = open(*path, prot); + if (*fd == -1) { + return -1; + } + + printf("init: %s %ld\n", *path, size); + prot = PROT_READ; + if (write) { + prot |= PROT_WRITE; + } + *addr = mmap(NULL, size, prot, MAP_SHARED, *fd, 0); + if (*addr == MAP_FAILED) { + return -1; + } + return 0; +} + +#if !defined(CONFIG_USER_ONLY) && defined(__linux__) +static int check_device_id (const char *base, const char *name, uint64_t value) +{ + char tmp[1024]; + sprintf(tmp, "%s/%s", base, name); + + int fd = open(tmp, O_RDONLY); + if (fd < 0) { + return -1; + } + + char v[1024]; + ssize_t s = read(fd, v, sizeof(v)); + if (s < 0) { + close(fd); + return -1; + } + v[s] = '\0'; + + char *end; + uint64_t vv = strtoull(v, &end, 16); + if (*end == '\n' && vv == value) { + return 0; + } + else { + return -1; + } +} + +static char* find_device(void) +{ + static char tmp[1024]; + char *res = NULL; + + glob_t g; + if (glob("/sys/devices/pci*/*", GLOB_NOSORT, NULL, &g) != 0) { + return NULL; + } + + + int i; + for (i = 0; i < g.gl_pathc; i++) { + char *path = g.gl_pathv[i]; + + if (check_device_id(path, "vendor", PCI_VENDOR_ID_REDHAT_QUMRANET) < 0) { + continue; + } + if (check_device_id(path, "device", PCI_DEVICE_ID_HYPERTRACE) < 0) { + continue; + } + + sprintf(tmp, "%s", path); + res = tmp; + break; + } + + globfree(&g); + + return res; +} +#endif + +int qemu_hypertrace_init(const char *base) +{ +#if defined(CONFIG_USER_ONLY) + const char *config_suff = "-config"; + const char *data_suff = "-data"; + const char *control_suff = "-control"; +#elif defined(__linux__) + const char *config_suff = "/resource0"; + const char *data_suff = "/resource1"; + const char *control_suff = "/resource2"; +#else +#error Unsupported OS +#endif + +#if defined(CONFIG_USER_ONLY) + if (base == NULL) { + errno = ENOENT; + return -1; + } +#elif defined(__linux__) + if (base == NULL) { + /* try to guess the base path */ + base = find_device(); + if (base == NULL) { + errno = ENOENT; + return -1; + } + } +#endif + + if (config_addr == NULL) { + printf("init config\n"); + int res; + + if (pthread_mutex_lock(&init_mutex)) { + return -1; + } + + res = init_channel_file(base, config_suff, getpagesize(), + &config_path, &config_fd, &config_addr, + false); + if (res != 0) { + return res; + } + + config = (struct hypertrace_config*)config_addr; + + if (pthread_mutex_unlock(&init_mutex)) { + return -1; + } + } + + if (data_addr == NULL) { + printf("init data\n"); + int res; + + if (pthread_mutex_lock(&init_mutex)) { + return -1; + } + + res = init_channel_file(base, data_suff, config->data_size, + &data_path, &data_fd, &data_addr, + true); + if (res != 0) { + return res; + } + + if (pthread_mutex_unlock(&init_mutex)) { + return -1; + } + } + + if (control_addr == NULL) { + printf("init control\n"); + int res; + uint64_t control_size = config->control_size; + + if (pthread_mutex_lock(&init_mutex)) { + return -1; + } + + res = init_channel_file(base, control_suff, control_size, + &control_path, &control_fd, &control_addr, + true); + if (res != 0) { + return res; + } + +#if defined(CONFIG_USER_ONLY) + control_addr_1 = (uint64_t*)((char*)control_addr + config->control_size / 2); +#endif + + if (pthread_mutex_unlock(&init_mutex)) { + return -1; + } + } + + return 0; +} + + +static int fini_channel(int *fd, char **path) +{ + if (*fd != -1) { + if (close(*fd) == -1) { + return -1; + } + *fd = -1; + } + if (*path != NULL) { + free(*path); + *path = NULL; + } + return 0; +} + +int qemu_hypertrace_fini(void) +{ + if (fini_channel(&data_fd, &data_path) != 0) { + return -1; + } + if (fini_channel(&control_fd, &control_path) != 0) { + return -1; + } + return 0; +} + + +uint64_t qemu_hypertrace_max_clients(void) +{ + printf("max_clients\n"); + return config->max_clients; +} + +uint64_t qemu_hypertrace_num_args(void) +{ + printf("num_args\n"); + return config->client_args; +} + +uint64_t *qemu_hypertrace_data(uint64_t client) +{ + printf("data\n"); + return &data_addr[client * CONFIG_HYPERTRACE_ARGS * sizeof(uint64_t)]; +} + +void qemu_hypertrace (uint64_t client, uint64_t arg1) +{ + uint64_t *ctrl = control_addr; + ctrl[client] = arg1; +#if defined(CONFIG_USER_ONLY) + /* QEMU in 'user' mode uses two faulting pages to detect invocations */ + ctrl = control_addr_1; + ctrl[client] = arg1; +#endif +} diff --git a/hypertrace/guest/user/qemu-hypertrace.h b/hypertrace/guest/user/qemu-hypertrace.h new file mode 100644 index 0000000..aa78bb3 --- /dev/null +++ b/hypertrace/guest/user/qemu-hypertrace.h @@ -0,0 +1,80 @@ +/* + * Guest-side management of hypertrace. + * + * Copyright (C) 2016 Lluís Vilanova <vilanova@ac.upc.edu> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <stdint.h> +#include <sys/types.h> + + +/** + * qemu_hypertrace_init: + * @base: Base path to the hypertrace channel. + * + * Initialize the hypertrace channel. The operation is idempotent, and must be + * called once per thread if running in QEMU's "user" mode. + * + * The base path to the hypertrace channel depends on the type of QEMU target: + * + * - User (single-application) + * The base path provided when starting QEMU ("-hypertrace" commandline + * option). + * + * - System (OS-dependant) + * + Linux + * The base path to the hypertrace channel virtual device; on a default QEMU + * device setup for x86 this is "/sys/devices/pci0000:00/0000:00:04.0". If + * NULL is provided, the hypertrace device will be automatically detected. + * + * Returns: Zero on success. + */ +int qemu_hypertrace_init(const char *base); + +/** + * qemu_hypertrace_fini: + * + * Deinitialize the hypertrace channel. + * + * Returns: Zero on success. + */ +int qemu_hypertrace_fini(void); + +/** + * qemu_hypertrace_max_clients: + * + * Maximum number of concurrent clients accepted by other calls. + */ +uint64_t qemu_hypertrace_max_clients(void); + +/** + * qemu_hypertrace_num_args: + * + * Number of uint64_t values read by each call to qemu_hypertrace(). + */ +uint64_t qemu_hypertrace_num_args(void); + +/** + * qemu_hypertrace_data: + * @client: Client identifier. + * + * Pointer to the start of the data channel for the given client. Clients must + * write their arguments there (all but the first one). + */ +uint64_t *qemu_hypertrace_data(uint64_t client); + +/** + * qemu_hypertrace: + * @client: Client identifier. + * @arg1: First argument of the hypertrace event. + * + * Emit a hypertrace event. + * + * Each of the clients (e.g., thread) must use a different client identifier to + * ensure they can work concurrently without using locks (i.e., each uses a + * different portion of the data channel). + */ +void qemu_hypertrace(uint64_t client, uint64_t arg1); ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v2 6/6] hypertrace: Add guest-side Linux module 2016-09-05 18:56 [Qemu-devel] [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel Lluís Vilanova ` (4 preceding siblings ...) 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 5/6] hypertrace: Add guest-side user-level library Lluís Vilanova @ 2016-09-05 18:56 ` Lluís Vilanova 2016-09-05 19:23 ` [Qemu-devel] [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel no-reply 6 siblings, 0 replies; 14+ messages in thread From: Lluís Vilanova @ 2016-09-05 18:56 UTC (permalink / raw) To: qemu-devel Cc: Daniel P Berrange, Luiz Capitulino, Eric Blake, Stefan Hajnoczi Provides guest Linux kernel module "qemu-hypertrace.ko" to abstract access to the hypertrace channel. Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> --- Makefile | 4 - configure | 4 + hypertrace/guest/linux-module/Kbuild.in | 7 + hypertrace/guest/linux-module/Makefile | 23 +++ .../include/linux/qemu-hypertrace-internal.h | 46 ++++++ .../linux-module/include/linux/qemu-hypertrace.h | 73 ++++++++++ hypertrace/guest/linux-module/qemu-hypertrace.c | 146 ++++++++++++++++++++ 7 files changed, 302 insertions(+), 1 deletion(-) create mode 100644 hypertrace/guest/linux-module/Kbuild.in create mode 100644 hypertrace/guest/linux-module/Makefile create mode 100644 hypertrace/guest/linux-module/include/linux/qemu-hypertrace-internal.h create mode 100644 hypertrace/guest/linux-module/include/linux/qemu-hypertrace.h create mode 100644 hypertrace/guest/linux-module/qemu-hypertrace.c diff --git a/Makefile b/Makefile index 8fb469b..4a47823 100644 --- a/Makefile +++ b/Makefile @@ -461,8 +461,10 @@ endif endif install-hypertrace: - $(INSTALL_DIR) "$(DESTDIR)$(includedir)" + $(INSTALL_DIR) "$(DESTDIR)$(includedir)/linux" $(INSTALL_DATA) "$(SRC_PATH)/hypertrace/guest/user/qemu-hypertrace.h" "$(DESTDIR)$(includedir)/" + $(INSTALL_DATA) "$(SRC_PATH)/hypertrace/guest/linux-module/include/linux/qemu-hypertrace.h" "$(DESTDIR)$(includedir)/linux" + $(INSTALL_DATA) "$(SRC_PATH)/hypertrace/guest/linux-module/include/linux/qemu-hypertrace-internal.h" "$(DESTDIR)$(includedir)/linux" install: all $(if $(BUILD_DOCS),install-doc) \ diff --git a/configure b/configure index ad83fff..fadaaf5 100755 --- a/configure +++ b/configure @@ -5795,6 +5795,10 @@ fi symlink "$source_path/Makefile.target" "$target_dir/Makefile" mkdir -p $target_dir/hypertrace/guest/user symlink $source_path/hypertrace/guest/user/Makefile $target_dir/hypertrace/guest/user/Makefile +if test "$target_softmmu" = "yes"; then + mkdir -p $target_dir/hypertrace/guest/linux-module + symlink $source_path/hypertrace/guest/linux-module/Makefile $target_dir/hypertrace/guest/linux-module/Makefile +fi upper() { echo "$@"| LC_ALL=C tr '[a-z]' '[A-Z]' diff --git a/hypertrace/guest/linux-module/Kbuild.in b/hypertrace/guest/linux-module/Kbuild.in new file mode 100644 index 0000000..56abaea --- /dev/null +++ b/hypertrace/guest/linux-module/Kbuild.in @@ -0,0 +1,7 @@ +# -*- mode: makefile -*- + +COMMON_H = $(shell readlink -f $(MOD_SRC_PATH)/../../common.h) + +src = $(MOD_SRC_PATH) +ccflags-y := -I$(src)/include/ -DCOMMON_H=$(COMMON_H) +obj-m := qemu-hypertrace.o diff --git a/hypertrace/guest/linux-module/Makefile b/hypertrace/guest/linux-module/Makefile new file mode 100644 index 0000000..b30cdeb --- /dev/null +++ b/hypertrace/guest/linux-module/Makefile @@ -0,0 +1,23 @@ +include ../../../../config-host.mak +include ../../../config-target.mak +include $(SRC_PATH)/rules.mak + +MOD_SRC_PATH = $(SRC_PATH)/hypertrace/guest/linux-module + +LINUX_BUILD_PATH = /lib/modules/$(shell uname -r)/build + +vpath % $(MOD_SRC_PATH) + + +all: Kbuild + $(MAKE) -C $(LINUX_BUILD_PATH) M=$(shell pwd) \ + MOD_SRC_PATH=$(MOD_SRC_PATH) \ + modules + +clean: Kbuild + $(MAKE) -C $(LINUX_BUILD_PATH) M=$(shell pwd) clean + rm -f $< + +Kbuild: $(MOD_SRC_PATH)/Kbuild.in Makefile + rm -f $@ + cp $< $@ diff --git a/hypertrace/guest/linux-module/include/linux/qemu-hypertrace-internal.h b/hypertrace/guest/linux-module/include/linux/qemu-hypertrace-internal.h new file mode 100644 index 0000000..63dfee0 --- /dev/null +++ b/hypertrace/guest/linux-module/include/linux/qemu-hypertrace-internal.h @@ -0,0 +1,46 @@ +/* -*- C -*- + * + * Guest-side management of hypertrace. + * + * Copyright (C) 2016 Lluís Vilanova <vilanova@ac.upc.edu> + * + * 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 3 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/. + */ + +extern uint64_t _qemu_hypertrace_channel_max_clients; +extern uint64_t _qemu_hypertrace_channel_num_args; +extern uint64_t *_qemu_hypertrace_channel_data; +extern uint64_t *_qemu_hypertrace_channel_control; + +static inline uint64_t qemu_hypertrace_max_clients(void) +{ + return _qemu_hypertrace_channel_max_clients; +} + +static inline uint64_t qemu_hypertrace_num_args(void) +{ + return _qemu_hypertrace_channel_num_args; +} + +static inline uint64_t *qemu_hypertrace_data(uint64_t client) +{ + size_t args_size = qemu_hypertrace_num_args() * sizeof(uint64_t); + return &_qemu_hypertrace_channel_data[client * args_size]; +} + +static inline void qemu_hypertrace (uint64_t client, uint64_t arg1) +{ + uint64_t *ctrlp = _qemu_hypertrace_channel_control; + ctrlp[client] = arg1; +} diff --git a/hypertrace/guest/linux-module/include/linux/qemu-hypertrace.h b/hypertrace/guest/linux-module/include/linux/qemu-hypertrace.h new file mode 100644 index 0000000..f4b70c9 --- /dev/null +++ b/hypertrace/guest/linux-module/include/linux/qemu-hypertrace.h @@ -0,0 +1,73 @@ +/* -*- C -*- + * + * Guest-side management of hypertrace. + * + * Copyright (C) 2016 Lluís Vilanova <vilanova@ac.upc.edu> + * + * 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 3 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/. + */ + +#ifndef QEMU_HYPERTRACE_H +#define QEMU_HYPERTRACE_H + +#include <linux/types.h> + + +/** + * qemu_hypertrace_max_clients: + * + * Maximum number of concurrent clients accepted by other calls. + */ +static uint64_t qemu_hypertrace_max_clients(void); + +/** + * qemu_hypertrace_num_args: + * + * Number of uint64_t values read by each call to qemu_hypertrace(). + */ +static uint64_t qemu_hypertrace_num_args(void); + +/** + * qemu_hypertrace_data: + * @client: Client identifier. + * + * Pointer to the start of the data channel for the given client. Clients must + * write their arguments there (all but the first one). + */ +static uint64_t *qemu_hypertrace_data(uint64_t client); + +/** + * qemu_hypertrace: + * @client: Client identifier. + * @arg1: First argument of the hypertrace event. + * + * Emit a hypertrace event. + * + * Each of the clients (e.g., CPU) must use a different client identifier to + * ensure they can work concurrently without using locks (i.e., each uses a + * different portion of the data channel). + * + * Note: You should use wmb() before writing into the control channel iff you + * have written into the data channel. + * + * Note: Use preempt_disable() and preempt_enable() if you're using data offsets + * based on the CPU identifiers (or else data might be mixed if a task is + * re-scheduled). + */ +static void qemu_hypertrace(uint64_t client, uint64_t arg1); + + +#include <linux/qemu-hypertrace-internal.h> + +#endif /* QEMU_HYPERTRACE_H */ diff --git a/hypertrace/guest/linux-module/qemu-hypertrace.c b/hypertrace/guest/linux-module/qemu-hypertrace.c new file mode 100644 index 0000000..901d424 --- /dev/null +++ b/hypertrace/guest/linux-module/qemu-hypertrace.c @@ -0,0 +1,146 @@ +/* + * Guest-side management of hypertrace. + * + * Copyright (C) 2016 Lluís Vilanova <vilanova@ac.upc.edu> + * + * 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 3 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/. + */ + +#include <linux/qemu-hypertrace.h> + +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/uaccess.h> + +#define xstr(s) #s +#define str(s) xstr(s) +#include str(COMMON_H) + + +#define VERSION_STR "0.1" +#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 +#define PCI_DEVICE_ID_HYPERTRACE 0x10f0 + + +MODULE_DESCRIPTION("Kernel interface to QEMU's hypertrace device"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lluís Vilanova"); +MODULE_VERSION(VERSION_STR); + + +////////////////////////////////////////////////////////////////////// +// Kernel interface + +uint64_t _qemu_hypertrace_channel_max_clients; +uint64_t _qemu_hypertrace_channel_num_args; +static uint64_t *_qemu_hypertrace_channel_config; +uint64_t *_qemu_hypertrace_channel_data; +uint64_t *_qemu_hypertrace_channel_control; + +EXPORT_SYMBOL(_qemu_hypertrace_channel_max_clients); +EXPORT_SYMBOL(_qemu_hypertrace_channel_num_args); +EXPORT_SYMBOL(_qemu_hypertrace_channel_data); +EXPORT_SYMBOL(_qemu_hypertrace_channel_control); + + +////////////////////////////////////////////////////////////////////// +// Channel initialization + +static +int +init_channel (uint64_t **vaddr, struct pci_dev *dev, int bar) +{ + void * res; + resource_size_t start, size; + + start = pci_resource_start(dev, bar); + size = pci_resource_len(dev, bar); + + if (start == 0 || size == 0) { + return -ENOENT; + } + + res = ioremap(start, size); + if (res == 0) { + return -EINVAL; + } + + *vaddr = res; + return 0; +} + +////////////////////////////////////////////////////////////////////// +// Module (de)initialization + +int init_module(void) +{ + int res = 0; + struct pci_dev *dev = NULL; + struct hypertrace_config *config; + + printk(KERN_NOTICE "Loading QEMU hypertrace module (version %s)\n", + VERSION_STR); + + dev = pci_get_device(PCI_VENDOR_ID_REDHAT_QUMRANET, PCI_DEVICE_ID_HYPERTRACE, NULL); + if (dev == NULL) { + res = -ENOENT; + printk(KERN_ERR "Unable to find hypertrace device\n"); + goto error; + } + + res = init_channel(&_qemu_hypertrace_channel_config, dev, 0); + if (res != 0) { + printk(KERN_ERR "Unable to find hypertrace config channel\n"); + goto error; + } + + config = (struct hypertrace_config*)_qemu_hypertrace_channel_config; + _qemu_hypertrace_channel_max_clients = config->max_clients; + _qemu_hypertrace_channel_num_args = config->client_args; + + res = init_channel(&_qemu_hypertrace_channel_data, dev, 1); + if (res != 0) { + printk(KERN_ERR "Unable to find hypertrace data channel\n"); + goto error_config; + } + + res = init_channel(&_qemu_hypertrace_channel_control, dev, 0); + if (res != 0) { + printk(KERN_ERR "Unable to find hypertrace control channel\n"); + goto error_data; + } + + goto ok; + +error_data: + iounmap(_qemu_hypertrace_channel_data); + +error_config: + iounmap(_qemu_hypertrace_channel_config); + _qemu_hypertrace_channel_config = NULL; + _qemu_hypertrace_channel_data = NULL; + +error: +ok: + return res; +} + +void cleanup_module(void) +{ + printk(KERN_NOTICE "Unloading QEMU hypertrace module\n"); + + iounmap(_qemu_hypertrace_channel_config); + iounmap(_qemu_hypertrace_channel_data); + iounmap(_qemu_hypertrace_channel_control); +} ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel 2016-09-05 18:56 [Qemu-devel] [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel Lluís Vilanova ` (5 preceding siblings ...) 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 6/6] hypertrace: Add guest-side Linux module Lluís Vilanova @ 2016-09-05 19:23 ` no-reply 2016-09-06 9:11 ` [Qemu-devel] Checkpatch false positives (Was: Re: [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel) Lluís Vilanova 6 siblings, 1 reply; 14+ messages in thread From: no-reply @ 2016-09-05 19:23 UTC (permalink / raw) To: vilanova; +Cc: famz, qemu-devel, stefanha, lcapitulino Hi, Your series seems to have some coding style problems. See output below for more information: Subject: [Qemu-devel] [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel Type: series Message-id: 147310178240.10840.14758930096407696981.stgit@fimbulvetr.bsc.es === TEST SCRIPT BEGIN === #!/bin/bash BASE=base n=1 total=$(git log --oneline $BASE.. | wc -l) failed=0 # Useful git options git config --local diff.renamelimit 0 git config --local diff.renames True commits="$(git log --format=%H --reverse $BASE..)" for c in $commits; do echo "Checking PATCH $n/$total: $(git show --no-patch --format=%s $c)..." if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then failed=1 echo fi n=$((n+1)) done exit $failed === TEST SCRIPT END === Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384 From https://github.com/patchew-project/qemu * [new tag] patchew/1473099234-10882-1-git-send-email-kwolf@redhat.com -> patchew/1473099234-10882-1-git-send-email-kwolf@redhat.com * [new tag] patchew/147310178240.10840.14758930096407696981.stgit@fimbulvetr.bsc.es -> patchew/147310178240.10840.14758930096407696981.stgit@fimbulvetr.bsc.es * [new tag] patchew/alpine.DEB.2.10.1609051159150.4105@sstabellini-ThinkPad-X260 -> patchew/alpine.DEB.2.10.1609051159150.4105@sstabellini-ThinkPad-X260 Switched to a new branch 'test' 0b7ef18 hypertrace: Add guest-side Linux module 1c66cbd hypertrace: Add guest-side user-level library b67ef31 hypertrace: [softmmu] Add QEMU-side proxy to "guest_hypertrace" event 536c66c hypertrace: [*-user] Add QEMU-side proxy to "guest_hypertrace" event 8861ce2 hypertrace: Add tracing event "guest_hypertrace" bc68e0b hypertrace: Add documentation === OUTPUT BEGIN === Checking PATCH 1/6: hypertrace: Add documentation... ERROR: trailing whitespace #109: FILE: docs/hypertrace.txt:92: + $ ERROR: trailing whitespace #110: FILE: docs/hypertrace.txt:93: + $ ERROR: trailing whitespace #117: FILE: docs/hypertrace.txt:100: + $ ERROR: trailing whitespace #123: FILE: docs/hypertrace.txt:106: + $ ERROR: trailing whitespace #130: FILE: docs/hypertrace.txt:113: + $ ERROR: trailing whitespace #154: FILE: docs/hypertrace.txt:137: + $ ERROR: trailing whitespace #156: FILE: docs/hypertrace.txt:139: + $ ERROR: trailing whitespace #160: FILE: docs/hypertrace.txt:143: + $ ERROR: trailing whitespace #171: FILE: docs/hypertrace.txt:154: + $ ERROR: trailing whitespace #181: FILE: docs/hypertrace.txt:164: + $ total: 10 errors, 0 warnings, 236 lines checked Your patch has style problems, please review. If any of these errors are false positives report them to the maintainer, see CHECKPATCH in MAINTAINERS. Checking PATCH 2/6: hypertrace: Add tracing event "guest_hypertrace"... Checking PATCH 3/6: hypertrace: [*-user] Add QEMU-side proxy to "guest_hypertrace" event... WARNING: line over 80 characters #81: FILE: bsd-user/main.c:866: + hypertrace_opt_parse(optarg, &hypertrace_base, &hypertrace_max_clients); WARNING: line over 80 characters #176: FILE: bsd-user/syscall.c:375: + target_to_host_bitmask(arg4, mmap_flags_tbl), WARNING: line over 80 characters #200: FILE: bsd-user/syscall.c:463: + target_to_host_bitmask(arg4, mmap_flags_tbl), WARNING: line over 80 characters #224: FILE: bsd-user/syscall.c:540: + target_to_host_bitmask(arg4, mmap_flags_tbl), ERROR: architecture specific defines should be avoided #302: FILE: hypertrace/common.h:10: +#if !defined(__KERNEL__) ERROR: open brace '{' following struct go on the same line #307: FILE: hypertrace/common.h:15: +struct hypertrace_config +{ ERROR: do not initialise statics to 0 or NULL #370: FILE: hypertrace/user.c:48: +static char *config_path = NULL; ERROR: do not initialise statics to 0 or NULL #372: FILE: hypertrace/user.c:50: +static uint64_t *qemu_config = NULL; ERROR: do not initialise statics to 0 or NULL #374: FILE: hypertrace/user.c:52: +static char *data_path = NULL; ERROR: do not initialise statics to 0 or NULL #376: FILE: hypertrace/user.c:54: +static uint64_t *qemu_data = NULL; ERROR: do not initialise statics to 0 or NULL #378: FILE: hypertrace/user.c:56: +static char *control_path = NULL; ERROR: do not initialise statics to 0 or NULL #380: FILE: hypertrace/user.c:58: +static uint64_t *qemu_control = NULL; WARNING: line over 80 characters #405: FILE: hypertrace/user.c:83: +void hypertrace_opt_parse(const char *optarg, char **base, unsigned int *max_clients_) ERROR: "foo ** bar" should be "foo **bar" #427: FILE: hypertrace/user.c:105: + char ** path, int *fd, uint64_t **addr) ERROR: line over 90 characters #490: FILE: hypertrace/user.c:168: + init_channel(base, "-config", TARGET_PAGE_SIZE, &config_path, &config_fd, &qemu_config); ERROR: "(foo*)" should be "(foo *)" #491: FILE: hypertrace/user.c:169: + pconfig = (struct hypertrace_config*)qemu_config; WARNING: line over 80 characters #498: FILE: hypertrace/user.c:176: + init_channel(base, "-data", config.data_size, &data_path, &data_fd, &qemu_data); ERROR: line over 90 characters #506: FILE: hypertrace/user.c:184: + init_channel(base, "-control", config.control_size, &control_path, &control_fd, &qemu_control); ERROR: do not initialise statics to 0 or NULL #549: FILE: hypertrace/user.c:227: + static bool atexit_in = false; WARNING: line over 80 characters #565: FILE: hypertrace/user.c:243: +bool hypertrace_guest_mmap_check(int fd, unsigned long len, unsigned long offset) WARNING: line over 80 characters #600: FILE: hypertrace/user.c:278: + printf("cpu->hypertrace_control=%p %lu %lu\n", qemu_addr, s.st_dev, s.st_ino); WARNING: line over 80 characters #602: FILE: hypertrace/user.c:280: + if (mprotect(vcpu->hypertrace_control, config.control_size / 2, PROT_READ) == -1) { WARNING: line over 80 characters #603: FILE: hypertrace/user.c:281: + error_report("error: mprotect(hypertrace_control): %s", strerror(errno)); ERROR: "(foo*)" should be "(foo *)" #641: FILE: hypertrace/user.c:319: + uint64_t vcontrol = ((uint64_t*)control_0)[client]; WARNING: line over 80 characters #694: FILE: hypertrace/user.h:27: +void hypertrace_opt_parse(const char *optarg, char **base, unsigned int *max_clients); WARNING: line over 80 characters #712: FILE: hypertrace/user.h:45: +bool hypertrace_guest_mmap_check(int fd, unsigned long len, unsigned long offset); total: 14 errors, 12 warnings, 833 lines checked Your patch has style problems, please review. If any of these errors are false positives report them to the maintainer, see CHECKPATCH in MAINTAINERS. Checking PATCH 4/6: hypertrace: [softmmu] Add QEMU-side proxy to "guest_hypertrace" event... ERROR: open brace '{' following struct go on the same line #81: FILE: hypertrace/softmmu.c:43: +typedef struct HypertraceState +{ ERROR: "(foo*)" should be "(foo *)" #103: FILE: hypertrace/softmmu.c:65: + char *mem = &((char*)s->control_ptr)[addr]; ERROR: "(foo*)" should be "(foo *)" #108: FILE: hypertrace/softmmu.c:70: + res = ((uint8_t*)mem)[0]; ERROR: "(foo*)" should be "(foo *)" #113: FILE: hypertrace/softmmu.c:75: + res = ((uint16_t*)mem)[0]; ERROR: "(foo*)" should be "(foo *)" #118: FILE: hypertrace/softmmu.c:80: + res = ((uint32_t*)mem)[0]; ERROR: "(foo*)" should be "(foo *)" #123: FILE: hypertrace/softmmu.c:85: + res = ((uint64_t*)mem)[0]; ERROR: Error messages should not contain newlines #127: FILE: hypertrace/softmmu.c:89: + error_report("error: hypertrace: Unexpected read of size %d\n", size); ERROR: "(foo*)" should be "(foo *)" #139: FILE: hypertrace/softmmu.c:101: + char *mem = &((char*)s->control_ptr)[addr]; ERROR: "(foo*)" should be "(foo *)" #144: FILE: hypertrace/softmmu.c:106: + uint8_t *res = (uint8_t*)mem; ERROR: "(foo*)" should be "(foo *)" #150: FILE: hypertrace/softmmu.c:112: + uint16_t *res = (uint16_t*)mem; ERROR: "(foo*)" should be "(foo *)" #156: FILE: hypertrace/softmmu.c:118: + uint32_t *res = (uint32_t*)mem; ERROR: "(foo*)" should be "(foo *)" #162: FILE: hypertrace/softmmu.c:124: + uint64_t *res = (uint64_t*)mem; ERROR: Error messages should not contain newlines #167: FILE: hypertrace/softmmu.c:129: + error_report("error: hypertrace: Unexpected write of size %d\n", size); ERROR: "(foo*)" should be "(foo *)" #172: FILE: hypertrace/softmmu.c:134: + uint64_t vcontrol = ((uint64_t*)s->control_ptr)[client]; ERROR: "(foo*)" should be "(foo *)" #173: FILE: hypertrace/softmmu.c:135: + uint64_t *data_ptr = (uint64_t*)s->data_ptr; ERROR: Error messages should not contain newlines #197: FILE: hypertrace/softmmu.c:159: + error_setg(errp, "hypertrace: must have at least one client\n"); WARNING: line over 80 characters #203: FILE: hypertrace/softmmu.c:165: + error_setg(&s->migration_blocker, "The 'hypertrace' device cannot be migrated"); total: 16 errors, 1 warnings, 256 lines checked Your patch has style problems, please review. If any of these errors are false positives report them to the maintainer, see CHECKPATCH in MAINTAINERS. Checking PATCH 5/6: hypertrace: Add guest-side user-level library... ERROR: do not initialise statics to 0 or NULL #123: FILE: hypertrace/guest/user/common.c:35: +static char *config_path = NULL; ERROR: do not initialise statics to 0 or NULL #125: FILE: hypertrace/guest/user/common.c:37: +static uint64_t *config_addr = NULL; ERROR: do not initialise statics to 0 or NULL #126: FILE: hypertrace/guest/user/common.c:38: +static struct hypertrace_config *config = NULL; ERROR: do not initialise statics to 0 or NULL #129: FILE: hypertrace/guest/user/common.c:41: +static char *data_path = NULL; ERROR: do not initialise statics to 0 or NULL #131: FILE: hypertrace/guest/user/common.c:43: +static uint64_t *data_addr = NULL; ERROR: do not initialise statics to 0 or NULL #133: FILE: hypertrace/guest/user/common.c:45: +static char *control_path = NULL; ERROR: do not initialise statics to 0 or NULL #136: FILE: hypertrace/guest/user/common.c:48: +static __thread uint64_t *control_addr = NULL; ERROR: do not initialise statics to 0 or NULL #137: FILE: hypertrace/guest/user/common.c:49: +static __thread uint64_t *control_addr_1 = NULL; ERROR: do not initialise statics to 0 or NULL #139: FILE: hypertrace/guest/user/common.c:51: +static uint64_t *control_addr = NULL; ERROR: "foo ** bar" should be "foo **bar" #144: FILE: hypertrace/guest/user/common.c:56: + char ** path, int *fd, uint64_t **addr, bool write) ERROR: architecture specific defines should be avoided #172: FILE: hypertrace/guest/user/common.c:84: +#if !defined(CONFIG_USER_ONLY) && defined(__linux__) ERROR: space prohibited between function name and open parenthesis '(' #173: FILE: hypertrace/guest/user/common.c:85: +static int check_device_id (const char *base, const char *name, uint64_t value) ERROR: consider using qemu_strtoull in preference to strtoull #192: FILE: hypertrace/guest/user/common.c:104: + uint64_t vv = strtoull(v, &end, 16); ERROR: else should follow close brace '}' #196: FILE: hypertrace/guest/user/common.c:108: + } + else { ERROR: "foo* bar" should be "foo *bar" #201: FILE: hypertrace/guest/user/common.c:113: +static char* find_device(void) WARNING: line over 80 characters #216: FILE: hypertrace/guest/user/common.c:128: + if (check_device_id(path, "vendor", PCI_VENDOR_ID_REDHAT_QUMRANET) < 0) { ERROR: "(foo*)" should be "(foo *)" #279: FILE: hypertrace/guest/user/common.c:191: + config = (struct hypertrace_config*)config_addr; WARNING: line over 80 characters #323: FILE: hypertrace/guest/user/common.c:235: + control_addr_1 = (uint64_t*)((char*)control_addr + config->control_size / 2); ERROR: "(foo*)" should be "(foo *)" #323: FILE: hypertrace/guest/user/common.c:235: + control_addr_1 = (uint64_t*)((char*)control_addr + config->control_size / 2); ERROR: space prohibited between function name and open parenthesis '(' #380: FILE: hypertrace/guest/user/common.c:292: +void qemu_hypertrace (uint64_t client, uint64_t arg1) total: 18 errors, 2 warnings, 433 lines checked Your patch has style problems, please review. If any of these errors are false positives report them to the maintainer, see CHECKPATCH in MAINTAINERS. Checking PATCH 6/6: hypertrace: Add guest-side Linux module... ERROR: space prohibited between function name and open parenthesis '(' #135: FILE: hypertrace/guest/linux-module/include/linux/qemu-hypertrace-internal.h:42: +static inline void qemu_hypertrace (uint64_t client, uint64_t arg1) ERROR: do not use C99 // comments #266: FILE: hypertrace/guest/linux-module/qemu-hypertrace.c:42: +////////////////////////////////////////////////////////////////////// ERROR: do not use C99 // comments #267: FILE: hypertrace/guest/linux-module/qemu-hypertrace.c:43: +// Kernel interface ERROR: do not use C99 // comments #281: FILE: hypertrace/guest/linux-module/qemu-hypertrace.c:57: +////////////////////////////////////////////////////////////////////// ERROR: do not use C99 // comments #282: FILE: hypertrace/guest/linux-module/qemu-hypertrace.c:58: +// Channel initialization ERROR: space prohibited between function name and open parenthesis '(' #286: FILE: hypertrace/guest/linux-module/qemu-hypertrace.c:62: +init_channel (uint64_t **vaddr, struct pci_dev *dev, int bar) ERROR: "foo * bar" should be "foo *bar" #288: FILE: hypertrace/guest/linux-module/qemu-hypertrace.c:64: + void * res; ERROR: do not use C99 // comments #307: FILE: hypertrace/guest/linux-module/qemu-hypertrace.c:83: +////////////////////////////////////////////////////////////////////// ERROR: do not use C99 // comments #308: FILE: hypertrace/guest/linux-module/qemu-hypertrace.c:84: +// Module (de)initialization WARNING: line over 80 characters #319: FILE: hypertrace/guest/linux-module/qemu-hypertrace.c:95: + dev = pci_get_device(PCI_VENDOR_ID_REDHAT_QUMRANET, PCI_DEVICE_ID_HYPERTRACE, NULL); ERROR: "(foo*)" should be "(foo *)" #332: FILE: hypertrace/guest/linux-module/qemu-hypertrace.c:108: + config = (struct hypertrace_config*)_qemu_hypertrace_channel_config; total: 10 errors, 1 warnings, 316 lines checked Your patch has style problems, please review. If any of these errors are false positives report them to the maintainer, see CHECKPATCH in MAINTAINERS. === OUTPUT END === Test command exited with code: 1 --- Email generated automatically by Patchew [http://patchew.org/]. Please send your feedback to patchew-devel@freelists.org ^ permalink raw reply [flat|nested] 14+ messages in thread
* [Qemu-devel] Checkpatch false positives (Was: Re: [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel) 2016-09-05 19:23 ` [Qemu-devel] [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel no-reply @ 2016-09-06 9:11 ` Lluís Vilanova 2016-09-06 9:16 ` Paolo Bonzini 0 siblings, 1 reply; 14+ messages in thread From: Lluís Vilanova @ 2016-09-06 9:11 UTC (permalink / raw) To: Paolo Bonzini; +Cc: qemu-devel no-reply writes: > Checking PATCH 1/6: hypertrace: Add documentation... > ERROR: trailing whitespace > #109: FILE: docs/hypertrace.txt:92: > + $ > ERROR: trailing whitespace > #110: FILE: docs/hypertrace.txt:93: > + $ > ERROR: trailing whitespace > #117: FILE: docs/hypertrace.txt:100: > + $ > ERROR: trailing whitespace > #123: FILE: docs/hypertrace.txt:106: > + $ > ERROR: trailing whitespace > #130: FILE: docs/hypertrace.txt:113: > + $ > ERROR: trailing whitespace > #154: FILE: docs/hypertrace.txt:137: > + $ > ERROR: trailing whitespace > #156: FILE: docs/hypertrace.txt:139: > + $ > ERROR: trailing whitespace > #160: FILE: docs/hypertrace.txt:143: > + $ > ERROR: trailing whitespace > #171: FILE: docs/hypertrace.txt:154: > + $ > ERROR: trailing whitespace > #181: FILE: docs/hypertrace.txt:164: > + $ > total: 10 errors, 0 warnings, 236 lines checked > Your patch has style problems, please review. If any of these errors > are false positives report them to the maintainer, see > CHECKPATCH in MAINTAINERS. The errors above are false positives. AFAIR, in .txt files empty lines in code examples need 4 white spaces to let the wiki properly render them as a single code example block. Thanks, Lluis ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] Checkpatch false positives (Was: Re: [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel) 2016-09-06 9:11 ` [Qemu-devel] Checkpatch false positives (Was: Re: [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel) Lluís Vilanova @ 2016-09-06 9:16 ` Paolo Bonzini 2016-09-06 10:19 ` [Qemu-devel] Checkpatch false positives Lluís Vilanova 0 siblings, 1 reply; 14+ messages in thread From: Paolo Bonzini @ 2016-09-06 9:16 UTC (permalink / raw) To: qemu-devel On 06/09/2016 11:11, Lluís Vilanova wrote: > no-reply writes: >> Checking PATCH 1/6: hypertrace: Add documentation... >> ERROR: trailing whitespace >> #109: FILE: docs/hypertrace.txt:92: >> + $ > >> ERROR: trailing whitespace >> #110: FILE: docs/hypertrace.txt:93: >> + $ > >> ERROR: trailing whitespace >> #117: FILE: docs/hypertrace.txt:100: >> + $ > >> ERROR: trailing whitespace >> #123: FILE: docs/hypertrace.txt:106: >> + $ > >> ERROR: trailing whitespace >> #130: FILE: docs/hypertrace.txt:113: >> + $ > >> ERROR: trailing whitespace >> #154: FILE: docs/hypertrace.txt:137: >> + $ > >> ERROR: trailing whitespace >> #156: FILE: docs/hypertrace.txt:139: >> + $ > >> ERROR: trailing whitespace >> #160: FILE: docs/hypertrace.txt:143: >> + $ > >> ERROR: trailing whitespace >> #171: FILE: docs/hypertrace.txt:154: >> + $ > >> ERROR: trailing whitespace >> #181: FILE: docs/hypertrace.txt:164: >> + $ > >> total: 10 errors, 0 warnings, 236 lines checked > >> Your patch has style problems, please review. If any of these errors >> are false positives report them to the maintainer, see >> CHECKPATCH in MAINTAINERS. > > The errors above are false positives. AFAIR, in .txt files empty lines in code > examples need 4 white spaces to let the wiki properly render them as a single > code example block. Right, can you make a patch for that? It should recognize exactly 4 patches and only apply to .txt and .md files. Paolo ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] Checkpatch false positives 2016-09-06 9:16 ` Paolo Bonzini @ 2016-09-06 10:19 ` Lluís Vilanova 0 siblings, 0 replies; 14+ messages in thread From: Lluís Vilanova @ 2016-09-06 10:19 UTC (permalink / raw) To: Paolo Bonzini; +Cc: qemu-devel Paolo Bonzini writes: > On 06/09/2016 11:11, Lluís Vilanova wrote: >> no-reply writes: >>> Checking PATCH 1/6: hypertrace: Add documentation... >>> ERROR: trailing whitespace >>> #109: FILE: docs/hypertrace.txt:92: >>> + $ >> >>> ERROR: trailing whitespace >>> #110: FILE: docs/hypertrace.txt:93: >>> + $ >> >>> ERROR: trailing whitespace >>> #117: FILE: docs/hypertrace.txt:100: >>> + $ >> >>> ERROR: trailing whitespace >>> #123: FILE: docs/hypertrace.txt:106: >>> + $ >> >>> ERROR: trailing whitespace >>> #130: FILE: docs/hypertrace.txt:113: >>> + $ >> >>> ERROR: trailing whitespace >>> #154: FILE: docs/hypertrace.txt:137: >>> + $ >> >>> ERROR: trailing whitespace >>> #156: FILE: docs/hypertrace.txt:139: >>> + $ >> >>> ERROR: trailing whitespace >>> #160: FILE: docs/hypertrace.txt:143: >>> + $ >> >>> ERROR: trailing whitespace >>> #171: FILE: docs/hypertrace.txt:154: >>> + $ >> >>> ERROR: trailing whitespace >>> #181: FILE: docs/hypertrace.txt:164: >>> + $ >> >>> total: 10 errors, 0 warnings, 236 lines checked >> >>> Your patch has style problems, please review. If any of these errors >>> are false positives report them to the maintainer, see >>> CHECKPATCH in MAINTAINERS. >> >> The errors above are false positives. AFAIR, in .txt files empty lines in code >> examples need 4 white spaces to let the wiki properly render them as a single >> code example block. > Right, can you make a patch for that? It should recognize exactly 4 > patches and only apply to .txt and .md files. Ok. I won't properly check this only applies to lines where surrounding text is 4-column-indented, though, so it can have false negatives. Cheers, Lluis ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2016-09-14 14:37 UTC | newest] Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2016-09-05 18:56 [Qemu-devel] [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel Lluís Vilanova 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 1/6] hypertrace: Add documentation Lluís Vilanova 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 2/6] hypertrace: Add tracing event "guest_hypertrace" Lluís Vilanova 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 3/6] hypertrace: [*-user] Add QEMU-side proxy to "guest_hypertrace" event Lluís Vilanova 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 4/6] hypertrace: [softmmu] " Lluís Vilanova 2016-09-06 1:43 ` Michael S. Tsirkin 2016-09-09 13:19 ` Lluís Vilanova 2016-09-14 14:37 ` Stefan Hajnoczi 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 5/6] hypertrace: Add guest-side user-level library Lluís Vilanova 2016-09-05 18:56 ` [Qemu-devel] [PATCH v2 6/6] hypertrace: Add guest-side Linux module Lluís Vilanova 2016-09-05 19:23 ` [Qemu-devel] [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel no-reply 2016-09-06 9:11 ` [Qemu-devel] Checkpatch false positives (Was: Re: [PATCH v2 0/6] hypertrace: Lightweight guest-to-QEMU trace channel) Lluís Vilanova 2016-09-06 9:16 ` Paolo Bonzini 2016-09-06 10:19 ` [Qemu-devel] Checkpatch false positives Lluís Vilanova
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.