summaryrefslogtreecommitdiff
path: root/tools/verification/rv/src
diff options
context:
space:
mode:
authorDaniel Bristot de Oliveira <bristot@kernel.org>2022-11-11 16:53:05 +0100
committerSteven Rostedt (Google) <rostedt@goodmis.org>2022-12-09 18:06:24 -0500
commit4bc4b131d44c8ead00130fae678ff6c3417d7e13 (patch)
tree40056bc80c2cbe821e1d81dbbabdcc4d447f89f6 /tools/verification/rv/src
parent4c6874374859d89aa6a75019bb0a913369e472c9 (diff)
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>
Diffstat (limited to 'tools/verification/rv/src')
-rw-r--r--tools/verification/rv/src/rv.c185
-rw-r--r--tools/verification/rv/src/trace.c133
-rw-r--r--tools/verification/rv/src/utils.c47
3 files changed, 365 insertions, 0 deletions
diff --git a/tools/verification/rv/src/rv.c b/tools/verification/rv/src/rv.c
new file mode 100644
index 000000000000..a9ea1c891ce0
--- /dev/null
+++ b/tools/verification/rv/src/rv.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rv tool, the interface for the Linux kernel RV subsystem and home of
+ * user-space controlled monitors.
+ *
+ * Copyright (C) 2022 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
+ */
+
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <trace.h>
+#include <utils.h>
+
+static int stop_session;
+
+/*
+ * stop_rv - tell monitors to stop
+ */
+static void stop_rv(int sig)
+{
+ stop_session = 1;
+}
+
+/**
+ * should_stop - check if the monitor should stop.
+ *
+ * Returns 1 if the monitor should stop, 0 otherwise.
+ */
+int should_stop(void)
+{
+ return stop_session;
+}
+
+/*
+ * rv_list - list all available monitors
+ */
+static void rv_list(int argc, char **argv)
+{
+ static const char *const usage[] = {
+ "",
+ " usage: rv list [-h]",
+ "",
+ " list all available monitors",
+ "",
+ " -h/--help: print this menu",
+ NULL,
+ };
+ int i;
+
+ if (argc > 1) {
+ fprintf(stderr, "rv version %s\n", VERSION);
+
+ /* more than 1 is always usage */
+ for (i = 0; usage[i]; i++)
+ fprintf(stderr, "%s\n", usage[i]);
+
+ /* but only -h is valid */
+ if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
+ exit(0);
+ else
+ exit(1);
+ }
+
+ exit(0);
+}
+
+/*
+ * rv_mon - try to run a monitor passed as argument
+ */
+static void rv_mon(int argc, char **argv)
+{
+ char *monitor_name;
+ int i, run;
+
+ static const char *const usage[] = {
+ "",
+ " usage: rv mon [-h] monitor [monitor options]",
+ "",
+ " run a monitor",
+ "",
+ " -h/--help: print this menu",
+ "",
+ " monitor [monitor options]: the monitor, passing",
+ " the arguments to the [monitor options]",
+ NULL,
+ };
+
+ /* requires at least one argument */
+ if (argc == 1) {
+
+ fprintf(stderr, "rv version %s\n", VERSION);
+
+ for (i = 0; usage[i]; i++)
+ fprintf(stderr, "%s\n", usage[i]);
+ exit(1);
+ } else if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+
+ fprintf(stderr, "rv version %s\n", VERSION);
+
+ for (i = 0; usage[i]; i++)
+ fprintf(stderr, "%s\n", usage[i]);
+ exit(0);
+ }
+
+ monitor_name = argv[1];
+ /*
+ * Call all possible monitor implementations, looking
+ * for the [monitor].
+ */
+
+ if (!run)
+ err_msg("rv: monitor %s does not exist\n", monitor_name);
+ exit(!run);
+}
+
+static void usage(int exit_val, const char *fmt, ...)
+{
+ char message[1024];
+ va_list ap;
+ int i;
+
+ static const char *const usage[] = {
+ "",
+ " 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",
+ NULL,
+ };
+
+ va_start(ap, fmt);
+ vsnprintf(message, sizeof(message), fmt, ap);
+ va_end(ap);
+
+ fprintf(stderr, "rv version %s: %s\n", VERSION, message);
+
+ for (i = 0; usage[i]; i++)
+ fprintf(stderr, "%s\n", usage[i]);
+
+ exit(exit_val);
+}
+
+/*
+ * main - select which main sending the command
+ *
+ * main itself redirects the arguments to the sub-commands
+ * to handle the options.
+ *
+ * subcommands should exit.
+ */
+int main(int argc, char **argv)
+{
+ if (geteuid())
+ usage(1, "%s needs root permission", argv[0]);
+
+ if (argc <= 1)
+ usage(1, "%s requires a command", argv[0]);
+
+ if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
+ usage(0, "help");
+
+ if (!strcmp(argv[1], "list"))
+ rv_list(--argc, &argv[1]);
+
+ if (!strcmp(argv[1], "mon")) {
+ /*
+ * monitor's main should monitor should_stop() function.
+ * and exit.
+ */
+ signal(SIGINT, stop_rv);
+
+ rv_mon(argc - 1, &argv[1]);
+ }
+
+ /* invalid sub-command */
+ usage(1, "%s does not know the %s command, old version?", argv[0], argv[1]);
+}
diff --git a/tools/verification/rv/src/trace.c b/tools/verification/rv/src/trace.c
new file mode 100644
index 000000000000..2c7deed47f8d
--- /dev/null
+++ b/tools/verification/rv/src/trace.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * trace helpers.
+ *
+ * Copyright (C) 2022 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
+ */
+
+#include <sys/sendfile.h>
+#include <tracefs.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <rv.h>
+#include <trace.h>
+#include <utils.h>
+
+/*
+ * create_instance - create a trace instance with *instance_name
+ */
+static struct tracefs_instance *create_instance(char *instance_name)
+{
+ return tracefs_instance_create(instance_name);
+}
+
+/*
+ * destroy_instance - remove a trace instance and free the data
+ */
+static void destroy_instance(struct tracefs_instance *inst)
+{
+ tracefs_instance_destroy(inst);
+ tracefs_instance_free(inst);
+}
+
+/**
+ * collect_registered_events - call the existing callback function for the event
+ *
+ * If an event has a registered callback function, call it.
+ * Otherwise, ignore the event.
+ *
+ * Returns 0 if the event was collected, 1 if the tool should stop collecting trace.
+ */
+int
+collect_registered_events(struct tep_event *event, struct tep_record *record,
+ int cpu, void *context)
+{
+ struct trace_instance *trace = context;
+ struct trace_seq *s = trace->seq;
+
+ if (should_stop())
+ return 1;
+
+ if (!event->handler)
+ return 0;
+
+ event->handler(s, record, event, context);
+
+ return 0;
+}
+
+/**
+ * trace_instance_destroy - destroy and free a rv trace instance
+ */
+void trace_instance_destroy(struct trace_instance *trace)
+{
+ if (trace->inst) {
+ destroy_instance(trace->inst);
+ trace->inst = NULL;
+ }
+
+ if (trace->seq) {
+ free(trace->seq);
+ trace->seq = NULL;
+ }
+
+ if (trace->tep) {
+ tep_free(trace->tep);
+ trace->tep = NULL;
+ }
+}
+
+/**
+ * trace_instance_init - create an trace instance
+ *
+ * It is more than the tracefs instance, as it contains other
+ * things required for the tracing, such as the local events and
+ * a seq file.
+ *
+ * Note that the trace instance is returned disabled. This allows
+ * the tool to apply some other configs, like setting priority
+ * to the kernel threads, before starting generating trace entries.
+ *
+ * Returns 0 on success, non-zero otherwise.
+ */
+int trace_instance_init(struct trace_instance *trace, char *name)
+{
+ trace->seq = calloc(1, sizeof(*trace->seq));
+ if (!trace->seq)
+ goto out_err;
+
+ trace_seq_init(trace->seq);
+
+ trace->inst = create_instance(name);
+ if (!trace->inst)
+ goto out_err;
+
+ trace->tep = tracefs_local_events(NULL);
+ if (!trace->tep)
+ goto out_err;
+
+ /*
+ * Let the main enable the record after setting some other
+ * things such as the priority of the tracer's threads.
+ */
+ tracefs_trace_off(trace->inst);
+
+ return 0;
+
+out_err:
+ trace_instance_destroy(trace);
+ return 1;
+}
+
+/**
+ * trace_instance_start - start tracing a given rv instance
+ *
+ * Returns 0 on success, -1 otherwise.
+ */
+int trace_instance_start(struct trace_instance *trace)
+{
+ return tracefs_trace_on(trace->inst);
+}
diff --git a/tools/verification/rv/src/utils.c b/tools/verification/rv/src/utils.c
new file mode 100644
index 000000000000..5677b439dc2f
--- /dev/null
+++ b/tools/verification/rv/src/utils.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * util functions.
+ *
+ * Copyright (C) 2022 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <utils.h>
+
+int config_debug;
+
+#define MAX_MSG_LENGTH 1024
+
+/**
+ * err_msg - print an error message to the stderr
+ */
+void err_msg(const char *fmt, ...)
+{
+ char message[MAX_MSG_LENGTH];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(message, sizeof(message), fmt, ap);
+ va_end(ap);
+
+ fprintf(stderr, "%s", message);
+}
+
+/**
+ * debug_msg - print a debug message to stderr if debug is set
+ */
+void debug_msg(const char *fmt, ...)
+{
+ char message[MAX_MSG_LENGTH];
+ va_list ap;
+
+ if (!config_debug)
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(message, sizeof(message), fmt, ap);
+ va_end(ap);
+
+ fprintf(stderr, "%s", message);
+}