Commit 90db26e6 authored by Alan Maguire's avatar Alan Maguire Committed by Andrii Nakryiko
Browse files

libbpf: Improve string parsing for uprobe auto-attach



For uprobe auto-attach, the parsing can be simplified for the SEC()
name to a single sscanf(); the return value of the sscanf can then
be used to distinguish between sections that simply specify
"u[ret]probe" (and thus cannot auto-attach), those that specify
"u[ret]probe/binary_path:function+offset" etc.

Suggested-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Signed-off-by: default avatarAlan Maguire <alan.maguire@oracle.com>
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/1649245431-29956-3-git-send-email-alan.maguire@oracle.com
parent a1c9d61b
Loading
Loading
Loading
Loading
+33 −48
Original line number Diff line number Diff line
@@ -10913,60 +10913,45 @@ bpf_program__attach_uprobe_opts(const struct bpf_program *prog, pid_t pid,
static int attach_uprobe(const struct bpf_program *prog, long cookie, struct bpf_link **link)
{
	DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, opts);
	char *func, *probe_name, *func_end;
	char *func_name, binary_path[512];
	unsigned long long raw_offset;
	size_t offset = 0;
	int n;
	char *probe_type = NULL, *binary_path = NULL, *func_name = NULL;
	int n, ret = -EINVAL;
	long offset = 0;

	*link = NULL;

	opts.retprobe = str_has_pfx(prog->sec_name, "uretprobe");
	if (opts.retprobe)
		probe_name = prog->sec_name + sizeof("uretprobe") - 1;
	else
		probe_name = prog->sec_name + sizeof("uprobe") - 1;
	if (probe_name[0] == '/')
		probe_name++;

	n = sscanf(prog->sec_name, "%m[^/]/%m[^:]:%m[a-zA-Z0-9_.]+%li",
		   &probe_type, &binary_path, &func_name, &offset);
	switch (n) {
	case 1:
		/* handle SEC("u[ret]probe") - format is valid, but auto-attach is impossible. */
	if (strlen(probe_name) == 0)
		return 0;

	snprintf(binary_path, sizeof(binary_path), "%s", probe_name);
	/* ':' should be prior to function+offset */
	func_name = strrchr(binary_path, ':');
	if (!func_name) {
		pr_warn("section '%s' missing ':function[+offset]' specification\n",
			prog->sec_name);
		return -EINVAL;
	}
	func_name[0] = '\0';
	func_name++;
	n = sscanf(func_name, "%m[a-zA-Z0-9_.]+%li", &func, &offset);
	if (n < 1) {
		pr_warn("uprobe name '%s' is invalid\n", func_name);
		return -EINVAL;
	}
		ret = 0;
		break;
	case 2:
		pr_warn("prog '%s': section '%s' missing ':function[+offset]' specification\n",
			prog->name, prog->sec_name);
		break;
	case 3:
	case 4:
		opts.retprobe = strcmp(probe_type, "uretprobe") == 0;
		if (opts.retprobe && offset != 0) {
		free(func);
		pr_warn("uretprobes do not support offset specification\n");
		return -EINVAL;
			pr_warn("prog '%s': uretprobes do not support offset specification\n",
				prog->name);
			break;
		}

	/* Is func a raw address? */
	errno = 0;
	raw_offset = strtoull(func, &func_end, 0);
	if (!errno && !*func_end) {
		free(func);
		func = NULL;
		offset = (size_t)raw_offset;
		opts.func_name = func_name;
		*link = bpf_program__attach_uprobe_opts(prog, -1, binary_path, offset, &opts);
		ret = libbpf_get_error(*link);
		break;
	default:
		pr_warn("prog '%s': invalid format of section definition '%s'\n", prog->name,
			prog->sec_name);
		break;
	}
	opts.func_name = func;
	free(probe_type);
	free(binary_path);
	free(func_name);

	*link = bpf_program__attach_uprobe_opts(prog, -1, binary_path, offset, &opts);
	free(func);
	return libbpf_get_error(*link);
	return ret;
}

struct bpf_link *bpf_program__attach_uprobe(const struct bpf_program *prog,