new file mode 100644
@@ -0,0 +1,123 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_find_cid_pid, tracefs_instance_find_cid_pid -
+helper functions to handle tracing guests
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+char pass:[*]*tracefs_find_cid_pid*(int _cid_);
+char pass:[*]*tracefs_instance_find_cid_pid*(struct tracefs_instance pass:[*]_instance_, int _cid_);
+--
+
+DESCRIPTION
+-----------
+The *tracefs_find_cid_pid*() will use tracing to follow the wakeups of connecting to
+the given _cid_ in order to find the pid of the guest thread that belongs to the vsocket cid.
+It will then read the proc file system to find the thread leader, and it will return
+the pid of the thread leader.
+
+The *tracefs_instance_find_cid_pid*() is the same as *tracefs_find_cid_pid*() but defines
+the instance to use to perform the tracing in. If NULL it will use the top level
+buffer to perform the tracing.
+
+RETURN VALUE
+------------
+Both *tracefs_find_cid_pid*() and *tracefs_instance_find_cid_pid*() will return the
+pid of the guest main thread that belongs to the _cid_, or -1 on error (or not found).
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdlib.h>
+#include <unistd.h>
+#include <tracefs.h>
+
+#define MAX_CID 256
+
+static void find_cid(struct tracefs_instance *instance, int cid)
+{
+ int pid;
+
+ pid = tracefs_instance_find_cid_pid(instance, cid);
+ if (pid >= 0)
+ printf("%d\t%d\n", cid, pid);
+}
+
+static int find_cids(void)
+{
+ struct tracefs_instance *instance;
+ char *name;
+ int cid;
+ int ret;
+
+ ret = asprintf(&name, "vsock_find-%d\n", getpid());
+ if (ret < 0)
+ return ret;
+
+ instance = tracefs_instance_create(name);
+ free(name);
+ if (!instance)
+ return -1;
+
+ for (cid = 0; cid < MAX_CID; cid++)
+ find_cid(instance, cid);
+
+ tracefs_event_disable(instance, NULL, NULL);
+ tracefs_instance_destroy(instance);
+ tracefs_instance_free(instance);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ find_cids();
+ exit(0);
+}
+--
+FILES
+-----
+[verse]
+--
+*tracefs.h*
+ Header file to include in order to have access to the library APIs.
+*-ltracefs*
+ Linker switch to add when building a program that uses the library.
+--
+
+SEE ALSO
+--------
+*libtracefs*(3),
+*libtraceevent*(3),
+*trace-cmd*(1)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>
+--
+REPORTING BUGS
+--------------
+Report bugs to <linux-trace-devel@vger.kernel.org>
+
+LICENSE
+-------
+libtracefs is Free Software licensed under the GNU LGPL 2.1
+
+RESOURCES
+---------
+https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/
+
+COPYING
+-------
+Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).
@@ -73,12 +73,19 @@ else
endif
endif
+ifndef NO_VSOCK
+VSOCK_DEFINED := $(shell if (echo "$(pound)include <linux/vm_sockets.h>" | $(CC) -E - >/dev/null 2>&1) ; then echo 1; else echo 0 ; fi)
+else
+VSOCK_DEFINED := 0
+endif
+
etcdir ?= /etc
etcdir_SQ = '$(subst ','\'',$(etcdir))'
export man_dir man_dir_SQ html_install html_install_SQ INSTALL
export img_install img_install_SQ
export DESTDIR DESTDIR_SQ
+export VSOCK_DEFINED
pound := \#
@@ -640,4 +640,8 @@ int tracefs_cpu_flush(struct tracefs_cpu *tcpu, void *buffer);
int tracefs_cpu_flush_write(struct tracefs_cpu *tcpu, int wfd);
int tracefs_cpu_pipe(struct tracefs_cpu *tcpu, int wfd, bool nonblock);
+/* Mapping vsocket cids to pids using tracing */
+int tracefs_instance_find_cid_pid(struct tracefs_instance *instance, int cid);
+int tracefs_find_cid_pid(int cid);
+
#endif /* _TRACE_FS_H */
@@ -22,6 +22,7 @@ EXAMPLES += tracer
EXAMPLES += stream
EXAMPLES += instances-affinity
EXAMPLES += cpu
+EXAMPLES += guest
TARGETS :=
TARGETS += sqlhist
@@ -15,6 +15,9 @@ OBJS += tracefs-dynevents.o
OBJS += tracefs-eprobes.o
OBJS += tracefs-uprobes.o
OBJS += tracefs-record.o
+ifeq ($(VSOCK_DEFINED), 1)
+OBJS += tracefs-vsock.o
+endif
# Order matters for the the three below
OBJS += sqlhist-lex.o
new file mode 100644
@@ -0,0 +1,274 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <linux/vm_sockets.h>
+
+#include <tracefs.h>
+
+static int open_vsock(unsigned int cid, unsigned int port)
+{
+ struct sockaddr_vm addr = {
+ .svm_family = AF_VSOCK,
+ .svm_cid = cid,
+ .svm_port = port,
+ };
+ int sd;
+
+ sd = socket(AF_VSOCK, SOCK_STREAM, 0);
+ if (sd < 0)
+ return -1;
+
+ if (connect(sd, (struct sockaddr *)&addr, sizeof(addr)))
+ return -1;
+
+ return sd;
+}
+
+struct pids {
+ struct pids *next;
+ int pid;
+};
+
+struct trace_info {
+ struct tracefs_instance *instance;
+ struct tep_handle *tep;
+ struct tep_event *wake_up;
+ struct tep_event *kvm_exit;
+ struct tep_format_field *wake_pid;
+ struct pids *pids;
+ int pid;
+};
+
+static void tear_down_trace(struct trace_info *info)
+{
+ tracefs_event_disable(info->instance, NULL, NULL);
+ tep_free(info->tep);
+ info->tep = NULL;
+}
+
+static int add_pid(struct pids **pids, int pid)
+{
+ struct pids *new_pid;
+
+ new_pid = malloc(sizeof(*new_pid));
+ if (!new_pid)
+ return -1;
+
+ new_pid->pid = pid;
+ new_pid->next = *pids;
+ *pids = new_pid;
+ return 0;
+}
+
+static bool match_pid(struct pids *pids, int pid)
+{
+ while (pids) {
+ if (pids->pid == pid)
+ return true;
+ pids = pids->next;
+ }
+ return false;
+}
+
+static int waking_callback(struct tep_event *event, struct tep_record *record,
+ int cpu, void *data)
+{
+ struct trace_info *info = data;
+ unsigned long long val;
+ int flags;
+ int pid;
+ int ret;
+
+ pid = tep_data_pid(event->tep, record);
+ if (!match_pid(info->pids, pid))
+ return 0;
+
+ /* Ignore wakeups in interrupts */
+ flags = tep_data_flags(event->tep, record);
+ if (flags & (TRACE_FLAG_HARDIRQ | TRACE_FLAG_SOFTIRQ))
+ return 0;
+
+ if (!info->wake_pid) {
+ info->wake_pid = tep_find_field(event, "pid");
+
+ if (!info->wake_pid)
+ return -1;
+ }
+
+ ret = tep_read_number_field(info->wake_pid, record->data, &val);
+ if (ret < 0)
+ return -1;
+
+ return add_pid(&info->pids, (int)val);
+}
+
+static int exit_callback(struct tep_event *event, struct tep_record *record,
+ int cpu, void *data)
+{
+ struct trace_info *info = data;
+ int pid;
+
+ pid = tep_data_pid(event->tep, record);
+ if (!match_pid(info->pids, pid))
+ return 0;
+
+ info->pid = pid;
+
+ /* Found the pid we are looking for, stop the trace */
+ return -1;
+}
+
+static int setup_trace(struct trace_info *info)
+{
+ const char *systems[] = { "sched", "kvm", NULL};
+ int ret;
+
+ info->pids = NULL;
+
+ tracefs_trace_off(info->instance);
+ info->tep = tracefs_local_events_system(NULL, systems);
+ if (!info->tep)
+ return -1;
+
+ /*
+ * Follow the wake ups, starting with this pid, to find
+ * the one that exits to the guest. That will be the thread
+ * of the vCPU of the guest.
+ */
+ ret = tracefs_follow_event(info->tep, info->instance,
+ "sched", "sched_waking",
+ waking_callback, info);
+ if (ret < 0)
+ goto fail;
+
+ ret = tracefs_follow_event(info->tep, info->instance,
+ "kvm", "kvm_exit",
+ exit_callback, info);
+ if (ret < 0)
+ goto fail;
+
+ ret = tracefs_event_enable(info->instance, "sched", "sched_waking");
+ if (ret < 0)
+ goto fail;
+
+ ret = tracefs_event_enable(info->instance, "kvm", "kvm_exit");
+ if (ret < 0)
+ goto fail;
+
+ return 0;
+fail:
+ tear_down_trace(info);
+ return -1;
+}
+
+
+static void free_pids(struct pids *pids)
+{
+ struct pids *next;
+
+ while (pids) {
+ next = pids;
+ pids = pids->next;
+ free(next);
+ }
+}
+
+static int find_thread_leader(int pid)
+{
+ FILE *fp;
+ char *path;
+ char *save;
+ char *buf = NULL;
+ size_t l = 0;
+ int tgid = -1;
+
+ if (asprintf(&path, "/proc/%d/status", pid) < 0)
+ return -1;
+
+ fp = fopen(path, "r");
+ free(path);
+ if (!fp)
+ return -1;
+
+ while (getline(&buf, &l, fp) > 0) {
+ char *tok;
+
+ if (strncmp(buf, "Tgid:", 5) != 0)
+ continue;
+ tok = strtok_r(buf, ":", &save);
+ if (!tok)
+ continue;
+ tok = strtok_r(NULL, ":", &save);
+ if (!tok)
+ continue;
+ while (isspace(*tok))
+ tok++;
+ tgid = strtol(tok, NULL, 0);
+ break;
+ }
+ free(buf);
+
+ return tgid > 0 ? tgid : -1;
+}
+
+int tracefs_instance_find_cid_pid(struct tracefs_instance *instance, int cid)
+{
+ struct trace_info info = {};
+ int this_pid = getpid();
+ int ret;
+ int fd;
+
+ info.instance = instance;
+
+ if (setup_trace(&info) < 0)
+ return -1;
+
+ ret = add_pid(&info.pids, this_pid);
+ if (ret < 0)
+ goto out;
+
+ tracefs_instance_file_clear(info.instance, "trace");
+ tracefs_trace_on(info.instance);
+ fd = open_vsock(cid, -1);
+ tracefs_trace_off(info.instance);
+ if (fd >= 0)
+ close(fd);
+ info.pid = -1;
+ ret = tracefs_iterate_raw_events(info.tep, info.instance,
+ NULL, 0, NULL, &info);
+ if (info.pid <= 0)
+ ret = -1;
+ if (ret == 0)
+ ret = find_thread_leader(info.pid);
+
+ out:
+ free_pids(info.pids);
+ info.pids = NULL;
+ tear_down_trace(&info);
+
+ return ret;
+}
+
+int tracefs_find_cid_pid(int cid)
+{
+ struct tracefs_instance *instance;
+ char *name;
+ int ret;
+
+ ret = asprintf(&name, "_tracefs_vsock_find-%d\n", getpid());
+ if (ret < 0)
+ return ret;
+
+ instance = tracefs_instance_create(name);
+ free(name);
+ if (!instance)
+ return -1;
+
+ ret = tracefs_instance_find_cid_pid(instance, cid);
+
+ tracefs_instance_destroy(instance);
+ tracefs_instance_free(instance);
+
+ return ret;
+}