From: Jiri Olsa <jolsa@kernel.org>
To: Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>
Cc: bpf@vger.kernel.org, Martin KaFai Lau <kafai@fb.com>,
Song Liu <songliubraving@fb.com>, Yonghong Song <yhs@fb.com>,
John Fastabend <john.fastabend@gmail.com>,
KP Singh <kpsingh@chromium.org>,
Stanislav Fomichev <sdf@google.com>, Hao Luo <haoluo@google.com>,
Arnaldo Carvalho de Melo <acme@kernel.org>
Subject: [RFC/PATCH bpf-next 06/20] libbpf: Factor elf_for_each_symbol function
Date: Mon, 24 Apr 2023 18:04:33 +0200 [thread overview]
Message-ID: <20230424160447.2005755-7-jolsa@kernel.org> (raw)
In-Reply-To: <20230424160447.2005755-1-jolsa@kernel.org>
Currently we have elf_find_func_offset function that looks up
symbol in the binary and returns its offset to be used for uprobe
attachment.
For attaching multiple uprobes we will need interface that allows
us to get offsets for multiple symbols specified either by name or
regular expression.
Factoring out elf_for_each_symbol helper function that iterates
all symbols in binary and calls following callbacks:
fn_match - on each symbol
if it returns error < 0, we bail out with that error
fn_done - when we finish iterating symbol section,
if it returns true, we don't iterate next section
It will be used in following changes to lookup multiple symbols
and their offsets.
Changing elf_find_func_offset to use elf_for_each_symbol with
single_match callback that's looking to match single function.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
tools/lib/bpf/libbpf.c | 185 +++++++++++++++++++++++++----------------
1 file changed, 114 insertions(+), 71 deletions(-)
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index b5bde1f19831..92c92ed2101f 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -10707,30 +10707,87 @@ static Elf_Scn *elf_find_next_scn_by_type(Elf *elf, int sh_type, Elf_Scn *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;
+struct elf_func_offset {
+ const char *name;
+ unsigned long offset;
+ int last_bind;
size_t name_len;
- GElf_Ehdr ehdr;
+ bool is_name_qualified;
+};
- 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;
+static int single_done(void *_data)
+{
+ struct elf_func_offset *data = _data;
+
+ return data->offset > 0;
+}
+
+static int single_match(Elf *elf, const char *binary_path, const char *sname,
+ GElf_Sym *sym, void *_data)
+{
+ struct elf_func_offset *data = _data;
+ size_t name_len = data->name_len;
+ const char *name = data->name;
+ Elf_Scn *sym_scn;
+ GElf_Shdr sym_sh;
+ int curr_bind;
+
+ 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)
+ return 0;
+ /* ...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 (!data->is_name_qualified && sname[name_len] != '\0' && sname[name_len] != '@')
+ return 0;
+
+ if (data->offset > 0) {
+ /* handle multiple matches */
+ if (data->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);
+ return -LIBBPF_ERRNO__FORMAT;
+ } else if (curr_bind == STB_WEAK) {
+ /* already have a non-weak bind, and
+ * this is a weak bind, so ignore.
+ */
+ return 0;
+ }
}
- /* 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;
+ /* 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)
+ return 0;
+ if (!gelf_getshdr(sym_scn, &sym_sh))
+ return 0;
+
+ data->offset = sym->st_value - sym_sh.sh_addr + sym_sh.sh_offset;
+ data->last_bind = curr_bind;
+ return 0;
+}
+
+static int elf_for_each_symbol(Elf *elf, const char *binary_path,
+ int (*fn_match)(Elf *, const char *, const char *, GElf_Sym *, void *),
+ int (*fn_done)(void *),
+ void *data)
+{
+ int i, sh_types[2] = { SHT_DYNSYM, SHT_SYMTAB };
+ int ret = -ENOENT;
/* 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
@@ -10741,7 +10798,6 @@ static long elf_find_func_offset(Elf *elf, const char *binary_path, const char *
size_t nr_syms, strtabidx, idx;
Elf_Data *symbols = NULL;
Elf_Scn *scn = NULL;
- int last_bind = -1;
const char *sname;
GElf_Shdr sh;
@@ -10764,10 +10820,7 @@ static long elf_find_func_offset(Elf *elf, const char *binary_path, const char *
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;
@@ -10779,58 +10832,48 @@ static long elf_find_func_offset(Elf *elf, const char *binary_path, const char *
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;
+ ret = fn_match(elf, binary_path, sname, &sym, data);
+ if (ret < 0)
+ goto out;
+ }
+ if (fn_done(data))
+ break;
+ }
- 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;
- }
- }
+out:
+ return ret;
+}
- /* 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;
+/* 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)
+{
+ struct elf_func_offset data = {
+ .name = name,
+ .last_bind = -1,
+ .name_len = strlen(name),
+ /* Does name specify "@@LIB"? */
+ .is_name_qualified = strstr(name, "@@") != NULL,
+ };
+ bool is_shared_lib;
+ GElf_Ehdr ehdr;
+ long ret;
+ int err;
- ret = sym.st_value - sym_sh.sh_addr + sym_sh.sh_offset;
- last_bind = curr_bind;
- }
- if (ret > 0)
- break;
+ 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;
+
+ err = elf_for_each_symbol(elf, binary_path, single_match, single_done, &data);
+ ret = err < 0 ? (long) err : data.offset;
if (ret > 0) {
pr_debug("elf: symbol address match for '%s' in '%s': 0x%lx\n", name, binary_path,
ret);
--
2.40.0
next prev parent reply other threads:[~2023-04-24 16:05 UTC|newest]
Thread overview: 52+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-04-24 16:04 [RFC/PATCH bpf-next 00/20] bpf: Add multi uprobe link Jiri Olsa
2023-04-24 16:04 ` [RFC/PATCH bpf-next 01/20] " Jiri Olsa
2023-04-24 22:11 ` Alexei Starovoitov
2023-04-25 9:54 ` Jiri Olsa
2023-04-26 19:01 ` Andrii Nakryiko
2023-04-27 13:15 ` Jiri Olsa
2023-04-25 23:56 ` Yonghong Song
2023-04-26 7:37 ` Jiri Olsa
2023-04-26 19:00 ` Andrii Nakryiko
2023-04-27 13:14 ` Jiri Olsa
2023-04-26 19:17 ` Andrii Nakryiko
2023-04-27 13:15 ` Jiri Olsa
2023-04-24 16:04 ` [RFC/PATCH bpf-next 02/20] bpf: Add cookies support for uprobe_multi link Jiri Olsa
2023-04-26 0:03 ` Yonghong Song
2023-04-26 19:13 ` Andrii Nakryiko
2023-04-27 12:58 ` Jiri Olsa
2023-04-24 16:04 ` [RFC/PATCH bpf-next 03/20] bpf: Add bpf_get_func_ip helper support for uprobe link Jiri Olsa
2023-04-26 19:11 ` Andrii Nakryiko
2023-04-27 12:45 ` Jiri Olsa
2023-04-24 16:04 ` [RFC/PATCH bpf-next 04/20] libbpf: Update uapi bpf.h tools header Jiri Olsa
2023-04-26 19:14 ` Andrii Nakryiko
2023-04-27 12:58 ` Jiri Olsa
2023-04-24 16:04 ` [RFC/PATCH bpf-next 05/20] libbpf: Add uprobe_multi attach type and link names Jiri Olsa
2023-04-26 19:14 ` Andrii Nakryiko
2023-04-24 16:04 ` Jiri Olsa [this message]
2023-04-26 19:27 ` [RFC/PATCH bpf-next 06/20] libbpf: Factor elf_for_each_symbol function Andrii Nakryiko
2023-04-27 13:23 ` Jiri Olsa
2023-04-27 22:28 ` Andrii Nakryiko
2023-04-24 16:04 ` [RFC/PATCH bpf-next 07/20] libbpf: Add elf_find_multi_func_offset function Jiri Olsa
2023-04-24 16:04 ` [RFC/PATCH bpf-next 08/20] libbpf: Add elf_find_patern_func_offset function Jiri Olsa
2023-04-26 19:24 ` Andrii Nakryiko
2023-04-27 13:21 ` Jiri Olsa
2023-04-27 22:29 ` Andrii Nakryiko
2023-04-24 16:04 ` [RFC/PATCH bpf-next 09/20] libbpf: Add bpf_link_create support for multi uprobes Jiri Olsa
2023-04-24 16:04 ` [RFC/PATCH bpf-next 10/20] libbpf: Add bpf_program__attach_uprobe_multi_opts function Jiri Olsa
2023-04-24 16:04 ` [RFC/PATCH bpf-next 11/20] libbpf: Add support for uprobe.multi/uprobe.multi program sections Jiri Olsa
2023-04-26 19:31 ` Andrii Nakryiko
2023-04-24 16:04 ` [RFC/PATCH bpf-next 12/20] libbpf: Add uprobe multi link support to bpf_program__attach_usdt Jiri Olsa
2023-04-26 19:32 ` Andrii Nakryiko
2023-04-24 16:04 ` [RFC/PATCH bpf-next 13/20] selftests/bpf: Add uprobe_multi skel test Jiri Olsa
2023-04-24 16:04 ` [RFC/PATCH bpf-next 14/20] selftests/bpf: Add uprobe_multi api test Jiri Olsa
2023-04-24 16:04 ` [RFC/PATCH bpf-next 15/20] selftests/bpf: Add uprobe_multi link test Jiri Olsa
2023-04-24 16:04 ` [RFC/PATCH bpf-next 16/20] selftests/bpf: Add uprobe_multi test program Jiri Olsa
2023-04-24 16:04 ` [RFC/PATCH bpf-next 17/20] selftests/bpf: Add uprobe_multi bench test Jiri Olsa
2023-04-24 16:04 ` [RFC/PATCH bpf-next 18/20] selftests/bpf: Add usdt_multi test program Jiri Olsa
2023-04-24 16:04 ` [RFC/PATCH bpf-next 19/20] selftests/bpf: Add usdt_multi bench test Jiri Olsa
2023-04-24 16:04 ` [RFC/PATCH bpf-next 20/20] selftests/bpf: Add uprobe_multi cookie test Jiri Olsa
2023-04-26 19:09 ` [RFC/PATCH bpf-next 00/20] bpf: Add multi uprobe link Andrii Nakryiko
2023-04-27 12:44 ` Jiri Olsa
2023-04-27 22:24 ` Andrii Nakryiko
2023-04-28 10:55 ` Jiri Olsa
2023-04-28 21:19 ` Andrii Nakryiko
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=20230424160447.2005755-7-jolsa@kernel.org \
--to=jolsa@kernel.org \
--cc=acme@kernel.org \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=haoluo@google.com \
--cc=john.fastabend@gmail.com \
--cc=kafai@fb.com \
--cc=kpsingh@chromium.org \
--cc=sdf@google.com \
--cc=songliubraving@fb.com \
--cc=yhs@fb.com \
/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