Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d8b5297f authored by Thomas Gleixner's avatar Thomas Gleixner
Browse files

Merge tag 'perf-core-for-mingo-5.1-20190321' of...

Merge tag 'perf-core-for-mingo-5.1-20190321' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux

 into perf/urgent

Pull perf/core improvements and fixes from Arnaldo:

BPF:

  Song Liu:

  - Add support for annotating BPF programs, using the PERF_RECORD_BPF_EVENT
    and PERF_RECORD_KSYMBOL recently added to the kernel and plugging
    binutils's libopcodes disassembly of BPF programs with the existing
    annotation interfaces in 'perf annotate', 'perf report' and 'perf top'
    various output formats (--stdio, --stdio2, --tui).

perf list:

  Andi Kleen:

  - Filter metrics when using substring search.

perf record:

  Andi Kleen:

  - Allow to limit number of reported perf.data files

  - Clarify help for --switch-output.

perf report:

  Andi Kleen

  - Indicate JITed code better.

  - Show all sort keys in help output.

perf script:

  Andi Kleen:

  - Support relative time.

perf stat:

  Andi Kleen:

  - Improve scaling.

General:

  Changbin Du:

  - Fix some mostly error path memory and reference count leaks found
    using gcc's ASan and UBSan.

Vendor events:

  Mamatha Inamdar:

  - Remove P8 HW events which are not supported.

Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parents 4a98be82 f8dfeae0
Loading
Loading
Loading
Loading
+59 −207
Original line number Diff line number Diff line
@@ -401,41 +401,31 @@ static int do_show(int argc, char **argv)

