diff mbox series

[PATCHv3,bpf-next,07/26] libbpf: Move elf_find_func_offset* functions to elf object

Message ID 20230630083344.984305-8-jolsa@kernel.org (mailing list archive)
State Changes Requested
Delegated to: BPF
Headers show
Series bpf: Add multi uprobe link | expand

Checks

Context Check Description
netdev/series_format fail Series longer than 15 patches (and no cover letter)
netdev/tree_selection success Clearly marked for bpf-next, async
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 8 this patch: 8
netdev/cc_maintainers warning 3 maintainers not CCed: kpsingh@kernel.org martin.lau@linux.dev song@kernel.org
netdev/build_clang fail Errors and warnings before: 18 this patch: 18
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 8 this patch: 8
netdev/checkpatch warning CHECK: Comparison to NULL could be written "strstr" WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? WARNING: line length of 100 exceeds 80 columns WARNING: line length of 84 exceeds 80 columns WARNING: line length of 85 exceeds 80 columns WARNING: line length of 87 exceeds 80 columns WARNING: line length of 88 exceeds 80 columns WARNING: line length of 89 exceeds 80 columns WARNING: line length of 93 exceeds 80 columns WARNING: line length of 94 exceeds 80 columns WARNING: line length of 95 exceeds 80 columns WARNING: line length of 96 exceeds 80 columns WARNING: line length of 98 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ${{ matrix.test }} on ${{ matrix.arch }} with ${{ matrix.toolchain_full }}
bpf/vmtest-bpf-next-VM_Test-2 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-3 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-4 success Logs for build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-5 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 fail Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-7 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-8 success Logs for veristat

Commit Message

Jiri Olsa June 30, 2023, 8:33 a.m. UTC
Adding new elf object that will contain elf related functions.
There's no functional change.

Suggested-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/lib/bpf/Build        |   2 +-
 tools/lib/bpf/elf.c        | 198 +++++++++++++++++++++++++++++++++++++
 tools/lib/bpf/libbpf.c     | 186 +---------------------------------
 tools/lib/bpf/libbpf_elf.h |  11 +++
 4 files changed, 211 insertions(+), 186 deletions(-)
 create mode 100644 tools/lib/bpf/elf.c
 create mode 100644 tools/lib/bpf/libbpf_elf.h

Comments

Andrii Nakryiko July 6, 2023, 11:02 p.m. UTC | #1
On Fri, Jun 30, 2023 at 1:35 AM Jiri Olsa <jolsa@kernel.org> wrote:
>
> Adding new elf object that will contain elf related functions.
> There's no functional change.
>
> Suggested-by: Andrii Nakryiko <andrii@kernel.org>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---
>  tools/lib/bpf/Build        |   2 +-
>  tools/lib/bpf/elf.c        | 198 +++++++++++++++++++++++++++++++++++++
>  tools/lib/bpf/libbpf.c     | 186 +---------------------------------
>  tools/lib/bpf/libbpf_elf.h |  11 +++
>  4 files changed, 211 insertions(+), 186 deletions(-)
>  create mode 100644 tools/lib/bpf/elf.c
>  create mode 100644 tools/lib/bpf/libbpf_elf.h
>

[...]

> diff --git a/tools/lib/bpf/libbpf_elf.h b/tools/lib/bpf/libbpf_elf.h
> new file mode 100644
> index 000000000000..1b652220fabf
> --- /dev/null
> +++ b/tools/lib/bpf/libbpf_elf.h
> @@ -0,0 +1,11 @@
> +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
> +
> +#ifndef __LIBBPF_LIBBPF_ELF_H
> +#define __LIBBPF_LIBBPF_ELF_H
> +
> +#include <libelf.h>
> +
> +long elf_find_func_offset(Elf *elf, const char *binary_path, const char *name);
> +long elf_find_func_offset_from_file(const char *binary_path, const char *name);
> +
> +#endif /* *__LIBBPF_LIBBPF_ELF_H */

we have libbpf_internal.h, let's put all this there for now, it's
already all the internal stuff together, I don't know if separate
header with few functions gives us much

