diff options
Diffstat (limited to 'tools/lib/traceevent')
| -rw-r--r-- | tools/lib/traceevent/Makefile | 189 | ||||
| -rw-r--r-- | tools/lib/traceevent/event-parse.c | 108 | ||||
| -rw-r--r-- | tools/lib/traceevent/event-parse.h | 69 | ||||
| -rw-r--r-- | tools/lib/traceevent/event-plugin.c | 215 | ||||
| -rw-r--r-- | tools/lib/traceevent/parse-filter.c | 673 | ||||
| -rw-r--r-- | tools/lib/traceevent/plugin_cfg80211.c | 24 | ||||
| -rw-r--r-- | tools/lib/traceevent/plugin_function.c | 160 | ||||
| -rw-r--r-- | tools/lib/traceevent/plugin_hrtimer.c | 78 | ||||
| -rw-r--r-- | tools/lib/traceevent/plugin_jbd2.c | 68 | ||||
| -rw-r--r-- | tools/lib/traceevent/plugin_kmem.c | 72 | ||||
| -rw-r--r-- | tools/lib/traceevent/plugin_kvm.c | 436 | ||||
| -rw-r--r-- | tools/lib/traceevent/plugin_mac80211.c | 95 | ||||
| -rw-r--r-- | tools/lib/traceevent/plugin_sched_switch.c | 148 | ||||
| -rw-r--r-- | tools/lib/traceevent/plugin_scsi.c | 423 | ||||
| -rw-r--r-- | tools/lib/traceevent/plugin_xen.c | 130 |
15 files changed, 2477 insertions, 411 deletions
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index fc1502098595..f778d48ac609 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile | |||
| @@ -43,6 +43,32 @@ man_dir_SQ = '$(subst ','\'',$(man_dir))' | |||
| 43 | export man_dir man_dir_SQ INSTALL | 43 | export man_dir man_dir_SQ INSTALL |
| 44 | export DESTDIR DESTDIR_SQ | 44 | export DESTDIR DESTDIR_SQ |
| 45 | 45 | ||
| 46 | set_plugin_dir := 1 | ||
| 47 | |||
| 48 | # Set plugin_dir to preffered global plugin location | ||
| 49 | # If we install under $HOME directory we go under | ||
| 50 | # $(HOME)/.traceevent/plugins | ||
| 51 | # | ||
| 52 | # We dont set PLUGIN_DIR in case we install under $HOME | ||
| 53 | # directory, because by default the code looks under: | ||
| 54 | # $(HOME)/.traceevent/plugins by default. | ||
| 55 | # | ||
| 56 | ifeq ($(plugin_dir),) | ||
| 57 | ifeq ($(prefix),$(HOME)) | ||
| 58 | override plugin_dir = $(HOME)/.traceevent/plugins | ||
| 59 | set_plugin_dir := 0 | ||
| 60 | else | ||
| 61 | override plugin_dir = $(prefix)/lib/traceevent/plugins | ||
| 62 | endif | ||
| 63 | endif | ||
| 64 | |||
| 65 | ifeq ($(set_plugin_dir),1) | ||
| 66 | PLUGIN_DIR = -DPLUGIN_DIR="$(DESTDIR)/$(plugin_dir)" | ||
| 67 | PLUGIN_DIR_SQ = '$(subst ','\'',$(PLUGIN_DIR))' | ||
| 68 | endif | ||
| 69 | |||
| 70 | include $(if $(BUILD_SRC),$(BUILD_SRC)/)../../scripts/Makefile.include | ||
| 71 | |||
| 46 | # copy a bit from Linux kbuild | 72 | # copy a bit from Linux kbuild |
| 47 | 73 | ||
| 48 | ifeq ("$(origin V)", "command line") | 74 | ifeq ("$(origin V)", "command line") |
| @@ -57,18 +83,13 @@ ifeq ("$(origin O)", "command line") | |||
| 57 | endif | 83 | endif |
| 58 | 84 | ||
| 59 | ifeq ($(BUILD_SRC),) | 85 | ifeq ($(BUILD_SRC),) |
| 60 | ifneq ($(BUILD_OUTPUT),) | 86 | ifneq ($(OUTPUT),) |
| 61 | 87 | ||
| 62 | define build_output | 88 | define build_output |
| 63 | $(if $(VERBOSE:1=),@)+$(MAKE) -C $(BUILD_OUTPUT) \ | 89 | $(if $(VERBOSE:1=),@)+$(MAKE) -C $(OUTPUT) \ |
| 64 | BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1 | 90 | BUILD_SRC=$(CURDIR)/ -f $(CURDIR)/Makefile $1 |
| 65 | endef | 91 | endef |
| 66 | 92 | ||
| 67 | saved-output := $(BUILD_OUTPUT) | ||
| 68 | BUILD_OUTPUT := $(shell cd $(BUILD_OUTPUT) && /bin/pwd) | ||
| 69 | $(if $(BUILD_OUTPUT),, \ | ||
| 70 | $(error output directory "$(saved-output)" does not exist)) | ||
| 71 | |||
| 72 | all: sub-make | 93 | all: sub-make |
| 73 | 94 | ||
| 74 | $(MAKECMDGOALS): sub-make | 95 | $(MAKECMDGOALS): sub-make |
| @@ -80,7 +101,7 @@ sub-make: force | |||
| 80 | # Leave processing to above invocation of make | 101 | # Leave processing to above invocation of make |
| 81 | skip-makefile := 1 | 102 | skip-makefile := 1 |
| 82 | 103 | ||
| 83 | endif # BUILD_OUTPUT | 104 | endif # OUTPUT |
| 84 | endif # BUILD_SRC | 105 | endif # BUILD_SRC |
| 85 | 106 | ||
| 86 | # We process the rest of the Makefile if this is the final invocation of make | 107 | # We process the rest of the Makefile if this is the final invocation of make |
| @@ -96,6 +117,7 @@ export prefix bindir src obj | |||
| 96 | # Shell quotes | 117 | # Shell quotes |
| 97 | bindir_SQ = $(subst ','\'',$(bindir)) | 118 | bindir_SQ = $(subst ','\'',$(bindir)) |
| 98 | bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) | 119 | bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) |
| 120 | plugin_dir_SQ = $(subst ','\'',$(plugin_dir)) | ||
| 99 | 121 | ||
| 100 | LIB_FILE = libtraceevent.a libtraceevent.so | 122 | LIB_FILE = libtraceevent.a libtraceevent.so |
| 101 | 123 | ||
| @@ -125,41 +147,14 @@ override CFLAGS += $(udis86-flags) -D_GNU_SOURCE | |||
| 125 | 147 | ||
| 126 | ifeq ($(VERBOSE),1) | 148 | ifeq ($(VERBOSE),1) |
| 127 | Q = | 149 | Q = |
| 128 | print_compile = | ||
| 129 | print_app_build = | ||
| 130 | print_fpic_compile = | ||
| 131 | print_shared_lib_compile = | ||
| 132 | print_plugin_obj_compile = | ||
| 133 | print_plugin_build = | ||
| 134 | print_install = | ||
| 135 | else | 150 | else |
| 136 | Q = @ | 151 | Q = @ |
| 137 | print_compile = echo ' CC '$(OBJ); | ||
| 138 | print_app_build = echo ' BUILD '$(OBJ); | ||
| 139 | print_fpic_compile = echo ' CC FPIC '$(OBJ); | ||
| 140 | print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ); | ||
| 141 | print_plugin_obj_compile = echo ' BUILD PLUGIN OBJ '$(OBJ); | ||
| 142 | print_plugin_build = echo ' BUILD PLUGIN '$(OBJ); | ||
| 143 | print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ); | ||
| 144 | print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2'; | ||
| 145 | endif | 152 | endif |
| 146 | 153 | ||
| 147 | do_fpic_compile = \ | ||
| 148 | ($(print_fpic_compile) \ | ||
| 149 | $(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@) | ||
| 150 | |||
| 151 | do_app_build = \ | ||
| 152 | ($(print_app_build) \ | ||
| 153 | $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS)) | ||
| 154 | |||
| 155 | do_compile_shared_library = \ | 154 | do_compile_shared_library = \ |
| 156 | ($(print_shared_lib_compile) \ | 155 | ($(print_shared_lib_compile) \ |
| 157 | $(CC) --shared $^ -o $@) | 156 | $(CC) --shared $^ -o $@) |
| 158 | 157 | ||
| 159 | do_compile_plugin_obj = \ | ||
| 160 | ($(print_plugin_obj_compile) \ | ||
| 161 | $(CC) -c $(CFLAGS) -fPIC -o $@ $<) | ||
| 162 | |||
| 163 | do_plugin_build = \ | 158 | do_plugin_build = \ |
| 164 | ($(print_plugin_build) \ | 159 | ($(print_plugin_build) \ |
| 165 | $(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<) | 160 | $(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<) |
| @@ -169,23 +164,37 @@ do_build_static_lib = \ | |||
| 169 | $(RM) $@; $(AR) rcs $@ $^) | 164 | $(RM) $@; $(AR) rcs $@ $^) |
| 170 | 165 | ||
| 171 | 166 | ||
| 172 | define do_compile | 167 | do_compile = $(QUIET_CC)$(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@; |
| 173 | $(print_compile) \ | ||
| 174 | $(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@; | ||
| 175 | endef | ||
| 176 | 168 | ||
| 177 | $(obj)/%.o: $(src)/%.c | 169 | $(obj)/%.o: $(src)/%.c |
| 178 | $(Q)$(call do_compile) | 170 | $(call do_compile) |
| 179 | 171 | ||
| 180 | %.o: $(src)/%.c | 172 | %.o: $(src)/%.c |
| 181 | $(Q)$(call do_compile) | 173 | $(call do_compile) |
| 182 | 174 | ||
| 183 | PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o | 175 | PEVENT_LIB_OBJS = event-parse.o |
| 176 | PEVENT_LIB_OBJS += event-plugin.o | ||
| 177 | PEVENT_LIB_OBJS += trace-seq.o | ||
| 178 | PEVENT_LIB_OBJS += parse-filter.o | ||
| 179 | PEVENT_LIB_OBJS += parse-utils.o | ||
| 184 | PEVENT_LIB_OBJS += kbuffer-parse.o | 180 | PEVENT_LIB_OBJS += kbuffer-parse.o |
| 185 | 181 | ||
| 186 | ALL_OBJS = $(PEVENT_LIB_OBJS) | 182 | PLUGIN_OBJS = plugin_jbd2.o |
| 183 | PLUGIN_OBJS += plugin_hrtimer.o | ||
| 184 | PLUGIN_OBJS += plugin_kmem.o | ||
| 185 | PLUGIN_OBJS += plugin_kvm.o | ||
| 186 | PLUGIN_OBJS += plugin_mac80211.o | ||
| 187 | PLUGIN_OBJS += plugin_sched_switch.o | ||
| 188 | PLUGIN_OBJS += plugin_function.o | ||
| 189 | PLUGIN_OBJS += plugin_xen.o | ||
| 190 | PLUGIN_OBJS += plugin_scsi.o | ||
| 191 | PLUGIN_OBJS += plugin_cfg80211.o | ||
| 192 | |||
| 193 | PLUGINS := $(PLUGIN_OBJS:.o=.so) | ||
| 194 | |||
| 195 | ALL_OBJS = $(PEVENT_LIB_OBJS) $(PLUGIN_OBJS) | ||
| 187 | 196 | ||
| 188 | CMD_TARGETS = $(LIB_FILE) | 197 | CMD_TARGETS = $(LIB_FILE) $(PLUGINS) |
| 189 | 198 | ||
| 190 | TARGETS = $(CMD_TARGETS) | 199 | TARGETS = $(CMD_TARGETS) |
| 191 | 200 | ||
| @@ -195,32 +204,40 @@ all: all_cmd | |||
| 195 | all_cmd: $(CMD_TARGETS) | 204 | all_cmd: $(CMD_TARGETS) |
| 196 | 205 | ||
| 197 | libtraceevent.so: $(PEVENT_LIB_OBJS) | 206 | libtraceevent.so: $(PEVENT_LIB_OBJS) |
| 198 | $(Q)$(do_compile_shared_library) | 207 | $(QUIET_LINK)$(CC) --shared $^ -o $@ |
| 199 | 208 | ||
| 200 | libtraceevent.a: $(PEVENT_LIB_OBJS) | 209 | libtraceevent.a: $(PEVENT_LIB_OBJS) |
| 201 | $(Q)$(do_build_static_lib) | 210 | $(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^ |
| 211 | |||
| 212 | plugins: $(PLUGINS) | ||
| 202 | 213 | ||
| 203 | $(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS | 214 | $(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS |
| 204 | $(Q)$(do_fpic_compile) | 215 | $(QUIET_CC_FPIC)$(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@ |
| 216 | |||
| 217 | $(PLUGIN_OBJS): %.o : $(src)/%.c | ||
| 218 | $(QUIET_CC_FPIC)$(CC) -c $(CFLAGS) -fPIC -o $@ $< | ||
| 219 | |||
| 220 | $(PLUGINS): %.so: %.o | ||
| 221 | $(QUIET_LINK)$(CC) $(CFLAGS) -shared -nostartfiles -o $@ $< | ||
| 205 | 222 | ||
| 206 | define make_version.h | 223 | define make_version.h |
| 207 | (echo '/* This file is automatically generated. Do not modify. */'; \ | 224 | (echo '/* This file is automatically generated. Do not modify. */'; \ |
| 208 | echo \#define VERSION_CODE $(shell \ | 225 | echo \#define VERSION_CODE $(shell \ |
| 209 | expr $(VERSION) \* 256 + $(PATCHLEVEL)); \ | 226 | expr $(VERSION) \* 256 + $(PATCHLEVEL)); \ |
| 210 | echo '#define EXTRAVERSION ' $(EXTRAVERSION); \ | 227 | echo '#define EXTRAVERSION ' $(EXTRAVERSION); \ |
| 211 | echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"'; \ | 228 | echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"'; \ |
| 212 | echo '#define FILE_VERSION '$(FILE_VERSION); \ | 229 | echo '#define FILE_VERSION '$(FILE_VERSION); \ |
| 213 | ) > $1 | 230 | ) > $1 |
| 214 | endef | 231 | endef |
| 215 | 232 | ||
| 216 | define update_version.h | 233 | define update_version.h |
| 217 | ($(call make_version.h, $@.tmp); \ | 234 | ($(call make_version.h, $@.tmp); \ |
| 218 | if [ -r $@ ] && cmp -s $@ $@.tmp; then \ | 235 | if [ -r $@ ] && cmp -s $@ $@.tmp; then \ |
| 219 | rm -f $@.tmp; \ | 236 | rm -f $@.tmp; \ |
| 220 | else \ | 237 | else \ |
| 221 | echo ' UPDATE $@'; \ | 238 | echo ' UPDATE $@'; \ |
| 222 | mv -f $@.tmp $@; \ | 239 | mv -f $@.tmp $@; \ |
| 223 | fi); | 240 | fi); |
| 224 | endef | 241 | endef |
| 225 | 242 | ||
| 226 | ep_version.h: force | 243 | ep_version.h: force |
| @@ -229,13 +246,13 @@ ep_version.h: force | |||
| 229 | VERSION_FILES = ep_version.h | 246 | VERSION_FILES = ep_version.h |
| 230 | 247 | ||
| 231 | define update_dir | 248 | define update_dir |
| 232 | (echo $1 > $@.tmp; \ | 249 | (echo $1 > $@.tmp; \ |
| 233 | if [ -r $@ ] && cmp -s $@ $@.tmp; then \ | 250 | if [ -r $@ ] && cmp -s $@ $@.tmp; then \ |
| 234 | rm -f $@.tmp; \ | 251 | rm -f $@.tmp; \ |
| 235 | else \ | 252 | else \ |
| 236 | echo ' UPDATE $@'; \ | 253 | echo ' UPDATE $@'; \ |
| 237 | mv -f $@.tmp $@; \ | 254 | mv -f $@.tmp $@; \ |
| 238 | fi); | 255 | fi); |
| 239 | endef | 256 | endef |
| 240 | 257 | ||
| 241 | ## make deps | 258 | ## make deps |
| @@ -245,10 +262,10 @@ all_deps := $(all_objs:%.o=.%.d) | |||
| 245 | 262 | ||
| 246 | # let .d file also depends on the source and header files | 263 | # let .d file also depends on the source and header files |
| 247 | define check_deps | 264 | define check_deps |
| 248 | @set -e; $(RM) $@; \ | 265 | @set -e; $(RM) $@; \ |
| 249 | $(CC) -MM $(CFLAGS) $< > $@.$$$$; \ | 266 | $(CC) -MM $(CFLAGS) $< > $@.$$$$; \ |
| 250 | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ | 267 | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ |
| 251 | $(RM) $@.$$$$ | 268 | $(RM) $@.$$$$ |
| 252 | endef | 269 | endef |
| 253 | 270 | ||
| 254 | $(all_deps): .%.d: $(src)/%.c | 271 | $(all_deps): .%.d: $(src)/%.c |
| @@ -283,27 +300,41 @@ TAGS: force | |||
| 283 | --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' | 300 | --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' |
| 284 | 301 | ||
| 285 | define do_install | 302 | define do_install |
| 286 | $(print_install) \ | ||
| 287 | if [ ! -d '$(DESTDIR_SQ)$2' ]; then \ | 303 | if [ ! -d '$(DESTDIR_SQ)$2' ]; then \ |
| 288 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \ | 304 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \ |
| 289 | fi; \ | 305 | fi; \ |
| 290 | $(INSTALL) $1 '$(DESTDIR_SQ)$2' | 306 | $(INSTALL) $1 '$(DESTDIR_SQ)$2' |
| 291 | endef | 307 | endef |
| 292 | 308 | ||
| 293 | install_lib: all_cmd | 309 | define do_install_plugins |
| 294 | $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ)) | 310 | for plugin in $1; do \ |
| 311 | $(call do_install,$$plugin,$(plugin_dir_SQ)); \ | ||
| 312 | done | ||
| 313 | endef | ||
| 314 | |||
| 315 | install_lib: all_cmd install_plugins | ||
| 316 | $(call QUIET_INSTALL, $(LIB_FILE)) \ | ||
| 317 | $(call do_install,$(LIB_FILE),$(bindir_SQ)) | ||
| 318 | |||
| 319 | install_plugins: $(PLUGINS) | ||
| 320 | $(call QUIET_INSTALL, trace_plugins) \ | ||
| 321 | $(call do_install_plugins, $(PLUGINS)) | ||
| 295 | 322 | ||
| 296 | install: install_lib | 323 | install: install_lib |
| 297 | 324 | ||
| 298 | clean: | 325 | clean: |
| 299 | $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d | 326 | $(call QUIET_CLEAN, libtraceevent) \ |
| 300 | $(RM) TRACEEVENT-CFLAGS tags TAGS | 327 | $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d \ |
| 328 | $(RM) TRACEEVENT-CFLAGS tags TAGS | ||
| 301 | 329 | ||
| 302 | endif # skip-makefile | 330 | endif # skip-makefile |
| 303 | 331 | ||
| 304 | PHONY += force | 332 | PHONY += force plugins |
| 305 | force: | 333 | force: |
| 306 | 334 | ||
| 335 | plugins: | ||
| 336 | @echo > /dev/null | ||
| 337 | |||
| 307 | # Declare the contents of the .PHONY variable as phony. We keep that | 338 | # Declare the contents of the .PHONY variable as phony. We keep that |
| 308 | # information in a variable so we can use it in if_changed and friends. | 339 | # information in a variable so we can use it in if_changed and friends. |
| 309 | .PHONY: $(PHONY) | 340 | .PHONY: $(PHONY) |
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 217c82ee3665..2ce565a73dd5 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
| @@ -2710,7 +2710,6 @@ process_func_handler(struct event_format *event, struct pevent_function_handler | |||
| 2710 | struct print_arg *farg; | 2710 | struct print_arg *farg; |
| 2711 | enum event_type type; | 2711 | enum event_type type; |
| 2712 | char *token; | 2712 | char *token; |
| 2713 | const char *test; | ||
| 2714 | int i; | 2713 | int i; |
| 2715 | 2714 | ||
| 2716 | arg->type = PRINT_FUNC; | 2715 | arg->type = PRINT_FUNC; |
| @@ -2727,15 +2726,19 @@ process_func_handler(struct event_format *event, struct pevent_function_handler | |||
| 2727 | } | 2726 | } |
| 2728 | 2727 | ||
| 2729 | type = process_arg(event, farg, &token); | 2728 | type = process_arg(event, farg, &token); |
| 2730 | if (i < (func->nr_args - 1)) | 2729 | if (i < (func->nr_args - 1)) { |
| 2731 | test = ","; | 2730 | if (type != EVENT_DELIM || strcmp(token, ",") != 0) { |
| 2732 | else | 2731 | warning("Error: function '%s()' expects %d arguments but event %s only uses %d", |
| 2733 | test = ")"; | 2732 | func->name, func->nr_args, |
| 2734 | 2733 | event->name, i + 1); | |
| 2735 | if (test_type_token(type, token, EVENT_DELIM, test)) { | 2734 | goto err; |
| 2736 | free_arg(farg); | 2735 | } |
| 2737 | free_token(token); | 2736 | } else { |
| 2738 | return EVENT_ERROR; | 2737 | if (type != EVENT_DELIM || strcmp(token, ")") != 0) { |
| 2738 | warning("Error: function '%s()' only expects %d arguments but event %s has more", | ||
| 2739 | func->name, func->nr_args, event->name); | ||
| 2740 | goto err; | ||
| 2741 | } | ||
| 2739 | } | 2742 | } |
| 2740 | 2743 | ||
| 2741 | *next_arg = farg; | 2744 | *next_arg = farg; |
| @@ -2747,6 +2750,11 @@ process_func_handler(struct event_format *event, struct pevent_function_handler | |||
| 2747 | *tok = token; | 2750 | *tok = token; |
| 2748 | 2751 | ||
| 2749 | return type; | 2752 | return type; |
| 2753 | |||
| 2754 | err: | ||
| 2755 | free_arg(farg); | ||
| 2756 | free_token(token); | ||
| 2757 | return EVENT_ERROR; | ||
| 2750 | } | 2758 | } |
| 2751 | 2759 | ||
| 2752 | static enum event_type | 2760 | static enum event_type |
| @@ -4099,6 +4107,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event | |||
| 4099 | unsigned long long val; | 4107 | unsigned long long val; |
| 4100 | struct func_map *func; | 4108 | struct func_map *func; |
| 4101 | const char *saveptr; | 4109 | const char *saveptr; |
| 4110 | struct trace_seq p; | ||
| 4102 | char *bprint_fmt = NULL; | 4111 | char *bprint_fmt = NULL; |
| 4103 | char format[32]; | 4112 | char format[32]; |
| 4104 | int show_func; | 4113 | int show_func; |
| @@ -4306,8 +4315,12 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event | |||
| 4306 | format[len] = 0; | 4315 | format[len] = 0; |
| 4307 | if (!len_as_arg) | 4316 | if (!len_as_arg) |
| 4308 | len_arg = -1; | 4317 | len_arg = -1; |
| 4309 | print_str_arg(s, data, size, event, | 4318 | /* Use helper trace_seq */ |
| 4319 | trace_seq_init(&p); | ||
| 4320 | print_str_arg(&p, data, size, event, | ||
| 4310 | format, len_arg, arg); | 4321 | format, len_arg, arg); |
| 4322 | trace_seq_terminate(&p); | ||
| 4323 | trace_seq_puts(s, p.buffer); | ||
| 4311 | arg = arg->next; | 4324 | arg = arg->next; |
| 4312 | break; | 4325 | break; |
| 4313 | default: | 4326 | default: |
| @@ -5116,8 +5129,38 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, | |||
| 5116 | return ret; | 5129 | return ret; |
| 5117 | } | 5130 | } |
| 5118 | 5131 | ||
| 5132 | static enum pevent_errno | ||
| 5133 | __pevent_parse_event(struct pevent *pevent, | ||
| 5134 | struct event_format **eventp, | ||
| 5135 | const char *buf, unsigned long size, | ||
| 5136 | const char *sys) | ||
| 5137 | { | ||
| 5138 | int ret = __pevent_parse_format(eventp, pevent, buf, size, sys); | ||
| 5139 | struct event_format *event = *eventp; | ||
| 5140 | |||
| 5141 | if (event == NULL) | ||
| 5142 | return ret; | ||
| 5143 | |||
| 5144 | if (pevent && add_event(pevent, event)) { | ||
| 5145 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 5146 | goto event_add_failed; | ||
| 5147 | } | ||
| 5148 | |||
| 5149 | #define PRINT_ARGS 0 | ||
| 5150 | if (PRINT_ARGS && event->print_fmt.args) | ||
| 5151 | print_args(event->print_fmt.args); | ||
| 5152 | |||
| 5153 | return 0; | ||
| 5154 | |||
| 5155 | event_add_failed: | ||
| 5156 | pevent_free_format(event); | ||
| 5157 | return ret; | ||
| 5158 | } | ||
| 5159 | |||
| 5119 | /** | 5160 | /** |
| 5120 | * pevent_parse_format - parse the event format | 5161 | * pevent_parse_format - parse the event format |
| 5162 | * @pevent: the handle to the pevent | ||
| 5163 | * @eventp: returned format | ||
| 5121 | * @buf: the buffer storing the event format string | 5164 | * @buf: the buffer storing the event format string |
| 5122 | * @size: the size of @buf | 5165 | * @size: the size of @buf |
| 5123 | * @sys: the system the event belongs to | 5166 | * @sys: the system the event belongs to |
| @@ -5129,10 +5172,12 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, | |||
| 5129 | * | 5172 | * |
| 5130 | * /sys/kernel/debug/tracing/events/.../.../format | 5173 | * /sys/kernel/debug/tracing/events/.../.../format |
| 5131 | */ | 5174 | */ |
| 5132 | enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf, | 5175 | enum pevent_errno pevent_parse_format(struct pevent *pevent, |
| 5176 | struct event_format **eventp, | ||
| 5177 | const char *buf, | ||
| 5133 | unsigned long size, const char *sys) | 5178 | unsigned long size, const char *sys) |
| 5134 | { | 5179 | { |
| 5135 | return __pevent_parse_format(eventp, NULL, buf, size, sys); | 5180 | return __pevent_parse_event(pevent, eventp, buf, size, sys); |
| 5136 | } | 5181 | } |
| 5137 | 5182 | ||
| 5138 | /** | 5183 | /** |
| @@ -5153,25 +5198,7 @@ enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, | |||
| 5153 | unsigned long size, const char *sys) | 5198 | unsigned long size, const char *sys) |
| 5154 | { | 5199 | { |
| 5155 | struct event_format *event = NULL; | 5200 | struct event_format *event = NULL; |
| 5156 | int ret = __pevent_parse_format(&event, pevent, buf, size, sys); | 5201 | return __pevent_parse_event(pevent, &event, buf, size, sys); |
| 5157 | |||
| 5158 | if (event == NULL) | ||
| 5159 | return ret; | ||
| 5160 | |||
| 5161 | if (add_event(pevent, event)) { | ||
| 5162 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 5163 | goto event_add_failed; | ||
| 5164 | } | ||
| 5165 | |||
| 5166 | #define PRINT_ARGS 0 | ||
| 5167 | if (PRINT_ARGS && event->print_fmt.args) | ||
| 5168 | print_args(event->print_fmt.args); | ||
| 5169 | |||
| 5170 | return 0; | ||
| 5171 | |||
| 5172 | event_add_failed: | ||
| 5173 | pevent_free_format(event); | ||
| 5174 | return ret; | ||
| 5175 | } | 5202 | } |
| 5176 | 5203 | ||
| 5177 | #undef _PE | 5204 | #undef _PE |
| @@ -5203,22 +5230,7 @@ int pevent_strerror(struct pevent *pevent __maybe_unused, | |||
| 5203 | 5230 | ||
| 5204 | idx = errnum - __PEVENT_ERRNO__START - 1; | 5231 | idx = errnum - __PEVENT_ERRNO__START - 1; |
| 5205 | msg = pevent_error_str[idx]; | 5232 | msg = pevent_error_str[idx]; |
| 5206 | 5233 | snprintf(buf, buflen, "%s", msg); | |
| 5207 | switch (errnum) { | ||
| 5208 | case PEVENT_ERRNO__MEM_ALLOC_FAILED: | ||
| 5209 | case PEVENT_ERRNO__PARSE_EVENT_FAILED: | ||
| 5210 | case PEVENT_ERRNO__READ_ID_FAILED: | ||
| 5211 | case PEVENT_ERRNO__READ_FORMAT_FAILED: | ||
| 5212 | case PEVENT_ERRNO__READ_PRINT_FAILED: | ||
| 5213 | case PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED: | ||
| 5214 | case PEVENT_ERRNO__INVALID_ARG_TYPE: | ||
| 5215 | snprintf(buf, buflen, "%s", msg); | ||
| 5216 | break; | ||
| 5217 | |||
| 5218 | default: | ||
| 5219 | /* cannot reach here */ | ||
| 5220 | break; | ||
| 5221 | } | ||
| 5222 | 5234 | ||
| 5223 | return 0; | 5235 | return 0; |
| 5224 | } | 5236 | } |
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 8d73d2594f65..cf5db9013f2c 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)) |
| @@ -355,12 +356,35 @@ enum pevent_flag { | |||
| 355 | _PE(READ_FORMAT_FAILED, "failed to read event format"), \ | 356 | _PE(READ_FORMAT_FAILED, "failed to read event format"), \ |
| 356 | _PE(READ_PRINT_FAILED, "failed to read event print fmt"), \ | 357 | _PE(READ_PRINT_FAILED, "failed to read event print fmt"), \ |
| 357 | _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\ | 358 | _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\ |
| 358 | _PE(INVALID_ARG_TYPE, "invalid argument type") | 359 | _PE(INVALID_ARG_TYPE, "invalid argument type"), \ |
| 360 | _PE(INVALID_EXP_TYPE, "invalid expression type"), \ | ||
| 361 | _PE(INVALID_OP_TYPE, "invalid operator type"), \ | ||
| 362 | _PE(INVALID_EVENT_NAME, "invalid event name"), \ | ||
| 363 | _PE(EVENT_NOT_FOUND, "no event found"), \ | ||
| 364 | _PE(SYNTAX_ERROR, "syntax error"), \ | ||
| 365 | _PE(ILLEGAL_RVALUE, "illegal rvalue"), \ | ||
| 366 | _PE(ILLEGAL_LVALUE, "illegal lvalue for string comparison"), \ | ||
| 367 | _PE(INVALID_REGEX, "regex did not compute"), \ | ||
| 368 | _PE(ILLEGAL_STRING_CMP, "illegal comparison for string"), \ | ||
| 369 | _PE(ILLEGAL_INTEGER_CMP,"illegal comparison for integer"), \ | ||
| 370 | _PE(REPARENT_NOT_OP, "cannot reparent other than OP"), \ | ||
| 371 | _PE(REPARENT_FAILED, "failed to reparent filter OP"), \ | ||
| 372 | _PE(BAD_FILTER_ARG, "bad arg in filter tree"), \ | ||
| 373 | _PE(UNEXPECTED_TYPE, "unexpected type (not a value)"), \ | ||
| 374 | _PE(ILLEGAL_TOKEN, "illegal token"), \ | ||
| 375 | _PE(INVALID_PAREN, "open parenthesis cannot come here"), \ | ||
| 376 | _PE(UNBALANCED_PAREN, "unbalanced number of parenthesis"), \ | ||
| 377 | _PE(UNKNOWN_TOKEN, "unknown token"), \ | ||
| 378 | _PE(FILTER_NOT_FOUND, "no filter found"), \ | ||
| 379 | _PE(NOT_A_NUMBER, "must have number field"), \ | ||
| 380 | _PE(NO_FILTER, "no filters exists"), \ | ||
| 381 | _PE(FILTER_MISS, "record does not match to filter") | ||
| 359 | 382 | ||
| 360 | #undef _PE | 383 | #undef _PE |
| 361 | #define _PE(__code, __str) PEVENT_ERRNO__ ## __code | 384 | #define _PE(__code, __str) PEVENT_ERRNO__ ## __code |
| 362 | enum pevent_errno { | 385 | enum pevent_errno { |
| 363 | PEVENT_ERRNO__SUCCESS = 0, | 386 | PEVENT_ERRNO__SUCCESS = 0, |
| 387 | PEVENT_ERRNO__FILTER_MATCH = PEVENT_ERRNO__SUCCESS, | ||
| 364 | 388 | ||
| 365 | /* | 389 | /* |
| 366 | * Choose an arbitrary negative big number not to clash with standard | 390 | * Choose an arbitrary negative big number not to clash with standard |
| @@ -377,6 +401,11 @@ enum pevent_errno { | |||
| 377 | }; | 401 | }; |
| 378 | #undef _PE | 402 | #undef _PE |
| 379 | 403 | ||
| 404 | struct plugin_list; | ||
| 405 | |||
| 406 | struct plugin_list *traceevent_load_plugins(struct pevent *pevent); | ||
| 407 | void traceevent_unload_plugins(struct plugin_list *plugin_list); | ||
| 408 | |||
| 380 | struct cmdline; | 409 | struct cmdline; |
| 381 | struct cmdline_list; | 410 | struct cmdline_list; |
| 382 | struct func_map; | 411 | struct func_map; |
| @@ -522,6 +551,15 @@ __data2host8(struct pevent *pevent, unsigned long long data) | |||
| 522 | __data2host8(pevent, __val); \ | 551 | __data2host8(pevent, __val); \ |
| 523 | }) | 552 | }) |
| 524 | 553 | ||
| 554 | static inline int traceevent_host_bigendian(void) | ||
| 555 | { | ||
| 556 | unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 }; | ||
| 557 | unsigned int val; | ||
| 558 | |||
| 559 | memcpy(&val, str, 4); | ||
| 560 | return val == 0x01020304; | ||
| 561 | } | ||
| 562 | |||
| 525 | /* taken from kernel/trace/trace.h */ | 563 | /* taken from kernel/trace/trace.h */ |
| 526 | enum trace_flag_type { | 564 | enum trace_flag_type { |
| 527 | TRACE_FLAG_IRQS_OFF = 0x01, | 565 | TRACE_FLAG_IRQS_OFF = 0x01, |
| @@ -547,7 +585,9 @@ int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long siz | |||
| 547 | 585 | ||
| 548 | enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, | 586 | enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, |
| 549 | unsigned long size, const char *sys); | 587 | unsigned long size, const char *sys); |
| 550 | enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf, | 588 | enum pevent_errno pevent_parse_format(struct pevent *pevent, |
| 589 | struct event_format **eventp, | ||
| 590 | const char *buf, | ||
| 551 | unsigned long size, const char *sys); | 591 | unsigned long size, const char *sys); |
| 552 | void pevent_free_format(struct event_format *event); | 592 | void pevent_free_format(struct event_format *event); |
| 553 | 593 | ||
| @@ -811,18 +851,22 @@ struct filter_type { | |||
| 811 | struct filter_arg *filter; | 851 | struct filter_arg *filter; |
| 812 | }; | 852 | }; |
| 813 | 853 | ||
| 854 | #define PEVENT_FILTER_ERROR_BUFSZ 1024 | ||
| 855 | |||
| 814 | struct event_filter { | 856 | struct event_filter { |
| 815 | struct pevent *pevent; | 857 | struct pevent *pevent; |
| 816 | int filters; | 858 | int filters; |
| 817 | struct filter_type *event_filters; | 859 | struct filter_type *event_filters; |
| 860 | char error_buffer[PEVENT_FILTER_ERROR_BUFSZ]; | ||
| 818 | }; | 861 | }; |
| 819 | 862 | ||
| 820 | struct event_filter *pevent_filter_alloc(struct pevent *pevent); | 863 | struct event_filter *pevent_filter_alloc(struct pevent *pevent); |
| 821 | 864 | ||
| 822 | #define FILTER_NONE -2 | 865 | /* for backward compatibility */ |
| 823 | #define FILTER_NOEXIST -1 | 866 | #define FILTER_NONE PEVENT_ERRNO__FILTER_NOT_FOUND |
| 824 | #define FILTER_MISS 0 | 867 | #define FILTER_NOEXIST PEVENT_ERRNO__NO_FILTER |
| 825 | #define FILTER_MATCH 1 | 868 | #define FILTER_MISS PEVENT_ERRNO__FILTER_MISS |
| 869 | #define FILTER_MATCH PEVENT_ERRNO__FILTER_MATCH | ||
| 826 | 870 | ||
| 827 | enum filter_trivial_type { | 871 | enum filter_trivial_type { |
| 828 | FILTER_TRIVIAL_FALSE, | 872 | FILTER_TRIVIAL_FALSE, |
| @@ -830,20 +874,21 @@ enum filter_trivial_type { | |||
| 830 | FILTER_TRIVIAL_BOTH, | 874 | FILTER_TRIVIAL_BOTH, |
| 831 | }; | 875 | }; |
| 832 | 876 | ||
| 833 | int pevent_filter_add_filter_str(struct event_filter *filter, | 877 | enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, |
| 834 | const char *filter_str, | 878 | const char *filter_str); |
| 835 | char **error_str); | ||
| 836 | 879 | ||
| 880 | enum pevent_errno pevent_filter_match(struct event_filter *filter, | ||
| 881 | struct pevent_record *record); | ||
| 837 | 882 | ||
| 838 | int pevent_filter_match(struct event_filter *filter, | 883 | int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err, |
| 839 | struct pevent_record *record); | 884 | char *buf, size_t buflen); |
| 840 | 885 | ||
| 841 | int pevent_event_filtered(struct event_filter *filter, | 886 | int pevent_event_filtered(struct event_filter *filter, |
| 842 | int event_id); | 887 | int event_id); |
| 843 | 888 | ||
| 844 | void pevent_filter_reset(struct event_filter *filter); | 889 | void pevent_filter_reset(struct event_filter *filter); |
| 845 | 890 | ||
| 846 | void pevent_filter_clear_trivial(struct event_filter *filter, | 891 | int pevent_filter_clear_trivial(struct event_filter *filter, |
| 847 | enum filter_trivial_type type); | 892 | enum filter_trivial_type type); |
| 848 | 893 | ||
| 849 | void pevent_filter_free(struct event_filter *filter); | 894 | void pevent_filter_free(struct event_filter *filter); |
diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c new file mode 100644 index 000000000000..125f5676bcb5 --- /dev/null +++ b/tools/lib/traceevent/event-plugin.c | |||
| @@ -0,0 +1,215 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; | ||
| 8 | * version 2.1 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
| 17 | * | ||
| 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <string.h> | ||
| 22 | #include <dlfcn.h> | ||
| 23 | #include <stdlib.h> | ||
| 24 | #include <sys/types.h> | ||
| 25 | #include <sys/stat.h> | ||
| 26 | #include <unistd.h> | ||
| 27 | #include <dirent.h> | ||
| 28 | #include "event-parse.h" | ||
| 29 | #include "event-utils.h" | ||
| 30 | |||
| 31 | #define LOCAL_PLUGIN_DIR ".traceevent/plugins" | ||
| 32 | |||
| 33 | struct plugin_list { | ||
| 34 | struct plugin_list *next; | ||
| 35 | char *name; | ||
| 36 | void *handle; | ||
| 37 | }; | ||
| 38 | |||
| 39 | static void | ||
| 40 | load_plugin(struct pevent *pevent, const char *path, | ||
| 41 | const char *file, void *data) | ||
| 42 | { | ||
| 43 | struct plugin_list **plugin_list = data; | ||
| 44 | pevent_plugin_load_func func; | ||
| 45 | struct plugin_list *list; | ||
| 46 | const char *alias; | ||
| 47 | char *plugin; | ||
| 48 | void *handle; | ||
| 49 | |||
| 50 | plugin = malloc(strlen(path) + strlen(file) + 2); | ||
| 51 | if (!plugin) { | ||
| 52 | warning("could not allocate plugin memory\n"); | ||
| 53 | return; | ||
| 54 | } | ||
| 55 | |||
| 56 | strcpy(plugin, path); | ||
| 57 | strcat(plugin, "/"); | ||
| 58 | strcat(plugin, file); | ||
| 59 | |||
| 60 | handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL); | ||
| 61 | if (!handle) { | ||
| 62 | warning("could not load plugin '%s'\n%s\n", | ||
| 63 | plugin, dlerror()); | ||
| 64 | goto out_free; | ||
| 65 | } | ||
| 66 | |||
| 67 | alias = dlsym(handle, PEVENT_PLUGIN_ALIAS_NAME); | ||
| 68 | if (!alias) | ||
| 69 | alias = file; | ||
| 70 | |||
| 71 | func = dlsym(handle, PEVENT_PLUGIN_LOADER_NAME); | ||
| 72 | if (!func) { | ||
| 73 | warning("could not find func '%s' in plugin '%s'\n%s\n", | ||
| 74 | PEVENT_PLUGIN_LOADER_NAME, plugin, dlerror()); | ||
| 75 | goto out_free; | ||
| 76 | } | ||
| 77 | |||
| 78 | list = malloc(sizeof(*list)); | ||
| 79 | if (!list) { | ||
| 80 | warning("could not allocate plugin memory\n"); | ||
| 81 | goto out_free; | ||
| 82 | } | ||
| 83 | |||
| 84 | list->next = *plugin_list; | ||
| 85 | list->handle = handle; | ||
| 86 | list->name = plugin; | ||
| 87 | *plugin_list = list; | ||
| 88 | |||
| 89 | pr_stat("registering plugin: %s", plugin); | ||
| 90 | func(pevent); | ||
| 91 | return; | ||
| 92 | |||
| 93 | out_free: | ||
| 94 | free(plugin); | ||
| 95 | } | ||
| 96 | |||
| 97 | static void | ||
| 98 | load_plugins_dir(struct pevent *pevent, const char *suffix, | ||
| 99 | const char *path, | ||
| 100 | void (*load_plugin)(struct pevent *pevent, | ||
| 101 | const char *path, | ||
| 102 | const char *name, | ||
| 103 | void *data), | ||
| 104 | void *data) | ||
| 105 | { | ||
| 106 | struct dirent *dent; | ||
| 107 | struct stat st; | ||
| 108 | DIR *dir; | ||
| 109 | int ret; | ||
| 110 | |||
| 111 | ret = stat(path, &st); | ||
| 112 | if (ret < 0) | ||
| 113 | return; | ||
| 114 | |||
| 115 | if (!S_ISDIR(st.st_mode)) | ||
| 116 | return; | ||
| 117 | |||
| 118 | dir = opendir(path); | ||
| 119 | if (!dir) | ||
| 120 | return; | ||
| 121 | |||
| 122 | while ((dent = readdir(dir))) { | ||
| 123 | const char *name = dent->d_name; | ||
| 124 | |||
| 125 | if (strcmp(name, ".") == 0 || | ||
| 126 | strcmp(name, "..") == 0) | ||
| 127 | continue; | ||
| 128 | |||
| 129 | /* Only load plugins that end in suffix */ | ||
| 130 | if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0) | ||
| 131 | continue; | ||
| 132 | |||
| 133 | load_plugin(pevent, path, name, data); | ||
| 134 | } | ||
| 135 | |||
| 136 | closedir(dir); | ||
| 137 | } | ||
| 138 | |||
| 139 | static void | ||
| 140 | load_plugins(struct pevent *pevent, const char *suffix, | ||
| 141 | void (*load_plugin)(struct pevent *pevent, | ||
| 142 | const char *path, | ||
| 143 | const char *name, | ||
| 144 | void *data), | ||
| 145 | void *data) | ||
| 146 | { | ||
| 147 | char *home; | ||
| 148 | char *path; | ||
| 149 | char *envdir; | ||
| 150 | |||
| 151 | /* | ||
| 152 | * If a system plugin directory was defined, | ||
| 153 | * check that first. | ||
| 154 | */ | ||
| 155 | #ifdef PLUGIN_DIR | ||
| 156 | load_plugins_dir(pevent, suffix, PLUGIN_DIR, load_plugin, data); | ||
| 157 | #endif | ||
| 158 | |||
| 159 | /* | ||
| 160 | * Next let the environment-set plugin directory | ||
| 161 | * override the system defaults. | ||
| 162 | */ | ||
| 163 | envdir = getenv("TRACEEVENT_PLUGIN_DIR"); | ||
| 164 | if (envdir) | ||
| 165 | load_plugins_dir(pevent, suffix, envdir, load_plugin, data); | ||
| 166 | |||
| 167 | /* | ||
| 168 | * Now let the home directory override the environment | ||
| 169 | * or system defaults. | ||
| 170 | */ | ||
| 171 | home = getenv("HOME"); | ||
| 172 | if (!home) | ||
| 173 | return; | ||
| 174 | |||
| 175 | path = malloc(strlen(home) + strlen(LOCAL_PLUGIN_DIR) + 2); | ||
| 176 | if (!path) { | ||
| 177 | warning("could not allocate plugin memory\n"); | ||
| 178 | return; | ||
| 179 | } | ||
| 180 | |||
| 181 | strcpy(path, home); | ||
| 182 | strcat(path, "/"); | ||
| 183 | strcat(path, LOCAL_PLUGIN_DIR); | ||
| 184 | |||
| 185 | load_plugins_dir(pevent, suffix, path, load_plugin, data); | ||
| 186 | |||
| 187 | free(path); | ||
| 188 | } | ||
| 189 | |||
| 190 | struct plugin_list* | ||
| 191 | traceevent_load_plugins(struct pevent *pevent) | ||
| 192 | { | ||
| 193 | struct plugin_list *list = NULL; | ||
| 194 | |||
| 195 | load_plugins(pevent, ".so", load_plugin, &list); | ||
| 196 | return list; | ||
| 197 | } | ||
| 198 | |||
| 199 | void | ||
| 200 | traceevent_unload_plugins(struct plugin_list *plugin_list) | ||
| 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(); | ||
| 211 | dlclose(list->handle); | ||
| 212 | free(list->name); | ||
| 213 | free(list); | ||
| 214 | } | ||
| 215 | } | ||
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index 2500e75583fc..b50234402fc2 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c | |||
| @@ -38,41 +38,31 @@ struct event_list { | |||
| 38 | struct event_format *event; | 38 | struct event_format *event; |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | #define MAX_ERR_STR_SIZE 256 | 41 | static void show_error(char *error_buf, const char *fmt, ...) |
| 42 | |||
| 43 | static void show_error(char **error_str, const char *fmt, ...) | ||
| 44 | { | 42 | { |
| 45 | unsigned long long index; | 43 | unsigned long long index; |
| 46 | const char *input; | 44 | const char *input; |
| 47 | char *error; | ||
| 48 | va_list ap; | 45 | va_list ap; |
| 49 | int len; | 46 | int len; |
| 50 | int i; | 47 | int i; |
| 51 | 48 | ||
| 52 | if (!error_str) | ||
| 53 | return; | ||
| 54 | |||
| 55 | input = pevent_get_input_buf(); | 49 | input = pevent_get_input_buf(); |
| 56 | index = pevent_get_input_buf_ptr(); | 50 | index = pevent_get_input_buf_ptr(); |
| 57 | len = input ? strlen(input) : 0; | 51 | len = input ? strlen(input) : 0; |
| 58 | 52 | ||
| 59 | error = malloc_or_die(MAX_ERR_STR_SIZE + (len*2) + 3); | ||
| 60 | |||
| 61 | if (len) { | 53 | if (len) { |
| 62 | strcpy(error, input); | 54 | strcpy(error_buf, input); |
| 63 | error[len] = '\n'; | 55 | error_buf[len] = '\n'; |
| 64 | for (i = 1; i < len && i < index; i++) | 56 | for (i = 1; i < len && i < index; i++) |
| 65 | error[len+i] = ' '; | 57 | error_buf[len+i] = ' '; |
| 66 | error[len + i] = '^'; | 58 | error_buf[len + i] = '^'; |
| 67 | error[len + i + 1] = '\n'; | 59 | error_buf[len + i + 1] = '\n'; |
| 68 | len += i+2; | 60 | len += i+2; |
| 69 | } | 61 | } |
| 70 | 62 | ||
| 71 | va_start(ap, fmt); | 63 | va_start(ap, fmt); |
| 72 | vsnprintf(error + len, MAX_ERR_STR_SIZE, fmt, ap); | 64 | vsnprintf(error_buf + len, PEVENT_FILTER_ERROR_BUFSZ - len, fmt, ap); |
| 73 | va_end(ap); | 65 | va_end(ap); |
| 74 | |||
| 75 | *error_str = error; | ||
| 76 | } | 66 | } |
| 77 | 67 | ||
| 78 | static void free_token(char *token) | 68 | static void free_token(char *token) |
| @@ -95,7 +85,11 @@ static enum event_type read_token(char **tok) | |||
| 95 | (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) && | 85 | (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) && |
| 96 | pevent_peek_char() == '~') { | 86 | pevent_peek_char() == '~') { |
| 97 | /* append it */ | 87 | /* append it */ |
| 98 | *tok = malloc_or_die(3); | 88 | *tok = malloc(3); |
| 89 | if (*tok == NULL) { | ||
| 90 | free_token(token); | ||
| 91 | return EVENT_ERROR; | ||
| 92 | } | ||
| 99 | sprintf(*tok, "%c%c", *token, '~'); | 93 | sprintf(*tok, "%c%c", *token, '~'); |
| 100 | free_token(token); | 94 | free_token(token); |
| 101 | /* Now remove the '~' from the buffer */ | 95 | /* Now remove the '~' from the buffer */ |
| @@ -147,11 +141,13 @@ add_filter_type(struct event_filter *filter, int id) | |||
| 147 | if (filter_type) | 141 | if (filter_type) |
| 148 | return filter_type; | 142 | return filter_type; |
| 149 | 143 | ||
| 150 | filter->event_filters = realloc(filter->event_filters, | 144 | filter_type = realloc(filter->event_filters, |
| 151 | sizeof(*filter->event_filters) * | 145 | sizeof(*filter->event_filters) * |
| 152 | (filter->filters + 1)); | 146 | (filter->filters + 1)); |
| 153 | if (!filter->event_filters) | 147 | if (!filter_type) |
| 154 | die("Could not allocate filter"); | 148 | return NULL; |
| 149 | |||
| 150 | filter->event_filters = filter_type; | ||
| 155 | 151 | ||
| 156 | for (i = 0; i < filter->filters; i++) { | 152 | for (i = 0; i < filter->filters; i++) { |
| 157 | if (filter->event_filters[i].event_id > id) | 153 | if (filter->event_filters[i].event_id > id) |
| @@ -182,7 +178,10 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent) | |||
| 182 | { | 178 | { |
| 183 | struct event_filter *filter; | 179 | struct event_filter *filter; |
| 184 | 180 | ||
| 185 | filter = malloc_or_die(sizeof(*filter)); | 181 | filter = malloc(sizeof(*filter)); |
| 182 | if (filter == NULL) | ||
| 183 | return NULL; | ||
| 184 | |||
| 186 | memset(filter, 0, sizeof(*filter)); | 185 | memset(filter, 0, sizeof(*filter)); |
| 187 | filter->pevent = pevent; | 186 | filter->pevent = pevent; |
| 188 | pevent_ref(pevent); | 187 | pevent_ref(pevent); |
| @@ -192,12 +191,7 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent) | |||
| 192 | 191 | ||
| 193 | static struct filter_arg *allocate_arg(void) | 192 | static struct filter_arg *allocate_arg(void) |
| 194 | { | 193 | { |
| 195 | struct filter_arg *arg; | 194 | return calloc(1, sizeof(struct filter_arg)); |
| 196 | |||
| 197 | arg = malloc_or_die(sizeof(*arg)); | ||
| 198 | memset(arg, 0, sizeof(*arg)); | ||
| 199 | |||
| 200 | return arg; | ||
| 201 | } | 195 | } |
| 202 | 196 | ||
| 203 | static void free_arg(struct filter_arg *arg) | 197 | static void free_arg(struct filter_arg *arg) |
| @@ -242,15 +236,19 @@ static void free_arg(struct filter_arg *arg) | |||
| 242 | free(arg); | 236 | free(arg); |
| 243 | } | 237 | } |
| 244 | 238 | ||
| 245 | static void add_event(struct event_list **events, | 239 | static int add_event(struct event_list **events, |
| 246 | struct event_format *event) | 240 | struct event_format *event) |
| 247 | { | 241 | { |
| 248 | struct event_list *list; | 242 | struct event_list *list; |
| 249 | 243 | ||
| 250 | list = malloc_or_die(sizeof(*list)); | 244 | list = malloc(sizeof(*list)); |
| 245 | if (list == NULL) | ||
| 246 | return -1; | ||
| 247 | |||
| 251 | list->next = *events; | 248 | list->next = *events; |
| 252 | *events = list; | 249 | *events = list; |
| 253 | list->event = event; | 250 | list->event = event; |
| 251 | return 0; | ||
| 254 | } | 252 | } |
| 255 | 253 | ||
| 256 | static int event_match(struct event_format *event, | 254 | static int event_match(struct event_format *event, |
| @@ -265,7 +263,7 @@ static int event_match(struct event_format *event, | |||
| 265 | !regexec(ereg, event->name, 0, NULL, 0); | 263 | !regexec(ereg, event->name, 0, NULL, 0); |
| 266 | } | 264 | } |
| 267 | 265 | ||
| 268 | static int | 266 | static enum pevent_errno |
| 269 | find_event(struct pevent *pevent, struct event_list **events, | 267 | find_event(struct pevent *pevent, struct event_list **events, |
| 270 | char *sys_name, char *event_name) | 268 | char *sys_name, char *event_name) |
| 271 | { | 269 | { |
| @@ -273,6 +271,7 @@ find_event(struct pevent *pevent, struct event_list **events, | |||
| 273 | regex_t ereg; | 271 | regex_t ereg; |
| 274 | regex_t sreg; | 272 | regex_t sreg; |
| 275 | int match = 0; | 273 | int match = 0; |
| 274 | int fail = 0; | ||
| 276 | char *reg; | 275 | char *reg; |
| 277 | int ret; | 276 | int ret; |
| 278 | int i; | 277 | int i; |
| @@ -283,23 +282,31 @@ find_event(struct pevent *pevent, struct event_list **events, | |||
| 283 | sys_name = NULL; | 282 | sys_name = NULL; |
| 284 | } | 283 | } |
| 285 | 284 | ||
| 286 | reg = malloc_or_die(strlen(event_name) + 3); | 285 | reg = malloc(strlen(event_name) + 3); |
| 286 | if (reg == NULL) | ||
| 287 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 288 | |||
| 287 | sprintf(reg, "^%s$", event_name); | 289 | sprintf(reg, "^%s$", event_name); |
| 288 | 290 | ||
| 289 | ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB); | 291 | ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB); |
| 290 | free(reg); | 292 | free(reg); |
| 291 | 293 | ||
| 292 | if (ret) | 294 | if (ret) |
| 293 | return -1; | 295 | return PEVENT_ERRNO__INVALID_EVENT_NAME; |
| 294 | 296 | ||
| 295 | if (sys_name) { | 297 | if (sys_name) { |
| 296 | reg = malloc_or_die(strlen(sys_name) + 3); | 298 | reg = malloc(strlen(sys_name) + 3); |
| 299 | if (reg == NULL) { | ||
| 300 | regfree(&ereg); | ||
| 301 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 302 | } | ||
| 303 | |||
| 297 | sprintf(reg, "^%s$", sys_name); | 304 | sprintf(reg, "^%s$", sys_name); |
| 298 | ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB); | 305 | ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB); |
| 299 | free(reg); | 306 | free(reg); |
| 300 | if (ret) { | 307 | if (ret) { |
| 301 | regfree(&ereg); | 308 | regfree(&ereg); |
| 302 | return -1; | 309 | return PEVENT_ERRNO__INVALID_EVENT_NAME; |
| 303 | } | 310 | } |
| 304 | } | 311 | } |
| 305 | 312 | ||
| @@ -307,7 +314,10 @@ find_event(struct pevent *pevent, struct event_list **events, | |||
| 307 | event = pevent->events[i]; | 314 | event = pevent->events[i]; |
| 308 | if (event_match(event, sys_name ? &sreg : NULL, &ereg)) { | 315 | if (event_match(event, sys_name ? &sreg : NULL, &ereg)) { |
| 309 | match = 1; | 316 | match = 1; |
| 310 | add_event(events, event); | 317 | if (add_event(events, event) < 0) { |
| 318 | fail = 1; | ||
| 319 | break; | ||
| 320 | } | ||
| 311 | } | 321 | } |
| 312 | } | 322 | } |
| 313 | 323 | ||
| @@ -316,7 +326,9 @@ find_event(struct pevent *pevent, struct event_list **events, | |||
| 316 | regfree(&sreg); | 326 | regfree(&sreg); |
| 317 | 327 | ||
| 318 | if (!match) | 328 | if (!match) |
| 319 | return -1; | 329 | return PEVENT_ERRNO__EVENT_NOT_FOUND; |
| 330 | if (fail) | ||
| 331 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 320 | 332 | ||
| 321 | return 0; | 333 | return 0; |
| 322 | } | 334 | } |
| @@ -332,14 +344,18 @@ static void free_events(struct event_list *events) | |||
| 332 | } | 344 | } |
| 333 | } | 345 | } |
| 334 | 346 | ||
| 335 | static struct filter_arg * | 347 | static enum pevent_errno |
| 336 | create_arg_item(struct event_format *event, const char *token, | 348 | create_arg_item(struct event_format *event, const char *token, |
| 337 | enum event_type type, char **error_str) | 349 | enum event_type type, struct filter_arg **parg, char *error_str) |
| 338 | { | 350 | { |
| 339 | struct format_field *field; | 351 | struct format_field *field; |
| 340 | struct filter_arg *arg; | 352 | struct filter_arg *arg; |
| 341 | 353 | ||
| 342 | arg = allocate_arg(); | 354 | arg = allocate_arg(); |
| 355 | if (arg == NULL) { | ||
| 356 | show_error(error_str, "failed to allocate filter arg"); | ||
| 357 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 358 | } | ||
| 343 | 359 | ||
| 344 | switch (type) { | 360 | switch (type) { |
| 345 | 361 | ||
| @@ -349,8 +365,11 @@ create_arg_item(struct event_format *event, const char *token, | |||
| 349 | arg->value.type = | 365 | arg->value.type = |
| 350 | type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR; | 366 | type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR; |
| 351 | arg->value.str = strdup(token); | 367 | arg->value.str = strdup(token); |
| 352 | if (!arg->value.str) | 368 | if (!arg->value.str) { |
| 353 | die("malloc string"); | 369 | free_arg(arg); |
| 370 | show_error(error_str, "failed to allocate string filter arg"); | ||
| 371 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 372 | } | ||
| 354 | break; | 373 | break; |
| 355 | case EVENT_ITEM: | 374 | case EVENT_ITEM: |
| 356 | /* if it is a number, then convert it */ | 375 | /* if it is a number, then convert it */ |
| @@ -377,11 +396,11 @@ create_arg_item(struct event_format *event, const char *token, | |||
| 377 | break; | 396 | break; |
| 378 | default: | 397 | default: |
| 379 | free_arg(arg); | 398 | free_arg(arg); |
| 380 | show_error(error_str, "expected a value but found %s", | 399 | show_error(error_str, "expected a value but found %s", token); |
| 381 | token); | 400 | return PEVENT_ERRNO__UNEXPECTED_TYPE; |
| 382 | return NULL; | ||
| 383 | } | 401 | } |
| 384 | return arg; | 402 | *parg = arg; |
| 403 | return 0; | ||
| 385 | } | 404 | } |
| 386 | 405 | ||
| 387 | static struct filter_arg * | 406 | static struct filter_arg * |
| @@ -390,6 +409,9 @@ create_arg_op(enum filter_op_type btype) | |||
| 390 | struct filter_arg *arg; | 409 | struct filter_arg *arg; |
| 391 | 410 | ||
| 392 | arg = allocate_arg(); | 411 | arg = allocate_arg(); |
| 412 | if (!arg) | ||
| 413 | return NULL; | ||
| 414 | |||
| 393 | arg->type = FILTER_ARG_OP; | 415 | arg->type = FILTER_ARG_OP; |
| 394 | arg->op.type = btype; | 416 | arg->op.type = btype; |
| 395 | 417 | ||
| @@ -402,6 +424,9 @@ create_arg_exp(enum filter_exp_type etype) | |||
| 402 | struct filter_arg *arg; | 424 | struct filter_arg *arg; |
| 403 | 425 | ||
| 404 | arg = allocate_arg(); | 426 | arg = allocate_arg(); |
| 427 | if (!arg) | ||
| 428 | return NULL; | ||
| 429 | |||
| 405 | arg->type = FILTER_ARG_EXP; | 430 | arg->type = FILTER_ARG_EXP; |
| 406 | arg->op.type = etype; | 431 | arg->op.type = etype; |
| 407 | 432 | ||
| @@ -414,6 +439,9 @@ create_arg_cmp(enum filter_exp_type etype) | |||
| 414 | struct filter_arg *arg; | 439 | struct filter_arg *arg; |
| 415 | 440 | ||
| 416 | arg = allocate_arg(); | 441 | arg = allocate_arg(); |
| 442 | if (!arg) | ||
| 443 | return NULL; | ||
| 444 | |||
| 417 | /* Use NUM and change if necessary */ | 445 | /* Use NUM and change if necessary */ |
| 418 | arg->type = FILTER_ARG_NUM; | 446 | arg->type = FILTER_ARG_NUM; |
| 419 | arg->op.type = etype; | 447 | arg->op.type = etype; |
| @@ -421,8 +449,8 @@ create_arg_cmp(enum filter_exp_type etype) | |||
| 421 | return arg; | 449 | return arg; |
| 422 | } | 450 | } |
| 423 | 451 | ||
| 424 | static int add_right(struct filter_arg *op, struct filter_arg *arg, | 452 | static enum pevent_errno |
| 425 | char **error_str) | 453 | add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str) |
| 426 | { | 454 | { |
| 427 | struct filter_arg *left; | 455 | struct filter_arg *left; |
| 428 | char *str; | 456 | char *str; |
| @@ -453,9 +481,8 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
| 453 | case FILTER_ARG_FIELD: | 481 | case FILTER_ARG_FIELD: |
| 454 | break; | 482 | break; |
| 455 | default: | 483 | default: |
| 456 | show_error(error_str, | 484 | show_error(error_str, "Illegal rvalue"); |
| 457 | "Illegal rvalue"); | 485 | return PEVENT_ERRNO__ILLEGAL_RVALUE; |
| 458 | return -1; | ||
| 459 | } | 486 | } |
| 460 | 487 | ||
| 461 | /* | 488 | /* |
| @@ -502,7 +529,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
| 502 | if (left->type != FILTER_ARG_FIELD) { | 529 | if (left->type != FILTER_ARG_FIELD) { |
| 503 | show_error(error_str, | 530 | show_error(error_str, |
| 504 | "Illegal lvalue for string comparison"); | 531 | "Illegal lvalue for string comparison"); |
| 505 | return -1; | 532 | return PEVENT_ERRNO__ILLEGAL_LVALUE; |
| 506 | } | 533 | } |
| 507 | 534 | ||
| 508 | /* Make sure this is a valid string compare */ | 535 | /* Make sure this is a valid string compare */ |
| @@ -521,25 +548,31 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
| 521 | show_error(error_str, | 548 | show_error(error_str, |
| 522 | "RegEx '%s' did not compute", | 549 | "RegEx '%s' did not compute", |
| 523 | str); | 550 | str); |
| 524 | return -1; | 551 | return PEVENT_ERRNO__INVALID_REGEX; |
| 525 | } | 552 | } |
| 526 | break; | 553 | break; |
| 527 | default: | 554 | default: |
| 528 | show_error(error_str, | 555 | show_error(error_str, |
| 529 | "Illegal comparison for string"); | 556 | "Illegal comparison for string"); |
| 530 | return -1; | 557 | return PEVENT_ERRNO__ILLEGAL_STRING_CMP; |
| 531 | } | 558 | } |
| 532 | 559 | ||
| 533 | op->type = FILTER_ARG_STR; | 560 | op->type = FILTER_ARG_STR; |
| 534 | op->str.type = op_type; | 561 | op->str.type = op_type; |
| 535 | op->str.field = left->field.field; | 562 | op->str.field = left->field.field; |
| 536 | op->str.val = strdup(str); | 563 | op->str.val = strdup(str); |
| 537 | if (!op->str.val) | 564 | if (!op->str.val) { |
| 538 | die("malloc string"); | 565 | show_error(error_str, "Failed to allocate string filter"); |
| 566 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 567 | } | ||
| 539 | /* | 568 | /* |
| 540 | * Need a buffer to copy data for tests | 569 | * Need a buffer to copy data for tests |
| 541 | */ | 570 | */ |
| 542 | op->str.buffer = malloc_or_die(op->str.field->size + 1); | 571 | op->str.buffer = malloc(op->str.field->size + 1); |
| 572 | if (!op->str.buffer) { | ||
| 573 | show_error(error_str, "Failed to allocate string filter"); | ||
| 574 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 575 | } | ||
| 543 | /* Null terminate this buffer */ | 576 | /* Null terminate this buffer */ |
| 544 | op->str.buffer[op->str.field->size] = 0; | 577 | op->str.buffer[op->str.field->size] = 0; |
| 545 | 578 | ||
| @@ -557,7 +590,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
| 557 | case FILTER_CMP_NOT_REGEX: | 590 | case FILTER_CMP_NOT_REGEX: |
| 558 | show_error(error_str, | 591 | show_error(error_str, |
| 559 | "Op not allowed with integers"); | 592 | "Op not allowed with integers"); |
| 560 | return -1; | 593 | return PEVENT_ERRNO__ILLEGAL_INTEGER_CMP; |
| 561 | 594 | ||
| 562 | default: | 595 | default: |
| 563 | break; | 596 | break; |
| @@ -577,9 +610,8 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
| 577 | return 0; | 610 | return 0; |
| 578 | 611 | ||
| 579 | out_fail: | 612 | out_fail: |
| 580 | show_error(error_str, | 613 | show_error(error_str, "Syntax error"); |
| 581 | "Syntax error"); | 614 | return PEVENT_ERRNO__SYNTAX_ERROR; |
| 582 | return -1; | ||
| 583 | } | 615 | } |
| 584 | 616 | ||
| 585 | static struct filter_arg * | 617 | static struct filter_arg * |
| @@ -592,7 +624,7 @@ rotate_op_right(struct filter_arg *a, struct filter_arg *b) | |||
| 592 | return arg; | 624 | return arg; |
| 593 | } | 625 | } |
| 594 | 626 | ||
| 595 | static int add_left(struct filter_arg *op, struct filter_arg *arg) | 627 | static enum pevent_errno add_left(struct filter_arg *op, struct filter_arg *arg) |
| 596 | { | 628 | { |
| 597 | switch (op->type) { | 629 | switch (op->type) { |
| 598 | case FILTER_ARG_EXP: | 630 | case FILTER_ARG_EXP: |
| @@ -611,11 +643,11 @@ static int add_left(struct filter_arg *op, struct filter_arg *arg) | |||
| 611 | /* left arg of compares must be a field */ | 643 | /* left arg of compares must be a field */ |
| 612 | if (arg->type != FILTER_ARG_FIELD && | 644 | if (arg->type != FILTER_ARG_FIELD && |
| 613 | arg->type != FILTER_ARG_BOOLEAN) | 645 | arg->type != FILTER_ARG_BOOLEAN) |
| 614 | return -1; | 646 | return PEVENT_ERRNO__INVALID_ARG_TYPE; |
| 615 | op->num.left = arg; | 647 | op->num.left = arg; |
| 616 | break; | 648 | break; |
| 617 | default: | 649 | default: |
| 618 | return -1; | 650 | return PEVENT_ERRNO__INVALID_ARG_TYPE; |
| 619 | } | 651 | } |
| 620 | return 0; | 652 | return 0; |
| 621 | } | 653 | } |
| @@ -728,15 +760,18 @@ enum filter_vals { | |||
| 728 | FILTER_VAL_TRUE, | 760 | FILTER_VAL_TRUE, |
| 729 | }; | 761 | }; |
| 730 | 762 | ||
| 731 | void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, | 763 | static enum pevent_errno |
| 732 | struct filter_arg *arg) | 764 | reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, |
| 765 | struct filter_arg *arg, char *error_str) | ||
| 733 | { | 766 | { |
| 734 | struct filter_arg *other_child; | 767 | struct filter_arg *other_child; |
| 735 | struct filter_arg **ptr; | 768 | struct filter_arg **ptr; |
| 736 | 769 | ||
| 737 | if (parent->type != FILTER_ARG_OP && | 770 | if (parent->type != FILTER_ARG_OP && |
| 738 | arg->type != FILTER_ARG_OP) | 771 | arg->type != FILTER_ARG_OP) { |
| 739 | die("can not reparent other than OP"); | 772 | show_error(error_str, "can not reparent other than OP"); |
| 773 | return PEVENT_ERRNO__REPARENT_NOT_OP; | ||
| 774 | } | ||
| 740 | 775 | ||
| 741 | /* Get the sibling */ | 776 | /* Get the sibling */ |
| 742 | if (old_child->op.right == arg) { | 777 | if (old_child->op.right == arg) { |
| @@ -745,8 +780,10 @@ void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, | |||
| 745 | } else if (old_child->op.left == arg) { | 780 | } else if (old_child->op.left == arg) { |
| 746 | ptr = &old_child->op.left; | 781 | ptr = &old_child->op.left; |
| 747 | other_child = old_child->op.right; | 782 | other_child = old_child->op.right; |
| 748 | } else | 783 | } else { |
| 749 | die("Error in reparent op, find other child"); | 784 | show_error(error_str, "Error in reparent op, find other child"); |
| 785 | return PEVENT_ERRNO__REPARENT_FAILED; | ||
| 786 | } | ||
| 750 | 787 | ||
| 751 | /* Detach arg from old_child */ | 788 | /* Detach arg from old_child */ |
| 752 | *ptr = NULL; | 789 | *ptr = NULL; |
| @@ -757,23 +794,29 @@ void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, | |||
| 757 | *parent = *arg; | 794 | *parent = *arg; |
| 758 | /* Free arg without recussion */ | 795 | /* Free arg without recussion */ |
| 759 | free(arg); | 796 | free(arg); |
| 760 | return; | 797 | return 0; |
| 761 | } | 798 | } |
| 762 | 799 | ||
| 763 | if (parent->op.right == old_child) | 800 | if (parent->op.right == old_child) |
| 764 | ptr = &parent->op.right; | 801 | ptr = &parent->op.right; |
| 765 | else if (parent->op.left == old_child) | 802 | else if (parent->op.left == old_child) |
| 766 | ptr = &parent->op.left; | 803 | ptr = &parent->op.left; |
| 767 | else | 804 | else { |
| 768 | die("Error in reparent op"); | 805 | show_error(error_str, "Error in reparent op"); |
| 806 | return PEVENT_ERRNO__REPARENT_FAILED; | ||
| 807 | } | ||
| 808 | |||
| 769 | *ptr = arg; | 809 | *ptr = arg; |
| 770 | 810 | ||
| 771 | free_arg(old_child); | 811 | free_arg(old_child); |
| 812 | return 0; | ||
| 772 | } | 813 | } |
| 773 | 814 | ||
| 774 | enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg) | 815 | /* Returns either filter_vals (success) or pevent_errno (failfure) */ |
| 816 | static int test_arg(struct filter_arg *parent, struct filter_arg *arg, | ||
| 817 | char *error_str) | ||
| 775 | { | 818 | { |
| 776 | enum filter_vals lval, rval; | 819 | int lval, rval; |
| 777 | 820 | ||
| 778 | switch (arg->type) { | 821 | switch (arg->type) { |
| 779 | 822 | ||
| @@ -788,63 +831,68 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg) | |||
| 788 | return FILTER_VAL_NORM; | 831 | return FILTER_VAL_NORM; |
| 789 | 832 | ||
| 790 | case FILTER_ARG_EXP: | 833 | case FILTER_ARG_EXP: |
| 791 | lval = test_arg(arg, arg->exp.left); | 834 | lval = test_arg(arg, arg->exp.left, error_str); |
| 792 | if (lval != FILTER_VAL_NORM) | 835 | if (lval != FILTER_VAL_NORM) |
| 793 | return lval; | 836 | return lval; |
| 794 | rval = test_arg(arg, arg->exp.right); | 837 | rval = test_arg(arg, arg->exp.right, error_str); |
| 795 | if (rval != FILTER_VAL_NORM) | 838 | if (rval != FILTER_VAL_NORM) |
| 796 | return rval; | 839 | return rval; |
| 797 | return FILTER_VAL_NORM; | 840 | return FILTER_VAL_NORM; |
| 798 | 841 | ||
| 799 | case FILTER_ARG_NUM: | 842 | case FILTER_ARG_NUM: |
| 800 | lval = test_arg(arg, arg->num.left); | 843 | lval = test_arg(arg, arg->num.left, error_str); |
| 801 | if (lval != FILTER_VAL_NORM) | 844 | if (lval != FILTER_VAL_NORM) |
| 802 | return lval; | 845 | return lval; |
| 803 | rval = test_arg(arg, arg->num.right); | 846 | rval = test_arg(arg, arg->num.right, error_str); |
| 804 | if (rval != FILTER_VAL_NORM) | 847 | if (rval != FILTER_VAL_NORM) |
| 805 | return rval; | 848 | return rval; |
| 806 | return FILTER_VAL_NORM; | 849 | return FILTER_VAL_NORM; |
| 807 | 850 | ||
| 808 | case FILTER_ARG_OP: | 851 | case FILTER_ARG_OP: |
| 809 | if (arg->op.type != FILTER_OP_NOT) { | 852 | if (arg->op.type != FILTER_OP_NOT) { |
| 810 | lval = test_arg(arg, arg->op.left); | 853 | lval = test_arg(arg, arg->op.left, error_str); |
| 811 | switch (lval) { | 854 | switch (lval) { |
| 812 | case FILTER_VAL_NORM: | 855 | case FILTER_VAL_NORM: |
| 813 | break; | 856 | break; |
| 814 | case FILTER_VAL_TRUE: | 857 | case FILTER_VAL_TRUE: |
| 815 | if (arg->op.type == FILTER_OP_OR) | 858 | if (arg->op.type == FILTER_OP_OR) |
| 816 | return FILTER_VAL_TRUE; | 859 | return FILTER_VAL_TRUE; |
| 817 | rval = test_arg(arg, arg->op.right); | 860 | rval = test_arg(arg, arg->op.right, error_str); |
| 818 | if (rval != FILTER_VAL_NORM) | 861 | if (rval != FILTER_VAL_NORM) |
| 819 | return rval; | 862 | return rval; |
| 820 | 863 | ||
| 821 | reparent_op_arg(parent, arg, arg->op.right); | 864 | return reparent_op_arg(parent, arg, arg->op.right, |
| 822 | return FILTER_VAL_NORM; | 865 | error_str); |
| 823 | 866 | ||
| 824 | case FILTER_VAL_FALSE: | 867 | case FILTER_VAL_FALSE: |
| 825 | if (arg->op.type == FILTER_OP_AND) | 868 | if (arg->op.type == FILTER_OP_AND) |
| 826 | return FILTER_VAL_FALSE; | 869 | return FILTER_VAL_FALSE; |
| 827 | rval = test_arg(arg, arg->op.right); | 870 | rval = test_arg(arg, arg->op.right, error_str); |
| 828 | if (rval != FILTER_VAL_NORM) | 871 | if (rval != FILTER_VAL_NORM) |
| 829 | return rval; | 872 | return rval; |
| 830 | 873 | ||
| 831 | reparent_op_arg(parent, arg, arg->op.right); | 874 | return reparent_op_arg(parent, arg, arg->op.right, |
| 832 | return FILTER_VAL_NORM; | 875 | error_str); |
| 876 | |||
| 877 | default: | ||
| 878 | return lval; | ||
| 833 | } | 879 | } |
| 834 | } | 880 | } |
| 835 | 881 | ||
| 836 | rval = test_arg(arg, arg->op.right); | 882 | rval = test_arg(arg, arg->op.right, error_str); |
| 837 | switch (rval) { | 883 | switch (rval) { |
| 838 | case FILTER_VAL_NORM: | 884 | case FILTER_VAL_NORM: |
| 885 | default: | ||
| 839 | break; | 886 | break; |
| 887 | |||
| 840 | case FILTER_VAL_TRUE: | 888 | case FILTER_VAL_TRUE: |
| 841 | if (arg->op.type == FILTER_OP_OR) | 889 | if (arg->op.type == FILTER_OP_OR) |
| 842 | return FILTER_VAL_TRUE; | 890 | return FILTER_VAL_TRUE; |
| 843 | if (arg->op.type == FILTER_OP_NOT) | 891 | if (arg->op.type == FILTER_OP_NOT) |
| 844 | return FILTER_VAL_FALSE; | 892 | return FILTER_VAL_FALSE; |
| 845 | 893 | ||
| 846 | reparent_op_arg(parent, arg, arg->op.left); | 894 | return reparent_op_arg(parent, arg, arg->op.left, |
| 847 | return FILTER_VAL_NORM; | 895 | error_str); |
| 848 | 896 | ||
| 849 | case FILTER_VAL_FALSE: | 897 | case FILTER_VAL_FALSE: |
| 850 | if (arg->op.type == FILTER_OP_AND) | 898 | if (arg->op.type == FILTER_OP_AND) |
| @@ -852,41 +900,56 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg) | |||
| 852 | if (arg->op.type == FILTER_OP_NOT) | 900 | if (arg->op.type == FILTER_OP_NOT) |
| 853 | return FILTER_VAL_TRUE; | 901 | return FILTER_VAL_TRUE; |
| 854 | 902 | ||
| 855 | reparent_op_arg(parent, arg, arg->op.left); | 903 | return reparent_op_arg(parent, arg, arg->op.left, |
| 856 | return FILTER_VAL_NORM; | 904 | error_str); |
| 857 | } | 905 | } |
| 858 | 906 | ||
| 859 | return FILTER_VAL_NORM; | 907 | return rval; |
| 860 | default: | 908 | default: |
| 861 | die("bad arg in filter tree"); | 909 | show_error(error_str, "bad arg in filter tree"); |
| 910 | return PEVENT_ERRNO__BAD_FILTER_ARG; | ||
| 862 | } | 911 | } |
| 863 | return FILTER_VAL_NORM; | 912 | return FILTER_VAL_NORM; |
| 864 | } | 913 | } |
| 865 | 914 | ||
| 866 | /* Remove any unknown event fields */ | 915 | /* Remove any unknown event fields */ |
| 867 | static struct filter_arg *collapse_tree(struct filter_arg *arg) | 916 | static int collapse_tree(struct filter_arg *arg, |
| 917 | struct filter_arg **arg_collapsed, char *error_str) | ||
| 868 | { | 918 | { |
| 869 | enum filter_vals ret; | 919 | int ret; |
| 870 | 920 | ||
| 871 | ret = test_arg(arg, arg); | 921 | ret = test_arg(arg, arg, error_str); |
| 872 | switch (ret) { | 922 | switch (ret) { |
| 873 | case FILTER_VAL_NORM: | 923 | case FILTER_VAL_NORM: |
| 874 | return arg; | 924 | break; |
| 875 | 925 | ||
| 876 | case FILTER_VAL_TRUE: | 926 | case FILTER_VAL_TRUE: |
| 877 | case FILTER_VAL_FALSE: | 927 | case FILTER_VAL_FALSE: |
| 878 | free_arg(arg); | 928 | free_arg(arg); |
| 879 | arg = allocate_arg(); | 929 | arg = allocate_arg(); |
| 880 | arg->type = FILTER_ARG_BOOLEAN; | 930 | if (arg) { |
| 881 | arg->boolean.value = ret == FILTER_VAL_TRUE; | 931 | arg->type = FILTER_ARG_BOOLEAN; |
| 932 | arg->boolean.value = ret == FILTER_VAL_TRUE; | ||
| 933 | } else { | ||
| 934 | show_error(error_str, "Failed to allocate filter arg"); | ||
| 935 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 936 | } | ||
| 937 | break; | ||
| 938 | |||
| 939 | default: | ||
| 940 | /* test_arg() already set the error_str */ | ||
| 941 | free_arg(arg); | ||
| 942 | arg = NULL; | ||
| 943 | break; | ||
| 882 | } | 944 | } |
| 883 | 945 | ||
| 884 | return arg; | 946 | *arg_collapsed = arg; |
| 947 | return ret; | ||
| 885 | } | 948 | } |
| 886 | 949 | ||
| 887 | static int | 950 | static enum pevent_errno |
| 888 | process_filter(struct event_format *event, struct filter_arg **parg, | 951 | process_filter(struct event_format *event, struct filter_arg **parg, |
| 889 | char **error_str, int not) | 952 | char *error_str, int not) |
| 890 | { | 953 | { |
| 891 | enum event_type type; | 954 | enum event_type type; |
| 892 | char *token = NULL; | 955 | char *token = NULL; |
| @@ -898,7 +961,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 898 | enum filter_op_type btype; | 961 | enum filter_op_type btype; |
| 899 | enum filter_exp_type etype; | 962 | enum filter_exp_type etype; |
| 900 | enum filter_cmp_type ctype; | 963 | enum filter_cmp_type ctype; |
| 901 | int ret; | 964 | enum pevent_errno ret; |
| 902 | 965 | ||
| 903 | *parg = NULL; | 966 | *parg = NULL; |
| 904 | 967 | ||
| @@ -909,8 +972,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 909 | case EVENT_SQUOTE: | 972 | case EVENT_SQUOTE: |
| 910 | case EVENT_DQUOTE: | 973 | case EVENT_DQUOTE: |
| 911 | case EVENT_ITEM: | 974 | case EVENT_ITEM: |
| 912 | arg = create_arg_item(event, token, type, error_str); | 975 | ret = create_arg_item(event, token, type, &arg, error_str); |
| 913 | if (!arg) | 976 | if (ret < 0) |
| 914 | goto fail; | 977 | goto fail; |
| 915 | if (!left_item) | 978 | if (!left_item) |
| 916 | left_item = arg; | 979 | left_item = arg; |
| @@ -923,20 +986,20 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 923 | if (not) { | 986 | if (not) { |
| 924 | arg = NULL; | 987 | arg = NULL; |
| 925 | if (current_op) | 988 | if (current_op) |
| 926 | goto fail_print; | 989 | goto fail_syntax; |
| 927 | free(token); | 990 | free(token); |
| 928 | *parg = current_exp; | 991 | *parg = current_exp; |
| 929 | return 0; | 992 | return 0; |
| 930 | } | 993 | } |
| 931 | } else | 994 | } else |
| 932 | goto fail_print; | 995 | goto fail_syntax; |
| 933 | arg = NULL; | 996 | arg = NULL; |
| 934 | break; | 997 | break; |
| 935 | 998 | ||
| 936 | case EVENT_DELIM: | 999 | case EVENT_DELIM: |
| 937 | if (*token == ',') { | 1000 | if (*token == ',') { |
| 938 | show_error(error_str, | 1001 | show_error(error_str, "Illegal token ','"); |
| 939 | "Illegal token ','"); | 1002 | ret = PEVENT_ERRNO__ILLEGAL_TOKEN; |
| 940 | goto fail; | 1003 | goto fail; |
| 941 | } | 1004 | } |
| 942 | 1005 | ||
| @@ -944,19 +1007,23 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 944 | if (left_item) { | 1007 | if (left_item) { |
| 945 | show_error(error_str, | 1008 | show_error(error_str, |
| 946 | "Open paren can not come after item"); | 1009 | "Open paren can not come after item"); |
| 1010 | ret = PEVENT_ERRNO__INVALID_PAREN; | ||
| 947 | goto fail; | 1011 | goto fail; |
| 948 | } | 1012 | } |
| 949 | if (current_exp) { | 1013 | if (current_exp) { |
| 950 | show_error(error_str, | 1014 | show_error(error_str, |
| 951 | "Open paren can not come after expression"); | 1015 | "Open paren can not come after expression"); |
| 1016 | ret = PEVENT_ERRNO__INVALID_PAREN; | ||
| 952 | goto fail; | 1017 | goto fail; |
| 953 | } | 1018 | } |
| 954 | 1019 | ||
| 955 | ret = process_filter(event, &arg, error_str, 0); | 1020 | ret = process_filter(event, &arg, error_str, 0); |
| 956 | if (ret != 1) { | 1021 | if (ret != PEVENT_ERRNO__UNBALANCED_PAREN) { |
| 957 | if (ret == 0) | 1022 | if (ret == 0) { |
| 958 | show_error(error_str, | 1023 | show_error(error_str, |
| 959 | "Unbalanced number of '('"); | 1024 | "Unbalanced number of '('"); |
| 1025 | ret = PEVENT_ERRNO__UNBALANCED_PAREN; | ||
| 1026 | } | ||
| 960 | goto fail; | 1027 | goto fail; |
| 961 | } | 1028 | } |
| 962 | ret = 0; | 1029 | ret = 0; |
| @@ -964,7 +1031,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 964 | /* A not wants just one expression */ | 1031 | /* A not wants just one expression */ |
| 965 | if (not) { | 1032 | if (not) { |
| 966 | if (current_op) | 1033 | if (current_op) |
| 967 | goto fail_print; | 1034 | goto fail_syntax; |
| 968 | *parg = arg; | 1035 | *parg = arg; |
| 969 | return 0; | 1036 | return 0; |
| 970 | } | 1037 | } |
| @@ -979,19 +1046,19 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 979 | 1046 | ||
| 980 | } else { /* ')' */ | 1047 | } else { /* ')' */ |
| 981 | if (!current_op && !current_exp) | 1048 | if (!current_op && !current_exp) |
| 982 | goto fail_print; | 1049 | goto fail_syntax; |
| 983 | 1050 | ||
| 984 | /* Make sure everything is finished at this level */ | 1051 | /* Make sure everything is finished at this level */ |
| 985 | if (current_exp && !check_op_done(current_exp)) | 1052 | if (current_exp && !check_op_done(current_exp)) |
| 986 | goto fail_print; | 1053 | goto fail_syntax; |
| 987 | if (current_op && !check_op_done(current_op)) | 1054 | if (current_op && !check_op_done(current_op)) |
| 988 | goto fail_print; | 1055 | goto fail_syntax; |
| 989 | 1056 | ||
| 990 | if (current_op) | 1057 | if (current_op) |
| 991 | *parg = current_op; | 1058 | *parg = current_op; |
| 992 | else | 1059 | else |
| 993 | *parg = current_exp; | 1060 | *parg = current_exp; |
| 994 | return 1; | 1061 | return PEVENT_ERRNO__UNBALANCED_PAREN; |
| 995 | } | 1062 | } |
| 996 | break; | 1063 | break; |
| 997 | 1064 | ||
| @@ -1003,21 +1070,22 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 1003 | case OP_BOOL: | 1070 | case OP_BOOL: |
| 1004 | /* Logic ops need a left expression */ | 1071 | /* Logic ops need a left expression */ |
| 1005 | if (!current_exp && !current_op) | 1072 | if (!current_exp && !current_op) |
| 1006 | goto fail_print; | 1073 | goto fail_syntax; |
| 1007 | /* fall through */ | 1074 | /* fall through */ |
| 1008 | case OP_NOT: | 1075 | case OP_NOT: |
| 1009 | /* logic only processes ops and exp */ | 1076 | /* logic only processes ops and exp */ |
| 1010 | if (left_item) | 1077 | if (left_item) |
| 1011 | goto fail_print; | 1078 | goto fail_syntax; |
| 1012 | break; | 1079 | break; |
| 1013 | case OP_EXP: | 1080 | case OP_EXP: |
| 1014 | case OP_CMP: | 1081 | case OP_CMP: |
| 1015 | if (!left_item) | 1082 | if (!left_item) |
| 1016 | goto fail_print; | 1083 | goto fail_syntax; |
| 1017 | break; | 1084 | break; |
| 1018 | case OP_NONE: | 1085 | case OP_NONE: |
| 1019 | show_error(error_str, | 1086 | show_error(error_str, |
| 1020 | "Unknown op token %s", token); | 1087 | "Unknown op token %s", token); |
| 1088 | ret = PEVENT_ERRNO__UNKNOWN_TOKEN; | ||
| 1021 | goto fail; | 1089 | goto fail; |
| 1022 | } | 1090 | } |
| 1023 | 1091 | ||
| @@ -1025,6 +1093,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 1025 | switch (op_type) { | 1093 | switch (op_type) { |
| 1026 | case OP_BOOL: | 1094 | case OP_BOOL: |
| 1027 | arg = create_arg_op(btype); | 1095 | arg = create_arg_op(btype); |
| 1096 | if (arg == NULL) | ||
| 1097 | goto fail_alloc; | ||
| 1028 | if (current_op) | 1098 | if (current_op) |
| 1029 | ret = add_left(arg, current_op); | 1099 | ret = add_left(arg, current_op); |
| 1030 | else | 1100 | else |
| @@ -1035,6 +1105,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 1035 | 1105 | ||
| 1036 | case OP_NOT: | 1106 | case OP_NOT: |
| 1037 | arg = create_arg_op(btype); | 1107 | arg = create_arg_op(btype); |
| 1108 | if (arg == NULL) | ||
| 1109 | goto fail_alloc; | ||
| 1038 | if (current_op) | 1110 | if (current_op) |
| 1039 | ret = add_right(current_op, arg, error_str); | 1111 | ret = add_right(current_op, arg, error_str); |
| 1040 | if (ret < 0) | 1112 | if (ret < 0) |
| @@ -1054,6 +1126,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 1054 | arg = create_arg_exp(etype); | 1126 | arg = create_arg_exp(etype); |
| 1055 | else | 1127 | else |
| 1056 | arg = create_arg_cmp(ctype); | 1128 | arg = create_arg_cmp(ctype); |
| 1129 | if (arg == NULL) | ||
| 1130 | goto fail_alloc; | ||
| 1057 | 1131 | ||
| 1058 | if (current_op) | 1132 | if (current_op) |
| 1059 | ret = add_right(current_op, arg, error_str); | 1133 | ret = add_right(current_op, arg, error_str); |
| @@ -1062,7 +1136,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 1062 | ret = add_left(arg, left_item); | 1136 | ret = add_left(arg, left_item); |
| 1063 | if (ret < 0) { | 1137 | if (ret < 0) { |
| 1064 | arg = NULL; | 1138 | arg = NULL; |
| 1065 | goto fail_print; | 1139 | goto fail_syntax; |
| 1066 | } | 1140 | } |
| 1067 | current_exp = arg; | 1141 | current_exp = arg; |
| 1068 | break; | 1142 | break; |
| @@ -1071,57 +1145,64 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
| 1071 | } | 1145 | } |
| 1072 | arg = NULL; | 1146 | arg = NULL; |
| 1073 | if (ret < 0) | 1147 | if (ret < 0) |
| 1074 | goto fail_print; | 1148 | goto fail_syntax; |
| 1075 | break; | 1149 | break; |
| 1076 | case EVENT_NONE: | 1150 | case EVENT_NONE: |
| 1077 | break; | 1151 | break; |
| 1152 | case EVENT_ERROR: | ||
| 1153 | goto fail_alloc; | ||
| 1078 | default: | 1154 | default: |
| 1079 | goto fail_print; | 1155 | goto fail_syntax; |
| 1080 | } | 1156 | } |
| 1081 | } while (type != EVENT_NONE); | 1157 | } while (type != EVENT_NONE); |
| 1082 | 1158 | ||
| 1083 | if (!current_op && !current_exp) | 1159 | if (!current_op && !current_exp) |
| 1084 | goto fail_print; | 1160 | goto fail_syntax; |
| 1085 | 1161 | ||
| 1086 | if (!current_op) | 1162 | if (!current_op) |
| 1087 | current_op = current_exp; | 1163 | current_op = current_exp; |
| 1088 | 1164 | ||
| 1089 | current_op = collapse_tree(current_op); | 1165 | ret = collapse_tree(current_op, parg, error_str); |
| 1166 | if (ret < 0) | ||
| 1167 | goto fail; | ||
| 1090 | 1168 | ||
| 1091 | *parg = current_op; | 1169 | *parg = current_op; |
| 1092 | 1170 | ||
| 1093 | return 0; | 1171 | return 0; |
| 1094 | 1172 | ||
| 1095 | fail_print: | 1173 | fail_alloc: |
| 1174 | show_error(error_str, "failed to allocate filter arg"); | ||
| 1175 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 1176 | goto fail; | ||
| 1177 | fail_syntax: | ||
| 1096 | show_error(error_str, "Syntax error"); | 1178 | show_error(error_str, "Syntax error"); |
| 1179 | ret = PEVENT_ERRNO__SYNTAX_ERROR; | ||
| 1097 | fail: | 1180 | fail: |
| 1098 | free_arg(current_op); | 1181 | free_arg(current_op); |
| 1099 | free_arg(current_exp); | 1182 | free_arg(current_exp); |
| 1100 | free_arg(arg); | 1183 | free_arg(arg); |
| 1101 | free(token); | 1184 | free(token); |
| 1102 | return -1; | 1185 | return ret; |
| 1103 | } | 1186 | } |
| 1104 | 1187 | ||
| 1105 | static int | 1188 | static enum pevent_errno |
| 1106 | process_event(struct event_format *event, const char *filter_str, | 1189 | process_event(struct event_format *event, const char *filter_str, |
| 1107 | struct filter_arg **parg, char **error_str) | 1190 | struct filter_arg **parg, char *error_str) |
| 1108 | { | 1191 | { |
| 1109 | int ret; | 1192 | int ret; |
| 1110 | 1193 | ||
| 1111 | pevent_buffer_init(filter_str, strlen(filter_str)); | 1194 | pevent_buffer_init(filter_str, strlen(filter_str)); |
| 1112 | 1195 | ||
| 1113 | ret = process_filter(event, parg, error_str, 0); | 1196 | ret = process_filter(event, parg, error_str, 0); |
| 1114 | if (ret == 1) { | ||
| 1115 | show_error(error_str, | ||
| 1116 | "Unbalanced number of ')'"); | ||
| 1117 | return -1; | ||
| 1118 | } | ||
| 1119 | if (ret < 0) | 1197 | if (ret < 0) |
| 1120 | return ret; | 1198 | return ret; |
| 1121 | 1199 | ||
| 1122 | /* If parg is NULL, then make it into FALSE */ | 1200 | /* If parg is NULL, then make it into FALSE */ |
| 1123 | if (!*parg) { | 1201 | if (!*parg) { |
| 1124 | *parg = allocate_arg(); | 1202 | *parg = allocate_arg(); |
| 1203 | if (*parg == NULL) | ||
| 1204 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 1205 | |||
| 1125 | (*parg)->type = FILTER_ARG_BOOLEAN; | 1206 | (*parg)->type = FILTER_ARG_BOOLEAN; |
| 1126 | (*parg)->boolean.value = FILTER_FALSE; | 1207 | (*parg)->boolean.value = FILTER_FALSE; |
| 1127 | } | 1208 | } |
| @@ -1129,13 +1210,13 @@ process_event(struct event_format *event, const char *filter_str, | |||
| 1129 | return 0; | 1210 | return 0; |
| 1130 | } | 1211 | } |
| 1131 | 1212 | ||
| 1132 | static int filter_event(struct event_filter *filter, | 1213 | static enum pevent_errno |
| 1133 | struct event_format *event, | 1214 | filter_event(struct event_filter *filter, struct event_format *event, |
| 1134 | const char *filter_str, char **error_str) | 1215 | const char *filter_str, char *error_str) |
| 1135 | { | 1216 | { |
| 1136 | struct filter_type *filter_type; | 1217 | struct filter_type *filter_type; |
| 1137 | struct filter_arg *arg; | 1218 | struct filter_arg *arg; |
| 1138 | int ret; | 1219 | enum pevent_errno ret; |
| 1139 | 1220 | ||
| 1140 | if (filter_str) { | 1221 | if (filter_str) { |
| 1141 | ret = process_event(event, filter_str, &arg, error_str); | 1222 | ret = process_event(event, filter_str, &arg, error_str); |
| @@ -1145,11 +1226,17 @@ static int filter_event(struct event_filter *filter, | |||
| 1145 | } else { | 1226 | } else { |
| 1146 | /* just add a TRUE arg */ | 1227 | /* just add a TRUE arg */ |
| 1147 | arg = allocate_arg(); | 1228 | arg = allocate_arg(); |
| 1229 | if (arg == NULL) | ||
| 1230 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 1231 | |||
| 1148 | arg->type = FILTER_ARG_BOOLEAN; | 1232 | arg->type = FILTER_ARG_BOOLEAN; |
| 1149 | arg->boolean.value = FILTER_TRUE; | 1233 | arg->boolean.value = FILTER_TRUE; |
| 1150 | } | 1234 | } |
| 1151 | 1235 | ||
| 1152 | filter_type = add_filter_type(filter, event->id); | 1236 | filter_type = add_filter_type(filter, event->id); |
| 1237 | if (filter_type == NULL) | ||
| 1238 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 1239 | |||
| 1153 | if (filter_type->filter) | 1240 | if (filter_type->filter) |
| 1154 | free_arg(filter_type->filter); | 1241 | free_arg(filter_type->filter); |
| 1155 | filter_type->filter = arg; | 1242 | filter_type->filter = arg; |
| @@ -1157,22 +1244,24 @@ static int filter_event(struct event_filter *filter, | |||
| 1157 | return 0; | 1244 | return 0; |
| 1158 | } | 1245 | } |
| 1159 | 1246 | ||
| 1247 | static void filter_init_error_buf(struct event_filter *filter) | ||
| 1248 | { | ||
| 1249 | /* clear buffer to reset show error */ | ||
| 1250 | pevent_buffer_init("", 0); | ||
| 1251 | filter->error_buffer[0] = '\0'; | ||
| 1252 | } | ||
| 1253 | |||
| 1160 | /** | 1254 | /** |
| 1161 | * pevent_filter_add_filter_str - add a new filter | 1255 | * pevent_filter_add_filter_str - add a new filter |
| 1162 | * @filter: the event filter to add to | 1256 | * @filter: the event filter to add to |
| 1163 | * @filter_str: the filter string that contains the filter | 1257 | * @filter_str: the filter string that contains the filter |
| 1164 | * @error_str: string containing reason for failed filter | ||
| 1165 | * | ||
| 1166 | * Returns 0 if the filter was successfully added | ||
| 1167 | * -1 if there was an error. | ||
| 1168 | * | 1258 | * |
| 1169 | * On error, if @error_str points to a string pointer, | 1259 | * Returns 0 if the filter was successfully added or a |
| 1170 | * it is set to the reason that the filter failed. | 1260 | * negative error code. Use pevent_filter_strerror() to see |
| 1171 | * This string must be freed with "free". | 1261 | * actual error message in case of error. |
| 1172 | */ | 1262 | */ |
| 1173 | int pevent_filter_add_filter_str(struct event_filter *filter, | 1263 | enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, |
| 1174 | const char *filter_str, | 1264 | const char *filter_str) |
| 1175 | char **error_str) | ||
| 1176 | { | 1265 | { |
| 1177 | struct pevent *pevent = filter->pevent; | 1266 | struct pevent *pevent = filter->pevent; |
| 1178 | struct event_list *event; | 1267 | struct event_list *event; |
| @@ -1183,15 +1272,11 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
| 1183 | char *event_name = NULL; | 1272 | char *event_name = NULL; |
| 1184 | char *sys_name = NULL; | 1273 | char *sys_name = NULL; |
| 1185 | char *sp; | 1274 | char *sp; |
| 1186 | int rtn = 0; | 1275 | enum pevent_errno rtn = 0; /* PEVENT_ERRNO__SUCCESS */ |
| 1187 | int len; | 1276 | int len; |
| 1188 | int ret; | 1277 | int ret; |
| 1189 | 1278 | ||
| 1190 | /* clear buffer to reset show error */ | 1279 | filter_init_error_buf(filter); |
| 1191 | pevent_buffer_init("", 0); | ||
| 1192 | |||
| 1193 | if (error_str) | ||
| 1194 | *error_str = NULL; | ||
| 1195 | 1280 | ||
| 1196 | filter_start = strchr(filter_str, ':'); | 1281 | filter_start = strchr(filter_str, ':'); |
| 1197 | if (filter_start) | 1282 | if (filter_start) |
| @@ -1199,7 +1284,6 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
| 1199 | else | 1284 | else |
| 1200 | len = strlen(filter_str); | 1285 | len = strlen(filter_str); |
| 1201 | 1286 | ||
| 1202 | |||
| 1203 | do { | 1287 | do { |
| 1204 | next_event = strchr(filter_str, ','); | 1288 | next_event = strchr(filter_str, ','); |
| 1205 | if (next_event && | 1289 | if (next_event && |
| @@ -1210,7 +1294,12 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
| 1210 | else | 1294 | else |
| 1211 | len = strlen(filter_str); | 1295 | len = strlen(filter_str); |
| 1212 | 1296 | ||
| 1213 | this_event = malloc_or_die(len + 1); | 1297 | this_event = malloc(len + 1); |
| 1298 | if (this_event == NULL) { | ||
| 1299 | /* This can only happen when events is NULL, but still */ | ||
| 1300 | free_events(events); | ||
| 1301 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
| 1302 | } | ||
| 1214 | memcpy(this_event, filter_str, len); | 1303 | memcpy(this_event, filter_str, len); |
| 1215 | this_event[len] = 0; | 1304 | this_event[len] = 0; |
| 1216 | 1305 | ||
| @@ -1223,27 +1312,18 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
| 1223 | event_name = strtok_r(NULL, "/", &sp); | 1312 | event_name = strtok_r(NULL, "/", &sp); |
| 1224 | 1313 | ||
| 1225 | if (!sys_name) { | 1314 | if (!sys_name) { |
| 1226 | show_error(error_str, "No filter found"); | ||
| 1227 | /* This can only happen when events is NULL, but still */ | 1315 | /* This can only happen when events is NULL, but still */ |
| 1228 | free_events(events); | 1316 | free_events(events); |
| 1229 | free(this_event); | 1317 | free(this_event); |
| 1230 | return -1; | 1318 | return PEVENT_ERRNO__FILTER_NOT_FOUND; |
| 1231 | } | 1319 | } |
| 1232 | 1320 | ||
| 1233 | /* Find this event */ | 1321 | /* Find this event */ |
| 1234 | ret = find_event(pevent, &events, strim(sys_name), strim(event_name)); | 1322 | ret = find_event(pevent, &events, strim(sys_name), strim(event_name)); |
| 1235 | if (ret < 0) { | 1323 | if (ret < 0) { |
| 1236 | if (event_name) | ||
| 1237 | show_error(error_str, | ||
| 1238 | "No event found under '%s.%s'", | ||
| 1239 | sys_name, event_name); | ||
| 1240 | else | ||
| 1241 | show_error(error_str, | ||
| 1242 | "No event found under '%s'", | ||
| 1243 | sys_name); | ||
| 1244 | free_events(events); | 1324 | free_events(events); |
| 1245 | free(this_event); | 1325 | free(this_event); |
| 1246 | return -1; | 1326 | return ret; |
| 1247 | } | 1327 | } |
| 1248 | free(this_event); | 1328 | free(this_event); |
| 1249 | } while (filter_str); | 1329 | } while (filter_str); |
| @@ -1255,7 +1335,7 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
| 1255 | /* filter starts here */ | 1335 | /* filter starts here */ |
| 1256 | for (event = events; event; event = event->next) { | 1336 | for (event = events; event; event = event->next) { |
| 1257 | ret = filter_event(filter, event->event, filter_start, | 1337 | ret = filter_event(filter, event->event, filter_start, |
| 1258 | error_str); | 1338 | filter->error_buffer); |
| 1259 | /* Failures are returned if a parse error happened */ | 1339 | /* Failures are returned if a parse error happened */ |
| 1260 | if (ret < 0) | 1340 | if (ret < 0) |
| 1261 | rtn = ret; | 1341 | rtn = ret; |
| @@ -1263,8 +1343,10 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
| 1263 | if (ret >= 0 && pevent->test_filters) { | 1343 | if (ret >= 0 && pevent->test_filters) { |
| 1264 | char *test; | 1344 | char *test; |
| 1265 | test = pevent_filter_make_string(filter, event->event->id); | 1345 | test = pevent_filter_make_string(filter, event->event->id); |
| 1266 | printf(" '%s: %s'\n", event->event->name, test); | 1346 | if (test) { |
| 1267 | free(test); | 1347 | printf(" '%s: %s'\n", event->event->name, test); |
| 1348 | free(test); | ||
| 1349 | } | ||
| 1268 | } | 1350 | } |
| 1269 | } | 1351 | } |
| 1270 | 1352 | ||
| @@ -1282,6 +1364,32 @@ static void free_filter_type(struct filter_type *filter_type) | |||
| 1282 | } | 1364 | } |
| 1283 | 1365 | ||
| 1284 | /** | 1366 | /** |
| 1367 | * pevent_filter_strerror - fill error message in a buffer | ||
| 1368 | * @filter: the event filter contains error | ||
| 1369 | * @err: the error code | ||
| 1370 | * @buf: the buffer to be filled in | ||
| 1371 | * @buflen: the size of the buffer | ||
| 1372 | * | ||
| 1373 | * Returns 0 if message was filled successfully, -1 if error | ||
| 1374 | */ | ||
| 1375 | int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err, | ||
| 1376 | char *buf, size_t buflen) | ||
| 1377 | { | ||
| 1378 | if (err <= __PEVENT_ERRNO__START || err >= __PEVENT_ERRNO__END) | ||
| 1379 | return -1; | ||
| 1380 | |||
| 1381 | if (strlen(filter->error_buffer) > 0) { | ||
| 1382 | size_t len = snprintf(buf, buflen, "%s", filter->error_buffer); | ||
| 1383 | |||
| 1384 | if (len > buflen) | ||
| 1385 | return -1; | ||
| 1386 | return 0; | ||
| 1387 | } | ||
| 1388 | |||
| 1389 | return pevent_strerror(filter->pevent, err, buf, buflen); | ||
| 1390 | } | ||
| 1391 | |||
| 1392 | /** | ||
| 1285 | * pevent_filter_remove_event - remove a filter for an event | 1393 | * pevent_filter_remove_event - remove a filter for an event |
| 1286 | * @filter: the event filter to remove from | 1394 | * @filter: the event filter to remove from |
| 1287 | * @event_id: the event to remove a filter for | 1395 | * @event_id: the event to remove a filter for |
| @@ -1374,6 +1482,9 @@ static int copy_filter_type(struct event_filter *filter, | |||
| 1374 | if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) { | 1482 | if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) { |
| 1375 | /* Add trivial event */ | 1483 | /* Add trivial event */ |
| 1376 | arg = allocate_arg(); | 1484 | arg = allocate_arg(); |
| 1485 | if (arg == NULL) | ||
| 1486 | return -1; | ||
| 1487 | |||
| 1377 | arg->type = FILTER_ARG_BOOLEAN; | 1488 | arg->type = FILTER_ARG_BOOLEAN; |
| 1378 | if (strcmp(str, "TRUE") == 0) | 1489 | if (strcmp(str, "TRUE") == 0) |
| 1379 | arg->boolean.value = 1; | 1490 | arg->boolean.value = 1; |
| @@ -1381,6 +1492,9 @@ static int copy_filter_type(struct event_filter *filter, | |||
| 1381 | arg->boolean.value = 0; | 1492 | arg->boolean.value = 0; |
| 1382 | 1493 | ||
| 1383 | filter_type = add_filter_type(filter, event->id); | 1494 | filter_type = add_filter_type(filter, event->id); |
| 1495 | if (filter_type == NULL) | ||
| 1496 | return -1; | ||
| 1497 | |||
| 1384 | filter_type->filter = arg; | 1498 | filter_type->filter = arg; |
| 1385 | 1499 | ||
| 1386 | free(str); | 1500 | free(str); |
| @@ -1482,8 +1596,10 @@ int pevent_update_trivial(struct event_filter *dest, struct event_filter *source | |||
| 1482 | * @type: remove only true, false, or both | 1596 | * @type: remove only true, false, or both |
| 1483 | * | 1597 | * |
| 1484 | * Removes filters that only contain a TRUE or FALES boolean arg. | 1598 | * Removes filters that only contain a TRUE or FALES boolean arg. |
| 1599 | * | ||
| 1600 | * Returns 0 on success and -1 if there was a problem. | ||
| 1485 | */ | 1601 | */ |
| 1486 | void pevent_filter_clear_trivial(struct event_filter *filter, | 1602 | int pevent_filter_clear_trivial(struct event_filter *filter, |
| 1487 | enum filter_trivial_type type) | 1603 | enum filter_trivial_type type) |
| 1488 | { | 1604 | { |
| 1489 | struct filter_type *filter_type; | 1605 | struct filter_type *filter_type; |
| @@ -1492,13 +1608,15 @@ void pevent_filter_clear_trivial(struct event_filter *filter, | |||
| 1492 | int i; | 1608 | int i; |
| 1493 | 1609 | ||
| 1494 | if (!filter->filters) | 1610 | if (!filter->filters) |
| 1495 | return; | 1611 | return 0; |
| 1496 | 1612 | ||
| 1497 | /* | 1613 | /* |
| 1498 | * Two steps, first get all ids with trivial filters. | 1614 | * Two steps, first get all ids with trivial filters. |
| 1499 | * then remove those ids. | 1615 | * then remove those ids. |
| 1500 | */ | 1616 | */ |
| 1501 | for (i = 0; i < filter->filters; i++) { | 1617 | for (i = 0; i < filter->filters; i++) { |
| 1618 | int *new_ids; | ||
| 1619 | |||
| 1502 | filter_type = &filter->event_filters[i]; | 1620 | filter_type = &filter->event_filters[i]; |
| 1503 | if (filter_type->filter->type != FILTER_ARG_BOOLEAN) | 1621 | if (filter_type->filter->type != FILTER_ARG_BOOLEAN) |
| 1504 | continue; | 1622 | continue; |
| @@ -1513,19 +1631,24 @@ void pevent_filter_clear_trivial(struct event_filter *filter, | |||
| 1513 | break; | 1631 | break; |
| 1514 | } | 1632 | } |
| 1515 | 1633 | ||
| 1516 | ids = realloc(ids, sizeof(*ids) * (count + 1)); | 1634 | new_ids = realloc(ids, sizeof(*ids) * (count + 1)); |
| 1517 | if (!ids) | 1635 | if (!new_ids) { |
| 1518 | die("Can't allocate ids"); | 1636 | free(ids); |
| 1637 | return -1; | ||
| 1638 | } | ||
| 1639 | |||
| 1640 | ids = new_ids; | ||
| 1519 | ids[count++] = filter_type->event_id; | 1641 | ids[count++] = filter_type->event_id; |
| 1520 | } | 1642 | } |
| 1521 | 1643 | ||
| 1522 | if (!count) | 1644 | if (!count) |
| 1523 | return; | 1645 | return 0; |
| 1524 | 1646 | ||
| 1525 | for (i = 0; i < count; i++) | 1647 | for (i = 0; i < count; i++) |
| 1526 | pevent_filter_remove_event(filter, ids[i]); | 1648 | pevent_filter_remove_event(filter, ids[i]); |
| 1527 | 1649 | ||
| 1528 | free(ids); | 1650 | free(ids); |
| 1651 | return 0; | ||
| 1529 | } | 1652 | } |
| 1530 | 1653 | ||
| 1531 | /** | 1654 | /** |
| @@ -1565,8 +1688,8 @@ int pevent_filter_event_has_trivial(struct event_filter *filter, | |||
| 1565 | } | 1688 | } |
| 1566 | } | 1689 | } |
| 1567 | 1690 | ||
| 1568 | static int test_filter(struct event_format *event, | 1691 | static int test_filter(struct event_format *event, struct filter_arg *arg, |
| 1569 | struct filter_arg *arg, struct pevent_record *record); | 1692 | struct pevent_record *record, enum pevent_errno *err); |
| 1570 | 1693 | ||
| 1571 | static const char * | 1694 | static const char * |
| 1572 | get_comm(struct event_format *event, struct pevent_record *record) | 1695 | get_comm(struct event_format *event, struct pevent_record *record) |
| @@ -1612,15 +1735,24 @@ get_value(struct event_format *event, | |||
| 1612 | } | 1735 | } |
| 1613 | 1736 | ||
| 1614 | static unsigned long long | 1737 | static unsigned long long |
| 1615 | get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record); | 1738 | get_arg_value(struct event_format *event, struct filter_arg *arg, |
| 1739 | struct pevent_record *record, enum pevent_errno *err); | ||
| 1616 | 1740 | ||
| 1617 | static unsigned long long | 1741 | static unsigned long long |
| 1618 | get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record) | 1742 | get_exp_value(struct event_format *event, struct filter_arg *arg, |
| 1743 | struct pevent_record *record, enum pevent_errno *err) | ||
| 1619 | { | 1744 | { |
| 1620 | unsigned long long lval, rval; | 1745 | unsigned long long lval, rval; |
| 1621 | 1746 | ||
| 1622 | lval = get_arg_value(event, arg->exp.left, record); | 1747 | lval = get_arg_value(event, arg->exp.left, record, err); |
| 1623 | rval = get_arg_value(event, arg->exp.right, record); | 1748 | rval = get_arg_value(event, arg->exp.right, record, err); |
| 1749 | |||
| 1750 | if (*err) { | ||
| 1751 | /* | ||
| 1752 | * There was an error, no need to process anymore. | ||
| 1753 | */ | ||
| 1754 | return 0; | ||
| 1755 | } | ||
| 1624 | 1756 | ||
| 1625 | switch (arg->exp.type) { | 1757 | switch (arg->exp.type) { |
| 1626 | case FILTER_EXP_ADD: | 1758 | case FILTER_EXP_ADD: |
| @@ -1655,39 +1787,51 @@ get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_ | |||
| 1655 | 1787 | ||
| 1656 | case FILTER_EXP_NOT: | 1788 | case FILTER_EXP_NOT: |
| 1657 | default: | 1789 | default: |
| 1658 | die("error in exp"); | 1790 | if (!*err) |
| 1791 | *err = PEVENT_ERRNO__INVALID_EXP_TYPE; | ||
| 1659 | } | 1792 | } |
| 1660 | return 0; | 1793 | return 0; |
| 1661 | } | 1794 | } |
| 1662 | 1795 | ||
| 1663 | static unsigned long long | 1796 | static unsigned long long |
| 1664 | get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record) | 1797 | get_arg_value(struct event_format *event, struct filter_arg *arg, |
| 1798 | struct pevent_record *record, enum pevent_errno *err) | ||
| 1665 | { | 1799 | { |
| 1666 | switch (arg->type) { | 1800 | switch (arg->type) { |
| 1667 | case FILTER_ARG_FIELD: | 1801 | case FILTER_ARG_FIELD: |
| 1668 | return get_value(event, arg->field.field, record); | 1802 | return get_value(event, arg->field.field, record); |
| 1669 | 1803 | ||
| 1670 | case FILTER_ARG_VALUE: | 1804 | case FILTER_ARG_VALUE: |
| 1671 | if (arg->value.type != FILTER_NUMBER) | 1805 | if (arg->value.type != FILTER_NUMBER) { |
| 1672 | die("must have number field!"); | 1806 | if (!*err) |
| 1807 | *err = PEVENT_ERRNO__NOT_A_NUMBER; | ||
| 1808 | } | ||
| 1673 | return arg->value.val; | 1809 | return arg->value.val; |
| 1674 | 1810 | ||
| 1675 | case FILTER_ARG_EXP: | 1811 | case FILTER_ARG_EXP: |
| 1676 | return get_exp_value(event, arg, record); | 1812 | return get_exp_value(event, arg, record, err); |
| 1677 | 1813 | ||
| 1678 | default: | 1814 | default: |
| 1679 | die("oops in filter"); | 1815 | if (!*err) |
| 1816 | *err = PEVENT_ERRNO__INVALID_ARG_TYPE; | ||
| 1680 | } | 1817 | } |
| 1681 | return 0; | 1818 | return 0; |
| 1682 | } | 1819 | } |
| 1683 | 1820 | ||
| 1684 | static int test_num(struct event_format *event, | 1821 | static int test_num(struct event_format *event, struct filter_arg *arg, |
| 1685 | struct filter_arg *arg, struct pevent_record *record) | 1822 | struct pevent_record *record, enum pevent_errno *err) |
| 1686 | { | 1823 | { |
| 1687 | unsigned long long lval, rval; | 1824 | unsigned long long lval, rval; |
| 1688 | 1825 | ||
| 1689 | lval = get_arg_value(event, arg->num.left, record); | 1826 | lval = get_arg_value(event, arg->num.left, record, err); |
| 1690 | rval = get_arg_value(event, arg->num.right, record); | 1827 | rval = get_arg_value(event, arg->num.right, record, err); |
| 1828 | |||
| 1829 | if (*err) { | ||
| 1830 | /* | ||
| 1831 | * There was an error, no need to process anymore. | ||
| 1832 | */ | ||
| 1833 | return 0; | ||
| 1834 | } | ||
| 1691 | 1835 | ||
| 1692 | switch (arg->num.type) { | 1836 | switch (arg->num.type) { |
| 1693 | case FILTER_CMP_EQ: | 1837 | case FILTER_CMP_EQ: |
| @@ -1709,7 +1853,8 @@ static int test_num(struct event_format *event, | |||
| 1709 | return lval <= rval; | 1853 | return lval <= rval; |
| 1710 | 1854 | ||
| 1711 | default: | 1855 | default: |
| 1712 | /* ?? */ | 1856 | if (!*err) |
| 1857 | *err = PEVENT_ERRNO__ILLEGAL_INTEGER_CMP; | ||
| 1713 | return 0; | 1858 | return 0; |
| 1714 | } | 1859 | } |
| 1715 | } | 1860 | } |
| @@ -1756,8 +1901,8 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r | |||
| 1756 | return val; | 1901 | return val; |
| 1757 | } | 1902 | } |
| 1758 | 1903 | ||
| 1759 | static int test_str(struct event_format *event, | 1904 | static int test_str(struct event_format *event, struct filter_arg *arg, |
| 1760 | struct filter_arg *arg, struct pevent_record *record) | 1905 | struct pevent_record *record, enum pevent_errno *err) |
| 1761 | { | 1906 | { |
| 1762 | const char *val; | 1907 | const char *val; |
| 1763 | 1908 | ||
| @@ -1781,48 +1926,57 @@ static int test_str(struct event_format *event, | |||
| 1781 | return regexec(&arg->str.reg, val, 0, NULL, 0); | 1926 | return regexec(&arg->str.reg, val, 0, NULL, 0); |
| 1782 | 1927 | ||
| 1783 | default: | 1928 | default: |
| 1784 | /* ?? */ | 1929 | if (!*err) |
| 1930 | *err = PEVENT_ERRNO__ILLEGAL_STRING_CMP; | ||
| 1785 | return 0; | 1931 | return 0; |
| 1786 | } | 1932 | } |
| 1787 | } | 1933 | } |
| 1788 | 1934 | ||
| 1789 | static int test_op(struct event_format *event, | 1935 | static int test_op(struct event_format *event, struct filter_arg *arg, |
| 1790 | struct filter_arg *arg, struct pevent_record *record) | 1936 | struct pevent_record *record, enum pevent_errno *err) |
| 1791 | { | 1937 | { |
| 1792 | switch (arg->op.type) { | 1938 | switch (arg->op.type) { |
| 1793 | case FILTER_OP_AND: | 1939 | case FILTER_OP_AND: |
| 1794 | return test_filter(event, arg->op.left, record) && | 1940 | return test_filter(event, arg->op.left, record, err) && |
| 1795 | test_filter(event, arg->op.right, record); | 1941 | test_filter(event, arg->op.right, record, err); |
| 1796 | 1942 | ||
| 1797 | case FILTER_OP_OR: | 1943 | case FILTER_OP_OR: |
| 1798 | return test_filter(event, arg->op.left, record) || | 1944 | return test_filter(event, arg->op.left, record, err) || |
| 1799 | test_filter(event, arg->op.right, record); | 1945 | test_filter(event, arg->op.right, record, err); |
| 1800 | 1946 | ||
| 1801 | case FILTER_OP_NOT: | 1947 | case FILTER_OP_NOT: |
| 1802 | return !test_filter(event, arg->op.right, record); | 1948 | return !test_filter(event, arg->op.right, record, err); |
| 1803 | 1949 | ||
| 1804 | default: | 1950 | default: |
| 1805 | /* ?? */ | 1951 | if (!*err) |
| 1952 | *err = PEVENT_ERRNO__INVALID_OP_TYPE; | ||
| 1806 | return 0; | 1953 | return 0; |
| 1807 | } | 1954 | } |
| 1808 | } | 1955 | } |
| 1809 | 1956 | ||
| 1810 | static int test_filter(struct event_format *event, | 1957 | static int test_filter(struct event_format *event, struct filter_arg *arg, |
| 1811 | struct filter_arg *arg, struct pevent_record *record) | 1958 | struct pevent_record *record, enum pevent_errno *err) |
| 1812 | { | 1959 | { |
| 1960 | if (*err) { | ||
| 1961 | /* | ||
| 1962 | * There was an error, no need to process anymore. | ||
| 1963 | */ | ||
| 1964 | return 0; | ||
| 1965 | } | ||
| 1966 | |||
| 1813 | switch (arg->type) { | 1967 | switch (arg->type) { |
| 1814 | case FILTER_ARG_BOOLEAN: | 1968 | case FILTER_ARG_BOOLEAN: |
| 1815 | /* easy case */ | 1969 | /* easy case */ |
| 1816 | return arg->boolean.value; | 1970 | return arg->boolean.value; |
| 1817 | 1971 | ||
| 1818 | case FILTER_ARG_OP: | 1972 | case FILTER_ARG_OP: |
| 1819 | return test_op(event, arg, record); | 1973 | return test_op(event, arg, record, err); |
| 1820 | 1974 | ||
| 1821 | case FILTER_ARG_NUM: | 1975 | case FILTER_ARG_NUM: |
| 1822 | return test_num(event, arg, record); | 1976 | return test_num(event, arg, record, err); |
| 1823 | 1977 | ||
| 1824 | case FILTER_ARG_STR: | 1978 | case FILTER_ARG_STR: |
| 1825 | return test_str(event, arg, record); | 1979 | return test_str(event, arg, record, err); |
| 1826 | 1980 | ||
| 1827 | case FILTER_ARG_EXP: | 1981 | case FILTER_ARG_EXP: |
| 1828 | case FILTER_ARG_VALUE: | 1982 | case FILTER_ARG_VALUE: |
| @@ -1831,11 +1985,11 @@ static int test_filter(struct event_format *event, | |||
| 1831 | * Expressions, fields and values evaluate | 1985 | * Expressions, fields and values evaluate |
| 1832 | * to true if they return non zero | 1986 | * to true if they return non zero |
| 1833 | */ | 1987 | */ |
| 1834 | return !!get_arg_value(event, arg, record); | 1988 | return !!get_arg_value(event, arg, record, err); |
| 1835 | 1989 | ||
| 1836 | default: | 1990 | default: |
| 1837 | die("oops!"); | 1991 | if (!*err) |
| 1838 | /* ?? */ | 1992 | *err = PEVENT_ERRNO__INVALID_ARG_TYPE; |
| 1839 | return 0; | 1993 | return 0; |
| 1840 | } | 1994 | } |
| 1841 | } | 1995 | } |
| @@ -1848,8 +2002,7 @@ static int test_filter(struct event_format *event, | |||
| 1848 | * Returns 1 if filter found for @event_id | 2002 | * Returns 1 if filter found for @event_id |
| 1849 | * otherwise 0; | 2003 | * otherwise 0; |
| 1850 | */ | 2004 | */ |
| 1851 | int pevent_event_filtered(struct event_filter *filter, | 2005 | int pevent_event_filtered(struct event_filter *filter, int event_id) |
| 1852 | int event_id) | ||
| 1853 | { | 2006 | { |
| 1854 | struct filter_type *filter_type; | 2007 | struct filter_type *filter_type; |
| 1855 | 2008 | ||
| @@ -1866,31 +2019,38 @@ int pevent_event_filtered(struct event_filter *filter, | |||
| 1866 | * @filter: filter struct with filter information | 2019 | * @filter: filter struct with filter information |
| 1867 | * @record: the record to test against the filter | 2020 | * @record: the record to test against the filter |
| 1868 | * | 2021 | * |
| 1869 | * Returns: | 2022 | * Returns: match result or error code (prefixed with PEVENT_ERRNO__) |
| 1870 | * 1 - filter found for event and @record matches | 2023 | * FILTER_MATCH - filter found for event and @record matches |
| 1871 | * 0 - filter found for event and @record does not match | 2024 | * FILTER_MISS - filter found for event and @record does not match |
| 1872 | * -1 - no filter found for @record's event | 2025 | * FILTER_NOT_FOUND - no filter found for @record's event |
| 1873 | * -2 - if no filters exist | 2026 | * NO_FILTER - if no filters exist |
| 2027 | * otherwise - error occurred during test | ||
| 1874 | */ | 2028 | */ |
| 1875 | int pevent_filter_match(struct event_filter *filter, | 2029 | enum pevent_errno pevent_filter_match(struct event_filter *filter, |
| 1876 | struct pevent_record *record) | 2030 | struct pevent_record *record) |
| 1877 | { | 2031 | { |
| 1878 | struct pevent *pevent = filter->pevent; | 2032 | struct pevent *pevent = filter->pevent; |
| 1879 | struct filter_type *filter_type; | 2033 | struct filter_type *filter_type; |
| 1880 | int event_id; | 2034 | int event_id; |
| 2035 | int ret; | ||
| 2036 | enum pevent_errno err = 0; | ||
| 2037 | |||
| 2038 | filter_init_error_buf(filter); | ||
| 1881 | 2039 | ||
| 1882 | if (!filter->filters) | 2040 | if (!filter->filters) |
| 1883 | return FILTER_NONE; | 2041 | return PEVENT_ERRNO__NO_FILTER; |
| 1884 | 2042 | ||
| 1885 | event_id = pevent_data_type(pevent, record); | 2043 | event_id = pevent_data_type(pevent, record); |
| 1886 | 2044 | ||
| 1887 | filter_type = find_filter_type(filter, event_id); | 2045 | filter_type = find_filter_type(filter, event_id); |
| 1888 | |||
| 1889 | if (!filter_type) | 2046 | if (!filter_type) |
| 1890 | return FILTER_NOEXIST; | 2047 | return PEVENT_ERRNO__FILTER_NOT_FOUND; |
| 2048 | |||
| 2049 | ret = test_filter(filter_type->event, filter_type->filter, record, &err); | ||
| 2050 | if (err) | ||
| 2051 | return err; | ||
| 1891 | 2052 | ||
| 1892 | return test_filter(filter_type->event, filter_type->filter, record) ? | 2053 | return ret ? PEVENT_ERRNO__FILTER_MATCH : PEVENT_ERRNO__FILTER_MISS; |
| 1893 | FILTER_MATCH : FILTER_MISS; | ||
| 1894 | } | 2054 | } |
| 1895 | 2055 | ||
| 1896 | static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | 2056 | static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) |
| @@ -1902,7 +2062,6 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 1902 | int left_val = -1; | 2062 | int left_val = -1; |
| 1903 | int right_val = -1; | 2063 | int right_val = -1; |
| 1904 | int val; | 2064 | int val; |
| 1905 | int len; | ||
| 1906 | 2065 | ||
| 1907 | switch (arg->op.type) { | 2066 | switch (arg->op.type) { |
| 1908 | case FILTER_OP_AND: | 2067 | case FILTER_OP_AND: |
| @@ -1949,11 +2108,7 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 1949 | default: | 2108 | default: |
| 1950 | break; | 2109 | break; |
| 1951 | } | 2110 | } |
| 1952 | str = malloc_or_die(6); | 2111 | asprintf(&str, val ? "TRUE" : "FALSE"); |
| 1953 | if (val) | ||
| 1954 | strcpy(str, "TRUE"); | ||
| 1955 | else | ||
| 1956 | strcpy(str, "FALSE"); | ||
| 1957 | break; | 2112 | break; |
| 1958 | } | 2113 | } |
| 1959 | } | 2114 | } |
| @@ -1971,10 +2126,7 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 1971 | break; | 2126 | break; |
| 1972 | } | 2127 | } |
| 1973 | 2128 | ||
| 1974 | len = strlen(left) + strlen(right) + strlen(op) + 10; | 2129 | asprintf(&str, "(%s) %s (%s)", left, op, right); |
| 1975 | str = malloc_or_die(len); | ||
| 1976 | snprintf(str, len, "(%s) %s (%s)", | ||
| 1977 | left, op, right); | ||
| 1978 | break; | 2130 | break; |
| 1979 | 2131 | ||
| 1980 | case FILTER_OP_NOT: | 2132 | case FILTER_OP_NOT: |
| @@ -1990,16 +2142,10 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 1990 | right_val = 0; | 2142 | right_val = 0; |
| 1991 | if (right_val >= 0) { | 2143 | if (right_val >= 0) { |
| 1992 | /* just return the opposite */ | 2144 | /* just return the opposite */ |
| 1993 | str = malloc_or_die(6); | 2145 | asprintf(&str, right_val ? "FALSE" : "TRUE"); |
| 1994 | if (right_val) | ||
| 1995 | strcpy(str, "FALSE"); | ||
| 1996 | else | ||
| 1997 | strcpy(str, "TRUE"); | ||
| 1998 | break; | 2146 | break; |
| 1999 | } | 2147 | } |
| 2000 | len = strlen(right) + strlen(op) + 3; | 2148 | asprintf(&str, "%s(%s)", op, right); |
| 2001 | str = malloc_or_die(len); | ||
| 2002 | snprintf(str, len, "%s(%s)", op, right); | ||
| 2003 | break; | 2149 | break; |
| 2004 | 2150 | ||
| 2005 | default: | 2151 | default: |
| @@ -2013,11 +2159,9 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 2013 | 2159 | ||
| 2014 | static char *val_to_str(struct event_filter *filter, struct filter_arg *arg) | 2160 | static char *val_to_str(struct event_filter *filter, struct filter_arg *arg) |
| 2015 | { | 2161 | { |
| 2016 | char *str; | 2162 | char *str = NULL; |
| 2017 | |||
| 2018 | str = malloc_or_die(30); | ||
| 2019 | 2163 | ||
| 2020 | snprintf(str, 30, "%lld", arg->value.val); | 2164 | asprintf(&str, "%lld", arg->value.val); |
| 2021 | 2165 | ||
| 2022 | return str; | 2166 | return str; |
| 2023 | } | 2167 | } |
| @@ -2033,7 +2177,6 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 2033 | char *rstr; | 2177 | char *rstr; |
| 2034 | char *op; | 2178 | char *op; |
| 2035 | char *str = NULL; | 2179 | char *str = NULL; |
| 2036 | int len; | ||
| 2037 | 2180 | ||
| 2038 | lstr = arg_to_str(filter, arg->exp.left); | 2181 | lstr = arg_to_str(filter, arg->exp.left); |
| 2039 | rstr = arg_to_str(filter, arg->exp.right); | 2182 | rstr = arg_to_str(filter, arg->exp.right); |
| @@ -2072,12 +2215,11 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 2072 | op = "^"; | 2215 | op = "^"; |
| 2073 | break; | 2216 | break; |
| 2074 | default: | 2217 | default: |
| 2075 | die("oops in exp"); | 2218 | op = "[ERROR IN EXPRESSION TYPE]"; |
| 2219 | break; | ||
| 2076 | } | 2220 | } |
| 2077 | 2221 | ||
| 2078 | len = strlen(op) + strlen(lstr) + strlen(rstr) + 4; | 2222 | asprintf(&str, "%s %s %s", lstr, op, rstr); |
| 2079 | str = malloc_or_die(len); | ||
| 2080 | snprintf(str, len, "%s %s %s", lstr, op, rstr); | ||
| 2081 | out: | 2223 | out: |
| 2082 | free(lstr); | 2224 | free(lstr); |
| 2083 | free(rstr); | 2225 | free(rstr); |
| @@ -2091,7 +2233,6 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 2091 | char *rstr; | 2233 | char *rstr; |
| 2092 | char *str = NULL; | 2234 | char *str = NULL; |
| 2093 | char *op = NULL; | 2235 | char *op = NULL; |
| 2094 | int len; | ||
| 2095 | 2236 | ||
| 2096 | lstr = arg_to_str(filter, arg->num.left); | 2237 | lstr = arg_to_str(filter, arg->num.left); |
| 2097 | rstr = arg_to_str(filter, arg->num.right); | 2238 | rstr = arg_to_str(filter, arg->num.right); |
| @@ -2122,10 +2263,7 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 2122 | if (!op) | 2263 | if (!op) |
| 2123 | op = "<="; | 2264 | op = "<="; |
| 2124 | 2265 | ||
| 2125 | len = strlen(lstr) + strlen(op) + strlen(rstr) + 4; | 2266 | asprintf(&str, "%s %s %s", lstr, op, rstr); |
| 2126 | str = malloc_or_die(len); | ||
| 2127 | sprintf(str, "%s %s %s", lstr, op, rstr); | ||
| 2128 | |||
| 2129 | break; | 2267 | break; |
| 2130 | 2268 | ||
| 2131 | default: | 2269 | default: |
| @@ -2143,7 +2281,6 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 2143 | { | 2281 | { |
| 2144 | char *str = NULL; | 2282 | char *str = NULL; |
| 2145 | char *op = NULL; | 2283 | char *op = NULL; |
| 2146 | int len; | ||
| 2147 | 2284 | ||
| 2148 | switch (arg->str.type) { | 2285 | switch (arg->str.type) { |
| 2149 | case FILTER_CMP_MATCH: | 2286 | case FILTER_CMP_MATCH: |
| @@ -2161,12 +2298,8 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 2161 | if (!op) | 2298 | if (!op) |
| 2162 | op = "!~"; | 2299 | op = "!~"; |
| 2163 | 2300 | ||
| 2164 | len = strlen(arg->str.field->name) + strlen(op) + | 2301 | asprintf(&str, "%s %s \"%s\"", |
| 2165 | strlen(arg->str.val) + 6; | 2302 | arg->str.field->name, op, arg->str.val); |
| 2166 | str = malloc_or_die(len); | ||
| 2167 | snprintf(str, len, "%s %s \"%s\"", | ||
| 2168 | arg->str.field->name, | ||
| 2169 | op, arg->str.val); | ||
| 2170 | break; | 2303 | break; |
| 2171 | 2304 | ||
| 2172 | default: | 2305 | default: |
| @@ -2178,15 +2311,11 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 2178 | 2311 | ||
| 2179 | static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg) | 2312 | static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg) |
| 2180 | { | 2313 | { |
| 2181 | char *str; | 2314 | char *str = NULL; |
| 2182 | 2315 | ||
| 2183 | switch (arg->type) { | 2316 | switch (arg->type) { |
| 2184 | case FILTER_ARG_BOOLEAN: | 2317 | case FILTER_ARG_BOOLEAN: |
| 2185 | str = malloc_or_die(6); | 2318 | asprintf(&str, arg->boolean.value ? "TRUE" : "FALSE"); |
| 2186 | if (arg->boolean.value) | ||
| 2187 | strcpy(str, "TRUE"); | ||
| 2188 | else | ||
| 2189 | strcpy(str, "FALSE"); | ||
| 2190 | return str; | 2319 | return str; |
| 2191 | 2320 | ||
| 2192 | case FILTER_ARG_OP: | 2321 | case FILTER_ARG_OP: |
| @@ -2221,7 +2350,7 @@ static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
| 2221 | * | 2350 | * |
| 2222 | * Returns a string that displays the filter contents. | 2351 | * Returns a string that displays the filter contents. |
| 2223 | * This string must be freed with free(str). | 2352 | * This string must be freed with free(str). |
| 2224 | * NULL is returned if no filter is found. | 2353 | * NULL is returned if no filter is found or allocation failed. |
| 2225 | */ | 2354 | */ |
| 2226 | char * | 2355 | char * |
| 2227 | pevent_filter_make_string(struct event_filter *filter, int event_id) | 2356 | pevent_filter_make_string(struct event_filter *filter, int event_id) |
diff --git a/tools/lib/traceevent/plugin_cfg80211.c b/tools/lib/traceevent/plugin_cfg80211.c new file mode 100644 index 000000000000..dcab8e873c21 --- /dev/null +++ b/tools/lib/traceevent/plugin_cfg80211.c | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <string.h> | ||
| 3 | #include <inttypes.h> | ||
| 4 | #include <endian.h> | ||
| 5 | #include "event-parse.h" | ||
| 6 | |||
| 7 | static unsigned long long | ||
| 8 | process___le16_to_cpup(struct trace_seq *s, | ||
| 9 | unsigned long long *args) | ||
| 10 | { | ||
| 11 | uint16_t *val = (uint16_t *) args[0]; | ||
| 12 | return val ? (long long) le16toh(*val) : 0; | ||
| 13 | } | ||
| 14 | |||
| 15 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 16 | { | ||
| 17 | pevent_register_print_function(pevent, | ||
| 18 | process___le16_to_cpup, | ||
| 19 | PEVENT_FUNC_ARG_INT, | ||
| 20 | "__le16_to_cpup", | ||
| 21 | PEVENT_FUNC_ARG_PTR, | ||
| 22 | PEVENT_FUNC_ARG_VOID); | ||
| 23 | return 0; | ||
| 24 | } | ||
diff --git a/tools/lib/traceevent/plugin_function.c b/tools/lib/traceevent/plugin_function.c new file mode 100644 index 000000000000..aad92ad5e96f --- /dev/null +++ b/tools/lib/traceevent/plugin_function.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 | #include "event-utils.h" | ||
| 26 | |||
| 27 | static struct func_stack { | ||
| 28 | int size; | ||
| 29 | char **stack; | ||
| 30 | } *fstack; | ||
| 31 | |||
| 32 | static int cpus = -1; | ||
| 33 | |||
| 34 | #define STK_BLK 10 | ||
| 35 | |||
| 36 | static void add_child(struct func_stack *stack, const char *child, int pos) | ||
| 37 | { | ||
| 38 | int i; | ||
| 39 | |||
| 40 | if (!child) | ||
| 41 | return; | ||
| 42 | |||
| 43 | if (pos < stack->size) | ||
| 44 | free(stack->stack[pos]); | ||
| 45 | else { | ||
| 46 | char **ptr; | ||
| 47 | |||
| 48 | ptr = realloc(stack->stack, sizeof(char *) * | ||
| 49 | (stack->size + STK_BLK)); | ||
| 50 | if (!ptr) { | ||
| 51 | warning("could not allocate plugin memory\n"); | ||
| 52 | return; | ||
| 53 | } | ||
| 54 | |||
| 55 | stack->stack = ptr; | ||
| 56 | |||
| 57 | for (i = stack->size; i < stack->size + STK_BLK; i++) | ||
| 58 | stack->stack[i] = NULL; | ||
| 59 | stack->size += STK_BLK; | ||
| 60 | } | ||
| 61 | |||
| 62 | stack->stack[pos] = strdup(child); | ||
| 63 | } | ||
| 64 | |||
| 65 | static int add_and_get_index(const char *parent, const char *child, int cpu) | ||
| 66 | { | ||
| 67 | int i; | ||
| 68 | |||
| 69 | if (cpu < 0) | ||
| 70 | return 0; | ||
| 71 | |||
| 72 | if (cpu > cpus) { | ||
| 73 | struct func_stack *ptr; | ||
| 74 | |||
| 75 | ptr = realloc(fstack, sizeof(*fstack) * (cpu + 1)); | ||
| 76 | if (!ptr) { | ||
| 77 | warning("could not allocate plugin memory\n"); | ||
| 78 | return 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | fstack = ptr; | ||
| 82 | |||
| 83 | /* Account for holes in the cpu count */ | ||
| 84 | for (i = cpus + 1; i <= cpu; i++) | ||
| 85 | memset(&fstack[i], 0, sizeof(fstack[i])); | ||
| 86 | cpus = cpu; | ||
| 87 | } | ||
| 88 | |||
| 89 | for (i = 0; i < fstack[cpu].size && fstack[cpu].stack[i]; i++) { | ||
| 90 | if (strcmp(parent, fstack[cpu].stack[i]) == 0) { | ||
| 91 | add_child(&fstack[cpu], child, i+1); | ||
| 92 | return i; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | /* Not found */ | ||
| 97 | add_child(&fstack[cpu], parent, 0); | ||
| 98 | add_child(&fstack[cpu], child, 1); | ||
| 99 | return 0; | ||
| 100 | } | ||
| 101 | |||
| 102 | static int function_handler(struct trace_seq *s, struct pevent_record *record, | ||
| 103 | struct event_format *event, void *context) | ||
| 104 | { | ||
| 105 | struct pevent *pevent = event->pevent; | ||
| 106 | unsigned long long function; | ||
| 107 | unsigned long long pfunction; | ||
| 108 | const char *func; | ||
| 109 | const char *parent; | ||
| 110 | int index; | ||
| 111 | |||
| 112 | if (pevent_get_field_val(s, event, "ip", record, &function, 1)) | ||
| 113 | return trace_seq_putc(s, '!'); | ||
| 114 | |||
| 115 | func = pevent_find_function(pevent, function); | ||
| 116 | |||
| 117 | if (pevent_get_field_val(s, event, "parent_ip", record, &pfunction, 1)) | ||
| 118 | return trace_seq_putc(s, '!'); | ||
| 119 | |||
| 120 | parent = pevent_find_function(pevent, pfunction); | ||
| 121 | |||
| 122 | index = add_and_get_index(parent, func, record->cpu); | ||
| 123 | |||
| 124 | trace_seq_printf(s, "%*s", index*3, ""); | ||
| 125 | |||
| 126 | if (func) | ||
| 127 | trace_seq_printf(s, "%s", func); | ||
| 128 | else | ||
| 129 | trace_seq_printf(s, "0x%llx", function); | ||
| 130 | |||
| 131 | trace_seq_printf(s, " <-- "); | ||
| 132 | if (parent) | ||
| 133 | trace_seq_printf(s, "%s", parent); | ||
| 134 | else | ||
| 135 | trace_seq_printf(s, "0x%llx", pfunction); | ||
| 136 | |||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 141 | { | ||
| 142 | pevent_register_event_handler(pevent, -1, "ftrace", "function", | ||
| 143 | function_handler, NULL); | ||
| 144 | return 0; | ||
| 145 | } | ||
| 146 | |||
| 147 | void PEVENT_PLUGIN_UNLOADER(void) | ||
| 148 | { | ||
| 149 | int i, x; | ||
| 150 | |||
| 151 | for (i = 0; i <= cpus; i++) { | ||
| 152 | for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++) | ||
| 153 | free(fstack[i].stack[x]); | ||
| 154 | free(fstack[i].stack); | ||
| 155 | } | ||
| 156 | |||
| 157 | free(fstack); | ||
| 158 | fstack = NULL; | ||
| 159 | cpus = -1; | ||
| 160 | } | ||
diff --git a/tools/lib/traceevent/plugin_hrtimer.c b/tools/lib/traceevent/plugin_hrtimer.c new file mode 100644 index 000000000000..0b0ebf30aa44 --- /dev/null +++ b/tools/lib/traceevent/plugin_hrtimer.c | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * Copyright (C) 2009 Johannes Berg <johannes@sipsolutions.net> | ||
| 4 | * | ||
| 5 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; | ||
| 9 | * version 2.1 of the License (not later!) | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
| 18 | * | ||
| 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 20 | */ | ||
| 21 | #include <stdio.h> | ||
| 22 | #include <stdlib.h> | ||
| 23 | #include <string.h> | ||
| 24 | |||
| 25 | #include "event-parse.h" | ||
| 26 | |||
| 27 | static int timer_expire_handler(struct trace_seq *s, | ||
| 28 | struct pevent_record *record, | ||
| 29 | struct event_format *event, void *context) | ||
| 30 | { | ||
| 31 | trace_seq_printf(s, "hrtimer="); | ||
| 32 | |||
| 33 | if (pevent_print_num_field(s, "0x%llx", event, "timer", | ||
| 34 | record, 0) == -1) | ||
| 35 | pevent_print_num_field(s, "0x%llx", event, "hrtimer", | ||
| 36 | record, 1); | ||
| 37 | |||
| 38 | trace_seq_printf(s, " now="); | ||
| 39 | |||
| 40 | pevent_print_num_field(s, "%llu", event, "now", record, 1); | ||
| 41 | |||
| 42 | pevent_print_func_field(s, " function=%s", event, "function", | ||
| 43 | record, 0); | ||
| 44 | return 0; | ||
| 45 | } | ||
| 46 | |||
| 47 | static int timer_start_handler(struct trace_seq *s, | ||
| 48 | struct pevent_record *record, | ||
| 49 | struct event_format *event, void *context) | ||
| 50 | { | ||
| 51 | trace_seq_printf(s, "hrtimer="); | ||
| 52 | |||
| 53 | if (pevent_print_num_field(s, "0x%llx", event, "timer", | ||
| 54 | record, 0) == -1) | ||
| 55 | pevent_print_num_field(s, "0x%llx", event, "hrtimer", | ||
| 56 | record, 1); | ||
| 57 | |||
| 58 | pevent_print_func_field(s, " function=%s", event, "function", | ||
| 59 | record, 0); | ||
| 60 | |||
| 61 | trace_seq_printf(s, " expires="); | ||
| 62 | pevent_print_num_field(s, "%llu", event, "expires", record, 1); | ||
| 63 | |||
| 64 | trace_seq_printf(s, " softexpires="); | ||
| 65 | pevent_print_num_field(s, "%llu", event, "softexpires", record, 1); | ||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 70 | { | ||
| 71 | pevent_register_event_handler(pevent, -1, | ||
| 72 | "timer", "hrtimer_expire_entry", | ||
| 73 | timer_expire_handler, NULL); | ||
| 74 | |||
| 75 | pevent_register_event_handler(pevent, -1, "timer", "hrtimer_start", | ||
| 76 | timer_start_handler, NULL); | ||
| 77 | return 0; | ||
| 78 | } | ||
diff --git a/tools/lib/traceevent/plugin_jbd2.c b/tools/lib/traceevent/plugin_jbd2.c new file mode 100644 index 000000000000..2f93f81f0bac --- /dev/null +++ b/tools/lib/traceevent/plugin_jbd2.c | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; | ||
| 8 | * version 2.1 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
| 17 | * | ||
| 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 19 | */ | ||
| 20 | #include <stdio.h> | ||
| 21 | #include <stdlib.h> | ||
| 22 | #include <string.h> | ||
| 23 | |||
| 24 | #include "event-parse.h" | ||
| 25 | |||
| 26 | #define MINORBITS 20 | ||
| 27 | #define MINORMASK ((1U << MINORBITS) - 1) | ||
| 28 | |||
| 29 | #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) | ||
| 30 | #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) | ||
| 31 | |||
| 32 | static unsigned long long | ||
| 33 | process_jbd2_dev_to_name(struct trace_seq *s, | ||
| 34 | unsigned long long *args) | ||
| 35 | { | ||
| 36 | unsigned int dev = args[0]; | ||
| 37 | |||
| 38 | trace_seq_printf(s, "%d:%d", MAJOR(dev), MINOR(dev)); | ||
| 39 | return 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | static unsigned long long | ||
| 43 | process_jiffies_to_msecs(struct trace_seq *s, | ||
| 44 | unsigned long long *args) | ||
| 45 | { | ||
| 46 | unsigned long long jiffies = args[0]; | ||
| 47 | |||
| 48 | trace_seq_printf(s, "%lld", jiffies); | ||
| 49 | return jiffies; | ||
| 50 | } | ||
| 51 | |||
| 52 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 53 | { | ||
| 54 | pevent_register_print_function(pevent, | ||
| 55 | process_jbd2_dev_to_name, | ||
| 56 | PEVENT_FUNC_ARG_STRING, | ||
| 57 | "jbd2_dev_to_name", | ||
| 58 | PEVENT_FUNC_ARG_INT, | ||
| 59 | PEVENT_FUNC_ARG_VOID); | ||
| 60 | |||
| 61 | pevent_register_print_function(pevent, | ||
| 62 | process_jiffies_to_msecs, | ||
| 63 | PEVENT_FUNC_ARG_LONG, | ||
| 64 | "jiffies_to_msecs", | ||
| 65 | PEVENT_FUNC_ARG_LONG, | ||
| 66 | PEVENT_FUNC_ARG_VOID); | ||
| 67 | return 0; | ||
| 68 | } | ||
diff --git a/tools/lib/traceevent/plugin_kmem.c b/tools/lib/traceevent/plugin_kmem.c new file mode 100644 index 000000000000..7115c8037ea8 --- /dev/null +++ b/tools/lib/traceevent/plugin_kmem.c | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; | ||
| 8 | * version 2.1 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
| 17 | * | ||
| 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 19 | */ | ||
| 20 | #include <stdio.h> | ||
| 21 | #include <stdlib.h> | ||
| 22 | #include <string.h> | ||
| 23 | |||
| 24 | #include "event-parse.h" | ||
| 25 | |||
| 26 | static int call_site_handler(struct trace_seq *s, struct pevent_record *record, | ||
| 27 | struct event_format *event, void *context) | ||
| 28 | { | ||
| 29 | struct format_field *field; | ||
| 30 | unsigned long long val, addr; | ||
| 31 | void *data = record->data; | ||
| 32 | const char *func; | ||
| 33 | |||
| 34 | field = pevent_find_field(event, "call_site"); | ||
| 35 | if (!field) | ||
| 36 | return 1; | ||
| 37 | |||
| 38 | if (pevent_read_number_field(field, data, &val)) | ||
| 39 | return 1; | ||
| 40 | |||
| 41 | func = pevent_find_function(event->pevent, val); | ||
| 42 | if (!func) | ||
| 43 | return 1; | ||
| 44 | |||
| 45 | addr = pevent_find_function_address(event->pevent, val); | ||
| 46 | |||
| 47 | trace_seq_printf(s, "(%s+0x%x) ", func, (int)(val - addr)); | ||
| 48 | return 1; | ||
| 49 | } | ||
| 50 | |||
| 51 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 52 | { | ||
| 53 | pevent_register_event_handler(pevent, -1, "kmem", "kfree", | ||
| 54 | call_site_handler, NULL); | ||
| 55 | |||
| 56 | pevent_register_event_handler(pevent, -1, "kmem", "kmalloc", | ||
| 57 | call_site_handler, NULL); | ||
| 58 | |||
| 59 | pevent_register_event_handler(pevent, -1, "kmem", "kmalloc_node", | ||
| 60 | call_site_handler, NULL); | ||
| 61 | |||
| 62 | pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_alloc", | ||
| 63 | call_site_handler, NULL); | ||
| 64 | |||
| 65 | pevent_register_event_handler(pevent, -1, "kmem", | ||
| 66 | "kmem_cache_alloc_node", | ||
| 67 | call_site_handler, NULL); | ||
| 68 | |||
| 69 | pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_free", | ||
| 70 | call_site_handler, NULL); | ||
| 71 | return 0; | ||
| 72 | } | ||
diff --git a/tools/lib/traceevent/plugin_kvm.c b/tools/lib/traceevent/plugin_kvm.c new file mode 100644 index 000000000000..a0e282c6b967 --- /dev/null +++ b/tools/lib/traceevent/plugin_kvm.c | |||
| @@ -0,0 +1,436 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; | ||
| 8 | * version 2.1 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
| 17 | * | ||
| 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 19 | */ | ||
| 20 | #include <stdio.h> | ||
| 21 | #include <stdlib.h> | ||
| 22 | #include <string.h> | ||
| 23 | #include <stdint.h> | ||
| 24 | |||
| 25 | #include "event-parse.h" | ||
| 26 | |||
| 27 | #ifdef HAVE_UDIS86 | ||
| 28 | |||
| 29 | #include <udis86.h> | ||
| 30 | |||
| 31 | static ud_t ud; | ||
| 32 | |||
| 33 | static void init_disassembler(void) | ||
| 34 | { | ||
| 35 | ud_init(&ud); | ||
| 36 | ud_set_syntax(&ud, UD_SYN_ATT); | ||
| 37 | } | ||
| 38 | |||
| 39 | static const char *disassemble(unsigned char *insn, int len, uint64_t rip, | ||
| 40 | int cr0_pe, int eflags_vm, | ||
| 41 | int cs_d, int cs_l) | ||
| 42 | { | ||
| 43 | int mode; | ||
| 44 | |||
| 45 | if (!cr0_pe) | ||
| 46 | mode = 16; | ||
| 47 | else if (eflags_vm) | ||
| 48 | mode = 16; | ||
| 49 | else if (cs_l) | ||
| 50 | mode = 64; | ||
| 51 | else if (cs_d) | ||
| 52 | mode = 32; | ||
| 53 | else | ||
| 54 | mode = 16; | ||
| 55 | |||
| 56 | ud_set_pc(&ud, rip); | ||
| 57 | ud_set_mode(&ud, mode); | ||
| 58 | ud_set_input_buffer(&ud, insn, len); | ||
| 59 | ud_disassemble(&ud); | ||
| 60 | return ud_insn_asm(&ud); | ||
| 61 | } | ||
| 62 | |||
| 63 | #else | ||
| 64 | |||
| 65 | static void init_disassembler(void) | ||
| 66 | { | ||
| 67 | } | ||
| 68 | |||
| 69 | static const char *disassemble(unsigned char *insn, int len, uint64_t rip, | ||
| 70 | int cr0_pe, int eflags_vm, | ||
| 71 | int cs_d, int cs_l) | ||
| 72 | { | ||
| 73 | static char out[15*3+1]; | ||
| 74 | int i; | ||
| 75 | |||
| 76 | for (i = 0; i < len; ++i) | ||
| 77 | sprintf(out + i * 3, "%02x ", insn[i]); | ||
| 78 | out[len*3-1] = '\0'; | ||
| 79 | return out; | ||
| 80 | } | ||
| 81 | |||
| 82 | #endif | ||
| 83 | |||
| 84 | |||
| 85 | #define VMX_EXIT_REASONS \ | ||
| 86 | _ER(EXCEPTION_NMI, 0) \ | ||
| 87 | _ER(EXTERNAL_INTERRUPT, 1) \ | ||
| 88 | _ER(TRIPLE_FAULT, 2) \ | ||
| 89 | _ER(PENDING_INTERRUPT, 7) \ | ||
| 90 | _ER(NMI_WINDOW, 8) \ | ||
| 91 | _ER(TASK_SWITCH, 9) \ | ||
| 92 | _ER(CPUID, 10) \ | ||
| 93 | _ER(HLT, 12) \ | ||
| 94 | _ER(INVD, 13) \ | ||
| 95 | _ER(INVLPG, 14) \ | ||
| 96 | _ER(RDPMC, 15) \ | ||
| 97 | _ER(RDTSC, 16) \ | ||
| 98 | _ER(VMCALL, 18) \ | ||
| 99 | _ER(VMCLEAR, 19) \ | ||
| 100 | _ER(VMLAUNCH, 20) \ | ||
| 101 | _ER(VMPTRLD, 21) \ | ||
| 102 | _ER(VMPTRST, 22) \ | ||
| 103 | _ER(VMREAD, 23) \ | ||
| 104 | _ER(VMRESUME, 24) \ | ||
| 105 | _ER(VMWRITE, 25) \ | ||
| 106 | _ER(VMOFF, 26) \ | ||
| 107 | _ER(VMON, 27) \ | ||
| 108 | _ER(CR_ACCESS, 28) \ | ||
| 109 | _ER(DR_ACCESS, 29) \ | ||
| 110 | _ER(IO_INSTRUCTION, 30) \ | ||
| 111 | _ER(MSR_READ, 31) \ | ||
| 112 | _ER(MSR_WRITE, 32) \ | ||
| 113 | _ER(MWAIT_INSTRUCTION, 36) \ | ||
| 114 | _ER(MONITOR_INSTRUCTION, 39) \ | ||
| 115 | _ER(PAUSE_INSTRUCTION, 40) \ | ||
| 116 | _ER(MCE_DURING_VMENTRY, 41) \ | ||
| 117 | _ER(TPR_BELOW_THRESHOLD, 43) \ | ||
| 118 | _ER(APIC_ACCESS, 44) \ | ||
| 119 | _ER(EOI_INDUCED, 45) \ | ||
| 120 | _ER(EPT_VIOLATION, 48) \ | ||
| 121 | _ER(EPT_MISCONFIG, 49) \ | ||
| 122 | _ER(INVEPT, 50) \ | ||
| 123 | _ER(PREEMPTION_TIMER, 52) \ | ||
| 124 | _ER(WBINVD, 54) \ | ||
| 125 | _ER(XSETBV, 55) \ | ||
| 126 | _ER(APIC_WRITE, 56) \ | ||
| 127 | _ER(INVPCID, 58) | ||
| 128 | |||
| 129 | #define SVM_EXIT_REASONS \ | ||
| 130 | _ER(EXIT_READ_CR0, 0x000) \ | ||
| 131 | _ER(EXIT_READ_CR3, 0x003) \ | ||
| 132 | _ER(EXIT_READ_CR4, 0x004) \ | ||
| 133 | _ER(EXIT_READ_CR8, 0x008) \ | ||
| 134 | _ER(EXIT_WRITE_CR0, 0x010) \ | ||
| 135 | _ER(EXIT_WRITE_CR3, 0x013) \ | ||
| 136 | _ER(EXIT_WRITE_CR4, 0x014) \ | ||
| 137 | _ER(EXIT_WRITE_CR8, 0x018) \ | ||
| 138 | _ER(EXIT_READ_DR0, 0x020) \ | ||
| 139 | _ER(EXIT_READ_DR1, 0x021) \ | ||
| 140 | _ER(EXIT_READ_DR2, 0x022) \ | ||
| 141 | _ER(EXIT_READ_DR3, 0x023) \ | ||
| 142 | _ER(EXIT_READ_DR4, 0x024) \ | ||
| 143 | _ER(EXIT_READ_DR5, 0x025) \ | ||
| 144 | _ER(EXIT_READ_DR6, 0x026) \ | ||
| 145 | _ER(EXIT_READ_DR7, 0x027) \ | ||
| 146 | _ER(EXIT_WRITE_DR0, 0x030) \ | ||
| 147 | _ER(EXIT_WRITE_DR1, 0x031) \ | ||
| 148 | _ER(EXIT_WRITE_DR2, 0x032) \ | ||
| 149 | _ER(EXIT_WRITE_DR3, 0x033) \ | ||
| 150 | _ER(EXIT_WRITE_DR4, 0x034) \ | ||
| 151 | _ER(EXIT_WRITE_DR5, 0x035) \ | ||
| 152 | _ER(EXIT_WRITE_DR6, 0x036) \ | ||
| 153 | _ER(EXIT_WRITE_DR7, 0x037) \ | ||
| 154 | _ER(EXIT_EXCP_BASE, 0x040) \ | ||
| 155 | _ER(EXIT_INTR, 0x060) \ | ||
| 156 | _ER(EXIT_NMI, 0x061) \ | ||
| 157 | _ER(EXIT_SMI, 0x062) \ | ||
| 158 | _ER(EXIT_INIT, 0x063) \ | ||
| 159 | _ER(EXIT_VINTR, 0x064) \ | ||
| 160 | _ER(EXIT_CR0_SEL_WRITE, 0x065) \ | ||
| 161 | _ER(EXIT_IDTR_READ, 0x066) \ | ||
| 162 | _ER(EXIT_GDTR_READ, 0x067) \ | ||
| 163 | _ER(EXIT_LDTR_READ, 0x068) \ | ||
| 164 | _ER(EXIT_TR_READ, 0x069) \ | ||
| 165 | _ER(EXIT_IDTR_WRITE, 0x06a) \ | ||
| 166 | _ER(EXIT_GDTR_WRITE, 0x06b) \ | ||
| 167 | _ER(EXIT_LDTR_WRITE, 0x06c) \ | ||
| 168 | _ER(EXIT_TR_WRITE, 0x06d) \ | ||
| 169 | _ER(EXIT_RDTSC, 0x06e) \ | ||
| 170 | _ER(EXIT_RDPMC, 0x06f) \ | ||
| 171 | _ER(EXIT_PUSHF, 0x070) \ | ||
| 172 | _ER(EXIT_POPF, 0x071) \ | ||
| 173 | _ER(EXIT_CPUID, 0x072) \ | ||
| 174 | _ER(EXIT_RSM, 0x073) \ | ||
| 175 | _ER(EXIT_IRET, 0x074) \ | ||
| 176 | _ER(EXIT_SWINT, 0x075) \ | ||
| 177 | _ER(EXIT_INVD, 0x076) \ | ||
| 178 | _ER(EXIT_PAUSE, 0x077) \ | ||
| 179 | _ER(EXIT_HLT, 0x078) \ | ||
| 180 | _ER(EXIT_INVLPG, 0x079) \ | ||
| 181 | _ER(EXIT_INVLPGA, 0x07a) \ | ||
| 182 | _ER(EXIT_IOIO, 0x07b) \ | ||
| 183 | _ER(EXIT_MSR, 0x07c) \ | ||
| 184 | _ER(EXIT_TASK_SWITCH, 0x07d) \ | ||
| 185 | _ER(EXIT_FERR_FREEZE, 0x07e) \ | ||
| 186 | _ER(EXIT_SHUTDOWN, 0x07f) \ | ||
| 187 | _ER(EXIT_VMRUN, 0x080) \ | ||
| 188 | _ER(EXIT_VMMCALL, 0x081) \ | ||
| 189 | _ER(EXIT_VMLOAD, 0x082) \ | ||
| 190 | _ER(EXIT_VMSAVE, 0x083) \ | ||
| 191 | _ER(EXIT_STGI, 0x084) \ | ||
| 192 | _ER(EXIT_CLGI, 0x085) \ | ||
| 193 | _ER(EXIT_SKINIT, 0x086) \ | ||
| 194 | _ER(EXIT_RDTSCP, 0x087) \ | ||
| 195 | _ER(EXIT_ICEBP, 0x088) \ | ||
| 196 | _ER(EXIT_WBINVD, 0x089) \ | ||
| 197 | _ER(EXIT_MONITOR, 0x08a) \ | ||
| 198 | _ER(EXIT_MWAIT, 0x08b) \ | ||
| 199 | _ER(EXIT_MWAIT_COND, 0x08c) \ | ||
| 200 | _ER(EXIT_NPF, 0x400) \ | ||
| 201 | _ER(EXIT_ERR, -1) | ||
| 202 | |||
| 203 | #define _ER(reason, val) { #reason, val }, | ||
| 204 | struct str_values { | ||
| 205 | const char *str; | ||
| 206 | int val; | ||
| 207 | }; | ||
| 208 | |||
| 209 | static struct str_values vmx_exit_reasons[] = { | ||
| 210 | VMX_EXIT_REASONS | ||
| 211 | { NULL, -1} | ||
| 212 | }; | ||
| 213 | |||
| 214 | static struct str_values svm_exit_reasons[] = { | ||
| 215 | SVM_EXIT_REASONS | ||
| 216 | { NULL, -1} | ||
| 217 | }; | ||
| 218 | |||
| 219 | static struct isa_exit_reasons { | ||
| 220 | unsigned isa; | ||
| 221 | struct str_values *strings; | ||
| 222 | } isa_exit_reasons[] = { | ||
| 223 | { .isa = 1, .strings = vmx_exit_reasons }, | ||
| 224 | { .isa = 2, .strings = svm_exit_reasons }, | ||
| 225 | { } | ||
| 226 | }; | ||
| 227 | |||
| 228 | static const char *find_exit_reason(unsigned isa, int val) | ||
| 229 | { | ||
| 230 | struct str_values *strings = NULL; | ||
| 231 | int i; | ||
| 232 | |||
| 233 | for (i = 0; isa_exit_reasons[i].strings; ++i) | ||
| 234 | if (isa_exit_reasons[i].isa == isa) { | ||
| 235 | strings = isa_exit_reasons[i].strings; | ||
| 236 | break; | ||
| 237 | } | ||
| 238 | if (!strings) | ||
| 239 | return "UNKNOWN-ISA"; | ||
| 240 | for (i = 0; strings[i].val >= 0; i++) | ||
| 241 | if (strings[i].val == val) | ||
| 242 | break; | ||
| 243 | if (strings[i].str) | ||
| 244 | return strings[i].str; | ||
| 245 | return "UNKNOWN"; | ||
| 246 | } | ||
| 247 | |||
| 248 | static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record, | ||
| 249 | struct event_format *event, void *context) | ||
| 250 | { | ||
| 251 | unsigned long long isa; | ||
| 252 | unsigned long long val; | ||
| 253 | unsigned long long info1 = 0, info2 = 0; | ||
| 254 | |||
| 255 | if (pevent_get_field_val(s, event, "exit_reason", record, &val, 1) < 0) | ||
| 256 | return -1; | ||
| 257 | |||
| 258 | if (pevent_get_field_val(s, event, "isa", record, &isa, 0) < 0) | ||
| 259 | isa = 1; | ||
| 260 | |||
| 261 | trace_seq_printf(s, "reason %s", find_exit_reason(isa, val)); | ||
| 262 | |||
| 263 | pevent_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1); | ||
| 264 | |||
| 265 | if (pevent_get_field_val(s, event, "info1", record, &info1, 0) >= 0 | ||
| 266 | && pevent_get_field_val(s, event, "info2", record, &info2, 0) >= 0) | ||
| 267 | trace_seq_printf(s, " info %llx %llx", info1, info2); | ||
| 268 | |||
| 269 | return 0; | ||
| 270 | } | ||
| 271 | |||
| 272 | #define KVM_EMUL_INSN_F_CR0_PE (1 << 0) | ||
| 273 | #define KVM_EMUL_INSN_F_EFL_VM (1 << 1) | ||
| 274 | #define KVM_EMUL_INSN_F_CS_D (1 << 2) | ||
| 275 | #define KVM_EMUL_INSN_F_CS_L (1 << 3) | ||
| 276 | |||
| 277 | static int kvm_emulate_insn_handler(struct trace_seq *s, | ||
| 278 | struct pevent_record *record, | ||
| 279 | struct event_format *event, void *context) | ||
| 280 | { | ||
| 281 | unsigned long long rip, csbase, len, flags, failed; | ||
| 282 | int llen; | ||
| 283 | uint8_t *insn; | ||
| 284 | const char *disasm; | ||
| 285 | |||
| 286 | if (pevent_get_field_val(s, event, "rip", record, &rip, 1) < 0) | ||
| 287 | return -1; | ||
| 288 | |||
| 289 | if (pevent_get_field_val(s, event, "csbase", record, &csbase, 1) < 0) | ||
| 290 | return -1; | ||
| 291 | |||
| 292 | if (pevent_get_field_val(s, event, "len", record, &len, 1) < 0) | ||
| 293 | return -1; | ||
| 294 | |||
| 295 | if (pevent_get_field_val(s, event, "flags", record, &flags, 1) < 0) | ||
| 296 | return -1; | ||
| 297 | |||
| 298 | if (pevent_get_field_val(s, event, "failed", record, &failed, 1) < 0) | ||
| 299 | return -1; | ||
| 300 | |||
| 301 | insn = pevent_get_field_raw(s, event, "insn", record, &llen, 1); | ||
| 302 | if (!insn) | ||
| 303 | return -1; | ||
| 304 | |||
| 305 | disasm = disassemble(insn, len, rip, | ||
| 306 | flags & KVM_EMUL_INSN_F_CR0_PE, | ||
| 307 | flags & KVM_EMUL_INSN_F_EFL_VM, | ||
| 308 | flags & KVM_EMUL_INSN_F_CS_D, | ||
| 309 | flags & KVM_EMUL_INSN_F_CS_L); | ||
| 310 | |||
| 311 | trace_seq_printf(s, "%llx:%llx: %s%s", csbase, rip, disasm, | ||
| 312 | failed ? " FAIL" : ""); | ||
| 313 | return 0; | ||
| 314 | } | ||
| 315 | |||
| 316 | union kvm_mmu_page_role { | ||
| 317 | unsigned word; | ||
| 318 | struct { | ||
| 319 | unsigned glevels:4; | ||
| 320 | unsigned level:4; | ||
| 321 | unsigned quadrant:2; | ||
| 322 | unsigned pad_for_nice_hex_output:6; | ||
| 323 | unsigned direct:1; | ||
| 324 | unsigned access:3; | ||
| 325 | unsigned invalid:1; | ||
| 326 | unsigned cr4_pge:1; | ||
| 327 | unsigned nxe:1; | ||
| 328 | }; | ||
| 329 | }; | ||
| 330 | |||
| 331 | static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record, | ||
| 332 | struct event_format *event, void *context) | ||
| 333 | { | ||
| 334 | unsigned long long val; | ||
| 335 | static const char *access_str[] = { | ||
| 336 | "---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux" | ||
| 337 | }; | ||
| 338 | union kvm_mmu_page_role role; | ||
| 339 | |||
| 340 | if (pevent_get_field_val(s, event, "role", record, &val, 1) < 0) | ||
| 341 | return -1; | ||
| 342 | |||
| 343 | role.word = (int)val; | ||
| 344 | |||
| 345 | /* | ||
| 346 | * We can only use the structure if file is of the same | ||
| 347 | * endianess. | ||
| 348 | */ | ||
| 349 | if (pevent_is_file_bigendian(event->pevent) == | ||
| 350 | pevent_is_host_bigendian(event->pevent)) { | ||
| 351 | |||
| 352 | trace_seq_printf(s, "%u/%u q%u%s %s%s %spge %snxe", | ||
| 353 | role.level, | ||
| 354 | role.glevels, | ||
| 355 | role.quadrant, | ||
| 356 | role.direct ? " direct" : "", | ||
| 357 | access_str[role.access], | ||
| 358 | role.invalid ? " invalid" : "", | ||
| 359 | role.cr4_pge ? "" : "!", | ||
| 360 | role.nxe ? "" : "!"); | ||
| 361 | } else | ||
| 362 | trace_seq_printf(s, "WORD: %08x", role.word); | ||
| 363 | |||
| 364 | pevent_print_num_field(s, " root %u ", event, | ||
| 365 | "root_count", record, 1); | ||
| 366 | |||
| 367 | if (pevent_get_field_val(s, event, "unsync", record, &val, 1) < 0) | ||
| 368 | return -1; | ||
| 369 | |||
| 370 | trace_seq_printf(s, "%s%c", val ? "unsync" : "sync", 0); | ||
| 371 | return 0; | ||
| 372 | } | ||
| 373 | |||
| 374 | static int kvm_mmu_get_page_handler(struct trace_seq *s, | ||
| 375 | struct pevent_record *record, | ||
| 376 | struct event_format *event, void *context) | ||
| 377 | { | ||
| 378 | unsigned long long val; | ||
| 379 | |||
| 380 | if (pevent_get_field_val(s, event, "created", record, &val, 1) < 0) | ||
| 381 | return -1; | ||
| 382 | |||
| 383 | trace_seq_printf(s, "%s ", val ? "new" : "existing"); | ||
| 384 | |||
| 385 | if (pevent_get_field_val(s, event, "gfn", record, &val, 1) < 0) | ||
| 386 | return -1; | ||
| 387 | |||
| 388 | trace_seq_printf(s, "sp gfn %llx ", val); | ||
| 389 | return kvm_mmu_print_role(s, record, event, context); | ||
| 390 | } | ||
| 391 | |||
| 392 | #define PT_WRITABLE_SHIFT 1 | ||
| 393 | #define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT) | ||
| 394 | |||
| 395 | static unsigned long long | ||
| 396 | process_is_writable_pte(struct trace_seq *s, unsigned long long *args) | ||
| 397 | { | ||
| 398 | unsigned long pte = args[0]; | ||
| 399 | return pte & PT_WRITABLE_MASK; | ||
| 400 | } | ||
| 401 | |||
| 402 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 403 | { | ||
| 404 | init_disassembler(); | ||
| 405 | |||
| 406 | pevent_register_event_handler(pevent, -1, "kvm", "kvm_exit", | ||
| 407 | kvm_exit_handler, NULL); | ||
| 408 | |||
| 409 | pevent_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", | ||
| 410 | kvm_emulate_insn_handler, NULL); | ||
| 411 | |||
| 412 | pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", | ||
| 413 | kvm_mmu_get_page_handler, NULL); | ||
| 414 | |||
| 415 | pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page", | ||
| 416 | kvm_mmu_print_role, NULL); | ||
| 417 | |||
| 418 | pevent_register_event_handler(pevent, -1, | ||
| 419 | "kvmmmu", "kvm_mmu_unsync_page", | ||
| 420 | kvm_mmu_print_role, NULL); | ||
| 421 | |||
| 422 | pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page", | ||
| 423 | kvm_mmu_print_role, NULL); | ||
| 424 | |||
| 425 | pevent_register_event_handler(pevent, -1, "kvmmmu", | ||
| 426 | "kvm_mmu_prepare_zap_page", kvm_mmu_print_role, | ||
| 427 | NULL); | ||
| 428 | |||
| 429 | pevent_register_print_function(pevent, | ||
| 430 | process_is_writable_pte, | ||
| 431 | PEVENT_FUNC_ARG_INT, | ||
| 432 | "is_writable_pte", | ||
| 433 | PEVENT_FUNC_ARG_LONG, | ||
| 434 | PEVENT_FUNC_ARG_VOID); | ||
| 435 | return 0; | ||
| 436 | } | ||
diff --git a/tools/lib/traceevent/plugin_mac80211.c b/tools/lib/traceevent/plugin_mac80211.c new file mode 100644 index 000000000000..558a3b91c046 --- /dev/null +++ b/tools/lib/traceevent/plugin_mac80211.c | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009 Johannes Berg <johannes@sipsolutions.net> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; | ||
| 8 | * version 2.1 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
| 17 | * | ||
| 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 19 | */ | ||
| 20 | #include <stdio.h> | ||
| 21 | #include <stdlib.h> | ||
| 22 | #include <string.h> | ||
| 23 | |||
| 24 | #include "event-parse.h" | ||
| 25 | |||
| 26 | #define INDENT 65 | ||
| 27 | |||
| 28 | static void print_string(struct trace_seq *s, struct event_format *event, | ||
| 29 | const char *name, const void *data) | ||
| 30 | { | ||
| 31 | struct format_field *f = pevent_find_field(event, name); | ||
| 32 | int offset; | ||
| 33 | int length; | ||
| 34 | |||
| 35 | if (!f) { | ||
| 36 | trace_seq_printf(s, "NOTFOUND:%s", name); | ||
| 37 | return; | ||
| 38 | } | ||
| 39 | |||
| 40 | offset = f->offset; | ||
| 41 | length = f->size; | ||
| 42 | |||
| 43 | if (!strncmp(f->type, "__data_loc", 10)) { | ||
| 44 | unsigned long long v; | ||
| 45 | if (pevent_read_number_field(f, data, &v)) { | ||
| 46 | trace_seq_printf(s, "invalid_data_loc"); | ||
| 47 | return; | ||
| 48 | } | ||
| 49 | offset = v & 0xffff; | ||
| 50 | length = v >> 16; | ||
| 51 | } | ||
| 52 | |||
| 53 | trace_seq_printf(s, "%.*s", length, (char *)data + offset); | ||
| 54 | } | ||
| 55 | |||
| 56 | #define SF(fn) pevent_print_num_field(s, fn ":%d", event, fn, record, 0) | ||
| 57 | #define SFX(fn) pevent_print_num_field(s, fn ":%#x", event, fn, record, 0) | ||
| 58 | #define SP() trace_seq_putc(s, ' ') | ||
| 59 | |||
| 60 | static int drv_bss_info_changed(struct trace_seq *s, | ||
| 61 | struct pevent_record *record, | ||
| 62 | struct event_format *event, void *context) | ||
| 63 | { | ||
| 64 | void *data = record->data; | ||
| 65 | |||
| 66 | print_string(s, event, "wiphy_name", data); | ||
| 67 | trace_seq_printf(s, " vif:"); | ||
| 68 | print_string(s, event, "vif_name", data); | ||
| 69 | pevent_print_num_field(s, "(%d)", event, "vif_type", record, 1); | ||
| 70 | |||
| 71 | trace_seq_printf(s, "\n%*s", INDENT, ""); | ||
| 72 | SF("assoc"); SP(); | ||
| 73 | SF("aid"); SP(); | ||
| 74 | SF("cts"); SP(); | ||
| 75 | SF("shortpre"); SP(); | ||
| 76 | SF("shortslot"); SP(); | ||
| 77 | SF("dtimper"); SP(); | ||
| 78 | trace_seq_printf(s, "\n%*s", INDENT, ""); | ||
| 79 | SF("bcnint"); SP(); | ||
| 80 | SFX("assoc_cap"); SP(); | ||
| 81 | SFX("basic_rates"); SP(); | ||
| 82 | SF("enable_beacon"); | ||
| 83 | trace_seq_printf(s, "\n%*s", INDENT, ""); | ||
| 84 | SF("ht_operation_mode"); | ||
| 85 | |||
| 86 | return 0; | ||
| 87 | } | ||
| 88 | |||
| 89 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 90 | { | ||
| 91 | pevent_register_event_handler(pevent, -1, "mac80211", | ||
| 92 | "drv_bss_info_changed", | ||
| 93 | drv_bss_info_changed, NULL); | ||
| 94 | return 0; | ||
| 95 | } | ||
diff --git a/tools/lib/traceevent/plugin_sched_switch.c b/tools/lib/traceevent/plugin_sched_switch.c new file mode 100644 index 000000000000..fea3724aa24f --- /dev/null +++ b/tools/lib/traceevent/plugin_sched_switch.c | |||
| @@ -0,0 +1,148 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; | ||
| 8 | * version 2.1 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
| 17 | * | ||
| 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 19 | */ | ||
| 20 | #include <stdio.h> | ||
| 21 | #include <stdlib.h> | ||
| 22 | #include <string.h> | ||
| 23 | |||
| 24 | #include "event-parse.h" | ||
| 25 | |||
| 26 | static void write_state(struct trace_seq *s, int val) | ||
| 27 | { | ||
| 28 | const char states[] = "SDTtZXxW"; | ||
| 29 | int found = 0; | ||
| 30 | int i; | ||
| 31 | |||
| 32 | for (i = 0; i < (sizeof(states) - 1); i++) { | ||
| 33 | if (!(val & (1 << i))) | ||
| 34 | continue; | ||
| 35 | |||
| 36 | if (found) | ||
| 37 | trace_seq_putc(s, '|'); | ||
| 38 | |||
| 39 | found = 1; | ||
| 40 | trace_seq_putc(s, states[i]); | ||
| 41 | } | ||
| 42 | |||
| 43 | if (!found) | ||
| 44 | trace_seq_putc(s, 'R'); | ||
| 45 | } | ||
| 46 | |||
| 47 | static void write_and_save_comm(struct format_field *field, | ||
| 48 | struct pevent_record *record, | ||
| 49 | struct trace_seq *s, int pid) | ||
| 50 | { | ||
| 51 | const char *comm; | ||
| 52 | int len; | ||
| 53 | |||
| 54 | comm = (char *)(record->data + field->offset); | ||
| 55 | len = s->len; | ||
| 56 | trace_seq_printf(s, "%.*s", | ||
| 57 | field->size, comm); | ||
| 58 | |||
| 59 | /* make sure the comm has a \0 at the end. */ | ||
| 60 | trace_seq_terminate(s); | ||
| 61 | comm = &s->buffer[len]; | ||
| 62 | |||
| 63 | /* Help out the comm to ids. This will handle dups */ | ||
| 64 | pevent_register_comm(field->event->pevent, comm, pid); | ||
| 65 | } | ||
| 66 | |||
| 67 | static int sched_wakeup_handler(struct trace_seq *s, | ||
| 68 | struct pevent_record *record, | ||
| 69 | struct event_format *event, void *context) | ||
| 70 | { | ||
| 71 | struct format_field *field; | ||
| 72 | unsigned long long val; | ||
| 73 | |||
| 74 | if (pevent_get_field_val(s, event, "pid", record, &val, 1)) | ||
| 75 | return trace_seq_putc(s, '!'); | ||
| 76 | |||
| 77 | field = pevent_find_any_field(event, "comm"); | ||
| 78 | if (field) { | ||
| 79 | write_and_save_comm(field, record, s, val); | ||
| 80 | trace_seq_putc(s, ':'); | ||
| 81 | } | ||
| 82 | trace_seq_printf(s, "%lld", val); | ||
| 83 | |||
| 84 | if (pevent_get_field_val(s, event, "prio", record, &val, 0) == 0) | ||
| 85 | trace_seq_printf(s, " [%lld]", val); | ||
| 86 | |||
| 87 | if (pevent_get_field_val(s, event, "success", record, &val, 1) == 0) | ||
| 88 | trace_seq_printf(s, " success=%lld", val); | ||
| 89 | |||
| 90 | if (pevent_get_field_val(s, event, "target_cpu", record, &val, 0) == 0) | ||
| 91 | trace_seq_printf(s, " CPU:%03llu", val); | ||
| 92 | |||
| 93 | return 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | static int sched_switch_handler(struct trace_seq *s, | ||
| 97 | struct pevent_record *record, | ||
| 98 | struct event_format *event, void *context) | ||
| 99 | { | ||
| 100 | struct format_field *field; | ||
| 101 | unsigned long long val; | ||
| 102 | |||
| 103 | if (pevent_get_field_val(s, event, "prev_pid", record, &val, 1)) | ||
| 104 | return trace_seq_putc(s, '!'); | ||
| 105 | |||
| 106 | field = pevent_find_any_field(event, "prev_comm"); | ||
| 107 | if (field) { | ||
| 108 | write_and_save_comm(field, record, s, val); | ||
| 109 | trace_seq_putc(s, ':'); | ||
| 110 | } | ||
| 111 | trace_seq_printf(s, "%lld ", val); | ||
| 112 | |||
| 113 | if (pevent_get_field_val(s, event, "prev_prio", record, &val, 0) == 0) | ||
| 114 | trace_seq_printf(s, "[%lld] ", val); | ||
| 115 | |||
| 116 | if (pevent_get_field_val(s, event, "prev_state", record, &val, 0) == 0) | ||
| 117 | write_state(s, val); | ||
| 118 | |||
| 119 | trace_seq_puts(s, " ==> "); | ||
| 120 | |||
| 121 | if (pevent_get_field_val(s, event, "next_pid", record, &val, 1)) | ||
| 122 | return trace_seq_putc(s, '!'); | ||
| 123 | |||
| 124 | field = pevent_find_any_field(event, "next_comm"); | ||
| 125 | if (field) { | ||
| 126 | write_and_save_comm(field, record, s, val); | ||
| 127 | trace_seq_putc(s, ':'); | ||
| 128 | } | ||
| 129 | trace_seq_printf(s, "%lld", val); | ||
| 130 | |||
| 131 | if (pevent_get_field_val(s, event, "next_prio", record, &val, 0) == 0) | ||
| 132 | trace_seq_printf(s, " [%lld]", val); | ||
| 133 | |||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 138 | { | ||
| 139 | pevent_register_event_handler(pevent, -1, "sched", "sched_switch", | ||
| 140 | sched_switch_handler, NULL); | ||
| 141 | |||
| 142 | pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup", | ||
| 143 | sched_wakeup_handler, NULL); | ||
| 144 | |||
| 145 | pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup_new", | ||
| 146 | sched_wakeup_handler, NULL); | ||
| 147 | return 0; | ||
| 148 | } | ||
diff --git a/tools/lib/traceevent/plugin_scsi.c b/tools/lib/traceevent/plugin_scsi.c new file mode 100644 index 000000000000..6fb8e3e3fcad --- /dev/null +++ b/tools/lib/traceevent/plugin_scsi.c | |||
| @@ -0,0 +1,423 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <string.h> | ||
| 3 | #include <inttypes.h> | ||
| 4 | #include "event-parse.h" | ||
| 5 | |||
| 6 | typedef unsigned long sector_t; | ||
| 7 | typedef uint64_t u64; | ||
| 8 | typedef unsigned int u32; | ||
| 9 | |||
| 10 | /* | ||
| 11 | * SCSI opcodes | ||
| 12 | */ | ||
| 13 | #define TEST_UNIT_READY 0x00 | ||
| 14 | #define REZERO_UNIT 0x01 | ||
| 15 | #define REQUEST_SENSE 0x03 | ||
| 16 | #define FORMAT_UNIT 0x04 | ||
| 17 | #define READ_BLOCK_LIMITS 0x05 | ||
| 18 | #define REASSIGN_BLOCKS 0x07 | ||
| 19 | #define INITIALIZE_ELEMENT_STATUS 0x07 | ||
| 20 | #define READ_6 0x08 | ||
| 21 | #define WRITE_6 0x0a | ||
| 22 | #define SEEK_6 0x0b | ||
| 23 | #define READ_REVERSE 0x0f | ||
| 24 | #define WRITE_FILEMARKS 0x10 | ||
| 25 | #define SPACE 0x11 | ||
| 26 | #define INQUIRY 0x12 | ||
| 27 | #define RECOVER_BUFFERED_DATA 0x14 | ||
| 28 | #define MODE_SELECT 0x15 | ||
| 29 | #define RESERVE 0x16 | ||
| 30 | #define RELEASE 0x17 | ||
| 31 | #define COPY 0x18 | ||
| 32 | #define ERASE 0x19 | ||
| 33 | #define MODE_SENSE 0x1a | ||
| 34 | #define START_STOP 0x1b | ||
| 35 | #define RECEIVE_DIAGNOSTIC 0x1c | ||
| 36 | #define SEND_DIAGNOSTIC 0x1d | ||
| 37 | #define ALLOW_MEDIUM_REMOVAL 0x1e | ||
| 38 | |||
| 39 | #define READ_FORMAT_CAPACITIES 0x23 | ||
| 40 | #define SET_WINDOW 0x24 | ||
| 41 | #define READ_CAPACITY 0x25 | ||
| 42 | #define READ_10 0x28 | ||
| 43 | #define WRITE_10 0x2a | ||
| 44 | #define SEEK_10 0x2b | ||
| 45 | #define POSITION_TO_ELEMENT 0x2b | ||
| 46 | #define WRITE_VERIFY 0x2e | ||
| 47 | #define VERIFY 0x2f | ||
| 48 | #define SEARCH_HIGH 0x30 | ||
| 49 | #define SEARCH_EQUAL 0x31 | ||
| 50 | #define SEARCH_LOW 0x32 | ||
| 51 | #define SET_LIMITS 0x33 | ||
| 52 | #define PRE_FETCH 0x34 | ||
| 53 | #define READ_POSITION 0x34 | ||
| 54 | #define SYNCHRONIZE_CACHE 0x35 | ||
| 55 | #define LOCK_UNLOCK_CACHE 0x36 | ||
| 56 | #define READ_DEFECT_DATA 0x37 | ||
| 57 | #define MEDIUM_SCAN 0x38 | ||
| 58 | #define COMPARE 0x39 | ||
| 59 | #define COPY_VERIFY 0x3a | ||
| 60 | #define WRITE_BUFFER 0x3b | ||
| 61 | #define READ_BUFFER 0x3c | ||
| 62 | #define UPDATE_BLOCK 0x3d | ||
| 63 | #define READ_LONG 0x3e | ||
| 64 | #define WRITE_LONG 0x3f | ||
| 65 | #define CHANGE_DEFINITION 0x40 | ||
| 66 | #define WRITE_SAME 0x41 | ||
| 67 | #define UNMAP 0x42 | ||
| 68 | #define READ_TOC 0x43 | ||
| 69 | #define READ_HEADER 0x44 | ||
| 70 | #define GET_EVENT_STATUS_NOTIFICATION 0x4a | ||
| 71 | #define LOG_SELECT 0x4c | ||
| 72 | #define LOG_SENSE 0x4d | ||
| 73 | #define XDWRITEREAD_10 0x53 | ||
| 74 | #define MODE_SELECT_10 0x55 | ||
| 75 | #define RESERVE_10 0x56 | ||
| 76 | #define RELEASE_10 0x57 | ||
| 77 | #define MODE_SENSE_10 0x5a | ||
| 78 | #define PERSISTENT_RESERVE_IN 0x5e | ||
| 79 | #define PERSISTENT_RESERVE_OUT 0x5f | ||
| 80 | #define VARIABLE_LENGTH_CMD 0x7f | ||
| 81 | #define REPORT_LUNS 0xa0 | ||
| 82 | #define SECURITY_PROTOCOL_IN 0xa2 | ||
| 83 | #define MAINTENANCE_IN 0xa3 | ||
| 84 | #define MAINTENANCE_OUT 0xa4 | ||
| 85 | #define MOVE_MEDIUM 0xa5 | ||
| 86 | #define EXCHANGE_MEDIUM 0xa6 | ||
| 87 | #define READ_12 0xa8 | ||
| 88 | #define WRITE_12 0xaa | ||
| 89 | #define READ_MEDIA_SERIAL_NUMBER 0xab | ||
| 90 | #define WRITE_VERIFY_12 0xae | ||
| 91 | #define VERIFY_12 0xaf | ||
| 92 | #define SEARCH_HIGH_12 0xb0 | ||
| 93 | #define SEARCH_EQUAL_12 0xb1 | ||
| 94 | #define SEARCH_LOW_12 0xb2 | ||
| 95 | #define SECURITY_PROTOCOL_OUT 0xb5 | ||
| 96 | #define READ_ELEMENT_STATUS 0xb8 | ||
| 97 | #define SEND_VOLUME_TAG 0xb6 | ||
| 98 | #define WRITE_LONG_2 0xea | ||
| 99 | #define EXTENDED_COPY 0x83 | ||
| 100 | #define RECEIVE_COPY_RESULTS 0x84 | ||
| 101 | #define ACCESS_CONTROL_IN 0x86 | ||
| 102 | #define ACCESS_CONTROL_OUT 0x87 | ||
| 103 | #define READ_16 0x88 | ||
| 104 | #define WRITE_16 0x8a | ||
| 105 | #define READ_ATTRIBUTE 0x8c | ||
| 106 | #define WRITE_ATTRIBUTE 0x8d | ||
| 107 | #define VERIFY_16 0x8f | ||
| 108 | #define SYNCHRONIZE_CACHE_16 0x91 | ||
| 109 | #define WRITE_SAME_16 0x93 | ||
| 110 | #define SERVICE_ACTION_IN 0x9e | ||
| 111 | /* values for service action in */ | ||
| 112 | #define SAI_READ_CAPACITY_16 0x10 | ||
| 113 | #define SAI_GET_LBA_STATUS 0x12 | ||
| 114 | /* values for VARIABLE_LENGTH_CMD service action codes | ||
| 115 | * see spc4r17 Section D.3.5, table D.7 and D.8 */ | ||
| 116 | #define VLC_SA_RECEIVE_CREDENTIAL 0x1800 | ||
| 117 | /* values for maintenance in */ | ||
| 118 | #define MI_REPORT_IDENTIFYING_INFORMATION 0x05 | ||
| 119 | #define MI_REPORT_TARGET_PGS 0x0a | ||
| 120 | #define MI_REPORT_ALIASES 0x0b | ||
| 121 | #define MI_REPORT_SUPPORTED_OPERATION_CODES 0x0c | ||
| 122 | #define MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS 0x0d | ||
| 123 | #define MI_REPORT_PRIORITY 0x0e | ||
| 124 | #define MI_REPORT_TIMESTAMP 0x0f | ||
| 125 | #define MI_MANAGEMENT_PROTOCOL_IN 0x10 | ||
| 126 | /* value for MI_REPORT_TARGET_PGS ext header */ | ||
| 127 | #define MI_EXT_HDR_PARAM_FMT 0x20 | ||
| 128 | /* values for maintenance out */ | ||
| 129 | #define MO_SET_IDENTIFYING_INFORMATION 0x06 | ||
| 130 | #define MO_SET_TARGET_PGS 0x0a | ||
| 131 | #define MO_CHANGE_ALIASES 0x0b | ||
| 132 | #define MO_SET_PRIORITY 0x0e | ||
| 133 | #define MO_SET_TIMESTAMP 0x0f | ||
| 134 | #define MO_MANAGEMENT_PROTOCOL_OUT 0x10 | ||
| 135 | /* values for variable length command */ | ||
| 136 | #define XDREAD_32 0x03 | ||
| 137 | #define XDWRITE_32 0x04 | ||
| 138 | #define XPWRITE_32 0x06 | ||
| 139 | #define XDWRITEREAD_32 0x07 | ||
| 140 | #define READ_32 0x09 | ||
| 141 | #define VERIFY_32 0x0a | ||
| 142 | #define WRITE_32 0x0b | ||
| 143 | #define WRITE_SAME_32 0x0d | ||
| 144 | |||
| 145 | #define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f) | ||
| 146 | #define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9]) | ||
| 147 | |||
| 148 | static const char * | ||
| 149 | scsi_trace_misc(struct trace_seq *, unsigned char *, int); | ||
| 150 | |||
| 151 | static const char * | ||
| 152 | scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 153 | { | ||
| 154 | const char *ret = p->buffer + p->len; | ||
| 155 | sector_t lba = 0, txlen = 0; | ||
| 156 | |||
| 157 | lba |= ((cdb[1] & 0x1F) << 16); | ||
| 158 | lba |= (cdb[2] << 8); | ||
| 159 | lba |= cdb[3]; | ||
| 160 | txlen = cdb[4]; | ||
| 161 | |||
| 162 | trace_seq_printf(p, "lba=%llu txlen=%llu", | ||
| 163 | (unsigned long long)lba, (unsigned long long)txlen); | ||
| 164 | trace_seq_putc(p, 0); | ||
| 165 | return ret; | ||
| 166 | } | ||
| 167 | |||
| 168 | static const char * | ||
| 169 | scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 170 | { | ||
| 171 | const char *ret = p->buffer + p->len; | ||
| 172 | sector_t lba = 0, txlen = 0; | ||
| 173 | |||
| 174 | lba |= (cdb[2] << 24); | ||
| 175 | lba |= (cdb[3] << 16); | ||
| 176 | lba |= (cdb[4] << 8); | ||
| 177 | lba |= cdb[5]; | ||
| 178 | txlen |= (cdb[7] << 8); | ||
| 179 | txlen |= cdb[8]; | ||
| 180 | |||
| 181 | trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", | ||
| 182 | (unsigned long long)lba, (unsigned long long)txlen, | ||
| 183 | cdb[1] >> 5); | ||
| 184 | |||
| 185 | if (cdb[0] == WRITE_SAME) | ||
| 186 | trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1); | ||
| 187 | |||
| 188 | trace_seq_putc(p, 0); | ||
| 189 | return ret; | ||
| 190 | } | ||
| 191 | |||
| 192 | static const char * | ||
| 193 | scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 194 | { | ||
| 195 | const char *ret = p->buffer + p->len; | ||
| 196 | sector_t lba = 0, txlen = 0; | ||
| 197 | |||
| 198 | lba |= (cdb[2] << 24); | ||
| 199 | lba |= (cdb[3] << 16); | ||
| 200 | lba |= (cdb[4] << 8); | ||
| 201 | lba |= cdb[5]; | ||
| 202 | txlen |= (cdb[6] << 24); | ||
| 203 | txlen |= (cdb[7] << 16); | ||
| 204 | txlen |= (cdb[8] << 8); | ||
| 205 | txlen |= cdb[9]; | ||
| 206 | |||
| 207 | trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", | ||
| 208 | (unsigned long long)lba, (unsigned long long)txlen, | ||
| 209 | cdb[1] >> 5); | ||
| 210 | trace_seq_putc(p, 0); | ||
| 211 | return ret; | ||
| 212 | } | ||
| 213 | |||
| 214 | static const char * | ||
| 215 | scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 216 | { | ||
| 217 | const char *ret = p->buffer + p->len; | ||
| 218 | sector_t lba = 0, txlen = 0; | ||
| 219 | |||
| 220 | lba |= ((u64)cdb[2] << 56); | ||
| 221 | lba |= ((u64)cdb[3] << 48); | ||
| 222 | lba |= ((u64)cdb[4] << 40); | ||
| 223 | lba |= ((u64)cdb[5] << 32); | ||
| 224 | lba |= (cdb[6] << 24); | ||
| 225 | lba |= (cdb[7] << 16); | ||
| 226 | lba |= (cdb[8] << 8); | ||
| 227 | lba |= cdb[9]; | ||
| 228 | txlen |= (cdb[10] << 24); | ||
| 229 | txlen |= (cdb[11] << 16); | ||
| 230 | txlen |= (cdb[12] << 8); | ||
| 231 | txlen |= cdb[13]; | ||
| 232 | |||
| 233 | trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", | ||
| 234 | (unsigned long long)lba, (unsigned long long)txlen, | ||
| 235 | cdb[1] >> 5); | ||
| 236 | |||
| 237 | if (cdb[0] == WRITE_SAME_16) | ||
| 238 | trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1); | ||
| 239 | |||
| 240 | trace_seq_putc(p, 0); | ||
| 241 | return ret; | ||
| 242 | } | ||
| 243 | |||
| 244 | static const char * | ||
| 245 | scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 246 | { | ||
| 247 | const char *ret = p->buffer + p->len, *cmd; | ||
| 248 | sector_t lba = 0, txlen = 0; | ||
| 249 | u32 ei_lbrt = 0; | ||
| 250 | |||
| 251 | switch (SERVICE_ACTION32(cdb)) { | ||
| 252 | case READ_32: | ||
| 253 | cmd = "READ"; | ||
| 254 | break; | ||
| 255 | case VERIFY_32: | ||
| 256 | cmd = "VERIFY"; | ||
| 257 | break; | ||
| 258 | case WRITE_32: | ||
| 259 | cmd = "WRITE"; | ||
| 260 | break; | ||
| 261 | case WRITE_SAME_32: | ||
| 262 | cmd = "WRITE_SAME"; | ||
| 263 | break; | ||
| 264 | default: | ||
| 265 | trace_seq_printf(p, "UNKNOWN"); | ||
| 266 | goto out; | ||
| 267 | } | ||
| 268 | |||
| 269 | lba |= ((u64)cdb[12] << 56); | ||
| 270 | lba |= ((u64)cdb[13] << 48); | ||
| 271 | lba |= ((u64)cdb[14] << 40); | ||
| 272 | lba |= ((u64)cdb[15] << 32); | ||
| 273 | lba |= (cdb[16] << 24); | ||
| 274 | lba |= (cdb[17] << 16); | ||
| 275 | lba |= (cdb[18] << 8); | ||
| 276 | lba |= cdb[19]; | ||
| 277 | ei_lbrt |= (cdb[20] << 24); | ||
| 278 | ei_lbrt |= (cdb[21] << 16); | ||
| 279 | ei_lbrt |= (cdb[22] << 8); | ||
| 280 | ei_lbrt |= cdb[23]; | ||
| 281 | txlen |= (cdb[28] << 24); | ||
| 282 | txlen |= (cdb[29] << 16); | ||
| 283 | txlen |= (cdb[30] << 8); | ||
| 284 | txlen |= cdb[31]; | ||
| 285 | |||
| 286 | trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u", | ||
| 287 | cmd, (unsigned long long)lba, | ||
| 288 | (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt); | ||
| 289 | |||
| 290 | if (SERVICE_ACTION32(cdb) == WRITE_SAME_32) | ||
| 291 | trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1); | ||
| 292 | |||
| 293 | out: | ||
| 294 | trace_seq_putc(p, 0); | ||
| 295 | return ret; | ||
| 296 | } | ||
| 297 | |||
| 298 | static const char * | ||
| 299 | scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 300 | { | ||
| 301 | const char *ret = p->buffer + p->len; | ||
| 302 | unsigned int regions = cdb[7] << 8 | cdb[8]; | ||
| 303 | |||
| 304 | trace_seq_printf(p, "regions=%u", (regions - 8) / 16); | ||
| 305 | trace_seq_putc(p, 0); | ||
| 306 | return ret; | ||
| 307 | } | ||
| 308 | |||
| 309 | static const char * | ||
| 310 | scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 311 | { | ||
| 312 | const char *ret = p->buffer + p->len, *cmd; | ||
| 313 | sector_t lba = 0; | ||
| 314 | u32 alloc_len = 0; | ||
| 315 | |||
| 316 | switch (SERVICE_ACTION16(cdb)) { | ||
| 317 | case SAI_READ_CAPACITY_16: | ||
| 318 | cmd = "READ_CAPACITY_16"; | ||
| 319 | break; | ||
| 320 | case SAI_GET_LBA_STATUS: | ||
| 321 | cmd = "GET_LBA_STATUS"; | ||
| 322 | break; | ||
| 323 | default: | ||
| 324 | trace_seq_printf(p, "UNKNOWN"); | ||
| 325 | goto out; | ||
| 326 | } | ||
| 327 | |||
| 328 | lba |= ((u64)cdb[2] << 56); | ||
| 329 | lba |= ((u64)cdb[3] << 48); | ||
| 330 | lba |= ((u64)cdb[4] << 40); | ||
| 331 | lba |= ((u64)cdb[5] << 32); | ||
| 332 | lba |= (cdb[6] << 24); | ||
| 333 | lba |= (cdb[7] << 16); | ||
| 334 | lba |= (cdb[8] << 8); | ||
| 335 | lba |= cdb[9]; | ||
| 336 | alloc_len |= (cdb[10] << 24); | ||
| 337 | alloc_len |= (cdb[11] << 16); | ||
| 338 | alloc_len |= (cdb[12] << 8); | ||
| 339 | alloc_len |= cdb[13]; | ||
| 340 | |||
| 341 | trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, | ||
| 342 | (unsigned long long)lba, alloc_len); | ||
| 343 | |||
| 344 | out: | ||
| 345 | trace_seq_putc(p, 0); | ||
| 346 | return ret; | ||
| 347 | } | ||
| 348 | |||
| 349 | static const char * | ||
| 350 | scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 351 | { | ||
| 352 | switch (SERVICE_ACTION32(cdb)) { | ||
| 353 | case READ_32: | ||
| 354 | case VERIFY_32: | ||
| 355 | case WRITE_32: | ||
| 356 | case WRITE_SAME_32: | ||
| 357 | return scsi_trace_rw32(p, cdb, len); | ||
| 358 | default: | ||
| 359 | return scsi_trace_misc(p, cdb, len); | ||
| 360 | } | ||
| 361 | } | ||
| 362 | |||
| 363 | static const char * | ||
| 364 | scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 365 | { | ||
| 366 | const char *ret = p->buffer + p->len; | ||
| 367 | |||
| 368 | trace_seq_printf(p, "-"); | ||
| 369 | trace_seq_putc(p, 0); | ||
| 370 | return ret; | ||
| 371 | } | ||
| 372 | |||
| 373 | const char * | ||
| 374 | scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len) | ||
| 375 | { | ||
| 376 | switch (cdb[0]) { | ||
| 377 | case READ_6: | ||
| 378 | case WRITE_6: | ||
| 379 | return scsi_trace_rw6(p, cdb, len); | ||
| 380 | case READ_10: | ||
| 381 | case VERIFY: | ||
| 382 | case WRITE_10: | ||
| 383 | case WRITE_SAME: | ||
| 384 | return scsi_trace_rw10(p, cdb, len); | ||
| 385 | case READ_12: | ||
| 386 | case VERIFY_12: | ||
| 387 | case WRITE_12: | ||
| 388 | return scsi_trace_rw12(p, cdb, len); | ||
| 389 | case READ_16: | ||
| 390 | case VERIFY_16: | ||
| 391 | case WRITE_16: | ||
| 392 | case WRITE_SAME_16: | ||
| 393 | return scsi_trace_rw16(p, cdb, len); | ||
| 394 | case UNMAP: | ||
| 395 | return scsi_trace_unmap(p, cdb, len); | ||
| 396 | case SERVICE_ACTION_IN: | ||
| 397 | return scsi_trace_service_action_in(p, cdb, len); | ||
| 398 | case VARIABLE_LENGTH_CMD: | ||
| 399 | return scsi_trace_varlen(p, cdb, len); | ||
| 400 | default: | ||
| 401 | return scsi_trace_misc(p, cdb, len); | ||
| 402 | } | ||
| 403 | } | ||
| 404 | |||
| 405 | unsigned long long process_scsi_trace_parse_cdb(struct trace_seq *s, | ||
| 406 | unsigned long long *args) | ||
| 407 | { | ||
| 408 | scsi_trace_parse_cdb(s, (unsigned char *) args[1], args[2]); | ||
| 409 | return 0; | ||
| 410 | } | ||
| 411 | |||
| 412 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 413 | { | ||
| 414 | pevent_register_print_function(pevent, | ||
| 415 | process_scsi_trace_parse_cdb, | ||
| 416 | PEVENT_FUNC_ARG_STRING, | ||
| 417 | "scsi_trace_parse_cdb", | ||
| 418 | PEVENT_FUNC_ARG_PTR, | ||
| 419 | PEVENT_FUNC_ARG_PTR, | ||
| 420 | PEVENT_FUNC_ARG_INT, | ||
| 421 | PEVENT_FUNC_ARG_VOID); | ||
| 422 | return 0; | ||
| 423 | } | ||
diff --git a/tools/lib/traceevent/plugin_xen.c b/tools/lib/traceevent/plugin_xen.c new file mode 100644 index 000000000000..e7794298f3a9 --- /dev/null +++ b/tools/lib/traceevent/plugin_xen.c | |||
| @@ -0,0 +1,130 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <stdlib.h> | ||
| 3 | #include <string.h> | ||
| 4 | #include "event-parse.h" | ||
| 5 | |||
| 6 | #define __HYPERVISOR_set_trap_table 0 | ||
| 7 | #define __HYPERVISOR_mmu_update 1 | ||
| 8 | #define __HYPERVISOR_set_gdt 2 | ||
| 9 | #define __HYPERVISOR_stack_switch 3 | ||
| 10 | #define __HYPERVISOR_set_callbacks 4 | ||
| 11 | #define __HYPERVISOR_fpu_taskswitch 5 | ||
| 12 | #define __HYPERVISOR_sched_op_compat 6 | ||
| 13 | #define __HYPERVISOR_dom0_op 7 | ||
| 14 | #define __HYPERVISOR_set_debugreg 8 | ||
| 15 | #define __HYPERVISOR_get_debugreg 9 | ||
| 16 | #define __HYPERVISOR_update_descriptor 10 | ||
| 17 | #define __HYPERVISOR_memory_op 12 | ||
| 18 | #define __HYPERVISOR_multicall 13 | ||
| 19 | #define __HYPERVISOR_update_va_mapping 14 | ||
| 20 | #define __HYPERVISOR_set_timer_op 15 | ||
| 21 | #define __HYPERVISOR_event_channel_op_compat 16 | ||
| 22 | #define __HYPERVISOR_xen_version 17 | ||
| 23 | #define __HYPERVISOR_console_io 18 | ||
| 24 | #define __HYPERVISOR_physdev_op_compat 19 | ||
| 25 | #define __HYPERVISOR_grant_table_op 20 | ||
| 26 | #define __HYPERVISOR_vm_assist 21 | ||
| 27 | #define __HYPERVISOR_update_va_mapping_otherdomain 22 | ||
| 28 | #define __HYPERVISOR_iret 23 /* x86 only */ | ||
| 29 | #define __HYPERVISOR_vcpu_op 24 | ||
| 30 | #define __HYPERVISOR_set_segment_base 25 /* x86/64 only */ | ||
| 31 | #define __HYPERVISOR_mmuext_op 26 | ||
| 32 | #define __HYPERVISOR_acm_op 27 | ||
| 33 | #define __HYPERVISOR_nmi_op 28 | ||
| 34 | #define __HYPERVISOR_sched_op 29 | ||
| 35 | #define __HYPERVISOR_callback_op 30 | ||
| 36 | #define __HYPERVISOR_xenoprof_op 31 | ||
| 37 | #define __HYPERVISOR_event_channel_op 32 | ||
| 38 | #define __HYPERVISOR_physdev_op 33 | ||
| 39 | #define __HYPERVISOR_hvm_op 34 | ||
| 40 | #define __HYPERVISOR_tmem_op 38 | ||
| 41 | |||
| 42 | /* Architecture-specific hypercall definitions. */ | ||
| 43 | #define __HYPERVISOR_arch_0 48 | ||
| 44 | #define __HYPERVISOR_arch_1 49 | ||
| 45 | #define __HYPERVISOR_arch_2 50 | ||
| 46 | #define __HYPERVISOR_arch_3 51 | ||
| 47 | #define __HYPERVISOR_arch_4 52 | ||
| 48 | #define __HYPERVISOR_arch_5 53 | ||
| 49 | #define __HYPERVISOR_arch_6 54 | ||
| 50 | #define __HYPERVISOR_arch_7 55 | ||
| 51 | |||
| 52 | #define N(x) [__HYPERVISOR_##x] = "("#x")" | ||
| 53 | static const char *xen_hypercall_names[] = { | ||
| 54 | N(set_trap_table), | ||
| 55 | N(mmu_update), | ||
| 56 | N(set_gdt), | ||
| 57 | N(stack_switch), | ||
| 58 | N(set_callbacks), | ||
| 59 | N(fpu_taskswitch), | ||
| 60 | N(sched_op_compat), | ||
| 61 | N(dom0_op), | ||
| 62 | N(set_debugreg), | ||
| 63 | N(get_debugreg), | ||
| 64 | N(update_descriptor), | ||
| 65 | N(memory_op), | ||
| 66 | N(multicall), | ||
| 67 | N(update_va_mapping), | ||
| 68 | N(set_timer_op), | ||
| 69 | N(event_channel_op_compat), | ||
| 70 | N(xen_version), | ||
| 71 | N(console_io), | ||
| 72 | N(physdev_op_compat), | ||
| 73 | N(grant_table_op), | ||
| 74 | N(vm_assist), | ||
| 75 | N(update_va_mapping_otherdomain), | ||
| 76 | N(iret), | ||
| 77 | N(vcpu_op), | ||
| 78 | N(set_segment_base), | ||
| 79 | N(mmuext_op), | ||
| 80 | N(acm_op), | ||
| 81 | N(nmi_op), | ||
| 82 | N(sched_op), | ||
| 83 | N(callback_op), | ||
| 84 | N(xenoprof_op), | ||
| 85 | N(event_channel_op), | ||
| 86 | N(physdev_op), | ||
| 87 | N(hvm_op), | ||
| 88 | |||
| 89 | /* Architecture-specific hypercall definitions. */ | ||
| 90 | N(arch_0), | ||
| 91 | N(arch_1), | ||
| 92 | N(arch_2), | ||
| 93 | N(arch_3), | ||
| 94 | N(arch_4), | ||
| 95 | N(arch_5), | ||
| 96 | N(arch_6), | ||
| 97 | N(arch_7), | ||
| 98 | }; | ||
| 99 | #undef N | ||
| 100 | |||
| 101 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | ||
| 102 | |||
| 103 | static const char *xen_hypercall_name(unsigned op) | ||
| 104 | { | ||
| 105 | if (op < ARRAY_SIZE(xen_hypercall_names) && | ||
| 106 | xen_hypercall_names[op] != NULL) | ||
| 107 | return xen_hypercall_names[op]; | ||
| 108 | |||
| 109 | return ""; | ||
| 110 | } | ||
| 111 | |||
| 112 | unsigned long long process_xen_hypercall_name(struct trace_seq *s, | ||
| 113 | unsigned long long *args) | ||
| 114 | { | ||
| 115 | unsigned int op = args[0]; | ||
| 116 | |||
| 117 | trace_seq_printf(s, "%s", xen_hypercall_name(op)); | ||
| 118 | return 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
| 122 | { | ||
| 123 | pevent_register_print_function(pevent, | ||
| 124 | process_xen_hypercall_name, | ||
| 125 | PEVENT_FUNC_ARG_STRING, | ||
| 126 | "xen_hypercall_name", | ||
| 127 | PEVENT_FUNC_ARG_INT, | ||
| 128 | PEVENT_FUNC_ARG_VOID); | ||
| 129 | return 0; | ||
| 130 | } | ||
