Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rv: Add rv tool

This is the (user-space) runtime verification tool, named rv.

This tool aims to be the interface for in-kernel rv monitors, as
well as the home for monitors in user-space (online asynchronous),
and in *eBPF.

The tool receives a command as the first argument, the current
commands are:

list - list all available monitors
mon - run a given monitor

Each monitor is an independent piece of software inside the
tool and can have their own arguments.

There is no monitor implemented in this patch, it only
adds the basic structure of the tool, based on rtla.

# rv --help
rv version 6.1.0-rc4: help

usage: rv command [-h] [command_options]

-h/--help: print this menu

command: run one of the following command:
list: list all available monitors
mon: run a monitor

[command options]: each command has its own set of options
run rv command -h for further information

*dot2bpf is the next patch set, depends on this, doing cleanups.

Link: https://lkml.kernel.org/r/fb51184f3b95aea0d7bfdc33ec09f4153aee84fa.1668180100.git.bristot@kernel.org

Cc: Jonathan Corbet <corbet@lwn.net>
Signed-off-by: Daniel Bristot de Oliveira <bristot@kernel.org>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

authored by

Daniel Bristot de Oliveira and committed by
Steven Rostedt (Google)
4bc4b131 4c687437

+558
+119
tools/verification/rv/Makefile
··· 1 + NAME := rv 2 + # Follow the kernel version 3 + VERSION := $(shell cat VERSION 2> /dev/null || make -sC ../../.. kernelversion | grep -v make) 4 + 5 + # From libtracefs: 6 + # Makefiles suck: This macro sets a default value of $(2) for the 7 + # variable named by $(1), unless the variable has been set by 8 + # environment or command line. This is necessary for CC and AR 9 + # because make sets default values, so the simpler ?= approach 10 + # won't work as expected. 11 + define allow-override 12 + $(if $(or $(findstring environment,$(origin $(1))),\ 13 + $(findstring command line,$(origin $(1)))),,\ 14 + $(eval $(1) = $(2))) 15 + endef 16 + 17 + # Allow setting CC and AR, or setting CROSS_COMPILE as a prefix. 18 + $(call allow-override,CC,$(CROSS_COMPILE)gcc) 19 + $(call allow-override,AR,$(CROSS_COMPILE)ar) 20 + $(call allow-override,STRIP,$(CROSS_COMPILE)strip) 21 + $(call allow-override,PKG_CONFIG,pkg-config) 22 + $(call allow-override,LD_SO_CONF_PATH,/etc/ld.so.conf.d/) 23 + $(call allow-override,LDCONFIG,ldconfig) 24 + 25 + INSTALL = install 26 + MKDIR = mkdir 27 + FOPTS := -flto=auto -ffat-lto-objects -fexceptions -fstack-protector-strong \ 28 + -fasynchronous-unwind-tables -fstack-clash-protection 29 + WOPTS := -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -Wno-maybe-uninitialized 30 + 31 + TRACEFS_HEADERS := $$($(PKG_CONFIG) --cflags libtracefs) 32 + 33 + CFLAGS := -O -g -DVERSION=\"$(VERSION)\" $(FOPTS) $(MOPTS) $(WOPTS) $(TRACEFS_HEADERS) $(EXTRA_CFLAGS) -I include 34 + LDFLAGS := -ggdb $(EXTRA_LDFLAGS) 35 + LIBS := $$($(PKG_CONFIG) --libs libtracefs) 36 + 37 + SRC := $(wildcard src/*.c) 38 + HDR := $(wildcard src/*.h) 39 + OBJ := $(SRC:.c=.o) 40 + DIRS := src 41 + FILES := Makefile README.txt 42 + CEXT := bz2 43 + TARBALL := $(NAME)-$(VERSION).tar.$(CEXT) 44 + TAROPTS := -cvjf $(TARBALL) 45 + BINDIR := /usr/bin 46 + DATADIR := /usr/share 47 + MANDIR := $(DATADIR)/man 48 + LICDIR := $(DATADIR)/licenses 49 + SRCTREE := $(or $(BUILD_SRC),$(CURDIR)) 50 + 51 + LIBTRACEEVENT_MIN_VERSION = 1.5 52 + LIBTRACEFS_MIN_VERSION = 1.3 53 + 54 + .PHONY: all warnings show_warnings 55 + all: warnings rv 56 + 57 + TEST_LIBTRACEEVENT = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEEVENT_MIN_VERSION) libtraceevent > /dev/null 2>&1 || echo n") 58 + ifeq ("$(TEST_LIBTRACEEVENT)", "n") 59 + WARNINGS = show_warnings 60 + MISSING_LIBS += echo "** libtraceevent version $(LIBTRACEEVENT_MIN_VERSION) or higher"; 61 + MISSING_PACKAGES += "libtraceevent-devel" 62 + MISSING_SOURCE += echo "** https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/ "; 63 + endif 64 + 65 + TEST_LIBTRACEFS = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEFS_MIN_VERSION) libtracefs > /dev/null 2>&1 || echo n") 66 + ifeq ("$(TEST_LIBTRACEFS)", "n") 67 + WARNINGS = show_warnings 68 + MISSING_LIBS += echo "** libtracefs version $(LIBTRACEFS_MIN_VERSION) or higher"; 69 + MISSING_PACKAGES += "libtracefs-devel" 70 + MISSING_SOURCE += echo "** https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ "; 71 + endif 72 + 73 + define show_dependencies 74 + @echo "********************************************"; \ 75 + echo "** NOTICE: Failed build dependencies"; \ 76 + echo "**"; \ 77 + echo "** Required Libraries:"; \ 78 + $(MISSING_LIBS) \ 79 + echo "**"; \ 80 + echo "** Consider installing the latest libtracefs from your"; \ 81 + echo "** distribution, e.g., 'dnf install $(MISSING_PACKAGES)' on Fedora,"; \ 82 + echo "** or from source:"; \ 83 + echo "**"; \ 84 + $(MISSING_SOURCE) \ 85 + echo "**"; \ 86 + echo "********************************************" 87 + endef 88 + 89 + show_warnings: 90 + $(call show_dependencies); 91 + 92 + ifneq ("$(WARNINGS)", "") 93 + ERROR_OUT = $(error Please add the necessary dependencies) 94 + 95 + warnings: $(WARNINGS) 96 + $(ERROR_OUT) 97 + endif 98 + 99 + rv: $(OBJ) 100 + $(CC) -o rv $(LDFLAGS) $(OBJ) $(LIBS) 101 + 102 + .PHONY: install 103 + install: 104 + $(MKDIR) -p $(DESTDIR)$(BINDIR) 105 + $(INSTALL) rv -m 755 $(DESTDIR)$(BINDIR) 106 + $(STRIP) $(DESTDIR)$(BINDIR)/rv 107 + 108 + .PHONY: clean tarball 109 + clean: 110 + @test ! -f rv || rm rv 111 + @test ! -f $(TARBALL) || rm -f $(TARBALL) 112 + @rm -rf *~ $(OBJ) *.tar.$(CEXT) 113 + 114 + tarball: clean 115 + rm -rf $(NAME)-$(VERSION) && mkdir $(NAME)-$(VERSION) 116 + echo $(VERSION) > $(NAME)-$(VERSION)/VERSION 117 + cp -r $(DIRS) $(FILES) $(NAME)-$(VERSION) 118 + tar $(TAROPTS) --exclude='*~' $(NAME)-$(VERSION) 119 + rm -rf $(NAME)-$(VERSION)
+38
tools/verification/rv/README.txt
··· 1 + RV: Runtime Verification 2 + 3 + Runtime Verification (RV) is a lightweight (yet rigorous) method that 4 + complements classical exhaustive verification techniques (such as model 5 + checking and theorem proving) with a more practical approach for 6 + complex systems. 7 + 8 + The rv tool is the interface for a collection of monitors that aim 9 + analysing the logical and timing behavior of Linux. 10 + 11 + Installing RV 12 + 13 + RV depends on the following libraries and tools: 14 + 15 + - libtracefs 16 + - libtraceevent 17 + 18 + It also depends on python3-docutils to compile man pages. 19 + 20 + For development, we suggest the following steps for compiling rtla: 21 + 22 + $ git clone git://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git 23 + $ cd libtraceevent/ 24 + $ make 25 + $ sudo make install 26 + $ cd .. 27 + $ git clone git://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git 28 + $ cd libtracefs/ 29 + $ make 30 + $ sudo make install 31 + $ cd .. 32 + $ cd $rv_src 33 + $ make 34 + $ sudo make install 35 + 36 + For further information, please see rv manpage and the kernel documentation: 37 + Runtime Verification: 38 + Documentation/trace/rv/runtime-verification.rst
+12
tools/verification/rv/include/rv.h
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #define MAX_DESCRIPTION 1024 4 + #define MAX_DA_NAME_LEN 24 5 + 6 + struct monitor { 7 + char name[MAX_DA_NAME_LEN]; 8 + char desc[MAX_DESCRIPTION]; 9 + int enabled; 10 + }; 11 + 12 + int should_stop(void);
+16
tools/verification/rv/include/trace.h
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <tracefs.h> 4 + 5 + struct trace_instance { 6 + struct tracefs_instance *inst; 7 + struct tep_handle *tep; 8 + struct trace_seq *seq; 9 + }; 10 + 11 + int trace_instance_init(struct trace_instance *trace, char *name); 12 + int trace_instance_start(struct trace_instance *trace); 13 + void trace_instance_destroy(struct trace_instance *trace); 14 + 15 + int collect_registered_events(struct tep_event *event, struct tep_record *record, 16 + int cpu, void *context);
+8
tools/verification/rv/include/utils.h
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #define MAX_PATH 1024 4 + 5 + void debug_msg(const char *fmt, ...); 6 + void err_msg(const char *fmt, ...); 7 + 8 + extern int config_debug;
+185
tools/verification/rv/src/rv.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * rv tool, the interface for the Linux kernel RV subsystem and home of 4 + * user-space controlled monitors. 5 + * 6 + * Copyright (C) 2022 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org> 7 + */ 8 + 9 + #include <stdlib.h> 10 + #include <signal.h> 11 + #include <unistd.h> 12 + 13 + #include <trace.h> 14 + #include <utils.h> 15 + 16 + static int stop_session; 17 + 18 + /* 19 + * stop_rv - tell monitors to stop 20 + */ 21 + static void stop_rv(int sig) 22 + { 23 + stop_session = 1; 24 + } 25 + 26 + /** 27 + * should_stop - check if the monitor should stop. 28 + * 29 + * Returns 1 if the monitor should stop, 0 otherwise. 30 + */ 31 + int should_stop(void) 32 + { 33 + return stop_session; 34 + } 35 + 36 + /* 37 + * rv_list - list all available monitors 38 + */ 39 + static void rv_list(int argc, char **argv) 40 + { 41 + static const char *const usage[] = { 42 + "", 43 + " usage: rv list [-h]", 44 + "", 45 + " list all available monitors", 46 + "", 47 + " -h/--help: print this menu", 48 + NULL, 49 + }; 50 + int i; 51 + 52 + if (argc > 1) { 53 + fprintf(stderr, "rv version %s\n", VERSION); 54 + 55 + /* more than 1 is always usage */ 56 + for (i = 0; usage[i]; i++) 57 + fprintf(stderr, "%s\n", usage[i]); 58 + 59 + /* but only -h is valid */ 60 + if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) 61 + exit(0); 62 + else 63 + exit(1); 64 + } 65 + 66 + exit(0); 67 + } 68 + 69 + /* 70 + * rv_mon - try to run a monitor passed as argument 71 + */ 72 + static void rv_mon(int argc, char **argv) 73 + { 74 + char *monitor_name; 75 + int i, run; 76 + 77 + static const char *const usage[] = { 78 + "", 79 + " usage: rv mon [-h] monitor [monitor options]", 80 + "", 81 + " run a monitor", 82 + "", 83 + " -h/--help: print this menu", 84 + "", 85 + " monitor [monitor options]: the monitor, passing", 86 + " the arguments to the [monitor options]", 87 + NULL, 88 + }; 89 + 90 + /* requires at least one argument */ 91 + if (argc == 1) { 92 + 93 + fprintf(stderr, "rv version %s\n", VERSION); 94 + 95 + for (i = 0; usage[i]; i++) 96 + fprintf(stderr, "%s\n", usage[i]); 97 + exit(1); 98 + } else if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { 99 + 100 + fprintf(stderr, "rv version %s\n", VERSION); 101 + 102 + for (i = 0; usage[i]; i++) 103 + fprintf(stderr, "%s\n", usage[i]); 104 + exit(0); 105 + } 106 + 107 + monitor_name = argv[1]; 108 + /* 109 + * Call all possible monitor implementations, looking 110 + * for the [monitor]. 111 + */ 112 + 113 + if (!run) 114 + err_msg("rv: monitor %s does not exist\n", monitor_name); 115 + exit(!run); 116 + } 117 + 118 + static void usage(int exit_val, const char *fmt, ...) 119 + { 120 + char message[1024]; 121 + va_list ap; 122 + int i; 123 + 124 + static const char *const usage[] = { 125 + "", 126 + " usage: rv command [-h] [command_options]", 127 + "", 128 + " -h/--help: print this menu", 129 + "", 130 + " command: run one of the following command:", 131 + " list: list all available monitors", 132 + " mon: run a monitor", 133 + "", 134 + " [command options]: each command has its own set of options", 135 + " run rv command -h for further information", 136 + NULL, 137 + }; 138 + 139 + va_start(ap, fmt); 140 + vsnprintf(message, sizeof(message), fmt, ap); 141 + va_end(ap); 142 + 143 + fprintf(stderr, "rv version %s: %s\n", VERSION, message); 144 + 145 + for (i = 0; usage[i]; i++) 146 + fprintf(stderr, "%s\n", usage[i]); 147 + 148 + exit(exit_val); 149 + } 150 + 151 + /* 152 + * main - select which main sending the command 153 + * 154 + * main itself redirects the arguments to the sub-commands 155 + * to handle the options. 156 + * 157 + * subcommands should exit. 158 + */ 159 + int main(int argc, char **argv) 160 + { 161 + if (geteuid()) 162 + usage(1, "%s needs root permission", argv[0]); 163 + 164 + if (argc <= 1) 165 + usage(1, "%s requires a command", argv[0]); 166 + 167 + if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) 168 + usage(0, "help"); 169 + 170 + if (!strcmp(argv[1], "list")) 171 + rv_list(--argc, &argv[1]); 172 + 173 + if (!strcmp(argv[1], "mon")) { 174 + /* 175 + * monitor's main should monitor should_stop() function. 176 + * and exit. 177 + */ 178 + signal(SIGINT, stop_rv); 179 + 180 + rv_mon(argc - 1, &argv[1]); 181 + } 182 + 183 + /* invalid sub-command */ 184 + usage(1, "%s does not know the %s command, old version?", argv[0], argv[1]); 185 + }
+133
tools/verification/rv/src/trace.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * trace helpers. 4 + * 5 + * Copyright (C) 2022 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org> 6 + */ 7 + 8 + #include <sys/sendfile.h> 9 + #include <tracefs.h> 10 + #include <signal.h> 11 + #include <stdlib.h> 12 + #include <unistd.h> 13 + #include <errno.h> 14 + 15 + #include <rv.h> 16 + #include <trace.h> 17 + #include <utils.h> 18 + 19 + /* 20 + * create_instance - create a trace instance with *instance_name 21 + */ 22 + static struct tracefs_instance *create_instance(char *instance_name) 23 + { 24 + return tracefs_instance_create(instance_name); 25 + } 26 + 27 + /* 28 + * destroy_instance - remove a trace instance and free the data 29 + */ 30 + static void destroy_instance(struct tracefs_instance *inst) 31 + { 32 + tracefs_instance_destroy(inst); 33 + tracefs_instance_free(inst); 34 + } 35 + 36 + /** 37 + * collect_registered_events - call the existing callback function for the event 38 + * 39 + * If an event has a registered callback function, call it. 40 + * Otherwise, ignore the event. 41 + * 42 + * Returns 0 if the event was collected, 1 if the tool should stop collecting trace. 43 + */ 44 + int 45 + collect_registered_events(struct tep_event *event, struct tep_record *record, 46 + int cpu, void *context) 47 + { 48 + struct trace_instance *trace = context; 49 + struct trace_seq *s = trace->seq; 50 + 51 + if (should_stop()) 52 + return 1; 53 + 54 + if (!event->handler) 55 + return 0; 56 + 57 + event->handler(s, record, event, context); 58 + 59 + return 0; 60 + } 61 + 62 + /** 63 + * trace_instance_destroy - destroy and free a rv trace instance 64 + */ 65 + void trace_instance_destroy(struct trace_instance *trace) 66 + { 67 + if (trace->inst) { 68 + destroy_instance(trace->inst); 69 + trace->inst = NULL; 70 + } 71 + 72 + if (trace->seq) { 73 + free(trace->seq); 74 + trace->seq = NULL; 75 + } 76 + 77 + if (trace->tep) { 78 + tep_free(trace->tep); 79 + trace->tep = NULL; 80 + } 81 + } 82 + 83 + /** 84 + * trace_instance_init - create an trace instance 85 + * 86 + * It is more than the tracefs instance, as it contains other 87 + * things required for the tracing, such as the local events and 88 + * a seq file. 89 + * 90 + * Note that the trace instance is returned disabled. This allows 91 + * the tool to apply some other configs, like setting priority 92 + * to the kernel threads, before starting generating trace entries. 93 + * 94 + * Returns 0 on success, non-zero otherwise. 95 + */ 96 + int trace_instance_init(struct trace_instance *trace, char *name) 97 + { 98 + trace->seq = calloc(1, sizeof(*trace->seq)); 99 + if (!trace->seq) 100 + goto out_err; 101 + 102 + trace_seq_init(trace->seq); 103 + 104 + trace->inst = create_instance(name); 105 + if (!trace->inst) 106 + goto out_err; 107 + 108 + trace->tep = tracefs_local_events(NULL); 109 + if (!trace->tep) 110 + goto out_err; 111 + 112 + /* 113 + * Let the main enable the record after setting some other 114 + * things such as the priority of the tracer's threads. 115 + */ 116 + tracefs_trace_off(trace->inst); 117 + 118 + return 0; 119 + 120 + out_err: 121 + trace_instance_destroy(trace); 122 + return 1; 123 + } 124 + 125 + /** 126 + * trace_instance_start - start tracing a given rv instance 127 + * 128 + * Returns 0 on success, -1 otherwise. 129 + */ 130 + int trace_instance_start(struct trace_instance *trace) 131 + { 132 + return tracefs_trace_on(trace->inst); 133 + }
+47
tools/verification/rv/src/utils.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * util functions. 4 + * 5 + * Copyright (C) 2022 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org> 6 + */ 7 + 8 + #include <stdarg.h> 9 + #include <stdio.h> 10 + #include <utils.h> 11 + 12 + int config_debug; 13 + 14 + #define MAX_MSG_LENGTH 1024 15 + 16 + /** 17 + * err_msg - print an error message to the stderr 18 + */ 19 + void err_msg(const char *fmt, ...) 20 + { 21 + char message[MAX_MSG_LENGTH]; 22 + va_list ap; 23 + 24 + va_start(ap, fmt); 25 + vsnprintf(message, sizeof(message), fmt, ap); 26 + va_end(ap); 27 + 28 + fprintf(stderr, "%s", message); 29 + } 30 + 31 + /** 32 + * debug_msg - print a debug message to stderr if debug is set 33 + */ 34 + void debug_msg(const char *fmt, ...) 35 + { 36 + char message[MAX_MSG_LENGTH]; 37 + va_list ap; 38 + 39 + if (!config_debug) 40 + return; 41 + 42 + va_start(ap, fmt); 43 + vsnprintf(message, sizeof(message), fmt, ap); 44 + va_end(ap); 45 + 46 + fprintf(stderr, "%s", message); 47 + }