aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lib
diff options
context:
space:
mode:
Diffstat (limited to 'tools/lib')
-rw-r--r--tools/lib/api/Makefile (renamed from tools/lib/lk/Makefile)18
-rw-r--r--tools/lib/api/fs/debugfs.c (renamed from tools/lib/lk/debugfs.c)0
-rw-r--r--tools/lib/api/fs/debugfs.h (renamed from tools/lib/lk/debugfs.h)6
-rw-r--r--tools/lib/lockdep/Makefile251
-rw-r--r--tools/lib/lockdep/common.c33
-rw-r--r--tools/lib/lockdep/include/liblockdep/common.h50
-rw-r--r--tools/lib/lockdep/include/liblockdep/mutex.h70
-rw-r--r--tools/lib/lockdep/include/liblockdep/rwlock.h86
-rwxr-xr-xtools/lib/lockdep/lockdep3
-rw-r--r--tools/lib/lockdep/lockdep.c2
-rw-r--r--tools/lib/lockdep/lockdep_internals.h1
-rw-r--r--tools/lib/lockdep/lockdep_states.h1
-rw-r--r--tools/lib/lockdep/preload.c447
-rw-r--r--tools/lib/lockdep/rbtree.c1
-rwxr-xr-xtools/lib/lockdep/run_tests.sh27
-rw-r--r--tools/lib/lockdep/tests/AA.c13
-rw-r--r--tools/lib/lockdep/tests/ABBA.c13
-rw-r--r--tools/lib/lockdep/tests/ABBCCA.c15
-rw-r--r--tools/lib/lockdep/tests/ABBCCDDA.c17
-rw-r--r--tools/lib/lockdep/tests/ABCABC.c15
-rw-r--r--tools/lib/lockdep/tests/ABCDBCDA.c17
-rw-r--r--tools/lib/lockdep/tests/ABCDBDDA.c17
-rw-r--r--tools/lib/lockdep/tests/WW.c13
-rw-r--r--tools/lib/lockdep/tests/common.h12
-rw-r--r--tools/lib/lockdep/tests/unlock_balance.c12
-rw-r--r--tools/lib/lockdep/uinclude/asm/hash.h6
-rw-r--r--tools/lib/lockdep/uinclude/asm/hweight.h3
-rw-r--r--tools/lib/lockdep/uinclude/asm/sections.h3
-rw-r--r--tools/lib/lockdep/uinclude/linux/bitops.h3
-rw-r--r--tools/lib/lockdep/uinclude/linux/compiler.h7
-rw-r--r--tools/lib/lockdep/uinclude/linux/debug_locks.h12
-rw-r--r--tools/lib/lockdep/uinclude/linux/delay.h3
-rw-r--r--tools/lib/lockdep/uinclude/linux/export.h7
-rw-r--r--tools/lib/lockdep/uinclude/linux/ftrace.h3
-rw-r--r--tools/lib/lockdep/uinclude/linux/gfp.h3
-rw-r--r--tools/lib/lockdep/uinclude/linux/hardirq.h11
-rw-r--r--tools/lib/lockdep/uinclude/linux/hash.h1
-rw-r--r--tools/lib/lockdep/uinclude/linux/interrupt.h3
-rw-r--r--tools/lib/lockdep/uinclude/linux/irqflags.h38
-rw-r--r--tools/lib/lockdep/uinclude/linux/kallsyms.h32
-rw-r--r--tools/lib/lockdep/uinclude/linux/kern_levels.h25
-rw-r--r--tools/lib/lockdep/uinclude/linux/kernel.h44
-rw-r--r--tools/lib/lockdep/uinclude/linux/kmemcheck.h8
-rw-r--r--tools/lib/lockdep/uinclude/linux/linkage.h3
-rw-r--r--tools/lib/lockdep/uinclude/linux/list.h1
-rw-r--r--tools/lib/lockdep/uinclude/linux/lockdep.h55
-rw-r--r--tools/lib/lockdep/uinclude/linux/module.h6
-rw-r--r--tools/lib/lockdep/uinclude/linux/mutex.h3
-rw-r--r--tools/lib/lockdep/uinclude/linux/poison.h1
-rw-r--r--tools/lib/lockdep/uinclude/linux/prefetch.h6
-rw-r--r--tools/lib/lockdep/uinclude/linux/proc_fs.h3
-rw-r--r--tools/lib/lockdep/uinclude/linux/rbtree.h1
-rw-r--r--tools/lib/lockdep/uinclude/linux/rbtree_augmented.h2
-rw-r--r--tools/lib/lockdep/uinclude/linux/rcu.h21
-rw-r--r--tools/lib/lockdep/uinclude/linux/seq_file.h3
-rw-r--r--tools/lib/lockdep/uinclude/linux/spinlock.h25
-rw-r--r--tools/lib/lockdep/uinclude/linux/stacktrace.h32
-rw-r--r--tools/lib/lockdep/uinclude/linux/stringify.h7
-rw-r--r--tools/lib/lockdep/uinclude/linux/types.h58
-rw-r--r--tools/lib/lockdep/uinclude/trace/events/lock.h3
-rw-r--r--tools/lib/symbol/kallsyms.c58
-rw-r--r--tools/lib/symbol/kallsyms.h24
-rw-r--r--tools/lib/traceevent/Makefile191
-rw-r--r--tools/lib/traceevent/event-parse.c244
-rw-r--r--tools/lib/traceevent/event-parse.h86
-rw-r--r--tools/lib/traceevent/event-plugin.c215
-rw-r--r--tools/lib/traceevent/event-utils.h4
-rw-r--r--tools/lib/traceevent/parse-filter.c673
-rw-r--r--tools/lib/traceevent/parse-utils.c44
-rw-r--r--tools/lib/traceevent/plugin_cfg80211.c30
-rw-r--r--tools/lib/traceevent/plugin_function.c163
-rw-r--r--tools/lib/traceevent/plugin_hrtimer.c88
-rw-r--r--tools/lib/traceevent/plugin_jbd2.c77
-rw-r--r--tools/lib/traceevent/plugin_kmem.c94
-rw-r--r--tools/lib/traceevent/plugin_kvm.c465
-rw-r--r--tools/lib/traceevent/plugin_mac80211.c102
-rw-r--r--tools/lib/traceevent/plugin_sched_switch.c160
-rw-r--r--tools/lib/traceevent/plugin_scsi.c429
-rw-r--r--tools/lib/traceevent/plugin_xen.c136
-rw-r--r--tools/lib/traceevent/trace-seq.c67
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 @@
1include ../../scripts/Makefile.include 1include ../../scripts/Makefile.include
2include ../../perf/config/utilities.mak # QUIET_CLEAN
2 3
3CC = $(CROSS_COMPILE)gcc 4CC = $(CROSS_COMPILE)gcc
4AR = $(CROSS_COMPILE)ar 5AR = $(CROSS_COMPILE)ar
@@ -7,11 +8,11 @@ AR = $(CROSS_COMPILE)ar
7LIB_H= 8LIB_H=
8LIB_OBJS= 9LIB_OBJS=
9 10
10LIB_H += debugfs.h 11LIB_H += fs/debugfs.h
11 12
12LIB_OBJS += $(OUTPUT)debugfs.o 13LIB_OBJS += $(OUTPUT)fs/debugfs.o
13 14
14LIBFILE = liblk.a 15LIBFILE = libapikfs.a
15 16
16CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC 17CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC
17EXTLIBS = -lelf -lpthread -lrt -lm 18EXTLIBS = -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 29libapi_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
35clean: 39clean:
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
27extern char debugfs_mountpoint[]; 27extern 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
2LL_VERSION = 0
3LL_PATCHLEVEL = 0
4LL_EXTRAVERSION = 1
5
6# file format version
7FILE_VERSION = 1
8
9MAKEFLAGS += --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.
17define allow-override
18 $(if $(or $(findstring environment,$(origin $(1))),\
19 $(findstring command line,$(origin $(1)))),,\
20 $(eval $(1) = $(2)))
21endef
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
27INSTALL = 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.
33DESTDIR ?=
34DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))'
35
36prefix ?= /usr/local
37libdir_relative = lib
38libdir = $(prefix)/$(libdir_relative)
39bindir_relative = bin
40bindir = $(prefix)/$(bindir_relative)
41
42export DESTDIR DESTDIR_SQ INSTALL
43
44# copy a bit from Linux kbuild
45
46ifeq ("$(origin V)", "command line")
47 VERBOSE = $(V)
48endif
49ifndef VERBOSE
50 VERBOSE = 0
51endif
52
53ifeq ("$(origin O)", "command line")
54 BUILD_OUTPUT := $(O)
55endif
56
57ifeq ($(BUILD_SRC),)
58ifneq ($(BUILD_OUTPUT),)
59
60define build_output
61 $(if $(VERBOSE:1=),@)$(MAKE) -C $(BUILD_OUTPUT) \
62 BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1
63endef
64
65saved-output := $(BUILD_OUTPUT)
66BUILD_OUTPUT := $(shell cd $(BUILD_OUTPUT) && /bin/pwd)
67$(if $(BUILD_OUTPUT),, \
68 $(error output directory "$(saved-output)" does not exist))
69
70all: sub-make
71
72gui: force
73 $(call build_output, all_cmd)
74
75$(filter-out gui,$(MAKECMDGOALS)): sub-make
76
77sub-make: force
78 $(call build_output, $(MAKECMDGOALS))
79
80
81# Leave processing to above invocation of make
82skip-makefile := 1
83
84endif # BUILD_OUTPUT
85endif # BUILD_SRC
86
87# We process the rest of the Makefile if this is the final invocation of make
88ifeq ($(skip-makefile),)
89
90srctree := $(realpath $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR)))
91objtree := $(realpath $(CURDIR))
92src := $(srctree)
93obj := $(objtree)
94
95export prefix libdir bindir src obj
96
97# Shell quotes
98libdir_SQ = $(subst ','\'',$(libdir))
99bindir_SQ = $(subst ','\'',$(bindir))
100
101LIB_FILE = liblockdep.a liblockdep.so
102BIN_FILE = lockdep
103
104CONFIG_INCLUDES =
105CONFIG_LIBS =
106CONFIG_FLAGS =
107
108OBJ = $@
109N =
110
111export Q VERBOSE
112
113LIBLOCKDEP_VERSION = $(LL_VERSION).$(LL_PATCHLEVEL).$(LL_EXTRAVERSION)
114
115INCLUDES = -I. -I/usr/local/include -I./uinclude -I./include $(CONFIG_INCLUDES)
116
117# Set compile option CFLAGS if not set elsewhere
118CFLAGS ?= -g -DCONFIG_LOCKDEP -DCONFIG_STACKTRACE -DCONFIG_PROVE_LOCKING -DBITS_PER_LONG=__WORDSIZE -DLIBLOCKDEP_VERSION='"$(LIBLOCKDEP_VERSION)"' -rdynamic -O0 -g
119
120override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ)
121
122ifeq ($(VERBOSE),1)
123 Q =
124 print_compile =
125 print_app_build =
126 print_fpic_compile =
127 print_shared_lib_compile =
128 print_install =
129else
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';
137endif
138
139do_fpic_compile = \
140 ($(print_fpic_compile) \
141 $(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@)
142
143do_app_build = \
144 ($(print_app_build) \
145 $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS))
146
147do_compile_shared_library = \
148 ($(print_shared_lib_compile) \
149 $(CC) --shared $^ -o $@ -lpthread -ldl)
150
151do_build_static_lib = \
152 ($(print_static_lib_build) \
153 $(RM) $@; $(AR) rcs $@ $^)
154
155
156define do_compile
157 $(print_compile) \
158 $(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@;
159endef
160
161$(obj)/%.o: $(src)/%.c
162 $(Q)$(call do_compile)
163
164%.o: $(src)/%.c
165 $(Q)$(call do_compile)
166
167PEVENT_LIB_OBJS = common.o lockdep.o preload.o rbtree.o
168
169ALL_OBJS = $(PEVENT_LIB_OBJS)
170
171CMD_TARGETS = $(LIB_FILE)
172
173TARGETS = $(CMD_TARGETS)
174
175
176all: all_cmd
177
178all_cmd: $(CMD_TARGETS)
179
180liblockdep.so: $(PEVENT_LIB_OBJS)
181 $(Q)$(do_compile_shared_library)
182
183liblockdep.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
191all_objs := $(sort $(ALL_OBJS))
192all_deps := $(all_objs:%.o=.%.d)
193
194# let .d file also depends on the source and header files
195define check_deps
196 @set -e; $(RM) $@; \
197 $(CC) -MM $(CFLAGS) $< > $@.$$$$; \
198 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
199 $(RM) $@.$$$$
200endef
201
202$(all_deps): .%.d: $(src)/%.c
203 $(Q)$(call check_deps)
204
205$(all_objs) : %.o : .%.d
206
207dep_includes := $(wildcard $(all_deps))
208
209ifneq ($(dep_includes),)
210 include $(dep_includes)
211endif
212
213### Detect environment changes
214TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):$(ARCH):$(CROSS_COMPILE)
215
216tags: force
217 $(RM) tags
218 find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \
219 --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/'
220
221TAGS: force
222 $(RM) TAGS
223 find . -name '*.[ch]' | xargs etags \
224 --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/'
225
226define 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'
232endef
233
234install_lib: all_cmd
235 $(Q)$(call do_install,$(LIB_FILE),$(libdir_SQ))
236 $(Q)$(call do_install,$(BIN_FILE),$(bindir_SQ))
237
238install: install_lib
239
240clean:
241 $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d
242 $(RM) tags TAGS
243
244endif # skip-makefile
245
246PHONY += force
247force:
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
8static __thread struct task_struct current_obj;
9
10/* lockdep wants these */
11bool debug_locks = true;
12bool 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(&current_obj);
22}
23
24struct 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 &current_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
21struct lockdep_subclass_key {
22 char __one_byte;
23};
24
25struct lock_class_key {
26 struct lockdep_subclass_key subkeys[MAX_LOCKDEP_SUBCLASSES];
27};
28
29struct 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
39void lockdep_init_map(struct lockdep_map *lock, const char *name,
40 struct lock_class_key *key, int subclass);
41void 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);
44void 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
7struct liblockdep_pthread_mutex {
8 pthread_mutex_t mutex;
9 struct lockdep_map dep_map;
10};
11
12typedef 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
20static 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
36static 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
42static 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
48static 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
54static 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
7struct liblockdep_pthread_rwlock {
8 pthread_rwlock_t rwlock;
9 struct lockdep_map dep_map;
10};
11
12typedef 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
20static 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
37static 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
44static 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
50static 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
56static 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
62static 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
68static 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
3LD_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 */
18struct 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 */
37static struct rb_root locks = RB_ROOT;
38static pthread_rwlock_t locks_rwlock = PTHREAD_RWLOCK_INITIALIZER;
39
40/* pthread mutex API */
41
42#ifdef __GLIBC__
43extern int __pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
44extern int __pthread_mutex_lock(pthread_mutex_t *mutex);
45extern int __pthread_mutex_trylock(pthread_mutex_t *mutex);
46extern int __pthread_mutex_unlock(pthread_mutex_t *mutex);
47extern 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
55static int (*ll_pthread_mutex_init)(pthread_mutex_t *mutex,
56 const pthread_mutexattr_t *attr) = __pthread_mutex_init;
57static int (*ll_pthread_mutex_lock)(pthread_mutex_t *mutex) = __pthread_mutex_lock;
58static int (*ll_pthread_mutex_trylock)(pthread_mutex_t *mutex) = __pthread_mutex_trylock;
59static int (*ll_pthread_mutex_unlock)(pthread_mutex_t *mutex) = __pthread_mutex_unlock;
60static int (*ll_pthread_mutex_destroy)(pthread_mutex_t *mutex) = __pthread_mutex_destroy;
61
62/* pthread rwlock API */
63
64#ifdef __GLIBC__
65extern int __pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
66extern int __pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
67extern int __pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
68extern int __pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
69extern int __pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
70extern int __pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
71extern 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
82static int (*ll_pthread_rwlock_init)(pthread_rwlock_t *rwlock,
83 const pthread_rwlockattr_t *attr) = __pthread_rwlock_init;
84static int (*ll_pthread_rwlock_destroy)(pthread_rwlock_t *rwlock) = __pthread_rwlock_destroy;
85static int (*ll_pthread_rwlock_rdlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_rdlock;
86static int (*ll_pthread_rwlock_tryrdlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_tryrdlock;
87static int (*ll_pthread_rwlock_trywrlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_trywrlock;
88static int (*ll_pthread_rwlock_wrlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_wrlock;
89static int (*ll_pthread_rwlock_unlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_unlock;
90
91enum { none, prepare, done, } __init_state;
92static void init_preload(void);
93static void try_init_preload(void)
94{
95 if (!__init_state != done)
96 init_preload();
97}
98
99static 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
127static struct lock_lookup __locks[LIBLOCKDEP_STATIC_ENTRIES];
128static int __locks_nr;
129
130static inline bool is_static_lock(struct lock_lookup *lock)
131{
132 return lock >= __locks && lock < __locks + ARRAY_SIZE(__locks);
133}
134
135static 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
162static 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 */
175static 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
212static 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
220int 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
249int 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
278int 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
292int 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
311int 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 */
326int 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
340int 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
349int 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
363int 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
377int 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
391int 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
405int 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
3make &> /dev/null
4
5for 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
15done
16
17for 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
27done
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
3void 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
4void 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
4void 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
4void 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
4void 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
4void 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
4void 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
3void 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
3void 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
9extern bool debug_locks;
10extern 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
9struct module;
10
11static 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>
21static 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
4static 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
15struct 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
25extern 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
40static 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
4static 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
4int rcu_scheduler_active;
5
6static inline int rcu_lockdep_current_cpu_online(void)
7{
8 return 1;
9}
10
11static inline int rcu_is_cpu_idle(void)
12{
13 return 1;
14}
15
16static 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
10static inline void arch_spin_lock(arch_spinlock_t *mutex)
11{
12 pthread_mutex_lock(mutex);
13}
14
15static inline void arch_spin_unlock(arch_spinlock_t *mutex)
16{
17 pthread_mutex_unlock(mutex);
18}
19
20static 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
6struct stack_trace {
7 unsigned int nr_entries, max_entries;
8 unsigned long *entries;
9 int skip;
10};
11
12static 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
21static 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
10struct page;
11struct kmem_cache;
12
13typedef unsigned gfp_t;
14
15typedef __u64 u64;
16typedef __s64 s64;
17
18typedef __u32 u32;
19typedef __s32 s32;
20
21typedef __u16 u16;
22typedef __s16 s16;
23
24typedef __u8 u8;
25typedef __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
39typedef __u16 __bitwise __le16;
40typedef __u16 __bitwise __be16;
41typedef __u32 __bitwise __le32;
42typedef __u32 __bitwise __be32;
43typedef __u64 __bitwise __le64;
44typedef __u64 __bitwise __be64;
45
46struct list_head {
47 struct list_head *next, *prev;
48};
49
50struct hlist_head {
51 struct hlist_node *first;
52};
53
54struct 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
5int 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
56out_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
12static 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
20int 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))'
43export man_dir man_dir_SQ INSTALL 43export man_dir man_dir_SQ INSTALL
44export DESTDIR DESTDIR_SQ 44export DESTDIR DESTDIR_SQ
45 45
46set_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#
56ifeq ($(plugin_dir),)
57ifeq ($(prefix),$(HOME))
58override plugin_dir = $(HOME)/.traceevent/plugins
59set_plugin_dir := 0
60else
61override plugin_dir = $(prefix)/lib/traceevent/plugins
62endif
63endif
64
65ifeq ($(set_plugin_dir),1)
66PLUGIN_DIR = -DPLUGIN_DIR="$(plugin_dir)"
67PLUGIN_DIR_SQ = '$(subst ','\'',$(PLUGIN_DIR))'
68endif
69
70include $(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
48ifeq ("$(origin V)", "command line") 74ifeq ("$(origin V)", "command line")
@@ -57,18 +83,13 @@ ifeq ("$(origin O)", "command line")
57endif 83endif
58 84
59ifeq ($(BUILD_SRC),) 85ifeq ($(BUILD_SRC),)
60ifneq ($(BUILD_OUTPUT),) 86ifneq ($(OUTPUT),)
61 87
62define build_output 88define 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
65endef 91endef
66 92
67saved-output := $(BUILD_OUTPUT)
68BUILD_OUTPUT := $(shell cd $(BUILD_OUTPUT) && /bin/pwd)
69$(if $(BUILD_OUTPUT),, \
70 $(error output directory "$(saved-output)" does not exist))
71
72all: sub-make 93all: 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
81skip-makefile := 1 102skip-makefile := 1
82 103
83endif # BUILD_OUTPUT 104endif # OUTPUT
84endif # BUILD_SRC 105endif # 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
97bindir_SQ = $(subst ','\'',$(bindir)) 118bindir_SQ = $(subst ','\'',$(bindir))
98bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) 119bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
120plugin_dir_SQ = $(subst ','\'',$(plugin_dir))
99 121
100LIB_FILE = libtraceevent.a libtraceevent.so 122LIB_FILE = libtraceevent.a libtraceevent.so
101 123
@@ -114,7 +136,7 @@ export Q VERBOSE
114 136
115EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION) 137EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION)
116 138
117INCLUDES = -I. $(CONFIG_INCLUDES) 139INCLUDES = -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
120CFLAGS ?= -g -Wall 142CFLAGS ?= -g -Wall
@@ -125,41 +147,14 @@ override CFLAGS += $(udis86-flags) -D_GNU_SOURCE
125 147
126ifeq ($(VERBOSE),1) 148ifeq ($(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 =
135else 150else
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';
145endif 152endif
146 153
147do_fpic_compile = \
148 ($(print_fpic_compile) \
149 $(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@)
150
151do_app_build = \
152 ($(print_app_build) \
153 $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS))
154
155do_compile_shared_library = \ 154do_compile_shared_library = \
156 ($(print_shared_lib_compile) \ 155 ($(print_shared_lib_compile) \
157 $(CC) --shared $^ -o $@) 156 $(CC) --shared $^ -o $@)
158 157
159do_compile_plugin_obj = \
160 ($(print_plugin_obj_compile) \
161 $(CC) -c $(CFLAGS) -fPIC -o $@ $<)
162
163do_plugin_build = \ 158do_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
172define do_compile 167do_compile = $(QUIET_CC)$(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@;
173 $(print_compile) \
174 $(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@;
175endef
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
183PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o 175PEVENT_LIB_OBJS = event-parse.o
176PEVENT_LIB_OBJS += event-plugin.o
177PEVENT_LIB_OBJS += trace-seq.o
178PEVENT_LIB_OBJS += parse-filter.o
179PEVENT_LIB_OBJS += parse-utils.o
184PEVENT_LIB_OBJS += kbuffer-parse.o 180PEVENT_LIB_OBJS += kbuffer-parse.o
185 181
186ALL_OBJS = $(PEVENT_LIB_OBJS) 182PLUGIN_OBJS = plugin_jbd2.o
183PLUGIN_OBJS += plugin_hrtimer.o
184PLUGIN_OBJS += plugin_kmem.o
185PLUGIN_OBJS += plugin_kvm.o
186PLUGIN_OBJS += plugin_mac80211.o
187PLUGIN_OBJS += plugin_sched_switch.o
188PLUGIN_OBJS += plugin_function.o
189PLUGIN_OBJS += plugin_xen.o
190PLUGIN_OBJS += plugin_scsi.o
191PLUGIN_OBJS += plugin_cfg80211.o
192
193PLUGINS := $(PLUGIN_OBJS:.o=.so)
194
195ALL_OBJS = $(PEVENT_LIB_OBJS) $(PLUGIN_OBJS)
187 196
188CMD_TARGETS = $(LIB_FILE) 197CMD_TARGETS = $(LIB_FILE) $(PLUGINS)
189 198
190TARGETS = $(CMD_TARGETS) 199TARGETS = $(CMD_TARGETS)
191 200
@@ -195,32 +204,40 @@ all: all_cmd
195all_cmd: $(CMD_TARGETS) 204all_cmd: $(CMD_TARGETS)
196 205
197libtraceevent.so: $(PEVENT_LIB_OBJS) 206libtraceevent.so: $(PEVENT_LIB_OBJS)
198 $(Q)$(do_compile_shared_library) 207 $(QUIET_LINK)$(CC) --shared $^ -o $@
199 208
200libtraceevent.a: $(PEVENT_LIB_OBJS) 209libtraceevent.a: $(PEVENT_LIB_OBJS)
201 $(Q)$(do_build_static_lib) 210 $(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^
211
212plugins: $(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
206define make_version.h 223define 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
214endef 231endef
215 232
216define update_version.h 233define 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);
224endef 241endef
225 242
226ep_version.h: force 243ep_version.h: force
@@ -229,13 +246,13 @@ ep_version.h: force
229VERSION_FILES = ep_version.h 246VERSION_FILES = ep_version.h
230 247
231define update_dir 248define 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);
239endef 256endef
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
247define check_deps 264define 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) $@.$$$$
252endef 269endef
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
285define do_install 302define 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'
291endef 307endef
292 308
293install_lib: all_cmd 309define 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
313endef
314
315install_lib: all_cmd install_plugins
316 $(call QUIET_INSTALL, $(LIB_FILE)) \
317 $(call do_install,$(LIB_FILE),$(bindir_SQ))
318
319install_plugins: $(PLUGINS)
320 $(call QUIET_INSTALL, trace_plugins) \
321 $(call do_install_plugins, $(PLUGINS))
295 322
296install: install_lib 323install: install_lib
297 324
298clean: 325clean:
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
302endif # skip-makefile 330endif # skip-makefile
303 331
304PHONY += force 332PHONY += force plugins
305force: 333force:
306 334
335plugins:
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
2754err:
2755 free_arg(farg);
2756 free_token(token);
2757 return EVENT_ERROR;
2750} 2758}
2751 2759
2752static enum event_type 2760static 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
5132static 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
5155event_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 */
5132enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf, 5175enum 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
5172event_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 */
5573int 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
5586static 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
5675static 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 */
5710int 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
5731not_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
61enum 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
72void trace_seq_init(struct trace_seq *s); 80void 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
99typedef int (*pevent_plugin_load_func)(struct pevent *pevent); 107typedef int (*pevent_plugin_load_func)(struct pevent *pevent);
100typedef int (*pevent_plugin_unload_func)(void); 108typedef int (*pevent_plugin_unload_func)(struct pevent *pevent);
101 109
102struct plugin_option { 110struct 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
362enum pevent_errno { 392enum 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
411struct plugin_list;
412
413struct plugin_list *traceevent_load_plugins(struct pevent *pevent);
414void traceevent_unload_plugins(struct plugin_list *plugin_list,
415 struct pevent *pevent);
416
380struct cmdline; 417struct cmdline;
381struct cmdline_list; 418struct cmdline_list;
382struct func_map; 419struct 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
562static 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 */
526enum trace_flag_type { 572enum 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
548enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, 594enum 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);
550enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf, 596enum 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);
552void pevent_free_format(struct event_format *event); 600void 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,
576int pevent_register_event_handler(struct pevent *pevent, int id, 624int 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);
627int 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);
579int pevent_register_print_function(struct pevent *pevent, 630int 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, ...);
634int pevent_unregister_print_function(struct pevent *pevent,
635 pevent_func_handler func, char *name);
583 636
584struct format_field *pevent_find_common_field(struct event_format *event, const char *name); 637struct format_field *pevent_find_common_field(struct event_format *event, const char *name);
585struct format_field *pevent_find_field(struct event_format *event, const char *name); 638struct 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
814struct event_filter { 869struct 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
820struct event_filter *pevent_filter_alloc(struct pevent *pevent); 876struct 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
827enum filter_trivial_type { 884enum 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
833int pevent_filter_add_filter_str(struct event_filter *filter, 890enum 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
893enum pevent_errno pevent_filter_match(struct event_filter *filter,
894 struct pevent_record *record);
837 895
838int pevent_filter_match(struct event_filter *filter, 896int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err,
839 struct pevent_record *record); 897 char *buf, size_t buflen);
840 898
841int pevent_event_filtered(struct event_filter *filter, 899int pevent_event_filtered(struct event_filter *filter,
842 int event_id); 900 int event_id);
843 901
844void pevent_filter_reset(struct event_filter *filter); 902void pevent_filter_reset(struct event_filter *filter);
845 903
846void pevent_filter_clear_trivial(struct event_filter *filter, 904int pevent_filter_clear_trivial(struct event_filter *filter,
847 enum filter_trivial_type type); 905 enum filter_trivial_type type);
848 906
849void pevent_filter_free(struct event_filter *filter); 907void 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
33struct plugin_list {
34 struct plugin_list *next;
35 char *name;
36 void *handle;
37};
38
39static void
40load_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
97static void
98load_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
139static void
140load_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
190struct plugin_list*
191traceevent_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
199void
200traceevent_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 */
26void die(const char *fmt, ...);
27void *malloc_or_die(unsigned int size);
28void warning(const char *fmt, ...); 26void warning(const char *fmt, ...);
29void pr_stat(const char *fmt, ...); 27void pr_stat(const char *fmt, ...);
30void vpr_stat(const char *fmt, va_list ap); 28void vpr_stat(const char *fmt, va_list ap);
31 29
32/* Always available */ 30/* Always available */
33void __die(const char *fmt, ...);
34void __warning(const char *fmt, ...); 31void __warning(const char *fmt, ...);
35void __pr_stat(const char *fmt, ...); 32void __pr_stat(const char *fmt, ...);
36 33
37void __vdie(const char *fmt, ...);
38void __vwarning(const char *fmt, ...); 34void __vwarning(const char *fmt, ...);
39void __vpr_stat(const char *fmt, ...); 35void __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 41static void show_error(char *error_buf, const char *fmt, ...)
42
43static 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
78static void free_token(char *token) 68static 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
193static struct filter_arg *allocate_arg(void) 192static 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
203static void free_arg(struct filter_arg *arg) 197static 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
245static void add_event(struct event_list **events, 239static 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
256static int event_match(struct event_format *event, 254static 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
268static int 266static enum pevent_errno
269find_event(struct pevent *pevent, struct event_list **events, 267find_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
335static struct filter_arg * 347static enum pevent_errno
336create_arg_item(struct event_format *event, const char *token, 348create_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
387static struct filter_arg * 406static 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
424static int add_right(struct filter_arg *op, struct filter_arg *arg, 452static enum pevent_errno
425 char **error_str) 453add_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
585static struct filter_arg * 617static 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
595static int add_left(struct filter_arg *op, struct filter_arg *arg) 627static 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
731void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, 763static enum pevent_errno
732 struct filter_arg *arg) 764reparent_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
774enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg) 815/* Returns either filter_vals (success) or pevent_errno (failfure) */
816static 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 */
867static struct filter_arg *collapse_tree(struct filter_arg *arg) 916static 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
887static int 950static enum pevent_errno
888process_filter(struct event_format *event, struct filter_arg **parg, 951process_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
1105static int 1188static enum pevent_errno
1106process_event(struct event_format *event, const char *filter_str, 1189process_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
1132static int filter_event(struct event_filter *filter, 1213static enum pevent_errno
1133 struct event_format *event, 1214filter_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
1247static 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 */
1173int pevent_filter_add_filter_str(struct event_filter *filter, 1263enum 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 */
1375int 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 */
1486void pevent_filter_clear_trivial(struct event_filter *filter, 1602int 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
1568static int test_filter(struct event_format *event, 1691static 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
1571static const char * 1694static const char *
1572get_comm(struct event_format *event, struct pevent_record *record) 1695get_comm(struct event_format *event, struct pevent_record *record)
@@ -1612,15 +1735,24 @@ get_value(struct event_format *event,
1612} 1735}
1613 1736
1614static unsigned long long 1737static unsigned long long
1615get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record); 1738get_arg_value(struct event_format *event, struct filter_arg *arg,
1739 struct pevent_record *record, enum pevent_errno *err);
1616 1740
1617static unsigned long long 1741static unsigned long long
1618get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record) 1742get_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
1663static unsigned long long 1796static unsigned long long
1664get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record) 1797get_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
1684static int test_num(struct event_format *event, 1821static 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
1759static int test_str(struct event_format *event, 1904static 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
1789static int test_op(struct event_format *event, 1935static 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
1810static int test_filter(struct event_format *event, 1957static 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 */
1851int pevent_event_filtered(struct event_filter *filter, 2005int 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 */
1875int pevent_filter_match(struct event_filter *filter, 2029enum 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
1896static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) 2056static 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
2014static char *val_to_str(struct event_filter *filter, struct filter_arg *arg) 2160static 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);
2081out: 2223out:
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
2179static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg) 2312static 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 */
2226char * 2355char *
2227pevent_filter_make_string(struct event_filter *filter, int event_id) 2356pevent_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
28void __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
44void __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
53void __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
62void __vwarning(const char *fmt, va_list ap) 28void __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
121void __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
7static unsigned long long
8process___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
15int 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
26void 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
27static struct func_stack {
28 int size;
29 char **stack;
30} *fstack;
31
32static int cpus = -1;
33
34#define STK_BLK 10
35
36static 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
65static 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
102static 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
140int 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
147void 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
27static 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
47static 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
69int 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
80void 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
32static unsigned long long
33process_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
42static unsigned long long
43process_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
52int 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
70void 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
26static 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
51int 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
74void 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
31static ud_t ud;
32
33static void init_disassembler(void)
34{
35 ud_init(&ud);
36 ud_set_syntax(&ud, UD_SYN_ATT);
37}
38
39static 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
65static void init_disassembler(void)
66{
67}
68
69static 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 },
204struct str_values {
205 const char *str;
206 int val;
207};
208
209static struct str_values vmx_exit_reasons[] = {
210 VMX_EXIT_REASONS
211 { NULL, -1}
212};
213
214static struct str_values svm_exit_reasons[] = {
215 SVM_EXIT_REASONS
216 { NULL, -1}
217};
218
219static 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
228static 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
248static 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
277static 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
316union 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
331static 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
374static 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
395static unsigned long long
396process_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
402int 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
438void 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
28static 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
60static 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
89int 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
97void 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
26static 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
47static 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
67static 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
96static 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
137int 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
150void 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
6typedef unsigned long sector_t;
7typedef uint64_t u64;
8typedef 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
148static const char *
149scsi_trace_misc(struct trace_seq *, unsigned char *, int);
150
151static const char *
152scsi_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
168static const char *
169scsi_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
192static const char *
193scsi_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
214static const char *
215scsi_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
244static const char *
245scsi_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
293out:
294 trace_seq_putc(p, 0);
295 return ret;
296}
297
298static const char *
299scsi_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
309static const char *
310scsi_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
344out:
345 trace_seq_putc(p, 0);
346 return ret;
347}
348
349static const char *
350scsi_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
363static const char *
364scsi_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
373const char *
374scsi_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
405unsigned 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
412int 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
425void 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")"
53static 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
103static 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
112unsigned 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
121int 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
132void 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) \
34do { \ 35do { \
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) \
42do { \
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
79static void expand_buffer(struct trace_seq *s) 95static 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
188int trace_seq_putc(struct trace_seq *s, unsigned char c) 212int 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
200void trace_seq_terminate(struct trace_seq *s) 226void 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)
208int trace_seq_do_printf(struct trace_seq *s) 234int 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}