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

Merge branch 'bpf_iter-BTF_ID-at-build-time'

Yonghong Song says:

====================
Commit 5a2798ab32ba
("bpf: Add BTF_ID_LIST/BTF_ID/BTF_ID_UNUSED macros")
implemented a mechanism to compute btf_ids at kernel build
time which can simplify kernel implementation and reduce
runtime overhead by removing in-kernel btf_id calculation.

This patch set tried to use this mechanism to compute
btf_ids for bpf_skc_to_*() helpers and for btf_id_or_null ctx
arguments specified during bpf iterator registration.
Please see individual patch for details.

Changelogs:
v1 -> v2:
- v1 ([1]) is only for bpf_skc_to_*() helpers. This version
expanded it to cover ctx btf_id_or_null arguments
- abandoned the change of "extern u32 name[]" to
"static u32 name[]" for BPF_ID_LIST local "name" definition.
gcc 9 incurred a compilation error.

[1]: https://lore.kernel.org/bpf/20200717184706.3476992-1-yhs@fb.com/T
====================

Signed-off-by: Alexei Starovoitov <ast@kernel.org>

+153 -73
+1 -4
include/linux/bpf.h
··· 668 668 struct bpf_ctx_arg_aux { 669 669 u32 offset; 670 670 enum bpf_reg_type reg_type; 671 + u32 btf_id; 671 672 }; 672 673 673 674 struct bpf_prog_aux { ··· 1542 1541 1543 1542 struct bpf_map *bpf_map_offload_map_alloc(union bpf_attr *attr); 1544 1543 void bpf_map_offload_map_free(struct bpf_map *map); 1545 - void init_btf_sock_ids(struct btf *btf); 1546 1544 #else 1547 1545 static inline int bpf_prog_offload_init(struct bpf_prog *prog, 1548 1546 union bpf_attr *attr) ··· 1565 1565 } 1566 1566 1567 1567 static inline void bpf_map_offload_map_free(struct bpf_map *map) 1568 - { 1569 - } 1570 - static inline void init_btf_sock_ids(struct btf *btf) 1571 1568 { 1572 1569 } 1573 1570 #endif /* CONFIG_NET && CONFIG_BPF_SYSCALL */
+37 -3
include/linux/btf_ids.h
··· 57 57 * .zero 4 58 58 * 59 59 */ 60 - #define __BTF_ID_LIST(name) \ 60 + #define __BTF_ID_LIST(name, scope) \ 61 61 asm( \ 62 62 ".pushsection " BTF_IDS_SECTION ",\"a\"; \n" \ 63 - ".local " #name "; \n" \ 63 + "." #scope " " #name "; \n" \ 64 64 #name ":; \n" \ 65 65 ".popsection; \n"); \ 66 66 67 67 #define BTF_ID_LIST(name) \ 68 - __BTF_ID_LIST(name) \ 68 + __BTF_ID_LIST(name, local) \ 69 69 extern u32 name[]; 70 + 71 + #define BTF_ID_LIST_GLOBAL(name) \ 72 + __BTF_ID_LIST(name, globl) 70 73 71 74 /* 72 75 * The BTF_ID_UNUSED macro defines 4 zero bytes. ··· 93 90 #define BTF_ID_LIST(name) static u32 name[5]; 94 91 #define BTF_ID(prefix, name) 95 92 #define BTF_ID_UNUSED 93 + #define BTF_ID_LIST_GLOBAL(name) u32 name[1]; 96 94 97 95 #endif /* CONFIG_DEBUG_INFO_BTF */ 96 + 97 + #ifdef CONFIG_NET 98 + /* Define a list of socket types which can be the argument for 99 + * skc_to_*_sock() helpers. All these sockets should have 100 + * sock_common as the first argument in its memory layout. 101 + */ 102 + #define BTF_SOCK_TYPE_xxx \ 103 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_INET, inet_sock) \ 104 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_INET_CONN, inet_connection_sock) \ 105 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_INET_REQ, inet_request_sock) \ 106 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_INET_TW, inet_timewait_sock) \ 107 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_REQ, request_sock) \ 108 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_SOCK, sock) \ 109 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_SOCK_COMMON, sock_common) \ 110 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP, tcp_sock) \ 111 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP_REQ, tcp_request_sock) \ 112 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP_TW, tcp_timewait_sock) \ 113 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP6, tcp6_sock) \ 114 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_UDP, udp_sock) \ 115 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_UDP6, udp6_sock) 116 + 117 + enum { 118 + #define BTF_SOCK_TYPE(name, str) name, 119 + BTF_SOCK_TYPE_xxx 120 + #undef BTF_SOCK_TYPE 121 + MAX_BTF_SOCK_TYPE, 122 + }; 123 + 124 + extern u32 btf_sock_ids[]; 125 + #endif 98 126 99 127 #endif
+3 -3
kernel/bpf/btf.c
··· 3672 3672 goto errout; 3673 3673 3674 3674 bpf_struct_ops_init(btf, log); 3675 - init_btf_sock_ids(btf); 3676 3675 3677 3676 btf_verifier_env_free(env); 3678 3677 refcount_set(&btf->refcnt, 1); ··· 3817 3818 return true; 3818 3819 3819 3820 /* this is a pointer to another type */ 3820 - info->reg_type = PTR_TO_BTF_ID; 3821 3821 for (i = 0; i < prog->aux->ctx_arg_info_size; i++) { 3822 3822 const struct bpf_ctx_arg_aux *ctx_arg_info = &prog->aux->ctx_arg_info[i]; 3823 3823 3824 3824 if (ctx_arg_info->offset == off) { 3825 3825 info->reg_type = ctx_arg_info->reg_type; 3826 - break; 3826 + info->btf_id = ctx_arg_info->btf_id; 3827 + return true; 3827 3828 } 3828 3829 } 3829 3830 3831 + info->reg_type = PTR_TO_BTF_ID; 3830 3832 if (tgt_prog) { 3831 3833 ret = btf_translate_to_vmlinux(log, btf, t, tgt_prog->type, arg); 3832 3834 if (ret > 0) {
+6 -1
kernel/bpf/map_iter.c
··· 4 4 #include <linux/fs.h> 5 5 #include <linux/filter.h> 6 6 #include <linux/kernel.h> 7 + #include <linux/btf_ids.h> 7 8 8 9 struct bpf_iter_seq_map_info { 9 10 u32 mid; ··· 82 81 .show = bpf_map_seq_show, 83 82 }; 84 83 85 - static const struct bpf_iter_reg bpf_map_reg_info = { 84 + BTF_ID_LIST(btf_bpf_map_id) 85 + BTF_ID(struct, bpf_map) 86 + 87 + static struct bpf_iter_reg bpf_map_reg_info = { 86 88 .target = "bpf_map", 87 89 .seq_ops = &bpf_map_seq_ops, 88 90 .init_seq_private = NULL, ··· 100 96 101 97 static int __init bpf_map_iter_init(void) 102 98 { 99 + bpf_map_reg_info.ctx_arg_info[0].btf_id = *btf_bpf_map_id; 103 100 return bpf_iter_reg_target(&bpf_map_reg_info); 104 101 } 105 102
+10 -2
kernel/bpf/task_iter.c
··· 7 7 #include <linux/fs.h> 8 8 #include <linux/fdtable.h> 9 9 #include <linux/filter.h> 10 + #include <linux/btf_ids.h> 10 11 11 12 struct bpf_iter_seq_task_common { 12 13 struct pid_namespace *ns; ··· 313 312 .show = task_file_seq_show, 314 313 }; 315 314 316 - static const struct bpf_iter_reg task_reg_info = { 315 + BTF_ID_LIST(btf_task_file_ids) 316 + BTF_ID(struct, task_struct) 317 + BTF_ID(struct, file) 318 + 319 + static struct bpf_iter_reg task_reg_info = { 317 320 .target = "task", 318 321 .seq_ops = &task_seq_ops, 319 322 .init_seq_private = init_seq_pidns, ··· 330 325 }, 331 326 }; 332 327 333 - static const struct bpf_iter_reg task_file_reg_info = { 328 + static struct bpf_iter_reg task_file_reg_info = { 334 329 .target = "task_file", 335 330 .seq_ops = &task_file_seq_ops, 336 331 .init_seq_private = init_seq_pidns, ··· 349 344 { 350 345 int ret; 351 346 347 + task_reg_info.ctx_arg_info[0].btf_id = btf_task_file_ids[0]; 352 348 ret = bpf_iter_reg_target(&task_reg_info); 353 349 if (ret) 354 350 return ret; 355 351 352 + task_file_reg_info.ctx_arg_info[0].btf_id = btf_task_file_ids[0]; 353 + task_file_reg_info.ctx_arg_info[1].btf_id = btf_task_file_ids[1]; 356 354 return bpf_iter_reg_target(&task_file_reg_info); 357 355 } 358 356 late_initcall(task_iter_init);
+5 -44
net/core/filter.c
··· 9421 9421 bpf_dispatcher_change_prog(BPF_DISPATCHER_PTR(xdp), prev_prog, prog); 9422 9422 } 9423 9423 9424 - /* Define a list of socket types which can be the argument for 9425 - * skc_to_*_sock() helpers. All these sockets should have 9426 - * sock_common as the first argument in its memory layout. 9427 - */ 9428 - #define BTF_SOCK_TYPE_xxx \ 9429 - BTF_SOCK_TYPE(BTF_SOCK_TYPE_INET, "inet_sock") \ 9430 - BTF_SOCK_TYPE(BTF_SOCK_TYPE_INET_CONN, "inet_connection_sock") \ 9431 - BTF_SOCK_TYPE(BTF_SOCK_TYPE_INET_REQ, "inet_request_sock") \ 9432 - BTF_SOCK_TYPE(BTF_SOCK_TYPE_INET_TW, "inet_timewait_sock") \ 9433 - BTF_SOCK_TYPE(BTF_SOCK_TYPE_REQ, "request_sock") \ 9434 - BTF_SOCK_TYPE(BTF_SOCK_TYPE_SOCK, "sock") \ 9435 - BTF_SOCK_TYPE(BTF_SOCK_TYPE_SOCK_COMMON, "sock_common") \ 9436 - BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP, "tcp_sock") \ 9437 - BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP_REQ, "tcp_request_sock") \ 9438 - BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP_TW, "tcp_timewait_sock") \ 9439 - BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP6, "tcp6_sock") \ 9440 - BTF_SOCK_TYPE(BTF_SOCK_TYPE_UDP, "udp_sock") \ 9441 - BTF_SOCK_TYPE(BTF_SOCK_TYPE_UDP6, "udp6_sock") 9442 - 9443 - enum { 9444 - #define BTF_SOCK_TYPE(name, str) name, 9424 + #ifdef CONFIG_DEBUG_INFO_BTF 9425 + BTF_ID_LIST_GLOBAL(btf_sock_ids) 9426 + #define BTF_SOCK_TYPE(name, type) BTF_ID(struct, type) 9445 9427 BTF_SOCK_TYPE_xxx 9446 9428 #undef BTF_SOCK_TYPE 9447 - MAX_BTF_SOCK_TYPE, 9448 - }; 9449 - 9450 - static int btf_sock_ids[MAX_BTF_SOCK_TYPE]; 9451 - 9452 - #ifdef CONFIG_BPF_SYSCALL 9453 - static const char *bpf_sock_types[] = { 9454 - #define BTF_SOCK_TYPE(name, str) str, 9455 - BTF_SOCK_TYPE_xxx 9456 - #undef BTF_SOCK_TYPE 9457 - }; 9458 - 9459 - void init_btf_sock_ids(struct btf *btf) 9460 - { 9461 - int i, btf_id; 9462 - 9463 - for (i = 0; i < MAX_BTF_SOCK_TYPE; i++) { 9464 - btf_id = btf_find_by_name_kind(btf, bpf_sock_types[i], 9465 - BTF_KIND_STRUCT); 9466 - if (btf_id > 0) 9467 - btf_sock_ids[i] = btf_id; 9468 - } 9469 - } 9429 + #else 9430 + u32 btf_sock_ids[MAX_BTF_SOCK_TYPE]; 9470 9431 #endif 9471 9432 9472 9433 static bool check_arg_btf_id(u32 btf_id, u32 arg)
+3 -1
net/ipv4/tcp_ipv4.c
··· 76 76 #include <linux/proc_fs.h> 77 77 #include <linux/seq_file.h> 78 78 #include <linux/inetdevice.h> 79 + #include <linux/btf_ids.h> 79 80 80 81 #include <crypto/hash.h> 81 82 #include <linux/scatterlist.h> ··· 2955 2954 bpf_iter_fini_seq_net(priv_data); 2956 2955 } 2957 2956 2958 - static const struct bpf_iter_reg tcp_reg_info = { 2957 + static struct bpf_iter_reg tcp_reg_info = { 2959 2958 .target = "tcp", 2960 2959 .seq_ops = &bpf_iter_tcp_seq_ops, 2961 2960 .init_seq_private = bpf_iter_init_tcp, ··· 2970 2969 2971 2970 static void __init bpf_iter_register(void) 2972 2971 { 2972 + tcp_reg_info.ctx_arg_info[0].btf_id = btf_sock_ids[BTF_SOCK_TYPE_SOCK_COMMON]; 2973 2973 if (bpf_iter_reg_target(&tcp_reg_info)) 2974 2974 pr_warn("Warning: could not register bpf iterator tcp\n"); 2975 2975 }
+3 -1
net/ipv4/udp.c
··· 106 106 #include <net/xfrm.h> 107 107 #include <trace/events/udp.h> 108 108 #include <linux/static_key.h> 109 + #include <linux/btf_ids.h> 109 110 #include <trace/events/skb.h> 110 111 #include <net/busy_poll.h> 111 112 #include "udp_impl.h" ··· 3233 3232 bpf_iter_fini_seq_net(priv_data); 3234 3233 } 3235 3234 3236 - static const struct bpf_iter_reg udp_reg_info = { 3235 + static struct bpf_iter_reg udp_reg_info = { 3237 3236 .target = "udp", 3238 3237 .seq_ops = &bpf_iter_udp_seq_ops, 3239 3238 .init_seq_private = bpf_iter_init_udp, ··· 3248 3247 3249 3248 static void __init bpf_iter_register(void) 3250 3249 { 3250 + udp_reg_info.ctx_arg_info[0].btf_id = btf_sock_ids[BTF_SOCK_TYPE_UDP]; 3251 3251 if (bpf_iter_reg_target(&udp_reg_info)) 3252 3252 pr_warn("Warning: could not register bpf iterator udp\n"); 3253 3253 }
+6 -1
net/ipv6/route.c
··· 61 61 #include <net/l3mdev.h> 62 62 #include <net/ip.h> 63 63 #include <linux/uaccess.h> 64 + #include <linux/btf_ids.h> 64 65 65 66 #ifdef CONFIG_SYSCTL 66 67 #include <linux/sysctl.h> ··· 6424 6423 #if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS) 6425 6424 DEFINE_BPF_ITER_FUNC(ipv6_route, struct bpf_iter_meta *meta, struct fib6_info *rt) 6426 6425 6427 - static const struct bpf_iter_reg ipv6_route_reg_info = { 6426 + BTF_ID_LIST(btf_fib6_info_id) 6427 + BTF_ID(struct, fib6_info) 6428 + 6429 + static struct bpf_iter_reg ipv6_route_reg_info = { 6428 6430 .target = "ipv6_route", 6429 6431 .seq_ops = &ipv6_route_seq_ops, 6430 6432 .init_seq_private = bpf_iter_init_seq_net, ··· 6442 6438 6443 6439 static int __init bpf_iter_register(void) 6444 6440 { 6441 + ipv6_route_reg_info.ctx_arg_info[0].btf_id = *btf_fib6_info_id; 6445 6442 return bpf_iter_reg_target(&ipv6_route_reg_info); 6446 6443 } 6447 6444
+6 -1
net/netlink/af_netlink.c
··· 60 60 #include <linux/genetlink.h> 61 61 #include <linux/net_namespace.h> 62 62 #include <linux/nospec.h> 63 + #include <linux/btf_ids.h> 63 64 64 65 #include <net/net_namespace.h> 65 66 #include <net/netns/generic.h> ··· 2804 2803 }; 2805 2804 2806 2805 #if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS) 2807 - static const struct bpf_iter_reg netlink_reg_info = { 2806 + BTF_ID_LIST(btf_netlink_sock_id) 2807 + BTF_ID(struct, netlink_sock) 2808 + 2809 + static struct bpf_iter_reg netlink_reg_info = { 2808 2810 .target = "netlink", 2809 2811 .seq_ops = &netlink_seq_ops, 2810 2812 .init_seq_private = bpf_iter_init_seq_net, ··· 2822 2818 2823 2819 static int __init bpf_iter_register(void) 2824 2820 { 2821 + netlink_reg_info.ctx_arg_info[0].btf_id = *btf_netlink_sock_id; 2825 2822 return bpf_iter_reg_target(&netlink_reg_info); 2826 2823 } 2827 2824 #endif
+47 -4
tools/include/linux/btf_ids.h
··· 3 3 #ifndef _LINUX_BTF_IDS_H 4 4 #define _LINUX_BTF_IDS_H 5 5 6 + #ifdef CONFIG_DEBUG_INFO_BTF 7 + 6 8 #include <linux/compiler.h> /* for __PASTE */ 7 9 8 10 /* ··· 23 21 asm( \ 24 22 ".pushsection " BTF_IDS_SECTION ",\"a\"; \n" \ 25 23 ".local " #symbol " ; \n" \ 26 - ".type " #symbol ", @object; \n" \ 24 + ".type " #symbol ", STT_OBJECT; \n" \ 27 25 ".size " #symbol ", 4; \n" \ 28 26 #symbol ": \n" \ 29 27 ".zero 4 \n" \ ··· 57 55 * .zero 4 58 56 * 59 57 */ 60 - #define __BTF_ID_LIST(name) \ 58 + #define __BTF_ID_LIST(name, scope) \ 61 59 asm( \ 62 60 ".pushsection " BTF_IDS_SECTION ",\"a\"; \n" \ 63 - ".local " #name "; \n" \ 61 + "." #scope " " #name "; \n" \ 64 62 #name ":; \n" \ 65 63 ".popsection; \n"); \ 66 64 67 65 #define BTF_ID_LIST(name) \ 68 - __BTF_ID_LIST(name) \ 66 + __BTF_ID_LIST(name, local) \ 69 67 extern u32 name[]; 68 + 69 + #define BTF_ID_LIST_GLOBAL(name) \ 70 + __BTF_ID_LIST(name, globl) 70 71 71 72 /* 72 73 * The BTF_ID_UNUSED macro defines 4 zero bytes. ··· 88 83 ".zero 4 \n" \ 89 84 ".popsection; \n"); 90 85 86 + #else 87 + 88 + #define BTF_ID_LIST(name) static u32 name[5]; 89 + #define BTF_ID(prefix, name) 90 + #define BTF_ID_UNUSED 91 + #define BTF_ID_LIST_GLOBAL(name) u32 name[1]; 92 + 93 + #endif /* CONFIG_DEBUG_INFO_BTF */ 94 + 95 + #ifdef CONFIG_NET 96 + /* Define a list of socket types which can be the argument for 97 + * skc_to_*_sock() helpers. All these sockets should have 98 + * sock_common as the first argument in its memory layout. 99 + */ 100 + #define BTF_SOCK_TYPE_xxx \ 101 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_INET, inet_sock) \ 102 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_INET_CONN, inet_connection_sock) \ 103 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_INET_REQ, inet_request_sock) \ 104 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_INET_TW, inet_timewait_sock) \ 105 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_REQ, request_sock) \ 106 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_SOCK, sock) \ 107 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_SOCK_COMMON, sock_common) \ 108 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP, tcp_sock) \ 109 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP_REQ, tcp_request_sock) \ 110 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP_TW, tcp_timewait_sock) \ 111 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP6, tcp6_sock) \ 112 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_UDP, udp_sock) \ 113 + BTF_SOCK_TYPE(BTF_SOCK_TYPE_UDP6, udp6_sock) 114 + 115 + enum { 116 + #define BTF_SOCK_TYPE(name, str) name, 117 + BTF_SOCK_TYPE_xxx 118 + #undef BTF_SOCK_TYPE 119 + MAX_BTF_SOCK_TYPE, 120 + }; 121 + 122 + extern u32 btf_sock_ids[]; 123 + #endif 91 124 92 125 #endif
+26 -8
tools/testing/selftests/bpf/prog_tests/resolve_btfids.c
··· 6 6 #include <bpf/libbpf.h> 7 7 #include <linux/btf.h> 8 8 #include <linux/kernel.h> 9 + #define CONFIG_DEBUG_INFO_BTF 9 10 #include <linux/btf_ids.h> 10 11 #include "test_progs.h" 11 12 ··· 28 27 { "func", BTF_KIND_FUNC, -1 }, 29 28 }; 30 29 31 - BTF_ID_LIST(test_list) 30 + BTF_ID_LIST(test_list_local) 31 + BTF_ID_UNUSED 32 + BTF_ID(typedef, S) 33 + BTF_ID(typedef, T) 34 + BTF_ID(typedef, U) 35 + BTF_ID(struct, S) 36 + BTF_ID(union, U) 37 + BTF_ID(func, func) 38 + 39 + extern __u32 test_list_global[]; 40 + BTF_ID_LIST_GLOBAL(test_list_global) 32 41 BTF_ID_UNUSED 33 42 BTF_ID(typedef, S) 34 43 BTF_ID(typedef, T) ··· 104 93 105 94 int test_resolve_btfids(void) 106 95 { 107 - unsigned int i; 96 + __u32 *test_list, *test_lists[] = { test_list_local, test_list_global }; 97 + unsigned int i, j; 108 98 int ret = 0; 109 99 110 100 if (resolve_symbols()) 111 101 return -1; 112 102 113 - /* Check BTF_ID_LIST(test_list) IDs */ 114 - for (i = 0; i < ARRAY_SIZE(test_symbols) && !ret; i++) { 115 - ret = CHECK(test_list[i] != test_symbols[i].id, 116 - "id_check", 117 - "wrong ID for %s (%d != %d)\n", test_symbols[i].name, 118 - test_list[i], test_symbols[i].id); 103 + /* Check BTF_ID_LIST(test_list_local) and 104 + * BTF_ID_LIST_GLOBAL(test_list_global) IDs 105 + */ 106 + for (j = 0; j < ARRAY_SIZE(test_lists); j++) { 107 + test_list = test_lists[j]; 108 + for (i = 0; i < ARRAY_SIZE(test_symbols) && !ret; i++) { 109 + ret = CHECK(test_list[i] != test_symbols[i].id, 110 + "id_check", 111 + "wrong ID for %s (%d != %d)\n", 112 + test_symbols[i].name, 113 + test_list[i], test_symbols[i].id); 114 + } 119 115 } 120 116 121 117 return ret;