(root)/
strace-6.5/
tests-m32/
bpf-obj_get_info_by_fd.c
       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  }