Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752277AbbD3K7S (ORCPT ); Thu, 30 Apr 2015 06:59:18 -0400 Received: from szxga03-in.huawei.com ([119.145.14.66]:14622 "EHLO szxga03-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751638AbbD3Kxg (ORCPT ); Thu, 30 Apr 2015 06:53:36 -0400 From: Wang Nan To: , , , , , , CC: , , , Subject: [RFC PATCH 19/22] perf bpf: dump eBPF program before loading. Date: Thu, 30 Apr 2015 10:52:42 +0000 Message-ID: <1430391165-30267-20-git-send-email-wangnan0@huawei.com> X-Mailer: git-send-email 1.8.3.4 In-Reply-To: <1430391165-30267-1-git-send-email-wangnan0@huawei.com> References: <1430391165-30267-1-git-send-email-wangnan0@huawei.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.107.197.210] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020203.554209AF.006D,ss=1,re=0.000,recu=0.000,reip=0.000,cl=1,cld=1,fgs=0, ip=0.0.0.0, so=2013-05-26 15:14:31, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: bbce26320d72fc41687be5a3b307c2f9 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 7209 Lines: 244 Copy print_bpf_insn() from kernel/bpf/verifier.c to bpf.c, dump the program if called by -vv. Signed-off-by: Wang Nan --- tools/perf/util/bpf-loader.c | 14 +++- tools/perf/util/bpf.c | 156 +++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/bpf.h | 1 + 3 files changed, 170 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 0395483..6587e99 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -849,6 +849,16 @@ static __u64 ptr_to_u64(void *ptr) return (__u64) (unsigned long) ptr; } +static void +dump_perf_prog(struct bpf_perf_prog *prog) +{ + if (verbose < 2) + return; + pr_info("-- BEGIN DUMP '%s' --\n", prog->name); + bpf_dump_prog(prog->insns, prog->insns_cnt); + pr_info("-- FINISH DUMP '%s' --\n", prog->name); +} + static int bpf_perf_prog_load(struct bpf_obj *obj, struct bpf_perf_prog *prog) { @@ -857,6 +867,8 @@ bpf_perf_prog_load(struct bpf_obj *obj, struct bpf_perf_prog *prog) #define LOG_BUF_SIZE 65536 static char bpf_log_buf[LOG_BUF_SIZE]; + dump_perf_prog(prog); + bzero(&attr, sizeof(attr)); attr.prog_type = BPF_PROG_TYPE_KPROBE; @@ -902,7 +914,7 @@ int bpf__load(const char *path) struct bpf_obj *obj; int err; - pr_debug("bpf: loading %s\n", path); + pr_debug("bpf: loading %s, verbose=%d\n", path, verbose); if (elf_version(EV_CURRENT) == EV_NONE) { pr_err("bpf: failed to init libelf for %s\n", path); diff --git a/tools/perf/util/bpf.c b/tools/perf/util/bpf.c index f752723..eb3411b 100644 --- a/tools/perf/util/bpf.c +++ b/tools/perf/util/bpf.c @@ -8,12 +8,14 @@ */ #include +#include #include #include #include #include #include #include "perf.h" +#include "debug.h" #include "bpf.h" int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr, size_t size) @@ -37,3 +39,157 @@ int bpf_create_map(struct bpf_map_def *map_def) return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); } + +/* Taken from kernel/bpf/verifier.c, s/verbose/_verbose/g*/ +static const char *const bpf_class_string[] = { + [BPF_LD] = "ld", + [BPF_LDX] = "ldx", + [BPF_ST] = "st", + [BPF_STX] = "stx", + [BPF_ALU] = "alu", + [BPF_JMP] = "jmp", + [BPF_RET] = "BUG", + [BPF_ALU64] = "alu64", +}; + +static const char *const bpf_alu_string[] = { + [BPF_ADD >> 4] = "+=", + [BPF_SUB >> 4] = "-=", + [BPF_MUL >> 4] = "*=", + [BPF_DIV >> 4] = "/=", + [BPF_OR >> 4] = "|=", + [BPF_AND >> 4] = "&=", + [BPF_LSH >> 4] = "<<=", + [BPF_RSH >> 4] = ">>=", + [BPF_NEG >> 4] = "neg", + [BPF_MOD >> 4] = "%=", + [BPF_XOR >> 4] = "^=", + [BPF_MOV >> 4] = "=", + [BPF_ARSH >> 4] = "s>>=", + [BPF_END >> 4] = "endian", +}; + +static const char *const bpf_ldst_string[] = { + [BPF_W >> 3] = "u32", + [BPF_H >> 3] = "u16", + [BPF_B >> 3] = "u8", + [BPF_DW >> 3] = "u64", +}; + +static const char *const bpf_jmp_string[] = { + [BPF_JA >> 4] = "jmp", + [BPF_JEQ >> 4] = "==", + [BPF_JGT >> 4] = ">", + [BPF_JGE >> 4] = ">=", + [BPF_JSET >> 4] = "&", + [BPF_JNE >> 4] = "!=", + [BPF_JSGT >> 4] = "s>", + [BPF_JSGE >> 4] = "s>=", + [BPF_CALL >> 4] = "call", + [BPF_EXIT >> 4] = "exit", +}; +#define _verbose pr_info +static void print_bpf_insn(struct bpf_insn *insn) +{ + u8 class = BPF_CLASS(insn->code); + + if (class == BPF_ALU || class == BPF_ALU64) { + if (BPF_SRC(insn->code) == BPF_X) + _verbose("(%02x) %sr%d %s %sr%d\n", + insn->code, class == BPF_ALU ? "(u32) " : "", + insn->dst_reg, + bpf_alu_string[BPF_OP(insn->code) >> 4], + class == BPF_ALU ? "(u32) " : "", + insn->src_reg); + else + _verbose("(%02x) %sr%d %s %s%d\n", + insn->code, class == BPF_ALU ? "(u32) " : "", + insn->dst_reg, + bpf_alu_string[BPF_OP(insn->code) >> 4], + class == BPF_ALU ? "(u32) " : "", + insn->imm); + } else if (class == BPF_STX) { + if (BPF_MODE(insn->code) == BPF_MEM) + _verbose("(%02x) *(%s *)(r%d %+d) = r%d\n", + insn->code, + bpf_ldst_string[BPF_SIZE(insn->code) >> 3], + insn->dst_reg, + insn->off, insn->src_reg); + else if (BPF_MODE(insn->code) == BPF_XADD) + _verbose("(%02x) lock *(%s *)(r%d %+d) += r%d\n", + insn->code, + bpf_ldst_string[BPF_SIZE(insn->code) >> 3], + insn->dst_reg, insn->off, + insn->src_reg); + else + _verbose("BUG_%02x\n", insn->code); + } else if (class == BPF_ST) { + if (BPF_MODE(insn->code) != BPF_MEM) { + _verbose("BUG_st_%02x\n", insn->code); + return; + } + _verbose("(%02x) *(%s *)(r%d %+d) = %d\n", + insn->code, + bpf_ldst_string[BPF_SIZE(insn->code) >> 3], + insn->dst_reg, + insn->off, insn->imm); + } else if (class == BPF_LDX) { + if (BPF_MODE(insn->code) != BPF_MEM) { + _verbose("BUG_ldx_%02x\n", insn->code); + return; + } + _verbose("(%02x) r%d = *(%s *)(r%d %+d)\n", + insn->code, insn->dst_reg, + bpf_ldst_string[BPF_SIZE(insn->code) >> 3], + insn->src_reg, insn->off); + } else if (class == BPF_LD) { + if (BPF_MODE(insn->code) == BPF_ABS) { + _verbose("(%02x) r0 = *(%s *)skb[%d]\n", + insn->code, + bpf_ldst_string[BPF_SIZE(insn->code) >> 3], + insn->imm); + } else if (BPF_MODE(insn->code) == BPF_IND) { + _verbose("(%02x) r0 = *(%s *)skb[r%d + %d]\n", + insn->code, + bpf_ldst_string[BPF_SIZE(insn->code) >> 3], + insn->src_reg, insn->imm); + } else if (BPF_MODE(insn->code) == BPF_IMM) { + _verbose("(%02x) r%d = 0x%x\n", + insn->code, insn->dst_reg, insn->imm); + } else { + _verbose("BUG_ld_%02x\n", insn->code); + return; + } + } else if (class == BPF_JMP) { + u8 opcode = BPF_OP(insn->code); + + if (opcode == BPF_CALL) { + _verbose("(%02x) call %d\n", insn->code, insn->imm); + } else if (insn->code == (BPF_JMP | BPF_JA)) { + _verbose("(%02x) goto pc%+d\n", + insn->code, insn->off); + } else if (insn->code == (BPF_JMP | BPF_EXIT)) { + _verbose("(%02x) exit\n", insn->code); + } else if (BPF_SRC(insn->code) == BPF_X) { + _verbose("(%02x) if r%d %s r%d goto pc%+d\n", + insn->code, insn->dst_reg, + bpf_jmp_string[BPF_OP(insn->code) >> 4], + insn->src_reg, insn->off); + } else { + _verbose("(%02x) if r%d %s 0x%x goto pc%+d\n", + insn->code, insn->dst_reg, + bpf_jmp_string[BPF_OP(insn->code) >> 4], + insn->imm, insn->off); + } + } else { + _verbose("(%02x) %s\n", insn->code, bpf_class_string[class]); + } +} + +void bpf_dump_prog(struct bpf_insn *insn, size_t nr_insn) +{ + unsigned int i; + + for (i = 0; i < nr_insn; i++) + print_bpf_insn(&insn[i]); +} diff --git a/tools/perf/util/bpf.h b/tools/perf/util/bpf.h index be106b0..b4a6802 100644 --- a/tools/perf/util/bpf.h +++ b/tools/perf/util/bpf.h @@ -19,4 +19,5 @@ struct bpf_map_def { int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr, size_t size); int bpf_create_map(struct bpf_map_def *map_def); +void bpf_dump_prog(struct bpf_insn *insn, size_t nr_insn); #endif -- 1.8.3.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/