Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 544abd44 authored by Krister Johansen's avatar Krister Johansen Committed by Arnaldo Carvalho de Melo
Browse files

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: default avatarKrister 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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent bf2e710b
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -130,6 +130,11 @@ OPTIONS
--max-probes=NUM::
	Set the maximum number of probe points for an event. Default is 128.

--target-ns=PID:
	Obtain mount namespace information from the target pid.  This is
	used when creating a uprobe for a process that resides in a
	different mount namespace from the perf(1) utility.

-x::
--exec=PATH::
	Specify path to the executable or shared library file for user
@@ -264,6 +269,10 @@ Add probes at malloc() function on libc

 ./perf probe -x /lib/libc.so.6 malloc or ./perf probe /lib/libc.so.6 malloc

Add a uprobe to a target process running in a different mount namespace

 ./perf probe --target-ns <target pid> -x /lib64/libc.so.6 malloc

SEE ALSO
--------
linkperf:perf-trace[1], linkperf:perf-record[1], linkperf:perf-buildid-cache[1]
+1 −1
Original line number Diff line number Diff line
@@ -126,7 +126,7 @@ void arch__post_process_probe_trace_events(struct perf_probe_event *pev,
	struct rb_node *tmp;
	int i = 0;

	map = get_target_map(pev->target, pev->uprobes);
	map = get_target_map(pev->target, pev->nsi, pev->uprobes);
	if (!map || map__load(map) < 0)
		return;

+39 −4
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ static struct {
	struct line_range line_range;
	char *target;
	struct strfilter *filter;
	struct nsinfo *nsi;
} params;

/* Parse an event definition. Note that any error must die. */
@@ -80,6 +81,9 @@ static int parse_probe_event(const char *str)
		params.target_used = true;
	}

	if (params.nsi)
		pev->nsi = nsinfo__get(params.nsi);

	/* Parse a perf-probe command into event */
	ret = parse_perf_probe_command(str, pev);
	pr_debug("%d arguments\n", pev->nargs);
@@ -189,7 +193,7 @@ static int opt_set_target(const struct option *opt, const char *str,

		/* Expand given path to absolute path, except for modulename */
		if (params.uprobes || strchr(str, '/')) {
			tmp = realpath(str, NULL);
			tmp = nsinfo__realpath(str, params.nsi);
			if (!tmp) {
				pr_warning("Failed to get the absolute path of %s: %m\n", str);
				return ret;
@@ -208,6 +212,34 @@ static int opt_set_target(const struct option *opt, const char *str,
	return ret;
}

static int opt_set_target_ns(const struct option *opt __maybe_unused,
			     const char *str, int unset __maybe_unused)
{
	int ret = -ENOENT;
	pid_t ns_pid;
	struct nsinfo *nsip;

	if (str) {
		errno = 0;
		ns_pid = (pid_t)strtol(str, NULL, 10);
		if (errno != 0) {
			ret = -errno;
			pr_warning("Failed to parse %s as a pid: %s\n", str,
				   strerror(errno));
			return ret;
		}
		nsip = nsinfo__new(ns_pid);
		if (nsip && nsip->need_setns)
			params.nsi = nsinfo__get(nsip);
		nsinfo__put(nsip);

		ret = 0;
	}

	return ret;
}


/* Command option callbacks */

#ifdef HAVE_DWARF_SUPPORT
@@ -299,6 +331,7 @@ static void cleanup_params(void)
	line_range__clear(&params.line_range);
	free(params.target);
	strfilter__delete(params.filter);
	nsinfo__put(params.nsi);
	memset(&params, 0, sizeof(params));
}

@@ -554,6 +587,8 @@ __cmd_probe(int argc, const char **argv)
	OPT_BOOLEAN(0, "cache", &probe_conf.cache, "Manipulate probe cache"),
	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
		   "Look for files with symbols relative to this directory"),
	OPT_CALLBACK(0, "target-ns", NULL, "pid",
		     "target pid for namespace contexts", opt_set_target_ns),
	OPT_END()
	};
	int ret;
@@ -634,15 +669,15 @@ __cmd_probe(int argc, const char **argv)
			pr_err_with_code("  Error: Failed to show event list.", ret);
		return ret;
	case 'F':
		ret = show_available_funcs(params.target, params.filter,
					params.uprobes);
		ret = show_available_funcs(params.target, params.nsi,
					   params.filter, params.uprobes);
		if (ret < 0)
			pr_err_with_code("  Error: Failed to show functions.", ret);
		return ret;
#ifdef HAVE_DWARF_SUPPORT
	case 'L':
		ret = show_line_range(&params.line_range, params.target,
				      params.uprobes);
				      params.nsi, params.uprobes);
		if (ret < 0)
			pr_err_with_code("  Error: Failed to show lines.", ret);
		return ret;
+13 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include "event.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <sched.h>
#include <stdlib.h>
#include <stdio.h>
@@ -233,3 +234,15 @@ void nsinfo__mountns_exit(struct nscookie *nc)
		nc->newns = -1;
	}
}

char *nsinfo__realpath(const char *path, struct nsinfo *nsi)
{
	char *rpath;
	struct nscookie nsc;

	nsinfo__mountns_enter(nsi, &nsc);
	rpath = realpath(path, NULL);
	nsinfo__mountns_exit(&nsc);

	return rpath;
}
+2 −0
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ void nsinfo__put(struct nsinfo *nsi);
void nsinfo__mountns_enter(struct nsinfo *nsi, struct nscookie *nc);
void nsinfo__mountns_exit(struct nscookie *nc);

char *nsinfo__realpath(const char *path, struct nsinfo *nsi);

static inline void __nsinfo__zput(struct nsinfo **nsip)
{
	if (nsip) {
Loading