mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	libbpf: Add enum64 support for btf_dump
Add enum64 btf dumping support. For long long and unsigned long long dump, suffixes 'LL' and 'ULL' are added to avoid compilation errors in some cases. Acked-by: Andrii Nakryiko <andrii@kernel.org> Signed-off-by: Yonghong Song <yhs@fb.com> Link: https://lore.kernel.org/r/20220607062631.3720526-1-yhs@fb.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
		
							parent
							
								
									2ef2026349
								
							
						
					
					
						commit
						d90ec262b3
					
				
					 2 changed files with 108 additions and 34 deletions
				
			
		| 
						 | 
				
			
			@ -566,6 +566,11 @@ static inline struct btf_enum64 *btf_enum64(const struct btf_type *t)
 | 
			
		|||
	return (struct btf_enum64 *)(t + 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __u64 btf_enum64_value(const struct btf_enum64 *e)
 | 
			
		||||
{
 | 
			
		||||
	return ((__u64)e->val_hi32 << 32) | e->val_lo32;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct btf_member *btf_members(const struct btf_type *t)
 | 
			
		||||
{
 | 
			
		||||
	return (struct btf_member *)(t + 1);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -318,6 +318,7 @@ static int btf_dump_mark_referenced(struct btf_dump *d)
 | 
			
		|||
		switch (btf_kind(t)) {
 | 
			
		||||
		case BTF_KIND_INT:
 | 
			
		||||
		case BTF_KIND_ENUM:
 | 
			
		||||
		case BTF_KIND_ENUM64:
 | 
			
		||||
		case BTF_KIND_FWD:
 | 
			
		||||
		case BTF_KIND_FLOAT:
 | 
			
		||||
			break;
 | 
			
		||||
| 
						 | 
				
			
			@ -538,6 +539,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
 | 
			
		|||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
	case BTF_KIND_ENUM:
 | 
			
		||||
	case BTF_KIND_ENUM64:
 | 
			
		||||
	case BTF_KIND_FWD:
 | 
			
		||||
		/*
 | 
			
		||||
		 * non-anonymous or non-referenced enums are top-level
 | 
			
		||||
| 
						 | 
				
			
			@ -739,6 +741,7 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
 | 
			
		|||
		tstate->emit_state = EMITTED;
 | 
			
		||||
		break;
 | 
			
		||||
	case BTF_KIND_ENUM:
 | 
			
		||||
	case BTF_KIND_ENUM64:
 | 
			
		||||
		if (top_level_def) {
 | 
			
		||||
			btf_dump_emit_enum_def(d, id, t, 0);
 | 
			
		||||
			btf_dump_printf(d, ";\n\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -989,38 +992,81 @@ static void btf_dump_emit_enum_fwd(struct btf_dump *d, __u32 id,
 | 
			
		|||
	btf_dump_printf(d, "enum %s", btf_dump_type_name(d, id));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void btf_dump_emit_enum32_val(struct btf_dump *d,
 | 
			
		||||
				     const struct btf_type *t,
 | 
			
		||||
				     int lvl, __u16 vlen)
 | 
			
		||||
{
 | 
			
		||||
	const struct btf_enum *v = btf_enum(t);
 | 
			
		||||
	bool is_signed = btf_kflag(t);
 | 
			
		||||
	const char *fmt_str;
 | 
			
		||||
	const char *name;
 | 
			
		||||
	size_t dup_cnt;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < vlen; i++, v++) {
 | 
			
		||||
		name = btf_name_of(d, v->name_off);
 | 
			
		||||
		/* enumerators share namespace with typedef idents */
 | 
			
		||||
		dup_cnt = btf_dump_name_dups(d, d->ident_names, name);
 | 
			
		||||
		if (dup_cnt > 1) {
 | 
			
		||||
			fmt_str = is_signed ? "\n%s%s___%zd = %d," : "\n%s%s___%zd = %u,";
 | 
			
		||||
			btf_dump_printf(d, fmt_str, pfx(lvl + 1), name, dup_cnt, v->val);
 | 
			
		||||
		} else {
 | 
			
		||||
			fmt_str = is_signed ? "\n%s%s = %d," : "\n%s%s = %u,";
 | 
			
		||||
			btf_dump_printf(d, fmt_str, pfx(lvl + 1), name, v->val);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void btf_dump_emit_enum64_val(struct btf_dump *d,
 | 
			
		||||
				     const struct btf_type *t,
 | 
			
		||||
				     int lvl, __u16 vlen)
 | 
			
		||||
{
 | 
			
		||||
	const struct btf_enum64 *v = btf_enum64(t);
 | 
			
		||||
	bool is_signed = btf_kflag(t);
 | 
			
		||||
	const char *fmt_str;
 | 
			
		||||
	const char *name;
 | 
			
		||||
	size_t dup_cnt;
 | 
			
		||||
	__u64 val;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < vlen; i++, v++) {
 | 
			
		||||
		name = btf_name_of(d, v->name_off);
 | 
			
		||||
		dup_cnt = btf_dump_name_dups(d, d->ident_names, name);
 | 
			
		||||
		val = btf_enum64_value(v);
 | 
			
		||||
		if (dup_cnt > 1) {
 | 
			
		||||
			fmt_str = is_signed ? "\n%s%s___%zd = %lldLL,"
 | 
			
		||||
					    : "\n%s%s___%zd = %lluULL,";
 | 
			
		||||
			btf_dump_printf(d, fmt_str,
 | 
			
		||||
					pfx(lvl + 1), name, dup_cnt,
 | 
			
		||||
					(unsigned long long)val);
 | 
			
		||||
		} else {
 | 
			
		||||
			fmt_str = is_signed ? "\n%s%s = %lldLL,"
 | 
			
		||||
					    : "\n%s%s = %lluULL,";
 | 
			
		||||
			btf_dump_printf(d, fmt_str,
 | 
			
		||||
					pfx(lvl + 1), name,
 | 
			
		||||
					(unsigned long long)val);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
static void btf_dump_emit_enum_def(struct btf_dump *d, __u32 id,
 | 
			
		||||
				   const struct btf_type *t,
 | 
			
		||||
				   int lvl)
 | 
			
		||||
{
 | 
			
		||||
	const struct btf_enum *v = btf_enum(t);
 | 
			
		||||
	__u16 vlen = btf_vlen(t);
 | 
			
		||||
	const char *name;
 | 
			
		||||
	size_t dup_cnt;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	btf_dump_printf(d, "enum%s%s",
 | 
			
		||||
			t->name_off ? " " : "",
 | 
			
		||||
			btf_dump_type_name(d, id));
 | 
			
		||||
 | 
			
		||||
	if (vlen) {
 | 
			
		||||
		btf_dump_printf(d, " {");
 | 
			
		||||
		for (i = 0; i < vlen; i++, v++) {
 | 
			
		||||
			name = btf_name_of(d, v->name_off);
 | 
			
		||||
			/* enumerators share namespace with typedef idents */
 | 
			
		||||
			dup_cnt = btf_dump_name_dups(d, d->ident_names, name);
 | 
			
		||||
			if (dup_cnt > 1) {
 | 
			
		||||
				btf_dump_printf(d, "\n%s%s___%zu = %u,",
 | 
			
		||||
						pfx(lvl + 1), name, dup_cnt,
 | 
			
		||||
						(__u32)v->val);
 | 
			
		||||
			} else {
 | 
			
		||||
				btf_dump_printf(d, "\n%s%s = %u,",
 | 
			
		||||
						pfx(lvl + 1), name,
 | 
			
		||||
						(__u32)v->val);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		btf_dump_printf(d, "\n%s}", pfx(lvl));
 | 
			
		||||
	}
 | 
			
		||||
	if (!vlen)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	btf_dump_printf(d, " {");
 | 
			
		||||
	if (btf_is_enum(t))
 | 
			
		||||
		btf_dump_emit_enum32_val(d, t, lvl, vlen);
 | 
			
		||||
	else
 | 
			
		||||
		btf_dump_emit_enum64_val(d, t, lvl, vlen);
 | 
			
		||||
	btf_dump_printf(d, "\n%s}", pfx(lvl));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void btf_dump_emit_fwd_def(struct btf_dump *d, __u32 id,
 | 
			
		||||
| 
						 | 
				
			
			@ -1178,6 +1224,7 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
 | 
			
		|||
			break;
 | 
			
		||||
		case BTF_KIND_INT:
 | 
			
		||||
		case BTF_KIND_ENUM:
 | 
			
		||||
		case BTF_KIND_ENUM64:
 | 
			
		||||
		case BTF_KIND_FWD:
 | 
			
		||||
		case BTF_KIND_STRUCT:
 | 
			
		||||
		case BTF_KIND_UNION:
 | 
			
		||||
| 
						 | 
				
			
			@ -1312,6 +1359,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
 | 
			
		|||
				btf_dump_emit_struct_fwd(d, id, t);
 | 
			
		||||
			break;
 | 
			
		||||
		case BTF_KIND_ENUM:
 | 
			
		||||
		case BTF_KIND_ENUM64:
 | 
			
		||||
			btf_dump_emit_mods(d, decls);
 | 
			
		||||
			/* inline anonymous enum */
 | 
			
		||||
			if (t->name_off == 0 && !d->skip_anon_defs)
 | 
			
		||||
| 
						 | 
				
			
			@ -1988,7 +2036,8 @@ static int btf_dump_get_enum_value(struct btf_dump *d,
 | 
			
		|||
				   __u32 id,
 | 
			
		||||
				   __s64 *value)
 | 
			
		||||
{
 | 
			
		||||
	/* handle unaligned enum value */
 | 
			
		||||
	bool is_signed = btf_kflag(t);
 | 
			
		||||
 | 
			
		||||
	if (!ptr_is_aligned(d->btf, id, data)) {
 | 
			
		||||
		__u64 val;
 | 
			
		||||
		int err;
 | 
			
		||||
| 
						 | 
				
			
			@ -2005,13 +2054,13 @@ static int btf_dump_get_enum_value(struct btf_dump *d,
 | 
			
		|||
		*value = *(__s64 *)data;
 | 
			
		||||
		return 0;
 | 
			
		||||
	case 4:
 | 
			
		||||
		*value = *(__s32 *)data;
 | 
			
		||||
		*value = is_signed ? *(__s32 *)data : *(__u32 *)data;
 | 
			
		||||
		return 0;
 | 
			
		||||
	case 2:
 | 
			
		||||
		*value = *(__s16 *)data;
 | 
			
		||||
		*value = is_signed ? *(__s16 *)data : *(__u16 *)data;
 | 
			
		||||
		return 0;
 | 
			
		||||
	case 1:
 | 
			
		||||
		*value = *(__s8 *)data;
 | 
			
		||||
		*value = is_signed ? *(__s8 *)data : *(__u8 *)data;
 | 
			
		||||
		return 0;
 | 
			
		||||
	default:
 | 
			
		||||
		pr_warn("unexpected size %d for enum, id:[%u]\n", t->size, id);
 | 
			
		||||
| 
						 | 
				
			
			@ -2024,7 +2073,7 @@ static int btf_dump_enum_data(struct btf_dump *d,
 | 
			
		|||
			      __u32 id,
 | 
			
		||||
			      const void *data)
 | 
			
		||||
{
 | 
			
		||||
	const struct btf_enum *e;
 | 
			
		||||
	bool is_signed;
 | 
			
		||||
	__s64 value;
 | 
			
		||||
	int i, err;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2032,14 +2081,31 @@ static int btf_dump_enum_data(struct btf_dump *d,
 | 
			
		|||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	for (i = 0, e = btf_enum(t); i < btf_vlen(t); i++, e++) {
 | 
			
		||||
		if (value != e->val)
 | 
			
		||||
			continue;
 | 
			
		||||
		btf_dump_type_values(d, "%s", btf_name_of(d, e->name_off));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	is_signed = btf_kflag(t);
 | 
			
		||||
	if (btf_is_enum(t)) {
 | 
			
		||||
		const struct btf_enum *e;
 | 
			
		||||
 | 
			
		||||
	btf_dump_type_values(d, "%d", value);
 | 
			
		||||
		for (i = 0, e = btf_enum(t); i < btf_vlen(t); i++, e++) {
 | 
			
		||||
			if (value != e->val)
 | 
			
		||||
				continue;
 | 
			
		||||
			btf_dump_type_values(d, "%s", btf_name_of(d, e->name_off));
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		btf_dump_type_values(d, is_signed ? "%d" : "%u", value);
 | 
			
		||||
	} else {
 | 
			
		||||
		const struct btf_enum64 *e;
 | 
			
		||||
 | 
			
		||||
		for (i = 0, e = btf_enum64(t); i < btf_vlen(t); i++, e++) {
 | 
			
		||||
			if (value != btf_enum64_value(e))
 | 
			
		||||
				continue;
 | 
			
		||||
			btf_dump_type_values(d, "%s", btf_name_of(d, e->name_off));
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		btf_dump_type_values(d, is_signed ? "%lldLL" : "%lluULL",
 | 
			
		||||
				     (unsigned long long)value);
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2099,6 +2165,7 @@ static int btf_dump_type_data_check_overflow(struct btf_dump *d,
 | 
			
		|||
	case BTF_KIND_FLOAT:
 | 
			
		||||
	case BTF_KIND_PTR:
 | 
			
		||||
	case BTF_KIND_ENUM:
 | 
			
		||||
	case BTF_KIND_ENUM64:
 | 
			
		||||
		if (data + bits_offset / 8 + size > d->typed_dump->data_end)
 | 
			
		||||
			return -E2BIG;
 | 
			
		||||
		break;
 | 
			
		||||
| 
						 | 
				
			
			@ -2203,6 +2270,7 @@ static int btf_dump_type_data_check_zero(struct btf_dump *d,
 | 
			
		|||
		return -ENODATA;
 | 
			
		||||
	}
 | 
			
		||||
	case BTF_KIND_ENUM:
 | 
			
		||||
	case BTF_KIND_ENUM64:
 | 
			
		||||
		err = btf_dump_get_enum_value(d, t, data, id, &value);
 | 
			
		||||
		if (err)
 | 
			
		||||
			return err;
 | 
			
		||||
| 
						 | 
				
			
			@ -2275,6 +2343,7 @@ static int btf_dump_dump_type_data(struct btf_dump *d,
 | 
			
		|||
		err = btf_dump_struct_data(d, t, id, data);
 | 
			
		||||
		break;
 | 
			
		||||
	case BTF_KIND_ENUM:
 | 
			
		||||
	case BTF_KIND_ENUM64:
 | 
			
		||||
		/* handle bitfield and int enum values */
 | 
			
		||||
		if (bit_sz) {
 | 
			
		||||
			__u64 print_num;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue