lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20131220180154.GB28878@ghostprotocols.net>
Date:	Fri, 20 Dec 2013 15:01:54 -0300
From:	Arnaldo Carvalho de Melo <acme@...stprotocols.net>
To:	Masami Hiramatsu <masami.hiramatsu.pt@...achi.com>
Cc:	Ingo Molnar <mingo@...nel.org>,
	Srikar Dronamraju <srikar@...ux.vnet.ibm.com>,
	David Ahern <dsahern@...il.com>,
	lkml <linux-kernel@...r.kernel.org>,
	"Steven Rostedt (Red Hat)" <rostedt@...dmis.org>,
	Oleg Nesterov <oleg@...hat.com>,
	"David A. Long" <dave.long@...aro.org>, systemtap@...rceware.org,
	yrl.pp-manager.tt@...achi.com, Namhyung Kim <namhyung@...nel.org>
Subject: Re: [PATCH -tip  2/3] perf-probe: Support dwarf on uprobe events

Em Fri, Dec 20, 2013 at 10:02:59AM +0000, Masami Hiramatsu escreveu:
> Support dwarf(debuginfo) based operations for uprobe events.
> With this change, perf probe can analyze debuginfo of user
> application binary to set up new uprobe event.
> This allows perf-probe --add/--line works with -x option.
> (Actually, --vars has already accepted -x option)

Can you provide an example?

Showing output from commands when new features are implemented can speed
up the process of having it used :-)

