diff options
author | Krister Johansen <kjlx@templeofstupid.com> | 2017-07-05 21:48:10 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2017-07-18 22:14:10 -0400 |
commit | 544abd44c7064c8a58a6bd2073d757f6b91d98c5 (patch) | |
tree | faa9e5d4c4b86067f4b5cd9f8200010a726a314d | |
parent | bf2e710b3cb8445c052f2ff50b4875a2523bb279 (diff) |
perf probe: Allow placing uprobes in alternate namespaces.
Teaches perf how to place a uprobe on a file that's in a different mount
namespace. The user must add the probe using the --target-ns argument
to perf probe. Once it has been placed, it may be recorded against
without further namespace-specific commands.
Signed-off-by: Krister Johansen <kjlx@templeofstupid.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
[ PPC build fixed by Ravi: ]
Link: http://lkml.kernel.org/r/1500287542-6219-1-git-send-email-ravi.bangoria@linux.vnet.ibm.com
Cc: Thomas-Mich Richter <tmricht@linux.vnet.ibm.com>
[ Fix !HAVE_DWARF_SUPPORT build ]
Link: http://lkml.kernel.org/r/1499305693-1599-4-git-send-email-kjlx@templeofstupid.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/perf/Documentation/perf-probe.txt | 9 | ||||
-rw-r--r-- | tools/perf/arch/powerpc/util/sym-handling.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-probe.c | 43 | ||||
-rw-r--r-- | tools/perf/util/namespaces.c | 13 | ||||
-rw-r--r-- | tools/perf/util/namespaces.h | 2 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 80 | ||||
-rw-r--r-- | tools/perf/util/probe-event.h | 10 |
7 files changed, 125 insertions, 34 deletions
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 165c2b1d4317..a42aabc2b082 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt | |||
@@ -130,6 +130,11 @@ OPTIONS | |||
130 | --max-probes=NUM:: | 130 | --max-probes=NUM:: |
131 | Set the maximum number of probe points for an event. Default is 128. | 131 | Set the maximum number of probe points for an event. Default is 128. |
132 | 132 | ||
133 | --target-ns=PID: | ||
134 | Obtain mount namespace information from the target pid. This is | ||
135 | used when creating a uprobe for a process that resides in a | ||
136 | different mount namespace from the perf(1) utility. | ||
137 | |||
133 | -x:: | 138 | -x:: |
134 | --exec=PATH:: | 139 | --exec=PATH:: |
135 | Specify path to the executable or shared library file for user | 140 | Specify path to the executable or shared library file for user |
@@ -264,6 +269,10 @@ Add probes at malloc() function on libc | |||
264 | 269 | ||
265 | ./perf probe -x /lib/libc.so.6 malloc or ./perf probe /lib/libc.so.6 malloc | 270 | ./perf probe -x /lib/libc.so.6 malloc or ./perf probe /lib/libc.so.6 malloc |
266 | 271 | ||
272 | Add a uprobe to a target process running in a different mount namespace | ||
273 | |||
274 | ./perf probe --target-ns <target pid> -x /lib64/libc.so.6 malloc | ||
275 | |||
267 | SEE ALSO | 276 | SEE ALSO |
268 | -------- | 277 | -------- |
269 | linkperf:perf-trace[1], linkperf:perf-record[1], linkperf:perf-buildid-cache[1] | 278 | linkperf:perf-trace[1], linkperf:perf-record[1], linkperf:perf-buildid-cache[1] |
diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c index bf9a2594572c..9c4e23d8c8ce 100644 --- a/tools/perf/arch/powerpc/util/sym-handling.c +++ b/tools/perf/arch/powerpc/util/sym-handling.c | |||
@@ -126,7 +126,7 @@ void arch__post_process_probe_trace_events(struct perf_probe_event *pev, | |||
126 | struct rb_node *tmp; | 126 | struct rb_node *tmp; |
127 | int i = 0; | 127 | int i = 0; |
128 | 128 | ||
129 | map = get_target_map(pev->target, pev->uprobes); | 129 | map = get_target_map(pev->target, pev->nsi, pev->uprobes); |
130 | if (!map || map__load(map) < 0) | 130 | if (!map || map__load(map) < 0) |
131 | return; | 131 | return; |
132 | 132 | ||
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index cf9f9e9c2fc0..3fb98d59cd27 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -58,6 +58,7 @@ static struct { | |||
58 | struct line_range line_range; | 58 | struct line_range line_range; |
59 | char *target; | 59 | char *target; |
60 | struct strfilter *filter; | 60 | struct strfilter *filter; |
61 | struct nsinfo *nsi; | ||
61 | } params; | 62 | } params; |
62 | 63 | ||
63 | /* Parse an event definition. Note that any error must die. */ | 64 | /* Parse an event definition. Note that any error must die. */ |
@@ -80,6 +81,9 @@ static int parse_probe_event(const char *str) | |||
80 | params.target_used = true; | 81 | params.target_used = true; |
81 | } | 82 | } |
82 | 83 | ||
84 | if (params.nsi) | ||
85 | pev->nsi = nsinfo__get(params.nsi); | ||
86 | |||
83 | /* Parse a perf-probe command into event */ | 87 | /* Parse a perf-probe command into event */ |
84 | ret = parse_perf_probe_command(str, pev); | 88 | ret = parse_perf_probe_command(str, pev); |
85 | pr_debug("%d arguments\n", pev->nargs); | 89 | pr_debug("%d arguments\n", pev->nargs); |
@@ -189,7 +193,7 @@ static int opt_set_target(const struct option *opt, const char *str, | |||
189 | 193 | ||
190 | /* Expand given path to absolute path, except for modulename */ | 194 | /* Expand given path to absolute path, except for modulename */ |
191 | if (params.uprobes || strchr(str, '/')) { | 195 | if (params.uprobes || strchr(str, '/')) { |
192 | tmp = realpath(str, NULL); | 196 | tmp = nsinfo__realpath(str, params.nsi); |
193 | if (!tmp) { | 197 | if (!tmp) { |
194 | pr_warning("Failed to get the absolute path of %s: %m\n", str); | 198 | pr_warning("Failed to get the absolute path of %s: %m\n", str); |
195 | return ret; | 199 | return ret; |
@@ -208,6 +212,34 @@ static int opt_set_target(const struct option *opt, const char *str, | |||
208 | return ret; | 212 | return ret; |
209 | } | 213 | } |
210 | 214 | ||
215 | static int opt_set_target_ns(const struct option *opt __maybe_unused, | ||
216 | const char *str, int unset __maybe_unused) | ||
217 | { | ||
218 | int ret = -ENOENT; | ||
219 | pid_t ns_pid; | ||
220 | struct nsinfo *nsip; | ||
221 | |||
222 | if (str) { | ||
223 | errno = 0; | ||
224 | ns_pid = (pid_t)strtol(str, NULL, 10); | ||
225 | if (errno != 0) { | ||
226 | ret = -errno; | ||
227 | pr_warning("Failed to parse %s as a pid: %s\n", str, | ||
228 | strerror(errno)); | ||
229 | return ret; | ||
230 | } | ||
231 | nsip = nsinfo__new(ns_pid); | ||
232 | if (nsip && nsip->need_setns) | ||
233 | params.nsi = nsinfo__get(nsip); | ||
234 | nsinfo__put(nsip); | ||
235 | |||
236 | ret = 0; | ||
237 | } | ||
238 | |||
239 | return ret; | ||
240 | } | ||
241 | |||
242 | |||
211 | /* Command option callbacks */ | 243 | /* Command option callbacks */ |
212 | 244 | ||
213 | #ifdef HAVE_DWARF_SUPPORT | 245 | #ifdef HAVE_DWARF_SUPPORT |
@@ -299,6 +331,7 @@ static void cleanup_params(void) | |||
299 | line_range__clear(¶ms.line_range); | 331 | line_range__clear(¶ms.line_range); |
300 | free(params.target); | 332 | free(params.target); |
301 | strfilter__delete(params.filter); | 333 | strfilter__delete(params.filter); |
334 | nsinfo__put(params.nsi); | ||
302 | memset(¶ms, 0, sizeof(params)); | 335 | memset(¶ms, 0, sizeof(params)); |
303 | } | 336 | } |
304 | 337 | ||
@@ -554,6 +587,8 @@ __cmd_probe(int argc, const char **argv) | |||
554 | OPT_BOOLEAN(0, "cache", &probe_conf.cache, "Manipulate probe cache"), | 587 | OPT_BOOLEAN(0, "cache", &probe_conf.cache, "Manipulate probe cache"), |
555 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", | 588 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", |
556 | "Look for files with symbols relative to this directory"), | 589 | "Look for files with symbols relative to this directory"), |
590 | OPT_CALLBACK(0, "target-ns", NULL, "pid", | ||
591 | "target pid for namespace contexts", opt_set_target_ns), | ||
557 | OPT_END() | 592 | OPT_END() |
558 | }; | 593 | }; |
559 | int ret; | 594 | int ret; |
@@ -634,15 +669,15 @@ __cmd_probe(int argc, const char **argv) | |||
634 | pr_err_with_code(" Error: Failed to show event list.", ret); | 669 | pr_err_with_code(" Error: Failed to show event list.", ret); |
635 | return ret; | 670 | return ret; |
636 | case 'F': | 671 | case 'F': |
637 | ret = show_available_funcs(params.target, params.filter, | 672 | ret = show_available_funcs(params.target, params.nsi, |
638 | params.uprobes); | 673 | params.filter, params.uprobes); |
639 | if (ret < 0) | 674 | if (ret < 0) |
640 | pr_err_with_code(" Error: Failed to show functions.", ret); | 675 | pr_err_with_code(" Error: Failed to show functions.", ret); |
641 | return ret; | 676 | return ret; |
642 | #ifdef HAVE_DWARF_SUPPORT | 677 | #ifdef HAVE_DWARF_SUPPORT |
643 | case 'L': | 678 | case 'L': |
644 | ret = show_line_range(¶ms.line_range, params.target, | 679 | ret = show_line_range(¶ms.line_range, params.target, |
645 | params.uprobes); | 680 | params.nsi, params.uprobes); |
646 | if (ret < 0) | 681 | if (ret < 0) |
647 | pr_err_with_code(" Error: Failed to show lines.", ret); | 682 | pr_err_with_code(" Error: Failed to show lines.", ret); |
648 | return ret; | 683 | return ret; |
diff --git a/tools/perf/util/namespaces.c b/tools/perf/util/namespaces.c index fc5f398779a4..a58e91197729 100644 --- a/tools/perf/util/namespaces.c +++ b/tools/perf/util/namespaces.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include "event.h" | 11 | #include "event.h" |
12 | #include <sys/types.h> | 12 | #include <sys/types.h> |
13 | #include <sys/stat.h> | 13 | #include <sys/stat.h> |
14 | #include <limits.h> | ||
14 | #include <sched.h> | 15 | #include <sched.h> |
15 | #include <stdlib.h> | 16 | #include <stdlib.h> |
16 | #include <stdio.h> | 17 | #include <stdio.h> |
@@ -233,3 +234,15 @@ void nsinfo__mountns_exit(struct nscookie *nc) | |||
233 | nc->newns = -1; | 234 | nc->newns = -1; |
234 | } | 235 | } |
235 | } | 236 | } |
237 | |||
238 | char *nsinfo__realpath(const char *path, struct nsinfo *nsi) | ||
239 | { | ||
240 | char *rpath; | ||
241 | struct nscookie nsc; | ||
242 | |||
243 | nsinfo__mountns_enter(nsi, &nsc); | ||
244 | rpath = realpath(path, NULL); | ||
245 | nsinfo__mountns_exit(&nsc); | ||
246 | |||
247 | return rpath; | ||
248 | } | ||
diff --git a/tools/perf/util/namespaces.h b/tools/perf/util/namespaces.h index f19aa41119ae..05d82601c9a6 100644 --- a/tools/perf/util/namespaces.h +++ b/tools/perf/util/namespaces.h | |||
@@ -49,6 +49,8 @@ void nsinfo__put(struct nsinfo *nsi); | |||
49 | void nsinfo__mountns_enter(struct nsinfo *nsi, struct nscookie *nc); | 49 | void nsinfo__mountns_enter(struct nsinfo *nsi, struct nscookie *nc); |
50 | void nsinfo__mountns_exit(struct nscookie *nc); | 50 | void nsinfo__mountns_exit(struct nscookie *nc); |
51 | 51 | ||
52 | char *nsinfo__realpath(const char *path, struct nsinfo *nsi); | ||
53 | |||
52 | static inline void __nsinfo__zput(struct nsinfo **nsip) | 54 | static inline void __nsinfo__zput(struct nsinfo **nsip) |
53 | { | 55 | { |
54 | if (nsip) { | 56 | if (nsip) { |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index a2670e9d652d..a80895a7e611 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -184,13 +184,19 @@ static struct map *kernel_get_module_map(const char *module) | |||
184 | return NULL; | 184 | return NULL; |
185 | } | 185 | } |
186 | 186 | ||
187 | struct map *get_target_map(const char *target, bool user) | 187 | struct map *get_target_map(const char *target, struct nsinfo *nsi, bool user) |
188 | { | 188 | { |
189 | /* Init maps of given executable or kernel */ | 189 | /* Init maps of given executable or kernel */ |
190 | if (user) | 190 | if (user) { |
191 | return dso__new_map(target); | 191 | struct map *map; |
192 | else | 192 | |
193 | map = dso__new_map(target); | ||
194 | if (map && map->dso) | ||
195 | map->dso->nsinfo = nsinfo__get(nsi); | ||
196 | return map; | ||
197 | } else { | ||
193 | return kernel_get_module_map(target); | 198 | return kernel_get_module_map(target); |
199 | } | ||
194 | } | 200 | } |
195 | 201 | ||
196 | static int convert_exec_to_group(const char *exec, char **result) | 202 | static int convert_exec_to_group(const char *exec, char **result) |
@@ -366,7 +372,8 @@ found: | |||
366 | static int find_alternative_probe_point(struct debuginfo *dinfo, | 372 | static int find_alternative_probe_point(struct debuginfo *dinfo, |
367 | struct perf_probe_point *pp, | 373 | struct perf_probe_point *pp, |
368 | struct perf_probe_point *result, | 374 | struct perf_probe_point *result, |
369 | const char *target, bool uprobes) | 375 | const char *target, struct nsinfo *nsi, |
376 | bool uprobes) | ||
370 | { | 377 | { |
371 | struct map *map = NULL; | 378 | struct map *map = NULL; |
372 | struct symbol *sym; | 379 | struct symbol *sym; |
@@ -377,7 +384,7 @@ static int find_alternative_probe_point(struct debuginfo *dinfo, | |||
377 | if (!pp->function || pp->file) | 384 | if (!pp->function || pp->file) |
378 | return -ENOTSUP; | 385 | return -ENOTSUP; |
379 | 386 | ||
380 | map = get_target_map(target, uprobes); | 387 | map = get_target_map(target, nsi, uprobes); |
381 | if (!map) | 388 | if (!map) |
382 | return -EINVAL; | 389 | return -EINVAL; |
383 | 390 | ||
@@ -421,8 +428,8 @@ static int get_alternative_probe_event(struct debuginfo *dinfo, | |||
421 | 428 | ||
422 | memcpy(tmp, &pev->point, sizeof(*tmp)); | 429 | memcpy(tmp, &pev->point, sizeof(*tmp)); |
423 | memset(&pev->point, 0, sizeof(pev->point)); | 430 | memset(&pev->point, 0, sizeof(pev->point)); |
424 | ret = find_alternative_probe_point(dinfo, tmp, &pev->point, | 431 | ret = find_alternative_probe_point(dinfo, tmp, &pev->point, pev->target, |
425 | pev->target, pev->uprobes); | 432 | pev->nsi, pev->uprobes); |
426 | if (ret < 0) | 433 | if (ret < 0) |
427 | memcpy(&pev->point, tmp, sizeof(*tmp)); | 434 | memcpy(&pev->point, tmp, sizeof(*tmp)); |
428 | 435 | ||
@@ -444,7 +451,7 @@ static int get_alternative_line_range(struct debuginfo *dinfo, | |||
444 | if (lr->end != INT_MAX) | 451 | if (lr->end != INT_MAX) |
445 | len = lr->end - lr->start; | 452 | len = lr->end - lr->start; |
446 | ret = find_alternative_probe_point(dinfo, &pp, &result, | 453 | ret = find_alternative_probe_point(dinfo, &pp, &result, |
447 | target, user); | 454 | target, NULL, user); |
448 | if (!ret) { | 455 | if (!ret) { |
449 | lr->function = result.function; | 456 | lr->function = result.function; |
450 | lr->file = result.file; | 457 | lr->file = result.file; |
@@ -457,12 +464,14 @@ static int get_alternative_line_range(struct debuginfo *dinfo, | |||
457 | } | 464 | } |
458 | 465 | ||
459 | /* Open new debuginfo of given module */ | 466 | /* Open new debuginfo of given module */ |
460 | static struct debuginfo *open_debuginfo(const char *module, bool silent) | 467 | static struct debuginfo *open_debuginfo(const char *module, struct nsinfo *nsi, |
468 | bool silent) | ||
461 | { | 469 | { |
462 | const char *path = module; | 470 | const char *path = module; |
463 | char reason[STRERR_BUFSIZE]; | 471 | char reason[STRERR_BUFSIZE]; |
464 | struct debuginfo *ret = NULL; | 472 | struct debuginfo *ret = NULL; |
465 | struct dso *dso = NULL; | 473 | struct dso *dso = NULL; |
474 | struct nscookie nsc; | ||
466 | int err; | 475 | int err; |
467 | 476 | ||
468 | if (!module || !strchr(module, '/')) { | 477 | if (!module || !strchr(module, '/')) { |
@@ -480,6 +489,7 @@ static struct debuginfo *open_debuginfo(const char *module, bool silent) | |||
480 | } | 489 | } |
481 | path = dso->long_name; | 490 | path = dso->long_name; |
482 | } | 491 | } |
492 | nsinfo__mountns_enter(nsi, &nsc); | ||
483 | ret = debuginfo__new(path); | 493 | ret = debuginfo__new(path); |
484 | if (!ret && !silent) { | 494 | if (!ret && !silent) { |
485 | pr_warning("The %s file has no debug information.\n", path); | 495 | pr_warning("The %s file has no debug information.\n", path); |
@@ -489,6 +499,7 @@ static struct debuginfo *open_debuginfo(const char *module, bool silent) | |||
489 | pr_warning("Rebuild with -g, "); | 499 | pr_warning("Rebuild with -g, "); |
490 | pr_warning("or install an appropriate debuginfo package.\n"); | 500 | pr_warning("or install an appropriate debuginfo package.\n"); |
491 | } | 501 | } |
502 | nsinfo__mountns_exit(&nsc); | ||
492 | return ret; | 503 | return ret; |
493 | } | 504 | } |
494 | 505 | ||
@@ -516,7 +527,7 @@ static struct debuginfo *debuginfo_cache__open(const char *module, bool silent) | |||
516 | goto out; | 527 | goto out; |
517 | } | 528 | } |
518 | 529 | ||
519 | debuginfo_cache = open_debuginfo(module, silent); | 530 | debuginfo_cache = open_debuginfo(module, NULL, silent); |
520 | if (!debuginfo_cache) | 531 | if (!debuginfo_cache) |
521 | zfree(&debuginfo_cache_path); | 532 | zfree(&debuginfo_cache_path); |
522 | out: | 533 | out: |
@@ -531,14 +542,18 @@ static void debuginfo_cache__exit(void) | |||
531 | } | 542 | } |
532 | 543 | ||
533 | 544 | ||
534 | static int get_text_start_address(const char *exec, unsigned long *address) | 545 | static int get_text_start_address(const char *exec, unsigned long *address, |
546 | struct nsinfo *nsi) | ||
535 | { | 547 | { |
536 | Elf *elf; | 548 | Elf *elf; |
537 | GElf_Ehdr ehdr; | 549 | GElf_Ehdr ehdr; |
538 | GElf_Shdr shdr; | 550 | GElf_Shdr shdr; |
539 | int fd, ret = -ENOENT; | 551 | int fd, ret = -ENOENT; |
552 | struct nscookie nsc; | ||
540 | 553 | ||
554 | nsinfo__mountns_enter(nsi, &nsc); | ||
541 | fd = open(exec, O_RDONLY); | 555 | fd = open(exec, O_RDONLY); |
556 | nsinfo__mountns_exit(&nsc); | ||
542 | if (fd < 0) | 557 | if (fd < 0) |
543 | return -errno; | 558 | return -errno; |
544 | 559 | ||
@@ -582,7 +597,7 @@ static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp, | |||
582 | ret = -EINVAL; | 597 | ret = -EINVAL; |
583 | goto error; | 598 | goto error; |
584 | } | 599 | } |
585 | ret = get_text_start_address(tp->module, &stext); | 600 | ret = get_text_start_address(tp->module, &stext, NULL); |
586 | if (ret < 0) | 601 | if (ret < 0) |
587 | goto error; | 602 | goto error; |
588 | addr += stext; | 603 | addr += stext; |
@@ -659,7 +674,7 @@ post_process_offline_probe_trace_events(struct probe_trace_event *tevs, | |||
659 | 674 | ||
660 | /* Prepare a map for offline binary */ | 675 | /* Prepare a map for offline binary */ |
661 | map = dso__new_map(pathname); | 676 | map = dso__new_map(pathname); |
662 | if (!map || get_text_start_address(pathname, &stext) < 0) { | 677 | if (!map || get_text_start_address(pathname, &stext, NULL) < 0) { |
663 | pr_warning("Failed to get ELF symbols for %s\n", pathname); | 678 | pr_warning("Failed to get ELF symbols for %s\n", pathname); |
664 | return -EINVAL; | 679 | return -EINVAL; |
665 | } | 680 | } |
@@ -676,7 +691,8 @@ post_process_offline_probe_trace_events(struct probe_trace_event *tevs, | |||
676 | } | 691 | } |
677 | 692 | ||
678 | static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, | 693 | static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, |
679 | int ntevs, const char *exec) | 694 | int ntevs, const char *exec, |
695 | struct nsinfo *nsi) | ||
680 | { | 696 | { |
681 | int i, ret = 0; | 697 | int i, ret = 0; |
682 | unsigned long stext = 0; | 698 | unsigned long stext = 0; |
@@ -684,7 +700,7 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, | |||
684 | if (!exec) | 700 | if (!exec) |
685 | return 0; | 701 | return 0; |
686 | 702 | ||
687 | ret = get_text_start_address(exec, &stext); | 703 | ret = get_text_start_address(exec, &stext, nsi); |
688 | if (ret < 0) | 704 | if (ret < 0) |
689 | return ret; | 705 | return ret; |
690 | 706 | ||
@@ -715,7 +731,7 @@ post_process_module_probe_trace_events(struct probe_trace_event *tevs, | |||
715 | if (!module) | 731 | if (!module) |
716 | return 0; | 732 | return 0; |
717 | 733 | ||
718 | map = get_target_map(module, false); | 734 | map = get_target_map(module, NULL, false); |
719 | if (!map || debuginfo__get_text_offset(dinfo, &text_offs, true) < 0) { | 735 | if (!map || debuginfo__get_text_offset(dinfo, &text_offs, true) < 0) { |
720 | pr_warning("Failed to get ELF symbols for %s\n", module); | 736 | pr_warning("Failed to get ELF symbols for %s\n", module); |
721 | return -EINVAL; | 737 | return -EINVAL; |
@@ -802,7 +818,8 @@ static int post_process_probe_trace_events(struct perf_probe_event *pev, | |||
802 | int ret; | 818 | int ret; |
803 | 819 | ||
804 | if (uprobe) | 820 | if (uprobe) |
805 | ret = add_exec_to_probe_trace_events(tevs, ntevs, module); | 821 | ret = add_exec_to_probe_trace_events(tevs, ntevs, module, |
822 | pev->nsi); | ||
806 | else if (module) | 823 | else if (module) |
807 | /* Currently ref_reloc_sym based probe is not for drivers */ | 824 | /* Currently ref_reloc_sym based probe is not for drivers */ |
808 | ret = post_process_module_probe_trace_events(tevs, ntevs, | 825 | ret = post_process_module_probe_trace_events(tevs, ntevs, |
@@ -825,7 +842,7 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
825 | struct debuginfo *dinfo; | 842 | struct debuginfo *dinfo; |
826 | int ntevs, ret = 0; | 843 | int ntevs, ret = 0; |
827 | 844 | ||
828 | dinfo = open_debuginfo(pev->target, !need_dwarf); | 845 | dinfo = open_debuginfo(pev->target, pev->nsi, !need_dwarf); |
829 | if (!dinfo) { | 846 | if (!dinfo) { |
830 | if (need_dwarf) | 847 | if (need_dwarf) |
831 | return -ENOENT; | 848 | return -ENOENT; |
@@ -945,7 +962,7 @@ static int __show_line_range(struct line_range *lr, const char *module, | |||
945 | char sbuf[STRERR_BUFSIZE]; | 962 | char sbuf[STRERR_BUFSIZE]; |
946 | 963 | ||
947 | /* Search a line range */ | 964 | /* Search a line range */ |
948 | dinfo = open_debuginfo(module, false); | 965 | dinfo = open_debuginfo(module, NULL, false); |
949 | if (!dinfo) | 966 | if (!dinfo) |
950 | return -ENOENT; | 967 | return -ENOENT; |
951 | 968 | ||
@@ -1021,14 +1038,18 @@ end: | |||
1021 | return ret; | 1038 | return ret; |
1022 | } | 1039 | } |
1023 | 1040 | ||
1024 | int show_line_range(struct line_range *lr, const char *module, bool user) | 1041 | int show_line_range(struct line_range *lr, const char *module, |
1042 | struct nsinfo *nsi, bool user) | ||
1025 | { | 1043 | { |
1026 | int ret; | 1044 | int ret; |
1045 | struct nscookie nsc; | ||
1027 | 1046 | ||
1028 | ret = init_probe_symbol_maps(user); | 1047 | ret = init_probe_symbol_maps(user); |
1029 | if (ret < 0) | 1048 | if (ret < 0) |
1030 | return ret; | 1049 | return ret; |
1050 | nsinfo__mountns_enter(nsi, &nsc); | ||
1031 | ret = __show_line_range(lr, module, user); | 1051 | ret = __show_line_range(lr, module, user); |
1052 | nsinfo__mountns_exit(&nsc); | ||
1032 | exit_probe_symbol_maps(); | 1053 | exit_probe_symbol_maps(); |
1033 | 1054 | ||
1034 | return ret; | 1055 | return ret; |
@@ -1111,7 +1132,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, | |||
1111 | if (ret < 0) | 1132 | if (ret < 0) |
1112 | return ret; | 1133 | return ret; |
1113 | 1134 | ||
1114 | dinfo = open_debuginfo(pevs->target, false); | 1135 | dinfo = open_debuginfo(pevs->target, pevs->nsi, false); |
1115 | if (!dinfo) { | 1136 | if (!dinfo) { |
1116 | ret = -ENOENT; | 1137 | ret = -ENOENT; |
1117 | goto out; | 1138 | goto out; |
@@ -1155,6 +1176,7 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
1155 | 1176 | ||
1156 | int show_line_range(struct line_range *lr __maybe_unused, | 1177 | int show_line_range(struct line_range *lr __maybe_unused, |
1157 | const char *module __maybe_unused, | 1178 | const char *module __maybe_unused, |
1179 | struct nsinfo *nsi __maybe_unused, | ||
1158 | bool user __maybe_unused) | 1180 | bool user __maybe_unused) |
1159 | { | 1181 | { |
1160 | pr_warning("Debuginfo-analysis is not supported.\n"); | 1182 | pr_warning("Debuginfo-analysis is not supported.\n"); |
@@ -2703,6 +2725,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, | |||
2703 | struct probe_trace_event *tev = NULL; | 2725 | struct probe_trace_event *tev = NULL; |
2704 | struct probe_cache *cache = NULL; | 2726 | struct probe_cache *cache = NULL; |
2705 | struct strlist *namelist[2] = {NULL, NULL}; | 2727 | struct strlist *namelist[2] = {NULL, NULL}; |
2728 | struct nscookie nsc; | ||
2706 | 2729 | ||
2707 | up = pev->uprobes ? 1 : 0; | 2730 | up = pev->uprobes ? 1 : 0; |
2708 | fd[up] = __open_probe_file_and_namelist(up, &namelist[up]); | 2731 | fd[up] = __open_probe_file_and_namelist(up, &namelist[up]); |
@@ -2729,7 +2752,9 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, | |||
2729 | if (ret < 0) | 2752 | if (ret < 0) |
2730 | break; | 2753 | break; |
2731 | 2754 | ||
2755 | nsinfo__mountns_enter(pev->nsi, &nsc); | ||
2732 | ret = probe_file__add_event(fd[up], tev); | 2756 | ret = probe_file__add_event(fd[up], tev); |
2757 | nsinfo__mountns_exit(&nsc); | ||
2733 | if (ret < 0) | 2758 | if (ret < 0) |
2734 | break; | 2759 | break; |
2735 | 2760 | ||
@@ -2805,7 +2830,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, | |||
2805 | int ret, i, j, skipped = 0; | 2830 | int ret, i, j, skipped = 0; |
2806 | char *mod_name; | 2831 | char *mod_name; |
2807 | 2832 | ||
2808 | map = get_target_map(pev->target, pev->uprobes); | 2833 | map = get_target_map(pev->target, pev->nsi, pev->uprobes); |
2809 | if (!map) { | 2834 | if (!map) { |
2810 | ret = -EINVAL; | 2835 | ret = -EINVAL; |
2811 | goto out; | 2836 | goto out; |
@@ -3345,13 +3370,16 @@ int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs) | |||
3345 | void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs) | 3370 | void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs) |
3346 | { | 3371 | { |
3347 | int i, j; | 3372 | int i, j; |
3373 | struct perf_probe_event *pev; | ||
3348 | 3374 | ||
3349 | /* Loop 3: cleanup and free trace events */ | 3375 | /* Loop 3: cleanup and free trace events */ |
3350 | for (i = 0; i < npevs; i++) { | 3376 | for (i = 0; i < npevs; i++) { |
3377 | pev = &pevs[i]; | ||
3351 | for (j = 0; j < pevs[i].ntevs; j++) | 3378 | for (j = 0; j < pevs[i].ntevs; j++) |
3352 | clear_probe_trace_event(&pevs[i].tevs[j]); | 3379 | clear_probe_trace_event(&pevs[i].tevs[j]); |
3353 | zfree(&pevs[i].tevs); | 3380 | zfree(&pevs[i].tevs); |
3354 | pevs[i].ntevs = 0; | 3381 | pevs[i].ntevs = 0; |
3382 | nsinfo__zput(pev->nsi); | ||
3355 | clear_perf_probe_event(&pevs[i]); | 3383 | clear_perf_probe_event(&pevs[i]); |
3356 | } | 3384 | } |
3357 | } | 3385 | } |
@@ -3409,8 +3437,8 @@ out: | |||
3409 | return ret; | 3437 | return ret; |
3410 | } | 3438 | } |
3411 | 3439 | ||
3412 | int show_available_funcs(const char *target, struct strfilter *_filter, | 3440 | int show_available_funcs(const char *target, struct nsinfo *nsi, |
3413 | bool user) | 3441 | struct strfilter *_filter, bool user) |
3414 | { | 3442 | { |
3415 | struct rb_node *nd; | 3443 | struct rb_node *nd; |
3416 | struct map *map; | 3444 | struct map *map; |
@@ -3421,7 +3449,7 @@ int show_available_funcs(const char *target, struct strfilter *_filter, | |||
3421 | return ret; | 3449 | return ret; |
3422 | 3450 | ||
3423 | /* Get a symbol map */ | 3451 | /* Get a symbol map */ |
3424 | map = get_target_map(target, user); | 3452 | map = get_target_map(target, nsi, user); |
3425 | if (!map) { | 3453 | if (!map) { |
3426 | pr_err("Failed to get a map for %s\n", (target) ? : "kernel"); | 3454 | pr_err("Failed to get a map for %s\n", (target) ? : "kernel"); |
3427 | return -EINVAL; | 3455 | return -EINVAL; |
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 5812947418dd..078681d12168 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/compiler.h> | 4 | #include <linux/compiler.h> |
5 | #include <stdbool.h> | 5 | #include <stdbool.h> |
6 | #include "intlist.h" | 6 | #include "intlist.h" |
7 | #include "namespaces.h" | ||
7 | 8 | ||
8 | /* Probe related configurations */ | 9 | /* Probe related configurations */ |
9 | struct probe_conf { | 10 | struct probe_conf { |
@@ -92,6 +93,7 @@ struct perf_probe_event { | |||
92 | struct perf_probe_arg *args; /* Arguments */ | 93 | struct perf_probe_arg *args; /* Arguments */ |
93 | struct probe_trace_event *tevs; | 94 | struct probe_trace_event *tevs; |
94 | int ntevs; | 95 | int ntevs; |
96 | struct nsinfo *nsi; /* Target namespace */ | ||
95 | }; | 97 | }; |
96 | 98 | ||
97 | /* Line range */ | 99 | /* Line range */ |
@@ -163,10 +165,12 @@ int show_perf_probe_event(const char *group, const char *event, | |||
163 | struct perf_probe_event *pev, | 165 | struct perf_probe_event *pev, |
164 | const char *module, bool use_stdout); | 166 | const char *module, bool use_stdout); |
165 | int show_perf_probe_events(struct strfilter *filter); | 167 | int show_perf_probe_events(struct strfilter *filter); |
166 | int show_line_range(struct line_range *lr, const char *module, bool user); | 168 | int show_line_range(struct line_range *lr, const char *module, |
169 | struct nsinfo *nsi, bool user); | ||
167 | int show_available_vars(struct perf_probe_event *pevs, int npevs, | 170 | int show_available_vars(struct perf_probe_event *pevs, int npevs, |
168 | struct strfilter *filter); | 171 | struct strfilter *filter); |
169 | int show_available_funcs(const char *module, struct strfilter *filter, bool user); | 172 | int show_available_funcs(const char *module, struct nsinfo *nsi, |
173 | struct strfilter *filter, bool user); | ||
170 | void arch__fix_tev_from_maps(struct perf_probe_event *pev, | 174 | void arch__fix_tev_from_maps(struct perf_probe_event *pev, |
171 | struct probe_trace_event *tev, struct map *map, | 175 | struct probe_trace_event *tev, struct map *map, |
172 | struct symbol *sym); | 176 | struct symbol *sym); |
@@ -180,7 +184,7 @@ int e_snprintf(char *str, size_t size, const char *format, ...) __printf(3, 4); | |||
180 | int copy_to_probe_trace_arg(struct probe_trace_arg *tvar, | 184 | int copy_to_probe_trace_arg(struct probe_trace_arg *tvar, |
181 | struct perf_probe_arg *pvar); | 185 | struct perf_probe_arg *pvar); |
182 | 186 | ||
183 | struct map *get_target_map(const char *target, bool user); | 187 | struct map *get_target_map(const char *target, struct nsinfo *nsi, bool user); |
184 | 188 | ||
185 | void arch__post_process_probe_trace_events(struct perf_probe_event *pev, | 189 | void arch__post_process_probe_trace_events(struct perf_probe_event *pev, |
186 | int ntevs); | 190 | int ntevs); |