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

Commit 4c859351 authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Arnaldo Carvalho de Melo
Browse files

perf probe: Support glob wildcards for function name



Support glob wildcards for function name when adding new probes. This
will allow us to build caches of function-entry level information with
$params.

e.g.
  ----
  # perf probe --no-inlines --add 'kmalloc* $params'
  Added new events:
    probe:kmalloc_slab   (on kmalloc* with $params)
    probe:kmalloc_large_node (on kmalloc* with $params)
    probe:kmalloc_order_trace (on kmalloc* with $params)

  You can now use it in all perf tools, such as:

        perf record -e probe:kmalloc_order_trace -aR sleep 1

  # perf probe --list
    probe:kmalloc_large_node (on kmalloc_large_node@mm/slub.c with size flags node)
    probe:kmalloc_order_trace (on kmalloc_order_trace@mm/slub.c with size flags order)
    probe:kmalloc_slab   (on kmalloc_slab@mm/slab_common.c with size flags)
  ----

Signed-off-by: default avatarMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Tested-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Hemant Kumar <hemant@linux.vnet.ibm.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20150508010335.24812.19972.stgit@localhost.localdomain


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 6cfd1f68
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -139,10 +139,26 @@ int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
{
	const char *name;

	name = dwarf_diename(dw_die);
	return name ? (strcmp(tname, name) == 0) : false;
}

/**
 * die_match_name - Match diename and glob
 * @dw_die: a DIE
 * @glob: a string of target glob pattern
 *
 * Glob matching the name of @dw_die and @glob. Return false if matching fail.
 */
bool die_match_name(Dwarf_Die *dw_die, const char *glob)
{
	const char *name;

	name = dwarf_diename(dw_die);
	return name ? strglobmatch(name, glob) : false;
}

/**
 * die_get_call_lineno - Get callsite line number of inline-function instance
 * @in_die: a DIE of an inlined function instance
+3 −0
Original line number Diff line number Diff line
@@ -47,6 +47,9 @@ extern bool die_is_func_instance(Dwarf_Die *dw_die);
/* Compare diename and tname */
extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname);

/* Matching diename with glob pattern */
extern bool die_match_name(Dwarf_Die *dw_die, const char *glob);

/* Get callsite line number of inline-function instance */
extern int die_get_call_lineno(Dwarf_Die *in_die);

+14 −5
Original line number Diff line number Diff line
@@ -589,6 +589,10 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs,
				if (!tmp)
					return -ENOMEM;
			}
			/* If we have no realname, use symbol for it */
			if (!tevs[i].point.realname)
				tevs[i].point.realname = tevs[i].point.symbol;
			else
				free(tevs[i].point.symbol);
			tevs[i].point.symbol = tmp;
			tevs[i].point.offset = tevs[i].point.address -
@@ -1900,6 +1904,7 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
	free(tev->event);
	free(tev->group);
	free(tev->point.symbol);
	free(tev->point.realname);
	free(tev->point.module);
	for (i = 0; i < tev->nargs; i++) {
		free(tev->args[i].name);
@@ -2377,6 +2382,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
	struct strlist *namelist;
	LIST_HEAD(blacklist);
	struct kprobe_blacklist_node *node;
	bool safename;

	if (pev->uprobes)
		fd = open_uprobe_events(true);
@@ -2402,6 +2408,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
			pr_debug("No kprobe blacklist support, ignored\n");
	}

	safename = (pev->point.function && !strisglob(pev->point.function));
	ret = 0;
	pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":");
	for (i = 0; i < ntevs; i++) {
@@ -2420,10 +2427,10 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
		if (pev->event)
			event = pev->event;
		else
			if (pev->point.function)
			if (safename)
				event = pev->point.function;
			else
				event = tev->point.symbol;
				event = tev->point.realname;
		if (pev->group)
			group = pev->group;
		else
@@ -2488,8 +2495,10 @@ static int find_probe_functions(struct map *map, char *name)
{
	int found = 0;
	struct symbol *sym;
	struct rb_node *tmp;

	map__for_each_symbol_by_name(map, name, sym) {
	map__for_each_symbol(map, sym, tmp) {
		if (strglobmatch(sym->name, name))
			found++;
	}

+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ extern bool probe_event_dry_run;

/* kprobe-tracer and uprobe-tracer tracing point */
struct probe_trace_point {
	char		*realname;	/* function real name (if needed) */
	char		*symbol;	/* Base symbol */
	char		*module;	/* Module name */
	unsigned long	offset;		/* Offset from symbol */
+21 −6
Original line number Diff line number Diff line
@@ -717,7 +717,7 @@ static int find_best_scope_cb(Dwarf_Die *fn_die, void *data)
	}
	/* If the function name is given, that's what user expects */
	if (fsp->function) {
		if (die_compare_name(fn_die, fsp->function)) {
		if (die_match_name(fn_die, fsp->function)) {
			memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
			fsp->found = true;
			return 1;
@@ -920,13 +920,14 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)

	/* Check tag and diename */
	if (!die_is_func_def(sp_die) ||
	    !die_compare_name(sp_die, pp->function))
	    !die_match_name(sp_die, pp->function))
		return DWARF_CB_OK;

	/* Check declared file */
	if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die)))
		return DWARF_CB_OK;

	pr_debug("Matched function: %s\n", dwarf_diename(sp_die));
	pf->fname = dwarf_decl_file(sp_die);
	if (pp->line) { /* Function relative line */
		dwarf_decl_line(sp_die, &pf->lno);
@@ -943,10 +944,20 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
			/* TODO: Check the address in this function */
			param->retval = call_probe_finder(sp_die, pf);
		}
	} else if (!probe_conf.no_inlines)
	} else if (!probe_conf.no_inlines) {
		/* Inlined function: search instances */
		param->retval = die_walk_instances(sp_die,
					probe_point_inline_cb, (void *)pf);
		/* This could be a non-existed inline definition */
		if (param->retval == -ENOENT && strisglob(pp->function))
			param->retval = 0;
	}

	/* We need to find other candidates */
	if (strisglob(pp->function) && param->retval >= 0) {
		param->retval = 0;	/* We have to clear the result */
		return DWARF_CB_OK;
	}

	return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */
}
@@ -975,7 +986,7 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
		if (dwarf_tag(param->sp_die) != DW_TAG_subprogram)
			return DWARF_CB_OK;

		if (die_compare_name(param->sp_die, param->function)) {
		if (die_match_name(param->sp_die, param->function)) {
			if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die))
				return DWARF_CB_OK;

@@ -1028,7 +1039,7 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
		return -ENOMEM;

	/* Fastpath: lookup by function name from .debug_pubnames section */
	if (pp->function) {
	if (pp->function && !strisglob(pp->function)) {
		struct pubname_callback_param pubname_param = {
			.function = pp->function,
			.file	  = pp->file,
@@ -1177,6 +1188,10 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
	if (ret < 0)
		return ret;

	tev->point.realname = strdup(dwarf_diename(sc_die));
	if (!tev->point.realname)
		return -ENOMEM;

	pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
		 tev->point.offset);

@@ -1535,7 +1550,7 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
		return DWARF_CB_OK;

	if (die_is_func_def(sp_die) &&
	    die_compare_name(sp_die, lr->function)) {
	    die_match_name(sp_die, lr->function)) {
		lf->fname = dwarf_decl_file(sp_die);
		dwarf_decl_line(sp_die, &lr->offset);
		pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
Loading