- Arnaldo
 
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@...achi.com>
> ---
>  tools/perf/builtin-probe.c    |    2 
>  tools/perf/util/probe-event.c |  230 +++++++++++++++++++++++++++--------------
>  2 files changed, 155 insertions(+), 77 deletions(-)
> 
> diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
> index b40d064..7fc566a 100644
> --- a/tools/perf/builtin-probe.c
> +++ b/tools/perf/builtin-probe.c
> @@ -420,7 +420,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
>  	}
>  
>  #ifdef HAVE_DWARF_SUPPORT
> -	if (params.show_lines && !params.uprobes) {
> +	if (params.show_lines) {
>  		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 05be5de..e27cecb 100644
> --- a/tools/perf/util/probe-event.c
> +++ b/tools/perf/util/probe-event.c
> @@ -186,6 +186,90 @@ static int init_user_exec(void)
>  	return ret;
>  }
>  
> +static const char *__target_symbol;
> +static struct symbol *__result_sym;
> +
> +static int filter_target_symbol(struct map *map __maybe_unused,
> +				struct symbol *sym)
> +{
> +	if (strcmp(__target_symbol, sym->name) == 0) {
> +		__result_sym = sym;
> +		return 0;
> +	}
> +	return 1;
> +}
> +
> +/* Find the offset of the symbol in the executable binary */
> +static int find_symbol_offset(const char *exec, const char *function,
> +			      unsigned long *offs)
> +{
> +	struct symbol *sym;
> +	struct map *map = NULL;
> +	int ret = -EINVAL;
> +
> +	if (!offs)
> +		return -EINVAL;
> +
> +	map = dso__new_map(exec);
> +	if (!map) {
> +		pr_warning("Cannot find appropriate DSO for %s.\n", exec);
> +		goto out;
> +	}
> +	pr_debug("Search %s in %s\n", function, exec);
> +	__target_symbol = function;
> +	__result_sym = NULL;
> +	if (map__load(map, filter_target_symbol)) {
> +		pr_err("Failed to find %s in %s.\n", function, exec);
> +		goto out;
> +	}
> +	sym = __result_sym;
> +	if (!sym) {
> +		pr_warning("Cannot find %s in DSO %s\n", function, exec);
> +		goto out;
> +	}
> +
> +	*offs = (map->start > sym->start) ?  map->start : 0;
> +	*offs += sym->start + map->pgoff;
> +	ret = 0;
> +out:
> +	if (map) {
> +		dso__delete(map->dso);
> +		map__delete(map);
> +	}
> +	return ret;
> +}
> +
> +static int convert_exec_to_group(const char *exec, char **result)
> +{
> +	char *ptr1, *ptr2, *exec_copy;
> +	char buf[64];
> +	int ret;
> +
> +	exec_copy = strdup(exec);
> +	if (!exec_copy)
> +		return -ENOMEM;
> +
> +	ptr1 = basename(exec_copy);
> +	if (!ptr1) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	ptr2 = strpbrk(ptr1, "-._");
> +	if (ptr2)
> +		*ptr2 = '\0';
> +	ret = e_snprintf(buf, 64, "%s_%s", PERFPROBE_GROUP, ptr1);
> +	if (ret < 0)
> +		goto out;
> +
> +	*result = strdup(buf);
> +	ret = *result ? 0 : -ENOMEM;
> +
> +out:
> +	free(exec_copy);
> +	return ret;
> +}
> +
>  static int convert_to_perf_probe_point(struct probe_trace_point *tp,
>  					struct perf_probe_point *pp)
>  {
> @@ -261,6 +345,45 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
>  	return 0;
>  }
>  
> +static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
> +					  int ntevs, const char *exec,
> +					  const char *group)
> +{
> +	int i, ret = 0;
> +	unsigned long offset;
> +	char buf[32];
> +
> +	if (!exec)
> +		return 0;
> +
> +	for (i = 0; i < ntevs && ret >= 0; i++) {
> +		/* Get proper offset */
> +		ret = find_symbol_offset(exec, tevs[i].point.symbol, &offset);
> +		if (ret < 0)
> +			break;
> +		offset += tevs[i].point.offset;
> +		tevs[i].point.offset = 0;
> +		free(tevs[i].point.symbol);
> +		ret = e_snprintf(buf, 32, "0x%lx", offset);
> +		if (ret < 0)
> +			break;
> +		tevs[i].point.module = strdup(exec);
> +		tevs[i].point.symbol = strdup(buf);
> +		if (!tevs[i].point.symbol || !tevs[i].point.module) {
> +			ret = -ENOMEM;
> +			break;
> +		}
> +		/* Replace group name if not given */
> +		if (!group) {
> +			free(tevs[i].group);
> +			ret = convert_exec_to_group(exec, &tevs[i].group);
> +		}
> +		tevs[i].uprobes = true;
> +	}
> +
> +	return ret;
> +}
> +
>  static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
>  					    int ntevs, const char *module)
>  {
> @@ -305,15 +428,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
>  	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) {
> @@ -332,9 +446,14 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
>  
>  	if (ntevs > 0) {	/* Succeeded to find trace events */
>  		pr_debug("find %d probe_trace_events.\n", ntevs);
> -		if (target)
> -			ret = add_module_to_probe_trace_events(*tevs, ntevs,
> -							       target);
> +		if (target) {
> +			if (pev->uprobes)
> +				ret = add_exec_to_probe_trace_events(*tevs,
> +						 ntevs, target, pev->group);
> +			else
> +				ret = add_module_to_probe_trace_events(*tevs,
> +						 ntevs, target);
> +		}
>  		return ret < 0 ? ret : ntevs;
>  	}
>  
> @@ -654,9 +773,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
>  		return -ENOSYS;
>  	}
>  
> -	if (pev->uprobes)
> -		return convert_name_to_addr(pev, target);
> -
>  	return 0;
>  }
>  
> @@ -1916,11 +2032,26 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
>  	int ret = 0, i;
>  	struct probe_trace_event *tev;
>  
> +	if (pev->uprobes)
> +		if (!pev->group) {
> +			ret = convert_exec_to_group(target, &pev->group);
> +			if (ret != 0) {
> +				pr_warning("Failed to make group name.\n");
> +				return ret;
> +			}
> +		}
> +
>  	/* Convert perf_probe_event with debuginfo */
>  	ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
>  	if (ret != 0)
>  		return ret;	/* Found in debuginfo or got an error */
>  
> +	if (pev->uprobes) {
> +		ret = convert_name_to_addr(pev, target);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
>  	/* Allocate trace event buffer */
>  	tev = *tevs = zalloc(sizeof(struct probe_trace_event));
>  	if (tev == NULL)
> @@ -2279,88 +2410,35 @@ int show_available_funcs(const char *target, struct strfilter *_filter,
>  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;
>  	int ret = -EINVAL;
> -	unsigned long long vaddr = 0;
> +	unsigned 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;
> -	}
> -
> -	map = dso__new_map(exec);
> -	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");
> -		goto out;
> -	}
> -
> -	sym = map__find_symbol_by_name(map, function, NULL);
> -	if (!sym) {
> -		pr_warning("Cannot find %s in DSO %s\n", function, exec);
> +	ret = find_symbol_offset(exec, pp->function, &vaddr);
> +	if (ret < 0)
>  		goto out;
> -	}
>  
> -	if (map->start > sym->start)
> -		vaddr = map->start;
> -	vaddr += sym->start + pp->offset + map->pgoff;
> +	vaddr += pp->offset;
>  	pp->offset = 0;
>  
>  	if (!pev->event) {
> -		pev->event = function;
> -		function = NULL;
> -	}
> -	if (!pev->group) {
> -		char *ptr1, *ptr2, *exec_copy;
> -
> -		pev->group = zalloc(sizeof(char *) * 64);
> -		exec_copy = strdup(exec);
> -		if (!exec_copy) {
> -			ret = -ENOMEM;
> -			pr_warning("Failed to copy exec string.\n");
> -			goto out;
> -		}
> +		pev->event = pp->function;
> +	} else
> +		free(pp->function);
>  
> -		ptr1 = strdup(basename(exec_copy));
> -		if (ptr1) {
> -			ptr2 = strpbrk(ptr1, "-._");
> -			if (ptr2)
> -				*ptr2 = '\0';
> -			e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
> -					ptr1);
> -			free(ptr1);
> -		}
> -		free(exec_copy);
> -	}
> -	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);
> +	e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%lx", vaddr);
>  	ret = 0;
>  
>  out:
> -	if (map) {
> -		dso__delete(map->dso);
> -		map__delete(map);
> -	}
> -	if (function)
> -		free(function);
>  	return ret;
>  }
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