static int do_dump(int argc, char **argv)
{
	unsigned int finfo_rec_size, linfo_rec_size, jited_linfo_rec_size;
	void *func_info = NULL, *linfo = NULL, *jited_linfo = NULL;
	unsigned int nr_finfo, nr_linfo = 0, nr_jited_linfo = 0;
	struct bpf_prog_info_linear *info_linear;
	struct bpf_prog_linfo *prog_linfo = NULL;
	unsigned long *func_ksyms = NULL;
	struct bpf_prog_info info = {};
	unsigned int *func_lens = NULL;
	enum {DUMP_JITED, DUMP_XLATED} mode;
	const char *disasm_opt = NULL;
	unsigned int nr_func_ksyms;
	unsigned int nr_func_lens;
	struct bpf_prog_info *info;
	struct dump_data dd = {};
	__u32 len = sizeof(info);
	void *func_info = NULL;
	struct btf *btf = NULL;
	unsigned int buf_size;
	char *filepath = NULL;
	bool opcodes = false;
	bool visual = false;
	char func_sig[1024];
	unsigned char *buf;
	bool linum = false;
	__u32 *member_len;
	__u64 *member_ptr;
	__u32 member_len;
	__u64 arrays;
	ssize_t n;
	int err;
	int fd;

	if (is_prefix(*argv, "jited")) {
		if (disasm_init())
			return -1;

		member_len = &info.jited_prog_len;
		member_ptr = &info.jited_prog_insns;
		mode = DUMP_JITED;
	} else if (is_prefix(*argv, "xlated")) {
		member_len = &info.xlated_prog_len;
		member_ptr = &info.xlated_prog_insns;
		mode = DUMP_XLATED;
	} else {
		p_err("expected 'xlated' or 'jited', got: %s", *argv);
		return -1;
@@ -474,175 +464,50 @@ static int do_dump(int argc, char **argv)
		return -1;
	}

	err = bpf_obj_get_info_by_fd(fd, &info, &len);
	if (err) {
		p_err("can't get prog info: %s", strerror(errno));
		return -1;
	}

	if (!*member_len) {
		p_info("no instructions returned");
		close(fd);
		return 0;
	}

	buf_size = *member_len;

	buf = malloc(buf_size);
	if (!buf) {
		p_err("mem alloc failed");
		close(fd);
		return -1;
	}

	nr_func_ksyms = info.nr_jited_ksyms;
	if (nr_func_ksyms) {
		func_ksyms = malloc(nr_func_ksyms * sizeof(__u64));
		if (!func_ksyms) {
			p_err("mem alloc failed");
			close(fd);
			goto err_free;
		}
	}

	nr_func_lens = info.nr_jited_func_lens;
	if (nr_func_lens) {
		func_lens = malloc(nr_func_lens * sizeof(__u32));
		if (!func_lens) {
			p_err("mem alloc failed");
			close(fd);
			goto err_free;
		}
	}

	nr_finfo = info.nr_func_info;
	finfo_rec_size = info.func_info_rec_size;
	if (nr_finfo && finfo_rec_size) {
		func_info = malloc(nr_finfo * finfo_rec_size);
		if (!func_info) {
			p_err("mem alloc failed");
			close(fd);
			goto err_free;
		}
	}

	linfo_rec_size = info.line_info_rec_size;
	if (info.nr_line_info && linfo_rec_size && info.btf_id) {
		nr_linfo = info.nr_line_info;
		linfo = malloc(nr_linfo * linfo_rec_size);
		if (!linfo) {
			p_err("mem alloc failed");
			close(fd);
			goto err_free;
		}
	}

	jited_linfo_rec_size = info.jited_line_info_rec_size;
	if (info.nr_jited_line_info &&
	    jited_linfo_rec_size &&
	    info.nr_jited_ksyms &&
	    info.nr_jited_func_lens &&
	    info.btf_id) {
		nr_jited_linfo = info.nr_jited_line_info;
		jited_linfo = malloc(nr_jited_linfo * jited_linfo_rec_size);
		if (!jited_linfo) {
			p_err("mem alloc failed");
			close(fd);
			goto err_free;
		}
	}

	memset(&info, 0, sizeof(info));
	if (mode == DUMP_JITED)
		arrays = 1UL << BPF_PROG_INFO_JITED_INSNS;
	else
		arrays = 1UL << BPF_PROG_INFO_XLATED_INSNS;

	*member_ptr = ptr_to_u64(buf);
	*member_len = buf_size;
	info.jited_ksyms = ptr_to_u64(func_ksyms);
	info.nr_jited_ksyms = nr_func_ksyms;
	info.jited_func_lens = ptr_to_u64(func_lens);
	info.nr_jited_func_lens = nr_func_lens;
	info.nr_func_info = nr_finfo;
	info.func_info_rec_size = finfo_rec_size;
	info.func_info = ptr_to_u64(func_info);
	info.nr_line_info = nr_linfo;
	info.line_info_rec_size = linfo_rec_size;
	info.line_info = ptr_to_u64(linfo);
	info.nr_jited_line_info = nr_jited_linfo;
	info.jited_line_info_rec_size = jited_linfo_rec_size;
	info.jited_line_info = ptr_to_u64(jited_linfo);
	arrays |= 1UL << BPF_PROG_INFO_JITED_KSYMS;
	arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS;
	arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO;
	arrays |= 1UL << BPF_PROG_INFO_LINE_INFO;
	arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO;

	err = bpf_obj_get_info_by_fd(fd, &info, &len);
	info_linear = bpf_program__get_prog_info_linear(fd, arrays);
	close(fd);
	if (err) {
	if (IS_ERR_OR_NULL(info_linear)) {
		p_err("can't get prog info: %s", strerror(errno));
		goto err_free;
	}

	if (*member_len > buf_size) {
		p_err("too many instructions returned");
		goto err_free;
	}

	if (info.nr_jited_ksyms > nr_func_ksyms) {
		p_err("too many addresses returned");
		goto err_free;
	}

	if (info.nr_jited_func_lens > nr_func_lens) {
		p_err("too many values returned");
		goto err_free;
	}

	if (info.nr_func_info != nr_finfo) {
		p_err("incorrect nr_func_info %d vs. expected %d",
		      info.nr_func_info, nr_finfo);
		goto err_free;
	}

	if (info.func_info_rec_size != finfo_rec_size) {
		p_err("incorrect func_info_rec_size %d vs. expected %d",
		      info.func_info_rec_size, finfo_rec_size);
		goto err_free;
	}

	if (linfo && info.nr_line_info != nr_linfo) {
		p_err("incorrect nr_line_info %u vs. expected %u",
		      info.nr_line_info, nr_linfo);
		goto err_free;
	}

	if (info.line_info_rec_size != linfo_rec_size) {
		p_err("incorrect line_info_rec_size %u vs. expected %u",
		      info.line_info_rec_size, linfo_rec_size);
		goto err_free;
	}

	if (jited_linfo && info.nr_jited_line_info != nr_jited_linfo) {
		p_err("incorrect nr_jited_line_info %u vs. expected %u",
		      info.nr_jited_line_info, nr_jited_linfo);
		goto err_free;
		return -1;
	}

	if (info.jited_line_info_rec_size != jited_linfo_rec_size) {
		p_err("incorrect jited_line_info_rec_size %u vs. expected %u",
		      info.jited_line_info_rec_size, jited_linfo_rec_size);
	info = &info_linear->info;
	if (mode == DUMP_JITED) {
		if (info->jited_prog_len == 0) {
			p_info("no instructions returned");
			goto err_free;
		}

	if ((member_len == &info.jited_prog_len &&
	     info.jited_prog_insns == 0) ||
	    (member_len == &info.xlated_prog_len &&
	     info.xlated_prog_insns == 0)) {
		buf = (unsigned char *)(info->jited_prog_insns);
		member_len = info->jited_prog_len;
	} else {	/* DUMP_XLATED */
		if (info->xlated_prog_len == 0) {
			p_err("error retrieving insn dump: kernel.kptr_restrict set?");
			goto err_free;
		}
		buf = (unsigned char *)info->xlated_prog_insns;
		member_len = info->xlated_prog_len;
	}

	if (info.btf_id && btf__get_from_id(info.btf_id, &btf)) {
	if (info->btf_id && btf__get_from_id(info->btf_id, &btf)) {
		p_err("failed to get btf");
		goto err_free;
	}

	if (nr_linfo) {
		prog_linfo = bpf_prog_linfo__new(&info);
	func_info = (void *)info->func_info;

	if (info->nr_line_info) {
		prog_linfo = bpf_prog_linfo__new(info);
		if (!prog_linfo)
			p_info("error in processing bpf_line_info.  continue without it.");
	}
@@ -655,9 +520,9 @@ static int do_dump(int argc, char **argv)
			goto err_free;
		}

		n = write(fd, buf, *member_len);
		n = write(fd, buf, member_len);
		close(fd);
		if (n != *member_len) {
		if (n != member_len) {
			p_err("error writing output file: %s",
			      n < 0 ? strerror(errno) : "short write");
			goto err_free;
@@ -665,19 +530,19 @@ static int do_dump(int argc, char **argv)

		if (json_output)
			jsonw_null(json_wtr);
	} else if (member_len == &info.jited_prog_len) {
	} else if (mode == DUMP_JITED) {
		const char *name = NULL;

		if (info.ifindex) {
			name = ifindex_to_bfd_params(info.ifindex,
						     info.netns_dev,
						     info.netns_ino,
		if (info->ifindex) {
			name = ifindex_to_bfd_params(info->ifindex,
						     info->netns_dev,
						     info->netns_ino,
						     &disasm_opt);
			if (!name)
				goto err_free;
		}

		if (info.nr_jited_func_lens && info.jited_func_lens) {
		if (info->nr_jited_func_lens && info->jited_func_lens) {
			struct kernel_sym *sym = NULL;
			struct bpf_func_info *record;
			char sym_name[SYM_MAX_NAME];
@@ -685,17 +550,16 @@ static int do_dump(int argc, char **argv)
			__u64 *ksyms = NULL;
			__u32 *lens;
			__u32 i;

			if (info.nr_jited_ksyms) {
			if (info->nr_jited_ksyms) {
				kernel_syms_load(&dd);
				ksyms = (__u64 *) info.jited_ksyms;
				ksyms = (__u64 *) info->jited_ksyms;
			}

			if (json_output)
				jsonw_start_array(json_wtr);

			lens = (__u32 *) info.jited_func_lens;
			for (i = 0; i < info.nr_jited_func_lens; i++) {
			lens = (__u32 *) info->jited_func_lens;
			for (i = 0; i < info->nr_jited_func_lens; i++) {
				if (ksyms) {
					sym = kernel_syms_search(&dd, ksyms[i]);
					if (sym)
@@ -707,7 +571,7 @@ static int do_dump(int argc, char **argv)
				}

				if (func_info) {
					record = func_info + i * finfo_rec_size;
					record = func_info + i * info->func_info_rec_size;
					btf_dumper_type_only(btf, record->type_id,
							     func_sig,
							     sizeof(func_sig));
@@ -744,49 +608,37 @@ static int do_dump(int argc, char **argv)
			if (json_output)
				jsonw_end_array(json_wtr);
		} else {
			disasm_print_insn(buf, *member_len, opcodes, name,
			disasm_print_insn(buf, member_len, opcodes, name,
					  disasm_opt, btf, NULL, 0, 0, false);
		}
	} else if (visual) {
		if (json_output)
			jsonw_null(json_wtr);
		else
			dump_xlated_cfg(buf, *member_len);
			dump_xlated_cfg(buf, member_len);
	} else {
		kernel_syms_load(&dd);
		dd.nr_jited_ksyms = info.nr_jited_ksyms;
		dd.jited_ksyms = (__u64 *) info.jited_ksyms;
		dd.nr_jited_ksyms = info->nr_jited_ksyms;
		dd.jited_ksyms = (__u64 *) info->jited_ksyms;
		dd.btf = btf;
		dd.func_info = func_info;
		dd.finfo_rec_size = finfo_rec_size;
		dd.finfo_rec_size = info->func_info_rec_size;
		dd.prog_linfo = prog_linfo;

		if (json_output)
			dump_xlated_json(&dd, buf, *member_len, opcodes,
			dump_xlated_json(&dd, buf, member_len, opcodes,
					 linum);
		else
			dump_xlated_plain(&dd, buf, *member_len, opcodes,
			dump_xlated_plain(&dd, buf, member_len, opcodes,
					  linum);
		kernel_syms_destroy(&dd);
	}

	free(buf);
	free(func_ksyms);
	free(func_lens);
	free(func_info);
	free(linfo);
	free(jited_linfo);
	bpf_prog_linfo__free(prog_linfo);
	free(info_linear);
	return 0;

err_free:
	free(buf);
	free(func_ksyms);
	free(func_lens);
	free(func_info);
	free(linfo);
	free(jited_linfo);
	bpf_prog_linfo__free(prog_linfo);
	free(info_linear);
	return -1;
}

+4 −2
Original line number Diff line number Diff line
@@ -66,7 +66,8 @@ FEATURE_TESTS_BASIC := \
        sched_getcpu			\
        sdt				\
        setns				\
        libaio
        libaio				\
        disassembler-four-args

# FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
# of all feature tests
@@ -118,7 +119,8 @@ FEATURE_DISPLAY ?= \
         lzma                   \
         get_cpuid              \
         bpf			\
         libaio
         libaio			\
         disassembler-four-args

# Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features.
# If in the future we need per-feature checks/flags for features not
+5 −0
Original line number Diff line number Diff line
@@ -178,6 +178,10 @@
# include "test-reallocarray.c"
#undef main

#define main main_test_disassembler_four_args
# include "test-disassembler-four-args.c"
#undef main

int main(int argc, char *argv[])
{
	main_test_libpython();
@@ -219,6 +223,7 @@ int main(int argc, char *argv[])
	main_test_setns();
	main_test_libaio();
	main_test_reallocarray();
	main_test_disassembler_four_args();

	return 0;
}
+252 −1
Original line number Diff line number Diff line
@@ -112,6 +112,11 @@ void libbpf_print(enum libbpf_print_level level, const char *format, ...)
# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ
#endif

static inline __u64 ptr_to_u64(const void *ptr)
{
	return (__u64) (unsigned long) ptr;
}

struct bpf_capabilities {
	/* v4.14: kernel support for program & map names. */
	__u32 name:1;
@@ -622,7 +627,7 @@ bpf_object__init_maps(struct bpf_object *obj, int flags)
	bool strict = !(flags & MAPS_RELAX_COMPAT);
	int i, map_idx, map_def_sz, nr_maps = 0;
	Elf_Scn *scn;
	Elf_Data *data;
	Elf_Data *data = NULL;
	Elf_Data *symbols = obj->efile.symbols;

	if (obj->efile.maps_shndx < 0)
@@ -2999,3 +3004,249 @@ bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
	ring_buffer_write_tail(header, data_tail);
	return ret;
}

struct bpf_prog_info_array_desc {
	int	array_offset;	/* e.g. offset of jited_prog_insns */
	int	count_offset;	/* e.g. offset of jited_prog_len */
	int	size_offset;	/* > 0: offset of rec size,
				 * < 0: fix size of -size_offset
				 */
};

static struct bpf_prog_info_array_desc bpf_prog_info_array_desc[] = {
	[BPF_PROG_INFO_JITED_INSNS] = {
		offsetof(struct bpf_prog_info, jited_prog_insns),
		offsetof(struct bpf_prog_info, jited_prog_len),
		-1,
	},
	[BPF_PROG_INFO_XLATED_INSNS] = {
		offsetof(struct bpf_prog_info, xlated_prog_insns),
		offsetof(struct bpf_prog_info, xlated_prog_len),
		-1,
	},
	[BPF_PROG_INFO_MAP_IDS] = {
		offsetof(struct bpf_prog_info, map_ids),
		offsetof(struct bpf_prog_info, nr_map_ids),
		-(int)sizeof(__u32),
	},
	[BPF_PROG_INFO_JITED_KSYMS] = {
		offsetof(struct bpf_prog_info, jited_ksyms),
		offsetof(struct bpf_prog_info, nr_jited_ksyms),
		-(int)sizeof(__u64),
	},
	[BPF_PROG_INFO_JITED_FUNC_LENS] = {
		offsetof(struct bpf_prog_info, jited_func_lens),
		offsetof(struct bpf_prog_info, nr_jited_func_lens),
		-(int)sizeof(__u32),
	},
	[BPF_PROG_INFO_FUNC_INFO] = {
		offsetof(struct bpf_prog_info, func_info),
		offsetof(struct bpf_prog_info, nr_func_info),
		offsetof(struct bpf_prog_info, func_info_rec_size),
	},
	[BPF_PROG_INFO_LINE_INFO] = {
		offsetof(struct bpf_prog_info, line_info),
		offsetof(struct bpf_prog_info, nr_line_info),
		offsetof(struct bpf_prog_info, line_info_rec_size),
	},
	[BPF_PROG_INFO_JITED_LINE_INFO] = {
		offsetof(struct bpf_prog_info, jited_line_info),
		offsetof(struct bpf_prog_info, nr_jited_line_info),
		offsetof(struct bpf_prog_info, jited_line_info_rec_size),
	},
	[BPF_PROG_INFO_PROG_TAGS] = {
		offsetof(struct bpf_prog_info, prog_tags),
		offsetof(struct bpf_prog_info, nr_prog_tags),
		-(int)sizeof(__u8) * BPF_TAG_SIZE,
	},

};

static __u32 bpf_prog_info_read_offset_u32(struct bpf_prog_info *info, int offset)
{
	__u32 *array = (__u32 *)info;

	if (offset >= 0)
		return array[offset / sizeof(__u32)];
	return -(int)offset;
}

static __u64 bpf_prog_info_read_offset_u64(struct bpf_prog_info *info, int offset)
{
	__u64 *array = (__u64 *)info;

	if (offset >= 0)
		return array[offset / sizeof(__u64)];
	return -(int)offset;
}

static void bpf_prog_info_set_offset_u32(struct bpf_prog_info *info, int offset,
					 __u32 val)
{
	__u32 *array = (__u32 *)info;

	if (offset >= 0)
		array[offset / sizeof(__u32)] = val;
}

static void bpf_prog_info_set_offset_u64(struct bpf_prog_info *info, int offset,
					 __u64 val)
{
	__u64 *array = (__u64 *)info;

	if (offset >= 0)
		array[offset / sizeof(__u64)] = val;
}

struct bpf_prog_info_linear *
bpf_program__get_prog_info_linear(int fd, __u64 arrays)
{
	struct bpf_prog_info_linear *info_linear;
	struct bpf_prog_info info = {};
	__u32 info_len = sizeof(info);
	__u32 data_len = 0;
	int i, err;
	void *ptr;

	if (arrays >> BPF_PROG_INFO_LAST_ARRAY)
		return ERR_PTR(-EINVAL);

	/* step 1: get array dimensions */
	err = bpf_obj_get_info_by_fd(fd, &info, &info_len);
	if (err) {
		pr_debug("can't get prog info: %s", strerror(errno));
		return ERR_PTR(-EFAULT);
	}

	/* step 2: calculate total size of all arrays */
	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
		bool include_array = (arrays & (1UL << i)) > 0;
		struct bpf_prog_info_array_desc *desc;
		__u32 count, size;

		desc = bpf_prog_info_array_desc + i;

		/* kernel is too old to support this field */
		if (info_len < desc->array_offset + sizeof(__u32) ||
		    info_len < desc->count_offset + sizeof(__u32) ||
		    (desc->size_offset > 0 && info_len < desc->size_offset))
			include_array = false;

		if (!include_array) {
			arrays &= ~(1UL << i);	/* clear the bit */
			continue;
		}

		count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
		size  = bpf_prog_info_read_offset_u32(&info, desc->size_offset);

		data_len += count * size;
	}

	/* step 3: allocate continuous memory */
	data_len = roundup(data_len, sizeof(__u64));
	info_linear = malloc(sizeof(struct bpf_prog_info_linear) + data_len);
	if (!info_linear)
		return ERR_PTR(-ENOMEM);

	/* step 4: fill data to info_linear->info */
	info_linear->arrays = arrays;
	memset(&info_linear->info, 0, sizeof(info));
	ptr = info_linear->data;

	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
		struct bpf_prog_info_array_desc *desc;
		__u32 count, size;

		if ((arrays & (1UL << i)) == 0)
			continue;

		desc  = bpf_prog_info_array_desc + i;
		count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
		size  = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
		bpf_prog_info_set_offset_u32(&info_linear->info,
					     desc->count_offset, count);
		bpf_prog_info_set_offset_u32(&info_linear->info,
					     desc->size_offset, size);
		bpf_prog_info_set_offset_u64(&info_linear->info,
					     desc->array_offset,
					     ptr_to_u64(ptr));
		ptr += count * size;
	}

	/* step 5: call syscall again to get required arrays */
	err = bpf_obj_get_info_by_fd(fd, &info_linear->info, &info_len);
	if (err) {
		pr_debug("can't get prog info: %s", strerror(errno));
		free(info_linear);
		return ERR_PTR(-EFAULT);
	}

	/* step 6: verify the data */
	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
		struct bpf_prog_info_array_desc *desc;
		__u32 v1, v2;

		if ((arrays & (1UL << i)) == 0)
			continue;

		desc = bpf_prog_info_array_desc + i;
		v1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
		v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
						   desc->count_offset);
		if (v1 != v2)
			pr_warning("%s: mismatch in element count\n", __func__);

		v1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
		v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
						   desc->size_offset);
		if (v1 != v2)
			pr_warning("%s: mismatch in rec size\n", __func__);
	}

	/* step 7: update info_len and data_len */
	info_linear->info_len = sizeof(struct bpf_prog_info);
	info_linear->data_len = data_len;

	return info_linear;
}

void bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear)
{
	int i;

	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
		struct bpf_prog_info_array_desc *desc;
		__u64 addr, offs;

		if ((info_linear->arrays & (1UL << i)) == 0)
			continue;

		desc = bpf_prog_info_array_desc + i;
		addr = bpf_prog_info_read_offset_u64(&info_linear->info,
						     desc->array_offset);
		offs = addr - ptr_to_u64(info_linear->data);
		bpf_prog_info_set_offset_u64(&info_linear->info,
					     desc->array_offset, offs);
	}
}

void bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear)
{
	int i;

	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
		struct bpf_prog_info_array_desc *desc;
		__u64 addr, offs;

		if ((info_linear->arrays & (1UL << i)) == 0)
			continue;

		desc = bpf_prog_info_array_desc + i;
		offs = bpf_prog_info_read_offset_u64(&info_linear->info,
						     desc->array_offset);
		addr = offs + ptr_to_u64(info_linear->data);
		bpf_prog_info_set_offset_u64(&info_linear->info,
					     desc->array_offset, addr);
	}
}
+63 −0
Original line number Diff line number Diff line
@@ -378,6 +378,69 @@ LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);
LIBBPF_API bool bpf_probe_helper(enum bpf_func_id id,
				 enum bpf_prog_type prog_type, __u32 ifindex);

/*
 * Get bpf_prog_info in continuous memory
 *
 * struct bpf_prog_info has multiple arrays. The user has option to choose
 * arrays to fetch from kernel. The following APIs provide an uniform way to
 * fetch these data. All arrays in bpf_prog_info are stored in a single
 * continuous memory region. This makes it easy to store the info in a
 * file.
 *
 * Before writing bpf_prog_info_linear to files, it is necessary to
 * translate pointers in bpf_prog_info to offsets. Helper functions
 * bpf_program__bpil_addr_to_offs() and bpf_program__bpil_offs_to_addr()
 * are introduced to switch between pointers and offsets.
 *
 * Examples:
 *   # To fetch map_ids and prog_tags:
 *   __u64 arrays = (1UL << BPF_PROG_INFO_MAP_IDS) |
 *           (1UL << BPF_PROG_INFO_PROG_TAGS);
 *   struct bpf_prog_info_linear *info_linear =
 *           bpf_program__get_prog_info_linear(fd, arrays);
 *
 *   # To save data in file
 *   bpf_program__bpil_addr_to_offs(info_linear);
 *   write(f, info_linear, sizeof(*info_linear) + info_linear->data_len);
 *
 *   # To read data from file
 *   read(f, info_linear, <proper_size>);
 *   bpf_program__bpil_offs_to_addr(info_linear);
 */
enum bpf_prog_info_array {
	BPF_PROG_INFO_FIRST_ARRAY = 0,
	BPF_PROG_INFO_JITED_INSNS = 0,
	BPF_PROG_INFO_XLATED_INSNS,
	BPF_PROG_INFO_MAP_IDS,
	BPF_PROG_INFO_JITED_KSYMS,
	BPF_PROG_INFO_JITED_FUNC_LENS,
	BPF_PROG_INFO_FUNC_INFO,
	BPF_PROG_INFO_LINE_INFO,
	BPF_PROG_INFO_JITED_LINE_INFO,
	BPF_PROG_INFO_PROG_TAGS,
	BPF_PROG_INFO_LAST_ARRAY,
};

struct bpf_prog_info_linear {
	/* size of struct bpf_prog_info, when the tool is compiled */
	__u32			info_len;
	/* total bytes allocated for data, round up to 8 bytes */
	__u32			data_len;
	/* which arrays are included in data */
	__u64			arrays;
	struct bpf_prog_info	info;
	__u8			data[];
};

LIBBPF_API struct bpf_prog_info_linear *
bpf_program__get_prog_info_linear(int fd, __u64 arrays);

LIBBPF_API void
bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear);

LIBBPF_API void
bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear);

#ifdef __cplusplus
} /* extern "C" */
#endif
Loading