diff options
Diffstat (limited to 'tools/lib')
29 files changed, 602 insertions, 436 deletions
diff --git a/tools/lib/api/Build b/tools/lib/api/Build index 3653965cf..e8b8a23b9 100644 --- a/tools/lib/api/Build +++ b/tools/lib/api/Build @@ -1,2 +1,3 @@ libapi-y += fd/ libapi-y += fs/ +libapi-y += cpu.o diff --git a/tools/lib/api/Makefile b/tools/lib/api/Makefile index fe1b02c2c..d85904dc9 100644 --- a/tools/lib/api/Makefile +++ b/tools/lib/api/Makefile @@ -21,12 +21,14 @@ CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 RM = rm -f -build := -f $(srctree)/tools/build/Makefile.build dir=. obj API_IN := $(OUTPUT)libapi-in.o +all: + export srctree OUTPUT CC LD CFLAGS V +include $(srctree)/tools/build/Makefile.include -all: $(LIBFILE) +all: fixdep $(LIBFILE) $(API_IN): FORCE @$(MAKE) $(build)=libapi diff --git a/tools/lib/api/cpu.c b/tools/lib/api/cpu.c new file mode 100644 index 000000000..8c6489356 --- /dev/null +++ b/tools/lib/api/cpu.c @@ -0,0 +1,18 @@ +#include <stdio.h> + +#include "cpu.h" +#include "fs/fs.h" + +int cpu__get_max_freq(unsigned long long *freq) +{ + char entry[PATH_MAX]; + int cpu; + + if (sysfs__read_int("devices/system/cpu/online", &cpu) < 0) + return -1; + + snprintf(entry, sizeof(entry), + "devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", cpu); + + return sysfs__read_ull(entry, freq); +} diff --git a/tools/lib/api/cpu.h b/tools/lib/api/cpu.h new file mode 100644 index 000000000..81e9d3955 --- /dev/null +++ b/tools/lib/api/cpu.h @@ -0,0 +1,6 @@ +#ifndef __API_CPU__ +#define __API_CPU__ + +int cpu__get_max_freq(unsigned long long *freq); + +#endif /* __API_CPU__ */ diff --git a/tools/lib/api/fs/Build b/tools/lib/api/fs/Build index 6de5a4f0b..f4ed9629a 100644 --- a/tools/lib/api/fs/Build +++ b/tools/lib/api/fs/Build @@ -1,4 +1,2 @@ libapi-y += fs.o -libapi-y += debugfs.o -libapi-y += findfs.o -libapi-y += tracefs.o +libapi-y += tracing_path.o diff --git a/tools/lib/api/fs/debugfs.c b/tools/lib/api/fs/debugfs.c deleted file mode 100644 index eb7cf4d18..000000000 --- a/tools/lib/api/fs/debugfs.c +++ /dev/null @@ -1,129 +0,0 @@ -#define _GNU_SOURCE -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <stdbool.h> -#include <sys/vfs.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/mount.h> -#include <linux/kernel.h> - -#include "debugfs.h" -#include "tracefs.h" - -#ifndef DEBUGFS_DEFAULT_PATH -#define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug" -#endif - -char debugfs_mountpoint[PATH_MAX + 1] = DEBUGFS_DEFAULT_PATH; - -static const char * const debugfs_known_mountpoints[] = { - DEBUGFS_DEFAULT_PATH, - "/debug", - 0, -}; - -static bool debugfs_found; - -bool debugfs_configured(void) -{ - return debugfs_find_mountpoint() != NULL; -} - -/* find the path to the mounted debugfs */ -const char *debugfs_find_mountpoint(void) -{ - const char *ret; - - if (debugfs_found) - return (const char *)debugfs_mountpoint; - - ret = find_mountpoint("debugfs", (long) DEBUGFS_MAGIC, - debugfs_mountpoint, PATH_MAX + 1, - debugfs_known_mountpoints); - if (ret) - debugfs_found = true; - - return ret; -} - -/* mount the debugfs somewhere if it's not mounted */ -char *debugfs_mount(const char *mountpoint) -{ - /* see if it's already mounted */ - if (debugfs_find_mountpoint()) - goto out; - - /* if not mounted and no argument */ - if (mountpoint == NULL) { - /* see if environment variable set */ - mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT); - /* if no environment variable, use default */ - if (mountpoint == NULL) - mountpoint = DEBUGFS_DEFAULT_PATH; - } - - if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0) - return NULL; - - /* save the mountpoint */ - debugfs_found = true; - strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); -out: - return debugfs_mountpoint; -} - -int debugfs__strerror_open(int err, char *buf, size_t size, const char *filename) -{ - char sbuf[128]; - - switch (err) { - case ENOENT: - if (debugfs_found) { - snprintf(buf, size, - "Error:\tFile %s/%s not found.\n" - "Hint:\tPerhaps this kernel misses some CONFIG_ setting to enable this feature?.\n", - debugfs_mountpoint, filename); - break; - } - snprintf(buf, size, "%s", - "Error:\tUnable to find debugfs\n" - "Hint:\tWas your kernel compiled with debugfs support?\n" - "Hint:\tIs the debugfs filesystem mounted?\n" - "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'"); - break; - case EACCES: { - const char *mountpoint = debugfs_mountpoint; - - if (!access(debugfs_mountpoint, R_OK) && strncmp(filename, "tracing/", 8) == 0) { - const char *tracefs_mntpoint = tracefs_find_mountpoint(); - - if (tracefs_mntpoint) - mountpoint = tracefs_mntpoint; - } - - snprintf(buf, size, - "Error:\tNo permissions to read %s/%s\n" - "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n", - debugfs_mountpoint, filename, mountpoint); - } - break; - default: - snprintf(buf, size, "%s", strerror_r(err, sbuf, sizeof(sbuf))); - break; - } - - return 0; -} - -int debugfs__strerror_open_tp(int err, char *buf, size_t size, const char *sys, const char *name) -{ - char path[PATH_MAX]; - - snprintf(path, PATH_MAX, "tracing/events/%s/%s", sys, name ?: "*"); - - return debugfs__strerror_open(err, buf, size, path); -} diff --git a/tools/lib/api/fs/debugfs.h b/tools/lib/api/fs/debugfs.h deleted file mode 100644 index 455023698..000000000 --- a/tools/lib/api/fs/debugfs.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef __API_DEBUGFS_H__ -#define __API_DEBUGFS_H__ - -#include "findfs.h" - -#ifndef DEBUGFS_MAGIC -#define DEBUGFS_MAGIC 0x64626720 -#endif - -#ifndef PERF_DEBUGFS_ENVIRONMENT -#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR" -#endif - -bool debugfs_configured(void); -const char *debugfs_find_mountpoint(void); -char *debugfs_mount(const char *mountpoint); - -extern char debugfs_mountpoint[]; - -int debugfs__strerror_open(int err, char *buf, size_t size, const char *filename); -int debugfs__strerror_open_tp(int err, char *buf, size_t size, const char *sys, const char *name); - -#endif /* __API_DEBUGFS_H__ */ diff --git a/tools/lib/api/fs/findfs.c b/tools/lib/api/fs/findfs.c deleted file mode 100644 index 49946cb6d..000000000 --- a/tools/lib/api/fs/findfs.c +++ /dev/null @@ -1,63 +0,0 @@ -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdbool.h> -#include <sys/vfs.h> - -#include "findfs.h" - -/* verify that a mountpoint is actually the type we want */ - -int valid_mountpoint(const char *mount, long magic) -{ - struct statfs st_fs; - - if (statfs(mount, &st_fs) < 0) - return -ENOENT; - else if ((long)st_fs.f_type != magic) - return -ENOENT; - - return 0; -} - -/* find the path to a mounted file system */ -const char *find_mountpoint(const char *fstype, long magic, - char *mountpoint, int len, - const char * const *known_mountpoints) -{ - const char * const *ptr; - char format[128]; - char type[100]; - FILE *fp; - - if (known_mountpoints) { - ptr = known_mountpoints; - while (*ptr) { - if (valid_mountpoint(*ptr, magic) == 0) { - strncpy(mountpoint, *ptr, len - 1); - mountpoint[len-1] = 0; - return mountpoint; - } - ptr++; - } - } - - /* give up and parse /proc/mounts */ - fp = fopen("/proc/mounts", "r"); - if (fp == NULL) - return NULL; - - snprintf(format, 128, "%%*s %%%ds %%99s %%*s %%*d %%*d\n", len); - - while (fscanf(fp, format, mountpoint, type) == 2) { - if (strcmp(type, fstype) == 0) - break; - } - fclose(fp); - - if (strcmp(type, fstype) != 0) - return NULL; - - return mountpoint; -} diff --git a/tools/lib/api/fs/findfs.h b/tools/lib/api/fs/findfs.h deleted file mode 100644 index b6f5d05ac..000000000 --- a/tools/lib/api/fs/findfs.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef __API_FINDFS_H__ -#define __API_FINDFS_H__ - -#include <stdbool.h> - -#define _STR(x) #x -#define STR(x) _STR(x) - -/* - * On most systems <limits.h> would have given us this, but not on some systems - * (e.g. GNU/Hurd). - */ -#ifndef PATH_MAX -#define PATH_MAX 4096 -#endif - -const char *find_mountpoint(const char *fstype, long magic, - char *mountpoint, int len, - const char * const *known_mountpoints); - -int valid_mountpoint(const char *mount, long magic); - -#endif /* __API_FINDFS_H__ */ diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index 128ef6332..459599d1b 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -1,7 +1,6 @@ -/* TODO merge/factor in debugfs.c here */ - #include <ctype.h> #include <errno.h> +#include <limits.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -11,10 +10,29 @@ #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> +#include <sys/mount.h> -#include "debugfs.h" #include "fs.h" +#define _STR(x) #x +#define STR(x) _STR(x) + +#ifndef SYSFS_MAGIC +#define SYSFS_MAGIC 0x62656572 +#endif + +#ifndef PROC_SUPER_MAGIC +#define PROC_SUPER_MAGIC 0x9fa0 +#endif + +#ifndef DEBUGFS_MAGIC +#define DEBUGFS_MAGIC 0x64626720 +#endif + +#ifndef TRACEFS_MAGIC +#define TRACEFS_MAGIC 0x74726163 +#endif + static const char * const sysfs__fs_known_mountpoints[] = { "/sys", 0, @@ -25,19 +43,48 @@ static const char * const procfs__known_mountpoints[] = { 0, }; +#ifndef DEBUGFS_DEFAULT_PATH +#define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug" +#endif + +static const char * const debugfs__known_mountpoints[] = { + DEBUGFS_DEFAULT_PATH, + "/debug", + 0, +}; + + +#ifndef TRACEFS_DEFAULT_PATH +#define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing" +#endif + +static const char * const tracefs__known_mountpoints[] = { + TRACEFS_DEFAULT_PATH, + "/sys/kernel/debug/tracing", + "/tracing", + "/trace", + 0, +}; + struct fs { const char *name; const char * const *mounts; - char path[PATH_MAX + 1]; + char path[PATH_MAX]; bool found; long magic; }; enum { - FS__SYSFS = 0, - FS__PROCFS = 1, + FS__SYSFS = 0, + FS__PROCFS = 1, + FS__DEBUGFS = 2, + FS__TRACEFS = 3, }; +#ifndef TRACEFS_MAGIC +#define TRACEFS_MAGIC 0x74726163 +#endif + static struct fs fs__entries[] = { [FS__SYSFS] = { .name = "sysfs", @@ -49,6 +96,16 @@ static struct fs fs__entries[] = { .mounts = procfs__known_mountpoints, .magic = PROC_SUPER_MAGIC, }, + [FS__DEBUGFS] = { + .name = "debugfs", + .mounts = debugfs__known_mountpoints, + .magic = DEBUGFS_MAGIC, + }, + [FS__TRACEFS] = { + .name = "tracefs", + .mounts = tracefs__known_mountpoints, + .magic = TRACEFS_MAGIC, + }, }; static bool fs__read_mounts(struct fs *fs) @@ -159,14 +216,54 @@ static const char *fs__mountpoint(int idx) return fs__get_mountpoint(fs); } -#define FS__MOUNTPOINT(name, idx) \ -const char *name##__mountpoint(void) \ -{ \ - return fs__mountpoint(idx); \ +static const char *mount_overload(struct fs *fs) +{ + size_t name_len = strlen(fs->name); + /* "PERF_" + name + "_ENVIRONMENT" + '\0' */ + char upper_name[5 + name_len + 12 + 1]; + + snprintf(upper_name, name_len, "PERF_%s_ENVIRONMENT", fs->name); + mem_toupper(upper_name, name_len); + + return getenv(upper_name) ?: *fs->mounts; +} + +static const char *fs__mount(int idx) +{ + struct fs *fs = &fs__entries[idx]; + const char *mountpoint; + + if (fs__mountpoint(idx)) + return (const char *)fs->path; + + mountpoint = mount_overload(fs); + + if (mount(NULL, mountpoint, fs->name, 0, NULL) < 0) + return NULL; + + return fs__check_mounts(fs) ? fs->path : NULL; +} + +#define FS(name, idx) \ +const char *name##__mountpoint(void) \ +{ \ + return fs__mountpoint(idx); \ +} \ + \ +const char *name##__mount(void) \ +{ \ + return fs__mount(idx); \ +} \ + \ +bool name##__configured(void) \ +{ \ + return name##__mountpoint() != NULL; \ } -FS__MOUNTPOINT(sysfs, FS__SYSFS); -FS__MOUNTPOINT(procfs, FS__PROCFS); +FS(sysfs, FS__SYSFS); +FS(procfs, FS__PROCFS); +FS(debugfs, FS__DEBUGFS); +FS(tracefs, FS__TRACEFS); int filename__read_int(const char *filename, int *value) { @@ -185,6 +282,50 @@ int filename__read_int(const char *filename, int *value) return err; } +int filename__read_ull(const char *filename, unsigned long long *value) +{ + char line[64]; + int fd = open(filename, O_RDONLY), err = -1; + + if (fd < 0) + return -1; + + if (read(fd, line, sizeof(line)) > 0) { + *value = strtoull(line, NULL, 10); + if (*value != ULLONG_MAX) + err = 0; + } + + close(fd); + return err; +} + +int sysfs__read_ull(const char *entry, unsigned long long *value) +{ + char path[PATH_MAX]; + const char *sysfs = sysfs__mountpoint(); + + if (!sysfs) + return -1; + + snprintf(path, sizeof(path), "%s/%s", sysfs, entry); + + return filename__read_ull(path, value); +} + +int sysfs__read_int(const char *entry, int *value) +{ + char path[PATH_MAX]; + const char *sysfs = sysfs__mountpoint(); + + if (!sysfs) + return -1; + + snprintf(path, sizeof(path), "%s/%s", sysfs, entry); + + return filename__read_int(path, value); +} + int sysctl__read_int(const char *sysctl, int *value) { char path[PATH_MAX]; diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index 6caa2bbc6..d024a7f68 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h @@ -1,17 +1,33 @@ #ifndef __API_FS__ #define __API_FS__ -#ifndef SYSFS_MAGIC -#define SYSFS_MAGIC 0x62656572 -#endif +#include <stdbool.h> -#ifndef PROC_SUPER_MAGIC -#define PROC_SUPER_MAGIC 0x9fa0 +/* + * On most systems <limits.h> would have given us this, but not on some systems + * (e.g. GNU/Hurd). + */ +#ifndef PATH_MAX +#define PATH_MAX 4096 #endif -const char *sysfs__mountpoint(void); -const char *procfs__mountpoint(void); +#define FS(name) \ + const char *name##__mountpoint(void); \ + const char *name##__mount(void); \ + bool name##__configured(void); \ + +FS(sysfs) +FS(procfs) +FS(debugfs) +FS(tracefs) + +#undef FS + int filename__read_int(const char *filename, int *value); +int filename__read_ull(const char *filename, unsigned long long *value); + int sysctl__read_int(const char *sysctl, int *value); +int sysfs__read_int(const char *entry, int *value); +int sysfs__read_ull(const char *entry, unsigned long long *value); #endif /* __API_FS__ */ diff --git a/tools/lib/api/fs/tracefs.c b/tools/lib/api/fs/tracefs.c deleted file mode 100644 index e4aa9688b..000000000 --- a/tools/lib/api/fs/tracefs.c +++ /dev/null @@ -1,78 +0,0 @@ -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <stdbool.h> -#include <sys/vfs.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/mount.h> -#include <linux/kernel.h> - -#include "tracefs.h" - -#ifndef TRACEFS_DEFAULT_PATH -#define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing" -#endif - -char tracefs_mountpoint[PATH_MAX + 1] = TRACEFS_DEFAULT_PATH; - -static const char * const tracefs_known_mountpoints[] = { - TRACEFS_DEFAULT_PATH, - "/sys/kernel/debug/tracing", - "/tracing", - "/trace", - 0, -}; - -static bool tracefs_found; - -bool tracefs_configured(void) -{ - return tracefs_find_mountpoint() != NULL; -} - -/* find the path to the mounted tracefs */ -const char *tracefs_find_mountpoint(void) -{ - const char *ret; - - if (tracefs_found) - return (const char *)tracefs_mountpoint; - - ret = find_mountpoint("tracefs", (long) TRACEFS_MAGIC, - tracefs_mountpoint, PATH_MAX + 1, - tracefs_known_mountpoints); - - if (ret) - tracefs_found = true; - - return ret; -} - -/* mount the tracefs somewhere if it's not mounted */ -char *tracefs_mount(const char *mountpoint) -{ - /* see if it's already mounted */ - if (tracefs_find_mountpoint()) - goto out; - - /* if not mounted and no argument */ - if (mountpoint == NULL) { - /* see if environment variable set */ - mountpoint = getenv(PERF_TRACEFS_ENVIRONMENT); - /* if no environment variable, use default */ - if (mountpoint == NULL) - mountpoint = TRACEFS_DEFAULT_PATH; - } - - if (mount(NULL, mountpoint, "tracefs", 0, NULL) < 0) - return NULL; - - /* save the mountpoint */ - tracefs_found = true; - strncpy(tracefs_mountpoint, mountpoint, sizeof(tracefs_mountpoint)); -out: - return tracefs_mountpoint; -} diff --git a/tools/lib/api/fs/tracefs.h b/tools/lib/api/fs/tracefs.h deleted file mode 100644 index da780ac49..000000000 --- a/tools/lib/api/fs/tracefs.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __API_TRACEFS_H__ -#define __API_TRACEFS_H__ - -#include "findfs.h" - -#ifndef TRACEFS_MAGIC -#define TRACEFS_MAGIC 0x74726163 -#endif - -#ifndef PERF_TRACEFS_ENVIRONMENT -#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR" -#endif - -bool tracefs_configured(void); -const char *tracefs_find_mountpoint(void); -int tracefs_valid_mountpoint(const char *debugfs); -char *tracefs_mount(const char *mountpoint); - -extern char tracefs_mountpoint[]; - -#endif /* __API_DEBUGFS_H__ */ diff --git a/tools/lib/api/fs/tracing_path.c b/tools/lib/api/fs/tracing_path.c new file mode 100644 index 000000000..a26bb5ea8 --- /dev/null +++ b/tools/lib/api/fs/tracing_path.c @@ -0,0 +1,135 @@ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include "fs.h" + +#include "tracing_path.h" + + +char tracing_mnt[PATH_MAX] = "/sys/kernel/debug"; +char tracing_path[PATH_MAX] = "/sys/kernel/debug/tracing"; +char tracing_events_path[PATH_MAX] = "/sys/kernel/debug/tracing/events"; + + +static void __tracing_path_set(const char *tracing, const char *mountpoint) +{ + snprintf(tracing_mnt, sizeof(tracing_mnt), "%s", mountpoint); + snprintf(tracing_path, sizeof(tracing_path), "%s/%s", + mountpoint, tracing); + snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s%s", + mountpoint, tracing, "events"); +} + +static const char *tracing_path_tracefs_mount(void) +{ + const char *mnt; + + mnt = tracefs__mount(); + if (!mnt) + return NULL; + + __tracing_path_set("", mnt); + + return mnt; +} + +static const char *tracing_path_debugfs_mount(void) +{ + const char *mnt; + + mnt = debugfs__mount(); + if (!mnt) + return NULL; + + __tracing_path_set("tracing/", mnt); + + return mnt; +} + +const char *tracing_path_mount(void) +{ + const char *mnt; + + mnt = tracing_path_tracefs_mount(); + if (mnt) + return mnt; + + mnt = tracing_path_debugfs_mount(); + + return mnt; +} + +void tracing_path_set(const char *mntpt) +{ + __tracing_path_set("tracing/", mntpt); +} + +char *get_tracing_file(const char *name) +{ + char *file; + + if (asprintf(&file, "%s/%s", tracing_path, name) < 0) + return NULL; + + return file; +} + +void put_tracing_file(char *file) +{ + free(file); +} + +static int strerror_open(int err, char *buf, size_t size, const char *filename) +{ + char sbuf[128]; + + switch (err) { + case ENOENT: + /* + * We will get here if we can't find the tracepoint, but one of + * debugfs or tracefs is configured, which means you probably + * want some tracepoint which wasn't compiled in your kernel. + * - jirka + */ + if (debugfs__configured() || tracefs__configured()) { + snprintf(buf, size, + "Error:\tFile %s/%s not found.\n" + "Hint:\tPerhaps this kernel misses some CONFIG_ setting to enable this feature?.\n", + tracing_events_path, filename); + break; + } + snprintf(buf, size, "%s", + "Error:\tUnable to find debugfs/tracefs\n" + "Hint:\tWas your kernel compiled with debugfs/tracefs support?\n" + "Hint:\tIs the debugfs/tracefs filesystem mounted?\n" + "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'"); + break; + case EACCES: { + snprintf(buf, size, + "Error:\tNo permissions to read %s/%s\n" + "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n", + tracing_events_path, filename, tracing_mnt); + } + break; + default: + snprintf(buf, size, "%s", strerror_r(err, sbuf, sizeof(sbuf))); + break; + } + + return 0; +} + +int tracing_path__strerror_open_tp(int err, char *buf, size_t size, const char *sys, const char *name) +{ + char path[PATH_MAX]; + + snprintf(path, PATH_MAX, "%s/%s", sys, name ?: "*"); + + return strerror_open(err, buf, size, path); +} diff --git a/tools/lib/api/fs/tracing_path.h b/tools/lib/api/fs/tracing_path.h new file mode 100644 index 000000000..3f233ac70 --- /dev/null +++ b/tools/lib/api/fs/tracing_path.h @@ -0,0 +1,16 @@ +#ifndef __API_FS_TRACING_PATH_H +#define __API_FS_TRACING_PATH_H + +#include <linux/types.h> + +extern char tracing_path[]; +extern char tracing_events_path[]; + +void tracing_path_set(const char *mountpoint); +const char *tracing_path_mount(void); + +char *get_tracing_file(const char *name); +void put_tracing_file(char *file); + +int tracing_path__strerror_open_tp(int err, char *buf, size_t size, const char *sys, const char *name); +#endif /* __API_FS_TRACING_PATH_H */ diff --git a/tools/lib/bpf/.gitignore b/tools/lib/bpf/.gitignore index 812aeedae..f81e549dd 100644 --- a/tools/lib/bpf/.gitignore +++ b/tools/lib/bpf/.gitignore @@ -1,2 +1,2 @@ libbpf_version.h -FEATURE-DUMP +FEATURE-DUMP.libbpf diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index f68d23a0b..a3caaf3ea 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -64,8 +64,9 @@ srctree := $(patsubst %/,%,$(dir $(srctree))) #$(info Determined 'srctree' to be $(srctree)) endif -FEATURE_DISPLAY = libelf libelf-getphdrnum libelf-mmap bpf -FEATURE_TESTS = libelf bpf +FEATURE_USER = .libbpf +FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf +FEATURE_DISPLAY = libelf bpf INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/arch/$(ARCH)/include/uapi -I$(srctree)/include/uapi FEATURE_CHECK_CFLAGS-bpf = $(INCLUDES) @@ -122,8 +123,10 @@ endif # the same command line setup. MAKEOVERRIDES= +all: + export srctree OUTPUT CC LD CFLAGS V -build := -f $(srctree)/tools/build/Makefile.build dir=. obj +include $(srctree)/tools/build/Makefile.include BPF_IN := $(OUTPUT)libbpf-in.o LIB_FILE := $(addprefix $(OUTPUT),$(LIB_FILE)) @@ -132,7 +135,7 @@ CMD_TARGETS = $(LIB_FILE) TARGETS = $(CMD_TARGETS) -all: $(VERSION_FILES) all_cmd +all: fixdep $(VERSION_FILES) all_cmd all_cmd: $(CMD_TARGETS) @@ -177,7 +180,7 @@ config-clean: clean: $(call QUIET_CLEAN, libbpf) $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d \ $(RM) LIBBPF-CFLAGS - $(call QUIET_CLEAN, core-gen) $(RM) $(OUTPUT)FEATURE-DUMP + $(call QUIET_CLEAN, core-gen) $(RM) $(OUTPUT)FEATURE-DUMP.libbpf diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 4252fc22f..e176bad19 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -61,6 +61,60 @@ void libbpf_set_print(libbpf_print_fn_t warn, __pr_debug = debug; } +#define STRERR_BUFSIZE 128 + +#define ERRNO_OFFSET(e) ((e) - __LIBBPF_ERRNO__START) +#define ERRCODE_OFFSET(c) ERRNO_OFFSET(LIBBPF_ERRNO__##c) +#define NR_ERRNO (__LIBBPF_ERRNO__END - __LIBBPF_ERRNO__START) + +static const char *libbpf_strerror_table[NR_ERRNO] = { + [ERRCODE_OFFSET(LIBELF)] = "Something wrong in libelf", + [ERRCODE_OFFSET(FORMAT)] = "BPF object format invalid", + [ERRCODE_OFFSET(KVERSION)] = "'version' section incorrect or lost", + [ERRCODE_OFFSET(ENDIAN)] = "Endian missmatch", + [ERRCODE_OFFSET(INTERNAL)] = "Internal error in libbpf", + [ERRCODE_OFFSET(RELOC)] = "Relocation failed", + [ERRCODE_OFFSET(VERIFY)] = "Kernel verifier blocks program loading", + [ERRCODE_OFFSET(PROG2BIG)] = "Program too big", + [ERRCODE_OFFSET(KVER)] = "Incorrect kernel version", +}; + +int libbpf_strerror(int err, char *buf, size_t size) +{ + if (!buf || !size) + return -1; + + err = err > 0 ? err : -err; + + if (err < __LIBBPF_ERRNO__START) { + int ret; + + ret = strerror_r(err, buf, size); + buf[size - 1] = '\0'; + return ret; + } + + if (err < __LIBBPF_ERRNO__END) { + const char *msg; + + msg = libbpf_strerror_table[ERRNO_OFFSET(err)]; + snprintf(buf, size, "%s", msg); + buf[size - 1] = '\0'; + return 0; + } + + snprintf(buf, size, "Unknown libbpf error %d", err); + buf[size - 1] = '\0'; + return -1; +} + +#define CHECK_ERR(action, err, out) do { \ + err = action; \ + if (err) \ + goto out; \ +} while(0) + + /* Copied from tools/perf/util/util.h */ #ifndef zfree # define zfree(ptr) ({ free(*ptr); *ptr = NULL; }) @@ -258,7 +312,7 @@ static struct bpf_object *bpf_object__new(const char *path, obj = calloc(1, sizeof(struct bpf_object) + strlen(path) + 1); if (!obj) { pr_warning("alloc memory failed for %s\n", path); - return NULL; + return ERR_PTR(-ENOMEM); } strcpy(obj->path, path); @@ -305,7 +359,7 @@ static int bpf_object__elf_init(struct bpf_object *obj) if (obj_elf_valid(obj)) { pr_warning("elf init: internal error\n"); - return -EEXIST; + return -LIBBPF_ERRNO__LIBELF; } if (obj->efile.obj_buf_sz > 0) { @@ -331,14 +385,14 @@ static int bpf_object__elf_init(struct bpf_object *obj) if (!obj->efile.elf) { pr_warning("failed to open %s as ELF file\n", obj->path); - err = -EINVAL; + err = -LIBBPF_ERRNO__LIBELF; goto errout; } if (!gelf_getehdr(obj->efile.elf, &obj->efile.ehdr)) { pr_warning("failed to get EHDR from %s\n", obj->path); - err = -EINVAL; + err = -LIBBPF_ERRNO__FORMAT; goto errout; } ep = &obj->efile.ehdr; @@ -346,7 +400,7 @@ static int bpf_object__elf_init(struct bpf_object *obj) if ((ep->e_type != ET_REL) || (ep->e_machine != 0)) { pr_warning("%s is not an eBPF object file\n", obj->path); - err = -EINVAL; + err = -LIBBPF_ERRNO__FORMAT; goto errout; } @@ -374,14 +428,14 @@ bpf_object__check_endianness(struct bpf_object *obj) goto mismatch; break; default: - return -EINVAL; + return -LIBBPF_ERRNO__ENDIAN; } return 0; mismatch: pr_warning("Error: endianness mismatch.\n"); - return -EINVAL; + return -LIBBPF_ERRNO__ENDIAN; } static int @@ -402,7 +456,7 @@ bpf_object__init_kversion(struct bpf_object *obj, if (size != sizeof(kver)) { pr_warning("invalid kver section in %s\n", obj->path); - return -EINVAL; + return -LIBBPF_ERRNO__FORMAT; } memcpy(&kver, data, sizeof(kver)); obj->kern_version = kver; @@ -444,7 +498,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj) if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) { pr_warning("failed to get e_shstrndx from %s\n", obj->path); - return -EINVAL; + return -LIBBPF_ERRNO__FORMAT; } while ((scn = elf_nextscn(elf, scn)) != NULL) { @@ -456,7 +510,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj) if (gelf_getshdr(scn, &sh) != &sh) { pr_warning("failed to get section header from %s\n", obj->path); - err = -EINVAL; + err = -LIBBPF_ERRNO__FORMAT; goto out; } @@ -464,7 +518,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj) if (!name) { pr_warning("failed to get section name from %s\n", obj->path); - err = -EINVAL; + err = -LIBBPF_ERRNO__FORMAT; goto out; } @@ -472,7 +526,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj) if (!data) { pr_warning("failed to get section data from %s(%s)\n", name, obj->path); - err = -EINVAL; + err = -LIBBPF_ERRNO__FORMAT; goto out; } pr_debug("section %s, size %ld, link %d, flags %lx, type=%d\n", @@ -495,7 +549,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj) if (obj->efile.symbols) { pr_warning("bpf: multiple SYMTAB in %s\n", obj->path); - err = -EEXIST; + err = -LIBBPF_ERRNO__FORMAT; } else obj->efile.symbols = data; } else if ((sh.sh_type == SHT_PROGBITS) && @@ -504,7 +558,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj) err = bpf_object__add_program(obj, data->d_buf, data->d_size, name, idx); if (err) { - char errmsg[128]; + char errmsg[STRERR_BUFSIZE]; + strerror_r(-err, errmsg, sizeof(errmsg)); pr_warning("failed to alloc program %s (%s): %s", name, obj->path, errmsg); @@ -576,7 +631,7 @@ bpf_program__collect_reloc(struct bpf_program *prog, if (!gelf_getrel(data, i, &rel)) { pr_warning("relocation: failed to get %d reloc\n", i); - return -EINVAL; + return -LIBBPF_ERRNO__FORMAT; } insn_idx = rel.r_offset / sizeof(struct bpf_insn); @@ -587,20 +642,20 @@ bpf_program__collect_reloc(struct bpf_program *prog, &sym)) { pr_warning("relocation: symbol %"PRIx64" not found\n", GELF_R_SYM(rel.r_info)); - return -EINVAL; + return -LIBBPF_ERRNO__FORMAT; } if (insns[insn_idx].code != (BPF_LD | BPF_IMM | BPF_DW)) { pr_warning("bpf: relocation: invalid relo for insns[%d].code 0x%x\n", insn_idx, insns[insn_idx].code); - return -EINVAL; + return -LIBBPF_ERRNO__RELOC; } map_idx = sym.st_value / sizeof(struct bpf_map_def); if (map_idx >= nr_maps) { pr_warning("bpf relocation: map_idx %d large than %d\n", (int)map_idx, (int)nr_maps - 1); - return -EINVAL; + return -LIBBPF_ERRNO__RELOC; } prog->reloc_desc[i].insn_idx = insn_idx; @@ -683,7 +738,7 @@ bpf_program__relocate(struct bpf_program *prog, int *map_fds) if (insn_idx >= (int)prog->insns_cnt) { pr_warning("relocation out of range: '%s'\n", prog->section_name); - return -ERANGE; + return -LIBBPF_ERRNO__RELOC; } insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD; insns[insn_idx].imm = map_fds[map_idx]; @@ -721,7 +776,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj) if (!obj_elf_valid(obj)) { pr_warning("Internal error: elf object is closed\n"); - return -EINVAL; + return -LIBBPF_ERRNO__INTERNAL; } for (i = 0; i < obj->efile.nr_reloc; i++) { @@ -734,21 +789,21 @@ static int bpf_object__collect_reloc(struct bpf_object *obj) if (shdr->sh_type != SHT_REL) { pr_warning("internal error at %d\n", __LINE__); - return -EINVAL; + return -LIBBPF_ERRNO__INTERNAL; } prog = bpf_object__find_prog_by_idx(obj, idx); if (!prog) { pr_warning("relocation failed: no %d section\n", idx); - return -ENOENT; + return -LIBBPF_ERRNO__RELOC; } err = bpf_program__collect_reloc(prog, nr_maps, shdr, data, obj->efile.symbols); if (err) - return -EINVAL; + return err; } return 0; } @@ -777,13 +832,23 @@ load_program(struct bpf_insn *insns, int insns_cnt, goto out; } - ret = -EINVAL; + ret = -LIBBPF_ERRNO__LOAD; pr_warning("load bpf program failed: %s\n", strerror(errno)); - if (log_buf) { + if (log_buf && log_buf[0] != '\0') { + ret = -LIBBPF_ERRNO__VERIFY; pr_warning("-- BEGIN DUMP LOG ---\n"); pr_warning("\n%s\n", log_buf); pr_warning("-- END LOG --\n"); + } else { + if (insns_cnt >= BPF_MAXINSNS) { + pr_warning("Program too large (%d insns), at most %d insns\n", + insns_cnt, BPF_MAXINSNS); + ret = -LIBBPF_ERRNO__PROG2BIG; + } else if (log_buf) { + pr_warning("log buffer is empty\n"); + ret = -LIBBPF_ERRNO__KVER; + } } out: @@ -831,7 +896,7 @@ static int bpf_object__validate(struct bpf_object *obj) if (obj->kern_version == 0) { pr_warning("%s doesn't provide kernel version\n", obj->path); - return -EINVAL; + return -LIBBPF_ERRNO__KVERSION; } return 0; } @@ -840,32 +905,28 @@ static struct bpf_object * __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz) { struct bpf_object *obj; + int err; if (elf_version(EV_CURRENT) == EV_NONE) { pr_warning("failed to init libelf for %s\n", path); - return NULL; + return ERR_PTR(-LIBBPF_ERRNO__LIBELF); } obj = bpf_object__new(path, obj_buf, obj_buf_sz); - if (!obj) - return NULL; + if (IS_ERR(obj)) + return obj; - if (bpf_object__elf_init(obj)) - goto out; - if (bpf_object__check_endianness(obj)) - goto out; - if (bpf_object__elf_collect(obj)) - goto out; - if (bpf_object__collect_reloc(obj)) - goto out; - if (bpf_object__validate(obj)) - goto out; + CHECK_ERR(bpf_object__elf_init(obj), err, out); + CHECK_ERR(bpf_object__check_endianness(obj), err, out); + CHECK_ERR(bpf_object__elf_collect(obj), err, out); + CHECK_ERR(bpf_object__collect_reloc(obj), err, out); + CHECK_ERR(bpf_object__validate(obj), err, out); bpf_object__elf_finish(obj); return obj; out: bpf_object__close(obj); - return NULL; + return ERR_PTR(err); } struct bpf_object *bpf_object__open(const char *path) @@ -922,6 +983,8 @@ int bpf_object__unload(struct bpf_object *obj) int bpf_object__load(struct bpf_object *obj) { + int err; + if (!obj) return -EINVAL; @@ -931,18 +994,16 @@ int bpf_object__load(struct bpf_object *obj) } obj->loaded = true; - if (bpf_object__create_maps(obj)) - goto out; - if (bpf_object__relocate(obj)) - goto out; - if (bpf_object__load_progs(obj)) - goto out; + + CHECK_ERR(bpf_object__create_maps(obj), err, out); + CHECK_ERR(bpf_object__relocate(obj), err, out); + CHECK_ERR(bpf_object__load_progs(obj), err, out); return 0; out: bpf_object__unload(obj); pr_warning("failed to load object '%s'\n", obj->path); - return -EINVAL; + return err; } void bpf_object__close(struct bpf_object *obj) @@ -990,10 +1051,18 @@ const char * bpf_object__get_name(struct bpf_object *obj) { if (!obj) - return NULL; + return ERR_PTR(-EINVAL); return obj->path; } +unsigned int +bpf_object__get_kversion(struct bpf_object *obj) +{ + if (!obj) + return 0; + return obj->kern_version; +} + struct bpf_program * bpf_program__next(struct bpf_program *prev, struct bpf_object *obj) { @@ -1034,16 +1103,16 @@ int bpf_program__get_private(struct bpf_program *prog, void **ppriv) return 0; } -const char *bpf_program__title(struct bpf_program *prog, bool dup) +const char *bpf_program__title(struct bpf_program *prog, bool needs_copy) { const char *title; title = prog->section_name; - if (dup) { + if (needs_copy) { title = strdup(title); if (!title) { pr_warning("failed to strdup program title\n"); - return NULL; + return ERR_PTR(-ENOMEM); } } diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index f16170c95..c9a9aef28 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -10,6 +10,26 @@ #include <stdio.h> #include <stdbool.h> +#include <linux/err.h> + +enum libbpf_errno { + __LIBBPF_ERRNO__START = 4000, + + /* Something wrong in libelf */ + LIBBPF_ERRNO__LIBELF = __LIBBPF_ERRNO__START, + LIBBPF_ERRNO__FORMAT, /* BPF object format invalid */ + LIBBPF_ERRNO__KVERSION, /* Incorrect or no 'version' section */ + LIBBPF_ERRNO__ENDIAN, /* Endian missmatch */ + LIBBPF_ERRNO__INTERNAL, /* Internal error in libbpf */ + LIBBPF_ERRNO__RELOC, /* Relocation failed */ + LIBBPF_ERRNO__LOAD, /* Load program failure for unknown reason */ + LIBBPF_ERRNO__VERIFY, /* Kernel verifier blocks program loading */ + LIBBPF_ERRNO__PROG2BIG, /* Program too big */ + LIBBPF_ERRNO__KVER, /* Incorrect kernel version */ + __LIBBPF_ERRNO__END, +}; + +int libbpf_strerror(int err, char *buf, size_t size); /* * In include/linux/compiler-gcc.h, __printf is defined. However @@ -36,6 +56,7 @@ void bpf_object__close(struct bpf_object *object); int bpf_object__load(struct bpf_object *obj); int bpf_object__unload(struct bpf_object *obj); const char *bpf_object__get_name(struct bpf_object *obj); +unsigned int bpf_object__get_kversion(struct bpf_object *obj); struct bpf_object *bpf_object__next(struct bpf_object *prev); #define bpf_object__for_each_safe(pos, tmp) \ @@ -63,7 +84,7 @@ int bpf_program__set_private(struct bpf_program *prog, void *priv, int bpf_program__get_private(struct bpf_program *prog, void **ppriv); -const char *bpf_program__title(struct bpf_program *prog, bool dup); +const char *bpf_program__title(struct bpf_program *prog, bool needs_copy); int bpf_program__fd(struct bpf_program *prog); diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile index 18ffccf00..7e319afac 100644 --- a/tools/lib/lockdep/Makefile +++ b/tools/lib/lockdep/Makefile @@ -93,8 +93,10 @@ else print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2'; endif +all: + export srctree OUTPUT CC LD CFLAGS V -build := -f $(srctree)/tools/build/Makefile.build dir=. obj +include $(srctree)/tools/build/Makefile.include do_compile_shared_library = \ ($(print_shared_lib_compile) \ @@ -109,7 +111,7 @@ CMD_TARGETS = $(LIB_FILE) TARGETS = $(CMD_TARGETS) -all: all_cmd +all: fixdep all_cmd all_cmd: $(CMD_TARGETS) diff --git a/tools/lib/lockdep/common.c b/tools/lib/lockdep/common.c index 8ef602f18..9be663340 100644 --- a/tools/lib/lockdep/common.c +++ b/tools/lib/lockdep/common.c @@ -18,7 +18,7 @@ __attribute__((constructor)) static void liblockdep_init(void) __attribute__((destructor)) static void liblockdep_exit(void) { - debug_check_no_locks_held(¤t_obj); + debug_check_no_locks_held(); } struct task_struct *__curr(void) diff --git a/tools/lib/lockdep/include/liblockdep/common.h b/tools/lib/lockdep/include/liblockdep/common.h index 0bda63002..a60c14b96 100644 --- a/tools/lib/lockdep/include/liblockdep/common.h +++ b/tools/lib/lockdep/include/liblockdep/common.h @@ -43,6 +43,8 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass, struct lockdep_map *nest_lock, unsigned long ip); void lock_release(struct lockdep_map *lock, int nested, unsigned long ip); +extern void debug_check_no_locks_freed(const void *from, unsigned long len); +extern void lockdep_init(void); #define STATIC_LOCKDEP_MAP_INIT(_name, _key) \ { .name = (_name), .key = (void *)(_key), } diff --git a/tools/lib/lockdep/uinclude/linux/compiler.h b/tools/lib/lockdep/uinclude/linux/compiler.h index 7ac838a1f..6386dc318 100644 --- a/tools/lib/lockdep/uinclude/linux/compiler.h +++ b/tools/lib/lockdep/uinclude/linux/compiler.h @@ -3,5 +3,7 @@ #define __used __attribute__((__unused__)) #define unlikely +#define WRITE_ONCE(x, val) x=(val) +#define RCU_INIT_POINTER(p, v) p=(v) #endif diff --git a/tools/lib/lockdep/uinclude/linux/lockdep.h b/tools/lib/lockdep/uinclude/linux/lockdep.h index c1552c285..c808c7d02 100644 --- a/tools/lib/lockdep/uinclude/linux/lockdep.h +++ b/tools/lib/lockdep/uinclude/linux/lockdep.h @@ -6,7 +6,7 @@ #include <string.h> #include <limits.h> #include <linux/utsname.h> - +#include <linux/compiler.h> #define MAX_LOCK_DEPTH 2000UL @@ -54,5 +54,6 @@ static struct new_utsname *init_utsname(void) #define static_obj(x) 1 #define debug_show_all_locks() +extern void debug_check_no_locks_held(void); #endif diff --git a/tools/lib/symbol/kallsyms.c b/tools/lib/symbol/kallsyms.c index 18bc271a4..5e431077f 100644 --- a/tools/lib/symbol/kallsyms.c +++ b/tools/lib/symbol/kallsyms.c @@ -2,6 +2,12 @@ #include <stdio.h> #include <stdlib.h> +u8 kallsyms2elf_type(char type) +{ + type = tolower(type); + return (type == 't' || type == 'w') ? STT_FUNC : STT_OBJECT; +} + int kallsyms__parse(const char *filename, void *arg, int (*process_symbol)(void *arg, const char *name, char type, u64 start)) diff --git a/tools/lib/symbol/kallsyms.h b/tools/lib/symbol/kallsyms.h index 6084f5e18..4071316a7 100644 --- a/tools/lib/symbol/kallsyms.h +++ b/tools/lib/symbol/kallsyms.h @@ -9,7 +9,7 @@ #define KSYM_NAME_LEN 256 #endif -static inline u8 kallsyms2elf_type(char type) +static inline u8 kallsyms2elf_binding(char type) { if (type == 'W') return STB_WEAK; @@ -17,6 +17,8 @@ static inline u8 kallsyms2elf_type(char type) return isupper(type) ? STB_GLOBAL : STB_LOCAL; } +u8 kallsyms2elf_type(char type); + int kallsyms__parse(const char *filename, void *arg, int (*process_symbol)(void *arg, const char *name, char type, u64 start)); diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index cf42b0904..2a912df67 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -848,6 +848,7 @@ static void free_arg(struct print_arg *arg) free(arg->bitmask.bitmask); break; case PRINT_DYNAMIC_ARRAY: + case PRINT_DYNAMIC_ARRAY_LEN: free(arg->dynarray.index); break; case PRINT_OP: @@ -2729,6 +2730,42 @@ process_dynamic_array(struct event_format *event, struct print_arg *arg, char ** } static enum event_type +process_dynamic_array_len(struct event_format *event, struct print_arg *arg, + char **tok) +{ + struct format_field *field; + enum event_type type; + char *token; + + if (read_expect_type(EVENT_ITEM, &token) < 0) + goto out_free; + + arg->type = PRINT_DYNAMIC_ARRAY_LEN; + + /* Find the field */ + field = pevent_find_field(event, token); + if (!field) + goto out_free; + + arg->dynarray.field = field; + arg->dynarray.index = 0; + + if (read_expected(EVENT_DELIM, ")") < 0) + goto out_err; + + type = read_token(&token); + *tok = token; + + return type; + + out_free: + free_token(token); + out_err: + *tok = NULL; + return EVENT_ERROR; +} + +static enum event_type process_paren(struct event_format *event, struct print_arg *arg, char **tok) { struct print_arg *item_arg; @@ -2975,6 +3012,10 @@ process_function(struct event_format *event, struct print_arg *arg, free_token(token); return process_dynamic_array(event, arg, tok); } + if (strcmp(token, "__get_dynamic_array_len") == 0) { + free_token(token); + return process_dynamic_array_len(event, arg, tok); + } func = find_func_handler(event->pevent, token); if (func) { @@ -3655,14 +3696,25 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg goto out_warning_op; } break; + case PRINT_DYNAMIC_ARRAY_LEN: + offset = pevent_read_number(pevent, + data + arg->dynarray.field->offset, + arg->dynarray.field->size); + /* + * The total allocated length of the dynamic array is + * stored in the top half of the field, and the offset + * is in the bottom half of the 32 bit field. + */ + val = (unsigned long long)(offset >> 16); + break; case PRINT_DYNAMIC_ARRAY: /* Without [], we pass the address to the dynamic data */ offset = pevent_read_number(pevent, data + arg->dynarray.field->offset, arg->dynarray.field->size); /* - * The actual length of the dynamic array is stored - * in the top half of the field, and the offset + * The total allocated length of the dynamic array is + * stored in the top half of the field, and the offset * is in the bottom half of the 32 bit field. */ offset &= 0xffff; @@ -4853,8 +4905,8 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event else ls = 2; - if (*(ptr+1) == 'F' || - *(ptr+1) == 'f') { + if (*(ptr+1) == 'F' || *(ptr+1) == 'f' || + *(ptr+1) == 'S' || *(ptr+1) == 's') { ptr++; show_func = *ptr; } else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') { diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 204befb05..6fc83c7ed 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -294,6 +294,7 @@ enum print_arg_type { PRINT_OP, PRINT_FUNC, PRINT_BITMASK, + PRINT_DYNAMIC_ARRAY_LEN, }; struct print_arg { diff --git a/tools/lib/traceevent/plugin_kvm.c b/tools/lib/traceevent/plugin_kvm.c index 88fe83dff..18536f756 100644 --- a/tools/lib/traceevent/plugin_kvm.c +++ b/tools/lib/traceevent/plugin_kvm.c @@ -124,7 +124,10 @@ static const char *disassemble(unsigned char *insn, int len, uint64_t rip, _ER(WBINVD, 54) \ _ER(XSETBV, 55) \ _ER(APIC_WRITE, 56) \ - _ER(INVPCID, 58) + _ER(INVPCID, 58) \ + _ER(PML_FULL, 62) \ + _ER(XSAVES, 63) \ + _ER(XRSTORS, 64) #define SVM_EXIT_REASONS \ _ER(EXIT_READ_CR0, 0x000) \ @@ -352,15 +355,18 @@ static int kvm_nested_vmexit_handler(struct trace_seq *s, struct pevent_record * union kvm_mmu_page_role { unsigned word; struct { - unsigned glevels:4; unsigned level:4; + unsigned cr4_pae:1; unsigned quadrant:2; - unsigned pad_for_nice_hex_output:6; unsigned direct:1; unsigned access:3; unsigned invalid:1; - unsigned cr4_pge:1; unsigned nxe:1; + unsigned cr0_wp:1; + unsigned smep_and_not_wp:1; + unsigned smap_and_not_wp:1; + unsigned pad_for_nice_hex_output:8; + unsigned smm:8; }; }; @@ -385,15 +391,18 @@ static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record, if (pevent_is_file_bigendian(event->pevent) == pevent_is_host_bigendian(event->pevent)) { - trace_seq_printf(s, "%u/%u q%u%s %s%s %spge %snxe", + trace_seq_printf(s, "%u q%u%s %s%s %spae %snxe %swp%s%s%s", role.level, - role.glevels, role.quadrant, role.direct ? " direct" : "", access_str[role.access], role.invalid ? " invalid" : "", - role.cr4_pge ? "" : "!", - role.nxe ? "" : "!"); + role.cr4_pae ? "" : "!", + role.nxe ? "" : "!", + role.cr0_wp ? "" : "!", + role.smep_and_not_wp ? " smep" : "", + role.smap_and_not_wp ? " smap" : "", + role.smm ? " smm" : ""); } else trace_seq_printf(s, "WORD: %08x", role.word); |