Re: [PATCH v2 dwarves] btf: Remove ftrace filter

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, May 06, 2021 at 01:56:22PM -0700, Martin KaFai Lau wrote:
> BTF is currently generated for functions that are in ftrace list
> or extern.
> 
> A recent use case also needs BTF generated for functions included in
> allowlist.  In particular, the kernel
> commit e78aea8b2170 ("bpf: tcp: Put some tcp cong functions in allowlist for bpf-tcp-cc")
> allows bpf program to directly call a few tcp cc kernel functions. Those
> kernel functions are currently allowed only if CONFIG_DYNAMIC_FTRACE
> is set to ensure they are in the ftrace list but this kconfig dependency
> is unnecessary.
> 
> Those kernel functions are specified under an ELF section .BTF_ids.
> There was an earlier attempt [0] to add another filter for the functions in
> the .BTF_ids section.  That discussion concluded that the ftrace filter
> should be removed instead.
> 
> This patch is to remove the ftrace filter and its related functions.
> 
> Number of BTF FUNC with and without is_ftrace_func():
> My kconfig in x86: 40643 vs 46225
> Jiri reported on arm: 25022 vs 55812
> 
> [0]: https://lore.kernel.org/dwarves/20210423213728.3538141-1-kafai@xxxxxx/
> 
> Cc: Andrii Nakryiko <andrii@xxxxxxxxxx>
> Cc: Jiri Olsa <jolsa@xxxxxxxxxx>
> Signed-off-by: Martin KaFai Lau <kafai@xxxxxx>

This fixes an issue with Fedora's s390x config that CKI noticed:

https://groups.google.com/g/clang-built-linux/c/IzthpckBJvc/m/MPWGDmXiAwAJ

Tested-by: Nathan Chancellor <nathan@xxxxxxxxxx> # build

