On Thu, Nov 10, 2022 at 6:43 AM Eduard Zingerman <eddyz87@xxxxxxxxx> wrote: > > Covers the following cases: > - `__atribute__((btf_decl_tag("...")))` could be applied to structs > and unions; > - decl tag applied to an empty struct is printed on a single line; > - decl tags with the same name could be applied to several structs; > - several decl tags could be applied to the same struct; > - attribute `packed` works fine with decl tags (it is a separate > branch in `tools/lib/bpf/btf_dump.c:btf_dump_emit_attributes`; > - decl tag could be attached to typedef; > - decl tag could be attached to a struct field; > - decl tag could be attached to a struct field and a struct itself > simultaneously; > - decl tag could be attached to a global variable; > - decl tag could be attached to a func proto parameter; > - btf__add_decl_tag could be interleaved with btf_dump__dump_type calls. > > Signed-off-by: Eduard Zingerman <eddyz87@xxxxxxxxx> > --- > .../selftests/bpf/prog_tests/btf_dump.c | 79 +++++++++++++++++++ > .../bpf/progs/btf_dump_test_case_decl_tag.c | 65 +++++++++++++++ > 2 files changed, 144 insertions(+) > create mode 100644 tools/testing/selftests/bpf/progs/btf_dump_test_case_decl_tag.c > [...] > + /* First, BTF corresponding to the following C code: > + * > + * typedef void (*fn)(int a __btf_decl_tag("a_tag")); > + * > + */ > + id = btf__add_int(btf, "int", 4, BTF_INT_SIGNED); > + ASSERT_EQ(id, 1, "int_id"); > + id = btf__add_func_proto(btf, 0); > + ASSERT_EQ(id, 2, "func_proto_id"); > + err = btf__add_func_param(btf, "a", 1); > + ASSERT_OK(err, "func_param_ok"); > + id = btf__add_decl_tag(btf, "a_tag", 2, 0); > + ASSERT_EQ(id, 3, "decl_tag_a"); > + id = btf__add_ptr(btf, 2); > + ASSERT_EQ(id, 4, "proto_ptr"); > + id = btf__add_typedef(btf, "fn", 4); > + ASSERT_EQ(id, 5, "typedef"); can you please also add decl_tag for func_proto itself (comp_idx == -1) > + > + err = btf_dump_all_types(btf, d); > + ASSERT_OK(err, "btf_dump_all_types #1"); > + fflush(dump_buf_file); > + dump_buf[dump_buf_sz] = 0; /* some libc implementations don't do this */ > + > + ASSERT_STREQ(dump_buf, > + "#if __has_attribute(btf_decl_tag)\n" > + "#define __btf_decl_tag(x) __attribute__((btf_decl_tag(x)))\n" > + "#else\n" > + "#define __btf_decl_tag(x)\n" > + "#endif\n" > + "\n" > + "typedef void (*fn)(int a __btf_decl_tag(\"a_tag\"));\n\n", > + "decl tags for fn"); > + [...] > +struct tag_on_field_and_struct { > + int x __btf_decl_tag("t1"); > +} __btf_decl_tag("t2"); > + > +struct root_struct { > + struct empty_with_tag a; > + struct one_tag b; > + struct same_tag c; > + struct two_tags d; > + struct packed e; > + td_with_tag f; > + struct tags_on_fields g; > + struct tag_on_field_and_struct h; > +}; > + > +SEC(".data") int global_var __btf_decl_tag("var_tag") = (int)777; do you need explicit SEC(".data")? I'd expect global_var is put into .data anyways. If it's about __attribute__((unused)), then we can do that more explicitly here instead of through SEC()? Or just make sure global_var is used in f() internally > + > +/* ------ END-EXPECTED-OUTPUT ------ */ > + > +int f(struct root_struct *s) > +{ > + return 0; > +} > -- > 2.34.1 >