]> granicus.if.org Git - strace/commitdiff
bpf: add support for instruction decoding
authorEugene Syromyatnikov <evgsyr@gmail.com>
Thu, 22 Feb 2018 06:58:30 +0000 (07:58 +0100)
committerDmitry V. Levin <ldv@altlinux.org>
Mon, 28 May 2018 17:34:50 +0000 (17:34 +0000)
* xlat/ebpf_regs.in: New file.
* bpf.c (struct ebpf_insn, struct ebpf_insns_data): New type definitions.
(print_ebpf_insn, print_ebpf_prog): New functions.
(DEF_BPF_CMD_DECODER(BPF_PROG_LOAD)): Use them.

bpf.c
tests/bpf.c
xlat/ebpf_regs.in [new file with mode: 0644]

diff --git a/bpf.c b/bpf.c
index 008428b28ffbf59411ce94dfb427e6624bc4c048..ba5a01ae9f51f1ede6bf82e8bc89559bb7676988 100644 (file)
--- a/bpf.c
+++ b/bpf.c
@@ -33,6 +33,7 @@
 #ifdef HAVE_LINUX_BPF_H
 # include <linux/bpf.h>
 #endif
+#include <linux/filter.h>
 
 #include "bpf_attr.h"
 
@@ -46,6 +47,7 @@
 #include "xlat/bpf_attach_type.h"
 #include "xlat/bpf_attach_flags.h"
 #include "xlat/bpf_query_flags.h"
+#include "xlat/ebpf_regs.h"
 #include "xlat/numa_node.h"
 
 /** Storage for all the data that is needed to be stored on entering. */
@@ -126,6 +128,61 @@ decode_attr_extra_data(struct tcb *const tcp,
        return 0;
 }
 