> ---
> v2: Remove sym_sec_idx, last_idx, and sh. (Jiri Olsa)
> 
>  btf_encoder.c | 285 ++------------------------------------------------
>  1 file changed, 7 insertions(+), 278 deletions(-)
> 
> diff --git a/btf_encoder.c b/btf_encoder.c
> index 80e896961d4e..c711f124b31e 100644
> --- a/btf_encoder.c
> +++ b/btf_encoder.c
> @@ -27,17 +27,8 @@
>   */
>  #define KSYM_NAME_LEN 128
>  
> -struct funcs_layout {
> -	unsigned long mcount_start;
> -	unsigned long mcount_stop;
> -	unsigned long mcount_sec_idx;
> -};
> -
>  struct elf_function {
>  	const char	*name;
> -	unsigned long	 addr;
> -	unsigned long	 size;
> -	unsigned long	 sh_addr;
>  	bool		 generated;
>  };
>  
> @@ -64,12 +55,9 @@ static void delete_functions(void)
>  #define max(x, y) ((x) < (y) ? (y) : (x))
>  #endif
>  
> -static int collect_function(struct btf_elf *btfe, GElf_Sym *sym,
> -			    size_t sym_sec_idx)
> +static int collect_function(struct btf_elf *btfe, GElf_Sym *sym)
>  {
>  	struct elf_function *new;
> -	static GElf_Shdr sh;
> -	static size_t last_idx;
>  	const char *name;
>  
>  	if (elf_sym__type(sym) != STT_FUNC)
> @@ -91,257 +79,12 @@ static int collect_function(struct btf_elf *btfe, GElf_Sym *sym,
>  		functions = new;
>  	}
>  
> -	if (sym_sec_idx != last_idx) {
> -		if (!elf_section_by_idx(btfe->elf, &sh, sym_sec_idx))
> -			return 0;
> -		last_idx = sym_sec_idx;
> -	}
> -
>  	functions[functions_cnt].name = name;
> -	functions[functions_cnt].addr = elf_sym__value(sym);
> -	functions[functions_cnt].size = elf_sym__size(sym);
> -	functions[functions_cnt].sh_addr = sh.sh_addr;
>  	functions[functions_cnt].generated = false;
>  	functions_cnt++;
>  	return 0;
>  }
>  
> -static int addrs_cmp(const void *_a, const void *_b)
> -{
> -	const __u64 *a = _a;
> -	const __u64 *b = _b;
> -
> -	if (*a == *b)
> -		return 0;
> -	return *a < *b ? -1 : 1;
> -}
> -
> -static int get_vmlinux_addrs(struct btf_elf *btfe, struct funcs_layout *fl,
> -			     __u64 **paddrs, __u64 *pcount)
> -{
> -	__u64 *addrs, count, offset;
> -	unsigned int addr_size, i;
> -	Elf_Data *data;
> -	GElf_Shdr shdr;
> -	Elf_Scn *sec;
> -
> -	/* Initialize for the sake of all error paths below. */
> -	*paddrs = NULL;
> -	*pcount = 0;
> -
> -	if (!fl->mcount_start || !fl->mcount_stop)
> -		return 0;
> -
> -	/*
> -	 * Find mcount addressed marked by __start_mcount_loc
> -	 * and __stop_mcount_loc symbols and load them into
> -	 * sorted array.
> -	 */
> -	sec = elf_getscn(btfe->elf, fl->mcount_sec_idx);
> -	if (!sec || !gelf_getshdr(sec, &shdr)) {
> -		fprintf(stderr, "Failed to get section(%lu) header.\n",
> -			fl->mcount_sec_idx);
> -		return -1;
> -	}
> -
> -	/* Get address size from processed file's ELF class. */
> -	addr_size = gelf_getclass(btfe->elf) == ELFCLASS32 ? 4 : 8;
> -
> -	offset = fl->mcount_start - shdr.sh_addr;
> -	count  = (fl->mcount_stop - fl->mcount_start) / addr_size;
> -
> -	data = elf_getdata(sec, 0);
> -	if (!data) {
> -		fprintf(stderr, "Failed to get section(%lu) data.\n",
> -			fl->mcount_sec_idx);
> -		return -1;
> -	}
> -
> -	addrs = malloc(count * sizeof(addrs[0]));
> -	if (!addrs) {
> -		fprintf(stderr, "Failed to allocate memory for ftrace addresses.\n");
> -		return -1;
> -	}
> -
> -	if (addr_size == sizeof(__u64)) {
> -		memcpy(addrs, data->d_buf + offset, count * addr_size);
> -	} else {
> -		for (i = 0; i < count; i++)
> -			addrs[i] = (__u64) *((__u32 *) (data->d_buf + offset + i * addr_size));
> -	}
> -
> -	*paddrs = addrs;
> -	*pcount = count;
> -	return 0;
> -}
> -
> -static int
> -get_kmod_addrs(struct btf_elf *btfe, __u64 **paddrs, __u64 *pcount)
> -{
> -	__u64 *addrs, count;
> -	unsigned int addr_size, i;
> -	GElf_Shdr shdr_mcount;
> -	Elf_Data *data;
> -	Elf_Scn *sec;
> -
> -	/* Initialize for the sake of all error paths below. */
> -	*paddrs = NULL;
> -	*pcount = 0;
> -
> -	/* get __mcount_loc */
> -	sec = elf_section_by_name(btfe->elf, &btfe->ehdr, &shdr_mcount,
> -				  "__mcount_loc", NULL);
> -	if (!sec) {
> -		if (btf_elf__verbose) {
> -			printf("%s: '%s' doesn't have __mcount_loc section\n", __func__,
> -			       btfe->filename);
> -		}
> -		return 0;
> -	}
> -
> -	data = elf_getdata(sec, NULL);
> -	if (!data) {
> -		fprintf(stderr, "Failed to data for __mcount_loc section.\n");
> -		return -1;
> -	}
> -
> -	/* Get address size from processed file's ELF class. */
> -	addr_size = gelf_getclass(btfe->elf) == ELFCLASS32 ? 4 : 8;
> -
> -	count = data->d_size / addr_size;
> -
> -	addrs = malloc(count * sizeof(addrs[0]));
> -	if (!addrs) {
> -		fprintf(stderr, "Failed to allocate memory for ftrace addresses.\n");
> -		return -1;
> -	}
> -
> -	if (addr_size == sizeof(__u64)) {
> -		memcpy(addrs, data->d_buf, count * addr_size);
> -	} else {
> -		for (i = 0; i < count; i++)
> -			addrs[i] = (__u64) *((__u32 *) (data->d_buf + i * addr_size));
> -	}
> -
> -	/*
> -	 * We get Elf object from dwfl_module_getelf function,
> -	 * which performs all possible relocations, including
> -	 * __mcount_loc section.
> -	 *
> -	 * So addrs array now contains relocated values, which
> -	 * we need take into account when we compare them to
> -	 * functions values, see comment in setup_functions
> -	 * function.
> -	 */
> -	*paddrs = addrs;
> -	*pcount = count;
> -	return 0;
> -}
> -
> -static int is_ftrace_func(struct elf_function *func, __u64 *addrs, __u64 count)
> -{
> -	__u64 start = func->addr;
> -	__u64 addr, end = func->addr + func->size;
> -
> -	/*
> -	 * The invariant here is addr[r] that is the smallest address
> -	 * that is >= than function start addr. Except the corner case
> -	 * where there is no such r, but for that we have a final check
> -	 * in the return.
> -	 */
> -	size_t l = 0, r = count - 1, m;
> -
> -	/* make sure we don't use invalid r */
> -	if (count == 0)
> -		return false;
> -
> -	while (l < r) {
> -		m = l + (r - l) / 2;
> -		addr = addrs[m];
> -
> -		if (addr >= start) {
> -			/* we satisfy invariant, so tighten r */
> -			r = m;
> -		} else {
> -			/* m is not good enough as l, maybe m + 1 will be */
> -			l = m + 1;
> -		}
> -	}
> -
> -	return start <= addrs[r] && addrs[r] < end;
> -}
> -
> -static int setup_functions(struct btf_elf *btfe, struct funcs_layout *fl)
> -{
> -	__u64 *addrs, count, i;
> -	int functions_valid = 0;
> -	bool kmod = false;
> -
> -	/*
> -	 * Check if we are processing vmlinux image and
> -	 * get mcount data if it's detected.
> -	 */
> -	if (get_vmlinux_addrs(btfe, fl, &addrs, &count))
> -		return -1;
> -
> -	/*
> -	 * Check if we are processing kernel module and
> -	 * get mcount data if it's detected.
> -	 */
> -	if (!addrs) {
> -		if (get_kmod_addrs(btfe, &addrs, &count))
> -			return -1;
> -		kmod = true;
> -	}
> -
> -	if (!addrs) {
> -		if (btf_elf__verbose)
> -			printf("ftrace symbols not detected, falling back to DWARF data\n");
> -		delete_functions();
> -		return 0;
> -	}
> -
> -	qsort(addrs, count, sizeof(addrs[0]), addrs_cmp);
> -	qsort(functions, functions_cnt, sizeof(functions[0]), functions_cmp);
> -
> -	/*
> -	 * Let's got through all collected functions and filter
> -	 * out those that are not in ftrace.
> -	 */
> -	for (i = 0; i < functions_cnt; i++) {
> -		struct elf_function *func = &functions[i];
> -		/*
> -		 * For vmlinux image both addrs[x] and functions[x]::addr
> -		 * values are final address and are comparable.
> -		 *
> -		 * For kernel module addrs[x] is final address, but
> -		 * functions[x]::addr is relative address within section
> -		 * and needs to be relocated by adding sh_addr.
> -		 */
> -		if (kmod)
> -			func->addr += func->sh_addr;
> -
> -		/* Make sure function is within ftrace addresses. */
> -		if (is_ftrace_func(func, addrs, count)) {
> -			/*
> -			 * We iterate over sorted array, so we can easily skip
> -			 * not valid item and move following valid field into
> -			 * its place, and still keep the 'new' array sorted.
> -			 */
> -			if (i != functions_valid)
> -				functions[functions_valid] = functions[i];
> -			functions_valid++;
> -		}
> -	}
> -
> -	functions_cnt = functions_valid;
> -	free(addrs);
> -
> -	if (btf_elf__verbose)
> -		printf("Found %d functions!\n", functions_cnt);
> -	return 0;
> -}
> -
>  static struct elf_function *find_function(const struct btf_elf *btfe,
>  					  const char *name)
>  {
> @@ -620,23 +363,8 @@ static int collect_percpu_var(struct btf_elf *btfe, GElf_Sym *sym,
>  	return 0;
>  }
>  
> -static void collect_symbol(GElf_Sym *sym, struct funcs_layout *fl,
> -			   size_t sym_sec_idx)
> -{
> -	if (!fl->mcount_start &&
> -	    !strcmp("__start_mcount_loc", elf_sym__name(sym, btfe->symtab))) {
> -		fl->mcount_start = sym->st_value;
> -		fl->mcount_sec_idx = sym_sec_idx;
> -	}
> -
> -	if (!fl->mcount_stop &&
> -	    !strcmp("__stop_mcount_loc", elf_sym__name(sym, btfe->symtab)))
> -		fl->mcount_stop = sym->st_value;
> -}
> -
>  static int collect_symbols(struct btf_elf *btfe, bool collect_percpu_vars)
>  {
> -	struct funcs_layout fl = { };
>  	Elf32_Word sym_sec_idx;
>  	uint32_t core_id;
>  	GElf_Sym sym;
> @@ -648,9 +376,8 @@ static int collect_symbols(struct btf_elf *btfe, bool collect_percpu_vars)
>  	elf_symtab__for_each_symbol_index(btfe->symtab, core_id, sym, sym_sec_idx) {
>  		if (collect_percpu_vars && collect_percpu_var(btfe, &sym, sym_sec_idx))
>  			return -1;
> -		if (collect_function(btfe, &sym, sym_sec_idx))
> +		if (collect_function(btfe, &sym))
>  			return -1;
> -		collect_symbol(&sym, &fl, sym_sec_idx);
>  	}
>  
>  	if (collect_percpu_vars) {
> @@ -661,9 +388,11 @@ static int collect_symbols(struct btf_elf *btfe, bool collect_percpu_vars)
>  			printf("Found %d per-CPU variables!\n", percpu_var_cnt);
>  	}
>  
> -	if (functions_cnt && setup_functions(btfe, &fl)) {
> -		fprintf(stderr, "Failed to filter DWARF functions\n");
> -		return -1;
> +	if (functions_cnt) {
> +		qsort(functions, functions_cnt, sizeof(functions[0]),
> +		      functions_cmp);
> +		if (btf_elf__verbose)
> +			printf("Found %d functions!\n", functions_cnt);
>  	}
>  
>  	return 0;
> -- 
> 2.30.2
> 



[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux