diff options
| -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 2780d9ce48b..fb673bef479 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt @@ -77,7 +77,8 @@ OPTIONS  -F::  --funcs:: -	Show available functions in given module or kernel. +	Show available functions in given module or kernel. With -x/--exec, +	can also list functions in a user space executable / shared library.  --filter=FILTER::  	(Only for --vars and --funcs) Set filter. FILTER is a combination of glob @@ -98,6 +99,11 @@ OPTIONS  --max-probes::  	Set the maximum number of probe points for an event. Default is 128. +-x:: +--exec=PATH:: +	Specify path to the executable or shared library file for user +	space tracing. Can also be used with --funcs option. +  PROBE SYNTAX  ------------  Probe points are defined by following syntax. @@ -182,6 +188,13 @@ Delete all probes on schedule().   ./perf probe --del='schedule*' +Add probes at zfree() function on /bin/zsh + + ./perf probe -x /bin/zsh zfree + +Add probes at malloc() function on libc + + ./perf probe -x /lib/libc.so.6 malloc  SEE ALSO  -------- diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 4935c09dd5b..ee3d84a7c89 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -54,6 +54,7 @@ static struct {  	bool show_ext_vars;  	bool show_funcs;  	bool mod_events; +	bool uprobes;  	int nevents;  	struct perf_probe_event events[MAX_PROBES];  	struct strlist *dellist; @@ -75,6 +76,8 @@ static int parse_probe_event(const char *str)  		return -1;  	} +	pev->uprobes = params.uprobes; +  	/* Parse a perf-probe command into event */  	ret = parse_perf_probe_command(str, pev);  	pr_debug("%d arguments\n", pev->nargs); @@ -125,6 +128,28 @@ static int opt_del_probe_event(const struct option *opt __used,  	return 0;  } +static int opt_set_target(const struct option *opt, const char *str, +			int unset __used) +{ +	int ret = -ENOENT; + +	if  (str && !params.target) { +		if (!strcmp(opt->long_name, "exec")) +			params.uprobes = true; +#ifdef DWARF_SUPPORT +		else if (!strcmp(opt->long_name, "module")) +			params.uprobes = false; +#endif +		else +			return ret; + +		params.target = str; +		ret = 0; +	} + +	return ret; +} +  #ifdef DWARF_SUPPORT  static int opt_show_lines(const struct option *opt __used,  			  const char *str, int unset __used) @@ -246,9 +271,9 @@ static const struct option options[] = {  		   "file", "vmlinux pathname"),  	OPT_STRING('s', "source", &symbol_conf.source_prefix,  		   "directory", "path to kernel source"), -	OPT_STRING('m', "module", ¶ms.target, -		   "modname|path", -		   "target module name (for online) or path (for offline)"), +	OPT_CALLBACK('m', "module", NULL, "modname|path", +		"target module name (for online) or path (for offline)", +		opt_set_target),  #endif  	OPT__DRY_RUN(&probe_event_dry_run),  	OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, @@ -260,6 +285,8 @@ static const struct option options[] = {  		     "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"  		     "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",  		     opt_set_filter), +	OPT_CALLBACK('x', "exec", NULL, "executable|path", +			"target executable name or path", opt_set_target),  	OPT_END()  }; @@ -310,6 +337,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)  			pr_err("  Error: Don't use --list with --funcs.\n");  			usage_with_options(probe_usage, options);  		} +		if (params.uprobes) { +			pr_warning("  Error: Don't use --list with --exec.\n"); +			usage_with_options(probe_usage, options); +		}  		ret = show_perf_probe_events();  		if (ret < 0)  			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)  		if (!params.filter)  			params.filter = strfilter__new(DEFAULT_FUNC_FILTER,  						       NULL); -		ret = show_available_funcs(params.target, -					   params.filter); +		ret = show_available_funcs(params.target, params.filter, +					params.uprobes);  		strfilter__delete(params.filter);  		if (ret < 0)  			pr_err("  Error: Failed to show functions." @@ -343,7 +374,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)  	}  #ifdef DWARF_SUPPORT -	if (params.show_lines) { +	if (params.show_lines && !params.uprobes) {  		if (params.mod_events) {  			pr_err("  Error: Don't use --line with"  			       " --add/--del.\n"); diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 8a8ee64e72d..59dccc98b55 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -44,6 +44,7 @@  #include "trace-event.h"	/* For __unused */  #include "probe-event.h"  #include "probe-finder.h" +#include "session.h"  #define MAX_CMDLEN 256  #define MAX_PROBE_ARGS 128 @@ -70,6 +71,8 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)  }  static char *synthesize_perf_probe_point(struct perf_probe_point *pp); +static int convert_name_to_addr(struct perf_probe_event *pev, +				const char *exec);  static struct machine machine;  /* Initialize symbol maps and path of vmlinux/modules */ @@ -170,6 +173,34 @@ const char *kernel_get_module_path(const char *module)  	return (dso) ? dso->long_name : NULL;  } +static int init_user_exec(void) +{ +	int ret = 0; + +	symbol_conf.try_vmlinux_path = false; +	symbol_conf.sort_by_name = true; +	ret = symbol__init(); + +	if (ret < 0) +		pr_debug("Failed to init symbol map.\n"); + +	return ret; +} + +static int convert_to_perf_probe_point(struct probe_trace_point *tp, +					struct perf_probe_point *pp) +{ +	pp->function = strdup(tp->symbol); + +	if (pp->function == NULL) +		return -ENOMEM; + +	pp->offset = tp->offset; +	pp->retprobe = tp->retprobe; + +	return 0; +} +  #ifdef DWARF_SUPPORT  /* Open new debuginfo of given module */  static struct debuginfo *open_debuginfo(const char *module) @@ -224,10 +255,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,  	if (ret <= 0) {  		pr_debug("Failed to find corresponding probes from "  			 "debuginfo. Use kprobe event information.\n"); -		pp->function = strdup(tp->symbol); -		if (pp->function == NULL) -			return -ENOMEM; -		pp->offset = tp->offset; +		return convert_to_perf_probe_point(tp, pp);  	}  	pp->retprobe = tp->retprobe; @@ -275,9 +303,20 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,  					  int max_tevs, const char *target)  {  	bool need_dwarf = perf_probe_event_need_dwarf(pev); -	struct debuginfo *dinfo = open_debuginfo(target); +	struct debuginfo *dinfo;  	int ntevs, ret = 0; +	if (pev->uprobes) { +		if (need_dwarf) { +			pr_warning("Debuginfo-analysis is not yet supported" +					" with -x/--exec option.\n"); +			return -ENOSYS; +		} +		return convert_name_to_addr(pev, target); +	} + +	dinfo = open_debuginfo(target); +  	if (!dinfo) {  		if (need_dwarf) {  			pr_warning("Failed to open debuginfo file.\n"); @@ -603,23 +642,22 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,  		pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);  		return -ENOENT;  	} -	pp->function = strdup(tp->symbol); -	if (pp->function == NULL) -		return -ENOMEM; -	pp->offset = tp->offset; -	pp->retprobe = tp->retprobe; -	return 0; +	return convert_to_perf_probe_point(tp, pp);  }  static int try_to_find_probe_trace_events(struct perf_probe_event *pev,  				struct probe_trace_event **tevs __unused, -				int max_tevs __unused, const char *mod __unused) +				int max_tevs __unused, const char *target)  {  	if (perf_probe_event_need_dwarf(pev)) {  		pr_warning("Debuginfo-analysis is not supported.\n");  		return -ENOSYS;  	} + +	if (pev->uprobes) +		return convert_name_to_addr(pev, target); +  	return 0;  } @@ -1341,11 +1379,18 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)  	if (buf == NULL)  		return NULL; -	len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu", -			 tp->retprobe ? 'r' : 'p', -			 tev->group, tev->event, -			 tp->module ?: "", tp->module ? ":" : "", -			 tp->symbol, tp->offset); +	if (tev->uprobes) +		len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s", +				 tp->retprobe ? 'r' : 'p', +				 tev->group, tev->event, +				 tp->module, tp->symbol); +	else +		len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu", +				 tp->retprobe ? 'r' : 'p', +				 tev->group, tev->event, +				 tp->module ?: "", tp->module ? ":" : "", +				 tp->symbol, tp->offset); +  	if (len <= 0)  		goto error; @@ -1364,7 +1409,7 @@ error:  }  static int convert_to_perf_probe_event(struct probe_trace_event *tev, -				       struct perf_probe_event *pev) +			       struct perf_probe_event *pev, bool is_kprobe)  {  	char buf[64] = "";  	int i, ret; @@ -1376,7 +1421,11 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,  		return -ENOMEM;  	/* Convert trace_point to probe_point */ -	ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point); +	if (is_kprobe) +		ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point); +	else +		ret = convert_to_perf_probe_point(&tev->point, &pev->point); +  	if (ret < 0)  		return ret; @@ -1472,7 +1521,26 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)  	memset(tev, 0, sizeof(*tev));  } -static int open_kprobe_events(bool readwrite) +static void print_warn_msg(const char *file, bool is_kprobe) +{ + +	if (errno == ENOENT) { +		const char *config; + +		if (!is_kprobe) +			config = "CONFIG_UPROBE_EVENTS"; +		else +			config = "CONFIG_KPROBE_EVENTS"; + +		pr_warning("%s file does not exist - please rebuild kernel" +				" with %s.\n", file, config); +	} else +		pr_warning("Failed to open %s file: %s\n", file, +				strerror(errno)); +} + +static int open_probe_events(const char *trace_file, bool readwrite, +				bool is_kprobe)  {  	char buf[PATH_MAX];  	const char *__debugfs; @@ -1484,27 +1552,31 @@ static int open_kprobe_events(bool readwrite)  		return -ENOENT;  	} -	ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs); +	ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file);  	if (ret >= 0) {  		pr_debug("Opening %s write=%d\n", buf, readwrite);  		if (readwrite && !probe_event_dry_run)  			ret = open(buf, O_RDWR, O_APPEND);  		else  			ret = open(buf, O_RDONLY, 0); -	} -	if (ret < 0) { -		if (errno == ENOENT) -			pr_warning("kprobe_events file does not exist - please" -				 " rebuild kernel with CONFIG_KPROBE_EVENT.\n"); -		else -			pr_warning("Failed to open kprobe_events file: %s\n", -				   strerror(errno)); +		if (ret < 0) +			print_warn_msg(buf, is_kprobe);  	}  	return ret;  } -/* Get raw string list of current kprobe_events */ +static int open_kprobe_events(bool readwrite) +{ +	return open_probe_events("tracing/kprobe_events", readwrite, true); +} + +static int open_uprobe_events(bool readwrite) +{ +	return open_probe_events("tracing/uprobe_events", readwrite, false); +} + +/* Get raw string list of current kprobe_events  or uprobe_events */  static struct strlist *get_probe_trace_command_rawlist(int fd)  {  	int ret, idx; @@ -1569,36 +1641,26 @@ static int show_perf_probe_event(struct perf_probe_event *pev)  	return ret;  } -/* List up current perf-probe events */ -int show_perf_probe_events(void) +static int __show_perf_probe_events(int fd, bool is_kprobe)  { -	int fd, ret; +	int ret = 0;  	struct probe_trace_event tev;  	struct perf_probe_event pev;  	struct strlist *rawlist;  	struct str_node *ent; -	setup_pager(); -	ret = init_vmlinux(); -	if (ret < 0) -		return ret; -  	memset(&tev, 0, sizeof(tev));  	memset(&pev, 0, sizeof(pev)); -	fd = open_kprobe_events(false); -	if (fd < 0) -		return fd; -  	rawlist = get_probe_trace_command_rawlist(fd); -	close(fd);  	if (!rawlist)  		return -ENOENT;  	strlist__for_each(ent, rawlist) {  		ret = parse_probe_trace_command(ent->s, &tev);  		if (ret >= 0) { -			ret = convert_to_perf_probe_event(&tev, &pev); +			ret = convert_to_perf_probe_event(&tev, &pev, +								is_kprobe);  			if (ret >= 0)  				ret = show_perf_probe_event(&pev);  		} @@ -1612,6 +1674,33 @@ int show_perf_probe_events(void)  	return ret;  } +/* List up current perf-probe events */ +int show_perf_probe_events(void) +{ +	int fd, ret; + +	setup_pager(); +	fd = open_kprobe_events(false); + +	if (fd < 0) +		return fd; + +	ret = init_vmlinux(); +	if (ret < 0) +		return ret; + +	ret = __show_perf_probe_events(fd, true); +	close(fd); + +	fd = open_uprobe_events(false); +	if (fd >= 0) { +		ret = __show_perf_probe_events(fd, false); +		close(fd); +	} + +	return ret; +} +  /* Get current perf-probe event names */  static struct strlist *get_probe_trace_event_names(int fd, bool include_group)  { @@ -1717,7 +1806,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,  	const char *event, *group;  	struct strlist *namelist; -	fd = open_kprobe_events(true); +	if (pev->uprobes) +		fd = open_uprobe_events(true); +	else +		fd = open_kprobe_events(true); +  	if (fd < 0)  		return fd;  	/* Get current event names */ @@ -1829,6 +1922,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,  	tev->point.offset = pev->point.offset;  	tev->point.retprobe = pev->point.retprobe;  	tev->nargs = pev->nargs; +	tev->uprobes = pev->uprobes; +  	if (tev->nargs) {  		tev->args = zalloc(sizeof(struct probe_trace_arg)  				   * tev->nargs); @@ -1859,6 +1954,9 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,  		}  	} +	if (pev->uprobes) +		return 1; +  	/* Currently just checking function name from symbol map */  	sym = __find_kernel_function_by_name(tev->point.symbol, NULL);  	if (!sym) { @@ -1894,12 +1992,18 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,  	int i, j, ret;  	struct __event_package *pkgs; +	ret = 0;  	pkgs = zalloc(sizeof(struct __event_package) * npevs); +  	if (pkgs == NULL)  		return -ENOMEM; -	/* Init vmlinux path */ -	ret = init_vmlinux(); +	if (!pevs->uprobes) +		/* Init vmlinux path */ +		ret = init_vmlinux(); +	else +		ret = init_user_exec(); +  	if (ret < 0) {  		free(pkgs);  		return ret; @@ -1971,23 +2075,15 @@ error:  	return ret;  } -static int del_trace_probe_event(int fd, const char *group, -				  const char *event, struct strlist *namelist) +static int del_trace_probe_event(int fd, const char *buf, +						  struct strlist *namelist)  { -	char buf[128];  	struct str_node *ent, *n; -	int found = 0, ret = 0; - -	ret = e_snprintf(buf, 128, "%s:%s", group, event); -	if (ret < 0) { -		pr_err("Failed to copy event.\n"); -		return ret; -	} +	int ret = -1;  	if (strpbrk(buf, "*?")) { /* Glob-exp */  		strlist__for_each_safe(ent, n, namelist)  			if (strglobmatch(ent->s, buf)) { -				found++;  				ret = __del_trace_probe_event(fd, ent);  				if (ret < 0)  					break; @@ -1996,40 +2092,43 @@ static int del_trace_probe_event(int fd, const char *group,  	} else {  		ent = strlist__find(namelist, buf);  		if (ent) { -			found++;  			ret = __del_trace_probe_event(fd, ent);  			if (ret >= 0)  				strlist__remove(namelist, ent);  		}  	} -	if (found == 0 && ret >= 0) -		pr_info("Info: Event \"%s\" does not exist.\n", buf);  	return ret;  }  int del_perf_probe_events(struct strlist *dellist)  { -	int fd, ret = 0; +	int ret = -1, ufd = -1, kfd = -1; +	char buf[128];  	const char *group, *event;  	char *p, *str;  	struct str_node *ent; -	struct strlist *namelist; - -	fd = open_kprobe_events(true); -	if (fd < 0) -		return fd; +	struct strlist *namelist = NULL, *unamelist = NULL;  	/* Get current event names */ -	namelist = get_probe_trace_event_names(fd, true); -	if (namelist == NULL) -		return -EINVAL; +	kfd = open_kprobe_events(true); +	if (kfd < 0) +		return kfd; + +	namelist = get_probe_trace_event_names(kfd, true); +	ufd = open_uprobe_events(true); + +	if (ufd >= 0) +		unamelist = get_probe_trace_event_names(ufd, true); + +	if (namelist == NULL && unamelist == NULL) +		goto error;  	strlist__for_each(ent, dellist) {  		str = strdup(ent->s);  		if (str == NULL) {  			ret = -ENOMEM; -			break; +			goto error;  		}  		pr_debug("Parsing: %s\n", str);  		p = strchr(str, ':'); @@ -2041,17 +2140,46 @@ int del_perf_probe_events(struct strlist *dellist)  			group = "*";  			event = str;  		} + +		ret = e_snprintf(buf, 128, "%s:%s", group, event); +		if (ret < 0) { +			pr_err("Failed to copy event."); +			free(str); +			goto error; +		} +  		pr_debug("Group: %s, Event: %s\n", group, event); -		ret = del_trace_probe_event(fd, group, event, namelist); + +		if (namelist) +			ret = del_trace_probe_event(kfd, buf, namelist); + +		if (unamelist && ret != 0) +			ret = del_trace_probe_event(ufd, buf, unamelist); + +		if (ret != 0) +			pr_info("Info: Event \"%s\" does not exist.\n", buf); +  		free(str); -		if (ret < 0) -			break;  	} -	strlist__delete(namelist); -	close(fd); + +error: +	if (kfd >= 0) { +		if (namelist) +			strlist__delete(namelist); + +		close(kfd); +	} + +	if (ufd >= 0) { +		if (unamelist) +			strlist__delete(unamelist); + +		close(ufd); +	}  	return ret;  } +  /* TODO: don't use a global variable for filter ... */  static struct strfilter *available_func_filter; @@ -2068,30 +2196,152 @@ static int filter_available_functions(struct map *map __unused,  	return 1;  } -int show_available_funcs(const char *target, struct strfilter *_filter) +static int __show_available_funcs(struct map *map) +{ +	if (map__load(map, filter_available_functions)) { +		pr_err("Failed to load map.\n"); +		return -EINVAL; +	} +	if (!dso__sorted_by_name(map->dso, map->type)) +		dso__sort_by_name(map->dso, map->type); + +	dso__fprintf_symbols_by_name(map->dso, map->type, stdout); +	return 0; +} + +static int available_kernel_funcs(const char *module)  {  	struct map *map;  	int ret; -	setup_pager(); -  	ret = init_vmlinux();  	if (ret < 0)  		return ret; -	map = kernel_get_module_map(target); +	map = kernel_get_module_map(module);  	if (!map) { -		pr_err("Failed to find %s map.\n", (target) ? : "kernel"); +		pr_err("Failed to find %s map.\n", (module) ? : "kernel");  		return -EINVAL;  	} +	return __show_available_funcs(map); +} + +static int available_user_funcs(const char *target) +{ +	struct map *map; +	int ret; + +	ret = init_user_exec(); +	if (ret < 0) +		return ret; + +	map = dso__new_map(target); +	ret = __show_available_funcs(map); +	dso__delete(map->dso); +	map__delete(map); +	return ret; +} + +int show_available_funcs(const char *target, struct strfilter *_filter, +					bool user) +{ +	setup_pager();  	available_func_filter = _filter; + +	if (!user) +		return available_kernel_funcs(target); + +	return available_user_funcs(target); +} + +/* + * uprobe_events only accepts address: + * Convert function and any offset to address + */ +static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec) +{ +	struct perf_probe_point *pp = &pev->point; +	struct symbol *sym; +	struct map *map = NULL; +	char *function = NULL, *name = NULL; +	int ret = -EINVAL; +	unsigned long long vaddr = 0; + +	if (!pp->function) { +		pr_warning("No function specified for uprobes"); +		goto out; +	} + +	function = strdup(pp->function); +	if (!function) { +		pr_warning("Failed to allocate memory by strdup.\n"); +		ret = -ENOMEM; +		goto out; +	} + +	name = realpath(exec, NULL); +	if (!name) { +		pr_warning("Cannot find realpath for %s.\n", exec); +		goto out; +	} +	map = dso__new_map(name); +	if (!map) { +		pr_warning("Cannot find appropriate DSO for %s.\n", exec); +		goto out; +	} +	available_func_filter = strfilter__new(function, NULL);  	if (map__load(map, filter_available_functions)) {  		pr_err("Failed to load map.\n"); -		return -EINVAL; +		goto out;  	} -	if (!dso__sorted_by_name(map->dso, map->type)) -		dso__sort_by_name(map->dso, map->type); -	dso__fprintf_symbols_by_name(map->dso, map->type, stdout); -	return 0; +	sym = map__find_symbol_by_name(map, function, NULL); +	if (!sym) { +		pr_warning("Cannot find %s in DSO %s\n", function, exec); +		goto out; +	} + +	if (map->start > sym->start) +		vaddr = map->start; +	vaddr += sym->start + pp->offset + map->pgoff; +	pp->offset = 0; + +	if (!pev->event) { +		pev->event = function; +		function = NULL; +	} +	if (!pev->group) { +		char *ptr1, *ptr2; + +		pev->group = zalloc(sizeof(char *) * 64); +		ptr1 = strdup(basename(exec)); +		if (ptr1) { +			ptr2 = strpbrk(ptr1, "-._"); +			if (ptr2) +				*ptr2 = '\0'; +			e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP, +					ptr1); +			free(ptr1); +		} +	} +	free(pp->function); +	pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS); +	if (!pp->function) { +		ret = -ENOMEM; +		pr_warning("Failed to allocate memory by zalloc.\n"); +		goto out; +	} +	e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr); +	ret = 0; + +out: +	if (map) { +		dso__delete(map->dso); +		map__delete(map); +	} +	if (function) +		free(function); +	if (name) +		free(name); +	return ret;  } diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index a7dee835f49..f9f3de8b422 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -7,7 +7,7 @@  extern bool probe_event_dry_run; -/* kprobe-tracer tracing point */ +/* kprobe-tracer and uprobe-tracer tracing point */  struct probe_trace_point {  	char		*symbol;	/* Base symbol */  	char		*module;	/* Module name */ @@ -21,7 +21,7 @@ struct probe_trace_arg_ref {  	long				offset;	/* Offset value */  }; -/* kprobe-tracer tracing argument */ +/* kprobe-tracer and uprobe-tracer tracing argument */  struct probe_trace_arg {  	char				*name;	/* Argument name */  	char				*value;	/* Base value */ @@ -29,12 +29,13 @@ struct probe_trace_arg {  	struct probe_trace_arg_ref	*ref;	/* Referencing offset */  }; -/* kprobe-tracer tracing event (point + arg) */ +/* kprobe-tracer and uprobe-tracer tracing event (point + arg) */  struct probe_trace_event {  	char				*event;	/* Event name */  	char				*group;	/* Group name */  	struct probe_trace_point	point;	/* Trace point */  	int				nargs;	/* Number of args */ +	bool				uprobes;	/* uprobes only */  	struct probe_trace_arg		*args;	/* Arguments */  }; @@ -70,6 +71,7 @@ struct perf_probe_event {  	char			*group;	/* Group name */  	struct perf_probe_point	point;	/* Probe point */  	int			nargs;	/* Number of arguments */ +	bool			uprobes;  	struct perf_probe_arg	*args;	/* Arguments */  }; @@ -129,8 +131,8 @@ extern int show_line_range(struct line_range *lr, const char *module);  extern int show_available_vars(struct perf_probe_event *pevs, int npevs,  			       int max_probe_points, const char *module,  			       struct strfilter *filter, bool externs); -extern int show_available_funcs(const char *module, struct strfilter *filter); - +extern int show_available_funcs(const char *module, struct strfilter *filter, +				bool user);  /* Maximum index number of event-name postfix */  #define MAX_EVENT_INDEX	1024 diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index c0a028c3eba..caaf75ad645 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,  	return ret;  } + +struct map *dso__new_map(const char *name) +{ +	struct dso *dso = dso__new(name); +	struct map *map = map__new2(0, dso, MAP__FUNCTION); + +	return map; +} diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 1f003884f1a..5649d63798c 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);  void dso__set_build_id(struct dso *dso, void *build_id);  void dso__read_running_kernel_build_id(struct dso *dso,  				       struct machine *machine); +struct map *dso__new_map(const char *name);  struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,  				u64 addr);  struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,  |