aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lib
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-01-20 13:28:30 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-01-20 13:28:30 -0500
commit9326657abe1a83ed4b4f396b923ca1217fd50cba (patch)
tree9fd5035a6f68af7306d58938e309bd36ed81646c /tools/lib
parent2cc3f16cad1561c6fc551aefff559e53726efc8b (diff)
parent45e6af06367e7b2eb8dc49671092462d8f8a5f47 (diff)
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar: "Kernel side changes: - Add Intel RAPL energy counter support (Stephane Eranian) - Clean up uprobes (Oleg Nesterov) - Optimize ring-buffer writes (Peter Zijlstra) Tooling side changes, user visible: - 'perf diff': - Add column colouring improvements (Ramkumar Ramachandra) - 'perf kvm': - Add guest related improvements, including allowing to specify a directory with guest specific /proc information (Dongsheng Yang) - Add shell completion support (Ramkumar Ramachandra) - Add '-v' option (Dongsheng Yang) - Support --guestmount (Dongsheng Yang) - 'perf probe': - Support showing source code, asking for variables to be collected at probe time and other 'perf probe' operations that use DWARF information. This supports only binaries with debugging information at this time, detached debuginfo (aka debuginfo packages) support should come in later patches (Masami Hiramatsu) - 'perf record': - Rename --no-delay option to --no-buffering, better reflecting its purpose and freeing up '--delay' to take the place of '--initial-delay', so that 'record' and 'stat' are consistent (Arnaldo Carvalho de Melo) - Default the -t/--thread option to no inheritance (Adrian Hunter) - Make per-cpu mmaps the default (Adrian Hunter) - 'perf report': - Improve callchain processing performance (Frederic Weisbecker) - Retain bfd reference to lookup source line numbers, greatly optimizing, among other use cases, 'perf report -s srcline' (Adrian Hunter) - Improve callchain processing performance even more (Namhyung Kim) - Add a perf.data file header window in the 'perf report' TUI, associated with the 'i' hotkey, providing a counterpart to the --header option in the stdio UI (Namhyung Kim) - 'perf script': - Add an option in 'perf script' to print the source line number (Adrian Hunter) - Add --header/--header-only options to 'script' and 'report', the default is not tho show the header info, but as this has been the default for some time, leave a single line explaining how to obtain that information (Jiri Olsa) - Add options to show comm, fork, exit and mmap PERF_RECORD_ events (Namhyung Kim) - Print callchains and symbols if they exist (David Ahern) - 'perf timechart' - Add backtrace support to CPU info - Print pid along the name - Add support for CPU topology - Add new option --highlight'ing threads, be it by name or, if a numeric value is provided, that run more than given duration (Stanislav Fomichev) - 'perf top': - Make 'perf top -g' refer to callchains, for consistency with other tools (David Ahern) - 'perf trace': - Handle old kernels where the "raw_syscalls" tracepoints were called plain "syscalls" (David Ahern) - Remove thread summary coloring, by Pekka Enberg. - Honour -m option in 'trace', the tool was offering the option to set the mmap size, but wasn't using it when doing the actual mmap on the events file descriptors (Jiri Olsa) - generic: - Backport libtraceevent plugin support (trace-cmd repository, with plugins for jbd2, hrtimer, kmem, kvm, mac80211, sched_switch, function, xen, scsi, cfg80211 (Jiri Olsa) - Print session information only if --stdio is given (Namhyung Kim) Tooling side changes, developer visible (plumbing): - Improve 'perf probe' exit path, release resources (Masami Hiramatsu) - Improve libtraceevent plugins exit path, allowing the registering of an unregister handler to be called at exit time (Namhyung Kim) - Add an alias to the build test makefile (make -C tools/perf build-test) (Namhyung Kim) - Get rid of die() and friends (good riddance!) in libtraceevent (Namhyung Kim) - Fix cross build problems related to pkgconfig and CROSS_COMPILE not being propagated to the feature tests, leading to features being tested in the host and then being enabled on the target (Mark Rutland) - Improve forked workload error reporting by sending the errno in the signal data queueing integer field, using sigqueue and by doing the signal setup in the evlist methods, removing open coded equivalents in various tools (Arnaldo Carvalho de Melo) - Do more auto exit cleanup chores in the 'evlist' destructor, so that the tools don't have to all do that sequence (Arnaldo Carvalho de Melo) - Pack 'struct perf_session_env' and 'struct trace' (Arnaldo Carvalho de Melo) - Add test for building detached source tarballs (Arnaldo Carvalho de Melo) - Move some header files (tools/perf/ to tools/include/ to make them available to other tools/ dwelling codebases (Namhyung Kim) - Move logic to warn about kptr_restrict'ed kernels to separate function in 'report' (Arnaldo Carvalho de Melo) - Move hist browser selection code to separate function (Arnaldo Carvalho de Melo) - Move histogram entries collapsing to separate function (Arnaldo Carvalho de Melo) - Introduce evlist__for_each() & friends (Arnaldo Carvalho de Melo) - Automate setup of FEATURE_CHECK_(C|LD)FLAGS-all variables (Jiri Olsa) - Move arch setup into seprate Makefile (Jiri Olsa) - Make libtraceevent install target quieter (Jiri Olsa) - Make tests/make output more compact (Jiri Olsa) - Ignore generated files in feature-checks (Chunwei Chen) - Introduce pevent_filter_strerror() in libtraceevent, similar in purpose to libc's strerror() function (Namhyung Kim) - Use perf_data_file methods to write output file in 'record' and 'inject' (Jiri Olsa) - Use pr_*() functions where applicable in 'report' (Namhyumg Kim) - Add 'machine' 'addr_location' struct to have full picture (machine, thread, map, symbol, addr) for a (partially) resolved address, reducing function signatures (Arnaldo Carvalho de Melo) - Reduce code duplication in the histogram entry creation/insertion (Arnaldo Carvalho de Melo) - Auto allocate annotation histogram data structures (Arnaldo Carvalho de Melo) - No need to test against NULL before calling free, also set freed memory in struct pointers to NULL, to help fixing use after free bugs (Arnaldo Carvalho de Melo) - Rename some struct DSO binary_type related members and methods, to clarify its purpose and need for differentiation (symtab_type, ie one is about the files .text, CFI, etc, i.e. its binary contents, and the other is about where the symbol table came from (Arnaldo Carvalho de Melo) - Convert to new topic libraries, starting with an API one (sysfs, debugfs, etc), renaming liblk in the process (Borislav Petkov) - Get rid of some more panic() like error handling in libtraceevent. (Namhyung Kim) - Get rid of panic() like calls in libtraceevent (Namyung Kim) - Start carving out symbol parsing routines (perf, just moving routines to topic files in tools/lib/symbol/, tools that want to use it need to integrate it directly, ie no tools/lib/symbol/Makefile is provided (Arnaldo Carvalho de Melo) - Assorted refactoring patches, moving code around and adding utility evlist methods that will be used in the IPT patchset (Adrian Hunter) - Assorted mmap_pages handling fixes (Adrian Hunter) - Several man pages typo fixes (Dongsheng Yang) - Get rid of several die() calls in libtraceevent (Namhyung Kim) - Use basename() in a more robust way, to avoid problems related to different system library implementations for that function (Stephane Eranian) - Remove open coded management of short_name_allocated member (Adrian Hunter) - Several cleanups in the "dso" methods, constifying some parameters and renaming some fields to clarify its purpose (Arnaldo Carvalho de Melo) - Add per-feature check flags, fixing libunwind related build problems on some architectures (Jean Pihet) - Do not disable source line lookup just because of one failure. (Adrian Hunter) - Several 'perf kvm' man page corrections (Dongsheng Yang) - Correct the message in feature-libnuma checking, swowing the right devel package names for various distros (Dongsheng Yang) - Polish 'readn()' function and introduce its counterpart, 'writen()' (Jiri Olsa) - Start moving timechart state from global variables to a 'perf_tool' derived 'timechart' struct (Arnaldo Carvalho de Melo) ... and lots of fixes and improvements I forgot to list" * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (282 commits) perf tools: Remove unnecessary callchain cursor state restore on unmatch perf callchain: Spare double comparison of callchain first entry perf tools: Do proper comm override error handling perf symbols: Export elf_section_by_name and reuse perf probe: Release all dynamically allocated parameters perf probe: Release allocated probe_trace_event if failed perf tools: Add 'build-test' make target tools lib traceevent: Unregister handler when xen plugin is unloaded tools lib traceevent: Unregister handler when scsi plugin is unloaded tools lib traceevent: Unregister handler when jbd2 plugin is is unloaded tools lib traceevent: Unregister handler when cfg80211 plugin is unloaded tools lib traceevent: Unregister handler when mac80211 plugin is unloaded tools lib traceevent: Unregister handler when sched_switch plugin is unloaded tools lib traceevent: Unregister handler when kvm plugin is unloaded tools lib traceevent: Unregister handler when kmem plugin is unloaded tools lib traceevent: Unregister handler when hrtimer plugin is unloaded tools lib traceevent: Unregister handler when function plugin is unloaded tools lib traceevent: Add pevent_unregister_print_function() tools lib traceevent: Add pevent_unregister_event_handler() tools lib traceevent: fix pointer-integer size mismatch ...
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/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
23 files changed, 2873 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/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..56d52a33a3df 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="$(DESTDIR)/$(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}