diff options
Diffstat (limited to 'tools/perf/builtin-probe.c')
-rw-r--r-- | tools/perf/builtin-probe.c | 153 |
1 files changed, 141 insertions, 12 deletions
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 199d5e19554f..2c0e64d0b4aa 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include "builtin.h" | 36 | #include "builtin.h" |
37 | #include "util/util.h" | 37 | #include "util/util.h" |
38 | #include "util/strlist.h" | 38 | #include "util/strlist.h" |
39 | #include "util/strfilter.h" | ||
39 | #include "util/symbol.h" | 40 | #include "util/symbol.h" |
40 | #include "util/debug.h" | 41 | #include "util/debug.h" |
41 | #include "util/debugfs.h" | 42 | #include "util/debugfs.h" |
@@ -43,6 +44,8 @@ | |||
43 | #include "util/probe-finder.h" | 44 | #include "util/probe-finder.h" |
44 | #include "util/probe-event.h" | 45 | #include "util/probe-event.h" |
45 | 46 | ||
47 | #define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*" | ||
48 | #define DEFAULT_FUNC_FILTER "!_*" | ||
46 | #define MAX_PATH_LEN 256 | 49 | #define MAX_PATH_LEN 256 |
47 | 50 | ||
48 | /* Session management structure */ | 51 | /* Session management structure */ |
@@ -50,14 +53,19 @@ static struct { | |||
50 | bool list_events; | 53 | bool list_events; |
51 | bool force_add; | 54 | bool force_add; |
52 | bool show_lines; | 55 | bool show_lines; |
56 | bool show_vars; | ||
57 | bool show_ext_vars; | ||
58 | bool show_funcs; | ||
59 | bool mod_events; | ||
53 | int nevents; | 60 | int nevents; |
54 | struct perf_probe_event events[MAX_PROBES]; | 61 | struct perf_probe_event events[MAX_PROBES]; |
55 | struct strlist *dellist; | 62 | struct strlist *dellist; |
56 | struct line_range line_range; | 63 | struct line_range line_range; |
64 | const char *target_module; | ||
57 | int max_probe_points; | 65 | int max_probe_points; |
66 | struct strfilter *filter; | ||
58 | } params; | 67 | } params; |
59 | 68 | ||
60 | |||
61 | /* Parse an event definition. Note that any error must die. */ | 69 | /* Parse an event definition. Note that any error must die. */ |
62 | static int parse_probe_event(const char *str) | 70 | static int parse_probe_event(const char *str) |
63 | { | 71 | { |
@@ -92,6 +100,7 @@ static int parse_probe_event_argv(int argc, const char **argv) | |||
92 | len = 0; | 100 | len = 0; |
93 | for (i = 0; i < argc; i++) | 101 | for (i = 0; i < argc; i++) |
94 | len += sprintf(&buf[len], "%s ", argv[i]); | 102 | len += sprintf(&buf[len], "%s ", argv[i]); |
103 | params.mod_events = true; | ||
95 | ret = parse_probe_event(buf); | 104 | ret = parse_probe_event(buf); |
96 | free(buf); | 105 | free(buf); |
97 | return ret; | 106 | return ret; |
@@ -100,9 +109,10 @@ static int parse_probe_event_argv(int argc, const char **argv) | |||
100 | static int opt_add_probe_event(const struct option *opt __used, | 109 | static int opt_add_probe_event(const struct option *opt __used, |
101 | const char *str, int unset __used) | 110 | const char *str, int unset __used) |
102 | { | 111 | { |
103 | if (str) | 112 | if (str) { |
113 | params.mod_events = true; | ||
104 | return parse_probe_event(str); | 114 | return parse_probe_event(str); |
105 | else | 115 | } else |
106 | return 0; | 116 | return 0; |
107 | } | 117 | } |
108 | 118 | ||
@@ -110,6 +120,7 @@ static int opt_del_probe_event(const struct option *opt __used, | |||
110 | const char *str, int unset __used) | 120 | const char *str, int unset __used) |
111 | { | 121 | { |
112 | if (str) { | 122 | if (str) { |
123 | params.mod_events = true; | ||
113 | if (!params.dellist) | 124 | if (!params.dellist) |
114 | params.dellist = strlist__new(true, NULL); | 125 | params.dellist = strlist__new(true, NULL); |
115 | strlist__add(params.dellist, str); | 126 | strlist__add(params.dellist, str); |
@@ -130,15 +141,56 @@ static int opt_show_lines(const struct option *opt __used, | |||
130 | 141 | ||
131 | return ret; | 142 | return ret; |
132 | } | 143 | } |
144 | |||
145 | static int opt_show_vars(const struct option *opt __used, | ||
146 | const char *str, int unset __used) | ||
147 | { | ||
148 | struct perf_probe_event *pev = ¶ms.events[params.nevents]; | ||
149 | int ret; | ||
150 | |||
151 | if (!str) | ||
152 | return 0; | ||
153 | |||
154 | ret = parse_probe_event(str); | ||
155 | if (!ret && pev->nargs != 0) { | ||
156 | pr_err(" Error: '--vars' doesn't accept arguments.\n"); | ||
157 | return -EINVAL; | ||
158 | } | ||
159 | params.show_vars = true; | ||
160 | |||
161 | return ret; | ||
162 | } | ||
133 | #endif | 163 | #endif |
134 | 164 | ||
165 | static int opt_set_filter(const struct option *opt __used, | ||
166 | const char *str, int unset __used) | ||
167 | { | ||
168 | const char *err; | ||
169 | |||
170 | if (str) { | ||
171 | pr_debug2("Set filter: %s\n", str); | ||
172 | if (params.filter) | ||
173 | strfilter__delete(params.filter); | ||
174 | params.filter = strfilter__new(str, &err); | ||
175 | if (!params.filter) { | ||
176 | pr_err("Filter parse error at %td.\n", err - str + 1); | ||
177 | pr_err("Source: \"%s\"\n", str); | ||
178 | pr_err(" %*c\n", (int)(err - str + 1), '^'); | ||
179 | return -EINVAL; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
135 | static const char * const probe_usage[] = { | 186 | static const char * const probe_usage[] = { |
136 | "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", | 187 | "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", |
137 | "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", | 188 | "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", |
138 | "perf probe [<options>] --del '[GROUP:]EVENT' ...", | 189 | "perf probe [<options>] --del '[GROUP:]EVENT' ...", |
139 | "perf probe --list", | 190 | "perf probe --list", |
140 | #ifdef DWARF_SUPPORT | 191 | #ifdef DWARF_SUPPORT |
141 | "perf probe --line 'LINEDESC'", | 192 | "perf probe [<options>] --line 'LINEDESC'", |
193 | "perf probe [<options>] --vars 'PROBEPOINT'", | ||
142 | #endif | 194 | #endif |
143 | NULL | 195 | NULL |
144 | }; | 196 | }; |
@@ -180,14 +232,28 @@ static const struct option options[] = { | |||
180 | OPT_CALLBACK('L', "line", NULL, | 232 | OPT_CALLBACK('L', "line", NULL, |
181 | "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]", | 233 | "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]", |
182 | "Show source code lines.", opt_show_lines), | 234 | "Show source code lines.", opt_show_lines), |
235 | OPT_CALLBACK('V', "vars", NULL, | ||
236 | "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT", | ||
237 | "Show accessible variables on PROBEDEF", opt_show_vars), | ||
238 | OPT_BOOLEAN('\0', "externs", ¶ms.show_ext_vars, | ||
239 | "Show external variables too (with --vars only)"), | ||
183 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 240 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
184 | "file", "vmlinux pathname"), | 241 | "file", "vmlinux pathname"), |
185 | OPT_STRING('s', "source", &symbol_conf.source_prefix, | 242 | OPT_STRING('s', "source", &symbol_conf.source_prefix, |
186 | "directory", "path to kernel source"), | 243 | "directory", "path to kernel source"), |
244 | OPT_STRING('m', "module", ¶ms.target_module, | ||
245 | "modname", "target module name"), | ||
187 | #endif | 246 | #endif |
188 | OPT__DRY_RUN(&probe_event_dry_run), | 247 | OPT__DRY_RUN(&probe_event_dry_run), |
189 | OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, | 248 | OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, |
190 | "Set how many probe points can be found for a probe."), | 249 | "Set how many probe points can be found for a probe."), |
250 | OPT_BOOLEAN('F', "funcs", ¶ms.show_funcs, | ||
251 | "Show potential probe-able functions."), | ||
252 | OPT_CALLBACK('\0', "filter", NULL, | ||
253 | "[!]FILTER", "Set a filter (with --vars/funcs only)\n" | ||
254 | "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n" | ||
255 | "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)", | ||
256 | opt_set_filter), | ||
191 | OPT_END() | 257 | OPT_END() |
192 | }; | 258 | }; |
193 | 259 | ||
@@ -213,11 +279,16 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
213 | params.max_probe_points = MAX_PROBES; | 279 | params.max_probe_points = MAX_PROBES; |
214 | 280 | ||
215 | if ((!params.nevents && !params.dellist && !params.list_events && | 281 | if ((!params.nevents && !params.dellist && !params.list_events && |
216 | !params.show_lines)) | 282 | !params.show_lines && !params.show_funcs)) |
217 | usage_with_options(probe_usage, options); | 283 | usage_with_options(probe_usage, options); |
218 | 284 | ||
285 | /* | ||
286 | * Only consider the user's kernel image path if given. | ||
287 | */ | ||
288 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); | ||
289 | |||
219 | if (params.list_events) { | 290 | if (params.list_events) { |
220 | if (params.nevents != 0 || params.dellist) { | 291 | if (params.mod_events) { |
221 | pr_err(" Error: Don't use --list with --add/--del.\n"); | 292 | pr_err(" Error: Don't use --list with --add/--del.\n"); |
222 | usage_with_options(probe_usage, options); | 293 | usage_with_options(probe_usage, options); |
223 | } | 294 | } |
@@ -225,26 +296,83 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
225 | pr_err(" Error: Don't use --list with --line.\n"); | 296 | pr_err(" Error: Don't use --list with --line.\n"); |
226 | usage_with_options(probe_usage, options); | 297 | usage_with_options(probe_usage, options); |
227 | } | 298 | } |
299 | if (params.show_vars) { | ||
300 | pr_err(" Error: Don't use --list with --vars.\n"); | ||
301 | usage_with_options(probe_usage, options); | ||
302 | } | ||
303 | if (params.show_funcs) { | ||
304 | pr_err(" Error: Don't use --list with --funcs.\n"); | ||
305 | usage_with_options(probe_usage, options); | ||
306 | } | ||
228 | ret = show_perf_probe_events(); | 307 | ret = show_perf_probe_events(); |
229 | if (ret < 0) | 308 | if (ret < 0) |
230 | pr_err(" Error: Failed to show event list. (%d)\n", | 309 | pr_err(" Error: Failed to show event list. (%d)\n", |
231 | ret); | 310 | ret); |
232 | return ret; | 311 | return ret; |
233 | } | 312 | } |
313 | if (params.show_funcs) { | ||
314 | if (params.nevents != 0 || params.dellist) { | ||
315 | pr_err(" Error: Don't use --funcs with" | ||
316 | " --add/--del.\n"); | ||
317 | usage_with_options(probe_usage, options); | ||
318 | } | ||
319 | if (params.show_lines) { | ||
320 | pr_err(" Error: Don't use --funcs with --line.\n"); | ||
321 | usage_with_options(probe_usage, options); | ||
322 | } | ||
323 | if (params.show_vars) { | ||
324 | pr_err(" Error: Don't use --funcs with --vars.\n"); | ||
325 | usage_with_options(probe_usage, options); | ||
326 | } | ||
327 | if (!params.filter) | ||
328 | params.filter = strfilter__new(DEFAULT_FUNC_FILTER, | ||
329 | NULL); | ||
330 | ret = show_available_funcs(params.target_module, | ||
331 | params.filter); | ||
332 | strfilter__delete(params.filter); | ||
333 | if (ret < 0) | ||
334 | pr_err(" Error: Failed to show functions." | ||
335 | " (%d)\n", ret); | ||
336 | return ret; | ||
337 | } | ||
234 | 338 | ||
235 | #ifdef DWARF_SUPPORT | 339 | #ifdef DWARF_SUPPORT |
236 | if (params.show_lines) { | 340 | if (params.show_lines) { |
237 | if (params.nevents != 0 || params.dellist) { | 341 | if (params.mod_events) { |
238 | pr_warning(" Error: Don't use --line with" | 342 | pr_err(" Error: Don't use --line with" |
239 | " --add/--del.\n"); | 343 | " --add/--del.\n"); |
344 | usage_with_options(probe_usage, options); | ||
345 | } | ||
346 | if (params.show_vars) { | ||
347 | pr_err(" Error: Don't use --line with --vars.\n"); | ||
240 | usage_with_options(probe_usage, options); | 348 | usage_with_options(probe_usage, options); |
241 | } | 349 | } |
242 | 350 | ||
243 | ret = show_line_range(¶ms.line_range); | 351 | ret = show_line_range(¶ms.line_range, params.target_module); |
244 | if (ret < 0) | 352 | if (ret < 0) |
245 | pr_err(" Error: Failed to show lines. (%d)\n", ret); | 353 | pr_err(" Error: Failed to show lines. (%d)\n", ret); |
246 | return ret; | 354 | return ret; |
247 | } | 355 | } |
356 | if (params.show_vars) { | ||
357 | if (params.mod_events) { | ||
358 | pr_err(" Error: Don't use --vars with" | ||
359 | " --add/--del.\n"); | ||
360 | usage_with_options(probe_usage, options); | ||
361 | } | ||
362 | if (!params.filter) | ||
363 | params.filter = strfilter__new(DEFAULT_VAR_FILTER, | ||
364 | NULL); | ||
365 | |||
366 | ret = show_available_vars(params.events, params.nevents, | ||
367 | params.max_probe_points, | ||
368 | params.target_module, | ||
369 | params.filter, | ||
370 | params.show_ext_vars); | ||
371 | strfilter__delete(params.filter); | ||
372 | if (ret < 0) | ||
373 | pr_err(" Error: Failed to show vars. (%d)\n", ret); | ||
374 | return ret; | ||
375 | } | ||
248 | #endif | 376 | #endif |
249 | 377 | ||
250 | if (params.dellist) { | 378 | if (params.dellist) { |
@@ -258,8 +386,9 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
258 | 386 | ||
259 | if (params.nevents) { | 387 | if (params.nevents) { |
260 | ret = add_perf_probe_events(params.events, params.nevents, | 388 | ret = add_perf_probe_events(params.events, params.nevents, |
261 | params.force_add, | 389 | params.max_probe_points, |
262 | params.max_probe_points); | 390 | params.target_module, |
391 | params.force_add); | ||
263 | if (ret < 0) { | 392 | if (ret < 0) { |
264 | pr_err(" Error: Failed to add events. (%d)\n", ret); | 393 | pr_err(" Error: Failed to add events. (%d)\n", ret); |
265 | return ret; | 394 | return ret; |