1 /*
2 * Check bpf(BPF_OBJ_GET_INFO_BY_FD) decoding.
3 *
4 * Copyright (c) 2018-2022 The strace developers.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "tests.h"
11
12 #ifndef CHECK_OBJ_PROG
13 # define CHECK_OBJ_PROG 0
14 #endif
15
16 #include <inttypes.h>
17 #include <stddef.h>
18 #include <stdio.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <time.h>
23 #include <unistd.h>
24 #include <sys/sysmacros.h>
25
26 #include "print_fields.h"
27 #include "scno.h"
28
29 #ifdef HAVE_LINUX_BPF_H
30 # include <linux/bpf.h>
31 #endif
32
33 #include "bpf_attr.h"
34
35 #include "xlat.h"
36 #include "xlat/bpf_map_flags.h"
37 #include "xlat/bpf_map_types.h"
38 #include "xlat/bpf_prog_types.h"
39
40 #define XLAT_MACROS_ONLY
41 #include "xlat/bpf_commands.h"
42 #include "xlat/bpf_op_alu.h"
43 #include "xlat/bpf_op_jmp.h"
44 #include "xlat/bpf_size.h"
45 #include "xlat/bpf_src.h"
46 #include "xlat/clocknames.h"
47 #include "xlat/ebpf_class.h"
48 #include "xlat/ebpf_mode.h"
49 #include "xlat/ebpf_op_alu.h"
50 #include "xlat/ebpf_regs.h"
51 #include "xlat/ebpf_size.h"
52
53 #ifndef HAVE_STRUCT_BPF_INSN
54 struct bpf_insn {
55 uint8_t code;
56 uint8_t dst_reg:4;
57 uint8_t src_reg:4;
58 int16_t off;
59 int32_t imm;
60 };
61 #endif
62
63 static const char *errstr;
64
65 static long
66 sys_bpf(kernel_ulong_t cmd, void *attr, kernel_ulong_t size)
67 {
68 long rc = syscall(__NR_bpf, cmd, attr, size);
69 errstr = sprintrc(rc);
70 return rc;
71 }
72
73 static void
74 print_map_create(void *attr_void, size_t size, long rc)
75 {
76 struct BPF_MAP_CREATE_struct *attr = attr_void;
77
78 printf("bpf(BPF_MAP_CREATE, {map_type=BPF_MAP_TYPE_ARRAY, key_size=4"
79 ", value_size=%u, max_entries=%u",
80 attr->value_size, attr->max_entries);
81 if (size > offsetof(struct BPF_MAP_CREATE_struct, map_flags))
82 printf(", map_flags=0");
83 if (size > offsetof(struct BPF_MAP_CREATE_struct, inner_map_fd))
84 printf(", inner_map_fd=0</dev/null>");
85 if (size > offsetof(struct BPF_MAP_CREATE_struct, map_name))
86 printf(", map_name=\"%s\"", attr->map_name);
87 if (size > offsetof(struct BPF_MAP_CREATE_struct, map_ifindex))
88 printf(", map_ifindex=0");
89 if (size > offsetof(struct BPF_MAP_CREATE_struct, btf_fd)) {
90 printf(", btf_fd=0</dev/null>"
91 ", btf_key_type_id=0, btf_value_type_id=0");
92 }
93 if (size > offsetof(struct BPF_MAP_CREATE_struct,
94 btf_vmlinux_value_type_id)) {
95 printf(", btf_vmlinux_value_type_id=0");
96 }
97 if (size > offsetof(struct BPF_MAP_CREATE_struct,
98 map_extra)) {
99 printf(", map_extra=0");
100 }
101 printf("}, %zu) = ", size);
102 if (rc >= 0)
103 printf("%ld<anon_inode:bpf-map>\n", rc);
104 else
105 puts(errstr);
106 }
107
108 #if CHECK_OBJ_PROG
109 static struct bpf_insn socket_prog[] = {
110 { /* 0 */
111 .code = BPF_ALU64 | BPF_K | BPF_MOV,
112 .dst_reg = BPF_REG_1,
113 .imm = 0,
114 },
115 { /* 1 */
116 .code = BPF_STX | BPF_W | BPF_MEM,
117 .dst_reg = BPF_REG_10,
118 .src_reg = BPF_REG_1,
119 .off = -4,
120 },
121 { /* 2 */
122 .code = BPF_ALU64 | BPF_X | BPF_MOV,
123 .dst_reg = BPF_REG_2,
124 .src_reg = BPF_REG_10,
125 },
126 { /* 3 */
127 .code = BPF_ALU64 | BPF_K | BPF_ADD,
128 .dst_reg = BPF_REG_2,
129 .imm = -4,
130 },
131 { /* 4 */
132 .code = BPF_LD | BPF_DW | BPF_IMM,
133 .dst_reg = BPF_REG_1,
134 .src_reg = 1 /* BPF_PSEUDO_MAP_FD */,
135 .imm = 0, /* to be set to map fd2 */
136 },
137 { /* 5 */
138 .imm = 0,
139 },
140 { /* 6 */
141 .code = BPF_LD | BPF_DW | BPF_IMM,
142 .dst_reg = BPF_REG_1,
143 .src_reg = 1 /* BPF_PSEUDO_MAP_FD */,
144 .imm = 0, /* to be set to map fd */
145 },
146 { /* 7 */
147 .imm = 0,
148 },
149 { /* 8 */
150 .code = BPF_JMP | BPF_K | BPF_CALL,
151 .imm = 0x1, /* BPF_FUNC_map_lookup_elem */
152 },
153 { /* 9 */
154 .code = BPF_ALU64 | BPF_K | BPF_MOV,
155 .dst_reg = BPF_REG_0,
156 .imm = 0,
157 },
158 { /* 10 */
159 .code = BPF_JMP | BPF_K | BPF_EXIT,
160 },
161 };
162
163 # if VERBOSE
164 static const char *socket_prog_fmt =
165 "[{code=BPF_ALU64|BPF_K|BPF_MOV"
166 ", dst_reg=BPF_REG_1, src_reg=BPF_REG_0, off=0, imm=0}"
167 ", {code=BPF_STX|BPF_W|BPF_MEM"
168 ", dst_reg=BPF_REG_10, src_reg=BPF_REG_1, off=-4, imm=0}"
169 ", {code=BPF_ALU64|BPF_X|BPF_MOV"
170 ", dst_reg=BPF_REG_2, src_reg=BPF_REG_10, off=0, imm=0}"
171 ", {code=BPF_ALU64|BPF_K|BPF_ADD"
172 ", dst_reg=BPF_REG_2, src_reg=BPF_REG_0, off=0, imm=0xfffffffc}"
173 ", {code=BPF_LD|BPF_DW|BPF_IMM"
174 ", dst_reg=BPF_REG_1, src_reg=BPF_REG_1, off=0, imm=%#x}"
175 ", {code=BPF_LD|BPF_W|BPF_IMM"
176 ", dst_reg=BPF_REG_0, src_reg=BPF_REG_0, off=0, imm=0}"
177 ", {code=BPF_LD|BPF_DW|BPF_IMM"
178 ", dst_reg=BPF_REG_1, src_reg=BPF_REG_1, off=0, imm=%#x}"
179 ", {code=BPF_LD|BPF_W|BPF_IMM"
180 ", dst_reg=BPF_REG_0, src_reg=BPF_REG_0, off=0, imm=0}"
181 ", {code=BPF_JMP|BPF_K|BPF_CALL"
182 ", dst_reg=BPF_REG_0, src_reg=BPF_REG_0, off=0, imm=0x1}"
183 ", {code=BPF_ALU64|BPF_K|BPF_MOV"
184 ", dst_reg=BPF_REG_0, src_reg=BPF_REG_0, off=0, imm=0}"
185 ", {code=BPF_JMP|BPF_K|BPF_EXIT"
186 ", dst_reg=BPF_REG_0, src_reg=BPF_REG_0, off=0, imm=0}"
187 "]";
188 # endif /* VERBOSE */
189
190 static const char *license = "BSD";
191 static char log_buf[4096];
192
193 static void
194 print_prog_load(void *attr_void, size_t size, long rc)
195 {
196 printf("bpf(BPF_PROG_LOAD, {prog_type=BPF_PROG_TYPE_SOCKET_FILTER"
197 ", insn_cnt=%zu, insns=", ARRAY_SIZE(socket_prog));
198 # if VERBOSE
199 printf(socket_prog_fmt, socket_prog[4].imm, socket_prog[6].imm);
200 # else
201 printf("%p", socket_prog);
202 # endif
203 if (size > offsetof(struct BPF_PROG_LOAD_struct, license))
204 printf(", license=\"BSD\"");
205 if (size > offsetof(struct BPF_PROG_LOAD_struct, log_buf))
206 printf(", log_level=7, log_size=%zu, log_buf=\"\"",
207 sizeof(log_buf));
208 if (size > offsetof(struct BPF_PROG_LOAD_struct, kern_version))
209 printf(", kern_version=KERNEL_VERSION(57005, 192, 222)");
210 if (size > offsetof(struct BPF_PROG_LOAD_struct, prog_flags))
211 printf(", prog_flags=0");
212 if (size > offsetof(struct BPF_PROG_LOAD_struct, prog_name))
213 printf(", prog_name=\"test_prog\"");
214 if (size > offsetof(struct BPF_PROG_LOAD_struct, prog_ifindex))
215 printf(", prog_ifindex=0");
216 if (size > offsetof(struct BPF_PROG_LOAD_struct, expected_attach_type))
217 printf(", expected_attach_type=BPF_CGROUP_INET_INGRESS");
218 if (size > offsetof(struct BPF_PROG_LOAD_struct, prog_btf_fd))
219 printf(", prog_btf_fd=0</dev/null>");
220 if (size > offsetof(struct BPF_PROG_LOAD_struct, func_info_rec_size))
221 printf(", func_info_rec_size=0");
222 if (size > offsetof(struct BPF_PROG_LOAD_struct, func_info))
223 printf(", func_info=NULL");
224 if (size > offsetof(struct BPF_PROG_LOAD_struct, func_info_cnt))
225 printf(", func_info_cnt=0");
226 if (size > offsetof(struct BPF_PROG_LOAD_struct, line_info_rec_size))
227 printf(", line_info_rec_size=0");
228 if (size > offsetof(struct BPF_PROG_LOAD_struct, line_info))
229 printf(", line_info=NULL");
230 if (size > offsetof(struct BPF_PROG_LOAD_struct, line_info_cnt))
231 printf(", line_info_cnt=0");
232 if (size > offsetof(struct BPF_PROG_LOAD_struct, attach_btf_id))
233 printf(", attach_btf_id=0");
234 if (size > offsetof(struct BPF_PROG_LOAD_struct, attach_prog_fd))
235 printf(", attach_prog_fd=0</dev/null>");
236 if (size > offsetof(struct BPF_PROG_LOAD_struct, fd_array))
237 printf(", fd_array=NULL");
238 printf("}, %zu) = ", size);
239 if (rc >= 0)
240 printf("%ld<anon_inode:bpf-prog>\n", rc);
241 else
242 puts(errstr);
243 }
244 #endif /* CHECK_OBJ_PROG */
245
246 static long
247 try_bpf(kernel_ulong_t cmd, void (*printer)(void *attr, size_t size, long rc),
248 void *attr, size_t **sizes)
249 {
250 long rc;
251
252 for (rc = -1; **sizes; (*sizes)++) {
253 rc = sys_bpf(cmd, attr, **sizes);
254 printer(attr, **sizes, rc);
255
256 if (rc >= 0)
257 break;
258 }
259
260 return rc;
261 }
262
263 int
264 main(int ac, char **av)
265 {
266 /*
267 * There is a delay when the locked memory is being reclaimed
268 * after a BPF program or map is removed.
269 *
270 * Privileged tools like iproute2 and bpftool workaround this
271 * by raising RLIMIT_MEMLOCK to infinity prior to creating
272 * BPF objects.
273 *
274 * This test is expected to be invoked without extra privileges
275 * and therefore does not have this option.
276 *
277 * The approach taken by this test is serialize all invocations
278 * and insert a delay long enough to let the locked memory be
279 * reclaimed.
280 */
281 lock_file_by_dirname(av[0], "bpf-obj_get_info_by_fd");
282 sleep(1);
283
284 int ret;
285
286 struct BPF_MAP_CREATE_struct bpf_map_create_attr = {
287 .map_type = BPF_MAP_TYPE_ARRAY,
288 .key_size = 4,
289 .value_size = 8,
290 .max_entries = 1,
291 .map_name = "test_map",
292 };
293 struct BPF_MAP_CREATE_struct bpf_map_create_attr2 = {
294 .map_type = BPF_MAP_TYPE_ARRAY,
295 .key_size = 4,
296 .value_size = 1,
297 .max_entries = 5,
298 .map_name = "test_map_too",
299 };
300 size_t bpf_map_create_attr_sizes[] = {
301 sizeof(bpf_map_create_attr),
302 offsetofend(struct BPF_MAP_CREATE_struct, max_entries),
303 0,
304 };
305
306 #if CHECK_OBJ_PROG
307 struct BPF_PROG_LOAD_struct bpf_prog_load_attr = {
308 .prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
309 .insn_cnt = ARRAY_SIZE(socket_prog),
310 .insns = (uintptr_t) socket_prog,
311 .license = (uintptr_t) license,
312 .log_level = 7,
313 .log_size = sizeof(log_buf),
314 .log_buf = (uintptr_t) log_buf,
315 .kern_version = 0xdeadc0de,
316 .prog_name = "test_prog",
317 };
318 size_t bpf_prog_load_attr_sizes[] = {
319 BPF_PROG_LOAD_struct_size,
320 offsetofend(struct BPF_PROG_LOAD_struct, prog_name),
321 offsetofend(struct BPF_PROG_LOAD_struct, prog_flags),
322 offsetofend(struct BPF_PROG_LOAD_struct, kern_version),
323 offsetofend(struct BPF_PROG_LOAD_struct, log_buf),
324 offsetofend(struct BPF_PROG_LOAD_struct, license),
325 offsetofend(struct BPF_PROG_LOAD_struct, insns),
326 0,
327 };
328 #endif /* CHECK_OBJ_PROG */
329
330 size_t *bpf_map_create_attr_size = bpf_map_create_attr_sizes;
331 int map_fd = try_bpf(BPF_MAP_CREATE, print_map_create,
332 &bpf_map_create_attr, &bpf_map_create_attr_size);
333 if (map_fd < 0)
334 perror_msg_and_skip("First BPF_MAP_CREATE failed");
335 int map_fd2 = try_bpf(BPF_MAP_CREATE, print_map_create,
336 &bpf_map_create_attr2, &bpf_map_create_attr_size);
337 if (map_fd2 < 0)
338 perror_msg_and_skip("Second BPF_MAP_CREATE failed");
339
340 #if CHECK_OBJ_PROG
341 socket_prog[4].imm = map_fd2;
342 socket_prog[6].imm = map_fd;
343
344 size_t *bpf_prog_load_attr_size = bpf_prog_load_attr_sizes;
345 int prog_fd = try_bpf(BPF_PROG_LOAD, print_prog_load,
346 &bpf_prog_load_attr, &bpf_prog_load_attr_size);
347 if (prog_fd < 0)
348 perror_msg_and_skip("BPF_PROG_LOAD failed (log: \"%s\")",
349 log_buf);
350 #endif /* CHECK_OBJ_PROG */
351
352 /*
353 * This has to be a macro, otherwise the compiler complains that
354 * initializer element is not constant.
355 */
356 #define MAP_INFO_SZ (sizeof(*map_info) + 64)
357 struct bpf_map_info_struct *map_info = tail_alloc(MAP_INFO_SZ
358 + sizeof(*map_info));
359 struct BPF_OBJ_GET_INFO_BY_FD_struct bpf_map_get_info_attr[] = {
360 {
361 .bpf_fd = map_fd,
362 .info_len = sizeof(*map_info),
363 .info = (uintptr_t) map_info,
364 },
365 {
366 .bpf_fd = map_fd2,
367 .info_len = MAP_INFO_SZ,
368 .info = (uintptr_t) (map_info + 1),
369 },
370 };
371
372 for (size_t i = 0; i < 2; i++) {
373 memset(map_info + i, 0, MAP_INFO_SZ);
374 ret = sys_bpf(BPF_OBJ_GET_INFO_BY_FD,
375 &bpf_map_get_info_attr[i],
376 sizeof(bpf_map_get_info_attr[i]));
377 if (ret < 0)
378 perror_msg_and_skip("BPF_OBJ_GET_INFO_BY_FD map failed");
379
380 printf("bpf(BPF_OBJ_GET_INFO_BY_FD"
381 ", {info={bpf_fd=%d<anon_inode:bpf-map>, info_len=%zu",
382 i ? map_fd2 : map_fd,
383 i ? MAP_INFO_SZ : sizeof(*map_info));
384 if (bpf_map_get_info_attr[i].info_len !=
385 (i ? MAP_INFO_SZ : sizeof(*map_info)))
386 printf(" => %u", bpf_map_get_info_attr[i].info_len);
387
388 printf(", info=");
389 #if VERBOSE
390 printf("{type=");
391 printxval(bpf_map_types, map_info[i].type, "BPF_MAP_TYPE_???");
392 printf(", ");
393 PRINT_FIELD_U(map_info[i], id);
394 printf(", ");
395 PRINT_FIELD_U(map_info[i], key_size);
396 printf(", ");
397 PRINT_FIELD_U(map_info[i], value_size);
398 printf(", ");
399 PRINT_FIELD_U(map_info[i], max_entries);
400 printf(", map_flags=");
401 printflags(bpf_map_flags, map_info[i].map_flags, "BPF_F_???");
402
403 if (bpf_map_get_info_attr[i].info_len >
404 offsetof(struct bpf_map_info_struct, name)) {
405 printf(", name=");
406 print_quoted_cstring(map_info[i].name,
407 sizeof(map_info[i].name));
408 }
409 if (bpf_map_get_info_attr[i].info_len >
410 offsetof(struct bpf_map_info_struct, ifindex))
411 printf(", ifindex=%u", map_info[i].ifindex);
412 if (bpf_map_get_info_attr[i].info_len >
413 offsetof(struct bpf_map_info_struct,
414 btf_vmlinux_value_type_id)) {
415 printf(", btf_vmlinux_value_type_id=%u",
416 map_info[i].btf_vmlinux_value_type_id);
417 }
418 if (bpf_map_get_info_attr[i].info_len >
419 offsetof(struct bpf_map_info_struct, netns_dev))
420 printf(", netns_dev=makedev(%#x, %#x)",
421 major(map_info[i].netns_dev),
422 minor(map_info[i].netns_dev));
423 if (bpf_map_get_info_attr[i].info_len >
424 offsetof(struct bpf_map_info_struct, netns_ino))
425 printf(", netns_ino=%" PRIu64, map_info[i].netns_ino);
426 if (bpf_map_get_info_attr[i].info_len >
427 offsetof(struct bpf_map_info_struct, btf_id)) {
428 printf(", ");
429 PRINT_FIELD_U(map_info[i], btf_id);
430 }
431 if (bpf_map_get_info_attr[i].info_len >
432 offsetof(struct bpf_map_info_struct, btf_key_type_id)) {
433 printf(", ");
434 PRINT_FIELD_U(map_info[i], btf_key_type_id);
435 }
436 if (bpf_map_get_info_attr[i].info_len >
437 offsetof(struct bpf_map_info_struct, btf_value_type_id)) {
438 printf(", ");
439 PRINT_FIELD_U(map_info[i], btf_value_type_id);
440 }
441 printf("}");
442 #else /* !VERBOSE */
443 printf("%p", map_info + i);
444 #endif /* VERBOSE */
445 printf("}}, %zu) = %s\n", sizeof(bpf_map_get_info_attr[i]),
446 errstr);
447 }
448
449 #if CHECK_OBJ_PROG
450 /*
451 * This has to be a macro, otherwise the compiler complains that
452 * initializer element is not constant.
453 */
454 # define PROG_INFO_SZ (sizeof(*prog_info) + 64)
455 struct bpf_prog_info_struct *prog_info = tail_alloc(PROG_INFO_SZ);
456 struct bpf_insn *xlated_prog = tail_alloc(sizeof(*xlated_prog) * 42);
457 uint32_t *map_ids = tail_alloc(sizeof(*map_ids) * 3);
458 struct BPF_OBJ_GET_INFO_BY_FD_struct bpf_prog_get_info_attr = {
459 .bpf_fd = prog_fd,
460 .info_len = PROG_INFO_SZ,
461 .info = (uintptr_t) prog_info,
462 };
463 size_t old_prog_info_len = PROG_INFO_SZ;
464
465 memset(prog_info, 0, PROG_INFO_SZ);
466 for (unsigned int i = 0; i < 5; i++) {
467 prog_info->jited_prog_len = 0;
468 prog_info->nr_jited_ksyms = 0;
469 prog_info->nr_jited_func_lens = 0;
470 prog_info->func_info_rec_size = 0;
471 prog_info->nr_func_info = 0;
472 prog_info->nr_line_info = 0;
473 prog_info->nr_jited_line_info = 0;
474 prog_info->jited_line_info = 0;
475 prog_info->line_info_rec_size = 0;
476 prog_info->jited_line_info_rec_size = 0;
477 prog_info->nr_prog_tags = 0;
478 memset(prog_info + 1, 0, PROG_INFO_SZ - sizeof(*prog_info));
479 switch (i) {
480 case 1:
481 prog_info->xlated_prog_insns =
482 (uintptr_t) (xlated_prog + 42);
483 prog_info->xlated_prog_len = 336;
484 prog_info->map_ids = (uintptr_t) (map_ids + 3);
485 prog_info->nr_map_ids = 3;
486 break;
487 case 2:
488 prog_info->xlated_prog_insns = (uintptr_t) xlated_prog;
489 /* TODO: check xlated_prog output */
490 prog_info->xlated_prog_len = 0;
491 prog_info->map_ids = (uintptr_t) map_ids;
492 prog_info->nr_map_ids = 0;
493 break;
494 case 3:
495 prog_info->xlated_prog_insns = (uintptr_t) xlated_prog;
496 prog_info->xlated_prog_len = 0;
497 prog_info->map_ids = (uintptr_t) map_ids;
498 prog_info->nr_map_ids = 3;
499 break;
500 case 4:
501 prog_info->xlated_prog_insns = (uintptr_t) xlated_prog;
502 prog_info->xlated_prog_len = 1;
503 prog_info->map_ids = (uintptr_t) (map_ids + 1);
504 prog_info->nr_map_ids = 1;
505 }
506
507 ret = sys_bpf(BPF_OBJ_GET_INFO_BY_FD, &bpf_prog_get_info_attr,
508 sizeof(bpf_prog_get_info_attr));
509 if (i != 1 && i != 4 && ret < 0)
510 perror_msg_and_skip("BPF_OBJ_GET_INFO_BY_FD"
511 " prog %u failed", i);
512
513 printf("bpf(BPF_OBJ_GET_INFO_BY_FD"
514 ", {info={bpf_fd=%d<anon_inode:bpf-prog>, info_len=%zu",
515 prog_fd, old_prog_info_len);
516 if (!i && bpf_prog_get_info_attr.info_len != PROG_INFO_SZ)
517 printf(" => %u", bpf_prog_get_info_attr.info_len);
518 old_prog_info_len = bpf_prog_get_info_attr.info_len;
519
520 printf(", info=");
521 # if VERBOSE
522 printf("{type=");
523 printxval(bpf_prog_types, prog_info->type, "BPF_PROG_TYPE_???");
524 printf(", ");
525 PRINT_FIELD_U(*prog_info, id);
526 printf(", tag=");
527 print_quoted_hex(prog_info->tag, sizeof(prog_info->tag));
528 printf(", jited_prog_len=0");
529 if (prog_info->jited_prog_len)
530 printf(" => %u", prog_info->jited_prog_len);
531 printf(", jited_prog_insns=NULL");
532 switch (i) {
533 case 0:
534 printf(", xlated_prog_len=0");
535 if (prog_info->xlated_prog_len)
536 printf(" => %u", prog_info->xlated_prog_len);
537 printf(", xlated_prog_insns=NULL");
538 break;
539 case 1:
540 printf(", xlated_prog_len=336");
541 if (prog_info->xlated_prog_len != 336)
542 printf(" => %u", prog_info->xlated_prog_len);
543 if (prog_info->xlated_prog_len)
544 printf(", xlated_prog_insns=%p", xlated_prog + 42);
545 else
546 printf(", xlated_prog_insns=[]");
547 break;
548 case 2:
549 case 3:
550 printf(", xlated_prog_len=0");
551 if (prog_info->xlated_prog_len)
552 printf(" => %u", prog_info->xlated_prog_len);
553 printf(", xlated_prog_insns=[]");
554 break;
555 case 4:
556 printf(", xlated_prog_len=1");
557 if (prog_info->xlated_prog_len != 1)
558 printf(" => %u", prog_info->xlated_prog_len);
559 printf(", xlated_prog_insns=[]");
560 break;
561 }
562
563 if (bpf_prog_get_info_attr.info_len >
564 offsetof(struct bpf_prog_info_struct, load_time)) {
565 enum { S_NS = 1000000000 };
566
567 printf(", load_time=%" PRIu64, prog_info->load_time);
568
569 /*
570 * NB: this is janky, as strace can get somewhat
571 * different results.
572 */
573 struct timespec boot;
574 struct timespec rtc;
575
576 if (!clock_gettime(CLOCK_BOOTTIME, &boot) &&
577 !clock_gettime(CLOCK_REALTIME, &rtc)) {
578 rtc.tv_nsec = rtc.tv_nsec - boot.tv_nsec;
579 rtc.tv_sec = rtc.tv_sec - boot.tv_sec
580 - !!(rtc.tv_nsec < 0);
581 if (rtc.tv_nsec < 0)
582 rtc.tv_nsec += S_NS;
583
584 boot.tv_nsec = rtc.tv_nsec
585 + prog_info->load_time % S_NS;
586 boot.tv_sec = rtc.tv_sec
587 + prog_info->load_time / S_NS
588 + boot.tv_nsec / S_NS;
589
590 print_time_t_nsec(boot.tv_sec, 0, true);
591 }
592 }
593 if (bpf_prog_get_info_attr.info_len >
594 offsetof(struct bpf_prog_info_struct, created_by_uid))
595 printf(", created_by_uid=%u",
596 prog_info->created_by_uid);
597
598 if (bpf_prog_get_info_attr.info_len >
599 offsetof(struct bpf_prog_info_struct, map_ids)) {
600 switch (i) {
601 case 0:
602 printf(", nr_map_ids=0");
603 if (prog_info->nr_map_ids)
604 printf(" => 2");
605 printf(", map_ids=NULL");
606 break;
607 case 1:
608 printf(", nr_map_ids=3, map_ids=%p",
609 map_ids + 3);
610 break;
611 case 2:
612 printf(", nr_map_ids=0");
613 if (prog_info->nr_map_ids)
614 printf(" => 2");
615 printf(", map_ids=[]");
616 break;
617 case 3:
618 printf(", nr_map_ids=3");
619 if (prog_info->nr_map_ids != 3)
620 printf(" => 2");
621 printf(", map_ids=[%u, %u]",
622 map_info[1].id, map_info[0].id);
623 break;
624 case 4:
625 printf(", nr_map_ids=1");
626 if (prog_info->nr_map_ids != 1)
627 printf(" => 2");
628 printf(", map_ids=[%u]", map_info[1].id);
629 break;
630 }
631 }
632
633 if (bpf_prog_get_info_attr.info_len >
634 offsetof(struct bpf_prog_info_struct, name))
635 printf(", name=\"test_prog\"");
636 if (bpf_prog_get_info_attr.info_len >
637 offsetof(struct bpf_prog_info_struct, ifindex))
638 printf(", ifindex=%u", prog_info->ifindex);
639 if (bpf_prog_get_info_attr.info_len >
640 offsetofend(struct bpf_prog_info_struct, ifindex))
641 printf(", gpl_compatible=%u", prog_info->gpl_compatible);
642 if (bpf_prog_get_info_attr.info_len >
643 offsetof(struct bpf_prog_info_struct, netns_dev))
644 printf(", netns_dev=makedev(%#x, %#x)",
645 major(prog_info->netns_dev),
646 minor(prog_info->netns_dev));
647 if (bpf_prog_get_info_attr.info_len >
648 offsetof(struct bpf_prog_info_struct, netns_ino))
649 printf(", netns_ino=%" PRIu64, prog_info->netns_ino);
650
651 if (bpf_prog_get_info_attr.info_len >
652 offsetof(struct bpf_prog_info_struct, nr_jited_ksyms)) {
653 printf(", nr_jited_ksyms=0");
654 if (prog_info->nr_jited_ksyms)
655 printf(" => %u", prog_info->nr_jited_ksyms);
656 }
657 if (bpf_prog_get_info_attr.info_len >
658 offsetof(struct bpf_prog_info_struct, nr_jited_func_lens)) {
659 printf(", nr_jited_func_lens=0");
660 if (prog_info->nr_jited_func_lens)
661 printf(" => %u", prog_info->nr_jited_func_lens);
662 }
663 if (bpf_prog_get_info_attr.info_len >
664 offsetof(struct bpf_prog_info_struct, jited_ksyms))
665 printf(", jited_ksyms=NULL");
666 if (bpf_prog_get_info_attr.info_len >
667 offsetof(struct bpf_prog_info_struct, jited_func_lens))
668 printf(", jited_func_lens=NULL");
669
670 if (bpf_prog_get_info_attr.info_len >
671 offsetof(struct bpf_prog_info_struct, btf_id)) {
672 printf(", ");
673 PRINT_FIELD_U(*prog_info, btf_id);
674 }
675 if (bpf_prog_get_info_attr.info_len >
676 offsetof(struct bpf_prog_info_struct, func_info_rec_size)) {
677 printf(", func_info_rec_size=0");
678 if (prog_info->func_info_rec_size)
679 printf(" => %u", prog_info->func_info_rec_size);
680 }
681 if (bpf_prog_get_info_attr.info_len >
682 offsetof(struct bpf_prog_info_struct, func_info))
683 printf(", func_info=NULL");
684 if (bpf_prog_get_info_attr.info_len >
685 offsetof(struct bpf_prog_info_struct, nr_func_info)) {
686 printf(", nr_func_info=0");
687 if (prog_info->nr_func_info)
688 printf(" => %u", prog_info->nr_func_info);
689 }
690 if (bpf_prog_get_info_attr.info_len >
691 offsetof(struct bpf_prog_info_struct, nr_line_info)) {
692 printf(", nr_line_info=0");
693 if (prog_info->nr_line_info)
694 printf(" => %u", prog_info->nr_line_info);
695 }
696 if (bpf_prog_get_info_attr.info_len >
697 offsetof(struct bpf_prog_info_struct, line_info))
698 printf(", line_info=NULL");
699 if (bpf_prog_get_info_attr.info_len >
700 offsetof(struct bpf_prog_info_struct, jited_line_info))
701 printf(", jited_line_info=NULL");
702 if (bpf_prog_get_info_attr.info_len >
703 offsetof(struct bpf_prog_info_struct, nr_jited_line_info)) {
704 printf(", nr_jited_line_info=0");
705 if (prog_info->nr_jited_line_info)
706 printf(" => %u", prog_info->nr_jited_line_info);
707 }
708 if (bpf_prog_get_info_attr.info_len >
709 offsetof(struct bpf_prog_info_struct, line_info_rec_size)) {
710 printf(", line_info_rec_size=0");
711 if (prog_info->line_info_rec_size)
712 printf(" => %u", prog_info->line_info_rec_size);
713 }
714 if (bpf_prog_get_info_attr.info_len >
715 offsetof(struct bpf_prog_info_struct, jited_line_info_rec_size)) {
716 printf(", jited_line_info_rec_size=0");
717 if (prog_info->jited_line_info_rec_size)
718 printf(" => %u", prog_info->jited_line_info_rec_size);
719 }
720 if (bpf_prog_get_info_attr.info_len >
721 offsetof(struct bpf_prog_info_struct, nr_prog_tags)) {
722 printf(", nr_prog_tags=0");
723 if (prog_info->nr_prog_tags)
724 printf(" => %u", prog_info->nr_prog_tags);
725 }
726 if (bpf_prog_get_info_attr.info_len >
727 offsetof(struct bpf_prog_info_struct, prog_tags))
728 printf(", prog_tags=NULL");
729 if (bpf_prog_get_info_attr.info_len >
730 offsetof(struct bpf_prog_info_struct, run_time_ns))
731 printf(", run_time_ns=%llu",
732 (unsigned long long) prog_info->run_time_ns);
733 if (bpf_prog_get_info_attr.info_len >
734 offsetof(struct bpf_prog_info_struct, run_cnt))
735 printf(", run_cnt=%llu",
736 (unsigned long long) prog_info->run_cnt);
737 if (bpf_prog_get_info_attr.info_len >
738 offsetof(struct bpf_prog_info_struct, recursion_misses))
739 printf(", recursion_misses=%llu",
740 (unsigned long long) prog_info->recursion_misses);
741 if (bpf_prog_get_info_attr.info_len >
742 offsetof(struct bpf_prog_info_struct, verified_insns))
743 printf(", verified_insns=%u", prog_info->verified_insns);
744
745 printf("}");
746 # else /* !VERBOSE */
747 printf("%p", prog_info);
748 # endif /* VERBOSE */
749 printf("}}, %zu) = %s\n",
750 sizeof(bpf_prog_get_info_attr), errstr);
751 }
752 #endif /* CHECK_OBJ_PROG */
753
754 puts("+++ exited with 0 +++");
755 return 0;
756 }