diff options
author | Ingo Molnar <mingo@kernel.org> | 2013-12-05 04:55:07 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2013-12-05 04:55:07 -0500 |
commit | 00f1762dcc43097b8f9c88d3a0aca7762da642d3 (patch) | |
tree | 37b2b61811c16f687a0af54ca54991503a07327f | |
parent | 89e3bbd58a6186b832fe2b9419ac2f9ab90e9089 (diff) | |
parent | 6d65894bc028d0342829ea1e64c9e9efad571124 (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
* Backport libtraceevent plugin support from trace-cmd repository, with
plugins for jbd2, hrtimer, kmem, kvm, mac80211, sched_switch, function,
xen, scsi, cfg80211. From Jiri Olsa.
* Retain bfd reference to lookup source line numbers, greatly optimizing, among
other use cases, 'perf report -s srcline', from Adrian Hunter.
* Do not disable source line lookup just because of one failure, from Adrian Hunter.
* Fix random fd closing with no libelf, from Adrian Hunter.
* Do not call perf_event__preprocess_sample() twice in 'perf script',
from Adrian Hunter.
* Several 'perf kvm' man page corrections, from Dongsheng Yang.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
42 files changed, 2305 insertions, 193 deletions
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index fc1502098595..0d9cbb426b44 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile | |||
@@ -43,6 +43,30 @@ man_dir_SQ = '$(subst ','\'',$(man_dir))' | |||
43 | export man_dir man_dir_SQ INSTALL | 43 | export man_dir man_dir_SQ INSTALL |
44 | export DESTDIR DESTDIR_SQ | 44 | export DESTDIR DESTDIR_SQ |
45 | 45 | ||
46 | set_plugin_dir := 1 | ||
47 | |||
48 | # Set plugin_dir to preffered global plugin location | ||
49 | # If we install under $HOME directory we go under | ||
50 | # $(HOME)/.traceevent/plugins | ||
51 | # | ||
52 | # We dont set PLUGIN_DIR in case we install under $HOME | ||
53 | # directory, because by default the code looks under: | ||
54 | # $(HOME)/.traceevent/plugins by default. | ||
55 | # | ||
56 | ifeq ($(plugin_dir),) | ||
57 | ifeq ($(prefix),$(HOME)) | ||
58 | override plugin_dir = $(HOME)/.traceevent/plugins | ||
59 | set_plugin_dir := 0 | ||
60 | else | ||
61 | override plugin_dir = $(prefix)/lib/traceevent/plugins | ||
62 | endif | ||
63 | endif | ||
64 | |||
65 | ifeq ($(set_plugin_dir),1) | ||
66 | PLUGIN_DIR = -DPLUGIN_DIR="$(DESTDIR)/$(plugin_dir)" | ||
67 | PLUGIN_DIR_SQ = '$(subst ','\'',$(PLUGIN_DIR))' | ||
68 | endif | ||
69 | |||
46 | # copy a bit from Linux kbuild | 70 | # copy a bit from Linux kbuild |
47 | 71 | ||
48 | ifeq ("$(origin V)", "command line") | 72 | ifeq ("$(origin V)", "command line") |
@@ -96,6 +120,7 @@ export prefix bindir src obj | |||
96 | # Shell quotes | 120 | # Shell quotes |
97 | bindir_SQ = $(subst ','\'',$(bindir)) | 121 | bindir_SQ = $(subst ','\'',$(bindir)) |
98 | bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) | 122 | bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) |
123 | plugin_dir_SQ = $(subst ','\'',$(plugin_dir)) | ||
99 | 124 | ||
100 | LIB_FILE = libtraceevent.a libtraceevent.so | 125 | LIB_FILE = libtraceevent.a libtraceevent.so |
101 | 126 | ||
@@ -138,10 +163,10 @@ else | |||
138 | print_app_build = echo ' BUILD '$(OBJ); | 163 | print_app_build = echo ' BUILD '$(OBJ); |
139 | print_fpic_compile = echo ' CC FPIC '$(OBJ); | 164 | print_fpic_compile = echo ' CC FPIC '$(OBJ); |
140 | print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ); | 165 | print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ); |
141 | print_plugin_obj_compile = echo ' BUILD PLUGIN OBJ '$(OBJ); | 166 | print_plugin_obj_compile = echo ' CC FPIC '$(OBJ); |
142 | print_plugin_build = echo ' BUILD PLUGIN '$(OBJ); | 167 | print_plugin_build = echo ' BUILD PLUGIN '$(OBJ); |
143 | print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ); | 168 | print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ); |
144 | print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2'; | 169 | print_install = echo ' INSTALL '$1; |
145 | endif | 170 | endif |
146 | 171 | ||
147 | do_fpic_compile = \ | 172 | do_fpic_compile = \ |
@@ -180,12 +205,29 @@ $(obj)/%.o: $(src)/%.c | |||
180 | %.o: $(src)/%.c | 205 | %.o: $(src)/%.c |
181 | $(Q)$(call do_compile) | 206 | $(Q)$(call do_compile) |
182 | 207 | ||
183 | PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o | 208 | PEVENT_LIB_OBJS = event-parse.o |
209 | PEVENT_LIB_OBJS += event-plugin.o | ||
210 | PEVENT_LIB_OBJS += trace-seq.o | ||
211 | PEVENT_LIB_OBJS += parse-filter.o | ||
212 | PEVENT_LIB_OBJS += parse-utils.o | ||
184 | PEVENT_LIB_OBJS += kbuffer-parse.o | 213 | PEVENT_LIB_OBJS += kbuffer-parse.o |
185 | 214 | ||
186 | ALL_OBJS = $(PEVENT_LIB_OBJS) | 215 | PLUGIN_OBJS = plugin_jbd2.o |
216 | PLUGIN_OBJS += plugin_hrtimer.o | ||
217 | PLUGIN_OBJS += plugin_kmem.o | ||
218 | PLUGIN_OBJS += plugin_kvm.o | ||
219 | PLUGIN_OBJS += plugin_mac80211.o | ||
220 | PLUGIN_OBJS += plugin_sched_switch.o | ||
221 | PLUGIN_OBJS += plugin_function.o | ||
222 | PLUGIN_OBJS += plugin_xen.o | ||
223 | PLUGIN_OBJS += plugin_scsi.o | ||
224 | PLUGIN_OBJS += plugin_cfg80211.o | ||
225 | |||
226 | PLUGINS := $(PLUGIN_OBJS:.o=.so) | ||
187 | 227 | ||
188 | CMD_TARGETS = $(LIB_FILE) | 228 | ALL_OBJS = $(PEVENT_LIB_OBJS) $(PLUGIN_OBJS) |
229 | |||
230 | CMD_TARGETS = $(LIB_FILE) $(PLUGINS) | ||
189 | 231 | ||
190 | TARGETS = $(CMD_TARGETS) | 232 | TARGETS = $(CMD_TARGETS) |
191 | 233 | ||
@@ -200,9 +242,17 @@ libtraceevent.so: $(PEVENT_LIB_OBJS) | |||
200 | libtraceevent.a: $(PEVENT_LIB_OBJS) | 242 | libtraceevent.a: $(PEVENT_LIB_OBJS) |
201 | $(Q)$(do_build_static_lib) | 243 | $(Q)$(do_build_static_lib) |
202 | 244 | ||
245 | plugins: $(PLUGINS) | ||
246 | |||
203 | $(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS | 247 | $(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS |
204 | $(Q)$(do_fpic_compile) | 248 | $(Q)$(do_fpic_compile) |
205 | 249 | ||
250 | $(PLUGIN_OBJS): %.o : $(src)/%.c | ||
251 | $(Q)$(do_compile_plugin_obj) | ||
252 | |||
253 | $(PLUGINS): %.so: %.o | ||
254 | $(Q)$(do_plugin_build) | ||
255 | |||
206 | define make_version.h | 256 | define make_version.h |
207 | (echo '/* This file is automatically generated. Do not modify. */'; \ | 257 | (echo '/* This file is automatically generated. Do not modify. */'; \ |
208 | echo \#define VERSION_CODE $(shell \ | 258 | echo \#define VERSION_CODE $(shell \ |
@@ -290,9 +340,16 @@ define do_install | |||
290 | $(INSTALL) $1 '$(DESTDIR_SQ)$2' | 340 | $(INSTALL) $1 '$(DESTDIR_SQ)$2' |
291 | endef | 341 | endef |
292 | 342 | ||
293 | install_lib: all_cmd | 343 | install_lib: all_cmd install_plugins |
294 | $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ)) | 344 | $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ)) |
295 | 345 | ||
346 | PLUGINS_INSTALL = $(subst .so,.install,$(PLUGINS)) | ||
347 | |||
348 | $(PLUGINS_INSTALL): %.install : %.so force | ||
349 | $(Q)$(call do_install,$<,$(plugin_dir_SQ)) | ||
350 | |||
351 | install_plugins: $(PLUGINS_INSTALL) | ||
352 | |||
296 | install: install_lib | 353 | install: install_lib |
297 | 354 | ||
298 | clean: | 355 | clean: |
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 900fca01bdd3..9849873265d4 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
@@ -5121,8 +5121,38 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, | |||
5121 | return ret; | 5121 | return ret; |
5122 | } | 5122 | } |
5123 | 5123 | ||
5124 | static enum pevent_errno | ||
5125 | __pevent_parse_event(struct pevent *pevent, | ||
5126 | struct event_format **eventp, | ||
5127 | const char *buf, unsigned long size, | ||
5128 | const char *sys) | ||
5129 | { | ||
5130 | int ret = __pevent_parse_format(eventp, pevent, buf, size, sys); | ||
5131 | struct event_format *event = *eventp; | ||
5132 | |||
5133 | if (event == NULL) | ||
5134 | return ret; | ||
5135 | |||
5136 | if (pevent && add_event(pevent, event)) { | ||
5137 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
5138 | goto event_add_failed; | ||
5139 | } | ||
5140 | |||
5141 | #define PRINT_ARGS 0 | ||
5142 | if (PRINT_ARGS && event->print_fmt.args) | ||
5143 | print_args(event->print_fmt.args); | ||
5144 | |||
5145 | return 0; | ||
5146 | |||
5147 | event_add_failed: | ||
5148 | pevent_free_format(event); | ||
5149 | return ret; | ||
5150 | } | ||
5151 | |||
5124 | /** | 5152 | /** |
5125 | * pevent_parse_format - parse the event format | 5153 | * pevent_parse_format - parse the event format |
5154 | * @pevent: the handle to the pevent | ||
5155 | * @eventp: returned format | ||
5126 | * @buf: the buffer storing the event format string | 5156 | * @buf: the buffer storing the event format string |
5127 | * @size: the size of @buf | 5157 | * @size: the size of @buf |
5128 | * @sys: the system the event belongs to | 5158 | * @sys: the system the event belongs to |
@@ -5134,10 +5164,12 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, | |||
5134 | * | 5164 | * |
5135 | * /sys/kernel/debug/tracing/events/.../.../format | 5165 | * /sys/kernel/debug/tracing/events/.../.../format |
5136 | */ | 5166 | */ |
5137 | enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf, | 5167 | enum pevent_errno pevent_parse_format(struct pevent *pevent, |
5168 | struct event_format **eventp, | ||
5169 | const char *buf, | ||
5138 | unsigned long size, const char *sys) | 5170 | unsigned long size, const char *sys) |
5139 | { | 5171 | { |
5140 | return __pevent_parse_format(eventp, NULL, buf, size, sys); | 5172 | return __pevent_parse_event(pevent, eventp, buf, size, sys); |
5141 | } | 5173 | } |
5142 | 5174 | ||
5143 | /** | 5175 | /** |
@@ -5158,25 +5190,7 @@ enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, | |||
5158 | unsigned long size, const char *sys) | 5190 | unsigned long size, const char *sys) |
5159 | { | 5191 | { |
5160 | struct event_format *event = NULL; | 5192 | struct event_format *event = NULL; |
5161 | int ret = __pevent_parse_format(&event, pevent, buf, size, sys); | 5193 | return __pevent_parse_event(pevent, &event, buf, size, sys); |
5162 | |||
5163 | if (event == NULL) | ||
5164 | return ret; | ||
5165 | |||
5166 | if (add_event(pevent, event)) { | ||
5167 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
5168 | goto event_add_failed; | ||
5169 | } | ||
5170 | |||
5171 | #define PRINT_ARGS 0 | ||
5172 | if (PRINT_ARGS && event->print_fmt.args) | ||
5173 | print_args(event->print_fmt.args); | ||
5174 | |||
5175 | return 0; | ||
5176 | |||
5177 | event_add_failed: | ||
5178 | pevent_free_format(event); | ||
5179 | return ret; | ||
5180 | } | 5194 | } |
5181 | 5195 | ||
5182 | #undef _PE | 5196 | #undef _PE |
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 8d73d2594f65..620c27a72960 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <stdbool.h> | 23 | #include <stdbool.h> |
24 | #include <stdarg.h> | 24 | #include <stdarg.h> |
25 | #include <regex.h> | 25 | #include <regex.h> |
26 | #include <string.h> | ||
26 | 27 | ||
27 | #ifndef __maybe_unused | 28 | #ifndef __maybe_unused |
28 | #define __maybe_unused __attribute__((unused)) | 29 | #define __maybe_unused __attribute__((unused)) |
@@ -377,6 +378,11 @@ enum pevent_errno { | |||
377 | }; | 378 | }; |
378 | #undef _PE | 379 | #undef _PE |
379 | 380 | ||
381 | struct plugin_list; | ||
382 | |||
383 | struct plugin_list *traceevent_load_plugins(struct pevent *pevent); | ||
384 | void traceevent_unload_plugins(struct plugin_list *plugin_list); | ||
385 | |||
380 | struct cmdline; | 386 | struct cmdline; |
381 | struct cmdline_list; | 387 | struct cmdline_list; |
382 | struct func_map; | 388 | struct func_map; |
@@ -522,6 +528,15 @@ __data2host8(struct pevent *pevent, unsigned long long data) | |||
522 | __data2host8(pevent, __val); \ | 528 | __data2host8(pevent, __val); \ |
523 | }) | 529 | }) |
524 | 530 | ||
531 | static inline int traceevent_host_bigendian(void) | ||
532 | { | ||
533 | unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 }; | ||
534 | unsigned int val; | ||
535 | |||
536 | memcpy(&val, str, 4); | ||
537 | return val == 0x01020304; | ||
538 | } | ||
539 | |||
525 | /* taken from kernel/trace/trace.h */ | 540 | /* taken from kernel/trace/trace.h */ |
526 | enum trace_flag_type { | 541 | enum trace_flag_type { |
527 | TRACE_FLAG_IRQS_OFF = 0x01, | 542 | TRACE_FLAG_IRQS_OFF = 0x01, |
@@ -547,7 +562,9 @@ int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long siz | |||
547 | 562 | ||
548 | enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, | 563 | enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, |
549 | unsigned long size, const char *sys); | 564 | unsigned long size, const char *sys); |
550 | enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf, | 565 | enum pevent_errno pevent_parse_format(struct pevent *pevent, |
566 | struct event_format **eventp, | ||
567 | const char *buf, | ||
551 | unsigned long size, const char *sys); | 568 | unsigned long size, const char *sys); |
552 | void pevent_free_format(struct event_format *event); | 569 | void pevent_free_format(struct event_format *event); |
553 | 570 | ||
diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c new file mode 100644 index 000000000000..125f5676bcb5 --- /dev/null +++ b/tools/lib/traceevent/event-plugin.c | |||
@@ -0,0 +1,215 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * version 2.1 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
17 | * | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
19 | */ | ||
20 | |||
21 | #include <string.h> | ||
22 | #include <dlfcn.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <sys/types.h> | ||
25 | #include <sys/stat.h> | ||
26 | #include <unistd.h> | ||
27 | #include <dirent.h> | ||
28 | #include "event-parse.h" | ||
29 | #include "event-utils.h" | ||
30 | |||
31 | #define LOCAL_PLUGIN_DIR ".traceevent/plugins" | ||
32 | |||
33 | struct plugin_list { | ||
34 | struct plugin_list *next; | ||
35 | char *name; | ||
36 | void *handle; | ||
37 | }; | ||
38 | |||
39 | static void | ||
40 | load_plugin(struct pevent *pevent, const char *path, | ||
41 | const char *file, void *data) | ||
42 | { | ||
43 | struct plugin_list **plugin_list = data; | ||
44 | pevent_plugin_load_func func; | ||
45 | struct plugin_list *list; | ||
46 | const char *alias; | ||
47 | char *plugin; | ||
48 | void *handle; | ||
49 | |||
50 | plugin = malloc(strlen(path) + strlen(file) + 2); | ||
51 | if (!plugin) { | ||
52 | warning("could not allocate plugin memory\n"); | ||
53 | return; | ||
54 | } | ||
55 | |||
56 | strcpy(plugin, path); | ||
57 | strcat(plugin, "/"); | ||
58 | strcat(plugin, file); | ||
59 | |||
60 | handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL); | ||
61 | if (!handle) { | ||
62 | warning("could not load plugin '%s'\n%s\n", | ||
63 | plugin, dlerror()); | ||
64 | goto out_free; | ||
65 | } | ||
66 | |||
67 | alias = dlsym(handle, PEVENT_PLUGIN_ALIAS_NAME); | ||
68 | if (!alias) | ||
69 | alias = file; | ||
70 | |||
71 | func = dlsym(handle, PEVENT_PLUGIN_LOADER_NAME); | ||
72 | if (!func) { | ||
73 | warning("could not find func '%s' in plugin '%s'\n%s\n", | ||
74 | PEVENT_PLUGIN_LOADER_NAME, plugin, dlerror()); | ||
75 | goto out_free; | ||
76 | } | ||
77 | |||
78 | list = malloc(sizeof(*list)); | ||
79 | if (!list) { | ||
80 | warning("could not allocate plugin memory\n"); | ||
81 | goto out_free; | ||
82 | } | ||
83 | |||
84 | list->next = *plugin_list; | ||
85 | list->handle = handle; | ||
86 | list->name = plugin; | ||
87 | *plugin_list = list; | ||
88 | |||
89 | pr_stat("registering plugin: %s", plugin); | ||
90 | func(pevent); | ||
91 | return; | ||
92 | |||
93 | out_free: | ||
94 | free(plugin); | ||
95 | } | ||
96 | |||
97 | static void | ||
98 | load_plugins_dir(struct pevent *pevent, const char *suffix, | ||
99 | const char *path, | ||
100 | void (*load_plugin)(struct pevent *pevent, | ||
101 | const char *path, | ||
102 | const char *name, | ||
103 | void *data), | ||
104 | void *data) | ||
105 | { | ||
106 | struct dirent *dent; | ||
107 | struct stat st; | ||
108 | DIR *dir; | ||
109 | int ret; | ||
110 | |||
111 | ret = stat(path, &st); | ||
112 | if (ret < 0) | ||
113 | return; | ||
114 | |||
115 | if (!S_ISDIR(st.st_mode)) | ||
116 | return; | ||
117 | |||
118 | dir = opendir(path); | ||
119 | if (!dir) | ||
120 | return; | ||
121 | |||
122 | while ((dent = readdir(dir))) { | ||
123 | const char *name = dent->d_name; | ||
124 | |||
125 | if (strcmp(name, ".") == 0 || | ||
126 | strcmp(name, "..") == 0) | ||
127 | continue; | ||
128 | |||
129 | /* Only load plugins that end in suffix */ | ||
130 | if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0) | ||
131 | continue; | ||
132 | |||
133 | load_plugin(pevent, path, name, data); | ||
134 | } | ||
135 | |||
136 | closedir(dir); | ||
137 | } | ||
138 | |||
139 | static void | ||
140 | load_plugins(struct pevent *pevent, const char *suffix, | ||
141 | void (*load_plugin)(struct pevent *pevent, | ||
142 | const char *path, | ||
143 | const char *name, | ||
144 | void *data), | ||
145 | void *data) | ||
146 | { | ||
147 | char *home; | ||
148 | char *path; | ||
149 | char *envdir; | ||
150 | |||
151 | /* | ||
152 | * If a system plugin directory was defined, | ||
153 | * check that first. | ||
154 | */ | ||
155 | #ifdef PLUGIN_DIR | ||
156 | load_plugins_dir(pevent, suffix, PLUGIN_DIR, load_plugin, data); | ||
157 | #endif | ||
158 | |||
159 | /* | ||
160 | * Next let the environment-set plugin directory | ||
161 | * override the system defaults. | ||
162 | */ | ||
163 | envdir = getenv("TRACEEVENT_PLUGIN_DIR"); | ||
164 | if (envdir) | ||
165 | load_plugins_dir(pevent, suffix, envdir, load_plugin, data); | ||
166 | |||
167 | /* | ||
168 | * Now let the home directory override the environment | ||
169 | * or system defaults. | ||
170 | */ | ||
171 | home = getenv("HOME"); | ||
172 | if (!home) | ||
173 | return; | ||
174 | |||
175 | path = malloc(strlen(home) + strlen(LOCAL_PLUGIN_DIR) + 2); | ||
176 | if (!path) { | ||
177 | warning("could not allocate plugin memory\n"); | ||
178 | return; | ||
179 | } | ||
180 | |||
181 | strcpy(path, home); | ||
182 | strcat(path, "/"); | ||
183 | strcat(path, LOCAL_PLUGIN_DIR); | ||
184 | |||
185 | load_plugins_dir(pevent, suffix, path, load_plugin, data); | ||
186 | |||
187 | free(path); | ||
188 | } | ||
189 | |||
190 | struct plugin_list* | ||
191 | traceevent_load_plugins(struct pevent *pevent) | ||
192 | { | ||
193 | struct plugin_list *list = NULL; | ||
194 | |||
195 | load_plugins(pevent, ".so", load_plugin, &list); | ||
196 | return list; | ||
197 | } | ||
198 | |||
199 | void | ||
200 | traceevent_unload_plugins(struct plugin_list *plugin_list) | ||
201 | { | ||
202 | pevent_plugin_unload_func func; | ||
203 | struct plugin_list *list; | ||
204 | |||
205 | while (plugin_list) { | ||
206 | list = plugin_list; | ||
207 | plugin_list = list->next; | ||
208 | func = dlsym(list->handle, PEVENT_PLUGIN_UNLOADER_NAME); | ||
209 | if (func) | ||
210 | func(); | ||
211 | dlclose(list->handle); | ||
212 | free(list->name); | ||
213 | free(list); | ||
214 | } | ||
215 | } | ||
diff --git a/tools/lib/traceevent/plugin_cfg80211.c b/tools/lib/traceevent/plugin_cfg80211.c new file mode 100644 index 000000000000..dcab8e873c21 --- /dev/null +++ b/tools/lib/traceevent/plugin_cfg80211.c | |||
@@ -0,0 +1,24 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <string.h> | ||
3 | #include <inttypes.h> | ||
4 | #include <endian.h> | ||
5 | #include "event-parse.h" | ||
6 | |||
7 | static unsigned long long | ||
8 | process___le16_to_cpup(struct trace_seq *s, | ||
9 | unsigned long long *args) | ||
10 | { | ||
11 | uint16_t *val = (uint16_t *) args[0]; | ||
12 | return val ? (long long) le16toh(*val) : 0; | ||
13 | } | ||
14 | |||
15 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
16 | { | ||
17 | pevent_register_print_function(pevent, | ||
18 | process___le16_to_cpup, | ||
19 | PEVENT_FUNC_ARG_INT, | ||
20 | "__le16_to_cpup", | ||
21 | PEVENT_FUNC_ARG_PTR, | ||
22 | PEVENT_FUNC_ARG_VOID); | ||
23 | return 0; | ||
24 | } | ||
diff --git a/tools/lib/traceevent/plugin_function.c b/tools/lib/traceevent/plugin_function.c new file mode 100644 index 000000000000..aad92ad5e96f --- /dev/null +++ b/tools/lib/traceevent/plugin_function.c | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * version 2.1 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
17 | * | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
19 | */ | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | |||
24 | #include "event-parse.h" | ||
25 | #include "event-utils.h" | ||
26 | |||
27 | static struct func_stack { | ||
28 | int size; | ||
29 | char **stack; | ||
30 | } *fstack; | ||
31 | |||
32 | static int cpus = -1; | ||
33 | |||
34 | #define STK_BLK 10 | ||
35 | |||
36 | static void add_child(struct func_stack *stack, const char *child, int pos) | ||
37 | { | ||
38 | int i; | ||
39 | |||
40 | if (!child) | ||
41 | return; | ||
42 | |||
43 | if (pos < stack->size) | ||
44 | free(stack->stack[pos]); | ||
45 | else { | ||
46 | char **ptr; | ||
47 | |||
48 | ptr = realloc(stack->stack, sizeof(char *) * | ||
49 | (stack->size + STK_BLK)); | ||
50 | if (!ptr) { | ||
51 | warning("could not allocate plugin memory\n"); | ||
52 | return; | ||
53 | } | ||
54 | |||
55 | stack->stack = ptr; | ||
56 | |||
57 | for (i = stack->size; i < stack->size + STK_BLK; i++) | ||
58 | stack->stack[i] = NULL; | ||
59 | stack->size += STK_BLK; | ||
60 | } | ||
61 | |||
62 | stack->stack[pos] = strdup(child); | ||
63 | } | ||
64 | |||
65 | static int add_and_get_index(const char *parent, const char *child, int cpu) | ||
66 | { | ||
67 | int i; | ||
68 | |||
69 | if (cpu < 0) | ||
70 | return 0; | ||
71 | |||
72 | if (cpu > cpus) { | ||
73 | struct func_stack *ptr; | ||
74 | |||
75 | ptr = realloc(fstack, sizeof(*fstack) * (cpu + 1)); | ||
76 | if (!ptr) { | ||
77 | warning("could not allocate plugin memory\n"); | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | fstack = ptr; | ||
82 | |||
83 | /* Account for holes in the cpu count */ | ||
84 | for (i = cpus + 1; i <= cpu; i++) | ||
85 | memset(&fstack[i], 0, sizeof(fstack[i])); | ||
86 | cpus = cpu; | ||
87 | } | ||
88 | |||
89 | for (i = 0; i < fstack[cpu].size && fstack[cpu].stack[i]; i++) { | ||
90 | if (strcmp(parent, fstack[cpu].stack[i]) == 0) { | ||
91 | add_child(&fstack[cpu], child, i+1); | ||
92 | return i; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | /* Not found */ | ||
97 | add_child(&fstack[cpu], parent, 0); | ||
98 | add_child(&fstack[cpu], child, 1); | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int function_handler(struct trace_seq *s, struct pevent_record *record, | ||
103 | struct event_format *event, void *context) | ||
104 | { | ||
105 | struct pevent *pevent = event->pevent; | ||
106 | unsigned long long function; | ||
107 | unsigned long long pfunction; | ||
108 | const char *func; | ||
109 | const char *parent; | ||
110 | int index; | ||
111 | |||
112 | if (pevent_get_field_val(s, event, "ip", record, &function, 1)) | ||
113 | return trace_seq_putc(s, '!'); | ||
114 | |||
115 | func = pevent_find_function(pevent, function); | ||
116 | |||
117 | if (pevent_get_field_val(s, event, "parent_ip", record, &pfunction, 1)) | ||
118 | return trace_seq_putc(s, '!'); | ||
119 | |||
120 | parent = pevent_find_function(pevent, pfunction); | ||
121 | |||
122 | index = add_and_get_index(parent, func, record->cpu); | ||
123 | |||
124 | trace_seq_printf(s, "%*s", index*3, ""); | ||
125 | |||
126 | if (func) | ||
127 | trace_seq_printf(s, "%s", func); | ||
128 | else | ||
129 | trace_seq_printf(s, "0x%llx", function); | ||
130 | |||
131 | trace_seq_printf(s, " <-- "); | ||
132 | if (parent) | ||
133 | trace_seq_printf(s, "%s", parent); | ||
134 | else | ||
135 | trace_seq_printf(s, "0x%llx", pfunction); | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
141 | { | ||
142 | pevent_register_event_handler(pevent, -1, "ftrace", "function", | ||
143 | function_handler, NULL); | ||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | void PEVENT_PLUGIN_UNLOADER(void) | ||
148 | { | ||
149 | int i, x; | ||
150 | |||
151 | for (i = 0; i <= cpus; i++) { | ||
152 | for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++) | ||
153 | free(fstack[i].stack[x]); | ||
154 | free(fstack[i].stack); | ||
155 | } | ||
156 | |||
157 | free(fstack); | ||
158 | fstack = NULL; | ||
159 | cpus = -1; | ||
160 | } | ||
diff --git a/tools/lib/traceevent/plugin_hrtimer.c b/tools/lib/traceevent/plugin_hrtimer.c new file mode 100644 index 000000000000..0b0ebf30aa44 --- /dev/null +++ b/tools/lib/traceevent/plugin_hrtimer.c | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * Copyright (C) 2009 Johannes Berg <johannes@sipsolutions.net> | ||
4 | * | ||
5 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU Lesser General Public | ||
8 | * License as published by the Free Software Foundation; | ||
9 | * version 2.1 of the License (not later!) | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU Lesser General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU Lesser General Public | ||
17 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
18 | * | ||
19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
20 | */ | ||
21 | #include <stdio.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <string.h> | ||
24 | |||
25 | #include "event-parse.h" | ||
26 | |||
27 | static int timer_expire_handler(struct trace_seq *s, | ||
28 | struct pevent_record *record, | ||
29 | struct event_format *event, void *context) | ||
30 | { | ||
31 | trace_seq_printf(s, "hrtimer="); | ||
32 | |||
33 | if (pevent_print_num_field(s, "0x%llx", event, "timer", | ||
34 | record, 0) == -1) | ||
35 | pevent_print_num_field(s, "0x%llx", event, "hrtimer", | ||
36 | record, 1); | ||
37 | |||
38 | trace_seq_printf(s, " now="); | ||
39 | |||
40 | pevent_print_num_field(s, "%llu", event, "now", record, 1); | ||
41 | |||
42 | pevent_print_func_field(s, " function=%s", event, "function", | ||
43 | record, 0); | ||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | static int timer_start_handler(struct trace_seq *s, | ||
48 | struct pevent_record *record, | ||
49 | struct event_format *event, void *context) | ||
50 | { | ||
51 | trace_seq_printf(s, "hrtimer="); | ||
52 | |||
53 | if (pevent_print_num_field(s, "0x%llx", event, "timer", | ||
54 | record, 0) == -1) | ||
55 | pevent_print_num_field(s, "0x%llx", event, "hrtimer", | ||
56 | record, 1); | ||
57 | |||
58 | pevent_print_func_field(s, " function=%s", event, "function", | ||
59 | record, 0); | ||
60 | |||
61 | trace_seq_printf(s, " expires="); | ||
62 | pevent_print_num_field(s, "%llu", event, "expires", record, 1); | ||
63 | |||
64 | trace_seq_printf(s, " softexpires="); | ||
65 | pevent_print_num_field(s, "%llu", event, "softexpires", record, 1); | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
70 | { | ||
71 | pevent_register_event_handler(pevent, -1, | ||
72 | "timer", "hrtimer_expire_entry", | ||
73 | timer_expire_handler, NULL); | ||
74 | |||
75 | pevent_register_event_handler(pevent, -1, "timer", "hrtimer_start", | ||
76 | timer_start_handler, NULL); | ||
77 | return 0; | ||
78 | } | ||
diff --git a/tools/lib/traceevent/plugin_jbd2.c b/tools/lib/traceevent/plugin_jbd2.c new file mode 100644 index 000000000000..2f93f81f0bac --- /dev/null +++ b/tools/lib/traceevent/plugin_jbd2.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * version 2.1 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
17 | * | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
19 | */ | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | |||
24 | #include "event-parse.h" | ||
25 | |||
26 | #define MINORBITS 20 | ||
27 | #define MINORMASK ((1U << MINORBITS) - 1) | ||
28 | |||
29 | #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) | ||
30 | #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) | ||
31 | |||
32 | static unsigned long long | ||
33 | process_jbd2_dev_to_name(struct trace_seq *s, | ||
34 | unsigned long long *args) | ||
35 | { | ||
36 | unsigned int dev = args[0]; | ||
37 | |||
38 | trace_seq_printf(s, "%d:%d", MAJOR(dev), MINOR(dev)); | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static unsigned long long | ||
43 | process_jiffies_to_msecs(struct trace_seq *s, | ||
44 | unsigned long long *args) | ||
45 | { | ||
46 | unsigned long long jiffies = args[0]; | ||
47 | |||
48 | trace_seq_printf(s, "%lld", jiffies); | ||
49 | return jiffies; | ||
50 | } | ||
51 | |||
52 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
53 | { | ||
54 | pevent_register_print_function(pevent, | ||
55 | process_jbd2_dev_to_name, | ||
56 | PEVENT_FUNC_ARG_STRING, | ||
57 | "jbd2_dev_to_name", | ||
58 | PEVENT_FUNC_ARG_INT, | ||
59 | PEVENT_FUNC_ARG_VOID); | ||
60 | |||
61 | pevent_register_print_function(pevent, | ||
62 | process_jiffies_to_msecs, | ||
63 | PEVENT_FUNC_ARG_LONG, | ||
64 | "jiffies_to_msecs", | ||
65 | PEVENT_FUNC_ARG_LONG, | ||
66 | PEVENT_FUNC_ARG_VOID); | ||
67 | return 0; | ||
68 | } | ||
diff --git a/tools/lib/traceevent/plugin_kmem.c b/tools/lib/traceevent/plugin_kmem.c new file mode 100644 index 000000000000..7115c8037ea8 --- /dev/null +++ b/tools/lib/traceevent/plugin_kmem.c | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * version 2.1 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
17 | * | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
19 | */ | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | |||
24 | #include "event-parse.h" | ||
25 | |||
26 | static int call_site_handler(struct trace_seq *s, struct pevent_record *record, | ||
27 | struct event_format *event, void *context) | ||
28 | { | ||
29 | struct format_field *field; | ||
30 | unsigned long long val, addr; | ||
31 | void *data = record->data; | ||
32 | const char *func; | ||
33 | |||
34 | field = pevent_find_field(event, "call_site"); | ||
35 | if (!field) | ||
36 | return 1; | ||
37 | |||
38 | if (pevent_read_number_field(field, data, &val)) | ||
39 | return 1; | ||
40 | |||
41 | func = pevent_find_function(event->pevent, val); | ||
42 | if (!func) | ||
43 | return 1; | ||
44 | |||
45 | addr = pevent_find_function_address(event->pevent, val); | ||
46 | |||
47 | trace_seq_printf(s, "(%s+0x%x) ", func, (int)(val - addr)); | ||
48 | return 1; | ||
49 | } | ||
50 | |||
51 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
52 | { | ||
53 | pevent_register_event_handler(pevent, -1, "kmem", "kfree", | ||
54 | call_site_handler, NULL); | ||
55 | |||
56 | pevent_register_event_handler(pevent, -1, "kmem", "kmalloc", | ||
57 | call_site_handler, NULL); | ||
58 | |||
59 | pevent_register_event_handler(pevent, -1, "kmem", "kmalloc_node", | ||
60 | call_site_handler, NULL); | ||
61 | |||
62 | pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_alloc", | ||
63 | call_site_handler, NULL); | ||
64 | |||
65 | pevent_register_event_handler(pevent, -1, "kmem", | ||
66 | "kmem_cache_alloc_node", | ||
67 | call_site_handler, NULL); | ||
68 | |||
69 | pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_free", | ||
70 | call_site_handler, NULL); | ||
71 | return 0; | ||
72 | } | ||
diff --git a/tools/lib/traceevent/plugin_kvm.c b/tools/lib/traceevent/plugin_kvm.c new file mode 100644 index 000000000000..a0e282c6b967 --- /dev/null +++ b/tools/lib/traceevent/plugin_kvm.c | |||
@@ -0,0 +1,436 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * version 2.1 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
17 | * | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
19 | */ | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include <stdint.h> | ||
24 | |||
25 | #include "event-parse.h" | ||
26 | |||
27 | #ifdef HAVE_UDIS86 | ||
28 | |||
29 | #include <udis86.h> | ||
30 | |||
31 | static ud_t ud; | ||
32 | |||
33 | static void init_disassembler(void) | ||
34 | { | ||
35 | ud_init(&ud); | ||
36 | ud_set_syntax(&ud, UD_SYN_ATT); | ||
37 | } | ||
38 | |||
39 | static const char *disassemble(unsigned char *insn, int len, uint64_t rip, | ||
40 | int cr0_pe, int eflags_vm, | ||
41 | int cs_d, int cs_l) | ||
42 | { | ||
43 | int mode; | ||
44 | |||
45 | if (!cr0_pe) | ||
46 | mode = 16; | ||
47 | else if (eflags_vm) | ||
48 | mode = 16; | ||
49 | else if (cs_l) | ||
50 | mode = 64; | ||
51 | else if (cs_d) | ||
52 | mode = 32; | ||
53 | else | ||
54 | mode = 16; | ||
55 | |||
56 | ud_set_pc(&ud, rip); | ||
57 | ud_set_mode(&ud, mode); | ||
58 | ud_set_input_buffer(&ud, insn, len); | ||
59 | ud_disassemble(&ud); | ||
60 | return ud_insn_asm(&ud); | ||
61 | } | ||
62 | |||
63 | #else | ||
64 | |||
65 | static void init_disassembler(void) | ||
66 | { | ||
67 | } | ||
68 | |||
69 | static const char *disassemble(unsigned char *insn, int len, uint64_t rip, | ||
70 | int cr0_pe, int eflags_vm, | ||
71 | int cs_d, int cs_l) | ||
72 | { | ||
73 | static char out[15*3+1]; | ||
74 | int i; | ||
75 | |||
76 | for (i = 0; i < len; ++i) | ||
77 | sprintf(out + i * 3, "%02x ", insn[i]); | ||
78 | out[len*3-1] = '\0'; | ||
79 | return out; | ||
80 | } | ||
81 | |||
82 | #endif | ||
83 | |||
84 | |||
85 | #define VMX_EXIT_REASONS \ | ||
86 | _ER(EXCEPTION_NMI, 0) \ | ||
87 | _ER(EXTERNAL_INTERRUPT, 1) \ | ||
88 | _ER(TRIPLE_FAULT, 2) \ | ||
89 | _ER(PENDING_INTERRUPT, 7) \ | ||
90 | _ER(NMI_WINDOW, 8) \ | ||
91 | _ER(TASK_SWITCH, 9) \ | ||
92 | _ER(CPUID, 10) \ | ||
93 | _ER(HLT, 12) \ | ||
94 | _ER(INVD, 13) \ | ||
95 | _ER(INVLPG, 14) \ | ||
96 | _ER(RDPMC, 15) \ | ||
97 | _ER(RDTSC, 16) \ | ||
98 | _ER(VMCALL, 18) \ | ||
99 | _ER(VMCLEAR, 19) \ | ||
100 | _ER(VMLAUNCH, 20) \ | ||
101 | _ER(VMPTRLD, 21) \ | ||
102 | _ER(VMPTRST, 22) \ | ||
103 | _ER(VMREAD, 23) \ | ||
104 | _ER(VMRESUME, 24) \ | ||
105 | _ER(VMWRITE, 25) \ | ||
106 | _ER(VMOFF, 26) \ | ||
107 | _ER(VMON, 27) \ | ||
108 | _ER(CR_ACCESS, 28) \ | ||
109 | _ER(DR_ACCESS, 29) \ | ||
110 | _ER(IO_INSTRUCTION, 30) \ | ||
111 | _ER(MSR_READ, 31) \ | ||
112 | _ER(MSR_WRITE, 32) \ | ||
113 | _ER(MWAIT_INSTRUCTION, 36) \ | ||
114 | _ER(MONITOR_INSTRUCTION, 39) \ | ||
115 | _ER(PAUSE_INSTRUCTION, 40) \ | ||
116 | _ER(MCE_DURING_VMENTRY, 41) \ | ||
117 | _ER(TPR_BELOW_THRESHOLD, 43) \ | ||
118 | _ER(APIC_ACCESS, 44) \ | ||
119 | _ER(EOI_INDUCED, 45) \ | ||
120 | _ER(EPT_VIOLATION, 48) \ | ||
121 | _ER(EPT_MISCONFIG, 49) \ | ||
122 | _ER(INVEPT, 50) \ | ||
123 | _ER(PREEMPTION_TIMER, 52) \ | ||
124 | _ER(WBINVD, 54) \ | ||
125 | _ER(XSETBV, 55) \ | ||
126 | _ER(APIC_WRITE, 56) \ | ||
127 | _ER(INVPCID, 58) | ||
128 | |||
129 | #define SVM_EXIT_REASONS \ | ||
130 | _ER(EXIT_READ_CR0, 0x000) \ | ||
131 | _ER(EXIT_READ_CR3, 0x003) \ | ||
132 | _ER(EXIT_READ_CR4, 0x004) \ | ||
133 | _ER(EXIT_READ_CR8, 0x008) \ | ||
134 | _ER(EXIT_WRITE_CR0, 0x010) \ | ||
135 | _ER(EXIT_WRITE_CR3, 0x013) \ | ||
136 | _ER(EXIT_WRITE_CR4, 0x014) \ | ||
137 | _ER(EXIT_WRITE_CR8, 0x018) \ | ||
138 | _ER(EXIT_READ_DR0, 0x020) \ | ||
139 | _ER(EXIT_READ_DR1, 0x021) \ | ||
140 | _ER(EXIT_READ_DR2, 0x022) \ | ||
141 | _ER(EXIT_READ_DR3, 0x023) \ | ||
142 | _ER(EXIT_READ_DR4, 0x024) \ | ||
143 | _ER(EXIT_READ_DR5, 0x025) \ | ||
144 | _ER(EXIT_READ_DR6, 0x026) \ | ||
145 | _ER(EXIT_READ_DR7, 0x027) \ | ||
146 | _ER(EXIT_WRITE_DR0, 0x030) \ | ||
147 | _ER(EXIT_WRITE_DR1, 0x031) \ | ||
148 | _ER(EXIT_WRITE_DR2, 0x032) \ | ||
149 | _ER(EXIT_WRITE_DR3, 0x033) \ | ||
150 | _ER(EXIT_WRITE_DR4, 0x034) \ | ||
151 | _ER(EXIT_WRITE_DR5, 0x035) \ | ||
152 | _ER(EXIT_WRITE_DR6, 0x036) \ | ||
153 | _ER(EXIT_WRITE_DR7, 0x037) \ | ||
154 | _ER(EXIT_EXCP_BASE, 0x040) \ | ||
155 | _ER(EXIT_INTR, 0x060) \ | ||
156 | _ER(EXIT_NMI, 0x061) \ | ||
157 | _ER(EXIT_SMI, 0x062) \ | ||
158 | _ER(EXIT_INIT, 0x063) \ | ||
159 | _ER(EXIT_VINTR, 0x064) \ | ||
160 | _ER(EXIT_CR0_SEL_WRITE, 0x065) \ | ||
161 | _ER(EXIT_IDTR_READ, 0x066) \ | ||
162 | _ER(EXIT_GDTR_READ, 0x067) \ | ||
163 | _ER(EXIT_LDTR_READ, 0x068) \ | ||
164 | _ER(EXIT_TR_READ, 0x069) \ | ||
165 | _ER(EXIT_IDTR_WRITE, 0x06a) \ | ||
166 | _ER(EXIT_GDTR_WRITE, 0x06b) \ | ||
167 | _ER(EXIT_LDTR_WRITE, 0x06c) \ | ||
168 | _ER(EXIT_TR_WRITE, 0x06d) \ | ||
169 | _ER(EXIT_RDTSC, 0x06e) \ | ||
170 | _ER(EXIT_RDPMC, 0x06f) \ | ||
171 | _ER(EXIT_PUSHF, 0x070) \ | ||
172 | _ER(EXIT_POPF, 0x071) \ | ||
173 | _ER(EXIT_CPUID, 0x072) \ | ||
174 | _ER(EXIT_RSM, 0x073) \ | ||
175 | _ER(EXIT_IRET, 0x074) \ | ||
176 | _ER(EXIT_SWINT, 0x075) \ | ||
177 | _ER(EXIT_INVD, 0x076) \ | ||
178 | _ER(EXIT_PAUSE, 0x077) \ | ||
179 | _ER(EXIT_HLT, 0x078) \ | ||
180 | _ER(EXIT_INVLPG, 0x079) \ | ||
181 | _ER(EXIT_INVLPGA, 0x07a) \ | ||
182 | _ER(EXIT_IOIO, 0x07b) \ | ||
183 | _ER(EXIT_MSR, 0x07c) \ | ||
184 | _ER(EXIT_TASK_SWITCH, 0x07d) \ | ||
185 | _ER(EXIT_FERR_FREEZE, 0x07e) \ | ||
186 | _ER(EXIT_SHUTDOWN, 0x07f) \ | ||
187 | _ER(EXIT_VMRUN, 0x080) \ | ||
188 | _ER(EXIT_VMMCALL, 0x081) \ | ||
189 | _ER(EXIT_VMLOAD, 0x082) \ | ||
190 | _ER(EXIT_VMSAVE, 0x083) \ | ||
191 | _ER(EXIT_STGI, 0x084) \ | ||
192 | _ER(EXIT_CLGI, 0x085) \ | ||
193 | _ER(EXIT_SKINIT, 0x086) \ | ||
194 | _ER(EXIT_RDTSCP, 0x087) \ | ||
195 | _ER(EXIT_ICEBP, 0x088) \ | ||
196 | _ER(EXIT_WBINVD, 0x089) \ | ||
197 | _ER(EXIT_MONITOR, 0x08a) \ | ||
198 | _ER(EXIT_MWAIT, 0x08b) \ | ||
199 | _ER(EXIT_MWAIT_COND, 0x08c) \ | ||
200 | _ER(EXIT_NPF, 0x400) \ | ||
201 | _ER(EXIT_ERR, -1) | ||
202 | |||
203 | #define _ER(reason, val) { #reason, val }, | ||
204 | struct str_values { | ||
205 | const char *str; | ||
206 | int val; | ||
207 | }; | ||
208 | |||
209 | static struct str_values vmx_exit_reasons[] = { | ||
210 | VMX_EXIT_REASONS | ||
211 | { NULL, -1} | ||
212 | }; | ||
213 | |||
214 | static struct str_values svm_exit_reasons[] = { | ||
215 | SVM_EXIT_REASONS | ||
216 | { NULL, -1} | ||
217 | }; | ||
218 | |||
219 | static struct isa_exit_reasons { | ||
220 | unsigned isa; | ||
221 | struct str_values *strings; | ||
222 | } isa_exit_reasons[] = { | ||
223 | { .isa = 1, .strings = vmx_exit_reasons }, | ||
224 | { .isa = 2, .strings = svm_exit_reasons }, | ||
225 | { } | ||
226 | }; | ||
227 | |||
228 | static const char *find_exit_reason(unsigned isa, int val) | ||
229 | { | ||
230 | struct str_values *strings = NULL; | ||
231 | int i; | ||
232 | |||
233 | for (i = 0; isa_exit_reasons[i].strings; ++i) | ||
234 | if (isa_exit_reasons[i].isa == isa) { | ||
235 | strings = isa_exit_reasons[i].strings; | ||
236 | break; | ||
237 | } | ||
238 | if (!strings) | ||
239 | return "UNKNOWN-ISA"; | ||
240 | for (i = 0; strings[i].val >= 0; i++) | ||
241 | if (strings[i].val == val) | ||
242 | break; | ||
243 | if (strings[i].str) | ||
244 | return strings[i].str; | ||
245 | return "UNKNOWN"; | ||
246 | } | ||
247 | |||
248 | static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record, | ||
249 | struct event_format *event, void *context) | ||
250 | { | ||
251 | unsigned long long isa; | ||
252 | unsigned long long val; | ||
253 | unsigned long long info1 = 0, info2 = 0; | ||
254 | |||
255 | if (pevent_get_field_val(s, event, "exit_reason", record, &val, 1) < 0) | ||
256 | return -1; | ||
257 | |||
258 | if (pevent_get_field_val(s, event, "isa", record, &isa, 0) < 0) | ||
259 | isa = 1; | ||
260 | |||
261 | trace_seq_printf(s, "reason %s", find_exit_reason(isa, val)); | ||
262 | |||
263 | pevent_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1); | ||
264 | |||
265 | if (pevent_get_field_val(s, event, "info1", record, &info1, 0) >= 0 | ||
266 | && pevent_get_field_val(s, event, "info2", record, &info2, 0) >= 0) | ||
267 | trace_seq_printf(s, " info %llx %llx", info1, info2); | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | #define KVM_EMUL_INSN_F_CR0_PE (1 << 0) | ||
273 | #define KVM_EMUL_INSN_F_EFL_VM (1 << 1) | ||
274 | #define KVM_EMUL_INSN_F_CS_D (1 << 2) | ||
275 | #define KVM_EMUL_INSN_F_CS_L (1 << 3) | ||
276 | |||
277 | static int kvm_emulate_insn_handler(struct trace_seq *s, | ||
278 | struct pevent_record *record, | ||
279 | struct event_format *event, void *context) | ||
280 | { | ||
281 | unsigned long long rip, csbase, len, flags, failed; | ||
282 | int llen; | ||
283 | uint8_t *insn; | ||
284 | const char *disasm; | ||
285 | |||
286 | if (pevent_get_field_val(s, event, "rip", record, &rip, 1) < 0) | ||
287 | return -1; | ||
288 | |||
289 | if (pevent_get_field_val(s, event, "csbase", record, &csbase, 1) < 0) | ||
290 | return -1; | ||
291 | |||
292 | if (pevent_get_field_val(s, event, "len", record, &len, 1) < 0) | ||
293 | return -1; | ||
294 | |||
295 | if (pevent_get_field_val(s, event, "flags", record, &flags, 1) < 0) | ||
296 | return -1; | ||
297 | |||
298 | if (pevent_get_field_val(s, event, "failed", record, &failed, 1) < 0) | ||
299 | return -1; | ||
300 | |||
301 | insn = pevent_get_field_raw(s, event, "insn", record, &llen, 1); | ||
302 | if (!insn) | ||
303 | return -1; | ||
304 | |||
305 | disasm = disassemble(insn, len, rip, | ||
306 | flags & KVM_EMUL_INSN_F_CR0_PE, | ||
307 | flags & KVM_EMUL_INSN_F_EFL_VM, | ||
308 | flags & KVM_EMUL_INSN_F_CS_D, | ||
309 | flags & KVM_EMUL_INSN_F_CS_L); | ||
310 | |||
311 | trace_seq_printf(s, "%llx:%llx: %s%s", csbase, rip, disasm, | ||
312 | failed ? " FAIL" : ""); | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | union kvm_mmu_page_role { | ||
317 | unsigned word; | ||
318 | struct { | ||
319 | unsigned glevels:4; | ||
320 | unsigned level:4; | ||
321 | unsigned quadrant:2; | ||
322 | unsigned pad_for_nice_hex_output:6; | ||
323 | unsigned direct:1; | ||
324 | unsigned access:3; | ||
325 | unsigned invalid:1; | ||
326 | unsigned cr4_pge:1; | ||
327 | unsigned nxe:1; | ||
328 | }; | ||
329 | }; | ||
330 | |||
331 | static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record, | ||
332 | struct event_format *event, void *context) | ||
333 | { | ||
334 | unsigned long long val; | ||
335 | static const char *access_str[] = { | ||
336 | "---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux" | ||
337 | }; | ||
338 | union kvm_mmu_page_role role; | ||
339 | |||
340 | if (pevent_get_field_val(s, event, "role", record, &val, 1) < 0) | ||
341 | return -1; | ||
342 | |||
343 | role.word = (int)val; | ||
344 | |||
345 | /* | ||
346 | * We can only use the structure if file is of the same | ||
347 | * endianess. | ||
348 | */ | ||
349 | if (pevent_is_file_bigendian(event->pevent) == | ||
350 | pevent_is_host_bigendian(event->pevent)) { | ||
351 | |||
352 | trace_seq_printf(s, "%u/%u q%u%s %s%s %spge %snxe", | ||
353 | role.level, | ||
354 | role.glevels, | ||
355 | role.quadrant, | ||
356 | role.direct ? " direct" : "", | ||
357 | access_str[role.access], | ||
358 | role.invalid ? " invalid" : "", | ||
359 | role.cr4_pge ? "" : "!", | ||
360 | role.nxe ? "" : "!"); | ||
361 | } else | ||
362 | trace_seq_printf(s, "WORD: %08x", role.word); | ||
363 | |||
364 | pevent_print_num_field(s, " root %u ", event, | ||
365 | "root_count", record, 1); | ||
366 | |||
367 | if (pevent_get_field_val(s, event, "unsync", record, &val, 1) < 0) | ||
368 | return -1; | ||
369 | |||
370 | trace_seq_printf(s, "%s%c", val ? "unsync" : "sync", 0); | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static int kvm_mmu_get_page_handler(struct trace_seq *s, | ||
375 | struct pevent_record *record, | ||
376 | struct event_format *event, void *context) | ||
377 | { | ||
378 | unsigned long long val; | ||
379 | |||
380 | if (pevent_get_field_val(s, event, "created", record, &val, 1) < 0) | ||
381 | return -1; | ||
382 | |||
383 | trace_seq_printf(s, "%s ", val ? "new" : "existing"); | ||
384 | |||
385 | if (pevent_get_field_val(s, event, "gfn", record, &val, 1) < 0) | ||
386 | return -1; | ||
387 | |||
388 | trace_seq_printf(s, "sp gfn %llx ", val); | ||
389 | return kvm_mmu_print_role(s, record, event, context); | ||
390 | } | ||
391 | |||
392 | #define PT_WRITABLE_SHIFT 1 | ||
393 | #define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT) | ||
394 | |||
395 | static unsigned long long | ||
396 | process_is_writable_pte(struct trace_seq *s, unsigned long long *args) | ||
397 | { | ||
398 | unsigned long pte = args[0]; | ||
399 | return pte & PT_WRITABLE_MASK; | ||
400 | } | ||
401 | |||
402 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
403 | { | ||
404 | init_disassembler(); | ||
405 | |||
406 | pevent_register_event_handler(pevent, -1, "kvm", "kvm_exit", | ||
407 | kvm_exit_handler, NULL); | ||
408 | |||
409 | pevent_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", | ||
410 | kvm_emulate_insn_handler, NULL); | ||
411 | |||
412 | pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", | ||
413 | kvm_mmu_get_page_handler, NULL); | ||
414 | |||
415 | pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page", | ||
416 | kvm_mmu_print_role, NULL); | ||
417 | |||
418 | pevent_register_event_handler(pevent, -1, | ||
419 | "kvmmmu", "kvm_mmu_unsync_page", | ||
420 | kvm_mmu_print_role, NULL); | ||
421 | |||
422 | pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page", | ||
423 | kvm_mmu_print_role, NULL); | ||
424 | |||
425 | pevent_register_event_handler(pevent, -1, "kvmmmu", | ||
426 | "kvm_mmu_prepare_zap_page", kvm_mmu_print_role, | ||
427 | NULL); | ||
428 | |||
429 | pevent_register_print_function(pevent, | ||
430 | process_is_writable_pte, | ||
431 | PEVENT_FUNC_ARG_INT, | ||
432 | "is_writable_pte", | ||
433 | PEVENT_FUNC_ARG_LONG, | ||
434 | PEVENT_FUNC_ARG_VOID); | ||
435 | return 0; | ||
436 | } | ||
diff --git a/tools/lib/traceevent/plugin_mac80211.c b/tools/lib/traceevent/plugin_mac80211.c new file mode 100644 index 000000000000..558a3b91c046 --- /dev/null +++ b/tools/lib/traceevent/plugin_mac80211.c | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Johannes Berg <johannes@sipsolutions.net> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * version 2.1 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
17 | * | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
19 | */ | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | |||
24 | #include "event-parse.h" | ||
25 | |||
26 | #define INDENT 65 | ||
27 | |||
28 | static void print_string(struct trace_seq *s, struct event_format *event, | ||
29 | const char *name, const void *data) | ||
30 | { | ||
31 | struct format_field *f = pevent_find_field(event, name); | ||
32 | int offset; | ||
33 | int length; | ||
34 | |||
35 | if (!f) { | ||
36 | trace_seq_printf(s, "NOTFOUND:%s", name); | ||
37 | return; | ||
38 | } | ||
39 | |||
40 | offset = f->offset; | ||
41 | length = f->size; | ||
42 | |||
43 | if (!strncmp(f->type, "__data_loc", 10)) { | ||
44 | unsigned long long v; | ||
45 | if (pevent_read_number_field(f, data, &v)) { | ||
46 | trace_seq_printf(s, "invalid_data_loc"); | ||
47 | return; | ||
48 | } | ||
49 | offset = v & 0xffff; | ||
50 | length = v >> 16; | ||
51 | } | ||
52 | |||
53 | trace_seq_printf(s, "%.*s", length, (char *)data + offset); | ||
54 | } | ||
55 | |||
56 | #define SF(fn) pevent_print_num_field(s, fn ":%d", event, fn, record, 0) | ||
57 | #define SFX(fn) pevent_print_num_field(s, fn ":%#x", event, fn, record, 0) | ||
58 | #define SP() trace_seq_putc(s, ' ') | ||
59 | |||
60 | static int drv_bss_info_changed(struct trace_seq *s, | ||
61 | struct pevent_record *record, | ||
62 | struct event_format *event, void *context) | ||
63 | { | ||
64 | void *data = record->data; | ||
65 | |||
66 | print_string(s, event, "wiphy_name", data); | ||
67 | trace_seq_printf(s, " vif:"); | ||
68 | print_string(s, event, "vif_name", data); | ||
69 | pevent_print_num_field(s, "(%d)", event, "vif_type", record, 1); | ||
70 | |||
71 | trace_seq_printf(s, "\n%*s", INDENT, ""); | ||
72 | SF("assoc"); SP(); | ||
73 | SF("aid"); SP(); | ||
74 | SF("cts"); SP(); | ||
75 | SF("shortpre"); SP(); | ||
76 | SF("shortslot"); SP(); | ||
77 | SF("dtimper"); SP(); | ||
78 | trace_seq_printf(s, "\n%*s", INDENT, ""); | ||
79 | SF("bcnint"); SP(); | ||
80 | SFX("assoc_cap"); SP(); | ||
81 | SFX("basic_rates"); SP(); | ||
82 | SF("enable_beacon"); | ||
83 | trace_seq_printf(s, "\n%*s", INDENT, ""); | ||
84 | SF("ht_operation_mode"); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
90 | { | ||
91 | pevent_register_event_handler(pevent, -1, "mac80211", | ||
92 | "drv_bss_info_changed", | ||
93 | drv_bss_info_changed, NULL); | ||
94 | return 0; | ||
95 | } | ||
diff --git a/tools/lib/traceevent/plugin_sched_switch.c b/tools/lib/traceevent/plugin_sched_switch.c new file mode 100644 index 000000000000..fea3724aa24f --- /dev/null +++ b/tools/lib/traceevent/plugin_sched_switch.c | |||
@@ -0,0 +1,148 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * version 2.1 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
17 | * | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
19 | */ | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | |||
24 | #include "event-parse.h" | ||
25 | |||
26 | static void write_state(struct trace_seq *s, int val) | ||
27 | { | ||
28 | const char states[] = "SDTtZXxW"; | ||
29 | int found = 0; | ||
30 | int i; | ||
31 | |||
32 | for (i = 0; i < (sizeof(states) - 1); i++) { | ||
33 | if (!(val & (1 << i))) | ||
34 | continue; | ||
35 | |||
36 | if (found) | ||
37 | trace_seq_putc(s, '|'); | ||
38 | |||
39 | found = 1; | ||
40 | trace_seq_putc(s, states[i]); | ||
41 | } | ||
42 | |||
43 | if (!found) | ||
44 | trace_seq_putc(s, 'R'); | ||
45 | } | ||
46 | |||
47 | static void write_and_save_comm(struct format_field *field, | ||
48 | struct pevent_record *record, | ||
49 | struct trace_seq *s, int pid) | ||
50 | { | ||
51 | const char *comm; | ||
52 | int len; | ||
53 | |||
54 | comm = (char *)(record->data + field->offset); | ||
55 | len = s->len; | ||
56 | trace_seq_printf(s, "%.*s", | ||
57 | field->size, comm); | ||
58 | |||
59 | /* make sure the comm has a \0 at the end. */ | ||
60 | trace_seq_terminate(s); | ||
61 | comm = &s->buffer[len]; | ||
62 | |||
63 | /* Help out the comm to ids. This will handle dups */ | ||
64 | pevent_register_comm(field->event->pevent, comm, pid); | ||
65 | } | ||
66 | |||
67 | static int sched_wakeup_handler(struct trace_seq *s, | ||
68 | struct pevent_record *record, | ||
69 | struct event_format *event, void *context) | ||
70 | { | ||
71 | struct format_field *field; | ||
72 | unsigned long long val; | ||
73 | |||
74 | if (pevent_get_field_val(s, event, "pid", record, &val, 1)) | ||
75 | return trace_seq_putc(s, '!'); | ||
76 | |||
77 | field = pevent_find_any_field(event, "comm"); | ||
78 | if (field) { | ||
79 | write_and_save_comm(field, record, s, val); | ||
80 | trace_seq_putc(s, ':'); | ||
81 | } | ||
82 | trace_seq_printf(s, "%lld", val); | ||
83 | |||
84 | if (pevent_get_field_val(s, event, "prio", record, &val, 0) == 0) | ||
85 | trace_seq_printf(s, " [%lld]", val); | ||
86 | |||
87 | if (pevent_get_field_val(s, event, "success", record, &val, 1) == 0) | ||
88 | trace_seq_printf(s, " success=%lld", val); | ||
89 | |||
90 | if (pevent_get_field_val(s, event, "target_cpu", record, &val, 0) == 0) | ||
91 | trace_seq_printf(s, " CPU:%03llu", val); | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int sched_switch_handler(struct trace_seq *s, | ||
97 | struct pevent_record *record, | ||
98 | struct event_format *event, void *context) | ||
99 | { | ||
100 | struct format_field *field; | ||
101 | unsigned long long val; | ||
102 | |||
103 | if (pevent_get_field_val(s, event, "prev_pid", record, &val, 1)) | ||
104 | return trace_seq_putc(s, '!'); | ||
105 | |||
106 | field = pevent_find_any_field(event, "prev_comm"); | ||
107 | if (field) { | ||
108 | write_and_save_comm(field, record, s, val); | ||
109 | trace_seq_putc(s, ':'); | ||
110 | } | ||
111 | trace_seq_printf(s, "%lld ", val); | ||
112 | |||
113 | if (pevent_get_field_val(s, event, "prev_prio", record, &val, 0) == 0) | ||
114 | trace_seq_printf(s, "[%lld] ", val); | ||
115 | |||
116 | if (pevent_get_field_val(s, event, "prev_state", record, &val, 0) == 0) | ||
117 | write_state(s, val); | ||
118 | |||
119 | trace_seq_puts(s, " ==> "); | ||
120 | |||
121 | if (pevent_get_field_val(s, event, "next_pid", record, &val, 1)) | ||
122 | return trace_seq_putc(s, '!'); | ||
123 | |||
124 | field = pevent_find_any_field(event, "next_comm"); | ||
125 | if (field) { | ||
126 | write_and_save_comm(field, record, s, val); | ||
127 | trace_seq_putc(s, ':'); | ||
128 | } | ||
129 | trace_seq_printf(s, "%lld", val); | ||
130 | |||
131 | if (pevent_get_field_val(s, event, "next_prio", record, &val, 0) == 0) | ||
132 | trace_seq_printf(s, " [%lld]", val); | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
138 | { | ||
139 | pevent_register_event_handler(pevent, -1, "sched", "sched_switch", | ||
140 | sched_switch_handler, NULL); | ||
141 | |||
142 | pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup", | ||
143 | sched_wakeup_handler, NULL); | ||
144 | |||
145 | pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup_new", | ||
146 | sched_wakeup_handler, NULL); | ||
147 | return 0; | ||
148 | } | ||
diff --git a/tools/lib/traceevent/plugin_scsi.c b/tools/lib/traceevent/plugin_scsi.c new file mode 100644 index 000000000000..6fb8e3e3fcad --- /dev/null +++ b/tools/lib/traceevent/plugin_scsi.c | |||
@@ -0,0 +1,423 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <string.h> | ||
3 | #include <inttypes.h> | ||
4 | #include "event-parse.h" | ||
5 | |||
6 | typedef unsigned long sector_t; | ||
7 | typedef uint64_t u64; | ||
8 | typedef unsigned int u32; | ||
9 | |||
10 | /* | ||
11 | * SCSI opcodes | ||
12 | */ | ||
13 | #define TEST_UNIT_READY 0x00 | ||
14 | #define REZERO_UNIT 0x01 | ||
15 | #define REQUEST_SENSE 0x03 | ||
16 | #define FORMAT_UNIT 0x04 | ||
17 | #define READ_BLOCK_LIMITS 0x05 | ||
18 | #define REASSIGN_BLOCKS 0x07 | ||
19 | #define INITIALIZE_ELEMENT_STATUS 0x07 | ||
20 | #define READ_6 0x08 | ||
21 | #define WRITE_6 0x0a | ||
22 | #define SEEK_6 0x0b | ||
23 | #define READ_REVERSE 0x0f | ||
24 | #define WRITE_FILEMARKS 0x10 | ||
25 | #define SPACE 0x11 | ||
26 | #define INQUIRY 0x12 | ||
27 | #define RECOVER_BUFFERED_DATA 0x14 | ||
28 | #define MODE_SELECT 0x15 | ||
29 | #define RESERVE 0x16 | ||
30 | #define RELEASE 0x17 | ||
31 | #define COPY 0x18 | ||
32 | #define ERASE 0x19 | ||
33 | #define MODE_SENSE 0x1a | ||
34 | #define START_STOP 0x1b | ||
35 | #define RECEIVE_DIAGNOSTIC 0x1c | ||
36 | #define SEND_DIAGNOSTIC 0x1d | ||
37 | #define ALLOW_MEDIUM_REMOVAL 0x1e | ||
38 | |||
39 | #define READ_FORMAT_CAPACITIES 0x23 | ||
40 | #define SET_WINDOW 0x24 | ||
41 | #define READ_CAPACITY 0x25 | ||
42 | #define READ_10 0x28 | ||
43 | #define WRITE_10 0x2a | ||
44 | #define SEEK_10 0x2b | ||
45 | #define POSITION_TO_ELEMENT 0x2b | ||
46 | #define WRITE_VERIFY 0x2e | ||
47 | #define VERIFY 0x2f | ||
48 | #define SEARCH_HIGH 0x30 | ||
49 | #define SEARCH_EQUAL 0x31 | ||
50 | #define SEARCH_LOW 0x32 | ||
51 | #define SET_LIMITS 0x33 | ||
52 | #define PRE_FETCH 0x34 | ||
53 | #define READ_POSITION 0x34 | ||
54 | #define SYNCHRONIZE_CACHE 0x35 | ||
55 | #define LOCK_UNLOCK_CACHE 0x36 | ||
56 | #define READ_DEFECT_DATA 0x37 | ||
57 | #define MEDIUM_SCAN 0x38 | ||
58 | #define COMPARE 0x39 | ||
59 | #define COPY_VERIFY 0x3a | ||
60 | #define WRITE_BUFFER 0x3b | ||
61 | #define READ_BUFFER 0x3c | ||
62 | #define UPDATE_BLOCK 0x3d | ||
63 | #define READ_LONG 0x3e | ||
64 | #define WRITE_LONG 0x3f | ||
65 | #define CHANGE_DEFINITION 0x40 | ||
66 | #define WRITE_SAME 0x41 | ||
67 | #define UNMAP 0x42 | ||
68 | #define READ_TOC 0x43 | ||
69 | #define READ_HEADER 0x44 | ||
70 | #define GET_EVENT_STATUS_NOTIFICATION 0x4a | ||
71 | #define LOG_SELECT 0x4c | ||
72 | #define LOG_SENSE 0x4d | ||
73 | #define XDWRITEREAD_10 0x53 | ||
74 | #define MODE_SELECT_10 0x55 | ||
75 | #define RESERVE_10 0x56 | ||
76 | #define RELEASE_10 0x57 | ||
77 | #define MODE_SENSE_10 0x5a | ||
78 | #define PERSISTENT_RESERVE_IN 0x5e | ||
79 | #define PERSISTENT_RESERVE_OUT 0x5f | ||
80 | #define VARIABLE_LENGTH_CMD 0x7f | ||
81 | #define REPORT_LUNS 0xa0 | ||
82 | #define SECURITY_PROTOCOL_IN 0xa2 | ||
83 | #define MAINTENANCE_IN 0xa3 | ||
84 | #define MAINTENANCE_OUT 0xa4 | ||
85 | #define MOVE_MEDIUM 0xa5 | ||
86 | #define EXCHANGE_MEDIUM 0xa6 | ||
87 | #define READ_12 0xa8 | ||
88 | #define WRITE_12 0xaa | ||
89 | #define READ_MEDIA_SERIAL_NUMBER 0xab | ||
90 | #define WRITE_VERIFY_12 0xae | ||
91 | #define VERIFY_12 0xaf | ||
92 | #define SEARCH_HIGH_12 0xb0 | ||
93 | #define SEARCH_EQUAL_12 0xb1 | ||
94 | #define SEARCH_LOW_12 0xb2 | ||
95 | #define SECURITY_PROTOCOL_OUT 0xb5 | ||
96 | #define READ_ELEMENT_STATUS 0xb8 | ||
97 | #define SEND_VOLUME_TAG 0xb6 | ||
98 | #define WRITE_LONG_2 0xea | ||
99 | #define EXTENDED_COPY 0x83 | ||
100 | #define RECEIVE_COPY_RESULTS 0x84 | ||
101 | #define ACCESS_CONTROL_IN 0x86 | ||
102 | #define ACCESS_CONTROL_OUT 0x87 | ||
103 | #define READ_16 0x88 | ||
104 | #define WRITE_16 0x8a | ||
105 | #define READ_ATTRIBUTE 0x8c | ||
106 | #define WRITE_ATTRIBUTE 0x8d | ||
107 | #define VERIFY_16 0x8f | ||
108 | #define SYNCHRONIZE_CACHE_16 0x91 | ||
109 | #define WRITE_SAME_16 0x93 | ||
110 | #define SERVICE_ACTION_IN 0x9e | ||
111 | /* values for service action in */ | ||
112 | #define SAI_READ_CAPACITY_16 0x10 | ||
113 | #define SAI_GET_LBA_STATUS 0x12 | ||
114 | /* values for VARIABLE_LENGTH_CMD service action codes | ||
115 | * see spc4r17 Section D.3.5, table D.7 and D.8 */ | ||
116 | #define VLC_SA_RECEIVE_CREDENTIAL 0x1800 | ||
117 | /* values for maintenance in */ | ||
118 | #define MI_REPORT_IDENTIFYING_INFORMATION 0x05 | ||
119 | #define MI_REPORT_TARGET_PGS 0x0a | ||
120 | #define MI_REPORT_ALIASES 0x0b | ||
121 | #define MI_REPORT_SUPPORTED_OPERATION_CODES 0x0c | ||
122 | #define MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS 0x0d | ||
123 | #define MI_REPORT_PRIORITY 0x0e | ||
124 | #define MI_REPORT_TIMESTAMP 0x0f | ||
125 | #define MI_MANAGEMENT_PROTOCOL_IN 0x10 | ||
126 | /* value for MI_REPORT_TARGET_PGS ext header */ | ||
127 | #define MI_EXT_HDR_PARAM_FMT 0x20 | ||
128 | /* values for maintenance out */ | ||
129 | #define MO_SET_IDENTIFYING_INFORMATION 0x06 | ||
130 | #define MO_SET_TARGET_PGS 0x0a | ||
131 | #define MO_CHANGE_ALIASES 0x0b | ||
132 | #define MO_SET_PRIORITY 0x0e | ||
133 | #define MO_SET_TIMESTAMP 0x0f | ||
134 | #define MO_MANAGEMENT_PROTOCOL_OUT 0x10 | ||
135 | /* values for variable length command */ | ||
136 | #define XDREAD_32 0x03 | ||
137 | #define XDWRITE_32 0x04 | ||
138 | #define XPWRITE_32 0x06 | ||
139 | #define XDWRITEREAD_32 0x07 | ||
140 | #define READ_32 0x09 | ||
141 | #define VERIFY_32 0x0a | ||
142 | #define WRITE_32 0x0b | ||
143 | #define WRITE_SAME_32 0x0d | ||
144 | |||
145 | #define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f) | ||
146 | #define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9]) | ||
147 | |||
148 | static const char * | ||
149 | scsi_trace_misc(struct trace_seq *, unsigned char *, int); | ||
150 | |||
151 | static const char * | ||
152 | scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len) | ||
153 | { | ||
154 | const char *ret = p->buffer + p->len; | ||
155 | sector_t lba = 0, txlen = 0; | ||
156 | |||
157 | lba |= ((cdb[1] & 0x1F) << 16); | ||
158 | lba |= (cdb[2] << 8); | ||
159 | lba |= cdb[3]; | ||
160 | txlen = cdb[4]; | ||
161 | |||
162 | trace_seq_printf(p, "lba=%llu txlen=%llu", | ||
163 | (unsigned long long)lba, (unsigned long long)txlen); | ||
164 | trace_seq_putc(p, 0); | ||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | static const char * | ||
169 | scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len) | ||
170 | { | ||
171 | const char *ret = p->buffer + p->len; | ||
172 | sector_t lba = 0, txlen = 0; | ||
173 | |||
174 | lba |= (cdb[2] << 24); | ||
175 | lba |= (cdb[3] << 16); | ||
176 | lba |= (cdb[4] << 8); | ||
177 | lba |= cdb[5]; | ||
178 | txlen |= (cdb[7] << 8); | ||
179 | txlen |= cdb[8]; | ||
180 | |||
181 | trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", | ||
182 | (unsigned long long)lba, (unsigned long long)txlen, | ||
183 | cdb[1] >> 5); | ||
184 | |||
185 | if (cdb[0] == WRITE_SAME) | ||
186 | trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1); | ||
187 | |||
188 | trace_seq_putc(p, 0); | ||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | static const char * | ||
193 | scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len) | ||
194 | { | ||
195 | const char *ret = p->buffer + p->len; | ||
196 | sector_t lba = 0, txlen = 0; | ||
197 | |||
198 | lba |= (cdb[2] << 24); | ||
199 | lba |= (cdb[3] << 16); | ||
200 | lba |= (cdb[4] << 8); | ||
201 | lba |= cdb[5]; | ||
202 | txlen |= (cdb[6] << 24); | ||
203 | txlen |= (cdb[7] << 16); | ||
204 | txlen |= (cdb[8] << 8); | ||
205 | txlen |= cdb[9]; | ||
206 | |||
207 | trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", | ||
208 | (unsigned long long)lba, (unsigned long long)txlen, | ||
209 | cdb[1] >> 5); | ||
210 | trace_seq_putc(p, 0); | ||
211 | return ret; | ||
212 | } | ||
213 | |||
214 | static const char * | ||
215 | scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len) | ||
216 | { | ||
217 | const char *ret = p->buffer + p->len; | ||
218 | sector_t lba = 0, txlen = 0; | ||
219 | |||
220 | lba |= ((u64)cdb[2] << 56); | ||
221 | lba |= ((u64)cdb[3] << 48); | ||
222 | lba |= ((u64)cdb[4] << 40); | ||
223 | lba |= ((u64)cdb[5] << 32); | ||
224 | lba |= (cdb[6] << 24); | ||
225 | lba |= (cdb[7] << 16); | ||
226 | lba |= (cdb[8] << 8); | ||
227 | lba |= cdb[9]; | ||
228 | txlen |= (cdb[10] << 24); | ||
229 | txlen |= (cdb[11] << 16); | ||
230 | txlen |= (cdb[12] << 8); | ||
231 | txlen |= cdb[13]; | ||
232 | |||
233 | trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", | ||
234 | (unsigned long long)lba, (unsigned long long)txlen, | ||
235 | cdb[1] >> 5); | ||
236 | |||
237 | if (cdb[0] == WRITE_SAME_16) | ||
238 | trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1); | ||
239 | |||
240 | trace_seq_putc(p, 0); | ||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | static const char * | ||
245 | scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) | ||
246 | { | ||
247 | const char *ret = p->buffer + p->len, *cmd; | ||
248 | sector_t lba = 0, txlen = 0; | ||
249 | u32 ei_lbrt = 0; | ||
250 | |||
251 | switch (SERVICE_ACTION32(cdb)) { | ||
252 | case READ_32: | ||
253 | cmd = "READ"; | ||
254 | break; | ||
255 | case VERIFY_32: | ||
256 | cmd = "VERIFY"; | ||
257 | break; | ||
258 | case WRITE_32: | ||
259 | cmd = "WRITE"; | ||
260 | break; | ||
261 | case WRITE_SAME_32: | ||
262 | cmd = "WRITE_SAME"; | ||
263 | break; | ||
264 | default: | ||
265 | trace_seq_printf(p, "UNKNOWN"); | ||
266 | goto out; | ||
267 | } | ||
268 | |||
269 | lba |= ((u64)cdb[12] << 56); | ||
270 | lba |= ((u64)cdb[13] << 48); | ||
271 | lba |= ((u64)cdb[14] << 40); | ||
272 | lba |= ((u64)cdb[15] << 32); | ||
273 | lba |= (cdb[16] << 24); | ||
274 | lba |= (cdb[17] << 16); | ||
275 | lba |= (cdb[18] << 8); | ||
276 | lba |= cdb[19]; | ||
277 | ei_lbrt |= (cdb[20] << 24); | ||
278 | ei_lbrt |= (cdb[21] << 16); | ||
279 | ei_lbrt |= (cdb[22] << 8); | ||
280 | ei_lbrt |= cdb[23]; | ||
281 | txlen |= (cdb[28] << 24); | ||
282 | txlen |= (cdb[29] << 16); | ||
283 | txlen |= (cdb[30] << 8); | ||
284 | txlen |= cdb[31]; | ||
285 | |||
286 | trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u", | ||
287 | cmd, (unsigned long long)lba, | ||
288 | (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt); | ||
289 | |||
290 | if (SERVICE_ACTION32(cdb) == WRITE_SAME_32) | ||
291 | trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1); | ||
292 | |||
293 | out: | ||
294 | trace_seq_putc(p, 0); | ||
295 | return ret; | ||
296 | } | ||
297 | |||
298 | static const char * | ||
299 | scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len) | ||
300 | { | ||
301 | const char *ret = p->buffer + p->len; | ||
302 | unsigned int regions = cdb[7] << 8 | cdb[8]; | ||
303 | |||
304 | trace_seq_printf(p, "regions=%u", (regions - 8) / 16); | ||
305 | trace_seq_putc(p, 0); | ||
306 | return ret; | ||
307 | } | ||
308 | |||
309 | static const char * | ||
310 | scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len) | ||
311 | { | ||
312 | const char *ret = p->buffer + p->len, *cmd; | ||
313 | sector_t lba = 0; | ||
314 | u32 alloc_len = 0; | ||
315 | |||
316 | switch (SERVICE_ACTION16(cdb)) { | ||
317 | case SAI_READ_CAPACITY_16: | ||
318 | cmd = "READ_CAPACITY_16"; | ||
319 | break; | ||
320 | case SAI_GET_LBA_STATUS: | ||
321 | cmd = "GET_LBA_STATUS"; | ||
322 | break; | ||
323 | default: | ||
324 | trace_seq_printf(p, "UNKNOWN"); | ||
325 | goto out; | ||
326 | } | ||
327 | |||
328 | lba |= ((u64)cdb[2] << 56); | ||
329 | lba |= ((u64)cdb[3] << 48); | ||
330 | lba |= ((u64)cdb[4] << 40); | ||
331 | lba |= ((u64)cdb[5] << 32); | ||
332 | lba |= (cdb[6] << 24); | ||
333 | lba |= (cdb[7] << 16); | ||
334 | lba |= (cdb[8] << 8); | ||
335 | lba |= cdb[9]; | ||
336 | alloc_len |= (cdb[10] << 24); | ||
337 | alloc_len |= (cdb[11] << 16); | ||
338 | alloc_len |= (cdb[12] << 8); | ||
339 | alloc_len |= cdb[13]; | ||
340 | |||
341 | trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, | ||
342 | (unsigned long long)lba, alloc_len); | ||
343 | |||
344 | out: | ||
345 | trace_seq_putc(p, 0); | ||
346 | return ret; | ||
347 | } | ||
348 | |||
349 | static const char * | ||
350 | scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len) | ||
351 | { | ||
352 | switch (SERVICE_ACTION32(cdb)) { | ||
353 | case READ_32: | ||
354 | case VERIFY_32: | ||
355 | case WRITE_32: | ||
356 | case WRITE_SAME_32: | ||
357 | return scsi_trace_rw32(p, cdb, len); | ||
358 | default: | ||
359 | return scsi_trace_misc(p, cdb, len); | ||
360 | } | ||
361 | } | ||
362 | |||
363 | static const char * | ||
364 | scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len) | ||
365 | { | ||
366 | const char *ret = p->buffer + p->len; | ||
367 | |||
368 | trace_seq_printf(p, "-"); | ||
369 | trace_seq_putc(p, 0); | ||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | const char * | ||
374 | scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len) | ||
375 | { | ||
376 | switch (cdb[0]) { | ||
377 | case READ_6: | ||
378 | case WRITE_6: | ||
379 | return scsi_trace_rw6(p, cdb, len); | ||
380 | case READ_10: | ||
381 | case VERIFY: | ||
382 | case WRITE_10: | ||
383 | case WRITE_SAME: | ||
384 | return scsi_trace_rw10(p, cdb, len); | ||
385 | case READ_12: | ||
386 | case VERIFY_12: | ||
387 | case WRITE_12: | ||
388 | return scsi_trace_rw12(p, cdb, len); | ||
389 | case READ_16: | ||
390 | case VERIFY_16: | ||
391 | case WRITE_16: | ||
392 | case WRITE_SAME_16: | ||
393 | return scsi_trace_rw16(p, cdb, len); | ||
394 | case UNMAP: | ||
395 | return scsi_trace_unmap(p, cdb, len); | ||
396 | case SERVICE_ACTION_IN: | ||
397 | return scsi_trace_service_action_in(p, cdb, len); | ||
398 | case VARIABLE_LENGTH_CMD: | ||
399 | return scsi_trace_varlen(p, cdb, len); | ||
400 | default: | ||
401 | return scsi_trace_misc(p, cdb, len); | ||
402 | } | ||
403 | } | ||
404 | |||
405 | unsigned long long process_scsi_trace_parse_cdb(struct trace_seq *s, | ||
406 | unsigned long long *args) | ||
407 | { | ||
408 | scsi_trace_parse_cdb(s, (unsigned char *) args[1], args[2]); | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
413 | { | ||
414 | pevent_register_print_function(pevent, | ||
415 | process_scsi_trace_parse_cdb, | ||
416 | PEVENT_FUNC_ARG_STRING, | ||
417 | "scsi_trace_parse_cdb", | ||
418 | PEVENT_FUNC_ARG_PTR, | ||
419 | PEVENT_FUNC_ARG_PTR, | ||
420 | PEVENT_FUNC_ARG_INT, | ||
421 | PEVENT_FUNC_ARG_VOID); | ||
422 | return 0; | ||
423 | } | ||
diff --git a/tools/lib/traceevent/plugin_xen.c b/tools/lib/traceevent/plugin_xen.c new file mode 100644 index 000000000000..e7794298f3a9 --- /dev/null +++ b/tools/lib/traceevent/plugin_xen.c | |||
@@ -0,0 +1,130 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdlib.h> | ||
3 | #include <string.h> | ||
4 | #include "event-parse.h" | ||
5 | |||
6 | #define __HYPERVISOR_set_trap_table 0 | ||
7 | #define __HYPERVISOR_mmu_update 1 | ||
8 | #define __HYPERVISOR_set_gdt 2 | ||
9 | #define __HYPERVISOR_stack_switch 3 | ||
10 | #define __HYPERVISOR_set_callbacks 4 | ||
11 | #define __HYPERVISOR_fpu_taskswitch 5 | ||
12 | #define __HYPERVISOR_sched_op_compat 6 | ||
13 | #define __HYPERVISOR_dom0_op 7 | ||
14 | #define __HYPERVISOR_set_debugreg 8 | ||
15 | #define __HYPERVISOR_get_debugreg 9 | ||
16 | #define __HYPERVISOR_update_descriptor 10 | ||
17 | #define __HYPERVISOR_memory_op 12 | ||
18 | #define __HYPERVISOR_multicall 13 | ||
19 | #define __HYPERVISOR_update_va_mapping 14 | ||
20 | #define __HYPERVISOR_set_timer_op 15 | ||
21 | #define __HYPERVISOR_event_channel_op_compat 16 | ||
22 | #define __HYPERVISOR_xen_version 17 | ||
23 | #define __HYPERVISOR_console_io 18 | ||
24 | #define __HYPERVISOR_physdev_op_compat 19 | ||
25 | #define __HYPERVISOR_grant_table_op 20 | ||
26 | #define __HYPERVISOR_vm_assist 21 | ||
27 | #define __HYPERVISOR_update_va_mapping_otherdomain 22 | ||
28 | #define __HYPERVISOR_iret 23 /* x86 only */ | ||
29 | #define __HYPERVISOR_vcpu_op 24 | ||
30 | #define __HYPERVISOR_set_segment_base 25 /* x86/64 only */ | ||
31 | #define __HYPERVISOR_mmuext_op 26 | ||
32 | #define __HYPERVISOR_acm_op 27 | ||
33 | #define __HYPERVISOR_nmi_op 28 | ||
34 | #define __HYPERVISOR_sched_op 29 | ||
35 | #define __HYPERVISOR_callback_op 30 | ||
36 | #define __HYPERVISOR_xenoprof_op 31 | ||
37 | #define __HYPERVISOR_event_channel_op 32 | ||
38 | #define __HYPERVISOR_physdev_op 33 | ||
39 | #define __HYPERVISOR_hvm_op 34 | ||
40 | #define __HYPERVISOR_tmem_op 38 | ||
41 | |||
42 | /* Architecture-specific hypercall definitions. */ | ||
43 | #define __HYPERVISOR_arch_0 48 | ||
44 | #define __HYPERVISOR_arch_1 49 | ||
45 | #define __HYPERVISOR_arch_2 50 | ||
46 | #define __HYPERVISOR_arch_3 51 | ||
47 | #define __HYPERVISOR_arch_4 52 | ||
48 | #define __HYPERVISOR_arch_5 53 | ||
49 | #define __HYPERVISOR_arch_6 54 | ||
50 | #define __HYPERVISOR_arch_7 55 | ||
51 | |||
52 | #define N(x) [__HYPERVISOR_##x] = "("#x")" | ||
53 | static const char *xen_hypercall_names[] = { | ||
54 | N(set_trap_table), | ||
55 | N(mmu_update), | ||
56 | N(set_gdt), | ||
57 | N(stack_switch), | ||
58 | N(set_callbacks), | ||
59 | N(fpu_taskswitch), | ||
60 | N(sched_op_compat), | ||
61 | N(dom0_op), | ||
62 | N(set_debugreg), | ||
63 | N(get_debugreg), | ||
64 | N(update_descriptor), | ||
65 | N(memory_op), | ||
66 | N(multicall), | ||
67 | N(update_va_mapping), | ||
68 | N(set_timer_op), | ||
69 | N(event_channel_op_compat), | ||
70 | N(xen_version), | ||
71 | N(console_io), | ||
72 | N(physdev_op_compat), | ||
73 | N(grant_table_op), | ||
74 | N(vm_assist), | ||
75 | N(update_va_mapping_otherdomain), | ||
76 | N(iret), | ||
77 | N(vcpu_op), | ||
78 | N(set_segment_base), | ||
79 | N(mmuext_op), | ||
80 | N(acm_op), | ||
81 | N(nmi_op), | ||
82 | N(sched_op), | ||
83 | N(callback_op), | ||
84 | N(xenoprof_op), | ||
85 | N(event_channel_op), | ||
86 | N(physdev_op), | ||
87 | N(hvm_op), | ||
88 | |||
89 | /* Architecture-specific hypercall definitions. */ | ||
90 | N(arch_0), | ||
91 | N(arch_1), | ||
92 | N(arch_2), | ||
93 | N(arch_3), | ||
94 | N(arch_4), | ||
95 | N(arch_5), | ||
96 | N(arch_6), | ||
97 | N(arch_7), | ||
98 | }; | ||
99 | #undef N | ||
100 | |||
101 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | ||
102 | |||
103 | static const char *xen_hypercall_name(unsigned op) | ||
104 | { | ||
105 | if (op < ARRAY_SIZE(xen_hypercall_names) && | ||
106 | xen_hypercall_names[op] != NULL) | ||
107 | return xen_hypercall_names[op]; | ||
108 | |||
109 | return ""; | ||
110 | } | ||
111 | |||
112 | unsigned long long process_xen_hypercall_name(struct trace_seq *s, | ||
113 | unsigned long long *args) | ||
114 | { | ||
115 | unsigned int op = args[0]; | ||
116 | |||
117 | trace_seq_printf(s, "%s", xen_hypercall_name(op)); | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
122 | { | ||
123 | pevent_register_print_function(pevent, | ||
124 | process_xen_hypercall_name, | ||
125 | PEVENT_FUNC_ARG_STRING, | ||
126 | "xen_hypercall_name", | ||
127 | PEVENT_FUNC_ARG_INT, | ||
128 | PEVENT_FUNC_ARG_VOID); | ||
129 | return 0; | ||
130 | } | ||
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt index 6a06cefe9642..96a9a1dea727 100644 --- a/tools/perf/Documentation/perf-kvm.txt +++ b/tools/perf/Documentation/perf-kvm.txt | |||
@@ -24,10 +24,17 @@ There are a couple of variants of perf kvm: | |||
24 | of an arbitrary workload. | 24 | of an arbitrary workload. |
25 | 25 | ||
26 | 'perf kvm record <command>' to record the performance counter profile | 26 | 'perf kvm record <command>' to record the performance counter profile |
27 | of an arbitrary workload and save it into a perf data file. If both | 27 | of an arbitrary workload and save it into a perf data file. We set the |
28 | --host and --guest are input, the perf data file name is perf.data.kvm. | 28 | default behavior of perf kvm as --guest, so if neither --host nor --guest |
29 | If there is no --host but --guest, the file name is perf.data.guest. | 29 | is input, the perf data file name is perf.data.guest. If --host is input, |
30 | If there is no --guest but --host, the file name is perf.data.host. | 30 | the perf data file name is perf.data.kvm. If you want to record data into |
31 | perf.data.host, please input --host --no-guest. The behaviors are shown as | ||
32 | following: | ||
33 | Default('') -> perf.data.guest | ||
34 | --host -> perf.data.kvm | ||
35 | --guest -> perf.data.guest | ||
36 | --host --guest -> perf.data.kvm | ||
37 | --host --no-guest -> perf.data.host | ||
31 | 38 | ||
32 | 'perf kvm report' to display the performance counter profile information | 39 | 'perf kvm report' to display the performance counter profile information |
33 | recorded via perf kvm record. | 40 | recorded via perf kvm record. |
@@ -37,7 +44,9 @@ There are a couple of variants of perf kvm: | |||
37 | 44 | ||
38 | 'perf kvm buildid-list' to display the buildids found in a perf data file, | 45 | 'perf kvm buildid-list' to display the buildids found in a perf data file, |
39 | so that other tools can be used to fetch packages with matching symbol tables | 46 | so that other tools can be used to fetch packages with matching symbol tables |
40 | for use by perf report. | 47 | for use by perf report. As buildid is read from /sys/kernel/notes in os, then |
48 | if you want to list the buildid for guest, please make sure your perf data file | ||
49 | was captured with --guestmount in perf kvm record. | ||
41 | 50 | ||
42 | 'perf kvm stat <command>' to run a command and gather performance counter | 51 | 'perf kvm stat <command>' to run a command and gather performance counter |
43 | statistics. | 52 | statistics. |
@@ -58,14 +67,14 @@ There are a couple of variants of perf kvm: | |||
58 | OPTIONS | 67 | OPTIONS |
59 | ------- | 68 | ------- |
60 | -i:: | 69 | -i:: |
61 | --input=:: | 70 | --input=<path>:: |
62 | Input file name. | 71 | Input file name. |
63 | -o:: | 72 | -o:: |
64 | --output:: | 73 | --output=<path>:: |
65 | Output file name. | 74 | Output file name. |
66 | --host=:: | 75 | --host:: |
67 | Collect host side performance profile. | 76 | Collect host side performance profile. |
68 | --guest=:: | 77 | --guest:: |
69 | Collect guest side performance profile. | 78 | Collect guest side performance profile. |
70 | --guestmount=<path>:: | 79 | --guestmount=<path>:: |
71 | Guest os root file system mount directory. Users mounts guest os | 80 | Guest os root file system mount directory. Users mounts guest os |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index e416ccc7d831..ca3b87d5389a 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -105,7 +105,7 @@ ifeq ($(config),1) | |||
105 | include config/Makefile | 105 | include config/Makefile |
106 | endif | 106 | endif |
107 | 107 | ||
108 | export prefix bindir sharedir sysconfdir | 108 | export prefix bindir sharedir sysconfdir DESTDIR |
109 | 109 | ||
110 | # sparse is architecture-neutral, which means that we need to tell it | 110 | # sparse is architecture-neutral, which means that we need to tell it |
111 | # explicitly what architecture to check for. Fix this up for yours.. | 111 | # explicitly what architecture to check for. Fix this up for yours.. |
@@ -353,6 +353,7 @@ LIB_OBJS += $(OUTPUT)util/pmu-bison.o | |||
353 | LIB_OBJS += $(OUTPUT)util/trace-event-read.o | 353 | LIB_OBJS += $(OUTPUT)util/trace-event-read.o |
354 | LIB_OBJS += $(OUTPUT)util/trace-event-info.o | 354 | LIB_OBJS += $(OUTPUT)util/trace-event-info.o |
355 | LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o | 355 | LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o |
356 | LIB_OBJS += $(OUTPUT)util/trace-event.o | ||
356 | LIB_OBJS += $(OUTPUT)util/svghelper.o | 357 | LIB_OBJS += $(OUTPUT)util/svghelper.o |
357 | LIB_OBJS += $(OUTPUT)util/sort.o | 358 | LIB_OBJS += $(OUTPUT)util/sort.o |
358 | LIB_OBJS += $(OUTPUT)util/hist.o | 359 | LIB_OBJS += $(OUTPUT)util/hist.o |
@@ -710,13 +711,20 @@ $(LIB_FILE): $(LIB_OBJS) | |||
710 | # libtraceevent.a | 711 | # libtraceevent.a |
711 | TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch]) | 712 | TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch]) |
712 | 713 | ||
713 | $(LIBTRACEEVENT): $(TE_SOURCES) | 714 | LIBTRACEEVENT_FLAGS = $(QUIET_SUBDIR1) O=$(OUTPUT) |
714 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) CFLAGS="-g -Wall $(EXTRA_CFLAGS)" libtraceevent.a | 715 | LIBTRACEEVENT_FLAGS += CFLAGS="-g -Wall $(EXTRA_CFLAGS)" |
716 | LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ) | ||
717 | |||
718 | $(LIBTRACEEVENT): $(TE_SOURCES) $(OUTPUT)PERF-CFLAGS | ||
719 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) libtraceevent.a plugins | ||
715 | 720 | ||
716 | $(LIBTRACEEVENT)-clean: | 721 | $(LIBTRACEEVENT)-clean: |
717 | $(call QUIET_CLEAN, libtraceevent) | 722 | $(call QUIET_CLEAN, libtraceevent) |
718 | @$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null | 723 | @$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null |
719 | 724 | ||
725 | install-traceevent-plugins: | ||
726 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins | ||
727 | |||
720 | LIBLK_SOURCES = $(wildcard $(LK_PATH)*.[ch]) | 728 | LIBLK_SOURCES = $(wildcard $(LK_PATH)*.[ch]) |
721 | 729 | ||
722 | # if subdir is set, we've been called from above so target has been built | 730 | # if subdir is set, we've been called from above so target has been built |
@@ -785,7 +793,7 @@ cscope: | |||
785 | 793 | ||
786 | ### Detect prefix changes | 794 | ### Detect prefix changes |
787 | TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\ | 795 | TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\ |
788 | $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ) | 796 | $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):$(plugindir_SQ) |
789 | 797 | ||
790 | $(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS | 798 | $(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS |
791 | @FLAGS='$(TRACK_CFLAGS)'; \ | 799 | @FLAGS='$(TRACK_CFLAGS)'; \ |
@@ -849,7 +857,7 @@ endif | |||
849 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \ | 857 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \ |
850 | $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' | 858 | $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' |
851 | 859 | ||
852 | install: install-bin try-install-man | 860 | install: install-bin try-install-man install-traceevent-plugins |
853 | 861 | ||
854 | install-python_ext: | 862 | install-python_ext: |
855 | $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' | 863 | $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 952dce979252..4484886dcf08 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -414,7 +414,8 @@ static void print_sample_bts(union perf_event *event, | |||
414 | struct perf_sample *sample, | 414 | struct perf_sample *sample, |
415 | struct perf_evsel *evsel, | 415 | struct perf_evsel *evsel, |
416 | struct machine *machine, | 416 | struct machine *machine, |
417 | struct thread *thread) | 417 | struct thread *thread, |
418 | struct addr_location *al) | ||
418 | { | 419 | { |
419 | struct perf_event_attr *attr = &evsel->attr; | 420 | struct perf_event_attr *attr = &evsel->attr; |
420 | 421 | ||
@@ -424,7 +425,7 @@ static void print_sample_bts(union perf_event *event, | |||
424 | printf(" "); | 425 | printf(" "); |
425 | else | 426 | else |
426 | printf("\n"); | 427 | printf("\n"); |
427 | perf_evsel__print_ip(evsel, event, sample, machine, | 428 | perf_evsel__print_ip(evsel, sample, machine, al, |
428 | output[attr->type].print_ip_opts, | 429 | output[attr->type].print_ip_opts, |
429 | PERF_MAX_STACK_DEPTH); | 430 | PERF_MAX_STACK_DEPTH); |
430 | } | 431 | } |
@@ -443,7 +444,7 @@ static void print_sample_bts(union perf_event *event, | |||
443 | static void process_event(union perf_event *event, struct perf_sample *sample, | 444 | static void process_event(union perf_event *event, struct perf_sample *sample, |
444 | struct perf_evsel *evsel, struct machine *machine, | 445 | struct perf_evsel *evsel, struct machine *machine, |
445 | struct thread *thread, | 446 | struct thread *thread, |
446 | struct addr_location *al __maybe_unused) | 447 | struct addr_location *al) |
447 | { | 448 | { |
448 | struct perf_event_attr *attr = &evsel->attr; | 449 | struct perf_event_attr *attr = &evsel->attr; |
449 | 450 | ||
@@ -458,7 +459,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample, | |||
458 | } | 459 | } |
459 | 460 | ||
460 | if (is_bts_event(attr)) { | 461 | if (is_bts_event(attr)) { |
461 | print_sample_bts(event, sample, evsel, machine, thread); | 462 | print_sample_bts(event, sample, evsel, machine, thread, al); |
462 | return; | 463 | return; |
463 | } | 464 | } |
464 | 465 | ||
@@ -474,7 +475,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample, | |||
474 | else | 475 | else |
475 | printf("\n"); | 476 | printf("\n"); |
476 | 477 | ||
477 | perf_evsel__print_ip(evsel, event, sample, machine, | 478 | perf_evsel__print_ip(evsel, sample, machine, al, |
478 | output[attr->type].print_ip_opts, | 479 | output[attr->type].print_ip_opts, |
479 | PERF_MAX_STACK_DEPTH); | 480 | PERF_MAX_STACK_DEPTH); |
480 | } | 481 | } |
@@ -1785,7 +1786,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1785 | return -1; | 1786 | return -1; |
1786 | } | 1787 | } |
1787 | 1788 | ||
1788 | err = scripting_ops->generate_script(session->pevent, | 1789 | err = scripting_ops->generate_script(session->tevent.pevent, |
1789 | "perf-script"); | 1790 | "perf-script"); |
1790 | goto out; | 1791 | goto out; |
1791 | } | 1792 | } |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 9f2a242fa79c..56afe339661a 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include "util/intlist.h" | 11 | #include "util/intlist.h" |
12 | #include "util/thread_map.h" | 12 | #include "util/thread_map.h" |
13 | #include "util/stat.h" | 13 | #include "util/stat.h" |
14 | #include "trace-event.h" | ||
14 | 15 | ||
15 | #include <libaudit.h> | 16 | #include <libaudit.h> |
16 | #include <stdlib.h> | 17 | #include <stdlib.h> |
@@ -1430,11 +1431,11 @@ static int trace__read_syscall_info(struct trace *trace, int id) | |||
1430 | sc->fmt = syscall_fmt__find(sc->name); | 1431 | sc->fmt = syscall_fmt__find(sc->name); |
1431 | 1432 | ||
1432 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); | 1433 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); |
1433 | sc->tp_format = event_format__new("syscalls", tp_name); | 1434 | sc->tp_format = trace_event__tp_format("syscalls", tp_name); |
1434 | 1435 | ||
1435 | if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) { | 1436 | if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) { |
1436 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias); | 1437 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias); |
1437 | sc->tp_format = event_format__new("syscalls", tp_name); | 1438 | sc->tp_format = trace_event__tp_format("syscalls", tp_name); |
1438 | } | 1439 | } |
1439 | 1440 | ||
1440 | if (sc->tp_format == NULL) | 1441 | if (sc->tp_format == NULL) |
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 36e66ac40abc..bae10720a136 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -141,7 +141,6 @@ CORE_FEATURE_TESTS = \ | |||
141 | libslang \ | 141 | libslang \ |
142 | libunwind \ | 142 | libunwind \ |
143 | on-exit \ | 143 | on-exit \ |
144 | stackprotector \ | ||
145 | stackprotector-all \ | 144 | stackprotector-all \ |
146 | timerfd | 145 | timerfd |
147 | 146 | ||
@@ -209,10 +208,6 @@ ifeq ($(feature-stackprotector-all), 1) | |||
209 | CFLAGS += -fstack-protector-all | 208 | CFLAGS += -fstack-protector-all |
210 | endif | 209 | endif |
211 | 210 | ||
212 | ifeq ($(feature-stackprotector), 1) | ||
213 | CFLAGS += -Wstack-protector | ||
214 | endif | ||
215 | |||
216 | ifeq ($(DEBUG),0) | 211 | ifeq ($(DEBUG),0) |
217 | ifeq ($(feature-fortify-source), 1) | 212 | ifeq ($(feature-fortify-source), 1) |
218 | CFLAGS += -D_FORTIFY_SOURCE=2 | 213 | CFLAGS += -D_FORTIFY_SOURCE=2 |
@@ -598,3 +593,11 @@ else | |||
598 | perfexec_instdir = $(prefix)/$(perfexecdir) | 593 | perfexec_instdir = $(prefix)/$(perfexecdir) |
599 | endif | 594 | endif |
600 | perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) | 595 | perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) |
596 | |||
597 | # If we install to $(HOME) we keep the traceevent default: | ||
598 | # $(HOME)/.traceevent/plugins | ||
599 | # Otherwise we install plugins into the global $(libdir). | ||
600 | ifdef DESTDIR | ||
601 | plugindir=$(libdir)/traceevent/plugins | ||
602 | plugindir_SQ= $(subst ','\'',$(prefix)/$(plugindir)) | ||
603 | endif | ||
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile index 87e790017c69..b8bb749c3392 100644 --- a/tools/perf/config/feature-checks/Makefile +++ b/tools/perf/config/feature-checks/Makefile | |||
@@ -26,7 +26,6 @@ FILES= \ | |||
26 | test-libunwind-debug-frame \ | 26 | test-libunwind-debug-frame \ |
27 | test-on-exit \ | 27 | test-on-exit \ |
28 | test-stackprotector-all \ | 28 | test-stackprotector-all \ |
29 | test-stackprotector \ | ||
30 | test-timerfd | 29 | test-timerfd |
31 | 30 | ||
32 | CC := $(CC) -MD | 31 | CC := $(CC) -MD |
@@ -38,7 +37,7 @@ BUILD = $(CC) $(CFLAGS) $(LDFLAGS) -o $(OUTPUT)$@ $@.c | |||
38 | ############################### | 37 | ############################### |
39 | 38 | ||
40 | test-all: | 39 | test-all: |
41 | $(BUILD) -Werror -fstack-protector -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma $(LIBUNWIND_LIBS) -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl | 40 | $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma $(LIBUNWIND_LIBS) -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl |
42 | 41 | ||
43 | test-hello: | 42 | test-hello: |
44 | $(BUILD) | 43 | $(BUILD) |
@@ -46,9 +45,6 @@ test-hello: | |||
46 | test-stackprotector-all: | 45 | test-stackprotector-all: |
47 | $(BUILD) -Werror -fstack-protector-all | 46 | $(BUILD) -Werror -fstack-protector-all |
48 | 47 | ||
49 | test-stackprotector: | ||
50 | $(BUILD) -Werror -fstack-protector -Wstack-protector | ||
51 | |||
52 | test-fortify-source: | 48 | test-fortify-source: |
53 | $(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2 | 49 | $(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2 |
54 | 50 | ||
diff --git a/tools/perf/config/feature-checks/test-stackprotector.c b/tools/perf/config/feature-checks/test-stackprotector.c deleted file mode 100644 index c9f398d87868..000000000000 --- a/tools/perf/config/feature-checks/test-stackprotector.c +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | #include <stdio.h> | ||
2 | |||
3 | int main(void) | ||
4 | { | ||
5 | return puts("hi"); | ||
6 | } | ||
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 399e74c34c1a..8640a9121e72 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c | |||
@@ -16,13 +16,11 @@ | |||
16 | int verbose; | 16 | int verbose; |
17 | bool dump_trace = false, quiet = false; | 17 | bool dump_trace = false, quiet = false; |
18 | 18 | ||
19 | int eprintf(int level, const char *fmt, ...) | 19 | static int _eprintf(int level, const char *fmt, va_list args) |
20 | { | 20 | { |
21 | va_list args; | ||
22 | int ret = 0; | 21 | int ret = 0; |
23 | 22 | ||
24 | if (verbose >= level) { | 23 | if (verbose >= level) { |
25 | va_start(args, fmt); | ||
26 | if (use_browser >= 1) | 24 | if (use_browser >= 1) |
27 | ui_helpline__vshow(fmt, args); | 25 | ui_helpline__vshow(fmt, args); |
28 | else | 26 | else |
@@ -33,6 +31,32 @@ int eprintf(int level, const char *fmt, ...) | |||
33 | return ret; | 31 | return ret; |
34 | } | 32 | } |
35 | 33 | ||
34 | int eprintf(int level, const char *fmt, ...) | ||
35 | { | ||
36 | va_list args; | ||
37 | int ret; | ||
38 | |||
39 | va_start(args, fmt); | ||
40 | ret = _eprintf(level, fmt, args); | ||
41 | va_end(args); | ||
42 | |||
43 | return ret; | ||
44 | } | ||
45 | |||
46 | /* | ||
47 | * Overloading libtraceevent standard info print | ||
48 | * function, display with -v in perf. | ||
49 | */ | ||
50 | void pr_stat(const char *fmt, ...) | ||
51 | { | ||
52 | va_list args; | ||
53 | |||
54 | va_start(args, fmt); | ||
55 | _eprintf(1, fmt, args); | ||
56 | va_end(args); | ||
57 | eprintf(1, "\n"); | ||
58 | } | ||
59 | |||
36 | int dump_printf(const char *fmt, ...) | 60 | int dump_printf(const char *fmt, ...) |
37 | { | 61 | { |
38 | va_list args; | 62 | va_list args; |
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index efbd98805ad0..443694c36b03 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
@@ -17,4 +17,6 @@ void trace_event(union perf_event *event); | |||
17 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); | 17 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); |
18 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); | 18 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); |
19 | 19 | ||
20 | void pr_stat(const char *fmt, ...); | ||
21 | |||
20 | #endif /* __PERF_DEBUG_H */ | 22 | #endif /* __PERF_DEBUG_H */ |
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index af4c687cc49b..a0c7c591f4b2 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c | |||
@@ -451,6 +451,7 @@ struct dso *dso__new(const char *name) | |||
451 | dso->sorted_by_name = 0; | 451 | dso->sorted_by_name = 0; |
452 | dso->has_build_id = 0; | 452 | dso->has_build_id = 0; |
453 | dso->has_srcline = 1; | 453 | dso->has_srcline = 1; |
454 | dso->a2l_fails = 1; | ||
454 | dso->kernel = DSO_TYPE_USER; | 455 | dso->kernel = DSO_TYPE_USER; |
455 | dso->needs_swap = DSO_SWAP__UNSET; | 456 | dso->needs_swap = DSO_SWAP__UNSET; |
456 | INIT_LIST_HEAD(&dso->node); | 457 | INIT_LIST_HEAD(&dso->node); |
@@ -469,6 +470,8 @@ void dso__delete(struct dso *dso) | |||
469 | if (dso->lname_alloc) | 470 | if (dso->lname_alloc) |
470 | free(dso->long_name); | 471 | free(dso->long_name); |
471 | dso_cache__free(&dso->cache); | 472 | dso_cache__free(&dso->cache); |
473 | dso__free_a2l(dso); | ||
474 | free(dso->symsrc_filename); | ||
472 | free(dso); | 475 | free(dso); |
473 | } | 476 | } |
474 | 477 | ||
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 9ac666abbe7e..384f2d97e38e 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h | |||
@@ -77,6 +77,9 @@ struct dso { | |||
77 | struct rb_root symbols[MAP__NR_TYPES]; | 77 | struct rb_root symbols[MAP__NR_TYPES]; |
78 | struct rb_root symbol_names[MAP__NR_TYPES]; | 78 | struct rb_root symbol_names[MAP__NR_TYPES]; |
79 | struct rb_root cache; | 79 | struct rb_root cache; |
80 | void *a2l; | ||
81 | char *symsrc_filename; | ||
82 | unsigned int a2l_fails; | ||
80 | enum dso_kernel_type kernel; | 83 | enum dso_kernel_type kernel; |
81 | enum dso_swap_type needs_swap; | 84 | enum dso_swap_type needs_swap; |
82 | enum dso_binary_type symtab_type; | 85 | enum dso_binary_type symtab_type; |
@@ -166,4 +169,6 @@ static inline bool dso__is_kcore(struct dso *dso) | |||
166 | dso->data_type == DSO_BINARY_TYPE__GUEST_KCORE; | 169 | dso->data_type == DSO_BINARY_TYPE__GUEST_KCORE; |
167 | } | 170 | } |
168 | 171 | ||
172 | void dso__free_a2l(struct dso *dso); | ||
173 | |||
169 | #endif /* __PERF_DSO */ | 174 | #endif /* __PERF_DSO */ |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 76fa76431329..7bb6ee1ca19f 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -819,13 +819,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) | |||
819 | if (evlist->threads == NULL) | 819 | if (evlist->threads == NULL) |
820 | return -1; | 820 | return -1; |
821 | 821 | ||
822 | if (target->default_per_cpu) | 822 | if (target__uses_dummy_map(target)) |
823 | evlist->cpus = target->per_thread ? | ||
824 | cpu_map__dummy_new() : | ||
825 | cpu_map__new(target->cpu_list); | ||
826 | else if (target__has_task(target)) | ||
827 | evlist->cpus = cpu_map__dummy_new(); | ||
828 | else if (!target__has_cpu(target) && !target->uses_mmap) | ||
829 | evlist->cpus = cpu_map__dummy_new(); | 823 | evlist->cpus = cpu_map__dummy_new(); |
830 | else | 824 | else |
831 | evlist->cpus = cpu_map__new(target->cpu_list); | 825 | evlist->cpus = cpu_map__new(target->cpu_list); |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index b5fe7f9b2e15..7b510fd1f08d 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include "target.h" | 23 | #include "target.h" |
24 | #include "perf_regs.h" | 24 | #include "perf_regs.h" |
25 | #include "debug.h" | 25 | #include "debug.h" |
26 | #include "trace-event.h" | ||
26 | 27 | ||
27 | static struct { | 28 | static struct { |
28 | bool sample_id_all; | 29 | bool sample_id_all; |
@@ -180,47 +181,6 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) | |||
180 | return evsel; | 181 | return evsel; |
181 | } | 182 | } |
182 | 183 | ||
183 | struct event_format *event_format__new(const char *sys, const char *name) | ||
184 | { | ||
185 | int fd, n; | ||
186 | char *filename; | ||
187 | void *bf = NULL, *nbf; | ||
188 | size_t size = 0, alloc_size = 0; | ||
189 | struct event_format *format = NULL; | ||
190 | |||
191 | if (asprintf(&filename, "%s/%s/%s/format", tracing_events_path, sys, name) < 0) | ||
192 | goto out; | ||
193 | |||
194 | fd = open(filename, O_RDONLY); | ||
195 | if (fd < 0) | ||
196 | goto out_free_filename; | ||
197 | |||
198 | do { | ||
199 | if (size == alloc_size) { | ||
200 | alloc_size += BUFSIZ; | ||
201 | nbf = realloc(bf, alloc_size); | ||
202 | if (nbf == NULL) | ||
203 | goto out_free_bf; | ||
204 | bf = nbf; | ||
205 | } | ||
206 | |||
207 | n = read(fd, bf + size, alloc_size - size); | ||
208 | if (n < 0) | ||
209 | goto out_free_bf; | ||
210 | size += n; | ||
211 | } while (n > 0); | ||
212 | |||
213 | pevent_parse_format(&format, bf, size, sys); | ||
214 | |||
215 | out_free_bf: | ||
216 | free(bf); | ||
217 | close(fd); | ||
218 | out_free_filename: | ||
219 | free(filename); | ||
220 | out: | ||
221 | return format; | ||
222 | } | ||
223 | |||
224 | struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx) | 184 | struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx) |
225 | { | 185 | { |
226 | struct perf_evsel *evsel = zalloc(sizeof(*evsel)); | 186 | struct perf_evsel *evsel = zalloc(sizeof(*evsel)); |
@@ -235,7 +195,7 @@ struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int | |||
235 | if (asprintf(&evsel->name, "%s:%s", sys, name) < 0) | 195 | if (asprintf(&evsel->name, "%s:%s", sys, name) < 0) |
236 | goto out_free; | 196 | goto out_free; |
237 | 197 | ||
238 | evsel->tp_format = event_format__new(sys, name); | 198 | evsel->tp_format = trace_event__tp_format(sys, name); |
239 | if (evsel->tp_format == NULL) | 199 | if (evsel->tp_format == NULL) |
240 | goto out_free; | 200 | goto out_free; |
241 | 201 | ||
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 3e755f2bfe8f..125cdc9250ee 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -2834,11 +2834,11 @@ int perf_session__read_header(struct perf_session *session) | |||
2834 | 2834 | ||
2835 | symbol_conf.nr_events = nr_attrs; | 2835 | symbol_conf.nr_events = nr_attrs; |
2836 | 2836 | ||
2837 | perf_header__process_sections(header, fd, &session->pevent, | 2837 | perf_header__process_sections(header, fd, &session->tevent, |
2838 | perf_file_section__process); | 2838 | perf_file_section__process); |
2839 | 2839 | ||
2840 | if (perf_evlist__prepare_tracepoint_events(session->evlist, | 2840 | if (perf_evlist__prepare_tracepoint_events(session->evlist, |
2841 | session->pevent)) | 2841 | session->tevent.pevent)) |
2842 | goto out_delete_evlist; | 2842 | goto out_delete_evlist; |
2843 | 2843 | ||
2844 | return 0; | 2844 | return 0; |
@@ -3003,7 +3003,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused, | |||
3003 | lseek(fd, offset + sizeof(struct tracing_data_event), | 3003 | lseek(fd, offset + sizeof(struct tracing_data_event), |
3004 | SEEK_SET); | 3004 | SEEK_SET); |
3005 | 3005 | ||
3006 | size_read = trace_report(fd, &session->pevent, | 3006 | size_read = trace_report(fd, &session->tevent, |
3007 | session->repipe); | 3007 | session->repipe); |
3008 | padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; | 3008 | padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; |
3009 | 3009 | ||
@@ -3025,7 +3025,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused, | |||
3025 | } | 3025 | } |
3026 | 3026 | ||
3027 | perf_evlist__prepare_tracepoint_events(session->evlist, | 3027 | perf_evlist__prepare_tracepoint_events(session->evlist, |
3028 | session->pevent); | 3028 | session->tevent.pevent); |
3029 | 3029 | ||
3030 | return size_read + padding; | 3030 | return size_read + padding; |
3031 | } | 3031 | } |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 84cdb072ac83..bac817ab2068 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -502,15 +502,11 @@ static u64 machine__get_kernel_start_addr(struct machine *machine) | |||
502 | char path[PATH_MAX]; | 502 | char path[PATH_MAX]; |
503 | struct process_args args; | 503 | struct process_args args; |
504 | 504 | ||
505 | if (machine__is_host(machine)) { | 505 | if (machine__is_default_guest(machine)) |
506 | filename = "/proc/kallsyms"; | 506 | filename = (char *)symbol_conf.default_guest_kallsyms; |
507 | } else { | 507 | else { |
508 | if (machine__is_default_guest(machine)) | 508 | sprintf(path, "%s/proc/kallsyms", machine->root_dir); |
509 | filename = (char *)symbol_conf.default_guest_kallsyms; | 509 | filename = path; |
510 | else { | ||
511 | sprintf(path, "%s/proc/kallsyms", machine->root_dir); | ||
512 | filename = path; | ||
513 | } | ||
514 | } | 510 | } |
515 | 511 | ||
516 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) | 512 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) |
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index 239036fb2b2c..595bfc73d2ed 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources | |||
@@ -18,4 +18,5 @@ util/cgroup.c | |||
18 | util/rblist.c | 18 | util/rblist.c |
19 | util/strlist.c | 19 | util/strlist.c |
20 | util/fs.c | 20 | util/fs.c |
21 | util/trace-event.c | ||
21 | ../../lib/rbtree.c | 22 | ../../lib/rbtree.c |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 4ce146bae552..8a7da6f4a569 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1487,11 +1487,10 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | |||
1487 | return NULL; | 1487 | return NULL; |
1488 | } | 1488 | } |
1489 | 1489 | ||
1490 | void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | 1490 | void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, |
1491 | struct perf_sample *sample, struct machine *machine, | 1491 | struct machine *machine, struct addr_location *al, |
1492 | unsigned int print_opts, unsigned int stack_depth) | 1492 | unsigned int print_opts, unsigned int stack_depth) |
1493 | { | 1493 | { |
1494 | struct addr_location al; | ||
1495 | struct callchain_cursor_node *node; | 1494 | struct callchain_cursor_node *node; |
1496 | int print_ip = print_opts & PRINT_IP_OPT_IP; | 1495 | int print_ip = print_opts & PRINT_IP_OPT_IP; |
1497 | int print_sym = print_opts & PRINT_IP_OPT_SYM; | 1496 | int print_sym = print_opts & PRINT_IP_OPT_SYM; |
@@ -1500,15 +1499,10 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | |||
1500 | int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; | 1499 | int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; |
1501 | char s = print_oneline ? ' ' : '\t'; | 1500 | char s = print_oneline ? ' ' : '\t'; |
1502 | 1501 | ||
1503 | if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { | ||
1504 | error("problem processing %d event, skipping it.\n", | ||
1505 | event->header.type); | ||
1506 | return; | ||
1507 | } | ||
1508 | |||
1509 | if (symbol_conf.use_callchain && sample->callchain) { | 1502 | if (symbol_conf.use_callchain && sample->callchain) { |
1503 | struct addr_location node_al; | ||
1510 | 1504 | ||
1511 | if (machine__resolve_callchain(machine, evsel, al.thread, | 1505 | if (machine__resolve_callchain(machine, evsel, al->thread, |
1512 | sample, NULL, NULL, | 1506 | sample, NULL, NULL, |
1513 | PERF_MAX_STACK_DEPTH) != 0) { | 1507 | PERF_MAX_STACK_DEPTH) != 0) { |
1514 | if (verbose) | 1508 | if (verbose) |
@@ -1517,6 +1511,9 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | |||
1517 | } | 1511 | } |
1518 | callchain_cursor_commit(&callchain_cursor); | 1512 | callchain_cursor_commit(&callchain_cursor); |
1519 | 1513 | ||
1514 | if (print_symoffset) | ||
1515 | node_al = *al; | ||
1516 | |||
1520 | while (stack_depth) { | 1517 | while (stack_depth) { |
1521 | node = callchain_cursor_current(&callchain_cursor); | 1518 | node = callchain_cursor_current(&callchain_cursor); |
1522 | if (!node) | 1519 | if (!node) |
@@ -1531,9 +1528,9 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | |||
1531 | if (print_sym) { | 1528 | if (print_sym) { |
1532 | printf(" "); | 1529 | printf(" "); |
1533 | if (print_symoffset) { | 1530 | if (print_symoffset) { |
1534 | al.addr = node->ip; | 1531 | node_al.addr = node->ip; |
1535 | al.map = node->map; | 1532 | node_al.map = node->map; |
1536 | symbol__fprintf_symname_offs(node->sym, &al, stdout); | 1533 | symbol__fprintf_symname_offs(node->sym, &node_al, stdout); |
1537 | } else | 1534 | } else |
1538 | symbol__fprintf_symname(node->sym, stdout); | 1535 | symbol__fprintf_symname(node->sym, stdout); |
1539 | } | 1536 | } |
@@ -1553,7 +1550,7 @@ next: | |||
1553 | } | 1550 | } |
1554 | 1551 | ||
1555 | } else { | 1552 | } else { |
1556 | if (al.sym && al.sym->ignore) | 1553 | if (al->sym && al->sym->ignore) |
1557 | return; | 1554 | return; |
1558 | 1555 | ||
1559 | if (print_ip) | 1556 | if (print_ip) |
@@ -1562,15 +1559,15 @@ next: | |||
1562 | if (print_sym) { | 1559 | if (print_sym) { |
1563 | printf(" "); | 1560 | printf(" "); |
1564 | if (print_symoffset) | 1561 | if (print_symoffset) |
1565 | symbol__fprintf_symname_offs(al.sym, &al, | 1562 | symbol__fprintf_symname_offs(al->sym, al, |
1566 | stdout); | 1563 | stdout); |
1567 | else | 1564 | else |
1568 | symbol__fprintf_symname(al.sym, stdout); | 1565 | symbol__fprintf_symname(al->sym, stdout); |
1569 | } | 1566 | } |
1570 | 1567 | ||
1571 | if (print_dso) { | 1568 | if (print_dso) { |
1572 | printf(" ("); | 1569 | printf(" ("); |
1573 | map__fprintf_dsoname(al.map, stdout); | 1570 | map__fprintf_dsoname(al->map, stdout); |
1574 | printf(")"); | 1571 | printf(")"); |
1575 | } | 1572 | } |
1576 | } | 1573 | } |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 50f640958f0f..004d3e8116aa 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -1,6 +1,7 @@ | |||
1 | #ifndef __PERF_SESSION_H | 1 | #ifndef __PERF_SESSION_H |
2 | #define __PERF_SESSION_H | 2 | #define __PERF_SESSION_H |
3 | 3 | ||
4 | #include "trace-event.h" | ||
4 | #include "hist.h" | 5 | #include "hist.h" |
5 | #include "event.h" | 6 | #include "event.h" |
6 | #include "header.h" | 7 | #include "header.h" |
@@ -32,7 +33,7 @@ struct perf_session { | |||
32 | struct perf_header header; | 33 | struct perf_header header; |
33 | struct machines machines; | 34 | struct machines machines; |
34 | struct perf_evlist *evlist; | 35 | struct perf_evlist *evlist; |
35 | struct pevent *pevent; | 36 | struct trace_event tevent; |
36 | struct events_stats stats; | 37 | struct events_stats stats; |
37 | bool repipe; | 38 | bool repipe; |
38 | struct ordered_samples ordered_samples; | 39 | struct ordered_samples ordered_samples; |
@@ -105,8 +106,8 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); | |||
105 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | 106 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, |
106 | unsigned int type); | 107 | unsigned int type); |
107 | 108 | ||
108 | void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | 109 | void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, |
109 | struct perf_sample *sample, struct machine *machine, | 110 | struct machine *machine, struct addr_location *al, |
110 | unsigned int print_opts, unsigned int stack_depth); | 111 | unsigned int print_opts, unsigned int stack_depth); |
111 | 112 | ||
112 | int perf_session__cpu_bitmap(struct perf_session *session, | 113 | int perf_session__cpu_bitmap(struct perf_session *session, |
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index d11aefbc4b8d..0c075560ad46 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c | |||
@@ -146,18 +146,24 @@ static void addr2line_cleanup(struct a2l_data *a2l) | |||
146 | } | 146 | } |
147 | 147 | ||
148 | static int addr2line(const char *dso_name, unsigned long addr, | 148 | static int addr2line(const char *dso_name, unsigned long addr, |
149 | char **file, unsigned int *line) | 149 | char **file, unsigned int *line, struct dso *dso) |
150 | { | 150 | { |
151 | int ret = 0; | 151 | int ret = 0; |
152 | struct a2l_data *a2l; | 152 | struct a2l_data *a2l = dso->a2l; |
153 | |||
154 | if (!a2l) { | ||
155 | dso->a2l = addr2line_init(dso_name); | ||
156 | a2l = dso->a2l; | ||
157 | } | ||
153 | 158 | ||
154 | a2l = addr2line_init(dso_name); | ||
155 | if (a2l == NULL) { | 159 | if (a2l == NULL) { |
156 | pr_warning("addr2line_init failed for %s\n", dso_name); | 160 | pr_warning("addr2line_init failed for %s\n", dso_name); |
157 | return 0; | 161 | return 0; |
158 | } | 162 | } |
159 | 163 | ||
160 | a2l->addr = addr; | 164 | a2l->addr = addr; |
165 | a2l->found = false; | ||
166 | |||
161 | bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); | 167 | bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); |
162 | 168 | ||
163 | if (a2l->found && a2l->filename) { | 169 | if (a2l->found && a2l->filename) { |
@@ -168,14 +174,26 @@ static int addr2line(const char *dso_name, unsigned long addr, | |||
168 | ret = 1; | 174 | ret = 1; |
169 | } | 175 | } |
170 | 176 | ||
171 | addr2line_cleanup(a2l); | ||
172 | return ret; | 177 | return ret; |
173 | } | 178 | } |
174 | 179 | ||
180 | void dso__free_a2l(struct dso *dso) | ||
181 | { | ||
182 | struct a2l_data *a2l = dso->a2l; | ||
183 | |||
184 | if (!a2l) | ||
185 | return; | ||
186 | |||
187 | addr2line_cleanup(a2l); | ||
188 | |||
189 | dso->a2l = NULL; | ||
190 | } | ||
191 | |||
175 | #else /* HAVE_LIBBFD_SUPPORT */ | 192 | #else /* HAVE_LIBBFD_SUPPORT */ |
176 | 193 | ||
177 | static int addr2line(const char *dso_name, unsigned long addr, | 194 | static int addr2line(const char *dso_name, unsigned long addr, |
178 | char **file, unsigned int *line_nr) | 195 | char **file, unsigned int *line_nr, |
196 | struct dso *dso __maybe_unused) | ||
179 | { | 197 | { |
180 | FILE *fp; | 198 | FILE *fp; |
181 | char cmd[PATH_MAX]; | 199 | char cmd[PATH_MAX]; |
@@ -219,42 +237,58 @@ out: | |||
219 | pclose(fp); | 237 | pclose(fp); |
220 | return ret; | 238 | return ret; |
221 | } | 239 | } |
240 | |||
241 | void dso__free_a2l(struct dso *dso __maybe_unused) | ||
242 | { | ||
243 | } | ||
244 | |||
222 | #endif /* HAVE_LIBBFD_SUPPORT */ | 245 | #endif /* HAVE_LIBBFD_SUPPORT */ |
223 | 246 | ||
247 | /* | ||
248 | * Number of addr2line failures (without success) before disabling it for that | ||
249 | * dso. | ||
250 | */ | ||
251 | #define A2L_FAIL_LIMIT 123 | ||
252 | |||
224 | char *get_srcline(struct dso *dso, unsigned long addr) | 253 | char *get_srcline(struct dso *dso, unsigned long addr) |
225 | { | 254 | { |
226 | char *file = NULL; | 255 | char *file = NULL; |
227 | unsigned line = 0; | 256 | unsigned line = 0; |
228 | char *srcline; | 257 | char *srcline; |
229 | char *dso_name = dso->long_name; | 258 | char *dso_name; |
230 | size_t size; | ||
231 | 259 | ||
232 | if (!dso->has_srcline) | 260 | if (!dso->has_srcline) |
233 | return SRCLINE_UNKNOWN; | 261 | return SRCLINE_UNKNOWN; |
234 | 262 | ||
263 | if (dso->symsrc_filename) | ||
264 | dso_name = dso->symsrc_filename; | ||
265 | else | ||
266 | dso_name = dso->long_name; | ||
267 | |||
235 | if (dso_name[0] == '[') | 268 | if (dso_name[0] == '[') |
236 | goto out; | 269 | goto out; |
237 | 270 | ||
238 | if (!strncmp(dso_name, "/tmp/perf-", 10)) | 271 | if (!strncmp(dso_name, "/tmp/perf-", 10)) |
239 | goto out; | 272 | goto out; |
240 | 273 | ||
241 | if (!addr2line(dso_name, addr, &file, &line)) | 274 | if (!addr2line(dso_name, addr, &file, &line, dso)) |
242 | goto out; | 275 | goto out; |
243 | 276 | ||
244 | /* just calculate actual length */ | 277 | if (asprintf(&srcline, "%s:%u", file, line) < 0) { |
245 | size = snprintf(NULL, 0, "%s:%u", file, line) + 1; | 278 | free(file); |
279 | goto out; | ||
280 | } | ||
246 | 281 | ||
247 | srcline = malloc(size); | 282 | dso->a2l_fails = 0; |
248 | if (srcline) | ||
249 | snprintf(srcline, size, "%s:%u", file, line); | ||
250 | else | ||
251 | srcline = SRCLINE_UNKNOWN; | ||
252 | 283 | ||
253 | free(file); | 284 | free(file); |
254 | return srcline; | 285 | return srcline; |
255 | 286 | ||
256 | out: | 287 | out: |
257 | dso->has_srcline = 0; | 288 | if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) { |
289 | dso->has_srcline = 0; | ||
290 | dso__free_a2l(dso); | ||
291 | } | ||
258 | return SRCLINE_UNKNOWN; | 292 | return SRCLINE_UNKNOWN; |
259 | } | 293 | } |
260 | 294 | ||
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index 2d2dd0532b5a..ac7070a2f2b6 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c | |||
@@ -253,6 +253,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused, | |||
253 | if (!ss->name) | 253 | if (!ss->name) |
254 | goto out_close; | 254 | goto out_close; |
255 | 255 | ||
256 | ss->fd = fd; | ||
256 | ss->type = type; | 257 | ss->type = type; |
257 | 258 | ||
258 | return 0; | 259 | return 0; |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 360eefecb81d..de87dbac50a0 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -1336,6 +1336,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
1336 | if (!syms_ss && symsrc__has_symtab(ss)) { | 1336 | if (!syms_ss && symsrc__has_symtab(ss)) { |
1337 | syms_ss = ss; | 1337 | syms_ss = ss; |
1338 | next_slot = true; | 1338 | next_slot = true; |
1339 | if (!dso->symsrc_filename) | ||
1340 | dso->symsrc_filename = strdup(name); | ||
1339 | } | 1341 | } |
1340 | 1342 | ||
1341 | if (!runtime_ss && symsrc__possibly_runtime(ss)) { | 1343 | if (!runtime_ss && symsrc__possibly_runtime(ss)) { |
diff --git a/tools/perf/util/target.h b/tools/perf/util/target.h index 31dd2e9a27d0..7381b1ca4041 100644 --- a/tools/perf/util/target.h +++ b/tools/perf/util/target.h | |||
@@ -63,4 +63,17 @@ static inline bool target__none(struct target *target) | |||
63 | return !target__has_task(target) && !target__has_cpu(target); | 63 | return !target__has_task(target) && !target__has_cpu(target); |
64 | } | 64 | } |
65 | 65 | ||
66 | static inline bool target__uses_dummy_map(struct target *target) | ||
67 | { | ||
68 | bool use_dummy = false; | ||
69 | |||
70 | if (target->default_per_cpu) | ||
71 | use_dummy = target->per_thread ? true : false; | ||
72 | else if (target__has_task(target) || | ||
73 | (!target__has_cpu(target) && !target->uses_mmap)) | ||
74 | use_dummy = true; | ||
75 | |||
76 | return use_dummy; | ||
77 | } | ||
78 | |||
66 | #endif /* _PERF_TARGET_H */ | 79 | #endif /* _PERF_TARGET_H */ |
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 6681f71f2f95..e0d6d07f6848 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
@@ -28,19 +28,6 @@ | |||
28 | #include "util.h" | 28 | #include "util.h" |
29 | #include "trace-event.h" | 29 | #include "trace-event.h" |
30 | 30 | ||
31 | struct pevent *read_trace_init(int file_bigendian, int host_bigendian) | ||
32 | { | ||
33 | struct pevent *pevent = pevent_alloc(); | ||
34 | |||
35 | if (pevent != NULL) { | ||
36 | pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); | ||
37 | pevent_set_file_bigendian(pevent, file_bigendian); | ||
38 | pevent_set_host_bigendian(pevent, host_bigendian); | ||
39 | } | ||
40 | |||
41 | return pevent; | ||
42 | } | ||
43 | |||
44 | static int get_common_field(struct scripting_context *context, | 31 | static int get_common_field(struct scripting_context *context, |
45 | int *offset, int *size, const char *type) | 32 | int *offset, int *size, const char *type) |
46 | { | 33 | { |
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index f2112270c663..e113e180c48f 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c | |||
@@ -343,7 +343,7 @@ static int read_event_files(struct pevent *pevent) | |||
343 | return 0; | 343 | return 0; |
344 | } | 344 | } |
345 | 345 | ||
346 | ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) | 346 | ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) |
347 | { | 347 | { |
348 | char buf[BUFSIZ]; | 348 | char buf[BUFSIZ]; |
349 | char test[] = { 23, 8, 68 }; | 349 | char test[] = { 23, 8, 68 }; |
@@ -356,11 +356,9 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) | |||
356 | int host_bigendian; | 356 | int host_bigendian; |
357 | int file_long_size; | 357 | int file_long_size; |
358 | int file_page_size; | 358 | int file_page_size; |
359 | struct pevent *pevent; | 359 | struct pevent *pevent = NULL; |
360 | int err; | 360 | int err; |
361 | 361 | ||
362 | *ppevent = NULL; | ||
363 | |||
364 | repipe = __repipe; | 362 | repipe = __repipe; |
365 | input_fd = fd; | 363 | input_fd = fd; |
366 | 364 | ||
@@ -390,12 +388,17 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) | |||
390 | file_bigendian = buf[0]; | 388 | file_bigendian = buf[0]; |
391 | host_bigendian = bigendian(); | 389 | host_bigendian = bigendian(); |
392 | 390 | ||
393 | pevent = read_trace_init(file_bigendian, host_bigendian); | 391 | if (trace_event__init(tevent)) { |
394 | if (pevent == NULL) { | 392 | pr_debug("trace_event__init failed"); |
395 | pr_debug("read_trace_init failed"); | ||
396 | goto out; | 393 | goto out; |
397 | } | 394 | } |
398 | 395 | ||
396 | pevent = tevent->pevent; | ||
397 | |||
398 | pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); | ||
399 | pevent_set_file_bigendian(pevent, file_bigendian); | ||
400 | pevent_set_host_bigendian(pevent, host_bigendian); | ||
401 | |||
399 | if (do_read(buf, 1) < 0) | 402 | if (do_read(buf, 1) < 0) |
400 | goto out; | 403 | goto out; |
401 | file_long_size = buf[0]; | 404 | file_long_size = buf[0]; |
@@ -432,11 +435,10 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) | |||
432 | pevent_print_printk(pevent); | 435 | pevent_print_printk(pevent); |
433 | } | 436 | } |
434 | 437 | ||
435 | *ppevent = pevent; | ||
436 | pevent = NULL; | 438 | pevent = NULL; |
437 | 439 | ||
438 | out: | 440 | out: |
439 | if (pevent) | 441 | if (pevent) |
440 | pevent_free(pevent); | 442 | trace_event__cleanup(tevent); |
441 | return size; | 443 | return size; |
442 | } | 444 | } |
diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c new file mode 100644 index 000000000000..d9f5f6137ab3 --- /dev/null +++ b/tools/perf/util/trace-event.c | |||
@@ -0,0 +1,82 @@ | |||
1 | |||
2 | #include <stdio.h> | ||
3 | #include <unistd.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <errno.h> | ||
6 | #include <sys/types.h> | ||
7 | #include <sys/stat.h> | ||
8 | #include <fcntl.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <traceevent/event-parse.h> | ||
11 | #include "trace-event.h" | ||
12 | #include "util.h" | ||
13 | |||
14 | /* | ||
15 | * global trace_event object used by trace_event__tp_format | ||
16 | * | ||
17 | * TODO There's no cleanup call for this. Add some sort of | ||
18 | * __exit function support and call trace_event__cleanup | ||
19 | * there. | ||
20 | */ | ||
21 | static struct trace_event tevent; | ||
22 | |||
23 | int trace_event__init(struct trace_event *t) | ||
24 | { | ||
25 | struct pevent *pevent = pevent_alloc(); | ||
26 | |||
27 | if (pevent) { | ||
28 | t->plugin_list = traceevent_load_plugins(pevent); | ||
29 | t->pevent = pevent; | ||
30 | } | ||
31 | |||
32 | return pevent ? 0 : -1; | ||
33 | } | ||
34 | |||
35 | void trace_event__cleanup(struct trace_event *t) | ||
36 | { | ||
37 | pevent_free(t->pevent); | ||
38 | traceevent_unload_plugins(t->plugin_list); | ||
39 | } | ||
40 | |||
41 | static struct event_format* | ||
42 | tp_format(const char *sys, const char *name) | ||
43 | { | ||
44 | struct pevent *pevent = tevent.pevent; | ||
45 | struct event_format *event = NULL; | ||
46 | char path[PATH_MAX]; | ||
47 | size_t size; | ||
48 | char *data; | ||
49 | |||
50 | scnprintf(path, PATH_MAX, "%s/%s/%s/format", | ||
51 | tracing_events_path, sys, name); | ||
52 | |||
53 | if (filename__read_str(path, &data, &size)) | ||
54 | return NULL; | ||
55 | |||
56 | pevent_parse_format(pevent, &event, data, size, sys); | ||
57 | |||
58 | free(data); | ||
59 | return event; | ||
60 | } | ||
61 | |||
62 | struct event_format* | ||
63 | trace_event__tp_format(const char *sys, const char *name) | ||
64 | { | ||
65 | static bool initialized; | ||
66 | |||
67 | if (!initialized) { | ||
68 | int be = traceevent_host_bigendian(); | ||
69 | struct pevent *pevent; | ||
70 | |||
71 | if (trace_event__init(&tevent)) | ||
72 | return NULL; | ||
73 | |||
74 | pevent = tevent.pevent; | ||
75 | pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); | ||
76 | pevent_set_file_bigendian(pevent, be); | ||
77 | pevent_set_host_bigendian(pevent, be); | ||
78 | initialized = true; | ||
79 | } | ||
80 | |||
81 | return tp_format(sys, name); | ||
82 | } | ||
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 04df63114109..3a01618c5b87 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h | |||
@@ -3,17 +3,26 @@ | |||
3 | 3 | ||
4 | #include <traceevent/event-parse.h> | 4 | #include <traceevent/event-parse.h> |
5 | #include "parse-events.h" | 5 | #include "parse-events.h" |
6 | #include "session.h" | ||
7 | 6 | ||
8 | struct machine; | 7 | struct machine; |
9 | struct perf_sample; | 8 | struct perf_sample; |
10 | union perf_event; | 9 | union perf_event; |
11 | struct perf_tool; | 10 | struct perf_tool; |
12 | struct thread; | 11 | struct thread; |
12 | struct plugin_list; | ||
13 | |||
14 | struct trace_event { | ||
15 | struct pevent *pevent; | ||
16 | struct plugin_list *plugin_list; | ||
17 | }; | ||
18 | |||
19 | int trace_event__init(struct trace_event *t); | ||
20 | void trace_event__cleanup(struct trace_event *t); | ||
21 | struct event_format* | ||
22 | trace_event__tp_format(const char *sys, const char *name); | ||
13 | 23 | ||
14 | int bigendian(void); | 24 | int bigendian(void); |
15 | 25 | ||
16 | struct pevent *read_trace_init(int file_bigendian, int host_bigendian); | ||
17 | void event_format__print(struct event_format *event, | 26 | void event_format__print(struct event_format *event, |
18 | int cpu, void *data, int size); | 27 | int cpu, void *data, int size); |
19 | 28 | ||
@@ -27,7 +36,7 @@ raw_field_value(struct event_format *event, const char *name, void *data); | |||
27 | void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); | 36 | void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); |
28 | void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); | 37 | void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); |
29 | 38 | ||
30 | ssize_t trace_report(int fd, struct pevent **pevent, bool repipe); | 39 | ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe); |
31 | 40 | ||
32 | struct event_format *trace_find_next_event(struct pevent *pevent, | 41 | struct event_format *trace_find_next_event(struct pevent *pevent, |
33 | struct event_format *event); | 42 | struct event_format *event); |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index b1d5376b9dd9..bae8756a4eb1 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -6,6 +6,8 @@ | |||
6 | #endif | 6 | #endif |
7 | #include <stdio.h> | 7 | #include <stdio.h> |
8 | #include <stdlib.h> | 8 | #include <stdlib.h> |
9 | #include <string.h> | ||
10 | #include <errno.h> | ||
9 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
10 | 12 | ||
11 | /* | 13 | /* |
@@ -433,3 +435,50 @@ int filename__read_int(const char *filename, int *value) | |||
433 | close(fd); | 435 | close(fd); |
434 | return err; | 436 | return err; |
435 | } | 437 | } |
438 | |||
439 | int filename__read_str(const char *filename, char **buf, size_t *sizep) | ||
440 | { | ||
441 | size_t size = 0, alloc_size = 0; | ||
442 | void *bf = NULL, *nbf; | ||
443 | int fd, n, err = 0; | ||
444 | |||
445 | fd = open(filename, O_RDONLY); | ||
446 | if (fd < 0) | ||
447 | return -errno; | ||
448 | |||
449 | do { | ||
450 | if (size == alloc_size) { | ||
451 | alloc_size += BUFSIZ; | ||
452 | nbf = realloc(bf, alloc_size); | ||
453 | if (!nbf) { | ||
454 | err = -ENOMEM; | ||
455 | break; | ||
456 | } | ||
457 | |||
458 | bf = nbf; | ||
459 | } | ||
460 | |||
461 | n = read(fd, bf + size, alloc_size - size); | ||
462 | if (n < 0) { | ||
463 | if (size) { | ||
464 | pr_warning("read failed %d: %s\n", | ||
465 | errno, strerror(errno)); | ||
466 | err = 0; | ||
467 | } else | ||
468 | err = -errno; | ||
469 | |||
470 | break; | ||
471 | } | ||
472 | |||
473 | size += n; | ||
474 | } while (n > 0); | ||
475 | |||
476 | if (!err) { | ||
477 | *sizep = size; | ||
478 | *buf = bf; | ||
479 | } else | ||
480 | free(bf); | ||
481 | |||
482 | close(fd); | ||
483 | return err; | ||
484 | } | ||
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index ce0f73d4d91f..adb39f251f90 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -308,4 +308,5 @@ char *get_srcline(struct dso *dso, unsigned long addr); | |||
308 | void free_srcline(char *srcline); | 308 | void free_srcline(char *srcline); |
309 | 309 | ||
310 | int filename__read_int(const char *filename, int *value); | 310 | int filename__read_int(const char *filename, int *value); |
311 | int filename__read_str(const char *filename, char **buf, size_t *sizep); | ||
311 | #endif /* GIT_COMPAT_UTIL_H */ | 312 | #endif /* GIT_COMPAT_UTIL_H */ |