Commit 726e333f authored by Alexei Starovoitov's avatar Alexei Starovoitov
Browse files

Merge branch 'compile-once-run-everywhere'

Andrii Nakryiko says:

====================
This patch set implements central part of CO-RE (Compile Once - Run
Everywhere, see [0] and [1] for slides and video): relocating fields offsets.
Most of the details are written down as comments to corresponding parts of the
code.

Patch #1 adds a bunch of commonly useful btf_xxx helpers to simplify working
with BTF types.
Patch #2 converts existing libbpf code to these new helpers and removes some
of pre-existing ones.
Patch #3 adds loading of .BTF.ext offset relocations section and macros to
work with its contents.
Patch #4 implements CO-RE relocations algorithm in libbpf.
Patch #5 introduced BPF_CORE_READ macro, hiding usage of Clang's
__builtin_preserve_access_index intrinsic that records offset relocation.
Patches #6-#14 adds selftests validating various parts of relocation handling,
type compatibility, etc.

For all tests to work, you'll need latest Clang/LLVM supporting
__builtin_preserve_access_index intrinsic, used for recording offset
relocations. Kernel on which selftests run should have BTF information built
in (CONFIG_DEBUG_INFO_BTF=y).

  [0] http://vger.kernel.org/bpfconf2019.html#session-2
  [1] http://vger.kernel.org/lpc-bpf2018.html#session-2



v5->v6:
- fix bad comment formatting for real (Alexei);

v4->v5:
- drop constness for btf_xxx() helpers, allowing to avoid type casts (Alexei);
- rebase on latest bpf-next, change test__printf back to printf;

v3->v4:
- added btf_xxx helpers (Alexei);
- switched libbpf code to new helpers;
- reduced amount of logging and simplified format in few places (Alexei);
- made flavor name parsing logic more strict (exactly three underscores);
- no uname() error checking (Alexei);
- updated misc tests to reflect latest Clang fixes (Yonghong);

v2->v3:
- enclose BPF_CORE_READ args in parens (Song);

v1->v2:
- add offsetofend(), fix btf_ext optional fields checks (Song);
- add bpf_core_dump_spec() for logging spec representation;
- move special first element processing out of the loop (Song);
- typo fixes (Song);
- drop BPF_ST | BPF_MEM insn relocation (Alexei);
- extracted BPF_CORE_READ into bpf_helpers (Alexei);
- added extra tests validating Clang capturing relocs correctly (Yonghong);
- switch core_relocs.c to use sub-tests;
- updated mods tests after Clang bug was fixed (Yonghong);
- fix bug enumerating candidate types;
====================

Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents 682cdbdc 29e1c668
Loading
Loading
Loading
Loading
+110 −140
Original line number Original line Diff line number Diff line
@@ -19,13 +19,6 @@
#define BTF_MAX_NR_TYPES 0x7fffffff
#define BTF_MAX_NR_TYPES 0x7fffffff
#define BTF_MAX_STR_OFFSET 0x7fffffff
#define BTF_MAX_STR_OFFSET 0x7fffffff


#define IS_MODIFIER(k) (((k) == BTF_KIND_TYPEDEF) || \
		((k) == BTF_KIND_VOLATILE) || \
		((k) == BTF_KIND_CONST) || \
		((k) == BTF_KIND_RESTRICT))

#define IS_VAR(k) ((k) == BTF_KIND_VAR)

static struct btf_type btf_void;
static struct btf_type btf_void;


struct btf {
struct btf {
@@ -42,47 +35,6 @@ struct btf {
	int fd;
	int fd;
};
};


struct btf_ext_info {
	/*
	 * info points to the individual info section (e.g. func_info and
	 * line_info) from the .BTF.ext. It does not include the __u32 rec_size.
	 */
	void *info;
	__u32 rec_size;
	__u32 len;
};

struct btf_ext {
	union {
		struct btf_ext_header *hdr;
		void *data;
	};
	struct btf_ext_info func_info;
	struct btf_ext_info line_info;
	__u32 data_size;
};

struct btf_ext_info_sec {
	__u32	sec_name_off;
	__u32	num_info;
	/* Followed by num_info * record_size number of bytes */
	__u8	data[0];
};

/* The minimum bpf_func_info checked by the loader */
struct bpf_func_info_min {
	__u32   insn_off;
	__u32   type_id;
};

/* The minimum bpf_line_info checked by the loader */
struct bpf_line_info_min {
	__u32	insn_off;
	__u32	file_name_off;
	__u32	line_off;
	__u32	line_col;
};

static inline __u64 ptr_to_u64(const void *ptr)
static inline __u64 ptr_to_u64(const void *ptr)
{
{
	return (__u64) (unsigned long) ptr;
	return (__u64) (unsigned long) ptr;
@@ -192,9 +144,9 @@ static int btf_parse_str_sec(struct btf *btf)
static int btf_type_size(struct btf_type *t)
static int btf_type_size(struct btf_type *t)
{
{
	int base_size = sizeof(struct btf_type);
	int base_size = sizeof(struct btf_type);
	__u16 vlen = BTF_INFO_VLEN(t->info);
	__u16 vlen = btf_vlen(t);


	switch (BTF_INFO_KIND(t->info)) {
	switch (btf_kind(t)) {
	case BTF_KIND_FWD:
	case BTF_KIND_FWD:
	case BTF_KIND_CONST:
	case BTF_KIND_CONST:
	case BTF_KIND_VOLATILE:
	case BTF_KIND_VOLATILE:
@@ -219,7 +171,7 @@ static int btf_type_size(struct btf_type *t)
	case BTF_KIND_DATASEC:
	case BTF_KIND_DATASEC:
		return base_size + vlen * sizeof(struct btf_var_secinfo);
		return base_size + vlen * sizeof(struct btf_var_secinfo);
	default:
	default:
		pr_debug("Unsupported BTF_KIND:%u\n", BTF_INFO_KIND(t->info));
		pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t));
		return -EINVAL;
		return -EINVAL;
	}
	}
}
}
@@ -263,7 +215,7 @@ const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 type_id)


