diff --git a/Makefile b/Makefile index 69e63e472..64aad39a5 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ ifneq ("$(NO_CROSS_COMPILER)", "") else mkdir -p ./bin/$(TARGETOS)_$(TARGETARCH) $(CC) -o ./bin/$(TARGETOS)_$(TARGETARCH)/syz-executor$(EXE) executor/executor.cc \ - $(ADDCFLAGS) $(CFLAGS) -DGOOS_$(TARGETOS)=1 -DGOARCH_$(TARGETARCH)=1 \ + $(ADDCFLAGS) $(CFLAGS) -L/usr/local/lib64 -lbpf -lelf -lz -DGOOS_$(TARGETOS)=1 -DGOARCH_$(TARGETARCH)=1 \ -DHOSTGOOS_$(HOSTOS)=1 -DGIT_REVISION=\"$(REV)\" endif endif diff --git a/README.md b/README.md index 607147fd5..b0fdef2a2 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,137 @@ -# syzkaller - kernel fuzzer - -[![CI Status](https://github.com/google/syzkaller/workflows/ci/badge.svg)](https://github.com/google/syzkaller/actions?query=workflow/ci) -[![OSS-Fuzz](https://oss-fuzz-build-logs.storage.googleapis.com/badges/syzkaller.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?q=label:Proj-syzkaller) -[![Go Report Card](https://goreportcard.com/badge/github.com/google/syzkaller)](https://goreportcard.com/report/github.com/google/syzkaller) -[![Coverage Status](https://codecov.io/gh/google/syzkaller/graph/badge.svg)](https://codecov.io/gh/google/syzkaller) -[![GoDoc](https://godoc.org/github.com/google/syzkaller?status.svg)](https://godoc.org/github.com/google/syzkaller) -[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE) - -`syzkaller` (`[siːzˈkɔːlə]`) is an unsupervised coverage-guided kernel fuzzer.\ -Supported OSes: `Akaros`, `FreeBSD`, `Fuchsia`, `gVisor`, `Linux`, `NetBSD`, `OpenBSD`, `Windows`. - -Mailing list: [syzkaller@googlegroups.com](https://groups.google.com/forum/#!forum/syzkaller) (join on [web](https://groups.google.com/forum/#!forum/syzkaller) or by [email](mailto:syzkaller+subscribe@googlegroups.com)). - -Found bugs: [Akaros](docs/akaros/found_bugs.md), [Darwin/XNU](docs/darwin/README.md), [FreeBSD](docs/freebsd/found_bugs.md), [Linux](docs/linux/found_bugs.md), [NetBSD](docs/netbsd/found_bugs.md), [OpenBSD](docs/openbsd/found_bugs.md), [Windows](docs/windows/README.md). - -## Documentation - -Initially, syzkaller was developed with Linux kernel fuzzing in mind, but now -it's being extended to support other OS kernels as well. -Most of the documentation at this moment is related to the [Linux](docs/linux/setup.md) kernel. -For other OS kernels check: -[Akaros](docs/akaros/README.md), -[Darwin/XNU](docs/darwin/README.md), -[FreeBSD](docs/freebsd/README.md), -[Fuchsia](docs/fuchsia/README.md), -[NetBSD](docs/netbsd/README.md), -[OpenBSD](docs/openbsd/setup.md), -[Starnix](docs/starnix/README.md), -[Windows](docs/windows/README.md), -[gVisor](docs/gvisor/README.md). - -- [How to install syzkaller](docs/setup.md) -- [How to use syzkaller](docs/usage.md) -- [How syzkaller works](docs/internals.md) -- [How to install syzbot](docs/setup_syzbot.md) -- [How to contribute to syzkaller](docs/contributing.md) -- [How to report Linux kernel bugs](docs/linux/reporting_kernel_bugs.md) -- [Tech talks and articles](docs/talks.md) -- [Research work based on syzkaller](docs/research.md) - -## Disclaimer - -This is not an official Google product. +# BPF Runtime Fuzzer (BRF) +BRF is a coverage-guided fuzzer that aims to fuzz the runtime compononets of eBPF shielded by the verifier. BRF uses semantic-aware and dependency-aware input generation/mutation logic as well as generating syscalls to trigger the execution of eBPF programs to achieve the goal. The implementation of BRF is based on Syzkaller. + +## Prerequisites + +### LLVM +To use latest bpf features, it is better to build the kernel using the latest llvm. + +``` bash +git clone --branch llvmorg-17.0.6 https://github.com/llvm/llvm-project.git +mkdir llvm-project/build; cd llvm-project/build +cmake ../llvm -DLLVM_TARGETS_TO_BUILD="BPF;X86" \ + -DLLVM_ENABLE_PROJECTS=clang \ + -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_BUILD_TYPE=Release \ + -DLLVM_BUILD_RUNTIME=OFF +make +``` +After the build completes, export build/bin to $PATH. + +### Pahole +``` bash +git clone --branch v1.24 https://github.com/acmel/dwarves.git +mkdir dwarves/build; cd dwarves/build +cmake ../ +make +sudo make install +``` + +More to be added. Let us know if you think something should be added here. + +### Build Linux kernel +Here we use the development branch of network device subsystem of the Linux kernel. +``` bash +git clone https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git $KERNEL +cd $KERNEL +make CC=clang-17 defconfig +make CC=clang-17 kvm_guest.config +``` +Follow the [guide](/docs/linux/kernel_configs.md) and enable kernel configs required by Syzkaller + +Enable bpf-related configs by editing .config or through menuconfig. +``` make +CONFIG_BPF_SYSCALL +CONFIG_BPF_JIT +CONFIG_BPF_LSM +CONFIG_DEBUG_INFO_BTF +CONFIG_MODULE_ALLOW_BTF_MISMATCH +CONFIG_TEST_BPF +CONFIG_CGROUP_BPF +CONFIG_NET_ACT_BPF +CONFIG_NET_CLS_BPF +CONFIG_BPF_STREAM_PARSER +CONFIG_LWTUNNEL_BPF +CONFIG_IPV6_SEG6_BPF +CONFIG_LIRC +CONFIG_BPF_LIRC_MODE2 +``` + +Finally, build the Linux kernel with Clang/LLVM. +``` make +make CC=clang-17 +``` + +Build bpftool and libbpf to be used later +``` bash +cd $KERNEL/tools/bpf/bpftool +make CC=clang-17 +cd $KERNEL/tools/lib/bpf +make +``` + +### Create Debian Bookworm Linux image +``` bash +mkdir $IMAGE; cd $IMAGE +cp $SYZKALLER/tools/create-image.sh . +chmod +x create-image.sh +ADD_PACKAGE="make,sysbench,git,vim,tmux,usbutils,tcpdump,clang-16" ./create-image.sh --feature full --distribution bookworm --seek 8191 +``` + +### Prepare the image for compiling BPF programs +Prepare BRF working directory. The directory will be shared with the guest to store and compile BPF programs. +``` bash +mkdir $BRF_WORKDIR; cd $BRF_WORKDIR +cp $KERNEL/tools/bpf/bpftool/vmlinux.h . +``` + +Boot into the guest and install libbpf headers. +``` bash +qemu-system-x86_64 \ + -m 2G \ + -smp 2 \ + -kernel $KERNEL/arch/x86/boot/bzImage \ + -append "console=ttyS0 root=/dev/sda earlyprintk=serial net.ifnames=0" \ + -drive file=$IMAGE/bookworm.img,format=raw \ + -net user,host=10.0.2.10,hostfwd=tcp:127.0.0.1:10021-:22 \ + -net nic,model=e1000 \ + -virtfs local,path=$KERNEL,mount_tag=host0,security_model=mapped,id=host0 \ + -enable-kvm \ + -nographic \ + -pidfile vm.pid \ + 2>&1 | tee vm.log +``` +``` bash +mkdir /mnt/kernel_src +mount -t 9p -o trans=virtio,version=9p2000.L host0 /mnt/kernel_src +cd /mnt/kernel_src/tools/lib/bpf +make install_headers +``` +## Run BRF +Create a config like the following and replace $SYZKALLER, $KERNEL, $IMAGE and $BRF\_WORKDIR with the actual paths. +``` json +{ + "target": "linux/amd64", + "http": "127.0.0.1:56741", + "workdir": "$SYZKALLER/workdir/bookworm", + "kernel_obj": "$KERNEL", + "image": "$IMAGE/bookworm.img", + "sshkey": "$IMAGE/bookworm.id_rsa", + "syzkaller": "$SYZKALLER", + "procs": 8, + "type": "qemu", + "vm": { + "count": 4, + "kernel": "$KERNEL/arch/x86/boot/bzImage", + "cpu": 2, + "mem": 2048, + "brf_workdir": "$BRF_WORKDIR" + } +} +``` +Run Syzkaller manager: +``` +mkdir -p workdir/bookworm +./bin/syzkaller -config my.cfg +``` +## Acknoledgement diff --git a/executor/common_brf_linux.h b/executor/common_brf_linux.h new file mode 100644 index 000000000..e74e9957f --- /dev/null +++ b/executor/common_brf_linux.h @@ -0,0 +1,256 @@ + +#define OBJ_LIST_SIZE 32 + +static struct bpf_object *bpf_object_list[OBJ_LIST_SIZE]; + +struct bpf_res { + int prog_fds[32]; + int prog_num; + int map_fds[32]; + int map_num; +}; + +static long syz_bpf_prog_open(volatile long a0) +{ + const char* file = (char*)a0; + struct bpf_object* obj; + char bpf_err_buf[256]; + unsigned int i; + long err; + + obj = bpf_object__open(file); + err = libbpf_get_error(obj); + if (err) { + debug("syz_bpf_prog_open: failed to open bpf object %s: %s", file, bpf_err_buf); + return -1; + } + + for (i = 0; i < OBJ_LIST_SIZE; i++) { + if (!bpf_object_list[i]) { + bpf_object_list[i] = obj; + return 0; + } + } + + debug("syz_bpf_prog_open: bpf_object_list full"); + return -1; +} + +static struct bpf_object *find_bpf_object_by_basename(const char *path) +{ + char name[BPF_OBJ_NAME_LEN]; + char *end; + int i = 0; + + for (i = 0; i < OBJ_LIST_SIZE; i++) { + if (!bpf_object_list[i]) + break; + + strncpy(name, basename(path), sizeof(name) - 1); + end = strchr(name, '.'); + if (end) + *end = 0; + + if (strcmp(bpf_object__name(bpf_object_list[i]), name) == 0) + return bpf_object_list[i]; + } + return NULL; +} + +static long syz_bpf_prog_load(volatile long a0, volatile long a1) +{ + const char *file = (char *)a0; + struct bpf_res *res = (struct bpf_res *)a1; + struct bpf_program *prog; + struct bpf_object *obj; + struct bpf_map *map; + int i, err; + + obj = find_bpf_object_by_basename(file); + if (!obj) { + debug("syz_bpf_prog_load: cannot find %s", file); + return -1; + } + + err = bpf_object__load(obj); + if (err) { + debug("syz_bpf_prog_load: failed to load bpf prog, errno %d", err); + return -1; + } + + i = 0; + bpf_object__for_each_program(prog, obj) + res->prog_fds[i++] = bpf_program__fd(prog); + + i = 0; + bpf_object__for_each_map(map, obj) + res->map_fds[i++] = bpf_map__fd(map); + + return res->prog_fds[0]; +} + +#define LO_IFINDEX 1 + +static bool check_attach_res(struct bpf_program *prog, int *res) +{ + LIBBPF_OPTS(bpf_map_create_opts, opts); + struct perf_event_attr attr = { + .type = PERF_TYPE_HARDWARE, + .config = PERF_COUNT_HW_CPU_CYCLES, + .sample_freq = 50, + .inherit = 1, + .freq = 1, + }; + + if (*res > 0) + return true; + + switch (bpf_program__type(prog)) { + case BPF_PROG_TYPE_SOCKET_FILTER: + *res = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + goto check_fd; + case BPF_PROG_TYPE_SCHED_CLS: + case BPF_PROG_TYPE_SCHED_ACT: + case BPF_PROG_TYPE_XDP: + *res = LO_IFINDEX; + return true; + case BPF_PROG_TYPE_PERF_EVENT: + *res = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0); + goto check_fd; + case BPF_PROG_TYPE_CGROUP_SKB: + case BPF_PROG_TYPE_CGROUP_SOCK: + case BPF_PROG_TYPE_CGROUP_DEVICE: + case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: + case BPF_PROG_TYPE_CGROUP_SYSCTL: + case BPF_PROG_TYPE_CGROUP_SOCKOPT: + *res = open("/sys/fs/cgroup", O_RDONLY); + goto check_fd; + case BPF_PROG_TYPE_SK_SKB: + case BPF_PROG_TYPE_SK_MSG: + *res = bpf_map_create(BPF_MAP_TYPE_SOCKMAP, "brf", + sizeof(int), sizeof(int), 1, &opts); + goto check_fd; + case BPF_PROG_TYPE_LIRC_MODE2: + *res = open("/dev/lirc0", O_RDWR); + goto check_fd; + case BPF_PROG_TYPE_SK_REUSEPORT: + *res = socket(AF_INET, SOCK_DGRAM, 0); + goto check_fd; + case BPF_PROG_TYPE_FLOW_DISSECTOR: + case BPF_PROG_TYPE_SK_LOOKUP: + *res = open("/proc/self/ns/net", O_RDONLY); + goto check_fd; + default: + return true; + } + +check_fd: + return *res >= 0; +} + +static int bpf_program_attach(struct bpf_program *prog, int res, struct bpf_link **link) +{ + struct bpf_tcx_opts tcx_opts; + struct bpf_netfilter_opts nf_opts; + int optval = 1; + int fd, ret; + + if (!check_attach_res(prog, &res)) { + debug("syz_bpf_prog_attach: no attach point for %s", + libbpf_bpf_prog_type_str(bpf_program__type(prog))); + return -1; + } + + fd = bpf_program__fd(prog); + + switch (bpf_program__type(prog)) { + case BPF_PROG_TYPE_SOCKET_FILTER: + return setsockopt(res, SOL_SOCKET, SO_ATTACH_BPF, &fd, sizeof(fd)); + case BPF_PROG_TYPE_KPROBE: + case BPF_PROG_TYPE_TRACEPOINT: + case BPF_PROG_TYPE_RAW_TRACEPOINT: + case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE: + case BPF_PROG_TYPE_TRACING: + *link = bpf_program__attach(prog); + goto check_link; + case BPF_PROG_TYPE_SCHED_CLS: + case BPF_PROG_TYPE_SCHED_ACT: + *link = bpf_program__attach_tcx(prog, res, &tcx_opts); + goto check_link; + case BPF_PROG_TYPE_XDP: + *link = bpf_program__attach_xdp(prog, res); + goto check_link; + case BPF_PROG_TYPE_PERF_EVENT: + *link = bpf_program__attach_perf_event(prog, res); + goto check_link; + case BPF_PROG_TYPE_CGROUP_SKB: + case BPF_PROG_TYPE_CGROUP_SOCK: + case BPF_PROG_TYPE_CGROUP_DEVICE: + case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: + case BPF_PROG_TYPE_CGROUP_SYSCTL: + case BPF_PROG_TYPE_CGROUP_SOCKOPT: + *link = bpf_program__attach_cgroup(prog, res); + goto check_link; + case BPF_PROG_TYPE_LWT_IN: + case BPF_PROG_TYPE_LWT_OUT: + case BPF_PROG_TYPE_LWT_XMIT: + case BPF_PROG_TYPE_LWT_SEG6LOCAL: + break; + case BPF_PROG_TYPE_SOCK_OPS: + *link = bpf_program__attach_cgroup(prog, res); + goto check_link; + case BPF_PROG_TYPE_SK_SKB: + return bpf_prog_attach(fd, res, BPF_SK_SKB_VERDICT, 0); + case BPF_PROG_TYPE_SK_MSG: + return bpf_prog_attach(fd, res, BPF_SK_MSG_VERDICT, 0); + case BPF_PROG_TYPE_LIRC_MODE2: + return bpf_prog_attach(fd, res, BPF_LIRC_MODE2, 0); + case BPF_PROG_TYPE_SK_REUSEPORT: + ret = setsockopt(res, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); + return ret?: setsockopt(res, SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF, &fd, sizeof(fd)); + case BPF_PROG_TYPE_FLOW_DISSECTOR: + *link = bpf_program__attach_netns(prog, res); + goto check_link; + case BPF_PROG_TYPE_STRUCT_OPS: + case BPF_PROG_TYPE_EXT: + case BPF_PROG_TYPE_LSM: + *link = bpf_program__attach_lsm(prog); + goto check_link; + case BPF_PROG_TYPE_SK_LOOKUP: + *link = bpf_program__attach_netns(prog, res); + goto check_link; + case BPF_PROG_TYPE_SYSCALL: + break; + case BPF_PROG_TYPE_NETFILTER: + *link = bpf_program__attach_netfilter(prog, &nf_opts); + goto check_link; + default: + break; + } + + return -1; + +check_link: + return (*link != NULL) ? 0 : -1; +} + +static long syz_bpf_prog_attach(volatile long a0) +{ + const char *file = (char *)a0; + int attach_res = -1; + struct bpf_program *prog; + struct bpf_object *obj; + struct bpf_link *link = NULL; + + obj = find_bpf_object_by_basename(file); + if (!obj) { + debug("syz_bpf_prog_attach: cannot find %s", file); + return -1; + } + + bpf_object__for_each_program(prog, obj) { + bpf_program_attach(prog, attach_res, &link); + } + + return link? bpf_link__fd(link) : 0; +} diff --git a/executor/common_linux.h b/executor/common_linux.h index 9558bdb7d..b3f4f90c4 100644 --- a/executor/common_linux.h +++ b/executor/common_linux.h @@ -5682,3 +5682,12 @@ static long syz_pidfd_open(volatile long pid, volatile long flags) } #endif + +#if SYZ_EXECUTOR || __NR_syz_bpf_prog_open || __NR_syz_bpf_prog_load || __NR_syz_bpf_prog_attach +#include +#include +#include + +#include "common_brf_linux.h" + +#endif diff --git a/go.mod b/go.mod index 8e4bd4e0a..8d4e8a31c 100644 --- a/go.mod +++ b/go.mod @@ -16,12 +16,12 @@ require ( github.com/prometheus/client_golang v1.17.0 github.com/stretchr/testify v1.8.4 github.com/ulikunitz/xz v0.5.11 - golang.org/x/net v0.19.0 + golang.org/x/net v0.20.0 golang.org/x/oauth2 v0.15.0 golang.org/x/perf v0.0.0-20230221235046-aebcfb61e84c - golang.org/x/sync v0.5.0 - golang.org/x/sys v0.15.0 - golang.org/x/tools v0.14.0 + golang.org/x/sync v0.6.0 + golang.org/x/sys v0.16.0 + golang.org/x/tools v0.17.0 google.golang.org/api v0.153.0 google.golang.org/appengine/v2 v2.0.5 google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 @@ -205,10 +205,10 @@ require ( go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.9.0 // indirect go.uber.org/zap v1.24.0 // indirect - golang.org/x/crypto v0.16.0 // indirect + golang.org/x/crypto v0.18.0 // indirect golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea // indirect golang.org/x/exp/typeparams v0.0.0-20230307190834-24139beb5833 // indirect - golang.org/x/mod v0.13.0 // indirect + golang.org/x/mod v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect diff --git a/go.sum b/go.sum index e1ec58157..6f848f030 100644 --- a/go.sum +++ b/go.sum @@ -681,8 +681,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -742,8 +742,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -786,8 +786,8 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/oauth2 v0.0.0-20170207211851-4464e7848382/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -816,8 +816,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -877,8 +877,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -976,8 +976,8 @@ golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/csource/generated.go b/pkg/csource/generated.go index dbb18a811..5a87318c6 100644 --- a/pkg/csource/generated.go +++ b/pkg/csource/generated.go @@ -11842,6 +11842,95 @@ static long syz_pidfd_open(volatile long pid, volatile long flags) #endif +#if SYZ_EXECUTOR || __NR_syz_bpf_prog_open || __NR_syz_bpf_prog_load +#include +#include + +#define OBJ_LIST_SIZE 32 + +static struct bpf_object *bpf_object_list[OBJ_LIST_SIZE]; + +static long syz_bpf_prog_open(volatile long a0) +{ + const char* file = (char*)a0; + struct bpf_object* obj; + char bpf_err_buf[256]; + unsigned int i; + long err; + + obj = bpf_object__open(file); + err = libbpf_get_error(obj); + if (err) { + debug("syz_bpf_prog_open: failed to open bpf object %s: %s", file, bpf_err_buf); + return -1; + } + + for (i = 0; i < OBJ_LIST_SIZE; i++) { + if (!bpf_object_list[i]) { + bpf_object_list[i] = obj; + return 0; + } + } + + debug("syz_bpf_prog_open: bpf_object_list full"); + return -1; +} + +static struct bpf_object *find_bpf_object_by_basename(const char *path) +{ + char name[BPF_OBJ_NAME_LEN]; + char *end; + int i = 0; + + for (i = 0; i < OBJ_LIST_SIZE; i++) { + if (!bpf_object_list[i]) + break; + + strncpy(name, basename(path), sizeof(name) - 1); + end = strchr(name, '.'); + if (end) + *end = 0; + + if (strcmp(bpf_object__name(bpf_object_list[i]), name) == 0) + return bpf_object_list[i]; + } + return NULL; +} + +static long syz_bpf_prog_load(volatile long a0, volatile long a1) +{ + const char *file = (char *)a0; + struct bpf_res *res = (struct bpf_res *)a1; + struct bpf_program *prog; + struct bpf_object *obj; + struct bpf_map *map; + int i, err; + + obj = find_bpf_object_by_basename(file); + if (!obj) { + debug("syz_bpf_prog_load: cannot find %s", file); + return -1; + } + + err = bpf_object__load(obj); + if (err) { + debug("syz_bpf_prog_load: failed to load bpf prog, errno %d", err); + return -1; + } + + i = 0; + bpf_object__for_each_program(prog, obj) + res->prog_fds[i++] = bpf_program__fd(prog); + + i = 0; + bpf_object__for_each_map(map, obj) + res->map_fds[i++] = bpf_map__fd(map); + + return res->prog_fds[0]; +} + +#endif + #elif GOOS_test #include diff --git a/pkg/host/syscalls_linux.go b/pkg/host/syscalls_linux.go index d59fe491b..ee3ee170e 100644 --- a/pkg/host/syscalls_linux.go +++ b/pkg/host/syscalls_linux.go @@ -328,6 +328,9 @@ var syzkallSupport = map[string]func(*prog.Syscall, *prog.Target, string) (bool, "syz_pkey_set": isSyzPkeySetSupported, "syz_socket_connect_nvme_tcp": isSyzSocketConnectNvmeTCPSupported, "syz_pidfd_open": alwaysSupported, + "syz_bpf_prog_open": alwaysSupported, + "syz_bpf_prog_load": alwaysSupported, + "syz_bpf_prog_attach": alwaysSupported, } func isSupportedSyzkall(c *prog.Syscall, target *prog.Target, sandbox string) (bool, string) { diff --git a/prog/brf.go b/prog/brf.go index d40d5f030..adf9593d1 100644 --- a/prog/brf.go +++ b/prog/brf.go @@ -1,17 +1,240 @@ package prog +import ( + "fmt" + "os" + "os/exec" + "time" + + "github.com/google/syzkaller/pkg/osutil" +) + type BpfRuntimeFuzzer struct { isEnabled bool + workDir string + + helperFuncMap map[string]*BpfHelperFunc + progTypeMap map[BpfProgTypeEnum]*BpfProgTypeDef + ctxAccessMap map[BpfProgTypeEnum]*BpfCtxAccess } func NewBpfRuntimeFuzzer(enable bool) *BpfRuntimeFuzzer { brf := new(BpfRuntimeFuzzer) + + if (!enable) { + return brf + } + + brf.workDir = "/mnt/brf_work_dir" + err := mountBrfWorkDir(brf.workDir) + if (err != nil) { + return brf + } + brf.isEnabled = true + brf.helperFuncMap = make(map[string]*BpfHelperFunc) + brf.progTypeMap = make(map[BpfProgTypeEnum]*BpfProgTypeDef) + brf.ctxAccessMap = make(map[BpfProgTypeEnum]*BpfCtxAccess) + + brf.InitFromSrc(HelperFuncMap, ProgTypeMap, CtxAccessMap) return brf } +func mountBrfWorkDir(dir string) error { + var timeout time.Duration = 10000000000 + + err := os.Mkdir(dir, os.ModeDir) + if err != nil { + fmt.Printf("failed to create brf work dir: %v\n", err) + return err + } + + args := []string{"-t", "9p", "-o", "trans=virtio,version=9p2000.L", "brf", dir} + _, err = osutil.RunCmd(timeout, "", "mount", args...) + if err != nil { + fmt.Printf("failed to mount brf work dir: %v\n", err) + return err + } + return nil +} + func (brf *BpfRuntimeFuzzer) IsEnabled() bool { return brf.isEnabled } +func (brf *BpfRuntimeFuzzer) GenPrologue(r *randGen, s *state, prog *Prog) { + var p *BpfProg + + if !brf.isEnabled { + return + } + + p = brf.genSeedBpfProg(r) + + c0 := genBpfProgOpenCall(r, s, p) + s.analyze(c0) + prog.Calls = append(prog.Calls, c0) + + c1 := genBpfProgLoadCall(r, s, p) + s.analyze(c1) + prog.Calls = append(prog.Calls, c1) + + c2 := genBpfProgAttachCall(r, s, p) + s.analyze(c2) + prog.Calls = append(prog.Calls, c2) +} + +func genBpfProgOpenCall(r *randGen, s *state, p *BpfProg) *Call { + meta := r.target.SyscallMap["syz_bpf_prog_open"] + args := make([]Arg, len(meta.Args)) + c := MakeCall(meta, nil) + + pathStr := []byte(p.BasePath + ".o") + pathArg := meta.Args[0] + pathPtr := pathArg.Type.(*PtrType) + pathBuffer := pathPtr.Elem.(*BufferType) + pathBufferDir := pathPtr.ElemDir + pathBufferArg := MakeDataArg(pathBuffer, pathBufferDir, pathStr) + args[0] = r.allocAddr(s, pathArg.Type, pathArg.Dir(DirIn), pathBufferArg.Size(), pathBufferArg) + + c.Args = args + r.target.assignSizesCall(c) + return c +} + +func genBpfProgLoadCall(r *randGen, s *state, p *BpfProg) *Call { + meta := r.target.SyscallMap["syz_bpf_prog_load"] + args := make([]Arg, len(meta.Args)) + c := MakeCall(meta, nil) + + pathStr := []byte(p.BasePath + ".o") + pathArg := meta.Args[0] + pathPtr := pathArg.Type.(*PtrType) + pathBuffer := pathPtr.Elem.(*BufferType) + pathBufferDir := pathPtr.ElemDir + pathBufferArg := MakeDataArg(pathBuffer, pathBufferDir, pathStr) + args[0] = r.allocAddr(s, pathArg.Type, pathArg.Dir(DirIn), pathBufferArg.Size(), pathBufferArg) + args[1], _ = r.generateArg(s, meta.Args[1].Type, meta.Args[1].Dir(DirIn)) + + c.Args = args + r.target.assignSizesCall(c) + return c +} + +func genBpfProgAttachCall(r *randGen, s *state, p *BpfProg) *Call { + meta := r.target.SyscallMap["syz_bpf_prog_attach"] + args := make([]Arg, len(meta.Args)) + c := MakeCall(meta, nil) + + pathStr := []byte(p.BasePath + ".o") + pathArg := meta.Args[0] + pathPtr := pathArg.Type.(*PtrType) + pathBuffer := pathPtr.Elem.(*BufferType) + pathBufferDir := pathPtr.ElemDir + pathBufferArg := MakeDataArg(pathBuffer, pathBufferDir, pathStr) + args[0] = r.allocAddr(s, pathArg.Type, pathArg.Dir(DirIn), pathBufferArg.Size(), pathBufferArg) + + c.Args = args + r.target.assignSizesCall(c) + return c +} + +func (brf *BpfRuntimeFuzzer) genSeedBpfProg(r *randGen) *BpfProg { + var opt BrfGenProgOpt + var p *BpfProg + var ok bool + +// opt.useTestSrc = true + opt.genProgAttempt = 20 + opt.basePath = brf.workDir + + for i := 0; i < opt.genProgAttempt; i++ { + if p, ok = brf.GenBpfProg(r, opt); !ok { + continue + } + p.FixRef(r) + p.FixSpinLock(r) + + if err := p.writeCSource(); err != nil { + fmt.Printf("failed to write bpf program c source: %v\n", err) + return nil + } + + if err := p.writeGob(); err != nil { + fmt.Printf("failed to serialize bpf program: %v\n", err) + return nil + } + + if err := brf.compileBpfProg(p); err != nil { + fmt.Printf("failed to compile bpf program: %v\n", err) + continue + } + return p + } + return nil +} + +func (brf *BpfRuntimeFuzzer) mutSeedBpfProg(r *randGen, path string) *BpfProg { + var opt BrfGenProgOpt + var p *BpfProg + +// opt.useTestSrc = true + opt.genProgAttempt = 20 + opt.basePath = brf.workDir + + p = NewBpfProg(nil, nil, opt) + p.readGob(path) + p.pt = brf.progTypeMap[p.TypeEnum] + + for i := 0; i < opt.genProgAttempt; i++ { + for ok := false; !ok; { + ok = brf.MutBpfProg(r, p, opt) + } + p.FixRef(r) + p.FixSpinLock(r) + + if err := p.writeCSource(); err != nil { + fmt.Printf("failed to write bpf program c source: %v\n", err) + return nil + } + + if err := p.writeGob(); err != nil { + fmt.Printf("failed to serialize bpf program: %v\n", err) + return nil + } + + if err := brf.compileBpfProg(p); err != nil { + fmt.Printf("failed to compile bpf program: %v\n", err) + continue + } + return p + } + return nil +} + +func (brf *BpfRuntimeFuzzer) genBpfProg(r *randGen, opt BrfGenProgOpt) (*BpfProg, bool) { + p := newBpfProg(r, opt) + + return p, true +} + +func (brf *BpfRuntimeFuzzer) mutBpfProg(r *randGen, p *BpfProg, opt BrfGenProgOpt) bool { + return true +} + +func (brf *BpfRuntimeFuzzer) compileBpfProg(p *BpfProg) error { + var timeout time.Duration = 10000000000 + cmd := exec.Command("clang-16", "-g", "-D__TARGET_ARCH_x86", "-mlittle-endian", + "-idirafter", "/usr/local/include", + "-idirafter", "/usr/local/llvm/include", + "-idirafter", "/usr/include/x86_64-linux-gnu", + "-idirafter", "/usr/include", + "-Wno-compare-distinct-pointer-types", "-O2", "-target", "bpf", "-mcpu=v3", + "-c", p.BasePath + ".c", + "-o", p.BasePath + ".o") + cmd.Dir = brf.workDir + + _, err := osutil.Run(timeout, cmd) + return err +} diff --git a/prog/brf_legacy.go b/prog/brf_legacy.go new file mode 100644 index 000000000..dc3f3deef --- /dev/null +++ b/prog/brf_legacy.go @@ -0,0 +1,2835 @@ +package prog + +import ( + "bytes" + "fmt" + "time" + "strings" +) + +type PathLinePair struct { + Path string + Line int +} + +type BpfAttachOption struct { + Str1 string + Str2 string + IntOpts []int64 +} + +type SecDefGenFunc func(r *randGen) (string, *StructDef) + +type SecDef struct { + Sec string + SecDefGen SecDefGenFunc + Sleepable bool +} + +type BpfProgTypeEnum int + +const ( + BPF_PROG_TYPE_UNSPEC BpfProgTypeEnum = iota + BPF_PROG_TYPE_SOCKET_FILTER + BPF_PROG_TYPE_KPROBE + BPF_PROG_TYPE_SCHED_CLS + BPF_PROG_TYPE_SCHED_ACT + BPF_PROG_TYPE_TRACEPOINT + BPF_PROG_TYPE_XDP + BPF_PROG_TYPE_PERF_EVENT + BPF_PROG_TYPE_CGROUP_SKB + BPF_PROG_TYPE_CGROUP_SOCK + BPF_PROG_TYPE_LWT_IN + BPF_PROG_TYPE_LWT_OUT + BPF_PROG_TYPE_LWT_XMIT + BPF_PROG_TYPE_SOCK_OPS + BPF_PROG_TYPE_SK_SKB + BPF_PROG_TYPE_CGROUP_DEVICE + BPF_PROG_TYPE_SK_MSG + BPF_PROG_TYPE_RAW_TRACEPOINT + BPF_PROG_TYPE_CGROUP_SOCK_ADDR + BPF_PROG_TYPE_LWT_SEG6LOCAL + BPF_PROG_TYPE_LIRC_MODE2 + BPF_PROG_TYPE_SK_REUSEPORT + BPF_PROG_TYPE_FLOW_DISSECTOR + BPF_PROG_TYPE_CGROUP_SYSCTL + BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE + BPF_PROG_TYPE_CGROUP_SOCKOPT + BPF_PROG_TYPE_TRACING + BPF_PROG_TYPE_STRUCT_OPS + BPF_PROG_TYPE_EXT + BPF_PROG_TYPE_LSM + BPF_PROG_TYPE_SK_LOOKUP + BPF_PROG_TYPE_SYSCALL + BPF_PROG_TYPE_NETFILTER + BPF_PROG_TYPE_MAX +) + +type BpfProgTypeDef struct { + Name string + User string + Kern string + Enum BpfProgTypeEnum + SecDefs []SecDef + FuncProtos []string + Helpers []*BpfHelperFunc + ctxAccess *BpfCtxAccess +} + +func NewBpfProgTypeDef() *BpfProgTypeDef { + bpfProgType := new(BpfProgTypeDef) + return bpfProgType +} + +func (pt *BpfProgTypeDef) getHelper(helperEnum string) *BpfHelperFunc { + for _, helper := range pt.Helpers { + if helper.Enum == helperEnum { + return helper + } + } + return nil +} + +func (pt *BpfProgTypeDef) getHelpers(helperEnums []string) []*BpfHelperFunc { + var helpers []*BpfHelperFunc + for _, helper := range pt.Helpers { + for _, enum := range helperEnums { + if helper.Enum == enum { + helpers = append(helpers, helper) + } + } + } + return helpers +} + +type BpfHelperFunc struct { + Num int + Enum string + Name string + Proto string + Args []string + ArgBtfIds []string + Ret string + RetBtfId string + GplOnly bool + PktAccess bool +} + +type BpfMap struct { + MapType string + MapFlags []string + MapName string + Key *StructDef + Val *StructDef + MaxEntries int64 + InnerMap *BpfMap +} + +func (m *BpfMap) getFlag(f string) int { + for i, flag := range m.MapFlags { + if flag == f { + return i + } + } + return -1 +} + +func (m *BpfMap) addFlag(flag string) { + if f := m.getFlag(flag); f == -1 { + m.MapFlags = append(m.MapFlags, flag) + } +} + +func (m *BpfMap) removeFlag(flag string) { + if f := m.getFlag(flag); f != -1 { + m.MapFlags = append(m.MapFlags[0:f], m.MapFlags[f+1:]...) + } +} + +func (m *BpfMap) FlagsStr() string { + flags := "0" + for _, f := range m.MapFlags { + flags = flags + " | " + f + } + return flags +} + +type ArgHint int32 + +const ( + HintGenSpinlock = iota + HintGenTimer + HintGenConstStr + HintGenXdpSockMap + HintGenSockMap +) + +type BpfCallGenHint struct { + ArgHints map[ArgHint]bool + RetAccessSize int // return value will be accessed with the size + IsRetAccessRaw bool // return value is used for raw memory access + PreferredMap *BpfMap +} + +func newBpfCallGenHint(m *BpfMap) *BpfCallGenHint { + hint := &BpfCallGenHint { + ArgHints: make(map[ArgHint]bool), + RetAccessSize: 0, + IsRetAccessRaw: false, + PreferredMap: m, + } + return hint +} + +type BpfArg struct { + Name string + ArgType string + Prepare string + CanBeNull bool + IsNotNull bool + Umin int64 + Umax int64 + IsPktAccess bool + IsPktMetaAccess bool + AccessSize int +} + +func NewBpfArg(helper *BpfHelperFunc, arg int) *BpfArg { + newArg := &BpfArg{ + ArgType: helper.Args[arg], + CanBeNull: true, + Umin: int64(-1), + Umax: int64(-1), + } + + argType := newArg.ArgType + //XXX need to review the constraints + if argType[0:9] == "ARG_CONST" { + if argType == "ARG_CONST_SIZE" { + newArg.Umin = int64(0) + newArg.Umax = int64(1 << 29) + } else if argType == "ARG_CONST_SIZE_OR_ZERO" { + newArg.Umax = int64(1 << 29) + } + //"ARG_CONST_ALLOC_SIZE_OR_ZERO" + } else if argType[len(argType)-7:len(argType)] != "OR_NULL" || argType == "ARG_PTR_TO_MAP_VALUE_OR_NULL"{ //XXX investigate 5065 to how may_be_null work/the difference between ARG_PTR_TO_MAP_VALUE and ARG_PTR_TO_MAP_VALUE_OR_NULL + newArg.CanBeNull = false + } + return newArg +} + +type BpfCall struct { + Helper *BpfHelperFunc + Args []*BpfArg + ArgMap *BpfMap + Ret string + RetType string //XXX switch to StructDef + StackVarSize int + Hint *BpfCallGenHint + PostCalls []*BpfCall +} + +func NewBpfCall(helper *BpfHelperFunc, hint *BpfCallGenHint) *BpfCall { + newCall := &BpfCall{ + Helper: helper, + Args: make([]*BpfArg, len(helper.Args)), + Hint: hint, + } + return newCall +} + +func (call *BpfCall) getArgConstraints(s *BpfProg) []string { + var constraints []string + for _, arg := range call.Args { + if arg.IsPktMetaAccess { + constraints = append(constraints, fmt.Sprintf("%v + %v < %v", s.CtxVars["data_meta"], arg.AccessSize, s.CtxVars["data"])) + continue + } + if arg.IsPktAccess { + constraints = append(constraints, fmt.Sprintf("%v + %v < %v", s.CtxVars["data"], arg.AccessSize, s.CtxVars["data_end"])) + continue + } + //if !arg.CanBeNull && !arg.IsNotNull && strings.Contains(arg.ArgType, "ARG_PTR_TO") { + if !arg.CanBeNull && !arg.IsNotNull { + varStart := strings.Index(arg.Name, "&") + 1 + if idx := strings.Index(arg.Name, "->"); idx != -1 { + constraints = append(constraints, fmt.Sprintf("%v", arg.Name[varStart:idx])) + } else { + constraints = append(constraints, fmt.Sprintf("%v", arg.Name[varStart:len(arg.Name)])) + } + continue + } + if arg.Umin != int64(-1) { + if arg.Umin == int64(0) { + constraints = append(constraints, fmt.Sprintf("(%v != 0 && (%v & 0x8000000000000000UL == 0))", arg.Name, arg.Name)) + } else { + constraints = append(constraints, fmt.Sprintf("%v > %v", arg.Name, arg.Umin)) //XXX potential mutation point + } + } + if arg.Umax != int64(-1) { + constraints = append(constraints, fmt.Sprintf("%v < %v", arg.Name, arg.Umax)) + } + } + return constraints +} + +//XXX use prog.Arg +type StructDef struct { + Name string + FieldNames []string + FieldTypes []string + Size int + Hints map[ArgHint]bool + IsStruct bool +} + +func (sd *StructDef) offsetOfMember(mi int) int { + offset := 0 + for i := 0; i < mi; i++ { + switch (sd.FieldTypes[i]) { + case "struct bpf_spin_lock": offset += 4 + case "struct bpf_timer": offset += 16 + case "char [8]": offset += 8 + case "uint64_t": offset += 8 + case "uint32_t": offset += 4 + case "uint16_t": offset += 2 + case "uint8_t": offset += 1 + } + } + return offset +} + +func (sd *StructDef) findMember(m string) int { + for i, mt := range sd.FieldTypes { + if mt == m { + return i + } + } + return -1 +} + +func occupiedSize(hints map[ArgHint]bool) int { + occupied := 0 + if _, ok := hints[HintGenSpinlock]; ok { + occupied += 4 + } + if _, ok := hints[HintGenTimer]; ok { + occupied += 16 + } + if _, ok := hints[HintGenConstStr]; ok { + occupied += 8 + } + return occupied +} + +func NewBpfProg(pt *BpfProgTypeDef, r *randGen, opt BrfGenProgOpt) *BpfProg { + p := &BpfProg{ + pt: pt, + Externs: make(map[string]string), + CtxVars: make(map[string]string), + CtxTypes: make(map[string]string), + } + + if (opt.useTestSrc) { + p.BasePath = opt.basePath + "/test_prog" + p.UseTestSrc = true + } else { + p.BasePath = opt.basePath + fmt.Sprintf("/prog_%x", time.Now().UnixNano()) + } + + if r != nil { + p.RetVal = genRandReturnVal(r, pt.Enum) + p.Sec = pt.SecDefs[r.Intn(len(pt.SecDefs))] + if p.Sec.SecDefGen != nil { + name, _ := p.Sec.SecDefGen(r) + p.SecStr = fmt.Sprintf("SEC(\"%s%s\")\n", p.Sec.Sec, name) + } else { + p.SecStr = fmt.Sprintf("SEC(\"%s\")\n", p.Sec.Sec) + } + } + p.AttachOpt.IntOpts = make([]int64, 8) + return p +} + +func (s *BpfProg) NewMap(newMapType BpfMapType, hint *BpfCallGenHint, minValSize int, r *randGen) *BpfMap { + mapType := newMapType.Type + maxEntries := int64(0) + if newMapType.MaxEntries == -1 { + maxEntries = int64(r.Intn(1 << 10)) // XXX negative? + } else if newMapType.MaxEntries == 0 { + maxEntries = int64(0) + } else if newMapType.Type == "BPF_MAP_TYPE_RINGBUF" { + maxEntries = (int64(1) << r.Intn(newMapType.MaxEntries)) * 4096 + } else { + maxEntries = int64(r.Intn(newMapType.MaxEntries)) + } + if _, ok := hint.ArgHints[HintGenConstStr]; ok { + maxEntries = 1 + } + + kok := false + var mapKey *StructDef + compatKeyStructs := getCompatKeyStructDefs(s, newMapType); + if r.Intn(2) == 1 && len(compatKeyStructs) > 0 { + mapKey = compatKeyStructs[r.Intn(len(compatKeyStructs))] + } else { + mapKey, kok = generateStruct(s, r, newMapType.KeySize, hint.ArgHints, false, 0) + if !kok { + return nil + } + } + + vok := false + var mapVal *StructDef + compatValStructs := getCompatValStructDefs(s, hint, minValSize, newMapType); + if r.Intn(2) == 1 && len(compatValStructs) > 0 { + mapVal = compatValStructs[r.Intn(len(compatValStructs))] + } else { + mapVal, vok = generateStruct(s, r, newMapType.ValSize, hint.ArgHints, true, minValSize) + if !vok { + return nil + } + } + + var innerMap *BpfMap + if mapType == "BPF_MAP_TYPE_ARRAY_OF_MAPS" || mapType == "BPF_MAP_TYPE_HASH_OF_MAPS" { + var innerMapHint BpfCallGenHint + innerMapType := bpfMapTypes[r.Intn(len(bpfMapTypes))] + innerMap = s.NewMap(innerMapType, &innerMapHint, 0, r) + } + + var mapFlags []string + for _, fs := range newMapType.ManFlags { + if len(fs) == 1 { + mapFlags = append(mapFlags, fs[0]) + } else { + mapFlags = append(mapFlags, fs[r.Intn(len(fs))]) + } + } + for _, fs := range newMapType.OptFlags { + if mapVal != nil { + if _, ok := mapVal.Hints[HintGenConstStr]; ok && len(fs) == 2 && fs[0] == "BPF_F_WRONLY" { + mapFlags = append(mapFlags, fs[1]) + continue + } + } + if r.Intn(2) == 1 { + continue + } + if len(fs) == 1 { + mapFlags = append(mapFlags, fs[0]) + } else { + mapFlags = append(mapFlags, fs[r.Intn(len(fs))]) + } + } + + newMap := &BpfMap{ + MapType: mapType, + MapFlags: mapFlags, + MapName: fmt.Sprintf("map_%v", len(s.Maps)), + Key: mapKey, + Val: mapVal, + MaxEntries: maxEntries, + InnerMap: innerMap, + } + s.Maps = append(s.Maps, newMap) + return newMap +} + +func (s *BpfProg) AddMap(typ string, flags []string, name string, key *StructDef, val *StructDef, size int64) *BpfMap { + newMap := &BpfMap{ + MapType: typ, + MapFlags: flags, + MapName: name, + Key: key, + Val: val, + MaxEntries: size, + } + s.Maps = append(s.Maps, newMap) + return newMap +} + +//func (s *BpfProg) ProgType() int { +// return s.pt.Num +//} +// +//func (s *BpfProg) ProgTypeEnum() string { +// return s.pt.Enum +//} + +func NewBpfFuncProto(attr map[string]string) *BpfHelperFunc { + bfp := new(BpfHelperFunc) + bfp.Proto = attr["proto"] + bfp.Name = attr["func"] + bfp.Ret = attr["ret_type"] + bfp.GplOnly = attr["gpl_only"] == "true" + for i := 1; i <= 5; i++ { + argName := fmt.Sprintf("arg%d_type", i) + if argType, ok := attr[argName]; ok { + bfp.Args = append(bfp.Args, argType) + } + } + return bfp +} + +func isPtrRegType(t RegType) bool { + return t.String() != "SCALAR_VALUE" +} + +type RegType interface { + String() string + Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg + CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool +} + +type ScalarValRegType struct { +} + +func (t ScalarValRegType) String() string { + return "SCALAR_VALUE" +} + +func (t ScalarValRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + a := NewBpfArg(call.Helper, arg) + + size := r.Intn(64) + if call.StackVarSize != 0 { + size = call.StackVarSize + } + + a.IsNotNull = true + a.Name = fmt.Sprintf("v%d", s.VarId) + a.Prepare = fmt.Sprintf(" int64_t %s = %d;\n", a.Name, size) // XXX does uint64 or int64 matter? + s.VarId += 1 + return a +} + +func (t ScalarValRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + return true +} + +var ctxStructsMap = map[string]*StructDef{ + "bpf_sock_ops": &StructDef{ + Name: "bpf_sock_ops", + FieldTypes: []string{"uint32_t", "uint32_t [4]", "uint32_t", "uint32_t", "uint32_t", "uint32_t [4]", "uint32_t [4]", "uint32_t", "uint32_t", "uint32_t", + "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", + "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", + "uint32_t", "uint32_t", "uint32_t", "uint64_t", "uint64_t", "struct bpf_sock*", "void*", "void*", "uint32_t", "uint32_t"}, + FieldNames: []string{"op", "args", "family", "remote_ip4", "local_ip4", "remote_ip6", "local_ip6", "remote_port", "local_port", "is_fullsock", + "snd_cwnd", "srtt_us", "bpf_sock_ops_cb_flags", "state", "rtt_min", "snd_ssthresh", "rcv_nxt", "snd_nxt", "snd_una", "mss_cache", + "ecn_flags", "rate_delivered", "rate_interval_us", "packets_out", "retrans_out", "total_retrans", "segs_in", "data_segs_in", "segs_out", "data_segs_out", + "lost_out", "sacked_out", "sk_txhash", "bytes_received", "bytes_acked", "sk", "skb_data", "skb_data_end", "skb_len", "skb_tcp_flags"}, + Size: 216, + IsStruct: true, + }, + "sk_reuseport_md": &StructDef{ + Name: "sk_reuseport_md", + FieldTypes: []string{"void *", "void *", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "struct bpf_sock*", "struct bpf_sock*"}, + FieldNames: []string{"data", "data_end", "len", "eth_protocol", "ip_protocol", "bind_inany", "hash", "sk", "migrating_sk"}, + Size: 52, + IsStruct: true, + }, + "sk_msg_md": &StructDef{ + Name: "sk_msg_md", + FieldTypes: []string{"void *", "void *", "uint32_t", "uint32_t", "uint32_t", "uint32_t [4]", "uint32_t [4]", "uint32_t", "uint32_t", "uint32_t", + "struct bpf_sock*"}, + FieldNames: []string{"data", "data_end", "family", "remote_ip4", "local_ip4", "remote_ip6", "local_ip6", "remote_port", "local_port", "size", + "sk"}, + Size: 80, + IsStruct: true, + }, + "__sk_buff": &StructDef{ + Name: "__sk_buff", + FieldTypes: []string{"uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", + "uint32_t", "uint32_t", "uint32_t [5]", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", + "uint32_t", "uint32_t [4]", "uint32_t [4]", "uint32_t", "uint32_t", "uint32_t", "struct bpf_flow_keys*", "uint64_t", "uint32_t", "uint32_t", + "struct bpf_sock*", "uint32_t"}, + FieldNames: []string{"len", "pkt_type", "mark", "queue_mapping", "protocol", "vlan_present", "vlan_tci", "vlan_proto", "priority", "ingress_ifindex", + "ifindex", "tc_index", "cb", "hash", "tc_classid", "data", "data_end", "napi_id", "family", "remote_ip4", + "local_ip4", "remote_ip6", "local_ip6", "remote_port", "local_port", "data_meta", "flow_keys", "tstamp", "wire_len", "gso_segs", + "sk", "gso_size"}, + Size: 180, + IsStruct: true, + }, + "bpf_sock": &StructDef{ + Name: "bpf_sock", + FieldTypes: []string{"uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t [4]", "uint32_t", "uint32_t", + "uint32_t", "uint32_t [4]", "uint32_t", "int32_t"}, + FieldNames: []string{"bound_dev_if", "family", "type", "protocol", "mark", "priority", "src_ip4", "src_ip6", "src_port", "dst_port", + "dst_ip4", "dst_ip6", "state", "rx_queue_mapping"}, + Size: 80, + IsStruct: true, + }, + "bpf_raw_tracepoint_args": &StructDef{ + Name: "bpf_raw_tracepoint_args", + FieldTypes: []string{"uint64_t [0]"}, + FieldNames: []string{"args"}, + Size: 8, + IsStruct: true,//XXX fix this + }, + "bpf_sockopt": &StructDef{ + Name: "bpf_sockopt", + FieldTypes: []string{"struct bpf_sock*", "void *", "void *", "int32_t", "int32_t", "int32_t", "int32_t"}, + FieldNames: []string{"sk", "optval", "optval_end", "level", "optname", "optlen", "retval"}, + Size: 40, + IsStruct: true, + }, + "bpf_sk_lookup": &StructDef{ + Name: "bpf_sk_lookup", + FieldTypes: []string{"struct bpf_sock*", "uint32_t", "uint32_t", "uint32_t", "uint32_t [4]", "uint32_t", "uint32_t", "uint32_t [4]", "uint32_t"}, + FieldNames: []string{"sk", "family", "protocol", "remote_ip4", "remote_ip6", "remote_port", "local_ip4", "local_ip6", "local_port"}, + Size: 64, + IsStruct: true, + }, + "bpf_sock_addr": &StructDef{ + Name: "bpf_sock_addr", + FieldTypes: []string{"uint32_t", "uint32_t", "uint32_t [4]", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t [4]", "struct bpf_sock*"}, + FieldNames: []string{"user_family", "user_ip4", "user_ip6", "user_port", "family", "type", "protocol", "msg_src_ip4", "msg_src_ip6", "sk"}, + Size: 68, + IsStruct: true, + }, + "bpf_perf_event_data": &StructDef{ + Name: "bpf_perf_event_data", + FieldTypes: []string{"struct bpf_user_pt_regs_t", "uint64_t", "uint64_t"}, + FieldNames: []string{"regs", "sample_period", "addr"}, + Size: 184, + IsStruct: true, + }, + "bpf_sysctl": &StructDef{ + Name: "bpf_sysctl", + FieldTypes: []string{"uint32_t", "uint32_t"}, + FieldNames: []string{"write", "file_pos"}, + Size: 8, + IsStruct: true, + }, + "xdp_md": &StructDef{ + Name: "xdp_md", + FieldTypes: []string{"uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t", "uint32_t"}, + FieldNames: []string{"data", "data_end", "data_meta", "ingress_ifindex", "rx_queue_index", "egress_ifindex"}, + Size: 24, + IsStruct: true, + }, + "bpf_user_pt_regs_t": &StructDef{ + Name: "bpf_user_pt_regs_t", + FieldTypes: []string{"uint64_t", "uint64_t", "uint64_t", "uint64_t", "uint64_t", "uint64_t", "uint64_t", "uint64_t", "uint64_t", "uint64_t", + "uint64_t", "uint64_t", "uint64_t", "uint64_t", "uint64_t", "uint64_t", "uint64_t", "uint64_t", "uint64_t", "uint64_t", + "uint64_t"}, + FieldNames: []string{"r15", "r14", "r13", "r12", "bp", "bx", "r11", "r10", "r9", "r8", + "ax", "cx", "dx", "si", "di", "orig_ax", "ip", "cs", "flags", "sp", + "ss"}, + Size: 168, + IsStruct: true, + }, +} + +type PtrToCtxRegType struct { +} + +func (t PtrToCtxRegType) String() string { + return "PTR_TO_CTX" +} + +func (t PtrToCtxRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + a := NewBpfArg(call.Helper, arg) + //CTX access is handled by genRandBpfCtxAccess + a.Name = fmt.Sprintf("ctx") + a.IsNotNull = true + return a +} + +func (t PtrToCtxRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + return true +} + +type ConstPtrToMapRegType struct { +} + +func (t ConstPtrToMapRegType) String() string { + return "CONST_PTR_TO_MAP" +} + +type BpfMapType struct { + Type string + ManFlags [][]string + OptFlags [][]string + KeySize []int + ValSize []int + MaxEntries int +} + +//XXX add key, value constraints +var bpfMapTypes = []BpfMapType { +// BpfMapType{"BPF_PROG_TYPE_UNSPEC",[]string{}}, + BpfMapType{"BPF_MAP_TYPE_HASH", + [][]string{}, + [][]string{[]string{"BPF_F_NO_PREALLOC"},[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"},[]string{"BPF_F_WRONLY_PROG","BPF_F_RDONLY_PROG"},[]string{"BPF_F_ZERO_SEED"}}, + []int{1,1<<12},[]int{1,1<<12},-1}, + BpfMapType{"BPF_MAP_TYPE_ARRAY", + [][]string{}, + [][]string{[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_MMAPABLE"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"},[]string{"BPF_F_WRONLY_PROG","BPF_F_RDONLY_PROG"},[]string{"BPF_F_INNER_MAP"}}, + []int{4,4},[]int{1,1<<12},-1}, + BpfMapType{"BPF_MAP_TYPE_PROG_ARRAY", + [][]string{}, + [][]string{[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"}}, + []int{4,4},[]int{4,4},-1}, + BpfMapType{"BPF_MAP_TYPE_PERF_EVENT_ARRAY", + [][]string{}, + [][]string{[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"},[]string{"BPF_F_PRESERVE_ELEMS"}}, + []int{4,4},[]int{4,4},-1}, + BpfMapType{"BPF_MAP_TYPE_PERCPU_HASH", + [][]string{}, + [][]string{[]string{"BPF_F_NO_PREALLOC"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"},[]string{"BPF_F_WRONLY_PROG","BPF_F_RDONLY_PROG"},[]string{"BPF_F_ZERO_SEED"}}, + []int{1,1<<12},[]int{1,1<<12},-1}, + BpfMapType{"BPF_MAP_TYPE_PERCPU_ARRAY", + [][]string{}, + [][]string{[]string{"BPF_F_WRONLY","BPF_F_RDONLY"},[]string{"BPF_F_WRONLY_PROG","BPF_F_RDONLY_PROG"}}, + []int{4,4},[]int{1,1<<12},-1}, + BpfMapType{"BPF_MAP_TYPE_STACK_TRACE", + [][]string{}, + [][]string{[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_RDONLY","BPF_F_WRONLY"},[]string{"BPF_F_STACK_BUILD_ID"}}, + []int{4,4},[]int{8,1<<12,8},-1}, + BpfMapType{"BPF_MAP_TYPE_CGROUP_ARRAY", + [][]string{}, + [][]string{[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"}}, + []int{4,4},[]int{4,4},-1}, + BpfMapType{"BPF_MAP_TYPE_LRU_HASH", + [][]string{}, + [][]string{[]string{"BPF_F_NO_COMMON_LRU","BPF_F_NUMA_NODE"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"},[]string{"BPF_F_WRONLY_PROG","BPF_F_RDONLY_PROG"},[]string{"BPF_F_ZERO_SEED"}}, + []int{1,1<<12},[]int{1,1<<12},-1}, + BpfMapType{"BPF_MAP_TYPE_LRU_PERCPU_HASH", + [][]string{}, + [][]string{[]string{"BPF_F_NO_COMMON_LRU"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"},[]string{"BPF_F_WRONLY_PROG","BPF_F_RDONLY_PROG"},[]string{"BPF_F_ZERO_SEED"}}, + []int{1,1<<12},[]int{1,1<<12},-1}, + BpfMapType{"BPF_MAP_TYPE_LPM_TRIE", + [][]string{[]string{"BPF_F_NO_PREALLOC"}}, +// [][]string{[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"},[]string{"BPF_F_WRONLY_PROG","BPF_F_RDONLY_PROG"}}, + [][]string{[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_WRONLY"},[]string{"BPF_F_WRONLY_PROG","BPF_F_RDONLY_PROG"}}, + []int{9,264},[]int{1,1<<12},-1}, + BpfMapType{"BPF_MAP_TYPE_ARRAY_OF_MAPS", + [][]string{}, + [][]string{[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"}}, + []int{4,4},[]int{4,4},-1}, + BpfMapType{"BPF_MAP_TYPE_HASH_OF_MAPS", + [][]string{}, +// [][]string{[]string{"BPF_F_NO_PREALLOC"},[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"},[]string{"BPF_F_WRONLY_PROG","BPF_F_RDONLY_PROG"},[]string{"BPF_F_ZERO_SEED"}}, +// do not use BPF_F_RDONLY so that libbpf can fill in the inner maps + [][]string{[]string{"BPF_F_NO_PREALLOC"},[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_WRONLY"},[]string{"BPF_F_WRONLY_PROG","BPF_F_RDONLY_PROG"},[]string{"BPF_F_ZERO_SEED"}}, + []int{1,1<<12},[]int{4,4},-1}, + BpfMapType{"BPF_MAP_TYPE_DEVMAP", + [][]string{}, + [][]string{[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"}}, + []int{4,4},[]int{4,8,4},-1}, + BpfMapType{"BPF_MAP_TYPE_SOCKMAP", + [][]string{}, + [][]string{[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"}}, + []int{4,4},[]int{4,8,4},-1}, + BpfMapType{"BPF_MAP_TYPE_CPUMAP", + [][]string{}, + [][]string{[]string{"BPF_F_NUMA_NODE"}}, + []int{4,4},[]int{4,8,4},-1}, + BpfMapType{"BPF_MAP_TYPE_XSKMAP", + [][]string{}, + [][]string{[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"}}, + []int{4,4},[]int{4,4},-1}, + BpfMapType{"BPF_MAP_TYPE_SOCKHASH", + [][]string{}, + [][]string{[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"}}, + []int{1,512},[]int{4,8,4},-1}, + BpfMapType{"BPF_MAP_TYPE_CGROUP_STORAGE", + [][]string{}, + [][]string{[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_RDONLY_PROG","BPF_F_WRONLY_PROG"}}, + []int{8,12,4},[]int{8,1<<16},0}, + BpfMapType{"BPF_MAP_TYPE_REUSEPORT_SOCKARRAY", + [][]string{}, + [][]string{[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"},[]string{"BPF_F_WRONLY_PROG","BPF_F_RDONLY_PROG"}}, + []int{1,1<<16},[]int{4,8,4},-1}, //XXX 16 for max for now + BpfMapType{"BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE", + [][]string{}, + [][]string{[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_RDONLY_PROG","BPF_F_WRONLY_PROG"}}, + []int{8,12,4},[]int{8,1<<16},0}, +// []int{4,4},[]int{1,1<<16},0}, // XXX 16 for max for now + BpfMapType{"BPF_MAP_TYPE_QUEUE", + [][]string{}, + [][]string{[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"},[]string{"BPF_F_RDONLY_PROG"},[]string{"BPF_F_WRONLY_PROG"}}, + []int{0,0},[]int{1,1<<12},-1}, + BpfMapType{"BPF_MAP_TYPE_STACK", + [][]string{}, + [][]string{[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"},[]string{"BPF_F_RDONLY_PROG"},[]string{"BPF_F_WRONLY_PROG"}}, + []int{0,0},[]int{1,1<<12},-1}, + BpfMapType{"BPF_MAP_TYPE_SK_STORAGE", + [][]string{[]string{"BPF_F_NO_PREALLOC"}}, + [][]string{[]string{"BPF_F_CLONE"}}, + []int{4,4},[]int{1,1<<16},0}, // XXX 16 for max for now + BpfMapType{"BPF_MAP_TYPE_DEVMAP_HASH", + [][]string{}, + [][]string{[]string{"BPF_F_NUMA_NODE"},[]string{"BPF_F_WRONLY","BPF_F_RDONLY"}}, + []int{4,4},[]int{4,8,4},-1}, + BpfMapType{"BPF_MAP_TYPE_STRUCT_OPS", + [][]string{}, + [][]string{}, + []int{4,4},[]int{0,1<<12},1}, // XXX 12 for now + BpfMapType{"BPF_MAP_TYPE_RINGBUF", + [][]string{}, + [][]string{[]string{"BPF_F_NUMA_NODE"}}, + []int{0,0},[]int{0,0},24}, // 1<<24 + BpfMapType{"BPF_MAP_TYPE_INODE_STORAGE", + [][]string{[]string{"BPF_F_NO_PREALLOC"}}, + [][]string{[]string{"BPF_F_CLONE"}}, + []int{4,4},[]int{1,1<<16},0}, // XXX 16 for max for now + BpfMapType{"BPF_MAP_TYPE_TASK_STORAGE", + [][]string{[]string{"BPF_F_NO_PREALLOC"}}, + [][]string{[]string{"BPF_F_CLONE"}}, + []int{4,4},[]int{1,1<<16},0}, // XXX 16 for max for now +} + +func generateStruct(s *BpfProg, r *randGen, sizeConstraints []int, hints map[ArgHint]bool, useHint bool, minSizeHint int) (*StructDef, bool) { + min := sizeConstraints[0] + max := sizeConstraints[1] + align := 1 + if len(sizeConstraints) == 3 { + align = sizeConstraints[2] + } + + sd := new(StructDef) + sd.Hints = make(map[ArgHint]bool) + target := "key" + if useHint { + target = "val" + } + fmt.Printf("(%v) gen %v struct_%d initial min=%v max=%v align=%v ArgHints=%x occu=%d\n", + rd, target, len(s.Structs), min, max, align, hints, occupiedSize(hints)) + + if useHint { + occupied := occupiedSize(hints) + if occupied > max { + fmt.Printf("error: map type value size not large enough to accommodate %x\n", hints) + return nil, false + } + if occupied > min { + min = occupied + } + + if minSizeHint > max { + fmt.Printf("error: map type size not large enough to accommodate %x\n", minSizeHint) + return nil, false + } else if min != max && minSizeHint > min { + min = minSizeHint + } + } + + size := 0 + if min == max { + size = min + } else if max > min { + // XXX Re-adjust max to 128 for now + if max > 128 { + max = 128 + } + size = r.Intn(max-min+1) + min + // adjust size according to alignment + if align != 1 { + size = size - (size%align) + } + } else { + fmt.Printf("error: max < min\n") + return nil, false + } + if size == 0 { + return nil, true + } + sd.Size = size + + fmt.Printf("(%v) gen %v struct_%d adjust min=%v max=%v align=%v, size=%v\n", + rd, target, len(s.Structs), min, max, align, size) + + offset := 0 + for { + if offset >= size { + break + } + toEnd := size - offset + if _, ok := hints[HintGenSpinlock]; useHint && ok { + sd.Hints[HintGenSpinlock] = true + delete(hints, HintGenSpinlock) + sd.FieldTypes = append(sd.FieldTypes, "struct bpf_spin_lock") + offset += 4 + } else if _, ok := hints[HintGenTimer]; useHint && ok { + sd.Hints[HintGenTimer] = true + delete(hints, HintGenTimer) + sd.FieldTypes = append(sd.FieldTypes, "struct bpf_timer") + offset += 16 + } else if _, ok := hints[HintGenConstStr]; useHint && ok { + sd.Hints[HintGenConstStr] = true + delete(hints, HintGenConstStr) + sd.FieldTypes = append(sd.FieldTypes, "char [8]") + offset += 8 + } else if toEnd >= 8 { + sd.FieldTypes = append(sd.FieldTypes, "uint64_t") + offset += 8 + } else if toEnd >= 4 { + sd.FieldTypes = append(sd.FieldTypes, "uint32_t") + offset += 4 + } else if toEnd >= 2 { + sd.FieldTypes = append(sd.FieldTypes, "uint16_t") + offset += 2 + } else { + sd.FieldTypes = append(sd.FieldTypes, "uint8_t") + offset += 1 + } + } + + if len(sd.FieldTypes) == 1 { + sd.IsStruct = false + sd.Name = fmt.Sprintf("%v", sd.FieldTypes[0]) + } else { + sd.IsStruct = true + sd.Name = fmt.Sprintf("struct_%d", len(s.Structs)) + } + + s.Structs = append(s.Structs, sd) + return sd, true +} + +var mayUpdateSockmapProgs = map[BpfProgTypeEnum]bool { + BPF_PROG_TYPE_TRACING: true, +// if (eatype == BPF_TRACE_ITER) + BPF_PROG_TYPE_SOCKET_FILTER: true, + BPF_PROG_TYPE_SCHED_CLS: true, + BPF_PROG_TYPE_SCHED_ACT: true, + BPF_PROG_TYPE_XDP: true, + BPF_PROG_TYPE_SK_REUSEPORT: true, + BPF_PROG_TYPE_FLOW_DISSECTOR: true, + BPF_PROG_TYPE_SK_LOOKUP: true, +} + +var funcCompMaps = map[string][]string { + "BPF_FUNC_tail_call": []string{"BPF_MAP_TYPE_PROG_ARRAY"}, + "BPF_FUNC_perf_event_read": []string{"BPF_MAP_TYPE_PERF_EVENT_ARRAY"}, + "BPF_FUNC_perf_event_output": []string{"BPF_MAP_TYPE_PERF_EVENT_ARRAY"}, + "BPF_FUNC_perf_event_read_value": []string{"BPF_MAP_TYPE_PERF_EVENT_ARRAY"}, + "BPF_FUNC_skb_output": []string{"BPF_MAP_TYPE_PERF_EVENT_ARRAY"}, + "BPF_FUNC_xdp_output": []string{"BPF_MAP_TYPE_PERF_EVENT_ARRAY"}, + "BPF_FUNC_ringbuf_output": []string{"BPF_MAP_TYPE_RINGBUF"}, + "BPF_FUNC_ringbuf_reserve": []string{"BPF_MAP_TYPE_RINGBUF"}, + "BPF_FUNC_ringbuf_query": []string{"BPF_MAP_TYPE_RINGBUF"}, + "BPF_FUNC_get_stackid": []string{"BPF_MAP_TYPE_STACK_TRACE"}, + "BPF_FUNC_current_task_under_cgroup": []string{"BPF_MAP_TYPE_CGROUP_ARRAY"}, + "BPF_FUNC_skb_under_cgroup": []string{"BPF_MAP_TYPE_CGROUP_ARRAY"}, + "BPF_FUNC_redirect_map": []string{"BPF_MAP_TYPE_DEVMAP","BPF_MAP_TYPE_DEVMAP_HASH","BPF_MAP_TYPE_CPUMAP","BPF_MAP_TYPE_XSKMAP"}, + "BPF_FUNC_sk_redirect_map": []string{"BPF_MAP_TYPE_SOCKMAP"}, + "BPF_FUNC_msg_redirect_map": []string{"BPF_MAP_TYPE_SOCKMAP"}, + "BPF_FUNC_sock_map_update": []string{"BPF_MAP_TYPE_SOCKMAP"}, + "BPF_FUNC_sk_redirect_hash": []string{"BPF_MAP_TYPE_SOCKHASH"}, + "BPF_FUNC_msg_redirect_hash": []string{"BPF_MAP_TYPE_SOCKHASH"}, + "BPF_FUNC_sock_hash_update": []string{"BPF_MAP_TYPE_SOCKHASH"}, + "BPF_FUNC_get_local_storage": []string{"BPF_MAP_TYPE_CGROUP_STORAGE","BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE"}, + "BPF_FUNC_sk_select_reuseport": []string{"BPF_MAP_TYPE_REUSEPORT_SOCKARRAY","BPF_MAP_TYPE_SOCKMAP","BPF_MAP_TYPE_SOCKHASH"}, + "BPF_FUNC_map_peek_elem": []string{"BPF_MAP_TYPE_QUEUE","BPF_MAP_TYPE_STACK"}, + "BPF_FUNC_map_pop_elem": []string{"BPF_MAP_TYPE_QUEUE","BPF_MAP_TYPE_STACK"}, + "BPF_FUNC_map_push_elem": []string{"BPF_MAP_TYPE_QUEUE","BPF_MAP_TYPE_STACK"}, + "BPF_FUNC_sk_storage_get": []string{"BPF_MAP_TYPE_SK_STORAGE"}, + "BPF_FUNC_sk_storage_delete": []string{"BPF_MAP_TYPE_SK_STORAGE"}, + "BPF_FUNC_inode_storage_get": []string{"BPF_MAP_TYPE_INODE_STORAGE"}, + "BPF_FUNC_inode_storage_delete": []string{"BPF_MAP_TYPE_INODE_STORAGE"}, + "BPF_FUNC_task_storage_get": []string{"BPF_MAP_TYPE_TASK_STORAGE"}, + "BPF_FUNC_task_storage_delete": []string{"BPF_MAP_TYPE_TASK_STORAGE"}, +} + +var mapCompFuncs = map[string][]string { + "BPF_MAP_TYPE_PROG_ARRAY": []string{"BPF_FUNC_tail_call"}, + "BPF_MAP_TYPE_PERF_EVENT_ARRAY": []string{"BPF_FUNC_perf_event_read","BPF_FUNC_perf_event_output","BPF_FUNC_skb_output","BPF_FUNC_perf_event_read_value","BPF_FUNC_xdp_output"}, + "BPF_MAP_TYPE_RINGBUF": []string{"BPF_FUNC_ringbuf_output","BPF_FUNC_ringbuf_reserve","BPF_FUNC_ringbuf_query"}, + "BPF_MAP_TYPE_STACK_TRACE": []string{"BPF_FUNC_get_stackid"}, + "BPF_MAP_TYPE_CGROUP_ARRAY": []string{"BPF_FUNC_skb_under_cgroup","BPF_FUNC_current_task_under_cgroup"}, + "BPF_MAP_TYPE_CGROUP_STORAGE": []string{"BPF_FUNC_get_local_storage"}, + "BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE": []string{"BPF_FUNC_get_local_storage"}, + "BPF_MAP_TYPE_DEVMAP": []string{"BPF_FUNC_redirect_map","BPF_FUNC_map_lookup_elem"}, + "BPF_MAP_TYPE_DEVMAP_HASH": []string{"BPF_FUNC_redirect_map","BPF_FUNC_map_lookup_elem"}, + "BPF_MAP_TYPE_CPUMAP": []string{"BPF_FUNC_redirect_map"}, + "BPF_MAP_TYPE_XSKMAP": []string{"BPF_FUNC_redirect_map","BPF_FUNC_map_lookup_elem"}, + "BPF_MAP_TYPE_ARRAY_OF_MAPS": []string{"BPF_FUNC_map_lookup_elem"}, + "BPF_MAP_TYPE_HASH_OF_MAPS": []string{"BPF_FUNC_map_lookup_elem"}, + "BPF_MAP_TYPE_SOCKMAP": []string{"BPF_FUNC_sk_redirect_map","BPF_FUNC_sock_map_update","BPF_FUNC_map_delete_elem","BPF_FUNC_msg_redirect_map","BPF_FUNC_sk_select_reuseport","BPF_FUNC_map_lookup_elem"}, + // XXX !may_update_sockmap(env, func_id)) + "BPF_MAP_TYPE_SOCKHASH": []string{"BPF_FUNC_sk_redirect_hash","BPF_FUNC_sock_hash_update","BPF_FUNC_map_delete_elem","BPF_FUNC_msg_redirect_hash","BPF_FUNC_sk_select_reuseport","BPF_FUNC_map_lookup_elem"}, + // XXX !may_update_sockmap(env, func_id)) + "BPF_MAP_TYPE_REUSEPORT_SOCKARRAY": []string{"BPF_FUNC_sk_select_reuseport"}, + "BPF_MAP_TYPE_QUEUE": []string{"BPF_FUNC_map_peek_elem","BPF_FUNC_map_pop_elem","BPF_FUNC_map_push_elem"}, + "BPF_MAP_TYPE_STACK": []string{"BPF_FUNC_map_peek_elem","BPF_FUNC_map_pop_elem","BPF_FUNC_map_push_elem"}, + "BPF_MAP_TYPE_SK_STORAGE": []string{"BPF_FUNC_sk_storage_get","BPF_FUNC_sk_storage_delete"}, + "BPF_MAP_TYPE_INODE_STORAGE": []string{"BPF_FUNC_inode_storage_get","BPF_FUNC_inode_storage_delete"}, + "BPF_MAP_TYPE_TASK_STORAGE": []string{"BPF_FUNC_task_storage_get","BPF_FUNC_task_storage_delete"}, +} + +func isMapFuncCompatible(m string, f string) bool { + if maps, ok := funcCompMaps[f]; ok { + compatible := false + for _, cm := range maps { + if cm == m { + compatible = true + break + } + } + if !compatible { + return false + } + } + if funcs, ok := mapCompFuncs[m]; ok { + compatible := false + for _, cf := range funcs { + if cf == f { + compatible = true + break + } + } + if !compatible { + return false + } + } + return true +} + +func getHelperCompatMaps(s *BpfProg, call *BpfCall) []*BpfMap { + var compatMaps []*BpfMap + for _, m := range s.Maps { + if !isMapFuncCompatible(m.MapType, call.Helper.Enum) { + continue + } + + mapHasSpinlock := (m.Val != nil && m.Val.findMember("struct bpf_spin_lock") != -1) + mapHasTimer := (m.Val != nil && m.Val.findMember("struct bpf_timer") != -1) + mapHasConstStr := (m.Val != nil && m.Val.findMember("char [8]") != -1) + mapIsRdOnly := (m.getFlag("BPF_F_RDONLY_PROG") != -1) + mapIsWrOnly := (m.getFlag("BPF_F_WRONLY_PROG") != -1) + + //6084 + if (call.Helper.Enum == "BPF_FUNC_map_delete_elem" || call.Helper.Enum == "BPF_FUNC_map_update_elem" || + call.Helper.Enum == "BPF_FUNC_map_push_elem" || call.Helper.Enum == "BPF_FUNC_map_pop_elem") && + mapIsRdOnly { + continue + } + //4706, 4767 + _, genSpinlock := call.Hint.ArgHints[HintGenSpinlock] + _, genTimer := call.Hint.ArgHints[HintGenTimer] + _, genConstStr := call.Hint.ArgHints[HintGenConstStr] + if (genSpinlock && (!mapHasSpinlock || mapIsRdOnly)) || + (genTimer && (!mapHasTimer || mapIsRdOnly)) || + (genConstStr && !mapHasConstStr) { + continue + } + //11473, 11478, 11484 + if mapHasSpinlock && + (s.pt.Enum == BPF_PROG_TYPE_SOCKET_FILTER || isTracingProgType(s.pt.Enum) || s.Sec.Sleepable) { + continue + } + //11503 + if m.MapType == "BPF_MAP_TYPE_STRUCT_OPS" { + continue + } + //11526 + if s.Sec.Sleepable && + !(m.MapType == "BPF_MAP_TYPE_HASH" || m.MapType == "BPF_MAP_TYPE_LRU_HASH" || m.MapType == "BPF_MAP_TYPE_ARRAY" || + m.MapType == "BPF_MAP_TYPE_PERCPU_HASH" || m.MapType == "BPF_MAP_TYPE_PERCPU_ARRAY" || m.MapType == "BPF_MAP_TYPE_LRU_PERCPU_HASH" || + m.MapType == "BPF_MAP_TYPE_ARRAY_OF_MAPS" || m.MapType == "BPF_MAP_TYPE_HASH_OF_MAPS" || m.MapType == "BPF_MAP_TYPE_RINGBUF") { + continue + } + //11704 + if m.MapType == "BPF_MAP_TYPE_CGROUP_STORAGE" { + hasCgroupStorageMap := false + for _, pm := range s.Maps { + if pm.MapType == "BPF_MAP_TYPE_CGROUP_STORAGE" { + hasCgroupStorageMap = true + } + } + if hasCgroupStorageMap { + continue + } + } + if m.MapType == "BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE" { + hasPercpuCgroupStorageMap := false + for _, pm := range s.Maps { + if pm.MapType == "BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE" { + hasPercpuCgroupStorageMap = true + } + } + if hasPercpuCgroupStorageMap { + continue + } + } + + _, genSockMap := call.Hint.ArgHints[HintGenSockMap] + _, genXdpSockMap := call.Hint.ArgHints[HintGenXdpSockMap] + if call.Helper.Ret == "RET_PTR_TO_MAP_VALUE_OR_NULL" { + if genXdpSockMap != (m.MapType == "BPF_MAP_TYPE_XSKMAP") { + continue + } + if genSockMap != (m.MapType == "BPF_MAP_TYPE_SOCKMAP" || m.MapType == "BPF_MAP_TYPE_SOCKHASH") { + continue + } + } + + if (call.Helper.Ret == "RET_PTR_TO_MAP_VALUE" || call.Helper.Ret == "RET_PTR_TO_MAP_VALUE_OR_NULL") && call.Hint.RetAccessSize != 0 { + if m.Val == nil || m.Val.Size < call.Hint.RetAccessSize { + continue + } + if mapIsRdOnly && call.Hint.IsRetAccessRaw { + continue + } + if mapIsWrOnly && !call.Hint.IsRetAccessRaw { + continue + } + if call.Hint.IsRetAccessRaw && (m.MapType == "BPF_MAP_TYPE_DEVMAP" || m.MapType == "BPF_MAP_TYPE_DEVMAP_HASH") { + continue + } + } + compatMaps = append(compatMaps, m) + } + return compatMaps +} + +func isTracingProgType(e BpfProgTypeEnum) bool { + return e == BPF_PROG_TYPE_KPROBE || e == BPF_PROG_TYPE_TRACEPOINT || e == BPF_PROG_TYPE_PERF_EVENT || e == BPF_PROG_TYPE_RAW_TRACEPOINT +} + +func getHelperCompatMapTypes(s *BpfProg, call *BpfCall) []BpfMapType { + var compatMapTypes []BpfMapType + for _, mt := range bpfMapTypes { + if !isMapFuncCompatible(mt.Type, call.Helper.Enum) { + continue + } + if mt.ValSize[1] < occupiedSize(call.Hint.ArgHints) { + continue + } + if _, ok := call.Hint.ArgHints[HintGenSpinlock]; ok { + if mt.Type != "BPF_MAP_TYPE_HASH" && mt.Type != "BPF_MAP_TYPE_ARRAY" && + mt.Type != "BPF_MAP_TYPE_CGROUP_STORAGE" && mt.Type != "BPF_MAP_TYPE_SK_STORAGE" && + mt.Type != "BPF_MAP_TYPE_INODE_STORAGE" && mt.Type != "BPF_MAP_TYPE_TASK_STORAGE" { + continue + } + //11473, 11478, 11484 + if s.pt.Enum == BPF_PROG_TYPE_SOCKET_FILTER || isTracingProgType(s.pt.Enum) || s.Sec.Sleepable { + continue + } + } + if _, ok := call.Hint.ArgHints[HintGenTimer]; ok { + if mt.Type != "BPF_MAP_TYPE_HASH" && mt.Type != "BPF_MAP_TYPE_LRU_HASH" && mt.Type != "BPF_MAP_TYPE_ARRAY" { + continue + } + if isTracingProgType(s.pt.Enum) { // 11491 + continue + } + } + //11503 + if mt.Type == "BPF_MAP_TYPE_STRUCT_OPS" { + continue + } + //11526 + if s.Sec.Sleepable && + !(mt.Type == "BPF_MAP_TYPE_HASH" || mt.Type == "BPF_MAP_TYPE_LRU_HASH" || mt.Type == "BPF_MAP_TYPE_ARRAY" || + mt.Type == "BPF_MAP_TYPE_PERCPU_HASH" || mt.Type == "BPF_MAP_TYPE_PERCPU_ARRAY" || mt.Type == "BPF_MAP_TYPE_LRU_PERCPU_HASH" || + mt.Type == "BPF_MAP_TYPE_ARRAY_OF_MAPS" || mt.Type == "BPF_MAP_TYPE_HASH_OF_MAPS" || mt.Type == "BPF_MAP_TYPE_RINGBUF") { + continue + } + //11704 + if mt.Type == "BPF_MAP_TYPE_CGROUP_STORAGE" { + hasCgroupStorageMap := false + for _, pm := range s.Maps { + if pm.MapType == "BPF_MAP_TYPE_CGROUP_STORAGE" { + hasCgroupStorageMap = true + } + } + if hasCgroupStorageMap { + continue + } + } + if mt.Type == "BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE" { + hasPercpuCgroupStorageMap := false + for _, pm := range s.Maps { + if pm.MapType == "BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE" { + hasPercpuCgroupStorageMap = true + } + } + if hasPercpuCgroupStorageMap { + continue + } + } + _, genSockMap := call.Hint.ArgHints[HintGenSockMap] + _, genXdpSockMap := call.Hint.ArgHints[HintGenXdpSockMap] + if call.Helper.Ret == "RET_PTR_TO_MAP_VALUE_OR_NULL" { + if genXdpSockMap != (mt.Type == "BPF_MAP_TYPE_XSKMAP") { + continue + } + if genSockMap != (mt.Type == "BPF_MAP_TYPE_SOCKMAP" || mt.Type == "BPF_MAP_TYPE_SOCKHASH") { + continue + } + } + if call.Hint.IsRetAccessRaw && (mt.Type == "BPF_MAP_TYPE_DEVMAP" || mt.Type == "BPF_MAP_TYPE_DEVMAP_HASH") { + continue + } + // check if the current program type permits updating sockmap + if call.Helper.Enum == "BPF_FUNC_map_update_elem" && (mt.Type == "BPF_MAP_TYPE_SOCKMAP" || mt.Type == "BPF_MAP_TYPE_SOCKHASH") { + if _, ok := mayUpdateSockmapProgs[s.pt.Enum]; !ok { + continue + } + } + compatMapTypes = append(compatMapTypes, mt) + } + return compatMapTypes +} + +func getCompatKeyStructDefs(s *BpfProg, mapType BpfMapType) []*StructDef { + var compatStructs []*StructDef + for _, structDef := range s.Structs { + if structDef.Size < mapType.KeySize[0] || structDef.Size > mapType.KeySize[1] { + continue + } + compatStructs = append(compatStructs, structDef) + } + return compatStructs +} + +func getCompatValStructDefs(s *BpfProg, hint *BpfCallGenHint, minValSize int, mapType BpfMapType) []*StructDef { + var compatStructs []*StructDef + for _, structDef := range s.Structs { + //if (call.Helper.Ret == "RET_PTR_TO_MAP_VALUE" || call.Helper.Ret == "RET_PTR_TO_MAP_VALUE_OR_NULL") && + // structDef.Size < call.Hint.RetAccessSize { + // continue + //} + if minValSize != -1 && structDef.Size < minValSize { + continue + } + if _, ok := hint.ArgHints[HintGenSpinlock]; ok && + structDef.findMember("struct bpf_spin_lock") == -1 { + continue + } + if _, ok := hint.ArgHints[HintGenTimer]; ok && + structDef.findMember("struct bpf_timer") == -1 { + continue + } + if _, ok := hint.ArgHints[HintGenConstStr]; ok && + structDef.findMember("char [8]") == -1 { + continue + } + if _, ok := hint.ArgHints[HintGenSockMap]; ok { + continue + } + if _, ok := hint.ArgHints[HintGenXdpSockMap]; ok { + continue + } + if structDef.Size < mapType.ValSize[0] || structDef.Size > mapType.ValSize[1] { + continue + } + if len(mapType.KeySize) == 3 && structDef.Size % mapType.KeySize[2] != 0 { + continue + } + compatStructs = append(compatStructs, structDef) + } + return compatStructs +} + +func (t ConstPtrToMapRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + a := NewBpfArg(call.Helper, arg) + a.IsNotNull = true + + if call.Hint.PreferredMap != nil { + call.ArgMap = call.Hint.PreferredMap + a.Name = fmt.Sprintf("&%v", call.ArgMap.MapName) + return a + } + + if call.ArgMap != nil { + a.Name = fmt.Sprintf("&%v", call.ArgMap.MapName) + return a + } + + var m *BpfMap + + if compatMaps := getHelperCompatMaps(s, call); len(compatMaps) != 0 && r.nOutOf(2, 3) { + // Choose an existing map + m = compatMaps[r.Intn(len(compatMaps))] + } else { + // Use a newly generated map + var newMapType BpfMapType + compatMapTypes := getHelperCompatMapTypes(s, call) + if len(compatMapTypes) == 0 { + return nil// XXX failed + } + + if _, ok := call.Hint.ArgHints[HintGenConstStr]; ok { + mapTypeArrayIdx := -1 + for mi, mt := range compatMapTypes { + if mt.Type == "BPF_MAP_TYPE_ARRAY" { + mapTypeArrayIdx = mi + break + } + } + if mapTypeArrayIdx == -1 { + return nil + } + newMapType = compatMapTypes[mapTypeArrayIdx] + } else { + newMapType = compatMapTypes[r.Intn(len(compatMapTypes))] + } + + minValSize := -1 + if call.Helper.Ret == "RET_PTR_TO_MAP_VALUE" || call.Helper.Ret == "RET_PTR_TO_MAP_VALUE_OR_NULL" { + minValSize = call.Hint.RetAccessSize + } + m = s.NewMap(newMapType, call.Hint, minValSize, r) + + if m == nil { + return nil + } + + if call.Helper.Enum == "BPF_FUNC_map_delete_elem" || call.Helper.Enum == "BPF_FUNC_map_update_elem" || + call.Helper.Enum == "BPF_FUNC_map_push_elem" || call.Helper.Enum == "BPF_FUNC_map_pop_elem" { + m.removeFlag("BPF_F_RDONLY_PROG") + } + //4706,4767 + if m.Val != nil && (m.Val.findMember("struct bpf_spin_lock") != -1 || m.Val.findMember("struct bpf_timer") != -1) { + m.removeFlag("BPF_F_RDONLY_PROG") + } + //11461 + if s.pt.Enum == BPF_PROG_TYPE_PERF_EVENT && + (newMapType.Type == "BPF_MAP_TYPE_HASH" || newMapType.Type == "BPF_MAP_TYPE_PERCPU_HASH" || newMapType.Type == "BPF_MAP_TYPE_HASH_OF_MAPS") { + m.removeFlag("BPF_F_NO_PREALLOC") + } + //11518 + if s.Sec.Sleepable && + (newMapType.Type == "BPF_MAP_TYPE_HASH" || newMapType.Type == "BPF_MAP_TYPE_LRU_HASH" || newMapType.Type == "BPF_MAP_TYPE_ARRAY" || + newMapType.Type == "BPF_MAP_TYPE_PERCPU_HASH" || newMapType.Type == "BPF_MAP_TYPE_PERCPU_ARRAY" || newMapType.Type == "BPF_MAP_TYPE_LRU_PERCPU_HASH" || + newMapType.Type == "BPF_MAP_TYPE_ARRAY_OF_MAPS" || newMapType.Type == "BPF_MAP_TYPE_HASH_OF_MAPS") { + m.removeFlag("BPF_F_NO_PREALLOC") + } + } + call.ArgMap = m + a.Name = fmt.Sprintf("&%v", m.MapName) + return a +} + +func (t ConstPtrToMapRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + return true +} + +type PtrToMapValueRegType struct { +} + +func (t PtrToMapValueRegType) String() string { + return "PTR_TO_MAP_VALUE" +} + +func (t PtrToMapValueRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + //XXX Consider record loaded map values and reuse them + return nil +} + +func (t PtrToMapValueRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + return true +} + +type PtrToStackRegType struct { +} + +func (t PtrToStackRegType) String() string { + return "PTR_TO_STACK" +} + +func roundUp(val int, align int) int { + ret := val / align + if val % align != 0 { + ret += 1 + } + return ret * align +} + +func (t PtrToStackRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + a := NewBpfArg(call.Helper, arg) + + varSize := r.Intn(64) + if call.ArgMap != nil { + if call.Helper.Args[arg] == "ARG_PTR_TO_MAP_KEY" && call.ArgMap.Key != nil { + varSize = roundUp(call.ArgMap.Key.Size, 8) //XXX need to round up key size? + } + if (call.Helper.Args[arg] == "ARG_PTR_TO_MAP_VALUE" || call.Helper.Args[arg] == "ARG_PTR_TO_MAP_VALUE_OR_NULL" || call.Helper.Args[arg] == "ARG_PTR_TO_UNINIT_MAP_VALUE") && call.ArgMap.Val != nil { + varSize = roundUp(call.ArgMap.Val.Size, 8) + } + } + + call.StackVarSize = varSize + a.IsNotNull = true + a.Name = fmt.Sprintf("v%d", s.VarId) + a.Prepare = fmt.Sprintf(" char %s[%d] = {};\n", a.Name, varSize) + s.VarId += 1 + return a +} + +func (t PtrToStackRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + return true +} + +var PktPtrReadOnly = map[BpfProgTypeEnum]bool { + BPF_PROG_TYPE_LWT_IN: true, + BPF_PROG_TYPE_LWT_OUT: true, + BPF_PROG_TYPE_LWT_SEG6LOCAL: true, + BPF_PROG_TYPE_SK_REUSEPORT: true, + BPF_PROG_TYPE_FLOW_DISSECTOR: true, + BPF_PROG_TYPE_CGROUP_SKB: true, +} + +var PktPtrReadWrite = map[BpfProgTypeEnum]bool { + BPF_PROG_TYPE_SCHED_CLS: true, + BPF_PROG_TYPE_SCHED_ACT: true, + BPF_PROG_TYPE_XDP: true, + BPF_PROG_TYPE_LWT_XMIT: true, + BPF_PROG_TYPE_SK_SKB: true, + BPF_PROG_TYPE_SK_MSG: true, +} + +var PktPtrReadWriteNoCheck = map[BpfProgTypeEnum]bool { + BPF_PROG_TYPE_CGROUP_SOCKOPT: true, +} + +func checkPktAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + canWrite := true + if _, ok := PktPtrReadOnly[s.pt.Enum]; ok { + canWrite = false + } else if _, ok := PktPtrReadWrite[s.pt.Enum]; ok { + canWrite = true + } else if _, ok := PktPtrReadWriteNoCheck[s.pt.Enum]; ok { + return true + } else { + return false + } + + if (!canWrite && isWrite) { + return false + } else { + return h.PktAccess + } +} + +type PtrToPacketMetaRegType struct { +} + +func (t PtrToPacketMetaRegType) String() string { + return "PTR_TO_PACKET_META" +} + +func (t PtrToPacketMetaRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + return nil +} + +func (t PtrToPacketMetaRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + return checkPktAccess(s, h, isWrite) +} + +type PtrToPacketRegType struct { +} + +func (t PtrToPacketRegType) String() string { + return "PTR_TO_PACKET" +} + +func (t PtrToPacketRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + return nil +} + +func (t PtrToPacketRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + return checkPktAccess(s, h, isWrite) +} + +type PtrToPacketEndRegType struct { +} + +func (t PtrToPacketEndRegType) String() string { + return "PTR_TO_PACKET_END" +} + +func (t PtrToPacketEndRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + return nil +} + +func (t PtrToPacketEndRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + //XXX not found in check_mem_access + return false +} + +type PtrToFlowKeysRegType struct { +} + +func (t PtrToFlowKeysRegType) String() string { + return "PTR_TO_FLOW_KEYS" +} + +func (t PtrToFlowKeysRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + return nil +} + +func (t PtrToFlowKeysRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + return true +} + +type PtrToSocketRegType struct { +} + +func (t PtrToSocketRegType) String() string { + return "PTR_TO_SOCKET" +} + +func (t PtrToSocketRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + return nil +} + +func (t PtrToSocketRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + return !isWrite +} + +type PtrToSockCommonRegType struct { +} + +func (t PtrToSockCommonRegType) String() string { + return "PTR_TO_SOCK_COMMON" +} + +func (t PtrToSockCommonRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + return nil +} + +func (t PtrToSockCommonRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + return !isWrite +} + +type PtrToTcpSockRegType struct { +} + +func (t PtrToTcpSockRegType) String() string { + return "PTR_TO_TCP_SOCK" +} + +func (t PtrToTcpSockRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + return nil +} + +func (t PtrToTcpSockRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + return !isWrite +} + +type PtrToTpBufferRegType struct { +} + +func (t PtrToTpBufferRegType) String() string { + return "PTR_TO_TP_BUFFER" +} + +func (t PtrToTpBufferRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + return nil +} + +func (t PtrToTpBufferRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + return true +} + +type PtrToXdpSockRegType struct { +} + +func (t PtrToXdpSockRegType) String() string { + return "PTR_TO_XDP_SOCK" +} + +func (t PtrToXdpSockRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + return nil +} + +func (t PtrToXdpSockRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + return !isWrite +} + +type PtrToBtfIdRegType struct { +} + +func (t PtrToBtfIdRegType) String() string { + return "PTR_TO_BTF_ID" +} + +func (t PtrToBtfIdRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + return nil +} + +func (t PtrToBtfIdRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + return true +} + +type PtrToMemRegType struct { +} + +func (t PtrToMemRegType) String() string { + return "PTR_TO_ALLOC_MEM" +} + +func (t PtrToMemRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + return nil +} + +func (t PtrToMemRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + return true +} + +type PtrToRdOnlyBufRegType struct { +} + +func (t PtrToRdOnlyBufRegType) String() string { + return "PTR_TO_RDONLY_BUF" +} + +func (t PtrToRdOnlyBufRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + return nil +} + +func (t PtrToRdOnlyBufRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + return !isWrite +} + +type PtrToRdWrBufRegType struct { +} + +func (t PtrToRdWrBufRegType) String() string { + return "PTR_TO_RDWR_BUF" +} + +func (t PtrToRdWrBufRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + return nil +} + +func (t PtrToRdWrBufRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + return true +} + +type PtrToPercpuBtfIdRegType struct { +} + +func (t PtrToPercpuBtfIdRegType) String() string { + return "PTR_TO_PERCPU_BTF_ID" +} + +func (t PtrToPercpuBtfIdRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + a := NewBpfArg(call.Helper, arg) + s.Externs["bpf_prog_active"] = "int" + a.IsNotNull = true + a.Name = fmt.Sprintf("&bpf_prog_active") + return a +} + +func (t PtrToPercpuBtfIdRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + //XXX not found in check_mem_access + return false +} + +type PtrToFuncRegType struct { +} + +func (t PtrToFuncRegType) String() string { + return "PTR_TO_FUNC" +} + +func (t PtrToFuncRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + return nil +} + +func (t PtrToFuncRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + //XXX not found in check_mem_access + return false +} + +type PtrToMapKeyRegType struct { +} + +func (t PtrToMapKeyRegType) String() string { + return "PTR_TO_MAP_KEY" +} + +func (t PtrToMapKeyRegType) Generate(s *BpfProg, r *randGen, call *BpfCall, arg int) *BpfArg { + return nil +} + +func (t PtrToMapKeyRegType) CheckAccess(s *BpfProg, h *BpfHelperFunc, isWrite bool) bool { + return !isWrite +} + +type BpfCtxAccessAttr struct { + rangeInCtx []string + canRead bool + canWrite bool + size int //exact size check + defaultSize int //for wide/narrow access check + wideAccess bool //wide access check + narrowAccess bool //narrow access check + regType RegType + attachTypes []string +} + +type BpfCtxAccess struct { + regTypeMap map[string][][]string + others map[string]*BpfCtxAccess + accesses []BpfCtxAccessAttr +} + +func NewBpfCtxAccess() *BpfCtxAccess { + newCtxAccess := &BpfCtxAccess{ + regTypeMap: make(map[string][][]string), + others: make(map[string]*BpfCtxAccess), + } + return newCtxAccess +} + +var Brf *BpfRuntimeFuzzer + +func InitBrf(enable bool) { + Brf = NewBpfRuntimeFuzzer(enable) + + Brf.InitFromSrc(HelperFuncMap, ProgTypeMap, CtxAccessMap) +} + +var map_key_value_types = []RegType{ + PtrToStackRegType{}, + PtrToPacketRegType{}, + PtrToPacketMetaRegType{}, + PtrToMapKeyRegType{}, + PtrToMapValueRegType{}, +} + +var scalar_types = []RegType{ScalarValRegType{}} + +var const_map_ptr_types = []RegType{ConstPtrToMapRegType{}} + +var context_types = []RegType{PtrToCtxRegType{}} + +var sock_types = []RegType{ + PtrToSockCommonRegType{}, + PtrToSocketRegType{}, + PtrToTcpSockRegType{}, + PtrToXdpSockRegType{}, +} + +var btf_id_sock_common_types = []RegType{ + PtrToSockCommonRegType{}, + PtrToSocketRegType{}, + PtrToTcpSockRegType{}, + PtrToXdpSockRegType{}, + PtrToBtfIdRegType{}, +} + +var fullsock_types = []RegType{PtrToSocketRegType{}} + +var btf_ptr_types = []RegType{PtrToBtfIdRegType{}} + +var spin_lock_types = []RegType{PtrToMapValueRegType{}} + +var mem_types = []RegType{ + PtrToStackRegType{}, + PtrToPacketRegType{}, + PtrToPacketMetaRegType{}, + PtrToMapKeyRegType{}, + PtrToMapValueRegType{}, + PtrToMemRegType{}, + PtrToRdOnlyBufRegType{}, + PtrToRdWrBufRegType{}, +} + +var alloc_mem_types = []RegType{PtrToMemRegType{}} + +var int_ptr_types = []RegType{ + PtrToStackRegType{}, + PtrToPacketRegType{}, + PtrToPacketMetaRegType{}, + PtrToMapKeyRegType{}, + PtrToMapValueRegType{}, +} + +var percpu_btf_ptr_types = []RegType{PtrToPercpuBtfIdRegType{}} + +var func_ptr_types = []RegType{PtrToFuncRegType{}} + +var stack_ptr_types = []RegType{PtrToStackRegType{}} + +var const_str_ptr_types = []RegType{PtrToMapValueRegType{}} + +var timer_types = []RegType{PtrToMapValueRegType{}} + +var all_types = []RegType{ + ScalarValRegType{}, + PtrToCtxRegType{}, + ConstPtrToMapRegType{}, + PtrToMapValueRegType{}, + PtrToStackRegType{}, + PtrToPacketMetaRegType{}, + PtrToPacketRegType{}, + PtrToPacketEndRegType{}, + PtrToFlowKeysRegType{}, + PtrToSocketRegType{}, + PtrToSockCommonRegType{}, + PtrToTcpSockRegType{}, + PtrToTpBufferRegType{}, + PtrToXdpSockRegType{}, + PtrToBtfIdRegType{}, + PtrToMemRegType{}, + PtrToRdOnlyBufRegType{}, + PtrToRdWrBufRegType{}, + PtrToPercpuBtfIdRegType{}, + PtrToFuncRegType{}, + PtrToMapKeyRegType{}, +} + +var compatibleRegType = map[string][]RegType { + "ARG_ANYTHING": all_types, + "ARG_PTR_TO_MAP_KEY": map_key_value_types, + "ARG_PTR_TO_MAP_VALUE": map_key_value_types, + "ARG_PTR_TO_UNINIT_MAP_VALUE": map_key_value_types, + "ARG_PTR_TO_MAP_VALUE_OR_NULL": map_key_value_types, + "ARG_CONST_SIZE": scalar_types, + "ARG_CONST_SIZE_OR_ZERO": scalar_types, + "ARG_CONST_ALLOC_SIZE_OR_ZERO": scalar_types, + "ARG_CONST_MAP_PTR": const_map_ptr_types, + "ARG_PTR_TO_CTX": context_types, + "ARG_PTR_TO_CTX_OR_NULL": context_types, + "ARG_PTR_TO_SOCK_COMMON": sock_types, + "ARG_PTR_TO_BTF_ID_SOCK_COMMON": btf_id_sock_common_types, + "ARG_PTR_TO_SOCKET": fullsock_types, + "ARG_PTR_TO_SOCKET_OR_NULL": fullsock_types, + "ARG_PTR_TO_BTF_ID": btf_ptr_types, + "ARG_PTR_TO_SPIN_LOCK": spin_lock_types, + "ARG_PTR_TO_MEM": mem_types, + "ARG_PTR_TO_MEM_OR_NULL": mem_types, + "ARG_PTR_TO_UNINIT_MEM": mem_types, + "ARG_PTR_TO_ALLOC_MEM": alloc_mem_types, + "ARG_PTR_TO_ALLOC_MEM_OR_NULL": alloc_mem_types, + "ARG_PTR_TO_INT": int_ptr_types, + "ARG_PTR_TO_LONG": int_ptr_types, + "ARG_PTR_TO_PERCPU_BTF_ID": percpu_btf_ptr_types, + "ARG_PTR_TO_FUNC": func_ptr_types, + "ARG_PTR_TO_STACK_OR_NULL": stack_ptr_types, + "ARG_PTR_TO_CONST_STR": const_str_ptr_types, + "ARG_PTR_TO_TIMER": timer_types, +} + +func (sd *StructDef) fieldIdx(f string) int { + fieldName := f + if f[len(f)-1: len(f)] == "]" { + fieldName = f[0:len(f)-3] + } + + for i, name := range sd.FieldNames { + if name == fieldName { + return i + } + } + fmt.Printf("cannot find field %v (%v) in %v\n", f, fieldName, sd.Name) + return -1 +} + +func getCtxAccessAttr(sd *StructDef, accesses []BpfCtxAccessAttr, fieldIdx int, isWrite bool) (BpfCtxAccessAttr, int) { + for _, fi := range accesses { + if len(fi.rangeInCtx) == 1 && sd.fieldIdx(fi.rangeInCtx[0]) == fieldIdx && fi.canWrite == isWrite { + return fi, 1 + } else if len(fi.rangeInCtx) == 2 && sd.fieldIdx(fi.rangeInCtx[0]) <= fieldIdx && sd.fieldIdx(fi.rangeInCtx[1]) >= fieldIdx && fi.canWrite == isWrite { + if fi.rangeInCtx[0] == fi.rangeInCtx[1] { + return fi, 1 + } else { + return fi, 2 + } + } else if fi.rangeInCtx[0] == "default" && fi.canWrite == isWrite { + return fi, 2 + } + } + return BpfCtxAccessAttr{}, -1 +} + +func (brf *BpfRuntimeFuzzer) InitFromSrc(hMap map[string]*BpfHelperFunc, ptMap map[BpfProgTypeEnum]*BpfProgTypeDef, caMap map[BpfProgTypeEnum]*BpfCtxAccess) { + brf.helperFuncMap = hMap + brf.progTypeMap = ptMap + brf.ctxAccessMap = caMap + + for name, pt := range brf.progTypeMap { + availableHelper := make(map[string]bool) + for _, proto := range pt.FuncProtos { + helper := brf.helperFuncMap[proto] + if _, ok := availableHelper[helper.Enum]; !ok { + availableHelper[helper.Enum] = true + pt.Helpers = append(pt.Helpers, helper) + } + } + + var accesses []BpfCtxAccessAttr + pt.ctxAccess = brf.ctxAccessMap[name] + var sd *StructDef + var ctxStructName = pt.User + if len(pt.User) > 6 && pt.User[0:6] == "struct" { + sd = ctxStructsMap[pt.User[7:len(pt.User)]] + ctxStructName = pt.User[7:len(pt.User)] + } + if ctxStruct, ok := ctxStructsMap[ctxStructName]; ok { + for i, fi := range ctxStruct.FieldNames { + if readAccess, res := getCtxAccessAttr(sd, pt.ctxAccess.accesses, i, false); res != -1 { + if res == 2 { + readAccess.rangeInCtx = []string{fi, fi} + } + accesses = append(accesses, readAccess) + } else { + accesses = append(accesses, BpfCtxAccessAttr{rangeInCtx: []string{fi, fi}}) + } + if writeAccess, res := getCtxAccessAttr(sd, pt.ctxAccess.accesses, i, true); res != -1 { + if res == 2 { + writeAccess.rangeInCtx = []string{fi, fi} + } + accesses = append(accesses, writeAccess) + } else { + accesses = append(accesses, BpfCtxAccessAttr{rangeInCtx: []string{fi, fi}}) + } + } + pt.ctxAccess.accesses = accesses + } + } +} + +//func (brf *BpfRuntimeFuzzer) ProgTypeEnumToString(pv int) string { +// pe := "" +// var pt *BpfProgTypeDef +// for _, pt = range brf.progTypeMap { +// if pt.Num == pv { +// pe = pt.Enum +// break; +// } +// } +// return pe +//} + +//func (brf *BpfRuntimeFuzzer) HelperEnumToString(pv int, hv int) string { +// var pt *BpfProgTypeDef +// for _, pt = range brf.progTypeMap { +// if pt.Num == pv { +// break; +// } +// } +// +// if pt == nil { +// return "" +// } +// +// he := "" +// for _, helper := range pt.Helpers { +// if helper.Num == hv { +// he = helper.Enum +// } +// } +// return he +//} + +func (brf *BpfRuntimeFuzzer) MapTypeEnumToString(mv int) string { + me := "" + if mv > 0 && mv <= len(bpfMapTypes) { + me = bpfMapTypes[mv-1].Type + } + return me +} + +func findMember(s *BpfProg, structType string, memberType string) int { + for _, sd := range s.Structs { + if sd.Name == structType { + return sd.findMember(memberType) + } + } + return -1 +} + +//XXX record fail prog:func pair +func (s *BpfProg) genBpfHelperCallArg(r *randGen, call *BpfCall, arg int) bool { + argType := call.Helper.Args[arg] + fmt.Printf("(%v) gen call[%v] arg[%v]=%v (%v)\n", rd, len(s.Calls), arg, argType, call.Helper.Enum) + + var a *BpfArg + ok := false + if !ok && call.Helper.Enum == "BPF_FUNC_get_local_storage" && arg == 1 {//6311 + a = NewBpfArg(call.Helper, arg) + a.Name = "0" + a.IsNotNull = true + ok = true + } + if !ok && r.nOutOf(1, 3) { + fmt.Printf("(%v) gen arg using helper return value\n", rd) + a, ok = s.genRandBpfHelperCall(r, call, arg) + } + if !ok && r.nOutOf(1, 2) { + fmt.Printf("(%v) gen arg using ctx access\n", rd) + a, ok = s.genRandBpfCtxAccess(r, call, arg) + } + if !ok { + fmt.Printf("(%v) gen arg directly\n", rd) + a, ok = s.genRandDirectAccess(r, call, arg) + } + if !ok { + return false + } + fmt.Printf("(%v) gen arg v%v\n", r, ok, s.VarId) + + if argType == "ARG_CONST_SIZE" || argType == "ARG_CONST_SIZE_OR_ZERO" { + a.Umax = int64(call.StackVarSize) //XXX check if this handle multiple mem size pairs + } + + // Adding a predicate other than the referenced object can produce paths that may leak references + // XXX Is it possible to achieve so without leaking ref? + if call.isRefReleaseCall() != -1 && arg != 0 { + //if a.IsNotNull && a.CanBeNull { + if !a.IsNotNull && !a.CanBeNull { + return false + } + } + + call.Args[arg] = a + return true +} + +//XXX add mem size constraints +func (s *BpfProg) genCompatibleRegTypes(call *BpfCall, arg int) ([]RegType, string) { + argType := call.Helper.Args[arg] + regTypes := compatibleRegType[argType] + if argType == "ARG_PTR_TO_UNINIT_MAP_VALUE" || argType == "ARG_PTR_TO_UNINIT_MEM" { + for i, t := range regTypes { + if !t.CheckAccess(s, call.Helper, true) { + regTypes = append(regTypes[0:i], regTypes[i+1:]...) + } + } + } + if !checkPktAccess(s, call.Helper, false) { //verbose_5053 + for i, t := range regTypes { + if t.String() == "PTR_TO_PACKET" || t.String() == "PTR_TO_PACKET_META" { + regTypes = append(regTypes[0:i], regTypes[i+1:]...) + } + } + } + + btfId := "" + if argType == "ARG_PTR_TO_BTF_ID" { + btfId = call.Helper.ArgBtfIds[0] //XXX helpers have only one at most now + } else if argType == "ARG_PTR_TO_BTF_ID_SOCK_COMMON" { + btfId = "struct sock_common" + } + return regTypes, btfId +} + +func (s *BpfProg) genRandDirectAccess(r *randGen, call *BpfCall, arg int) (*BpfArg, bool) { + compatRegTypes, _ := s.genCompatibleRegTypes(call, arg) + for i := 0; i < 5; i++ { + rt := compatRegTypes[r.Intn(len(compatRegTypes))] + a := rt.Generate(s, r, call, arg) + if a != nil { + fmt.Printf("(%v) gen arg using %v directly\n", rd, rt.String()) + return a, true + } + } + return nil, false +} + +func (s *BpfProg) genRandBpfCtxAccess(r *randGen, call *BpfCall, arg int) (*BpfArg, bool) { + compatRegTypes, _ := s.genCompatibleRegTypes(call, arg) + for i := 0; i < 5; i++ { + a := NewBpfArg(call.Helper, arg) + rt := compatRegTypes[r.Intn(len(compatRegTypes))].String() + ranges, ok := s.pt.ctxAccess.regTypeMap[rt] + if !ok { + ranges, ok = s.pt.ctxAccess.regTypeMap[rt+"_OR_NULL"]//XXX improve arg OR_NULL compatibility check/propagation + } + + if !ok { + continue + } + + var ctxStruct *StructDef + if len(s.pt.User) > 6 && s.pt.User[0:6] == "struct" { + ctxStruct = ctxStructsMap[s.pt.User[7:len(s.pt.User)]] + readAccess := s.pt.ctxAccess.accesses[ctxStruct.fieldIdx(ranges[0][2])*2].canRead + writeAccess := s.pt.ctxAccess.accesses[ctxStruct.fieldIdx(ranges[0][2])*2+1].canWrite + if !readAccess && !writeAccess { + continue + } + } else { + var defaultAccess BpfCtxAccessAttr + for _, access := range s.pt.ctxAccess.accesses { + if access.rangeInCtx[0] == "default" { + defaultAccess = access + } + } + if !defaultAccess.canRead && !defaultAccess.canWrite { + continue + } + } + + typ := "void *" + if rt == "PTR_TO_SOCK_COMMON" { + typ = "struct sock_common*" + } + + field := ranges[0][2] + if v, ok := s.CtxVars[field]; ok { + a.Name = v + } else { + a.Name = fmt.Sprintf("v%d", s.VarId) + s.VarId += 1 + s.CtxVars[field] = a.Name + s.CtxTypes[field] = typ + } + if rt == "PTR_TO_PACKET_META" { + if _, ok := s.CtxVars["data"]; !ok { + a1 := fmt.Sprintf("v%d", s.VarId) + s.VarId += 1 + s.CtxVars["data"] = a1 + s.CtxTypes["data"] = typ + } + argType := call.Helper.Args[arg] + a.IsPktMetaAccess = true + if argType == "ARG_PTR_TO_MAP_KEY" { + if call.ArgMap != nil && call.ArgMap.Key != nil { + //a.AccessSize = call.ArgMap.Key.Size + a.AccessSize = roundUp(call.ArgMap.Key.Size, 8) //XXX need to round up key size? + } + } + if argType == "ARG_PTR_TO_MAP_VALUE" || argType == "ARG_PTR_TO_MAP_VALUE_OR_NULL" || argType == "ARG_PTR_TO_UNINIT_MAP_VALUE" { + if call.ArgMap != nil && call.ArgMap.Val != nil { + //a.AccessSize = call.ArgMap.Val.Size + a.AccessSize = roundUp(call.ArgMap.Val.Size, 8) + } + } + if argType == "ARG_PTR_TO_MEM" || argType == "ARG_PTR_TO_MEM_OR_NULL" || argType == "ARG_PTR_TO_UNINIT_MEM" { + size := r.Intn(128)//XXX determine max + a.AccessSize = size + call.StackVarSize = size + } + if argType == "ARG_PTR_TO_INT" { + a.AccessSize = 4 + } + if argType == "ARG_PTR_TO_LONG" { + a.AccessSize = 8 + } +// a.AccessSize = call.Hint.RetAccessSize + } + if rt == "PTR_TO_PACKET" { + if _, ok := s.CtxVars["data_end"]; !ok { + a1 := fmt.Sprintf("v%d", s.VarId) + s.VarId += 1 + s.CtxVars["data_end"] = a1 + s.CtxTypes["data_end"] = typ + } + argType := call.Helper.Args[arg] + a.IsPktAccess = true + if argType == "ARG_PTR_TO_MAP_KEY" { + if call.ArgMap != nil && call.ArgMap.Key != nil { + //a.AccessSize = call.ArgMap.Key.Size + a.AccessSize = roundUp(call.ArgMap.Key.Size, 8) //XXX need to round up key size? + } + } + if argType == "ARG_PTR_TO_MAP_VALUE" || argType == "ARG_PTR_TO_MAP_VALUE_OR_NULL" || argType == "ARG_PTR_TO_UNINIT_MAP_VALUE" { + if call.ArgMap != nil && call.ArgMap.Val != nil { + //a.AccessSize = call.ArgMap.Val.Size + a.AccessSize = roundUp(call.ArgMap.Val.Size, 8) + } + } + if argType == "ARG_PTR_TO_MEM" || argType == "ARG_PTR_TO_MEM_OR_NULL" || argType == "ARG_PTR_TO_UNINIT_MEM" { + size := r.Intn(128)//XXX determine max + a.AccessSize = size + call.StackVarSize = size + } + if argType == "ARG_PTR_TO_INT" { + a.AccessSize = 4 + } + if argType == "ARG_PTR_TO_LONG" { + a.AccessSize = 8 + } +// a.AccessSize = call.Hint.RetAccessSize + } + return a, true + } + return nil, false +} + + +//RET_INTEGER, /* function returns integer */ +//RET_VOID, /* function doesn't return anything */ +//RET_PTR_TO_MAP_VALUE, /* returns a pointer to map elem value */ +//RET_PTR_TO_MAP_VALUE_OR_NULL, /* returns a pointer to map elem value or NULL */ +//RET_PTR_TO_SOCKET_OR_NULL, /* returns a pointer to a socket or NULL */ +//RET_PTR_TO_TCP_SOCK_OR_NULL, /* returns a pointer to a tcp_sock or NULL */ +//RET_PTR_TO_SOCK_COMMON_OR_NULL, /* returns a pointer to a sock_common or NULL */ +//RET_PTR_TO_ALLOC_MEM_OR_NULL, /* returns a pointer to dynamically allocated memory or NULL */ +//RET_PTR_TO_BTF_ID_OR_NULL, /* returns a pointer to a btf_id or NULL */ +//RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL, /* returns a pointer to a valid memory or a btf_id or NULL */ +//RET_PTR_TO_MEM_OR_BTF_ID, /* returns a pointer to a valid memory or a btf_id */ +//RET_PTR_TO_BTF_ID, /* returns a pointer to a btf_id */ +func bpfRetType(call *BpfCall) string { + if call.Helper.Ret == "RET_INTEGER" { + return "uint64_t" + } else if call.Helper.Ret == "RET_PTR_TO_MAP_VALUE" || + call.Helper.Ret == "RET_PTR_TO_MAP_VALUE_OR_NULL" { + if call.ArgMap.Val == nil { + return "void *" + } else { + return fmt.Sprintf("%v*", call.ArgMap.Val.Name) + } + } else if call.Helper.Ret == "RET_PTR_TO_BTF_ID_OR_NULL" || + call.Helper.Ret == "RET_PTR_TO_BTF_ID" { + return fmt.Sprintf("%v*", call.Helper.RetBtfId) + } else if call.Helper.Ret == "RET_PTR_TO_ALLOC_MEM_OR_NULL" || + call.Helper.Ret == "RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL" || + call.Helper.Ret == "RET_PTR_TO_MEM_OR_BTF_ID" { + return "void *" + } else if call.Helper.Ret == "RET_PTR_TO_TCP_SOCK_OR_NULL" || + call.Helper.Ret == "RET_PTR_TO_SOCKET_OR_NULL" || + call.Helper.Ret == "RET_PTR_TO_SOCK_COMMON_OR_NULL" { + return "struct bpf_sock*" + } else { + return "" + } +} + +// recursion depth of genBpfHelperCall +var rd int + +func (s *BpfProg) getBpfHelpers(enums []string) ([]*BpfHelperFunc) { + var helpers []*BpfHelperFunc + for _, helper := range s.pt.Helpers { + for _, enum := range enums { + if helper.Enum == enum { + helpers = append(helpers, helper) + } + } + } + return helpers +} + +func (s *BpfProg) genBpfHelperCall(r *randGen, helper *BpfHelperFunc, hint *BpfCallGenHint, prepend bool) (*BpfCall, bool) { + rd += 1 + if rd > 100 { + fmt.Printf("(%v) failed to gen helper call. Tried generating helper call resursively too hard\n", rd) + return nil, false + } + + preferredMapName := "nil" + if hint.PreferredMap != nil { + preferredMapName = hint.PreferredMap.MapName + } + fmt.Printf("(%v) gen call[%v] hint: ArgHints=%v, RetAccessSize=%v, IsRetAccessRaw=%v, PreferredMap=%v\n", + rd, len(s.Calls), hint.ArgHints, hint.RetAccessSize, hint.IsRetAccessRaw, preferredMapName) + + call := NewBpfCall(helper, hint) + attempt := 0 + for i := 0; i < len(helper.Args); { + fmt.Printf("(%v) attempt=%v\n", rd, attempt) + if s.genBpfHelperCallArg(r, call, i) { + attempt = 0 + i++ + } else if attempt += 1; attempt > 50 { + fmt.Printf("failed to gen arg[%d] for %v\n", i , helper.Enum) + return nil, false + } + } + + // Do not acquire references if the program has no helper to release them + if call.isRefAcquireCall() == 1 && len(s.getBpfHelpers([]string{"BPF_FUNC_sk_release"})) == 0 { + return nil, false + } + + if typ := bpfRetType(call); typ != "" { + call.RetType = typ + } + call.Ret = fmt.Sprintf("v%v", s.VarId) + s.VarId += 1 + if prepend { + s.Calls = append([]*BpfCall{call}, s.Calls...) + } else { + s.Calls = append(s.Calls, call) + } + rd -= 1 + + return call, true +} + +var retToRegTypeMap = map[string]map[string]bool{ + "RET_INTEGER": map[string]bool{"SCALAR_VALUE": true}, + "RET_VOID": map[string]bool{"NOT_INIT": true}, + "RET_PTR_TO_MAP_VALUE": map[string]bool{"PTR_TO_MAP_VALUE": true}, +// "RET_PTR_TO_MAP_VALUE_OR_NULL": map[string]bool{"PTR_TO_MAP_VALUE": true}, + "RET_PTR_TO_MAP_VALUE_OR_NULL": map[string]bool{"PTR_TO_MAP_VALUE": true, "PTR_TO_XDP_SOCK": true, "PTR_TO_SOCKET": true}, + "RET_PTR_TO_SOCKET_OR_NULL": map[string]bool{"PTR_TO_SOCKET": true}, + "RET_PTR_TO_TCP_SOCK_OR_NULL": map[string]bool{"PTR_TO_TCP_SOCK": true}, + "RET_PTR_TO_SOCK_COMMON_OR_NULL": map[string]bool{"PTR_TO_SOCK_COMMON": true}, + "RET_PTR_TO_ALLOC_MEM_OR_NULL": map[string]bool{"PTR_TO_ALLOC_MEM": true}, + "RET_PTR_TO_BTF_ID_OR_NULL": map[string]bool{"PTR_TO_BTF_ID": true}, + "RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL": map[string]bool{"PTR_TO_MEM": true, "PTR_TO_BTF_ID":true}, + "RET_PTR_TO_MEM_OR_BTF_ID": map[string]bool{"PTR_TO_MEM": true, "PTR_TO_BTF_ID":true}, + "RET_PTR_TO_BTF_ID": map[string]bool{"PTR_TO_BTF_ID": true}, +} + +func helperCanReturn(helper *BpfHelperFunc, reg RegType, btfId string) bool { + if retToRegTypeMap[helper.Ret][reg.String()] { + if btfId != "" { + if helper.Ret == "RET_PTR_TO_BTF_ID_OR_NULL" || helper.Ret == "RET_PTR_TO_BTF_ID" { + return btfId == helper.RetBtfId + } + if helper.Ret == "RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL" || helper.Ret == "RET_PTR_TO_MEM_OR_BTF_ID" { + //XXX gen random ksym + return false + } + } + return true + } + return false +} + +func genHint(r *randGen, producer *BpfHelperFunc, consumer *BpfCall, arg int) *BpfCallGenHint { + hint := newBpfCallGenHint(nil) + consumerArg := consumer.Helper.Args[arg] + + if (consumerArg == "ARG_PTR_TO_SOCK_COMMON" || consumerArg == "ARG_PTR_TO_BTF_ID_SOCK_COMMON") { + if producer.Ret == "RET_PTR_TO_MAP_VALUE_OR_NULL" { + if r.nOutOf(1, 2) { + hint.ArgHints[HintGenXdpSockMap] = true + } else { + hint.ArgHints[HintGenSockMap] = true + } + } + } + if (consumerArg == "ARG_PTR_TO_SOCKET" || consumerArg == "ARG_PTR_TO_SOCKET_OR_NULL") { + if producer.Ret == "RET_PTR_TO_MAP_VALUE_OR_NULL" { + hint.ArgHints[HintGenSockMap] = true + } + } + if consumerArg == "ARG_PTR_TO_SPIN_LOCK" { + hint.ArgHints[HintGenSpinlock] = true + } + if consumerArg == "ARG_PTR_TO_TIMER" { + hint.ArgHints[HintGenTimer] = true + } + if consumerArg == "ARG_PTR_TO_CONST_STR" { + hint.ArgHints[HintGenConstStr] = true + } + + if consumerArg == "ARG_PTR_TO_MAP_KEY" { + if consumer.ArgMap != nil && consumer.ArgMap.Key != nil { + hint.RetAccessSize = roundUp(consumer.ArgMap.Key.Size, 8) + //hint.RetAccessSize = consumer.ArgMap.Key.Size + } + } + if consumerArg == "ARG_PTR_TO_MAP_VALUE" || consumerArg == "ARG_PTR_TO_MAP_VALUE_OR_NULL" || consumerArg == "ARG_PTR_TO_UNINIT_MAP_VALUE" { + if consumer.ArgMap != nil && consumer.ArgMap.Val != nil { + hint.RetAccessSize = roundUp(consumer.ArgMap.Val.Size, 8) + //hint.RetAccessSize = consumer.ArgMap.Val.Size + } + } + + if consumerArg == "ARG_PTR_TO_UNINIT_MAP_VALUE" || consumerArg == "ARG_PTR_TO_UNINIT_MEM" { + hint.IsRetAccessRaw = true + } + + return hint +} + +/* Generate a random helper call that returns values compatible with *arg*-th argument of *call* */ +func (s *BpfProg) genRandBpfHelperCall(r *randGen, call *BpfCall, arg int) (*BpfArg, bool) { + a := NewBpfArg(call.Helper, arg) + var compatHelpers []*BpfHelperFunc + compatRegTypes, btfId := s.genCompatibleRegTypes(call, arg) + for _, helper := range s.pt.Helpers { + for _, regType := range compatRegTypes { + if !helperCanReturn(helper, regType, btfId) { + continue + } + if call.Helper.Args[arg] == "ARG_CONST_ALLOC_SIZE_OR_ZERO" && regType.String() == "SCALAR_VALUE" { //5228 + continue + } + compatHelpers = append(compatHelpers, helper) + fmt.Printf("(%v) compatible helper: %v\n", rd, helper.Enum) + } + } + + if len(compatHelpers) == 0 { + return nil, false + } + + helper := compatHelpers[r.Intn(len(compatHelpers))] + hint := genHint(r, helper, call, arg) + prodCall, ok := s.genBpfHelperCall(r, helper, hint, false) + if ok { + argType := call.Helper.Args[arg] + retStruct := "" + if start := strings.Index(prodCall.RetType, "struct_"); start != -1 { + if end := strings.Index(prodCall.RetType, "*"); end != -1 { + retStruct = prodCall.RetType[start:end] + } + } + if argType == "ARG_PTR_TO_SPIN_LOCK" { + mi := findMember(s, retStruct, "struct bpf_spin_lock") + a.Name = fmt.Sprintf("&%v->e%v", prodCall.Ret, mi) + } else if argType == "ARG_PTR_TO_TIMER" { + call.ArgMap = prodCall.ArgMap + mi := findMember(s, retStruct, "struct bpf_timer") + a.Name = fmt.Sprintf("&%v->e%v", prodCall.Ret, mi) + } else if argType == "ARG_PTR_TO_CONST_STR" { + mi := findMember(s, retStruct, "char [8]") + a.Name = fmt.Sprintf("%v->e%v", prodCall.Ret, mi) + } else if (prodCall.Helper.Ret == "RET_PTR_TO_MAP_VALUE" || prodCall.Helper.Ret == "RET_PTR_TO_MAP_VALUE_OR_NULL") && + prodCall.ArgMap.Val != nil && len(prodCall.ArgMap.Val.FieldTypes) >= 2 { + var members []int + for mi, mt := range prodCall.ArgMap.Val.FieldTypes { + if mt != "struct bpf_spin_lock" && mt != "struct bpf_timer" && + (prodCall.ArgMap.Val.Size - prodCall.ArgMap.Val.offsetOfMember(mi) >= prodCall.Hint.RetAccessSize) { + members = append(members, mi) + } + } + if len(members) == 0 { + fmt.Printf("(%v) failed to find a valid offset in %v\n", rd, prodCall.ArgMap.MapName) + ok = false + } else { + a.Name = fmt.Sprintf("&%v->e%v", prodCall.Ret, members[r.Intn(len(members))]) + a.CanBeNull = false //XXX add this in case it is passed to ANYTHING + } + } else { + a.Name = prodCall.Ret + } + + if ok { + if prodCall.Helper.Ret == "RET_INTEGER" || prodCall.Helper.Ret == "RET_VOID" || + prodCall.Helper.Ret == "RET_PTR_TO_MAP_VALUE" || + prodCall.Helper.Ret == "RET_PTR_TO_MEM_OR_BTF_ID" || + prodCall.Helper.Ret == "RET_PTR_TO_BTF_ID" { + if !a.CanBeNull { + a.IsNotNull = true + } + } + + //3149, 3155 + if prodCall.Helper.Ret == "RET_PTR_TO_MAP_VALUE" || prodCall.Helper.Ret == "RET_PTR_TO_MAP_VALUE_OR_NULL" { + if argType == "ARG_PTR_TO_UNINIT_MAP_VALUE" || argType == "ARG_PTR_TO_UNINIT_MEM" { + prodCall.ArgMap.removeFlag("BPF_F_RDONLY_PROG") + } else { + prodCall.ArgMap.removeFlag("BPF_F_WRONLY_PROG") + } + } + } + } + return a, ok +} + +func (brf *BpfRuntimeFuzzer) GenBpfProg(r *randGen, opt BrfGenProgOpt) (*BpfProg, bool) { + pt := brf.progTypeMap[BpfProgTypeEnum(r.Intn(int(BPF_PROG_TYPE_TRACING))+1)] + helper := pt.Helpers[r.Intn(len(pt.Helpers))] + p := NewBpfProg(pt, r, opt) + + fmt.Printf("gen prog %v %v\n", pt.Name, helper.Enum) + rd = 0 + hint := newBpfCallGenHint(nil) + _, ok := p.genBpfHelperCall(r, helper, hint, false) + return p, ok +} + +func (brf *BpfRuntimeFuzzer) MutBpfProg(r *randGen, s *BpfProg, opt BrfGenProgOpt) bool { + var calls []*BpfCall + for _, c := range s.Calls { + if len(c.Args) > 0 { + calls = append(calls, c) + } + } + + if len(calls) == 0 { + return false + } + + call := calls[r.Intn(len(calls))] + arg := r.Intn(len(call.Args)) + return s.genBpfHelperCallArg(r, call, arg) +} + +type ObjRef struct { + vars []string + objMap *BpfMap + typ int + count int + calls []*BpfCall +} + +func (call *BpfCall) isRefAcquireCall() int { + refType := -1 + if call.Helper.Enum == "BPF_FUNC_sk_lookup_tcp" || call.Helper.Enum == "BPF_FUNC_sk_lookup_udp" || call.Helper.Enum == "BPF_FUNC_skc_lookup_tcp" || + (call.Helper.Enum == "BPF_FUNC_map_lookup_elem" && (call.ArgMap.MapType == "BPF_MAP_TYPE_SOCKMAP" || call.ArgMap.MapType == "BPF_MAP_TYPE_SOCKHASH")) { + refType = 1 + } + if call.Helper.Enum == "BPF_FUNC_ringbuf_reserve" { + refType = 2 + } + return refType +} + +func (call *BpfCall) isRefReleaseCall() int { + refType := -1 + if call.Helper.Enum == "BPF_FUNC_sk_release" { + refType = 1 + } + if call.Helper.Enum == "BPF_FUNC_ringbuf_submit" || call.Helper.Enum == "BPF_FUNC_ringbuf_discard" { + refType = 2 + } + return refType +} + +func (call *BpfCall) isRefPropagateCall() int { + refType := -1 + if call.Helper.Enum == "BPF_FUNC_tcp_sock" || call.Helper.Enum == "BPF_FUNC_sk_fullsock" || + call.Helper.Enum == "BPF_FUNC_skc_to_tcp_sock" || call.Helper.Enum == "BPF_FUNC_skc_to_tcp6_sock" || + call.Helper.Enum == "BPF_FUNC_skc_to_udp6_sock" || call.Helper.Enum == "BPF_FUNC_skc_to_tcp_timewait_sock" || + call.Helper.Enum == "BPF_FUNC_skc_to_tcp_request_sock" { + refType = 1 + } + return refType +} + +func (s *BpfProg) FixRef(r *randGen) { + objRefMap := make(map[string]*ObjRef) + for i, call := range s.Calls { + if refType := call.isRefAcquireCall(); refType != -1 { + v := call.Ret + if _, ok := objRefMap[v]; !ok { + objRefMap[v] = &ObjRef{vars: []string{v}, objMap: call.ArgMap, typ: refType, count: 0, calls: []*BpfCall{call}} + } + objRefMap[v].count += 1 + fmt.Printf("ref(%v:%v) acquired by call #%v %v\n", v, objRefMap[v].count, i, call.Helper.Enum) + } + if refType := call.isRefReleaseCall(); refType != -1 { + v := call.Args[0].Name + if _, ok := objRefMap[v]; !ok { + objRefMap[v] = &ObjRef{vars: []string{v}, objMap: call.ArgMap, typ: refType, count: 0, calls: []*BpfCall{call}} + } + objRefMap[v].count -= 1 + fmt.Printf("ref(%v:%v) released by call #%v %v\n", v, objRefMap[v].count, i, call.Helper.Enum) + } + if refType := call.isRefPropagateCall(); refType != -1 { + v := call.Args[0].Name + vp := call.Ret + if ref, ok := objRefMap[v]; ok { + ref.calls = append(ref.calls, call) + ref.vars = append(ref.vars, vp) + objRefMap[vp] = ref + fmt.Printf("ref(%v:%v) propagated by call #%v %v\n", v, objRefMap[v].count, i, call.Helper.Enum) + } else { + fmt.Printf("ref(%v:0) propagated by call #%v %v\n", v, i, call.Helper.Enum) + } + } + } + + for _, ref := range objRefMap { + if ref.count < 0 { + // Add a ref-acquire helper + if ref.typ == 1 { + helpers := s.getBpfHelpers([]string{"BPF_FUNC_sk_lookup_tcp", "BPF_FUNC_sk_lookup_udp", "BPF_FUNC_skc_lookup_tcp", "BPF_FUNC_map_lookup_elem"}) + if len(helpers) > 0 { + helper := helpers[r.Intn(len(helpers))] + hint := newBpfCallGenHint(ref.objMap) + if prodCall, ok := s.genBpfHelperCall(r, helper, hint, true); ok {//XXX change to ENUM append, prepend, random + ref.calls[0].Args[0].Name = prodCall.Ret + fmt.Printf("ref: fix releasing invalid ref(%v:%v) by adding %v\n", ref.vars[0], ref.count, helper.Enum) + } else { + fmt.Printf("ref: fix releasing invalid ref(%v:%v) failed since no helper can acquire the reference\n", ref.vars[0], ref.count) + } + } + } + if ref.typ == 2 { + helpers := s.getBpfHelpers([]string{"BPF_FUNC_ringbuf_reserve"}) + if len(helpers) > 0 { + helper := helpers[r.Intn(len(helpers))] + hint := newBpfCallGenHint(ref.objMap) + if prodCall, ok := s.genBpfHelperCall(r, helper, hint, true); ok { + ref.calls[0].Args[0].Name = prodCall.Ret + fmt.Printf("ref: fix releasing invalid ref(%v:%v) by adding %v\n", ref.vars[0], ref.count, helper.Enum) + } else { + fmt.Printf("ref: fix releasing invalid ref(%v:%v) failed since no helper can acquire the reference\n", ref.vars[0], ref.count) + } + } + } + } + if ref.count > 0 { + // Add a ref-release helper + if ref.typ == 1 { + helpers := s.getBpfHelpers([]string{"BPF_FUNC_sk_release"}) + if len(helpers) > 0 { + helper := helpers[r.Intn(len(helpers))] + hint := newBpfCallGenHint(ref.objMap) + //s.genBpfHelperCall(r, h, hint, false) + call := NewBpfCall(helper, hint) + a0 := NewBpfArg(helper, 0) + a0.Name = ref.vars[r.Intn(len(ref.vars))] + call.Args[0] = a0 + ref.calls[0].PostCalls = append(ref.calls[0].PostCalls, call) + //s.Calls = append(s.Calls, call) + ref.count = 0 + fmt.Printf("ref: fixing leaking ref(%v:%v) by adding %v\n", ref.vars[0], ref.count, helper.Enum) + } else { + fmt.Printf("ref: fixing leaking ref(%v:%v) failed since no helper can release the reference\n", ref.vars[0], ref.count) + } + } + if ref.typ == 2 { + helpers := s.getBpfHelpers([]string{"BPF_FUNC_ringbuf_submit", "BPF_FUNC_ringbuf_discard"}) + if len(helpers) > 0 { + helper := helpers[r.Intn(len(helpers))] + hint := newBpfCallGenHint(ref.objMap) + //s.genBpfHelperCall(r, h, hint, false) + call := NewBpfCall(helper, hint) + a0 := NewBpfArg(helper, 0) + a0.Name = ref.vars[r.Intn(len(ref.vars))] + call.Args[0] = a0 + a1 := NewBpfArg(helper, 1) + a1.Name = "0" + a1.IsNotNull = true + call.Args[1] = a1 + s.Calls = append(s.Calls, call) + ref.count = 0 + fmt.Printf("ref: fixing leaking ref(%v:%v) by adding %v\n", ref.vars[0], ref.count, helper.Enum) + } else { + fmt.Printf("ref: fixing leaking ref(%v:%v) failed since no helper can release the reference\n", ref.vars[0], ref.count) + } + } + } + } +} + +func (s *BpfProg) FixSpinLock(r *randGen) { + lockHeld := "" + for i, call := range s.Calls { + if call.Helper.Enum == "BPF_FUNC_spin_unlock" { + if lockHeld == "" { + if helper := s.pt.getHelper("BPF_FUNC_spin_lock"); helper != nil { + hint := newBpfCallGenHint(nil) + call := NewBpfCall(helper, hint) + a0 := NewBpfArg(helper, 0) + a0.Name = s.Calls[i].Args[0].Name + call.Args[0] = a0 + lockHeld = a0.Name + s.Calls = append(s.Calls[:i+1], s.Calls[i:]...) + s.Calls[i] = call + } else { + fmt.Printf("spinlock: fixing spinlock failed since no helper can lock the spinlock\n") + break + } + } else { + if lockHeld == call.Args[0].Name { + lockHeld = "" + } else { + fmt.Printf("spinlock: fixing a mismatch spin_unlock\n") + call.Args[0].Name = lockHeld + } + } + } + if call.Helper.Enum == "BPF_FUNC_spin_lock" { + if i == len(s.Calls)-1 || s.Calls[i+1].Helper.Enum != "BPF_FUNC_spin_unlock" { + if helper := s.pt.getHelper("BPF_FUNC_spin_unlock"); helper != nil { + hint := newBpfCallGenHint(nil) + call := NewBpfCall(helper, hint) + a0 := NewBpfArg(helper, 0) + a0.Name = s.Calls[i].Args[0].Name + call.Args[0] = a0 + lockHeld = a0.Name + s.Calls = append(s.Calls[:i+1], s.Calls[i:]...) + s.Calls[i+1] = call + } else { + fmt.Printf("spinlock: fixing spinlock failed since no helper can unlock the spinlock\n") + break + } + } else { + lockHeld = call.Args[0].Name + } + } + } +} + +//417-program exit +func genRandReturnVal(r *randGen, e BpfProgTypeEnum) int { + retVal := 0 + switch(e) { + case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: + //retVal = r.Intn(4) //(0,3) + retVal = 1 + case BPF_PROG_TYPE_CGROUP_SKB: + //retVal = r.Intn(4) //(0,3) + retVal = r.Intn(2) //(0,1) + case BPF_PROG_TYPE_CGROUP_SOCK: + retVal = r.Intn(2) //(0,1) + case BPF_PROG_TYPE_SOCK_OPS: + retVal = r.Intn(2) //(0,1) + case BPF_PROG_TYPE_CGROUP_DEVICE: + retVal = r.Intn(2) //(0,1) + case BPF_PROG_TYPE_CGROUP_SYSCTL: + retVal = r.Intn(2) //(0,1) + case BPF_PROG_TYPE_CGROUP_SOCKOPT: + retVal = r.Intn(2) //(0,1) + case BPF_PROG_TYPE_RAW_TRACEPOINT: + retVal = 0 + case BPF_PROG_TYPE_TRACING: + retVal = 0 + case BPF_PROG_TYPE_SK_LOOKUP: + retVal = r.Intn(2) //(SK_DROP, SK_PASS) + default: + retVal = r.Intn(1<<32) + } + return retVal +} + +var srcBegin =` +#include "vmlinux.h" +#include + +#define DEFINE_BPF_MAP(the_map, TypeOfMap, MapFlags, TypeOfKey, TypeOfValue, MaxEntries) \ + struct { \ + __uint(type, TypeOfMap); \ + __uint(map_flags, (MapFlags)); \ + __uint(max_entries, (MaxEntries)); \ + __type(key, TypeOfKey); \ + __type(value, TypeOfValue); \ + } the_map SEC(".maps"); + +#define DEFINE_BPF_MAP_IN_MAP(the_map, TypeOfMap, MapFlags, TypeOfKey, TypeOfValue, MaxEntries, innerMap) \ + struct { \ + __uint(type, TypeOfMap); \ + __uint(map_flags, (MapFlags)); \ + __uint(max_entries, (MaxEntries)); \ + __type(key, TypeOfKey); \ + __array(values, typeof(innerMap)); \ + } the_map SEC(".maps") = { .values = {&innerMap}, }; + +#define DEFINE_BPF_MAP_NO_KEY(the_map, TypeOfMap, MapFlags, TypeOfValue, MaxEntries) \ + struct { \ + __uint(type, TypeOfMap); \ + __uint(map_flags, (MapFlags)); \ + __uint(max_entries, (MaxEntries)); \ + __type(value, TypeOfValue); \ + } the_map SEC(".maps"); + +#define DEFINE_BPF_MAP_NO_VAL(the_map, TypeOfMap, MapFlags, TypeOfKey, MaxEntries) \ + struct { \ + __uint(type, TypeOfMap); \ + __uint(map_flags, (MapFlags)); \ + __uint(max_entries, (MaxEntries)); \ + __type(key, TypeOfKey); \ + } the_map SEC(".maps"); + +#define DEFINE_BPF_MAP_NO_KEY_VAL(the_map, TypeOfMap, MapFlags, MaxEntries) \ + struct { \ + __uint(type, TypeOfMap); \ + __uint(map_flags, (MapFlags)); \ + __uint(max_entries, (MaxEntries)); \ + } the_map SEC(".maps"); + +` + +func (p *BpfProg) genCSource() string { + s := new(bytes.Buffer) + s.WriteString(srcBegin) + + for _, t := range p.Structs { + if !t.IsStruct { + continue + } + + fmt.Fprintf(s, "typedef struct %v {\n", t.Name) + for i, m := range t.FieldTypes { + if m == "char [8]" { + fmt.Fprintf(s, " char e%v[8];\n", i) + } else { + fmt.Fprintf(s, " %v e%v;\n", m, i) + } + } + fmt.Fprintf(s, "} %v;\n\n", t.Name) + } + + for v, t := range p.Externs { + fmt.Fprintf(s, "extern const %s %s __ksym;\n\n", t, v) + } + + for _, m := range p.Maps { + if m.Key == nil && m.Val == nil { + fmt.Fprintf(s, "DEFINE_BPF_MAP_NO_KEY_VAL(%s, %s, %s, %d);\n", m.MapName, m.MapType, m.FlagsStr(), m.MaxEntries) + } else if m.Key == nil { + fmt.Fprintf(s, "DEFINE_BPF_MAP_NO_KEY(%s, %s, %s, %s, %d);\n", m.MapName, m.MapType, m.FlagsStr(), m.Val.Name, m.MaxEntries) + } else if m.Val == nil { + fmt.Fprintf(s, "DEFINE_BPF_MAP_NO_VAL(%s, %s, %s, %s, %d);\n", m.MapName, m.MapType, m.FlagsStr(), m.Key.Name, m.MaxEntries) + } else if m.InnerMap == nil { + fmt.Fprintf(s, "DEFINE_BPF_MAP(%s, %s, %s, %s, %s, %d);\n", m.MapName, m.MapType, m.FlagsStr(), m.Key.Name, m.Val.Name, m.MaxEntries) + } else { + fmt.Fprintf(s, "DEFINE_BPF_MAP_IN_MAP(%s, %s, %s, %s, %s, %d, %s);\n", m.MapName, m.MapType, m.FlagsStr(), m.Key.Name, m.Val.Name, m.MaxEntries, m.InnerMap.MapName) + } + } + + fmt.Fprintf(s, "%s", p.SecStr) + fmt.Fprintf(s, "int func(%s *ctx) {\n", p.pt.User) + for field, v := range p.CtxVars { + fmt.Fprintf(s, " %s %s = ctx->%s;\n", p.CtxTypes[field], v, field) + } + for i, call := range p.Calls { + for j, arg := range call.Args { + if arg == nil { + fmt.Printf("debug %v %v %v nil\n", i, call.Helper.Enum, j) + } + if arg.Prepare != "" { + fmt.Fprintf(s, "%s", arg.Prepare) + } + } + if call.RetType != "" { + fmt.Fprintf(s, " %s %s = 0;\n", call.RetType, call.Ret) // XXX see if compiler stop optimize out null check + } + + // Check arguments before calling a helper + indent := "" + constraints := call.getArgConstraints(p) + if len(constraints) != 0 { + fmt.Fprintf(s, " if (") + for i, c := range constraints { + fmt.Fprintf(s, "%v", c) + if i < len(constraints)-1 { + fmt.Fprintf(s, " && ") + } + } + fmt.Fprintf(s, ") {\n") + indent = " " + } + + if call.RetType != "" { + fmt.Fprintf(s, "%s %s = bpf_%s(", indent, call.Ret, call.Helper.Enum[9:]) + } else { + fmt.Fprintf(s, "%s bpf_%s(", indent, call.Helper.Enum[9:]) + } + for i, arg := range call.Args { + fmt.Fprintf(s, "%v", arg.Name) + if i < len(call.Args)-1 { + fmt.Fprintf(s, ", ") + } + } + fmt.Fprintf(s, ");\n") + + for _, pcall := range call.PostCalls { + fmt.Fprintf(s, "%s bpf_%s(", indent, pcall.Helper.Enum[9:]) + for i, arg := range pcall.Args { + fmt.Fprintf(s, "%v", arg.Name) + if i < len(pcall.Args)-1 { + fmt.Fprintf(s, ", ") + } + } + fmt.Fprintf(s, ");\n") + } + + if len(constraints) != 0 { + fmt.Fprintf(s, " }\n") + } + } + + fmt.Fprintf(s, " return %v;\n", p.RetVal) + fmt.Fprintf(s, "}\n\n") + + fmt.Fprintf(s, "char _license[] SEC(\"license\") = \"GPL\";\n") + + fmt.Printf("\n%v\n", s) + + return s.String() +} + diff --git a/prog/brf_prog.go b/prog/brf_prog.go new file mode 100644 index 000000000..f0ec4d57c --- /dev/null +++ b/prog/brf_prog.go @@ -0,0 +1,111 @@ +package prog + +import ( + "encoding/gob" + "fmt" + "os" + "time" +) + +type BpfProg struct { + BasePath string + UseTestSrc bool + + pt *BpfProgTypeDef + TypeEnum BpfProgTypeEnum + VarId int + Maps []*BpfMap + Calls []*BpfCall + Structs []*StructDef + Externs map[string]string + CtxVars map[string]string + CtxTypes map[string]string + RetVal int + SecStr string + Sec SecDef + Path string + AttachOpt BpfAttachOption +} + +type BrfGenProgOpt struct { + genProgAttempt int + useTestSrc bool + basePath string +} + +func newBpfProg(r *randGen, opt BrfGenProgOpt) *BpfProg { + p := &BpfProg {} + + if (opt.useTestSrc) { + p.BasePath = opt.basePath + "/test_prog" + p.UseTestSrc = true + } else { + p.BasePath = fmt.Sprintf("%v/prog_%x", opt.basePath, time.Now().UnixNano()) + } + + return p +} + +func (p *BpfProg) writeCSource() error { + var progSrc string + + if (p.UseTestSrc) { + progSrc = testSrc + } else { + progSrc = p.genCSource() + } + + f, err := os.Create(p.BasePath + ".c") + if err != nil { + return err + } + defer f.Close() + + _, err = f.WriteString(progSrc) + return err +} + +func (p *BpfProg) writeGob() error { + f, err := os.Create(p.BasePath + ".gob") + if err != nil { + return err + } + defer f.Close() + + return gob.NewEncoder(f).Encode(p) +} + +func (p *BpfProg) readGob(path string) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + return gob.NewDecoder(file).Decode(p) +} + + +var testSrc = ` +#include "vmlinux.h" +#include + +#define DEFINE_BPF_MAP(the_map, TypeOfMap, MapFlags, TypeOfKey, TypeOfValue, MaxEntries) \ + struct { \ + __uint(type, TypeOfMap); \ + __uint(map_flags, (MapFlags)); \ + __uint(max_entries, (MaxEntries)); \ + __type(key, TypeOfKey); \ + __type(value, TypeOfValue); \ + } the_map SEC(".maps"); + +DEFINE_BPF_MAP(array_map, BPF_MAP_TYPE_ARRAY, 0, int, int, 1); + +SEC("cgroup_skb/egress") +int func(struct __sk_buff *ctx) +{ + int *value, key = 0; + value = bpf_map_lookup_elem(&array_map, &key); + return 0; +} +` diff --git a/prog/brf_types.go b/prog/brf_types.go new file mode 100644 index 000000000..774f2f6d8 --- /dev/null +++ b/prog/brf_types.go @@ -0,0 +1,1711 @@ +package prog + +var HelperFuncMap = map[string]*BpfHelperFunc{ + "bpf_map_lookup_elem_proto": &BpfHelperFunc{Num: 1, Enum: "BPF_FUNC_map_lookup_elem", Name: "bpf_map_lookup_elem", Proto: "bpf_map_lookup_elem_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_PTR_TO_MAP_KEY"}, Ret: "RET_PTR_TO_MAP_VALUE_OR_NULL", PktAccess: true}, + "bpf_map_update_elem_proto": &BpfHelperFunc{Num: 2, Enum: "BPF_FUNC_map_update_elem", Name: "bpf_map_update_elem", Proto: "bpf_map_update_elem_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_PTR_TO_MAP_KEY", "ARG_PTR_TO_MAP_VALUE", "ARG_ANYTHING"}, Ret: "RET_INTEGER", PktAccess: true}, + "bpf_map_delete_elem_proto": &BpfHelperFunc{Num: 3, Enum: "BPF_FUNC_map_delete_elem", Name: "bpf_map_delete_elem", Proto: "bpf_map_delete_elem_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_PTR_TO_MAP_KEY"}, Ret: "RET_INTEGER", PktAccess: true}, + "bpf_probe_read_compat_proto": &BpfHelperFunc{Num: 4, Enum: "BPF_FUNC_probe_read", Name: "bpf_probe_read_compat", Proto: "bpf_probe_read_compat_proto", Args: []string{"ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE_OR_ZERO", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_ktime_get_ns_proto": &BpfHelperFunc{Num: 5, Enum: "BPF_FUNC_ktime_get_ns", Name: "bpf_ktime_get_ns", Proto: "bpf_ktime_get_ns_proto", Ret: "RET_INTEGER"}, + "bpf_trace_printk_proto": &BpfHelperFunc{Num: 6, Enum: "BPF_FUNC_trace_printk", Name: "bpf_trace_printk", Proto: "bpf_trace_printk_proto", Args: []string{"ARG_PTR_TO_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_get_prandom_u32_proto": &BpfHelperFunc{Num: 7, Enum: "BPF_FUNC_get_prandom_u32", Name: "bpf_get_prandom_u32", Proto: "bpf_get_prandom_u32_proto", Ret: "RET_INTEGER"}, + "bpf_get_smp_processor_id_proto": &BpfHelperFunc{Num: 8, Enum: "BPF_FUNC_get_smp_processor_id", Name: "bpf_get_smp_processor_id", Proto: "bpf_get_smp_processor_id_proto", Ret: "RET_INTEGER"}, + "bpf_get_raw_smp_processor_id_proto": &BpfHelperFunc{Num: 8, Enum: "BPF_FUNC_get_smp_processor_id", Name: "bpf_get_raw_cpu_id", Proto: "bpf_get_raw_smp_processor_id_proto", Ret: "RET_INTEGER"}, + "bpf_skb_store_bytes_proto": &BpfHelperFunc{Num: 9, Enum: "BPF_FUNC_skb_store_bytes", Name: "bpf_skb_store_bytes", Proto: "bpf_skb_store_bytes_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_l3_csum_replace_proto": &BpfHelperFunc{Num: 10, Enum: "BPF_FUNC_l3_csum_replace", Name: "bpf_l3_csum_replace", Proto: "bpf_l3_csum_replace_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_l4_csum_replace_proto": &BpfHelperFunc{Num: 11, Enum: "BPF_FUNC_l4_csum_replace", Name: "bpf_l4_csum_replace", Proto: "bpf_l4_csum_replace_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_tail_call_proto": &BpfHelperFunc{Num: 12, Enum: "BPF_FUNC_tail_call", Name: "NULL", Proto: "bpf_tail_call_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_ANYTHING"}, Ret: "RET_VOID"}, + "bpf_clone_redirect_proto": &BpfHelperFunc{Num: 13, Enum: "BPF_FUNC_clone_redirect", Name: "bpf_clone_redirect", Proto: "bpf_clone_redirect_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_get_current_pid_tgid_proto": &BpfHelperFunc{Num: 14, Enum: "BPF_FUNC_get_current_pid_tgid", Name: "bpf_get_current_pid_tgid", Proto: "bpf_get_current_pid_tgid_proto", Ret: "RET_INTEGER"}, + "bpf_get_current_uid_gid_proto": &BpfHelperFunc{Num: 15, Enum: "BPF_FUNC_get_current_uid_gid", Name: "bpf_get_current_uid_gid", Proto: "bpf_get_current_uid_gid_proto", Ret: "RET_INTEGER"}, + "bpf_get_current_comm_proto": &BpfHelperFunc{Num: 16, Enum: "BPF_FUNC_get_current_comm", Name: "bpf_get_current_comm", Proto: "bpf_get_current_comm_proto", Args: []string{"ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_get_cgroup_classid_proto": &BpfHelperFunc{Num: 17, Enum: "BPF_FUNC_get_cgroup_classid", Name: "bpf_get_cgroup_classid", Proto: "bpf_get_cgroup_classid_proto", Args: []string{"ARG_PTR_TO_CTX"}, Ret: "RET_INTEGER"}, + "bpf_get_cgroup_classid_curr_proto": &BpfHelperFunc{Num: 17, Enum: "BPF_FUNC_get_cgroup_classid", Name: "bpf_get_cgroup_classid_curr", Proto: "bpf_get_cgroup_classid_curr_proto", Ret: "RET_INTEGER"}, + "bpf_skb_vlan_push_proto": &BpfHelperFunc{Num: 18, Enum: "BPF_FUNC_skb_vlan_push", Name: "bpf_skb_vlan_push", Proto: "bpf_skb_vlan_push_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_skb_vlan_pop_proto": &BpfHelperFunc{Num: 19, Enum: "BPF_FUNC_skb_vlan_pop", Name: "bpf_skb_vlan_pop", Proto: "bpf_skb_vlan_pop_proto", Args: []string{"ARG_PTR_TO_CTX"}, Ret: "RET_INTEGER"}, + "bpf_skb_get_tunnel_key_proto": &BpfHelperFunc{Num: 20, Enum: "BPF_FUNC_skb_get_tunnel_key", Name: "bpf_skb_get_tunnel_key", Proto: "bpf_skb_get_tunnel_key_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_skb_set_tunnel_key_proto": &BpfHelperFunc{Num: 21, Enum: "BPF_FUNC_skb_set_tunnel_key", Name: "bpf_skb_set_tunnel_key", Proto: "bpf_skb_set_tunnel_key_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_perf_event_read_proto": &BpfHelperFunc{Num: 22, Enum: "BPF_FUNC_perf_event_read", Name: "bpf_perf_event_read", Proto: "bpf_perf_event_read_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_redirect_proto": &BpfHelperFunc{Num: 23, Enum: "BPF_FUNC_redirect", Name: "bpf_redirect", Proto: "bpf_redirect_proto", Args: []string{"ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_xdp_redirect_proto": &BpfHelperFunc{Num: 23, Enum: "BPF_FUNC_redirect", Name: "bpf_xdp_redirect", Proto: "bpf_xdp_redirect_proto", Args: []string{"ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_get_route_realm_proto": &BpfHelperFunc{Num: 24, Enum: "BPF_FUNC_get_route_realm", Name: "bpf_get_route_realm", Proto: "bpf_get_route_realm_proto", Args: []string{"ARG_PTR_TO_CTX"}, Ret: "RET_INTEGER"}, + "bpf_perf_event_output_proto": &BpfHelperFunc{Num: 25, Enum: "BPF_FUNC_perf_event_output", Name: "bpf_perf_event_output", Proto: "bpf_perf_event_output_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_ANYTHING", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE_OR_ZERO"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_event_output_data_proto": &BpfHelperFunc{Num: 25, Enum: "BPF_FUNC_perf_event_output", Name: "bpf_event_output_data", Proto: "bpf_event_output_data_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_ANYTHING", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE_OR_ZERO"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_skb_event_output_proto": &BpfHelperFunc{Num: 25, Enum: "BPF_FUNC_perf_event_output", Name: "bpf_skb_event_output", Proto: "bpf_skb_event_output_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_ANYTHING", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE_OR_ZERO"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_xdp_event_output_proto": &BpfHelperFunc{Num: 25, Enum: "BPF_FUNC_perf_event_output", Name: "bpf_xdp_event_output", Proto: "bpf_xdp_event_output_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_ANYTHING", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE_OR_ZERO"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_perf_event_output_proto_tp": &BpfHelperFunc{Num: 25, Enum: "BPF_FUNC_perf_event_output", Name: "bpf_perf_event_output_tp", Proto: "bpf_perf_event_output_proto_tp", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_ANYTHING", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE_OR_ZERO"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_perf_event_output_proto_raw_tp": &BpfHelperFunc{Num: 25, Enum: "BPF_FUNC_perf_event_output", Name: "bpf_perf_event_output_raw_tp", Proto: "bpf_perf_event_output_proto_raw_tp", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_ANYTHING", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE_OR_ZERO"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_skb_load_bytes_proto": &BpfHelperFunc{Num: 26, Enum: "BPF_FUNC_skb_load_bytes", Name: "bpf_skb_load_bytes", Proto: "bpf_skb_load_bytes_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_flow_dissector_load_bytes_proto": &BpfHelperFunc{Num: 26, Enum: "BPF_FUNC_skb_load_bytes", Name: "bpf_flow_dissector_load_bytes", Proto: "bpf_flow_dissector_load_bytes_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "sk_reuseport_load_bytes_proto": &BpfHelperFunc{Num: 26, Enum: "BPF_FUNC_skb_load_bytes", Name: "sk_reuseport_load_bytes", Proto: "sk_reuseport_load_bytes_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_get_stackid_proto": &BpfHelperFunc{Num: 27, Enum: "BPF_FUNC_get_stackid", Name: "bpf_get_stackid", Proto: "bpf_get_stackid_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_get_stackid_proto_pe": &BpfHelperFunc{Num: 27, Enum: "BPF_FUNC_get_stackid", Name: "bpf_get_stackid_pe", Proto: "bpf_get_stackid_proto_pe", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_get_stackid_proto_tp": &BpfHelperFunc{Num: 27, Enum: "BPF_FUNC_get_stackid", Name: "bpf_get_stackid_tp", Proto: "bpf_get_stackid_proto_tp", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_get_stackid_proto_raw_tp": &BpfHelperFunc{Num: 27, Enum: "BPF_FUNC_get_stackid", Name: "bpf_get_stackid_raw_tp", Proto: "bpf_get_stackid_proto_raw_tp", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_csum_diff_proto": &BpfHelperFunc{Num: 28, Enum: "BPF_FUNC_csum_diff", Name: "bpf_csum_diff", Proto: "bpf_csum_diff_proto", Args: []string{"ARG_PTR_TO_MEM_OR_NULL", "ARG_CONST_SIZE_OR_ZERO", "ARG_PTR_TO_MEM_OR_NULL", "ARG_CONST_SIZE_OR_ZERO", "ARG_ANYTHING"}, Ret: "RET_INTEGER", PktAccess: true}, + "bpf_skb_get_tunnel_opt_proto": &BpfHelperFunc{Num: 29, Enum: "BPF_FUNC_skb_get_tunnel_opt", Name: "bpf_skb_get_tunnel_opt", Proto: "bpf_skb_get_tunnel_opt_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_skb_set_tunnel_opt_proto": &BpfHelperFunc{Num: 30, Enum: "BPF_FUNC_skb_set_tunnel_opt", Name: "bpf_skb_set_tunnel_opt", Proto: "bpf_skb_set_tunnel_opt_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_skb_change_proto_proto": &BpfHelperFunc{Num: 31, Enum: "BPF_FUNC_skb_change_proto", Name: "bpf_skb_change_proto", Proto: "bpf_skb_change_proto_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_skb_change_type_proto": &BpfHelperFunc{Num: 32, Enum: "BPF_FUNC_skb_change_type", Name: "bpf_skb_change_type", Proto: "bpf_skb_change_type_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_skb_under_cgroup_proto": &BpfHelperFunc{Num: 33, Enum: "BPF_FUNC_skb_under_cgroup", Name: "bpf_skb_under_cgroup", Proto: "bpf_skb_under_cgroup_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_get_hash_recalc_proto": &BpfHelperFunc{Num: 34, Enum: "BPF_FUNC_get_hash_recalc", Name: "bpf_get_hash_recalc", Proto: "bpf_get_hash_recalc_proto", Args: []string{"ARG_PTR_TO_CTX"}, Ret: "RET_INTEGER"}, + "bpf_get_current_task_proto": &BpfHelperFunc{Num: 35, Enum: "BPF_FUNC_get_current_task", Name: "bpf_get_current_task", Proto: "bpf_get_current_task_proto", Ret: "RET_INTEGER", GplOnly: true}, + "bpf_probe_write_user_proto": &BpfHelperFunc{Num: 36, Enum: "BPF_FUNC_probe_write_user", Name: "bpf_probe_write_user", Proto: "bpf_probe_write_user_proto", Args: []string{"ARG_ANYTHING", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_current_task_under_cgroup_proto": &BpfHelperFunc{Num: 37, Enum: "BPF_FUNC_current_task_under_cgroup", Name: "bpf_current_task_under_cgroup", Proto: "bpf_current_task_under_cgroup_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_skb_change_tail_proto": &BpfHelperFunc{Num: 38, Enum: "BPF_FUNC_skb_change_tail", Name: "bpf_skb_change_tail", Proto: "bpf_skb_change_tail_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "sk_skb_change_tail_proto": &BpfHelperFunc{Num: 38, Enum: "BPF_FUNC_skb_change_tail", Name: "sk_skb_change_tail", Proto: "sk_skb_change_tail_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_skb_pull_data_proto": &BpfHelperFunc{Num: 39, Enum: "BPF_FUNC_skb_pull_data", Name: "bpf_skb_pull_data", Proto: "bpf_skb_pull_data_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "sk_skb_pull_data_proto": &BpfHelperFunc{Num: 39, Enum: "BPF_FUNC_skb_pull_data", Name: "sk_skb_pull_data", Proto: "sk_skb_pull_data_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_csum_update_proto": &BpfHelperFunc{Num: 40, Enum: "BPF_FUNC_csum_update", Name: "bpf_csum_update", Proto: "bpf_csum_update_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_set_hash_invalid_proto": &BpfHelperFunc{Num: 41, Enum: "BPF_FUNC_set_hash_invalid", Name: "bpf_set_hash_invalid", Proto: "bpf_set_hash_invalid_proto", Args: []string{"ARG_PTR_TO_CTX"}, Ret: "RET_INTEGER"}, + "bpf_get_numa_node_id_proto": &BpfHelperFunc{Num: 42, Enum: "BPF_FUNC_get_numa_node_id", Name: "bpf_get_numa_node_id", Proto: "bpf_get_numa_node_id_proto", Ret: "RET_INTEGER"}, + "bpf_skb_change_head_proto": &BpfHelperFunc{Num: 43, Enum: "BPF_FUNC_skb_change_head", Name: "bpf_skb_change_head", Proto: "bpf_skb_change_head_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "sk_skb_change_head_proto": &BpfHelperFunc{Num: 43, Enum: "BPF_FUNC_skb_change_head", Name: "sk_skb_change_head", Proto: "sk_skb_change_head_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_xdp_adjust_head_proto": &BpfHelperFunc{Num: 44, Enum: "BPF_FUNC_xdp_adjust_head", Name: "bpf_xdp_adjust_head", Proto: "bpf_xdp_adjust_head_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_probe_read_compat_str_proto": &BpfHelperFunc{Num: 45, Enum: "BPF_FUNC_probe_read_str", Name: "bpf_probe_read_compat_str", Proto: "bpf_probe_read_compat_str_proto", Args: []string{"ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE_OR_ZERO", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_get_socket_cookie_proto": &BpfHelperFunc{Num: 46, Enum: "BPF_FUNC_get_socket_cookie", Name: "bpf_get_socket_cookie", Proto: "bpf_get_socket_cookie_proto", Args: []string{"ARG_PTR_TO_CTX"}, Ret: "RET_INTEGER"}, + "bpf_get_socket_cookie_sock_addr_proto": &BpfHelperFunc{Num: 46, Enum: "BPF_FUNC_get_socket_cookie", Name: "bpf_get_socket_cookie_sock_addr", Proto: "bpf_get_socket_cookie_sock_addr_proto", Args: []string{"ARG_PTR_TO_CTX"}, Ret: "RET_INTEGER"}, + "bpf_get_socket_cookie_sock_proto": &BpfHelperFunc{Num: 46, Enum: "BPF_FUNC_get_socket_cookie", Name: "bpf_get_socket_cookie_sock", Proto: "bpf_get_socket_cookie_sock_proto", Args: []string{"ARG_PTR_TO_CTX"}, Ret: "RET_INTEGER"}, + "bpf_get_socket_cookie_sock_ops_proto": &BpfHelperFunc{Num: 46, Enum: "BPF_FUNC_get_socket_cookie", Name: "bpf_get_socket_cookie_sock_ops", Proto: "bpf_get_socket_cookie_sock_ops_proto", Args: []string{"ARG_PTR_TO_CTX"}, Ret: "RET_INTEGER"}, + "bpf_get_socket_ptr_cookie_proto": &BpfHelperFunc{Num: 46, Enum: "BPF_FUNC_get_socket_cookie", Name: "bpf_get_socket_ptr_cookie", Proto: "bpf_get_socket_ptr_cookie_proto", Args: []string{"ARG_PTR_TO_BTF_ID_SOCK_COMMON"}, Ret: "RET_INTEGER"}, + "bpf_get_socket_uid_proto": &BpfHelperFunc{Num: 47, Enum: "BPF_FUNC_get_socket_uid", Name: "bpf_get_socket_uid", Proto: "bpf_get_socket_uid_proto", Args: []string{"ARG_PTR_TO_CTX"}, Ret: "RET_INTEGER"}, + "bpf_set_hash_proto": &BpfHelperFunc{Num: 48, Enum: "BPF_FUNC_set_hash", Name: "bpf_set_hash", Proto: "bpf_set_hash_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_sock_ops_setsockopt_proto": &BpfHelperFunc{Num: 49, Enum: "BPF_FUNC_setsockopt", Name: "bpf_sock_ops_setsockopt", Proto: "bpf_sock_ops_setsockopt_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_sk_setsockopt_proto": &BpfHelperFunc{Num: 49, Enum: "BPF_FUNC_setsockopt", Name: "bpf_sk_setsockopt", Proto: "bpf_sk_setsockopt_proto", Args: []string{"ARG_PTR_TO_BTF_ID_SOCK_COMMON", "ARG_ANYTHING", "ARG_ANYTHING", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_sock_addr_setsockopt_proto": &BpfHelperFunc{Num: 49, Enum: "BPF_FUNC_setsockopt", Name: "bpf_sock_addr_setsockopt", Proto: "bpf_sock_addr_setsockopt_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_skb_adjust_room_proto": &BpfHelperFunc{Num: 50, Enum: "BPF_FUNC_skb_adjust_room", Name: "bpf_skb_adjust_room", Proto: "bpf_skb_adjust_room_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "sk_skb_adjust_room_proto": &BpfHelperFunc{Num: 50, Enum: "BPF_FUNC_skb_adjust_room", Name: "sk_skb_adjust_room", Proto: "sk_skb_adjust_room_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_xdp_redirect_map_proto": &BpfHelperFunc{Num: 51, Enum: "BPF_FUNC_redirect_map", Name: "bpf_redirect_map", Proto: "bpf_xdp_redirect_map_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_sk_redirect_map_proto": &BpfHelperFunc{Num: 52, Enum: "BPF_FUNC_sk_redirect_map", Name: "bpf_sk_redirect_map", Proto: "bpf_sk_redirect_map_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_sock_map_update_proto": &BpfHelperFunc{Num: 53, Enum: "BPF_FUNC_sock_map_update", Name: "bpf_sock_map_update", Proto: "bpf_sock_map_update_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_PTR_TO_MAP_KEY", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_xdp_adjust_meta_proto": &BpfHelperFunc{Num: 54, Enum: "BPF_FUNC_xdp_adjust_meta", Name: "bpf_xdp_adjust_meta", Proto: "bpf_xdp_adjust_meta_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_perf_event_read_value_proto": &BpfHelperFunc{Num: 55, Enum: "BPF_FUNC_perf_event_read_value", Name: "bpf_perf_event_read_value", Proto: "bpf_perf_event_read_value_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_ANYTHING", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_perf_prog_read_value_proto": &BpfHelperFunc{Num: 56, Enum: "BPF_FUNC_perf_prog_read_value", Name: "bpf_perf_prog_read_value", Proto: "bpf_perf_prog_read_value_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_sock_ops_getsockopt_proto": &BpfHelperFunc{Num: 57, Enum: "BPF_FUNC_getsockopt", Name: "bpf_sock_ops_getsockopt", Proto: "bpf_sock_ops_getsockopt_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_sk_getsockopt_proto": &BpfHelperFunc{Num: 57, Enum: "BPF_FUNC_getsockopt", Name: "bpf_sk_getsockopt", Proto: "bpf_sk_getsockopt_proto", Args: []string{"ARG_PTR_TO_BTF_ID_SOCK_COMMON", "ARG_ANYTHING", "ARG_ANYTHING", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_sock_addr_getsockopt_proto": &BpfHelperFunc{Num: 57, Enum: "BPF_FUNC_getsockopt", Name: "bpf_sock_addr_getsockopt", Proto: "bpf_sock_addr_getsockopt_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_override_return_proto": &BpfHelperFunc{Num: 58, Enum: "BPF_FUNC_override_return", Name: "bpf_override_return", Proto: "bpf_override_return_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_sock_ops_cb_flags_set_proto": &BpfHelperFunc{Num: 59, Enum: "BPF_FUNC_sock_ops_cb_flags_set", Name: "bpf_sock_ops_cb_flags_set", Proto: "bpf_sock_ops_cb_flags_set_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_msg_redirect_map_proto": &BpfHelperFunc{Num: 60, Enum: "BPF_FUNC_msg_redirect_map", Name: "bpf_msg_redirect_map", Proto: "bpf_msg_redirect_map_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_msg_apply_bytes_proto": &BpfHelperFunc{Num: 61, Enum: "BPF_FUNC_msg_apply_bytes", Name: "bpf_msg_apply_bytes", Proto: "bpf_msg_apply_bytes_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_msg_cork_bytes_proto": &BpfHelperFunc{Num: 62, Enum: "BPF_FUNC_msg_cork_bytes", Name: "bpf_msg_cork_bytes", Proto: "bpf_msg_cork_bytes_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_msg_pull_data_proto": &BpfHelperFunc{Num: 63, Enum: "BPF_FUNC_msg_pull_data", Name: "bpf_msg_pull_data", Proto: "bpf_msg_pull_data_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_bind_proto": &BpfHelperFunc{Num: 64, Enum: "BPF_FUNC_bind", Name: "bpf_bind", Proto: "bpf_bind_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_xdp_adjust_tail_proto": &BpfHelperFunc{Num: 65, Enum: "BPF_FUNC_xdp_adjust_tail", Name: "bpf_xdp_adjust_tail", Proto: "bpf_xdp_adjust_tail_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_skb_get_xfrm_state_proto": &BpfHelperFunc{Num: 66, Enum: "BPF_FUNC_skb_get_xfrm_state", Name: "bpf_skb_get_xfrm_state", Proto: "bpf_skb_get_xfrm_state_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_get_stack_proto": &BpfHelperFunc{Num: 67, Enum: "BPF_FUNC_get_stack", Name: "bpf_get_stack", Proto: "bpf_get_stack_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE_OR_ZERO", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_get_stack_proto_raw_tp": &BpfHelperFunc{Num: 67, Enum: "BPF_FUNC_get_stack", Name: "bpf_get_stack_raw_tp", Proto: "bpf_get_stack_proto_raw_tp", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE_OR_ZERO", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_get_stack_proto_tp": &BpfHelperFunc{Num: 67, Enum: "BPF_FUNC_get_stack", Name: "bpf_get_stack_tp", Proto: "bpf_get_stack_proto_tp", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE_OR_ZERO", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_get_stack_proto_pe": &BpfHelperFunc{Num: 67, Enum: "BPF_FUNC_get_stack", Name: "bpf_get_stack_pe", Proto: "bpf_get_stack_proto_pe", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE_OR_ZERO", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_skb_load_bytes_relative_proto": &BpfHelperFunc{Num: 68, Enum: "BPF_FUNC_skb_load_bytes_relative", Name: "bpf_skb_load_bytes_relative", Proto: "bpf_skb_load_bytes_relative_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "sk_reuseport_load_bytes_relative_proto": &BpfHelperFunc{Num: 68, Enum: "BPF_FUNC_skb_load_bytes_relative", Name: "sk_reuseport_load_bytes_relative", Proto: "sk_reuseport_load_bytes_relative_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_skb_fib_lookup_proto": &BpfHelperFunc{Num: 69, Enum: "BPF_FUNC_fib_lookup", Name: "bpf_skb_fib_lookup", Proto: "bpf_skb_fib_lookup_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_xdp_fib_lookup_proto": &BpfHelperFunc{Num: 69, Enum: "BPF_FUNC_fib_lookup", Name: "bpf_xdp_fib_lookup", Proto: "bpf_xdp_fib_lookup_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_sock_hash_update_proto": &BpfHelperFunc{Num: 70, Enum: "BPF_FUNC_sock_hash_update", Name: "bpf_sock_hash_update", Proto: "bpf_sock_hash_update_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_PTR_TO_MAP_KEY", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_msg_redirect_hash_proto": &BpfHelperFunc{Num: 71, Enum: "BPF_FUNC_msg_redirect_hash", Name: "bpf_msg_redirect_hash", Proto: "bpf_msg_redirect_hash_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_PTR_TO_MAP_KEY", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_sk_redirect_hash_proto": &BpfHelperFunc{Num: 72, Enum: "BPF_FUNC_sk_redirect_hash", Name: "bpf_sk_redirect_hash", Proto: "bpf_sk_redirect_hash_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_PTR_TO_MAP_KEY", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_lwt_in_push_encap_proto": &BpfHelperFunc{Num: 73, Enum: "BPF_FUNC_lwt_push_encap", Name: "bpf_lwt_in_push_encap", Proto: "bpf_lwt_in_push_encap_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_lwt_xmit_push_encap_proto": &BpfHelperFunc{Num: 74, Enum: "BPF_FUNC_lwt_push_encap", Name: "bpf_lwt_xmit_push_encap", Proto: "bpf_lwt_xmit_push_encap_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_lwt_seg6_store_bytes_proto": &BpfHelperFunc{Num: 75, Enum: "BPF_FUNC_lwt_seg6_store_bytes", Name: "bpf_lwt_seg6_store_bytes", Proto: "bpf_lwt_seg6_store_bytes_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_PTR_TO_MEM"}, Ret: "RET_INTEGER"}, + "bpf_lwt_seg6_adjust_srh_proto": &BpfHelperFunc{Num: 76, Enum: "BPF_FUNC_lwt_seg6_adjust_srh", Name: "bpf_lwt_seg6_adjust_srh", Proto: "bpf_lwt_seg6_adjust_srh_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_lwt_seg6_action_proto": &BpfHelperFunc{Num: 77, Enum: "BPF_FUNC_lwt_seg6_action", Name: "bpf_lwt_seg6_action", Proto: "bpf_lwt_seg6_action_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "rc_repeat_proto": &BpfHelperFunc{Num: 78, Enum: "BPF_FUNC_rc_repeat", Name: "bpf_rc_repeat", Proto: "rc_repeat_proto", Args: []string{"ARG_PTR_TO_CTX"}, Ret: "RET_INTEGER", GplOnly: true}, + "rc_keydown_proto": &BpfHelperFunc{Num: 79, Enum: "BPF_FUNC_rc_keydown", Name: "bpf_rc_keydown", Proto: "rc_keydown_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_skb_cgroup_id_proto": &BpfHelperFunc{Num: 80, Enum: "BPF_FUNC_skb_cgroup_id", Name: "bpf_skb_cgroup_id", Proto: "bpf_skb_cgroup_id_proto", Args: []string{"ARG_PTR_TO_CTX"}, Ret: "RET_INTEGER"}, + "bpf_get_current_cgroup_id_proto": &BpfHelperFunc{Num: 81, Enum: "BPF_FUNC_get_current_cgroup_id", Name: "bpf_get_current_cgroup_id", Proto: "bpf_get_current_cgroup_id_proto", Ret: "RET_INTEGER"}, + "bpf_get_local_storage_proto": &BpfHelperFunc{Num: 82, Enum: "BPF_FUNC_get_local_storage", Name: "bpf_get_local_storage", Proto: "bpf_get_local_storage_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_ANYTHING"}, Ret: "RET_PTR_TO_MAP_VALUE"}, + "sk_select_reuseport_proto": &BpfHelperFunc{Num: 83, Enum: "BPF_FUNC_sk_select_reuseport", Name: "sk_select_reuseport", Proto: "sk_select_reuseport_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_CONST_MAP_PTR", "ARG_PTR_TO_MAP_KEY", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_skb_ancestor_cgroup_id_proto": &BpfHelperFunc{Num: 84, Enum: "BPF_FUNC_skb_ancestor_cgroup_id", Name: "bpf_skb_ancestor_cgroup_id", Proto: "bpf_skb_ancestor_cgroup_id_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_sk_lookup_tcp_proto": &BpfHelperFunc{Num: 85, Enum: "BPF_FUNC_sk_lookup_tcp", Name: "bpf_sk_lookup_tcp", Proto: "bpf_sk_lookup_tcp_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_PTR_TO_SOCKET_OR_NULL", PktAccess: true}, + "bpf_xdp_sk_lookup_tcp_proto": &BpfHelperFunc{Num: 85, Enum: "BPF_FUNC_sk_lookup_tcp", Name: "bpf_xdp_sk_lookup_tcp", Proto: "bpf_xdp_sk_lookup_tcp_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_PTR_TO_SOCKET_OR_NULL", PktAccess: true}, + "bpf_sock_addr_sk_lookup_tcp_proto": &BpfHelperFunc{Num: 85, Enum: "BPF_FUNC_sk_lookup_tcp", Name: "bpf_sock_addr_sk_lookup_tcp", Proto: "bpf_sock_addr_sk_lookup_tcp_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_PTR_TO_SOCKET_OR_NULL"}, + "bpf_sk_lookup_udp_proto": &BpfHelperFunc{Num: 85, Enum: "BPF_FUNC_sk_lookup_udp", Name: "bpf_sk_lookup_udp", Proto: "bpf_sk_lookup_udp_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_PTR_TO_SOCKET_OR_NULL", PktAccess: true}, + "bpf_xdp_sk_lookup_udp_proto": &BpfHelperFunc{Num: 85, Enum: "BPF_FUNC_sk_lookup_udp", Name: "bpf_xdp_sk_lookup_udp", Proto: "bpf_xdp_sk_lookup_udp_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_PTR_TO_SOCKET_OR_NULL", PktAccess: true}, + "bpf_sock_addr_sk_lookup_udp_proto": &BpfHelperFunc{Num: 85, Enum: "BPF_FUNC_sk_lookup_udp", Name: "bpf_sock_addr_sk_lookup_udp", Proto: "bpf_sock_addr_sk_lookup_udp_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_PTR_TO_SOCKET_OR_NULL"}, + "bpf_sk_release_proto": &BpfHelperFunc{Num: 86, Enum: "BPF_FUNC_sk_release", Name: "bpf_sk_release", Proto: "bpf_sk_release_proto", Args: []string{"ARG_PTR_TO_BTF_ID_SOCK_COMMON"}, Ret: "RET_INTEGER"}, + "bpf_map_push_elem_proto": &BpfHelperFunc{Num: 87, Enum: "BPF_FUNC_map_push_elem", Name: "bpf_map_push_elem", Proto: "bpf_map_push_elem_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_PTR_TO_MAP_VALUE", "ARG_ANYTHING"}, Ret: "RET_INTEGER", PktAccess: true}, + "bpf_map_pop_elem_proto": &BpfHelperFunc{Num: 88, Enum: "BPF_FUNC_map_pop_elem", Name: "bpf_map_pop_elem", Proto: "bpf_map_pop_elem_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_PTR_TO_UNINIT_MAP_VALUE"}, Ret: "RET_INTEGER"}, + "bpf_map_peek_elem_proto": &BpfHelperFunc{Num: 89, Enum: "BPF_FUNC_map_peek_elem", Name: "bpf_map_peek_elem", Proto: "bpf_map_peek_elem_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_PTR_TO_UNINIT_MAP_VALUE"}, Ret: "RET_INTEGER"}, + "bpf_msg_push_data_proto": &BpfHelperFunc{Num: 90, Enum: "BPF_FUNC_msg_push_data", Name: "bpf_msg_push_data", Proto: "bpf_msg_push_data_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_msg_pop_data_proto": &BpfHelperFunc{Num: 91, Enum: "BPF_FUNC_msg_pop_data", Name: "bpf_msg_pop_data", Proto: "bpf_msg_pop_data_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "rc_pointer_rel_proto": &BpfHelperFunc{Num: 92, Enum: "BPF_FUNC_rc_pointer_rel", Name: "bpf_rc_pointer_rel", Proto: "rc_pointer_rel_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_spin_lock_proto": &BpfHelperFunc{Num: 93, Enum: "BPF_FUNC_spin_lock", Name: "bpf_spin_lock", Proto: "bpf_spin_lock_proto", Args: []string{"ARG_PTR_TO_SPIN_LOCK"}, Ret: "RET_VOID"}, + "bpf_spin_unlock_proto": &BpfHelperFunc{Num: 94, Enum: "BPF_FUNC_spin_unlock", Name: "bpf_spin_unlock", Proto: "bpf_spin_unlock_proto", Args: []string{"ARG_PTR_TO_SPIN_LOCK"}, Ret: "RET_VOID"}, + "bpf_sk_fullsock_proto": &BpfHelperFunc{Num: 95, Enum: "BPF_FUNC_sk_fullsock", Name: "bpf_sk_fullsock", Proto: "bpf_sk_fullsock_proto", Args: []string{"ARG_PTR_TO_SOCK_COMMON"}, Ret: "RET_PTR_TO_SOCKET_OR_NULL"}, + "bpf_tcp_sock_proto": &BpfHelperFunc{Num: 96, Enum: "BPF_FUNC_tcp_sock", Name: "bpf_tcp_sock", Proto: "bpf_tcp_sock_proto", Args: []string{"ARG_PTR_TO_SOCK_COMMON"}, Ret: "RET_PTR_TO_TCP_SOCK_OR_NULL"}, + "bpf_skb_ecn_set_ce_proto": &BpfHelperFunc{Num: 97, Enum: "BPF_FUNC_skb_ecn_set_ce", Name: "bpf_skb_ecn_set_ce", Proto: "bpf_skb_ecn_set_ce_proto", Args: []string{"ARG_PTR_TO_CTX"}, Ret: "RET_INTEGER"}, + "bpf_get_listener_sock_proto": &BpfHelperFunc{Num: 98, Enum: "BPF_FUNC_get_listener_sock", Name: "bpf_get_listener_sock", Proto: "bpf_get_listener_sock_proto", Args: []string{"ARG_PTR_TO_SOCK_COMMON"}, Ret: "RET_PTR_TO_SOCKET_OR_NULL"}, + "bpf_skc_lookup_tcp_proto": &BpfHelperFunc{Num: 99, Enum: "BPF_FUNC_skc_lookup_tcp", Name: "bpf_skc_lookup_tcp", Proto: "bpf_skc_lookup_tcp_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_PTR_TO_SOCK_COMMON_OR_NULL", PktAccess: true}, + "bpf_xdp_skc_lookup_tcp_proto": &BpfHelperFunc{Num: 99, Enum: "BPF_FUNC_skc_lookup_tcp", Name: "bpf_xdp_skc_lookup_tcp", Proto: "bpf_xdp_skc_lookup_tcp_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_PTR_TO_SOCK_COMMON_OR_NULL", PktAccess: true}, + "bpf_sock_addr_skc_lookup_tcp_proto": &BpfHelperFunc{Num: 99, Enum: "BPF_FUNC_skc_lookup_tcp", Name: "bpf_sock_addr_skc_lookup_tcp", Proto: "bpf_sock_addr_skc_lookup_tcp_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_PTR_TO_SOCK_COMMON_OR_NULL"}, + "bpf_tcp_check_syncookie_proto": &BpfHelperFunc{Num: 100, Enum: "BPF_FUNC_tcp_check_syncookie", Name: "bpf_tcp_check_syncookie", Proto: "bpf_tcp_check_syncookie_proto", Args: []string{"ARG_PTR_TO_BTF_ID_SOCK_COMMON", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER", GplOnly: true, PktAccess: true}, + "bpf_sysctl_get_name_proto": &BpfHelperFunc{Num: 101, Enum: "BPF_FUNC_sysctl_get_name", Name: "bpf_sysctl_get_name", Proto: "bpf_sysctl_get_name_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_sysctl_get_current_value_proto": &BpfHelperFunc{Num: 102, Enum: "BPF_FUNC_sysctl_get_current_value", Name: "bpf_sysctl_get_current_value", Proto: "bpf_sysctl_get_current_value_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_sysctl_get_new_value_proto": &BpfHelperFunc{Num: 103, Enum: "BPF_FUNC_sysctl_get_new_value", Name: "bpf_sysctl_get_new_value", Proto: "bpf_sysctl_get_new_value_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_sysctl_set_new_value_proto": &BpfHelperFunc{Num: 104, Enum: "BPF_FUNC_sysctl_set_new_value", Name: "bpf_sysctl_set_new_value", Proto: "bpf_sysctl_set_new_value_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_strtol_proto": &BpfHelperFunc{Num: 105, Enum: "BPF_FUNC_strtol", Name: "bpf_strtol", Proto: "bpf_strtol_proto", Args: []string{"ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING", "ARG_PTR_TO_LONG"}, Ret: "RET_INTEGER"}, + "bpf_strtoul_proto": &BpfHelperFunc{Num: 106, Enum: "BPF_FUNC_strtoul", Name: "bpf_strtoul", Proto: "bpf_strtoul_proto", Args: []string{"ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING", "ARG_PTR_TO_LONG"}, Ret: "RET_INTEGER"}, + "bpf_sk_storage_get_proto": &BpfHelperFunc{Num: 107, Enum: "BPF_FUNC_sk_storage_get", Name: "bpf_sk_storage_get", Proto: "bpf_sk_storage_get_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_PTR_TO_BTF_ID_SOCK_COMMON", "ARG_PTR_TO_MAP_VALUE_OR_NULL", "ARG_ANYTHING"}, Ret: "RET_PTR_TO_MAP_VALUE_OR_NULL"}, + "bpf_sk_storage_get_cg_sock_proto": &BpfHelperFunc{Num: 107, Enum: "BPF_FUNC_sk_storage_get", Name: "bpf_sk_storage_get", Proto: "bpf_sk_storage_get_cg_sock_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_PTR_TO_CTX", "ARG_PTR_TO_MAP_VALUE_OR_NULL", "ARG_ANYTHING"}, Ret: "RET_PTR_TO_MAP_VALUE_OR_NULL"}, + "bpf_sk_storage_get_tracing_proto": &BpfHelperFunc{Num: 107, Enum: "BPF_FUNC_sk_storage_get", Name: "bpf_sk_storage_get_tracing", Proto: "bpf_sk_storage_get_tracing_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_PTR_TO_BTF_ID", "ARG_PTR_TO_MAP_VALUE_OR_NULL", "ARG_ANYTHING"}, ArgBtfIds: []string{"struct sock_common"}, Ret: "RET_PTR_TO_MAP_VALUE_OR_NULL"}, + "bpf_sk_storage_delete_proto": &BpfHelperFunc{Num: 108, Enum: "BPF_FUNC_sk_storage_delete", Name: "bpf_sk_storage_delete", Proto: "bpf_sk_storage_delete_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_PTR_TO_BTF_ID_SOCK_COMMON"}, Ret: "RET_INTEGER"}, + "bpf_sk_storage_delete_tracing_proto": &BpfHelperFunc{Num: 108, Enum: "BPF_FUNC_sk_storage_delete", Name: "bpf_sk_storage_delete_tracing", Proto: "bpf_sk_storage_delete_tracing_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_PTR_TO_BTF_ID"}, ArgBtfIds: []string{"struct sock_common"}, Ret: "RET_INTEGER"}, + "bpf_send_signal_proto": &BpfHelperFunc{Num: 109, Enum: "BPF_FUNC_send_signal", Name: "bpf_send_signal", Proto: "bpf_send_signal_proto", Args: []string{"ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_tcp_gen_syncookie_proto": &BpfHelperFunc{Num: 110, Enum: "BPF_FUNC_tcp_gen_syncookie", Name: "bpf_tcp_gen_syncookie", Proto: "bpf_tcp_gen_syncookie_proto", Args: []string{"ARG_PTR_TO_BTF_ID_SOCK_COMMON", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER", GplOnly: true, PktAccess: true}, + "bpf_skb_output_proto": &BpfHelperFunc{Num: 111, Enum: "BPF_FUNC_skb_output", Name: "bpf_skb_event_output", Proto: "bpf_skb_output_proto", Args: []string{"ARG_PTR_TO_BTF_ID", "ARG_CONST_MAP_PTR", "ARG_ANYTHING", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE_OR_ZERO"}, ArgBtfIds: []string{"struct sk_buff"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_probe_read_user_proto": &BpfHelperFunc{Num: 112, Enum: "BPF_FUNC_probe_read_user", Name: "bpf_probe_read_user", Proto: "bpf_probe_read_user_proto", Args: []string{"ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE_OR_ZERO", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_probe_read_kernel_proto": &BpfHelperFunc{Num: 113, Enum: "BPF_FUNC_probe_read_kernel", Name: "bpf_probe_read_kernel", Proto: "bpf_probe_read_kernel_proto", Args: []string{"ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE_OR_ZERO", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_probe_read_user_str_proto": &BpfHelperFunc{Num: 114, Enum: "BPF_FUNC_probe_read_user_str", Name: "bpf_probe_read_user_str", Proto: "bpf_probe_read_user_str_proto", Args: []string{"ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE_OR_ZERO", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_probe_read_kernel_str_proto": &BpfHelperFunc{Num: 115, Enum: "BPF_FUNC_probe_read_kernel_str", Name: "bpf_probe_read_kernel_str", Proto: "bpf_probe_read_kernel_str_proto", Args: []string{"ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE_OR_ZERO", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_tcp_send_ack_proto": &BpfHelperFunc{Num: 116, Enum: "BPF_FUNC_tcp_send_ack", Name: "bpf_tcp_send_ack", Proto: "bpf_tcp_send_ack_proto", Args: []string{"ARG_PTR_TO_BTF_ID", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_send_signal_thread_proto": &BpfHelperFunc{Num: 117, Enum: "BPF_FUNC_send_signal_thread", Name: "bpf_send_signal_thread", Proto: "bpf_send_signal_thread_proto", Args: []string{"ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_jiffies64_proto": &BpfHelperFunc{Num: 118, Enum: "BPF_FUNC_jiffies64", Name: "bpf_jiffies64", Proto: "bpf_jiffies64_proto", Ret: "RET_INTEGER"}, + "bpf_read_branch_records_proto": &BpfHelperFunc{Num: 119, Enum: "BPF_FUNC_read_branch_records", Name: "bpf_read_branch_records", Proto: "bpf_read_branch_records_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM_OR_NULL", "ARG_CONST_SIZE_OR_ZERO", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_get_ns_current_pid_tgid_proto": &BpfHelperFunc{Num: 120, Enum: "BPF_FUNC_get_ns_current_pid_tgid", Name: "bpf_get_ns_current_pid_tgid", Proto: "bpf_get_ns_current_pid_tgid_proto", Args: []string{"ARG_ANYTHING", "ARG_ANYTHING", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_xdp_output_proto": &BpfHelperFunc{Num: 121, Enum: "BPF_FUNC_xdp_output", Name: "bpf_xdp_event_output", Proto: "bpf_xdp_output_proto", Args: []string{"ARG_PTR_TO_BTF_ID", "ARG_CONST_MAP_PTR", "ARG_ANYTHING", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE_OR_ZERO"}, ArgBtfIds: []string{"struct xdp_buff"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_get_netns_cookie_sock_addr_proto": &BpfHelperFunc{Num: 122, Enum: "BPF_FUNC_get_netns_cookie", Name: "bpf_get_netns_cookie_sock_addr", Proto: "bpf_get_netns_cookie_sock_addr_proto", Args: []string{"ARG_PTR_TO_CTX_OR_NULL"}, Ret: "RET_INTEGER"}, + "bpf_get_netns_cookie_sock_proto": &BpfHelperFunc{Num: 122, Enum: "BPF_FUNC_get_netns_cookie", Name: "bpf_get_netns_cookie_sock", Proto: "bpf_get_netns_cookie_sock_proto", Args: []string{"ARG_PTR_TO_CTX_OR_NULL"}, Ret: "RET_INTEGER"}, + "bpf_get_netns_cookie_sock_ops_proto": &BpfHelperFunc{Num: 122, Enum: "BPF_FUNC_get_netns_cookie", Name: "bpf_get_netns_cookie_sock_ops", Proto: "bpf_get_netns_cookie_sock_ops_proto", Args: []string{"ARG_PTR_TO_CTX_OR_NULL"}, Ret: "RET_INTEGER"}, + "bpf_get_netns_cookie_sk_msg_proto": &BpfHelperFunc{Num: 122, Enum: "BPF_FUNC_get_netns_cookie", Name: "bpf_get_netns_cookie_sk_msg", Proto: "bpf_get_netns_cookie_sk_msg_proto", Args: []string{"ARG_PTR_TO_CTX_OR_NULL"}, Ret: "RET_INTEGER"}, + "bpf_get_netns_cookie_sockopt_proto": &BpfHelperFunc{Num: 122, Enum: "BPF_FUNC_get_netns_cookie", Name: "bpf_get_netns_cookie_sockopt", Proto: "bpf_get_netns_cookie_sockopt_proto", Args: []string{"ARG_PTR_TO_CTX_OR_NULL"}, Ret: "RET_INTEGER"}, + "bpf_get_current_ancestor_cgroup_id_proto": &BpfHelperFunc{Num: 123, Enum: "BPF_FUNC_get_current_ancestor_cgroup_id", Name: "bpf_get_current_ancestor_cgroup_id", Proto: "bpf_get_current_ancestor_cgroup_id_proto", Args: []string{"ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_sk_assign_proto": &BpfHelperFunc{Num: 124, Enum: "BPF_FUNC_sk_assign", Name: "bpf_sk_assign", Proto: "bpf_sk_assign_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_BTF_ID_SOCK_COMMON", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_sk_lookup_assign_proto": &BpfHelperFunc{Num: 124, Enum: "BPF_FUNC_sk_assign", Name: "bpf_sk_lookup_assign", Proto: "bpf_sk_lookup_assign_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_SOCKET_OR_NULL", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_ktime_get_boot_ns_proto": &BpfHelperFunc{Num: 125, Enum: "BPF_FUNC_ktime_get_boot_ns", Name: "bpf_ktime_get_boot_ns", Proto: "bpf_ktime_get_boot_ns_proto", Ret: "RET_INTEGER"}, + "bpf_seq_printf_proto": &BpfHelperFunc{Num: 126, Enum: "BPF_FUNC_seq_printf", Name: "bpf_seq_printf", Proto: "bpf_seq_printf_proto", Args: []string{"ARG_PTR_TO_BTF_ID", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_PTR_TO_MEM_OR_NULL", "ARG_CONST_SIZE_OR_ZERO"}, ArgBtfIds: []string{"struct seq_file"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_seq_write_proto": &BpfHelperFunc{Num: 127, Enum: "BPF_FUNC_seq_write", Name: "bpf_seq_write", Proto: "bpf_seq_write_proto", Args: []string{"ARG_PTR_TO_BTF_ID", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE_OR_ZERO"}, ArgBtfIds: []string{"struct seq_file"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_sk_cgroup_id_proto": &BpfHelperFunc{Num: 128, Enum: "BPF_FUNC_sk_cgroup_id", Name: "bpf_sk_cgroup_id", Proto: "bpf_sk_cgroup_id_proto", Args: []string{"ARG_PTR_TO_BTF_ID_SOCK_COMMON"}, Ret: "RET_INTEGER"}, + "bpf_sk_ancestor_cgroup_id_proto": &BpfHelperFunc{Num: 129, Enum: "BPF_FUNC_sk_ancestor_cgroup_id", Name: "bpf_sk_ancestor_cgroup_id", Proto: "bpf_sk_ancestor_cgroup_id_proto", Args: []string{"ARG_PTR_TO_BTF_ID_SOCK_COMMON", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_ringbuf_output_proto": &BpfHelperFunc{Num: 130, Enum: "BPF_FUNC_ringbuf_output", Name: "bpf_ringbuf_output", Proto: "bpf_ringbuf_output_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE_OR_ZERO", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_ringbuf_reserve_proto": &BpfHelperFunc{Num: 131, Enum: "BPF_FUNC_ringbuf_reserve", Name: "bpf_ringbuf_reserve", Proto: "bpf_ringbuf_reserve_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_CONST_ALLOC_SIZE_OR_ZERO", "ARG_ANYTHING"}, Ret: "RET_PTR_TO_ALLOC_MEM_OR_NULL"}, + "bpf_ringbuf_submit_proto": &BpfHelperFunc{Num: 132, Enum: "BPF_FUNC_ringbuf_submit", Name: "bpf_ringbuf_submit", Proto: "bpf_ringbuf_submit_proto", Args: []string{"ARG_PTR_TO_ALLOC_MEM", "ARG_ANYTHING"}, Ret: "RET_VOID"}, + "bpf_ringbuf_discard_proto": &BpfHelperFunc{Num: 133, Enum: "BPF_FUNC_ringbuf_discard", Name: "bpf_ringbuf_discard", Proto: "bpf_ringbuf_discard_proto", Args: []string{"ARG_PTR_TO_ALLOC_MEM", "ARG_ANYTHING"}, Ret: "RET_VOID"}, + "bpf_ringbuf_query_proto": &BpfHelperFunc{Num: 134, Enum: "BPF_FUNC_ringbuf_query", Name: "bpf_ringbuf_query", Proto: "bpf_ringbuf_query_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_csum_level_proto": &BpfHelperFunc{Num: 135, Enum: "BPF_FUNC_csum_level", Name: "bpf_csum_level", Proto: "bpf_csum_level_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_skc_to_tcp6_sock_proto": &BpfHelperFunc{Num: 136, Enum: "BPF_FUNC_skc_to_tcp6_sock", Name: "bpf_skc_to_tcp6_sock", Proto: "bpf_skc_to_tcp6_sock_proto", Args: []string{"ARG_PTR_TO_BTF_ID_SOCK_COMMON"}, Ret: "RET_PTR_TO_BTF_ID_OR_NULL", RetBtfId: "struct tcp6_sock"}, + "bpf_skc_to_tcp_sock_proto": &BpfHelperFunc{Num: 137, Enum: "BPF_FUNC_skc_to_tcp_sock", Name: "bpf_skc_to_tcp_sock", Proto: "bpf_skc_to_tcp_sock_proto", Args: []string{"ARG_PTR_TO_BTF_ID_SOCK_COMMON"}, Ret: "RET_PTR_TO_BTF_ID_OR_NULL", RetBtfId: "struct tcp_sock"}, + "bpf_skc_to_tcp_timewait_sock_proto": &BpfHelperFunc{Num: 138, Enum: "BPF_FUNC_skc_to_tcp_timewait_sock", Name: "bpf_skc_to_tcp_timewait_sock", Proto: "bpf_skc_to_tcp_timewait_sock_proto", Args: []string{"ARG_PTR_TO_BTF_ID_SOCK_COMMON"}, Ret: "RET_PTR_TO_BTF_ID_OR_NULL", RetBtfId: "struct tcp_timewait_sock"}, + "bpf_skc_to_tcp_request_sock_proto": &BpfHelperFunc{Num: 139, Enum: "BPF_FUNC_skc_to_tcp_request_sock", Name: "bpf_skc_to_tcp_request_sock", Proto: "bpf_skc_to_tcp_request_sock_proto", Args: []string{"ARG_PTR_TO_BTF_ID_SOCK_COMMON"}, Ret: "RET_PTR_TO_BTF_ID_OR_NULL", RetBtfId: "struct tcp_request_sock"}, + "bpf_skc_to_udp6_sock_proto": &BpfHelperFunc{Num: 140, Enum: "BPF_FUNC_skc_to_udp6_sock", Name: "bpf_skc_to_udp6_sock", Proto: "bpf_skc_to_udp6_sock_proto", Args: []string{"ARG_PTR_TO_BTF_ID_SOCK_COMMON"}, Ret: "RET_PTR_TO_BTF_ID_OR_NULL", RetBtfId: "struct udp6_sock"}, + "bpf_get_task_stack_proto": &BpfHelperFunc{Num: 141, Enum: "BPF_FUNC_get_task_stack", Name: "bpf_get_task_stack", Proto: "bpf_get_task_stack_proto", Args: []string{"ARG_PTR_TO_BTF_ID", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE_OR_ZERO", "ARG_ANYTHING"}, ArgBtfIds: []string{"struct task_struct"}, Ret: "RET_INTEGER"}, + "bpf_sock_ops_load_hdr_opt_proto": &BpfHelperFunc{Num: 142, Enum: "BPF_FUNC_load_hdr_opt", Name: "bpf_sock_ops_load_hdr_opt", Proto: "bpf_sock_ops_load_hdr_opt_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_sock_ops_store_hdr_opt_proto": &BpfHelperFunc{Num: 143, Enum: "BPF_FUNC_store_hdr_opt", Name: "bpf_sock_ops_store_hdr_opt", Proto: "bpf_sock_ops_store_hdr_opt_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_sock_ops_reserve_hdr_opt_proto": &BpfHelperFunc{Num: 144, Enum: "BPF_FUNC_reserve_hdr_opt", Name: "bpf_sock_ops_reserve_hdr_opt", Proto: "bpf_sock_ops_reserve_hdr_opt_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_inode_storage_get_proto": &BpfHelperFunc{Num: 145, Enum: "BPF_FUNC_inode_storage_get", Name: "bpf_inode_storage_get", Proto: "bpf_inode_storage_get_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_PTR_TO_BTF_ID", "ARG_PTR_TO_MAP_VALUE_OR_NULL", "ARG_ANYTHING"}, ArgBtfIds: []string{"struct inode"}, Ret: "RET_PTR_TO_MAP_VALUE_OR_NULL"}, + "bpf_inode_storage_delete_proto": &BpfHelperFunc{Num: 146, Enum: "BPF_FUNC_inode_storage_delete", Name: "bpf_inode_storage_delete", Proto: "bpf_inode_storage_delete_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_PTR_TO_BTF_ID"}, ArgBtfIds: []string{"struct inode"}, Ret: "RET_INTEGER"}, + "bpf_d_path_proto": &BpfHelperFunc{Num: 147, Enum: "BPF_FUNC_d_path", Name: "bpf_d_path", Proto: "bpf_d_path_proto", Args: []string{"ARG_PTR_TO_BTF_ID", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE_OR_ZERO"}, ArgBtfIds: []string{"struct path"}, Ret: "RET_INTEGER"}, + "bpf_copy_from_user_proto": &BpfHelperFunc{Num: 148, Enum: "BPF_FUNC_copy_from_user", Name: "bpf_copy_from_user", Proto: "bpf_copy_from_user_proto", Args: []string{"ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE_OR_ZERO", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_snprintf_btf_proto": &BpfHelperFunc{Num: 149, Enum: "BPF_FUNC_snprintf_btf", Name: "bpf_snprintf_btf", Proto: "bpf_snprintf_btf_proto", Args: []string{"ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_seq_printf_btf_proto": &BpfHelperFunc{Num: 150, Enum: "BPF_FUNC_seq_printf_btf", Name: "bpf_seq_printf_btf", Proto: "bpf_seq_printf_btf_proto", Args: []string{"ARG_PTR_TO_BTF_ID", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE_OR_ZERO", "ARG_ANYTHING"}, ArgBtfIds: []string{"struct seq_file"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_skb_cgroup_classid_proto": &BpfHelperFunc{Num: 151, Enum: "BPF_FUNC_skb_cgroup_classid", Name: "bpf_skb_cgroup_classid", Proto: "bpf_skb_cgroup_classid_proto", Args: []string{"ARG_PTR_TO_CTX"}, Ret: "RET_INTEGER"}, + "bpf_redirect_neigh_proto": &BpfHelperFunc{Num: 152, Enum: "BPF_FUNC_redirect_neigh", Name: "bpf_redirect_neigh", Proto: "bpf_redirect_neigh_proto", Args: []string{"ARG_ANYTHING", "ARG_PTR_TO_MEM_OR_NULL", "ARG_CONST_SIZE_OR_ZERO", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_per_cpu_ptr_proto": &BpfHelperFunc{Num: 153, Enum: "BPF_FUNC_per_cpu_ptr", Name: "bpf_per_cpu_ptr", Proto: "bpf_per_cpu_ptr_proto", Args: []string{"ARG_PTR_TO_PERCPU_BTF_ID", "ARG_ANYTHING"}, Ret: "RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL"}, + "bpf_this_cpu_ptr_proto": &BpfHelperFunc{Num: 154, Enum: "BPF_FUNC_this_cpu_ptr", Name: "bpf_this_cpu_ptr", Proto: "bpf_this_cpu_ptr_proto", Args: []string{"ARG_PTR_TO_PERCPU_BTF_ID"}, Ret: "RET_PTR_TO_MEM_OR_BTF_ID"}, + "bpf_redirect_peer_proto": &BpfHelperFunc{Num: 155, Enum: "BPF_FUNC_redirect_peer", Name: "bpf_redirect_peer", Proto: "bpf_redirect_peer_proto", Args: []string{"ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_task_storage_get_proto": &BpfHelperFunc{Num: 156, Enum: "BPF_FUNC_task_storage_get", Name: "bpf_task_storage_get", Proto: "bpf_task_storage_get_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_PTR_TO_BTF_ID", "ARG_PTR_TO_MAP_VALUE_OR_NULL", "ARG_ANYTHING"}, ArgBtfIds: []string{"struct task_struct"}, Ret: "RET_PTR_TO_MAP_VALUE_OR_NULL"}, + "bpf_task_storage_delete_proto": &BpfHelperFunc{Num: 157, Enum: "BPF_FUNC_task_storage_delete", Name: "bpf_task_storage_delete", Proto: "bpf_task_storage_delete_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_PTR_TO_BTF_ID"}, ArgBtfIds: []string{"struct task_struct"}, Ret: "RET_INTEGER"}, + "bpf_get_current_task_btf_proto": &BpfHelperFunc{Num: 158, Enum: "BPF_FUNC_get_current_task_btf", Name: "bpf_get_current_task_btf", Proto: "bpf_get_current_task_btf_proto", Ret: "RET_PTR_TO_BTF_ID", RetBtfId: "struct task_struct", GplOnly: true}, + "bpf_bprm_opts_set_proto": &BpfHelperFunc{Num: 159, Enum: "BPF_FUNC_bprm_opts_set", Name: "bpf_bprm_opts_set", Proto: "bpf_bprm_opts_set_proto", Args: []string{"ARG_PTR_TO_BTF_ID", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_ktime_get_coarse_ns_proto": &BpfHelperFunc{Num: 160, Enum: "BPF_FUNC_ktime_get_coarse_ns", Name: "bpf_ktime_get_coarse_ns", Proto: "bpf_ktime_get_coarse_ns_proto", Ret: "RET_INTEGER"}, + "bpf_ima_inode_hash_proto": &BpfHelperFunc{Num: 161, Enum: "BPF_FUNC_ima_inode_hash", Name: "bpf_ima_inode_hash", Proto: "bpf_ima_inode_hash_proto", Args: []string{"ARG_PTR_TO_BTF_ID", "ARG_PTR_TO_UNINIT_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_sock_from_file_proto": &BpfHelperFunc{Num: 162, Enum: "BPF_FUNC_sock_from_file", Name: "bpf_sock_from_file", Proto: "bpf_sock_from_file_proto", Args: []string{"ARG_PTR_TO_BTF_ID"}, ArgBtfIds: []string{"struct file"}, Ret: "RET_PTR_TO_BTF_ID_OR_NULL", RetBtfId: "struct socket"}, + "bpf_skb_check_mtu_proto": &BpfHelperFunc{Num: 163, Enum: "BPF_FUNC_check_mtu", Name: "bpf_skb_check_mtu", Proto: "bpf_skb_check_mtu_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_PTR_TO_INT", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_xdp_check_mtu_proto": &BpfHelperFunc{Num: 163, Enum: "BPF_FUNC_check_mtu", Name: "bpf_xdp_check_mtu", Proto: "bpf_xdp_check_mtu_proto", Args: []string{"ARG_PTR_TO_CTX", "ARG_ANYTHING", "ARG_PTR_TO_INT", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_for_each_map_elem_proto": &BpfHelperFunc{Num: 164, Enum: "BPF_FUNC_for_each_map_elem", Name: "bpf_for_each_map_elem", Proto: "bpf_for_each_map_elem_proto", Args: []string{"ARG_CONST_MAP_PTR", "ARG_PTR_TO_FUNC", "ARG_PTR_TO_STACK_OR_NULL", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_snprintf_proto": &BpfHelperFunc{Num: 165, Enum: "BPF_FUNC_snprintf", Name: "bpf_snprintf", Proto: "bpf_snprintf_proto", Args: []string{"ARG_PTR_TO_MEM_OR_NULL", "ARG_CONST_SIZE_OR_ZERO", "ARG_PTR_TO_CONST_STR", "ARG_PTR_TO_MEM_OR_NULL", "ARG_CONST_SIZE_OR_ZERO"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_sys_bpf_proto": &BpfHelperFunc{Num: 166, Enum: "BPF_FUNC_sys_bpf", Name: "bpf_sys_bpf", Proto: "bpf_sys_bpf_proto", Args: []string{"ARG_ANYTHING", "ARG_PTR_TO_MEM", "ARG_CONST_SIZE"}, Ret: "RET_INTEGER"}, + "bpf_btf_find_by_name_kind_proto": &BpfHelperFunc{Num: 167, Enum: "BPF_FUNC_btf_find_by_name_kind", Name: "bpf_btf_find_by_name_kind", Proto: "bpf_btf_find_by_name_kind_proto", Args: []string{"ARG_PTR_TO_MEM", "ARG_CONST_SIZE", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_sys_close_proto": &BpfHelperFunc{Num: 168, Enum: "BPF_FUNC_sys_close", Name: "bpf_sys_close", Proto: "bpf_sys_close_proto", Args: []string{"ARG_ANYTHING"}, Ret: "RET_INTEGER"}, + "bpf_timer_init_proto": &BpfHelperFunc{Num: 169, Enum: "BPF_FUNC_timer_init", Name: "bpf_timer_init", Proto: "bpf_timer_init_proto", Args: []string{"ARG_PTR_TO_TIMER", "ARG_CONST_MAP_PTR", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_timer_set_callback_proto": &BpfHelperFunc{Num: 170, Enum: "BPF_FUNC_timer_set_callback", Name: "bpf_timer_set_callback", Proto: "bpf_timer_set_callback_proto", Args: []string{"ARG_PTR_TO_TIMER", "ARG_PTR_TO_FUNC"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_timer_start_proto": &BpfHelperFunc{Num: 171, Enum: "BPF_FUNC_timer_start", Name: "bpf_timer_start", Proto: "bpf_timer_start_proto", Args: []string{"ARG_PTR_TO_TIMER", "ARG_ANYTHING", "ARG_ANYTHING"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_timer_cancel_proto": &BpfHelperFunc{Num: 172, Enum: "BPF_FUNC_timer_cancel", Name: "bpf_timer_cancel", Proto: "bpf_timer_cancel_proto", Args: []string{"ARG_PTR_TO_TIMER"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_get_func_ip_proto_kprobe": &BpfHelperFunc{Num: 173, Enum: "BPF_FUNC_get_func_ip", Name: "bpf_get_func_ip_kprobe", Proto: "bpf_get_func_ip_proto_kprobe", Args: []string{"ARG_PTR_TO_CTX"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_get_func_ip_proto_tracing": &BpfHelperFunc{Num: 173, Enum: "BPF_FUNC_get_func_ip", Name: "bpf_get_func_ip_tracing", Proto: "bpf_get_func_ip_proto_tracing", Args: []string{"ARG_PTR_TO_CTX"}, Ret: "RET_INTEGER", GplOnly: true}, + "bpf_get_attach_cookie_proto_trace": &BpfHelperFunc{Num: 174, Enum: "BPF_FUNC_get_attach_cookie", Name: "bpf_get_attach_cookie_trace", Proto: "bpf_get_attach_cookie_proto_trace", Args: []string{"ARG_PTR_TO_CTX"}, Ret: "RET_INTEGER"}, + "bpf_get_attach_cookie_proto_pe": &BpfHelperFunc{Num: 174, Enum: "BPF_FUNC_get_attach_cookie", Name: "bpf_get_attach_cookie_pe", Proto: "bpf_get_attach_cookie_proto_pe", Args: []string{"ARG_PTR_TO_CTX"}, Ret: "RET_INTEGER"}, + "bpf_task_pt_regs_proto": &BpfHelperFunc{Num: 175, Enum: "BPF_FUNC_task_pt_regs", Name: "bpf_task_pt_regs", Proto: "bpf_task_pt_regs_proto", Args: []string{"ARG_PTR_TO_BTF_ID"}, ArgBtfIds: []string{"struct task_struct"}, Ret: "RET_PTR_TO_BTF_ID", RetBtfId: "struct pt_regs", GplOnly: true}, +} + +var ProgTypeMap = map[BpfProgTypeEnum]*BpfProgTypeDef{ + BPF_PROG_TYPE_SOCK_OPS: &BpfProgTypeDef{ + Name: "sock_ops", + User: "struct bpf_sock_ops", + Kern: "struct bpf_sock_ops_kern", + Enum: BPF_PROG_TYPE_SOCK_OPS, + SecDefs: []SecDef{ + SecDef{"sockops", nil, false}, + }, + FuncProtos: []string{ + "bpf_sock_ops_setsockopt_proto", "bpf_sock_ops_getsockopt_proto", "bpf_sock_ops_cb_flags_set_proto", "bpf_sock_map_update_proto", + "bpf_sock_hash_update_proto", "bpf_get_socket_cookie_sock_ops_proto", "bpf_get_local_storage_proto", "bpf_event_output_data_proto", + "bpf_sk_storage_get_proto", "bpf_sk_storage_delete_proto", "bpf_get_netns_cookie_sock_ops_proto", "bpf_sock_ops_load_hdr_opt_proto", + "bpf_sock_ops_store_hdr_opt_proto", "bpf_sock_ops_reserve_hdr_opt_proto", "bpf_tcp_sock_proto", + //bpf_sk_base_func_proto + "bpf_skc_to_tcp6_sock_proto", "bpf_skc_to_tcp_sock_proto", "bpf_skc_to_tcp_timewait_sock_proto", "bpf_skc_to_tcp_request_sock_proto", + "bpf_skc_to_udp6_sock_proto", "bpf_ktime_get_coarse_ns_proto", + // bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_LIRC_MODE2: &BpfProgTypeDef{ + Name: "lirc_mode2", + User: "__u32", + Kern: "u32", + Enum: BPF_PROG_TYPE_LIRC_MODE2, + SecDefs: []SecDef{ + SecDef{"lirc_mode2", nil, false}, + }, + FuncProtos: []string{ + "rc_repeat_proto", "rc_keydown_proto", "rc_pointer_rel_proto", "bpf_map_lookup_elem_proto", + "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", "bpf_map_pop_elem_proto", + "bpf_map_peek_elem_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", "bpf_tail_call_proto", + "bpf_get_prandom_u32_proto", + "bpf_trace_printk_proto", + }}, + BPF_PROG_TYPE_SK_REUSEPORT: &BpfProgTypeDef{ + Name: "sk_reuseport", + User: "struct sk_reuseport_md", + Kern: "struct sk_reuseport_kern", + Enum: BPF_PROG_TYPE_SK_REUSEPORT, + SecDefs: []SecDef{ + SecDef{"sk_reuseport/migrate", nil, false}, + SecDef{"sk_reuseport", nil, false}, + }, + FuncProtos: []string{ + "sk_select_reuseport_proto", "sk_reuseport_load_bytes_proto", "sk_reuseport_load_bytes_relative_proto", "bpf_get_socket_ptr_cookie_proto", + "bpf_ktime_get_coarse_ns_proto", + //bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_SK_MSG: &BpfProgTypeDef{ + Name: "sk_msg", + User: "struct sk_msg_md", + Kern: "struct sk_msg", + Enum: BPF_PROG_TYPE_SK_MSG, + SecDefs: []SecDef{ + SecDef{"sk_msg", nil, false}, + }, + FuncProtos: []string{ + "bpf_msg_redirect_map_proto", "bpf_msg_redirect_hash_proto", "bpf_msg_apply_bytes_proto", "bpf_msg_cork_bytes_proto", + "bpf_msg_pull_data_proto", "bpf_msg_push_data_proto", "bpf_msg_pop_data_proto", "bpf_event_output_data_proto", + "bpf_get_current_uid_gid_proto", "bpf_get_current_pid_tgid_proto", "bpf_sk_storage_get_proto", "bpf_sk_storage_delete_proto", + "bpf_get_netns_cookie_sk_msg_proto", "bpf_get_current_cgroup_id_proto", "bpf_get_current_ancestor_cgroup_id_proto", "bpf_get_cgroup_classid_curr_proto", + //bpf_sk_base_func_proto + "bpf_skc_to_tcp6_sock_proto", "bpf_skc_to_tcp_sock_proto", "bpf_skc_to_tcp_timewait_sock_proto", "bpf_skc_to_tcp_request_sock_proto", + "bpf_skc_to_udp6_sock_proto", "bpf_ktime_get_coarse_ns_proto", + // bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_FLOW_DISSECTOR: &BpfProgTypeDef{ + Name: "flow_dissector", + User: "struct __sk_buff", + Kern: "struct bpf_flow_dissector", + Enum: BPF_PROG_TYPE_FLOW_DISSECTOR, + SecDefs: []SecDef{ + SecDef{"flow_dissector", nil, false}, + }, + FuncProtos: []string{ + "bpf_flow_dissector_load_bytes_proto", + //bpf_sk_base_func_proto + "bpf_skc_to_tcp6_sock_proto", "bpf_skc_to_tcp_sock_proto", "bpf_skc_to_tcp_timewait_sock_proto", "bpf_skc_to_tcp_request_sock_proto", + "bpf_skc_to_udp6_sock_proto", "bpf_ktime_get_coarse_ns_proto", + // bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_SOCKET_FILTER: &BpfProgTypeDef{ + Name: "sk_filter", + User: "struct __sk_buff", + Kern: "struct sk_buff", + Enum: BPF_PROG_TYPE_SOCKET_FILTER, + SecDefs: []SecDef{ + SecDef{"socket", nil, false}, + }, + FuncProtos: []string{ + "bpf_skb_load_bytes_proto", + "bpf_skb_load_bytes_relative_proto", + "bpf_get_socket_cookie_proto", + "bpf_get_socket_uid_proto", + "bpf_skb_event_output_proto", + //bpf_sk_base_func_proto + "bpf_skc_to_tcp6_sock_proto", "bpf_skc_to_tcp_sock_proto", "bpf_skc_to_tcp_timewait_sock_proto", "bpf_skc_to_tcp_request_sock_proto", + "bpf_skc_to_udp6_sock_proto", "bpf_ktime_get_coarse_ns_proto", + // bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_CGROUP_SKB: &BpfProgTypeDef{ + Name: "cg_skb", + User: "struct __sk_buff", + Kern: "struct sk_buff", + Enum: BPF_PROG_TYPE_CGROUP_SKB, + SecDefs: []SecDef{ + SecDef{"cgroup_skb/ingress", nil, false}, + SecDef{"cgroup_skb/egress", nil, false}, + SecDef{"cgroup/skb", nil, false}, + }, + FuncProtos: []string{ + "bpf_get_local_storage_proto", "bpf_sk_fullsock_proto", "bpf_sk_storage_get_proto", "bpf_sk_storage_delete_proto", + "bpf_skb_event_output_proto", "bpf_skb_cgroup_id_proto", "bpf_skb_ancestor_cgroup_id_proto", "bpf_sk_cgroup_id_proto", + "bpf_sk_ancestor_cgroup_id_proto", "bpf_sk_lookup_tcp_proto", "bpf_sk_lookup_udp_proto", "bpf_sk_release_proto", + "bpf_skc_lookup_tcp_proto", "bpf_tcp_sock_proto", "bpf_get_listener_sock_proto", "bpf_skb_ecn_set_ce_proto", + //sk_filter_func_proto + "bpf_skb_load_bytes_proto", "bpf_skb_load_bytes_relative_proto", "bpf_get_socket_cookie_proto", "bpf_get_socket_uid_proto", + "bpf_skb_event_output_proto", + // bpf_sk_base_func_proto + "bpf_skc_to_tcp6_sock_proto", "bpf_skc_to_tcp_sock_proto", "bpf_skc_to_tcp_timewait_sock_proto", "bpf_skc_to_tcp_request_sock_proto", + "bpf_skc_to_udp6_sock_proto", "bpf_ktime_get_coarse_ns_proto", + // bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_CGROUP_SOCK: &BpfProgTypeDef{ + Name: "cg_sock", + User: "struct bpf_sock", + Kern: "struct sock", + Enum: BPF_PROG_TYPE_CGROUP_SOCK, + SecDefs: []SecDef{ + SecDef{"cgroup/sock_create", nil, false}, + SecDef{"cgroup/sock_release", nil, false}, + SecDef{"cgroup/sock", nil, false}, + SecDef{"cgroup/post_bind4", nil, false}, + SecDef{"cgroup/post_bind6", nil, false}, + }, + FuncProtos: []string{ + "bpf_get_current_uid_gid_proto", "bpf_get_local_storage_proto", "bpf_get_socket_cookie_sock_proto", "bpf_get_netns_cookie_sock_proto", + "bpf_event_output_data_proto", "bpf_get_current_pid_tgid_proto", "bpf_get_current_comm_proto", "bpf_get_current_cgroup_id_proto", + "bpf_get_current_ancestor_cgroup_id_proto", "bpf_get_cgroup_classid_curr_proto", "bpf_sk_storage_get_cg_sock_proto", + "bpf_ktime_get_coarse_ns_proto", + //bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_LWT_IN: &BpfProgTypeDef{ + Name: "lwt_in", + User: "struct __sk_buff", + Kern: "struct sk_buff", + Enum: BPF_PROG_TYPE_LWT_IN, + SecDefs: []SecDef{ + SecDef{"lwt_in", nil, false}, + }, + FuncProtos: []string{ + "bpf_lwt_in_push_encap_proto", + //lwt_out_func_proto + "bpf_skb_load_bytes_proto", "bpf_skb_pull_data_proto", "bpf_csum_diff_proto", "bpf_get_cgroup_classid_proto", + "bpf_get_route_realm_proto", "bpf_get_hash_recalc_proto", "bpf_skb_event_output_proto", "bpf_get_smp_processor_id_proto", + "bpf_skb_under_cgroup_proto", + // bpf_sk_base_func_proto + "bpf_skc_to_tcp6_sock_proto", "bpf_skc_to_tcp_sock_proto", "bpf_skc_to_tcp_timewait_sock_proto", "bpf_skc_to_tcp_request_sock_proto", + "bpf_skc_to_udp6_sock_proto", "bpf_ktime_get_coarse_ns_proto", + // bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_LWT_SEG6LOCAL: &BpfProgTypeDef{ + Name: "lwt_seg6local", + User: "struct __sk_buff", + Kern: "struct sk_buff", + Enum: BPF_PROG_TYPE_LWT_SEG6LOCAL, + SecDefs: []SecDef{ + SecDef{"lwt_seg6local", nil, false}, + }, + FuncProtos: []string{ + "bpf_lwt_seg6_store_bytes_proto", "bpf_lwt_seg6_action_proto", "bpf_lwt_seg6_adjust_srh_proto", + //lwt_out_func_proto + "bpf_skb_load_bytes_proto", "bpf_skb_pull_data_proto", "bpf_csum_diff_proto", "bpf_get_cgroup_classid_proto", + "bpf_get_route_realm_proto", "bpf_get_hash_recalc_proto", "bpf_skb_event_output_proto", "bpf_get_smp_processor_id_proto", + "bpf_skb_under_cgroup_proto", + // bpf_sk_base_func_proto + "bpf_skc_to_tcp6_sock_proto", "bpf_skc_to_tcp_sock_proto", "bpf_skc_to_tcp_timewait_sock_proto", "bpf_skc_to_tcp_request_sock_proto", + "bpf_skc_to_udp6_sock_proto", "bpf_ktime_get_coarse_ns_proto", + // bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_SK_SKB: &BpfProgTypeDef{ + Name: "sk_skb", + User: "struct __sk_buff", + Kern: "struct sk_buff", + Enum: BPF_PROG_TYPE_SK_SKB, + SecDefs: []SecDef{ + SecDef{"sk_skb/stream_parser", nil, false}, + SecDef{"sk_skb/stream_verdict", nil, false}, + SecDef{"sk_skb", nil, false}, + }, + FuncProtos: []string{ + "bpf_skb_store_bytes_proto", "bpf_skb_load_bytes_proto", "sk_skb_pull_data_proto", "sk_skb_change_tail_proto", + "sk_skb_change_head_proto", "sk_skb_adjust_room_proto", "bpf_get_socket_cookie_proto", "bpf_get_socket_uid_proto", + "bpf_sk_redirect_map_proto", "bpf_sk_redirect_hash_proto", "bpf_skb_event_output_proto", "bpf_sk_lookup_tcp_proto", + "bpf_sk_lookup_udp_proto", "bpf_sk_release_proto", "bpf_skc_lookup_tcp_proto", + //bpf_sk_base_func_proto + "bpf_skc_to_tcp6_sock_proto", "bpf_skc_to_tcp_sock_proto", "bpf_skc_to_tcp_timewait_sock_proto", "bpf_skc_to_tcp_request_sock_proto", + "bpf_skc_to_udp6_sock_proto", "bpf_ktime_get_coarse_ns_proto", + // bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_RAW_TRACEPOINT: &BpfProgTypeDef{ + Name: "raw_tracepoint", + User: "struct bpf_raw_tracepoint_args", + Kern: "u64", + Enum: BPF_PROG_TYPE_RAW_TRACEPOINT, + SecDefs: []SecDef{ + SecDef{"raw_tracepoint/", GenRawTracepointEntry, false}, + SecDef{"raw_tp/", GenRawTracepointEntry, false}, + }, + FuncProtos: []string{ + "bpf_perf_event_output_proto_raw_tp", "bpf_get_stackid_proto_raw_tp", "bpf_get_stack_proto_raw_tp", + //bpf_tracing_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_tail_call_proto", "bpf_get_current_pid_tgid_proto", "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", + "bpf_task_pt_regs_proto", "bpf_get_current_uid_gid_proto", "bpf_get_current_comm_proto", "bpf_trace_printk_proto", + "bpf_get_smp_processor_id_proto", "bpf_get_numa_node_id_proto", "bpf_perf_event_read_proto", "bpf_current_task_under_cgroup_proto", + "bpf_get_prandom_u32_proto", "bpf_probe_write_user_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_probe_read_compat_proto", "bpf_probe_read_compat_str_proto", + "bpf_get_current_cgroup_id_proto", "bpf_get_current_ancestor_cgroup_id_proto", "bpf_send_signal_proto", "bpf_send_signal_thread_proto", + "bpf_perf_event_read_value_proto", "bpf_get_ns_current_pid_tgid_proto", "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", + "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", "bpf_ringbuf_query_proto", "bpf_jiffies64_proto", + "bpf_get_task_stack_proto", "bpf_copy_from_user_proto", "bpf_snprintf_btf_proto", "bpf_per_cpu_ptr_proto", + "bpf_this_cpu_ptr_proto", "bpf_task_storage_get_proto", "bpf_task_storage_delete_proto", "bpf_for_each_map_elem_proto", + "bpf_snprintf_proto", /*"bpf_get_func_ip_proto_tracing",*/ "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_timer_init_proto", "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", + }}, + BPF_PROG_TYPE_CGROUP_DEVICE: &BpfProgTypeDef{ + Name: "cg_dev", + User: "struct bpf_cgroup_dev_ctx", + Kern: "struct bpf_cgroup_dev_ctx", + Enum: BPF_PROG_TYPE_CGROUP_DEVICE, + SecDefs: []SecDef{ + SecDef{"cgroup/dev", nil, false}, + }, + FuncProtos: []string{ + "bpf_get_current_uid_gid_proto", "bpf_get_local_storage_proto", "bpf_get_current_cgroup_id_proto", "bpf_event_output_data_proto", + //bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_CGROUP_SOCKOPT: &BpfProgTypeDef{ + Name: "cg_sockopt", + User: "struct bpf_sockopt", + Kern: "struct bpf_sockopt_kern", + Enum: BPF_PROG_TYPE_CGROUP_SOCKOPT, + SecDefs: []SecDef{ + SecDef{"cgroup/getsockopt", nil, false}, + SecDef{"cgroup/setsockopt", nil, false}, + }, + FuncProtos: []string{ + "bpf_get_netns_cookie_sockopt_proto", "bpf_sk_storage_get_proto", "bpf_sk_storage_delete_proto", "bpf_sk_setsockopt_proto", + "bpf_sk_getsockopt_proto", "bpf_tcp_sock_proto", + //cgroup_base_func_proto + "bpf_get_current_uid_gid_proto", "bpf_get_local_storage_proto", "bpf_get_current_cgroup_id_proto", "bpf_event_output_data_proto", + // bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_SK_LOOKUP: &BpfProgTypeDef{ + Name: "sk_lookup", + User: "struct bpf_sk_lookup", + Kern: "struct bpf_sk_lookup_kern", + Enum: BPF_PROG_TYPE_SK_LOOKUP, + SecDefs: []SecDef{ + SecDef{"sk_lookup", nil, false}, + }, + FuncProtos: []string{ + "bpf_event_output_data_proto", "bpf_sk_lookup_assign_proto", "bpf_sk_release_proto", + //bpf_sk_base_func_proto + "bpf_skc_to_tcp6_sock_proto", "bpf_skc_to_tcp_sock_proto", "bpf_skc_to_tcp_timewait_sock_proto", "bpf_skc_to_tcp_request_sock_proto", + "bpf_skc_to_udp6_sock_proto", "bpf_ktime_get_coarse_ns_proto", + // bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_SCHED_CLS: &BpfProgTypeDef{ + Name: "tc_cls", + User: "struct __sk_buff", + Kern: "struct sk_buff", + Enum: BPF_PROG_TYPE_SCHED_CLS, + SecDefs: []SecDef{ + SecDef{"tc", nil, false}, + SecDef{"classifier", nil, false}, + }, + FuncProtos: []string{ + "bpf_skb_store_bytes_proto", "bpf_skb_load_bytes_proto", "bpf_skb_load_bytes_relative_proto", "bpf_skb_pull_data_proto", + "bpf_csum_diff_proto", "bpf_csum_update_proto", "bpf_csum_level_proto", "bpf_l3_csum_replace_proto", + "bpf_l4_csum_replace_proto", "bpf_clone_redirect_proto", "bpf_get_cgroup_classid_proto", "bpf_skb_vlan_push_proto", + "bpf_skb_vlan_pop_proto", "bpf_skb_change_proto_proto", "bpf_skb_change_type_proto", "bpf_skb_adjust_room_proto", + "bpf_skb_change_tail_proto", "bpf_skb_change_head_proto", "bpf_skb_get_tunnel_key_proto", "bpf_skb_set_tunnel_key_proto", + "bpf_skb_get_tunnel_opt_proto", "bpf_skb_set_tunnel_opt_proto", "bpf_redirect_proto", "bpf_redirect_neigh_proto", + "bpf_redirect_peer_proto", "bpf_get_route_realm_proto", "bpf_get_hash_recalc_proto", "bpf_set_hash_invalid_proto", + "bpf_set_hash_proto", "bpf_skb_event_output_proto", "bpf_get_smp_processor_id_proto", "bpf_skb_under_cgroup_proto", + "bpf_get_socket_cookie_proto", "bpf_get_socket_uid_proto", "bpf_skb_fib_lookup_proto", "bpf_skb_check_mtu_proto", + "bpf_sk_fullsock_proto", "bpf_sk_storage_get_proto", "bpf_sk_storage_delete_proto", "bpf_skb_get_xfrm_state_proto", + "bpf_skb_cgroup_classid_proto", "bpf_skb_cgroup_id_proto", "bpf_skb_ancestor_cgroup_id_proto", "bpf_sk_lookup_tcp_proto", + "bpf_sk_lookup_udp_proto", "bpf_sk_release_proto", "bpf_tcp_sock_proto", "bpf_get_listener_sock_proto", + "bpf_skc_lookup_tcp_proto", "bpf_tcp_check_syncookie_proto", "bpf_skb_ecn_set_ce_proto", "bpf_tcp_gen_syncookie_proto", + "bpf_sk_assign_proto", + //bpf_sk_base_func_proto + "bpf_skc_to_tcp6_sock_proto", "bpf_skc_to_tcp_sock_proto", "bpf_skc_to_tcp_timewait_sock_proto", "bpf_skc_to_tcp_request_sock_proto", + "bpf_skc_to_udp6_sock_proto", "bpf_ktime_get_coarse_ns_proto", + // bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_SCHED_ACT: &BpfProgTypeDef{ + Name: "tc_act", + User: "struct __sk_buff", + Kern: "struct sk_buff", + Enum: BPF_PROG_TYPE_SCHED_ACT, + SecDefs: []SecDef{ + SecDef{"action", nil, false}, + }, + FuncProtos: []string{ + "bpf_skb_store_bytes_proto", "bpf_skb_load_bytes_proto", "bpf_skb_load_bytes_relative_proto", "bpf_skb_pull_data_proto", + "bpf_csum_diff_proto", "bpf_csum_update_proto", "bpf_csum_level_proto", "bpf_l3_csum_replace_proto", + "bpf_l4_csum_replace_proto", "bpf_clone_redirect_proto", "bpf_get_cgroup_classid_proto", "bpf_skb_vlan_push_proto", + "bpf_skb_vlan_pop_proto", "bpf_skb_change_proto_proto", "bpf_skb_change_type_proto", "bpf_skb_adjust_room_proto", + "bpf_skb_change_tail_proto", "bpf_skb_change_head_proto", "bpf_skb_get_tunnel_key_proto", "bpf_skb_set_tunnel_key_proto", + "bpf_skb_get_tunnel_opt_proto", "bpf_skb_set_tunnel_opt_proto", "bpf_redirect_proto", "bpf_redirect_neigh_proto", + "bpf_redirect_peer_proto", "bpf_get_route_realm_proto", "bpf_get_hash_recalc_proto", "bpf_set_hash_invalid_proto", + "bpf_set_hash_proto", "bpf_skb_event_output_proto", "bpf_get_smp_processor_id_proto", "bpf_skb_under_cgroup_proto", + "bpf_get_socket_cookie_proto", "bpf_get_socket_uid_proto", "bpf_skb_fib_lookup_proto", "bpf_skb_check_mtu_proto", + "bpf_sk_fullsock_proto", "bpf_sk_storage_get_proto", "bpf_sk_storage_delete_proto", "bpf_skb_get_xfrm_state_proto", + "bpf_skb_cgroup_classid_proto", "bpf_skb_cgroup_id_proto", "bpf_skb_ancestor_cgroup_id_proto", "bpf_sk_lookup_tcp_proto", + "bpf_sk_lookup_udp_proto", "bpf_sk_release_proto", "bpf_tcp_sock_proto", "bpf_get_listener_sock_proto", + "bpf_skc_lookup_tcp_proto", "bpf_tcp_check_syncookie_proto", "bpf_skb_ecn_set_ce_proto", "bpf_tcp_gen_syncookie_proto", + "bpf_sk_assign_proto", + //bpf_sk_base_func_proto + "bpf_skc_to_tcp6_sock_proto", "bpf_skc_to_tcp_sock_proto", "bpf_skc_to_tcp_timewait_sock_proto", "bpf_skc_to_tcp_request_sock_proto", + "bpf_skc_to_udp6_sock_proto", "bpf_ktime_get_coarse_ns_proto", + // bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_CGROUP_SOCK_ADDR: &BpfProgTypeDef{ + Name: "cg_sock_addr", + User: "struct bpf_sock_addr", + Kern: "struct bpf_sock_addr_kern", + Enum: BPF_PROG_TYPE_CGROUP_SOCK_ADDR, + SecDefs: []SecDef{ + SecDef{"cgroup/bind4", nil, false}, + SecDef{"cgroup/bind6", nil, false}, + SecDef{"cgroup/connect4", nil, false}, + SecDef{"cgroup/connect6", nil, false}, + SecDef{"cgroup/sendmsg4", nil, false}, + SecDef{"cgroup/sendmsg6", nil, false}, + SecDef{"cgroup/recvmsg4", nil, false}, + SecDef{"cgroup/recvmsg6", nil, false}, + SecDef{"cgroup/getpeername4", nil, false}, + SecDef{"cgroup/getpeername6", nil, false}, + SecDef{"cgroup/getsockname4", nil, false}, + SecDef{"cgroup/getsockname6", nil, false}, + }, + FuncProtos: []string{ + "bpf_get_current_uid_gid_proto", "bpf_bind_proto", "bpf_get_socket_cookie_sock_addr_proto", "bpf_get_netns_cookie_sock_addr_proto", + "bpf_get_local_storage_proto", "bpf_event_output_data_proto", "bpf_get_current_pid_tgid_proto", "bpf_get_current_comm_proto", + "bpf_get_current_cgroup_id_proto", "bpf_get_current_ancestor_cgroup_id_proto", "bpf_get_cgroup_classid_curr_proto", "bpf_sock_addr_sk_lookup_tcp_proto", + "bpf_sock_addr_sk_lookup_udp_proto", "bpf_sk_release_proto", "bpf_sock_addr_skc_lookup_tcp_proto", "bpf_sk_storage_get_proto", + "bpf_sk_storage_delete_proto", "bpf_sock_addr_setsockopt_proto", "bpf_sock_addr_getsockopt_proto", + //bpf_sk_base_func_proto + "bpf_skc_to_tcp6_sock_proto", "bpf_skc_to_tcp_sock_proto", "bpf_skc_to_tcp_timewait_sock_proto", "bpf_skc_to_tcp_request_sock_proto", + "bpf_skc_to_udp6_sock_proto", "bpf_ktime_get_coarse_ns_proto", + // bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_PERF_EVENT: &BpfProgTypeDef{ + Name: "perf_event", + User: "struct bpf_perf_event_data", + Kern: "struct bpf_perf_event_data_kern", + Enum: BPF_PROG_TYPE_PERF_EVENT, + SecDefs: []SecDef{ + SecDef{"perf_event", nil, false}, + }, + FuncProtos: []string{ + "bpf_perf_event_output_proto_tp", "bpf_get_stackid_proto_pe", "bpf_get_stack_proto_pe", "bpf_perf_prog_read_value_proto", + "bpf_read_branch_records_proto", "bpf_get_attach_cookie_proto_pe", + //bpf_tracing_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_tail_call_proto", "bpf_get_current_pid_tgid_proto", "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", + "bpf_task_pt_regs_proto", "bpf_get_current_uid_gid_proto", "bpf_get_current_comm_proto", "bpf_trace_printk_proto", + "bpf_get_smp_processor_id_proto", "bpf_get_numa_node_id_proto", "bpf_perf_event_read_proto", "bpf_current_task_under_cgroup_proto", + "bpf_get_prandom_u32_proto", "bpf_probe_write_user_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_probe_read_compat_proto", "bpf_probe_read_compat_str_proto", + "bpf_get_current_cgroup_id_proto", "bpf_get_current_ancestor_cgroup_id_proto", "bpf_send_signal_proto", "bpf_send_signal_thread_proto", + "bpf_perf_event_read_value_proto", "bpf_get_ns_current_pid_tgid_proto", "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", + "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", "bpf_ringbuf_query_proto", "bpf_jiffies64_proto", + "bpf_get_task_stack_proto", "bpf_copy_from_user_proto", "bpf_snprintf_btf_proto", "bpf_per_cpu_ptr_proto", + "bpf_this_cpu_ptr_proto", "bpf_task_storage_get_proto", "bpf_task_storage_delete_proto", "bpf_for_each_map_elem_proto", + "bpf_snprintf_proto", /*"bpf_get_func_ip_proto_tracing",*/ "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_timer_init_proto", "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", + }}, + BPF_PROG_TYPE_CGROUP_SYSCTL: &BpfProgTypeDef{ + Name: "cg_sysctl", + User: "struct bpf_sysctl", + Kern: "struct bpf_sysctl_kern", + Enum: BPF_PROG_TYPE_CGROUP_SYSCTL, + SecDefs: []SecDef{ + SecDef{"cgroup/sysctl", nil, false}, + }, + FuncProtos: []string{ + "bpf_strtol_proto", "bpf_strtoul_proto", "bpf_sysctl_get_name_proto", "bpf_sysctl_get_current_value_proto", "bpf_sysctl_get_new_value_proto", + "bpf_sysctl_set_new_value_proto", "bpf_ktime_get_coarse_ns_proto", + //cgroup_base_func_proto + "bpf_get_current_uid_gid_proto", "bpf_get_local_storage_proto", "bpf_get_current_cgroup_id_proto", "bpf_event_output_data_proto", + // bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_XDP: &BpfProgTypeDef{ + Name: "xdp", + User: "struct xdp_md", + Kern: "struct xdp_buff", + Enum: BPF_PROG_TYPE_XDP, + SecDefs: []SecDef{ +// SecDef{"xdp.frags/devmap", nil, false}, + //SecDef{"xdp/devmap", nil, false}, //XXX to be supported + //SecDef{"xdp_devmap/", GenXdpEntry, false}, +// SecDef{"xdp.frags/cpumap", nil, false}, + //SecDef{"xdp/cpumap", nil, false}, //XXX to be supported + //SecDef{"xdp_cpumap/", GenXdpEntry, false}, +// SecDef{"xdp.frags", nil, false}, + SecDef{"xdp", nil, false}, + }, + FuncProtos: []string{ + "bpf_xdp_event_output_proto", "bpf_get_smp_processor_id_proto", "bpf_csum_diff_proto", "bpf_xdp_adjust_head_proto", + "bpf_xdp_adjust_meta_proto", "bpf_xdp_redirect_proto", "bpf_xdp_redirect_map_proto", "bpf_xdp_adjust_tail_proto", + "bpf_xdp_fib_lookup_proto", "bpf_xdp_check_mtu_proto", "bpf_xdp_sk_lookup_udp_proto", "bpf_xdp_sk_lookup_tcp_proto", + "bpf_sk_release_proto", "bpf_xdp_skc_lookup_tcp_proto", "bpf_tcp_check_syncookie_proto", "bpf_tcp_gen_syncookie_proto", + //bpf_sk_base_func_proto + "bpf_skc_to_tcp6_sock_proto", "bpf_skc_to_tcp_sock_proto", "bpf_skc_to_tcp_timewait_sock_proto", "bpf_skc_to_tcp_request_sock_proto", + "bpf_skc_to_udp6_sock_proto", "bpf_ktime_get_coarse_ns_proto", + // bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_LWT_OUT: &BpfProgTypeDef{ + Name: "lwt_out", + User: "struct __sk_buff", + Kern: "struct sk_buff", + Enum: BPF_PROG_TYPE_LWT_OUT, + SecDefs: []SecDef{ + SecDef{"lwt_out", nil, false}, + }, + FuncProtos: []string{ + "bpf_skb_load_bytes_proto", "bpf_skb_pull_data_proto", "bpf_csum_diff_proto", "bpf_get_cgroup_classid_proto", + "bpf_get_route_realm_proto", "bpf_get_hash_recalc_proto", "bpf_skb_event_output_proto", "bpf_get_smp_processor_id_proto", + "bpf_skb_under_cgroup_proto", + //bpf_sk_base_func_proto + "bpf_skc_to_tcp6_sock_proto", "bpf_skc_to_tcp_sock_proto", "bpf_skc_to_tcp_timewait_sock_proto", "bpf_skc_to_tcp_request_sock_proto", + "bpf_skc_to_udp6_sock_proto", "bpf_ktime_get_coarse_ns_proto", + // bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_LWT_XMIT: &BpfProgTypeDef{ + Name: "lwt_xmit", + User: "struct __sk_buff", + Kern: "struct sk_buff", + Enum: BPF_PROG_TYPE_LWT_XMIT, + SecDefs: []SecDef{ + SecDef{"lwt_xmit", nil, false}, + }, + FuncProtos: []string{ + "bpf_skb_get_tunnel_key_proto", "bpf_skb_set_tunnel_key_proto", "bpf_skb_get_tunnel_opt_proto", "bpf_skb_set_tunnel_opt_proto", + "bpf_redirect_proto", "bpf_clone_redirect_proto", "bpf_skb_change_tail_proto", "bpf_skb_change_head_proto", + "bpf_skb_store_bytes_proto", "bpf_csum_update_proto", "bpf_csum_level_proto", "bpf_l3_csum_replace_proto", + "bpf_l4_csum_replace_proto", "bpf_set_hash_invalid_proto", "bpf_lwt_xmit_push_encap_proto", + //lwt_out_func_proto + "bpf_skb_load_bytes_proto", "bpf_skb_pull_data_proto", "bpf_csum_diff_proto", "bpf_get_cgroup_classid_proto", + "bpf_get_route_realm_proto", "bpf_get_hash_recalc_proto", "bpf_skb_event_output_proto", "bpf_get_smp_processor_id_proto", + "bpf_skb_under_cgroup_proto", + // bpf_sk_base_func_proto + "bpf_skc_to_tcp6_sock_proto", "bpf_skc_to_tcp_sock_proto", "bpf_skc_to_tcp_timewait_sock_proto", "bpf_skc_to_tcp_request_sock_proto", + "bpf_skc_to_udp6_sock_proto", "bpf_ktime_get_coarse_ns_proto", + // bpf_base_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + "bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + "bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", "bpf_timer_init_proto", + "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", "bpf_trace_printk_proto", + "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", "bpf_snprintf_proto", + "bpf_task_pt_regs_proto", + }}, + BPF_PROG_TYPE_KPROBE: &BpfProgTypeDef{ + Name: "kprobe", + User: "struct bpf_user_pt_regs_t", + Kern: "struct pt_regs", + Enum: BPF_PROG_TYPE_KPROBE, + SecDefs: []SecDef{ + SecDef{"kprobe/", GenKprobeEntry, false}, + SecDef{"uprobe/", GenKprobeEntry, false}, + SecDef{"kretprobe/", GenKprobeEntry, false}, + SecDef{"uretprobe/", GenKprobeEntry, false}, + }, + FuncProtos: []string{ + "bpf_perf_event_output_proto", "bpf_get_stackid_proto", "bpf_get_stack_proto", "bpf_override_return_proto", + "bpf_get_attach_cookie_proto_trace", "bpf_get_func_ip_proto_kprobe", + //bpf_tracing_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_tail_call_proto", "bpf_get_current_pid_tgid_proto", "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", + "bpf_task_pt_regs_proto", "bpf_get_current_uid_gid_proto", "bpf_get_current_comm_proto", "bpf_trace_printk_proto", + "bpf_get_smp_processor_id_proto", "bpf_get_numa_node_id_proto", "bpf_perf_event_read_proto", "bpf_current_task_under_cgroup_proto", + "bpf_get_prandom_u32_proto", "bpf_probe_write_user_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_probe_read_compat_proto", "bpf_probe_read_compat_str_proto", + "bpf_get_current_cgroup_id_proto", "bpf_get_current_ancestor_cgroup_id_proto", "bpf_send_signal_proto", "bpf_send_signal_thread_proto", + "bpf_perf_event_read_value_proto", "bpf_get_ns_current_pid_tgid_proto", "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", + "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", "bpf_ringbuf_query_proto", "bpf_jiffies64_proto", + "bpf_get_task_stack_proto", "bpf_copy_from_user_proto", "bpf_snprintf_btf_proto", "bpf_per_cpu_ptr_proto", + "bpf_this_cpu_ptr_proto", "bpf_task_storage_get_proto", "bpf_task_storage_delete_proto", "bpf_for_each_map_elem_proto", + "bpf_snprintf_proto", "bpf_get_func_ip_proto_tracing", "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_timer_init_proto", "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", + }}, + BPF_PROG_TYPE_TRACEPOINT: &BpfProgTypeDef{ + Name: "tracepoint", + User: "__u64", + Kern: "u64", + Enum: BPF_PROG_TYPE_TRACEPOINT, + SecDefs: []SecDef{ + SecDef{"tracepoint/", GenTracepointEntry, false}, + SecDef{"tp/", GenTracepointEntry, false}, + }, + FuncProtos: []string{ + "bpf_perf_event_output_proto_tp", "bpf_get_stackid_proto_tp", "bpf_get_stack_proto_tp", "bpf_get_attach_cookie_proto_trace", + //bpf_tracing_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_tail_call_proto", "bpf_get_current_pid_tgid_proto", "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", + "bpf_task_pt_regs_proto", "bpf_get_current_uid_gid_proto", "bpf_get_current_comm_proto", "bpf_trace_printk_proto", + "bpf_get_smp_processor_id_proto", "bpf_get_numa_node_id_proto", "bpf_perf_event_read_proto", "bpf_current_task_under_cgroup_proto", + "bpf_get_prandom_u32_proto", "bpf_probe_write_user_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_probe_read_compat_proto", "bpf_probe_read_compat_str_proto", + "bpf_get_current_cgroup_id_proto", "bpf_get_current_ancestor_cgroup_id_proto", "bpf_send_signal_proto", "bpf_send_signal_thread_proto", + "bpf_perf_event_read_value_proto", "bpf_get_ns_current_pid_tgid_proto", "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", + "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", "bpf_ringbuf_query_proto", "bpf_jiffies64_proto", + "bpf_get_task_stack_proto", "bpf_copy_from_user_proto", "bpf_snprintf_btf_proto", "bpf_per_cpu_ptr_proto", + "bpf_this_cpu_ptr_proto", "bpf_task_storage_get_proto", "bpf_task_storage_delete_proto", "bpf_for_each_map_elem_proto", + "bpf_snprintf_proto", /*"bpf_get_func_ip_proto_tracing",*/ "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_timer_init_proto", "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", + }}, + BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE: &BpfProgTypeDef{ + Name: "raw_tracepoint_writable", + User: "struct bpf_raw_tracepoint_args", + Kern: "u64", + Enum: BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, + SecDefs: []SecDef{ + SecDef{"raw_tracepoint.w/", GenRawTracepointEntry, false}, + SecDef{"raw_tp.w/", GenRawTracepointEntry, false}, + }, + FuncProtos: []string{ + "bpf_perf_event_output_proto_raw_tp", "bpf_get_stackid_proto_raw_tp", "bpf_get_stack_proto", + //bpf_tracing_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_tail_call_proto", "bpf_get_current_pid_tgid_proto", "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", + "bpf_task_pt_regs_proto", "bpf_get_current_uid_gid_proto", "bpf_get_current_comm_proto", "bpf_trace_printk_proto", + "bpf_get_smp_processor_id_proto", "bpf_get_numa_node_id_proto", "bpf_perf_event_read_proto", "bpf_current_task_under_cgroup_proto", + "bpf_get_prandom_u32_proto", "bpf_probe_write_user_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_probe_read_compat_proto", "bpf_probe_read_compat_str_proto", + "bpf_get_current_cgroup_id_proto", "bpf_get_current_ancestor_cgroup_id_proto", "bpf_send_signal_proto", "bpf_send_signal_thread_proto", + "bpf_perf_event_read_value_proto", "bpf_get_ns_current_pid_tgid_proto", "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", + "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", "bpf_ringbuf_query_proto", "bpf_jiffies64_proto", + "bpf_get_task_stack_proto", "bpf_copy_from_user_proto", "bpf_snprintf_btf_proto", "bpf_per_cpu_ptr_proto", + "bpf_this_cpu_ptr_proto", "bpf_task_storage_get_proto", "bpf_task_storage_delete_proto", "bpf_for_each_map_elem_proto", + "bpf_snprintf_proto", /*"bpf_get_func_ip_proto_tracing",*/ "bpf_spin_lock_proto", "bpf_spin_unlock_proto", + "bpf_timer_init_proto", "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", + }}, + BPF_PROG_TYPE_TRACING: &BpfProgTypeDef{ + Name: "tracing", + User: "void *", + Kern: "void *", + Enum: BPF_PROG_TYPE_TRACING, + SecDefs: []SecDef{ + SecDef{"tp_btf/", nil, false}, + SecDef{"fentry/", GenBPFTrampoline, false}, + SecDef{"fmod_ret", GenBPFTrampoline, false}, + SecDef{"fexit/", GenBPFTrampoline, false}, + SecDef{"fentry.s/", GenBPFTrampoline, true}, + SecDef{"fmod_ret.s/", GenBPFTrampoline, true}, + SecDef{"fexit.s/", GenBPFTrampoline, true}, + SecDef{"iter/", GenTracingIter, false}, + SecDef{"iter.s/", GenTracingIter, true}, + }, + FuncProtos: []string{ + "bpf_skb_output_proto", "bpf_xdp_output_proto", "bpf_skc_to_tcp6_sock_proto", "bpf_skc_to_tcp_sock_proto", + "bpf_skc_to_tcp_timewait_sock_proto", "bpf_skc_to_tcp_request_sock_proto", "bpf_skc_to_udp6_sock_proto", "bpf_sk_storage_get_tracing_proto", + "bpf_sk_storage_delete_tracing_proto", "bpf_sock_from_file_proto", "bpf_get_socket_ptr_cookie_proto", "bpf_seq_printf_proto", + "bpf_seq_write_proto", "bpf_seq_printf_btf_proto", "bpf_d_path_proto", + //raw_tp_prog_func_proto + "bpf_perf_event_output_proto_raw_tp", "bpf_get_stackid_proto_raw_tp", "bpf_get_stack_proto_raw_tp", + // bpf_tracing_func_proto + "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + "bpf_tail_call_proto", "bpf_get_current_pid_tgid_proto", "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", + "bpf_task_pt_regs_proto", "bpf_get_current_uid_gid_proto", "bpf_get_current_comm_proto", "bpf_trace_printk_proto", + "bpf_get_smp_processor_id_proto", "bpf_get_numa_node_id_proto", "bpf_perf_event_read_proto", "bpf_current_task_under_cgroup_proto", + "bpf_get_prandom_u32_proto", "bpf_probe_write_user_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", + "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_probe_read_compat_proto", "bpf_probe_read_compat_str_proto", + "bpf_get_current_cgroup_id_proto", "bpf_get_current_ancestor_cgroup_id_proto", "bpf_send_signal_proto", "bpf_send_signal_thread_proto", + "bpf_perf_event_read_value_proto", "bpf_get_ns_current_pid_tgid_proto", "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", + "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", "bpf_ringbuf_query_proto", "bpf_jiffies64_proto", + "bpf_get_task_stack_proto", "bpf_copy_from_user_proto", "bpf_snprintf_btf_proto", "bpf_per_cpu_ptr_proto", + "bpf_this_cpu_ptr_proto", "bpf_task_storage_get_proto", "bpf_task_storage_delete_proto", "bpf_for_each_map_elem_proto", + "bpf_snprintf_proto", "bpf_get_func_ip_proto_tracing", + // bpf_base_func_proto + //"bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", + //"bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_get_prandom_u32_proto", "bpf_get_raw_smp_processor_id_proto", + //"bpf_get_numa_node_id_proto", "bpf_tail_call_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", + //"bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", + //"bpf_ringbuf_query_proto", "bpf_for_each_map_elem_proto", "bpf_spin_lock_proto", + "bpf_spin_unlock_proto", + //"bpf_jiffies64_proto", "bpf_per_cpu_ptr_proto", "bpf_this_cpu_ptr_proto", + "bpf_timer_init_proto", "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", + //"bpf_trace_printk_proto", "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", "bpf_probe_read_user_proto", + //"bpf_probe_read_kernel_proto", "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_snprintf_btf_proto", + //"bpf_snprintf_proto", "bpf_task_pt_regs_proto", + }}, +// BPF_PROG_TYPE_STRUCT_OPS: &BpfProgTypeDef{ +// Name: "bpf_struct_ops", +// User: "void *", +// Kern: "void *", +// Enum: BPF_PROG_TYPE_STRUCT_OPS, +// SecDefs: []SecDef{ +// SecDef{"struct_ops+", nil, false} +// }, +// FuncProtos: []string{//XXX: why missing this prog type +// }}, +// BPF_PROG_TYPE_EXT: &BpfProgTypeDef{ +// Name: "bpf_extension", +// User: "void *", +// Kern: "void *", +// Enum: BPF_PROG_TYPE_EXT, +// SecDefs: []SecDef{ +// SecDef{"freplace/", nil, false} +// }, +// FuncProtos: []string{//XXX: why missing this prog type +// }}, +// BPF_PROG_TYPE_LSM: &BpfProgTypeDef{ +// Name: "lsm", +// User: "void *", +// Kern: "void *", +// Enum: BPF_PROG_TYPE_LSM, +// SecDefs: []SecDef{ +// SecDef{"lsm/", nil, false}, +// SecDef{"lsm.s/", nil, true}, +// }, +// FuncProtos: []string{//XXX: why missing this prog type +// "bpf_inode_storage_get_proto","bpf_inode_storage_delete_proto","bpf_sk_storage_get_proto", "bpf_sk_storage_delete_proto", +// "bpf_spin_lock_proto", "bpf_spin_unlock_proto", "bpf_bprm_opts_set_proto", "bpf_ima_inode_hash_proto", +// //bpf_tracing_func_proto +// "bpf_map_lookup_elem_proto", "bpf_map_update_elem_proto", "bpf_map_delete_elem_proto", "bpf_map_push_elem_proto", +// "bpf_map_pop_elem_proto", "bpf_map_peek_elem_proto", "bpf_ktime_get_ns_proto", "bpf_ktime_get_boot_ns_proto", +// "bpf_tail_call_proto", "bpf_get_current_pid_tgid_proto", "bpf_get_current_task_proto", "bpf_get_current_task_btf_proto", +// "bpf_task_pt_regs_proto", "bpf_get_current_uid_gid_proto", "bpf_get_current_comm_proto", "bpf_trace_printk_proto", +// "bpf_get_smp_processor_id_proto", "bpf_get_numa_node_id_proto", "bpf_perf_event_read_proto", "bpf_current_task_under_cgroup_proto", +// "bpf_get_prandom_u32_proto", "bpf_probe_write_user_proto", "bpf_probe_read_user_proto", "bpf_probe_read_kernel_proto", +// "bpf_probe_read_user_str_proto", "bpf_probe_read_kernel_str_proto", "bpf_probe_read_compat_proto", "bpf_probe_read_compat_str_proto", +// "bpf_get_current_cgroup_id_proto", "bpf_get_current_ancestor_cgroup_id_proto", "bpf_send_signal_proto", "bpf_send_signal_thread_proto", +// "bpf_perf_event_read_value_proto", "bpf_get_ns_current_pid_tgid_proto", "bpf_ringbuf_output_proto", "bpf_ringbuf_reserve_proto", +// "bpf_ringbuf_submit_proto", "bpf_ringbuf_discard_proto", "bpf_ringbuf_query_proto", "bpf_jiffies64_proto", +// "bpf_get_task_stack_proto", "bpf_copy_from_user_proto", "bpf_snprintf_btf_proto", "bpf_per_cpu_ptr_proto", +// "bpf_this_cpu_ptr_proto", "bpf_task_storage_get_proto", "bpf_task_storage_delete_proto", "bpf_for_each_map_elem_proto", +// "bpf_snprintf_proto", /*"bpf_get_func_ip_proto_tracing",*/ /*"bpf_spin_lock_proto", "bpf_spin_unlock_proto",*/ +// "bpf_timer_init_proto", "bpf_timer_set_callback_proto", "bpf_timer_start_proto", "bpf_timer_cancel_proto", +// }}, +// "bpf_syscall": &BpfProgTypeDef{ +// Name: "bpf_syscall", +// User: "void *", +// Kern: "void *", +// Enum: "BPF_PROG_SYSCALL", +// SecDefs: []SecDef{ +// SecDef{"syscall/", nil} +// }, +// FuncProtos: []string{//XXX: why missing this prog type +// }}, +} + +type TracingIterCtx struct { + Name string + Ctx *StructDef +} + +/* +./kernel/bpf/map_iter.c:DEFINE_BPF_ITER_FUNC(bpf_map, struct bpf_iter_meta *meta, struct bpf_map *map) +./kernel/bpf/map_iter.c:DEFINE_BPF_ITER_FUNC(bpf_map_elem, struct bpf_iter_meta *meta, +./kernel/bpf/prog_iter.c:DEFINE_BPF_ITER_FUNC(bpf_prog, struct bpf_iter_meta *meta, struct bpf_prog *prog) +./kernel/bpf/task_iter.c:DEFINE_BPF_ITER_FUNC(task, struct bpf_iter_meta *meta, struct task_struct *task) +./kernel/bpf/task_iter.c:DEFINE_BPF_ITER_FUNC(task_file, struct bpf_iter_meta *meta, +./kernel/bpf/task_iter.c:DEFINE_BPF_ITER_FUNC(task_vma, struct bpf_iter_meta *meta, +./net/unix/af_unix.c:DEFINE_BPF_ITER_FUNC(unix, struct bpf_iter_meta *meta, +./net/ipv4/udp.c:DEFINE_BPF_ITER_FUNC(udp, struct bpf_iter_meta *meta, +./net/ipv4/tcp_ipv4.c:DEFINE_BPF_ITER_FUNC(tcp, struct bpf_iter_meta *meta, +./net/core/bpf_sk_storage.c:DEFINE_BPF_ITER_FUNC(bpf_sk_storage_map, struct bpf_iter_meta *meta, +./net/core/sock_map.c:DEFINE_BPF_ITER_FUNC(sockmap, struct bpf_iter_meta *meta, +./net/netlink/af_netlink.c:DEFINE_BPF_ITER_FUNC(netlink, struct bpf_iter_meta *meta, struct netlink_sock *sk) +./net/ipv6/route.c:DEFINE_BPF_ITER_FUNC(ipv6_route, struct bpf_iter_meta *meta, struct fib6_info *rt) +*/ +var tracingIterCtxs = []TracingIterCtx{ + TracingIterCtx{Name:"bpf_map", Ctx: nil}, + TracingIterCtx{Name:"bpf_map_elem", Ctx: nil}, + TracingIterCtx{Name:"bpf_prog", Ctx: nil}, + TracingIterCtx{Name:"task", Ctx: nil}, + TracingIterCtx{Name:"task_file", Ctx: nil}, + TracingIterCtx{Name:"task_vma", Ctx: nil}, + TracingIterCtx{Name:"unix", Ctx: nil}, + TracingIterCtx{Name:"udp", Ctx: nil}, + TracingIterCtx{Name:"tcp", Ctx: nil}, + TracingIterCtx{Name:"bpf_sk_storage_map", Ctx: nil}, + TracingIterCtx{Name:"sockmap", Ctx: nil}, + TracingIterCtx{Name:"netlink", Ctx: nil}, + TracingIterCtx{Name:"ipv6_route", Ctx: nil}, +} + +func GenXdpEntry(r *randGen) (string, *StructDef) { + return "", nil +} + +func GenKprobeEntry(r *randGen) (string, *StructDef) { + return "__x64_sys_nanosleep", nil +} + +func GenTracepointEntry(r *randGen) (string, *StructDef) { + return "sched/sched_switch", nil +} + +func GenRawTracepointEntry(r *randGen) (string, *StructDef) { + return "sys_enter", nil +} + +func GenBPFTrampoline(r *randGen) (string, *StructDef) { + return "__x64_sys_getpgid", nil +} + +func GenTracingIter(r *randGen) (string, *StructDef) { + i := r.Intn(len(tracingIterCtxs)) + return tracingIterCtxs[i].Name, nil +} + +var CtxAccessMap = map[BpfProgTypeEnum]*BpfCtxAccess{ + BPF_PROG_TYPE_CGROUP_SOCK_ADDR: &BpfCtxAccess{ + regTypeMap: map[string][][]string{ + "PTR_TO_SOCKET": [][]string{[]string{"offsetof", "struct bpf_sock_addr", "sk", ""}}, + }, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"user_ip4", "user_ip4"}, canRead: true, defaultSize: 4, narrowAccess: true, attachTypes: []string{ + "BPF_CGROUP_INET4_BIND", "BPF_CGROUP_INET4_CONNECT", "BPF_CGROUP_INET4_GETPEERNAME", "BPF_CGROUP_INET4_GETSOCKNAME", "BPF_CGROUP_UDP4_SENDMSG", "BPF_CGROUP_UDP4_RECVMSG"},}, + {rangeInCtx: []string{"user_ip6[0]", "user_ip6[3]"}, canRead: true, defaultSize: 4, wideAccess: true, narrowAccess: true, attachTypes: []string{ + "BPF_CGROUP_INET6_BIND", "BPF_CGROUP_INET6_CONNECT", "BPF_CGROUP_INET6_GETPEERNAME", "BPF_CGROUP_INET6_GETSOCKNAME", "BPF_CGROUP_UDP6_SENDMSG", "BPF_CGROUP_UDP6_RECVMSG"},}, + {rangeInCtx: []string{"msg_src_ip4", "msg_src_ip4"}, canRead: true, defaultSize: 4, narrowAccess: true, attachTypes: []string{ + "BPF_CGROUP_UDP4_SENDMSG"},}, + {rangeInCtx: []string{"msg_src_ip6[0]", "msg_src_ip6[3]"}, canRead: true, defaultSize: 4, wideAccess: true, narrowAccess: true, attachTypes: []string{ + "BPF_CGROUP_UDP6_SENDMSG"},}, + {rangeInCtx: []string{"user_ip4", "user_ip4"}, canWrite: true, size: 4, attachTypes: []string{ + "BPF_CGROUP_INET4_BIND", "BPF_CGROUP_INET4_CONNECT", "BPF_CGROUP_INET4_GETPEERNAME", "BPF_CGROUP_INET4_GETSOCKNAME", "BPF_CGROUP_UDP4_SENDMSG", "BPF_CGROUP_UDP4_RECVMSG"},}, + {rangeInCtx: []string{"user_ip6[0]", "user_ip6[3]"}, canWrite: true, size: 4, defaultSize: 4, wideAccess: true, attachTypes: []string{ + "BPF_CGROUP_INET6_BIND", "BPF_CGROUP_INET6_CONNECT", "BPF_CGROUP_INET6_GETPEERNAME", "BPF_CGROUP_INET6_GETSOCKNAME", "BPF_CGROUP_UDP6_SENDMSG", "BPF_CGROUP_UDP6_RECVMSG"},}, + {rangeInCtx: []string{"msg_src_ip4", "msg_src_ip4"}, canWrite: true, size: 4, attachTypes: []string{ + "BPF_CGROUP_UDP4_SENDMSG"},}, + {rangeInCtx: []string{"msg_src_ip6[0]", "msg_src_ip6[3]"}, canWrite: true, size: 4, defaultSize: 4, wideAccess: true, attachTypes: []string{ + "BPF_CGROUP_UDP6_SENDMSG"},}, + {rangeInCtx: []string{"sk"}, canRead: true, size: 8, regType: &PtrToSocketRegType{},}, + {rangeInCtx: []string{"default"}, canRead: true, size: 4,}, + }, + }, + BPF_PROG_TYPE_SCHED_CLS: &BpfCtxAccess{ + regTypeMap: map[string][][]string{ + "PTR_TO_SOCK_COMMON_OR_NULL": [][]string{[]string{"offsetof", "struct __sk_buff", "sk", ""}}, + "PTR_TO_PACKET": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data", ""}}, + "PTR_TO_PACKET_META": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data_meta", ""}}, + "PTR_TO_PACKET_END": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data_end", ""}}, + }, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"family", "local_port"},}, + {rangeInCtx: []string{"mark", "mark"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"mark", "mark"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"tc_index", "tc_index"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"tc_index", "tc_index"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"priority", "priority"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"priority", "priority"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"tc_classid", "tc_classid"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"tc_classid", "tc_classid"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"queue_mapping", "queue_mapping"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"queue_mapping", "queue_mapping"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"cb[0]", "cb[4]"}, canRead: true, canWrite: true,}, + {rangeInCtx: []string{"remote_ip6[0]", "remote_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"local_ip6[0]", "local_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"remote_ip4", "remote_ip4"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"data", "data"}, canRead: true, canWrite: true, size: 4, regType: &PtrToPacketRegType{},}, + {rangeInCtx: []string{"data_meta", "data_meta"}, canRead: true, canWrite: true, size: 4, regType: &PtrToPacketMetaRegType{},}, + {rangeInCtx: []string{"data_end", "data_end"}, canRead: true, canWrite: true, size: 4, regType: &PtrToPacketEndRegType{},}, + {rangeInCtx: []string{"flow_keys", "flow_keys"},}, + {rangeInCtx: []string{"tstamp", "tstamp"}, canRead: true, canWrite: true, size: 8,}, + {rangeInCtx: []string{"sk"}, canRead: true, size: 8, regType: &PtrToSockCommonRegType{},}, + {rangeInCtx: []string{"default"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"default"}, canRead: true, defaultSize: 4, narrowAccess: true}, + }, + }, + BPF_PROG_TYPE_SCHED_ACT: &BpfCtxAccess{ + regTypeMap: map[string][][]string{ + "PTR_TO_SOCK_COMMON_OR_NULL": [][]string{[]string{"offsetof", "struct __sk_buff", "sk", ""}}, + "PTR_TO_PACKET": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data", ""}}, + "PTR_TO_PACKET_META": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data_meta", ""}}, + "PTR_TO_PACKET_END": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data_end", ""}}, + }, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"family", "local_port"},}, + {rangeInCtx: []string{"mark", "mark"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"mark", "mark"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"tc_index", "tc_index"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"tc_index", "tc_index"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"priority", "priority"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"priority", "priority"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"tc_classid", "tc_classid"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"tc_classid", "tc_classid"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"queue_mapping", "queue_mapping"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"queue_mapping", "queue_mapping"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"cb[0]", "cb[4]"}, canRead: true, canWrite: true,}, + {rangeInCtx: []string{"remote_ip6[0]", "remote_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"local_ip6[0]", "local_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"remote_ip4", "remote_ip4"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"data", "data"}, canRead: true, canWrite: true, size: 4, regType: &PtrToPacketRegType{},}, + {rangeInCtx: []string{"data_meta", "data_meta"}, canRead: true, canWrite: true, size: 4, regType: &PtrToPacketMetaRegType{},}, + {rangeInCtx: []string{"data_end", "data_end"}, canRead: true, canWrite: true, size: 4, regType: &PtrToPacketEndRegType{},}, + {rangeInCtx: []string{"flow_keys", "flow_keys"},}, + {rangeInCtx: []string{"tstamp", "tstamp"}, canRead: true, canWrite: true, size: 8,}, + {rangeInCtx: []string{"sk"}, canRead: true, size: 8, regType: &PtrToSockCommonRegType{},}, + {rangeInCtx: []string{"default"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"default"}, canRead: true, defaultSize: 4, narrowAccess: true}, + }, + }, + BPF_PROG_TYPE_LWT_OUT: &BpfCtxAccess{ + regTypeMap: map[string][][]string{ + "PTR_TO_PACKET": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data", ""}}, + "PTR_TO_PACKET_END": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data_end", ""}}, + "PTR_TO_SOCK_COMMON_OR_NULL": [][]string{[]string{"offsetof", "struct __sk_buff", "sk", ""}}, + }, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"tc_classid"},}, + {rangeInCtx: []string{"family", "local_port"},}, + {rangeInCtx: []string{"data_meta"},}, + {rangeInCtx: []string{"tstamp"},}, + {rangeInCtx: []string{"wire_len"},}, + // + {rangeInCtx: []string{"mark"}, canRead: true, canWrite: true,}, + {rangeInCtx: []string{"priority"}, canRead: true, canWrite: true,}, + {rangeInCtx: []string{"cb[0]", "cb[4]"}, canRead: true, canWrite: true,}, + //bpf_skb_is_valid_access + {rangeInCtx: []string{"remote_ip6[0]", "remote_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"local_ip6[0]", "local_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"remote_ip4", "remote_ip4"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"data"}, canRead: true, canWrite: true, size: 4, regType: &PtrToPacketRegType{}}, + {rangeInCtx: []string{"data_meta"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"data_end"}, canRead: true, canWrite: true, size: 4, regType: &PtrToPacketEndRegType{}}, + {rangeInCtx: []string{"flow_keys"},}, + {rangeInCtx: []string{"tstamp"}, canRead: true, canWrite: true, size: 8,}, + {rangeInCtx: []string{"sk"}, canRead: true, size: 8, regType: &PtrToSockCommonRegType{},}, + {rangeInCtx: []string{"default"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"default"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + }, + }, + BPF_PROG_TYPE_LWT_XMIT: &BpfCtxAccess{ + regTypeMap: map[string][][]string{ + "PTR_TO_PACKET": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data", ""}}, + "PTR_TO_PACKET_END": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data_end", ""}}, + "PTR_TO_SOCK_COMMON_OR_NULL": [][]string{[]string{"offsetof", "struct __sk_buff", "sk", ""}}, + }, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"tc_classid"},}, + {rangeInCtx: []string{"family", "local_port"},}, + {rangeInCtx: []string{"data_meta"},}, + {rangeInCtx: []string{"tstamp"},}, + {rangeInCtx: []string{"wire_len"},}, + // + {rangeInCtx: []string{"mark"}, canRead: true, canWrite: true,}, + {rangeInCtx: []string{"priority"}, canRead: true, canWrite: true,}, + {rangeInCtx: []string{"cb[0]", "cb[4]"}, canRead: true, canWrite: true,}, + //bpf_skb_is_valid_access + {rangeInCtx: []string{"remote_ip6[0]", "remote_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"local_ip6[0]", "local_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"remote_ip4", "remote_ip4"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"data", "data"}, canRead: true, canWrite: true, size: 4, regType: &PtrToPacketRegType{}}, + {rangeInCtx: []string{"data_meta", "data_meta"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"data_end", "data_end"}, canRead: true, canWrite: true, size: 4, regType: &PtrToPacketEndRegType{}}, + {rangeInCtx: []string{"flow_keys", "flow_keys"},}, + {rangeInCtx: []string{"tstamp", "tstamp"}, canRead: true, canWrite: true, size: 8,}, + {rangeInCtx: []string{"sk"}, canRead: true, size: 8, regType: &PtrToSockCommonRegType{},}, + {rangeInCtx: []string{"default"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"default"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + }, + }, + BPF_PROG_TYPE_PERF_EVENT: &BpfCtxAccess{ + regTypeMap: map[string][][]string{}, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"sample_period", "sample_period"}, canRead: true, defaultSize: 8, narrowAccess: true,}, + {rangeInCtx: []string{"addr", "addr"}, canRead: true, defaultSize: 8, narrowAccess: true,}, + {rangeInCtx: []string{"default"}, canRead: true, size: 4,}, + }, + }, + BPF_PROG_TYPE_KPROBE: &BpfCtxAccess{ + regTypeMap: map[string][][]string{}, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"default"}, canRead: true,}, + }, + }, + BPF_PROG_TYPE_TRACEPOINT: &BpfCtxAccess{ + regTypeMap: map[string][][]string{}, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"default"}, canRead: true,}, + }, + }, + BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE: &BpfCtxAccess{ + regTypeMap: map[string][][]string{}, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"default"}, canRead: true,}, + }, + }, + BPF_PROG_TYPE_RAW_TRACEPOINT: &BpfCtxAccess{ + regTypeMap: map[string][][]string{}, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"default"}, canRead: true,}, + }, + }, + BPF_PROG_TYPE_TRACING: &BpfCtxAccess{ + regTypeMap: map[string][][]string{}, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"default"}, canRead: true,}, //XXX btf_ctx_access + }, + }, + BPF_PROG_TYPE_CGROUP_SYSCTL: &BpfCtxAccess{ + regTypeMap: map[string][][]string{}, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"write"}, canRead: true, defaultSize: 4, narrowAccess: true}, + {rangeInCtx: []string{"file_pos"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"file_pos"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"default"},}, + }, + }, + BPF_PROG_TYPE_XDP: &BpfCtxAccess{ + regTypeMap: map[string][][]string{ + "PTR_TO_PACKET": [][]string{[]string{"offsetof", "struct xdp_md", "data", ""}}, + "PTR_TO_PACKET_META": [][]string{[]string{"offsetof", "struct xdp_md", "data_meta", ""}}, + "PTR_TO_PACKET_END": [][]string{[]string{"offsetof", "struct xdp_md", "data_end", ""}}, + }, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"data"}, canRead: true, size: 4, regType: &PtrToPacketRegType{},}, + {rangeInCtx: []string{"data_meta"}, canRead: true, size: 4, regType: &PtrToPacketMetaRegType{},}, + {rangeInCtx: []string{"data_end"}, canRead: true, size: 4, regType: &PtrToPacketEndRegType{},}, + {rangeInCtx: []string{"rx_queue_index"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"default"}, canRead: true, size: 4,}, + }, + }, + BPF_PROG_TYPE_LIRC_MODE2: &BpfCtxAccess{ + regTypeMap: map[string][][]string{}, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"default"}, canRead: true, size: 4,}, + }, + }, + BPF_PROG_TYPE_SK_REUSEPORT: &BpfCtxAccess{ + regTypeMap: map[string][][]string{ + "PTR_TO_PACKET_END": [][]string{[]string{"offsetof", "struct sk_reuseport_md", "data_end", ""}}, + "PTR_TO_SOCKET": [][]string{[]string{"offsetof", "struct sk_reuseport_md", "sk", ""}}, + "PTR_TO_SOCK_COMMON_OR_NULL": [][]string{[]string{"offsetof", "struct sk_reuseport_md", "migrating_sk", ""}}, + "PTR_TO_PACKET": [][]string{[]string{"offsetof", "struct sk_reuseport_md", "data", ""}}, + }, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"data"}, canRead: true, size: 8, regType: &PtrToPacketRegType{},}, + {rangeInCtx: []string{"data_end"}, canRead: true, size: 8, regType: &PtrToPacketEndRegType{},}, + {rangeInCtx: []string{"hash"}, canRead: true, size: 4,}, + {rangeInCtx: []string{"sk", "sk"}, canRead: true, size: 8, regType: &PtrToSocketRegType{},}, + {rangeInCtx: []string{"migrating_sk", "migrating_sk"}, canRead: true, size: 8, regType: &PtrToSockCommonRegType{},}, + {rangeInCtx: []string{"eth_protocol", "eth_protocol"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"ip_protocol", "ip_protocol"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"bind_inany", "bind_inany"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"len", "len"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"default"},}, + }, + }, + BPF_PROG_TYPE_SOCK_OPS: &BpfCtxAccess{ + regTypeMap: map[string][][]string{ + "PTR_TO_SOCKET_OR_NULL": [][]string{[]string{"offsetof", "struct bpf_sock_ops", "sk", ""}}, + "PTR_TO_PACKET": [][]string{[]string{"offsetof", "struct bpf_sock_ops", "skb_data", ""}}, + "PTR_TO_PACKET_END": [][]string{[]string{"offsetof", "struct bpf_sock_ops", "skb_data_end", ""}}, + }, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + //{rangeInCtx: []string{"reply"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"args[0]", "args[0]"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"sk_txhash"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"bytes_received", "bytes_acked"}, canRead: true, size: 8,}, + {rangeInCtx: []string{"sk"}, canRead: true, size: 8, regType: &PtrToSocketRegType{},}, + {rangeInCtx: []string{"skb_data"}, canRead: true, size: 8, regType: &PtrToPacketRegType{},}, + {rangeInCtx: []string{"skb_data_end"}, canRead: true, size: 8, regType: &PtrToPacketEndRegType{},}, + {rangeInCtx: []string{"default"}, canRead: true, size: 4,}, + }, + }, + BPF_PROG_TYPE_CGROUP_SKB: &BpfCtxAccess{ + regTypeMap: map[string][][]string{ + "PTR_TO_SOCK_COMMON_OR_NULL": [][]string{[]string{"offsetof", "struct __sk_buff", "sk", ""}}, + "PTR_TO_PACKET": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data", ""}}, + "PTR_TO_PACKET_END": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data_end", ""}}, + }, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"tc_classid"},}, + {rangeInCtx: []string{"data_meta"},}, + {rangeInCtx: []string{"wire_len"},}, +// {rangeInCtx: []string{"data"},}, +// {rangeInCtx: []string{"data_end"},}, + {rangeInCtx: []string{"mark"}, canRead: true, canWrite: true,}, + {rangeInCtx: []string{"priority"}, canRead: true, canWrite: true,}, +// {rangeInCtx: []string{"cb[0]", "cb[4]"}, canRead: true, canWrite: true,}, +// {rangeInCtx: []string{"tstamp"}, canRead: true, canWrite: true,}, + {rangeInCtx: []string{"cb[0]", "cb[4]"}, canRead: true, canWrite: true,}, + {rangeInCtx: []string{"remote_ip6[0]", "remote_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"local_ip6[0]", "local_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"remote_ip4", "remote_ip4"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"data", "data"}, canRead: true, canWrite: true, size: 4, regType: &PtrToPacketRegType{}}, + {rangeInCtx: []string{"data_meta", "data_meta"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"data_end", "data_end"}, canRead: true, canWrite: true, size: 4, regType: &PtrToPacketEndRegType{}}, + {rangeInCtx: []string{"flow_keys", "flow_keys"},}, + {rangeInCtx: []string{"tstamp", "tstamp"}, canRead: true, canWrite: true, size: 8,}, + {rangeInCtx: []string{"sk"}, canRead: true, size: 8, regType: &PtrToSockCommonRegType{},}, + {rangeInCtx: []string{"default"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"default"}, canRead: true, defaultSize: 4, narrowAccess: true,}, +//bpf_skb_is_valid_access +// {rangeInCtx: []string{"cb[0]", "cb[4]"}, canRead: true, canWrite: true,}, +// {rangeInCtx: []string{"remote_ip6[0]", "remote_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"local_ip6[0]", "local_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"remote_ip4", "remote_ip4"}, canRead: true, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"data", "data"}, canRead: true, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"data_meta", "data_meta"}, canRead: true, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"data_end", "data_end"}, canRead: true, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"flow_keys", "flow_keys"},}, +// {rangeInCtx: []string{"tstamp", "tstamp"}, canRead: true, canWrite: true, size: 8,}, +// {rangeInCtx: []string{"sk"}, canRead: true, size: 8, regType: &PtrToSockCommonRegType{},}, +// {rangeInCtx: []string{"default"}, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"default"}, canRead: true, defaultSize: 4, narrowAccess: true}, + }, + }, + BPF_PROG_TYPE_CGROUP_SOCK: &BpfCtxAccess{ + regTypeMap: map[string][][]string{}, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"state"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"family"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"type"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"protocol"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"dst_port"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"src_port"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"rx_queue_mapping"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"src_ip4", "src_ip4"}, canRead: true, defaultSize: 4, narrowAccess: true, attachTypes: []string{"BPF_CGROUP_INET4_POST_BIND"},}, + {rangeInCtx: []string{"src_ip6[0]", "src_ip6[3]"}, canRead: true, defaultSize: 4, narrowAccess: true, attachTypes: []string{"BPF_CGROUP_INET6_POST_BIND"},}, + {rangeInCtx: []string{"dst_ip4", "dst_ip4"}, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"dst_ip6[0]", "dst_ip6[3]"}, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"bound_dev_if"}, canRead: true, canWrite: true, defaultSize: 4, attachTypes: []string{"BPF_CGROUP_INET_SOCK_CREATE","BPF_CGROUP_INET_SOCK_RELEASE"},}, + {rangeInCtx: []string{"mark"}, canRead: true, canWrite: true, defaultSize: 4, attachTypes: []string{"BPF_CGROUP_INET_SOCK_CREATE","BPF_CGROUP_INET_SOCK_RELEASE"},}, + {rangeInCtx: []string{"priority"}, canRead: true, canWrite: true, defaultSize: 4, attachTypes: []string{"BPF_CGROUP_INET_SOCK_CREATE","BPF_CGROUP_INET_SOCK_RELEASE"},}, + {rangeInCtx: []string{"src_port"}, canRead: true, defaultSize: 4, attachTypes: []string{"BPF_CGROUP_INET4_POST_BIND","BPF_CGROUP_INET6_POST_BIND"},}, + {rangeInCtx: []string{"default"}, canRead: true, defaultSize: 4,}, + }, + }, + BPF_PROG_TYPE_LWT_IN: &BpfCtxAccess{ + regTypeMap: map[string][][]string{ + "PTR_TO_PACKET": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data", ""}}, + "PTR_TO_PACKET_END": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data_end", ""}}, + "PTR_TO_SOCK_COMMON_OR_NULL": [][]string{[]string{"offsetof", "struct __sk_buff", "sk", ""}}, + }, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"tc_classid"},}, + {rangeInCtx: []string{"family", "local_port"},}, + {rangeInCtx: []string{"data_meta"},}, + {rangeInCtx: []string{"tstamp"},}, + {rangeInCtx: []string{"wire_len"},}, + // + {rangeInCtx: []string{"mark"}, canRead: true, canWrite: true,}, + {rangeInCtx: []string{"priority"}, canRead: true, canWrite: true,}, + {rangeInCtx: []string{"cb[0]", "cb[4]"}, canRead: true, canWrite: true,}, + //bpf_skb_is_valid_access + {rangeInCtx: []string{"remote_ip6[0]", "remote_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"local_ip6[0]", "local_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"remote_ip4", "remote_ip4"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"data", "data"}, canRead: true, canWrite: true, size: 4, regType: &PtrToPacketRegType{}}, + {rangeInCtx: []string{"data_meta", "data_meta"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"data_end", "data_end"}, canRead: true, canWrite: true, size: 4, regType: &PtrToPacketEndRegType{}}, + {rangeInCtx: []string{"flow_keys", "flow_keys"},}, + {rangeInCtx: []string{"tstamp", "tstamp"}, canRead: true, canWrite: true, size: 8,}, + {rangeInCtx: []string{"sk"}, canRead: true, size: 8, regType: &PtrToSockCommonRegType{},}, + {rangeInCtx: []string{"default"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"default"}, canRead: true, defaultSize: 4, narrowAccess: true,}, +//bpf_skb_is_valid_access +// {rangeInCtx: []string{"cb[0]", "cb[4]"}, canRead: true, canWrite: true,}, +// {rangeInCtx: []string{"remote_ip6[0]", "remote_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"local_ip6[0]", "local_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"remote_ip4", "remote_ip4"}, canRead: true, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"data"}, canRead: true, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"data_meta"}, canRead: true, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"data_end"}, canRead: true, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"flow_keys"},}, +// {rangeInCtx: []string{"tstamp"}, canRead: true, canWrite: true, size: 8,}, +// {rangeInCtx: []string{"sk"}, canRead: true, size: 8, regType: &PtrToSockCommonRegType{},}, +// {rangeInCtx: []string{"default"}, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"default"}, canRead: true, defaultSize: 4, narrowAccess: true}, + }, + }, + BPF_PROG_TYPE_LWT_SEG6LOCAL: &BpfCtxAccess{ + regTypeMap: map[string][][]string{ + "PTR_TO_PACKET_END": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data_end", ""}}, + "PTR_TO_PACKET": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data", ""}}, + "PTR_TO_SOCK_COMMON_OR_NULL": [][]string{[]string{"offsetof", "struct __sk_buff", "sk", ""}}, + }, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"tc_classid"},}, + {rangeInCtx: []string{"family", "local_port"},}, + {rangeInCtx: []string{"data_meta"},}, + {rangeInCtx: []string{"tstamp"},}, + {rangeInCtx: []string{"wire_len"},}, + // + {rangeInCtx: []string{"mark"}, canRead: true, canWrite: true,}, + {rangeInCtx: []string{"priority"}, canRead: true, canWrite: true,}, + {rangeInCtx: []string{"cb[0]", "cb[4]"}, canRead: true, canWrite: true,}, + //bpf_skb_is_valid_access + {rangeInCtx: []string{"remote_ip6[0]", "remote_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"local_ip6[0]", "local_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"remote_ip4", "remote_ip4"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"data", "data"}, canRead: true, canWrite: true, size: 4, regType: &PtrToPacketRegType{}}, + {rangeInCtx: []string{"data_meta", "data_meta"}, canRead: true, canWrite: true, size: 4,}, + {rangeInCtx: []string{"data_end", "data_end"}, canRead: true, canWrite: true, size: 4, regType: &PtrToPacketEndRegType{}}, + {rangeInCtx: []string{"flow_keys", "flow_keys"},}, + {rangeInCtx: []string{"tstamp", "tstamp"}, canRead: true, canWrite: true, size: 8,}, + {rangeInCtx: []string{"sk"}, canRead: true, size: 8, regType: &PtrToSockCommonRegType{},}, + {rangeInCtx: []string{"default"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"default"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + }, + }, + BPF_PROG_TYPE_SK_SKB: &BpfCtxAccess{ + regTypeMap: map[string][][]string{ + "PTR_TO_PACKET": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data", ""}}, + "PTR_TO_PACKET_END": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data_end", ""}}, + "PTR_TO_SOCK_COMMON_OR_NULL": [][]string{[]string{"offsetof", "struct __sk_buff", "sk", ""}}, + }, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"tc_classid", "tc_classid"},}, + {rangeInCtx: []string{"data_meta", "data_meta"},}, + {rangeInCtx: []string{"tstamp", "tstamp"},}, + {rangeInCtx: []string{"wire_len", "wire_len"},}, + {rangeInCtx: []string{"tc_index", "tc_index"}, canWrite: true,}, + {rangeInCtx: []string{"priority", "priority"}, canWrite: true,}, + {rangeInCtx: []string{"mark", "mark"},}, +// {rangeInCtx: []string{"data", "data"}, regType}, +// {rangeInCtx: []string{"data_end", "data_end"}, regType}, +//bpf_skb_is_valid_access + {rangeInCtx: []string{"cb[0]", "cb[4]"}, canRead: true, /*canWrite: true,*/}, + {rangeInCtx: []string{"remote_ip6[0]", "remote_ip6[3]"}, canRead: true, /*canWrite: true,*/ size: 4,}, + {rangeInCtx: []string{"local_ip6[0]", "local_ip6[3]"}, canRead: true, /*canWrite: true,*/ size: 4,}, + {rangeInCtx: []string{"remote_ip4", "remote_ip4"}, canRead: true, /*canWrite: true,*/ size: 4,}, + {rangeInCtx: []string{"data", "data"}, canRead: true, /*canWrite: true,*/ size: 4, regType: &PtrToPacketRegType{},}, +// {rangeInCtx: []string{"data_meta", "data_meta"}, canRead: true, /*canWrite: true,*/ size: 4,}, + {rangeInCtx: []string{"data_end", "data_end"}, canRead: true, /*canWrite: true,*/ size: 4, regType: &PtrToPacketEndRegType{},}, + {rangeInCtx: []string{"flow_keys", "flow_keys"},}, + {rangeInCtx: []string{"tstamp", "tstamp"}, canRead: true, /*canWrite: true,*/ size: 8,}, + {rangeInCtx: []string{"sk"}, canRead: true, size: 8, regType: &PtrToSockCommonRegType{},}, + {rangeInCtx: []string{"default"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"default"}, canRead: true, defaultSize: 4, narrowAccess: true}, + }, + }, + BPF_PROG_TYPE_SK_MSG: &BpfCtxAccess{ + regTypeMap: map[string][][]string{ + "PTR_TO_PACKET": [][]string{[]string{"offsetof", "struct sk_msg_md", "data", ""}}, + "PTR_TO_PACKET_END": [][]string{[]string{"offsetof", "struct sk_msg_md", "data_end", ""}}, + "PTR_TO_SOCKET": [][]string{[]string{"offsetof", "struct sk_msg_md", "sk", ""}}, + }, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"data", "data"}, canRead: true, size: 8, regType: &PtrToPacketRegType{},}, + {rangeInCtx: []string{"data_end", "data_end"}, canRead: true, size: 8, regType: &PtrToPacketEndRegType{},}, + {rangeInCtx: []string{"sk"}, canRead: true, size: 8, regType: &PtrToSocketRegType{},}, + {rangeInCtx: []string{"family", "family"}, canRead: true, size: 4,}, + {rangeInCtx: []string{"remote_ip4", "remote_ip4"}, canRead: true, size: 4,}, + {rangeInCtx: []string{"local_ip4", "local_ip4"}, canRead: true, size: 4,}, + {rangeInCtx: []string{"remote_ip6[0]", "remote_ip6[3]"}, canRead: true, size: 4,}, + {rangeInCtx: []string{"local_ip6[0]", "local_ip6[3]"}, canRead: true, size: 4,}, + {rangeInCtx: []string{"remote_port", "remote_port"}, canRead: true, size: 4,}, + {rangeInCtx: []string{"local_port", "local_port"}, canRead: true, size: 4,}, + {rangeInCtx: []string{"size", "size"}, canRead: true, size: 4,}, + {rangeInCtx: []string{"default"},}, + }, + }, + BPF_PROG_TYPE_FLOW_DISSECTOR: &BpfCtxAccess{ + regTypeMap: map[string][][]string{ + "PTR_TO_PACKET": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data", ""}}, + "PTR_TO_PACKET_END": [][]string{[]string{"bpf_ctx_range", "struct __sk_buff", "data_end", ""}}, + "PTR_TO_FLOW_KEYS": [][]string{[]string{"bpf_ctx_range_ptr", "struct __sk_buff", "flow_keys", ""}}, + }, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"data", "data"}, canRead: true, size: 4, regType: &PtrToPacketRegType{},}, + {rangeInCtx: []string{"data_end", "data_end"}, canRead: true, size: 4, regType: &PtrToPacketEndRegType{},}, + {rangeInCtx: []string{"flow_keys", "flow_keys"}, canRead: true, size: 4, regType: &PtrToFlowKeysRegType{},}, + {rangeInCtx: []string{"default"},}, + }, + }, + BPF_PROG_TYPE_SOCKET_FILTER: &BpfCtxAccess{ + regTypeMap: map[string][][]string{ + "PTR_TO_SOCK_COMMON_OR_NULL": [][]string{[]string{"offsetof", "struct __sk_buff", "sk", ""}}, + }, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"tc_classid", "tc_classid"},}, + {rangeInCtx: []string{"data", "data"},}, + {rangeInCtx: []string{"data_meta", "data_meta"},}, + {rangeInCtx: []string{"data_end", "data_end"},}, + {rangeInCtx: []string{"family", "local_port"},}, + {rangeInCtx: []string{"tstamp", "tstamp"},}, + {rangeInCtx: []string{"wire_len", "wire_len"},}, + {rangeInCtx: []string{"cb[0]", "cb[4]"}, canRead: true, canWrite: true,}, + {rangeInCtx: []string{"remote_ip6[0]", "remote_ip6[3]"}, canRead: true, size: 4,}, + {rangeInCtx: []string{"local_ip6[0]", "local_ip6[3]"}, canRead: true, size: 4,}, + {rangeInCtx: []string{"remote_ip4", "remote_ip4"}, canRead: true, size: 4,}, +// {rangeInCtx: []string{"data", "data"}, canRead: true, size: 4,}, +// {rangeInCtx: []string{"data_meta", "data_meta"}, canRead: true, size: 4,}, +// {rangeInCtx: []string{"data_end", "data_end"}, canRead: true, size: 4,}, + {rangeInCtx: []string{"flow_keys", "flow_keys"},}, +// {rangeInCtx: []string{"tstamp", "tstamp"}, canRead: true, size: 8,}, + {rangeInCtx: []string{"sk"}, canRead: true, size: 8, regType: &PtrToSockCommonRegType{},}, + {rangeInCtx: []string{"default"}, canRead: true, defaultSize: 4, narrowAccess: true,}, +//bpf_skb_is_valid_access +// {rangeInCtx: []string{"cb[0]", "cb[4]"}, canRead: true, canWrite: true,}, +// {rangeInCtx: []string{"remote_ip6[0]", "remote_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"local_ip6[0]", "local_ip6[3]"}, canRead: true, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"remote_ip4", "remote_ip4"}, canRead: true, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"data", "data"}, canRead: true, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"data_meta", "data_meta"}, canRead: true, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"data_end", "data_end"}, canRead: true, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"flow_keys", "flow_keys"},}, +// {rangeInCtx: []string{"tstamp", "tstamp"}, canRead: true, canWrite: true, size: 8,}, +// {rangeInCtx: []string{"sk"}, canRead: true, size: 8, regType: &PtrToSockCommonRegType{},}, +// {rangeInCtx: []string{"default"}, canWrite: true, size: 4,}, +// {rangeInCtx: []string{"default"}, canRead: true, defaultSize: 4, narrowAccess: true}, + }, + }, + BPF_PROG_TYPE_CGROUP_DEVICE: &BpfCtxAccess{ + regTypeMap: map[string][][]string{}, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"access_type", "access_type"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"default"}, canRead: true, size: 4,}, + }, + }, + BPF_PROG_TYPE_CGROUP_SOCKOPT: &BpfCtxAccess{ + regTypeMap: map[string][][]string{ + "PTR_TO_SOCKET": [][]string{[]string{"offsetof", "struct bpf_sockopt", "sk", ""}}, + "PTR_TO_PACKET": [][]string{[]string{"offsetof", "struct bpf_sockopt", "optval", ""}}, + "PTR_TO_PACKET_END": [][]string{[]string{"offsetof", "struct bpf_sockopt", "optval_end", ""}}, + }, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"retval"}, canWrite: true, size: 4, attachTypes: []string{"BPF_CGROUP_GETSOCKOPT"},}, + {rangeInCtx: []string{"optname"}, canWrite: true, size: 4, attachTypes: []string{"BPF_CGROUP_SETSOCKOPT"},}, + {rangeInCtx: []string{"level"}, canWrite: true, size: 4, attachTypes: []string{"BPF_CGROUP_SETSOCKOPT"},}, + {rangeInCtx: []string{"optlen"}, canWrite: true, size: 4,}, + {rangeInCtx: []string{"sk", "sk"}, canRead: true, size: 8, regType: &PtrToSocketRegType{},}, + {rangeInCtx: []string{"optval", "optval"}, canRead: true, size: 8, regType: &PtrToPacketRegType{},}, + {rangeInCtx: []string{"optval_end", "optval_end"}, canRead: true, size: 8, regType: &PtrToPacketEndRegType{},}, + {rangeInCtx: []string{"retval", "retval"}, canRead: true, size: 4, attachTypes: []string{"BPF_CGROUP_GETSOCKOPT"},}, + {rangeInCtx: []string{"default"}, canRead: true, size: 4,}, + }, + }, + BPF_PROG_TYPE_SK_LOOKUP: &BpfCtxAccess{ + regTypeMap: map[string][][]string{ + "PTR_TO_SOCKET_OR_NULL": [][]string{[]string{"offsetof", "struct bpf_sk_lookup", "sk", ""}}, + }, + others: map[string]*BpfCtxAccess{}, + accesses: []BpfCtxAccessAttr{ + {rangeInCtx: []string{"family", "family"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"protocol", "protocol"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"remote_ip4", "remote_ip4"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"local_ip4", "local_ip4"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"remote_ip6[0]", "remote_ip6[3]"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"local_ip6[0]", "local_ip6[3]"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"remote_port", "remote_port"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"local_port", "local_port"}, canRead: true, defaultSize: 4, narrowAccess: true,}, + {rangeInCtx: []string{"default"},}, + }, + }, +} diff --git a/prog/generation.go b/prog/generation.go index 09240e858..8fbf316b1 100644 --- a/prog/generation.go +++ b/prog/generation.go @@ -15,6 +15,7 @@ func (target *Target) Generate(rs rand.Source, ncalls int, ct *ChoiceTable) *Pro } r := newRand(target, rs) s := newState(target, ct, nil) + target.Brf.GenPrologue(r, s, p) for len(p.Calls) < ncalls { calls := r.generateCall(s, p, len(p.Calls)) for _, c := range calls { diff --git a/sys/linux/bpf.txt b/sys/linux/bpf.txt index c54bb64d3..b278449ec 100644 --- a/sys/linux/bpf.txt +++ b/sys/linux/bpf.txt @@ -92,6 +92,18 @@ type bpf_prog_xdp bpf_prog_t[const[BPF_PROG_TYPE_XDP, int32], const[BPF_XDP, int type bpf_link_create_xdp bpf_link_create_arg_t[fd_bpf_prog_xdp, ifindex, const[BPF_XDP, int32], flags[xdp_flags, int32]] xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST, XDP_FLAGS_SKB_MODE, XDP_FLAGS_DRV_MODE, XDP_FLAGS_HW_MODE, XDP_FLAGS_REPLACE +syz_bpf_prog_open(path ptr[in, filename]) +syz_bpf_prog_load(path ptr[in, filename], res ptr[out, bpf_res]) fd_bpf_prog +syz_bpf_prog_attach(path ptr[in, filename]) fd_bpf_link + + +bpf_res { + prog_fds array[fd_bpf_prog, 32] + prog_num len[prog_fds, int32] + map_fds array[fd_bpf_map, 32] + map_num len[map_fds, int32] +} + bpf_map_const_str_freeze { in fd_bpf_const_str out bpf_frozen_const_str (out_overlay) diff --git a/sys/targets/targets.go b/sys/targets/targets.go index 4c840119a..591ed040c 100644 --- a/sys/targets/targets.go +++ b/sys/targets/targets.go @@ -491,6 +491,9 @@ var oses = map[string]osCommon{ "syz_clone3": {"clone3", "exit"}, "syz_clone": {"clone", "exit"}, "syz_pidfd_open": {"pidfd_open"}, + "syz_bpf_prog_open": {"bpf$PROG_LOAD"}, + "syz_bpf_prog_load": {"bpf$PROG_LOAD"}, + "syz_bpf_prog_attach": {"bpf$BPF_PROG_ATTACH"}, }, cflags: []string{"-static-pie"}, }, diff --git a/syz-fuzzer/proc.go b/syz-fuzzer/proc.go index 2ca72107a..fdbcdf323 100644 --- a/syz-fuzzer/proc.go +++ b/syz-fuzzer/proc.go @@ -60,42 +60,42 @@ func newProc(fuzzer *Fuzzer, pid int) (*Proc, error) { } func (proc *Proc) loop() { - generatePeriod := 100 - if proc.fuzzer.config.Flags&ipc.FlagSignal == 0 { - // If we don't have real coverage signal, generate programs more frequently - // because fallback signal is weak. - generatePeriod = 2 - } +// generatePeriod := 1 +// if proc.fuzzer.config.Flags&ipc.FlagSignal == 0 { +// // If we don't have real coverage signal, generate programs more frequently +// // because fallback signal is weak. +// generatePeriod = 2 +// } for i := 0; ; i++ { - item := proc.fuzzer.workQueue.dequeue() - if item != nil { - switch item := item.(type) { - case *WorkTriage: - proc.triageInput(item) - case *WorkCandidate: - proc.execute(proc.execOpts, item.p, item.flags, StatCandidate) - case *WorkSmash: - proc.smashInput(item) - default: - log.SyzFatalf("unknown work type: %#v", item) - } - continue - } +// item := proc.fuzzer.workQueue.dequeue() +// if item != nil { +// switch item := item.(type) { +// case *WorkTriage: +// proc.triageInput(item) +// case *WorkCandidate: +// proc.execute(proc.execOpts, item.p, item.flags, StatCandidate) +// case *WorkSmash: +// proc.smashInput(item) +// default: +// log.SyzFatalf("unknown work type: %#v", item) +// } +// continue +// } ct := proc.fuzzer.choiceTable - fuzzerSnapshot := proc.fuzzer.snapshot() - if len(fuzzerSnapshot.corpus) == 0 || i%generatePeriod == 0 { +// fuzzerSnapshot := proc.fuzzer.snapshot() +// if len(fuzzerSnapshot.corpus) == 0 || i%generatePeriod == 0 { // Generate a new prog. p := proc.fuzzer.target.Generate(proc.rnd, prog.RecommendedCalls, ct) log.Logf(1, "#%v: generated", proc.pid) proc.executeAndCollide(proc.execOpts, p, ProgNormal, StatGenerate) - } else { - // Mutate an existing prog. - p := fuzzerSnapshot.chooseProgram(proc.rnd).Clone() - p.Mutate(proc.rnd, prog.RecommendedCalls, ct, proc.fuzzer.noMutate, fuzzerSnapshot.corpus) - log.Logf(1, "#%v: mutated", proc.pid) - proc.executeAndCollide(proc.execOpts, p, ProgNormal, StatFuzz) - } +// } else { +// // Mutate an existing prog. +// p := fuzzerSnapshot.chooseProgram(proc.rnd).Clone() +// p.Mutate(proc.rnd, prog.RecommendedCalls, ct, proc.fuzzer.noMutate, fuzzerSnapshot.corpus) +// log.Logf(1, "#%v: mutated", proc.pid) +// proc.executeAndCollide(proc.execOpts, p, ProgNormal, StatFuzz) +// } } } diff --git a/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go b/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go deleted file mode 100644 index d33c8890f..000000000 --- a/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.13 - -package poly1305 - -// Generic fallbacks for the math/bits intrinsics, copied from -// src/math/bits/bits.go. They were added in Go 1.12, but Add64 and Sum64 had -// variable time fallbacks until Go 1.13. - -func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) { - sum = x + y + carry - carryOut = ((x & y) | ((x | y) &^ sum)) >> 63 - return -} - -func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) { - diff = x - y - borrow - borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 63 - return -} - -func bitsMul64(x, y uint64) (hi, lo uint64) { - const mask32 = 1<<32 - 1 - x0 := x & mask32 - x1 := x >> 32 - y0 := y & mask32 - y1 := y >> 32 - w0 := x0 * y0 - t := x1*y0 + w0>>32 - w1 := t & mask32 - w2 := t >> 32 - w1 += x0 * y1 - hi = x1*y1 + w2 + w1>>32 - lo = x * y - return -} diff --git a/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go b/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go deleted file mode 100644 index 495c1fa69..000000000 --- a/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.13 - -package poly1305 - -import "math/bits" - -func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) { - return bits.Add64(x, y, carry) -} - -func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) { - return bits.Sub64(x, y, borrow) -} - -func bitsMul64(x, y uint64) (hi, lo uint64) { - return bits.Mul64(x, y) -} diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go b/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go index e041da5ea..ec2202bd7 100644 --- a/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go +++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go @@ -7,7 +7,10 @@ package poly1305 -import "encoding/binary" +import ( + "encoding/binary" + "math/bits" +) // Poly1305 [RFC 7539] is a relatively simple algorithm: the authentication tag // for a 64 bytes message is approximately @@ -114,13 +117,13 @@ type uint128 struct { } func mul64(a, b uint64) uint128 { - hi, lo := bitsMul64(a, b) + hi, lo := bits.Mul64(a, b) return uint128{lo, hi} } func add128(a, b uint128) uint128 { - lo, c := bitsAdd64(a.lo, b.lo, 0) - hi, c := bitsAdd64(a.hi, b.hi, c) + lo, c := bits.Add64(a.lo, b.lo, 0) + hi, c := bits.Add64(a.hi, b.hi, c) if c != 0 { panic("poly1305: unexpected overflow") } @@ -155,8 +158,8 @@ func updateGeneric(state *macState, msg []byte) { // hide leading zeroes. For full chunks, that's 1 << 128, so we can just // add 1 to the most significant (2¹²⁸) limb, h2. if len(msg) >= TagSize { - h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0) - h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(msg[8:16]), c) + h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0) + h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(msg[8:16]), c) h2 += c + 1 msg = msg[TagSize:] @@ -165,8 +168,8 @@ func updateGeneric(state *macState, msg []byte) { copy(buf[:], msg) buf[len(msg)] = 1 - h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0) - h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(buf[8:16]), c) + h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0) + h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(buf[8:16]), c) h2 += c msg = nil @@ -219,9 +222,9 @@ func updateGeneric(state *macState, msg []byte) { m3 := h2r1 t0 := m0.lo - t1, c := bitsAdd64(m1.lo, m0.hi, 0) - t2, c := bitsAdd64(m2.lo, m1.hi, c) - t3, _ := bitsAdd64(m3.lo, m2.hi, c) + t1, c := bits.Add64(m1.lo, m0.hi, 0) + t2, c := bits.Add64(m2.lo, m1.hi, c) + t3, _ := bits.Add64(m3.lo, m2.hi, c) // Now we have the result as 4 64-bit limbs, and we need to reduce it // modulo 2¹³⁰ - 5. The special shape of this Crandall prime lets us do @@ -243,14 +246,14 @@ func updateGeneric(state *macState, msg []byte) { // To add c * 5 to h, we first add cc = c * 4, and then add (cc >> 2) = c. - h0, c = bitsAdd64(h0, cc.lo, 0) - h1, c = bitsAdd64(h1, cc.hi, c) + h0, c = bits.Add64(h0, cc.lo, 0) + h1, c = bits.Add64(h1, cc.hi, c) h2 += c cc = shiftRightBy2(cc) - h0, c = bitsAdd64(h0, cc.lo, 0) - h1, c = bitsAdd64(h1, cc.hi, c) + h0, c = bits.Add64(h0, cc.lo, 0) + h1, c = bits.Add64(h1, cc.hi, c) h2 += c // h2 is at most 3 + 1 + 1 = 5, making the whole of h at most @@ -287,9 +290,9 @@ func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) { // in constant time, we compute t = h - (2¹³⁰ - 5), and select h as the // result if the subtraction underflows, and t otherwise. - hMinusP0, b := bitsSub64(h0, p0, 0) - hMinusP1, b := bitsSub64(h1, p1, b) - _, b = bitsSub64(h2, p2, b) + hMinusP0, b := bits.Sub64(h0, p0, 0) + hMinusP1, b := bits.Sub64(h1, p1, b) + _, b = bits.Sub64(h2, p2, b) // h = h if h < p else h - p h0 = select64(b, h0, hMinusP0) @@ -301,8 +304,8 @@ func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) { // // by just doing a wide addition with the 128 low bits of h and discarding // the overflow. - h0, c := bitsAdd64(h0, s[0], 0) - h1, _ = bitsAdd64(h1, s[1], c) + h0, c := bits.Add64(h0, s[0], 0) + h1, _ = bits.Add64(h1, s[1], c) binary.LittleEndian.PutUint64(out[0:8], h0) binary.LittleEndian.PutUint64(out[8:16], h1) diff --git a/vendor/golang.org/x/mod/modfile/rule.go b/vendor/golang.org/x/mod/modfile/rule.go index e0869fa38..35fd1f534 100644 --- a/vendor/golang.org/x/mod/modfile/rule.go +++ b/vendor/golang.org/x/mod/modfile/rule.go @@ -542,7 +542,7 @@ func parseReplace(filename string, line *Line, verb string, args []string, fix V if strings.Contains(ns, "@") { return nil, errorf("replacement module must match format 'path version', not 'path@version'") } - return nil, errorf("replacement module without version must be directory path (rooted or starting with ./ or ../)") + return nil, errorf("replacement module without version must be directory path (rooted or starting with . or ..)") } if filepath.Separator == '/' && strings.Contains(ns, `\`) { return nil, errorf("replacement directory appears to be Windows path (on a non-windows system)") @@ -555,7 +555,6 @@ func parseReplace(filename string, line *Line, verb string, args []string, fix V } if IsDirectoryPath(ns) { return nil, errorf("replacement module directory path %q cannot have version", ns) - } } return &Replace{ @@ -679,14 +678,15 @@ func (f *WorkFile) add(errs *ErrorList, line *Line, verb string, args []string, } } -// IsDirectoryPath reports whether the given path should be interpreted -// as a directory path. Just like on the go command line, relative paths +// IsDirectoryPath reports whether the given path should be interpreted as a directory path. +// Just like on the go command line, relative paths starting with a '.' or '..' path component // and rooted paths are directory paths; the rest are module paths. func IsDirectoryPath(ns string) bool { // Because go.mod files can move from one system to another, // we check all known path syntaxes, both Unix and Windows. - return strings.HasPrefix(ns, "./") || strings.HasPrefix(ns, "../") || strings.HasPrefix(ns, "/") || - strings.HasPrefix(ns, `.\`) || strings.HasPrefix(ns, `..\`) || strings.HasPrefix(ns, `\`) || + return ns == "." || strings.HasPrefix(ns, "./") || strings.HasPrefix(ns, `.\`) || + ns == ".." || strings.HasPrefix(ns, "../") || strings.HasPrefix(ns, `..\`) || + strings.HasPrefix(ns, "/") || strings.HasPrefix(ns, `\`) || len(ns) >= 2 && ('A' <= ns[0] && ns[0] <= 'Z' || 'a' <= ns[0] && ns[0] <= 'z') && ns[1] == ':' } diff --git a/vendor/golang.org/x/sync/errgroup/errgroup.go b/vendor/golang.org/x/sync/errgroup/errgroup.go index b18efb743..948a3ee63 100644 --- a/vendor/golang.org/x/sync/errgroup/errgroup.go +++ b/vendor/golang.org/x/sync/errgroup/errgroup.go @@ -4,6 +4,9 @@ // Package errgroup provides synchronization, error propagation, and Context // cancelation for groups of goroutines working on subtasks of a common task. +// +// [errgroup.Group] is related to [sync.WaitGroup] but adds handling of tasks +// returning errors. package errgroup import ( diff --git a/vendor/golang.org/x/sys/execabs/execabs.go b/vendor/golang.org/x/sys/execabs/execabs.go deleted file mode 100644 index 3bf40fdfe..000000000 --- a/vendor/golang.org/x/sys/execabs/execabs.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package execabs is a drop-in replacement for os/exec -// that requires PATH lookups to find absolute paths. -// That is, execabs.Command("cmd") runs the same PATH lookup -// as exec.Command("cmd"), but if the result is a path -// which is relative, the Run and Start methods will report -// an error instead of running the executable. -// -// See https://blog.golang.org/path-security for more information -// about when it may be necessary or appropriate to use this package. -package execabs - -import ( - "context" - "fmt" - "os/exec" - "path/filepath" - "reflect" - "unsafe" -) - -// ErrNotFound is the error resulting if a path search failed to find an executable file. -// It is an alias for exec.ErrNotFound. -var ErrNotFound = exec.ErrNotFound - -// Cmd represents an external command being prepared or run. -// It is an alias for exec.Cmd. -type Cmd = exec.Cmd - -// Error is returned by LookPath when it fails to classify a file as an executable. -// It is an alias for exec.Error. -type Error = exec.Error - -// An ExitError reports an unsuccessful exit by a command. -// It is an alias for exec.ExitError. -type ExitError = exec.ExitError - -func relError(file, path string) error { - return fmt.Errorf("%s resolves to executable in current directory (.%c%s)", file, filepath.Separator, path) -} - -// LookPath searches for an executable named file in the directories -// named by the PATH environment variable. If file contains a slash, -// it is tried directly and the PATH is not consulted. The result will be -// an absolute path. -// -// LookPath differs from exec.LookPath in its handling of PATH lookups, -// which are used for file names without slashes. If exec.LookPath's -// PATH lookup would have returned an executable from the current directory, -// LookPath instead returns an error. -func LookPath(file string) (string, error) { - path, err := exec.LookPath(file) - if err != nil && !isGo119ErrDot(err) { - return "", err - } - if filepath.Base(file) == file && !filepath.IsAbs(path) { - return "", relError(file, path) - } - return path, nil -} - -func fixCmd(name string, cmd *exec.Cmd) { - if filepath.Base(name) == name && !filepath.IsAbs(cmd.Path) && !isGo119ErrFieldSet(cmd) { - // exec.Command was called with a bare binary name and - // exec.LookPath returned a path which is not absolute. - // Set cmd.lookPathErr and clear cmd.Path so that it - // cannot be run. - lookPathErr := (*error)(unsafe.Pointer(reflect.ValueOf(cmd).Elem().FieldByName("lookPathErr").Addr().Pointer())) - if *lookPathErr == nil { - *lookPathErr = relError(name, cmd.Path) - } - cmd.Path = "" - } -} - -// CommandContext is like Command but includes a context. -// -// The provided context is used to kill the process (by calling os.Process.Kill) -// if the context becomes done before the command completes on its own. -func CommandContext(ctx context.Context, name string, arg ...string) *exec.Cmd { - cmd := exec.CommandContext(ctx, name, arg...) - fixCmd(name, cmd) - return cmd - -} - -// Command returns the Cmd struct to execute the named program with the given arguments. -// See exec.Command for most details. -// -// Command differs from exec.Command in its handling of PATH lookups, -// which are used when the program name contains no slashes. -// If exec.Command would have returned an exec.Cmd configured to run an -// executable from the current directory, Command instead -// returns an exec.Cmd that will return an error from Start or Run. -func Command(name string, arg ...string) *exec.Cmd { - cmd := exec.Command(name, arg...) - fixCmd(name, cmd) - return cmd -} diff --git a/vendor/golang.org/x/sys/execabs/execabs_go118.go b/vendor/golang.org/x/sys/execabs/execabs_go118.go deleted file mode 100644 index 5627d70e3..000000000 --- a/vendor/golang.org/x/sys/execabs/execabs_go118.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.19 - -package execabs - -import "os/exec" - -func isGo119ErrDot(err error) bool { - return false -} - -func isGo119ErrFieldSet(cmd *exec.Cmd) bool { - return false -} diff --git a/vendor/golang.org/x/sys/execabs/execabs_go119.go b/vendor/golang.org/x/sys/execabs/execabs_go119.go deleted file mode 100644 index d60ab1b41..000000000 --- a/vendor/golang.org/x/sys/execabs/execabs_go119.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.19 - -package execabs - -import ( - "errors" - "os/exec" -) - -func isGo119ErrDot(err error) bool { - return errors.Is(err, exec.ErrDot) -} - -func isGo119ErrFieldSet(cmd *exec.Cmd) bool { - return cmd.Err != nil -} diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh index 6202638ba..c6492020e 100644 --- a/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -248,6 +248,7 @@ struct ltchars { #include #include #include +#include #include #include #include @@ -283,10 +284,6 @@ struct ltchars { #include #endif -#ifndef MSG_FASTOPEN -#define MSG_FASTOPEN 0x20000000 -#endif - #ifndef PTRACE_GETREGS #define PTRACE_GETREGS 0xc #endif @@ -295,14 +292,6 @@ struct ltchars { #define PTRACE_SETREGS 0xd #endif -#ifndef SOL_NETLINK -#define SOL_NETLINK 270 -#endif - -#ifndef SOL_SMC -#define SOL_SMC 286 -#endif - #ifdef SOL_BLUETOOTH // SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h // but it is already in bluetooth_linux.go @@ -319,10 +308,23 @@ struct ltchars { #undef TIPC_WAIT_FOREVER #define TIPC_WAIT_FOREVER 0xffffffff -// Copied from linux/l2tp.h -// Including linux/l2tp.h here causes conflicts between linux/in.h -// and netinet/in.h included via net/route.h above. -#define IPPROTO_L2TP 115 +// Copied from linux/netfilter/nf_nat.h +// Including linux/netfilter/nf_nat.h here causes conflicts between linux/in.h +// and netinet/in.h. +#define NF_NAT_RANGE_MAP_IPS (1 << 0) +#define NF_NAT_RANGE_PROTO_SPECIFIED (1 << 1) +#define NF_NAT_RANGE_PROTO_RANDOM (1 << 2) +#define NF_NAT_RANGE_PERSISTENT (1 << 3) +#define NF_NAT_RANGE_PROTO_RANDOM_FULLY (1 << 4) +#define NF_NAT_RANGE_PROTO_OFFSET (1 << 5) +#define NF_NAT_RANGE_NETMAP (1 << 6) +#define NF_NAT_RANGE_PROTO_RANDOM_ALL \ + (NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PROTO_RANDOM_FULLY) +#define NF_NAT_RANGE_MASK \ + (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED | \ + NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PERSISTENT | \ + NF_NAT_RANGE_PROTO_RANDOM_FULLY | NF_NAT_RANGE_PROTO_OFFSET | \ + NF_NAT_RANGE_NETMAP) // Copied from linux/hid.h. // Keep in sync with the size of the referenced fields. @@ -603,6 +605,9 @@ ccflags="$@" $2 ~ /^FSOPT_/ || $2 ~ /^WDIO[CFS]_/ || $2 ~ /^NFN/ || + $2 !~ /^NFT_META_IIFTYPE/ && + $2 ~ /^NFT_/ || + $2 ~ /^NF_NAT_/ || $2 ~ /^XDP_/ || $2 ~ /^RWF_/ || $2 ~ /^(HDIO|WIN|SMART)_/ || diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go index c73cfe2f1..a5d3ff8df 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go @@ -2127,6 +2127,60 @@ const ( NFNL_SUBSYS_QUEUE = 0x3 NFNL_SUBSYS_ULOG = 0x4 NFS_SUPER_MAGIC = 0x6969 + NFT_CHAIN_FLAGS = 0x7 + NFT_CHAIN_MAXNAMELEN = 0x100 + NFT_CT_MAX = 0x17 + NFT_DATA_RESERVED_MASK = 0xffffff00 + NFT_DATA_VALUE_MAXLEN = 0x40 + NFT_EXTHDR_OP_MAX = 0x4 + NFT_FIB_RESULT_MAX = 0x3 + NFT_INNER_MASK = 0xf + NFT_LOGLEVEL_MAX = 0x8 + NFT_NAME_MAXLEN = 0x100 + NFT_NG_MAX = 0x1 + NFT_OBJECT_CONNLIMIT = 0x5 + NFT_OBJECT_COUNTER = 0x1 + NFT_OBJECT_CT_EXPECT = 0x9 + NFT_OBJECT_CT_HELPER = 0x3 + NFT_OBJECT_CT_TIMEOUT = 0x7 + NFT_OBJECT_LIMIT = 0x4 + NFT_OBJECT_MAX = 0xa + NFT_OBJECT_QUOTA = 0x2 + NFT_OBJECT_SECMARK = 0x8 + NFT_OBJECT_SYNPROXY = 0xa + NFT_OBJECT_TUNNEL = 0x6 + NFT_OBJECT_UNSPEC = 0x0 + NFT_OBJ_MAXNAMELEN = 0x100 + NFT_OSF_MAXGENRELEN = 0x10 + NFT_QUEUE_FLAG_BYPASS = 0x1 + NFT_QUEUE_FLAG_CPU_FANOUT = 0x2 + NFT_QUEUE_FLAG_MASK = 0x3 + NFT_REG32_COUNT = 0x10 + NFT_REG32_SIZE = 0x4 + NFT_REG_MAX = 0x4 + NFT_REG_SIZE = 0x10 + NFT_REJECT_ICMPX_MAX = 0x3 + NFT_RT_MAX = 0x4 + NFT_SECMARK_CTX_MAXLEN = 0x100 + NFT_SET_MAXNAMELEN = 0x100 + NFT_SOCKET_MAX = 0x3 + NFT_TABLE_F_MASK = 0x3 + NFT_TABLE_MAXNAMELEN = 0x100 + NFT_TRACETYPE_MAX = 0x3 + NFT_TUNNEL_F_MASK = 0x7 + NFT_TUNNEL_MAX = 0x1 + NFT_TUNNEL_MODE_MAX = 0x2 + NFT_USERDATA_MAXLEN = 0x100 + NFT_XFRM_KEY_MAX = 0x6 + NF_NAT_RANGE_MAP_IPS = 0x1 + NF_NAT_RANGE_MASK = 0x7f + NF_NAT_RANGE_NETMAP = 0x40 + NF_NAT_RANGE_PERSISTENT = 0x8 + NF_NAT_RANGE_PROTO_OFFSET = 0x20 + NF_NAT_RANGE_PROTO_RANDOM = 0x4 + NF_NAT_RANGE_PROTO_RANDOM_ALL = 0x14 + NF_NAT_RANGE_PROTO_RANDOM_FULLY = 0x10 + NF_NAT_RANGE_PROTO_SPECIFIED = 0x2 NILFS_SUPER_MAGIC = 0x3434 NL0 = 0x0 NL1 = 0x100 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go index a1d061597..9dc42410b 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go @@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) { var libc_unveil_trampoline_addr uintptr //go:cgo_import_dynamic libc_unveil unveil "libc.so" - - diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go index 5b2a74097..0d3a0751c 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go @@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) { var libc_unveil_trampoline_addr uintptr //go:cgo_import_dynamic libc_unveil unveil "libc.so" - - diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go index f6eda1344..c39f7776d 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go @@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) { var libc_unveil_trampoline_addr uintptr //go:cgo_import_dynamic libc_unveil unveil "libc.so" - - diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go index 55df20ae9..57571d072 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go @@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) { var libc_unveil_trampoline_addr uintptr //go:cgo_import_dynamic libc_unveil unveil "libc.so" - - diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go index 8c1155cbc..e62963e67 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go @@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) { var libc_unveil_trampoline_addr uintptr //go:cgo_import_dynamic libc_unveil unveil "libc.so" - - diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go index 7cc80c58d..00831354c 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go @@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) { var libc_unveil_trampoline_addr uintptr //go:cgo_import_dynamic libc_unveil unveil "libc.so" - - diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go index 0688737f4..79029ed58 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go @@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) { var libc_unveil_trampoline_addr uintptr //go:cgo_import_dynamic libc_unveil unveil "libc.so" - - diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go index 47dc57967..ffb8708cc 100644 --- a/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -194,6 +194,7 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW //sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW //sys SetEndOfFile(handle Handle) (err error) +//sys SetFileValidData(handle Handle, validDataLength int64) (err error) //sys GetSystemTimeAsFileTime(time *Filetime) //sys GetSystemTimePreciseAsFileTime(time *Filetime) //sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff] diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go index 146a1f019..e8791c82c 100644 --- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go +++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go @@ -342,6 +342,7 @@ var ( procSetDefaultDllDirectories = modkernel32.NewProc("SetDefaultDllDirectories") procSetDllDirectoryW = modkernel32.NewProc("SetDllDirectoryW") procSetEndOfFile = modkernel32.NewProc("SetEndOfFile") + procSetFileValidData = modkernel32.NewProc("SetFileValidData") procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW") procSetErrorMode = modkernel32.NewProc("SetErrorMode") procSetEvent = modkernel32.NewProc("SetEvent") @@ -2988,6 +2989,14 @@ func SetEndOfFile(handle Handle) (err error) { return } +func SetFileValidData(handle Handle, validDataLength int64) (err error) { + r1, _, e1 := syscall.Syscall(procSetFileValidData.Addr(), 2, uintptr(handle), uintptr(validDataLength), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func SetEnvironmentVariable(name *uint16, value *uint16) (err error) { r1, _, e1 := syscall.Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0) if r1 == 0 { diff --git a/vendor/golang.org/x/tools/go/analysis/analysistest/analysistest.go b/vendor/golang.org/x/tools/go/analysis/analysistest/analysistest.go index 0c066baa3..72b703f7b 100644 --- a/vendor/golang.org/x/tools/go/analysis/analysistest/analysistest.go +++ b/vendor/golang.org/x/tools/go/analysis/analysistest/analysistest.go @@ -147,14 +147,18 @@ func RunWithSuggestedFixes(t Testing, dir string, a *analysis.Analyzer, patterns for _, diag := range act.Diagnostics { for _, sf := range diag.SuggestedFixes { for _, edit := range sf.TextEdits { + start, end := edit.Pos, edit.End + if !end.IsValid() { + end = start + } // Validate the edit. - if edit.Pos > edit.End { + if start > end { t.Errorf( "diagnostic for analysis %v contains Suggested Fix with malformed edit: pos (%v) > end (%v)", - act.Pass.Analyzer.Name, edit.Pos, edit.End) + act.Pass.Analyzer.Name, start, end) continue } - file, endfile := act.Pass.Fset.File(edit.Pos), act.Pass.Fset.File(edit.End) + file, endfile := act.Pass.Fset.File(start), act.Pass.Fset.File(end) if file == nil || endfile == nil || file != endfile { t.Errorf( "diagnostic for analysis %v contains Suggested Fix with malformed spanning files %v and %v", @@ -172,8 +176,8 @@ func RunWithSuggestedFixes(t Testing, dir string, a *analysis.Analyzer, patterns fileEdits[file] = make(map[string][]diff.Edit) } fileEdits[file][sf.Message] = append(fileEdits[file][sf.Message], diff.Edit{ - Start: file.Offset(edit.Pos), - End: file.Offset(edit.End), + Start: file.Offset(start), + End: file.Offset(end), New: string(edit.NewText), }) } diff --git a/vendor/golang.org/x/tools/go/analysis/internal/checker/checker.go b/vendor/golang.org/x/tools/go/analysis/internal/checker/checker.go index 33ca77a06..3c8935008 100644 --- a/vendor/golang.org/x/tools/go/analysis/internal/checker/checker.go +++ b/vendor/golang.org/x/tools/go/analysis/internal/checker/checker.go @@ -342,20 +342,28 @@ func applyFixes(roots []*action) error { for _, edit := range sf.TextEdits { // Validate the edit. // Any error here indicates a bug in the analyzer. - file := act.pkg.Fset.File(edit.Pos) + start, end := edit.Pos, edit.End + file := act.pkg.Fset.File(start) if file == nil { return fmt.Errorf("analysis %q suggests invalid fix: missing file info for pos (%v)", - act.a.Name, edit.Pos) + act.a.Name, start) } - if edit.Pos > edit.End { + if !end.IsValid() { + end = start + } + if start > end { return fmt.Errorf("analysis %q suggests invalid fix: pos (%v) > end (%v)", - act.a.Name, edit.Pos, edit.End) + act.a.Name, start, end) } - if eof := token.Pos(file.Base() + file.Size()); edit.End > eof { + if eof := token.Pos(file.Base() + file.Size()); end > eof { return fmt.Errorf("analysis %q suggests invalid fix: end (%v) past end of file (%v)", - act.a.Name, edit.End, eof) + act.a.Name, end, eof) + } + edit := diff.Edit{ + Start: file.Offset(start), + End: file.Offset(end), + New: string(edit.NewText), } - edit := diff.Edit{Start: file.Offset(edit.Pos), End: file.Offset(edit.End), New: string(edit.NewText)} editsForTokenFile[file] = append(editsForTokenFile[file], edit) } } @@ -485,11 +493,11 @@ func diff3Conflict(path string, xlabel, ylabel string, xedits, yedits []diff.Edi } oldlabel, old := "base", string(contents) - xdiff, err := diff.ToUnified(oldlabel, xlabel, old, xedits) + xdiff, err := diff.ToUnified(oldlabel, xlabel, old, xedits, diff.DefaultContextLines) if err != nil { return err } - ydiff, err := diff.ToUnified(oldlabel, ylabel, old, yedits) + ydiff, err := diff.ToUnified(oldlabel, ylabel, old, yedits, diff.DefaultContextLines) if err != nil { return err } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go b/vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go index f0b90a492..6976f0d90 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go @@ -15,6 +15,7 @@ import ( "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/go/types/typeutil" ) //go:embed doc.go @@ -36,12 +37,9 @@ func run(pass *analysis.Pass) (interface{}, error) { } inspect.Preorder(nodeFilter, func(n ast.Node) { call := n.(*ast.CallExpr) - if ident, ok := call.Fun.(*ast.Ident); ok && ident.Name == "append" { - if _, ok := pass.TypesInfo.Uses[ident].(*types.Builtin); ok { - if len(call.Args) == 1 { - pass.ReportRangef(call, "append with no values") - } - } + b, ok := typeutil.Callee(pass.TypesInfo, call).(*types.Builtin) + if ok && b.Name() == "append" && len(call.Args) == 1 { + pass.ReportRangef(call, "append with no values") } }) diff --git a/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go b/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go index 10489bea1..3bfd50122 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go @@ -18,6 +18,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" + "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/go/ast/inspector" ) @@ -77,7 +78,7 @@ func run(pass *analysis.Pass) (interface{}, error) { // isMapIndex returns true if e is a map index expression. func isMapIndex(info *types.Info, e ast.Expr) bool { - if idx, ok := analysisutil.Unparen(e).(*ast.IndexExpr); ok { + if idx, ok := astutil.Unparen(e).(*ast.IndexExpr); ok { if typ := info.Types[idx.X].Type; typ != nil { _, ok := typ.Underlying().(*types.Map) return ok diff --git a/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go b/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go index b40e081ec..931f9ca75 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go @@ -8,12 +8,12 @@ import ( _ "embed" "go/ast" "go/token" - "go/types" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/go/types/typeutil" ) //go:embed doc.go @@ -52,18 +52,8 @@ func run(pass *analysis.Pass) (interface{}, error) { if !ok { continue } - sel, ok := call.Fun.(*ast.SelectorExpr) - if !ok { - continue - } - pkgIdent, _ := sel.X.(*ast.Ident) - pkgName, ok := pass.TypesInfo.Uses[pkgIdent].(*types.PkgName) - if !ok || pkgName.Imported().Path() != "sync/atomic" { - continue - } - - switch sel.Sel.Name { - case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr": + fn := typeutil.StaticCallee(pass.TypesInfo, call) + if analysisutil.IsFunctionNamed(fn, "sync/atomic", "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr") { checkAtomicAddAssignment(pass, n.Lhs[i], call) } } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go b/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go index 01683e45a..aff6d25b3 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go @@ -18,6 +18,7 @@ import ( "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/go/types/typeutil" ) const Doc = "check for non-64-bits-aligned arguments to sync/atomic functions" @@ -42,31 +43,20 @@ func run(pass *analysis.Pass) (interface{}, error) { nodeFilter := []ast.Node{ (*ast.CallExpr)(nil), } + funcNames := []string{ + "AddInt64", "AddUint64", + "LoadInt64", "LoadUint64", + "StoreInt64", "StoreUint64", + "SwapInt64", "SwapUint64", + "CompareAndSwapInt64", "CompareAndSwapUint64", + } inspect.Preorder(nodeFilter, func(node ast.Node) { call := node.(*ast.CallExpr) - sel, ok := call.Fun.(*ast.SelectorExpr) - if !ok { - return - } - pkgIdent, ok := sel.X.(*ast.Ident) - if !ok { - return - } - pkgName, ok := pass.TypesInfo.Uses[pkgIdent].(*types.PkgName) - if !ok || pkgName.Imported().Path() != "sync/atomic" { - return - } - - switch sel.Sel.Name { - case "AddInt64", "AddUint64", - "LoadInt64", "LoadUint64", - "StoreInt64", "StoreUint64", - "SwapInt64", "SwapUint64", - "CompareAndSwapInt64", "CompareAndSwapUint64": - + fn := typeutil.StaticCallee(pass.TypesInfo, call) + if analysisutil.IsFunctionNamed(fn, "sync/atomic", funcNames...) { // For all the listed functions, the expression to check is always the first function argument. - check64BitAlignment(pass, sel.Sel.Name, call.Args[0]) + check64BitAlignment(pass, fn.Name(), call.Args[0]) } }) diff --git a/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go b/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go index 4219f087b..564329774 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go @@ -14,6 +14,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" + "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/go/ast/inspector" ) @@ -83,7 +84,7 @@ func (op boolOp) commutativeSets(info *types.Info, e *ast.BinaryExpr, seen map[* i := 0 var sets [][]ast.Expr for j := 0; j <= len(exprs); j++ { - if j == len(exprs) || hasSideEffects(info, exprs[j]) { + if j == len(exprs) || analysisutil.HasSideEffects(info, exprs[j]) { if i < j { sets = append(sets, exprs[i:j]) } @@ -162,46 +163,13 @@ func (op boolOp) checkSuspect(pass *analysis.Pass, exprs []ast.Expr) { } } -// hasSideEffects reports whether evaluation of e has side effects. -func hasSideEffects(info *types.Info, e ast.Expr) bool { - safe := true - ast.Inspect(e, func(node ast.Node) bool { - switch n := node.(type) { - case *ast.CallExpr: - typVal := info.Types[n.Fun] - switch { - case typVal.IsType(): - // Type conversion, which is safe. - case typVal.IsBuiltin(): - // Builtin func, conservatively assumed to not - // be safe for now. - safe = false - return false - default: - // A non-builtin func or method call. - // Conservatively assume that all of them have - // side effects for now. - safe = false - return false - } - case *ast.UnaryExpr: - if n.Op == token.ARROW { - safe = false - return false - } - } - return true - }) - return !safe -} - // split returns a slice of all subexpressions in e that are connected by op. // For example, given 'a || (b || c) || d' with the or op, // split returns []{d, c, b, a}. // seen[e] is already true; any newly processed exprs are added to seen. func (op boolOp) split(e ast.Expr, seen map[*ast.BinaryExpr]bool) (exprs []ast.Expr) { for { - e = unparen(e) + e = astutil.Unparen(e) if b, ok := e.(*ast.BinaryExpr); ok && b.Op == op.tok { seen[b] = true exprs = append(exprs, op.split(b.Y, seen)...) @@ -213,14 +181,3 @@ func (op boolOp) split(e ast.Expr, seen map[*ast.BinaryExpr]bool) (exprs []ast.E } return } - -// unparen returns e with any enclosing parentheses stripped. -func unparen(e ast.Expr) ast.Expr { - for { - p, ok := e.(*ast.ParenExpr) - if !ok { - return e - } - e = p.X - } -} diff --git a/vendor/golang.org/x/tools/go/analysis/passes/buildssa/buildssa.go b/vendor/golang.org/x/tools/go/analysis/passes/buildssa/buildssa.go index 881b8fd67..f077ea282 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/buildssa/buildssa.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/buildssa/buildssa.go @@ -26,15 +26,13 @@ var Analyzer = &analysis.Analyzer{ } // SSA provides SSA-form intermediate representation for all the -// non-blank source functions in the current package. +// source functions in the current package. type SSA struct { Pkg *ssa.Package SrcFuncs []*ssa.Function } func run(pass *analysis.Pass) (interface{}, error) { - // Plundered from ssautil.BuildPackage. - // We must create a new Program for each Package because the // analysis API provides no place to hang a Program shared by // all Packages. Consequently, SSA Packages and Functions do not @@ -51,20 +49,10 @@ func run(pass *analysis.Pass) (interface{}, error) { prog := ssa.NewProgram(pass.Fset, mode) - // Create SSA packages for all imports. - // Order is not significant. - created := make(map[*types.Package]bool) - var createAll func(pkgs []*types.Package) - createAll = func(pkgs []*types.Package) { - for _, p := range pkgs { - if !created[p] { - created[p] = true - prog.CreatePackage(p, nil, nil, true) - createAll(p.Imports()) - } - } + // Create SSA packages for direct imports. + for _, p := range pass.Pkg.Imports() { + prog.CreatePackage(p, nil, nil, true) } - createAll(pass.Pkg.Imports()) // Create and build the primary package. ssapkg := prog.CreatePackage(pass.Pkg, pass.Files, pass.TypesInfo, false) @@ -76,16 +64,6 @@ func run(pass *analysis.Pass) (interface{}, error) { for _, f := range pass.Files { for _, decl := range f.Decls { if fdecl, ok := decl.(*ast.FuncDecl); ok { - - // SSA will not build a Function - // for a FuncDecl named blank. - // That's arguably too strict but - // relaxing it would break uniqueness of - // names of package members. - if fdecl.Name.Name == "_" { - continue - } - // (init functions have distinct Func // objects named "init" and distinct // ssa.Functions named "init#1", ...) diff --git a/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go b/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go index 98d9a777a..4e8643975 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go @@ -19,6 +19,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" + "golang.org/x/tools/go/ast/astutil" ) const debug = false @@ -64,7 +65,7 @@ func checkCgo(fset *token.FileSet, f *ast.File, info *types.Info, reportf func(t // Is this a C.f() call? var name string - if sel, ok := analysisutil.Unparen(call.Fun).(*ast.SelectorExpr); ok { + if sel, ok := astutil.Unparen(call.Fun).(*ast.SelectorExpr); ok { if id, ok := sel.X.(*ast.Ident); ok && id.Name == "C" { name = sel.Sel.Name } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go b/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go index c7a49776f..847063bb3 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go @@ -72,7 +72,7 @@ func run(pass *analysis.Pass) (interface{}, error) { } var structuralTypes []types.Type switch typ := typ.(type) { - case *typeparams.TypeParam: + case *types.TypeParam: terms, err := typeparams.StructuralTerms(typ) if err != nil { return // invalid type @@ -163,7 +163,7 @@ func isLocalType(pass *analysis.Pass, typ types.Type) bool { case *types.Named: // names in package foo are local to foo_test too return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(pass.Pkg.Path(), "_test") - case *typeparams.TypeParam: + case *types.TypeParam: return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(pass.Pkg.Path(), "_test") } return false diff --git a/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go b/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go index ec7727de7..6cbbc7e81 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go @@ -16,6 +16,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" + "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/internal/typeparams" ) @@ -223,7 +224,7 @@ func (path typePath) String() string { } func lockPathRhs(pass *analysis.Pass, x ast.Expr) typePath { - x = analysisutil.Unparen(x) // ignore parens on rhs + x = astutil.Unparen(x) // ignore parens on rhs if _, ok := x.(*ast.CompositeLit); ok { return nil @@ -233,7 +234,7 @@ func lockPathRhs(pass *analysis.Pass, x ast.Expr) typePath { return nil } if star, ok := x.(*ast.StarExpr); ok { - if _, ok := analysisutil.Unparen(star.X).(*ast.CallExpr); ok { + if _, ok := astutil.Unparen(star.X).(*ast.CallExpr); ok { // A call may return a pointer to a zero value. return nil } @@ -254,7 +255,7 @@ func lockPath(tpkg *types.Package, typ types.Type, seen map[types.Type]bool) typ } seen[typ] = true - if tpar, ok := typ.(*typeparams.TypeParam); ok { + if tpar, ok := typ.(*types.TypeParam); ok { terms, err := typeparams.StructuralTerms(tpar) if err != nil { return nil // invalid type @@ -319,9 +320,7 @@ func lockPath(tpkg *types.Package, typ types.Type, seen map[types.Type]bool) typ // In go1.10, sync.noCopy did not implement Locker. // (The Unlock method was added only in CL 121876.) // TODO(adonovan): remove workaround when we drop go1.10. - if named, ok := typ.(*types.Named); ok && - named.Obj().Name() == "noCopy" && - named.Obj().Pkg().Path() == "sync" { + if analysisutil.IsNamedType(typ, "sync", "noCopy") { return []string{typ.String()} } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/deepequalerrors/deepequalerrors.go b/vendor/golang.org/x/tools/go/analysis/passes/deepequalerrors/deepequalerrors.go index 3a1818764..1a83bddbc 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/deepequalerrors/deepequalerrors.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/deepequalerrors/deepequalerrors.go @@ -46,11 +46,8 @@ func run(pass *analysis.Pass) (interface{}, error) { } inspect.Preorder(nodeFilter, func(n ast.Node) { call := n.(*ast.CallExpr) - fn, ok := typeutil.Callee(pass.TypesInfo, call).(*types.Func) - if !ok { - return - } - if fn.FullName() == "reflect.DeepEqual" && hasError(pass, call.Args[0]) && hasError(pass, call.Args[1]) { + fn, _ := typeutil.Callee(pass.TypesInfo, call).(*types.Func) + if analysisutil.IsFunctionNamed(fn, "reflect", "DeepEqual") && hasError(pass, call.Args[0]) && hasError(pass, call.Args[1]) { pass.ReportRangef(call, "avoid using reflect.DeepEqual with errors") } }) diff --git a/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go b/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go index ed2a122f2..5e8e80a6a 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go @@ -7,7 +7,6 @@ package defers import ( _ "embed" "go/ast" - "go/types" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" @@ -36,8 +35,7 @@ func run(pass *analysis.Pass) (interface{}, error) { checkDeferCall := func(node ast.Node) bool { switch v := node.(type) { case *ast.CallExpr: - fn, ok := typeutil.Callee(pass.TypesInfo, v).(*types.Func) - if ok && fn.Name() == "Since" && fn.Pkg().Path() == "time" { + if analysisutil.IsFunctionNamed(typeutil.StaticCallee(pass.TypesInfo, v), "time", "Since") { pass.Reportf(v.Pos(), "call to time.Since is not deferred") } case *ast.FuncLit: diff --git a/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go b/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go index 2fcbdfafb..7f62ad4c8 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go @@ -51,15 +51,12 @@ func run(pass *analysis.Pass) (interface{}, error) { inspect.Preorder(nodeFilter, func(n ast.Node) { call := n.(*ast.CallExpr) fn := typeutil.StaticCallee(pass.TypesInfo, call) - if fn == nil { - return // not a static call + if !analysisutil.IsFunctionNamed(fn, "errors", "As") { + return } if len(call.Args) < 2 { return // not enough arguments, e.g. called with return values of another function } - if fn.FullName() != "errors.As" { - return - } if err := checkAsTarget(pass, call.Args[1]); err != nil { pass.ReportRangef(call, "%v", err) } @@ -69,9 +66,6 @@ func run(pass *analysis.Pass) (interface{}, error) { var errorType = types.Universe.Lookup("error").Type() -// pointerToInterfaceOrError reports whether the type of e is a pointer to an interface or a type implementing error, -// or is the empty interface. - // checkAsTarget reports an error if the second argument to errors.As is invalid. func checkAsTarget(pass *analysis.Pass, e ast.Expr) error { t := pass.TypesInfo.Types[e].Type diff --git a/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go b/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go index 61c3b764f..c6b6c81b4 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go @@ -116,7 +116,7 @@ func isHTTPFuncOrMethodOnClient(info *types.Info, expr *ast.CallExpr) bool { if res.Len() != 2 { return false // the function called does not return two values. } - if ptr, ok := res.At(0).Type().(*types.Pointer); !ok || !isNamedType(ptr.Elem(), "net/http", "Response") { + if ptr, ok := res.At(0).Type().(*types.Pointer); !ok || !analysisutil.IsNamedType(ptr.Elem(), "net/http", "Response") { return false // the first return type is not *http.Response. } @@ -131,11 +131,11 @@ func isHTTPFuncOrMethodOnClient(info *types.Info, expr *ast.CallExpr) bool { return ok && id.Name == "http" // function in net/http package. } - if isNamedType(typ, "net/http", "Client") { + if analysisutil.IsNamedType(typ, "net/http", "Client") { return true // method on http.Client. } ptr, ok := typ.(*types.Pointer) - return ok && isNamedType(ptr.Elem(), "net/http", "Client") // method on *http.Client. + return ok && analysisutil.IsNamedType(ptr.Elem(), "net/http", "Client") // method on *http.Client. } // restOfBlock, given a traversal stack, finds the innermost containing @@ -171,13 +171,3 @@ func rootIdent(n ast.Node) *ast.Ident { return nil } } - -// isNamedType reports whether t is the named type path.name. -func isNamedType(t types.Type, path, name string) bool { - n, ok := t.(*types.Named) - if !ok { - return false - } - obj := n.Obj() - return obj.Name() == name && obj.Pkg() != nil && obj.Pkg().Path() == path -} diff --git a/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/parameterized.go b/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/parameterized.go index b84577fcf..12507f996 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/parameterized.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/parameterized.go @@ -95,14 +95,14 @@ func (w *tpWalker) isParameterized(typ types.Type) (res bool) { return w.isParameterized(t.Elem()) case *types.Named: - list := typeparams.NamedTypeArgs(t) + list := t.TypeArgs() for i, n := 0, list.Len(); i < n; i++ { if w.isParameterized(list.At(i)) { return true } } - case *typeparams.TypeParam: + case *types.TypeParam: return true default: diff --git a/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go b/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go index a8d84034d..3f01b3b55 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go @@ -13,6 +13,8 @@ import ( "go/token" "go/types" "os" + + "golang.org/x/tools/internal/analysisinternal" ) // Format returns a string representation of the expression. @@ -55,17 +57,6 @@ func HasSideEffects(info *types.Info, e ast.Expr) bool { return !safe } -// Unparen returns e with any enclosing parentheses stripped. -func Unparen(e ast.Expr) ast.Expr { - for { - p, ok := e.(*ast.ParenExpr) - if !ok { - return e - } - e = p.X - } -} - // ReadFile reads a file and adds it to the FileSet // so that we can report errors against it using lineStart. func ReadFile(fset *token.FileSet, filename string) ([]byte, *token.File, error) { @@ -118,3 +109,48 @@ func Imports(pkg *types.Package, path string) bool { } return false } + +// IsNamedType reports whether t is the named type with the given package path +// and one of the given names. +// This function avoids allocating the concatenation of "pkg.Name", +// which is important for the performance of syntax matching. +func IsNamedType(t types.Type, pkgPath string, names ...string) bool { + n, ok := t.(*types.Named) + if !ok { + return false + } + obj := n.Obj() + if obj == nil || obj.Pkg() == nil || obj.Pkg().Path() != pkgPath { + return false + } + name := obj.Name() + for _, n := range names { + if name == n { + return true + } + } + return false +} + +// IsFunctionNamed reports whether f is a top-level function defined in the +// given package and has one of the given names. +// It returns false if f is nil or a method. +func IsFunctionNamed(f *types.Func, pkgPath string, names ...string) bool { + if f == nil { + return false + } + if f.Pkg() == nil || f.Pkg().Path() != pkgPath { + return false + } + if f.Type().(*types.Signature).Recv() != nil { + return false + } + for _, n := range names { + if f.Name() == n { + return true + } + } + return false +} + +var MustExtractDoc = analysisinternal.MustExtractDoc diff --git a/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/doc.go index dc544df1b..c95b1c1c9 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/doc.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/doc.go @@ -14,8 +14,12 @@ // in such a way (e.g. with go or defer) that it may outlive the loop // iteration and possibly observe the wrong value of the variable. // +// Note: An iteration variable can only outlive a loop iteration in Go versions <=1.21. +// In Go 1.22 and later, the loop variable lifetimes changed to create a new +// iteration variable per loop iteration. (See go.dev/issue/60078.) +// // In this example, all the deferred functions run after the loop has -// completed, so all observe the final value of v. +// completed, so all observe the final value of v [ 0 { + if tparams := fn.Type.TypeParams; tparams != nil && len(tparams.List) > 0 { pass.Reportf(fn.Pos(), "%s should not have type params", fnName) } @@ -466,7 +459,7 @@ func checkTest(pass *analysis.Pass, fn *ast.FuncDecl, prefix string) { return } - if tparams := typeparams.ForFuncType(fn.Type); tparams != nil && len(tparams.List) > 0 { + if tparams := fn.Type.TypeParams; tparams != nil && len(tparams.List) > 0 { // Note: cmd/go/internal/load also errors about TestXXX and BenchmarkXXX functions with type parameters. // We have currently decided to also warn before compilation/package loading. This can help users in IDEs. // TODO(adonovan): use ReportRangef(tparams). diff --git a/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go b/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go index c45b9fa54..eb84502bd 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go @@ -88,29 +88,16 @@ func run(pass *analysis.Pass) (interface{}, error) { } func isTimeDotFormat(f *types.Func) bool { - if f.Name() != "Format" || f.Pkg().Path() != "time" { - return false - } - sig, ok := f.Type().(*types.Signature) - if !ok { + if f.Name() != "Format" || f.Pkg() == nil || f.Pkg().Path() != "time" { return false } // Verify that the receiver is time.Time. - recv := sig.Recv() - if recv == nil { - return false - } - named, ok := recv.Type().(*types.Named) - return ok && named.Obj().Name() == "Time" + recv := f.Type().(*types.Signature).Recv() + return recv != nil && analysisutil.IsNamedType(recv.Type(), "time", "Time") } func isTimeDotParse(f *types.Func) bool { - if f.Name() != "Parse" || f.Pkg().Path() != "time" { - return false - } - // Verify that there is no receiver. - sig, ok := f.Type().(*types.Signature) - return ok && sig.Recv() == nil + return analysisutil.IsFunctionNamed(f, "time", "Parse") } // badFormatAt return the start of a bad format in e or -1 if no bad format is found. diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go b/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go index 7043baa89..f4e73528b 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go @@ -14,7 +14,6 @@ import ( "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" - "golang.org/x/tools/internal/typeparams" ) //go:embed doc.go @@ -92,7 +91,7 @@ func run(pass *analysis.Pass) (interface{}, error) { t := pass.TypesInfo.Types[call.Args[argidx]].Type switch t.Underlying().(type) { - case *types.Pointer, *types.Interface, *typeparams.TypeParam: + case *types.Pointer, *types.Interface, *types.TypeParam: return } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go b/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go index e43ac2078..32e71ef97 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go @@ -15,6 +15,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" + "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/go/ast/inspector" ) @@ -68,7 +69,7 @@ func isSafeUintptr(info *types.Info, x ast.Expr) bool { // Check unsafe.Pointer safety rules according to // https://golang.org/pkg/unsafe/#Pointer. - switch x := analysisutil.Unparen(x).(type) { + switch x := astutil.Unparen(x).(type) { case *ast.SelectorExpr: // "(6) Conversion of a reflect.SliceHeader or // reflect.StringHeader Data field to or from Pointer." @@ -104,8 +105,7 @@ func isSafeUintptr(info *types.Info, x ast.Expr) bool { } switch sel.Sel.Name { case "Pointer", "UnsafeAddr": - t, ok := info.Types[sel.X].Type.(*types.Named) - if ok && t.Obj().Pkg().Path() == "reflect" && t.Obj().Name() == "Value" { + if analysisutil.IsNamedType(info.Types[sel.X].Type, "reflect", "Value") { return true } } @@ -118,7 +118,7 @@ func isSafeUintptr(info *types.Info, x ast.Expr) bool { // isSafeArith reports whether x is a pointer arithmetic expression that is safe // to convert to unsafe.Pointer. func isSafeArith(info *types.Info, x ast.Expr) bool { - switch x := analysisutil.Unparen(x).(type) { + switch x := astutil.Unparen(x).(type) { case *ast.CallExpr: // Base case: initial conversion from unsafe.Pointer to uintptr. return len(x.Args) == 1 && @@ -153,13 +153,5 @@ func hasBasicType(info *types.Info, x ast.Expr, kind types.BasicKind) bool { // isReflectHeader reports whether t is reflect.SliceHeader or reflect.StringHeader. func isReflectHeader(t types.Type) bool { - if named, ok := t.(*types.Named); ok { - if obj := named.Obj(); obj.Pkg() != nil && obj.Pkg().Path() == "reflect" { - switch obj.Name() { - case "SliceHeader", "StringHeader": - return true - } - } - } - return false + return analysisutil.IsNamedType(t, "reflect", "SliceHeader", "StringHeader") } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go b/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go index cb487a217..76f42b052 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go @@ -24,6 +24,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" + "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" ) @@ -58,7 +59,25 @@ func init() { // List standard library functions here. // The context.With{Cancel,Deadline,Timeout} entries are // effectively redundant wrt the lostcancel analyzer. - funcs.Set("errors.New,fmt.Errorf,fmt.Sprintf,fmt.Sprint,sort.Reverse,context.WithValue,context.WithCancel,context.WithDeadline,context.WithTimeout") + funcs = stringSetFlag{ + "context.WithCancel": true, + "context.WithDeadline": true, + "context.WithTimeout": true, + "context.WithValue": true, + "errors.New": true, + "fmt.Errorf": true, + "fmt.Sprint": true, + "fmt.Sprintf": true, + "slices.Clip": true, + "slices.Compact": true, + "slices.CompactFunc": true, + "slices.Delete": true, + "slices.DeleteFunc": true, + "slices.Grow": true, + "slices.Insert": true, + "slices.Replace": true, + "sort.Reverse": true, + } Analyzer.Flags.Var(&funcs, "funcs", "comma-separated list of functions whose results must be used") @@ -82,7 +101,7 @@ func run(pass *analysis.Pass) (interface{}, error) { (*ast.ExprStmt)(nil), } inspect.Preorder(nodeFilter, func(n ast.Node) { - call, ok := analysisutil.Unparen(n.(*ast.ExprStmt).X).(*ast.CallExpr) + call, ok := astutil.Unparen(n.(*ast.ExprStmt).X).(*ast.CallExpr) if !ok { return // not a call statement } @@ -92,7 +111,6 @@ func run(pass *analysis.Pass) (interface{}, error) { if !ok { return // e.g. var or builtin } - if sig := fn.Type().(*types.Signature); sig.Recv() != nil { // method (e.g. foo.String()) if types.Identical(sig, sigNoArgsStringResult) { diff --git a/vendor/golang.org/x/tools/go/analysis/validate.go b/vendor/golang.org/x/tools/go/analysis/validate.go index 9da5692af..4f2c40456 100644 --- a/vendor/golang.org/x/tools/go/analysis/validate.go +++ b/vendor/golang.org/x/tools/go/analysis/validate.go @@ -19,6 +19,8 @@ import ( // that the Requires graph is acyclic; // that analyzer fact types are unique; // that each fact type is a pointer. +// +// Analyzer names need not be unique, though this may be confusing. func Validate(analyzers []*Analyzer) error { // Map each fact type to its sole generating analyzer. factTypes := make(map[reflect.Type]*Analyzer) diff --git a/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go b/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go index 9fa5aa192..2c4c4e232 100644 --- a/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go +++ b/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go @@ -11,8 +11,6 @@ import ( "go/ast" "go/token" "sort" - - "golang.org/x/tools/internal/typeparams" ) // PathEnclosingInterval returns the node that encloses the source @@ -322,7 +320,7 @@ func childrenOf(n ast.Node) []ast.Node { children = append(children, n.Recv) } children = append(children, n.Name) - if tparams := typeparams.ForFuncType(n.Type); tparams != nil { + if tparams := n.Type.TypeParams; tparams != nil { children = append(children, tparams) } if n.Type.Params != nil { @@ -377,7 +375,7 @@ func childrenOf(n ast.Node) []ast.Node { tok(n.Lbrack, len("[")), tok(n.Rbrack, len("]"))) - case *typeparams.IndexListExpr: + case *ast.IndexListExpr: children = append(children, tok(n.Lbrack, len("[")), tok(n.Rbrack, len("]"))) @@ -588,7 +586,7 @@ func NodeDescription(n ast.Node) string { return "decrement statement" case *ast.IndexExpr: return "index expression" - case *typeparams.IndexListExpr: + case *ast.IndexListExpr: return "index list expression" case *ast.InterfaceType: return "interface type" diff --git a/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go b/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go index f430b21b9..58934f766 100644 --- a/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go +++ b/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go @@ -9,8 +9,6 @@ import ( "go/ast" "reflect" "sort" - - "golang.org/x/tools/internal/typeparams" ) // An ApplyFunc is invoked by Apply for each node n, even if n is nil, @@ -252,7 +250,7 @@ func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast. a.apply(n, "X", nil, n.X) a.apply(n, "Index", nil, n.Index) - case *typeparams.IndexListExpr: + case *ast.IndexListExpr: a.apply(n, "X", nil, n.X) a.applyList(n, "Indices") @@ -293,7 +291,7 @@ func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast. a.apply(n, "Fields", nil, n.Fields) case *ast.FuncType: - if tparams := typeparams.ForFuncType(n); tparams != nil { + if tparams := n.TypeParams; tparams != nil { a.apply(n, "TypeParams", nil, tparams) } a.apply(n, "Params", nil, n.Params) @@ -408,7 +406,7 @@ func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast. case *ast.TypeSpec: a.apply(n, "Doc", nil, n.Doc) a.apply(n, "Name", nil, n.Name) - if tparams := typeparams.ForTypeSpec(n); tparams != nil { + if tparams := n.TypeParams; tparams != nil { a.apply(n, "TypeParams", nil, tparams) } a.apply(n, "Type", nil, n.Type) diff --git a/vendor/golang.org/x/tools/go/ast/inspector/typeof.go b/vendor/golang.org/x/tools/go/ast/inspector/typeof.go index 703c81395..2a872f89d 100644 --- a/vendor/golang.org/x/tools/go/ast/inspector/typeof.go +++ b/vendor/golang.org/x/tools/go/ast/inspector/typeof.go @@ -12,8 +12,6 @@ package inspector import ( "go/ast" "math" - - "golang.org/x/tools/internal/typeparams" ) const ( @@ -171,7 +169,7 @@ func typeOf(n ast.Node) uint64 { return 1 << nIncDecStmt case *ast.IndexExpr: return 1 << nIndexExpr - case *typeparams.IndexListExpr: + case *ast.IndexListExpr: return 1 << nIndexListExpr case *ast.InterfaceType: return 1 << nInterfaceType diff --git a/vendor/golang.org/x/tools/go/internal/cgo/cgo.go b/vendor/golang.org/x/tools/go/internal/cgo/cgo.go index 38d5c6c7c..697974bb9 100644 --- a/vendor/golang.org/x/tools/go/internal/cgo/cgo.go +++ b/vendor/golang.org/x/tools/go/internal/cgo/cgo.go @@ -59,11 +59,10 @@ import ( "go/token" "log" "os" + "os/exec" "path/filepath" "regexp" "strings" - - exec "golang.org/x/sys/execabs" ) // ProcessFiles invokes the cgo preprocessor on bp.CgoFiles, parses diff --git a/vendor/golang.org/x/tools/go/internal/cgo/cgo_pkgconfig.go b/vendor/golang.org/x/tools/go/internal/cgo/cgo_pkgconfig.go index 7d94bbc1e..b5bb95a63 100644 --- a/vendor/golang.org/x/tools/go/internal/cgo/cgo_pkgconfig.go +++ b/vendor/golang.org/x/tools/go/internal/cgo/cgo_pkgconfig.go @@ -8,7 +8,7 @@ import ( "errors" "fmt" "go/build" - exec "golang.org/x/sys/execabs" + "os/exec" "strings" ) diff --git a/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go b/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go index 0454cdd78..333676b7c 100644 --- a/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go +++ b/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go @@ -13,16 +13,17 @@ import ( "golang.org/x/tools/internal/gocommand" ) -var debug = false - func GetSizesForArgsGolist(ctx context.Context, inv gocommand.Invocation, gocmdRunner *gocommand.Runner) (string, string, error) { inv.Verb = "list" inv.Args = []string{"-f", "{{context.GOARCH}} {{context.Compiler}}", "--", "unsafe"} stdout, stderr, friendlyErr, rawErr := gocmdRunner.RunRaw(ctx, inv) var goarch, compiler string if rawErr != nil { - if rawErrMsg := rawErr.Error(); strings.Contains(rawErrMsg, "cannot find main module") || strings.Contains(rawErrMsg, "go.mod file not found") { - // User's running outside of a module. All bets are off. Get GOARCH and guess compiler is gc. + rawErrMsg := rawErr.Error() + if strings.Contains(rawErrMsg, "cannot find main module") || + strings.Contains(rawErrMsg, "go.mod file not found") { + // User's running outside of a module. + // All bets are off. Get GOARCH and guess compiler is gc. // TODO(matloob): Is this a problem in practice? inv.Verb = "env" inv.Args = []string{"GOARCH"} @@ -32,8 +33,12 @@ func GetSizesForArgsGolist(ctx context.Context, inv gocommand.Invocation, gocmdR } goarch = strings.TrimSpace(envout.String()) compiler = "gc" - } else { + } else if friendlyErr != nil { return "", "", friendlyErr + } else { + // This should be unreachable, but be defensive + // in case RunRaw's error results are inconsistent. + return "", "", rawErr } } else { fields := strings.Fields(stdout.String()) diff --git a/vendor/golang.org/x/tools/go/loader/loader.go b/vendor/golang.org/x/tools/go/loader/loader.go index edf62c2cc..013c0f505 100644 --- a/vendor/golang.org/x/tools/go/loader/loader.go +++ b/vendor/golang.org/x/tools/go/loader/loader.go @@ -23,7 +23,7 @@ import ( "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/go/internal/cgo" - "golang.org/x/tools/internal/typeparams" + "golang.org/x/tools/internal/versions" ) var ignoreVendor build.ImportMode @@ -1033,13 +1033,14 @@ func (imp *importer) newPackageInfo(path, dir string) *PackageInfo { Defs: make(map[*ast.Ident]types.Object), Uses: make(map[*ast.Ident]types.Object), Implicits: make(map[ast.Node]types.Object), + Instances: make(map[*ast.Ident]types.Instance), Scopes: make(map[ast.Node]*types.Scope), Selections: make(map[*ast.SelectorExpr]*types.Selection), }, errorFunc: imp.conf.TypeChecker.Error, dir: dir, } - typeparams.InitInstanceInfo(&info.Info) + versions.InitFileVersions(&info.Info) // Copy the types.Config so we can vary it across PackageInfos. tc := imp.conf.TypeChecker diff --git a/vendor/golang.org/x/tools/go/packages/doc.go b/vendor/golang.org/x/tools/go/packages/doc.go index a7a8f73e3..b2a0b7c6a 100644 --- a/vendor/golang.org/x/tools/go/packages/doc.go +++ b/vendor/golang.org/x/tools/go/packages/doc.go @@ -5,12 +5,32 @@ /* Package packages loads Go packages for inspection and analysis. -The Load function takes as input a list of patterns and return a list of Package -structs describing individual packages matched by those patterns. -The LoadMode controls the amount of detail in the loaded packages. - -Load passes most patterns directly to the underlying build tool, -but all patterns with the prefix "query=", where query is a +The [Load] function takes as input a list of patterns and returns a +list of [Package] values describing individual packages matched by those +patterns. +A [Config] specifies configuration options, the most important of which is +the [LoadMode], which controls the amount of detail in the loaded packages. + +Load passes most patterns directly to the underlying build tool. +The default build tool is the go command. +Its supported patterns are described at +https://pkg.go.dev/cmd/go#hdr-Package_lists_and_patterns. + +Load may be used in Go projects that use alternative build systems, by +installing an appropriate "driver" program for the build system and +specifying its location in the GOPACKAGESDRIVER environment variable. +For example, +https://github.com/bazelbuild/rules_go/wiki/Editor-and-tool-integration +explains how to use the driver for Bazel. +The driver program is responsible for interpreting patterns in its +preferred notation and reporting information about the packages that +they identify. +(See driverRequest and driverResponse types for the JSON +schema used by the protocol. +Though the protocol is supported, these types are currently unexported; +see #64608 for a proposal to publish them.) + +Regardless of driver, all patterns with the prefix "query=", where query is a non-empty string of letters from [a-z], are reserved and may be interpreted as query operators. @@ -64,7 +84,7 @@ reported about the loaded packages. See the documentation for type LoadMode for details. Most tools should pass their command-line arguments (after any flags) -uninterpreted to the loader, so that the loader can interpret them +uninterpreted to [Load], so that it can interpret them according to the conventions of the underlying build system. See the Example function for typical usage. */ diff --git a/vendor/golang.org/x/tools/go/packages/external.go b/vendor/golang.org/x/tools/go/packages/external.go index 7242a0a7d..7db1d1293 100644 --- a/vendor/golang.org/x/tools/go/packages/external.go +++ b/vendor/golang.org/x/tools/go/packages/external.go @@ -12,8 +12,8 @@ import ( "bytes" "encoding/json" "fmt" - exec "golang.org/x/sys/execabs" "os" + "os/exec" "strings" ) diff --git a/vendor/golang.org/x/tools/go/packages/golist.go b/vendor/golang.org/x/tools/go/packages/golist.go index 1f1eade0a..cd375fbc3 100644 --- a/vendor/golang.org/x/tools/go/packages/golist.go +++ b/vendor/golang.org/x/tools/go/packages/golist.go @@ -11,6 +11,7 @@ import ( "fmt" "log" "os" + "os/exec" "path" "path/filepath" "reflect" @@ -20,7 +21,6 @@ import ( "sync" "unicode" - exec "golang.org/x/sys/execabs" "golang.org/x/tools/go/internal/packagesdriver" "golang.org/x/tools/internal/gocommand" "golang.org/x/tools/internal/packagesinternal" @@ -208,62 +208,6 @@ extractQueries: } } - // Only use go/packages' overlay processing if we're using a Go version - // below 1.16. Otherwise, go list handles it. - if goVersion, err := state.getGoVersion(); err == nil && goVersion < 16 { - modifiedPkgs, needPkgs, err := state.processGolistOverlay(response) - if err != nil { - return nil, err - } - - var containsCandidates []string - if len(containFiles) > 0 { - containsCandidates = append(containsCandidates, modifiedPkgs...) - containsCandidates = append(containsCandidates, needPkgs...) - } - if err := state.addNeededOverlayPackages(response, needPkgs); err != nil { - return nil, err - } - // Check candidate packages for containFiles. - if len(containFiles) > 0 { - for _, id := range containsCandidates { - pkg, ok := response.seenPackages[id] - if !ok { - response.addPackage(&Package{ - ID: id, - Errors: []Error{{ - Kind: ListError, - Msg: fmt.Sprintf("package %s expected but not seen", id), - }}, - }) - continue - } - for _, f := range containFiles { - for _, g := range pkg.GoFiles { - if sameFile(f, g) { - response.addRoot(id) - } - } - } - } - } - // Add root for any package that matches a pattern. This applies only to - // packages that are modified by overlays, since they are not added as - // roots automatically. - for _, pattern := range restPatterns { - match := matchPattern(pattern) - for _, pkgID := range modifiedPkgs { - pkg, ok := response.seenPackages[pkgID] - if !ok { - continue - } - if match(pkg.PkgPath) { - response.addRoot(pkg.ID) - } - } - } - } - sizeswg.Wait() if sizeserr != nil { return nil, sizeserr @@ -271,24 +215,6 @@ extractQueries: return response.dr, nil } -func (state *golistState) addNeededOverlayPackages(response *responseDeduper, pkgs []string) error { - if len(pkgs) == 0 { - return nil - } - dr, err := state.createDriverResponse(pkgs...) - if err != nil { - return err - } - for _, pkg := range dr.Packages { - response.addPackage(pkg) - } - _, needPkgs, err := state.processGolistOverlay(response) - if err != nil { - return err - } - return state.addNeededOverlayPackages(response, needPkgs) -} - func (state *golistState) runContainsQueries(response *responseDeduper, queries []string) error { for _, query := range queries { // TODO(matloob): Do only one query per directory. diff --git a/vendor/golang.org/x/tools/go/packages/golist_overlay.go b/vendor/golang.org/x/tools/go/packages/golist_overlay.go index 9576b472f..d823c474a 100644 --- a/vendor/golang.org/x/tools/go/packages/golist_overlay.go +++ b/vendor/golang.org/x/tools/go/packages/golist_overlay.go @@ -6,314 +6,11 @@ package packages import ( "encoding/json" - "fmt" - "go/parser" - "go/token" - "os" "path/filepath" - "regexp" - "sort" - "strconv" - "strings" "golang.org/x/tools/internal/gocommand" ) -// processGolistOverlay provides rudimentary support for adding -// files that don't exist on disk to an overlay. The results can be -// sometimes incorrect. -// TODO(matloob): Handle unsupported cases, including the following: -// - determining the correct package to add given a new import path -func (state *golistState) processGolistOverlay(response *responseDeduper) (modifiedPkgs, needPkgs []string, err error) { - havePkgs := make(map[string]string) // importPath -> non-test package ID - needPkgsSet := make(map[string]bool) - modifiedPkgsSet := make(map[string]bool) - - pkgOfDir := make(map[string][]*Package) - for _, pkg := range response.dr.Packages { - // This is an approximation of import path to id. This can be - // wrong for tests, vendored packages, and a number of other cases. - havePkgs[pkg.PkgPath] = pkg.ID - dir, err := commonDir(pkg.GoFiles) - if err != nil { - return nil, nil, err - } - if dir != "" { - pkgOfDir[dir] = append(pkgOfDir[dir], pkg) - } - } - - // If no new imports are added, it is safe to avoid loading any needPkgs. - // Otherwise, it's hard to tell which package is actually being loaded - // (due to vendoring) and whether any modified package will show up - // in the transitive set of dependencies (because new imports are added, - // potentially modifying the transitive set of dependencies). - var overlayAddsImports bool - - // If both a package and its test package are created by the overlay, we - // need the real package first. Process all non-test files before test - // files, and make the whole process deterministic while we're at it. - var overlayFiles []string - for opath := range state.cfg.Overlay { - overlayFiles = append(overlayFiles, opath) - } - sort.Slice(overlayFiles, func(i, j int) bool { - iTest := strings.HasSuffix(overlayFiles[i], "_test.go") - jTest := strings.HasSuffix(overlayFiles[j], "_test.go") - if iTest != jTest { - return !iTest // non-tests are before tests. - } - return overlayFiles[i] < overlayFiles[j] - }) - for _, opath := range overlayFiles { - contents := state.cfg.Overlay[opath] - base := filepath.Base(opath) - dir := filepath.Dir(opath) - var pkg *Package // if opath belongs to both a package and its test variant, this will be the test variant - var testVariantOf *Package // if opath is a test file, this is the package it is testing - var fileExists bool - isTestFile := strings.HasSuffix(opath, "_test.go") - pkgName, ok := extractPackageName(opath, contents) - if !ok { - // Don't bother adding a file that doesn't even have a parsable package statement - // to the overlay. - continue - } - // If all the overlay files belong to a different package, change the - // package name to that package. - maybeFixPackageName(pkgName, isTestFile, pkgOfDir[dir]) - nextPackage: - for _, p := range response.dr.Packages { - if pkgName != p.Name && p.ID != "command-line-arguments" { - continue - } - for _, f := range p.GoFiles { - if !sameFile(filepath.Dir(f), dir) { - continue - } - // Make sure to capture information on the package's test variant, if needed. - if isTestFile && !hasTestFiles(p) { - // TODO(matloob): Are there packages other than the 'production' variant - // of a package that this can match? This shouldn't match the test main package - // because the file is generated in another directory. - testVariantOf = p - continue nextPackage - } else if !isTestFile && hasTestFiles(p) { - // We're examining a test variant, but the overlaid file is - // a non-test file. Because the overlay implementation - // (currently) only adds a file to one package, skip this - // package, so that we can add the file to the production - // variant of the package. (https://golang.org/issue/36857 - // tracks handling overlays on both the production and test - // variant of a package). - continue nextPackage - } - if pkg != nil && p != pkg && pkg.PkgPath == p.PkgPath { - // We have already seen the production version of the - // for which p is a test variant. - if hasTestFiles(p) { - testVariantOf = pkg - } - } - pkg = p - if filepath.Base(f) == base { - fileExists = true - } - } - } - // The overlay could have included an entirely new package or an - // ad-hoc package. An ad-hoc package is one that we have manually - // constructed from inadequate `go list` results for a file= query. - // It will have the ID command-line-arguments. - if pkg == nil || pkg.ID == "command-line-arguments" { - // Try to find the module or gopath dir the file is contained in. - // Then for modules, add the module opath to the beginning. - pkgPath, ok, err := state.getPkgPath(dir) - if err != nil { - return nil, nil, err - } - if !ok { - break - } - var forTest string // only set for x tests - isXTest := strings.HasSuffix(pkgName, "_test") - if isXTest { - forTest = pkgPath - pkgPath += "_test" - } - id := pkgPath - if isTestFile { - if isXTest { - id = fmt.Sprintf("%s [%s.test]", pkgPath, forTest) - } else { - id = fmt.Sprintf("%s [%s.test]", pkgPath, pkgPath) - } - } - if pkg != nil { - // TODO(rstambler): We should change the package's path and ID - // here. The only issue is that this messes with the roots. - } else { - // Try to reclaim a package with the same ID, if it exists in the response. - for _, p := range response.dr.Packages { - if reclaimPackage(p, id, opath, contents) { - pkg = p - break - } - } - // Otherwise, create a new package. - if pkg == nil { - pkg = &Package{ - PkgPath: pkgPath, - ID: id, - Name: pkgName, - Imports: make(map[string]*Package), - } - response.addPackage(pkg) - havePkgs[pkg.PkgPath] = id - // Add the production package's sources for a test variant. - if isTestFile && !isXTest && testVariantOf != nil { - pkg.GoFiles = append(pkg.GoFiles, testVariantOf.GoFiles...) - pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, testVariantOf.CompiledGoFiles...) - // Add the package under test and its imports to the test variant. - pkg.forTest = testVariantOf.PkgPath - for k, v := range testVariantOf.Imports { - pkg.Imports[k] = &Package{ID: v.ID} - } - } - if isXTest { - pkg.forTest = forTest - } - } - } - } - if !fileExists { - pkg.GoFiles = append(pkg.GoFiles, opath) - // TODO(matloob): Adding the file to CompiledGoFiles can exhibit the wrong behavior - // if the file will be ignored due to its build tags. - pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, opath) - modifiedPkgsSet[pkg.ID] = true - } - imports, err := extractImports(opath, contents) - if err != nil { - // Let the parser or type checker report errors later. - continue - } - for _, imp := range imports { - // TODO(rstambler): If the package is an x test and the import has - // a test variant, make sure to replace it. - if _, found := pkg.Imports[imp]; found { - continue - } - overlayAddsImports = true - id, ok := havePkgs[imp] - if !ok { - var err error - id, err = state.resolveImport(dir, imp) - if err != nil { - return nil, nil, err - } - } - pkg.Imports[imp] = &Package{ID: id} - // Add dependencies to the non-test variant version of this package as well. - if testVariantOf != nil { - testVariantOf.Imports[imp] = &Package{ID: id} - } - } - } - - // toPkgPath guesses the package path given the id. - toPkgPath := func(sourceDir, id string) (string, error) { - if i := strings.IndexByte(id, ' '); i >= 0 { - return state.resolveImport(sourceDir, id[:i]) - } - return state.resolveImport(sourceDir, id) - } - - // Now that new packages have been created, do another pass to determine - // the new set of missing packages. - for _, pkg := range response.dr.Packages { - for _, imp := range pkg.Imports { - if len(pkg.GoFiles) == 0 { - return nil, nil, fmt.Errorf("cannot resolve imports for package %q with no Go files", pkg.PkgPath) - } - pkgPath, err := toPkgPath(filepath.Dir(pkg.GoFiles[0]), imp.ID) - if err != nil { - return nil, nil, err - } - if _, ok := havePkgs[pkgPath]; !ok { - needPkgsSet[pkgPath] = true - } - } - } - - if overlayAddsImports { - needPkgs = make([]string, 0, len(needPkgsSet)) - for pkg := range needPkgsSet { - needPkgs = append(needPkgs, pkg) - } - } - modifiedPkgs = make([]string, 0, len(modifiedPkgsSet)) - for pkg := range modifiedPkgsSet { - modifiedPkgs = append(modifiedPkgs, pkg) - } - return modifiedPkgs, needPkgs, err -} - -// resolveImport finds the ID of a package given its import path. -// In particular, it will find the right vendored copy when in GOPATH mode. -func (state *golistState) resolveImport(sourceDir, importPath string) (string, error) { - env, err := state.getEnv() - if err != nil { - return "", err - } - if env["GOMOD"] != "" { - return importPath, nil - } - - searchDir := sourceDir - for { - vendorDir := filepath.Join(searchDir, "vendor") - exists, ok := state.vendorDirs[vendorDir] - if !ok { - info, err := os.Stat(vendorDir) - exists = err == nil && info.IsDir() - state.vendorDirs[vendorDir] = exists - } - - if exists { - vendoredPath := filepath.Join(vendorDir, importPath) - if info, err := os.Stat(vendoredPath); err == nil && info.IsDir() { - // We should probably check for .go files here, but shame on anyone who fools us. - path, ok, err := state.getPkgPath(vendoredPath) - if err != nil { - return "", err - } - if ok { - return path, nil - } - } - } - - // We know we've hit the top of the filesystem when we Dir / and get /, - // or C:\ and get C:\, etc. - next := filepath.Dir(searchDir) - if next == searchDir { - break - } - searchDir = next - } - return importPath, nil -} - -func hasTestFiles(p *Package) bool { - for _, f := range p.GoFiles { - if strings.HasSuffix(f, "_test.go") { - return true - } - } - return false -} - // determineRootDirs returns a mapping from absolute directories that could // contain code to their corresponding import path prefixes. func (state *golistState) determineRootDirs() (map[string]string, error) { @@ -384,192 +81,3 @@ func (state *golistState) determineRootDirsGOPATH() (map[string]string, error) { } return m, nil } - -func extractImports(filename string, contents []byte) ([]string, error) { - f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.ImportsOnly) // TODO(matloob): reuse fileset? - if err != nil { - return nil, err - } - var res []string - for _, imp := range f.Imports { - quotedPath := imp.Path.Value - path, err := strconv.Unquote(quotedPath) - if err != nil { - return nil, err - } - res = append(res, path) - } - return res, nil -} - -// reclaimPackage attempts to reuse a package that failed to load in an overlay. -// -// If the package has errors and has no Name, GoFiles, or Imports, -// then it's possible that it doesn't yet exist on disk. -func reclaimPackage(pkg *Package, id string, filename string, contents []byte) bool { - // TODO(rstambler): Check the message of the actual error? - // It differs between $GOPATH and module mode. - if pkg.ID != id { - return false - } - if len(pkg.Errors) != 1 { - return false - } - if pkg.Name != "" || pkg.ExportFile != "" { - return false - } - if len(pkg.GoFiles) > 0 || len(pkg.CompiledGoFiles) > 0 || len(pkg.OtherFiles) > 0 { - return false - } - if len(pkg.Imports) > 0 { - return false - } - pkgName, ok := extractPackageName(filename, contents) - if !ok { - return false - } - pkg.Name = pkgName - pkg.Errors = nil - return true -} - -func extractPackageName(filename string, contents []byte) (string, bool) { - // TODO(rstambler): Check the message of the actual error? - // It differs between $GOPATH and module mode. - f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.PackageClauseOnly) // TODO(matloob): reuse fileset? - if err != nil { - return "", false - } - return f.Name.Name, true -} - -// commonDir returns the directory that all files are in, "" if files is empty, -// or an error if they aren't in the same directory. -func commonDir(files []string) (string, error) { - seen := make(map[string]bool) - for _, f := range files { - seen[filepath.Dir(f)] = true - } - if len(seen) > 1 { - return "", fmt.Errorf("files (%v) are in more than one directory: %v", files, seen) - } - for k := range seen { - // seen has only one element; return it. - return k, nil - } - return "", nil // no files -} - -// It is possible that the files in the disk directory dir have a different package -// name from newName, which is deduced from the overlays. If they all have a different -// package name, and they all have the same package name, then that name becomes -// the package name. -// It returns true if it changes the package name, false otherwise. -func maybeFixPackageName(newName string, isTestFile bool, pkgsOfDir []*Package) { - names := make(map[string]int) - for _, p := range pkgsOfDir { - names[p.Name]++ - } - if len(names) != 1 { - // some files are in different packages - return - } - var oldName string - for k := range names { - oldName = k - } - if newName == oldName { - return - } - // We might have a case where all of the package names in the directory are - // the same, but the overlay file is for an x test, which belongs to its - // own package. If the x test does not yet exist on disk, we may not yet - // have its package name on disk, but we should not rename the packages. - // - // We use a heuristic to determine if this file belongs to an x test: - // The test file should have a package name whose package name has a _test - // suffix or looks like "newName_test". - maybeXTest := strings.HasPrefix(oldName+"_test", newName) || strings.HasSuffix(newName, "_test") - if isTestFile && maybeXTest { - return - } - for _, p := range pkgsOfDir { - p.Name = newName - } -} - -// This function is copy-pasted from -// https://github.com/golang/go/blob/9706f510a5e2754595d716bd64be8375997311fb/src/cmd/go/internal/search/search.go#L360. -// It should be deleted when we remove support for overlays from go/packages. -// -// NOTE: This does not handle any ./... or ./ style queries, as this function -// doesn't know the working directory. -// -// matchPattern(pattern)(name) reports whether -// name matches pattern. Pattern is a limited glob -// pattern in which '...' means 'any string' and there -// is no other special syntax. -// Unfortunately, there are two special cases. Quoting "go help packages": -// -// First, /... at the end of the pattern can match an empty string, -// so that net/... matches both net and packages in its subdirectories, like net/http. -// Second, any slash-separated pattern element containing a wildcard never -// participates in a match of the "vendor" element in the path of a vendored -// package, so that ./... does not match packages in subdirectories of -// ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do. -// Note, however, that a directory named vendor that itself contains code -// is not a vendored package: cmd/vendor would be a command named vendor, -// and the pattern cmd/... matches it. -func matchPattern(pattern string) func(name string) bool { - // Convert pattern to regular expression. - // The strategy for the trailing /... is to nest it in an explicit ? expression. - // The strategy for the vendor exclusion is to change the unmatchable - // vendor strings to a disallowed code point (vendorChar) and to use - // "(anything but that codepoint)*" as the implementation of the ... wildcard. - // This is a bit complicated but the obvious alternative, - // namely a hand-written search like in most shell glob matchers, - // is too easy to make accidentally exponential. - // Using package regexp guarantees linear-time matching. - - const vendorChar = "\x00" - - if strings.Contains(pattern, vendorChar) { - return func(name string) bool { return false } - } - - re := regexp.QuoteMeta(pattern) - re = replaceVendor(re, vendorChar) - switch { - case strings.HasSuffix(re, `/`+vendorChar+`/\.\.\.`): - re = strings.TrimSuffix(re, `/`+vendorChar+`/\.\.\.`) + `(/vendor|/` + vendorChar + `/\.\.\.)` - case re == vendorChar+`/\.\.\.`: - re = `(/vendor|/` + vendorChar + `/\.\.\.)` - case strings.HasSuffix(re, `/\.\.\.`): - re = strings.TrimSuffix(re, `/\.\.\.`) + `(/\.\.\.)?` - } - re = strings.ReplaceAll(re, `\.\.\.`, `[^`+vendorChar+`]*`) - - reg := regexp.MustCompile(`^` + re + `$`) - - return func(name string) bool { - if strings.Contains(name, vendorChar) { - return false - } - return reg.MatchString(replaceVendor(name, vendorChar)) - } -} - -// replaceVendor returns the result of replacing -// non-trailing vendor path elements in x with repl. -func replaceVendor(x, repl string) string { - if !strings.Contains(x, "vendor") { - return x - } - elem := strings.Split(x, "/") - for i := 0; i < len(elem)-1; i++ { - if elem[i] == "vendor" { - elem[i] = repl - } - } - return strings.Join(elem, "/") -} diff --git a/vendor/golang.org/x/tools/go/packages/packages.go b/vendor/golang.org/x/tools/go/packages/packages.go index ece0e7c60..81e9e6a72 100644 --- a/vendor/golang.org/x/tools/go/packages/packages.go +++ b/vendor/golang.org/x/tools/go/packages/packages.go @@ -27,8 +27,8 @@ import ( "golang.org/x/tools/go/gcexportdata" "golang.org/x/tools/internal/gocommand" "golang.org/x/tools/internal/packagesinternal" - "golang.org/x/tools/internal/typeparams" "golang.org/x/tools/internal/typesinternal" + "golang.org/x/tools/internal/versions" ) // A LoadMode controls the amount of detail to return when loading. @@ -258,31 +258,52 @@ type driverResponse struct { // proceeding with further analysis. The PrintErrors function is // provided for convenient display of all errors. func Load(cfg *Config, patterns ...string) ([]*Package, error) { - l := newLoader(cfg) - response, err := defaultDriver(&l.Config, patterns...) + ld := newLoader(cfg) + response, external, err := defaultDriver(&ld.Config, patterns...) if err != nil { return nil, err } - l.sizes = types.SizesFor(response.Compiler, response.Arch) - return l.refine(response) + + ld.sizes = types.SizesFor(response.Compiler, response.Arch) + if ld.sizes == nil && ld.Config.Mode&(NeedTypes|NeedTypesSizes|NeedTypesInfo) != 0 { + // Type size information is needed but unavailable. + if external { + // An external driver may fail to populate the Compiler/GOARCH fields, + // especially since they are relatively new (see #63700). + // Provide a sensible fallback in this case. + ld.sizes = types.SizesFor("gc", runtime.GOARCH) + if ld.sizes == nil { // gccgo-only arch + ld.sizes = types.SizesFor("gc", "amd64") + } + } else { + // Go list should never fail to deliver accurate size information. + // Reject the whole Load since the error is the same for every package. + return nil, fmt.Errorf("can't determine type sizes for compiler %q on GOARCH %q", + response.Compiler, response.Arch) + } + } + + return ld.refine(response) } // defaultDriver is a driver that implements go/packages' fallback behavior. // It will try to request to an external driver, if one exists. If there's // no external driver, or the driver returns a response with NotHandled set, // defaultDriver will fall back to the go list driver. -func defaultDriver(cfg *Config, patterns ...string) (*driverResponse, error) { - driver := findExternalDriver(cfg) - if driver == nil { - driver = goListDriver - } - response, err := driver(cfg, patterns...) - if err != nil { - return response, err - } else if response.NotHandled { - return goListDriver(cfg, patterns...) +// The boolean result indicates that an external driver handled the request. +func defaultDriver(cfg *Config, patterns ...string) (*driverResponse, bool, error) { + if driver := findExternalDriver(cfg); driver != nil { + response, err := driver(cfg, patterns...) + if err != nil { + return nil, false, err + } else if !response.NotHandled { + return response, true, nil + } + // (fall through) } - return response, nil + + response, err := goListDriver(cfg, patterns...) + return response, false, err } // A Package describes a loaded Go package. @@ -411,12 +432,6 @@ func init() { packagesinternal.GetDepsErrors = func(p interface{}) []*packagesinternal.PackageError { return p.(*Package).depsErrors } - packagesinternal.GetGoCmdRunner = func(config interface{}) *gocommand.Runner { - return config.(*Config).gocmdRunner - } - packagesinternal.SetGoCmdRunner = func(config interface{}, runner *gocommand.Runner) { - config.(*Config).gocmdRunner = runner - } packagesinternal.SetModFile = func(config interface{}, value string) { config.(*Config).modFile = value } @@ -553,7 +568,7 @@ type loaderPackage struct { type loader struct { pkgs map[string]*loaderPackage Config - sizes types.Sizes + sizes types.Sizes // non-nil if needed by mode parseCache map[string]*parseValue parseCacheMu sync.Mutex exportMu sync.Mutex // enforces mutual exclusion of exportdata operations @@ -678,39 +693,38 @@ func (ld *loader) refine(response *driverResponse) ([]*Package, error) { } } - // Materialize the import graph. - - const ( - white = 0 // new - grey = 1 // in progress - black = 2 // complete - ) - - // visit traverses the import graph, depth-first, - // and materializes the graph as Packages.Imports. - // - // Valid imports are saved in the Packages.Import map. - // Invalid imports (cycles and missing nodes) are saved in the importErrors map. - // Thus, even in the presence of both kinds of errors, the Import graph remains a DAG. - // - // visit returns whether the package needs src or has a transitive - // dependency on a package that does. These are the only packages - // for which we load source code. - var stack []*loaderPackage - var visit func(lpkg *loaderPackage) bool - var srcPkgs []*loaderPackage - visit = func(lpkg *loaderPackage) bool { - switch lpkg.color { - case black: - return lpkg.needsrc - case grey: - panic("internal error: grey node") - } - lpkg.color = grey - stack = append(stack, lpkg) // push - stubs := lpkg.Imports // the structure form has only stubs with the ID in the Imports - // If NeedImports isn't set, the imports fields will all be zeroed out. - if ld.Mode&NeedImports != 0 { + if ld.Mode&NeedImports != 0 { + // Materialize the import graph. + + const ( + white = 0 // new + grey = 1 // in progress + black = 2 // complete + ) + + // visit traverses the import graph, depth-first, + // and materializes the graph as Packages.Imports. + // + // Valid imports are saved in the Packages.Import map. + // Invalid imports (cycles and missing nodes) are saved in the importErrors map. + // Thus, even in the presence of both kinds of errors, + // the Import graph remains a DAG. + // + // visit returns whether the package needs src or has a transitive + // dependency on a package that does. These are the only packages + // for which we load source code. + var stack []*loaderPackage + var visit func(lpkg *loaderPackage) bool + visit = func(lpkg *loaderPackage) bool { + switch lpkg.color { + case black: + return lpkg.needsrc + case grey: + panic("internal error: grey node") + } + lpkg.color = grey + stack = append(stack, lpkg) // push + stubs := lpkg.Imports // the structure form has only stubs with the ID in the Imports lpkg.Imports = make(map[string]*Package, len(stubs)) for importPath, ipkg := range stubs { var importErr error @@ -734,40 +748,39 @@ func (ld *loader) refine(response *driverResponse) ([]*Package, error) { } lpkg.Imports[importPath] = imp.Package } - } - if lpkg.needsrc { - srcPkgs = append(srcPkgs, lpkg) - } - if ld.Mode&NeedTypesSizes != 0 { - lpkg.TypesSizes = ld.sizes - } - stack = stack[:len(stack)-1] // pop - lpkg.color = black - return lpkg.needsrc - } + // Complete type information is required for the + // immediate dependencies of each source package. + if lpkg.needsrc && ld.Mode&NeedTypes != 0 { + for _, ipkg := range lpkg.Imports { + ld.pkgs[ipkg.ID].needtypes = true + } + } - if ld.Mode&NeedImports == 0 { - // We do this to drop the stub import packages that we are not even going to try to resolve. - for _, lpkg := range initial { - lpkg.Imports = nil + // NeedTypeSizes causes TypeSizes to be set even + // on packages for which types aren't needed. + if ld.Mode&NeedTypesSizes != 0 { + lpkg.TypesSizes = ld.sizes + } + stack = stack[:len(stack)-1] // pop + lpkg.color = black + + return lpkg.needsrc } - } else { + // For each initial package, create its import DAG. for _, lpkg := range initial { visit(lpkg) } - } - if ld.Mode&NeedImports != 0 && ld.Mode&NeedTypes != 0 { - for _, lpkg := range srcPkgs { - // Complete type information is required for the - // immediate dependencies of each source package. - for _, ipkg := range lpkg.Imports { - imp := ld.pkgs[ipkg.ID] - imp.needtypes = true - } + + } else { + // !NeedImports: drop the stub (ID-only) import packages + // that we are not even going to try to resolve. + for _, lpkg := range initial { + lpkg.Imports = nil } } + // Load type data and syntax if needed, starting at // the initial packages (roots of the import DAG). if ld.Mode&NeedTypes != 0 || ld.Mode&NeedSyntax != 0 { @@ -1001,10 +1014,11 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { Defs: make(map[*ast.Ident]types.Object), Uses: make(map[*ast.Ident]types.Object), Implicits: make(map[ast.Node]types.Object), + Instances: make(map[*ast.Ident]types.Instance), Scopes: make(map[ast.Node]*types.Scope), Selections: make(map[*ast.SelectorExpr]*types.Selection), } - typeparams.InitInstanceInfo(lpkg.TypesInfo) + versions.InitFileVersions(lpkg.TypesInfo) lpkg.TypesSizes = ld.sizes importer := importerFunc(func(path string) (*types.Package, error) { @@ -1042,7 +1056,7 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { IgnoreFuncBodies: ld.Mode&NeedDeps == 0 && !lpkg.initial, Error: appendError, - Sizes: ld.sizes, + Sizes: ld.sizes, // may be nil } if lpkg.Module != nil && lpkg.Module.GoVersion != "" { typesinternal.SetGoVersion(tc, "go"+lpkg.Module.GoVersion) diff --git a/vendor/golang.org/x/tools/go/ssa/builder.go b/vendor/golang.org/x/tools/go/ssa/builder.go index 0e49537d0..8622dfc53 100644 --- a/vendor/golang.org/x/tools/go/ssa/builder.go +++ b/vendor/golang.org/x/tools/go/ssa/builder.go @@ -4,106 +4,73 @@ package ssa -// This file implements the BUILD phase of SSA construction. +// This file defines the builder, which builds SSA-form IR for function bodies. // -// SSA construction has two phases, CREATE and BUILD. In the CREATE phase -// (create.go), all packages are constructed and type-checked and -// definitions of all package members are created, method-sets are -// computed, and wrapper methods are synthesized. -// ssa.Packages are created in arbitrary order. +// SSA construction has two phases, "create" and "build". First, one +// or more packages are created in any order by a sequence of calls to +// CreatePackage, either from syntax or from mere type information. +// Each created package has a complete set of Members (const, var, +// type, func) that can be accessed through methods like +// Program.FuncValue. // -// In the BUILD phase (builder.go), the builder traverses the AST of -// each Go source function and generates SSA instructions for the -// function body. Initializer expressions for package-level variables -// are emitted to the package's init() function in the order specified -// by go/types.Info.InitOrder, then code for each function in the -// package is generated in lexical order. -// The BUILD phases for distinct packages are independent and are -// executed in parallel. +// It is not necessary to call CreatePackage for all dependencies of +// each syntax package, only for its direct imports. (In future +// perhaps even this restriction may be lifted.) // -// TODO(adonovan): indeed, building functions is now embarrassingly parallel. -// Audit for concurrency then benchmark using more goroutines. +// Second, packages created from syntax are built, by one or more +// calls to Package.Build, which may be concurrent; or by a call to +// Program.Build, which builds all packages in parallel. Building +// traverses the type-annotated syntax tree of each function body and +// creates SSA-form IR, a control-flow graph of instructions, +// populating fields such as Function.Body, .Params, and others. // -// State: +// Building may create additional methods, including: +// - wrapper methods (e.g. for embeddding, or implicit &recv) +// - bound method closures (e.g. for use(recv.f)) +// - thunks (e.g. for use(I.f) or use(T.f)) +// - generic instances (e.g. to produce f[int] from f[any]). +// As these methods are created, they are added to the build queue, +// and then processed in turn, until a fixed point is reached, +// Since these methods might belong to packages that were not +// created (by a call to CreatePackage), their Pkg field is unset. // -// The Package's and Program's indices (maps) are populated and -// mutated during the CREATE phase, but during the BUILD phase they -// remain constant. The sole exception is Prog.methodSets and its -// related maps, which are protected by a dedicated mutex. +// Instances of generic functions may be either instantiated (f[int] +// is a copy of f[T] with substitutions) or wrapped (f[int] delegates +// to f[T]), depending on the availability of generic syntax and the +// InstantiateGenerics mode flag. // -// Generic functions declared in a package P can be instantiated from functions -// outside of P. This happens independently of the CREATE and BUILD phase of P. +// Each package has an initializer function named "init" that calls +// the initializer functions of each direct import, computes and +// assigns the initial value of each global variable, and calls each +// source-level function named "init". (These generate SSA functions +// named "init#1", "init#2", etc.) // -// Locks: +// Runtime types // -// Mutexes are currently acquired according to the following order: -// Prog.methodsMu ⊃ canonizer.mu ⊃ printMu -// where x ⊃ y denotes that y can be acquired while x is held -// and x cannot be acquired while y is held. +// Each MakeInterface operation is a conversion from a non-interface +// type to an interface type. The semantics of this operation requires +// a runtime type descriptor, which is the type portion of an +// interface, and the value abstracted by reflect.Type. // -// Synthetics: +// The program accumulates all non-parameterized types that are +// encountered as MakeInterface operands, along with all types that +// may be derived from them using reflection. This set is available as +// Program.RuntimeTypes, and the methods of these types may be +// reachable via interface calls or reflection even if they are never +// referenced from the SSA IR. (In practice, algorithms such as RTA +// that compute reachability from package main perform their own +// tracking of runtime types at a finer grain, so this feature is not +// very useful.) // -// During the BUILD phase new functions can be created and built. These include: -// - wrappers (wrappers, bounds, thunks) -// - generic function instantiations -// These functions do not belong to a specific Pkg (Pkg==nil). Instead the -// Package that led to them being CREATED is obligated to ensure these -// are BUILT during the BUILD phase of the Package. +// Function literals // -// Runtime types: +// Anonymous functions must be built as soon as they are encountered, +// as it may affect locals of the enclosing function, but they are not +// marked 'built' until the end of the outermost enclosing function. +// (Among other things, this causes them to be logged in top-down order.) // -// A concrete type is a type that is fully monomorphized with concrete types, -// i.e. it cannot reach a TypeParam type. -// Some concrete types require full runtime type information. Cases -// include checking whether a type implements an interface or -// interpretation by the reflect package. All such types that may require -// this information will have all of their method sets built and will be added to Prog.methodSets. -// A type T is considered to require runtime type information if it is -// a runtime type and has a non-empty method set and either: -// - T flows into a MakeInterface instructions, -// - T appears in a concrete exported member, or -// - T is a type reachable from a type S that has non-empty method set. -// For any such type T, method sets must be created before the BUILD -// phase of the package is done. -// -// Function literals: -// -// The BUILD phase of a function literal (anonymous function) is tied to the -// BUILD phase of the enclosing parent function. The FreeVars of an anonymous -// function are discovered by building the anonymous function. This in turn -// changes which variables must be bound in a MakeClosure instruction in the -// parent. Anonymous functions also track where they are referred to in their -// parent function. -// -// Happens-before: -// -// The above discussion leads to the following happens-before relation for -// the BUILD and CREATE phases. -// The happens-before relation (with X 0 { targs := fn.subst.types(instanceArgs(fn.info, e)) - callee = fn.Prog.needsInstance(callee, targs, b.created) + callee = callee.instance(targs, b.created) } return callee } // Local var. - return emitLoad(fn, fn.lookup(obj, false)) // var (address) + return emitLoad(fn, fn.lookup(obj.(*types.Var), false)) // var (address) case *ast.SelectorExpr: sel := fn.selection(e) @@ -821,7 +787,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value { case types.MethodExpr: // (*T).f or T.f, the method f from the method-set of type T. // The result is a "thunk". - thunk := makeThunk(fn.Prog, sel, b.created) + thunk := createThunk(fn.Prog, sel, b.created) return emitConv(fn, thunk, fn.typ(tv.Type)) case types.MethodVal: @@ -836,7 +802,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value { if types.IsInterface(rt) { // If v may be an interface type I (after instantiating), // we must emit a check that v is non-nil. - if recv, ok := sel.recv.(*typeparams.TypeParam); ok { + if recv, ok := sel.recv.(*types.TypeParam); ok { // Emit a nil check if any possible instantiation of the // type parameter is an interface type. if typeSetOf(recv).Len() > 0 { @@ -856,7 +822,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value { } else { // non-type param interface // Emit nil check: typeassert v.(I). - emitTypeAssert(fn, v, rt, token.NoPos) + emitTypeAssert(fn, v, rt, e.Sel.Pos()) } } if targs := receiverTypeArgs(obj); len(targs) > 0 { @@ -864,7 +830,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value { obj = fn.Prog.canon.instantiateMethod(obj, fn.subst.types(targs), fn.Prog.ctxt) } c := &MakeClosure{ - Fn: makeBound(fn.Prog, obj, b.created), + Fn: createBound(fn.Prog, obj, b.created), Bindings: []Value{v}, } c.setPos(e.Sel.Pos()) @@ -882,7 +848,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value { panic("unexpected expression-relative selector") - case *typeparams.IndexListExpr: + case *ast.IndexListExpr: // f[X, Y] must be a generic function if !instance(fn.info, e.X) { panic("unexpected expression-could not match index list to instantiation") @@ -966,7 +932,10 @@ func (b *builder) receiver(fn *Function, e ast.Expr, wantAddr, escaping bool, se last := len(sel.index) - 1 // The position of implicit selection is the position of the inducing receiver expression. v = emitImplicitSelections(fn, v, sel.index[:last], e.Pos()) - if _, vptr := deref(v.Type()); !wantAddr && vptr { + if types.IsInterface(v.Type()) { + // When v is an interface, sel.Kind()==MethodValue and v.f is invoked. + // So v is not loaded, even if v has a pointer core type. + } else if _, vptr := deref(v.Type()); !wantAddr && vptr { v = emitLoad(fn, v) } return v @@ -994,11 +963,7 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) { c.Method = obj } else { // "Call"-mode call. - callee := fn.Prog.originFunc(obj) - if callee.typeparams.Len() > 0 { - callee = fn.Prog.needsInstance(callee, receiverTypeArgs(obj), b.created) - } - c.Value = callee + c.Value = fn.Prog.objectMethod(obj, b.created) c.Args = append(c.Args, v) } return @@ -1090,9 +1055,8 @@ func (b *builder) emitCallArgs(fn *Function, sig *types.Signature, e *ast.CallEx } else { // Replace a suffix of args with a slice containing it. at := types.NewArray(vt, int64(len(varargs))) - a := emitNew(fn, at, token.NoPos) + a := emitNew(fn, at, token.NoPos, "varargs") a.setPos(e.Rparen) - a.Comment = "varargs" for i, arg := range varargs { iaddr := &IndexAddr{ X: a, @@ -1139,7 +1103,7 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) { // 1:1 assignment for i, id := range spec.Names { if !isBlankIdent(id) { - fn.addLocalForIdent(id) + emitLocalVar(fn, identVar(fn, id)) } lval := b.addr(fn, id, false) // non-escaping b.assign(fn, lval, spec.Values[i], true, nil) @@ -1150,7 +1114,7 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) { // Locals are implicitly zero-initialized. for _, id := range spec.Names { if !isBlankIdent(id) { - lhs := fn.addLocalForIdent(id) + lhs := emitLocalVar(fn, identVar(fn, id)) if fn.debugInfo() { emitDebugRef(fn, id, lhs, true) } @@ -1162,7 +1126,7 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) { tuple := b.exprN(fn, spec.Values[0]) for i, id := range spec.Names { if !isBlankIdent(id) { - fn.addLocalForIdent(id) + emitLocalVar(fn, identVar(fn, id)) lhs := b.addr(fn, id, false) // non-escaping lhs.store(fn, emitExtract(fn, tuple, i)) } @@ -1182,8 +1146,8 @@ func (b *builder) assignStmt(fn *Function, lhss, rhss []ast.Expr, isDef bool) { var lval lvalue = blank{} if !isBlankIdent(lhs) { if isDef { - if obj := fn.info.Defs[lhs.(*ast.Ident)]; obj != nil { - fn.addNamedLocal(obj) + if obj, ok := fn.info.Defs[lhs.(*ast.Ident)].(*types.Var); ok { + emitLocalVar(fn, obj) isZero[i] = true } } @@ -1292,9 +1256,7 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero switch t := t.(type) { case *types.Slice: at = types.NewArray(t.Elem(), b.arrayLen(fn, e.Elts)) - alloc := emitNew(fn, at, e.Lbrace) - alloc.Comment = "slicelit" - array = alloc + array = emitNew(fn, at, e.Lbrace, "slicelit") case *types.Array: at = t array = addr @@ -1582,13 +1544,13 @@ func (b *builder) typeSwitchStmt(fn *Function, s *ast.TypeSwitchStmt, label *lbl } func (b *builder) typeCaseBody(fn *Function, cc *ast.CaseClause, x Value, done *BasicBlock) { - if obj := fn.info.Implicits[cc]; obj != nil { + if obj, ok := fn.info.Implicits[cc].(*types.Var); ok { // In a switch y := x.(type), each case clause // implicitly declares a distinct object y. // In a single-type case, y has that type. // In multi-type cases, 'case nil' and default, // y has the same type as the interface operand. - emitStore(fn, fn.addNamedLocal(obj), x, obj.Pos()) + emitStore(fn, emitLocalVar(fn, obj), x, obj.Pos()) } fn.targets = &targets{ tail: fn.targets, @@ -1737,7 +1699,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) { case *ast.AssignStmt: // x := <-states[state].Chan if comm.Tok == token.DEFINE { - fn.addLocalForIdent(comm.Lhs[0].(*ast.Ident)) + emitLocalVar(fn, identVar(fn, comm.Lhs[0].(*ast.Ident))) } x := b.addr(fn, comm.Lhs[0], false) // non-escaping v := emitExtract(fn, sel, r) @@ -1748,7 +1710,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) { if len(comm.Lhs) == 2 { // x, ok := ... if comm.Tok == token.DEFINE { - fn.addLocalForIdent(comm.Lhs[1].(*ast.Ident)) + emitLocalVar(fn, identVar(fn, comm.Lhs[1].(*ast.Ident))) } ok := b.addr(fn, comm.Lhs[1], false) // non-escaping ok.store(fn, emitExtract(fn, sel, 1)) @@ -1783,20 +1745,32 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) { // forStmt emits to fn code for the for statement s, optionally // labelled by label. func (b *builder) forStmt(fn *Function, s *ast.ForStmt, label *lblock) { - // ...init... - // jump loop + // Use forStmtGo122 instead if it applies. + if s.Init != nil { + if assign, ok := s.Init.(*ast.AssignStmt); ok && assign.Tok == token.DEFINE { + afterGo122 := versions.Compare(fn.goversion, "go1.21") > 0 + if afterGo122 { + b.forStmtGo122(fn, s, label) + return + } + } + } + + // ...init... + // jump loop // loop: - // if cond goto body else done + // if cond goto body else done // body: - // ...body... - // jump post - // post: (target of continue) - // ...post... - // jump loop + // ...body... + // jump post + // post: (target of continue) + // ...post... + // jump loop // done: (target of break) if s.Init != nil { b.stmt(fn, s.Init) } + body := fn.newBasicBlock("for.body") done := fn.newBasicBlock("for.done") // target of 'break' loop := body // target of back-edge @@ -1834,23 +1808,188 @@ func (b *builder) forStmt(fn *Function, s *ast.ForStmt, label *lblock) { fn.currentBlock = done } +// forStmtGo122 emits to fn code for the for statement s, optionally +// labelled by label. s must define its variables. +// +// This allocates once per loop iteration. This is only correct in +// GoVersions >= go1.22. +func (b *builder) forStmtGo122(fn *Function, s *ast.ForStmt, label *lblock) { + // i_outer = alloc[T] + // *i_outer = ...init... // under objects[i] = i_outer + // jump loop + // loop: + // i = phi [head: i_outer, loop: i_next] + // ...cond... // under objects[i] = i + // if cond goto body else done + // body: + // ...body... // under objects[i] = i (same as loop) + // jump post + // post: + // tmp = *i + // i_next = alloc[T] + // *i_next = tmp + // ...post... // under objects[i] = i_next + // goto loop + // done: + + init := s.Init.(*ast.AssignStmt) + startingBlocks := len(fn.Blocks) + + pre := fn.currentBlock // current block before starting + loop := fn.newBasicBlock("for.loop") // target of back-edge + body := fn.newBasicBlock("for.body") + post := fn.newBasicBlock("for.post") // target of 'continue' + done := fn.newBasicBlock("for.done") // target of 'break' + + // For each of the n loop variables, we create five SSA values, + // outer, phi, next, load, and store in pre, loop, and post. + // There is no limit on n. + type loopVar struct { + obj *types.Var + outer *Alloc + phi *Phi + load *UnOp + next *Alloc + store *Store + } + vars := make([]loopVar, len(init.Lhs)) + for i, lhs := range init.Lhs { + v := identVar(fn, lhs.(*ast.Ident)) + typ := fn.typ(v.Type()) + + fn.currentBlock = pre + outer := emitLocal(fn, typ, v.Pos(), v.Name()) + + fn.currentBlock = loop + phi := &Phi{Comment: v.Name()} + phi.pos = v.Pos() + phi.typ = outer.Type() + fn.emit(phi) + + fn.currentBlock = post + // If next is is local, it reuses the address and zeroes the old value so + // load before allocating next. + load := emitLoad(fn, phi) + next := emitLocal(fn, typ, v.Pos(), v.Name()) + store := emitStore(fn, next, load, token.NoPos) + + phi.Edges = []Value{outer, next} // pre edge is emitted before post edge. + + vars[i] = loopVar{v, outer, phi, load, next, store} + } + + // ...init... under fn.objects[v] = i_outer + fn.currentBlock = pre + for _, v := range vars { + fn.vars[v.obj] = v.outer + } + const isDef = false // assign to already-allocated outers + b.assignStmt(fn, init.Lhs, init.Rhs, isDef) + if label != nil { + label._break = done + label._continue = post + } + emitJump(fn, loop) + + // ...cond... under fn.objects[v] = i + fn.currentBlock = loop + for _, v := range vars { + fn.vars[v.obj] = v.phi + } + if s.Cond != nil { + b.cond(fn, s.Cond, body, done) + } else { + emitJump(fn, body) + } + + // ...body... under fn.objects[v] = i + fn.currentBlock = body + fn.targets = &targets{ + tail: fn.targets, + _break: done, + _continue: post, + } + b.stmt(fn, s.Body) + fn.targets = fn.targets.tail + emitJump(fn, post) + + // ...post... under fn.objects[v] = i_next + for _, v := range vars { + fn.vars[v.obj] = v.next + } + fn.currentBlock = post + if s.Post != nil { + b.stmt(fn, s.Post) + } + emitJump(fn, loop) // back-edge + fn.currentBlock = done + + // For each loop variable that does not escape, + // (the common case), fuse its next cells into its + // (local) outer cell as they have disjoint live ranges. + // + // It is sufficient to test whether i_next escapes, + // because its Heap flag will be marked true if either + // the cond or post expression causes i to escape + // (because escape distributes over phi). + var nlocals int + for _, v := range vars { + if !v.next.Heap { + nlocals++ + } + } + if nlocals > 0 { + replace := make(map[Value]Value, 2*nlocals) + dead := make(map[Instruction]bool, 4*nlocals) + for _, v := range vars { + if !v.next.Heap { + replace[v.next] = v.outer + replace[v.phi] = v.outer + dead[v.phi], dead[v.next], dead[v.load], dead[v.store] = true, true, true, true + } + } + + // Replace all uses of i_next and phi with i_outer. + // Referrers have not been built for fn yet so only update Instruction operands. + // We need only look within the blocks added by the loop. + var operands []*Value // recycle storage + for _, b := range fn.Blocks[startingBlocks:] { + for _, instr := range b.Instrs { + operands = instr.Operands(operands[:0]) + for _, ptr := range operands { + k := *ptr + if v := replace[k]; v != nil { + *ptr = v + } + } + } + } + + // Remove instructions for phi, load, and store. + // lift() will remove the unused i_next *Alloc. + isDead := func(i Instruction) bool { return dead[i] } + loop.Instrs = removeInstrsIf(loop.Instrs, isDead) + post.Instrs = removeInstrsIf(post.Instrs, isDead) + } +} + // rangeIndexed emits to fn the header for an integer-indexed loop // over array, *array or slice value x. // The v result is defined only if tv is non-nil. // forPos is the position of the "for" token. func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type, pos token.Pos) (k, v Value, loop, done *BasicBlock) { // - // length = len(x) - // index = -1 - // loop: (target of continue) - // index++ - // if index < length goto body else done + // length = len(x) + // index = -1 + // loop: (target of continue) + // index++ + // if index < length goto body else done // body: - // k = index - // v = x[index] - // ...body... - // jump loop - // done: (target of break) + // k = index + // v = x[index] + // ...body... + // jump loop + // done: (target of break) // Determine number of iterations. var length Value @@ -1872,7 +2011,7 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type, pos token.P length = fn.emit(&c) } - index := fn.addLocal(tInt, token.NoPos) + index := emitLocal(fn, tInt, token.NoPos, "rangeindex") emitStore(fn, index, intConst(-1), pos) loop = fn.newBasicBlock("rangeindex.loop") @@ -1935,16 +2074,16 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type, pos token.P // if the respective component is not wanted. func (b *builder) rangeIter(fn *Function, x Value, tk, tv types.Type, pos token.Pos) (k, v Value, loop, done *BasicBlock) { // - // it = range x + // it = range x // loop: (target of continue) - // okv = next it (ok, key, value) - // ok = extract okv #0 - // if ok goto body else done + // okv = next it (ok, key, value) + // ok = extract okv #0 + // if ok goto body else done // body: - // k = extract okv #1 - // v = extract okv #2 - // ...body... - // jump loop + // k = extract okv #1 + // v = extract okv #2 + // ...body... + // jump loop // done: (target of break) // @@ -1997,13 +2136,13 @@ func (b *builder) rangeIter(fn *Function, x Value, tk, tv types.Type, pos token. func (b *builder) rangeChan(fn *Function, x Value, tk types.Type, pos token.Pos) (k Value, loop, done *BasicBlock) { // // loop: (target of continue) - // ko = <-x (key, ok) - // ok = extract ko #1 - // if ok goto body else done + // ko = <-x (key, ok) + // ok = extract ko #1 + // if ok goto body else done // body: - // k = extract ko #0 - // ... - // goto loop + // k = extract ko #0 + // ...body... + // goto loop // done: (target of break) loop = fn.newBasicBlock("rangechan.loop") @@ -2030,6 +2169,57 @@ func (b *builder) rangeChan(fn *Function, x Value, tk types.Type, pos token.Pos) return } +// rangeInt emits to fn the header for a range loop with an integer operand. +// tk is the key value's type, or nil if the k result is not wanted. +// pos is the position of the "for" token. +func (b *builder) rangeInt(fn *Function, x Value, tk types.Type, pos token.Pos) (k Value, loop, done *BasicBlock) { + // + // iter = 0 + // if 0 < x goto body else done + // loop: (target of continue) + // iter++ + // if iter < x goto body else done + // body: + // k = x + // ...body... + // jump loop + // done: (target of break) + + if isUntyped(x.Type()) { + x = emitConv(fn, x, tInt) + } + + T := x.Type() + iter := emitLocal(fn, T, token.NoPos, "rangeint.iter") + // x may be unsigned. Avoid initializing x to -1. + + body := fn.newBasicBlock("rangeint.body") + done = fn.newBasicBlock("rangeint.done") + emitIf(fn, emitCompare(fn, token.LSS, zeroConst(T), x, token.NoPos), body, done) + + loop = fn.newBasicBlock("rangeint.loop") + fn.currentBlock = loop + + incr := &BinOp{ + Op: token.ADD, + X: emitLoad(fn, iter), + Y: emitConv(fn, vOne, T), + } + incr.setType(T) + emitStore(fn, iter, fn.emit(incr), pos) + emitIf(fn, emitCompare(fn, token.LSS, incr, x, token.NoPos), body, done) + fn.currentBlock = body + + if tk != nil { + // Integer types (int, uint8, etc.) are named and + // we know that k is assignable to x when tk != nil. + // This implies tk and T are identical so no conversion is needed. + k = emitLoad(fn, iter) + } + + return +} + // rangeStmt emits to fn code for the range statement s, optionally // labelled by label. func (b *builder) rangeStmt(fn *Function, s *ast.RangeStmt, label *lblock) { @@ -2041,21 +2231,26 @@ func (b *builder) rangeStmt(fn *Function, s *ast.RangeStmt, label *lblock) { tv = fn.typeOf(s.Value) } - // If iteration variables are defined (:=), this - // occurs once outside the loop. - // - // Unlike a short variable declaration, a RangeStmt - // using := never redeclares an existing variable; it - // always creates a new one. - if s.Tok == token.DEFINE { + // create locals for s.Key and s.Value. + createVars := func() { + // Unlike a short variable declaration, a RangeStmt + // using := never redeclares an existing variable; it + // always creates a new one. if tk != nil { - fn.addLocalForIdent(s.Key.(*ast.Ident)) + emitLocalVar(fn, identVar(fn, s.Key.(*ast.Ident))) } if tv != nil { - fn.addLocalForIdent(s.Value.(*ast.Ident)) + emitLocalVar(fn, identVar(fn, s.Value.(*ast.Ident))) } } + afterGo122 := versions.Compare(fn.goversion, "go1.21") > 0 + if s.Tok == token.DEFINE && !afterGo122 { + // pre-go1.22: If iteration variables are defined (:=), this + // occurs once outside the loop. + createVars() + } + x := b.expr(fn, s.X) var k, v Value @@ -2067,13 +2262,30 @@ func (b *builder) rangeStmt(fn *Function, s *ast.RangeStmt, label *lblock) { case *types.Chan: k, loop, done = b.rangeChan(fn, x, tk, s.For) - case *types.Map, *types.Basic: // string + case *types.Map: k, v, loop, done = b.rangeIter(fn, x, tk, tv, s.For) + case *types.Basic: + switch { + case rt.Info()&types.IsString != 0: + k, v, loop, done = b.rangeIter(fn, x, tk, tv, s.For) + + case rt.Info()&types.IsInteger != 0: + k, loop, done = b.rangeInt(fn, x, tk, s.For) + + default: + panic("Cannot range over basic type: " + rt.String()) + } + default: panic("Cannot range over: " + rt.String()) } + if s.Tok == token.DEFINE && afterGo122 { + // go1.22: If iteration variables are defined (:=), this occurs inside the loop. + createVars() + } + // Evaluate both LHS expressions before we update either. var kl, vl lvalue if tk != nil { @@ -2297,73 +2509,71 @@ start: } } +// A buildFunc is a strategy for building the SSA body for a function. +type buildFunc = func(*builder, *Function) + +// iterate causes all created but unbuilt functions to be built. As +// this may create new methods, the process is iterated until it +// converges. +func (b *builder) iterate() { + for ; b.finished < b.created.Len(); b.finished++ { + fn := b.created.At(b.finished) + b.buildFunction(fn) + } +} + // buildFunction builds SSA code for the body of function fn. Idempotent. func (b *builder) buildFunction(fn *Function) { - if !fn.built { + if fn.build != nil { assert(fn.parent == nil, "anonymous functions should not be built by buildFunction()") - b.buildFunctionBody(fn) + + if fn.Prog.mode&LogSource != 0 { + defer logStack("build %s @ %s", fn, fn.Prog.Fset.Position(fn.pos))() + } + fn.build(b, fn) fn.done() } } -// buildFunctionBody builds SSA code for the body of function fn. -// -// fn is not done building until fn.done() is called. -func (b *builder) buildFunctionBody(fn *Function) { - // TODO(taking): see if this check is reachable. - if fn.Blocks != nil { - return // building already started +// buildParamsOnly builds fn.Params from fn.Signature, but does not build fn.Body. +func (b *builder) buildParamsOnly(fn *Function) { + // For external (C, asm) functions or functions loaded from + // export data, we must set fn.Params even though there is no + // body code to reference them. + if recv := fn.Signature.Recv(); recv != nil { + fn.addParamVar(recv) } + params := fn.Signature.Params() + for i, n := 0, params.Len(); i < n; i++ { + fn.addParamVar(params.At(i)) + } +} - var recvField *ast.FieldList - var body *ast.BlockStmt - var functype *ast.FuncType - switch n := fn.syntax.(type) { - case nil: - if fn.Params != nil { - return // not a Go source function. (Synthetic, or from object file.) - } +// buildFromSyntax builds fn.Body from fn.syntax, which must be non-nil. +func (b *builder) buildFromSyntax(fn *Function) { + var ( + recvField *ast.FieldList + body *ast.BlockStmt + functype *ast.FuncType + ) + switch syntax := fn.syntax.(type) { case *ast.FuncDecl: - functype = n.Type - recvField = n.Recv - body = n.Body + functype = syntax.Type + recvField = syntax.Recv + body = syntax.Body + if body == nil { + b.buildParamsOnly(fn) // no body (non-Go function) + return + } case *ast.FuncLit: - functype = n.Type - body = n.Body + functype = syntax.Type + body = syntax.Body + case nil: + panic("no syntax") default: - panic(n) + panic(syntax) // unexpected syntax } - if body == nil { - // External function. - if fn.Params == nil { - // This condition ensures we add a non-empty - // params list once only, but we may attempt - // the degenerate empty case repeatedly. - // TODO(adonovan): opt: don't do that. - - // We set Function.Params even though there is no body - // code to reference them. This simplifies clients. - if recv := fn.Signature.Recv(); recv != nil { - fn.addParamObj(recv) - } - params := fn.Signature.Params() - for i, n := 0, params.Len(); i < n; i++ { - fn.addParamObj(params.At(i)) - } - } - return - } - - // Build instantiation wrapper around generic body? - if fn.topLevelOrigin != nil && fn.subst == nil { - buildInstantiationWrapper(fn) - return - } - - if fn.Prog.mode&LogSource != 0 { - defer logStack("build function %s @ %s", fn, fn.Prog.Fset.Position(fn.pos))() - } fn.startBody() fn.createSyntacticParams(recvField, functype) b.stmt(fn, body) @@ -2381,45 +2591,17 @@ func (b *builder) buildFunctionBody(fn *Function) { fn.finishBody() } -// buildCreated does the BUILD phase for each function created by builder that is not yet BUILT. -// Functions are built using buildFunction. -// -// May add types that require runtime type information to builder. -func (b *builder) buildCreated() { - for ; b.finished < b.created.Len(); b.finished++ { - fn := b.created.At(b.finished) - b.buildFunction(fn) - } -} - -// Adds any needed runtime type information for the created functions. +// addRuntimeType records t as a runtime type, +// along with all types derivable from it using reflection. // -// May add newly CREATEd functions that may need to be built or runtime type information. -// -// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu) -func (b *builder) needsRuntimeTypes() { - if b.created.Len() == 0 { - return - } - prog := b.created.At(0).Prog - - var rtypes []types.Type - for ; b.rtypes < b.finished; b.rtypes++ { - fn := b.created.At(b.rtypes) - rtypes = append(rtypes, mayNeedRuntimeTypes(fn)...) - } - - // Calling prog.needMethodsOf(T) on a basic type T is a no-op. - // Filter out the basic types to reduce acquiring prog.methodsMu. - rtypes = nonbasicTypes(rtypes) - - for _, T := range rtypes { - prog.needMethodsOf(T, b.created) - } -} - -func (b *builder) done() bool { - return b.rtypes >= b.created.Len() +// Acquires prog.runtimeTypesMu. +func addRuntimeType(prog *Program, t types.Type) { + prog.runtimeTypesMu.Lock() + defer prog.runtimeTypesMu.Unlock() + forEachReachable(&prog.MethodSets, t, func(t types.Type) bool { + prev, _ := prog.runtimeTypes.Set(t, true).(bool) + return !prev // already seen? + }) } // Build calls Package.Build for each package in prog. @@ -2447,9 +2629,11 @@ func (prog *Program) Build() { // Build builds SSA code for all functions and vars in package p. // -// Precondition: CreatePackage must have been called for all of p's -// direct imports (and hence its direct imports must have been -// error-free). +// CreatePackage must have been called for all of p's direct imports +// (and hence its direct imports must have been error-free). It is not +// necessary to call CreatePackage for indirect dependencies. +// Functions will be created for all necessary methods in those +// packages on demand. // // Build is idempotent and thread-safe. func (p *Package) Build() { p.buildOnce.Do(p.build) } @@ -2458,45 +2642,39 @@ func (p *Package) build() { if p.info == nil { return // synthetic package, e.g. "testmain" } - - // Ensure we have runtime type info for all exported members. - // Additionally filter for just concrete types that can be runtime types. - // - // TODO(adonovan): ideally belongs in memberFromObject, but - // that would require package creation in topological order. - for name, mem := range p.Members { - isGround := func(m Member) bool { - switch m := m.(type) { - case *Type: - named, _ := m.Type().(*types.Named) - return named == nil || typeparams.ForNamed(named) == nil - case *Function: - return m.typeparams.Len() == 0 - } - return true // *NamedConst, *Global - } - if ast.IsExported(name) && isGround(mem) { - p.Prog.needMethodsOf(mem.Type(), &p.created) - } - } if p.Prog.mode&LogSource != 0 { defer logStack("build %s", p)() } b := builder{created: &p.created} - init := p.init - init.startBody() + b.iterate() + + // We no longer need transient information: ASTs or go/types deductions. + p.info = nil + p.created = nil + p.files = nil + p.initVersion = nil + + if p.Prog.mode&SanityCheckFunctions != 0 { + sanityCheckPackage(p) + } +} + +// buildPackageInit builds fn.Body for the synthetic package initializer. +func (b *builder) buildPackageInit(fn *Function) { + p := fn.Pkg + fn.startBody() var done *BasicBlock if p.Prog.mode&BareInits == 0 { // Make init() skip if package is already initialized. initguard := p.Var("init$guard") - doinit := init.newBasicBlock("init.start") - done = init.newBasicBlock("init.done") - emitIf(init, emitLoad(init, initguard), done, doinit) - init.currentBlock = doinit - emitStore(init, initguard, vTrue, token.NoPos) + doinit := fn.newBasicBlock("init.start") + done = fn.newBasicBlock("init.done") + emitIf(fn, emitLoad(fn, initguard), done, doinit) + fn.currentBlock = doinit + emitStore(fn, initguard, vTrue, token.NoPos) // Call the init() function of each package we import. for _, pkg := range p.Pkg.Imports() { @@ -2506,9 +2684,9 @@ func (p *Package) build() { } var v Call v.Call.Value = prereq.init - v.Call.pos = init.pos + v.Call.pos = fn.pos v.setType(types.NewTuple()) - init.emit(&v) + fn.emit(&v) } } @@ -2516,11 +2694,18 @@ func (p *Package) build() { if len(p.info.InitOrder) > 0 && len(p.files) == 0 { panic("no source files provided for package. cannot initialize globals") } + for _, varinit := range p.info.InitOrder { - if init.Prog.mode&LogSource != 0 { + if fn.Prog.mode&LogSource != 0 { fmt.Fprintf(os.Stderr, "build global initializer %v @ %s\n", varinit.Lhs, p.Prog.Fset.Position(varinit.Rhs.Pos())) } + // Initializers for global vars are evaluated in dependency + // order, but may come from arbitrary files of the package + // with different versions, so we transiently update + // fn.goversion for each one. (Since init is a synthetic + // function it has no syntax of its own that needs a version.) + fn.goversion = p.initVersion[varinit.Rhs] if len(varinit.Lhs) == 1 { // 1:1 initialization: var x, y = a(), b() var lval lvalue @@ -2529,28 +2714,33 @@ func (p *Package) build() { } else { lval = blank{} } - b.assign(init, lval, varinit.Rhs, true, nil) + b.assign(fn, lval, varinit.Rhs, true, nil) } else { // n:1 initialization: var x, y := f() - tuple := b.exprN(init, varinit.Rhs) + tuple := b.exprN(fn, varinit.Rhs) for i, v := range varinit.Lhs { if v.Name() == "_" { continue } - emitStore(init, p.objects[v].(*Global), emitExtract(init, tuple, i), v.Pos()) + emitStore(fn, p.objects[v].(*Global), emitExtract(fn, tuple, i), v.Pos()) } } } + // The rest of the init function is synthetic: + // no syntax, info, goversion. + fn.info = nil + fn.goversion = "" + // Call all of the declared init() functions in source order. for _, file := range p.files { for _, decl := range file.Decls { if decl, ok := decl.(*ast.FuncDecl); ok { id := decl.Name if !isBlankIdent(id) && id.Name == "init" && decl.Recv == nil { - fn := p.objects[p.info.Defs[id]].(*Function) + declaredInit := p.objects[p.info.Defs[id]].(*Function) var v Call - v.Call.Value = fn + v.Call.Value = declaredInit v.setType(types.NewTuple()) p.init.emit(&v) } @@ -2560,35 +2750,9 @@ func (p *Package) build() { // Finish up init(). if p.Prog.mode&BareInits == 0 { - emitJump(init, done) - init.currentBlock = done - } - init.emit(new(Return)) - init.finishBody() - init.done() - - // Build all CREATEd functions and add runtime types. - // These Functions include package-level functions, init functions, methods, and synthetic (including unreachable/blank ones). - // Builds any functions CREATEd while building this package. - // - // Initially the created functions for the package are: - // [init, decl0, ... , declN] - // Where decl0, ..., declN are declared functions in source order, but it's not significant. - // - // As these are built, more functions (function literals, wrappers, etc.) can be CREATEd. - // Iterate until we reach a fixed point. - // - // Wait for init() to be BUILT as that cannot be built by buildFunction(). - // - for !b.done() { - b.buildCreated() // build any CREATEd and not BUILT function. May add runtime types. - b.needsRuntimeTypes() // Add all of the runtime type information. May CREATE Functions. - } - - p.info = nil // We no longer need ASTs or go/types deductions. - p.created = nil // We no longer need created functions. - - if p.Prog.mode&SanityCheckFunctions != 0 { - sanityCheckPackage(p) + emitJump(fn, done) + fn.currentBlock = done } + fn.emit(new(Return)) + fn.finishBody() } diff --git a/vendor/golang.org/x/tools/go/ssa/const.go b/vendor/golang.org/x/tools/go/ssa/const.go index 4a51a2cb4..2a6ac5882 100644 --- a/vendor/golang.org/x/tools/go/ssa/const.go +++ b/vendor/golang.org/x/tools/go/ssa/const.go @@ -125,7 +125,7 @@ func zeroString(t types.Type, from *types.Package) string { components[i] = zeroString(t.At(i).Type(), from) } return "(" + strings.Join(components, ", ") + ")" - case *typeparams.TypeParam: + case *types.TypeParam: return "*new(" + relType(t, from) + ")" } panic(fmt.Sprint("zeroString: unexpected ", t)) diff --git a/vendor/golang.org/x/tools/go/ssa/coretype.go b/vendor/golang.org/x/tools/go/ssa/coretype.go index 128d61e42..88136b438 100644 --- a/vendor/golang.org/x/tools/go/ssa/coretype.go +++ b/vendor/golang.org/x/tools/go/ssa/coretype.go @@ -40,19 +40,19 @@ func isBytestring(T types.Type) bool { } // termList is a list of types. -type termList []*typeparams.Term // type terms of the type set +type termList []*types.Term // type terms of the type set func (s termList) Len() int { return len(s) } func (s termList) At(i int) types.Type { return s[i].Type() } // typeSetOf returns the type set of typ. Returns an empty typeset on an error. func typeSetOf(typ types.Type) termList { // This is a adaptation of x/exp/typeparams.NormalTerms which x/tools cannot depend on. - var terms []*typeparams.Term + var terms []*types.Term var err error switch typ := typ.(type) { - case *typeparams.TypeParam: + case *types.TypeParam: terms, err = typeparams.StructuralTerms(typ) - case *typeparams.Union: + case *types.Union: terms, err = typeparams.UnionTermSet(typ) case *types.Interface: terms, err = typeparams.InterfaceTermSet(typ) @@ -60,7 +60,7 @@ func typeSetOf(typ types.Type) termList { // Common case. // Specializing the len=1 case to avoid a slice // had no measurable space/time benefit. - terms = []*typeparams.Term{typeparams.NewTerm(false, typ)} + terms = []*types.Term{types.NewTerm(false, typ)} } if err != nil { diff --git a/vendor/golang.org/x/tools/go/ssa/create.go b/vendor/golang.org/x/tools/go/ssa/create.go index 1bf88c83e..c4da35d0b 100644 --- a/vendor/golang.org/x/tools/go/ssa/create.go +++ b/vendor/golang.org/x/tools/go/ssa/create.go @@ -15,41 +15,43 @@ import ( "os" "sync" - "golang.org/x/tools/go/types/typeutil" - "golang.org/x/tools/internal/typeparams" + "golang.org/x/tools/internal/versions" ) // NewProgram returns a new SSA Program. // // mode controls diagnostics and checking during SSA construction. +// +// To construct an SSA program: +// +// - Call NewProgram to create an empty Program. +// - Call CreatePackage providing typed syntax for each package +// you want to build, and call it with types but not +// syntax for each of those package's direct dependencies. +// - Call [Package.Build] on each syntax package you wish to build, +// or [Program.Build] to build all of them. +// +// See the Example tests for simple examples. func NewProgram(fset *token.FileSet, mode BuilderMode) *Program { - prog := &Program{ + return &Program{ Fset: fset, imported: make(map[string]*Package), packages: make(map[*types.Package]*Package), - thunks: make(map[selectionKey]*Function), - bounds: make(map[boundsKey]*Function), mode: mode, canon: newCanonizer(), - ctxt: typeparams.NewContext(), - instances: make(map[*Function]*instanceSet), + ctxt: types.NewContext(), parameterized: tpWalker{seen: make(map[types.Type]bool)}, } - - h := typeutil.MakeHasher() // protected by methodsMu, in effect - prog.methodSets.SetHasher(h) - prog.runtimeTypes.SetHasher(h) - - return prog } // memberFromObject populates package pkg with a member for the // typechecker object obj. // // For objects from Go source code, syntax is the associated syntax -// tree (for funcs and vars only); it will be used during the build +// tree (for funcs and vars only) and goversion defines the +// appropriate interpretation; they will be used during the build // phase. -func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { +func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node, goversion string) { name := obj.Name() switch obj := obj.(type) { case *types.Builtin: @@ -58,9 +60,11 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { } case *types.TypeName: - pkg.Members[name] = &Type{ - object: obj, - pkg: pkg, + if name != "_" { + pkg.Members[name] = &Type{ + object: obj, + pkg: pkg, + } } case *types.Const: @@ -70,7 +74,9 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { pkg: pkg, } pkg.objects[obj] = c - pkg.Members[name] = c + if name != "_" { + pkg.Members[name] = c + } case *types.Var: g := &Global{ @@ -81,7 +87,9 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { pos: obj.Pos(), } pkg.objects[obj] = g - pkg.Members[name] = g + if name != "_" { + pkg.Members[name] = g + } case *types.Func: sig := obj.Type().(*types.Signature) @@ -89,36 +97,10 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { pkg.ninit++ name = fmt.Sprintf("init#%d", pkg.ninit) } - - // Collect type parameters if this is a generic function/method. - var tparams *typeparams.TypeParamList - if rtparams := typeparams.RecvTypeParams(sig); rtparams.Len() > 0 { - tparams = rtparams - } else if sigparams := typeparams.ForSignature(sig); sigparams.Len() > 0 { - tparams = sigparams - } - - fn := &Function{ - name: name, - object: obj, - Signature: sig, - syntax: syntax, - pos: obj.Pos(), - Pkg: pkg, - Prog: pkg.Prog, - typeparams: tparams, - info: pkg.info, - } - pkg.created.Add(fn) - if syntax == nil { - fn.Synthetic = "loaded from gc object file" - } - if tparams.Len() > 0 { - fn.Prog.createInstanceSet(fn) - } - + fn := createFunction(pkg.Prog, obj, name, syntax, pkg.info, goversion, &pkg.created) + fn.Pkg = pkg pkg.objects[obj] = fn - if sig.Recv() == nil { + if name != "_" && sig.Recv() == nil { pkg.Members[name] = fn // package-level function } @@ -127,45 +109,79 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { } } +// createFunction creates a function or method. It supports both +// CreatePackage (with or without syntax) and the on-demand creation +// of methods in non-created packages based on their types.Func. +func createFunction(prog *Program, obj *types.Func, name string, syntax ast.Node, info *types.Info, goversion string, cr *creator) *Function { + sig := obj.Type().(*types.Signature) + + // Collect type parameters. + var tparams *types.TypeParamList + if rtparams := sig.RecvTypeParams(); rtparams.Len() > 0 { + tparams = rtparams // method of generic type + } else if sigparams := sig.TypeParams(); sigparams.Len() > 0 { + tparams = sigparams // generic function + } + + /* declared function/method (from syntax or export data) */ + fn := &Function{ + name: name, + object: obj, + Signature: sig, + build: (*builder).buildFromSyntax, + syntax: syntax, + info: info, + goversion: goversion, + pos: obj.Pos(), + Pkg: nil, // may be set by caller + Prog: prog, + typeparams: tparams, + } + if fn.syntax == nil { + fn.Synthetic = "from type information" + fn.build = (*builder).buildParamsOnly + } + if tparams.Len() > 0 { + fn.generic = new(generic) + } + cr.Add(fn) + return fn +} + // membersFromDecl populates package pkg with members for each // typechecker object (var, func, const or type) associated with the // specified decl. -func membersFromDecl(pkg *Package, decl ast.Decl) { +func membersFromDecl(pkg *Package, decl ast.Decl, goversion string) { switch decl := decl.(type) { case *ast.GenDecl: // import, const, type or var switch decl.Tok { case token.CONST: for _, spec := range decl.Specs { for _, id := range spec.(*ast.ValueSpec).Names { - if !isBlankIdent(id) { - memberFromObject(pkg, pkg.info.Defs[id], nil) - } + memberFromObject(pkg, pkg.info.Defs[id], nil, "") } } case token.VAR: for _, spec := range decl.Specs { + for _, rhs := range spec.(*ast.ValueSpec).Values { + pkg.initVersion[rhs] = goversion + } for _, id := range spec.(*ast.ValueSpec).Names { - if !isBlankIdent(id) { - memberFromObject(pkg, pkg.info.Defs[id], spec) - } + memberFromObject(pkg, pkg.info.Defs[id], spec, goversion) } } case token.TYPE: for _, spec := range decl.Specs { id := spec.(*ast.TypeSpec).Name - if !isBlankIdent(id) { - memberFromObject(pkg, pkg.info.Defs[id], nil) - } + memberFromObject(pkg, pkg.info.Defs[id], nil, "") } } case *ast.FuncDecl: id := decl.Name - if !isBlankIdent(id) { - memberFromObject(pkg, pkg.info.Defs[id], decl) - } + memberFromObject(pkg, pkg.info.Defs[id], decl, goversion) } } @@ -182,7 +198,7 @@ func (c *creator) Add(fn *Function) { func (c *creator) At(i int) *Function { return (*c)[i] } func (c *creator) Len() int { return len(*c) } -// CreatePackage constructs and returns an SSA Package from the +// CreatePackage creates and returns an SSA Package from the // specified type-checked, error-free file ASTs, and populates its // Members mapping. // @@ -190,36 +206,48 @@ func (c *creator) Len() int { return len(*c) } // subsequent call to ImportedPackage(pkg.Path()). // // The real work of building SSA form for each function is not done -// until a subsequent call to Package.Build(). +// until a subsequent call to Package.Build. +// +// CreatePackage should not be called after building any package in +// the program. func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info *types.Info, importable bool) *Package { + // TODO(adonovan): assert that no package has yet been built. + if pkg == nil { + panic("nil pkg") // otherwise pkg.Scope below returns types.Universe! + } p := &Package{ Prog: prog, Members: make(map[string]Member), objects: make(map[types.Object]Member), Pkg: pkg, - info: info, // transient (CREATE and BUILD phases) - files: files, // transient (CREATE and BUILD phases) + syntax: info != nil, + // transient values (cleared after Package.Build) + info: info, + files: files, + initVersion: make(map[ast.Expr]string), } - // Add init() function. + /* synthesized package initializer */ p.init = &Function{ name: "init", Signature: new(types.Signature), Synthetic: "package initializer", Pkg: p, Prog: prog, + build: (*builder).buildPackageInit, info: p.info, + goversion: "", // See Package.build for details. } p.Members[p.init.name] = p.init p.created.Add(p.init) - // CREATE phase. // Allocate all package members: vars, funcs, consts and types. if len(files) > 0 { // Go source package. for _, file := range files { + goversion := versions.Lang(versions.FileVersions(p.info, file)) for _, decl := range file.Decls { - membersFromDecl(p, decl) + membersFromDecl(p, decl, goversion) } } } else { @@ -229,11 +257,11 @@ func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info * scope := p.Pkg.Scope() for _, name := range scope.Names() { obj := scope.Lookup(name) - memberFromObject(p, obj, nil) + memberFromObject(p, obj, nil, "") if obj, ok := obj.(*types.TypeName); ok { if named, ok := obj.Type().(*types.Named); ok { for i, n := 0, named.NumMethods(); i < n; i++ { - memberFromObject(p, named.Method(i), nil) + memberFromObject(p, named.Method(i), nil, "") } } } @@ -271,8 +299,8 @@ func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info * // printMu serializes printing of Packages/Functions to stdout. var printMu sync.Mutex -// AllPackages returns a new slice containing all packages in the -// program prog in unspecified order. +// AllPackages returns a new slice containing all packages created by +// prog.CreatePackage in in unspecified order. func (prog *Program) AllPackages() []*Package { pkgs := make([]*Package, 0, len(prog.packages)) for _, pkg := range prog.packages { diff --git a/vendor/golang.org/x/tools/go/ssa/doc.go b/vendor/golang.org/x/tools/go/ssa/doc.go index a687de45e..3310b5509 100644 --- a/vendor/golang.org/x/tools/go/ssa/doc.go +++ b/vendor/golang.org/x/tools/go/ssa/doc.go @@ -7,8 +7,6 @@ // static single-assignment (SSA) form intermediate representation // (IR) for the bodies of functions. // -// THIS INTERFACE IS EXPERIMENTAL AND IS LIKELY TO CHANGE. -// // For an introduction to SSA form, see // http://en.wikipedia.org/wiki/Static_single_assignment_form. // This page provides a broader reading list: @@ -21,15 +19,15 @@ // All looping, branching and switching constructs are replaced with // unstructured control flow. Higher-level control flow constructs // such as multi-way branch can be reconstructed as needed; see -// ssautil.Switches() for an example. +// [golang.org/x/tools/go/ssa/ssautil.Switches] for an example. // // The simplest way to create the SSA representation of a package is -// to load typed syntax trees using golang.org/x/tools/go/packages, then -// invoke the ssautil.Packages helper function. See Example_loadPackages -// and Example_loadWholeProgram for examples. -// The resulting ssa.Program contains all the packages and their +// to load typed syntax trees using [golang.org/x/tools/go/packages], then +// invoke the [golang.org/x/tools/go/ssa/ssautil.Packages] helper function. +// (See the package-level Examples named LoadPackages and LoadWholeProgram.) +// The resulting [ssa.Program] contains all the packages and their // members, but SSA code is not created for function bodies until a -// subsequent call to (*Package).Build or (*Program).Build. +// subsequent call to [Package.Build] or [Program.Build]. // // The builder initially builds a naive SSA form in which all local // variables are addresses of stack locations with explicit loads and @@ -41,13 +39,13 @@ // // The primary interfaces of this package are: // -// - Member: a named member of a Go package. -// - Value: an expression that yields a value. -// - Instruction: a statement that consumes values and performs computation. -// - Node: a Value or Instruction (emphasizing its membership in the SSA value graph) +// - [Member]: a named member of a Go package. +// - [Value]: an expression that yields a value. +// - [Instruction]: a statement that consumes values and performs computation. +// - [Node]: a [Value] or [Instruction] (emphasizing its membership in the SSA value graph) // -// A computation that yields a result implements both the Value and -// Instruction interfaces. The following table shows for each +// A computation that yields a result implements both the [Value] and +// [Instruction] interfaces. The following table shows for each // concrete type which of these interfaces it implements. // // Value? Instruction? Member? @@ -97,15 +95,15 @@ // *TypeAssert ✔ ✔ // *UnOp ✔ ✔ // -// Other key types in this package include: Program, Package, Function -// and BasicBlock. +// Other key types in this package include: [Program], [Package], [Function] +// and [BasicBlock]. // // The program representation constructed by this package is fully // resolved internally, i.e. it does not rely on the names of Values, // Packages, Functions, Types or BasicBlocks for the correct // interpretation of the program. Only the identities of objects and // the topology of the SSA and type graphs are semantically -// significant. (There is one exception: Ids, used to identify field +// significant. (There is one exception: [types.Id] values, which identify field // and method names, contain strings.) Avoidance of name-based // operations simplifies the implementation of subsequent passes and // can make them very efficient. Many objects are nonetheless named @@ -113,11 +111,9 @@ // either accurate or unambiguous. The public API exposes a number of // name-based maps for client convenience. // -// The ssa/ssautil package provides various utilities that depend only -// on the public API of this package. -// -// TODO(adonovan): Consider the exceptional control-flow implications -// of defer and recover(). +// The [golang.org/x/tools/go/ssa/ssautil] package provides various +// helper functions, for example to simplify loading a Go program into +// SSA form. // // TODO(adonovan): write a how-to document for all the various cases // of trying to determine corresponding elements across the four diff --git a/vendor/golang.org/x/tools/go/ssa/emit.go b/vendor/golang.org/x/tools/go/ssa/emit.go index abb617e6d..d77b4407a 100644 --- a/vendor/golang.org/x/tools/go/ssa/emit.go +++ b/vendor/golang.org/x/tools/go/ssa/emit.go @@ -13,16 +13,53 @@ import ( "go/types" ) -// emitNew emits to f a new (heap Alloc) instruction allocating an -// object of type typ. pos is the optional source location. -func emitNew(f *Function, typ types.Type, pos token.Pos) *Alloc { - v := &Alloc{Heap: true} +// emitAlloc emits to f a new Alloc instruction allocating a variable +// of type typ. +// +// The caller must set Alloc.Heap=true (for an heap-allocated variable) +// or add the Alloc to f.Locals (for a frame-allocated variable). +// +// During building, a variable in f.Locals may have its Heap flag +// set when it is discovered that its address is taken. +// These Allocs are removed from f.Locals at the end. +// +// The builder should generally call one of the emit{New,Local,LocalVar} wrappers instead. +func emitAlloc(f *Function, typ types.Type, pos token.Pos, comment string) *Alloc { + v := &Alloc{Comment: comment} v.setType(types.NewPointer(typ)) v.setPos(pos) f.emit(v) return v } +// emitNew emits to f a new Alloc instruction heap-allocating a +// variable of type typ. pos is the optional source location. +func emitNew(f *Function, typ types.Type, pos token.Pos, comment string) *Alloc { + alloc := emitAlloc(f, typ, pos, comment) + alloc.Heap = true + return alloc +} + +// emitLocal creates a local var for (t, pos, comment) and +// emits an Alloc instruction for it. +// +// (Use this function or emitNew for synthetic variables; +// for source-level variables, use emitLocalVar.) +func emitLocal(f *Function, t types.Type, pos token.Pos, comment string) *Alloc { + local := emitAlloc(f, t, pos, comment) + f.Locals = append(f.Locals, local) + return local +} + +// emitLocalVar creates a local var for v and emits an Alloc instruction for it. +// Subsequent calls to f.lookup(v) return it. +// It applies the appropriate generic instantiation to the type. +func emitLocalVar(f *Function, v *types.Var) *Alloc { + alloc := emitLocal(f, f.typ(v.Type()), v.Pos(), v.Name()) + f.vars[v] = alloc + return alloc +} + // emitLoad emits to f an instruction to load the address addr into a // new temporary, and returns the value so defined. func emitLoad(f *Function, addr Value) *UnOp { @@ -148,7 +185,7 @@ func emitCompare(f *Function, op token.Token, x, y Value, pos token.Pos) Value { // Precondition: neither argument is a named type. func isValuePreserving(ut_src, ut_dst types.Type) bool { // Identical underlying types? - if structTypesIdentical(ut_dst, ut_src) { + if types.IdenticalIgnoreTags(ut_dst, ut_src) { return true } @@ -206,6 +243,13 @@ func emitConv(f *Function, val Value, typ types.Type) Value { val = emitConv(f, val, types.Default(ut_src)) } + // Record the types of operands to MakeInterface, if + // non-parameterized, as they are the set of runtime types. + t := val.Type() + if f.typeparams.Len() == 0 || !f.Prog.parameterized.isParameterized(t) { + addRuntimeType(f.Prog, t) + } + mi := &MakeInterface{X: val} mi.setType(typ) return f.emit(mi) @@ -537,48 +581,6 @@ func emitFieldSelection(f *Function, v Value, index int, wantAddr bool, id *ast. return v } -// emitSliceToArray emits to f code to convert a slice value to an array value. -// -// Precondition: all types in type set of typ are arrays and convertible to all -// types in the type set of val.Type(). -func emitSliceToArray(f *Function, val Value, typ types.Type) Value { - // Emit the following: - // if val == nil && len(typ) == 0 { - // ptr = &[0]T{} - // } else { - // ptr = SliceToArrayPointer(val) - // } - // v = *ptr - - ptype := types.NewPointer(typ) - p := &SliceToArrayPointer{X: val} - p.setType(ptype) - ptr := f.emit(p) - - nilb := f.newBasicBlock("slicetoarray.nil") - nonnilb := f.newBasicBlock("slicetoarray.nonnil") - done := f.newBasicBlock("slicetoarray.done") - - cond := emitCompare(f, token.EQL, ptr, zeroConst(ptype), token.NoPos) - emitIf(f, cond, nilb, nonnilb) - f.currentBlock = nilb - - zero := f.addLocal(typ, token.NoPos) - emitJump(f, done) - f.currentBlock = nonnilb - - emitJump(f, done) - f.currentBlock = done - - phi := &Phi{Edges: []Value{zero, ptr}, Comment: "slicetoarray"} - phi.pos = val.Pos() - phi.setType(typ) - x := f.emit(phi) - unOp := &UnOp{Op: token.MUL, X: x} - unOp.setType(typ) - return f.emit(unOp) -} - // createRecoverBlock emits to f a block of code to return after a // recovered panic, and sets f.Recover to it. // diff --git a/vendor/golang.org/x/tools/go/ssa/func.go b/vendor/golang.org/x/tools/go/ssa/func.go index 38c3e31ba..22f878d4e 100644 --- a/vendor/golang.org/x/tools/go/ssa/func.go +++ b/vendor/golang.org/x/tools/go/ssa/func.go @@ -10,13 +10,10 @@ import ( "bytes" "fmt" "go/ast" - "go/token" "go/types" "io" "os" "strings" - - "golang.org/x/tools/internal/typeparams" ) // Like ObjectOf, but panics instead of returning nil. @@ -46,7 +43,7 @@ func (f *Function) typ(T types.Type) types.Type { // If id is an Instance, returns info.Instances[id].Type. // Otherwise returns f.typeOf(id). func (f *Function) instanceType(id *ast.Ident) types.Type { - if t, ok := typeparams.GetInstances(f.info)[id]; ok { + if t, ok := f.info.Instances[id]; ok { return t.Type } return f.typeOf(id) @@ -108,52 +105,40 @@ type lblock struct { // labelledBlock returns the branch target associated with the // specified label, creating it if needed. func (f *Function) labelledBlock(label *ast.Ident) *lblock { - obj := f.objectOf(label) + obj := f.objectOf(label).(*types.Label) lb := f.lblocks[obj] if lb == nil { lb = &lblock{_goto: f.newBasicBlock(label.Name)} if f.lblocks == nil { - f.lblocks = make(map[types.Object]*lblock) + f.lblocks = make(map[*types.Label]*lblock) } f.lblocks[obj] = lb } return lb } -// addParam adds a (non-escaping) parameter to f.Params of the -// specified name, type and source position. -func (f *Function) addParam(name string, typ types.Type, pos token.Pos) *Parameter { - v := &Parameter{ - name: name, - typ: typ, - pos: pos, - parent: f, - } - f.Params = append(f.Params, v) - return v -} - -func (f *Function) addParamObj(obj types.Object) *Parameter { - name := obj.Name() +// addParamVar adds a parameter to f.Params. +func (f *Function) addParamVar(v *types.Var) *Parameter { + name := v.Name() if name == "" { name = fmt.Sprintf("arg%d", len(f.Params)) } - param := f.addParam(name, f.typ(obj.Type()), obj.Pos()) - param.object = obj + param := &Parameter{ + name: name, + object: v, + typ: f.typ(v.Type()), + parent: f, + } + f.Params = append(f.Params, param) return param } // addSpilledParam declares a parameter that is pre-spilled to the // stack; the function body will load/store the spilled location. // Subsequent lifting will eliminate spills where possible. -func (f *Function) addSpilledParam(obj types.Object) { - param := f.addParamObj(obj) - spill := &Alloc{Comment: obj.Name()} - spill.setType(types.NewPointer(param.Type())) - spill.setPos(obj.Pos()) - f.objects[obj] = spill - f.Locals = append(f.Locals, spill) - f.emit(spill) +func (f *Function) addSpilledParam(obj *types.Var) { + param := f.addParamVar(obj) + spill := emitLocalVar(f, obj) f.emit(&Store{Addr: spill, Val: param}) } @@ -161,7 +146,7 @@ func (f *Function) addSpilledParam(obj types.Object) { // Precondition: f.Type() already set. func (f *Function) startBody() { f.currentBlock = f.newBasicBlock("entry") - f.objects = make(map[types.Object]Value) // needed for some synthetics, e.g. init + f.vars = make(map[*types.Var]Value) // needed for some synthetics, e.g. init } // createSyntacticParams populates f.Params and generates code (spills @@ -177,11 +162,11 @@ func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.Func if recv != nil { for _, field := range recv.List { for _, n := range field.Names { - f.addSpilledParam(f.info.Defs[n]) + f.addSpilledParam(identVar(f, n)) } // Anonymous receiver? No need to spill. if field.Names == nil { - f.addParamObj(f.Signature.Recv()) + f.addParamVar(f.Signature.Recv()) } } } @@ -191,11 +176,11 @@ func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.Func n := len(f.Params) // 1 if has recv, 0 otherwise for _, field := range functype.Params.List { for _, n := range field.Names { - f.addSpilledParam(f.info.Defs[n]) + f.addSpilledParam(identVar(f, n)) } // Anonymous parameter? No need to spill. if field.Names == nil { - f.addParamObj(f.Signature.Params().At(len(f.Params) - n)) + f.addParamVar(f.Signature.Params().At(len(f.Params) - n)) } } } @@ -205,7 +190,8 @@ func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.Func for _, field := range functype.Results.List { // Implicit "var" decl of locals for named results. for _, n := range field.Names { - f.namedResults = append(f.namedResults, f.addLocalForIdent(n)) + namedResult := emitLocalVar(f, identVar(f, n)) + f.namedResults = append(f.namedResults, namedResult) } } } @@ -250,49 +236,14 @@ func buildReferrers(f *Function) { } } -// mayNeedRuntimeTypes returns all of the types in the body of fn that might need runtime types. -// -// EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu) -func mayNeedRuntimeTypes(fn *Function) []types.Type { - // Collect all types that may need rtypes, i.e. those that flow into an interface. - var ts []types.Type - for _, bb := range fn.Blocks { - for _, instr := range bb.Instrs { - if mi, ok := instr.(*MakeInterface); ok { - ts = append(ts, mi.X.Type()) - } - } - } - - // Types that contain a parameterized type are considered to not be runtime types. - if fn.typeparams.Len() == 0 { - return ts // No potentially parameterized types. - } - // Filter parameterized types, in place. - fn.Prog.methodsMu.Lock() - defer fn.Prog.methodsMu.Unlock() - filtered := ts[:0] - for _, t := range ts { - if !fn.Prog.parameterized.isParameterized(t) { - filtered = append(filtered, t) - } - } - return filtered -} - // finishBody() finalizes the contents of the function after SSA code generation of its body. // // The function is not done being built until done() is called. func (f *Function) finishBody() { - f.objects = nil + f.vars = nil f.currentBlock = nil f.lblocks = nil - // Don't pin the AST in memory (except in debug mode). - if n := f.syntax; n != nil && !f.debugInfo() { - f.syntax = extentNode{n.Pos(), n.End()} - } - // Remove from f.Locals any Allocs that escape to the heap. j := 0 for _, l := range f.Locals { @@ -320,15 +271,15 @@ func (f *Function) finishBody() { lift(f) } - // clear remaining stateful variables + // clear remaining builder state f.namedResults = nil // (used by lifting) - f.info = nil f.subst = nil numberRegisters(f) // uses f.namedRegisters } -// After this, function is done with BUILD phase. +// done marks the building of f's SSA body complete, +// along with any nested functions, and optionally prints them. func (f *Function) done() { assert(f.parent == nil, "done called on an anonymous function") @@ -338,7 +289,7 @@ func (f *Function) done() { visit(anon) // anon is done building before f. } - f.built = true // function is done with BUILD phase + f.build = nil // function is built if f.Prog.mode&PrintFunctions != 0 { printMu.Lock() @@ -376,7 +327,6 @@ func (f *Function) removeNilBlocks() { // size of the instruction stream, and causes Functions to depend upon // the ASTs, potentially keeping them live in memory for longer. func (pkg *Package) SetDebugMode(debug bool) { - // TODO(adonovan): do we want ast.File granularity? pkg.debug = debug } @@ -387,40 +337,25 @@ func (f *Function) debugInfo() bool { return p != nil && p.debug } -// addNamedLocal creates a local variable, adds it to function f and -// returns it. Its name and type are taken from obj. Subsequent -// calls to f.lookup(obj) will return the same local. -func (f *Function) addNamedLocal(obj types.Object) *Alloc { - l := f.addLocal(obj.Type(), obj.Pos()) - l.Comment = obj.Name() - f.objects[obj] = l - return l -} - -func (f *Function) addLocalForIdent(id *ast.Ident) *Alloc { - return f.addNamedLocal(f.info.Defs[id]) -} - -// addLocal creates an anonymous local variable of type typ, adds it -// to function f and returns it. pos is the optional source location. -func (f *Function) addLocal(typ types.Type, pos token.Pos) *Alloc { - typ = f.typ(typ) - v := &Alloc{} - v.setType(types.NewPointer(typ)) - v.setPos(pos) - f.Locals = append(f.Locals, v) - f.emit(v) - return v -} - // lookup returns the address of the named variable identified by obj // that is local to function f or one of its enclosing functions. // If escaping, the reference comes from a potentially escaping pointer // expression and the referent must be heap-allocated. -func (f *Function) lookup(obj types.Object, escaping bool) Value { - if v, ok := f.objects[obj]; ok { - if alloc, ok := v.(*Alloc); ok && escaping { - alloc.Heap = true +// We assume the referent is a *Alloc or *Phi. +// (The only Phis at this stage are those created directly by go1.22 "for" loops.) +func (f *Function) lookup(obj *types.Var, escaping bool) Value { + if v, ok := f.vars[obj]; ok { + if escaping { + switch v := v.(type) { + case *Alloc: + v.Heap = true + case *Phi: + for _, edge := range v.Edges { + if alloc, ok := edge.(*Alloc); ok { + alloc.Heap = true + } + } + } } return v // function-local var (address) } @@ -438,7 +373,7 @@ func (f *Function) lookup(obj types.Object, escaping bool) Value { outer: outer, parent: f, } - f.objects[obj] = v + f.vars[obj] = v f.FreeVars = append(f.FreeVars, v) return v } @@ -536,7 +471,7 @@ func writeSignature(buf *bytes.Buffer, from *types.Package, name string, sig *ty func (fn *Function) declaredPackage() *Package { switch { case fn.Pkg != nil: - return fn.Pkg // non-generic function + return fn.Pkg // non-generic function (does that follow??) case fn.topLevelOrigin != nil: return fn.topLevelOrigin.Pkg // instance of a named generic function case fn.parent != nil: @@ -689,17 +624,11 @@ func (prog *Program) NewFunction(name string, sig *types.Signature, provenance s return &Function{Prog: prog, name: name, Signature: sig, Synthetic: provenance} } -type extentNode [2]token.Pos - -func (n extentNode) Pos() token.Pos { return n[0] } -func (n extentNode) End() token.Pos { return n[1] } - -// Syntax returns an ast.Node whose Pos/End methods provide the -// lexical extent of the function if it was defined by Go source code -// (f.Synthetic==""), or nil otherwise. -// -// If f was built with debug information (see Package.SetDebugRef), -// the result is the *ast.FuncDecl or *ast.FuncLit that declared the -// function. Otherwise, it is an opaque Node providing only position -// information; this avoids pinning the AST in memory. +// Syntax returns the function's syntax (*ast.Func{Decl,Lit) +// if it was produced from syntax. func (f *Function) Syntax() ast.Node { return f.syntax } + +// identVar returns the variable defined by id. +func identVar(fn *Function, id *ast.Ident) *types.Var { + return fn.info.Defs[id].(*types.Var) +} diff --git a/vendor/golang.org/x/tools/go/ssa/identical.go b/vendor/golang.org/x/tools/go/ssa/identical.go deleted file mode 100644 index e8026967b..000000000 --- a/vendor/golang.org/x/tools/go/ssa/identical.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.8 -// +build go1.8 - -package ssa - -import "go/types" - -var structTypesIdentical = types.IdenticalIgnoreTags diff --git a/vendor/golang.org/x/tools/go/ssa/identical_17.go b/vendor/golang.org/x/tools/go/ssa/identical_17.go deleted file mode 100644 index 575aa5dfc..000000000 --- a/vendor/golang.org/x/tools/go/ssa/identical_17.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.8 -// +build !go1.8 - -package ssa - -import "go/types" - -var structTypesIdentical = types.Identical diff --git a/vendor/golang.org/x/tools/go/ssa/instantiate.go b/vendor/golang.org/x/tools/go/ssa/instantiate.go index 38249dea2..c155f6736 100644 --- a/vendor/golang.org/x/tools/go/ssa/instantiate.go +++ b/vendor/golang.org/x/tools/go/ssa/instantiate.go @@ -6,130 +6,60 @@ package ssa import ( "fmt" - "go/ast" "go/types" + "sync" "golang.org/x/tools/internal/typeparams" ) -// _Instances returns all of the instances generated by runtime types for this function in an unspecified order. -// -// Thread-safe. -// -// This is an experimental interface! It may change without warning. -func (prog *Program) _Instances(fn *Function) []*Function { - if fn.typeparams.Len() == 0 || len(fn.typeargs) > 0 { - return nil - } - - prog.methodsMu.Lock() - defer prog.methodsMu.Unlock() - return prog.instances[fn].list() -} - -// A set of instantiations of a generic function fn. -type instanceSet struct { - fn *Function // fn.typeparams.Len() > 0 and len(fn.typeargs) == 0. - instances map[*typeList]*Function // canonical type arguments to an instance. - syntax *ast.FuncDecl // fn.syntax copy for instantiating after fn is done. nil on synthetic packages. - info *types.Info // fn.pkg.info copy for building after fn is done.. nil on synthetic packages. - - // TODO(taking): Consider ways to allow for clearing syntax and info when done building. - // May require a public API change as MethodValue can request these be built after prog.Build() is done. -} - -func (insts *instanceSet) list() []*Function { - if insts == nil { - return nil - } - - fns := make([]*Function, 0, len(insts.instances)) - for _, fn := range insts.instances { - fns = append(fns, fn) - } - return fns +// A generic records information about a generic origin function, +// including a cache of existing instantiations. +type generic struct { + instancesMu sync.Mutex + instances map[*typeList]*Function // canonical type arguments to an instance. } -// createInstanceSet adds a new instanceSet for a generic function fn if one does not exist. +// instance returns a Function that is the instantiation of generic +// origin function fn with the type arguments targs. // -// Precondition: fn is a package level declaration (function or method). +// Any created instance is added to cr. // -// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodMu) -func (prog *Program) createInstanceSet(fn *Function) { - assert(fn.typeparams.Len() > 0 && len(fn.typeargs) == 0, "Can only create instance sets for generic functions") - - prog.methodsMu.Lock() - defer prog.methodsMu.Unlock() - - syntax, _ := fn.syntax.(*ast.FuncDecl) - assert((syntax == nil) == (fn.syntax == nil), "fn.syntax is either nil or a *ast.FuncDecl") - - if _, ok := prog.instances[fn]; !ok { - prog.instances[fn] = &instanceSet{ - fn: fn, - syntax: syntax, - info: fn.info, +// Acquires fn.generic.instancesMu. +func (fn *Function) instance(targs []types.Type, cr *creator) *Function { + key := fn.Prog.canon.List(targs) + + gen := fn.generic + + gen.instancesMu.Lock() + defer gen.instancesMu.Unlock() + inst, ok := gen.instances[key] + if !ok { + inst = createInstance(fn, targs, cr) + if gen.instances == nil { + gen.instances = make(map[*typeList]*Function) } + gen.instances[key] = inst } + return inst } -// needsInstance returns a Function that is the instantiation of fn with the type arguments targs. -// -// Any CREATEd instance is added to cr. -// -// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodMu) -func (prog *Program) needsInstance(fn *Function, targs []types.Type, cr *creator) *Function { - prog.methodsMu.Lock() - defer prog.methodsMu.Unlock() - - return prog.lookupOrCreateInstance(fn, targs, cr) -} - -// lookupOrCreateInstance returns a Function that is the instantiation of fn with the type arguments targs. -// -// Any CREATEd instance is added to cr. -// -// EXCLUSIVE_LOCKS_REQUIRED(prog.methodMu) -func (prog *Program) lookupOrCreateInstance(fn *Function, targs []types.Type, cr *creator) *Function { - return prog.instances[fn].lookupOrCreate(targs, &prog.parameterized, cr) -} - -// lookupOrCreate returns the instantiation of insts.fn using targs. +// createInstance returns the instantiation of generic function fn using targs. // If the instantiation is created, this is added to cr. -func (insts *instanceSet) lookupOrCreate(targs []types.Type, parameterized *tpWalker, cr *creator) *Function { - if insts.instances == nil { - insts.instances = make(map[*typeList]*Function) - } - - fn := insts.fn +// +// Requires fn.generic.instancesMu. +func createInstance(fn *Function, targs []types.Type, cr *creator) *Function { prog := fn.Prog - // canonicalize on a tuple of targs. Sig is not unique. - // - // func A[T any]() { - // var x T - // fmt.Println("%T", x) - // } - key := prog.canon.List(targs) - if inst, ok := insts.instances[key]; ok { - return inst - } - - // CREATE instance/instantiation wrapper - var syntax ast.Node - if insts.syntax != nil { - syntax = insts.syntax - } - + // Compute signature. var sig *types.Signature var obj *types.Func if recv := fn.Signature.Recv(); recv != nil { // method - m := fn.object.(*types.Func) - obj = prog.canon.instantiateMethod(m, targs, prog.ctxt) + obj = prog.canon.instantiateMethod(fn.object, targs, prog.ctxt) sig = obj.Type().(*types.Signature) } else { - instSig, err := typeparams.Instantiate(prog.ctxt, fn.Signature, targs, false) + // function + instSig, err := types.Instantiate(prog.ctxt, fn.Signature, targs, false) if err != nil { panic(err) } @@ -137,41 +67,48 @@ func (insts *instanceSet) lookupOrCreate(targs []types.Type, parameterized *tpWa if !ok { panic("Instantiate of a Signature returned a non-signature") } - obj = fn.object.(*types.Func) // instantiation does not exist yet + obj = fn.object // instantiation does not exist yet sig = prog.canon.Type(instance).(*types.Signature) } - var synthetic string - var subst *subster - - concrete := !parameterized.anyParameterized(targs) - - if prog.mode&InstantiateGenerics != 0 && concrete { + // Choose strategy (instance or wrapper). + var ( + synthetic string + subst *subster + build buildFunc + ) + if prog.mode&InstantiateGenerics != 0 && !prog.parameterized.anyParameterized(targs) { synthetic = fmt.Sprintf("instance of %s", fn.Name()) - scope := typeparams.OriginMethod(obj).Scope() - subst = makeSubster(prog.ctxt, scope, fn.typeparams, targs, false) + if fn.syntax != nil { + scope := typeparams.OriginMethod(obj).Scope() + subst = makeSubster(prog.ctxt, scope, fn.typeparams, targs, false) + build = (*builder).buildFromSyntax + } else { + build = (*builder).buildParamsOnly + } } else { synthetic = fmt.Sprintf("instantiation wrapper of %s", fn.Name()) + build = (*builder).buildInstantiationWrapper } - name := fmt.Sprintf("%s%s", fn.Name(), targs) // may not be unique + /* generic instance or instantiation wrapper */ instance := &Function{ - name: name, + name: fmt.Sprintf("%s%s", fn.Name(), targs), // may not be unique object: obj, Signature: sig, Synthetic: synthetic, - syntax: syntax, + syntax: fn.syntax, // \ + info: fn.info, // } empty for non-created packages + goversion: fn.goversion, // / + build: build, topLevelOrigin: fn, pos: obj.Pos(), Pkg: nil, Prog: fn.Prog, typeparams: fn.typeparams, // share with origin typeargs: targs, - info: insts.info, // on synthetic packages info is nil. subst: subst, } - cr.Add(instance) - insts.instances[key] = instance return instance } diff --git a/vendor/golang.org/x/tools/go/ssa/lift.go b/vendor/golang.org/x/tools/go/ssa/lift.go index dbd8790c6..da49fe9f1 100644 --- a/vendor/golang.org/x/tools/go/ssa/lift.go +++ b/vendor/golang.org/x/tools/go/ssa/lift.go @@ -103,9 +103,14 @@ func buildDomFrontier(fn *Function) domFrontier { } func removeInstr(refs []Instruction, instr Instruction) []Instruction { + return removeInstrsIf(refs, func(i Instruction) bool { return i == instr }) +} + +func removeInstrsIf(refs []Instruction, p func(Instruction) bool) []Instruction { + // TODO(taking): replace with go1.22 slices.DeleteFunc. i := 0 for _, ref := range refs { - if ref == instr { + if p(ref) { continue } refs[i] = ref diff --git a/vendor/golang.org/x/tools/go/ssa/methods.go b/vendor/golang.org/x/tools/go/ssa/methods.go index 294498371..4797b3928 100644 --- a/vendor/golang.org/x/tools/go/ssa/methods.go +++ b/vendor/golang.org/x/tools/go/ssa/methods.go @@ -10,54 +10,124 @@ import ( "fmt" "go/types" + "golang.org/x/tools/go/types/typeutil" "golang.org/x/tools/internal/typeparams" ) // MethodValue returns the Function implementing method sel, building -// wrapper methods on demand. It returns nil if sel denotes an -// abstract (interface or parameterized) method. +// wrapper methods on demand. It returns nil if sel denotes an +// interface or generic method. // // Precondition: sel.Kind() == MethodVal. // // Thread-safe. // -// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu) +// Acquires prog.methodsMu. func (prog *Program) MethodValue(sel *types.Selection) *Function { if sel.Kind() != types.MethodVal { panic(fmt.Sprintf("MethodValue(%s) kind != MethodVal", sel)) } T := sel.Recv() if types.IsInterface(T) { - return nil // abstract method (interface, possibly type param) + return nil // interface method or type parameter } + + if prog.parameterized.isParameterized(T) { + return nil // generic method + } + if prog.mode&LogSource != 0 { defer logStack("MethodValue %s %v", T, sel)() } - var m *Function - b := builder{created: &creator{}} + var cr creator - prog.methodsMu.Lock() - // Checks whether a type param is reachable from T. - // This is an expensive check. May need to be optimized later. - if !prog.parameterized.isParameterized(T) { - m = prog.addMethod(prog.createMethodSet(T), sel, b.created) + m := func() *Function { + prog.methodsMu.Lock() + defer prog.methodsMu.Unlock() + + // Get or create SSA method set. + mset, ok := prog.methodSets.At(T).(*methodSet) + if !ok { + mset = &methodSet{mapping: make(map[string]*Function)} + prog.methodSets.Set(T, mset) + } + + // Get or create SSA method. + id := sel.Obj().Id() + fn, ok := mset.mapping[id] + if !ok { + obj := sel.Obj().(*types.Func) + _, ptrObj := deptr(recvType(obj)) + _, ptrRecv := deptr(T) + needsPromotion := len(sel.Index()) > 1 + needsIndirection := !ptrObj && ptrRecv + if needsPromotion || needsIndirection { + fn = createWrapper(prog, toSelection(sel), &cr) + } else { + fn = prog.objectMethod(obj, &cr) + } + if fn.Signature.Recv() == nil { + panic(fn) + } + mset.mapping[id] = fn + } + + return fn + }() + + b := builder{created: &cr} + b.iterate() + + return m +} + +// objectMethod returns the Function for a given method symbol. +// The symbol may be an instance of a generic function. It need not +// belong to an existing SSA package created by a call to +// prog.CreatePackage. +// +// objectMethod panics if the function is not a method. +// +// Acquires prog.objectMethodsMu. +func (prog *Program) objectMethod(obj *types.Func, cr *creator) *Function { + sig := obj.Type().(*types.Signature) + if sig.Recv() == nil { + panic("not a method: " + obj.String()) } - prog.methodsMu.Unlock() - if m == nil { - return nil // abstract method (generic) + // Belongs to a created package? + if fn := prog.FuncValue(obj); fn != nil { + return fn } - for !b.done() { - b.buildCreated() - b.needsRuntimeTypes() + + // Instantiation of generic? + if originObj := typeparams.OriginMethod(obj); originObj != obj { + origin := prog.objectMethod(originObj, cr) + assert(origin.typeparams.Len() > 0, "origin is not generic") + targs := receiverTypeArgs(obj) + return origin.instance(targs, cr) } - return m + + // Consult/update cache of methods created from types.Func. + prog.objectMethodsMu.Lock() + defer prog.objectMethodsMu.Unlock() + fn, ok := prog.objectMethods[obj] + if !ok { + fn = createFunction(prog, obj, obj.Name(), nil, nil, "", cr) + fn.Synthetic = "from type information (on demand)" + + if prog.objectMethods == nil { + prog.objectMethods = make(map[*types.Func]*Function) + } + prog.objectMethods[obj] = fn + } + return fn } // LookupMethod returns the implementation of the method of type T // identified by (pkg, name). It returns nil if the method exists but -// is abstract, and panics if T has no such method. +// is an interface method or generic method, and panics if T has no such method. func (prog *Program) LookupMethod(T types.Type, pkg *types.Package, name string) *Function { sel := prog.MethodSets.MethodSet(T).Lookup(pkg, name) if sel == nil { @@ -68,208 +138,136 @@ func (prog *Program) LookupMethod(T types.Type, pkg *types.Package, name string) // methodSet contains the (concrete) methods of a concrete type (non-interface, non-parameterized). type methodSet struct { - mapping map[string]*Function // populated lazily - complete bool // mapping contains all methods -} - -// Precondition: T is a concrete type, e.g. !isInterface(T) and not parameterized. -// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu) -func (prog *Program) createMethodSet(T types.Type) *methodSet { - if prog.mode&SanityCheckFunctions != 0 { - if types.IsInterface(T) || prog.parameterized.isParameterized(T) { - panic("type is interface or parameterized") - } - } - mset, ok := prog.methodSets.At(T).(*methodSet) - if !ok { - mset = &methodSet{mapping: make(map[string]*Function)} - prog.methodSets.Set(T, mset) - } - return mset -} - -// Adds any created functions to cr. -// Precondition: T is a concrete type, e.g. !isInterface(T) and not parameterized. -// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu) -func (prog *Program) addMethod(mset *methodSet, sel *types.Selection, cr *creator) *Function { - if sel.Kind() == types.MethodExpr { - panic(sel) - } - id := sel.Obj().Id() - fn := mset.mapping[id] - if fn == nil { - sel := toSelection(sel) - obj := sel.obj.(*types.Func) - - _, ptrObj := deptr(recvType(obj)) - _, ptrRecv := deptr(sel.recv) - - needsPromotion := len(sel.index) > 1 - needsIndirection := !ptrObj && ptrRecv - if needsPromotion || needsIndirection { - fn = makeWrapper(prog, sel, cr) - } else { - fn = prog.originFunc(obj) - if fn.typeparams.Len() > 0 { // instantiate - targs := receiverTypeArgs(obj) - fn = prog.lookupOrCreateInstance(fn, targs, cr) - } - } - if fn.Signature.Recv() == nil { - panic(fn) // missing receiver - } - mset.mapping[id] = fn - } - return fn + mapping map[string]*Function // populated lazily } -// RuntimeTypes returns a new unordered slice containing all -// concrete types in the program for which a complete (non-empty) -// method set is required at run-time. +// RuntimeTypes returns a new unordered slice containing all types in +// the program for which a runtime type is required. +// +// A runtime type is required for any non-parameterized, non-interface +// type that is converted to an interface, or for any type (including +// interface types) derivable from one through reflection. +// +// The methods of such types may be reachable through reflection or +// interface calls even if they are never called directly. // // Thread-safe. // -// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu) +// Acquires prog.runtimeTypesMu. func (prog *Program) RuntimeTypes() []types.Type { - prog.methodsMu.Lock() - defer prog.methodsMu.Unlock() - - var res []types.Type - prog.methodSets.Iterate(func(T types.Type, v interface{}) { - if v.(*methodSet).complete { - res = append(res, T) - } - }) - return res -} - -// declaredFunc returns the concrete function/method denoted by obj. -// Panic ensues if there is none. -func (prog *Program) declaredFunc(obj *types.Func) *Function { - if v := prog.packageLevelMember(obj); v != nil { - return v.(*Function) - } - panic("no concrete method: " + obj.String()) + prog.runtimeTypesMu.Lock() + defer prog.runtimeTypesMu.Unlock() + return prog.runtimeTypes.Keys() } -// needMethodsOf ensures that runtime type information (including the -// complete method set) is available for the specified type T and all -// its subcomponents. -// -// needMethodsOf must be called for at least every type that is an -// operand of some MakeInterface instruction, and for the type of -// every exported package member. -// -// Adds any created functions to cr. -// -// Precondition: T is not a method signature (*Signature with Recv()!=nil). -// Precondition: T is not parameterized. -// -// Thread-safe. (Called via Package.build from multiple builder goroutines.) +// forEachReachable calls f for type T and each type reachable from +// its type through reflection. // -// TODO(adonovan): make this faster. It accounts for 20% of SSA build time. +// The function f must use memoization to break cycles and +// return false when the type has already been visited. // -// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu) -func (prog *Program) needMethodsOf(T types.Type, cr *creator) { - prog.methodsMu.Lock() - prog.needMethods(T, false, cr) - prog.methodsMu.Unlock() -} - -// Precondition: T is not a method signature (*Signature with Recv()!=nil). -// Precondition: T is not parameterized. -// Recursive case: skip => don't create methods for T. -// -// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu) -func (prog *Program) needMethods(T types.Type, skip bool, cr *creator) { - // Each package maintains its own set of types it has visited. - if prevSkip, ok := prog.runtimeTypes.At(T).(bool); ok { - // needMethods(T) was previously called - if !prevSkip || skip { - return // already seen, with same or false 'skip' value - } - } - prog.runtimeTypes.Set(T, skip) - - tmset := prog.MethodSets.MethodSet(T) - - if !skip && !types.IsInterface(T) && tmset.Len() > 0 { - // Create methods of T. - mset := prog.createMethodSet(T) - if !mset.complete { - mset.complete = true - n := tmset.Len() - for i := 0; i < n; i++ { - prog.addMethod(mset, tmset.At(i), cr) +// TODO(adonovan): publish in typeutil and share with go/callgraph/rta. +func forEachReachable(msets *typeutil.MethodSetCache, T types.Type, f func(types.Type) bool) { + var visit func(T types.Type, skip bool) + visit = func(T types.Type, skip bool) { + if !skip { + if !f(T) { + return } } - } - - // Recursion over signatures of each method. - for i := 0; i < tmset.Len(); i++ { - sig := tmset.At(i).Type().(*types.Signature) - prog.needMethods(sig.Params(), false, cr) - prog.needMethods(sig.Results(), false, cr) - } - switch t := T.(type) { - case *types.Basic: - // nop + // Recursion over signatures of each method. + tmset := msets.MethodSet(T) + for i := 0; i < tmset.Len(); i++ { + sig := tmset.At(i).Type().(*types.Signature) + // It is tempting to call visit(sig, false) + // but, as noted in golang.org/cl/65450043, + // the Signature.Recv field is ignored by + // types.Identical and typeutil.Map, which + // is confusing at best. + // + // More importantly, the true signature rtype + // reachable from a method using reflection + // has no receiver but an extra ordinary parameter. + // For the Read method of io.Reader we want: + // func(Reader, []byte) (int, error) + // but here sig is: + // func([]byte) (int, error) + // with .Recv = Reader (though it is hard to + // notice because it doesn't affect Signature.String + // or types.Identical). + // + // TODO(adonovan): construct and visit the correct + // non-method signature with an extra parameter + // (though since unnamed func types have no methods + // there is essentially no actual demand for this). + // + // TODO(adonovan): document whether or not it is + // safe to skip non-exported methods (as RTA does). + visit(sig.Params(), true) // skip the Tuple + visit(sig.Results(), true) // skip the Tuple + } - case *types.Interface: - // nop---handled by recursion over method set. + switch T := T.(type) { + case *types.Basic: + // nop - case *types.Pointer: - prog.needMethods(t.Elem(), false, cr) + case *types.Interface: + // nop---handled by recursion over method set. - case *types.Slice: - prog.needMethods(t.Elem(), false, cr) + case *types.Pointer: + visit(T.Elem(), false) - case *types.Chan: - prog.needMethods(t.Elem(), false, cr) + case *types.Slice: + visit(T.Elem(), false) - case *types.Map: - prog.needMethods(t.Key(), false, cr) - prog.needMethods(t.Elem(), false, cr) + case *types.Chan: + visit(T.Elem(), false) - case *types.Signature: - if t.Recv() != nil { - panic(fmt.Sprintf("Signature %s has Recv %s", t, t.Recv())) - } - prog.needMethods(t.Params(), false, cr) - prog.needMethods(t.Results(), false, cr) - - case *types.Named: - // A pointer-to-named type can be derived from a named - // type via reflection. It may have methods too. - prog.needMethods(types.NewPointer(T), false, cr) - - // Consider 'type T struct{S}' where S has methods. - // Reflection provides no way to get from T to struct{S}, - // only to S, so the method set of struct{S} is unwanted, - // so set 'skip' flag during recursion. - prog.needMethods(t.Underlying(), true, cr) - - case *types.Array: - prog.needMethods(t.Elem(), false, cr) - - case *types.Struct: - for i, n := 0, t.NumFields(); i < n; i++ { - prog.needMethods(t.Field(i).Type(), false, cr) - } + case *types.Map: + visit(T.Key(), false) + visit(T.Elem(), false) - case *types.Tuple: - for i, n := 0, t.Len(); i < n; i++ { - prog.needMethods(t.At(i).Type(), false, cr) - } + case *types.Signature: + if T.Recv() != nil { + panic(fmt.Sprintf("Signature %s has Recv %s", T, T.Recv())) + } + visit(T.Params(), true) // skip the Tuple + visit(T.Results(), true) // skip the Tuple + + case *types.Named: + // A pointer-to-named type can be derived from a named + // type via reflection. It may have methods too. + visit(types.NewPointer(T), false) + + // Consider 'type T struct{S}' where S has methods. + // Reflection provides no way to get from T to struct{S}, + // only to S, so the method set of struct{S} is unwanted, + // so set 'skip' flag during recursion. + visit(T.Underlying(), true) // skip the unnamed type + + case *types.Array: + visit(T.Elem(), false) + + case *types.Struct: + for i, n := 0, T.NumFields(); i < n; i++ { + // TODO(adonovan): document whether or not + // it is safe to skip non-exported fields. + visit(T.Field(i).Type(), false) + } - case *typeparams.TypeParam: - panic(T) // type parameters are always abstract. + case *types.Tuple: + for i, n := 0, T.Len(); i < n; i++ { + visit(T.At(i).Type(), false) + } - case *typeparams.Union: - // nop + case *types.TypeParam, *types.Union: + // forEachReachable must not be called on parameterized types. + panic(T) - default: - panic(T) + default: + panic(T) + } } + visit(T, false) } diff --git a/vendor/golang.org/x/tools/go/ssa/parameterized.go b/vendor/golang.org/x/tools/go/ssa/parameterized.go index b90ee0e86..84db49d39 100644 --- a/vendor/golang.org/x/tools/go/ssa/parameterized.go +++ b/vendor/golang.org/x/tools/go/ssa/parameterized.go @@ -6,6 +6,7 @@ package ssa import ( "go/types" + "sync" "golang.org/x/tools/internal/typeparams" ) @@ -14,11 +15,24 @@ import ( // // NOTE: Adapted from go/types/infer.go. If that is exported in a future release remove this copy. type tpWalker struct { + mu sync.Mutex seen map[types.Type]bool } -// isParameterized returns true when typ reaches any type parameter. -func (w *tpWalker) isParameterized(typ types.Type) (res bool) { +// isParameterized reports whether t recursively contains a type parameter. +// Thread-safe. +func (w *tpWalker) isParameterized(t types.Type) bool { + // TODO(adonovan): profile. If this operation is expensive, + // handle the most common but shallow cases such as T, pkg.T, + // *T without consulting the cache under the lock. + + w.mu.Lock() + defer w.mu.Unlock() + return w.isParameterizedLocked(t) +} + +// Requires w.mu. +func (w *tpWalker) isParameterizedLocked(typ types.Type) (res bool) { // NOTE: Adapted from go/types/infer.go. Try to keep in sync. // detect cycles @@ -35,25 +49,25 @@ func (w *tpWalker) isParameterized(typ types.Type) (res bool) { break case *types.Array: - return w.isParameterized(t.Elem()) + return w.isParameterizedLocked(t.Elem()) case *types.Slice: - return w.isParameterized(t.Elem()) + return w.isParameterizedLocked(t.Elem()) case *types.Struct: for i, n := 0, t.NumFields(); i < n; i++ { - if w.isParameterized(t.Field(i).Type()) { + if w.isParameterizedLocked(t.Field(i).Type()) { return true } } case *types.Pointer: - return w.isParameterized(t.Elem()) + return w.isParameterizedLocked(t.Elem()) case *types.Tuple: n := t.Len() for i := 0; i < n; i++ { - if w.isParameterized(t.At(i).Type()) { + if w.isParameterizedLocked(t.At(i).Type()) { return true } } @@ -66,11 +80,11 @@ func (w *tpWalker) isParameterized(typ types.Type) (res bool) { // Similarly, the receiver of a method may declare (rather than // use) type parameters, we don't care about those either. // Thus, we only need to look at the input and result parameters. - return w.isParameterized(t.Params()) || w.isParameterized(t.Results()) + return w.isParameterizedLocked(t.Params()) || w.isParameterizedLocked(t.Results()) case *types.Interface: for i, n := 0, t.NumMethods(); i < n; i++ { - if w.isParameterized(t.Method(i).Type()) { + if w.isParameterizedLocked(t.Method(i).Type()) { return true } } @@ -79,31 +93,31 @@ func (w *tpWalker) isParameterized(typ types.Type) (res bool) { panic(err) } for _, term := range terms { - if w.isParameterized(term.Type()) { + if w.isParameterizedLocked(term.Type()) { return true } } case *types.Map: - return w.isParameterized(t.Key()) || w.isParameterized(t.Elem()) + return w.isParameterizedLocked(t.Key()) || w.isParameterizedLocked(t.Elem()) case *types.Chan: - return w.isParameterized(t.Elem()) + return w.isParameterizedLocked(t.Elem()) case *types.Named: - args := typeparams.NamedTypeArgs(t) + args := t.TypeArgs() // TODO(taking): this does not match go/types/infer.go. Check with rfindley. - if params := typeparams.ForNamed(t); params.Len() > args.Len() { + if params := t.TypeParams(); params.Len() > args.Len() { return true } for i, n := 0, args.Len(); i < n; i++ { - if w.isParameterized(args.At(i)) { + if w.isParameterizedLocked(args.At(i)) { return true } } - return w.isParameterized(t.Underlying()) // recurse for types local to parameterized functions + return w.isParameterizedLocked(t.Underlying()) // recurse for types local to parameterized functions - case *typeparams.TypeParam: + case *types.TypeParam: return true default: @@ -113,9 +127,13 @@ func (w *tpWalker) isParameterized(typ types.Type) (res bool) { return false } +// anyParameterized reports whether any element of ts is parameterized. +// Thread-safe. func (w *tpWalker) anyParameterized(ts []types.Type) bool { + w.mu.Lock() + defer w.mu.Unlock() for _, t := range ts { - if w.isParameterized(t) { + if w.isParameterizedLocked(t) { return true } } diff --git a/vendor/golang.org/x/tools/go/ssa/print.go b/vendor/golang.org/x/tools/go/ssa/print.go index 7f34a7b58..727a73502 100644 --- a/vendor/golang.org/x/tools/go/ssa/print.go +++ b/vendor/golang.org/x/tools/go/ssa/print.go @@ -17,7 +17,6 @@ import ( "strings" "golang.org/x/tools/go/types/typeutil" - "golang.org/x/tools/internal/typeparams" ) // relName returns the name of v relative to i. @@ -51,7 +50,7 @@ func relType(t types.Type, from *types.Package) string { return s } -func relTerm(term *typeparams.Term, from *types.Package) string { +func relTerm(term *types.Term, from *types.Package) string { s := relType(term.Type(), from) if term.Tilde() { return "~" + s diff --git a/vendor/golang.org/x/tools/go/ssa/sanity.go b/vendor/golang.org/x/tools/go/ssa/sanity.go index 886be0532..22a3c6bc3 100644 --- a/vendor/golang.org/x/tools/go/ssa/sanity.go +++ b/vendor/golang.org/x/tools/go/ssa/sanity.go @@ -132,6 +132,11 @@ func (s *sanity) checkInstr(idx int, instr Instruction) { case *BinOp: case *Call: + if common := instr.Call; common.IsInvoke() { + if !types.IsInterface(common.Value.Type()) { + s.errorf("invoke on %s (%s) which is not an interface type (or type param)", common.Value, common.Value.Type()) + } + } case *ChangeInterface: case *ChangeType: case *SliceToArrayPointer: @@ -422,7 +427,8 @@ func (s *sanity) checkFunction(fn *Function) bool { // shared across packages, or duplicated as weak symbols in a // separate-compilation model), and error.Error. if fn.Pkg == nil { - if strings.HasPrefix(fn.Synthetic, "wrapper ") || + if strings.HasPrefix(fn.Synthetic, "from type information (on demand)") || + strings.HasPrefix(fn.Synthetic, "wrapper ") || strings.HasPrefix(fn.Synthetic, "bound ") || strings.HasPrefix(fn.Synthetic, "thunk ") || strings.HasSuffix(fn.name, "Error") || diff --git a/vendor/golang.org/x/tools/go/ssa/source.go b/vendor/golang.org/x/tools/go/ssa/source.go index 9c900e3aa..6700305bd 100644 --- a/vendor/golang.org/x/tools/go/ssa/source.go +++ b/vendor/golang.org/x/tools/go/ssa/source.go @@ -172,16 +172,19 @@ func (f *Function) ValueForExpr(e ast.Expr) (value Value, isAddr bool) { // --- Lookup functions for source-level named entities (types.Objects) --- // Package returns the SSA Package corresponding to the specified -// type-checker package object. -// It returns nil if no such SSA package has been created. -func (prog *Program) Package(obj *types.Package) *Package { - return prog.packages[obj] +// type-checker package. It returns nil if no such Package was +// created by a prior call to prog.CreatePackage. +func (prog *Program) Package(pkg *types.Package) *Package { + return prog.packages[pkg] } -// packageLevelMember returns the package-level member corresponding to -// the specified named object, which may be a package-level const -// (*NamedConst), var (*Global) or func (*Function) of some package in -// prog. It returns nil if the object is not found. +// packageLevelMember returns the package-level member corresponding +// to the specified symbol, which may be a package-level const +// (*NamedConst), var (*Global) or func/method (*Function) of some +// package in prog. +// +// It returns nil if the object belongs to a package that has not been +// created by prog.CreatePackage. func (prog *Program) packageLevelMember(obj types.Object) Member { if pkg, ok := prog.packages[obj.Pkg()]; ok { return pkg.objects[obj] @@ -189,24 +192,16 @@ func (prog *Program) packageLevelMember(obj types.Object) Member { return nil } -// originFunc returns the package-level generic function that is the -// origin of obj. If returns nil if the generic function is not found. -func (prog *Program) originFunc(obj *types.Func) *Function { - return prog.declaredFunc(typeparams.OriginMethod(obj)) -} - -// FuncValue returns the concrete Function denoted by the source-level -// named function obj, or nil if obj denotes an interface method. -// -// TODO(adonovan): check the invariant that obj.Type() matches the -// result's Signature, both in the params/results and in the receiver. +// FuncValue returns the SSA function or (non-interface) method +// denoted by the specified func symbol. It returns nil id the symbol +// denotes an interface method, or belongs to a package that was not +// created by prog.CreatePackage. func (prog *Program) FuncValue(obj *types.Func) *Function { fn, _ := prog.packageLevelMember(obj).(*Function) return fn } -// ConstValue returns the SSA Value denoted by the source-level named -// constant obj. +// ConstValue returns the SSA constant denoted by the specified const symbol. func (prog *Program) ConstValue(obj *types.Const) *Const { // TODO(adonovan): opt: share (don't reallocate) // Consts for const objects and constant ast.Exprs. @@ -223,7 +218,7 @@ func (prog *Program) ConstValue(obj *types.Const) *Const { } // VarValue returns the SSA Value that corresponds to a specific -// identifier denoting the source-level named variable obj. +// identifier denoting the specified var symbol. // // VarValue returns nil if a local variable was not found, perhaps // because its package was not built, the debug information was not diff --git a/vendor/golang.org/x/tools/go/ssa/ssa.go b/vendor/golang.org/x/tools/go/ssa/ssa.go index bd42f2e0a..30bf4bc67 100644 --- a/vendor/golang.org/x/tools/go/ssa/ssa.go +++ b/vendor/golang.org/x/tools/go/ssa/ssa.go @@ -23,20 +23,25 @@ import ( type Program struct { Fset *token.FileSet // position information for the files of this Program imported map[string]*Package // all importable Packages, keyed by import path - packages map[*types.Package]*Package // all loaded Packages, keyed by object + packages map[*types.Package]*Package // all created Packages mode BuilderMode // set of mode bits for SSA construction MethodSets typeutil.MethodSetCache // cache of type-checker's method-sets - canon *canonizer // type canonicalization map - ctxt *typeparams.Context // cache for type checking instantiations + canon *canonizer // type canonicalization map + ctxt *types.Context // cache for type checking instantiations - methodsMu sync.Mutex // guards the following maps: - methodSets typeutil.Map // maps type to its concrete methodSet - runtimeTypes typeutil.Map // types for which rtypes are needed - bounds map[boundsKey]*Function // bounds for curried x.Method closures - thunks map[selectionKey]*Function // thunks for T.Method expressions - instances map[*Function]*instanceSet // instances of generic functions - parameterized tpWalker // determines whether a type reaches a type parameter. + methodsMu sync.Mutex + methodSets typeutil.Map // maps type to its concrete *methodSet + + parameterized tpWalker // memoization of whether a type refers to type parameters + + runtimeTypesMu sync.Mutex + runtimeTypes typeutil.Map // set of runtime types (from MakeInterface) + + // objectMethods is a memoization of objectMethod + // to avoid creation of duplicate methods from type information. + objectMethodsMu sync.Mutex + objectMethods map[*types.Func]*Function } // A Package is a single analyzed Go package containing Members for @@ -51,17 +56,19 @@ type Package struct { Prog *Program // the owning program Pkg *types.Package // the corresponding go/types.Package Members map[string]Member // all package members keyed by name (incl. init and init#%d) - objects map[types.Object]Member // mapping of package objects to members (incl. methods). Contains *NamedConst, *Global, *Function. + objects map[types.Object]Member // mapping of package objects to members (incl. methods). Contains *NamedConst, *Global, *Function (values but not types) init *Function // Func("init"); the package's init function debug bool // include full debug info in this package + syntax bool // package was loaded from syntax // The following fields are set transiently, then cleared // after building. - buildOnce sync.Once // ensures package building occurs once - ninit int32 // number of init functions - info *types.Info // package type information - files []*ast.File // package ASTs - created creator // members created as a result of building this package (includes declared functions, wrappers) + buildOnce sync.Once // ensures package building occurs once + ninit int32 // number of init functions + info *types.Info // package type information + files []*ast.File // package ASTs + created creator // members created as a result of building this package (includes declared functions, wrappers) + initVersion map[ast.Expr]string // goversion to use for each global var init expr } // A Member is a member of a Go package, implemented by *NamedConst, @@ -296,8 +303,8 @@ type Node interface { // // A generic function is a function or method that has uninstantiated type // parameters (TypeParams() != nil). Consider a hypothetical generic -// method, (*Map[K,V]).Get. It may be instantiated with all ground -// (non-parameterized) types as (*Map[string,int]).Get or with +// method, (*Map[K,V]).Get. It may be instantiated with all +// non-parameterized types as (*Map[string,int]).Get or with // parameterized types as (*Map[string,U]).Get, where U is a type parameter. // In both instantiations, Origin() refers to the instantiated generic // method, (*Map[K,V]).Get, TypeParams() refers to the parameters [K,V] of @@ -305,39 +312,45 @@ type Node interface { // respectively, and is nil in the generic method. type Function struct { name string - object types.Object // a declared *types.Func or one of its wrappers - method *selection // info about provenance of synthetic methods; thunk => non-nil + object *types.Func // symbol for declared function (nil for FuncLit or synthetic init) + method *selection // info about provenance of synthetic methods; thunk => non-nil Signature *types.Signature pos token.Pos - Synthetic string // provenance of synthetic function; "" for true source functions - syntax ast.Node // *ast.Func{Decl,Lit}; replaced with simple ast.Node after build, unless debug mode - parent *Function // enclosing function if anon; nil if global - Pkg *Package // enclosing package; nil for shared funcs (wrappers and error.Error) - Prog *Program // enclosing program + // source information + Synthetic string // provenance of synthetic function; "" for true source functions + syntax ast.Node // *ast.Func{Decl,Lit}, if from syntax (incl. generic instances) + info *types.Info // type annotations (iff syntax != nil) + goversion string // Go version of syntax (NB: init is special) + + build buildFunc // algorithm to build function body (nil => built) + parent *Function // enclosing function if anon; nil if global + Pkg *Package // enclosing package; nil for shared funcs (wrappers and error.Error) + Prog *Program // enclosing program + + // These fields are populated only when the function body is built: + Params []*Parameter // function parameters; for methods, includes receiver FreeVars []*FreeVar // free variables whose values must be supplied by closure - Locals []*Alloc // local variables of this function + Locals []*Alloc // frame-allocated variables of this function Blocks []*BasicBlock // basic blocks of the function; nil => external Recover *BasicBlock // optional; control transfers here after recovered panic AnonFuncs []*Function // anonymous functions directly beneath this one referrers []Instruction // referring instructions (iff Parent() != nil) - built bool // function has completed both CREATE and BUILD phase. anonIdx int32 // position of a nested function in parent's AnonFuncs. fn.Parent()!=nil => fn.Parent().AnonFunc[fn.anonIdx] == fn. - typeparams *typeparams.TypeParamList // type parameters of this function. typeparams.Len() > 0 => generic or instance of generic function - typeargs []types.Type // type arguments that instantiated typeparams. len(typeargs) > 0 => instance of generic function - topLevelOrigin *Function // the origin function if this is an instance of a source function. nil if Parent()!=nil. + typeparams *types.TypeParamList // type parameters of this function. typeparams.Len() > 0 => generic or instance of generic function + typeargs []types.Type // type arguments that instantiated typeparams. len(typeargs) > 0 => instance of generic function + topLevelOrigin *Function // the origin function if this is an instance of a source function. nil if Parent()!=nil. + generic *generic // instances of this function, if generic - // The following fields are set transiently during building, - // then cleared. + // The following fields are cleared after building. currentBlock *BasicBlock // where to emit code - objects map[types.Object]Value // addresses of local variables + vars map[*types.Var]Value // addresses of local variables namedResults []*Alloc // tuple of named results targets *targets // linked stack of branch targets - lblocks map[types.Object]*lblock // labelled blocks - info *types.Info // *types.Info to build from. nil for wrappers. - subst *subster // non-nil => expand generic body using this type substitution of ground types + lblocks map[*types.Label]*lblock // labelled blocks + subst *subster // type parameter substitutions (if non-nil) } // BasicBlock represents an SSA basic block. @@ -402,9 +415,8 @@ type FreeVar struct { // A Parameter represents an input parameter of a function. type Parameter struct { name string - object types.Object // a *types.Var; nil for non-source locals + object *types.Var // non-nil typ types.Type - pos token.Pos parent *Function referrers []Instruction } @@ -482,15 +494,12 @@ type Builtin struct { // type of the allocated variable is actually // Type().Underlying().(*types.Pointer).Elem(). // -// If Heap is false, Alloc allocates space in the function's -// activation record (frame); we refer to an Alloc(Heap=false) as a -// "local" alloc. Each local Alloc returns the same address each time -// it is executed within the same activation; the space is -// re-initialized to zero. +// If Heap is false, Alloc zero-initializes the same local variable in +// the call frame and returns its address; in this case the Alloc must +// be present in Function.Locals. We call this a "local" alloc. // -// If Heap is true, Alloc allocates space in the heap; we -// refer to an Alloc(Heap=true) as a "new" alloc. Each new Alloc -// returns a different address each time it is executed. +// If Heap is true, Alloc allocates a new zero-initialized variable +// each time the instruction is executed. We call this a "new" alloc. // // When Alloc is applied to a channel, map or slice type, it returns // the address of an uninitialized (nil) reference of that kind; store @@ -681,8 +690,8 @@ type Convert struct { type MultiConvert struct { register X Value - from []*typeparams.Term - to []*typeparams.Term + from []*types.Term + to []*types.Term } // ChangeInterface constructs a value of one interface type from a @@ -1068,11 +1077,12 @@ type Next struct { // Type() reflects the actual type of the result, possibly a // 2-types.Tuple; AssertedType is the asserted type. // -// Pos() returns the ast.CallExpr.Lparen if the instruction arose from -// an explicit T(e) conversion; the ast.TypeAssertExpr.Lparen if the -// instruction arose from an explicit e.(T) operation; or the -// ast.CaseClause.Case if the instruction arose from a case of a -// type-switch statement. +// Depending on the TypeAssert's purpose, Pos may return: +// - the ast.CallExpr.Lparen of an explicit T(e) conversion; +// - the ast.TypeAssertExpr.Lparen of an explicit e.(T) operation; +// - the ast.CaseClause.Case of a case of a type-switch statement; +// - the Ident(m).NamePos of an interface method value i.m +// (for which TypeAssert may be used to effect the nil check). // // Example printed form: // @@ -1390,7 +1400,7 @@ type anInstruction struct { // represents a dynamically dispatched call to an interface method. // In this mode, Value is the interface value and Method is the // interface's abstract method. The interface value may be a type -// parameter. Note: an abstract method may be shared by multiple +// parameter. Note: an interface method may be shared by multiple // interfaces due to embedding; Value.Type() provides the specific // interface used for this call. // @@ -1408,7 +1418,7 @@ type anInstruction struct { // the last element of Args is a slice. type CallCommon struct { Value Value // receiver (invoke mode) or func value (call mode) - Method *types.Func // abstract method (invoke mode) + Method *types.Func // interface method (invoke mode) Args []Value // actual parameters (in static method call, includes receiver) pos token.Pos // position of CallExpr.Lparen, iff explicit in source } @@ -1507,14 +1517,19 @@ func (v *Global) String() string { return v.RelString(nil) func (v *Global) Package() *Package { return v.Pkg } func (v *Global) RelString(from *types.Package) string { return relString(v, from) } -func (v *Function) Name() string { return v.name } -func (v *Function) Type() types.Type { return v.Signature } -func (v *Function) Pos() token.Pos { return v.pos } -func (v *Function) Token() token.Token { return token.FUNC } -func (v *Function) Object() types.Object { return v.object } -func (v *Function) String() string { return v.RelString(nil) } -func (v *Function) Package() *Package { return v.Pkg } -func (v *Function) Parent() *Function { return v.parent } +func (v *Function) Name() string { return v.name } +func (v *Function) Type() types.Type { return v.Signature } +func (v *Function) Pos() token.Pos { return v.pos } +func (v *Function) Token() token.Token { return token.FUNC } +func (v *Function) Object() types.Object { + if v.object != nil { + return types.Object(v.object) + } + return nil +} +func (v *Function) String() string { return v.RelString(nil) } +func (v *Function) Package() *Package { return v.Pkg } +func (v *Function) Parent() *Function { return v.parent } func (v *Function) Referrers() *[]Instruction { if v.parent != nil { return &v.referrers @@ -1524,10 +1539,7 @@ func (v *Function) Referrers() *[]Instruction { // TypeParams are the function's type parameters if generic or the // type parameters that were instantiated if fn is an instantiation. -// -// TODO(taking): declare result type as *types.TypeParamList -// after we drop support for go1.17. -func (fn *Function) TypeParams() *typeparams.TypeParamList { +func (fn *Function) TypeParams() *types.TypeParamList { return fn.typeparams } @@ -1562,7 +1574,7 @@ func (v *Parameter) Type() types.Type { return v.typ } func (v *Parameter) Name() string { return v.name } func (v *Parameter) Object() types.Object { return v.object } func (v *Parameter) Referrers() *[]Instruction { return &v.referrers } -func (v *Parameter) Pos() token.Pos { return v.pos } +func (v *Parameter) Pos() token.Pos { return v.object.Pos() } func (v *Parameter) Parent() *Function { return v.parent } func (v *Alloc) Type() types.Type { return v.typ } diff --git a/vendor/golang.org/x/tools/go/ssa/ssautil/load.go b/vendor/golang.org/x/tools/go/ssa/ssautil/load.go index 96d69a20a..3daa67a07 100644 --- a/vendor/golang.org/x/tools/go/ssa/ssautil/load.go +++ b/vendor/golang.org/x/tools/go/ssa/ssautil/load.go @@ -14,14 +14,14 @@ import ( "golang.org/x/tools/go/loader" "golang.org/x/tools/go/packages" "golang.org/x/tools/go/ssa" - "golang.org/x/tools/internal/typeparams" + "golang.org/x/tools/internal/versions" ) // Packages creates an SSA program for a set of packages. // // The packages must have been loaded from source syntax using the -// golang.org/x/tools/go/packages.Load function in LoadSyntax or -// LoadAllSyntax mode. +// [packages.Load] function in [packages.LoadSyntax] or +// [packages.LoadAllSyntax] mode. // // Packages creates an SSA package for each well-typed package in the // initial list, plus all their dependencies. The resulting list of @@ -29,12 +29,30 @@ import ( // a nil if SSA code could not be constructed for the corresponding initial // package due to type errors. // -// Code for bodies of functions is not built until Build is called on -// the resulting Program. SSA code is constructed only for the initial -// packages with well-typed syntax trees. +// Code for bodies of functions is not built until [Program.Build] is +// called on the resulting Program. SSA code is constructed only for +// the initial packages with well-typed syntax trees. // // The mode parameter controls diagnostics and checking during SSA construction. func Packages(initial []*packages.Package, mode ssa.BuilderMode) (*ssa.Program, []*ssa.Package) { + // TODO(adonovan): opt: this calls CreatePackage far more than + // necessary: for all dependencies, not just the (non-initial) + // direct dependencies of the initial packages. + // + // But can it reasonably be changed without breaking the + // spirit and/or letter of the law above? Clients may notice + // if we call CreatePackage less, as methods like + // Program.FuncValue will return nil. Or must we provide a new + // function (and perhaps deprecate this one)? Is it worth it? + // + // Tim King makes the interesting point that it would be + // possible to entirely alleviate the client from the burden + // of calling CreatePackage for non-syntax packages, if we + // were to treat vars and funcs lazily in the same way we now + // treat methods. (In essence, try to move away from the + // notion of ssa.Packages, and make the Program answer + // all reasonable questions about any types.Object.) + return doPackages(initial, mode, false) } @@ -42,7 +60,7 @@ func Packages(initial []*packages.Package, mode ssa.BuilderMode) (*ssa.Program, // their dependencies. // // The packages must have been loaded from source syntax using the -// golang.org/x/tools/go/packages.Load function in LoadAllSyntax mode. +// [packages.Load] function in [packages.LoadAllSyntax] mode. // // AllPackages creates an SSA package for each well-typed package in the // initial list, plus all their dependencies. The resulting list of @@ -102,7 +120,7 @@ func doPackages(initial []*packages.Package, mode ssa.BuilderMode, deps bool) (* // // The mode parameter controls diagnostics and checking during SSA construction. // -// Deprecated: Use golang.org/x/tools/go/packages and the Packages +// Deprecated: Use [golang.org/x/tools/go/packages] and the [Packages] // function instead; see ssa.Example_loadPackages. func CreateProgram(lprog *loader.Program, mode ssa.BuilderMode) *ssa.Program { prog := ssa.NewProgram(lprog.Fset, mode) @@ -116,16 +134,17 @@ func CreateProgram(lprog *loader.Program, mode ssa.BuilderMode) *ssa.Program { return prog } -// BuildPackage builds an SSA program with IR for a single package. +// BuildPackage builds an SSA program with SSA intermediate +// representation (IR) for all functions of a single package. // -// It populates pkg by type-checking the specified file ASTs. All +// It populates pkg by type-checking the specified file syntax trees. All // dependencies are loaded using the importer specified by tc, which // typically loads compiler export data; SSA code cannot be built for -// those packages. BuildPackage then constructs an ssa.Program with all +// those packages. BuildPackage then constructs an [ssa.Program] with all // dependency packages created, and builds and returns the SSA package // corresponding to pkg. // -// The caller must have set pkg.Path() to the import path. +// The caller must have set pkg.Path to the import path. // // The operation fails if there were any type-checking or import errors. // @@ -143,10 +162,11 @@ func BuildPackage(tc *types.Config, fset *token.FileSet, pkg *types.Package, fil Defs: make(map[*ast.Ident]types.Object), Uses: make(map[*ast.Ident]types.Object), Implicits: make(map[ast.Node]types.Object), + Instances: make(map[*ast.Ident]types.Instance), Scopes: make(map[ast.Node]*types.Scope), Selections: make(map[*ast.SelectorExpr]*types.Selection), } - typeparams.InitInstanceInfo(info) + versions.InitFileVersions(info) if err := types.NewChecker(tc, fset, pkg, info).Files(files); err != nil { return nil, nil, err } @@ -168,6 +188,25 @@ func BuildPackage(tc *types.Config, fset *token.FileSet, pkg *types.Package, fil } createAll(pkg.Imports()) + // TODO(adonovan): we could replace createAll with just: + // + // // Create SSA packages for all imports. + // for _, p := range pkg.Imports() { + // prog.CreatePackage(p, nil, nil, true) + // } + // + // (with minor changes to changes to ../builder_test.go as + // shown in CL 511715 PS 10.) But this would strictly violate + // the letter of the doc comment above, which says "all + // dependencies created". + // + // Tim makes the good point with some extra work we could + // remove the need for any CreatePackage calls except the + // ones with syntax (i.e. primary packages). Of course + // You wouldn't have ssa.Packages and Members for as + // many things but no-one really uses that anyway. + // I wish I had done this from the outset. + // Create and build the primary package. ssapkg := prog.CreatePackage(pkg, files, info, false) ssapkg.Build() diff --git a/vendor/golang.org/x/tools/go/ssa/ssautil/visit.go b/vendor/golang.org/x/tools/go/ssa/ssautil/visit.go index 5f27050b0..b4feb42cb 100644 --- a/vendor/golang.org/x/tools/go/ssa/ssautil/visit.go +++ b/vendor/golang.org/x/tools/go/ssa/ssautil/visit.go @@ -4,7 +4,14 @@ package ssautil // import "golang.org/x/tools/go/ssa/ssautil" -import "golang.org/x/tools/go/ssa" +import ( + "go/ast" + "go/types" + + "golang.org/x/tools/go/ssa" + + _ "unsafe" // for linkname hack +) // This file defines utilities for visiting the SSA representation of // a Program. @@ -18,50 +25,113 @@ import "golang.org/x/tools/go/ssa" // synthetic wrappers. // // Precondition: all packages are built. +// +// TODO(adonovan): this function is underspecified. It doesn't +// actually work like a linker, which computes reachability from main +// using something like go/callgraph/cha (without materializing the +// call graph). In fact, it treats all public functions and all +// methods of public non-parameterized types as roots, even though +// they may be unreachable--but only in packages created from syntax. +// +// I think we should deprecate AllFunctions function in favor of two +// clearly defined ones: +// +// 1. The first would efficiently compute CHA reachability from a set +// of main packages, making it suitable for a whole-program +// analysis context with InstantiateGenerics, in conjunction with +// Program.Build. +// +// 2. The second would return only the set of functions corresponding +// to source Func{Decl,Lit} syntax, like SrcFunctions in +// go/analysis/passes/buildssa; this is suitable for +// package-at-a-time (or handful of packages) context. +// ssa.Package could easily expose it as a field. +// +// We could add them unexported for now and use them via the linkname hack. func AllFunctions(prog *ssa.Program) map[*ssa.Function]bool { - visit := visitor{ - prog: prog, - seen: make(map[*ssa.Function]bool), + seen := make(map[*ssa.Function]bool) + + var function func(fn *ssa.Function) + function = func(fn *ssa.Function) { + if !seen[fn] { + seen[fn] = true + var buf [10]*ssa.Value // avoid alloc in common case + for _, b := range fn.Blocks { + for _, instr := range b.Instrs { + for _, op := range instr.Operands(buf[:0]) { + if fn, ok := (*op).(*ssa.Function); ok { + function(fn) + } + } + } + } + } } - visit.program() - return visit.seen -} -type visitor struct { - prog *ssa.Program - seen map[*ssa.Function]bool -} + // TODO(adonovan): opt: provide a way to share a builder + // across a sequence of MethodValue calls. -func (visit *visitor) program() { - for _, pkg := range visit.prog.AllPackages() { - for _, mem := range pkg.Members { - if fn, ok := mem.(*ssa.Function); ok { - visit.function(fn) + methodsOf := func(T types.Type) { + if !types.IsInterface(T) { + mset := prog.MethodSets.MethodSet(T) + for i := 0; i < mset.Len(); i++ { + function(prog.MethodValue(mset.At(i))) } } } - for _, T := range visit.prog.RuntimeTypes() { - mset := visit.prog.MethodSets.MethodSet(T) - for i, n := 0, mset.Len(); i < n; i++ { - visit.function(visit.prog.MethodValue(mset.At(i))) + + // Historically, Program.RuntimeTypes used to include the type + // of any exported member of a package loaded from syntax that + // has a non-parameterized type, plus all types + // reachable from that type using reflection, even though + // these runtime types may not be required for them. + // + // Rather than break existing programs that rely on + // AllFunctions visiting extra methods that are unreferenced + // by IR and unreachable via reflection, we moved the logic + // here, unprincipled though it is. + // (See doc comment for better ideas.) + // + // Nonetheless, after the move, we no longer visit every + // method of any type recursively reachable from T, only the + // methods of T and *T themselves, and we only apply this to + // named types T, and not to the type of every exported + // package member. + exportedTypeHack := func(t *ssa.Type) { + if isSyntactic(t.Package()) && + ast.IsExported(t.Name()) && + !types.IsInterface(t.Type()) { + // Consider only named types. + // (Ignore aliases and unsafe.Pointer.) + if named, ok := t.Type().(*types.Named); ok { + if named.TypeParams() == nil { + methodsOf(named) // T + methodsOf(types.NewPointer(named)) // *T + } + } } } -} -func (visit *visitor) function(fn *ssa.Function) { - if !visit.seen[fn] { - visit.seen[fn] = true - var buf [10]*ssa.Value // avoid alloc in common case - for _, b := range fn.Blocks { - for _, instr := range b.Instrs { - for _, op := range instr.Operands(buf[:0]) { - if fn, ok := (*op).(*ssa.Function); ok { - visit.function(fn) - } - } + for _, pkg := range prog.AllPackages() { + for _, mem := range pkg.Members { + switch mem := mem.(type) { + case *ssa.Function: + // Visit all package-level declared functions. + function(mem) + + case *ssa.Type: + exportedTypeHack(mem) } } } + + // Visit all methods of types for which runtime types were + // materialized, as they are reachable through reflection. + for _, T := range prog.RuntimeTypes() { + methodsOf(T) + } + + return seen } // MainPackages returns the subset of the specified packages @@ -76,3 +146,12 @@ func MainPackages(pkgs []*ssa.Package) []*ssa.Package { } return mains } + +// TODO(adonovan): propose a principled API for this. One possibility +// is a new field, Package.SrcFunctions []*Function, which would +// contain the list of SrcFunctions described in point 2 of the +// AllFunctions doc comment, or nil if the package is not from syntax. +// But perhaps overloading nil vs empty slice is too subtle. +// +//go:linkname isSyntactic golang.org/x/tools/go/ssa.isSyntactic +func isSyntactic(pkg *ssa.Package) bool diff --git a/vendor/golang.org/x/tools/go/ssa/subst.go b/vendor/golang.org/x/tools/go/ssa/subst.go index 23d19ae73..a9a6d41e8 100644 --- a/vendor/golang.org/x/tools/go/ssa/subst.go +++ b/vendor/golang.org/x/tools/go/ssa/subst.go @@ -6,8 +6,6 @@ package ssa import ( "go/types" - - "golang.org/x/tools/internal/typeparams" ) // Type substituter for a fixed set of replacement types. @@ -18,11 +16,11 @@ import ( // // Not concurrency-safe. type subster struct { - replacements map[*typeparams.TypeParam]types.Type // values should contain no type params - cache map[types.Type]types.Type // cache of subst results - ctxt *typeparams.Context // cache for instantiation - scope *types.Scope // *types.Named declared within this scope can be substituted (optional) - debug bool // perform extra debugging checks + replacements map[*types.TypeParam]types.Type // values should contain no type params + cache map[types.Type]types.Type // cache of subst results + ctxt *types.Context // cache for instantiation + scope *types.Scope // *types.Named declared within this scope can be substituted (optional) + debug bool // perform extra debugging checks // TODO(taking): consider adding Pos // TODO(zpavlinovic): replacements can contain type params // when generating instances inside of a generic function body. @@ -31,11 +29,11 @@ type subster struct { // Returns a subster that replaces tparams[i] with targs[i]. Uses ctxt as a cache. // targs should not contain any types in tparams. // scope is the (optional) lexical block of the generic function for which we are substituting. -func makeSubster(ctxt *typeparams.Context, scope *types.Scope, tparams *typeparams.TypeParamList, targs []types.Type, debug bool) *subster { +func makeSubster(ctxt *types.Context, scope *types.Scope, tparams *types.TypeParamList, targs []types.Type, debug bool) *subster { assert(tparams.Len() == len(targs), "makeSubster argument count must match") subst := &subster{ - replacements: make(map[*typeparams.TypeParam]types.Type, tparams.Len()), + replacements: make(map[*types.TypeParam]types.Type, tparams.Len()), cache: make(map[types.Type]types.Type), ctxt: ctxt, scope: scope, @@ -82,7 +80,7 @@ func (subst *subster) typ(t types.Type) (res types.Type) { // fall through if result r will be identical to t, types.Identical(r, t). switch t := t.(type) { - case *typeparams.TypeParam: + case *types.TypeParam: r := subst.replacements[t] assert(r != nil, "type param without replacement encountered") return r @@ -131,7 +129,7 @@ func (subst *subster) typ(t types.Type) (res types.Type) { case *types.Signature: return subst.signature(t) - case *typeparams.Union: + case *types.Union: return subst.union(t) case *types.Interface: @@ -220,25 +218,25 @@ func (subst *subster) var_(v *types.Var) *types.Var { return v } -func (subst *subster) union(u *typeparams.Union) *typeparams.Union { - var out []*typeparams.Term // nil => no updates +func (subst *subster) union(u *types.Union) *types.Union { + var out []*types.Term // nil => no updates for i, n := 0, u.Len(); i < n; i++ { t := u.Term(i) r := subst.typ(t.Type()) if r != t.Type() && out == nil { - out = make([]*typeparams.Term, n) + out = make([]*types.Term, n) for j := 0; j < i; j++ { out[j] = u.Term(j) } } if out != nil { - out[i] = typeparams.NewTerm(t.Tilde(), r) + out[i] = types.NewTerm(t.Tilde(), r) } } if out != nil { - return typeparams.NewUnion(out) + return types.NewUnion(out) } return u } @@ -310,7 +308,7 @@ func (subst *subster) named(t *types.Named) types.Type { // (2) locally scoped type, // (3) generic (type parameters but no type arguments), or // (4) instantiated (type parameters and type arguments). - tparams := typeparams.ForNamed(t) + tparams := t.TypeParams() if tparams.Len() == 0 { if subst.scope != nil && !subst.scope.Contains(t.Obj().Pos()) { // Outside the current function scope? @@ -344,7 +342,7 @@ func (subst *subster) named(t *types.Named) types.Type { n.SetUnderlying(subst.typ(t.Underlying())) return n } - targs := typeparams.NamedTypeArgs(t) + targs := t.TypeArgs() // insts are arguments to instantiate using. insts := make([]types.Type, tparams.Len()) @@ -367,13 +365,13 @@ func (subst *subster) named(t *types.Named) types.Type { inst := subst.typ(targs.At(i)) // TODO(generic): Check with rfindley for mutual recursion insts[i] = inst } - r, err := typeparams.Instantiate(subst.ctxt, typeparams.NamedTypeOrigin(t), insts, false) + r, err := types.Instantiate(subst.ctxt, t.Origin(), insts, false) assert(err == nil, "failed to Instantiate Named type") return r } func (subst *subster) signature(t *types.Signature) types.Type { - tparams := typeparams.ForSignature(t) + tparams := t.TypeParams() // We are choosing not to support tparams.Len() > 0 until a need has been observed in practice. // @@ -398,7 +396,7 @@ func (subst *subster) signature(t *types.Signature) types.Type { params := subst.tuple(t.Params()) results := subst.tuple(t.Results()) if recv != t.Recv() || params != t.Params() || results != t.Results() { - return typeparams.NewSignatureType(recv, nil, nil, params, results, t.Variadic()) + return types.NewSignatureType(recv, nil, nil, params, results, t.Variadic()) } return t } @@ -422,7 +420,7 @@ func reaches(t types.Type, c map[types.Type]bool) (res bool) { }() switch t := t.(type) { - case *typeparams.TypeParam, *types.Basic: + case *types.TypeParam, *types.Basic: return false case *types.Array: return reaches(t.Elem(), c) @@ -451,7 +449,7 @@ func reaches(t types.Type, c map[types.Type]bool) (res bool) { return true } return reaches(t.Params(), c) || reaches(t.Results(), c) - case *typeparams.Union: + case *types.Union: for i := 0; i < t.Len(); i++ { if reaches(t.Term(i).Type(), c) { return true diff --git a/vendor/golang.org/x/tools/go/ssa/util.go b/vendor/golang.org/x/tools/go/ssa/util.go index 68cc971b3..6e9f1282b 100644 --- a/vendor/golang.org/x/tools/go/ssa/util.go +++ b/vendor/golang.org/x/tools/go/ssa/util.go @@ -180,24 +180,6 @@ func makeLen(T types.Type) *Builtin { } } -// nonbasicTypes returns a list containing all of the types T in ts that are non-basic. -func nonbasicTypes(ts []types.Type) []types.Type { - if len(ts) == 0 { - return nil - } - added := make(map[types.Type]bool) // additionally filter duplicates - var filtered []types.Type - for _, T := range ts { - if !isBasic(T) { - if !added[T] { - added[T] = true - filtered = append(filtered, T) - } - } - } - return filtered -} - // receiverTypeArgs returns the type arguments to a function's receiver. // Returns an empty list if obj does not have a receiver or its receiver does not have type arguments. func receiverTypeArgs(obj *types.Func) []types.Type { @@ -210,7 +192,7 @@ func receiverTypeArgs(obj *types.Func) []types.Type { if !ok { return nil } - ts := typeparams.NamedTypeArgs(named) + ts := named.TypeArgs() if ts.Len() == 0 { return nil } @@ -229,7 +211,7 @@ func recvAsFirstArg(sig *types.Signature) *types.Signature { for i := 0; i < sig.Params().Len(); i++ { params = append(params, sig.Params().At(i)) } - return typeparams.NewSignatureType(nil, nil, nil, types.NewTuple(params...), sig.Results(), sig.Variadic()) + return types.NewSignatureType(nil, nil, nil, types.NewTuple(params...), sig.Results(), sig.Variadic()) } // instance returns whether an expression is a simple or qualified identifier @@ -246,13 +228,13 @@ func instance(info *types.Info, expr ast.Expr) bool { default: return false } - _, ok := typeparams.GetInstances(info)[id] + _, ok := info.Instances[id] return ok } // instanceArgs returns the Instance[id].TypeArgs as a slice. func instanceArgs(info *types.Info, id *ast.Ident) []types.Type { - targList := typeparams.GetInstances(info)[id].TypeArgs + targList := info.Instances[id].TypeArgs if targList == nil { return nil } @@ -370,13 +352,13 @@ func (m *typeListMap) hash(ts []types.Type) uint32 { } // instantiateMethod instantiates m with targs and returns a canonical representative for this method. -func (canon *canonizer) instantiateMethod(m *types.Func, targs []types.Type, ctxt *typeparams.Context) *types.Func { +func (canon *canonizer) instantiateMethod(m *types.Func, targs []types.Type, ctxt *types.Context) *types.Func { recv := recvType(m) if p, ok := recv.(*types.Pointer); ok { recv = p.Elem() } named := recv.(*types.Named) - inst, err := typeparams.Instantiate(ctxt, typeparams.NamedTypeOrigin(named), targs, false) + inst, err := types.Instantiate(ctxt, named.Origin(), targs, false) if err != nil { panic(err) } @@ -384,3 +366,16 @@ func (canon *canonizer) instantiateMethod(m *types.Func, targs []types.Type, ctx obj, _, _ := types.LookupFieldOrMethod(rep, true, m.Pkg(), m.Name()) return obj.(*types.Func) } + +// Exposed to ssautil using the linkname hack. +func isSyntactic(pkg *Package) bool { return pkg.syntax } + +// mapValues returns a new unordered array of map values. +func mapValues[K comparable, V any](m map[K]V) []V { + vals := make([]V, 0, len(m)) + for _, fn := range m { + vals = append(vals, fn) + } + return vals + +} diff --git a/vendor/golang.org/x/tools/go/ssa/wrappers.go b/vendor/golang.org/x/tools/go/ssa/wrappers.go index 123ea6858..7c7ee4099 100644 --- a/vendor/golang.org/x/tools/go/ssa/wrappers.go +++ b/vendor/golang.org/x/tools/go/ssa/wrappers.go @@ -28,7 +28,7 @@ import ( // -- wrappers ----------------------------------------------------------- -// makeWrapper returns a synthetic method that delegates to the +// createWrapper returns a synthetic method that delegates to the // declared method denoted by meth.Obj(), first performing any // necessary pointer indirections or field selections implied by meth. // @@ -40,21 +40,17 @@ import ( // - optional implicit field selections // - meth.Obj() may denote a concrete or an interface method // - the result may be a thunk or a wrapper. -// -// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu) -func makeWrapper(prog *Program, sel *selection, cr *creator) *Function { +func createWrapper(prog *Program, sel *selection, cr *creator) *Function { obj := sel.obj.(*types.Func) // the declared function sig := sel.typ.(*types.Signature) // type of this wrapper var recv *types.Var // wrapper's receiver or thunk's params[0] name := obj.Name() var description string - var start int // first regular param if sel.kind == types.MethodExpr { name += "$thunk" description = "thunk" recv = sig.Params().At(0) - start = 1 } else { description = "wrapper" recv = sig.Recv() @@ -62,8 +58,9 @@ func makeWrapper(prog *Program, sel *selection, cr *creator) *Function { description = fmt.Sprintf("%s for %s", description, sel.obj) if prog.mode&LogSource != 0 { - defer logStack("make %s to (%s)", description, recv.Type())() + defer logStack("create %s to (%s)", description, recv.Type())() } + /* method wrapper */ fn := &Function{ name: name, method: sel, @@ -72,35 +69,53 @@ func makeWrapper(prog *Program, sel *selection, cr *creator) *Function { Synthetic: description, Prog: prog, pos: obj.Pos(), - info: nil, // info is not set on wrappers. + // wrappers have no syntax + build: (*builder).buildWrapper, + syntax: nil, + info: nil, + goversion: "", } cr.Add(fn) + return fn +} + +// buildWrapper builds fn.Body for a method wrapper. +func (b *builder) buildWrapper(fn *Function) { + var recv *types.Var // wrapper's receiver or thunk's params[0] + var start int // first regular param + if fn.method.kind == types.MethodExpr { + recv = fn.Signature.Params().At(0) + start = 1 + } else { + recv = fn.Signature.Recv() + } + fn.startBody() fn.addSpilledParam(recv) createParams(fn, start) - indices := sel.index + indices := fn.method.index var v Value = fn.Locals[0] // spilled receiver - srdt, ptrRecv := deptr(sel.recv) + srdt, ptrRecv := deptr(fn.method.recv) if ptrRecv { v = emitLoad(fn, v) // For simple indirection wrappers, perform an informative nil-check: // "value method (T).f called using nil *T pointer" - _, ptrObj := deptr(recvType(obj)) + _, ptrObj := deptr(recvType(fn.object)) if len(indices) == 1 && !ptrObj { var c Call c.Call.Value = &Builtin{ name: "ssa:wrapnilchk", sig: types.NewSignature(nil, - types.NewTuple(anonVar(sel.recv), anonVar(tString), anonVar(tString)), - types.NewTuple(anonVar(sel.recv)), false), + types.NewTuple(anonVar(fn.method.recv), anonVar(tString), anonVar(tString)), + types.NewTuple(anonVar(fn.method.recv)), false), } c.Call.Args = []Value{ v, stringConst(srdt.String()), - stringConst(sel.obj.Name()), + stringConst(fn.method.obj.Name()), } c.setType(v.Type()) v = fn.emit(&c) @@ -122,18 +137,14 @@ func makeWrapper(prog *Program, sel *selection, cr *creator) *Function { // address of implicit C field. var c Call - if r := recvType(obj); !types.IsInterface(r) { // concrete method + if r := recvType(fn.object); !types.IsInterface(r) { // concrete method if _, ptrObj := deptr(r); !ptrObj { v = emitLoad(fn, v) } - callee := prog.originFunc(obj) - if callee.typeparams.Len() > 0 { - callee = prog.lookupOrCreateInstance(callee, receiverTypeArgs(obj), cr) - } - c.Call.Value = callee + c.Call.Value = fn.Prog.objectMethod(fn.object, b.created) c.Call.Args = append(c.Call.Args, v) } else { - c.Call.Method = obj + c.Call.Method = fn.object c.Call.Value = emitLoad(fn, v) // interface (possibly a typeparam) } for _, arg := range fn.Params[1:] { @@ -141,8 +152,6 @@ func makeWrapper(prog *Program, sel *selection, cr *creator) *Function { } emitTailCall(fn, &c) fn.finishBody() - fn.done() - return fn } // createParams creates parameters for wrapper method fn based on its @@ -151,13 +160,13 @@ func makeWrapper(prog *Program, sel *selection, cr *creator) *Function { func createParams(fn *Function, start int) { tparams := fn.Signature.Params() for i, n := start, tparams.Len(); i < n; i++ { - fn.addParamObj(tparams.At(i)) + fn.addParamVar(tparams.At(i)) } } // -- bounds ----------------------------------------------------------- -// makeBound returns a bound method wrapper (or "bound"), a synthetic +// createBound returns a bound method wrapper (or "bound"), a synthetic // function that delegates to a concrete or interface method denoted // by obj. The resulting function has no receiver, but has one free // variable which will be used as the method's receiver in the @@ -176,66 +185,57 @@ func createParams(fn *Function, start int) { // // f := func() { return t.meth() } // -// Unlike makeWrapper, makeBound need perform no indirection or field +// Unlike createWrapper, createBound need perform no indirection or field // selections because that can be done before the closure is // constructed. -// -// EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu) -func makeBound(prog *Program, obj *types.Func, cr *creator) *Function { - targs := receiverTypeArgs(obj) - key := boundsKey{obj, prog.canon.List(targs)} - - prog.methodsMu.Lock() - defer prog.methodsMu.Unlock() - fn, ok := prog.bounds[key] - if !ok { - description := fmt.Sprintf("bound method wrapper for %s", obj) - if prog.mode&LogSource != 0 { - defer logStack("%s", description)() - } - fn = &Function{ - name: obj.Name() + "$bound", - object: obj, - Signature: changeRecv(obj.Type().(*types.Signature), nil), // drop receiver - Synthetic: description, - Prog: prog, - pos: obj.Pos(), - info: nil, // info is not set on wrappers. - } - cr.Add(fn) - - fv := &FreeVar{name: "recv", typ: recvType(obj), parent: fn} - fn.FreeVars = []*FreeVar{fv} - fn.startBody() - createParams(fn, 0) - var c Call - - if !types.IsInterface(recvType(obj)) { // concrete - callee := prog.originFunc(obj) - if callee.typeparams.Len() > 0 { - callee = prog.lookupOrCreateInstance(callee, targs, cr) - } - c.Call.Value = callee - c.Call.Args = []Value{fv} - } else { - c.Call.Method = obj - c.Call.Value = fv // interface (possibly a typeparam) - } - for _, arg := range fn.Params { - c.Call.Args = append(c.Call.Args, arg) - } - emitTailCall(fn, &c) - fn.finishBody() - fn.done() - - prog.bounds[key] = fn +func createBound(prog *Program, obj *types.Func, cr *creator) *Function { + description := fmt.Sprintf("bound method wrapper for %s", obj) + if prog.mode&LogSource != 0 { + defer logStack("%s", description)() + } + /* bound method wrapper */ + fn := &Function{ + name: obj.Name() + "$bound", + object: obj, + Signature: changeRecv(obj.Type().(*types.Signature), nil), // drop receiver + Synthetic: description, + Prog: prog, + pos: obj.Pos(), + // wrappers have no syntax + build: (*builder).buildBound, + syntax: nil, + info: nil, + goversion: "", } + fn.FreeVars = []*FreeVar{{name: "recv", typ: recvType(obj), parent: fn}} // (cyclic) + cr.Add(fn) return fn } +// buildBound builds fn.Body for a bound method closure. +func (b *builder) buildBound(fn *Function) { + fn.startBody() + createParams(fn, 0) + var c Call + + recv := fn.FreeVars[0] + if !types.IsInterface(recvType(fn.object)) { // concrete + c.Call.Value = fn.Prog.objectMethod(fn.object, b.created) + c.Call.Args = []Value{recv} + } else { + c.Call.Method = fn.object + c.Call.Value = recv // interface (possibly a typeparam) + } + for _, arg := range fn.Params { + c.Call.Args = append(c.Call.Args, arg) + } + emitTailCall(fn, &c) + fn.finishBody() +} + // -- thunks ----------------------------------------------------------- -// makeThunk returns a thunk, a synthetic function that delegates to a +// createThunk returns a thunk, a synthetic function that delegates to a // concrete or interface method denoted by sel.obj. The resulting // function has no receiver, but has an additional (first) regular // parameter. @@ -251,38 +251,16 @@ func makeBound(prog *Program, obj *types.Func, cr *creator) *Function { // f is a synthetic wrapper defined as if by: // // f := func(t T) { return t.meth() } -// -// TODO(adonovan): opt: currently the stub is created even when used -// directly in a function call: C.f(i, 0). This is less efficient -// than inlining the stub. -// -// EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu) -func makeThunk(prog *Program, sel *selection, cr *creator) *Function { +func createThunk(prog *Program, sel *selection, cr *creator) *Function { if sel.kind != types.MethodExpr { panic(sel) } - // Canonicalize sel.recv to avoid constructing duplicate thunks. - canonRecv := prog.canon.Type(sel.recv) - key := selectionKey{ - kind: sel.kind, - recv: canonRecv, - obj: sel.obj, - index: fmt.Sprint(sel.index), - indirect: sel.indirect, + fn := createWrapper(prog, sel, cr) + if fn.Signature.Recv() != nil { + panic(fn) // unexpected receiver } - prog.methodsMu.Lock() - defer prog.methodsMu.Unlock() - - fn, ok := prog.thunks[key] - if !ok { - fn = makeWrapper(prog, sel, cr) - if fn.Signature.Recv() != nil { - panic(fn) // unexpected receiver - } - prog.thunks[key] = fn - } return fn } @@ -290,21 +268,6 @@ func changeRecv(s *types.Signature, recv *types.Var) *types.Signature { return types.NewSignature(recv, s.Params(), s.Results(), s.Variadic()) } -// selectionKey is like types.Selection but a usable map key. -type selectionKey struct { - kind types.SelectionKind - recv types.Type // canonicalized via Program.canon - obj types.Object - index string - indirect bool -} - -// boundsKey is a unique for the object and a type instantiation. -type boundsKey struct { - obj types.Object // t.meth - inst *typeList // canonical type instantiation list. -} - // A local version of *types.Selection. // Needed for some additional control, such as creating a MethodExpr for an instantiation. type selection struct { @@ -329,16 +292,16 @@ func toSelection(sel *types.Selection) *selection { // -- instantiations -------------------------------------------------- -// buildInstantiationWrapper creates a body for an instantiation +// buildInstantiationWrapper builds the body of an instantiation // wrapper fn. The body calls the original generic function, // bracketed by ChangeType conversions on its arguments and results. -func buildInstantiationWrapper(fn *Function) { +func (b *builder) buildInstantiationWrapper(fn *Function) { orig := fn.topLevelOrigin sig := fn.Signature fn.startBody() if sig.Recv() != nil { - fn.addParamObj(sig.Recv()) + fn.addParamVar(sig.Recv()) } createParams(fn, 0) diff --git a/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go b/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go index fa5834baf..11d5c8c3a 100644 --- a/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go +++ b/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go @@ -26,13 +26,10 @@ package objectpath import ( "fmt" "go/types" - "sort" "strconv" "strings" - _ "unsafe" "golang.org/x/tools/internal/typeparams" - "golang.org/x/tools/internal/typesinternal" ) // A Path is an opaque name that identifies a types.Object @@ -123,20 +120,7 @@ func For(obj types.Object) (Path, error) { // An Encoder amortizes the cost of encoding the paths of multiple objects. // The zero value of an Encoder is ready to use. type Encoder struct { - scopeMemo map[*types.Scope][]types.Object // memoization of scopeObjects - namedMethodsMemo map[*types.Named][]*types.Func // memoization of namedMethods() - skipMethodSorting bool -} - -// Expose back doors so that gopls can avoid method sorting, which can dominate -// analysis on certain repositories. -// -// TODO(golang/go#61443): remove this. -func init() { - typesinternal.SkipEncoderMethodSorting = func(enc interface{}) { - enc.(*Encoder).skipMethodSorting = true - } - typesinternal.ObjectpathObject = object + scopeMemo map[*types.Scope][]types.Object // memoization of scopeObjects } // For returns the path to an object relative to its package, @@ -239,7 +223,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) { // Reject obviously non-viable cases. switch obj := obj.(type) { case *types.TypeName: - if _, ok := obj.Type().(*typeparams.TypeParam); !ok { + if _, ok := obj.Type().(*types.TypeParam); !ok { // With the exception of type parameters, only package-level type names // have a path. return "", fmt.Errorf("no path for %v", obj) @@ -299,7 +283,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) { } } else { if named, _ := T.(*types.Named); named != nil { - if r := findTypeParam(obj, typeparams.ForNamed(named), path, nil); r != nil { + if r := findTypeParam(obj, named.TypeParams(), path, nil); r != nil { // generic named type return Path(r), nil } @@ -328,31 +312,18 @@ func (enc *Encoder) For(obj types.Object) (Path, error) { // Inspect declared methods of defined types. if T, ok := o.Type().(*types.Named); ok { path = append(path, opType) - if !enc.skipMethodSorting { - // Note that method index here is always with respect - // to canonical ordering of methods, regardless of how - // they appear in the underlying type. - for i, m := range enc.namedMethods(T) { - path2 := appendOpArg(path, opMethod, i) - if m == obj { - return Path(path2), nil // found declared method - } - if r := find(obj, m.Type(), append(path2, opType), nil); r != nil { - return Path(r), nil - } + // The method index here is always with respect + // to the underlying go/types data structures, + // which ultimately derives from source order + // and must be preserved by export data. + for i := 0; i < T.NumMethods(); i++ { + m := T.Method(i) + path2 := appendOpArg(path, opMethod, i) + if m == obj { + return Path(path2), nil // found declared method } - } else { - // This branch must match the logic in the branch above, using go/types - // APIs without sorting. - for i := 0; i < T.NumMethods(); i++ { - m := T.Method(i) - path2 := appendOpArg(path, opMethod, i) - if m == obj { - return Path(path2), nil // found declared method - } - if r := find(obj, m.Type(), append(path2, opType), nil); r != nil { - return Path(r), nil - } + if r := find(obj, m.Type(), append(path2, opType), nil); r != nil { + return Path(r), nil } } } @@ -448,22 +419,13 @@ func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) { path = append(path, name...) path = append(path, opType) - if !enc.skipMethodSorting { - for i, m := range enc.namedMethods(named) { - if m == meth { - path = appendOpArg(path, opMethod, i) - return Path(path), true - } - } - } else { - // This branch must match the logic of the branch above, using go/types - // APIs without sorting. - for i := 0; i < named.NumMethods(); i++ { - m := named.Method(i) - if m == meth { - path = appendOpArg(path, opMethod, i) - return Path(path), true - } + // Method indices are w.r.t. the go/types data structures, + // ultimately deriving from source order, + // which is preserved by export data. + for i := 0; i < named.NumMethods(); i++ { + if named.Method(i) == meth { + path = appendOpArg(path, opMethod, i) + return Path(path), true } } @@ -500,7 +462,7 @@ func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName] } return find(obj, T.Elem(), append(path, opElem), seen) case *types.Signature: - if r := findTypeParam(obj, typeparams.ForSignature(T), path, seen); r != nil { + if r := findTypeParam(obj, T.TypeParams(), path, seen); r != nil { return r } if r := find(obj, T.Params(), append(path, opParams), seen); r != nil { @@ -543,7 +505,7 @@ func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName] } } return nil - case *typeparams.TypeParam: + case *types.TypeParam: name := T.Obj() if name == obj { return append(path, opObj) @@ -563,7 +525,7 @@ func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName] panic(T) } -func findTypeParam(obj types.Object, list *typeparams.TypeParamList, path []byte, seen map[*types.TypeName]bool) []byte { +func findTypeParam(obj types.Object, list *types.TypeParamList, path []byte, seen map[*types.TypeName]bool) []byte { for i := 0; i < list.Len(); i++ { tparam := list.At(i) path2 := appendOpArg(path, opTypeParam, i) @@ -576,12 +538,7 @@ func findTypeParam(obj types.Object, list *typeparams.TypeParamList, path []byte // Object returns the object denoted by path p within the package pkg. func Object(pkg *types.Package, p Path) (types.Object, error) { - return object(pkg, string(p), false) -} - -// Note: the skipMethodSorting parameter must match the value of -// Encoder.skipMethodSorting used during encoding. -func object(pkg *types.Package, pathstr string, skipMethodSorting bool) (types.Object, error) { + pathstr := string(p) if pathstr == "" { return nil, fmt.Errorf("empty path") } @@ -605,7 +562,7 @@ func object(pkg *types.Package, pathstr string, skipMethodSorting bool) (types.O } // abstraction of *types.{Named,Signature} type hasTypeParams interface { - TypeParams() *typeparams.TypeParamList + TypeParams() *types.TypeParamList } // abstraction of *types.{Named,TypeParam} type hasObj interface { @@ -707,7 +664,7 @@ func object(pkg *types.Package, pathstr string, skipMethodSorting bool) (types.O t = tparams.At(index) case opConstraint: - tparam, ok := t.(*typeparams.TypeParam) + tparam, ok := t.(*types.TypeParam) if !ok { return nil, fmt.Errorf("cannot apply %q to %s (got %T, want type parameter)", code, t, t) } @@ -747,12 +704,7 @@ func object(pkg *types.Package, pathstr string, skipMethodSorting bool) (types.O if index >= t.NumMethods() { return nil, fmt.Errorf("method index %d out of range [0-%d)", index, t.NumMethods()) } - if skipMethodSorting { - obj = t.Method(index) - } else { - methods := namedMethods(t) // (unmemoized) - obj = methods[index] // Id-ordered - } + obj = t.Method(index) default: return nil, fmt.Errorf("cannot apply %q to %s (got %T, want interface or named)", code, t, t) @@ -779,33 +731,6 @@ func object(pkg *types.Package, pathstr string, skipMethodSorting bool) (types.O return obj, nil // success } -// namedMethods returns the methods of a Named type in ascending Id order. -func namedMethods(named *types.Named) []*types.Func { - methods := make([]*types.Func, named.NumMethods()) - for i := range methods { - methods[i] = named.Method(i) - } - sort.Slice(methods, func(i, j int) bool { - return methods[i].Id() < methods[j].Id() - }) - return methods -} - -// namedMethods is a memoization of the namedMethods function. Callers must not modify the result. -func (enc *Encoder) namedMethods(named *types.Named) []*types.Func { - m := enc.namedMethodsMemo - if m == nil { - m = make(map[*types.Named][]*types.Func) - enc.namedMethodsMemo = m - } - methods, ok := m[named] - if !ok { - methods = namedMethods(named) // allocates and sorts - m[named] = methods - } - return methods -} - // scopeObjects is a memoization of scope objects. // Callers must not modify the result. func (enc *Encoder) scopeObjects(scope *types.Scope) []types.Object { diff --git a/vendor/golang.org/x/tools/go/types/typeutil/callee.go b/vendor/golang.org/x/tools/go/types/typeutil/callee.go index 90b3ab0e2..90dc541ad 100644 --- a/vendor/golang.org/x/tools/go/types/typeutil/callee.go +++ b/vendor/golang.org/x/tools/go/types/typeutil/callee.go @@ -22,7 +22,7 @@ func Callee(info *types.Info, call *ast.CallExpr) types.Object { // Look through type instantiation if necessary. isInstance := false switch fun.(type) { - case *ast.IndexExpr, *typeparams.IndexListExpr: + case *ast.IndexExpr, *ast.IndexListExpr: // When extracting the callee from an *IndexExpr, we need to check that // it is a *types.Func and not a *types.Var. // Example: Don't match a slice m within the expression `m[0]()`. diff --git a/vendor/golang.org/x/tools/go/types/typeutil/map.go b/vendor/golang.org/x/tools/go/types/typeutil/map.go index 7bd2fdb38..544246dac 100644 --- a/vendor/golang.org/x/tools/go/types/typeutil/map.go +++ b/vendor/golang.org/x/tools/go/types/typeutil/map.go @@ -219,7 +219,7 @@ type Hasher struct { // generic types or functions, and instantiated signatures do not have type // parameter lists, we should never encounter a second non-empty type // parameter list when hashing a generic signature. - sigTParams *typeparams.TypeParamList + sigTParams *types.TypeParamList } // MakeHasher returns a new Hasher instance. @@ -297,7 +297,7 @@ func (h Hasher) hashFor(t types.Type) uint32 { // We should never encounter a generic signature while hashing another // generic signature, but defensively set sigTParams only if h.mask is // unset. - tparams := typeparams.ForSignature(t) + tparams := t.TypeParams() if h.sigTParams == nil && tparams.Len() != 0 { h = Hasher{ // There may be something more efficient than discarding the existing @@ -318,7 +318,7 @@ func (h Hasher) hashFor(t types.Type) uint32 { return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results()) - case *typeparams.Union: + case *types.Union: return h.hashUnion(t) case *types.Interface: @@ -354,14 +354,14 @@ func (h Hasher) hashFor(t types.Type) uint32 { case *types.Named: hash := h.hashPtr(t.Obj()) - targs := typeparams.NamedTypeArgs(t) + targs := t.TypeArgs() for i := 0; i < targs.Len(); i++ { targ := targs.At(i) hash += 2 * h.Hash(targ) } return hash - case *typeparams.TypeParam: + case *types.TypeParam: return h.hashTypeParam(t) case *types.Tuple: @@ -381,7 +381,7 @@ func (h Hasher) hashTuple(tuple *types.Tuple) uint32 { return hash } -func (h Hasher) hashUnion(t *typeparams.Union) uint32 { +func (h Hasher) hashUnion(t *types.Union) uint32 { // Hash type restrictions. terms, err := typeparams.UnionTermSet(t) // if err != nil t has invalid type restrictions. Fall back on a non-zero @@ -392,7 +392,7 @@ func (h Hasher) hashUnion(t *typeparams.Union) uint32 { return h.hashTermSet(terms) } -func (h Hasher) hashTermSet(terms []*typeparams.Term) uint32 { +func (h Hasher) hashTermSet(terms []*types.Term) uint32 { hash := 9157 + 2*uint32(len(terms)) for _, term := range terms { // term order is not significant. @@ -416,7 +416,7 @@ func (h Hasher) hashTermSet(terms []*typeparams.Term) uint32 { // are not identical. // // Otherwise the hash of t depends only on t's pointer identity. -func (h Hasher) hashTypeParam(t *typeparams.TypeParam) uint32 { +func (h Hasher) hashTypeParam(t *types.TypeParam) uint32 { if h.sigTParams != nil { i := t.Index() if i >= 0 && i < h.sigTParams.Len() && t == h.sigTParams.At(i) { @@ -489,7 +489,7 @@ func (h Hasher) shallowHash(t types.Type) uint32 { case *types.Pointer: return 4393139 - case *typeparams.Union: + case *types.Union: return 562448657 case *types.Interface: @@ -504,7 +504,7 @@ func (h Hasher) shallowHash(t types.Type) uint32 { case *types.Named: return h.hashPtr(t.Obj()) - case *typeparams.TypeParam: + case *types.TypeParam: return h.hashPtr(t.Obj()) } panic(fmt.Sprintf("shallowHash: %T: %v", t, t)) diff --git a/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go b/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go new file mode 100644 index 000000000..2b2916804 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go @@ -0,0 +1,386 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package analysisinternal provides gopls' internal analyses with a +// number of helper functions that operate on typed syntax trees. +package analysisinternal + +import ( + "bytes" + "fmt" + "go/ast" + "go/token" + "go/types" + "strconv" +) + +func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos { + // Get the end position for the type error. + offset, end := fset.PositionFor(start, false).Offset, start + if offset >= len(src) { + return end + } + if width := bytes.IndexAny(src[offset:], " \n,():;[]+-*"); width > 0 { + end = start + token.Pos(width) + } + return end +} + +func ZeroValue(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { + under := typ + if n, ok := typ.(*types.Named); ok { + under = n.Underlying() + } + switch u := under.(type) { + case *types.Basic: + switch { + case u.Info()&types.IsNumeric != 0: + return &ast.BasicLit{Kind: token.INT, Value: "0"} + case u.Info()&types.IsBoolean != 0: + return &ast.Ident{Name: "false"} + case u.Info()&types.IsString != 0: + return &ast.BasicLit{Kind: token.STRING, Value: `""`} + default: + panic(fmt.Sprintf("unknown basic type %v", u)) + } + case *types.Chan, *types.Interface, *types.Map, *types.Pointer, *types.Signature, *types.Slice, *types.Array: + return ast.NewIdent("nil") + case *types.Struct: + texpr := TypeExpr(f, pkg, typ) // typ because we want the name here. + if texpr == nil { + return nil + } + return &ast.CompositeLit{ + Type: texpr, + } + } + return nil +} + +// IsZeroValue checks whether the given expression is a 'zero value' (as determined by output of +// analysisinternal.ZeroValue) +func IsZeroValue(expr ast.Expr) bool { + switch e := expr.(type) { + case *ast.BasicLit: + return e.Value == "0" || e.Value == `""` + case *ast.Ident: + return e.Name == "nil" || e.Name == "false" + default: + return false + } +} + +// TypeExpr returns syntax for the specified type. References to +// named types from packages other than pkg are qualified by an appropriate +// package name, as defined by the import environment of file. +func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { + switch t := typ.(type) { + case *types.Basic: + switch t.Kind() { + case types.UnsafePointer: + return &ast.SelectorExpr{X: ast.NewIdent("unsafe"), Sel: ast.NewIdent("Pointer")} + default: + return ast.NewIdent(t.Name()) + } + case *types.Pointer: + x := TypeExpr(f, pkg, t.Elem()) + if x == nil { + return nil + } + return &ast.UnaryExpr{ + Op: token.MUL, + X: x, + } + case *types.Array: + elt := TypeExpr(f, pkg, t.Elem()) + if elt == nil { + return nil + } + return &ast.ArrayType{ + Len: &ast.BasicLit{ + Kind: token.INT, + Value: fmt.Sprintf("%d", t.Len()), + }, + Elt: elt, + } + case *types.Slice: + elt := TypeExpr(f, pkg, t.Elem()) + if elt == nil { + return nil + } + return &ast.ArrayType{ + Elt: elt, + } + case *types.Map: + key := TypeExpr(f, pkg, t.Key()) + value := TypeExpr(f, pkg, t.Elem()) + if key == nil || value == nil { + return nil + } + return &ast.MapType{ + Key: key, + Value: value, + } + case *types.Chan: + dir := ast.ChanDir(t.Dir()) + if t.Dir() == types.SendRecv { + dir = ast.SEND | ast.RECV + } + value := TypeExpr(f, pkg, t.Elem()) + if value == nil { + return nil + } + return &ast.ChanType{ + Dir: dir, + Value: value, + } + case *types.Signature: + var params []*ast.Field + for i := 0; i < t.Params().Len(); i++ { + p := TypeExpr(f, pkg, t.Params().At(i).Type()) + if p == nil { + return nil + } + params = append(params, &ast.Field{ + Type: p, + Names: []*ast.Ident{ + { + Name: t.Params().At(i).Name(), + }, + }, + }) + } + var returns []*ast.Field + for i := 0; i < t.Results().Len(); i++ { + r := TypeExpr(f, pkg, t.Results().At(i).Type()) + if r == nil { + return nil + } + returns = append(returns, &ast.Field{ + Type: r, + }) + } + return &ast.FuncType{ + Params: &ast.FieldList{ + List: params, + }, + Results: &ast.FieldList{ + List: returns, + }, + } + case *types.Named: + if t.Obj().Pkg() == nil { + return ast.NewIdent(t.Obj().Name()) + } + if t.Obj().Pkg() == pkg { + return ast.NewIdent(t.Obj().Name()) + } + pkgName := t.Obj().Pkg().Name() + + // If the file already imports the package under another name, use that. + for _, cand := range f.Imports { + if path, _ := strconv.Unquote(cand.Path.Value); path == t.Obj().Pkg().Path() { + if cand.Name != nil && cand.Name.Name != "" { + pkgName = cand.Name.Name + } + } + } + if pkgName == "." { + return ast.NewIdent(t.Obj().Name()) + } + return &ast.SelectorExpr{ + X: ast.NewIdent(pkgName), + Sel: ast.NewIdent(t.Obj().Name()), + } + case *types.Struct: + return ast.NewIdent(t.String()) + case *types.Interface: + return ast.NewIdent(t.String()) + default: + return nil + } +} + +// StmtToInsertVarBefore returns the ast.Stmt before which we can safely insert a new variable. +// Some examples: +// +// Basic Example: +// z := 1 +// y := z + x +// If x is undeclared, then this function would return `y := z + x`, so that we +// can insert `x := ` on the line before `y := z + x`. +// +// If stmt example: +// if z == 1 { +// } else if z == y {} +// If y is undeclared, then this function would return `if z == 1 {`, because we cannot +// insert a statement between an if and an else if statement. As a result, we need to find +// the top of the if chain to insert `y := ` before. +func StmtToInsertVarBefore(path []ast.Node) ast.Stmt { + enclosingIndex := -1 + for i, p := range path { + if _, ok := p.(ast.Stmt); ok { + enclosingIndex = i + break + } + } + if enclosingIndex == -1 { + return nil + } + enclosingStmt := path[enclosingIndex] + switch enclosingStmt.(type) { + case *ast.IfStmt: + // The enclosingStmt is inside of the if declaration, + // We need to check if we are in an else-if stmt and + // get the base if statement. + return baseIfStmt(path, enclosingIndex) + case *ast.CaseClause: + // Get the enclosing switch stmt if the enclosingStmt is + // inside of the case statement. + for i := enclosingIndex + 1; i < len(path); i++ { + if node, ok := path[i].(*ast.SwitchStmt); ok { + return node + } else if node, ok := path[i].(*ast.TypeSwitchStmt); ok { + return node + } + } + } + if len(path) <= enclosingIndex+1 { + return enclosingStmt.(ast.Stmt) + } + // Check if the enclosing statement is inside another node. + switch expr := path[enclosingIndex+1].(type) { + case *ast.IfStmt: + // Get the base if statement. + return baseIfStmt(path, enclosingIndex+1) + case *ast.ForStmt: + if expr.Init == enclosingStmt || expr.Post == enclosingStmt { + return expr + } + } + return enclosingStmt.(ast.Stmt) +} + +// baseIfStmt walks up the if/else-if chain until we get to +// the top of the current if chain. +func baseIfStmt(path []ast.Node, index int) ast.Stmt { + stmt := path[index] + for i := index + 1; i < len(path); i++ { + if node, ok := path[i].(*ast.IfStmt); ok && node.Else == stmt { + stmt = node + continue + } + break + } + return stmt.(ast.Stmt) +} + +// WalkASTWithParent walks the AST rooted at n. The semantics are +// similar to ast.Inspect except it does not call f(nil). +func WalkASTWithParent(n ast.Node, f func(n ast.Node, parent ast.Node) bool) { + var ancestors []ast.Node + ast.Inspect(n, func(n ast.Node) (recurse bool) { + if n == nil { + ancestors = ancestors[:len(ancestors)-1] + return false + } + + var parent ast.Node + if len(ancestors) > 0 { + parent = ancestors[len(ancestors)-1] + } + ancestors = append(ancestors, n) + return f(n, parent) + }) +} + +// MatchingIdents finds the names of all identifiers in 'node' that match any of the given types. +// 'pos' represents the position at which the identifiers may be inserted. 'pos' must be within +// the scope of each of identifier we select. Otherwise, we will insert a variable at 'pos' that +// is unrecognized. +func MatchingIdents(typs []types.Type, node ast.Node, pos token.Pos, info *types.Info, pkg *types.Package) map[types.Type][]string { + + // Initialize matches to contain the variable types we are searching for. + matches := make(map[types.Type][]string) + for _, typ := range typs { + if typ == nil { + continue // TODO(adonovan): is this reachable? + } + matches[typ] = nil // create entry + } + + seen := map[types.Object]struct{}{} + ast.Inspect(node, func(n ast.Node) bool { + if n == nil { + return false + } + // Prevent circular definitions. If 'pos' is within an assignment statement, do not + // allow any identifiers in that assignment statement to be selected. Otherwise, + // we could do the following, where 'x' satisfies the type of 'f0': + // + // x := fakeStruct{f0: x} + // + if assign, ok := n.(*ast.AssignStmt); ok && pos > assign.Pos() && pos <= assign.End() { + return false + } + if n.End() > pos { + return n.Pos() <= pos + } + ident, ok := n.(*ast.Ident) + if !ok || ident.Name == "_" { + return true + } + obj := info.Defs[ident] + if obj == nil || obj.Type() == nil { + return true + } + if _, ok := obj.(*types.TypeName); ok { + return true + } + // Prevent duplicates in matches' values. + if _, ok = seen[obj]; ok { + return true + } + seen[obj] = struct{}{} + // Find the scope for the given position. Then, check whether the object + // exists within the scope. + innerScope := pkg.Scope().Innermost(pos) + if innerScope == nil { + return true + } + _, foundObj := innerScope.LookupParent(ident.Name, pos) + if foundObj != obj { + return true + } + // The object must match one of the types that we are searching for. + // TODO(adonovan): opt: use typeutil.Map? + if names, ok := matches[obj.Type()]; ok { + matches[obj.Type()] = append(names, ident.Name) + } else { + // If the object type does not exactly match + // any of the target types, greedily find the first + // target type that the object type can satisfy. + for typ := range matches { + if equivalentTypes(obj.Type(), typ) { + matches[typ] = append(matches[typ], ident.Name) + } + } + } + return true + }) + return matches +} + +func equivalentTypes(want, got types.Type) bool { + if types.Identical(want, got) { + return true + } + // Code segment to help check for untyped equality from (golang/go#32146). + if rhs, ok := want.(*types.Basic); ok && rhs.Info()&types.IsUntyped > 0 { + if lhs, ok := got.Underlying().(*types.Basic); ok { + return rhs.Info()&types.IsConstType == lhs.Info()&types.IsConstType + } + } + return types.AssignableTo(want, got) +} diff --git a/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/extractdoc.go b/vendor/golang.org/x/tools/internal/analysisinternal/extractdoc.go similarity index 99% rename from vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/extractdoc.go rename to vendor/golang.org/x/tools/internal/analysisinternal/extractdoc.go index 0e175ca06..39507723d 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/extractdoc.go +++ b/vendor/golang.org/x/tools/internal/analysisinternal/extractdoc.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package analysisutil +package analysisinternal import ( "fmt" diff --git a/vendor/golang.org/x/tools/internal/diff/ndiff.go b/vendor/golang.org/x/tools/internal/diff/ndiff.go index 050b08ded..fbef4d730 100644 --- a/vendor/golang.org/x/tools/internal/diff/ndiff.go +++ b/vendor/golang.org/x/tools/internal/diff/ndiff.go @@ -18,7 +18,7 @@ func Strings(before, after string) []Edit { return nil // common case } - if stringIsASCII(before) && stringIsASCII(after) { + if isASCII(before) && isASCII(after) { // TODO(adonovan): opt: specialize diffASCII for strings. return diffASCII([]byte(before), []byte(after)) } @@ -32,7 +32,7 @@ func Bytes(before, after []byte) []Edit { return nil // common case } - if bytesIsASCII(before) && bytesIsASCII(after) { + if isASCII(before) && isASCII(after) { return diffASCII(before, after) } return diffRunes(runes(before), runes(after)) @@ -88,18 +88,8 @@ func runesLen(runes []rune) (len int) { return len } -// stringIsASCII reports whether s contains only ASCII. -// TODO(adonovan): combine when x/tools allows generics. -func stringIsASCII(s string) bool { - for i := 0; i < len(s); i++ { - if s[i] >= utf8.RuneSelf { - return false - } - } - return true -} - -func bytesIsASCII(s []byte) bool { +// isASCII reports whether s contains only ASCII. +func isASCII[S string | []byte](s S) bool { for i := 0; i < len(s); i++ { if s[i] >= utf8.RuneSelf { return false diff --git a/vendor/golang.org/x/tools/internal/diff/unified.go b/vendor/golang.org/x/tools/internal/diff/unified.go index 1308503f7..cfbda6102 100644 --- a/vendor/golang.org/x/tools/internal/diff/unified.go +++ b/vendor/golang.org/x/tools/internal/diff/unified.go @@ -10,12 +10,16 @@ import ( "strings" ) +// DefaultContextLines is the number of unchanged lines of surrounding +// context displayed by Unified. Use ToUnified to specify a different value. +const DefaultContextLines = 3 + // Unified returns a unified diff of the old and new strings. // The old and new labels are the names of the old and new files. // If the strings are equal, it returns the empty string. func Unified(oldLabel, newLabel, old, new string) string { edits := Strings(old, new) - unified, err := ToUnified(oldLabel, newLabel, old, edits) + unified, err := ToUnified(oldLabel, newLabel, old, edits, DefaultContextLines) if err != nil { // Can't happen: edits are consistent. log.Fatalf("internal error in diff.Unified: %v", err) @@ -23,11 +27,12 @@ func Unified(oldLabel, newLabel, old, new string) string { return unified } -// ToUnified applies the edits to content and returns a unified diff. +// ToUnified applies the edits to content and returns a unified diff, +// with contextLines lines of (unchanged) context around each diff hunk. // The old and new labels are the names of the content and result files. // It returns an error if the edits are inconsistent; see ApplyEdits. -func ToUnified(oldLabel, newLabel, content string, edits []Edit) (string, error) { - u, err := toUnified(oldLabel, newLabel, content, edits) +func ToUnified(oldLabel, newLabel, content string, edits []Edit, contextLines int) (string, error) { + u, err := toUnified(oldLabel, newLabel, content, edits, contextLines) if err != nil { return "", err } @@ -93,14 +98,10 @@ func (k opKind) String() string { } } -const ( - edge = 3 - gap = edge * 2 -) - // toUnified takes a file contents and a sequence of edits, and calculates // a unified diff that represents those edits. -func toUnified(fromName, toName string, content string, edits []Edit) (unified, error) { +func toUnified(fromName, toName string, content string, edits []Edit, contextLines int) (unified, error) { + gap := contextLines * 2 u := unified{ from: fromName, to: toName, @@ -136,7 +137,7 @@ func toUnified(fromName, toName string, content string, edits []Edit) (unified, //need to start a new hunk if h != nil { // add the edge to the previous hunk - addEqualLines(h, lines, last, last+edge) + addEqualLines(h, lines, last, last+contextLines) u.hunks = append(u.hunks, h) } toLine += start - last @@ -145,7 +146,7 @@ func toUnified(fromName, toName string, content string, edits []Edit) (unified, toLine: toLine + 1, } // add the edge to the new hunk - delta := addEqualLines(h, lines, start-edge, start) + delta := addEqualLines(h, lines, start-contextLines, start) h.fromLine -= delta h.toLine -= delta } @@ -163,7 +164,7 @@ func toUnified(fromName, toName string, content string, edits []Edit) (unified, } if h != nil { // add the edge to the final hunk - addEqualLines(h, lines, last, last+edge) + addEqualLines(h, lines, last, last+contextLines) u.hunks = append(u.hunks, h) } return u, nil diff --git a/vendor/golang.org/x/tools/internal/event/keys/util.go b/vendor/golang.org/x/tools/internal/event/keys/util.go new file mode 100644 index 000000000..c0e8e731c --- /dev/null +++ b/vendor/golang.org/x/tools/internal/event/keys/util.go @@ -0,0 +1,21 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package keys + +import ( + "sort" + "strings" +) + +// Join returns a canonical join of the keys in S: +// a sorted comma-separated string list. +func Join[S ~[]T, T ~string](s S) string { + strs := make([]string, 0, len(s)) + for _, v := range s { + strs = append(strs, string(v)) + } + sort.Strings(strs) + return strings.Join(strs, ",") +} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go deleted file mode 100644 index c40c7e931..000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package fastwalk provides a faster version of [filepath.Walk] for file system -// scanning tools. -package fastwalk - -import ( - "errors" - "os" - "path/filepath" - "runtime" - "sync" -) - -// ErrTraverseLink is used as a return value from WalkFuncs to indicate that the -// symlink named in the call may be traversed. -var ErrTraverseLink = errors.New("fastwalk: traverse symlink, assuming target is a directory") - -// ErrSkipFiles is a used as a return value from WalkFuncs to indicate that the -// callback should not be called for any other files in the current directory. -// Child directories will still be traversed. -var ErrSkipFiles = errors.New("fastwalk: skip remaining files in directory") - -// Walk is a faster implementation of [filepath.Walk]. -// -// [filepath.Walk]'s design necessarily calls [os.Lstat] on each file, -// even if the caller needs less info. -// Many tools need only the type of each file. -// On some platforms, this information is provided directly by the readdir -// system call, avoiding the need to stat each file individually. -// fastwalk_unix.go contains a fork of the syscall routines. -// -// See golang.org/issue/16399. -// -// Walk walks the file tree rooted at root, calling walkFn for -// each file or directory in the tree, including root. -// -// If Walk returns [filepath.SkipDir], the directory is skipped. -// -// Unlike [filepath.Walk]: -// - file stat calls must be done by the user. -// The only provided metadata is the file type, which does not include -// any permission bits. -// - multiple goroutines stat the filesystem concurrently. The provided -// walkFn must be safe for concurrent use. -// - Walk can follow symlinks if walkFn returns the TraverseLink -// sentinel error. It is the walkFn's responsibility to prevent -// Walk from going into symlink cycles. -func Walk(root string, walkFn func(path string, typ os.FileMode) error) error { - // TODO(bradfitz): make numWorkers configurable? We used a - // minimum of 4 to give the kernel more info about multiple - // things we want, in hopes its I/O scheduling can take - // advantage of that. Hopefully most are in cache. Maybe 4 is - // even too low of a minimum. Profile more. - numWorkers := 4 - if n := runtime.NumCPU(); n > numWorkers { - numWorkers = n - } - - // Make sure to wait for all workers to finish, otherwise - // walkFn could still be called after returning. This Wait call - // runs after close(e.donec) below. - var wg sync.WaitGroup - defer wg.Wait() - - w := &walker{ - fn: walkFn, - enqueuec: make(chan walkItem, numWorkers), // buffered for performance - workc: make(chan walkItem, numWorkers), // buffered for performance - donec: make(chan struct{}), - - // buffered for correctness & not leaking goroutines: - resc: make(chan error, numWorkers), - } - defer close(w.donec) - - for i := 0; i < numWorkers; i++ { - wg.Add(1) - go w.doWork(&wg) - } - todo := []walkItem{{dir: root}} - out := 0 - for { - workc := w.workc - var workItem walkItem - if len(todo) == 0 { - workc = nil - } else { - workItem = todo[len(todo)-1] - } - select { - case workc <- workItem: - todo = todo[:len(todo)-1] - out++ - case it := <-w.enqueuec: - todo = append(todo, it) - case err := <-w.resc: - out-- - if err != nil { - return err - } - if out == 0 && len(todo) == 0 { - // It's safe to quit here, as long as the buffered - // enqueue channel isn't also readable, which might - // happen if the worker sends both another unit of - // work and its result before the other select was - // scheduled and both w.resc and w.enqueuec were - // readable. - select { - case it := <-w.enqueuec: - todo = append(todo, it) - default: - return nil - } - } - } - } -} - -// doWork reads directories as instructed (via workc) and runs the -// user's callback function. -func (w *walker) doWork(wg *sync.WaitGroup) { - defer wg.Done() - for { - select { - case <-w.donec: - return - case it := <-w.workc: - select { - case <-w.donec: - return - case w.resc <- w.walk(it.dir, !it.callbackDone): - } - } - } -} - -type walker struct { - fn func(path string, typ os.FileMode) error - - donec chan struct{} // closed on fastWalk's return - workc chan walkItem // to workers - enqueuec chan walkItem // from workers - resc chan error // from workers -} - -type walkItem struct { - dir string - callbackDone bool // callback already called; don't do it again -} - -func (w *walker) enqueue(it walkItem) { - select { - case w.enqueuec <- it: - case <-w.donec: - } -} - -func (w *walker) onDirEnt(dirName, baseName string, typ os.FileMode) error { - joined := dirName + string(os.PathSeparator) + baseName - if typ == os.ModeDir { - w.enqueue(walkItem{dir: joined}) - return nil - } - - err := w.fn(joined, typ) - if typ == os.ModeSymlink { - if err == ErrTraverseLink { - // Set callbackDone so we don't call it twice for both the - // symlink-as-symlink and the symlink-as-directory later: - w.enqueue(walkItem{dir: joined, callbackDone: true}) - return nil - } - if err == filepath.SkipDir { - // Permit SkipDir on symlinks too. - return nil - } - } - return err -} - -func (w *walker) walk(root string, runUserCallback bool) error { - if runUserCallback { - err := w.fn(root, os.ModeDir) - if err == filepath.SkipDir { - return nil - } - if err != nil { - return err - } - } - - return readDir(root, w.onDirEnt) -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_darwin.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_darwin.go deleted file mode 100644 index 0ca55e0d5..000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_darwin.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build darwin && cgo -// +build darwin,cgo - -package fastwalk - -/* -#include - -// fastwalk_readdir_r wraps readdir_r so that we don't have to pass a dirent** -// result pointer which triggers CGO's "Go pointer to Go pointer" check unless -// we allocat the result dirent* with malloc. -// -// fastwalk_readdir_r returns 0 on success, -1 upon reaching the end of the -// directory, or a positive error number to indicate failure. -static int fastwalk_readdir_r(DIR *fd, struct dirent *entry) { - struct dirent *result; - int ret = readdir_r(fd, entry, &result); - if (ret == 0 && result == NULL) { - ret = -1; // EOF - } - return ret; -} -*/ -import "C" - -import ( - "os" - "syscall" - "unsafe" -) - -func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { - fd, err := openDir(dirName) - if err != nil { - return &os.PathError{Op: "opendir", Path: dirName, Err: err} - } - defer C.closedir(fd) - - skipFiles := false - var dirent syscall.Dirent - for { - ret := int(C.fastwalk_readdir_r(fd, (*C.struct_dirent)(unsafe.Pointer(&dirent)))) - if ret != 0 { - if ret == -1 { - break // EOF - } - if ret == int(syscall.EINTR) { - continue - } - return &os.PathError{Op: "readdir", Path: dirName, Err: syscall.Errno(ret)} - } - if dirent.Ino == 0 { - continue - } - typ := dtToType(dirent.Type) - if skipFiles && typ.IsRegular() { - continue - } - name := (*[len(syscall.Dirent{}.Name)]byte)(unsafe.Pointer(&dirent.Name))[:] - name = name[:dirent.Namlen] - for i, c := range name { - if c == 0 { - name = name[:i] - break - } - } - // Check for useless names before allocating a string. - if string(name) == "." || string(name) == ".." { - continue - } - if err := fn(dirName, string(name), typ); err != nil { - if err != ErrSkipFiles { - return err - } - skipFiles = true - } - } - - return nil -} - -func dtToType(typ uint8) os.FileMode { - switch typ { - case syscall.DT_BLK: - return os.ModeDevice - case syscall.DT_CHR: - return os.ModeDevice | os.ModeCharDevice - case syscall.DT_DIR: - return os.ModeDir - case syscall.DT_FIFO: - return os.ModeNamedPipe - case syscall.DT_LNK: - return os.ModeSymlink - case syscall.DT_REG: - return 0 - case syscall.DT_SOCK: - return os.ModeSocket - } - return ^os.FileMode(0) -} - -// openDir wraps opendir(3) and handles any EINTR errors. The returned *DIR -// needs to be closed with closedir(3). -func openDir(path string) (*C.DIR, error) { - name, err := syscall.BytePtrFromString(path) - if err != nil { - return nil, err - } - for { - fd, err := C.opendir((*C.char)(unsafe.Pointer(name))) - if err != syscall.EINTR { - return fd, err - } - } -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go deleted file mode 100644 index d58595dbd..000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build freebsd || openbsd || netbsd -// +build freebsd openbsd netbsd - -package fastwalk - -import "syscall" - -func direntInode(dirent *syscall.Dirent) uint64 { - return uint64(dirent.Fileno) -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go deleted file mode 100644 index d3922890b..000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build (linux || (darwin && !cgo)) && !appengine -// +build linux darwin,!cgo -// +build !appengine - -package fastwalk - -import "syscall" - -func direntInode(dirent *syscall.Dirent) uint64 { - return dirent.Ino -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go deleted file mode 100644 index 38a4db6af..000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build (darwin && !cgo) || freebsd || openbsd || netbsd -// +build darwin,!cgo freebsd openbsd netbsd - -package fastwalk - -import "syscall" - -func direntNamlen(dirent *syscall.Dirent) uint64 { - return uint64(dirent.Namlen) -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go deleted file mode 100644 index c82e57df8..000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build linux && !appengine -// +build linux,!appengine - -package fastwalk - -import ( - "bytes" - "syscall" - "unsafe" -) - -func direntNamlen(dirent *syscall.Dirent) uint64 { - const fixedHdr = uint16(unsafe.Offsetof(syscall.Dirent{}.Name)) - nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])) - const nameBufLen = uint16(len(nameBuf)) - limit := dirent.Reclen - fixedHdr - if limit > nameBufLen { - limit = nameBufLen - } - nameLen := bytes.IndexByte(nameBuf[:limit], 0) - if nameLen < 0 { - panic("failed to find terminating 0 byte in dirent") - } - return uint64(nameLen) -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go deleted file mode 100644 index 27e860243..000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build appengine || (!linux && !darwin && !freebsd && !openbsd && !netbsd) -// +build appengine !linux,!darwin,!freebsd,!openbsd,!netbsd - -package fastwalk - -import ( - "os" -) - -// readDir calls fn for each directory entry in dirName. -// It does not descend into directories or follow symlinks. -// If fn returns a non-nil error, readDir returns with that error -// immediately. -func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { - fis, err := os.ReadDir(dirName) - if err != nil { - return err - } - skipFiles := false - for _, fi := range fis { - info, err := fi.Info() - if err != nil { - return err - } - if info.Mode().IsRegular() && skipFiles { - continue - } - if err := fn(dirName, fi.Name(), info.Mode()&os.ModeType); err != nil { - if err == ErrSkipFiles { - skipFiles = true - continue - } - return err - } - } - return nil -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go deleted file mode 100644 index f12f1a734..000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build (linux || freebsd || openbsd || netbsd || (darwin && !cgo)) && !appengine -// +build linux freebsd openbsd netbsd darwin,!cgo -// +build !appengine - -package fastwalk - -import ( - "fmt" - "os" - "syscall" - "unsafe" -) - -const blockSize = 8 << 10 - -// unknownFileMode is a sentinel (and bogus) os.FileMode -// value used to represent a syscall.DT_UNKNOWN Dirent.Type. -const unknownFileMode os.FileMode = os.ModeNamedPipe | os.ModeSocket | os.ModeDevice - -func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { - fd, err := open(dirName, 0, 0) - if err != nil { - return &os.PathError{Op: "open", Path: dirName, Err: err} - } - defer syscall.Close(fd) - - // The buffer must be at least a block long. - buf := make([]byte, blockSize) // stack-allocated; doesn't escape - bufp := 0 // starting read position in buf - nbuf := 0 // end valid data in buf - skipFiles := false - for { - if bufp >= nbuf { - bufp = 0 - nbuf, err = readDirent(fd, buf) - if err != nil { - return os.NewSyscallError("readdirent", err) - } - if nbuf <= 0 { - return nil - } - } - consumed, name, typ := parseDirEnt(buf[bufp:nbuf]) - bufp += consumed - if name == "" || name == "." || name == ".." { - continue - } - // Fallback for filesystems (like old XFS) that don't - // support Dirent.Type and have DT_UNKNOWN (0) there - // instead. - if typ == unknownFileMode { - fi, err := os.Lstat(dirName + "/" + name) - if err != nil { - // It got deleted in the meantime. - if os.IsNotExist(err) { - continue - } - return err - } - typ = fi.Mode() & os.ModeType - } - if skipFiles && typ.IsRegular() { - continue - } - if err := fn(dirName, name, typ); err != nil { - if err == ErrSkipFiles { - skipFiles = true - continue - } - return err - } - } -} - -func parseDirEnt(buf []byte) (consumed int, name string, typ os.FileMode) { - // golang.org/issue/37269 - dirent := &syscall.Dirent{} - copy((*[unsafe.Sizeof(syscall.Dirent{})]byte)(unsafe.Pointer(dirent))[:], buf) - if v := unsafe.Offsetof(dirent.Reclen) + unsafe.Sizeof(dirent.Reclen); uintptr(len(buf)) < v { - panic(fmt.Sprintf("buf size of %d smaller than dirent header size %d", len(buf), v)) - } - if len(buf) < int(dirent.Reclen) { - panic(fmt.Sprintf("buf size %d < record length %d", len(buf), dirent.Reclen)) - } - consumed = int(dirent.Reclen) - if direntInode(dirent) == 0 { // File absent in directory. - return - } - switch dirent.Type { - case syscall.DT_REG: - typ = 0 - case syscall.DT_DIR: - typ = os.ModeDir - case syscall.DT_LNK: - typ = os.ModeSymlink - case syscall.DT_BLK: - typ = os.ModeDevice - case syscall.DT_FIFO: - typ = os.ModeNamedPipe - case syscall.DT_SOCK: - typ = os.ModeSocket - case syscall.DT_UNKNOWN: - typ = unknownFileMode - default: - // Skip weird things. - // It's probably a DT_WHT (http://lwn.net/Articles/325369/) - // or something. Revisit if/when this package is moved outside - // of goimports. goimports only cares about regular files, - // symlinks, and directories. - return - } - - nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])) - nameLen := direntNamlen(dirent) - - // Special cases for common things: - if nameLen == 1 && nameBuf[0] == '.' { - name = "." - } else if nameLen == 2 && nameBuf[0] == '.' && nameBuf[1] == '.' { - name = ".." - } else { - name = string(nameBuf[:nameLen]) - } - return -} - -// According to https://golang.org/doc/go1.14#runtime -// A consequence of the implementation of preemption is that on Unix systems, including Linux and macOS -// systems, programs built with Go 1.14 will receive more signals than programs built with earlier releases. -// -// This causes syscall.Open and syscall.ReadDirent sometimes fail with EINTR errors. -// We need to retry in this case. -func open(path string, mode int, perm uint32) (fd int, err error) { - for { - fd, err := syscall.Open(path, mode, perm) - if err != syscall.EINTR { - return fd, err - } - } -} - -func readDirent(fd int, buf []byte) (n int, err error) { - for { - nbuf, err := syscall.ReadDirent(fd, buf) - if err != syscall.EINTR { - return nbuf, err - } - } -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iexport.go b/vendor/golang.org/x/tools/internal/gcimporter/iexport.go index 6103dd710..2ee8c7016 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/iexport.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/iexport.go @@ -24,7 +24,6 @@ import ( "golang.org/x/tools/go/types/objectpath" "golang.org/x/tools/internal/tokeninternal" - "golang.org/x/tools/internal/typeparams" ) // IExportShallow encodes "shallow" export data for the specified package. @@ -481,7 +480,7 @@ func (p *iexporter) doDecl(obj types.Object) { } // Function. - if typeparams.ForSignature(sig).Len() == 0 { + if sig.TypeParams().Len() == 0 { w.tag('F') } else { w.tag('G') @@ -494,7 +493,7 @@ func (p *iexporter) doDecl(obj types.Object) { // // While importing the type parameters, tparamList computes and records // their export name, so that it can be later used when writing the index. - if tparams := typeparams.ForSignature(sig); tparams.Len() > 0 { + if tparams := sig.TypeParams(); tparams.Len() > 0 { w.tparamList(obj.Name(), tparams, obj.Pkg()) } w.signature(sig) @@ -507,14 +506,14 @@ func (p *iexporter) doDecl(obj types.Object) { case *types.TypeName: t := obj.Type() - if tparam, ok := t.(*typeparams.TypeParam); ok { + if tparam, ok := t.(*types.TypeParam); ok { w.tag('P') w.pos(obj.Pos()) constraint := tparam.Constraint() if p.version >= iexportVersionGo1_18 { implicit := false if iface, _ := constraint.(*types.Interface); iface != nil { - implicit = typeparams.IsImplicit(iface) + implicit = iface.IsImplicit() } w.bool(implicit) } @@ -535,17 +534,17 @@ func (p *iexporter) doDecl(obj types.Object) { panic(internalErrorf("%s is not a defined type", t)) } - if typeparams.ForNamed(named).Len() == 0 { + if named.TypeParams().Len() == 0 { w.tag('T') } else { w.tag('U') } w.pos(obj.Pos()) - if typeparams.ForNamed(named).Len() > 0 { + if named.TypeParams().Len() > 0 { // While importing the type parameters, tparamList computes and records // their export name, so that it can be later used when writing the index. - w.tparamList(obj.Name(), typeparams.ForNamed(named), obj.Pkg()) + w.tparamList(obj.Name(), named.TypeParams(), obj.Pkg()) } underlying := obj.Type().Underlying() @@ -565,7 +564,7 @@ func (p *iexporter) doDecl(obj types.Object) { // Receiver type parameters are type arguments of the receiver type, so // their name must be qualified before exporting recv. - if rparams := typeparams.RecvTypeParams(sig); rparams.Len() > 0 { + if rparams := sig.RecvTypeParams(); rparams.Len() > 0 { prefix := obj.Name() + "." + m.Name() for i := 0; i < rparams.Len(); i++ { rparam := rparams.At(i) @@ -740,19 +739,19 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) { } switch t := t.(type) { case *types.Named: - if targs := typeparams.NamedTypeArgs(t); targs.Len() > 0 { + if targs := t.TypeArgs(); targs.Len() > 0 { w.startType(instanceType) // TODO(rfindley): investigate if this position is correct, and if it // matters. w.pos(t.Obj().Pos()) w.typeList(targs, pkg) - w.typ(typeparams.NamedTypeOrigin(t), pkg) + w.typ(t.Origin(), pkg) return } w.startType(definedType) w.qualifiedType(t.Obj()) - case *typeparams.TypeParam: + case *types.TypeParam: w.startType(typeParamType) w.qualifiedType(t.Obj()) @@ -868,7 +867,7 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) { w.signature(sig) } - case *typeparams.Union: + case *types.Union: w.startType(unionType) nt := t.Len() w.uint64(uint64(nt)) @@ -948,14 +947,14 @@ func (w *exportWriter) signature(sig *types.Signature) { } } -func (w *exportWriter) typeList(ts *typeparams.TypeList, pkg *types.Package) { +func (w *exportWriter) typeList(ts *types.TypeList, pkg *types.Package) { w.uint64(uint64(ts.Len())) for i := 0; i < ts.Len(); i++ { w.typ(ts.At(i), pkg) } } -func (w *exportWriter) tparamList(prefix string, list *typeparams.TypeParamList, pkg *types.Package) { +func (w *exportWriter) tparamList(prefix string, list *types.TypeParamList, pkg *types.Package) { ll := uint64(list.Len()) w.uint64(ll) for i := 0; i < list.Len(); i++ { @@ -973,7 +972,7 @@ const blankMarker = "$" // differs from its actual object name: it is prefixed with a qualifier, and // blank type parameter names are disambiguated by their index in the type // parameter list. -func tparamExportName(prefix string, tparam *typeparams.TypeParam) string { +func tparamExportName(prefix string, tparam *types.TypeParam) string { assert(prefix != "") name := tparam.Obj().Name() if name == "_" { diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iimport.go b/vendor/golang.org/x/tools/internal/gcimporter/iimport.go index 8e64cf644..9bde15e3b 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/iimport.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/iimport.go @@ -22,7 +22,6 @@ import ( "strings" "golang.org/x/tools/go/types/objectpath" - "golang.org/x/tools/internal/typeparams" ) type intReader struct { @@ -321,7 +320,7 @@ func iimportCommon(fset *token.FileSet, getPackages GetPackagesFunc, data []byte // Therefore, we defer calling SetConstraint there, and call it here instead // after all types are complete. for _, d := range p.later { - typeparams.SetTypeParamConstraint(d.t, d.constraint) + d.t.SetConstraint(d.constraint) } for _, typ := range p.interfaceList { @@ -339,7 +338,7 @@ func iimportCommon(fset *token.FileSet, getPackages GetPackagesFunc, data []byte } type setConstraintArgs struct { - t *typeparams.TypeParam + t *types.TypeParam constraint types.Type } @@ -549,7 +548,7 @@ func (r *importReader) obj(name string) { r.declare(types.NewConst(pos, r.currPkg, name, typ, val)) case 'F', 'G': - var tparams []*typeparams.TypeParam + var tparams []*types.TypeParam if tag == 'G' { tparams = r.tparamList() } @@ -566,7 +565,7 @@ func (r *importReader) obj(name string) { r.declare(obj) if tag == 'U' { tparams := r.tparamList() - typeparams.SetForNamed(named, tparams) + named.SetTypeParams(tparams) } underlying := r.p.typAt(r.uint64(), named).Underlying() @@ -583,12 +582,12 @@ func (r *importReader) obj(name string) { // typeparams being used in the method sig/body). base := baseType(recv.Type()) assert(base != nil) - targs := typeparams.NamedTypeArgs(base) - var rparams []*typeparams.TypeParam + targs := base.TypeArgs() + var rparams []*types.TypeParam if targs.Len() > 0 { - rparams = make([]*typeparams.TypeParam, targs.Len()) + rparams = make([]*types.TypeParam, targs.Len()) for i := range rparams { - rparams[i] = targs.At(i).(*typeparams.TypeParam) + rparams[i] = targs.At(i).(*types.TypeParam) } } msig := r.signature(recv, rparams, nil) @@ -606,7 +605,7 @@ func (r *importReader) obj(name string) { } name0 := tparamName(name) tn := types.NewTypeName(pos, r.currPkg, name0, nil) - t := typeparams.NewTypeParam(tn, nil) + t := types.NewTypeParam(tn, nil) // To handle recursive references to the typeparam within its // bound, save the partial type in tparamIndex before reading the bounds. @@ -622,7 +621,7 @@ func (r *importReader) obj(name string) { if iface == nil { errorf("non-interface constraint marked implicit") } - typeparams.MarkImplicit(iface) + iface.MarkImplicit() } // The constraint type may not be complete, if we // are in the middle of a type recursion involving type @@ -966,7 +965,7 @@ func (r *importReader) doType(base *types.Named) (res types.Type) { // The imported instantiated type doesn't include any methods, so // we must always use the methods of the base (orig) type. // TODO provide a non-nil *Environment - t, _ := typeparams.Instantiate(nil, baseType, targs, false) + t, _ := types.Instantiate(nil, baseType, targs, false) // Workaround for golang/go#61561. See the doc for instanceList for details. r.p.instanceList = append(r.p.instanceList, t) @@ -976,11 +975,11 @@ func (r *importReader) doType(base *types.Named) (res types.Type) { if r.p.version < iexportVersionGenerics { errorf("unexpected instantiation type") } - terms := make([]*typeparams.Term, r.uint64()) + terms := make([]*types.Term, r.uint64()) for i := range terms { - terms[i] = typeparams.NewTerm(r.bool(), r.typ()) + terms[i] = types.NewTerm(r.bool(), r.typ()) } - return typeparams.NewUnion(terms) + return types.NewUnion(terms) } } @@ -1008,23 +1007,23 @@ func (r *importReader) objectPathObject() types.Object { return obj } -func (r *importReader) signature(recv *types.Var, rparams []*typeparams.TypeParam, tparams []*typeparams.TypeParam) *types.Signature { +func (r *importReader) signature(recv *types.Var, rparams []*types.TypeParam, tparams []*types.TypeParam) *types.Signature { params := r.paramList() results := r.paramList() variadic := params.Len() > 0 && r.bool() - return typeparams.NewSignatureType(recv, rparams, tparams, params, results, variadic) + return types.NewSignatureType(recv, rparams, tparams, params, results, variadic) } -func (r *importReader) tparamList() []*typeparams.TypeParam { +func (r *importReader) tparamList() []*types.TypeParam { n := r.uint64() if n == 0 { return nil } - xs := make([]*typeparams.TypeParam, n) + xs := make([]*types.TypeParam, n) for i := range xs { // Note: the standard library importer is tolerant of nil types here, // though would panic in SetTypeParams. - xs[i] = r.typ().(*typeparams.TypeParam) + xs[i] = r.typ().(*types.TypeParam) } return xs } diff --git a/vendor/golang.org/x/tools/internal/gocommand/invoke.go b/vendor/golang.org/x/tools/internal/gocommand/invoke.go index 53cf66da0..55312522d 100644 --- a/vendor/golang.org/x/tools/internal/gocommand/invoke.go +++ b/vendor/golang.org/x/tools/internal/gocommand/invoke.go @@ -13,6 +13,7 @@ import ( "io" "log" "os" + "os/exec" "reflect" "regexp" "runtime" @@ -21,8 +22,6 @@ import ( "sync" "time" - exec "golang.org/x/sys/execabs" - "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/event/keys" "golang.org/x/tools/internal/event/label" @@ -85,6 +84,7 @@ func (runner *Runner) RunPiped(ctx context.Context, inv Invocation, stdout, stde // RunRaw runs the invocation, serializing requests only if they fight over // go.mod changes. +// Postcondition: both error results have same nilness. func (runner *Runner) RunRaw(ctx context.Context, inv Invocation) (*bytes.Buffer, *bytes.Buffer, error, error) { ctx, done := event.Start(ctx, "gocommand.Runner.RunRaw", invLabels(inv)...) defer done() @@ -95,23 +95,24 @@ func (runner *Runner) RunRaw(ctx context.Context, inv Invocation) (*bytes.Buffer stdout, stderr, friendlyErr, err := runner.runConcurrent(ctx, inv) // If we encounter a load concurrency error, we need to retry serially. - if friendlyErr == nil || !modConcurrencyError.MatchString(friendlyErr.Error()) { - return stdout, stderr, friendlyErr, err + if friendlyErr != nil && modConcurrencyError.MatchString(friendlyErr.Error()) { + event.Error(ctx, "Load concurrency error, will retry serially", err) + + // Run serially by calling runPiped. + stdout.Reset() + stderr.Reset() + friendlyErr, err = runner.runPiped(ctx, inv, stdout, stderr) } - event.Error(ctx, "Load concurrency error, will retry serially", err) - // Run serially by calling runPiped. - stdout.Reset() - stderr.Reset() - friendlyErr, err = runner.runPiped(ctx, inv, stdout, stderr) return stdout, stderr, friendlyErr, err } +// Postcondition: both error results have same nilness. func (runner *Runner) runConcurrent(ctx context.Context, inv Invocation) (*bytes.Buffer, *bytes.Buffer, error, error) { // Wait for 1 worker to become available. select { case <-ctx.Done(): - return nil, nil, nil, ctx.Err() + return nil, nil, ctx.Err(), ctx.Err() case runner.inFlight <- struct{}{}: defer func() { <-runner.inFlight }() } @@ -121,6 +122,7 @@ func (runner *Runner) runConcurrent(ctx context.Context, inv Invocation) (*bytes return stdout, stderr, friendlyErr, err } +// Postcondition: both error results have same nilness. func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stderr io.Writer) (error, error) { // Make sure the runner is always initialized. runner.initialize() @@ -129,7 +131,7 @@ func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stde // runPiped commands. select { case <-ctx.Done(): - return nil, ctx.Err() + return ctx.Err(), ctx.Err() case runner.serialized <- struct{}{}: defer func() { <-runner.serialized }() } @@ -139,7 +141,7 @@ func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stde for i := 0; i < maxInFlight; i++ { select { case <-ctx.Done(): - return nil, ctx.Err() + return ctx.Err(), ctx.Err() case runner.inFlight <- struct{}{}: // Make sure we always "return" any workers we took. defer func() { <-runner.inFlight }() @@ -172,6 +174,7 @@ type Invocation struct { Logf func(format string, args ...interface{}) } +// Postcondition: both error results have same nilness. func (i *Invocation) runWithFriendlyError(ctx context.Context, stdout, stderr io.Writer) (friendlyError error, rawError error) { rawError = i.run(ctx, stdout, stderr) if rawError != nil { diff --git a/vendor/golang.org/x/tools/internal/gopathwalk/walk.go b/vendor/golang.org/x/tools/internal/gopathwalk/walk.go index 452e342c5..52f74e643 100644 --- a/vendor/golang.org/x/tools/internal/gopathwalk/walk.go +++ b/vendor/golang.org/x/tools/internal/gopathwalk/walk.go @@ -9,13 +9,12 @@ package gopathwalk import ( "bufio" "bytes" + "io/fs" "log" "os" "path/filepath" "strings" "time" - - "golang.org/x/tools/internal/fastwalk" ) // Options controls the behavior of a Walk call. @@ -45,21 +44,18 @@ type Root struct { } // Walk walks Go source directories ($GOROOT, $GOPATH, etc) to find packages. -// For each package found, add will be called (concurrently) with the absolute +// For each package found, add will be called with the absolute // paths of the containing source directory and the package directory. -// add will be called concurrently. func Walk(roots []Root, add func(root Root, dir string), opts Options) { WalkSkip(roots, add, func(Root, string) bool { return false }, opts) } // WalkSkip walks Go source directories ($GOROOT, $GOPATH, etc) to find packages. -// For each package found, add will be called (concurrently) with the absolute +// For each package found, add will be called with the absolute // paths of the containing source directory and the package directory. -// For each directory that will be scanned, skip will be called (concurrently) +// For each directory that will be scanned, skip will be called // with the absolute paths of the containing source directory and the directory. // If skip returns false on a directory it will be processed. -// add will be called concurrently. -// skip will be called concurrently. func WalkSkip(roots []Root, add func(root Root, dir string), skip func(root Root, dir string) bool, opts Options) { for _, root := range roots { walkDir(root, add, skip, opts) @@ -78,14 +74,25 @@ func walkDir(root Root, add func(Root, string), skip func(root Root, dir string) if opts.Logf != nil { opts.Logf("scanning %s", root.Path) } + w := &walker{ - root: root, - add: add, - skip: skip, - opts: opts, + root: root, + add: add, + skip: skip, + opts: opts, + added: make(map[string]bool), } w.init() - if err := fastwalk.Walk(root.Path, w.walk); err != nil { + + // Add a trailing path separator to cause filepath.WalkDir to traverse symlinks. + path := root.Path + if len(path) == 0 { + path = "." + string(filepath.Separator) + } else if !os.IsPathSeparator(path[len(path)-1]) { + path = path + string(filepath.Separator) + } + + if err := filepath.WalkDir(path, w.walk); err != nil { logf := opts.Logf if logf == nil { logf = log.Printf @@ -105,7 +112,10 @@ type walker struct { skip func(Root, string) bool // The callback that will be invoked for every dir. dir is skipped if it returns true. opts Options // Options passed to Walk by the user. - ignoredDirs []os.FileInfo // The ignored directories, loaded from .goimportsignore files. + pathSymlinks []os.FileInfo + ignoredDirs []string + + added map[string]bool } // init initializes the walker based on its Options @@ -121,13 +131,9 @@ func (w *walker) init() { for _, p := range ignoredPaths { full := filepath.Join(w.root.Path, p) - if fi, err := os.Stat(full); err == nil { - w.ignoredDirs = append(w.ignoredDirs, fi) - if w.opts.Logf != nil { - w.opts.Logf("Directory added to ignore list: %s", full) - } - } else if w.opts.Logf != nil { - w.opts.Logf("Error statting ignored directory: %v", err) + w.ignoredDirs = append(w.ignoredDirs, full) + if w.opts.Logf != nil { + w.opts.Logf("Directory added to ignore list: %s", full) } } } @@ -162,9 +168,9 @@ func (w *walker) getIgnoredDirs(path string) []string { } // shouldSkipDir reports whether the file should be skipped or not. -func (w *walker) shouldSkipDir(fi os.FileInfo, dir string) bool { +func (w *walker) shouldSkipDir(dir string) bool { for _, ignoredDir := range w.ignoredDirs { - if os.SameFile(fi, ignoredDir) { + if dir == ignoredDir { return true } } @@ -176,85 +182,150 @@ func (w *walker) shouldSkipDir(fi os.FileInfo, dir string) bool { } // walk walks through the given path. -func (w *walker) walk(path string, typ os.FileMode) error { - if typ.IsRegular() { +// +// Errors are logged if w.opts.Logf is non-nil, but otherwise ignored: +// walk returns only nil or fs.SkipDir. +func (w *walker) walk(path string, d fs.DirEntry, err error) error { + if err != nil { + // We have no way to report errors back through Walk or WalkSkip, + // so just log and ignore them. + if w.opts.Logf != nil { + w.opts.Logf("%v", err) + } + if d == nil { + // Nothing more to do: the error prevents us from knowing + // what path even represents. + return nil + } + } + + if d.Type().IsRegular() { + if !strings.HasSuffix(path, ".go") { + return nil + } + dir := filepath.Dir(path) if dir == w.root.Path && (w.root.Type == RootGOROOT || w.root.Type == RootGOPATH) { // Doesn't make sense to have regular files // directly in your $GOPATH/src or $GOROOT/src. - return fastwalk.ErrSkipFiles - } - if !strings.HasSuffix(path, ".go") { return nil } - w.add(w.root, dir) - return fastwalk.ErrSkipFiles + if !w.added[dir] { + w.add(w.root, dir) + w.added[dir] = true + } + return nil } - if typ == os.ModeDir { + + if d.IsDir() { base := filepath.Base(path) if base == "" || base[0] == '.' || base[0] == '_' || base == "testdata" || (w.root.Type == RootGOROOT && w.opts.ModulesEnabled && base == "vendor") || (!w.opts.ModulesEnabled && base == "node_modules") { - return filepath.SkipDir + return fs.SkipDir } - fi, err := os.Lstat(path) - if err == nil && w.shouldSkipDir(fi, path) { - return filepath.SkipDir + if w.shouldSkipDir(path) { + return fs.SkipDir } return nil } - if typ == os.ModeSymlink { - base := filepath.Base(path) - if strings.HasPrefix(base, ".#") { - // Emacs noise. - return nil - } - if w.shouldTraverse(path) { - return fastwalk.ErrTraverseLink + + if d.Type()&os.ModeSymlink != 0 { + // TODO(bcmills): 'go list all' itself ignores symlinks within GOROOT/src + // and GOPATH/src. Do we really need to traverse them here? If so, why? + + fi, err := os.Stat(path) + if err != nil || !fi.IsDir() { + // Not a directory. Just walk the file (or broken link) and be done. + return w.walk(path, fs.FileInfoToDirEntry(fi), err) } - } - return nil -} -// shouldTraverse reports whether the symlink fi, found in dir, -// should be followed. It makes sure symlinks were never visited -// before to avoid symlink loops. -func (w *walker) shouldTraverse(path string) bool { - ts, err := os.Stat(path) - if err != nil { - logf := w.opts.Logf - if logf == nil { - logf = log.Printf + // Avoid walking symlink cycles: if we have already followed a symlink to + // this directory as a parent of itself, don't follow it again. + // + // This doesn't catch the first time through a cycle, but it also minimizes + // the number of extra stat calls we make if we *don't* encounter a cycle. + // Since we don't actually expect to encounter symlink cycles in practice, + // this seems like the right tradeoff. + for _, parent := range w.pathSymlinks { + if os.SameFile(fi, parent) { + return nil + } } - logf("%v", err) - return false - } - if !ts.IsDir() { - return false - } - if w.shouldSkipDir(ts, filepath.Dir(path)) { - return false - } - // Check for symlink loops by statting each directory component - // and seeing if any are the same file as ts. - for { - parent := filepath.Dir(path) - if parent == path { - // Made it to the root without seeing a cycle. - // Use this symlink. - return true + + w.pathSymlinks = append(w.pathSymlinks, fi) + defer func() { + w.pathSymlinks = w.pathSymlinks[:len(w.pathSymlinks)-1] + }() + + // On some platforms the OS (or the Go os package) sometimes fails to + // resolve directory symlinks before a trailing slash + // (even though POSIX requires it to do so). + // + // On macOS that failure may be caused by a known libc/kernel bug; + // see https://go.dev/issue/59586. + // + // On Windows before Go 1.21, it may be caused by a bug in + // os.Lstat (fixed in https://go.dev/cl/463177). + // + // Since we need to handle this explicitly on broken platforms anyway, + // it is simplest to just always do that and not rely on POSIX pathname + // resolution to walk the directory (such as by calling WalkDir with + // a trailing slash appended to the path). + // + // Instead, we make a sequence of walk calls — directly and through + // recursive calls to filepath.WalkDir — simulating what WalkDir would do + // if the symlink were a regular directory. + + // First we call walk on the path as a directory + // (instead of a symlink). + err = w.walk(path, fs.FileInfoToDirEntry(fi), nil) + if err == fs.SkipDir { + return nil + } else if err != nil { + // This should be impossible, but handle it anyway in case + // walk is changed to return other errors. + return err } - parentInfo, err := os.Stat(parent) + + // Now read the directory and walk its entries. + ents, err := os.ReadDir(path) if err != nil { - return false + // Report the ReadDir error, as filepath.WalkDir would do. + err = w.walk(path, fs.FileInfoToDirEntry(fi), err) + if err == fs.SkipDir { + return nil + } else if err != nil { + return err // Again, should be impossible. + } + // Fall through and iterate over whatever entries we did manage to get. } - if os.SameFile(ts, parentInfo) { - // Cycle. Don't traverse. - return false + + for _, d := range ents { + nextPath := filepath.Join(path, d.Name()) + if d.IsDir() { + // We want to walk the whole directory tree rooted at nextPath, + // not just the single entry for the directory. + err := filepath.WalkDir(nextPath, w.walk) + if err != nil && w.opts.Logf != nil { + w.opts.Logf("%v", err) + } + } else { + err := w.walk(nextPath, d, nil) + if err == fs.SkipDir { + // Skip the rest of the entries in the parent directory of nextPath + // (that is, path itself). + break + } else if err != nil { + return err // Again, should be impossible. + } + } } - path = parent + return nil } + // Not a file, regular directory, or symlink; skip. + return nil } diff --git a/vendor/golang.org/x/tools/internal/imports/fix.go b/vendor/golang.org/x/tools/internal/imports/fix.go index 01e8ba5fa..dd369c072 100644 --- a/vendor/golang.org/x/tools/internal/imports/fix.go +++ b/vendor/golang.org/x/tools/internal/imports/fix.go @@ -254,7 +254,7 @@ type pass struct { otherFiles []*ast.File // sibling files. // Intermediate state, generated by load. - existingImports map[string]*ImportInfo + existingImports map[string][]*ImportInfo allRefs references missingRefs references @@ -319,7 +319,7 @@ func (p *pass) importIdentifier(imp *ImportInfo) string { func (p *pass) load() ([]*ImportFix, bool) { p.knownPackages = map[string]*packageInfo{} p.missingRefs = references{} - p.existingImports = map[string]*ImportInfo{} + p.existingImports = map[string][]*ImportInfo{} // Load basic information about the file in question. p.allRefs = collectReferences(p.f) @@ -350,7 +350,7 @@ func (p *pass) load() ([]*ImportFix, bool) { } } for _, imp := range imports { - p.existingImports[p.importIdentifier(imp)] = imp + p.existingImports[p.importIdentifier(imp)] = append(p.existingImports[p.importIdentifier(imp)], imp) } // Find missing references. @@ -389,31 +389,33 @@ func (p *pass) fix() ([]*ImportFix, bool) { // Found everything, or giving up. Add the new imports and remove any unused. var fixes []*ImportFix - for _, imp := range p.existingImports { - // We deliberately ignore globals here, because we can't be sure - // they're in the same package. People do things like put multiple - // main packages in the same directory, and we don't want to - // remove imports if they happen to have the same name as a var in - // a different package. - if _, ok := p.allRefs[p.importIdentifier(imp)]; !ok { - fixes = append(fixes, &ImportFix{ - StmtInfo: *imp, - IdentName: p.importIdentifier(imp), - FixType: DeleteImport, - }) - continue - } + for _, identifierImports := range p.existingImports { + for _, imp := range identifierImports { + // We deliberately ignore globals here, because we can't be sure + // they're in the same package. People do things like put multiple + // main packages in the same directory, and we don't want to + // remove imports if they happen to have the same name as a var in + // a different package. + if _, ok := p.allRefs[p.importIdentifier(imp)]; !ok { + fixes = append(fixes, &ImportFix{ + StmtInfo: *imp, + IdentName: p.importIdentifier(imp), + FixType: DeleteImport, + }) + continue + } - // An existing import may need to update its import name to be correct. - if name := p.importSpecName(imp); name != imp.Name { - fixes = append(fixes, &ImportFix{ - StmtInfo: ImportInfo{ - Name: name, - ImportPath: imp.ImportPath, - }, - IdentName: p.importIdentifier(imp), - FixType: SetImportName, - }) + // An existing import may need to update its import name to be correct. + if name := p.importSpecName(imp); name != imp.Name { + fixes = append(fixes, &ImportFix{ + StmtInfo: ImportInfo{ + Name: name, + ImportPath: imp.ImportPath, + }, + IdentName: p.importIdentifier(imp), + FixType: SetImportName, + }) + } } } // Collecting fixes involved map iteration, so sort for stability. See diff --git a/vendor/golang.org/x/tools/internal/packagesinternal/packages.go b/vendor/golang.org/x/tools/internal/packagesinternal/packages.go index d9950b1f0..44719de17 100644 --- a/vendor/golang.org/x/tools/internal/packagesinternal/packages.go +++ b/vendor/golang.org/x/tools/internal/packagesinternal/packages.go @@ -5,10 +5,6 @@ // Package packagesinternal exposes internal-only fields from go/packages. package packagesinternal -import ( - "golang.org/x/tools/internal/gocommand" -) - var GetForTest = func(p interface{}) string { return "" } var GetDepsErrors = func(p interface{}) []*PackageError { return nil } @@ -18,10 +14,6 @@ type PackageError struct { Err string // the error itself } -var GetGoCmdRunner = func(config interface{}) *gocommand.Runner { return nil } - -var SetGoCmdRunner = func(config interface{}, runner *gocommand.Runner) {} - var TypecheckCgo int var DepsErrors int // must be set as a LoadMode to call GetDepsErrors var ForTest int // must be set as a LoadMode to call GetForTest diff --git a/vendor/golang.org/x/tools/internal/testenv/testenv.go b/vendor/golang.org/x/tools/internal/testenv/testenv.go index 4d29ebe7f..511da9d7e 100644 --- a/vendor/golang.org/x/tools/internal/testenv/testenv.go +++ b/vendor/golang.org/x/tools/internal/testenv/testenv.go @@ -11,6 +11,7 @@ import ( "fmt" "go/build" "os" + "os/exec" "path/filepath" "runtime" "runtime/debug" @@ -21,8 +22,6 @@ import ( "golang.org/x/mod/modfile" "golang.org/x/tools/internal/goroot" - - exec "golang.org/x/sys/execabs" ) // packageMainIsDevel reports whether the module containing package main @@ -447,3 +446,32 @@ func NeedsLocalXTools(t testing.TB) { t.Skipf("skipping test: %s module path is %q, not %q", modFilePath, modulePath, want) } } + +// NeedsGoExperiment skips t if the current process environment does not +// have a GOEXPERIMENT flag set. +func NeedsGoExperiment(t testing.TB, flag string) { + t.Helper() + + goexp := os.Getenv("GOEXPERIMENT") + set := false + for _, f := range strings.Split(goexp, ",") { + if f == "" { + continue + } + if f == "none" { + // GOEXPERIMENT=none disables all experiment flags. + set = false + break + } + val := true + if strings.HasPrefix(f, "no") { + f, val = f[2:], false + } + if f == flag { + set = val + } + } + if !set { + t.Skipf("skipping test: flag %q is not set in GOEXPERIMENT=%q", flag, goexp) + } +} diff --git a/vendor/golang.org/x/tools/internal/typeparams/common.go b/vendor/golang.org/x/tools/internal/typeparams/common.go index d0d0649fe..cdab98853 100644 --- a/vendor/golang.org/x/tools/internal/typeparams/common.go +++ b/vendor/golang.org/x/tools/internal/typeparams/common.go @@ -42,7 +42,7 @@ func UnpackIndexExpr(n ast.Node) (x ast.Expr, lbrack token.Pos, indices []ast.Ex switch e := n.(type) { case *ast.IndexExpr: return e.X, e.Lbrack, []ast.Expr{e.Index}, e.Rbrack - case *IndexListExpr: + case *ast.IndexListExpr: return e.X, e.Lbrack, e.Indices, e.Rbrack } return nil, token.NoPos, nil, token.NoPos @@ -63,7 +63,7 @@ func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack toke Rbrack: rbrack, } default: - return &IndexListExpr{ + return &ast.IndexListExpr{ X: x, Lbrack: lbrack, Indices: indices, @@ -74,7 +74,7 @@ func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack toke // IsTypeParam reports whether t is a type parameter. func IsTypeParam(t types.Type) bool { - _, ok := t.(*TypeParam) + _, ok := t.(*types.TypeParam) return ok } @@ -100,11 +100,11 @@ func OriginMethod(fn *types.Func) *types.Func { // Receiver is a *types.Interface. return fn } - if ForNamed(named).Len() == 0 { + if named.TypeParams().Len() == 0 { // Receiver base has no type parameters, so we can avoid the lookup below. return fn } - orig := NamedTypeOrigin(named) + orig := named.Origin() gfn, _, _ := types.LookupFieldOrMethod(orig, true, fn.Pkg(), fn.Name()) // This is a fix for a gopls crash (#60628) due to a go/types bug (#60634). In: @@ -157,7 +157,7 @@ func OriginMethod(fn *types.Func) *types.Func { // // In this case, GenericAssignableTo reports that instantiations of Container // are assignable to the corresponding instantiation of Interface. -func GenericAssignableTo(ctxt *Context, V, T types.Type) bool { +func GenericAssignableTo(ctxt *types.Context, V, T types.Type) bool { // If V and T are not both named, or do not have matching non-empty type // parameter lists, fall back on types.AssignableTo. @@ -167,9 +167,9 @@ func GenericAssignableTo(ctxt *Context, V, T types.Type) bool { return types.AssignableTo(V, T) } - vtparams := ForNamed(VN) - ttparams := ForNamed(TN) - if vtparams.Len() == 0 || vtparams.Len() != ttparams.Len() || NamedTypeArgs(VN).Len() != 0 || NamedTypeArgs(TN).Len() != 0 { + vtparams := VN.TypeParams() + ttparams := TN.TypeParams() + if vtparams.Len() == 0 || vtparams.Len() != ttparams.Len() || VN.TypeArgs().Len() != 0 || TN.TypeArgs().Len() != 0 { return types.AssignableTo(V, T) } @@ -182,7 +182,7 @@ func GenericAssignableTo(ctxt *Context, V, T types.Type) bool { // Minor optimization: ensure we share a context across the two // instantiations below. if ctxt == nil { - ctxt = NewContext() + ctxt = types.NewContext() } var targs []types.Type @@ -190,12 +190,12 @@ func GenericAssignableTo(ctxt *Context, V, T types.Type) bool { targs = append(targs, vtparams.At(i)) } - vinst, err := Instantiate(ctxt, V, targs, true) + vinst, err := types.Instantiate(ctxt, V, targs, true) if err != nil { panic("type parameters should satisfy their own constraints") } - tinst, err := Instantiate(ctxt, T, targs, true) + tinst, err := types.Instantiate(ctxt, T, targs, true) if err != nil { return false } diff --git a/vendor/golang.org/x/tools/internal/typeparams/coretype.go b/vendor/golang.org/x/tools/internal/typeparams/coretype.go index 71248209e..7ea8840ea 100644 --- a/vendor/golang.org/x/tools/internal/typeparams/coretype.go +++ b/vendor/golang.org/x/tools/internal/typeparams/coretype.go @@ -108,15 +108,15 @@ func CoreType(T types.Type) types.Type { // // _NormalTerms makes no guarantees about the order of terms, except that it // is deterministic. -func _NormalTerms(typ types.Type) ([]*Term, error) { +func _NormalTerms(typ types.Type) ([]*types.Term, error) { switch typ := typ.(type) { - case *TypeParam: + case *types.TypeParam: return StructuralTerms(typ) - case *Union: + case *types.Union: return UnionTermSet(typ) case *types.Interface: return InterfaceTermSet(typ) default: - return []*Term{NewTerm(false, typ)}, nil + return []*types.Term{types.NewTerm(false, typ)}, nil } } diff --git a/vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go b/vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go deleted file mode 100644 index 18212390e..000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package typeparams - -// Enabled reports whether type parameters are enabled in the current build -// environment. -const Enabled = false diff --git a/vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go b/vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go deleted file mode 100644 index d67148823..000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.18 -// +build go1.18 - -package typeparams - -// Note: this constant is in a separate file as this is the only acceptable -// diff between the <1.18 API of this package and the 1.18 API. - -// Enabled reports whether type parameters are enabled in the current build -// environment. -const Enabled = true diff --git a/vendor/golang.org/x/tools/internal/typeparams/normalize.go b/vendor/golang.org/x/tools/internal/typeparams/normalize.go index 9c631b651..93c80fdc9 100644 --- a/vendor/golang.org/x/tools/internal/typeparams/normalize.go +++ b/vendor/golang.org/x/tools/internal/typeparams/normalize.go @@ -60,7 +60,7 @@ var ErrEmptyTypeSet = errors.New("empty type set") // // StructuralTerms makes no guarantees about the order of terms, except that it // is deterministic. -func StructuralTerms(tparam *TypeParam) ([]*Term, error) { +func StructuralTerms(tparam *types.TypeParam) ([]*types.Term, error) { constraint := tparam.Constraint() if constraint == nil { return nil, fmt.Errorf("%s has nil constraint", tparam) @@ -78,7 +78,7 @@ func StructuralTerms(tparam *TypeParam) ([]*Term, error) { // // See the documentation of StructuralTerms for more information on // normalization. -func InterfaceTermSet(iface *types.Interface) ([]*Term, error) { +func InterfaceTermSet(iface *types.Interface) ([]*types.Term, error) { return computeTermSet(iface) } @@ -88,11 +88,11 @@ func InterfaceTermSet(iface *types.Interface) ([]*Term, error) { // // See the documentation of StructuralTerms for more information on // normalization. -func UnionTermSet(union *Union) ([]*Term, error) { +func UnionTermSet(union *types.Union) ([]*types.Term, error) { return computeTermSet(union) } -func computeTermSet(typ types.Type) ([]*Term, error) { +func computeTermSet(typ types.Type) ([]*types.Term, error) { tset, err := computeTermSetInternal(typ, make(map[types.Type]*termSet), 0) if err != nil { return nil, err @@ -103,9 +103,9 @@ func computeTermSet(typ types.Type) ([]*Term, error) { if tset.terms.isAll() { return nil, nil } - var terms []*Term + var terms []*types.Term for _, term := range tset.terms { - terms = append(terms, NewTerm(term.tilde, term.typ)) + terms = append(terms, types.NewTerm(term.tilde, term.typ)) } return terms, nil } @@ -162,7 +162,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in tset.terms = allTermlist for i := 0; i < u.NumEmbeddeds(); i++ { embedded := u.EmbeddedType(i) - if _, ok := embedded.Underlying().(*TypeParam); ok { + if _, ok := embedded.Underlying().(*types.TypeParam); ok { return nil, fmt.Errorf("invalid embedded type %T", embedded) } tset2, err := computeTermSetInternal(embedded, seen, depth+1) @@ -171,7 +171,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in } tset.terms = tset.terms.intersect(tset2.terms) } - case *Union: + case *types.Union: // The term set of a union is the union of term sets of its terms. tset.terms = nil for i := 0; i < u.Len(); i++ { @@ -184,7 +184,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in return nil, err } terms = tset2.terms - case *TypeParam, *Union: + case *types.TypeParam, *types.Union: // A stand-alone type parameter or union is not permitted as union // term. return nil, fmt.Errorf("invalid union term %T", t) @@ -199,7 +199,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in return nil, fmt.Errorf("exceeded max term count %d", maxTermCount) } } - case *TypeParam: + case *types.TypeParam: panic("unreachable") default: // For all other types, the term set is just a single non-tilde term diff --git a/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go b/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go deleted file mode 100644 index 7ed86e171..000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package typeparams - -import ( - "go/ast" - "go/token" - "go/types" -) - -func unsupported() { - panic("type parameters are unsupported at this go version") -} - -// IndexListExpr is a placeholder type, as type parameters are not supported at -// this Go version. Its methods panic on use. -type IndexListExpr struct { - ast.Expr - X ast.Expr // expression - Lbrack token.Pos // position of "[" - Indices []ast.Expr // index expressions - Rbrack token.Pos // position of "]" -} - -// ForTypeSpec returns an empty field list, as type parameters on not supported -// at this Go version. -func ForTypeSpec(*ast.TypeSpec) *ast.FieldList { - return nil -} - -// ForFuncType returns an empty field list, as type parameters are not -// supported at this Go version. -func ForFuncType(*ast.FuncType) *ast.FieldList { - return nil -} - -// TypeParam is a placeholder type, as type parameters are not supported at -// this Go version. Its methods panic on use. -type TypeParam struct{ types.Type } - -func (*TypeParam) Index() int { unsupported(); return 0 } -func (*TypeParam) Constraint() types.Type { unsupported(); return nil } -func (*TypeParam) Obj() *types.TypeName { unsupported(); return nil } - -// TypeParamList is a placeholder for an empty type parameter list. -type TypeParamList struct{} - -func (*TypeParamList) Len() int { return 0 } -func (*TypeParamList) At(int) *TypeParam { unsupported(); return nil } - -// TypeList is a placeholder for an empty type list. -type TypeList struct{} - -func (*TypeList) Len() int { return 0 } -func (*TypeList) At(int) types.Type { unsupported(); return nil } - -// NewTypeParam is unsupported at this Go version, and panics. -func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam { - unsupported() - return nil -} - -// SetTypeParamConstraint is unsupported at this Go version, and panics. -func SetTypeParamConstraint(tparam *TypeParam, constraint types.Type) { - unsupported() -} - -// NewSignatureType calls types.NewSignature, panicking if recvTypeParams or -// typeParams is non-empty. -func NewSignatureType(recv *types.Var, recvTypeParams, typeParams []*TypeParam, params, results *types.Tuple, variadic bool) *types.Signature { - if len(recvTypeParams) != 0 || len(typeParams) != 0 { - panic("signatures cannot have type parameters at this Go version") - } - return types.NewSignature(recv, params, results, variadic) -} - -// ForSignature returns an empty slice. -func ForSignature(*types.Signature) *TypeParamList { - return nil -} - -// RecvTypeParams returns a nil slice. -func RecvTypeParams(sig *types.Signature) *TypeParamList { - return nil -} - -// IsComparable returns false, as no interfaces are type-restricted at this Go -// version. -func IsComparable(*types.Interface) bool { - return false -} - -// IsMethodSet returns true, as no interfaces are type-restricted at this Go -// version. -func IsMethodSet(*types.Interface) bool { - return true -} - -// IsImplicit returns false, as no interfaces are implicit at this Go version. -func IsImplicit(*types.Interface) bool { - return false -} - -// MarkImplicit does nothing, because this Go version does not have implicit -// interfaces. -func MarkImplicit(*types.Interface) {} - -// ForNamed returns an empty type parameter list, as type parameters are not -// supported at this Go version. -func ForNamed(*types.Named) *TypeParamList { - return nil -} - -// SetForNamed panics if tparams is non-empty. -func SetForNamed(_ *types.Named, tparams []*TypeParam) { - if len(tparams) > 0 { - unsupported() - } -} - -// NamedTypeArgs returns nil. -func NamedTypeArgs(*types.Named) *TypeList { - return nil -} - -// NamedTypeOrigin is the identity method at this Go version. -func NamedTypeOrigin(named *types.Named) *types.Named { - return named -} - -// Term holds information about a structural type restriction. -type Term struct { - tilde bool - typ types.Type -} - -func (m *Term) Tilde() bool { return m.tilde } -func (m *Term) Type() types.Type { return m.typ } -func (m *Term) String() string { - pre := "" - if m.tilde { - pre = "~" - } - return pre + m.typ.String() -} - -// NewTerm is unsupported at this Go version, and panics. -func NewTerm(tilde bool, typ types.Type) *Term { - return &Term{tilde, typ} -} - -// Union is a placeholder type, as type parameters are not supported at this Go -// version. Its methods panic on use. -type Union struct{ types.Type } - -func (*Union) Len() int { return 0 } -func (*Union) Term(i int) *Term { unsupported(); return nil } - -// NewUnion is unsupported at this Go version, and panics. -func NewUnion(terms []*Term) *Union { - unsupported() - return nil -} - -// InitInstanceInfo is a noop at this Go version. -func InitInstanceInfo(*types.Info) {} - -// Instance is a placeholder type, as type parameters are not supported at this -// Go version. -type Instance struct { - TypeArgs *TypeList - Type types.Type -} - -// GetInstances returns a nil map, as type parameters are not supported at this -// Go version. -func GetInstances(info *types.Info) map[*ast.Ident]Instance { return nil } - -// Context is a placeholder type, as type parameters are not supported at -// this Go version. -type Context struct{} - -// NewContext returns a placeholder Context instance. -func NewContext() *Context { - return &Context{} -} - -// Instantiate is unsupported on this Go version, and panics. -func Instantiate(ctxt *Context, typ types.Type, targs []types.Type, validate bool) (types.Type, error) { - unsupported() - return nil, nil -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go b/vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go deleted file mode 100644 index cf301af1d..000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.18 -// +build go1.18 - -package typeparams - -import ( - "go/ast" - "go/types" -) - -// IndexListExpr is an alias for ast.IndexListExpr. -type IndexListExpr = ast.IndexListExpr - -// ForTypeSpec returns n.TypeParams. -func ForTypeSpec(n *ast.TypeSpec) *ast.FieldList { - if n == nil { - return nil - } - return n.TypeParams -} - -// ForFuncType returns n.TypeParams. -func ForFuncType(n *ast.FuncType) *ast.FieldList { - if n == nil { - return nil - } - return n.TypeParams -} - -// TypeParam is an alias for types.TypeParam -type TypeParam = types.TypeParam - -// TypeParamList is an alias for types.TypeParamList -type TypeParamList = types.TypeParamList - -// TypeList is an alias for types.TypeList -type TypeList = types.TypeList - -// NewTypeParam calls types.NewTypeParam. -func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam { - return types.NewTypeParam(name, constraint) -} - -// SetTypeParamConstraint calls tparam.SetConstraint(constraint). -func SetTypeParamConstraint(tparam *TypeParam, constraint types.Type) { - tparam.SetConstraint(constraint) -} - -// NewSignatureType calls types.NewSignatureType. -func NewSignatureType(recv *types.Var, recvTypeParams, typeParams []*TypeParam, params, results *types.Tuple, variadic bool) *types.Signature { - return types.NewSignatureType(recv, recvTypeParams, typeParams, params, results, variadic) -} - -// ForSignature returns sig.TypeParams() -func ForSignature(sig *types.Signature) *TypeParamList { - return sig.TypeParams() -} - -// RecvTypeParams returns sig.RecvTypeParams(). -func RecvTypeParams(sig *types.Signature) *TypeParamList { - return sig.RecvTypeParams() -} - -// IsComparable calls iface.IsComparable(). -func IsComparable(iface *types.Interface) bool { - return iface.IsComparable() -} - -// IsMethodSet calls iface.IsMethodSet(). -func IsMethodSet(iface *types.Interface) bool { - return iface.IsMethodSet() -} - -// IsImplicit calls iface.IsImplicit(). -func IsImplicit(iface *types.Interface) bool { - return iface.IsImplicit() -} - -// MarkImplicit calls iface.MarkImplicit(). -func MarkImplicit(iface *types.Interface) { - iface.MarkImplicit() -} - -// ForNamed extracts the (possibly empty) type parameter object list from -// named. -func ForNamed(named *types.Named) *TypeParamList { - return named.TypeParams() -} - -// SetForNamed sets the type params tparams on n. Each tparam must be of -// dynamic type *types.TypeParam. -func SetForNamed(n *types.Named, tparams []*TypeParam) { - n.SetTypeParams(tparams) -} - -// NamedTypeArgs returns named.TypeArgs(). -func NamedTypeArgs(named *types.Named) *TypeList { - return named.TypeArgs() -} - -// NamedTypeOrigin returns named.Orig(). -func NamedTypeOrigin(named *types.Named) *types.Named { - return named.Origin() -} - -// Term is an alias for types.Term. -type Term = types.Term - -// NewTerm calls types.NewTerm. -func NewTerm(tilde bool, typ types.Type) *Term { - return types.NewTerm(tilde, typ) -} - -// Union is an alias for types.Union -type Union = types.Union - -// NewUnion calls types.NewUnion. -func NewUnion(terms []*Term) *Union { - return types.NewUnion(terms) -} - -// InitInstanceInfo initializes info to record information about type and -// function instances. -func InitInstanceInfo(info *types.Info) { - info.Instances = make(map[*ast.Ident]types.Instance) -} - -// Instance is an alias for types.Instance. -type Instance = types.Instance - -// GetInstances returns info.Instances. -func GetInstances(info *types.Info) map[*ast.Ident]Instance { - return info.Instances -} - -// Context is an alias for types.Context. -type Context = types.Context - -// NewContext calls types.NewContext. -func NewContext() *Context { - return types.NewContext() -} - -// Instantiate calls types.Instantiate. -func Instantiate(ctxt *Context, typ types.Type, targs []types.Type, validate bool) (types.Type, error) { - return types.Instantiate(ctxt, typ, targs, validate) -} diff --git a/vendor/golang.org/x/tools/internal/typesinternal/objectpath.go b/vendor/golang.org/x/tools/internal/typesinternal/objectpath.go deleted file mode 100644 index 5e96e8955..000000000 --- a/vendor/golang.org/x/tools/internal/typesinternal/objectpath.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package typesinternal - -import "go/types" - -// This file contains back doors that allow gopls to avoid method sorting when -// using the objectpath package. -// -// This is performance-critical in certain repositories, but changing the -// behavior of the objectpath package is still being discussed in -// golang/go#61443. If we decide to remove the sorting in objectpath we can -// simply delete these back doors. Otherwise, we should add a new API to -// objectpath that allows controlling the sorting. - -// SkipEncoderMethodSorting marks enc (which must be an *objectpath.Encoder) as -// not requiring sorted methods. -var SkipEncoderMethodSorting func(enc interface{}) - -// ObjectpathObject is like objectpath.Object, but allows suppressing method -// sorting. -var ObjectpathObject func(pkg *types.Package, p string, skipMethodSorting bool) (types.Object, error) diff --git a/vendor/golang.org/x/tools/internal/versions/gover.go b/vendor/golang.org/x/tools/internal/versions/gover.go new file mode 100644 index 000000000..bbabcd22e --- /dev/null +++ b/vendor/golang.org/x/tools/internal/versions/gover.go @@ -0,0 +1,172 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This is a fork of internal/gover for use by x/tools until +// go1.21 and earlier are no longer supported by x/tools. + +package versions + +import "strings" + +// A gover is a parsed Go gover: major[.Minor[.Patch]][kind[pre]] +// The numbers are the original decimal strings to avoid integer overflows +// and since there is very little actual math. (Probably overflow doesn't matter in practice, +// but at the time this code was written, there was an existing test that used +// go1.99999999999, which does not fit in an int on 32-bit platforms. +// The "big decimal" representation avoids the problem entirely.) +type gover struct { + major string // decimal + minor string // decimal or "" + patch string // decimal or "" + kind string // "", "alpha", "beta", "rc" + pre string // decimal or "" +} + +// compare returns -1, 0, or +1 depending on whether +// x < y, x == y, or x > y, interpreted as toolchain versions. +// The versions x and y must not begin with a "go" prefix: just "1.21" not "go1.21". +// Malformed versions compare less than well-formed versions and equal to each other. +// The language version "1.21" compares less than the release candidate and eventual releases "1.21rc1" and "1.21.0". +func compare(x, y string) int { + vx := parse(x) + vy := parse(y) + + if c := cmpInt(vx.major, vy.major); c != 0 { + return c + } + if c := cmpInt(vx.minor, vy.minor); c != 0 { + return c + } + if c := cmpInt(vx.patch, vy.patch); c != 0 { + return c + } + if c := strings.Compare(vx.kind, vy.kind); c != 0 { // "" < alpha < beta < rc + return c + } + if c := cmpInt(vx.pre, vy.pre); c != 0 { + return c + } + return 0 +} + +// lang returns the Go language version. For example, lang("1.2.3") == "1.2". +func lang(x string) string { + v := parse(x) + if v.minor == "" || v.major == "1" && v.minor == "0" { + return v.major + } + return v.major + "." + v.minor +} + +// isValid reports whether the version x is valid. +func isValid(x string) bool { + return parse(x) != gover{} +} + +// parse parses the Go version string x into a version. +// It returns the zero version if x is malformed. +func parse(x string) gover { + var v gover + + // Parse major version. + var ok bool + v.major, x, ok = cutInt(x) + if !ok { + return gover{} + } + if x == "" { + // Interpret "1" as "1.0.0". + v.minor = "0" + v.patch = "0" + return v + } + + // Parse . before minor version. + if x[0] != '.' { + return gover{} + } + + // Parse minor version. + v.minor, x, ok = cutInt(x[1:]) + if !ok { + return gover{} + } + if x == "" { + // Patch missing is same as "0" for older versions. + // Starting in Go 1.21, patch missing is different from explicit .0. + if cmpInt(v.minor, "21") < 0 { + v.patch = "0" + } + return v + } + + // Parse patch if present. + if x[0] == '.' { + v.patch, x, ok = cutInt(x[1:]) + if !ok || x != "" { + // Note that we are disallowing prereleases (alpha, beta, rc) for patch releases here (x != ""). + // Allowing them would be a bit confusing because we already have: + // 1.21 < 1.21rc1 + // But a prerelease of a patch would have the opposite effect: + // 1.21.3rc1 < 1.21.3 + // We've never needed them before, so let's not start now. + return gover{} + } + return v + } + + // Parse prerelease. + i := 0 + for i < len(x) && (x[i] < '0' || '9' < x[i]) { + if x[i] < 'a' || 'z' < x[i] { + return gover{} + } + i++ + } + if i == 0 { + return gover{} + } + v.kind, x = x[:i], x[i:] + if x == "" { + return v + } + v.pre, x, ok = cutInt(x) + if !ok || x != "" { + return gover{} + } + + return v +} + +// cutInt scans the leading decimal number at the start of x to an integer +// and returns that value and the rest of the string. +func cutInt(x string) (n, rest string, ok bool) { + i := 0 + for i < len(x) && '0' <= x[i] && x[i] <= '9' { + i++ + } + if i == 0 || x[0] == '0' && i != 1 { // no digits or unnecessary leading zero + return "", "", false + } + return x[:i], x[i:], true +} + +// cmpInt returns cmp.Compare(x, y) interpreting x and y as decimal numbers. +// (Copied from golang.org/x/mod/semver's compareInt.) +func cmpInt(x, y string) int { + if x == y { + return 0 + } + if len(x) < len(y) { + return -1 + } + if len(x) > len(y) { + return +1 + } + if x < y { + return -1 + } else { + return +1 + } +} diff --git a/vendor/golang.org/x/tools/internal/versions/types.go b/vendor/golang.org/x/tools/internal/versions/types.go new file mode 100644 index 000000000..562eef21f --- /dev/null +++ b/vendor/golang.org/x/tools/internal/versions/types.go @@ -0,0 +1,19 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package versions + +import ( + "go/types" +) + +// GoVersion returns the Go version of the type package. +// It returns zero if no version can be determined. +func GoVersion(pkg *types.Package) string { + // TODO(taking): x/tools can call GoVersion() [from 1.21] after 1.25. + if pkg, ok := any(pkg).(interface{ GoVersion() string }); ok { + return pkg.GoVersion() + } + return "" +} diff --git a/vendor/golang.org/x/tools/internal/versions/types_go121.go b/vendor/golang.org/x/tools/internal/versions/types_go121.go new file mode 100644 index 000000000..a7b79207a --- /dev/null +++ b/vendor/golang.org/x/tools/internal/versions/types_go121.go @@ -0,0 +1,20 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !go1.22 +// +build !go1.22 + +package versions + +import ( + "go/ast" + "go/types" +) + +// FileVersions always reports the a file's Go version as the +// zero version at this Go version. +func FileVersions(info *types.Info, file *ast.File) string { return "" } + +// InitFileVersions is a noop at this Go version. +func InitFileVersions(*types.Info) {} diff --git a/vendor/golang.org/x/tools/internal/versions/types_go122.go b/vendor/golang.org/x/tools/internal/versions/types_go122.go new file mode 100644 index 000000000..7b9ba89a8 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/versions/types_go122.go @@ -0,0 +1,24 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.22 +// +build go1.22 + +package versions + +import ( + "go/ast" + "go/types" +) + +// FileVersions maps a file to the file's semantic Go version. +// The reported version is the zero version if a version cannot be determined. +func FileVersions(info *types.Info, file *ast.File) string { + return info.FileVersions[file] +} + +// InitFileVersions initializes info to record Go versions for Go files. +func InitFileVersions(info *types.Info) { + info.FileVersions = make(map[*ast.File]string) +} diff --git a/vendor/golang.org/x/tools/internal/versions/versions.go b/vendor/golang.org/x/tools/internal/versions/versions.go new file mode 100644 index 000000000..e16f6c33a --- /dev/null +++ b/vendor/golang.org/x/tools/internal/versions/versions.go @@ -0,0 +1,52 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package versions + +// Note: If we use build tags to use go/versions when go >=1.22, +// we run into go.dev/issue/53737. Under some operations users would see an +// import of "go/versions" even if they would not compile the file. +// For example, during `go get -u ./...` (go.dev/issue/64490) we do not try to include +// For this reason, this library just a clone of go/versions for the moment. + +// Lang returns the Go language version for version x. +// If x is not a valid version, Lang returns the empty string. +// For example: +// +// Lang("go1.21rc2") = "go1.21" +// Lang("go1.21.2") = "go1.21" +// Lang("go1.21") = "go1.21" +// Lang("go1") = "go1" +// Lang("bad") = "" +// Lang("1.21") = "" +func Lang(x string) string { + v := lang(stripGo(x)) + if v == "" { + return "" + } + return x[:2+len(v)] // "go"+v without allocation +} + +// Compare returns -1, 0, or +1 depending on whether +// x < y, x == y, or x > y, interpreted as Go versions. +// The versions x and y must begin with a "go" prefix: "go1.21" not "1.21". +// Invalid versions, including the empty string, compare less than +// valid versions and equal to each other. +// The language version "go1.21" compares less than the +// release candidate and eventual releases "go1.21rc1" and "go1.21.0". +// Custom toolchain suffixes are ignored during comparison: +// "go1.21.0" and "go1.21.0-bigcorp" are equal. +func Compare(x, y string) int { return compare(stripGo(x), stripGo(y)) } + +// IsValid reports whether the version x is valid. +func IsValid(x string) bool { return isValid(stripGo(x)) } + +// stripGo converts from a "go1.21" version to a "1.21" version. +// If v does not start with "go", stripGo returns the empty string (a known invalid version). +func stripGo(v string) string { + if len(v) < 2 || v[:2] != "go" { + return "" + } + return v[2:] +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 11af7396b..b1d822ce2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -814,7 +814,7 @@ go.uber.org/zap/internal/bufferpool go.uber.org/zap/internal/color go.uber.org/zap/internal/exit go.uber.org/zap/zapcore -# golang.org/x/crypto v0.16.0 +# golang.org/x/crypto v0.18.0 ## explicit; go 1.18 golang.org/x/crypto/chacha20 golang.org/x/crypto/chacha20poly1305 @@ -830,13 +830,13 @@ golang.org/x/exp/slices # golang.org/x/exp/typeparams v0.0.0-20230307190834-24139beb5833 ## explicit; go 1.18 golang.org/x/exp/typeparams -# golang.org/x/mod v0.13.0 +# golang.org/x/mod v0.14.0 ## explicit; go 1.18 golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile golang.org/x/mod/module golang.org/x/mod/semver -# golang.org/x/net v0.19.0 +# golang.org/x/net v0.20.0 ## explicit; go 1.18 golang.org/x/net/context golang.org/x/net/http/httpguts @@ -861,14 +861,13 @@ golang.org/x/oauth2/jwt golang.org/x/perf/benchstat golang.org/x/perf/internal/stats golang.org/x/perf/storage/benchfmt -# golang.org/x/sync v0.5.0 +# golang.org/x/sync v0.6.0 ## explicit; go 1.18 golang.org/x/sync/errgroup golang.org/x/sync/semaphore -# golang.org/x/sys v0.15.0 +# golang.org/x/sys v0.16.0 ## explicit; go 1.18 golang.org/x/sys/cpu -golang.org/x/sys/execabs golang.org/x/sys/unix golang.org/x/sys/windows # golang.org/x/text v0.14.0 @@ -883,7 +882,7 @@ golang.org/x/text/width # golang.org/x/time v0.5.0 ## explicit; go 1.18 golang.org/x/time/rate -# golang.org/x/tools v0.14.0 +# golang.org/x/tools v0.17.0 ## explicit; go 1.18 golang.org/x/tools/go/analysis golang.org/x/tools/go/analysis/analysistest @@ -949,6 +948,7 @@ golang.org/x/tools/go/ssa/ssautil golang.org/x/tools/go/types/objectpath golang.org/x/tools/go/types/typeutil golang.org/x/tools/imports +golang.org/x/tools/internal/analysisinternal golang.org/x/tools/internal/diff golang.org/x/tools/internal/diff/lcs golang.org/x/tools/internal/event @@ -956,7 +956,6 @@ golang.org/x/tools/internal/event/core golang.org/x/tools/internal/event/keys golang.org/x/tools/internal/event/label golang.org/x/tools/internal/event/tag -golang.org/x/tools/internal/fastwalk golang.org/x/tools/internal/gcimporter golang.org/x/tools/internal/gocommand golang.org/x/tools/internal/gopathwalk @@ -969,6 +968,7 @@ golang.org/x/tools/internal/testenv golang.org/x/tools/internal/tokeninternal golang.org/x/tools/internal/typeparams golang.org/x/tools/internal/typesinternal +golang.org/x/tools/internal/versions golang.org/x/tools/txtar # golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 ## explicit; go 1.17 diff --git a/vm/qemu/qemu.go b/vm/qemu/qemu.go index bb616af47..ccaf643de 100644 --- a/vm/qemu/qemu.go +++ b/vm/qemu/qemu.go @@ -73,6 +73,8 @@ type Config struct { Snapshot bool `json:"snapshot"` // Magic key used to dongle macOS to the device. AppleSmcOsk string `json:"apple_smc_osk"` + // BPF runtime fuzzer working directory to be shared with the VM + BrfWorkDir string `json:"brf_workdir"` } type Pool struct { @@ -505,6 +507,11 @@ func (inst *instance) boot() error { "-device", "isa-applesmc,osk="+inst.cfg.AppleSmcOsk, ) } + if inst.cfg.BrfWorkDir != "" { + args = append(args, + "-virtfs", "local,path="+inst.cfg.BrfWorkDir+",mount_tag=brf,security_model=mapped,id=brf", + ) + } if inst.debug { log.Logf(0, "running command: %v %#v", inst.cfg.Qemu, args) }