Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S964913AbbEOHxP (ORCPT ); Fri, 15 May 2015 03:53:15 -0400 Received: from szxga01-in.huawei.com ([58.251.152.64]:62706 "EHLO szxga01-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934270AbbEOHxL (ORCPT ); Fri, 15 May 2015 03:53:11 -0400 From: Wang Nan To: , , , , , , , , , , , CC: , , , Subject: [RFC PATCH v2 17/37] tools lib bpf: collect relocation instructions for each program. Date: Fri, 15 May 2015 07:51:10 +0000 Message-ID: <1431676290-1230-18-git-send-email-wangnan0@huawei.com> X-Mailer: git-send-email 1.8.3.4 In-Reply-To: <1431676290-1230-1-git-send-email-wangnan0@huawei.com> References: <1431676290-1230-1-git-send-email-wangnan0@huawei.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.107.197.200] X-CFilter-Loop: Reflected Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5489 Lines: 214 This patch records the indics of instructions which are needed to be relocated. Those information are saved in 'reloc_desc' field in 'struct bpf_program'. In loading phase (this patch takes effect in opening phase), the collected instructions will be replaced by map loading instructions. Since we are going to close the ELF file and clear all data at the end of 'opening' phase, ELF information will no longer be valid in 'loading' phase. We have to locate the instructions before maps are loaded, instead of directly modifying the instruction. 'struct bpf_map_def' is introduce in this patch to let us know how many maps defined in the object. Signed-off-by: Wang Nan --- tools/lib/bpf/libbpf.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++ tools/lib/bpf/libbpf.h | 10 ++++ 2 files changed, 138 insertions(+) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 8fd29a9..ded96cb 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -87,6 +88,12 @@ struct bpf_program { char *section_name; struct bpf_insn *insns; size_t insns_cnt; + + struct { + int insn_idx; + int map_idx; + } *reloc_desc; + int nr_reloc; }; struct bpf_object { @@ -131,6 +138,12 @@ static void bpf_clear_program(struct bpf_program *prog) free(prog->insns); prog->insns = NULL; } + if (prog->reloc_desc) { + free(prog->reloc_desc); + prog->reloc_desc = NULL; + } + + prog->nr_reloc = 0; prog->insns_cnt = 0; prog->idx = -1; } @@ -521,6 +534,119 @@ out: return err; } +static struct bpf_program * +bpf_find_prog_by_idx(struct bpf_object *obj, int idx) +{ + struct bpf_program *prog; + size_t i; + + for (i = 0; i < obj->nr_programs; i++) { + prog = &obj->programs[i]; + if (prog->idx == idx) + return prog; + } + return NULL; +} + +static int +bpf_program_collect_reloc(struct bpf_object *obj, + GElf_Shdr *shdr, + Elf_Data *data, + struct bpf_program *prog) +{ + int i, nrels; + size_t nr_maps = obj->maps_buf_sz / sizeof(struct bpf_map_def); + + pr_debug("collecting relocating info for: '%s'\n", + prog->section_name); + nrels = shdr->sh_size / shdr->sh_entsize; + + prog->reloc_desc = malloc(sizeof(*prog->reloc_desc) * nrels); + if (!prog->reloc_desc) { + pr_warning("failed to alloc memory in relocation\n"); + return -ENOMEM; + } + prog->nr_reloc = nrels; + + for (i = 0; i < nrels; i++) { + GElf_Sym sym; + GElf_Rel rel; + unsigned int insn_idx; + struct bpf_insn *insns = prog->insns; + size_t map_idx; + + if (!gelf_getrel(data, i, &rel)) { + pr_warning("relocation: failed to get " + "%d reloc\n", i); + return -EINVAL; + } + + insn_idx = rel.r_offset / sizeof(struct bpf_insn); + pr_debug("relocation: insn_idx=%u\n", insn_idx); + + if (!gelf_getsym(obj->elf.symbols, + GELF_R_SYM(rel.r_info), + &sym)) { + pr_warning("relocation: symbol %"PRIx64 + " not found\n", + GELF_R_SYM(rel.r_info)); + return -EINVAL; + } + + if (insns[insn_idx].code != (BPF_LD | BPF_IMM | BPF_DW)) { + pr_warning("bpf: relocation: invalid relo for " + "insns[%d].code 0x%x\n", + insn_idx, insns[insn_idx].code); + return -EINVAL; + } + + map_idx = sym.st_value / sizeof(struct bpf_map_def); + if (map_idx >= nr_maps) { + pr_warning("bpf relocation: map_idx %d large than %d\n", + (int)map_idx, (int)nr_maps - 1); + return -EINVAL; + } + + prog->reloc_desc[i].insn_idx = insn_idx; + prog->reloc_desc[i].map_idx = map_idx; + } + return 0; +} + +static int bpf_obj_collect_reloc(struct bpf_object *obj) +{ + int i, err; + + if (!obj_elf_valid(obj)) { + pr_warning("Internal error: elf object is closed\n"); + return -EINVAL; + } + + for (i = 0; i < obj->elf.nr_reloc; i++) { + GElf_Shdr *shdr = &obj->elf.reloc[i].shdr; + Elf_Data *data = obj->elf.reloc[i].data; + int idx = shdr->sh_info; + struct bpf_program *prog; + + if (shdr->sh_type != SHT_REL) { + pr_warning("internal error at %d\n", __LINE__); + return -EINVAL; + } + + prog = bpf_find_prog_by_idx(obj, idx); + if (!prog) { + pr_warning("relocation failed: no %d section\n", + idx); + return -ENOENT; + } + + err = bpf_program_collect_reloc(obj, shdr, data, prog); + if (err) + return -EINVAL; + } + return 0; +} + static int bpf_obj_validate(struct bpf_object *obj) { if (obj->kern_version == 0) { @@ -556,6 +682,8 @@ struct bpf_object *bpf_open_object(const char *path) goto out; if (bpf_obj_elf_collect(obj)) goto out; + if (bpf_obj_collect_reloc(obj)) + goto out; if (bpf_obj_validate(obj)) goto out; diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index e523ae9..3505be7 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -21,4 +21,14 @@ struct bpf_object; struct bpf_object *bpf_open_object(const char *path); void bpf_close_object(struct bpf_object *object); +/* + * packed attribute is unnecessary for 'bpf_map_def'. + */ +struct bpf_map_def { + unsigned int type; + unsigned int key_size; + unsigned int value_size; + unsigned int max_entries; +}; + #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/