Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752015AbbD3LCd (ORCPT ); Thu, 30 Apr 2015 07:02:33 -0400 Received: from szxga01-in.huawei.com ([58.251.152.64]:65225 "EHLO szxga01-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751208AbbD3Kxb (ORCPT ); Thu, 30 Apr 2015 06:53:31 -0400 From: Wang Nan To: , , , , , , CC: , , , Subject: [RFC PATCH 05/22] perf bpf: open eBPF object file and do basic validation. Date: Thu, 30 Apr 2015 10:52:28 +0000 Message-ID: <1430391165-30267-6-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 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4166 Lines: 195 This patch adds basic 'struct bpf_obj' which will be used for eBPF object files loading. eBPF object files are compiled by LLVM as ELF format. In this patch, libelf is used to open those files, read EHDR and do basic validation according to e_type and e_machine. All elf related staffs are grouped together and reside in 'struct bpf_obj'. bpf_obj_clear_elf() is introduced to clear it. Signed-off-by: Wang Nan --- tools/perf/util/bpf-loader.c | 133 +++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/bpf-loader.h | 16 ++++++ 2 files changed, 149 insertions(+) diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 84d3cc3..3eb7504 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -20,10 +20,143 @@ #include #include +static LIST_HEAD(bpf_obj_list); + +static struct bpf_obj *__bpf_obj_alloc(const char *path) +{ + struct bpf_obj *obj; + + obj = calloc(1, sizeof(struct bpf_obj)); + if (!obj) { + pr_err("bpf: alloc memory failed for %s\n", path); + return NULL; + } + + obj->path = strdup(path); + if (!obj->path) { + pr_err("bpf: failed to strdup '%s'\n", path); + free(obj); + return NULL; + } + return obj; +} + +static void bpf_obj_clear_elf(struct bpf_obj *obj) +{ + if (!obj_elf_valid(obj)) + return; + + if (obj->elf.elf) { + elf_end(obj->elf.elf); + obj->elf.elf = NULL; + } + if (obj->elf.fd >= 0) { + close(obj->elf.fd); + obj->elf.fd = -1; + } +} + +static void bpf_obj_close(struct bpf_obj *obj) +{ + if (!obj) + return; + + bpf_obj_clear_elf(obj); + + if (obj->path) + free(obj->path); + free(obj); +} + +static struct bpf_obj *bpf_obj_alloc(const char *path) +{ + struct bpf_obj *obj; + + obj = __bpf_obj_alloc(path); + if (!obj) + goto out; + + obj->elf.fd = -1; + return obj; +out: + bpf_obj_close(obj); + return NULL; +} + +static int bpf_obj_elf_init(struct bpf_obj *obj) +{ + int err = 0; + GElf_Ehdr *ep; + + if (obj_elf_valid(obj)) { + pr_err("bpf: elf init: internal error\n"); + return -EEXIST; + } + + obj->elf.fd = open(obj->path, O_RDONLY); + if (obj->elf.fd < 0) { + pr_err("bpf: failed to open %s: %s\n", obj->path, + strerror(errno)); + return -errno; + } + + obj->elf.elf = elf_begin(obj->elf.fd, + PERF_ELF_C_READ_MMAP, + NULL); + if (!obj->elf.elf) { + pr_err("bpf: failed to open %s as ELF file\n", + obj->path); + err = -EINVAL; + goto errout; + } + + if (!gelf_getehdr(obj->elf.elf, &obj->elf.ehdr)) { + pr_err("bpf: failed to get EHDR from %s\n", + obj->path); + err = -EINVAL; + goto errout; + } + ep = &obj->elf.ehdr; + + if ((ep->e_type != ET_REL) || (ep->e_machine != 0)) { + pr_err("bpf: %s is not an eBPF object file\n", + obj->path); + err = -EINVAL; + goto errout; + } + + return 0; +errout: + bpf_obj_clear_elf(obj); + return err; +} + int bpf__load(const char *path) { + struct bpf_obj *obj; + int err; + pr_debug("bpf: loading %s\n", path); + + if (elf_version(EV_CURRENT) == EV_NONE) { + pr_err("bpf: failed to init libelf for %s\n", path); + return -ENOTSUP; + } + + obj = bpf_obj_alloc(path); + if (!obj) { + err = -EINVAL; + goto out; + } + + if ((err = bpf_obj_elf_init(obj))) + goto out; + + list_add(&obj->list, &bpf_obj_list); return 0; +out: + bpf_obj_close(obj); + return -1; } int bpf__run(void) diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index 122b178..6a6651b 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h @@ -18,4 +18,20 @@ int bpf__load(const char *path); int bpf__run(void); +struct bpf_obj { + /* All bpf objs should be linked together. */ + struct list_head list; + char *path; + + /* + * Information when doing elf related work. Only valid if fd + * is valid. + */ + struct { + int fd; + Elf *elf; + GElf_Ehdr ehdr; + } elf; +}; +#define obj_elf_valid(o) ((o)->elf.fd >= 0) #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/