> --
> 2.41.0
>
Andrii Nakryiko July 6, 2023, 11:03 p.m. UTC | #2
On Fri, Jun 30, 2023 at 1:35 AM Jiri Olsa <jolsa@kernel.org> wrote:
>
> Adding new elf object that will contain elf related functions.
> There's no functional change.
>
> Suggested-by: Andrii Nakryiko <andrii@kernel.org>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---
>  tools/lib/bpf/Build        |   2 +-
>  tools/lib/bpf/elf.c        | 198 +++++++++++++++++++++++++++++++++++++
>  tools/lib/bpf/libbpf.c     | 186 +---------------------------------
>  tools/lib/bpf/libbpf_elf.h |  11 +++
>  4 files changed, 211 insertions(+), 186 deletions(-)
>  create mode 100644 tools/lib/bpf/elf.c
>  create mode 100644 tools/lib/bpf/libbpf_elf.h
>
> diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build
> index b8b0a6369363..2d0c282c8588 100644
> --- a/tools/lib/bpf/Build
> +++ b/tools/lib/bpf/Build
> @@ -1,4 +1,4 @@
>  libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o \
>             netlink.o bpf_prog_linfo.o libbpf_probes.o hashmap.o \
>             btf_dump.o ringbuf.o strset.o linker.o gen_loader.o relo_core.o \
> -           usdt.o zip.o
> +           usdt.o zip.o elf.o
> diff --git a/tools/lib/bpf/elf.c b/tools/lib/bpf/elf.c
> new file mode 100644
> index 000000000000..2b62b4af28ce
> --- /dev/null
> +++ b/tools/lib/bpf/elf.c
> @@ -0,0 +1,198 @@
> +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
> +
> +#include <libelf.h>
> +#include <gelf.h>
> +#include <fcntl.h>
> +#include <linux/kernel.h>

do you know why we need linux/kernel.h include? is it to get __u32 and
other typedefs?

> +
> +#include "libbpf_elf.h"
> +#include "libbpf_internal.h"
> +#include "str_error.h"
> +
> +#define STRERR_BUFSIZE  128
> +

[...]
Jiri Olsa July 11, 2023, 9:05 a.m. UTC | #3
On Thu, Jul 06, 2023 at 04:02:22PM -0700, Andrii Nakryiko wrote:
> On Fri, Jun 30, 2023 at 1:35 AM Jiri Olsa <jolsa@kernel.org> wrote:
> >
> > Adding new elf object that will contain elf related functions.
> > There's no functional change.
> >
> > Suggested-by: Andrii Nakryiko <andrii@kernel.org>
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > ---
> >  tools/lib/bpf/Build        |   2 +-
> >  tools/lib/bpf/elf.c        | 198 +++++++++++++++++++++++++++++++++++++
> >  tools/lib/bpf/libbpf.c     | 186 +---------------------------------
> >  tools/lib/bpf/libbpf_elf.h |  11 +++
> >  4 files changed, 211 insertions(+), 186 deletions(-)
> >  create mode 100644 tools/lib/bpf/elf.c
> >  create mode 100644 tools/lib/bpf/libbpf_elf.h
> >
> 
> [...]
> 
> > diff --git a/tools/lib/bpf/libbpf_elf.h b/tools/lib/bpf/libbpf_elf.h
> > new file mode 100644
> > index 000000000000..1b652220fabf
> > --- /dev/null
> > +++ b/tools/lib/bpf/libbpf_elf.h
> > @@ -0,0 +1,11 @@
> > +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
> > +
> > +#ifndef __LIBBPF_LIBBPF_ELF_H
> > +#define __LIBBPF_LIBBPF_ELF_H
> > +
> > +#include <libelf.h>
> > +
> > +long elf_find_func_offset(Elf *elf, const char *binary_path, const char *name);
> > +long elf_find_func_offset_from_file(const char *binary_path, const char *name);
> > +
> > +#endif /* *__LIBBPF_LIBBPF_ELF_H */
> 
> we have libbpf_internal.h, let's put all this there for now, it's
> already all the internal stuff together, I don't know if separate
> header with few functions gives us much

there's more functions coming later in the patchset

	struct elf_fd {
		Elf *elf;
		int fd;
	};

	int elf_open(const char *binary_path, struct elf_fd *elf_fd);
	void elf_close(struct elf_fd *elf_fd);

	int elf_resolve_syms_offsets(const char *binary_path, int cnt,
				     const char **syms, unsigned long **poffsets);

	int elf_resolve_pattern_offsets(const char *binary_path, const char *pattern,
					 unsigned long **poffsets, size_t *pcnt);


