[PATCH perf/core 4/4] perf-probe: Find probe events without target module

From: Masami Hiramatsu
Date: Sat Jan 07 2017 - 00:29:49 EST


Find probe events without -m "module" option. If perf-probe
failed to find given function in kernel image, it tries to
find same symbol and module in kallsyms, and retry search
in the found module. E.g.

# perf probe -D i915_capabilities
p:probe/i915_capabilities i915:i915_capabilities+0

Note: without -m option, perf probe can not find inlined
function since there is no symbol information in kallsyms.

Signed-off-by: Masami Hiramatsu <mhiramat@xxxxxxxxxx>
Suggested-by: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
---
tools/perf/util/probe-event.c | 74 ++++++++++++++++++++++++++++++-----------
1 file changed, 55 insertions(+), 19 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 6a6f44d..09bd093 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -858,11 +858,7 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,

debuginfo__delete(dinfo);

- if (ntevs == 0) { /* No error but failed to find probe point. */
- pr_warning("Probe point '%s' not found.\n",
- synthesize_perf_probe_point(&pev->point));
- return -ENOENT;
- } else if (ntevs < 0) {
+ if (ntevs < 0) {
/* Error path : ntevs < 0 */
pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs);
if (ntevs == -EBADF)
@@ -2073,8 +2069,10 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
} else {
if (tp->symbol && !addr) {
if (kernel_get_symbol_address_by_name(tp->symbol,
- &addr, true, false) < 0)
+ &addr, true, false) < 0) {
+ ret = 0;
goto out;
+ }
}
if (addr) {
addr += tp->offset;
@@ -2829,9 +2827,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
*/
num_matched_functions = find_probe_functions(map, pp->function, syms);
if (num_matched_functions == 0) {
- pr_err("Failed to find symbol %s in %s\n", pp->function,
- pev->target ? : "kernel");
- ret = -ENOENT;
+ ret = 0;
goto out;
} else if (num_matched_functions > probe_conf.max_probes) {
pr_err("Too many functions matched in %s\n",
@@ -3233,6 +3229,43 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
return ret;
}

+static int __convert_to_probe_trace_events(struct perf_probe_event *pev,
+ struct probe_trace_event **tevs)
+{
+ int ret;
+
+ /* At first, we need to lookup cache entry */
+ ret = find_probe_trace_events_from_cache(pev, tevs);
+ if (ret > 0 || pev->sdt) /* SDT can be found only in the cache */
+ return ret == 0 ? -ENOENT : ret; /* Found in probe cache */
+
+ /* Convert perf_probe_event with debuginfo */
+ ret = try_to_find_probe_trace_events(pev, tevs);
+ if (ret != 0)
+ return ret; /* Found in debuginfo or got an error */
+
+ return find_probe_trace_events_from_map(pev, tevs);
+}
+
+static char *find_module_from_kallsyms(const char *symbol_name)
+{
+ struct machine *machine = machine__new_kallsyms();
+ struct symbol *sym;
+ struct map *map;
+ char *module;
+
+ pr_debug("Try to find module for %s\n", symbol_name);
+ sym = machine__find_kernel_function_by_name(machine, symbol_name, &map);
+ if (!sym || map->dso->short_name[0] != '[')
+ return NULL;
+ pr_debug("Found: %s in %s\n", sym->name, map->dso->short_name);
+ module = strdup(map->dso->short_name + 1);
+ if (module)
+ module[strlen(module) - 1] = '\0';
+
+ return module;
+}
+
static int convert_to_probe_trace_events(struct perf_probe_event *pev,
struct probe_trace_event **tevs)
{
@@ -3255,17 +3288,20 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
if (ret > 0)
return ret;

- /* At first, we need to lookup cache entry */
- ret = find_probe_trace_events_from_cache(pev, tevs);
- if (ret > 0 || pev->sdt) /* SDT can be found only in the cache */
- return ret == 0 ? -ENOENT : ret; /* Found in probe cache */
-
- /* Convert perf_probe_event with debuginfo */
- ret = try_to_find_probe_trace_events(pev, tevs);
- if (ret != 0)
- return ret; /* Found in debuginfo or got an error */
+ ret = __convert_to_probe_trace_events(pev, tevs);
+ /* Not found. will retry to check kmodule if possible */
+ if (ret == 0 && !pev->uprobes && !pev->target) {
+ pev->target = find_module_from_kallsyms(pev->point.function);
+ if (pev->target)
+ ret = __convert_to_probe_trace_events(pev, tevs);
+ }

- return find_probe_trace_events_from_map(pev, tevs);
+ if (ret == 0) {
+ pr_warning("Probe point '%s' not found.\n",
+ synthesize_perf_probe_point(&pev->point));
+ ret = -ENOENT;
+ }
+ return ret;
}

int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs)