@@ -31,6 +31,7 @@ TRACE_CMD_OBJS += trace-show.o
TRACE_CMD_OBJS += trace-list.o
TRACE_CMD_OBJS += trace-usage.o
TRACE_CMD_OBJS += trace-dump.o
+TRACE_CMD_OBJS += trace-vm.o
ifeq ($(VSOCK_DEFINED), 1)
TRACE_CMD_OBJS += trace-tsync.o
endif
@@ -8,6 +8,7 @@
#include <sys/types.h>
#include <dirent.h> /* for DIR */
+#include <ctype.h> /* for isdigit() */
#include "trace-cmd.h"
#include "event-utils.h"
@@ -283,6 +284,17 @@ void update_first_instance(struct buffer_instance *instance, int topt);
void show_instance_file(struct buffer_instance *instance, const char *name);
+struct trace_guest {
+ char *name;
+ int cid;
+ int pid;
+ int cpu_max;
+ int *cpu_pid;
+};
+struct trace_guest *get_guest_by_cid(unsigned int guest_cid);
+struct trace_guest *get_guest_by_name(char *name);
+void read_qemu_guests(void);
+int get_guest_pid(unsigned int guest_cid);
int get_guest_vcpu_pid(unsigned int guest_cid, unsigned int guest_vcpu);
/* moved from trace-cmd.h */
@@ -313,4 +325,12 @@ void *malloc_or_die(unsigned int size); /* Can be overridden */
void __noreturn __die(const char *fmt, ...);
void __noreturn _vdie(const char *fmt, va_list ap);
+static inline bool is_digits(const char *s)
+{
+ for (; *s; s++)
+ if (!isdigit(*s))
+ return false;
+ return true;
+}
+
#endif /* __TRACE_LOCAL_H */
@@ -3190,239 +3190,37 @@ static int do_accept(int sd)
return -1;
}
-static bool is_digits(const char *s)
+static char *parse_guest_name(char *gname, int *cid, int *port)
{
- for (; *s; s++)
- if (!isdigit(*s))
- return false;
- return true;
-}
-
-struct guest {
- char *name;
- int cid;
- int pid;
- int cpu_max;
- int *cpu_pid;
-};
-
-static struct guest *guests;
-static size_t guests_len;
-
-static int set_vcpu_pid_mapping(struct guest *guest, int cpu, int pid)
-{
- int *cpu_pid;
- int i;
-
- if (cpu >= guest->cpu_max) {
- cpu_pid = realloc(guest->cpu_pid, (cpu + 1) * sizeof(int));
- if (!cpu_pid)
- return -1;
- /* Handle sparse CPU numbers */
- for (i = guest->cpu_max; i < cpu; i++)
- cpu_pid[i] = -1;
- guest->cpu_max = cpu + 1;
- guest->cpu_pid = cpu_pid;
- }
- guest->cpu_pid[cpu] = pid;
- return 0;
-}
-
-static struct guest *get_guest_info(unsigned int guest_cid)
-{
- int i;
-
- if (!guests)
- return NULL;
-
- for (i = 0; i < guests_len; i++)
- if (guest_cid == guests[i].cid)
- return guests + i;
- return NULL;
-}
-
-static char *get_qemu_guest_name(char *arg)
-{
- char *tok, *end = arg;
-
- while ((tok = strsep(&end, ","))) {
- if (strncmp(tok, "guest=", 6) == 0)
- return tok + 6;
- }
-
- return arg;
-}
-
-static int read_qemu_guests_pids(char *guest_task, struct guest *guest)
-{
- struct dirent *entry;
- char path[PATH_MAX];
- char *buf = NULL;
- size_t n = 0;
- int ret = 0;
- long vcpu;
- long pid;
- DIR *dir;
- FILE *f;
-
- snprintf(path, sizeof(path), "/proc/%s/task", guest_task);
- dir = opendir(path);
- if (!dir)
- return -1;
-
- while (!ret && (entry = readdir(dir))) {
- if (!(entry->d_type == DT_DIR && is_digits(entry->d_name)))
- continue;
-
- snprintf(path, sizeof(path), "/proc/%s/task/%s/comm",
- guest_task, entry->d_name);
- f = fopen(path, "r");
- if (!f)
- continue;
-
- if (getline(&buf, &n, f) >= 0 &&
- strncmp(buf, "CPU ", 4) == 0) {
- vcpu = strtol(buf + 4, NULL, 10);
- pid = strtol(entry->d_name, NULL, 10);
- if (vcpu < INT_MAX && pid < INT_MAX &&
- vcpu >= 0 && pid >= 0) {
- if (set_vcpu_pid_mapping(guest, vcpu, pid))
- ret = -1;
- }
- }
-
- fclose(f);
- }
- free(buf);
- return ret;
-}
-
-static void read_qemu_guests(void)
-{
- static bool initialized;
- struct dirent *entry;
- char path[PATH_MAX];
- DIR *dir;
-
- if (initialized)
- return;
-
- initialized = true;
- dir = opendir("/proc");
- if (!dir)
- die("Can not open /proc");
-
- while ((entry = readdir(dir))) {
- bool is_qemu = false, last_was_name = false;
- struct guest guest = {};
- char *p, *arg = NULL;
- size_t arg_size = 0;
- FILE *f;
-
- if (!(entry->d_type == DT_DIR && is_digits(entry->d_name)))
- continue;
-
- guest.pid = atoi(entry->d_name);
- snprintf(path, sizeof(path), "/proc/%s/cmdline", entry->d_name);
- f = fopen(path, "r");
- if (!f)
- continue;
-
- while (getdelim(&arg, &arg_size, 0, f) != -1) {
- if (!is_qemu && strstr(arg, "qemu-system-")) {
- is_qemu = true;
- continue;
- }
-
- if (!is_qemu)
- continue;
-
- if (strcmp(arg, "-name") == 0) {
- last_was_name = true;
- continue;
- }
-
- if (last_was_name) {
- guest.name = strdup(get_qemu_guest_name(arg));
- if (!guest.name)
- die("allocating guest name");
- last_was_name = false;
- continue;
- }
-
- p = strstr(arg, "guest-cid=");
- if (p) {
- guest.cid = atoi(p + 10);
- continue;
- }
- }
-
- if (!is_qemu)
- goto next;
-
- if (read_qemu_guests_pids(entry->d_name, &guest))
- warning("Failed to retrieve VPCU - PID mapping for guest %s",
- guest.name ? guest.name : "Unknown");
-
- guests = realloc(guests, (guests_len + 1) * sizeof(*guests));
- if (!guests)
- die("Can not allocate guest buffer");
- guests[guests_len++] = guest;
-
-next:
- free(arg);
- fclose(f);
- }
-
- closedir(dir);
-}
-
-static char *parse_guest_name(char *guest, int *cid, int *port)
-{
- size_t i;
+ struct trace_guest *guest;
char *p;
*port = -1;
- p = strrchr(guest, ':');
+ p = strrchr(gname, ':');
if (p) {
*p = '\0';
*port = atoi(p + 1);
}
*cid = -1;
- p = strrchr(guest, '@');
+ p = strrchr(gname, '@');
if (p) {
*p = '\0';
*cid = atoi(p + 1);
- } else if (is_digits(guest))
- *cid = atoi(guest);
+ } else if (is_digits(gname))
+ *cid = atoi(gname);
read_qemu_guests();
- for (i = 0; i < guests_len; i++) {
- if ((*cid > 0 && *cid == guests[i].cid) ||
- strcmp(guest, guests[i].name) == 0) {
- *cid = guests[i].cid;
- return guests[i].name;
- }
+ if (*cid > 0)
+ guest = get_guest_by_cid(*cid);
+ else
+ guest = get_guest_by_name(gname);
+ if (guest) {
+ *cid = guest->cid;
+ return guest->name;
}
- return guest;
-}
-
-int get_guest_vcpu_pid(unsigned int guest_cid, unsigned int guest_vcpu)
-{
- int i;
-
- if (!guests)
- return -1;
-
- for (i = 0; i < guests_len; i++) {
- if (guests[i].cpu_pid < 0 || guest_vcpu >= guests[i].cpu_max)
- continue;
- if (guest_cid == guests[i].cid)
- return guests[i].cpu_pid[guest_vcpu];
- }
- return -1;
+ return gname;
}
static void set_prio(int prio)
@@ -4089,7 +3887,7 @@ static void append_buffer(struct tracecmd_output *handle,
static void
add_guest_info(struct tracecmd_output *handle, struct buffer_instance *instance)
{
- struct guest *guest = get_guest_info(instance->cid);
+ struct trace_guest *guest = get_guest_by_cid(instance->cid);
char *buf, *p;
int size;
int i;
new file mode 100644
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2008, 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ * Copyright (C) 2020, VMware, Tzvetomir Stoyanov <tz.stoyanov@gmail.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <limits.h>
+
+#include "trace-local.h"
+#include "trace-msg.h"
+
+static struct trace_guest *guests;
+static size_t guests_len;
+
+static int set_vcpu_pid_mapping(struct trace_guest *guest, int cpu, int pid)
+{
+ int *cpu_pid;
+ int i;
+
+ if (cpu >= guest->cpu_max) {
+ cpu_pid = realloc(guest->cpu_pid, (cpu + 1) * sizeof(int));
+ if (!cpu_pid)
+ return -1;
+ /* Handle sparse CPU numbers */
+ for (i = guest->cpu_max; i < cpu; i++)
+ cpu_pid[i] = -1;
+ guest->cpu_max = cpu + 1;
+ guest->cpu_pid = cpu_pid;
+ }
+ guest->cpu_pid[cpu] = pid;
+ return 0;
+}
+
+struct trace_guest *get_guest_by_cid(unsigned int guest_cid)
+{
+ int i;
+
+ if (!guests)
+ return NULL;
+
+ for (i = 0; i < guests_len; i++)
+ if (guest_cid == guests[i].cid)
+ return guests + i;
+ return NULL;
+}
+
+struct trace_guest *get_guest_by_name(char *name)
+{
+ int i;
+
+ if (!guests)
+ return NULL;
+
+ for (i = 0; i < guests_len; i++)
+ if (strcmp(name, guests[i].name) == 0)
+ return guests + i;
+ return NULL;
+}
+
+static char *get_qemu_guest_name(char *arg)
+{
+ char *tok, *end = arg;
+
+ while ((tok = strsep(&end, ","))) {
+ if (strncmp(tok, "guest=", 6) == 0)
+ return tok + 6;
+ }
+
+ return arg;
+}
+
+static int read_qemu_guests_pids(char *guest_task, struct trace_guest *guest)
+{
+ struct dirent *entry;
+ char path[PATH_MAX];
+ char *buf = NULL;
+ size_t n = 0;
+ int ret = 0;
+ long vcpu;
+ long pid;
+ DIR *dir;
+ FILE *f;
+
+ snprintf(path, sizeof(path), "/proc/%s/task", guest_task);
+ dir = opendir(path);
+ if (!dir)
+ return -1;
+
+ while (!ret && (entry = readdir(dir))) {
+ if (!(entry->d_type == DT_DIR && is_digits(entry->d_name)))
+ continue;
+
+ snprintf(path, sizeof(path), "/proc/%s/task/%s/comm",
+ guest_task, entry->d_name);
+ f = fopen(path, "r");
+ if (!f)
+ continue;
+
+ if (getline(&buf, &n, f) >= 0 &&
+ strncmp(buf, "CPU ", 4) == 0) {
+ vcpu = strtol(buf + 4, NULL, 10);
+ pid = strtol(entry->d_name, NULL, 10);
+ if (vcpu < INT_MAX && pid < INT_MAX &&
+ vcpu >= 0 && pid >= 0) {
+ if (set_vcpu_pid_mapping(guest, vcpu, pid))
+ ret = -1;
+ }
+ }
+
+ fclose(f);
+ }
+ free(buf);
+ return ret;
+}
+
+void read_qemu_guests(void)
+{
+ static bool initialized;
+ struct dirent *entry;
+ char path[PATH_MAX];
+ DIR *dir;
+
+ if (initialized)
+ return;
+
+ initialized = true;
+ dir = opendir("/proc");
+ if (!dir)
+ die("Can not open /proc");
+
+ while ((entry = readdir(dir))) {
+ bool is_qemu = false, last_was_name = false;
+ struct trace_guest guest = {};
+ char *p, *arg = NULL;
+ size_t arg_size = 0;
+ FILE *f;
+
+ if (!(entry->d_type == DT_DIR && is_digits(entry->d_name)))
+ continue;
+
+ guest.pid = atoi(entry->d_name);
+ snprintf(path, sizeof(path), "/proc/%s/cmdline", entry->d_name);
+ f = fopen(path, "r");
+ if (!f)
+ continue;
+
+ while (getdelim(&arg, &arg_size, 0, f) != -1) {
+ if (!is_qemu && strstr(arg, "qemu-system-")) {
+ is_qemu = true;
+ continue;
+ }
+
+ if (!is_qemu)
+ continue;
+
+ if (strcmp(arg, "-name") == 0) {
+ last_was_name = true;
+ continue;
+ }
+
+ if (last_was_name) {
+ guest.name = strdup(get_qemu_guest_name(arg));
+ if (!guest.name)
+ die("allocating guest name");
+ last_was_name = false;
+ continue;
+ }
+
+ p = strstr(arg, "guest-cid=");
+ if (p) {
+ guest.cid = atoi(p + 10);
+ continue;
+ }
+ }
+
+ if (!is_qemu)
+ goto next;
+
+ if (read_qemu_guests_pids(entry->d_name, &guest))
+ warning("Failed to retrieve VPCU - PID mapping for guest %s",
+ guest.name ? guest.name : "Unknown");
+
+ guests = realloc(guests, (guests_len + 1) * sizeof(*guests));
+ if (!guests)
+ die("Can not allocate guest buffer");
+ guests[guests_len++] = guest;
+
+next:
+ free(arg);
+ fclose(f);
+ }
+
+ closedir(dir);
+}
+
+int get_guest_vcpu_pid(unsigned int guest_cid, unsigned int guest_vcpu)
+{
+ int i;
+
+ if (!guests)
+ return -1;
+
+ for (i = 0; i < guests_len; i++) {
+ if (guests[i].cpu_pid < 0 || guest_vcpu >= guests[i].cpu_max)
+ continue;
+ if (guest_cid == guests[i].cid)
+ return guests[i].cpu_pid[guest_vcpu];
+ }
+ return -1;
+}
All trace-cmd internal functions related to VM / guest resolving and mappings are moved from trace-record.c to trace-vm.c. Internal APIs are added to access the guest database, so this functionality can be used by other logic, internally in the trace-cmd context. Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com> --- tracecmd/Makefile | 1 + tracecmd/include/trace-local.h | 20 +++ tracecmd/trace-record.c | 232 +++------------------------------ tracecmd/trace-vm.c | 214 ++++++++++++++++++++++++++++++ 4 files changed, 250 insertions(+), 217 deletions(-) create mode 100644 tracecmd/trace-vm.c