aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2012-06-04 00:35:19 -0400
committerLen Brown <len.brown@intel.com>2012-06-04 00:35:19 -0400
commit7e1bd6e38b1f30860ce25a014c6d6adfb0079f4a (patch)
tree65c5898ba93007d4399150c7a127a670bcfbc30d /tools
parent301f33fbcf4ced53b3de114846ecece5d6aafeeb (diff)
parentf8f5701bdaf9134b1f90e5044a82c66324d2073f (diff)
Merge branch 'upstream' into bugfix-video
Update bugfix-video branch to 2.5-rc1 so I don't have to again resolve the conflict in these patches vs. upstream. Conflicts: drivers/gpu/drm/gma500/psb_drv.c text conflict: add comment vs delete neighboring line keep just this: /* igd_opregion_init(&dev_priv->opregion_dev); */ /* acpi_video_register(); */ Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile77
-rw-r--r--tools/lib/traceevent/Makefile303
-rw-r--r--tools/lib/traceevent/event-parse.c5079
-rw-r--r--tools/lib/traceevent/event-parse.h804
-rw-r--r--tools/lib/traceevent/event-utils.h80
-rw-r--r--tools/lib/traceevent/parse-filter.c2261
-rw-r--r--tools/lib/traceevent/parse-utils.c110
-rw-r--r--tools/lib/traceevent/trace-seq.c200
-rw-r--r--tools/perf/Documentation/perf-evlist.txt8
-rw-r--r--tools/perf/Documentation/perf-probe.txt19
-rw-r--r--tools/perf/Documentation/perf-record.txt2
-rw-r--r--tools/perf/Documentation/perfconfig.example9
-rw-r--r--tools/perf/Makefile134
-rw-r--r--tools/perf/builtin-annotate.c2
-rw-r--r--tools/perf/builtin-buildid-list.c6
-rw-r--r--tools/perf/builtin-evlist.c103
-rw-r--r--tools/perf/builtin-inject.c5
-rw-r--r--tools/perf/builtin-kmem.c6
-rw-r--r--tools/perf/builtin-lock.c26
-rw-r--r--tools/perf/builtin-probe.c86
-rw-r--r--tools/perf/builtin-record.c81
-rw-r--r--tools/perf/builtin-report.c35
-rw-r--r--tools/perf/builtin-sched.c42
-rw-r--r--tools/perf/builtin-script.c2
-rw-r--r--tools/perf/builtin-stat.c86
-rw-r--r--tools/perf/builtin-test.c565
-rw-r--r--tools/perf/builtin-top.c79
-rw-r--r--tools/perf/perf.h10
-rw-r--r--tools/perf/ui/browser.c (renamed from tools/perf/util/ui/browser.c)298
-rw-r--r--tools/perf/ui/browser.h (renamed from tools/perf/util/ui/browser.h)10
-rw-r--r--tools/perf/ui/browsers/annotate.c951
-rw-r--r--tools/perf/ui/browsers/hists.c (renamed from tools/perf/util/ui/browsers/hists.c)360
-rw-r--r--tools/perf/ui/browsers/map.c (renamed from tools/perf/util/ui/browsers/map.c)6
-rw-r--r--tools/perf/ui/browsers/map.h (renamed from tools/perf/util/ui/browsers/map.h)0
-rw-r--r--tools/perf/ui/gtk/browser.c (renamed from tools/perf/util/gtk/browser.c)31
-rw-r--r--tools/perf/ui/gtk/gtk.h (renamed from tools/perf/util/gtk/gtk.h)0
-rw-r--r--tools/perf/ui/gtk/setup.c12
-rw-r--r--tools/perf/ui/helpline.c (renamed from tools/perf/util/ui/helpline.c)0
-rw-r--r--tools/perf/ui/helpline.h (renamed from tools/perf/util/ui/helpline.h)0
-rw-r--r--tools/perf/ui/keysyms.h (renamed from tools/perf/util/ui/keysyms.h)0
-rw-r--r--tools/perf/ui/libslang.h (renamed from tools/perf/util/ui/libslang.h)0
-rw-r--r--tools/perf/ui/progress.c (renamed from tools/perf/util/ui/progress.c)0
-rw-r--r--tools/perf/ui/progress.h (renamed from tools/perf/util/ui/progress.h)0
-rw-r--r--tools/perf/ui/setup.c46
-rw-r--r--tools/perf/ui/tui/setup.c (renamed from tools/perf/util/ui/setup.c)77
-rw-r--r--tools/perf/ui/ui.h (renamed from tools/perf/util/ui/ui.h)0
-rw-r--r--tools/perf/ui/util.c (renamed from tools/perf/util/ui/util.c)0
-rw-r--r--tools/perf/ui/util.h (renamed from tools/perf/util/ui/util.h)0
-rw-r--r--tools/perf/util/annotate.c599
-rw-r--r--tools/perf/util/annotate.h67
-rw-r--r--tools/perf/util/build-id.c2
-rw-r--r--tools/perf/util/cache.h24
-rw-r--r--tools/perf/util/config.c2
-rw-r--r--tools/perf/util/debug.c1
-rw-r--r--tools/perf/util/debug.h2
-rw-r--r--tools/perf/util/evlist.c16
-rw-r--r--tools/perf/util/evlist.h4
-rw-r--r--tools/perf/util/evsel.c111
-rw-r--r--tools/perf/util/evsel.h3
-rw-r--r--tools/perf/util/header.c27
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/hist.c2
-rw-r--r--tools/perf/util/hist.h2
-rw-r--r--tools/perf/util/parse-events-test.c625
-rw-r--r--tools/perf/util/parse-events.c141
-rw-r--r--tools/perf/util/parse-events.h43
-rw-r--r--tools/perf/util/parse-events.l26
-rw-r--r--tools/perf/util/parse-events.y93
-rw-r--r--tools/perf/util/pmu.c74
-rw-r--r--tools/perf/util/probe-event.c422
-rw-r--r--tools/perf/util/probe-event.h12
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c16
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c16
-rw-r--r--tools/perf/util/session.c96
-rw-r--r--tools/perf/util/symbol.c8
-rw-r--r--tools/perf/util/symbol.h6
-rw-r--r--tools/perf/util/target.c142
-rw-r--r--tools/perf/util/target.h65
-rw-r--r--tools/perf/util/thread_map.c21
-rw-r--r--tools/perf/util/thread_map.h2
-rw-r--r--tools/perf/util/top.c19
-rw-r--r--tools/perf/util/top.h6
-rw-r--r--tools/perf/util/trace-event-info.c4
-rw-r--r--tools/perf/util/trace-event-parse.c3142
-rw-r--r--tools/perf/util/trace-event-read.c44
-rw-r--r--tools/perf/util/trace-event.h269
-rw-r--r--tools/perf/util/types.h5
-rw-r--r--tools/perf/util/ui/browsers/annotate.c433
-rw-r--r--tools/perf/util/usage.c38
-rw-r--r--tools/perf/util/util.c10
-rw-r--r--tools/perf/util/util.h5
-rw-r--r--tools/power/cpupower/man/cpupower-set.19
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.c35
-rw-r--r--tools/scripts/Makefile.include58
-rw-r--r--tools/testing/ktest/examples/README32
-rw-r--r--tools/testing/ktest/examples/crosstests.conf260
-rw-r--r--tools/testing/ktest/examples/include/bisect.conf90
-rw-r--r--tools/testing/ktest/examples/include/defaults.conf157
-rw-r--r--tools/testing/ktest/examples/include/min-config.conf60
-rw-r--r--tools/testing/ktest/examples/include/patchcheck.conf74
-rw-r--r--tools/testing/ktest/examples/include/tests.conf74
-rw-r--r--tools/testing/ktest/examples/kvm.conf88
-rw-r--r--tools/testing/ktest/examples/snowball.conf53
-rw-r--r--tools/testing/ktest/examples/test.conf62
-rwxr-xr-xtools/testing/ktest/ktest.pl36
-rw-r--r--tools/testing/ktest/sample.conf18
-rw-r--r--tools/testing/selftests/Makefile2
-rw-r--r--tools/testing/selftests/kcmp/Makefile29
-rw-r--r--tools/testing/selftests/kcmp/kcmp_test.c94
-rw-r--r--tools/testing/selftests/mqueue/.gitignore2
-rw-r--r--tools/testing/selftests/mqueue/Makefile10
-rw-r--r--tools/testing/selftests/mqueue/mq_open_tests.c492
-rw-r--r--tools/testing/selftests/mqueue/mq_perf_tests.c741
-rw-r--r--tools/usb/ffs-test.c2
-rw-r--r--tools/usb/testusb.c5
-rw-r--r--tools/virtio/linux/virtio.h1
-rw-r--r--tools/virtio/virtio_test.c26
-rw-r--r--tools/vm/page-types.c50
118 files changed, 15882 insertions, 5336 deletions
diff --git a/tools/Makefile b/tools/Makefile
new file mode 100644
index 000000000000..3ae43947a171
--- /dev/null
+++ b/tools/Makefile
@@ -0,0 +1,77 @@
1include scripts/Makefile.include
2
3help:
4 @echo 'Possible targets:'
5 @echo ''
6 @echo ' cpupower - a tool for all things x86 CPU power'
7 @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer'
8 @echo ' lguest - a minimal 32-bit x86 hypervisor'
9 @echo ' perf - Linux performance measurement and analysis tool'
10 @echo ' selftests - various kernel selftests'
11 @echo ' turbostat - Intel CPU idle stats and freq reporting tool'
12 @echo ' usb - USB testing tools'
13 @echo ' virtio - vhost test module'
14 @echo ' vm - misc vm tools'
15 @echo ' x86_energy_perf_policy - Intel energy policy tool'
16 @echo ''
17 @echo 'You can do:'
18 @echo ' $$ make -C tools/<tool>_install'
19 @echo ''
20 @echo ' from the kernel command line to build and install one of'
21 @echo ' the tools above'
22 @echo ''
23 @echo ' $$ make tools/install'
24 @echo ''
25 @echo ' installs all tools.'
26 @echo ''
27 @echo 'Cleaning targets:'
28 @echo ''
29 @echo ' all of the above with the "_clean" string appended cleans'
30 @echo ' the respective build directory.'
31 @echo ' clean: a summary clean target to clean _all_ folders'
32
33cpupower: FORCE
34 $(QUIET_SUBDIR0)power/$@/ $(QUIET_SUBDIR1)
35
36firewire lguest perf usb virtio vm: FORCE
37 $(QUIET_SUBDIR0)$@/ $(QUIET_SUBDIR1)
38
39selftests: FORCE
40 $(QUIET_SUBDIR0)testing/$@/ $(QUIET_SUBDIR1)
41
42turbostat x86_energy_perf_policy: FORCE
43 $(QUIET_SUBDIR0)power/x86/$@/ $(QUIET_SUBDIR1)
44
45cpupower_install:
46 $(QUIET_SUBDIR0)power/$(@:_install=)/ $(QUIET_SUBDIR1) install
47
48firewire_install lguest_install perf_install usb_install virtio_install vm_install:
49 $(QUIET_SUBDIR0)$(@:_install=)/ $(QUIET_SUBDIR1) install
50
51selftests_install:
52 $(QUIET_SUBDIR0)testing/$(@:_clean=)/ $(QUIET_SUBDIR1) install
53
54turbostat_install x86_energy_perf_policy_install:
55 $(QUIET_SUBDIR0)power/x86/$(@:_install=)/ $(QUIET_SUBDIR1) install
56
57install: cpupower_install firewire_install lguest_install perf_install \
58 selftests_install turbostat_install usb_install virtio_install \
59 vm_install x86_energy_perf_policy_install
60
61cpupower_clean:
62 $(QUIET_SUBDIR0)power/cpupower/ $(QUIET_SUBDIR1) clean
63
64firewire_clean lguest_clean perf_clean usb_clean virtio_clean vm_clean:
65 $(QUIET_SUBDIR0)$(@:_clean=)/ $(QUIET_SUBDIR1) clean
66
67selftests_clean:
68 $(QUIET_SUBDIR0)testing/$(@:_clean=)/ $(QUIET_SUBDIR1) clean
69
70turbostat_clean x86_energy_perf_policy_clean:
71 $(QUIET_SUBDIR0)power/x86/$(@:_clean=)/ $(QUIET_SUBDIR1) clean
72
73clean: cpupower_clean firewire_clean lguest_clean perf_clean selftests_clean \
74 turbostat_clean usb_clean virtio_clean vm_clean \
75 x86_energy_perf_policy_clean
76
77.PHONY: FORCE
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile
new file mode 100644
index 000000000000..3d69aa9ff51e
--- /dev/null
+++ b/tools/lib/traceevent/Makefile
@@ -0,0 +1,303 @@
1# trace-cmd version
2EP_VERSION = 1
3EP_PATCHLEVEL = 1
4EP_EXTRAVERSION = 0
5
6# file format version
7FILE_VERSION = 6
8
9MAKEFLAGS += --no-print-directory
10
11
12# Makefiles suck: This macro sets a default value of $(2) for the
13# variable named by $(1), unless the variable has been set by
14# environment or command line. This is necessary for CC and AR
15# because make sets default values, so the simpler ?= approach
16# won't work as expected.
17define allow-override
18 $(if $(or $(findstring environment,$(origin $(1))),\
19 $(findstring command line,$(origin $(1)))),,\
20 $(eval $(1) = $(2)))
21endef
22
23# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix.
24$(call allow-override,CC,$(CROSS_COMPILE)gcc)
25$(call allow-override,AR,$(CROSS_COMPILE)ar)
26
27EXT = -std=gnu99
28INSTALL = install
29
30# Use DESTDIR for installing into a different root directory.
31# This is useful for building a package. The program will be
32# installed in this directory as if it was the root directory.
33# Then the build tool can move it later.
34DESTDIR ?=
35DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))'
36
37prefix ?= /usr/local
38bindir_relative = bin
39bindir = $(prefix)/$(bindir_relative)
40man_dir = $(prefix)/share/man
41man_dir_SQ = '$(subst ','\'',$(man_dir))'
42html_install = $(prefix)/share/kernelshark/html
43html_install_SQ = '$(subst ','\'',$(html_install))'
44img_install = $(prefix)/share/kernelshark/html/images
45img_install_SQ = '$(subst ','\'',$(img_install))'
46
47export man_dir man_dir_SQ html_install html_install_SQ INSTALL
48export img_install img_install_SQ
49export DESTDIR DESTDIR_SQ
50
51# copy a bit from Linux kbuild
52
53ifeq ("$(origin V)", "command line")
54 VERBOSE = $(V)
55endif
56ifndef VERBOSE
57 VERBOSE = 0
58endif
59
60ifeq ("$(origin O)", "command line")
61 BUILD_OUTPUT := $(O)
62endif
63
64ifeq ($(BUILD_SRC),)
65ifneq ($(BUILD_OUTPUT),)
66
67define build_output
68 $(if $(VERBOSE:1=),@)$(MAKE) -C $(BUILD_OUTPUT) \
69 BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1
70endef
71
72saved-output := $(BUILD_OUTPUT)
73BUILD_OUTPUT := $(shell cd $(BUILD_OUTPUT) && /bin/pwd)
74$(if $(BUILD_OUTPUT),, \
75 $(error output directory "$(saved-output)" does not exist))
76
77all: sub-make
78
79gui: force
80 $(call build_output, all_cmd)
81
82$(filter-out gui,$(MAKECMDGOALS)): sub-make
83
84sub-make: force
85 $(call build_output, $(MAKECMDGOALS))
86
87
88# Leave processing to above invocation of make
89skip-makefile := 1
90
91endif # BUILD_OUTPUT
92endif # BUILD_SRC
93
94# We process the rest of the Makefile if this is the final invocation of make
95ifeq ($(skip-makefile),)
96
97srctree := $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR))
98objtree := $(CURDIR)
99src := $(srctree)
100obj := $(objtree)
101
102export prefix bindir src obj
103
104# Shell quotes
105bindir_SQ = $(subst ','\'',$(bindir))
106bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
107
108LIB_FILE = libtraceevent.a libtraceevent.so
109
110CONFIG_INCLUDES =
111CONFIG_LIBS =
112CONFIG_FLAGS =
113
114VERSION = $(EP_VERSION)
115PATCHLEVEL = $(EP_PATCHLEVEL)
116EXTRAVERSION = $(EP_EXTRAVERSION)
117
118OBJ = $@
119N =
120
121export Q VERBOSE
122
123EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION)
124
125INCLUDES = -I. -I/usr/local/include $(CONFIG_INCLUDES)
126
127# Set compile option CFLAGS if not set elsewhere
128CFLAGS ?= -g -Wall
129
130# Append required CFLAGS
131override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ)
132override CFLAGS += $(udis86-flags)
133
134ifeq ($(VERBOSE),1)
135 Q =
136 print_compile =
137 print_app_build =
138 print_fpic_compile =
139 print_shared_lib_compile =
140 print_plugin_obj_compile =
141 print_plugin_build =
142 print_install =
143else
144 Q = @
145 print_compile = echo ' CC '$(OBJ);
146 print_app_build = echo ' BUILD '$(OBJ);
147 print_fpic_compile = echo ' CC FPIC '$(OBJ);
148 print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ);
149 print_plugin_obj_compile = echo ' CC PLUGIN OBJ '$(OBJ);
150 print_plugin_build = echo ' CC PLUGI '$(OBJ);
151 print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ);
152 print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2';
153endif
154
155do_fpic_compile = \
156 ($(print_fpic_compile) \
157 $(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@)
158
159do_app_build = \
160 ($(print_app_build) \
161 $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS))
162
163do_compile_shared_library = \
164 ($(print_shared_lib_compile) \
165 $(CC) --shared $^ -o $@)
166
167do_compile_plugin_obj = \
168 ($(print_plugin_obj_compile) \
169 $(CC) -c $(CFLAGS) -fPIC -o $@ $<)
170
171do_plugin_build = \
172 ($(print_plugin_build) \
173 $(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<)
174
175do_build_static_lib = \
176 ($(print_static_lib_build) \
177 $(RM) $@; $(AR) rcs $@ $^)
178
179
180define do_compile
181 $(print_compile) \
182 $(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@;
183endef
184
185$(obj)/%.o: $(src)/%.c
186 $(Q)$(call do_compile)
187
188%.o: $(src)/%.c
189 $(Q)$(call do_compile)
190
191PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o
192
193ALL_OBJS = $(PEVENT_LIB_OBJS)
194
195CMD_TARGETS = $(LIB_FILE)
196
197TARGETS = $(CMD_TARGETS)
198
199
200all: all_cmd
201
202all_cmd: $(CMD_TARGETS)
203
204libtraceevent.so: $(PEVENT_LIB_OBJS)
205 $(Q)$(do_compile_shared_library)
206
207libtraceevent.a: $(PEVENT_LIB_OBJS)
208 $(Q)$(do_build_static_lib)
209
210$(PEVENT_LIB_OBJS): %.o: $(src)/%.c
211 $(Q)$(do_fpic_compile)
212
213define make_version.h
214 (echo '/* This file is automatically generated. Do not modify. */'; \
215 echo \#define VERSION_CODE $(shell \
216 expr $(VERSION) \* 256 + $(PATCHLEVEL)); \
217 echo '#define EXTRAVERSION ' $(EXTRAVERSION); \
218 echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"'; \
219 echo '#define FILE_VERSION '$(FILE_VERSION); \
220 ) > $1
221endef
222
223define update_version.h
224 ($(call make_version.h, $@.tmp); \
225 if [ -r $@ ] && cmp -s $@ $@.tmp; then \
226 rm -f $@.tmp; \
227 else \
228 echo ' UPDATE $@'; \
229 mv -f $@.tmp $@; \
230 fi);
231endef
232
233ep_version.h: force
234 $(Q)$(N)$(call update_version.h)
235
236VERSION_FILES = ep_version.h
237
238define update_dir
239 (echo $1 > $@.tmp; \
240 if [ -r $@ ] && cmp -s $@ $@.tmp; then \
241 rm -f $@.tmp; \
242 else \
243 echo ' UPDATE $@'; \
244 mv -f $@.tmp $@; \
245 fi);
246endef
247
248## make deps
249
250all_objs := $(sort $(ALL_OBJS))
251all_deps := $(all_objs:%.o=.%.d)
252
253define check_deps
254 $(CC) -M $(CFLAGS) $< > $@;
255endef
256
257$(gui_deps): ks_version.h
258$(non_gui_deps): tc_version.h
259
260$(all_deps): .%.d: $(src)/%.c
261 $(Q)$(call check_deps)
262
263$(all_objs) : %.o : .%.d
264
265dep_includes := $(wildcard $(all_deps))
266
267ifneq ($(dep_includes),)
268 include $(dep_includes)
269endif
270
271tags: force
272 $(RM) tags
273 find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px
274
275TAGS: force
276 $(RM) TAGS
277 find . -name '*.[ch]' | xargs etags
278
279define do_install
280 $(print_install) \
281 if [ ! -d '$(DESTDIR_SQ)$2' ]; then \
282 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \
283 fi; \
284 $(INSTALL) $1 '$(DESTDIR_SQ)$2'
285endef
286
287install_lib: all_cmd install_plugins install_python
288 $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ))
289
290install: install_lib
291
292clean:
293 $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES).*.d
294 $(RM) tags TAGS
295
296endif # skip-makefile
297
298PHONY += force
299force:
300
301# Declare the contents of the .PHONY variable as phony. We keep that
302# information in a variable so we can use it in if_changed and friends.
303.PHONY: $(PHONY)
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
new file mode 100644
index 000000000000..554828219c33
--- /dev/null
+++ b/tools/lib/traceevent/event-parse.c
@@ -0,0 +1,5079 @@
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, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 *
21 * The parts for function graph printing was taken and modified from the
22 * Linux Kernel that were written by
23 * - Copyright (C) 2009 Frederic Weisbecker,
24 * Frederic Weisbecker gave his permission to relicense the code to
25 * the Lesser General Public License.
26 */
27#define _GNU_SOURCE
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <stdarg.h>
32#include <ctype.h>
33#include <errno.h>
34
35#include "event-parse.h"
36#include "event-utils.h"
37
38static const char *input_buf;
39static unsigned long long input_buf_ptr;
40static unsigned long long input_buf_siz;
41
42static int is_flag_field;
43static int is_symbolic_field;
44
45static int show_warning = 1;
46
47#define do_warning(fmt, ...) \
48 do { \
49 if (show_warning) \
50 warning(fmt, ##__VA_ARGS__); \
51 } while (0)
52
53static void init_input_buf(const char *buf, unsigned long long size)
54{
55 input_buf = buf;
56 input_buf_siz = size;
57 input_buf_ptr = 0;
58}
59
60const char *pevent_get_input_buf(void)
61{
62 return input_buf;
63}
64
65unsigned long long pevent_get_input_buf_ptr(void)
66{
67 return input_buf_ptr;
68}
69
70struct event_handler {
71 struct event_handler *next;
72 int id;
73 const char *sys_name;
74 const char *event_name;
75 pevent_event_handler_func func;
76 void *context;
77};
78
79struct pevent_func_params {
80 struct pevent_func_params *next;
81 enum pevent_func_arg_type type;
82};
83
84struct pevent_function_handler {
85 struct pevent_function_handler *next;
86 enum pevent_func_arg_type ret_type;
87 char *name;
88 pevent_func_handler func;
89 struct pevent_func_params *params;
90 int nr_args;
91};
92
93static unsigned long long
94process_defined_func(struct trace_seq *s, void *data, int size,
95 struct event_format *event, struct print_arg *arg);
96
97static void free_func_handle(struct pevent_function_handler *func);
98
99/**
100 * pevent_buffer_init - init buffer for parsing
101 * @buf: buffer to parse
102 * @size: the size of the buffer
103 *
104 * For use with pevent_read_token(), this initializes the internal
105 * buffer that pevent_read_token() will parse.
106 */
107void pevent_buffer_init(const char *buf, unsigned long long size)
108{
109 init_input_buf(buf, size);
110}
111
112void breakpoint(void)
113{
114 static int x;
115 x++;
116}
117
118struct print_arg *alloc_arg(void)
119{
120 struct print_arg *arg;
121
122 arg = malloc_or_die(sizeof(*arg));
123 if (!arg)
124 return NULL;
125 memset(arg, 0, sizeof(*arg));
126
127 return arg;
128}
129
130struct cmdline {
131 char *comm;
132 int pid;
133};
134
135static int cmdline_cmp(const void *a, const void *b)
136{
137 const struct cmdline *ca = a;
138 const struct cmdline *cb = b;
139
140 if (ca->pid < cb->pid)
141 return -1;
142 if (ca->pid > cb->pid)
143 return 1;
144
145 return 0;
146}
147
148struct cmdline_list {
149 struct cmdline_list *next;
150 char *comm;
151 int pid;
152};
153
154static int cmdline_init(struct pevent *pevent)
155{
156 struct cmdline_list *cmdlist = pevent->cmdlist;
157 struct cmdline_list *item;
158 struct cmdline *cmdlines;
159 int i;
160
161 cmdlines = malloc_or_die(sizeof(*cmdlines) * pevent->cmdline_count);
162
163 i = 0;
164 while (cmdlist) {
165 cmdlines[i].pid = cmdlist->pid;
166 cmdlines[i].comm = cmdlist->comm;
167 i++;
168 item = cmdlist;
169 cmdlist = cmdlist->next;
170 free(item);
171 }
172
173 qsort(cmdlines, pevent->cmdline_count, sizeof(*cmdlines), cmdline_cmp);
174
175 pevent->cmdlines = cmdlines;
176 pevent->cmdlist = NULL;
177
178 return 0;
179}
180
181static char *find_cmdline(struct pevent *pevent, int pid)
182{
183 const struct cmdline *comm;
184 struct cmdline key;
185
186 if (!pid)
187 return "<idle>";
188
189 if (!pevent->cmdlines)
190 cmdline_init(pevent);
191
192 key.pid = pid;
193
194 comm = bsearch(&key, pevent->cmdlines, pevent->cmdline_count,
195 sizeof(*pevent->cmdlines), cmdline_cmp);
196
197 if (comm)
198 return comm->comm;
199 return "<...>";
200}
201
202/**
203 * pevent_pid_is_registered - return if a pid has a cmdline registered
204 * @pevent: handle for the pevent
205 * @pid: The pid to check if it has a cmdline registered with.
206 *
207 * Returns 1 if the pid has a cmdline mapped to it
208 * 0 otherwise.
209 */
210int pevent_pid_is_registered(struct pevent *pevent, int pid)
211{
212 const struct cmdline *comm;
213 struct cmdline key;
214
215 if (!pid)
216 return 1;
217
218 if (!pevent->cmdlines)
219 cmdline_init(pevent);
220
221 key.pid = pid;
222
223 comm = bsearch(&key, pevent->cmdlines, pevent->cmdline_count,
224 sizeof(*pevent->cmdlines), cmdline_cmp);
225
226 if (comm)
227 return 1;
228 return 0;
229}
230
231/*
232 * If the command lines have been converted to an array, then
233 * we must add this pid. This is much slower than when cmdlines
234 * are added before the array is initialized.
235 */
236static int add_new_comm(struct pevent *pevent, const char *comm, int pid)
237{
238 struct cmdline *cmdlines = pevent->cmdlines;
239 const struct cmdline *cmdline;
240 struct cmdline key;
241
242 if (!pid)
243 return 0;
244
245 /* avoid duplicates */
246 key.pid = pid;
247
248 cmdline = bsearch(&key, pevent->cmdlines, pevent->cmdline_count,
249 sizeof(*pevent->cmdlines), cmdline_cmp);
250 if (cmdline) {
251 errno = EEXIST;
252 return -1;
253 }
254
255 cmdlines = realloc(cmdlines, sizeof(*cmdlines) * (pevent->cmdline_count + 1));
256 if (!cmdlines) {
257 errno = ENOMEM;
258 return -1;
259 }
260
261 cmdlines[pevent->cmdline_count].pid = pid;
262 cmdlines[pevent->cmdline_count].comm = strdup(comm);
263 if (!cmdlines[pevent->cmdline_count].comm)
264 die("malloc comm");
265
266 if (cmdlines[pevent->cmdline_count].comm)
267 pevent->cmdline_count++;
268
269 qsort(cmdlines, pevent->cmdline_count, sizeof(*cmdlines), cmdline_cmp);
270 pevent->cmdlines = cmdlines;
271
272 return 0;
273}
274
275/**
276 * pevent_register_comm - register a pid / comm mapping
277 * @pevent: handle for the pevent
278 * @comm: the command line to register
279 * @pid: the pid to map the command line to
280 *
281 * This adds a mapping to search for command line names with
282 * a given pid. The comm is duplicated.
283 */
284int pevent_register_comm(struct pevent *pevent, const char *comm, int pid)
285{
286 struct cmdline_list *item;
287
288 if (pevent->cmdlines)
289 return add_new_comm(pevent, comm, pid);
290
291 item = malloc_or_die(sizeof(*item));
292 item->comm = strdup(comm);
293 if (!item->comm)
294 die("malloc comm");
295 item->pid = pid;
296 item->next = pevent->cmdlist;
297
298 pevent->cmdlist = item;
299 pevent->cmdline_count++;
300
301 return 0;
302}
303
304struct func_map {
305 unsigned long long addr;
306 char *func;
307 char *mod;
308};
309
310struct func_list {
311 struct func_list *next;
312 unsigned long long addr;
313 char *func;
314 char *mod;
315};
316
317static int func_cmp(const void *a, const void *b)
318{
319 const struct func_map *fa = a;
320 const struct func_map *fb = b;
321
322 if (fa->addr < fb->addr)
323 return -1;
324 if (fa->addr > fb->addr)
325 return 1;
326
327 return 0;
328}
329
330/*
331 * We are searching for a record in between, not an exact
332 * match.
333 */
334static int func_bcmp(const void *a, const void *b)
335{
336 const struct func_map *fa = a;
337 const struct func_map *fb = b;
338
339 if ((fa->addr == fb->addr) ||
340
341 (fa->addr > fb->addr &&
342 fa->addr < (fb+1)->addr))
343 return 0;
344
345 if (fa->addr < fb->addr)
346 return -1;
347
348 return 1;
349}
350
351static int func_map_init(struct pevent *pevent)
352{
353 struct func_list *funclist;
354 struct func_list *item;
355 struct func_map *func_map;
356 int i;
357
358 func_map = malloc_or_die(sizeof(*func_map) * (pevent->func_count + 1));
359 funclist = pevent->funclist;
360
361 i = 0;
362 while (funclist) {
363 func_map[i].func = funclist->func;
364 func_map[i].addr = funclist->addr;
365 func_map[i].mod = funclist->mod;
366 i++;
367 item = funclist;
368 funclist = funclist->next;
369 free(item);
370 }
371
372 qsort(func_map, pevent->func_count, sizeof(*func_map), func_cmp);
373
374 /*
375 * Add a special record at the end.
376 */
377 func_map[pevent->func_count].func = NULL;
378 func_map[pevent->func_count].addr = 0;
379 func_map[pevent->func_count].mod = NULL;
380
381 pevent->func_map = func_map;
382 pevent->funclist = NULL;
383
384 return 0;
385}
386
387static struct func_map *
388find_func(struct pevent *pevent, unsigned long long addr)
389{
390 struct func_map *func;
391 struct func_map key;
392
393 if (!pevent->func_map)
394 func_map_init(pevent);
395
396 key.addr = addr;
397
398 func = bsearch(&key, pevent->func_map, pevent->func_count,
399 sizeof(*pevent->func_map), func_bcmp);
400
401 return func;
402}
403
404/**
405 * pevent_find_function - find a function by a given address
406 * @pevent: handle for the pevent
407 * @addr: the address to find the function with
408 *
409 * Returns a pointer to the function stored that has the given
410 * address. Note, the address does not have to be exact, it
411 * will select the function that would contain the address.
412 */
413const char *pevent_find_function(struct pevent *pevent, unsigned long long addr)
414{
415 struct func_map *map;
416
417 map = find_func(pevent, addr);
418 if (!map)
419 return NULL;
420
421 return map->func;
422}
423
424/**
425 * pevent_find_function_address - find a function address by a given address
426 * @pevent: handle for the pevent
427 * @addr: the address to find the function with
428 *
429 * Returns the address the function starts at. This can be used in
430 * conjunction with pevent_find_function to print both the function
431 * name and the function offset.
432 */
433unsigned long long
434pevent_find_function_address(struct pevent *pevent, unsigned long long addr)
435{
436 struct func_map *map;
437
438 map = find_func(pevent, addr);
439 if (!map)
440 return 0;
441
442 return map->addr;
443}
444
445/**
446 * pevent_register_function - register a function with a given address
447 * @pevent: handle for the pevent
448 * @function: the function name to register
449 * @addr: the address the function starts at
450 * @mod: the kernel module the function may be in (NULL for none)
451 *
452 * This registers a function name with an address and module.
453 * The @func passed in is duplicated.
454 */
455int pevent_register_function(struct pevent *pevent, char *func,
456 unsigned long long addr, char *mod)
457{
458 struct func_list *item;
459
460 item = malloc_or_die(sizeof(*item));
461
462 item->next = pevent->funclist;
463 item->func = strdup(func);
464 if (mod)
465 item->mod = strdup(mod);
466 else
467 item->mod = NULL;
468 item->addr = addr;
469
470 pevent->funclist = item;
471
472 pevent->func_count++;
473
474 return 0;
475}
476
477/**
478 * pevent_print_funcs - print out the stored functions
479 * @pevent: handle for the pevent
480 *
481 * This prints out the stored functions.
482 */
483void pevent_print_funcs(struct pevent *pevent)
484{
485 int i;
486
487 if (!pevent->func_map)
488 func_map_init(pevent);
489
490 for (i = 0; i < (int)pevent->func_count; i++) {
491 printf("%016llx %s",
492 pevent->func_map[i].addr,
493 pevent->func_map[i].func);
494 if (pevent->func_map[i].mod)
495 printf(" [%s]\n", pevent->func_map[i].mod);
496 else
497 printf("\n");
498 }
499}
500
501struct printk_map {
502 unsigned long long addr;
503 char *printk;
504};
505
506struct printk_list {
507 struct printk_list *next;
508 unsigned long long addr;
509 char *printk;
510};
511
512static int printk_cmp(const void *a, const void *b)
513{
514 const struct func_map *fa = a;
515 const struct func_map *fb = b;
516
517 if (fa->addr < fb->addr)
518 return -1;
519 if (fa->addr > fb->addr)
520 return 1;
521
522 return 0;
523}
524
525static void printk_map_init(struct pevent *pevent)
526{
527 struct printk_list *printklist;
528 struct printk_list *item;
529 struct printk_map *printk_map;
530 int i;
531
532 printk_map = malloc_or_die(sizeof(*printk_map) * (pevent->printk_count + 1));
533
534 printklist = pevent->printklist;
535
536 i = 0;
537 while (printklist) {
538 printk_map[i].printk = printklist->printk;
539 printk_map[i].addr = printklist->addr;
540 i++;
541 item = printklist;
542 printklist = printklist->next;
543 free(item);
544 }
545
546 qsort(printk_map, pevent->printk_count, sizeof(*printk_map), printk_cmp);
547
548 pevent->printk_map = printk_map;
549 pevent->printklist = NULL;
550}
551
552static struct printk_map *
553find_printk(struct pevent *pevent, unsigned long long addr)
554{
555 struct printk_map *printk;
556 struct printk_map key;
557
558 if (!pevent->printk_map)
559 printk_map_init(pevent);
560
561 key.addr = addr;
562
563 printk = bsearch(&key, pevent->printk_map, pevent->printk_count,
564 sizeof(*pevent->printk_map), printk_cmp);
565
566 return printk;
567}
568
569/**
570 * pevent_register_print_string - register a string by its address
571 * @pevent: handle for the pevent
572 * @fmt: the string format to register
573 * @addr: the address the string was located at
574 *
575 * This registers a string by the address it was stored in the kernel.
576 * The @fmt passed in is duplicated.
577 */
578int pevent_register_print_string(struct pevent *pevent, char *fmt,
579 unsigned long long addr)
580{
581 struct printk_list *item;
582
583 item = malloc_or_die(sizeof(*item));
584
585 item->next = pevent->printklist;
586 pevent->printklist = item;
587 item->printk = strdup(fmt);
588 item->addr = addr;
589
590 pevent->printk_count++;
591
592 return 0;
593}
594
595/**
596 * pevent_print_printk - print out the stored strings
597 * @pevent: handle for the pevent
598 *
599 * This prints the string formats that were stored.
600 */
601void pevent_print_printk(struct pevent *pevent)
602{
603 int i;
604
605 if (!pevent->printk_map)
606 printk_map_init(pevent);
607
608 for (i = 0; i < (int)pevent->printk_count; i++) {
609 printf("%016llx %s\n",
610 pevent->printk_map[i].addr,
611 pevent->printk_map[i].printk);
612 }
613}
614
615static struct event_format *alloc_event(void)
616{
617 struct event_format *event;
618
619 event = malloc_or_die(sizeof(*event));
620 memset(event, 0, sizeof(*event));
621
622 return event;
623}
624
625static void add_event(struct pevent *pevent, struct event_format *event)
626{
627 int i;
628
629 if (!pevent->events)
630 pevent->events = malloc_or_die(sizeof(event));
631 else
632 pevent->events =
633 realloc(pevent->events, sizeof(event) *
634 (pevent->nr_events + 1));
635 if (!pevent->events)
636 die("Can not allocate events");
637
638 for (i = 0; i < pevent->nr_events; i++) {
639 if (pevent->events[i]->id > event->id)
640 break;
641 }
642 if (i < pevent->nr_events)
643 memmove(&pevent->events[i + 1],
644 &pevent->events[i],
645 sizeof(event) * (pevent->nr_events - i));
646
647 pevent->events[i] = event;
648 pevent->nr_events++;
649
650 event->pevent = pevent;
651}
652
653static int event_item_type(enum event_type type)
654{
655 switch (type) {
656 case EVENT_ITEM ... EVENT_SQUOTE:
657 return 1;
658 case EVENT_ERROR ... EVENT_DELIM:
659 default:
660 return 0;
661 }
662}
663
664static void free_flag_sym(struct print_flag_sym *fsym)
665{
666 struct print_flag_sym *next;
667
668 while (fsym) {
669 next = fsym->next;
670 free(fsym->value);
671 free(fsym->str);
672 free(fsym);
673 fsym = next;
674 }
675}
676
677static void free_arg(struct print_arg *arg)
678{
679 struct print_arg *farg;
680
681 if (!arg)
682 return;
683
684 switch (arg->type) {
685 case PRINT_ATOM:
686 free(arg->atom.atom);
687 break;
688 case PRINT_FIELD:
689 free(arg->field.name);
690 break;
691 case PRINT_FLAGS:
692 free_arg(arg->flags.field);
693 free(arg->flags.delim);
694 free_flag_sym(arg->flags.flags);
695 break;
696 case PRINT_SYMBOL:
697 free_arg(arg->symbol.field);
698 free_flag_sym(arg->symbol.symbols);
699 break;
700 case PRINT_TYPE:
701 free(arg->typecast.type);
702 free_arg(arg->typecast.item);
703 break;
704 case PRINT_STRING:
705 case PRINT_BSTRING:
706 free(arg->string.string);
707 break;
708 case PRINT_DYNAMIC_ARRAY:
709 free(arg->dynarray.index);
710 break;
711 case PRINT_OP:
712 free(arg->op.op);
713 free_arg(arg->op.left);
714 free_arg(arg->op.right);
715 break;
716 case PRINT_FUNC:
717 while (arg->func.args) {
718 farg = arg->func.args;
719 arg->func.args = farg->next;
720 free_arg(farg);
721 }
722 break;
723
724 case PRINT_NULL:
725 default:
726 break;
727 }
728
729 free(arg);
730}
731
732static enum event_type get_type(int ch)
733{
734 if (ch == '\n')
735 return EVENT_NEWLINE;
736 if (isspace(ch))
737 return EVENT_SPACE;
738 if (isalnum(ch) || ch == '_')
739 return EVENT_ITEM;
740 if (ch == '\'')
741 return EVENT_SQUOTE;
742 if (ch == '"')
743 return EVENT_DQUOTE;
744 if (!isprint(ch))
745 return EVENT_NONE;
746 if (ch == '(' || ch == ')' || ch == ',')
747 return EVENT_DELIM;
748
749 return EVENT_OP;
750}
751
752static int __read_char(void)
753{
754 if (input_buf_ptr >= input_buf_siz)
755 return -1;
756
757 return input_buf[input_buf_ptr++];
758}
759
760static int __peek_char(void)
761{
762 if (input_buf_ptr >= input_buf_siz)
763 return -1;
764
765 return input_buf[input_buf_ptr];
766}
767
768/**
769 * pevent_peek_char - peek at the next character that will be read
770 *
771 * Returns the next character read, or -1 if end of buffer.
772 */
773int pevent_peek_char(void)
774{
775 return __peek_char();
776}
777
778static enum event_type force_token(const char *str, char **tok);
779
780static enum event_type __read_token(char **tok)
781{
782 char buf[BUFSIZ];
783 int ch, last_ch, quote_ch, next_ch;
784 int i = 0;
785 int tok_size = 0;
786 enum event_type type;
787
788 *tok = NULL;
789
790
791 ch = __read_char();
792 if (ch < 0)
793 return EVENT_NONE;
794
795 type = get_type(ch);
796 if (type == EVENT_NONE)
797 return type;
798
799 buf[i++] = ch;
800
801 switch (type) {
802 case EVENT_NEWLINE:
803 case EVENT_DELIM:
804 *tok = malloc_or_die(2);
805 (*tok)[0] = ch;
806 (*tok)[1] = 0;
807 return type;
808
809 case EVENT_OP:
810 switch (ch) {
811 case '-':
812 next_ch = __peek_char();
813 if (next_ch == '>') {
814 buf[i++] = __read_char();
815 break;
816 }
817 /* fall through */
818 case '+':
819 case '|':
820 case '&':
821 case '>':
822 case '<':
823 last_ch = ch;
824 ch = __peek_char();
825 if (ch != last_ch)
826 goto test_equal;
827 buf[i++] = __read_char();
828 switch (last_ch) {
829 case '>':
830 case '<':
831 goto test_equal;
832 default:
833 break;
834 }
835 break;
836 case '!':
837 case '=':
838 goto test_equal;
839 default: /* what should we do instead? */
840 break;
841 }
842 buf[i] = 0;
843 *tok = strdup(buf);
844 return type;
845
846 test_equal:
847 ch = __peek_char();
848 if (ch == '=')
849 buf[i++] = __read_char();
850 goto out;
851
852 case EVENT_DQUOTE:
853 case EVENT_SQUOTE:
854 /* don't keep quotes */
855 i--;
856 quote_ch = ch;
857 last_ch = 0;
858 concat:
859 do {
860 if (i == (BUFSIZ - 1)) {
861 buf[i] = 0;
862 if (*tok) {
863 *tok = realloc(*tok, tok_size + BUFSIZ);
864 if (!*tok)
865 return EVENT_NONE;
866 strcat(*tok, buf);
867 } else
868 *tok = strdup(buf);
869
870 if (!*tok)
871 return EVENT_NONE;
872 tok_size += BUFSIZ;
873 i = 0;
874 }
875 last_ch = ch;
876 ch = __read_char();
877 buf[i++] = ch;
878 /* the '\' '\' will cancel itself */
879 if (ch == '\\' && last_ch == '\\')
880 last_ch = 0;
881 } while (ch != quote_ch || last_ch == '\\');
882 /* remove the last quote */
883 i--;
884
885 /*
886 * For strings (double quotes) check the next token.
887 * If it is another string, concatinate the two.
888 */
889 if (type == EVENT_DQUOTE) {
890 unsigned long long save_input_buf_ptr = input_buf_ptr;
891
892 do {
893 ch = __read_char();
894 } while (isspace(ch));
895 if (ch == '"')
896 goto concat;
897 input_buf_ptr = save_input_buf_ptr;
898 }
899
900 goto out;
901
902 case EVENT_ERROR ... EVENT_SPACE:
903 case EVENT_ITEM:
904 default:
905 break;
906 }
907
908 while (get_type(__peek_char()) == type) {
909 if (i == (BUFSIZ - 1)) {
910 buf[i] = 0;
911 if (*tok) {
912 *tok = realloc(*tok, tok_size + BUFSIZ);
913 if (!*tok)
914 return EVENT_NONE;
915 strcat(*tok, buf);
916 } else
917 *tok = strdup(buf);
918
919 if (!*tok)
920 return EVENT_NONE;
921 tok_size += BUFSIZ;
922 i = 0;
923 }
924 ch = __read_char();
925 buf[i++] = ch;
926 }
927
928 out:
929 buf[i] = 0;
930 if (*tok) {
931 *tok = realloc(*tok, tok_size + i);
932 if (!*tok)
933 return EVENT_NONE;
934 strcat(*tok, buf);
935 } else
936 *tok = strdup(buf);
937 if (!*tok)
938 return EVENT_NONE;
939
940 if (type == EVENT_ITEM) {
941 /*
942 * Older versions of the kernel has a bug that
943 * creates invalid symbols and will break the mac80211
944 * parsing. This is a work around to that bug.
945 *
946 * See Linux kernel commit:
947 * 811cb50baf63461ce0bdb234927046131fc7fa8b
948 */
949 if (strcmp(*tok, "LOCAL_PR_FMT") == 0) {
950 free(*tok);
951 *tok = NULL;
952 return force_token("\"\%s\" ", tok);
953 } else if (strcmp(*tok, "STA_PR_FMT") == 0) {
954 free(*tok);
955 *tok = NULL;
956 return force_token("\" sta:%pM\" ", tok);
957 } else if (strcmp(*tok, "VIF_PR_FMT") == 0) {
958 free(*tok);
959 *tok = NULL;
960 return force_token("\" vif:%p(%d)\" ", tok);
961 }
962 }
963
964 return type;
965}
966
967static enum event_type force_token(const char *str, char **tok)
968{
969 const char *save_input_buf;
970 unsigned long long save_input_buf_ptr;
971 unsigned long long save_input_buf_siz;
972 enum event_type type;
973
974 /* save off the current input pointers */
975 save_input_buf = input_buf;
976 save_input_buf_ptr = input_buf_ptr;
977 save_input_buf_siz = input_buf_siz;
978
979 init_input_buf(str, strlen(str));
980
981 type = __read_token(tok);
982
983 /* reset back to original token */
984 input_buf = save_input_buf;
985 input_buf_ptr = save_input_buf_ptr;
986 input_buf_siz = save_input_buf_siz;
987
988 return type;
989}
990
991static void free_token(char *tok)
992{
993 if (tok)
994 free(tok);
995}
996
997static enum event_type read_token(char **tok)
998{
999 enum event_type type;
1000
1001 for (;;) {
1002 type = __read_token(tok);
1003 if (type != EVENT_SPACE)
1004 return type;
1005
1006 free_token(*tok);
1007 }
1008
1009 /* not reached */
1010 *tok = NULL;
1011 return EVENT_NONE;
1012}
1013
1014/**
1015 * pevent_read_token - access to utilites to use the pevent parser
1016 * @tok: The token to return
1017 *
1018 * This will parse tokens from the string given by
1019 * pevent_init_data().
1020 *
1021 * Returns the token type.
1022 */
1023enum event_type pevent_read_token(char **tok)
1024{
1025 return read_token(tok);
1026}
1027
1028/**
1029 * pevent_free_token - free a token returned by pevent_read_token
1030 * @token: the token to free
1031 */
1032void pevent_free_token(char *token)
1033{
1034 free_token(token);
1035}
1036
1037/* no newline */
1038static enum event_type read_token_item(char **tok)
1039{
1040 enum event_type type;
1041
1042 for (;;) {
1043 type = __read_token(tok);
1044 if (type != EVENT_SPACE && type != EVENT_NEWLINE)
1045 return type;
1046 free_token(*tok);
1047 *tok = NULL;
1048 }
1049
1050 /* not reached */
1051 *tok = NULL;
1052 return EVENT_NONE;
1053}
1054
1055static int test_type(enum event_type type, enum event_type expect)
1056{
1057 if (type != expect) {
1058 do_warning("Error: expected type %d but read %d",
1059 expect, type);
1060 return -1;
1061 }
1062 return 0;
1063}
1064
1065static int test_type_token(enum event_type type, const char *token,
1066 enum event_type expect, const char *expect_tok)
1067{
1068 if (type != expect) {
1069 do_warning("Error: expected type %d but read %d",
1070 expect, type);
1071 return -1;
1072 }
1073
1074 if (strcmp(token, expect_tok) != 0) {
1075 do_warning("Error: expected '%s' but read '%s'",
1076 expect_tok, token);
1077 return -1;
1078 }
1079 return 0;
1080}
1081
1082static int __read_expect_type(enum event_type expect, char **tok, int newline_ok)
1083{
1084 enum event_type type;
1085
1086 if (newline_ok)
1087 type = read_token(tok);
1088 else
1089 type = read_token_item(tok);
1090 return test_type(type, expect);
1091}
1092
1093static int read_expect_type(enum event_type expect, char **tok)
1094{
1095 return __read_expect_type(expect, tok, 1);
1096}
1097
1098static int __read_expected(enum event_type expect, const char *str,
1099 int newline_ok)
1100{
1101 enum event_type type;
1102 char *token;
1103 int ret;
1104
1105 if (newline_ok)
1106 type = read_token(&token);
1107 else
1108 type = read_token_item(&token);
1109
1110 ret = test_type_token(type, token, expect, str);
1111
1112 free_token(token);
1113
1114 return ret;
1115}
1116
1117static int read_expected(enum event_type expect, const char *str)
1118{
1119 return __read_expected(expect, str, 1);
1120}
1121
1122static int read_expected_item(enum event_type expect, const char *str)
1123{
1124 return __read_expected(expect, str, 0);
1125}
1126
1127static char *event_read_name(void)
1128{
1129 char *token;
1130
1131 if (read_expected(EVENT_ITEM, "name") < 0)
1132 return NULL;
1133
1134 if (read_expected(EVENT_OP, ":") < 0)
1135 return NULL;
1136
1137 if (read_expect_type(EVENT_ITEM, &token) < 0)
1138 goto fail;
1139
1140 return token;
1141
1142 fail:
1143 free_token(token);
1144 return NULL;
1145}
1146
1147static int event_read_id(void)
1148{
1149 char *token;
1150 int id;
1151
1152 if (read_expected_item(EVENT_ITEM, "ID") < 0)
1153 return -1;
1154
1155 if (read_expected(EVENT_OP, ":") < 0)
1156 return -1;
1157
1158 if (read_expect_type(EVENT_ITEM, &token) < 0)
1159 goto fail;
1160
1161 id = strtoul(token, NULL, 0);
1162 free_token(token);
1163 return id;
1164
1165 fail:
1166 free_token(token);
1167 return -1;
1168}
1169
1170static int field_is_string(struct format_field *field)
1171{
1172 if ((field->flags & FIELD_IS_ARRAY) &&
1173 (strstr(field->type, "char") || strstr(field->type, "u8") ||
1174 strstr(field->type, "s8")))
1175 return 1;
1176
1177 return 0;
1178}
1179
1180static int field_is_dynamic(struct format_field *field)
1181{
1182 if (strncmp(field->type, "__data_loc", 10) == 0)
1183 return 1;
1184
1185 return 0;
1186}
1187
1188static int field_is_long(struct format_field *field)
1189{
1190 /* includes long long */
1191 if (strstr(field->type, "long"))
1192 return 1;
1193
1194 return 0;
1195}
1196
1197static int event_read_fields(struct event_format *event, struct format_field **fields)
1198{
1199 struct format_field *field = NULL;
1200 enum event_type type;
1201 char *token;
1202 char *last_token;
1203 int count = 0;
1204
1205 do {
1206 type = read_token(&token);
1207 if (type == EVENT_NEWLINE) {
1208 free_token(token);
1209 return count;
1210 }
1211
1212 count++;
1213
1214 if (test_type_token(type, token, EVENT_ITEM, "field"))
1215 goto fail;
1216 free_token(token);
1217
1218 type = read_token(&token);
1219 /*
1220 * The ftrace fields may still use the "special" name.
1221 * Just ignore it.
1222 */
1223 if (event->flags & EVENT_FL_ISFTRACE &&
1224 type == EVENT_ITEM && strcmp(token, "special") == 0) {
1225 free_token(token);
1226 type = read_token(&token);
1227 }
1228
1229 if (test_type_token(type, token, EVENT_OP, ":") < 0)
1230 goto fail;
1231
1232 free_token(token);
1233 if (read_expect_type(EVENT_ITEM, &token) < 0)
1234 goto fail;
1235
1236 last_token = token;
1237
1238 field = malloc_or_die(sizeof(*field));
1239 memset(field, 0, sizeof(*field));
1240 field->event = event;
1241
1242 /* read the rest of the type */
1243 for (;;) {
1244 type = read_token(&token);
1245 if (type == EVENT_ITEM ||
1246 (type == EVENT_OP && strcmp(token, "*") == 0) ||
1247 /*
1248 * Some of the ftrace fields are broken and have
1249 * an illegal "." in them.
1250 */
1251 (event->flags & EVENT_FL_ISFTRACE &&
1252 type == EVENT_OP && strcmp(token, ".") == 0)) {
1253
1254 if (strcmp(token, "*") == 0)
1255 field->flags |= FIELD_IS_POINTER;
1256
1257 if (field->type) {
1258 field->type = realloc(field->type,
1259 strlen(field->type) +
1260 strlen(last_token) + 2);
1261 strcat(field->type, " ");
1262 strcat(field->type, last_token);
1263 free(last_token);
1264 } else
1265 field->type = last_token;
1266 last_token = token;
1267 continue;
1268 }
1269
1270 break;
1271 }
1272
1273 if (!field->type) {
1274 die("no type found");
1275 goto fail;
1276 }
1277 field->name = last_token;
1278
1279 if (test_type(type, EVENT_OP))
1280 goto fail;
1281
1282 if (strcmp(token, "[") == 0) {
1283 enum event_type last_type = type;
1284 char *brackets = token;
1285 int len;
1286
1287 field->flags |= FIELD_IS_ARRAY;
1288
1289 type = read_token(&token);
1290
1291 if (type == EVENT_ITEM)
1292 field->arraylen = strtoul(token, NULL, 0);
1293 else
1294 field->arraylen = 0;
1295
1296 while (strcmp(token, "]") != 0) {
1297 if (last_type == EVENT_ITEM &&
1298 type == EVENT_ITEM)
1299 len = 2;
1300 else
1301 len = 1;
1302 last_type = type;
1303
1304 brackets = realloc(brackets,
1305 strlen(brackets) +
1306 strlen(token) + len);
1307 if (len == 2)
1308 strcat(brackets, " ");
1309 strcat(brackets, token);
1310 /* We only care about the last token */
1311 field->arraylen = strtoul(token, NULL, 0);
1312 free_token(token);
1313 type = read_token(&token);
1314 if (type == EVENT_NONE) {
1315 die("failed to find token");
1316 goto fail;
1317 }
1318 }
1319
1320 free_token(token);
1321
1322 brackets = realloc(brackets, strlen(brackets) + 2);
1323 strcat(brackets, "]");
1324
1325 /* add brackets to type */
1326
1327 type = read_token(&token);
1328 /*
1329 * If the next token is not an OP, then it is of
1330 * the format: type [] item;
1331 */
1332 if (type == EVENT_ITEM) {
1333 field->type = realloc(field->type,
1334 strlen(field->type) +
1335 strlen(field->name) +
1336 strlen(brackets) + 2);
1337 strcat(field->type, " ");
1338 strcat(field->type, field->name);
1339 free_token(field->name);
1340 strcat(field->type, brackets);
1341 field->name = token;
1342 type = read_token(&token);
1343 } else {
1344 field->type = realloc(field->type,
1345 strlen(field->type) +
1346 strlen(brackets) + 1);
1347 strcat(field->type, brackets);
1348 }
1349 free(brackets);
1350 }
1351
1352 if (field_is_string(field))
1353 field->flags |= FIELD_IS_STRING;
1354 if (field_is_dynamic(field))
1355 field->flags |= FIELD_IS_DYNAMIC;
1356 if (field_is_long(field))
1357 field->flags |= FIELD_IS_LONG;
1358
1359 if (test_type_token(type, token, EVENT_OP, ";"))
1360 goto fail;
1361 free_token(token);
1362
1363 if (read_expected(EVENT_ITEM, "offset") < 0)
1364 goto fail_expect;
1365
1366 if (read_expected(EVENT_OP, ":") < 0)
1367 goto fail_expect;
1368
1369 if (read_expect_type(EVENT_ITEM, &token))
1370 goto fail;
1371 field->offset = strtoul(token, NULL, 0);
1372 free_token(token);
1373
1374 if (read_expected(EVENT_OP, ";") < 0)
1375 goto fail_expect;
1376
1377 if (read_expected(EVENT_ITEM, "size") < 0)
1378 goto fail_expect;
1379
1380 if (read_expected(EVENT_OP, ":") < 0)
1381 goto fail_expect;
1382
1383 if (read_expect_type(EVENT_ITEM, &token))
1384 goto fail;
1385 field->size = strtoul(token, NULL, 0);
1386 free_token(token);
1387
1388 if (read_expected(EVENT_OP, ";") < 0)
1389 goto fail_expect;
1390
1391 type = read_token(&token);
1392 if (type != EVENT_NEWLINE) {
1393 /* newer versions of the kernel have a "signed" type */
1394 if (test_type_token(type, token, EVENT_ITEM, "signed"))
1395 goto fail;
1396
1397 free_token(token);
1398
1399 if (read_expected(EVENT_OP, ":") < 0)
1400 goto fail_expect;
1401
1402 if (read_expect_type(EVENT_ITEM, &token))
1403 goto fail;
1404
1405 /* add signed type */
1406
1407 free_token(token);
1408 if (read_expected(EVENT_OP, ";") < 0)
1409 goto fail_expect;
1410
1411 if (read_expect_type(EVENT_NEWLINE, &token))
1412 goto fail;
1413 }
1414
1415 free_token(token);
1416
1417 if (field->flags & FIELD_IS_ARRAY) {
1418 if (field->arraylen)
1419 field->elementsize = field->size / field->arraylen;
1420 else if (field->flags & FIELD_IS_STRING)
1421 field->elementsize = 1;
1422 else
1423 field->elementsize = event->pevent->long_size;
1424 } else
1425 field->elementsize = field->size;
1426
1427 *fields = field;
1428 fields = &field->next;
1429
1430 } while (1);
1431
1432 return 0;
1433
1434fail:
1435 free_token(token);
1436fail_expect:
1437 if (field) {
1438 free(field->type);
1439 free(field->name);
1440 free(field);
1441 }
1442 return -1;
1443}
1444
1445static int event_read_format(struct event_format *event)
1446{
1447 char *token;
1448 int ret;
1449
1450 if (read_expected_item(EVENT_ITEM, "format") < 0)
1451 return -1;
1452
1453 if (read_expected(EVENT_OP, ":") < 0)
1454 return -1;
1455
1456 if (read_expect_type(EVENT_NEWLINE, &token))
1457 goto fail;
1458 free_token(token);
1459
1460 ret = event_read_fields(event, &event->format.common_fields);
1461 if (ret < 0)
1462 return ret;
1463 event->format.nr_common = ret;
1464
1465 ret = event_read_fields(event, &event->format.fields);
1466 if (ret < 0)
1467 return ret;
1468 event->format.nr_fields = ret;
1469
1470 return 0;
1471
1472 fail:
1473 free_token(token);
1474 return -1;
1475}
1476
1477static enum event_type
1478process_arg_token(struct event_format *event, struct print_arg *arg,
1479 char **tok, enum event_type type);
1480
1481static enum event_type
1482process_arg(struct event_format *event, struct print_arg *arg, char **tok)
1483{
1484 enum event_type type;
1485 char *token;
1486
1487 type = read_token(&token);
1488 *tok = token;
1489
1490 return process_arg_token(event, arg, tok, type);
1491}
1492
1493static enum event_type
1494process_op(struct event_format *event, struct print_arg *arg, char **tok);
1495
1496static enum event_type
1497process_cond(struct event_format *event, struct print_arg *top, char **tok)
1498{
1499 struct print_arg *arg, *left, *right;
1500 enum event_type type;
1501 char *token = NULL;
1502
1503 arg = alloc_arg();
1504 left = alloc_arg();
1505 right = alloc_arg();
1506
1507 arg->type = PRINT_OP;
1508 arg->op.left = left;
1509 arg->op.right = right;
1510
1511 *tok = NULL;
1512 type = process_arg(event, left, &token);
1513
1514 again:
1515 /* Handle other operations in the arguments */
1516 if (type == EVENT_OP && strcmp(token, ":") != 0) {
1517 type = process_op(event, left, &token);
1518 goto again;
1519 }
1520
1521 if (test_type_token(type, token, EVENT_OP, ":"))
1522 goto out_free;
1523
1524 arg->op.op = token;
1525
1526 type = process_arg(event, right, &token);
1527
1528 top->op.right = arg;
1529
1530 *tok = token;
1531 return type;
1532
1533out_free:
1534 /* Top may point to itself */
1535 top->op.right = NULL;
1536 free_token(token);
1537 free_arg(arg);
1538 return EVENT_ERROR;
1539}
1540
1541static enum event_type
1542process_array(struct event_format *event, struct print_arg *top, char **tok)
1543{
1544 struct print_arg *arg;
1545 enum event_type type;
1546 char *token = NULL;
1547
1548 arg = alloc_arg();
1549
1550 *tok = NULL;
1551 type = process_arg(event, arg, &token);
1552 if (test_type_token(type, token, EVENT_OP, "]"))
1553 goto out_free;
1554
1555 top->op.right = arg;
1556
1557 free_token(token);
1558 type = read_token_item(&token);
1559 *tok = token;
1560
1561 return type;
1562
1563out_free:
1564 free_token(*tok);
1565 *tok = NULL;
1566 free_arg(arg);
1567 return EVENT_ERROR;
1568}
1569
1570static int get_op_prio(char *op)
1571{
1572 if (!op[1]) {
1573 switch (op[0]) {
1574 case '~':
1575 case '!':
1576 return 4;
1577 case '*':
1578 case '/':
1579 case '%':
1580 return 6;
1581 case '+':
1582 case '-':
1583 return 7;
1584 /* '>>' and '<<' are 8 */
1585 case '<':
1586 case '>':
1587 return 9;
1588 /* '==' and '!=' are 10 */
1589 case '&':
1590 return 11;
1591 case '^':
1592 return 12;
1593 case '|':
1594 return 13;
1595 case '?':
1596 return 16;
1597 default:
1598 do_warning("unknown op '%c'", op[0]);
1599 return -1;
1600 }
1601 } else {
1602 if (strcmp(op, "++") == 0 ||
1603 strcmp(op, "--") == 0) {
1604 return 3;
1605 } else if (strcmp(op, ">>") == 0 ||
1606 strcmp(op, "<<") == 0) {
1607 return 8;
1608 } else if (strcmp(op, ">=") == 0 ||
1609 strcmp(op, "<=") == 0) {
1610 return 9;
1611 } else if (strcmp(op, "==") == 0 ||
1612 strcmp(op, "!=") == 0) {
1613 return 10;
1614 } else if (strcmp(op, "&&") == 0) {
1615 return 14;
1616 } else if (strcmp(op, "||") == 0) {
1617 return 15;
1618 } else {
1619 do_warning("unknown op '%s'", op);
1620 return -1;
1621 }
1622 }
1623}
1624
1625static int set_op_prio(struct print_arg *arg)
1626{
1627
1628 /* single ops are the greatest */
1629 if (!arg->op.left || arg->op.left->type == PRINT_NULL)
1630 arg->op.prio = 0;
1631 else
1632 arg->op.prio = get_op_prio(arg->op.op);
1633
1634 return arg->op.prio;
1635}
1636
1637/* Note, *tok does not get freed, but will most likely be saved */
1638static enum event_type
1639process_op(struct event_format *event, struct print_arg *arg, char **tok)
1640{
1641 struct print_arg *left, *right = NULL;
1642 enum event_type type;
1643 char *token;
1644
1645 /* the op is passed in via tok */
1646 token = *tok;
1647
1648 if (arg->type == PRINT_OP && !arg->op.left) {
1649 /* handle single op */
1650 if (token[1]) {
1651 die("bad op token %s", token);
1652 goto out_free;
1653 }
1654 switch (token[0]) {
1655 case '~':
1656 case '!':
1657 case '+':
1658 case '-':
1659 break;
1660 default:
1661 do_warning("bad op token %s", token);
1662 goto out_free;
1663
1664 }
1665
1666 /* make an empty left */
1667 left = alloc_arg();
1668 left->type = PRINT_NULL;
1669 arg->op.left = left;
1670
1671 right = alloc_arg();
1672 arg->op.right = right;
1673
1674 /* do not free the token, it belongs to an op */
1675 *tok = NULL;
1676 type = process_arg(event, right, tok);
1677
1678 } else if (strcmp(token, "?") == 0) {
1679
1680 left = alloc_arg();
1681 /* copy the top arg to the left */
1682 *left = *arg;
1683
1684 arg->type = PRINT_OP;
1685 arg->op.op = token;
1686 arg->op.left = left;
1687 arg->op.prio = 0;
1688
1689 type = process_cond(event, arg, tok);
1690
1691 } else if (strcmp(token, ">>") == 0 ||
1692 strcmp(token, "<<") == 0 ||
1693 strcmp(token, "&") == 0 ||
1694 strcmp(token, "|") == 0 ||
1695 strcmp(token, "&&") == 0 ||
1696 strcmp(token, "||") == 0 ||
1697 strcmp(token, "-") == 0 ||
1698 strcmp(token, "+") == 0 ||
1699 strcmp(token, "*") == 0 ||
1700 strcmp(token, "^") == 0 ||
1701 strcmp(token, "/") == 0 ||
1702 strcmp(token, "<") == 0 ||
1703 strcmp(token, ">") == 0 ||
1704 strcmp(token, "==") == 0 ||
1705 strcmp(token, "!=") == 0) {
1706
1707 left = alloc_arg();
1708
1709 /* copy the top arg to the left */
1710 *left = *arg;
1711
1712 arg->type = PRINT_OP;
1713 arg->op.op = token;
1714 arg->op.left = left;
1715
1716 if (set_op_prio(arg) == -1) {
1717 event->flags |= EVENT_FL_FAILED;
1718 /* arg->op.op (= token) will be freed at out_free */
1719 arg->op.op = NULL;
1720 goto out_free;
1721 }
1722
1723 type = read_token_item(&token);
1724 *tok = token;
1725
1726 /* could just be a type pointer */
1727 if ((strcmp(arg->op.op, "*") == 0) &&
1728 type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
1729 if (left->type != PRINT_ATOM)
1730 die("bad pointer type");
1731 left->atom.atom = realloc(left->atom.atom,
1732 strlen(left->atom.atom) + 3);
1733 strcat(left->atom.atom, " *");
1734 free(arg->op.op);
1735 *arg = *left;
1736 free(left);
1737
1738 return type;
1739 }
1740
1741 right = alloc_arg();
1742 type = process_arg_token(event, right, tok, type);
1743 arg->op.right = right;
1744
1745 } else if (strcmp(token, "[") == 0) {
1746
1747 left = alloc_arg();
1748 *left = *arg;
1749
1750 arg->type = PRINT_OP;
1751 arg->op.op = token;
1752 arg->op.left = left;
1753
1754 arg->op.prio = 0;
1755
1756 type = process_array(event, arg, tok);
1757
1758 } else {
1759 do_warning("unknown op '%s'", token);
1760 event->flags |= EVENT_FL_FAILED;
1761 /* the arg is now the left side */
1762 goto out_free;
1763 }
1764
1765 if (type == EVENT_OP && strcmp(*tok, ":") != 0) {
1766 int prio;
1767
1768 /* higher prios need to be closer to the root */
1769 prio = get_op_prio(*tok);
1770
1771 if (prio > arg->op.prio)
1772 return process_op(event, arg, tok);
1773
1774 return process_op(event, right, tok);
1775 }
1776
1777 return type;
1778
1779 out_free:
1780 free_token(token);
1781 *tok = NULL;
1782 return EVENT_ERROR;
1783}
1784
1785static enum event_type
1786process_entry(struct event_format *event __unused, struct print_arg *arg,
1787 char **tok)
1788{
1789 enum event_type type;
1790 char *field;
1791 char *token;
1792
1793 if (read_expected(EVENT_OP, "->") < 0)
1794 goto out_err;
1795
1796 if (read_expect_type(EVENT_ITEM, &token) < 0)
1797 goto out_free;
1798 field = token;
1799
1800 arg->type = PRINT_FIELD;
1801 arg->field.name = field;
1802
1803 if (is_flag_field) {
1804 arg->field.field = pevent_find_any_field(event, arg->field.name);
1805 arg->field.field->flags |= FIELD_IS_FLAG;
1806 is_flag_field = 0;
1807 } else if (is_symbolic_field) {
1808 arg->field.field = pevent_find_any_field(event, arg->field.name);
1809 arg->field.field->flags |= FIELD_IS_SYMBOLIC;
1810 is_symbolic_field = 0;
1811 }
1812
1813 type = read_token(&token);
1814 *tok = token;
1815
1816 return type;
1817
1818 out_free:
1819 free_token(token);
1820 out_err:
1821 *tok = NULL;
1822 return EVENT_ERROR;
1823}
1824
1825static char *arg_eval (struct print_arg *arg);
1826
1827static unsigned long long
1828eval_type_str(unsigned long long val, const char *type, int pointer)
1829{
1830 int sign = 0;
1831 char *ref;
1832 int len;
1833
1834 len = strlen(type);
1835
1836 if (pointer) {
1837
1838 if (type[len-1] != '*') {
1839 do_warning("pointer expected with non pointer type");
1840 return val;
1841 }
1842
1843 ref = malloc_or_die(len);
1844 memcpy(ref, type, len);
1845
1846 /* chop off the " *" */
1847 ref[len - 2] = 0;
1848
1849 val = eval_type_str(val, ref, 0);
1850 free(ref);
1851 return val;
1852 }
1853
1854 /* check if this is a pointer */
1855 if (type[len - 1] == '*')
1856 return val;
1857
1858 /* Try to figure out the arg size*/
1859 if (strncmp(type, "struct", 6) == 0)
1860 /* all bets off */
1861 return val;
1862
1863 if (strcmp(type, "u8") == 0)
1864 return val & 0xff;
1865
1866 if (strcmp(type, "u16") == 0)
1867 return val & 0xffff;
1868
1869 if (strcmp(type, "u32") == 0)
1870 return val & 0xffffffff;
1871
1872 if (strcmp(type, "u64") == 0 ||
1873 strcmp(type, "s64"))
1874 return val;
1875
1876 if (strcmp(type, "s8") == 0)
1877 return (unsigned long long)(char)val & 0xff;
1878
1879 if (strcmp(type, "s16") == 0)
1880 return (unsigned long long)(short)val & 0xffff;
1881
1882 if (strcmp(type, "s32") == 0)
1883 return (unsigned long long)(int)val & 0xffffffff;
1884
1885 if (strncmp(type, "unsigned ", 9) == 0) {
1886 sign = 0;
1887 type += 9;
1888 }
1889
1890 if (strcmp(type, "char") == 0) {
1891 if (sign)
1892 return (unsigned long long)(char)val & 0xff;
1893 else
1894 return val & 0xff;
1895 }
1896
1897 if (strcmp(type, "short") == 0) {
1898 if (sign)
1899 return (unsigned long long)(short)val & 0xffff;
1900 else
1901 return val & 0xffff;
1902 }
1903
1904 if (strcmp(type, "int") == 0) {
1905 if (sign)
1906 return (unsigned long long)(int)val & 0xffffffff;
1907 else
1908 return val & 0xffffffff;
1909 }
1910
1911 return val;
1912}
1913
1914/*
1915 * Try to figure out the type.
1916 */
1917static unsigned long long
1918eval_type(unsigned long long val, struct print_arg *arg, int pointer)
1919{
1920 if (arg->type != PRINT_TYPE)
1921 die("expected type argument");
1922
1923 return eval_type_str(val, arg->typecast.type, pointer);
1924}
1925
1926static int arg_num_eval(struct print_arg *arg, long long *val)
1927{
1928 long long left, right;
1929 int ret = 1;
1930
1931 switch (arg->type) {
1932 case PRINT_ATOM:
1933 *val = strtoll(arg->atom.atom, NULL, 0);
1934 break;
1935 case PRINT_TYPE:
1936 ret = arg_num_eval(arg->typecast.item, val);
1937 if (!ret)
1938 break;
1939 *val = eval_type(*val, arg, 0);
1940 break;
1941 case PRINT_OP:
1942 switch (arg->op.op[0]) {
1943 case '|':
1944 ret = arg_num_eval(arg->op.left, &left);
1945 if (!ret)
1946 break;
1947 ret = arg_num_eval(arg->op.right, &right);
1948 if (!ret)
1949 break;
1950 if (arg->op.op[1])
1951 *val = left || right;
1952 else
1953 *val = left | right;
1954 break;
1955 case '&':
1956 ret = arg_num_eval(arg->op.left, &left);
1957 if (!ret)
1958 break;
1959 ret = arg_num_eval(arg->op.right, &right);
1960 if (!ret)
1961 break;
1962 if (arg->op.op[1])
1963 *val = left && right;
1964 else
1965 *val = left & right;
1966 break;
1967 case '<':
1968 ret = arg_num_eval(arg->op.left, &left);
1969 if (!ret)
1970 break;
1971 ret = arg_num_eval(arg->op.right, &right);
1972 if (!ret)
1973 break;
1974 switch (arg->op.op[1]) {
1975 case 0:
1976 *val = left < right;
1977 break;
1978 case '<':
1979 *val = left << right;
1980 break;
1981 case '=':
1982 *val = left <= right;
1983 break;
1984 default:
1985 do_warning("unknown op '%s'", arg->op.op);
1986 ret = 0;
1987 }
1988 break;
1989 case '>':
1990 ret = arg_num_eval(arg->op.left, &left);
1991 if (!ret)
1992 break;
1993 ret = arg_num_eval(arg->op.right, &right);
1994 if (!ret)
1995 break;
1996 switch (arg->op.op[1]) {
1997 case 0:
1998 *val = left > right;
1999 break;
2000 case '>':
2001 *val = left >> right;
2002 break;
2003 case '=':
2004 *val = left >= right;
2005 break;
2006 default:
2007 do_warning("unknown op '%s'", arg->op.op);
2008 ret = 0;
2009 }
2010 break;
2011 case '=':
2012 ret = arg_num_eval(arg->op.left, &left);
2013 if (!ret)
2014 break;
2015 ret = arg_num_eval(arg->op.right, &right);
2016 if (!ret)
2017 break;
2018
2019 if (arg->op.op[1] != '=') {
2020 do_warning("unknown op '%s'", arg->op.op);
2021 ret = 0;
2022 } else
2023 *val = left == right;
2024 break;
2025 case '!':
2026 ret = arg_num_eval(arg->op.left, &left);
2027 if (!ret)
2028 break;
2029 ret = arg_num_eval(arg->op.right, &right);
2030 if (!ret)
2031 break;
2032
2033 switch (arg->op.op[1]) {
2034 case '=':
2035 *val = left != right;
2036 break;
2037 default:
2038 do_warning("unknown op '%s'", arg->op.op);
2039 ret = 0;
2040 }
2041 break;
2042 case '-':
2043 /* check for negative */
2044 if (arg->op.left->type == PRINT_NULL)
2045 left = 0;
2046 else
2047 ret = arg_num_eval(arg->op.left, &left);
2048 if (!ret)
2049 break;
2050 ret = arg_num_eval(arg->op.right, &right);
2051 if (!ret)
2052 break;
2053 *val = left - right;
2054 break;
2055 case '+':
2056 if (arg->op.left->type == PRINT_NULL)
2057 left = 0;
2058 else
2059 ret = arg_num_eval(arg->op.left, &left);
2060 if (!ret)
2061 break;
2062 ret = arg_num_eval(arg->op.right, &right);
2063 if (!ret)
2064 break;
2065 *val = left + right;
2066 break;
2067 default:
2068 do_warning("unknown op '%s'", arg->op.op);
2069 ret = 0;
2070 }
2071 break;
2072
2073 case PRINT_NULL:
2074 case PRINT_FIELD ... PRINT_SYMBOL:
2075 case PRINT_STRING:
2076 case PRINT_BSTRING:
2077 default:
2078 do_warning("invalid eval type %d", arg->type);
2079 ret = 0;
2080
2081 }
2082 return ret;
2083}
2084
2085static char *arg_eval (struct print_arg *arg)
2086{
2087 long long val;
2088 static char buf[20];
2089
2090 switch (arg->type) {
2091 case PRINT_ATOM:
2092 return arg->atom.atom;
2093 case PRINT_TYPE:
2094 return arg_eval(arg->typecast.item);
2095 case PRINT_OP:
2096 if (!arg_num_eval(arg, &val))
2097 break;
2098 sprintf(buf, "%lld", val);
2099 return buf;
2100
2101 case PRINT_NULL:
2102 case PRINT_FIELD ... PRINT_SYMBOL:
2103 case PRINT_STRING:
2104 case PRINT_BSTRING:
2105 default:
2106 die("invalid eval type %d", arg->type);
2107 break;
2108 }
2109
2110 return NULL;
2111}
2112
2113static enum event_type
2114process_fields(struct event_format *event, struct print_flag_sym **list, char **tok)
2115{
2116 enum event_type type;
2117 struct print_arg *arg = NULL;
2118 struct print_flag_sym *field;
2119 char *token = *tok;
2120 char *value;
2121
2122 do {
2123 free_token(token);
2124 type = read_token_item(&token);
2125 if (test_type_token(type, token, EVENT_OP, "{"))
2126 break;
2127
2128 arg = alloc_arg();
2129
2130 free_token(token);
2131 type = process_arg(event, arg, &token);
2132
2133 if (type == EVENT_OP)
2134 type = process_op(event, arg, &token);
2135
2136 if (type == EVENT_ERROR)
2137 goto out_free;
2138
2139 if (test_type_token(type, token, EVENT_DELIM, ","))
2140 goto out_free;
2141
2142 field = malloc_or_die(sizeof(*field));
2143 memset(field, 0, sizeof(*field));
2144
2145 value = arg_eval(arg);
2146 if (value == NULL)
2147 goto out_free;
2148 field->value = strdup(value);
2149
2150 free_arg(arg);
2151 arg = alloc_arg();
2152
2153 free_token(token);
2154 type = process_arg(event, arg, &token);
2155 if (test_type_token(type, token, EVENT_OP, "}"))
2156 goto out_free;
2157
2158 value = arg_eval(arg);
2159 if (value == NULL)
2160 goto out_free;
2161 field->str = strdup(value);
2162 free_arg(arg);
2163 arg = NULL;
2164
2165 *list = field;
2166 list = &field->next;
2167
2168 free_token(token);
2169 type = read_token_item(&token);
2170 } while (type == EVENT_DELIM && strcmp(token, ",") == 0);
2171
2172 *tok = token;
2173 return type;
2174
2175out_free:
2176 free_arg(arg);
2177 free_token(token);
2178 *tok = NULL;
2179
2180 return EVENT_ERROR;
2181}
2182
2183static enum event_type
2184process_flags(struct event_format *event, struct print_arg *arg, char **tok)
2185{
2186 struct print_arg *field;
2187 enum event_type type;
2188 char *token;
2189
2190 memset(arg, 0, sizeof(*arg));
2191 arg->type = PRINT_FLAGS;
2192
2193 field = alloc_arg();
2194
2195 type = process_arg(event, field, &token);
2196
2197 /* Handle operations in the first argument */
2198 while (type == EVENT_OP)
2199 type = process_op(event, field, &token);
2200
2201 if (test_type_token(type, token, EVENT_DELIM, ","))
2202 goto out_free;
2203 free_token(token);
2204
2205 arg->flags.field = field;
2206
2207 type = read_token_item(&token);
2208 if (event_item_type(type)) {
2209 arg->flags.delim = token;
2210 type = read_token_item(&token);
2211 }
2212
2213 if (test_type_token(type, token, EVENT_DELIM, ","))
2214 goto out_free;
2215
2216 type = process_fields(event, &arg->flags.flags, &token);
2217 if (test_type_token(type, token, EVENT_DELIM, ")"))
2218 goto out_free;
2219
2220 free_token(token);
2221 type = read_token_item(tok);
2222 return type;
2223
2224 out_free:
2225 free_token(token);
2226 *tok = NULL;
2227 return EVENT_ERROR;
2228}
2229
2230static enum event_type
2231process_symbols(struct event_format *event, struct print_arg *arg, char **tok)
2232{
2233 struct print_arg *field;
2234 enum event_type type;
2235 char *token;
2236
2237 memset(arg, 0, sizeof(*arg));
2238 arg->type = PRINT_SYMBOL;
2239
2240 field = alloc_arg();
2241
2242 type = process_arg(event, field, &token);
2243 if (test_type_token(type, token, EVENT_DELIM, ","))
2244 goto out_free;
2245
2246 arg->symbol.field = field;
2247
2248 type = process_fields(event, &arg->symbol.symbols, &token);
2249 if (test_type_token(type, token, EVENT_DELIM, ")"))
2250 goto out_free;
2251
2252 free_token(token);
2253 type = read_token_item(tok);
2254 return type;
2255
2256 out_free:
2257 free_token(token);
2258 *tok = NULL;
2259 return EVENT_ERROR;
2260}
2261
2262static enum event_type
2263process_dynamic_array(struct event_format *event, struct print_arg *arg, char **tok)
2264{
2265 struct format_field *field;
2266 enum event_type type;
2267 char *token;
2268
2269 memset(arg, 0, sizeof(*arg));
2270 arg->type = PRINT_DYNAMIC_ARRAY;
2271
2272 /*
2273 * The item within the parenthesis is another field that holds
2274 * the index into where the array starts.
2275 */
2276 type = read_token(&token);
2277 *tok = token;
2278 if (type != EVENT_ITEM)
2279 goto out_free;
2280
2281 /* Find the field */
2282
2283 field = pevent_find_field(event, token);
2284 if (!field)
2285 goto out_free;
2286
2287 arg->dynarray.field = field;
2288 arg->dynarray.index = 0;
2289
2290 if (read_expected(EVENT_DELIM, ")") < 0)
2291 goto out_free;
2292
2293 free_token(token);
2294 type = read_token_item(&token);
2295 *tok = token;
2296 if (type != EVENT_OP || strcmp(token, "[") != 0)
2297 return type;
2298
2299 free_token(token);
2300 arg = alloc_arg();
2301 type = process_arg(event, arg, &token);
2302 if (type == EVENT_ERROR)
2303 goto out_free_arg;
2304
2305 if (!test_type_token(type, token, EVENT_OP, "]"))
2306 goto out_free_arg;
2307
2308 free_token(token);
2309 type = read_token_item(tok);
2310 return type;
2311
2312 out_free_arg:
2313 free_arg(arg);
2314 out_free:
2315 free_token(token);
2316 *tok = NULL;
2317 return EVENT_ERROR;
2318}
2319
2320static enum event_type
2321process_paren(struct event_format *event, struct print_arg *arg, char **tok)
2322{
2323 struct print_arg *item_arg;
2324 enum event_type type;
2325 char *token;
2326
2327 type = process_arg(event, arg, &token);
2328
2329 if (type == EVENT_ERROR)
2330 goto out_free;
2331
2332 if (type == EVENT_OP)
2333 type = process_op(event, arg, &token);
2334
2335 if (type == EVENT_ERROR)
2336 goto out_free;
2337
2338 if (test_type_token(type, token, EVENT_DELIM, ")"))
2339 goto out_free;
2340
2341 free_token(token);
2342 type = read_token_item(&token);
2343
2344 /*
2345 * If the next token is an item or another open paren, then
2346 * this was a typecast.
2347 */
2348 if (event_item_type(type) ||
2349 (type == EVENT_DELIM && strcmp(token, "(") == 0)) {
2350
2351 /* make this a typecast and contine */
2352
2353 /* prevous must be an atom */
2354 if (arg->type != PRINT_ATOM)
2355 die("previous needed to be PRINT_ATOM");
2356
2357 item_arg = alloc_arg();
2358
2359 arg->type = PRINT_TYPE;
2360 arg->typecast.type = arg->atom.atom;
2361 arg->typecast.item = item_arg;
2362 type = process_arg_token(event, item_arg, &token, type);
2363
2364 }
2365
2366 *tok = token;
2367 return type;
2368
2369 out_free:
2370 free_token(token);
2371 *tok = NULL;
2372 return EVENT_ERROR;
2373}
2374
2375
2376static enum event_type
2377process_str(struct event_format *event __unused, struct print_arg *arg, char **tok)
2378{
2379 enum event_type type;
2380 char *token;
2381
2382 if (read_expect_type(EVENT_ITEM, &token) < 0)
2383 goto out_free;
2384
2385 arg->type = PRINT_STRING;
2386 arg->string.string = token;
2387 arg->string.offset = -1;
2388
2389 if (read_expected(EVENT_DELIM, ")") < 0)
2390 goto out_err;
2391
2392 type = read_token(&token);
2393 *tok = token;
2394
2395 return type;
2396
2397 out_free:
2398 free_token(token);
2399 out_err:
2400 *tok = NULL;
2401 return EVENT_ERROR;
2402}
2403
2404static struct pevent_function_handler *
2405find_func_handler(struct pevent *pevent, char *func_name)
2406{
2407 struct pevent_function_handler *func;
2408
2409 for (func = pevent->func_handlers; func; func = func->next) {
2410 if (strcmp(func->name, func_name) == 0)
2411 break;
2412 }
2413
2414 return func;
2415}
2416
2417static void remove_func_handler(struct pevent *pevent, char *func_name)
2418{
2419 struct pevent_function_handler *func;
2420 struct pevent_function_handler **next;
2421
2422 next = &pevent->func_handlers;
2423 while ((func = *next)) {
2424 if (strcmp(func->name, func_name) == 0) {
2425 *next = func->next;
2426 free_func_handle(func);
2427 break;
2428 }
2429 next = &func->next;
2430 }
2431}
2432
2433static enum event_type
2434process_func_handler(struct event_format *event, struct pevent_function_handler *func,
2435 struct print_arg *arg, char **tok)
2436{
2437 struct print_arg **next_arg;
2438 struct print_arg *farg;
2439 enum event_type type;
2440 char *token;
2441 char *test;
2442 int i;
2443
2444 arg->type = PRINT_FUNC;
2445 arg->func.func = func;
2446
2447 *tok = NULL;
2448
2449 next_arg = &(arg->func.args);
2450 for (i = 0; i < func->nr_args; i++) {
2451 farg = alloc_arg();
2452 type = process_arg(event, farg, &token);
2453 if (i < (func->nr_args - 1))
2454 test = ",";
2455 else
2456 test = ")";
2457
2458 if (test_type_token(type, token, EVENT_DELIM, test)) {
2459 free_arg(farg);
2460 free_token(token);
2461 return EVENT_ERROR;
2462 }
2463
2464 *next_arg = farg;
2465 next_arg = &(farg->next);
2466 free_token(token);
2467 }
2468
2469 type = read_token(&token);
2470 *tok = token;
2471
2472 return type;
2473}
2474
2475static enum event_type
2476process_function(struct event_format *event, struct print_arg *arg,
2477 char *token, char **tok)
2478{
2479 struct pevent_function_handler *func;
2480
2481 if (strcmp(token, "__print_flags") == 0) {
2482 free_token(token);
2483 is_flag_field = 1;
2484 return process_flags(event, arg, tok);
2485 }
2486 if (strcmp(token, "__print_symbolic") == 0) {
2487 free_token(token);
2488 is_symbolic_field = 1;
2489 return process_symbols(event, arg, tok);
2490 }
2491 if (strcmp(token, "__get_str") == 0) {
2492 free_token(token);
2493 return process_str(event, arg, tok);
2494 }
2495 if (strcmp(token, "__get_dynamic_array") == 0) {
2496 free_token(token);
2497 return process_dynamic_array(event, arg, tok);
2498 }
2499
2500 func = find_func_handler(event->pevent, token);
2501 if (func) {
2502 free_token(token);
2503 return process_func_handler(event, func, arg, tok);
2504 }
2505
2506 do_warning("function %s not defined", token);
2507 free_token(token);
2508 return EVENT_ERROR;
2509}
2510
2511static enum event_type
2512process_arg_token(struct event_format *event, struct print_arg *arg,
2513 char **tok, enum event_type type)
2514{
2515 char *token;
2516 char *atom;
2517
2518 token = *tok;
2519
2520 switch (type) {
2521 case EVENT_ITEM:
2522 if (strcmp(token, "REC") == 0) {
2523 free_token(token);
2524 type = process_entry(event, arg, &token);
2525 break;
2526 }
2527 atom = token;
2528 /* test the next token */
2529 type = read_token_item(&token);
2530
2531 /*
2532 * If the next token is a parenthesis, then this
2533 * is a function.
2534 */
2535 if (type == EVENT_DELIM && strcmp(token, "(") == 0) {
2536 free_token(token);
2537 token = NULL;
2538 /* this will free atom. */
2539 type = process_function(event, arg, atom, &token);
2540 break;
2541 }
2542 /* atoms can be more than one token long */
2543 while (type == EVENT_ITEM) {
2544 atom = realloc(atom, strlen(atom) + strlen(token) + 2);
2545 strcat(atom, " ");
2546 strcat(atom, token);
2547 free_token(token);
2548 type = read_token_item(&token);
2549 }
2550
2551 arg->type = PRINT_ATOM;
2552 arg->atom.atom = atom;
2553 break;
2554
2555 case EVENT_DQUOTE:
2556 case EVENT_SQUOTE:
2557 arg->type = PRINT_ATOM;
2558 arg->atom.atom = token;
2559 type = read_token_item(&token);
2560 break;
2561 case EVENT_DELIM:
2562 if (strcmp(token, "(") == 0) {
2563 free_token(token);
2564 type = process_paren(event, arg, &token);
2565 break;
2566 }
2567 case EVENT_OP:
2568 /* handle single ops */
2569 arg->type = PRINT_OP;
2570 arg->op.op = token;
2571 arg->op.left = NULL;
2572 type = process_op(event, arg, &token);
2573
2574 /* On error, the op is freed */
2575 if (type == EVENT_ERROR)
2576 arg->op.op = NULL;
2577
2578 /* return error type if errored */
2579 break;
2580
2581 case EVENT_ERROR ... EVENT_NEWLINE:
2582 default:
2583 die("unexpected type %d", type);
2584 }
2585 *tok = token;
2586
2587 return type;
2588}
2589
2590static int event_read_print_args(struct event_format *event, struct print_arg **list)
2591{
2592 enum event_type type = EVENT_ERROR;
2593 struct print_arg *arg;
2594 char *token;
2595 int args = 0;
2596
2597 do {
2598 if (type == EVENT_NEWLINE) {
2599 type = read_token_item(&token);
2600 continue;
2601 }
2602
2603 arg = alloc_arg();
2604
2605 type = process_arg(event, arg, &token);
2606
2607 if (type == EVENT_ERROR) {
2608 free_token(token);
2609 free_arg(arg);
2610 return -1;
2611 }
2612
2613 *list = arg;
2614 args++;
2615
2616 if (type == EVENT_OP) {
2617 type = process_op(event, arg, &token);
2618 free_token(token);
2619 if (type == EVENT_ERROR) {
2620 *list = NULL;
2621 free_arg(arg);
2622 return -1;
2623 }
2624 list = &arg->next;
2625 continue;
2626 }
2627
2628 if (type == EVENT_DELIM && strcmp(token, ",") == 0) {
2629 free_token(token);
2630 *list = arg;
2631 list = &arg->next;
2632 continue;
2633 }
2634 break;
2635 } while (type != EVENT_NONE);
2636
2637 if (type != EVENT_NONE && type != EVENT_ERROR)
2638 free_token(token);
2639
2640 return args;
2641}
2642
2643static int event_read_print(struct event_format *event)
2644{
2645 enum event_type type;
2646 char *token;
2647 int ret;
2648
2649 if (read_expected_item(EVENT_ITEM, "print") < 0)
2650 return -1;
2651
2652 if (read_expected(EVENT_ITEM, "fmt") < 0)
2653 return -1;
2654
2655 if (read_expected(EVENT_OP, ":") < 0)
2656 return -1;
2657
2658 if (read_expect_type(EVENT_DQUOTE, &token) < 0)
2659 goto fail;
2660
2661 concat:
2662 event->print_fmt.format = token;
2663 event->print_fmt.args = NULL;
2664
2665 /* ok to have no arg */
2666 type = read_token_item(&token);
2667
2668 if (type == EVENT_NONE)
2669 return 0;
2670
2671 /* Handle concatenation of print lines */
2672 if (type == EVENT_DQUOTE) {
2673 char *cat;
2674
2675 cat = malloc_or_die(strlen(event->print_fmt.format) +
2676 strlen(token) + 1);
2677 strcpy(cat, event->print_fmt.format);
2678 strcat(cat, token);
2679 free_token(token);
2680 free_token(event->print_fmt.format);
2681 event->print_fmt.format = NULL;
2682 token = cat;
2683 goto concat;
2684 }
2685
2686 if (test_type_token(type, token, EVENT_DELIM, ","))
2687 goto fail;
2688
2689 free_token(token);
2690
2691 ret = event_read_print_args(event, &event->print_fmt.args);
2692 if (ret < 0)
2693 return -1;
2694
2695 return ret;
2696
2697 fail:
2698 free_token(token);
2699 return -1;
2700}
2701
2702/**
2703 * pevent_find_common_field - return a common field by event
2704 * @event: handle for the event
2705 * @name: the name of the common field to return
2706 *
2707 * Returns a common field from the event by the given @name.
2708 * This only searchs the common fields and not all field.
2709 */
2710struct format_field *
2711pevent_find_common_field(struct event_format *event, const char *name)
2712{
2713 struct format_field *format;
2714
2715 for (format = event->format.common_fields;
2716 format; format = format->next) {
2717 if (strcmp(format->name, name) == 0)
2718 break;
2719 }
2720
2721 return format;
2722}
2723
2724/**
2725 * pevent_find_field - find a non-common field
2726 * @event: handle for the event
2727 * @name: the name of the non-common field
2728 *
2729 * Returns a non-common field by the given @name.
2730 * This does not search common fields.
2731 */
2732struct format_field *
2733pevent_find_field(struct event_format *event, const char *name)
2734{
2735 struct format_field *format;
2736
2737 for (format = event->format.fields;
2738 format; format = format->next) {
2739 if (strcmp(format->name, name) == 0)
2740 break;
2741 }
2742
2743 return format;
2744}
2745
2746/**
2747 * pevent_find_any_field - find any field by name
2748 * @event: handle for the event
2749 * @name: the name of the field
2750 *
2751 * Returns a field by the given @name.
2752 * This searchs the common field names first, then
2753 * the non-common ones if a common one was not found.
2754 */
2755struct format_field *
2756pevent_find_any_field(struct event_format *event, const char *name)
2757{
2758 struct format_field *format;
2759
2760 format = pevent_find_common_field(event, name);
2761 if (format)
2762 return format;
2763 return pevent_find_field(event, name);
2764}
2765
2766/**
2767 * pevent_read_number - read a number from data
2768 * @pevent: handle for the pevent
2769 * @ptr: the raw data
2770 * @size: the size of the data that holds the number
2771 *
2772 * Returns the number (converted to host) from the
2773 * raw data.
2774 */
2775unsigned long long pevent_read_number(struct pevent *pevent,
2776 const void *ptr, int size)
2777{
2778 switch (size) {
2779 case 1:
2780 return *(unsigned char *)ptr;
2781 case 2:
2782 return data2host2(pevent, ptr);
2783 case 4:
2784 return data2host4(pevent, ptr);
2785 case 8:
2786 return data2host8(pevent, ptr);
2787 default:
2788 /* BUG! */
2789 return 0;
2790 }
2791}
2792
2793/**
2794 * pevent_read_number_field - read a number from data
2795 * @field: a handle to the field
2796 * @data: the raw data to read
2797 * @value: the value to place the number in
2798 *
2799 * Reads raw data according to a field offset and size,
2800 * and translates it into @value.
2801 *
2802 * Returns 0 on success, -1 otherwise.
2803 */
2804int pevent_read_number_field(struct format_field *field, const void *data,
2805 unsigned long long *value)
2806{
2807 if (!field)
2808 return -1;
2809 switch (field->size) {
2810 case 1:
2811 case 2:
2812 case 4:
2813 case 8:
2814 *value = pevent_read_number(field->event->pevent,
2815 data + field->offset, field->size);
2816 return 0;
2817 default:
2818 return -1;
2819 }
2820}
2821
2822static int get_common_info(struct pevent *pevent,
2823 const char *type, int *offset, int *size)
2824{
2825 struct event_format *event;
2826 struct format_field *field;
2827
2828 /*
2829 * All events should have the same common elements.
2830 * Pick any event to find where the type is;
2831 */
2832 if (!pevent->events)
2833 die("no event_list!");
2834
2835 event = pevent->events[0];
2836 field = pevent_find_common_field(event, type);
2837 if (!field)
2838 die("field '%s' not found", type);
2839
2840 *offset = field->offset;
2841 *size = field->size;
2842
2843 return 0;
2844}
2845
2846static int __parse_common(struct pevent *pevent, void *data,
2847 int *size, int *offset, const char *name)
2848{
2849 int ret;
2850
2851 if (!*size) {
2852 ret = get_common_info(pevent, name, offset, size);
2853 if (ret < 0)
2854 return ret;
2855 }
2856 return pevent_read_number(pevent, data + *offset, *size);
2857}
2858
2859static int trace_parse_common_type(struct pevent *pevent, void *data)
2860{
2861 return __parse_common(pevent, data,
2862 &pevent->type_size, &pevent->type_offset,
2863 "common_type");
2864}
2865
2866static int parse_common_pid(struct pevent *pevent, void *data)
2867{
2868 return __parse_common(pevent, data,
2869 &pevent->pid_size, &pevent->pid_offset,
2870 "common_pid");
2871}
2872
2873static int parse_common_pc(struct pevent *pevent, void *data)
2874{
2875 return __parse_common(pevent, data,
2876 &pevent->pc_size, &pevent->pc_offset,
2877 "common_preempt_count");
2878}
2879
2880static int parse_common_flags(struct pevent *pevent, void *data)
2881{
2882 return __parse_common(pevent, data,
2883 &pevent->flags_size, &pevent->flags_offset,
2884 "common_flags");
2885}
2886
2887static int parse_common_lock_depth(struct pevent *pevent, void *data)
2888{
2889 int ret;
2890
2891 ret = __parse_common(pevent, data,
2892 &pevent->ld_size, &pevent->ld_offset,
2893 "common_lock_depth");
2894 if (ret < 0)
2895 return -1;
2896
2897 return ret;
2898}
2899
2900static int events_id_cmp(const void *a, const void *b);
2901
2902/**
2903 * pevent_find_event - find an event by given id
2904 * @pevent: a handle to the pevent
2905 * @id: the id of the event
2906 *
2907 * Returns an event that has a given @id.
2908 */
2909struct event_format *pevent_find_event(struct pevent *pevent, int id)
2910{
2911 struct event_format **eventptr;
2912 struct event_format key;
2913 struct event_format *pkey = &key;
2914
2915 /* Check cache first */
2916 if (pevent->last_event && pevent->last_event->id == id)
2917 return pevent->last_event;
2918
2919 key.id = id;
2920
2921 eventptr = bsearch(&pkey, pevent->events, pevent->nr_events,
2922 sizeof(*pevent->events), events_id_cmp);
2923
2924 if (eventptr) {
2925 pevent->last_event = *eventptr;
2926 return *eventptr;
2927 }
2928
2929 return NULL;
2930}
2931
2932/**
2933 * pevent_find_event_by_name - find an event by given name
2934 * @pevent: a handle to the pevent
2935 * @sys: the system name to search for
2936 * @name: the name of the event to search for
2937 *
2938 * This returns an event with a given @name and under the system
2939 * @sys. If @sys is NULL the first event with @name is returned.
2940 */
2941struct event_format *
2942pevent_find_event_by_name(struct pevent *pevent,
2943 const char *sys, const char *name)
2944{
2945 struct event_format *event;
2946 int i;
2947
2948 if (pevent->last_event &&
2949 strcmp(pevent->last_event->name, name) == 0 &&
2950 (!sys || strcmp(pevent->last_event->system, sys) == 0))
2951 return pevent->last_event;
2952
2953 for (i = 0; i < pevent->nr_events; i++) {
2954 event = pevent->events[i];
2955 if (strcmp(event->name, name) == 0) {
2956 if (!sys)
2957 break;
2958 if (strcmp(event->system, sys) == 0)
2959 break;
2960 }
2961 }
2962 if (i == pevent->nr_events)
2963 event = NULL;
2964
2965 pevent->last_event = event;
2966 return event;
2967}
2968
2969static unsigned long long
2970eval_num_arg(void *data, int size, struct event_format *event, struct print_arg *arg)
2971{
2972 struct pevent *pevent = event->pevent;
2973 unsigned long long val = 0;
2974 unsigned long long left, right;
2975 struct print_arg *typearg = NULL;
2976 struct print_arg *larg;
2977 unsigned long offset;
2978 unsigned int field_size;
2979
2980 switch (arg->type) {
2981 case PRINT_NULL:
2982 /* ?? */
2983 return 0;
2984 case PRINT_ATOM:
2985 return strtoull(arg->atom.atom, NULL, 0);
2986 case PRINT_FIELD:
2987 if (!arg->field.field) {
2988 arg->field.field = pevent_find_any_field(event, arg->field.name);
2989 if (!arg->field.field)
2990 die("field %s not found", arg->field.name);
2991 }
2992 /* must be a number */
2993 val = pevent_read_number(pevent, data + arg->field.field->offset,
2994 arg->field.field->size);
2995 break;
2996 case PRINT_FLAGS:
2997 case PRINT_SYMBOL:
2998 break;
2999 case PRINT_TYPE:
3000 val = eval_num_arg(data, size, event, arg->typecast.item);
3001 return eval_type(val, arg, 0);
3002 case PRINT_STRING:
3003 case PRINT_BSTRING:
3004 return 0;
3005 case PRINT_FUNC: {
3006 struct trace_seq s;
3007 trace_seq_init(&s);
3008 val = process_defined_func(&s, data, size, event, arg);
3009 trace_seq_destroy(&s);
3010 return val;
3011 }
3012 case PRINT_OP:
3013 if (strcmp(arg->op.op, "[") == 0) {
3014 /*
3015 * Arrays are special, since we don't want
3016 * to read the arg as is.
3017 */
3018 right = eval_num_arg(data, size, event, arg->op.right);
3019
3020 /* handle typecasts */
3021 larg = arg->op.left;
3022 while (larg->type == PRINT_TYPE) {
3023 if (!typearg)
3024 typearg = larg;
3025 larg = larg->typecast.item;
3026 }
3027
3028 /* Default to long size */
3029 field_size = pevent->long_size;
3030
3031 switch (larg->type) {
3032 case PRINT_DYNAMIC_ARRAY:
3033 offset = pevent_read_number(pevent,
3034 data + larg->dynarray.field->offset,
3035 larg->dynarray.field->size);
3036 if (larg->dynarray.field->elementsize)
3037 field_size = larg->dynarray.field->elementsize;
3038 /*
3039 * The actual length of the dynamic array is stored
3040 * in the top half of the field, and the offset
3041 * is in the bottom half of the 32 bit field.
3042 */
3043 offset &= 0xffff;
3044 offset += right;
3045 break;
3046 case PRINT_FIELD:
3047 if (!larg->field.field) {
3048 larg->field.field =
3049 pevent_find_any_field(event, larg->field.name);
3050 if (!larg->field.field)
3051 die("field %s not found", larg->field.name);
3052 }
3053 field_size = larg->field.field->elementsize;
3054 offset = larg->field.field->offset +
3055 right * larg->field.field->elementsize;
3056 break;
3057 default:
3058 goto default_op; /* oops, all bets off */
3059 }
3060 val = pevent_read_number(pevent,
3061 data + offset, field_size);
3062 if (typearg)
3063 val = eval_type(val, typearg, 1);
3064 break;
3065 } else if (strcmp(arg->op.op, "?") == 0) {
3066 left = eval_num_arg(data, size, event, arg->op.left);
3067 arg = arg->op.right;
3068 if (left)
3069 val = eval_num_arg(data, size, event, arg->op.left);
3070 else
3071 val = eval_num_arg(data, size, event, arg->op.right);
3072 break;
3073 }
3074 default_op:
3075 left = eval_num_arg(data, size, event, arg->op.left);
3076 right = eval_num_arg(data, size, event, arg->op.right);
3077 switch (arg->op.op[0]) {
3078 case '!':
3079 switch (arg->op.op[1]) {
3080 case 0:
3081 val = !right;
3082 break;
3083 case '=':
3084 val = left != right;
3085 break;
3086 default:
3087 die("unknown op '%s'", arg->op.op);
3088 }
3089 break;
3090 case '~':
3091 val = ~right;
3092 break;
3093 case '|':
3094 if (arg->op.op[1])
3095 val = left || right;
3096 else
3097 val = left | right;
3098 break;
3099 case '&':
3100 if (arg->op.op[1])
3101 val = left && right;
3102 else
3103 val = left & right;
3104 break;
3105 case '<':
3106 switch (arg->op.op[1]) {
3107 case 0:
3108 val = left < right;
3109 break;
3110 case '<':
3111 val = left << right;
3112 break;
3113 case '=':
3114 val = left <= right;
3115 break;
3116 default:
3117 die("unknown op '%s'", arg->op.op);
3118 }
3119 break;
3120 case '>':
3121 switch (arg->op.op[1]) {
3122 case 0:
3123 val = left > right;
3124 break;
3125 case '>':
3126 val = left >> right;
3127 break;
3128 case '=':
3129 val = left >= right;
3130 break;
3131 default:
3132 die("unknown op '%s'", arg->op.op);
3133 }
3134 break;
3135 case '=':
3136 if (arg->op.op[1] != '=')
3137 die("unknown op '%s'", arg->op.op);
3138 val = left == right;
3139 break;
3140 case '-':
3141 val = left - right;
3142 break;
3143 case '+':
3144 val = left + right;
3145 break;
3146 case '/':
3147 val = left / right;
3148 break;
3149 case '*':
3150 val = left * right;
3151 break;
3152 default:
3153 die("unknown op '%s'", arg->op.op);
3154 }
3155 break;
3156 default: /* not sure what to do there */
3157 return 0;
3158 }
3159 return val;
3160}
3161
3162struct flag {
3163 const char *name;
3164 unsigned long long value;
3165};
3166
3167static const struct flag flags[] = {
3168 { "HI_SOFTIRQ", 0 },
3169 { "TIMER_SOFTIRQ", 1 },
3170 { "NET_TX_SOFTIRQ", 2 },
3171 { "NET_RX_SOFTIRQ", 3 },
3172 { "BLOCK_SOFTIRQ", 4 },
3173 { "BLOCK_IOPOLL_SOFTIRQ", 5 },
3174 { "TASKLET_SOFTIRQ", 6 },
3175 { "SCHED_SOFTIRQ", 7 },
3176 { "HRTIMER_SOFTIRQ", 8 },
3177 { "RCU_SOFTIRQ", 9 },
3178
3179 { "HRTIMER_NORESTART", 0 },
3180 { "HRTIMER_RESTART", 1 },
3181};
3182
3183static unsigned long long eval_flag(const char *flag)
3184{
3185 int i;
3186
3187 /*
3188 * Some flags in the format files do not get converted.
3189 * If the flag is not numeric, see if it is something that
3190 * we already know about.
3191 */
3192 if (isdigit(flag[0]))
3193 return strtoull(flag, NULL, 0);
3194
3195 for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++)
3196 if (strcmp(flags[i].name, flag) == 0)
3197 return flags[i].value;
3198
3199 return 0;
3200}
3201
3202static void print_str_to_seq(struct trace_seq *s, const char *format,
3203 int len_arg, const char *str)
3204{
3205 if (len_arg >= 0)
3206 trace_seq_printf(s, format, len_arg, str);
3207 else
3208 trace_seq_printf(s, format, str);
3209}
3210
3211static void print_str_arg(struct trace_seq *s, void *data, int size,
3212 struct event_format *event, const char *format,
3213 int len_arg, struct print_arg *arg)
3214{
3215 struct pevent *pevent = event->pevent;
3216 struct print_flag_sym *flag;
3217 unsigned long long val, fval;
3218 unsigned long addr;
3219 char *str;
3220 int print;
3221 int len;
3222
3223 switch (arg->type) {
3224 case PRINT_NULL:
3225 /* ?? */
3226 return;
3227 case PRINT_ATOM:
3228 print_str_to_seq(s, format, len_arg, arg->atom.atom);
3229 return;
3230 case PRINT_FIELD:
3231 if (!arg->field.field) {
3232 arg->field.field = pevent_find_any_field(event, arg->field.name);
3233 if (!arg->field.field)
3234 die("field %s not found", arg->field.name);
3235 }
3236 /* Zero sized fields, mean the rest of the data */
3237 len = arg->field.field->size ? : size - arg->field.field->offset;
3238
3239 /*
3240 * Some events pass in pointers. If this is not an array
3241 * and the size is the same as long_size, assume that it
3242 * is a pointer.
3243 */
3244 if (!(arg->field.field->flags & FIELD_IS_ARRAY) &&
3245 arg->field.field->size == pevent->long_size) {
3246 addr = *(unsigned long *)(data + arg->field.field->offset);
3247 trace_seq_printf(s, "%lx", addr);
3248 break;
3249 }
3250 str = malloc_or_die(len + 1);
3251 memcpy(str, data + arg->field.field->offset, len);
3252 str[len] = 0;
3253 print_str_to_seq(s, format, len_arg, str);
3254 free(str);
3255 break;
3256 case PRINT_FLAGS:
3257 val = eval_num_arg(data, size, event, arg->flags.field);
3258 print = 0;
3259 for (flag = arg->flags.flags; flag; flag = flag->next) {
3260 fval = eval_flag(flag->value);
3261 if (!val && !fval) {
3262 print_str_to_seq(s, format, len_arg, flag->str);
3263 break;
3264 }
3265 if (fval && (val & fval) == fval) {
3266 if (print && arg->flags.delim)
3267 trace_seq_puts(s, arg->flags.delim);
3268 print_str_to_seq(s, format, len_arg, flag->str);
3269 print = 1;
3270 val &= ~fval;
3271 }
3272 }
3273 break;
3274 case PRINT_SYMBOL:
3275 val = eval_num_arg(data, size, event, arg->symbol.field);
3276 for (flag = arg->symbol.symbols; flag; flag = flag->next) {
3277 fval = eval_flag(flag->value);
3278 if (val == fval) {
3279 print_str_to_seq(s, format, len_arg, flag->str);
3280 break;
3281 }
3282 }
3283 break;
3284
3285 case PRINT_TYPE:
3286 break;
3287 case PRINT_STRING: {
3288 int str_offset;
3289
3290 if (arg->string.offset == -1) {
3291 struct format_field *f;
3292
3293 f = pevent_find_any_field(event, arg->string.string);
3294 arg->string.offset = f->offset;
3295 }
3296 str_offset = data2host4(pevent, data + arg->string.offset);
3297 str_offset &= 0xffff;
3298 print_str_to_seq(s, format, len_arg, ((char *)data) + str_offset);
3299 break;
3300 }
3301 case PRINT_BSTRING:
3302 trace_seq_printf(s, format, arg->string.string);
3303 break;
3304 case PRINT_OP:
3305 /*
3306 * The only op for string should be ? :
3307 */
3308 if (arg->op.op[0] != '?')
3309 return;
3310 val = eval_num_arg(data, size, event, arg->op.left);
3311 if (val)
3312 print_str_arg(s, data, size, event,
3313 format, len_arg, arg->op.right->op.left);
3314 else
3315 print_str_arg(s, data, size, event,
3316 format, len_arg, arg->op.right->op.right);
3317 break;
3318 case PRINT_FUNC:
3319 process_defined_func(s, data, size, event, arg);
3320 break;
3321 default:
3322 /* well... */
3323 break;
3324 }
3325}
3326
3327static unsigned long long
3328process_defined_func(struct trace_seq *s, void *data, int size,
3329 struct event_format *event, struct print_arg *arg)
3330{
3331 struct pevent_function_handler *func_handle = arg->func.func;
3332 struct pevent_func_params *param;
3333 unsigned long long *args;
3334 unsigned long long ret;
3335 struct print_arg *farg;
3336 struct trace_seq str;
3337 struct save_str {
3338 struct save_str *next;
3339 char *str;
3340 } *strings = NULL, *string;
3341 int i;
3342
3343 if (!func_handle->nr_args) {
3344 ret = (*func_handle->func)(s, NULL);
3345 goto out;
3346 }
3347
3348 farg = arg->func.args;
3349 param = func_handle->params;
3350
3351 args = malloc_or_die(sizeof(*args) * func_handle->nr_args);
3352 for (i = 0; i < func_handle->nr_args; i++) {
3353 switch (param->type) {
3354 case PEVENT_FUNC_ARG_INT:
3355 case PEVENT_FUNC_ARG_LONG:
3356 case PEVENT_FUNC_ARG_PTR:
3357 args[i] = eval_num_arg(data, size, event, farg);
3358 break;
3359 case PEVENT_FUNC_ARG_STRING:
3360 trace_seq_init(&str);
3361 print_str_arg(&str, data, size, event, "%s", -1, farg);
3362 trace_seq_terminate(&str);
3363 string = malloc_or_die(sizeof(*string));
3364 string->next = strings;
3365 string->str = strdup(str.buffer);
3366 strings = string;
3367 trace_seq_destroy(&str);
3368 break;
3369 default:
3370 /*
3371 * Something went totally wrong, this is not
3372 * an input error, something in this code broke.
3373 */
3374 die("Unexpected end of arguments\n");
3375 break;
3376 }
3377 farg = farg->next;
3378 param = param->next;
3379 }
3380
3381 ret = (*func_handle->func)(s, args);
3382 free(args);
3383 while (strings) {
3384 string = strings;
3385 strings = string->next;
3386 free(string->str);
3387 free(string);
3388 }
3389
3390 out:
3391 /* TBD : handle return type here */
3392 return ret;
3393}
3394
3395static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event_format *event)
3396{
3397 struct pevent *pevent = event->pevent;
3398 struct format_field *field, *ip_field;
3399 struct print_arg *args, *arg, **next;
3400 unsigned long long ip, val;
3401 char *ptr;
3402 void *bptr;
3403
3404 field = pevent->bprint_buf_field;
3405 ip_field = pevent->bprint_ip_field;
3406
3407 if (!field) {
3408 field = pevent_find_field(event, "buf");
3409 if (!field)
3410 die("can't find buffer field for binary printk");
3411 ip_field = pevent_find_field(event, "ip");
3412 if (!ip_field)
3413 die("can't find ip field for binary printk");
3414 pevent->bprint_buf_field = field;
3415 pevent->bprint_ip_field = ip_field;
3416 }
3417
3418 ip = pevent_read_number(pevent, data + ip_field->offset, ip_field->size);
3419
3420 /*
3421 * The first arg is the IP pointer.
3422 */
3423 args = alloc_arg();
3424 arg = args;
3425 arg->next = NULL;
3426 next = &arg->next;
3427
3428 arg->type = PRINT_ATOM;
3429 arg->atom.atom = malloc_or_die(32);
3430 sprintf(arg->atom.atom, "%lld", ip);
3431
3432 /* skip the first "%pf : " */
3433 for (ptr = fmt + 6, bptr = data + field->offset;
3434 bptr < data + size && *ptr; ptr++) {
3435 int ls = 0;
3436
3437 if (*ptr == '%') {
3438 process_again:
3439 ptr++;
3440 switch (*ptr) {
3441 case '%':
3442 break;
3443 case 'l':
3444 ls++;
3445 goto process_again;
3446 case 'L':
3447 ls = 2;
3448 goto process_again;
3449 case '0' ... '9':
3450 goto process_again;
3451 case 'p':
3452 ls = 1;
3453 /* fall through */
3454 case 'd':
3455 case 'u':
3456 case 'x':
3457 case 'i':
3458 /* the pointers are always 4 bytes aligned */
3459 bptr = (void *)(((unsigned long)bptr + 3) &
3460 ~3);
3461 switch (ls) {
3462 case 0:
3463 ls = 4;
3464 break;
3465 case 1:
3466 ls = pevent->long_size;
3467 break;
3468 case 2:
3469 ls = 8;
3470 default:
3471 break;
3472 }
3473 val = pevent_read_number(pevent, bptr, ls);
3474 bptr += ls;
3475 arg = alloc_arg();
3476 arg->next = NULL;
3477 arg->type = PRINT_ATOM;
3478 arg->atom.atom = malloc_or_die(32);
3479 sprintf(arg->atom.atom, "%lld", val);
3480 *next = arg;
3481 next = &arg->next;
3482 break;
3483 case 's':
3484 arg = alloc_arg();
3485 arg->next = NULL;
3486 arg->type = PRINT_BSTRING;
3487 arg->string.string = strdup(bptr);
3488 bptr += strlen(bptr) + 1;
3489 *next = arg;
3490 next = &arg->next;
3491 default:
3492 break;
3493 }
3494 }
3495 }
3496
3497 return args;
3498}
3499
3500static void free_args(struct print_arg *args)
3501{
3502 struct print_arg *next;
3503
3504 while (args) {
3505 next = args->next;
3506
3507 free_arg(args);
3508 args = next;
3509 }
3510}
3511
3512static char *
3513get_bprint_format(void *data, int size __unused, struct event_format *event)
3514{
3515 struct pevent *pevent = event->pevent;
3516 unsigned long long addr;
3517 struct format_field *field;
3518 struct printk_map *printk;
3519 char *format;
3520 char *p;
3521
3522 field = pevent->bprint_fmt_field;
3523
3524 if (!field) {
3525 field = pevent_find_field(event, "fmt");
3526 if (!field)
3527 die("can't find format field for binary printk");
3528 pevent->bprint_fmt_field = field;
3529 }
3530
3531 addr = pevent_read_number(pevent, data + field->offset, field->size);
3532
3533 printk = find_printk(pevent, addr);
3534 if (!printk) {
3535 format = malloc_or_die(45);
3536 sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n",
3537 addr);
3538 return format;
3539 }
3540
3541 p = printk->printk;
3542 /* Remove any quotes. */
3543 if (*p == '"')
3544 p++;
3545 format = malloc_or_die(strlen(p) + 10);
3546 sprintf(format, "%s : %s", "%pf", p);
3547 /* remove ending quotes and new line since we will add one too */
3548 p = format + strlen(format) - 1;
3549 if (*p == '"')
3550 *p = 0;
3551
3552 p -= 2;
3553 if (strcmp(p, "\\n") == 0)
3554 *p = 0;
3555
3556 return format;
3557}
3558
3559static void print_mac_arg(struct trace_seq *s, int mac, void *data, int size,
3560 struct event_format *event, struct print_arg *arg)
3561{
3562 unsigned char *buf;
3563 char *fmt = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x";
3564
3565 if (arg->type == PRINT_FUNC) {
3566 process_defined_func(s, data, size, event, arg);
3567 return;
3568 }
3569
3570 if (arg->type != PRINT_FIELD) {
3571 trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d",
3572 arg->type);
3573 return;
3574 }
3575
3576 if (mac == 'm')
3577 fmt = "%.2x%.2x%.2x%.2x%.2x%.2x";
3578 if (!arg->field.field) {
3579 arg->field.field =
3580 pevent_find_any_field(event, arg->field.name);
3581 if (!arg->field.field)
3582 die("field %s not found", arg->field.name);
3583 }
3584 if (arg->field.field->size != 6) {
3585 trace_seq_printf(s, "INVALIDMAC");
3586 return;
3587 }
3588 buf = data + arg->field.field->offset;
3589 trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
3590}
3591
3592static void print_event_fields(struct trace_seq *s, void *data, int size,
3593 struct event_format *event)
3594{
3595 struct format_field *field;
3596 unsigned long long val;
3597 unsigned int offset, len, i;
3598
3599 field = event->format.fields;
3600 while (field) {
3601 trace_seq_printf(s, " %s=", field->name);
3602 if (field->flags & FIELD_IS_ARRAY) {
3603 offset = field->offset;
3604 len = field->size;
3605 if (field->flags & FIELD_IS_DYNAMIC) {
3606 val = pevent_read_number(event->pevent, data + offset, len);
3607 offset = val;
3608 len = offset >> 16;
3609 offset &= 0xffff;
3610 }
3611 if (field->flags & FIELD_IS_STRING) {
3612 trace_seq_printf(s, "%s", (char *)data + offset);
3613 } else {
3614 trace_seq_puts(s, "ARRAY[");
3615 for (i = 0; i < len; i++) {
3616 if (i)
3617 trace_seq_puts(s, ", ");
3618 trace_seq_printf(s, "%02x",
3619 *((unsigned char *)data + offset + i));
3620 }
3621 trace_seq_putc(s, ']');
3622 }
3623 } else {
3624 val = pevent_read_number(event->pevent, data + field->offset,
3625 field->size);
3626 if (field->flags & FIELD_IS_POINTER) {
3627 trace_seq_printf(s, "0x%llx", val);
3628 } else if (field->flags & FIELD_IS_SIGNED) {
3629 switch (field->size) {
3630 case 4:
3631 /*
3632 * If field is long then print it in hex.
3633 * A long usually stores pointers.
3634 */
3635 if (field->flags & FIELD_IS_LONG)
3636 trace_seq_printf(s, "0x%x", (int)val);
3637 else
3638 trace_seq_printf(s, "%d", (int)val);
3639 break;
3640 case 2:
3641 trace_seq_printf(s, "%2d", (short)val);
3642 break;
3643 case 1:
3644 trace_seq_printf(s, "%1d", (char)val);
3645 break;
3646 default:
3647 trace_seq_printf(s, "%lld", val);
3648 }
3649 } else {
3650 if (field->flags & FIELD_IS_LONG)
3651 trace_seq_printf(s, "0x%llx", val);
3652 else
3653 trace_seq_printf(s, "%llu", val);
3654 }
3655 }
3656 field = field->next;
3657 }
3658}
3659
3660static void pretty_print(struct trace_seq *s, void *data, int size, struct event_format *event)
3661{
3662 struct pevent *pevent = event->pevent;
3663 struct print_fmt *print_fmt = &event->print_fmt;
3664 struct print_arg *arg = print_fmt->args;
3665 struct print_arg *args = NULL;
3666 const char *ptr = print_fmt->format;
3667 unsigned long long val;
3668 struct func_map *func;
3669 const char *saveptr;
3670 char *bprint_fmt = NULL;
3671 char format[32];
3672 int show_func;
3673 int len_as_arg;
3674 int len_arg;
3675 int len;
3676 int ls;
3677
3678 if (event->flags & EVENT_FL_FAILED) {
3679 trace_seq_printf(s, "[FAILED TO PARSE]");
3680 print_event_fields(s, data, size, event);
3681 return;
3682 }
3683
3684 if (event->flags & EVENT_FL_ISBPRINT) {
3685 bprint_fmt = get_bprint_format(data, size, event);
3686 args = make_bprint_args(bprint_fmt, data, size, event);
3687 arg = args;
3688 ptr = bprint_fmt;
3689 }
3690
3691 for (; *ptr; ptr++) {
3692 ls = 0;
3693 if (*ptr == '\\') {
3694 ptr++;
3695 switch (*ptr) {
3696 case 'n':
3697 trace_seq_putc(s, '\n');
3698 break;
3699 case 't':
3700 trace_seq_putc(s, '\t');
3701 break;
3702 case 'r':
3703 trace_seq_putc(s, '\r');
3704 break;
3705 case '\\':
3706 trace_seq_putc(s, '\\');
3707 break;
3708 default:
3709 trace_seq_putc(s, *ptr);
3710 break;
3711 }
3712
3713 } else if (*ptr == '%') {
3714 saveptr = ptr;
3715 show_func = 0;
3716 len_as_arg = 0;
3717 cont_process:
3718 ptr++;
3719 switch (*ptr) {
3720 case '%':
3721 trace_seq_putc(s, '%');
3722 break;
3723 case '#':
3724 /* FIXME: need to handle properly */
3725 goto cont_process;
3726 case 'h':
3727 ls--;
3728 goto cont_process;
3729 case 'l':
3730 ls++;
3731 goto cont_process;
3732 case 'L':
3733 ls = 2;
3734 goto cont_process;
3735 case '*':
3736 /* The argument is the length. */
3737 if (!arg)
3738 die("no argument match");
3739 len_arg = eval_num_arg(data, size, event, arg);
3740 len_as_arg = 1;
3741 arg = arg->next;
3742 goto cont_process;
3743 case '.':
3744 case 'z':
3745 case 'Z':
3746 case '0' ... '9':
3747 goto cont_process;
3748 case 'p':
3749 if (pevent->long_size == 4)
3750 ls = 1;
3751 else
3752 ls = 2;
3753
3754 if (*(ptr+1) == 'F' ||
3755 *(ptr+1) == 'f') {
3756 ptr++;
3757 show_func = *ptr;
3758 } else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') {
3759 print_mac_arg(s, *(ptr+1), data, size, event, arg);
3760 ptr++;
3761 break;
3762 }
3763
3764 /* fall through */
3765 case 'd':
3766 case 'i':
3767 case 'x':
3768 case 'X':
3769 case 'u':
3770 if (!arg)
3771 die("no argument match");
3772
3773 len = ((unsigned long)ptr + 1) -
3774 (unsigned long)saveptr;
3775
3776 /* should never happen */
3777 if (len > 31)
3778 die("bad format!");
3779
3780 memcpy(format, saveptr, len);
3781 format[len] = 0;
3782
3783 val = eval_num_arg(data, size, event, arg);
3784 arg = arg->next;
3785
3786 if (show_func) {
3787 func = find_func(pevent, val);
3788 if (func) {
3789 trace_seq_puts(s, func->func);
3790 if (show_func == 'F')
3791 trace_seq_printf(s,
3792 "+0x%llx",
3793 val - func->addr);
3794 break;
3795 }
3796 }
3797 if (pevent->long_size == 8 && ls) {
3798 char *p;
3799
3800 ls = 2;
3801 /* make %l into %ll */
3802 p = strchr(format, 'l');
3803 if (p)
3804 memmove(p, p+1, strlen(p)+1);
3805 else if (strcmp(format, "%p") == 0)
3806 strcpy(format, "0x%llx");
3807 }
3808 switch (ls) {
3809 case -2:
3810 if (len_as_arg)
3811 trace_seq_printf(s, format, len_arg, (char)val);
3812 else
3813 trace_seq_printf(s, format, (char)val);
3814 break;
3815 case -1:
3816 if (len_as_arg)
3817 trace_seq_printf(s, format, len_arg, (short)val);
3818 else
3819 trace_seq_printf(s, format, (short)val);
3820 break;
3821 case 0:
3822 if (len_as_arg)
3823 trace_seq_printf(s, format, len_arg, (int)val);
3824 else
3825 trace_seq_printf(s, format, (int)val);
3826 break;
3827 case 1:
3828 if (len_as_arg)
3829 trace_seq_printf(s, format, len_arg, (long)val);
3830 else
3831 trace_seq_printf(s, format, (long)val);
3832 break;
3833 case 2:
3834 if (len_as_arg)
3835 trace_seq_printf(s, format, len_arg,
3836 (long long)val);
3837 else
3838 trace_seq_printf(s, format, (long long)val);
3839 break;
3840 default:
3841 die("bad count (%d)", ls);
3842 }
3843 break;
3844 case 's':
3845 if (!arg)
3846 die("no matching argument");
3847
3848 len = ((unsigned long)ptr + 1) -
3849 (unsigned long)saveptr;
3850
3851 /* should never happen */
3852 if (len > 31)
3853 die("bad format!");
3854
3855 memcpy(format, saveptr, len);
3856 format[len] = 0;
3857 if (!len_as_arg)
3858 len_arg = -1;
3859 print_str_arg(s, data, size, event,
3860 format, len_arg, arg);
3861 arg = arg->next;
3862 break;
3863 default:
3864 trace_seq_printf(s, ">%c<", *ptr);
3865
3866 }
3867 } else
3868 trace_seq_putc(s, *ptr);
3869 }
3870
3871 if (args) {
3872 free_args(args);
3873 free(bprint_fmt);
3874 }
3875}
3876
3877/**
3878 * pevent_data_lat_fmt - parse the data for the latency format
3879 * @pevent: a handle to the pevent
3880 * @s: the trace_seq to write to
3881 * @data: the raw data to read from
3882 * @size: currently unused.
3883 *
3884 * This parses out the Latency format (interrupts disabled,
3885 * need rescheduling, in hard/soft interrupt, preempt count
3886 * and lock depth) and places it into the trace_seq.
3887 */
3888void pevent_data_lat_fmt(struct pevent *pevent,
3889 struct trace_seq *s, struct pevent_record *record)
3890{
3891 static int check_lock_depth = 1;
3892 static int lock_depth_exists;
3893 unsigned int lat_flags;
3894 unsigned int pc;
3895 int lock_depth;
3896 int hardirq;
3897 int softirq;
3898 void *data = record->data;
3899
3900 lat_flags = parse_common_flags(pevent, data);
3901 pc = parse_common_pc(pevent, data);
3902 /* lock_depth may not always exist */
3903 if (check_lock_depth) {
3904 struct format_field *field;
3905 struct event_format *event;
3906
3907 check_lock_depth = 0;
3908 event = pevent->events[0];
3909 field = pevent_find_common_field(event, "common_lock_depth");
3910 if (field)
3911 lock_depth_exists = 1;
3912 }
3913 if (lock_depth_exists)
3914 lock_depth = parse_common_lock_depth(pevent, data);
3915
3916 hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
3917 softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
3918
3919 trace_seq_printf(s, "%c%c%c",
3920 (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
3921 (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
3922 'X' : '.',
3923 (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
3924 'N' : '.',
3925 (hardirq && softirq) ? 'H' :
3926 hardirq ? 'h' : softirq ? 's' : '.');
3927
3928 if (pc)
3929 trace_seq_printf(s, "%x", pc);
3930 else
3931 trace_seq_putc(s, '.');
3932
3933 if (lock_depth_exists) {
3934 if (lock_depth < 0)
3935 trace_seq_putc(s, '.');
3936 else
3937 trace_seq_printf(s, "%d", lock_depth);
3938 }
3939
3940 trace_seq_terminate(s);
3941}
3942
3943/**
3944 * pevent_data_type - parse out the given event type
3945 * @pevent: a handle to the pevent
3946 * @rec: the record to read from
3947 *
3948 * This returns the event id from the @rec.
3949 */
3950int pevent_data_type(struct pevent *pevent, struct pevent_record *rec)
3951{
3952 return trace_parse_common_type(pevent, rec->data);
3953}
3954
3955/**
3956 * pevent_data_event_from_type - find the event by a given type
3957 * @pevent: a handle to the pevent
3958 * @type: the type of the event.
3959 *
3960 * This returns the event form a given @type;
3961 */
3962struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type)
3963{
3964 return pevent_find_event(pevent, type);
3965}
3966
3967/**
3968 * pevent_data_pid - parse the PID from raw data
3969 * @pevent: a handle to the pevent
3970 * @rec: the record to parse
3971 *
3972 * This returns the PID from a raw data.
3973 */
3974int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec)
3975{
3976 return parse_common_pid(pevent, rec->data);
3977}
3978
3979/**
3980 * pevent_data_comm_from_pid - return the command line from PID
3981 * @pevent: a handle to the pevent
3982 * @pid: the PID of the task to search for
3983 *
3984 * This returns a pointer to the command line that has the given
3985 * @pid.
3986 */
3987const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid)
3988{
3989 const char *comm;
3990
3991 comm = find_cmdline(pevent, pid);
3992 return comm;
3993}
3994
3995/**
3996 * pevent_data_comm_from_pid - parse the data into the print format
3997 * @s: the trace_seq to write to
3998 * @event: the handle to the event
3999 * @cpu: the cpu the event was recorded on
4000 * @data: the raw data
4001 * @size: the size of the raw data
4002 * @nsecs: the timestamp of the event
4003 *
4004 * This parses the raw @data using the given @event information and
4005 * writes the print format into the trace_seq.
4006 */
4007void pevent_event_info(struct trace_seq *s, struct event_format *event,
4008 struct pevent_record *record)
4009{
4010 int print_pretty = 1;
4011
4012 if (event->pevent->print_raw)
4013 print_event_fields(s, record->data, record->size, event);
4014 else {
4015
4016 if (event->handler)
4017 print_pretty = event->handler(s, record, event,
4018 event->context);
4019
4020 if (print_pretty)
4021 pretty_print(s, record->data, record->size, event);
4022 }
4023
4024 trace_seq_terminate(s);
4025}
4026
4027void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
4028 struct pevent_record *record)
4029{
4030 static char *spaces = " "; /* 20 spaces */
4031 struct event_format *event;
4032 unsigned long secs;
4033 unsigned long usecs;
4034 unsigned long nsecs;
4035 const char *comm;
4036 void *data = record->data;
4037 int type;
4038 int pid;
4039 int len;
4040 int p;
4041
4042 secs = record->ts / NSECS_PER_SEC;
4043 nsecs = record->ts - secs * NSECS_PER_SEC;
4044
4045 if (record->size < 0) {
4046 do_warning("ug! negative record size %d", record->size);
4047 return;
4048 }
4049
4050 type = trace_parse_common_type(pevent, data);
4051
4052 event = pevent_find_event(pevent, type);
4053 if (!event) {
4054 do_warning("ug! no event found for type %d", type);
4055 return;
4056 }
4057
4058 pid = parse_common_pid(pevent, data);
4059 comm = find_cmdline(pevent, pid);
4060
4061 if (pevent->latency_format) {
4062 trace_seq_printf(s, "%8.8s-%-5d %3d",
4063 comm, pid, record->cpu);
4064 pevent_data_lat_fmt(pevent, s, record);
4065 } else
4066 trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu);
4067
4068 if (pevent->flags & PEVENT_NSEC_OUTPUT) {
4069 usecs = nsecs;
4070 p = 9;
4071 } else {
4072 usecs = (nsecs + 500) / NSECS_PER_USEC;
4073 p = 6;
4074 }
4075
4076 trace_seq_printf(s, " %5lu.%0*lu: %s: ", secs, p, usecs, event->name);
4077
4078 /* Space out the event names evenly. */
4079 len = strlen(event->name);
4080 if (len < 20)
4081 trace_seq_printf(s, "%.*s", 20 - len, spaces);
4082
4083 pevent_event_info(s, event, record);
4084}
4085
4086static int events_id_cmp(const void *a, const void *b)
4087{
4088 struct event_format * const * ea = a;
4089 struct event_format * const * eb = b;
4090
4091 if ((*ea)->id < (*eb)->id)
4092 return -1;
4093
4094 if ((*ea)->id > (*eb)->id)
4095 return 1;
4096
4097 return 0;
4098}
4099
4100static int events_name_cmp(const void *a, const void *b)
4101{
4102 struct event_format * const * ea = a;
4103 struct event_format * const * eb = b;
4104 int res;
4105
4106 res = strcmp((*ea)->name, (*eb)->name);
4107 if (res)
4108 return res;
4109
4110 res = strcmp((*ea)->system, (*eb)->system);
4111 if (res)
4112 return res;
4113
4114 return events_id_cmp(a, b);
4115}
4116
4117static int events_system_cmp(const void *a, const void *b)
4118{
4119 struct event_format * const * ea = a;
4120 struct event_format * const * eb = b;
4121 int res;
4122
4123 res = strcmp((*ea)->system, (*eb)->system);
4124 if (res)
4125 return res;
4126
4127 res = strcmp((*ea)->name, (*eb)->name);
4128 if (res)
4129 return res;
4130
4131 return events_id_cmp(a, b);
4132}
4133
4134struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type sort_type)
4135{
4136 struct event_format **events;
4137 int (*sort)(const void *a, const void *b);
4138
4139 events = pevent->sort_events;
4140
4141 if (events && pevent->last_type == sort_type)
4142 return events;
4143
4144 if (!events) {
4145 events = malloc(sizeof(*events) * (pevent->nr_events + 1));
4146 if (!events)
4147 return NULL;
4148
4149 memcpy(events, pevent->events, sizeof(*events) * pevent->nr_events);
4150 events[pevent->nr_events] = NULL;
4151
4152 pevent->sort_events = events;
4153
4154 /* the internal events are sorted by id */
4155 if (sort_type == EVENT_SORT_ID) {
4156 pevent->last_type = sort_type;
4157 return events;
4158 }
4159 }
4160
4161 switch (sort_type) {
4162 case EVENT_SORT_ID:
4163 sort = events_id_cmp;
4164 break;
4165 case EVENT_SORT_NAME:
4166 sort = events_name_cmp;
4167 break;
4168 case EVENT_SORT_SYSTEM:
4169 sort = events_system_cmp;
4170 break;
4171 default:
4172 return events;
4173 }
4174
4175 qsort(events, pevent->nr_events, sizeof(*events), sort);
4176 pevent->last_type = sort_type;
4177
4178 return events;
4179}
4180
4181static struct format_field **
4182get_event_fields(const char *type, const char *name,
4183 int count, struct format_field *list)
4184{
4185 struct format_field **fields;
4186 struct format_field *field;
4187 int i = 0;
4188
4189 fields = malloc_or_die(sizeof(*fields) * (count + 1));
4190 for (field = list; field; field = field->next) {
4191 fields[i++] = field;
4192 if (i == count + 1) {
4193 do_warning("event %s has more %s fields than specified",
4194 name, type);
4195 i--;
4196 break;
4197 }
4198 }
4199
4200 if (i != count)
4201 do_warning("event %s has less %s fields than specified",
4202 name, type);
4203
4204 fields[i] = NULL;
4205
4206 return fields;
4207}
4208
4209/**
4210 * pevent_event_common_fields - return a list of common fields for an event
4211 * @event: the event to return the common fields of.
4212 *
4213 * Returns an allocated array of fields. The last item in the array is NULL.
4214 * The array must be freed with free().
4215 */
4216struct format_field **pevent_event_common_fields(struct event_format *event)
4217{
4218 return get_event_fields("common", event->name,
4219 event->format.nr_common,
4220 event->format.common_fields);
4221}
4222
4223/**
4224 * pevent_event_fields - return a list of event specific fields for an event
4225 * @event: the event to return the fields of.
4226 *
4227 * Returns an allocated array of fields. The last item in the array is NULL.
4228 * The array must be freed with free().
4229 */
4230struct format_field **pevent_event_fields(struct event_format *event)
4231{
4232 return get_event_fields("event", event->name,
4233 event->format.nr_fields,
4234 event->format.fields);
4235}
4236
4237static void print_fields(struct trace_seq *s, struct print_flag_sym *field)
4238{
4239 trace_seq_printf(s, "{ %s, %s }", field->value, field->str);
4240 if (field->next) {
4241 trace_seq_puts(s, ", ");
4242 print_fields(s, field->next);
4243 }
4244}
4245
4246/* for debugging */
4247static void print_args(struct print_arg *args)
4248{
4249 int print_paren = 1;
4250 struct trace_seq s;
4251
4252 switch (args->type) {
4253 case PRINT_NULL:
4254 printf("null");
4255 break;
4256 case PRINT_ATOM:
4257 printf("%s", args->atom.atom);
4258 break;
4259 case PRINT_FIELD:
4260 printf("REC->%s", args->field.name);
4261 break;
4262 case PRINT_FLAGS:
4263 printf("__print_flags(");
4264 print_args(args->flags.field);
4265 printf(", %s, ", args->flags.delim);
4266 trace_seq_init(&s);
4267 print_fields(&s, args->flags.flags);
4268 trace_seq_do_printf(&s);
4269 trace_seq_destroy(&s);
4270 printf(")");
4271 break;
4272 case PRINT_SYMBOL:
4273 printf("__print_symbolic(");
4274 print_args(args->symbol.field);
4275 printf(", ");
4276 trace_seq_init(&s);
4277 print_fields(&s, args->symbol.symbols);
4278 trace_seq_do_printf(&s);
4279 trace_seq_destroy(&s);
4280 printf(")");
4281 break;
4282 case PRINT_STRING:
4283 case PRINT_BSTRING:
4284 printf("__get_str(%s)", args->string.string);
4285 break;
4286 case PRINT_TYPE:
4287 printf("(%s)", args->typecast.type);
4288 print_args(args->typecast.item);
4289 break;
4290 case PRINT_OP:
4291 if (strcmp(args->op.op, ":") == 0)
4292 print_paren = 0;
4293 if (print_paren)
4294 printf("(");
4295 print_args(args->op.left);
4296 printf(" %s ", args->op.op);
4297 print_args(args->op.right);
4298 if (print_paren)
4299 printf(")");
4300 break;
4301 default:
4302 /* we should warn... */
4303 return;
4304 }
4305 if (args->next) {
4306 printf("\n");
4307 print_args(args->next);
4308 }
4309}
4310
4311static void parse_header_field(const char *field,
4312 int *offset, int *size, int mandatory)
4313{
4314 unsigned long long save_input_buf_ptr;
4315 unsigned long long save_input_buf_siz;
4316 char *token;
4317 int type;
4318
4319 save_input_buf_ptr = input_buf_ptr;
4320 save_input_buf_siz = input_buf_siz;
4321
4322 if (read_expected(EVENT_ITEM, "field") < 0)
4323 return;
4324 if (read_expected(EVENT_OP, ":") < 0)
4325 return;
4326
4327 /* type */
4328 if (read_expect_type(EVENT_ITEM, &token) < 0)
4329 goto fail;
4330 free_token(token);
4331
4332 /*
4333 * If this is not a mandatory field, then test it first.
4334 */
4335 if (mandatory) {
4336 if (read_expected(EVENT_ITEM, field) < 0)
4337 return;
4338 } else {
4339 if (read_expect_type(EVENT_ITEM, &token) < 0)
4340 goto fail;
4341 if (strcmp(token, field) != 0)
4342 goto discard;
4343 free_token(token);
4344 }
4345
4346 if (read_expected(EVENT_OP, ";") < 0)
4347 return;
4348 if (read_expected(EVENT_ITEM, "offset") < 0)
4349 return;
4350 if (read_expected(EVENT_OP, ":") < 0)
4351 return;
4352 if (read_expect_type(EVENT_ITEM, &token) < 0)
4353 goto fail;
4354 *offset = atoi(token);
4355 free_token(token);
4356 if (read_expected(EVENT_OP, ";") < 0)
4357 return;
4358 if (read_expected(EVENT_ITEM, "size") < 0)
4359 return;
4360 if (read_expected(EVENT_OP, ":") < 0)
4361 return;
4362 if (read_expect_type(EVENT_ITEM, &token) < 0)
4363 goto fail;
4364 *size = atoi(token);
4365 free_token(token);
4366 if (read_expected(EVENT_OP, ";") < 0)
4367 return;
4368 type = read_token(&token);
4369 if (type != EVENT_NEWLINE) {
4370 /* newer versions of the kernel have a "signed" type */
4371 if (type != EVENT_ITEM)
4372 goto fail;
4373
4374 if (strcmp(token, "signed") != 0)
4375 goto fail;
4376
4377 free_token(token);
4378
4379 if (read_expected(EVENT_OP, ":") < 0)
4380 return;
4381
4382 if (read_expect_type(EVENT_ITEM, &token))
4383 goto fail;
4384
4385 free_token(token);
4386 if (read_expected(EVENT_OP, ";") < 0)
4387 return;
4388
4389 if (read_expect_type(EVENT_NEWLINE, &token))
4390 goto fail;
4391 }
4392 fail:
4393 free_token(token);
4394 return;
4395
4396 discard:
4397 input_buf_ptr = save_input_buf_ptr;
4398 input_buf_siz = save_input_buf_siz;
4399 *offset = 0;
4400 *size = 0;
4401 free_token(token);
4402}
4403
4404/**
4405 * pevent_parse_header_page - parse the data stored in the header page
4406 * @pevent: the handle to the pevent
4407 * @buf: the buffer storing the header page format string
4408 * @size: the size of @buf
4409 * @long_size: the long size to use if there is no header
4410 *
4411 * This parses the header page format for information on the
4412 * ring buffer used. The @buf should be copied from
4413 *
4414 * /sys/kernel/debug/tracing/events/header_page
4415 */
4416int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size,
4417 int long_size)
4418{
4419 int ignore;
4420
4421 if (!size) {
4422 /*
4423 * Old kernels did not have header page info.
4424 * Sorry but we just use what we find here in user space.
4425 */
4426 pevent->header_page_ts_size = sizeof(long long);
4427 pevent->header_page_size_size = long_size;
4428 pevent->header_page_data_offset = sizeof(long long) + long_size;
4429 pevent->old_format = 1;
4430 return -1;
4431 }
4432 init_input_buf(buf, size);
4433
4434 parse_header_field("timestamp", &pevent->header_page_ts_offset,
4435 &pevent->header_page_ts_size, 1);
4436 parse_header_field("commit", &pevent->header_page_size_offset,
4437 &pevent->header_page_size_size, 1);
4438 parse_header_field("overwrite", &pevent->header_page_overwrite,
4439 &ignore, 0);
4440 parse_header_field("data", &pevent->header_page_data_offset,
4441 &pevent->header_page_data_size, 1);
4442
4443 return 0;
4444}
4445
4446static int event_matches(struct event_format *event,
4447 int id, const char *sys_name,
4448 const char *event_name)
4449{
4450 if (id >= 0 && id != event->id)
4451 return 0;
4452
4453 if (event_name && (strcmp(event_name, event->name) != 0))
4454 return 0;
4455
4456 if (sys_name && (strcmp(sys_name, event->system) != 0))
4457 return 0;
4458
4459 return 1;
4460}
4461
4462static void free_handler(struct event_handler *handle)
4463{
4464 free((void *)handle->sys_name);
4465 free((void *)handle->event_name);
4466 free(handle);
4467}
4468
4469static int find_event_handle(struct pevent *pevent, struct event_format *event)
4470{
4471 struct event_handler *handle, **next;
4472
4473 for (next = &pevent->handlers; *next;
4474 next = &(*next)->next) {
4475 handle = *next;
4476 if (event_matches(event, handle->id,
4477 handle->sys_name,
4478 handle->event_name))
4479 break;
4480 }
4481
4482 if (!(*next))
4483 return 0;
4484
4485 pr_stat("overriding event (%d) %s:%s with new print handler",
4486 event->id, event->system, event->name);
4487
4488 event->handler = handle->func;
4489 event->context = handle->context;
4490
4491 *next = handle->next;
4492 free_handler(handle);
4493
4494 return 1;
4495}
4496
4497/**
4498 * pevent_parse_event - parse the event format
4499 * @pevent: the handle to the pevent
4500 * @buf: the buffer storing the event format string
4501 * @size: the size of @buf
4502 * @sys: the system the event belongs to
4503 *
4504 * This parses the event format and creates an event structure
4505 * to quickly parse raw data for a given event.
4506 *
4507 * These files currently come from:
4508 *
4509 * /sys/kernel/debug/tracing/events/.../.../format
4510 */
4511int pevent_parse_event(struct pevent *pevent,
4512 const char *buf, unsigned long size,
4513 const char *sys)
4514{
4515 struct event_format *event;
4516 int ret;
4517
4518 init_input_buf(buf, size);
4519
4520 event = alloc_event();
4521 if (!event)
4522 return -ENOMEM;
4523
4524 event->name = event_read_name();
4525 if (!event->name) {
4526 /* Bad event? */
4527 free(event);
4528 return -1;
4529 }
4530
4531 if (strcmp(sys, "ftrace") == 0) {
4532
4533 event->flags |= EVENT_FL_ISFTRACE;
4534
4535 if (strcmp(event->name, "bprint") == 0)
4536 event->flags |= EVENT_FL_ISBPRINT;
4537 }
4538
4539 event->id = event_read_id();
4540 if (event->id < 0)
4541 die("failed to read event id");
4542
4543 event->system = strdup(sys);
4544
4545 /* Add pevent to event so that it can be referenced */
4546 event->pevent = pevent;
4547
4548 ret = event_read_format(event);
4549 if (ret < 0) {
4550 do_warning("failed to read event format for %s", event->name);
4551 goto event_failed;
4552 }
4553
4554 /*
4555 * If the event has an override, don't print warnings if the event
4556 * print format fails to parse.
4557 */
4558 if (find_event_handle(pevent, event))
4559 show_warning = 0;
4560
4561 ret = event_read_print(event);
4562 if (ret < 0) {
4563 do_warning("failed to read event print fmt for %s",
4564 event->name);
4565 show_warning = 1;
4566 goto event_failed;
4567 }
4568 show_warning = 1;
4569
4570 add_event(pevent, event);
4571
4572 if (!ret && (event->flags & EVENT_FL_ISFTRACE)) {
4573 struct format_field *field;
4574 struct print_arg *arg, **list;
4575
4576 /* old ftrace had no args */
4577
4578 list = &event->print_fmt.args;
4579 for (field = event->format.fields; field; field = field->next) {
4580 arg = alloc_arg();
4581 *list = arg;
4582 list = &arg->next;
4583 arg->type = PRINT_FIELD;
4584 arg->field.name = strdup(field->name);
4585 arg->field.field = field;
4586 }
4587 return 0;
4588 }
4589
4590#define PRINT_ARGS 0
4591 if (PRINT_ARGS && event->print_fmt.args)
4592 print_args(event->print_fmt.args);
4593
4594 return 0;
4595
4596 event_failed:
4597 event->flags |= EVENT_FL_FAILED;
4598 /* still add it even if it failed */
4599 add_event(pevent, event);
4600 return -1;
4601}
4602
4603int get_field_val(struct trace_seq *s, struct format_field *field,
4604 const char *name, struct pevent_record *record,
4605 unsigned long long *val, int err)
4606{
4607 if (!field) {
4608 if (err)
4609 trace_seq_printf(s, "<CANT FIND FIELD %s>", name);
4610 return -1;
4611 }
4612
4613 if (pevent_read_number_field(field, record->data, val)) {
4614 if (err)
4615 trace_seq_printf(s, " %s=INVALID", name);
4616 return -1;
4617 }
4618
4619 return 0;
4620}
4621
4622/**
4623 * pevent_get_field_raw - return the raw pointer into the data field
4624 * @s: The seq to print to on error
4625 * @event: the event that the field is for
4626 * @name: The name of the field
4627 * @record: The record with the field name.
4628 * @len: place to store the field length.
4629 * @err: print default error if failed.
4630 *
4631 * Returns a pointer into record->data of the field and places
4632 * the length of the field in @len.
4633 *
4634 * On failure, it returns NULL.
4635 */
4636void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event,
4637 const char *name, struct pevent_record *record,
4638 int *len, int err)
4639{
4640 struct format_field *field;
4641 void *data = record->data;
4642 unsigned offset;
4643 int dummy;
4644
4645 if (!event)
4646 return NULL;
4647
4648 field = pevent_find_field(event, name);
4649
4650 if (!field) {
4651 if (err)
4652 trace_seq_printf(s, "<CANT FIND FIELD %s>", name);
4653 return NULL;
4654 }
4655
4656 /* Allow @len to be NULL */
4657 if (!len)
4658 len = &dummy;
4659
4660 offset = field->offset;
4661 if (field->flags & FIELD_IS_DYNAMIC) {
4662 offset = pevent_read_number(event->pevent,
4663 data + offset, field->size);
4664 *len = offset >> 16;
4665 offset &= 0xffff;
4666 } else
4667 *len = field->size;
4668
4669 return data + offset;
4670}
4671
4672/**
4673 * pevent_get_field_val - find a field and return its value
4674 * @s: The seq to print to on error
4675 * @event: the event that the field is for
4676 * @name: The name of the field
4677 * @record: The record with the field name.
4678 * @val: place to store the value of the field.
4679 * @err: print default error if failed.
4680 *
4681 * Returns 0 on success -1 on field not found.
4682 */
4683int pevent_get_field_val(struct trace_seq *s, struct event_format *event,
4684 const char *name, struct pevent_record *record,
4685 unsigned long long *val, int err)
4686{
4687 struct format_field *field;
4688
4689 if (!event)
4690 return -1;
4691
4692 field = pevent_find_field(event, name);
4693
4694 return get_field_val(s, field, name, record, val, err);
4695}
4696
4697/**
4698 * pevent_get_common_field_val - find a common field and return its value
4699 * @s: The seq to print to on error
4700 * @event: the event that the field is for
4701 * @name: The name of the field
4702 * @record: The record with the field name.
4703 * @val: place to store the value of the field.
4704 * @err: print default error if failed.
4705 *
4706 * Returns 0 on success -1 on field not found.
4707 */
4708int pevent_get_common_field_val(struct trace_seq *s, struct event_format *event,
4709 const char *name, struct pevent_record *record,
4710 unsigned long long *val, int err)
4711{
4712 struct format_field *field;
4713
4714 if (!event)
4715 return -1;
4716
4717 field = pevent_find_common_field(event, name);
4718
4719 return get_field_val(s, field, name, record, val, err);
4720}
4721
4722/**
4723 * pevent_get_any_field_val - find a any field and return its value
4724 * @s: The seq to print to on error
4725 * @event: the event that the field is for
4726 * @name: The name of the field
4727 * @record: The record with the field name.
4728 * @val: place to store the value of the field.
4729 * @err: print default error if failed.
4730 *
4731 * Returns 0 on success -1 on field not found.
4732 */
4733int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event,
4734 const char *name, struct pevent_record *record,
4735 unsigned long long *val, int err)
4736{
4737 struct format_field *field;
4738
4739 if (!event)
4740 return -1;
4741
4742 field = pevent_find_any_field(event, name);
4743
4744 return get_field_val(s, field, name, record, val, err);
4745}
4746
4747/**
4748 * pevent_print_num_field - print a field and a format
4749 * @s: The seq to print to
4750 * @fmt: The printf format to print the field with.
4751 * @event: the event that the field is for
4752 * @name: The name of the field
4753 * @record: The record with the field name.
4754 * @err: print default error if failed.
4755 *
4756 * Returns: 0 on success, -1 field not fould, or 1 if buffer is full.
4757 */
4758int pevent_print_num_field(struct trace_seq *s, const char *fmt,
4759 struct event_format *event, const char *name,
4760 struct pevent_record *record, int err)
4761{
4762 struct format_field *field = pevent_find_field(event, name);
4763 unsigned long long val;
4764
4765 if (!field)
4766 goto failed;
4767
4768 if (pevent_read_number_field(field, record->data, &val))
4769 goto failed;
4770
4771 return trace_seq_printf(s, fmt, val);
4772
4773 failed:
4774 if (err)
4775 trace_seq_printf(s, "CAN'T FIND FIELD \"%s\"", name);
4776 return -1;
4777}
4778
4779static void free_func_handle(struct pevent_function_handler *func)
4780{
4781 struct pevent_func_params *params;
4782
4783 free(func->name);
4784
4785 while (func->params) {
4786 params = func->params;
4787 func->params = params->next;
4788 free(params);
4789 }
4790
4791 free(func);
4792}
4793
4794/**
4795 * pevent_register_print_function - register a helper function
4796 * @pevent: the handle to the pevent
4797 * @func: the function to process the helper function
4798 * @name: the name of the helper function
4799 * @parameters: A list of enum pevent_func_arg_type
4800 *
4801 * Some events may have helper functions in the print format arguments.
4802 * This allows a plugin to dynmically create a way to process one
4803 * of these functions.
4804 *
4805 * The @parameters is a variable list of pevent_func_arg_type enums that
4806 * must end with PEVENT_FUNC_ARG_VOID.
4807 */
4808int pevent_register_print_function(struct pevent *pevent,
4809 pevent_func_handler func,
4810 enum pevent_func_arg_type ret_type,
4811 char *name, ...)
4812{
4813 struct pevent_function_handler *func_handle;
4814 struct pevent_func_params **next_param;
4815 struct pevent_func_params *param;
4816 enum pevent_func_arg_type type;
4817 va_list ap;
4818
4819 func_handle = find_func_handler(pevent, name);
4820 if (func_handle) {
4821 /*
4822 * This is most like caused by the users own
4823 * plugins updating the function. This overrides the
4824 * system defaults.
4825 */
4826 pr_stat("override of function helper '%s'", name);
4827 remove_func_handler(pevent, name);
4828 }
4829
4830 func_handle = malloc_or_die(sizeof(*func_handle));
4831 memset(func_handle, 0, sizeof(*func_handle));
4832
4833 func_handle->ret_type = ret_type;
4834 func_handle->name = strdup(name);
4835 func_handle->func = func;
4836 if (!func_handle->name)
4837 die("Failed to allocate function name");
4838
4839 next_param = &(func_handle->params);
4840 va_start(ap, name);
4841 for (;;) {
4842 type = va_arg(ap, enum pevent_func_arg_type);
4843 if (type == PEVENT_FUNC_ARG_VOID)
4844 break;
4845
4846 if (type < 0 || type >= PEVENT_FUNC_ARG_MAX_TYPES) {
4847 warning("Invalid argument type %d", type);
4848 goto out_free;
4849 }
4850
4851 param = malloc_or_die(sizeof(*param));
4852 param->type = type;
4853 param->next = NULL;
4854
4855 *next_param = param;
4856 next_param = &(param->next);
4857
4858 func_handle->nr_args++;
4859 }
4860 va_end(ap);
4861
4862 func_handle->next = pevent->func_handlers;
4863 pevent->func_handlers = func_handle;
4864
4865 return 0;
4866 out_free:
4867 va_end(ap);
4868 free_func_handle(func_handle);
4869 return -1;
4870}
4871
4872/**
4873 * pevent_register_event_handle - register a way to parse an event
4874 * @pevent: the handle to the pevent
4875 * @id: the id of the event to register
4876 * @sys_name: the system name the event belongs to
4877 * @event_name: the name of the event
4878 * @func: the function to call to parse the event information
4879 *
4880 * This function allows a developer to override the parsing of
4881 * a given event. If for some reason the default print format
4882 * is not sufficient, this function will register a function
4883 * for an event to be used to parse the data instead.
4884 *
4885 * If @id is >= 0, then it is used to find the event.
4886 * else @sys_name and @event_name are used.
4887 */
4888int pevent_register_event_handler(struct pevent *pevent,
4889 int id, char *sys_name, char *event_name,
4890 pevent_event_handler_func func,
4891 void *context)
4892{
4893 struct event_format *event;
4894 struct event_handler *handle;
4895
4896 if (id >= 0) {
4897 /* search by id */
4898 event = pevent_find_event(pevent, id);
4899 if (!event)
4900 goto not_found;
4901 if (event_name && (strcmp(event_name, event->name) != 0))
4902 goto not_found;
4903 if (sys_name && (strcmp(sys_name, event->system) != 0))
4904 goto not_found;
4905 } else {
4906 event = pevent_find_event_by_name(pevent, sys_name, event_name);
4907 if (!event)
4908 goto not_found;
4909 }
4910
4911 pr_stat("overriding event (%d) %s:%s with new print handler",
4912 event->id, event->system, event->name);
4913
4914 event->handler = func;
4915 event->context = context;
4916 return 0;
4917
4918 not_found:
4919 /* Save for later use. */
4920 handle = malloc_or_die(sizeof(*handle));
4921 memset(handle, 0, sizeof(*handle));
4922 handle->id = id;
4923 if (event_name)
4924 handle->event_name = strdup(event_name);
4925 if (sys_name)
4926 handle->sys_name = strdup(sys_name);
4927
4928 handle->func = func;
4929 handle->next = pevent->handlers;
4930 pevent->handlers = handle;
4931 handle->context = context;
4932
4933 return -1;
4934}
4935
4936/**
4937 * pevent_alloc - create a pevent handle
4938 */
4939struct pevent *pevent_alloc(void)
4940{
4941 struct pevent *pevent;
4942
4943 pevent = malloc(sizeof(*pevent));
4944 if (!pevent)
4945 return NULL;
4946 memset(pevent, 0, sizeof(*pevent));
4947 pevent->ref_count = 1;
4948
4949 return pevent;
4950}
4951
4952void pevent_ref(struct pevent *pevent)
4953{
4954 pevent->ref_count++;
4955}
4956
4957static void free_format_fields(struct format_field *field)
4958{
4959 struct format_field *next;
4960
4961 while (field) {
4962 next = field->next;
4963 free(field->type);
4964 free(field->name);
4965 free(field);
4966 field = next;
4967 }
4968}
4969
4970static void free_formats(struct format *format)
4971{
4972 free_format_fields(format->common_fields);
4973 free_format_fields(format->fields);
4974}
4975
4976static void free_event(struct event_format *event)
4977{
4978 free(event->name);
4979 free(event->system);
4980
4981 free_formats(&event->format);
4982
4983 free(event->print_fmt.format);
4984 free_args(event->print_fmt.args);
4985
4986 free(event);
4987}
4988
4989/**
4990 * pevent_free - free a pevent handle
4991 * @pevent: the pevent handle to free
4992 */
4993void pevent_free(struct pevent *pevent)
4994{
4995 struct cmdline_list *cmdlist, *cmdnext;
4996 struct func_list *funclist, *funcnext;
4997 struct printk_list *printklist, *printknext;
4998 struct pevent_function_handler *func_handler;
4999 struct event_handler *handle;
5000 int i;
5001
5002 if (!pevent)
5003 return;
5004
5005 cmdlist = pevent->cmdlist;
5006 funclist = pevent->funclist;
5007 printklist = pevent->printklist;
5008
5009 pevent->ref_count--;
5010 if (pevent->ref_count)
5011 return;
5012
5013 if (pevent->cmdlines) {
5014 for (i = 0; i < pevent->cmdline_count; i++)
5015 free(pevent->cmdlines[i].comm);
5016 free(pevent->cmdlines);
5017 }
5018
5019 while (cmdlist) {
5020 cmdnext = cmdlist->next;
5021 free(cmdlist->comm);
5022 free(cmdlist);
5023 cmdlist = cmdnext;
5024 }
5025
5026 if (pevent->func_map) {
5027 for (i = 0; i < pevent->func_count; i++) {
5028 free(pevent->func_map[i].func);
5029 free(pevent->func_map[i].mod);
5030 }
5031 free(pevent->func_map);
5032 }
5033
5034 while (funclist) {
5035 funcnext = funclist->next;
5036 free(funclist->func);
5037 free(funclist->mod);
5038 free(funclist);
5039 funclist = funcnext;
5040 }
5041
5042 while (pevent->func_handlers) {
5043 func_handler = pevent->func_handlers;
5044 pevent->func_handlers = func_handler->next;
5045 free_func_handle(func_handler);
5046 }
5047
5048 if (pevent->printk_map) {
5049 for (i = 0; i < pevent->printk_count; i++)
5050 free(pevent->printk_map[i].printk);
5051 free(pevent->printk_map);
5052 }
5053
5054 while (printklist) {
5055 printknext = printklist->next;
5056 free(printklist->printk);
5057 free(printklist);
5058 printklist = printknext;
5059 }
5060
5061 for (i = 0; i < pevent->nr_events; i++)
5062 free_event(pevent->events[i]);
5063
5064 while (pevent->handlers) {
5065 handle = pevent->handlers;
5066 pevent->handlers = handle->next;
5067 free_handler(handle);
5068 }
5069
5070 free(pevent->events);
5071 free(pevent->sort_events);
5072
5073 free(pevent);
5074}
5075
5076void pevent_unref(struct pevent *pevent)
5077{
5078 pevent_free(pevent);
5079}
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
new file mode 100644
index 000000000000..ac997bc7b592
--- /dev/null
+++ b/tools/lib/traceevent/event-parse.h
@@ -0,0 +1,804 @@
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, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#ifndef _PARSE_EVENTS_H
22#define _PARSE_EVENTS_H
23
24#include <stdarg.h>
25#include <regex.h>
26
27#ifndef __unused
28#define __unused __attribute__ ((unused))
29#endif
30
31/* ----------------------- trace_seq ----------------------- */
32
33
34#ifndef TRACE_SEQ_BUF_SIZE
35#define TRACE_SEQ_BUF_SIZE 4096
36#endif
37
38#ifndef DEBUG_RECORD
39#define DEBUG_RECORD 0
40#endif
41
42struct pevent_record {
43 unsigned long long ts;
44 unsigned long long offset;
45 long long missed_events; /* buffer dropped events before */
46 int record_size; /* size of binary record */
47 int size; /* size of data */
48 void *data;
49 int cpu;
50 int ref_count;
51 int locked; /* Do not free, even if ref_count is zero */
52 void *private;
53#if DEBUG_RECORD
54 struct pevent_record *prev;
55 struct pevent_record *next;
56 long alloc_addr;
57#endif
58};
59
60/*
61 * Trace sequences are used to allow a function to call several other functions
62 * to create a string of data to use (up to a max of PAGE_SIZE).
63 */
64
65struct trace_seq {
66 char *buffer;
67 unsigned int buffer_size;
68 unsigned int len;
69 unsigned int readpos;
70};
71
72void trace_seq_init(struct trace_seq *s);
73void trace_seq_destroy(struct trace_seq *s);
74
75extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
76 __attribute__ ((format (printf, 2, 3)));
77extern int trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
78 __attribute__ ((format (printf, 2, 0)));
79
80extern int trace_seq_puts(struct trace_seq *s, const char *str);
81extern int trace_seq_putc(struct trace_seq *s, unsigned char c);
82
83extern void trace_seq_terminate(struct trace_seq *s);
84
85extern int trace_seq_do_printf(struct trace_seq *s);
86
87
88/* ----------------------- pevent ----------------------- */
89
90struct pevent;
91struct event_format;
92
93typedef int (*pevent_event_handler_func)(struct trace_seq *s,
94 struct pevent_record *record,
95 struct event_format *event,
96 void *context);
97
98typedef int (*pevent_plugin_load_func)(struct pevent *pevent);
99typedef int (*pevent_plugin_unload_func)(void);
100
101struct plugin_option {
102 struct plugin_option *next;
103 void *handle;
104 char *file;
105 char *name;
106 char *plugin_alias;
107 char *description;
108 char *value;
109 void *private;
110 int set;
111};
112
113/*
114 * Plugin hooks that can be called:
115 *
116 * PEVENT_PLUGIN_LOADER: (required)
117 * The function name to initialized the plugin.
118 *
119 * int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
120 *
121 * PEVENT_PLUGIN_UNLOADER: (optional)
122 * The function called just before unloading
123 *
124 * int PEVENT_PLUGIN_UNLOADER(void)
125 *
126 * PEVENT_PLUGIN_OPTIONS: (optional)
127 * Plugin options that can be set before loading
128 *
129 * struct plugin_option PEVENT_PLUGIN_OPTIONS[] = {
130 * {
131 * .name = "option-name",
132 * .plugin_alias = "overide-file-name", (optional)
133 * .description = "description of option to show users",
134 * },
135 * {
136 * .name = NULL,
137 * },
138 * };
139 *
140 * Array must end with .name = NULL;
141 *
142 *
143 * .plugin_alias is used to give a shorter name to access
144 * the vairable. Useful if a plugin handles more than one event.
145 *
146 * PEVENT_PLUGIN_ALIAS: (optional)
147 * The name to use for finding options (uses filename if not defined)
148 */
149#define PEVENT_PLUGIN_LOADER pevent_plugin_loader
150#define PEVENT_PLUGIN_UNLOADER pevent_plugin_unloader
151#define PEVENT_PLUGIN_OPTIONS pevent_plugin_options
152#define PEVENT_PLUGIN_ALIAS pevent_plugin_alias
153#define _MAKE_STR(x) #x
154#define MAKE_STR(x) _MAKE_STR(x)
155#define PEVENT_PLUGIN_LOADER_NAME MAKE_STR(PEVENT_PLUGIN_LOADER)
156#define PEVENT_PLUGIN_UNLOADER_NAME MAKE_STR(PEVENT_PLUGIN_UNLOADER)
157#define PEVENT_PLUGIN_OPTIONS_NAME MAKE_STR(PEVENT_PLUGIN_OPTIONS)
158#define PEVENT_PLUGIN_ALIAS_NAME MAKE_STR(PEVENT_PLUGIN_ALIAS)
159
160#define NSECS_PER_SEC 1000000000ULL
161#define NSECS_PER_USEC 1000ULL
162
163enum format_flags {
164 FIELD_IS_ARRAY = 1,
165 FIELD_IS_POINTER = 2,
166 FIELD_IS_SIGNED = 4,
167 FIELD_IS_STRING = 8,
168 FIELD_IS_DYNAMIC = 16,
169 FIELD_IS_LONG = 32,
170 FIELD_IS_FLAG = 64,
171 FIELD_IS_SYMBOLIC = 128,
172};
173
174struct format_field {
175 struct format_field *next;
176 struct event_format *event;
177 char *type;
178 char *name;
179 int offset;
180 int size;
181 unsigned int arraylen;
182 unsigned int elementsize;
183 unsigned long flags;
184};
185
186struct format {
187 int nr_common;
188 int nr_fields;
189 struct format_field *common_fields;
190 struct format_field *fields;
191};
192
193struct print_arg_atom {
194 char *atom;
195};
196
197struct print_arg_string {
198 char *string;
199 int offset;
200};
201
202struct print_arg_field {
203 char *name;
204 struct format_field *field;
205};
206
207struct print_flag_sym {
208 struct print_flag_sym *next;
209 char *value;
210 char *str;
211};
212
213struct print_arg_typecast {
214 char *type;
215 struct print_arg *item;
216};
217
218struct print_arg_flags {
219 struct print_arg *field;
220 char *delim;
221 struct print_flag_sym *flags;
222};
223
224struct print_arg_symbol {
225 struct print_arg *field;
226 struct print_flag_sym *symbols;
227};
228
229struct print_arg_dynarray {
230 struct format_field *field;
231 struct print_arg *index;
232};
233
234struct print_arg;
235
236struct print_arg_op {
237 char *op;
238 int prio;
239 struct print_arg *left;
240 struct print_arg *right;
241};
242
243struct pevent_function_handler;
244
245struct print_arg_func {
246 struct pevent_function_handler *func;
247 struct print_arg *args;
248};
249
250enum print_arg_type {
251 PRINT_NULL,
252 PRINT_ATOM,
253 PRINT_FIELD,
254 PRINT_FLAGS,
255 PRINT_SYMBOL,
256 PRINT_TYPE,
257 PRINT_STRING,
258 PRINT_BSTRING,
259 PRINT_DYNAMIC_ARRAY,
260 PRINT_OP,
261 PRINT_FUNC,
262};
263
264struct print_arg {
265 struct print_arg *next;
266 enum print_arg_type type;
267 union {
268 struct print_arg_atom atom;
269 struct print_arg_field field;
270 struct print_arg_typecast typecast;
271 struct print_arg_flags flags;
272 struct print_arg_symbol symbol;
273 struct print_arg_func func;
274 struct print_arg_string string;
275 struct print_arg_op op;
276 struct print_arg_dynarray dynarray;
277 };
278};
279
280struct print_fmt {
281 char *format;
282 struct print_arg *args;
283};
284
285struct event_format {
286 struct pevent *pevent;
287 char *name;
288 int id;
289 int flags;
290 struct format format;
291 struct print_fmt print_fmt;
292 char *system;
293 pevent_event_handler_func handler;
294 void *context;
295};
296
297enum {
298 EVENT_FL_ISFTRACE = 0x01,
299 EVENT_FL_ISPRINT = 0x02,
300 EVENT_FL_ISBPRINT = 0x04,
301 EVENT_FL_ISFUNCENT = 0x10,
302 EVENT_FL_ISFUNCRET = 0x20,
303
304 EVENT_FL_FAILED = 0x80000000
305};
306
307enum event_sort_type {
308 EVENT_SORT_ID,
309 EVENT_SORT_NAME,
310 EVENT_SORT_SYSTEM,
311};
312
313enum event_type {
314 EVENT_ERROR,
315 EVENT_NONE,
316 EVENT_SPACE,
317 EVENT_NEWLINE,
318 EVENT_OP,
319 EVENT_DELIM,
320 EVENT_ITEM,
321 EVENT_DQUOTE,
322 EVENT_SQUOTE,
323};
324
325typedef unsigned long long (*pevent_func_handler)(struct trace_seq *s,
326 unsigned long long *args);
327
328enum pevent_func_arg_type {
329 PEVENT_FUNC_ARG_VOID,
330 PEVENT_FUNC_ARG_INT,
331 PEVENT_FUNC_ARG_LONG,
332 PEVENT_FUNC_ARG_STRING,
333 PEVENT_FUNC_ARG_PTR,
334 PEVENT_FUNC_ARG_MAX_TYPES
335};
336
337enum pevent_flag {
338 PEVENT_NSEC_OUTPUT = 1, /* output in NSECS */
339};
340
341struct cmdline;
342struct cmdline_list;
343struct func_map;
344struct func_list;
345struct event_handler;
346
347struct pevent {
348 int ref_count;
349
350 int header_page_ts_offset;
351 int header_page_ts_size;
352 int header_page_size_offset;
353 int header_page_size_size;
354 int header_page_data_offset;
355 int header_page_data_size;
356 int header_page_overwrite;
357
358 int file_bigendian;
359 int host_bigendian;
360
361 int latency_format;
362
363 int old_format;
364
365 int cpus;
366 int long_size;
367
368 struct cmdline *cmdlines;
369 struct cmdline_list *cmdlist;
370 int cmdline_count;
371
372 struct func_map *func_map;
373 struct func_list *funclist;
374 unsigned int func_count;
375
376 struct printk_map *printk_map;
377 struct printk_list *printklist;
378 unsigned int printk_count;
379
380
381 struct event_format **events;
382 int nr_events;
383 struct event_format **sort_events;
384 enum event_sort_type last_type;
385
386 int type_offset;
387 int type_size;
388
389 int pid_offset;
390 int pid_size;
391
392 int pc_offset;
393 int pc_size;
394
395 int flags_offset;
396 int flags_size;
397
398 int ld_offset;
399 int ld_size;
400
401 int print_raw;
402
403 int test_filters;
404
405 int flags;
406
407 struct format_field *bprint_ip_field;
408 struct format_field *bprint_fmt_field;
409 struct format_field *bprint_buf_field;
410
411 struct event_handler *handlers;
412 struct pevent_function_handler *func_handlers;
413
414 /* cache */
415 struct event_format *last_event;
416};
417
418static inline void pevent_set_flag(struct pevent *pevent, int flag)
419{
420 pevent->flags |= flag;
421}
422
423static inline unsigned short
424__data2host2(struct pevent *pevent, unsigned short data)
425{
426 unsigned short swap;
427
428 if (pevent->host_bigendian == pevent->file_bigendian)
429 return data;
430
431 swap = ((data & 0xffULL) << 8) |
432 ((data & (0xffULL << 8)) >> 8);
433
434 return swap;
435}
436
437static inline unsigned int
438__data2host4(struct pevent *pevent, unsigned int data)
439{
440 unsigned int swap;
441
442 if (pevent->host_bigendian == pevent->file_bigendian)
443 return data;
444
445 swap = ((data & 0xffULL) << 24) |
446 ((data & (0xffULL << 8)) << 8) |
447 ((data & (0xffULL << 16)) >> 8) |
448 ((data & (0xffULL << 24)) >> 24);
449
450 return swap;
451}
452
453static inline unsigned long long
454__data2host8(struct pevent *pevent, unsigned long long data)
455{
456 unsigned long long swap;
457
458 if (pevent->host_bigendian == pevent->file_bigendian)
459 return data;
460
461 swap = ((data & 0xffULL) << 56) |
462 ((data & (0xffULL << 8)) << 40) |
463 ((data & (0xffULL << 16)) << 24) |
464 ((data & (0xffULL << 24)) << 8) |
465 ((data & (0xffULL << 32)) >> 8) |
466 ((data & (0xffULL << 40)) >> 24) |
467 ((data & (0xffULL << 48)) >> 40) |
468 ((data & (0xffULL << 56)) >> 56);
469
470 return swap;
471}
472
473#define data2host2(pevent, ptr) __data2host2(pevent, *(unsigned short *)(ptr))
474#define data2host4(pevent, ptr) __data2host4(pevent, *(unsigned int *)(ptr))
475#define data2host8(pevent, ptr) \
476({ \
477 unsigned long long __val; \
478 \
479 memcpy(&__val, (ptr), sizeof(unsigned long long)); \
480 __data2host8(pevent, __val); \
481})
482
483/* taken from kernel/trace/trace.h */
484enum trace_flag_type {
485 TRACE_FLAG_IRQS_OFF = 0x01,
486 TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
487 TRACE_FLAG_NEED_RESCHED = 0x04,
488 TRACE_FLAG_HARDIRQ = 0x08,
489 TRACE_FLAG_SOFTIRQ = 0x10,
490};
491
492int pevent_register_comm(struct pevent *pevent, const char *comm, int pid);
493int pevent_register_function(struct pevent *pevent, char *name,
494 unsigned long long addr, char *mod);
495int pevent_register_print_string(struct pevent *pevent, char *fmt,
496 unsigned long long addr);
497int pevent_pid_is_registered(struct pevent *pevent, int pid);
498
499void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
500 struct pevent_record *record);
501
502int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size,
503 int long_size);
504
505int pevent_parse_event(struct pevent *pevent, const char *buf,
506 unsigned long size, const char *sys);
507
508void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event,
509 const char *name, struct pevent_record *record,
510 int *len, int err);
511
512int pevent_get_field_val(struct trace_seq *s, struct event_format *event,
513 const char *name, struct pevent_record *record,
514 unsigned long long *val, int err);
515int pevent_get_common_field_val(struct trace_seq *s, struct event_format *event,
516 const char *name, struct pevent_record *record,
517 unsigned long long *val, int err);
518int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event,
519 const char *name, struct pevent_record *record,
520 unsigned long long *val, int err);
521
522int pevent_print_num_field(struct trace_seq *s, const char *fmt,
523 struct event_format *event, const char *name,
524 struct pevent_record *record, int err);
525
526int pevent_register_event_handler(struct pevent *pevent, int id, char *sys_name, char *event_name,
527 pevent_event_handler_func func, void *context);
528int pevent_register_print_function(struct pevent *pevent,
529 pevent_func_handler func,
530 enum pevent_func_arg_type ret_type,
531 char *name, ...);
532
533struct format_field *pevent_find_common_field(struct event_format *event, const char *name);
534struct format_field *pevent_find_field(struct event_format *event, const char *name);
535struct format_field *pevent_find_any_field(struct event_format *event, const char *name);
536
537const char *pevent_find_function(struct pevent *pevent, unsigned long long addr);
538unsigned long long
539pevent_find_function_address(struct pevent *pevent, unsigned long long addr);
540unsigned long long pevent_read_number(struct pevent *pevent, const void *ptr, int size);
541int pevent_read_number_field(struct format_field *field, const void *data,
542 unsigned long long *value);
543
544struct event_format *pevent_find_event(struct pevent *pevent, int id);
545
546struct event_format *
547pevent_find_event_by_name(struct pevent *pevent, const char *sys, const char *name);
548
549void pevent_data_lat_fmt(struct pevent *pevent,
550 struct trace_seq *s, struct pevent_record *record);
551int pevent_data_type(struct pevent *pevent, struct pevent_record *rec);
552struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type);
553int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec);
554const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid);
555void pevent_event_info(struct trace_seq *s, struct event_format *event,
556 struct pevent_record *record);
557
558struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type);
559struct format_field **pevent_event_common_fields(struct event_format *event);
560struct format_field **pevent_event_fields(struct event_format *event);
561
562static inline int pevent_get_cpus(struct pevent *pevent)
563{
564 return pevent->cpus;
565}
566
567static inline void pevent_set_cpus(struct pevent *pevent, int cpus)
568{
569 pevent->cpus = cpus;
570}
571
572static inline int pevent_get_long_size(struct pevent *pevent)
573{
574 return pevent->long_size;
575}
576
577static inline void pevent_set_long_size(struct pevent *pevent, int long_size)
578{
579 pevent->long_size = long_size;
580}
581
582static inline int pevent_is_file_bigendian(struct pevent *pevent)
583{
584 return pevent->file_bigendian;
585}
586
587static inline void pevent_set_file_bigendian(struct pevent *pevent, int endian)
588{
589 pevent->file_bigendian = endian;
590}
591
592static inline int pevent_is_host_bigendian(struct pevent *pevent)
593{
594 return pevent->host_bigendian;
595}
596
597static inline void pevent_set_host_bigendian(struct pevent *pevent, int endian)
598{
599 pevent->host_bigendian = endian;
600}
601
602static inline int pevent_is_latency_format(struct pevent *pevent)
603{
604 return pevent->latency_format;
605}
606
607static inline void pevent_set_latency_format(struct pevent *pevent, int lat)
608{
609 pevent->latency_format = lat;
610}
611
612struct pevent *pevent_alloc(void);
613void pevent_free(struct pevent *pevent);
614void pevent_ref(struct pevent *pevent);
615void pevent_unref(struct pevent *pevent);
616
617/* access to the internal parser */
618void pevent_buffer_init(const char *buf, unsigned long long size);
619enum event_type pevent_read_token(char **tok);
620void pevent_free_token(char *token);
621int pevent_peek_char(void);
622const char *pevent_get_input_buf(void);
623unsigned long long pevent_get_input_buf_ptr(void);
624
625/* for debugging */
626void pevent_print_funcs(struct pevent *pevent);
627void pevent_print_printk(struct pevent *pevent);
628
629/* ----------------------- filtering ----------------------- */
630
631enum filter_boolean_type {
632 FILTER_FALSE,
633 FILTER_TRUE,
634};
635
636enum filter_op_type {
637 FILTER_OP_AND = 1,
638 FILTER_OP_OR,
639 FILTER_OP_NOT,
640};
641
642enum filter_cmp_type {
643 FILTER_CMP_NONE,
644 FILTER_CMP_EQ,
645 FILTER_CMP_NE,
646 FILTER_CMP_GT,
647 FILTER_CMP_LT,
648 FILTER_CMP_GE,
649 FILTER_CMP_LE,
650 FILTER_CMP_MATCH,
651 FILTER_CMP_NOT_MATCH,
652 FILTER_CMP_REGEX,
653 FILTER_CMP_NOT_REGEX,
654};
655
656enum filter_exp_type {
657 FILTER_EXP_NONE,
658 FILTER_EXP_ADD,
659 FILTER_EXP_SUB,
660 FILTER_EXP_MUL,
661 FILTER_EXP_DIV,
662 FILTER_EXP_MOD,
663 FILTER_EXP_RSHIFT,
664 FILTER_EXP_LSHIFT,
665 FILTER_EXP_AND,
666 FILTER_EXP_OR,
667 FILTER_EXP_XOR,
668 FILTER_EXP_NOT,
669};
670
671enum filter_arg_type {
672 FILTER_ARG_NONE,
673 FILTER_ARG_BOOLEAN,
674 FILTER_ARG_VALUE,
675 FILTER_ARG_FIELD,
676 FILTER_ARG_EXP,
677 FILTER_ARG_OP,
678 FILTER_ARG_NUM,
679 FILTER_ARG_STR,
680};
681
682enum filter_value_type {
683 FILTER_NUMBER,
684 FILTER_STRING,
685 FILTER_CHAR
686};
687
688struct fliter_arg;
689
690struct filter_arg_boolean {
691 enum filter_boolean_type value;
692};
693
694struct filter_arg_field {
695 struct format_field *field;
696};
697
698struct filter_arg_value {
699 enum filter_value_type type;
700 union {
701 char *str;
702 unsigned long long val;
703 };
704};
705
706struct filter_arg_op {
707 enum filter_op_type type;
708 struct filter_arg *left;
709 struct filter_arg *right;
710};
711
712struct filter_arg_exp {
713 enum filter_exp_type type;
714 struct filter_arg *left;
715 struct filter_arg *right;
716};
717
718struct filter_arg_num {
719 enum filter_cmp_type type;
720 struct filter_arg *left;
721 struct filter_arg *right;
722};
723
724struct filter_arg_str {
725 enum filter_cmp_type type;
726 struct format_field *field;
727 char *val;
728 char *buffer;
729 regex_t reg;
730};
731
732struct filter_arg {
733 enum filter_arg_type type;
734 union {
735 struct filter_arg_boolean boolean;
736 struct filter_arg_field field;
737 struct filter_arg_value value;
738 struct filter_arg_op op;
739 struct filter_arg_exp exp;
740 struct filter_arg_num num;
741 struct filter_arg_str str;
742 };
743};
744
745struct filter_type {
746 int event_id;
747 struct event_format *event;
748 struct filter_arg *filter;
749};
750
751struct event_filter {
752 struct pevent *pevent;
753 int filters;
754 struct filter_type *event_filters;
755};
756
757struct event_filter *pevent_filter_alloc(struct pevent *pevent);
758
759#define FILTER_NONE -2
760#define FILTER_NOEXIST -1
761#define FILTER_MISS 0
762#define FILTER_MATCH 1
763
764enum filter_trivial_type {
765 FILTER_TRIVIAL_FALSE,
766 FILTER_TRIVIAL_TRUE,
767 FILTER_TRIVIAL_BOTH,
768};
769
770int pevent_filter_add_filter_str(struct event_filter *filter,
771 const char *filter_str,
772 char **error_str);
773
774
775int pevent_filter_match(struct event_filter *filter,
776 struct pevent_record *record);
777
778int pevent_event_filtered(struct event_filter *filter,
779 int event_id);
780
781void pevent_filter_reset(struct event_filter *filter);
782
783void pevent_filter_clear_trivial(struct event_filter *filter,
784 enum filter_trivial_type type);
785
786void pevent_filter_free(struct event_filter *filter);
787
788char *pevent_filter_make_string(struct event_filter *filter, int event_id);
789
790int pevent_filter_remove_event(struct event_filter *filter,
791 int event_id);
792
793int pevent_filter_event_has_trivial(struct event_filter *filter,
794 int event_id,
795 enum filter_trivial_type type);
796
797int pevent_filter_copy(struct event_filter *dest, struct event_filter *source);
798
799int pevent_update_trivial(struct event_filter *dest, struct event_filter *source,
800 enum filter_trivial_type type);
801
802int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2);
803
804#endif /* _PARSE_EVENTS_H */
diff --git a/tools/lib/traceevent/event-utils.h b/tools/lib/traceevent/event-utils.h
new file mode 100644
index 000000000000..08296383d1e6
--- /dev/null
+++ b/tools/lib/traceevent/event-utils.h
@@ -0,0 +1,80 @@
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, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#ifndef __UTIL_H
22#define __UTIL_H
23
24#include <ctype.h>
25
26/* Can be overridden */
27void die(const char *fmt, ...);
28void *malloc_or_die(unsigned int size);
29void warning(const char *fmt, ...);
30void pr_stat(const char *fmt, ...);
31void vpr_stat(const char *fmt, va_list ap);
32
33/* Always available */
34void __die(const char *fmt, ...);
35void __warning(const char *fmt, ...);
36void __pr_stat(const char *fmt, ...);
37
38void __vdie(const char *fmt, ...);
39void __vwarning(const char *fmt, ...);
40void __vpr_stat(const char *fmt, ...);
41
42static inline char *strim(char *string)
43{
44 char *ret;
45
46 if (!string)
47 return NULL;
48 while (*string) {
49 if (!isspace(*string))
50 break;
51 string++;
52 }
53 ret = string;
54
55 string = ret + strlen(ret) - 1;
56 while (string > ret) {
57 if (!isspace(*string))
58 break;
59 string--;
60 }
61 string[1] = 0;
62
63 return ret;
64}
65
66static inline int has_text(const char *text)
67{
68 if (!text)
69 return 0;
70
71 while (*text) {
72 if (!isspace(*text))
73 return 1;
74 text++;
75 }
76
77 return 0;
78}
79
80#endif
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c
new file mode 100644
index 000000000000..dfcfe2c131de
--- /dev/null
+++ b/tools/lib/traceevent/parse-filter.c
@@ -0,0 +1,2261 @@
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, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <stdarg.h>
25#include <errno.h>
26#include <sys/types.h>
27
28#include "event-parse.h"
29#include "event-utils.h"
30
31#define COMM "COMM"
32
33static struct format_field comm = {
34 .name = "COMM",
35};
36
37struct event_list {
38 struct event_list *next;
39 struct event_format *event;
40};
41
42#define MAX_ERR_STR_SIZE 256
43
44static void show_error(char **error_str, const char *fmt, ...)
45{
46 unsigned long long index;
47 const char *input;
48 char *error;
49 va_list ap;
50 int len;
51 int i;
52
53 if (!error_str)
54 return;
55
56 input = pevent_get_input_buf();
57 index = pevent_get_input_buf_ptr();
58 len = input ? strlen(input) : 0;
59
60 error = malloc_or_die(MAX_ERR_STR_SIZE + (len*2) + 3);
61
62 if (len) {
63 strcpy(error, input);
64 error[len] = '\n';
65 for (i = 1; i < len && i < index; i++)
66 error[len+i] = ' ';
67 error[len + i] = '^';
68 error[len + i + 1] = '\n';
69 len += i+2;
70 }
71
72 va_start(ap, fmt);
73 vsnprintf(error + len, MAX_ERR_STR_SIZE, fmt, ap);
74 va_end(ap);
75
76 *error_str = error;
77}
78
79static void free_token(char *token)
80{
81 pevent_free_token(token);
82}
83
84static enum event_type read_token(char **tok)
85{
86 enum event_type type;
87 char *token = NULL;
88
89 do {
90 free_token(token);
91 type = pevent_read_token(&token);
92 } while (type == EVENT_NEWLINE || type == EVENT_SPACE);
93
94 /* If token is = or ! check to see if the next char is ~ */
95 if (token &&
96 (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) &&
97 pevent_peek_char() == '~') {
98 /* append it */
99 *tok = malloc(3);
100 sprintf(*tok, "%c%c", *token, '~');
101 free_token(token);
102 /* Now remove the '~' from the buffer */
103 pevent_read_token(&token);
104 free_token(token);
105 } else
106 *tok = token;
107
108 return type;
109}
110
111static int filter_cmp(const void *a, const void *b)
112{
113 const struct filter_type *ea = a;
114 const struct filter_type *eb = b;
115
116 if (ea->event_id < eb->event_id)
117 return -1;
118
119 if (ea->event_id > eb->event_id)
120 return 1;
121
122 return 0;
123}
124
125static struct filter_type *
126find_filter_type(struct event_filter *filter, int id)
127{
128 struct filter_type *filter_type;
129 struct filter_type key;
130
131 key.event_id = id;
132
133 filter_type = bsearch(&key, filter->event_filters,
134 filter->filters,
135 sizeof(*filter->event_filters),
136 filter_cmp);
137
138 return filter_type;
139}
140
141static struct filter_type *
142add_filter_type(struct event_filter *filter, int id)
143{
144 struct filter_type *filter_type;
145 int i;
146
147 filter_type = find_filter_type(filter, id);
148 if (filter_type)
149 return filter_type;
150
151 if (!filter->filters)
152 filter->event_filters =
153 malloc_or_die(sizeof(*filter->event_filters));
154 else {
155 filter->event_filters =
156 realloc(filter->event_filters,
157 sizeof(*filter->event_filters) *
158 (filter->filters + 1));
159 if (!filter->event_filters)
160 die("Could not allocate filter");
161 }
162
163 for (i = 0; i < filter->filters; i++) {
164 if (filter->event_filters[i].event_id > id)
165 break;
166 }
167
168 if (i < filter->filters)
169 memmove(&filter->event_filters[i+1],
170 &filter->event_filters[i],
171 sizeof(*filter->event_filters) *
172 (filter->filters - i));
173
174 filter_type = &filter->event_filters[i];
175 filter_type->event_id = id;
176 filter_type->event = pevent_find_event(filter->pevent, id);
177 filter_type->filter = NULL;
178
179 filter->filters++;
180
181 return filter_type;
182}
183
184/**
185 * pevent_filter_alloc - create a new event filter
186 * @pevent: The pevent that this filter is associated with
187 */
188struct event_filter *pevent_filter_alloc(struct pevent *pevent)
189{
190 struct event_filter *filter;
191
192 filter = malloc_or_die(sizeof(*filter));
193 memset(filter, 0, sizeof(*filter));
194 filter->pevent = pevent;
195 pevent_ref(pevent);
196
197 return filter;
198}
199
200static struct filter_arg *allocate_arg(void)
201{
202 struct filter_arg *arg;
203
204 arg = malloc_or_die(sizeof(*arg));
205 memset(arg, 0, sizeof(*arg));
206
207 return arg;
208}
209
210static void free_arg(struct filter_arg *arg)
211{
212 if (!arg)
213 return;
214
215 switch (arg->type) {
216 case FILTER_ARG_NONE:
217 case FILTER_ARG_BOOLEAN:
218 case FILTER_ARG_NUM:
219 break;
220
221 case FILTER_ARG_STR:
222 free(arg->str.val);
223 regfree(&arg->str.reg);
224 free(arg->str.buffer);
225 break;
226
227 case FILTER_ARG_OP:
228 free_arg(arg->op.left);
229 free_arg(arg->op.right);
230 default:
231 break;
232 }
233
234 free(arg);
235}
236
237static void add_event(struct event_list **events,
238 struct event_format *event)
239{
240 struct event_list *list;
241
242 list = malloc_or_die(sizeof(*list));
243 list->next = *events;
244 *events = list;
245 list->event = event;
246}
247
248static int event_match(struct event_format *event,
249 regex_t *sreg, regex_t *ereg)
250{
251 if (sreg) {
252 return !regexec(sreg, event->system, 0, NULL, 0) &&
253 !regexec(ereg, event->name, 0, NULL, 0);
254 }
255
256 return !regexec(ereg, event->system, 0, NULL, 0) ||
257 !regexec(ereg, event->name, 0, NULL, 0);
258}
259
260static int
261find_event(struct pevent *pevent, struct event_list **events,
262 char *sys_name, char *event_name)
263{
264 struct event_format *event;
265 regex_t ereg;
266 regex_t sreg;
267 int match = 0;
268 char *reg;
269 int ret;
270 int i;
271
272 if (!event_name) {
273 /* if no name is given, then swap sys and name */
274 event_name = sys_name;
275 sys_name = NULL;
276 }
277
278 reg = malloc_or_die(strlen(event_name) + 3);
279 sprintf(reg, "^%s$", event_name);
280
281 ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB);
282 free(reg);
283
284 if (ret)
285 return -1;
286
287 if (sys_name) {
288 reg = malloc_or_die(strlen(sys_name) + 3);
289 sprintf(reg, "^%s$", sys_name);
290 ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB);
291 free(reg);
292 if (ret) {
293 regfree(&ereg);
294 return -1;
295 }
296 }
297
298 for (i = 0; i < pevent->nr_events; i++) {
299 event = pevent->events[i];
300 if (event_match(event, sys_name ? &sreg : NULL, &ereg)) {
301 match = 1;
302 add_event(events, event);
303 }
304 }
305
306 regfree(&ereg);
307 if (sys_name)
308 regfree(&sreg);
309
310 if (!match)
311 return -1;
312
313 return 0;
314}
315
316static void free_events(struct event_list *events)
317{
318 struct event_list *event;
319
320 while (events) {
321 event = events;
322 events = events->next;
323 free(event);
324 }
325}
326
327static struct filter_arg *
328create_arg_item(struct event_format *event, const char *token,
329 enum event_type type, char **error_str)
330{
331 struct format_field *field;
332 struct filter_arg *arg;
333
334 arg = allocate_arg();
335
336 switch (type) {
337
338 case EVENT_SQUOTE:
339 case EVENT_DQUOTE:
340 arg->type = FILTER_ARG_VALUE;
341 arg->value.type =
342 type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR;
343 arg->value.str = strdup(token);
344 if (!arg->value.str)
345 die("malloc string");
346 break;
347 case EVENT_ITEM:
348 /* if it is a number, then convert it */
349 if (isdigit(token[0])) {
350 arg->type = FILTER_ARG_VALUE;
351 arg->value.type = FILTER_NUMBER;
352 arg->value.val = strtoull(token, NULL, 0);
353 break;
354 }
355 /* Consider this a field */
356 field = pevent_find_any_field(event, token);
357 if (!field) {
358 if (strcmp(token, COMM) != 0) {
359 /* not a field, Make it false */
360 arg->type = FILTER_ARG_BOOLEAN;
361 arg->boolean.value = FILTER_FALSE;
362 break;
363 }
364 /* If token is 'COMM' then it is special */
365 field = &comm;
366 }
367 arg->type = FILTER_ARG_FIELD;
368 arg->field.field = field;
369 break;
370 default:
371 free_arg(arg);
372 show_error(error_str, "expected a value but found %s",
373 token);
374 return NULL;
375 }
376 return arg;
377}
378
379static struct filter_arg *
380create_arg_op(enum filter_op_type btype)
381{
382 struct filter_arg *arg;
383
384 arg = allocate_arg();
385 arg->type = FILTER_ARG_OP;
386 arg->op.type = btype;
387
388 return arg;
389}
390
391static struct filter_arg *
392create_arg_exp(enum filter_exp_type etype)
393{
394 struct filter_arg *arg;
395
396 arg = allocate_arg();
397 arg->type = FILTER_ARG_EXP;
398 arg->op.type = etype;
399
400 return arg;
401}
402
403static struct filter_arg *
404create_arg_cmp(enum filter_exp_type etype)
405{
406 struct filter_arg *arg;
407
408 arg = allocate_arg();
409 /* Use NUM and change if necessary */
410 arg->type = FILTER_ARG_NUM;
411 arg->op.type = etype;
412
413 return arg;
414}
415
416static int add_right(struct filter_arg *op, struct filter_arg *arg,
417 char **error_str)
418{
419 struct filter_arg *left;
420 char *str;
421 int op_type;
422 int ret;
423
424 switch (op->type) {
425 case FILTER_ARG_EXP:
426 if (op->exp.right)
427 goto out_fail;
428 op->exp.right = arg;
429 break;
430
431 case FILTER_ARG_OP:
432 if (op->op.right)
433 goto out_fail;
434 op->op.right = arg;
435 break;
436
437 case FILTER_ARG_NUM:
438 if (op->op.right)
439 goto out_fail;
440 /*
441 * The arg must be num, str, or field
442 */
443 switch (arg->type) {
444 case FILTER_ARG_VALUE:
445 case FILTER_ARG_FIELD:
446 break;
447 default:
448 show_error(error_str,
449 "Illegal rvalue");
450 return -1;
451 }
452
453 /*
454 * Depending on the type, we may need to
455 * convert this to a string or regex.
456 */
457 switch (arg->value.type) {
458 case FILTER_CHAR:
459 /*
460 * A char should be converted to number if
461 * the string is 1 byte, and the compare
462 * is not a REGEX.
463 */
464 if (strlen(arg->value.str) == 1 &&
465 op->num.type != FILTER_CMP_REGEX &&
466 op->num.type != FILTER_CMP_NOT_REGEX) {
467 arg->value.type = FILTER_NUMBER;
468 goto do_int;
469 }
470 /* fall through */
471 case FILTER_STRING:
472
473 /* convert op to a string arg */
474 op_type = op->num.type;
475 left = op->num.left;
476 str = arg->value.str;
477
478 /* reset the op for the new field */
479 memset(op, 0, sizeof(*op));
480
481 /*
482 * If left arg was a field not found then
483 * NULL the entire op.
484 */
485 if (left->type == FILTER_ARG_BOOLEAN) {
486 free_arg(left);
487 free_arg(arg);
488 op->type = FILTER_ARG_BOOLEAN;
489 op->boolean.value = FILTER_FALSE;
490 break;
491 }
492
493 /* Left arg must be a field */
494 if (left->type != FILTER_ARG_FIELD) {
495 show_error(error_str,
496 "Illegal lvalue for string comparison");
497 return -1;
498 }
499
500 /* Make sure this is a valid string compare */
501 switch (op_type) {
502 case FILTER_CMP_EQ:
503 op_type = FILTER_CMP_MATCH;
504 break;
505 case FILTER_CMP_NE:
506 op_type = FILTER_CMP_NOT_MATCH;
507 break;
508
509 case FILTER_CMP_REGEX:
510 case FILTER_CMP_NOT_REGEX:
511 ret = regcomp(&op->str.reg, str, REG_ICASE|REG_NOSUB);
512 if (ret) {
513 show_error(error_str,
514 "RegEx '%s' did not compute",
515 str);
516 return -1;
517 }
518 break;
519 default:
520 show_error(error_str,
521 "Illegal comparison for string");
522 return -1;
523 }
524
525 op->type = FILTER_ARG_STR;
526 op->str.type = op_type;
527 op->str.field = left->field.field;
528 op->str.val = strdup(str);
529 if (!op->str.val)
530 die("malloc string");
531 /*
532 * Need a buffer to copy data for tests
533 */
534 op->str.buffer = malloc_or_die(op->str.field->size + 1);
535 /* Null terminate this buffer */
536 op->str.buffer[op->str.field->size] = 0;
537
538 /* We no longer have left or right args */
539 free_arg(arg);
540 free_arg(left);
541
542 break;
543
544 case FILTER_NUMBER:
545
546 do_int:
547 switch (op->num.type) {
548 case FILTER_CMP_REGEX:
549 case FILTER_CMP_NOT_REGEX:
550 show_error(error_str,
551 "Op not allowed with integers");
552 return -1;
553
554 default:
555 break;
556 }
557
558 /* numeric compare */
559 op->num.right = arg;
560 break;
561 default:
562 goto out_fail;
563 }
564 break;
565 default:
566 goto out_fail;
567 }
568
569 return 0;
570
571 out_fail:
572 show_error(error_str,
573 "Syntax error");
574 return -1;
575}
576
577static struct filter_arg *
578rotate_op_right(struct filter_arg *a, struct filter_arg *b)
579{
580 struct filter_arg *arg;
581
582 arg = a->op.right;
583 a->op.right = b;
584 return arg;
585}
586
587static int add_left(struct filter_arg *op, struct filter_arg *arg)
588{
589 switch (op->type) {
590 case FILTER_ARG_EXP:
591 if (arg->type == FILTER_ARG_OP)
592 arg = rotate_op_right(arg, op);
593 op->exp.left = arg;
594 break;
595
596 case FILTER_ARG_OP:
597 op->op.left = arg;
598 break;
599 case FILTER_ARG_NUM:
600 if (arg->type == FILTER_ARG_OP)
601 arg = rotate_op_right(arg, op);
602
603 /* left arg of compares must be a field */
604 if (arg->type != FILTER_ARG_FIELD &&
605 arg->type != FILTER_ARG_BOOLEAN)
606 return -1;
607 op->num.left = arg;
608 break;
609 default:
610 return -1;
611 }
612 return 0;
613}
614
615enum op_type {
616 OP_NONE,
617 OP_BOOL,
618 OP_NOT,
619 OP_EXP,
620 OP_CMP,
621};
622
623static enum op_type process_op(const char *token,
624 enum filter_op_type *btype,
625 enum filter_cmp_type *ctype,
626 enum filter_exp_type *etype)
627{
628 *btype = FILTER_OP_NOT;
629 *etype = FILTER_EXP_NONE;
630 *ctype = FILTER_CMP_NONE;
631
632 if (strcmp(token, "&&") == 0)
633 *btype = FILTER_OP_AND;
634 else if (strcmp(token, "||") == 0)
635 *btype = FILTER_OP_OR;
636 else if (strcmp(token, "!") == 0)
637 return OP_NOT;
638
639 if (*btype != FILTER_OP_NOT)
640 return OP_BOOL;
641
642 /* Check for value expressions */
643 if (strcmp(token, "+") == 0) {
644 *etype = FILTER_EXP_ADD;
645 } else if (strcmp(token, "-") == 0) {
646 *etype = FILTER_EXP_SUB;
647 } else if (strcmp(token, "*") == 0) {
648 *etype = FILTER_EXP_MUL;
649 } else if (strcmp(token, "/") == 0) {
650 *etype = FILTER_EXP_DIV;
651 } else if (strcmp(token, "%") == 0) {
652 *etype = FILTER_EXP_MOD;
653 } else if (strcmp(token, ">>") == 0) {
654 *etype = FILTER_EXP_RSHIFT;
655 } else if (strcmp(token, "<<") == 0) {
656 *etype = FILTER_EXP_LSHIFT;
657 } else if (strcmp(token, "&") == 0) {
658 *etype = FILTER_EXP_AND;
659 } else if (strcmp(token, "|") == 0) {
660 *etype = FILTER_EXP_OR;
661 } else if (strcmp(token, "^") == 0) {
662 *etype = FILTER_EXP_XOR;
663 } else if (strcmp(token, "~") == 0)
664 *etype = FILTER_EXP_NOT;
665
666 if (*etype != FILTER_EXP_NONE)
667 return OP_EXP;
668
669 /* Check for compares */
670 if (strcmp(token, "==") == 0)
671 *ctype = FILTER_CMP_EQ;
672 else if (strcmp(token, "!=") == 0)
673 *ctype = FILTER_CMP_NE;
674 else if (strcmp(token, "<") == 0)
675 *ctype = FILTER_CMP_LT;
676 else if (strcmp(token, ">") == 0)
677 *ctype = FILTER_CMP_GT;
678 else if (strcmp(token, "<=") == 0)
679 *ctype = FILTER_CMP_LE;
680 else if (strcmp(token, ">=") == 0)
681 *ctype = FILTER_CMP_GE;
682 else if (strcmp(token, "=~") == 0)
683 *ctype = FILTER_CMP_REGEX;
684 else if (strcmp(token, "!~") == 0)
685 *ctype = FILTER_CMP_NOT_REGEX;
686 else
687 return OP_NONE;
688
689 return OP_CMP;
690}
691
692static int check_op_done(struct filter_arg *arg)
693{
694 switch (arg->type) {
695 case FILTER_ARG_EXP:
696 return arg->exp.right != NULL;
697
698 case FILTER_ARG_OP:
699 return arg->op.right != NULL;
700
701 case FILTER_ARG_NUM:
702 return arg->num.right != NULL;
703
704 case FILTER_ARG_STR:
705 /* A string conversion is always done */
706 return 1;
707
708 case FILTER_ARG_BOOLEAN:
709 /* field not found, is ok */
710 return 1;
711
712 default:
713 return 0;
714 }
715}
716
717enum filter_vals {
718 FILTER_VAL_NORM,
719 FILTER_VAL_FALSE,
720 FILTER_VAL_TRUE,
721};
722
723void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
724 struct filter_arg *arg)
725{
726 struct filter_arg *other_child;
727 struct filter_arg **ptr;
728
729 if (parent->type != FILTER_ARG_OP &&
730 arg->type != FILTER_ARG_OP)
731 die("can not reparent other than OP");
732
733 /* Get the sibling */
734 if (old_child->op.right == arg) {
735 ptr = &old_child->op.right;
736 other_child = old_child->op.left;
737 } else if (old_child->op.left == arg) {
738 ptr = &old_child->op.left;
739 other_child = old_child->op.right;
740 } else
741 die("Error in reparent op, find other child");
742
743 /* Detach arg from old_child */
744 *ptr = NULL;
745
746 /* Check for root */
747 if (parent == old_child) {
748 free_arg(other_child);
749 *parent = *arg;
750 /* Free arg without recussion */
751 free(arg);
752 return;
753 }
754
755 if (parent->op.right == old_child)
756 ptr = &parent->op.right;
757 else if (parent->op.left == old_child)
758 ptr = &parent->op.left;
759 else
760 die("Error in reparent op");
761 *ptr = arg;
762
763 free_arg(old_child);
764}
765
766enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg)
767{
768 enum filter_vals lval, rval;
769
770 switch (arg->type) {
771
772 /* bad case */
773 case FILTER_ARG_BOOLEAN:
774 return FILTER_VAL_FALSE + arg->boolean.value;
775
776 /* good cases: */
777 case FILTER_ARG_STR:
778 case FILTER_ARG_VALUE:
779 case FILTER_ARG_FIELD:
780 return FILTER_VAL_NORM;
781
782 case FILTER_ARG_EXP:
783 lval = test_arg(arg, arg->exp.left);
784 if (lval != FILTER_VAL_NORM)
785 return lval;
786 rval = test_arg(arg, arg->exp.right);
787 if (rval != FILTER_VAL_NORM)
788 return rval;
789 return FILTER_VAL_NORM;
790
791 case FILTER_ARG_NUM:
792 lval = test_arg(arg, arg->num.left);
793 if (lval != FILTER_VAL_NORM)
794 return lval;
795 rval = test_arg(arg, arg->num.right);
796 if (rval != FILTER_VAL_NORM)
797 return rval;
798 return FILTER_VAL_NORM;
799
800 case FILTER_ARG_OP:
801 if (arg->op.type != FILTER_OP_NOT) {
802 lval = test_arg(arg, arg->op.left);
803 switch (lval) {
804 case FILTER_VAL_NORM:
805 break;
806 case FILTER_VAL_TRUE:
807 if (arg->op.type == FILTER_OP_OR)
808 return FILTER_VAL_TRUE;
809 rval = test_arg(arg, arg->op.right);
810 if (rval != FILTER_VAL_NORM)
811 return rval;
812
813 reparent_op_arg(parent, arg, arg->op.right);
814 return FILTER_VAL_NORM;
815
816 case FILTER_VAL_FALSE:
817 if (arg->op.type == FILTER_OP_AND)
818 return FILTER_VAL_FALSE;
819 rval = test_arg(arg, arg->op.right);
820 if (rval != FILTER_VAL_NORM)
821 return rval;
822
823 reparent_op_arg(parent, arg, arg->op.right);
824 return FILTER_VAL_NORM;
825 }
826 }
827
828 rval = test_arg(arg, arg->op.right);
829 switch (rval) {
830 case FILTER_VAL_NORM:
831 break;
832 case FILTER_VAL_TRUE:
833 if (arg->op.type == FILTER_OP_OR)
834 return FILTER_VAL_TRUE;
835 if (arg->op.type == FILTER_OP_NOT)
836 return FILTER_VAL_FALSE;
837
838 reparent_op_arg(parent, arg, arg->op.left);
839 return FILTER_VAL_NORM;
840
841 case FILTER_VAL_FALSE:
842 if (arg->op.type == FILTER_OP_AND)
843 return FILTER_VAL_FALSE;
844 if (arg->op.type == FILTER_OP_NOT)
845 return FILTER_VAL_TRUE;
846
847 reparent_op_arg(parent, arg, arg->op.left);
848 return FILTER_VAL_NORM;
849 }
850
851 return FILTER_VAL_NORM;
852 default:
853 die("bad arg in filter tree");
854 }
855 return FILTER_VAL_NORM;
856}
857
858/* Remove any unknown event fields */
859static struct filter_arg *collapse_tree(struct filter_arg *arg)
860{
861 enum filter_vals ret;
862
863 ret = test_arg(arg, arg);
864 switch (ret) {
865 case FILTER_VAL_NORM:
866 return arg;
867
868 case FILTER_VAL_TRUE:
869 case FILTER_VAL_FALSE:
870 free_arg(arg);
871 arg = allocate_arg();
872 arg->type = FILTER_ARG_BOOLEAN;
873 arg->boolean.value = ret == FILTER_VAL_TRUE;
874 }
875
876 return arg;
877}
878
879static int
880process_filter(struct event_format *event, struct filter_arg **parg,
881 char **error_str, int not)
882{
883 enum event_type type;
884 char *token = NULL;
885 struct filter_arg *current_op = NULL;
886 struct filter_arg *current_exp = NULL;
887 struct filter_arg *left_item = NULL;
888 struct filter_arg *arg = NULL;
889 enum op_type op_type;
890 enum filter_op_type btype;
891 enum filter_exp_type etype;
892 enum filter_cmp_type ctype;
893 int ret;
894
895 *parg = NULL;
896
897 do {
898 free(token);
899 type = read_token(&token);
900 switch (type) {
901 case EVENT_SQUOTE:
902 case EVENT_DQUOTE:
903 case EVENT_ITEM:
904 arg = create_arg_item(event, token, type, error_str);
905 if (!arg)
906 goto fail;
907 if (!left_item)
908 left_item = arg;
909 else if (current_exp) {
910 ret = add_right(current_exp, arg, error_str);
911 if (ret < 0)
912 goto fail;
913 left_item = NULL;
914 /* Not's only one one expression */
915 if (not) {
916 arg = NULL;
917 if (current_op)
918 goto fail_print;
919 free(token);
920 *parg = current_exp;
921 return 0;
922 }
923 } else
924 goto fail_print;
925 arg = NULL;
926 break;
927
928 case EVENT_DELIM:
929 if (*token == ',') {
930 show_error(error_str,
931 "Illegal token ','");
932 goto fail;
933 }
934
935 if (*token == '(') {
936 if (left_item) {
937 show_error(error_str,
938 "Open paren can not come after item");
939 goto fail;
940 }
941 if (current_exp) {
942 show_error(error_str,
943 "Open paren can not come after expression");
944 goto fail;
945 }
946
947 ret = process_filter(event, &arg, error_str, 0);
948 if (ret != 1) {
949 if (ret == 0)
950 show_error(error_str,
951 "Unbalanced number of '('");
952 goto fail;
953 }
954 ret = 0;
955
956 /* A not wants just one expression */
957 if (not) {
958 if (current_op)
959 goto fail_print;
960 *parg = arg;
961 return 0;
962 }
963
964 if (current_op)
965 ret = add_right(current_op, arg, error_str);
966 else
967 current_exp = arg;
968
969 if (ret < 0)
970 goto fail;
971
972 } else { /* ')' */
973 if (!current_op && !current_exp)
974 goto fail_print;
975
976 /* Make sure everything is finished at this level */
977 if (current_exp && !check_op_done(current_exp))
978 goto fail_print;
979 if (current_op && !check_op_done(current_op))
980 goto fail_print;
981
982 if (current_op)
983 *parg = current_op;
984 else
985 *parg = current_exp;
986 return 1;
987 }
988 break;
989
990 case EVENT_OP:
991 op_type = process_op(token, &btype, &ctype, &etype);
992
993 /* All expect a left arg except for NOT */
994 switch (op_type) {
995 case OP_BOOL:
996 /* Logic ops need a left expression */
997 if (!current_exp && !current_op)
998 goto fail_print;
999 /* fall through */
1000 case OP_NOT:
1001 /* logic only processes ops and exp */
1002 if (left_item)
1003 goto fail_print;
1004 break;
1005 case OP_EXP:
1006 case OP_CMP:
1007 if (!left_item)
1008 goto fail_print;
1009 break;
1010 case OP_NONE:
1011 show_error(error_str,
1012 "Unknown op token %s", token);
1013 goto fail;
1014 }
1015
1016 ret = 0;
1017 switch (op_type) {
1018 case OP_BOOL:
1019 arg = create_arg_op(btype);
1020 if (current_op)
1021 ret = add_left(arg, current_op);
1022 else
1023 ret = add_left(arg, current_exp);
1024 current_op = arg;
1025 current_exp = NULL;
1026 break;
1027
1028 case OP_NOT:
1029 arg = create_arg_op(btype);
1030 if (current_op)
1031 ret = add_right(current_op, arg, error_str);
1032 if (ret < 0)
1033 goto fail;
1034 current_exp = arg;
1035 ret = process_filter(event, &arg, error_str, 1);
1036 if (ret < 0)
1037 goto fail;
1038 ret = add_right(current_exp, arg, error_str);
1039 if (ret < 0)
1040 goto fail;
1041 break;
1042
1043 case OP_EXP:
1044 case OP_CMP:
1045 if (op_type == OP_EXP)
1046 arg = create_arg_exp(etype);
1047 else
1048 arg = create_arg_cmp(ctype);
1049
1050 if (current_op)
1051 ret = add_right(current_op, arg, error_str);
1052 if (ret < 0)
1053 goto fail;
1054 ret = add_left(arg, left_item);
1055 if (ret < 0) {
1056 arg = NULL;
1057 goto fail_print;
1058 }
1059 current_exp = arg;
1060 break;
1061 default:
1062 break;
1063 }
1064 arg = NULL;
1065 if (ret < 0)
1066 goto fail_print;
1067 break;
1068 case EVENT_NONE:
1069 break;
1070 default:
1071 goto fail_print;
1072 }
1073 } while (type != EVENT_NONE);
1074
1075 if (!current_op && !current_exp)
1076 goto fail_print;
1077
1078 if (!current_op)
1079 current_op = current_exp;
1080
1081 current_op = collapse_tree(current_op);
1082
1083 *parg = current_op;
1084
1085 return 0;
1086
1087 fail_print:
1088 show_error(error_str, "Syntax error");
1089 fail:
1090 free_arg(current_op);
1091 free_arg(current_exp);
1092 free_arg(arg);
1093 free(token);
1094 return -1;
1095}
1096
1097static int
1098process_event(struct event_format *event, const char *filter_str,
1099 struct filter_arg **parg, char **error_str)
1100{
1101 int ret;
1102
1103 pevent_buffer_init(filter_str, strlen(filter_str));
1104
1105 ret = process_filter(event, parg, error_str, 0);
1106 if (ret == 1) {
1107 show_error(error_str,
1108 "Unbalanced number of ')'");
1109 return -1;
1110 }
1111 if (ret < 0)
1112 return ret;
1113
1114 /* If parg is NULL, then make it into FALSE */
1115 if (!*parg) {
1116 *parg = allocate_arg();
1117 (*parg)->type = FILTER_ARG_BOOLEAN;
1118 (*parg)->boolean.value = FILTER_FALSE;
1119 }
1120
1121 return 0;
1122}
1123
1124static int filter_event(struct event_filter *filter,
1125 struct event_format *event,
1126 const char *filter_str, char **error_str)
1127{
1128 struct filter_type *filter_type;
1129 struct filter_arg *arg;
1130 int ret;
1131
1132 if (filter_str) {
1133 ret = process_event(event, filter_str, &arg, error_str);
1134 if (ret < 0)
1135 return ret;
1136
1137 } else {
1138 /* just add a TRUE arg */
1139 arg = allocate_arg();
1140 arg->type = FILTER_ARG_BOOLEAN;
1141 arg->boolean.value = FILTER_TRUE;
1142 }
1143
1144 filter_type = add_filter_type(filter, event->id);
1145 if (filter_type->filter)
1146 free_arg(filter_type->filter);
1147 filter_type->filter = arg;
1148
1149 return 0;
1150}
1151
1152/**
1153 * pevent_filter_add_filter_str - add a new filter
1154 * @filter: the event filter to add to
1155 * @filter_str: the filter string that contains the filter
1156 * @error_str: string containing reason for failed filter
1157 *
1158 * Returns 0 if the filter was successfully added
1159 * -1 if there was an error.
1160 *
1161 * On error, if @error_str points to a string pointer,
1162 * it is set to the reason that the filter failed.
1163 * This string must be freed with "free".
1164 */
1165int pevent_filter_add_filter_str(struct event_filter *filter,
1166 const char *filter_str,
1167 char **error_str)
1168{
1169 struct pevent *pevent = filter->pevent;
1170 struct event_list *event;
1171 struct event_list *events = NULL;
1172 const char *filter_start;
1173 const char *next_event;
1174 char *this_event;
1175 char *event_name = NULL;
1176 char *sys_name = NULL;
1177 char *sp;
1178 int rtn = 0;
1179 int len;
1180 int ret;
1181
1182 /* clear buffer to reset show error */
1183 pevent_buffer_init("", 0);
1184
1185 if (error_str)
1186 *error_str = NULL;
1187
1188 filter_start = strchr(filter_str, ':');
1189 if (filter_start)
1190 len = filter_start - filter_str;
1191 else
1192 len = strlen(filter_str);
1193
1194
1195 do {
1196 next_event = strchr(filter_str, ',');
1197 if (next_event &&
1198 (!filter_start || next_event < filter_start))
1199 len = next_event - filter_str;
1200 else if (filter_start)
1201 len = filter_start - filter_str;
1202 else
1203 len = strlen(filter_str);
1204
1205 this_event = malloc_or_die(len + 1);
1206 memcpy(this_event, filter_str, len);
1207 this_event[len] = 0;
1208
1209 if (next_event)
1210 next_event++;
1211
1212 filter_str = next_event;
1213
1214 sys_name = strtok_r(this_event, "/", &sp);
1215 event_name = strtok_r(NULL, "/", &sp);
1216
1217 if (!sys_name) {
1218 show_error(error_str, "No filter found");
1219 /* This can only happen when events is NULL, but still */
1220 free_events(events);
1221 free(this_event);
1222 return -1;
1223 }
1224
1225 /* Find this event */
1226 ret = find_event(pevent, &events, strim(sys_name), strim(event_name));
1227 if (ret < 0) {
1228 if (event_name)
1229 show_error(error_str,
1230 "No event found under '%s.%s'",
1231 sys_name, event_name);
1232 else
1233 show_error(error_str,
1234 "No event found under '%s'",
1235 sys_name);
1236 free_events(events);
1237 free(this_event);
1238 return -1;
1239 }
1240 free(this_event);
1241 } while (filter_str);
1242
1243 /* Skip the ':' */
1244 if (filter_start)
1245 filter_start++;
1246
1247 /* filter starts here */
1248 for (event = events; event; event = event->next) {
1249 ret = filter_event(filter, event->event, filter_start,
1250 error_str);
1251 /* Failures are returned if a parse error happened */
1252 if (ret < 0)
1253 rtn = ret;
1254
1255 if (ret >= 0 && pevent->test_filters) {
1256 char *test;
1257 test = pevent_filter_make_string(filter, event->event->id);
1258 printf(" '%s: %s'\n", event->event->name, test);
1259 free(test);
1260 }
1261 }
1262
1263 free_events(events);
1264
1265 if (rtn >= 0 && pevent->test_filters)
1266 exit(0);
1267
1268 return rtn;
1269}
1270
1271static void free_filter_type(struct filter_type *filter_type)
1272{
1273 free_arg(filter_type->filter);
1274}
1275
1276/**
1277 * pevent_filter_remove_event - remove a filter for an event
1278 * @filter: the event filter to remove from
1279 * @event_id: the event to remove a filter for
1280 *
1281 * Removes the filter saved for an event defined by @event_id
1282 * from the @filter.
1283 *
1284 * Returns 1: if an event was removed
1285 * 0: if the event was not found
1286 */
1287int pevent_filter_remove_event(struct event_filter *filter,
1288 int event_id)
1289{
1290 struct filter_type *filter_type;
1291 unsigned long len;
1292
1293 if (!filter->filters)
1294 return 0;
1295
1296 filter_type = find_filter_type(filter, event_id);
1297
1298 if (!filter_type)
1299 return 0;
1300
1301 free_filter_type(filter_type);
1302
1303 /* The filter_type points into the event_filters array */
1304 len = (unsigned long)(filter->event_filters + filter->filters) -
1305 (unsigned long)(filter_type + 1);
1306
1307 memmove(filter_type, filter_type + 1, len);
1308 filter->filters--;
1309
1310 memset(&filter->event_filters[filter->filters], 0,
1311 sizeof(*filter_type));
1312
1313 return 1;
1314}
1315
1316/**
1317 * pevent_filter_reset - clear all filters in a filter
1318 * @filter: the event filter to reset
1319 *
1320 * Removes all filters from a filter and resets it.
1321 */
1322void pevent_filter_reset(struct event_filter *filter)
1323{
1324 int i;
1325
1326 for (i = 0; i < filter->filters; i++)
1327 free_filter_type(&filter->event_filters[i]);
1328
1329 free(filter->event_filters);
1330 filter->filters = 0;
1331 filter->event_filters = NULL;
1332}
1333
1334void pevent_filter_free(struct event_filter *filter)
1335{
1336 pevent_unref(filter->pevent);
1337
1338 pevent_filter_reset(filter);
1339
1340 free(filter);
1341}
1342
1343static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg);
1344
1345static int copy_filter_type(struct event_filter *filter,
1346 struct event_filter *source,
1347 struct filter_type *filter_type)
1348{
1349 struct filter_arg *arg;
1350 struct event_format *event;
1351 const char *sys;
1352 const char *name;
1353 char *str;
1354
1355 /* Can't assume that the pevent's are the same */
1356 sys = filter_type->event->system;
1357 name = filter_type->event->name;
1358 event = pevent_find_event_by_name(filter->pevent, sys, name);
1359 if (!event)
1360 return -1;
1361
1362 str = arg_to_str(source, filter_type->filter);
1363 if (!str)
1364 return -1;
1365
1366 if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) {
1367 /* Add trivial event */
1368 arg = allocate_arg();
1369 arg->type = FILTER_ARG_BOOLEAN;
1370 if (strcmp(str, "TRUE") == 0)
1371 arg->boolean.value = 1;
1372 else
1373 arg->boolean.value = 0;
1374
1375 filter_type = add_filter_type(filter, event->id);
1376 filter_type->filter = arg;
1377
1378 free(str);
1379 return 0;
1380 }
1381
1382 filter_event(filter, event, str, NULL);
1383 free(str);
1384
1385 return 0;
1386}
1387
1388/**
1389 * pevent_filter_copy - copy a filter using another filter
1390 * @dest - the filter to copy to
1391 * @source - the filter to copy from
1392 *
1393 * Returns 0 on success and -1 if not all filters were copied
1394 */
1395int pevent_filter_copy(struct event_filter *dest, struct event_filter *source)
1396{
1397 int ret = 0;
1398 int i;
1399
1400 pevent_filter_reset(dest);
1401
1402 for (i = 0; i < source->filters; i++) {
1403 if (copy_filter_type(dest, source, &source->event_filters[i]))
1404 ret = -1;
1405 }
1406 return ret;
1407}
1408
1409
1410/**
1411 * pevent_update_trivial - update the trivial filters with the given filter
1412 * @dest - the filter to update
1413 * @source - the filter as the source of the update
1414 * @type - the type of trivial filter to update.
1415 *
1416 * Scan dest for trivial events matching @type to replace with the source.
1417 *
1418 * Returns 0 on success and -1 if there was a problem updating, but
1419 * events may have still been updated on error.
1420 */
1421int pevent_update_trivial(struct event_filter *dest, struct event_filter *source,
1422 enum filter_trivial_type type)
1423{
1424 struct pevent *src_pevent;
1425 struct pevent *dest_pevent;
1426 struct event_format *event;
1427 struct filter_type *filter_type;
1428 struct filter_arg *arg;
1429 char *str;
1430 int i;
1431
1432 src_pevent = source->pevent;
1433 dest_pevent = dest->pevent;
1434
1435 /* Do nothing if either of the filters has nothing to filter */
1436 if (!dest->filters || !source->filters)
1437 return 0;
1438
1439 for (i = 0; i < dest->filters; i++) {
1440 filter_type = &dest->event_filters[i];
1441 arg = filter_type->filter;
1442 if (arg->type != FILTER_ARG_BOOLEAN)
1443 continue;
1444 if ((arg->boolean.value && type == FILTER_TRIVIAL_FALSE) ||
1445 (!arg->boolean.value && type == FILTER_TRIVIAL_TRUE))
1446 continue;
1447
1448 event = filter_type->event;
1449
1450 if (src_pevent != dest_pevent) {
1451 /* do a look up */
1452 event = pevent_find_event_by_name(src_pevent,
1453 event->system,
1454 event->name);
1455 if (!event)
1456 return -1;
1457 }
1458
1459 str = pevent_filter_make_string(source, event->id);
1460 if (!str)
1461 continue;
1462
1463 /* Don't bother if the filter is trivial too */
1464 if (strcmp(str, "TRUE") != 0 && strcmp(str, "FALSE") != 0)
1465 filter_event(dest, event, str, NULL);
1466 free(str);
1467 }
1468 return 0;
1469}
1470
1471/**
1472 * pevent_filter_clear_trivial - clear TRUE and FALSE filters
1473 * @filter: the filter to remove trivial filters from
1474 * @type: remove only true, false, or both
1475 *
1476 * Removes filters that only contain a TRUE or FALES boolean arg.
1477 */
1478void pevent_filter_clear_trivial(struct event_filter *filter,
1479 enum filter_trivial_type type)
1480{
1481 struct filter_type *filter_type;
1482 int count = 0;
1483 int *ids;
1484 int i;
1485
1486 if (!filter->filters)
1487 return;
1488
1489 /*
1490 * Two steps, first get all ids with trivial filters.
1491 * then remove those ids.
1492 */
1493 for (i = 0; i < filter->filters; i++) {
1494 filter_type = &filter->event_filters[i];
1495 if (filter_type->filter->type != FILTER_ARG_BOOLEAN)
1496 continue;
1497 switch (type) {
1498 case FILTER_TRIVIAL_FALSE:
1499 if (filter_type->filter->boolean.value)
1500 continue;
1501 case FILTER_TRIVIAL_TRUE:
1502 if (!filter_type->filter->boolean.value)
1503 continue;
1504 default:
1505 break;
1506 }
1507 if (count)
1508 ids = realloc(ids, sizeof(*ids) * (count + 1));
1509 else
1510 ids = malloc(sizeof(*ids));
1511 if (!ids)
1512 die("Can't allocate ids");
1513 ids[count++] = filter_type->event_id;
1514 }
1515
1516 if (!count)
1517 return;
1518
1519 for (i = 0; i < count; i++)
1520 pevent_filter_remove_event(filter, ids[i]);
1521
1522 free(ids);
1523}
1524
1525/**
1526 * pevent_filter_event_has_trivial - return true event contains trivial filter
1527 * @filter: the filter with the information
1528 * @event_id: the id of the event to test
1529 * @type: trivial type to test for (TRUE, FALSE, EITHER)
1530 *
1531 * Returns 1 if the event contains a matching trivial type
1532 * otherwise 0.
1533 */
1534int pevent_filter_event_has_trivial(struct event_filter *filter,
1535 int event_id,
1536 enum filter_trivial_type type)
1537{
1538 struct filter_type *filter_type;
1539
1540 if (!filter->filters)
1541 return 0;
1542
1543 filter_type = find_filter_type(filter, event_id);
1544
1545 if (!filter_type)
1546 return 0;
1547
1548 if (filter_type->filter->type != FILTER_ARG_BOOLEAN)
1549 return 0;
1550
1551 switch (type) {
1552 case FILTER_TRIVIAL_FALSE:
1553 return !filter_type->filter->boolean.value;
1554
1555 case FILTER_TRIVIAL_TRUE:
1556 return filter_type->filter->boolean.value;
1557 default:
1558 return 1;
1559 }
1560}
1561
1562static int test_filter(struct event_format *event,
1563 struct filter_arg *arg, struct pevent_record *record);
1564
1565static const char *
1566get_comm(struct event_format *event, struct pevent_record *record)
1567{
1568 const char *comm;
1569 int pid;
1570
1571 pid = pevent_data_pid(event->pevent, record);
1572 comm = pevent_data_comm_from_pid(event->pevent, pid);
1573 return comm;
1574}
1575
1576static unsigned long long
1577get_value(struct event_format *event,
1578 struct format_field *field, struct pevent_record *record)
1579{
1580 unsigned long long val;
1581
1582 /* Handle our dummy "comm" field */
1583 if (field == &comm) {
1584 const char *name;
1585
1586 name = get_comm(event, record);
1587 return (unsigned long)name;
1588 }
1589
1590 pevent_read_number_field(field, record->data, &val);
1591
1592 if (!(field->flags & FIELD_IS_SIGNED))
1593 return val;
1594
1595 switch (field->size) {
1596 case 1:
1597 return (char)val;
1598 case 2:
1599 return (short)val;
1600 case 4:
1601 return (int)val;
1602 case 8:
1603 return (long long)val;
1604 }
1605 return val;
1606}
1607
1608static unsigned long long
1609get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record);
1610
1611static unsigned long long
1612get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record)
1613{
1614 unsigned long long lval, rval;
1615
1616 lval = get_arg_value(event, arg->exp.left, record);
1617 rval = get_arg_value(event, arg->exp.right, record);
1618
1619 switch (arg->exp.type) {
1620 case FILTER_EXP_ADD:
1621 return lval + rval;
1622
1623 case FILTER_EXP_SUB:
1624 return lval - rval;
1625
1626 case FILTER_EXP_MUL:
1627 return lval * rval;
1628
1629 case FILTER_EXP_DIV:
1630 return lval / rval;
1631
1632 case FILTER_EXP_MOD:
1633 return lval % rval;
1634
1635 case FILTER_EXP_RSHIFT:
1636 return lval >> rval;
1637
1638 case FILTER_EXP_LSHIFT:
1639 return lval << rval;
1640
1641 case FILTER_EXP_AND:
1642 return lval & rval;
1643
1644 case FILTER_EXP_OR:
1645 return lval | rval;
1646
1647 case FILTER_EXP_XOR:
1648 return lval ^ rval;
1649
1650 case FILTER_EXP_NOT:
1651 default:
1652 die("error in exp");
1653 }
1654 return 0;
1655}
1656
1657static unsigned long long
1658get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record)
1659{
1660 switch (arg->type) {
1661 case FILTER_ARG_FIELD:
1662 return get_value(event, arg->field.field, record);
1663
1664 case FILTER_ARG_VALUE:
1665 if (arg->value.type != FILTER_NUMBER)
1666 die("must have number field!");
1667 return arg->value.val;
1668
1669 case FILTER_ARG_EXP:
1670 return get_exp_value(event, arg, record);
1671
1672 default:
1673 die("oops in filter");
1674 }
1675 return 0;
1676}
1677
1678static int test_num(struct event_format *event,
1679 struct filter_arg *arg, struct pevent_record *record)
1680{
1681 unsigned long long lval, rval;
1682
1683 lval = get_arg_value(event, arg->num.left, record);
1684 rval = get_arg_value(event, arg->num.right, record);
1685
1686 switch (arg->num.type) {
1687 case FILTER_CMP_EQ:
1688 return lval == rval;
1689
1690 case FILTER_CMP_NE:
1691 return lval != rval;
1692
1693 case FILTER_CMP_GT:
1694 return lval > rval;
1695
1696 case FILTER_CMP_LT:
1697 return lval < rval;
1698
1699 case FILTER_CMP_GE:
1700 return lval >= rval;
1701
1702 case FILTER_CMP_LE:
1703 return lval <= rval;
1704
1705 default:
1706 /* ?? */
1707 return 0;
1708 }
1709}
1710
1711static const char *get_field_str(struct filter_arg *arg, struct pevent_record *record)
1712{
1713 const char *val = record->data + arg->str.field->offset;
1714
1715 /*
1716 * We need to copy the data since we can't be sure the field
1717 * is null terminated.
1718 */
1719 if (*(val + arg->str.field->size - 1)) {
1720 /* copy it */
1721 memcpy(arg->str.buffer, val, arg->str.field->size);
1722 /* the buffer is already NULL terminated */
1723 val = arg->str.buffer;
1724 }
1725 return val;
1726}
1727
1728static int test_str(struct event_format *event,
1729 struct filter_arg *arg, struct pevent_record *record)
1730{
1731 const char *val;
1732
1733 if (arg->str.field == &comm)
1734 val = get_comm(event, record);
1735 else
1736 val = get_field_str(arg, record);
1737
1738 switch (arg->str.type) {
1739 case FILTER_CMP_MATCH:
1740 return strcmp(val, arg->str.val) == 0;
1741
1742 case FILTER_CMP_NOT_MATCH:
1743 return strcmp(val, arg->str.val) != 0;
1744
1745 case FILTER_CMP_REGEX:
1746 /* Returns zero on match */
1747 return !regexec(&arg->str.reg, val, 0, NULL, 0);
1748
1749 case FILTER_CMP_NOT_REGEX:
1750 return regexec(&arg->str.reg, val, 0, NULL, 0);
1751
1752 default:
1753 /* ?? */
1754 return 0;
1755 }
1756}
1757
1758static int test_op(struct event_format *event,
1759 struct filter_arg *arg, struct pevent_record *record)
1760{
1761 switch (arg->op.type) {
1762 case FILTER_OP_AND:
1763 return test_filter(event, arg->op.left, record) &&
1764 test_filter(event, arg->op.right, record);
1765
1766 case FILTER_OP_OR:
1767 return test_filter(event, arg->op.left, record) ||
1768 test_filter(event, arg->op.right, record);
1769
1770 case FILTER_OP_NOT:
1771 return !test_filter(event, arg->op.right, record);
1772
1773 default:
1774 /* ?? */
1775 return 0;
1776 }
1777}
1778
1779static int test_filter(struct event_format *event,
1780 struct filter_arg *arg, struct pevent_record *record)
1781{
1782 switch (arg->type) {
1783 case FILTER_ARG_BOOLEAN:
1784 /* easy case */
1785 return arg->boolean.value;
1786
1787 case FILTER_ARG_OP:
1788 return test_op(event, arg, record);
1789
1790 case FILTER_ARG_NUM:
1791 return test_num(event, arg, record);
1792
1793 case FILTER_ARG_STR:
1794 return test_str(event, arg, record);
1795
1796 case FILTER_ARG_EXP:
1797 case FILTER_ARG_VALUE:
1798 case FILTER_ARG_FIELD:
1799 /*
1800 * Expressions, fields and values evaluate
1801 * to true if they return non zero
1802 */
1803 return !!get_arg_value(event, arg, record);
1804
1805 default:
1806 die("oops!");
1807 /* ?? */
1808 return 0;
1809 }
1810}
1811
1812/**
1813 * pevent_event_filtered - return true if event has filter
1814 * @filter: filter struct with filter information
1815 * @event_id: event id to test if filter exists
1816 *
1817 * Returns 1 if filter found for @event_id
1818 * otherwise 0;
1819 */
1820int pevent_event_filtered(struct event_filter *filter,
1821 int event_id)
1822{
1823 struct filter_type *filter_type;
1824
1825 if (!filter->filters)
1826 return 0;
1827
1828 filter_type = find_filter_type(filter, event_id);
1829
1830 return filter_type ? 1 : 0;
1831}
1832
1833/**
1834 * pevent_filter_match - test if a record matches a filter
1835 * @filter: filter struct with filter information
1836 * @record: the record to test against the filter
1837 *
1838 * Returns:
1839 * 1 - filter found for event and @record matches
1840 * 0 - filter found for event and @record does not match
1841 * -1 - no filter found for @record's event
1842 * -2 - if no filters exist
1843 */
1844int pevent_filter_match(struct event_filter *filter,
1845 struct pevent_record *record)
1846{
1847 struct pevent *pevent = filter->pevent;
1848 struct filter_type *filter_type;
1849 int event_id;
1850
1851 if (!filter->filters)
1852 return FILTER_NONE;
1853
1854 event_id = pevent_data_type(pevent, record);
1855
1856 filter_type = find_filter_type(filter, event_id);
1857
1858 if (!filter_type)
1859 return FILTER_NOEXIST;
1860
1861 return test_filter(filter_type->event, filter_type->filter, record) ?
1862 FILTER_MATCH : FILTER_MISS;
1863}
1864
1865static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
1866{
1867 char *str = NULL;
1868 char *left = NULL;
1869 char *right = NULL;
1870 char *op = NULL;
1871 int left_val = -1;
1872 int right_val = -1;
1873 int val;
1874 int len;
1875
1876 switch (arg->op.type) {
1877 case FILTER_OP_AND:
1878 op = "&&";
1879 /* fall through */
1880 case FILTER_OP_OR:
1881 if (!op)
1882 op = "||";
1883
1884 left = arg_to_str(filter, arg->op.left);
1885 right = arg_to_str(filter, arg->op.right);
1886 if (!left || !right)
1887 break;
1888
1889 /* Try to consolidate boolean values */
1890 if (strcmp(left, "TRUE") == 0)
1891 left_val = 1;
1892 else if (strcmp(left, "FALSE") == 0)
1893 left_val = 0;
1894
1895 if (strcmp(right, "TRUE") == 0)
1896 right_val = 1;
1897 else if (strcmp(right, "FALSE") == 0)
1898 right_val = 0;
1899
1900 if (left_val >= 0) {
1901 if ((arg->op.type == FILTER_OP_AND && !left_val) ||
1902 (arg->op.type == FILTER_OP_OR && left_val)) {
1903 /* Just return left value */
1904 str = left;
1905 left = NULL;
1906 break;
1907 }
1908 if (right_val >= 0) {
1909 /* just evaluate this. */
1910 val = 0;
1911 switch (arg->op.type) {
1912 case FILTER_OP_AND:
1913 val = left_val && right_val;
1914 break;
1915 case FILTER_OP_OR:
1916 val = left_val || right_val;
1917 break;
1918 default:
1919 break;
1920 }
1921 str = malloc_or_die(6);
1922 if (val)
1923 strcpy(str, "TRUE");
1924 else
1925 strcpy(str, "FALSE");
1926 break;
1927 }
1928 }
1929 if (right_val >= 0) {
1930 if ((arg->op.type == FILTER_OP_AND && !right_val) ||
1931 (arg->op.type == FILTER_OP_OR && right_val)) {
1932 /* Just return right value */
1933 str = right;
1934 right = NULL;
1935 break;
1936 }
1937 /* The right value is meaningless */
1938 str = left;
1939 left = NULL;
1940 break;
1941 }
1942
1943 len = strlen(left) + strlen(right) + strlen(op) + 10;
1944 str = malloc_or_die(len);
1945 snprintf(str, len, "(%s) %s (%s)",
1946 left, op, right);
1947 break;
1948
1949 case FILTER_OP_NOT:
1950 op = "!";
1951 right = arg_to_str(filter, arg->op.right);
1952 if (!right)
1953 break;
1954
1955 /* See if we can consolidate */
1956 if (strcmp(right, "TRUE") == 0)
1957 right_val = 1;
1958 else if (strcmp(right, "FALSE") == 0)
1959 right_val = 0;
1960 if (right_val >= 0) {
1961 /* just return the opposite */
1962 str = malloc_or_die(6);
1963 if (right_val)
1964 strcpy(str, "FALSE");
1965 else
1966 strcpy(str, "TRUE");
1967 break;
1968 }
1969 len = strlen(right) + strlen(op) + 3;
1970 str = malloc_or_die(len);
1971 snprintf(str, len, "%s(%s)", op, right);
1972 break;
1973
1974 default:
1975 /* ?? */
1976 break;
1977 }
1978 free(left);
1979 free(right);
1980 return str;
1981}
1982
1983static char *val_to_str(struct event_filter *filter, struct filter_arg *arg)
1984{
1985 char *str;
1986
1987 str = malloc_or_die(30);
1988
1989 snprintf(str, 30, "%lld", arg->value.val);
1990
1991 return str;
1992}
1993
1994static char *field_to_str(struct event_filter *filter, struct filter_arg *arg)
1995{
1996 return strdup(arg->field.field->name);
1997}
1998
1999static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
2000{
2001 char *lstr;
2002 char *rstr;
2003 char *op;
2004 char *str;
2005 int len;
2006
2007 lstr = arg_to_str(filter, arg->exp.left);
2008 rstr = arg_to_str(filter, arg->exp.right);
2009
2010 switch (arg->exp.type) {
2011 case FILTER_EXP_ADD:
2012 op = "+";
2013 break;
2014 case FILTER_EXP_SUB:
2015 op = "-";
2016 break;
2017 case FILTER_EXP_MUL:
2018 op = "*";
2019 break;
2020 case FILTER_EXP_DIV:
2021 op = "/";
2022 break;
2023 case FILTER_EXP_MOD:
2024 op = "%";
2025 break;
2026 case FILTER_EXP_RSHIFT:
2027 op = ">>";
2028 break;
2029 case FILTER_EXP_LSHIFT:
2030 op = "<<";
2031 break;
2032 case FILTER_EXP_AND:
2033 op = "&";
2034 break;
2035 case FILTER_EXP_OR:
2036 op = "|";
2037 break;
2038 case FILTER_EXP_XOR:
2039 op = "^";
2040 break;
2041 default:
2042 die("oops in exp");
2043 }
2044
2045 len = strlen(op) + strlen(lstr) + strlen(rstr) + 4;
2046 str = malloc_or_die(len);
2047 snprintf(str, len, "%s %s %s", lstr, op, rstr);
2048 free(lstr);
2049 free(rstr);
2050
2051 return str;
2052}
2053
2054static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
2055{
2056 char *lstr;
2057 char *rstr;
2058 char *str = NULL;
2059 char *op = NULL;
2060 int len;
2061
2062 lstr = arg_to_str(filter, arg->num.left);
2063 rstr = arg_to_str(filter, arg->num.right);
2064
2065 switch (arg->num.type) {
2066 case FILTER_CMP_EQ:
2067 op = "==";
2068 /* fall through */
2069 case FILTER_CMP_NE:
2070 if (!op)
2071 op = "!=";
2072 /* fall through */
2073 case FILTER_CMP_GT:
2074 if (!op)
2075 op = ">";
2076 /* fall through */
2077 case FILTER_CMP_LT:
2078 if (!op)
2079 op = "<";
2080 /* fall through */
2081 case FILTER_CMP_GE:
2082 if (!op)
2083 op = ">=";
2084 /* fall through */
2085 case FILTER_CMP_LE:
2086 if (!op)
2087 op = "<=";
2088
2089 len = strlen(lstr) + strlen(op) + strlen(rstr) + 4;
2090 str = malloc_or_die(len);
2091 sprintf(str, "%s %s %s", lstr, op, rstr);
2092
2093 break;
2094
2095 default:
2096 /* ?? */
2097 break;
2098 }
2099
2100 free(lstr);
2101 free(rstr);
2102 return str;
2103}
2104
2105static char *str_to_str(struct event_filter *filter, struct filter_arg *arg)
2106{
2107 char *str = NULL;
2108 char *op = NULL;
2109 int len;
2110
2111 switch (arg->str.type) {
2112 case FILTER_CMP_MATCH:
2113 op = "==";
2114 /* fall through */
2115 case FILTER_CMP_NOT_MATCH:
2116 if (!op)
2117 op = "!=";
2118 /* fall through */
2119 case FILTER_CMP_REGEX:
2120 if (!op)
2121 op = "=~";
2122 /* fall through */
2123 case FILTER_CMP_NOT_REGEX:
2124 if (!op)
2125 op = "!~";
2126
2127 len = strlen(arg->str.field->name) + strlen(op) +
2128 strlen(arg->str.val) + 6;
2129 str = malloc_or_die(len);
2130 snprintf(str, len, "%s %s \"%s\"",
2131 arg->str.field->name,
2132 op, arg->str.val);
2133 break;
2134
2135 default:
2136 /* ?? */
2137 break;
2138 }
2139 return str;
2140}
2141
2142static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)
2143{
2144 char *str;
2145
2146 switch (arg->type) {
2147 case FILTER_ARG_BOOLEAN:
2148 str = malloc_or_die(6);
2149 if (arg->boolean.value)
2150 strcpy(str, "TRUE");
2151 else
2152 strcpy(str, "FALSE");
2153 return str;
2154
2155 case FILTER_ARG_OP:
2156 return op_to_str(filter, arg);
2157
2158 case FILTER_ARG_NUM:
2159 return num_to_str(filter, arg);
2160
2161 case FILTER_ARG_STR:
2162 return str_to_str(filter, arg);
2163
2164 case FILTER_ARG_VALUE:
2165 return val_to_str(filter, arg);
2166
2167 case FILTER_ARG_FIELD:
2168 return field_to_str(filter, arg);
2169
2170 case FILTER_ARG_EXP:
2171 return exp_to_str(filter, arg);
2172
2173 default:
2174 /* ?? */
2175 return NULL;
2176 }
2177
2178}
2179
2180/**
2181 * pevent_filter_make_string - return a string showing the filter
2182 * @filter: filter struct with filter information
2183 * @event_id: the event id to return the filter string with
2184 *
2185 * Returns a string that displays the filter contents.
2186 * This string must be freed with free(str).
2187 * NULL is returned if no filter is found.
2188 */
2189char *
2190pevent_filter_make_string(struct event_filter *filter, int event_id)
2191{
2192 struct filter_type *filter_type;
2193
2194 if (!filter->filters)
2195 return NULL;
2196
2197 filter_type = find_filter_type(filter, event_id);
2198
2199 if (!filter_type)
2200 return NULL;
2201
2202 return arg_to_str(filter, filter_type->filter);
2203}
2204
2205/**
2206 * pevent_filter_compare - compare two filters and return if they are the same
2207 * @filter1: Filter to compare with @filter2
2208 * @filter2: Filter to compare with @filter1
2209 *
2210 * Returns:
2211 * 1 if the two filters hold the same content.
2212 * 0 if they do not.
2213 */
2214int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2)
2215{
2216 struct filter_type *filter_type1;
2217 struct filter_type *filter_type2;
2218 char *str1, *str2;
2219 int result;
2220 int i;
2221
2222 /* Do the easy checks first */
2223 if (filter1->filters != filter2->filters)
2224 return 0;
2225 if (!filter1->filters && !filter2->filters)
2226 return 1;
2227
2228 /*
2229 * Now take a look at each of the events to see if they have the same
2230 * filters to them.
2231 */
2232 for (i = 0; i < filter1->filters; i++) {
2233 filter_type1 = &filter1->event_filters[i];
2234 filter_type2 = find_filter_type(filter2, filter_type1->event_id);
2235 if (!filter_type2)
2236 break;
2237 if (filter_type1->filter->type != filter_type2->filter->type)
2238 break;
2239 switch (filter_type1->filter->type) {
2240 case FILTER_TRIVIAL_FALSE:
2241 case FILTER_TRIVIAL_TRUE:
2242 /* trivial types just need the type compared */
2243 continue;
2244 default:
2245 break;
2246 }
2247 /* The best way to compare complex filters is with strings */
2248 str1 = arg_to_str(filter1, filter_type1->filter);
2249 str2 = arg_to_str(filter2, filter_type2->filter);
2250 result = strcmp(str1, str2) != 0;
2251 free(str1);
2252 free(str2);
2253 if (result)
2254 break;
2255 }
2256
2257 if (i < filter1->filters)
2258 return 0;
2259 return 1;
2260}
2261
diff --git a/tools/lib/traceevent/parse-utils.c b/tools/lib/traceevent/parse-utils.c
new file mode 100644
index 000000000000..f023a133abb6
--- /dev/null
+++ b/tools/lib/traceevent/parse-utils.c
@@ -0,0 +1,110 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <stdarg.h>
5#include <errno.h>
6
7#define __weak __attribute__((weak))
8
9void __vdie(const char *fmt, va_list ap)
10{
11 int ret = errno;
12
13 if (errno)
14 perror("trace-cmd");
15 else
16 ret = -1;
17
18 fprintf(stderr, " ");
19 vfprintf(stderr, fmt, ap);
20
21 fprintf(stderr, "\n");
22 exit(ret);
23}
24
25void __die(const char *fmt, ...)
26{
27 va_list ap;
28
29 va_start(ap, fmt);
30 __vdie(fmt, ap);
31 va_end(ap);
32}
33
34void __weak die(const char *fmt, ...)
35{
36 va_list ap;
37
38 va_start(ap, fmt);
39 __vdie(fmt, ap);
40 va_end(ap);
41}
42
43void __vwarning(const char *fmt, va_list ap)
44{
45 if (errno)
46 perror("trace-cmd");
47 errno = 0;
48
49 fprintf(stderr, " ");
50 vfprintf(stderr, fmt, ap);
51
52 fprintf(stderr, "\n");
53}
54
55void __warning(const char *fmt, ...)
56{
57 va_list ap;
58
59 va_start(ap, fmt);
60 __vwarning(fmt, ap);
61 va_end(ap);
62}
63
64void __weak warning(const char *fmt, ...)
65{
66 va_list ap;
67
68 va_start(ap, fmt);
69 __vwarning(fmt, ap);
70 va_end(ap);
71}
72
73void __vpr_stat(const char *fmt, va_list ap)
74{
75 vprintf(fmt, ap);
76 printf("\n");
77}
78
79void __pr_stat(const char *fmt, ...)
80{
81 va_list ap;
82
83 va_start(ap, fmt);
84 __vpr_stat(fmt, ap);
85 va_end(ap);
86}
87
88void __weak vpr_stat(const char *fmt, va_list ap)
89{
90 __vpr_stat(fmt, ap);
91}
92
93void __weak pr_stat(const char *fmt, ...)
94{
95 va_list ap;
96
97 va_start(ap, fmt);
98 __vpr_stat(fmt, ap);
99 va_end(ap);
100}
101
102void __weak *malloc_or_die(unsigned int size)
103{
104 void *data;
105
106 data = malloc(size);
107 if (!data)
108 die("malloc");
109 return data;
110}
diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c
new file mode 100644
index 000000000000..b1ccc923e8a5
--- /dev/null
+++ b/tools/lib/traceevent/trace-seq.c
@@ -0,0 +1,200 @@
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, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <stdarg.h>
25
26#include "event-parse.h"
27#include "event-utils.h"
28
29/*
30 * The TRACE_SEQ_POISON is to catch the use of using
31 * a trace_seq structure after it was destroyed.
32 */
33#define TRACE_SEQ_POISON ((void *)0xdeadbeef)
34#define TRACE_SEQ_CHECK(s) \
35do { \
36 if ((s)->buffer == TRACE_SEQ_POISON) \
37 die("Usage of trace_seq after it was destroyed"); \
38} while (0)
39
40/**
41 * trace_seq_init - initialize the trace_seq structure
42 * @s: a pointer to the trace_seq structure to initialize
43 */
44void trace_seq_init(struct trace_seq *s)
45{
46 s->len = 0;
47 s->readpos = 0;
48 s->buffer_size = TRACE_SEQ_BUF_SIZE;
49 s->buffer = malloc_or_die(s->buffer_size);
50}
51
52/**
53 * trace_seq_destroy - free up memory of a trace_seq
54 * @s: a pointer to the trace_seq to free the buffer
55 *
56 * Only frees the buffer, not the trace_seq struct itself.
57 */
58void trace_seq_destroy(struct trace_seq *s)
59{
60 if (!s)
61 return;
62 TRACE_SEQ_CHECK(s);
63 free(s->buffer);
64 s->buffer = TRACE_SEQ_POISON;
65}
66
67static void expand_buffer(struct trace_seq *s)
68{
69 s->buffer_size += TRACE_SEQ_BUF_SIZE;
70 s->buffer = realloc(s->buffer, s->buffer_size);
71 if (!s->buffer)
72 die("Can't allocate trace_seq buffer memory");
73}
74
75/**
76 * trace_seq_printf - sequence printing of trace information
77 * @s: trace sequence descriptor
78 * @fmt: printf format string
79 *
80 * It returns 0 if the trace oversizes the buffer's free
81 * space, 1 otherwise.
82 *
83 * The tracer may use either sequence operations or its own
84 * copy to user routines. To simplify formating of a trace
85 * trace_seq_printf is used to store strings into a special
86 * buffer (@s). Then the output may be either used by
87 * the sequencer or pulled into another buffer.
88 */
89int
90trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
91{
92 va_list ap;
93 int len;
94 int ret;
95
96 TRACE_SEQ_CHECK(s);
97
98 try_again:
99 len = (s->buffer_size - 1) - s->len;
100
101 va_start(ap, fmt);
102 ret = vsnprintf(s->buffer + s->len, len, fmt, ap);
103 va_end(ap);
104
105 if (ret >= len) {
106 expand_buffer(s);
107 goto try_again;
108 }
109
110 s->len += ret;
111
112 return 1;
113}
114
115/**
116 * trace_seq_vprintf - sequence printing of trace information
117 * @s: trace sequence descriptor
118 * @fmt: printf format string
119 *
120 * The tracer may use either sequence operations or its own
121 * copy to user routines. To simplify formating of a trace
122 * trace_seq_printf is used to store strings into a special
123 * buffer (@s). Then the output may be either used by
124 * the sequencer or pulled into another buffer.
125 */
126int
127trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
128{
129 int len;
130 int ret;
131
132 TRACE_SEQ_CHECK(s);
133
134 try_again:
135 len = (s->buffer_size - 1) - s->len;
136
137 ret = vsnprintf(s->buffer + s->len, len, fmt, args);
138
139 if (ret >= len) {
140 expand_buffer(s);
141 goto try_again;
142 }
143
144 s->len += ret;
145
146 return len;
147}
148
149/**
150 * trace_seq_puts - trace sequence printing of simple string
151 * @s: trace sequence descriptor
152 * @str: simple string to record
153 *
154 * The tracer may use either the sequence operations or its own
155 * copy to user routines. This function records a simple string
156 * into a special buffer (@s) for later retrieval by a sequencer
157 * or other mechanism.
158 */
159int trace_seq_puts(struct trace_seq *s, const char *str)
160{
161 int len;
162
163 TRACE_SEQ_CHECK(s);
164
165 len = strlen(str);
166
167 while (len > ((s->buffer_size - 1) - s->len))
168 expand_buffer(s);
169
170 memcpy(s->buffer + s->len, str, len);
171 s->len += len;
172
173 return len;
174}
175
176int trace_seq_putc(struct trace_seq *s, unsigned char c)
177{
178 TRACE_SEQ_CHECK(s);
179
180 while (s->len >= (s->buffer_size - 1))
181 expand_buffer(s);
182
183 s->buffer[s->len++] = c;
184
185 return 1;
186}
187
188void trace_seq_terminate(struct trace_seq *s)
189{
190 TRACE_SEQ_CHECK(s);
191
192 /* There's always one character left on the buffer */
193 s->buffer[s->len] = 0;
194}
195
196int trace_seq_do_printf(struct trace_seq *s)
197{
198 TRACE_SEQ_CHECK(s);
199 return printf("%.*s", s->len, s->buffer);
200}
diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt
index 0507ec7bad71..15217345c2fa 100644
--- a/tools/perf/Documentation/perf-evlist.txt
+++ b/tools/perf/Documentation/perf-evlist.txt
@@ -20,6 +20,14 @@ OPTIONS
20--input=:: 20--input=::
21 Input file name. (default: perf.data unless stdin is a fifo) 21 Input file name. (default: perf.data unless stdin is a fifo)
22 22
23-F::
24--freq=::
25 Show just the sample frequency used for each event.
26
27-v::
28--verbose=::
29 Show all fields.
30
23SEE ALSO 31SEE ALSO
24-------- 32--------
25linkperf:perf-record[1], linkperf:perf-list[1], 33linkperf:perf-record[1], linkperf:perf-list[1],
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 2780d9ce48bf..b715cb71592b 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -77,7 +77,8 @@ OPTIONS
77 77
78-F:: 78-F::
79--funcs:: 79--funcs::
80 Show available functions in given module or kernel. 80 Show available functions in given module or kernel. With -x/--exec,
81 can also list functions in a user space executable / shared library.
81 82
82--filter=FILTER:: 83--filter=FILTER::
83 (Only for --vars and --funcs) Set filter. FILTER is a combination of glob 84 (Only for --vars and --funcs) Set filter. FILTER is a combination of glob
@@ -98,6 +99,15 @@ OPTIONS
98--max-probes:: 99--max-probes::
99 Set the maximum number of probe points for an event. Default is 128. 100 Set the maximum number of probe points for an event. Default is 128.
100 101
102-x::
103--exec=PATH::
104 Specify path to the executable or shared library file for user
105 space tracing. Can also be used with --funcs option.
106
107In absence of -m/-x options, perf probe checks if the first argument after
108the options is an absolute path name. If its an absolute path, perf probe
109uses it as a target module/target user space binary to probe.
110
101PROBE SYNTAX 111PROBE SYNTAX
102------------ 112------------
103Probe points are defined by following syntax. 113Probe points are defined by following syntax.
@@ -182,6 +192,13 @@ Delete all probes on schedule().
182 192
183 ./perf probe --del='schedule*' 193 ./perf probe --del='schedule*'
184 194
195Add probes at zfree() function on /bin/zsh
196
197 ./perf probe -x /bin/zsh zfree or ./perf probe /bin/zsh zfree
198
199Add probes at malloc() function on libc
200
201 ./perf probe -x /lib/libc.so.6 malloc or ./perf probe /lib/libc.so.6 malloc
185 202
186SEE ALSO 203SEE ALSO
187-------- 204--------
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index a1386b2fff00..b38a1f9ad460 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -168,7 +168,7 @@ following filters are defined:
168 - any: any type of branches 168 - any: any type of branches
169 - any_call: any function call or system call 169 - any_call: any function call or system call
170 - any_ret: any function return or system call return 170 - any_ret: any function return or system call return
171 - any_ind: any indirect branch 171 - ind_call: any indirect branch
172 - u: only when the branch target is at the user level 172 - u: only when the branch target is at the user level
173 - k: only when the branch target is in the kernel 173 - k: only when the branch target is in the kernel
174 - hv: only when the target is at the hypervisor level 174 - hv: only when the target is at the hypervisor level
diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example
index d1448668f4d4..767ea2436e1c 100644
--- a/tools/perf/Documentation/perfconfig.example
+++ b/tools/perf/Documentation/perfconfig.example
@@ -6,6 +6,7 @@
6 normal = black, lightgray 6 normal = black, lightgray
7 selected = lightgray, magenta 7 selected = lightgray, magenta
8 code = blue, lightgray 8 code = blue, lightgray
9 addr = magenta, lightgray
9 10
10[tui] 11[tui]
11 12
@@ -18,3 +19,11 @@
18 19
19 # Default, disable using /dev/null 20 # Default, disable using /dev/null
20 dir = /root/.debug 21 dir = /root/.debug
22
23[annotate]
24
25 # Defaults
26 hide_src_code = false
27 use_offset = true
28 jump_arrows = true
29 show_nr_jumps = false
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 92271d32bc30..0eee64cfe9a0 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -1,18 +1,10 @@
1ifeq ("$(origin O)", "command line") 1include ../scripts/Makefile.include
2 OUTPUT := $(O)/
3endif
4 2
5# The default target of this Makefile is... 3# The default target of this Makefile is...
6all: 4all:
7 5
8include config/utilities.mak 6include config/utilities.mak
9 7
10ifneq ($(OUTPUT),)
11# check that the output directory actually exists
12OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
13$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
14endif
15
16# Define V to have a more verbose compile. 8# Define V to have a more verbose compile.
17# 9#
18# Define O to save output files in a separate directory. 10# Define O to save output files in a separate directory.
@@ -84,39 +76,20 @@ ifneq ($(WERROR),0)
84 CFLAGS_WERROR := -Werror 76 CFLAGS_WERROR := -Werror
85endif 77endif
86 78
87#
88# Include saner warnings here, which can catch bugs:
89#
90
91EXTRA_WARNINGS := -Wformat
92EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-security
93EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-y2k
94EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow
95EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self
96EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked
97EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls
98EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3
99EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default
100EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum
101EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers
102EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef
103EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings
104EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast
105EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations
106EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-prototypes
107EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wnested-externs
108EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition
109EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes
110EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement
111
112ifeq ("$(origin DEBUG)", "command line") 79ifeq ("$(origin DEBUG)", "command line")
113 PERF_DEBUG = $(DEBUG) 80 PERF_DEBUG = $(DEBUG)
114endif 81endif
115ifndef PERF_DEBUG 82ifndef PERF_DEBUG
116 CFLAGS_OPTIMIZE = -O6 83 CFLAGS_OPTIMIZE = -O6 -D_FORTIFY_SOURCE=2
84endif
85
86ifdef PARSER_DEBUG
87 PARSER_DEBUG_BISON := -t
88 PARSER_DEBUG_FLEX := -d
89 PARSER_DEBUG_CFLAGS := -DPARSER_DEBUG
117endif 90endif
118 91
119CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) 92CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS)
120EXTLIBS = -lpthread -lrt -lelf -lm 93EXTLIBS = -lpthread -lrt -lelf -lm
121ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 94ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
122ALL_LDFLAGS = $(LDFLAGS) 95ALL_LDFLAGS = $(LDFLAGS)
@@ -182,7 +155,7 @@ endif
182 155
183### --- END CONFIGURATION SECTION --- 156### --- END CONFIGURATION SECTION ---
184 157
185BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 158BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
186BASIC_LDFLAGS = 159BASIC_LDFLAGS =
187 160
188# Guard against environment variables 161# Guard against environment variables
@@ -211,6 +184,17 @@ $(OUTPUT)python/perf.so: $(PYRF_OBJS) $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
211 184
212SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) 185SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
213 186
187TRACE_EVENT_DIR = ../lib/traceevent/
188
189ifeq ("$(origin O)", "command line")
190 TE_PATH=$(OUTPUT)/
191else
192 TE_PATH=$(TRACE_EVENT_DIR)/
193endif
194
195LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
196TE_LIB := -L$(TE_PATH) -ltraceevent
197
214# 198#
215# Single 'perf' binary right now: 199# Single 'perf' binary right now:
216# 200#
@@ -238,10 +222,10 @@ FLEX = flex
238BISON= bison 222BISON= bison
239 223
240$(OUTPUT)util/parse-events-flex.c: util/parse-events.l 224$(OUTPUT)util/parse-events-flex.c: util/parse-events.l
241 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c 225 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
242 226
243$(OUTPUT)util/parse-events-bison.c: util/parse-events.y 227$(OUTPUT)util/parse-events-bison.c: util/parse-events.y
244 $(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o $(OUTPUT)util/parse-events-bison.c 228 $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c
245 229
246$(OUTPUT)util/pmu-flex.c: util/pmu.l 230$(OUTPUT)util/pmu-flex.c: util/pmu.l
247 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c 231 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
@@ -333,6 +317,8 @@ LIB_H += util/cpumap.h
333LIB_H += util/top.h 317LIB_H += util/top.h
334LIB_H += $(ARCH_INCLUDE) 318LIB_H += $(ARCH_INCLUDE)
335LIB_H += util/cgroup.h 319LIB_H += util/cgroup.h
320LIB_H += $(TRACE_EVENT_DIR)event-parse.h
321LIB_H += util/target.h
336 322
337LIB_OBJS += $(OUTPUT)util/abspath.o 323LIB_OBJS += $(OUTPUT)util/abspath.o
338LIB_OBJS += $(OUTPUT)util/alias.o 324LIB_OBJS += $(OUTPUT)util/alias.o
@@ -352,6 +338,7 @@ LIB_OBJS += $(OUTPUT)util/help.o
352LIB_OBJS += $(OUTPUT)util/levenshtein.o 338LIB_OBJS += $(OUTPUT)util/levenshtein.o
353LIB_OBJS += $(OUTPUT)util/parse-options.o 339LIB_OBJS += $(OUTPUT)util/parse-options.o
354LIB_OBJS += $(OUTPUT)util/parse-events.o 340LIB_OBJS += $(OUTPUT)util/parse-events.o
341LIB_OBJS += $(OUTPUT)util/parse-events-test.o
355LIB_OBJS += $(OUTPUT)util/path.o 342LIB_OBJS += $(OUTPUT)util/path.o
356LIB_OBJS += $(OUTPUT)util/rbtree.o 343LIB_OBJS += $(OUTPUT)util/rbtree.o
357LIB_OBJS += $(OUTPUT)util/bitmap.o 344LIB_OBJS += $(OUTPUT)util/bitmap.o
@@ -394,6 +381,7 @@ LIB_OBJS += $(OUTPUT)util/util.o
394LIB_OBJS += $(OUTPUT)util/xyarray.o 381LIB_OBJS += $(OUTPUT)util/xyarray.o
395LIB_OBJS += $(OUTPUT)util/cpumap.o 382LIB_OBJS += $(OUTPUT)util/cpumap.o
396LIB_OBJS += $(OUTPUT)util/cgroup.o 383LIB_OBJS += $(OUTPUT)util/cgroup.o
384LIB_OBJS += $(OUTPUT)util/target.o
397 385
398BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 386BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
399 387
@@ -429,7 +417,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
429BUILTIN_OBJS += $(OUTPUT)builtin-test.o 417BUILTIN_OBJS += $(OUTPUT)builtin-test.o
430BUILTIN_OBJS += $(OUTPUT)builtin-inject.o 418BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
431 419
432PERFLIBS = $(LIB_FILE) 420PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT)
433 421
434# Files needed for the python binding, perf.so 422# Files needed for the python binding, perf.so
435# pyrf is just an internal name needed for all those wrappers. 423# pyrf is just an internal name needed for all those wrappers.
@@ -506,22 +494,23 @@ else
506 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h 494 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
507 BASIC_CFLAGS += -I/usr/include/slang 495 BASIC_CFLAGS += -I/usr/include/slang
508 EXTLIBS += -lnewt -lslang 496 EXTLIBS += -lnewt -lslang
509 LIB_OBJS += $(OUTPUT)util/ui/setup.o 497 LIB_OBJS += $(OUTPUT)ui/setup.o
510 LIB_OBJS += $(OUTPUT)util/ui/browser.o 498 LIB_OBJS += $(OUTPUT)ui/browser.o
511 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o 499 LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
512 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o 500 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
513 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o 501 LIB_OBJS += $(OUTPUT)ui/browsers/map.o
514 LIB_OBJS += $(OUTPUT)util/ui/helpline.o 502 LIB_OBJS += $(OUTPUT)ui/helpline.o
515 LIB_OBJS += $(OUTPUT)util/ui/progress.o 503 LIB_OBJS += $(OUTPUT)ui/progress.o
516 LIB_OBJS += $(OUTPUT)util/ui/util.o 504 LIB_OBJS += $(OUTPUT)ui/util.o
517 LIB_H += util/ui/browser.h 505 LIB_OBJS += $(OUTPUT)ui/tui/setup.o
518 LIB_H += util/ui/browsers/map.h 506 LIB_H += ui/browser.h
519 LIB_H += util/ui/helpline.h 507 LIB_H += ui/browsers/map.h
520 LIB_H += util/ui/keysyms.h 508 LIB_H += ui/helpline.h
521 LIB_H += util/ui/libslang.h 509 LIB_H += ui/keysyms.h
522 LIB_H += util/ui/progress.h 510 LIB_H += ui/libslang.h
523 LIB_H += util/ui/util.h 511 LIB_H += ui/progress.h
524 LIB_H += util/ui/ui.h 512 LIB_H += ui/util.h
513 LIB_H += ui/ui.h
525 endif 514 endif
526endif 515endif
527 516
@@ -535,7 +524,12 @@ else
535 else 524 else
536 BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0) 525 BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0)
537 EXTLIBS += $(shell pkg-config --libs gtk+-2.0) 526 EXTLIBS += $(shell pkg-config --libs gtk+-2.0)
538 LIB_OBJS += $(OUTPUT)util/gtk/browser.o 527 LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
528 LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
529 # Make sure that it'd be included only once.
530 ifneq ($(findstring -DNO_NEWT_SUPPORT,$(BASIC_CFLAGS)),)
531 LIB_OBJS += $(OUTPUT)ui/setup.o
532 endif
539 endif 533 endif
540endif 534endif
541 535
@@ -678,18 +672,6 @@ else
678 endif 672 endif
679endif 673endif
680 674
681ifneq ($(findstring $(MAKEFLAGS),s),s)
682ifndef V
683 QUIET_CC = @echo ' ' CC $@;
684 QUIET_AR = @echo ' ' AR $@;
685 QUIET_LINK = @echo ' ' LINK $@;
686 QUIET_MKDIR = @echo ' ' MKDIR $@;
687 QUIET_GEN = @echo ' ' GEN $@;
688 QUIET_FLEX = @echo ' ' FLEX $@;
689 QUIET_BISON = @echo ' ' BISON $@;
690endif
691endif
692
693ifdef ASCIIDOC8 675ifdef ASCIIDOC8
694 export ASCIIDOC8 676 export ASCIIDOC8
695endif 677endif
@@ -800,16 +782,16 @@ $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
800$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS 782$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
801 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 783 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
802 784
803$(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS 785$(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS
804 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 786 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
805 787
806$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS 788$(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
807 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 789 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
808 790
809$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS 791$(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
810 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 792 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
811 793
812$(OUTPUT)util/ui/browsers/map.o: util/ui/browsers/map.c $(OUTPUT)PERF-CFLAGS 794$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
813 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 795 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
814 796
815$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS 797$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
@@ -844,6 +826,10 @@ $(sort $(dir $(DIRECTORY_DEPS))):
844$(LIB_FILE): $(LIB_OBJS) 826$(LIB_FILE): $(LIB_OBJS)
845 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) 827 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
846 828
829# libtraceevent.a
830$(LIBTRACEEVENT):
831 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) $(COMMAND_O) libtraceevent.a
832
847help: 833help:
848 @echo 'Perf make targets:' 834 @echo 'Perf make targets:'
849 @echo ' doc - make *all* documentation (see below)' 835 @echo ' doc - make *all* documentation (see below)'
@@ -990,6 +976,6 @@ clean:
990 $(RM) $(OUTPUT)util/*-{bison,flex}* 976 $(RM) $(OUTPUT)util/*-{bison,flex}*
991 $(python-clean) 977 $(python-clean)
992 978
993.PHONY: all install clean strip 979.PHONY: all install clean strip $(LIBTRACEEVENT)
994.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell 980.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
995.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS 981.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 806e0a286634..67522cf87405 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -215,7 +215,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
215 } 215 }
216 216
217 if (total_nr_samples == 0) { 217 if (total_nr_samples == 0) {
218 ui__warning("The %s file has no samples!\n", session->filename); 218 ui__error("The %s file has no samples!\n", session->filename);
219 goto out_delete; 219 goto out_delete;
220 } 220 }
221out_delete: 221out_delete:
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 52480467e9ff..6b2bcfbde150 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -84,7 +84,11 @@ static int perf_session__list_build_ids(void)
84 if (filename__fprintf_build_id(session->filename, stdout)) 84 if (filename__fprintf_build_id(session->filename, stdout))
85 goto out; 85 goto out;
86 86
87 if (with_hits) 87 /*
88 * in pipe-mode, the only way to get the buildids is to parse
89 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
90 */
91 if (with_hits || session->fd_pipe)
88 perf_session__process_events(session, &build_id__mark_dso_hit_ops); 92 perf_session__process_events(session, &build_id__mark_dso_hit_ops);
89 93
90 perf_session__fprintf_dsos_buildid(session, stdout, with_hits); 94 perf_session__fprintf_dsos_buildid(session, stdout, with_hits);
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index 26760322c4f4..acd78dc28341 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -15,9 +15,40 @@
15#include "util/parse-options.h" 15#include "util/parse-options.h"
16#include "util/session.h" 16#include "util/session.h"
17 17
18static const char *input_name; 18struct perf_attr_details {
19 bool freq;
20 bool verbose;
21};
22
23static int comma_printf(bool *first, const char *fmt, ...)
24{
25 va_list args;
26 int ret = 0;
27
28 if (!*first) {
29 ret += printf(",");
30 } else {
31 ret += printf(":");
32 *first = false;
33 }
34
35 va_start(args, fmt);
36 ret += vprintf(fmt, args);
37 va_end(args);
38 return ret;
39}
40
41static int __if_print(bool *first, const char *field, u64 value)
42{
43 if (value == 0)
44 return 0;
45
46 return comma_printf(first, " %s: %" PRIu64, field, value);
47}
48
49#define if_print(field) __if_print(&first, #field, pos->attr.field)
19 50
20static int __cmd_evlist(void) 51static int __cmd_evlist(const char *input_name, struct perf_attr_details *details)
21{ 52{
22 struct perf_session *session; 53 struct perf_session *session;
23 struct perf_evsel *pos; 54 struct perf_evsel *pos;
@@ -26,8 +57,52 @@ static int __cmd_evlist(void)
26 if (session == NULL) 57 if (session == NULL)
27 return -ENOMEM; 58 return -ENOMEM;
28 59
29 list_for_each_entry(pos, &session->evlist->entries, node) 60 list_for_each_entry(pos, &session->evlist->entries, node) {
30 printf("%s\n", event_name(pos)); 61 bool first = true;
62
63 printf("%s", event_name(pos));
64
65 if (details->verbose || details->freq) {
66 comma_printf(&first, " sample_freq=%" PRIu64,
67 (u64)pos->attr.sample_freq);
68 }
69
70 if (details->verbose) {
71 if_print(type);
72 if_print(config);
73 if_print(config1);
74 if_print(config2);
75 if_print(size);
76 if_print(sample_type);
77 if_print(read_format);
78 if_print(disabled);
79 if_print(inherit);
80 if_print(pinned);
81 if_print(exclusive);
82 if_print(exclude_user);
83 if_print(exclude_kernel);
84 if_print(exclude_hv);
85 if_print(exclude_idle);
86 if_print(mmap);
87 if_print(comm);
88 if_print(freq);
89 if_print(inherit_stat);
90 if_print(enable_on_exec);
91 if_print(task);
92 if_print(watermark);
93 if_print(precise_ip);
94 if_print(mmap_data);
95 if_print(sample_id_all);
96 if_print(exclude_host);
97 if_print(exclude_guest);
98 if_print(__reserved_1);
99 if_print(wakeup_events);
100 if_print(bp_type);
101 if_print(branch_sample_type);
102 }
103
104 putchar('\n');
105 }
31 106
32 perf_session__delete(session); 107 perf_session__delete(session);
33 return 0; 108 return 0;
@@ -38,17 +113,23 @@ static const char * const evlist_usage[] = {
38 NULL 113 NULL
39}; 114};
40 115
41static const struct option options[] = {
42 OPT_STRING('i', "input", &input_name, "file",
43 "input file name"),
44 OPT_END()
45};
46
47int cmd_evlist(int argc, const char **argv, const char *prefix __used) 116int cmd_evlist(int argc, const char **argv, const char *prefix __used)
48{ 117{
118 struct perf_attr_details details = { .verbose = false, };
119 const char *input_name = NULL;
120 const struct option options[] = {
121 OPT_STRING('i', "input", &input_name, "file",
122 "Input file name"),
123 OPT_BOOLEAN('F', "freq", &details.freq,
124 "Show the sample frequency"),
125 OPT_BOOLEAN('v', "verbose", &details.verbose,
126 "Show all event attr details"),
127 OPT_END()
128 };
129
49 argc = parse_options(argc, argv, options, evlist_usage, 0); 130 argc = parse_options(argc, argv, options, evlist_usage, 0);
50 if (argc) 131 if (argc)
51 usage_with_options(evlist_usage, options); 132 usage_with_options(evlist_usage, options);
52 133
53 return __cmd_evlist(); 134 return __cmd_evlist(input_name, &details);
54} 135}
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 09c106193e65..3beab489afc5 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -60,6 +60,11 @@ static int perf_event__repipe_tracing_data_synth(union perf_event *event,
60static int perf_event__repipe_attr(union perf_event *event, 60static int perf_event__repipe_attr(union perf_event *event,
61 struct perf_evlist **pevlist __used) 61 struct perf_evlist **pevlist __used)
62{ 62{
63 int ret;
64 ret = perf_event__process_attr(event, pevlist);
65 if (ret)
66 return ret;
67
63 return perf_event__repipe_synth(NULL, event, NULL); 68 return perf_event__repipe_synth(NULL, event, NULL);
64} 69}
65 70
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 39104c0beea3..547af48deb4f 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -192,7 +192,7 @@ static void insert_caller_stat(unsigned long call_site,
192} 192}
193 193
194static void process_alloc_event(void *data, 194static void process_alloc_event(void *data,
195 struct event *event, 195 struct event_format *event,
196 int cpu, 196 int cpu,
197 u64 timestamp __used, 197 u64 timestamp __used,
198 struct thread *thread __used, 198 struct thread *thread __used,
@@ -253,7 +253,7 @@ static struct alloc_stat *search_alloc_stat(unsigned long ptr,
253} 253}
254 254
255static void process_free_event(void *data, 255static void process_free_event(void *data,
256 struct event *event, 256 struct event_format *event,
257 int cpu, 257 int cpu,
258 u64 timestamp __used, 258 u64 timestamp __used,
259 struct thread *thread __used) 259 struct thread *thread __used)
@@ -281,7 +281,7 @@ static void process_free_event(void *data,
281static void process_raw_event(union perf_event *raw_event __used, void *data, 281static void process_raw_event(union perf_event *raw_event __used, void *data,
282 int cpu, u64 timestamp, struct thread *thread) 282 int cpu, u64 timestamp, struct thread *thread)
283{ 283{
284 struct event *event; 284 struct event_format *event;
285 int type; 285 int type;
286 286
287 type = trace_parse_common_type(data); 287 type = trace_parse_common_type(data);
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 12c814838993..fd53319de20d 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -356,25 +356,25 @@ struct trace_release_event {
356 356
357struct trace_lock_handler { 357struct trace_lock_handler {
358 void (*acquire_event)(struct trace_acquire_event *, 358 void (*acquire_event)(struct trace_acquire_event *,
359 struct event *, 359 struct event_format *,
360 int cpu, 360 int cpu,
361 u64 timestamp, 361 u64 timestamp,
362 struct thread *thread); 362 struct thread *thread);
363 363
364 void (*acquired_event)(struct trace_acquired_event *, 364 void (*acquired_event)(struct trace_acquired_event *,
365 struct event *, 365 struct event_format *,
366 int cpu, 366 int cpu,
367 u64 timestamp, 367 u64 timestamp,
368 struct thread *thread); 368 struct thread *thread);
369 369
370 void (*contended_event)(struct trace_contended_event *, 370 void (*contended_event)(struct trace_contended_event *,
371 struct event *, 371 struct event_format *,
372 int cpu, 372 int cpu,
373 u64 timestamp, 373 u64 timestamp,
374 struct thread *thread); 374 struct thread *thread);
375 375
376 void (*release_event)(struct trace_release_event *, 376 void (*release_event)(struct trace_release_event *,
377 struct event *, 377 struct event_format *,
378 int cpu, 378 int cpu,
379 u64 timestamp, 379 u64 timestamp,
380 struct thread *thread); 380 struct thread *thread);
@@ -416,7 +416,7 @@ enum acquire_flags {
416 416
417static void 417static void
418report_lock_acquire_event(struct trace_acquire_event *acquire_event, 418report_lock_acquire_event(struct trace_acquire_event *acquire_event,
419 struct event *__event __used, 419 struct event_format *__event __used,
420 int cpu __used, 420 int cpu __used,
421 u64 timestamp __used, 421 u64 timestamp __used,
422 struct thread *thread __used) 422 struct thread *thread __used)
@@ -480,7 +480,7 @@ end:
480 480
481static void 481static void
482report_lock_acquired_event(struct trace_acquired_event *acquired_event, 482report_lock_acquired_event(struct trace_acquired_event *acquired_event,
483 struct event *__event __used, 483 struct event_format *__event __used,
484 int cpu __used, 484 int cpu __used,
485 u64 timestamp __used, 485 u64 timestamp __used,
486 struct thread *thread __used) 486 struct thread *thread __used)
@@ -536,7 +536,7 @@ end:
536 536
537static void 537static void
538report_lock_contended_event(struct trace_contended_event *contended_event, 538report_lock_contended_event(struct trace_contended_event *contended_event,
539 struct event *__event __used, 539 struct event_format *__event __used,
540 int cpu __used, 540 int cpu __used,
541 u64 timestamp __used, 541 u64 timestamp __used,
542 struct thread *thread __used) 542 struct thread *thread __used)
@@ -583,7 +583,7 @@ end:
583 583
584static void 584static void
585report_lock_release_event(struct trace_release_event *release_event, 585report_lock_release_event(struct trace_release_event *release_event,
586 struct event *__event __used, 586 struct event_format *__event __used,
587 int cpu __used, 587 int cpu __used,
588 u64 timestamp __used, 588 u64 timestamp __used,
589 struct thread *thread __used) 589 struct thread *thread __used)
@@ -647,7 +647,7 @@ static struct trace_lock_handler *trace_handler;
647 647
648static void 648static void
649process_lock_acquire_event(void *data, 649process_lock_acquire_event(void *data,
650 struct event *event __used, 650 struct event_format *event __used,
651 int cpu __used, 651 int cpu __used,
652 u64 timestamp __used, 652 u64 timestamp __used,
653 struct thread *thread __used) 653 struct thread *thread __used)
@@ -666,7 +666,7 @@ process_lock_acquire_event(void *data,
666 666
667static void 667static void
668process_lock_acquired_event(void *data, 668process_lock_acquired_event(void *data,
669 struct event *event __used, 669 struct event_format *event __used,
670 int cpu __used, 670 int cpu __used,
671 u64 timestamp __used, 671 u64 timestamp __used,
672 struct thread *thread __used) 672 struct thread *thread __used)
@@ -684,7 +684,7 @@ process_lock_acquired_event(void *data,
684 684
685static void 685static void
686process_lock_contended_event(void *data, 686process_lock_contended_event(void *data,
687 struct event *event __used, 687 struct event_format *event __used,
688 int cpu __used, 688 int cpu __used,
689 u64 timestamp __used, 689 u64 timestamp __used,
690 struct thread *thread __used) 690 struct thread *thread __used)
@@ -702,7 +702,7 @@ process_lock_contended_event(void *data,
702 702
703static void 703static void
704process_lock_release_event(void *data, 704process_lock_release_event(void *data,
705 struct event *event __used, 705 struct event_format *event __used,
706 int cpu __used, 706 int cpu __used,
707 u64 timestamp __used, 707 u64 timestamp __used,
708 struct thread *thread __used) 708 struct thread *thread __used)
@@ -721,7 +721,7 @@ process_lock_release_event(void *data,
721static void 721static void
722process_raw_event(void *data, int cpu, u64 timestamp, struct thread *thread) 722process_raw_event(void *data, int cpu, u64 timestamp, struct thread *thread)
723{ 723{
724 struct event *event; 724 struct event_format *event;
725 int type; 725 int type;
726 726
727 type = trace_parse_common_type(data); 727 type = trace_parse_common_type(data);
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 4935c09dd5b5..e215ae61b2ae 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -54,6 +54,7 @@ static struct {
54 bool show_ext_vars; 54 bool show_ext_vars;
55 bool show_funcs; 55 bool show_funcs;
56 bool mod_events; 56 bool mod_events;
57 bool uprobes;
57 int nevents; 58 int nevents;
58 struct perf_probe_event events[MAX_PROBES]; 59 struct perf_probe_event events[MAX_PROBES];
59 struct strlist *dellist; 60 struct strlist *dellist;
@@ -75,6 +76,8 @@ static int parse_probe_event(const char *str)
75 return -1; 76 return -1;
76 } 77 }
77 78
79 pev->uprobes = params.uprobes;
80
78 /* Parse a perf-probe command into event */ 81 /* Parse a perf-probe command into event */
79 ret = parse_perf_probe_command(str, pev); 82 ret = parse_perf_probe_command(str, pev);
80 pr_debug("%d arguments\n", pev->nargs); 83 pr_debug("%d arguments\n", pev->nargs);
@@ -82,21 +85,58 @@ static int parse_probe_event(const char *str)
82 return ret; 85 return ret;
83} 86}
84 87
88static int set_target(const char *ptr)
89{
90 int found = 0;
91 const char *buf;
92
93 /*
94 * The first argument after options can be an absolute path
95 * to an executable / library or kernel module.
96 *
97 * TODO: Support relative path, and $PATH, $LD_LIBRARY_PATH,
98 * short module name.
99 */
100 if (!params.target && ptr && *ptr == '/') {
101 params.target = ptr;
102 found = 1;
103 buf = ptr + (strlen(ptr) - 3);
104
105 if (strcmp(buf, ".ko"))
106 params.uprobes = true;
107
108 }
109
110 return found;
111}
112
85static int parse_probe_event_argv(int argc, const char **argv) 113static int parse_probe_event_argv(int argc, const char **argv)
86{ 114{
87 int i, len, ret; 115 int i, len, ret, found_target;
88 char *buf; 116 char *buf;
89 117
118 found_target = set_target(argv[0]);
119 if (found_target && argc == 1)
120 return 0;
121
90 /* Bind up rest arguments */ 122 /* Bind up rest arguments */
91 len = 0; 123 len = 0;
92 for (i = 0; i < argc; i++) 124 for (i = 0; i < argc; i++) {
125 if (i == 0 && found_target)
126 continue;
127
93 len += strlen(argv[i]) + 1; 128 len += strlen(argv[i]) + 1;
129 }
94 buf = zalloc(len + 1); 130 buf = zalloc(len + 1);
95 if (buf == NULL) 131 if (buf == NULL)
96 return -ENOMEM; 132 return -ENOMEM;
97 len = 0; 133 len = 0;
98 for (i = 0; i < argc; i++) 134 for (i = 0; i < argc; i++) {
135 if (i == 0 && found_target)
136 continue;
137
99 len += sprintf(&buf[len], "%s ", argv[i]); 138 len += sprintf(&buf[len], "%s ", argv[i]);
139 }
100 params.mod_events = true; 140 params.mod_events = true;
101 ret = parse_probe_event(buf); 141 ret = parse_probe_event(buf);
102 free(buf); 142 free(buf);
@@ -125,6 +165,28 @@ static int opt_del_probe_event(const struct option *opt __used,
125 return 0; 165 return 0;
126} 166}
127 167
168static int opt_set_target(const struct option *opt, const char *str,
169 int unset __used)
170{
171 int ret = -ENOENT;
172
173 if (str && !params.target) {
174 if (!strcmp(opt->long_name, "exec"))
175 params.uprobes = true;
176#ifdef DWARF_SUPPORT
177 else if (!strcmp(opt->long_name, "module"))
178 params.uprobes = false;
179#endif
180 else
181 return ret;
182
183 params.target = str;
184 ret = 0;
185 }
186
187 return ret;
188}
189
128#ifdef DWARF_SUPPORT 190#ifdef DWARF_SUPPORT
129static int opt_show_lines(const struct option *opt __used, 191static int opt_show_lines(const struct option *opt __used,
130 const char *str, int unset __used) 192 const char *str, int unset __used)
@@ -246,9 +308,9 @@ static const struct option options[] = {
246 "file", "vmlinux pathname"), 308 "file", "vmlinux pathname"),
247 OPT_STRING('s', "source", &symbol_conf.source_prefix, 309 OPT_STRING('s', "source", &symbol_conf.source_prefix,
248 "directory", "path to kernel source"), 310 "directory", "path to kernel source"),
249 OPT_STRING('m', "module", &params.target, 311 OPT_CALLBACK('m', "module", NULL, "modname|path",
250 "modname|path", 312 "target module name (for online) or path (for offline)",
251 "target module name (for online) or path (for offline)"), 313 opt_set_target),
252#endif 314#endif
253 OPT__DRY_RUN(&probe_event_dry_run), 315 OPT__DRY_RUN(&probe_event_dry_run),
254 OPT_INTEGER('\0', "max-probes", &params.max_probe_points, 316 OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
@@ -260,6 +322,8 @@ static const struct option options[] = {
260 "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n" 322 "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
261 "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)", 323 "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
262 opt_set_filter), 324 opt_set_filter),
325 OPT_CALLBACK('x', "exec", NULL, "executable|path",
326 "target executable name or path", opt_set_target),
263 OPT_END() 327 OPT_END()
264}; 328};
265 329
@@ -310,6 +374,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
310 pr_err(" Error: Don't use --list with --funcs.\n"); 374 pr_err(" Error: Don't use --list with --funcs.\n");
311 usage_with_options(probe_usage, options); 375 usage_with_options(probe_usage, options);
312 } 376 }
377 if (params.uprobes) {
378 pr_warning(" Error: Don't use --list with --exec.\n");
379 usage_with_options(probe_usage, options);
380 }
313 ret = show_perf_probe_events(); 381 ret = show_perf_probe_events();
314 if (ret < 0) 382 if (ret < 0)
315 pr_err(" Error: Failed to show event list. (%d)\n", 383 pr_err(" Error: Failed to show event list. (%d)\n",
@@ -333,8 +401,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
333 if (!params.filter) 401 if (!params.filter)
334 params.filter = strfilter__new(DEFAULT_FUNC_FILTER, 402 params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
335 NULL); 403 NULL);
336 ret = show_available_funcs(params.target, 404 ret = show_available_funcs(params.target, params.filter,
337 params.filter); 405 params.uprobes);
338 strfilter__delete(params.filter); 406 strfilter__delete(params.filter);
339 if (ret < 0) 407 if (ret < 0)
340 pr_err(" Error: Failed to show functions." 408 pr_err(" Error: Failed to show functions."
@@ -343,7 +411,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
343 } 411 }
344 412
345#ifdef DWARF_SUPPORT 413#ifdef DWARF_SUPPORT
346 if (params.show_lines) { 414 if (params.show_lines && !params.uprobes) {
347 if (params.mod_events) { 415 if (params.mod_events) {
348 pr_err(" Error: Don't use --line with" 416 pr_err(" Error: Don't use --line with"
349 " --add/--del.\n"); 417 " --add/--del.\n");
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index be4e1eee782e..f95840d04e4c 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -44,7 +44,6 @@ struct perf_record {
44 struct perf_evlist *evlist; 44 struct perf_evlist *evlist;
45 struct perf_session *session; 45 struct perf_session *session;
46 const char *progname; 46 const char *progname;
47 const char *uid_str;
48 int output; 47 int output;
49 unsigned int page_size; 48 unsigned int page_size;
50 int realtime_prio; 49 int realtime_prio;
@@ -218,7 +217,7 @@ try_again:
218 if (err == EPERM || err == EACCES) { 217 if (err == EPERM || err == EACCES) {
219 ui__error_paranoid(); 218 ui__error_paranoid();
220 exit(EXIT_FAILURE); 219 exit(EXIT_FAILURE);
221 } else if (err == ENODEV && opts->cpu_list) { 220 } else if (err == ENODEV && opts->target.cpu_list) {
222 die("No such device - did you specify" 221 die("No such device - did you specify"
223 " an out-of-range profile CPU?\n"); 222 " an out-of-range profile CPU?\n");
224 } else if (err == EINVAL) { 223 } else if (err == EINVAL) {
@@ -243,9 +242,13 @@ try_again:
243 /* 242 /*
244 * If it's cycles then fall back to hrtimer 243 * If it's cycles then fall back to hrtimer
245 * based cpu-clock-tick sw counter, which 244 * based cpu-clock-tick sw counter, which
246 * is always available even if no PMU support: 245 * is always available even if no PMU support.
246 *
247 * PPC returns ENXIO until 2.6.37 (behavior changed
248 * with commit b0a873e).
247 */ 249 */
248 if (attr->type == PERF_TYPE_HARDWARE 250 if ((err == ENOENT || err == ENXIO)
251 && attr->type == PERF_TYPE_HARDWARE
249 && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 252 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
250 253
251 if (verbose) 254 if (verbose)
@@ -253,11 +256,15 @@ try_again:
253 "trying to fall back to cpu-clock-ticks\n"); 256 "trying to fall back to cpu-clock-ticks\n");
254 attr->type = PERF_TYPE_SOFTWARE; 257 attr->type = PERF_TYPE_SOFTWARE;
255 attr->config = PERF_COUNT_SW_CPU_CLOCK; 258 attr->config = PERF_COUNT_SW_CPU_CLOCK;
259 if (pos->name) {
260 free(pos->name);
261 pos->name = NULL;
262 }
256 goto try_again; 263 goto try_again;
257 } 264 }
258 265
259 if (err == ENOENT) { 266 if (err == ENOENT) {
260 ui__warning("The %s event is not supported.\n", 267 ui__error("The %s event is not supported.\n",
261 event_name(pos)); 268 event_name(pos));
262 exit(EXIT_FAILURE); 269 exit(EXIT_FAILURE);
263 } 270 }
@@ -389,7 +396,7 @@ static void perf_record__mmap_read_all(struct perf_record *rec)
389 perf_record__mmap_read(rec, &rec->evlist->mmap[i]); 396 perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
390 } 397 }
391 398
392 if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO)) 399 if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
393 write_output(rec, &finished_round_event, sizeof(finished_round_event)); 400 write_output(rec, &finished_round_event, sizeof(finished_round_event));
394} 401}
395 402
@@ -471,7 +478,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
471 perf_header__clear_feat(&session->header, HEADER_BUILD_ID); 478 perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
472 479
473 if (!have_tracepoints(&evsel_list->entries)) 480 if (!have_tracepoints(&evsel_list->entries))
474 perf_header__clear_feat(&session->header, HEADER_TRACE_INFO); 481 perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
475 482
476 if (!rec->opts.branch_stack) 483 if (!rec->opts.branch_stack)
477 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); 484 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
@@ -578,7 +585,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
578 perf_session__process_machines(session, tool, 585 perf_session__process_machines(session, tool,
579 perf_event__synthesize_guest_os); 586 perf_event__synthesize_guest_os);
580 587
581 if (!opts->system_wide) 588 if (!opts->target.system_wide)
582 perf_event__synthesize_thread_map(tool, evsel_list->threads, 589 perf_event__synthesize_thread_map(tool, evsel_list->threads,
583 process_synthesized_event, 590 process_synthesized_event,
584 machine); 591 machine);
@@ -746,7 +753,10 @@ static struct perf_record record = {
746 .mmap_pages = UINT_MAX, 753 .mmap_pages = UINT_MAX,
747 .user_freq = UINT_MAX, 754 .user_freq = UINT_MAX,
748 .user_interval = ULLONG_MAX, 755 .user_interval = ULLONG_MAX,
749 .freq = 1000, 756 .freq = 4000,
757 .target = {
758 .uses_mmap = true,
759 },
750 }, 760 },
751 .write_mode = WRITE_FORCE, 761 .write_mode = WRITE_FORCE,
752 .file_new = true, 762 .file_new = true,
@@ -765,9 +775,9 @@ const struct option record_options[] = {
765 parse_events_option), 775 parse_events_option),
766 OPT_CALLBACK(0, "filter", &record.evlist, "filter", 776 OPT_CALLBACK(0, "filter", &record.evlist, "filter",
767 "event filter", parse_filter), 777 "event filter", parse_filter),
768 OPT_STRING('p', "pid", &record.opts.target_pid, "pid", 778 OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
769 "record events on existing process id"), 779 "record events on existing process id"),
770 OPT_STRING('t', "tid", &record.opts.target_tid, "tid", 780 OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
771 "record events on existing thread id"), 781 "record events on existing thread id"),
772 OPT_INTEGER('r', "realtime", &record.realtime_prio, 782 OPT_INTEGER('r', "realtime", &record.realtime_prio,
773 "collect data with this RT SCHED_FIFO priority"), 783 "collect data with this RT SCHED_FIFO priority"),
@@ -775,11 +785,11 @@ const struct option record_options[] = {
775 "collect data without buffering"), 785 "collect data without buffering"),
776 OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples, 786 OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
777 "collect raw sample records from all opened counters"), 787 "collect raw sample records from all opened counters"),
778 OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide, 788 OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
779 "system-wide collection from all CPUs"), 789 "system-wide collection from all CPUs"),
780 OPT_BOOLEAN('A', "append", &record.append_file, 790 OPT_BOOLEAN('A', "append", &record.append_file,
781 "append to the output file to do incremental profiling"), 791 "append to the output file to do incremental profiling"),
782 OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu", 792 OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
783 "list of cpus to monitor"), 793 "list of cpus to monitor"),
784 OPT_BOOLEAN('f', "force", &record.force, 794 OPT_BOOLEAN('f', "force", &record.force,
785 "overwrite existing data file (deprecated)"), 795 "overwrite existing data file (deprecated)"),
@@ -813,7 +823,8 @@ const struct option record_options[] = {
813 OPT_CALLBACK('G', "cgroup", &record.evlist, "name", 823 OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
814 "monitor event in cgroup name only", 824 "monitor event in cgroup name only",
815 parse_cgroups), 825 parse_cgroups),
816 OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"), 826 OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
827 "user to profile"),
817 828
818 OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack, 829 OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
819 "branch any", "sample any taken branches", 830 "branch any", "sample any taken branches",
@@ -831,6 +842,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
831 struct perf_evsel *pos; 842 struct perf_evsel *pos;
832 struct perf_evlist *evsel_list; 843 struct perf_evlist *evsel_list;
833 struct perf_record *rec = &record; 844 struct perf_record *rec = &record;
845 char errbuf[BUFSIZ];
834 846
835 perf_header__set_cmdline(argc, argv); 847 perf_header__set_cmdline(argc, argv);
836 848
@@ -842,13 +854,12 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
842 854
843 argc = parse_options(argc, argv, record_options, record_usage, 855 argc = parse_options(argc, argv, record_options, record_usage,
844 PARSE_OPT_STOP_AT_NON_OPTION); 856 PARSE_OPT_STOP_AT_NON_OPTION);
845 if (!argc && !rec->opts.target_pid && !rec->opts.target_tid && 857 if (!argc && perf_target__none(&rec->opts.target))
846 !rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
847 usage_with_options(record_usage, record_options); 858 usage_with_options(record_usage, record_options);
848 859
849 if (rec->force && rec->append_file) { 860 if (rec->force && rec->append_file) {
850 fprintf(stderr, "Can't overwrite and append at the same time." 861 ui__error("Can't overwrite and append at the same time."
851 " You need to choose between -f and -A"); 862 " You need to choose between -f and -A");
852 usage_with_options(record_usage, record_options); 863 usage_with_options(record_usage, record_options);
853 } else if (rec->append_file) { 864 } else if (rec->append_file) {
854 rec->write_mode = WRITE_APPEND; 865 rec->write_mode = WRITE_APPEND;
@@ -856,9 +867,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
856 rec->write_mode = WRITE_FORCE; 867 rec->write_mode = WRITE_FORCE;
857 } 868 }
858 869
859 if (nr_cgroups && !rec->opts.system_wide) { 870 if (nr_cgroups && !rec->opts.target.system_wide) {
860 fprintf(stderr, "cgroup monitoring only available in" 871 ui__error("cgroup monitoring only available in"
861 " system-wide mode\n"); 872 " system-wide mode\n");
862 usage_with_options(record_usage, record_options); 873 usage_with_options(record_usage, record_options);
863 } 874 }
864 875
@@ -883,17 +894,25 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
883 goto out_symbol_exit; 894 goto out_symbol_exit;
884 } 895 }
885 896
886 rec->opts.uid = parse_target_uid(rec->uid_str, rec->opts.target_tid, 897 err = perf_target__validate(&rec->opts.target);
887 rec->opts.target_pid); 898 if (err) {
888 if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1) 899 perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
889 goto out_free_fd; 900 ui__warning("%s", errbuf);
901 }
902
903 err = perf_target__parse_uid(&rec->opts.target);
904 if (err) {
905 int saved_errno = errno;
890 906
891 if (rec->opts.target_pid) 907 perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
892 rec->opts.target_tid = rec->opts.target_pid; 908 ui__error("%s", errbuf);
909
910 err = -saved_errno;
911 goto out_free_fd;
912 }
893 913
894 if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid, 914 err = -ENOMEM;
895 rec->opts.target_tid, rec->opts.uid, 915 if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
896 rec->opts.cpu_list) < 0)
897 usage_with_options(record_usage, record_options); 916 usage_with_options(record_usage, record_options);
898 917
899 list_for_each_entry(pos, &evsel_list->entries, node) { 918 list_for_each_entry(pos, &evsel_list->entries, node) {
@@ -914,7 +933,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
914 else if (rec->opts.freq) { 933 else if (rec->opts.freq) {
915 rec->opts.default_interval = rec->opts.freq; 934 rec->opts.default_interval = rec->opts.freq;
916 } else { 935 } else {
917 fprintf(stderr, "frequency and count are zero, aborting\n"); 936 ui__error("frequency and count are zero, aborting\n");
918 err = -EINVAL; 937 err = -EINVAL;
919 goto out_free_fd; 938 goto out_free_fd;
920 } 939 }
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index cdae9b2db1cc..8c767c6bca91 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -251,13 +251,13 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
251 251
252 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { 252 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
253 if (sort__has_parent) { 253 if (sort__has_parent) {
254 ui__warning("Selected --sort parent, but no " 254 ui__error("Selected --sort parent, but no "
255 "callchain data. Did you call " 255 "callchain data. Did you call "
256 "'perf record' without -g?\n"); 256 "'perf record' without -g?\n");
257 return -EINVAL; 257 return -EINVAL;
258 } 258 }
259 if (symbol_conf.use_callchain) { 259 if (symbol_conf.use_callchain) {
260 ui__warning("Selected -g but no callchain data. Did " 260 ui__error("Selected -g but no callchain data. Did "
261 "you call 'perf record' without -g?\n"); 261 "you call 'perf record' without -g?\n");
262 return -1; 262 return -1;
263 } 263 }
@@ -266,17 +266,15 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
266 !symbol_conf.use_callchain) { 266 !symbol_conf.use_callchain) {
267 symbol_conf.use_callchain = true; 267 symbol_conf.use_callchain = true;
268 if (callchain_register_param(&callchain_param) < 0) { 268 if (callchain_register_param(&callchain_param) < 0) {
269 ui__warning("Can't register callchain " 269 ui__error("Can't register callchain params.\n");
270 "params.\n");
271 return -EINVAL; 270 return -EINVAL;
272 } 271 }
273 } 272 }
274 273
275 if (sort__branch_mode == 1) { 274 if (sort__branch_mode == 1) {
276 if (!(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) { 275 if (!(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) {
277 fprintf(stderr, "selected -b but no branch data." 276 ui__error("Selected -b but no branch data. "
278 " Did you call perf record without" 277 "Did you call perf record without -b?\n");
279 " -b?\n");
280 return -1; 278 return -1;
281 } 279 }
282 } 280 }
@@ -296,12 +294,15 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
296{ 294{
297 size_t ret; 295 size_t ret;
298 char unit; 296 char unit;
299 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE]; 297 unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE];
298 u64 nr_events = self->stats.total_period;
300 299
301 nr_events = convert_unit(nr_events, &unit); 300 nr_samples = convert_unit(nr_samples, &unit);
302 ret = fprintf(fp, "# Events: %lu%c", nr_events, unit); 301 ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
303 if (evname != NULL) 302 if (evname != NULL)
304 ret += fprintf(fp, " %s", evname); 303 ret += fprintf(fp, " of event '%s'", evname);
304
305 ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
305 return ret + fprintf(fp, "\n#\n"); 306 return ret + fprintf(fp, "\n#\n");
306} 307}
307 308
@@ -417,7 +418,7 @@ static int __cmd_report(struct perf_report *rep)
417 } 418 }
418 419
419 if (nr_samples == 0) { 420 if (nr_samples == 0) {
420 ui__warning("The %s file has no samples!\n", session->filename); 421 ui__error("The %s file has no samples!\n", session->filename);
421 goto out_delete; 422 goto out_delete;
422 } 423 }
423 424
@@ -680,14 +681,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
680 681
681 } 682 }
682 683
683 if (strcmp(report.input_name, "-") != 0) { 684 if (strcmp(report.input_name, "-") != 0)
684 if (report.use_gtk) 685 setup_browser(true);
685 perf_gtk_setup_browser(argc, argv, true); 686 else
686 else
687 setup_browser(true);
688 } else {
689 use_browser = 0; 687 use_browser = 0;
690 }
691 688
692 /* 689 /*
693 * Only in the newt browser we are doing integrated annotation, 690 * Only in the newt browser we are doing integrated annotation,
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 1cad3af4bf4c..b125e07eb399 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -728,34 +728,34 @@ struct trace_migrate_task_event {
728struct trace_sched_handler { 728struct trace_sched_handler {
729 void (*switch_event)(struct trace_switch_event *, 729 void (*switch_event)(struct trace_switch_event *,
730 struct machine *, 730 struct machine *,
731 struct event *, 731 struct event_format *,
732 int cpu, 732 int cpu,
733 u64 timestamp, 733 u64 timestamp,
734 struct thread *thread); 734 struct thread *thread);
735 735
736 void (*runtime_event)(struct trace_runtime_event *, 736 void (*runtime_event)(struct trace_runtime_event *,
737 struct machine *, 737 struct machine *,
738 struct event *, 738 struct event_format *,
739 int cpu, 739 int cpu,
740 u64 timestamp, 740 u64 timestamp,
741 struct thread *thread); 741 struct thread *thread);
742 742
743 void (*wakeup_event)(struct trace_wakeup_event *, 743 void (*wakeup_event)(struct trace_wakeup_event *,
744 struct machine *, 744 struct machine *,
745 struct event *, 745 struct event_format *,
746 int cpu, 746 int cpu,
747 u64 timestamp, 747 u64 timestamp,
748 struct thread *thread); 748 struct thread *thread);
749 749
750 void (*fork_event)(struct trace_fork_event *, 750 void (*fork_event)(struct trace_fork_event *,
751 struct event *, 751 struct event_format *,
752 int cpu, 752 int cpu,
753 u64 timestamp, 753 u64 timestamp,
754 struct thread *thread); 754 struct thread *thread);
755 755
756 void (*migrate_task_event)(struct trace_migrate_task_event *, 756 void (*migrate_task_event)(struct trace_migrate_task_event *,
757 struct machine *machine, 757 struct machine *machine,
758 struct event *, 758 struct event_format *,
759 int cpu, 759 int cpu,
760 u64 timestamp, 760 u64 timestamp,
761 struct thread *thread); 761 struct thread *thread);
@@ -765,7 +765,7 @@ struct trace_sched_handler {
765static void 765static void
766replay_wakeup_event(struct trace_wakeup_event *wakeup_event, 766replay_wakeup_event(struct trace_wakeup_event *wakeup_event,
767 struct machine *machine __used, 767 struct machine *machine __used,
768 struct event *event, 768 struct event_format *event,
769 int cpu __used, 769 int cpu __used,
770 u64 timestamp __used, 770 u64 timestamp __used,
771 struct thread *thread __used) 771 struct thread *thread __used)
@@ -792,7 +792,7 @@ static u64 cpu_last_switched[MAX_CPUS];
792static void 792static void
793replay_switch_event(struct trace_switch_event *switch_event, 793replay_switch_event(struct trace_switch_event *switch_event,
794 struct machine *machine __used, 794 struct machine *machine __used,
795 struct event *event, 795 struct event_format *event,
796 int cpu, 796 int cpu,
797 u64 timestamp, 797 u64 timestamp,
798 struct thread *thread __used) 798 struct thread *thread __used)
@@ -835,7 +835,7 @@ replay_switch_event(struct trace_switch_event *switch_event,
835 835
836static void 836static void
837replay_fork_event(struct trace_fork_event *fork_event, 837replay_fork_event(struct trace_fork_event *fork_event,
838 struct event *event, 838 struct event_format *event,
839 int cpu __used, 839 int cpu __used,
840 u64 timestamp __used, 840 u64 timestamp __used,
841 struct thread *thread __used) 841 struct thread *thread __used)
@@ -944,7 +944,7 @@ static void thread_atoms_insert(struct thread *thread)
944 944
945static void 945static void
946latency_fork_event(struct trace_fork_event *fork_event __used, 946latency_fork_event(struct trace_fork_event *fork_event __used,
947 struct event *event __used, 947 struct event_format *event __used,
948 int cpu __used, 948 int cpu __used,
949 u64 timestamp __used, 949 u64 timestamp __used,
950 struct thread *thread __used) 950 struct thread *thread __used)
@@ -1026,7 +1026,7 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
1026static void 1026static void
1027latency_switch_event(struct trace_switch_event *switch_event, 1027latency_switch_event(struct trace_switch_event *switch_event,
1028 struct machine *machine, 1028 struct machine *machine,
1029 struct event *event __used, 1029 struct event_format *event __used,
1030 int cpu, 1030 int cpu,
1031 u64 timestamp, 1031 u64 timestamp,
1032 struct thread *thread __used) 1032 struct thread *thread __used)
@@ -1079,7 +1079,7 @@ latency_switch_event(struct trace_switch_event *switch_event,
1079static void 1079static void
1080latency_runtime_event(struct trace_runtime_event *runtime_event, 1080latency_runtime_event(struct trace_runtime_event *runtime_event,
1081 struct machine *machine, 1081 struct machine *machine,
1082 struct event *event __used, 1082 struct event_format *event __used,
1083 int cpu, 1083 int cpu,
1084 u64 timestamp, 1084 u64 timestamp,
1085 struct thread *this_thread __used) 1085 struct thread *this_thread __used)
@@ -1102,7 +1102,7 @@ latency_runtime_event(struct trace_runtime_event *runtime_event,
1102static void 1102static void
1103latency_wakeup_event(struct trace_wakeup_event *wakeup_event, 1103latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1104 struct machine *machine, 1104 struct machine *machine,
1105 struct event *__event __used, 1105 struct event_format *__event __used,
1106 int cpu __used, 1106 int cpu __used,
1107 u64 timestamp, 1107 u64 timestamp,
1108 struct thread *thread __used) 1108 struct thread *thread __used)
@@ -1150,7 +1150,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1150static void 1150static void
1151latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event, 1151latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1152 struct machine *machine, 1152 struct machine *machine,
1153 struct event *__event __used, 1153 struct event_format *__event __used,
1154 int cpu __used, 1154 int cpu __used,
1155 u64 timestamp, 1155 u64 timestamp,
1156 struct thread *thread __used) 1156 struct thread *thread __used)
@@ -1361,7 +1361,7 @@ static struct trace_sched_handler *trace_handler;
1361 1361
1362static void 1362static void
1363process_sched_wakeup_event(struct perf_tool *tool __used, 1363process_sched_wakeup_event(struct perf_tool *tool __used,
1364 struct event *event, 1364 struct event_format *event,
1365 struct perf_sample *sample, 1365 struct perf_sample *sample,
1366 struct machine *machine, 1366 struct machine *machine,
1367 struct thread *thread) 1367 struct thread *thread)
@@ -1398,7 +1398,7 @@ static char next_shortname2 = '0';
1398static void 1398static void
1399map_switch_event(struct trace_switch_event *switch_event, 1399map_switch_event(struct trace_switch_event *switch_event,
1400 struct machine *machine, 1400 struct machine *machine,
1401 struct event *event __used, 1401 struct event_format *event __used,
1402 int this_cpu, 1402 int this_cpu,
1403 u64 timestamp, 1403 u64 timestamp,
1404 struct thread *thread __used) 1404 struct thread *thread __used)
@@ -1476,7 +1476,7 @@ map_switch_event(struct trace_switch_event *switch_event,
1476 1476
1477static void 1477static void
1478process_sched_switch_event(struct perf_tool *tool __used, 1478process_sched_switch_event(struct perf_tool *tool __used,
1479 struct event *event, 1479 struct event_format *event,
1480 struct perf_sample *sample, 1480 struct perf_sample *sample,
1481 struct machine *machine, 1481 struct machine *machine,
1482 struct thread *thread) 1482 struct thread *thread)
@@ -1512,7 +1512,7 @@ process_sched_switch_event(struct perf_tool *tool __used,
1512 1512
1513static void 1513static void
1514process_sched_runtime_event(struct perf_tool *tool __used, 1514process_sched_runtime_event(struct perf_tool *tool __used,
1515 struct event *event, 1515 struct event_format *event,
1516 struct perf_sample *sample, 1516 struct perf_sample *sample,
1517 struct machine *machine, 1517 struct machine *machine,
1518 struct thread *thread) 1518 struct thread *thread)
@@ -1532,7 +1532,7 @@ process_sched_runtime_event(struct perf_tool *tool __used,
1532 1532
1533static void 1533static void
1534process_sched_fork_event(struct perf_tool *tool __used, 1534process_sched_fork_event(struct perf_tool *tool __used,
1535 struct event *event, 1535 struct event_format *event,
1536 struct perf_sample *sample, 1536 struct perf_sample *sample,
1537 struct machine *machine __used, 1537 struct machine *machine __used,
1538 struct thread *thread) 1538 struct thread *thread)
@@ -1554,7 +1554,7 @@ process_sched_fork_event(struct perf_tool *tool __used,
1554 1554
1555static void 1555static void
1556process_sched_exit_event(struct perf_tool *tool __used, 1556process_sched_exit_event(struct perf_tool *tool __used,
1557 struct event *event, 1557 struct event_format *event,
1558 struct perf_sample *sample __used, 1558 struct perf_sample *sample __used,
1559 struct machine *machine __used, 1559 struct machine *machine __used,
1560 struct thread *thread __used) 1560 struct thread *thread __used)
@@ -1565,7 +1565,7 @@ process_sched_exit_event(struct perf_tool *tool __used,
1565 1565
1566static void 1566static void
1567process_sched_migrate_task_event(struct perf_tool *tool __used, 1567process_sched_migrate_task_event(struct perf_tool *tool __used,
1568 struct event *event, 1568 struct event_format *event,
1569 struct perf_sample *sample, 1569 struct perf_sample *sample,
1570 struct machine *machine, 1570 struct machine *machine,
1571 struct thread *thread) 1571 struct thread *thread)
@@ -1586,7 +1586,7 @@ process_sched_migrate_task_event(struct perf_tool *tool __used,
1586 sample->time, thread); 1586 sample->time, thread);
1587} 1587}
1588 1588
1589typedef void (*tracepoint_handler)(struct perf_tool *tool, struct event *event, 1589typedef void (*tracepoint_handler)(struct perf_tool *tool, struct event_format *event,
1590 struct perf_sample *sample, 1590 struct perf_sample *sample,
1591 struct machine *machine, 1591 struct machine *machine,
1592 struct thread *thread); 1592 struct thread *thread);
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index d4ce733b9eba..8e395a538eb9 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -261,7 +261,7 @@ static void print_sample_start(struct perf_sample *sample,
261 struct perf_event_attr *attr) 261 struct perf_event_attr *attr)
262{ 262{
263 int type; 263 int type;
264 struct event *event; 264 struct event_format *event;
265 const char *evname = NULL; 265 const char *evname = NULL;
266 unsigned long secs; 266 unsigned long secs;
267 unsigned long usecs; 267 unsigned long usecs;
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 1e5e9b270f5e..62ae30d34fa6 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -173,24 +173,23 @@ static struct perf_event_attr very_very_detailed_attrs[] = {
173 173
174 174
175 175
176struct perf_evlist *evsel_list; 176static struct perf_evlist *evsel_list;
177 177
178static bool system_wide = false; 178static struct perf_target target = {
179static int run_idx = 0; 179 .uid = UINT_MAX,
180};
180 181
182static int run_idx = 0;
181static int run_count = 1; 183static int run_count = 1;
182static bool no_inherit = false; 184static bool no_inherit = false;
183static bool scale = true; 185static bool scale = true;
184static bool no_aggr = false; 186static bool no_aggr = false;
185static const char *target_pid;
186static const char *target_tid;
187static pid_t child_pid = -1; 187static pid_t child_pid = -1;
188static bool null_run = false; 188static bool null_run = false;
189static int detailed_run = 0; 189static int detailed_run = 0;
190static bool sync_run = false; 190static bool sync_run = false;
191static bool big_num = true; 191static bool big_num = true;
192static int big_num_opt = -1; 192static int big_num_opt = -1;
193static const char *cpu_list;
194static const char *csv_sep = NULL; 193static const char *csv_sep = NULL;
195static bool csv_output = false; 194static bool csv_output = false;
196static bool group = false; 195static bool group = false;
@@ -265,18 +264,18 @@ static double stddev_stats(struct stats *stats)
265 return sqrt(variance_mean); 264 return sqrt(variance_mean);
266} 265}
267 266
268struct stats runtime_nsecs_stats[MAX_NR_CPUS]; 267static struct stats runtime_nsecs_stats[MAX_NR_CPUS];
269struct stats runtime_cycles_stats[MAX_NR_CPUS]; 268static struct stats runtime_cycles_stats[MAX_NR_CPUS];
270struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS]; 269static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS];
271struct stats runtime_stalled_cycles_back_stats[MAX_NR_CPUS]; 270static struct stats runtime_stalled_cycles_back_stats[MAX_NR_CPUS];
272struct stats runtime_branches_stats[MAX_NR_CPUS]; 271static struct stats runtime_branches_stats[MAX_NR_CPUS];
273struct stats runtime_cacherefs_stats[MAX_NR_CPUS]; 272static struct stats runtime_cacherefs_stats[MAX_NR_CPUS];
274struct stats runtime_l1_dcache_stats[MAX_NR_CPUS]; 273static struct stats runtime_l1_dcache_stats[MAX_NR_CPUS];
275struct stats runtime_l1_icache_stats[MAX_NR_CPUS]; 274static struct stats runtime_l1_icache_stats[MAX_NR_CPUS];
276struct stats runtime_ll_cache_stats[MAX_NR_CPUS]; 275static struct stats runtime_ll_cache_stats[MAX_NR_CPUS];
277struct stats runtime_itlb_cache_stats[MAX_NR_CPUS]; 276static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
278struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; 277static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
279struct stats walltime_nsecs_stats; 278static struct stats walltime_nsecs_stats;
280 279
281static int create_perf_stat_counter(struct perf_evsel *evsel, 280static int create_perf_stat_counter(struct perf_evsel *evsel,
282 struct perf_evsel *first) 281 struct perf_evsel *first)
@@ -299,15 +298,15 @@ retry:
299 if (exclude_guest_missing) 298 if (exclude_guest_missing)
300 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; 299 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
301 300
302 if (system_wide) { 301 if (perf_target__has_cpu(&target)) {
303 ret = perf_evsel__open_per_cpu(evsel, evsel_list->cpus, 302 ret = perf_evsel__open_per_cpu(evsel, evsel_list->cpus,
304 group, group_fd); 303 group, group_fd);
305 if (ret) 304 if (ret)
306 goto check_ret; 305 goto check_ret;
307 return 0; 306 return 0;
308 } 307 }
309 308
310 if (!target_pid && !target_tid && (!group || evsel == first)) { 309 if (!perf_target__has_task(&target) && (!group || evsel == first)) {
311 attr->disabled = 1; 310 attr->disabled = 1;
312 attr->enable_on_exec = 1; 311 attr->enable_on_exec = 1;
313 } 312 }
@@ -471,7 +470,7 @@ static int run_perf_stat(int argc __used, const char **argv)
471 exit(-1); 470 exit(-1);
472 } 471 }
473 472
474 if (!target_tid && !target_pid && !system_wide) 473 if (perf_target__none(&target))
475 evsel_list->threads->map[0] = child_pid; 474 evsel_list->threads->map[0] = child_pid;
476 475
477 /* 476 /*
@@ -506,7 +505,7 @@ static int run_perf_stat(int argc __used, const char **argv)
506 error("You may not have permission to collect %sstats.\n" 505 error("You may not have permission to collect %sstats.\n"
507 "\t Consider tweaking" 506 "\t Consider tweaking"
508 " /proc/sys/kernel/perf_event_paranoid or running as root.", 507 " /proc/sys/kernel/perf_event_paranoid or running as root.",
509 system_wide ? "system-wide " : ""); 508 target.system_wide ? "system-wide " : "");
510 } else { 509 } else {
511 error("open_counter returned with %d (%s). " 510 error("open_counter returned with %d (%s). "
512 "/bin/dmesg may provide additional information.\n", 511 "/bin/dmesg may provide additional information.\n",
@@ -998,14 +997,14 @@ static void print_stat(int argc, const char **argv)
998 if (!csv_output) { 997 if (!csv_output) {
999 fprintf(output, "\n"); 998 fprintf(output, "\n");
1000 fprintf(output, " Performance counter stats for "); 999 fprintf(output, " Performance counter stats for ");
1001 if (!target_pid && !target_tid) { 1000 if (!perf_target__has_task(&target)) {
1002 fprintf(output, "\'%s", argv[0]); 1001 fprintf(output, "\'%s", argv[0]);
1003 for (i = 1; i < argc; i++) 1002 for (i = 1; i < argc; i++)
1004 fprintf(output, " %s", argv[i]); 1003 fprintf(output, " %s", argv[i]);
1005 } else if (target_pid) 1004 } else if (target.pid)
1006 fprintf(output, "process id \'%s", target_pid); 1005 fprintf(output, "process id \'%s", target.pid);
1007 else 1006 else
1008 fprintf(output, "thread id \'%s", target_tid); 1007 fprintf(output, "thread id \'%s", target.tid);
1009 1008
1010 fprintf(output, "\'"); 1009 fprintf(output, "\'");
1011 if (run_count > 1) 1010 if (run_count > 1)
@@ -1079,11 +1078,11 @@ static const struct option options[] = {
1079 "event filter", parse_filter), 1078 "event filter", parse_filter),
1080 OPT_BOOLEAN('i', "no-inherit", &no_inherit, 1079 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
1081 "child tasks do not inherit counters"), 1080 "child tasks do not inherit counters"),
1082 OPT_STRING('p', "pid", &target_pid, "pid", 1081 OPT_STRING('p', "pid", &target.pid, "pid",
1083 "stat events on existing process id"), 1082 "stat events on existing process id"),
1084 OPT_STRING('t', "tid", &target_tid, "tid", 1083 OPT_STRING('t', "tid", &target.tid, "tid",
1085 "stat events on existing thread id"), 1084 "stat events on existing thread id"),
1086 OPT_BOOLEAN('a', "all-cpus", &system_wide, 1085 OPT_BOOLEAN('a', "all-cpus", &target.system_wide,
1087 "system-wide collection from all CPUs"), 1086 "system-wide collection from all CPUs"),
1088 OPT_BOOLEAN('g', "group", &group, 1087 OPT_BOOLEAN('g', "group", &group,
1089 "put the counters into a counter group"), 1088 "put the counters into a counter group"),
@@ -1102,7 +1101,7 @@ static const struct option options[] = {
1102 OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, 1101 OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
1103 "print large numbers with thousands\' separators", 1102 "print large numbers with thousands\' separators",
1104 stat__set_big_num), 1103 stat__set_big_num),
1105 OPT_STRING('C', "cpu", &cpu_list, "cpu", 1104 OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
1106 "list of cpus to monitor in system-wide"), 1105 "list of cpus to monitor in system-wide"),
1107 OPT_BOOLEAN('A', "no-aggr", &no_aggr, 1106 OPT_BOOLEAN('A', "no-aggr", &no_aggr,
1108 "disable CPU count aggregation"), 1107 "disable CPU count aggregation"),
@@ -1220,13 +1219,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1220 } else if (big_num_opt == 0) /* User passed --no-big-num */ 1219 } else if (big_num_opt == 0) /* User passed --no-big-num */
1221 big_num = false; 1220 big_num = false;
1222 1221
1223 if (!argc && !target_pid && !target_tid) 1222 if (!argc && !perf_target__has_task(&target))
1224 usage_with_options(stat_usage, options); 1223 usage_with_options(stat_usage, options);
1225 if (run_count <= 0) 1224 if (run_count <= 0)
1226 usage_with_options(stat_usage, options); 1225 usage_with_options(stat_usage, options);
1227 1226
1228 /* no_aggr, cgroup are for system-wide only */ 1227 /* no_aggr, cgroup are for system-wide only */
1229 if ((no_aggr || nr_cgroups) && !system_wide) { 1228 if ((no_aggr || nr_cgroups) && !perf_target__has_cpu(&target)) {
1230 fprintf(stderr, "both cgroup and no-aggregation " 1229 fprintf(stderr, "both cgroup and no-aggregation "
1231 "modes only available in system-wide mode\n"); 1230 "modes only available in system-wide mode\n");
1232 1231
@@ -1236,23 +1235,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1236 if (add_default_attributes()) 1235 if (add_default_attributes())
1237 goto out; 1236 goto out;
1238 1237
1239 if (target_pid) 1238 perf_target__validate(&target);
1240 target_tid = target_pid;
1241 1239
1242 evsel_list->threads = thread_map__new_str(target_pid, 1240 if (perf_evlist__create_maps(evsel_list, &target) < 0) {
1243 target_tid, UINT_MAX); 1241 if (perf_target__has_task(&target))
1244 if (evsel_list->threads == NULL) { 1242 pr_err("Problems finding threads of monitor\n");
1245 pr_err("Problems finding threads of monitor\n"); 1243 if (perf_target__has_cpu(&target))
1246 usage_with_options(stat_usage, options); 1244 perror("failed to parse CPUs map");
1247 }
1248
1249 if (system_wide)
1250 evsel_list->cpus = cpu_map__new(cpu_list);
1251 else
1252 evsel_list->cpus = cpu_map__dummy_new();
1253 1245
1254 if (evsel_list->cpus == NULL) {
1255 perror("failed to parse CPUs map");
1256 usage_with_options(stat_usage, options); 1246 usage_with_options(stat_usage, options);
1257 return -1; 1247 return -1;
1258 } 1248 }
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 223ffdcc0fd8..5a8727c08757 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -604,556 +604,6 @@ out_free_threads:
604#undef nsyscalls 604#undef nsyscalls
605} 605}
606 606
607#define TEST_ASSERT_VAL(text, cond) \
608do { \
609 if (!(cond)) { \
610 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
611 return -1; \
612 } \
613} while (0)
614
615static int test__checkevent_tracepoint(struct perf_evlist *evlist)
616{
617 struct perf_evsel *evsel = list_entry(evlist->entries.next,
618 struct perf_evsel, node);
619
620 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
621 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
622 TEST_ASSERT_VAL("wrong sample_type",
623 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
624 evsel->attr.sample_type);
625 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
626 return 0;
627}
628
629static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
630{
631 struct perf_evsel *evsel;
632
633 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
634
635 list_for_each_entry(evsel, &evlist->entries, node) {
636 TEST_ASSERT_VAL("wrong type",
637 PERF_TYPE_TRACEPOINT == evsel->attr.type);
638 TEST_ASSERT_VAL("wrong sample_type",
639 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
640 == evsel->attr.sample_type);
641 TEST_ASSERT_VAL("wrong sample_period",
642 1 == evsel->attr.sample_period);
643 }
644 return 0;
645}
646
647static int test__checkevent_raw(struct perf_evlist *evlist)
648{
649 struct perf_evsel *evsel = list_entry(evlist->entries.next,
650 struct perf_evsel, node);
651
652 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
653 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
654 TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config);
655 return 0;
656}
657
658static int test__checkevent_numeric(struct perf_evlist *evlist)
659{
660 struct perf_evsel *evsel = list_entry(evlist->entries.next,
661 struct perf_evsel, node);
662
663 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
664 TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
665 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
666 return 0;
667}
668
669static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
670{
671 struct perf_evsel *evsel = list_entry(evlist->entries.next,
672 struct perf_evsel, node);
673
674 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
675 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
676 TEST_ASSERT_VAL("wrong config",
677 PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
678 return 0;
679}
680
681static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist)
682{
683 struct perf_evsel *evsel = list_entry(evlist->entries.next,
684 struct perf_evsel, node);
685
686 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
687 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
688 TEST_ASSERT_VAL("wrong config",
689 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
690 TEST_ASSERT_VAL("wrong period",
691 100000 == evsel->attr.sample_period);
692 TEST_ASSERT_VAL("wrong config1",
693 0 == evsel->attr.config1);
694 TEST_ASSERT_VAL("wrong config2",
695 1 == evsel->attr.config2);
696 return 0;
697}
698
699static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
700{
701 struct perf_evsel *evsel = list_entry(evlist->entries.next,
702 struct perf_evsel, node);
703
704 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
705 TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
706 TEST_ASSERT_VAL("wrong config",
707 PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
708 return 0;
709}
710
711static int test__checkevent_genhw(struct perf_evlist *evlist)
712{
713 struct perf_evsel *evsel = list_entry(evlist->entries.next,
714 struct perf_evsel, node);
715
716 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
717 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
718 TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config);
719 return 0;
720}
721
722static int test__checkevent_breakpoint(struct perf_evlist *evlist)
723{
724 struct perf_evsel *evsel = list_entry(evlist->entries.next,
725 struct perf_evsel, node);
726
727 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
728 TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
729 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
730 TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
731 evsel->attr.bp_type);
732 TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
733 evsel->attr.bp_len);
734 return 0;
735}
736
737static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
738{
739 struct perf_evsel *evsel = list_entry(evlist->entries.next,
740 struct perf_evsel, node);
741
742 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
743 TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
744 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
745 TEST_ASSERT_VAL("wrong bp_type",
746 HW_BREAKPOINT_X == evsel->attr.bp_type);
747 TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len);
748 return 0;
749}
750
751static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
752{
753 struct perf_evsel *evsel = list_entry(evlist->entries.next,
754 struct perf_evsel, node);
755
756 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
757 TEST_ASSERT_VAL("wrong type",
758 PERF_TYPE_BREAKPOINT == evsel->attr.type);
759 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
760 TEST_ASSERT_VAL("wrong bp_type",
761 HW_BREAKPOINT_R == evsel->attr.bp_type);
762 TEST_ASSERT_VAL("wrong bp_len",
763 HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
764 return 0;
765}
766
767static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
768{
769 struct perf_evsel *evsel = list_entry(evlist->entries.next,
770 struct perf_evsel, node);
771
772 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
773 TEST_ASSERT_VAL("wrong type",
774 PERF_TYPE_BREAKPOINT == evsel->attr.type);
775 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
776 TEST_ASSERT_VAL("wrong bp_type",
777 HW_BREAKPOINT_W == evsel->attr.bp_type);
778 TEST_ASSERT_VAL("wrong bp_len",
779 HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
780 return 0;
781}
782
783static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist)
784{
785 struct perf_evsel *evsel = list_entry(evlist->entries.next,
786 struct perf_evsel, node);
787
788 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
789 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
790 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
791 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
792
793 return test__checkevent_tracepoint(evlist);
794}
795
796static int
797test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist)
798{
799 struct perf_evsel *evsel;
800
801 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
802
803 list_for_each_entry(evsel, &evlist->entries, node) {
804 TEST_ASSERT_VAL("wrong exclude_user",
805 !evsel->attr.exclude_user);
806 TEST_ASSERT_VAL("wrong exclude_kernel",
807 evsel->attr.exclude_kernel);
808 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
809 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
810 }
811
812 return test__checkevent_tracepoint_multi(evlist);
813}
814
815static int test__checkevent_raw_modifier(struct perf_evlist *evlist)
816{
817 struct perf_evsel *evsel = list_entry(evlist->entries.next,
818 struct perf_evsel, node);
819
820 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
821 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
822 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
823 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
824
825 return test__checkevent_raw(evlist);
826}
827
828static int test__checkevent_numeric_modifier(struct perf_evlist *evlist)
829{
830 struct perf_evsel *evsel = list_entry(evlist->entries.next,
831 struct perf_evsel, node);
832
833 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
834 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
835 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
836 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
837
838 return test__checkevent_numeric(evlist);
839}
840
841static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist)
842{
843 struct perf_evsel *evsel = list_entry(evlist->entries.next,
844 struct perf_evsel, node);
845
846 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
847 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
848 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
849 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
850
851 return test__checkevent_symbolic_name(evlist);
852}
853
854static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist)
855{
856 struct perf_evsel *evsel = list_entry(evlist->entries.next,
857 struct perf_evsel, node);
858
859 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
860 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
861
862 return test__checkevent_symbolic_name(evlist);
863}
864
865static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist)
866{
867 struct perf_evsel *evsel = list_entry(evlist->entries.next,
868 struct perf_evsel, node);
869
870 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
871 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
872
873 return test__checkevent_symbolic_name(evlist);
874}
875
876static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist)
877{
878 struct perf_evsel *evsel = list_entry(evlist->entries.next,
879 struct perf_evsel, node);
880
881 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
882 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
883 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
884 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
885
886 return test__checkevent_symbolic_alias(evlist);
887}
888
889static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
890{
891 struct perf_evsel *evsel = list_entry(evlist->entries.next,
892 struct perf_evsel, node);
893
894 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
895 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
896 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
897 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
898
899 return test__checkevent_genhw(evlist);
900}
901
902static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
903{
904 struct perf_evsel *evsel = list_entry(evlist->entries.next,
905 struct perf_evsel, node);
906
907 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
908 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
909 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
910 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
911
912 return test__checkevent_breakpoint(evlist);
913}
914
915static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
916{
917 struct perf_evsel *evsel = list_entry(evlist->entries.next,
918 struct perf_evsel, node);
919
920 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
921 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
922 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
923 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
924
925 return test__checkevent_breakpoint_x(evlist);
926}
927
928static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
929{
930 struct perf_evsel *evsel = list_entry(evlist->entries.next,
931 struct perf_evsel, node);
932
933 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
934 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
935 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
936 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
937
938 return test__checkevent_breakpoint_r(evlist);
939}
940
941static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
942{
943 struct perf_evsel *evsel = list_entry(evlist->entries.next,
944 struct perf_evsel, node);
945
946 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
947 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
948 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
949 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
950
951 return test__checkevent_breakpoint_w(evlist);
952}
953
954static int test__checkevent_pmu(struct perf_evlist *evlist)
955{
956
957 struct perf_evsel *evsel = list_entry(evlist->entries.next,
958 struct perf_evsel, node);
959
960 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
961 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
962 TEST_ASSERT_VAL("wrong config", 10 == evsel->attr.config);
963 TEST_ASSERT_VAL("wrong config1", 1 == evsel->attr.config1);
964 TEST_ASSERT_VAL("wrong config2", 3 == evsel->attr.config2);
965 TEST_ASSERT_VAL("wrong period", 1000 == evsel->attr.sample_period);
966
967 return 0;
968}
969
970static int test__checkevent_list(struct perf_evlist *evlist)
971{
972 struct perf_evsel *evsel;
973
974 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
975
976 /* r1 */
977 evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
978 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
979 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
980 TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
981 TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2);
982 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
983 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
984 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
985 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
986
987 /* syscalls:sys_enter_open:k */
988 evsel = list_entry(evsel->node.next, struct perf_evsel, node);
989 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
990 TEST_ASSERT_VAL("wrong sample_type",
991 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
992 evsel->attr.sample_type);
993 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
994 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
995 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
996 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
997 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
998
999 /* 1:1:hp */
1000 evsel = list_entry(evsel->node.next, struct perf_evsel, node);
1001 TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
1002 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
1003 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
1004 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
1005 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
1006 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
1007
1008 return 0;
1009}
1010
1011static struct test__event_st {
1012 const char *name;
1013 __u32 type;
1014 int (*check)(struct perf_evlist *evlist);
1015} test__events[] = {
1016 {
1017 .name = "syscalls:sys_enter_open",
1018 .check = test__checkevent_tracepoint,
1019 },
1020 {
1021 .name = "syscalls:*",
1022 .check = test__checkevent_tracepoint_multi,
1023 },
1024 {
1025 .name = "r1a",
1026 .check = test__checkevent_raw,
1027 },
1028 {
1029 .name = "1:1",
1030 .check = test__checkevent_numeric,
1031 },
1032 {
1033 .name = "instructions",
1034 .check = test__checkevent_symbolic_name,
1035 },
1036 {
1037 .name = "cycles/period=100000,config2/",
1038 .check = test__checkevent_symbolic_name_config,
1039 },
1040 {
1041 .name = "faults",
1042 .check = test__checkevent_symbolic_alias,
1043 },
1044 {
1045 .name = "L1-dcache-load-miss",
1046 .check = test__checkevent_genhw,
1047 },
1048 {
1049 .name = "mem:0",
1050 .check = test__checkevent_breakpoint,
1051 },
1052 {
1053 .name = "mem:0:x",
1054 .check = test__checkevent_breakpoint_x,
1055 },
1056 {
1057 .name = "mem:0:r",
1058 .check = test__checkevent_breakpoint_r,
1059 },
1060 {
1061 .name = "mem:0:w",
1062 .check = test__checkevent_breakpoint_w,
1063 },
1064 {
1065 .name = "syscalls:sys_enter_open:k",
1066 .check = test__checkevent_tracepoint_modifier,
1067 },
1068 {
1069 .name = "syscalls:*:u",
1070 .check = test__checkevent_tracepoint_multi_modifier,
1071 },
1072 {
1073 .name = "r1a:kp",
1074 .check = test__checkevent_raw_modifier,
1075 },
1076 {
1077 .name = "1:1:hp",
1078 .check = test__checkevent_numeric_modifier,
1079 },
1080 {
1081 .name = "instructions:h",
1082 .check = test__checkevent_symbolic_name_modifier,
1083 },
1084 {
1085 .name = "faults:u",
1086 .check = test__checkevent_symbolic_alias_modifier,
1087 },
1088 {
1089 .name = "L1-dcache-load-miss:kp",
1090 .check = test__checkevent_genhw_modifier,
1091 },
1092 {
1093 .name = "mem:0:u",
1094 .check = test__checkevent_breakpoint_modifier,
1095 },
1096 {
1097 .name = "mem:0:x:k",
1098 .check = test__checkevent_breakpoint_x_modifier,
1099 },
1100 {
1101 .name = "mem:0:r:hp",
1102 .check = test__checkevent_breakpoint_r_modifier,
1103 },
1104 {
1105 .name = "mem:0:w:up",
1106 .check = test__checkevent_breakpoint_w_modifier,
1107 },
1108 {
1109 .name = "cpu/config=10,config1,config2=3,period=1000/u",
1110 .check = test__checkevent_pmu,
1111 },
1112 {
1113 .name = "r1,syscalls:sys_enter_open:k,1:1:hp",
1114 .check = test__checkevent_list,
1115 },
1116 {
1117 .name = "instructions:G",
1118 .check = test__checkevent_exclude_host_modifier,
1119 },
1120 {
1121 .name = "instructions:H",
1122 .check = test__checkevent_exclude_guest_modifier,
1123 },
1124};
1125
1126#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
1127
1128static int test__parse_events(void)
1129{
1130 struct perf_evlist *evlist;
1131 u_int i;
1132 int ret = 0;
1133
1134 for (i = 0; i < TEST__EVENTS_CNT; i++) {
1135 struct test__event_st *e = &test__events[i];
1136
1137 evlist = perf_evlist__new(NULL, NULL);
1138 if (evlist == NULL)
1139 break;
1140
1141 ret = parse_events(evlist, e->name, 0);
1142 if (ret) {
1143 pr_debug("failed to parse event '%s', err %d\n",
1144 e->name, ret);
1145 break;
1146 }
1147
1148 ret = e->check(evlist);
1149 perf_evlist__delete(evlist);
1150 if (ret)
1151 break;
1152 }
1153
1154 return ret;
1155}
1156
1157static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp, 607static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp,
1158 size_t *sizep) 608 size_t *sizep)
1159{ 609{
@@ -1195,6 +645,10 @@ realloc:
1195static int test__PERF_RECORD(void) 645static int test__PERF_RECORD(void)
1196{ 646{
1197 struct perf_record_opts opts = { 647 struct perf_record_opts opts = {
648 .target = {
649 .uid = UINT_MAX,
650 .uses_mmap = true,
651 },
1198 .no_delay = true, 652 .no_delay = true,
1199 .freq = 10, 653 .freq = 10,
1200 .mmap_pages = 256, 654 .mmap_pages = 256,
@@ -1237,8 +691,7 @@ static int test__PERF_RECORD(void)
1237 * perf_evlist__prepare_workload we'll fill in the only thread 691 * perf_evlist__prepare_workload we'll fill in the only thread
1238 * we're monitoring, the one forked there. 692 * we're monitoring, the one forked there.
1239 */ 693 */
1240 err = perf_evlist__create_maps(evlist, opts.target_pid, 694 err = perf_evlist__create_maps(evlist, &opts.target);
1241 opts.target_tid, UINT_MAX, opts.cpu_list);
1242 if (err < 0) { 695 if (err < 0) {
1243 pr_debug("Not enough memory to create thread/cpu maps\n"); 696 pr_debug("Not enough memory to create thread/cpu maps\n");
1244 goto out_delete_evlist; 697 goto out_delete_evlist;
@@ -1579,8 +1032,6 @@ static int __test__rdpmc(void)
1579 sa.sa_sigaction = segfault_handler; 1032 sa.sa_sigaction = segfault_handler;
1580 sigaction(SIGSEGV, &sa, NULL); 1033 sigaction(SIGSEGV, &sa, NULL);
1581 1034
1582 fprintf(stderr, "\n\n");
1583
1584 fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 1035 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
1585 if (fd < 0) { 1036 if (fd < 0) {
1586 die("Error: sys_perf_event_open() syscall returned " 1037 die("Error: sys_perf_event_open() syscall returned "
@@ -1605,7 +1056,7 @@ static int __test__rdpmc(void)
1605 loops *= 10; 1056 loops *= 10;
1606 1057
1607 delta = now - stamp; 1058 delta = now - stamp;
1608 fprintf(stderr, "%14d: %14Lu\n", n, (long long)delta); 1059 pr_debug("%14d: %14Lu\n", n, (long long)delta);
1609 1060
1610 delta_sum += delta; 1061 delta_sum += delta;
1611 } 1062 }
@@ -1613,7 +1064,7 @@ static int __test__rdpmc(void)
1613 munmap(addr, page_size); 1064 munmap(addr, page_size);
1614 close(fd); 1065 close(fd);
1615 1066
1616 fprintf(stderr, " "); 1067 pr_debug(" ");
1617 1068
1618 if (!delta_sum) 1069 if (!delta_sum)
1619 return -1; 1070 return -1;
@@ -1674,7 +1125,7 @@ static struct test {
1674 }, 1125 },
1675 { 1126 {
1676 .desc = "parse events tests", 1127 .desc = "parse events tests",
1677 .func = test__parse_events, 1128 .func = parse_events__test,
1678 }, 1129 },
1679#if defined(__x86_64__) || defined(__i386__) 1130#if defined(__x86_64__) || defined(__i386__)
1680 { 1131 {
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 8ef59f8262bb..871b540293e1 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -588,7 +588,7 @@ static void *display_thread_tui(void *arg)
588 * via --uid. 588 * via --uid.
589 */ 589 */
590 list_for_each_entry(pos, &top->evlist->entries, node) 590 list_for_each_entry(pos, &top->evlist->entries, node)
591 pos->hists.uid_filter_str = top->uid_str; 591 pos->hists.uid_filter_str = top->target.uid_str;
592 592
593 perf_evlist__tui_browse_hists(top->evlist, help, 593 perf_evlist__tui_browse_hists(top->evlist, help,
594 perf_top__sort_new_samples, 594 perf_top__sort_new_samples,
@@ -900,6 +900,9 @@ static void perf_top__start_counters(struct perf_top *top)
900 attr->read_format |= PERF_FORMAT_ID; 900 attr->read_format |= PERF_FORMAT_ID;
901 } 901 }
902 902
903 if (perf_target__has_cpu(&top->target))
904 attr->sample_type |= PERF_SAMPLE_CPU;
905
903 if (symbol_conf.use_callchain) 906 if (symbol_conf.use_callchain)
904 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 907 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
905 908
@@ -948,20 +951,24 @@ try_again:
948 951
949 attr->type = PERF_TYPE_SOFTWARE; 952 attr->type = PERF_TYPE_SOFTWARE;
950 attr->config = PERF_COUNT_SW_CPU_CLOCK; 953 attr->config = PERF_COUNT_SW_CPU_CLOCK;
954 if (counter->name) {
955 free(counter->name);
956 counter->name = NULL;
957 }
951 goto try_again; 958 goto try_again;
952 } 959 }
953 960
954 if (err == ENOENT) { 961 if (err == ENOENT) {
955 ui__warning("The %s event is not supported.\n", 962 ui__error("The %s event is not supported.\n",
956 event_name(counter)); 963 event_name(counter));
957 goto out_err; 964 goto out_err;
958 } else if (err == EMFILE) { 965 } else if (err == EMFILE) {
959 ui__warning("Too many events are opened.\n" 966 ui__error("Too many events are opened.\n"
960 "Try again after reducing the number of events\n"); 967 "Try again after reducing the number of events\n");
961 goto out_err; 968 goto out_err;
962 } 969 }
963 970
964 ui__warning("The sys_perf_event_open() syscall " 971 ui__error("The sys_perf_event_open() syscall "
965 "returned with %d (%s). /bin/dmesg " 972 "returned with %d (%s). /bin/dmesg "
966 "may provide additional information.\n" 973 "may provide additional information.\n"
967 "No CONFIG_PERF_EVENTS=y kernel support " 974 "No CONFIG_PERF_EVENTS=y kernel support "
@@ -971,7 +978,7 @@ try_again:
971 } 978 }
972 979
973 if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) { 980 if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) {
974 ui__warning("Failed to mmap with %d (%s)\n", 981 ui__error("Failed to mmap with %d (%s)\n",
975 errno, strerror(errno)); 982 errno, strerror(errno));
976 goto out_err; 983 goto out_err;
977 } 984 }
@@ -987,12 +994,12 @@ static int perf_top__setup_sample_type(struct perf_top *top)
987{ 994{
988 if (!top->sort_has_symbols) { 995 if (!top->sort_has_symbols) {
989 if (symbol_conf.use_callchain) { 996 if (symbol_conf.use_callchain) {
990 ui__warning("Selected -g but \"sym\" not present in --sort/-s."); 997 ui__error("Selected -g but \"sym\" not present in --sort/-s.");
991 return -EINVAL; 998 return -EINVAL;
992 } 999 }
993 } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) { 1000 } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) {
994 if (callchain_register_param(&callchain_param) < 0) { 1001 if (callchain_register_param(&callchain_param) < 0) {
995 ui__warning("Can't register callchain params.\n"); 1002 ui__error("Can't register callchain params.\n");
996 return -EINVAL; 1003 return -EINVAL;
997 } 1004 }
998 } 1005 }
@@ -1016,7 +1023,7 @@ static int __cmd_top(struct perf_top *top)
1016 if (ret) 1023 if (ret)
1017 goto out_delete; 1024 goto out_delete;
1018 1025
1019 if (top->target_tid || top->uid != UINT_MAX) 1026 if (perf_target__has_task(&top->target))
1020 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, 1027 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
1021 perf_event__process, 1028 perf_event__process,
1022 &top->session->host_machine); 1029 &top->session->host_machine);
@@ -1034,7 +1041,7 @@ static int __cmd_top(struct perf_top *top)
1034 1041
1035 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : 1042 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
1036 display_thread), top)) { 1043 display_thread), top)) {
1037 printf("Could not create display thread.\n"); 1044 ui__error("Could not create display thread.\n");
1038 exit(-1); 1045 exit(-1);
1039 } 1046 }
1040 1047
@@ -1043,7 +1050,7 @@ static int __cmd_top(struct perf_top *top)
1043 1050
1044 param.sched_priority = top->realtime_prio; 1051 param.sched_priority = top->realtime_prio;
1045 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 1052 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
1046 printf("Could not set realtime priority.\n"); 1053 ui__error("Could not set realtime priority.\n");
1047 exit(-1); 1054 exit(-1);
1048 } 1055 }
1049 } 1056 }
@@ -1150,14 +1157,17 @@ static const char * const top_usage[] = {
1150int cmd_top(int argc, const char **argv, const char *prefix __used) 1157int cmd_top(int argc, const char **argv, const char *prefix __used)
1151{ 1158{
1152 struct perf_evsel *pos; 1159 struct perf_evsel *pos;
1153 int status = -ENOMEM; 1160 int status;
1161 char errbuf[BUFSIZ];
1154 struct perf_top top = { 1162 struct perf_top top = {
1155 .count_filter = 5, 1163 .count_filter = 5,
1156 .delay_secs = 2, 1164 .delay_secs = 2,
1157 .uid = UINT_MAX, 1165 .freq = 4000, /* 4 KHz */
1158 .freq = 1000, /* 1 KHz */
1159 .mmap_pages = 128, 1166 .mmap_pages = 128,
1160 .sym_pcnt_filter = 5, 1167 .sym_pcnt_filter = 5,
1168 .target = {
1169 .uses_mmap = true,
1170 },
1161 }; 1171 };
1162 char callchain_default_opt[] = "fractal,0.5,callee"; 1172 char callchain_default_opt[] = "fractal,0.5,callee";
1163 const struct option options[] = { 1173 const struct option options[] = {
@@ -1166,13 +1176,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1166 parse_events_option), 1176 parse_events_option),
1167 OPT_INTEGER('c', "count", &top.default_interval, 1177 OPT_INTEGER('c', "count", &top.default_interval,
1168 "event period to sample"), 1178 "event period to sample"),
1169 OPT_STRING('p', "pid", &top.target_pid, "pid", 1179 OPT_STRING('p', "pid", &top.target.pid, "pid",
1170 "profile events on existing process id"), 1180 "profile events on existing process id"),
1171 OPT_STRING('t', "tid", &top.target_tid, "tid", 1181 OPT_STRING('t', "tid", &top.target.tid, "tid",
1172 "profile events on existing thread id"), 1182 "profile events on existing thread id"),
1173 OPT_BOOLEAN('a', "all-cpus", &top.system_wide, 1183 OPT_BOOLEAN('a', "all-cpus", &top.target.system_wide,
1174 "system-wide collection from all CPUs"), 1184 "system-wide collection from all CPUs"),
1175 OPT_STRING('C', "cpu", &top.cpu_list, "cpu", 1185 OPT_STRING('C', "cpu", &top.target.cpu_list, "cpu",
1176 "list of cpus to monitor"), 1186 "list of cpus to monitor"),
1177 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 1187 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1178 "file", "vmlinux pathname"), 1188 "file", "vmlinux pathname"),
@@ -1227,7 +1237,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1227 "Display raw encoding of assembly instructions (default)"), 1237 "Display raw encoding of assembly instructions (default)"),
1228 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 1238 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1229 "Specify disassembler style (e.g. -M intel for intel syntax)"), 1239 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1230 OPT_STRING('u', "uid", &top.uid_str, "user", "user to profile"), 1240 OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"),
1231 OPT_END() 1241 OPT_END()
1232 }; 1242 };
1233 1243
@@ -1253,27 +1263,32 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1253 1263
1254 setup_browser(false); 1264 setup_browser(false);
1255 1265
1256 top.uid = parse_target_uid(top.uid_str, top.target_tid, top.target_pid); 1266 status = perf_target__validate(&top.target);
1257 if (top.uid_str != NULL && top.uid == UINT_MAX - 1) 1267 if (status) {
1258 goto out_delete_evlist; 1268 perf_target__strerror(&top.target, status, errbuf, BUFSIZ);
1269 ui__warning("%s", errbuf);
1270 }
1259 1271
1260 /* CPU and PID are mutually exclusive */ 1272 status = perf_target__parse_uid(&top.target);
1261 if (top.target_tid && top.cpu_list) { 1273 if (status) {
1262 printf("WARNING: PID switch overriding CPU\n"); 1274 int saved_errno = errno;
1263 sleep(1); 1275
1264 top.cpu_list = NULL; 1276 perf_target__strerror(&top.target, status, errbuf, BUFSIZ);
1277 ui__error("%s", errbuf);
1278
1279 status = -saved_errno;
1280 goto out_delete_evlist;
1265 } 1281 }
1266 1282
1267 if (top.target_pid) 1283 if (perf_target__none(&top.target))
1268 top.target_tid = top.target_pid; 1284 top.target.system_wide = true;
1269 1285
1270 if (perf_evlist__create_maps(top.evlist, top.target_pid, 1286 if (perf_evlist__create_maps(top.evlist, &top.target) < 0)
1271 top.target_tid, top.uid, top.cpu_list) < 0)
1272 usage_with_options(top_usage, options); 1287 usage_with_options(top_usage, options);
1273 1288
1274 if (!top.evlist->nr_entries && 1289 if (!top.evlist->nr_entries &&
1275 perf_evlist__add_default(top.evlist) < 0) { 1290 perf_evlist__add_default(top.evlist) < 0) {
1276 pr_err("Not enough memory for event selector list\n"); 1291 ui__error("Not enough memory for event selector list\n");
1277 return -ENOMEM; 1292 return -ENOMEM;
1278 } 1293 }
1279 1294
@@ -1290,7 +1305,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1290 else if (top.freq) { 1305 else if (top.freq) {
1291 top.default_interval = top.freq; 1306 top.default_interval = top.freq;
1292 } else { 1307 } else {
1293 fprintf(stderr, "frequency and count are zero, aborting\n"); 1308 ui__error("frequency and count are zero, aborting\n");
1294 exit(EXIT_FAILURE); 1309 exit(EXIT_FAILURE);
1295 } 1310 }
1296 1311
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 89e3355ab173..f960ccb2edc6 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -207,10 +207,10 @@ extern const char perf_version_string[];
207 207
208void pthread__unblock_sigwinch(void); 208void pthread__unblock_sigwinch(void);
209 209
210#include "util/target.h"
211
210struct perf_record_opts { 212struct perf_record_opts {
211 const char *target_pid; 213 struct perf_target target;
212 const char *target_tid;
213 uid_t uid;
214 bool call_graph; 214 bool call_graph;
215 bool group; 215 bool group;
216 bool inherit_stat; 216 bool inherit_stat;
@@ -223,15 +223,13 @@ struct perf_record_opts {
223 bool sample_time; 223 bool sample_time;
224 bool sample_id_all_missing; 224 bool sample_id_all_missing;
225 bool exclude_guest_missing; 225 bool exclude_guest_missing;
226 bool system_wide;
227 bool period; 226 bool period;
228 unsigned int freq; 227 unsigned int freq;
229 unsigned int mmap_pages; 228 unsigned int mmap_pages;
230 unsigned int user_freq; 229 unsigned int user_freq;
231 int branch_stack; 230 u64 branch_stack;
232 u64 default_interval; 231 u64 default_interval;
233 u64 user_interval; 232 u64 user_interval;
234 const char *cpu_list;
235}; 233};
236 234
237#endif 235#endif
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/ui/browser.c
index 556829124b02..1818a531f1d3 100644
--- a/tools/perf/util/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -27,21 +27,24 @@ static int ui_browser__percent_color(struct ui_browser *browser,
27 return HE_COLORSET_NORMAL; 27 return HE_COLORSET_NORMAL;
28} 28}
29 29
30void ui_browser__set_color(struct ui_browser *self __used, int color) 30int ui_browser__set_color(struct ui_browser *browser, int color)
31{ 31{
32 int ret = browser->current_color;
33 browser->current_color = color;
32 SLsmg_set_color(color); 34 SLsmg_set_color(color);
35 return ret;
33} 36}
34 37
35void ui_browser__set_percent_color(struct ui_browser *self, 38void ui_browser__set_percent_color(struct ui_browser *browser,
36 double percent, bool current) 39 double percent, bool current)
37{ 40{
38 int color = ui_browser__percent_color(self, percent, current); 41 int color = ui_browser__percent_color(browser, percent, current);
39 ui_browser__set_color(self, color); 42 ui_browser__set_color(browser, color);
40} 43}
41 44
42void ui_browser__gotorc(struct ui_browser *self, int y, int x) 45void ui_browser__gotorc(struct ui_browser *browser, int y, int x)
43{ 46{
44 SLsmg_gotorc(self->y + y, self->x + x); 47 SLsmg_gotorc(browser->y + y, browser->x + x);
45} 48}
46 49
47static struct list_head * 50static struct list_head *
@@ -70,23 +73,23 @@ ui_browser__list_head_filter_prev_entries(struct ui_browser *browser,
70 return NULL; 73 return NULL;
71} 74}
72 75
73void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence) 76void ui_browser__list_head_seek(struct ui_browser *browser, off_t offset, int whence)
74{ 77{
75 struct list_head *head = self->entries; 78 struct list_head *head = browser->entries;
76 struct list_head *pos; 79 struct list_head *pos;
77 80
78 if (self->nr_entries == 0) 81 if (browser->nr_entries == 0)
79 return; 82 return;
80 83
81 switch (whence) { 84 switch (whence) {
82 case SEEK_SET: 85 case SEEK_SET:
83 pos = ui_browser__list_head_filter_entries(self, head->next); 86 pos = ui_browser__list_head_filter_entries(browser, head->next);
84 break; 87 break;
85 case SEEK_CUR: 88 case SEEK_CUR:
86 pos = self->top; 89 pos = browser->top;
87 break; 90 break;
88 case SEEK_END: 91 case SEEK_END:
89 pos = ui_browser__list_head_filter_prev_entries(self, head->prev); 92 pos = ui_browser__list_head_filter_prev_entries(browser, head->prev);
90 break; 93 break;
91 default: 94 default:
92 return; 95 return;
@@ -96,18 +99,18 @@ void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whenc
96 99
97 if (offset > 0) { 100 if (offset > 0) {
98 while (offset-- != 0) 101 while (offset-- != 0)
99 pos = ui_browser__list_head_filter_entries(self, pos->next); 102 pos = ui_browser__list_head_filter_entries(browser, pos->next);
100 } else { 103 } else {
101 while (offset++ != 0) 104 while (offset++ != 0)
102 pos = ui_browser__list_head_filter_prev_entries(self, pos->prev); 105 pos = ui_browser__list_head_filter_prev_entries(browser, pos->prev);
103 } 106 }
104 107
105 self->top = pos; 108 browser->top = pos;
106} 109}
107 110
108void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence) 111void ui_browser__rb_tree_seek(struct ui_browser *browser, off_t offset, int whence)
109{ 112{
110 struct rb_root *root = self->entries; 113 struct rb_root *root = browser->entries;
111 struct rb_node *nd; 114 struct rb_node *nd;
112 115
113 switch (whence) { 116 switch (whence) {
@@ -115,7 +118,7 @@ void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence)
115 nd = rb_first(root); 118 nd = rb_first(root);
116 break; 119 break;
117 case SEEK_CUR: 120 case SEEK_CUR:
118 nd = self->top; 121 nd = browser->top;
119 break; 122 break;
120 case SEEK_END: 123 case SEEK_END:
121 nd = rb_last(root); 124 nd = rb_last(root);
@@ -132,23 +135,23 @@ void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence)
132 nd = rb_prev(nd); 135 nd = rb_prev(nd);
133 } 136 }
134 137
135 self->top = nd; 138 browser->top = nd;
136} 139}
137 140
138unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self) 141unsigned int ui_browser__rb_tree_refresh(struct ui_browser *browser)
139{ 142{
140 struct rb_node *nd; 143 struct rb_node *nd;
141 int row = 0; 144 int row = 0;
142 145
143 if (self->top == NULL) 146 if (browser->top == NULL)
144 self->top = rb_first(self->entries); 147 browser->top = rb_first(browser->entries);
145 148
146 nd = self->top; 149 nd = browser->top;
147 150
148 while (nd != NULL) { 151 while (nd != NULL) {
149 ui_browser__gotorc(self, row, 0); 152 ui_browser__gotorc(browser, row, 0);
150 self->write(self, nd, row); 153 browser->write(browser, nd, row);
151 if (++row == self->height) 154 if (++row == browser->height)
152 break; 155 break;
153 nd = rb_next(nd); 156 nd = rb_next(nd);
154 } 157 }
@@ -156,17 +159,17 @@ unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self)
156 return row; 159 return row;
157} 160}
158 161
159bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row) 162bool ui_browser__is_current_entry(struct ui_browser *browser, unsigned row)
160{ 163{
161 return self->top_idx + row == self->index; 164 return browser->top_idx + row == browser->index;
162} 165}
163 166
164void ui_browser__refresh_dimensions(struct ui_browser *self) 167void ui_browser__refresh_dimensions(struct ui_browser *browser)
165{ 168{
166 self->width = SLtt_Screen_Cols - 1; 169 browser->width = SLtt_Screen_Cols - 1;
167 self->height = SLtt_Screen_Rows - 2; 170 browser->height = SLtt_Screen_Rows - 2;
168 self->y = 1; 171 browser->y = 1;
169 self->x = 0; 172 browser->x = 0;
170} 173}
171 174
172void ui_browser__handle_resize(struct ui_browser *browser) 175void ui_browser__handle_resize(struct ui_browser *browser)
@@ -222,10 +225,10 @@ bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text)
222 return key == K_ENTER || toupper(key) == 'Y'; 225 return key == K_ENTER || toupper(key) == 'Y';
223} 226}
224 227
225void ui_browser__reset_index(struct ui_browser *self) 228void ui_browser__reset_index(struct ui_browser *browser)
226{ 229{
227 self->index = self->top_idx = 0; 230 browser->index = browser->top_idx = 0;
228 self->seek(self, 0, SEEK_SET); 231 browser->seek(browser, 0, SEEK_SET);
229} 232}
230 233
231void __ui_browser__show_title(struct ui_browser *browser, const char *title) 234void __ui_browser__show_title(struct ui_browser *browser, const char *title)
@@ -242,26 +245,26 @@ void ui_browser__show_title(struct ui_browser *browser, const char *title)
242 pthread_mutex_unlock(&ui__lock); 245 pthread_mutex_unlock(&ui__lock);
243} 246}
244 247
245int ui_browser__show(struct ui_browser *self, const char *title, 248int ui_browser__show(struct ui_browser *browser, const char *title,
246 const char *helpline, ...) 249 const char *helpline, ...)
247{ 250{
248 int err; 251 int err;
249 va_list ap; 252 va_list ap;
250 253
251 ui_browser__refresh_dimensions(self); 254 ui_browser__refresh_dimensions(browser);
252 255
253 pthread_mutex_lock(&ui__lock); 256 pthread_mutex_lock(&ui__lock);
254 __ui_browser__show_title(self, title); 257 __ui_browser__show_title(browser, title);
255 258
256 self->title = title; 259 browser->title = title;
257 free(self->helpline); 260 free(browser->helpline);
258 self->helpline = NULL; 261 browser->helpline = NULL;
259 262
260 va_start(ap, helpline); 263 va_start(ap, helpline);
261 err = vasprintf(&self->helpline, helpline, ap); 264 err = vasprintf(&browser->helpline, helpline, ap);
262 va_end(ap); 265 va_end(ap);
263 if (err > 0) 266 if (err > 0)
264 ui_helpline__push(self->helpline); 267 ui_helpline__push(browser->helpline);
265 pthread_mutex_unlock(&ui__lock); 268 pthread_mutex_unlock(&ui__lock);
266 return err ? 0 : -1; 269 return err ? 0 : -1;
267} 270}
@@ -347,7 +350,7 @@ void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries)
347 browser->seek(browser, browser->top_idx, SEEK_SET); 350 browser->seek(browser, browser->top_idx, SEEK_SET);
348} 351}
349 352
350int ui_browser__run(struct ui_browser *self, int delay_secs) 353int ui_browser__run(struct ui_browser *browser, int delay_secs)
351{ 354{
352 int err, key; 355 int err, key;
353 356
@@ -355,7 +358,7 @@ int ui_browser__run(struct ui_browser *self, int delay_secs)
355 off_t offset; 358 off_t offset;
356 359
357 pthread_mutex_lock(&ui__lock); 360 pthread_mutex_lock(&ui__lock);
358 err = __ui_browser__refresh(self); 361 err = __ui_browser__refresh(browser);
359 SLsmg_refresh(); 362 SLsmg_refresh();
360 pthread_mutex_unlock(&ui__lock); 363 pthread_mutex_unlock(&ui__lock);
361 if (err < 0) 364 if (err < 0)
@@ -365,18 +368,18 @@ int ui_browser__run(struct ui_browser *self, int delay_secs)
365 368
366 if (key == K_RESIZE) { 369 if (key == K_RESIZE) {
367 ui__refresh_dimensions(false); 370 ui__refresh_dimensions(false);
368 ui_browser__refresh_dimensions(self); 371 ui_browser__refresh_dimensions(browser);
369 __ui_browser__show_title(self, self->title); 372 __ui_browser__show_title(browser, browser->title);
370 ui_helpline__puts(self->helpline); 373 ui_helpline__puts(browser->helpline);
371 continue; 374 continue;
372 } 375 }
373 376
374 if (self->use_navkeypressed && !self->navkeypressed) { 377 if (browser->use_navkeypressed && !browser->navkeypressed) {
375 if (key == K_DOWN || key == K_UP || 378 if (key == K_DOWN || key == K_UP ||
376 key == K_PGDN || key == K_PGUP || 379 key == K_PGDN || key == K_PGUP ||
377 key == K_HOME || key == K_END || 380 key == K_HOME || key == K_END ||
378 key == ' ') { 381 key == ' ') {
379 self->navkeypressed = true; 382 browser->navkeypressed = true;
380 continue; 383 continue;
381 } else 384 } else
382 return key; 385 return key;
@@ -384,59 +387,59 @@ int ui_browser__run(struct ui_browser *self, int delay_secs)
384 387
385 switch (key) { 388 switch (key) {
386 case K_DOWN: 389 case K_DOWN:
387 if (self->index == self->nr_entries - 1) 390 if (browser->index == browser->nr_entries - 1)
388 break; 391 break;
389 ++self->index; 392 ++browser->index;
390 if (self->index == self->top_idx + self->height) { 393 if (browser->index == browser->top_idx + browser->height) {
391 ++self->top_idx; 394 ++browser->top_idx;
392 self->seek(self, +1, SEEK_CUR); 395 browser->seek(browser, +1, SEEK_CUR);
393 } 396 }
394 break; 397 break;
395 case K_UP: 398 case K_UP:
396 if (self->index == 0) 399 if (browser->index == 0)
397 break; 400 break;
398 --self->index; 401 --browser->index;
399 if (self->index < self->top_idx) { 402 if (browser->index < browser->top_idx) {
400 --self->top_idx; 403 --browser->top_idx;
401 self->seek(self, -1, SEEK_CUR); 404 browser->seek(browser, -1, SEEK_CUR);
402 } 405 }
403 break; 406 break;
404 case K_PGDN: 407 case K_PGDN:
405 case ' ': 408 case ' ':
406 if (self->top_idx + self->height > self->nr_entries - 1) 409 if (browser->top_idx + browser->height > browser->nr_entries - 1)
407 break; 410 break;
408 411
409 offset = self->height; 412 offset = browser->height;
410 if (self->index + offset > self->nr_entries - 1) 413 if (browser->index + offset > browser->nr_entries - 1)
411 offset = self->nr_entries - 1 - self->index; 414 offset = browser->nr_entries - 1 - browser->index;
412 self->index += offset; 415 browser->index += offset;
413 self->top_idx += offset; 416 browser->top_idx += offset;
414 self->seek(self, +offset, SEEK_CUR); 417 browser->seek(browser, +offset, SEEK_CUR);
415 break; 418 break;
416 case K_PGUP: 419 case K_PGUP:
417 if (self->top_idx == 0) 420 if (browser->top_idx == 0)
418 break; 421 break;
419 422
420 if (self->top_idx < self->height) 423 if (browser->top_idx < browser->height)
421 offset = self->top_idx; 424 offset = browser->top_idx;
422 else 425 else
423 offset = self->height; 426 offset = browser->height;
424 427
425 self->index -= offset; 428 browser->index -= offset;
426 self->top_idx -= offset; 429 browser->top_idx -= offset;
427 self->seek(self, -offset, SEEK_CUR); 430 browser->seek(browser, -offset, SEEK_CUR);
428 break; 431 break;
429 case K_HOME: 432 case K_HOME:
430 ui_browser__reset_index(self); 433 ui_browser__reset_index(browser);
431 break; 434 break;
432 case K_END: 435 case K_END:
433 offset = self->height - 1; 436 offset = browser->height - 1;
434 if (offset >= self->nr_entries) 437 if (offset >= browser->nr_entries)
435 offset = self->nr_entries - 1; 438 offset = browser->nr_entries - 1;
436 439
437 self->index = self->nr_entries - 1; 440 browser->index = browser->nr_entries - 1;
438 self->top_idx = self->index - offset; 441 browser->top_idx = browser->index - offset;
439 self->seek(self, -offset, SEEK_END); 442 browser->seek(browser, -offset, SEEK_END);
440 break; 443 break;
441 default: 444 default:
442 return key; 445 return key;
@@ -445,22 +448,22 @@ int ui_browser__run(struct ui_browser *self, int delay_secs)
445 return -1; 448 return -1;
446} 449}
447 450
448unsigned int ui_browser__list_head_refresh(struct ui_browser *self) 451unsigned int ui_browser__list_head_refresh(struct ui_browser *browser)
449{ 452{
450 struct list_head *pos; 453 struct list_head *pos;
451 struct list_head *head = self->entries; 454 struct list_head *head = browser->entries;
452 int row = 0; 455 int row = 0;
453 456
454 if (self->top == NULL || self->top == self->entries) 457 if (browser->top == NULL || browser->top == browser->entries)
455 self->top = ui_browser__list_head_filter_entries(self, head->next); 458 browser->top = ui_browser__list_head_filter_entries(browser, head->next);
456 459
457 pos = self->top; 460 pos = browser->top;
458 461
459 list_for_each_from(pos, head) { 462 list_for_each_from(pos, head) {
460 if (!self->filter || !self->filter(self, pos)) { 463 if (!browser->filter || !browser->filter(browser, pos)) {
461 ui_browser__gotorc(self, row, 0); 464 ui_browser__gotorc(browser, row, 0);
462 self->write(self, pos, row); 465 browser->write(browser, pos, row);
463 if (++row == self->height) 466 if (++row == browser->height)
464 break; 467 break;
465 } 468 }
466 } 469 }
@@ -503,6 +506,12 @@ static struct ui_browser__colorset {
503 .bg = "default", 506 .bg = "default",
504 }, 507 },
505 { 508 {
509 .colorset = HE_COLORSET_ADDR,
510 .name = "addr",
511 .fg = "magenta",
512 .bg = "default",
513 },
514 {
506 .name = NULL, 515 .name = NULL,
507 } 516 }
508}; 517};
@@ -584,6 +593,111 @@ unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
584 return row; 593 return row;
585} 594}
586 595
596void __ui_browser__vline(struct ui_browser *browser, unsigned int column,
597 u16 start, u16 end)
598{
599 SLsmg_set_char_set(1);
600 ui_browser__gotorc(browser, start, column);
601 SLsmg_draw_vline(end - start + 1);
602 SLsmg_set_char_set(0);
603}
604
605void ui_browser__write_graph(struct ui_browser *browser __used, int graph)
606{
607 SLsmg_set_char_set(1);
608 SLsmg_write_char(graph);
609 SLsmg_set_char_set(0);
610}
611
612static void __ui_browser__line_arrow_up(struct ui_browser *browser,
613 unsigned int column,
614 u64 start, u64 end)
615{
616 unsigned int row, end_row;
617
618 SLsmg_set_char_set(1);
619
620 if (start < browser->top_idx + browser->height) {
621 row = start - browser->top_idx;
622 ui_browser__gotorc(browser, row, column);
623 SLsmg_write_char(SLSMG_LLCORN_CHAR);
624 ui_browser__gotorc(browser, row, column + 1);
625 SLsmg_draw_hline(2);
626
627 if (row-- == 0)
628 goto out;
629 } else
630 row = browser->height - 1;
631
632 if (end > browser->top_idx)
633 end_row = end - browser->top_idx;
634 else
635 end_row = 0;
636
637 ui_browser__gotorc(browser, end_row, column);
638 SLsmg_draw_vline(row - end_row + 1);
639
640 ui_browser__gotorc(browser, end_row, column);
641 if (end >= browser->top_idx) {
642 SLsmg_write_char(SLSMG_ULCORN_CHAR);
643 ui_browser__gotorc(browser, end_row, column + 1);
644 SLsmg_write_char(SLSMG_HLINE_CHAR);
645 ui_browser__gotorc(browser, end_row, column + 2);
646 SLsmg_write_char(SLSMG_RARROW_CHAR);
647 }
648out:
649 SLsmg_set_char_set(0);
650}
651
652static void __ui_browser__line_arrow_down(struct ui_browser *browser,
653 unsigned int column,
654 u64 start, u64 end)
655{
656 unsigned int row, end_row;
657
658 SLsmg_set_char_set(1);
659
660 if (start >= browser->top_idx) {
661 row = start - browser->top_idx;
662 ui_browser__gotorc(browser, row, column);
663 SLsmg_write_char(SLSMG_ULCORN_CHAR);
664 ui_browser__gotorc(browser, row, column + 1);
665 SLsmg_draw_hline(2);
666
667 if (row++ == 0)
668 goto out;
669 } else
670 row = 0;
671
672 if (end >= browser->top_idx + browser->height)
673 end_row = browser->height - 1;
674 else
675 end_row = end - browser->top_idx;;
676
677 ui_browser__gotorc(browser, row, column);
678 SLsmg_draw_vline(end_row - row + 1);
679
680 ui_browser__gotorc(browser, end_row, column);
681 if (end < browser->top_idx + browser->height) {
682 SLsmg_write_char(SLSMG_LLCORN_CHAR);
683 ui_browser__gotorc(browser, end_row, column + 1);
684 SLsmg_write_char(SLSMG_HLINE_CHAR);
685 ui_browser__gotorc(browser, end_row, column + 2);
686 SLsmg_write_char(SLSMG_RARROW_CHAR);
687 }
688out:
689 SLsmg_set_char_set(0);
690}
691
692void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,
693 u64 start, u64 end)
694{
695 if (start > end)
696 __ui_browser__line_arrow_up(browser, column, start, end);
697 else
698 __ui_browser__line_arrow_down(browser, column, start, end);
699}
700
587void ui_browser__init(void) 701void ui_browser__init(void)
588{ 702{
589 int i = 0; 703 int i = 0;
@@ -594,4 +708,6 @@ void ui_browser__init(void)
594 struct ui_browser__colorset *c = &ui_browser__colorsets[i++]; 708 struct ui_browser__colorset *c = &ui_browser__colorsets[i++];
595 sltt_set_color(c->colorset, c->name, c->fg, c->bg); 709 sltt_set_color(c->colorset, c->name, c->fg, c->bg);
596 } 710 }
711
712 annotate_browser__init();
597} 713}
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/ui/browser.h
index 6ee82f60feaf..af70314605e5 100644
--- a/tools/perf/util/ui/browser.h
+++ b/tools/perf/ui/browser.h
@@ -10,11 +10,13 @@
10#define HE_COLORSET_NORMAL 52 10#define HE_COLORSET_NORMAL 52
11#define HE_COLORSET_SELECTED 53 11#define HE_COLORSET_SELECTED 53
12#define HE_COLORSET_CODE 54 12#define HE_COLORSET_CODE 54
13#define HE_COLORSET_ADDR 55
13 14
14struct ui_browser { 15struct ui_browser {
15 u64 index, top_idx; 16 u64 index, top_idx;
16 void *top, *entries; 17 void *top, *entries;
17 u16 y, x, width, height; 18 u16 y, x, width, height;
19 int current_color;
18 void *priv; 20 void *priv;
19 const char *title; 21 const char *title;
20 char *helpline; 22 char *helpline;
@@ -27,7 +29,7 @@ struct ui_browser {
27 bool use_navkeypressed; 29 bool use_navkeypressed;
28}; 30};
29 31
30void ui_browser__set_color(struct ui_browser *self, int color); 32int ui_browser__set_color(struct ui_browser *browser, int color);
31void ui_browser__set_percent_color(struct ui_browser *self, 33void ui_browser__set_percent_color(struct ui_browser *self,
32 double percent, bool current); 34 double percent, bool current);
33bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row); 35bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row);
@@ -35,6 +37,9 @@ void ui_browser__refresh_dimensions(struct ui_browser *self);
35void ui_browser__reset_index(struct ui_browser *self); 37void ui_browser__reset_index(struct ui_browser *self);
36 38
37void ui_browser__gotorc(struct ui_browser *self, int y, int x); 39void ui_browser__gotorc(struct ui_browser *self, int y, int x);
40void ui_browser__write_graph(struct ui_browser *browser, int graph);
41void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,
42 u64 start, u64 end);
38void __ui_browser__show_title(struct ui_browser *browser, const char *title); 43void __ui_browser__show_title(struct ui_browser *browser, const char *title);
39void ui_browser__show_title(struct ui_browser *browser, const char *title); 44void ui_browser__show_title(struct ui_browser *browser, const char *title);
40int ui_browser__show(struct ui_browser *self, const char *title, 45int ui_browser__show(struct ui_browser *self, const char *title,
@@ -44,6 +49,8 @@ int ui_browser__refresh(struct ui_browser *self);
44int ui_browser__run(struct ui_browser *browser, int delay_secs); 49int ui_browser__run(struct ui_browser *browser, int delay_secs);
45void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries); 50void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries);
46void ui_browser__handle_resize(struct ui_browser *browser); 51void ui_browser__handle_resize(struct ui_browser *browser);
52void __ui_browser__vline(struct ui_browser *browser, unsigned int column,
53 u16 start, u16 end);
47 54
48int ui_browser__warning(struct ui_browser *browser, int timeout, 55int ui_browser__warning(struct ui_browser *browser, int timeout,
49 const char *format, ...); 56 const char *format, ...);
@@ -62,4 +69,5 @@ void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whenc
62unsigned int ui_browser__list_head_refresh(struct ui_browser *self); 69unsigned int ui_browser__list_head_refresh(struct ui_browser *self);
63 70
64void ui_browser__init(void); 71void ui_browser__init(void);
72void annotate_browser__init(void);
65#endif /* _PERF_UI_BROWSER_H_ */ 73#endif /* _PERF_UI_BROWSER_H_ */
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
new file mode 100644
index 000000000000..4deea6aaf927
--- /dev/null
+++ b/tools/perf/ui/browsers/annotate.c
@@ -0,0 +1,951 @@
1#include "../../util/util.h"
2#include "../browser.h"
3#include "../helpline.h"
4#include "../libslang.h"
5#include "../ui.h"
6#include "../util.h"
7#include "../../util/annotate.h"
8#include "../../util/hist.h"
9#include "../../util/sort.h"
10#include "../../util/symbol.h"
11#include <pthread.h>
12#include <newt.h>
13
14struct browser_disasm_line {
15 struct rb_node rb_node;
16 double percent;
17 u32 idx;
18 int idx_asm;
19 int jump_sources;
20};
21
22static struct annotate_browser_opt {
23 bool hide_src_code,
24 use_offset,
25 jump_arrows,
26 show_nr_jumps;
27} annotate_browser__opts = {
28 .use_offset = true,
29 .jump_arrows = true,
30};
31
32struct annotate_browser {
33 struct ui_browser b;
34 struct rb_root entries;
35 struct rb_node *curr_hot;
36 struct disasm_line *selection;
37 struct disasm_line **offsets;
38 u64 start;
39 int nr_asm_entries;
40 int nr_entries;
41 int max_jump_sources;
42 int nr_jumps;
43 bool searching_backwards;
44 u8 addr_width;
45 u8 jumps_width;
46 u8 target_width;
47 u8 min_addr_width;
48 u8 max_addr_width;
49 char search_bf[128];
50};
51
52static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
53{
54 return (struct browser_disasm_line *)(dl + 1);
55}
56
57static bool disasm_line__filter(struct ui_browser *browser __used, void *entry)
58{
59 if (annotate_browser__opts.hide_src_code) {
60 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
61 return dl->offset == -1;
62 }
63
64 return false;
65}
66
67static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
68 int nr, bool current)
69{
70 if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
71 return HE_COLORSET_SELECTED;
72 if (nr == browser->max_jump_sources)
73 return HE_COLORSET_TOP;
74 if (nr > 1)
75 return HE_COLORSET_MEDIUM;
76 return HE_COLORSET_NORMAL;
77}
78
79static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
80 int nr, bool current)
81{
82 int color = annotate_browser__jumps_percent_color(browser, nr, current);
83 return ui_browser__set_color(&browser->b, color);
84}
85
86static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
87{
88 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
89 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
90 struct browser_disasm_line *bdl = disasm_line__browser(dl);
91 bool current_entry = ui_browser__is_current_entry(browser, row);
92 bool change_color = (!annotate_browser__opts.hide_src_code &&
93 (!current_entry || (browser->use_navkeypressed &&
94 !browser->navkeypressed)));
95 int width = browser->width, printed;
96 char bf[256];
97
98 if (dl->offset != -1 && bdl->percent != 0.0) {
99 ui_browser__set_percent_color(browser, bdl->percent, current_entry);
100 slsmg_printf("%6.2f ", bdl->percent);
101 } else {
102 ui_browser__set_percent_color(browser, 0, current_entry);
103 slsmg_write_nstring(" ", 7);
104 }
105
106 SLsmg_write_char(' ');
107
108 /* The scroll bar isn't being used */
109 if (!browser->navkeypressed)
110 width += 1;
111
112 if (!*dl->line)
113 slsmg_write_nstring(" ", width - 7);
114 else if (dl->offset == -1) {
115 printed = scnprintf(bf, sizeof(bf), "%*s ",
116 ab->addr_width, " ");
117 slsmg_write_nstring(bf, printed);
118 slsmg_write_nstring(dl->line, width - printed - 6);
119 } else {
120 u64 addr = dl->offset;
121 int color = -1;
122
123 if (!annotate_browser__opts.use_offset)
124 addr += ab->start;
125
126 if (!annotate_browser__opts.use_offset) {
127 printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
128 } else {
129 if (bdl->jump_sources) {
130 if (annotate_browser__opts.show_nr_jumps) {
131 int prev;
132 printed = scnprintf(bf, sizeof(bf), "%*d ",
133 ab->jumps_width,
134 bdl->jump_sources);
135 prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
136 current_entry);
137 slsmg_write_nstring(bf, printed);
138 ui_browser__set_color(browser, prev);
139 }
140
141 printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
142 ab->target_width, addr);
143 } else {
144 printed = scnprintf(bf, sizeof(bf), "%*s ",
145 ab->addr_width, " ");
146 }
147 }
148
149 if (change_color)
150 color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
151 slsmg_write_nstring(bf, printed);
152 if (change_color)
153 ui_browser__set_color(browser, color);
154 if (dl->ins && dl->ins->ops->scnprintf) {
155 if (ins__is_jump(dl->ins)) {
156 bool fwd = dl->ops.target.offset > (u64)dl->offset;
157
158 ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
159 SLSMG_UARROW_CHAR);
160 SLsmg_write_char(' ');
161 } else if (ins__is_call(dl->ins)) {
162 ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
163 SLsmg_write_char(' ');
164 } else {
165 slsmg_write_nstring(" ", 2);
166 }
167 } else {
168 if (strcmp(dl->name, "retq")) {
169 slsmg_write_nstring(" ", 2);
170 } else {
171 ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
172 SLsmg_write_char(' ');
173 }
174 }
175
176 disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
177 slsmg_write_nstring(bf, width - 10 - printed);
178 }
179
180 if (current_entry)
181 ab->selection = dl;
182}
183
184static void annotate_browser__draw_current_jump(struct ui_browser *browser)
185{
186 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
187 struct disasm_line *cursor = ab->selection, *target;
188 struct browser_disasm_line *btarget, *bcursor;
189 unsigned int from, to;
190
191 if (!cursor || !cursor->ins || !ins__is_jump(cursor->ins) ||
192 !disasm_line__has_offset(cursor))
193 return;
194
195 target = ab->offsets[cursor->ops.target.offset];
196 if (!target)
197 return;
198
199 bcursor = disasm_line__browser(cursor);
200 btarget = disasm_line__browser(target);
201
202 if (annotate_browser__opts.hide_src_code) {
203 from = bcursor->idx_asm;
204 to = btarget->idx_asm;
205 } else {
206 from = (u64)bcursor->idx;
207 to = (u64)btarget->idx;
208 }
209
210 ui_browser__set_color(browser, HE_COLORSET_CODE);
211 __ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to);
212}
213
214static unsigned int annotate_browser__refresh(struct ui_browser *browser)
215{
216 int ret = ui_browser__list_head_refresh(browser);
217
218 if (annotate_browser__opts.jump_arrows)
219 annotate_browser__draw_current_jump(browser);
220
221 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
222 __ui_browser__vline(browser, 7, 0, browser->height - 1);
223 return ret;
224}
225
226static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx)
227{
228 double percent = 0.0;
229
230 if (dl->offset != -1) {
231 int len = sym->end - sym->start;
232 unsigned int hits = 0;
233 struct annotation *notes = symbol__annotation(sym);
234 struct source_line *src_line = notes->src->lines;
235 struct sym_hist *h = annotation__histogram(notes, evidx);
236 s64 offset = dl->offset;
237 struct disasm_line *next;
238
239 next = disasm__get_next_ip_line(&notes->src->source, dl);
240 while (offset < (s64)len &&
241 (next == NULL || offset < next->offset)) {
242 if (src_line) {
243 percent += src_line[offset].percent;
244 } else
245 hits += h->addr[offset];
246
247 ++offset;
248 }
249 /*
250 * If the percentage wasn't already calculated in
251 * symbol__get_source_line, do it now:
252 */
253 if (src_line == NULL && h->sum)
254 percent = 100.0 * hits / h->sum;
255 }
256
257 return percent;
258}
259
260static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl)
261{
262 struct rb_node **p = &root->rb_node;
263 struct rb_node *parent = NULL;
264 struct browser_disasm_line *l;
265
266 while (*p != NULL) {
267 parent = *p;
268 l = rb_entry(parent, struct browser_disasm_line, rb_node);
269 if (bdl->percent < l->percent)
270 p = &(*p)->rb_left;
271 else
272 p = &(*p)->rb_right;
273 }
274 rb_link_node(&bdl->rb_node, parent, p);
275 rb_insert_color(&bdl->rb_node, root);
276}
277
278static void annotate_browser__set_top(struct annotate_browser *browser,
279 struct disasm_line *pos, u32 idx)
280{
281 unsigned back;
282
283 ui_browser__refresh_dimensions(&browser->b);
284 back = browser->b.height / 2;
285 browser->b.top_idx = browser->b.index = idx;
286
287 while (browser->b.top_idx != 0 && back != 0) {
288 pos = list_entry(pos->node.prev, struct disasm_line, node);
289
290 if (disasm_line__filter(&browser->b, &pos->node))
291 continue;
292
293 --browser->b.top_idx;
294 --back;
295 }
296
297 browser->b.top = pos;
298 browser->b.navkeypressed = true;
299}
300
301static void annotate_browser__set_rb_top(struct annotate_browser *browser,
302 struct rb_node *nd)
303{
304 struct browser_disasm_line *bpos;
305 struct disasm_line *pos;
306 u32 idx;
307
308 bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
309 pos = ((struct disasm_line *)bpos) - 1;
310 idx = bpos->idx;
311 if (annotate_browser__opts.hide_src_code)
312 idx = bpos->idx_asm;
313 annotate_browser__set_top(browser, pos, idx);
314 browser->curr_hot = nd;
315}
316
317static void annotate_browser__calc_percent(struct annotate_browser *browser,
318 int evidx)
319{
320 struct map_symbol *ms = browser->b.priv;
321 struct symbol *sym = ms->sym;
322 struct annotation *notes = symbol__annotation(sym);
323 struct disasm_line *pos;
324
325 browser->entries = RB_ROOT;
326
327 pthread_mutex_lock(&notes->lock);
328
329 list_for_each_entry(pos, &notes->src->source, node) {
330 struct browser_disasm_line *bpos = disasm_line__browser(pos);
331 bpos->percent = disasm_line__calc_percent(pos, sym, evidx);
332 if (bpos->percent < 0.01) {
333 RB_CLEAR_NODE(&bpos->rb_node);
334 continue;
335 }
336 disasm_rb_tree__insert(&browser->entries, bpos);
337 }
338 pthread_mutex_unlock(&notes->lock);
339
340 browser->curr_hot = rb_last(&browser->entries);
341}
342
343static bool annotate_browser__toggle_source(struct annotate_browser *browser)
344{
345 struct disasm_line *dl;
346 struct browser_disasm_line *bdl;
347 off_t offset = browser->b.index - browser->b.top_idx;
348
349 browser->b.seek(&browser->b, offset, SEEK_CUR);
350 dl = list_entry(browser->b.top, struct disasm_line, node);
351 bdl = disasm_line__browser(dl);
352
353 if (annotate_browser__opts.hide_src_code) {
354 if (bdl->idx_asm < offset)
355 offset = bdl->idx;
356
357 browser->b.nr_entries = browser->nr_entries;
358 annotate_browser__opts.hide_src_code = false;
359 browser->b.seek(&browser->b, -offset, SEEK_CUR);
360 browser->b.top_idx = bdl->idx - offset;
361 browser->b.index = bdl->idx;
362 } else {
363 if (bdl->idx_asm < 0) {
364 ui_helpline__puts("Only available for assembly lines.");
365 browser->b.seek(&browser->b, -offset, SEEK_CUR);
366 return false;
367 }
368
369 if (bdl->idx_asm < offset)
370 offset = bdl->idx_asm;
371
372 browser->b.nr_entries = browser->nr_asm_entries;
373 annotate_browser__opts.hide_src_code = true;
374 browser->b.seek(&browser->b, -offset, SEEK_CUR);
375 browser->b.top_idx = bdl->idx_asm - offset;
376 browser->b.index = bdl->idx_asm;
377 }
378
379 return true;
380}
381
382static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
383{
384 ui_browser__reset_index(&browser->b);
385 browser->b.nr_entries = browser->nr_asm_entries;
386}
387
388static bool annotate_browser__callq(struct annotate_browser *browser,
389 int evidx, void (*timer)(void *arg),
390 void *arg, int delay_secs)
391{
392 struct map_symbol *ms = browser->b.priv;
393 struct disasm_line *dl = browser->selection;
394 struct symbol *sym = ms->sym;
395 struct annotation *notes;
396 struct symbol *target;
397 u64 ip;
398
399 if (!ins__is_call(dl->ins))
400 return false;
401
402 ip = ms->map->map_ip(ms->map, dl->ops.target.addr);
403 target = map__find_symbol(ms->map, ip, NULL);
404 if (target == NULL) {
405 ui_helpline__puts("The called function was not found.");
406 return true;
407 }
408
409 notes = symbol__annotation(target);
410 pthread_mutex_lock(&notes->lock);
411
412 if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
413 pthread_mutex_unlock(&notes->lock);
414 ui__warning("Not enough memory for annotating '%s' symbol!\n",
415 target->name);
416 return true;
417 }
418
419 pthread_mutex_unlock(&notes->lock);
420 symbol__tui_annotate(target, ms->map, evidx, timer, arg, delay_secs);
421 ui_browser__show_title(&browser->b, sym->name);
422 return true;
423}
424
425static
426struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
427 s64 offset, s64 *idx)
428{
429 struct map_symbol *ms = browser->b.priv;
430 struct symbol *sym = ms->sym;
431 struct annotation *notes = symbol__annotation(sym);
432 struct disasm_line *pos;
433
434 *idx = 0;
435 list_for_each_entry(pos, &notes->src->source, node) {
436 if (pos->offset == offset)
437 return pos;
438 if (!disasm_line__filter(&browser->b, &pos->node))
439 ++*idx;
440 }
441
442 return NULL;
443}
444
445static bool annotate_browser__jump(struct annotate_browser *browser)
446{
447 struct disasm_line *dl = browser->selection;
448 s64 idx;
449
450 if (!ins__is_jump(dl->ins))
451 return false;
452
453 dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
454 if (dl == NULL) {
455 ui_helpline__puts("Invallid jump offset");
456 return true;
457 }
458
459 annotate_browser__set_top(browser, dl, idx);
460
461 return true;
462}
463
464static
465struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
466 char *s, s64 *idx)
467{
468 struct map_symbol *ms = browser->b.priv;
469 struct symbol *sym = ms->sym;
470 struct annotation *notes = symbol__annotation(sym);
471 struct disasm_line *pos = browser->selection;
472
473 *idx = browser->b.index;
474 list_for_each_entry_continue(pos, &notes->src->source, node) {
475 if (disasm_line__filter(&browser->b, &pos->node))
476 continue;
477
478 ++*idx;
479
480 if (pos->line && strstr(pos->line, s) != NULL)
481 return pos;
482 }
483
484 return NULL;
485}
486
487static bool __annotate_browser__search(struct annotate_browser *browser)
488{
489 struct disasm_line *dl;
490 s64 idx;
491
492 dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
493 if (dl == NULL) {
494 ui_helpline__puts("String not found!");
495 return false;
496 }
497
498 annotate_browser__set_top(browser, dl, idx);
499 browser->searching_backwards = false;
500 return true;
501}
502
503static
504struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
505 char *s, s64 *idx)
506{
507 struct map_symbol *ms = browser->b.priv;
508 struct symbol *sym = ms->sym;
509 struct annotation *notes = symbol__annotation(sym);
510 struct disasm_line *pos = browser->selection;
511
512 *idx = browser->b.index;
513 list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
514 if (disasm_line__filter(&browser->b, &pos->node))
515 continue;
516
517 --*idx;
518
519 if (pos->line && strstr(pos->line, s) != NULL)
520 return pos;
521 }
522
523 return NULL;
524}
525
526static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
527{
528 struct disasm_line *dl;
529 s64 idx;
530
531 dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
532 if (dl == NULL) {
533 ui_helpline__puts("String not found!");
534 return false;
535 }
536
537 annotate_browser__set_top(browser, dl, idx);
538 browser->searching_backwards = true;
539 return true;
540}
541
542static bool annotate_browser__search_window(struct annotate_browser *browser,
543 int delay_secs)
544{
545 if (ui_browser__input_window("Search", "String: ", browser->search_bf,
546 "ENTER: OK, ESC: Cancel",
547 delay_secs * 2) != K_ENTER ||
548 !*browser->search_bf)
549 return false;
550
551 return true;
552}
553
554static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
555{
556 if (annotate_browser__search_window(browser, delay_secs))
557 return __annotate_browser__search(browser);
558
559 return false;
560}
561
562static bool annotate_browser__continue_search(struct annotate_browser *browser,
563 int delay_secs)
564{
565 if (!*browser->search_bf)
566 return annotate_browser__search(browser, delay_secs);
567
568 return __annotate_browser__search(browser);
569}
570
571static bool annotate_browser__search_reverse(struct annotate_browser *browser,
572 int delay_secs)
573{
574 if (annotate_browser__search_window(browser, delay_secs))
575 return __annotate_browser__search_reverse(browser);
576
577 return false;
578}
579
580static
581bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
582 int delay_secs)
583{
584 if (!*browser->search_bf)
585 return annotate_browser__search_reverse(browser, delay_secs);
586
587 return __annotate_browser__search_reverse(browser);
588}
589
590static void annotate_browser__update_addr_width(struct annotate_browser *browser)
591{
592 if (annotate_browser__opts.use_offset)
593 browser->target_width = browser->min_addr_width;
594 else
595 browser->target_width = browser->max_addr_width;
596
597 browser->addr_width = browser->target_width;
598
599 if (annotate_browser__opts.show_nr_jumps)
600 browser->addr_width += browser->jumps_width + 1;
601}
602
603static int annotate_browser__run(struct annotate_browser *browser, int evidx,
604 void(*timer)(void *arg),
605 void *arg, int delay_secs)
606{
607 struct rb_node *nd = NULL;
608 struct map_symbol *ms = browser->b.priv;
609 struct symbol *sym = ms->sym;
610 const char *help = "Press 'h' for help on key bindings";
611 int key;
612
613 if (ui_browser__show(&browser->b, sym->name, help) < 0)
614 return -1;
615
616 annotate_browser__calc_percent(browser, evidx);
617
618 if (browser->curr_hot) {
619 annotate_browser__set_rb_top(browser, browser->curr_hot);
620 browser->b.navkeypressed = false;
621 }
622
623 nd = browser->curr_hot;
624
625 while (1) {
626 key = ui_browser__run(&browser->b, delay_secs);
627
628 if (delay_secs != 0) {
629 annotate_browser__calc_percent(browser, evidx);
630 /*
631 * Current line focus got out of the list of most active
632 * lines, NULL it so that if TAB|UNTAB is pressed, we
633 * move to curr_hot (current hottest line).
634 */
635 if (nd != NULL && RB_EMPTY_NODE(nd))
636 nd = NULL;
637 }
638
639 switch (key) {
640 case K_TIMER:
641 if (timer != NULL)
642 timer(arg);
643
644 if (delay_secs != 0)
645 symbol__annotate_decay_histogram(sym, evidx);
646 continue;
647 case K_TAB:
648 if (nd != NULL) {
649 nd = rb_prev(nd);
650 if (nd == NULL)
651 nd = rb_last(&browser->entries);
652 } else
653 nd = browser->curr_hot;
654 break;
655 case K_UNTAB:
656 if (nd != NULL)
657 nd = rb_next(nd);
658 if (nd == NULL)
659 nd = rb_first(&browser->entries);
660 else
661 nd = browser->curr_hot;
662 break;
663 case K_F1:
664 case 'h':
665 ui_browser__help_window(&browser->b,
666 "UP/DOWN/PGUP\n"
667 "PGDN/SPACE Navigate\n"
668 "q/ESC/CTRL+C Exit\n\n"
669 "-> Go to target\n"
670 "<- Exit\n"
671 "h Cycle thru hottest instructions\n"
672 "j Toggle showing jump to target arrows\n"
673 "J Toggle showing number of jump sources on targets\n"
674 "n Search next string\n"
675 "o Toggle disassembler output/simplified view\n"
676 "s Toggle source code view\n"
677 "/ Search string\n"
678 "? Search previous string\n");
679 continue;
680 case 'H':
681 nd = browser->curr_hot;
682 break;
683 case 's':
684 if (annotate_browser__toggle_source(browser))
685 ui_helpline__puts(help);
686 continue;
687 case 'o':
688 annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
689 annotate_browser__update_addr_width(browser);
690 continue;
691 case 'j':
692 annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
693 continue;
694 case 'J':
695 annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
696 annotate_browser__update_addr_width(browser);
697 continue;
698 case '/':
699 if (annotate_browser__search(browser, delay_secs)) {
700show_help:
701 ui_helpline__puts(help);
702 }
703 continue;
704 case 'n':
705 if (browser->searching_backwards ?
706 annotate_browser__continue_search_reverse(browser, delay_secs) :
707 annotate_browser__continue_search(browser, delay_secs))
708 goto show_help;
709 continue;
710 case '?':
711 if (annotate_browser__search_reverse(browser, delay_secs))
712 goto show_help;
713 continue;
714 case 'D': {
715 static int seq;
716 ui_helpline__pop();
717 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
718 seq++, browser->b.nr_entries,
719 browser->b.height,
720 browser->b.index,
721 browser->b.top_idx,
722 browser->nr_asm_entries);
723 }
724 continue;
725 case K_ENTER:
726 case K_RIGHT:
727 if (browser->selection == NULL)
728 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
729 else if (browser->selection->offset == -1)
730 ui_helpline__puts("Actions are only available for assembly lines.");
731 else if (!browser->selection->ins) {
732 if (strcmp(browser->selection->name, "retq"))
733 goto show_sup_ins;
734 goto out;
735 } else if (!(annotate_browser__jump(browser) ||
736 annotate_browser__callq(browser, evidx, timer, arg, delay_secs))) {
737show_sup_ins:
738 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
739 }
740 continue;
741 case K_LEFT:
742 case K_ESC:
743 case 'q':
744 case CTRL('c'):
745 goto out;
746 default:
747 continue;
748 }
749
750 if (nd != NULL)
751 annotate_browser__set_rb_top(browser, nd);
752 }
753out:
754 ui_browser__hide(&browser->b);
755 return key;
756}
757
758int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
759 void(*timer)(void *arg), void *arg, int delay_secs)
760{
761 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
762 timer, arg, delay_secs);
763}
764
765static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
766 size_t size)
767{
768 u64 offset;
769
770 for (offset = 0; offset < size; ++offset) {
771 struct disasm_line *dl = browser->offsets[offset], *dlt;
772 struct browser_disasm_line *bdlt;
773
774 if (!dl || !dl->ins || !ins__is_jump(dl->ins) ||
775 !disasm_line__has_offset(dl))
776 continue;
777
778 if (dl->ops.target.offset >= size) {
779 ui__error("jump to after symbol!\n"
780 "size: %zx, jump target: %" PRIx64,
781 size, dl->ops.target.offset);
782 continue;
783 }
784
785 dlt = browser->offsets[dl->ops.target.offset];
786 /*
787 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
788 * have to adjust to the previous offset?
789 */
790 if (dlt == NULL)
791 continue;
792
793 bdlt = disasm_line__browser(dlt);
794 if (++bdlt->jump_sources > browser->max_jump_sources)
795 browser->max_jump_sources = bdlt->jump_sources;
796
797 ++browser->nr_jumps;
798 }
799
800}
801
802static inline int width_jumps(int n)
803{
804 if (n >= 100)
805 return 5;
806 if (n / 10)
807 return 2;
808 return 1;
809}
810
811int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
812 void(*timer)(void *arg), void *arg,
813 int delay_secs)
814{
815 struct disasm_line *pos, *n;
816 struct annotation *notes;
817 const size_t size = symbol__size(sym);
818 struct map_symbol ms = {
819 .map = map,
820 .sym = sym,
821 };
822 struct annotate_browser browser = {
823 .b = {
824 .refresh = annotate_browser__refresh,
825 .seek = ui_browser__list_head_seek,
826 .write = annotate_browser__write,
827 .filter = disasm_line__filter,
828 .priv = &ms,
829 .use_navkeypressed = true,
830 },
831 };
832 int ret = -1;
833
834 if (sym == NULL)
835 return -1;
836
837 if (map->dso->annotate_warned)
838 return -1;
839
840 browser.offsets = zalloc(size * sizeof(struct disasm_line *));
841 if (browser.offsets == NULL) {
842 ui__error("Not enough memory!");
843 return -1;
844 }
845
846 if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) {
847 ui__error("%s", ui_helpline__last_msg);
848 goto out_free_offsets;
849 }
850
851 ui_helpline__push("Press <- or ESC to exit");
852
853 notes = symbol__annotation(sym);
854 browser.start = map__rip_2objdump(map, sym->start);
855
856 list_for_each_entry(pos, &notes->src->source, node) {
857 struct browser_disasm_line *bpos;
858 size_t line_len = strlen(pos->line);
859
860 if (browser.b.width < line_len)
861 browser.b.width = line_len;
862 bpos = disasm_line__browser(pos);
863 bpos->idx = browser.nr_entries++;
864 if (pos->offset != -1) {
865 bpos->idx_asm = browser.nr_asm_entries++;
866 /*
867 * FIXME: short term bandaid to cope with assembly
868 * routines that comes with labels in the same column
869 * as the address in objdump, sigh.
870 *
871 * E.g. copy_user_generic_unrolled
872 */
873 if (pos->offset < (s64)size)
874 browser.offsets[pos->offset] = pos;
875 } else
876 bpos->idx_asm = -1;
877 }
878
879 annotate_browser__mark_jump_targets(&browser, size);
880
881 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
882 browser.max_addr_width = hex_width(sym->end);
883 browser.jumps_width = width_jumps(browser.max_jump_sources);
884 browser.b.nr_entries = browser.nr_entries;
885 browser.b.entries = &notes->src->source,
886 browser.b.width += 18; /* Percentage */
887
888 if (annotate_browser__opts.hide_src_code)
889 annotate_browser__init_asm_mode(&browser);
890
891 annotate_browser__update_addr_width(&browser);
892
893 ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
894 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
895 list_del(&pos->node);
896 disasm_line__free(pos);
897 }
898
899out_free_offsets:
900 free(browser.offsets);
901 return ret;
902}
903
904#define ANNOTATE_CFG(n) \
905 { .name = #n, .value = &annotate_browser__opts.n, }
906
907/*
908 * Keep the entries sorted, they are bsearch'ed
909 */
910static struct annotate__config {
911 const char *name;
912 bool *value;
913} annotate__configs[] = {
914 ANNOTATE_CFG(hide_src_code),
915 ANNOTATE_CFG(jump_arrows),
916 ANNOTATE_CFG(show_nr_jumps),
917 ANNOTATE_CFG(use_offset),
918};
919
920#undef ANNOTATE_CFG
921
922static int annotate_config__cmp(const void *name, const void *cfgp)
923{
924 const struct annotate__config *cfg = cfgp;
925
926 return strcmp(name, cfg->name);
927}
928
929static int annotate__config(const char *var, const char *value, void *data __used)
930{
931 struct annotate__config *cfg;
932 const char *name;
933
934 if (prefixcmp(var, "annotate.") != 0)
935 return 0;
936
937 name = var + 9;
938 cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
939 sizeof(struct annotate__config), annotate_config__cmp);
940
941 if (cfg == NULL)
942 return -1;
943
944 *cfg->value = perf_config_bool(name, value);
945 return 0;
946}
947
948void annotate_browser__init(void)
949{
950 perf_config(annotate__config, NULL);
951}
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 2f83e5dc9967..53f6697d014e 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -5,12 +5,12 @@
5#include <newt.h> 5#include <newt.h>
6#include <linux/rbtree.h> 6#include <linux/rbtree.h>
7 7
8#include "../../evsel.h" 8#include "../../util/evsel.h"
9#include "../../evlist.h" 9#include "../../util/evlist.h"
10#include "../../hist.h" 10#include "../../util/hist.h"
11#include "../../pstack.h" 11#include "../../util/pstack.h"
12#include "../../sort.h" 12#include "../../util/sort.h"
13#include "../../util.h" 13#include "../../util/util.h"
14 14
15#include "../browser.h" 15#include "../browser.h"
16#include "../helpline.h" 16#include "../helpline.h"
@@ -26,21 +26,21 @@ struct hist_browser {
26 bool has_symbols; 26 bool has_symbols;
27}; 27};
28 28
29static int hists__browser_title(struct hists *self, char *bf, size_t size, 29static int hists__browser_title(struct hists *hists, char *bf, size_t size,
30 const char *ev_name); 30 const char *ev_name);
31 31
32static void hist_browser__refresh_dimensions(struct hist_browser *self) 32static void hist_browser__refresh_dimensions(struct hist_browser *browser)
33{ 33{
34 /* 3 == +/- toggle symbol before actual hist_entry rendering */ 34 /* 3 == +/- toggle symbol before actual hist_entry rendering */
35 self->b.width = 3 + (hists__sort_list_width(self->hists) + 35 browser->b.width = 3 + (hists__sort_list_width(browser->hists) +
36 sizeof("[k]")); 36 sizeof("[k]"));
37} 37}
38 38
39static void hist_browser__reset(struct hist_browser *self) 39static void hist_browser__reset(struct hist_browser *browser)
40{ 40{
41 self->b.nr_entries = self->hists->nr_entries; 41 browser->b.nr_entries = browser->hists->nr_entries;
42 hist_browser__refresh_dimensions(self); 42 hist_browser__refresh_dimensions(browser);
43 ui_browser__reset_index(&self->b); 43 ui_browser__reset_index(&browser->b);
44} 44}
45 45
46static char tree__folded_sign(bool unfolded) 46static char tree__folded_sign(bool unfolded)
@@ -48,32 +48,32 @@ static char tree__folded_sign(bool unfolded)
48 return unfolded ? '-' : '+'; 48 return unfolded ? '-' : '+';
49} 49}
50 50
51static char map_symbol__folded(const struct map_symbol *self) 51static char map_symbol__folded(const struct map_symbol *ms)
52{ 52{
53 return self->has_children ? tree__folded_sign(self->unfolded) : ' '; 53 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
54} 54}
55 55
56static char hist_entry__folded(const struct hist_entry *self) 56static char hist_entry__folded(const struct hist_entry *he)
57{ 57{
58 return map_symbol__folded(&self->ms); 58 return map_symbol__folded(&he->ms);
59} 59}
60 60
61static char callchain_list__folded(const struct callchain_list *self) 61static char callchain_list__folded(const struct callchain_list *cl)
62{ 62{
63 return map_symbol__folded(&self->ms); 63 return map_symbol__folded(&cl->ms);
64} 64}
65 65
66static void map_symbol__set_folding(struct map_symbol *self, bool unfold) 66static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
67{ 67{
68 self->unfolded = unfold ? self->has_children : false; 68 ms->unfolded = unfold ? ms->has_children : false;
69} 69}
70 70
71static int callchain_node__count_rows_rb_tree(struct callchain_node *self) 71static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
72{ 72{
73 int n = 0; 73 int n = 0;
74 struct rb_node *nd; 74 struct rb_node *nd;
75 75
76 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) { 76 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
77 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 77 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
78 struct callchain_list *chain; 78 struct callchain_list *chain;
79 char folded_sign = ' '; /* No children */ 79 char folded_sign = ' '; /* No children */
@@ -123,23 +123,23 @@ static int callchain__count_rows(struct rb_root *chain)
123 return n; 123 return n;
124} 124}
125 125
126static bool map_symbol__toggle_fold(struct map_symbol *self) 126static bool map_symbol__toggle_fold(struct map_symbol *ms)
127{ 127{
128 if (!self) 128 if (!ms)
129 return false; 129 return false;
130 130
131 if (!self->has_children) 131 if (!ms->has_children)
132 return false; 132 return false;
133 133
134 self->unfolded = !self->unfolded; 134 ms->unfolded = !ms->unfolded;
135 return true; 135 return true;
136} 136}
137 137
138static void callchain_node__init_have_children_rb_tree(struct callchain_node *self) 138static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
139{ 139{
140 struct rb_node *nd = rb_first(&self->rb_root); 140 struct rb_node *nd = rb_first(&node->rb_root);
141 141
142 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) { 142 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
143 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 143 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
144 struct callchain_list *chain; 144 struct callchain_list *chain;
145 bool first = true; 145 bool first = true;
@@ -158,49 +158,49 @@ static void callchain_node__init_have_children_rb_tree(struct callchain_node *se
158 } 158 }
159} 159}
160 160
161static void callchain_node__init_have_children(struct callchain_node *self) 161static void callchain_node__init_have_children(struct callchain_node *node)
162{ 162{
163 struct callchain_list *chain; 163 struct callchain_list *chain;
164 164
165 list_for_each_entry(chain, &self->val, list) 165 list_for_each_entry(chain, &node->val, list)
166 chain->ms.has_children = !RB_EMPTY_ROOT(&self->rb_root); 166 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
167 167
168 callchain_node__init_have_children_rb_tree(self); 168 callchain_node__init_have_children_rb_tree(node);
169} 169}
170 170
171static void callchain__init_have_children(struct rb_root *self) 171static void callchain__init_have_children(struct rb_root *root)
172{ 172{
173 struct rb_node *nd; 173 struct rb_node *nd;
174 174
175 for (nd = rb_first(self); nd; nd = rb_next(nd)) { 175 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
176 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 176 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
177 callchain_node__init_have_children(node); 177 callchain_node__init_have_children(node);
178 } 178 }
179} 179}
180 180
181static void hist_entry__init_have_children(struct hist_entry *self) 181static void hist_entry__init_have_children(struct hist_entry *he)
182{ 182{
183 if (!self->init_have_children) { 183 if (!he->init_have_children) {
184 self->ms.has_children = !RB_EMPTY_ROOT(&self->sorted_chain); 184 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
185 callchain__init_have_children(&self->sorted_chain); 185 callchain__init_have_children(&he->sorted_chain);
186 self->init_have_children = true; 186 he->init_have_children = true;
187 } 187 }
188} 188}
189 189
190static bool hist_browser__toggle_fold(struct hist_browser *self) 190static bool hist_browser__toggle_fold(struct hist_browser *browser)
191{ 191{
192 if (map_symbol__toggle_fold(self->selection)) { 192 if (map_symbol__toggle_fold(browser->selection)) {
193 struct hist_entry *he = self->he_selection; 193 struct hist_entry *he = browser->he_selection;
194 194
195 hist_entry__init_have_children(he); 195 hist_entry__init_have_children(he);
196 self->hists->nr_entries -= he->nr_rows; 196 browser->hists->nr_entries -= he->nr_rows;
197 197
198 if (he->ms.unfolded) 198 if (he->ms.unfolded)
199 he->nr_rows = callchain__count_rows(&he->sorted_chain); 199 he->nr_rows = callchain__count_rows(&he->sorted_chain);
200 else 200 else
201 he->nr_rows = 0; 201 he->nr_rows = 0;
202 self->hists->nr_entries += he->nr_rows; 202 browser->hists->nr_entries += he->nr_rows;
203 self->b.nr_entries = self->hists->nr_entries; 203 browser->b.nr_entries = browser->hists->nr_entries;
204 204
205 return true; 205 return true;
206 } 206 }
@@ -209,12 +209,12 @@ static bool hist_browser__toggle_fold(struct hist_browser *self)
209 return false; 209 return false;
210} 210}
211 211
212static int callchain_node__set_folding_rb_tree(struct callchain_node *self, bool unfold) 212static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
213{ 213{
214 int n = 0; 214 int n = 0;
215 struct rb_node *nd; 215 struct rb_node *nd;
216 216
217 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) { 217 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
218 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 218 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
219 struct callchain_list *chain; 219 struct callchain_list *chain;
220 bool has_children = false; 220 bool has_children = false;
@@ -263,37 +263,37 @@ static int callchain__set_folding(struct rb_root *chain, bool unfold)
263 return n; 263 return n;
264} 264}
265 265
266static void hist_entry__set_folding(struct hist_entry *self, bool unfold) 266static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
267{ 267{
268 hist_entry__init_have_children(self); 268 hist_entry__init_have_children(he);
269 map_symbol__set_folding(&self->ms, unfold); 269 map_symbol__set_folding(&he->ms, unfold);
270 270
271 if (self->ms.has_children) { 271 if (he->ms.has_children) {
272 int n = callchain__set_folding(&self->sorted_chain, unfold); 272 int n = callchain__set_folding(&he->sorted_chain, unfold);
273 self->nr_rows = unfold ? n : 0; 273 he->nr_rows = unfold ? n : 0;
274 } else 274 } else
275 self->nr_rows = 0; 275 he->nr_rows = 0;
276} 276}
277 277
278static void hists__set_folding(struct hists *self, bool unfold) 278static void hists__set_folding(struct hists *hists, bool unfold)
279{ 279{
280 struct rb_node *nd; 280 struct rb_node *nd;
281 281
282 self->nr_entries = 0; 282 hists->nr_entries = 0;
283 283
284 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 284 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
285 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 285 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
286 hist_entry__set_folding(he, unfold); 286 hist_entry__set_folding(he, unfold);
287 self->nr_entries += 1 + he->nr_rows; 287 hists->nr_entries += 1 + he->nr_rows;
288 } 288 }
289} 289}
290 290
291static void hist_browser__set_folding(struct hist_browser *self, bool unfold) 291static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
292{ 292{
293 hists__set_folding(self->hists, unfold); 293 hists__set_folding(browser->hists, unfold);
294 self->b.nr_entries = self->hists->nr_entries; 294 browser->b.nr_entries = browser->hists->nr_entries;
295 /* Go to the start, we may be way after valid entries after a collapse */ 295 /* Go to the start, we may be way after valid entries after a collapse */
296 ui_browser__reset_index(&self->b); 296 ui_browser__reset_index(&browser->b);
297} 297}
298 298
299static void ui_browser__warn_lost_events(struct ui_browser *browser) 299static void ui_browser__warn_lost_events(struct ui_browser *browser)
@@ -305,64 +305,64 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser)
305 "Or reduce the sampling frequency."); 305 "Or reduce the sampling frequency.");
306} 306}
307 307
308static int hist_browser__run(struct hist_browser *self, const char *ev_name, 308static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
309 void(*timer)(void *arg), void *arg, int delay_secs) 309 void(*timer)(void *arg), void *arg, int delay_secs)
310{ 310{
311 int key; 311 int key;
312 char title[160]; 312 char title[160];
313 313
314 self->b.entries = &self->hists->entries; 314 browser->b.entries = &browser->hists->entries;
315 self->b.nr_entries = self->hists->nr_entries; 315 browser->b.nr_entries = browser->hists->nr_entries;
316 316
317 hist_browser__refresh_dimensions(self); 317 hist_browser__refresh_dimensions(browser);
318 hists__browser_title(self->hists, title, sizeof(title), ev_name); 318 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
319 319
320 if (ui_browser__show(&self->b, title, 320 if (ui_browser__show(&browser->b, title,
321 "Press '?' for help on key bindings") < 0) 321 "Press '?' for help on key bindings") < 0)
322 return -1; 322 return -1;
323 323
324 while (1) { 324 while (1) {
325 key = ui_browser__run(&self->b, delay_secs); 325 key = ui_browser__run(&browser->b, delay_secs);
326 326
327 switch (key) { 327 switch (key) {
328 case K_TIMER: 328 case K_TIMER:
329 timer(arg); 329 timer(arg);
330 ui_browser__update_nr_entries(&self->b, self->hists->nr_entries); 330 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
331 331
332 if (self->hists->stats.nr_lost_warned != 332 if (browser->hists->stats.nr_lost_warned !=
333 self->hists->stats.nr_events[PERF_RECORD_LOST]) { 333 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
334 self->hists->stats.nr_lost_warned = 334 browser->hists->stats.nr_lost_warned =
335 self->hists->stats.nr_events[PERF_RECORD_LOST]; 335 browser->hists->stats.nr_events[PERF_RECORD_LOST];
336 ui_browser__warn_lost_events(&self->b); 336 ui_browser__warn_lost_events(&browser->b);
337 } 337 }
338 338
339 hists__browser_title(self->hists, title, sizeof(title), ev_name); 339 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
340 ui_browser__show_title(&self->b, title); 340 ui_browser__show_title(&browser->b, title);
341 continue; 341 continue;
342 case 'D': { /* Debug */ 342 case 'D': { /* Debug */
343 static int seq; 343 static int seq;
344 struct hist_entry *h = rb_entry(self->b.top, 344 struct hist_entry *h = rb_entry(browser->b.top,
345 struct hist_entry, rb_node); 345 struct hist_entry, rb_node);
346 ui_helpline__pop(); 346 ui_helpline__pop();
347 ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", 347 ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
348 seq++, self->b.nr_entries, 348 seq++, browser->b.nr_entries,
349 self->hists->nr_entries, 349 browser->hists->nr_entries,
350 self->b.height, 350 browser->b.height,
351 self->b.index, 351 browser->b.index,
352 self->b.top_idx, 352 browser->b.top_idx,
353 h->row_offset, h->nr_rows); 353 h->row_offset, h->nr_rows);
354 } 354 }
355 break; 355 break;
356 case 'C': 356 case 'C':
357 /* Collapse the whole world. */ 357 /* Collapse the whole world. */
358 hist_browser__set_folding(self, false); 358 hist_browser__set_folding(browser, false);
359 break; 359 break;
360 case 'E': 360 case 'E':
361 /* Expand the whole world. */ 361 /* Expand the whole world. */
362 hist_browser__set_folding(self, true); 362 hist_browser__set_folding(browser, true);
363 break; 363 break;
364 case K_ENTER: 364 case K_ENTER:
365 if (hist_browser__toggle_fold(self)) 365 if (hist_browser__toggle_fold(browser))
366 break; 366 break;
367 /* fall thru */ 367 /* fall thru */
368 default: 368 default:
@@ -370,23 +370,23 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name,
370 } 370 }
371 } 371 }
372out: 372out:
373 ui_browser__hide(&self->b); 373 ui_browser__hide(&browser->b);
374 return key; 374 return key;
375} 375}
376 376
377static char *callchain_list__sym_name(struct callchain_list *self, 377static char *callchain_list__sym_name(struct callchain_list *cl,
378 char *bf, size_t bfsize) 378 char *bf, size_t bfsize)
379{ 379{
380 if (self->ms.sym) 380 if (cl->ms.sym)
381 return self->ms.sym->name; 381 return cl->ms.sym->name;
382 382
383 snprintf(bf, bfsize, "%#" PRIx64, self->ip); 383 snprintf(bf, bfsize, "%#" PRIx64, cl->ip);
384 return bf; 384 return bf;
385} 385}
386 386
387#define LEVEL_OFFSET_STEP 3 387#define LEVEL_OFFSET_STEP 3
388 388
389static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self, 389static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
390 struct callchain_node *chain_node, 390 struct callchain_node *chain_node,
391 u64 total, int level, 391 u64 total, int level,
392 unsigned short row, 392 unsigned short row,
@@ -444,21 +444,21 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
444 } 444 }
445 445
446 color = HE_COLORSET_NORMAL; 446 color = HE_COLORSET_NORMAL;
447 width = self->b.width - (offset + extra_offset + 2); 447 width = browser->b.width - (offset + extra_offset + 2);
448 if (ui_browser__is_current_entry(&self->b, row)) { 448 if (ui_browser__is_current_entry(&browser->b, row)) {
449 self->selection = &chain->ms; 449 browser->selection = &chain->ms;
450 color = HE_COLORSET_SELECTED; 450 color = HE_COLORSET_SELECTED;
451 *is_current_entry = true; 451 *is_current_entry = true;
452 } 452 }
453 453
454 ui_browser__set_color(&self->b, color); 454 ui_browser__set_color(&browser->b, color);
455 ui_browser__gotorc(&self->b, row, 0); 455 ui_browser__gotorc(&browser->b, row, 0);
456 slsmg_write_nstring(" ", offset + extra_offset); 456 slsmg_write_nstring(" ", offset + extra_offset);
457 slsmg_printf("%c ", folded_sign); 457 slsmg_printf("%c ", folded_sign);
458 slsmg_write_nstring(str, width); 458 slsmg_write_nstring(str, width);
459 free(alloc_str); 459 free(alloc_str);
460 460
461 if (++row == self->b.height) 461 if (++row == browser->b.height)
462 goto out; 462 goto out;
463do_next: 463do_next:
464 if (folded_sign == '+') 464 if (folded_sign == '+')
@@ -467,11 +467,11 @@ do_next:
467 467
468 if (folded_sign == '-') { 468 if (folded_sign == '-') {
469 const int new_level = level + (extra_offset ? 2 : 1); 469 const int new_level = level + (extra_offset ? 2 : 1);
470 row += hist_browser__show_callchain_node_rb_tree(self, child, new_total, 470 row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
471 new_level, row, row_offset, 471 new_level, row, row_offset,
472 is_current_entry); 472 is_current_entry);
473 } 473 }
474 if (row == self->b.height) 474 if (row == browser->b.height)
475 goto out; 475 goto out;
476 node = next; 476 node = next;
477 } 477 }
@@ -479,7 +479,7 @@ out:
479 return row - first_row; 479 return row - first_row;
480} 480}
481 481
482static int hist_browser__show_callchain_node(struct hist_browser *self, 482static int hist_browser__show_callchain_node(struct hist_browser *browser,
483 struct callchain_node *node, 483 struct callchain_node *node,
484 int level, unsigned short row, 484 int level, unsigned short row,
485 off_t *row_offset, 485 off_t *row_offset,
@@ -488,7 +488,7 @@ static int hist_browser__show_callchain_node(struct hist_browser *self,
488 struct callchain_list *chain; 488 struct callchain_list *chain;
489 int first_row = row, 489 int first_row = row,
490 offset = level * LEVEL_OFFSET_STEP, 490 offset = level * LEVEL_OFFSET_STEP,
491 width = self->b.width - offset; 491 width = browser->b.width - offset;
492 char folded_sign = ' '; 492 char folded_sign = ' ';
493 493
494 list_for_each_entry(chain, &node->val, list) { 494 list_for_each_entry(chain, &node->val, list) {
@@ -503,26 +503,26 @@ static int hist_browser__show_callchain_node(struct hist_browser *self,
503 } 503 }
504 504
505 color = HE_COLORSET_NORMAL; 505 color = HE_COLORSET_NORMAL;
506 if (ui_browser__is_current_entry(&self->b, row)) { 506 if (ui_browser__is_current_entry(&browser->b, row)) {
507 self->selection = &chain->ms; 507 browser->selection = &chain->ms;
508 color = HE_COLORSET_SELECTED; 508 color = HE_COLORSET_SELECTED;
509 *is_current_entry = true; 509 *is_current_entry = true;
510 } 510 }
511 511
512 s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr)); 512 s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
513 ui_browser__gotorc(&self->b, row, 0); 513 ui_browser__gotorc(&browser->b, row, 0);
514 ui_browser__set_color(&self->b, color); 514 ui_browser__set_color(&browser->b, color);
515 slsmg_write_nstring(" ", offset); 515 slsmg_write_nstring(" ", offset);
516 slsmg_printf("%c ", folded_sign); 516 slsmg_printf("%c ", folded_sign);
517 slsmg_write_nstring(s, width - 2); 517 slsmg_write_nstring(s, width - 2);
518 518
519 if (++row == self->b.height) 519 if (++row == browser->b.height)
520 goto out; 520 goto out;
521 } 521 }
522 522
523 if (folded_sign == '-') 523 if (folded_sign == '-')
524 row += hist_browser__show_callchain_node_rb_tree(self, node, 524 row += hist_browser__show_callchain_node_rb_tree(browser, node,
525 self->hists->stats.total_period, 525 browser->hists->stats.total_period,
526 level + 1, row, 526 level + 1, row,
527 row_offset, 527 row_offset,
528 is_current_entry); 528 is_current_entry);
@@ -530,7 +530,7 @@ out:
530 return row - first_row; 530 return row - first_row;
531} 531}
532 532
533static int hist_browser__show_callchain(struct hist_browser *self, 533static int hist_browser__show_callchain(struct hist_browser *browser,
534 struct rb_root *chain, 534 struct rb_root *chain,
535 int level, unsigned short row, 535 int level, unsigned short row,
536 off_t *row_offset, 536 off_t *row_offset,
@@ -542,31 +542,31 @@ static int hist_browser__show_callchain(struct hist_browser *self,
542 for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 542 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
543 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 543 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
544 544
545 row += hist_browser__show_callchain_node(self, node, level, 545 row += hist_browser__show_callchain_node(browser, node, level,
546 row, row_offset, 546 row, row_offset,
547 is_current_entry); 547 is_current_entry);
548 if (row == self->b.height) 548 if (row == browser->b.height)
549 break; 549 break;
550 } 550 }
551 551
552 return row - first_row; 552 return row - first_row;
553} 553}
554 554
555static int hist_browser__show_entry(struct hist_browser *self, 555static int hist_browser__show_entry(struct hist_browser *browser,
556 struct hist_entry *entry, 556 struct hist_entry *entry,
557 unsigned short row) 557 unsigned short row)
558{ 558{
559 char s[256]; 559 char s[256];
560 double percent; 560 double percent;
561 int printed = 0; 561 int printed = 0;
562 int width = self->b.width - 6; /* The percentage */ 562 int width = browser->b.width - 6; /* The percentage */
563 char folded_sign = ' '; 563 char folded_sign = ' ';
564 bool current_entry = ui_browser__is_current_entry(&self->b, row); 564 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
565 off_t row_offset = entry->row_offset; 565 off_t row_offset = entry->row_offset;
566 566
567 if (current_entry) { 567 if (current_entry) {
568 self->he_selection = entry; 568 browser->he_selection = entry;
569 self->selection = &entry->ms; 569 browser->selection = &entry->ms;
570 } 570 }
571 571
572 if (symbol_conf.use_callchain) { 572 if (symbol_conf.use_callchain) {
@@ -575,11 +575,11 @@ static int hist_browser__show_entry(struct hist_browser *self,
575 } 575 }
576 576
577 if (row_offset == 0) { 577 if (row_offset == 0) {
578 hist_entry__snprintf(entry, s, sizeof(s), self->hists); 578 hist_entry__snprintf(entry, s, sizeof(s), browser->hists);
579 percent = (entry->period * 100.0) / self->hists->stats.total_period; 579 percent = (entry->period * 100.0) / browser->hists->stats.total_period;
580 580
581 ui_browser__set_percent_color(&self->b, percent, current_entry); 581 ui_browser__set_percent_color(&browser->b, percent, current_entry);
582 ui_browser__gotorc(&self->b, row, 0); 582 ui_browser__gotorc(&browser->b, row, 0);
583 if (symbol_conf.use_callchain) { 583 if (symbol_conf.use_callchain) {
584 slsmg_printf("%c ", folded_sign); 584 slsmg_printf("%c ", folded_sign);
585 width -= 2; 585 width -= 2;
@@ -588,11 +588,11 @@ static int hist_browser__show_entry(struct hist_browser *self,
588 slsmg_printf(" %5.2f%%", percent); 588 slsmg_printf(" %5.2f%%", percent);
589 589
590 /* The scroll bar isn't being used */ 590 /* The scroll bar isn't being used */
591 if (!self->b.navkeypressed) 591 if (!browser->b.navkeypressed)
592 width += 1; 592 width += 1;
593 593
594 if (!current_entry || !self->b.navkeypressed) 594 if (!current_entry || !browser->b.navkeypressed)
595 ui_browser__set_color(&self->b, HE_COLORSET_NORMAL); 595 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
596 596
597 if (symbol_conf.show_nr_samples) { 597 if (symbol_conf.show_nr_samples) {
598 slsmg_printf(" %11u", entry->nr_events); 598 slsmg_printf(" %11u", entry->nr_events);
@@ -610,12 +610,12 @@ static int hist_browser__show_entry(struct hist_browser *self,
610 } else 610 } else
611 --row_offset; 611 --row_offset;
612 612
613 if (folded_sign == '-' && row != self->b.height) { 613 if (folded_sign == '-' && row != browser->b.height) {
614 printed += hist_browser__show_callchain(self, &entry->sorted_chain, 614 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
615 1, row, &row_offset, 615 1, row, &row_offset,
616 &current_entry); 616 &current_entry);
617 if (current_entry) 617 if (current_entry)
618 self->he_selection = entry; 618 browser->he_selection = entry;
619 } 619 }
620 620
621 return printed; 621 return printed;
@@ -631,22 +631,22 @@ static void ui_browser__hists_init_top(struct ui_browser *browser)
631 } 631 }
632} 632}
633 633
634static unsigned int hist_browser__refresh(struct ui_browser *self) 634static unsigned int hist_browser__refresh(struct ui_browser *browser)
635{ 635{
636 unsigned row = 0; 636 unsigned row = 0;
637 struct rb_node *nd; 637 struct rb_node *nd;
638 struct hist_browser *hb = container_of(self, struct hist_browser, b); 638 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
639 639
640 ui_browser__hists_init_top(self); 640 ui_browser__hists_init_top(browser);
641 641
642 for (nd = self->top; nd; nd = rb_next(nd)) { 642 for (nd = browser->top; nd; nd = rb_next(nd)) {
643 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 643 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
644 644
645 if (h->filtered) 645 if (h->filtered)
646 continue; 646 continue;
647 647
648 row += hist_browser__show_entry(hb, h, row); 648 row += hist_browser__show_entry(hb, h, row);
649 if (row == self->height) 649 if (row == browser->height)
650 break; 650 break;
651 } 651 }
652 652
@@ -679,27 +679,27 @@ static struct rb_node *hists__filter_prev_entries(struct rb_node *nd)
679 return NULL; 679 return NULL;
680} 680}
681 681
682static void ui_browser__hists_seek(struct ui_browser *self, 682static void ui_browser__hists_seek(struct ui_browser *browser,
683 off_t offset, int whence) 683 off_t offset, int whence)
684{ 684{
685 struct hist_entry *h; 685 struct hist_entry *h;
686 struct rb_node *nd; 686 struct rb_node *nd;
687 bool first = true; 687 bool first = true;
688 688
689 if (self->nr_entries == 0) 689 if (browser->nr_entries == 0)
690 return; 690 return;
691 691
692 ui_browser__hists_init_top(self); 692 ui_browser__hists_init_top(browser);
693 693
694 switch (whence) { 694 switch (whence) {
695 case SEEK_SET: 695 case SEEK_SET:
696 nd = hists__filter_entries(rb_first(self->entries)); 696 nd = hists__filter_entries(rb_first(browser->entries));
697 break; 697 break;
698 case SEEK_CUR: 698 case SEEK_CUR:
699 nd = self->top; 699 nd = browser->top;
700 goto do_offset; 700 goto do_offset;
701 case SEEK_END: 701 case SEEK_END:
702 nd = hists__filter_prev_entries(rb_last(self->entries)); 702 nd = hists__filter_prev_entries(rb_last(browser->entries));
703 first = false; 703 first = false;
704 break; 704 break;
705 default: 705 default:
@@ -710,7 +710,7 @@ static void ui_browser__hists_seek(struct ui_browser *self,
710 * Moves not relative to the first visible entry invalidates its 710 * Moves not relative to the first visible entry invalidates its
711 * row_offset: 711 * row_offset:
712 */ 712 */
713 h = rb_entry(self->top, struct hist_entry, rb_node); 713 h = rb_entry(browser->top, struct hist_entry, rb_node);
714 h->row_offset = 0; 714 h->row_offset = 0;
715 715
716 /* 716 /*
@@ -738,7 +738,7 @@ do_offset:
738 } else { 738 } else {
739 h->row_offset += offset; 739 h->row_offset += offset;
740 offset = 0; 740 offset = 0;
741 self->top = nd; 741 browser->top = nd;
742 break; 742 break;
743 } 743 }
744 } 744 }
@@ -746,7 +746,7 @@ do_offset:
746 if (nd == NULL) 746 if (nd == NULL)
747 break; 747 break;
748 --offset; 748 --offset;
749 self->top = nd; 749 browser->top = nd;
750 } while (offset != 0); 750 } while (offset != 0);
751 } else if (offset < 0) { 751 } else if (offset < 0) {
752 while (1) { 752 while (1) {
@@ -759,7 +759,7 @@ do_offset:
759 } else { 759 } else {
760 h->row_offset += offset; 760 h->row_offset += offset;
761 offset = 0; 761 offset = 0;
762 self->top = nd; 762 browser->top = nd;
763 break; 763 break;
764 } 764 }
765 } else { 765 } else {
@@ -769,7 +769,7 @@ do_offset:
769 } else { 769 } else {
770 h->row_offset = h->nr_rows + offset; 770 h->row_offset = h->nr_rows + offset;
771 offset = 0; 771 offset = 0;
772 self->top = nd; 772 browser->top = nd;
773 break; 773 break;
774 } 774 }
775 } 775 }
@@ -779,7 +779,7 @@ do_offset:
779 if (nd == NULL) 779 if (nd == NULL)
780 break; 780 break;
781 ++offset; 781 ++offset;
782 self->top = nd; 782 browser->top = nd;
783 if (offset == 0) { 783 if (offset == 0) {
784 /* 784 /*
785 * Last unfiltered hist_entry, check if it is 785 * Last unfiltered hist_entry, check if it is
@@ -794,7 +794,7 @@ do_offset:
794 first = false; 794 first = false;
795 } 795 }
796 } else { 796 } else {
797 self->top = nd; 797 browser->top = nd;
798 h = rb_entry(nd, struct hist_entry, rb_node); 798 h = rb_entry(nd, struct hist_entry, rb_node);
799 h->row_offset = 0; 799 h->row_offset = 0;
800 } 800 }
@@ -802,52 +802,56 @@ do_offset:
802 802
803static struct hist_browser *hist_browser__new(struct hists *hists) 803static struct hist_browser *hist_browser__new(struct hists *hists)
804{ 804{
805 struct hist_browser *self = zalloc(sizeof(*self)); 805 struct hist_browser *browser = zalloc(sizeof(*browser));
806 806
807 if (self) { 807 if (browser) {
808 self->hists = hists; 808 browser->hists = hists;
809 self->b.refresh = hist_browser__refresh; 809 browser->b.refresh = hist_browser__refresh;
810 self->b.seek = ui_browser__hists_seek; 810 browser->b.seek = ui_browser__hists_seek;
811 self->b.use_navkeypressed = true; 811 browser->b.use_navkeypressed = true;
812 if (sort__branch_mode == 1) 812 if (sort__branch_mode == 1)
813 self->has_symbols = sort_sym_from.list.next != NULL; 813 browser->has_symbols = sort_sym_from.list.next != NULL;
814 else 814 else
815 self->has_symbols = sort_sym.list.next != NULL; 815 browser->has_symbols = sort_sym.list.next != NULL;
816 } 816 }
817 817
818 return self; 818 return browser;
819} 819}
820 820
821static void hist_browser__delete(struct hist_browser *self) 821static void hist_browser__delete(struct hist_browser *browser)
822{ 822{
823 free(self); 823 free(browser);
824} 824}
825 825
826static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self) 826static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
827{ 827{
828 return self->he_selection; 828 return browser->he_selection;
829} 829}
830 830
831static struct thread *hist_browser__selected_thread(struct hist_browser *self) 831static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
832{ 832{
833 return self->he_selection->thread; 833 return browser->he_selection->thread;
834} 834}
835 835
836static int hists__browser_title(struct hists *self, char *bf, size_t size, 836static int hists__browser_title(struct hists *hists, char *bf, size_t size,
837 const char *ev_name) 837 const char *ev_name)
838{ 838{
839 char unit; 839 char unit;
840 int printed; 840 int printed;
841 const struct dso *dso = self->dso_filter; 841 const struct dso *dso = hists->dso_filter;
842 const struct thread *thread = self->thread_filter; 842 const struct thread *thread = hists->thread_filter;
843 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE]; 843 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
844 u64 nr_events = hists->stats.total_period;
845
846 nr_samples = convert_unit(nr_samples, &unit);
847 printed = scnprintf(bf, size,
848 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
849 nr_samples, unit, ev_name, nr_events);
844 850
845 nr_events = convert_unit(nr_events, &unit);
846 printed = scnprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
847 851
848 if (self->uid_filter_str) 852 if (hists->uid_filter_str)
849 printed += snprintf(bf + printed, size - printed, 853 printed += snprintf(bf + printed, size - printed,
850 ", UID: %s", self->uid_filter_str); 854 ", UID: %s", hists->uid_filter_str);
851 if (thread) 855 if (thread)
852 printed += scnprintf(bf + printed, size - printed, 856 printed += scnprintf(bf + printed, size - printed,
853 ", Thread: %s(%d)", 857 ", Thread: %s(%d)",
@@ -875,8 +879,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
875 void(*timer)(void *arg), void *arg, 879 void(*timer)(void *arg), void *arg,
876 int delay_secs) 880 int delay_secs)
877{ 881{
878 struct hists *self = &evsel->hists; 882 struct hists *hists = &evsel->hists;
879 struct hist_browser *browser = hist_browser__new(self); 883 struct hist_browser *browser = hist_browser__new(hists);
880 struct branch_info *bi; 884 struct branch_info *bi;
881 struct pstack *fstack; 885 struct pstack *fstack;
882 char *options[16]; 886 char *options[16];
@@ -937,13 +941,13 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
937 goto zoom_dso; 941 goto zoom_dso;
938 case 't': 942 case 't':
939 goto zoom_thread; 943 goto zoom_thread;
940 case 's': 944 case '/':
941 if (ui_browser__input_window("Symbol to show", 945 if (ui_browser__input_window("Symbol to show",
942 "Please enter the name of symbol you want to see", 946 "Please enter the name of symbol you want to see",
943 buf, "ENTER: OK, ESC: Cancel", 947 buf, "ENTER: OK, ESC: Cancel",
944 delay_secs * 2) == K_ENTER) { 948 delay_secs * 2) == K_ENTER) {
945 self->symbol_filter_str = *buf ? buf : NULL; 949 hists->symbol_filter_str = *buf ? buf : NULL;
946 hists__filter_by_symbol(self); 950 hists__filter_by_symbol(hists);
947 hist_browser__reset(browser); 951 hist_browser__reset(browser);
948 } 952 }
949 continue; 953 continue;
@@ -965,7 +969,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
965 "E Expand all callchains\n" 969 "E Expand all callchains\n"
966 "d Zoom into current DSO\n" 970 "d Zoom into current DSO\n"
967 "t Zoom into current Thread\n" 971 "t Zoom into current Thread\n"
968 "s Filter symbol by name"); 972 "/ Filter symbol by name");
969 continue; 973 continue;
970 case K_ENTER: 974 case K_ENTER:
971 case K_RIGHT: 975 case K_RIGHT:
@@ -1124,7 +1128,7 @@ zoom_out_dso:
1124 sort_dso.elide = true; 1128 sort_dso.elide = true;
1125 pstack__push(fstack, &browser->hists->dso_filter); 1129 pstack__push(fstack, &browser->hists->dso_filter);
1126 } 1130 }
1127 hists__filter_by_dso(self); 1131 hists__filter_by_dso(hists);
1128 hist_browser__reset(browser); 1132 hist_browser__reset(browser);
1129 } else if (choice == zoom_thread) { 1133 } else if (choice == zoom_thread) {
1130zoom_thread: 1134zoom_thread:
@@ -1142,7 +1146,7 @@ zoom_out_thread:
1142 sort_thread.elide = true; 1146 sort_thread.elide = true;
1143 pstack__push(fstack, &browser->hists->thread_filter); 1147 pstack__push(fstack, &browser->hists->thread_filter);
1144 } 1148 }
1145 hists__filter_by_thread(self); 1149 hists__filter_by_thread(hists);
1146 hist_browser__reset(browser); 1150 hist_browser__reset(browser);
1147 } 1151 }
1148 } 1152 }
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
index eca6575abfd0..98851d55a53e 100644
--- a/tools/perf/util/ui/browsers/map.c
+++ b/tools/perf/ui/browsers/map.c
@@ -5,9 +5,9 @@
5#include <sys/ttydefaults.h> 5#include <sys/ttydefaults.h>
6#include <string.h> 6#include <string.h>
7#include <linux/bitops.h> 7#include <linux/bitops.h>
8#include "../../util.h" 8#include "../../util/util.h"
9#include "../../debug.h" 9#include "../../util/debug.h"
10#include "../../symbol.h" 10#include "../../util/symbol.h"
11#include "../browser.h" 11#include "../browser.h"
12#include "../helpline.h" 12#include "../helpline.h"
13#include "map.h" 13#include "map.h"
diff --git a/tools/perf/util/ui/browsers/map.h b/tools/perf/ui/browsers/map.h
index df8581a43e17..df8581a43e17 100644
--- a/tools/perf/util/ui/browsers/map.h
+++ b/tools/perf/ui/browsers/map.h
diff --git a/tools/perf/util/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 258352a2356c..0656c381a89c 100644
--- a/tools/perf/util/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -9,24 +9,13 @@
9 9
10#define MAX_COLUMNS 32 10#define MAX_COLUMNS 32
11 11
12void perf_gtk_setup_browser(int argc, const char *argv[], 12static void perf_gtk__signal(int sig)
13 bool fallback_to_pager __used)
14{
15 gtk_init(&argc, (char ***)&argv);
16}
17
18void perf_gtk_exit_browser(bool wait_for_ok __used)
19{
20 gtk_main_quit();
21}
22
23static void perf_gtk_signal(int sig)
24{ 13{
25 psignal(sig, "perf"); 14 psignal(sig, "perf");
26 gtk_main_quit(); 15 gtk_main_quit();
27} 16}
28 17
29static void perf_gtk_resize_window(GtkWidget *window) 18static void perf_gtk__resize_window(GtkWidget *window)
30{ 19{
31 GdkRectangle rect; 20 GdkRectangle rect;
32 GdkScreen *screen; 21 GdkScreen *screen;
@@ -46,7 +35,7 @@ static void perf_gtk_resize_window(GtkWidget *window)
46 gtk_window_resize(GTK_WINDOW(window), width, height); 35 gtk_window_resize(GTK_WINDOW(window), width, height);
47} 36}
48 37
49static void perf_gtk_show_hists(GtkWidget *window, struct hists *hists) 38static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
50{ 39{
51 GType col_types[MAX_COLUMNS]; 40 GType col_types[MAX_COLUMNS];
52 GtkCellRenderer *renderer; 41 GtkCellRenderer *renderer;
@@ -142,11 +131,11 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
142 GtkWidget *notebook; 131 GtkWidget *notebook;
143 GtkWidget *window; 132 GtkWidget *window;
144 133
145 signal(SIGSEGV, perf_gtk_signal); 134 signal(SIGSEGV, perf_gtk__signal);
146 signal(SIGFPE, perf_gtk_signal); 135 signal(SIGFPE, perf_gtk__signal);
147 signal(SIGINT, perf_gtk_signal); 136 signal(SIGINT, perf_gtk__signal);
148 signal(SIGQUIT, perf_gtk_signal); 137 signal(SIGQUIT, perf_gtk__signal);
149 signal(SIGTERM, perf_gtk_signal); 138 signal(SIGTERM, perf_gtk__signal);
150 139
151 window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 140 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
152 141
@@ -168,7 +157,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
168 GTK_POLICY_AUTOMATIC, 157 GTK_POLICY_AUTOMATIC,
169 GTK_POLICY_AUTOMATIC); 158 GTK_POLICY_AUTOMATIC);
170 159
171 perf_gtk_show_hists(scrolled_window, hists); 160 perf_gtk__show_hists(scrolled_window, hists);
172 161
173 tab_label = gtk_label_new(evname); 162 tab_label = gtk_label_new(evname);
174 163
@@ -179,7 +168,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
179 168
180 gtk_widget_show_all(window); 169 gtk_widget_show_all(window);
181 170
182 perf_gtk_resize_window(window); 171 perf_gtk__resize_window(window);
183 172
184 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); 173 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
185 174
diff --git a/tools/perf/util/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
index 75177ee04032..75177ee04032 100644
--- a/tools/perf/util/gtk/gtk.h
+++ b/tools/perf/ui/gtk/gtk.h
diff --git a/tools/perf/ui/gtk/setup.c b/tools/perf/ui/gtk/setup.c
new file mode 100644
index 000000000000..829529957766
--- /dev/null
+++ b/tools/perf/ui/gtk/setup.c
@@ -0,0 +1,12 @@
1#include "gtk.h"
2#include "../../util/cache.h"
3
4int perf_gtk__init(void)
5{
6 return gtk_init_check(NULL, NULL) ? 0 : -1;
7}
8
9void perf_gtk__exit(bool wait_for_ok __used)
10{
11 gtk_main_quit();
12}
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/ui/helpline.c
index 2f950c2641c8..2f950c2641c8 100644
--- a/tools/perf/util/ui/helpline.c
+++ b/tools/perf/ui/helpline.c
diff --git a/tools/perf/util/ui/helpline.h b/tools/perf/ui/helpline.h
index 7bab6b34e35e..7bab6b34e35e 100644
--- a/tools/perf/util/ui/helpline.h
+++ b/tools/perf/ui/helpline.h
diff --git a/tools/perf/util/ui/keysyms.h b/tools/perf/ui/keysyms.h
index 809eca5707fa..809eca5707fa 100644
--- a/tools/perf/util/ui/keysyms.h
+++ b/tools/perf/ui/keysyms.h
diff --git a/tools/perf/util/ui/libslang.h b/tools/perf/ui/libslang.h
index 4d54b6450f5b..4d54b6450f5b 100644
--- a/tools/perf/util/ui/libslang.h
+++ b/tools/perf/ui/libslang.h
diff --git a/tools/perf/util/ui/progress.c b/tools/perf/ui/progress.c
index 13aa64e50e11..13aa64e50e11 100644
--- a/tools/perf/util/ui/progress.c
+++ b/tools/perf/ui/progress.c
diff --git a/tools/perf/util/ui/progress.h b/tools/perf/ui/progress.h
index d9c205b59aa1..d9c205b59aa1 100644
--- a/tools/perf/util/ui/progress.h
+++ b/tools/perf/ui/progress.h
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
new file mode 100644
index 000000000000..791fb15ce350
--- /dev/null
+++ b/tools/perf/ui/setup.c
@@ -0,0 +1,46 @@
1#include "../cache.h"
2#include "../debug.h"
3
4
5void setup_browser(bool fallback_to_pager)
6{
7 if (!isatty(1) || dump_trace)
8 use_browser = 0;
9
10 /* default to TUI */
11 if (use_browser < 0)
12 use_browser = 1;
13
14 switch (use_browser) {
15 case 2:
16 if (perf_gtk__init() == 0)
17 break;
18 /* fall through */
19 case 1:
20 use_browser = 1;
21 if (ui__init() == 0)
22 break;
23 /* fall through */
24 default:
25 use_browser = 0;
26 if (fallback_to_pager)
27 setup_pager();
28 break;
29 }
30}
31
32void exit_browser(bool wait_for_ok)
33{
34 switch (use_browser) {
35 case 2:
36 perf_gtk__exit(wait_for_ok);
37 break;
38
39 case 1:
40 ui__exit(wait_for_ok);
41 break;
42
43 default:
44 break;
45 }
46}
diff --git a/tools/perf/util/ui/setup.c b/tools/perf/ui/tui/setup.c
index 85a69faa09aa..d33e943ac434 100644
--- a/tools/perf/util/ui/setup.c
+++ b/tools/perf/ui/tui/setup.c
@@ -2,14 +2,14 @@
2#include <signal.h> 2#include <signal.h>
3#include <stdbool.h> 3#include <stdbool.h>
4 4
5#include "../cache.h" 5#include "../../util/cache.h"
6#include "../debug.h" 6#include "../../util/debug.h"
7#include "browser.h" 7#include "../browser.h"
8#include "helpline.h" 8#include "../helpline.h"
9#include "ui.h" 9#include "../ui.h"
10#include "util.h" 10#include "../util.h"
11#include "libslang.h" 11#include "../libslang.h"
12#include "keysyms.h" 12#include "../keysyms.h"
13 13
14pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; 14pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
15 15
@@ -93,45 +93,26 @@ static void newt_suspend(void *d __used)
93 newtResume(); 93 newtResume();
94} 94}
95 95
96static int ui__init(void)
97{
98 int err = SLkp_init();
99
100 if (err < 0)
101 goto out;
102
103 SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
104out:
105 return err;
106}
107
108static void ui__exit(void)
109{
110 SLtt_set_cursor_visibility(1);
111 SLsmg_refresh();
112 SLsmg_reset_smg();
113 SLang_reset_tty();
114}
115
116static void ui__signal(int sig) 96static void ui__signal(int sig)
117{ 97{
118 ui__exit(); 98 ui__exit(false);
119 psignal(sig, "perf"); 99 psignal(sig, "perf");
120 exit(0); 100 exit(0);
121} 101}
122 102
123void setup_browser(bool fallback_to_pager) 103int ui__init(void)
124{ 104{
125 if (!isatty(1) || !use_browser || dump_trace) { 105 int err;
126 use_browser = 0;
127 if (fallback_to_pager)
128 setup_pager();
129 return;
130 }
131 106
132 use_browser = 1;
133 newtInit(); 107 newtInit();
134 ui__init(); 108 err = SLkp_init();
109 if (err < 0) {
110 pr_err("TUI initialization failed.\n");
111 goto out;
112 }
113
114 SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
115
135 newtSetSuspendCallback(newt_suspend, NULL); 116 newtSetSuspendCallback(newt_suspend, NULL);
136 ui_helpline__init(); 117 ui_helpline__init();
137 ui_browser__init(); 118 ui_browser__init();
@@ -141,15 +122,19 @@ void setup_browser(bool fallback_to_pager)
141 signal(SIGINT, ui__signal); 122 signal(SIGINT, ui__signal);
142 signal(SIGQUIT, ui__signal); 123 signal(SIGQUIT, ui__signal);
143 signal(SIGTERM, ui__signal); 124 signal(SIGTERM, ui__signal);
125out:
126 return err;
144} 127}
145 128
146void exit_browser(bool wait_for_ok) 129void ui__exit(bool wait_for_ok)
147{ 130{
148 if (use_browser > 0) { 131 if (wait_for_ok)
149 if (wait_for_ok) 132 ui__question_window("Fatal Error",
150 ui__question_window("Fatal Error", 133 ui_helpline__last_msg,
151 ui_helpline__last_msg, 134 "Press any key...", 0);
152 "Press any key...", 0); 135
153 ui__exit(); 136 SLtt_set_cursor_visibility(1);
154 } 137 SLsmg_refresh();
138 SLsmg_reset_smg();
139 SLang_reset_tty();
155} 140}
diff --git a/tools/perf/util/ui/ui.h b/tools/perf/ui/ui.h
index 7b67045479f6..7b67045479f6 100644
--- a/tools/perf/util/ui/ui.h
+++ b/tools/perf/ui/ui.h
diff --git a/tools/perf/util/ui/util.c b/tools/perf/ui/util.c
index ad4374a16bb0..ad4374a16bb0 100644
--- a/tools/perf/util/ui/util.c
+++ b/tools/perf/ui/util.c
diff --git a/tools/perf/util/ui/util.h b/tools/perf/ui/util.h
index 2d1738bd71c8..2d1738bd71c8 100644
--- a/tools/perf/util/ui/util.h
+++ b/tools/perf/ui/util.h
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 08c6d138a655..8069dfb5ba77 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -18,6 +18,403 @@
18 18
19const char *disassembler_style; 19const char *disassembler_style;
20 20
21static struct ins *ins__find(const char *name);
22static int disasm_line__parse(char *line, char **namep, char **rawp);
23
24static void ins__delete(struct ins_operands *ops)
25{
26 free(ops->source.raw);
27 free(ops->source.name);
28 free(ops->target.raw);
29 free(ops->target.name);
30}
31
32static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
33 struct ins_operands *ops)
34{
35 return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw);
36}
37
38int ins__scnprintf(struct ins *ins, char *bf, size_t size,
39 struct ins_operands *ops)
40{
41 if (ins->ops->scnprintf)
42 return ins->ops->scnprintf(ins, bf, size, ops);
43
44 return ins__raw_scnprintf(ins, bf, size, ops);
45}
46
47static int call__parse(struct ins_operands *ops)
48{
49 char *endptr, *tok, *name;
50
51 ops->target.addr = strtoull(ops->raw, &endptr, 16);
52
53 name = strchr(endptr, '<');
54 if (name == NULL)
55 goto indirect_call;
56
57 name++;
58
59 tok = strchr(name, '>');
60 if (tok == NULL)
61 return -1;
62
63 *tok = '\0';
64 ops->target.name = strdup(name);
65 *tok = '>';
66
67 return ops->target.name == NULL ? -1 : 0;
68
69indirect_call:
70 tok = strchr(endptr, '(');
71 if (tok != NULL) {
72 ops->target.addr = 0;
73 return 0;
74 }
75
76 tok = strchr(endptr, '*');
77 if (tok == NULL)
78 return -1;
79
80 ops->target.addr = strtoull(tok + 1, NULL, 16);
81 return 0;
82}
83
84static int call__scnprintf(struct ins *ins, char *bf, size_t size,
85 struct ins_operands *ops)
86{
87 if (ops->target.name)
88 return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name);
89
90 if (ops->target.addr == 0)
91 return ins__raw_scnprintf(ins, bf, size, ops);
92
93 return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr);
94}
95
96static struct ins_ops call_ops = {
97 .parse = call__parse,
98 .scnprintf = call__scnprintf,
99};
100
101bool ins__is_call(const struct ins *ins)
102{
103 return ins->ops == &call_ops;
104}
105
106static int jump__parse(struct ins_operands *ops)
107{
108 const char *s = strchr(ops->raw, '+');
109
110 ops->target.addr = strtoll(ops->raw, NULL, 16);
111
112 if (s++ != NULL)
113 ops->target.offset = strtoll(s, NULL, 16);
114 else
115 ops->target.offset = UINT64_MAX;
116
117 return 0;
118}
119
120static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
121 struct ins_operands *ops)
122{
123 return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset);
124}
125
126static struct ins_ops jump_ops = {
127 .parse = jump__parse,
128 .scnprintf = jump__scnprintf,
129};
130
131bool ins__is_jump(const struct ins *ins)
132{
133 return ins->ops == &jump_ops;
134}
135
136static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
137{
138 char *endptr, *name, *t;
139
140 if (strstr(raw, "(%rip)") == NULL)
141 return 0;
142
143 *addrp = strtoull(comment, &endptr, 16);
144 name = strchr(endptr, '<');
145 if (name == NULL)
146 return -1;
147
148 name++;
149
150 t = strchr(name, '>');
151 if (t == NULL)
152 return 0;
153
154 *t = '\0';
155 *namep = strdup(name);
156 *t = '>';
157
158 return 0;
159}
160
161static int lock__parse(struct ins_operands *ops)
162{
163 char *name;
164
165 ops->locked.ops = zalloc(sizeof(*ops->locked.ops));
166 if (ops->locked.ops == NULL)
167 return 0;
168
169 if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0)
170 goto out_free_ops;
171
172 ops->locked.ins = ins__find(name);
173 if (ops->locked.ins == NULL)
174 goto out_free_ops;
175
176 if (!ops->locked.ins->ops)
177 return 0;
178
179 if (ops->locked.ins->ops->parse)
180 ops->locked.ins->ops->parse(ops->locked.ops);
181
182 return 0;
183
184out_free_ops:
185 free(ops->locked.ops);
186 ops->locked.ops = NULL;
187 return 0;
188}
189
190static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
191 struct ins_operands *ops)
192{
193 int printed;
194
195 if (ops->locked.ins == NULL)
196 return ins__raw_scnprintf(ins, bf, size, ops);
197
198 printed = scnprintf(bf, size, "%-6.6s ", ins->name);
199 return printed + ins__scnprintf(ops->locked.ins, bf + printed,
200 size - printed, ops->locked.ops);
201}
202
203static void lock__delete(struct ins_operands *ops)
204{
205 free(ops->locked.ops);
206 free(ops->target.raw);
207 free(ops->target.name);
208}
209
210static struct ins_ops lock_ops = {
211 .free = lock__delete,
212 .parse = lock__parse,
213 .scnprintf = lock__scnprintf,
214};
215
216static int mov__parse(struct ins_operands *ops)
217{
218 char *s = strchr(ops->raw, ','), *target, *comment, prev;
219
220 if (s == NULL)
221 return -1;
222
223 *s = '\0';
224 ops->source.raw = strdup(ops->raw);
225 *s = ',';
226
227 if (ops->source.raw == NULL)
228 return -1;
229
230 target = ++s;
231
232 while (s[0] != '\0' && !isspace(s[0]))
233 ++s;
234 prev = *s;
235 *s = '\0';
236
237 ops->target.raw = strdup(target);
238 *s = prev;
239
240 if (ops->target.raw == NULL)
241 goto out_free_source;
242
243 comment = strchr(s, '#');
244 if (comment == NULL)
245 return 0;
246
247 while (comment[0] != '\0' && isspace(comment[0]))
248 ++comment;
249
250 comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name);
251 comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
252
253 return 0;
254
255out_free_source:
256 free(ops->source.raw);
257 ops->source.raw = NULL;
258 return -1;
259}
260
261static int mov__scnprintf(struct ins *ins, char *bf, size_t size,
262 struct ins_operands *ops)
263{
264 return scnprintf(bf, size, "%-6.6s %s,%s", ins->name,
265 ops->source.name ?: ops->source.raw,
266 ops->target.name ?: ops->target.raw);
267}
268
269static struct ins_ops mov_ops = {
270 .parse = mov__parse,
271 .scnprintf = mov__scnprintf,
272};
273
274static int dec__parse(struct ins_operands *ops)
275{
276 char *target, *comment, *s, prev;
277
278 target = s = ops->raw;
279
280 while (s[0] != '\0' && !isspace(s[0]))
281 ++s;
282 prev = *s;
283 *s = '\0';
284
285 ops->target.raw = strdup(target);
286 *s = prev;
287
288 if (ops->target.raw == NULL)
289 return -1;
290
291 comment = strchr(s, '#');
292 if (comment == NULL)
293 return 0;
294
295 while (comment[0] != '\0' && isspace(comment[0]))
296 ++comment;
297
298 comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
299
300 return 0;
301}
302
303static int dec__scnprintf(struct ins *ins, char *bf, size_t size,
304 struct ins_operands *ops)
305{
306 return scnprintf(bf, size, "%-6.6s %s", ins->name,
307 ops->target.name ?: ops->target.raw);
308}
309
310static struct ins_ops dec_ops = {
311 .parse = dec__parse,
312 .scnprintf = dec__scnprintf,
313};
314
315static int nop__scnprintf(struct ins *ins __used, char *bf, size_t size,
316 struct ins_operands *ops __used)
317{
318 return scnprintf(bf, size, "%-6.6s", "nop");
319}
320
321static struct ins_ops nop_ops = {
322 .scnprintf = nop__scnprintf,
323};
324
325/*
326 * Must be sorted by name!
327 */
328static struct ins instructions[] = {
329 { .name = "add", .ops = &mov_ops, },
330 { .name = "addl", .ops = &mov_ops, },
331 { .name = "addq", .ops = &mov_ops, },
332 { .name = "addw", .ops = &mov_ops, },
333 { .name = "and", .ops = &mov_ops, },
334 { .name = "bts", .ops = &mov_ops, },
335 { .name = "call", .ops = &call_ops, },
336 { .name = "callq", .ops = &call_ops, },
337 { .name = "cmp", .ops = &mov_ops, },
338 { .name = "cmpb", .ops = &mov_ops, },
339 { .name = "cmpl", .ops = &mov_ops, },
340 { .name = "cmpq", .ops = &mov_ops, },
341 { .name = "cmpw", .ops = &mov_ops, },
342 { .name = "cmpxch", .ops = &mov_ops, },
343 { .name = "dec", .ops = &dec_ops, },
344 { .name = "decl", .ops = &dec_ops, },
345 { .name = "imul", .ops = &mov_ops, },
346 { .name = "inc", .ops = &dec_ops, },
347 { .name = "incl", .ops = &dec_ops, },
348 { .name = "ja", .ops = &jump_ops, },
349 { .name = "jae", .ops = &jump_ops, },
350 { .name = "jb", .ops = &jump_ops, },
351 { .name = "jbe", .ops = &jump_ops, },
352 { .name = "jc", .ops = &jump_ops, },
353 { .name = "jcxz", .ops = &jump_ops, },
354 { .name = "je", .ops = &jump_ops, },
355 { .name = "jecxz", .ops = &jump_ops, },
356 { .name = "jg", .ops = &jump_ops, },
357 { .name = "jge", .ops = &jump_ops, },
358 { .name = "jl", .ops = &jump_ops, },
359 { .name = "jle", .ops = &jump_ops, },
360 { .name = "jmp", .ops = &jump_ops, },
361 { .name = "jmpq", .ops = &jump_ops, },
362 { .name = "jna", .ops = &jump_ops, },
363 { .name = "jnae", .ops = &jump_ops, },
364 { .name = "jnb", .ops = &jump_ops, },
365 { .name = "jnbe", .ops = &jump_ops, },
366 { .name = "jnc", .ops = &jump_ops, },
367 { .name = "jne", .ops = &jump_ops, },
368 { .name = "jng", .ops = &jump_ops, },
369 { .name = "jnge", .ops = &jump_ops, },
370 { .name = "jnl", .ops = &jump_ops, },
371 { .name = "jnle", .ops = &jump_ops, },
372 { .name = "jno", .ops = &jump_ops, },
373 { .name = "jnp", .ops = &jump_ops, },
374 { .name = "jns", .ops = &jump_ops, },
375 { .name = "jnz", .ops = &jump_ops, },
376 { .name = "jo", .ops = &jump_ops, },
377 { .name = "jp", .ops = &jump_ops, },
378 { .name = "jpe", .ops = &jump_ops, },
379 { .name = "jpo", .ops = &jump_ops, },
380 { .name = "jrcxz", .ops = &jump_ops, },
381 { .name = "js", .ops = &jump_ops, },
382 { .name = "jz", .ops = &jump_ops, },
383 { .name = "lea", .ops = &mov_ops, },
384 { .name = "lock", .ops = &lock_ops, },
385 { .name = "mov", .ops = &mov_ops, },
386 { .name = "movb", .ops = &mov_ops, },
387 { .name = "movdqa",.ops = &mov_ops, },
388 { .name = "movl", .ops = &mov_ops, },
389 { .name = "movq", .ops = &mov_ops, },
390 { .name = "movslq", .ops = &mov_ops, },
391 { .name = "movzbl", .ops = &mov_ops, },
392 { .name = "movzwl", .ops = &mov_ops, },
393 { .name = "nop", .ops = &nop_ops, },
394 { .name = "nopl", .ops = &nop_ops, },
395 { .name = "nopw", .ops = &nop_ops, },
396 { .name = "or", .ops = &mov_ops, },
397 { .name = "orl", .ops = &mov_ops, },
398 { .name = "test", .ops = &mov_ops, },
399 { .name = "testb", .ops = &mov_ops, },
400 { .name = "testl", .ops = &mov_ops, },
401 { .name = "xadd", .ops = &mov_ops, },
402};
403
404static int ins__cmp(const void *name, const void *insp)
405{
406 const struct ins *ins = insp;
407
408 return strcmp(name, ins->name);
409}
410
411static struct ins *ins__find(const char *name)
412{
413 const int nmemb = ARRAY_SIZE(instructions);
414
415 return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp);
416}
417
21int symbol__annotate_init(struct map *map __used, struct symbol *sym) 418int symbol__annotate_init(struct map *map __used, struct symbol *sym)
22{ 419{
23 struct annotation *notes = symbol__annotation(sym); 420 struct annotation *notes = symbol__annotation(sym);
@@ -28,7 +425,7 @@ int symbol__annotate_init(struct map *map __used, struct symbol *sym)
28int symbol__alloc_hist(struct symbol *sym) 425int symbol__alloc_hist(struct symbol *sym)
29{ 426{
30 struct annotation *notes = symbol__annotation(sym); 427 struct annotation *notes = symbol__annotation(sym);
31 const size_t size = sym->end - sym->start + 1; 428 const size_t size = symbol__size(sym);
32 size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64)); 429 size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
33 430
34 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); 431 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
@@ -78,31 +475,110 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
78 return 0; 475 return 0;
79} 476}
80 477
81static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize) 478static void disasm_line__init_ins(struct disasm_line *dl)
479{
480 dl->ins = ins__find(dl->name);
481
482 if (dl->ins == NULL)
483 return;
484
485 if (!dl->ins->ops)
486 return;
487
488 if (dl->ins->ops->parse)
489 dl->ins->ops->parse(&dl->ops);
490}
491
492static int disasm_line__parse(char *line, char **namep, char **rawp)
493{
494 char *name = line, tmp;
495
496 while (isspace(name[0]))
497 ++name;
498
499 if (name[0] == '\0')
500 return -1;
501
502 *rawp = name + 1;
503
504 while ((*rawp)[0] != '\0' && !isspace((*rawp)[0]))
505 ++*rawp;
506
507 tmp = (*rawp)[0];
508 (*rawp)[0] = '\0';
509 *namep = strdup(name);
510
511 if (*namep == NULL)
512 goto out_free_name;
513
514 (*rawp)[0] = tmp;
515
516 if ((*rawp)[0] != '\0') {
517 (*rawp)++;
518 while (isspace((*rawp)[0]))
519 ++(*rawp);
520 }
521
522 return 0;
523
524out_free_name:
525 free(*namep);
526 *namep = NULL;
527 return -1;
528}
529
530static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize)
82{ 531{
83 struct objdump_line *self = malloc(sizeof(*self) + privsize); 532 struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
84 533
85 if (self != NULL) { 534 if (dl != NULL) {
86 self->offset = offset; 535 dl->offset = offset;
87 self->line = line; 536 dl->line = strdup(line);
537 if (dl->line == NULL)
538 goto out_delete;
539
540 if (offset != -1) {
541 if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0)
542 goto out_free_line;
543
544 disasm_line__init_ins(dl);
545 }
88 } 546 }
89 547
90 return self; 548 return dl;
549
550out_free_line:
551 free(dl->line);
552out_delete:
553 free(dl);
554 return NULL;
555}
556
557void disasm_line__free(struct disasm_line *dl)
558{
559 free(dl->line);
560 free(dl->name);
561 if (dl->ins && dl->ins->ops->free)
562 dl->ins->ops->free(&dl->ops);
563 else
564 ins__delete(&dl->ops);
565 free(dl);
91} 566}
92 567
93void objdump_line__free(struct objdump_line *self) 568int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw)
94{ 569{
95 free(self->line); 570 if (raw || !dl->ins)
96 free(self); 571 return scnprintf(bf, size, "%-6.6s %s", dl->name, dl->ops.raw);
572
573 return ins__scnprintf(dl->ins, bf, size, &dl->ops);
97} 574}
98 575
99static void objdump__add_line(struct list_head *head, struct objdump_line *line) 576static void disasm__add(struct list_head *head, struct disasm_line *line)
100{ 577{
101 list_add_tail(&line->node, head); 578 list_add_tail(&line->node, head);
102} 579}
103 580
104struct objdump_line *objdump__get_next_ip_line(struct list_head *head, 581struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos)
105 struct objdump_line *pos)
106{ 582{
107 list_for_each_entry_continue(pos, head, node) 583 list_for_each_entry_continue(pos, head, node)
108 if (pos->offset >= 0) 584 if (pos->offset >= 0)
@@ -111,15 +587,14 @@ struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
111 return NULL; 587 return NULL;
112} 588}
113 589
114static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, 590static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start,
115 int evidx, u64 len, int min_pcnt, 591 int evidx, u64 len, int min_pcnt, int printed,
116 int printed, int max_lines, 592 int max_lines, struct disasm_line *queue)
117 struct objdump_line *queue)
118{ 593{
119 static const char *prev_line; 594 static const char *prev_line;
120 static const char *prev_color; 595 static const char *prev_color;
121 596
122 if (oline->offset != -1) { 597 if (dl->offset != -1) {
123 const char *path = NULL; 598 const char *path = NULL;
124 unsigned int hits = 0; 599 unsigned int hits = 0;
125 double percent = 0.0; 600 double percent = 0.0;
@@ -127,10 +602,11 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
127 struct annotation *notes = symbol__annotation(sym); 602 struct annotation *notes = symbol__annotation(sym);
128 struct source_line *src_line = notes->src->lines; 603 struct source_line *src_line = notes->src->lines;
129 struct sym_hist *h = annotation__histogram(notes, evidx); 604 struct sym_hist *h = annotation__histogram(notes, evidx);
130 s64 offset = oline->offset; 605 s64 offset = dl->offset;
131 struct objdump_line *next; 606 const u64 addr = start + offset;
607 struct disasm_line *next;
132 608
133 next = objdump__get_next_ip_line(&notes->src->source, oline); 609 next = disasm__get_next_ip_line(&notes->src->source, dl);
134 610
135 while (offset < (s64)len && 611 while (offset < (s64)len &&
136 (next == NULL || offset < next->offset)) { 612 (next == NULL || offset < next->offset)) {
@@ -155,9 +631,9 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
155 631
156 if (queue != NULL) { 632 if (queue != NULL) {
157 list_for_each_entry_from(queue, &notes->src->source, node) { 633 list_for_each_entry_from(queue, &notes->src->source, node) {
158 if (queue == oline) 634 if (queue == dl)
159 break; 635 break;
160 objdump_line__print(queue, sym, evidx, len, 636 disasm_line__print(queue, sym, start, evidx, len,
161 0, 0, 1, NULL); 637 0, 0, 1, NULL);
162 } 638 }
163 } 639 }
@@ -180,17 +656,18 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
180 656
181 color_fprintf(stdout, color, " %7.2f", percent); 657 color_fprintf(stdout, color, " %7.2f", percent);
182 printf(" : "); 658 printf(" : ");
183 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", oline->line); 659 color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr);
660 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);
184 } else if (max_lines && printed >= max_lines) 661 } else if (max_lines && printed >= max_lines)
185 return 1; 662 return 1;
186 else { 663 else {
187 if (queue) 664 if (queue)
188 return -1; 665 return -1;
189 666
190 if (!*oline->line) 667 if (!*dl->line)
191 printf(" :\n"); 668 printf(" :\n");
192 else 669 else
193 printf(" : %s\n", oline->line); 670 printf(" : %s\n", dl->line);
194 } 671 }
195 672
196 return 0; 673 return 0;
@@ -200,8 +677,8 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
200 FILE *file, size_t privsize) 677 FILE *file, size_t privsize)
201{ 678{
202 struct annotation *notes = symbol__annotation(sym); 679 struct annotation *notes = symbol__annotation(sym);
203 struct objdump_line *objdump_line; 680 struct disasm_line *dl;
204 char *line = NULL, *tmp, *tmp2, *c; 681 char *line = NULL, *parsed_line, *tmp, *tmp2, *c;
205 size_t line_len; 682 size_t line_len;
206 s64 line_ip, offset = -1; 683 s64 line_ip, offset = -1;
207 684
@@ -219,6 +696,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
219 *c = 0; 696 *c = 0;
220 697
221 line_ip = -1; 698 line_ip = -1;
699 parsed_line = line;
222 700
223 /* 701 /*
224 * Strip leading spaces: 702 * Strip leading spaces:
@@ -246,14 +724,17 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
246 offset = line_ip - start; 724 offset = line_ip - start;
247 if (offset < 0 || (u64)line_ip > end) 725 if (offset < 0 || (u64)line_ip > end)
248 offset = -1; 726 offset = -1;
727 else
728 parsed_line = tmp2 + 1;
249 } 729 }
250 730
251 objdump_line = objdump_line__new(offset, line, privsize); 731 dl = disasm_line__new(offset, parsed_line, privsize);
252 if (objdump_line == NULL) { 732 free(line);
253 free(line); 733
734 if (dl == NULL)
254 return -1; 735 return -1;
255 } 736
256 objdump__add_line(&notes->src->source, objdump_line); 737 disasm__add(&notes->src->source, dl);
257 738
258 return 0; 739 return 0;
259} 740}
@@ -476,7 +957,7 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx)
476{ 957{
477 struct annotation *notes = symbol__annotation(sym); 958 struct annotation *notes = symbol__annotation(sym);
478 struct sym_hist *h = annotation__histogram(notes, evidx); 959 struct sym_hist *h = annotation__histogram(notes, evidx);
479 u64 len = sym->end - sym->start, offset; 960 u64 len = symbol__size(sym), offset;
480 961
481 for (offset = 0; offset < len; ++offset) 962 for (offset = 0; offset < len; ++offset)
482 if (h->addr[offset] != 0) 963 if (h->addr[offset] != 0)
@@ -492,7 +973,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
492 struct dso *dso = map->dso; 973 struct dso *dso = map->dso;
493 const char *filename = dso->long_name, *d_filename; 974 const char *filename = dso->long_name, *d_filename;
494 struct annotation *notes = symbol__annotation(sym); 975 struct annotation *notes = symbol__annotation(sym);
495 struct objdump_line *pos, *queue = NULL; 976 struct disasm_line *pos, *queue = NULL;
977 u64 start = map__rip_2objdump(map, sym->start);
496 int printed = 2, queue_len = 0; 978 int printed = 2, queue_len = 0;
497 int more = 0; 979 int more = 0;
498 u64 len; 980 u64 len;
@@ -502,7 +984,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
502 else 984 else
503 d_filename = basename(filename); 985 d_filename = basename(filename);
504 986
505 len = sym->end - sym->start; 987 len = symbol__size(sym);
506 988
507 printf(" Percent | Source code & Disassembly of %s\n", d_filename); 989 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
508 printf("------------------------------------------------\n"); 990 printf("------------------------------------------------\n");
@@ -516,8 +998,9 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
516 queue_len = 0; 998 queue_len = 0;
517 } 999 }
518 1000
519 switch (objdump_line__print(pos, sym, evidx, len, min_pcnt, 1001 switch (disasm_line__print(pos, sym, start, evidx, len,
520 printed, max_lines, queue)) { 1002 min_pcnt, printed, max_lines,
1003 queue)) {
521 case 0: 1004 case 0:
522 ++printed; 1005 ++printed;
523 if (context) { 1006 if (context) {
@@ -561,7 +1044,7 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
561{ 1044{
562 struct annotation *notes = symbol__annotation(sym); 1045 struct annotation *notes = symbol__annotation(sym);
563 struct sym_hist *h = annotation__histogram(notes, evidx); 1046 struct sym_hist *h = annotation__histogram(notes, evidx);
564 int len = sym->end - sym->start, offset; 1047 int len = symbol__size(sym), offset;
565 1048
566 h->sum = 0; 1049 h->sum = 0;
567 for (offset = 0; offset < len; ++offset) { 1050 for (offset = 0; offset < len; ++offset) {
@@ -570,14 +1053,42 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
570 } 1053 }
571} 1054}
572 1055
573void objdump_line_list__purge(struct list_head *head) 1056void disasm__purge(struct list_head *head)
574{ 1057{
575 struct objdump_line *pos, *n; 1058 struct disasm_line *pos, *n;
576 1059
577 list_for_each_entry_safe(pos, n, head, node) { 1060 list_for_each_entry_safe(pos, n, head, node) {
578 list_del(&pos->node); 1061 list_del(&pos->node);
579 objdump_line__free(pos); 1062 disasm_line__free(pos);
1063 }
1064}
1065
1066static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
1067{
1068 size_t printed;
1069
1070 if (dl->offset == -1)
1071 return fprintf(fp, "%s\n", dl->line);
1072
1073 printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name);
1074
1075 if (dl->ops.raw[0] != '\0') {
1076 printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
1077 dl->ops.raw);
580 } 1078 }
1079
1080 return printed + fprintf(fp, "\n");
1081}
1082
1083size_t disasm__fprintf(struct list_head *head, FILE *fp)
1084{
1085 struct disasm_line *pos;
1086 size_t printed = 0;
1087
1088 list_for_each_entry(pos, head, node)
1089 printed += disasm_line__fprintf(pos, fp);
1090
1091 return printed;
581} 1092}
582 1093
583int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 1094int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
@@ -592,7 +1103,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
592 if (symbol__annotate(sym, map, 0) < 0) 1103 if (symbol__annotate(sym, map, 0) < 0)
593 return -1; 1104 return -1;
594 1105
595 len = sym->end - sym->start; 1106 len = symbol__size(sym);
596 1107
597 if (print_lines) { 1108 if (print_lines) {
598 symbol__get_source_line(sym, map, evidx, &source_line, 1109 symbol__get_source_line(sym, map, evidx, &source_line,
@@ -605,7 +1116,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
605 if (print_lines) 1116 if (print_lines)
606 symbol__free_source_line(sym, len); 1117 symbol__free_source_line(sym, len);
607 1118
608 objdump_line_list__purge(&symbol__annotation(sym)->src->source); 1119 disasm__purge(&symbol__annotation(sym)->src->source);
609 1120
610 return 0; 1121 return 0;
611} 1122}
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index efa5dc82bfae..78a5692dd718 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -2,20 +2,69 @@
2#define __PERF_ANNOTATE_H 2#define __PERF_ANNOTATE_H
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include <stdint.h>
5#include "types.h" 6#include "types.h"
6#include "symbol.h" 7#include "symbol.h"
7#include <linux/list.h> 8#include <linux/list.h>
8#include <linux/rbtree.h> 9#include <linux/rbtree.h>
9 10
10struct objdump_line { 11struct ins;
11 struct list_head node; 12
12 s64 offset; 13struct ins_operands {
13 char *line; 14 char *raw;
15 struct {
16 char *raw;
17 char *name;
18 u64 addr;
19 u64 offset;
20 } target;
21 union {
22 struct {
23 char *raw;
24 char *name;
25 u64 addr;
26 } source;
27 struct {
28 struct ins *ins;
29 struct ins_operands *ops;
30 } locked;
31 };
14}; 32};
15 33
16void objdump_line__free(struct objdump_line *self); 34struct ins_ops {
17struct objdump_line *objdump__get_next_ip_line(struct list_head *head, 35 void (*free)(struct ins_operands *ops);
18 struct objdump_line *pos); 36 int (*parse)(struct ins_operands *ops);
37 int (*scnprintf)(struct ins *ins, char *bf, size_t size,
38 struct ins_operands *ops);
39};
40
41struct ins {
42 const char *name;
43 struct ins_ops *ops;
44};
45
46bool ins__is_jump(const struct ins *ins);
47bool ins__is_call(const struct ins *ins);
48int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops);
49
50struct disasm_line {
51 struct list_head node;
52 s64 offset;
53 char *line;
54 char *name;
55 struct ins *ins;
56 struct ins_operands ops;
57};
58
59static inline bool disasm_line__has_offset(const struct disasm_line *dl)
60{
61 return dl->ops.target.offset != UINT64_MAX;
62}
63
64void disasm_line__free(struct disasm_line *dl);
65struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos);
66int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw);
67size_t disasm__fprintf(struct list_head *head, FILE *fp);
19 68
20struct sym_hist { 69struct sym_hist {
21 u64 sum; 70 u64 sum;
@@ -32,7 +81,7 @@ struct source_line {
32 * 81 *
33 * @histogram: Array of addr hit histograms per event being monitored 82 * @histogram: Array of addr hit histograms per event being monitored
34 * @lines: If 'print_lines' is specified, per source code line percentages 83 * @lines: If 'print_lines' is specified, per source code line percentages
35 * @source: source parsed from objdump -dS 84 * @source: source parsed from a disassembler like objdump -dS
36 * 85 *
37 * lines is allocated, percentages calculated and all sorted by percentage 86 * lines is allocated, percentages calculated and all sorted by percentage
38 * when the annotation is about to be presented, so the percentages are for 87 * when the annotation is about to be presented, so the percentages are for
@@ -82,7 +131,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
82 int context); 131 int context);
83void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); 132void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
84void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); 133void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
85void objdump_line_list__purge(struct list_head *head); 134void disasm__purge(struct list_head *head);
86 135
87int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 136int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
88 bool print_lines, bool full_paths, int min_pcnt, 137 bool print_lines, bool full_paths, int min_pcnt,
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index dff9c7a725f4..fd9a5944b627 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -65,6 +65,8 @@ struct perf_tool build_id__mark_dso_hit_ops = {
65 .mmap = perf_event__process_mmap, 65 .mmap = perf_event__process_mmap,
66 .fork = perf_event__process_task, 66 .fork = perf_event__process_task,
67 .exit = perf_event__exit_del_thread, 67 .exit = perf_event__exit_del_thread,
68 .attr = perf_event__process_attr,
69 .build_id = perf_event__process_build_id,
68}; 70};
69 71
70char *dso__build_id_filename(struct dso *self, char *bf, size_t size) 72char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 8dd224df3e54..cff18c617d13 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -33,7 +33,7 @@ extern int pager_use_color;
33 33
34extern int use_browser; 34extern int use_browser;
35 35
36#ifdef NO_NEWT_SUPPORT 36#if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT)
37static inline void setup_browser(bool fallback_to_pager) 37static inline void setup_browser(bool fallback_to_pager)
38{ 38{
39 if (fallback_to_pager) 39 if (fallback_to_pager)
@@ -43,19 +43,29 @@ static inline void exit_browser(bool wait_for_ok __used) {}
43#else 43#else
44void setup_browser(bool fallback_to_pager); 44void setup_browser(bool fallback_to_pager);
45void exit_browser(bool wait_for_ok); 45void exit_browser(bool wait_for_ok);
46
47#ifdef NO_NEWT_SUPPORT
48static inline int ui__init(void)
49{
50 return -1;
51}
52static inline void ui__exit(bool wait_for_ok __used) {}
53#else
54int ui__init(void);
55void ui__exit(bool wait_for_ok);
46#endif 56#endif
47 57
48#ifdef NO_GTK2_SUPPORT 58#ifdef NO_GTK2_SUPPORT
49static inline void perf_gtk_setup_browser(int argc __used, const char *argv[] __used, bool fallback_to_pager) 59static inline int perf_gtk__init(void)
50{ 60{
51 if (fallback_to_pager) 61 return -1;
52 setup_pager();
53} 62}
54static inline void perf_gtk_exit_browser(bool wait_for_ok __used) {} 63static inline void perf_gtk__exit(bool wait_for_ok __used) {}
55#else 64#else
56void perf_gtk_setup_browser(int argc, const char *argv[], bool fallback_to_pager); 65int perf_gtk__init(void);
57void perf_gtk_exit_browser(bool wait_for_ok); 66void perf_gtk__exit(bool wait_for_ok);
58#endif 67#endif
68#endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */
59 69
60char *alias_lookup(const char *alias); 70char *alias_lookup(const char *alias);
61int split_cmdline(char *cmdline, const char ***argv); 71int split_cmdline(char *cmdline, const char ***argv);
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 0deac6a14b65..6faa3a18bfbd 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -120,7 +120,7 @@ static char *parse_value(void)
120 120
121static inline int iskeychar(int c) 121static inline int iskeychar(int c)
122{ 122{
123 return isalnum(c) || c == '-'; 123 return isalnum(c) || c == '-' || c == '_';
124} 124}
125 125
126static int get_value(config_fn_t fn, void *data, char *name, unsigned int len) 126static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 26817daa2961..efb1fce259a4 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -11,6 +11,7 @@
11#include "event.h" 11#include "event.h"
12#include "debug.h" 12#include "debug.h"
13#include "util.h" 13#include "util.h"
14#include "target.h"
14 15
15int verbose; 16int verbose;
16bool dump_trace = false, quiet = false; 17bool dump_trace = false, quiet = false;
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index f2ce88d04f54..6bebe7f0a20c 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -26,7 +26,7 @@ static inline void ui_progress__update(u64 curr __used, u64 total __used,
26#else 26#else
27extern char ui_helpline__last_msg[]; 27extern char ui_helpline__last_msg[];
28int ui_helpline__show_help(const char *format, va_list ap); 28int ui_helpline__show_help(const char *format, va_list ap);
29#include "ui/progress.h" 29#include "../ui/progress.h"
30int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); 30int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
31#endif 31#endif
32 32
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 1986d8051bd1..4ac5f5ae4ce9 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -11,6 +11,7 @@
11#include <poll.h> 11#include <poll.h>
12#include "cpumap.h" 12#include "cpumap.h"
13#include "thread_map.h" 13#include "thread_map.h"
14#include "target.h"
14#include "evlist.h" 15#include "evlist.h"
15#include "evsel.h" 16#include "evsel.h"
16#include <unistd.h> 17#include <unistd.h>
@@ -599,18 +600,21 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
599 return perf_evlist__mmap_per_cpu(evlist, prot, mask); 600 return perf_evlist__mmap_per_cpu(evlist, prot, mask);
600} 601}
601 602
602int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid, 603int perf_evlist__create_maps(struct perf_evlist *evlist,
603 const char *target_tid, uid_t uid, const char *cpu_list) 604 struct perf_target *target)
604{ 605{
605 evlist->threads = thread_map__new_str(target_pid, target_tid, uid); 606 evlist->threads = thread_map__new_str(target->pid, target->tid,
607 target->uid);
606 608
607 if (evlist->threads == NULL) 609 if (evlist->threads == NULL)
608 return -1; 610 return -1;
609 611
610 if (uid != UINT_MAX || (cpu_list == NULL && target_tid)) 612 if (perf_target__has_task(target))
613 evlist->cpus = cpu_map__dummy_new();
614 else if (!perf_target__has_cpu(target) && !target->uses_mmap)
611 evlist->cpus = cpu_map__dummy_new(); 615 evlist->cpus = cpu_map__dummy_new();
612 else 616 else
613 evlist->cpus = cpu_map__new(cpu_list); 617 evlist->cpus = cpu_map__new(target->cpu_list);
614 618
615 if (evlist->cpus == NULL) 619 if (evlist->cpus == NULL)
616 goto out_delete_threads; 620 goto out_delete_threads;
@@ -827,7 +831,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
827 exit(-1); 831 exit(-1);
828 } 832 }
829 833
830 if (!opts->system_wide && !opts->target_tid && !opts->target_pid) 834 if (perf_target__none(&opts->target))
831 evlist->threads->map[0] = evlist->workload.pid; 835 evlist->threads->map[0] = evlist->workload.pid;
832 836
833 close(child_ready_pipe[1]); 837 close(child_ready_pipe[1]);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 21f1c9e57f13..58abb63ac13a 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -106,8 +106,8 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
106 evlist->threads = threads; 106 evlist->threads = threads;
107} 107}
108 108
109int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid, 109int perf_evlist__create_maps(struct perf_evlist *evlist,
110 const char *tid, uid_t uid, const char *cpu_list); 110 struct perf_target *target);
111void perf_evlist__delete_maps(struct perf_evlist *evlist); 111void perf_evlist__delete_maps(struct perf_evlist *evlist);
112int perf_evlist__set_filters(struct perf_evlist *evlist); 112int perf_evlist__set_filters(struct perf_evlist *evlist);
113 113
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 8c13dbcb84b9..91d19138f3ec 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -14,6 +14,8 @@
14#include "util.h" 14#include "util.h"
15#include "cpumap.h" 15#include "cpumap.h"
16#include "thread_map.h" 16#include "thread_map.h"
17#include "target.h"
18#include "../../include/linux/perf_event.h"
17 19
18#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 20#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
19#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0)) 21#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
@@ -63,12 +65,102 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
63 return evsel; 65 return evsel;
64} 66}
65 67
68static const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = {
69 "cycles",
70 "instructions",
71 "cache-references",
72 "cache-misses",
73 "branches",
74 "branch-misses",
75 "bus-cycles",
76 "stalled-cycles-frontend",
77 "stalled-cycles-backend",
78 "ref-cycles",
79};
80
81const char *__perf_evsel__hw_name(u64 config)
82{
83 if (config < PERF_COUNT_HW_MAX && perf_evsel__hw_names[config])
84 return perf_evsel__hw_names[config];
85
86 return "unknown-hardware";
87}
88
89static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
90{
91 int colon = 0;
92 struct perf_event_attr *attr = &evsel->attr;
93 int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(attr->config));
94 bool exclude_guest_default = false;
95
96#define MOD_PRINT(context, mod) do { \
97 if (!attr->exclude_##context) { \
98 if (!colon) colon = r++; \
99 r += scnprintf(bf + r, size - r, "%c", mod); \
100 } } while(0)
101
102 if (attr->exclude_kernel || attr->exclude_user || attr->exclude_hv) {
103 MOD_PRINT(kernel, 'k');
104 MOD_PRINT(user, 'u');
105 MOD_PRINT(hv, 'h');
106 exclude_guest_default = true;
107 }
108
109 if (attr->precise_ip) {
110 if (!colon)
111 colon = r++;
112 r += scnprintf(bf + r, size - r, "%.*s", attr->precise_ip, "ppp");
113 exclude_guest_default = true;
114 }
115
116 if (attr->exclude_host || attr->exclude_guest == exclude_guest_default) {
117 MOD_PRINT(host, 'H');
118 MOD_PRINT(guest, 'G');
119 }
120#undef MOD_PRINT
121 if (colon)
122 bf[colon] = ':';
123 return r;
124}
125
126int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size)
127{
128 int ret;
129
130 switch (evsel->attr.type) {
131 case PERF_TYPE_RAW:
132 ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config);
133 break;
134
135 case PERF_TYPE_HARDWARE:
136 ret = perf_evsel__hw_name(evsel, bf, size);
137 break;
138 default:
139 /*
140 * FIXME
141 *
142 * This is the minimal perf_evsel__name so that we can
143 * reconstruct event names taking into account event modifiers.
144 *
145 * The old event_name uses it now for raw anr hw events, so that
146 * we don't drag all the parsing stuff into the python binding.
147 *
148 * On the next devel cycle the rest of the event naming will be
149 * brought here.
150 */
151 return 0;
152 }
153
154 return ret;
155}
156
66void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, 157void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
67 struct perf_evsel *first) 158 struct perf_evsel *first)
68{ 159{
69 struct perf_event_attr *attr = &evsel->attr; 160 struct perf_event_attr *attr = &evsel->attr;
70 int track = !evsel->idx; /* only the first counter needs these */ 161 int track = !evsel->idx; /* only the first counter needs these */
71 162
163 attr->disabled = 1;
72 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; 164 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
73 attr->inherit = !opts->no_inherit; 165 attr->inherit = !opts->no_inherit;
74 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 166 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
@@ -106,15 +198,15 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
106 if (opts->call_graph) 198 if (opts->call_graph)
107 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 199 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
108 200
109 if (opts->system_wide) 201 if (perf_target__has_cpu(&opts->target))
110 attr->sample_type |= PERF_SAMPLE_CPU; 202 attr->sample_type |= PERF_SAMPLE_CPU;
111 203
112 if (opts->period) 204 if (opts->period)
113 attr->sample_type |= PERF_SAMPLE_PERIOD; 205 attr->sample_type |= PERF_SAMPLE_PERIOD;
114 206
115 if (!opts->sample_id_all_missing && 207 if (!opts->sample_id_all_missing &&
116 (opts->sample_time || opts->system_wide || 208 (opts->sample_time || !opts->no_inherit ||
117 !opts->no_inherit || opts->cpu_list)) 209 perf_target__has_cpu(&opts->target)))
118 attr->sample_type |= PERF_SAMPLE_TIME; 210 attr->sample_type |= PERF_SAMPLE_TIME;
119 211
120 if (opts->raw_samples) { 212 if (opts->raw_samples) {
@@ -135,9 +227,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
135 attr->mmap = track; 227 attr->mmap = track;
136 attr->comm = track; 228 attr->comm = track;
137 229
138 if (!opts->target_pid && !opts->target_tid && !opts->system_wide && 230 if (perf_target__none(&opts->target) &&
139 (!opts->group || evsel == first)) { 231 (!opts->group || evsel == first)) {
140 attr->disabled = 1;
141 attr->enable_on_exec = 1; 232 attr->enable_on_exec = 1;
142 } 233 }
143} 234}
@@ -461,10 +552,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
461 * used for cross-endian analysis. See git commit 65014ab3 552 * used for cross-endian analysis. See git commit 65014ab3
462 * for why this goofiness is needed. 553 * for why this goofiness is needed.
463 */ 554 */
464 union { 555 union u64_swap u;
465 u64 val64;
466 u32 val32[2];
467 } u;
468 556
469 memset(data, 0, sizeof(*data)); 557 memset(data, 0, sizeof(*data));
470 data->cpu = data->pid = data->tid = -1; 558 data->cpu = data->pid = data->tid = -1;
@@ -607,10 +695,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
607 * used for cross-endian analysis. See git commit 65014ab3 695 * used for cross-endian analysis. See git commit 65014ab3
608 * for why this goofiness is needed. 696 * for why this goofiness is needed.
609 */ 697 */
610 union { 698 union u64_swap u;
611 u64 val64;
612 u32 val32[2];
613 } u;
614 699
615 array = event->sample.array; 700 array = event->sample.array;
616 701
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 3d6b3e4cb66b..4ba8b564e6f4 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -83,6 +83,9 @@ void perf_evsel__config(struct perf_evsel *evsel,
83 struct perf_record_opts *opts, 83 struct perf_record_opts *opts,
84 struct perf_evsel *first); 84 struct perf_evsel *first);
85 85
86const char* __perf_evsel__hw_name(u64 config);
87int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size);
88
86int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 89int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
87int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 90int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
88int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 91int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index c0b70c697a36..2dd5edf161b7 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -31,21 +31,16 @@ static const char **header_argv;
31 31
32int perf_header__push_event(u64 id, const char *name) 32int perf_header__push_event(u64 id, const char *name)
33{ 33{
34 struct perf_trace_event_type *nevents;
35
34 if (strlen(name) > MAX_EVENT_NAME) 36 if (strlen(name) > MAX_EVENT_NAME)
35 pr_warning("Event %s will be truncated\n", name); 37 pr_warning("Event %s will be truncated\n", name);
36 38
37 if (!events) { 39 nevents = realloc(events, (event_count + 1) * sizeof(*events));
38 events = malloc(sizeof(struct perf_trace_event_type)); 40 if (nevents == NULL)
39 if (events == NULL) 41 return -ENOMEM;
40 return -ENOMEM; 42 events = nevents;
41 } else {
42 struct perf_trace_event_type *nevents;
43 43
44 nevents = realloc(events, (event_count + 1) * sizeof(*events));
45 if (nevents == NULL)
46 return -ENOMEM;
47 events = nevents;
48 }
49 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); 44 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
50 events[event_count].event_id = id; 45 events[event_count].event_id = id;
51 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); 46 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
@@ -442,7 +437,7 @@ static bool perf_session__read_build_ids(struct perf_session *session, bool with
442 return ret; 437 return ret;
443} 438}
444 439
445static int write_trace_info(int fd, struct perf_header *h __used, 440static int write_tracing_data(int fd, struct perf_header *h __used,
446 struct perf_evlist *evlist) 441 struct perf_evlist *evlist)
447{ 442{
448 return read_tracing_data(fd, &evlist->entries); 443 return read_tracing_data(fd, &evlist->entries);
@@ -1477,7 +1472,7 @@ out:
1477 return err; 1472 return err;
1478} 1473}
1479 1474
1480static int process_trace_info(struct perf_file_section *section __unused, 1475static int process_tracing_data(struct perf_file_section *section __unused,
1481 struct perf_header *ph __unused, 1476 struct perf_header *ph __unused,
1482 int feat __unused, int fd) 1477 int feat __unused, int fd)
1483{ 1478{
@@ -1513,11 +1508,11 @@ struct feature_ops {
1513 .full_only = true } 1508 .full_only = true }
1514 1509
1515/* feature_ops not implemented: */ 1510/* feature_ops not implemented: */
1516#define print_trace_info NULL 1511#define print_tracing_data NULL
1517#define print_build_id NULL 1512#define print_build_id NULL
1518 1513
1519static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { 1514static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1520 FEAT_OPP(HEADER_TRACE_INFO, trace_info), 1515 FEAT_OPP(HEADER_TRACING_DATA, tracing_data),
1521 FEAT_OPP(HEADER_BUILD_ID, build_id), 1516 FEAT_OPP(HEADER_BUILD_ID, build_id),
1522 FEAT_OPA(HEADER_HOSTNAME, hostname), 1517 FEAT_OPA(HEADER_HOSTNAME, hostname),
1523 FEAT_OPA(HEADER_OSRELEASE, osrelease), 1518 FEAT_OPA(HEADER_OSRELEASE, osrelease),
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 21a6be09c129..2d42b3e1826f 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -12,7 +12,7 @@
12enum { 12enum {
13 HEADER_RESERVED = 0, /* always cleared */ 13 HEADER_RESERVED = 0, /* always cleared */
14 HEADER_FIRST_FEATURE = 1, 14 HEADER_FIRST_FEATURE = 1,
15 HEADER_TRACE_INFO = 1, 15 HEADER_TRACING_DATA = 1,
16 HEADER_BUILD_ID, 16 HEADER_BUILD_ID,
17 17
18 HEADER_HOSTNAME, 18 HEADER_HOSTNAME,
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 9f6d630d5316..1293b5ebea4d 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -599,7 +599,7 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
599 if (chain->ms.sym) 599 if (chain->ms.sym)
600 ret += fprintf(fp, "%s\n", chain->ms.sym->name); 600 ret += fprintf(fp, "%s\n", chain->ms.sym->name);
601 else 601 else
602 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip); 602 ret += fprintf(fp, "0x%0" PRIx64 "\n", chain->ip);
603 603
604 return ret; 604 return ret;
605} 605}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 2cae9df40e04..cfc64e293f90 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -138,7 +138,7 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
138#define K_LEFT -1 138#define K_LEFT -1
139#define K_RIGHT -2 139#define K_RIGHT -2
140#else 140#else
141#include "ui/keysyms.h" 141#include "../ui/keysyms.h"
142int hist_entry__tui_annotate(struct hist_entry *he, int evidx, 142int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
143 void(*timer)(void *arg), void *arg, int delay_secs); 143 void(*timer)(void *arg), void *arg, int delay_secs);
144 144
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c
new file mode 100644
index 000000000000..76b98e2a587d
--- /dev/null
+++ b/tools/perf/util/parse-events-test.c
@@ -0,0 +1,625 @@
1
2#include "parse-events.h"
3#include "evsel.h"
4#include "evlist.h"
5#include "sysfs.h"
6#include "../../../include/linux/hw_breakpoint.h"
7
8#define TEST_ASSERT_VAL(text, cond) \
9do { \
10 if (!(cond)) { \
11 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
12 return -1; \
13 } \
14} while (0)
15
16static int test__checkevent_tracepoint(struct perf_evlist *evlist)
17{
18 struct perf_evsel *evsel = list_entry(evlist->entries.next,
19 struct perf_evsel, node);
20
21 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
22 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
23 TEST_ASSERT_VAL("wrong sample_type",
24 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
25 evsel->attr.sample_type);
26 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
27 return 0;
28}
29
30static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
31{
32 struct perf_evsel *evsel;
33
34 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
35
36 list_for_each_entry(evsel, &evlist->entries, node) {
37 TEST_ASSERT_VAL("wrong type",
38 PERF_TYPE_TRACEPOINT == evsel->attr.type);
39 TEST_ASSERT_VAL("wrong sample_type",
40 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
41 == evsel->attr.sample_type);
42 TEST_ASSERT_VAL("wrong sample_period",
43 1 == evsel->attr.sample_period);
44 }
45 return 0;
46}
47
48static int test__checkevent_raw(struct perf_evlist *evlist)
49{
50 struct perf_evsel *evsel = list_entry(evlist->entries.next,
51 struct perf_evsel, node);
52
53 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
54 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
55 TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config);
56 return 0;
57}
58
59static int test__checkevent_numeric(struct perf_evlist *evlist)
60{
61 struct perf_evsel *evsel = list_entry(evlist->entries.next,
62 struct perf_evsel, node);
63
64 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
65 TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
66 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
67 return 0;
68}
69
70static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
71{
72 struct perf_evsel *evsel = list_entry(evlist->entries.next,
73 struct perf_evsel, node);
74
75 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
76 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
77 TEST_ASSERT_VAL("wrong config",
78 PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
79 return 0;
80}
81
82static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist)
83{
84 struct perf_evsel *evsel = list_entry(evlist->entries.next,
85 struct perf_evsel, node);
86
87 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
88 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
89 TEST_ASSERT_VAL("wrong config",
90 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
91 TEST_ASSERT_VAL("wrong period",
92 100000 == evsel->attr.sample_period);
93 TEST_ASSERT_VAL("wrong config1",
94 0 == evsel->attr.config1);
95 TEST_ASSERT_VAL("wrong config2",
96 1 == evsel->attr.config2);
97 return 0;
98}
99
100static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
101{
102 struct perf_evsel *evsel = list_entry(evlist->entries.next,
103 struct perf_evsel, node);
104
105 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
106 TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
107 TEST_ASSERT_VAL("wrong config",
108 PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
109 return 0;
110}
111
112static int test__checkevent_genhw(struct perf_evlist *evlist)
113{
114 struct perf_evsel *evsel = list_entry(evlist->entries.next,
115 struct perf_evsel, node);
116
117 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
118 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
119 TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config);
120 return 0;
121}
122
123static int test__checkevent_breakpoint(struct perf_evlist *evlist)
124{
125 struct perf_evsel *evsel = list_entry(evlist->entries.next,
126 struct perf_evsel, node);
127
128 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
129 TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
130 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
131 TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
132 evsel->attr.bp_type);
133 TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
134 evsel->attr.bp_len);
135 return 0;
136}
137
138static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
139{
140 struct perf_evsel *evsel = list_entry(evlist->entries.next,
141 struct perf_evsel, node);
142
143 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
144 TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
145 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
146 TEST_ASSERT_VAL("wrong bp_type",
147 HW_BREAKPOINT_X == evsel->attr.bp_type);
148 TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len);
149 return 0;
150}
151
152static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
153{
154 struct perf_evsel *evsel = list_entry(evlist->entries.next,
155 struct perf_evsel, node);
156
157 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
158 TEST_ASSERT_VAL("wrong type",
159 PERF_TYPE_BREAKPOINT == evsel->attr.type);
160 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
161 TEST_ASSERT_VAL("wrong bp_type",
162 HW_BREAKPOINT_R == evsel->attr.bp_type);
163 TEST_ASSERT_VAL("wrong bp_len",
164 HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
165 return 0;
166}
167
168static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
169{
170 struct perf_evsel *evsel = list_entry(evlist->entries.next,
171 struct perf_evsel, node);
172
173 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
174 TEST_ASSERT_VAL("wrong type",
175 PERF_TYPE_BREAKPOINT == evsel->attr.type);
176 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
177 TEST_ASSERT_VAL("wrong bp_type",
178 HW_BREAKPOINT_W == evsel->attr.bp_type);
179 TEST_ASSERT_VAL("wrong bp_len",
180 HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
181 return 0;
182}
183
184static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist)
185{
186 struct perf_evsel *evsel = list_entry(evlist->entries.next,
187 struct perf_evsel, node);
188
189 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
190 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
191 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
192 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
193
194 return test__checkevent_tracepoint(evlist);
195}
196
197static int
198test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist)
199{
200 struct perf_evsel *evsel;
201
202 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
203
204 list_for_each_entry(evsel, &evlist->entries, node) {
205 TEST_ASSERT_VAL("wrong exclude_user",
206 !evsel->attr.exclude_user);
207 TEST_ASSERT_VAL("wrong exclude_kernel",
208 evsel->attr.exclude_kernel);
209 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
210 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
211 }
212
213 return test__checkevent_tracepoint_multi(evlist);
214}
215
216static int test__checkevent_raw_modifier(struct perf_evlist *evlist)
217{
218 struct perf_evsel *evsel = list_entry(evlist->entries.next,
219 struct perf_evsel, node);
220
221 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
222 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
223 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
224 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
225
226 return test__checkevent_raw(evlist);
227}
228
229static int test__checkevent_numeric_modifier(struct perf_evlist *evlist)
230{
231 struct perf_evsel *evsel = list_entry(evlist->entries.next,
232 struct perf_evsel, node);
233
234 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
235 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
236 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
237 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
238
239 return test__checkevent_numeric(evlist);
240}
241
242static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist)
243{
244 struct perf_evsel *evsel = list_entry(evlist->entries.next,
245 struct perf_evsel, node);
246
247 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
248 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
249 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
250 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
251
252 return test__checkevent_symbolic_name(evlist);
253}
254
255static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist)
256{
257 struct perf_evsel *evsel = list_entry(evlist->entries.next,
258 struct perf_evsel, node);
259
260 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
261 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
262
263 return test__checkevent_symbolic_name(evlist);
264}
265
266static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist)
267{
268 struct perf_evsel *evsel = list_entry(evlist->entries.next,
269 struct perf_evsel, node);
270
271 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
272 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
273
274 return test__checkevent_symbolic_name(evlist);
275}
276
277static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist)
278{
279 struct perf_evsel *evsel = list_entry(evlist->entries.next,
280 struct perf_evsel, node);
281
282 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
283 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
284 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
285 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
286
287 return test__checkevent_symbolic_alias(evlist);
288}
289
290static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
291{
292 struct perf_evsel *evsel = list_entry(evlist->entries.next,
293 struct perf_evsel, node);
294
295 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
296 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
297 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
298 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
299
300 return test__checkevent_genhw(evlist);
301}
302
303static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
304{
305 struct perf_evsel *evsel = list_entry(evlist->entries.next,
306 struct perf_evsel, node);
307
308 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
309 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
310 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
311 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
312
313 return test__checkevent_breakpoint(evlist);
314}
315
316static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
317{
318 struct perf_evsel *evsel = list_entry(evlist->entries.next,
319 struct perf_evsel, node);
320
321 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
322 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
323 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
324 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
325
326 return test__checkevent_breakpoint_x(evlist);
327}
328
329static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
330{
331 struct perf_evsel *evsel = list_entry(evlist->entries.next,
332 struct perf_evsel, node);
333
334 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
335 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
336 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
337 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
338
339 return test__checkevent_breakpoint_r(evlist);
340}
341
342static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
343{
344 struct perf_evsel *evsel = list_entry(evlist->entries.next,
345 struct perf_evsel, node);
346
347 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
348 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
349 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
350 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
351
352 return test__checkevent_breakpoint_w(evlist);
353}
354
355static int test__checkevent_pmu(struct perf_evlist *evlist)
356{
357
358 struct perf_evsel *evsel = list_entry(evlist->entries.next,
359 struct perf_evsel, node);
360
361 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
362 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
363 TEST_ASSERT_VAL("wrong config", 10 == evsel->attr.config);
364 TEST_ASSERT_VAL("wrong config1", 1 == evsel->attr.config1);
365 TEST_ASSERT_VAL("wrong config2", 3 == evsel->attr.config2);
366 TEST_ASSERT_VAL("wrong period", 1000 == evsel->attr.sample_period);
367
368 return 0;
369}
370
371static int test__checkevent_list(struct perf_evlist *evlist)
372{
373 struct perf_evsel *evsel;
374
375 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
376
377 /* r1 */
378 evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
379 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
380 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
381 TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
382 TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2);
383 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
384 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
385 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
386 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
387
388 /* syscalls:sys_enter_open:k */
389 evsel = list_entry(evsel->node.next, struct perf_evsel, node);
390 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
391 TEST_ASSERT_VAL("wrong sample_type",
392 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
393 evsel->attr.sample_type);
394 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
395 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
396 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
397 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
398 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
399
400 /* 1:1:hp */
401 evsel = list_entry(evsel->node.next, struct perf_evsel, node);
402 TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
403 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
404 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
405 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
406 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
407 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
408
409 return 0;
410}
411
412static int test__checkevent_pmu_name(struct perf_evlist *evlist)
413{
414 struct perf_evsel *evsel;
415
416 /* cpu/config=1,name=krava1/u */
417 evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
418 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
419 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
420 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
421 TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "krava"));
422
423 /* cpu/config=2/" */
424 evsel = list_entry(evsel->node.next, struct perf_evsel, node);
425 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
426 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
427 TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config);
428 TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "raw 0x2"));
429
430 return 0;
431}
432
433struct test__event_st {
434 const char *name;
435 __u32 type;
436 int (*check)(struct perf_evlist *evlist);
437};
438
439static struct test__event_st test__events[] = {
440 [0] = {
441 .name = "syscalls:sys_enter_open",
442 .check = test__checkevent_tracepoint,
443 },
444 [1] = {
445 .name = "syscalls:*",
446 .check = test__checkevent_tracepoint_multi,
447 },
448 [2] = {
449 .name = "r1a",
450 .check = test__checkevent_raw,
451 },
452 [3] = {
453 .name = "1:1",
454 .check = test__checkevent_numeric,
455 },
456 [4] = {
457 .name = "instructions",
458 .check = test__checkevent_symbolic_name,
459 },
460 [5] = {
461 .name = "cycles/period=100000,config2/",
462 .check = test__checkevent_symbolic_name_config,
463 },
464 [6] = {
465 .name = "faults",
466 .check = test__checkevent_symbolic_alias,
467 },
468 [7] = {
469 .name = "L1-dcache-load-miss",
470 .check = test__checkevent_genhw,
471 },
472 [8] = {
473 .name = "mem:0",
474 .check = test__checkevent_breakpoint,
475 },
476 [9] = {
477 .name = "mem:0:x",
478 .check = test__checkevent_breakpoint_x,
479 },
480 [10] = {
481 .name = "mem:0:r",
482 .check = test__checkevent_breakpoint_r,
483 },
484 [11] = {
485 .name = "mem:0:w",
486 .check = test__checkevent_breakpoint_w,
487 },
488 [12] = {
489 .name = "syscalls:sys_enter_open:k",
490 .check = test__checkevent_tracepoint_modifier,
491 },
492 [13] = {
493 .name = "syscalls:*:u",
494 .check = test__checkevent_tracepoint_multi_modifier,
495 },
496 [14] = {
497 .name = "r1a:kp",
498 .check = test__checkevent_raw_modifier,
499 },
500 [15] = {
501 .name = "1:1:hp",
502 .check = test__checkevent_numeric_modifier,
503 },
504 [16] = {
505 .name = "instructions:h",
506 .check = test__checkevent_symbolic_name_modifier,
507 },
508 [17] = {
509 .name = "faults:u",
510 .check = test__checkevent_symbolic_alias_modifier,
511 },
512 [18] = {
513 .name = "L1-dcache-load-miss:kp",
514 .check = test__checkevent_genhw_modifier,
515 },
516 [19] = {
517 .name = "mem:0:u",
518 .check = test__checkevent_breakpoint_modifier,
519 },
520 [20] = {
521 .name = "mem:0:x:k",
522 .check = test__checkevent_breakpoint_x_modifier,
523 },
524 [21] = {
525 .name = "mem:0:r:hp",
526 .check = test__checkevent_breakpoint_r_modifier,
527 },
528 [22] = {
529 .name = "mem:0:w:up",
530 .check = test__checkevent_breakpoint_w_modifier,
531 },
532 [23] = {
533 .name = "r1,syscalls:sys_enter_open:k,1:1:hp",
534 .check = test__checkevent_list,
535 },
536 [24] = {
537 .name = "instructions:G",
538 .check = test__checkevent_exclude_host_modifier,
539 },
540 [25] = {
541 .name = "instructions:H",
542 .check = test__checkevent_exclude_guest_modifier,
543 },
544};
545
546#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
547
548static struct test__event_st test__events_pmu[] = {
549 [0] = {
550 .name = "cpu/config=10,config1,config2=3,period=1000/u",
551 .check = test__checkevent_pmu,
552 },
553 [1] = {
554 .name = "cpu/config=1,name=krava/u,cpu/config=2/u",
555 .check = test__checkevent_pmu_name,
556 },
557};
558
559#define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \
560 sizeof(struct test__event_st))
561
562static int test(struct test__event_st *e)
563{
564 struct perf_evlist *evlist;
565 int ret;
566
567 evlist = perf_evlist__new(NULL, NULL);
568 if (evlist == NULL)
569 return -ENOMEM;
570
571 ret = parse_events(evlist, e->name, 0);
572 if (ret) {
573 pr_debug("failed to parse event '%s', err %d\n",
574 e->name, ret);
575 return ret;
576 }
577
578 ret = e->check(evlist);
579 perf_evlist__delete(evlist);
580
581 return ret;
582}
583
584static int test_events(struct test__event_st *events, unsigned cnt)
585{
586 int ret = 0;
587 unsigned i;
588
589 for (i = 0; i < cnt; i++) {
590 struct test__event_st *e = &events[i];
591
592 pr_debug("running test %d '%s'\n", i, e->name);
593 ret = test(e);
594 if (ret)
595 break;
596 }
597
598 return ret;
599}
600
601static int test_pmu(void)
602{
603 struct stat st;
604 char path[PATH_MAX];
605 int ret;
606
607 snprintf(path, PATH_MAX, "%s/bus/event_source/devices/cpu/format/",
608 sysfs_find_mountpoint());
609
610 ret = stat(path, &st);
611 if (ret)
612 pr_debug("ommiting PMU cpu tests\n");
613 return !ret;
614}
615
616int parse_events__test(void)
617{
618 int ret;
619
620 ret = test_events(test__events, TEST__EVENTS_CNT);
621 if (!ret && test_pmu())
622 ret = test_events(test__events_pmu, TEST__EVENTS_PMU_CNT);
623
624 return ret;
625}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 5b3a0ef4e232..05dbc8b3c767 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -23,8 +23,10 @@ struct event_symbol {
23 const char *alias; 23 const char *alias;
24}; 24};
25 25
26int parse_events_parse(struct list_head *list, struct list_head *list_tmp, 26#ifdef PARSER_DEBUG
27 int *idx); 27extern int parse_events_debug;
28#endif
29int parse_events_parse(struct list_head *list, int *idx);
28 30
29#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x 31#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
30#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x 32#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -60,19 +62,6 @@ static struct event_symbol event_symbols[] = {
60#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) 62#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE)
61#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) 63#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT)
62 64
63static const char *hw_event_names[PERF_COUNT_HW_MAX] = {
64 "cycles",
65 "instructions",
66 "cache-references",
67 "cache-misses",
68 "branches",
69 "branch-misses",
70 "bus-cycles",
71 "stalled-cycles-frontend",
72 "stalled-cycles-backend",
73 "ref-cycles",
74};
75
76static const char *sw_event_names[PERF_COUNT_SW_MAX] = { 65static const char *sw_event_names[PERF_COUNT_SW_MAX] = {
77 "cpu-clock", 66 "cpu-clock",
78 "task-clock", 67 "task-clock",
@@ -298,6 +287,16 @@ const char *event_name(struct perf_evsel *evsel)
298 u64 config = evsel->attr.config; 287 u64 config = evsel->attr.config;
299 int type = evsel->attr.type; 288 int type = evsel->attr.type;
300 289
290 if (type == PERF_TYPE_RAW || type == PERF_TYPE_HARDWARE) {
291 /*
292 * XXX minimal fix, see comment on perf_evsen__name, this static buffer
293 * will go away together with event_name in the next devel cycle.
294 */
295 static char bf[128];
296 perf_evsel__name(evsel, bf, sizeof(bf));
297 return bf;
298 }
299
301 if (evsel->name) 300 if (evsel->name)
302 return evsel->name; 301 return evsel->name;
303 302
@@ -315,9 +314,7 @@ const char *__event_name(int type, u64 config)
315 314
316 switch (type) { 315 switch (type) {
317 case PERF_TYPE_HARDWARE: 316 case PERF_TYPE_HARDWARE:
318 if (config < PERF_COUNT_HW_MAX && hw_event_names[config]) 317 return __perf_evsel__hw_name(config);
319 return hw_event_names[config];
320 return "unknown-hardware";
321 318
322 case PERF_TYPE_HW_CACHE: { 319 case PERF_TYPE_HW_CACHE: {
323 u8 cache_type, cache_op, cache_result; 320 u8 cache_type, cache_op, cache_result;
@@ -355,20 +352,30 @@ const char *__event_name(int type, u64 config)
355 return "unknown"; 352 return "unknown";
356} 353}
357 354
358static int add_event(struct list_head *list, int *idx, 355static int add_event(struct list_head **_list, int *idx,
359 struct perf_event_attr *attr, char *name) 356 struct perf_event_attr *attr, char *name)
360{ 357{
361 struct perf_evsel *evsel; 358 struct perf_evsel *evsel;
359 struct list_head *list = *_list;
360
361 if (!list) {
362 list = malloc(sizeof(*list));
363 if (!list)
364 return -ENOMEM;
365 INIT_LIST_HEAD(list);
366 }
362 367
363 event_attr_init(attr); 368 event_attr_init(attr);
364 369
365 evsel = perf_evsel__new(attr, (*idx)++); 370 evsel = perf_evsel__new(attr, (*idx)++);
366 if (!evsel) 371 if (!evsel) {
372 free(list);
367 return -ENOMEM; 373 return -ENOMEM;
368 374 }
369 list_add_tail(&evsel->node, list);
370 375
371 evsel->name = strdup(name); 376 evsel->name = strdup(name);
377 list_add_tail(&evsel->node, list);
378 *_list = list;
372 return 0; 379 return 0;
373} 380}
374 381
@@ -390,7 +397,7 @@ static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
390 return -1; 397 return -1;
391} 398}
392 399
393int parse_events_add_cache(struct list_head *list, int *idx, 400int parse_events_add_cache(struct list_head **list, int *idx,
394 char *type, char *op_result1, char *op_result2) 401 char *type, char *op_result1, char *op_result2)
395{ 402{
396 struct perf_event_attr attr; 403 struct perf_event_attr attr;
@@ -451,7 +458,7 @@ int parse_events_add_cache(struct list_head *list, int *idx,
451 return add_event(list, idx, &attr, name); 458 return add_event(list, idx, &attr, name);
452} 459}
453 460
454static int add_tracepoint(struct list_head *list, int *idx, 461static int add_tracepoint(struct list_head **list, int *idx,
455 char *sys_name, char *evt_name) 462 char *sys_name, char *evt_name)
456{ 463{
457 struct perf_event_attr attr; 464 struct perf_event_attr attr;
@@ -488,7 +495,7 @@ static int add_tracepoint(struct list_head *list, int *idx,
488 return add_event(list, idx, &attr, name); 495 return add_event(list, idx, &attr, name);
489} 496}
490 497
491static int add_tracepoint_multi(struct list_head *list, int *idx, 498static int add_tracepoint_multi(struct list_head **list, int *idx,
492 char *sys_name, char *evt_name) 499 char *sys_name, char *evt_name)
493{ 500{
494 char evt_path[MAXPATHLEN]; 501 char evt_path[MAXPATHLEN];
@@ -519,7 +526,7 @@ static int add_tracepoint_multi(struct list_head *list, int *idx,
519 return ret; 526 return ret;
520} 527}
521 528
522int parse_events_add_tracepoint(struct list_head *list, int *idx, 529int parse_events_add_tracepoint(struct list_head **list, int *idx,
523 char *sys, char *event) 530 char *sys, char *event)
524{ 531{
525 int ret; 532 int ret;
@@ -563,7 +570,7 @@ parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
563 return 0; 570 return 0;
564} 571}
565 572
566int parse_events_add_breakpoint(struct list_head *list, int *idx, 573int parse_events_add_breakpoint(struct list_head **list, int *idx,
567 void *ptr, char *type) 574 void *ptr, char *type)
568{ 575{
569 struct perf_event_attr attr; 576 struct perf_event_attr attr;
@@ -593,17 +600,27 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
593static int config_term(struct perf_event_attr *attr, 600static int config_term(struct perf_event_attr *attr,
594 struct parse_events__term *term) 601 struct parse_events__term *term)
595{ 602{
596 switch (term->type) { 603#define CHECK_TYPE_VAL(type) \
604do { \
605 if (PARSE_EVENTS__TERM_TYPE_ ## type != term->type_val) \
606 return -EINVAL; \
607} while (0)
608
609 switch (term->type_term) {
597 case PARSE_EVENTS__TERM_TYPE_CONFIG: 610 case PARSE_EVENTS__TERM_TYPE_CONFIG:
611 CHECK_TYPE_VAL(NUM);
598 attr->config = term->val.num; 612 attr->config = term->val.num;
599 break; 613 break;
600 case PARSE_EVENTS__TERM_TYPE_CONFIG1: 614 case PARSE_EVENTS__TERM_TYPE_CONFIG1:
615 CHECK_TYPE_VAL(NUM);
601 attr->config1 = term->val.num; 616 attr->config1 = term->val.num;
602 break; 617 break;
603 case PARSE_EVENTS__TERM_TYPE_CONFIG2: 618 case PARSE_EVENTS__TERM_TYPE_CONFIG2:
619 CHECK_TYPE_VAL(NUM);
604 attr->config2 = term->val.num; 620 attr->config2 = term->val.num;
605 break; 621 break;
606 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: 622 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
623 CHECK_TYPE_VAL(NUM);
607 attr->sample_period = term->val.num; 624 attr->sample_period = term->val.num;
608 break; 625 break;
609 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: 626 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
@@ -612,10 +629,15 @@ static int config_term(struct perf_event_attr *attr,
612 * attr->branch_sample_type = term->val.num; 629 * attr->branch_sample_type = term->val.num;
613 */ 630 */
614 break; 631 break;
632 case PARSE_EVENTS__TERM_TYPE_NAME:
633 CHECK_TYPE_VAL(STR);
634 break;
615 default: 635 default:
616 return -EINVAL; 636 return -EINVAL;
617 } 637 }
638
618 return 0; 639 return 0;
640#undef CHECK_TYPE_VAL
619} 641}
620 642
621static int config_attr(struct perf_event_attr *attr, 643static int config_attr(struct perf_event_attr *attr,
@@ -630,7 +652,7 @@ static int config_attr(struct perf_event_attr *attr,
630 return 0; 652 return 0;
631} 653}
632 654
633int parse_events_add_numeric(struct list_head *list, int *idx, 655int parse_events_add_numeric(struct list_head **list, int *idx,
634 unsigned long type, unsigned long config, 656 unsigned long type, unsigned long config,
635 struct list_head *head_config) 657 struct list_head *head_config)
636{ 658{
@@ -648,7 +670,24 @@ int parse_events_add_numeric(struct list_head *list, int *idx,
648 (char *) __event_name(type, config)); 670 (char *) __event_name(type, config));
649} 671}
650 672
651int parse_events_add_pmu(struct list_head *list, int *idx, 673static int parse_events__is_name_term(struct parse_events__term *term)
674{
675 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
676}
677
678static char *pmu_event_name(struct perf_event_attr *attr,
679 struct list_head *head_terms)
680{
681 struct parse_events__term *term;
682
683 list_for_each_entry(term, head_terms, list)
684 if (parse_events__is_name_term(term))
685 return term->val.str;
686
687 return (char *) __event_name(PERF_TYPE_RAW, attr->config);
688}
689
690int parse_events_add_pmu(struct list_head **list, int *idx,
652 char *name, struct list_head *head_config) 691 char *name, struct list_head *head_config)
653{ 692{
654 struct perf_event_attr attr; 693 struct perf_event_attr attr;
@@ -669,7 +708,8 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
669 if (perf_pmu__config(pmu, &attr, head_config)) 708 if (perf_pmu__config(pmu, &attr, head_config))
670 return -EINVAL; 709 return -EINVAL;
671 710
672 return add_event(list, idx, &attr, (char *) "pmu"); 711 return add_event(list, idx, &attr,
712 pmu_event_name(&attr, head_config));
673} 713}
674 714
675void parse_events_update_lists(struct list_head *list_event, 715void parse_events_update_lists(struct list_head *list_event,
@@ -681,7 +721,7 @@ void parse_events_update_lists(struct list_head *list_event,
681 * list, for next event definition. 721 * list, for next event definition.
682 */ 722 */
683 list_splice_tail(list_event, list_all); 723 list_splice_tail(list_event, list_all);
684 INIT_LIST_HEAD(list_event); 724 free(list_event);
685} 725}
686 726
687int parse_events_modifier(struct list_head *list, char *str) 727int parse_events_modifier(struct list_head *list, char *str)
@@ -756,10 +796,14 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
756 796
757 buffer = parse_events__scan_string(str); 797 buffer = parse_events__scan_string(str);
758 798
759 ret = parse_events_parse(&list, &list_tmp, &idx); 799#ifdef PARSER_DEBUG
800 parse_events_debug = 1;
801#endif
802 ret = parse_events_parse(&list, &idx);
760 803
761 parse_events__flush_buffer(buffer); 804 parse_events__flush_buffer(buffer);
762 parse_events__delete_buffer(buffer); 805 parse_events__delete_buffer(buffer);
806 parse_events_lex_destroy();
763 807
764 if (!ret) { 808 if (!ret) {
765 int entries = idx - evlist->nr_entries; 809 int entries = idx - evlist->nr_entries;
@@ -1015,11 +1059,12 @@ void print_events(const char *event_glob)
1015 1059
1016int parse_events__is_hardcoded_term(struct parse_events__term *term) 1060int parse_events__is_hardcoded_term(struct parse_events__term *term)
1017{ 1061{
1018 return term->type <= PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX; 1062 return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
1019} 1063}
1020 1064
1021int parse_events__new_term(struct parse_events__term **_term, int type, 1065static int new_term(struct parse_events__term **_term, int type_val,
1022 char *config, char *str, long num) 1066 int type_term, char *config,
1067 char *str, long num)
1023{ 1068{
1024 struct parse_events__term *term; 1069 struct parse_events__term *term;
1025 1070
@@ -1028,15 +1073,11 @@ int parse_events__new_term(struct parse_events__term **_term, int type,
1028 return -ENOMEM; 1073 return -ENOMEM;
1029 1074
1030 INIT_LIST_HEAD(&term->list); 1075 INIT_LIST_HEAD(&term->list);
1031 term->type = type; 1076 term->type_val = type_val;
1077 term->type_term = type_term;
1032 term->config = config; 1078 term->config = config;
1033 1079
1034 switch (type) { 1080 switch (type_val) {
1035 case PARSE_EVENTS__TERM_TYPE_CONFIG:
1036 case PARSE_EVENTS__TERM_TYPE_CONFIG1:
1037 case PARSE_EVENTS__TERM_TYPE_CONFIG2:
1038 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
1039 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
1040 case PARSE_EVENTS__TERM_TYPE_NUM: 1081 case PARSE_EVENTS__TERM_TYPE_NUM:
1041 term->val.num = num; 1082 term->val.num = num;
1042 break; 1083 break;
@@ -1051,6 +1092,20 @@ int parse_events__new_term(struct parse_events__term **_term, int type,
1051 return 0; 1092 return 0;
1052} 1093}
1053 1094
1095int parse_events__term_num(struct parse_events__term **term,
1096 int type_term, char *config, long num)
1097{
1098 return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term,
1099 config, NULL, num);
1100}
1101
1102int parse_events__term_str(struct parse_events__term **term,
1103 int type_term, char *config, char *str)
1104{
1105 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term,
1106 config, str, 0);
1107}
1108
1054void parse_events__free_terms(struct list_head *terms) 1109void parse_events__free_terms(struct list_head *terms)
1055{ 1110{
1056 struct parse_events__term *term, *h; 1111 struct parse_events__term *term, *h;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index ca069f893381..8cac57ab4ee6 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -4,7 +4,11 @@
4 * Parse symbolic events/counts passed in as options: 4 * Parse symbolic events/counts passed in as options:
5 */ 5 */
6 6
7#include <linux/list.h>
8#include <stdbool.h>
9#include "types.h"
7#include "../../../include/linux/perf_event.h" 10#include "../../../include/linux/perf_event.h"
11#include "types.h"
8 12
9struct list_head; 13struct list_head;
10struct perf_evsel; 14struct perf_evsel;
@@ -34,16 +38,18 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
34#define EVENTS_HELP_MAX (128*1024) 38#define EVENTS_HELP_MAX (128*1024)
35 39
36enum { 40enum {
41 PARSE_EVENTS__TERM_TYPE_NUM,
42 PARSE_EVENTS__TERM_TYPE_STR,
43};
44
45enum {
46 PARSE_EVENTS__TERM_TYPE_USER,
37 PARSE_EVENTS__TERM_TYPE_CONFIG, 47 PARSE_EVENTS__TERM_TYPE_CONFIG,
38 PARSE_EVENTS__TERM_TYPE_CONFIG1, 48 PARSE_EVENTS__TERM_TYPE_CONFIG1,
39 PARSE_EVENTS__TERM_TYPE_CONFIG2, 49 PARSE_EVENTS__TERM_TYPE_CONFIG2,
50 PARSE_EVENTS__TERM_TYPE_NAME,
40 PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD, 51 PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
41 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, 52 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
42 PARSE_EVENTS__TERM_TYPE_NUM,
43 PARSE_EVENTS__TERM_TYPE_STR,
44
45 PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX =
46 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
47}; 53};
48 54
49struct parse_events__term { 55struct parse_events__term {
@@ -52,35 +58,34 @@ struct parse_events__term {
52 char *str; 58 char *str;
53 long num; 59 long num;
54 } val; 60 } val;
55 int type; 61 int type_val;
56 62 int type_term;
57 struct list_head list; 63 struct list_head list;
58}; 64};
59 65
60int parse_events__is_hardcoded_term(struct parse_events__term *term); 66int parse_events__is_hardcoded_term(struct parse_events__term *term);
61int parse_events__new_term(struct parse_events__term **term, int type, 67int parse_events__term_num(struct parse_events__term **_term,
62 char *config, char *str, long num); 68 int type_term, char *config, long num);
69int parse_events__term_str(struct parse_events__term **_term,
70 int type_term, char *config, char *str);
63void parse_events__free_terms(struct list_head *terms); 71void parse_events__free_terms(struct list_head *terms);
64int parse_events_modifier(struct list_head *list __used, char *str __used); 72int parse_events_modifier(struct list_head *list, char *str);
65int parse_events_add_tracepoint(struct list_head *list, int *idx, 73int parse_events_add_tracepoint(struct list_head **list, int *idx,
66 char *sys, char *event); 74 char *sys, char *event);
67int parse_events_add_raw(struct perf_evlist *evlist, unsigned long config, 75int parse_events_add_numeric(struct list_head **list, int *idx,
68 unsigned long config1, unsigned long config2,
69 char *mod);
70int parse_events_add_numeric(struct list_head *list, int *idx,
71 unsigned long type, unsigned long config, 76 unsigned long type, unsigned long config,
72 struct list_head *head_config); 77 struct list_head *head_config);
73int parse_events_add_cache(struct list_head *list, int *idx, 78int parse_events_add_cache(struct list_head **list, int *idx,
74 char *type, char *op_result1, char *op_result2); 79 char *type, char *op_result1, char *op_result2);
75int parse_events_add_breakpoint(struct list_head *list, int *idx, 80int parse_events_add_breakpoint(struct list_head **list, int *idx,
76 void *ptr, char *type); 81 void *ptr, char *type);
77int parse_events_add_pmu(struct list_head *list, int *idx, 82int parse_events_add_pmu(struct list_head **list, int *idx,
78 char *pmu , struct list_head *head_config); 83 char *pmu , struct list_head *head_config);
79void parse_events_update_lists(struct list_head *list_event, 84void parse_events_update_lists(struct list_head *list_event,
80 struct list_head *list_all); 85 struct list_head *list_all);
81void parse_events_error(struct list_head *list_all, 86void parse_events_error(struct list_head *list_all,
82 struct list_head *list_event,
83 int *idx, char const *msg); 87 int *idx, char const *msg);
88int parse_events__test(void);
84 89
85void print_events(const char *event_glob); 90void print_events(const char *event_glob);
86void print_events_type(u8 type); 91void print_events_type(u8 type);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 1fcf1bbc5458..618a8e788399 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -1,5 +1,6 @@
1 1
2%option prefix="parse_events_" 2%option prefix="parse_events_"
3%option stack
3 4
4%{ 5%{
5#include <errno.h> 6#include <errno.h>
@@ -50,6 +51,8 @@ static int term(int type)
50 51
51%} 52%}
52 53
54%x mem
55
53num_dec [0-9]+ 56num_dec [0-9]+
54num_hex 0x[a-fA-F0-9]+ 57num_hex 0x[a-fA-F0-9]+
55num_raw_hex [a-fA-F0-9]+ 58num_raw_hex [a-fA-F0-9]+
@@ -102,16 +105,16 @@ misses|miss { return str(PE_NAME_CACHE_OP_RESULT); }
102config { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); } 105config { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); }
103config1 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); } 106config1 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); }
104config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); } 107config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); }
108name { return term(PARSE_EVENTS__TERM_TYPE_NAME); }
105period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } 109period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
106branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } 110branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
107 111
108mem: { return PE_PREFIX_MEM; } 112mem: { BEGIN(mem); return PE_PREFIX_MEM; }
109r{num_raw_hex} { return raw(); } 113r{num_raw_hex} { return raw(); }
110{num_dec} { return value(10); } 114{num_dec} { return value(10); }
111{num_hex} { return value(16); } 115{num_hex} { return value(16); }
112 116
113{modifier_event} { return str(PE_MODIFIER_EVENT); } 117{modifier_event} { return str(PE_MODIFIER_EVENT); }
114{modifier_bp} { return str(PE_MODIFIER_BP); }
115{name} { return str(PE_NAME); } 118{name} { return str(PE_NAME); }
116"/" { return '/'; } 119"/" { return '/'; }
117- { return '-'; } 120- { return '-'; }
@@ -119,6 +122,25 @@ r{num_raw_hex} { return raw(); }
119: { return ':'; } 122: { return ':'; }
120= { return '='; } 123= { return '='; }
121 124
125<mem>{
126{modifier_bp} { return str(PE_MODIFIER_BP); }
127: { return ':'; }
128{num_dec} { return value(10); }
129{num_hex} { return value(16); }
130 /*
131 * We need to separate 'mem:' scanner part, in order to get specific
132 * modifier bits parsed out. Otherwise we would need to handle PE_NAME
133 * and we'd need to parse it manually. During the escape from <mem>
134 * state we need to put the escaping char back, so we dont miss it.
135 */
136. { unput(*parse_events_text); BEGIN(INITIAL); }
137 /*
138 * We destroy the scanner after reaching EOF,
139 * but anyway just to be sure get back to INIT state.
140 */
141<<EOF>> { BEGIN(INITIAL); }
142}
143
122%% 144%%
123 145
124int parse_events_wrap(void) 146int parse_events_wrap(void)
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index d9637da7333c..362cc59332ae 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -1,7 +1,6 @@
1 1
2%name-prefix "parse_events_" 2%name-prefix "parse_events_"
3%parse-param {struct list_head *list_all} 3%parse-param {struct list_head *list_all}
4%parse-param {struct list_head *list_event}
5%parse-param {int *idx} 4%parse-param {int *idx}
6 5
7%{ 6%{
@@ -41,6 +40,14 @@ do { \
41%type <str> PE_MODIFIER_BP 40%type <str> PE_MODIFIER_BP
42%type <head> event_config 41%type <head> event_config
43%type <term> event_term 42%type <term> event_term
43%type <head> event_pmu
44%type <head> event_legacy_symbol
45%type <head> event_legacy_cache
46%type <head> event_legacy_mem
47%type <head> event_legacy_tracepoint
48%type <head> event_legacy_numeric
49%type <head> event_legacy_raw
50%type <head> event_def
44 51
45%union 52%union
46{ 53{
@@ -62,13 +69,13 @@ event_def PE_MODIFIER_EVENT
62 * (there could be more events added for multiple tracepoint 69 * (there could be more events added for multiple tracepoint
63 * definitions via '*?'. 70 * definitions via '*?'.
64 */ 71 */
65 ABORT_ON(parse_events_modifier(list_event, $2)); 72 ABORT_ON(parse_events_modifier($1, $2));
66 parse_events_update_lists(list_event, list_all); 73 parse_events_update_lists($1, list_all);
67} 74}
68| 75|
69event_def 76event_def
70{ 77{
71 parse_events_update_lists(list_event, list_all); 78 parse_events_update_lists($1, list_all);
72} 79}
73 80
74event_def: event_pmu | 81event_def: event_pmu |
@@ -82,71 +89,102 @@ event_def: event_pmu |
82event_pmu: 89event_pmu:
83PE_NAME '/' event_config '/' 90PE_NAME '/' event_config '/'
84{ 91{
85 ABORT_ON(parse_events_add_pmu(list_event, idx, $1, $3)); 92 struct list_head *list = NULL;
93
94 ABORT_ON(parse_events_add_pmu(&list, idx, $1, $3));
86 parse_events__free_terms($3); 95 parse_events__free_terms($3);
96 $$ = list;
87} 97}
88 98
89event_legacy_symbol: 99event_legacy_symbol:
90PE_VALUE_SYM '/' event_config '/' 100PE_VALUE_SYM '/' event_config '/'
91{ 101{
102 struct list_head *list = NULL;
92 int type = $1 >> 16; 103 int type = $1 >> 16;
93 int config = $1 & 255; 104 int config = $1 & 255;
94 105
95 ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, $3)); 106 ABORT_ON(parse_events_add_numeric(&list, idx, type, config, $3));
96 parse_events__free_terms($3); 107 parse_events__free_terms($3);
108 $$ = list;
97} 109}
98| 110|
99PE_VALUE_SYM sep_slash_dc 111PE_VALUE_SYM sep_slash_dc
100{ 112{
113 struct list_head *list = NULL;
101 int type = $1 >> 16; 114 int type = $1 >> 16;
102 int config = $1 & 255; 115 int config = $1 & 255;
103 116
104 ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, NULL)); 117 ABORT_ON(parse_events_add_numeric(&list, idx, type, config, NULL));
118 $$ = list;
105} 119}
106 120
107event_legacy_cache: 121event_legacy_cache:
108PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT 122PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
109{ 123{
110 ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, $5)); 124 struct list_head *list = NULL;
125
126 ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, $5));
127 $$ = list;
111} 128}
112| 129|
113PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT 130PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
114{ 131{
115 ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, NULL)); 132 struct list_head *list = NULL;
133
134 ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, NULL));
135 $$ = list;
116} 136}
117| 137|
118PE_NAME_CACHE_TYPE 138PE_NAME_CACHE_TYPE
119{ 139{
120 ABORT_ON(parse_events_add_cache(list_event, idx, $1, NULL, NULL)); 140 struct list_head *list = NULL;
141
142 ABORT_ON(parse_events_add_cache(&list, idx, $1, NULL, NULL));
143 $$ = list;
121} 144}
122 145
123event_legacy_mem: 146event_legacy_mem:
124PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc 147PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
125{ 148{
126 ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, $4)); 149 struct list_head *list = NULL;
150
151 ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, $4));
152 $$ = list;
127} 153}
128| 154|
129PE_PREFIX_MEM PE_VALUE sep_dc 155PE_PREFIX_MEM PE_VALUE sep_dc
130{ 156{
131 ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, NULL)); 157 struct list_head *list = NULL;
158
159 ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, NULL));
160 $$ = list;
132} 161}
133 162
134event_legacy_tracepoint: 163event_legacy_tracepoint:
135PE_NAME ':' PE_NAME 164PE_NAME ':' PE_NAME
136{ 165{
137 ABORT_ON(parse_events_add_tracepoint(list_event, idx, $1, $3)); 166 struct list_head *list = NULL;
167
168 ABORT_ON(parse_events_add_tracepoint(&list, idx, $1, $3));
169 $$ = list;
138} 170}
139 171
140event_legacy_numeric: 172event_legacy_numeric:
141PE_VALUE ':' PE_VALUE 173PE_VALUE ':' PE_VALUE
142{ 174{
143 ABORT_ON(parse_events_add_numeric(list_event, idx, $1, $3, NULL)); 175 struct list_head *list = NULL;
176
177 ABORT_ON(parse_events_add_numeric(&list, idx, $1, $3, NULL));
178 $$ = list;
144} 179}
145 180
146event_legacy_raw: 181event_legacy_raw:
147PE_RAW 182PE_RAW
148{ 183{
149 ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, $1, NULL)); 184 struct list_head *list = NULL;
185
186 ABORT_ON(parse_events_add_numeric(&list, idx, PERF_TYPE_RAW, $1, NULL));
187 $$ = list;
150} 188}
151 189
152event_config: 190event_config:
@@ -176,8 +214,8 @@ PE_NAME '=' PE_NAME
176{ 214{
177 struct parse_events__term *term; 215 struct parse_events__term *term;
178 216
179 ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_STR, 217 ABORT_ON(parse_events__term_str(&term, PARSE_EVENTS__TERM_TYPE_USER,
180 $1, $3, 0)); 218 $1, $3));
181 $$ = term; 219 $$ = term;
182} 220}
183| 221|
@@ -185,8 +223,8 @@ PE_NAME '=' PE_VALUE
185{ 223{
186 struct parse_events__term *term; 224 struct parse_events__term *term;
187 225
188 ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM, 226 ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
189 $1, NULL, $3)); 227 $1, $3));
190 $$ = term; 228 $$ = term;
191} 229}
192| 230|
@@ -194,8 +232,16 @@ PE_NAME
194{ 232{
195 struct parse_events__term *term; 233 struct parse_events__term *term;
196 234
197 ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM, 235 ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
198 $1, NULL, 1)); 236 $1, 1));
237 $$ = term;
238}
239|
240PE_TERM '=' PE_NAME
241{
242 struct parse_events__term *term;
243
244 ABORT_ON(parse_events__term_str(&term, $1, NULL, $3));
199 $$ = term; 245 $$ = term;
200} 246}
201| 247|
@@ -203,7 +249,7 @@ PE_TERM '=' PE_VALUE
203{ 249{
204 struct parse_events__term *term; 250 struct parse_events__term *term;
205 251
206 ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, $3)); 252 ABORT_ON(parse_events__term_num(&term, $1, NULL, $3));
207 $$ = term; 253 $$ = term;
208} 254}
209| 255|
@@ -211,7 +257,7 @@ PE_TERM
211{ 257{
212 struct parse_events__term *term; 258 struct parse_events__term *term;
213 259
214 ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, 1)); 260 ABORT_ON(parse_events__term_num(&term, $1, NULL, 1));
215 $$ = term; 261 $$ = term;
216} 262}
217 263
@@ -222,7 +268,6 @@ sep_slash_dc: '/' | ':' |
222%% 268%%
223 269
224void parse_events_error(struct list_head *list_all __used, 270void parse_events_error(struct list_head *list_all __used,
225 struct list_head *list_event __used,
226 int *idx __used, 271 int *idx __used,
227 char const *msg __used) 272 char const *msg __used)
228{ 273{
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index cb08a118e811..a119a5371699 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -225,7 +225,7 @@ static int pmu_config_term(struct list_head *formats,
225 if (parse_events__is_hardcoded_term(term)) 225 if (parse_events__is_hardcoded_term(term))
226 return 0; 226 return 0;
227 227
228 if (term->type != PARSE_EVENTS__TERM_TYPE_NUM) 228 if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
229 return -EINVAL; 229 return -EINVAL;
230 230
231 format = pmu_find_format(formats, term->config); 231 format = pmu_find_format(formats, term->config);
@@ -246,6 +246,11 @@ static int pmu_config_term(struct list_head *formats,
246 return -EINVAL; 246 return -EINVAL;
247 } 247 }
248 248
249 /*
250 * XXX If we ever decide to go with string values for
251 * non-hardcoded terms, here's the place to translate
252 * them into value.
253 */
249 *vp |= pmu_format_value(format->bits, term->val.num); 254 *vp |= pmu_format_value(format->bits, term->val.num);
250 return 0; 255 return 0;
251} 256}
@@ -253,9 +258,9 @@ static int pmu_config_term(struct list_head *formats,
253static int pmu_config(struct list_head *formats, struct perf_event_attr *attr, 258static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
254 struct list_head *head_terms) 259 struct list_head *head_terms)
255{ 260{
256 struct parse_events__term *term, *h; 261 struct parse_events__term *term;
257 262
258 list_for_each_entry_safe(term, h, head_terms, list) 263 list_for_each_entry(term, head_terms, list)
259 if (pmu_config_term(formats, attr, term)) 264 if (pmu_config_term(formats, attr, term))
260 return -EINVAL; 265 return -EINVAL;
261 266
@@ -324,49 +329,58 @@ static struct test_format {
324/* Simulated users input. */ 329/* Simulated users input. */
325static struct parse_events__term test_terms[] = { 330static struct parse_events__term test_terms[] = {
326 { 331 {
327 .config = (char *) "krava01", 332 .config = (char *) "krava01",
328 .val.num = 15, 333 .val.num = 15,
329 .type = PARSE_EVENTS__TERM_TYPE_NUM, 334 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
335 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
330 }, 336 },
331 { 337 {
332 .config = (char *) "krava02", 338 .config = (char *) "krava02",
333 .val.num = 170, 339 .val.num = 170,
334 .type = PARSE_EVENTS__TERM_TYPE_NUM, 340 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
341 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
335 }, 342 },
336 { 343 {
337 .config = (char *) "krava03", 344 .config = (char *) "krava03",
338 .val.num = 1, 345 .val.num = 1,
339 .type = PARSE_EVENTS__TERM_TYPE_NUM, 346 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
347 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
340 }, 348 },
341 { 349 {
342 .config = (char *) "krava11", 350 .config = (char *) "krava11",
343 .val.num = 27, 351 .val.num = 27,
344 .type = PARSE_EVENTS__TERM_TYPE_NUM, 352 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
353 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
345 }, 354 },
346 { 355 {
347 .config = (char *) "krava12", 356 .config = (char *) "krava12",
348 .val.num = 1, 357 .val.num = 1,
349 .type = PARSE_EVENTS__TERM_TYPE_NUM, 358 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
359 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
350 }, 360 },
351 { 361 {
352 .config = (char *) "krava13", 362 .config = (char *) "krava13",
353 .val.num = 2, 363 .val.num = 2,
354 .type = PARSE_EVENTS__TERM_TYPE_NUM, 364 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
365 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
355 }, 366 },
356 { 367 {
357 .config = (char *) "krava21", 368 .config = (char *) "krava21",
358 .val.num = 119, 369 .val.num = 119,
359 .type = PARSE_EVENTS__TERM_TYPE_NUM, 370 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
371 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
360 }, 372 },
361 { 373 {
362 .config = (char *) "krava22", 374 .config = (char *) "krava22",
363 .val.num = 11, 375 .val.num = 11,
364 .type = PARSE_EVENTS__TERM_TYPE_NUM, 376 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
377 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
365 }, 378 },
366 { 379 {
367 .config = (char *) "krava23", 380 .config = (char *) "krava23",
368 .val.num = 2, 381 .val.num = 2,
369 .type = PARSE_EVENTS__TERM_TYPE_NUM, 382 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
383 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
370 }, 384 },
371}; 385};
372#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term)) 386#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 8a8ee64e72d1..59dccc98b554 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -44,6 +44,7 @@
44#include "trace-event.h" /* For __unused */ 44#include "trace-event.h" /* For __unused */
45#include "probe-event.h" 45#include "probe-event.h"
46#include "probe-finder.h" 46#include "probe-finder.h"
47#include "session.h"
47 48
48#define MAX_CMDLEN 256 49#define MAX_CMDLEN 256
49#define MAX_PROBE_ARGS 128 50#define MAX_PROBE_ARGS 128
@@ -70,6 +71,8 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
70} 71}
71 72
72static char *synthesize_perf_probe_point(struct perf_probe_point *pp); 73static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
74static int convert_name_to_addr(struct perf_probe_event *pev,
75 const char *exec);
73static struct machine machine; 76static struct machine machine;
74 77
75/* Initialize symbol maps and path of vmlinux/modules */ 78/* Initialize symbol maps and path of vmlinux/modules */
@@ -170,6 +173,34 @@ const char *kernel_get_module_path(const char *module)
170 return (dso) ? dso->long_name : NULL; 173 return (dso) ? dso->long_name : NULL;
171} 174}
172 175
176static int init_user_exec(void)
177{
178 int ret = 0;
179
180 symbol_conf.try_vmlinux_path = false;
181 symbol_conf.sort_by_name = true;
182 ret = symbol__init();
183
184 if (ret < 0)
185 pr_debug("Failed to init symbol map.\n");
186
187 return ret;
188}
189
190static int convert_to_perf_probe_point(struct probe_trace_point *tp,
191 struct perf_probe_point *pp)
192{
193 pp->function = strdup(tp->symbol);
194
195 if (pp->function == NULL)
196 return -ENOMEM;
197
198 pp->offset = tp->offset;
199 pp->retprobe = tp->retprobe;
200
201 return 0;
202}
203
173#ifdef DWARF_SUPPORT 204#ifdef DWARF_SUPPORT
174/* Open new debuginfo of given module */ 205/* Open new debuginfo of given module */
175static struct debuginfo *open_debuginfo(const char *module) 206static struct debuginfo *open_debuginfo(const char *module)
@@ -224,10 +255,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
224 if (ret <= 0) { 255 if (ret <= 0) {
225 pr_debug("Failed to find corresponding probes from " 256 pr_debug("Failed to find corresponding probes from "
226 "debuginfo. Use kprobe event information.\n"); 257 "debuginfo. Use kprobe event information.\n");
227 pp->function = strdup(tp->symbol); 258 return convert_to_perf_probe_point(tp, pp);
228 if (pp->function == NULL)
229 return -ENOMEM;
230 pp->offset = tp->offset;
231 } 259 }
232 pp->retprobe = tp->retprobe; 260 pp->retprobe = tp->retprobe;
233 261
@@ -275,9 +303,20 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
275 int max_tevs, const char *target) 303 int max_tevs, const char *target)
276{ 304{
277 bool need_dwarf = perf_probe_event_need_dwarf(pev); 305 bool need_dwarf = perf_probe_event_need_dwarf(pev);
278 struct debuginfo *dinfo = open_debuginfo(target); 306 struct debuginfo *dinfo;
279 int ntevs, ret = 0; 307 int ntevs, ret = 0;
280 308
309 if (pev->uprobes) {
310 if (need_dwarf) {
311 pr_warning("Debuginfo-analysis is not yet supported"
312 " with -x/--exec option.\n");
313 return -ENOSYS;
314 }
315 return convert_name_to_addr(pev, target);
316 }
317
318 dinfo = open_debuginfo(target);
319
281 if (!dinfo) { 320 if (!dinfo) {
282 if (need_dwarf) { 321 if (need_dwarf) {
283 pr_warning("Failed to open debuginfo file.\n"); 322 pr_warning("Failed to open debuginfo file.\n");
@@ -603,23 +642,22 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
603 pr_err("Failed to find symbol %s in kernel.\n", tp->symbol); 642 pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
604 return -ENOENT; 643 return -ENOENT;
605 } 644 }
606 pp->function = strdup(tp->symbol);
607 if (pp->function == NULL)
608 return -ENOMEM;
609 pp->offset = tp->offset;
610 pp->retprobe = tp->retprobe;
611 645
612 return 0; 646 return convert_to_perf_probe_point(tp, pp);
613} 647}
614 648
615static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 649static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
616 struct probe_trace_event **tevs __unused, 650 struct probe_trace_event **tevs __unused,
617 int max_tevs __unused, const char *mod __unused) 651 int max_tevs __unused, const char *target)
618{ 652{
619 if (perf_probe_event_need_dwarf(pev)) { 653 if (perf_probe_event_need_dwarf(pev)) {
620 pr_warning("Debuginfo-analysis is not supported.\n"); 654 pr_warning("Debuginfo-analysis is not supported.\n");
621 return -ENOSYS; 655 return -ENOSYS;
622 } 656 }
657
658 if (pev->uprobes)
659 return convert_name_to_addr(pev, target);
660
623 return 0; 661 return 0;
624} 662}
625 663
@@ -1341,11 +1379,18 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
1341 if (buf == NULL) 1379 if (buf == NULL)
1342 return NULL; 1380 return NULL;
1343 1381
1344 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu", 1382 if (tev->uprobes)
1345 tp->retprobe ? 'r' : 'p', 1383 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s",
1346 tev->group, tev->event, 1384 tp->retprobe ? 'r' : 'p',
1347 tp->module ?: "", tp->module ? ":" : "", 1385 tev->group, tev->event,
1348 tp->symbol, tp->offset); 1386 tp->module, tp->symbol);
1387 else
1388 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
1389 tp->retprobe ? 'r' : 'p',
1390 tev->group, tev->event,
1391 tp->module ?: "", tp->module ? ":" : "",
1392 tp->symbol, tp->offset);
1393
1349 if (len <= 0) 1394 if (len <= 0)
1350 goto error; 1395 goto error;
1351 1396
@@ -1364,7 +1409,7 @@ error:
1364} 1409}
1365 1410
1366static int convert_to_perf_probe_event(struct probe_trace_event *tev, 1411static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1367 struct perf_probe_event *pev) 1412 struct perf_probe_event *pev, bool is_kprobe)
1368{ 1413{
1369 char buf[64] = ""; 1414 char buf[64] = "";
1370 int i, ret; 1415 int i, ret;
@@ -1376,7 +1421,11 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1376 return -ENOMEM; 1421 return -ENOMEM;
1377 1422
1378 /* Convert trace_point to probe_point */ 1423 /* Convert trace_point to probe_point */
1379 ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point); 1424 if (is_kprobe)
1425 ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
1426 else
1427 ret = convert_to_perf_probe_point(&tev->point, &pev->point);
1428
1380 if (ret < 0) 1429 if (ret < 0)
1381 return ret; 1430 return ret;
1382 1431
@@ -1472,7 +1521,26 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
1472 memset(tev, 0, sizeof(*tev)); 1521 memset(tev, 0, sizeof(*tev));
1473} 1522}
1474 1523
1475static int open_kprobe_events(bool readwrite) 1524static void print_warn_msg(const char *file, bool is_kprobe)
1525{
1526
1527 if (errno == ENOENT) {
1528 const char *config;
1529
1530 if (!is_kprobe)
1531 config = "CONFIG_UPROBE_EVENTS";
1532 else
1533 config = "CONFIG_KPROBE_EVENTS";
1534
1535 pr_warning("%s file does not exist - please rebuild kernel"
1536 " with %s.\n", file, config);
1537 } else
1538 pr_warning("Failed to open %s file: %s\n", file,
1539 strerror(errno));
1540}
1541
1542static int open_probe_events(const char *trace_file, bool readwrite,
1543 bool is_kprobe)
1476{ 1544{
1477 char buf[PATH_MAX]; 1545 char buf[PATH_MAX];
1478 const char *__debugfs; 1546 const char *__debugfs;
@@ -1484,27 +1552,31 @@ static int open_kprobe_events(bool readwrite)
1484 return -ENOENT; 1552 return -ENOENT;
1485 } 1553 }
1486 1554
1487 ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs); 1555 ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file);
1488 if (ret >= 0) { 1556 if (ret >= 0) {
1489 pr_debug("Opening %s write=%d\n", buf, readwrite); 1557 pr_debug("Opening %s write=%d\n", buf, readwrite);
1490 if (readwrite && !probe_event_dry_run) 1558 if (readwrite && !probe_event_dry_run)
1491 ret = open(buf, O_RDWR, O_APPEND); 1559 ret = open(buf, O_RDWR, O_APPEND);
1492 else 1560 else
1493 ret = open(buf, O_RDONLY, 0); 1561 ret = open(buf, O_RDONLY, 0);
1494 }
1495 1562
1496 if (ret < 0) { 1563 if (ret < 0)
1497 if (errno == ENOENT) 1564 print_warn_msg(buf, is_kprobe);
1498 pr_warning("kprobe_events file does not exist - please"
1499 " rebuild kernel with CONFIG_KPROBE_EVENT.\n");
1500 else
1501 pr_warning("Failed to open kprobe_events file: %s\n",
1502 strerror(errno));
1503 } 1565 }
1504 return ret; 1566 return ret;
1505} 1567}
1506 1568
1507/* Get raw string list of current kprobe_events */ 1569static int open_kprobe_events(bool readwrite)
1570{
1571 return open_probe_events("tracing/kprobe_events", readwrite, true);
1572}
1573
1574static int open_uprobe_events(bool readwrite)
1575{
1576 return open_probe_events("tracing/uprobe_events", readwrite, false);
1577}
1578
1579/* Get raw string list of current kprobe_events or uprobe_events */
1508static struct strlist *get_probe_trace_command_rawlist(int fd) 1580static struct strlist *get_probe_trace_command_rawlist(int fd)
1509{ 1581{
1510 int ret, idx; 1582 int ret, idx;
@@ -1569,36 +1641,26 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
1569 return ret; 1641 return ret;
1570} 1642}
1571 1643
1572/* List up current perf-probe events */ 1644static int __show_perf_probe_events(int fd, bool is_kprobe)
1573int show_perf_probe_events(void)
1574{ 1645{
1575 int fd, ret; 1646 int ret = 0;
1576 struct probe_trace_event tev; 1647 struct probe_trace_event tev;
1577 struct perf_probe_event pev; 1648 struct perf_probe_event pev;
1578 struct strlist *rawlist; 1649 struct strlist *rawlist;
1579 struct str_node *ent; 1650 struct str_node *ent;
1580 1651
1581 setup_pager();
1582 ret = init_vmlinux();
1583 if (ret < 0)
1584 return ret;
1585
1586 memset(&tev, 0, sizeof(tev)); 1652 memset(&tev, 0, sizeof(tev));
1587 memset(&pev, 0, sizeof(pev)); 1653 memset(&pev, 0, sizeof(pev));
1588 1654
1589 fd = open_kprobe_events(false);
1590 if (fd < 0)
1591 return fd;
1592
1593 rawlist = get_probe_trace_command_rawlist(fd); 1655 rawlist = get_probe_trace_command_rawlist(fd);
1594 close(fd);
1595 if (!rawlist) 1656 if (!rawlist)
1596 return -ENOENT; 1657 return -ENOENT;
1597 1658
1598 strlist__for_each(ent, rawlist) { 1659 strlist__for_each(ent, rawlist) {
1599 ret = parse_probe_trace_command(ent->s, &tev); 1660 ret = parse_probe_trace_command(ent->s, &tev);
1600 if (ret >= 0) { 1661 if (ret >= 0) {
1601 ret = convert_to_perf_probe_event(&tev, &pev); 1662 ret = convert_to_perf_probe_event(&tev, &pev,
1663 is_kprobe);
1602 if (ret >= 0) 1664 if (ret >= 0)
1603 ret = show_perf_probe_event(&pev); 1665 ret = show_perf_probe_event(&pev);
1604 } 1666 }
@@ -1612,6 +1674,33 @@ int show_perf_probe_events(void)
1612 return ret; 1674 return ret;
1613} 1675}
1614 1676
1677/* List up current perf-probe events */
1678int show_perf_probe_events(void)
1679{
1680 int fd, ret;
1681
1682 setup_pager();
1683 fd = open_kprobe_events(false);
1684
1685 if (fd < 0)
1686 return fd;
1687
1688 ret = init_vmlinux();
1689 if (ret < 0)
1690 return ret;
1691
1692 ret = __show_perf_probe_events(fd, true);
1693 close(fd);
1694
1695 fd = open_uprobe_events(false);
1696 if (fd >= 0) {
1697 ret = __show_perf_probe_events(fd, false);
1698 close(fd);
1699 }
1700
1701 return ret;
1702}
1703
1615/* Get current perf-probe event names */ 1704/* Get current perf-probe event names */
1616static struct strlist *get_probe_trace_event_names(int fd, bool include_group) 1705static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
1617{ 1706{
@@ -1717,7 +1806,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
1717 const char *event, *group; 1806 const char *event, *group;
1718 struct strlist *namelist; 1807 struct strlist *namelist;
1719 1808
1720 fd = open_kprobe_events(true); 1809 if (pev->uprobes)
1810 fd = open_uprobe_events(true);
1811 else
1812 fd = open_kprobe_events(true);
1813
1721 if (fd < 0) 1814 if (fd < 0)
1722 return fd; 1815 return fd;
1723 /* Get current event names */ 1816 /* Get current event names */
@@ -1829,6 +1922,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1829 tev->point.offset = pev->point.offset; 1922 tev->point.offset = pev->point.offset;
1830 tev->point.retprobe = pev->point.retprobe; 1923 tev->point.retprobe = pev->point.retprobe;
1831 tev->nargs = pev->nargs; 1924 tev->nargs = pev->nargs;
1925 tev->uprobes = pev->uprobes;
1926
1832 if (tev->nargs) { 1927 if (tev->nargs) {
1833 tev->args = zalloc(sizeof(struct probe_trace_arg) 1928 tev->args = zalloc(sizeof(struct probe_trace_arg)
1834 * tev->nargs); 1929 * tev->nargs);
@@ -1859,6 +1954,9 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1859 } 1954 }
1860 } 1955 }
1861 1956
1957 if (pev->uprobes)
1958 return 1;
1959
1862 /* Currently just checking function name from symbol map */ 1960 /* Currently just checking function name from symbol map */
1863 sym = __find_kernel_function_by_name(tev->point.symbol, NULL); 1961 sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
1864 if (!sym) { 1962 if (!sym) {
@@ -1894,12 +1992,18 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1894 int i, j, ret; 1992 int i, j, ret;
1895 struct __event_package *pkgs; 1993 struct __event_package *pkgs;
1896 1994
1995 ret = 0;
1897 pkgs = zalloc(sizeof(struct __event_package) * npevs); 1996 pkgs = zalloc(sizeof(struct __event_package) * npevs);
1997
1898 if (pkgs == NULL) 1998 if (pkgs == NULL)
1899 return -ENOMEM; 1999 return -ENOMEM;
1900 2000
1901 /* Init vmlinux path */ 2001 if (!pevs->uprobes)
1902 ret = init_vmlinux(); 2002 /* Init vmlinux path */
2003 ret = init_vmlinux();
2004 else
2005 ret = init_user_exec();
2006
1903 if (ret < 0) { 2007 if (ret < 0) {
1904 free(pkgs); 2008 free(pkgs);
1905 return ret; 2009 return ret;
@@ -1971,23 +2075,15 @@ error:
1971 return ret; 2075 return ret;
1972} 2076}
1973 2077
1974static int del_trace_probe_event(int fd, const char *group, 2078static int del_trace_probe_event(int fd, const char *buf,
1975 const char *event, struct strlist *namelist) 2079 struct strlist *namelist)
1976{ 2080{
1977 char buf[128];
1978 struct str_node *ent, *n; 2081 struct str_node *ent, *n;
1979 int found = 0, ret = 0; 2082 int ret = -1;
1980
1981 ret = e_snprintf(buf, 128, "%s:%s", group, event);
1982 if (ret < 0) {
1983 pr_err("Failed to copy event.\n");
1984 return ret;
1985 }
1986 2083
1987 if (strpbrk(buf, "*?")) { /* Glob-exp */ 2084 if (strpbrk(buf, "*?")) { /* Glob-exp */
1988 strlist__for_each_safe(ent, n, namelist) 2085 strlist__for_each_safe(ent, n, namelist)
1989 if (strglobmatch(ent->s, buf)) { 2086 if (strglobmatch(ent->s, buf)) {
1990 found++;
1991 ret = __del_trace_probe_event(fd, ent); 2087 ret = __del_trace_probe_event(fd, ent);
1992 if (ret < 0) 2088 if (ret < 0)
1993 break; 2089 break;
@@ -1996,40 +2092,43 @@ static int del_trace_probe_event(int fd, const char *group,
1996 } else { 2092 } else {
1997 ent = strlist__find(namelist, buf); 2093 ent = strlist__find(namelist, buf);
1998 if (ent) { 2094 if (ent) {
1999 found++;
2000 ret = __del_trace_probe_event(fd, ent); 2095 ret = __del_trace_probe_event(fd, ent);
2001 if (ret >= 0) 2096 if (ret >= 0)
2002 strlist__remove(namelist, ent); 2097 strlist__remove(namelist, ent);
2003 } 2098 }
2004 } 2099 }
2005 if (found == 0 && ret >= 0)
2006 pr_info("Info: Event \"%s\" does not exist.\n", buf);
2007 2100
2008 return ret; 2101 return ret;
2009} 2102}
2010 2103
2011int del_perf_probe_events(struct strlist *dellist) 2104int del_perf_probe_events(struct strlist *dellist)
2012{ 2105{
2013 int fd, ret = 0; 2106 int ret = -1, ufd = -1, kfd = -1;
2107 char buf[128];
2014 const char *group, *event; 2108 const char *group, *event;
2015 char *p, *str; 2109 char *p, *str;
2016 struct str_node *ent; 2110 struct str_node *ent;
2017 struct strlist *namelist; 2111 struct strlist *namelist = NULL, *unamelist = NULL;
2018
2019 fd = open_kprobe_events(true);
2020 if (fd < 0)
2021 return fd;
2022 2112
2023 /* Get current event names */ 2113 /* Get current event names */
2024 namelist = get_probe_trace_event_names(fd, true); 2114 kfd = open_kprobe_events(true);
2025 if (namelist == NULL) 2115 if (kfd < 0)
2026 return -EINVAL; 2116 return kfd;
2117
2118 namelist = get_probe_trace_event_names(kfd, true);
2119 ufd = open_uprobe_events(true);
2120
2121 if (ufd >= 0)
2122 unamelist = get_probe_trace_event_names(ufd, true);
2123
2124 if (namelist == NULL && unamelist == NULL)
2125 goto error;
2027 2126
2028 strlist__for_each(ent, dellist) { 2127 strlist__for_each(ent, dellist) {
2029 str = strdup(ent->s); 2128 str = strdup(ent->s);
2030 if (str == NULL) { 2129 if (str == NULL) {
2031 ret = -ENOMEM; 2130 ret = -ENOMEM;
2032 break; 2131 goto error;
2033 } 2132 }
2034 pr_debug("Parsing: %s\n", str); 2133 pr_debug("Parsing: %s\n", str);
2035 p = strchr(str, ':'); 2134 p = strchr(str, ':');
@@ -2041,17 +2140,46 @@ int del_perf_probe_events(struct strlist *dellist)
2041 group = "*"; 2140 group = "*";
2042 event = str; 2141 event = str;
2043 } 2142 }
2143
2144 ret = e_snprintf(buf, 128, "%s:%s", group, event);
2145 if (ret < 0) {
2146 pr_err("Failed to copy event.");
2147 free(str);
2148 goto error;
2149 }
2150
2044 pr_debug("Group: %s, Event: %s\n", group, event); 2151 pr_debug("Group: %s, Event: %s\n", group, event);
2045 ret = del_trace_probe_event(fd, group, event, namelist); 2152
2153 if (namelist)
2154 ret = del_trace_probe_event(kfd, buf, namelist);
2155
2156 if (unamelist && ret != 0)
2157 ret = del_trace_probe_event(ufd, buf, unamelist);
2158
2159 if (ret != 0)
2160 pr_info("Info: Event \"%s\" does not exist.\n", buf);
2161
2046 free(str); 2162 free(str);
2047 if (ret < 0)
2048 break;
2049 } 2163 }
2050 strlist__delete(namelist); 2164
2051 close(fd); 2165error:
2166 if (kfd >= 0) {
2167 if (namelist)
2168 strlist__delete(namelist);
2169
2170 close(kfd);
2171 }
2172
2173 if (ufd >= 0) {
2174 if (unamelist)
2175 strlist__delete(unamelist);
2176
2177 close(ufd);
2178 }
2052 2179
2053 return ret; 2180 return ret;
2054} 2181}
2182
2055/* TODO: don't use a global variable for filter ... */ 2183/* TODO: don't use a global variable for filter ... */
2056static struct strfilter *available_func_filter; 2184static struct strfilter *available_func_filter;
2057 2185
@@ -2068,30 +2196,152 @@ static int filter_available_functions(struct map *map __unused,
2068 return 1; 2196 return 1;
2069} 2197}
2070 2198
2071int show_available_funcs(const char *target, struct strfilter *_filter) 2199static int __show_available_funcs(struct map *map)
2200{
2201 if (map__load(map, filter_available_functions)) {
2202 pr_err("Failed to load map.\n");
2203 return -EINVAL;
2204 }
2205 if (!dso__sorted_by_name(map->dso, map->type))
2206 dso__sort_by_name(map->dso, map->type);
2207
2208 dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
2209 return 0;
2210}
2211
2212static int available_kernel_funcs(const char *module)
2072{ 2213{
2073 struct map *map; 2214 struct map *map;
2074 int ret; 2215 int ret;
2075 2216
2076 setup_pager();
2077
2078 ret = init_vmlinux(); 2217 ret = init_vmlinux();
2079 if (ret < 0) 2218 if (ret < 0)
2080 return ret; 2219 return ret;
2081 2220
2082 map = kernel_get_module_map(target); 2221 map = kernel_get_module_map(module);
2083 if (!map) { 2222 if (!map) {
2084 pr_err("Failed to find %s map.\n", (target) ? : "kernel"); 2223 pr_err("Failed to find %s map.\n", (module) ? : "kernel");
2085 return -EINVAL; 2224 return -EINVAL;
2086 } 2225 }
2226 return __show_available_funcs(map);
2227}
2228
2229static int available_user_funcs(const char *target)
2230{
2231 struct map *map;
2232 int ret;
2233
2234 ret = init_user_exec();
2235 if (ret < 0)
2236 return ret;
2237
2238 map = dso__new_map(target);
2239 ret = __show_available_funcs(map);
2240 dso__delete(map->dso);
2241 map__delete(map);
2242 return ret;
2243}
2244
2245int show_available_funcs(const char *target, struct strfilter *_filter,
2246 bool user)
2247{
2248 setup_pager();
2087 available_func_filter = _filter; 2249 available_func_filter = _filter;
2250
2251 if (!user)
2252 return available_kernel_funcs(target);
2253
2254 return available_user_funcs(target);
2255}
2256
2257/*
2258 * uprobe_events only accepts address:
2259 * Convert function and any offset to address
2260 */
2261static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
2262{
2263 struct perf_probe_point *pp = &pev->point;
2264 struct symbol *sym;
2265 struct map *map = NULL;
2266 char *function = NULL, *name = NULL;
2267 int ret = -EINVAL;
2268 unsigned long long vaddr = 0;
2269
2270 if (!pp->function) {
2271 pr_warning("No function specified for uprobes");
2272 goto out;
2273 }
2274
2275 function = strdup(pp->function);
2276 if (!function) {
2277 pr_warning("Failed to allocate memory by strdup.\n");
2278 ret = -ENOMEM;
2279 goto out;
2280 }
2281
2282 name = realpath(exec, NULL);
2283 if (!name) {
2284 pr_warning("Cannot find realpath for %s.\n", exec);
2285 goto out;
2286 }
2287 map = dso__new_map(name);
2288 if (!map) {
2289 pr_warning("Cannot find appropriate DSO for %s.\n", exec);
2290 goto out;
2291 }
2292 available_func_filter = strfilter__new(function, NULL);
2088 if (map__load(map, filter_available_functions)) { 2293 if (map__load(map, filter_available_functions)) {
2089 pr_err("Failed to load map.\n"); 2294 pr_err("Failed to load map.\n");
2090 return -EINVAL; 2295 goto out;
2091 } 2296 }
2092 if (!dso__sorted_by_name(map->dso, map->type))
2093 dso__sort_by_name(map->dso, map->type);
2094 2297
2095 dso__fprintf_symbols_by_name(map->dso, map->type, stdout); 2298 sym = map__find_symbol_by_name(map, function, NULL);
2096 return 0; 2299 if (!sym) {
2300 pr_warning("Cannot find %s in DSO %s\n", function, exec);
2301 goto out;
2302 }
2303
2304 if (map->start > sym->start)
2305 vaddr = map->start;
2306 vaddr += sym->start + pp->offset + map->pgoff;
2307 pp->offset = 0;
2308
2309 if (!pev->event) {
2310 pev->event = function;
2311 function = NULL;
2312 }
2313 if (!pev->group) {
2314 char *ptr1, *ptr2;
2315
2316 pev->group = zalloc(sizeof(char *) * 64);
2317 ptr1 = strdup(basename(exec));
2318 if (ptr1) {
2319 ptr2 = strpbrk(ptr1, "-._");
2320 if (ptr2)
2321 *ptr2 = '\0';
2322 e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
2323 ptr1);
2324 free(ptr1);
2325 }
2326 }
2327 free(pp->function);
2328 pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
2329 if (!pp->function) {
2330 ret = -ENOMEM;
2331 pr_warning("Failed to allocate memory by zalloc.\n");
2332 goto out;
2333 }
2334 e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
2335 ret = 0;
2336
2337out:
2338 if (map) {
2339 dso__delete(map->dso);
2340 map__delete(map);
2341 }
2342 if (function)
2343 free(function);
2344 if (name)
2345 free(name);
2346 return ret;
2097} 2347}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index a7dee835f49c..f9f3de8b4220 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -7,7 +7,7 @@
7 7
8extern bool probe_event_dry_run; 8extern bool probe_event_dry_run;
9 9
10/* kprobe-tracer tracing point */ 10/* kprobe-tracer and uprobe-tracer tracing point */
11struct probe_trace_point { 11struct probe_trace_point {
12 char *symbol; /* Base symbol */ 12 char *symbol; /* Base symbol */
13 char *module; /* Module name */ 13 char *module; /* Module name */
@@ -21,7 +21,7 @@ struct probe_trace_arg_ref {
21 long offset; /* Offset value */ 21 long offset; /* Offset value */
22}; 22};
23 23
24/* kprobe-tracer tracing argument */ 24/* kprobe-tracer and uprobe-tracer tracing argument */
25struct probe_trace_arg { 25struct probe_trace_arg {
26 char *name; /* Argument name */ 26 char *name; /* Argument name */
27 char *value; /* Base value */ 27 char *value; /* Base value */
@@ -29,12 +29,13 @@ struct probe_trace_arg {
29 struct probe_trace_arg_ref *ref; /* Referencing offset */ 29 struct probe_trace_arg_ref *ref; /* Referencing offset */
30}; 30};
31 31
32/* kprobe-tracer tracing event (point + arg) */ 32/* kprobe-tracer and uprobe-tracer tracing event (point + arg) */
33struct probe_trace_event { 33struct probe_trace_event {
34 char *event; /* Event name */ 34 char *event; /* Event name */
35 char *group; /* Group name */ 35 char *group; /* Group name */
36 struct probe_trace_point point; /* Trace point */ 36 struct probe_trace_point point; /* Trace point */
37 int nargs; /* Number of args */ 37 int nargs; /* Number of args */
38 bool uprobes; /* uprobes only */
38 struct probe_trace_arg *args; /* Arguments */ 39 struct probe_trace_arg *args; /* Arguments */
39}; 40};
40 41
@@ -70,6 +71,7 @@ struct perf_probe_event {
70 char *group; /* Group name */ 71 char *group; /* Group name */
71 struct perf_probe_point point; /* Probe point */ 72 struct perf_probe_point point; /* Probe point */
72 int nargs; /* Number of arguments */ 73 int nargs; /* Number of arguments */
74 bool uprobes;
73 struct perf_probe_arg *args; /* Arguments */ 75 struct perf_probe_arg *args; /* Arguments */
74}; 76};
75 77
@@ -129,8 +131,8 @@ extern int show_line_range(struct line_range *lr, const char *module);
129extern int show_available_vars(struct perf_probe_event *pevs, int npevs, 131extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
130 int max_probe_points, const char *module, 132 int max_probe_points, const char *module,
131 struct strfilter *filter, bool externs); 133 struct strfilter *filter, bool externs);
132extern int show_available_funcs(const char *module, struct strfilter *filter); 134extern int show_available_funcs(const char *module, struct strfilter *filter,
133 135 bool user);
134 136
135/* Maximum index number of event-name postfix */ 137/* Maximum index number of event-name postfix */
136#define MAX_EVENT_INDEX 1024 138#define MAX_EVENT_INDEX 1024
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index e30749e38a9b..4c1b3d72a1d2 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -56,7 +56,7 @@ INTERP my_perl;
56#define FTRACE_MAX_EVENT \ 56#define FTRACE_MAX_EVENT \
57 ((1 << (sizeof(unsigned short) * 8)) - 1) 57 ((1 << (sizeof(unsigned short) * 8)) - 1)
58 58
59struct event *events[FTRACE_MAX_EVENT]; 59struct event_format *events[FTRACE_MAX_EVENT];
60 60
61extern struct scripting_context *scripting_context; 61extern struct scripting_context *scripting_context;
62 62
@@ -181,7 +181,7 @@ static void define_flag_field(const char *ev_name,
181 LEAVE; 181 LEAVE;
182} 182}
183 183
184static void define_event_symbols(struct event *event, 184static void define_event_symbols(struct event_format *event,
185 const char *ev_name, 185 const char *ev_name,
186 struct print_arg *args) 186 struct print_arg *args)
187{ 187{
@@ -209,6 +209,8 @@ static void define_event_symbols(struct event *event,
209 define_symbolic_values(args->symbol.symbols, ev_name, 209 define_symbolic_values(args->symbol.symbols, ev_name,
210 cur_field_name); 210 cur_field_name);
211 break; 211 break;
212 case PRINT_BSTRING:
213 case PRINT_DYNAMIC_ARRAY:
212 case PRINT_STRING: 214 case PRINT_STRING:
213 break; 215 break;
214 case PRINT_TYPE: 216 case PRINT_TYPE:
@@ -220,7 +222,9 @@ static void define_event_symbols(struct event *event,
220 define_event_symbols(event, ev_name, args->op.left); 222 define_event_symbols(event, ev_name, args->op.left);
221 define_event_symbols(event, ev_name, args->op.right); 223 define_event_symbols(event, ev_name, args->op.right);
222 break; 224 break;
225 case PRINT_FUNC:
223 default: 226 default:
227 pr_err("Unsupported print arg type\n");
224 /* we should warn... */ 228 /* we should warn... */
225 return; 229 return;
226 } 230 }
@@ -229,10 +233,10 @@ static void define_event_symbols(struct event *event,
229 define_event_symbols(event, ev_name, args->next); 233 define_event_symbols(event, ev_name, args->next);
230} 234}
231 235
232static inline struct event *find_cache_event(int type) 236static inline struct event_format *find_cache_event(int type)
233{ 237{
234 static char ev_name[256]; 238 static char ev_name[256];
235 struct event *event; 239 struct event_format *event;
236 240
237 if (events[type]) 241 if (events[type])
238 return events[type]; 242 return events[type];
@@ -258,7 +262,7 @@ static void perl_process_tracepoint(union perf_event *pevent __unused,
258 static char handler[256]; 262 static char handler[256];
259 unsigned long long val; 263 unsigned long long val;
260 unsigned long s, ns; 264 unsigned long s, ns;
261 struct event *event; 265 struct event_format *event;
262 int type; 266 int type;
263 int pid; 267 int pid;
264 int cpu = sample->cpu; 268 int cpu = sample->cpu;
@@ -446,7 +450,7 @@ static int perl_stop_script(void)
446 450
447static int perl_generate_script(const char *outfile) 451static int perl_generate_script(const char *outfile)
448{ 452{
449 struct event *event = NULL; 453 struct event_format *event = NULL;
450 struct format_field *f; 454 struct format_field *f;
451 char fname[PATH_MAX]; 455 char fname[PATH_MAX];
452 int not_first, count; 456 int not_first, count;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index c2623c6f9b51..acb9795286c4 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -37,7 +37,7 @@ PyMODINIT_FUNC initperf_trace_context(void);
37#define FTRACE_MAX_EVENT \ 37#define FTRACE_MAX_EVENT \
38 ((1 << (sizeof(unsigned short) * 8)) - 1) 38 ((1 << (sizeof(unsigned short) * 8)) - 1)
39 39
40struct event *events[FTRACE_MAX_EVENT]; 40struct event_format *events[FTRACE_MAX_EVENT];
41 41
42#define MAX_FIELDS 64 42#define MAX_FIELDS 64
43#define N_COMMON_FIELDS 7 43#define N_COMMON_FIELDS 7
@@ -136,7 +136,7 @@ static void define_field(enum print_arg_type field_type,
136 Py_DECREF(t); 136 Py_DECREF(t);
137} 137}
138 138
139static void define_event_symbols(struct event *event, 139static void define_event_symbols(struct event_format *event,
140 const char *ev_name, 140 const char *ev_name,
141 struct print_arg *args) 141 struct print_arg *args)
142{ 142{
@@ -178,6 +178,10 @@ static void define_event_symbols(struct event *event,
178 define_event_symbols(event, ev_name, args->op.right); 178 define_event_symbols(event, ev_name, args->op.right);
179 break; 179 break;
180 default: 180 default:
181 /* gcc warns for these? */
182 case PRINT_BSTRING:
183 case PRINT_DYNAMIC_ARRAY:
184 case PRINT_FUNC:
181 /* we should warn... */ 185 /* we should warn... */
182 return; 186 return;
183 } 187 }
@@ -186,10 +190,10 @@ static void define_event_symbols(struct event *event,
186 define_event_symbols(event, ev_name, args->next); 190 define_event_symbols(event, ev_name, args->next);
187} 191}
188 192
189static inline struct event *find_cache_event(int type) 193static inline struct event_format *find_cache_event(int type)
190{ 194{
191 static char ev_name[256]; 195 static char ev_name[256];
192 struct event *event; 196 struct event_format *event;
193 197
194 if (events[type]) 198 if (events[type])
195 return events[type]; 199 return events[type];
@@ -216,7 +220,7 @@ static void python_process_event(union perf_event *pevent __unused,
216 struct format_field *field; 220 struct format_field *field;
217 unsigned long long val; 221 unsigned long long val;
218 unsigned long s, ns; 222 unsigned long s, ns;
219 struct event *event; 223 struct event_format *event;
220 unsigned n = 0; 224 unsigned n = 0;
221 int type; 225 int type;
222 int pid; 226 int pid;
@@ -436,7 +440,7 @@ out:
436 440
437static int python_generate_script(const char *outfile) 441static int python_generate_script(const char *outfile)
438{ 442{
439 struct event *event = NULL; 443 struct event_format *event = NULL;
440 struct format_field *f; 444 struct format_field *f;
441 char fname[PATH_MAX]; 445 char fname[PATH_MAX];
442 int not_first, count; 446 int not_first, count;
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 1efd3bee6336..93d355d27109 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -481,6 +481,38 @@ static void perf_event__read_swap(union perf_event *event)
481 event->read.id = bswap_64(event->read.id); 481 event->read.id = bswap_64(event->read.id);
482} 482}
483 483
484static u8 revbyte(u8 b)
485{
486 int rev = (b >> 4) | ((b & 0xf) << 4);
487 rev = ((rev & 0xcc) >> 2) | ((rev & 0x33) << 2);
488 rev = ((rev & 0xaa) >> 1) | ((rev & 0x55) << 1);
489 return (u8) rev;
490}
491
492/*
493 * XXX this is hack in attempt to carry flags bitfield
494 * throught endian village. ABI says:
495 *
496 * Bit-fields are allocated from right to left (least to most significant)
497 * on little-endian implementations and from left to right (most to least
498 * significant) on big-endian implementations.
499 *
500 * The above seems to be byte specific, so we need to reverse each
501 * byte of the bitfield. 'Internet' also says this might be implementation
502 * specific and we probably need proper fix and carry perf_event_attr
503 * bitfield flags in separate data file FEAT_ section. Thought this seems
504 * to work for now.
505 */
506static void swap_bitfield(u8 *p, unsigned len)
507{
508 unsigned i;
509
510 for (i = 0; i < len; i++) {
511 *p = revbyte(*p);
512 p++;
513 }
514}
515
484/* exported for swapping attributes in file header */ 516/* exported for swapping attributes in file header */
485void perf_event__attr_swap(struct perf_event_attr *attr) 517void perf_event__attr_swap(struct perf_event_attr *attr)
486{ 518{
@@ -494,6 +526,8 @@ void perf_event__attr_swap(struct perf_event_attr *attr)
494 attr->bp_type = bswap_32(attr->bp_type); 526 attr->bp_type = bswap_32(attr->bp_type);
495 attr->bp_addr = bswap_64(attr->bp_addr); 527 attr->bp_addr = bswap_64(attr->bp_addr);
496 attr->bp_len = bswap_64(attr->bp_len); 528 attr->bp_len = bswap_64(attr->bp_len);
529
530 swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64));
497} 531}
498 532
499static void perf_event__hdr_attr_swap(union perf_event *event) 533static void perf_event__hdr_attr_swap(union perf_event *event)
@@ -1064,8 +1098,9 @@ volatile int session_done;
1064static int __perf_session__process_pipe_events(struct perf_session *self, 1098static int __perf_session__process_pipe_events(struct perf_session *self,
1065 struct perf_tool *tool) 1099 struct perf_tool *tool)
1066{ 1100{
1067 union perf_event event; 1101 union perf_event *event;
1068 uint32_t size; 1102 uint32_t size, cur_size = 0;
1103 void *buf = NULL;
1069 int skip = 0; 1104 int skip = 0;
1070 u64 head; 1105 u64 head;
1071 int err; 1106 int err;
@@ -1074,8 +1109,14 @@ static int __perf_session__process_pipe_events(struct perf_session *self,
1074 perf_tool__fill_defaults(tool); 1109 perf_tool__fill_defaults(tool);
1075 1110
1076 head = 0; 1111 head = 0;
1112 cur_size = sizeof(union perf_event);
1113
1114 buf = malloc(cur_size);
1115 if (!buf)
1116 return -errno;
1077more: 1117more:
1078 err = readn(self->fd, &event, sizeof(struct perf_event_header)); 1118 event = buf;
1119 err = readn(self->fd, event, sizeof(struct perf_event_header));
1079 if (err <= 0) { 1120 if (err <= 0) {
1080 if (err == 0) 1121 if (err == 0)
1081 goto done; 1122 goto done;
@@ -1085,13 +1126,23 @@ more:
1085 } 1126 }
1086 1127
1087 if (self->header.needs_swap) 1128 if (self->header.needs_swap)
1088 perf_event_header__bswap(&event.header); 1129 perf_event_header__bswap(&event->header);
1089 1130
1090 size = event.header.size; 1131 size = event->header.size;
1091 if (size == 0) 1132 if (size == 0)
1092 size = 8; 1133 size = 8;
1093 1134
1094 p = &event; 1135 if (size > cur_size) {
1136 void *new = realloc(buf, size);
1137 if (!new) {
1138 pr_err("failed to allocate memory to read event\n");
1139 goto out_err;
1140 }
1141 buf = new;
1142 cur_size = size;
1143 event = buf;
1144 }
1145 p = event;
1095 p += sizeof(struct perf_event_header); 1146 p += sizeof(struct perf_event_header);
1096 1147
1097 if (size - sizeof(struct perf_event_header)) { 1148 if (size - sizeof(struct perf_event_header)) {
@@ -1107,17 +1158,11 @@ more:
1107 } 1158 }
1108 } 1159 }
1109 1160
1110 if ((skip = perf_session__process_event(self, &event, tool, head)) < 0) { 1161 if ((skip = perf_session__process_event(self, event, tool, head)) < 0) {
1111 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", 1162 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
1112 head, event.header.size, event.header.type); 1163 head, event->header.size, event->header.type);
1113 /* 1164 err = -EINVAL;
1114 * assume we lost track of the stream, check alignment, and 1165 goto out_err;
1115 * increment a single u64 in the hope to catch on again 'soon'.
1116 */
1117 if (unlikely(head & 7))
1118 head &= ~7ULL;
1119
1120 size = 8;
1121 } 1166 }
1122 1167
1123 head += size; 1168 head += size;
@@ -1130,6 +1175,7 @@ more:
1130done: 1175done:
1131 err = 0; 1176 err = 0;
1132out_err: 1177out_err:
1178 free(buf);
1133 perf_session__warn_about_errors(self, tool); 1179 perf_session__warn_about_errors(self, tool);
1134 perf_session_free_sample_buffers(self); 1180 perf_session_free_sample_buffers(self);
1135 return err; 1181 return err;
@@ -1226,17 +1272,11 @@ more:
1226 1272
1227 if (size == 0 || 1273 if (size == 0 ||
1228 perf_session__process_event(session, event, tool, file_pos) < 0) { 1274 perf_session__process_event(session, event, tool, file_pos) < 0) {
1229 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", 1275 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
1230 file_offset + head, event->header.size, 1276 file_offset + head, event->header.size,
1231 event->header.type); 1277 event->header.type);
1232 /* 1278 err = -EINVAL;
1233 * assume we lost track of the stream, check alignment, and 1279 goto out_err;
1234 * increment a single u64 in the hope to catch on again 'soon'.
1235 */
1236 if (unlikely(head & 7))
1237 head &= ~7ULL;
1238
1239 size = 8;
1240 } 1280 }
1241 1281
1242 head += size; 1282 head += size;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index ab9867b2b433..e2ba8858f3e1 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -2783,3 +2783,11 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
2783 2783
2784 return ret; 2784 return ret;
2785} 2785}
2786
2787struct map *dso__new_map(const char *name)
2788{
2789 struct dso *dso = dso__new(name);
2790 struct map *map = map__new2(0, dso, MAP__FUNCTION);
2791
2792 return map;
2793}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index ac49ef208a5f..5649d63798cb 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -65,6 +65,11 @@ struct symbol {
65 65
66void symbol__delete(struct symbol *sym); 66void symbol__delete(struct symbol *sym);
67 67
68static inline size_t symbol__size(const struct symbol *sym)
69{
70 return sym->end - sym->start + 1;
71}
72
68struct strlist; 73struct strlist;
69 74
70struct symbol_conf { 75struct symbol_conf {
@@ -237,6 +242,7 @@ void dso__set_long_name(struct dso *dso, char *name);
237void dso__set_build_id(struct dso *dso, void *build_id); 242void dso__set_build_id(struct dso *dso, void *build_id);
238void dso__read_running_kernel_build_id(struct dso *dso, 243void dso__read_running_kernel_build_id(struct dso *dso,
239 struct machine *machine); 244 struct machine *machine);
245struct map *dso__new_map(const char *name);
240struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, 246struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
241 u64 addr); 247 u64 addr);
242struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 248struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c
new file mode 100644
index 000000000000..1064d5b148ad
--- /dev/null
+++ b/tools/perf/util/target.c
@@ -0,0 +1,142 @@
1/*
2 * Helper functions for handling target threads/cpus
3 *
4 * Copyright (C) 2012, LG Electronics, Namhyung Kim <namhyung.kim@lge.com>
5 *
6 * Released under the GPL v2.
7 */
8
9#include "target.h"
10#include "debug.h"
11
12#include <pwd.h>
13#include <string.h>
14
15
16enum perf_target_errno perf_target__validate(struct perf_target *target)
17{
18 enum perf_target_errno ret = PERF_ERRNO_TARGET__SUCCESS;
19
20 if (target->pid)
21 target->tid = target->pid;
22
23 /* CPU and PID are mutually exclusive */
24 if (target->tid && target->cpu_list) {
25 target->cpu_list = NULL;
26 if (ret == PERF_ERRNO_TARGET__SUCCESS)
27 ret = PERF_ERRNO_TARGET__PID_OVERRIDE_CPU;
28 }
29
30 /* UID and PID are mutually exclusive */
31 if (target->tid && target->uid_str) {
32 target->uid_str = NULL;
33 if (ret == PERF_ERRNO_TARGET__SUCCESS)
34 ret = PERF_ERRNO_TARGET__PID_OVERRIDE_UID;
35 }
36
37 /* UID and CPU are mutually exclusive */
38 if (target->uid_str && target->cpu_list) {
39 target->cpu_list = NULL;
40 if (ret == PERF_ERRNO_TARGET__SUCCESS)
41 ret = PERF_ERRNO_TARGET__UID_OVERRIDE_CPU;
42 }
43
44 /* PID and SYSTEM are mutually exclusive */
45 if (target->tid && target->system_wide) {
46 target->system_wide = false;
47 if (ret == PERF_ERRNO_TARGET__SUCCESS)
48 ret = PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM;
49 }
50
51 /* UID and SYSTEM are mutually exclusive */
52 if (target->uid_str && target->system_wide) {
53 target->system_wide = false;
54 if (ret == PERF_ERRNO_TARGET__SUCCESS)
55 ret = PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM;
56 }
57
58 return ret;
59}
60
61enum perf_target_errno perf_target__parse_uid(struct perf_target *target)
62{
63 struct passwd pwd, *result;
64 char buf[1024];
65 const char *str = target->uid_str;
66
67 target->uid = UINT_MAX;
68 if (str == NULL)
69 return PERF_ERRNO_TARGET__SUCCESS;
70
71 /* Try user name first */
72 getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
73
74 if (result == NULL) {
75 /*
76 * The user name not found. Maybe it's a UID number.
77 */
78 char *endptr;
79 int uid = strtol(str, &endptr, 10);
80
81 if (*endptr != '\0')
82 return PERF_ERRNO_TARGET__INVALID_UID;
83
84 getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
85
86 if (result == NULL)
87 return PERF_ERRNO_TARGET__USER_NOT_FOUND;
88 }
89
90 target->uid = result->pw_uid;
91 return PERF_ERRNO_TARGET__SUCCESS;
92}
93
94/*
95 * This must have a same ordering as the enum perf_target_errno.
96 */
97static const char *perf_target__error_str[] = {
98 "PID/TID switch overriding CPU",
99 "PID/TID switch overriding UID",
100 "UID switch overriding CPU",
101 "PID/TID switch overriding SYSTEM",
102 "UID switch overriding SYSTEM",
103 "Invalid User: %s",
104 "Problems obtaining information for user %s",
105};
106
107int perf_target__strerror(struct perf_target *target, int errnum,
108 char *buf, size_t buflen)
109{
110 int idx;
111 const char *msg;
112
113 if (errnum >= 0) {
114 strerror_r(errnum, buf, buflen);
115 return 0;
116 }
117
118 if (errnum < __PERF_ERRNO_TARGET__START ||
119 errnum >= __PERF_ERRNO_TARGET__END)
120 return -1;
121
122 idx = errnum - __PERF_ERRNO_TARGET__START;
123 msg = perf_target__error_str[idx];
124
125 switch (errnum) {
126 case PERF_ERRNO_TARGET__PID_OVERRIDE_CPU
127 ... PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM:
128 snprintf(buf, buflen, "%s", msg);
129 break;
130
131 case PERF_ERRNO_TARGET__INVALID_UID:
132 case PERF_ERRNO_TARGET__USER_NOT_FOUND:
133 snprintf(buf, buflen, msg, target->uid_str);
134 break;
135
136 default:
137 /* cannot reach here */
138 break;
139 }
140
141 return 0;
142}
diff --git a/tools/perf/util/target.h b/tools/perf/util/target.h
new file mode 100644
index 000000000000..a4be8575fda5
--- /dev/null
+++ b/tools/perf/util/target.h
@@ -0,0 +1,65 @@
1#ifndef _PERF_TARGET_H
2#define _PERF_TARGET_H
3
4#include <stdbool.h>
5#include <sys/types.h>
6
7struct perf_target {
8 const char *pid;
9 const char *tid;
10 const char *cpu_list;
11 const char *uid_str;
12 uid_t uid;
13 bool system_wide;
14 bool uses_mmap;
15};
16
17enum perf_target_errno {
18 PERF_ERRNO_TARGET__SUCCESS = 0,
19
20 /*
21 * Choose an arbitrary negative big number not to clash with standard
22 * errno since SUS requires the errno has distinct positive values.
23 * See 'Issue 6' in the link below.
24 *
25 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
26 */
27 __PERF_ERRNO_TARGET__START = -10000,
28
29
30 /* for perf_target__validate() */
31 PERF_ERRNO_TARGET__PID_OVERRIDE_CPU = __PERF_ERRNO_TARGET__START,
32 PERF_ERRNO_TARGET__PID_OVERRIDE_UID,
33 PERF_ERRNO_TARGET__UID_OVERRIDE_CPU,
34 PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM,
35 PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM,
36
37 /* for perf_target__parse_uid() */
38 PERF_ERRNO_TARGET__INVALID_UID,
39 PERF_ERRNO_TARGET__USER_NOT_FOUND,
40
41 __PERF_ERRNO_TARGET__END,
42};
43
44enum perf_target_errno perf_target__validate(struct perf_target *target);
45enum perf_target_errno perf_target__parse_uid(struct perf_target *target);
46
47int perf_target__strerror(struct perf_target *target, int errnum, char *buf,
48 size_t buflen);
49
50static inline bool perf_target__has_task(struct perf_target *target)
51{
52 return target->tid || target->pid || target->uid_str;
53}
54
55static inline bool perf_target__has_cpu(struct perf_target *target)
56{
57 return target->system_wide || target->cpu_list;
58}
59
60static inline bool perf_target__none(struct perf_target *target)
61{
62 return !perf_target__has_task(target) && !perf_target__has_cpu(target);
63}
64
65#endif /* _PERF_TARGET_H */
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index 84d9bd782004..9b5f856cc280 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -188,28 +188,27 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
188 nt = realloc(threads, (sizeof(*threads) + 188 nt = realloc(threads, (sizeof(*threads) +
189 sizeof(pid_t) * total_tasks)); 189 sizeof(pid_t) * total_tasks));
190 if (nt == NULL) 190 if (nt == NULL)
191 goto out_free_threads; 191 goto out_free_namelist;
192 192
193 threads = nt; 193 threads = nt;
194 194
195 if (threads) { 195 for (i = 0; i < items; i++) {
196 for (i = 0; i < items; i++) 196 threads->map[j++] = atoi(namelist[i]->d_name);
197 threads->map[j++] = atoi(namelist[i]->d_name);
198 threads->nr = total_tasks;
199 }
200
201 for (i = 0; i < items; i++)
202 free(namelist[i]); 197 free(namelist[i]);
198 }
199 threads->nr = total_tasks;
203 free(namelist); 200 free(namelist);
204
205 if (!threads)
206 break;
207 } 201 }
208 202
209out: 203out:
210 strlist__delete(slist); 204 strlist__delete(slist);
211 return threads; 205 return threads;
212 206
207out_free_namelist:
208 for (i = 0; i < items; i++)
209 free(namelist[i]);
210 free(namelist);
211
213out_free_threads: 212out_free_threads:
214 free(threads); 213 free(threads);
215 threads = NULL; 214 threads = NULL;
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index 7da80f14418b..f718df8a3c59 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -6,7 +6,7 @@
6 6
7struct thread_map { 7struct thread_map {
8 int nr; 8 int nr;
9 int map[]; 9 pid_t map[];
10}; 10};
11 11
12struct thread_map *thread_map__new_by_pid(pid_t pid); 12struct thread_map *thread_map__new_by_pid(pid_t pid);
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index 09fe579ccafb..abe0e8e95068 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -69,23 +69,24 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
69 69
70 ret += SNPRINTF(bf + ret, size - ret, "], "); 70 ret += SNPRINTF(bf + ret, size - ret, "], ");
71 71
72 if (top->target_pid) 72 if (top->target.pid)
73 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", 73 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s",
74 top->target_pid); 74 top->target.pid);
75 else if (top->target_tid) 75 else if (top->target.tid)
76 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", 76 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s",
77 top->target_tid); 77 top->target.tid);
78 else if (top->uid_str != NULL) 78 else if (top->target.uid_str != NULL)
79 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s", 79 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
80 top->uid_str); 80 top->target.uid_str);
81 else 81 else
82 ret += SNPRINTF(bf + ret, size - ret, " (all"); 82 ret += SNPRINTF(bf + ret, size - ret, " (all");
83 83
84 if (top->cpu_list) 84 if (top->target.cpu_list)
85 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", 85 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
86 top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list); 86 top->evlist->cpus->nr > 1 ? "s" : "",
87 top->target.cpu_list);
87 else { 88 else {
88 if (top->target_tid) 89 if (top->target.tid)
89 ret += SNPRINTF(bf + ret, size - ret, ")"); 90 ret += SNPRINTF(bf + ret, size - ret, ")");
90 else 91 else
91 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", 92 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index ce61cb2d1acf..33347ca89ee4 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -13,6 +13,7 @@ struct perf_session;
13struct perf_top { 13struct perf_top {
14 struct perf_tool tool; 14 struct perf_tool tool;
15 struct perf_evlist *evlist; 15 struct perf_evlist *evlist;
16 struct perf_target target;
16 /* 17 /*
17 * Symbols will be added here in perf_event__process_sample and will 18 * Symbols will be added here in perf_event__process_sample and will
18 * get out after decayed. 19 * get out after decayed.
@@ -23,10 +24,7 @@ struct perf_top {
23 u64 guest_us_samples, guest_kernel_samples; 24 u64 guest_us_samples, guest_kernel_samples;
24 int print_entries, count_filter, delay_secs; 25 int print_entries, count_filter, delay_secs;
25 int freq; 26 int freq;
26 const char *target_pid, *target_tid;
27 uid_t uid;
28 bool hide_kernel_symbols, hide_user_symbols, zero; 27 bool hide_kernel_symbols, hide_user_symbols, zero;
29 bool system_wide;
30 bool use_tui, use_stdio; 28 bool use_tui, use_stdio;
31 bool sort_has_symbols; 29 bool sort_has_symbols;
32 bool dont_use_callchains; 30 bool dont_use_callchains;
@@ -37,7 +35,6 @@ struct perf_top {
37 bool sample_id_all_missing; 35 bool sample_id_all_missing;
38 bool exclude_guest_missing; 36 bool exclude_guest_missing;
39 bool dump_symtab; 37 bool dump_symtab;
40 const char *cpu_list;
41 struct hist_entry *sym_filter_entry; 38 struct hist_entry *sym_filter_entry;
42 struct perf_evsel *sym_evsel; 39 struct perf_evsel *sym_evsel;
43 struct perf_session *session; 40 struct perf_session *session;
@@ -47,7 +44,6 @@ struct perf_top {
47 int realtime_prio; 44 int realtime_prio;
48 int sym_pcnt_filter; 45 int sym_pcnt_filter;
49 const char *sym_filter; 46 const char *sym_filter;
50 const char *uid_str;
51}; 47};
52 48
53size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); 49size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index fc22cf5c605f..a8d81c35ef66 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -68,7 +68,7 @@ struct events {
68}; 68};
69 69
70 70
71void *malloc_or_die(unsigned int size) 71static void *malloc_or_die(unsigned int size)
72{ 72{
73 void *data; 73 void *data;
74 74
@@ -448,6 +448,8 @@ static void tracing_data_header(void)
448 else 448 else
449 buf[0] = 0; 449 buf[0] = 0;
450 450
451 read_trace_init(buf[0], buf[0]);
452
451 write_or_die(buf, 1); 453 write_or_die(buf, 1);
452 454
453 /* save size of long */ 455 /* save size of long */
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index dfd1bd8371a4..df2fddbf0cd2 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -17,2169 +17,305 @@
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * 18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 *
21 * The parts for function graph printing was taken and modified from the
22 * Linux Kernel that were written by Frederic Weisbecker.
23 */ 20 */
24
25#include <stdio.h> 21#include <stdio.h>
26#include <stdlib.h> 22#include <stdlib.h>
27#include <string.h> 23#include <string.h>
24#include <ctype.h>
28#include <errno.h> 25#include <errno.h>
29 26
30#include "../perf.h" 27#include "../perf.h"
31#include "util.h" 28#include "util.h"
32#include "trace-event.h" 29#include "trace-event.h"
33 30
34int header_page_ts_offset;
35int header_page_ts_size;
36int header_page_size_offset;
37int header_page_size_size; 31int header_page_size_size;
38int header_page_overwrite_offset; 32int header_page_ts_size;
39int header_page_overwrite_size;
40int header_page_data_offset; 33int header_page_data_offset;
41int header_page_data_size;
42
43bool latency_format;
44
45static char *input_buf;
46static unsigned long long input_buf_ptr;
47static unsigned long long input_buf_siz;
48
49static int cpus;
50static int long_size;
51static int is_flag_field;
52static int is_symbolic_field;
53
54static struct format_field *
55find_any_field(struct event *event, const char *name);
56
57static void init_input_buf(char *buf, unsigned long long size)
58{
59 input_buf = buf;
60 input_buf_siz = size;
61 input_buf_ptr = 0;
62}
63
64struct cmdline {
65 char *comm;
66 int pid;
67};
68
69static struct cmdline *cmdlines;
70static int cmdline_count;
71
72static int cmdline_cmp(const void *a, const void *b)
73{
74 const struct cmdline *ca = a;
75 const struct cmdline *cb = b;
76
77 if (ca->pid < cb->pid)
78 return -1;
79 if (ca->pid > cb->pid)
80 return 1;
81
82 return 0;
83}
84 34
85void parse_cmdlines(char *file, int size __unused) 35struct pevent *perf_pevent;
86{ 36static struct pevent *pevent;
87 struct cmdline_list {
88 struct cmdline_list *next;
89 char *comm;
90 int pid;
91 } *list = NULL, *item;
92 char *line;
93 char *next = NULL;
94 int i;
95 37
96 line = strtok_r(file, "\n", &next); 38bool latency_format;
97 while (line) {
98 item = malloc_or_die(sizeof(*item));
99 sscanf(line, "%d %as", &item->pid,
100 (float *)(void *)&item->comm); /* workaround gcc warning */
101 item->next = list;
102 list = item;
103 line = strtok_r(NULL, "\n", &next);
104 cmdline_count++;
105 }
106
107 cmdlines = malloc_or_die(sizeof(*cmdlines) * cmdline_count);
108
109 i = 0;
110 while (list) {
111 cmdlines[i].pid = list->pid;
112 cmdlines[i].comm = list->comm;
113 i++;
114 item = list;
115 list = list->next;
116 free(item);
117 }
118
119 qsort(cmdlines, cmdline_count, sizeof(*cmdlines), cmdline_cmp);
120}
121
122static struct func_map {
123 unsigned long long addr;
124 char *func;
125 char *mod;
126} *func_list;
127static unsigned int func_count;
128
129static int func_cmp(const void *a, const void *b)
130{
131 const struct func_map *fa = a;
132 const struct func_map *fb = b;
133
134 if (fa->addr < fb->addr)
135 return -1;
136 if (fa->addr > fb->addr)
137 return 1;
138
139 return 0;
140}
141
142void parse_proc_kallsyms(char *file, unsigned int size __unused)
143{
144 struct func_list {
145 struct func_list *next;
146 unsigned long long addr;
147 char *func;
148 char *mod;
149 } *list = NULL, *item;
150 char *line;
151 char *next = NULL;
152 char *addr_str;
153 char ch;
154 int ret __used;
155 int i;
156
157 line = strtok_r(file, "\n", &next);
158 while (line) {
159 item = malloc_or_die(sizeof(*item));
160 item->mod = NULL;
161 ret = sscanf(line, "%as %c %as\t[%as",
162 (float *)(void *)&addr_str, /* workaround gcc warning */
163 &ch,
164 (float *)(void *)&item->func,
165 (float *)(void *)&item->mod);
166 item->addr = strtoull(addr_str, NULL, 16);
167 free(addr_str);
168
169 /* truncate the extra ']' */
170 if (item->mod)
171 item->mod[strlen(item->mod) - 1] = 0;
172
173
174 item->next = list;
175 list = item;
176 line = strtok_r(NULL, "\n", &next);
177 func_count++;
178 }
179
180 func_list = malloc_or_die(sizeof(*func_list) * (func_count + 1));
181
182 i = 0;
183 while (list) {
184 func_list[i].func = list->func;
185 func_list[i].addr = list->addr;
186 func_list[i].mod = list->mod;
187 i++;
188 item = list;
189 list = list->next;
190 free(item);
191 }
192
193 qsort(func_list, func_count, sizeof(*func_list), func_cmp);
194
195 /*
196 * Add a special record at the end.
197 */
198 func_list[func_count].func = NULL;
199 func_list[func_count].addr = 0;
200 func_list[func_count].mod = NULL;
201}
202 39
203/* 40int read_trace_init(int file_bigendian, int host_bigendian)
204 * We are searching for a record in between, not an exact
205 * match.
206 */
207static int func_bcmp(const void *a, const void *b)
208{ 41{
209 const struct func_map *fa = a; 42 if (pevent)
210 const struct func_map *fb = b;
211
212 if ((fa->addr == fb->addr) ||
213
214 (fa->addr > fb->addr &&
215 fa->addr < (fb+1)->addr))
216 return 0; 43 return 0;
217 44
218 if (fa->addr < fb->addr) 45 perf_pevent = pevent_alloc();
219 return -1; 46 pevent = perf_pevent;
220
221 return 1;
222}
223
224static struct func_map *find_func(unsigned long long addr)
225{
226 struct func_map *func;
227 struct func_map key;
228
229 key.addr = addr;
230
231 func = bsearch(&key, func_list, func_count, sizeof(*func_list),
232 func_bcmp);
233
234 return func;
235}
236
237void print_funcs(void)
238{
239 int i;
240
241 for (i = 0; i < (int)func_count; i++) {
242 printf("%016llx %s",
243 func_list[i].addr,
244 func_list[i].func);
245 if (func_list[i].mod)
246 printf(" [%s]\n", func_list[i].mod);
247 else
248 printf("\n");
249 }
250}
251 47
252static struct printk_map { 48 pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
253 unsigned long long addr; 49 pevent_set_file_bigendian(pevent, file_bigendian);
254 char *printk; 50 pevent_set_host_bigendian(pevent, host_bigendian);
255} *printk_list;
256static unsigned int printk_count;
257
258static int printk_cmp(const void *a, const void *b)
259{
260 const struct func_map *fa = a;
261 const struct func_map *fb = b;
262
263 if (fa->addr < fb->addr)
264 return -1;
265 if (fa->addr > fb->addr)
266 return 1;
267 51
268 return 0; 52 return 0;
269} 53}
270 54
271static struct printk_map *find_printk(unsigned long long addr) 55static int get_common_field(struct scripting_context *context,
272{ 56 int *offset, int *size, const char *type)
273 struct printk_map *printk;
274 struct printk_map key;
275
276 key.addr = addr;
277
278 printk = bsearch(&key, printk_list, printk_count, sizeof(*printk_list),
279 printk_cmp);
280
281 return printk;
282}
283
284void parse_ftrace_printk(char *file, unsigned int size __unused)
285{
286 struct printk_list {
287 struct printk_list *next;
288 unsigned long long addr;
289 char *printk;
290 } *list = NULL, *item;
291 char *line;
292 char *next = NULL;
293 char *addr_str;
294 int i;
295
296 line = strtok_r(file, "\n", &next);
297 while (line) {
298 addr_str = strsep(&line, ":");
299 if (!line) {
300 warning("error parsing print strings");
301 break;
302 }
303 item = malloc_or_die(sizeof(*item));
304 item->addr = strtoull(addr_str, NULL, 16);
305 /* fmt still has a space, skip it */
306 item->printk = strdup(line+1);
307 item->next = list;
308 list = item;
309 line = strtok_r(NULL, "\n", &next);
310 printk_count++;
311 }
312
313 printk_list = malloc_or_die(sizeof(*printk_list) * printk_count + 1);
314
315 i = 0;
316 while (list) {
317 printk_list[i].printk = list->printk;
318 printk_list[i].addr = list->addr;
319 i++;
320 item = list;
321 list = list->next;
322 free(item);
323 }
324
325 qsort(printk_list, printk_count, sizeof(*printk_list), printk_cmp);
326}
327
328void print_printk(void)
329{
330 int i;
331
332 for (i = 0; i < (int)printk_count; i++) {
333 printf("%016llx %s\n",
334 printk_list[i].addr,
335 printk_list[i].printk);
336 }
337}
338
339static struct event *alloc_event(void)
340{
341 struct event *event;
342
343 event = malloc_or_die(sizeof(*event));
344 memset(event, 0, sizeof(*event));
345
346 return event;
347}
348
349enum event_type {
350 EVENT_ERROR,
351 EVENT_NONE,
352 EVENT_SPACE,
353 EVENT_NEWLINE,
354 EVENT_OP,
355 EVENT_DELIM,
356 EVENT_ITEM,
357 EVENT_DQUOTE,
358 EVENT_SQUOTE,
359};
360
361static struct event *event_list;
362
363static void add_event(struct event *event)
364{ 57{
365 event->next = event_list; 58 struct event_format *event;
366 event_list = event; 59 struct format_field *field;
367}
368
369static int event_item_type(enum event_type type)
370{
371 switch (type) {
372 case EVENT_ITEM ... EVENT_SQUOTE:
373 return 1;
374 case EVENT_ERROR ... EVENT_DELIM:
375 default:
376 return 0;
377 }
378}
379
380static void free_arg(struct print_arg *arg)
381{
382 if (!arg)
383 return;
384
385 switch (arg->type) {
386 case PRINT_ATOM:
387 if (arg->atom.atom)
388 free(arg->atom.atom);
389 break;
390 case PRINT_NULL:
391 case PRINT_FIELD ... PRINT_OP:
392 default:
393 /* todo */
394 break;
395 }
396
397 free(arg);
398}
399
400static enum event_type get_type(int ch)
401{
402 if (ch == '\n')
403 return EVENT_NEWLINE;
404 if (isspace(ch))
405 return EVENT_SPACE;
406 if (isalnum(ch) || ch == '_')
407 return EVENT_ITEM;
408 if (ch == '\'')
409 return EVENT_SQUOTE;
410 if (ch == '"')
411 return EVENT_DQUOTE;
412 if (!isprint(ch))
413 return EVENT_NONE;
414 if (ch == '(' || ch == ')' || ch == ',')
415 return EVENT_DELIM;
416
417 return EVENT_OP;
418}
419
420static int __read_char(void)
421{
422 if (input_buf_ptr >= input_buf_siz)
423 return -1;
424
425 return input_buf[input_buf_ptr++];
426}
427
428static int __peek_char(void)
429{
430 if (input_buf_ptr >= input_buf_siz)
431 return -1;
432
433 return input_buf[input_buf_ptr];
434}
435
436static enum event_type __read_token(char **tok)
437{
438 char buf[BUFSIZ];
439 int ch, last_ch, quote_ch, next_ch;
440 int i = 0;
441 int tok_size = 0;
442 enum event_type type;
443
444 *tok = NULL;
445
446
447 ch = __read_char();
448 if (ch < 0)
449 return EVENT_NONE;
450
451 type = get_type(ch);
452 if (type == EVENT_NONE)
453 return type;
454
455 buf[i++] = ch;
456
457 switch (type) {
458 case EVENT_NEWLINE:
459 case EVENT_DELIM:
460 *tok = malloc_or_die(2);
461 (*tok)[0] = ch;
462 (*tok)[1] = 0;
463 return type;
464
465 case EVENT_OP:
466 switch (ch) {
467 case '-':
468 next_ch = __peek_char();
469 if (next_ch == '>') {
470 buf[i++] = __read_char();
471 break;
472 }
473 /* fall through */
474 case '+':
475 case '|':
476 case '&':
477 case '>':
478 case '<':
479 last_ch = ch;
480 ch = __peek_char();
481 if (ch != last_ch)
482 goto test_equal;
483 buf[i++] = __read_char();
484 switch (last_ch) {
485 case '>':
486 case '<':
487 goto test_equal;
488 default:
489 break;
490 }
491 break;
492 case '!':
493 case '=':
494 goto test_equal;
495 default: /* what should we do instead? */
496 break;
497 }
498 buf[i] = 0;
499 *tok = strdup(buf);
500 return type;
501
502 test_equal:
503 ch = __peek_char();
504 if (ch == '=')
505 buf[i++] = __read_char();
506 break;
507
508 case EVENT_DQUOTE:
509 case EVENT_SQUOTE:
510 /* don't keep quotes */
511 i--;
512 quote_ch = ch;
513 last_ch = 0;
514 do {
515 if (i == (BUFSIZ - 1)) {
516 buf[i] = 0;
517 if (*tok) {
518 *tok = realloc(*tok, tok_size + BUFSIZ);
519 if (!*tok)
520 return EVENT_NONE;
521 strcat(*tok, buf);
522 } else
523 *tok = strdup(buf);
524
525 if (!*tok)
526 return EVENT_NONE;
527 tok_size += BUFSIZ;
528 i = 0;
529 }
530 last_ch = ch;
531 ch = __read_char();
532 buf[i++] = ch;
533 /* the '\' '\' will cancel itself */
534 if (ch == '\\' && last_ch == '\\')
535 last_ch = 0;
536 } while (ch != quote_ch || last_ch == '\\');
537 /* remove the last quote */
538 i--;
539 goto out;
540
541 case EVENT_ERROR ... EVENT_SPACE:
542 case EVENT_ITEM:
543 default:
544 break;
545 }
546
547 while (get_type(__peek_char()) == type) {
548 if (i == (BUFSIZ - 1)) {
549 buf[i] = 0;
550 if (*tok) {
551 *tok = realloc(*tok, tok_size + BUFSIZ);
552 if (!*tok)
553 return EVENT_NONE;
554 strcat(*tok, buf);
555 } else
556 *tok = strdup(buf);
557
558 if (!*tok)
559 return EVENT_NONE;
560 tok_size += BUFSIZ;
561 i = 0;
562 }
563 ch = __read_char();
564 buf[i++] = ch;
565 }
566
567 out:
568 buf[i] = 0;
569 if (*tok) {
570 *tok = realloc(*tok, tok_size + i);
571 if (!*tok)
572 return EVENT_NONE;
573 strcat(*tok, buf);
574 } else
575 *tok = strdup(buf);
576 if (!*tok)
577 return EVENT_NONE;
578
579 return type;
580}
581
582static void free_token(char *tok)
583{
584 if (tok)
585 free(tok);
586}
587
588static enum event_type read_token(char **tok)
589{
590 enum event_type type;
591
592 for (;;) {
593 type = __read_token(tok);
594 if (type != EVENT_SPACE)
595 return type;
596
597 free_token(*tok);
598 }
599
600 /* not reached */
601 return EVENT_NONE;
602}
603
604/* no newline */
605static enum event_type read_token_item(char **tok)
606{
607 enum event_type type;
608
609 for (;;) {
610 type = __read_token(tok);
611 if (type != EVENT_SPACE && type != EVENT_NEWLINE)
612 return type;
613
614 free_token(*tok);
615 }
616
617 /* not reached */
618 return EVENT_NONE;
619}
620
621static int test_type(enum event_type type, enum event_type expect)
622{
623 if (type != expect) {
624 warning("Error: expected type %d but read %d",
625 expect, type);
626 return -1;
627 }
628 return 0;
629}
630 60
631static int __test_type_token(enum event_type type, char *token, 61 if (!*size) {
632 enum event_type expect, const char *expect_tok, 62 if (!pevent->events)
633 bool warn) 63 return 0;
634{
635 if (type != expect) {
636 if (warn)
637 warning("Error: expected type %d but read %d",
638 expect, type);
639 return -1;
640 }
641 64
642 if (strcmp(token, expect_tok) != 0) { 65 event = pevent->events[0];
643 if (warn) 66 field = pevent_find_common_field(event, type);
644 warning("Error: expected '%s' but read '%s'", 67 if (!field)
645 expect_tok, token); 68 return 0;
646 return -1; 69 *offset = field->offset;
70 *size = field->size;
647 } 71 }
648 return 0;
649}
650 72
651static int test_type_token(enum event_type type, char *token, 73 return pevent_read_number(pevent, context->event_data + *offset, *size);
652 enum event_type expect, const char *expect_tok)
653{
654 return __test_type_token(type, token, expect, expect_tok, true);
655} 74}
656 75
657static int __read_expect_type(enum event_type expect, char **tok, int newline_ok) 76int common_lock_depth(struct scripting_context *context)
658{
659 enum event_type type;
660
661 if (newline_ok)
662 type = read_token(tok);
663 else
664 type = read_token_item(tok);
665 return test_type(type, expect);
666}
667
668static int read_expect_type(enum event_type expect, char **tok)
669{
670 return __read_expect_type(expect, tok, 1);
671}
672
673static int __read_expected(enum event_type expect, const char *str,
674 int newline_ok, bool warn)
675{ 77{
676 enum event_type type; 78 static int offset;
677 char *token; 79 static int size;
678 int ret; 80 int ret;
679 81
680 if (newline_ok) 82 ret = get_common_field(context, &size, &offset,
681 type = read_token(&token); 83 "common_lock_depth");
682 else 84 if (ret < 0)
683 type = read_token_item(&token); 85 return -1;
684
685 ret = __test_type_token(type, token, expect, str, warn);
686
687 free_token(token);
688 86
689 return ret; 87 return ret;
690} 88}
691 89
692static int read_expected(enum event_type expect, const char *str) 90int common_flags(struct scripting_context *context)
693{
694 return __read_expected(expect, str, 1, true);
695}
696
697static int read_expected_item(enum event_type expect, const char *str)
698{
699 return __read_expected(expect, str, 0, true);
700}
701
702static char *event_read_name(void)
703{
704 char *token;
705
706 if (read_expected(EVENT_ITEM, "name") < 0)
707 return NULL;
708
709 if (read_expected(EVENT_OP, ":") < 0)
710 return NULL;
711
712 if (read_expect_type(EVENT_ITEM, &token) < 0)
713 goto fail;
714
715 return token;
716
717 fail:
718 free_token(token);
719 return NULL;
720}
721
722static int event_read_id(void)
723{ 91{
724 char *token; 92 static int offset;
725 int id = -1; 93 static int size;
726 94 int ret;
727 if (read_expected_item(EVENT_ITEM, "ID") < 0)
728 return -1;
729 95
730 if (read_expected(EVENT_OP, ":") < 0) 96 ret = get_common_field(context, &size, &offset,
97 "common_flags");
98 if (ret < 0)
731 return -1; 99 return -1;
732 100
733 if (read_expect_type(EVENT_ITEM, &token) < 0) 101 return ret;
734 goto free;
735
736 id = strtoul(token, NULL, 0);
737
738 free:
739 free_token(token);
740 return id;
741}
742
743static int field_is_string(struct format_field *field)
744{
745 if ((field->flags & FIELD_IS_ARRAY) &&
746 (!strstr(field->type, "char") || !strstr(field->type, "u8") ||
747 !strstr(field->type, "s8")))
748 return 1;
749
750 return 0;
751}
752
753static int field_is_dynamic(struct format_field *field)
754{
755 if (!strncmp(field->type, "__data_loc", 10))
756 return 1;
757
758 return 0;
759}
760
761static int event_read_fields(struct event *event, struct format_field **fields)
762{
763 struct format_field *field = NULL;
764 enum event_type type;
765 char *token;
766 char *last_token;
767 int count = 0;
768
769 do {
770 type = read_token(&token);
771 if (type == EVENT_NEWLINE) {
772 free_token(token);
773 return count;
774 }
775
776 count++;
777
778 if (test_type_token(type, token, EVENT_ITEM, "field"))
779 goto fail;
780 free_token(token);
781
782 type = read_token(&token);
783 /*
784 * The ftrace fields may still use the "special" name.
785 * Just ignore it.
786 */
787 if (event->flags & EVENT_FL_ISFTRACE &&
788 type == EVENT_ITEM && strcmp(token, "special") == 0) {
789 free_token(token);
790 type = read_token(&token);
791 }
792
793 if (test_type_token(type, token, EVENT_OP, ":") < 0)
794 return -1;
795
796 if (read_expect_type(EVENT_ITEM, &token) < 0)
797 goto fail;
798
799 last_token = token;
800
801 field = malloc_or_die(sizeof(*field));
802 memset(field, 0, sizeof(*field));
803
804 /* read the rest of the type */
805 for (;;) {
806 type = read_token(&token);
807 if (type == EVENT_ITEM ||
808 (type == EVENT_OP && strcmp(token, "*") == 0) ||
809 /*
810 * Some of the ftrace fields are broken and have
811 * an illegal "." in them.
812 */
813 (event->flags & EVENT_FL_ISFTRACE &&
814 type == EVENT_OP && strcmp(token, ".") == 0)) {
815
816 if (strcmp(token, "*") == 0)
817 field->flags |= FIELD_IS_POINTER;
818
819 if (field->type) {
820 field->type = realloc(field->type,
821 strlen(field->type) +
822 strlen(last_token) + 2);
823 strcat(field->type, " ");
824 strcat(field->type, last_token);
825 } else
826 field->type = last_token;
827 last_token = token;
828 continue;
829 }
830
831 break;
832 }
833
834 if (!field->type) {
835 die("no type found");
836 goto fail;
837 }
838 field->name = last_token;
839
840 if (test_type(type, EVENT_OP))
841 goto fail;
842
843 if (strcmp(token, "[") == 0) {
844 enum event_type last_type = type;
845 char *brackets = token;
846 int len;
847
848 field->flags |= FIELD_IS_ARRAY;
849
850 type = read_token(&token);
851 while (strcmp(token, "]") != 0) {
852 if (last_type == EVENT_ITEM &&
853 type == EVENT_ITEM)
854 len = 2;
855 else
856 len = 1;
857 last_type = type;
858
859 brackets = realloc(brackets,
860 strlen(brackets) +
861 strlen(token) + len);
862 if (len == 2)
863 strcat(brackets, " ");
864 strcat(brackets, token);
865 free_token(token);
866 type = read_token(&token);
867 if (type == EVENT_NONE) {
868 die("failed to find token");
869 goto fail;
870 }
871 }
872
873 free_token(token);
874
875 brackets = realloc(brackets, strlen(brackets) + 2);
876 strcat(brackets, "]");
877
878 /* add brackets to type */
879
880 type = read_token(&token);
881 /*
882 * If the next token is not an OP, then it is of
883 * the format: type [] item;
884 */
885 if (type == EVENT_ITEM) {
886 field->type = realloc(field->type,
887 strlen(field->type) +
888 strlen(field->name) +
889 strlen(brackets) + 2);
890 strcat(field->type, " ");
891 strcat(field->type, field->name);
892 free_token(field->name);
893 strcat(field->type, brackets);
894 field->name = token;
895 type = read_token(&token);
896 } else {
897 field->type = realloc(field->type,
898 strlen(field->type) +
899 strlen(brackets) + 1);
900 strcat(field->type, brackets);
901 }
902 free(brackets);
903 }
904
905 if (field_is_string(field)) {
906 field->flags |= FIELD_IS_STRING;
907 if (field_is_dynamic(field))
908 field->flags |= FIELD_IS_DYNAMIC;
909 }
910
911 if (test_type_token(type, token, EVENT_OP, ";"))
912 goto fail;
913 free_token(token);
914
915 if (read_expected(EVENT_ITEM, "offset") < 0)
916 goto fail_expect;
917
918 if (read_expected(EVENT_OP, ":") < 0)
919 goto fail_expect;
920
921 if (read_expect_type(EVENT_ITEM, &token))
922 goto fail;
923 field->offset = strtoul(token, NULL, 0);
924 free_token(token);
925
926 if (read_expected(EVENT_OP, ";") < 0)
927 goto fail_expect;
928
929 if (read_expected(EVENT_ITEM, "size") < 0)
930 goto fail_expect;
931
932 if (read_expected(EVENT_OP, ":") < 0)
933 goto fail_expect;
934
935 if (read_expect_type(EVENT_ITEM, &token))
936 goto fail;
937 field->size = strtoul(token, NULL, 0);
938 free_token(token);
939
940 if (read_expected(EVENT_OP, ";") < 0)
941 goto fail_expect;
942
943 type = read_token(&token);
944 if (type != EVENT_NEWLINE) {
945 /* newer versions of the kernel have a "signed" type */
946 if (test_type_token(type, token, EVENT_ITEM, "signed"))
947 goto fail;
948
949 free_token(token);
950
951 if (read_expected(EVENT_OP, ":") < 0)
952 goto fail_expect;
953
954 if (read_expect_type(EVENT_ITEM, &token))
955 goto fail;
956
957 if (strtoul(token, NULL, 0))
958 field->flags |= FIELD_IS_SIGNED;
959
960 free_token(token);
961 if (read_expected(EVENT_OP, ";") < 0)
962 goto fail_expect;
963
964 if (read_expect_type(EVENT_NEWLINE, &token))
965 goto fail;
966 }
967
968 free_token(token);
969
970 *fields = field;
971 fields = &field->next;
972
973 } while (1);
974
975 return 0;
976
977fail:
978 free_token(token);
979fail_expect:
980 if (field)
981 free(field);
982 return -1;
983} 102}
984 103
985static int event_read_format(struct event *event) 104int common_pc(struct scripting_context *context)
986{ 105{
987 char *token; 106 static int offset;
107 static int size;
988 int ret; 108 int ret;
989 109
990 if (read_expected_item(EVENT_ITEM, "format") < 0) 110 ret = get_common_field(context, &size, &offset,
991 return -1; 111 "common_preempt_count");
992
993 if (read_expected(EVENT_OP, ":") < 0)
994 return -1;
995
996 if (read_expect_type(EVENT_NEWLINE, &token))
997 goto fail;
998 free_token(token);
999
1000 ret = event_read_fields(event, &event->format.common_fields);
1001 if (ret < 0) 112 if (ret < 0)
1002 return ret; 113 return -1;
1003 event->format.nr_common = ret;
1004
1005 ret = event_read_fields(event, &event->format.fields);
1006 if (ret < 0)
1007 return ret;
1008 event->format.nr_fields = ret;
1009
1010 return 0;
1011
1012 fail:
1013 free_token(token);
1014 return -1;
1015}
1016
1017enum event_type
1018process_arg_token(struct event *event, struct print_arg *arg,
1019 char **tok, enum event_type type);
1020
1021static enum event_type
1022process_arg(struct event *event, struct print_arg *arg, char **tok)
1023{
1024 enum event_type type;
1025 char *token;
1026
1027 type = read_token(&token);
1028 *tok = token;
1029 114
1030 return process_arg_token(event, arg, tok, type); 115 return ret;
1031} 116}
1032 117
1033static enum event_type 118unsigned long long
1034process_cond(struct event *event, struct print_arg *top, char **tok) 119raw_field_value(struct event_format *event, const char *name, void *data)
1035{ 120{
1036 struct print_arg *arg, *left, *right; 121 struct format_field *field;
1037 enum event_type type; 122 unsigned long long val;
1038 char *token = NULL;
1039
1040 arg = malloc_or_die(sizeof(*arg));
1041 memset(arg, 0, sizeof(*arg));
1042
1043 left = malloc_or_die(sizeof(*left));
1044
1045 right = malloc_or_die(sizeof(*right));
1046
1047 arg->type = PRINT_OP;
1048 arg->op.left = left;
1049 arg->op.right = right;
1050
1051 *tok = NULL;
1052 type = process_arg(event, left, &token);
1053 if (test_type_token(type, token, EVENT_OP, ":"))
1054 goto out_free;
1055
1056 arg->op.op = token;
1057
1058 type = process_arg(event, right, &token);
1059 123
1060 top->op.right = arg; 124 field = pevent_find_any_field(event, name);
125 if (!field)
126 return 0ULL;
1061 127
1062 *tok = token; 128 pevent_read_number_field(field, data, &val);
1063 return type;
1064 129
1065out_free: 130 return val;
1066 free_token(*tok);
1067 free(right);
1068 free(left);
1069 free_arg(arg);
1070 return EVENT_ERROR;
1071} 131}
1072 132
1073static enum event_type 133void *raw_field_ptr(struct event_format *event, const char *name, void *data)
1074process_array(struct event *event, struct print_arg *top, char **tok)
1075{ 134{
1076 struct print_arg *arg; 135 struct format_field *field;
1077 enum event_type type;
1078 char *token = NULL;
1079
1080 arg = malloc_or_die(sizeof(*arg));
1081 memset(arg, 0, sizeof(*arg));
1082
1083 *tok = NULL;
1084 type = process_arg(event, arg, &token);
1085 if (test_type_token(type, token, EVENT_OP, "]"))
1086 goto out_free;
1087
1088 top->op.right = arg;
1089
1090 free_token(token);
1091 type = read_token_item(&token);
1092 *tok = token;
1093
1094 return type;
1095 136
1096out_free: 137 field = pevent_find_any_field(event, name);
1097 free_token(*tok); 138 if (!field)
1098 free_arg(arg); 139 return NULL;
1099 return EVENT_ERROR;
1100}
1101 140
1102static int get_op_prio(char *op) 141 if (field->flags & FIELD_IS_DYNAMIC) {
1103{ 142 int offset;
1104 if (!op[1]) {
1105 switch (op[0]) {
1106 case '*':
1107 case '/':
1108 case '%':
1109 return 6;
1110 case '+':
1111 case '-':
1112 return 7;
1113 /* '>>' and '<<' are 8 */
1114 case '<':
1115 case '>':
1116 return 9;
1117 /* '==' and '!=' are 10 */
1118 case '&':
1119 return 11;
1120 case '^':
1121 return 12;
1122 case '|':
1123 return 13;
1124 case '?':
1125 return 16;
1126 default:
1127 die("unknown op '%c'", op[0]);
1128 return -1;
1129 }
1130 } else {
1131 if (strcmp(op, "++") == 0 ||
1132 strcmp(op, "--") == 0) {
1133 return 3;
1134 } else if (strcmp(op, ">>") == 0 ||
1135 strcmp(op, "<<") == 0) {
1136 return 8;
1137 } else if (strcmp(op, ">=") == 0 ||
1138 strcmp(op, "<=") == 0) {
1139 return 9;
1140 } else if (strcmp(op, "==") == 0 ||
1141 strcmp(op, "!=") == 0) {
1142 return 10;
1143 } else if (strcmp(op, "&&") == 0) {
1144 return 14;
1145 } else if (strcmp(op, "||") == 0) {
1146 return 15;
1147 } else {
1148 die("unknown op '%s'", op);
1149 return -1;
1150 }
1151 }
1152}
1153 143
1154static void set_op_prio(struct print_arg *arg) 144 offset = *(int *)(data + field->offset);
1155{ 145 offset &= 0xffff;
1156 146
1157 /* single ops are the greatest */ 147 return data + offset;
1158 if (!arg->op.left || arg->op.left->type == PRINT_NULL) {
1159 arg->op.prio = 0;
1160 return;
1161 } 148 }
1162 149
1163 arg->op.prio = get_op_prio(arg->op.op); 150 return data + field->offset;
1164} 151}
1165 152
1166static enum event_type 153int trace_parse_common_type(void *data)
1167process_op(struct event *event, struct print_arg *arg, char **tok)
1168{ 154{
1169 struct print_arg *left, *right = NULL; 155 struct pevent_record record;
1170 enum event_type type;
1171 char *token;
1172
1173 /* the op is passed in via tok */
1174 token = *tok;
1175
1176 if (arg->type == PRINT_OP && !arg->op.left) {
1177 /* handle single op */
1178 if (token[1]) {
1179 die("bad op token %s", token);
1180 return EVENT_ERROR;
1181 }
1182 switch (token[0]) {
1183 case '!':
1184 case '+':
1185 case '-':
1186 break;
1187 default:
1188 die("bad op token %s", token);
1189 return EVENT_ERROR;
1190 }
1191
1192 /* make an empty left */
1193 left = malloc_or_die(sizeof(*left));
1194 left->type = PRINT_NULL;
1195 arg->op.left = left;
1196
1197 right = malloc_or_die(sizeof(*right));
1198 arg->op.right = right;
1199
1200 type = process_arg(event, right, tok);
1201
1202 } else if (strcmp(token, "?") == 0) {
1203
1204 left = malloc_or_die(sizeof(*left));
1205 /* copy the top arg to the left */
1206 *left = *arg;
1207
1208 arg->type = PRINT_OP;
1209 arg->op.op = token;
1210 arg->op.left = left;
1211 arg->op.prio = 0;
1212
1213 type = process_cond(event, arg, tok);
1214
1215 } else if (strcmp(token, ">>") == 0 ||
1216 strcmp(token, "<<") == 0 ||
1217 strcmp(token, "&") == 0 ||
1218 strcmp(token, "|") == 0 ||
1219 strcmp(token, "&&") == 0 ||
1220 strcmp(token, "||") == 0 ||
1221 strcmp(token, "-") == 0 ||
1222 strcmp(token, "+") == 0 ||
1223 strcmp(token, "*") == 0 ||
1224 strcmp(token, "^") == 0 ||
1225 strcmp(token, "/") == 0 ||
1226 strcmp(token, "<") == 0 ||
1227 strcmp(token, ">") == 0 ||
1228 strcmp(token, "==") == 0 ||
1229 strcmp(token, "!=") == 0) {
1230
1231 left = malloc_or_die(sizeof(*left));
1232
1233 /* copy the top arg to the left */
1234 *left = *arg;
1235
1236 arg->type = PRINT_OP;
1237 arg->op.op = token;
1238 arg->op.left = left;
1239
1240 set_op_prio(arg);
1241
1242 right = malloc_or_die(sizeof(*right));
1243
1244 type = read_token_item(&token);
1245 *tok = token;
1246
1247 /* could just be a type pointer */
1248 if ((strcmp(arg->op.op, "*") == 0) &&
1249 type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
1250 if (left->type != PRINT_ATOM)
1251 die("bad pointer type");
1252 left->atom.atom = realloc(left->atom.atom,
1253 sizeof(left->atom.atom) + 3);
1254 strcat(left->atom.atom, " *");
1255 *arg = *left;
1256 free(arg);
1257
1258 return type;
1259 }
1260
1261 type = process_arg_token(event, right, tok, type);
1262
1263 arg->op.right = right;
1264
1265 } else if (strcmp(token, "[") == 0) {
1266
1267 left = malloc_or_die(sizeof(*left));
1268 *left = *arg;
1269
1270 arg->type = PRINT_OP;
1271 arg->op.op = token;
1272 arg->op.left = left;
1273
1274 arg->op.prio = 0;
1275 type = process_array(event, arg, tok);
1276
1277 } else {
1278 warning("unknown op '%s'", token);
1279 event->flags |= EVENT_FL_FAILED;
1280 /* the arg is now the left side */
1281 return EVENT_NONE;
1282 }
1283
1284 if (type == EVENT_OP) {
1285 int prio;
1286
1287 /* higher prios need to be closer to the root */
1288 prio = get_op_prio(*tok);
1289
1290 if (prio > arg->op.prio)
1291 return process_op(event, arg, tok);
1292 156
1293 return process_op(event, right, tok); 157 record.data = data;
1294 } 158 return pevent_data_type(pevent, &record);
1295
1296 return type;
1297} 159}
1298 160
1299static enum event_type 161int trace_parse_common_pid(void *data)
1300process_entry(struct event *event __unused, struct print_arg *arg,
1301 char **tok)
1302{ 162{
1303 enum event_type type; 163 struct pevent_record record;
1304 char *field;
1305 char *token;
1306
1307 if (read_expected(EVENT_OP, "->") < 0)
1308 return EVENT_ERROR;
1309
1310 if (read_expect_type(EVENT_ITEM, &token) < 0)
1311 goto fail;
1312 field = token;
1313
1314 arg->type = PRINT_FIELD;
1315 arg->field.name = field;
1316
1317 if (is_flag_field) {
1318 arg->field.field = find_any_field(event, arg->field.name);
1319 arg->field.field->flags |= FIELD_IS_FLAG;
1320 is_flag_field = 0;
1321 } else if (is_symbolic_field) {
1322 arg->field.field = find_any_field(event, arg->field.name);
1323 arg->field.field->flags |= FIELD_IS_SYMBOLIC;
1324 is_symbolic_field = 0;
1325 }
1326
1327 type = read_token(&token);
1328 *tok = token;
1329 164
1330 return type; 165 record.data = data;
1331 166 return pevent_data_pid(pevent, &record);
1332fail:
1333 free_token(token);
1334 return EVENT_ERROR;
1335} 167}
1336 168
1337static char *arg_eval (struct print_arg *arg); 169unsigned long long read_size(void *ptr, int size)
1338
1339static long long arg_num_eval(struct print_arg *arg)
1340{ 170{
1341 long long left, right; 171 return pevent_read_number(pevent, ptr, size);
1342 long long val = 0;
1343
1344 switch (arg->type) {
1345 case PRINT_ATOM:
1346 val = strtoll(arg->atom.atom, NULL, 0);
1347 break;
1348 case PRINT_TYPE:
1349 val = arg_num_eval(arg->typecast.item);
1350 break;
1351 case PRINT_OP:
1352 switch (arg->op.op[0]) {
1353 case '|':
1354 left = arg_num_eval(arg->op.left);
1355 right = arg_num_eval(arg->op.right);
1356 if (arg->op.op[1])
1357 val = left || right;
1358 else
1359 val = left | right;
1360 break;
1361 case '&':
1362 left = arg_num_eval(arg->op.left);
1363 right = arg_num_eval(arg->op.right);
1364 if (arg->op.op[1])
1365 val = left && right;
1366 else
1367 val = left & right;
1368 break;
1369 case '<':
1370 left = arg_num_eval(arg->op.left);
1371 right = arg_num_eval(arg->op.right);
1372 switch (arg->op.op[1]) {
1373 case 0:
1374 val = left < right;
1375 break;
1376 case '<':
1377 val = left << right;
1378 break;
1379 case '=':
1380 val = left <= right;
1381 break;
1382 default:
1383 die("unknown op '%s'", arg->op.op);
1384 }
1385 break;
1386 case '>':
1387 left = arg_num_eval(arg->op.left);
1388 right = arg_num_eval(arg->op.right);
1389 switch (arg->op.op[1]) {
1390 case 0:
1391 val = left > right;
1392 break;
1393 case '>':
1394 val = left >> right;
1395 break;
1396 case '=':
1397 val = left >= right;
1398 break;
1399 default:
1400 die("unknown op '%s'", arg->op.op);
1401 }
1402 break;
1403 case '=':
1404 left = arg_num_eval(arg->op.left);
1405 right = arg_num_eval(arg->op.right);
1406
1407 if (arg->op.op[1] != '=')
1408 die("unknown op '%s'", arg->op.op);
1409
1410 val = left == right;
1411 break;
1412 case '!':
1413 left = arg_num_eval(arg->op.left);
1414 right = arg_num_eval(arg->op.right);
1415
1416 switch (arg->op.op[1]) {
1417 case '=':
1418 val = left != right;
1419 break;
1420 default:
1421 die("unknown op '%s'", arg->op.op);
1422 }
1423 break;
1424 case '+':
1425 left = arg_num_eval(arg->op.left);
1426 right = arg_num_eval(arg->op.right);
1427 val = left + right;
1428 break;
1429 default:
1430 die("unknown op '%s'", arg->op.op);
1431 }
1432 break;
1433
1434 case PRINT_NULL:
1435 case PRINT_FIELD ... PRINT_SYMBOL:
1436 case PRINT_STRING:
1437 default:
1438 die("invalid eval type %d", arg->type);
1439
1440 }
1441 return val;
1442} 172}
1443 173
1444static char *arg_eval (struct print_arg *arg) 174struct event_format *trace_find_event(int type)
1445{ 175{
1446 long long val; 176 return pevent_find_event(pevent, type);
1447 static char buf[20];
1448
1449 switch (arg->type) {
1450 case PRINT_ATOM:
1451 return arg->atom.atom;
1452 case PRINT_TYPE:
1453 return arg_eval(arg->typecast.item);
1454 case PRINT_OP:
1455 val = arg_num_eval(arg);
1456 sprintf(buf, "%lld", val);
1457 return buf;
1458
1459 case PRINT_NULL:
1460 case PRINT_FIELD ... PRINT_SYMBOL:
1461 case PRINT_STRING:
1462 default:
1463 die("invalid eval type %d", arg->type);
1464 break;
1465 }
1466
1467 return NULL;
1468} 177}
1469 178
1470static enum event_type
1471process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1472{
1473 enum event_type type;
1474 struct print_arg *arg = NULL;
1475 struct print_flag_sym *field;
1476 char *token = NULL;
1477 char *value;
1478
1479 do {
1480 free_token(token);
1481 type = read_token_item(&token);
1482 if (test_type_token(type, token, EVENT_OP, "{"))
1483 break;
1484
1485 arg = malloc_or_die(sizeof(*arg));
1486
1487 free_token(token);
1488 type = process_arg(event, arg, &token);
1489
1490 if (type == EVENT_OP)
1491 type = process_op(event, arg, &token);
1492
1493 if (type == EVENT_ERROR)
1494 goto out_free;
1495
1496 if (test_type_token(type, token, EVENT_DELIM, ","))
1497 goto out_free;
1498
1499 field = malloc_or_die(sizeof(*field));
1500 memset(field, 0, sizeof(*field));
1501
1502 value = arg_eval(arg);
1503 field->value = strdup(value);
1504
1505 free_token(token);
1506 type = process_arg(event, arg, &token);
1507 if (test_type_token(type, token, EVENT_OP, "}"))
1508 goto out_free;
1509
1510 value = arg_eval(arg);
1511 field->str = strdup(value);
1512 free_arg(arg);
1513 arg = NULL;
1514
1515 *list = field;
1516 list = &field->next;
1517 179
1518 free_token(token); 180void print_trace_event(int cpu, void *data, int size)
1519 type = read_token_item(&token);
1520 } while (type == EVENT_DELIM && strcmp(token, ",") == 0);
1521
1522 *tok = token;
1523 return type;
1524
1525out_free:
1526 free_arg(arg);
1527 free_token(token);
1528
1529 return EVENT_ERROR;
1530}
1531
1532static enum event_type
1533process_flags(struct event *event, struct print_arg *arg, char **tok)
1534{ 181{
1535 struct print_arg *field; 182 struct event_format *event;
1536 enum event_type type; 183 struct pevent_record record;
1537 char *token; 184 struct trace_seq s;
1538 185 int type;
1539 memset(arg, 0, sizeof(*arg));
1540 arg->type = PRINT_FLAGS;
1541
1542 if (read_expected_item(EVENT_DELIM, "(") < 0)
1543 return EVENT_ERROR;
1544
1545 field = malloc_or_die(sizeof(*field));
1546
1547 type = process_arg(event, field, &token);
1548 while (type == EVENT_OP)
1549 type = process_op(event, field, &token);
1550 if (test_type_token(type, token, EVENT_DELIM, ","))
1551 goto out_free;
1552 186
1553 arg->flags.field = field; 187 type = trace_parse_common_type(data);
1554 188
1555 type = read_token_item(&token); 189 event = trace_find_event(type);
1556 if (event_item_type(type)) { 190 if (!event) {
1557 arg->flags.delim = token; 191 warning("ug! no event found for type %d", type);
1558 type = read_token_item(&token); 192 return;
1559 } 193 }
1560 194
1561 if (test_type_token(type, token, EVENT_DELIM, ",")) 195 memset(&record, 0, sizeof(record));
1562 goto out_free; 196 record.cpu = cpu;
1563 197 record.size = size;
1564 type = process_fields(event, &arg->flags.flags, &token); 198 record.data = data;
1565 if (test_type_token(type, token, EVENT_DELIM, ")"))
1566 goto out_free;
1567 199
1568 free_token(token); 200 trace_seq_init(&s);
1569 type = read_token_item(tok); 201 pevent_print_event(pevent, &s, &record);
1570 return type; 202 trace_seq_do_printf(&s);
1571 203 printf("\n");
1572out_free:
1573 free_token(token);
1574 return EVENT_ERROR;
1575} 204}
1576 205
1577static enum event_type 206void print_event(int cpu, void *data, int size, unsigned long long nsecs,
1578process_symbols(struct event *event, struct print_arg *arg, char **tok) 207 char *comm)
1579{ 208{
1580 struct print_arg *field; 209 struct pevent_record record;
1581 enum event_type type; 210 struct trace_seq s;
1582 char *token; 211 int pid;
1583
1584 memset(arg, 0, sizeof(*arg));
1585 arg->type = PRINT_SYMBOL;
1586
1587 if (read_expected_item(EVENT_DELIM, "(") < 0)
1588 return EVENT_ERROR;
1589
1590 field = malloc_or_die(sizeof(*field));
1591
1592 type = process_arg(event, field, &token);
1593 if (test_type_token(type, token, EVENT_DELIM, ","))
1594 goto out_free;
1595 212
1596 arg->symbol.field = field; 213 pevent->latency_format = latency_format;
1597 214
1598 type = process_fields(event, &arg->symbol.symbols, &token); 215 record.ts = nsecs;
1599 if (test_type_token(type, token, EVENT_DELIM, ")")) 216 record.cpu = cpu;
1600 goto out_free; 217 record.size = size;
218 record.data = data;
219 pid = pevent_data_pid(pevent, &record);
1601 220
1602 free_token(token); 221 if (!pevent_pid_is_registered(pevent, pid))
1603 type = read_token_item(tok); 222 pevent_register_comm(pevent, comm, pid);
1604 return type;
1605 223
1606out_free: 224 trace_seq_init(&s);
1607 free_token(token); 225 pevent_print_event(pevent, &s, &record);
1608 return EVENT_ERROR; 226 trace_seq_do_printf(&s);
227 printf("\n");
1609} 228}
1610 229
1611static enum event_type 230void parse_proc_kallsyms(char *file, unsigned int size __unused)
1612process_paren(struct event *event, struct print_arg *arg, char **tok)
1613{ 231{
1614 struct print_arg *item_arg; 232 unsigned long long addr;
1615 enum event_type type; 233 char *func;
1616 char *token; 234 char *line;
1617 235 char *next = NULL;
1618 type = process_arg(event, arg, &token); 236 char *addr_str;
1619 237 char *mod;
1620 if (type == EVENT_ERROR) 238 char ch;
1621 return EVENT_ERROR;
1622
1623 if (type == EVENT_OP)
1624 type = process_op(event, arg, &token);
1625
1626 if (type == EVENT_ERROR)
1627 return EVENT_ERROR;
1628
1629 if (test_type_token(type, token, EVENT_DELIM, ")")) {
1630 free_token(token);
1631 return EVENT_ERROR;
1632 }
1633
1634 free_token(token);
1635 type = read_token_item(&token);
1636
1637 /*
1638 * If the next token is an item or another open paren, then
1639 * this was a typecast.
1640 */
1641 if (event_item_type(type) ||
1642 (type == EVENT_DELIM && strcmp(token, "(") == 0)) {
1643
1644 /* make this a typecast and contine */
1645 239
1646 /* prevous must be an atom */ 240 line = strtok_r(file, "\n", &next);
1647 if (arg->type != PRINT_ATOM) 241 while (line) {
1648 die("previous needed to be PRINT_ATOM"); 242 mod = NULL;
243 sscanf(line, "%as %c %as\t[%as",
244 (float *)(void *)&addr_str, /* workaround gcc warning */
245 &ch, (float *)(void *)&func, (float *)(void *)&mod);
246 addr = strtoull(addr_str, NULL, 16);
247 free(addr_str);
1649 248
1650 item_arg = malloc_or_die(sizeof(*item_arg)); 249 /* truncate the extra ']' */
250 if (mod)
251 mod[strlen(mod) - 1] = 0;
1651 252
1652 arg->type = PRINT_TYPE; 253 pevent_register_function(pevent, func, addr, mod);
1653 arg->typecast.type = arg->atom.atom; 254 free(func);
1654 arg->typecast.item = item_arg; 255 free(mod);
1655 type = process_arg_token(event, item_arg, &token, type);
1656 256
257 line = strtok_r(NULL, "\n", &next);
1657 } 258 }
1658
1659 *tok = token;
1660 return type;
1661} 259}
1662 260
1663 261void parse_ftrace_printk(char *file, unsigned int size __unused)
1664static enum event_type
1665process_str(struct event *event __unused, struct print_arg *arg, char **tok)
1666{ 262{
1667 enum event_type type; 263 unsigned long long addr;
1668 char *token; 264 char *printk;
1669 265 char *line;
1670 if (read_expected(EVENT_DELIM, "(") < 0) 266 char *next = NULL;
1671 return EVENT_ERROR; 267 char *addr_str;
1672 268 char *fmt;
1673 if (read_expect_type(EVENT_ITEM, &token) < 0)
1674 goto fail;
1675
1676 arg->type = PRINT_STRING;
1677 arg->string.string = token;
1678 arg->string.offset = -1;
1679
1680 if (read_expected(EVENT_DELIM, ")") < 0)
1681 return EVENT_ERROR;
1682
1683 type = read_token(&token);
1684 *tok = token;
1685
1686 return type;
1687fail:
1688 free_token(token);
1689 return EVENT_ERROR;
1690}
1691 269
1692enum event_type 270 line = strtok_r(file, "\n", &next);
1693process_arg_token(struct event *event, struct print_arg *arg, 271 while (line) {
1694 char **tok, enum event_type type) 272 addr_str = strtok_r(line, ":", &fmt);
1695{ 273 if (!addr_str) {
1696 char *token; 274 warning("printk format with empty entry");
1697 char *atom;
1698
1699 token = *tok;
1700
1701 switch (type) {
1702 case EVENT_ITEM:
1703 if (strcmp(token, "REC") == 0) {
1704 free_token(token);
1705 type = process_entry(event, arg, &token);
1706 } else if (strcmp(token, "__print_flags") == 0) {
1707 free_token(token);
1708 is_flag_field = 1;
1709 type = process_flags(event, arg, &token);
1710 } else if (strcmp(token, "__print_symbolic") == 0) {
1711 free_token(token);
1712 is_symbolic_field = 1;
1713 type = process_symbols(event, arg, &token);
1714 } else if (strcmp(token, "__get_str") == 0) {
1715 free_token(token);
1716 type = process_str(event, arg, &token);
1717 } else {
1718 atom = token;
1719 /* test the next token */
1720 type = read_token_item(&token);
1721
1722 /* atoms can be more than one token long */
1723 while (type == EVENT_ITEM) {
1724 atom = realloc(atom, strlen(atom) + strlen(token) + 2);
1725 strcat(atom, " ");
1726 strcat(atom, token);
1727 free_token(token);
1728 type = read_token_item(&token);
1729 }
1730
1731 /* todo, test for function */
1732
1733 arg->type = PRINT_ATOM;
1734 arg->atom.atom = atom;
1735 }
1736 break;
1737 case EVENT_DQUOTE:
1738 case EVENT_SQUOTE:
1739 arg->type = PRINT_ATOM;
1740 arg->atom.atom = token;
1741 type = read_token_item(&token);
1742 break;
1743 case EVENT_DELIM:
1744 if (strcmp(token, "(") == 0) {
1745 free_token(token);
1746 type = process_paren(event, arg, &token);
1747 break; 275 break;
1748 } 276 }
1749 case EVENT_OP: 277 addr = strtoull(addr_str, NULL, 16);
1750 /* handle single ops */ 278 /* fmt still has a space, skip it */
1751 arg->type = PRINT_OP; 279 printk = strdup(fmt+1);
1752 arg->op.op = token; 280 line = strtok_r(NULL, "\n", &next);
1753 arg->op.left = NULL; 281 pevent_register_print_string(pevent, printk, addr);
1754 type = process_op(event, arg, &token);
1755
1756 break;
1757
1758 case EVENT_ERROR ... EVENT_NEWLINE:
1759 default:
1760 die("unexpected type %d", type);
1761 }
1762 *tok = token;
1763
1764 return type;
1765}
1766
1767static int event_read_print_args(struct event *event, struct print_arg **list)
1768{
1769 enum event_type type = EVENT_ERROR;
1770 struct print_arg *arg;
1771 char *token;
1772 int args = 0;
1773
1774 do {
1775 if (type == EVENT_NEWLINE) {
1776 free_token(token);
1777 type = read_token_item(&token);
1778 continue;
1779 }
1780
1781 arg = malloc_or_die(sizeof(*arg));
1782 memset(arg, 0, sizeof(*arg));
1783
1784 type = process_arg(event, arg, &token);
1785
1786 if (type == EVENT_ERROR) {
1787 free_arg(arg);
1788 return -1;
1789 }
1790
1791 *list = arg;
1792 args++;
1793
1794 if (type == EVENT_OP) {
1795 type = process_op(event, arg, &token);
1796 list = &arg->next;
1797 continue;
1798 }
1799
1800 if (type == EVENT_DELIM && strcmp(token, ",") == 0) {
1801 free_token(token);
1802 *list = arg;
1803 list = &arg->next;
1804 continue;
1805 }
1806 break;
1807 } while (type != EVENT_NONE);
1808
1809 if (type != EVENT_NONE)
1810 free_token(token);
1811
1812 return args;
1813}
1814
1815static int event_read_print(struct event *event)
1816{
1817 enum event_type type;
1818 char *token;
1819 int ret;
1820
1821 if (read_expected_item(EVENT_ITEM, "print") < 0)
1822 return -1;
1823
1824 if (read_expected(EVENT_ITEM, "fmt") < 0)
1825 return -1;
1826
1827 if (read_expected(EVENT_OP, ":") < 0)
1828 return -1;
1829
1830 if (read_expect_type(EVENT_DQUOTE, &token) < 0)
1831 goto fail;
1832
1833 concat:
1834 event->print_fmt.format = token;
1835 event->print_fmt.args = NULL;
1836
1837 /* ok to have no arg */
1838 type = read_token_item(&token);
1839
1840 if (type == EVENT_NONE)
1841 return 0;
1842
1843 /* Handle concatination of print lines */
1844 if (type == EVENT_DQUOTE) {
1845 char *cat;
1846
1847 cat = malloc_or_die(strlen(event->print_fmt.format) +
1848 strlen(token) + 1);
1849 strcpy(cat, event->print_fmt.format);
1850 strcat(cat, token);
1851 free_token(token);
1852 free_token(event->print_fmt.format);
1853 event->print_fmt.format = NULL;
1854 token = cat;
1855 goto concat;
1856 }
1857
1858 if (test_type_token(type, token, EVENT_DELIM, ","))
1859 goto fail;
1860
1861 free_token(token);
1862
1863 ret = event_read_print_args(event, &event->print_fmt.args);
1864 if (ret < 0)
1865 return -1;
1866
1867 return ret;
1868
1869 fail:
1870 free_token(token);
1871 return -1;
1872}
1873
1874static struct format_field *
1875find_common_field(struct event *event, const char *name)
1876{
1877 struct format_field *format;
1878
1879 for (format = event->format.common_fields;
1880 format; format = format->next) {
1881 if (strcmp(format->name, name) == 0)
1882 break;
1883 }
1884
1885 return format;
1886}
1887
1888static struct format_field *
1889find_field(struct event *event, const char *name)
1890{
1891 struct format_field *format;
1892
1893 for (format = event->format.fields;
1894 format; format = format->next) {
1895 if (strcmp(format->name, name) == 0)
1896 break;
1897 } 282 }
1898
1899 return format;
1900} 283}
1901 284
1902static struct format_field * 285int parse_ftrace_file(char *buf, unsigned long size)
1903find_any_field(struct event *event, const char *name)
1904{ 286{
1905 struct format_field *format; 287 return pevent_parse_event(pevent, buf, size, "ftrace");
1906
1907 format = find_common_field(event, name);
1908 if (format)
1909 return format;
1910 return find_field(event, name);
1911} 288}
1912 289
1913unsigned long long read_size(void *ptr, int size) 290int parse_event_file(char *buf, unsigned long size, char *sys)
1914{ 291{
1915 switch (size) { 292 return pevent_parse_event(pevent, buf, size, sys);
1916 case 1:
1917 return *(unsigned char *)ptr;
1918 case 2:
1919 return data2host2(ptr);
1920 case 4:
1921 return data2host4(ptr);
1922 case 8:
1923 return data2host8(ptr);
1924 default:
1925 /* BUG! */
1926 return 0;
1927 }
1928} 293}
1929 294
1930unsigned long long 295struct event_format *trace_find_next_event(struct event_format *event)
1931raw_field_value(struct event *event, const char *name, void *data)
1932{ 296{
1933 struct format_field *field; 297 static int idx;
1934
1935 field = find_any_field(event, name);
1936 if (!field)
1937 return 0ULL;
1938 298
1939 return read_size(data + field->offset, field->size); 299 if (!pevent->events)
1940}
1941
1942void *raw_field_ptr(struct event *event, const char *name, void *data)
1943{
1944 struct format_field *field;
1945
1946 field = find_any_field(event, name);
1947 if (!field)
1948 return NULL; 300 return NULL;
1949 301
1950 if (field->flags & FIELD_IS_DYNAMIC) { 302 if (!event) {
1951 int offset; 303 idx = 0;
1952 304 return pevent->events[0];
1953 offset = *(int *)(data + field->offset);
1954 offset &= 0xffff;
1955
1956 return data + offset;
1957 }
1958
1959 return data + field->offset;
1960}
1961
1962static int get_common_info(const char *type, int *offset, int *size)
1963{
1964 struct event *event;
1965 struct format_field *field;
1966
1967 /*
1968 * All events should have the same common elements.
1969 * Pick any event to find where the type is;
1970 */
1971 if (!event_list)
1972 die("no event_list!");
1973
1974 event = event_list;
1975 field = find_common_field(event, type);
1976 if (!field)
1977 die("field '%s' not found", type);
1978
1979 *offset = field->offset;
1980 *size = field->size;
1981
1982 return 0;
1983}
1984
1985static int __parse_common(void *data, int *size, int *offset,
1986 const char *name)
1987{
1988 int ret;
1989
1990 if (!*size) {
1991 ret = get_common_info(name, offset, size);
1992 if (ret < 0)
1993 return ret;
1994 } 305 }
1995 return read_size(data + *offset, *size);
1996}
1997
1998int trace_parse_common_type(void *data)
1999{
2000 static int type_offset;
2001 static int type_size;
2002
2003 return __parse_common(data, &type_size, &type_offset,
2004 "common_type");
2005}
2006
2007int trace_parse_common_pid(void *data)
2008{
2009 static int pid_offset;
2010 static int pid_size;
2011
2012 return __parse_common(data, &pid_size, &pid_offset,
2013 "common_pid");
2014}
2015
2016int parse_common_pc(void *data)
2017{
2018 static int pc_offset;
2019 static int pc_size;
2020
2021 return __parse_common(data, &pc_size, &pc_offset,
2022 "common_preempt_count");
2023}
2024
2025int parse_common_flags(void *data)
2026{
2027 static int flags_offset;
2028 static int flags_size;
2029
2030 return __parse_common(data, &flags_size, &flags_offset,
2031 "common_flags");
2032}
2033
2034int parse_common_lock_depth(void *data)
2035{
2036 static int ld_offset;
2037 static int ld_size;
2038 int ret;
2039 306
2040 ret = __parse_common(data, &ld_size, &ld_offset, 307 if (idx < pevent->nr_events && event == pevent->events[idx]) {
2041 "common_lock_depth"); 308 idx++;
2042 if (ret < 0) 309 if (idx == pevent->nr_events)
2043 return -1; 310 return NULL;
2044 311 return pevent->events[idx];
2045 return ret;
2046}
2047
2048struct event *trace_find_event(int id)
2049{
2050 struct event *event;
2051
2052 for (event = event_list; event; event = event->next) {
2053 if (event->id == id)
2054 break;
2055 } 312 }
2056 return event;
2057}
2058
2059struct event *trace_find_next_event(struct event *event)
2060{
2061 if (!event)
2062 return event_list;
2063
2064 return event->next;
2065}
2066
2067static unsigned long long eval_num_arg(void *data, int size,
2068 struct event *event, struct print_arg *arg)
2069{
2070 unsigned long long val = 0;
2071 unsigned long long left, right;
2072 struct print_arg *larg;
2073 313
2074 switch (arg->type) { 314 for (idx = 1; idx < pevent->nr_events; idx++) {
2075 case PRINT_NULL: 315 if (event == pevent->events[idx - 1])
2076 /* ?? */ 316 return pevent->events[idx];
2077 return 0;
2078 case PRINT_ATOM:
2079 return strtoull(arg->atom.atom, NULL, 0);
2080 case PRINT_FIELD:
2081 if (!arg->field.field) {
2082 arg->field.field = find_any_field(event, arg->field.name);
2083 if (!arg->field.field)
2084 die("field %s not found", arg->field.name);
2085 }
2086 /* must be a number */
2087 val = read_size(data + arg->field.field->offset,
2088 arg->field.field->size);
2089 break;
2090 case PRINT_FLAGS:
2091 case PRINT_SYMBOL:
2092 break;
2093 case PRINT_TYPE:
2094 return eval_num_arg(data, size, event, arg->typecast.item);
2095 case PRINT_STRING:
2096 return 0;
2097 break;
2098 case PRINT_OP:
2099 if (strcmp(arg->op.op, "[") == 0) {
2100 /*
2101 * Arrays are special, since we don't want
2102 * to read the arg as is.
2103 */
2104 if (arg->op.left->type != PRINT_FIELD)
2105 goto default_op; /* oops, all bets off */
2106 larg = arg->op.left;
2107 if (!larg->field.field) {
2108 larg->field.field =
2109 find_any_field(event, larg->field.name);
2110 if (!larg->field.field)
2111 die("field %s not found", larg->field.name);
2112 }
2113 right = eval_num_arg(data, size, event, arg->op.right);
2114 val = read_size(data + larg->field.field->offset +
2115 right * long_size, long_size);
2116 break;
2117 }
2118 default_op:
2119 left = eval_num_arg(data, size, event, arg->op.left);
2120 right = eval_num_arg(data, size, event, arg->op.right);
2121 switch (arg->op.op[0]) {
2122 case '|':
2123 if (arg->op.op[1])
2124 val = left || right;
2125 else
2126 val = left | right;
2127 break;
2128 case '&':
2129 if (arg->op.op[1])
2130 val = left && right;
2131 else
2132 val = left & right;
2133 break;
2134 case '<':
2135 switch (arg->op.op[1]) {
2136 case 0:
2137 val = left < right;
2138 break;
2139 case '<':
2140 val = left << right;
2141 break;
2142 case '=':
2143 val = left <= right;
2144 break;
2145 default:
2146 die("unknown op '%s'", arg->op.op);
2147 }
2148 break;
2149 case '>':
2150 switch (arg->op.op[1]) {
2151 case 0:
2152 val = left > right;
2153 break;
2154 case '>':
2155 val = left >> right;
2156 break;
2157 case '=':
2158 val = left >= right;
2159 break;
2160 default:
2161 die("unknown op '%s'", arg->op.op);
2162 }
2163 break;
2164 case '=':
2165 if (arg->op.op[1] != '=')
2166 die("unknown op '%s'", arg->op.op);
2167 val = left == right;
2168 break;
2169 case '-':
2170 val = left - right;
2171 break;
2172 case '+':
2173 val = left + right;
2174 break;
2175 default:
2176 die("unknown op '%s'", arg->op.op);
2177 }
2178 break;
2179 default: /* not sure what to do there */
2180 return 0;
2181 } 317 }
2182 return val; 318 return NULL;
2183} 319}
2184 320
2185struct flag { 321struct flag {
@@ -2221,933 +357,3 @@ unsigned long long eval_flag(const char *flag)
2221 357
2222 return 0; 358 return 0;
2223} 359}
2224
2225static void print_str_arg(void *data, int size,
2226 struct event *event, struct print_arg *arg)
2227{
2228 struct print_flag_sym *flag;
2229 unsigned long long val, fval;
2230 char *str;
2231 int print;
2232
2233 switch (arg->type) {
2234 case PRINT_NULL:
2235 /* ?? */
2236 return;
2237 case PRINT_ATOM:
2238 printf("%s", arg->atom.atom);
2239 return;
2240 case PRINT_FIELD:
2241 if (!arg->field.field) {
2242 arg->field.field = find_any_field(event, arg->field.name);
2243 if (!arg->field.field)
2244 die("field %s not found", arg->field.name);
2245 }
2246 str = malloc_or_die(arg->field.field->size + 1);
2247 memcpy(str, data + arg->field.field->offset,
2248 arg->field.field->size);
2249 str[arg->field.field->size] = 0;
2250 printf("%s", str);
2251 free(str);
2252 break;
2253 case PRINT_FLAGS:
2254 val = eval_num_arg(data, size, event, arg->flags.field);
2255 print = 0;
2256 for (flag = arg->flags.flags; flag; flag = flag->next) {
2257 fval = eval_flag(flag->value);
2258 if (!val && !fval) {
2259 printf("%s", flag->str);
2260 break;
2261 }
2262 if (fval && (val & fval) == fval) {
2263 if (print && arg->flags.delim)
2264 printf("%s", arg->flags.delim);
2265 printf("%s", flag->str);
2266 print = 1;
2267 val &= ~fval;
2268 }
2269 }
2270 break;
2271 case PRINT_SYMBOL:
2272 val = eval_num_arg(data, size, event, arg->symbol.field);
2273 for (flag = arg->symbol.symbols; flag; flag = flag->next) {
2274 fval = eval_flag(flag->value);
2275 if (val == fval) {
2276 printf("%s", flag->str);
2277 break;
2278 }
2279 }
2280 break;
2281
2282 case PRINT_TYPE:
2283 break;
2284 case PRINT_STRING: {
2285 int str_offset;
2286
2287 if (arg->string.offset == -1) {
2288 struct format_field *f;
2289
2290 f = find_any_field(event, arg->string.string);
2291 arg->string.offset = f->offset;
2292 }
2293 str_offset = *(int *)(data + arg->string.offset);
2294 str_offset &= 0xffff;
2295 printf("%s", ((char *)data) + str_offset);
2296 break;
2297 }
2298 case PRINT_OP:
2299 /*
2300 * The only op for string should be ? :
2301 */
2302 if (arg->op.op[0] != '?')
2303 return;
2304 val = eval_num_arg(data, size, event, arg->op.left);
2305 if (val)
2306 print_str_arg(data, size, event, arg->op.right->op.left);
2307 else
2308 print_str_arg(data, size, event, arg->op.right->op.right);
2309 break;
2310 default:
2311 /* well... */
2312 break;
2313 }
2314}
2315
2316static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event *event)
2317{
2318 static struct format_field *field, *ip_field;
2319 struct print_arg *args, *arg, **next;
2320 unsigned long long ip, val;
2321 char *ptr;
2322 void *bptr;
2323
2324 if (!field) {
2325 field = find_field(event, "buf");
2326 if (!field)
2327 die("can't find buffer field for binary printk");
2328 ip_field = find_field(event, "ip");
2329 if (!ip_field)
2330 die("can't find ip field for binary printk");
2331 }
2332
2333 ip = read_size(data + ip_field->offset, ip_field->size);
2334
2335 /*
2336 * The first arg is the IP pointer.
2337 */
2338 args = malloc_or_die(sizeof(*args));
2339 arg = args;
2340 arg->next = NULL;
2341 next = &arg->next;
2342
2343 arg->type = PRINT_ATOM;
2344 arg->atom.atom = malloc_or_die(32);
2345 sprintf(arg->atom.atom, "%lld", ip);
2346
2347 /* skip the first "%pf : " */
2348 for (ptr = fmt + 6, bptr = data + field->offset;
2349 bptr < data + size && *ptr; ptr++) {
2350 int ls = 0;
2351
2352 if (*ptr == '%') {
2353 process_again:
2354 ptr++;
2355 switch (*ptr) {
2356 case '%':
2357 break;
2358 case 'l':
2359 ls++;
2360 goto process_again;
2361 case 'L':
2362 ls = 2;
2363 goto process_again;
2364 case '0' ... '9':
2365 goto process_again;
2366 case 'p':
2367 ls = 1;
2368 /* fall through */
2369 case 'd':
2370 case 'u':
2371 case 'x':
2372 case 'i':
2373 /* the pointers are always 4 bytes aligned */
2374 bptr = (void *)(((unsigned long)bptr + 3) &
2375 ~3);
2376 switch (ls) {
2377 case 0:
2378 case 1:
2379 ls = long_size;
2380 break;
2381 case 2:
2382 ls = 8;
2383 default:
2384 break;
2385 }
2386 val = read_size(bptr, ls);
2387 bptr += ls;
2388 arg = malloc_or_die(sizeof(*arg));
2389 arg->next = NULL;
2390 arg->type = PRINT_ATOM;
2391 arg->atom.atom = malloc_or_die(32);
2392 sprintf(arg->atom.atom, "%lld", val);
2393 *next = arg;
2394 next = &arg->next;
2395 break;
2396 case 's':
2397 arg = malloc_or_die(sizeof(*arg));
2398 arg->next = NULL;
2399 arg->type = PRINT_STRING;
2400 arg->string.string = strdup(bptr);
2401 bptr += strlen(bptr) + 1;
2402 *next = arg;
2403 next = &arg->next;
2404 default:
2405 break;
2406 }
2407 }
2408 }
2409
2410 return args;
2411}
2412
2413static void free_args(struct print_arg *args)
2414{
2415 struct print_arg *next;
2416
2417 while (args) {
2418 next = args->next;
2419
2420 if (args->type == PRINT_ATOM)
2421 free(args->atom.atom);
2422 else
2423 free(args->string.string);
2424 free(args);
2425 args = next;
2426 }
2427}
2428
2429static char *get_bprint_format(void *data, int size __unused, struct event *event)
2430{
2431 unsigned long long addr;
2432 static struct format_field *field;
2433 struct printk_map *printk;
2434 char *format;
2435 char *p;
2436
2437 if (!field) {
2438 field = find_field(event, "fmt");
2439 if (!field)
2440 die("can't find format field for binary printk");
2441 printf("field->offset = %d size=%d\n", field->offset, field->size);
2442 }
2443
2444 addr = read_size(data + field->offset, field->size);
2445
2446 printk = find_printk(addr);
2447 if (!printk) {
2448 format = malloc_or_die(45);
2449 sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n",
2450 addr);
2451 return format;
2452 }
2453
2454 p = printk->printk;
2455 /* Remove any quotes. */
2456 if (*p == '"')
2457 p++;
2458 format = malloc_or_die(strlen(p) + 10);
2459 sprintf(format, "%s : %s", "%pf", p);
2460 /* remove ending quotes and new line since we will add one too */
2461 p = format + strlen(format) - 1;
2462 if (*p == '"')
2463 *p = 0;
2464
2465 p -= 2;
2466 if (strcmp(p, "\\n") == 0)
2467 *p = 0;
2468
2469 return format;
2470}
2471
2472static void pretty_print(void *data, int size, struct event *event)
2473{
2474 struct print_fmt *print_fmt = &event->print_fmt;
2475 struct print_arg *arg = print_fmt->args;
2476 struct print_arg *args = NULL;
2477 const char *ptr = print_fmt->format;
2478 unsigned long long val;
2479 struct func_map *func;
2480 const char *saveptr;
2481 char *bprint_fmt = NULL;
2482 char format[32];
2483 int show_func;
2484 int len;
2485 int ls;
2486
2487 if (event->flags & EVENT_FL_ISFUNC)
2488 ptr = " %pF <-- %pF";
2489
2490 if (event->flags & EVENT_FL_ISBPRINT) {
2491 bprint_fmt = get_bprint_format(data, size, event);
2492 args = make_bprint_args(bprint_fmt, data, size, event);
2493 arg = args;
2494 ptr = bprint_fmt;
2495 }
2496
2497 for (; *ptr; ptr++) {
2498 ls = 0;
2499 if (*ptr == '\\') {
2500 ptr++;
2501 switch (*ptr) {
2502 case 'n':
2503 printf("\n");
2504 break;
2505 case 't':
2506 printf("\t");
2507 break;
2508 case 'r':
2509 printf("\r");
2510 break;
2511 case '\\':
2512 printf("\\");
2513 break;
2514 default:
2515 printf("%c", *ptr);
2516 break;
2517 }
2518
2519 } else if (*ptr == '%') {
2520 saveptr = ptr;
2521 show_func = 0;
2522 cont_process:
2523 ptr++;
2524 switch (*ptr) {
2525 case '%':
2526 printf("%%");
2527 break;
2528 case 'l':
2529 ls++;
2530 goto cont_process;
2531 case 'L':
2532 ls = 2;
2533 goto cont_process;
2534 case 'z':
2535 case 'Z':
2536 case '0' ... '9':
2537 goto cont_process;
2538 case 'p':
2539 if (long_size == 4)
2540 ls = 1;
2541 else
2542 ls = 2;
2543
2544 if (*(ptr+1) == 'F' ||
2545 *(ptr+1) == 'f') {
2546 ptr++;
2547 show_func = *ptr;
2548 }
2549
2550 /* fall through */
2551 case 'd':
2552 case 'i':
2553 case 'x':
2554 case 'X':
2555 case 'u':
2556 if (!arg)
2557 die("no argument match");
2558
2559 len = ((unsigned long)ptr + 1) -
2560 (unsigned long)saveptr;
2561
2562 /* should never happen */
2563 if (len > 32)
2564 die("bad format!");
2565
2566 memcpy(format, saveptr, len);
2567 format[len] = 0;
2568
2569 val = eval_num_arg(data, size, event, arg);
2570 arg = arg->next;
2571
2572 if (show_func) {
2573 func = find_func(val);
2574 if (func) {
2575 printf("%s", func->func);
2576 if (show_func == 'F')
2577 printf("+0x%llx",
2578 val - func->addr);
2579 break;
2580 }
2581 }
2582 switch (ls) {
2583 case 0:
2584 printf(format, (int)val);
2585 break;
2586 case 1:
2587 printf(format, (long)val);
2588 break;
2589 case 2:
2590 printf(format, (long long)val);
2591 break;
2592 default:
2593 die("bad count (%d)", ls);
2594 }
2595 break;
2596 case 's':
2597 if (!arg)
2598 die("no matching argument");
2599
2600 print_str_arg(data, size, event, arg);
2601 arg = arg->next;
2602 break;
2603 default:
2604 printf(">%c<", *ptr);
2605
2606 }
2607 } else
2608 printf("%c", *ptr);
2609 }
2610
2611 if (args) {
2612 free_args(args);
2613 free(bprint_fmt);
2614 }
2615}
2616
2617static inline int log10_cpu(int nb)
2618{
2619 if (nb / 100)
2620 return 3;
2621 if (nb / 10)
2622 return 2;
2623 return 1;
2624}
2625
2626static void print_lat_fmt(void *data, int size __unused)
2627{
2628 unsigned int lat_flags;
2629 unsigned int pc;
2630 int lock_depth;
2631 int hardirq;
2632 int softirq;
2633
2634 lat_flags = parse_common_flags(data);
2635 pc = parse_common_pc(data);
2636 lock_depth = parse_common_lock_depth(data);
2637
2638 hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
2639 softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
2640
2641 printf("%c%c%c",
2642 (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
2643 (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
2644 'X' : '.',
2645 (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
2646 'N' : '.',
2647 (hardirq && softirq) ? 'H' :
2648 hardirq ? 'h' : softirq ? 's' : '.');
2649
2650 if (pc)
2651 printf("%x", pc);
2652 else
2653 printf(".");
2654
2655 if (lock_depth < 0)
2656 printf(". ");
2657 else
2658 printf("%d ", lock_depth);
2659}
2660
2661#define TRACE_GRAPH_INDENT 2
2662
2663static struct record *
2664get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
2665 struct record *next)
2666{
2667 struct format_field *field;
2668 struct event *event;
2669 unsigned long val;
2670 int type;
2671 int pid;
2672
2673 type = trace_parse_common_type(next->data);
2674 event = trace_find_event(type);
2675 if (!event)
2676 return NULL;
2677
2678 if (!(event->flags & EVENT_FL_ISFUNCRET))
2679 return NULL;
2680
2681 pid = trace_parse_common_pid(next->data);
2682 field = find_field(event, "func");
2683 if (!field)
2684 die("function return does not have field func");
2685
2686 val = read_size(next->data + field->offset, field->size);
2687
2688 if (cur_pid != pid || cur_func != val)
2689 return NULL;
2690
2691 /* this is a leaf, now advance the iterator */
2692 return trace_read_data(cpu);
2693}
2694
2695/* Signal a overhead of time execution to the output */
2696static void print_graph_overhead(unsigned long long duration)
2697{
2698 /* Non nested entry or return */
2699 if (duration == ~0ULL)
2700 return (void)printf(" ");
2701
2702 /* Duration exceeded 100 msecs */
2703 if (duration > 100000ULL)
2704 return (void)printf("! ");
2705
2706 /* Duration exceeded 10 msecs */
2707 if (duration > 10000ULL)
2708 return (void)printf("+ ");
2709
2710 printf(" ");
2711}
2712
2713static void print_graph_duration(unsigned long long duration)
2714{
2715 unsigned long usecs = duration / 1000;
2716 unsigned long nsecs_rem = duration % 1000;
2717 /* log10(ULONG_MAX) + '\0' */
2718 char msecs_str[21];
2719 char nsecs_str[5];
2720 int len;
2721 int i;
2722
2723 sprintf(msecs_str, "%lu", usecs);
2724
2725 /* Print msecs */
2726 len = printf("%lu", usecs);
2727
2728 /* Print nsecs (we don't want to exceed 7 numbers) */
2729 if (len < 7) {
2730 snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem);
2731 len += printf(".%s", nsecs_str);
2732 }
2733
2734 printf(" us ");
2735
2736 /* Print remaining spaces to fit the row's width */
2737 for (i = len; i < 7; i++)
2738 printf(" ");
2739
2740 printf("| ");
2741}
2742
2743static void
2744print_graph_entry_leaf(struct event *event, void *data, struct record *ret_rec)
2745{
2746 unsigned long long rettime, calltime;
2747 unsigned long long duration, depth;
2748 unsigned long long val;
2749 struct format_field *field;
2750 struct func_map *func;
2751 struct event *ret_event;
2752 int type;
2753 int i;
2754
2755 type = trace_parse_common_type(ret_rec->data);
2756 ret_event = trace_find_event(type);
2757
2758 field = find_field(ret_event, "rettime");
2759 if (!field)
2760 die("can't find rettime in return graph");
2761 rettime = read_size(ret_rec->data + field->offset, field->size);
2762
2763 field = find_field(ret_event, "calltime");
2764 if (!field)
2765 die("can't find rettime in return graph");
2766 calltime = read_size(ret_rec->data + field->offset, field->size);
2767
2768 duration = rettime - calltime;
2769
2770 /* Overhead */
2771 print_graph_overhead(duration);
2772
2773 /* Duration */
2774 print_graph_duration(duration);
2775
2776 field = find_field(event, "depth");
2777 if (!field)
2778 die("can't find depth in entry graph");
2779 depth = read_size(data + field->offset, field->size);
2780
2781 /* Function */
2782 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2783 printf(" ");
2784
2785 field = find_field(event, "func");
2786 if (!field)
2787 die("can't find func in entry graph");
2788 val = read_size(data + field->offset, field->size);
2789 func = find_func(val);
2790
2791 if (func)
2792 printf("%s();", func->func);
2793 else
2794 printf("%llx();", val);
2795}
2796
2797static void print_graph_nested(struct event *event, void *data)
2798{
2799 struct format_field *field;
2800 unsigned long long depth;
2801 unsigned long long val;
2802 struct func_map *func;
2803 int i;
2804
2805 /* No overhead */
2806 print_graph_overhead(-1);
2807
2808 /* No time */
2809 printf(" | ");
2810
2811 field = find_field(event, "depth");
2812 if (!field)
2813 die("can't find depth in entry graph");
2814 depth = read_size(data + field->offset, field->size);
2815
2816 /* Function */
2817 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2818 printf(" ");
2819
2820 field = find_field(event, "func");
2821 if (!field)
2822 die("can't find func in entry graph");
2823 val = read_size(data + field->offset, field->size);
2824 func = find_func(val);
2825
2826 if (func)
2827 printf("%s() {", func->func);
2828 else
2829 printf("%llx() {", val);
2830}
2831
2832static void
2833pretty_print_func_ent(void *data, int size, struct event *event,
2834 int cpu, int pid)
2835{
2836 struct format_field *field;
2837 struct record *rec;
2838 void *copy_data;
2839 unsigned long val;
2840
2841 if (latency_format) {
2842 print_lat_fmt(data, size);
2843 printf(" | ");
2844 }
2845
2846 field = find_field(event, "func");
2847 if (!field)
2848 die("function entry does not have func field");
2849
2850 val = read_size(data + field->offset, field->size);
2851
2852 /*
2853 * peek_data may unmap the data pointer. Copy it first.
2854 */
2855 copy_data = malloc_or_die(size);
2856 memcpy(copy_data, data, size);
2857 data = copy_data;
2858
2859 rec = trace_peek_data(cpu);
2860 if (rec) {
2861 rec = get_return_for_leaf(cpu, pid, val, rec);
2862 if (rec) {
2863 print_graph_entry_leaf(event, data, rec);
2864 goto out_free;
2865 }
2866 }
2867 print_graph_nested(event, data);
2868out_free:
2869 free(data);
2870}
2871
2872static void
2873pretty_print_func_ret(void *data, int size __unused, struct event *event)
2874{
2875 unsigned long long rettime, calltime;
2876 unsigned long long duration, depth;
2877 struct format_field *field;
2878 int i;
2879
2880 if (latency_format) {
2881 print_lat_fmt(data, size);
2882 printf(" | ");
2883 }
2884
2885 field = find_field(event, "rettime");
2886 if (!field)
2887 die("can't find rettime in return graph");
2888 rettime = read_size(data + field->offset, field->size);
2889
2890 field = find_field(event, "calltime");
2891 if (!field)
2892 die("can't find calltime in return graph");
2893 calltime = read_size(data + field->offset, field->size);
2894
2895 duration = rettime - calltime;
2896
2897 /* Overhead */
2898 print_graph_overhead(duration);
2899
2900 /* Duration */
2901 print_graph_duration(duration);
2902
2903 field = find_field(event, "depth");
2904 if (!field)
2905 die("can't find depth in entry graph");
2906 depth = read_size(data + field->offset, field->size);
2907
2908 /* Function */
2909 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2910 printf(" ");
2911
2912 printf("}");
2913}
2914
2915static void
2916pretty_print_func_graph(void *data, int size, struct event *event,
2917 int cpu, int pid)
2918{
2919 if (event->flags & EVENT_FL_ISFUNCENT)
2920 pretty_print_func_ent(data, size, event, cpu, pid);
2921 else if (event->flags & EVENT_FL_ISFUNCRET)
2922 pretty_print_func_ret(data, size, event);
2923 printf("\n");
2924}
2925
2926void print_trace_event(int cpu, void *data, int size)
2927{
2928 struct event *event;
2929 int type;
2930 int pid;
2931
2932 type = trace_parse_common_type(data);
2933
2934 event = trace_find_event(type);
2935 if (!event) {
2936 warning("ug! no event found for type %d", type);
2937 return;
2938 }
2939
2940 pid = trace_parse_common_pid(data);
2941
2942 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
2943 return pretty_print_func_graph(data, size, event, cpu, pid);
2944
2945 if (latency_format)
2946 print_lat_fmt(data, size);
2947
2948 if (event->flags & EVENT_FL_FAILED) {
2949 printf("EVENT '%s' FAILED TO PARSE\n",
2950 event->name);
2951 return;
2952 }
2953
2954 pretty_print(data, size, event);
2955}
2956
2957static void print_fields(struct print_flag_sym *field)
2958{
2959 printf("{ %s, %s }", field->value, field->str);
2960 if (field->next) {
2961 printf(", ");
2962 print_fields(field->next);
2963 }
2964}
2965
2966static void print_args(struct print_arg *args)
2967{
2968 int print_paren = 1;
2969
2970 switch (args->type) {
2971 case PRINT_NULL:
2972 printf("null");
2973 break;
2974 case PRINT_ATOM:
2975 printf("%s", args->atom.atom);
2976 break;
2977 case PRINT_FIELD:
2978 printf("REC->%s", args->field.name);
2979 break;
2980 case PRINT_FLAGS:
2981 printf("__print_flags(");
2982 print_args(args->flags.field);
2983 printf(", %s, ", args->flags.delim);
2984 print_fields(args->flags.flags);
2985 printf(")");
2986 break;
2987 case PRINT_SYMBOL:
2988 printf("__print_symbolic(");
2989 print_args(args->symbol.field);
2990 printf(", ");
2991 print_fields(args->symbol.symbols);
2992 printf(")");
2993 break;
2994 case PRINT_STRING:
2995 printf("__get_str(%s)", args->string.string);
2996 break;
2997 case PRINT_TYPE:
2998 printf("(%s)", args->typecast.type);
2999 print_args(args->typecast.item);
3000 break;
3001 case PRINT_OP:
3002 if (strcmp(args->op.op, ":") == 0)
3003 print_paren = 0;
3004 if (print_paren)
3005 printf("(");
3006 print_args(args->op.left);
3007 printf(" %s ", args->op.op);
3008 print_args(args->op.right);
3009 if (print_paren)
3010 printf(")");
3011 break;
3012 default:
3013 /* we should warn... */
3014 return;
3015 }
3016 if (args->next) {
3017 printf("\n");
3018 print_args(args->next);
3019 }
3020}
3021
3022int parse_ftrace_file(char *buf, unsigned long size)
3023{
3024 struct format_field *field;
3025 struct print_arg *arg, **list;
3026 struct event *event;
3027 int ret;
3028
3029 init_input_buf(buf, size);
3030
3031 event = alloc_event();
3032 if (!event)
3033 return -ENOMEM;
3034
3035 event->flags |= EVENT_FL_ISFTRACE;
3036
3037 event->name = event_read_name();
3038 if (!event->name)
3039 die("failed to read ftrace event name");
3040
3041 if (strcmp(event->name, "function") == 0)
3042 event->flags |= EVENT_FL_ISFUNC;
3043
3044 else if (strcmp(event->name, "funcgraph_entry") == 0)
3045 event->flags |= EVENT_FL_ISFUNCENT;
3046
3047 else if (strcmp(event->name, "funcgraph_exit") == 0)
3048 event->flags |= EVENT_FL_ISFUNCRET;
3049
3050 else if (strcmp(event->name, "bprint") == 0)
3051 event->flags |= EVENT_FL_ISBPRINT;
3052
3053 event->id = event_read_id();
3054 if (event->id < 0)
3055 die("failed to read ftrace event id");
3056
3057 add_event(event);
3058
3059 ret = event_read_format(event);
3060 if (ret < 0)
3061 die("failed to read ftrace event format");
3062
3063 ret = event_read_print(event);
3064 if (ret < 0)
3065 die("failed to read ftrace event print fmt");
3066
3067 /* New ftrace handles args */
3068 if (ret > 0)
3069 return 0;
3070 /*
3071 * The arguments for ftrace files are parsed by the fields.
3072 * Set up the fields as their arguments.
3073 */
3074 list = &event->print_fmt.args;
3075 for (field = event->format.fields; field; field = field->next) {
3076 arg = malloc_or_die(sizeof(*arg));
3077 memset(arg, 0, sizeof(*arg));
3078 *list = arg;
3079 list = &arg->next;
3080 arg->type = PRINT_FIELD;
3081 arg->field.name = field->name;
3082 arg->field.field = field;
3083 }
3084 return 0;
3085}
3086
3087int parse_event_file(char *buf, unsigned long size, char *sys)
3088{
3089 struct event *event;
3090 int ret;
3091
3092 init_input_buf(buf, size);
3093
3094 event = alloc_event();
3095 if (!event)
3096 return -ENOMEM;
3097
3098 event->name = event_read_name();
3099 if (!event->name)
3100 die("failed to read event name");
3101
3102 event->id = event_read_id();
3103 if (event->id < 0)
3104 die("failed to read event id");
3105
3106 ret = event_read_format(event);
3107 if (ret < 0) {
3108 warning("failed to read event format for %s", event->name);
3109 goto event_failed;
3110 }
3111
3112 ret = event_read_print(event);
3113 if (ret < 0) {
3114 warning("failed to read event print fmt for %s", event->name);
3115 goto event_failed;
3116 }
3117
3118 event->system = strdup(sys);
3119
3120#define PRINT_ARGS 0
3121 if (PRINT_ARGS && event->print_fmt.args)
3122 print_args(event->print_fmt.args);
3123
3124 add_event(event);
3125 return 0;
3126
3127 event_failed:
3128 event->flags |= EVENT_FL_FAILED;
3129 /* still add it even if it failed */
3130 add_event(event);
3131 return -1;
3132}
3133
3134void parse_set_info(int nr_cpus, int long_sz)
3135{
3136 cpus = nr_cpus;
3137 long_size = long_sz;
3138}
3139
3140int common_pc(struct scripting_context *context)
3141{
3142 return parse_common_pc(context->event_data);
3143}
3144
3145int common_flags(struct scripting_context *context)
3146{
3147 return parse_common_flags(context->event_data);
3148}
3149
3150int common_lock_depth(struct scripting_context *context)
3151{
3152 return parse_common_lock_depth(context->event_data);
3153}
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index b9592e0de8d7..f097e0dd6c5c 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -52,6 +52,16 @@ static unsigned long page_size;
52static ssize_t calc_data_size; 52static ssize_t calc_data_size;
53static bool repipe; 53static bool repipe;
54 54
55static void *malloc_or_die(int size)
56{
57 void *ret;
58
59 ret = malloc(size);
60 if (!ret)
61 die("malloc");
62 return ret;
63}
64
55static int do_read(int fd, void *buf, int size) 65static int do_read(int fd, void *buf, int size)
56{ 66{
57 int rsize = size; 67 int rsize = size;
@@ -109,7 +119,7 @@ static unsigned int read4(void)
109 unsigned int data; 119 unsigned int data;
110 120
111 read_or_die(&data, 4); 121 read_or_die(&data, 4);
112 return __data2host4(data); 122 return __data2host4(perf_pevent, data);
113} 123}
114 124
115static unsigned long long read8(void) 125static unsigned long long read8(void)
@@ -117,7 +127,7 @@ static unsigned long long read8(void)
117 unsigned long long data; 127 unsigned long long data;
118 128
119 read_or_die(&data, 8); 129 read_or_die(&data, 8);
120 return __data2host8(data); 130 return __data2host8(perf_pevent, data);
121} 131}
122 132
123static char *read_string(void) 133static char *read_string(void)
@@ -282,7 +292,7 @@ struct cpu_data {
282 unsigned long long offset; 292 unsigned long long offset;
283 unsigned long long size; 293 unsigned long long size;
284 unsigned long long timestamp; 294 unsigned long long timestamp;
285 struct record *next; 295 struct pevent_record *next;
286 char *page; 296 char *page;
287 int cpu; 297 int cpu;
288 int index; 298 int index;
@@ -367,9 +377,9 @@ static int calc_index(void *ptr, int cpu)
367 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page; 377 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
368} 378}
369 379
370struct record *trace_peek_data(int cpu) 380struct pevent_record *trace_peek_data(int cpu)
371{ 381{
372 struct record *data; 382 struct pevent_record *data;
373 void *page = cpu_data[cpu].page; 383 void *page = cpu_data[cpu].page;
374 int idx = cpu_data[cpu].index; 384 int idx = cpu_data[cpu].index;
375 void *ptr = page + idx; 385 void *ptr = page + idx;
@@ -389,15 +399,15 @@ struct record *trace_peek_data(int cpu)
389 /* FIXME: handle header page */ 399 /* FIXME: handle header page */
390 if (header_page_ts_size != 8) 400 if (header_page_ts_size != 8)
391 die("expected a long long type for timestamp"); 401 die("expected a long long type for timestamp");
392 cpu_data[cpu].timestamp = data2host8(ptr); 402 cpu_data[cpu].timestamp = data2host8(perf_pevent, ptr);
393 ptr += 8; 403 ptr += 8;
394 switch (header_page_size_size) { 404 switch (header_page_size_size) {
395 case 4: 405 case 4:
396 cpu_data[cpu].page_size = data2host4(ptr); 406 cpu_data[cpu].page_size = data2host4(perf_pevent, ptr);
397 ptr += 4; 407 ptr += 4;
398 break; 408 break;
399 case 8: 409 case 8:
400 cpu_data[cpu].page_size = data2host8(ptr); 410 cpu_data[cpu].page_size = data2host8(perf_pevent, ptr);
401 ptr += 8; 411 ptr += 8;
402 break; 412 break;
403 default: 413 default:
@@ -414,7 +424,7 @@ read_again:
414 return trace_peek_data(cpu); 424 return trace_peek_data(cpu);
415 } 425 }
416 426
417 type_len_ts = data2host4(ptr); 427 type_len_ts = data2host4(perf_pevent, ptr);
418 ptr += 4; 428 ptr += 4;
419 429
420 type_len = type_len4host(type_len_ts); 430 type_len = type_len4host(type_len_ts);
@@ -424,14 +434,14 @@ read_again:
424 case RINGBUF_TYPE_PADDING: 434 case RINGBUF_TYPE_PADDING:
425 if (!delta) 435 if (!delta)
426 die("error, hit unexpected end of page"); 436 die("error, hit unexpected end of page");
427 length = data2host4(ptr); 437 length = data2host4(perf_pevent, ptr);
428 ptr += 4; 438 ptr += 4;
429 length *= 4; 439 length *= 4;
430 ptr += length; 440 ptr += length;
431 goto read_again; 441 goto read_again;
432 442
433 case RINGBUF_TYPE_TIME_EXTEND: 443 case RINGBUF_TYPE_TIME_EXTEND:
434 extend = data2host4(ptr); 444 extend = data2host4(perf_pevent, ptr);
435 ptr += 4; 445 ptr += 4;
436 extend <<= TS_SHIFT; 446 extend <<= TS_SHIFT;
437 extend += delta; 447 extend += delta;
@@ -442,7 +452,7 @@ read_again:
442 ptr += 12; 452 ptr += 12;
443 break; 453 break;
444 case 0: 454 case 0:
445 length = data2host4(ptr); 455 length = data2host4(perf_pevent, ptr);
446 ptr += 4; 456 ptr += 4;
447 die("here! length=%d", length); 457 die("here! length=%d", length);
448 break; 458 break;
@@ -467,9 +477,9 @@ read_again:
467 return data; 477 return data;
468} 478}
469 479
470struct record *trace_read_data(int cpu) 480struct pevent_record *trace_read_data(int cpu)
471{ 481{
472 struct record *data; 482 struct pevent_record *data;
473 483
474 data = trace_peek_data(cpu); 484 data = trace_peek_data(cpu);
475 cpu_data[cpu].next = NULL; 485 cpu_data[cpu].next = NULL;
@@ -509,6 +519,8 @@ ssize_t trace_report(int fd, bool __repipe)
509 file_bigendian = buf[0]; 519 file_bigendian = buf[0];
510 host_bigendian = bigendian(); 520 host_bigendian = bigendian();
511 521
522 read_trace_init(file_bigendian, host_bigendian);
523
512 read_or_die(buf, 1); 524 read_or_die(buf, 1);
513 long_size = buf[0]; 525 long_size = buf[0];
514 526
@@ -526,11 +538,11 @@ ssize_t trace_report(int fd, bool __repipe)
526 repipe = false; 538 repipe = false;
527 539
528 if (show_funcs) { 540 if (show_funcs) {
529 print_funcs(); 541 pevent_print_funcs(perf_pevent);
530 return size; 542 return size;
531 } 543 }
532 if (show_printk) { 544 if (show_printk) {
533 print_printk(); 545 pevent_print_printk(perf_pevent);
534 return size; 546 return size;
535 } 547 }
536 548
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 58ae14c5baac..639852ac1117 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,20 +1,21 @@
1#ifndef __PERF_TRACE_EVENTS_H 1#ifndef _PERF_UTIL_TRACE_EVENT_H
2#define __PERF_TRACE_EVENTS_H 2#define _PERF_UTIL_TRACE_EVENT_H
3 3
4#include <stdbool.h>
5#include "parse-events.h" 4#include "parse-events.h"
5#include "event-parse.h"
6#include "session.h"
6 7
7struct machine; 8struct machine;
8struct perf_sample; 9struct perf_sample;
9union perf_event; 10union perf_event;
10struct thread; 11struct thread;
11 12
12#define __unused __attribute__((unused)) 13extern int header_page_size_size;
13 14extern int header_page_ts_size;
15extern int header_page_data_offset;
14 16
15#ifndef PAGE_MASK 17extern bool latency_format;
16#define PAGE_MASK (page_size - 1) 18extern struct pevent *perf_pevent;
17#endif
18 19
19enum { 20enum {
20 RINGBUF_TYPE_PADDING = 29, 21 RINGBUF_TYPE_PADDING = 29,
@@ -26,246 +27,37 @@ enum {
26#define TS_SHIFT 27 27#define TS_SHIFT 27
27#endif 28#endif
28 29
29#define NSECS_PER_SEC 1000000000ULL 30int bigendian(void);
30#define NSECS_PER_USEC 1000ULL
31
32enum format_flags {
33 FIELD_IS_ARRAY = 1,
34 FIELD_IS_POINTER = 2,
35 FIELD_IS_SIGNED = 4,
36 FIELD_IS_STRING = 8,
37 FIELD_IS_DYNAMIC = 16,
38 FIELD_IS_FLAG = 32,
39 FIELD_IS_SYMBOLIC = 64,
40};
41
42struct format_field {
43 struct format_field *next;
44 char *type;
45 char *name;
46 int offset;
47 int size;
48 unsigned long flags;
49};
50
51struct format {
52 int nr_common;
53 int nr_fields;
54 struct format_field *common_fields;
55 struct format_field *fields;
56};
57
58struct print_arg_atom {
59 char *atom;
60};
61
62struct print_arg_string {
63 char *string;
64 int offset;
65};
66
67struct print_arg_field {
68 char *name;
69 struct format_field *field;
70};
71
72struct print_flag_sym {
73 struct print_flag_sym *next;
74 char *value;
75 char *str;
76};
77
78struct print_arg_typecast {
79 char *type;
80 struct print_arg *item;
81};
82
83struct print_arg_flags {
84 struct print_arg *field;
85 char *delim;
86 struct print_flag_sym *flags;
87};
88
89struct print_arg_symbol {
90 struct print_arg *field;
91 struct print_flag_sym *symbols;
92};
93
94struct print_arg;
95
96struct print_arg_op {
97 char *op;
98 int prio;
99 struct print_arg *left;
100 struct print_arg *right;
101};
102
103struct print_arg_func {
104 char *name;
105 struct print_arg *args;
106};
107
108enum print_arg_type {
109 PRINT_NULL,
110 PRINT_ATOM,
111 PRINT_FIELD,
112 PRINT_FLAGS,
113 PRINT_SYMBOL,
114 PRINT_TYPE,
115 PRINT_STRING,
116 PRINT_OP,
117};
118
119struct print_arg {
120 struct print_arg *next;
121 enum print_arg_type type;
122 union {
123 struct print_arg_atom atom;
124 struct print_arg_field field;
125 struct print_arg_typecast typecast;
126 struct print_arg_flags flags;
127 struct print_arg_symbol symbol;
128 struct print_arg_func func;
129 struct print_arg_string string;
130 struct print_arg_op op;
131 };
132};
133
134struct print_fmt {
135 char *format;
136 struct print_arg *args;
137};
138
139struct event {
140 struct event *next;
141 char *name;
142 int id;
143 int flags;
144 struct format format;
145 struct print_fmt print_fmt;
146 char *system;
147};
148
149enum {
150 EVENT_FL_ISFTRACE = 0x01,
151 EVENT_FL_ISPRINT = 0x02,
152 EVENT_FL_ISBPRINT = 0x04,
153 EVENT_FL_ISFUNC = 0x08,
154 EVENT_FL_ISFUNCENT = 0x10,
155 EVENT_FL_ISFUNCRET = 0x20,
156
157 EVENT_FL_FAILED = 0x80000000
158};
159
160struct record {
161 unsigned long long ts;
162 int size;
163 void *data;
164};
165
166struct record *trace_peek_data(int cpu);
167struct record *trace_read_data(int cpu);
168
169void parse_set_info(int nr_cpus, int long_sz);
170
171ssize_t trace_report(int fd, bool repipe);
172
173void *malloc_or_die(unsigned int size);
174 31
175void parse_cmdlines(char *file, int size); 32int read_trace_init(int file_bigendian, int host_bigendian);
176void parse_proc_kallsyms(char *file, unsigned int size); 33void print_trace_event(int cpu, void *data, int size);
177void parse_ftrace_printk(char *file, unsigned int size);
178 34
179void print_funcs(void); 35void print_event(int cpu, void *data, int size, unsigned long long nsecs,
180void print_printk(void); 36 char *comm);
181 37
182int parse_ftrace_file(char *buf, unsigned long size); 38int parse_ftrace_file(char *buf, unsigned long size);
183int parse_event_file(char *buf, unsigned long size, char *sys); 39int parse_event_file(char *buf, unsigned long size, char *sys);
184void print_trace_event(int cpu, void *data, int size);
185
186extern int file_bigendian;
187extern int host_bigendian;
188
189int bigendian(void);
190
191static inline unsigned short __data2host2(unsigned short data)
192{
193 unsigned short swap;
194
195 if (host_bigendian == file_bigendian)
196 return data;
197 40
198 swap = ((data & 0xffULL) << 8) | 41struct pevent_record *trace_peek_data(int cpu);
199 ((data & (0xffULL << 8)) >> 8); 42struct event_format *trace_find_event(int type);
200 43
201 return swap; 44unsigned long long
202} 45raw_field_value(struct event_format *event, const char *name, void *data);
203 46void *raw_field_ptr(struct event_format *event, const char *name, void *data);
204static inline unsigned int __data2host4(unsigned int data)
205{
206 unsigned int swap;
207
208 if (host_bigendian == file_bigendian)
209 return data;
210
211 swap = ((data & 0xffULL) << 24) |
212 ((data & (0xffULL << 8)) << 8) |
213 ((data & (0xffULL << 16)) >> 8) |
214 ((data & (0xffULL << 24)) >> 24);
215
216 return swap;
217}
218
219static inline unsigned long long __data2host8(unsigned long long data)
220{
221 unsigned long long swap;
222
223 if (host_bigendian == file_bigendian)
224 return data;
225
226 swap = ((data & 0xffULL) << 56) |
227 ((data & (0xffULL << 8)) << 40) |
228 ((data & (0xffULL << 16)) << 24) |
229 ((data & (0xffULL << 24)) << 8) |
230 ((data & (0xffULL << 32)) >> 8) |
231 ((data & (0xffULL << 40)) >> 24) |
232 ((data & (0xffULL << 48)) >> 40) |
233 ((data & (0xffULL << 56)) >> 56);
234
235 return swap;
236}
237 47
238#define data2host2(ptr) __data2host2(*(unsigned short *)ptr) 48void parse_proc_kallsyms(char *file, unsigned int size __unused);
239#define data2host4(ptr) __data2host4(*(unsigned int *)ptr) 49void parse_ftrace_printk(char *file, unsigned int size __unused);
240#define data2host8(ptr) ({ \
241 unsigned long long __val; \
242 \
243 memcpy(&__val, (ptr), sizeof(unsigned long long)); \
244 __data2host8(__val); \
245})
246 50
247extern int header_page_ts_offset; 51ssize_t trace_report(int fd, bool repipe);
248extern int header_page_ts_size;
249extern int header_page_size_offset;
250extern int header_page_size_size;
251extern int header_page_data_offset;
252extern int header_page_data_size;
253
254extern bool latency_format;
255 52
256int trace_parse_common_type(void *data); 53int trace_parse_common_type(void *data);
257int trace_parse_common_pid(void *data); 54int trace_parse_common_pid(void *data);
258int parse_common_pc(void *data); 55
259int parse_common_flags(void *data); 56struct event_format *trace_find_next_event(struct event_format *event);
260int parse_common_lock_depth(void *data);
261struct event *trace_find_event(int id);
262struct event *trace_find_next_event(struct event *event);
263unsigned long long read_size(void *ptr, int size); 57unsigned long long read_size(void *ptr, int size);
264unsigned long long
265raw_field_value(struct event *event, const char *name, void *data);
266void *raw_field_ptr(struct event *event, const char *name, void *data);
267unsigned long long eval_flag(const char *flag); 58unsigned long long eval_flag(const char *flag);
268 59
60struct pevent_record *trace_read_data(int cpu);
269int read_tracing_data(int fd, struct list_head *pattrs); 61int read_tracing_data(int fd, struct list_head *pattrs);
270 62
271struct tracing_data { 63struct tracing_data {
@@ -280,15 +72,6 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
280void tracing_data_put(struct tracing_data *tdata); 72void tracing_data_put(struct tracing_data *tdata);
281 73
282 74
283/* taken from kernel/trace/trace.h */
284enum trace_flag_type {
285 TRACE_FLAG_IRQS_OFF = 0x01,
286 TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
287 TRACE_FLAG_NEED_RESCHED = 0x04,
288 TRACE_FLAG_HARDIRQ = 0x08,
289 TRACE_FLAG_SOFTIRQ = 0x10,
290};
291
292struct scripting_ops { 75struct scripting_ops {
293 const char *name; 76 const char *name;
294 int (*start_script) (const char *script, int argc, const char **argv); 77 int (*start_script) (const char *script, int argc, const char **argv);
@@ -314,4 +97,4 @@ int common_pc(struct scripting_context *context);
314int common_flags(struct scripting_context *context); 97int common_flags(struct scripting_context *context);
315int common_lock_depth(struct scripting_context *context); 98int common_lock_depth(struct scripting_context *context);
316 99
317#endif /* __PERF_TRACE_EVENTS_H */ 100#endif /* _PERF_UTIL_TRACE_EVENT_H */
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
index 5f3689a3d085..c51fa6b70a28 100644
--- a/tools/perf/util/types.h
+++ b/tools/perf/util/types.h
@@ -16,4 +16,9 @@ typedef signed short s16;
16typedef unsigned char u8; 16typedef unsigned char u8;
17typedef signed char s8; 17typedef signed char s8;
18 18
19union u64_swap {
20 u64 val64;
21 u32 val32[2];
22};
23
19#endif /* __PERF_TYPES_H */ 24#endif /* __PERF_TYPES_H */
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
deleted file mode 100644
index 57a4c6ef3fd2..000000000000
--- a/tools/perf/util/ui/browsers/annotate.c
+++ /dev/null
@@ -1,433 +0,0 @@
1#include "../../util.h"
2#include "../browser.h"
3#include "../helpline.h"
4#include "../libslang.h"
5#include "../ui.h"
6#include "../util.h"
7#include "../../annotate.h"
8#include "../../hist.h"
9#include "../../sort.h"
10#include "../../symbol.h"
11#include <pthread.h>
12#include <newt.h>
13
14struct annotate_browser {
15 struct ui_browser b;
16 struct rb_root entries;
17 struct rb_node *curr_hot;
18 struct objdump_line *selection;
19 int nr_asm_entries;
20 int nr_entries;
21 bool hide_src_code;
22};
23
24struct objdump_line_rb_node {
25 struct rb_node rb_node;
26 double percent;
27 u32 idx;
28 int idx_asm;
29};
30
31static inline
32struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self)
33{
34 return (struct objdump_line_rb_node *)(self + 1);
35}
36
37static bool objdump_line__filter(struct ui_browser *browser, void *entry)
38{
39 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
40
41 if (ab->hide_src_code) {
42 struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
43 return ol->offset == -1;
44 }
45
46 return false;
47}
48
49static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
50{
51 struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
52 struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
53 bool current_entry = ui_browser__is_current_entry(self, row);
54 int width = self->width;
55
56 if (ol->offset != -1) {
57 struct objdump_line_rb_node *olrb = objdump_line__rb(ol);
58 ui_browser__set_percent_color(self, olrb->percent, current_entry);
59 slsmg_printf(" %7.2f ", olrb->percent);
60 } else {
61 ui_browser__set_percent_color(self, 0, current_entry);
62 slsmg_write_nstring(" ", 9);
63 }
64
65 SLsmg_write_char(':');
66 slsmg_write_nstring(" ", 8);
67
68 /* The scroll bar isn't being used */
69 if (!self->navkeypressed)
70 width += 1;
71
72 if (!ab->hide_src_code && ol->offset != -1)
73 if (!current_entry || (self->use_navkeypressed &&
74 !self->navkeypressed))
75 ui_browser__set_color(self, HE_COLORSET_CODE);
76
77 if (!*ol->line)
78 slsmg_write_nstring(" ", width - 18);
79 else
80 slsmg_write_nstring(ol->line, width - 18);
81
82 if (current_entry)
83 ab->selection = ol;
84}
85
86static double objdump_line__calc_percent(struct objdump_line *self,
87 struct symbol *sym, int evidx)
88{
89 double percent = 0.0;
90
91 if (self->offset != -1) {
92 int len = sym->end - sym->start;
93 unsigned int hits = 0;
94 struct annotation *notes = symbol__annotation(sym);
95 struct source_line *src_line = notes->src->lines;
96 struct sym_hist *h = annotation__histogram(notes, evidx);
97 s64 offset = self->offset;
98 struct objdump_line *next;
99
100 next = objdump__get_next_ip_line(&notes->src->source, self);
101 while (offset < (s64)len &&
102 (next == NULL || offset < next->offset)) {
103 if (src_line) {
104 percent += src_line[offset].percent;
105 } else
106 hits += h->addr[offset];
107
108 ++offset;
109 }
110 /*
111 * If the percentage wasn't already calculated in
112 * symbol__get_source_line, do it now:
113 */
114 if (src_line == NULL && h->sum)
115 percent = 100.0 * hits / h->sum;
116 }
117
118 return percent;
119}
120
121static void objdump__insert_line(struct rb_root *self,
122 struct objdump_line_rb_node *line)
123{
124 struct rb_node **p = &self->rb_node;
125 struct rb_node *parent = NULL;
126 struct objdump_line_rb_node *l;
127
128 while (*p != NULL) {
129 parent = *p;
130 l = rb_entry(parent, struct objdump_line_rb_node, rb_node);
131 if (line->percent < l->percent)
132 p = &(*p)->rb_left;
133 else
134 p = &(*p)->rb_right;
135 }
136 rb_link_node(&line->rb_node, parent, p);
137 rb_insert_color(&line->rb_node, self);
138}
139
140static void annotate_browser__set_top(struct annotate_browser *self,
141 struct rb_node *nd)
142{
143 struct objdump_line_rb_node *rbpos;
144 struct objdump_line *pos;
145 unsigned back;
146
147 ui_browser__refresh_dimensions(&self->b);
148 back = self->b.height / 2;
149 rbpos = rb_entry(nd, struct objdump_line_rb_node, rb_node);
150 pos = ((struct objdump_line *)rbpos) - 1;
151 self->b.top_idx = self->b.index = rbpos->idx;
152
153 while (self->b.top_idx != 0 && back != 0) {
154 pos = list_entry(pos->node.prev, struct objdump_line, node);
155
156 --self->b.top_idx;
157 --back;
158 }
159
160 self->b.top = pos;
161 self->curr_hot = nd;
162}
163
164static void annotate_browser__calc_percent(struct annotate_browser *browser,
165 int evidx)
166{
167 struct map_symbol *ms = browser->b.priv;
168 struct symbol *sym = ms->sym;
169 struct annotation *notes = symbol__annotation(sym);
170 struct objdump_line *pos;
171
172 browser->entries = RB_ROOT;
173
174 pthread_mutex_lock(&notes->lock);
175
176 list_for_each_entry(pos, &notes->src->source, node) {
177 struct objdump_line_rb_node *rbpos = objdump_line__rb(pos);
178 rbpos->percent = objdump_line__calc_percent(pos, sym, evidx);
179 if (rbpos->percent < 0.01) {
180 RB_CLEAR_NODE(&rbpos->rb_node);
181 continue;
182 }
183 objdump__insert_line(&browser->entries, rbpos);
184 }
185 pthread_mutex_unlock(&notes->lock);
186
187 browser->curr_hot = rb_last(&browser->entries);
188}
189
190static bool annotate_browser__toggle_source(struct annotate_browser *browser)
191{
192 struct objdump_line *ol;
193 struct objdump_line_rb_node *olrb;
194 off_t offset = browser->b.index - browser->b.top_idx;
195
196 browser->b.seek(&browser->b, offset, SEEK_CUR);
197 ol = list_entry(browser->b.top, struct objdump_line, node);
198 olrb = objdump_line__rb(ol);
199
200 if (browser->hide_src_code) {
201 if (olrb->idx_asm < offset)
202 offset = olrb->idx;
203
204 browser->b.nr_entries = browser->nr_entries;
205 browser->hide_src_code = false;
206 browser->b.seek(&browser->b, -offset, SEEK_CUR);
207 browser->b.top_idx = olrb->idx - offset;
208 browser->b.index = olrb->idx;
209 } else {
210 if (olrb->idx_asm < 0) {
211 ui_helpline__puts("Only available for assembly lines.");
212 browser->b.seek(&browser->b, -offset, SEEK_CUR);
213 return false;
214 }
215
216 if (olrb->idx_asm < offset)
217 offset = olrb->idx_asm;
218
219 browser->b.nr_entries = browser->nr_asm_entries;
220 browser->hide_src_code = true;
221 browser->b.seek(&browser->b, -offset, SEEK_CUR);
222 browser->b.top_idx = olrb->idx_asm - offset;
223 browser->b.index = olrb->idx_asm;
224 }
225
226 return true;
227}
228
229static int annotate_browser__run(struct annotate_browser *self, int evidx,
230 void(*timer)(void *arg),
231 void *arg, int delay_secs)
232{
233 struct rb_node *nd = NULL;
234 struct map_symbol *ms = self->b.priv;
235 struct symbol *sym = ms->sym;
236 const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, "
237 "H: Go to hottest line, ->/ENTER: Line action, "
238 "S: Toggle source code view";
239 int key;
240
241 if (ui_browser__show(&self->b, sym->name, help) < 0)
242 return -1;
243
244 annotate_browser__calc_percent(self, evidx);
245
246 if (self->curr_hot)
247 annotate_browser__set_top(self, self->curr_hot);
248
249 nd = self->curr_hot;
250
251 while (1) {
252 key = ui_browser__run(&self->b, delay_secs);
253
254 if (delay_secs != 0) {
255 annotate_browser__calc_percent(self, evidx);
256 /*
257 * Current line focus got out of the list of most active
258 * lines, NULL it so that if TAB|UNTAB is pressed, we
259 * move to curr_hot (current hottest line).
260 */
261 if (nd != NULL && RB_EMPTY_NODE(nd))
262 nd = NULL;
263 }
264
265 switch (key) {
266 case K_TIMER:
267 if (timer != NULL)
268 timer(arg);
269
270 if (delay_secs != 0)
271 symbol__annotate_decay_histogram(sym, evidx);
272 continue;
273 case K_TAB:
274 if (nd != NULL) {
275 nd = rb_prev(nd);
276 if (nd == NULL)
277 nd = rb_last(&self->entries);
278 } else
279 nd = self->curr_hot;
280 break;
281 case K_UNTAB:
282 if (nd != NULL)
283 nd = rb_next(nd);
284 if (nd == NULL)
285 nd = rb_first(&self->entries);
286 else
287 nd = self->curr_hot;
288 break;
289 case 'H':
290 case 'h':
291 nd = self->curr_hot;
292 break;
293 case 'S':
294 case 's':
295 if (annotate_browser__toggle_source(self))
296 ui_helpline__puts(help);
297 continue;
298 case K_ENTER:
299 case K_RIGHT:
300 if (self->selection == NULL) {
301 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
302 continue;
303 }
304
305 if (self->selection->offset == -1) {
306 ui_helpline__puts("Actions are only available for assembly lines.");
307 continue;
308 } else {
309 char *s = strstr(self->selection->line, "callq ");
310 struct annotation *notes;
311 struct symbol *target;
312 u64 ip;
313
314 if (s == NULL) {
315 ui_helpline__puts("Actions are only available for the 'callq' instruction.");
316 continue;
317 }
318
319 s = strchr(s, ' ');
320 if (s++ == NULL) {
321 ui_helpline__puts("Invallid callq instruction.");
322 continue;
323 }
324
325 ip = strtoull(s, NULL, 16);
326 ip = ms->map->map_ip(ms->map, ip);
327 target = map__find_symbol(ms->map, ip, NULL);
328 if (target == NULL) {
329 ui_helpline__puts("The called function was not found.");
330 continue;
331 }
332
333 notes = symbol__annotation(target);
334 pthread_mutex_lock(&notes->lock);
335
336 if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
337 pthread_mutex_unlock(&notes->lock);
338 ui__warning("Not enough memory for annotating '%s' symbol!\n",
339 target->name);
340 continue;
341 }
342
343 pthread_mutex_unlock(&notes->lock);
344 symbol__tui_annotate(target, ms->map, evidx,
345 timer, arg, delay_secs);
346 ui_browser__show_title(&self->b, sym->name);
347 }
348 continue;
349 case K_LEFT:
350 case K_ESC:
351 case 'q':
352 case CTRL('c'):
353 goto out;
354 default:
355 continue;
356 }
357
358 if (nd != NULL)
359 annotate_browser__set_top(self, nd);
360 }
361out:
362 ui_browser__hide(&self->b);
363 return key;
364}
365
366int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
367 void(*timer)(void *arg), void *arg, int delay_secs)
368{
369 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
370 timer, arg, delay_secs);
371}
372
373int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
374 void(*timer)(void *arg), void *arg,
375 int delay_secs)
376{
377 struct objdump_line *pos, *n;
378 struct annotation *notes;
379 struct map_symbol ms = {
380 .map = map,
381 .sym = sym,
382 };
383 struct annotate_browser browser = {
384 .b = {
385 .refresh = ui_browser__list_head_refresh,
386 .seek = ui_browser__list_head_seek,
387 .write = annotate_browser__write,
388 .filter = objdump_line__filter,
389 .priv = &ms,
390 .use_navkeypressed = true,
391 },
392 };
393 int ret;
394
395 if (sym == NULL)
396 return -1;
397
398 if (map->dso->annotate_warned)
399 return -1;
400
401 if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) {
402 ui__error("%s", ui_helpline__last_msg);
403 return -1;
404 }
405
406 ui_helpline__push("Press <- or ESC to exit");
407
408 notes = symbol__annotation(sym);
409
410 list_for_each_entry(pos, &notes->src->source, node) {
411 struct objdump_line_rb_node *rbpos;
412 size_t line_len = strlen(pos->line);
413
414 if (browser.b.width < line_len)
415 browser.b.width = line_len;
416 rbpos = objdump_line__rb(pos);
417 rbpos->idx = browser.nr_entries++;
418 if (pos->offset != -1)
419 rbpos->idx_asm = browser.nr_asm_entries++;
420 else
421 rbpos->idx_asm = -1;
422 }
423
424 browser.b.nr_entries = browser.nr_entries;
425 browser.b.entries = &notes->src->source,
426 browser.b.width += 18; /* Percentage */
427 ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
428 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
429 list_del(&pos->node);
430 objdump_line__free(pos);
431 }
432 return ret;
433}
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c
index 52bb07c6442a..4007aca8e0ca 100644
--- a/tools/perf/util/usage.c
+++ b/tools/perf/util/usage.c
@@ -82,41 +82,3 @@ void warning(const char *warn, ...)
82 warn_routine(warn, params); 82 warn_routine(warn, params);
83 va_end(params); 83 va_end(params);
84} 84}
85
86uid_t parse_target_uid(const char *str, const char *tid, const char *pid)
87{
88 struct passwd pwd, *result;
89 char buf[1024];
90
91 if (str == NULL)
92 return UINT_MAX;
93
94 /* UID and PID are mutually exclusive */
95 if (tid || pid) {
96 ui__warning("PID/TID switch overriding UID\n");
97 sleep(1);
98 return UINT_MAX;
99 }
100
101 getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
102
103 if (result == NULL) {
104 char *endptr;
105 int uid = strtol(str, &endptr, 10);
106
107 if (*endptr != '\0') {
108 ui__error("Invalid user %s\n", str);
109 return UINT_MAX - 1;
110 }
111
112 getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
113
114 if (result == NULL) {
115 ui__error("Problems obtaining information for user %s\n",
116 str);
117 return UINT_MAX - 1;
118 }
119 }
120
121 return result->pw_uid;
122}
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 8109a907841e..d03599fbe78b 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -148,3 +148,13 @@ int readn(int fd, void *buf, size_t n)
148 148
149 return buf - buf_start; 149 return buf - buf_start;
150} 150}
151
152size_t hex_width(u64 v)
153{
154 size_t n = 1;
155
156 while ((v >>= 4))
157 ++n;
158
159 return n;
160}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 0f99f394d8e0..2daaedb83d84 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -74,7 +74,6 @@
74#include <netinet/tcp.h> 74#include <netinet/tcp.h>
75#include <arpa/inet.h> 75#include <arpa/inet.h>
76#include <netdb.h> 76#include <netdb.h>
77#include <pwd.h>
78#include <inttypes.h> 77#include <inttypes.h>
79#include "../../../include/linux/magic.h" 78#include "../../../include/linux/magic.h"
80#include "types.h" 79#include "types.h"
@@ -249,8 +248,6 @@ struct perf_event_attr;
249 248
250void event_attr_init(struct perf_event_attr *attr); 249void event_attr_init(struct perf_event_attr *attr);
251 250
252uid_t parse_target_uid(const char *str, const char *tid, const char *pid);
253
254#define _STR(x) #x 251#define _STR(x) #x
255#define STR(x) _STR(x) 252#define STR(x) _STR(x)
256 253
@@ -265,4 +262,6 @@ bool is_power_of_2(unsigned long n)
265 return (n != 0 && ((n & (n - 1)) == 0)); 262 return (n != 0 && ((n & (n - 1)) == 0));
266} 263}
267 264
265size_t hex_width(u64 v);
266
268#endif 267#endif
diff --git a/tools/power/cpupower/man/cpupower-set.1 b/tools/power/cpupower/man/cpupower-set.1
index c4954a9fe4e7..9dbd536518ab 100644
--- a/tools/power/cpupower/man/cpupower-set.1
+++ b/tools/power/cpupower/man/cpupower-set.1
@@ -85,15 +85,6 @@ Possible values are:
85savings 85savings
86.RE 86.RE
87 87
88sched_mc_power_savings is dependent upon SCHED_MC, which is
89itself architecture dependent.
90
91sched_smt_power_savings is dependent upon SCHED_SMT, which
92is itself architecture dependent.
93
94The two files are independent of each other. It is possible
95that one file may be present without the other.
96
97.SH "SEE ALSO" 88.SH "SEE ALSO"
98cpupower-info(1), cpupower-monitor(1), powertop(1) 89cpupower-info(1), cpupower-monitor(1), powertop(1)
99.PP 90.PP
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
index c6343024a611..96e28c124b5c 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.c
+++ b/tools/power/cpupower/utils/helpers/sysfs.c
@@ -362,22 +362,7 @@ char *sysfs_get_cpuidle_driver(void)
362 */ 362 */
363int sysfs_get_sched(const char *smt_mc) 363int sysfs_get_sched(const char *smt_mc)
364{ 364{
365 unsigned long value; 365 return -ENODEV;
366 char linebuf[MAX_LINE_LEN];
367 char *endp;
368 char path[SYSFS_PATH_MAX];
369
370 if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
371 return -EINVAL;
372
373 snprintf(path, sizeof(path),
374 PATH_TO_CPU "sched_%s_power_savings", smt_mc);
375 if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0)
376 return -1;
377 value = strtoul(linebuf, &endp, 0);
378 if (endp == linebuf || errno == ERANGE)
379 return -1;
380 return value;
381} 366}
382 367
383/* 368/*
@@ -388,21 +373,5 @@ int sysfs_get_sched(const char *smt_mc)
388 */ 373 */
389int sysfs_set_sched(const char *smt_mc, int val) 374int sysfs_set_sched(const char *smt_mc, int val)
390{ 375{
391 char linebuf[MAX_LINE_LEN]; 376 return -ENODEV;
392 char path[SYSFS_PATH_MAX];
393 struct stat statbuf;
394
395 if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
396 return -EINVAL;
397
398 snprintf(path, sizeof(path),
399 PATH_TO_CPU "sched_%s_power_savings", smt_mc);
400 sprintf(linebuf, "%d", val);
401
402 if (stat(path, &statbuf) != 0)
403 return -ENODEV;
404
405 if (sysfs_write_file(path, linebuf, MAX_LINE_LEN) == 0)
406 return -1;
407 return 0;
408} 377}
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include
new file mode 100644
index 000000000000..bde8521d56bb
--- /dev/null
+++ b/tools/scripts/Makefile.include
@@ -0,0 +1,58 @@
1ifeq ("$(origin O)", "command line")
2 OUTPUT := $(O)/
3 COMMAND_O := O=$(O)
4endif
5
6ifneq ($(OUTPUT),)
7# check that the output directory actually exists
8OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
9$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
10endif
11
12#
13# Include saner warnings here, which can catch bugs:
14#
15EXTRA_WARNINGS := -Wbad-function-cast
16EXTRA_WARNINGS += -Wdeclaration-after-statement
17EXTRA_WARNINGS += -Wformat-security
18EXTRA_WARNINGS += -Wformat-y2k
19EXTRA_WARNINGS += -Winit-self
20EXTRA_WARNINGS += -Wmissing-declarations
21EXTRA_WARNINGS += -Wmissing-prototypes
22EXTRA_WARNINGS += -Wnested-externs
23EXTRA_WARNINGS += -Wno-system-headers
24EXTRA_WARNINGS += -Wold-style-definition
25EXTRA_WARNINGS += -Wpacked
26EXTRA_WARNINGS += -Wredundant-decls
27EXTRA_WARNINGS += -Wshadow
28EXTRA_WARNINGS += -Wstrict-aliasing=3
29EXTRA_WARNINGS += -Wstrict-prototypes
30EXTRA_WARNINGS += -Wswitch-default
31EXTRA_WARNINGS += -Wswitch-enum
32EXTRA_WARNINGS += -Wundef
33EXTRA_WARNINGS += -Wwrite-strings
34EXTRA_WARNINGS += -Wformat
35
36ifneq ($(findstring $(MAKEFLAGS), w),w)
37PRINT_DIR = --no-print-directory
38else
39NO_SUBDIR = :
40endif
41
42QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
43QUIET_SUBDIR1 =
44
45ifneq ($(findstring $(MAKEFLAGS),s),s)
46ifndef V
47 QUIET_CC = @echo ' ' CC $@;
48 QUIET_AR = @echo ' ' AR $@;
49 QUIET_LINK = @echo ' ' LINK $@;
50 QUIET_MKDIR = @echo ' ' MKDIR $@;
51 QUIET_GEN = @echo ' ' GEN $@;
52 QUIET_SUBDIR0 = +@subdir=
53 QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
54 $(MAKE) $(PRINT_DIR) -C $$subdir
55 QUIET_FLEX = @echo ' ' FLEX $@;
56 QUIET_BISON = @echo ' ' BISON $@;
57endif
58endif
diff --git a/tools/testing/ktest/examples/README b/tools/testing/ktest/examples/README
new file mode 100644
index 000000000000..a12d295a09d8
--- /dev/null
+++ b/tools/testing/ktest/examples/README
@@ -0,0 +1,32 @@
1This directory contains example configs to use ktest for various tasks.
2The configs still need to be customized for your environment, but it
3is broken up by task which makes it easier to understand how to set up
4ktest.
5
6The configs are based off of real working configs but have been modified
7and commented to show more generic use cases that are more helpful for
8developers.
9
10crosstests.conf - this config shows an example of testing a git repo against
11 lots of different architectures. It only does build tests, but makes
12 it easy to compile test different archs. You can download the arch
13 cross compilers from:
14 http://kernel.org/pub/tools/crosstool/files/bin/x86_64/
15
16test.conf - A generic example of a config. This is based on an actual config
17 used to perform real testing.
18
19kvm.conf - A example of a config that is used to test a virtual guest running
20 on a host.
21
22snowball.conf - An example config that was used to demo ktest.pl against
23 a snowball ARM board.
24
25include/ - The include directory holds default configs that can be
26 included into other configs. This is a real use example that shows how
27 to reuse configs for various machines or set ups. The files here
28 are included by other config files, where the other config files define
29 options and variables that will make the included config work for the
30 given environment.
31
32
diff --git a/tools/testing/ktest/examples/crosstests.conf b/tools/testing/ktest/examples/crosstests.conf
new file mode 100644
index 000000000000..46736604c26c
--- /dev/null
+++ b/tools/testing/ktest/examples/crosstests.conf
@@ -0,0 +1,260 @@
1#
2# Example config for cross compiling
3#
4# In this config, it is expected that the tool chains from:
5#
6# http://kernel.org/pub/tools/crosstool/files/bin/x86_64/
7#
8# running on a x86_64 system have been downloaded and installed into:
9#
10# /usr/local/
11#
12# such that the compiler binaries are something like:
13#
14# /usr/local/gcc-4.5.2-nolibc/mips-linux/bin/mips-linux-gcc
15#
16# Some of the archs will use gcc-4.5.1 instead of gcc-4.5.2
17# this config uses variables to differentiate them.
18#
19# Comments describe some of the options, but full descriptions of
20# options are described in the samples.conf file.
21
22# ${PWD} is defined by ktest.pl to be the directory that the user
23# was in when they executed ktest.pl. It may be better to hardcode the
24# path name here. THIS_DIR is the variable used through out the config file
25# in case you want to change it.
26
27THIS_DIR := ${PWD}
28
29# Update the BUILD_DIR option to the location of your git repo you want to test.
30BUILD_DIR = ${THIS_DIR}/linux.git
31
32# The build will go into this directory. It will be created when you run the test.
33OUTPUT_DIR = ${THIS_DIR}/cross-compile
34
35# The build will be compiled with -j8
36BUILD_OPTIONS = -j8
37
38# The test will not stop when it hits a failure.
39DIE_ON_FAILURE = 0
40
41# If you want to have ktest.pl store the failure somewhere, uncomment this option
42# and change the directory where ktest should store the failures.
43#STORE_FAILURES = ${THIS_DIR}/failures
44
45# The log file is stored in the OUTPUT_DIR called cross.log
46# If you enable this, you need to create the OUTPUT_DIR. It wont be created for you.
47LOG_FILE = ${OUTPUT_DIR}/cross.log
48
49# The log file will be cleared each time you run ktest.
50CLEAR_LOG = 1
51
52# As some archs do not build with the defconfig, they have been marked
53# to be ignored. If you want to test them anyway, change DO_FAILED to 1.
54# If a test that has been marked as DO_FAILED passes, then you should change
55# that test to be DO_DEFAULT
56
57DO_FAILED := 0
58DO_DEFAULT := 1
59
60# By setting both DO_FAILED and DO_DEFAULT to zero, you can pick a single
61# arch that you want to test. (uncomment RUN and chose your arch)
62#RUN := m32r
63
64# At the bottom of the config file exists a bisect test. You can update that
65# test and set DO_FAILED and DO_DEFAULT to zero, and uncomment this variable
66# to run the bisect on the arch.
67#RUN := bisect
68
69# By default all tests will be running gcc 4.5.2. Some tests are using 4.5.1
70# and they select that in the test.
71# Note: GCC_VER is declared as on option and not a variable ('=' instead of ':=')
72# This is important. A variable is used only in the config file and if it is set
73# it stays that way for the rest of the config file until it is change again.
74# Here we want GCC_VER to remain persistent and change for each test, as it is used in
75# the MAKE_CMD. By using '=' instead of ':=' we achieve our goal.
76
77GCC_VER = 4.5.2
78MAKE_CMD = PATH=/usr/local/gcc-${GCC_VER}-nolibc/${CROSS}/bin:$PATH CROSS_COMPILE=${CROSS}- make ARCH=${ARCH}
79
80# all tests are only doing builds.
81TEST_TYPE = build
82
83# If you want to add configs on top of the defconfig, you can add those configs into
84# the add-config file and uncomment this option. This is useful if you want to test
85# all cross compiles with PREEMPT set, or TRACING on, etc.
86#ADD_CONFIG = ${THIS_DIR}/add-config
87
88# All tests are using defconfig
89BUILD_TYPE = defconfig
90
91# The test names will have the arch and cross compiler used. This will be shown in
92# the results.
93TEST_NAME = ${ARCH} ${CROSS}
94
95# alpha
96TEST_START IF ${RUN} == alpha || ${DO_DEFAULT}
97# Notice that CROSS and ARCH are also options and not variables (again '=' instead
98# of ':='). This is because TEST_NAME and MAKE_CMD wil use them for each test.
99# Only options are available during runs. Variables are only present in parsing the
100# config file.
101CROSS = alpha-linux
102ARCH = alpha
103
104# arm
105TEST_START IF ${RUN} == arm || ${DO_DEFAULT}
106CROSS = arm-unknown-linux-gnueabi
107ARCH = arm
108
109# black fin
110TEST_START IF ${RUN} == bfin || ${DO_DEFAULT}
111CROSS = bfin-uclinux
112ARCH = blackfin
113BUILD_OPTIONS = -j8 vmlinux
114
115# cris - FAILS?
116TEST_START IF ${RUN} == cris || ${RUN} == cris64 || ${DO_FAILED}
117CROSS = cris-linux
118ARCH = cris
119
120# cris32 - not right arch?
121TEST_START IF ${RUN} == cris || ${RUN} == cris32 || ${DO_FAILED}
122CROSS = crisv32-linux
123ARCH = cris
124
125# ia64
126TEST_START IF ${RUN} == ia64 || ${DO_DEFAULT}
127CROSS = ia64-linux
128ARCH = ia64
129
130# frv
131TEST_START IF ${RUN} == frv || ${DO_FAILED}
132CROSS = frv-linux
133ARCH = frv
134GCC_VER = 4.5.1
135
136# h8300 - failed make defconfig??
137TEST_START IF ${RUN} == h8300 || ${DO_FAILED}
138CROSS = h8300-elf
139ARCH = h8300
140GCC_VER = 4.5.1
141
142# m68k fails with error?
143TEST_START IF ${RUN} == m68k || ${DO_DEFAULT}
144CROSS = m68k-linux
145ARCH = m68k
146
147# mips64
148TEST_START IF ${RUN} == mips || ${RUN} == mips64 || ${DO_DEFAULT}
149CROSS = mips64-linux
150ARCH = mips
151
152# mips32
153TEST_START IF ${RUN} == mips || ${RUN} == mips32 || ${DO_DEFAULT}
154CROSS = mips-linux
155ARCH = mips
156
157# m32r
158TEST_START IF ${RUN} == m32r || ${DO_FAILED}
159CROSS = m32r-linux
160ARCH = m32r
161GCC_VER = 4.5.1
162BUILD_OPTIONS = -j8 vmlinux
163
164# parisc64 failed?
165TEST_START IF ${RUN} == hppa || ${RUN} == hppa64 || ${DO_FAILED}
166CROSS = hppa64-linux
167ARCH = parisc
168
169# parisc
170TEST_START IF ${RUN} == hppa || ${RUN} == hppa32 || ${DO_FAILED}
171CROSS = hppa-linux
172ARCH = parisc
173
174# ppc
175TEST_START IF ${RUN} == ppc || ${RUN} == ppc32 || ${DO_DEFAULT}
176CROSS = powerpc-linux
177ARCH = powerpc
178
179# ppc64
180TEST_START IF ${RUN} == ppc || ${RUN} == ppc64 || ${DO_DEFAULT}
181CROSS = powerpc64-linux
182ARCH = powerpc
183
184# s390
185TEST_START IF ${RUN} == s390 || ${DO_DEFAULT}
186CROSS = s390x-linux
187ARCH = s390
188
189# sh
190TEST_START IF ${RUN} == sh || ${DO_DEFAULT}
191CROSS = sh4-linux
192ARCH = sh
193
194# sparc64
195TEST_START IF ${RUN} == sparc || ${RUN} == sparc64 || ${DO_DEFAULT}
196CROSS = sparc64-linux
197ARCH = sparc64
198
199# sparc
200TEST_START IF ${RUN} == sparc || ${RUN} == sparc32 || ${DO_DEFAULT}
201CROSS = sparc-linux
202ARCH = sparc
203
204# xtensa failed
205TEST_START IF ${RUN} == xtensa || ${DO_FAILED}
206CROSS = xtensa-linux
207ARCH = xtensa
208
209# UML
210TEST_START IF ${RUN} == uml || ${DO_DEFAULT}
211MAKE_CMD = make ARCH=um SUBARCH=x86_64
212ARCH = uml
213CROSS =
214
215TEST_START IF ${RUN} == x86 || ${RUN} == i386 || ${DO_DEFAULT}
216MAKE_CMD = make ARCH=i386
217ARCH = i386
218CROSS =
219
220TEST_START IF ${RUN} == x86 || ${RUN} == x86_64 || ${DO_DEFAULT}
221MAKE_CMD = make ARCH=x86_64
222ARCH = x86_64
223CROSS =
224
225#################################
226
227# This is a bisect if needed. You need to give it a MIN_CONFIG that
228# will be the config file it uses. Basically, just copy the created defconfig
229# for the arch someplace and point MIN_CONFIG to it.
230TEST_START IF ${RUN} == bisect
231MIN_CONFIG = ${THIS_DIR}/min-config
232CROSS = s390x-linux
233ARCH = s390
234TEST_TYPE = bisect
235BISECT_TYPE = build
236BISECT_GOOD = v3.1
237BISECT_BAD = v3.2
238CHECKOUT = v3.2
239
240#################################
241
242# These defaults are needed to keep ktest.pl from complaining. They are
243# ignored because the test does not go pass the build. No install or
244# booting of the target images.
245
246DEFAULTS
247MACHINE = crosstest
248SSH_USER = root
249BUILD_TARGET = cross
250TARGET_IMAGE = image
251POWER_CYCLE = cycle
252CONSOLE = console
253LOCALVERSION = version
254GRUB_MENU = grub
255
256REBOOT_ON_ERROR = 0
257POWEROFF_ON_ERROR = 0
258POWEROFF_ON_SUCCESS = 0
259REBOOT_ON_SUCCESS = 0
260
diff --git a/tools/testing/ktest/examples/include/bisect.conf b/tools/testing/ktest/examples/include/bisect.conf
new file mode 100644
index 000000000000..009bea65bfb6
--- /dev/null
+++ b/tools/testing/ktest/examples/include/bisect.conf
@@ -0,0 +1,90 @@
1#
2# This example shows the bisect tests (git bisect and config bisect)
3#
4
5
6# The config that includes this file may define a RUN_TEST
7# variable that will tell this config what test to run.
8# (what to set the TEST option to).
9#
10DEFAULTS IF NOT DEFINED RUN_TEST
11# Requires that hackbench is in the PATH
12RUN_TEST := ${SSH} hackbench 50
13
14
15# Set TEST to 'bisect' to do a normal git bisect. You need
16# to modify the options below to make it bisect the exact
17# commits you are interested in.
18#
19TEST_START IF ${TEST} == bisect
20TEST_TYPE = bisect
21# You must set the commit that was considered good (git bisect good)
22BISECT_GOOD = v3.3
23# You must set the commit that was considered bad (git bisect bad)
24BISECT_BAD = HEAD
25# It's best to specify the branch to checkout before starting the bisect.
26CHECKOUT = origin/master
27# This can be build, boot, or test. Here we are doing a bisect
28# that requires to run a test to know if the bisect was good or bad.
29# The test should exit with 0 on good, non-zero for bad. But see
30# the BISECT_RET_* options in samples.conf to override this.
31BISECT_TYPE = test
32TEST = ${RUN_TEST}
33# It is usually a good idea to confirm that the GOOD and the BAD
34# commits are truly good and bad respectively. Having BISECT_CHECK
35# set to 1 will check both that the good commit works and the bad
36# commit fails. If you only want to check one or the other,
37# set BISECT_CHECK to 'good' or to 'bad'.
38BISECT_CHECK = 1
39#BISECT_CHECK = good
40#BISECT_CHECK = bad
41
42# Usually it's a good idea to specify the exact config you
43# want to use throughout the entire bisect. Here we placed
44# it in the directory we called ktest.pl from and named it
45# 'config-bisect'.
46MIN_CONFIG = ${THIS_DIR}/config-bisect
47# By default, if we are doing a BISECT_TYPE = test run but the
48# build or boot fails, ktest.pl will do a 'git bisect skip'.
49# Uncomment the below option to make ktest stop testing on such
50# an error.
51#BISECT_SKIP = 0
52# Now if you had BISECT_SKIP = 0 and the test fails, you can
53# examine what happened and then do 'git bisect log > /tmp/replay'
54# Set BISECT_REPLAY to /tmp/replay and ktest.pl will run the
55# 'git bisect replay /tmp/replay' before continuing the bisect test.
56#BISECT_REPLAY = /tmp/replay
57# If you used BISECT_REPLAY after the bisect test failed, you may
58# not want to continue the bisect on that commit that failed.
59# By setting BISECT_START to a new commit. ktest.pl will checkout
60# that commit after it has performed the 'git bisect replay' but
61# before it continues running the bisect test.
62#BISECT_START = 2545eb6198e7e1ec50daa0cfc64a4cdfecf24ec9
63
64# Now if you don't trust ktest.pl to make the decisions for you, then
65# set BISECT_MANUAL to 1. This will cause ktest.pl not to decide
66# if the commit was good or bad. Instead, it will ask you to tell
67# it if the current commit was good. In the mean time, you could
68# take the result, load it on any machine you want. Run several tests,
69# or whatever you feel like. Then, when you are happy, you can tell
70# ktest if you think it was good or not and ktest.pl will continue
71# the git bisect. You can even change what commit it is currently at.
72#BISECT_MANUAL = 1
73
74
75# One of the unique tests that ktest does is the config bisect.
76# Currently (which hopefully will be fixed soon), the bad config
77# must be a superset of the good config. This is because it only
78# searches for a config that causes the target to fail. If the
79# good config is not a subset of the bad config, or if the target
80# fails because of a lack of a config, then it will not find
81# the config for you.
82TEST_START IF ${TEST} == config-bisect
83TEST_TYPE = config_bisect
84# set to build, boot, test
85CONFIG_BISECT_TYPE = boot
86# Set the config that is considered bad.
87CONFIG_BISECT = ${THIS_DIR}/config-bad
88# This config is optional. By default it uses the
89# MIN_CONFIG as the good config.
90CONFIG_BISECT_GOOD = ${THIS_DIR}/config-good
diff --git a/tools/testing/ktest/examples/include/defaults.conf b/tools/testing/ktest/examples/include/defaults.conf
new file mode 100644
index 000000000000..323a552ce642
--- /dev/null
+++ b/tools/testing/ktest/examples/include/defaults.conf
@@ -0,0 +1,157 @@
1# This file holds defaults for most the tests. It defines the options that
2# are most common to tests that are likely to be shared.
3#
4# Note, after including this file, a config file may override any option
5# with a DEFAULTS OVERRIDE section.
6#
7
8# For those cases that use the same machine to boot a 64 bit
9# and a 32 bit version. The MACHINE is the DNS name to get to the
10# box (usually different if it was 64 bit or 32 bit) but the
11# BOX here is defined as a variable that will be the name of the box
12# itself. It is useful for calling scripts that will power cycle
13# the box, as only one script needs to be created to power cycle
14# even though the box itself has multiple operating systems on it.
15# By default, BOX and MACHINE are the same.
16
17DEFAULTS IF NOT DEFINED BOX
18BOX := ${MACHINE}
19
20
21# Consider each box as 64 bit box, unless the config including this file
22# has defined BITS = 32
23
24DEFAULTS IF NOT DEFINED BITS
25BITS := 64
26
27
28DEFAULTS
29
30# THIS_DIR is used through out the configs and defaults to ${PWD} which
31# is the directory that ktest.pl was called from.
32
33THIS_DIR := ${PWD}
34
35
36# to orginize your configs, having each machine save their configs
37# into a separate directly is useful.
38CONFIG_DIR := ${THIS_DIR}/configs/${MACHINE}
39
40# Reset the log before running each test.
41CLEAR_LOG = 1
42
43# As installing kernels usually requires root privilege, default the
44# user on the target as root. It is also required that the target
45# allows ssh to root from the host without asking for a password.
46
47SSH_USER = root
48
49# For accesing the machine, we will ssh to root@machine.
50SSH := ssh ${SSH_USER}@${MACHINE}
51
52# Update this. The default here is ktest will ssh to the target box
53# and run a script called 'run-test' located on that box.
54TEST = ${SSH} run-test
55
56# Point build dir to the git repo you use
57BUILD_DIR = ${THIS_DIR}/linux.git
58
59# Each machine will have its own output build directory.
60OUTPUT_DIR = ${THIS_DIR}/build/${MACHINE}
61
62# Yes this config is focused on x86 (but ktest works for other archs too)
63BUILD_TARGET = arch/x86/boot/bzImage
64TARGET_IMAGE = /boot/vmlinuz-test
65
66# have directory for the scripts to reboot and power cycle the boxes
67SCRIPTS_DIR := ${THIS_DIR}/scripts
68
69# You can have each box/machine have a script to power cycle it.
70# Name your script <box>-cycle.
71POWER_CYCLE = ${SCRIPTS_DIR}/${BOX}-cycle
72
73# This script is used to power off the box.
74POWER_OFF = ${SCRIPTS_DIR}/${BOX}-poweroff
75
76# Keep your test kernels separate from your other kernels.
77LOCALVERSION = -test
78
79# The /boot/grub/menu.lst is searched for the line:
80# title Test Kernel
81# and ktest will use that kernel to reboot into.
82# For grub2 or other boot loaders, you need to set BOOT_TYPE
83# to 'script' and define other ways to load the kernel.
84# See snowball.conf example.
85#
86GRUB_MENU = Test Kernel
87
88# The kernel build will use this option.
89BUILD_OPTIONS = -j8
90
91# Keeping the log file with the output dir is convenient.
92LOG_FILE = ${OUTPUT_DIR}/${MACHINE}.log
93
94# Each box should have their own minum configuration
95# See min-config.conf
96MIN_CONFIG = ${CONFIG_DIR}/config-min
97
98# For things like randconfigs, there may be configs you find that
99# are already broken, or there may be some configs that you always
100# want set. Uncomment ADD_CONFIG and point it to the make config files
101# that set the configs you want to keep on (or off) in your build.
102# ADD_CONFIG is usually something to add configs to all machines,
103# where as, MIN_CONFIG is specific per machine.
104#ADD_CONFIG = ${THIS_DIR}/config-broken ${THIS_DIR}/config-general
105
106# To speed up reboots for bisects and patchcheck, instead of
107# waiting 60 seconds for the console to be idle, if this line is
108# seen in the console output, ktest will know the good kernel has
109# finished rebooting and it will be able to continue the tests.
110REBOOT_SUCCESS_LINE = ${MACHINE} login:
111
112# The following is different ways to end the test.
113# by setting the variable REBOOT to: none, error, fail or
114# something else, ktest will power cycle or reboot the target box
115# at the end of the tests.
116#
117# REBOOT := none
118# Don't do anything at the end of the test.
119#
120# REBOOT := error
121# Reboot the box if ktest detects an error
122#
123# REBOOT := fail
124# Do not stop on failure, and after all tests are complete
125# power off the box (for both success and error)
126# This is good to run over a weekend and you don't want to waste
127# electricity.
128#
129
130DEFAULTS IF ${REBOOT} == none
131REBOOT_ON_SUCCESS = 0
132REBOOT_ON_ERROR = 0
133POWEROFF_ON_ERROR = 0
134POWEROFF_ON_SUCCESS = 0
135
136DEFAULTS ELSE IF ${REBOOT} == error
137REBOOT_ON_SUCCESS = 0
138REBOOT_ON_ERROR = 1
139POWEROFF_ON_ERROR = 0
140POWEROFF_ON_SUCCESS = 0
141
142DEFAULTS ELSE IF ${REBOOT} == fail
143REBOOT_ON_SUCCESS = 0
144POWEROFF_ON_ERROR = 1
145POWEROFF_ON_SUCCESS = 1
146POWEROFF_AFTER_HALT = 120
147DIE_ON_FAILURE = 0
148
149# Store the failure information into this directory
150# such as the .config, dmesg, and build log.
151STORE_FAILURES = ${THIS_DIR}/failures
152
153DEFAULTS ELSE
154REBOOT_ON_SUCCESS = 1
155REBOOT_ON_ERROR = 1
156POWEROFF_ON_ERROR = 0
157POWEROFF_ON_SUCCESS = 0
diff --git a/tools/testing/ktest/examples/include/min-config.conf b/tools/testing/ktest/examples/include/min-config.conf
new file mode 100644
index 000000000000..c703cc46d151
--- /dev/null
+++ b/tools/testing/ktest/examples/include/min-config.conf
@@ -0,0 +1,60 @@
1#
2# This file has some examples for creating a MIN_CONFIG.
3# (A .config file that is the minimum for a machine to boot, or
4# to boot and make a network connection.)
5#
6# A MIN_CONFIG is very useful as it is the minimum configuration
7# needed to boot a given machine. You can debug someone else's
8# .config by only setting the configs in your MIN_CONFIG. The closer
9# your MIN_CONFIG is to the true minimum set of configs needed to
10# boot your machine, the closer the config you test with will be
11# to the users config that had the failure.
12#
13# The make_min_config test allows you to create a MIN_CONFIG that
14# is truly the minimum set of configs needed to boot a box.
15#
16# In this example, the final config will reside in
17# ${CONFIG_DIR}/config-new-min and ${CONFIG_DIR}/config-new-min-net.
18# Just move one to the location you have set for MIN_CONFIG.
19#
20# The first test creates a MIN_CONFIG that will be the minimum
21# configuration to boot ${MACHINE} and be able to ssh to it.
22#
23# The second test creates a MIN_CONFIG that will only boot
24# the target and most likely will not let you ssh to it. (Notice
25# how the second test uses the first test's result to continue with.
26# This is because the second test config is a subset of the first).
27#
28# The ${CONFIG_DIR}/config-skip (and -net) will hold the configs
29# that ktest.pl found would not boot the target without them set.
30# The config-new-min holds configs that ktest.pl could not test
31# directly because another config that was needed to boot the box
32# selected them. Sometimes it is possible that this file will hold
33# the true minimum configuration. You can test to see if this is
34# the case by running the boot test with BOOT_TYPE = allnoconfig and
35# setting setting the MIN_CONFIG to ${CONFIG_DIR}/config-skip. If the
36# machine still boots, then you can use the config-skip as your MIN_CONFIG.
37#
38# These tests can run for several hours (and perhaps days).
39# It's OK to kill the test with a Ctrl^C. By restarting without
40# modifying this config, ktest.pl will notice that the config-new-min(-net)
41# exists, and will use that instead as the starting point.
42# The USE_OUTPUT_MIN_CONFIG is set to 1 to keep ktest.pl from asking
43# you if you want to use the OUTPUT_MIN_CONFIG as the starting point.
44# By using the OUTPUT_MIN_CONFIG as the starting point will allow ktest.pl to
45# start almost where it left off.
46#
47TEST_START IF ${TEST} == min-config
48TEST_TYPE = make_min_config
49OUTPUT_MIN_CONFIG = ${CONFIG_DIR}/config-new-min-net
50IGNORE_CONFIG = ${CONFIG_DIR}/config-skip-net
51MIN_CONFIG_TYPE = test
52TEST = ${SSH} echo hi
53USE_OUTPUT_MIN_CONFIG = 1
54
55TEST_START IF ${TEST} == min-config && ${MULTI}
56TEST_TYPE = make_min_config
57OUTPUT_MIN_CONFIG = ${CONFIG_DIR}/config-new-min
58IGNORE_CONFIG = ${CONFIG_DIR}/config-skip
59MIN_CONFIG = ${CONFIG_DIR}/config-new-min-net
60USE_OUTPUT_MIN_CONFIG = 1
diff --git a/tools/testing/ktest/examples/include/patchcheck.conf b/tools/testing/ktest/examples/include/patchcheck.conf
new file mode 100644
index 000000000000..339d3e1700ff
--- /dev/null
+++ b/tools/testing/ktest/examples/include/patchcheck.conf
@@ -0,0 +1,74 @@
1# patchcheck.conf
2#
3# This contains a test that takes two git commits and will test each
4# commit between the two. The build test will look at what files the
5# commit has touched, and if any of those files produce a warning, then
6# the build will fail.
7
8
9# PATCH_START is the commit to begin with and PATCH_END is the commit
10# to end with (inclusive). This is similar to doing a git rebase -i PATCH_START~1
11# and then testing each commit and doing a git rebase --continue.
12# You can use a SHA1, a git tag, or anything that git will accept for a checkout
13
14PATCH_START := HEAD~3
15PATCH_END := HEAD
16
17# Change PATCH_CHECKOUT to be the branch you want to test. The test will
18# do a git checkout of this branch before starting. Obviously both
19# PATCH_START and PATCH_END must be in this branch (and PATCH_START must
20# be contained by PATCH_END).
21
22PATCH_CHECKOUT := test/branch
23
24# Usually it's a good idea to have a set config to use for testing individual
25# patches.
26PATCH_CONFIG := ${CONFIG_DIR}/config-patchcheck
27
28# Change PATCH_TEST to run some test for each patch. Each commit that is
29# tested, after it is built and installed on the test machine, this command
30# will be executed. Usually what is done is to ssh to the target box and
31# run some test scripts. If you just want to boot test your patches
32# comment PATCH_TEST out.
33PATCH_TEST := ${SSH} "/usr/local/bin/ktest-test-script"
34
35DEFAULTS IF DEFINED PATCH_TEST
36PATCH_TEST_TYPE := test
37
38DEFAULTS ELSE
39PATCH_TEST_TYPE := boot
40
41# If for some reason a file has a warning that one of your patches touch
42# but you do not care about it, set IGNORE_WARNINGS to that commit(s)
43# (space delimited)
44#IGNORE_WARNINGS = 39eaf7ef884dcc44f7ff1bac803ca2a1dcf43544 6edb2a8a385f0cdef51dae37ff23e74d76d8a6ce
45
46# If you are running a multi test, and the test failed on the first
47# test but on, say the 5th patch. If you want to restart on the
48# fifth patch, set PATCH_START1. This will make the first test start
49# from this commit instead of the PATCH_START commit.
50# Note, do not change this option. Just define PATCH_START1 in the
51# top config (the one you pass to ktest.pl), and this will use it,
52# otherwise it will just use PATCH_START if PATCH_START1 is not defined.
53DEFAULTS IF NOT DEFINED PATCH_START1
54PATCH_START1 := ${PATCH_START}
55
56TEST_START IF ${TEST} == patchcheck
57TEST_TYPE = patchcheck
58MIN_CONFIG = ${PATCH_CONFIG}
59TEST = ${PATCH_TEST}
60PATCHCHECK_TYPE = ${PATCH_TEST_TYPE}
61PATCHCHECK_START = ${PATCH_START1}
62PATCHCHECK_END = ${PATCH_END}
63CHECKOUT = ${PATCH_CHECKOUT}
64
65TEST_START IF ${TEST} == patchcheck && ${MULTI}
66TEST_TYPE = patchcheck
67MIN_CONFIG = ${PATCH_CONFIG}
68TEST = ${PATCH_TEST}
69PATCHCHECK_TYPE = ${PATCH_TEST_TYPE}
70PATCHCHECK_START = ${PATCH_START}
71PATCHCHECK_END = ${PATCH_END}
72CHECKOUT = ${PATCH_CHECKOUT}
73# Use multi to test different compilers?
74MAKE_CMD = CC=gcc-4.5.1 make
diff --git a/tools/testing/ktest/examples/include/tests.conf b/tools/testing/ktest/examples/include/tests.conf
new file mode 100644
index 000000000000..4fdb811bd810
--- /dev/null
+++ b/tools/testing/ktest/examples/include/tests.conf
@@ -0,0 +1,74 @@
1#
2# This is an example of various tests that you can run
3#
4# The variable TEST can be of boot, build, randconfig, or test.
5#
6# Note that TEST is a variable created with ':=' and only exists
7# throughout the config processing (not during the tests itself).
8#
9# The TEST option (defined with '=') is used to tell ktest.pl
10# what test to run after a successful boot. The TEST option is
11# persistent into the test runs.
12#
13
14# The config that includes this file may define a BOOT_TYPE
15# variable that tells this config what type of boot test to run.
16# If it's not defined, the below DEFAULTS will set the default
17# to 'oldconfig'.
18#
19DEFAULTS IF NOT DEFINED BOOT_TYPE
20BOOT_TYPE := oldconfig
21
22# The config that includes this file may define a RUN_TEST
23# variable that will tell this config what test to run.
24# (what to set the TEST option to).
25#
26DEFAULTS IF NOT DEFINED RUN_TEST
27# Requires that hackbench is in the PATH
28RUN_TEST := ${SSH} hackbench 50
29
30
31# If TEST is set to 'boot' then just build a kernel and boot
32# the target.
33TEST_START IF ${TEST} == boot
34TEST_TYPE = boot
35# Notice how we set the BUILD_TYPE option to the BOOT_TYPE variable.
36BUILD_TYPE = ${BOOT_TYPE}
37# Do not do a make mrproper.
38BUILD_NOCLEAN = 1
39
40# If you only want to build the kernel, and perhaps install
41# and test it yourself, then just set TEST to build.
42TEST_START IF ${TEST} == build
43TEST_TYPE = build
44BUILD_TYPE = ${BOOT_TYPE}
45BUILD_NOCLEAN = 1
46
47# Build, install, boot and test with a randconfg 10 times.
48# It is important that you have set MIN_CONFIG in the config
49# that includes this file otherwise it is likely that the
50# randconfig will not have the neccessary configs needed to
51# boot your box. This version of the test requires a min
52# config that has enough to make sure the target has network
53# working.
54TEST_START ITERATE 10 IF ${TEST} == randconfig
55MIN_CONFIG = ${CONFIG_DIR}/config-min-net
56TEST_TYPE = test
57BUILD_TYPE = randconfig
58TEST = ${RUN_TEST}
59
60# This is the same as above, but only tests to a boot prompt.
61# The MIN_CONFIG used here does not need to have networking
62# working.
63TEST_START ITERATE 10 IF ${TEST} == randconfig && ${MULTI}
64TEST_TYPE = boot
65BUILD_TYPE = randconfig
66MIN_CONFIG = ${CONFIG_DIR}/config-min
67MAKE_CMD = make
68
69# This builds, installs, boots and tests the target.
70TEST_START IF ${TEST} == test
71TEST_TYPE = test
72BUILD_TYPE = ${BOOT_TYPE}
73TEST = ${RUN_TEST}
74BUILD_NOCLEAN = 1
diff --git a/tools/testing/ktest/examples/kvm.conf b/tools/testing/ktest/examples/kvm.conf
new file mode 100644
index 000000000000..831c7c5395f1
--- /dev/null
+++ b/tools/testing/ktest/examples/kvm.conf
@@ -0,0 +1,88 @@
1#
2# This config is an example usage of ktest.pl with a kvm guest
3#
4# The guest is called 'Guest' and this would be something that
5# could be run on the host to test a virtual machine target.
6
7MACHINE = Guest
8
9
10# Use virsh to read the serial console of the guest
11CONSOLE = virsh console ${MACHINE}
12
13#*************************************#
14# This part is the same as test.conf #
15#*************************************#
16
17# The include files will set up the type of test to run. Just set TEST to
18# which test you want to run.
19#
20# TESTS = patchcheck, randconfig, boot, test, config-bisect, bisect, min-config
21#
22# See the include/*.conf files that define these tests
23#
24TEST := patchcheck
25
26# Some tests may have more than one test to run. Define MULTI := 1 to run
27# the extra tests.
28MULTI := 0
29
30# In case you want to differentiate which type of system you are testing
31BITS := 64
32
33# REBOOT = none, error, fail, empty
34# See include/defaults.conf
35REBOOT := empty
36
37
38# The defaults file will set up various settings that can be used by all
39# machine configs.
40INCLUDE include/defaults.conf
41
42
43#*************************************#
44# Now we are different from test.conf #
45#*************************************#
46
47
48# The example here assumes that Guest is running a Fedora release
49# that uses dracut for its initfs. The POST_INSTALL will be executed
50# after the install of the kernel and modules are complete.
51#
52POST_INSTALL = ${SSH} /sbin/dracut -f /boot/initramfs-test.img $KERNEL_VERSION
53
54# Guests sometimes get stuck on reboot. We wait 3 seconds after running
55# the reboot command and then do a full power-cycle of the guest.
56# This forces the guest to restart.
57#
58POWERCYCLE_AFTER_REBOOT = 3
59
60# We do the same after the halt command, but this time we wait 20 seconds.
61POWEROFF_AFTER_HALT = 20
62
63
64# As the defaults.conf file has a POWER_CYCLE option already defined,
65# and options can not be defined in the same section more than once
66# (all DEFAULTS sections are considered the same). We use the
67# DEFAULTS OVERRIDE to tell ktest.pl to ignore the previous defined
68# options, for the options set in the OVERRIDE section.
69#
70DEFAULTS OVERRIDE
71
72# Instead of using the default POWER_CYCLE option defined in
73# defaults.conf, we use virsh to cycle it. To do so, we destroy
74# the guest, wait 5 seconds, and then start it up again.
75# Crude, but effective.
76#
77POWER_CYCLE = virsh destroy ${MACHINE}; sleep 5; virsh start ${MACHINE}
78
79
80DEFAULTS
81
82# The following files each handle a different test case.
83# Having them included allows you to set up more than one machine and share
84# the same tests.
85INCLUDE include/patchcheck.conf
86INCLUDE include/tests.conf
87INCLUDE include/bisect.conf
88INCLUDE include/min-config.conf
diff --git a/tools/testing/ktest/examples/snowball.conf b/tools/testing/ktest/examples/snowball.conf
new file mode 100644
index 000000000000..a82a3c5bc2b7
--- /dev/null
+++ b/tools/testing/ktest/examples/snowball.conf
@@ -0,0 +1,53 @@
1# This example was used to boot the snowball ARM board.
2# See http://people.redhat.com/srostedt/ktest-embedded-2012/
3
4# PWD is a ktest.pl variable that will result in the process working
5# directory that ktest.pl is executed in.
6
7# THIS_DIR is automatically assigned the PWD of the path that generated
8# the config file. It is best to use this variable when assigning other
9# directory paths within this directory. This allows you to easily
10# move the test cases to other locations or to other machines.
11#
12THIS_DIR := /home/rostedt/work/demo/ktest-embed
13LOG_FILE = ${OUTPUT_DIR}/snowball.log
14CLEAR_LOG = 1
15MAKE_CMD = PATH=/usr/local/gcc-4.5.2-nolibc/arm-unknown-linux-gnueabi/bin:$PATH CROSS_COMPILE=arm-unknown-linux-gnueabi- make ARCH=arm
16ADD_CONFIG = ${THIS_DIR}/addconfig
17
18SCP_TO_TARGET = echo "don't do scp"
19
20TFTPBOOT := /var/lib/tftpboot
21TFTPDEF := ${TFTPBOOT}/snowball-default
22TFTPTEST := ${OUTPUT_DIR}/${BUILD_TARGET}
23
24SWITCH_TO_GOOD = cp ${TFTPDEF} ${TARGET_IMAGE}
25SWITCH_TO_TEST = cp ${TFTPTEST} ${TARGET_IMAGE}
26
27# Define each test with TEST_START
28# The config options below it will override the defaults
29TEST_START SKIP
30TEST_TYPE = boot
31BUILD_TYPE = u8500_defconfig
32BUILD_NOCLEAN = 1
33
34TEST_START
35TEST_TYPE = make_min_config
36OUTPUT_MIN_CONFIG = ${THIS_DIR}/config.newmin
37START_MIN_CONFIG = ${THIS_DIR}/config.orig
38IGNORE_CONFIG = ${THIS_DIR}/config.ignore
39BUILD_NOCLEAN = 1
40
41
42DEFAULTS
43LOCALVERSION = -test
44POWER_CYCLE = echo use the thumb luke; read a
45CONSOLE = cat ${THIS_DIR}/snowball-cat
46REBOOT_TYPE = script
47SSH_USER = root
48BUILD_OPTIONS = -j8 uImage
49BUILD_DIR = ${THIS_DIR}/linux.git
50OUTPUT_DIR = ${THIS_DIR}/snowball-build
51MACHINE = snowball
52TARGET_IMAGE = /var/lib/tftpboot/snowball-image
53BUILD_TARGET = arch/arm/boot/uImage
diff --git a/tools/testing/ktest/examples/test.conf b/tools/testing/ktest/examples/test.conf
new file mode 100644
index 000000000000..b725210efb7f
--- /dev/null
+++ b/tools/testing/ktest/examples/test.conf
@@ -0,0 +1,62 @@
1#
2# Generic config for a machine
3#
4
5# Name your machine (the DNS name, what you ssh to)
6MACHINE = foo
7
8# BOX can be different than foo, if the machine BOX has
9# multiple partitions with different systems installed. For example,
10# you may have a i386 and x86_64 installation on a test box.
11# If this is the case, MACHINE defines the way to connect to the
12# machine, which may be different between which system the machine
13# is booting into. BOX is used for the scripts to reboot and power cycle
14# the machine, where it does not matter which system the machine boots into.
15#
16#BOX := bar
17
18# Define a way to read the console
19CONSOLE = stty -F /dev/ttyS0 115200 parodd; cat /dev/ttyS0
20
21# The include files will set up the type of test to run. Just set TEST to
22# which test you want to run.
23#
24# TESTS = patchcheck, randconfig, boot, test, config-bisect, bisect, min-config
25#
26# See the include/*.conf files that define these tests
27#
28TEST := patchcheck
29
30# Some tests may have more than one test to run. Define MULTI := 1 to run
31# the extra tests.
32MULTI := 0
33
34# In case you want to differentiate which type of system you are testing
35BITS := 64
36
37# REBOOT = none, error, fail, empty
38# See include/defaults.conf
39REBOOT := empty
40
41# The defaults file will set up various settings that can be used by all
42# machine configs.
43INCLUDE include/defaults.conf
44
45# In case you need to add a patch for a bisect or something
46#PRE_BUILD = patch -p1 < ${THIS_DIR}/fix.patch
47
48# Reset the repo after the build and remove all 'test' modules from the target
49# Notice that DO_POST_BUILD is a variable (defined by ':=') and POST_BUILD
50# is the option (defined by '=')
51
52DO_POST_BUILD := git reset --hard
53POST_BUILD = ${SSH} 'rm -rf /lib/modules/*-test*'; ${DO_POST_BUILD}
54
55# The following files each handle a different test case.
56# Having them included allows you to set up more than one machine and share
57# the same tests.
58INCLUDE include/patchcheck.conf
59INCLUDE include/tests.conf
60INCLUDE include/bisect.conf
61INCLUDE include/min-config.conf
62
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index 4915408f6a98..292b13ad03f5 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -39,6 +39,7 @@ my %default = (
39 "CLEAR_LOG" => 0, 39 "CLEAR_LOG" => 0,
40 "BISECT_MANUAL" => 0, 40 "BISECT_MANUAL" => 0,
41 "BISECT_SKIP" => 1, 41 "BISECT_SKIP" => 1,
42 "MIN_CONFIG_TYPE" => "boot",
42 "SUCCESS_LINE" => "login:", 43 "SUCCESS_LINE" => "login:",
43 "DETECT_TRIPLE_FAULT" => 1, 44 "DETECT_TRIPLE_FAULT" => 1,
44 "NO_INSTALL" => 0, 45 "NO_INSTALL" => 0,
@@ -66,6 +67,7 @@ my %default = (
66 67
67my $ktest_config; 68my $ktest_config;
68my $version; 69my $version;
70my $have_version = 0;
69my $machine; 71my $machine;
70my $ssh_user; 72my $ssh_user;
71my $tmpdir; 73my $tmpdir;
@@ -106,6 +108,8 @@ my $minconfig;
106my $start_minconfig; 108my $start_minconfig;
107my $start_minconfig_defined; 109my $start_minconfig_defined;
108my $output_minconfig; 110my $output_minconfig;
111my $minconfig_type;
112my $use_output_minconfig;
109my $ignore_config; 113my $ignore_config;
110my $ignore_errors; 114my $ignore_errors;
111my $addconfig; 115my $addconfig;
@@ -205,6 +209,8 @@ my %option_map = (
205 "MIN_CONFIG" => \$minconfig, 209 "MIN_CONFIG" => \$minconfig,
206 "OUTPUT_MIN_CONFIG" => \$output_minconfig, 210 "OUTPUT_MIN_CONFIG" => \$output_minconfig,
207 "START_MIN_CONFIG" => \$start_minconfig, 211 "START_MIN_CONFIG" => \$start_minconfig,
212 "MIN_CONFIG_TYPE" => \$minconfig_type,
213 "USE_OUTPUT_MIN_CONFIG" => \$use_output_minconfig,
208 "IGNORE_CONFIG" => \$ignore_config, 214 "IGNORE_CONFIG" => \$ignore_config,
209 "TEST" => \$run_test, 215 "TEST" => \$run_test,
210 "ADD_CONFIG" => \$addconfig, 216 "ADD_CONFIG" => \$addconfig,
@@ -1702,10 +1708,12 @@ sub install {
1702 1708
1703sub get_version { 1709sub get_version {
1704 # get the release name 1710 # get the release name
1711 return if ($have_version);
1705 doprint "$make kernelrelease ... "; 1712 doprint "$make kernelrelease ... ";
1706 $version = `$make kernelrelease | tail -1`; 1713 $version = `$make kernelrelease | tail -1`;
1707 chomp($version); 1714 chomp($version);
1708 doprint "$version\n"; 1715 doprint "$version\n";
1716 $have_version = 1;
1709} 1717}
1710 1718
1711sub start_monitor_and_boot { 1719sub start_monitor_and_boot {
@@ -1828,6 +1836,9 @@ sub build {
1828 my $save_no_reboot = $no_reboot; 1836 my $save_no_reboot = $no_reboot;
1829 $no_reboot = 1; 1837 $no_reboot = 1;
1830 1838
1839 # Calculate a new version from here.
1840 $have_version = 0;
1841
1831 if (defined($pre_build)) { 1842 if (defined($pre_build)) {
1832 my $ret = run_command $pre_build; 1843 my $ret = run_command $pre_build;
1833 if (!$ret && defined($pre_build_die) && 1844 if (!$ret && defined($pre_build_die) &&
@@ -1887,6 +1898,9 @@ sub build {
1887 undef $redirect; 1898 undef $redirect;
1888 1899
1889 if (defined($post_build)) { 1900 if (defined($post_build)) {
1901 # Because a post build may change the kernel version
1902 # do it now.
1903 get_version;
1890 my $ret = run_command $post_build; 1904 my $ret = run_command $post_build;
1891 if (!$ret && defined($post_build_die) && 1905 if (!$ret && defined($post_build_die) &&
1892 $post_build_die) { 1906 $post_build_die) {
@@ -3119,6 +3133,12 @@ sub test_this_config {
3119sub make_min_config { 3133sub make_min_config {
3120 my ($i) = @_; 3134 my ($i) = @_;
3121 3135
3136 my $type = $minconfig_type;
3137 if ($type ne "boot" && $type ne "test") {
3138 fail "Invalid MIN_CONFIG_TYPE '$minconfig_type'\n" .
3139 " make_min_config works only with 'boot' and 'test'\n" and return;
3140 }
3141
3122 if (!defined($output_minconfig)) { 3142 if (!defined($output_minconfig)) {
3123 fail "OUTPUT_MIN_CONFIG not defined" and return; 3143 fail "OUTPUT_MIN_CONFIG not defined" and return;
3124 } 3144 }
@@ -3128,8 +3148,15 @@ sub make_min_config {
3128 # that instead. 3148 # that instead.
3129 if (-f $output_minconfig && !$start_minconfig_defined) { 3149 if (-f $output_minconfig && !$start_minconfig_defined) {
3130 print "$output_minconfig exists\n"; 3150 print "$output_minconfig exists\n";
3131 if (read_yn " Use it as minconfig?") { 3151 if (!defined($use_output_minconfig)) {
3152 if (read_yn " Use it as minconfig?") {
3153 $start_minconfig = $output_minconfig;
3154 }
3155 } elsif ($use_output_minconfig > 0) {
3156 doprint "Using $output_minconfig as MIN_CONFIG\n";
3132 $start_minconfig = $output_minconfig; 3157 $start_minconfig = $output_minconfig;
3158 } else {
3159 doprint "Set to still use MIN_CONFIG as starting point\n";
3133 } 3160 }
3134 } 3161 }
3135 3162
@@ -3278,6 +3305,11 @@ sub make_min_config {
3278 build "oldconfig" or $failed = 1; 3305 build "oldconfig" or $failed = 1;
3279 if (!$failed) { 3306 if (!$failed) {
3280 start_monitor_and_boot or $failed = 1; 3307 start_monitor_and_boot or $failed = 1;
3308
3309 if ($type eq "test" && !$failed) {
3310 do_run_test or $failed = 1;
3311 }
3312
3281 end_monitor; 3313 end_monitor;
3282 } 3314 }
3283 3315
@@ -3474,6 +3506,8 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
3474 $no_reboot = 1; 3506 $no_reboot = 1;
3475 $reboot_success = 0; 3507 $reboot_success = 0;
3476 3508
3509 $have_version = 0;
3510
3477 $iteration = $i; 3511 $iteration = $i;
3478 3512
3479 my $makecmd = set_test_option("MAKE_CMD", $i); 3513 my $makecmd = set_test_option("MAKE_CMD", $i);
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf
index b682456afda8..cf362b3d1ec9 100644
--- a/tools/testing/ktest/sample.conf
+++ b/tools/testing/ktest/sample.conf
@@ -158,7 +158,7 @@
158# 158#
159# TEST_START IF (DEFINED ALL_TESTS || ${MYTEST} == boottest) && ${MACHINE} == gandalf 159# TEST_START IF (DEFINED ALL_TESTS || ${MYTEST} == boottest) && ${MACHINE} == gandalf
160# 160#
161# Notice the use of paranthesis. Without any paranthesis the above would be 161# Notice the use of parentheses. Without any parentheses the above would be
162# processed the same as: 162# processed the same as:
163# 163#
164# TEST_START IF DEFINED ALL_TESTS || (${MYTEST} == boottest && ${MACHINE} == gandalf) 164# TEST_START IF DEFINED ALL_TESTS || (${MYTEST} == boottest && ${MACHINE} == gandalf)
@@ -1105,10 +1105,26 @@
1105# and will not be tested again in later runs. 1105# and will not be tested again in later runs.
1106# (optional) 1106# (optional)
1107# 1107#
1108# MIN_CONFIG_TYPE can be either 'boot' or 'test'. With 'boot' it will
1109# test if the created config can just boot the machine. If this is
1110# set to 'test', then the TEST option must be defined and the created
1111# config will not only boot the target, but also make sure that the
1112# config lets the test succeed. This is useful to make sure the final
1113# config that is generated allows network activity (ssh).
1114# (optional)
1115#
1116# USE_OUTPUT_MIN_CONFIG set this to 1 if you do not want to be prompted
1117# about using the OUTPUT_MIN_CONFIG as the MIN_CONFIG as the starting
1118# point. Set it to 0 if you want to always just use the given MIN_CONFIG.
1119# If it is not defined, it will prompt you to pick which config
1120# to start with (MIN_CONFIG or OUTPUT_MIN_CONFIG).
1121#
1108# Example: 1122# Example:
1109# 1123#
1110# TEST_TYPE = make_min_config 1124# TEST_TYPE = make_min_config
1111# OUTPUT_MIN_CONFIG = /path/to/config-new-min 1125# OUTPUT_MIN_CONFIG = /path/to/config-new-min
1112# START_MIN_CONFIG = /path/to/config-min 1126# START_MIN_CONFIG = /path/to/config-min
1113# IGNORE_CONFIG = /path/to/config-tested 1127# IGNORE_CONFIG = /path/to/config-tested
1128# MIN_CONFIG_TYPE = test
1129# TEST = ssh ${USER}@${MACHINE} echo hi
1114# 1130#
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 28bc57ee757c..a4162e15c25f 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -1,4 +1,4 @@
1TARGETS = breakpoints vm 1TARGETS = breakpoints kcmp mqueue vm
2 2
3all: 3all:
4 for TARGET in $(TARGETS); do \ 4 for TARGET in $(TARGETS); do \
diff --git a/tools/testing/selftests/kcmp/Makefile b/tools/testing/selftests/kcmp/Makefile
new file mode 100644
index 000000000000..dc79b86ea65c
--- /dev/null
+++ b/tools/testing/selftests/kcmp/Makefile
@@ -0,0 +1,29 @@
1uname_M := $(shell uname -m 2>/dev/null || echo not)
2ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
3ifeq ($(ARCH),i386)
4 ARCH := X86
5 CFLAGS := -DCONFIG_X86_32 -D__i386__
6endif
7ifeq ($(ARCH),x86_64)
8 ARCH := X86
9 CFLAGS := -DCONFIG_X86_64 -D__x86_64__
10endif
11
12CFLAGS += -I../../../../arch/x86/include/generated/
13CFLAGS += -I../../../../include/
14CFLAGS += -I../../../../usr/include/
15CFLAGS += -I../../../../arch/x86/include/
16
17all:
18ifeq ($(ARCH),X86)
19 gcc $(CFLAGS) kcmp_test.c -o run_test
20else
21 echo "Not an x86 target, can't build kcmp selftest"
22endif
23
24run-tests: all
25 ./kcmp_test
26
27clean:
28 rm -fr ./run_test
29 rm -fr ./test-file
diff --git a/tools/testing/selftests/kcmp/kcmp_test.c b/tools/testing/selftests/kcmp/kcmp_test.c
new file mode 100644
index 000000000000..358cc6bfa35d
--- /dev/null
+++ b/tools/testing/selftests/kcmp/kcmp_test.c
@@ -0,0 +1,94 @@
1#define _GNU_SOURCE
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <signal.h>
6#include <limits.h>
7#include <unistd.h>
8#include <errno.h>
9#include <string.h>
10#include <fcntl.h>
11
12#include <linux/unistd.h>
13#include <linux/kcmp.h>
14
15#include <sys/syscall.h>
16#include <sys/types.h>
17#include <sys/stat.h>
18#include <sys/wait.h>
19
20static long sys_kcmp(int pid1, int pid2, int type, int fd1, int fd2)
21{
22 return syscall(__NR_kcmp, pid1, pid2, type, fd1, fd2);
23}
24
25int main(int argc, char **argv)
26{
27 const char kpath[] = "kcmp-test-file";
28 int pid1, pid2;
29 int fd1, fd2;
30 int status;
31
32 fd1 = open(kpath, O_RDWR | O_CREAT | O_TRUNC, 0644);
33 pid1 = getpid();
34
35 if (fd1 < 0) {
36 perror("Can't create file");
37 exit(1);
38 }
39
40 pid2 = fork();
41 if (pid2 < 0) {
42 perror("fork failed");
43 exit(1);
44 }
45
46 if (!pid2) {
47 int pid2 = getpid();
48 int ret;
49
50 fd2 = open(kpath, O_RDWR, 0644);
51 if (fd2 < 0) {
52 perror("Can't open file");
53 exit(1);
54 }
55
56 /* An example of output and arguments */
57 printf("pid1: %6d pid2: %6d FD: %2ld FILES: %2ld VM: %2ld "
58 "FS: %2ld SIGHAND: %2ld IO: %2ld SYSVSEM: %2ld "
59 "INV: %2ld\n",
60 pid1, pid2,
61 sys_kcmp(pid1, pid2, KCMP_FILE, fd1, fd2),
62 sys_kcmp(pid1, pid2, KCMP_FILES, 0, 0),
63 sys_kcmp(pid1, pid2, KCMP_VM, 0, 0),
64 sys_kcmp(pid1, pid2, KCMP_FS, 0, 0),
65 sys_kcmp(pid1, pid2, KCMP_SIGHAND, 0, 0),
66 sys_kcmp(pid1, pid2, KCMP_IO, 0, 0),
67 sys_kcmp(pid1, pid2, KCMP_SYSVSEM, 0, 0),
68
69 /* This one should fail */
70 sys_kcmp(pid1, pid2, KCMP_TYPES + 1, 0, 0));
71
72 /* This one should return same fd */
73 ret = sys_kcmp(pid1, pid2, KCMP_FILE, fd1, fd1);
74 if (ret) {
75 printf("FAIL: 0 expected but %d returned\n", ret);
76 ret = -1;
77 } else
78 printf("PASS: 0 returned as expected\n");
79
80 /* Compare with self */
81 ret = sys_kcmp(pid1, pid1, KCMP_VM, 0, 0);
82 if (ret) {
83 printf("FAIL: 0 expected but %li returned\n", ret);
84 ret = -1;
85 } else
86 printf("PASS: 0 returned as expected\n");
87
88 exit(ret);
89 }
90
91 waitpid(pid2, &status, P_ALL);
92
93 return 0;
94}
diff --git a/tools/testing/selftests/mqueue/.gitignore b/tools/testing/selftests/mqueue/.gitignore
new file mode 100644
index 000000000000..d8d42377205a
--- /dev/null
+++ b/tools/testing/selftests/mqueue/.gitignore
@@ -0,0 +1,2 @@
1mq_open_tests
2mq_perf_tests
diff --git a/tools/testing/selftests/mqueue/Makefile b/tools/testing/selftests/mqueue/Makefile
new file mode 100644
index 000000000000..54c0aad2b47c
--- /dev/null
+++ b/tools/testing/selftests/mqueue/Makefile
@@ -0,0 +1,10 @@
1all:
2 gcc -O2 -lrt mq_open_tests.c -o mq_open_tests
3 gcc -O2 -lrt -lpthread -lpopt -o mq_perf_tests mq_perf_tests.c
4
5run_tests:
6 ./mq_open_tests /test1
7 ./mq_perf_tests
8
9clean:
10 rm -f mq_open_tests mq_perf_tests
diff --git a/tools/testing/selftests/mqueue/mq_open_tests.c b/tools/testing/selftests/mqueue/mq_open_tests.c
new file mode 100644
index 000000000000..711cc2923047
--- /dev/null
+++ b/tools/testing/selftests/mqueue/mq_open_tests.c
@@ -0,0 +1,492 @@
1/*
2 * This application is Copyright 2012 Red Hat, Inc.
3 * Doug Ledford <dledford@redhat.com>
4 *
5 * mq_open_tests is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * mq_open_tests is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * For the full text of the license, see <http://www.gnu.org/licenses/>.
15 *
16 * mq_open_tests.c
17 * Tests the various situations that should either succeed or fail to
18 * open a posix message queue and then reports whether or not they
19 * did as they were supposed to.
20 *
21 */
22#include <stdio.h>
23#include <stdlib.h>
24#include <unistd.h>
25#include <fcntl.h>
26#include <string.h>
27#include <limits.h>
28#include <errno.h>
29#include <sys/types.h>
30#include <sys/time.h>
31#include <sys/resource.h>
32#include <sys/stat.h>
33#include <mqueue.h>
34
35static char *usage =
36"Usage:\n"
37" %s path\n"
38"\n"
39" path Path name of the message queue to create\n"
40"\n"
41" Note: this program must be run as root in order to enable all tests\n"
42"\n";
43
44char *DEF_MSGS = "/proc/sys/fs/mqueue/msg_default";
45char *DEF_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_default";
46char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max";
47char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max";
48
49int default_settings;
50struct rlimit saved_limits, cur_limits;
51int saved_def_msgs, saved_def_msgsize, saved_max_msgs, saved_max_msgsize;
52int cur_def_msgs, cur_def_msgsize, cur_max_msgs, cur_max_msgsize;
53FILE *def_msgs, *def_msgsize, *max_msgs, *max_msgsize;
54char *queue_path;
55mqd_t queue = -1;
56
57static inline void __set(FILE *stream, int value, char *err_msg);
58void shutdown(int exit_val, char *err_cause, int line_no);
59static inline int get(FILE *stream);
60static inline void set(FILE *stream, int value);
61static inline void getr(int type, struct rlimit *rlim);
62static inline void setr(int type, struct rlimit *rlim);
63void validate_current_settings();
64static inline void test_queue(struct mq_attr *attr, struct mq_attr *result);
65static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result);
66
67static inline void __set(FILE *stream, int value, char *err_msg)
68{
69 rewind(stream);
70 if (fprintf(stream, "%d", value) < 0)
71 perror(err_msg);
72}
73
74
75void shutdown(int exit_val, char *err_cause, int line_no)
76{
77 static int in_shutdown = 0;
78
79 /* In case we get called recursively by a set() call below */
80 if (in_shutdown++)
81 return;
82
83 seteuid(0);
84
85 if (queue != -1)
86 if (mq_close(queue))
87 perror("mq_close() during shutdown");
88 if (queue_path)
89 /*
90 * Be silent if this fails, if we cleaned up already it's
91 * expected to fail
92 */
93 mq_unlink(queue_path);
94 if (default_settings) {
95 if (saved_def_msgs)
96 __set(def_msgs, saved_def_msgs,
97 "failed to restore saved_def_msgs");
98 if (saved_def_msgsize)
99 __set(def_msgsize, saved_def_msgsize,
100 "failed to restore saved_def_msgsize");
101 }
102 if (saved_max_msgs)
103 __set(max_msgs, saved_max_msgs,
104 "failed to restore saved_max_msgs");
105 if (saved_max_msgsize)
106 __set(max_msgsize, saved_max_msgsize,
107 "failed to restore saved_max_msgsize");
108 if (exit_val)
109 error(exit_val, errno, "%s at %d", err_cause, line_no);
110 exit(0);
111}
112
113static inline int get(FILE *stream)
114{
115 int value;
116 rewind(stream);
117 if (fscanf(stream, "%d", &value) != 1)
118 shutdown(4, "Error reading /proc entry", __LINE__ - 1);
119 return value;
120}
121
122static inline void set(FILE *stream, int value)
123{
124 int new_value;
125
126 rewind(stream);
127 if (fprintf(stream, "%d", value) < 0)
128 return shutdown(5, "Failed writing to /proc file",
129 __LINE__ - 1);
130 new_value = get(stream);
131 if (new_value != value)
132 return shutdown(5, "We didn't get what we wrote to /proc back",
133 __LINE__ - 1);
134}
135
136static inline void getr(int type, struct rlimit *rlim)
137{
138 if (getrlimit(type, rlim))
139 shutdown(6, "getrlimit()", __LINE__ - 1);
140}
141
142static inline void setr(int type, struct rlimit *rlim)
143{
144 if (setrlimit(type, rlim))
145 shutdown(7, "setrlimit()", __LINE__ - 1);
146}
147
148void validate_current_settings()
149{
150 int rlim_needed;
151
152 if (cur_limits.rlim_cur < 4096) {
153 printf("Current rlimit value for POSIX message queue bytes is "
154 "unreasonably low,\nincreasing.\n\n");
155 cur_limits.rlim_cur = 8192;
156 cur_limits.rlim_max = 16384;
157 setr(RLIMIT_MSGQUEUE, &cur_limits);
158 }
159
160 if (default_settings) {
161 rlim_needed = (cur_def_msgs + 1) * (cur_def_msgsize + 1 +
162 2 * sizeof(void *));
163 if (rlim_needed > cur_limits.rlim_cur) {
164 printf("Temporarily lowering default queue parameters "
165 "to something that will work\n"
166 "with the current rlimit values.\n\n");
167 set(def_msgs, 10);
168 cur_def_msgs = 10;
169 set(def_msgsize, 128);
170 cur_def_msgsize = 128;
171 }
172 } else {
173 rlim_needed = (cur_max_msgs + 1) * (cur_max_msgsize + 1 +
174 2 * sizeof(void *));
175 if (rlim_needed > cur_limits.rlim_cur) {
176 printf("Temporarily lowering maximum queue parameters "
177 "to something that will work\n"
178 "with the current rlimit values in case this is "
179 "a kernel that ties the default\n"
180 "queue parameters to the maximum queue "
181 "parameters.\n\n");
182 set(max_msgs, 10);
183 cur_max_msgs = 10;
184 set(max_msgsize, 128);
185 cur_max_msgsize = 128;
186 }
187 }
188}
189
190/*
191 * test_queue - Test opening a queue, shutdown if we fail. This should
192 * only be called in situations that should never fail. We clean up
193 * after ourselves and return the queue attributes in *result.
194 */
195static inline void test_queue(struct mq_attr *attr, struct mq_attr *result)
196{
197 int flags = O_RDWR | O_EXCL | O_CREAT;
198 int perms = DEFFILEMODE;
199
200 if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
201 shutdown(1, "mq_open()", __LINE__);
202 if (mq_getattr(queue, result))
203 shutdown(1, "mq_getattr()", __LINE__);
204 if (mq_close(queue))
205 shutdown(1, "mq_close()", __LINE__);
206 queue = -1;
207 if (mq_unlink(queue_path))
208 shutdown(1, "mq_unlink()", __LINE__);
209}
210
211/*
212 * Same as test_queue above, but failure is not fatal.
213 * Returns:
214 * 0 - Failed to create a queue
215 * 1 - Created a queue, attributes in *result
216 */
217static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result)
218{
219 int flags = O_RDWR | O_EXCL | O_CREAT;
220 int perms = DEFFILEMODE;
221
222 if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
223 return 0;
224 if (mq_getattr(queue, result))
225 shutdown(1, "mq_getattr()", __LINE__);
226 if (mq_close(queue))
227 shutdown(1, "mq_close()", __LINE__);
228 queue = -1;
229 if (mq_unlink(queue_path))
230 shutdown(1, "mq_unlink()", __LINE__);
231 return 1;
232}
233
234int main(int argc, char *argv[])
235{
236 struct mq_attr attr, result;
237
238 if (argc != 2) {
239 fprintf(stderr, "Must pass a valid queue name\n\n");
240 fprintf(stderr, usage, argv[0]);
241 exit(1);
242 }
243
244 /*
245 * Although we can create a msg queue with a non-absolute path name,
246 * unlink will fail. So, if the name doesn't start with a /, add one
247 * when we save it.
248 */
249 if (*argv[1] == '/')
250 queue_path = strdup(argv[1]);
251 else {
252 queue_path = malloc(strlen(argv[1]) + 2);
253 if (!queue_path) {
254 perror("malloc()");
255 exit(1);
256 }
257 queue_path[0] = '/';
258 queue_path[1] = 0;
259 strcat(queue_path, argv[1]);
260 }
261
262 if (getuid() != 0) {
263 fprintf(stderr, "Not running as root, but almost all tests "
264 "require root in order to modify\nsystem settings. "
265 "Exiting.\n");
266 exit(1);
267 }
268
269 /* Find out what files there are for us to make tweaks in */
270 def_msgs = fopen(DEF_MSGS, "r+");
271 def_msgsize = fopen(DEF_MSGSIZE, "r+");
272 max_msgs = fopen(MAX_MSGS, "r+");
273 max_msgsize = fopen(MAX_MSGSIZE, "r+");
274
275 if (!max_msgs)
276 shutdown(2, "Failed to open msg_max", __LINE__);
277 if (!max_msgsize)
278 shutdown(2, "Failed to open msgsize_max", __LINE__);
279 if (def_msgs || def_msgsize)
280 default_settings = 1;
281
282 /* Load up the current system values for everything we can */
283 getr(RLIMIT_MSGQUEUE, &saved_limits);
284 cur_limits = saved_limits;
285 if (default_settings) {
286 saved_def_msgs = cur_def_msgs = get(def_msgs);
287 saved_def_msgsize = cur_def_msgsize = get(def_msgsize);
288 }
289 saved_max_msgs = cur_max_msgs = get(max_msgs);
290 saved_max_msgsize = cur_max_msgsize = get(max_msgsize);
291
292 /* Tell the user our initial state */
293 printf("\nInitial system state:\n");
294 printf("\tUsing queue path:\t\t%s\n", queue_path);
295 printf("\tRLIMIT_MSGQUEUE(soft):\t\t%d\n", saved_limits.rlim_cur);
296 printf("\tRLIMIT_MSGQUEUE(hard):\t\t%d\n", saved_limits.rlim_max);
297 printf("\tMaximum Message Size:\t\t%d\n", saved_max_msgsize);
298 printf("\tMaximum Queue Size:\t\t%d\n", saved_max_msgs);
299 if (default_settings) {
300 printf("\tDefault Message Size:\t\t%d\n", saved_def_msgsize);
301 printf("\tDefault Queue Size:\t\t%d\n", saved_def_msgs);
302 } else {
303 printf("\tDefault Message Size:\t\tNot Supported\n");
304 printf("\tDefault Queue Size:\t\tNot Supported\n");
305 }
306 printf("\n");
307
308 validate_current_settings();
309
310 printf("Adjusted system state for testing:\n");
311 printf("\tRLIMIT_MSGQUEUE(soft):\t\t%d\n", cur_limits.rlim_cur);
312 printf("\tRLIMIT_MSGQUEUE(hard):\t\t%d\n", cur_limits.rlim_max);
313 printf("\tMaximum Message Size:\t\t%d\n", cur_max_msgsize);
314 printf("\tMaximum Queue Size:\t\t%d\n", cur_max_msgs);
315 if (default_settings) {
316 printf("\tDefault Message Size:\t\t%d\n", cur_def_msgsize);
317 printf("\tDefault Queue Size:\t\t%d\n", cur_def_msgs);
318 }
319
320 printf("\n\nTest series 1, behavior when no attr struct "
321 "passed to mq_open:\n");
322 if (!default_settings) {
323 test_queue(NULL, &result);
324 printf("Given sane system settings, mq_open without an attr "
325 "struct succeeds:\tPASS\n");
326 if (result.mq_maxmsg != cur_max_msgs ||
327 result.mq_msgsize != cur_max_msgsize) {
328 printf("Kernel does not support setting the default "
329 "mq attributes,\nbut also doesn't tie the "
330 "defaults to the maximums:\t\t\tPASS\n");
331 } else {
332 set(max_msgs, ++cur_max_msgs);
333 set(max_msgsize, ++cur_max_msgsize);
334 test_queue(NULL, &result);
335 if (result.mq_maxmsg == cur_max_msgs &&
336 result.mq_msgsize == cur_max_msgsize)
337 printf("Kernel does not support setting the "
338 "default mq attributes and\n"
339 "also ties system wide defaults to "
340 "the system wide maximums:\t\t"
341 "FAIL\n");
342 else
343 printf("Kernel does not support setting the "
344 "default mq attributes,\n"
345 "but also doesn't tie the defaults to "
346 "the maximums:\t\t\tPASS\n");
347 }
348 } else {
349 printf("Kernel supports setting defaults separately from "
350 "maximums:\t\tPASS\n");
351 /*
352 * While we are here, go ahead and test that the kernel
353 * properly follows the default settings
354 */
355 test_queue(NULL, &result);
356 printf("Given sane values, mq_open without an attr struct "
357 "succeeds:\t\tPASS\n");
358 if (result.mq_maxmsg != cur_def_msgs ||
359 result.mq_msgsize != cur_def_msgsize)
360 printf("Kernel supports setting defaults, but does "
361 "not actually honor them:\tFAIL\n\n");
362 else {
363 set(def_msgs, ++cur_def_msgs);
364 set(def_msgsize, ++cur_def_msgsize);
365 /* In case max was the same as the default */
366 set(max_msgs, ++cur_max_msgs);
367 set(max_msgsize, ++cur_max_msgsize);
368 test_queue(NULL, &result);
369 if (result.mq_maxmsg != cur_def_msgs ||
370 result.mq_msgsize != cur_def_msgsize)
371 printf("Kernel supports setting defaults, but "
372 "does not actually honor them:\t"
373 "FAIL\n");
374 else
375 printf("Kernel properly honors default setting "
376 "knobs:\t\t\t\tPASS\n");
377 }
378 set(def_msgs, cur_max_msgs + 1);
379 cur_def_msgs = cur_max_msgs + 1;
380 set(def_msgsize, cur_max_msgsize + 1);
381 cur_def_msgsize = cur_max_msgsize + 1;
382 if (cur_def_msgs * (cur_def_msgsize + 2 * sizeof(void *)) >=
383 cur_limits.rlim_cur) {
384 cur_limits.rlim_cur = (cur_def_msgs + 2) *
385 (cur_def_msgsize + 2 * sizeof(void *));
386 cur_limits.rlim_max = 2 * cur_limits.rlim_cur;
387 setr(RLIMIT_MSGQUEUE, &cur_limits);
388 }
389 if (test_queue_fail(NULL, &result)) {
390 if (result.mq_maxmsg == cur_max_msgs &&
391 result.mq_msgsize == cur_max_msgsize)
392 printf("Kernel properly limits default values "
393 "to lesser of default/max:\t\tPASS\n");
394 else
395 printf("Kernel does not properly set default "
396 "queue parameters when\ndefaults > "
397 "max:\t\t\t\t\t\t\t\tFAIL\n");
398 } else
399 printf("Kernel fails to open mq because defaults are "
400 "greater than maximums:\tFAIL\n");
401 set(def_msgs, --cur_def_msgs);
402 set(def_msgsize, --cur_def_msgsize);
403 cur_limits.rlim_cur = cur_limits.rlim_max = cur_def_msgs *
404 cur_def_msgsize;
405 setr(RLIMIT_MSGQUEUE, &cur_limits);
406 if (test_queue_fail(NULL, &result))
407 printf("Kernel creates queue even though defaults "
408 "would exceed\nrlimit setting:"
409 "\t\t\t\t\t\t\t\tFAIL\n");
410 else
411 printf("Kernel properly fails to create queue when "
412 "defaults would\nexceed rlimit:"
413 "\t\t\t\t\t\t\t\tPASS\n");
414 }
415
416 /*
417 * Test #2 - open with an attr struct that exceeds rlimit
418 */
419 printf("\n\nTest series 2, behavior when attr struct is "
420 "passed to mq_open:\n");
421 cur_max_msgs = 32;
422 cur_max_msgsize = cur_limits.rlim_max >> 4;
423 set(max_msgs, cur_max_msgs);
424 set(max_msgsize, cur_max_msgsize);
425 attr.mq_maxmsg = cur_max_msgs;
426 attr.mq_msgsize = cur_max_msgsize;
427 if (test_queue_fail(&attr, &result))
428 printf("Queue open in excess of rlimit max when euid = 0 "
429 "succeeded:\t\tFAIL\n");
430 else
431 printf("Queue open in excess of rlimit max when euid = 0 "
432 "failed:\t\tPASS\n");
433 attr.mq_maxmsg = cur_max_msgs + 1;
434 attr.mq_msgsize = 10;
435 if (test_queue_fail(&attr, &result))
436 printf("Queue open with mq_maxmsg > limit when euid = 0 "
437 "succeeded:\t\tPASS\n");
438 else
439 printf("Queue open with mq_maxmsg > limit when euid = 0 "
440 "failed:\t\tFAIL\n");
441 attr.mq_maxmsg = 1;
442 attr.mq_msgsize = cur_max_msgsize + 1;
443 if (test_queue_fail(&attr, &result))
444 printf("Queue open with mq_msgsize > limit when euid = 0 "
445 "succeeded:\t\tPASS\n");
446 else
447 printf("Queue open with mq_msgsize > limit when euid = 0 "
448 "failed:\t\tFAIL\n");
449 attr.mq_maxmsg = 65536;
450 attr.mq_msgsize = 65536;
451 if (test_queue_fail(&attr, &result))
452 printf("Queue open with total size > 2GB when euid = 0 "
453 "succeeded:\t\tFAIL\n");
454 else
455 printf("Queue open with total size > 2GB when euid = 0 "
456 "failed:\t\t\tPASS\n");
457 seteuid(99);
458 attr.mq_maxmsg = cur_max_msgs;
459 attr.mq_msgsize = cur_max_msgsize;
460 if (test_queue_fail(&attr, &result))
461 printf("Queue open in excess of rlimit max when euid = 99 "
462 "succeeded:\t\tFAIL\n");
463 else
464 printf("Queue open in excess of rlimit max when euid = 99 "
465 "failed:\t\tPASS\n");
466 attr.mq_maxmsg = cur_max_msgs + 1;
467 attr.mq_msgsize = 10;
468 if (test_queue_fail(&attr, &result))
469 printf("Queue open with mq_maxmsg > limit when euid = 99 "
470 "succeeded:\t\tFAIL\n");
471 else
472 printf("Queue open with mq_maxmsg > limit when euid = 99 "
473 "failed:\t\tPASS\n");
474 attr.mq_maxmsg = 1;
475 attr.mq_msgsize = cur_max_msgsize + 1;
476 if (test_queue_fail(&attr, &result))
477 printf("Queue open with mq_msgsize > limit when euid = 99 "
478 "succeeded:\t\tFAIL\n");
479 else
480 printf("Queue open with mq_msgsize > limit when euid = 99 "
481 "failed:\t\tPASS\n");
482 attr.mq_maxmsg = 65536;
483 attr.mq_msgsize = 65536;
484 if (test_queue_fail(&attr, &result))
485 printf("Queue open with total size > 2GB when euid = 99 "
486 "succeeded:\t\tFAIL\n");
487 else
488 printf("Queue open with total size > 2GB when euid = 99 "
489 "failed:\t\t\tPASS\n");
490
491 shutdown(0,"",0);
492}
diff --git a/tools/testing/selftests/mqueue/mq_perf_tests.c b/tools/testing/selftests/mqueue/mq_perf_tests.c
new file mode 100644
index 000000000000..2fadd4b97045
--- /dev/null
+++ b/tools/testing/selftests/mqueue/mq_perf_tests.c
@@ -0,0 +1,741 @@
1/*
2 * This application is Copyright 2012 Red Hat, Inc.
3 * Doug Ledford <dledford@redhat.com>
4 *
5 * mq_perf_tests is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * mq_perf_tests is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * For the full text of the license, see <http://www.gnu.org/licenses/>.
15 *
16 * mq_perf_tests.c
17 * Tests various types of message queue workloads, concentrating on those
18 * situations that invole large message sizes, large message queue depths,
19 * or both, and reports back useful metrics about kernel message queue
20 * performance.
21 *
22 */
23#define _GNU_SOURCE
24#include <stdio.h>
25#include <stdlib.h>
26#include <unistd.h>
27#include <fcntl.h>
28#include <string.h>
29#include <limits.h>
30#include <errno.h>
31#include <signal.h>
32#include <pthread.h>
33#include <sched.h>
34#include <sys/types.h>
35#include <sys/time.h>
36#include <sys/resource.h>
37#include <sys/stat.h>
38#include <mqueue.h>
39#include <popt.h>
40
41static char *usage =
42"Usage:\n"
43" %s [-c #[,#..] -f] path\n"
44"\n"
45" -c # Skip most tests and go straight to a high queue depth test\n"
46" and then run that test continuously (useful for running at\n"
47" the same time as some other workload to see how much the\n"
48" cache thrashing caused by adding messages to a very deep\n"
49" queue impacts the performance of other programs). The number\n"
50" indicates which CPU core we should bind the process to during\n"
51" the run. If you have more than one physical CPU, then you\n"
52" will need one copy per physical CPU package, and you should\n"
53" specify the CPU cores to pin ourself to via a comma separated\n"
54" list of CPU values.\n"
55" -f Only usable with continuous mode. Pin ourself to the CPUs\n"
56" as requested, then instead of looping doing a high mq\n"
57" workload, just busy loop. This will allow us to lock up a\n"
58" single CPU just like we normally would, but without actually\n"
59" thrashing the CPU cache. This is to make it easier to get\n"
60" comparable numbers from some other workload running on the\n"
61" other CPUs. One set of numbers with # CPUs locked up running\n"
62" an mq workload, and another set of numbers with those same\n"
63" CPUs locked away from the test workload, but not doing\n"
64" anything to trash the cache like the mq workload might.\n"
65" path Path name of the message queue to create\n"
66"\n"
67" Note: this program must be run as root in order to enable all tests\n"
68"\n";
69
70char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max";
71char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max";
72
73#define min(a, b) ((a) < (b) ? (a) : (b))
74#define MAX_CPUS 64
75char *cpu_option_string;
76int cpus_to_pin[MAX_CPUS];
77int num_cpus_to_pin;
78pthread_t cpu_threads[MAX_CPUS];
79pthread_t main_thread;
80cpu_set_t *cpu_set;
81int cpu_set_size;
82int cpus_online;
83
84#define MSG_SIZE 16
85#define TEST1_LOOPS 10000000
86#define TEST2_LOOPS 100000
87int continuous_mode;
88int continuous_mode_fake;
89
90struct rlimit saved_limits, cur_limits;
91int saved_max_msgs, saved_max_msgsize;
92int cur_max_msgs, cur_max_msgsize;
93FILE *max_msgs, *max_msgsize;
94int cur_nice;
95char *queue_path = "/mq_perf_tests";
96mqd_t queue = -1;
97struct mq_attr result;
98int mq_prio_max;
99
100const struct poptOption options[] = {
101 {
102 .longName = "continuous",
103 .shortName = 'c',
104 .argInfo = POPT_ARG_STRING,
105 .arg = &cpu_option_string,
106 .val = 'c',
107 .descrip = "Run continuous tests at a high queue depth in "
108 "order to test the effects of cache thrashing on "
109 "other tasks on the system. This test is intended "
110 "to be run on one core of each physical CPU while "
111 "some other CPU intensive task is run on all the other "
112 "cores of that same physical CPU and the other task "
113 "is timed. It is assumed that the process of adding "
114 "messages to the message queue in a tight loop will "
115 "impact that other task to some degree. Once the "
116 "tests are performed in this way, you should then "
117 "re-run the tests using fake mode in order to check "
118 "the difference in time required to perform the CPU "
119 "intensive task",
120 .argDescrip = "cpu[,cpu]",
121 },
122 {
123 .longName = "fake",
124 .shortName = 'f',
125 .argInfo = POPT_ARG_NONE,
126 .arg = &continuous_mode_fake,
127 .val = 0,
128 .descrip = "Tie up the CPUs that we would normally tie up in"
129 "continuous mode, but don't actually do any mq stuff, "
130 "just keep the CPU busy so it can't be used to process "
131 "system level tasks as this would free up resources on "
132 "the other CPU cores and skew the comparison between "
133 "the no-mqueue work and mqueue work tests",
134 .argDescrip = NULL,
135 },
136 {
137 .longName = "path",
138 .shortName = 'p',
139 .argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT,
140 .arg = &queue_path,
141 .val = 'p',
142 .descrip = "The name of the path to use in the mqueue "
143 "filesystem for our tests",
144 .argDescrip = "pathname",
145 },
146 POPT_AUTOHELP
147 POPT_TABLEEND
148};
149
150static inline void __set(FILE *stream, int value, char *err_msg);
151void shutdown(int exit_val, char *err_cause, int line_no);
152void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context);
153void sig_action(int signum, siginfo_t *info, void *context);
154static inline int get(FILE *stream);
155static inline void set(FILE *stream, int value);
156static inline int try_set(FILE *stream, int value);
157static inline void getr(int type, struct rlimit *rlim);
158static inline void setr(int type, struct rlimit *rlim);
159static inline void open_queue(struct mq_attr *attr);
160void increase_limits(void);
161
162static inline void __set(FILE *stream, int value, char *err_msg)
163{
164 rewind(stream);
165 if (fprintf(stream, "%d", value) < 0)
166 perror(err_msg);
167}
168
169
170void shutdown(int exit_val, char *err_cause, int line_no)
171{
172 static int in_shutdown = 0;
173 int errno_at_shutdown = errno;
174 int i;
175
176 /* In case we get called by multiple threads or from an sighandler */
177 if (in_shutdown++)
178 return;
179
180 for (i = 0; i < num_cpus_to_pin; i++)
181 if (cpu_threads[i]) {
182 pthread_kill(cpu_threads[i], SIGUSR1);
183 pthread_join(cpu_threads[i], NULL);
184 }
185
186 if (queue != -1)
187 if (mq_close(queue))
188 perror("mq_close() during shutdown");
189 if (queue_path)
190 /*
191 * Be silent if this fails, if we cleaned up already it's
192 * expected to fail
193 */
194 mq_unlink(queue_path);
195 if (saved_max_msgs)
196 __set(max_msgs, saved_max_msgs,
197 "failed to restore saved_max_msgs");
198 if (saved_max_msgsize)
199 __set(max_msgsize, saved_max_msgsize,
200 "failed to restore saved_max_msgsize");
201 if (exit_val)
202 error(exit_val, errno_at_shutdown, "%s at %d",
203 err_cause, line_no);
204 exit(0);
205}
206
207void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context)
208{
209 if (pthread_self() != main_thread)
210 pthread_exit(0);
211 else {
212 fprintf(stderr, "Caught signal %d in SIGUSR1 handler, "
213 "exiting\n", signum);
214 shutdown(0, "", 0);
215 fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n");
216 exit(0);
217 }
218}
219
220void sig_action(int signum, siginfo_t *info, void *context)
221{
222 if (pthread_self() != main_thread)
223 pthread_kill(main_thread, signum);
224 else {
225 fprintf(stderr, "Caught signal %d, exiting\n", signum);
226 shutdown(0, "", 0);
227 fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n");
228 exit(0);
229 }
230}
231
232static inline int get(FILE *stream)
233{
234 int value;
235 rewind(stream);
236 if (fscanf(stream, "%d", &value) != 1)
237 shutdown(4, "Error reading /proc entry", __LINE__);
238 return value;
239}
240
241static inline void set(FILE *stream, int value)
242{
243 int new_value;
244
245 rewind(stream);
246 if (fprintf(stream, "%d", value) < 0)
247 return shutdown(5, "Failed writing to /proc file", __LINE__);
248 new_value = get(stream);
249 if (new_value != value)
250 return shutdown(5, "We didn't get what we wrote to /proc back",
251 __LINE__);
252}
253
254static inline int try_set(FILE *stream, int value)
255{
256 int new_value;
257
258 rewind(stream);
259 fprintf(stream, "%d", value);
260 new_value = get(stream);
261 return new_value == value;
262}
263
264static inline void getr(int type, struct rlimit *rlim)
265{
266 if (getrlimit(type, rlim))
267 shutdown(6, "getrlimit()", __LINE__);
268}
269
270static inline void setr(int type, struct rlimit *rlim)
271{
272 if (setrlimit(type, rlim))
273 shutdown(7, "setrlimit()", __LINE__);
274}
275
276/**
277 * open_queue - open the global queue for testing
278 * @attr - An attr struct specifying the desired queue traits
279 * @result - An attr struct that lists the actual traits the queue has
280 *
281 * This open is not allowed to fail, failure will result in an orderly
282 * shutdown of the program. The global queue_path is used to set what
283 * queue to open, the queue descriptor is saved in the global queue
284 * variable.
285 */
286static inline void open_queue(struct mq_attr *attr)
287{
288 int flags = O_RDWR | O_EXCL | O_CREAT | O_NONBLOCK;
289 int perms = DEFFILEMODE;
290
291 queue = mq_open(queue_path, flags, perms, attr);
292 if (queue == -1)
293 shutdown(1, "mq_open()", __LINE__);
294 if (mq_getattr(queue, &result))
295 shutdown(1, "mq_getattr()", __LINE__);
296 printf("\n\tQueue %s created:\n", queue_path);
297 printf("\t\tmq_flags:\t\t\t%s\n", result.mq_flags & O_NONBLOCK ?
298 "O_NONBLOCK" : "(null)");
299 printf("\t\tmq_maxmsg:\t\t\t%d\n", result.mq_maxmsg);
300 printf("\t\tmq_msgsize:\t\t\t%d\n", result.mq_msgsize);
301 printf("\t\tmq_curmsgs:\t\t\t%d\n", result.mq_curmsgs);
302}
303
304void *fake_cont_thread(void *arg)
305{
306 int i;
307
308 for (i = 0; i < num_cpus_to_pin; i++)
309 if (cpu_threads[i] == pthread_self())
310 break;
311 printf("\tStarted fake continuous mode thread %d on CPU %d\n", i,
312 cpus_to_pin[i]);
313 while (1)
314 ;
315}
316
317void *cont_thread(void *arg)
318{
319 char buff[MSG_SIZE];
320 int i, priority;
321
322 for (i = 0; i < num_cpus_to_pin; i++)
323 if (cpu_threads[i] == pthread_self())
324 break;
325 printf("\tStarted continuous mode thread %d on CPU %d\n", i,
326 cpus_to_pin[i]);
327 while (1) {
328 while (mq_send(queue, buff, sizeof(buff), 0) == 0)
329 ;
330 mq_receive(queue, buff, sizeof(buff), &priority);
331 }
332}
333
334#define drain_queue() \
335 while (mq_receive(queue, buff, MSG_SIZE, &prio_in) == MSG_SIZE)
336
337#define do_untimed_send() \
338 do { \
339 if (mq_send(queue, buff, MSG_SIZE, prio_out)) \
340 shutdown(3, "Test send failure", __LINE__); \
341 } while (0)
342
343#define do_send_recv() \
344 do { \
345 clock_gettime(clock, &start); \
346 if (mq_send(queue, buff, MSG_SIZE, prio_out)) \
347 shutdown(3, "Test send failure", __LINE__); \
348 clock_gettime(clock, &middle); \
349 if (mq_receive(queue, buff, MSG_SIZE, &prio_in) != MSG_SIZE) \
350 shutdown(3, "Test receive failure", __LINE__); \
351 clock_gettime(clock, &end); \
352 nsec = ((middle.tv_sec - start.tv_sec) * 1000000000) + \
353 (middle.tv_nsec - start.tv_nsec); \
354 send_total.tv_nsec += nsec; \
355 if (send_total.tv_nsec >= 1000000000) { \
356 send_total.tv_sec++; \
357 send_total.tv_nsec -= 1000000000; \
358 } \
359 nsec = ((end.tv_sec - middle.tv_sec) * 1000000000) + \
360 (end.tv_nsec - middle.tv_nsec); \
361 recv_total.tv_nsec += nsec; \
362 if (recv_total.tv_nsec >= 1000000000) { \
363 recv_total.tv_sec++; \
364 recv_total.tv_nsec -= 1000000000; \
365 } \
366 } while (0)
367
368struct test {
369 char *desc;
370 void (*func)(int *);
371};
372
373void const_prio(int *prio)
374{
375 return;
376}
377
378void inc_prio(int *prio)
379{
380 if (++*prio == mq_prio_max)
381 *prio = 0;
382}
383
384void dec_prio(int *prio)
385{
386 if (--*prio < 0)
387 *prio = mq_prio_max - 1;
388}
389
390void random_prio(int *prio)
391{
392 *prio = random() % mq_prio_max;
393}
394
395struct test test2[] = {
396 {"\n\tTest #2a: Time send/recv message, queue full, constant prio\n",
397 const_prio},
398 {"\n\tTest #2b: Time send/recv message, queue full, increasing prio\n",
399 inc_prio},
400 {"\n\tTest #2c: Time send/recv message, queue full, decreasing prio\n",
401 dec_prio},
402 {"\n\tTest #2d: Time send/recv message, queue full, random prio\n",
403 random_prio},
404 {NULL, NULL}
405};
406
407/**
408 * Tests to perform (all done with MSG_SIZE messages):
409 *
410 * 1) Time to add/remove message with 0 messages on queue
411 * 1a) with constant prio
412 * 2) Time to add/remove message when queue close to capacity:
413 * 2a) with constant prio
414 * 2b) with increasing prio
415 * 2c) with decreasing prio
416 * 2d) with random prio
417 * 3) Test limits of priorities honored (double check _SC_MQ_PRIO_MAX)
418 */
419void *perf_test_thread(void *arg)
420{
421 char buff[MSG_SIZE];
422 int prio_out, prio_in;
423 int i;
424 clockid_t clock;
425 pthread_t *t;
426 struct timespec res, start, middle, end, send_total, recv_total;
427 unsigned long long nsec;
428 struct test *cur_test;
429
430 t = &cpu_threads[0];
431 printf("\n\tStarted mqueue performance test thread on CPU %d\n",
432 cpus_to_pin[0]);
433 mq_prio_max = sysconf(_SC_MQ_PRIO_MAX);
434 if (mq_prio_max == -1)
435 shutdown(2, "sysconf(_SC_MQ_PRIO_MAX)", __LINE__);
436 if (pthread_getcpuclockid(cpu_threads[0], &clock) != 0)
437 shutdown(2, "pthread_getcpuclockid", __LINE__);
438
439 if (clock_getres(clock, &res))
440 shutdown(2, "clock_getres()", __LINE__);
441
442 printf("\t\tMax priorities:\t\t\t%d\n", mq_prio_max);
443 printf("\t\tClock resolution:\t\t%d nsec%s\n", res.tv_nsec,
444 res.tv_nsec > 1 ? "s" : "");
445
446
447
448 printf("\n\tTest #1: Time send/recv message, queue empty\n");
449 printf("\t\t(%d iterations)\n", TEST1_LOOPS);
450 prio_out = 0;
451 send_total.tv_sec = 0;
452 send_total.tv_nsec = 0;
453 recv_total.tv_sec = 0;
454 recv_total.tv_nsec = 0;
455 for (i = 0; i < TEST1_LOOPS; i++)
456 do_send_recv();
457 printf("\t\tSend msg:\t\t\t%d.%ds total time\n",
458 send_total.tv_sec, send_total.tv_nsec);
459 nsec = ((unsigned long long)send_total.tv_sec * 1000000000 +
460 send_total.tv_nsec) / TEST1_LOOPS;
461 printf("\t\t\t\t\t\t%d nsec/msg\n", nsec);
462 printf("\t\tRecv msg:\t\t\t%d.%ds total time\n",
463 recv_total.tv_sec, recv_total.tv_nsec);
464 nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 +
465 recv_total.tv_nsec) / TEST1_LOOPS;
466 printf("\t\t\t\t\t\t%d nsec/msg\n", nsec);
467
468
469 for (cur_test = test2; cur_test->desc != NULL; cur_test++) {
470 printf(cur_test->desc);
471 printf("\t\t(%d iterations)\n", TEST2_LOOPS);
472 prio_out = 0;
473 send_total.tv_sec = 0;
474 send_total.tv_nsec = 0;
475 recv_total.tv_sec = 0;
476 recv_total.tv_nsec = 0;
477 printf("\t\tFilling queue...");
478 fflush(stdout);
479 clock_gettime(clock, &start);
480 for (i = 0; i < result.mq_maxmsg - 1; i++) {
481 do_untimed_send();
482 cur_test->func(&prio_out);
483 }
484 clock_gettime(clock, &end);
485 nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) *
486 1000000000) + (end.tv_nsec - start.tv_nsec);
487 printf("done.\t\t%lld.%llds\n", nsec / 1000000000,
488 nsec % 1000000000);
489 printf("\t\tTesting...");
490 fflush(stdout);
491 for (i = 0; i < TEST2_LOOPS; i++) {
492 do_send_recv();
493 cur_test->func(&prio_out);
494 }
495 printf("done.\n");
496 printf("\t\tSend msg:\t\t\t%d.%ds total time\n",
497 send_total.tv_sec, send_total.tv_nsec);
498 nsec = ((unsigned long long)send_total.tv_sec * 1000000000 +
499 send_total.tv_nsec) / TEST2_LOOPS;
500 printf("\t\t\t\t\t\t%d nsec/msg\n", nsec);
501 printf("\t\tRecv msg:\t\t\t%d.%ds total time\n",
502 recv_total.tv_sec, recv_total.tv_nsec);
503 nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 +
504 recv_total.tv_nsec) / TEST2_LOOPS;
505 printf("\t\t\t\t\t\t%d nsec/msg\n", nsec);
506 printf("\t\tDraining queue...");
507 fflush(stdout);
508 clock_gettime(clock, &start);
509 drain_queue();
510 clock_gettime(clock, &end);
511 nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) *
512 1000000000) + (end.tv_nsec - start.tv_nsec);
513 printf("done.\t\t%lld.%llds\n", nsec / 1000000000,
514 nsec % 1000000000);
515 }
516 return 0;
517}
518
519void increase_limits(void)
520{
521 cur_limits.rlim_cur = RLIM_INFINITY;
522 cur_limits.rlim_max = RLIM_INFINITY;
523 setr(RLIMIT_MSGQUEUE, &cur_limits);
524 while (try_set(max_msgs, cur_max_msgs += 10))
525 ;
526 cur_max_msgs = get(max_msgs);
527 while (try_set(max_msgsize, cur_max_msgsize += 1024))
528 ;
529 cur_max_msgsize = get(max_msgsize);
530 if (setpriority(PRIO_PROCESS, 0, -20) != 0)
531 shutdown(2, "setpriority()", __LINE__);
532 cur_nice = -20;
533}
534
535int main(int argc, char *argv[])
536{
537 struct mq_attr attr;
538 char *option, *next_option;
539 int i, cpu;
540 struct sigaction sa;
541 poptContext popt_context;
542 char rc;
543 void *retval;
544
545 main_thread = pthread_self();
546 num_cpus_to_pin = 0;
547
548 if (sysconf(_SC_NPROCESSORS_ONLN) == -1) {
549 perror("sysconf(_SC_NPROCESSORS_ONLN)");
550 exit(1);
551 }
552 cpus_online = min(MAX_CPUS, sysconf(_SC_NPROCESSORS_ONLN));
553 cpu_set = CPU_ALLOC(cpus_online);
554 if (cpu_set == NULL) {
555 perror("CPU_ALLOC()");
556 exit(1);
557 }
558 cpu_set_size = CPU_ALLOC_SIZE(cpus_online);
559 CPU_ZERO_S(cpu_set_size, cpu_set);
560
561 popt_context = poptGetContext(NULL, argc, (const char **)argv,
562 options, 0);
563
564 while ((rc = poptGetNextOpt(popt_context)) > 0) {
565 switch (rc) {
566 case 'c':
567 continuous_mode = 1;
568 option = cpu_option_string;
569 do {
570 next_option = strchr(option, ',');
571 if (next_option)
572 *next_option = '\0';
573 cpu = atoi(option);
574 if (cpu >= cpus_online)
575 fprintf(stderr, "CPU %d exceeds "
576 "cpus online, ignoring.\n",
577 cpu);
578 else
579 cpus_to_pin[num_cpus_to_pin++] = cpu;
580 if (next_option)
581 option = ++next_option;
582 } while (next_option && num_cpus_to_pin < MAX_CPUS);
583 /* Double check that they didn't give us the same CPU
584 * more than once */
585 for (cpu = 0; cpu < num_cpus_to_pin; cpu++) {
586 if (CPU_ISSET_S(cpus_to_pin[cpu], cpu_set_size,
587 cpu_set)) {
588 fprintf(stderr, "Any given CPU may "
589 "only be given once.\n");
590 exit(1);
591 } else
592 CPU_SET_S(cpus_to_pin[cpu],
593 cpu_set_size, cpu_set);
594 }
595 break;
596 case 'p':
597 /*
598 * Although we can create a msg queue with a
599 * non-absolute path name, unlink will fail. So,
600 * if the name doesn't start with a /, add one
601 * when we save it.
602 */
603 option = queue_path;
604 if (*option != '/') {
605 queue_path = malloc(strlen(option) + 2);
606 if (!queue_path) {
607 perror("malloc()");
608 exit(1);
609 }
610 queue_path[0] = '/';
611 queue_path[1] = 0;
612 strcat(queue_path, option);
613 free(option);
614 }
615 break;
616 }
617 }
618
619 if (continuous_mode && num_cpus_to_pin == 0) {
620 fprintf(stderr, "Must pass at least one CPU to continuous "
621 "mode.\n");
622 poptPrintUsage(popt_context, stderr, 0);
623 exit(1);
624 } else if (!continuous_mode) {
625 num_cpus_to_pin = 1;
626 cpus_to_pin[0] = cpus_online - 1;
627 }
628
629 if (getuid() != 0) {
630 fprintf(stderr, "Not running as root, but almost all tests "
631 "require root in order to modify\nsystem settings. "
632 "Exiting.\n");
633 exit(1);
634 }
635
636 max_msgs = fopen(MAX_MSGS, "r+");
637 max_msgsize = fopen(MAX_MSGSIZE, "r+");
638 if (!max_msgs)
639 shutdown(2, "Failed to open msg_max", __LINE__);
640 if (!max_msgsize)
641 shutdown(2, "Failed to open msgsize_max", __LINE__);
642
643 /* Load up the current system values for everything we can */
644 getr(RLIMIT_MSGQUEUE, &saved_limits);
645 cur_limits = saved_limits;
646 saved_max_msgs = cur_max_msgs = get(max_msgs);
647 saved_max_msgsize = cur_max_msgsize = get(max_msgsize);
648 errno = 0;
649 cur_nice = getpriority(PRIO_PROCESS, 0);
650 if (errno)
651 shutdown(2, "getpriority()", __LINE__);
652
653 /* Tell the user our initial state */
654 printf("\nInitial system state:\n");
655 printf("\tUsing queue path:\t\t\t%s\n", queue_path);
656 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%d\n", saved_limits.rlim_cur);
657 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%d\n", saved_limits.rlim_max);
658 printf("\tMaximum Message Size:\t\t\t%d\n", saved_max_msgsize);
659 printf("\tMaximum Queue Size:\t\t\t%d\n", saved_max_msgs);
660 printf("\tNice value:\t\t\t\t%d\n", cur_nice);
661 printf("\n");
662
663 increase_limits();
664
665 printf("Adjusted system state for testing:\n");
666 if (cur_limits.rlim_cur == RLIM_INFINITY) {
667 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n");
668 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n");
669 } else {
670 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%d\n",
671 cur_limits.rlim_cur);
672 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%d\n",
673 cur_limits.rlim_max);
674 }
675 printf("\tMaximum Message Size:\t\t\t%d\n", cur_max_msgsize);
676 printf("\tMaximum Queue Size:\t\t\t%d\n", cur_max_msgs);
677 printf("\tNice value:\t\t\t\t%d\n", cur_nice);
678 printf("\tContinuous mode:\t\t\t(%s)\n", continuous_mode ?
679 (continuous_mode_fake ? "fake mode" : "enabled") :
680 "disabled");
681 printf("\tCPUs to pin:\t\t\t\t%d", cpus_to_pin[0]);
682 for (cpu = 1; cpu < num_cpus_to_pin; cpu++)
683 printf(",%d", cpus_to_pin[cpu]);
684 printf("\n");
685
686 sa.sa_sigaction = sig_action_SIGUSR1;
687 sigemptyset(&sa.sa_mask);
688 sigaddset(&sa.sa_mask, SIGHUP);
689 sigaddset(&sa.sa_mask, SIGINT);
690 sigaddset(&sa.sa_mask, SIGQUIT);
691 sigaddset(&sa.sa_mask, SIGTERM);
692 sa.sa_flags = SA_SIGINFO;
693 if (sigaction(SIGUSR1, &sa, NULL) == -1)
694 shutdown(1, "sigaction(SIGUSR1)", __LINE__);
695 sa.sa_sigaction = sig_action;
696 if (sigaction(SIGHUP, &sa, NULL) == -1)
697 shutdown(1, "sigaction(SIGHUP)", __LINE__);
698 if (sigaction(SIGINT, &sa, NULL) == -1)
699 shutdown(1, "sigaction(SIGINT)", __LINE__);
700 if (sigaction(SIGQUIT, &sa, NULL) == -1)
701 shutdown(1, "sigaction(SIGQUIT)", __LINE__);
702 if (sigaction(SIGTERM, &sa, NULL) == -1)
703 shutdown(1, "sigaction(SIGTERM)", __LINE__);
704
705 if (!continuous_mode_fake) {
706 attr.mq_flags = O_NONBLOCK;
707 attr.mq_maxmsg = cur_max_msgs;
708 attr.mq_msgsize = MSG_SIZE;
709 open_queue(&attr);
710 }
711 for (i = 0; i < num_cpus_to_pin; i++) {
712 pthread_attr_t thread_attr;
713 void *thread_func;
714
715 if (continuous_mode_fake)
716 thread_func = &fake_cont_thread;
717 else if (continuous_mode)
718 thread_func = &cont_thread;
719 else
720 thread_func = &perf_test_thread;
721
722 CPU_ZERO_S(cpu_set_size, cpu_set);
723 CPU_SET_S(cpus_to_pin[i], cpu_set_size, cpu_set);
724 pthread_attr_init(&thread_attr);
725 pthread_attr_setaffinity_np(&thread_attr, cpu_set_size,
726 cpu_set);
727 if (pthread_create(&cpu_threads[i], &thread_attr, thread_func,
728 NULL))
729 shutdown(1, "pthread_create()", __LINE__);
730 pthread_attr_destroy(&thread_attr);
731 }
732
733 if (!continuous_mode) {
734 pthread_join(cpu_threads[0], &retval);
735 shutdown((long)retval, "perf_test_thread()", __LINE__);
736 } else {
737 while (1)
738 sleep(1);
739 }
740 shutdown(0, "", 0);
741}
diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c
index 4b107b5e623f..8674b9ec14f6 100644
--- a/tools/usb/ffs-test.c
+++ b/tools/usb/ffs-test.c
@@ -297,7 +297,7 @@ static void *start_thread_helper(void *arg)
297 297
298 ret = t->in(t, t->buf, t->buf_size); 298 ret = t->in(t, t->buf, t->buf_size);
299 if (ret > 0) { 299 if (ret > 0) {
300 ret = t->out(t, t->buf, t->buf_size); 300 ret = t->out(t, t->buf, ret);
301 name = out_name; 301 name = out_name;
302 op = "write"; 302 op = "write";
303 } else { 303 } else {
diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c
index 6e0f56701e44..82d7c590c026 100644
--- a/tools/usb/testusb.c
+++ b/tools/usb/testusb.c
@@ -358,6 +358,7 @@ static const char *usbfs_dir_find(void)
358{ 358{
359 static char usbfs_path_0[] = "/dev/usb/devices"; 359 static char usbfs_path_0[] = "/dev/usb/devices";
360 static char usbfs_path_1[] = "/proc/bus/usb/devices"; 360 static char usbfs_path_1[] = "/proc/bus/usb/devices";
361 static char udev_usb_path[] = "/dev/bus/usb";
361 362
362 static char *const usbfs_paths[] = { 363 static char *const usbfs_paths[] = {
363 usbfs_path_0, usbfs_path_1 364 usbfs_path_0, usbfs_path_1
@@ -376,6 +377,10 @@ static const char *usbfs_dir_find(void)
376 } 377 }
377 } while (++it != end); 378 } while (++it != end);
378 379
380 /* real device-nodes managed by udev */
381 if (access(udev_usb_path, F_OK) == 0)
382 return udev_usb_path;
383
379 return NULL; 384 return NULL;
380} 385}
381 386
diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h
index 7579f19e61e0..81847dd08bd0 100644
--- a/tools/virtio/linux/virtio.h
+++ b/tools/virtio/linux/virtio.h
@@ -203,6 +203,7 @@ void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len);
203void virtqueue_disable_cb(struct virtqueue *vq); 203void virtqueue_disable_cb(struct virtqueue *vq);
204 204
205bool virtqueue_enable_cb(struct virtqueue *vq); 205bool virtqueue_enable_cb(struct virtqueue *vq);
206bool virtqueue_enable_cb_delayed(struct virtqueue *vq);
206 207
207void *virtqueue_detach_unused_buf(struct virtqueue *vq); 208void *virtqueue_detach_unused_buf(struct virtqueue *vq);
208struct virtqueue *vring_new_virtqueue(unsigned int num, 209struct virtqueue *vring_new_virtqueue(unsigned int num,
diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c
index 6bf95f995364..e626fa553c5a 100644
--- a/tools/virtio/virtio_test.c
+++ b/tools/virtio/virtio_test.c
@@ -144,7 +144,8 @@ static void wait_for_interrupt(struct vdev_info *dev)
144 } 144 }
145} 145}
146 146
147static void run_test(struct vdev_info *dev, struct vq_info *vq, int bufs) 147static void run_test(struct vdev_info *dev, struct vq_info *vq,
148 bool delayed, int bufs)
148{ 149{
149 struct scatterlist sl; 150 struct scatterlist sl;
150 long started = 0, completed = 0; 151 long started = 0, completed = 0;
@@ -183,8 +184,12 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq, int bufs)
183 assert(started <= bufs); 184 assert(started <= bufs);
184 if (completed == bufs) 185 if (completed == bufs)
185 break; 186 break;
186 if (virtqueue_enable_cb(vq->vq)) { 187 if (delayed) {
187 wait_for_interrupt(dev); 188 if (virtqueue_enable_cb_delayed(vq->vq))
189 wait_for_interrupt(dev);
190 } else {
191 if (virtqueue_enable_cb(vq->vq))
192 wait_for_interrupt(dev);
188 } 193 }
189 } 194 }
190 test = 0; 195 test = 0;
@@ -216,6 +221,14 @@ const struct option longopts[] = {
216 .val = 'i', 221 .val = 'i',
217 }, 222 },
218 { 223 {
224 .name = "delayed-interrupt",
225 .val = 'D',
226 },
227 {
228 .name = "no-delayed-interrupt",
229 .val = 'd',
230 },
231 {
219 } 232 }
220}; 233};
221 234
@@ -224,6 +237,7 @@ static void help()
224 fprintf(stderr, "Usage: virtio_test [--help]" 237 fprintf(stderr, "Usage: virtio_test [--help]"
225 " [--no-indirect]" 238 " [--no-indirect]"
226 " [--no-event-idx]" 239 " [--no-event-idx]"
240 " [--delayed-interrupt]"
227 "\n"); 241 "\n");
228} 242}
229 243
@@ -233,6 +247,7 @@ int main(int argc, char **argv)
233 unsigned long long features = (1ULL << VIRTIO_RING_F_INDIRECT_DESC) | 247 unsigned long long features = (1ULL << VIRTIO_RING_F_INDIRECT_DESC) |
234 (1ULL << VIRTIO_RING_F_EVENT_IDX); 248 (1ULL << VIRTIO_RING_F_EVENT_IDX);
235 int o; 249 int o;
250 bool delayed = false;
236 251
237 for (;;) { 252 for (;;) {
238 o = getopt_long(argc, argv, optstring, longopts, NULL); 253 o = getopt_long(argc, argv, optstring, longopts, NULL);
@@ -251,6 +266,9 @@ int main(int argc, char **argv)
251 case 'i': 266 case 'i':
252 features &= ~(1ULL << VIRTIO_RING_F_INDIRECT_DESC); 267 features &= ~(1ULL << VIRTIO_RING_F_INDIRECT_DESC);
253 break; 268 break;
269 case 'D':
270 delayed = true;
271 break;
254 default: 272 default:
255 assert(0); 273 assert(0);
256 break; 274 break;
@@ -260,6 +278,6 @@ int main(int argc, char **argv)
260done: 278done:
261 vdev_info_init(&dev, features); 279 vdev_info_init(&dev, features);
262 vq_info_add(&dev, 256); 280 vq_info_add(&dev, 256);
263 run_test(&dev, &dev.vqs[0], 0x100000); 281 run_test(&dev, &dev.vqs[0], delayed, 0x100000);
264 return 0; 282 return 0;
265} 283}
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c
index 7dab7b25b5c6..f576971f6556 100644
--- a/tools/vm/page-types.c
+++ b/tools/vm/page-types.c
@@ -35,6 +35,7 @@
35#include <sys/mount.h> 35#include <sys/mount.h>
36#include <sys/statfs.h> 36#include <sys/statfs.h>
37#include "../../include/linux/magic.h" 37#include "../../include/linux/magic.h"
38#include "../../include/linux/kernel-page-flags.h"
38 39
39 40
40#ifndef MAX_PATH 41#ifndef MAX_PATH
@@ -73,33 +74,6 @@
73#define KPF_BYTES 8 74#define KPF_BYTES 8
74#define PROC_KPAGEFLAGS "/proc/kpageflags" 75#define PROC_KPAGEFLAGS "/proc/kpageflags"
75 76
76/* copied from kpageflags_read() */
77#define KPF_LOCKED 0
78#define KPF_ERROR 1
79#define KPF_REFERENCED 2
80#define KPF_UPTODATE 3
81#define KPF_DIRTY 4
82#define KPF_LRU 5
83#define KPF_ACTIVE 6
84#define KPF_SLAB 7
85#define KPF_WRITEBACK 8
86#define KPF_RECLAIM 9
87#define KPF_BUDDY 10
88
89/* [11-20] new additions in 2.6.31 */
90#define KPF_MMAP 11
91#define KPF_ANON 12
92#define KPF_SWAPCACHE 13
93#define KPF_SWAPBACKED 14
94#define KPF_COMPOUND_HEAD 15
95#define KPF_COMPOUND_TAIL 16
96#define KPF_HUGE 17
97#define KPF_UNEVICTABLE 18
98#define KPF_HWPOISON 19
99#define KPF_NOPAGE 20
100#define KPF_KSM 21
101#define KPF_THP 22
102
103/* [32-] kernel hacking assistances */ 77/* [32-] kernel hacking assistances */
104#define KPF_RESERVED 32 78#define KPF_RESERVED 32
105#define KPF_MLOCKED 33 79#define KPF_MLOCKED 33
@@ -326,7 +300,7 @@ static char *page_flag_name(uint64_t flags)
326{ 300{
327 static char buf[65]; 301 static char buf[65];
328 int present; 302 int present;
329 int i, j; 303 size_t i, j;
330 304
331 for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) { 305 for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) {
332 present = (flags >> i) & 1; 306 present = (flags >> i) & 1;
@@ -344,7 +318,7 @@ static char *page_flag_name(uint64_t flags)
344static char *page_flag_longname(uint64_t flags) 318static char *page_flag_longname(uint64_t flags)
345{ 319{
346 static char buf[1024]; 320 static char buf[1024];
347 int i, n; 321 size_t i, n;
348 322
349 for (i = 0, n = 0; i < ARRAY_SIZE(page_flag_names); i++) { 323 for (i = 0, n = 0; i < ARRAY_SIZE(page_flag_names); i++) {
350 if (!page_flag_names[i]) 324 if (!page_flag_names[i])
@@ -402,7 +376,7 @@ static void show_page(unsigned long voffset,
402 376
403static void show_summary(void) 377static void show_summary(void)
404{ 378{
405 int i; 379 size_t i;
406 380
407 printf(" flags\tpage-count MB" 381 printf(" flags\tpage-count MB"
408 " symbolic-flags\t\t\tlong-symbolic-flags\n"); 382 " symbolic-flags\t\t\tlong-symbolic-flags\n");
@@ -500,7 +474,7 @@ static int debugfs_valid_mountpoint(const char *debugfs)
500/* find the path to the mounted debugfs */ 474/* find the path to the mounted debugfs */
501static const char *debugfs_find_mountpoint(void) 475static const char *debugfs_find_mountpoint(void)
502{ 476{
503 const char **ptr; 477 const char *const *ptr;
504 char type[100]; 478 char type[100];
505 FILE *fp; 479 FILE *fp;
506 480
@@ -537,7 +511,7 @@ static const char *debugfs_find_mountpoint(void)
537 511
538static void debugfs_mount(void) 512static void debugfs_mount(void)
539{ 513{
540 const char **ptr; 514 const char *const *ptr;
541 515
542 /* see if it's already mounted */ 516 /* see if it's already mounted */
543 if (debugfs_find_mountpoint()) 517 if (debugfs_find_mountpoint())
@@ -614,10 +588,10 @@ static int unpoison_page(unsigned long offset)
614 * page frame walker 588 * page frame walker
615 */ 589 */
616 590
617static int hash_slot(uint64_t flags) 591static size_t hash_slot(uint64_t flags)
618{ 592{
619 int k = HASH_KEY(flags); 593 size_t k = HASH_KEY(flags);
620 int i; 594 size_t i;
621 595
622 /* Explicitly reserve slot 0 for flags 0: the following logic 596 /* Explicitly reserve slot 0 for flags 0: the following logic
623 * cannot distinguish an unoccupied slot from slot (flags==0). 597 * cannot distinguish an unoccupied slot from slot (flags==0).
@@ -670,7 +644,7 @@ static void walk_pfn(unsigned long voffset,
670{ 644{
671 uint64_t buf[KPAGEFLAGS_BATCH]; 645 uint64_t buf[KPAGEFLAGS_BATCH];
672 unsigned long batch; 646 unsigned long batch;
673 long pages; 647 unsigned long pages;
674 unsigned long i; 648 unsigned long i;
675 649
676 while (count) { 650 while (count) {
@@ -779,7 +753,7 @@ static const char *page_flag_type(uint64_t flag)
779 753
780static void usage(void) 754static void usage(void)
781{ 755{
782 int i, j; 756 size_t i, j;
783 757
784 printf( 758 printf(
785"page-types [options]\n" 759"page-types [options]\n"
@@ -938,7 +912,7 @@ static void add_bits_filter(uint64_t mask, uint64_t bits)
938 912
939static uint64_t parse_flag_name(const char *str, int len) 913static uint64_t parse_flag_name(const char *str, int len)
940{ 914{
941 int i; 915 size_t i;
942 916
943 if (!*str || !len) 917 if (!*str || !len)
944 return 0; 918 return 0;