and there's probably more elf helpers to eventually move in:

	libbpf.c:static const char *elf_sym_str(const struct bpf_object *obj, size_t off);
	libbpf.c:static const char *elf_sec_str(const struct bpf_object *obj, size_t off);
	libbpf.c:static Elf_Scn *elf_sec_by_idx(const struct bpf_object *obj, size_t idx);
	libbpf.c:static Elf_Scn *elf_sec_by_name(const struct bpf_object *obj, const char *name);
	libbpf.c:static Elf64_Shdr *elf_sec_hdr(const struct bpf_object *obj, Elf_Scn *scn);
	libbpf.c:static const char *elf_sec_name(const struct bpf_object *obj, Elf_Scn *scn);
	libbpf.c:static Elf_Data *elf_sec_data(const struct bpf_object *obj, Elf_Scn *scn);
	libbpf.c:static Elf64_Sym *elf_sym_by_idx(const struct bpf_object *obj, size_t idx);
	libbpf.c:static Elf64_Rel *elf_rel_by_idx(Elf_Data *data, size_t idx);

	usdt.c:static int find_elf_sec_by_name(Elf *elf, const char *sec_name, GElf_Shdr *shdr, Elf_Scn **scn)

	'struct elf_seg' stuff

	usdt.c:static int cmp_elf_segs(const void *_a, const void *_b)
	usdt.c:static int parse_elf_segs(Elf *elf, const char *path, struct elf_seg **segs, size_t *seg_cnt)
	usdt.c:static int parse_vma_segs(int pid, const char *lib_path, struct elf_seg **segs, size_t *seg_cnt)
	usdt.c:static struct elf_seg *find_elf_seg(struct elf_seg *segs, size_t seg_cnt, long virtaddr)
	usdt.c:static struct elf_seg *find_vma_seg(struct elf_seg *segs, size_t seg_cnt, long offset)


but I can add the new header file later in follow up changes when
we have more elf functions in

jirka
Jiri Olsa July 11, 2023, 9:05 a.m. UTC | #4
On Thu, Jul 06, 2023 at 04:03:22PM -0700, Andrii Nakryiko wrote:
> On Fri, Jun 30, 2023 at 1:35 AM Jiri Olsa <jolsa@kernel.org> wrote:
> >
> > Adding new elf object that will contain elf related functions.
> > There's no functional change.
> >
> > Suggested-by: Andrii Nakryiko <andrii@kernel.org>
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > ---
> >  tools/lib/bpf/Build        |   2 +-
> >  tools/lib/bpf/elf.c        | 198 +++++++++++++++++++++++++++++++++++++
> >  tools/lib/bpf/libbpf.c     | 186 +---------------------------------
> >  tools/lib/bpf/libbpf_elf.h |  11 +++
> >  4 files changed, 211 insertions(+), 186 deletions(-)
> >  create mode 100644 tools/lib/bpf/elf.c
> >  create mode 100644 tools/lib/bpf/libbpf_elf.h
> >
> > diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build
> > index b8b0a6369363..2d0c282c8588 100644
> > --- a/tools/lib/bpf/Build
> > +++ b/tools/lib/bpf/Build
> > @@ -1,4 +1,4 @@
> >  libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o \
> >             netlink.o bpf_prog_linfo.o libbpf_probes.o hashmap.o \
> >             btf_dump.o ringbuf.o strset.o linker.o gen_loader.o relo_core.o \
> > -           usdt.o zip.o
> > +           usdt.o zip.o elf.o
> > diff --git a/tools/lib/bpf/elf.c b/tools/lib/bpf/elf.c
> > new file mode 100644
> > index 000000000000..2b62b4af28ce
> > --- /dev/null
> > +++ b/tools/lib/bpf/elf.c
> > @@ -0,0 +1,198 @@
> > +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
> > +
> > +#include <libelf.h>
> > +#include <gelf.h>
> > +#include <fcntl.h>
> > +#include <linux/kernel.h>
> 
> do you know why we need linux/kernel.h include? is it to get __u32 and
> other typedefs?

it's for the ARRAY_SIZE macro

jirka

