diff options
| author | Srikar Dronamraju <srikar@linux.vnet.ibm.com> | 2012-04-16 08:09:09 -0400 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2012-05-11 12:58:17 -0400 |
| commit | 225466f1c2d816c33b4341008f45dfdc83a9f0cb (patch) | |
| tree | 72cd2adf96464922e64fc86dc76bf321f426bbf1 /tools | |
| parent | 5dcefda0fd87fefa440abc9b9d3f1089229f8911 (diff) | |
perf probe: Provide perf interface for uprobes
- Enhances perf to probe user space executables and libraries.
- Enhances -F/--funcs option of "perf probe" to list possible probe points in
an executable file or library.
- Documents userspace probing support in perf.
[ Probing a function in the executable using function name ]
perf probe -x /bin/zsh zfree
[ Probing a library function using function name ]
perf probe -x /lib64/libc.so.6 malloc
[ list probe-able functions in an executable ]
perf probe -F -x /bin/zsh
[ list probe-able functions in an library]
perf probe -F -x /lib/libc.so.6
Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Anton Arapov <anton@redhat.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Linux-mm <linux-mm@kvack.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20120416120909.30661.99781.sendpatchset@srdronam.in.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/perf/Documentation/perf-probe.txt | 15 | ||||
| -rw-r--r-- | tools/perf/builtin-probe.c | 43 | ||||
| -rw-r--r-- | tools/perf/util/probe-event.c | 422 | ||||
| -rw-r--r-- | tools/perf/util/probe-event.h | 12 | ||||
| -rw-r--r-- | tools/perf/util/symbol.c | 8 | ||||
| -rw-r--r-- | tools/perf/util/symbol.h | 1 |
6 files changed, 403 insertions, 98 deletions
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 2780d9ce48bf..fb673bef4798 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt | |||
| @@ -77,7 +77,8 @@ OPTIONS | |||
| 77 | 77 | ||
| 78 | -F:: | 78 | -F:: |
| 79 | --funcs:: | 79 | --funcs:: |
| 80 | Show available functions in given module or kernel. | 80 | Show available functions in given module or kernel. With -x/--exec, |
| 81 | can also list functions in a user space executable / shared library. | ||
| 81 | 82 | ||
| 82 | --filter=FILTER:: | 83 | --filter=FILTER:: |
| 83 | (Only for --vars and --funcs) Set filter. FILTER is a combination of glob | 84 | (Only for --vars and --funcs) Set filter. FILTER is a combination of glob |
| @@ -98,6 +99,11 @@ OPTIONS | |||
| 98 | --max-probes:: | 99 | --max-probes:: |
| 99 | Set the maximum number of probe points for an event. Default is 128. | 100 | Set the maximum number of probe points for an event. Default is 128. |
| 100 | 101 | ||
| 102 | -x:: | ||
| 103 | --exec=PATH:: | ||
| 104 | Specify path to the executable or shared library file for user | ||
| 105 | space tracing. Can also be used with --funcs option. | ||
| 106 | |||
| 101 | PROBE SYNTAX | 107 | PROBE SYNTAX |
| 102 | ------------ | 108 | ------------ |
| 103 | Probe points are defined by following syntax. | 109 | Probe points are defined by following syntax. |
| @@ -182,6 +188,13 @@ Delete all probes on schedule(). | |||
| 182 | 188 | ||
| 183 | ./perf probe --del='schedule*' | 189 | ./perf probe --del='schedule*' |
| 184 | 190 | ||
| 191 | Add probes at zfree() function on /bin/zsh | ||
| 192 | |||
| 193 | ./perf probe -x /bin/zsh zfree | ||
| 194 | |||
| 195 | Add probes at malloc() function on libc | ||
| 196 | |||
| 197 | ./perf probe -x /lib/libc.so.6 malloc | ||
| 185 | 198 | ||
| 186 | SEE ALSO | 199 | SEE ALSO |
| 187 | -------- | 200 | -------- |
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 4935c09dd5b5..ee3d84a7c895 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
| @@ -54,6 +54,7 @@ static struct { | |||
| 54 | bool show_ext_vars; | 54 | bool show_ext_vars; |
| 55 | bool show_funcs; | 55 | bool show_funcs; |
| 56 | bool mod_events; | 56 | bool mod_events; |
| 57 | bool uprobes; | ||
| 57 | int nevents; | 58 | int nevents; |
| 58 | struct perf_probe_event events[MAX_PROBES]; | 59 | struct perf_probe_event events[MAX_PROBES]; |
| 59 | struct strlist *dellist; | 60 | struct strlist *dellist; |
| @@ -75,6 +76,8 @@ static int parse_probe_event(const char *str) | |||
| 75 | return -1; | 76 | return -1; |
| 76 | } | 77 | } |
| 77 | 78 | ||
| 79 | pev->uprobes = params.uprobes; | ||
| 80 | |||
| 78 | /* Parse a perf-probe command into event */ | 81 | /* Parse a perf-probe command into event */ |
| 79 | ret = parse_perf_probe_command(str, pev); | 82 | ret = parse_perf_probe_command(str, pev); |
| 80 | pr_debug("%d arguments\n", pev->nargs); | 83 | pr_debug("%d arguments\n", pev->nargs); |
| @@ -125,6 +128,28 @@ static int opt_del_probe_event(const struct option *opt __used, | |||
| 125 | return 0; | 128 | return 0; |
| 126 | } | 129 | } |
| 127 | 130 | ||
| 131 | static int opt_set_target(const struct option *opt, const char *str, | ||
| 132 | int unset __used) | ||
| 133 | { | ||
| 134 | int ret = -ENOENT; | ||
| 135 | |||
| 136 | if (str && !params.target) { | ||
| 137 | if (!strcmp(opt->long_name, "exec")) | ||
| 138 | params.uprobes = true; | ||
| 139 | #ifdef DWARF_SUPPORT | ||
| 140 | else if (!strcmp(opt->long_name, "module")) | ||
| 141 | params.uprobes = false; | ||
| 142 | #endif | ||
| 143 | else | ||
| 144 | return ret; | ||
| 145 | |||
| 146 | params.target = str; | ||
| 147 | ret = 0; | ||
| 148 | } | ||
| 149 | |||
| 150 | return ret; | ||
| 151 | } | ||
| 152 | |||
| 128 | #ifdef DWARF_SUPPORT | 153 | #ifdef DWARF_SUPPORT |
| 129 | static int opt_show_lines(const struct option *opt __used, | 154 | static int opt_show_lines(const struct option *opt __used, |
| 130 | const char *str, int unset __used) | 155 | const char *str, int unset __used) |
| @@ -246,9 +271,9 @@ static const struct option options[] = { | |||
| 246 | "file", "vmlinux pathname"), | 271 | "file", "vmlinux pathname"), |
| 247 | OPT_STRING('s', "source", &symbol_conf.source_prefix, | 272 | OPT_STRING('s', "source", &symbol_conf.source_prefix, |
| 248 | "directory", "path to kernel source"), | 273 | "directory", "path to kernel source"), |
| 249 | OPT_STRING('m', "module", ¶ms.target, | 274 | OPT_CALLBACK('m', "module", NULL, "modname|path", |
| 250 | "modname|path", | 275 | "target module name (for online) or path (for offline)", |
| 251 | "target module name (for online) or path (for offline)"), | 276 | opt_set_target), |
| 252 | #endif | 277 | #endif |
| 253 | OPT__DRY_RUN(&probe_event_dry_run), | 278 | OPT__DRY_RUN(&probe_event_dry_run), |
| 254 | OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, | 279 | OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, |
| @@ -260,6 +285,8 @@ static const struct option options[] = { | |||
| 260 | "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n" | 285 | "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n" |
| 261 | "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)", | 286 | "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)", |
| 262 | opt_set_filter), | 287 | opt_set_filter), |
| 288 | OPT_CALLBACK('x', "exec", NULL, "executable|path", | ||
| 289 | "target executable name or path", opt_set_target), | ||
| 263 | OPT_END() | 290 | OPT_END() |
| 264 | }; | 291 | }; |
| 265 | 292 | ||
| @@ -310,6 +337,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
| 310 | pr_err(" Error: Don't use --list with --funcs.\n"); | 337 | pr_err(" Error: Don't use --list with --funcs.\n"); |
| 311 | usage_with_options(probe_usage, options); | 338 | usage_with_options(probe_usage, options); |
| 312 | } | 339 | } |
| 340 | if (params.uprobes) { | ||
| 341 | pr_warning(" Error: Don't use --list with --exec.\n"); | ||
| 342 | usage_with_options(probe_usage, options); | ||
| 343 | } | ||
| 313 | ret = show_perf_probe_events(); | 344 | ret = show_perf_probe_events(); |
| 314 | if (ret < 0) | 345 | if (ret < 0) |
| 315 | pr_err(" Error: Failed to show event list. (%d)\n", | 346 | pr_err(" Error: Failed to show event list. (%d)\n", |
| @@ -333,8 +364,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
| 333 | if (!params.filter) | 364 | if (!params.filter) |
| 334 | params.filter = strfilter__new(DEFAULT_FUNC_FILTER, | 365 | params.filter = strfilter__new(DEFAULT_FUNC_FILTER, |
| 335 | NULL); | 366 | NULL); |
| 336 | ret = show_available_funcs(params.target, | 367 | ret = show_available_funcs(params.target, params.filter, |
| 337 | params.filter); | 368 | params.uprobes); |
| 338 | strfilter__delete(params.filter); | 369 | strfilter__delete(params.filter); |
| 339 | if (ret < 0) | 370 | if (ret < 0) |
| 340 | pr_err(" Error: Failed to show functions." | 371 | pr_err(" Error: Failed to show functions." |
| @@ -343,7 +374,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
| 343 | } | 374 | } |
| 344 | 375 | ||
| 345 | #ifdef DWARF_SUPPORT | 376 | #ifdef DWARF_SUPPORT |
| 346 | if (params.show_lines) { | 377 | if (params.show_lines && !params.uprobes) { |
| 347 | if (params.mod_events) { | 378 | if (params.mod_events) { |
| 348 | pr_err(" Error: Don't use --line with" | 379 | pr_err(" Error: Don't use --line with" |
| 349 | " --add/--del.\n"); | 380 | " --add/--del.\n"); |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 8a8ee64e72d1..59dccc98b554 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
| @@ -44,6 +44,7 @@ | |||
| 44 | #include "trace-event.h" /* For __unused */ | 44 | #include "trace-event.h" /* For __unused */ |
| 45 | #include "probe-event.h" | 45 | #include "probe-event.h" |
| 46 | #include "probe-finder.h" | 46 | #include "probe-finder.h" |
| 47 | #include "session.h" | ||
| 47 | 48 | ||
| 48 | #define MAX_CMDLEN 256 | 49 | #define MAX_CMDLEN 256 |
| 49 | #define MAX_PROBE_ARGS 128 | 50 | #define MAX_PROBE_ARGS 128 |
| @@ -70,6 +71,8 @@ static int e_snprintf(char *str, size_t size, const char *format, ...) | |||
| 70 | } | 71 | } |
| 71 | 72 | ||
| 72 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); | 73 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); |
| 74 | static int convert_name_to_addr(struct perf_probe_event *pev, | ||
| 75 | const char *exec); | ||
| 73 | static struct machine machine; | 76 | static struct machine machine; |
| 74 | 77 | ||
| 75 | /* Initialize symbol maps and path of vmlinux/modules */ | 78 | /* Initialize symbol maps and path of vmlinux/modules */ |
| @@ -170,6 +173,34 @@ const char *kernel_get_module_path(const char *module) | |||
| 170 | return (dso) ? dso->long_name : NULL; | 173 | return (dso) ? dso->long_name : NULL; |
| 171 | } | 174 | } |
| 172 | 175 | ||
| 176 | static int init_user_exec(void) | ||
| 177 | { | ||
| 178 | int ret = 0; | ||
| 179 | |||
| 180 | symbol_conf.try_vmlinux_path = false; | ||
| 181 | symbol_conf.sort_by_name = true; | ||
| 182 | ret = symbol__init(); | ||
| 183 | |||
| 184 | if (ret < 0) | ||
| 185 | pr_debug("Failed to init symbol map.\n"); | ||
| 186 | |||
| 187 | return ret; | ||
| 188 | } | ||
| 189 | |||
| 190 | static int convert_to_perf_probe_point(struct probe_trace_point *tp, | ||
| 191 | struct perf_probe_point *pp) | ||
| 192 | { | ||
| 193 | pp->function = strdup(tp->symbol); | ||
| 194 | |||
| 195 | if (pp->function == NULL) | ||
| 196 | return -ENOMEM; | ||
| 197 | |||
| 198 | pp->offset = tp->offset; | ||
| 199 | pp->retprobe = tp->retprobe; | ||
| 200 | |||
| 201 | return 0; | ||
| 202 | } | ||
| 203 | |||
| 173 | #ifdef DWARF_SUPPORT | 204 | #ifdef DWARF_SUPPORT |
| 174 | /* Open new debuginfo of given module */ | 205 | /* Open new debuginfo of given module */ |
| 175 | static struct debuginfo *open_debuginfo(const char *module) | 206 | static struct debuginfo *open_debuginfo(const char *module) |
| @@ -224,10 +255,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | |||
| 224 | if (ret <= 0) { | 255 | if (ret <= 0) { |
| 225 | pr_debug("Failed to find corresponding probes from " | 256 | pr_debug("Failed to find corresponding probes from " |
| 226 | "debuginfo. Use kprobe event information.\n"); | 257 | "debuginfo. Use kprobe event information.\n"); |
| 227 | pp->function = strdup(tp->symbol); | 258 | return convert_to_perf_probe_point(tp, pp); |
| 228 | if (pp->function == NULL) | ||
| 229 | return -ENOMEM; | ||
| 230 | pp->offset = tp->offset; | ||
| 231 | } | 259 | } |
| 232 | pp->retprobe = tp->retprobe; | 260 | pp->retprobe = tp->retprobe; |
| 233 | 261 | ||
| @@ -275,9 +303,20 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
| 275 | int max_tevs, const char *target) | 303 | int max_tevs, const char *target) |
| 276 | { | 304 | { |
| 277 | bool need_dwarf = perf_probe_event_need_dwarf(pev); | 305 | bool need_dwarf = perf_probe_event_need_dwarf(pev); |
| 278 | struct debuginfo *dinfo = open_debuginfo(target); | 306 | struct debuginfo *dinfo; |
| 279 | int ntevs, ret = 0; | 307 | int ntevs, ret = 0; |
| 280 | 308 | ||
| 309 | if (pev->uprobes) { | ||
| 310 | if (need_dwarf) { | ||
| 311 | pr_warning("Debuginfo-analysis is not yet supported" | ||
| 312 | " with -x/--exec option.\n"); | ||
| 313 | return -ENOSYS; | ||
| 314 | } | ||
| 315 | return convert_name_to_addr(pev, target); | ||
| 316 | } | ||
| 317 | |||
| 318 | dinfo = open_debuginfo(target); | ||
| 319 | |||
| 281 | if (!dinfo) { | 320 | if (!dinfo) { |
| 282 | if (need_dwarf) { | 321 | if (need_dwarf) { |
| 283 | pr_warning("Failed to open debuginfo file.\n"); | 322 | pr_warning("Failed to open debuginfo file.\n"); |
| @@ -603,23 +642,22 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | |||
| 603 | pr_err("Failed to find symbol %s in kernel.\n", tp->symbol); | 642 | pr_err("Failed to find symbol %s in kernel.\n", tp->symbol); |
| 604 | return -ENOENT; | 643 | return -ENOENT; |
| 605 | } | 644 | } |
| 606 | pp->function = strdup(tp->symbol); | ||
| 607 | if (pp->function == NULL) | ||
| 608 | return -ENOMEM; | ||
| 609 | pp->offset = tp->offset; | ||
| 610 | pp->retprobe = tp->retprobe; | ||
| 611 | 645 | ||
| 612 | return 0; | 646 | return convert_to_perf_probe_point(tp, pp); |
| 613 | } | 647 | } |
| 614 | 648 | ||
| 615 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | 649 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, |
| 616 | struct probe_trace_event **tevs __unused, | 650 | struct probe_trace_event **tevs __unused, |
| 617 | int max_tevs __unused, const char *mod __unused) | 651 | int max_tevs __unused, const char *target) |
| 618 | { | 652 | { |
| 619 | if (perf_probe_event_need_dwarf(pev)) { | 653 | if (perf_probe_event_need_dwarf(pev)) { |
| 620 | pr_warning("Debuginfo-analysis is not supported.\n"); | 654 | pr_warning("Debuginfo-analysis is not supported.\n"); |
| 621 | return -ENOSYS; | 655 | return -ENOSYS; |
| 622 | } | 656 | } |
| 657 | |||
| 658 | if (pev->uprobes) | ||
| 659 | return convert_name_to_addr(pev, target); | ||
| 660 | |||
| 623 | return 0; | 661 | return 0; |
| 624 | } | 662 | } |
| 625 | 663 | ||
| @@ -1341,11 +1379,18 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev) | |||
| 1341 | if (buf == NULL) | 1379 | if (buf == NULL) |
| 1342 | return NULL; | 1380 | return NULL; |
| 1343 | 1381 | ||
| 1344 | len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu", | 1382 | if (tev->uprobes) |
| 1345 | tp->retprobe ? 'r' : 'p', | 1383 | len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s", |
| 1346 | tev->group, tev->event, | 1384 | tp->retprobe ? 'r' : 'p', |
| 1347 | tp->module ?: "", tp->module ? ":" : "", | 1385 | tev->group, tev->event, |
| 1348 | tp->symbol, tp->offset); | 1386 | tp->module, tp->symbol); |
| 1387 | else | ||
| 1388 | len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu", | ||
| 1389 | tp->retprobe ? 'r' : 'p', | ||
| 1390 | tev->group, tev->event, | ||
| 1391 | tp->module ?: "", tp->module ? ":" : "", | ||
| 1392 | tp->symbol, tp->offset); | ||
| 1393 | |||
| 1349 | if (len <= 0) | 1394 | if (len <= 0) |
| 1350 | goto error; | 1395 | goto error; |
| 1351 | 1396 | ||
| @@ -1364,7 +1409,7 @@ error: | |||
| 1364 | } | 1409 | } |
| 1365 | 1410 | ||
| 1366 | static int convert_to_perf_probe_event(struct probe_trace_event *tev, | 1411 | static int convert_to_perf_probe_event(struct probe_trace_event *tev, |
| 1367 | struct perf_probe_event *pev) | 1412 | struct perf_probe_event *pev, bool is_kprobe) |
| 1368 | { | 1413 | { |
| 1369 | char buf[64] = ""; | 1414 | char buf[64] = ""; |
| 1370 | int i, ret; | 1415 | int i, ret; |
| @@ -1376,7 +1421,11 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev, | |||
| 1376 | return -ENOMEM; | 1421 | return -ENOMEM; |
| 1377 | 1422 | ||
| 1378 | /* Convert trace_point to probe_point */ | 1423 | /* Convert trace_point to probe_point */ |
| 1379 | ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point); | 1424 | if (is_kprobe) |
| 1425 | ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point); | ||
| 1426 | else | ||
| 1427 | ret = convert_to_perf_probe_point(&tev->point, &pev->point); | ||
| 1428 | |||
| 1380 | if (ret < 0) | 1429 | if (ret < 0) |
| 1381 | return ret; | 1430 | return ret; |
| 1382 | 1431 | ||
| @@ -1472,7 +1521,26 @@ static void clear_probe_trace_event(struct probe_trace_event *tev) | |||
| 1472 | memset(tev, 0, sizeof(*tev)); | 1521 | memset(tev, 0, sizeof(*tev)); |
| 1473 | } | 1522 | } |
| 1474 | 1523 | ||
| 1475 | static int open_kprobe_events(bool readwrite) | 1524 | static void print_warn_msg(const char *file, bool is_kprobe) |
| 1525 | { | ||
| 1526 | |||
| 1527 | if (errno == ENOENT) { | ||
| 1528 | const char *config; | ||
| 1529 | |||
| 1530 | if (!is_kprobe) | ||
| 1531 | config = "CONFIG_UPROBE_EVENTS"; | ||
| 1532 | else | ||
| 1533 | config = "CONFIG_KPROBE_EVENTS"; | ||
| 1534 | |||
| 1535 | pr_warning("%s file does not exist - please rebuild kernel" | ||
| 1536 | " with %s.\n", file, config); | ||
| 1537 | } else | ||
| 1538 | pr_warning("Failed to open %s file: %s\n", file, | ||
| 1539 | strerror(errno)); | ||
| 1540 | } | ||
| 1541 | |||
| 1542 | static int open_probe_events(const char *trace_file, bool readwrite, | ||
| 1543 | bool is_kprobe) | ||
| 1476 | { | 1544 | { |
| 1477 | char buf[PATH_MAX]; | 1545 | char buf[PATH_MAX]; |
| 1478 | const char *__debugfs; | 1546 | const char *__debugfs; |
| @@ -1484,27 +1552,31 @@ static int open_kprobe_events(bool readwrite) | |||
| 1484 | return -ENOENT; | 1552 | return -ENOENT; |
| 1485 | } | 1553 | } |
| 1486 | 1554 | ||
| 1487 | ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs); | 1555 | ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file); |
| 1488 | if (ret >= 0) { | 1556 | if (ret >= 0) { |
| 1489 | pr_debug("Opening %s write=%d\n", buf, readwrite); | 1557 | pr_debug("Opening %s write=%d\n", buf, readwrite); |
| 1490 | if (readwrite && !probe_event_dry_run) | 1558 | if (readwrite && !probe_event_dry_run) |
| 1491 | ret = open(buf, O_RDWR, O_APPEND); | 1559 | ret = open(buf, O_RDWR, O_APPEND); |
| 1492 | else | 1560 | else |
| 1493 | ret = open(buf, O_RDONLY, 0); | 1561 | ret = open(buf, O_RDONLY, 0); |
| 1494 | } | ||
| 1495 | 1562 | ||
| 1496 | if (ret < 0) { | 1563 | if (ret < 0) |
| 1497 | if (errno == ENOENT) | 1564 | print_warn_msg(buf, is_kprobe); |
| 1498 | pr_warning("kprobe_events file does not exist - please" | ||
| 1499 | " rebuild kernel with CONFIG_KPROBE_EVENT.\n"); | ||
| 1500 | else | ||
| 1501 | pr_warning("Failed to open kprobe_events file: %s\n", | ||
| 1502 | strerror(errno)); | ||
| 1503 | } | 1565 | } |
| 1504 | return ret; | 1566 | return ret; |
| 1505 | } | 1567 | } |
| 1506 | 1568 | ||
| 1507 | /* Get raw string list of current kprobe_events */ | 1569 | static int open_kprobe_events(bool readwrite) |
| 1570 | { | ||
| 1571 | return open_probe_events("tracing/kprobe_events", readwrite, true); | ||
| 1572 | } | ||
| 1573 | |||
| 1574 | static int open_uprobe_events(bool readwrite) | ||
| 1575 | { | ||
| 1576 | return open_probe_events("tracing/uprobe_events", readwrite, false); | ||
| 1577 | } | ||
| 1578 | |||
| 1579 | /* Get raw string list of current kprobe_events or uprobe_events */ | ||
| 1508 | static struct strlist *get_probe_trace_command_rawlist(int fd) | 1580 | static struct strlist *get_probe_trace_command_rawlist(int fd) |
| 1509 | { | 1581 | { |
| 1510 | int ret, idx; | 1582 | int ret, idx; |
| @@ -1569,36 +1641,26 @@ static int show_perf_probe_event(struct perf_probe_event *pev) | |||
| 1569 | return ret; | 1641 | return ret; |
| 1570 | } | 1642 | } |
| 1571 | 1643 | ||
| 1572 | /* List up current perf-probe events */ | 1644 | static int __show_perf_probe_events(int fd, bool is_kprobe) |
| 1573 | int show_perf_probe_events(void) | ||
| 1574 | { | 1645 | { |
| 1575 | int fd, ret; | 1646 | int ret = 0; |
| 1576 | struct probe_trace_event tev; | 1647 | struct probe_trace_event tev; |
| 1577 | struct perf_probe_event pev; | 1648 | struct perf_probe_event pev; |
| 1578 | struct strlist *rawlist; | 1649 | struct strlist *rawlist; |
| 1579 | struct str_node *ent; | 1650 | struct str_node *ent; |
| 1580 | 1651 | ||
| 1581 | setup_pager(); | ||
| 1582 | ret = init_vmlinux(); | ||
| 1583 | if (ret < 0) | ||
| 1584 | return ret; | ||
| 1585 | |||
| 1586 | memset(&tev, 0, sizeof(tev)); | 1652 | memset(&tev, 0, sizeof(tev)); |
| 1587 | memset(&pev, 0, sizeof(pev)); | 1653 | memset(&pev, 0, sizeof(pev)); |
| 1588 | 1654 | ||
| 1589 | fd = open_kprobe_events(false); | ||
| 1590 | if (fd < 0) | ||
| 1591 | return fd; | ||
| 1592 | |||
| 1593 | rawlist = get_probe_trace_command_rawlist(fd); | 1655 | rawlist = get_probe_trace_command_rawlist(fd); |
| 1594 | close(fd); | ||
| 1595 | if (!rawlist) | 1656 | if (!rawlist) |
| 1596 | return -ENOENT; | 1657 | return -ENOENT; |
| 1597 | 1658 | ||
| 1598 | strlist__for_each(ent, rawlist) { | 1659 | strlist__for_each(ent, rawlist) { |
| 1599 | ret = parse_probe_trace_command(ent->s, &tev); | 1660 | ret = parse_probe_trace_command(ent->s, &tev); |
| 1600 | if (ret >= 0) { | 1661 | if (ret >= 0) { |
| 1601 | ret = convert_to_perf_probe_event(&tev, &pev); | 1662 | ret = convert_to_perf_probe_event(&tev, &pev, |
| 1663 | is_kprobe); | ||
| 1602 | if (ret >= 0) | 1664 | if (ret >= 0) |
| 1603 | ret = show_perf_probe_event(&pev); | 1665 | ret = show_perf_probe_event(&pev); |
| 1604 | } | 1666 | } |
| @@ -1612,6 +1674,33 @@ int show_perf_probe_events(void) | |||
| 1612 | return ret; | 1674 | return ret; |
| 1613 | } | 1675 | } |
| 1614 | 1676 | ||
| 1677 | /* List up current perf-probe events */ | ||
| 1678 | int show_perf_probe_events(void) | ||
| 1679 | { | ||
| 1680 | int fd, ret; | ||
| 1681 | |||
| 1682 | setup_pager(); | ||
| 1683 | fd = open_kprobe_events(false); | ||
| 1684 | |||
| 1685 | if (fd < 0) | ||
| 1686 | return fd; | ||
| 1687 | |||
| 1688 | ret = init_vmlinux(); | ||
| 1689 | if (ret < 0) | ||
| 1690 | return ret; | ||
| 1691 | |||
| 1692 | ret = __show_perf_probe_events(fd, true); | ||
| 1693 | close(fd); | ||
| 1694 | |||
| 1695 | fd = open_uprobe_events(false); | ||
| 1696 | if (fd >= 0) { | ||
| 1697 | ret = __show_perf_probe_events(fd, false); | ||
| 1698 | close(fd); | ||
| 1699 | } | ||
| 1700 | |||
| 1701 | return ret; | ||
| 1702 | } | ||
| 1703 | |||
| 1615 | /* Get current perf-probe event names */ | 1704 | /* Get current perf-probe event names */ |
| 1616 | static struct strlist *get_probe_trace_event_names(int fd, bool include_group) | 1705 | static struct strlist *get_probe_trace_event_names(int fd, bool include_group) |
| 1617 | { | 1706 | { |
| @@ -1717,7 +1806,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, | |||
| 1717 | const char *event, *group; | 1806 | const char *event, *group; |
| 1718 | struct strlist *namelist; | 1807 | struct strlist *namelist; |
| 1719 | 1808 | ||
| 1720 | fd = open_kprobe_events(true); | 1809 | if (pev->uprobes) |
| 1810 | fd = open_uprobe_events(true); | ||
| 1811 | else | ||
| 1812 | fd = open_kprobe_events(true); | ||
| 1813 | |||
| 1721 | if (fd < 0) | 1814 | if (fd < 0) |
| 1722 | return fd; | 1815 | return fd; |
| 1723 | /* Get current event names */ | 1816 | /* Get current event names */ |
| @@ -1829,6 +1922,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
| 1829 | tev->point.offset = pev->point.offset; | 1922 | tev->point.offset = pev->point.offset; |
| 1830 | tev->point.retprobe = pev->point.retprobe; | 1923 | tev->point.retprobe = pev->point.retprobe; |
| 1831 | tev->nargs = pev->nargs; | 1924 | tev->nargs = pev->nargs; |
| 1925 | tev->uprobes = pev->uprobes; | ||
| 1926 | |||
| 1832 | if (tev->nargs) { | 1927 | if (tev->nargs) { |
| 1833 | tev->args = zalloc(sizeof(struct probe_trace_arg) | 1928 | tev->args = zalloc(sizeof(struct probe_trace_arg) |
| 1834 | * tev->nargs); | 1929 | * tev->nargs); |
| @@ -1859,6 +1954,9 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
| 1859 | } | 1954 | } |
| 1860 | } | 1955 | } |
| 1861 | 1956 | ||
| 1957 | if (pev->uprobes) | ||
| 1958 | return 1; | ||
| 1959 | |||
| 1862 | /* Currently just checking function name from symbol map */ | 1960 | /* Currently just checking function name from symbol map */ |
| 1863 | sym = __find_kernel_function_by_name(tev->point.symbol, NULL); | 1961 | sym = __find_kernel_function_by_name(tev->point.symbol, NULL); |
| 1864 | if (!sym) { | 1962 | if (!sym) { |
| @@ -1894,12 +1992,18 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, | |||
| 1894 | int i, j, ret; | 1992 | int i, j, ret; |
| 1895 | struct __event_package *pkgs; | 1993 | struct __event_package *pkgs; |
| 1896 | 1994 | ||
| 1995 | ret = 0; | ||
| 1897 | pkgs = zalloc(sizeof(struct __event_package) * npevs); | 1996 | pkgs = zalloc(sizeof(struct __event_package) * npevs); |
| 1997 | |||
| 1898 | if (pkgs == NULL) | 1998 | if (pkgs == NULL) |
| 1899 | return -ENOMEM; | 1999 | return -ENOMEM; |
| 1900 | 2000 | ||
| 1901 | /* Init vmlinux path */ | 2001 | if (!pevs->uprobes) |
| 1902 | ret = init_vmlinux(); | 2002 | /* Init vmlinux path */ |
| 2003 | ret = init_vmlinux(); | ||
| 2004 | else | ||
| 2005 | ret = init_user_exec(); | ||
| 2006 | |||
| 1903 | if (ret < 0) { | 2007 | if (ret < 0) { |
| 1904 | free(pkgs); | 2008 | free(pkgs); |
| 1905 | return ret; | 2009 | return ret; |
| @@ -1971,23 +2075,15 @@ error: | |||
| 1971 | return ret; | 2075 | return ret; |
| 1972 | } | 2076 | } |
| 1973 | 2077 | ||
| 1974 | static int del_trace_probe_event(int fd, const char *group, | 2078 | static int del_trace_probe_event(int fd, const char *buf, |
| 1975 | const char *event, struct strlist *namelist) | 2079 | struct strlist *namelist) |
| 1976 | { | 2080 | { |
| 1977 | char buf[128]; | ||
| 1978 | struct str_node *ent, *n; | 2081 | struct str_node *ent, *n; |
| 1979 | int found = 0, ret = 0; | 2082 | int ret = -1; |
| 1980 | |||
| 1981 | ret = e_snprintf(buf, 128, "%s:%s", group, event); | ||
| 1982 | if (ret < 0) { | ||
| 1983 | pr_err("Failed to copy event.\n"); | ||
| 1984 | return ret; | ||
| 1985 | } | ||
| 1986 | 2083 | ||
| 1987 | if (strpbrk(buf, "*?")) { /* Glob-exp */ | 2084 | if (strpbrk(buf, "*?")) { /* Glob-exp */ |
| 1988 | strlist__for_each_safe(ent, n, namelist) | 2085 | strlist__for_each_safe(ent, n, namelist) |
| 1989 | if (strglobmatch(ent->s, buf)) { | 2086 | if (strglobmatch(ent->s, buf)) { |
| 1990 | found++; | ||
| 1991 | ret = __del_trace_probe_event(fd, ent); | 2087 | ret = __del_trace_probe_event(fd, ent); |
| 1992 | if (ret < 0) | 2088 | if (ret < 0) |
| 1993 | break; | 2089 | break; |
| @@ -1996,40 +2092,43 @@ static int del_trace_probe_event(int fd, const char *group, | |||
| 1996 | } else { | 2092 | } else { |
| 1997 | ent = strlist__find(namelist, buf); | 2093 | ent = strlist__find(namelist, buf); |
| 1998 | if (ent) { | 2094 | if (ent) { |
| 1999 | found++; | ||
| 2000 | ret = __del_trace_probe_event(fd, ent); | 2095 | ret = __del_trace_probe_event(fd, ent); |
| 2001 | if (ret >= 0) | 2096 | if (ret >= 0) |
| 2002 | strlist__remove(namelist, ent); | 2097 | strlist__remove(namelist, ent); |
| 2003 | } | 2098 | } |
| 2004 | } | 2099 | } |
| 2005 | if (found == 0 && ret >= 0) | ||
| 2006 | pr_info("Info: Event \"%s\" does not exist.\n", buf); | ||
| 2007 | 2100 | ||
| 2008 | return ret; | 2101 | return ret; |
| 2009 | } | 2102 | } |
| 2010 | 2103 | ||
| 2011 | int del_perf_probe_events(struct strlist *dellist) | 2104 | int del_perf_probe_events(struct strlist *dellist) |
| 2012 | { | 2105 | { |
| 2013 | int fd, ret = 0; | 2106 | int ret = -1, ufd = -1, kfd = -1; |
| 2107 | char buf[128]; | ||
| 2014 | const char *group, *event; | 2108 | const char *group, *event; |
| 2015 | char *p, *str; | 2109 | char *p, *str; |
| 2016 | struct str_node *ent; | 2110 | struct str_node *ent; |
| 2017 | struct strlist *namelist; | 2111 | struct strlist *namelist = NULL, *unamelist = NULL; |
| 2018 | |||
| 2019 | fd = open_kprobe_events(true); | ||
| 2020 | if (fd < 0) | ||
| 2021 | return fd; | ||
| 2022 | 2112 | ||
| 2023 | /* Get current event names */ | 2113 | /* Get current event names */ |
| 2024 | namelist = get_probe_trace_event_names(fd, true); | 2114 | kfd = open_kprobe_events(true); |
| 2025 | if (namelist == NULL) | 2115 | if (kfd < 0) |
| 2026 | return -EINVAL; | 2116 | return kfd; |
| 2117 | |||
| 2118 | namelist = get_probe_trace_event_names(kfd, true); | ||
| 2119 | ufd = open_uprobe_events(true); | ||
| 2120 | |||
| 2121 | if (ufd >= 0) | ||
| 2122 | unamelist = get_probe_trace_event_names(ufd, true); | ||
| 2123 | |||
| 2124 | if (namelist == NULL && unamelist == NULL) | ||
| 2125 | goto error; | ||
| 2027 | 2126 | ||
| 2028 | strlist__for_each(ent, dellist) { | 2127 | strlist__for_each(ent, dellist) { |
| 2029 | str = strdup(ent->s); | 2128 | str = strdup(ent->s); |
| 2030 | if (str == NULL) { | 2129 | if (str == NULL) { |
| 2031 | ret = -ENOMEM; | 2130 | ret = -ENOMEM; |
| 2032 | break; | 2131 | goto error; |
| 2033 | } | 2132 | } |
| 2034 | pr_debug("Parsing: %s\n", str); | 2133 | pr_debug("Parsing: %s\n", str); |
| 2035 | p = strchr(str, ':'); | 2134 | p = strchr(str, ':'); |
| @@ -2041,17 +2140,46 @@ int del_perf_probe_events(struct strlist *dellist) | |||
| 2041 | group = "*"; | 2140 | group = "*"; |
| 2042 | event = str; | 2141 | event = str; |
| 2043 | } | 2142 | } |
| 2143 | |||
| 2144 | ret = e_snprintf(buf, 128, "%s:%s", group, event); | ||
| 2145 | if (ret < 0) { | ||
| 2146 | pr_err("Failed to copy event."); | ||
| 2147 | free(str); | ||
| 2148 | goto error; | ||
| 2149 | } | ||
| 2150 | |||
| 2044 | pr_debug("Group: %s, Event: %s\n", group, event); | 2151 | pr_debug("Group: %s, Event: %s\n", group, event); |
| 2045 | ret = del_trace_probe_event(fd, group, event, namelist); | 2152 | |
| 2153 | if (namelist) | ||
| 2154 | ret = del_trace_probe_event(kfd, buf, namelist); | ||
| 2155 | |||
| 2156 | if (unamelist && ret != 0) | ||
| 2157 | ret = del_trace_probe_event(ufd, buf, unamelist); | ||
| 2158 | |||
| 2159 | if (ret != 0) | ||
| 2160 | pr_info("Info: Event \"%s\" does not exist.\n", buf); | ||
| 2161 | |||
| 2046 | free(str); | 2162 | free(str); |
| 2047 | if (ret < 0) | ||
| 2048 | break; | ||
| 2049 | } | 2163 | } |
| 2050 | strlist__delete(namelist); | 2164 | |
| 2051 | close(fd); | 2165 | error: |
| 2166 | if (kfd >= 0) { | ||
| 2167 | if (namelist) | ||
| 2168 | strlist__delete(namelist); | ||
| 2169 | |||
| 2170 | close(kfd); | ||
| 2171 | } | ||
| 2172 | |||
| 2173 | if (ufd >= 0) { | ||
| 2174 | if (unamelist) | ||
| 2175 | strlist__delete(unamelist); | ||
| 2176 | |||
| 2177 | close(ufd); | ||
| 2178 | } | ||
| 2052 | 2179 | ||
| 2053 | return ret; | 2180 | return ret; |
| 2054 | } | 2181 | } |
| 2182 | |||
| 2055 | /* TODO: don't use a global variable for filter ... */ | 2183 | /* TODO: don't use a global variable for filter ... */ |
| 2056 | static struct strfilter *available_func_filter; | 2184 | static struct strfilter *available_func_filter; |
| 2057 | 2185 | ||
| @@ -2068,30 +2196,152 @@ static int filter_available_functions(struct map *map __unused, | |||
| 2068 | return 1; | 2196 | return 1; |
| 2069 | } | 2197 | } |
| 2070 | 2198 | ||
| 2071 | int show_available_funcs(const char *target, struct strfilter *_filter) | 2199 | static int __show_available_funcs(struct map *map) |
| 2200 | { | ||
| 2201 | if (map__load(map, filter_available_functions)) { | ||
| 2202 | pr_err("Failed to load map.\n"); | ||
| 2203 | return -EINVAL; | ||
| 2204 | } | ||
| 2205 | if (!dso__sorted_by_name(map->dso, map->type)) | ||
| 2206 | dso__sort_by_name(map->dso, map->type); | ||
| 2207 | |||
| 2208 | dso__fprintf_symbols_by_name(map->dso, map->type, stdout); | ||
| 2209 | return 0; | ||
| 2210 | } | ||
| 2211 | |||
| 2212 | static int available_kernel_funcs(const char *module) | ||
| 2072 | { | 2213 | { |
| 2073 | struct map *map; | 2214 | struct map *map; |
| 2074 | int ret; | 2215 | int ret; |
| 2075 | 2216 | ||
| 2076 | setup_pager(); | ||
| 2077 | |||
| 2078 | ret = init_vmlinux(); | 2217 | ret = init_vmlinux(); |
| 2079 | if (ret < 0) | 2218 | if (ret < 0) |
| 2080 | return ret; | 2219 | return ret; |
| 2081 | 2220 | ||
| 2082 | map = kernel_get_module_map(target); | 2221 | map = kernel_get_module_map(module); |
| 2083 | if (!map) { | 2222 | if (!map) { |
| 2084 | pr_err("Failed to find %s map.\n", (target) ? : "kernel"); | 2223 | pr_err("Failed to find %s map.\n", (module) ? : "kernel"); |
| 2085 | return -EINVAL; | 2224 | return -EINVAL; |
| 2086 | } | 2225 | } |
| 2226 | return __show_available_funcs(map); | ||
| 2227 | } | ||
| 2228 | |||
| 2229 | static int available_user_funcs(const char *target) | ||
| 2230 | { | ||
| 2231 | struct map *map; | ||
| 2232 | int ret; | ||
| 2233 | |||
| 2234 | ret = init_user_exec(); | ||
| 2235 | if (ret < 0) | ||
| 2236 | return ret; | ||
| 2237 | |||
| 2238 | map = dso__new_map(target); | ||
| 2239 | ret = __show_available_funcs(map); | ||
| 2240 | dso__delete(map->dso); | ||
| 2241 | map__delete(map); | ||
| 2242 | return ret; | ||
| 2243 | } | ||
| 2244 | |||
| 2245 | int show_available_funcs(const char *target, struct strfilter *_filter, | ||
| 2246 | bool user) | ||
| 2247 | { | ||
| 2248 | setup_pager(); | ||
| 2087 | available_func_filter = _filter; | 2249 | available_func_filter = _filter; |
| 2250 | |||
| 2251 | if (!user) | ||
| 2252 | return available_kernel_funcs(target); | ||
| 2253 | |||
| 2254 | return available_user_funcs(target); | ||
| 2255 | } | ||
| 2256 | |||
| 2257 | /* | ||
| 2258 | * uprobe_events only accepts address: | ||
| 2259 | * Convert function and any offset to address | ||
| 2260 | */ | ||
| 2261 | static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec) | ||
| 2262 | { | ||
| 2263 | struct perf_probe_point *pp = &pev->point; | ||
| 2264 | struct symbol *sym; | ||
| 2265 | struct map *map = NULL; | ||
| 2266 | char *function = NULL, *name = NULL; | ||
| 2267 | int ret = -EINVAL; | ||
| 2268 | unsigned long long vaddr = 0; | ||
| 2269 | |||
| 2270 | if (!pp->function) { | ||
| 2271 | pr_warning("No function specified for uprobes"); | ||
| 2272 | goto out; | ||
| 2273 | } | ||
| 2274 | |||
| 2275 | function = strdup(pp->function); | ||
| 2276 | if (!function) { | ||
| 2277 | pr_warning("Failed to allocate memory by strdup.\n"); | ||
| 2278 | ret = -ENOMEM; | ||
| 2279 | goto out; | ||
| 2280 | } | ||
| 2281 | |||
| 2282 | name = realpath(exec, NULL); | ||
| 2283 | if (!name) { | ||
| 2284 | pr_warning("Cannot find realpath for %s.\n", exec); | ||
| 2285 | goto out; | ||
| 2286 | } | ||
| 2287 | map = dso__new_map(name); | ||
| 2288 | if (!map) { | ||
| 2289 | pr_warning("Cannot find appropriate DSO for %s.\n", exec); | ||
| 2290 | goto out; | ||
| 2291 | } | ||
| 2292 | available_func_filter = strfilter__new(function, NULL); | ||
| 2088 | if (map__load(map, filter_available_functions)) { | 2293 | if (map__load(map, filter_available_functions)) { |
| 2089 | pr_err("Failed to load map.\n"); | 2294 | pr_err("Failed to load map.\n"); |
| 2090 | return -EINVAL; | 2295 | goto out; |
| 2091 | } | 2296 | } |
| 2092 | if (!dso__sorted_by_name(map->dso, map->type)) | ||
| 2093 | dso__sort_by_name(map->dso, map->type); | ||
| 2094 | 2297 | ||
| 2095 | dso__fprintf_symbols_by_name(map->dso, map->type, stdout); | 2298 | sym = map__find_symbol_by_name(map, function, NULL); |
| 2096 | return 0; | 2299 | if (!sym) { |
| 2300 | pr_warning("Cannot find %s in DSO %s\n", function, exec); | ||
| 2301 | goto out; | ||
| 2302 | } | ||
| 2303 | |||
| 2304 | if (map->start > sym->start) | ||
| 2305 | vaddr = map->start; | ||
| 2306 | vaddr += sym->start + pp->offset + map->pgoff; | ||
| 2307 | pp->offset = 0; | ||
| 2308 | |||
| 2309 | if (!pev->event) { | ||
| 2310 | pev->event = function; | ||
| 2311 | function = NULL; | ||
| 2312 | } | ||
| 2313 | if (!pev->group) { | ||
| 2314 | char *ptr1, *ptr2; | ||
| 2315 | |||
| 2316 | pev->group = zalloc(sizeof(char *) * 64); | ||
| 2317 | ptr1 = strdup(basename(exec)); | ||
| 2318 | if (ptr1) { | ||
| 2319 | ptr2 = strpbrk(ptr1, "-._"); | ||
| 2320 | if (ptr2) | ||
| 2321 | *ptr2 = '\0'; | ||
| 2322 | e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP, | ||
| 2323 | ptr1); | ||
| 2324 | free(ptr1); | ||
| 2325 | } | ||
| 2326 | } | ||
| 2327 | free(pp->function); | ||
| 2328 | pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS); | ||
| 2329 | if (!pp->function) { | ||
| 2330 | ret = -ENOMEM; | ||
| 2331 | pr_warning("Failed to allocate memory by zalloc.\n"); | ||
| 2332 | goto out; | ||
| 2333 | } | ||
| 2334 | e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr); | ||
| 2335 | ret = 0; | ||
| 2336 | |||
| 2337 | out: | ||
| 2338 | if (map) { | ||
| 2339 | dso__delete(map->dso); | ||
| 2340 | map__delete(map); | ||
| 2341 | } | ||
| 2342 | if (function) | ||
| 2343 | free(function); | ||
| 2344 | if (name) | ||
| 2345 | free(name); | ||
| 2346 | return ret; | ||
| 2097 | } | 2347 | } |
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index a7dee835f49c..f9f3de8b4220 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | extern bool probe_event_dry_run; | 8 | extern bool probe_event_dry_run; |
| 9 | 9 | ||
| 10 | /* kprobe-tracer tracing point */ | 10 | /* kprobe-tracer and uprobe-tracer tracing point */ |
| 11 | struct probe_trace_point { | 11 | struct probe_trace_point { |
| 12 | char *symbol; /* Base symbol */ | 12 | char *symbol; /* Base symbol */ |
| 13 | char *module; /* Module name */ | 13 | char *module; /* Module name */ |
| @@ -21,7 +21,7 @@ struct probe_trace_arg_ref { | |||
| 21 | long offset; /* Offset value */ | 21 | long offset; /* Offset value */ |
| 22 | }; | 22 | }; |
| 23 | 23 | ||
| 24 | /* kprobe-tracer tracing argument */ | 24 | /* kprobe-tracer and uprobe-tracer tracing argument */ |
| 25 | struct probe_trace_arg { | 25 | struct probe_trace_arg { |
| 26 | char *name; /* Argument name */ | 26 | char *name; /* Argument name */ |
| 27 | char *value; /* Base value */ | 27 | char *value; /* Base value */ |
| @@ -29,12 +29,13 @@ struct probe_trace_arg { | |||
| 29 | struct probe_trace_arg_ref *ref; /* Referencing offset */ | 29 | struct probe_trace_arg_ref *ref; /* Referencing offset */ |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | /* kprobe-tracer tracing event (point + arg) */ | 32 | /* kprobe-tracer and uprobe-tracer tracing event (point + arg) */ |
| 33 | struct probe_trace_event { | 33 | struct probe_trace_event { |
| 34 | char *event; /* Event name */ | 34 | char *event; /* Event name */ |
| 35 | char *group; /* Group name */ | 35 | char *group; /* Group name */ |
| 36 | struct probe_trace_point point; /* Trace point */ | 36 | struct probe_trace_point point; /* Trace point */ |
| 37 | int nargs; /* Number of args */ | 37 | int nargs; /* Number of args */ |
| 38 | bool uprobes; /* uprobes only */ | ||
| 38 | struct probe_trace_arg *args; /* Arguments */ | 39 | struct probe_trace_arg *args; /* Arguments */ |
| 39 | }; | 40 | }; |
| 40 | 41 | ||
| @@ -70,6 +71,7 @@ struct perf_probe_event { | |||
| 70 | char *group; /* Group name */ | 71 | char *group; /* Group name */ |
| 71 | struct perf_probe_point point; /* Probe point */ | 72 | struct perf_probe_point point; /* Probe point */ |
| 72 | int nargs; /* Number of arguments */ | 73 | int nargs; /* Number of arguments */ |
| 74 | bool uprobes; | ||
| 73 | struct perf_probe_arg *args; /* Arguments */ | 75 | struct perf_probe_arg *args; /* Arguments */ |
| 74 | }; | 76 | }; |
| 75 | 77 | ||
| @@ -129,8 +131,8 @@ extern int show_line_range(struct line_range *lr, const char *module); | |||
| 129 | extern int show_available_vars(struct perf_probe_event *pevs, int npevs, | 131 | extern int show_available_vars(struct perf_probe_event *pevs, int npevs, |
| 130 | int max_probe_points, const char *module, | 132 | int max_probe_points, const char *module, |
| 131 | struct strfilter *filter, bool externs); | 133 | struct strfilter *filter, bool externs); |
| 132 | extern int show_available_funcs(const char *module, struct strfilter *filter); | 134 | extern int show_available_funcs(const char *module, struct strfilter *filter, |
| 133 | 135 | bool user); | |
| 134 | 136 | ||
| 135 | /* Maximum index number of event-name postfix */ | 137 | /* Maximum index number of event-name postfix */ |
| 136 | #define MAX_EVENT_INDEX 1024 | 138 | #define MAX_EVENT_INDEX 1024 |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index c0a028c3ebaf..caaf75ad645a 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
| @@ -2784,3 +2784,11 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type, | |||
| 2784 | 2784 | ||
| 2785 | return ret; | 2785 | return ret; |
| 2786 | } | 2786 | } |
| 2787 | |||
| 2788 | struct map *dso__new_map(const char *name) | ||
| 2789 | { | ||
| 2790 | struct dso *dso = dso__new(name); | ||
| 2791 | struct map *map = map__new2(0, dso, MAP__FUNCTION); | ||
| 2792 | |||
| 2793 | return map; | ||
| 2794 | } | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 1f003884f1ab..5649d63798cb 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
| @@ -242,6 +242,7 @@ void dso__set_long_name(struct dso *dso, char *name); | |||
| 242 | void dso__set_build_id(struct dso *dso, void *build_id); | 242 | void dso__set_build_id(struct dso *dso, void *build_id); |
| 243 | void dso__read_running_kernel_build_id(struct dso *dso, | 243 | void dso__read_running_kernel_build_id(struct dso *dso, |
| 244 | struct machine *machine); | 244 | struct machine *machine); |
| 245 | struct map *dso__new_map(const char *name); | ||
| 245 | struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, | 246 | struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, |
| 246 | u64 addr); | 247 | u64 addr); |
| 247 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, | 248 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, |
