diff options
Diffstat (limited to 'tools/lib/bpf/btf_dump.c')
| -rw-r--r-- | tools/lib/bpf/btf_dump.c | 232 | 
1 files changed, 134 insertions, 98 deletions
diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c index 7065bb5b2752..ede55fec3618 100644 --- a/tools/lib/bpf/btf_dump.c +++ b/tools/lib/bpf/btf_dump.c @@ -48,6 +48,8 @@ struct btf_dump_type_aux_state {  	__u8 fwd_emitted: 1;  	/* whether unique non-duplicate name was already assigned */  	__u8 name_resolved: 1; +	/* whether type is referenced from any other type */ +	__u8 referenced: 1;  };  struct btf_dump { @@ -100,21 +102,6 @@ static bool str_equal_fn(const void *a, const void *b, void *ctx)  	return strcmp(a, b) == 0;  } -static __u16 btf_kind_of(const struct btf_type *t) -{ -	return BTF_INFO_KIND(t->info); -} - -static __u16 btf_vlen_of(const struct btf_type *t) -{ -	return BTF_INFO_VLEN(t->info); -} - -static bool btf_kflag_of(const struct btf_type *t) -{ -	return BTF_INFO_KFLAG(t->info); -} -  static const char *btf_name_of(const struct btf_dump *d, __u32 name_off)  {  	return btf__name_by_offset(d->btf, name_off); @@ -188,6 +175,7 @@ void btf_dump__free(struct btf_dump *d)  	free(d);  } +static int btf_dump_mark_referenced(struct btf_dump *d);  static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr);  static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id); @@ -228,6 +216,11 @@ int btf_dump__dump_type(struct btf_dump *d, __u32 id)  		/* VOID is special */  		d->type_states[0].order_state = ORDERED;  		d->type_states[0].emit_state = EMITTED; + +		/* eagerly determine referenced types for anon enums */ +		err = btf_dump_mark_referenced(d); +		if (err) +			return err;  	}  	d->emit_queue_cnt = 0; @@ -241,6 +234,79 @@ int btf_dump__dump_type(struct btf_dump *d, __u32 id)  	return 0;  } +/* + * Mark all types that are referenced from any other type. This is used to + * determine top-level anonymous enums that need to be emitted as an + * independent type declarations. + * Anonymous enums come in two flavors: either embedded in a struct's field + * definition, in which case they have to be declared inline as part of field + * type declaration; or as a top-level anonymous enum, typically used for + * declaring global constants. It's impossible to distinguish between two + * without knowning whether given enum type was referenced from other type: + * top-level anonymous enum won't be referenced by anything, while embedded + * one will. + */ +static int btf_dump_mark_referenced(struct btf_dump *d) +{ +	int i, j, n = btf__get_nr_types(d->btf); +	const struct btf_type *t; +	__u16 vlen; + +	for (i = 1; i <= n; i++) { +		t = btf__type_by_id(d->btf, i); +		vlen = btf_vlen(t); + +		switch (btf_kind(t)) { +		case BTF_KIND_INT: +		case BTF_KIND_ENUM: +		case BTF_KIND_FWD: +			break; + +		case BTF_KIND_VOLATILE: +		case BTF_KIND_CONST: +		case BTF_KIND_RESTRICT: +		case BTF_KIND_PTR: +		case BTF_KIND_TYPEDEF: +		case BTF_KIND_FUNC: +		case BTF_KIND_VAR: +			d->type_states[t->type].referenced = 1; +			break; + +		case BTF_KIND_ARRAY: { +			const struct btf_array *a = btf_array(t); + +			d->type_states[a->index_type].referenced = 1; +			d->type_states[a->type].referenced = 1; +			break; +		} +		case BTF_KIND_STRUCT: +		case BTF_KIND_UNION: { +			const struct btf_member *m = btf_members(t); + +			for (j = 0; j < vlen; j++, m++) +				d->type_states[m->type].referenced = 1; +			break; +		} +		case BTF_KIND_FUNC_PROTO: { +			const struct btf_param *p = btf_params(t); + +			for (j = 0; j < vlen; j++, p++) +				d->type_states[p->type].referenced = 1; +			break; +		} +		case BTF_KIND_DATASEC: { +			const struct btf_var_secinfo *v = btf_var_secinfos(t); + +			for (j = 0; j < vlen; j++, v++) +				d->type_states[v->type].referenced = 1; +			break; +		} +		default: +			return -EINVAL; +		} +	} +	return 0; +}  static int btf_dump_add_emit_queue_id(struct btf_dump *d, __u32 id)  {  	__u32 *new_queue; @@ -349,7 +415,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)  	 */  	struct btf_dump_type_aux_state *tstate = &d->type_states[id];  	const struct btf_type *t; -	__u16 kind, vlen; +	__u16 vlen;  	int err, i;  	/* return true, letting typedefs know that it's ok to be emitted */ @@ -357,18 +423,16 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)  		return 1;  	t = btf__type_by_id(d->btf, id); -	kind = btf_kind_of(t);  	if (tstate->order_state == ORDERING) {  		/* type loop, but resolvable through fwd declaration */ -		if ((kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION) && -		    through_ptr && t->name_off != 0) +		if (btf_is_composite(t) && through_ptr && t->name_off != 0)  			return 0;  		pr_warning("unsatisfiable type cycle, id:[%u]\n", id);  		return -ELOOP;  	} -	switch (kind) { +	switch (btf_kind(t)) {  	case BTF_KIND_INT:  		tstate->order_state = ORDERED;  		return 0; @@ -378,14 +442,12 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)  		tstate->order_state = ORDERED;  		return err; -	case BTF_KIND_ARRAY: { -		const struct btf_array *a = (void *)(t + 1); +	case BTF_KIND_ARRAY: +		return btf_dump_order_type(d, btf_array(t)->type, through_ptr); -		return btf_dump_order_type(d, a->type, through_ptr); -	}  	case BTF_KIND_STRUCT:  	case BTF_KIND_UNION: { -		const struct btf_member *m = (void *)(t + 1); +		const struct btf_member *m = btf_members(t);  		/*  		 * struct/union is part of strong link, only if it's embedded  		 * (so no ptr in a path) or it's anonymous (so has to be @@ -396,7 +458,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)  		tstate->order_state = ORDERING; -		vlen = btf_vlen_of(t); +		vlen = btf_vlen(t);  		for (i = 0; i < vlen; i++, m++) {  			err = btf_dump_order_type(d, m->type, false);  			if (err < 0) @@ -414,7 +476,12 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)  	}  	case BTF_KIND_ENUM:  	case BTF_KIND_FWD: -		if (t->name_off != 0) { +		/* +		 * non-anonymous or non-referenced enums are top-level +		 * declarations and should be emitted. Same logic can be +		 * applied to FWDs, it won't hurt anyways. +		 */ +		if (t->name_off != 0 || !tstate->referenced) {  			err = btf_dump_add_emit_queue_id(d, id);  			if (err)  				return err; @@ -447,7 +514,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)  		return btf_dump_order_type(d, t->type, through_ptr);  	case BTF_KIND_FUNC_PROTO: { -		const struct btf_param *p = (void *)(t + 1); +		const struct btf_param *p = btf_params(t);  		bool is_strong;  		err = btf_dump_order_type(d, t->type, through_ptr); @@ -455,7 +522,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)  			return err;  		is_strong = err > 0; -		vlen = btf_vlen_of(t); +		vlen = btf_vlen(t);  		for (i = 0; i < vlen; i++, p++) {  			err = btf_dump_order_type(d, p->type, through_ptr);  			if (err < 0) @@ -553,12 +620,7 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)  		return;  	t = btf__type_by_id(d->btf, id); -	kind = btf_kind_of(t); - -	if (top_level_def && t->name_off == 0) { -		pr_warning("unexpected nameless definition, id:[%u]\n", id); -		return; -	} +	kind = btf_kind(t);  	if (tstate->emit_state == EMITTING) {  		if (tstate->fwd_emitted) @@ -618,12 +680,9 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)  	case BTF_KIND_RESTRICT:  		btf_dump_emit_type(d, t->type, cont_id);  		break; -	case BTF_KIND_ARRAY: { -		const struct btf_array *a = (void *)(t + 1); - -		btf_dump_emit_type(d, a->type, cont_id); +	case BTF_KIND_ARRAY: +		btf_dump_emit_type(d, btf_array(t)->type, cont_id);  		break; -	}  	case BTF_KIND_FWD:  		btf_dump_emit_fwd_def(d, id, t);  		btf_dump_printf(d, ";\n\n"); @@ -656,8 +715,8 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)  		 * applicable  		 */  		if (top_level_def || t->name_off == 0) { -			const struct btf_member *m = (void *)(t + 1); -			__u16 vlen = btf_vlen_of(t); +			const struct btf_member *m = btf_members(t); +			__u16 vlen = btf_vlen(t);  			int i, new_cont_id;  			new_cont_id = t->name_off == 0 ? cont_id : id; @@ -678,8 +737,8 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)  		}  		break;  	case BTF_KIND_FUNC_PROTO: { -		const struct btf_param *p = (void *)(t + 1); -		__u16 vlen = btf_vlen_of(t); +		const struct btf_param *p = btf_params(t); +		__u16 vlen = btf_vlen(t);  		int i;  		btf_dump_emit_type(d, t->type, cont_id); @@ -696,7 +755,7 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)  static int btf_align_of(const struct btf *btf, __u32 id)  {  	const struct btf_type *t = btf__type_by_id(btf, id); -	__u16 kind = btf_kind_of(t); +	__u16 kind = btf_kind(t);  	switch (kind) {  	case BTF_KIND_INT: @@ -709,15 +768,12 @@ static int btf_align_of(const struct btf *btf, __u32 id)  	case BTF_KIND_CONST:  	case BTF_KIND_RESTRICT:  		return btf_align_of(btf, t->type); -	case BTF_KIND_ARRAY: { -		const struct btf_array *a = (void *)(t + 1); - -		return btf_align_of(btf, a->type); -	} +	case BTF_KIND_ARRAY: +		return btf_align_of(btf, btf_array(t)->type);  	case BTF_KIND_STRUCT:  	case BTF_KIND_UNION: { -		const struct btf_member *m = (void *)(t + 1); -		__u16 vlen = btf_vlen_of(t); +		const struct btf_member *m = btf_members(t); +		__u16 vlen = btf_vlen(t);  		int i, align = 1;  		for (i = 0; i < vlen; i++, m++) @@ -726,7 +782,7 @@ static int btf_align_of(const struct btf *btf, __u32 id)  		return align;  	}  	default: -		pr_warning("unsupported BTF_KIND:%u\n", btf_kind_of(t)); +		pr_warning("unsupported BTF_KIND:%u\n", btf_kind(t));  		return 1;  	}  } @@ -737,20 +793,18 @@ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,  	const struct btf_member *m;  	int align, i, bit_sz;  	__u16 vlen; -	bool kflag;  	align = btf_align_of(btf, id);  	/* size of a non-packed struct has to be a multiple of its alignment*/  	if (t->size % align)  		return true; -	m = (void *)(t + 1); -	kflag = btf_kflag_of(t); -	vlen = btf_vlen_of(t); +	m = btf_members(t); +	vlen = btf_vlen(t);  	/* all non-bitfield fields have to be naturally aligned */  	for (i = 0; i < vlen; i++, m++) {  		align = btf_align_of(btf, m->type); -		bit_sz = kflag ? BTF_MEMBER_BITFIELD_SIZE(m->offset) : 0; +		bit_sz = btf_member_bitfield_size(t, i);  		if (bit_sz == 0 && m->offset % (8 * align) != 0)  			return true;  	} @@ -807,7 +861,7 @@ static void btf_dump_emit_struct_fwd(struct btf_dump *d, __u32 id,  				     const struct btf_type *t)  {  	btf_dump_printf(d, "%s %s", -			btf_kind_of(t) == BTF_KIND_STRUCT ? "struct" : "union", +			btf_is_struct(t) ? "struct" : "union",  			btf_dump_type_name(d, id));  } @@ -816,12 +870,11 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,  				     const struct btf_type *t,  				     int lvl)  { -	const struct btf_member *m = (void *)(t + 1); -	bool kflag = btf_kflag_of(t), is_struct; +	const struct btf_member *m = btf_members(t); +	bool is_struct = btf_is_struct(t);  	int align, i, packed, off = 0; -	__u16 vlen = btf_vlen_of(t); +	__u16 vlen = btf_vlen(t); -	is_struct = btf_kind_of(t) == BTF_KIND_STRUCT;  	packed = is_struct ? btf_is_struct_packed(d->btf, id, t) : 0;  	align = packed ? 1 : btf_align_of(d->btf, id); @@ -835,8 +888,8 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,  		int m_off, m_sz;  		fname = btf_name_of(d, m->name_off); -		m_sz = kflag ? BTF_MEMBER_BITFIELD_SIZE(m->offset) : 0; -		m_off = kflag ? BTF_MEMBER_BIT_OFFSET(m->offset) : m->offset; +		m_sz = btf_member_bitfield_size(t, i); +		m_off = btf_member_bit_offset(t, i);  		align = packed ? 1 : btf_align_of(d->btf, m->type);  		btf_dump_emit_bit_padding(d, off, m_off, m_sz, align, lvl + 1); @@ -870,8 +923,8 @@ 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 = (void *)(t+1); -	__u16 vlen = btf_vlen_of(t); +	const struct btf_enum *v = btf_enum(t); +	__u16 vlen = btf_vlen(t);  	const char *name;  	size_t dup_cnt;  	int i; @@ -905,7 +958,7 @@ static void btf_dump_emit_fwd_def(struct btf_dump *d, __u32 id,  {  	const char *name = btf_dump_type_name(d, id); -	if (btf_kflag_of(t)) +	if (btf_kflag(t))  		btf_dump_printf(d, "union %s", name);  	else  		btf_dump_printf(d, "struct %s", name); @@ -987,7 +1040,6 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,  	struct id_stack decl_stack;  	const struct btf_type *t;  	int err, stack_start; -	__u16 kind;  	stack_start = d->decl_stack_cnt;  	for (;;) { @@ -1008,8 +1060,7 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,  			break;  		t = btf__type_by_id(d->btf, id); -		kind = btf_kind_of(t); -		switch (kind) { +		switch (btf_kind(t)) {  		case BTF_KIND_PTR:  		case BTF_KIND_VOLATILE:  		case BTF_KIND_CONST: @@ -1017,12 +1068,9 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,  		case BTF_KIND_FUNC_PROTO:  			id = t->type;  			break; -		case BTF_KIND_ARRAY: { -			const struct btf_array *a = (void *)(t + 1); - -			id = a->type; +		case BTF_KIND_ARRAY: +			id = btf_array(t)->type;  			break; -		}  		case BTF_KIND_INT:  		case BTF_KIND_ENUM:  		case BTF_KIND_FWD: @@ -1032,7 +1080,7 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,  			goto done;  		default:  			pr_warning("unexpected type in decl chain, kind:%u, id:[%u]\n", -				   kind, id); +				   btf_kind(t), id);  			goto done;  		}  	} @@ -1070,7 +1118,7 @@ static void btf_dump_emit_mods(struct btf_dump *d, struct id_stack *decl_stack)  		id = decl_stack->ids[decl_stack->cnt - 1];  		t = btf__type_by_id(d->btf, id); -		switch (btf_kind_of(t)) { +		switch (btf_kind(t)) {  		case BTF_KIND_VOLATILE:  			btf_dump_printf(d, "volatile ");  			break; @@ -1087,20 +1135,6 @@ static void btf_dump_emit_mods(struct btf_dump *d, struct id_stack *decl_stack)  	}  } -static bool btf_is_mod_kind(const struct btf *btf, __u32 id) -{ -	const struct btf_type *t = btf__type_by_id(btf, id); - -	switch (btf_kind_of(t)) { -	case BTF_KIND_VOLATILE: -	case BTF_KIND_CONST: -	case BTF_KIND_RESTRICT: -		return true; -	default: -		return false; -	} -} -  static void btf_dump_emit_name(const struct btf_dump *d,  			       const char *name, bool last_was_ptr)  { @@ -1139,7 +1173,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,  		}  		t = btf__type_by_id(d->btf, id); -		kind = btf_kind_of(t); +		kind = btf_kind(t);  		switch (kind) {  		case BTF_KIND_INT: @@ -1185,7 +1219,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,  			btf_dump_printf(d, " restrict");  			break;  		case BTF_KIND_ARRAY: { -			const struct btf_array *a = (void *)(t + 1); +			const struct btf_array *a = btf_array(t);  			const struct btf_type *next_t;  			__u32 next_id;  			bool multidim; @@ -1201,7 +1235,8 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,  			 */  			while (decls->cnt) {  				next_id = decls->ids[decls->cnt - 1]; -				if (btf_is_mod_kind(d->btf, next_id)) +				next_t = btf__type_by_id(d->btf, next_id); +				if (btf_is_mod(next_t))  					decls->cnt--;  				else  					break; @@ -1213,8 +1248,9 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,  				return;  			} +			next_id = decls->ids[decls->cnt - 1];  			next_t = btf__type_by_id(d->btf, next_id); -			multidim = btf_kind_of(next_t) == BTF_KIND_ARRAY; +			multidim = btf_is_array(next_t);  			/* we need space if we have named non-pointer */  			if (fname[0] && !last_was_ptr)  				btf_dump_printf(d, " "); @@ -1228,8 +1264,8 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,  			return;  		}  		case BTF_KIND_FUNC_PROTO: { -			const struct btf_param *p = (void *)(t + 1); -			__u16 vlen = btf_vlen_of(t); +			const struct btf_param *p = btf_params(t); +			__u16 vlen = btf_vlen(t);  			int i;  			btf_dump_emit_mods(d, decls);  |