Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'btf-arbitrary-__attribute__-encoding'

Ihor Solodrai says:

====================
BTF: arbitrary __attribute__ encoding

This patch series extends BPF Type Format (BTF) to support arbitrary
__attribute__ encoding.

Setting the kind_flag to 1 in BTF type tags and decl tags now changes
the meaning for the encoded tag, in particular with respect to
btf_dump in libbpf.

If the kflag is set, then the string encoded by the tag represents the
full attribute-list of an attribute specifier [1].

This feature will allow extending tools such as pahole and bpftool to
capture and use more granular type information, and make it easier to
manage compatibility between clang and gcc BPF compilers.

[1] https://gcc.gnu.org/onlinedocs/gcc-13.2.0/gcc/Attribute-Syntax.html

v2->v3: nit fixes suggested by Andrii
v1->v2:
- When checking for specific BTF tags in the verifier, make sure the
tag's kflag is 0
- Split docs and libbpf changes into separate patches
- Various renames, as suggested by Andrii and Eduard

v2: https://lore.kernel.org/bpf/20250127233955.2275804-1-ihor.solodrai@linux.dev/
v1: https://lore.kernel.org/bpf/20250122025308.2717553-1-ihor.solodrai@pm.me
====================

Link: https://patch.msgid.link/20250130201239.1429648-1-ihor.solodrai@linux.dev
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>