static bool btf_type_is_void(const struct btf_type *t)
static bool btf_type_is_void(const struct btf_type *t)
{
{
	return t == &btf_void || BTF_INFO_KIND(t->info) == BTF_KIND_FWD;
	return t == &btf_void || btf_is_fwd(t);
}
}


static bool btf_type_is_void_or_null(const struct btf_type *t)
static bool btf_type_is_void_or_null(const struct btf_type *t)
@@ -284,7 +236,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
	t = btf__type_by_id(btf, type_id);
	t = btf__type_by_id(btf, type_id);
	for (i = 0; i < MAX_RESOLVE_DEPTH && !btf_type_is_void_or_null(t);
	for (i = 0; i < MAX_RESOLVE_DEPTH && !btf_type_is_void_or_null(t);
	     i++) {
	     i++) {
		switch (BTF_INFO_KIND(t->info)) {
		switch (btf_kind(t)) {
		case BTF_KIND_INT:
		case BTF_KIND_INT:
		case BTF_KIND_STRUCT:
		case BTF_KIND_STRUCT:
		case BTF_KIND_UNION:
		case BTF_KIND_UNION:
@@ -303,7 +255,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
			type_id = t->type;
			type_id = t->type;
			break;
			break;
		case BTF_KIND_ARRAY:
		case BTF_KIND_ARRAY:
			array = (const struct btf_array *)(t + 1);
			array = btf_array(t);
			if (nelems && array->nelems > UINT32_MAX / nelems)
			if (nelems && array->nelems > UINT32_MAX / nelems)
				return -E2BIG;
				return -E2BIG;
			nelems *= array->nelems;
			nelems *= array->nelems;
@@ -334,8 +286,7 @@ int btf__resolve_type(const struct btf *btf, __u32 type_id)
	t = btf__type_by_id(btf, type_id);
	t = btf__type_by_id(btf, type_id);
	while (depth < MAX_RESOLVE_DEPTH &&
	while (depth < MAX_RESOLVE_DEPTH &&
	       !btf_type_is_void_or_null(t) &&
	       !btf_type_is_void_or_null(t) &&
	       (IS_MODIFIER(BTF_INFO_KIND(t->info)) ||
	       (btf_is_mod(t) || btf_is_typedef(t) || btf_is_var(t))) {
		IS_VAR(BTF_INFO_KIND(t->info)))) {
		type_id = t->type;
		type_id = t->type;
		t = btf__type_by_id(btf, type_id);
		t = btf__type_by_id(btf, type_id);
		depth++;
		depth++;
@@ -554,11 +505,11 @@ static int compare_vsi_off(const void *_a, const void *_b)
static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf,
static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf,
			     struct btf_type *t)
			     struct btf_type *t)
{
{
	__u32 size = 0, off = 0, i, vars = BTF_INFO_VLEN(t->info);
	__u32 size = 0, off = 0, i, vars = btf_vlen(t);
	const char *name = btf__name_by_offset(btf, t->name_off);
	const char *name = btf__name_by_offset(btf, t->name_off);
	const struct btf_type *t_var;
	const struct btf_type *t_var;
	struct btf_var_secinfo *vsi;
	struct btf_var_secinfo *vsi;
	struct btf_var *var;
	const struct btf_var *var;
	int ret;
	int ret;


	if (!name) {
	if (!name) {
@@ -574,12 +525,11 @@ static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf,


	t->size = size;
	t->size = size;


	for (i = 0, vsi = (struct btf_var_secinfo *)(t + 1);
	for (i = 0, vsi = btf_var_secinfos(t); i < vars; i++, vsi++) {
	     i < vars; i++, vsi++) {
		t_var = btf__type_by_id(btf, vsi->type);
		t_var = btf__type_by_id(btf, vsi->type);
		var = (struct btf_var *)(t_var + 1);
		var = btf_var(t_var);


		if (BTF_INFO_KIND(t_var->info) != BTF_KIND_VAR) {
		if (!btf_is_var(t_var)) {
			pr_debug("Non-VAR type seen in section %s\n", name);
			pr_debug("Non-VAR type seen in section %s\n", name);
			return -EINVAL;
			return -EINVAL;
		}
		}
@@ -595,7 +545,8 @@ static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf,


		ret = bpf_object__variable_offset(obj, name, &off);
		ret = bpf_object__variable_offset(obj, name, &off);
		if (ret) {
		if (ret) {
			pr_debug("No offset found in symbol table for VAR %s\n", name);
			pr_debug("No offset found in symbol table for VAR %s\n",
				 name);
			return -ENOENT;
			return -ENOENT;
		}
		}


@@ -619,7 +570,7 @@ int btf__finalize_data(struct bpf_object *obj, struct btf *btf)
		 * is section size and global variable offset. We use
		 * is section size and global variable offset. We use
		 * the info from the ELF itself for this purpose.
		 * the info from the ELF itself for this purpose.
		 */
		 */
		if (BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC) {
		if (btf_is_datasec(t)) {
			err = btf_fixup_datasec(obj, btf, t);
			err = btf_fixup_datasec(obj, btf, t);
			if (err)
			if (err)
				break;
				break;
@@ -774,14 +725,13 @@ int btf__get_map_kv_tids(const struct btf *btf, const char *map_name,
		return -EINVAL;
		return -EINVAL;
	}
	}


	if (BTF_INFO_KIND(container_type->info) != BTF_KIND_STRUCT ||
	if (!btf_is_struct(container_type) || btf_vlen(container_type) < 2) {
	    BTF_INFO_VLEN(container_type->info) < 2) {
		pr_warning("map:%s container_name:%s is an invalid container struct\n",
		pr_warning("map:%s container_name:%s is an invalid container struct\n",
			   map_name, container_name);
			   map_name, container_name);
		return -EINVAL;
		return -EINVAL;
	}
	}


	key = (struct btf_member *)(container_type + 1);
	key = btf_members(container_type);
	value = key + 1;
	value = key + 1;


	key_size = btf__resolve_size(btf, key->type);
	key_size = btf__resolve_size(btf, key->type);
@@ -831,6 +781,9 @@ static int btf_ext_setup_info(struct btf_ext *btf_ext,
	/* The start of the info sec (including the __u32 record_size). */
	/* The start of the info sec (including the __u32 record_size). */
	void *info;
	void *info;


	if (ext_sec->len == 0)
		return 0;

	if (ext_sec->off & 0x03) {
	if (ext_sec->off & 0x03) {
		pr_debug(".BTF.ext %s section is not aligned to 4 bytes\n",
		pr_debug(".BTF.ext %s section is not aligned to 4 bytes\n",
		     ext_sec->desc);
		     ext_sec->desc);
@@ -934,11 +887,24 @@ static int btf_ext_setup_line_info(struct btf_ext *btf_ext)
	return btf_ext_setup_info(btf_ext, &param);
	return btf_ext_setup_info(btf_ext, &param);
}
}


static int btf_ext_setup_offset_reloc(struct btf_ext *btf_ext)
{
	struct btf_ext_sec_setup_param param = {
		.off = btf_ext->hdr->offset_reloc_off,
		.len = btf_ext->hdr->offset_reloc_len,
		.min_rec_size = sizeof(struct bpf_offset_reloc),
		.ext_info = &btf_ext->offset_reloc_info,
		.desc = "offset_reloc",
	};

	return btf_ext_setup_info(btf_ext, &param);
}

static int btf_ext_parse_hdr(__u8 *data, __u32 data_size)
static int btf_ext_parse_hdr(__u8 *data, __u32 data_size)
{
{
	const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
	const struct btf_ext_header *hdr = (struct btf_ext_header *)data;


	if (data_size < offsetof(struct btf_ext_header, func_info_off) ||
	if (data_size < offsetofend(struct btf_ext_header, hdr_len) ||
	    data_size < hdr->hdr_len) {
	    data_size < hdr->hdr_len) {
		pr_debug("BTF.ext header not found");
		pr_debug("BTF.ext header not found");
		return -EINVAL;
		return -EINVAL;
@@ -996,6 +962,9 @@ struct btf_ext *btf_ext__new(__u8 *data, __u32 size)
	}
	}
	memcpy(btf_ext->data, data, size);
	memcpy(btf_ext->data, data, size);


	if (btf_ext->hdr->hdr_len <
	    offsetofend(struct btf_ext_header, line_info_len))
		goto done;
	err = btf_ext_setup_func_info(btf_ext);
	err = btf_ext_setup_func_info(btf_ext);
	if (err)
	if (err)
		goto done;
		goto done;
@@ -1004,6 +973,13 @@ struct btf_ext *btf_ext__new(__u8 *data, __u32 size)
	if (err)
	if (err)
		goto done;
		goto done;


	if (btf_ext->hdr->hdr_len <
	    offsetofend(struct btf_ext_header, offset_reloc_len))
		goto done;
	err = btf_ext_setup_offset_reloc(btf_ext);
	if (err)
		goto done;

done:
done:
	if (err) {
	if (err) {
		btf_ext__free(btf_ext);
		btf_ext__free(btf_ext);
@@ -1440,10 +1416,9 @@ static struct btf_dedup *btf_dedup_new(struct btf *btf, struct btf_ext *btf_ext,
	d->map[0] = 0;
	d->map[0] = 0;
	for (i = 1; i <= btf->nr_types; i++) {
	for (i = 1; i <= btf->nr_types; i++) {
		struct btf_type *t = d->btf->types[i];
		struct btf_type *t = d->btf->types[i];
		__u16 kind = BTF_INFO_KIND(t->info);


		/* VAR and DATASEC are never deduped and are self-canonical */
		/* VAR and DATASEC are never deduped and are self-canonical */
		if (kind == BTF_KIND_VAR || kind == BTF_KIND_DATASEC)
		if (btf_is_var(t) || btf_is_datasec(t))
			d->map[i] = i;
			d->map[i] = i;
		else
		else
			d->map[i] = BTF_UNPROCESSED_ID;
			d->map[i] = BTF_UNPROCESSED_ID;
@@ -1484,11 +1459,11 @@ static int btf_for_each_str_off(struct btf_dedup *d, str_off_fn_t fn, void *ctx)
		if (r)
		if (r)
			return r;
			return r;


		switch (BTF_INFO_KIND(t->info)) {
		switch (btf_kind(t)) {
		case BTF_KIND_STRUCT:
		case BTF_KIND_STRUCT:
		case BTF_KIND_UNION: {
		case BTF_KIND_UNION: {
			struct btf_member *m = (struct btf_member *)(t + 1);
			struct btf_member *m = btf_members(t);
			__u16 vlen = BTF_INFO_VLEN(t->info);
			__u16 vlen = btf_vlen(t);


			for (j = 0; j < vlen; j++) {
			for (j = 0; j < vlen; j++) {
				r = fn(&m->name_off, ctx);
				r = fn(&m->name_off, ctx);
@@ -1499,8 +1474,8 @@ static int btf_for_each_str_off(struct btf_dedup *d, str_off_fn_t fn, void *ctx)
			break;
			break;
		}
		}
		case BTF_KIND_ENUM: {
		case BTF_KIND_ENUM: {
			struct btf_enum *m = (struct btf_enum *)(t + 1);
			struct btf_enum *m = btf_enum(t);
			__u16 vlen = BTF_INFO_VLEN(t->info);
			__u16 vlen = btf_vlen(t);


			for (j = 0; j < vlen; j++) {
			for (j = 0; j < vlen; j++) {
				r = fn(&m->name_off, ctx);
				r = fn(&m->name_off, ctx);
@@ -1511,8 +1486,8 @@ static int btf_for_each_str_off(struct btf_dedup *d, str_off_fn_t fn, void *ctx)
			break;
			break;
		}
		}
		case BTF_KIND_FUNC_PROTO: {
		case BTF_KIND_FUNC_PROTO: {
			struct btf_param *m = (struct btf_param *)(t + 1);
			struct btf_param *m = btf_params(t);
			__u16 vlen = BTF_INFO_VLEN(t->info);
			__u16 vlen = btf_vlen(t);


			for (j = 0; j < vlen; j++) {
			for (j = 0; j < vlen; j++) {
				r = fn(&m->name_off, ctx);
				r = fn(&m->name_off, ctx);
@@ -1801,16 +1776,16 @@ static long btf_hash_enum(struct btf_type *t)
/* Check structural equality of two ENUMs. */
/* Check structural equality of two ENUMs. */
static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)
static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)
{
{
	struct btf_enum *m1, *m2;
	const struct btf_enum *m1, *m2;
	__u16 vlen;
	__u16 vlen;
	int i;
	int i;


	if (!btf_equal_common(t1, t2))
	if (!btf_equal_common(t1, t2))
		return false;
		return false;


	vlen = BTF_INFO_VLEN(t1->info);
	vlen = btf_vlen(t1);
	m1 = (struct btf_enum *)(t1 + 1);
	m1 = btf_enum(t1);
	m2 = (struct btf_enum *)(t2 + 1);
	m2 = btf_enum(t2);
	for (i = 0; i < vlen; i++) {
	for (i = 0; i < vlen; i++) {
		if (m1->name_off != m2->name_off || m1->val != m2->val)
		if (m1->name_off != m2->name_off || m1->val != m2->val)
			return false;
			return false;
@@ -1822,8 +1797,7 @@ static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)


static inline bool btf_is_enum_fwd(struct btf_type *t)
static inline bool btf_is_enum_fwd(struct btf_type *t)
{
{
	return BTF_INFO_KIND(t->info) == BTF_KIND_ENUM &&
	return btf_is_enum(t) && btf_vlen(t) == 0;
	       BTF_INFO_VLEN(t->info) == 0;
}
}


static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
@@ -1843,8 +1817,8 @@ static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
 */
 */
static long btf_hash_struct(struct btf_type *t)
static long btf_hash_struct(struct btf_type *t)
{
{
	struct btf_member *member = (struct btf_member *)(t + 1);
	const struct btf_member *member = btf_members(t);
	__u32 vlen = BTF_INFO_VLEN(t->info);
	__u32 vlen = btf_vlen(t);
	long h = btf_hash_common(t);
	long h = btf_hash_common(t);
	int i;
	int i;


@@ -1864,16 +1838,16 @@ static long btf_hash_struct(struct btf_type *t)
 */
 */
static bool btf_shallow_equal_struct(struct btf_type *t1, struct btf_type *t2)
static bool btf_shallow_equal_struct(struct btf_type *t1, struct btf_type *t2)
{
{
	struct btf_member *m1, *m2;
	const struct btf_member *m1, *m2;
	__u16 vlen;
	__u16 vlen;
	int i;
	int i;


	if (!btf_equal_common(t1, t2))
	if (!btf_equal_common(t1, t2))
		return false;
		return false;


	vlen = BTF_INFO_VLEN(t1->info);
	vlen = btf_vlen(t1);
	m1 = (struct btf_member *)(t1 + 1);
	m1 = btf_members(t1);
	m2 = (struct btf_member *)(t2 + 1);
	m2 = btf_members(t2);
	for (i = 0; i < vlen; i++) {
	for (i = 0; i < vlen; i++) {
		if (m1->name_off != m2->name_off || m1->offset != m2->offset)
		if (m1->name_off != m2->name_off || m1->offset != m2->offset)
			return false;
			return false;
@@ -1890,7 +1864,7 @@ static bool btf_shallow_equal_struct(struct btf_type *t1, struct btf_type *t2)
 */
 */
static long btf_hash_array(struct btf_type *t)
static long btf_hash_array(struct btf_type *t)
{
{
	struct btf_array *info = (struct btf_array *)(t + 1);
	const struct btf_array *info = btf_array(t);
	long h = btf_hash_common(t);
	long h = btf_hash_common(t);


	h = hash_combine(h, info->type);
	h = hash_combine(h, info->type);
@@ -1908,13 +1882,13 @@ static long btf_hash_array(struct btf_type *t)
 */
 */
static bool btf_equal_array(struct btf_type *t1, struct btf_type *t2)
static bool btf_equal_array(struct btf_type *t1, struct btf_type *t2)
{
{
	struct btf_array *info1, *info2;
	const struct btf_array *info1, *info2;


	if (!btf_equal_common(t1, t2))
	if (!btf_equal_common(t1, t2))
		return false;
		return false;


	info1 = (struct btf_array *)(t1 + 1);
	info1 = btf_array(t1);
	info2 = (struct btf_array *)(t2 + 1);
	info2 = btf_array(t2);
	return info1->type == info2->type &&
	return info1->type == info2->type &&
	       info1->index_type == info2->index_type &&
	       info1->index_type == info2->index_type &&
	       info1->nelems == info2->nelems;
	       info1->nelems == info2->nelems;
@@ -1927,14 +1901,10 @@ static bool btf_equal_array(struct btf_type *t1, struct btf_type *t2)
 */
 */
static bool btf_compat_array(struct btf_type *t1, struct btf_type *t2)
static bool btf_compat_array(struct btf_type *t1, struct btf_type *t2)
{
{
	struct btf_array *info1, *info2;

	if (!btf_equal_common(t1, t2))
	if (!btf_equal_common(t1, t2))
		return false;
		return false;


	info1 = (struct btf_array *)(t1 + 1);
	return btf_array(t1)->nelems == btf_array(t2)->nelems;
	info2 = (struct btf_array *)(t2 + 1);
	return info1->nelems == info2->nelems;
}
}


/*
/*
@@ -1944,8 +1914,8 @@ static bool btf_compat_array(struct btf_type *t1, struct btf_type *t2)
 */
 */
static long btf_hash_fnproto(struct btf_type *t)
static long btf_hash_fnproto(struct btf_type *t)
{
{
	struct btf_param *member = (struct btf_param *)(t + 1);
	const struct btf_param *member = btf_params(t);
	__u16 vlen = BTF_INFO_VLEN(t->info);
	__u16 vlen = btf_vlen(t);
	long h = btf_hash_common(t);
	long h = btf_hash_common(t);
	int i;
	int i;


@@ -1966,16 +1936,16 @@ static long btf_hash_fnproto(struct btf_type *t)
 */
 */
static bool btf_equal_fnproto(struct btf_type *t1, struct btf_type *t2)
static bool btf_equal_fnproto(struct btf_type *t1, struct btf_type *t2)
{
{
	struct btf_param *m1, *m2;
	const struct btf_param *m1, *m2;
	__u16 vlen;
	__u16 vlen;
	int i;
	int i;


	if (!btf_equal_common(t1, t2))
	if (!btf_equal_common(t1, t2))
		return false;
		return false;


	vlen = BTF_INFO_VLEN(t1->info);
	vlen = btf_vlen(t1);
	m1 = (struct btf_param *)(t1 + 1);
	m1 = btf_params(t1);
	m2 = (struct btf_param *)(t2 + 1);
	m2 = btf_params(t2);
	for (i = 0; i < vlen; i++) {
	for (i = 0; i < vlen; i++) {
		if (m1->name_off != m2->name_off || m1->type != m2->type)
		if (m1->name_off != m2->name_off || m1->type != m2->type)
			return false;
			return false;
@@ -1992,7 +1962,7 @@ static bool btf_equal_fnproto(struct btf_type *t1, struct btf_type *t2)
 */
 */
static bool btf_compat_fnproto(struct btf_type *t1, struct btf_type *t2)
static bool btf_compat_fnproto(struct btf_type *t1, struct btf_type *t2)
{
{
	struct btf_param *m1, *m2;
	const struct btf_param *m1, *m2;
	__u16 vlen;
	__u16 vlen;
	int i;
	int i;


@@ -2000,9 +1970,9 @@ static bool btf_compat_fnproto(struct btf_type *t1, struct btf_type *t2)
	if (t1->name_off != t2->name_off || t1->info != t2->info)
	if (t1->name_off != t2->name_off || t1->info != t2->info)
		return false;
		return false;


	vlen = BTF_INFO_VLEN(t1->info);
	vlen = btf_vlen(t1);
	m1 = (struct btf_param *)(t1 + 1);
	m1 = btf_params(t1);
	m2 = (struct btf_param *)(t2 + 1);
	m2 = btf_params(t2);
	for (i = 0; i < vlen; i++) {
	for (i = 0; i < vlen; i++) {
		if (m1->name_off != m2->name_off)
		if (m1->name_off != m2->name_off)
			return false;
			return false;
@@ -2028,7 +1998,7 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)
	__u32 cand_id;
	__u32 cand_id;
	long h;
	long h;


	switch (BTF_INFO_KIND(t->info)) {
	switch (btf_kind(t)) {
	case BTF_KIND_CONST:
	case BTF_KIND_CONST:
	case BTF_KIND_VOLATILE:
	case BTF_KIND_VOLATILE:
	case BTF_KIND_RESTRICT:
	case BTF_KIND_RESTRICT:
@@ -2141,13 +2111,13 @@ static uint32_t resolve_fwd_id(struct btf_dedup *d, uint32_t type_id)
{
{
	__u32 orig_type_id = type_id;
	__u32 orig_type_id = type_id;


	if (BTF_INFO_KIND(d->btf->types[type_id]->info) != BTF_KIND_FWD)
	if (!btf_is_fwd(d->btf->types[type_id]))
		return type_id;
		return type_id;


	while (is_type_mapped(d, type_id) && d->map[type_id] != type_id)
	while (is_type_mapped(d, type_id) && d->map[type_id] != type_id)
		type_id = d->map[type_id];
		type_id = d->map[type_id];


	if (BTF_INFO_KIND(d->btf->types[type_id]->info) != BTF_KIND_FWD)
	if (!btf_is_fwd(d->btf->types[type_id]))
		return type_id;
		return type_id;


	return orig_type_id;
	return orig_type_id;
@@ -2156,7 +2126,7 @@ static uint32_t resolve_fwd_id(struct btf_dedup *d, uint32_t type_id)


static inline __u16 btf_fwd_kind(struct btf_type *t)
static inline __u16 btf_fwd_kind(struct btf_type *t)
{
{
	return BTF_INFO_KFLAG(t->info) ? BTF_KIND_UNION : BTF_KIND_STRUCT;
	return btf_kflag(t) ? BTF_KIND_UNION : BTF_KIND_STRUCT;
}
}


/*
/*
@@ -2277,8 +2247,8 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,


	cand_type = d->btf->types[cand_id];
	cand_type = d->btf->types[cand_id];
	canon_type = d->btf->types[canon_id];
	canon_type = d->btf->types[canon_id];
	cand_kind = BTF_INFO_KIND(cand_type->info);
	cand_kind = btf_kind(cand_type);
	canon_kind = BTF_INFO_KIND(canon_type->info);
	canon_kind = btf_kind(canon_type);


	if (cand_type->name_off != canon_type->name_off)
	if (cand_type->name_off != canon_type->name_off)
		return 0;
		return 0;
@@ -2327,12 +2297,12 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
		return btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
		return btf_dedup_is_equiv(d, cand_type->type, canon_type->type);


	case BTF_KIND_ARRAY: {
	case BTF_KIND_ARRAY: {
		struct btf_array *cand_arr, *canon_arr;
		const struct btf_array *cand_arr, *canon_arr;


		if (!btf_compat_array(cand_type, canon_type))
		if (!btf_compat_array(cand_type, canon_type))
			return 0;
			return 0;
		cand_arr = (struct btf_array *)(cand_type + 1);
		cand_arr = btf_array(cand_type);
		canon_arr = (struct btf_array *)(canon_type + 1);
		canon_arr = btf_array(canon_type);
		eq = btf_dedup_is_equiv(d,
		eq = btf_dedup_is_equiv(d,
			cand_arr->index_type, canon_arr->index_type);
			cand_arr->index_type, canon_arr->index_type);
		if (eq <= 0)
		if (eq <= 0)
@@ -2342,14 +2312,14 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,


	case BTF_KIND_STRUCT:
	case BTF_KIND_STRUCT:
	case BTF_KIND_UNION: {
	case BTF_KIND_UNION: {
		struct btf_member *cand_m, *canon_m;
		const struct btf_member *cand_m, *canon_m;
		__u16 vlen;
		__u16 vlen;


		if (!btf_shallow_equal_struct(cand_type, canon_type))
		if (!btf_shallow_equal_struct(cand_type, canon_type))
			return 0;
			return 0;
		vlen = BTF_INFO_VLEN(cand_type->info);
		vlen = btf_vlen(cand_type);
		cand_m = (struct btf_member *)(cand_type + 1);
		cand_m = btf_members(cand_type);
		canon_m = (struct btf_member *)(canon_type + 1);
		canon_m = btf_members(canon_type);
		for (i = 0; i < vlen; i++) {
		for (i = 0; i < vlen; i++) {
			eq = btf_dedup_is_equiv(d, cand_m->type, canon_m->type);
			eq = btf_dedup_is_equiv(d, cand_m->type, canon_m->type);
			if (eq <= 0)
			if (eq <= 0)
@@ -2362,7 +2332,7 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
	}
	}


	case BTF_KIND_FUNC_PROTO: {
	case BTF_KIND_FUNC_PROTO: {
		struct btf_param *cand_p, *canon_p;
		const struct btf_param *cand_p, *canon_p;
		__u16 vlen;
		__u16 vlen;


		if (!btf_compat_fnproto(cand_type, canon_type))
		if (!btf_compat_fnproto(cand_type, canon_type))
@@ -2370,9 +2340,9 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
		eq = btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
		eq = btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
		if (eq <= 0)
		if (eq <= 0)
			return eq;
			return eq;
		vlen = BTF_INFO_VLEN(cand_type->info);
		vlen = btf_vlen(cand_type);
		cand_p = (struct btf_param *)(cand_type + 1);
		cand_p = btf_params(cand_type);
		canon_p = (struct btf_param *)(canon_type + 1);
		canon_p = btf_params(canon_type);
		for (i = 0; i < vlen; i++) {
		for (i = 0; i < vlen; i++) {
			eq = btf_dedup_is_equiv(d, cand_p->type, canon_p->type);
			eq = btf_dedup_is_equiv(d, cand_p->type, canon_p->type);
			if (eq <= 0)
			if (eq <= 0)
@@ -2427,8 +2397,8 @@ static void btf_dedup_merge_hypot_map(struct btf_dedup *d)
		targ_type_id = d->hypot_map[cand_type_id];
		targ_type_id = d->hypot_map[cand_type_id];
		t_id = resolve_type_id(d, targ_type_id);
		t_id = resolve_type_id(d, targ_type_id);
		c_id = resolve_type_id(d, cand_type_id);
		c_id = resolve_type_id(d, cand_type_id);
		t_kind = BTF_INFO_KIND(d->btf->types[t_id]->info);
		t_kind = btf_kind(d->btf->types[t_id]);
		c_kind = BTF_INFO_KIND(d->btf->types[c_id]->info);
		c_kind = btf_kind(d->btf->types[c_id]);
		/*
		/*
		 * Resolve FWD into STRUCT/UNION.
		 * Resolve FWD into STRUCT/UNION.
		 * It's ok to resolve FWD into STRUCT/UNION that's not yet
		 * It's ok to resolve FWD into STRUCT/UNION that's not yet
@@ -2497,7 +2467,7 @@ static int btf_dedup_struct_type(struct btf_dedup *d, __u32 type_id)
		return 0;
		return 0;


	t = d->btf->types[type_id];
	t = d->btf->types[type_id];
	kind = BTF_INFO_KIND(t->info);
	kind = btf_kind(t);


	if (kind != BTF_KIND_STRUCT && kind != BTF_KIND_UNION)
	if (kind != BTF_KIND_STRUCT && kind != BTF_KIND_UNION)
		return 0;
		return 0;
@@ -2592,7 +2562,7 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
	t = d->btf->types[type_id];
	t = d->btf->types[type_id];
	d->map[type_id] = BTF_IN_PROGRESS_ID;
	d->map[type_id] = BTF_IN_PROGRESS_ID;


	switch (BTF_INFO_KIND(t->info)) {
	switch (btf_kind(t)) {
	case BTF_KIND_CONST:
	case BTF_KIND_CONST:
	case BTF_KIND_VOLATILE:
	case BTF_KIND_VOLATILE:
	case BTF_KIND_RESTRICT:
	case BTF_KIND_RESTRICT:
@@ -2616,7 +2586,7 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
		break;
		break;


	case BTF_KIND_ARRAY: {
	case BTF_KIND_ARRAY: {
		struct btf_array *info = (struct btf_array *)(t + 1);
		struct btf_array *info = btf_array(t);


		ref_type_id = btf_dedup_ref_type(d, info->type);
		ref_type_id = btf_dedup_ref_type(d, info->type);
		if (ref_type_id < 0)
		if (ref_type_id < 0)
@@ -2650,8 +2620,8 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
			return ref_type_id;
			return ref_type_id;
		t->type = ref_type_id;
		t->type = ref_type_id;


		vlen = BTF_INFO_VLEN(t->info);
		vlen = btf_vlen(t);
		param = (struct btf_param *)(t + 1);
		param = btf_params(t);
		for (i = 0; i < vlen; i++) {
		for (i = 0; i < vlen; i++) {
			ref_type_id = btf_dedup_ref_type(d, param->type);
			ref_type_id = btf_dedup_ref_type(d, param->type);
			if (ref_type_id < 0)
			if (ref_type_id < 0)
@@ -2791,7 +2761,7 @@ static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id)
	struct btf_type *t = d->btf->types[type_id];
	struct btf_type *t = d->btf->types[type_id];
	int i, r;
	int i, r;


	switch (BTF_INFO_KIND(t->info)) {
	switch (btf_kind(t)) {
	case BTF_KIND_INT:
	case BTF_KIND_INT:
	case BTF_KIND_ENUM:
	case BTF_KIND_ENUM:
		break;
		break;
@@ -2811,7 +2781,7 @@ static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id)
		break;
		break;


	case BTF_KIND_ARRAY: {
	case BTF_KIND_ARRAY: {
		struct btf_array *arr_info = (struct btf_array *)(t + 1);
		struct btf_array *arr_info = btf_array(t);


		r = btf_dedup_remap_type_id(d, arr_info->type);
		r = btf_dedup_remap_type_id(d, arr_info->type);
		if (r < 0)
		if (r < 0)
@@ -2826,8 +2796,8 @@ static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id)


	case BTF_KIND_STRUCT:
	case BTF_KIND_STRUCT:
	case BTF_KIND_UNION: {
	case BTF_KIND_UNION: {
		struct btf_member *member = (struct btf_member *)(t + 1);
		struct btf_member *member = btf_members(t);
		__u16 vlen = BTF_INFO_VLEN(t->info);
		__u16 vlen = btf_vlen(t);


		for (i = 0; i < vlen; i++) {
		for (i = 0; i < vlen; i++) {
			r = btf_dedup_remap_type_id(d, member->type);
			r = btf_dedup_remap_type_id(d, member->type);
@@ -2840,8 +2810,8 @@ static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id)
	}
	}


	case BTF_KIND_FUNC_PROTO: {
	case BTF_KIND_FUNC_PROTO: {
		struct btf_param *param = (struct btf_param *)(t + 1);
		struct btf_param *param = btf_params(t);
		__u16 vlen = BTF_INFO_VLEN(t->info);
		__u16 vlen = btf_vlen(t);


		r = btf_dedup_remap_type_id(d, t->type);
		r = btf_dedup_remap_type_id(d, t->type);
		if (r < 0)
		if (r < 0)
@@ -2859,8 +2829,8 @@ static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id)
	}
	}


	case BTF_KIND_DATASEC: {
	case BTF_KIND_DATASEC: {
		struct btf_var_secinfo *var = (struct btf_var_secinfo *)(t + 1);
		struct btf_var_secinfo *var = btf_var_secinfos(t);
		__u16 vlen = BTF_INFO_VLEN(t->info);
		__u16 vlen = btf_vlen(t);


		for (i = 0; i < vlen; i++) {
		for (i = 0; i < vlen; i++) {
			r = btf_dedup_remap_type_id(d, var->type);
			r = btf_dedup_remap_type_id(d, var->type);
+182 −0
Original line number Original line Diff line number Diff line
@@ -5,6 +5,7 @@
#define __LIBBPF_BTF_H
#define __LIBBPF_BTF_H


#include <stdarg.h>
#include <stdarg.h>
#include <linux/btf.h>
#include <linux/types.h>
#include <linux/types.h>


#ifdef __cplusplus
#ifdef __cplusplus
@@ -57,6 +58,10 @@ struct btf_ext_header {
	__u32	func_info_len;
	__u32	func_info_len;
	__u32	line_info_off;
	__u32	line_info_off;
	__u32	line_info_len;
	__u32	line_info_len;

	/* optional part of .BTF.ext header */
	__u32	offset_reloc_off;
	__u32	offset_reloc_len;
};
};


LIBBPF_API void btf__free(struct btf *btf);
LIBBPF_API void btf__free(struct btf *btf);
@@ -120,6 +125,183 @@ LIBBPF_API void btf_dump__free(struct btf_dump *d);


LIBBPF_API int btf_dump__dump_type(struct btf_dump *d, __u32 id);
LIBBPF_API int btf_dump__dump_type(struct btf_dump *d, __u32 id);


/*
 * A set of helpers for easier BTF types handling
 */
static inline __u16 btf_kind(const struct btf_type *t)
{
	return BTF_INFO_KIND(t->info);
}

static inline __u16 btf_vlen(const struct btf_type *t)
{
	return BTF_INFO_VLEN(t->info);
}

static inline bool btf_kflag(const struct btf_type *t)
{
	return BTF_INFO_KFLAG(t->info);
}

static inline bool btf_is_int(const struct btf_type *t)
{
	return btf_kind(t) == BTF_KIND_INT;
}

static inline bool btf_is_ptr(const struct btf_type *t)
{
	return btf_kind(t) == BTF_KIND_PTR;
}

static inline bool btf_is_array(const struct btf_type *t)
{
	return btf_kind(t) == BTF_KIND_ARRAY;
}

static inline bool btf_is_struct(const struct btf_type *t)
{
	return btf_kind(t) == BTF_KIND_STRUCT;
}

static inline bool btf_is_union(const struct btf_type *t)
{
	return btf_kind(t) == BTF_KIND_UNION;
}

static inline bool btf_is_composite(const struct btf_type *t)
{
	__u16 kind = btf_kind(t);

	return kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION;
}

static inline bool btf_is_enum(const struct btf_type *t)
{
	return btf_kind(t) == BTF_KIND_ENUM;
}

static inline bool btf_is_fwd(const struct btf_type *t)
{
	return btf_kind(t) == BTF_KIND_FWD;
}

static inline bool btf_is_typedef(const struct btf_type *t)
{
	return btf_kind(t) == BTF_KIND_TYPEDEF;
}

static inline bool btf_is_volatile(const struct btf_type *t)
{
	return btf_kind(t) == BTF_KIND_VOLATILE;
}

static inline bool btf_is_const(const struct btf_type *t)
{
	return btf_kind(t) == BTF_KIND_CONST;
}

static inline bool btf_is_restrict(const struct btf_type *t)
{
	return btf_kind(t) == BTF_KIND_RESTRICT;
}

static inline bool btf_is_mod(const struct btf_type *t)
{
	__u16 kind = btf_kind(t);

	return kind == BTF_KIND_VOLATILE ||
	       kind == BTF_KIND_CONST ||
	       kind == BTF_KIND_RESTRICT;
}

static inline bool btf_is_func(const struct btf_type *t)
{
	return btf_kind(t) == BTF_KIND_FUNC;
}

static inline bool btf_is_func_proto(const struct btf_type *t)
{
	return btf_kind(t) == BTF_KIND_FUNC_PROTO;
}

static inline bool btf_is_var(const struct btf_type *t)
{
	return btf_kind(t) == BTF_KIND_VAR;
}

static inline bool btf_is_datasec(const struct btf_type *t)
{
	return btf_kind(t) == BTF_KIND_DATASEC;
}

static inline __u8 btf_int_encoding(const struct btf_type *t)
{
	return BTF_INT_ENCODING(*(__u32 *)(t + 1));
}

static inline __u8 btf_int_offset(const struct btf_type *t)
{
	return BTF_INT_OFFSET(*(__u32 *)(t + 1));
}

static inline __u8 btf_int_bits(const struct btf_type *t)
{
	return BTF_INT_BITS(*(__u32 *)(t + 1));
}

static inline struct btf_array *btf_array(const struct btf_type *t)
{
	return (struct btf_array *)(t + 1);
}

static inline struct btf_enum *btf_enum(const struct btf_type *t)
{
	return (struct btf_enum *)(t + 1);
}

static inline struct btf_member *btf_members(const struct btf_type *t)
{
	return (struct btf_member *)(t + 1);
}

/* Get bit offset of a member with specified index. */
static inline __u32 btf_member_bit_offset(const struct btf_type *t,
					  __u32 member_idx)
{
	const struct btf_member *m = btf_members(t) + member_idx;
	bool kflag = btf_kflag(t);

	return kflag ? BTF_MEMBER_BIT_OFFSET(m->offset) : m->offset;
}
/*
 * Get bitfield size of a member, assuming t is BTF_KIND_STRUCT or
 * BTF_KIND_UNION. If member is not a bitfield, zero is returned.
 */
static inline __u32 btf_member_bitfield_size(const struct btf_type *t,
					     __u32 member_idx)
{
	const struct btf_member *m = btf_members(t) + member_idx;
	bool kflag = btf_kflag(t);

	return kflag ? BTF_MEMBER_BITFIELD_SIZE(m->offset) : 0;
}

static inline struct btf_param *btf_params(const struct btf_type *t)
{
	return (struct btf_param *)(t + 1);
}

static inline struct btf_var *btf_var(const struct btf_type *t)
{
	return (struct btf_var *)(t + 1);
}

static inline struct btf_var_secinfo *
btf_var_secinfos(const struct btf_type *t)
{
	return (struct btf_var_secinfo *)(t + 1);
}

#ifdef __cplusplus
#ifdef __cplusplus
} /* extern "C" */
} /* extern "C" */
#endif
#endif
+46 −92

File changed.

Preview size limit exceeded, changes collapsed.

+892 −49

File changed.

Preview size limit exceeded, changes collapsed.

+1 −0
Original line number Original line Diff line number Diff line
@@ -92,6 +92,7 @@ LIBBPF_API void bpf_object__close(struct bpf_object *object);
struct bpf_object_load_attr {
struct bpf_object_load_attr {
	struct bpf_object *obj;
	struct bpf_object *obj;
	int log_level;
	int log_level;
	const char *target_btf_path;
};
};


/* Load/unload object into/from kernel */
/* Load/unload object into/from kernel */
Loading