> 
> > +
> > +#include "libbpf_elf.h"
> > +#include "libbpf_internal.h"
> > +#include "str_error.h"
> > +
> > +#define STRERR_BUFSIZE  128
> > +
> 
> [...]
Andrii Nakryiko July 11, 2023, 5:01 p.m. UTC | #5
On Tue, Jul 11, 2023 at 2:05 AM Jiri Olsa <olsajiri@gmail.com> wrote:
>
> On Thu, Jul 06, 2023 at 04:02:22PM -0700, Andrii Nakryiko wrote:
> > On Fri, Jun 30, 2023 at 1:35 AM Jiri Olsa <jolsa@kernel.org> wrote:
> > >
> > > Adding new elf object that will contain elf related functions.
> > > There's no functional change.
> > >
> > > Suggested-by: Andrii Nakryiko <andrii@kernel.org>
> > > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > > ---
> > >  tools/lib/bpf/Build        |   2 +-
> > >  tools/lib/bpf/elf.c        | 198 +++++++++++++++++++++++++++++++++++++
> > >  tools/lib/bpf/libbpf.c     | 186 +---------------------------------
> > >  tools/lib/bpf/libbpf_elf.h |  11 +++
> > >  4 files changed, 211 insertions(+), 186 deletions(-)
> > >  create mode 100644 tools/lib/bpf/elf.c
> > >  create mode 100644 tools/lib/bpf/libbpf_elf.h
> > >
> >
> > [...]
> >
> > > diff --git a/tools/lib/bpf/libbpf_elf.h b/tools/lib/bpf/libbpf_elf.h
> > > new file mode 100644
> > > index 000000000000..1b652220fabf
> > > --- /dev/null
> > > +++ b/tools/lib/bpf/libbpf_elf.h
> > > @@ -0,0 +1,11 @@
> > > +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
> > > +
> > > +#ifndef __LIBBPF_LIBBPF_ELF_H
> > > +#define __LIBBPF_LIBBPF_ELF_H
> > > +
> > > +#include <libelf.h>
> > > +
> > > +long elf_find_func_offset(Elf *elf, const char *binary_path, const char *name);
> > > +long elf_find_func_offset_from_file(const char *binary_path, const char *name);
> > > +
> > > +#endif /* *__LIBBPF_LIBBPF_ELF_H */
> >
> > we have libbpf_internal.h, let's put all this there for now, it's
> > already all the internal stuff together, I don't know if separate
> > header with few functions gives us much
>
> there's more functions coming later in the patchset
>
>         struct elf_fd {
>                 Elf *elf;
>                 int fd;
>         };
>
>         int elf_open(const char *binary_path, struct elf_fd *elf_fd);
>         void elf_close(struct elf_fd *elf_fd);
>
>         int elf_resolve_syms_offsets(const char *binary_path, int cnt,
>                                      const char **syms, unsigned long **poffsets);
>
>         int elf_resolve_pattern_offsets(const char *binary_path, const char *pattern,
>                                          unsigned long **poffsets, size_t *pcnt);
>
>
> and there's probably more elf helpers to eventually move in:
>
>         libbpf.c:static const char *elf_sym_str(const struct bpf_object *obj, size_t off);
>         libbpf.c:static const char *elf_sec_str(const struct bpf_object *obj, size_t off);
>         libbpf.c:static Elf_Scn *elf_sec_by_idx(const struct bpf_object *obj, size_t idx);
>         libbpf.c:static Elf_Scn *elf_sec_by_name(const struct bpf_object *obj, const char *name);
>         libbpf.c:static Elf64_Shdr *elf_sec_hdr(const struct bpf_object *obj, Elf_Scn *scn);
>         libbpf.c:static const char *elf_sec_name(const struct bpf_object *obj, Elf_Scn *scn);
>         libbpf.c:static Elf_Data *elf_sec_data(const struct bpf_object *obj, Elf_Scn *scn);
>         libbpf.c:static Elf64_Sym *elf_sym_by_idx(const struct bpf_object *obj, size_t idx);
>         libbpf.c:static Elf64_Rel *elf_rel_by_idx(Elf_Data *data, size_t idx);
>

yep, I was anticipating that these will move as well. But I think it's
fine if they all stay in libbpf_internal.h, IMO. I'd rather not have
many small internal header for no good reason (like we have
str_error.h right now, with a single func declaration)