+struct ebpf_insn {
+       uint8_t code;
+       uint8_t dst_reg:4;
+       uint8_t src_reg:4;
+       int16_t off;
+       int32_t imm;
+};
+
+struct ebpf_insns_data {
+       unsigned int count;
+};
+
+static bool
+print_ebpf_insn(struct tcb * const tcp, void * const elem_buf,
+               const size_t elem_size, void * const data)
+{
+       struct ebpf_insns_data *eid = data;
+       struct ebpf_insn *insn = elem_buf;
+
+       if (eid->count++ >= BPF_MAXINSNS) {
+               tprints("...");
+               return false;
+       }
+
+       tprints("{code=");
+       print_bpf_filter_code(insn->code, true);
+
+       /* We can't use PRINT_FIELD_XVAL on bit fields */
+       tprints(", dst_reg=");
+       printxval_index(ebpf_regs, insn->dst_reg, "BPF_REG_???");
+       tprints(", src_reg=");
+       printxval_index(ebpf_regs, insn->src_reg, "BPF_REG_???");
+
+       PRINT_FIELD_D(", ", *insn, off);
+       PRINT_FIELD_X(", ", *insn, imm);
+       tprints("}");
+
+       return true;
+}
+
+void
+print_ebpf_prog(struct tcb *const tcp, const kernel_ulong_t addr,
+               const uint32_t len)
+{
+       if (abbrev(tcp)) {
+               printaddr(addr);
+       } else {
+               struct ebpf_insns_data eid = {};
+               struct ebpf_insn insn;
+
+               print_array(tcp, addr, len, &insn, sizeof(insn),
+                           umoven_or_printaddr, print_ebpf_insn, &eid);
+       }
+}
+
 BEGIN_BPF_CMD_DECODER(BPF_MAP_CREATE)
 {
        PRINT_FIELD_XVAL_INDEX("{", attr, map_type, bpf_map_types,
@@ -223,7 +280,9 @@ BEGIN_BPF_CMD_DECODER(BPF_PROG_LOAD)
        PRINT_FIELD_XVAL_INDEX("{", attr, prog_type, bpf_prog_types,
                               "BPF_PROG_TYPE_???");
        PRINT_FIELD_U(", ", attr, insn_cnt);
-       PRINT_FIELD_ADDR64(", ", attr, insns);
+       tprints(", insns=");
+       print_big_u64_addr(attr.insns);
+       print_ebpf_prog(tcp, attr.insns, attr.insn_cnt);
 
        tprintf(", license=");
        print_big_u64_addr(attr.license);
index c4e8880d2df094b9cf3a55a737013f53c8a49b1a..52a560c4f558981bca97041c6812960d7b11b7fb 100644 (file)
@@ -476,12 +476,28 @@ static const struct bpf_attr_check BPF_MAP_GET_NEXT_KEY_checks[] = {
 };
 
 static const struct bpf_insn insns[] = {
-       { .code = 0x95 }
+       {
+               .code = 0x95,
+               .dst_reg = 10,
+               .src_reg = 11,
+               .off = 0xdead,
+               .imm = 0xbadc0ded,
+       },
 };
 static const char license[] = "GPL";
 static char log_buf[4096];
 static const char pathname[] = "/sys/fs/bpf/foo/bar";
 
+#if VERBOSE
+# define INSNS_FMT \
+       "[{code=BPF_JMP|BPF_K|BPF_EXIT, dst_reg=BPF_REG_10" \
+       ", src_reg=0xb /* BPF_REG_??? */, off=%d, imm=%#x}]"
+# define INSNS_ARG insns[0].off, insns[0].imm
+#else
+# define INSNS_FMT "%p"
+# define INSNS_ARG insns
+#endif
+
 static void
 init_BPF_PROG_LOAD_attr3(struct bpf_attr_check *check)
 {
@@ -494,13 +510,13 @@ init_BPF_PROG_LOAD_attr3(struct bpf_attr_check *check)
 static void
 print_BPF_PROG_LOAD_attr3(const struct bpf_attr_check *check, unsigned long addr)
 {
-       printf("prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=%u, insns=%p"
-              ", license=\"%s\", log_level=2718281828, log_size=4096"
-              ", log_buf=%p, kern_version=KERNEL_VERSION(51966, 240, 13)"
+       printf("prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=%u"
+              ", insns=" INSNS_FMT ", license=\"%s\", log_level=2718281828"
+              ", log_size=4096, log_buf=%p"
+              ", kern_version=KERNEL_VERSION(51966, 240, 13)"
               ", prog_flags=0x2 /* BPF_F_??? */"
               ", prog_name=\"0123456789abcde\"..., prog_ifindex=3203399405",
-              (unsigned int) ARRAY_SIZE(insns), insns,
-              license, log_buf);
+              (unsigned int) ARRAY_SIZE(insns), INSNS_ARG, license, log_buf);
 }
 
 static void
@@ -516,13 +532,13 @@ init_BPF_PROG_LOAD_attr4(struct bpf_attr_check *check)
 static void
 print_BPF_PROG_LOAD_attr4(const struct bpf_attr_check *check, unsigned long addr)
 {
-       printf("prog_type=BPF_PROG_TYPE_UNSPEC, insn_cnt=%u, insns=%p"
+       printf("prog_type=BPF_PROG_TYPE_UNSPEC, insn_cnt=%u, insns=" INSNS_FMT
               ", license=\"%s\", log_level=2718281828, log_size=4096"
               ", log_buf=%p, kern_version=KERNEL_VERSION(51966, 240, 13)"
               ", prog_flags=BPF_F_STRICT_ALIGNMENT|0x2"
               ", prog_name=\"0123456789abcde\"..., prog_ifindex=%s"
               ", expected_attach_type=BPF_CGROUP_INET6_BIND",
-              (unsigned int) ARRAY_SIZE(insns), insns,
+              (unsigned int) ARRAY_SIZE(insns), INSNS_ARG,
               license, log_buf, IFINDEX_LO_STR);
 }
 
@@ -567,7 +583,8 @@ static struct bpf_attr_check BPF_PROG_LOAD_checks[] = {
                } },
                .size = offsetofend(struct BPF_PROG_LOAD_struct, prog_name),
                .str = "prog_type=BPF_PROG_TYPE_RAW_TRACEPOINT"
-                      ", insn_cnt=3134983661, insns=0xffffffff00000000"
+                      ", insn_cnt=3134983661"
+                      ", insns=" BIG_ADDR("0xffffffff00000000", "NULL")
                       ", license=" BIG_ADDR("0xffffffff00000000", "NULL")
                       ", log_level=2718281828, log_size=4096"
                       ", log_buf=0xffffffff00000000"
diff --git a/xlat/ebpf_regs.in b/xlat/ebpf_regs.in
new file mode 100644 (file)
index 0000000..9db066e
--- /dev/null
@@ -0,0 +1,12 @@
+#value_indexed
+BPF_REG_0  0
+BPF_REG_1  1
+BPF_REG_2  2
+BPF_REG_3  3
+BPF_REG_4  4
+BPF_REG_5  5
+BPF_REG_6  6
+BPF_REG_7  7
+BPF_REG_8  8
+BPF_REG_9  9
+BPF_REG_10 10