summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrii Nakryiko <andriin@fb.com>2019-09-25 16:37:45 -0400
committerDaniel Borkmann <daniel@iogearbox.net>2019-09-26 08:38:29 -0400
commit39529a9948d8f67f39cb72bec914c1adab38562d (patch)
tree24023d8202f40bf30143a2956bcdfdd62d7e5159
parent4670d68b9254710fdeaf794cad54d8b2c9929e0a (diff)
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 <andriin@fb.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Link: https://lore.kernel.org/bpf/20190925203745.3173184-1-andriin@fb.com
-rw-r--r--tools/lib/bpf/btf_dump.c93
1 files changed, 87 insertions, 6 deletions
diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c
index 84b0661db7f3..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 {
48 __u8 fwd_emitted: 1; 48 __u8 fwd_emitted: 1;
49 /* whether unique non-duplicate name was already assigned */ 49 /* whether unique non-duplicate name was already assigned */
50 __u8 name_resolved: 1; 50 __u8 name_resolved: 1;
51 /* whether type is referenced from any other type */
52 __u8 referenced: 1;
51}; 53};
52 54
53struct btf_dump { 55struct btf_dump {
@@ -173,6 +175,7 @@ void btf_dump__free(struct btf_dump *d)
173 free(d); 175 free(d);
174} 176}
175 177
178static int btf_dump_mark_referenced(struct btf_dump *d);
176static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr); 179static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr);
177static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id); 180static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id);
178 181
@@ -213,6 +216,11 @@ int btf_dump__dump_type(struct btf_dump *d, __u32 id)
213 /* VOID is special */ 216 /* VOID is special */
214 d->type_states[0].order_state = ORDERED; 217 d->type_states[0].order_state = ORDERED;
215 d->type_states[0].emit_state = EMITTED; 218 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;
216 } 224 }
217 225
218 d->emit_queue_cnt = 0; 226 d->emit_queue_cnt = 0;
@@ -226,6 +234,79 @@ int btf_dump__dump_type(struct btf_dump *d, __u32 id)
226 return 0; 234 return 0;
227} 235}
228 236
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 */
249static 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}
229static int btf_dump_add_emit_queue_id(struct btf_dump *d, __u32 id) 310static int btf_dump_add_emit_queue_id(struct btf_dump *d, __u32 id)
230{ 311{
231 __u32 *new_queue; 312 __u32 *new_queue;
@@ -395,7 +476,12 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
395 } 476 }
396 case BTF_KIND_ENUM: 477 case BTF_KIND_ENUM:
397 case BTF_KIND_FWD: 478 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) {
399 err = btf_dump_add_emit_queue_id(d, id); 485 err = btf_dump_add_emit_queue_id(d, id);
400 if (err) 486 if (err)
401 return err; 487 return err;
@@ -536,11 +622,6 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
536 t = btf__type_by_id(d->btf, id); 622 t = btf__type_by_id(d->btf, id);
537 kind = btf_kind(t); 623 kind = btf_kind(t);
538 624
539 if (top_level_def && t->name_off == 0) {
540 pr_warning("unexpected nameless definition, id:[%u]\n", id);
541 return;
542 }
543
544 if (tstate->emit_state == EMITTING) { 625 if (tstate->emit_state == EMITTING) {
545 if (tstate->fwd_emitted) 626 if (tstate->fwd_emitted)
546 return; 627 return;