netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Alexei Starovoitov <ast@kernel.org>
To: <davem@davemloft.net>
Cc: <daniel@iogearbox.net>, <netdev@vger.kernel.org>,
	<bpf@vger.kernel.org>, <kernel-team@fb.com>
Subject: [PATCH bpf-next 2/6] libbpf: Collect static vs global info about functions
Date: Tue, 7 Jan 2020 23:25:34 -0800	[thread overview]
Message-ID: <20200108072538.3359838-3-ast@kernel.org> (raw)
In-Reply-To: <20200108072538.3359838-1-ast@kernel.org>

Collect static vs global information about BPF functions from ELF file and
improve BTF with this additional info if llvm is too old and doesn't emit it on
its own.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
---
 tools/lib/bpf/libbpf.c | 115 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 111 insertions(+), 4 deletions(-)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index f72b3ed6c34b..2a4417d03ee2 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -294,6 +294,12 @@ struct extern_desc {
 
 static LIST_HEAD(bpf_objects_list);
 
+struct func_desc {
+	int insn_idx;
+	int sec_idx;
+	enum btf_func_linkage linkage;
+};
+
 struct bpf_object {
 	char name[BPF_OBJ_NAME_LEN];
 	char license[64];
@@ -304,6 +310,8 @@ struct bpf_object {
 	struct bpf_map *maps;
 	size_t nr_maps;
 	size_t maps_cap;
+	struct func_desc *funcs;
+	int nr_funcs;
 
 	char *kconfig;
 	struct extern_desc *externs;
@@ -313,6 +321,7 @@ struct bpf_object {
 	bool loaded;
 	bool has_pseudo_calls;
 	bool relaxed_core_relocs;
+	bool llvm_emits_func_linkage;
 
 	/*
 	 * Information when doing elf related work. Only valid if fd
@@ -526,10 +535,10 @@ bpf_object__init_prog_names(struct bpf_object *obj)
 				continue;
 			if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL)
 				continue;
-
 			name = elf_strptr(obj->efile.elf,
 					  obj->efile.strtabidx,
 					  sym.st_name);
+
 			if (!name) {
 				pr_warn("failed to get sym name string for prog %s\n",
 					prog->section_name);
@@ -2232,6 +2241,34 @@ static int cmp_externs(const void *_a, const void *_b)
 	return strcmp(a->name, b->name);
 }
 
+static int bpf_object__record_func_info(struct bpf_object *obj, GElf_Sym *sym)
+{
+	int bind = GELF_ST_BIND(sym->st_info);
+	bool static_func = bind == STB_LOCAL;
+	struct func_desc *f;
+
+	/*
+	 * Cannot check obj->caps.btf_func_linkage during elf open phase.
+	 * Otherwise could have skipped collection of this info.
+	 */
+
+	f = obj->funcs;
+	f = reallocarray(f, obj->nr_funcs + 1, sizeof(*f));
+	if (!f)
+		return -ENOMEM;
+	obj->funcs = f;
+	f = &f[obj->nr_funcs];
+	memset(f, 0, sizeof(*f));
+	obj->nr_funcs++;
+
+	f->insn_idx = sym->st_value / 8;
+	f->linkage = static_func ? BTF_FUNC_STATIC : BTF_FUNC_GLOBAL;
+	f->sec_idx = sym->st_shndx;
+	pr_debug("Func at insn %d sec %d linkage %d\n",
+		 f->insn_idx, f->sec_idx, f->linkage);
+	return 0;
+}
+
 static int bpf_object__collect_externs(struct bpf_object *obj)
 {
 	const struct btf_type *t;
@@ -2258,6 +2295,12 @@ static int bpf_object__collect_externs(struct bpf_object *obj)
 
 		if (!gelf_getsym(obj->efile.symbols, i, &sym))
 			return -LIBBPF_ERRNO__FORMAT;
+		if (GELF_ST_TYPE(sym.st_info) == STT_FUNC) {
+			int err = bpf_object__record_func_info(obj, &sym);
+
+			if (err)
+				return err;
+		}
 		if (!sym_is_extern(&sym))
 			continue;
 		ext_name = elf_strptr(obj->efile.elf, obj->efile.strtabidx,
@@ -3145,9 +3188,62 @@ check_btf_ext_reloc_err(struct bpf_program *prog, int err,
 	return 0;
 }
 
+static int btf_ext_improve_func_info(struct bpf_object *obj,
+				     struct bpf_program *prog,
+				     __u32 sec_idx)
+{
+	struct bpf_func_info_min *info;
+	struct btf_type *t;
+	struct func_desc *f;
+	const char *name;
+	int i, j;
+
+	if (!obj->caps.btf_func_linkage || obj->llvm_emits_func_linkage)
+		/*
+		 * If kernel doesn't understand func linkage or llvm emits
+		 * it already into BTF then don't try to improve BTF based on
+		 * ELF info.
+		 */
+		return 0;
+
+	info = prog->func_info;
+	for (i = 0; i < prog->func_info_cnt; i++) {
+		for (j = 0; j < obj->nr_funcs; j++) {
+			f = &obj->funcs[j];
+			if (f->insn_idx != info->insn_off ||
+			    f->sec_idx != sec_idx)
+				continue;
+			t = (void *)btf__type_by_id(obj->btf, info->type_id);
+			if (!t)
+				return -EINVAL;
+			name = btf__name_by_offset(obj->btf, t->name_off);
+			if (!name)
+				return -EINVAL;
+			pr_debug("Func '%s' at insn %d btf_id %d linkage in BTF %d in ELF %d\n",
+				 name, info->insn_off, info->type_id,
+				 BTF_INFO_VLEN(t->info), f->linkage);
+			if (BTF_INFO_VLEN(t->info) == f->linkage) {
+				if (BTF_INFO_VLEN(t->info)) {
+					/* llvm emits func linkage. Don't touch BTF */
+					obj->llvm_emits_func_linkage = true;
+					return 0;
+				}
+			} else {
+				/* improve BTF with static vs global */
+				t->info = BTF_INFO_ENC(BTF_KIND_FUNC, 0,
+						       f->linkage);
+			}
+			break;
+		}
+		info = ((void *)info) + prog->func_info_rec_size;
+	}
+	return 0;
+}
+
 static int
 bpf_program_reloc_btf_ext(struct bpf_program *prog, struct bpf_object *obj,
-			  const char *section_name,  __u32 insn_offset)
+			  const char *section_name,  __u32 insn_offset,
+			  __u32 sec_idx)
 {
 	int err;
 
@@ -3168,6 +3264,15 @@ bpf_program_reloc_btf_ext(struct bpf_program *prog, struct bpf_object *obj,
 						       "bpf_func_info");
 
 		prog->func_info_rec_size = btf_ext__func_info_rec_size(obj->btf_ext);
+		if (!insn_offset) {
+			/*
+			 * improve BTF_KIND_FUNC when func_info is allocated
+			 * first time. Don't touch it during relocation.
+			 */
+			err = btf_ext_improve_func_info(obj, prog, sec_idx);
+			if (err)
+				return err;
+		}
 	}
 
 	if (!insn_offset || prog->line_info) {
@@ -4308,7 +4413,8 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj,
 		if (obj->btf_ext) {
 			err = bpf_program_reloc_btf_ext(prog, obj,
 							text->section_name,
-							prog->insns_cnt);
+							prog->insns_cnt,
+							text->idx);
 			if (err)
 				return err;
 		}
@@ -4336,7 +4442,8 @@ bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj)
 
 	if (obj->btf_ext) {
 		err = bpf_program_reloc_btf_ext(prog, obj,
-						prog->section_name, 0);
+						prog->section_name, 0,
+						prog->idx);
 		if (err)
 			return err;
 	}
-- 
2.23.0


  parent reply	other threads:[~2020-01-08  7:26 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-01-08  7:25 [PATCH bpf-next 0/6] bpf: Introduce global functions Alexei Starovoitov
2020-01-08  7:25 ` [PATCH bpf-next 1/6] libbpf: Sanitize BTF_KIND_FUNC linkage Alexei Starovoitov
2020-01-08 17:35   ` Song Liu
2020-01-08 18:57   ` Yonghong Song
2020-01-08 20:12     ` Alexei Starovoitov
2020-01-08  7:25 ` Alexei Starovoitov [this message]
2020-01-08 10:25   ` [PATCH bpf-next 2/6] libbpf: Collect static vs global info about functions Toke Høiland-Jørgensen
2020-01-08 16:25     ` Yonghong Song
2020-01-09  8:50       ` Toke Høiland-Jørgensen
2020-01-08 17:57     ` Song Liu
2020-01-08 20:10       ` Alexei Starovoitov
2020-01-08  7:25 ` [PATCH bpf-next 3/6] bpf: Introduce function-by-function verification Alexei Starovoitov
2020-01-08 10:28   ` Toke Høiland-Jørgensen
2020-01-08 20:06     ` Alexei Starovoitov
2020-01-09  8:57       ` Toke Høiland-Jørgensen
2020-01-09 23:03         ` Alexei Starovoitov
2020-01-10 10:08           ` Toke Høiland-Jørgensen
2020-01-08 19:10   ` Song Liu
2020-01-08 20:20     ` Alexei Starovoitov
2020-01-08 21:24       ` Song Liu
2020-01-08 23:05   ` Alexei Starovoitov
2020-01-14 23:39   ` Stanislav Fomichev
2020-01-14 23:56     ` Andrii Nakryiko
2020-01-15  0:44       ` Stanislav Fomichev
2020-01-08  7:25 ` [PATCH bpf-next 4/6] selftests/bpf: Add fexit-to-skb test for global funcs Alexei Starovoitov
2020-01-08 19:15   ` Song Liu
2020-01-08  7:25 ` [PATCH bpf-next 5/6] selftests/bpf: Add a test for a large global function Alexei Starovoitov
2020-01-08 19:16   ` Song Liu
2020-01-08 19:17     ` Song Liu
2020-01-08  7:25 ` [PATCH bpf-next 6/6] selftests/bpf: Modify a test to check global functions Alexei Starovoitov
2020-01-08 19:18   ` Song Liu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200108072538.3359838-3-ast@kernel.org \
    --to=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=davem@davemloft.net \
    --cc=kernel-team@fb.com \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).