diff options
Diffstat (limited to 'tools/lib/bpf/btf.c')
| -rw-r--r-- | tools/lib/bpf/btf.c | 412 | 
1 files changed, 206 insertions, 206 deletions
| diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index bb1e06eb1eca..2d14f1a52d7a 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -130,7 +130,7 @@ static inline __u64 ptr_to_u64(const void *ptr)  /* Ensure given dynamically allocated memory region pointed to by *data* with   * capacity of *cap_cnt* elements each taking *elem_sz* bytes has enough - * memory to accomodate *add_cnt* new elements, assuming *cur_cnt* elements + * memory to accommodate *add_cnt* new elements, assuming *cur_cnt* elements   * are already used. At most *max_cnt* elements can be ever allocated.   * If necessary, memory is reallocated and all existing data is copied over,   * new pointer to the memory region is stored at *data, new memory region @@ -305,6 +305,8 @@ static int btf_type_size(const struct btf_type *t)  		return base_size + sizeof(__u32);  	case BTF_KIND_ENUM:  		return base_size + vlen * sizeof(struct btf_enum); +	case BTF_KIND_ENUM64: +		return base_size + vlen * sizeof(struct btf_enum64);  	case BTF_KIND_ARRAY:  		return base_size + sizeof(struct btf_array);  	case BTF_KIND_STRUCT: @@ -334,6 +336,7 @@ static void btf_bswap_type_base(struct btf_type *t)  static int btf_bswap_type_rest(struct btf_type *t)  {  	struct btf_var_secinfo *v; +	struct btf_enum64 *e64;  	struct btf_member *m;  	struct btf_array *a;  	struct btf_param *p; @@ -361,6 +364,13 @@ static int btf_bswap_type_rest(struct btf_type *t)  			e->val = bswap_32(e->val);  		}  		return 0; +	case BTF_KIND_ENUM64: +		for (i = 0, e64 = btf_enum64(t); i < vlen; i++, e64++) { +			e64->name_off = bswap_32(e64->name_off); +			e64->val_lo32 = bswap_32(e64->val_lo32); +			e64->val_hi32 = bswap_32(e64->val_hi32); +		} +		return 0;  	case BTF_KIND_ARRAY:  		a = btf_array(t);  		a->type = bswap_32(a->type); @@ -438,11 +448,6 @@ static int btf_parse_type_sec(struct btf *btf)  	return 0;  } -__u32 btf__get_nr_types(const struct btf *btf) -{ -	return btf->start_id + btf->nr_types - 1; -} -  __u32 btf__type_cnt(const struct btf *btf)  {  	return btf->start_id + btf->nr_types; @@ -472,9 +477,22 @@ const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 type_id)  static int determine_ptr_size(const struct btf *btf)  { +	static const char * const long_aliases[] = { +		"long", +		"long int", +		"int long", +		"unsigned long", +		"long unsigned", +		"unsigned long int", +		"unsigned int long", +		"long unsigned int", +		"long int unsigned", +		"int unsigned long", +		"int long unsigned", +	};  	const struct btf_type *t;  	const char *name; -	int i, n; +	int i, j, n;  	if (btf->base_btf && btf->base_btf->ptr_sz > 0)  		return btf->base_btf->ptr_sz; @@ -485,15 +503,16 @@ static int determine_ptr_size(const struct btf *btf)  		if (!btf_is_int(t))  			continue; +		if (t->size != 4 && t->size != 8) +			continue; +  		name = btf__name_by_offset(btf, t->name_off);  		if (!name)  			continue; -		if (strcmp(name, "long int") == 0 || -		    strcmp(name, "long unsigned int") == 0) { -			if (t->size != 4 && t->size != 8) -				continue; -			return t->size; +		for (j = 0; j < ARRAY_SIZE(long_aliases); j++) { +			if (strcmp(name, long_aliases[j]) == 0) +				return t->size;  		}  	} @@ -597,6 +616,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)  		case BTF_KIND_STRUCT:  		case BTF_KIND_UNION:  		case BTF_KIND_ENUM: +		case BTF_KIND_ENUM64:  		case BTF_KIND_DATASEC:  		case BTF_KIND_FLOAT:  			size = t->size; @@ -644,6 +664,7 @@ int btf__align_of(const struct btf *btf, __u32 id)  	switch (kind) {  	case BTF_KIND_INT:  	case BTF_KIND_ENUM: +	case BTF_KIND_ENUM64:  	case BTF_KIND_FLOAT:  		return min(btf_ptr_sz(btf), (size_t)t->size);  	case BTF_KIND_PTR: @@ -1382,92 +1403,6 @@ struct btf *btf__load_from_kernel_by_id(__u32 id)  	return btf__load_from_kernel_by_id_split(id, NULL);  } -int btf__get_from_id(__u32 id, struct btf **btf) -{ -	struct btf *res; -	int err; - -	*btf = NULL; -	res = btf__load_from_kernel_by_id(id); -	err = libbpf_get_error(res); - -	if (err) -		return libbpf_err(err); - -	*btf = res; -	return 0; -} - -int btf__get_map_kv_tids(const struct btf *btf, const char *map_name, -			 __u32 expected_key_size, __u32 expected_value_size, -			 __u32 *key_type_id, __u32 *value_type_id) -{ -	const struct btf_type *container_type; -	const struct btf_member *key, *value; -	const size_t max_name = 256; -	char container_name[max_name]; -	__s64 key_size, value_size; -	__s32 container_id; - -	if (snprintf(container_name, max_name, "____btf_map_%s", map_name) == max_name) { -		pr_warn("map:%s length of '____btf_map_%s' is too long\n", -			map_name, map_name); -		return libbpf_err(-EINVAL); -	} - -	container_id = btf__find_by_name(btf, container_name); -	if (container_id < 0) { -		pr_debug("map:%s container_name:%s cannot be found in BTF. Missing BPF_ANNOTATE_KV_PAIR?\n", -			 map_name, container_name); -		return libbpf_err(container_id); -	} - -	container_type = btf__type_by_id(btf, container_id); -	if (!container_type) { -		pr_warn("map:%s cannot find BTF type for container_id:%u\n", -			map_name, container_id); -		return libbpf_err(-EINVAL); -	} - -	if (!btf_is_struct(container_type) || btf_vlen(container_type) < 2) { -		pr_warn("map:%s container_name:%s is an invalid container struct\n", -			map_name, container_name); -		return libbpf_err(-EINVAL); -	} - -	key = btf_members(container_type); -	value = key + 1; - -	key_size = btf__resolve_size(btf, key->type); -	if (key_size < 0) { -		pr_warn("map:%s invalid BTF key_type_size\n", map_name); -		return libbpf_err(key_size); -	} - -	if (expected_key_size != key_size) { -		pr_warn("map:%s btf_key_type_size:%u != map_def_key_size:%u\n", -			map_name, (__u32)key_size, expected_key_size); -		return libbpf_err(-EINVAL); -	} - -	value_size = btf__resolve_size(btf, value->type); -	if (value_size < 0) { -		pr_warn("map:%s invalid BTF value_type_size\n", map_name); -		return libbpf_err(value_size); -	} - -	if (expected_value_size != value_size) { -		pr_warn("map:%s btf_value_type_size:%u != map_def_value_size:%u\n", -			map_name, (__u32)value_size, expected_value_size); -		return libbpf_err(-EINVAL); -	} - -	*key_type_id = key->type; -	*value_type_id = value->type; - -	return 0; -} -  static void btf_invalidate_raw_data(struct btf *btf)  {  	if (btf->raw_data) { @@ -2115,20 +2050,8 @@ int btf__add_field(struct btf *btf, const char *name, int type_id,  	return 0;  } -/* - * Append new BTF_KIND_ENUM type with: - *   - *name* - name of the enum, can be NULL or empty for anonymous enums; - *   - *byte_sz* - size of the enum, in bytes. - * - * Enum initially has no enum values in it (and corresponds to enum forward - * declaration). Enumerator values can be added by btf__add_enum_value() - * immediately after btf__add_enum() succeeds. - * - * Returns: - *   - >0, type ID of newly added BTF type; - *   - <0, on error. - */ -int btf__add_enum(struct btf *btf, const char *name, __u32 byte_sz) +static int btf_add_enum_common(struct btf *btf, const char *name, __u32 byte_sz, +			       bool is_signed, __u8 kind)  {  	struct btf_type *t;  	int sz, name_off = 0; @@ -2153,13 +2076,35 @@ int btf__add_enum(struct btf *btf, const char *name, __u32 byte_sz)  	/* start out with vlen=0; it will be adjusted when adding enum values */  	t->name_off = name_off; -	t->info = btf_type_info(BTF_KIND_ENUM, 0, 0); +	t->info = btf_type_info(kind, 0, is_signed);  	t->size = byte_sz;  	return btf_commit_type(btf, sz);  }  /* + * Append new BTF_KIND_ENUM type with: + *   - *name* - name of the enum, can be NULL or empty for anonymous enums; + *   - *byte_sz* - size of the enum, in bytes. + * + * Enum initially has no enum values in it (and corresponds to enum forward + * declaration). Enumerator values can be added by btf__add_enum_value() + * immediately after btf__add_enum() succeeds. + * + * Returns: + *   - >0, type ID of newly added BTF type; + *   - <0, on error. + */ +int btf__add_enum(struct btf *btf, const char *name, __u32 byte_sz) +{ +	/* +	 * set the signedness to be unsigned, it will change to signed +	 * if any later enumerator is negative. +	 */ +	return btf_add_enum_common(btf, name, byte_sz, false, BTF_KIND_ENUM); +} + +/*   * Append new enum value for the current ENUM type with:   *   - *name* - name of the enumerator value, can't be NULL or empty;   *   - *value* - integer value corresponding to enum value *name*; @@ -2206,6 +2151,82 @@ int btf__add_enum_value(struct btf *btf, const char *name, __s64 value)  	t = btf_last_type(btf);  	btf_type_inc_vlen(t); +	/* if negative value, set signedness to signed */ +	if (value < 0) +		t->info = btf_type_info(btf_kind(t), btf_vlen(t), true); + +	btf->hdr->type_len += sz; +	btf->hdr->str_off += sz; +	return 0; +} + +/* + * Append new BTF_KIND_ENUM64 type with: + *   - *name* - name of the enum, can be NULL or empty for anonymous enums; + *   - *byte_sz* - size of the enum, in bytes. + *   - *is_signed* - whether the enum values are signed or not; + * + * Enum initially has no enum values in it (and corresponds to enum forward + * declaration). Enumerator values can be added by btf__add_enum64_value() + * immediately after btf__add_enum64() succeeds. + * + * Returns: + *   - >0, type ID of newly added BTF type; + *   - <0, on error. + */ +int btf__add_enum64(struct btf *btf, const char *name, __u32 byte_sz, +		    bool is_signed) +{ +	return btf_add_enum_common(btf, name, byte_sz, is_signed, +				   BTF_KIND_ENUM64); +} + +/* + * Append new enum value for the current ENUM64 type with: + *   - *name* - name of the enumerator value, can't be NULL or empty; + *   - *value* - integer value corresponding to enum value *name*; + * Returns: + *   -  0, on success; + *   - <0, on error. + */ +int btf__add_enum64_value(struct btf *btf, const char *name, __u64 value) +{ +	struct btf_enum64 *v; +	struct btf_type *t; +	int sz, name_off; + +	/* last type should be BTF_KIND_ENUM64 */ +	if (btf->nr_types == 0) +		return libbpf_err(-EINVAL); +	t = btf_last_type(btf); +	if (!btf_is_enum64(t)) +		return libbpf_err(-EINVAL); + +	/* non-empty name */ +	if (!name || !name[0]) +		return libbpf_err(-EINVAL); + +	/* decompose and invalidate raw data */ +	if (btf_ensure_modifiable(btf)) +		return libbpf_err(-ENOMEM); + +	sz = sizeof(struct btf_enum64); +	v = btf_add_type_mem(btf, sz); +	if (!v) +		return libbpf_err(-ENOMEM); + +	name_off = btf__add_str(btf, name); +	if (name_off < 0) +		return name_off; + +	v->name_off = name_off; +	v->val_lo32 = (__u32)value; +	v->val_hi32 = value >> 32; + +	/* update parent type's vlen */ +	t = btf_last_type(btf); +	btf_type_inc_vlen(t); +  	btf->hdr->type_len += sz;  	btf->hdr->str_off += sz;  	return 0; @@ -2853,81 +2874,6 @@ const void *btf_ext__get_raw_data(const struct btf_ext *btf_ext, __u32 *size)  	return btf_ext->data;  } -static int btf_ext_reloc_info(const struct btf *btf, -			      const struct btf_ext_info *ext_info, -			      const char *sec_name, __u32 insns_cnt, -			      void **info, __u32 *cnt) -{ -	__u32 sec_hdrlen = sizeof(struct btf_ext_info_sec); -	__u32 i, record_size, existing_len, records_len; -	struct btf_ext_info_sec *sinfo; -	const char *info_sec_name; -	__u64 remain_len; -	void *data; - -	record_size = ext_info->rec_size; -	sinfo = ext_info->info; -	remain_len = ext_info->len; -	while (remain_len > 0) { -		records_len = sinfo->num_info * record_size; -		info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off); -		if (strcmp(info_sec_name, sec_name)) { -			remain_len -= sec_hdrlen + records_len; -			sinfo = (void *)sinfo + sec_hdrlen + records_len; -			continue; -		} - -		existing_len = (*cnt) * record_size; -		data = realloc(*info, existing_len + records_len); -		if (!data) -			return libbpf_err(-ENOMEM); - -		memcpy(data + existing_len, sinfo->data, records_len); -		/* adjust insn_off only, the rest data will be passed -		 * to the kernel. -		 */ -		for (i = 0; i < sinfo->num_info; i++) { -			__u32 *insn_off; - -			insn_off = data + existing_len + (i * record_size); -			*insn_off = *insn_off / sizeof(struct bpf_insn) + insns_cnt; -		} -		*info = data; -		*cnt += sinfo->num_info; -		return 0; -	} - -	return libbpf_err(-ENOENT); -} - -int btf_ext__reloc_func_info(const struct btf *btf, -			     const struct btf_ext *btf_ext, -			     const char *sec_name, __u32 insns_cnt, -			     void **func_info, __u32 *cnt) -{ -	return btf_ext_reloc_info(btf, &btf_ext->func_info, sec_name, -				  insns_cnt, func_info, cnt); -} - -int btf_ext__reloc_line_info(const struct btf *btf, -			     const struct btf_ext *btf_ext, -			     const char *sec_name, __u32 insns_cnt, -			     void **line_info, __u32 *cnt) -{ -	return btf_ext_reloc_info(btf, &btf_ext->line_info, sec_name, -				  insns_cnt, line_info, cnt); -} - -__u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext) -{ -	return btf_ext->func_info.rec_size; -} - -__u32 btf_ext__line_info_rec_size(const struct btf_ext *btf_ext) -{ -	return btf_ext->line_info.rec_size; -} -  struct btf_dedup;  static struct btf_dedup *btf_dedup_new(struct btf *btf, const struct btf_dedup_opts *opts); @@ -3077,9 +3023,7 @@ static int btf_dedup_remap_types(struct btf_dedup *d);   * deduplicating structs/unions is described in greater details in comments for   * `btf_dedup_is_equiv` function.   */ - -DEFAULT_VERSION(btf__dedup_v0_6_0, btf__dedup, LIBBPF_0.6.0) -int btf__dedup_v0_6_0(struct btf *btf, const struct btf_dedup_opts *opts) +int btf__dedup(struct btf *btf, const struct btf_dedup_opts *opts)  {  	struct btf_dedup *d;  	int err; @@ -3139,19 +3083,6 @@ done:  	return libbpf_err(err);  } -COMPAT_VERSION(btf__dedup_deprecated, btf__dedup, LIBBPF_0.0.2) -int btf__dedup_deprecated(struct btf *btf, struct btf_ext *btf_ext, const void *unused_opts) -{ -	LIBBPF_OPTS(btf_dedup_opts, opts, .btf_ext = btf_ext); - -	if (unused_opts) { -		pr_warn("please use new version of btf__dedup() that supports options\n"); -		return libbpf_err(-ENOTSUP); -	} - -	return btf__dedup(btf, &opts); -} -  #define BTF_UNPROCESSED_ID ((__u32)-1)  #define BTF_IN_PROGRESS_ID ((__u32)-2) @@ -3470,7 +3401,7 @@ static bool btf_equal_int_tag(struct btf_type *t1, struct btf_type *t2)  	return info1 == info2;  } -/* Calculate type signature hash of ENUM. */ +/* Calculate type signature hash of ENUM/ENUM64. */  static long btf_hash_enum(struct btf_type *t)  {  	long h; @@ -3504,9 +3435,31 @@ static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)  	return true;  } +static bool btf_equal_enum64(struct btf_type *t1, struct btf_type *t2) +{ +	const struct btf_enum64 *m1, *m2; +	__u16 vlen; +	int i; + +	if (!btf_equal_common(t1, t2)) +		return false; + +	vlen = btf_vlen(t1); +	m1 = btf_enum64(t1); +	m2 = btf_enum64(t2); +	for (i = 0; i < vlen; i++) { +		if (m1->name_off != m2->name_off || m1->val_lo32 != m2->val_lo32 || +		    m1->val_hi32 != m2->val_hi32) +			return false; +		m1++; +		m2++; +	} +	return true; +} +  static inline bool btf_is_enum_fwd(struct btf_type *t)  { -	return btf_is_enum(t) && btf_vlen(t) == 0; +	return btf_is_any_enum(t) && btf_vlen(t) == 0;  }  static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2) @@ -3519,6 +3472,17 @@ static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)  	       t1->size == t2->size;  } +static bool btf_compat_enum64(struct btf_type *t1, struct btf_type *t2) +{ +	if (!btf_is_enum_fwd(t1) && !btf_is_enum_fwd(t2)) +		return btf_equal_enum64(t1, t2); + +	/* ignore vlen when comparing */ +	return t1->name_off == t2->name_off && +	       (t1->info & ~0xffff) == (t2->info & ~0xffff) && +	       t1->size == t2->size; +} +  /*   * Calculate type signature hash of STRUCT/UNION, ignoring referenced type IDs,   * as referenced type IDs equivalence is established separately during type @@ -3731,6 +3695,7 @@ static int btf_dedup_prep(struct btf_dedup *d)  			h = btf_hash_int_decl_tag(t);  			break;  		case BTF_KIND_ENUM: +		case BTF_KIND_ENUM64:  			h = btf_hash_enum(t);  			break;  		case BTF_KIND_STRUCT: @@ -3820,6 +3785,27 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)  		}  		break; +	case BTF_KIND_ENUM64: +		h = btf_hash_enum(t); +		for_each_dedup_cand(d, hash_entry, h) { +			cand_id = (__u32)(long)hash_entry->value; +			cand = btf_type_by_id(d->btf, cand_id); +			if (btf_equal_enum64(t, cand)) { +				new_id = cand_id; +				break; +			} +			if (btf_compat_enum64(t, cand)) { +				if (btf_is_enum_fwd(t)) { +					/* resolve fwd to full enum */ +					new_id = cand_id; +					break; +				} +				/* resolve canonical enum fwd to full enum */ +				d->map[cand_id] = type_id; +			} +		} +		break; +  	case BTF_KIND_FWD:  	case BTF_KIND_FLOAT:  		h = btf_hash_common(t); @@ -4115,6 +4101,9 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,  	case BTF_KIND_ENUM:  		return btf_compat_enum(cand_type, canon_type); +	case BTF_KIND_ENUM64: +		return btf_compat_enum64(cand_type, canon_type); +  	case BTF_KIND_FWD:  	case BTF_KIND_FLOAT:  		return btf_equal_common(cand_type, canon_type); @@ -4717,6 +4706,7 @@ int btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ct  	case BTF_KIND_INT:  	case BTF_KIND_FLOAT:  	case BTF_KIND_ENUM: +	case BTF_KIND_ENUM64:  		return 0;  	case BTF_KIND_FWD: @@ -4811,6 +4801,16 @@ int btf_type_visit_str_offs(struct btf_type *t, str_off_visit_fn visit, void *ct  		}  		break;  	} +	case BTF_KIND_ENUM64: { +		struct btf_enum64 *m = btf_enum64(t); + +		for (i = 0, n = btf_vlen(t); i < n; i++, m++) { +			err = visit(&m->name_off, ctx); +			if (err) +				return err; +		} +		break; +	}  	case BTF_KIND_FUNC_PROTO: {  		struct btf_param *m = btf_params(t); |