diff options
Diffstat (limited to 'tools/lib')
| -rw-r--r-- | tools/lib/bpf/Makefile | 17 | ||||
| -rw-r--r-- | tools/lib/bpf/bpf.c | 48 | ||||
| -rw-r--r-- | tools/lib/bpf/bpf.h | 23 | ||||
| -rw-r--r-- | tools/lib/bpf/btf.c | 272 | ||||
| -rw-r--r-- | tools/lib/bpf/btf_dump.c | 46 | ||||
| -rw-r--r-- | tools/lib/bpf/hashmap.c | 18 | ||||
| -rw-r--r-- | tools/lib/bpf/hashmap.h | 91 | ||||
| -rw-r--r-- | tools/lib/bpf/libbpf.c | 266 | ||||
| -rw-r--r-- | tools/lib/bpf/libbpf.map | 6 | ||||
| -rw-r--r-- | tools/lib/bpf/libbpf_probes.c | 1 | ||||
| -rw-r--r-- | tools/lib/bpf/ringbuf.c | 4 | ||||
| -rw-r--r-- | tools/lib/bpf/strset.c | 18 | ||||
| -rw-r--r-- | tools/lib/bpf/usdt.c | 63 | 
13 files changed, 591 insertions, 282 deletions
| diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index 4c904ef0b47e..477666f3d496 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -286,3 +286,20 @@ tags:  # Delete partially updated (corrupted) files on error  .DELETE_ON_ERROR: + +help: +	@echo 'libbpf common targets:' +	@echo '  HINT: use "V=1" to enable verbose build' +	@echo '  all     - build libraries and pkgconfig' +	@echo '  clean   - remove all generated files' +	@echo '  check   - check abi and version info' +	@echo '' +	@echo 'libbpf install targets:' +	@echo '  HINT: use "prefix"(defaults to "/usr/local") or "DESTDIR" (defaults to "/")' +	@echo '        to adjust target desitantion, e.g. "make prefix=/usr/local install"' +	@echo '  install          - build and install all headers, libraries and pkgconfig' +	@echo '  install_headers  - install only headers to include/bpf' +	@echo '' +	@echo 'libbpf make targets:' +	@echo '  tags    - use ctags to make tag information for source code browsing' +	@echo '  cscope  - use cscope to make interactive source code browsing database' diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 1d49a0352836..9aff98f42a3d 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -935,58 +935,98 @@ int bpf_link_get_next_id(__u32 start_id, __u32 *next_id)  	return bpf_obj_get_next_id(start_id, next_id, BPF_LINK_GET_NEXT_ID);  } -int bpf_prog_get_fd_by_id(__u32 id) +int bpf_prog_get_fd_by_id_opts(__u32 id, +			       const struct bpf_get_fd_by_id_opts *opts)  {  	const size_t attr_sz = offsetofend(union bpf_attr, open_flags);  	union bpf_attr attr;  	int fd; +	if (!OPTS_VALID(opts, bpf_get_fd_by_id_opts)) +		return libbpf_err(-EINVAL); +  	memset(&attr, 0, attr_sz);  	attr.prog_id = id; +	attr.open_flags = OPTS_GET(opts, open_flags, 0);  	fd = sys_bpf_fd(BPF_PROG_GET_FD_BY_ID, &attr, attr_sz);  	return libbpf_err_errno(fd);  } -int bpf_map_get_fd_by_id(__u32 id) +int bpf_prog_get_fd_by_id(__u32 id) +{ +	return bpf_prog_get_fd_by_id_opts(id, NULL); +} + +int bpf_map_get_fd_by_id_opts(__u32 id, +			      const struct bpf_get_fd_by_id_opts *opts)  {  	const size_t attr_sz = offsetofend(union bpf_attr, open_flags);  	union bpf_attr attr;  	int fd; +	if (!OPTS_VALID(opts, bpf_get_fd_by_id_opts)) +		return libbpf_err(-EINVAL); +  	memset(&attr, 0, attr_sz);  	attr.map_id = id; +	attr.open_flags = OPTS_GET(opts, open_flags, 0);  	fd = sys_bpf_fd(BPF_MAP_GET_FD_BY_ID, &attr, attr_sz);  	return libbpf_err_errno(fd);  } -int bpf_btf_get_fd_by_id(__u32 id) +int bpf_map_get_fd_by_id(__u32 id) +{ +	return bpf_map_get_fd_by_id_opts(id, NULL); +} + +int bpf_btf_get_fd_by_id_opts(__u32 id, +			      const struct bpf_get_fd_by_id_opts *opts)  {  	const size_t attr_sz = offsetofend(union bpf_attr, open_flags);  	union bpf_attr attr;  	int fd; +	if (!OPTS_VALID(opts, bpf_get_fd_by_id_opts)) +		return libbpf_err(-EINVAL); +  	memset(&attr, 0, attr_sz);  	attr.btf_id = id; +	attr.open_flags = OPTS_GET(opts, open_flags, 0);  	fd = sys_bpf_fd(BPF_BTF_GET_FD_BY_ID, &attr, attr_sz);  	return libbpf_err_errno(fd);  } -int bpf_link_get_fd_by_id(__u32 id) +int bpf_btf_get_fd_by_id(__u32 id) +{ +	return bpf_btf_get_fd_by_id_opts(id, NULL); +} + +int bpf_link_get_fd_by_id_opts(__u32 id, +			       const struct bpf_get_fd_by_id_opts *opts)  {  	const size_t attr_sz = offsetofend(union bpf_attr, open_flags);  	union bpf_attr attr;  	int fd; +	if (!OPTS_VALID(opts, bpf_get_fd_by_id_opts)) +		return libbpf_err(-EINVAL); +  	memset(&attr, 0, attr_sz);  	attr.link_id = id; +	attr.open_flags = OPTS_GET(opts, open_flags, 0);  	fd = sys_bpf_fd(BPF_LINK_GET_FD_BY_ID, &attr, attr_sz);  	return libbpf_err_errno(fd);  } +int bpf_link_get_fd_by_id(__u32 id) +{ +	return bpf_link_get_fd_by_id_opts(id, NULL); +} +  int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len)  {  	const size_t attr_sz = offsetofend(union bpf_attr, info); diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 9c50beabdd14..7468978d3c27 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -365,10 +365,26 @@ LIBBPF_API int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id);  LIBBPF_API int bpf_map_get_next_id(__u32 start_id, __u32 *next_id);  LIBBPF_API int bpf_btf_get_next_id(__u32 start_id, __u32 *next_id);  LIBBPF_API int bpf_link_get_next_id(__u32 start_id, __u32 *next_id); + +struct bpf_get_fd_by_id_opts { +	size_t sz; /* size of this struct for forward/backward compatibility */ +	__u32 open_flags; /* permissions requested for the operation on fd */ +	size_t :0; +}; +#define bpf_get_fd_by_id_opts__last_field open_flags +  LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id); +LIBBPF_API int bpf_prog_get_fd_by_id_opts(__u32 id, +				const struct bpf_get_fd_by_id_opts *opts);  LIBBPF_API int bpf_map_get_fd_by_id(__u32 id); +LIBBPF_API int bpf_map_get_fd_by_id_opts(__u32 id, +				const struct bpf_get_fd_by_id_opts *opts);  LIBBPF_API int bpf_btf_get_fd_by_id(__u32 id); +LIBBPF_API int bpf_btf_get_fd_by_id_opts(__u32 id, +				const struct bpf_get_fd_by_id_opts *opts);  LIBBPF_API int bpf_link_get_fd_by_id(__u32 id); +LIBBPF_API int bpf_link_get_fd_by_id_opts(__u32 id, +				const struct bpf_get_fd_by_id_opts *opts);  LIBBPF_API int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len);  struct bpf_prog_query_opts { @@ -393,8 +409,15 @@ LIBBPF_API int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf,  				 __u32 *buf_len, __u32 *prog_id, __u32 *fd_type,  				 __u64 *probe_offset, __u64 *probe_addr); +#ifdef __cplusplus +/* forward-declaring enums in C++ isn't compatible with pure C enums, so + * instead define bpf_enable_stats() as accepting int as an input + */ +LIBBPF_API int bpf_enable_stats(int type); +#else  enum bpf_stats_type; /* defined in up-to-date linux/bpf.h */  LIBBPF_API int bpf_enable_stats(enum bpf_stats_type type); +#endif  struct bpf_prog_bind_opts {  	size_t sz; /* size of this struct for forward/backward compatibility */ diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index d88647da2c7f..71e165b09ed5 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -1559,15 +1559,15 @@ struct btf_pipe {  static int btf_rewrite_str(__u32 *str_off, void *ctx)  {  	struct btf_pipe *p = ctx; -	void *mapped_off; +	long mapped_off;  	int off, err;  	if (!*str_off) /* nothing to do for empty strings */  		return 0;  	if (p->str_off_map && -	    hashmap__find(p->str_off_map, (void *)(long)*str_off, &mapped_off)) { -		*str_off = (__u32)(long)mapped_off; +	    hashmap__find(p->str_off_map, *str_off, &mapped_off)) { +		*str_off = mapped_off;  		return 0;  	} @@ -1579,7 +1579,7 @@ static int btf_rewrite_str(__u32 *str_off, void *ctx)  	 * performing expensive string comparisons.  	 */  	if (p->str_off_map) { -		err = hashmap__append(p->str_off_map, (void *)(long)*str_off, (void *)(long)off); +		err = hashmap__append(p->str_off_map, *str_off, off);  		if (err)  			return err;  	} @@ -1630,8 +1630,8 @@ static int btf_rewrite_type_ids(__u32 *type_id, void *ctx)  	return 0;  } -static size_t btf_dedup_identity_hash_fn(const void *key, void *ctx); -static bool btf_dedup_equal_fn(const void *k1, const void *k2, void *ctx); +static size_t btf_dedup_identity_hash_fn(long key, void *ctx); +static bool btf_dedup_equal_fn(long k1, long k2, void *ctx);  int btf__add_btf(struct btf *btf, const struct btf *src_btf)  { @@ -1724,7 +1724,8 @@ err_out:  	memset(btf->strs_data + old_strs_len, 0, btf->hdr->str_len - old_strs_len);  	/* and now restore original strings section size; types data size -	 * wasn't modified, so doesn't need restoring, see big comment above */ +	 * wasn't modified, so doesn't need restoring, see big comment above +	 */  	btf->hdr->str_len = old_strs_len;  	hashmap__free(p.str_off_map); @@ -2329,7 +2330,7 @@ int btf__add_restrict(struct btf *btf, int ref_type_id)   */  int btf__add_type_tag(struct btf *btf, const char *value, int ref_type_id)  { -	if (!value|| !value[0]) +	if (!value || !value[0])  		return libbpf_err(-EINVAL);  	return btf_add_ref_kind(btf, BTF_KIND_TYPE_TAG, value, ref_type_id); @@ -2881,6 +2882,7 @@ static int btf_dedup_strings(struct btf_dedup *d);  static int btf_dedup_prim_types(struct btf_dedup *d);  static int btf_dedup_struct_types(struct btf_dedup *d);  static int btf_dedup_ref_types(struct btf_dedup *d); +static int btf_dedup_resolve_fwds(struct btf_dedup *d);  static int btf_dedup_compact_types(struct btf_dedup *d);  static int btf_dedup_remap_types(struct btf_dedup *d); @@ -2988,15 +2990,16 @@ static int btf_dedup_remap_types(struct btf_dedup *d);   * Algorithm summary   * =================   * - * Algorithm completes its work in 6 separate passes: + * Algorithm completes its work in 7 separate passes:   *   * 1. Strings deduplication.   * 2. Primitive types deduplication (int, enum, fwd).   * 3. Struct/union types deduplication. - * 4. Reference types deduplication (pointers, typedefs, arrays, funcs, func + * 4. Resolve unambiguous forward declarations. + * 5. Reference types deduplication (pointers, typedefs, arrays, funcs, func   *    protos, and const/volatile/restrict modifiers). - * 5. Types compaction. - * 6. Types remapping. + * 6. Types compaction. + * 7. Types remapping.   *   * Algorithm determines canonical type descriptor, which is a single   * representative type for each truly unique type. This canonical type is the @@ -3060,6 +3063,11 @@ int btf__dedup(struct btf *btf, const struct btf_dedup_opts *opts)  		pr_debug("btf_dedup_struct_types failed:%d\n", err);  		goto done;  	} +	err = btf_dedup_resolve_fwds(d); +	if (err < 0) { +		pr_debug("btf_dedup_resolve_fwds failed:%d\n", err); +		goto done; +	}  	err = btf_dedup_ref_types(d);  	if (err < 0) {  		pr_debug("btf_dedup_ref_types failed:%d\n", err); @@ -3126,12 +3134,11 @@ static long hash_combine(long h, long value)  }  #define for_each_dedup_cand(d, node, hash) \ -	hashmap__for_each_key_entry(d->dedup_table, node, (void *)hash) +	hashmap__for_each_key_entry(d->dedup_table, node, hash)  static int btf_dedup_table_add(struct btf_dedup *d, long hash, __u32 type_id)  { -	return hashmap__append(d->dedup_table, -			       (void *)hash, (void *)(long)type_id); +	return hashmap__append(d->dedup_table, hash, type_id);  }  static int btf_dedup_hypot_map_add(struct btf_dedup *d, @@ -3178,17 +3185,17 @@ static void btf_dedup_free(struct btf_dedup *d)  	free(d);  } -static size_t btf_dedup_identity_hash_fn(const void *key, void *ctx) +static size_t btf_dedup_identity_hash_fn(long key, void *ctx)  { -	return (size_t)key; +	return key;  } -static size_t btf_dedup_collision_hash_fn(const void *key, void *ctx) +static size_t btf_dedup_collision_hash_fn(long key, void *ctx)  {  	return 0;  } -static bool btf_dedup_equal_fn(const void *k1, const void *k2, void *ctx) +static bool btf_dedup_equal_fn(long k1, long k2, void *ctx)  {  	return k1 == k2;  } @@ -3404,23 +3411,17 @@ static long btf_hash_enum(struct btf_type *t)  {  	long h; -	/* don't hash vlen and enum members to support enum fwd resolving */ +	/* don't hash vlen, enum members and size to support enum fwd resolving */  	h = hash_combine(0, t->name_off); -	h = hash_combine(h, t->info & ~0xffff); -	h = hash_combine(h, t->size);  	return h;  } -/* Check structural equality of two ENUMs. */ -static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2) +static bool btf_equal_enum_members(struct btf_type *t1, struct btf_type *t2)  {  	const struct btf_enum *m1, *m2;  	__u16 vlen;  	int i; -	if (!btf_equal_common(t1, t2)) -		return false; -  	vlen = btf_vlen(t1);  	m1 = btf_enum(t1);  	m2 = btf_enum(t2); @@ -3433,15 +3434,12 @@ 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) +static bool btf_equal_enum64_members(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); @@ -3455,6 +3453,19 @@ static bool btf_equal_enum64(struct btf_type *t1, struct btf_type *t2)  	return true;  } +/* Check structural equality of two ENUMs or ENUM64s. */ +static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2) +{ +	if (!btf_equal_common(t1, t2)) +		return false; + +	/* t1 & t2 kinds are identical because of btf_equal_common */ +	if (btf_kind(t1) == BTF_KIND_ENUM) +		return btf_equal_enum_members(t1, t2); +	else +		return btf_equal_enum64_members(t1, t2); +} +  static inline bool btf_is_enum_fwd(struct btf_type *t)  {  	return btf_is_any_enum(t) && btf_vlen(t) == 0; @@ -3464,21 +3475,14 @@ static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)  {  	if (!btf_is_enum_fwd(t1) && !btf_is_enum_fwd(t2))  		return btf_equal_enum(t1, t2); -	/* ignore vlen when comparing */ -	return t1->name_off == t2->name_off && -	       (t1->info & ~0xffff) == (t2->info & ~0xffff) && -	       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 */ +	/* At this point either t1 or t2 or both are forward declarations, thus: +	 * - skip comparing vlen because it is zero for forward declarations; +	 * - skip comparing size to allow enum forward declarations +	 *   to be compatible with enum64 full declarations; +	 * - skip comparing kind for the same reason. +	 */  	return t1->name_off == t2->name_off && -	       (t1->info & ~0xffff) == (t2->info & ~0xffff) && -	       t1->size == t2->size; +	       btf_is_any_enum(t1) && btf_is_any_enum(t2);  }  /* @@ -3753,7 +3757,7 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)  	case BTF_KIND_INT:  		h = btf_hash_int_decl_tag(t);  		for_each_dedup_cand(d, hash_entry, h) { -			cand_id = (__u32)(long)hash_entry->value; +			cand_id = hash_entry->value;  			cand = btf_type_by_id(d->btf, cand_id);  			if (btf_equal_int_tag(t, cand)) {  				new_id = cand_id; @@ -3763,9 +3767,10 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)  		break;  	case BTF_KIND_ENUM: +	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_id = hash_entry->value;  			cand = btf_type_by_id(d->btf, cand_id);  			if (btf_equal_enum(t, cand)) {  				new_id = cand_id; @@ -3783,32 +3788,11 @@ 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);  		for_each_dedup_cand(d, hash_entry, h) { -			cand_id = (__u32)(long)hash_entry->value; +			cand_id = hash_entry->value;  			cand = btf_type_by_id(d->btf, cand_id);  			if (btf_equal_common(t, cand)) {  				new_id = cand_id; @@ -3887,14 +3871,14 @@ static inline __u16 btf_fwd_kind(struct btf_type *t)  }  /* Check if given two types are identical ARRAY definitions */ -static int btf_dedup_identical_arrays(struct btf_dedup *d, __u32 id1, __u32 id2) +static bool btf_dedup_identical_arrays(struct btf_dedup *d, __u32 id1, __u32 id2)  {  	struct btf_type *t1, *t2;  	t1 = btf_type_by_id(d->btf, id1);  	t2 = btf_type_by_id(d->btf, id2);  	if (!btf_is_array(t1) || !btf_is_array(t2)) -		return 0; +		return false;  	return btf_equal_array(t1, t2);  } @@ -3918,7 +3902,9 @@ static bool btf_dedup_identical_structs(struct btf_dedup *d, __u32 id1, __u32 id  	m1 = btf_members(t1);  	m2 = btf_members(t2);  	for (i = 0, n = btf_vlen(t1); i < n; i++, m1++, m2++) { -		if (m1->type != m2->type) +		if (m1->type != m2->type && +		    !btf_dedup_identical_arrays(d, m1->type, m2->type) && +		    !btf_dedup_identical_structs(d, m1->type, m2->type))  			return false;  	}  	return true; @@ -4097,10 +4083,8 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,  		return btf_equal_int_tag(cand_type, canon_type);  	case BTF_KIND_ENUM: -		return btf_compat_enum(cand_type, canon_type); -  	case BTF_KIND_ENUM64: -		return btf_compat_enum64(cand_type, canon_type); +		return btf_compat_enum(cand_type, canon_type);  	case BTF_KIND_FWD:  	case BTF_KIND_FLOAT: @@ -4311,7 +4295,7 @@ static int btf_dedup_struct_type(struct btf_dedup *d, __u32 type_id)  	h = btf_hash_struct(t);  	for_each_dedup_cand(d, hash_entry, h) { -		__u32 cand_id = (__u32)(long)hash_entry->value; +		__u32 cand_id = hash_entry->value;  		int eq;  		/* @@ -4416,7 +4400,7 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)  		h = btf_hash_common(t);  		for_each_dedup_cand(d, hash_entry, h) { -			cand_id = (__u32)(long)hash_entry->value; +			cand_id = hash_entry->value;  			cand = btf_type_by_id(d->btf, cand_id);  			if (btf_equal_common(t, cand)) {  				new_id = cand_id; @@ -4433,7 +4417,7 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)  		h = btf_hash_int_decl_tag(t);  		for_each_dedup_cand(d, hash_entry, h) { -			cand_id = (__u32)(long)hash_entry->value; +			cand_id = hash_entry->value;  			cand = btf_type_by_id(d->btf, cand_id);  			if (btf_equal_int_tag(t, cand)) {  				new_id = cand_id; @@ -4457,7 +4441,7 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)  		h = btf_hash_array(t);  		for_each_dedup_cand(d, hash_entry, h) { -			cand_id = (__u32)(long)hash_entry->value; +			cand_id = hash_entry->value;  			cand = btf_type_by_id(d->btf, cand_id);  			if (btf_equal_array(t, cand)) {  				new_id = cand_id; @@ -4489,7 +4473,7 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)  		h = btf_hash_fnproto(t);  		for_each_dedup_cand(d, hash_entry, h) { -			cand_id = (__u32)(long)hash_entry->value; +			cand_id = hash_entry->value;  			cand = btf_type_by_id(d->btf, cand_id);  			if (btf_equal_fnproto(t, cand)) {  				new_id = cand_id; @@ -4526,6 +4510,134 @@ static int btf_dedup_ref_types(struct btf_dedup *d)  }  /* + * Collect a map from type names to type ids for all canonical structs + * and unions. If the same name is shared by several canonical types + * use a special value 0 to indicate this fact. + */ +static int btf_dedup_fill_unique_names_map(struct btf_dedup *d, struct hashmap *names_map) +{ +	__u32 nr_types = btf__type_cnt(d->btf); +	struct btf_type *t; +	__u32 type_id; +	__u16 kind; +	int err; + +	/* +	 * Iterate over base and split module ids in order to get all +	 * available structs in the map. +	 */ +	for (type_id = 1; type_id < nr_types; ++type_id) { +		t = btf_type_by_id(d->btf, type_id); +		kind = btf_kind(t); + +		if (kind != BTF_KIND_STRUCT && kind != BTF_KIND_UNION) +			continue; + +		/* Skip non-canonical types */ +		if (type_id != d->map[type_id]) +			continue; + +		err = hashmap__add(names_map, t->name_off, type_id); +		if (err == -EEXIST) +			err = hashmap__set(names_map, t->name_off, 0, NULL, NULL); + +		if (err) +			return err; +	} + +	return 0; +} + +static int btf_dedup_resolve_fwd(struct btf_dedup *d, struct hashmap *names_map, __u32 type_id) +{ +	struct btf_type *t = btf_type_by_id(d->btf, type_id); +	enum btf_fwd_kind fwd_kind = btf_kflag(t); +	__u16 cand_kind, kind = btf_kind(t); +	struct btf_type *cand_t; +	uintptr_t cand_id; + +	if (kind != BTF_KIND_FWD) +		return 0; + +	/* Skip if this FWD already has a mapping */ +	if (type_id != d->map[type_id]) +		return 0; + +	if (!hashmap__find(names_map, t->name_off, &cand_id)) +		return 0; + +	/* Zero is a special value indicating that name is not unique */ +	if (!cand_id) +		return 0; + +	cand_t = btf_type_by_id(d->btf, cand_id); +	cand_kind = btf_kind(cand_t); +	if ((cand_kind == BTF_KIND_STRUCT && fwd_kind != BTF_FWD_STRUCT) || +	    (cand_kind == BTF_KIND_UNION && fwd_kind != BTF_FWD_UNION)) +		return 0; + +	d->map[type_id] = cand_id; + +	return 0; +} + +/* + * Resolve unambiguous forward declarations. + * + * The lion's share of all FWD declarations is resolved during + * `btf_dedup_struct_types` phase when different type graphs are + * compared against each other. However, if in some compilation unit a + * FWD declaration is not a part of a type graph compared against + * another type graph that declaration's canonical type would not be + * changed. Example: + * + * CU #1: + * + * struct foo; + * struct foo *some_global; + * + * CU #2: + * + * struct foo { int u; }; + * struct foo *another_global; + * + * After `btf_dedup_struct_types` the BTF looks as follows: + * + * [1] STRUCT 'foo' size=4 vlen=1 ... + * [2] INT 'int' size=4 ... + * [3] PTR '(anon)' type_id=1 + * [4] FWD 'foo' fwd_kind=struct + * [5] PTR '(anon)' type_id=4 + * + * This pass assumes that such FWD declarations should be mapped to + * structs or unions with identical name in case if the name is not + * ambiguous. + */ +static int btf_dedup_resolve_fwds(struct btf_dedup *d) +{ +	int i, err; +	struct hashmap *names_map; + +	names_map = hashmap__new(btf_dedup_identity_hash_fn, btf_dedup_equal_fn, NULL); +	if (IS_ERR(names_map)) +		return PTR_ERR(names_map); + +	err = btf_dedup_fill_unique_names_map(d, names_map); +	if (err < 0) +		goto exit; + +	for (i = 0; i < d->btf->nr_types; i++) { +		err = btf_dedup_resolve_fwd(d, names_map, d->btf->start_id + i); +		if (err < 0) +			break; +	} + +exit: +	hashmap__free(names_map); +	return err; +} + +/*   * Compact types.   *   * After we established for each type its corresponding canonical representative diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c index 4221f73a74d0..deb2bc9a0a7b 100644 --- a/tools/lib/bpf/btf_dump.c +++ b/tools/lib/bpf/btf_dump.c @@ -117,14 +117,14 @@ struct btf_dump {  	struct btf_dump_data *typed_dump;  }; -static size_t str_hash_fn(const void *key, void *ctx) +static size_t str_hash_fn(long key, void *ctx)  { -	return str_hash(key); +	return str_hash((void *)key);  } -static bool str_equal_fn(const void *a, const void *b, void *ctx) +static bool str_equal_fn(long a, long b, void *ctx)  { -	return strcmp(a, b) == 0; +	return strcmp((void *)a, (void *)b) == 0;  }  static const char *btf_name_of(const struct btf_dump *d, __u32 name_off) @@ -219,6 +219,17 @@ static int btf_dump_resize(struct btf_dump *d)  	return 0;  } +static void btf_dump_free_names(struct hashmap *map) +{ +	size_t bkt; +	struct hashmap_entry *cur; + +	hashmap__for_each_entry(map, cur, bkt) +		free((void *)cur->pkey); + +	hashmap__free(map); +} +  void btf_dump__free(struct btf_dump *d)  {  	int i; @@ -237,8 +248,8 @@ void btf_dump__free(struct btf_dump *d)  	free(d->cached_names);  	free(d->emit_queue);  	free(d->decl_stack); -	hashmap__free(d->type_names); -	hashmap__free(d->ident_names); +	btf_dump_free_names(d->type_names); +	btf_dump_free_names(d->ident_names);  	free(d);  } @@ -944,7 +955,11 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,  					  lvl + 1);  	} -	if (vlen) +	/* +	 * Keep `struct empty {}` on a single line, +	 * only print newline when there are regular or padding fields. +	 */ +	if (vlen || t->size)  		btf_dump_printf(d, "\n");  	btf_dump_printf(d, "%s}", pfx(lvl));  	if (packed) @@ -1520,11 +1535,22 @@ static void btf_dump_emit_type_cast(struct btf_dump *d, __u32 id,  static size_t btf_dump_name_dups(struct btf_dump *d, struct hashmap *name_map,  				 const char *orig_name)  { +	char *old_name, *new_name;  	size_t dup_cnt = 0; +	int err; + +	new_name = strdup(orig_name); +	if (!new_name) +		return 1; -	hashmap__find(name_map, orig_name, (void **)&dup_cnt); +	(void)hashmap__find(name_map, orig_name, &dup_cnt);  	dup_cnt++; -	hashmap__set(name_map, orig_name, (void *)dup_cnt, NULL, NULL); + +	err = hashmap__set(name_map, new_name, dup_cnt, &old_name, NULL); +	if (err) +		free(new_name); + +	free(old_name);  	return dup_cnt;  } @@ -1963,7 +1989,7 @@ static int btf_dump_struct_data(struct btf_dump *d,  {  	const struct btf_member *m = btf_members(t);  	__u16 n = btf_vlen(t); -	int i, err; +	int i, err = 0;  	/* note that we increment depth before calling btf_dump_print() below;  	 * this is intentional.  btf_dump_data_newline() will not print a diff --git a/tools/lib/bpf/hashmap.c b/tools/lib/bpf/hashmap.c index aeb09c288716..140ee4055676 100644 --- a/tools/lib/bpf/hashmap.c +++ b/tools/lib/bpf/hashmap.c @@ -128,7 +128,7 @@ static int hashmap_grow(struct hashmap *map)  }  static bool hashmap_find_entry(const struct hashmap *map, -			       const void *key, size_t hash, +			       const long key, size_t hash,  			       struct hashmap_entry ***pprev,  			       struct hashmap_entry **entry)  { @@ -151,18 +151,18 @@ static bool hashmap_find_entry(const struct hashmap *map,  	return false;  } -int hashmap__insert(struct hashmap *map, const void *key, void *value, -		    enum hashmap_insert_strategy strategy, -		    const void **old_key, void **old_value) +int hashmap_insert(struct hashmap *map, long key, long value, +		   enum hashmap_insert_strategy strategy, +		   long *old_key, long *old_value)  {  	struct hashmap_entry *entry;  	size_t h;  	int err;  	if (old_key) -		*old_key = NULL; +		*old_key = 0;  	if (old_value) -		*old_value = NULL; +		*old_value = 0;  	h = hash_bits(map->hash_fn(key, map->ctx), map->cap_bits);  	if (strategy != HASHMAP_APPEND && @@ -203,7 +203,7 @@ int hashmap__insert(struct hashmap *map, const void *key, void *value,  	return 0;  } -bool hashmap__find(const struct hashmap *map, const void *key, void **value) +bool hashmap_find(const struct hashmap *map, long key, long *value)  {  	struct hashmap_entry *entry;  	size_t h; @@ -217,8 +217,8 @@ bool hashmap__find(const struct hashmap *map, const void *key, void **value)  	return true;  } -bool hashmap__delete(struct hashmap *map, const void *key, -		     const void **old_key, void **old_value) +bool hashmap_delete(struct hashmap *map, long key, +		    long *old_key, long *old_value)  {  	struct hashmap_entry **pprev, *entry;  	size_t h; diff --git a/tools/lib/bpf/hashmap.h b/tools/lib/bpf/hashmap.h index 10a4c4cd13cf..0a5bf1937a7c 100644 --- a/tools/lib/bpf/hashmap.h +++ b/tools/lib/bpf/hashmap.h @@ -40,12 +40,32 @@ static inline size_t str_hash(const char *s)  	return h;  } -typedef size_t (*hashmap_hash_fn)(const void *key, void *ctx); -typedef bool (*hashmap_equal_fn)(const void *key1, const void *key2, void *ctx); +typedef size_t (*hashmap_hash_fn)(long key, void *ctx); +typedef bool (*hashmap_equal_fn)(long key1, long key2, void *ctx); +/* + * Hashmap interface is polymorphic, keys and values could be either + * long-sized integers or pointers, this is achieved as follows: + * - interface functions that operate on keys and values are hidden + *   behind auxiliary macros, e.g. hashmap_insert <-> hashmap__insert; + * - these auxiliary macros cast the key and value parameters as + *   long or long *, so the user does not have to specify the casts explicitly; + * - for pointer parameters (e.g. old_key) the size of the pointed + *   type is verified by hashmap_cast_ptr using _Static_assert; + * - when iterating using hashmap__for_each_* forms + *   hasmap_entry->key should be used for integer keys and + *   hasmap_entry->pkey should be used for pointer keys, + *   same goes for values. + */  struct hashmap_entry { -	const void *key; -	void *value; +	union { +		long key; +		const void *pkey; +	}; +	union { +		long value; +		void *pvalue; +	};  	struct hashmap_entry *next;  }; @@ -102,6 +122,13 @@ enum hashmap_insert_strategy {  	HASHMAP_APPEND,  }; +#define hashmap_cast_ptr(p) ({								\ +	_Static_assert((__builtin_constant_p((p)) ? (p) == NULL : 0) ||			\ +				sizeof(*(p)) == sizeof(long),				\ +		       #p " pointee should be a long-sized integer or a pointer");	\ +	(long *)(p);									\ +}) +  /*   * hashmap__insert() adds key/value entry w/ various semantics, depending on   * provided strategy value. If a given key/value pair replaced already @@ -109,42 +136,38 @@ enum hashmap_insert_strategy {   * through old_key and old_value to allow calling code do proper memory   * management.   */ -int hashmap__insert(struct hashmap *map, const void *key, void *value, -		    enum hashmap_insert_strategy strategy, -		    const void **old_key, void **old_value); +int hashmap_insert(struct hashmap *map, long key, long value, +		   enum hashmap_insert_strategy strategy, +		   long *old_key, long *old_value); -static inline int hashmap__add(struct hashmap *map, -			       const void *key, void *value) -{ -	return hashmap__insert(map, key, value, HASHMAP_ADD, NULL, NULL); -} +#define hashmap__insert(map, key, value, strategy, old_key, old_value) \ +	hashmap_insert((map), (long)(key), (long)(value), (strategy),  \ +		       hashmap_cast_ptr(old_key),		       \ +		       hashmap_cast_ptr(old_value)) -static inline int hashmap__set(struct hashmap *map, -			       const void *key, void *value, -			       const void **old_key, void **old_value) -{ -	return hashmap__insert(map, key, value, HASHMAP_SET, -			       old_key, old_value); -} +#define hashmap__add(map, key, value) \ +	hashmap__insert((map), (key), (value), HASHMAP_ADD, NULL, NULL) -static inline int hashmap__update(struct hashmap *map, -				  const void *key, void *value, -				  const void **old_key, void **old_value) -{ -	return hashmap__insert(map, key, value, HASHMAP_UPDATE, -			       old_key, old_value); -} +#define hashmap__set(map, key, value, old_key, old_value) \ +	hashmap__insert((map), (key), (value), HASHMAP_SET, (old_key), (old_value)) -static inline int hashmap__append(struct hashmap *map, -				  const void *key, void *value) -{ -	return hashmap__insert(map, key, value, HASHMAP_APPEND, NULL, NULL); -} +#define hashmap__update(map, key, value, old_key, old_value) \ +	hashmap__insert((map), (key), (value), HASHMAP_UPDATE, (old_key), (old_value)) + +#define hashmap__append(map, key, value) \ +	hashmap__insert((map), (key), (value), HASHMAP_APPEND, NULL, NULL) + +bool hashmap_delete(struct hashmap *map, long key, long *old_key, long *old_value); + +#define hashmap__delete(map, key, old_key, old_value)		       \ +	hashmap_delete((map), (long)(key),			       \ +		       hashmap_cast_ptr(old_key),		       \ +		       hashmap_cast_ptr(old_value)) -bool hashmap__delete(struct hashmap *map, const void *key, -		     const void **old_key, void **old_value); +bool hashmap_find(const struct hashmap *map, long key, long *value); -bool hashmap__find(const struct hashmap *map, const void *key, void **value); +#define hashmap__find(map, key, value) \ +	hashmap_find((map), (long)(key), hashmap_cast_ptr(value))  /*   * hashmap__for_each_entry - iterate over all entries in hashmap diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 91b7106a4a73..2a82f49ce16f 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -164,6 +164,7 @@ static const char * const map_type_name[] = {  	[BPF_MAP_TYPE_TASK_STORAGE]		= "task_storage",  	[BPF_MAP_TYPE_BLOOM_FILTER]		= "bloom_filter",  	[BPF_MAP_TYPE_USER_RINGBUF]             = "user_ringbuf", +	[BPF_MAP_TYPE_CGRP_STORAGE]		= "cgrp_storage",  };  static const char * const prog_type_name[] = { @@ -346,7 +347,8 @@ enum sec_def_flags {  	SEC_ATTACHABLE = 2,  	SEC_ATTACHABLE_OPT = SEC_ATTACHABLE | SEC_EXP_ATTACH_OPT,  	/* attachment target is specified through BTF ID in either kernel or -	 * other BPF program's BTF object */ +	 * other BPF program's BTF object +	 */  	SEC_ATTACH_BTF = 4,  	/* BPF program type allows sleeping/blocking in kernel */  	SEC_SLEEPABLE = 8, @@ -487,7 +489,7 @@ struct bpf_map {  	char *name;  	/* real_name is defined for special internal maps (.rodata*,  	 * .data*, .bss, .kconfig) and preserves their original ELF section -	 * name. This is important to be be able to find corresponding BTF +	 * name. This is important to be able to find corresponding BTF  	 * DATASEC information.  	 */  	char *real_name; @@ -597,7 +599,7 @@ struct elf_state {  	size_t shstrndx; /* section index for section name strings */  	size_t strtabidx;  	struct elf_sec_desc *secs; -	int sec_cnt; +	size_t sec_cnt;  	int btf_maps_shndx;  	__u32 btf_maps_sec_btf_id;  	int text_shndx; @@ -1408,6 +1410,10 @@ static int bpf_object__check_endianness(struct bpf_object *obj)  static int  bpf_object__init_license(struct bpf_object *obj, void *data, size_t size)  { +	if (!data) { +		pr_warn("invalid license section in %s\n", obj->path); +		return -LIBBPF_ERRNO__FORMAT; +	}  	/* libbpf_strlcpy() only copies first N - 1 bytes, so size + 1 won't  	 * go over allowed ELF data section buffer  	 */ @@ -1421,7 +1427,7 @@ bpf_object__init_kversion(struct bpf_object *obj, void *data, size_t size)  {  	__u32 kver; -	if (size != sizeof(kver)) { +	if (!data || size != sizeof(kver)) {  		pr_warn("invalid kver section in %s\n", obj->path);  		return -LIBBPF_ERRNO__FORMAT;  	} @@ -1457,15 +1463,12 @@ static int find_elf_sec_sz(const struct bpf_object *obj, const char *name, __u32  	return -ENOENT;  } -static int find_elf_var_offset(const struct bpf_object *obj, const char *name, __u32 *off) +static Elf64_Sym *find_elf_var_sym(const struct bpf_object *obj, const char *name)  {  	Elf_Data *symbols = obj->efile.symbols;  	const char *sname;  	size_t si; -	if (!name || !off) -		return -EINVAL; -  	for (si = 0; si < symbols->d_size / sizeof(Elf64_Sym); si++) {  		Elf64_Sym *sym = elf_sym_by_idx(obj, si); @@ -1479,15 +1482,13 @@ static int find_elf_var_offset(const struct bpf_object *obj, const char *name, _  		sname = elf_sym_str(obj, sym->st_name);  		if (!sname) {  			pr_warn("failed to get sym name string for var %s\n", name); -			return -EIO; -		} -		if (strcmp(name, sname) == 0) { -			*off = sym->st_value; -			return 0; +			return ERR_PTR(-EIO);  		} +		if (strcmp(name, sname) == 0) +			return sym;  	} -	return -ENOENT; +	return ERR_PTR(-ENOENT);  }  static struct bpf_map *bpf_object__add_map(struct bpf_object *obj) @@ -1578,7 +1579,38 @@ static char *internal_map_name(struct bpf_object *obj, const char *real_name)  }  static int -bpf_map_find_btf_info(struct bpf_object *obj, struct bpf_map *map); +map_fill_btf_type_info(struct bpf_object *obj, struct bpf_map *map); + +/* Internal BPF map is mmap()'able only if at least one of corresponding + * DATASEC's VARs are to be exposed through BPF skeleton. I.e., it's a GLOBAL + * variable and it's not marked as __hidden (which turns it into, effectively, + * a STATIC variable). + */ +static bool map_is_mmapable(struct bpf_object *obj, struct bpf_map *map) +{ +	const struct btf_type *t, *vt; +	struct btf_var_secinfo *vsi; +	int i, n; + +	if (!map->btf_value_type_id) +		return false; + +	t = btf__type_by_id(obj->btf, map->btf_value_type_id); +	if (!btf_is_datasec(t)) +		return false; + +	vsi = btf_var_secinfos(t); +	for (i = 0, n = btf_vlen(t); i < n; i++, vsi++) { +		vt = btf__type_by_id(obj->btf, vsi->type); +		if (!btf_is_var(vt)) +			continue; + +		if (btf_var(vt)->linkage != BTF_VAR_STATIC) +			return true; +	} + +	return false; +}  static int  bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type, @@ -1610,7 +1642,12 @@ bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type,  	def->max_entries = 1;  	def->map_flags = type == LIBBPF_MAP_RODATA || type == LIBBPF_MAP_KCONFIG  			 ? BPF_F_RDONLY_PROG : 0; -	def->map_flags |= BPF_F_MMAPABLE; + +	/* failures are fine because of maps like .rodata.str1.1 */ +	(void) map_fill_btf_type_info(obj, map); + +	if (map_is_mmapable(obj, map)) +		def->map_flags |= BPF_F_MMAPABLE;  	pr_debug("map '%s' (global data): at sec_idx %d, offset %zu, flags %x.\n",  		 map->name, map->sec_idx, map->sec_offset, def->map_flags); @@ -1627,9 +1664,6 @@ bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type,  		return err;  	} -	/* failures are fine because of maps like .rodata.str1.1 */ -	(void) bpf_map_find_btf_info(obj, map); -  	if (data)  		memcpy(map->mmaped, data, data_sz); @@ -1830,12 +1864,20 @@ static int set_kcfg_value_num(struct extern_desc *ext, void *ext_val,  		return -ERANGE;  	}  	switch (ext->kcfg.sz) { -		case 1: *(__u8 *)ext_val = value; break; -		case 2: *(__u16 *)ext_val = value; break; -		case 4: *(__u32 *)ext_val = value; break; -		case 8: *(__u64 *)ext_val = value; break; -		default: -			return -EINVAL; +	case 1: +		*(__u8 *)ext_val = value; +		break; +	case 2: +		*(__u16 *)ext_val = value; +		break; +	case 4: +		*(__u32 *)ext_val = value; +		break; +	case 8: +		*(__u64 *)ext_val = value; +		break; +	default: +		return -EINVAL;  	}  	ext->is_set = true;  	return 0; @@ -2541,7 +2583,7 @@ static int bpf_object__init_user_btf_map(struct bpf_object *obj,  		fill_map_from_def(map->inner_map, &inner_def);  	} -	err = bpf_map_find_btf_info(obj, map); +	err = map_fill_btf_type_info(obj, map);  	if (err)  		return err; @@ -2737,7 +2779,7 @@ static int bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf)  				m->type = enum64_placeholder_id;  				m->offset = 0;  			} -                } +		}  	}  	return 0; @@ -2846,57 +2888,89 @@ static int compare_vsi_off(const void *_a, const void *_b)  static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf,  			     struct btf_type *t)  { -	__u32 size = 0, off = 0, i, vars = btf_vlen(t); -	const char *name = btf__name_by_offset(btf, t->name_off); -	const struct btf_type *t_var; +	__u32 size = 0, i, vars = btf_vlen(t); +	const char *sec_name = btf__name_by_offset(btf, t->name_off);  	struct btf_var_secinfo *vsi; -	const struct btf_var *var; -	int ret; +	bool fixup_offsets = false; +	int err; -	if (!name) { +	if (!sec_name) {  		pr_debug("No name found in string section for DATASEC kind.\n");  		return -ENOENT;  	} -	/* .extern datasec size and var offsets were set correctly during -	 * extern collection step, so just skip straight to sorting variables +	/* Extern-backing datasecs (.ksyms, .kconfig) have their size and +	 * variable offsets set at the previous step. Further, not every +	 * extern BTF VAR has corresponding ELF symbol preserved, so we skip +	 * all fixups altogether for such sections and go straight to sorting +	 * VARs within their DATASEC.  	 */ -	if (t->size) +	if (strcmp(sec_name, KCONFIG_SEC) == 0 || strcmp(sec_name, KSYMS_SEC) == 0)  		goto sort_vars; -	ret = find_elf_sec_sz(obj, name, &size); -	if (ret || !size) { -		pr_debug("Invalid size for section %s: %u bytes\n", name, size); -		return -ENOENT; -	} +	/* Clang leaves DATASEC size and VAR offsets as zeroes, so we need to +	 * fix this up. But BPF static linker already fixes this up and fills +	 * all the sizes and offsets during static linking. So this step has +	 * to be optional. But the STV_HIDDEN handling is non-optional for any +	 * non-extern DATASEC, so the variable fixup loop below handles both +	 * functions at the same time, paying the cost of BTF VAR <-> ELF +	 * symbol matching just once. +	 */ +	if (t->size == 0) { +		err = find_elf_sec_sz(obj, sec_name, &size); +		if (err || !size) { +			pr_debug("sec '%s': failed to determine size from ELF: size %u, err %d\n", +				 sec_name, size, err); +			return -ENOENT; +		} -	t->size = size; +		t->size = size; +		fixup_offsets = true; +	}  	for (i = 0, vsi = btf_var_secinfos(t); i < vars; i++, vsi++) { +		const struct btf_type *t_var; +		struct btf_var *var; +		const char *var_name; +		Elf64_Sym *sym; +  		t_var = btf__type_by_id(btf, vsi->type);  		if (!t_var || !btf_is_var(t_var)) { -			pr_debug("Non-VAR type seen in section %s\n", name); +			pr_debug("sec '%s': unexpected non-VAR type found\n", sec_name);  			return -EINVAL;  		}  		var = btf_var(t_var); -		if (var->linkage == BTF_VAR_STATIC) +		if (var->linkage == BTF_VAR_STATIC || var->linkage == BTF_VAR_GLOBAL_EXTERN)  			continue; -		name = btf__name_by_offset(btf, t_var->name_off); -		if (!name) { -			pr_debug("No name found in string section for VAR kind\n"); +		var_name = btf__name_by_offset(btf, t_var->name_off); +		if (!var_name) { +			pr_debug("sec '%s': failed to find name of DATASEC's member #%d\n", +				 sec_name, i);  			return -ENOENT;  		} -		ret = find_elf_var_offset(obj, name, &off); -		if (ret) { -			pr_debug("No offset found in symbol table for VAR %s\n", -				 name); +		sym = find_elf_var_sym(obj, var_name); +		if (IS_ERR(sym)) { +			pr_debug("sec '%s': failed to find ELF symbol for VAR '%s'\n", +				 sec_name, var_name);  			return -ENOENT;  		} -		vsi->offset = off; +		if (fixup_offsets) +			vsi->offset = sym->st_value; + +		/* if variable is a global/weak symbol, but has restricted +		 * (STV_HIDDEN or STV_INTERNAL) visibility, mark its BTF VAR +		 * as static. This follows similar logic for functions (BPF +		 * subprogs) and influences libbpf's further decisions about +		 * whether to make global data BPF array maps as +		 * BPF_F_MMAPABLE. +		 */ +		if (ELF64_ST_VISIBILITY(sym->st_other) == STV_HIDDEN +		    || ELF64_ST_VISIBILITY(sym->st_other) == STV_INTERNAL) +			var->linkage = BTF_VAR_STATIC;  	}  sort_vars: @@ -2904,13 +2978,16 @@ sort_vars:  	return 0;  } -static int btf_finalize_data(struct bpf_object *obj, struct btf *btf) +static int bpf_object_fixup_btf(struct bpf_object *obj)  { -	int err = 0; -	__u32 i, n = btf__type_cnt(btf); +	int i, n, err = 0; + +	if (!obj->btf) +		return 0; +	n = btf__type_cnt(obj->btf);  	for (i = 1; i < n; i++) { -		struct btf_type *t = btf_type_by_id(btf, i); +		struct btf_type *t = btf_type_by_id(obj->btf, i);  		/* Loader needs to fix up some of the things compiler  		 * couldn't get its hands on while emitting BTF. This @@ -2918,28 +2995,12 @@ static int btf_finalize_data(struct bpf_object *obj, struct btf *btf)  		 * the info from the ELF itself for this purpose.  		 */  		if (btf_is_datasec(t)) { -			err = btf_fixup_datasec(obj, btf, t); +			err = btf_fixup_datasec(obj, obj->btf, t);  			if (err) -				break; +				return err;  		}  	} -	return libbpf_err(err); -} - -static int bpf_object__finalize_btf(struct bpf_object *obj) -{ -	int err; - -	if (!obj->btf) -		return 0; - -	err = btf_finalize_data(obj, obj->btf); -	if (err) { -		pr_warn("Error finalizing %s: %d.\n", BTF_ELF_SEC, err); -		return err; -	} -  	return 0;  } @@ -3312,10 +3373,15 @@ static int bpf_object__elf_collect(struct bpf_object *obj)  	Elf64_Shdr *sh;  	/* ELF section indices are 0-based, but sec #0 is special "invalid" -	 * section. e_shnum does include sec #0, so e_shnum is the necessary -	 * size of an array to keep all the sections. +	 * section. Since section count retrieved by elf_getshdrnum() does +	 * include sec #0, it is already the necessary size of an array to keep +	 * all the sections.  	 */ -	obj->efile.sec_cnt = obj->efile.ehdr->e_shnum; +	if (elf_getshdrnum(obj->efile.elf, &obj->efile.sec_cnt)) { +		pr_warn("elf: failed to get the number of sections for %s: %s\n", +			obj->path, elf_errmsg(-1)); +		return -LIBBPF_ERRNO__FORMAT; +	}  	obj->efile.secs = calloc(obj->efile.sec_cnt, sizeof(*obj->efile.secs));  	if (!obj->efile.secs)  		return -ENOMEM; @@ -3445,7 +3511,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj)  			sec_desc->sec_type = SEC_RELO;  			sec_desc->shdr = sh;  			sec_desc->data = data; -		} else if (sh->sh_type == SHT_NOBITS && strcmp(name, BSS_SEC) == 0) { +		} else if (sh->sh_type == SHT_NOBITS && (strcmp(name, BSS_SEC) == 0 || +							 str_has_pfx(name, BSS_SEC "."))) {  			sec_desc->sec_type = SEC_BSS;  			sec_desc->shdr = sh;  			sec_desc->data = data; @@ -3461,7 +3528,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj)  	}  	/* sort BPF programs by section name and in-section instruction offset -	 * for faster search */ +	 * for faster search +	 */  	if (obj->nr_programs)  		qsort(obj->programs, obj->nr_programs, sizeof(*obj->programs), cmp_progs); @@ -3760,7 +3828,7 @@ static int bpf_object__collect_externs(struct bpf_object *obj)  				return -EINVAL;  			}  			ext->kcfg.type = find_kcfg_type(obj->btf, t->type, -						        &ext->kcfg.is_signed); +							&ext->kcfg.is_signed);  			if (ext->kcfg.type == KCFG_UNKNOWN) {  				pr_warn("extern (kcfg) '%s': type is unsupported\n", ext_name);  				return -ENOTSUP; @@ -4106,6 +4174,9 @@ static struct bpf_program *find_prog_by_sec_insn(const struct bpf_object *obj,  	int l = 0, r = obj->nr_programs - 1, m;  	struct bpf_program *prog; +	if (!obj->nr_programs) +		return NULL; +  	while (l < r) {  		m = l + (r - l + 1) / 2;  		prog = &obj->programs[m]; @@ -4223,7 +4294,7 @@ bpf_object__collect_prog_relos(struct bpf_object *obj, Elf64_Shdr *shdr, Elf_Dat  	return 0;  } -static int bpf_map_find_btf_info(struct bpf_object *obj, struct bpf_map *map) +static int map_fill_btf_type_info(struct bpf_object *obj, struct bpf_map *map)  {  	int id; @@ -4905,9 +4976,9 @@ bpf_object__reuse_map(struct bpf_map *map)  	err = bpf_map__reuse_fd(map, pin_fd);  	close(pin_fd); -	if (err) { +	if (err)  		return err; -	} +  	map->pinned = true;  	pr_debug("reused pinned map at '%s'\n", map->pin_path); @@ -5425,7 +5496,7 @@ static int load_module_btfs(struct bpf_object *obj)  		}  		err = libbpf_ensure_mem((void **)&obj->btf_modules, &obj->btf_module_cap, -				        sizeof(*obj->btf_modules), obj->btf_module_cnt + 1); +					sizeof(*obj->btf_modules), obj->btf_module_cnt + 1);  		if (err)  			goto err_out; @@ -5541,21 +5612,16 @@ int bpf_core_types_match(const struct btf *local_btf, __u32 local_id,  	return __bpf_core_types_match(local_btf, local_id, targ_btf, targ_id, false, 32);  } -static size_t bpf_core_hash_fn(const void *key, void *ctx) +static size_t bpf_core_hash_fn(const long key, void *ctx)  { -	return (size_t)key; +	return key;  } -static bool bpf_core_equal_fn(const void *k1, const void *k2, void *ctx) +static bool bpf_core_equal_fn(const long k1, const long k2, void *ctx)  {  	return k1 == k2;  } -static void *u32_as_hash_key(__u32 x) -{ -	return (void *)(uintptr_t)x; -} -  static int record_relo_core(struct bpf_program *prog,  			    const struct bpf_core_relo *core_relo, int insn_idx)  { @@ -5598,7 +5664,6 @@ static int bpf_core_resolve_relo(struct bpf_program *prog,  				 struct bpf_core_relo_res *targ_res)  {  	struct bpf_core_spec specs_scratch[3] = {}; -	const void *type_key = u32_as_hash_key(relo->type_id);  	struct bpf_core_cand_list *cands = NULL;  	const char *prog_name = prog->name;  	const struct btf_type *local_type; @@ -5615,7 +5680,7 @@ static int bpf_core_resolve_relo(struct bpf_program *prog,  		return -EINVAL;  	if (relo->kind != BPF_CORE_TYPE_ID_LOCAL && -	    !hashmap__find(cand_cache, type_key, (void **)&cands)) { +	    !hashmap__find(cand_cache, local_id, &cands)) {  		cands = bpf_core_find_cands(prog->obj, local_btf, local_id);  		if (IS_ERR(cands)) {  			pr_warn("prog '%s': relo #%d: target candidate search failed for [%d] %s %s: %ld\n", @@ -5623,7 +5688,7 @@ static int bpf_core_resolve_relo(struct bpf_program *prog,  				local_name, PTR_ERR(cands));  			return PTR_ERR(cands);  		} -		err = hashmap__set(cand_cache, type_key, cands, NULL, NULL); +		err = hashmap__set(cand_cache, local_id, cands, NULL, NULL);  		if (err) {  			bpf_core_free_cands(cands);  			return err; @@ -5746,7 +5811,7 @@ out:  	if (!IS_ERR_OR_NULL(cand_cache)) {  		hashmap__for_each_entry(cand_cache, entry, i) { -			bpf_core_free_cands(entry->value); +			bpf_core_free_cands(entry->pvalue);  		}  		hashmap__free(cand_cache);  	} @@ -6183,7 +6248,8 @@ bpf_object__reloc_code(struct bpf_object *obj, struct bpf_program *main_prog,  		 * prog; each main prog can have a different set of  		 * subprograms appended (potentially in different order as  		 * well), so position of any subprog can be different for -		 * different main programs */ +		 * different main programs +		 */  		insn->imm = subprog->sub_insn_off - (prog->sub_insn_off + insn_idx) - 1;  		pr_debug("prog '%s': insn #%zu relocated, imm %d points to subprog '%s' (now at %zu offset)\n", @@ -7221,7 +7287,7 @@ static struct bpf_object *bpf_object_open(const char *path, const void *obj_buf,  	err = err ? : bpf_object__check_endianness(obj);  	err = err ? : bpf_object__elf_collect(obj);  	err = err ? : bpf_object__collect_externs(obj); -	err = err ? : bpf_object__finalize_btf(obj); +	err = err ? : bpf_object_fixup_btf(obj);  	err = err ? : bpf_object__init_maps(obj, opts);  	err = err ? : bpf_object_init_progs(obj, opts);  	err = err ? : bpf_object__collect_relos(obj); @@ -10941,7 +11007,7 @@ struct bpf_link *bpf_program__attach_usdt(const struct bpf_program *prog,  	usdt_cookie = OPTS_GET(opts, usdt_cookie, 0);  	link = usdt_manager_attach_usdt(obj->usdt_man, prog, pid, binary_path, -				        usdt_provider, usdt_name, usdt_cookie); +					usdt_provider, usdt_name, usdt_cookie);  	err = libbpf_get_error(link);  	if (err)  		return libbpf_err_ptr(err); @@ -12250,7 +12316,7 @@ int bpf_object__open_subskeleton(struct bpf_object_subskeleton *s)  	btf = bpf_object__btf(s->obj);  	if (!btf) {  		pr_warn("subskeletons require BTF at runtime (object %s)\n", -		        bpf_object__name(s->obj)); +			bpf_object__name(s->obj));  		return libbpf_err(-errno);  	} diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index c1d6aa7c82b6..71bf5691a689 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -367,10 +367,14 @@ LIBBPF_1.0.0 {  		libbpf_bpf_map_type_str;  		libbpf_bpf_prog_type_str;  		perf_buffer__buffer; -}; +} LIBBPF_0.8.0;  LIBBPF_1.1.0 {  	global: +		bpf_btf_get_fd_by_id_opts; +		bpf_link_get_fd_by_id_opts; +		bpf_map_get_fd_by_id_opts; +		bpf_prog_get_fd_by_id_opts;  		user_ring_buffer__discard;  		user_ring_buffer__free;  		user_ring_buffer__new; diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c index d504d96adc83..b44fcbb4b42e 100644 --- a/tools/lib/bpf/libbpf_probes.c +++ b/tools/lib/bpf/libbpf_probes.c @@ -221,6 +221,7 @@ static int probe_map_create(enum bpf_map_type map_type)  	case BPF_MAP_TYPE_SK_STORAGE:  	case BPF_MAP_TYPE_INODE_STORAGE:  	case BPF_MAP_TYPE_TASK_STORAGE: +	case BPF_MAP_TYPE_CGRP_STORAGE:  		btf_key_type_id = 1;  		btf_value_type_id = 3;  		value_size = 8; diff --git a/tools/lib/bpf/ringbuf.c b/tools/lib/bpf/ringbuf.c index 6af142953a94..47855af25f3b 100644 --- a/tools/lib/bpf/ringbuf.c +++ b/tools/lib/bpf/ringbuf.c @@ -128,7 +128,7 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,  	/* Map read-only producer page and data pages. We map twice as big  	 * data size to allow simple reading of samples that wrap around the  	 * end of a ring buffer. See kernel implementation for details. -	 * */ +	 */  	mmap_sz = rb->page_size + 2 * (__u64)info.max_entries;  	if (mmap_sz != (__u64)(size_t)mmap_sz) {  		pr_warn("ringbuf: ring buffer size (%u) is too big\n", info.max_entries); @@ -224,7 +224,7 @@ static inline int roundup_len(__u32 len)  	return (len + 7) / 8 * 8;  } -static int64_t ringbuf_process_ring(struct ring* r) +static int64_t ringbuf_process_ring(struct ring *r)  {  	int *len_ptr, len, err;  	/* 64-bit to avoid overflow in case of extreme application behavior */ diff --git a/tools/lib/bpf/strset.c b/tools/lib/bpf/strset.c index ea655318153f..2464bcbd04e0 100644 --- a/tools/lib/bpf/strset.c +++ b/tools/lib/bpf/strset.c @@ -19,19 +19,19 @@ struct strset {  	struct hashmap *strs_hash;  }; -static size_t strset_hash_fn(const void *key, void *ctx) +static size_t strset_hash_fn(long key, void *ctx)  {  	const struct strset *s = ctx; -	const char *str = s->strs_data + (long)key; +	const char *str = s->strs_data + key;  	return str_hash(str);  } -static bool strset_equal_fn(const void *key1, const void *key2, void *ctx) +static bool strset_equal_fn(long key1, long key2, void *ctx)  {  	const struct strset *s = ctx; -	const char *str1 = s->strs_data + (long)key1; -	const char *str2 = s->strs_data + (long)key2; +	const char *str1 = s->strs_data + key1; +	const char *str2 = s->strs_data + key2;  	return strcmp(str1, str2) == 0;  } @@ -67,7 +67,7 @@ struct strset *strset__new(size_t max_data_sz, const char *init_data, size_t ini  			/* hashmap__add() returns EEXIST if string with the same  			 * content already is in the hash map  			 */ -			err = hashmap__add(hash, (void *)off, (void *)off); +			err = hashmap__add(hash, off, off);  			if (err == -EEXIST)  				continue; /* duplicate */  			if (err) @@ -127,7 +127,7 @@ int strset__find_str(struct strset *set, const char *s)  	new_off = set->strs_data_len;  	memcpy(p, s, len); -	if (hashmap__find(set->strs_hash, (void *)new_off, (void **)&old_off)) +	if (hashmap__find(set->strs_hash, new_off, &old_off))  		return old_off;  	return -ENOENT; @@ -165,8 +165,8 @@ int strset__add_str(struct strset *set, const char *s)  	 * contents doesn't exist already (HASHMAP_ADD strategy). If such  	 * string exists, we'll get its offset in old_off (that's old_key).  	 */ -	err = hashmap__insert(set->strs_hash, (void *)new_off, (void *)new_off, -			      HASHMAP_ADD, (const void **)&old_off, NULL); +	err = hashmap__insert(set->strs_hash, new_off, new_off, +			      HASHMAP_ADD, &old_off, NULL);  	if (err == -EEXIST)  		return old_off; /* duplicated string, return existing offset */  	if (err) diff --git a/tools/lib/bpf/usdt.c b/tools/lib/bpf/usdt.c index e83b497c2245..75b411fc2c77 100644 --- a/tools/lib/bpf/usdt.c +++ b/tools/lib/bpf/usdt.c @@ -873,31 +873,27 @@ static void bpf_link_usdt_dealloc(struct bpf_link *link)  	free(usdt_link);  } -static size_t specs_hash_fn(const void *key, void *ctx) +static size_t specs_hash_fn(long key, void *ctx)  { -	const char *s = key; - -	return str_hash(s); +	return str_hash((char *)key);  } -static bool specs_equal_fn(const void *key1, const void *key2, void *ctx) +static bool specs_equal_fn(long key1, long key2, void *ctx)  { -	const char *s1 = key1; -	const char *s2 = key2; - -	return strcmp(s1, s2) == 0; +	return strcmp((char *)key1, (char *)key2) == 0;  }  static int allocate_spec_id(struct usdt_manager *man, struct hashmap *specs_hash,  			    struct bpf_link_usdt *link, struct usdt_target *target,  			    int *spec_id, bool *is_new)  { -	void *tmp; +	long tmp; +	void *new_ids;  	int err;  	/* check if we already allocated spec ID for this spec string */  	if (hashmap__find(specs_hash, target->spec_str, &tmp)) { -		*spec_id = (long)tmp; +		*spec_id = tmp;  		*is_new = false;  		return 0;  	} @@ -905,17 +901,17 @@ static int allocate_spec_id(struct usdt_manager *man, struct hashmap *specs_hash  	/* otherwise it's a new ID that needs to be set up in specs map and  	 * returned back to usdt_manager when USDT link is detached  	 */ -	tmp = libbpf_reallocarray(link->spec_ids, link->spec_cnt + 1, sizeof(*link->spec_ids)); -	if (!tmp) +	new_ids = libbpf_reallocarray(link->spec_ids, link->spec_cnt + 1, sizeof(*link->spec_ids)); +	if (!new_ids)  		return -ENOMEM; -	link->spec_ids = tmp; +	link->spec_ids = new_ids;  	/* get next free spec ID, giving preference to free list, if not empty */  	if (man->free_spec_cnt) {  		*spec_id = man->free_spec_ids[man->free_spec_cnt - 1];  		/* cache spec ID for current spec string for future lookups */ -		err = hashmap__add(specs_hash, target->spec_str, (void *)(long)*spec_id); +		err = hashmap__add(specs_hash, target->spec_str, *spec_id);  		if (err)  			 return err; @@ -928,7 +924,7 @@ static int allocate_spec_id(struct usdt_manager *man, struct hashmap *specs_hash  		*spec_id = man->next_free_spec_id;  		/* cache spec ID for current spec string for future lookups */ -		err = hashmap__add(specs_hash, target->spec_str, (void *)(long)*spec_id); +		err = hashmap__add(specs_hash, target->spec_str, *spec_id);  		if (err)  			 return err; @@ -1225,26 +1221,32 @@ static int calc_pt_regs_off(const char *reg_name)  static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg)  { -	char *reg_name = NULL; +	char reg_name[16];  	int arg_sz, len, reg_off;  	long off; -	if (sscanf(arg_str, " %d @ %ld ( %%%m[^)] ) %n", &arg_sz, &off, ®_name, &len) == 3) { +	if (sscanf(arg_str, " %d @ %ld ( %%%15[^)] ) %n", &arg_sz, &off, reg_name, &len) == 3) {  		/* Memory dereference case, e.g., -4@-20(%rbp) */  		arg->arg_type = USDT_ARG_REG_DEREF;  		arg->val_off = off;  		reg_off = calc_pt_regs_off(reg_name); -		free(reg_name);  		if (reg_off < 0)  			return reg_off;  		arg->reg_off = reg_off; -	} else if (sscanf(arg_str, " %d @ %%%ms %n", &arg_sz, ®_name, &len) == 2) { +	} else if (sscanf(arg_str, " %d @ ( %%%15[^)] ) %n", &arg_sz, reg_name, &len) == 2) { +		/* Memory dereference case without offset, e.g., 8@(%rsp) */ +		arg->arg_type = USDT_ARG_REG_DEREF; +		arg->val_off = 0; +		reg_off = calc_pt_regs_off(reg_name); +		if (reg_off < 0) +			return reg_off; +		arg->reg_off = reg_off; +	} else if (sscanf(arg_str, " %d @ %%%15s %n", &arg_sz, reg_name, &len) == 2) {  		/* Register read case, e.g., -4@%eax */  		arg->arg_type = USDT_ARG_REG;  		arg->val_off = 0;  		reg_off = calc_pt_regs_off(reg_name); -		free(reg_name);  		if (reg_off < 0)  			return reg_off;  		arg->reg_off = reg_off; @@ -1348,25 +1350,23 @@ static int calc_pt_regs_off(const char *reg_name)  static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg)  { -	char *reg_name = NULL; +	char reg_name[16];  	int arg_sz, len, reg_off;  	long off; -	if (sscanf(arg_str, " %d @ \[ %m[a-z0-9], %ld ] %n", &arg_sz, ®_name, &off, &len) == 3) { +	if (sscanf(arg_str, " %d @ \[ %15[a-z0-9], %ld ] %n", &arg_sz, reg_name, &off, &len) == 3) {  		/* Memory dereference case, e.g., -4@[sp, 96] */  		arg->arg_type = USDT_ARG_REG_DEREF;  		arg->val_off = off;  		reg_off = calc_pt_regs_off(reg_name); -		free(reg_name);  		if (reg_off < 0)  			return reg_off;  		arg->reg_off = reg_off; -	} else if (sscanf(arg_str, " %d @ \[ %m[a-z0-9] ] %n", &arg_sz, ®_name, &len) == 2) { +	} else if (sscanf(arg_str, " %d @ \[ %15[a-z0-9] ] %n", &arg_sz, reg_name, &len) == 2) {  		/* Memory dereference case, e.g., -4@[sp] */  		arg->arg_type = USDT_ARG_REG_DEREF;  		arg->val_off = 0;  		reg_off = calc_pt_regs_off(reg_name); -		free(reg_name);  		if (reg_off < 0)  			return reg_off;  		arg->reg_off = reg_off; @@ -1375,12 +1375,11 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec  		arg->arg_type = USDT_ARG_CONST;  		arg->val_off = off;  		arg->reg_off = 0; -	} else if (sscanf(arg_str, " %d @ %m[a-z0-9] %n", &arg_sz, ®_name, &len) == 2) { +	} else if (sscanf(arg_str, " %d @ %15[a-z0-9] %n", &arg_sz, reg_name, &len) == 2) {  		/* Register read case, e.g., -8@x4 */  		arg->arg_type = USDT_ARG_REG;  		arg->val_off = 0;  		reg_off = calc_pt_regs_off(reg_name); -		free(reg_name);  		if (reg_off < 0)  			return reg_off;  		arg->reg_off = reg_off; @@ -1459,16 +1458,15 @@ static int calc_pt_regs_off(const char *reg_name)  static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg)  { -	char *reg_name = NULL; +	char reg_name[16];  	int arg_sz, len, reg_off;  	long off; -	if (sscanf(arg_str, " %d @ %ld ( %m[a-z0-9] ) %n", &arg_sz, &off, ®_name, &len) == 3) { +	if (sscanf(arg_str, " %d @ %ld ( %15[a-z0-9] ) %n", &arg_sz, &off, reg_name, &len) == 3) {  		/* Memory dereference case, e.g., -8@-88(s0) */  		arg->arg_type = USDT_ARG_REG_DEREF;  		arg->val_off = off;  		reg_off = calc_pt_regs_off(reg_name); -		free(reg_name);  		if (reg_off < 0)  			return reg_off;  		arg->reg_off = reg_off; @@ -1477,12 +1475,11 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec  		arg->arg_type = USDT_ARG_CONST;  		arg->val_off = off;  		arg->reg_off = 0; -	} else if (sscanf(arg_str, " %d @ %m[a-z0-9] %n", &arg_sz, ®_name, &len) == 2) { +	} else if (sscanf(arg_str, " %d @ %15[a-z0-9] %n", &arg_sz, reg_name, &len) == 2) {  		/* Register read case, e.g., -8@a1 */  		arg->arg_type = USDT_ARG_REG;  		arg->val_off = 0;  		reg_off = calc_pt_regs_off(reg_name); -		free(reg_name);  		if (reg_off < 0)  			return reg_off;  		arg->reg_off = reg_off; |