+244 -85
+21 -4
Documentation/bpf/btf.rst
··· 102 102 * bits 24-28: kind (e.g. int, ptr, array...etc) 103 103 * bits 29-30: unused 104 104 * bit 31: kind_flag, currently used by 105 - * struct, union, fwd, enum and enum64. 105 + * struct, union, enum, fwd, enum64, 106 + * decl_tag and type_tag 106 107 */ 107 108 __u32 info; 108 109 /* "size" is used by INT, ENUM, STRUCT, UNION and ENUM64. ··· 479 478 480 479 ``struct btf_type`` encoding requirement: 481 480 * ``name_off``: offset to a non-empty string 482 - * ``info.kind_flag``: 0 481 + * ``info.kind_flag``: 0 or 1 483 482 * ``info.kind``: BTF_KIND_DECL_TAG 484 483 * ``info.vlen``: 0 485 484 * ``type``: ``struct``, ``union``, ``func``, ``var`` or ``typedef`` ··· 490 489 __u32 component_idx; 491 490 }; 492 491 493 - The ``name_off`` encodes btf_decl_tag attribute string. 494 492 The ``type`` should be ``struct``, ``union``, ``func``, ``var`` or ``typedef``. 495 493 For ``var`` or ``typedef`` type, ``btf_decl_tag.component_idx`` must be ``-1``. 496 494 For the other three types, if the btf_decl_tag attribute is ··· 499 499 a ``func`` argument, and ``btf_decl_tag.component_idx`` should be a 500 500 valid index (starting from 0) pointing to a member or an argument. 501 501 502 + If ``info.kind_flag`` is 0, then this is a normal decl tag, and the 503 + ``name_off`` encodes btf_decl_tag attribute string. 504 + 505 + If ``info.kind_flag`` is 1, then the decl tag represents an arbitrary 506 + __attribute__. In this case, ``name_off`` encodes a string 507 + representing the attribute-list of the attribute specifier. For 508 + example, for an ``__attribute__((aligned(4)))`` the string's contents 509 + is ``aligned(4)``. 510 + 502 511 2.2.18 BTF_KIND_TYPE_TAG 503 512 ~~~~~~~~~~~~~~~~~~~~~~~~ 504 513 505 514 ``struct btf_type`` encoding requirement: 506 515 * ``name_off``: offset to a non-empty string 507 - * ``info.kind_flag``: 0 516 + * ``info.kind_flag``: 0 or 1 508 517 * ``info.kind``: BTF_KIND_TYPE_TAG 509 518 * ``info.vlen``: 0 510 519 * ``type``: the type with ``btf_type_tag`` attribute ··· 530 521 type_tag, then zero or more const/volatile/restrict/typedef 531 522 and finally the base type. The base type is one of 532 523 int, ptr, array, struct, union, enum, func_proto and float types. 524 + 525 + Similarly to decl tags, if the ``info.kind_flag`` is 0, then this is a 526 + normal type tag, and the ``name_off`` encodes btf_type_tag attribute 527 + string. 528 + 529 + If ``info.kind_flag`` is 1, then the type tag represents an arbitrary 530 + __attribute__, and the ``name_off`` encodes a string representing the 531 + attribute-list of the attribute specifier. 533 532 534 533 2.2.19 BTF_KIND_ENUM64 535 534 ~~~~~~~~~~~~~~~~~~~~~~
+2 -1
include/uapi/linux/btf.h
··· 36 36 * bits 24-28: kind (e.g. int, ptr, array...etc) 37 37 * bits 29-30: unused 38 38 * bit 31: kind_flag, currently used by 39 - * struct, union, enum, fwd and enum64 39 + * struct, union, enum, fwd, enum64, 40 + * decl_tag and type_tag 40 41 */ 41 42 __u32 info; 42 43 /* "size" is used by INT, ENUM, STRUCT, UNION, DATASEC and ENUM64.
+12 -14
kernel/bpf/btf.c
··· 2575 2575 return -EINVAL; 2576 2576 } 2577 2577 2578 - if (btf_type_kflag(t)) { 2578 + if (btf_type_kflag(t) && !btf_type_is_type_tag(t)) { 2579 2579 btf_verifier_log_type(env, t, "Invalid btf_info kind_flag"); 2580 2580 return -EINVAL; 2581 2581 } ··· 3332 3332 u32 off, int sz, struct btf_field_info *info, u32 field_mask) 3333 3333 { 3334 3334 enum btf_field_type type; 3335 + const char *tag_value; 3336 + bool is_type_tag; 3335 3337 u32 res_id; 3336 3338 3337 3339 /* Permit modifiers on the pointer itself */ ··· 3343 3341 if (!btf_type_is_ptr(t)) 3344 3342 return BTF_FIELD_IGNORE; 3345 3343 t = btf_type_by_id(btf, t->type); 3346 - 3347 - if (!btf_type_is_type_tag(t)) 3344 + is_type_tag = btf_type_is_type_tag(t) && !btf_type_kflag(t); 3345 + if (!is_type_tag) 3348 3346 return BTF_FIELD_IGNORE; 3349 3347 /* Reject extra tags */ 3350 3348 if (btf_type_is_type_tag(btf_type_by_id(btf, t->type))) 3351 3349 return -EINVAL; 3352 - if (!strcmp("kptr_untrusted", __btf_name_by_offset(btf, t->name_off))) 3350 + tag_value = __btf_name_by_offset(btf, t->name_off); 3351 + if (!strcmp("kptr_untrusted", tag_value)) 3353 3352 type = BPF_KPTR_UNREF; 3354 - else if (!strcmp("kptr", __btf_name_by_offset(btf, t->name_off))) 3353 + else if (!strcmp("kptr", tag_value)) 3355 3354 type = BPF_KPTR_REF; 3356 - else if (!strcmp("percpu_kptr", __btf_name_by_offset(btf, t->name_off))) 3355 + else if (!strcmp("percpu_kptr", tag_value)) 3357 3356 type = BPF_KPTR_PERCPU; 3358 - else if (!strcmp("uptr", __btf_name_by_offset(btf, t->name_off))) 3357 + else if (!strcmp("uptr", tag_value)) 3359 3358 type = BPF_UPTR; 3360 3359 else 3361 3360 return -EINVAL; ··· 4944 4941 4945 4942 if (btf_type_vlen(t)) { 4946 4943 btf_verifier_log_type(env, t, "vlen != 0"); 4947 - return -EINVAL; 4948 - } 4949 - 4950 - if (btf_type_kflag(t)) { 4951 - btf_verifier_log_type(env, t, "Invalid btf_info kind_flag"); 4952 4944 return -EINVAL; 4953 4945 } 4954 4946 ··· 6741 6743 info->btf_id = t->type; 6742 6744 t = btf_type_by_id(btf, t->type); 6743 6745 6744 - if (btf_type_is_type_tag(t)) { 6746 + if (btf_type_is_type_tag(t) && !btf_type_kflag(t)) { 6745 6747 tag_value = __btf_name_by_offset(btf, t->name_off); 6746 6748 if (strcmp(tag_value, "user") == 0) 6747 6749 info->reg_type |= MEM_USER; ··· 7000 7002 7001 7003 /* check type tag */ 7002 7004 t = btf_type_by_id(btf, mtype->type); 7003 - if (btf_type_is_type_tag(t)) { 7005 + if (btf_type_is_type_tag(t) && !btf_type_kflag(t)) { 7004 7006 tag_value = __btf_name_by_offset(btf, t->name_off); 7005 7007 /* check __user tag */ 7006 7008 if (strcmp(tag_value, "user") == 0)
+2 -1
tools/include/uapi/linux/btf.h
··· 36 36 * bits 24-28: kind (e.g. int, ptr, array...etc) 37 37 * bits 29-30: unused 38 38 * bit 31: kind_flag, currently used by 39 - * struct, union, enum, fwd and enum64 39 + * struct, union, enum, fwd, enum64, 40 + * decl_tag and type_tag 40 41 */ 41 42 __u32 info; 42 43 /* "size" is used by INT, ENUM, STRUCT, UNION, DATASEC and ENUM64.
+63 -23
tools/lib/bpf/btf.c
··· 2090 2090 } 2091 2091 2092 2092 /* generic append function for PTR, TYPEDEF, CONST/VOLATILE/RESTRICT */ 2093 - static int btf_add_ref_kind(struct btf *btf, int kind, const char *name, int ref_type_id) 2093 + static int btf_add_ref_kind(struct btf *btf, int kind, const char *name, int ref_type_id, int kflag) 2094 2094 { 2095 2095 struct btf_type *t; 2096 2096 int sz, name_off = 0; ··· 2113 2113 } 2114 2114 2115 2115 t->name_off = name_off; 2116 - t->info = btf_type_info(kind, 0, 0); 2116 + t->info = btf_type_info(kind, 0, kflag); 2117 2117 t->type = ref_type_id; 2118 2118 2119 2119 return btf_commit_type(btf, sz); ··· 2128 2128 */ 2129 2129 int btf__add_ptr(struct btf *btf, int ref_type_id) 2130 2130 { 2131 - return btf_add_ref_kind(btf, BTF_KIND_PTR, NULL, ref_type_id); 2131 + return btf_add_ref_kind(btf, BTF_KIND_PTR, NULL, ref_type_id, 0); 2132 2132 } 2133 2133 2134 2134 /* ··· 2506 2506 struct btf_type *t; 2507 2507 int id; 2508 2508 2509 - id = btf_add_ref_kind(btf, BTF_KIND_FWD, name, 0); 2509 + id = btf_add_ref_kind(btf, BTF_KIND_FWD, name, 0, 0); 2510 2510 if (id <= 0) 2511 2511 return id; 2512 2512 t = btf_type_by_id(btf, id); ··· 2536 2536 if (!name || !name[0]) 2537 2537 return libbpf_err(-EINVAL); 2538 2538 2539 - return btf_add_ref_kind(btf, BTF_KIND_TYPEDEF, name, ref_type_id); 2539 + return btf_add_ref_kind(btf, BTF_KIND_TYPEDEF, name, ref_type_id, 0); 2540 2540 } 2541 2541 2542 2542 /* ··· 2548 2548 */ 2549 2549 int btf__add_volatile(struct btf *btf, int ref_type_id) 2550 2550 { 2551 - return btf_add_ref_kind(btf, BTF_KIND_VOLATILE, NULL, ref_type_id); 2551 + return btf_add_ref_kind(btf, BTF_KIND_VOLATILE, NULL, ref_type_id, 0); 2552 2552 } 2553 2553 2554 2554 /* ··· 2560 2560 */ 2561 2561 int btf__add_const(struct btf *btf, int ref_type_id) 2562 2562 { 2563 - return btf_add_ref_kind(btf, BTF_KIND_CONST, NULL, ref_type_id); 2563 + return btf_add_ref_kind(btf, BTF_KIND_CONST, NULL, ref_type_id, 0); 2564 2564 } 2565 2565 2566 2566 /* ··· 2572 2572 */ 2573 2573 int btf__add_restrict(struct btf *btf, int ref_type_id) 2574 2574 { 2575 - return btf_add_ref_kind(btf, BTF_KIND_RESTRICT, NULL, ref_type_id); 2575 + return btf_add_ref_kind(btf, BTF_KIND_RESTRICT, NULL, ref_type_id, 0); 2576 2576 } 2577 2577 2578 2578 /* ··· 2588 2588 if (!value || !value[0]) 2589 2589 return libbpf_err(-EINVAL); 2590 2590 2591 - return btf_add_ref_kind(btf, BTF_KIND_TYPE_TAG, value, ref_type_id); 2591 + return btf_add_ref_kind(btf, BTF_KIND_TYPE_TAG, value, ref_type_id, 0); 2592 + } 2593 + 2594 + /* 2595 + * Append new BTF_KIND_TYPE_TAG type with: 2596 + * - *value*, non-empty/non-NULL tag value; 2597 + * - *ref_type_id* - referenced type ID, it might not exist yet; 2598 + * Set info->kflag to 1, indicating this tag is an __attribute__ 2599 + * Returns: 2600 + * - >0, type ID of newly added BTF type; 2601 + * - <0, on error. 2602 + */ 2603 + int btf__add_type_attr(struct btf *btf, const char *value, int ref_type_id) 2604 + { 2605 + if (!value || !value[0]) 2606 + return libbpf_err(-EINVAL); 2607 + 2608 + return btf_add_ref_kind(btf, BTF_KIND_TYPE_TAG, value, ref_type_id, 1); 2592 2609 } 2593 2610 2594 2611 /* ··· 2627 2610 linkage != BTF_FUNC_EXTERN) 2628 2611 return libbpf_err(-EINVAL); 2629 2612 2630 - id = btf_add_ref_kind(btf, BTF_KIND_FUNC, name, proto_type_id); 2613 + id = btf_add_ref_kind(btf, BTF_KIND_FUNC, name, proto_type_id, 0); 2631 2614 if (id > 0) { 2632 2615 struct btf_type *t = btf_type_by_id(btf, id); 2633 2616 ··· 2862 2845 return 0; 2863 2846 } 2864 2847 2865 - /* 2866 - * Append new BTF_KIND_DECL_TAG type with: 2867 - * - *value* - non-empty/non-NULL string; 2868 - * - *ref_type_id* - referenced type ID, it might not exist yet; 2869 - * - *component_idx* - -1 for tagging reference type, otherwise struct/union 2870 - * member or function argument index; 2871 - * Returns: 2872 - * - >0, type ID of newly added BTF type; 2873 - * - <0, on error. 2874 - */ 2875 - int btf__add_decl_tag(struct btf *btf, const char *value, int ref_type_id, 2876 - int component_idx) 2848 + static int btf_add_decl_tag(struct btf *btf, const char *value, int ref_type_id, 2849 + int component_idx, int kflag) 2877 2850 { 2878 2851 struct btf_type *t; 2879 2852 int sz, value_off; ··· 2887 2880 return value_off; 2888 2881 2889 2882 t->name_off = value_off; 2890 - t->info = btf_type_info(BTF_KIND_DECL_TAG, 0, false); 2883 + t->info = btf_type_info(BTF_KIND_DECL_TAG, 0, kflag); 2891 2884 t->type = ref_type_id; 2892 2885 btf_decl_tag(t)->component_idx = component_idx; 2893 2886 2894 2887 return btf_commit_type(btf, sz); 2888 + } 2889 + 2890 + /* 2891 + * Append new BTF_KIND_DECL_TAG type with: 2892 + * - *value* - non-empty/non-NULL string; 2893 + * - *ref_type_id* - referenced type ID, it might not exist yet; 2894 + * - *component_idx* - -1 for tagging reference type, otherwise struct/union 2895 + * member or function argument index; 2896 + * Returns: 2897 + * - >0, type ID of newly added BTF type; 2898 + * - <0, on error. 2899 + */ 2900 + int btf__add_decl_tag(struct btf *btf, const char *value, int ref_type_id, 2901 + int component_idx) 2902 + { 2903 + return btf_add_decl_tag(btf, value, ref_type_id, component_idx, 0); 2904 + } 2905 + 2906 + /* 2907 + * Append new BTF_KIND_DECL_TAG type with: 2908 + * - *value* - non-empty/non-NULL string; 2909 + * - *ref_type_id* - referenced type ID, it might not exist yet; 2910 + * - *component_idx* - -1 for tagging reference type, otherwise struct/union 2911 + * member or function argument index; 2912 + * Set info->kflag to 1, indicating this tag is an __attribute__ 2913 + * Returns: 2914 + * - >0, type ID of newly added BTF type; 2915 + * - <0, on error. 2916 + */ 2917 + int btf__add_decl_attr(struct btf *btf, const char *value, int ref_type_id, 2918 + int component_idx) 2919 + { 2920 + return btf_add_decl_tag(btf, value, ref_type_id, component_idx, 1); 2895 2921 } 2896 2922 2897 2923 struct btf_ext_sec_info_param {
+3
tools/lib/bpf/btf.h
··· 227 227 LIBBPF_API int btf__add_const(struct btf *btf, int ref_type_id); 228 228 LIBBPF_API int btf__add_restrict(struct btf *btf, int ref_type_id); 229 229 LIBBPF_API int btf__add_type_tag(struct btf *btf, const char *value, int ref_type_id); 230 + LIBBPF_API int btf__add_type_attr(struct btf *btf, const char *value, int ref_type_id); 230 231 231 232 /* func and func_proto construction APIs */ 232 233 LIBBPF_API int btf__add_func(struct btf *btf, const char *name, ··· 244 243 /* tag construction API */ 245 244 LIBBPF_API int btf__add_decl_tag(struct btf *btf, const char *value, int ref_type_id, 246 245 int component_idx); 246 + LIBBPF_API int btf__add_decl_attr(struct btf *btf, const char *value, int ref_type_id, 247 + int component_idx); 247 248 248 249 struct btf_dedup_opts { 249 250 size_t sz;
+4 -1
tools/lib/bpf/btf_dump.c
··· 1494 1494 case BTF_KIND_TYPE_TAG: 1495 1495 btf_dump_emit_mods(d, decls); 1496 1496 name = btf_name_of(d, t->name_off); 1497 - btf_dump_printf(d, " __attribute__((btf_type_tag(\"%s\")))", name); 1497 + if (btf_kflag(t)) 1498 + btf_dump_printf(d, " __attribute__((%s))", name); 1499 + else 1500 + btf_dump_printf(d, " __attribute__((btf_type_tag(\"%s\")))", name); 1498 1501 break; 1499 1502 case BTF_KIND_ARRAY: { 1500 1503 const struct btf_array *a = btf_array(t);
+2
tools/lib/bpf/libbpf.map
··· 436 436 bpf_linker__add_buf; 437 437 bpf_linker__add_fd; 438 438 bpf_linker__new_fd; 439 + btf__add_decl_attr; 440 + btf__add_type_attr; 439 441 } LIBBPF_1.5.0;
+19 -4
tools/testing/selftests/bpf/prog_tests/btf.c
··· 3866 3866 .err_str = "vlen != 0", 3867 3867 }, 3868 3868 { 3869 - .descr = "decl_tag test #8, invalid kflag", 3869 + .descr = "decl_tag test #8, tag with kflag", 3870 3870 .raw_types = { 3871 3871 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ 3872 3872 BTF_VAR_ENC(NAME_TBD, 1, 0), /* [2] */ 3873 - BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_DECL_TAG, 1, 0), 2), (-1), 3873 + BTF_DECL_ATTR_ENC(NAME_TBD, 2, -1), 3874 3874 BTF_END_RAW, 3875 3875 }, 3876 3876 BTF_STR_SEC("\0local\0tag1"), ··· 3881 3881 .key_type_id = 1, 3882 3882 .value_type_id = 1, 3883 3883 .max_entries = 1, 3884 - .btf_load_err = true, 3885 - .err_str = "Invalid btf_info kind_flag", 3886 3884 }, 3887 3885 { 3888 3886 .descr = "decl_tag test #9, var, invalid component_idx", ··· 4203 4205 .max_entries = 1, 4204 4206 .btf_load_err = true, 4205 4207 .err_str = "Type tags don't precede modifiers", 4208 + }, 4209 + { 4210 + .descr = "type_tag test #7, tag with kflag", 4211 + .raw_types = { 4212 + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ 4213 + BTF_TYPE_ATTR_ENC(NAME_TBD, 1), /* [2] */ 4214 + BTF_PTR_ENC(2), /* [3] */ 4215 + BTF_END_RAW, 4216 + }, 4217 + BTF_STR_SEC("\0tag"), 4218 + .map_type = BPF_MAP_TYPE_ARRAY, 4219 + .map_name = "tag_type_check_btf", 4220 + .key_size = sizeof(int), 4221 + .value_size = 4, 4222 + .key_type_id = 1, 4223 + .value_type_id = 1, 4224 + .max_entries = 1, 4206 4225 }, 4207 4226 { 4208 4227 .descr = "enum64 test #1, unsigned, size 8",
+110 -37
tools/testing/selftests/bpf/prog_tests/btf_dump.c
··· 126 126 return err; 127 127 } 128 128 129 - static char *dump_buf; 130 - static size_t dump_buf_sz; 131 - static FILE *dump_buf_file; 129 + struct test_ctx { 130 + struct btf *btf; 131 + struct btf_dump *d; 132 + char *dump_buf; 133 + size_t dump_buf_sz; 134 + FILE *dump_buf_file; 135 + }; 136 + 137 + static void test_ctx__free(struct test_ctx *t) 138 + { 139 + fclose(t->dump_buf_file); 140 + free(t->dump_buf); 141 + btf_dump__free(t->d); 142 + btf__free(t->btf); 143 + } 144 + 145 + static int test_ctx__init(struct test_ctx *t) 146 + { 147 + t->dump_buf_file = open_memstream(&t->dump_buf, &t->dump_buf_sz); 148 + if (!ASSERT_OK_PTR(t->dump_buf_file, "dump_memstream")) 149 + return -1; 150 + t->btf = btf__new_empty(); 151 + if (!ASSERT_OK_PTR(t->btf, "new_empty")) 152 + goto err_out; 153 + t->d = btf_dump__new(t->btf, btf_dump_printf, t->dump_buf_file, NULL); 154 + if (!ASSERT_OK(libbpf_get_error(t->d), "btf_dump__new")) 155 + goto err_out; 156 + 157 + return 0; 158 + 159 + err_out: 160 + test_ctx__free(t); 161 + return -1; 162 + } 163 + 164 + static void test_ctx__dump_and_compare(struct test_ctx *t, 165 + const char *expected_output, 166 + const char *message) 167 + { 168 + int i, err; 169 + 170 + for (i = 1; i < btf__type_cnt(t->btf); i++) { 171 + err = btf_dump__dump_type(t->d, i); 172 + ASSERT_OK(err, "dump_type_ok"); 173 + } 174 + 175 + fflush(t->dump_buf_file); 176 + t->dump_buf[t->dump_buf_sz] = 0; /* some libc implementations don't do this */ 177 + 178 + ASSERT_STREQ(t->dump_buf, expected_output, message); 179 + } 132 180 133 181 static void test_btf_dump_incremental(void) 134 182 { 135 - struct btf *btf = NULL; 136 - struct btf_dump *d = NULL; 137 - int id, err, i; 183 + struct test_ctx t = {}; 184 + struct btf *btf; 185 + int id, err; 138 186 139 - dump_buf_file = open_memstream(&dump_buf, &dump_buf_sz); 140 - if (!ASSERT_OK_PTR(dump_buf_file, "dump_memstream")) 187 + if (test_ctx__init(&t)) 141 188 return; 142 - btf = btf__new_empty(); 143 - if (!ASSERT_OK_PTR(btf, "new_empty")) 144 - goto err_out; 145 - d = btf_dump__new(btf, btf_dump_printf, dump_buf_file, NULL); 146 - if (!ASSERT_OK(libbpf_get_error(d), "btf_dump__new")) 147 - goto err_out; 189 + 190 + btf = t.btf; 148 191 149 192 /* First, generate BTF corresponding to the following C code: 150 193 * ··· 225 182 err = btf__add_field(btf, "x", 4, 0, 0); 226 183 ASSERT_OK(err, "field_ok"); 227 184 228 - for (i = 1; i < btf__type_cnt(btf); i++) { 229 - err = btf_dump__dump_type(d, i); 230 - ASSERT_OK(err, "dump_type_ok"); 231 - } 232 - 233 - fflush(dump_buf_file); 234 - dump_buf[dump_buf_sz] = 0; /* some libc implementations don't do this */ 235 - 236 - ASSERT_STREQ(dump_buf, 185 + test_ctx__dump_and_compare(&t, 237 186 "enum x;\n" 238 187 "\n" 239 188 "enum x {\n" ··· 256 221 * enum values don't conflict; 257 222 * 258 223 */ 259 - fseek(dump_buf_file, 0, SEEK_SET); 224 + fseek(t.dump_buf_file, 0, SEEK_SET); 260 225 261 226 id = btf__add_struct(btf, "s", 4); 262 227 ASSERT_EQ(id, 7, "struct_id"); ··· 267 232 err = btf__add_field(btf, "s", 6, 64, 0); 268 233 ASSERT_OK(err, "field_ok"); 269 234 270 - for (i = 1; i < btf__type_cnt(btf); i++) { 271 - err = btf_dump__dump_type(d, i); 272 - ASSERT_OK(err, "dump_type_ok"); 273 - } 274 - 275 - fflush(dump_buf_file); 276 - dump_buf[dump_buf_sz] = 0; /* some libc implementations don't do this */ 277 - ASSERT_STREQ(dump_buf, 235 + test_ctx__dump_and_compare(&t, 278 236 "struct s___2 {\n" 279 237 " enum x x;\n" 280 238 " enum {\n" ··· 276 248 " struct s s;\n" 277 249 "};\n\n" , "c_dump1"); 278 250 279 - err_out: 280 - fclose(dump_buf_file); 281 - free(dump_buf); 282 - btf_dump__free(d); 283 - btf__free(btf); 251 + test_ctx__free(&t); 252 + } 253 + 254 + static void test_btf_dump_type_tags(void) 255 + { 256 + struct test_ctx t = {}; 257 + struct btf *btf; 258 + int id, err; 259 + 260 + if (test_ctx__init(&t)) 261 + return; 262 + 263 + btf = t.btf; 264 + 265 + /* Generate BTF corresponding to the following C code: 266 + * 267 + * struct s { 268 + * void __attribute__((btf_type_tag(\"void_tag\"))) *p1; 269 + * void __attribute__((void_attr)) *p2; 270 + * }; 271 + * 272 + */ 273 + 274 + id = btf__add_type_tag(btf, "void_tag", 0); 275 + ASSERT_EQ(id, 1, "type_tag_id"); 276 + id = btf__add_ptr(btf, id); 277 + ASSERT_EQ(id, 2, "void_ptr_id1"); 278 + 279 + id = btf__add_type_attr(btf, "void_attr", 0); 280 + ASSERT_EQ(id, 3, "type_attr_id"); 281 + id = btf__add_ptr(btf, id); 282 + ASSERT_EQ(id, 4, "void_ptr_id2"); 283 + 284 + id = btf__add_struct(btf, "s", 8); 285 + ASSERT_EQ(id, 5, "struct_id"); 286 + err = btf__add_field(btf, "p1", 2, 0, 0); 287 + ASSERT_OK(err, "field_ok1"); 288 + err = btf__add_field(btf, "p2", 4, 0, 0); 289 + ASSERT_OK(err, "field_ok2"); 290 + 291 + test_ctx__dump_and_compare(&t, 292 + "struct s {\n" 293 + " void __attribute__((btf_type_tag(\"void_tag\"))) *p1;\n" 294 + " void __attribute__((void_attr)) *p2;\n" 295 + "};\n\n", "dump_and_compare"); 296 + 297 + test_ctx__free(&t); 284 298 } 285 299 286 300 #define STRSIZE 4096 ··· 943 873 } 944 874 if (test__start_subtest("btf_dump: incremental")) 945 875 test_btf_dump_incremental(); 876 + 877 + if (test__start_subtest("btf_dump: type_tags")) 878 + test_btf_dump_type_tags(); 946 879 947 880 btf = libbpf_find_kernel_btf(); 948 881 if (!ASSERT_OK_PTR(btf, "no kernel BTF found"))
+6
tools/testing/selftests/bpf/test_btf.h
··· 72 72 #define BTF_TYPE_FLOAT_ENC(name, sz) \ 73 73 BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_FLOAT, 0, 0), sz) 74 74 75 + #define BTF_DECL_ATTR_ENC(value, type, component_idx) \ 76 + BTF_TYPE_ENC(value, BTF_INFO_ENC(BTF_KIND_DECL_TAG, 1, 0), type), (component_idx) 77 + 75 78 #define BTF_DECL_TAG_ENC(value, type, component_idx) \ 76 79 BTF_TYPE_ENC(value, BTF_INFO_ENC(BTF_KIND_DECL_TAG, 0, 0), type), (component_idx) 80 + 81 + #define BTF_TYPE_ATTR_ENC(value, type) \ 82 + BTF_TYPE_ENC(value, BTF_INFO_ENC(BTF_KIND_TYPE_TAG, 1, 0), type) 77 83 78 84 #define BTF_TYPE_TAG_ENC(value, type) \ 79 85 BTF_TYPE_ENC(value, BTF_INFO_ENC(BTF_KIND_TYPE_TAG, 0, 0), type)