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 | } |