>         usdt.c:static int find_elf_sec_by_name(Elf *elf, const char *sec_name, GElf_Shdr *shdr, Elf_Scn **scn)
>
>         'struct elf_seg' stuff
>
>         usdt.c:static int cmp_elf_segs(const void *_a, const void *_b)
>         usdt.c:static int parse_elf_segs(Elf *elf, const char *path, struct elf_seg **segs, size_t *seg_cnt)
>         usdt.c:static int parse_vma_segs(int pid, const char *lib_path, struct elf_seg **segs, size_t *seg_cnt)
>         usdt.c:static struct elf_seg *find_elf_seg(struct elf_seg *segs, size_t seg_cnt, long virtaddr)
>         usdt.c:static struct elf_seg *find_vma_seg(struct elf_seg *segs, size_t seg_cnt, long offset)
>
>
> but I can add the new header file later in follow up changes when
> we have more elf functions in

see above, I don't think we should, let's stick to libbpf_internal.h for now

>
> jirka
diff mbox series

Patch

diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build
index b8b0a6369363..2d0c282c8588 100644
--- a/tools/lib/bpf/Build
+++ b/tools/lib/bpf/Build
@@ -1,4 +1,4 @@ 
 libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o \
 	    netlink.o bpf_prog_linfo.o libbpf_probes.o hashmap.o \
 	    btf_dump.o ringbuf.o strset.o linker.o gen_loader.o relo_core.o \
