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 <mhira...@kernel.org>
Suggested-by: Arnaldo Carvalho de Melo <a...@redhat.com>
---
 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)

Reply via email to