diff options
Diffstat (limited to 'tools/lib')
80 files changed, 4431 insertions, 501 deletions
diff --git a/tools/lib/lk/Makefile b/tools/lib/api/Makefile index 3dba0a4aebbf..ed2f51e11b80 100644 --- a/tools/lib/lk/Makefile +++ b/tools/lib/api/Makefile | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | include ../../scripts/Makefile.include | 1 | include ../../scripts/Makefile.include |
| 2 | include ../../perf/config/utilities.mak # QUIET_CLEAN | ||
| 2 | 3 | ||
| 3 | CC = $(CROSS_COMPILE)gcc | 4 | CC = $(CROSS_COMPILE)gcc |
| 4 | AR = $(CROSS_COMPILE)ar | 5 | AR = $(CROSS_COMPILE)ar |
| @@ -7,11 +8,11 @@ AR = $(CROSS_COMPILE)ar | |||
| 7 | LIB_H= | 8 | LIB_H= |
| 8 | LIB_OBJS= | 9 | LIB_OBJS= |
| 9 | 10 | ||
| 10 | LIB_H += debugfs.h | 11 | LIB_H += fs/debugfs.h |
| 11 | 12 | ||
| 12 | LIB_OBJS += $(OUTPUT)debugfs.o | 13 | LIB_OBJS += $(OUTPUT)fs/debugfs.o |
| 13 | 14 | ||
| 14 | LIBFILE = liblk.a | 15 | LIBFILE = libapikfs.a |
| 15 | 16 | ||
| 16 | CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC | 17 | CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC |
| 17 | EXTLIBS = -lelf -lpthread -lrt -lm | 18 | EXTLIBS = -lelf -lpthread -lrt -lm |
| @@ -25,14 +26,17 @@ $(LIBFILE): $(LIB_OBJS) | |||
| 25 | 26 | ||
| 26 | $(LIB_OBJS): $(LIB_H) | 27 | $(LIB_OBJS): $(LIB_H) |
| 27 | 28 | ||
| 28 | $(OUTPUT)%.o: %.c | 29 | libapi_dirs: |
| 30 | $(QUIET_MKDIR)mkdir -p $(OUTPUT)fs/ | ||
| 31 | |||
| 32 | $(OUTPUT)%.o: %.c libapi_dirs | ||
| 29 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< | 33 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< |
| 30 | $(OUTPUT)%.s: %.c | 34 | $(OUTPUT)%.s: %.c libapi_dirs |
| 31 | $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $< | 35 | $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $< |
| 32 | $(OUTPUT)%.o: %.S | 36 | $(OUTPUT)%.o: %.S libapi_dirs |
| 33 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< | 37 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< |
| 34 | 38 | ||
| 35 | clean: | 39 | clean: |
| 36 | $(RM) $(LIB_OBJS) $(LIBFILE) | 40 | $(call QUIET_CLEAN, libapi) $(RM) $(LIB_OBJS) $(LIBFILE) |
| 37 | 41 | ||
| 38 | .PHONY: clean | 42 | .PHONY: clean |
diff --git a/tools/lib/lk/debugfs.c b/tools/lib/api/fs/debugfs.c index 7c4347962353..7c4347962353 100644 --- a/tools/lib/lk/debugfs.c +++ b/tools/lib/api/fs/debugfs.c | |||
diff --git a/tools/lib/lk/debugfs.h b/tools/lib/api/fs/debugfs.h index 935c59bdb442..f19d3df9609d 100644 --- a/tools/lib/lk/debugfs.h +++ b/tools/lib/api/fs/debugfs.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #ifndef __LK_DEBUGFS_H__ | 1 | #ifndef __API_DEBUGFS_H__ |
| 2 | #define __LK_DEBUGFS_H__ | 2 | #define __API_DEBUGFS_H__ |
| 3 | 3 | ||
| 4 | #define _STR(x) #x | 4 | #define _STR(x) #x |
| 5 | #define STR(x) _STR(x) | 5 | #define STR(x) _STR(x) |
| @@ -26,4 +26,4 @@ char *debugfs_mount(const char *mountpoint); | |||
| 26 | 26 | ||
| 27 | extern char debugfs_mountpoint[]; | 27 | extern char debugfs_mountpoint[]; |
| 28 | 28 | ||
| 29 | #endif /* __LK_DEBUGFS_H__ */ | 29 | #endif /* __API_DEBUGFS_H__ */ |
diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile new file mode 100644 index 000000000000..07b0b7542511 --- /dev/null +++ b/tools/lib/lockdep/Makefile | |||
| @@ -0,0 +1,251 @@ | |||
| 1 | # liblockdep version | ||
| 2 | LL_VERSION = 0 | ||
| 3 | LL_PATCHLEVEL = 0 | ||
| 4 | LL_EXTRAVERSION = 1 | ||
| 5 | |||
| 6 | # file format version | ||
| 7 | FILE_VERSION = 1 | ||
| 8 | |||
| 9 | MAKEFLAGS += --no-print-directory | ||
| 10 | |||
| 11 | |||
| 12 | # Makefiles suck: This macro sets a default value of $(2) for the | ||
| 13 | # variable named by $(1), unless the variable has been set by | ||
| 14 | # environment or command line. This is necessary for CC and AR | ||
| 15 | # because make sets default values, so the simpler ?= approach | ||
| 16 | # won't work as expected. | ||
| 17 | define allow-override | ||
| 18 | $(if $(or $(findstring environment,$(origin $(1))),\ | ||
| 19 | $(findstring command line,$(origin $(1)))),,\ | ||
| 20 | $(eval $(1) = $(2))) | ||
| 21 | endef | ||
| 22 | |||
| 23 | # Allow setting CC and AR, or setting CROSS_COMPILE as a prefix. | ||
| 24 | $(call allow-override,CC,$(CROSS_COMPILE)gcc) | ||
| 25 | $(call allow-override,AR,$(CROSS_COMPILE)ar) | ||
| 26 | |||
| 27 | INSTALL = install | ||
| 28 | |||
| 29 | # Use DESTDIR for installing into a different root directory. | ||
| 30 | # This is useful for building a package. The program will be | ||
| 31 | # installed in this directory as if it was the root directory. | ||
| 32 | # Then the build tool can move it later. | ||
| 33 | DESTDIR ?= | ||
| 34 | DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))' | ||
| 35 | |||
| 36 | prefix ?= /usr/local | ||
| 37 | libdir_relative = lib | ||
| 38 | libdir = $(prefix)/$(libdir_relative) | ||
| 39 | bindir_relative = bin | ||
| 40 | bindir = $(prefix)/$(bindir_relative) | ||
| 41 | |||
| 42 | export DESTDIR DESTDIR_SQ INSTALL | ||
| 43 | |||
| 44 | # copy a bit from Linux kbuild | ||
| 45 | |||
| 46 | ifeq ("$(origin V)", "command line") | ||
| 47 | VERBOSE = $(V) | ||
| 48 | endif | ||
| 49 | ifndef VERBOSE | ||
| 50 | VERBOSE = 0 | ||
| 51 | endif | ||
| 52 | |||
| 53 | ifeq ("$(origin O)", "command line") | ||
| 54 | BUILD_OUTPUT := $(O) | ||
| 55 | endif | ||
| 56 | |||
| 57 | ifeq ($(BUILD_SRC),) | ||
| 58 | ifneq ($(BUILD_OUTPUT),) | ||
| 59 | |||
| 60 | define build_output | ||
| 61 | $(if $(VERBOSE:1=),@)$(MAKE) -C $(BUILD_OUTPUT) \ | ||
| 62 | BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1 | ||
| 63 | endef | ||
| 64 | |||
| 65 | saved-output := $(BUILD_OUTPUT) | ||
| 66 | BUILD_OUTPUT := $(shell cd $(BUILD_OUTPUT) && /bin/pwd) | ||
| 67 | $(if $(BUILD_OUTPUT),, \ | ||
| 68 | $(error output directory "$(saved-output)" does not exist)) | ||
| 69 | |||
| 70 | all: sub-make | ||
| 71 | |||
| 72 | gui: force | ||
| 73 | $(call build_output, all_cmd) | ||
| 74 | |||
| 75 | $(filter-out gui,$(MAKECMDGOALS)): sub-make | ||
| 76 | |||
| 77 | sub-make: force | ||
| 78 | $(call build_output, $(MAKECMDGOALS)) | ||
| 79 | |||
| 80 | |||
| 81 | # Leave processing to above invocation of make | ||
| 82 | skip-makefile := 1 | ||
| 83 | |||
| 84 | endif # BUILD_OUTPUT | ||
| 85 | endif # BUILD_SRC | ||
| 86 | |||
| 87 | # We process the rest of the Makefile if this is the final invocation of make | ||
| 88 | ifeq ($(skip-makefile),) | ||
| 89 | |||
| 90 | srctree := $(realpath $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR))) | ||
| 91 | objtree := $(realpath $(CURDIR)) | ||
| 92 | src := $(srctree) | ||
| 93 | obj := $(objtree) | ||
| 94 | |||
| 95 | export prefix libdir bindir src obj | ||
| 96 | |||
| 97 | # Shell quotes | ||
| 98 | libdir_SQ = $(subst ','\'',$(libdir)) | ||
| 99 | bindir_SQ = $(subst ','\'',$(bindir)) | ||
| 100 | |||
| 101 | LIB_FILE = liblockdep.a liblockdep.so | ||
| 102 | BIN_FILE = lockdep | ||
| 103 | |||
| 104 | CONFIG_INCLUDES = | ||
| 105 | CONFIG_LIBS = | ||
| 106 | CONFIG_FLAGS = | ||
| 107 | |||
| 108 | OBJ = $@ | ||
| 109 | N = | ||
| 110 | |||
| 111 | export Q VERBOSE | ||
| 112 | |||
| 113 | LIBLOCKDEP_VERSION = $(LL_VERSION).$(LL_PATCHLEVEL).$(LL_EXTRAVERSION) | ||
| 114 | |||
| 115 | INCLUDES = -I. -I/usr/local/include -I./uinclude -I./include $(CONFIG_INCLUDES) | ||
| 116 | |||
| 117 | # Set compile option CFLAGS if not set elsewhere | ||
| 118 | CFLAGS ?= -g -DCONFIG_LOCKDEP -DCONFIG_STACKTRACE -DCONFIG_PROVE_LOCKING -DBITS_PER_LONG=__WORDSIZE -DLIBLOCKDEP_VERSION='"$(LIBLOCKDEP_VERSION)"' -rdynamic -O0 -g | ||
| 119 | |||
| 120 | override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ) | ||
| 121 | |||
| 122 | ifeq ($(VERBOSE),1) | ||
| 123 | Q = | ||
| 124 | print_compile = | ||
| 125 | print_app_build = | ||
| 126 | print_fpic_compile = | ||
| 127 | print_shared_lib_compile = | ||
| 128 | print_install = | ||
| 129 | else | ||
| 130 | Q = @ | ||
| 131 | print_compile = echo ' CC '$(OBJ); | ||
| 132 | print_app_build = echo ' BUILD '$(OBJ); | ||
| 133 | print_fpic_compile = echo ' CC FPIC '$(OBJ); | ||
| 134 | print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ); | ||
| 135 | print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ); | ||
| 136 | print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2'; | ||
| 137 | endif | ||
| 138 | |||
| 139 | do_fpic_compile = \ | ||
| 140 | ($(print_fpic_compile) \ | ||
| 141 | $(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@) | ||
| 142 | |||
| 143 | do_app_build = \ | ||
| 144 | ($(print_app_build) \ | ||
| 145 | $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS)) | ||
| 146 | |||
| 147 | do_compile_shared_library = \ | ||
| 148 | ($(print_shared_lib_compile) \ | ||
| 149 | $(CC) --shared $^ -o $@ -lpthread -ldl) | ||
| 150 | |||
| 151 | do_build_static_lib = \ | ||
| 152 | ($(print_static_lib_build) \ | ||
| 153 | $(RM) $@; $(AR) rcs $@ $^) | ||
| 154 | |||
| 155 | |||
| 156 | define do_compile | ||
| 157 | $(print_compile) \ | ||
| 158 | $(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@; | ||
| 159 | endef | ||
| 160 | |||
| 161 | $(obj)/%.o: $(src)/%.c | ||
| 162 | $(Q)$(call do_compile) | ||
| 163 | |||
| 164 | %.o: $(src)/%.c | ||
| 165 | $(Q)$(call do_compile) | ||
| 166 | |||
| 167 | PEVENT_LIB_OBJS = common.o lockdep.o preload.o rbtree.o | ||
| 168 | |||
| 169 | ALL_OBJS = $(PEVENT_LIB_OBJS) | ||
| 170 | |||
| 171 | CMD_TARGETS = $(LIB_FILE) | ||
| 172 | |||
| 173 | TARGETS = $(CMD_TARGETS) | ||
| 174 | |||
| 175 | |||
| 176 | all: all_cmd | ||
| 177 | |||
| 178 | all_cmd: $(CMD_TARGETS) | ||
| 179 | |||
| 180 | liblockdep.so: $(PEVENT_LIB_OBJS) | ||
| 181 | $(Q)$(do_compile_shared_library) | ||
| 182 | |||
| 183 | liblockdep.a: $(PEVENT_LIB_OBJS) | ||
| 184 | $(Q)$(do_build_static_lib) | ||
| 185 | |||
| 186 | $(PEVENT_LIB_OBJS): %.o: $(src)/%.c | ||
| 187 | $(Q)$(do_fpic_compile) | ||
| 188 | |||
| 189 | ## make deps | ||
| 190 | |||
| 191 | all_objs := $(sort $(ALL_OBJS)) | ||
| 192 | all_deps := $(all_objs:%.o=.%.d) | ||
| 193 | |||
| 194 | # let .d file also depends on the source and header files | ||
| 195 | define check_deps | ||
| 196 | @set -e; $(RM) $@; \ | ||
| 197 | $(CC) -MM $(CFLAGS) $< > $@.$$$$; \ | ||
| 198 | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ | ||
| 199 | $(RM) $@.$$$$ | ||
| 200 | endef | ||
| 201 | |||
| 202 | $(all_deps): .%.d: $(src)/%.c | ||
| 203 | $(Q)$(call check_deps) | ||
| 204 | |||
| 205 | $(all_objs) : %.o : .%.d | ||
| 206 | |||
| 207 | dep_includes := $(wildcard $(all_deps)) | ||
| 208 | |||
| 209 | ifneq ($(dep_includes),) | ||
| 210 | include $(dep_includes) | ||
| 211 | endif | ||
| 212 | |||
| 213 | ### Detect environment changes | ||
| 214 | TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):$(ARCH):$(CROSS_COMPILE) | ||
| 215 | |||
| 216 | tags: force | ||
| 217 | $(RM) tags | ||
| 218 | find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \ | ||
| 219 | --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' | ||
| 220 | |||
| 221 | TAGS: force | ||
| 222 | $(RM) TAGS | ||
| 223 | find . -name '*.[ch]' | xargs etags \ | ||
| 224 | --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' | ||
| 225 | |||
| 226 | define do_install | ||
| 227 | $(print_install) \ | ||
| 228 | if [ ! -d '$(DESTDIR_SQ)$2' ]; then \ | ||
| 229 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \ | ||
| 230 | fi; \ | ||
| 231 | $(INSTALL) $1 '$(DESTDIR_SQ)$2' | ||
| 232 | endef | ||
| 233 | |||
| 234 | install_lib: all_cmd | ||
| 235 | $(Q)$(call do_install,$(LIB_FILE),$(libdir_SQ)) | ||
| 236 | $(Q)$(call do_install,$(BIN_FILE),$(bindir_SQ)) | ||
| 237 | |||
| 238 | install: install_lib | ||
| 239 | |||
| 240 | clean: | ||
| 241 | $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d | ||
| 242 | $(RM) tags TAGS | ||
| 243 | |||
| 244 | endif # skip-makefile | ||
| 245 | |||
| 246 | PHONY += force | ||
| 247 | force: | ||
| 248 | |||
| 249 | # Declare the contents of the .PHONY variable as phony. We keep that | ||
| 250 | # information in a variable so we can use it in if_changed and friends. | ||
| 251 | .PHONY: $(PHONY) | ||
diff --git a/tools/lib/lockdep/common.c b/tools/lib/lockdep/common.c new file mode 100644 index 000000000000..8ef602f18a32 --- /dev/null +++ b/tools/lib/lockdep/common.c | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | #include <stddef.h> | ||
| 2 | #include <stdbool.h> | ||
| 3 | #include <linux/compiler.h> | ||
| 4 | #include <linux/lockdep.h> | ||
| 5 | #include <unistd.h> | ||
| 6 | #include <sys/syscall.h> | ||
| 7 | |||
| 8 | static __thread struct task_struct current_obj; | ||
| 9 | |||
| 10 | /* lockdep wants these */ | ||
| 11 | bool debug_locks = true; | ||
| 12 | bool debug_locks_silent; | ||
| 13 | |||
| 14 | __attribute__((constructor)) static void liblockdep_init(void) | ||
| 15 | { | ||
| 16 | lockdep_init(); | ||
| 17 | } | ||
| 18 | |||
| 19 | __attribute__((destructor)) static void liblockdep_exit(void) | ||
| 20 | { | ||
| 21 | debug_check_no_locks_held(¤t_obj); | ||
| 22 | } | ||
| 23 | |||
| 24 | struct task_struct *__curr(void) | ||
| 25 | { | ||
| 26 | if (current_obj.pid == 0) { | ||
| 27 | /* Makes lockdep output pretty */ | ||
| 28 | prctl(PR_GET_NAME, current_obj.comm); | ||
| 29 | current_obj.pid = syscall(__NR_gettid); | ||
| 30 | } | ||
| 31 | |||
| 32 | return ¤t_obj; | ||
| 33 | } | ||
diff --git a/tools/lib/lockdep/include/liblockdep/common.h b/tools/lib/lockdep/include/liblockdep/common.h new file mode 100644 index 000000000000..0bda630027c3 --- /dev/null +++ b/tools/lib/lockdep/include/liblockdep/common.h | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_COMMON_H | ||
| 2 | #define _LIBLOCKDEP_COMMON_H | ||
| 3 | |||
| 4 | #include <pthread.h> | ||
| 5 | |||
| 6 | #define NR_LOCKDEP_CACHING_CLASSES 2 | ||
| 7 | #define MAX_LOCKDEP_SUBCLASSES 8UL | ||
| 8 | |||
| 9 | #ifndef CALLER_ADDR0 | ||
| 10 | #define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0)) | ||
| 11 | #endif | ||
| 12 | |||
| 13 | #ifndef _RET_IP_ | ||
| 14 | #define _RET_IP_ CALLER_ADDR0 | ||
| 15 | #endif | ||
| 16 | |||
| 17 | #ifndef _THIS_IP_ | ||
| 18 | #define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; }) | ||
| 19 | #endif | ||
| 20 | |||
| 21 | struct lockdep_subclass_key { | ||
| 22 | char __one_byte; | ||
| 23 | }; | ||
| 24 | |||
| 25 | struct lock_class_key { | ||
| 26 | struct lockdep_subclass_key subkeys[MAX_LOCKDEP_SUBCLASSES]; | ||
| 27 | }; | ||
| 28 | |||
| 29 | struct lockdep_map { | ||
| 30 | struct lock_class_key *key; | ||
| 31 | struct lock_class *class_cache[NR_LOCKDEP_CACHING_CLASSES]; | ||
| 32 | const char *name; | ||
| 33 | #ifdef CONFIG_LOCK_STAT | ||
| 34 | int cpu; | ||
| 35 | unsigned long ip; | ||
| 36 | #endif | ||
| 37 | }; | ||
| 38 | |||
| 39 | void lockdep_init_map(struct lockdep_map *lock, const char *name, | ||
| 40 | struct lock_class_key *key, int subclass); | ||
| 41 | void lock_acquire(struct lockdep_map *lock, unsigned int subclass, | ||
| 42 | int trylock, int read, int check, | ||
| 43 | struct lockdep_map *nest_lock, unsigned long ip); | ||
| 44 | void lock_release(struct lockdep_map *lock, int nested, | ||
| 45 | unsigned long ip); | ||
| 46 | |||
| 47 | #define STATIC_LOCKDEP_MAP_INIT(_name, _key) \ | ||
| 48 | { .name = (_name), .key = (void *)(_key), } | ||
| 49 | |||
| 50 | #endif | ||
diff --git a/tools/lib/lockdep/include/liblockdep/mutex.h b/tools/lib/lockdep/include/liblockdep/mutex.h new file mode 100644 index 000000000000..c342f7087147 --- /dev/null +++ b/tools/lib/lockdep/include/liblockdep/mutex.h | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_MUTEX_H | ||
| 2 | #define _LIBLOCKDEP_MUTEX_H | ||
| 3 | |||
| 4 | #include <pthread.h> | ||
| 5 | #include "common.h" | ||
| 6 | |||
| 7 | struct liblockdep_pthread_mutex { | ||
| 8 | pthread_mutex_t mutex; | ||
| 9 | struct lockdep_map dep_map; | ||
| 10 | }; | ||
| 11 | |||
| 12 | typedef struct liblockdep_pthread_mutex liblockdep_pthread_mutex_t; | ||
| 13 | |||
| 14 | #define LIBLOCKDEP_PTHREAD_MUTEX_INITIALIZER(mtx) \ | ||
| 15 | (const struct liblockdep_pthread_mutex) { \ | ||
| 16 | .mutex = PTHREAD_MUTEX_INITIALIZER, \ | ||
| 17 | .dep_map = STATIC_LOCKDEP_MAP_INIT(#mtx, &((&(mtx))->dep_map)), \ | ||
| 18 | } | ||
| 19 | |||
| 20 | static inline int __mutex_init(liblockdep_pthread_mutex_t *lock, | ||
| 21 | const char *name, | ||
| 22 | struct lock_class_key *key, | ||
| 23 | const pthread_mutexattr_t *__mutexattr) | ||
| 24 | { | ||
| 25 | lockdep_init_map(&lock->dep_map, name, key, 0); | ||
| 26 | return pthread_mutex_init(&lock->mutex, __mutexattr); | ||
| 27 | } | ||
| 28 | |||
| 29 | #define liblockdep_pthread_mutex_init(mutex, mutexattr) \ | ||
| 30 | ({ \ | ||
| 31 | static struct lock_class_key __key; \ | ||
| 32 | \ | ||
| 33 | __mutex_init((mutex), #mutex, &__key, (mutexattr)); \ | ||
| 34 | }) | ||
| 35 | |||
| 36 | static inline int liblockdep_pthread_mutex_lock(liblockdep_pthread_mutex_t *lock) | ||
| 37 | { | ||
| 38 | lock_acquire(&lock->dep_map, 0, 0, 0, 2, NULL, (unsigned long)_RET_IP_); | ||
| 39 | return pthread_mutex_lock(&lock->mutex); | ||
| 40 | } | ||
| 41 | |||
| 42 | static inline int liblockdep_pthread_mutex_unlock(liblockdep_pthread_mutex_t *lock) | ||
| 43 | { | ||
| 44 | lock_release(&lock->dep_map, 0, (unsigned long)_RET_IP_); | ||
| 45 | return pthread_mutex_unlock(&lock->mutex); | ||
| 46 | } | ||
| 47 | |||
| 48 | static inline int liblockdep_pthread_mutex_trylock(liblockdep_pthread_mutex_t *lock) | ||
| 49 | { | ||
| 50 | lock_acquire(&lock->dep_map, 0, 1, 0, 2, NULL, (unsigned long)_RET_IP_); | ||
| 51 | return pthread_mutex_trylock(&lock->mutex) == 0 ? 1 : 0; | ||
| 52 | } | ||
| 53 | |||
| 54 | static inline int liblockdep_pthread_mutex_destroy(liblockdep_pthread_mutex_t *lock) | ||
| 55 | { | ||
| 56 | return pthread_mutex_destroy(&lock->mutex); | ||
| 57 | } | ||
| 58 | |||
| 59 | #ifdef __USE_LIBLOCKDEP | ||
| 60 | |||
| 61 | #define pthread_mutex_t liblockdep_pthread_mutex_t | ||
| 62 | #define pthread_mutex_init liblockdep_pthread_mutex_init | ||
| 63 | #define pthread_mutex_lock liblockdep_pthread_mutex_lock | ||
| 64 | #define pthread_mutex_unlock liblockdep_pthread_mutex_unlock | ||
| 65 | #define pthread_mutex_trylock liblockdep_pthread_mutex_trylock | ||
| 66 | #define pthread_mutex_destroy liblockdep_pthread_mutex_destroy | ||
| 67 | |||
| 68 | #endif | ||
| 69 | |||
| 70 | #endif | ||
diff --git a/tools/lib/lockdep/include/liblockdep/rwlock.h b/tools/lib/lockdep/include/liblockdep/rwlock.h new file mode 100644 index 000000000000..a680ab8c2e36 --- /dev/null +++ b/tools/lib/lockdep/include/liblockdep/rwlock.h | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_RWLOCK_H | ||
| 2 | #define _LIBLOCKDEP_RWLOCK_H | ||
| 3 | |||
| 4 | #include <pthread.h> | ||
| 5 | #include "common.h" | ||
| 6 | |||
| 7 | struct liblockdep_pthread_rwlock { | ||
| 8 | pthread_rwlock_t rwlock; | ||
| 9 | struct lockdep_map dep_map; | ||
| 10 | }; | ||
| 11 | |||
| 12 | typedef struct liblockdep_pthread_rwlock liblockdep_pthread_rwlock_t; | ||
| 13 | |||
| 14 | #define LIBLOCKDEP_PTHREAD_RWLOCK_INITIALIZER(rwl) \ | ||
| 15 | (struct liblockdep_pthread_rwlock) { \ | ||
| 16 | .rwlock = PTHREAD_RWLOCK_INITIALIZER, \ | ||
| 17 | .dep_map = STATIC_LOCKDEP_MAP_INIT(#rwl, &((&(rwl))->dep_map)), \ | ||
| 18 | } | ||
| 19 | |||
| 20 | static inline int __rwlock_init(liblockdep_pthread_rwlock_t *lock, | ||
| 21 | const char *name, | ||
| 22 | struct lock_class_key *key, | ||
| 23 | const pthread_rwlockattr_t *attr) | ||
| 24 | { | ||
| 25 | lockdep_init_map(&lock->dep_map, name, key, 0); | ||
| 26 | |||
| 27 | return pthread_rwlock_init(&lock->rwlock, attr); | ||
| 28 | } | ||
| 29 | |||
| 30 | #define liblockdep_pthread_rwlock_init(lock, attr) \ | ||
| 31 | ({ \ | ||
| 32 | static struct lock_class_key __key; \ | ||
| 33 | \ | ||
| 34 | __rwlock_init((lock), #lock, &__key, (attr)); \ | ||
| 35 | }) | ||
| 36 | |||
| 37 | static inline int liblockdep_pthread_rwlock_rdlock(liblockdep_pthread_rwlock_t *lock) | ||
| 38 | { | ||
| 39 | lock_acquire(&lock->dep_map, 0, 0, 2, 2, NULL, (unsigned long)_RET_IP_); | ||
| 40 | return pthread_rwlock_rdlock(&lock->rwlock); | ||
| 41 | |||
| 42 | } | ||
| 43 | |||
| 44 | static inline int liblockdep_pthread_rwlock_unlock(liblockdep_pthread_rwlock_t *lock) | ||
| 45 | { | ||
| 46 | lock_release(&lock->dep_map, 0, (unsigned long)_RET_IP_); | ||
| 47 | return pthread_rwlock_unlock(&lock->rwlock); | ||
| 48 | } | ||
| 49 | |||
| 50 | static inline int liblockdep_pthread_rwlock_wrlock(liblockdep_pthread_rwlock_t *lock) | ||
| 51 | { | ||
| 52 | lock_acquire(&lock->dep_map, 0, 0, 0, 2, NULL, (unsigned long)_RET_IP_); | ||
| 53 | return pthread_rwlock_wrlock(&lock->rwlock); | ||
| 54 | } | ||
| 55 | |||
| 56 | static inline int liblockdep_pthread_rwlock_tryrdlock(liblockdep_pthread_rwlock_t *lock) | ||
| 57 | { | ||
| 58 | lock_acquire(&lock->dep_map, 0, 1, 2, 2, NULL, (unsigned long)_RET_IP_); | ||
| 59 | return pthread_rwlock_tryrdlock(&lock->rwlock) == 0 ? 1 : 0; | ||
| 60 | } | ||
| 61 | |||
| 62 | static inline int liblockdep_pthread_rwlock_trywlock(liblockdep_pthread_rwlock_t *lock) | ||
| 63 | { | ||
| 64 | lock_acquire(&lock->dep_map, 0, 1, 0, 2, NULL, (unsigned long)_RET_IP_); | ||
| 65 | return pthread_rwlock_trywlock(&lock->rwlock) == 0 ? 1 : 0; | ||
| 66 | } | ||
| 67 | |||
| 68 | static inline int liblockdep_rwlock_destroy(liblockdep_pthread_rwlock_t *lock) | ||
| 69 | { | ||
| 70 | return pthread_rwlock_destroy(&lock->rwlock); | ||
| 71 | } | ||
| 72 | |||
| 73 | #ifdef __USE_LIBLOCKDEP | ||
| 74 | |||
| 75 | #define pthread_rwlock_t liblockdep_pthread_rwlock_t | ||
| 76 | #define pthread_rwlock_init liblockdep_pthread_rwlock_init | ||
| 77 | #define pthread_rwlock_rdlock liblockdep_pthread_rwlock_rdlock | ||
| 78 | #define pthread_rwlock_unlock liblockdep_pthread_rwlock_unlock | ||
| 79 | #define pthread_rwlock_wrlock liblockdep_pthread_rwlock_wrlock | ||
| 80 | #define pthread_rwlock_tryrdlock liblockdep_pthread_rwlock_tryrdlock | ||
| 81 | #define pthread_rwlock_trywlock liblockdep_pthread_rwlock_trywlock | ||
| 82 | #define pthread_rwlock_destroy liblockdep_rwlock_destroy | ||
| 83 | |||
| 84 | #endif | ||
| 85 | |||
| 86 | #endif | ||
diff --git a/tools/lib/lockdep/lockdep b/tools/lib/lockdep/lockdep new file mode 100755 index 000000000000..49af9fe19f5b --- /dev/null +++ b/tools/lib/lockdep/lockdep | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | |||
| 3 | LD_PRELOAD="./liblockdep.so $LD_PRELOAD" "$@" | ||
diff --git a/tools/lib/lockdep/lockdep.c b/tools/lib/lockdep/lockdep.c new file mode 100644 index 000000000000..f42b7e9aa48f --- /dev/null +++ b/tools/lib/lockdep/lockdep.c | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | #include <linux/lockdep.h> | ||
| 2 | #include "../../../kernel/locking/lockdep.c" | ||
diff --git a/tools/lib/lockdep/lockdep_internals.h b/tools/lib/lockdep/lockdep_internals.h new file mode 100644 index 000000000000..29d0c954cc24 --- /dev/null +++ b/tools/lib/lockdep/lockdep_internals.h | |||
| @@ -0,0 +1 @@ | |||
| #include "../../../kernel/locking/lockdep_internals.h" | |||
diff --git a/tools/lib/lockdep/lockdep_states.h b/tools/lib/lockdep/lockdep_states.h new file mode 100644 index 000000000000..248d235efda9 --- /dev/null +++ b/tools/lib/lockdep/lockdep_states.h | |||
| @@ -0,0 +1 @@ | |||
| #include "../../../kernel/locking/lockdep_states.h" | |||
diff --git a/tools/lib/lockdep/preload.c b/tools/lib/lockdep/preload.c new file mode 100644 index 000000000000..23bd69cb5ade --- /dev/null +++ b/tools/lib/lockdep/preload.c | |||
| @@ -0,0 +1,447 @@ | |||
| 1 | #define _GNU_SOURCE | ||
| 2 | #include <pthread.h> | ||
| 3 | #include <stdio.h> | ||
| 4 | #include <dlfcn.h> | ||
| 5 | #include <stdlib.h> | ||
| 6 | #include <sysexits.h> | ||
| 7 | #include "include/liblockdep/mutex.h" | ||
| 8 | #include "../../../include/linux/rbtree.h" | ||
| 9 | |||
| 10 | /** | ||
| 11 | * struct lock_lookup - liblockdep's view of a single unique lock | ||
| 12 | * @orig: pointer to the original pthread lock, used for lookups | ||
| 13 | * @dep_map: lockdep's dep_map structure | ||
| 14 | * @key: lockdep's key structure | ||
| 15 | * @node: rb-tree node used to store the lock in a global tree | ||
| 16 | * @name: a unique name for the lock | ||
| 17 | */ | ||
| 18 | struct lock_lookup { | ||
| 19 | void *orig; /* Original pthread lock, used for lookups */ | ||
| 20 | struct lockdep_map dep_map; /* Since all locks are dynamic, we need | ||
| 21 | * a dep_map and a key for each lock */ | ||
| 22 | /* | ||
| 23 | * Wait, there's no support for key classes? Yup :( | ||
| 24 | * Most big projects wrap the pthread api with their own calls to | ||
| 25 | * be compatible with different locking methods. This means that | ||
| 26 | * "classes" will be brokes since the function that creates all | ||
| 27 | * locks will point to a generic locking function instead of the | ||
| 28 | * actual code that wants to do the locking. | ||
| 29 | */ | ||
| 30 | struct lock_class_key key; | ||
| 31 | struct rb_node node; | ||
| 32 | #define LIBLOCKDEP_MAX_LOCK_NAME 22 | ||
| 33 | char name[LIBLOCKDEP_MAX_LOCK_NAME]; | ||
| 34 | }; | ||
| 35 | |||
| 36 | /* This is where we store our locks */ | ||
| 37 | static struct rb_root locks = RB_ROOT; | ||
| 38 | static pthread_rwlock_t locks_rwlock = PTHREAD_RWLOCK_INITIALIZER; | ||
| 39 | |||
| 40 | /* pthread mutex API */ | ||
| 41 | |||
| 42 | #ifdef __GLIBC__ | ||
| 43 | extern int __pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); | ||
| 44 | extern int __pthread_mutex_lock(pthread_mutex_t *mutex); | ||
| 45 | extern int __pthread_mutex_trylock(pthread_mutex_t *mutex); | ||
| 46 | extern int __pthread_mutex_unlock(pthread_mutex_t *mutex); | ||
| 47 | extern int __pthread_mutex_destroy(pthread_mutex_t *mutex); | ||
| 48 | #else | ||
| 49 | #define __pthread_mutex_init NULL | ||
| 50 | #define __pthread_mutex_lock NULL | ||
| 51 | #define __pthread_mutex_trylock NULL | ||
| 52 | #define __pthread_mutex_unlock NULL | ||
| 53 | #define __pthread_mutex_destroy NULL | ||
| 54 | #endif | ||
| 55 | static int (*ll_pthread_mutex_init)(pthread_mutex_t *mutex, | ||
| 56 | const pthread_mutexattr_t *attr) = __pthread_mutex_init; | ||
| 57 | static int (*ll_pthread_mutex_lock)(pthread_mutex_t *mutex) = __pthread_mutex_lock; | ||
| 58 | static int (*ll_pthread_mutex_trylock)(pthread_mutex_t *mutex) = __pthread_mutex_trylock; | ||
| 59 | static int (*ll_pthread_mutex_unlock)(pthread_mutex_t *mutex) = __pthread_mutex_unlock; | ||
| 60 | static int (*ll_pthread_mutex_destroy)(pthread_mutex_t *mutex) = __pthread_mutex_destroy; | ||
| 61 | |||
| 62 | /* pthread rwlock API */ | ||
| 63 | |||
| 64 | #ifdef __GLIBC__ | ||
| 65 | extern int __pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr); | ||
| 66 | extern int __pthread_rwlock_destroy(pthread_rwlock_t *rwlock); | ||
| 67 | extern int __pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); | ||
| 68 | extern int __pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); | ||
| 69 | extern int __pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); | ||
| 70 | extern int __pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); | ||
| 71 | extern int __pthread_rwlock_unlock(pthread_rwlock_t *rwlock); | ||
| 72 | #else | ||
| 73 | #define __pthread_rwlock_init NULL | ||
| 74 | #define __pthread_rwlock_destroy NULL | ||
| 75 | #define __pthread_rwlock_wrlock NULL | ||
| 76 | #define __pthread_rwlock_trywrlock NULL | ||
| 77 | #define __pthread_rwlock_rdlock NULL | ||
| 78 | #define __pthread_rwlock_tryrdlock NULL | ||
| 79 | #define __pthread_rwlock_unlock NULL | ||
| 80 | #endif | ||
| 81 | |||
| 82 | static int (*ll_pthread_rwlock_init)(pthread_rwlock_t *rwlock, | ||
| 83 | const pthread_rwlockattr_t *attr) = __pthread_rwlock_init; | ||
| 84 | static int (*ll_pthread_rwlock_destroy)(pthread_rwlock_t *rwlock) = __pthread_rwlock_destroy; | ||
| 85 | static int (*ll_pthread_rwlock_rdlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_rdlock; | ||
| 86 | static int (*ll_pthread_rwlock_tryrdlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_tryrdlock; | ||
| 87 | static int (*ll_pthread_rwlock_trywrlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_trywrlock; | ||
| 88 | static int (*ll_pthread_rwlock_wrlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_wrlock; | ||
| 89 | static int (*ll_pthread_rwlock_unlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_unlock; | ||
| 90 | |||
| 91 | enum { none, prepare, done, } __init_state; | ||
| 92 | static void init_preload(void); | ||
| 93 | static void try_init_preload(void) | ||
| 94 | { | ||
| 95 | if (!__init_state != done) | ||
| 96 | init_preload(); | ||
| 97 | } | ||
| 98 | |||
| 99 | static struct rb_node **__get_lock_node(void *lock, struct rb_node **parent) | ||
| 100 | { | ||
| 101 | struct rb_node **node = &locks.rb_node; | ||
| 102 | struct lock_lookup *l; | ||
| 103 | |||
| 104 | *parent = NULL; | ||
| 105 | |||
| 106 | while (*node) { | ||
| 107 | l = rb_entry(*node, struct lock_lookup, node); | ||
| 108 | |||
| 109 | *parent = *node; | ||
| 110 | if (lock < l->orig) | ||
| 111 | node = &l->node.rb_left; | ||
| 112 | else if (lock > l->orig) | ||
| 113 | node = &l->node.rb_right; | ||
| 114 | else | ||
| 115 | return node; | ||
| 116 | } | ||
| 117 | |||
| 118 | return node; | ||
| 119 | } | ||
| 120 | |||
| 121 | #ifndef LIBLOCKDEP_STATIC_ENTRIES | ||
| 122 | #define LIBLOCKDEP_STATIC_ENTRIES 1024 | ||
| 123 | #endif | ||
| 124 | |||
| 125 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | ||
| 126 | |||
| 127 | static struct lock_lookup __locks[LIBLOCKDEP_STATIC_ENTRIES]; | ||
| 128 | static int __locks_nr; | ||
| 129 | |||
| 130 | static inline bool is_static_lock(struct lock_lookup *lock) | ||
| 131 | { | ||
| 132 | return lock >= __locks && lock < __locks + ARRAY_SIZE(__locks); | ||
| 133 | } | ||
| 134 | |||
| 135 | static struct lock_lookup *alloc_lock(void) | ||
| 136 | { | ||
| 137 | if (__init_state != done) { | ||
| 138 | /* | ||
| 139 | * Some programs attempt to initialize and use locks in their | ||
| 140 | * allocation path. This means that a call to malloc() would | ||
| 141 | * result in locks being initialized and locked. | ||
| 142 | * | ||
| 143 | * Why is it an issue for us? dlsym() below will try allocating | ||
| 144 | * to give us the original function. Since this allocation will | ||
| 145 | * result in a locking operations, we have to let pthread deal | ||
| 146 | * with it, but we can't! we don't have the pointer to the | ||
| 147 | * original API since we're inside dlsym() trying to get it | ||
| 148 | */ | ||
| 149 | |||
| 150 | int idx = __locks_nr++; | ||
| 151 | if (idx >= ARRAY_SIZE(__locks)) { | ||
| 152 | fprintf(stderr, | ||
| 153 | "LOCKDEP error: insufficient LIBLOCKDEP_STATIC_ENTRIES\n"); | ||
| 154 | exit(EX_UNAVAILABLE); | ||
| 155 | } | ||
| 156 | return __locks + idx; | ||
| 157 | } | ||
| 158 | |||
| 159 | return malloc(sizeof(struct lock_lookup)); | ||
| 160 | } | ||
| 161 | |||
| 162 | static inline void free_lock(struct lock_lookup *lock) | ||
| 163 | { | ||
| 164 | if (likely(!is_static_lock(lock))) | ||
| 165 | free(lock); | ||
| 166 | } | ||
| 167 | |||
| 168 | /** | ||
| 169 | * __get_lock - find or create a lock instance | ||
| 170 | * @lock: pointer to a pthread lock function | ||
| 171 | * | ||
| 172 | * Try to find an existing lock in the rbtree using the provided pointer. If | ||
| 173 | * one wasn't found - create it. | ||
| 174 | */ | ||
| 175 | static struct lock_lookup *__get_lock(void *lock) | ||
| 176 | { | ||
| 177 | struct rb_node **node, *parent; | ||
| 178 | struct lock_lookup *l; | ||
| 179 | |||
| 180 | ll_pthread_rwlock_rdlock(&locks_rwlock); | ||
| 181 | node = __get_lock_node(lock, &parent); | ||
| 182 | ll_pthread_rwlock_unlock(&locks_rwlock); | ||
| 183 | if (*node) { | ||
| 184 | return rb_entry(*node, struct lock_lookup, node); | ||
| 185 | } | ||
| 186 | |||
| 187 | /* We didn't find the lock, let's create it */ | ||
| 188 | l = alloc_lock(); | ||
| 189 | if (l == NULL) | ||
| 190 | return NULL; | ||
| 191 | |||
| 192 | l->orig = lock; | ||
| 193 | /* | ||
| 194 | * Currently the name of the lock is the ptr value of the pthread lock, | ||
| 195 | * while not optimal, it makes debugging a bit easier. | ||
| 196 | * | ||
| 197 | * TODO: Get the real name of the lock using libdwarf | ||
| 198 | */ | ||
| 199 | sprintf(l->name, "%p", lock); | ||
| 200 | lockdep_init_map(&l->dep_map, l->name, &l->key, 0); | ||
| 201 | |||
| 202 | ll_pthread_rwlock_wrlock(&locks_rwlock); | ||
| 203 | /* This might have changed since the last time we fetched it */ | ||
| 204 | node = __get_lock_node(lock, &parent); | ||
| 205 | rb_link_node(&l->node, parent, node); | ||
| 206 | rb_insert_color(&l->node, &locks); | ||
| 207 | ll_pthread_rwlock_unlock(&locks_rwlock); | ||
| 208 | |||
| 209 | return l; | ||
| 210 | } | ||
| 211 | |||
| 212 | static void __del_lock(struct lock_lookup *lock) | ||
| 213 | { | ||
| 214 | ll_pthread_rwlock_wrlock(&locks_rwlock); | ||
| 215 | rb_erase(&lock->node, &locks); | ||
| 216 | ll_pthread_rwlock_unlock(&locks_rwlock); | ||
| 217 | free_lock(lock); | ||
| 218 | } | ||
| 219 | |||
| 220 | int pthread_mutex_init(pthread_mutex_t *mutex, | ||
| 221 | const pthread_mutexattr_t *attr) | ||
| 222 | { | ||
| 223 | int r; | ||
| 224 | |||
| 225 | /* | ||
| 226 | * We keep trying to init our preload module because there might be | ||
| 227 | * code in init sections that tries to touch locks before we are | ||
| 228 | * initialized, in that case we'll need to manually call preload | ||
| 229 | * to get us going. | ||
| 230 | * | ||
| 231 | * Funny enough, kernel's lockdep had the same issue, and used | ||
| 232 | * (almost) the same solution. See look_up_lock_class() in | ||
| 233 | * kernel/locking/lockdep.c for details. | ||
| 234 | */ | ||
| 235 | try_init_preload(); | ||
| 236 | |||
| 237 | r = ll_pthread_mutex_init(mutex, attr); | ||
| 238 | if (r == 0) | ||
| 239 | /* | ||
| 240 | * We do a dummy initialization here so that lockdep could | ||
| 241 | * warn us if something fishy is going on - such as | ||
| 242 | * initializing a held lock. | ||
| 243 | */ | ||
| 244 | __get_lock(mutex); | ||
| 245 | |||
| 246 | return r; | ||
| 247 | } | ||
| 248 | |||
| 249 | int pthread_mutex_lock(pthread_mutex_t *mutex) | ||
| 250 | { | ||
| 251 | int r; | ||
| 252 | |||
| 253 | try_init_preload(); | ||
| 254 | |||
| 255 | lock_acquire(&__get_lock(mutex)->dep_map, 0, 0, 0, 2, NULL, | ||
| 256 | (unsigned long)_RET_IP_); | ||
| 257 | /* | ||
| 258 | * Here's the thing with pthread mutexes: unlike the kernel variant, | ||
| 259 | * they can fail. | ||
| 260 | * | ||
| 261 | * This means that the behaviour here is a bit different from what's | ||
| 262 | * going on in the kernel: there we just tell lockdep that we took the | ||
| 263 | * lock before actually taking it, but here we must deal with the case | ||
| 264 | * that locking failed. | ||
| 265 | * | ||
| 266 | * To do that we'll "release" the lock if locking failed - this way | ||
| 267 | * we'll get lockdep doing the correct checks when we try to take | ||
| 268 | * the lock, and if that fails - we'll be back to the correct | ||
| 269 | * state by releasing it. | ||
| 270 | */ | ||
| 271 | r = ll_pthread_mutex_lock(mutex); | ||
| 272 | if (r) | ||
| 273 | lock_release(&__get_lock(mutex)->dep_map, 0, (unsigned long)_RET_IP_); | ||
| 274 | |||
| 275 | return r; | ||
| 276 | } | ||
| 277 | |||
| 278 | int pthread_mutex_trylock(pthread_mutex_t *mutex) | ||
| 279 | { | ||
| 280 | int r; | ||
| 281 | |||
| 282 | try_init_preload(); | ||
| 283 | |||
| 284 | lock_acquire(&__get_lock(mutex)->dep_map, 0, 1, 0, 2, NULL, (unsigned long)_RET_IP_); | ||
| 285 | r = ll_pthread_mutex_trylock(mutex); | ||
| 286 | if (r) | ||
| 287 | lock_release(&__get_lock(mutex)->dep_map, 0, (unsigned long)_RET_IP_); | ||
| 288 | |||
| 289 | return r; | ||
| 290 | } | ||
| 291 | |||
| 292 | int pthread_mutex_unlock(pthread_mutex_t *mutex) | ||
| 293 | { | ||
| 294 | int r; | ||
| 295 | |||
| 296 | try_init_preload(); | ||
| 297 | |||
| 298 | lock_release(&__get_lock(mutex)->dep_map, 0, (unsigned long)_RET_IP_); | ||
| 299 | /* | ||
| 300 | * Just like taking a lock, only in reverse! | ||
| 301 | * | ||
| 302 | * If we fail releasing the lock, tell lockdep we're holding it again. | ||
| 303 | */ | ||
| 304 | r = ll_pthread_mutex_unlock(mutex); | ||
| 305 | if (r) | ||
| 306 | lock_acquire(&__get_lock(mutex)->dep_map, 0, 0, 0, 2, NULL, (unsigned long)_RET_IP_); | ||
| 307 | |||
| 308 | return r; | ||
| 309 | } | ||
| 310 | |||
| 311 | int pthread_mutex_destroy(pthread_mutex_t *mutex) | ||
| 312 | { | ||
| 313 | try_init_preload(); | ||
| 314 | |||
| 315 | /* | ||
| 316 | * Let's see if we're releasing a lock that's held. | ||
| 317 | * | ||
| 318 | * TODO: Hook into free() and add that check there as well. | ||
| 319 | */ | ||
| 320 | debug_check_no_locks_freed(mutex, mutex + sizeof(*mutex)); | ||
| 321 | __del_lock(__get_lock(mutex)); | ||
| 322 | return ll_pthread_mutex_destroy(mutex); | ||
| 323 | } | ||
| 324 | |||
| 325 | /* This is the rwlock part, very similar to what happened with mutex above */ | ||
| 326 | int pthread_rwlock_init(pthread_rwlock_t *rwlock, | ||
| 327 | const pthread_rwlockattr_t *attr) | ||
| 328 | { | ||
| 329 | int r; | ||
| 330 | |||
| 331 | try_init_preload(); | ||
| 332 | |||
| 333 | r = ll_pthread_rwlock_init(rwlock, attr); | ||
| 334 | if (r == 0) | ||
| 335 | __get_lock(rwlock); | ||
| 336 | |||
| 337 | return r; | ||
| 338 | } | ||
| 339 | |||
| 340 | int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) | ||
| 341 | { | ||
| 342 | try_init_preload(); | ||
| 343 | |||
| 344 | debug_check_no_locks_freed(rwlock, rwlock + sizeof(*rwlock)); | ||
| 345 | __del_lock(__get_lock(rwlock)); | ||
| 346 | return ll_pthread_rwlock_destroy(rwlock); | ||
| 347 | } | ||
| 348 | |||
| 349 | int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) | ||
| 350 | { | ||
| 351 | int r; | ||
| 352 | |||
| 353 | init_preload(); | ||
| 354 | |||
| 355 | lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 2, 2, NULL, (unsigned long)_RET_IP_); | ||
| 356 | r = ll_pthread_rwlock_rdlock(rwlock); | ||
| 357 | if (r) | ||
| 358 | lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_); | ||
| 359 | |||
| 360 | return r; | ||
| 361 | } | ||
| 362 | |||
| 363 | int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) | ||
| 364 | { | ||
| 365 | int r; | ||
| 366 | |||
| 367 | init_preload(); | ||
| 368 | |||
| 369 | lock_acquire(&__get_lock(rwlock)->dep_map, 0, 1, 2, 2, NULL, (unsigned long)_RET_IP_); | ||
| 370 | r = ll_pthread_rwlock_tryrdlock(rwlock); | ||
| 371 | if (r) | ||
| 372 | lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_); | ||
| 373 | |||
| 374 | return r; | ||
| 375 | } | ||
| 376 | |||
| 377 | int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) | ||
| 378 | { | ||
| 379 | int r; | ||
| 380 | |||
| 381 | init_preload(); | ||
| 382 | |||
| 383 | lock_acquire(&__get_lock(rwlock)->dep_map, 0, 1, 0, 2, NULL, (unsigned long)_RET_IP_); | ||
| 384 | r = ll_pthread_rwlock_trywrlock(rwlock); | ||
| 385 | if (r) | ||
| 386 | lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_); | ||
| 387 | |||
| 388 | return r; | ||
| 389 | } | ||
| 390 | |||
| 391 | int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) | ||
| 392 | { | ||
| 393 | int r; | ||
| 394 | |||
| 395 | init_preload(); | ||
| 396 | |||
| 397 | lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 0, 2, NULL, (unsigned long)_RET_IP_); | ||
| 398 | r = ll_pthread_rwlock_wrlock(rwlock); | ||
| 399 | if (r) | ||
| 400 | lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_); | ||
| 401 | |||
| 402 | return r; | ||
| 403 | } | ||
| 404 | |||
| 405 | int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) | ||
| 406 | { | ||
| 407 | int r; | ||
| 408 | |||
| 409 | init_preload(); | ||
| 410 | |||
| 411 | lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_); | ||
| 412 | r = ll_pthread_rwlock_unlock(rwlock); | ||
| 413 | if (r) | ||
| 414 | lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 0, 2, NULL, (unsigned long)_RET_IP_); | ||
| 415 | |||
| 416 | return r; | ||
| 417 | } | ||
| 418 | |||
| 419 | __attribute__((constructor)) static void init_preload(void) | ||
| 420 | { | ||
| 421 | if (__init_state == done) | ||
| 422 | return; | ||
| 423 | |||
| 424 | #ifndef __GLIBC__ | ||
| 425 | __init_state = prepare; | ||
| 426 | |||
| 427 | ll_pthread_mutex_init = dlsym(RTLD_NEXT, "pthread_mutex_init"); | ||
| 428 | ll_pthread_mutex_lock = dlsym(RTLD_NEXT, "pthread_mutex_lock"); | ||
| 429 | ll_pthread_mutex_trylock = dlsym(RTLD_NEXT, "pthread_mutex_trylock"); | ||
| 430 | ll_pthread_mutex_unlock = dlsym(RTLD_NEXT, "pthread_mutex_unlock"); | ||
| 431 | ll_pthread_mutex_destroy = dlsym(RTLD_NEXT, "pthread_mutex_destroy"); | ||
| 432 | |||
| 433 | ll_pthread_rwlock_init = dlsym(RTLD_NEXT, "pthread_rwlock_init"); | ||
| 434 | ll_pthread_rwlock_destroy = dlsym(RTLD_NEXT, "pthread_rwlock_destroy"); | ||
| 435 | ll_pthread_rwlock_rdlock = dlsym(RTLD_NEXT, "pthread_rwlock_rdlock"); | ||
| 436 | ll_pthread_rwlock_tryrdlock = dlsym(RTLD_NEXT, "pthread_rwlock_tryrdlock"); | ||
| 437 | ll_pthread_rwlock_wrlock = dlsym(RTLD_NEXT, "pthread_rwlock_wrlock"); | ||
| 438 | ll_pthread_rwlock_trywrlock = dlsym(RTLD_NEXT, "pthread_rwlock_trywrlock"); | ||
| 439 | ll_pthread_rwlock_unlock = dlsym(RTLD_NEXT, "pthread_rwlock_unlock"); | ||
| 440 | #endif | ||
| 441 | |||
| 442 | printf("%p\n", ll_pthread_mutex_trylock);fflush(stdout); | ||
| 443 | |||
| 444 | lockdep_init(); | ||
| 445 | |||
| 446 | __init_state = done; | ||
| 447 | } | ||
diff --git a/tools/lib/lockdep/rbtree.c b/tools/lib/lockdep/rbtree.c new file mode 100644 index 000000000000..f7f43033c8b7 --- /dev/null +++ b/tools/lib/lockdep/rbtree.c | |||
| @@ -0,0 +1 @@ | |||
| #include "../../../lib/rbtree.c" | |||
diff --git a/tools/lib/lockdep/run_tests.sh b/tools/lib/lockdep/run_tests.sh new file mode 100755 index 000000000000..5334ad9d39b7 --- /dev/null +++ b/tools/lib/lockdep/run_tests.sh | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | #! /bin/bash | ||
| 2 | |||
| 3 | make &> /dev/null | ||
| 4 | |||
| 5 | for i in `ls tests/*.c`; do | ||
| 6 | testname=$(basename -s .c "$i") | ||
| 7 | gcc -o tests/$testname -pthread -lpthread $i liblockdep.a -Iinclude -D__USE_LIBLOCKDEP &> /dev/null | ||
| 8 | echo -ne "$testname... " | ||
| 9 | if [ $(timeout 1 ./tests/$testname | wc -l) -gt 0 ]; then | ||
| 10 | echo "PASSED!" | ||
| 11 | else | ||
| 12 | echo "FAILED!" | ||
| 13 | fi | ||
| 14 | rm tests/$testname | ||
| 15 | done | ||
| 16 | |||
| 17 | for i in `ls tests/*.c`; do | ||
| 18 | testname=$(basename -s .c "$i") | ||
| 19 | gcc -o tests/$testname -pthread -lpthread -Iinclude $i &> /dev/null | ||
| 20 | echo -ne "(PRELOAD) $testname... " | ||
| 21 | if [ $(timeout 1 ./lockdep ./tests/$testname | wc -l) -gt 0 ]; then | ||
| 22 | echo "PASSED!" | ||
| 23 | else | ||
| 24 | echo "FAILED!" | ||
| 25 | fi | ||
| 26 | rm tests/$testname | ||
| 27 | done | ||
diff --git a/tools/lib/lockdep/tests/AA.c b/tools/lib/lockdep/tests/AA.c new file mode 100644 index 000000000000..0f782ff404ac --- /dev/null +++ b/tools/lib/lockdep/tests/AA.c | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | #include <liblockdep/mutex.h> | ||
| 2 | |||
| 3 | void main(void) | ||
| 4 | { | ||
| 5 | pthread_mutex_t a, b; | ||
| 6 | |||
| 7 | pthread_mutex_init(&a, NULL); | ||
| 8 | pthread_mutex_init(&b, NULL); | ||
| 9 | |||
| 10 | pthread_mutex_lock(&a); | ||
| 11 | pthread_mutex_lock(&b); | ||
| 12 | pthread_mutex_lock(&a); | ||
| 13 | } | ||
diff --git a/tools/lib/lockdep/tests/ABBA.c b/tools/lib/lockdep/tests/ABBA.c new file mode 100644 index 000000000000..07f0e29d5485 --- /dev/null +++ b/tools/lib/lockdep/tests/ABBA.c | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | #include <liblockdep/mutex.h> | ||
| 2 | #include "common.h" | ||
| 3 | |||
| 4 | void main(void) | ||
| 5 | { | ||
| 6 | pthread_mutex_t a, b; | ||
| 7 | |||
| 8 | pthread_mutex_init(&a, NULL); | ||
| 9 | pthread_mutex_init(&b, NULL); | ||
| 10 | |||
| 11 | LOCK_UNLOCK_2(a, b); | ||
| 12 | LOCK_UNLOCK_2(b, a); | ||
| 13 | } | ||
diff --git a/tools/lib/lockdep/tests/ABBCCA.c b/tools/lib/lockdep/tests/ABBCCA.c new file mode 100644 index 000000000000..843db09ac666 --- /dev/null +++ b/tools/lib/lockdep/tests/ABBCCA.c | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | #include <liblockdep/mutex.h> | ||
| 2 | #include "common.h" | ||
| 3 | |||
| 4 | void main(void) | ||
| 5 | { | ||
| 6 | pthread_mutex_t a, b, c; | ||
| 7 | |||
| 8 | pthread_mutex_init(&a, NULL); | ||
| 9 | pthread_mutex_init(&b, NULL); | ||
| 10 | pthread_mutex_init(&c, NULL); | ||
| 11 | |||
| 12 | LOCK_UNLOCK_2(a, b); | ||
| 13 | LOCK_UNLOCK_2(b, c); | ||
| 14 | LOCK_UNLOCK_2(c, a); | ||
| 15 | } | ||
diff --git a/tools/lib/lockdep/tests/ABBCCDDA.c b/tools/lib/lockdep/tests/ABBCCDDA.c new file mode 100644 index 000000000000..33620e268f85 --- /dev/null +++ b/tools/lib/lockdep/tests/ABBCCDDA.c | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | #include <liblockdep/mutex.h> | ||
| 2 | #include "common.h" | ||
| 3 | |||
| 4 | void main(void) | ||
| 5 | { | ||
| 6 | pthread_mutex_t a, b, c, d; | ||
| 7 | |||
| 8 | pthread_mutex_init(&a, NULL); | ||
| 9 | pthread_mutex_init(&b, NULL); | ||
| 10 | pthread_mutex_init(&c, NULL); | ||
| 11 | pthread_mutex_init(&d, NULL); | ||
| 12 | |||
| 13 | LOCK_UNLOCK_2(a, b); | ||
| 14 | LOCK_UNLOCK_2(b, c); | ||
| 15 | LOCK_UNLOCK_2(c, d); | ||
| 16 | LOCK_UNLOCK_2(d, a); | ||
| 17 | } | ||
diff --git a/tools/lib/lockdep/tests/ABCABC.c b/tools/lib/lockdep/tests/ABCABC.c new file mode 100644 index 000000000000..3fee51e3a68a --- /dev/null +++ b/tools/lib/lockdep/tests/ABCABC.c | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | #include <liblockdep/mutex.h> | ||
| 2 | #include "common.h" | ||
| 3 | |||
| 4 | void main(void) | ||
| 5 | { | ||
| 6 | pthread_mutex_t a, b, c; | ||
| 7 | |||
| 8 | pthread_mutex_init(&a, NULL); | ||
| 9 | pthread_mutex_init(&b, NULL); | ||
| 10 | pthread_mutex_init(&c, NULL); | ||
| 11 | |||
| 12 | LOCK_UNLOCK_2(a, b); | ||
| 13 | LOCK_UNLOCK_2(c, a); | ||
| 14 | LOCK_UNLOCK_2(b, c); | ||
| 15 | } | ||
diff --git a/tools/lib/lockdep/tests/ABCDBCDA.c b/tools/lib/lockdep/tests/ABCDBCDA.c new file mode 100644 index 000000000000..427ba562c75b --- /dev/null +++ b/tools/lib/lockdep/tests/ABCDBCDA.c | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | #include <liblockdep/mutex.h> | ||
| 2 | #include "common.h" | ||
| 3 | |||
| 4 | void main(void) | ||
| 5 | { | ||
| 6 | pthread_mutex_t a, b, c, d; | ||
| 7 | |||
| 8 | pthread_mutex_init(&a, NULL); | ||
| 9 | pthread_mutex_init(&b, NULL); | ||
| 10 | pthread_mutex_init(&c, NULL); | ||
| 11 | pthread_mutex_init(&d, NULL); | ||
| 12 | |||
| 13 | LOCK_UNLOCK_2(a, b); | ||
| 14 | LOCK_UNLOCK_2(c, d); | ||
| 15 | LOCK_UNLOCK_2(b, c); | ||
| 16 | LOCK_UNLOCK_2(d, a); | ||
| 17 | } | ||
diff --git a/tools/lib/lockdep/tests/ABCDBDDA.c b/tools/lib/lockdep/tests/ABCDBDDA.c new file mode 100644 index 000000000000..680c6cf3e919 --- /dev/null +++ b/tools/lib/lockdep/tests/ABCDBDDA.c | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | #include <liblockdep/mutex.h> | ||
| 2 | #include "common.h" | ||
| 3 | |||
| 4 | void main(void) | ||
| 5 | { | ||
| 6 | pthread_mutex_t a, b, c, d; | ||
| 7 | |||
| 8 | pthread_mutex_init(&a, NULL); | ||
| 9 | pthread_mutex_init(&b, NULL); | ||
| 10 | pthread_mutex_init(&c, NULL); | ||
| 11 | pthread_mutex_init(&d, NULL); | ||
| 12 | |||
| 13 | LOCK_UNLOCK_2(a, b); | ||
| 14 | LOCK_UNLOCK_2(c, d); | ||
| 15 | LOCK_UNLOCK_2(b, d); | ||
| 16 | LOCK_UNLOCK_2(d, a); | ||
| 17 | } | ||
diff --git a/tools/lib/lockdep/tests/WW.c b/tools/lib/lockdep/tests/WW.c new file mode 100644 index 000000000000..d44f77d71029 --- /dev/null +++ b/tools/lib/lockdep/tests/WW.c | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | #include <liblockdep/rwlock.h> | ||
| 2 | |||
| 3 | void main(void) | ||
| 4 | { | ||
| 5 | pthread_rwlock_t a, b; | ||
| 6 | |||
| 7 | pthread_rwlock_init(&a, NULL); | ||
| 8 | pthread_rwlock_init(&b, NULL); | ||
| 9 | |||
| 10 | pthread_rwlock_wrlock(&a); | ||
| 11 | pthread_rwlock_rdlock(&b); | ||
| 12 | pthread_rwlock_wrlock(&a); | ||
| 13 | } | ||
diff --git a/tools/lib/lockdep/tests/common.h b/tools/lib/lockdep/tests/common.h new file mode 100644 index 000000000000..d89e94d47d86 --- /dev/null +++ b/tools/lib/lockdep/tests/common.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_TEST_COMMON_H | ||
| 2 | #define _LIBLOCKDEP_TEST_COMMON_H | ||
| 3 | |||
| 4 | #define LOCK_UNLOCK_2(a, b) \ | ||
| 5 | do { \ | ||
| 6 | pthread_mutex_lock(&(a)); \ | ||
| 7 | pthread_mutex_lock(&(b)); \ | ||
| 8 | pthread_mutex_unlock(&(b)); \ | ||
| 9 | pthread_mutex_unlock(&(a)); \ | ||
| 10 | } while(0) | ||
| 11 | |||
| 12 | #endif | ||
diff --git a/tools/lib/lockdep/tests/unlock_balance.c b/tools/lib/lockdep/tests/unlock_balance.c new file mode 100644 index 000000000000..0bc62de686f7 --- /dev/null +++ b/tools/lib/lockdep/tests/unlock_balance.c | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #include <liblockdep/mutex.h> | ||
| 2 | |||
| 3 | void main(void) | ||
| 4 | { | ||
| 5 | pthread_mutex_t a; | ||
| 6 | |||
| 7 | pthread_mutex_init(&a, NULL); | ||
| 8 | |||
| 9 | pthread_mutex_lock(&a); | ||
| 10 | pthread_mutex_unlock(&a); | ||
| 11 | pthread_mutex_unlock(&a); | ||
| 12 | } | ||
diff --git a/tools/lib/lockdep/uinclude/asm/hash.h b/tools/lib/lockdep/uinclude/asm/hash.h new file mode 100644 index 000000000000..d82b170bb216 --- /dev/null +++ b/tools/lib/lockdep/uinclude/asm/hash.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef __ASM_GENERIC_HASH_H | ||
| 2 | #define __ASM_GENERIC_HASH_H | ||
| 3 | |||
| 4 | /* Stub */ | ||
| 5 | |||
| 6 | #endif /* __ASM_GENERIC_HASH_H */ | ||
diff --git a/tools/lib/lockdep/uinclude/asm/hweight.h b/tools/lib/lockdep/uinclude/asm/hweight.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/asm/hweight.h | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | |||
| 2 | /* empty file */ | ||
| 3 | |||
diff --git a/tools/lib/lockdep/uinclude/asm/sections.h b/tools/lib/lockdep/uinclude/asm/sections.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/asm/sections.h | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | |||
| 2 | /* empty file */ | ||
| 3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/bitops.h b/tools/lib/lockdep/uinclude/linux/bitops.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/bitops.h | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | |||
| 2 | /* empty file */ | ||
| 3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/compiler.h b/tools/lib/lockdep/uinclude/linux/compiler.h new file mode 100644 index 000000000000..7ac838a1f196 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/compiler.h | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_LINUX_COMPILER_H_ | ||
| 2 | #define _LIBLOCKDEP_LINUX_COMPILER_H_ | ||
| 3 | |||
| 4 | #define __used __attribute__((__unused__)) | ||
| 5 | #define unlikely | ||
| 6 | |||
| 7 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/debug_locks.h b/tools/lib/lockdep/uinclude/linux/debug_locks.h new file mode 100644 index 000000000000..f38eb64df794 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/debug_locks.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_DEBUG_LOCKS_H_ | ||
| 2 | #define _LIBLOCKDEP_DEBUG_LOCKS_H_ | ||
| 3 | |||
| 4 | #include <stddef.h> | ||
| 5 | #include <linux/compiler.h> | ||
| 6 | |||
| 7 | #define DEBUG_LOCKS_WARN_ON(x) (x) | ||
| 8 | |||
| 9 | extern bool debug_locks; | ||
| 10 | extern bool debug_locks_silent; | ||
| 11 | |||
| 12 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/delay.h b/tools/lib/lockdep/uinclude/linux/delay.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/delay.h | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | |||
| 2 | /* empty file */ | ||
| 3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/export.h b/tools/lib/lockdep/uinclude/linux/export.h new file mode 100644 index 000000000000..6bdf3492c535 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/export.h | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_LINUX_EXPORT_H_ | ||
| 2 | #define _LIBLOCKDEP_LINUX_EXPORT_H_ | ||
| 3 | |||
| 4 | #define EXPORT_SYMBOL(sym) | ||
| 5 | #define EXPORT_SYMBOL_GPL(sym) | ||
| 6 | |||
| 7 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/ftrace.h b/tools/lib/lockdep/uinclude/linux/ftrace.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/ftrace.h | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | |||
| 2 | /* empty file */ | ||
| 3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/gfp.h b/tools/lib/lockdep/uinclude/linux/gfp.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/gfp.h | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | |||
| 2 | /* empty file */ | ||
| 3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/hardirq.h b/tools/lib/lockdep/uinclude/linux/hardirq.h new file mode 100644 index 000000000000..c8f3f8f58729 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/hardirq.h | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_LINUX_HARDIRQ_H_ | ||
| 2 | #define _LIBLOCKDEP_LINUX_HARDIRQ_H_ | ||
| 3 | |||
| 4 | #define SOFTIRQ_BITS 0UL | ||
| 5 | #define HARDIRQ_BITS 0UL | ||
| 6 | #define SOFTIRQ_SHIFT 0UL | ||
| 7 | #define HARDIRQ_SHIFT 0UL | ||
| 8 | #define hardirq_count() 0UL | ||
| 9 | #define softirq_count() 0UL | ||
| 10 | |||
| 11 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/hash.h b/tools/lib/lockdep/uinclude/linux/hash.h new file mode 100644 index 000000000000..0f8479858dc0 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/hash.h | |||
| @@ -0,0 +1 @@ | |||
| #include "../../../include/linux/hash.h" | |||
diff --git a/tools/lib/lockdep/uinclude/linux/interrupt.h b/tools/lib/lockdep/uinclude/linux/interrupt.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/interrupt.h | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | |||
| 2 | /* empty file */ | ||
| 3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/irqflags.h b/tools/lib/lockdep/uinclude/linux/irqflags.h new file mode 100644 index 000000000000..6cc296f0fad0 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/irqflags.h | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_LINUX_TRACE_IRQFLAGS_H_ | ||
| 2 | #define _LIBLOCKDEP_LINUX_TRACE_IRQFLAGS_H_ | ||
| 3 | |||
| 4 | # define trace_hardirq_context(p) 0 | ||
| 5 | # define trace_softirq_context(p) 0 | ||
| 6 | # define trace_hardirqs_enabled(p) 0 | ||
| 7 | # define trace_softirqs_enabled(p) 0 | ||
| 8 | # define trace_hardirq_enter() do { } while (0) | ||
| 9 | # define trace_hardirq_exit() do { } while (0) | ||
| 10 | # define lockdep_softirq_enter() do { } while (0) | ||
| 11 | # define lockdep_softirq_exit() do { } while (0) | ||
| 12 | # define INIT_TRACE_IRQFLAGS | ||
| 13 | |||
| 14 | # define stop_critical_timings() do { } while (0) | ||
| 15 | # define start_critical_timings() do { } while (0) | ||
| 16 | |||
| 17 | #define raw_local_irq_disable() do { } while (0) | ||
| 18 | #define raw_local_irq_enable() do { } while (0) | ||
| 19 | #define raw_local_irq_save(flags) ((flags) = 0) | ||
| 20 | #define raw_local_irq_restore(flags) do { } while (0) | ||
| 21 | #define raw_local_save_flags(flags) ((flags) = 0) | ||
| 22 | #define raw_irqs_disabled_flags(flags) do { } while (0) | ||
| 23 | #define raw_irqs_disabled() 0 | ||
| 24 | #define raw_safe_halt() | ||
| 25 | |||
| 26 | #define local_irq_enable() do { } while (0) | ||
| 27 | #define local_irq_disable() do { } while (0) | ||
| 28 | #define local_irq_save(flags) ((flags) = 0) | ||
| 29 | #define local_irq_restore(flags) do { } while (0) | ||
| 30 | #define local_save_flags(flags) ((flags) = 0) | ||
| 31 | #define irqs_disabled() (1) | ||
| 32 | #define irqs_disabled_flags(flags) (0) | ||
| 33 | #define safe_halt() do { } while (0) | ||
| 34 | |||
| 35 | #define trace_lock_release(x, y) | ||
| 36 | #define trace_lock_acquire(a, b, c, d, e, f, g) | ||
| 37 | |||
| 38 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/kallsyms.h b/tools/lib/lockdep/uinclude/linux/kallsyms.h new file mode 100644 index 000000000000..b0f2dbdf1a15 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/kallsyms.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_LINUX_KALLSYMS_H_ | ||
| 2 | #define _LIBLOCKDEP_LINUX_KALLSYMS_H_ | ||
| 3 | |||
| 4 | #include <linux/kernel.h> | ||
| 5 | #include <stdio.h> | ||
| 6 | |||
| 7 | #define KSYM_NAME_LEN 128 | ||
| 8 | |||
| 9 | struct module; | ||
| 10 | |||
| 11 | static inline const char *kallsyms_lookup(unsigned long addr, | ||
| 12 | unsigned long *symbolsize, | ||
| 13 | unsigned long *offset, | ||
| 14 | char **modname, char *namebuf) | ||
| 15 | { | ||
| 16 | return NULL; | ||
| 17 | } | ||
| 18 | |||
| 19 | #include <execinfo.h> | ||
| 20 | #include <stdlib.h> | ||
| 21 | static inline void print_ip_sym(unsigned long ip) | ||
| 22 | { | ||
| 23 | char **name; | ||
| 24 | |||
| 25 | name = backtrace_symbols((void **)&ip, 1); | ||
| 26 | |||
| 27 | printf("%s\n", *name); | ||
| 28 | |||
| 29 | free(name); | ||
| 30 | } | ||
| 31 | |||
| 32 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/kern_levels.h b/tools/lib/lockdep/uinclude/linux/kern_levels.h new file mode 100644 index 000000000000..3b9bade28698 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/kern_levels.h | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | #ifndef __KERN_LEVELS_H__ | ||
| 2 | #define __KERN_LEVELS_H__ | ||
| 3 | |||
| 4 | #define KERN_SOH "" /* ASCII Start Of Header */ | ||
| 5 | #define KERN_SOH_ASCII '' | ||
| 6 | |||
| 7 | #define KERN_EMERG KERN_SOH "" /* system is unusable */ | ||
| 8 | #define KERN_ALERT KERN_SOH "" /* action must be taken immediately */ | ||
| 9 | #define KERN_CRIT KERN_SOH "" /* critical conditions */ | ||
| 10 | #define KERN_ERR KERN_SOH "" /* error conditions */ | ||
| 11 | #define KERN_WARNING KERN_SOH "" /* warning conditions */ | ||
| 12 | #define KERN_NOTICE KERN_SOH "" /* normal but significant condition */ | ||
| 13 | #define KERN_INFO KERN_SOH "" /* informational */ | ||
| 14 | #define KERN_DEBUG KERN_SOH "" /* debug-level messages */ | ||
| 15 | |||
| 16 | #define KERN_DEFAULT KERN_SOH "" /* the default kernel loglevel */ | ||
| 17 | |||
| 18 | /* | ||
| 19 | * Annotation for a "continued" line of log printout (only done after a | ||
| 20 | * line that had no enclosing \n). Only to be used by core/arch code | ||
| 21 | * during early bootup (a continued line is not SMP-safe otherwise). | ||
| 22 | */ | ||
| 23 | #define KERN_CONT "" | ||
| 24 | |||
| 25 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/kernel.h b/tools/lib/lockdep/uinclude/linux/kernel.h new file mode 100644 index 000000000000..a11e3c357be7 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/kernel.h | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_LINUX_KERNEL_H_ | ||
| 2 | #define _LIBLOCKDEP_LINUX_KERNEL_H_ | ||
| 3 | |||
| 4 | #include <linux/export.h> | ||
| 5 | #include <linux/types.h> | ||
| 6 | #include <linux/rcu.h> | ||
| 7 | #include <linux/hardirq.h> | ||
| 8 | #include <linux/kern_levels.h> | ||
| 9 | |||
| 10 | #ifndef container_of | ||
| 11 | #define container_of(ptr, type, member) ({ \ | ||
| 12 | const typeof(((type *)0)->member) * __mptr = (ptr); \ | ||
| 13 | (type *)((char *)__mptr - offsetof(type, member)); }) | ||
| 14 | #endif | ||
| 15 | |||
| 16 | #define max(x, y) ({ \ | ||
| 17 | typeof(x) _max1 = (x); \ | ||
| 18 | typeof(y) _max2 = (y); \ | ||
| 19 | (void) (&_max1 == &_max2); \ | ||
| 20 | _max1 > _max2 ? _max1 : _max2; }) | ||
| 21 | |||
| 22 | #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) | ||
| 23 | #define WARN_ON(x) (x) | ||
| 24 | #define WARN_ON_ONCE(x) (x) | ||
| 25 | #define likely(x) (x) | ||
| 26 | #define WARN(x, y, z) (x) | ||
| 27 | #define uninitialized_var(x) x | ||
| 28 | #define __init | ||
| 29 | #define noinline | ||
| 30 | #define list_add_tail_rcu list_add_tail | ||
| 31 | |||
| 32 | #ifndef CALLER_ADDR0 | ||
| 33 | #define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0)) | ||
| 34 | #endif | ||
| 35 | |||
| 36 | #ifndef _RET_IP_ | ||
| 37 | #define _RET_IP_ CALLER_ADDR0 | ||
| 38 | #endif | ||
| 39 | |||
| 40 | #ifndef _THIS_IP_ | ||
| 41 | #define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; }) | ||
| 42 | #endif | ||
| 43 | |||
| 44 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/kmemcheck.h b/tools/lib/lockdep/uinclude/linux/kmemcheck.h new file mode 100644 index 000000000000..94d598bc6abe --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/kmemcheck.h | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_LINUX_KMEMCHECK_H_ | ||
| 2 | #define _LIBLOCKDEP_LINUX_KMEMCHECK_H_ | ||
| 3 | |||
| 4 | static inline void kmemcheck_mark_initialized(void *address, unsigned int n) | ||
| 5 | { | ||
| 6 | } | ||
| 7 | |||
| 8 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/linkage.h b/tools/lib/lockdep/uinclude/linux/linkage.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/linkage.h | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | |||
| 2 | /* empty file */ | ||
| 3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/list.h b/tools/lib/lockdep/uinclude/linux/list.h new file mode 100644 index 000000000000..6e9ef31ed82e --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/list.h | |||
| @@ -0,0 +1 @@ | |||
| #include "../../../include/linux/list.h" | |||
diff --git a/tools/lib/lockdep/uinclude/linux/lockdep.h b/tools/lib/lockdep/uinclude/linux/lockdep.h new file mode 100644 index 000000000000..d0f5d6e50214 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/lockdep.h | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_LOCKDEP_H_ | ||
| 2 | #define _LIBLOCKDEP_LOCKDEP_H_ | ||
| 3 | |||
| 4 | #include <sys/prctl.h> | ||
| 5 | #include <sys/syscall.h> | ||
| 6 | #include <string.h> | ||
| 7 | #include <limits.h> | ||
| 8 | #include <linux/utsname.h> | ||
| 9 | |||
| 10 | |||
| 11 | #define MAX_LOCK_DEPTH 2000UL | ||
| 12 | |||
| 13 | #include "../../../include/linux/lockdep.h" | ||
| 14 | |||
| 15 | struct task_struct { | ||
| 16 | u64 curr_chain_key; | ||
| 17 | int lockdep_depth; | ||
| 18 | unsigned int lockdep_recursion; | ||
| 19 | struct held_lock held_locks[MAX_LOCK_DEPTH]; | ||
| 20 | gfp_t lockdep_reclaim_gfp; | ||
| 21 | int pid; | ||
| 22 | char comm[17]; | ||
| 23 | }; | ||
| 24 | |||
| 25 | extern struct task_struct *__curr(void); | ||
| 26 | |||
| 27 | #define current (__curr()) | ||
| 28 | |||
| 29 | #define debug_locks_off() 1 | ||
| 30 | #define task_pid_nr(tsk) ((tsk)->pid) | ||
| 31 | |||
| 32 | #define KSYM_NAME_LEN 128 | ||
| 33 | #define printk printf | ||
| 34 | |||
| 35 | #define list_del_rcu list_del | ||
| 36 | |||
| 37 | #define atomic_t unsigned long | ||
| 38 | #define atomic_inc(x) ((*(x))++) | ||
| 39 | |||
| 40 | static struct new_utsname *init_utsname(void) | ||
| 41 | { | ||
| 42 | static struct new_utsname n = (struct new_utsname) { | ||
| 43 | .release = "liblockdep", | ||
| 44 | .version = LIBLOCKDEP_VERSION, | ||
| 45 | }; | ||
| 46 | |||
| 47 | return &n; | ||
| 48 | } | ||
| 49 | |||
| 50 | #define print_tainted() "" | ||
| 51 | #define static_obj(x) 1 | ||
| 52 | |||
| 53 | #define debug_show_all_locks() | ||
| 54 | |||
| 55 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/module.h b/tools/lib/lockdep/uinclude/linux/module.h new file mode 100644 index 000000000000..09c7a7be8ccc --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/module.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_LINUX_MODULE_H_ | ||
| 2 | #define _LIBLOCKDEP_LINUX_MODULE_H_ | ||
| 3 | |||
| 4 | #define module_param(name, type, perm) | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/mutex.h b/tools/lib/lockdep/uinclude/linux/mutex.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/mutex.h | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | |||
| 2 | /* empty file */ | ||
| 3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/poison.h b/tools/lib/lockdep/uinclude/linux/poison.h new file mode 100644 index 000000000000..0c27bdf14233 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/poison.h | |||
| @@ -0,0 +1 @@ | |||
| #include "../../../include/linux/poison.h" | |||
diff --git a/tools/lib/lockdep/uinclude/linux/prefetch.h b/tools/lib/lockdep/uinclude/linux/prefetch.h new file mode 100644 index 000000000000..d73fe6f850ac --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/prefetch.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_LINUX_PREFETCH_H_ | ||
| 2 | #define _LIBLOCKDEP_LINUX_PREFETCH_H | ||
| 3 | |||
| 4 | static inline void prefetch(void *a __attribute__((unused))) { } | ||
| 5 | |||
| 6 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/proc_fs.h b/tools/lib/lockdep/uinclude/linux/proc_fs.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/proc_fs.h | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | |||
| 2 | /* empty file */ | ||
| 3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/rbtree.h b/tools/lib/lockdep/uinclude/linux/rbtree.h new file mode 100644 index 000000000000..965901db4862 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/rbtree.h | |||
| @@ -0,0 +1 @@ | |||
| #include "../../../include/linux/rbtree.h" | |||
diff --git a/tools/lib/lockdep/uinclude/linux/rbtree_augmented.h b/tools/lib/lockdep/uinclude/linux/rbtree_augmented.h new file mode 100644 index 000000000000..c3759477379c --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/rbtree_augmented.h | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | #define __always_inline | ||
| 2 | #include "../../../include/linux/rbtree_augmented.h" | ||
diff --git a/tools/lib/lockdep/uinclude/linux/rcu.h b/tools/lib/lockdep/uinclude/linux/rcu.h new file mode 100644 index 000000000000..042ee8e463c9 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/rcu.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_RCU_H_ | ||
| 2 | #define _LIBLOCKDEP_RCU_H_ | ||
| 3 | |||
| 4 | int rcu_scheduler_active; | ||
| 5 | |||
| 6 | static inline int rcu_lockdep_current_cpu_online(void) | ||
| 7 | { | ||
| 8 | return 1; | ||
| 9 | } | ||
| 10 | |||
| 11 | static inline int rcu_is_cpu_idle(void) | ||
| 12 | { | ||
| 13 | return 1; | ||
| 14 | } | ||
| 15 | |||
| 16 | static inline bool rcu_is_watching(void) | ||
| 17 | { | ||
| 18 | return false; | ||
| 19 | } | ||
| 20 | |||
| 21 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/seq_file.h b/tools/lib/lockdep/uinclude/linux/seq_file.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/seq_file.h | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | |||
| 2 | /* empty file */ | ||
| 3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/spinlock.h b/tools/lib/lockdep/uinclude/linux/spinlock.h new file mode 100644 index 000000000000..68c1aa2bcba5 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/spinlock.h | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_SPINLOCK_H_ | ||
| 2 | #define _LIBLOCKDEP_SPINLOCK_H_ | ||
| 3 | |||
| 4 | #include <pthread.h> | ||
| 5 | #include <stdbool.h> | ||
| 6 | |||
| 7 | #define arch_spinlock_t pthread_mutex_t | ||
| 8 | #define __ARCH_SPIN_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER | ||
| 9 | |||
| 10 | static inline void arch_spin_lock(arch_spinlock_t *mutex) | ||
| 11 | { | ||
| 12 | pthread_mutex_lock(mutex); | ||
| 13 | } | ||
| 14 | |||
| 15 | static inline void arch_spin_unlock(arch_spinlock_t *mutex) | ||
| 16 | { | ||
| 17 | pthread_mutex_unlock(mutex); | ||
| 18 | } | ||
| 19 | |||
| 20 | static inline bool arch_spin_is_locked(arch_spinlock_t *mutex) | ||
| 21 | { | ||
| 22 | return true; | ||
| 23 | } | ||
| 24 | |||
| 25 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/stacktrace.h b/tools/lib/lockdep/uinclude/linux/stacktrace.h new file mode 100644 index 000000000000..39aecc6b19d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/stacktrace.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_LINUX_STACKTRACE_H_ | ||
| 2 | #define _LIBLOCKDEP_LINUX_STACKTRACE_H_ | ||
| 3 | |||
| 4 | #include <execinfo.h> | ||
| 5 | |||
| 6 | struct stack_trace { | ||
| 7 | unsigned int nr_entries, max_entries; | ||
| 8 | unsigned long *entries; | ||
| 9 | int skip; | ||
| 10 | }; | ||
| 11 | |||
| 12 | static inline void print_stack_trace(struct stack_trace *trace, int spaces) | ||
| 13 | { | ||
| 14 | backtrace_symbols_fd((void **)trace->entries, trace->nr_entries, 1); | ||
| 15 | } | ||
| 16 | |||
| 17 | #define save_stack_trace(trace) \ | ||
| 18 | ((trace)->nr_entries = \ | ||
| 19 | backtrace((void **)(trace)->entries, (trace)->max_entries)) | ||
| 20 | |||
| 21 | static inline int dump_stack(void) | ||
| 22 | { | ||
| 23 | void *array[64]; | ||
| 24 | size_t size; | ||
| 25 | |||
| 26 | size = backtrace(array, 64); | ||
| 27 | backtrace_symbols_fd(array, size, 1); | ||
| 28 | |||
| 29 | return 0; | ||
| 30 | } | ||
| 31 | |||
| 32 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/stringify.h b/tools/lib/lockdep/uinclude/linux/stringify.h new file mode 100644 index 000000000000..05dfcd1ac118 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/stringify.h | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_LINUX_STRINGIFY_H_ | ||
| 2 | #define _LIBLOCKDEP_LINUX_STRINGIFY_H_ | ||
| 3 | |||
| 4 | #define __stringify_1(x...) #x | ||
| 5 | #define __stringify(x...) __stringify_1(x) | ||
| 6 | |||
| 7 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/types.h b/tools/lib/lockdep/uinclude/linux/types.h new file mode 100644 index 000000000000..929938f426de --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/types.h | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | #ifndef _LIBLOCKDEP_LINUX_TYPES_H_ | ||
| 2 | #define _LIBLOCKDEP_LINUX_TYPES_H_ | ||
| 3 | |||
| 4 | #include <stdbool.h> | ||
| 5 | #include <stddef.h> | ||
| 6 | |||
| 7 | #define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */ | ||
| 8 | #include <asm/types.h> | ||
| 9 | |||
| 10 | struct page; | ||
| 11 | struct kmem_cache; | ||
| 12 | |||
| 13 | typedef unsigned gfp_t; | ||
| 14 | |||
| 15 | typedef __u64 u64; | ||
| 16 | typedef __s64 s64; | ||
| 17 | |||
| 18 | typedef __u32 u32; | ||
| 19 | typedef __s32 s32; | ||
| 20 | |||
| 21 | typedef __u16 u16; | ||
| 22 | typedef __s16 s16; | ||
| 23 | |||
| 24 | typedef __u8 u8; | ||
| 25 | typedef __s8 s8; | ||
| 26 | |||
| 27 | #ifdef __CHECKER__ | ||
| 28 | #define __bitwise__ __attribute__((bitwise)) | ||
| 29 | #else | ||
| 30 | #define __bitwise__ | ||
| 31 | #endif | ||
| 32 | #ifdef __CHECK_ENDIAN__ | ||
| 33 | #define __bitwise __bitwise__ | ||
| 34 | #else | ||
| 35 | #define __bitwise | ||
| 36 | #endif | ||
| 37 | |||
| 38 | |||
| 39 | typedef __u16 __bitwise __le16; | ||
| 40 | typedef __u16 __bitwise __be16; | ||
| 41 | typedef __u32 __bitwise __le32; | ||
| 42 | typedef __u32 __bitwise __be32; | ||
| 43 | typedef __u64 __bitwise __le64; | ||
| 44 | typedef __u64 __bitwise __be64; | ||
| 45 | |||
| 46 | struct list_head { | ||
| 47 | struct list_head *next, *prev; | ||
| 48 | }; | ||
| 49 | |||
| 50 | struct hlist_head { | ||
| 51 | struct hlist_node *first; | ||
| 52 | }; | ||
| 53 | |||
| 54 | struct hlist_node { | ||
| 55 | struct hlist_node *next, **pprev; | ||
| 56 | }; | ||
| 57 | |||
| 58 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/trace/events/lock.h b/tools/lib/lockdep/uinclude/trace/events/lock.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/trace/events/lock.h | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | |||
| 2 | /* empty file */ | ||
| 3 | |||
diff --git a/tools/lib/symbol/kallsyms.c b/tools/lib/symbol/kallsyms.c new file mode 100644 index 000000000000..18bc271a4bbc --- /dev/null +++ b/tools/lib/symbol/kallsyms.c | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | #include "symbol/kallsyms.h" | ||
| 2 | #include <stdio.h> | ||
| 3 | #include <stdlib.h> | ||
| 4 | |||
| 5 | int kallsyms__parse(const char *filename, void *arg, | ||
| 6 | int (*process_symbol)(void *arg, const char *name, | ||
| 7 | char type, u64 start)) | ||
| 8 | { | ||
| 9 | char *line = NULL; | ||
| 10 | size_t n; | ||
| 11 | int err = -1; | ||
| 12 | FILE *file = fopen(filename, "r"); | ||
| 13 | |||
| 14 | if (file == NULL) | ||
| 15 | goto out_failure; | ||
| 16 | |||
| 17 | err = 0; | ||
| 18 | |||
| 19 | while (!feof(file)) { | ||
| 20 | u64 start; | ||
| 21 | int line_len, len; | ||
| 22 | char symbol_type; | ||
| 23 | char *symbol_name; | ||
| 24 | |||
| 25 | line_len = getline(&line, &n, file); | ||
| 26 | if (line_len < 0 || !line) | ||
| 27 | break; | ||
| 28 | |||
| 29 | line[--line_len] = '\0'; /* \n */ | ||
| 30 | |||
| 31 | len = hex2u64(line, &start); | ||
| 32 | |||
| 33 | len++; | ||
| 34 | if (len + 2 >= line_len) | ||
| 35 | continue; | ||
| 36 | |||
| 37 | symbol_type = line[len]; | ||
| 38 | len += 2; | ||
| 39 | symbol_name = line + len; | ||
| 40 | len = line_len - len; | ||
| 41 | |||
| 42 | if (len >= KSYM_NAME_LEN) { | ||
| 43 | err = -1; | ||
| 44 | break; | ||
| 45 | } | ||
| 46 | |||
| 47 | err = process_symbol(arg, symbol_name, symbol_type, start); | ||
| 48 | if (err) | ||
| 49 | break; | ||
| 50 | } | ||
| 51 | |||
| 52 | free(line); | ||
| 53 | fclose(file); | ||
| 54 | return err; | ||
| 55 | |||
| 56 | out_failure: | ||
| 57 | return -1; | ||
| 58 | } | ||
diff --git a/tools/lib/symbol/kallsyms.h b/tools/lib/symbol/kallsyms.h new file mode 100644 index 000000000000..6084f5e18b3c --- /dev/null +++ b/tools/lib/symbol/kallsyms.h | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | #ifndef __TOOLS_KALLSYMS_H_ | ||
| 2 | #define __TOOLS_KALLSYMS_H_ 1 | ||
| 3 | |||
| 4 | #include <elf.h> | ||
| 5 | #include <linux/ctype.h> | ||
| 6 | #include <linux/types.h> | ||
| 7 | |||
| 8 | #ifndef KSYM_NAME_LEN | ||
| 9 | #define KSYM_NAME_LEN 256 | ||
| 10 | #endif | ||
| 11 | |||
| 12 | static inline u8 kallsyms2elf_type(char type) | ||
| 13 | { | ||
| 14 | if (type == 'W') | ||
| 15 | return STB_WEAK; | ||
| 16 | |||
| 17 | return isupper(type) ? STB_GLOBAL : STB_LOCAL; | ||
| 18 | } | ||
| 19 | |||
| 20 | int kallsyms__parse(const char *filename, void *arg, | ||
| 21 | int (*process_symbol)(void *arg, const char *name, | ||
| 22 | char type, u64 start)); | ||
| 23 | |||
| 24 | #endif /* __TOOLS_KALLSYMS_H_ */ | ||
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index fc1502098595..005c9cc06935 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile | |||
| @@ -43,6 +43,32 @@ man_dir_SQ = '$(subst ','\'',$(man_dir))' | |||
| 43 | export man_dir man_dir_SQ INSTALL | 43 | export man_dir man_dir_SQ INSTALL |
| 44 | export DESTDIR DESTDIR_SQ | 44 | export DESTDIR DESTDIR_SQ |
| 45 | 45 | ||
| 46 | set_plugin_dir := 1 | ||
| 47 | |||
| 48 | # Set plugin_dir to preffered global plugin location | ||
| 49 | # If we install under $HOME directory we go under | ||
| 50 | # $(HOME)/.traceevent/plugins | ||
| 51 | # | ||
| 52 | # We dont set PLUGIN_DIR in case we install under $HOME | ||
| 53 | # directory, because by default the code looks under: | ||
| 54 | # $(HOME)/.traceevent/plugins by default. | ||
| 55 | # | ||
| 56 | ifeq ($(plugin_dir),) | ||
| 57 | ifeq ($(prefix),$(HOME)) | ||
| 58 | override plugin_dir = $(HOME)/.traceevent/plugins | ||
| 59 | set_plugin_dir := 0 | ||
| 60 | else | ||
| 61 | override plugin_dir = $(prefix)/lib/traceevent/plugins | ||
| 62 | endif | ||
| 63 | endif | ||
| 64 | |||
| 65 | ifeq ($(set_plugin_dir),1) | ||
| 66 | PLUGIN_DIR = -DPLUGIN_DIR="$(plugin_dir)" | ||
| 67 | PLUGIN_DIR_SQ = '$(subst ','\'',$(PLUGIN_DIR))' | ||
| 68 | endif | ||
| 69 | |||
| 70 | include $(if $(BUILD_SRC),$(BUILD_SRC)/)../../scripts/Makefile.include | ||
| 71 | |||
| 46 | # copy a bit from Linux kbuild | 72 | # copy a bit from Linux kbuild |
| 47 | 73 | ||
| 48 | ifeq ("$(origin V)", "command line") | 74 | ifeq ("$(origin V)", "command line") |
| @@ -57,18 +83,13 @@ ifeq ("$(origin O)", "command line") | |||
| 57 | endif | 83 | endif |
| 58 | 84 | ||
| 59 | ifeq ($(BUILD_SRC),) | 85 | ifeq ($(BUILD_SRC),) |
| 60 | ifneq ($(BUILD_OUTPUT),) | 86 | ifneq ($(OUTPUT),) |
| 61 | 87 | ||
| 62 | define build_output | 88 | define build_output |
| 63 | $(if $(VERBOSE:1=),@)+$(MAKE) -C $(BUILD_OUTPUT) \ | 89 | $(if $(VERBOSE:1=),@)+$(MAKE) -C $(OUTPUT) \ |
| 64 | BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1 | 90 | BUILD_SRC=$(CURDIR)/ -f $(CURDIR)/Makefile $1 |
| 65 | endef | 91 | endef |
| 66 | 92 | ||
| 67 | saved-output := $(BUILD_OUTPUT) | ||
| 68 | BUILD_OUTPUT := $(shell cd $(BUILD_OUTPUT) && /bin/pwd) | ||
| 69 | $(if $(BUILD_OUTPUT),, \ | ||
| 70 | $(error output directory "$(saved-output)" does not exist)) | ||
| 71 | |||
| 72 | all: sub-make | 93 | all: sub-make |
| 73 | 94 | ||
| 74 | $(MAKECMDGOALS): sub-make | 95 | $(MAKECMDGOALS): sub-make |
| @@ -80,7 +101,7 @@ sub-make: force | |||
| 80 | # Leave processing to above invocation of make | 101 | # Leave processing to above invocation of make |
| 81 | skip-makefile := 1 | 102 | skip-makefile := 1 |
| 82 | 103 | ||
| 83 | endif # BUILD_OUTPUT | 104 | endif # OUTPUT |
| 84 | endif # BUILD_SRC | 105 | endif # BUILD_SRC |
| 85 | 106 | ||
| 86 | # We process the rest of the Makefile if this is the final invocation of make | 107 | # We process the rest of the Makefile if this is the final invocation of make |
| @@ -96,6 +117,7 @@ export prefix bindir src obj | |||
| 96 | # Shell quotes | 117 | # Shell quotes |
| 97 | bindir_SQ = $(subst ','\'',$(bindir)) | 118 | bindir_SQ = $(subst ','\'',$(bindir)) |
| 98 | bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) | 119 | bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) |
| 120 | plugin_dir_SQ = $(subst ','\'',$(plugin_dir)) | ||
| 99 | 121 | ||
| 100 | LIB_FILE = libtraceevent.a libtraceevent.so | 122 | LIB_FILE = libtraceevent.a libtraceevent.so |
| 101 | 123 | ||
| @@ -114,7 +136,7 @@ export Q VERBOSE | |||
| 114 | 136 | ||
| 115 | EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION) | 137 | EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION) |
| 116 | 138 | ||
| 117 | INCLUDES = -I. $(CONFIG_INCLUDES) | 139 | INCLUDES = -I. -I $(srctree)/../../include $(CONFIG_INCLUDES) |
| 118 | 140 | ||
| 119 | # Set compile option CFLAGS if not set elsewhere | 141 | # Set compile option CFLAGS if not set elsewhere |
| 120 | CFLAGS ?= -g -Wall | 142 | CFLAGS ?= -g -Wall |
| @@ -125,41 +147,14 @@ override CFLAGS += $(udis86-flags) -D_GNU_SOURCE | |||
| 125 | 147 | ||
| 126 | ifeq ($(VERBOSE),1) | 148 | ifeq ($(VERBOSE),1) |
| 127 | Q = | 149 | Q = |
| 128 | print_compile = | ||
| 129 | print_app_build = | ||
| 130 | print_fpic_compile = | ||
| 131 | print_shared_lib_compile = | ||
| 132 | print_plugin_obj_compile = | ||
| 133 | print_plugin_build = | ||
| 134 | print_install = | ||
| 135 | else | 150 | else |
| 136 | Q = @ | 151 | Q = @ |
| 137 | print_compile = echo ' CC '$(OBJ); | ||
| 138 | print_app_build = echo ' BUILD '$(OBJ); | ||
| 139 | print_fpic_compile = echo ' CC FPIC '$(OBJ); | ||
| 140 | print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ); | ||
| 141 | print_plugin_obj_compile = echo ' BUILD PLUGIN OBJ '$(OBJ); | ||
| 142 | print_plugin_build = echo ' BUILD PLUGIN '$(OBJ); | ||
| 143 | print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ); | ||
| 144 | print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2'; | ||
| 145 | endif | 152 | endif |
| 146 | 153 | ||
| 147 | do_fpic_compile = \ | ||
| 148 | ($(print_fpic_compile) \ | ||
| 149 | $(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@) | ||
| 150 | |||
| 151 | do_app_build = \ | ||
| 152 | ($(print_app_build) \ | ||
| 153 | $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS)) | ||
| 154 | |||
| 155 | do_compile_shared_library = \ | 154 | do_compile_shared_library = \ |
| 156 | ($(print_shared_lib_compile) \ | 155 | ($(print_shared_lib_compile) \ |
| 157 | $(CC) --shared $^ -o $@) | 156 | $(CC) --shared $^ -o $@) |
| 158 | 157 | ||
| 159 | do_compile_plugin_obj = \ | ||
| 160 | ($(print_plugin_obj_compile) \ | ||
| 161 | $(CC) -c $(CFLAGS) -fPIC -o $@ $<) | ||
| 162 | |||
| 163 | do_plugin_build = \ | 158 | do_plugin_build = \ |
| 164 | ($(print_plugin_build) \ | 159 | ($(print_plugin_build) \ |
| 165 | $(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<) | 160 | $(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<) |
| @@ -169,23 +164,37 @@ do_build_static_lib = \ | |||
| 169 | $(RM) $@; $(AR) rcs $@ $^) | 164 | $(RM) $@; $(AR) rcs $@ $^) |
| 170 | 165 | ||
| 171 | 166 | ||
| 172 | define do_compile | 167 | do_compile = $(QUIET_CC)$(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@; |
| 173 | $(print_compile) \ | ||
| 174 | $(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@; | ||
| 175 | endef | ||
| 176 | 168 | ||
| 177 | $(obj)/%.o: $(src)/%.c | 169 | $(obj)/%.o: $(src)/%.c |
| 178 | $(Q)$(call do_compile) | 170 | $(call do_compile) |
| 179 | 171 | ||
| 180 | %.o: $(src)/%.c | 172 | %.o: $(src)/%.c |
| 181 | $(Q)$(call do_compile) | 173 | $(call do_compile) |
| 182 | 174 | ||
| 183 | PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o | 175 | PEVENT_LIB_OBJS = event-parse.o |
| 176 | PEVENT_LIB_OBJS += event-plugin.o | ||
| 177 | PEVENT_LIB_OBJS += trace-seq.o | ||
| 178 | PEVENT_LIB_OBJS += parse-filter.o | ||
| 179 | PEVENT_LIB_OBJS += parse-utils.o | ||
| 184 | PEVENT_LIB_OBJS += kbuffer-parse.o | 180 | PEVENT_LIB_OBJS += kbuffer-parse.o |
| 185 | 181 | ||
| 186 | ALL_OBJS = $(PEVENT_LIB_OBJS) | 182 | PLUGIN_OBJS = plugin_jbd2.o |
| 183 | PLUGIN_OBJS += plugin_hrtimer.o | ||
| 184 | PLUGIN_OBJS += plugin_kmem.o | ||
| 185 | PLUGIN_OBJS += plugin_kvm.o | ||
| 186 | PLUGIN_OBJS += plugin_mac80211.o | ||
| 187 | PLUGIN_OBJS += plugin_sched_switch.o | ||
| 188 | PLUGIN_OBJS += plugin_function.o | ||
| 189 | PLUGIN_OBJS += plugin_xen.o | ||
| 190 | PLUGIN_OBJS += plugin_scsi.o | ||
| 191 | PLUGIN_OBJS += plugin_cfg80211.o | ||
| 192 | |||
| 193 | PLUGINS := $(PLUGIN_OBJS:.o=.so) | ||
| 194 | |||
| 195 | ALL_OBJS = $(PEVENT_LIB_OBJS) $(PLUGIN_OBJS) | ||
| 187 | 196 | ||
| 188 | CMD_TARGETS = $(LIB_FILE) | 197 | CMD_TARGETS = $(LIB_FILE) $(PLUGINS) |
| 189 | 198 | ||
| 190 | TARGETS = $(CMD_TARGETS) | 199 | TARGETS = $(CMD_TARGETS) |
| 191 | 200 | ||
| @@ -195,32 +204,40 @@ all: all_cmd | |||
| 195 | all_cmd: $(CMD_TARGETS) | 204 | all_cmd: $(CMD_TARGETS) |
| 196 | 205 | ||
| 197 | libtraceevent.so: $(PEVENT_LIB_OBJS) | 206 | libtraceevent.so: $(PEVENT_LIB_OBJS) |
| 198 | $(Q)$(do_compile_shared_library) | 207 | $(QUIET_LINK)$(CC) --shared $^ -o $@ |
| 199 | 208 | ||
| 200 | libtraceevent.a: $(PEVENT_LIB_OBJS) | 209 | libtraceevent.a: $(PEVENT_LIB_OBJS) |
| 201 | $(Q)$(do_build_static_lib) | 210 | $(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^ |
| 211 | |||
| 212 | plugins: $(PLUGINS) | ||
| 202 | 213 | ||
| 203 | $(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS | 214 | $(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS |
| 204 | $(Q)$(do_fpic_compile) | 215 | $(QUIET_CC_FPIC)$(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@ |
| 216 | |||
| 217 | $(PLUGIN_OBJS): %.o : $(src)/%.c | ||
| 218 | $(QUIET_CC_FPIC)$(CC) -c $(CFLAGS) -fPIC -o $@ $< | ||
| 219 | |||
| 220 | $(PLUGINS): %.so: %.o | ||
| 221 | $(QUIET_LINK)$(CC) $(CFLAGS) -shared -nostartfiles -o $@ $< | ||
| 205 | 222 | ||
| 206 | define make_version.h | 223 | define make_version.h |
| 207 | (echo '/* This file is automatically generated. Do not modify. */'; \ | 224 | (echo '/* This file is automatically generated. Do not modify. */'; \ |
| 208 | echo \#define VERSION_CODE $(shell \ | 225 | echo \#define VERSION_CODE $(shell \ |
| 209 | expr $(VERSION) \* 256 + $(PATCHLEVEL)); \ | 226 | expr $(VERSION) \* 256 + $(PATCHLEVEL)); \ |
| 210 | echo '#define EXTRAVERSION ' $(EXTRAVERSION); \ | 227 | echo '#define EXTRAVERSION ' $(EXTRAVERSION); \ |
| 211 | echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"'; \ | 228 | echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"'; \ |
| 212 | echo '#define FILE_VERSION '$(FILE_VERSION); \ | 229 | echo '#define FILE_VERSION '$(FILE_VERSION); \ |
| 213 | ) > $1 | 230 | ) > $1 |
| 214 | endef | 231 | endef |
| 215 | 232 | ||
| 216 | define update_version.h | 233 | define update_version.h |
| 217 | ($(call make_version.h, $@.tmp); \ | 234 | ($(call make_version.h, $@.tmp); \ |
| 218 | if [ -r $@ ] && cmp -s $@ $@.tmp; then \ | 235 | if [ -r $@ ] && cmp -s $@ $@.tmp; then \ |
| 219 | rm -f $@.tmp; \ | 236 | rm -f $@.tmp; \ |
| 220 | else \ | 237 | else \ |
| 221 | echo ' UPDATE $@'; \ | 238 | echo ' UPDATE $@'; \ |
| 222 | mv -f $@.tmp $@; \ | 239 | mv -f $@.tmp $@; \ |
| 223 | fi); | 240 | fi); |
| 224 | endef | 241 | endef |
| 225 | 242 | ||
| 226 | ep_version.h: force | 243 | ep_version.h: force |
| @@ -229,13 +246,13 @@ ep_version.h: force | |||
| 229 | VERSION_FILES = ep_version.h | 246 | VERSION_FILES = ep_version.h |
| 230 | 247 | ||
| 231 | define update_dir | 248 | define update_dir |
| 232 | (echo $1 > $@.tmp; \ | 249 | (echo $1 > $@.tmp; \ |
| 233 | if [ -r $@ ] && cmp -s $@ $@.tmp; then \ | 250 | if [ -r $@ ] && cmp -s $@ $@.tmp; then \ |
| 234 | rm -f $@.tmp; \ | 251 | rm -f $@.tmp; \ |
| 235 | else \ | 252 | else \ |
| 236 | echo ' UPDATE $@'; \ | 253 | echo ' UPDATE $@'; \ |
| 237 | mv -f $@.tmp $@; \ | 254 | mv -f $@.tmp $@; \ |
| 238 | fi); | 255 | fi); |
| 239 | endef | 256 | endef |
| 240 | 257 | ||
| 241 | ## make deps | 258 | ## make deps |
| @@ -245,10 +262,10 @@ all_deps := $(all_objs:%.o=.%.d) | |||
| 245 | 262 | ||
| 246 | # let .d file also depends on the source and header files | 263 | # let .d file also depends on the source and header files |
| 247 | define check_deps | 264 | define check_deps |
| 248 | @set -e; $(RM) $@; \ | 265 | @set -e; $(RM) $@; \ |
| 249 | $(CC) -MM $(CFLAGS) $< > $@.$$$$; \ | 266 | $(CC) -MM $(CFLAGS) $< > $@.$$$$; \ |
| 250 | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ | 267 | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ |
| 251 | $(RM) $@.$$$$ | 268 | $(RM) $@.$$$$ |
| 252 | endef | 269 | endef |
| 253 | 270 | ||
| 254 | $(all_deps): .%.d: $(src)/%.c | 271 | $(all_deps): .%.d: $(src)/%.c |
| @@ -283,27 +300,41 @@ TAGS: force | |||
| 283 | --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' | 300 | --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' |
| 284 | 301 | ||
| 285 | define do_install | 302 | define do_install |
| 286 | $(print_install) \ | ||
| 287 | if [ ! -d '$(DESTDIR_SQ)$2' ]; then \ | 303 | if [ ! -d '$(DESTDIR_SQ)$2' ]; then \ |
| 288 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \ | 304 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \ |
| 289 | fi; \ | 305 | fi; \ |
| 290 | $(INSTALL) $1 '$(DESTDIR_SQ)$2' | 306 | $(INSTALL) $1 '$(DESTDIR_SQ)$2' |
| 291 | endef | 307 | endef |
| 292 | 308 | ||
| 293 | install_lib: all_cmd | 309 | define do_install_plugins |
| 294 | $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ)) | 310 | for plugin in $1; do \ |
| 311 | $(call do_install,$$plugin,$(plugin_dir_SQ)); \ | ||
| 312 | done | ||
| 313 | endef | ||
| 314 | |||
| 315 | install_lib: all_cmd install_plugins | ||
| 316 | $(call QUIET_INSTALL, $(LIB_FILE)) \ | ||
| 317 | $(call do_install,$(LIB_FILE),$(bindir_SQ)) | ||
| 318 | |||
| 319 | install_plugins: $(PLUGINS) | ||
| 320 | $(call QUIET_INSTALL, trace_plugins) \ | ||
| 321 | $(call do_install_plugins, $(PLUGINS)) | ||
| 295 | 322 | ||
| 296 | install: install_lib | 323 | install: install_lib |
| 297 | 324 | ||
| 298 | clean: | 325 | clean: |
| 299 | $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d | 326 | $(call QUIET_CLEAN, libtraceevent) \ |
| 300 | $(RM) TRACEEVENT-CFLAGS tags TAGS | 327 | $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d \ |
| 328 | $(RM) TRACEEVENT-CFLAGS tags TAGS | ||
| 301 | 329 | ||
| 302 | endif # skip-makefile | 330 | endif # skip-makefile |
| 303 | 331 | ||
| 304 | PHONY += force | 332 | PHONY += force plugins |
| 305 | force: | 333 | force: |
| 306 | 334 | ||
| 335 | plugins: | ||
| 336 | @echo > /dev/null | ||
| 337 | |||
| 307 | # Declare the contents of the .PHONY variable as phony. We keep that | 338 | # Declare the contents of the .PHONY variable as phony. We keep that |
| 308 | # information in a variable so we can use it in if_changed and friends. | 339 | # information in a variable so we can use it in if_changed and friends. |
| 309 | .PHONY: $(PHONY) | 340 | .PHONY: $(PHONY) |
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 217c82ee3665..1587ea392ad6 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
| @@ -2710,7 +2710,6 @@ process_func_handler(struct event_format *event, struct pevent_function_handler | |||
| 2710 | struct print_arg *farg; | 2710 | struct print_arg *farg; |
| 2711 | enum event_type type; | 2711 | enum event_type type; |
| 2712 | char *token; | 2712 | char *token; |
| 2713 | const char *test; | ||
| 2714 | int i; | 2713 | int i; |
| 2715 | 2714 | ||
| 2716 | arg->type = PRINT_FUNC; | 2715 | arg->type = PRINT_FUNC; |
| @@ -2727,15 +2726,19 @@ process_func_handler(struct event_format *event, struct pevent_function_handler | |||
| 2727 | } | 2726 | } |
| 2728 | 2727 | ||
| 2729 | type = process_arg(event, farg, &token); | 2728 | type = process_arg(event, farg, &token); |
| 2730 | if (i < (func->nr_args - 1)) | 2729 | if (i < (func->nr_args - 1)) { |
| 2731 | test = ","; | 2730 | if (type != EVENT_DELIM || strcmp(token, ",") != 0) { |
| 2732 | else | 2731 | warning("Error: function '%s()' expects %d arguments but event %s only uses %d", |
| 2733 | test = ")"; | 2732 | func->name, func->nr_args, |
| 2734 | 2733 | event->name, i + 1); | |
| 2735 | if (test_type_token(type, token, EVENT_DELIM, test)) { | 2734 | goto err; |
| 2736 | free_arg(farg); | 2735 | } |
| 2737 | free_token(token); | 2736 | } else { |
| 2738 | return EVENT_ERROR; | 2737 | if (type != EVENT_DELIM || strcmp(token, ")") != 0) { |
| 2738 | warning("Error: function '%s()' only expects %d arguments but event %s has more", | ||
| 2739 | func->name, func->nr_args, event->name); | ||
| 2740 | goto err; | ||
| 2741 | } | ||
| 2739 | } | 2742 | } |
| 2740 | 2743 | ||
| 2741 | *next_arg = farg; | 2744 | *next_arg = farg; |
| @@ -2747,6 +2750,11 @@ process_func_handler(struct event_format *event, struct pevent_function_handler | |||
| 2747 | *tok = token; | 2750 | *tok = token; |
| 2748 | 2751 | ||
| 2749 | return type; | 2752 | return type; |
| 2753 | |||
| 2754 | err: | ||
| 2755 | free_arg(farg); | ||
| 2756 | free_token(token); | ||
| 2757 | return EVENT_ERROR; | ||
| 2750 | } | 2758 | } |
| 2751 | 2759 | ||
| 2752 | static enum event_type | 2760 | static enum event_type |
| @@ -4099,6 +4107,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event | |||
| 4099 | unsigned long long val; | 4107 | unsigned long long val; |
| 4100 | struct func_map *func; | 4108 | struct func_map *func; |
| 4101 | const char *saveptr; | 4109 | const char *saveptr; |
| 4110 | struct trace_seq p; | ||
| 4102 | char *bprint_fmt = NULL; | 4111 | char *bprint_fmt = NULL; |
| 4103 | char format[32]; | 4112 | char format[32]; |
| 4104 | int show_func; | 4113 | int show_func; |
| @@ -4306,8 +4315,12 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event | |||
| 4306 | format[len] = 0; | 4315 | format[len] = 0; |
| 4307 | if (!len_as_arg) | 4316 | if (!len_as_arg) |
| 4308 | len_arg = -1; | 4317 | len_arg = -1; |
| 4309 | print_str_arg(s, data, size, event, | 4318 | /* Use helper trace_seq */ |
| 4319 | trace_seq_init(&p); | ||
| 4320 | print_str_arg(&p, data, size, event, | ||
| 4310 | format, len_arg, arg); | 4321 | format, len_arg, arg); |
| 4322 | trace_seq_terminate(&p); | ||
| 4323 | trace_seq_puts(s, p.buffer); | ||
| 4311 | arg = arg->next; | 4324 | arg = arg->next; |
| 4312 | break; | 4325 | break; |
| 4313 | default: | 4326 | default: |
| @@ -5116,8 +5129,38 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, | |||
| 5116 | return ret; | 5129 | return ret; |
| 5117 | } | 5130 | } |
| 5118 | 5131 | ||
| 5132 | static enum pevent_errno | ||
| 5133 | __pevent_parse_event(struct pevent *pevent, | ||
| 5134 | struct event_format **eventp, | ||
| 5135 | const char *buf, unsigned long size, | ||
| 5136 | const char *sys) | ||
| 5137 | { | ||
| 5138 | int ret = __pevent_parse_format(eventp, pevent, buf, size, sys); | ||
| 5139 | struct event_format *event = *eventp; | ||
| 5140 | |||
| 5141 | if (event == NULL) | ||
| 5142 | return ret; | ||
| 5143 | |||
| 5144 | if (pevent && add_event(pevent, event)) { | ||
| 5145 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 5146 | goto event_add_failed; | ||
| 5147 | } | ||
| 5148 | |||
| 5149 | #define PRINT_ARGS 0 | ||
| 5150 | if (PRINT_ARGS && event->print_fmt.args) | ||
| 5151 | print_args(event->print_fmt.args); | ||
| 5152 | |||
| 5153 | return 0; | ||
| 5154 | |||
| 5155 | event_add_failed: | ||
| 5156 | pevent_free_format(event); | ||
| 5157 | return ret; | ||
| 5158 | } | ||
| 5159 | |||
| 5119 | /** | 5160 | /** |
| 5120 | * pevent_parse_format - parse the event format | 5161 | * pevent_parse_format - parse the event format |
| 5162 | * @pevent: the handle to the pevent | ||
| 5163 | * @eventp: returned format | ||
| 5121 | * @buf: the buffer storing the event format string | 5164 | * @buf: the buffer storing the event format string |
| 5122 | * @size: the size of @buf | 5165 | * @size: the size of @buf |
| 5123 | * @sys: the system the event belongs to | 5166 | * @sys: the system the event belongs to |
| @@ -5129,10 +5172,12 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, | |||
| 5129 | * | 5172 | * |
| 5130 | * /sys/kernel/debug/tracing/events/.../.../format | 5173 | * /sys/kernel/debug/tracing/events/.../.../format |
| 5131 | */ | 5174 | */ |
| 5132 | enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf, | 5175 | enum pevent_errno pevent_parse_format(struct pevent *pevent, |
| 5176 | struct event_format **eventp, | ||
| 5177 | const char *buf, | ||
| 5133 | unsigned long size, const char *sys) | 5178 | unsigned long size, const char *sys) |
| 5134 | { | 5179 | { |
| 5135 | return __pevent_parse_format(eventp, NULL, buf, size, sys); | 5180 | return __pevent_parse_event(pevent, eventp, buf, size, sys); |
| 5136 | } | 5181 | } |
| 5137 | 5182 | ||
| 5138 | /** | 5183 | /** |
| @@ -5153,25 +5198,7 @@ enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, | |||
| 5153 | unsigned long size, const char *sys) | 5198 | unsigned long size, const char *sys) |
| 5154 | { | 5199 | { |
| 5155 | struct event_format *event = NULL; | 5200 | struct event_format *event = NULL; |
| 5156 | int ret = __pevent_parse_format(&event, pevent, buf, size, sys); | 5201 | return __pevent_parse_event(pevent, &event, buf, size, sys); |
| 5157 | |||
| 5158 | if (event == NULL) | ||
| 5159 | return ret; | ||
| 5160 | |||
| 5161 | if (add_event(pevent, event)) { | ||
| 5162 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 5163 | goto event_add_failed; | ||
| 5164 | } | ||
| 5165 | |||
| 5166 | #define PRINT_ARGS 0 | ||
| 5167 | if (PRINT_ARGS && event->print_fmt.args) | ||
| 5168 | print_args(event->print_fmt.args); | ||
| 5169 | |||
| 5170 | return 0; | ||
| 5171 | |||
| 5172 | event_add_failed: | ||
| 5173 | pevent_free_format(event); | ||
| 5174 | return ret; | ||
| 5175 | } | 5202 | } |
| 5176 | 5203 | ||
| 5177 | #undef _PE | 5204 | #undef _PE |
| @@ -5203,22 +5230,7 @@ int pevent_strerror(struct pevent *pevent __maybe_unused, | |||
| 5203 | 5230 | ||
| 5204 | idx = errnum - __PEVENT_ERRNO__START - 1; | 5231 | idx = errnum - __PEVENT_ERRNO__START - 1; |
| 5205 | msg = pevent_error_str[idx]; | 5232 | msg = pevent_error_str[idx]; |
| 5206 | 5233 | snprintf(buf, buflen, "%s", msg); | |
| 5207 | switch (errnum) { | ||
| 5208 | case PEVENT_ERRNO__MEM_ALLOC_FAILED: | ||
| 5209 | case PEVENT_ERRNO__PARSE_EVENT_FAILED: | ||
| 5210 | case PEVENT_ERRNO__READ_ID_FAILED: | ||
| 5211 | case PEVENT_ERRNO__READ_FORMAT_FAILED: | ||
| 5212 | case PEVENT_ERRNO__READ_PRINT_FAILED: | ||
| 5213 | case PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED: | ||
| 5214 | case PEVENT_ERRNO__INVALID_ARG_TYPE: | ||
| 5215 | snprintf(buf, buflen, "%s", msg); | ||
| 5216 | break; | ||
| 5217 | |||
| 5218 | default: | ||
| 5219 | /* cannot reach here */ | ||
| 5220 | break; | ||
| 5221 | } | ||
| 5222 | 5234 | ||
| 5223 | return 0; | 5235 | return 0; |
| 5224 | } | 5236 | } |
| @@ -5549,6 +5561,52 @@ int pevent_register_print_function(struct pevent *pevent, | |||
| 5549 | } | 5561 | } |
| 5550 | 5562 | ||
| 5551 | /** | 5563 | /** |
| 5564 | * pevent_unregister_print_function - unregister a helper function | ||
| 5565 | * @pevent: the handle to the pevent | ||
| 5566 | * @func: the function to process the helper function | ||
| 5567 | * @name: the name of the helper function | ||
| 5568 | * | ||
| 5569 | * This function removes existing print handler for function @name. | ||
| 5570 | * | ||
| 5571 | * Returns 0 if the handler was removed successully, -1 otherwise. | ||
| 5572 | */ | ||
| 5573 | int pevent_unregister_print_function(struct pevent *pevent, | ||
| 5574 | pevent_func_handler func, char *name) | ||
| 5575 | { | ||
| 5576 | struct pevent_function_handler *func_handle; | ||
| 5577 | |||
| 5578 | func_handle = find_func_handler(pevent, name); | ||
| 5579 | if (func_handle && func_handle->func == func) { | ||
| 5580 | remove_func_handler(pevent, name); | ||
| 5581 | return 0; | ||
| 5582 | } | ||
| 5583 | return -1; | ||
| 5584 | } | ||
| 5585 | |||
| 5586 | static struct event_format *pevent_search_event(struct pevent *pevent, int id, | ||
| 5587 | const char *sys_name, | ||
| 5588 | const char *event_name) | ||
| 5589 | { | ||
| 5590 | struct event_format *event; | ||
| 5591 | |||
| 5592 | if (id >= 0) { | ||
| 5593 | /* search by id */ | ||
| 5594 | event = pevent_find_event(pevent, id); | ||
| 5595 | if (!event) | ||
| 5596 | return NULL; | ||
| 5597 | if (event_name && (strcmp(event_name, event->name) != 0)) | ||
| 5598 | return NULL; | ||
| 5599 | if (sys_name && (strcmp(sys_name, event->system) != 0)) | ||
| 5600 | return NULL; | ||
| 5601 | } else { | ||
| 5602 | event = pevent_find_event_by_name(pevent, sys_name, event_name); | ||
| 5603 | if (!event) | ||
| 5604 | return NULL; | ||
| 5605 | } | ||
| 5606 | return event; | ||
| 5607 | } | ||
| 5608 | |||
| 5609 | /** | ||
| 5552 | * pevent_register_event_handler - register a way to parse an event | 5610 | * pevent_register_event_handler - register a way to parse an event |
| 5553 | * @pevent: the handle to the pevent | 5611 | * @pevent: the handle to the pevent |
| 5554 | * @id: the id of the event to register | 5612 | * @id: the id of the event to register |
| @@ -5572,20 +5630,9 @@ int pevent_register_event_handler(struct pevent *pevent, int id, | |||
| 5572 | struct event_format *event; | 5630 | struct event_format *event; |
| 5573 | struct event_handler *handle; | 5631 | struct event_handler *handle; |
| 5574 | 5632 | ||
| 5575 | if (id >= 0) { | 5633 | event = pevent_search_event(pevent, id, sys_name, event_name); |
| 5576 | /* search by id */ | 5634 | if (event == NULL) |
| 5577 | event = pevent_find_event(pevent, id); | 5635 | goto not_found; |
| 5578 | if (!event) | ||
| 5579 | goto not_found; | ||
| 5580 | if (event_name && (strcmp(event_name, event->name) != 0)) | ||
| 5581 | goto not_found; | ||
| 5582 | if (sys_name && (strcmp(sys_name, event->system) != 0)) | ||
| 5583 | goto not_found; | ||
| 5584 | } else { | ||
| 5585 | event = pevent_find_event_by_name(pevent, sys_name, event_name); | ||
| 5586 | if (!event) | ||
| 5587 | goto not_found; | ||
| 5588 | } | ||
| 5589 | 5636 | ||
| 5590 | pr_stat("overriding event (%d) %s:%s with new print handler", | 5637 | pr_stat("overriding event (%d) %s:%s with new print handler", |
| 5591 | event->id, event->system, event->name); | 5638 | event->id, event->system, event->name); |
| @@ -5625,6 +5672,79 @@ int pevent_register_event_handler(struct pevent *pevent, int id, | |||
| 5625 | return -1; | 5672 | return -1; |
| 5626 | } | 5673 | } |
| 5627 | 5674 | ||
| 5675 | static int handle_matches(struct event_handler *handler, int id, | ||
| 5676 | const char *sys_name, const char *event_name, | ||
| 5677 | pevent_event_handler_func func, void *context) | ||
| 5678 | { | ||
| 5679 | if (id >= 0 && id != handler->id) | ||
| 5680 | return 0; | ||
| 5681 | |||
| 5682 | if (event_name && (strcmp(event_name, handler->event_name) != 0)) | ||
| 5683 | return 0; | ||
| 5684 | |||
| 5685 | if (sys_name && (strcmp(sys_name, handler->sys_name) != 0)) | ||
| 5686 | return 0; | ||
| 5687 | |||
| 5688 | if (func != handler->func || context != handler->context) | ||
| 5689 | return 0; | ||
| 5690 | |||
| 5691 | return 1; | ||
| 5692 | } | ||
| 5693 | |||
| 5694 | /** | ||
| 5695 | * pevent_unregister_event_handler - unregister an existing event handler | ||
| 5696 | * @pevent: the handle to the pevent | ||
| 5697 | * @id: the id of the event to unregister | ||
| 5698 | * @sys_name: the system name the handler belongs to | ||
| 5699 | * @event_name: the name of the event handler | ||
| 5700 | * @func: the function to call to parse the event information | ||
| 5701 | * @context: the data to be passed to @func | ||
| 5702 | * | ||
| 5703 | * This function removes existing event handler (parser). | ||
| 5704 | * | ||
| 5705 | * If @id is >= 0, then it is used to find the event. | ||
| 5706 | * else @sys_name and @event_name are used. | ||
| 5707 | * | ||
| 5708 | * Returns 0 if handler was removed successfully, -1 if event was not found. | ||
| 5709 | */ | ||
| 5710 | int pevent_unregister_event_handler(struct pevent *pevent, int id, | ||
| 5711 | const char *sys_name, const char *event_name, | ||
| 5712 | pevent_event_handler_func func, void *context) | ||
| 5713 | { | ||
| 5714 | struct event_format *event; | ||
| 5715 | struct event_handler *handle; | ||
| 5716 | struct event_handler **next; | ||
| 5717 | |||
| 5718 | event = pevent_search_event(pevent, id, sys_name, event_name); | ||
| 5719 | if (event == NULL) | ||
| 5720 | goto not_found; | ||
| 5721 | |||
| 5722 | if (event->handler == func && event->context == context) { | ||
| 5723 | pr_stat("removing override handler for event (%d) %s:%s. Going back to default handler.", | ||
| 5724 | event->id, event->system, event->name); | ||
| 5725 | |||
| 5726 | event->handler = NULL; | ||
| 5727 | event->context = NULL; | ||
| 5728 | return 0; | ||
| 5729 | } | ||
| 5730 | |||
| 5731 | not_found: | ||
| 5732 | for (next = &pevent->handlers; *next; next = &(*next)->next) { | ||
| 5733 | handle = *next; | ||
| 5734 | if (handle_matches(handle, id, sys_name, event_name, | ||
| 5735 | func, context)) | ||
| 5736 | break; | ||
| 5737 | } | ||
| 5738 | |||
| 5739 | if (!(*next)) | ||
| 5740 | return -1; | ||
| 5741 | |||
| 5742 | *next = handle->next; | ||
| 5743 | free_handler(handle); | ||
| 5744 | |||
| 5745 | return 0; | ||
| 5746 | } | ||
| 5747 | |||
| 5628 | /** | 5748 | /** |
| 5629 | * pevent_alloc - create a pevent handle | 5749 | * pevent_alloc - create a pevent handle |
| 5630 | */ | 5750 | */ |
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 8d73d2594f65..791c539374c7 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <stdbool.h> | 23 | #include <stdbool.h> |
| 24 | #include <stdarg.h> | 24 | #include <stdarg.h> |
| 25 | #include <regex.h> | 25 | #include <regex.h> |
| 26 | #include <string.h> | ||
| 26 | 27 | ||
| 27 | #ifndef __maybe_unused | 28 | #ifndef __maybe_unused |
| 28 | #define __maybe_unused __attribute__((unused)) | 29 | #define __maybe_unused __attribute__((unused)) |
| @@ -57,6 +58,12 @@ struct pevent_record { | |||
| 57 | #endif | 58 | #endif |
| 58 | }; | 59 | }; |
| 59 | 60 | ||
| 61 | enum trace_seq_fail { | ||
| 62 | TRACE_SEQ__GOOD, | ||
| 63 | TRACE_SEQ__BUFFER_POISONED, | ||
| 64 | TRACE_SEQ__MEM_ALLOC_FAILED, | ||
| 65 | }; | ||
| 66 | |||
| 60 | /* | 67 | /* |
| 61 | * Trace sequences are used to allow a function to call several other functions | 68 | * Trace sequences are used to allow a function to call several other functions |
| 62 | * to create a string of data to use (up to a max of PAGE_SIZE). | 69 | * to create a string of data to use (up to a max of PAGE_SIZE). |
| @@ -67,6 +74,7 @@ struct trace_seq { | |||
| 67 | unsigned int buffer_size; | 74 | unsigned int buffer_size; |
| 68 | unsigned int len; | 75 | unsigned int len; |
| 69 | unsigned int readpos; | 76 | unsigned int readpos; |
| 77 | enum trace_seq_fail state; | ||
| 70 | }; | 78 | }; |
| 71 | 79 | ||
| 72 | void trace_seq_init(struct trace_seq *s); | 80 | void trace_seq_init(struct trace_seq *s); |
| @@ -97,7 +105,7 @@ typedef int (*pevent_event_handler_func)(struct trace_seq *s, | |||
| 97 | void *context); | 105 | void *context); |
| 98 | 106 | ||
| 99 | typedef int (*pevent_plugin_load_func)(struct pevent *pevent); | 107 | typedef int (*pevent_plugin_load_func)(struct pevent *pevent); |
| 100 | typedef int (*pevent_plugin_unload_func)(void); | 108 | typedef int (*pevent_plugin_unload_func)(struct pevent *pevent); |
| 101 | 109 | ||
| 102 | struct plugin_option { | 110 | struct plugin_option { |
| 103 | struct plugin_option *next; | 111 | struct plugin_option *next; |
| @@ -122,7 +130,7 @@ struct plugin_option { | |||
| 122 | * PEVENT_PLUGIN_UNLOADER: (optional) | 130 | * PEVENT_PLUGIN_UNLOADER: (optional) |
| 123 | * The function called just before unloading | 131 | * The function called just before unloading |
| 124 | * | 132 | * |
| 125 | * int PEVENT_PLUGIN_UNLOADER(void) | 133 | * int PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) |
| 126 | * | 134 | * |
| 127 | * PEVENT_PLUGIN_OPTIONS: (optional) | 135 | * PEVENT_PLUGIN_OPTIONS: (optional) |
| 128 | * Plugin options that can be set before loading | 136 | * Plugin options that can be set before loading |
| @@ -355,12 +363,35 @@ enum pevent_flag { | |||
| 355 | _PE(READ_FORMAT_FAILED, "failed to read event format"), \ | 363 | _PE(READ_FORMAT_FAILED, "failed to read event format"), \ |
| 356 | _PE(READ_PRINT_FAILED, "failed to read event print fmt"), \ | 364 | _PE(READ_PRINT_FAILED, "failed to read event print fmt"), \ |
| 357 | _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\ | 365 | _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\ |
| 358 | _PE(INVALID_ARG_TYPE, "invalid argument type") | 366 | _PE(INVALID_ARG_TYPE, "invalid argument type"), \ |
| 367 | _PE(INVALID_EXP_TYPE, "invalid expression type"), \ | ||
| 368 | _PE(INVALID_OP_TYPE, "invalid operator type"), \ | ||
| 369 | _PE(INVALID_EVENT_NAME, "invalid event name"), \ | ||
| 370 | _PE(EVENT_NOT_FOUND, "no event found"), \ | ||
| 371 | _PE(SYNTAX_ERROR, "syntax error"), \ | ||
| 372 | _PE(ILLEGAL_RVALUE, "illegal rvalue"), \ | ||
| 373 | _PE(ILLEGAL_LVALUE, "illegal lvalue for string comparison"), \ | ||
| 374 | _PE(INVALID_REGEX, "regex did not compute"), \ | ||
| 375 | _PE(ILLEGAL_STRING_CMP, "illegal comparison for string"), \ | ||
| 376 | _PE(ILLEGAL_INTEGER_CMP,"illegal comparison for integer"), \ | ||
| 377 | _PE(REPARENT_NOT_OP, "cannot reparent other than OP"), \ | ||
| 378 | _PE(REPARENT_FAILED, "failed to reparent filter OP"), \ | ||
| 379 | _PE(BAD_FILTER_ARG, "bad arg in filter tree"), \ | ||
| 380 | _PE(UNEXPECTED_TYPE, "unexpected type (not a value)"), \ | ||
| 381 | _PE(ILLEGAL_TOKEN, "illegal token"), \ | ||
| 382 | _PE(INVALID_PAREN, "open parenthesis cannot come here"), \ | ||
| 383 | _PE(UNBALANCED_PAREN, "unbalanced number of parenthesis"), \ | ||
| 384 | _PE(UNKNOWN_TOKEN, "unknown token"), \ | ||
| 385 | _PE(FILTER_NOT_FOUND, "no filter found"), \ | ||
| 386 | _PE(NOT_A_NUMBER, "must have number field"), \ | ||
| 387 | _PE(NO_FILTER, "no filters exists"), \ | ||
| 388 | _PE(FILTER_MISS, "record does not match to filter") | ||
| 359 | 389 | ||
| 360 | #undef _PE | 390 | #undef _PE |
| 361 | #define _PE(__code, __str) PEVENT_ERRNO__ ## __code | 391 | #define _PE(__code, __str) PEVENT_ERRNO__ ## __code |
| 362 | enum pevent_errno { | 392 | enum pevent_errno { |
| 363 | PEVENT_ERRNO__SUCCESS = 0, | 393 | PEVENT_ERRNO__SUCCESS = 0, |
| 394 | PEVENT_ERRNO__FILTER_MATCH = PEVENT_ERRNO__SUCCESS, | ||
| 364 | 395 | ||
| 365 | /* | 396 | /* |
| 366 | * Choose an arbitrary negative big number not to clash with standard | 397 | * Choose an arbitrary negative big number not to clash with standard |
| @@ -377,6 +408,12 @@ enum pevent_errno { | |||
| 377 | }; | 408 | }; |
| 378 | #undef _PE | 409 | #undef _PE |
| 379 | 410 | ||
| 411 | struct plugin_list; | ||
| 412 | |||
| 413 | struct plugin_list *traceevent_load_plugins(struct pevent *pevent); | ||
| 414 | void traceevent_unload_plugins(struct plugin_list *plugin_list, | ||
| 415 | struct pevent *pevent); | ||
| 416 | |||
| 380 | struct cmdline; | 417 | struct cmdline; |
| 381 | struct cmdline_list; | 418 | struct cmdline_list; |
| 382 | struct func_map; | 419 | struct func_map; |
| @@ -522,6 +559,15 @@ __data2host8(struct pevent *pevent, unsigned long long data) | |||
| 522 | __data2host8(pevent, __val); \ | 559 | __data2host8(pevent, __val); \ |
| 523 | }) | 560 | }) |
| 524 | 561 | ||
| 562 | static inline int traceevent_host_bigendian(void) | ||
| 563 | { | ||
| 564 | unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 }; | ||
| 565 | unsigned int val; | ||
| 566 | |||
| 567 | memcpy(&val, str, 4); | ||
| 568 | return val == 0x01020304; | ||
| 569 | } | ||
| 570 | |||
| 525 | /* taken from kernel/trace/trace.h */ | 571 | /* taken from kernel/trace/trace.h */ |
| 526 | enum trace_flag_type { | 572 | enum trace_flag_type { |
| 527 | TRACE_FLAG_IRQS_OFF = 0x01, | 573 | TRACE_FLAG_IRQS_OFF = 0x01, |
| @@ -547,7 +593,9 @@ int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long siz | |||
| 547 | 593 | ||
| 548 | enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, | 594 | enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, |
| 549 | unsigned long size, const char *sys); | 595 | unsigned long size, const char *sys); |
| 550 | enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf, | 596 | enum pevent_errno pevent_parse_format(struct pevent *pevent, |
| 597 | struct event_format **eventp, | ||
| 598 | const char *buf, | ||
| 551 | unsigned long size, const char *sys); | 599 | unsigned long size, const char *sys); |
| 552 | void pevent_free_format(struct event_format *event); | 600 | void pevent_free_format(struct event_format *event); |
| 553 | 601 | ||
| @@ -576,10 +624,15 @@ int pevent_print_func_field(struct trace_seq *s, const char *fmt, | |||
| 576 | int pevent_register_event_handler(struct pevent *pevent, int id, | 624 | int pevent_register_event_handler(struct pevent *pevent, int id, |
| 577 | const char *sys_name, const char *event_name, | 625 | const char *sys_name, const char *event_name, |
| 578 | pevent_event_handler_func func, void *context); | 626 | pevent_event_handler_func func, void *context); |
| 627 | int pevent_unregister_event_handler(struct pevent *pevent, int id, | ||
| 628 | const char *sys_name, const char *event_name, | ||
| 629 | pevent_event_handler_func func, void *context); | ||
| 579 | int pevent_register_print_function(struct pevent *pevent, | 630 | int pevent_register_print_function(struct pevent *pevent, |
| 580 | pevent_func_handler func, | 631 | pevent_func_handler func, |
| 581 | enum pevent_func_arg_type ret_type, | 632 | enum pevent_func_arg_type ret_type, |
| 582 | char *name, ...); | 633 | char *name, ...); |
| 634 | int pevent_unregister_print_function(struct pevent *pevent, | ||
| 635 | pevent_func_handler func, char *name); | ||
| 583 | 636 | ||
| 584 | struct format_field *pevent_find_common_field(struct event_format *event, const char *name); | 637 | struct format_field *pevent_find_common_field(struct event_format *event, const char *name); |
| 585 | struct format_field *pevent_find_field(struct event_format *event, const char *name); | 638 | struct format_field *pevent_find_field(struct event_format *event, const char *name); |
| @@ -811,18 +864,22 @@ struct filter_type { | |||
| 811 | struct filter_arg *filter; | 864 | struct filter_arg *filter; |
| 812 | }; | 865 | }; |
| 813 | 866 | ||
| 867 | #define PEVENT_FILTER_ERROR_BUFSZ 1024 | ||
| 868 | |||
| 814 | struct event_filter { | 869 | struct event_filter { |
| 815 | struct pevent *pevent; | 870 | struct pevent *pevent; |
| 816 | int filters; | 871 | int filters; |
| 817 | struct filter_type *event_filters; | 872 | struct filter_type *event_filters; |
| 873 | char error_buffer[PEVENT_FILTER_ERROR_BUFSZ]; | ||
| 818 | }; | 874 | }; |
| 819 | 875 | ||
| 820 | struct event_filter *pevent_filter_alloc(struct pevent *pevent); | 876 | struct event_filter *pevent_filter_alloc(struct pevent *pevent); |
| 821 | 877 | ||
| 822 | #define FILTER_NONE -2 | 878 | /* for backward compatibility */ |
| 823 | #define FILTER_NOEXIST -1 | 879 | #define FILTER_NONE PEVENT_ERRNO__FILTER_NOT_FOUND |
| 824 | #define FILTER_MISS 0 | 880 | #define FILTER_NOEXIST PEVENT_ERRNO__NO_FILTER |
| 825 | #define FILTER_MATCH 1 | 881 | #define FILTER_MISS PEVENT_ERRNO__FILTER_MISS |
| 882 | #define FILTER_MATCH PEVENT_ERRNO__FILTER_MATCH | ||
| 826 | 883 | ||
| 827 | enum filter_trivial_type { | 884 | enum filter_trivial_type { |
| 828 | FILTER_TRIVIAL_FALSE, | 885 | FILTER_TRIVIAL_FALSE, |
| @@ -830,20 +887,21 @@ enum filter_trivial_type { | |||
| 830 | FILTER_TRIVIAL_BOTH, | 887 | FILTER_TRIVIAL_BOTH, |
| 831 | }; | 888 | }; |
| 832 | 889 | ||
| 833 | int pevent_filter_add_filter_str(struct event_filter *filter, | 890 | enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, |
| 834 | const char *filter_str, | 891 | const char *filter_str); |
| 835 | char **error_str); | ||
| 836 | 892 | ||
| 893 | enum pevent_errno pevent_filter_match(struct event_filter *filter, | ||
| 894 | struct pevent_record *record); | ||
| 837 | 895 | ||
| 838 | int pevent_filter_match(struct event_filter *filter, | 896 | int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err, |
| 839 | struct pevent_record *record); | 897 | char *buf, size_t buflen); |
| 840 | 898 | ||
| 841 | int pevent_event_filtered(struct event_filter *filter, | 899 | int pevent_event_filtered(struct event_filter *filter, |
| 842 | int event_id); | 900 | int event_id); |
| 843 | 901 | ||
| 844 | void pevent_filter_reset(struct event_filter *filter); | 902 | void pevent_filter_reset(struct event_filter *filter); |
| 845 | 903 | ||
| 846 | void pevent_filter_clear_trivial(struct event_filter *filter, | 904 | int pevent_filter_clear_trivial(struct event_filter *filter, |
| 847 | enum filter_trivial_type type); | 905 | enum filter_trivial_type type); |
| 848 | 906 | ||
| 849 | void pevent_filter_free(struct event_filter *filter); | 907 | void pevent_filter_free(struct event_filter *filter); |
diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c new file mode 100644 index 000000000000..0c8bf6780e4d --- /dev/null +++ b/tools/lib/traceevent/event-plugin.c | |||
| @@ -0,0 +1,215 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; | ||
| 8 | * version 2.1 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
| 17 | * | ||
| 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <string.h> | ||
| 22 | #include <dlfcn.h> | ||
| 23 | #include <stdlib.h> | ||
| 24 | #include <sys/types.h> | ||
| 25 | #include <sys/stat.h> | ||
| 26 | #include <unistd.h> | ||
| 27 | #include <dirent.h> | ||
| 28 | #include "event-parse.h" | ||
| 29 | #include "event-utils.h" | ||
| 30 | |||
| 31 | #define LOCAL_PLUGIN_DIR ".traceevent/plugins" | ||
| 32 | |||
| 33 | struct plugin_list { | ||
| 34 | struct plugin_list *next; | ||
| 35 | char *name; | ||
| 36 | void *handle; | ||
| 37 | }; | ||
| 38 | |||
| 39 | static void | ||
| 40 | load_plugin(struct pevent *pevent, const char *path, | ||
| 41 | const char *file, void *data) | ||
| 42 | { | ||
| 43 | struct plugin_list **plugin_list = data; | ||
| 44 | pevent_plugin_load_func func; | ||
| 45 | struct plugin_list *list; | ||
| 46 | const char *alias; | ||
| 47 | char *plugin; | ||
| 48 | void *handle; | ||
| 49 | |||
| 50 | plugin = malloc(strlen(path) + strlen(file) + 2); | ||
| 51 | if (!plugin) { | ||
| 52 | warning("could not allocate plugin memory\n"); | ||
| 53 | return; | ||
| 54 | } | ||
| 55 | |||
| 56 | strcpy(plugin, path); | ||
| 57 | strcat(plugin, "/"); | ||
| 58 | strcat(plugin, file); | ||
| 59 | |||
| 60 | handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL); | ||
| 61 | if (!handle) { | ||
| 62 | warning("could not load plugin '%s'\n%s\n", | ||
| 63 | plugin, dlerror()); | ||
| 64 | goto out_free; | ||
| 65 | } | ||
| 66 | |||
| 67 | alias = dlsym(handle, PEVENT_PLUGIN_ALIAS_NAME); | ||
| 68 | if (!alias) | ||
| 69 | alias = file; | ||
| 70 | |||
| 71 | func = dlsym(handle, PEVENT_PLUGIN_LOADER_NAME); | ||
| 72 | if (!func) { | ||
| 73 | warning("could not find func '%s' in plugin '%s'\n%s\n", | ||
| 74 | PEVENT_PLUGIN_LOADER_NAME, plugin, dlerror()); | ||
| 75 | goto out_free; | ||
| 76 | } | ||
| 77 | |||
| 78 | list = malloc(sizeof(*list)); | ||
| 79 | if (!list) { | ||
| 80 | warning("could not allocate plugin memory\n"); | ||
| 81 | goto out_free; | ||
| 82 | } | ||
| 83 | |||
| 84 | list->next = *plugin_list; | ||
| 85 | list->handle = handle; | ||
| 86 | list->name = plugin; | ||
| 87 | *plugin_list = list; | ||
| 88 | |||
| 89 | pr_stat("registering plugin: %s", plugin); | ||
| 90 | func(pevent); | ||
| 91 | return; | ||
| 92 | |||
| 93 | out_free: | ||
| 94 | free(plugin); | ||
| 95 | } | ||
| 96 | |||
| 97 | static void | ||
| 98 | load_plugins_dir(struct pevent *pevent, const char *suffix, | ||
| 99 | const char *path, | ||
| 100 | void (*load_plugin)(struct pevent *pevent, | ||
| 101 | const char *path, | ||
| 102 | const char *name, | ||
| 103 | void *data), | ||
| 104 | void *data) | ||
| 105 | { | ||
| 106 | struct dirent *dent; | ||
| 107 | struct stat st; | ||
| 108 | DIR *dir; | ||
| 109 | int ret; | ||
| 110 | |||
| 111 | ret = stat(path, &st); | ||
| 112 | if (ret < 0) | ||
| 113 | return; | ||
| 114 | |||
| 115 | if (!S_ISDIR(st.st_mode)) | ||
| 116 | return; | ||
| 117 | |||
| 118 | dir = opendir(path); | ||
| 119 | if (!dir) | ||
| 120 | return; | ||
| 121 | |||
| 122 | while ((dent = readdir(dir))) { | ||
| 123 | const char *name = dent->d_name; | ||
| 124 | |||
| 125 | if (strcmp(name, ".") == 0 || | ||
| 126 | strcmp(name, "..") == 0) | ||
| 127 | continue; | ||
| 128 | |||
| 129 | /* Only load plugins that end in suffix */ | ||
| 130 | if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0) | ||
| 131 | continue; | ||
| 132 | |||
| 133 | load_plugin(pevent, path, name, data); | ||
| 134 | } | ||
| 135 | |||
| 136 | closedir(dir); | ||
| 137 | } | ||
| 138 | |||
| 139 | static void | ||
| 140 | load_plugins(struct pevent *pevent, const char *suffix, | ||
| 141 | void (*load_plugin)(struct pevent *pevent, | ||
| 142 | const char *path, | ||
| 143 | const char *name, | ||
| 144 | void *data), | ||
| 145 | void *data) | ||
| 146 | { | ||
| 147 | char *home; | ||
| 148 | char *path; | ||
| 149 | char *envdir; | ||
| 150 | |||
| 151 | /* | ||
| 152 | * If a system plugin directory was defined, | ||
| 153 | * check that first. | ||
| 154 | */ | ||
| 155 | #ifdef PLUGIN_DIR | ||
| 156 | load_plugins_dir(pevent, suffix, PLUGIN_DIR, load_plugin, data); | ||
| 157 | #endif | ||
| 158 | |||
| 159 | /* | ||
| 160 | * Next let the environment-set plugin directory | ||
| 161 | * override the system defaults. | ||
| 162 | */ | ||
| 163 | envdir = getenv("TRACEEVENT_PLUGIN_DIR"); | ||
| 164 | if (envdir) | ||
| 165 | load_plugins_dir(pevent, suffix, envdir, load_plugin, data); | ||
| 166 | |||
| 167 | /* | ||
| 168 | * Now let the home directory override the environment | ||
| 169 | * or system defaults. | ||
| 170 | */ | ||
| 171 | home = getenv("HOME"); | ||
| 172 | if (!home) | ||
| 173 | return; | ||
| 174 | |||
| 175 | path = malloc(strlen(home) + strlen(LOCAL_PLUGIN_DIR) + 2); | ||
| 176 | if (!path) { | ||
| 177 | warning("could not allocate plugin memory\n"); | ||
| 178 | return; | ||
| 179 | } | ||
| 180 | |||
| 181 | strcpy(path, home); | ||
| 182 | strcat(path, "/"); | ||
| 183 | strcat(path, LOCAL_PLUGIN_DIR); | ||
| 184 | |||
| 185 | load_plugins_dir(pevent, suffix, path, load_plugin, data); | ||
| 186 | |||
| 187 | free(path); | ||
| 188 | } | ||
| 189 | |||
| 190 | struct plugin_list* | ||
| 191 | traceevent_load_plugins(struct pevent *pevent) | ||
| 192 | { | ||
| 193 | struct plugin_list *list = NULL; | ||
| 194 | |||
| 195 | load_plugins(pevent, ".so", load_plugin, &list); | ||
| 196 | return list; | ||
| 197 | } | ||
| 198 | |||
| 199 | void | ||
| 200 | traceevent_unload_plugins(struct plugin_list *plugin_list, struct pevent *pevent) | ||
| 201 | { | ||
| 202 | pevent_plugin_unload_func func; | ||
| 203 | struct plugin_list *list; | ||
| 204 | |||
| 205 | while (plugin_list) { | ||
| 206 | list = plugin_list; | ||
| 207 | plugin_list = list->next; | ||
| 208 | func = dlsym(list->handle, PEVENT_PLUGIN_UNLOADER_NAME); | ||
| 209 | if (func) | ||
| 210 | func(pevent); | ||
| 211 | dlclose(list->handle); | ||
| 212 | free(list->name); | ||
| 213 | free(list); | ||
| 214 | } | ||
| 215 | } | ||
diff --git a/tools/lib/traceevent/event-utils.h b/tools/lib/traceevent/event-utils.h index e76c9acb92cd..d1dc2170e402 100644 --- a/tools/lib/traceevent/event-utils.h +++ b/tools/lib/traceevent/event-utils.h | |||
| @@ -23,18 +23,14 @@ | |||
| 23 | #include <ctype.h> | 23 | #include <ctype.h> |
| 24 | 24 | ||
| 25 | /* Can be overridden */ | 25 | /* Can be overridden */ |
| 26 | void die(const char *fmt, ...); | ||
| 27 | void *malloc_or_die(unsigned int size); | ||
| 28 | void warning(const char *fmt, ...); | 26 | void warning(const char *fmt, ...); |
| 29 | void pr_stat(const char *fmt, ...); | 27 | void pr_stat(const char *fmt, ...); |
| 30 | void vpr_stat(const char *fmt, va_list ap); | 28 | void vpr_stat(const char *fmt, va_list ap); |
| 31 | 29 | ||
| 32 | /* Always available */ | 30 | /* Always available */ |
| 33 | void __die(const char *fmt, ...); | ||
| 34 | void __warning(const char *fmt, ...); | 31 | void __warning(const char *fmt, ...); |
| 35 | void __pr_stat(const char *fmt, ...); | 32 | void __pr_stat(const char *fmt, ...); |
| 36 | 33 | ||
| 37 | void __vdie(const char *fmt, ...); | ||
| 38 | void __vwarning(const char *fmt, ...); | 34 | void __vwarning(const char *fmt, ...); |
| 39 | void __vpr_stat(const char *fmt, ...); | 35 | void __vpr_stat(const char *fmt, ...); |
| 40 | 36 | ||
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index 2500e75583fc..b50234402fc2 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c | |||
| @@ -38,41 +38,31 @@ struct event_list { | |||
| 38 | struct event_format *event; | 38 | struct event_format *event; |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | #define MAX_ERR_STR_SIZE 256 | 41 | static void show_error(char *error_buf, const char *fmt, ...) |
| 42 | |||
| 43 | static void show_error(char **error_str, const char *fmt, ...) | ||
| 44 | { | 42 | { |
| 45 | unsigned long long index; | 43 | unsigned long long index; |
| 46 | const char *input; | 44 | const char *input; |
| 47 | char *error; | ||
| 48 | va_list ap; | 45 | va_list ap; |
| 49 | int len; | 46 | int len; |
| 50 | int i; | 47 | int i; |
| 51 | 48 | ||
| 52 | if (!error_str) | ||
| 53 | return; | ||
| 54 | |||
| 55 | input = pevent_get_input_buf(); | 49 | input = pevent_get_input_buf(); |
| 56 | index = pevent_get_input_buf_ptr(); | 50 | index = pevent_get_input_buf_ptr(); |
| 57 | len = input ? strlen(input) : 0; | 51 | len = input ? strlen(input) : 0; |
| 58 | 52 | ||
| 59 | error = malloc_or_die(MAX_ERR_STR_SIZE + (len*2) + 3); | ||
| 60 | |||
| 61 | if (len) { | 53 | if (len) { |
| 62 | strcpy(error, input); | 54 | strcpy(error_buf, input); |
| 63 | error[len] = '\n'; | 55 | error_buf[len] = '\n'; |
| 64 | for (i = 1; i < len && i < index; i++) | 56 | for (i = 1; i < len && i < index; i++) |
| 65 | error[len+i] = ' '; | 57 | error_buf[len+i] = ' '; |
| 66 | error[len + i] = '^'; | 58 | error_buf[len + i] = '^'; |
| 67 | error[len + i + 1] = '\n'; | 59 | error_buf[len + i + 1] = '\n'; |
| 68 | len += i+2; | 60 | len += i+2; |
| 69 | } | 61 | } |
| 70 | 62 | ||
| 71 | va_start(ap, fmt); | 63 | va_start(ap, fmt); |
| 72 | vsnprintf(error + len, MAX_ERR_STR_SIZE, fmt, ap); | 64 | vsnprintf(error_buf + len, PEVENT_FILTER_ERROR_BUFSZ - len, fmt, ap); |
| 73 | va_end(ap); | 65 | va_end(ap); |
| 74 | |||
| 75 | *error_str = error; | ||
| 76 | } | 66 | } |
| 77 | 67 | ||
| 78 | static void free_token(char *token) | 68 | static void free_token(char *token) |
| @@ -95,7 +85,11 @@ static enum event_type read_token(char **tok) | |||
| 95 | (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) && | 85 | (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) && |
| 96 | pevent_peek_char() == '~') { | 86 | pevent_peek_char() == '~') { |
| 97 | /* append it */ | 87 | /* append it */ |
| 98 | *tok = malloc_or_die(3); | 88 | *tok = malloc(3); |
| 89 | if (*tok == NULL) { | ||
| 90 | free_token(token); | ||
| 91 | return EVENT_ERROR; | ||
| 92 | } | ||
| 99 | sprintf(*tok, "%c%c", *token, '~'); | 93 | sprintf(*tok, "%c%c", *token, '~'); |
| 100 | free_token(token); | 94 | free_token(token); |
| 101 | /* Now remove the '~' from the buffer */ | 95 | /* Now remove the '~' from the buffer */ |
| @@ -147,11 +141,13 @@ add_filter_type(struct event_filter *filter, int id) | |||
| 147 | if (filter_type) | 141 | if (filter_type) |
| 148 | return filter_type; | 142 | return filter_type; |
| 149 | 143 | ||
| 150 | filter->event_filters = realloc(filter->event_filters, | 144 | filter_type = realloc(filter->event_filters, |
| 151 | sizeof(*filter->event_filters) * | 145 | sizeof(*filter->event_filters) * |
| 152 | (filter->filters + 1)); | 146 | (filter->filters + 1)); |
| 153 | if (!filter->event_filters) | 147 | if (!filter_type) |
| 154 | die("Could not allocate filter"); | 148 | return NULL; |
| 149 | |||
| 150 | filter->event_filters = filter_type; | ||
| 155 | 151 | ||
| 156 | for (i = 0; i < filter->filters; i++) { | 152 | for (i = 0; i < filter->filters; i++) { |
| 157 | if (filter->event_filters[i].event_id > id) | 153 | if (filter->event_filters[i].event_id > id) |
| @@ -182,7 +178,10 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent) | |||
| 182 | { | 178 | { |
| 183 | struct event_filter *filter; | 179 | struct event_filter *filter; |
| 184 | 180 | ||
| 185 | filter = malloc_or_die(sizeof(*filter)); | 181 | filter = malloc(sizeof(*filter)); |
| 182 | if (filter == NULL) | ||
| 183 | return NULL; | ||
| 184 | |||
| 186 | memset(filter, 0, sizeof(*filter)); | 185 | memset(filter, 0, sizeof(*filter)); |
| 187 | filter->pevent = pevent; | 186 | filter->pevent = pevent; |
| 188 | pevent_ref(pevent); | 187 | pevent_ref(pevent); |
| @@ -192,12 +191,7 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent) | |||
| 192 | 191 | ||
| 193 | static struct filter_arg *allocate_arg(void) | 192 | static struct filter_arg *allocate_arg(void) |
| 194 | { | 193 | { |
| 195 | struct filter_arg *arg; | 194 | return calloc(1, sizeof(struct filter_arg)); |
| 196 | |||
| 197 | arg = malloc_or_die(sizeof(*arg)); | ||
| 198 | memset(arg, 0, sizeof(*arg)); | ||
| 199 | |||
| 200 | return arg; | ||
| 201 | } | 195 | } |
| 202 | 196 | ||
| 203 | static void free_arg(struct filter_arg *arg) | 197 | static void free_arg(struct filter_arg *arg) |
| @@ -242,15 +236,19 @@ static void free_arg(struct filter_arg *arg) | |||
| 242 | free(arg); | 236 | free(arg); |
| 243 | } | 237 | } |
| 244 | 238 | ||
| 245 | static void add_event(struct event_list **events, | 239 | static int add_event(struct event_list **events, |
| 246 | struct event_format *event) | 240 | struct event_format *event) |
| 247 | { | 241 | { |
| 248 | struct event_list *list; | 242 | struct event_list *list; |
| 249 | 243 | ||
| 250 | list = malloc_or_die(sizeof(*list)); | 244 | list = malloc(sizeof(*list)); |
| 245 | if (list == NULL) | ||
| 246 | return -1; | ||
| 247 | |||
| 251 | list->next = *events; | 248 | list->next = *events; |
| 252 | *events = list; | 249 | *events = list; |
| 253 | list->event = event; | 250 | list->event = event; |
| 251 | return 0; | ||
| 254 | } | 252 | } |
| 255 | 253 | ||
| 256 | static int event_match(struct event_format *event, | 254 | static int event_match(struct event_format *event, |
| @@ -265,7 +263,7 @@ static int event_match(struct event_format *event, | |||
| 265 | !regexec(ereg, event->name, 0, NULL, 0); | 263 | !regexec(ereg, event->name, 0, NULL, 0); |
| 266 | } | 264 | } |
| 267 | 265 | ||
| 268 | static int | 266 | static enum pevent_errno |
| 269 | find_event(struct pevent *pevent, struct event_list **events, | 267 | find_event(struct pevent *pevent, struct event_list **events, |
| 270 | char *sys_name, char *event_name) | 268 | char *sys_name, char *event_name) |
| 271 | { | 269 | { |
| @@ -273,6 +271,7 @@ find_event(struct pevent *pevent, struct event_list **events, | |||
| 273 | regex_t ereg; | 271 | regex_t ereg; |
| 274 | regex_t sreg; | 272 | regex_t sreg; |
| 275 | int match = 0; | 273 | int match = 0; |
| 274 | int fail = 0; | ||
| 276 | char *reg; | 275 | char *reg; |
| 277 | int ret; | 276 | int ret; |
| 278 | int i; | 277 | int i; |
| @@ -283,23 +282,31 @@ find_event(struct pevent *pevent, struct event_list **events, | |||
| 283 | sys_name = NULL; | 282 | sys_name = NULL; |
| 284 | } | 283 | } |
| 285 | 284 | ||
| 286 | reg = malloc_or_die(strlen(event_name) + 3); | 285 | reg = malloc(strlen(event_name) + 3); |
| 286 | if (reg == NULL) | ||
| 287 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 288 | |||
| 287 | sprintf(reg, "^%s$", event_name); | 289 | sprintf(reg, "^%s$", event_name); |
| 288 | 290 | ||
| 289 | ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB); | 291 | ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB); |
| 290 | free(reg); | 292 | free(reg); |
| 291 | 293 | ||
| 292 | if (ret) | 294 | if (ret) |
| 293 | return -1; | 295 | return PEVENT_ERRNO__INVALID_EVENT_NAME; |
| 294 | 296 | ||
| 295 | if (sys_name) { | 297 | if (sys_name) { |
| 296 | reg = malloc_or_die(strlen(sys_name) + 3); | 298 | reg = malloc(strlen(sys_name) + 3); |
| 299 | if (reg == NULL) { | ||
| 300 | regfree(&ereg); | ||
| 301 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 302 | } | ||
| 303 | |||
| 297 | sprintf(reg, "^%s$", sys_name); | 304 | sprintf(reg, "^%s$", sys_name); |
| 298 | ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB); | 305 | ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB); |
| 299 | free(reg); | 306 | free(reg); |
| 300 | if (ret) { | 307 | if (ret) { |
| 301 | regfree(&ereg); | 308 | regfree(&ereg); |
| 302 | return -1; | 309 | return PEVENT_ERRNO__INVALID_EVENT_NAME; |
| 303 | } | 310 | } |
| 304 | } | 311 | } |
| 305 | 312 | ||
| @@ -307,7 +314,10 @@ find_event(struct pevent *pevent, struct event_list **events, | |||
| 307 | event = pevent->events[i]; | 314 | event = pevent->events[i]; |
| 308 | if (event_match(event, sys_name ? &sreg : NULL, &ereg)) { | 315 | if (event_match(event, sys_name ? &sreg : NULL, &ereg)) { |
| 309 | match = 1; | 316 | match = 1; |
| 310 | add_event(events, event); | 317 | if (add_event(events, event) < 0) { |
| 318 | fail = 1; | ||
| 319 | break; | ||
| 320 | } | ||
| 311 | } | 321 | } |
| 312 | } | 322 | } |
| 313 | 323 | ||
| @@ -316,7 +326,9 @@ find_event(struct pevent *pevent, struct event_list **events, | |||
| 316 | regfree(&sreg); | 326 | regfree(&sreg); |
| 317 | 327 | ||
| 318 | if (!match) | 328 | if (!match) |
| 319 | return -1; | 329 | return PEVENT_ERRNO__EVENT_NOT_FOUND; |
| 330 | if (fail) | ||
| 331 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 320 | 332 | ||
| 321 | return 0; | 333 | return 0; |
| 322 | } | 334 | } |
| @@ -332,14 +344,18 @@ static void free_events(struct event_list *events) | |||
| 332 | } | 344 | } |
| 333 | } | 345 | } |
| 334 | 346 | ||
| 335 | static struct filter_arg * | 347 | static enum pevent_errno |
| 336 | create_arg_item(struct event_format *event, const char *token, | 348 | create_arg_item(struct event_format *event, const char *token, |
| 337 | enum event_type type, char **error_str) | 349 | enum event_type type, struct filter_arg **parg, char *error_str) |
| 338 | { | 350 | { |
| 339 | struct format_field *field; | 351 | struct format_field *field; |
| 340 | struct filter_arg *arg; | 352 | struct filter_arg *arg; |
| 341 | 353 | ||
| 342 | arg = allocate_arg(); | 354 | arg = allocate_arg(); |
| 355 | if (arg == NULL) { | ||
| 356 | show_error(error_str, "failed to allocate filter arg"); | ||
| 357 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 358 | } | ||
| 343 | 359 | ||
| 344 | switch (type) { | 360 | switch (type) { |
| 345 | 361 | ||
| @@ -349,8 +365,11 @@ create_arg_item(struct event_format *event, const char *token, | |||
| 349 | arg->value.type = | 365 | arg->value.type = |
| 350 | type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR; | 366 | type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR; |
| 351 | arg->value.str = strdup(token); | 367 | arg->value.str = strdup(token); |
| 352 | if (!arg->value.str) | 368 | if (!arg->value.str) { |
| 353 | die("malloc string"); | 369 | free_arg(arg); |
| 370 | show_error(error_str, "failed to allocate string filter arg"); | ||
| 371 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 372 | } | ||
| 354 | break; | 373 | break; |
| 355 | case EVENT_ITEM: | 374 | case EVENT_ITEM: |
| 356 | /* if it is a number, then convert it */ | 375 | /* if it is a number, then convert it */ |
| @@ -377,11 +396,11 @@ create_arg_item(struct event_format *event, const char *token, | |||
| 377 | break; | 396 | break; |
| 378 | default: | 397 | default: |
| 379 | free_arg(arg); | 398 | free_arg(arg); |
| 380 | show_error(error_str, "expected a value but found %s", | 399 | show_error(error_str, "expected a value but found %s", token); |
| 381 | token); | 400 | return PEVENT_ERRNO__UNEXPECTED_TYPE; |
| 382 | return NULL; | ||
| 383 | } | 401 | } |
| 384 | return arg; | 402 | *parg = arg; |
| 403 | return 0; | ||
| 385 | } | 404 | } |
| 386 | 405 | ||
| 387 | static struct filter_arg * | 406 | static struct filter_arg * |
| @@ -390,6 +409,9 @@ create_arg_op(enum filter_op_type btype) | |||
| 390 | struct filter_arg *arg; | 409 | struct filter_arg *arg; |
| 391 | 410 | ||
| 392 | arg = allocate_arg(); | 411 | arg = allocate_arg(); |
| 412 | if (!arg) | ||
| 413 | return NULL; | ||
| 414 | |||
| 393 | arg->type = FILTER_ARG_OP; | 415 | arg->type = FILTER_ARG_OP; |
| 394 | arg->op.type = btype; | 416 | arg->op.type = btype; |
| 395 | 417 | ||
| @@ -402,6 +424,9 @@ create_arg_exp(enum filter_exp_type etype) | |||
| 402 | struct filter_arg *arg; | 424 | struct filter_arg *arg; |
| 403 | 425 | ||
| 404 | arg = allocate_arg(); | 426 | arg = allocate_arg(); |
| 427 | if (!arg) | ||
| 428 | return NULL; | ||
| 429 | |||
| 405 | arg->type = FILTER_ARG_EXP; | 430 | arg->type = FILTER_ARG_EXP; |
| 406 | arg->op.type = etype; | 431 | arg->op.type = etype; |
| 407 | 432 | ||
| @@ -414,6 +439,9 @@ create_arg_cmp(enum filter_exp_type etype) | |||
| 414 | struct filter_arg *arg; | 439 | struct filter_arg *arg; |
| 415 | 440 | ||
| 416 | arg = allocate_arg(); | 441 | arg = allocate_arg(); |
| 442 | if (!arg) | ||
| 443 | return NULL; | ||
| 444 | |||
| 417 | /* Use NUM and change if necessary */ | 445 | /* Use NUM and change if necessary */ |
| 418 | arg->type = FILTER_ARG_NUM; | 446 | arg->type = FILTER_ARG_NUM; |
| 419 | arg->op.type = etype; | 447 | arg->op.type = etype; |
| @@ -421,8 +449,8 @@ create_arg_cmp(enum filter_exp_type etype) | |||
| 421 | return arg; | 449 | return arg; |
| 422 | } | 450 | } |
| 423 | 451 | ||
| 424 | static int add_right(struct filter_arg *op, struct filter_arg *arg, | 452 | static enum pevent_errno |
| 425 | char **error_str) | 453 | add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str) |
| 426 | { | 454 | { |
| 427 | struct filter_arg *left; | 455 | struct filter_arg *left; |
| 428 | char *str; | 456 | char *str; |
| @@ -453,9 +481,8 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
| 453 | case FILTER_ARG_FIELD: | 481 | case FILTER_ARG_FIELD: |
| 454 | break; | 482 | break; |
| 455 | default: | 483 | default: |
| 456 | show_error(error_str, | 484 | show_error(error_str, "Illegal rvalue"); |
| 457 | "Illegal rvalue"); | 485 | return PEVENT_ERRNO__ILLEGAL_RVALUE; |
| 458 | return -1; | ||
| 459 | } | 486 | } |
| 460 | 487 | ||
| 461 | /* | 488 | /* |
| @@ -502,7 +529,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
| 502 | if (left->type != FILTER_ARG_FIELD) { | 529 | if (left->type != FILTER_ARG_FIELD) { |
| 503 | show_error(error_str, | 530 | show_error(error_str, |
| 504 | "Illegal lvalue for string comparison"); | 531 | "Illegal lvalue for string comparison"); |
| 505 | return -1; | 532 | return PEVENT_ERRNO__ILLEGAL_LVALUE; |
| 506 | } | 533 | } |
| 507 | 534 | ||
| 508 | /* Make sure this is a valid string compare */ | 535 | /* Make sure this is a valid string compare */ |
| @@ -521,25 +548,31 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
| 521 | show_error(error_str, | 548 | show_error(error_str, |
| 522 | "RegEx '%s' did not compute", | 549 | "RegEx '%s' did not compute", |
| 523 | str); | 550 | str); |
| 524 | return -1; | 551 | return PEVENT_ERRNO__INVALID_REGEX; |
| 525 | } | 552 | } |
| 526 | break; | 553 | break; |
| 527 | default: | 554 | default: |
| 528 | show_error(error_str, | 555 | show_error(error_str, |
| 529 | "Illegal comparison for string"); | 556 | "Illegal comparison for string"); |
| 530 | return -1; | 557 | return PEVENT_ERRNO__ILLEGAL_STRING_CMP; |
| 531 | } | 558 | } |
| 532 | 559 | ||
| 533 | op->type = FILTER_ARG_STR; | 560 | op->type = FILTER_ARG_STR; |
| 534 | op->str.type = op_type; | 561 | op->str.type = op_type; |
| 535 | op->str.field = left->field.field; | 562 | op->str.field = left->field.field; |
| 536 | op->str.val = strdup(str); | 563 | op->str.val = strdup(str); |
| 537 | if (!op->str.val) | 564 | if (!op->str.val) { |
| 538 | die("malloc string"); | 565 | show_error(error_str, "Failed to allocate string filter"); |
| 566 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 567 | } | ||
| 539 | /* | 568 | /* |
| 540 | * Need a buffer to copy data for tests | 569 | * Need a buffer to copy data for tests |
| 541 | */ | 570 | */ |
| 542 | op->str.buffer = malloc_or_die(op->str.field->size + 1); | 571 | op->str.buffer = malloc(op->str.field->size + 1); |
| 572 | if (!op->str.buffer) { | ||
| 573 | show_error(error_str, "Failed to allocate string filter"); | ||
| 574 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 575 | } | ||
| 543 | /* Null terminate this buffer */ | 576 | /* Null terminate this buffer */ |
| 544 | op->str.buffer[op->str.field->size] = 0; | 577 | op->str.buffer[op->str.field->size] = 0; |
| 545 | 578 | ||
| @@ -557,7 +590,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
| 557 | case FILTER_CMP_NOT_REGEX: | 590 | case FILTER_CMP_NOT_REGEX: |
| 558 | show_error(error_str, | 591 | show_error(error_str, |
| 559 | "Op not allowed with integers"); | 592 | "Op not allowed with integers"); |
| 560 | return -1; | 593 | return PEVENT_ERRNO__ILLEGAL_INTEGER_CMP; |
| 561 | 594 | ||
| 562 | default: | 595 | default: |
| 563 | break; | 596 | break; |
| @@ -577,9 +610,8 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
| 577 | return 0; | 610 | return 0; |
| 578 | 611 | ||
| 579 | out_fail: | 612 | out_fail: |
| 580 | show_error(error_str, | 613 | show_error(error_str, "Syntax error"); |
| 581 | "Syntax error"); | 614 | return PEVENT_ERRNO__SYNTAX_ERROR; |
| 582 | return -1; | ||
| 583 | } | 615 | } |
| 584 | 616 | ||
| 585 | static struct filter_arg * | 617 | static struct filter_arg * |
| @@ -592,7 +624,7 @@ rotate_op_right(struct filter_arg *a, struct filter_arg *b) | |||
| 592 | return arg; | 624 | return arg; |
| 593 | } | 625 | } |
| 594 | 626 | ||
| 595 | static int add_left(struct filter_arg *op, struct filter_arg *arg) | 627 | static enum pevent_errno add_left(struct filter_arg *op, struct filter_arg *arg) |
| 596 | { | 628 | { |
| 597 | switch (op->type) { | 629 | switch (op->type) { |
| 598 | case FILTER_ARG_EXP: | 630 | case FILTER_ARG_EXP: |
| @@ -611,11 +643,11 @@ static int add_left(struct filter_arg *op, struct filter_arg *arg) | |||
| 611 | /* left arg of compares must be a field */ | 643 | /* left arg of compares must be a field */ |
| 612 | if (arg->type != FILTER_ARG_FIELD && | 644 | if (arg->type != FILTER_ARG_FIELD && |
| 613 | arg->type != FILTER_ARG_BOOLEAN) | 645 | arg->type != FILTER_ARG_BOOLEAN) |
| 614 | return -1; | 646 | return PEVENT_ERRNO__INVALID_ARG_TYPE; |
| 615 | op->num.left = arg; | 647 | op->num.left = arg; |
| 616 | break; | 648 | break; |
| 617 | default: | 649 | default: |
| 618 | return -1; | 650 | return PEVENT_ERRNO__INVALID_ARG_TYPE; |
| 619 | } | 651 | } |
| 620 | return 0; | 652 | return 0; |
| 621 | } | 653 | } |
| @@ -728,15 +760,18 @@ enum filter_vals { | |||
| 728 | FILTER_VAL_TRUE, | 760 | FILTER_VAL_TRUE, |
| 729 | }; | 761 | }; |
| 730 | 762 | ||
| 731 | void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, | 763 | static enum pevent_errno |
| 732 | struct filter_arg *arg) | 764 | reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, |
| 765 | struct filter_arg *arg, char *error_str) | ||
| 733 | { | 766 | { |
| 734 | struct filter_arg *other_child; | 767 | struct filter_arg *other_child; |
| 735 | struct filter_arg **ptr; | 768 | struct filter_arg **ptr; |
| 736 | 769 | ||
| 737 | if (parent->type != FILTER_ARG_OP && | 770 | if (parent->type != FILTER_ARG_OP && |
| 738 | arg->type != FILTER_ARG_OP) | 771 | arg->type != FILTER_ARG_OP) { |
| 739 | die("can not reparent other than OP"); | 772 | show_error(error_str, "can not reparent other than OP"); |
| 773 | return PEVENT_ERRNO__REPARENT_NOT_OP; | ||
| 774 | } | ||
| 740 | 775 | ||
| 741 | /* Get the sibling */ | 776 | /* Get the sibling */ |
| 742 | if (old_child->op.right == arg) { | 777 | if (old_child->op.right == arg) { |
| @@ -745,8 +780,10 @@ void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, | |||
| 745 | } else if (old_child->op.left == arg) { | 780 | } else if (old_child->op.left == arg) { |
| 746 | ptr = &old_child->op.left; | 781 | ptr = &old_child->op.left; |
| 747 | other_child = old_child->op.right; | 782 | other_child = old_child->op.right; |
| 748 | } else | 783 | } else { |
| 749 | die("Error in reparent op, find other child"); | 784 | show_error(error_str, "Error in reparent op, find other child"); |
| 785 | return PEVENT_ERRNO__REPARENT_FAILED; | ||
| 786 | } | ||
| 750 | 787 | ||
| 751 | /* Detach arg from old_child */ | 788 | /* Detach arg from old_child */ |
| 752 | *ptr = NULL; | 789 | *ptr = NULL; |
| @@ -757,23 +794,29 @@ void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, | |||
| 757 | *parent = *arg; | 794 | *parent = *arg; |
| 758 | /* Free arg without recussion */ | 795 | /* Free arg without recussion */ |
| 759 | free(arg); | 796 | free(arg); |
| 760 | return; | 797 | return 0; |
| 761 | } | 798 | } |
| 762 | 799 | ||
| 763 | if (parent->op.right == old_child) | 800 | if (parent->op.right == old_child) |
| 764 | ptr = &parent->op.right; | 801 | ptr = &parent->op.right; |
| 765 | else if (parent->op.left == old_child) | 802 | else if (parent->op.left == old_child) |
| 766 | ptr = &parent->op.left; | 803 | ptr = &parent->op.left; |
| 767 | else | 804 | else { |
| 768 | die("Error in reparent op"); | 805 | show_error(error_str, "Error in reparent op"); |
| 806 | return PEVENT_ERRNO__REPARENT_FAILED; | ||
| 807 | } | ||
| 808 | |||
| 769 | *ptr = arg; | 809 | *ptr = arg; |
| 770 | 810 | ||
| 771 | free_arg(old_child); | 811 | free_arg(old_child); |
| 812 | return 0; | ||
| 772 | } | 813 | } |
| 773 | 814 | ||
| 774 | enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg) | 815 | /* Returns either filter_vals (success) or pevent_errno (failfure) */ |
| 816 | static int test_arg(struct filter_arg *parent, struct filter_arg *arg, | ||
| 817 | char *error_str) | ||
| 775 | { | 818 | { |
| 776 | enum filter_vals lval, rval; | 819 | int lval, rval; |
| 777 | 820 | ||
| 778 | switch (arg->type) { | 821 | switch (arg->type) { |
| 779 | 822 | ||
| @@ -788,63 +831,68 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg) | |||
| 788 | return FILTER_VAL_NORM; | 831 | return FILTER_VAL_NORM; |
| 789 | 832 | ||
| 790 | case FILTER_ARG_EXP: | 833 | case FILTER_ARG_EXP: |
| 791 | lval = test_arg(arg, arg->exp.left); | 834 | lval = test_arg(arg, arg->exp.left, error_str); |
| 792 | if (lval != FILTER_VAL_NORM) | 835 | if (lval != FILTER_VAL_NORM) |
| 793 | return lval; | 836 | return lval; |
| 794 | rval = test_arg(arg, arg->exp.right); | 837 | rval = test_arg(arg, arg->exp.right, error_str); |
| 795 | if (rval != FILTER_VAL_NORM) | 838 | if (rval != FILTER_VAL_NORM) |
| 796 | return rval; | 839 | return rval; |
| 797 | return FILTER_VAL_NORM; | 840 | return FILTER_VAL_NORM; |
| 798 | 841 | ||
| 799 | case FILTER_ARG_NUM: | 842 | case FILTER_ARG_NUM: |
| 800 | lval = test_arg(arg, arg->num.left); | 843 | lval = test_arg(arg, arg->num.left, error_str); |
| 801 | if (lval != FILTER_VAL_NORM) | 844 | if (lval != FILTER_VAL_NORM) |
| 802 | return lval; | 845 | return lval; |
| 803 | rval = test_arg(arg, arg->num.right); | 846 | rval = test_arg(arg, arg->num.right, error_str); |
| 804 | if (rval != FILTER_VAL_NORM) | 847 | if (rval != FILTER_VAL_NORM) |
| 805 | return rval; | 848 | return rval; |
| 806 | return FILTER_VAL_NORM; | 849 | return FILTER_VAL_NORM; |
| 807 | 850 | ||
| 808 | case FILTER_ARG_OP: | 851 | case FILTER_ARG_OP: |
| 809 | if (arg->op.type != FILTER_OP_NOT) { | 852 | if (arg->op.type != FILTER_OP_NOT) { |
| 810 | lval = test_arg(arg, arg->op.left); | 853 | lval = test_arg(arg, arg->op.left, error_str); |
| 811 | switch (lval) { | 854 | switch (lval) { |
| 812 | case FILTER_VAL_NORM: | 855 | case FILTER_VAL_NORM: |
| 813 | break; | 856 | break; |
| 814 | case FILTER_VAL_TRUE: | 857 | case FILTER_VAL_TRUE: |
| 815 | if (arg->op.type == FILTER_OP_OR) | 858 | if (arg->op.type == FILTER_OP_OR) |
| 816 | return FILTER_VAL_TRUE; | 859 | return FILTER_VAL_TRUE; |
| 817 | rval = test_arg(arg, arg->op.right); | 860 | rval = test_arg(arg, arg->op.right, error_str); |
| 818 | if (rval != FILTER_VAL_NORM) | 861 | if (rval != FILTER_VAL_NORM) |
| 819 | return rval; | 862 | return rval; |
| 820 | 863 | ||
| 821 | reparent_op_arg(parent, arg, arg->op.right); | 864 | return reparent_op_arg(parent, arg, arg->op.right, |
| 822 | return FILTER_VAL_NORM; | 865 | error_str); |
| 823 | 866 | ||
| 824 | case FILTER_VAL_FALSE: | 867 | case FILTER_VAL_FALSE: |
| 825 | if (arg->op.type == FILTER_OP_AND) | 868 | if (arg->op.type == FILTER_OP_AND) |
| 826 | return FILTER_VAL_FALSE; | 869 | return FILTER_VAL_FALSE; |
| 827 | rval = test_arg(arg, arg->op.right); | 870 | rval = test_arg(arg, arg->op.right, error_str); |
| 828 | if (rval != FILTER_VAL_NORM) | 871 | if (rval != FILTER_VAL_NORM) |
| 829 | return rval; | 872 | return rval; |
| 830 | 873 | ||
| 831 | reparent_op_arg(parent, arg, arg->op.right); | 874 | return reparent_op_arg(parent, arg, arg->op.right, |
| 832 | return FILTER_VAL_NORM; | 875 | error_str); |
| 876 | |||
| 877 | default: | ||
| 878 | return lval; | ||
| 833 | } | 879 | } |
| 834 | } | 880 | } |
| 835 | 881 | ||
| 836 | rval = test_arg(arg, arg->op.right); | 882 | rval = test_arg(arg, arg->op.right, error_str); |
| 837 | switch (rval) { | 883 | switch (rval) { |
| 838 | case FILTER_VAL_NORM: | 884 | case FILTER_VAL_NORM: |
| 885 | default: | ||
| 839 | break; | 886 | break; |
| 887 | |||
| 840 | case FILTER_VAL_TRUE: | 888 | case FILTER_VAL_TRUE: |
| 841 | if (arg->op.type == FILTER_OP_OR) | 889 | if (arg->op.type == FILTER_OP_OR) |
| 842 | return FILTER_VAL_TRUE; | 890 | return FILTER_VAL_TRUE; |
| 843 | if (arg->op.type == FILTER_OP_NOT) | 891 | if (arg->op.type == FILTER_OP_NOT) |
| 844 | return FILTER_VAL_FALSE; | 892 | return FILTER_VAL_FALSE; |
| 845 | 893 | ||
| 846 | reparent_op_arg(parent, arg, arg->op.left); | 894 | return reparent_op_arg(parent, arg, arg->op.left, |
| 847 | return FILTER_VAL_NORM; | 895 | error_str); |
| 848 | 896 | ||
| 849 | case FILTER_VAL_FALSE: | 897 | case FILTER_VAL_FALSE: |
| 850 | if (arg->op.type == FILTER_OP_AND) | 898 | if (arg->op.type == FILTER_OP_AND) |
| @@ -852,41 +900,56 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg) | |||
| 852 | if (arg->op.type == FILTER_OP_NOT) | 900 | if (arg->op.type == FILTER_OP_NOT) |
| 853 | return FILTER_VAL_TRUE; | 901 | return FILTER_VAL_TRUE; |
| 854 | 902 | ||
| 855 | reparent_op_arg(parent, arg, arg->op.left); | 903 | return reparent_op_arg(parent, arg, arg->op.left, |
| 856 | return FILTER_VAL_NORM; | 904 | error_str); |
| 857 | } | 905 | } |
| 858 | 906 | ||
| 859 | return FILTER_VAL_NORM; | 907 | return rval; |
| 860 | default: | 908 | default: |
| 861 | die("bad arg in filter tree"); | 909 | show_error(error_str, "bad arg in filter tree"); |
| 910 | return PEVENT_ERRNO__BAD_FILTER_ARG; | ||
| 862 | } | 911 | } |
| 863 | return FILTER_VAL_NORM; | 912 | return FILTER_VAL_NORM; |
| 864 | } | 913 | } |
| 865 | 914 | ||
| 866 | /* Remove any unknown event fields */ | 915 | /* Remove any unknown event fields */ |
| 867 | static struct filter_arg *collapse_tree(struct filter_arg *arg) | 916 | static int collapse_tree(struct filter_arg *arg, |
| 917 | struct filter_arg **arg_collapsed, char *error_str) | ||
| 868 | { | 918 | { |
| 869 | enum filter_vals ret; | 919 | int ret; |
| 870 | 920 | ||
| 871 | ret = test_arg(arg, arg); | 921 | ret = test_arg(arg, arg, error_str); |
| 872 | switch (ret) { | 922 | switch (ret) { |
| 873 | case FILTER_VAL_NORM: | 923 | case FILTER_VAL_NORM: |
| 874 | return arg; | 924 | break; |
| 875 | 925 | ||
| 876 | case FILTER_VAL_TRUE: | 926 | case FILTER_VAL_TRUE: |
| 877 | case FILTER_VAL_FALSE: | 927 | case FILTER_VAL_FALSE: |
| 878 | free_arg(arg); | 928 | free_arg(arg); |
| 879 | arg = allocate_arg(); | 929 | arg = allocate_arg(); |
| 880 | arg->type = FILTER_ARG_BOOLEAN; | 930 | if (arg) { |
| 881 | arg->boolean.value = ret == FILTER_VAL_TRUE; | 931 | arg->type = FILTER_ARG_BOOLEAN; |
| 932 | arg->boolean.value = ret == FILTER_VAL_TRUE; | ||
| 933 | } else { | ||
| 934 | show_error(error_str, "Failed to allocate filter arg"); | ||
| 935 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 936 | } | ||
| 937 | break; | ||
| 938 | |||
| 939 | default: | ||
| 940 | /* test_arg() already set the error_str */ | ||
| 941 | free_arg(arg); | ||
| 942 | arg = NULL; | ||
| 943 | break; | ||
| 882 | } | 944 | } |
| 883 | 945 | ||
| 884 | return arg; | 946 | *arg_collapsed = arg; |
| 947 | return ret; | ||
| 885 | } | 948 | } |
| 886 | 949 | ||
| 887 | static int | 950 | static enum pevent_errno |
| 888 | process_filter(struct event_format *event, struct filter_arg **parg, | 951 | process_filter(struct event_format *event, struct filter_arg **parg, |
| 889 | char **error_str, int not) | 952 | char *error_str, int not) |
| 890 | { | 953 | { |
| 891 | enum event_type type; | 954 | enum event_type type; |
| 892 | char *token = NULL; | 955 | char *token = NULL; |
| @@ -898,7 +961,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 898 | enum filter_op_type btype; | 961 | enum filter_op_type btype; |
| 899 | enum filter_exp_type etype; | 962 | enum filter_exp_type etype; |
| 900 | enum filter_cmp_type ctype; | 963 | enum filter_cmp_type ctype; |
| 901 | int ret; | 964 | enum pevent_errno ret; |
| 902 | 965 | ||
| 903 | *parg = NULL; | 966 | *parg = NULL; |
| 904 | 967 | ||
| @@ -909,8 +972,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 909 | case EVENT_SQUOTE: | 972 | case EVENT_SQUOTE: |
| 910 | case EVENT_DQUOTE: | 973 | case EVENT_DQUOTE: |
| 911 | case EVENT_ITEM: | 974 | case EVENT_ITEM: |
| 912 | arg = create_arg_item(event, token, type, error_str); | 975 | ret = create_arg_item(event, token, type, &arg, error_str); |
| 913 | if (!arg) | 976 | if (ret < 0) |
| 914 | goto fail; | 977 | goto fail; |
| 915 | if (!left_item) | 978 | if (!left_item) |
| 916 | left_item = arg; | 979 | left_item = arg; |
| @@ -923,20 +986,20 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 923 | if (not) { | 986 | if (not) { |
| 924 | arg = NULL; | 987 | arg = NULL; |
| 925 | if (current_op) | 988 | if (current_op) |
| 926 | goto fail_print; | 989 | goto fail_syntax; |
| 927 | free(token); | 990 | free(token); |
| 928 | *parg = current_exp; | 991 | *parg = current_exp; |
| 929 | return 0; | 992 | return 0; |
| 930 | } | 993 | } |
| 931 | } else | 994 | } else |
| 932 | goto fail_print; | 995 | goto fail_syntax; |
| 933 | arg = NULL; | 996 | arg = NULL; |
| 934 | break; | 997 | break; |
| 935 | 998 | ||
| 936 | case EVENT_DELIM: | 999 | case EVENT_DELIM: |
| 937 | if (*token == ',') { | 1000 | if (*token == ',') { |
| 938 | show_error(error_str, | 1001 | show_error(error_str, "Illegal token ','"); |
| 939 | "Illegal token ','"); | 1002 | ret = PEVENT_ERRNO__ILLEGAL_TOKEN; |
| 940 | goto fail; | 1003 | goto fail; |
| 941 | } | 1004 | } |
| 942 | 1005 | ||
| @@ -944,19 +1007,23 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 944 | if (left_item) { | 1007 | if (left_item) { |
| 945 | show_error(error_str, | 1008 | show_error(error_str, |
| 946 | "Open paren can not come after item"); | 1009 | "Open paren can not come after item"); |
| 1010 | ret = PEVENT_ERRNO__INVALID_PAREN; | ||
| 947 | goto fail; | 1011 | goto fail; |
| 948 | } | 1012 | } |
| 949 | if (current_exp) { | 1013 | if (current_exp) { |
| 950 | show_error(error_str, | 1014 | show_error(error_str, |
| 951 | "Open paren can not come after expression"); | 1015 | "Open paren can not come after expression"); |
| 1016 | ret = PEVENT_ERRNO__INVALID_PAREN; | ||
| 952 | goto fail; | 1017 | goto fail; |
| 953 | } | 1018 | } |
| 954 | 1019 | ||
| 955 | ret = process_filter(event, &arg, error_str, 0); | 1020 | ret = process_filter(event, &arg, error_str, 0); |
| 956 | if (ret != 1) { | 1021 | if (ret != PEVENT_ERRNO__UNBALANCED_PAREN) { |
| 957 | if (ret == 0) | 1022 | if (ret == 0) { |
| 958 | show_error(error_str, | 1023 | show_error(error_str, |
| 959 | "Unbalanced number of '('"); | 1024 | "Unbalanced number of '('"); |
| 1025 | ret = PEVENT_ERRNO__UNBALANCED_PAREN; | ||
| 1026 | } | ||
| 960 | goto fail; | 1027 | goto fail; |
| 961 | } | 1028 | } |
| 962 | ret = 0; | 1029 | ret = 0; |
| @@ -964,7 +1031,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 964 | /* A not wants just one expression */ | 1031 | /* A not wants just one expression */ |
| 965 | if (not) { | 1032 | if (not) { |
| 966 | if (current_op) | 1033 | if (current_op) |
| 967 | goto fail_print; | 1034 | goto fail_syntax; |
| 968 | *parg = arg; | 1035 | *parg = arg; |
| 969 | return 0; | 1036 | return 0; |
| 970 | } | 1037 | } |
| @@ -979,19 +1046,19 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 979 | 1046 | ||
| 980 | } else { /* ')' */ | 1047 | } else { /* ')' */ |
| 981 | if (!current_op && !current_exp) | 1048 | if (!current_op && !current_exp) |
| 982 | goto fail_print; | 1049 | goto fail_syntax; |
| 983 | 1050 | ||
| 984 | /* Make sure everything is finished at this level */ | 1051 | /* Make sure everything is finished at this level */ |
| 985 | if (current_exp && !check_op_done(current_exp)) | 1052 | if (current_exp && !check_op_done(current_exp)) |
| 986 | goto fail_print; | 1053 | goto fail_syntax; |
| 987 | if (current_op && !check_op_done(current_op)) | 1054 | if (current_op && !check_op_done(current_op)) |
| 988 | goto fail_print; | 1055 | goto fail_syntax; |
| 989 | 1056 | ||
| 990 | if (current_op) | 1057 | if (current_op) |
| 991 | *parg = current_op; | 1058 | *parg = current_op; |
| 992 | else | 1059 | else |
| 993 | *parg = current_exp; | 1060 | *parg = current_exp; |
| 994 | return 1; | 1061 | return PEVENT_ERRNO__UNBALANCED_PAREN; |
| 995 | } | 1062 | } |
| 996 | break; | 1063 | break; |
| 997 | 1064 | ||
| @@ -1003,21 +1070,22 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 1003 | case OP_BOOL: | 1070 | case OP_BOOL: |
| 1004 | /* Logic ops need a left expression */ | 1071 | /* Logic ops need a left expression */ |
| 1005 | if (!current_exp && !current_op) | 1072 | if (!current_exp && !current_op) |
| 1006 | goto fail_print; | 1073 | goto fail_syntax; |
| 1007 | /* fall through */ | 1074 | /* fall through */ |
| 1008 | case OP_NOT: | 1075 | case OP_NOT: |
| 1009 | /* logic only processes ops and exp */ | 1076 | /* logic only processes ops and exp */ |
| 1010 | if (left_item) | 1077 | if (left_item) |
| 1011 | goto fail_print; | 1078 | goto fail_syntax; |
| 1012 | break; | 1079 | break; |
| 1013 | case OP_EXP: | 1080 | case OP_EXP: |
| 1014 | case OP_CMP: | 1081 | case OP_CMP: |
| 1015 | if (!left_item) | 1082 | if (!left_item) |
| 1016 | goto fail_print; | 1083 | goto fail_syntax; |
| 1017 | break; | 1084 | break; |
| 1018 | case OP_NONE: | 1085 | case OP_NONE: |
| 1019 | show_error(error_str, | 1086 | show_error(error_str, |
| 1020 | "Unknown op token %s", token); | 1087 | "Unknown op token %s", token); |
| 1088 | ret = PEVENT_ERRNO__UNKNOWN_TOKEN; | ||
| 1021 | goto fail; | 1089 | goto fail; |
| 1022 | } | 1090 | } |
| 1023 | 1091 | ||
| @@ -1025,6 +1093,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 1025 | switch (op_type) { | 1093 | switch (op_type) { |
| 1026 | case OP_BOOL: | 1094 | case OP_BOOL: |
| 1027 | arg = create_arg_op(btype); | 1095 | arg = create_arg_op(btype); |
| 1096 | if (arg == NULL) | ||
| 1097 | goto fail_alloc; | ||
| 1028 | if (current_op) | 1098 | if (current_op) |
| 1029 | ret = add_left(arg, current_op); | 1099 | ret = add_left(arg, current_op); |
| 1030 | else | 1100 | else |
| @@ -1035,6 +1105,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 1035 | 1105 | ||
| 1036 | case OP_NOT: | 1106 | case OP_NOT: |
| 1037 | arg = create_arg_op(btype); | 1107 | arg = create_arg_op(btype); |
| 1108 | if (arg == NULL) | ||
| 1109 | goto fail_alloc; | ||
| 1038 | if (current_op) | 1110 | if (current_op) |
| 1039 | ret = add_right(current_op, arg, error_str); | 1111 | ret = add_right(current_op, arg, error_str); |
| 1040 | if (ret < 0) | 1112 | if (ret < 0) |
| @@ -1054,6 +1126,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 1054 | arg = create_arg_exp(etype); | 1126 | arg = create_arg_exp(etype); |
| 1055 | else | 1127 | else |
| 1056 | arg = create_arg_cmp(ctype); | 1128 | arg = create_arg_cmp(ctype); |
| 1129 | if (arg == NULL) | ||
| 1130 | goto fail_alloc; | ||
| 1057 | 1131 | ||
| 1058 | if (current_op) | 1132 | if (current_op) |
| 1059 | ret = add_right(current_op, arg, error_str); | 1133 | ret = add_right(current_op, arg, error_str); |
| @@ -1062,7 +1136,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 1062 | ret = add_left(arg, left_item); | 1136 | ret = add_left(arg, left_item); |
| 1063 | if (ret < 0) { | 1137 | if (ret < 0) { |
| 1064 | arg = NULL; | 1138 | arg = NULL; |
| 1065 | goto fail_print; | 1139 | goto fail_syntax; |
| 1066 | } | 1140 | } |
| 1067 | current_exp = arg; | 1141 | current_exp = arg; |
| 1068 | break; | 1142 | break; |
| @@ -1071,57 +1145,64 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 1071 | } | 1145 | } |
| 1072 | arg = NULL; | 1146 | arg = NULL; |
| 1073 | if (ret < 0) | 1147 | if (ret < 0) |
| 1074 | goto fail_print; | 1148 | goto fail_syntax; |
| 1075 | break; | 1149 | break; |
| 1076 | case EVENT_NONE: | 1150 | case EVENT_NONE: |
| 1077 | break; | 1151 | break; |
| 1152 | case EVENT_ERROR: | ||
| 1153 | goto fail_alloc; | ||
| 1078 | default: | 1154 | default: |
| 1079 | goto fail_print; | 1155 | goto fail_syntax; |
| 1080 | } | 1156 | } |
| 1081 | } while (type != EVENT_NONE); | 1157 | } while (type != EVENT_NONE); |
| 1082 | 1158 | ||
| 1083 | if (!current_op && !current_exp) | 1159 | if (!current_op && !current_exp) |
| 1084 | goto fail_print; | 1160 | goto fail_syntax; |
| 1085 | 1161 | ||
| 1086 | if (!current_op) | 1162 | if (!current_op) |
| 1087 | current_op = current_exp; | 1163 | current_op = current_exp; |
| 1088 | 1164 | ||
| 1089 | current_op = collapse_tree(current_op); | 1165 | ret = collapse_tree(current_op, parg, error_str); |
| 1166 | if (ret < 0) | ||
| 1167 | goto fail; | ||
| 1090 | 1168 | ||
| 1091 | *parg = current_op; | 1169 | *parg = current_op; |
| 1092 | 1170 | ||
| 1093 | return 0; | 1171 | return 0; |
| 1094 | 1172 | ||
| 1095 | fail_print: | 1173 | fail_alloc: |
| 1174 | show_error(error_str, "failed to allocate filter arg"); | ||
| 1175 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 1176 | goto fail; | ||
| 1177 | fail_syntax: | ||
| 1096 | show_error(error_str, "Syntax error"); | 1178 | show_error(error_str, "Syntax error"); |
| 1179 | ret = PEVENT_ERRNO__SYNTAX_ERROR; | ||
| 1097 | fail: | 1180 | fail: |
| 1098 | free_arg(current_op); | 1181 | free_arg(current_op); |
| 1099 | free_arg(current_exp); | 1182 | free_arg(current_exp); |
| 1100 | free_arg(arg); | 1183 | free_arg(arg); |
| 1101 | free(token); | 1184 | free(token); |
| 1102 | return -1; | 1185 | return ret; |
| 1103 | } | 1186 | } |
| 1104 | 1187 | ||
| 1105 | static int | 1188 | static enum pevent_errno |
| 1106 | process_event(struct event_format *event, const char *filter_str, | 1189 | process_event(struct event_format *event, const char *filter_str, |
| 1107 | struct filter_arg **parg, char **error_str) | 1190 | struct filter_arg **parg, char *error_str) |
| 1108 | { | 1191 | { |
| 1109 | int ret; | 1192 | int ret; |
| 1110 | 1193 | ||
| 1111 | pevent_buffer_init(filter_str, strlen(filter_str)); | 1194 | pevent_buffer_init(filter_str, strlen(filter_str)); |
| 1112 | 1195 | ||
| 1113 | ret = process_filter(event, parg, error_str, 0); | 1196 | ret = process_filter(event, parg, error_str, 0); |
| 1114 | if (ret == 1) { | ||
| 1115 | show_error(error_str, | ||
| 1116 | "Unbalanced number of ')'"); | ||
| 1117 | return -1; | ||
| 1118 | } | ||
| 1119 | if (ret < 0) | 1197 | if (ret < 0) |
| 1120 | return ret; | 1198 | return ret; |
| 1121 | 1199 | ||
| 1122 | /* If parg is NULL, then make it into FALSE */ | 1200 | /* If parg is NULL, then make it into FALSE */ |
| 1123 | if (!*parg) { | 1201 | if (!*parg) { |
| 1124 | *parg = allocate_arg(); | 1202 | *parg = allocate_arg(); |
| 1203 | if (*parg == NULL) | ||
| 1204 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 1205 | |||
| 1125 | (*parg)->type = FILTER_ARG_BOOLEAN; | 1206 | (*parg)->type = FILTER_ARG_BOOLEAN; |
| 1126 | (*parg)->boolean.value = FILTER_FALSE; | 1207 | (*parg)->boolean.value = FILTER_FALSE; |
| 1127 | } | 1208 | } |
| @@ -1129,13 +1210,13 @@ process_event(struct event_format *event, const char *filter_str, | |||
| 1129 | return 0; | 1210 | return 0; |
| 1130 | } | 1211 | } |
| 1131 | 1212 | ||
| 1132 | static int filter_event(struct event_filter *filter, | 1213 | static enum pevent_errno |
| 1133 | struct event_format *event, | 1214 | filter_event(struct event_filter *filter, struct event_format *event, |
| 1134 | const char *filter_str, char **error_str) | 1215 | const char *filter_str, char *error_str) |
| 1135 | { | 1216 | { |
| 1136 | struct filter_type *filter_type; | 1217 | struct filter_type *filter_type; |
| 1137 | struct filter_arg *arg; | 1218 | struct filter_arg *arg; |
| 1138 | int ret; | 1219 | enum pevent_errno ret; |
| 1139 | 1220 | ||
| 1140 | if (filter_str) { | 1221 | if (filter_str) { |
| 1141 | ret = process_event(event, filter_str, &arg, error_str); | 1222 | ret = process_event(event, filter_str, &arg, error_str); |
| @@ -1145,11 +1226,17 @@ static int filter_event(struct event_filter *filter, | |||
| 1145 | } else { | 1226 | } else { |
| 1146 | /* just add a TRUE arg */ | 1227 | /* just add a TRUE arg */ |
| 1147 | arg = allocate_arg(); | 1228 | arg = allocate_arg(); |
| 1229 | if (arg == NULL) | ||
| 1230 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 1231 | |||
| 1148 | arg->type = FILTER_ARG_BOOLEAN; | 1232 | arg->type = FILTER_ARG_BOOLEAN; |
| 1149 | arg->boolean.value = FILTER_TRUE; | 1233 | arg->boolean.value = FILTER_TRUE; |
| 1150 | } | 1234 | } |
| 1151 | 1235 | ||
| 1152 | filter_type = add_filter_type(filter, event->id); | 1236 | filter_type = add_filter_type(filter, event->id); |
| 1237 | if (filter_type == NULL) | ||
| 1238 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 1239 | |||
| 1153 | if (filter_type->filter) | 1240 | if (filter_type->filter) |
| 1154 | free_arg(filter_type->filter); | 1241 | free_arg(filter_type->filter); |
| 1155 | filter_type->filter = arg; | 1242 | filter_type->filter = arg; |
| @@ -1157,22 +1244,24 @@ static int filter_event(struct event_filter *filter, | |||
| 1157 | return 0; | 1244 | return 0; |
| 1158 | } | 1245 | } |
| 1159 | 1246 | ||
| 1247 | static void filter_init_error_buf(struct event_filter *filter) | ||
| 1248 | { | ||
| 1249 | /* clear buffer to reset show error */ | ||
| 1250 | pevent_buffer_init("", 0); | ||
| 1251 | filter->error_buffer[0] = '\0'; | ||
| 1252 | } | ||
| 1253 | |||
| 1160 | /** | 1254 | /** |
| 1161 | * pevent_filter_add_filter_str - add a new filter | 1255 | * pevent_filter_add_filter_str - add a new filter |
| 1162 | * @filter: the event filter to add to | 1256 | * @filter: the event filter to add to |
| 1163 | * @filter_str: the filter string that contains the filter | 1257 | * @filter_str: the filter string that contains the filter |
| 1164 | * @error_str: string containing reason for failed filter | ||
| 1165 | * | ||
| 1166 | * Returns 0 if the filter was successfully added | ||
| 1167 | * -1 if there was an error. | ||
| 1168 | * | 1258 | * |
| 1169 | * On error, if @error_str points to a string pointer, | 1259 | * Returns 0 if the filter was successfully added or a |
| 1170 | * it is set to the reason that the filter failed. | 1260 | * negative error code. Use pevent_filter_strerror() to see |
| 1171 | * This string must be freed with "free". | 1261 | * actual error message in case of error. |
| 1172 | */ | 1262 | */ |
| 1173 | int pevent_filter_add_filter_str(struct event_filter *filter, | 1263 | enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, |
| 1174 | const char *filter_str, | 1264 | const char *filter_str) |
| 1175 | char **error_str) | ||
| 1176 | { | 1265 | { |
| 1177 | struct pevent *pevent = filter->pevent; | 1266 | struct pevent *pevent = filter->pevent; |
| 1178 | struct event_list *event; | 1267 | struct event_list *event; |
| @@ -1183,15 +1272,11 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
| 1183 | char *event_name = NULL; | 1272 | char *event_name = NULL; |
| 1184 | char *sys_name = NULL; | 1273 | char *sys_name = NULL; |
| 1185 | char *sp; | 1274 | char *sp; |
| 1186 | int rtn = 0; | 1275 | enum pevent_errno rtn = 0; /* PEVENT_ERRNO__SUCCESS */ |
| 1187 | int len; | 1276 | int len; |
| 1188 | int ret; | 1277 | int ret; |
| 1189 | 1278 | ||
| 1190 | /* clear buffer to reset show error */ | 1279 | filter_init_error_buf(filter); |
| 1191 | pevent_buffer_init("", 0); | ||
| 1192 | |||
| 1193 | if (error_str) | ||
| 1194 | *error_str = NULL; | ||
| 1195 | 1280 | ||
| 1196 | filter_start = strchr(filter_str, ':'); | 1281 | filter_start = strchr(filter_str, ':'); |
| 1197 | if (filter_start) | 1282 | if (filter_start) |
| @@ -1199,7 +1284,6 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
| 1199 | else | 1284 | else |
| 1200 | len = strlen(filter_str); | 1285 | len = strlen(filter_str); |
| 1201 | 1286 | ||
| 1202 | |||
| 1203 | do { | 1287 | do { |
| 1204 | next_event = strchr(filter_str, ','); | 1288 | next_event = strchr(filter_str, ','); |
| 1205 | if (next_event && | 1289 | if (next_event && |
| @@ -1210,7 +1294,12 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
| 1210 | else | 1294 | else |
| 1211 | len = strlen(filter_str); | 1295 | len = strlen(filter_str); |
| 1212 | 1296 | ||
| 1213 | this_event = malloc_or_die(len + 1); | 1297 | this_event = malloc(len + 1); |
| 1298 | if (this_event == NULL) { | ||
| 1299 | /* This can only happen when events is NULL, but still */ | ||
| 1300 | free_events(events); | ||
| 1301 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 1302 | } | ||
| 1214 | memcpy(this_event, filter_str, len); | 1303 | memcpy(this_event, filter_str, len); |
| 1215 | this_event[len] = 0; | 1304 | this_event[len] = 0; |
| 1216 | 1305 | ||
| @@ -1223,27 +1312,18 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
| 1223 | event_name = strtok_r(NULL, "/", &sp); | 1312 | event_name = strtok_r(NULL, "/", &sp); |
| 1224 | 1313 | ||
| 1225 | if (!sys_name) { | 1314 | if (!sys_name) { |
| 1226 | show_error(error_str, "No filter found"); | ||
| 1227 | /* This can only happen when events is NULL, but still */ | 1315 | /* This can only happen when events is NULL, but still */ |
| 1228 | free_events(events); | 1316 | free_events(events); |
| 1229 | free(this_event); | 1317 | free(this_event); |
| 1230 | return -1; | 1318 | return PEVENT_ERRNO__FILTER_NOT_FOUND; |
| 1231 | } | 1319 | } |
| 1232 | 1320 | ||
| 1233 | /* Find this event */ | 1321 | /* Find this event */ |
| 1234 | ret = find_event(pevent, &events, strim(sys_name), strim(event_name)); | 1322 | ret = find_event(pevent, &events, strim(sys_name), strim(event_name)); |
| 1235 | if (ret < 0) { | 1323 | if (ret < 0) { |
| 1236 | if (event_name) | ||
| 1237 | show_error(error_str, | ||
| 1238 | "No event found under '%s.%s'", | ||
| 1239 | sys_name, event_name); | ||
| 1240 | else | ||
| 1241 | show_error(error_str, | ||
| 1242 | "No event found under '%s'", | ||
| 1243 | sys_name); | ||
| 1244 | free_events(events); | 1324 | free_events(events); |
| 1245 | free(this_event); | 1325 | free(this_event); |
| 1246 | return -1; | 1326 | return ret; |
| 1247 | } | 1327 | } |
| 1248 | free(this_event); | 1328 | free(this_event); |
| 1249 | } while (filter_str); | 1329 | } while (filter_str); |
| @@ -1255,7 +1335,7 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
| 1255 | /* filter starts here */ | 1335 | /* filter starts here */ |
| 1256 | for (event = events; event; event = event->next) { | 1336 | for (event = events; event; event = event->next) { |
| 1257 | ret = filter_event(filter, event->event, filter_start, | 1337 | ret = filter_event(filter, event->event, filter_start, |
| 1258 | error_str); | 1338 | filter->error_buffer); |
| 1259 | /* Failures are returned if a parse error happened */ | 1339 | /* Failures are returned if a parse error happened */ |
| 1260 | if (ret < 0) | 1340 | if (ret < 0) |
| 1261 | rtn = ret; | 1341 | rtn = ret; |
| @@ -1263,8 +1343,10 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
| 1263 | if (ret >= 0 && pevent->test_filters) { | 1343 | if (ret >= 0 && pevent->test_filters) { |
| 1264 | char *test; | 1344 | char *test; |
| 1265 | test = pevent_filter_make_string(filter, event->event->id); | 1345 | test = pevent_filter_make_string(filter, event->event->id); |
| 1266 | printf(" '%s: %s'\n", event->event->name, test); | 1346 | if (test) { |
| 1267 | free(test); | 1347 | printf(" '%s: %s'\n", event->event->name, test); |
| 1348 | free(test); | ||
| 1349 | } | ||
| 1268 | } | 1350 | } |
| 1269 | } | 1351 | } |
| 1270 | 1352 | ||
| @@ -1282,6 +1364,32 @@ static void free_filter_type(struct filter_type *filter_type) | |||
| 1282 | } | 1364 | } |
| 1283 | 1365 | ||
| 1284 | /** | 1366 | /** |
| 1367 | * pevent_filter_strerror - fill error message in a buffer | ||
| 1368 | * @filter: the event filter contains error | ||
| 1369 | * @err: the error code | ||
| 1370 | * @buf: the buffer to be filled in | ||
| 1371 | * @buflen: the size of the buffer | ||
| 1372 | * | ||
| 1373 | * Returns 0 if message was filled successfully, -1 if error | ||
| 1374 | */ | ||
| 1375 | int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err, | ||
| 1376 | char *buf, size_t buflen) | ||
| 1377 | { | ||
| 1378 | if (err <= __PEVENT_ERRNO__START || err >= __PEVENT_ERRNO__END) | ||
| 1379 | return -1; | ||
| 1380 | |||
| 1381 | if (strlen(filter->error_buffer) > 0) { | ||
| 1382 | size_t len = snprintf(buf, buflen, "%s", filter->error_buffer); | ||
| 1383 | |||
| 1384 | if (len > buflen) | ||
| 1385 | return -1; | ||
| 1386 | return 0; | ||
| 1387 | } | ||
| 1388 | |||
| 1389 | return pevent_strerror(filter->pevent, err, buf, buflen); | ||
| 1390 | } | ||
| 1391 | |||
| 1392 | /** | ||
| 1285 | * pevent_filter_remove_event - remove a filter for an event | 1393 | * pevent_filter_remove_event - remove a filter for an event |
| 1286 | * @filter: the event filter to remove from | 1394 | * @filter: the event filter to remove from |
| 1287 | * @event_id: the event to remove a filter for | 1395 | * @event_id: the event to remove a filter for |
| @@ -1374,6 +1482,9 @@ static int copy_filter_type(struct event_filter *filter, | |||
| 1374 | if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) { | 1482 | if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) { |
| 1375 | /* Add trivial event */ | 1483 | /* Add trivial event */ |
| 1376 | arg = allocate_arg(); | 1484 | arg = allocate_arg(); |
| 1485 | if (arg == NULL) | ||
| 1486 | return -1; | ||
| 1487 | |||
| 1377 | arg->type = FILTER_ARG_BOOLEAN; | 1488 | arg->type = FILTER_ARG_BOOLEAN; |
| 1378 | if (strcmp(str, "TRUE") == 0) | 1489 | if (strcmp(str, "TRUE") == 0) |
| 1379 | arg->boolean.value = 1; | 1490 | arg->boolean.value = 1; |
| @@ -1381,6 +1492,9 @@ static int copy_filter_type(struct event_filter *filter, | |||
| 1381 | arg->boolean.value = 0; | 1492 | arg->boolean.value = 0; |
| 1382 | 1493 | ||
| 1383 | filter_type = add_filter_type(filter, event->id); | 1494 | filter_type = add_filter_type(filter, event->id); |
| 1495 | if (filter_type == NULL) | ||
| 1496 | return -1; | ||
| 1497 | |||
| 1384 | filter_type->filter = arg; | 1498 | filter_type->filter = arg; |
| 1385 | 1499 | ||
| 1386 | free(str); | 1500 | free(str); |
| @@ -1482,8 +1596,10 @@ int pevent_update_trivial(struct event_filter *dest, struct event_filter *source | |||
| 1482 | * @type: remove only true, false, or both | 1596 | * @type: remove only true, false, or both |
| 1483 | * | 1597 | * |
| 1484 | * Removes filters that only contain a TRUE or FALES boolean arg. | 1598 | * Removes filters that only contain a TRUE or FALES boolean arg. |
| 1599 | * | ||
| 1600 | * Returns 0 on success and -1 if there was a problem. | ||
| 1485 | */ | 1601 | */ |
| 1486 | void pevent_filter_clear_trivial(struct event_filter *filter, | 1602 | int pevent_filter_clear_trivial(struct event_filter *filter, |
| 1487 | enum filter_trivial_type type) | 1603 | enum filter_trivial_type type) |
| 1488 | { | 1604 | { |
| 1489 | struct filter_type *filter_type; | 1605 | struct filter_type *filter_type; |
| @@ -1492,13 +1608,15 @@ void pevent_filter_clear_trivial(struct event_filter *filter, | |||
| 1492 | int i; | 1608 | int i; |
| 1493 | 1609 | ||
| 1494 | if (!filter->filters) | 1610 | if (!filter->filters) |
| 1495 | return; | 1611 | return 0; |
| 1496 | 1612 | ||
| 1497 | /* | 1613 | /* |
| 1498 | * Two steps, first get all ids with trivial filters. | 1614 | * Two steps, first get all ids with trivial filters. |
| 1499 | * then remove those ids. | 1615 | * then remove those ids. |
| 1500 | */ | 1616 | */ |
| 1501 | for (i = 0; i < filter->filters; i++) { | 1617 | for (i = 0; i < filter->filters; i++) { |
| 1618 | int *new_ids; | ||
| 1619 | |||
| 1502 | filter_type = &filter->event_filters[i]; | 1620 | filter_type = &filter->event_filters[i]; |
| 1503 | if (filter_type->filter->type != FILTER_ARG_BOOLEAN) | 1621 | if (filter_type->filter->type != FILTER_ARG_BOOLEAN) |
| 1504 | continue; | 1622 | continue; |
| @@ -1513,19 +1631,24 @@ void pevent_filter_clear_trivial(struct event_filter *filter, | |||
| 1513 | break; | 1631 | break; |
| 1514 | } | 1632 | } |
| 1515 | 1633 | ||
| 1516 | ids = realloc(ids, sizeof(*ids) * (count + 1)); | 1634 | new_ids = realloc(ids, sizeof(*ids) * (count + 1)); |
| 1517 | if (!ids) | 1635 | if (!new_ids) { |
| 1518 | die("Can't allocate ids"); | 1636 | free(ids); |
| 1637 | return -1; | ||
| 1638 | } | ||
| 1639 | |||
| 1640 | ids = new_ids; | ||
| 1519 | ids[count++] = filter_type->event_id; | 1641 | ids[count++] = filter_type->event_id; |
| 1520 | } | 1642 | } |
| 1521 | 1643 | ||
| 1522 | if (!count) | 1644 | if (!count) |
| 1523 | return; | 1645 | return 0; |
| 1524 | 1646 | ||
| 1525 | for (i = 0; i < count; i++) | 1647 | for (i = 0; i < count; i++) |
| 1526 | pevent_filter_remove_event(filter, ids[i]); | 1648 | pevent_filter_remove_event(filter, ids[i]); |
| 1527 | 1649 | ||
| 1528 | free(ids); | 1650 | free(ids); |
| 1651 | return 0; | ||
| 1529 | } | 1652 | } |
| 1530 | 1653 | ||
| 1531 | /** | 1654 | /** |
| @@ -1565,8 +1688,8 @@ int pevent_filter_event_has_trivial(struct event_filter *filter, | |||
| 1565 | } | 1688 | } |
| 1566 | } | 1689 | } |
| 1567 | 1690 | ||
| 1568 | static int test_filter(struct event_format *event, | 1691 | static int test_filter(struct event_format *event, struct filter_arg *arg, |
| 1569 | struct filter_arg *arg, struct pevent_record *record); | 1692 | struct pevent_record *record, enum pevent_errno *err); |
| 1570 | 1693 | ||
| 1571 | static const char * | 1694 | static const char * |
| 1572 | get_comm(struct event_format *event, struct pevent_record *record) | 1695 | get_comm(struct event_format *event, struct pevent_record *record) |
| @@ -1612,15 +1735,24 @@ get_value(struct event_format *event, | |||
| 1612 | } | 1735 | } |
| 1613 | 1736 | ||
| 1614 | static unsigned long long | 1737 | static unsigned long long |
| 1615 | get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record); | 1738 | get_arg_value(struct event_format *event, struct filter_arg *arg, |
| 1739 | struct pevent_record *record, enum pevent_errno *err); | ||
| 1616 | 1740 | ||
| 1617 | static unsigned long long | 1741 | static unsigned long long |
| 1618 | get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record) | 1742 | get_exp_value(struct event_format *event, struct filter_arg *arg, |
| 1743 | struct pevent_record *record, enum pevent_errno *err) | ||
| 1619 | { | 1744 | { |
| 1620 | unsigned long long lval, rval; | 1745 | unsigned long long lval, rval; |
| 1621 | 1746 | ||
| 1622 | lval = get_arg_value(event, arg->exp.left, record); | 1747 | lval = get_arg_value(event, arg->exp.left, record, err); |
| 1623 | rval = get_arg_value(event, arg->exp.right, record); | 1748 | rval = get_arg_value(event, arg->exp.right, record, err); |
| 1749 | |||
| 1750 | if (*err) { | ||
| 1751 | /* | ||
| 1752 | * There was an error, no need to process anymore. | ||
| 1753 | */ | ||
| 1754 | return 0; | ||
| 1755 | } | ||
| 1624 | 1756 | ||
| 1625 | switch (arg->exp.type) { | 1757 | switch (arg->exp.type) { |
| 1626 | case FILTER_EXP_ADD: | 1758 | case FILTER_EXP_ADD: |
| @@ -1655,39 +1787,51 @@ get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_ | |||
| 1655 | 1787 | ||
| 1656 | case FILTER_EXP_NOT: | 1788 | case FILTER_EXP_NOT: |
| 1657 | default: | 1789 | default: |
| 1658 | die("error in exp"); | 1790 | if (!*err) |
| 1791 | *err = PEVENT_ERRNO__INVALID_EXP_TYPE; | ||
| 1659 | } | 1792 | } |
| 1660 | return 0; | 1793 | return 0; |
| 1661 | } | 1794 | } |
| 1662 | 1795 | ||
| 1663 | static unsigned long long | 1796 | static unsigned long long |
| 1664 | get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record) | 1797 | get_arg_value(struct event_format *event, struct filter_arg *arg, |
| 1798 | struct pevent_record *record, enum pevent_errno *err) | ||
| 1665 | { | 1799 | { |
| 1666 | switch (arg->type) { | 1800 | switch (arg->type) { |
| 1667 | case FILTER_ARG_FIELD: | 1801 | case FILTER_ARG_FIELD: |
| 1668 | return get_value(event, arg->field.field, record); | 1802 | return get_value(event, arg->field.field, record); |
| 1669 | 1803 | ||
| 1670 | case FILTER_ARG_VALUE: | 1804 | case FILTER_ARG_VALUE: |
| 1671 | if (arg->value.type != FILTER_NUMBER) | 1805 | if (arg->value.type != FILTER_NUMBER) { |
| 1672 | die("must have number field!"); | 1806 | if (!*err) |
| 1807 | *err = PEVENT_ERRNO__NOT_A_NUMBER; | ||
| 1808 | } | ||
| 1673 | return arg->value.val; | 1809 | return arg->value.val; |
| 1674 | 1810 | ||
| 1675 | case FILTER_ARG_EXP: | 1811 | case FILTER_ARG_EXP: |
| 1676 | return get_exp_value(event, arg, record); | 1812 | return get_exp_value(event, arg, record, err); |
| 1677 | 1813 | ||
| 1678 | default: | 1814 | default: |
| 1679 | die("oops in filter"); | 1815 | if (!*err) |
| 1816 | *err = PEVENT_ERRNO__INVALID_ARG_TYPE; | ||
| 1680 | } | 1817 | } |
| 1681 | return 0; | 1818 | return 0; |
| 1682 | } | 1819 | } |
| 1683 | 1820 | ||
| 1684 | static int test_num(struct event_format *event, | 1821 | static int test_num(struct event_format *event, struct filter_arg *arg, |
| 1685 | struct filter_arg *arg, struct pevent_record *record) | 1822 | struct pevent_record *record, enum pevent_errno *err) |
| 1686 | { | 1823 | { |
| 1687 | unsigned long long lval, rval; | 1824 | unsigned long long lval, rval; |
| 1688 | 1825 | ||
| 1689 | lval = get_arg_value(event, arg->num.left, record); | 1826 | lval = get_arg_value(event, arg->num.left, record, err); |
| 1690 | rval = get_arg_value(event, arg->num.right, record); | 1827 | rval = get_arg_value(event, arg->num.right, record, err); |
| 1828 | |||
| 1829 | if (*err) { | ||
| 1830 | /* | ||
| 1831 | * There was an error, no need to process anymore. | ||
| 1832 | */ | ||
| 1833 | return 0; | ||
| 1834 | } | ||
| 1691 | 1835 | ||
| 1692 | switch (arg->num.type) { | 1836 | switch (arg->num.type) { |
| 1693 | case FILTER_CMP_EQ: | 1837 | case FILTER_CMP_EQ: |
| @@ -1709,7 +1853,8 @@ static int test_num(struct event_format *event, | |||
| 1709 | return lval <= rval; | 1853 | return lval <= rval; |
| 1710 | 1854 | ||
| 1711 | default: | 1855 | default: |
| 1712 | /* ?? */ | 1856 | if (!*err) |
| 1857 | *err = PEVENT_ERRNO__ILLEGAL_INTEGER_CMP; | ||
| 1713 | return 0; | 1858 | return 0; |
| 1714 | } | 1859 | } |
| 1715 | } | 1860 | } |
| @@ -1756,8 +1901,8 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r | |||
| 1756 | return val; | 1901 | return val; |
| 1757 | } | 1902 | } |
| 1758 | 1903 | ||
| 1759 | static int test_str(struct event_format *event, | 1904 | static int test_str(struct event_format *event, struct filter_arg *arg, |
| 1760 | struct filter_arg *arg, struct pevent_record *record) | 1905 | struct pevent_record *record, enum pevent_errno *err) |
| 1761 | { | 1906 | { |
| 1762 | const char *val; | 1907 | const char *val; |
| 1763 | 1908 | ||
| @@ -1781,48 +1926,57 @@ static int test_str(struct event_format *event, | |||
| 1781 | return regexec(&arg->str.reg, val, 0, NULL, 0); | 1926 | return regexec(&arg->str.reg, val, 0, NULL, 0); |
| 1782 | 1927 | ||
| 1783 | default: | 1928 | default: |
| 1784 | /* ?? */ | 1929 | if (!*err) |
| 1930 | *err = PEVENT_ERRNO__ILLEGAL_STRING_CMP; | ||
| 1785 | return 0; | 1931 | return 0; |
| 1786 | } | 1932 | } |
| 1787 | } | 1933 | } |
| 1788 | 1934 | ||
| 1789 | static int test_op(struct event_format *event, | 1935 | static int test_op(struct event_format *event, struct filter_arg *arg, |
| 1790 | struct filter_arg *arg, struct pevent_record *record) | 1936 | struct pevent_record *record, enum pevent_errno *err) |
| 1791 | { | 1937 | { |
| 1792 | switch (arg->op.type) { | 1938 | switch (arg->op.type) { |
| 1793 | case FILTER_OP_AND: | 1939 | case FILTER_OP_AND: |
| 1794 | return test_filter(event, arg->op.left, record) && | 1940 | return test_filter(event, arg->op.left, record, err) && |
| 1795 | test_filter(event, arg->op.right, record); | 1941 | test_filter(event, arg->op.right, record, err); |
| 1796 | 1942 | ||
| 1797 | case FILTER_OP_OR: | 1943 | case FILTER_OP_OR: |
| 1798 | return test_filter(event, arg->op.left, record) || | 1944 | return test_filter(event, arg->op.left, record, err) || |
| 1799 | test_filter(event, arg->op.right, record); | 1945 | test_filter(event, arg->op.right, record, err); |
| 1800 | 1946 | ||
| 1801 | case FILTER_OP_NOT: | 1947 | case FILTER_OP_NOT: |
| 1802 | return !test_filter(event, arg->op.right, record); | 1948 | return !test_filter(event, arg->op.right, record, err); |
| 1803 | 1949 | ||
| 1804 | default: | 1950 | default: |
| 1805 | /* ?? */ | 1951 | if (!*err) |
| 1952 | *err = PEVENT_ERRNO__INVALID_OP_TYPE; | ||
| 1806 | return 0; | 1953 | return 0; |
| 1807 | } | 1954 | } |
| 1808 | } | 1955 | } |
| 1809 | 1956 | ||
| 1810 | static int test_filter(struct event_format *event, | 1957 | static int test_filter(struct event_format *event, struct filter_arg *arg, |
| 1811 | struct filter_arg *arg, struct pevent_record *record) | 1958 | struct pevent_record *record, enum pevent_errno *err) |
| 1812 | { | 1959 | { |
| 1960 | if (*err) { | ||
| 1961 | /* | ||
| 1962 | * There was an error, no need to process anymore. | ||
| 1963 | */ | ||
| 1964 | return 0; | ||
| 1965 | } | ||
| 1966 | |||
| 1813 | switch (arg->type) { | 1967 | switch (arg->type) { |
| 1814 | case FILTER_ARG_BOOLEAN: | 1968 | case FILTER_ARG_BOOLEAN: |
| 1815 | /* easy case */ | 1969 | /* easy case */ |
| 1816 | return arg->boolean.value; | 1970 | return arg->boolean.value; |
| 1817 | 1971 | ||
| 1818 | case FILTER_ARG_OP: | 1972 | case FILTER_ARG_OP: |
| 1819 | return test_op(event, arg, record); | 1973 | return test_op(event, arg, record, err); |
| 1820 | 1974 | ||
| 1821 | case FILTER_ARG_NUM: | 1975 | case FILTER_ARG_NUM: |
| 1822 | return test_num(event, arg, record); | 1976 | return test_num(event, arg, record, err); |
| 1823 | 1977 | ||
| 1824 | case FILTER_ARG_STR: | 1978 | case FILTER_ARG_STR: |
| 1825 | return test_str(event, arg, record); | 1979 | return test_str(event, arg, record, err); |
| 1826 | 1980 | ||
| 1827 | case FILTER_ARG_EXP: | 1981 | case FILTER_ARG_EXP: |
| 1828 | case FILTER_ARG_VALUE: | 1982 | case FILTER_ARG_VALUE: |
| @@ -1831,11 +1985,11 @@ static int test_filter(struct event_format *event, | |||
| 1831 | * Expressions, fields and values evaluate | 1985 | * Expressions, fields and values evaluate |
| 1832 | * to true if they return non zero | 1986 | * to true if they return non zero |
| 1833 | */ | 1987 | */ |
| 1834 | return !!get_arg_value(event, arg, record); | 1988 | return !!get_arg_value(event, arg, record, err); |
| 1835 | 1989 | ||
| 1836 | default: | 1990 | default: |
| 1837 | die("oops!"); | 1991 | if (!*err) |
| 1838 | /* ?? */ | 1992 | *err = PEVENT_ERRNO__INVALID_ARG_TYPE; |
| 1839 | return 0; | 1993 | return 0; |
| 1840 | } | 1994 | } |
| 1841 | } | 1995 | } |
| @@ -1848,8 +2002,7 @@ static int test_filter(struct event_format *event, | |||
| 1848 | * Returns 1 if filter found for @event_id | 2002 | * Returns 1 if filter found for @event_id |
| 1849 | * otherwise 0; | 2003 | * otherwise 0; |
| 1850 | */ | 2004 | */ |
| 1851 | int pevent_event_filtered(struct event_filter *filter, | 2005 | int pevent_event_filtered(struct event_filter *filter, int event_id) |
| 1852 | int event_id) | ||
| 1853 | { | 2006 | { |
| 1854 | struct filter_type *filter_type; | 2007 | struct filter_type *filter_type; |
| 1855 | 2008 | ||
| @@ -1866,31 +2019,38 @@ int pevent_event_filtered(struct event_filter *filter, | |||
| 1866 | * @filter: filter struct with filter information | 2019 | * @filter: filter struct with filter information |
| 1867 | * @record: the record to test against the filter | 2020 | * @record: the record to test against the filter |
| 1868 | * | 2021 | * |
| 1869 | * Returns: | 2022 | * Returns: match result or error code (prefixed with PEVENT_ERRNO__) |
| 1870 | * 1 - filter found for event and @record matches | 2023 | * FILTER_MATCH - filter found for event and @record matches |
| 1871 | * 0 - filter found for event and @record does not match | 2024 | * FILTER_MISS - filter found for event and @record does not match |
| 1872 | * -1 - no filter found for @record's event | 2025 | * FILTER_NOT_FOUND - no filter found for @record's event |
| 1873 | * -2 - if no filters exist | 2026 | * NO_FILTER - if no filters exist |
| 2027 | * otherwise - error occurred during test | ||
| 1874 | */ | 2028 | */ |
| 1875 | int pevent_filter_match(struct event_filter *filter, | 2029 | enum pevent_errno pevent_filter_match(struct event_filter *filter, |
| 1876 | struct pevent_record *record) | 2030 | struct pevent_record *record) |
| 1877 | { | 2031 | { |
| 1878 | struct pevent *pevent = filter->pevent; | 2032 | struct pevent *pevent = filter->pevent; |
| 1879 | struct filter_type *filter_type; | 2033 | struct filter_type *filter_type; |
| 1880 | int event_id; | 2034 | int event_id; |
| 2035 | int ret; | ||
| 2036 | enum pevent_errno err = 0; | ||
| 2037 | |||
| 2038 | filter_init_error_buf(filter); | ||
| 1881 | 2039 | ||
| 1882 | if (!filter->filters) | 2040 | if (!filter->filters) |
| 1883 | return FILTER_NONE; | 2041 | return PEVENT_ERRNO__NO_FILTER; |
| 1884 | 2042 | ||
| 1885 | event_id = pevent_data_type(pevent, record); | 2043 | event_id = pevent_data_type(pevent, record); |
| 1886 | 2044 | ||
| 1887 | filter_type = find_filter_type(filter, event_id); | 2045 | filter_type = find_filter_type(filter, event_id); |
| 1888 | |||
| 1889 | if (!filter_type) | 2046 | if (!filter_type) |
| 1890 | return FILTER_NOEXIST; | 2047 | return PEVENT_ERRNO__FILTER_NOT_FOUND; |
| 2048 | |||
| 2049 | ret = test_filter(filter_type->event, filter_type->filter, record, &err); | ||
| 2050 | if (err) | ||
| 2051 | return err; | ||
| 1891 | 2052 | ||
| 1892 | return test_filter(filter_type->event, filter_type->filter, record) ? | 2053 | return ret ? PEVENT_ERRNO__FILTER_MATCH : PEVENT_ERRNO__FILTER_MISS; |
| 1893 | FILTER_MATCH : FILTER_MISS; | ||
| 1894 | } | 2054 | } |
| 1895 | 2055 | ||
| 1896 | static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | 2056 | static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) |
| @@ -1902,7 +2062,6 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 1902 | int left_val = -1; | 2062 | int left_val = -1; |
| 1903 | int right_val = -1; | 2063 | int right_val = -1; |
| 1904 | int val; | 2064 | int val; |
| 1905 | int len; | ||
| 1906 | 2065 | ||
| 1907 | switch (arg->op.type) { | 2066 | switch (arg->op.type) { |
| 1908 | case FILTER_OP_AND: | 2067 | case FILTER_OP_AND: |
| @@ -1949,11 +2108,7 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 1949 | default: | 2108 | default: |
| 1950 | break; | 2109 | break; |
| 1951 | } | 2110 | } |
| 1952 | str = malloc_or_die(6); | 2111 | asprintf(&str, val ? "TRUE" : "FALSE"); |
| 1953 | if (val) | ||
| 1954 | strcpy(str, "TRUE"); | ||
| 1955 | else | ||
| 1956 | strcpy(str, "FALSE"); | ||
| 1957 | break; | 2112 | break; |
| 1958 | } | 2113 | } |
| 1959 | } | 2114 | } |
| @@ -1971,10 +2126,7 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 1971 | break; | 2126 | break; |
| 1972 | } | 2127 | } |
| 1973 | 2128 | ||
| 1974 | len = strlen(left) + strlen(right) + strlen(op) + 10; | 2129 | asprintf(&str, "(%s) %s (%s)", left, op, right); |
| 1975 | str = malloc_or_die(len); | ||
| 1976 | snprintf(str, len, "(%s) %s (%s)", | ||
| 1977 | left, op, right); | ||
| 1978 | break; | 2130 | break; |
| 1979 | 2131 | ||
| 1980 | case FILTER_OP_NOT: | 2132 | case FILTER_OP_NOT: |
| @@ -1990,16 +2142,10 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 1990 | right_val = 0; | 2142 | right_val = 0; |
| 1991 | if (right_val >= 0) { | 2143 | if (right_val >= 0) { |
| 1992 | /* just return the opposite */ | 2144 | /* just return the opposite */ |
| 1993 | str = malloc_or_die(6); | 2145 | asprintf(&str, right_val ? "FALSE" : "TRUE"); |
| 1994 | if (right_val) | ||
| 1995 | strcpy(str, "FALSE"); | ||
| 1996 | else | ||
| 1997 | strcpy(str, "TRUE"); | ||
| 1998 | break; | 2146 | break; |
| 1999 | } | 2147 | } |
| 2000 | len = strlen(right) + strlen(op) + 3; | 2148 | asprintf(&str, "%s(%s)", op, right); |
| 2001 | str = malloc_or_die(len); | ||
| 2002 | snprintf(str, len, "%s(%s)", op, right); | ||
| 2003 | break; | 2149 | break; |
| 2004 | 2150 | ||
| 2005 | default: | 2151 | default: |
| @@ -2013,11 +2159,9 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 2013 | 2159 | ||
| 2014 | static char *val_to_str(struct event_filter *filter, struct filter_arg *arg) | 2160 | static char *val_to_str(struct event_filter *filter, struct filter_arg *arg) |
| 2015 | { | 2161 | { |
| 2016 | char *str; | 2162 | char *str = NULL; |
| 2017 | |||
| 2018 | str = malloc_or_die(30); | ||
| 2019 | 2163 | ||
| 2020 | snprintf(str, 30, "%lld", arg->value.val); | 2164 | asprintf(&str, "%lld", arg->value.val); |
| 2021 | 2165 | ||
| 2022 | return str; | 2166 | return str; |
| 2023 | } | 2167 | } |
| @@ -2033,7 +2177,6 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 2033 | char *rstr; | 2177 | char *rstr; |
| 2034 | char *op; | 2178 | char *op; |
| 2035 | char *str = NULL; | 2179 | char *str = NULL; |
| 2036 | int len; | ||
| 2037 | 2180 | ||
| 2038 | lstr = arg_to_str(filter, arg->exp.left); | 2181 | lstr = arg_to_str(filter, arg->exp.left); |
| 2039 | rstr = arg_to_str(filter, arg->exp.right); | 2182 | rstr = arg_to_str(filter, arg->exp.right); |
| @@ -2072,12 +2215,11 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 2072 | op = "^"; | 2215 | op = "^"; |
| 2073 | break; | 2216 | break; |
| 2074 | default: | 2217 | default: |
| 2075 | die("oops in exp"); | 2218 | op = "[ERROR IN EXPRESSION TYPE]"; |
| 2219 | break; | ||
| 2076 | } | 2220 | } |
| 2077 | 2221 | ||
| 2078 | len = strlen(op) + strlen(lstr) + strlen(rstr) + 4; | 2222 | asprintf(&str, "%s %s %s", lstr, op, rstr); |
| 2079 | str = malloc_or_die(len); | ||
| 2080 | snprintf(str, len, "%s %s %s", lstr, op, rstr); | ||
| 2081 | out: | 2223 | out: |
| 2082 | free(lstr); | 2224 | free(lstr); |
| 2083 | free(rstr); | 2225 | free(rstr); |
| @@ -2091,7 +2233,6 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 2091 | char *rstr; | 2233 | char *rstr; |
| 2092 | char *str = NULL; | 2234 | char *str = NULL; |
| 2093 | char *op = NULL; | 2235 | char *op = NULL; |
| 2094 | int len; | ||
| 2095 | 2236 | ||
| 2096 | lstr = arg_to_str(filter, arg->num.left); | 2237 | lstr = arg_to_str(filter, arg->num.left); |
| 2097 | rstr = arg_to_str(filter, arg->num.right); | 2238 | rstr = arg_to_str(filter, arg->num.right); |
| @@ -2122,10 +2263,7 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 2122 | if (!op) | 2263 | if (!op) |
| 2123 | op = "<="; | 2264 | op = "<="; |
| 2124 | 2265 | ||
| 2125 | len = strlen(lstr) + strlen(op) + strlen(rstr) + 4; | 2266 | asprintf(&str, "%s %s %s", lstr, op, rstr); |
| 2126 | str = malloc_or_die(len); | ||
| 2127 | sprintf(str, "%s %s %s", lstr, op, rstr); | ||
| 2128 | |||
| 2129 | break; | 2267 | break; |
| 2130 | 2268 | ||
| 2131 | default: | 2269 | default: |
| @@ -2143,7 +2281,6 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 2143 | { | 2281 | { |
| 2144 | char *str = NULL; | 2282 | char *str = NULL; |
| 2145 | char *op = NULL; | 2283 | char *op = NULL; |
| 2146 | int len; | ||
| 2147 | 2284 | ||
| 2148 | switch (arg->str.type) { | 2285 | switch (arg->str.type) { |
| 2149 | case FILTER_CMP_MATCH: | 2286 | case FILTER_CMP_MATCH: |
| @@ -2161,12 +2298,8 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 2161 | if (!op) | 2298 | if (!op) |
| 2162 | op = "!~"; | 2299 | op = "!~"; |
| 2163 | 2300 | ||
| 2164 | len = strlen(arg->str.field->name) + strlen(op) + | 2301 | asprintf(&str, "%s %s \"%s\"", |
| 2165 | strlen(arg->str.val) + 6; | 2302 | arg->str.field->name, op, arg->str.val); |
| 2166 | str = malloc_or_die(len); | ||
| 2167 | snprintf(str, len, "%s %s \"%s\"", | ||
| 2168 | arg->str.field->name, | ||
| 2169 | op, arg->str.val); | ||
| 2170 | break; | 2303 | break; |
| 2171 | 2304 | ||
| 2172 | default: | 2305 | default: |
| @@ -2178,15 +2311,11 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 2178 | 2311 | ||
| 2179 | static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg) | 2312 | static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg) |
| 2180 | { | 2313 | { |
| 2181 | char *str; | 2314 | char *str = NULL; |
| 2182 | 2315 | ||
| 2183 | switch (arg->type) { | 2316 | switch (arg->type) { |
| 2184 | case FILTER_ARG_BOOLEAN: | 2317 | case FILTER_ARG_BOOLEAN: |
| 2185 | str = malloc_or_die(6); | 2318 | asprintf(&str, arg->boolean.value ? "TRUE" : "FALSE"); |
| 2186 | if (arg->boolean.value) | ||
| 2187 | strcpy(str, "TRUE"); | ||
| 2188 | else | ||
| 2189 | strcpy(str, "FALSE"); | ||
| 2190 | return str; | 2319 | return str; |
| 2191 | 2320 | ||
| 2192 | case FILTER_ARG_OP: | 2321 | case FILTER_ARG_OP: |
| @@ -2221,7 +2350,7 @@ static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 2221 | * | 2350 | * |
| 2222 | * Returns a string that displays the filter contents. | 2351 | * Returns a string that displays the filter contents. |
| 2223 | * This string must be freed with free(str). | 2352 | * This string must be freed with free(str). |
| 2224 | * NULL is returned if no filter is found. | 2353 | * NULL is returned if no filter is found or allocation failed. |
| 2225 | */ | 2354 | */ |
| 2226 | char * | 2355 | char * |
| 2227 | pevent_filter_make_string(struct event_filter *filter, int event_id) | 2356 | pevent_filter_make_string(struct event_filter *filter, int event_id) |
diff --git a/tools/lib/traceevent/parse-utils.c b/tools/lib/traceevent/parse-utils.c index bba701cf10e6..eda07fa31dca 100644 --- a/tools/lib/traceevent/parse-utils.c +++ b/tools/lib/traceevent/parse-utils.c | |||
| @@ -25,40 +25,6 @@ | |||
| 25 | 25 | ||
| 26 | #define __weak __attribute__((weak)) | 26 | #define __weak __attribute__((weak)) |
| 27 | 27 | ||
| 28 | void __vdie(const char *fmt, va_list ap) | ||
| 29 | { | ||
| 30 | int ret = errno; | ||
| 31 | |||
| 32 | if (errno) | ||
| 33 | perror("trace-cmd"); | ||
| 34 | else | ||
| 35 | ret = -1; | ||
| 36 | |||
| 37 | fprintf(stderr, " "); | ||
| 38 | vfprintf(stderr, fmt, ap); | ||
| 39 | |||
| 40 | fprintf(stderr, "\n"); | ||
| 41 | exit(ret); | ||
| 42 | } | ||
| 43 | |||
| 44 | void __die(const char *fmt, ...) | ||
| 45 | { | ||
| 46 | va_list ap; | ||
| 47 | |||
| 48 | va_start(ap, fmt); | ||
| 49 | __vdie(fmt, ap); | ||
| 50 | va_end(ap); | ||
| 51 | } | ||
| 52 | |||
| 53 | void __weak die(const char *fmt, ...) | ||
| 54 | { | ||
| 55 | va_list ap; | ||
| 56 | |||
| 57 | va_start(ap, fmt); | ||
| 58 | __vdie(fmt, ap); | ||
| 59 | va_end(ap); | ||
| 60 | } | ||
| 61 | |||
| 62 | void __vwarning(const char *fmt, va_list ap) | 28 | void __vwarning(const char *fmt, va_list ap) |
| 63 | { | 29 | { |
| 64 | if (errno) | 30 | if (errno) |
| @@ -117,13 +83,3 @@ void __weak pr_stat(const char *fmt, ...) | |||
| 117 | __vpr_stat(fmt, ap); | 83 | __vpr_stat(fmt, ap); |
| 118 | va_end(ap); | 84 | va_end(ap); |
| 119 | } | 85 | } |
| 120 | |||
| 121 | void __weak *malloc_or_die(unsigned int size) | ||
| 122 | { | ||
| 123 | void *data; | ||
| 124 | |||
| 125 | data = malloc(size); | ||
| 126 | if (!data) | ||
| 127 | die("malloc"); | ||
| 128 | return data; | ||
| 129 | } | ||
diff --git a/tools/lib/traceevent/plugin_cfg80211.c b/tools/lib/traceevent/plugin_cfg80211.c new file mode 100644 index 000000000000..c066b25905f8 --- /dev/null +++ b/tools/lib/traceevent/plugin_cfg80211.c | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <string.h> | ||
| 3 | #include <inttypes.h> | ||
| 4 | #include <endian.h> | ||
| 5 | #include "event-parse.h" | ||
| 6 | |||
| 7 | static unsigned long long | ||
| 8 | process___le16_to_cpup(struct trace_seq *s, | ||
| 9 | unsigned long long *args) | ||
| 10 | { | ||
| 11 | uint16_t *val = (uint16_t *) (unsigned long) args[0]; | ||
| 12 | return val ? (long long) le16toh(*val) : 0; | ||
| 13 | } | ||
| 14 | |||
| 15 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 16 | { | ||
| 17 | pevent_register_print_function(pevent, | ||
| 18 | process___le16_to_cpup, | ||
| 19 | PEVENT_FUNC_ARG_INT, | ||
| 20 | "__le16_to_cpup", | ||
| 21 | PEVENT_FUNC_ARG_PTR, | ||
| 22 | PEVENT_FUNC_ARG_VOID); | ||
| 23 | return 0; | ||
| 24 | } | ||
| 25 | |||
| 26 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
| 27 | { | ||
| 28 | pevent_unregister_print_function(pevent, process___le16_to_cpup, | ||
| 29 | "__le16_to_cpup"); | ||
| 30 | } | ||
diff --git a/tools/lib/traceevent/plugin_function.c b/tools/lib/traceevent/plugin_function.c new file mode 100644 index 000000000000..80ba4ff1fe84 --- /dev/null +++ b/tools/lib/traceevent/plugin_function.c | |||
| @@ -0,0 +1,163 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; | ||
| 8 | * version 2.1 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
| 17 | * | ||
| 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 19 | */ | ||
| 20 | #include <stdio.h> | ||
| 21 | #include <stdlib.h> | ||
| 22 | #include <string.h> | ||
| 23 | |||
| 24 | #include "event-parse.h" | ||
| 25 | #include "event-utils.h" | ||
| 26 | |||
| 27 | static struct func_stack { | ||
| 28 | int size; | ||
| 29 | char **stack; | ||
| 30 | } *fstack; | ||
| 31 | |||
| 32 | static int cpus = -1; | ||
| 33 | |||
| 34 | #define STK_BLK 10 | ||
| 35 | |||
| 36 | static void add_child(struct func_stack *stack, const char *child, int pos) | ||
| 37 | { | ||
| 38 | int i; | ||
| 39 | |||
| 40 | if (!child) | ||
| 41 | return; | ||
| 42 | |||
| 43 | if (pos < stack->size) | ||
| 44 | free(stack->stack[pos]); | ||
| 45 | else { | ||
| 46 | char **ptr; | ||
| 47 | |||
| 48 | ptr = realloc(stack->stack, sizeof(char *) * | ||
| 49 | (stack->size + STK_BLK)); | ||
| 50 | if (!ptr) { | ||
| 51 | warning("could not allocate plugin memory\n"); | ||
| 52 | return; | ||
| 53 | } | ||
| 54 | |||
| 55 | stack->stack = ptr; | ||
| 56 | |||
| 57 | for (i = stack->size; i < stack->size + STK_BLK; i++) | ||
| 58 | stack->stack[i] = NULL; | ||
| 59 | stack->size += STK_BLK; | ||
| 60 | } | ||
| 61 | |||
| 62 | stack->stack[pos] = strdup(child); | ||
| 63 | } | ||
| 64 | |||
| 65 | static int add_and_get_index(const char *parent, const char *child, int cpu) | ||
| 66 | { | ||
| 67 | int i; | ||
| 68 | |||
| 69 | if (cpu < 0) | ||
| 70 | return 0; | ||
| 71 | |||
| 72 | if (cpu > cpus) { | ||
| 73 | struct func_stack *ptr; | ||
| 74 | |||
| 75 | ptr = realloc(fstack, sizeof(*fstack) * (cpu + 1)); | ||
| 76 | if (!ptr) { | ||
| 77 | warning("could not allocate plugin memory\n"); | ||
| 78 | return 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | fstack = ptr; | ||
| 82 | |||
| 83 | /* Account for holes in the cpu count */ | ||
| 84 | for (i = cpus + 1; i <= cpu; i++) | ||
| 85 | memset(&fstack[i], 0, sizeof(fstack[i])); | ||
| 86 | cpus = cpu; | ||
| 87 | } | ||
| 88 | |||
| 89 | for (i = 0; i < fstack[cpu].size && fstack[cpu].stack[i]; i++) { | ||
| 90 | if (strcmp(parent, fstack[cpu].stack[i]) == 0) { | ||
| 91 | add_child(&fstack[cpu], child, i+1); | ||
| 92 | return i; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | /* Not found */ | ||
| 97 | add_child(&fstack[cpu], parent, 0); | ||
| 98 | add_child(&fstack[cpu], child, 1); | ||
| 99 | return 0; | ||
| 100 | } | ||
| 101 | |||
| 102 | static int function_handler(struct trace_seq *s, struct pevent_record *record, | ||
| 103 | struct event_format *event, void *context) | ||
| 104 | { | ||
| 105 | struct pevent *pevent = event->pevent; | ||
| 106 | unsigned long long function; | ||
| 107 | unsigned long long pfunction; | ||
| 108 | const char *func; | ||
| 109 | const char *parent; | ||
| 110 | int index; | ||
| 111 | |||
| 112 | if (pevent_get_field_val(s, event, "ip", record, &function, 1)) | ||
| 113 | return trace_seq_putc(s, '!'); | ||
| 114 | |||
| 115 | func = pevent_find_function(pevent, function); | ||
| 116 | |||
| 117 | if (pevent_get_field_val(s, event, "parent_ip", record, &pfunction, 1)) | ||
| 118 | return trace_seq_putc(s, '!'); | ||
| 119 | |||
| 120 | parent = pevent_find_function(pevent, pfunction); | ||
| 121 | |||
| 122 | index = add_and_get_index(parent, func, record->cpu); | ||
| 123 | |||
| 124 | trace_seq_printf(s, "%*s", index*3, ""); | ||
| 125 | |||
| 126 | if (func) | ||
| 127 | trace_seq_printf(s, "%s", func); | ||
| 128 | else | ||
| 129 | trace_seq_printf(s, "0x%llx", function); | ||
| 130 | |||
| 131 | trace_seq_printf(s, " <-- "); | ||
| 132 | if (parent) | ||
| 133 | trace_seq_printf(s, "%s", parent); | ||
| 134 | else | ||
| 135 | trace_seq_printf(s, "0x%llx", pfunction); | ||
| 136 | |||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 141 | { | ||
| 142 | pevent_register_event_handler(pevent, -1, "ftrace", "function", | ||
| 143 | function_handler, NULL); | ||
| 144 | return 0; | ||
| 145 | } | ||
| 146 | |||
| 147 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
| 148 | { | ||
| 149 | int i, x; | ||
| 150 | |||
| 151 | pevent_unregister_event_handler(pevent, -1, "ftrace", "function", | ||
| 152 | function_handler, NULL); | ||
| 153 | |||
| 154 | for (i = 0; i <= cpus; i++) { | ||
| 155 | for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++) | ||
| 156 | free(fstack[i].stack[x]); | ||
| 157 | free(fstack[i].stack); | ||
| 158 | } | ||
| 159 | |||
| 160 | free(fstack); | ||
| 161 | fstack = NULL; | ||
| 162 | cpus = -1; | ||
| 163 | } | ||
diff --git a/tools/lib/traceevent/plugin_hrtimer.c b/tools/lib/traceevent/plugin_hrtimer.c new file mode 100644 index 000000000000..12bf14cc1152 --- /dev/null +++ b/tools/lib/traceevent/plugin_hrtimer.c | |||
| @@ -0,0 +1,88 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * Copyright (C) 2009 Johannes Berg <johannes@sipsolutions.net> | ||
| 4 | * | ||
| 5 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; | ||
| 9 | * version 2.1 of the License (not later!) | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
| 18 | * | ||
| 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 20 | */ | ||
| 21 | #include <stdio.h> | ||
| 22 | #include <stdlib.h> | ||
| 23 | #include <string.h> | ||
| 24 | |||
| 25 | #include "event-parse.h" | ||
| 26 | |||
| 27 | static int timer_expire_handler(struct trace_seq *s, | ||
| 28 | struct pevent_record *record, | ||
| 29 | struct event_format *event, void *context) | ||
| 30 | { | ||
| 31 | trace_seq_printf(s, "hrtimer="); | ||
| 32 | |||
| 33 | if (pevent_print_num_field(s, "0x%llx", event, "timer", | ||
| 34 | record, 0) == -1) | ||
| 35 | pevent_print_num_field(s, "0x%llx", event, "hrtimer", | ||
| 36 | record, 1); | ||
| 37 | |||
| 38 | trace_seq_printf(s, " now="); | ||
| 39 | |||
| 40 | pevent_print_num_field(s, "%llu", event, "now", record, 1); | ||
| 41 | |||
| 42 | pevent_print_func_field(s, " function=%s", event, "function", | ||
| 43 | record, 0); | ||
| 44 | return 0; | ||
| 45 | } | ||
| 46 | |||
| 47 | static int timer_start_handler(struct trace_seq *s, | ||
| 48 | struct pevent_record *record, | ||
| 49 | struct event_format *event, void *context) | ||
| 50 | { | ||
| 51 | trace_seq_printf(s, "hrtimer="); | ||
| 52 | |||
| 53 | if (pevent_print_num_field(s, "0x%llx", event, "timer", | ||
| 54 | record, 0) == -1) | ||
| 55 | pevent_print_num_field(s, "0x%llx", event, "hrtimer", | ||
| 56 | record, 1); | ||
| 57 | |||
| 58 | pevent_print_func_field(s, " function=%s", event, "function", | ||
| 59 | record, 0); | ||
| 60 | |||
| 61 | trace_seq_printf(s, " expires="); | ||
| 62 | pevent_print_num_field(s, "%llu", event, "expires", record, 1); | ||
| 63 | |||
| 64 | trace_seq_printf(s, " softexpires="); | ||
| 65 | pevent_print_num_field(s, "%llu", event, "softexpires", record, 1); | ||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 70 | { | ||
| 71 | pevent_register_event_handler(pevent, -1, | ||
| 72 | "timer", "hrtimer_expire_entry", | ||
| 73 | timer_expire_handler, NULL); | ||
| 74 | |||
| 75 | pevent_register_event_handler(pevent, -1, "timer", "hrtimer_start", | ||
| 76 | timer_start_handler, NULL); | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | |||
| 80 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
| 81 | { | ||
| 82 | pevent_unregister_event_handler(pevent, -1, | ||
| 83 | "timer", "hrtimer_expire_entry", | ||
| 84 | timer_expire_handler, NULL); | ||
| 85 | |||
| 86 | pevent_unregister_event_handler(pevent, -1, "timer", "hrtimer_start", | ||
| 87 | timer_start_handler, NULL); | ||
| 88 | } | ||
diff --git a/tools/lib/traceevent/plugin_jbd2.c b/tools/lib/traceevent/plugin_jbd2.c new file mode 100644 index 000000000000..0db714c721be --- /dev/null +++ b/tools/lib/traceevent/plugin_jbd2.c | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; | ||
| 8 | * version 2.1 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
| 17 | * | ||
| 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 19 | */ | ||
| 20 | #include <stdio.h> | ||
| 21 | #include <stdlib.h> | ||
| 22 | #include <string.h> | ||
| 23 | |||
| 24 | #include "event-parse.h" | ||
| 25 | |||
| 26 | #define MINORBITS 20 | ||
| 27 | #define MINORMASK ((1U << MINORBITS) - 1) | ||
| 28 | |||
| 29 | #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) | ||
| 30 | #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) | ||
| 31 | |||
| 32 | static unsigned long long | ||
| 33 | process_jbd2_dev_to_name(struct trace_seq *s, | ||
| 34 | unsigned long long *args) | ||
| 35 | { | ||
| 36 | unsigned int dev = args[0]; | ||
| 37 | |||
| 38 | trace_seq_printf(s, "%d:%d", MAJOR(dev), MINOR(dev)); | ||
| 39 | return 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | static unsigned long long | ||
| 43 | process_jiffies_to_msecs(struct trace_seq *s, | ||
| 44 | unsigned long long *args) | ||
| 45 | { | ||
| 46 | unsigned long long jiffies = args[0]; | ||
| 47 | |||
| 48 | trace_seq_printf(s, "%lld", jiffies); | ||
| 49 | return jiffies; | ||
| 50 | } | ||
| 51 | |||
| 52 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 53 | { | ||
| 54 | pevent_register_print_function(pevent, | ||
| 55 | process_jbd2_dev_to_name, | ||
| 56 | PEVENT_FUNC_ARG_STRING, | ||
| 57 | "jbd2_dev_to_name", | ||
| 58 | PEVENT_FUNC_ARG_INT, | ||
| 59 | PEVENT_FUNC_ARG_VOID); | ||
| 60 | |||
| 61 | pevent_register_print_function(pevent, | ||
| 62 | process_jiffies_to_msecs, | ||
| 63 | PEVENT_FUNC_ARG_LONG, | ||
| 64 | "jiffies_to_msecs", | ||
| 65 | PEVENT_FUNC_ARG_LONG, | ||
| 66 | PEVENT_FUNC_ARG_VOID); | ||
| 67 | return 0; | ||
| 68 | } | ||
| 69 | |||
| 70 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
| 71 | { | ||
| 72 | pevent_unregister_print_function(pevent, process_jbd2_dev_to_name, | ||
| 73 | "jbd2_dev_to_name"); | ||
| 74 | |||
| 75 | pevent_unregister_print_function(pevent, process_jiffies_to_msecs, | ||
| 76 | "jiffies_to_msecs"); | ||
| 77 | } | ||
diff --git a/tools/lib/traceevent/plugin_kmem.c b/tools/lib/traceevent/plugin_kmem.c new file mode 100644 index 000000000000..70650ff48d78 --- /dev/null +++ b/tools/lib/traceevent/plugin_kmem.c | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; | ||
| 8 | * version 2.1 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
| 17 | * | ||
| 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 19 | */ | ||
| 20 | #include <stdio.h> | ||
| 21 | #include <stdlib.h> | ||
| 22 | #include <string.h> | ||
| 23 | |||
| 24 | #include "event-parse.h" | ||
| 25 | |||
| 26 | static int call_site_handler(struct trace_seq *s, struct pevent_record *record, | ||
| 27 | struct event_format *event, void *context) | ||
| 28 | { | ||
| 29 | struct format_field *field; | ||
| 30 | unsigned long long val, addr; | ||
| 31 | void *data = record->data; | ||
| 32 | const char *func; | ||
| 33 | |||
| 34 | field = pevent_find_field(event, "call_site"); | ||
| 35 | if (!field) | ||
| 36 | return 1; | ||
| 37 | |||
| 38 | if (pevent_read_number_field(field, data, &val)) | ||
| 39 | return 1; | ||
| 40 | |||
| 41 | func = pevent_find_function(event->pevent, val); | ||
| 42 | if (!func) | ||
| 43 | return 1; | ||
| 44 | |||
| 45 | addr = pevent_find_function_address(event->pevent, val); | ||
| 46 | |||
| 47 | trace_seq_printf(s, "(%s+0x%x) ", func, (int)(val - addr)); | ||
| 48 | return 1; | ||
| 49 | } | ||
| 50 | |||
| 51 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 52 | { | ||
| 53 | pevent_register_event_handler(pevent, -1, "kmem", "kfree", | ||
| 54 | call_site_handler, NULL); | ||
| 55 | |||
| 56 | pevent_register_event_handler(pevent, -1, "kmem", "kmalloc", | ||
| 57 | call_site_handler, NULL); | ||
| 58 | |||
| 59 | pevent_register_event_handler(pevent, -1, "kmem", "kmalloc_node", | ||
| 60 | call_site_handler, NULL); | ||
| 61 | |||
| 62 | pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_alloc", | ||
| 63 | call_site_handler, NULL); | ||
| 64 | |||
| 65 | pevent_register_event_handler(pevent, -1, "kmem", | ||
| 66 | "kmem_cache_alloc_node", | ||
| 67 | call_site_handler, NULL); | ||
| 68 | |||
| 69 | pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_free", | ||
| 70 | call_site_handler, NULL); | ||
| 71 | return 0; | ||
| 72 | } | ||
| 73 | |||
| 74 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
| 75 | { | ||
| 76 | pevent_unregister_event_handler(pevent, -1, "kmem", "kfree", | ||
| 77 | call_site_handler, NULL); | ||
| 78 | |||
| 79 | pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc", | ||
| 80 | call_site_handler, NULL); | ||
| 81 | |||
| 82 | pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc_node", | ||
| 83 | call_site_handler, NULL); | ||
| 84 | |||
| 85 | pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_alloc", | ||
| 86 | call_site_handler, NULL); | ||
| 87 | |||
| 88 | pevent_unregister_event_handler(pevent, -1, "kmem", | ||
| 89 | "kmem_cache_alloc_node", | ||
| 90 | call_site_handler, NULL); | ||
| 91 | |||
| 92 | pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_free", | ||
| 93 | call_site_handler, NULL); | ||
| 94 | } | ||
diff --git a/tools/lib/traceevent/plugin_kvm.c b/tools/lib/traceevent/plugin_kvm.c new file mode 100644 index 000000000000..9e0e8c61b43b --- /dev/null +++ b/tools/lib/traceevent/plugin_kvm.c | |||
| @@ -0,0 +1,465 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; | ||
| 8 | * version 2.1 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
| 17 | * | ||
| 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 19 | */ | ||
| 20 | #include <stdio.h> | ||
| 21 | #include <stdlib.h> | ||
| 22 | #include <string.h> | ||
| 23 | #include <stdint.h> | ||
| 24 | |||
| 25 | #include "event-parse.h" | ||
| 26 | |||
| 27 | #ifdef HAVE_UDIS86 | ||
| 28 | |||
| 29 | #include <udis86.h> | ||
| 30 | |||
| 31 | static ud_t ud; | ||
| 32 | |||
| 33 | static void init_disassembler(void) | ||
| 34 | { | ||
| 35 | ud_init(&ud); | ||
| 36 | ud_set_syntax(&ud, UD_SYN_ATT); | ||
| 37 | } | ||
| 38 | |||
| 39 | static const char *disassemble(unsigned char *insn, int len, uint64_t rip, | ||
| 40 | int cr0_pe, int eflags_vm, | ||
| 41 | int cs_d, int cs_l) | ||
| 42 | { | ||
| 43 | int mode; | ||
| 44 | |||
| 45 | if (!cr0_pe) | ||
| 46 | mode = 16; | ||
| 47 | else if (eflags_vm) | ||
| 48 | mode = 16; | ||
| 49 | else if (cs_l) | ||
| 50 | mode = 64; | ||
| 51 | else if (cs_d) | ||
| 52 | mode = 32; | ||
| 53 | else | ||
| 54 | mode = 16; | ||
| 55 | |||
| 56 | ud_set_pc(&ud, rip); | ||
| 57 | ud_set_mode(&ud, mode); | ||
| 58 | ud_set_input_buffer(&ud, insn, len); | ||
| 59 | ud_disassemble(&ud); | ||
| 60 | return ud_insn_asm(&ud); | ||
| 61 | } | ||
| 62 | |||
| 63 | #else | ||
| 64 | |||
| 65 | static void init_disassembler(void) | ||
| 66 | { | ||
| 67 | } | ||
| 68 | |||
| 69 | static const char *disassemble(unsigned char *insn, int len, uint64_t rip, | ||
| 70 | int cr0_pe, int eflags_vm, | ||
| 71 | int cs_d, int cs_l) | ||
| 72 | { | ||
| 73 | static char out[15*3+1]; | ||
| 74 | int i; | ||
| 75 | |||
| 76 | for (i = 0; i < len; ++i) | ||
| 77 | sprintf(out + i * 3, "%02x ", insn[i]); | ||
| 78 | out[len*3-1] = '\0'; | ||
| 79 | return out; | ||
| 80 | } | ||
| 81 | |||
| 82 | #endif | ||
| 83 | |||
| 84 | |||
| 85 | #define VMX_EXIT_REASONS \ | ||
| 86 | _ER(EXCEPTION_NMI, 0) \ | ||
| 87 | _ER(EXTERNAL_INTERRUPT, 1) \ | ||
| 88 | _ER(TRIPLE_FAULT, 2) \ | ||
| 89 | _ER(PENDING_INTERRUPT, 7) \ | ||
| 90 | _ER(NMI_WINDOW, 8) \ | ||
| 91 | _ER(TASK_SWITCH, 9) \ | ||
| 92 | _ER(CPUID, 10) \ | ||
| 93 | _ER(HLT, 12) \ | ||
| 94 | _ER(INVD, 13) \ | ||
| 95 | _ER(INVLPG, 14) \ | ||
| 96 | _ER(RDPMC, 15) \ | ||
| 97 | _ER(RDTSC, 16) \ | ||
| 98 | _ER(VMCALL, 18) \ | ||
| 99 | _ER(VMCLEAR, 19) \ | ||
| 100 | _ER(VMLAUNCH, 20) \ | ||
| 101 | _ER(VMPTRLD, 21) \ | ||
| 102 | _ER(VMPTRST, 22) \ | ||
| 103 | _ER(VMREAD, 23) \ | ||
| 104 | _ER(VMRESUME, 24) \ | ||
| 105 | _ER(VMWRITE, 25) \ | ||
| 106 | _ER(VMOFF, 26) \ | ||
| 107 | _ER(VMON, 27) \ | ||
| 108 | _ER(CR_ACCESS, 28) \ | ||
| 109 | _ER(DR_ACCESS, 29) \ | ||
| 110 | _ER(IO_INSTRUCTION, 30) \ | ||
| 111 | _ER(MSR_READ, 31) \ | ||
| 112 | _ER(MSR_WRITE, 32) \ | ||
| 113 | _ER(MWAIT_INSTRUCTION, 36) \ | ||
| 114 | _ER(MONITOR_INSTRUCTION, 39) \ | ||
| 115 | _ER(PAUSE_INSTRUCTION, 40) \ | ||
| 116 | _ER(MCE_DURING_VMENTRY, 41) \ | ||
| 117 | _ER(TPR_BELOW_THRESHOLD, 43) \ | ||
| 118 | _ER(APIC_ACCESS, 44) \ | ||
| 119 | _ER(EOI_INDUCED, 45) \ | ||
| 120 | _ER(EPT_VIOLATION, 48) \ | ||
| 121 | _ER(EPT_MISCONFIG, 49) \ | ||
| 122 | _ER(INVEPT, 50) \ | ||
| 123 | _ER(PREEMPTION_TIMER, 52) \ | ||
| 124 | _ER(WBINVD, 54) \ | ||
| 125 | _ER(XSETBV, 55) \ | ||
| 126 | _ER(APIC_WRITE, 56) \ | ||
| 127 | _ER(INVPCID, 58) | ||
| 128 | |||
| 129 | #define SVM_EXIT_REASONS \ | ||
| 130 | _ER(EXIT_READ_CR0, 0x000) \ | ||
| 131 | _ER(EXIT_READ_CR3, 0x003) \ | ||
| 132 | _ER(EXIT_READ_CR4, 0x004) \ | ||
| 133 | _ER(EXIT_READ_CR8, 0x008) \ | ||
| 134 | _ER(EXIT_WRITE_CR0, 0x010) \ | ||
| 135 | _ER(EXIT_WRITE_CR3, 0x013) \ | ||
| 136 | _ER(EXIT_WRITE_CR4, 0x014) \ | ||
| 137 | _ER(EXIT_WRITE_CR8, 0x018) \ | ||
| 138 | _ER(EXIT_READ_DR0, 0x020) \ | ||
| 139 | _ER(EXIT_READ_DR1, 0x021) \ | ||
| 140 | _ER(EXIT_READ_DR2, 0x022) \ | ||
| 141 | _ER(EXIT_READ_DR3, 0x023) \ | ||
| 142 | _ER(EXIT_READ_DR4, 0x024) \ | ||
| 143 | _ER(EXIT_READ_DR5, 0x025) \ | ||
| 144 | _ER(EXIT_READ_DR6, 0x026) \ | ||
| 145 | _ER(EXIT_READ_DR7, 0x027) \ | ||
| 146 | _ER(EXIT_WRITE_DR0, 0x030) \ | ||
| 147 | _ER(EXIT_WRITE_DR1, 0x031) \ | ||
| 148 | _ER(EXIT_WRITE_DR2, 0x032) \ | ||
| 149 | _ER(EXIT_WRITE_DR3, 0x033) \ | ||
| 150 | _ER(EXIT_WRITE_DR4, 0x034) \ | ||
| 151 | _ER(EXIT_WRITE_DR5, 0x035) \ | ||
| 152 | _ER(EXIT_WRITE_DR6, 0x036) \ | ||
| 153 | _ER(EXIT_WRITE_DR7, 0x037) \ | ||
| 154 | _ER(EXIT_EXCP_BASE, 0x040) \ | ||
| 155 | _ER(EXIT_INTR, 0x060) \ | ||
| 156 | _ER(EXIT_NMI, 0x061) \ | ||
| 157 | _ER(EXIT_SMI, 0x062) \ | ||
| 158 | _ER(EXIT_INIT, 0x063) \ | ||
| 159 | _ER(EXIT_VINTR, 0x064) \ | ||
| 160 | _ER(EXIT_CR0_SEL_WRITE, 0x065) \ | ||
| 161 | _ER(EXIT_IDTR_READ, 0x066) \ | ||
| 162 | _ER(EXIT_GDTR_READ, 0x067) \ | ||
| 163 | _ER(EXIT_LDTR_READ, 0x068) \ | ||
| 164 | _ER(EXIT_TR_READ, 0x069) \ | ||
| 165 | _ER(EXIT_IDTR_WRITE, 0x06a) \ | ||
| 166 | _ER(EXIT_GDTR_WRITE, 0x06b) \ | ||
| 167 | _ER(EXIT_LDTR_WRITE, 0x06c) \ | ||
| 168 | _ER(EXIT_TR_WRITE, 0x06d) \ | ||
| 169 | _ER(EXIT_RDTSC, 0x06e) \ | ||
| 170 | _ER(EXIT_RDPMC, 0x06f) \ | ||
| 171 | _ER(EXIT_PUSHF, 0x070) \ | ||
| 172 | _ER(EXIT_POPF, 0x071) \ | ||
| 173 | _ER(EXIT_CPUID, 0x072) \ | ||
| 174 | _ER(EXIT_RSM, 0x073) \ | ||
| 175 | _ER(EXIT_IRET, 0x074) \ | ||
| 176 | _ER(EXIT_SWINT, 0x075) \ | ||
| 177 | _ER(EXIT_INVD, 0x076) \ | ||
| 178 | _ER(EXIT_PAUSE, 0x077) \ | ||
| 179 | _ER(EXIT_HLT, 0x078) \ | ||
| 180 | _ER(EXIT_INVLPG, 0x079) \ | ||
| 181 | _ER(EXIT_INVLPGA, 0x07a) \ | ||
| 182 | _ER(EXIT_IOIO, 0x07b) \ | ||
| 183 | _ER(EXIT_MSR, 0x07c) \ | ||
| 184 | _ER(EXIT_TASK_SWITCH, 0x07d) \ | ||
| 185 | _ER(EXIT_FERR_FREEZE, 0x07e) \ | ||
| 186 | _ER(EXIT_SHUTDOWN, 0x07f) \ | ||
| 187 | _ER(EXIT_VMRUN, 0x080) \ | ||
| 188 | _ER(EXIT_VMMCALL, 0x081) \ | ||
| 189 | _ER(EXIT_VMLOAD, 0x082) \ | ||
| 190 | _ER(EXIT_VMSAVE, 0x083) \ | ||
| 191 | _ER(EXIT_STGI, 0x084) \ | ||
| 192 | _ER(EXIT_CLGI, 0x085) \ | ||
| 193 | _ER(EXIT_SKINIT, 0x086) \ | ||
| 194 | _ER(EXIT_RDTSCP, 0x087) \ | ||
| 195 | _ER(EXIT_ICEBP, 0x088) \ | ||
| 196 | _ER(EXIT_WBINVD, 0x089) \ | ||
| 197 | _ER(EXIT_MONITOR, 0x08a) \ | ||
| 198 | _ER(EXIT_MWAIT, 0x08b) \ | ||
| 199 | _ER(EXIT_MWAIT_COND, 0x08c) \ | ||
| 200 | _ER(EXIT_NPF, 0x400) \ | ||
| 201 | _ER(EXIT_ERR, -1) | ||
| 202 | |||
| 203 | #define _ER(reason, val) { #reason, val }, | ||
| 204 | struct str_values { | ||
| 205 | const char *str; | ||
| 206 | int val; | ||
| 207 | }; | ||
| 208 | |||
| 209 | static struct str_values vmx_exit_reasons[] = { | ||
| 210 | VMX_EXIT_REASONS | ||
| 211 | { NULL, -1} | ||
| 212 | }; | ||
| 213 | |||
| 214 | static struct str_values svm_exit_reasons[] = { | ||
| 215 | SVM_EXIT_REASONS | ||
| 216 | { NULL, -1} | ||
| 217 | }; | ||
| 218 | |||
| 219 | static struct isa_exit_reasons { | ||
| 220 | unsigned isa; | ||
| 221 | struct str_values *strings; | ||
| 222 | } isa_exit_reasons[] = { | ||
| 223 | { .isa = 1, .strings = vmx_exit_reasons }, | ||
| 224 | { .isa = 2, .strings = svm_exit_reasons }, | ||
| 225 | { } | ||
| 226 | }; | ||
| 227 | |||
| 228 | static const char *find_exit_reason(unsigned isa, int val) | ||
| 229 | { | ||
| 230 | struct str_values *strings = NULL; | ||
| 231 | int i; | ||
| 232 | |||
| 233 | for (i = 0; isa_exit_reasons[i].strings; ++i) | ||
| 234 | if (isa_exit_reasons[i].isa == isa) { | ||
| 235 | strings = isa_exit_reasons[i].strings; | ||
| 236 | break; | ||
| 237 | } | ||
| 238 | if (!strings) | ||
| 239 | return "UNKNOWN-ISA"; | ||
| 240 | for (i = 0; strings[i].val >= 0; i++) | ||
| 241 | if (strings[i].val == val) | ||
| 242 | break; | ||
| 243 | if (strings[i].str) | ||
| 244 | return strings[i].str; | ||
| 245 | return "UNKNOWN"; | ||
| 246 | } | ||
| 247 | |||
| 248 | static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record, | ||
| 249 | struct event_format *event, void *context) | ||
| 250 | { | ||
| 251 | unsigned long long isa; | ||
| 252 | unsigned long long val; | ||
| 253 | unsigned long long info1 = 0, info2 = 0; | ||
| 254 | |||
| 255 | if (pevent_get_field_val(s, event, "exit_reason", record, &val, 1) < 0) | ||
| 256 | return -1; | ||
| 257 | |||
| 258 | if (pevent_get_field_val(s, event, "isa", record, &isa, 0) < 0) | ||
| 259 | isa = 1; | ||
| 260 | |||
| 261 | trace_seq_printf(s, "reason %s", find_exit_reason(isa, val)); | ||
| 262 | |||
| 263 | pevent_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1); | ||
| 264 | |||
| 265 | if (pevent_get_field_val(s, event, "info1", record, &info1, 0) >= 0 | ||
| 266 | && pevent_get_field_val(s, event, "info2", record, &info2, 0) >= 0) | ||
| 267 | trace_seq_printf(s, " info %llx %llx", info1, info2); | ||
| 268 | |||
| 269 | return 0; | ||
| 270 | } | ||
| 271 | |||
| 272 | #define KVM_EMUL_INSN_F_CR0_PE (1 << 0) | ||
| 273 | #define KVM_EMUL_INSN_F_EFL_VM (1 << 1) | ||
| 274 | #define KVM_EMUL_INSN_F_CS_D (1 << 2) | ||
| 275 | #define KVM_EMUL_INSN_F_CS_L (1 << 3) | ||
| 276 | |||
| 277 | static int kvm_emulate_insn_handler(struct trace_seq *s, | ||
| 278 | struct pevent_record *record, | ||
| 279 | struct event_format *event, void *context) | ||
| 280 | { | ||
| 281 | unsigned long long rip, csbase, len, flags, failed; | ||
| 282 | int llen; | ||
| 283 | uint8_t *insn; | ||
| 284 | const char *disasm; | ||
| 285 | |||
| 286 | if (pevent_get_field_val(s, event, "rip", record, &rip, 1) < 0) | ||
| 287 | return -1; | ||
| 288 | |||
| 289 | if (pevent_get_field_val(s, event, "csbase", record, &csbase, 1) < 0) | ||
| 290 | return -1; | ||
| 291 | |||
| 292 | if (pevent_get_field_val(s, event, "len", record, &len, 1) < 0) | ||
| 293 | return -1; | ||
| 294 | |||
| 295 | if (pevent_get_field_val(s, event, "flags", record, &flags, 1) < 0) | ||
| 296 | return -1; | ||
| 297 | |||
| 298 | if (pevent_get_field_val(s, event, "failed", record, &failed, 1) < 0) | ||
| 299 | return -1; | ||
| 300 | |||
| 301 | insn = pevent_get_field_raw(s, event, "insn", record, &llen, 1); | ||
| 302 | if (!insn) | ||
| 303 | return -1; | ||
| 304 | |||
| 305 | disasm = disassemble(insn, len, rip, | ||
| 306 | flags & KVM_EMUL_INSN_F_CR0_PE, | ||
| 307 | flags & KVM_EMUL_INSN_F_EFL_VM, | ||
| 308 | flags & KVM_EMUL_INSN_F_CS_D, | ||
| 309 | flags & KVM_EMUL_INSN_F_CS_L); | ||
| 310 | |||
| 311 | trace_seq_printf(s, "%llx:%llx: %s%s", csbase, rip, disasm, | ||
| 312 | failed ? " FAIL" : ""); | ||
| 313 | return 0; | ||
| 314 | } | ||
| 315 | |||
| 316 | union kvm_mmu_page_role { | ||
| 317 | unsigned word; | ||
| 318 | struct { | ||
| 319 | unsigned glevels:4; | ||
| 320 | unsigned level:4; | ||
| 321 | unsigned quadrant:2; | ||
| 322 | unsigned pad_for_nice_hex_output:6; | ||
| 323 | unsigned direct:1; | ||
| 324 | unsigned access:3; | ||
| 325 | unsigned invalid:1; | ||
| 326 | unsigned cr4_pge:1; | ||
| 327 | unsigned nxe:1; | ||
| 328 | }; | ||
| 329 | }; | ||
| 330 | |||
| 331 | static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record, | ||
| 332 | struct event_format *event, void *context) | ||
| 333 | { | ||
| 334 | unsigned long long val; | ||
| 335 | static const char *access_str[] = { | ||
| 336 | "---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux" | ||
| 337 | }; | ||
| 338 | union kvm_mmu_page_role role; | ||
| 339 | |||
| 340 | if (pevent_get_field_val(s, event, "role", record, &val, 1) < 0) | ||
| 341 | return -1; | ||
| 342 | |||
| 343 | role.word = (int)val; | ||
| 344 | |||
| 345 | /* | ||
| 346 | * We can only use the structure if file is of the same | ||
| 347 | * endianess. | ||
| 348 | */ | ||
| 349 | if (pevent_is_file_bigendian(event->pevent) == | ||
| 350 | pevent_is_host_bigendian(event->pevent)) { | ||
| 351 | |||
| 352 | trace_seq_printf(s, "%u/%u q%u%s %s%s %spge %snxe", | ||
| 353 | role.level, | ||
| 354 | role.glevels, | ||
| 355 | role.quadrant, | ||
| 356 | role.direct ? " direct" : "", | ||
| 357 | access_str[role.access], | ||
| 358 | role.invalid ? " invalid" : "", | ||
| 359 | role.cr4_pge ? "" : "!", | ||
| 360 | role.nxe ? "" : "!"); | ||
| 361 | } else | ||
| 362 | trace_seq_printf(s, "WORD: %08x", role.word); | ||
| 363 | |||
| 364 | pevent_print_num_field(s, " root %u ", event, | ||
| 365 | "root_count", record, 1); | ||
| 366 | |||
| 367 | if (pevent_get_field_val(s, event, "unsync", record, &val, 1) < 0) | ||
| 368 | return -1; | ||
| 369 | |||
| 370 | trace_seq_printf(s, "%s%c", val ? "unsync" : "sync", 0); | ||
| 371 | return 0; | ||
| 372 | } | ||
| 373 | |||
| 374 | static int kvm_mmu_get_page_handler(struct trace_seq *s, | ||
| 375 | struct pevent_record *record, | ||
| 376 | struct event_format *event, void *context) | ||
| 377 | { | ||
| 378 | unsigned long long val; | ||
| 379 | |||
| 380 | if (pevent_get_field_val(s, event, "created", record, &val, 1) < 0) | ||
| 381 | return -1; | ||
| 382 | |||
| 383 | trace_seq_printf(s, "%s ", val ? "new" : "existing"); | ||
| 384 | |||
| 385 | if (pevent_get_field_val(s, event, "gfn", record, &val, 1) < 0) | ||
| 386 | return -1; | ||
| 387 | |||
| 388 | trace_seq_printf(s, "sp gfn %llx ", val); | ||
| 389 | return kvm_mmu_print_role(s, record, event, context); | ||
| 390 | } | ||
| 391 | |||
| 392 | #define PT_WRITABLE_SHIFT 1 | ||
| 393 | #define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT) | ||
| 394 | |||
| 395 | static unsigned long long | ||
| 396 | process_is_writable_pte(struct trace_seq *s, unsigned long long *args) | ||
| 397 | { | ||
| 398 | unsigned long pte = args[0]; | ||
| 399 | return pte & PT_WRITABLE_MASK; | ||
| 400 | } | ||
| 401 | |||
| 402 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 403 | { | ||
| 404 | init_disassembler(); | ||
| 405 | |||
| 406 | pevent_register_event_handler(pevent, -1, "kvm", "kvm_exit", | ||
| 407 | kvm_exit_handler, NULL); | ||
| 408 | |||
| 409 | pevent_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", | ||
| 410 | kvm_emulate_insn_handler, NULL); | ||
| 411 | |||
| 412 | pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", | ||
| 413 | kvm_mmu_get_page_handler, NULL); | ||
| 414 | |||
| 415 | pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page", | ||
| 416 | kvm_mmu_print_role, NULL); | ||
| 417 | |||
| 418 | pevent_register_event_handler(pevent, -1, | ||
| 419 | "kvmmmu", "kvm_mmu_unsync_page", | ||
| 420 | kvm_mmu_print_role, NULL); | ||
| 421 | |||
| 422 | pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page", | ||
| 423 | kvm_mmu_print_role, NULL); | ||
| 424 | |||
| 425 | pevent_register_event_handler(pevent, -1, "kvmmmu", | ||
| 426 | "kvm_mmu_prepare_zap_page", kvm_mmu_print_role, | ||
| 427 | NULL); | ||
| 428 | |||
| 429 | pevent_register_print_function(pevent, | ||
| 430 | process_is_writable_pte, | ||
| 431 | PEVENT_FUNC_ARG_INT, | ||
| 432 | "is_writable_pte", | ||
| 433 | PEVENT_FUNC_ARG_LONG, | ||
| 434 | PEVENT_FUNC_ARG_VOID); | ||
| 435 | return 0; | ||
| 436 | } | ||
| 437 | |||
| 438 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
| 439 | { | ||
| 440 | pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_exit", | ||
| 441 | kvm_exit_handler, NULL); | ||
| 442 | |||
| 443 | pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", | ||
| 444 | kvm_emulate_insn_handler, NULL); | ||
| 445 | |||
| 446 | pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", | ||
| 447 | kvm_mmu_get_page_handler, NULL); | ||
| 448 | |||
| 449 | pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page", | ||
| 450 | kvm_mmu_print_role, NULL); | ||
| 451 | |||
| 452 | pevent_unregister_event_handler(pevent, -1, | ||
| 453 | "kvmmmu", "kvm_mmu_unsync_page", | ||
| 454 | kvm_mmu_print_role, NULL); | ||
| 455 | |||
| 456 | pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page", | ||
| 457 | kvm_mmu_print_role, NULL); | ||
| 458 | |||
| 459 | pevent_unregister_event_handler(pevent, -1, "kvmmmu", | ||
| 460 | "kvm_mmu_prepare_zap_page", kvm_mmu_print_role, | ||
| 461 | NULL); | ||
| 462 | |||
| 463 | pevent_unregister_print_function(pevent, process_is_writable_pte, | ||
| 464 | "is_writable_pte"); | ||
| 465 | } | ||
diff --git a/tools/lib/traceevent/plugin_mac80211.c b/tools/lib/traceevent/plugin_mac80211.c new file mode 100644 index 000000000000..7e15a0f1c2fd --- /dev/null +++ b/tools/lib/traceevent/plugin_mac80211.c | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009 Johannes Berg <johannes@sipsolutions.net> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; | ||
| 8 | * version 2.1 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
| 17 | * | ||
| 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 19 | */ | ||
| 20 | #include <stdio.h> | ||
| 21 | #include <stdlib.h> | ||
| 22 | #include <string.h> | ||
| 23 | |||
| 24 | #include "event-parse.h" | ||
| 25 | |||
| 26 | #define INDENT 65 | ||
| 27 | |||
| 28 | static void print_string(struct trace_seq *s, struct event_format *event, | ||
| 29 | const char *name, const void *data) | ||
| 30 | { | ||
| 31 | struct format_field *f = pevent_find_field(event, name); | ||
| 32 | int offset; | ||
| 33 | int length; | ||
| 34 | |||
| 35 | if (!f) { | ||
| 36 | trace_seq_printf(s, "NOTFOUND:%s", name); | ||
| 37 | return; | ||
| 38 | } | ||
| 39 | |||
| 40 | offset = f->offset; | ||
| 41 | length = f->size; | ||
| 42 | |||
| 43 | if (!strncmp(f->type, "__data_loc", 10)) { | ||
| 44 | unsigned long long v; | ||
| 45 | if (pevent_read_number_field(f, data, &v)) { | ||
| 46 | trace_seq_printf(s, "invalid_data_loc"); | ||
| 47 | return; | ||
| 48 | } | ||
| 49 | offset = v & 0xffff; | ||
| 50 | length = v >> 16; | ||
| 51 | } | ||
| 52 | |||
| 53 | trace_seq_printf(s, "%.*s", length, (char *)data + offset); | ||
| 54 | } | ||
| 55 | |||
| 56 | #define SF(fn) pevent_print_num_field(s, fn ":%d", event, fn, record, 0) | ||
| 57 | #define SFX(fn) pevent_print_num_field(s, fn ":%#x", event, fn, record, 0) | ||
| 58 | #define SP() trace_seq_putc(s, ' ') | ||
| 59 | |||
| 60 | static int drv_bss_info_changed(struct trace_seq *s, | ||
| 61 | struct pevent_record *record, | ||
| 62 | struct event_format *event, void *context) | ||
| 63 | { | ||
| 64 | void *data = record->data; | ||
| 65 | |||
| 66 | print_string(s, event, "wiphy_name", data); | ||
| 67 | trace_seq_printf(s, " vif:"); | ||
| 68 | print_string(s, event, "vif_name", data); | ||
| 69 | pevent_print_num_field(s, "(%d)", event, "vif_type", record, 1); | ||
| 70 | |||
| 71 | trace_seq_printf(s, "\n%*s", INDENT, ""); | ||
| 72 | SF("assoc"); SP(); | ||
| 73 | SF("aid"); SP(); | ||
| 74 | SF("cts"); SP(); | ||
| 75 | SF("shortpre"); SP(); | ||
| 76 | SF("shortslot"); SP(); | ||
| 77 | SF("dtimper"); SP(); | ||
| 78 | trace_seq_printf(s, "\n%*s", INDENT, ""); | ||
| 79 | SF("bcnint"); SP(); | ||
| 80 | SFX("assoc_cap"); SP(); | ||
| 81 | SFX("basic_rates"); SP(); | ||
| 82 | SF("enable_beacon"); | ||
| 83 | trace_seq_printf(s, "\n%*s", INDENT, ""); | ||
| 84 | SF("ht_operation_mode"); | ||
| 85 | |||
| 86 | return 0; | ||
| 87 | } | ||
| 88 | |||
| 89 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 90 | { | ||
| 91 | pevent_register_event_handler(pevent, -1, "mac80211", | ||
| 92 | "drv_bss_info_changed", | ||
| 93 | drv_bss_info_changed, NULL); | ||
| 94 | return 0; | ||
| 95 | } | ||
| 96 | |||
| 97 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
| 98 | { | ||
| 99 | pevent_unregister_event_handler(pevent, -1, "mac80211", | ||
| 100 | "drv_bss_info_changed", | ||
| 101 | drv_bss_info_changed, NULL); | ||
| 102 | } | ||
diff --git a/tools/lib/traceevent/plugin_sched_switch.c b/tools/lib/traceevent/plugin_sched_switch.c new file mode 100644 index 000000000000..f1ce60065258 --- /dev/null +++ b/tools/lib/traceevent/plugin_sched_switch.c | |||
| @@ -0,0 +1,160 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; | ||
| 8 | * version 2.1 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
| 17 | * | ||
| 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 19 | */ | ||
| 20 | #include <stdio.h> | ||
| 21 | #include <stdlib.h> | ||
| 22 | #include <string.h> | ||
| 23 | |||
| 24 | #include "event-parse.h" | ||
| 25 | |||
| 26 | static void write_state(struct trace_seq *s, int val) | ||
| 27 | { | ||
| 28 | const char states[] = "SDTtZXxW"; | ||
| 29 | int found = 0; | ||
| 30 | int i; | ||
| 31 | |||
| 32 | for (i = 0; i < (sizeof(states) - 1); i++) { | ||
| 33 | if (!(val & (1 << i))) | ||
| 34 | continue; | ||
| 35 | |||
| 36 | if (found) | ||
| 37 | trace_seq_putc(s, '|'); | ||
| 38 | |||
| 39 | found = 1; | ||
| 40 | trace_seq_putc(s, states[i]); | ||
| 41 | } | ||
| 42 | |||
| 43 | if (!found) | ||
| 44 | trace_seq_putc(s, 'R'); | ||
| 45 | } | ||
| 46 | |||
| 47 | static void write_and_save_comm(struct format_field *field, | ||
| 48 | struct pevent_record *record, | ||
| 49 | struct trace_seq *s, int pid) | ||
| 50 | { | ||
| 51 | const char *comm; | ||
| 52 | int len; | ||
| 53 | |||
| 54 | comm = (char *)(record->data + field->offset); | ||
| 55 | len = s->len; | ||
| 56 | trace_seq_printf(s, "%.*s", | ||
| 57 | field->size, comm); | ||
| 58 | |||
| 59 | /* make sure the comm has a \0 at the end. */ | ||
| 60 | trace_seq_terminate(s); | ||
| 61 | comm = &s->buffer[len]; | ||
| 62 | |||
| 63 | /* Help out the comm to ids. This will handle dups */ | ||
| 64 | pevent_register_comm(field->event->pevent, comm, pid); | ||
| 65 | } | ||
| 66 | |||
| 67 | static int sched_wakeup_handler(struct trace_seq *s, | ||
| 68 | struct pevent_record *record, | ||
| 69 | struct event_format *event, void *context) | ||
| 70 | { | ||
| 71 | struct format_field *field; | ||
| 72 | unsigned long long val; | ||
| 73 | |||
| 74 | if (pevent_get_field_val(s, event, "pid", record, &val, 1)) | ||
| 75 | return trace_seq_putc(s, '!'); | ||
| 76 | |||
| 77 | field = pevent_find_any_field(event, "comm"); | ||
| 78 | if (field) { | ||
| 79 | write_and_save_comm(field, record, s, val); | ||
| 80 | trace_seq_putc(s, ':'); | ||
| 81 | } | ||
| 82 | trace_seq_printf(s, "%lld", val); | ||
| 83 | |||
| 84 | if (pevent_get_field_val(s, event, "prio", record, &val, 0) == 0) | ||
| 85 | trace_seq_printf(s, " [%lld]", val); | ||
| 86 | |||
| 87 | if (pevent_get_field_val(s, event, "success", record, &val, 1) == 0) | ||
| 88 | trace_seq_printf(s, " success=%lld", val); | ||
| 89 | |||
| 90 | if (pevent_get_field_val(s, event, "target_cpu", record, &val, 0) == 0) | ||
| 91 | trace_seq_printf(s, " CPU:%03llu", val); | ||
| 92 | |||
| 93 | return 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | static int sched_switch_handler(struct trace_seq *s, | ||
| 97 | struct pevent_record *record, | ||
| 98 | struct event_format *event, void *context) | ||
| 99 | { | ||
| 100 | struct format_field *field; | ||
| 101 | unsigned long long val; | ||
| 102 | |||
| 103 | if (pevent_get_field_val(s, event, "prev_pid", record, &val, 1)) | ||
| 104 | return trace_seq_putc(s, '!'); | ||
| 105 | |||
| 106 | field = pevent_find_any_field(event, "prev_comm"); | ||
| 107 | if (field) { | ||
| 108 | write_and_save_comm(field, record, s, val); | ||
| 109 | trace_seq_putc(s, ':'); | ||
| 110 | } | ||
| 111 | trace_seq_printf(s, "%lld ", val); | ||
| 112 | |||
| 113 | if (pevent_get_field_val(s, event, "prev_prio", record, &val, 0) == 0) | ||
| 114 | trace_seq_printf(s, "[%lld] ", val); | ||
| 115 | |||
| 116 | if (pevent_get_field_val(s, event, "prev_state", record, &val, 0) == 0) | ||
| 117 | write_state(s, val); | ||
| 118 | |||
| 119 | trace_seq_puts(s, " ==> "); | ||
| 120 | |||
| 121 | if (pevent_get_field_val(s, event, "next_pid", record, &val, 1)) | ||
| 122 | return trace_seq_putc(s, '!'); | ||
| 123 | |||
| 124 | field = pevent_find_any_field(event, "next_comm"); | ||
| 125 | if (field) { | ||
| 126 | write_and_save_comm(field, record, s, val); | ||
| 127 | trace_seq_putc(s, ':'); | ||
| 128 | } | ||
| 129 | trace_seq_printf(s, "%lld", val); | ||
| 130 | |||
| 131 | if (pevent_get_field_val(s, event, "next_prio", record, &val, 0) == 0) | ||
| 132 | trace_seq_printf(s, " [%lld]", val); | ||
| 133 | |||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 138 | { | ||
| 139 | pevent_register_event_handler(pevent, -1, "sched", "sched_switch", | ||
| 140 | sched_switch_handler, NULL); | ||
| 141 | |||
| 142 | pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup", | ||
| 143 | sched_wakeup_handler, NULL); | ||
| 144 | |||
| 145 | pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup_new", | ||
| 146 | sched_wakeup_handler, NULL); | ||
| 147 | return 0; | ||
| 148 | } | ||
| 149 | |||
| 150 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
| 151 | { | ||
| 152 | pevent_unregister_event_handler(pevent, -1, "sched", "sched_switch", | ||
| 153 | sched_switch_handler, NULL); | ||
| 154 | |||
| 155 | pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup", | ||
| 156 | sched_wakeup_handler, NULL); | ||
| 157 | |||
| 158 | pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup_new", | ||
| 159 | sched_wakeup_handler, NULL); | ||
| 160 | } | ||
diff --git a/tools/lib/traceevent/plugin_scsi.c b/tools/lib/traceevent/plugin_scsi.c new file mode 100644 index 000000000000..eda326fc8620 --- /dev/null +++ b/tools/lib/traceevent/plugin_scsi.c | |||
| @@ -0,0 +1,429 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <string.h> | ||
| 3 | #include <inttypes.h> | ||
| 4 | #include "event-parse.h" | ||
| 5 | |||
| 6 | typedef unsigned long sector_t; | ||
| 7 | typedef uint64_t u64; | ||
| 8 | typedef unsigned int u32; | ||
| 9 | |||
| 10 | /* | ||
| 11 | * SCSI opcodes | ||
| 12 | */ | ||
| 13 | #define TEST_UNIT_READY 0x00 | ||
| 14 | #define REZERO_UNIT 0x01 | ||
| 15 | #define REQUEST_SENSE 0x03 | ||
| 16 | #define FORMAT_UNIT 0x04 | ||
| 17 | #define READ_BLOCK_LIMITS 0x05 | ||
| 18 | #define REASSIGN_BLOCKS 0x07 | ||
| 19 | #define INITIALIZE_ELEMENT_STATUS 0x07 | ||
| 20 | #define READ_6 0x08 | ||
| 21 | #define WRITE_6 0x0a | ||
| 22 | #define SEEK_6 0x0b | ||
| 23 | #define READ_REVERSE 0x0f | ||
| 24 | #define WRITE_FILEMARKS 0x10 | ||
| 25 | #define SPACE 0x11 | ||
| 26 | #define INQUIRY 0x12 | ||
| 27 | #define RECOVER_BUFFERED_DATA 0x14 | ||
| 28 | #define MODE_SELECT 0x15 | ||
| 29 | #define RESERVE 0x16 | ||
| 30 | #define RELEASE 0x17 | ||
| 31 | #define COPY 0x18 | ||
| 32 | #define ERASE 0x19 | ||
| 33 | #define MODE_SENSE 0x1a | ||
| 34 | #define START_STOP 0x1b | ||
| 35 | #define RECEIVE_DIAGNOSTIC 0x1c | ||
| 36 | #define SEND_DIAGNOSTIC 0x1d | ||
| 37 | #define ALLOW_MEDIUM_REMOVAL 0x1e | ||
| 38 | |||
| 39 | #define READ_FORMAT_CAPACITIES 0x23 | ||
| 40 | #define SET_WINDOW 0x24 | ||
| 41 | #define READ_CAPACITY 0x25 | ||
| 42 | #define READ_10 0x28 | ||
| 43 | #define WRITE_10 0x2a | ||
| 44 | #define SEEK_10 0x2b | ||
| 45 | #define POSITION_TO_ELEMENT 0x2b | ||
| 46 | #define WRITE_VERIFY 0x2e | ||
| 47 | #define VERIFY 0x2f | ||
| 48 | #define SEARCH_HIGH 0x30 | ||
| 49 | #define SEARCH_EQUAL 0x31 | ||
| 50 | #define SEARCH_LOW 0x32 | ||
| 51 | #define SET_LIMITS 0x33 | ||
| 52 | #define PRE_FETCH 0x34 | ||
| 53 | #define READ_POSITION 0x34 | ||
| 54 | #define SYNCHRONIZE_CACHE 0x35 | ||
| 55 | #define LOCK_UNLOCK_CACHE 0x36 | ||
| 56 | #define READ_DEFECT_DATA 0x37 | ||
| 57 | #define MEDIUM_SCAN 0x38 | ||
| 58 | #define COMPARE 0x39 | ||
| 59 | #define COPY_VERIFY 0x3a | ||
| 60 | #define WRITE_BUFFER 0x3b | ||
| 61 | #define READ_BUFFER 0x3c | ||
| 62 | #define UPDATE_BLOCK 0x3d | ||
| 63 | #define READ_LONG 0x3e | ||
| 64 | #define WRITE_LONG 0x3f | ||
| 65 | #define CHANGE_DEFINITION 0x40 | ||
| 66 | #define WRITE_SAME 0x41 | ||
| 67 | #define UNMAP 0x42 | ||
| 68 | #define READ_TOC 0x43 | ||
| 69 | #define READ_HEADER 0x44 | ||
| 70 | #define GET_EVENT_STATUS_NOTIFICATION 0x4a | ||
| 71 | #define LOG_SELECT 0x4c | ||
| 72 | #define LOG_SENSE 0x4d | ||
| 73 | #define XDWRITEREAD_10 0x53 | ||
| 74 | #define MODE_SELECT_10 0x55 | ||
| 75 | #define RESERVE_10 0x56 | ||
| 76 | #define RELEASE_10 0x57 | ||
| 77 | #define MODE_SENSE_10 0x5a | ||
| 78 | #define PERSISTENT_RESERVE_IN 0x5e | ||
| 79 | #define PERSISTENT_RESERVE_OUT 0x5f | ||
| 80 | #define VARIABLE_LENGTH_CMD 0x7f | ||
| 81 | #define REPORT_LUNS 0xa0 | ||
| 82 | #define SECURITY_PROTOCOL_IN 0xa2 | ||
| 83 | #define MAINTENANCE_IN 0xa3 | ||
| 84 | #define MAINTENANCE_OUT 0xa4 | ||
| 85 | #define MOVE_MEDIUM 0xa5 | ||
| 86 | #define EXCHANGE_MEDIUM 0xa6 | ||
| 87 | #define READ_12 0xa8 | ||
| 88 | #define WRITE_12 0xaa | ||
| 89 | #define READ_MEDIA_SERIAL_NUMBER 0xab | ||
| 90 | #define WRITE_VERIFY_12 0xae | ||
| 91 | #define VERIFY_12 0xaf | ||
| 92 | #define SEARCH_HIGH_12 0xb0 | ||
| 93 | #define SEARCH_EQUAL_12 0xb1 | ||
| 94 | #define SEARCH_LOW_12 0xb2 | ||
| 95 | #define SECURITY_PROTOCOL_OUT 0xb5 | ||
| 96 | #define READ_ELEMENT_STATUS 0xb8 | ||
| 97 | #define SEND_VOLUME_TAG 0xb6 | ||
| 98 | #define WRITE_LONG_2 0xea | ||
| 99 | #define EXTENDED_COPY 0x83 | ||
| 100 | #define RECEIVE_COPY_RESULTS 0x84 | ||
| 101 | #define ACCESS_CONTROL_IN 0x86 | ||
| 102 | #define ACCESS_CONTROL_OUT 0x87 | ||
| 103 | #define READ_16 0x88 | ||
| 104 | #define WRITE_16 0x8a | ||
| 105 | #define READ_ATTRIBUTE 0x8c | ||
| 106 | #define WRITE_ATTRIBUTE 0x8d | ||
| 107 | #define VERIFY_16 0x8f | ||
| 108 | #define SYNCHRONIZE_CACHE_16 0x91 | ||
| 109 | #define WRITE_SAME_16 0x93 | ||
| 110 | #define SERVICE_ACTION_IN 0x9e | ||
| 111 | /* values for service action in */ | ||
| 112 | #define SAI_READ_CAPACITY_16 0x10 | ||
| 113 | #define SAI_GET_LBA_STATUS 0x12 | ||
| 114 | /* values for VARIABLE_LENGTH_CMD service action codes | ||
| 115 | * see spc4r17 Section D.3.5, table D.7 and D.8 */ | ||
| 116 | #define VLC_SA_RECEIVE_CREDENTIAL 0x1800 | ||
| 117 | /* values for maintenance in */ | ||
| 118 | #define MI_REPORT_IDENTIFYING_INFORMATION 0x05 | ||
| 119 | #define MI_REPORT_TARGET_PGS 0x0a | ||
| 120 | #define MI_REPORT_ALIASES 0x0b | ||
| 121 | #define MI_REPORT_SUPPORTED_OPERATION_CODES 0x0c | ||
| 122 | #define MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS 0x0d | ||
| 123 | #define MI_REPORT_PRIORITY 0x0e | ||
| 124 | #define MI_REPORT_TIMESTAMP 0x0f | ||
| 125 | #define MI_MANAGEMENT_PROTOCOL_IN 0x10 | ||
| 126 | /* value for MI_REPORT_TARGET_PGS ext header */ | ||
| 127 | #define MI_EXT_HDR_PARAM_FMT 0x20 | ||
| 128 | /* values for maintenance out */ | ||
| 129 | #define MO_SET_IDENTIFYING_INFORMATION 0x06 | ||
| 130 | #define MO_SET_TARGET_PGS 0x0a | ||
| 131 | #define MO_CHANGE_ALIASES 0x0b | ||
| 132 | #define MO_SET_PRIORITY 0x0e | ||
| 133 | #define MO_SET_TIMESTAMP 0x0f | ||
| 134 | #define MO_MANAGEMENT_PROTOCOL_OUT 0x10 | ||
| 135 | /* values for variable length command */ | ||
| 136 | #define XDREAD_32 0x03 | ||
| 137 | #define XDWRITE_32 0x04 | ||
| 138 | #define XPWRITE_32 0x06 | ||
| 139 | #define XDWRITEREAD_32 0x07 | ||
| 140 | #define READ_32 0x09 | ||
| 141 | #define VERIFY_32 0x0a | ||
| 142 | #define WRITE_32 0x0b | ||
| 143 | #define WRITE_SAME_32 0x0d | ||
| 144 | |||
| 145 | #define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f) | ||
| 146 | #define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9]) | ||
| 147 | |||
| 148 | static const char * | ||
| 149 | scsi_trace_misc(struct trace_seq *, unsigned char *, int); | ||
| 150 | |||
| 151 | static const char * | ||
| 152 | scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 153 | { | ||
| 154 | const char *ret = p->buffer + p->len; | ||
| 155 | sector_t lba = 0, txlen = 0; | ||
| 156 | |||
| 157 | lba |= ((cdb[1] & 0x1F) << 16); | ||
| 158 | lba |= (cdb[2] << 8); | ||
| 159 | lba |= cdb[3]; | ||
| 160 | txlen = cdb[4]; | ||
| 161 | |||
| 162 | trace_seq_printf(p, "lba=%llu txlen=%llu", | ||
| 163 | (unsigned long long)lba, (unsigned long long)txlen); | ||
| 164 | trace_seq_putc(p, 0); | ||
| 165 | return ret; | ||
| 166 | } | ||
| 167 | |||
| 168 | static const char * | ||
| 169 | scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 170 | { | ||
| 171 | const char *ret = p->buffer + p->len; | ||
| 172 | sector_t lba = 0, txlen = 0; | ||
| 173 | |||
| 174 | lba |= (cdb[2] << 24); | ||
| 175 | lba |= (cdb[3] << 16); | ||
| 176 | lba |= (cdb[4] << 8); | ||
| 177 | lba |= cdb[5]; | ||
| 178 | txlen |= (cdb[7] << 8); | ||
| 179 | txlen |= cdb[8]; | ||
| 180 | |||
| 181 | trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", | ||
| 182 | (unsigned long long)lba, (unsigned long long)txlen, | ||
| 183 | cdb[1] >> 5); | ||
| 184 | |||
| 185 | if (cdb[0] == WRITE_SAME) | ||
| 186 | trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1); | ||
| 187 | |||
| 188 | trace_seq_putc(p, 0); | ||
| 189 | return ret; | ||
| 190 | } | ||
| 191 | |||
| 192 | static const char * | ||
| 193 | scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 194 | { | ||
| 195 | const char *ret = p->buffer + p->len; | ||
| 196 | sector_t lba = 0, txlen = 0; | ||
| 197 | |||
| 198 | lba |= (cdb[2] << 24); | ||
| 199 | lba |= (cdb[3] << 16); | ||
| 200 | lba |= (cdb[4] << 8); | ||
| 201 | lba |= cdb[5]; | ||
| 202 | txlen |= (cdb[6] << 24); | ||
| 203 | txlen |= (cdb[7] << 16); | ||
| 204 | txlen |= (cdb[8] << 8); | ||
| 205 | txlen |= cdb[9]; | ||
| 206 | |||
| 207 | trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", | ||
| 208 | (unsigned long long)lba, (unsigned long long)txlen, | ||
| 209 | cdb[1] >> 5); | ||
| 210 | trace_seq_putc(p, 0); | ||
| 211 | return ret; | ||
| 212 | } | ||
| 213 | |||
| 214 | static const char * | ||
| 215 | scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 216 | { | ||
| 217 | const char *ret = p->buffer + p->len; | ||
| 218 | sector_t lba = 0, txlen = 0; | ||
| 219 | |||
| 220 | lba |= ((u64)cdb[2] << 56); | ||
| 221 | lba |= ((u64)cdb[3] << 48); | ||
| 222 | lba |= ((u64)cdb[4] << 40); | ||
| 223 | lba |= ((u64)cdb[5] << 32); | ||
| 224 | lba |= (cdb[6] << 24); | ||
| 225 | lba |= (cdb[7] << 16); | ||
| 226 | lba |= (cdb[8] << 8); | ||
| 227 | lba |= cdb[9]; | ||
| 228 | txlen |= (cdb[10] << 24); | ||
| 229 | txlen |= (cdb[11] << 16); | ||
| 230 | txlen |= (cdb[12] << 8); | ||
| 231 | txlen |= cdb[13]; | ||
| 232 | |||
| 233 | trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", | ||
| 234 | (unsigned long long)lba, (unsigned long long)txlen, | ||
| 235 | cdb[1] >> 5); | ||
| 236 | |||
| 237 | if (cdb[0] == WRITE_SAME_16) | ||
| 238 | trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1); | ||
| 239 | |||
| 240 | trace_seq_putc(p, 0); | ||
| 241 | return ret; | ||
| 242 | } | ||
| 243 | |||
| 244 | static const char * | ||
| 245 | scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 246 | { | ||
| 247 | const char *ret = p->buffer + p->len, *cmd; | ||
| 248 | sector_t lba = 0, txlen = 0; | ||
| 249 | u32 ei_lbrt = 0; | ||
| 250 | |||
| 251 | switch (SERVICE_ACTION32(cdb)) { | ||
| 252 | case READ_32: | ||
| 253 | cmd = "READ"; | ||
| 254 | break; | ||
| 255 | case VERIFY_32: | ||
| 256 | cmd = "VERIFY"; | ||
| 257 | break; | ||
| 258 | case WRITE_32: | ||
| 259 | cmd = "WRITE"; | ||
| 260 | break; | ||
| 261 | case WRITE_SAME_32: | ||
| 262 | cmd = "WRITE_SAME"; | ||
| 263 | break; | ||
| 264 | default: | ||
| 265 | trace_seq_printf(p, "UNKNOWN"); | ||
| 266 | goto out; | ||
| 267 | } | ||
| 268 | |||
| 269 | lba |= ((u64)cdb[12] << 56); | ||
| 270 | lba |= ((u64)cdb[13] << 48); | ||
| 271 | lba |= ((u64)cdb[14] << 40); | ||
| 272 | lba |= ((u64)cdb[15] << 32); | ||
| 273 | lba |= (cdb[16] << 24); | ||
| 274 | lba |= (cdb[17] << 16); | ||
| 275 | lba |= (cdb[18] << 8); | ||
| 276 | lba |= cdb[19]; | ||
| 277 | ei_lbrt |= (cdb[20] << 24); | ||
| 278 | ei_lbrt |= (cdb[21] << 16); | ||
| 279 | ei_lbrt |= (cdb[22] << 8); | ||
| 280 | ei_lbrt |= cdb[23]; | ||
| 281 | txlen |= (cdb[28] << 24); | ||
| 282 | txlen |= (cdb[29] << 16); | ||
| 283 | txlen |= (cdb[30] << 8); | ||
| 284 | txlen |= cdb[31]; | ||
| 285 | |||
| 286 | trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u", | ||
| 287 | cmd, (unsigned long long)lba, | ||
| 288 | (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt); | ||
| 289 | |||
| 290 | if (SERVICE_ACTION32(cdb) == WRITE_SAME_32) | ||
| 291 | trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1); | ||
| 292 | |||
| 293 | out: | ||
| 294 | trace_seq_putc(p, 0); | ||
| 295 | return ret; | ||
| 296 | } | ||
| 297 | |||
| 298 | static const char * | ||
| 299 | scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 300 | { | ||
| 301 | const char *ret = p->buffer + p->len; | ||
| 302 | unsigned int regions = cdb[7] << 8 | cdb[8]; | ||
| 303 | |||
| 304 | trace_seq_printf(p, "regions=%u", (regions - 8) / 16); | ||
| 305 | trace_seq_putc(p, 0); | ||
| 306 | return ret; | ||
| 307 | } | ||
| 308 | |||
| 309 | static const char * | ||
| 310 | scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 311 | { | ||
| 312 | const char *ret = p->buffer + p->len, *cmd; | ||
| 313 | sector_t lba = 0; | ||
| 314 | u32 alloc_len = 0; | ||
| 315 | |||
| 316 | switch (SERVICE_ACTION16(cdb)) { | ||
| 317 | case SAI_READ_CAPACITY_16: | ||
| 318 | cmd = "READ_CAPACITY_16"; | ||
| 319 | break; | ||
| 320 | case SAI_GET_LBA_STATUS: | ||
| 321 | cmd = "GET_LBA_STATUS"; | ||
| 322 | break; | ||
| 323 | default: | ||
| 324 | trace_seq_printf(p, "UNKNOWN"); | ||
| 325 | goto out; | ||
| 326 | } | ||
| 327 | |||
| 328 | lba |= ((u64)cdb[2] << 56); | ||
| 329 | lba |= ((u64)cdb[3] << 48); | ||
| 330 | lba |= ((u64)cdb[4] << 40); | ||
| 331 | lba |= ((u64)cdb[5] << 32); | ||
| 332 | lba |= (cdb[6] << 24); | ||
| 333 | lba |= (cdb[7] << 16); | ||
| 334 | lba |= (cdb[8] << 8); | ||
| 335 | lba |= cdb[9]; | ||
| 336 | alloc_len |= (cdb[10] << 24); | ||
| 337 | alloc_len |= (cdb[11] << 16); | ||
| 338 | alloc_len |= (cdb[12] << 8); | ||
| 339 | alloc_len |= cdb[13]; | ||
| 340 | |||
| 341 | trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, | ||
| 342 | (unsigned long long)lba, alloc_len); | ||
| 343 | |||
| 344 | out: | ||
| 345 | trace_seq_putc(p, 0); | ||
| 346 | return ret; | ||
| 347 | } | ||
| 348 | |||
| 349 | static const char * | ||
| 350 | scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 351 | { | ||
| 352 | switch (SERVICE_ACTION32(cdb)) { | ||
| 353 | case READ_32: | ||
| 354 | case VERIFY_32: | ||
| 355 | case WRITE_32: | ||
| 356 | case WRITE_SAME_32: | ||
| 357 | return scsi_trace_rw32(p, cdb, len); | ||
| 358 | default: | ||
| 359 | return scsi_trace_misc(p, cdb, len); | ||
| 360 | } | ||
| 361 | } | ||
| 362 | |||
| 363 | static const char * | ||
| 364 | scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 365 | { | ||
| 366 | const char *ret = p->buffer + p->len; | ||
| 367 | |||
| 368 | trace_seq_printf(p, "-"); | ||
| 369 | trace_seq_putc(p, 0); | ||
| 370 | return ret; | ||
| 371 | } | ||
| 372 | |||
| 373 | const char * | ||
| 374 | scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 375 | { | ||
| 376 | switch (cdb[0]) { | ||
| 377 | case READ_6: | ||
| 378 | case WRITE_6: | ||
| 379 | return scsi_trace_rw6(p, cdb, len); | ||
| 380 | case READ_10: | ||
| 381 | case VERIFY: | ||
| 382 | case WRITE_10: | ||
| 383 | case WRITE_SAME: | ||
| 384 | return scsi_trace_rw10(p, cdb, len); | ||
| 385 | case READ_12: | ||
| 386 | case VERIFY_12: | ||
| 387 | case WRITE_12: | ||
| 388 | return scsi_trace_rw12(p, cdb, len); | ||
| 389 | case READ_16: | ||
| 390 | case VERIFY_16: | ||
| 391 | case WRITE_16: | ||
| 392 | case WRITE_SAME_16: | ||
| 393 | return scsi_trace_rw16(p, cdb, len); | ||
| 394 | case UNMAP: | ||
| 395 | return scsi_trace_unmap(p, cdb, len); | ||
| 396 | case SERVICE_ACTION_IN: | ||
| 397 | return scsi_trace_service_action_in(p, cdb, len); | ||
| 398 | case VARIABLE_LENGTH_CMD: | ||
| 399 | return scsi_trace_varlen(p, cdb, len); | ||
| 400 | default: | ||
| 401 | return scsi_trace_misc(p, cdb, len); | ||
| 402 | } | ||
| 403 | } | ||
| 404 | |||
| 405 | unsigned long long process_scsi_trace_parse_cdb(struct trace_seq *s, | ||
| 406 | unsigned long long *args) | ||
| 407 | { | ||
| 408 | scsi_trace_parse_cdb(s, (unsigned char *) (unsigned long) args[1], args[2]); | ||
| 409 | return 0; | ||
| 410 | } | ||
| 411 | |||
| 412 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 413 | { | ||
| 414 | pevent_register_print_function(pevent, | ||
| 415 | process_scsi_trace_parse_cdb, | ||
| 416 | PEVENT_FUNC_ARG_STRING, | ||
| 417 | "scsi_trace_parse_cdb", | ||
| 418 | PEVENT_FUNC_ARG_PTR, | ||
| 419 | PEVENT_FUNC_ARG_PTR, | ||
| 420 | PEVENT_FUNC_ARG_INT, | ||
| 421 | PEVENT_FUNC_ARG_VOID); | ||
| 422 | return 0; | ||
| 423 | } | ||
| 424 | |||
| 425 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
| 426 | { | ||
| 427 | pevent_unregister_print_function(pevent, process_scsi_trace_parse_cdb, | ||
| 428 | "scsi_trace_parse_cdb"); | ||
| 429 | } | ||
diff --git a/tools/lib/traceevent/plugin_xen.c b/tools/lib/traceevent/plugin_xen.c new file mode 100644 index 000000000000..3a413eaada68 --- /dev/null +++ b/tools/lib/traceevent/plugin_xen.c | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <stdlib.h> | ||
| 3 | #include <string.h> | ||
| 4 | #include "event-parse.h" | ||
| 5 | |||
| 6 | #define __HYPERVISOR_set_trap_table 0 | ||
| 7 | #define __HYPERVISOR_mmu_update 1 | ||
| 8 | #define __HYPERVISOR_set_gdt 2 | ||
| 9 | #define __HYPERVISOR_stack_switch 3 | ||
| 10 | #define __HYPERVISOR_set_callbacks 4 | ||
| 11 | #define __HYPERVISOR_fpu_taskswitch 5 | ||
| 12 | #define __HYPERVISOR_sched_op_compat 6 | ||
| 13 | #define __HYPERVISOR_dom0_op 7 | ||
| 14 | #define __HYPERVISOR_set_debugreg 8 | ||
| 15 | #define __HYPERVISOR_get_debugreg 9 | ||
| 16 | #define __HYPERVISOR_update_descriptor 10 | ||
| 17 | #define __HYPERVISOR_memory_op 12 | ||
| 18 | #define __HYPERVISOR_multicall 13 | ||
| 19 | #define __HYPERVISOR_update_va_mapping 14 | ||
| 20 | #define __HYPERVISOR_set_timer_op 15 | ||
| 21 | #define __HYPERVISOR_event_channel_op_compat 16 | ||
| 22 | #define __HYPERVISOR_xen_version 17 | ||
| 23 | #define __HYPERVISOR_console_io 18 | ||
| 24 | #define __HYPERVISOR_physdev_op_compat 19 | ||
| 25 | #define __HYPERVISOR_grant_table_op 20 | ||
| 26 | #define __HYPERVISOR_vm_assist 21 | ||
| 27 | #define __HYPERVISOR_update_va_mapping_otherdomain 22 | ||
| 28 | #define __HYPERVISOR_iret 23 /* x86 only */ | ||
| 29 | #define __HYPERVISOR_vcpu_op 24 | ||
| 30 | #define __HYPERVISOR_set_segment_base 25 /* x86/64 only */ | ||
| 31 | #define __HYPERVISOR_mmuext_op 26 | ||
| 32 | #define __HYPERVISOR_acm_op 27 | ||
| 33 | #define __HYPERVISOR_nmi_op 28 | ||
| 34 | #define __HYPERVISOR_sched_op 29 | ||
| 35 | #define __HYPERVISOR_callback_op 30 | ||
| 36 | #define __HYPERVISOR_xenoprof_op 31 | ||
| 37 | #define __HYPERVISOR_event_channel_op 32 | ||
| 38 | #define __HYPERVISOR_physdev_op 33 | ||
| 39 | #define __HYPERVISOR_hvm_op 34 | ||
| 40 | #define __HYPERVISOR_tmem_op 38 | ||
| 41 | |||
| 42 | /* Architecture-specific hypercall definitions. */ | ||
| 43 | #define __HYPERVISOR_arch_0 48 | ||
| 44 | #define __HYPERVISOR_arch_1 49 | ||
| 45 | #define __HYPERVISOR_arch_2 50 | ||
| 46 | #define __HYPERVISOR_arch_3 51 | ||
| 47 | #define __HYPERVISOR_arch_4 52 | ||
| 48 | #define __HYPERVISOR_arch_5 53 | ||
| 49 | #define __HYPERVISOR_arch_6 54 | ||
| 50 | #define __HYPERVISOR_arch_7 55 | ||
| 51 | |||
| 52 | #define N(x) [__HYPERVISOR_##x] = "("#x")" | ||
| 53 | static const char *xen_hypercall_names[] = { | ||
| 54 | N(set_trap_table), | ||
| 55 | N(mmu_update), | ||
| 56 | N(set_gdt), | ||
| 57 | N(stack_switch), | ||
| 58 | N(set_callbacks), | ||
| 59 | N(fpu_taskswitch), | ||
| 60 | N(sched_op_compat), | ||
| 61 | N(dom0_op), | ||
| 62 | N(set_debugreg), | ||
| 63 | N(get_debugreg), | ||
| 64 | N(update_descriptor), | ||
| 65 | N(memory_op), | ||
| 66 | N(multicall), | ||
| 67 | N(update_va_mapping), | ||
| 68 | N(set_timer_op), | ||
| 69 | N(event_channel_op_compat), | ||
| 70 | N(xen_version), | ||
| 71 | N(console_io), | ||
| 72 | N(physdev_op_compat), | ||
| 73 | N(grant_table_op), | ||
| 74 | N(vm_assist), | ||
| 75 | N(update_va_mapping_otherdomain), | ||
| 76 | N(iret), | ||
| 77 | N(vcpu_op), | ||
| 78 | N(set_segment_base), | ||
| 79 | N(mmuext_op), | ||
| 80 | N(acm_op), | ||
| 81 | N(nmi_op), | ||
| 82 | N(sched_op), | ||
| 83 | N(callback_op), | ||
| 84 | N(xenoprof_op), | ||
| 85 | N(event_channel_op), | ||
| 86 | N(physdev_op), | ||
| 87 | N(hvm_op), | ||
| 88 | |||
| 89 | /* Architecture-specific hypercall definitions. */ | ||
| 90 | N(arch_0), | ||
| 91 | N(arch_1), | ||
| 92 | N(arch_2), | ||
| 93 | N(arch_3), | ||
| 94 | N(arch_4), | ||
| 95 | N(arch_5), | ||
| 96 | N(arch_6), | ||
| 97 | N(arch_7), | ||
| 98 | }; | ||
| 99 | #undef N | ||
| 100 | |||
| 101 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | ||
| 102 | |||
| 103 | static const char *xen_hypercall_name(unsigned op) | ||
| 104 | { | ||
| 105 | if (op < ARRAY_SIZE(xen_hypercall_names) && | ||
| 106 | xen_hypercall_names[op] != NULL) | ||
| 107 | return xen_hypercall_names[op]; | ||
| 108 | |||
| 109 | return ""; | ||
| 110 | } | ||
| 111 | |||
| 112 | unsigned long long process_xen_hypercall_name(struct trace_seq *s, | ||
| 113 | unsigned long long *args) | ||
| 114 | { | ||
| 115 | unsigned int op = args[0]; | ||
| 116 | |||
| 117 | trace_seq_printf(s, "%s", xen_hypercall_name(op)); | ||
| 118 | return 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 122 | { | ||
| 123 | pevent_register_print_function(pevent, | ||
| 124 | process_xen_hypercall_name, | ||
| 125 | PEVENT_FUNC_ARG_STRING, | ||
| 126 | "xen_hypercall_name", | ||
| 127 | PEVENT_FUNC_ARG_INT, | ||
| 128 | PEVENT_FUNC_ARG_VOID); | ||
| 129 | return 0; | ||
| 130 | } | ||
| 131 | |||
| 132 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
| 133 | { | ||
| 134 | pevent_unregister_print_function(pevent, process_xen_hypercall_name, | ||
| 135 | "xen_hypercall_name"); | ||
| 136 | } | ||
diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c index d7f2e68bc5b9..ec3bd16a5488 100644 --- a/tools/lib/traceevent/trace-seq.c +++ b/tools/lib/traceevent/trace-seq.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <string.h> | 22 | #include <string.h> |
| 23 | #include <stdarg.h> | 23 | #include <stdarg.h> |
| 24 | 24 | ||
| 25 | #include <asm/bug.h> | ||
| 25 | #include "event-parse.h" | 26 | #include "event-parse.h" |
| 26 | #include "event-utils.h" | 27 | #include "event-utils.h" |
| 27 | 28 | ||
| @@ -32,10 +33,21 @@ | |||
| 32 | #define TRACE_SEQ_POISON ((void *)0xdeadbeef) | 33 | #define TRACE_SEQ_POISON ((void *)0xdeadbeef) |
| 33 | #define TRACE_SEQ_CHECK(s) \ | 34 | #define TRACE_SEQ_CHECK(s) \ |
| 34 | do { \ | 35 | do { \ |
| 35 | if ((s)->buffer == TRACE_SEQ_POISON) \ | 36 | if (WARN_ONCE((s)->buffer == TRACE_SEQ_POISON, \ |
| 36 | die("Usage of trace_seq after it was destroyed"); \ | 37 | "Usage of trace_seq after it was destroyed")) \ |
| 38 | (s)->state = TRACE_SEQ__BUFFER_POISONED; \ | ||
| 37 | } while (0) | 39 | } while (0) |
| 38 | 40 | ||
| 41 | #define TRACE_SEQ_CHECK_RET_N(s, n) \ | ||
| 42 | do { \ | ||
| 43 | TRACE_SEQ_CHECK(s); \ | ||
| 44 | if ((s)->state != TRACE_SEQ__GOOD) \ | ||
| 45 | return n; \ | ||
| 46 | } while (0) | ||
| 47 | |||
| 48 | #define TRACE_SEQ_CHECK_RET(s) TRACE_SEQ_CHECK_RET_N(s, ) | ||
| 49 | #define TRACE_SEQ_CHECK_RET0(s) TRACE_SEQ_CHECK_RET_N(s, 0) | ||
| 50 | |||
| 39 | /** | 51 | /** |
| 40 | * trace_seq_init - initialize the trace_seq structure | 52 | * trace_seq_init - initialize the trace_seq structure |
| 41 | * @s: a pointer to the trace_seq structure to initialize | 53 | * @s: a pointer to the trace_seq structure to initialize |
| @@ -45,7 +57,11 @@ void trace_seq_init(struct trace_seq *s) | |||
| 45 | s->len = 0; | 57 | s->len = 0; |
| 46 | s->readpos = 0; | 58 | s->readpos = 0; |
| 47 | s->buffer_size = TRACE_SEQ_BUF_SIZE; | 59 | s->buffer_size = TRACE_SEQ_BUF_SIZE; |
| 48 | s->buffer = malloc_or_die(s->buffer_size); | 60 | s->buffer = malloc(s->buffer_size); |
| 61 | if (s->buffer != NULL) | ||
| 62 | s->state = TRACE_SEQ__GOOD; | ||
| 63 | else | ||
| 64 | s->state = TRACE_SEQ__MEM_ALLOC_FAILED; | ||
| 49 | } | 65 | } |
| 50 | 66 | ||
| 51 | /** | 67 | /** |
| @@ -71,17 +87,23 @@ void trace_seq_destroy(struct trace_seq *s) | |||
| 71 | { | 87 | { |
| 72 | if (!s) | 88 | if (!s) |
| 73 | return; | 89 | return; |
| 74 | TRACE_SEQ_CHECK(s); | 90 | TRACE_SEQ_CHECK_RET(s); |
| 75 | free(s->buffer); | 91 | free(s->buffer); |
| 76 | s->buffer = TRACE_SEQ_POISON; | 92 | s->buffer = TRACE_SEQ_POISON; |
| 77 | } | 93 | } |
| 78 | 94 | ||
| 79 | static void expand_buffer(struct trace_seq *s) | 95 | static void expand_buffer(struct trace_seq *s) |
| 80 | { | 96 | { |
| 97 | char *buf; | ||
| 98 | |||
| 99 | buf = realloc(s->buffer, s->buffer_size + TRACE_SEQ_BUF_SIZE); | ||
| 100 | if (WARN_ONCE(!buf, "Can't allocate trace_seq buffer memory")) { | ||
| 101 | s->state = TRACE_SEQ__MEM_ALLOC_FAILED; | ||
| 102 | return; | ||
| 103 | } | ||
| 104 | |||
| 105 | s->buffer = buf; | ||
| 81 | s->buffer_size += TRACE_SEQ_BUF_SIZE; | 106 | s->buffer_size += TRACE_SEQ_BUF_SIZE; |
| 82 | s->buffer = realloc(s->buffer, s->buffer_size); | ||
| 83 | if (!s->buffer) | ||
| 84 | die("Can't allocate trace_seq buffer memory"); | ||
| 85 | } | 107 | } |
| 86 | 108 | ||
| 87 | /** | 109 | /** |
| @@ -105,9 +127,9 @@ trace_seq_printf(struct trace_seq *s, const char *fmt, ...) | |||
| 105 | int len; | 127 | int len; |
| 106 | int ret; | 128 | int ret; |
| 107 | 129 | ||
| 108 | TRACE_SEQ_CHECK(s); | ||
| 109 | |||
| 110 | try_again: | 130 | try_again: |
| 131 | TRACE_SEQ_CHECK_RET0(s); | ||
| 132 | |||
| 111 | len = (s->buffer_size - 1) - s->len; | 133 | len = (s->buffer_size - 1) - s->len; |
| 112 | 134 | ||
| 113 | va_start(ap, fmt); | 135 | va_start(ap, fmt); |
| @@ -141,9 +163,9 @@ trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args) | |||
| 141 | int len; | 163 | int len; |
| 142 | int ret; | 164 | int ret; |
| 143 | 165 | ||
| 144 | TRACE_SEQ_CHECK(s); | ||
| 145 | |||
| 146 | try_again: | 166 | try_again: |
| 167 | TRACE_SEQ_CHECK_RET0(s); | ||
| 168 | |||
| 147 | len = (s->buffer_size - 1) - s->len; | 169 | len = (s->buffer_size - 1) - s->len; |
| 148 | 170 | ||
| 149 | ret = vsnprintf(s->buffer + s->len, len, fmt, args); | 171 | ret = vsnprintf(s->buffer + s->len, len, fmt, args); |
| @@ -172,13 +194,15 @@ int trace_seq_puts(struct trace_seq *s, const char *str) | |||
| 172 | { | 194 | { |
| 173 | int len; | 195 | int len; |
| 174 | 196 | ||
| 175 | TRACE_SEQ_CHECK(s); | 197 | TRACE_SEQ_CHECK_RET0(s); |
| 176 | 198 | ||
| 177 | len = strlen(str); | 199 | len = strlen(str); |
| 178 | 200 | ||
| 179 | while (len > ((s->buffer_size - 1) - s->len)) | 201 | while (len > ((s->buffer_size - 1) - s->len)) |
| 180 | expand_buffer(s); | 202 | expand_buffer(s); |
| 181 | 203 | ||
| 204 | TRACE_SEQ_CHECK_RET0(s); | ||
| 205 | |||
| 182 | memcpy(s->buffer + s->len, str, len); | 206 | memcpy(s->buffer + s->len, str, len); |
| 183 | s->len += len; | 207 | s->len += len; |
| 184 | 208 | ||
| @@ -187,11 +211,13 @@ int trace_seq_puts(struct trace_seq *s, const char *str) | |||
| 187 | 211 | ||
| 188 | int trace_seq_putc(struct trace_seq *s, unsigned char c) | 212 | int trace_seq_putc(struct trace_seq *s, unsigned char c) |
| 189 | { | 213 | { |
| 190 | TRACE_SEQ_CHECK(s); | 214 | TRACE_SEQ_CHECK_RET0(s); |
| 191 | 215 | ||
| 192 | while (s->len >= (s->buffer_size - 1)) | 216 | while (s->len >= (s->buffer_size - 1)) |
| 193 | expand_buffer(s); | 217 | expand_buffer(s); |
| 194 | 218 | ||
| 219 | TRACE_SEQ_CHECK_RET0(s); | ||
| 220 | |||
| 195 | s->buffer[s->len++] = c; | 221 | s->buffer[s->len++] = c; |
| 196 | 222 | ||
| 197 | return 1; | 223 | return 1; |
| @@ -199,7 +225,7 @@ int trace_seq_putc(struct trace_seq *s, unsigned char c) | |||
| 199 | 225 | ||
| 200 | void trace_seq_terminate(struct trace_seq *s) | 226 | void trace_seq_terminate(struct trace_seq *s) |
| 201 | { | 227 | { |
| 202 | TRACE_SEQ_CHECK(s); | 228 | TRACE_SEQ_CHECK_RET(s); |
| 203 | 229 | ||
| 204 | /* There's always one character left on the buffer */ | 230 | /* There's always one character left on the buffer */ |
| 205 | s->buffer[s->len] = 0; | 231 | s->buffer[s->len] = 0; |
| @@ -208,5 +234,16 @@ void trace_seq_terminate(struct trace_seq *s) | |||
| 208 | int trace_seq_do_printf(struct trace_seq *s) | 234 | int trace_seq_do_printf(struct trace_seq *s) |
| 209 | { | 235 | { |
| 210 | TRACE_SEQ_CHECK(s); | 236 | TRACE_SEQ_CHECK(s); |
| 211 | return printf("%.*s", s->len, s->buffer); | 237 | |
| 238 | switch (s->state) { | ||
| 239 | case TRACE_SEQ__GOOD: | ||
| 240 | return printf("%.*s", s->len, s->buffer); | ||
| 241 | case TRACE_SEQ__BUFFER_POISONED: | ||
| 242 | puts("Usage of trace_seq after it was destroyed"); | ||
| 243 | break; | ||
| 244 | case TRACE_SEQ__MEM_ALLOC_FAILED: | ||
| 245 | puts("Can't allocate trace_seq buffer memory"); | ||
| 246 | break; | ||
| 247 | } | ||
| 248 | return -1; | ||
| 212 | } | 249 | } |