-	    usdt.o zip.o
+	    usdt.o zip.o elf.o
diff --git a/tools/lib/bpf/elf.c b/tools/lib/bpf/elf.c
new file mode 100644
index 000000000000..2b62b4af28ce
--- /dev/null
+++ b/tools/lib/bpf/elf.c
@@ -0,0 +1,198 @@ 
+// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
+
+#include <libelf.h>
+#include <gelf.h>
+#include <fcntl.h>
+#include <linux/kernel.h>
+
+#include "libbpf_elf.h"
+#include "libbpf_internal.h"
+#include "str_error.h"
+
+#define STRERR_BUFSIZE  128
+
+/* Return next ELF section of sh_type after scn, or first of that type if scn is NULL. */
+static Elf_Scn *elf_find_next_scn_by_type(Elf *elf, int sh_type, Elf_Scn *scn)
+{
+	while ((scn = elf_nextscn(elf, scn)) != NULL) {
+		GElf_Shdr sh;
+
+		if (!gelf_getshdr(scn, &sh))
+			continue;
+		if (sh.sh_type == sh_type)
+			return scn;
+	}
+	return NULL;
+}
+
+/* Find offset of function name in the provided ELF object. "binary_path" is
+ * the path to the ELF binary represented by "elf", and only used for error
+ * reporting matters. "name" matches symbol name or name@@LIB for library
+ * functions.
+ */
+long elf_find_func_offset(Elf *elf, const char *binary_path, const char *name)
+{
+	int i, sh_types[2] = { SHT_DYNSYM, SHT_SYMTAB };
+	bool is_shared_lib, is_name_qualified;
+	long ret = -ENOENT;
+	size_t name_len;
+	GElf_Ehdr ehdr;
+
+	if (!gelf_getehdr(elf, &ehdr)) {
+		pr_warn("elf: failed to get ehdr from %s: %s\n", binary_path, elf_errmsg(-1));
+		ret = -LIBBPF_ERRNO__FORMAT;
+		goto out;
+	}
+	/* for shared lib case, we do not need to calculate relative offset */
+	is_shared_lib = ehdr.e_type == ET_DYN;
+
+	name_len = strlen(name);
+	/* Does name specify "@@LIB"? */
+	is_name_qualified = strstr(name, "@@") != NULL;
+
+	/* Search SHT_DYNSYM, SHT_SYMTAB for symbol. This search order is used because if
+	 * a binary is stripped, it may only have SHT_DYNSYM, and a fully-statically
+	 * linked binary may not have SHT_DYMSYM, so absence of a section should not be
+	 * reported as a warning/error.
+	 */
+	for (i = 0; i < ARRAY_SIZE(sh_types); i++) {
+		size_t nr_syms, strtabidx, idx;
+		Elf_Data *symbols = NULL;
+		Elf_Scn *scn = NULL;
+		int last_bind = -1;
+		const char *sname;
+		GElf_Shdr sh;
+
+		scn = elf_find_next_scn_by_type(elf, sh_types[i], NULL);
+		if (!scn) {
+			pr_debug("elf: failed to find symbol table ELF sections in '%s'\n",
+				 binary_path);
+			continue;
+		}
+		if (!gelf_getshdr(scn, &sh))
+			continue;
+		strtabidx = sh.sh_link;
+		symbols = elf_getdata(scn, 0);
+		if (!symbols) {
+			pr_warn("elf: failed to get symbols for symtab section in '%s': %s\n",
+				binary_path, elf_errmsg(-1));
+			ret = -LIBBPF_ERRNO__FORMAT;
+			goto out;
+		}
+		nr_syms = symbols->d_size / sh.sh_entsize;
+
+		for (idx = 0; idx < nr_syms; idx++) {
+			int curr_bind;
+			GElf_Sym sym;
+			Elf_Scn *sym_scn;
+			GElf_Shdr sym_sh;
+
+			if (!gelf_getsym(symbols, idx, &sym))
+				continue;
+
+			if (GELF_ST_TYPE(sym.st_info) != STT_FUNC)
+				continue;
+
+			sname = elf_strptr(elf, strtabidx, sym.st_name);
+			if (!sname)
+				continue;
+
+			curr_bind = GELF_ST_BIND(sym.st_info);
+
+			/* User can specify func, func@@LIB or func@@LIB_VERSION. */
+			if (strncmp(sname, name, name_len) != 0)
+				continue;
+			/* ...but we don't want a search for "foo" to match 'foo2" also, so any
+			 * additional characters in sname should be of the form "@@LIB".
+			 */
+			if (!is_name_qualified && sname[name_len] != '\0' && sname[name_len] != '@')
+				continue;
+
+			if (ret >= 0) {
+				/* handle multiple matches */
+				if (last_bind != STB_WEAK && curr_bind != STB_WEAK) {
+					/* Only accept one non-weak bind. */
+					pr_warn("elf: ambiguous match for '%s', '%s' in '%s'\n",
+						sname, name, binary_path);
+					ret = -LIBBPF_ERRNO__FORMAT;
+					goto out;
+				} else if (curr_bind == STB_WEAK) {
+					/* already have a non-weak bind, and
+					 * this is a weak bind, so ignore.
+					 */
+					continue;
+				}
+			}
+
+			/* Transform symbol's virtual address (absolute for
+			 * binaries and relative for shared libs) into file
+			 * offset, which is what kernel is expecting for
+			 * uprobe/uretprobe attachment.
+			 * See Documentation/trace/uprobetracer.rst for more
+			 * details.
+			 * This is done by looking up symbol's containing
+			 * section's header and using it's virtual address
+			 * (sh_addr) and corresponding file offset (sh_offset)
+			 * to transform sym.st_value (virtual address) into
+			 * desired final file offset.
+			 */
+			sym_scn = elf_getscn(elf, sym.st_shndx);
+			if (!sym_scn)
+				continue;
+			if (!gelf_getshdr(sym_scn, &sym_sh))
+				continue;
+
+			ret = sym.st_value - sym_sh.sh_addr + sym_sh.sh_offset;
+			last_bind = curr_bind;
+		}
+		if (ret > 0)
+			break;
+	}
+
+	if (ret > 0) {
+		pr_debug("elf: symbol address match for '%s' in '%s': 0x%lx\n", name, binary_path,
+			 ret);
+	} else {
+		if (ret == 0) {
+			pr_warn("elf: '%s' is 0 in symtab for '%s': %s\n", name, binary_path,
+				is_shared_lib ? "should not be 0 in a shared library" :
+						"try using shared library path instead");
+			ret = -ENOENT;
+		} else {
+			pr_warn("elf: failed to find symbol '%s' in '%s'\n", name, binary_path);
+		}
+	}
+out:
+	return ret;
+}
+
+/* Find offset of function name in ELF object specified by path. "name" matches
+ * symbol name or name@@LIB for library functions.
+ */
+long elf_find_func_offset_from_file(const char *binary_path, const char *name)
+{
+	char errmsg[STRERR_BUFSIZE];
+	long ret = -ENOENT;
+	Elf *elf;
+	int fd;
+
+	fd = open(binary_path, O_RDONLY | O_CLOEXEC);
+	if (fd < 0) {
+		ret = -errno;
+		pr_warn("failed to open %s: %s\n", binary_path,
+			libbpf_strerror_r(ret, errmsg, sizeof(errmsg)));
+		return ret;
+	}
+	elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
+	if (!elf) {
+		pr_warn("elf: could not read elf from %s: %s\n", binary_path, elf_errmsg(-1));
+		close(fd);
+		return -LIBBPF_ERRNO__FORMAT;
+	}
+
+	ret = elf_find_func_offset(elf, binary_path, name);
+	elf_end(elf);
+	close(fd);
+	return ret;
+}
+
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 53dcf25c4878..093add8124d8 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -54,6 +54,7 @@ 
 #include "hashmap.h"
 #include "bpf_gen_internal.h"
 #include "zip.h"
