perf probe: Add --bootconfig to output definition in bootconfig format
authorMasami Hiramatsu <mhiramat@kernel.org>
Fri, 4 Jun 2021 16:28:43 +0000 (01:28 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 18 Jun 2021 16:50:05 +0000 (13:50 -0300)
Now the boot-time tracing supports kprobes events and that must be
written in bootconfig file in the following format.

  ftrace.event.kprobes.<EVENT_NAME>.probes = <PROBE-DEF>

'perf probe' already supports --definition (-D) action to show probe
definitions, but the format is for tracefs:

  [p|r][:EVENT_NAME] <PROBE-DEF>

This patch adds the --bootconfig option for -D action so that it outputs
the probe definitions in bootconfig format. E.g.

  $ perf probe --bootconfig -D "path_lookupat:7 err:s32 s:string"
  ftrace.event.kprobes.path_lookupat_L7.probe = 'path_lookupat.isra.0+309 err_s32=%ax:s32 s_string=+0(%r13):string'

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lore.kernel.org/lkml/162282412351.452340.14871995440005640114.stgit@devnote2
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-probe.c
tools/perf/util/probe-event.c
tools/perf/util/probe-event.h

index 6b15075..2bfd41d 100644 (file)
@@ -347,7 +347,10 @@ static int perf_add_probe_events(struct perf_probe_event *pevs, int npevs)
                goto out_cleanup;
 
        if (params.command == 'D') {    /* it shows definition */
-               ret = show_probe_trace_events(pevs, npevs);
+               if (probe_conf.bootconfig)
+                       ret = show_bootconfig_events(pevs, npevs);
+               else
+                       ret = show_probe_trace_events(pevs, npevs);
                goto out_cleanup;
        }
 
@@ -581,6 +584,8 @@ __cmd_probe(int argc, const char **argv)
                   "Look for files with symbols relative to this directory"),
        OPT_CALLBACK(0, "target-ns", NULL, "pid",
                     "target pid for namespace contexts", opt_set_target_ns),
+       OPT_BOOLEAN(0, "bootconfig", &probe_conf.bootconfig,
+                   "Output probe definition with bootconfig format"),
        OPT_END()
        };
        int ret;
@@ -692,6 +697,11 @@ __cmd_probe(int argc, const char **argv)
                }
                break;
        case 'D':
+               if (probe_conf.bootconfig && params.uprobes) {
+                       pr_err("  Error: --bootconfig doesn't support uprobes.\n");
+                       return -EINVAL;
+               }
+               __fallthrough;
        case 'a':
 
                /* Ensure the last given target is used */
index 0412842..c14e1d2 100644 (file)
@@ -3564,6 +3564,78 @@ int show_probe_trace_events(struct perf_probe_event *pevs, int npevs)
        return ret;
 }
 
+static int show_bootconfig_event(struct probe_trace_event *tev)
+{
+       struct probe_trace_point *tp = &tev->point;
+       struct strbuf buf;
+       char *ret = NULL;
+       int err;
+
+       if (strbuf_init(&buf, 32) < 0)
+               return -ENOMEM;
+
+       err = synthesize_kprobe_trace_def(tp, &buf);
+       if (err >= 0)
+               err = synthesize_probe_trace_args(tev, &buf);
+       if (err >= 0)
+               ret = strbuf_detach(&buf, NULL);
+       strbuf_release(&buf);
+
+       if (ret) {
+               printf("'%s'", ret);
+               free(ret);
+       }
+
+       return err;
+}
+
+int show_bootconfig_events(struct perf_probe_event *pevs, int npevs)
+{
+       struct strlist *namelist = strlist__new(NULL, NULL);
+       struct probe_trace_event *tev;
+       struct perf_probe_event *pev;
+       char *cur_name = NULL;
+       int i, j, ret = 0;
+
+       if (!namelist)
+               return -ENOMEM;
+
+       for (j = 0; j < npevs && !ret; j++) {
+               pev = &pevs[j];
+               if (pev->group && strcmp(pev->group, "probe"))
+                       pr_warning("WARN: Group name %s is ignored\n", pev->group);
+               if (pev->uprobes) {
+                       pr_warning("ERROR: Bootconfig doesn't support uprobes\n");
+                       ret = -EINVAL;
+                       break;
+               }
+               for (i = 0; i < pev->ntevs && !ret; i++) {
+                       tev = &pev->tevs[i];
+                       /* Skip if the symbol is out of .text or blacklisted */
+                       if (!tev->point.symbol && !pev->uprobes)
+                               continue;
+
+                       /* Set new name for tev (and update namelist) */
+                       ret = probe_trace_event__set_name(tev, pev,
+                                                         namelist, true);
+                       if (ret)
+                               break;
+
+                       if (!cur_name || strcmp(cur_name, tev->event)) {
+                               printf("%sftrace.event.kprobes.%s.probe = ",
+                                       cur_name ? "\n" : "", tev->event);
+                               cur_name = tev->event;
+                       } else
+                               printf(", ");
+                       ret = show_bootconfig_event(tev);
+               }
+       }
+       printf("\n");
+       strlist__delete(namelist);
+
+       return ret;
+}
+
 int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs)
 {
        int i, ret = 0;
index 4f0eb3a..65769d7 100644 (file)
@@ -15,6 +15,7 @@ struct probe_conf {
        bool    force_add;
        bool    no_inlines;
        bool    cache;
+       bool    bootconfig;
        int     max_probes;
        unsigned long   magic_num;
 };
@@ -163,6 +164,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs);
 int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs);
 int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs);
 int show_probe_trace_events(struct perf_probe_event *pevs, int npevs);
+int show_bootconfig_events(struct perf_probe_event *pevs, int npevs);
 void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs);
 
 struct strfilter;