Add -d/--disasm option to get the sbpf assembly
code dump, like:

  $ perf bpf -d ./comm1.o | head
  Disassembly of raw_syscalls:sys_enter:
     0: (b7) r1 = 1
         b7 01 00 00 01 00 00 00
     1: (7b) *(u64 *)(r10 -8) = r1
         7b 1a f8 ff 00 00 00 00
     2: (bf) r6 = r10
         bf a6 00 00 00 00 00 00
     3: (07) r6 += -24
         07 06 00 00 e8 ff ff ff
     4: (bf) r1 = r6
     ...

Link: http://lkml.kernel.org/n/tip-djopq2e6ajsg9h90hb9iu...@git.kernel.org
Signed-off-by: Jiri Olsa <jo...@kernel.org>
---
 tools/perf/Build           |   6 +++
 tools/perf/Makefile.config |   1 +
 tools/perf/builtin-bpf.c   | 107 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 114 insertions(+)

diff --git a/tools/perf/Build b/tools/perf/Build
index 7f521ac16466..0585fd3715d0 100644
--- a/tools/perf/Build
+++ b/tools/perf/Build
@@ -25,6 +25,7 @@ perf-y += builtin-data.o
 perf-y += builtin-version.o
 perf-y += builtin-c2c.o
 perf-y += builtin-bpf.o
+perf-y += bpf-disasm.o
 
 perf-$(CONFIG_TRACE) += builtin-trace.o
 perf-$(CONFIG_LIBELF) += builtin-probe.o
@@ -46,6 +47,7 @@ CFLAGS_perf.o              += 
-DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))"     \
 CFLAGS_builtin-trace.o    += 
-DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))"
 CFLAGS_builtin-report.o           += -DTIPDIR="BUILD_STR($(tipdir_SQ))"
 CFLAGS_builtin-report.o           += 
-DDOCDIR="BUILD_STR($(srcdir_SQ)/Documentation)"
+CFLAGS_builtin-bpf.o      += -I$(srctree)/kernel/bpf
 
 libperf-y += util/
 libperf-y += arch/
@@ -54,3 +56,7 @@ libperf-y += scripts/
 libperf-$(CONFIG_TRACE) += trace/beauty/
 
 gtk-y += ui/gtk/
+
+$(OUTPUT)bpf-disasm.o: ../../kernel/bpf/disasm.c FORCE
+       $(call rule_mkdir)
+       $(call if_changed_dep,cc_o_c)
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 98ff73648b51..575910cebb57 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -999,3 +999,4 @@ $(call detected_var,LIBDIR)
 $(call detected_var,GTK_CFLAGS)
 $(call detected_var,PERL_EMBED_CCOPTS)
 $(call detected_var,PYTHON_EMBED_CCOPTS)
+$(call detected_var,srctree)
diff --git a/tools/perf/builtin-bpf.c b/tools/perf/builtin-bpf.c
index 1ae93fd01a97..7065153a9577 100644
--- a/tools/perf/builtin-bpf.c
+++ b/tools/perf/builtin-bpf.c
@@ -4,6 +4,8 @@
 #include <time.h>
 #include <linux/compiler.h>
 #include <subcmd/parse-options.h>
+#include <bpf/bpf.h>
+#include <bpf/libbpf.h>
 #include "builtin.h"
 #include "perf.h"
 #include "target.h"
@@ -12,6 +14,7 @@
 #include "evlist.h"
 #include "evsel.h"
 #include "bpf-loader.h"
+#include "disasm.h"
 
 struct perf_bpf {
        struct target            target;
@@ -137,6 +140,104 @@ static int __cmd_bpf(int argc , const char **argv)
        return WEXITSTATUS(status);
 }
 
+static void print_insn(struct bpf_verifier_env *env __maybe_unused, const char 
*fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       vprintf(fmt, args);
+       va_end(args);
+}
+
+static const char *print_call(void *private_data __maybe_unused,
+                             const struct bpf_insn *insn __maybe_unused)
+{
+       return NULL;
+}
+
+static const char *print_imm(void *private_data __maybe_unused,
+                            const struct bpf_insn *insn __maybe_unused,
+                            __u64 full_imm __maybe_unused)
+{
+       return NULL;
+}
+
+static void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
+{
+       unsigned char *data = arg;
+       unsigned int i;
+
+       for (i = 0; i < n; i++) {
+               const char *pfx = "";
+
+               if (!i)
+                       /* nothing */;
+               else if (!(i % 16))
+                       fprintf(f, "\n");
+               else if (!(i % 8))
+                       fprintf(f, "  ");
+               else
+                       pfx = sep;
+
+               fprintf(f, "%s%02hhx", i ? pfx : "", data[i]);
+       }
+}
+
+static int disasm_fprintf(FILE *out, const char *filename, bool opcodes)
+{
+       const struct bpf_insn_cbs cbs = {
+               .cb_print       = print_insn,
+               .cb_call        = print_call,
+               .cb_imm         = print_imm,
+               .private_data   = NULL,
+       };
+       bool double_insn = false;
+       struct bpf_program *prog;
+       struct bpf_object *obj;
+       int i;
+
+       obj = bpf__prepare_load(filename, false);
+       if (IS_ERR(obj))
+               return -1;
+
+       bpf_object__for_each_program(prog, obj) {
+               struct bpf_insn *insn;
+               int insns_cnt;
+
+               fprintf(out, "Disassembly of %s:\n", bpf_program__title(prog, 
false));
+
+               insn = bpf_program__insns(prog, &insns_cnt);
+               if (!insn) {
+                       pr_err("failed: NULL instructions\n");
+                       return -1;
+               }
+
+               for (i = 0; i < (int) insns_cnt; i++) {
+                       if (double_insn) {
+                               double_insn = false;
+                               continue;
+                       }
+
+                       double_insn = insn[i].code == (BPF_LD | BPF_IMM | 
BPF_DW);
+
+                       printf("% 4d: ", i);
+                       print_bpf_insn(&cbs, NULL, insn + i, true);
+
+                       if (opcodes) {
+                               printf("       ");
+                               fprint_hex(stdout, insn + i, 8, " ");
+                               if (double_insn && i < (int) 
(insns_cnt*sizeof(*insn)) - 1) {
+                                       printf(" ");
+                                       fprint_hex(stdout, insn + i + 1, 8, " 
");
+                               }
+                               printf("\n");
+                       }
+               }
+       }
+
+       return 0;
+}
+
 int cmd_bpf(int argc, const char **argv)
 {
        int err = -1;
@@ -146,6 +247,7 @@ int cmd_bpf(int argc, const char **argv)
                NULL
        };
        const char *compile_src = NULL;
+       const char *disasm_obj = NULL;
        const struct option bpf_options[] = {
                OPT_CALLBACK('e', "event", &bpf.evlist, "event",
                             "event selector. use 'perf list' to list available 
events",
@@ -162,6 +264,8 @@ int cmd_bpf(int argc, const char **argv)
                         "be more verbose"),
                OPT_STRING('c', "compile", &compile_src, "eBPF source",
                           "compile eBPF object"),
+               OPT_STRING('d', "disasm", &disasm_obj, "eBPF object",
+                          "disasm eBPF object"),
                OPT_END()
        };
 
@@ -177,6 +281,9 @@ int cmd_bpf(int argc, const char **argv)
        if (compile_src)
                return bpf__compile(compile_src);
 
+       if (disasm_obj)
+               return disasm_fprintf(stdout, disasm_obj, true);
+
        if (!argc && target__none(&bpf.target))
                usage_with_options(bpf_usage, bpf_options);
 
-- 
2.13.6

Reply via email to