|
|
0e5b81 |
From 58a98f76ac95b1bb11920ff2b58206b2364e6b3b Mon Sep 17 00:00:00 2001
|
|
|
0e5b81 |
From: Martin KaFai Lau <kafai@fb.com>
|
|
|
0e5b81 |
Date: Thu, 6 May 2021 13:56:22 -0700
|
|
|
0e5b81 |
Subject: [PATCH] btf: Remove ftrace filter
|
|
|
0e5b81 |
|
|
|
0e5b81 |
BTF is currently generated for functions that are in ftrace list
|
|
|
0e5b81 |
or extern.
|
|
|
0e5b81 |
|
|
|
0e5b81 |
A recent use case also needs BTF generated for functions included in
|
|
|
0e5b81 |
allowlist.
|
|
|
0e5b81 |
|
|
|
0e5b81 |
In particular, the kernel commit:
|
|
|
0e5b81 |
|
|
|
0e5b81 |
e78aea8b2170 ("bpf: tcp: Put some tcp cong functions in allowlist for bpf-tcp-cc")
|
|
|
0e5b81 |
|
|
|
0e5b81 |
allows bpf program to directly call a few tcp cc kernel functions. Those
|
|
|
0e5b81 |
kernel functions are currently allowed only if CONFIG_DYNAMIC_FTRACE
|
|
|
0e5b81 |
is set to ensure they are in the ftrace list but this kconfig dependency
|
|
|
0e5b81 |
is unnecessary.
|
|
|
0e5b81 |
|
|
|
0e5b81 |
Those kernel functions are specified under an ELF section .BTF_ids.
|
|
|
0e5b81 |
There was an earlier attempt [0] to add another filter for the functions in
|
|
|
0e5b81 |
the .BTF_ids section. That discussion concluded that the ftrace filter
|
|
|
0e5b81 |
should be removed instead.
|
|
|
0e5b81 |
|
|
|
0e5b81 |
This patch is to remove the ftrace filter and its related functions.
|
|
|
0e5b81 |
|
|
|
0e5b81 |
Number of BTF FUNC with and without is_ftrace_func():
|
|
|
0e5b81 |
My kconfig in x86: 40643 vs 46225
|
|
|
0e5b81 |
Jiri reported on arm: 25022 vs 55812
|
|
|
0e5b81 |
|
|
|
0e5b81 |
[0]: https://lore.kernel.org/dwarves/20210423213728.3538141-1-kafai@fb.com/
|
|
|
0e5b81 |
|
|
|
0e5b81 |
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
|
|
|
0e5b81 |
Tested-by: Nathan Chancellor <nathan@kernel.org> # build
|
|
|
0e5b81 |
Acked-by: Jiri Olsa <jolsa@kernel.org>
|
|
|
0e5b81 |
Acked-by: Jiri Slaby <jirislaby@kernel.org>
|
|
|
0e5b81 |
Cc: Andrii Nakryiko <andrii@kernel.org>
|
|
|
0e5b81 |
Cc: Jiri Olsa <jolsa@kernel.org>
|
|
|
0e5b81 |
Cc: kernel-team@fb.com
|
|
|
0e5b81 |
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
|
0e5b81 |
---
|
|
|
0e5b81 |
btf_encoder.c | 285 ++------------------------------------------------
|
|
|
0e5b81 |
1 file changed, 7 insertions(+), 278 deletions(-)
|
|
|
0e5b81 |
|
|
|
0e5b81 |
diff --git a/btf_encoder.c b/btf_encoder.c
|
|
|
0e5b81 |
index 80e896961d4e..c711f124b31e 100644
|
|
|
0e5b81 |
--- a/btf_encoder.c
|
|
|
0e5b81 |
+++ b/btf_encoder.c
|
|
|
0e5b81 |
@@ -27,17 +27,8 @@
|
|
|
0e5b81 |
*/
|
|
|
0e5b81 |
#define KSYM_NAME_LEN 128
|
|
|
0e5b81 |
|
|
|
0e5b81 |
-struct funcs_layout {
|
|
|
0e5b81 |
- unsigned long mcount_start;
|
|
|
0e5b81 |
- unsigned long mcount_stop;
|
|
|
0e5b81 |
- unsigned long mcount_sec_idx;
|
|
|
0e5b81 |
-};
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
struct elf_function {
|
|
|
0e5b81 |
const char *name;
|
|
|
0e5b81 |
- unsigned long addr;
|
|
|
0e5b81 |
- unsigned long size;
|
|
|
0e5b81 |
- unsigned long sh_addr;
|
|
|
0e5b81 |
bool generated;
|
|
|
0e5b81 |
};
|
|
|
0e5b81 |
|
|
|
0e5b81 |
@@ -64,12 +55,9 @@ static void delete_functions(void)
|
|
|
0e5b81 |
#define max(x, y) ((x) < (y) ? (y) : (x))
|
|
|
0e5b81 |
#endif
|
|
|
0e5b81 |
|
|
|
0e5b81 |
-static int collect_function(struct btf_elf *btfe, GElf_Sym *sym,
|
|
|
0e5b81 |
- size_t sym_sec_idx)
|
|
|
0e5b81 |
+static int collect_function(struct btf_elf *btfe, GElf_Sym *sym)
|
|
|
0e5b81 |
{
|
|
|
0e5b81 |
struct elf_function *new;
|
|
|
0e5b81 |
- static GElf_Shdr sh;
|
|
|
0e5b81 |
- static size_t last_idx;
|
|
|
0e5b81 |
const char *name;
|
|
|
0e5b81 |
|
|
|
0e5b81 |
if (elf_sym__type(sym) != STT_FUNC)
|
|
|
0e5b81 |
@@ -91,257 +79,12 @@ static int collect_function(struct btf_elf *btfe, GElf_Sym *sym,
|
|
|
0e5b81 |
functions = new;
|
|
|
0e5b81 |
}
|
|
|
0e5b81 |
|
|
|
0e5b81 |
- if (sym_sec_idx != last_idx) {
|
|
|
0e5b81 |
- if (!elf_section_by_idx(btfe->elf, &sh, sym_sec_idx))
|
|
|
0e5b81 |
- return 0;
|
|
|
0e5b81 |
- last_idx = sym_sec_idx;
|
|
|
0e5b81 |
- }
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
functions[functions_cnt].name = name;
|
|
|
0e5b81 |
- functions[functions_cnt].addr = elf_sym__value(sym);
|
|
|
0e5b81 |
- functions[functions_cnt].size = elf_sym__size(sym);
|
|
|
0e5b81 |
- functions[functions_cnt].sh_addr = sh.sh_addr;
|
|
|
0e5b81 |
functions[functions_cnt].generated = false;
|
|
|
0e5b81 |
functions_cnt++;
|
|
|
0e5b81 |
return 0;
|
|
|
0e5b81 |
}
|
|
|
0e5b81 |
|
|
|
0e5b81 |
-static int addrs_cmp(const void *_a, const void *_b)
|
|
|
0e5b81 |
-{
|
|
|
0e5b81 |
- const __u64 *a = _a;
|
|
|
0e5b81 |
- const __u64 *b = _b;
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- if (*a == *b)
|
|
|
0e5b81 |
- return 0;
|
|
|
0e5b81 |
- return *a < *b ? -1 : 1;
|
|
|
0e5b81 |
-}
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
-static int get_vmlinux_addrs(struct btf_elf *btfe, struct funcs_layout *fl,
|
|
|
0e5b81 |
- __u64 **paddrs, __u64 *pcount)
|
|
|
0e5b81 |
-{
|
|
|
0e5b81 |
- __u64 *addrs, count, offset;
|
|
|
0e5b81 |
- unsigned int addr_size, i;
|
|
|
0e5b81 |
- Elf_Data *data;
|
|
|
0e5b81 |
- GElf_Shdr shdr;
|
|
|
0e5b81 |
- Elf_Scn *sec;
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- /* Initialize for the sake of all error paths below. */
|
|
|
0e5b81 |
- *paddrs = NULL;
|
|
|
0e5b81 |
- *pcount = 0;
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- if (!fl->mcount_start || !fl->mcount_stop)
|
|
|
0e5b81 |
- return 0;
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- /*
|
|
|
0e5b81 |
- * Find mcount addressed marked by __start_mcount_loc
|
|
|
0e5b81 |
- * and __stop_mcount_loc symbols and load them into
|
|
|
0e5b81 |
- * sorted array.
|
|
|
0e5b81 |
- */
|
|
|
0e5b81 |
- sec = elf_getscn(btfe->elf, fl->mcount_sec_idx);
|
|
|
0e5b81 |
- if (!sec || !gelf_getshdr(sec, &shdr)) {
|
|
|
0e5b81 |
- fprintf(stderr, "Failed to get section(%lu) header.\n",
|
|
|
0e5b81 |
- fl->mcount_sec_idx);
|
|
|
0e5b81 |
- return -1;
|
|
|
0e5b81 |
- }
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- /* Get address size from processed file's ELF class. */
|
|
|
0e5b81 |
- addr_size = gelf_getclass(btfe->elf) == ELFCLASS32 ? 4 : 8;
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- offset = fl->mcount_start - shdr.sh_addr;
|
|
|
0e5b81 |
- count = (fl->mcount_stop - fl->mcount_start) / addr_size;
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- data = elf_getdata(sec, 0);
|
|
|
0e5b81 |
- if (!data) {
|
|
|
0e5b81 |
- fprintf(stderr, "Failed to get section(%lu) data.\n",
|
|
|
0e5b81 |
- fl->mcount_sec_idx);
|
|
|
0e5b81 |
- return -1;
|
|
|
0e5b81 |
- }
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- addrs = malloc(count * sizeof(addrs[0]));
|
|
|
0e5b81 |
- if (!addrs) {
|
|
|
0e5b81 |
- fprintf(stderr, "Failed to allocate memory for ftrace addresses.\n");
|
|
|
0e5b81 |
- return -1;
|
|
|
0e5b81 |
- }
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- if (addr_size == sizeof(__u64)) {
|
|
|
0e5b81 |
- memcpy(addrs, data->d_buf + offset, count * addr_size);
|
|
|
0e5b81 |
- } else {
|
|
|
0e5b81 |
- for (i = 0; i < count; i++)
|
|
|
0e5b81 |
- addrs[i] = (__u64) *((__u32 *) (data->d_buf + offset + i * addr_size));
|
|
|
0e5b81 |
- }
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- *paddrs = addrs;
|
|
|
0e5b81 |
- *pcount = count;
|
|
|
0e5b81 |
- return 0;
|
|
|
0e5b81 |
-}
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
-static int
|
|
|
0e5b81 |
-get_kmod_addrs(struct btf_elf *btfe, __u64 **paddrs, __u64 *pcount)
|
|
|
0e5b81 |
-{
|
|
|
0e5b81 |
- __u64 *addrs, count;
|
|
|
0e5b81 |
- unsigned int addr_size, i;
|
|
|
0e5b81 |
- GElf_Shdr shdr_mcount;
|
|
|
0e5b81 |
- Elf_Data *data;
|
|
|
0e5b81 |
- Elf_Scn *sec;
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- /* Initialize for the sake of all error paths below. */
|
|
|
0e5b81 |
- *paddrs = NULL;
|
|
|
0e5b81 |
- *pcount = 0;
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- /* get __mcount_loc */
|
|
|
0e5b81 |
- sec = elf_section_by_name(btfe->elf, &btfe->ehdr, &shdr_mcount,
|
|
|
0e5b81 |
- "__mcount_loc", NULL);
|
|
|
0e5b81 |
- if (!sec) {
|
|
|
0e5b81 |
- if (btf_elf__verbose) {
|
|
|
0e5b81 |
- printf("%s: '%s' doesn't have __mcount_loc section\n", __func__,
|
|
|
0e5b81 |
- btfe->filename);
|
|
|
0e5b81 |
- }
|
|
|
0e5b81 |
- return 0;
|
|
|
0e5b81 |
- }
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- data = elf_getdata(sec, NULL);
|
|
|
0e5b81 |
- if (!data) {
|
|
|
0e5b81 |
- fprintf(stderr, "Failed to data for __mcount_loc section.\n");
|
|
|
0e5b81 |
- return -1;
|
|
|
0e5b81 |
- }
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- /* Get address size from processed file's ELF class. */
|
|
|
0e5b81 |
- addr_size = gelf_getclass(btfe->elf) == ELFCLASS32 ? 4 : 8;
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- count = data->d_size / addr_size;
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- addrs = malloc(count * sizeof(addrs[0]));
|
|
|
0e5b81 |
- if (!addrs) {
|
|
|
0e5b81 |
- fprintf(stderr, "Failed to allocate memory for ftrace addresses.\n");
|
|
|
0e5b81 |
- return -1;
|
|
|
0e5b81 |
- }
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- if (addr_size == sizeof(__u64)) {
|
|
|
0e5b81 |
- memcpy(addrs, data->d_buf, count * addr_size);
|
|
|
0e5b81 |
- } else {
|
|
|
0e5b81 |
- for (i = 0; i < count; i++)
|
|
|
0e5b81 |
- addrs[i] = (__u64) *((__u32 *) (data->d_buf + i * addr_size));
|
|
|
0e5b81 |
- }
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- /*
|
|
|
0e5b81 |
- * We get Elf object from dwfl_module_getelf function,
|
|
|
0e5b81 |
- * which performs all possible relocations, including
|
|
|
0e5b81 |
- * __mcount_loc section.
|
|
|
0e5b81 |
- *
|
|
|
0e5b81 |
- * So addrs array now contains relocated values, which
|
|
|
0e5b81 |
- * we need take into account when we compare them to
|
|
|
0e5b81 |
- * functions values, see comment in setup_functions
|
|
|
0e5b81 |
- * function.
|
|
|
0e5b81 |
- */
|
|
|
0e5b81 |
- *paddrs = addrs;
|
|
|
0e5b81 |
- *pcount = count;
|
|
|
0e5b81 |
- return 0;
|
|
|
0e5b81 |
-}
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
-static int is_ftrace_func(struct elf_function *func, __u64 *addrs, __u64 count)
|
|
|
0e5b81 |
-{
|
|
|
0e5b81 |
- __u64 start = func->addr;
|
|
|
0e5b81 |
- __u64 addr, end = func->addr + func->size;
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- /*
|
|
|
0e5b81 |
- * The invariant here is addr[r] that is the smallest address
|
|
|
0e5b81 |
- * that is >= than function start addr. Except the corner case
|
|
|
0e5b81 |
- * where there is no such r, but for that we have a final check
|
|
|
0e5b81 |
- * in the return.
|
|
|
0e5b81 |
- */
|
|
|
0e5b81 |
- size_t l = 0, r = count - 1, m;
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- /* make sure we don't use invalid r */
|
|
|
0e5b81 |
- if (count == 0)
|
|
|
0e5b81 |
- return false;
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- while (l < r) {
|
|
|
0e5b81 |
- m = l + (r - l) / 2;
|
|
|
0e5b81 |
- addr = addrs[m];
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- if (addr >= start) {
|
|
|
0e5b81 |
- /* we satisfy invariant, so tighten r */
|
|
|
0e5b81 |
- r = m;
|
|
|
0e5b81 |
- } else {
|
|
|
0e5b81 |
- /* m is not good enough as l, maybe m + 1 will be */
|
|
|
0e5b81 |
- l = m + 1;
|
|
|
0e5b81 |
- }
|
|
|
0e5b81 |
- }
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- return start <= addrs[r] && addrs[r] < end;
|
|
|
0e5b81 |
-}
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
-static int setup_functions(struct btf_elf *btfe, struct funcs_layout *fl)
|
|
|
0e5b81 |
-{
|
|
|
0e5b81 |
- __u64 *addrs, count, i;
|
|
|
0e5b81 |
- int functions_valid = 0;
|
|
|
0e5b81 |
- bool kmod = false;
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- /*
|
|
|
0e5b81 |
- * Check if we are processing vmlinux image and
|
|
|
0e5b81 |
- * get mcount data if it's detected.
|
|
|
0e5b81 |
- */
|
|
|
0e5b81 |
- if (get_vmlinux_addrs(btfe, fl, &addrs, &count))
|
|
|
0e5b81 |
- return -1;
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- /*
|
|
|
0e5b81 |
- * Check if we are processing kernel module and
|
|
|
0e5b81 |
- * get mcount data if it's detected.
|
|
|
0e5b81 |
- */
|
|
|
0e5b81 |
- if (!addrs) {
|
|
|
0e5b81 |
- if (get_kmod_addrs(btfe, &addrs, &count))
|
|
|
0e5b81 |
- return -1;
|
|
|
0e5b81 |
- kmod = true;
|
|
|
0e5b81 |
- }
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- if (!addrs) {
|
|
|
0e5b81 |
- if (btf_elf__verbose)
|
|
|
0e5b81 |
- printf("ftrace symbols not detected, falling back to DWARF data\n");
|
|
|
0e5b81 |
- delete_functions();
|
|
|
0e5b81 |
- return 0;
|
|
|
0e5b81 |
- }
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- qsort(addrs, count, sizeof(addrs[0]), addrs_cmp);
|
|
|
0e5b81 |
- qsort(functions, functions_cnt, sizeof(functions[0]), functions_cmp);
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- /*
|
|
|
0e5b81 |
- * Let's got through all collected functions and filter
|
|
|
0e5b81 |
- * out those that are not in ftrace.
|
|
|
0e5b81 |
- */
|
|
|
0e5b81 |
- for (i = 0; i < functions_cnt; i++) {
|
|
|
0e5b81 |
- struct elf_function *func = &functions[i];
|
|
|
0e5b81 |
- /*
|
|
|
0e5b81 |
- * For vmlinux image both addrs[x] and functions[x]::addr
|
|
|
0e5b81 |
- * values are final address and are comparable.
|
|
|
0e5b81 |
- *
|
|
|
0e5b81 |
- * For kernel module addrs[x] is final address, but
|
|
|
0e5b81 |
- * functions[x]::addr is relative address within section
|
|
|
0e5b81 |
- * and needs to be relocated by adding sh_addr.
|
|
|
0e5b81 |
- */
|
|
|
0e5b81 |
- if (kmod)
|
|
|
0e5b81 |
- func->addr += func->sh_addr;
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- /* Make sure function is within ftrace addresses. */
|
|
|
0e5b81 |
- if (is_ftrace_func(func, addrs, count)) {
|
|
|
0e5b81 |
- /*
|
|
|
0e5b81 |
- * We iterate over sorted array, so we can easily skip
|
|
|
0e5b81 |
- * not valid item and move following valid field into
|
|
|
0e5b81 |
- * its place, and still keep the 'new' array sorted.
|
|
|
0e5b81 |
- */
|
|
|
0e5b81 |
- if (i != functions_valid)
|
|
|
0e5b81 |
- functions[functions_valid] = functions[i];
|
|
|
0e5b81 |
- functions_valid++;
|
|
|
0e5b81 |
- }
|
|
|
0e5b81 |
- }
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- functions_cnt = functions_valid;
|
|
|
0e5b81 |
- free(addrs);
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- if (btf_elf__verbose)
|
|
|
0e5b81 |
- printf("Found %d functions!\n", functions_cnt);
|
|
|
0e5b81 |
- return 0;
|
|
|
0e5b81 |
-}
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
static struct elf_function *find_function(const struct btf_elf *btfe,
|
|
|
0e5b81 |
const char *name)
|
|
|
0e5b81 |
{
|
|
|
0e5b81 |
@@ -620,23 +363,8 @@ static int collect_percpu_var(struct btf_elf *btfe, GElf_Sym *sym,
|
|
|
0e5b81 |
return 0;
|
|
|
0e5b81 |
}
|
|
|
0e5b81 |
|
|
|
0e5b81 |
-static void collect_symbol(GElf_Sym *sym, struct funcs_layout *fl,
|
|
|
0e5b81 |
- size_t sym_sec_idx)
|
|
|
0e5b81 |
-{
|
|
|
0e5b81 |
- if (!fl->mcount_start &&
|
|
|
0e5b81 |
- !strcmp("__start_mcount_loc", elf_sym__name(sym, btfe->symtab))) {
|
|
|
0e5b81 |
- fl->mcount_start = sym->st_value;
|
|
|
0e5b81 |
- fl->mcount_sec_idx = sym_sec_idx;
|
|
|
0e5b81 |
- }
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
- if (!fl->mcount_stop &&
|
|
|
0e5b81 |
- !strcmp("__stop_mcount_loc", elf_sym__name(sym, btfe->symtab)))
|
|
|
0e5b81 |
- fl->mcount_stop = sym->st_value;
|
|
|
0e5b81 |
-}
|
|
|
0e5b81 |
-
|
|
|
0e5b81 |
static int collect_symbols(struct btf_elf *btfe, bool collect_percpu_vars)
|
|
|
0e5b81 |
{
|
|
|
0e5b81 |
- struct funcs_layout fl = { };
|
|
|
0e5b81 |
Elf32_Word sym_sec_idx;
|
|
|
0e5b81 |
uint32_t core_id;
|
|
|
0e5b81 |
GElf_Sym sym;
|
|
|
0e5b81 |
@@ -648,9 +376,8 @@ static int collect_symbols(struct btf_elf *btfe, bool collect_percpu_vars)
|
|
|
0e5b81 |
elf_symtab__for_each_symbol_index(btfe->symtab, core_id, sym, sym_sec_idx) {
|
|
|
0e5b81 |
if (collect_percpu_vars && collect_percpu_var(btfe, &sym, sym_sec_idx))
|
|
|
0e5b81 |
return -1;
|
|
|
0e5b81 |
- if (collect_function(btfe, &sym, sym_sec_idx))
|
|
|
0e5b81 |
+ if (collect_function(btfe, &sym))
|
|
|
0e5b81 |
return -1;
|
|
|
0e5b81 |
- collect_symbol(&sym, &fl, sym_sec_idx);
|
|
|
0e5b81 |
}
|
|
|
0e5b81 |
|
|
|
0e5b81 |
if (collect_percpu_vars) {
|
|
|
0e5b81 |
@@ -661,9 +388,11 @@ static int collect_symbols(struct btf_elf *btfe, bool collect_percpu_vars)
|
|
|
0e5b81 |
printf("Found %d per-CPU variables!\n", percpu_var_cnt);
|
|
|
0e5b81 |
}
|
|
|
0e5b81 |
|
|
|
0e5b81 |
- if (functions_cnt && setup_functions(btfe, &fl)) {
|
|
|
0e5b81 |
- fprintf(stderr, "Failed to filter DWARF functions\n");
|
|
|
0e5b81 |
- return -1;
|
|
|
0e5b81 |
+ if (functions_cnt) {
|
|
|
0e5b81 |
+ qsort(functions, functions_cnt, sizeof(functions[0]),
|
|
|
0e5b81 |
+ functions_cmp);
|
|
|
0e5b81 |
+ if (btf_elf__verbose)
|
|
|
0e5b81 |
+ printf("Found %d functions!\n", functions_cnt);
|
|
|
0e5b81 |
}
|
|
|
0e5b81 |
|
|
|
0e5b81 |
return 0;
|
|
|
0e5b81 |
--
|
|
|
0e5b81 |
2.31.1
|
|
|
0e5b81 |
|