+#include "libbpf_elf.h"
 
 #ifndef BPF_FS_MAGIC
 #define BPF_FS_MAGIC		0xcafe4a11
@@ -10811,191 +10812,6 @@  static int perf_event_uprobe_open_legacy(const char *probe_name, bool retprobe,
 	return err;
 }
 
-/* Return next ELF section of sh_type after scn, or first of that type if scn is NULL. */
-static Elf_Scn *elf_find_next_scn_by_type(Elf *elf, int sh_type, Elf_Scn *scn)
-{
-	while ((scn = elf_nextscn(elf, scn)) != NULL) {
-		GElf_Shdr sh;
-
-		if (!gelf_getshdr(scn, &sh))
-			continue;
-		if (sh.sh_type == sh_type)
-			return scn;
-	}
-	return NULL;
-}
-
-/* Find offset of function name in the provided ELF object. "binary_path" is
- * the path to the ELF binary represented by "elf", and only used for error
- * reporting matters. "name" matches symbol name or name@@LIB for library
- * functions.
- */
-static long elf_find_func_offset(Elf *elf, const char *binary_path, const char *name)
-{
-	int i, sh_types[2] = { SHT_DYNSYM, SHT_SYMTAB };
-	bool is_shared_lib, is_name_qualified;
-	long ret = -ENOENT;
-	size_t name_len;
-	GElf_Ehdr ehdr;
-
-	if (!gelf_getehdr(elf, &ehdr)) {
-		pr_warn("elf: failed to get ehdr from %s: %s\n", binary_path, elf_errmsg(-1));
-		ret = -LIBBPF_ERRNO__FORMAT;
-		goto out;
-	}
-	/* for shared lib case, we do not need to calculate relative offset */
-	is_shared_lib = ehdr.e_type == ET_DYN;
-
-	name_len = strlen(name);
-	/* Does name specify "@@LIB"? */
-	is_name_qualified = strstr(name, "@@") != NULL;
-
-	/* Search SHT_DYNSYM, SHT_SYMTAB for symbol. This search order is used because if
-	 * a binary is stripped, it may only have SHT_DYNSYM, and a fully-statically
-	 * linked binary may not have SHT_DYMSYM, so absence of a section should not be
-	 * reported as a warning/error.
-	 */
-	for (i = 0; i < ARRAY_SIZE(sh_types); i++) {
-		size_t nr_syms, strtabidx, idx;
-		Elf_Data *symbols = NULL;
-		Elf_Scn *scn = NULL;
-		int last_bind = -1;
-		const char *sname;
-		GElf_Shdr sh;
-
-		scn = elf_find_next_scn_by_type(elf, sh_types[i], NULL);
-		if (!scn) {
-			pr_debug("elf: failed to find symbol table ELF sections in '%s'\n",
-				 binary_path);
-			continue;
-		}
-		if (!gelf_getshdr(scn, &sh))
-			continue;
-		strtabidx = sh.sh_link;
-		symbols = elf_getdata(scn, 0);
-		if (!symbols) {
-			pr_warn("elf: failed to get symbols for symtab section in '%s': %s\n",
-				binary_path, elf_errmsg(-1));
-			ret = -LIBBPF_ERRNO__FORMAT;
-			goto out;
-		}
-		nr_syms = symbols->d_size / sh.sh_entsize;
-
-		for (idx = 0; idx < nr_syms; idx++) {
-			int curr_bind;
-			GElf_Sym sym;
-			Elf_Scn *sym_scn;
-			GElf_Shdr sym_sh;
-
-			if (!gelf_getsym(symbols, idx, &sym))
-				continue;
-
-			if (GELF_ST_TYPE(sym.st_info) != STT_FUNC)
-				continue;
-
-			sname = elf_strptr(elf, strtabidx, sym.st_name);
-			if (!sname)
-				continue;
-
-			curr_bind = GELF_ST_BIND(sym.st_info);
-
-			/* User can specify func, func@@LIB or func@@LIB_VERSION. */
-			if (strncmp(sname, name, name_len) != 0)
-				continue;
-			/* ...but we don't want a search for "foo" to match 'foo2" also, so any
-			 * additional characters in sname should be of the form "@@LIB".
-			 */
-			if (!is_name_qualified && sname[name_len] != '\0' && sname[name_len] != '@')
-				continue;
-
-			if (ret >= 0) {
-				/* handle multiple matches */
-				if (last_bind != STB_WEAK && curr_bind != STB_WEAK) {
-					/* Only accept one non-weak bind. */
-					pr_warn("elf: ambiguous match for '%s', '%s' in '%s'\n",
-						sname, name, binary_path);
-					ret = -LIBBPF_ERRNO__FORMAT;
-					goto out;
-				} else if (curr_bind == STB_WEAK) {
-					/* already have a non-weak bind, and
-					 * this is a weak bind, so ignore.
-					 */
-					continue;
-				}
-			}
-
-			/* Transform symbol's virtual address (absolute for
-			 * binaries and relative for shared libs) into file
-			 * offset, which is what kernel is expecting for
-			 * uprobe/uretprobe attachment.
-			 * See Documentation/trace/uprobetracer.rst for more
-			 * details.
-			 * This is done by looking up symbol's containing
-			 * section's header and using it's virtual address
-			 * (sh_addr) and corresponding file offset (sh_offset)
-			 * to transform sym.st_value (virtual address) into
-			 * desired final file offset.
-			 */
-			sym_scn = elf_getscn(elf, sym.st_shndx);
-			if (!sym_scn)
-				continue;
-			if (!gelf_getshdr(sym_scn, &sym_sh))
-				continue;
-
-			ret = sym.st_value - sym_sh.sh_addr + sym_sh.sh_offset;
-			last_bind = curr_bind;
-		}
-		if (ret > 0)
-			break;
-	}
-
-	if (ret > 0) {
-		pr_debug("elf: symbol address match for '%s' in '%s': 0x%lx\n", name, binary_path,
-			 ret);
-	} else {
-		if (ret == 0) {
-			pr_warn("elf: '%s' is 0 in symtab for '%s': %s\n", name, binary_path,
-				is_shared_lib ? "should not be 0 in a shared library" :
-						"try using shared library path instead");
-			ret = -ENOENT;
-		} else {
-			pr_warn("elf: failed to find symbol '%s' in '%s'\n", name, binary_path);
-		}
-	}
-out:
-	return ret;
-}
-
-/* Find offset of function name in ELF object specified by path. "name" matches
- * symbol name or name@@LIB for library functions.
- */
-static long elf_find_func_offset_from_file(const char *binary_path, const char *name)
-{
-	char errmsg[STRERR_BUFSIZE];
-	long ret = -ENOENT;
-	Elf *elf;
-	int fd;
-
-	fd = open(binary_path, O_RDONLY | O_CLOEXEC);
-	if (fd < 0) {
-		ret = -errno;
-		pr_warn("failed to open %s: %s\n", binary_path,
-			libbpf_strerror_r(ret, errmsg, sizeof(errmsg)));
-		return ret;
-	}
-	elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
-	if (!elf) {
-		pr_warn("elf: could not read elf from %s: %s\n", binary_path, elf_errmsg(-1));
-		close(fd);
-		return -LIBBPF_ERRNO__FORMAT;
-	}
-
-	ret = elf_find_func_offset(elf, binary_path, name);
-	elf_end(elf);
-	close(fd);
-	return ret;
-}
-
 /* Find offset of function name in archive specified by path. Currently
  * supported are .zip files that do not compress their contents, as used on
  * Android in the form of APKs, for example. "file_name" is the name of the ELF
diff --git a/tools/lib/bpf/libbpf_elf.h b/tools/lib/bpf/libbpf_elf.h
new file mode 100644
index 000000000000..1b652220fabf
--- /dev/null
+++ b/tools/lib/bpf/libbpf_elf.h
@@ -0,0 +1,11 @@ 
+/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
+
+#ifndef __LIBBPF_LIBBPF_ELF_H
+#define __LIBBPF_LIBBPF_ELF_H
+
+#include <libelf.h>
+
+long elf_find_func_offset(Elf *elf, const char *binary_path, const char *name);
+long elf_find_func_offset_from_file(const char *binary_path, const char *name);
+
+#endif /* *__LIBBPF_LIBBPF_ELF_H */