Skip to content

Commit 39529a9

Browse files
anakryikoborkmann
authored andcommitted
libbpf: Teach btf_dumper to emit stand-alone anonymous enum definitions
BTF-to-C converter previously skipped anonymous enums in an assumption that those are embedded in struct's field definitions. This is not always the case and a lot of kernel constants are defined as part of anonymous enums. This change fixes the logic by eagerly marking all types as either referenced by any other type or not. This is enough to distinguish two classes of anonymous enums and emit previously omitted enum definitions. Signed-off-by: Andrii Nakryiko <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 4670d68 commit 39529a9

File tree

1 file changed

+87
-6
lines changed

1 file changed

+87
-6
lines changed

tools/lib/bpf/btf_dump.c

Lines changed: 87 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ struct btf_dump_type_aux_state {
4848
__u8 fwd_emitted: 1;
4949
/* whether unique non-duplicate name was already assigned */
5050
__u8 name_resolved: 1;
51+
/* whether type is referenced from any other type */
52+
__u8 referenced: 1;
5153
};
5254

5355
struct btf_dump {
@@ -173,6 +175,7 @@ void btf_dump__free(struct btf_dump *d)
173175
free(d);
174176
}
175177

178+
static int btf_dump_mark_referenced(struct btf_dump *d);
176179
static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr);
177180
static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id);
178181

@@ -213,6 +216,11 @@ int btf_dump__dump_type(struct btf_dump *d, __u32 id)
213216
/* VOID is special */
214217
d->type_states[0].order_state = ORDERED;
215218
d->type_states[0].emit_state = EMITTED;
219+
220+
/* eagerly determine referenced types for anon enums */
221+
err = btf_dump_mark_referenced(d);
222+
if (err)
223+
return err;
216224
}
217225

218226
d->emit_queue_cnt = 0;
@@ -226,6 +234,79 @@ int btf_dump__dump_type(struct btf_dump *d, __u32 id)
226234
return 0;
227235
}
228236

237+
/*
238+
* Mark all types that are referenced from any other type. This is used to
239+
* determine top-level anonymous enums that need to be emitted as an
240+
* independent type declarations.
241+
* Anonymous enums come in two flavors: either embedded in a struct's field
242+
* definition, in which case they have to be declared inline as part of field
243+
* type declaration; or as a top-level anonymous enum, typically used for
244+
* declaring global constants. It's impossible to distinguish between two
245+
* without knowning whether given enum type was referenced from other type:
246+
* top-level anonymous enum won't be referenced by anything, while embedded
247+
* one will.
248+
*/
249+
static int btf_dump_mark_referenced(struct btf_dump *d)
250+
{
251+
int i, j, n = btf__get_nr_types(d->btf);
252+
const struct btf_type *t;
253+
__u16 vlen;
254+
255+
for (i = 1; i <= n; i++) {
256+
t = btf__type_by_id(d->btf, i);
257+
vlen = btf_vlen(t);
258+
259+
switch (btf_kind(t)) {
260+
case BTF_KIND_INT:
261+
case BTF_KIND_ENUM:
262+
case BTF_KIND_FWD:
263+
break;
264+
265+
case BTF_KIND_VOLATILE:
266+
case BTF_KIND_CONST:
267+
case BTF_KIND_RESTRICT:
268+
case BTF_KIND_PTR:
269+
case BTF_KIND_TYPEDEF:
270+
case BTF_KIND_FUNC:
271+
case BTF_KIND_VAR:
272+
d->type_states[t->type].referenced = 1;
273+
break;
274+
275+
case BTF_KIND_ARRAY: {
276+
const struct btf_array *a = btf_array(t);
277+
278+
d->type_states[a->index_type].referenced = 1;
279+
d->type_states[a->type].referenced = 1;
280+
break;
281+
}
282+
case BTF_KIND_STRUCT:
283+
case BTF_KIND_UNION: {
284+
const struct btf_member *m = btf_members(t);
285+
286+
for (j = 0; j < vlen; j++, m++)
287+
d->type_states[m->type].referenced = 1;
288+
break;
289+
}
290+
case BTF_KIND_FUNC_PROTO: {
291+
const struct btf_param *p = btf_params(t);
292+
293+
for (j = 0; j < vlen; j++, p++)
294+
d->type_states[p->type].referenced = 1;
295+
break;
296+
}
297+
case BTF_KIND_DATASEC: {
298+
const struct btf_var_secinfo *v = btf_var_secinfos(t);
299+
300+
for (j = 0; j < vlen; j++, v++)
301+
d->type_states[v->type].referenced = 1;
302+
break;
303+
}
304+
default:
305+
return -EINVAL;
306+
}
307+
}
308+
return 0;
309+
}
229310
static int btf_dump_add_emit_queue_id(struct btf_dump *d, __u32 id)
230311
{
231312
__u32 *new_queue;
@@ -395,7 +476,12 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
395476
}
396477
case BTF_KIND_ENUM:
397478
case BTF_KIND_FWD:
398-
if (t->name_off != 0) {
479+
/*
480+
* non-anonymous or non-referenced enums are top-level
481+
* declarations and should be emitted. Same logic can be
482+
* applied to FWDs, it won't hurt anyways.
483+
*/
484+
if (t->name_off != 0 || !tstate->referenced) {
399485
err = btf_dump_add_emit_queue_id(d, id);
400486
if (err)
401487
return err;
@@ -536,11 +622,6 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
536622
t = btf__type_by_id(d->btf, id);
537623
kind = btf_kind(t);
538624

539-
if (top_level_def && t->name_off == 0) {
540-
pr_warning("unexpected nameless definition, id:[%u]\n", id);
541-
return;
542-
}
543-
544625
if (tstate->emit_state == EMITTING) {
545626
if (tstate->fwd_emitted)
546627
return;

0 commit comments

Comments
 (0)